0
Fork 0
mirror of https://github.com/penpot/penpot-plugins.git synced 2025-01-06 14:50:21 -05:00

feat: load plugin

This commit is contained in:
Juanfran 2024-02-06 12:16:28 +01:00
parent f68faaaa2c
commit ee96862ed5
50 changed files with 962 additions and 816 deletions

View file

@ -0,0 +1,3 @@
{
"presets": ["@nx/js/babel"]
}

View file

@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

View file

@ -0,0 +1,8 @@
{
"jsc": {
"parser": {
"syntax": "typescript"
},
"target": "es2016"
}
}

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>ExamplePlugin</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" href="/src/styles.css" />
</head>
<body>
<app-root></app-root>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View file

@ -0,0 +1,8 @@
{
"name": "example-plugin",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"sourceRoot": "apps/example-plugin/src",
"tags": [],
"targets": {}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,4 @@
{
"name": "Example plugin",
"code": "http://localhost:4201/plugin.js"
}

View file

@ -0,0 +1,65 @@
html {
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
line-height: 1.5;
tab-size: 4;
scroll-behavior: smooth;
}
body {
font-family: inherit;
line-height: inherit;
margin: 0;
}
h1,
h2,
p,
pre {
margin: 0;
}
*,
::before,
::after {
box-sizing: border-box;
border-width: 0;
border-style: solid;
border-color: currentColor;
}
h1,
h2 {
font-size: inherit;
font-weight: inherit;
}
a {
color: inherit;
text-decoration: inherit;
}
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
'Liberation Mono', 'Courier New', monospace;
}
svg {
display: block;
vertical-align: middle;
}
svg {
shape-rendering: auto;
text-rendering: optimizeLegibility;
}
.wrapper {
width: 100%;
}
button {
padding: 0.5rem;
border-radius: 5px;
cursor: pointer;
margin-bottom: 10px;
}
h1 {
font-size: 20px;
margin-bottom: 10px;
}

View file

@ -0,0 +1,21 @@
import { AppElement } from './app.element';
describe('AppElement', () => {
let app: AppElement;
beforeEach(() => {
app = new AppElement();
});
it('should create successfully', () => {
expect(app).toBeTruthy();
});
it('should have a greeting', () => {
app.connectedCallback();
expect(app.querySelector('h1').innerHTML).toContain(
'Welcome example-plugin'
);
});
});

View file

@ -0,0 +1,57 @@
import './app.element.css';
export class AppElement extends HTMLElement {
public static observedAttributes = [];
connectedCallback() {
window.addEventListener('message', function (event) {
if (event.data.type === 'pingpong') {
console.log('iframe', event.data.content);
} else if (event.data.type === 'page') {
console.log('iframe', event.data);
const projectName = document.getElementById('project-name');
if (projectName) {
projectName.innerText = event.data.content;
}
} else if (event.data.type === 'init') {
const projectName = document.getElementById('project-name');
if (projectName) {
projectName.innerText = event.data.content.name;
}
}
});
this.innerHTML = `
<div class="wrapper">
<h1>Test area</h1>
<p>Current project name: <span id="project-name">Unknown</span></p>
<p>
<button type="button" class="act-ping-pong">Ping Pong message</button>
</p>
<p>
<button type="button" class="act-close-plugin">Close plugin</button>
</p>
</div>
`;
const pingPongAction = this.querySelector<HTMLElement>('.act-ping-pong');
pingPongAction?.addEventListener('click', () => {
parent.postMessage({ content: 'ping' }, '*');
});
const closeAction = this.querySelector<HTMLElement>('.act-close-plugin');
closeAction?.addEventListener('click', () => {
parent.postMessage({ content: 'close' }, '*');
});
parent.postMessage({ content: 'ready' }, '*');
}
}
customElements.define('app-root', AppElement);

View file

View file

@ -0,0 +1 @@
import './app/app.element';

View file

@ -0,0 +1,36 @@
/* eslint-disable */
export declare global {
declare namespace globalThis {
export const penpot = {
ui: {},
};
}
}
penpot.log('Hello from plugin');
penpot.ui.open('Plugin name', 'http://localhost:4201', {
width: 500,
height: 600,
});
penpot.ui.onMessage((message) => {
if (message.content === 'ping') {
penpot.log('ping received');
penpot.ui.sendMessage({ type: 'pingpong', content: 'pong' });
} else if (message.content === 'close') {
penpot.closePlugin();
} else if (message.content === 'ready') {
penpot.ui.sendMessage({
type: 'init',
content: {
name: penpot.getPageState().name,
},
});
}
});
penpot.on('pagechange', (page) => {
penpot.ui.sendMessage({ type: 'page', content: page.name });
});

View file

@ -0,0 +1 @@
/* You can add global styles to this file, and also import other style files */

View file

@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["node"]
},
"exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts"]
}

View file

@ -0,0 +1,30 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ESNext", "DOM"],
"moduleResolution": "Node",
"strict": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"skipLibCheck": true,
"types": ["vite/client"]
},
"include": ["src"],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

View file

@ -0,0 +1,26 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": [
"vitest/globals",
"vitest/importMeta",
"vite/client",
"node",
"vitest"
]
},
"include": [
"vite.config.ts",
"vitest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
]
}

View file

@ -0,0 +1,58 @@
/// <reference types='vitest' />
import { defineConfig } from 'vite';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
export default defineConfig({
root: __dirname,
cacheDir: '../../node_modules/.vite/apps/example-plugin',
server: {
port: 4200,
host: 'localhost',
},
preview: {
port: 4300,
host: 'localhost',
},
plugins: [nxViteTsPaths()],
// Uncomment this if you are using workers.
// worker: {
// plugins: [ nxViteTsPaths() ],
// },
build: {
outDir: '../../dist/apps/example-plugin',
reportCompressedSize: true,
commonjsOptions: {
transformMixedEsModules: true,
},
rollupOptions: {
input: {
plugin: 'src/plugin.ts',
index: './index.html',
},
output: {
entryFileNames: '[name].js',
},
},
},
test: {
globals: true,
cache: {
dir: '../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
reporters: ['default'],
coverage: {
reportsDirectory: '../../coverage/apps/example-plugin',
provider: 'v8',
},
},
});

14
docs/create-api.md Normal file
View file

@ -0,0 +1,14 @@
Add your API in `libs/plugins-runtime/src/lib/api/index.ts`.
Try to use `zod` to validate the input an output, for example:
```ts
{
sum: z.function()
.args(z.number(), z.number())
.returns(z.number())
.implement((callback, time) => {
setTimeout(callback, time);
});
}
```

35
docs/create-plugin.md Normal file
View file

@ -0,0 +1,35 @@
npx nx g @nx/web:application example-plugin --directory=apps/example-plugin
Create a manifes.json in /public
```json
{
"name": "Example plugin",
"url": "http://localhost:4201",
"code": "http://localhost:4201/plugin.js"
}
```
Add to the example vite.config.ts
```json
build: {
rollupOptions: {
input: {
plugin: 'src/plugin.ts',
index: './index.html',
},
output: {
entryFileNames: '[name].js',
},
},
}
```
Run static server `npx nx run example-plugin:serve-static --port 4201`
Go to penpot and load the plugin.
```ts
ɵloadPlugin({ manifest: 'http://localhost:4201/manifest.json' });
```

72
docs/index.mustache Normal file
View file

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<title>Penpot - Design Freedom for Teams</title>
<meta name="description" content="The open-source solution for design and prototyping.">
<meta property="og:locale" content="en_US">
<meta property="og:title" content="Penpot | Design Freedom for Teams">
<meta property="og:description" content="The open-source solution for design and prototyping">
<meta property="og:image" content="https://penpot.app/images/workspace-ui.jpg">
<meta name="twitter:title" content="Penpot | Design Freedom for Teams">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:description" content="The open-source solution for design and prototyping">
<meta name="twitter:image" content="https://penpot.app/images/workspace-ui.jpg">
<meta name="twitter:site" content="@penpotapp">
<meta name="twitter:creator" content="@penpotapp">
<meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)">
<link id="theme" href="css/main.css?ts={{& ts}}" rel="stylesheet" type="text/css" />
{{#isDebug}}
<link href="css/debug.css?ts={{& ts}}" rel="stylesheet" type="text/css" />
{{/isDebug}}
<link rel="icon" href="images/favicon.png" />
<script type="importmap">
{"imports": {"plugins-runtime": "http://localhost:4200/index.mjs"}}
</script>
<script type="module" src="http://localhost:4200/index.mjs"></script>
<script>
window.penpotTranslations = JSON.parse({{& translations}});
window.penpotThemes = {{& themes}};
window.penpotVersion = "%version%";
window.penpotBuildDate = "%buildDate%";
</script>
{{# manifest}}
<script>window.penpotWorkerURI="{{& worker}}"</script>
<script defer src="{{& config}}"></script>
<script defer src="{{& polyfills}}"></script>
{{/manifest}}
</head>
<body>
{{>../public/images/sprites/symbol/icons.svg}}
{{>../public/images/sprites/symbol/cursors.svg}}
<div id="app"></div>
<section id="modal"></section>
{{# manifest}}
<script defer src="{{& shared}}"></script>
<script defer src="{{& main}}"></script>
<penpot-plugins />
{{/manifest}}
<script type="importmap">
{"imports": {"plugins-runtime": "http://localhost:4200/index.mjs"}}
</script>
<script type="module">
import * as runtime from "plugins-runtime";
// console.log(globalThis.app.plugins);
runtime.initialize(globalThis.app.plugins);
</script>
</body>
</html>

52
docs/plugin-usage.md Normal file
View file

@ -0,0 +1,52 @@
Open UI:
```ts
penpot.ui.open('Plugin name', 'http://localhost:4201', {
width: 500,
height: 600,
});
```
### Messages
Receive message from iframe:
```ts
penpot.ui.onMessage((message) => {
penpot.log('Received message:', message);
});
```
Send message from iframe:
```ts
parent.postMessage({ content: 'text' }, '*');
```
Send message from plugin
```ts
penpot.ui.sendMessage({ type: 'hello' });
```
Send message from plugin:
```ts
window.addEventListener('message', function (event) {
console.log('Message received from plugin: ', event.data);
});
```
### Events
Current events `pagechange` and `filechange`.
```ts
const event = (page) => {
penpot.log(page.name);
};
penpot.on('pagechange', event);
penpot.off('pagechange', event);
```

View file

@ -1,5 +1,5 @@
{
"extends": ["../.eslintrc.json"],
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{

View file

@ -0,0 +1,11 @@
# plugins-runtime
Go to to the [this branch](https://github.com/penpot/penpot/tree/niwinz-poc-plugins) in the Penpot local code.
Copy `penpot-plugins/docs/index.mustache` to `penpot/frontend/resources/templates/index.mustache`.
Run the penpot runtime with `npm start`.
Now you can go to penpot and see the `log` of this file `plugins-runtime/src/index.ts`.
See [this docs about how to install plugins](../docs/create-plugin.md).

View file

@ -1,7 +1,10 @@
{
"name": "plugins-runtime",
"version": "0.0.1",
"dependencies": {},
"dependencies": {
"ses": "^1.1.0",
"zod": "^3.22.4"
},
"module": "./index.mjs",
"typings": "./index.d.ts"
}

View file

@ -0,0 +1,34 @@
import 'ses';
import './lib/plugin-modal';
import { ɵloadPlugin } from './lib/load-plugin';
import { setFileState, setPageState } from './lib/api';
repairIntrinsics({
evalTaming: 'unsafeEval',
});
globalThis.ɵloadPlugin = ɵloadPlugin;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function initialize(api: any) {
console.log('plugin context');
globalThis.ɵloadPlugin = ɵloadPlugin;
console.log(api);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
api.addListener('plugin-page', 'page', (page: any) => {
console.log('Page Changed:', page);
setPageState(page);
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
api.addListener('plugin-file', 'file', (file: any) => {
console.log('File Changed:', file);
setFileState(file);
});
}

View file

@ -0,0 +1,114 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { OpenUIOptions } from '../models/open-ui-options.model';
import openUIApi from './openUI.api';
import z from 'zod';
type Callback<T> = (message: T) => void;
const validEvents = ['pagechange', 'filechange'] as const;
let uiMessagesCallbacks: Callback<any>[] = [];
let modal: HTMLElement | null = null;
let pageState = {} as any;
let fileState = {} as any;
const eventListeners: Map<string, Callback<unknown>[]> = new Map();
window.addEventListener('message', (event) => {
for (const callback of uiMessagesCallbacks) {
callback(event.data);
}
});
export function triggerEvent<T>(type: string, message: T) {
const listeners = eventListeners.get(type) || [];
listeners.forEach((listener) => listener(message));
}
export function setPageState(page: unknown) {
pageState = page;
triggerEvent('pagechange', page);
}
export function setFileState(file: unknown) {
fileState = file;
triggerEvent('filechange', file);
}
export function createApi() {
const closePlugin = () => {
if (modal) {
modal.remove();
}
uiMessagesCallbacks = [];
modal = null;
};
const penpot = {
ui: {
open: (name: string, url: string, options: OpenUIOptions) => {
modal = openUIApi(name, url, options);
modal.addEventListener('close', closePlugin, {
once: true,
});
},
sendMessage: (message: unknown) => {
const event = new CustomEvent('message', {
detail: message,
});
modal?.dispatchEvent(event);
},
onMessage: z
.function()
.args(z.function())
.implement((callback) => {
uiMessagesCallbacks.push(callback);
}),
},
log: console.log,
setTimeout: z
.function()
.args(z.function(), z.number())
.implement((callback, time) => {
setTimeout(callback, time);
}),
closePlugin,
on: (type: string, fn: Callback<unknown>) => {
// z.function alter fn, so can't use it here
z.enum(validEvents).parse(type);
z.function().parse(fn);
const listeners = eventListeners.get(type) || [];
listeners.push(fn);
eventListeners.set(type, listeners);
},
off: (type: string, fn: () => void) => {
z.enum(validEvents).parse(type);
z.function().parse(fn);
const listeners = eventListeners.get(type) || [];
eventListeners.set(
type,
listeners.filter((listener) => listener !== fn)
);
},
getFileState: () => {
return fileState;
},
getPageState: () => {
return pageState;
},
};
return penpot;
}

View file

@ -0,0 +1,10 @@
import z from 'zod';
import { openUISchema } from '../models/open-ui-options.schema';
import { createModal } from '../create-modal';
export default z
.function()
.args(z.string(), z.string(), openUISchema)
.implement((title, url, options) => {
return createModal(title, url, options);
});

View file

@ -0,0 +1,14 @@
import { OpenUIOptions } from './models/open-ui-options.model';
export function createModal(name: string, url: string, options: OpenUIOptions) {
const modal = document.createElement('plugin-modal');
modal.setAttribute('title', name);
modal.setAttribute('iframe-src', url);
modal.setAttribute('width', String(options.width || 300));
modal.setAttribute('height', String(options.height || 400));
document.body.appendChild(modal);
return modal;
}

View file

@ -0,0 +1,5 @@
export declare global {
declare namespace globalThis {
function ɵloadPlugin(cofig: PluginConfig): void;
}
}

View file

@ -0,0 +1,31 @@
import { PluginConfig } from './models/plugin-config.model';
import { createApi } from './api';
import { parseManifest } from './parse-manifest';
let isLockedDown = false;
let lastApi: ReturnType<typeof createApi> | undefined;
export const ɵloadPlugin = async function (config: PluginConfig) {
const { code } = await parseManifest(config);
try {
if (!isLockedDown) {
isLockedDown = true;
hardenIntrinsics();
}
if (lastApi) {
lastApi.closePlugin();
}
lastApi = createApi();
const c = new Compartment({
penpot: harden(lastApi),
});
c.evaluate(code);
} catch (error) {
console.error(error);
}
};

View file

@ -0,0 +1,4 @@
import z from 'zod';
import { manifestSchema } from './manifest.schema';
export type Manifest = z.infer<typeof manifestSchema>;

View file

@ -0,0 +1,6 @@
import { z } from 'zod';
export const manifestSchema = z.object({
name: z.string(),
code: z.string().url(),
});

View file

@ -0,0 +1,4 @@
import z from 'zod';
import { openUISchema } from './open-ui-options.schema';
export type OpenUIOptions = z.infer<typeof openUISchema>;

View file

@ -0,0 +1,6 @@
import { z } from 'zod';
export const openUISchema = z.object({
width: z.number().positive(),
height: z.number().positive(),
});

View file

@ -0,0 +1,3 @@
export interface PluginConfig {
manifest: string;
}

View file

@ -0,0 +1,35 @@
import { Manifest } from './models/manifest.model';
import { manifestSchema } from './models/manifest.schema';
import { PluginConfig } from './models/plugin-config.model';
function loadManifest(url: string): Promise<Manifest> {
return fetch(url)
.then((response) => response.json())
.then((manifest: Manifest) => {
const parseResult = manifestSchema.safeParse(manifest);
if (!parseResult.success) {
throw new Error('Invalid plugin manifest');
}
return manifest;
})
.catch((error) => {
console.error(error);
throw error;
});
}
function loadCode(url: string): Promise<string> {
return fetch(url).then((response) => response.text());
}
export async function parseManifest(config: PluginConfig) {
const manifest = await loadManifest(config.manifest);
const code = await loadCode(manifest.code);
return {
manifest,
code,
};
}

View file

@ -0,0 +1,105 @@
export class PluginModalElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
const title = this.getAttribute('title');
const iframeSrc = this.getAttribute('iframe-src');
const width = Number(this.getAttribute('width') || '300');
const height = Number(this.getAttribute('height') || '400');
if (!title || !iframeSrc) {
throw new Error('title and iframe-src attributes are required');
}
if (!this.shadowRoot) {
throw new Error('Error creating shadow root');
}
const header = document.createElement('div');
header.classList.add('header');
const h1 = document.createElement('h1');
h1.textContent = title;
header.appendChild(h1);
const closeButton = document.createElement('button');
closeButton.setAttribute('type', 'button');
closeButton.textContent = '❌';
closeButton.addEventListener('click', () => {
if (!this.shadowRoot) {
return;
}
this.shadowRoot.dispatchEvent(
new CustomEvent('close', {
composed: true,
bubbles: true,
})
);
});
header.appendChild(closeButton);
const iframe = document.createElement('iframe');
iframe.src = iframeSrc;
this.addEventListener('message', (e: Event) => {
if (!iframe.contentWindow) {
return;
}
iframe.contentWindow.postMessage((e as CustomEvent).detail, '*');
});
this.shadowRoot.appendChild(header);
this.shadowRoot.appendChild(iframe);
const style = document.createElement('style');
style.textContent = `
:host {
display: flex;
flex-direction: column;
position: fixed;
inset-block-end: 10px;
inset-inline-start: 10px;
z-index: 1000;
background: white;
padding: 20px;
border-radius: 5px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
inline-size: ${width}px;
block-size: ${height}px;
}
.header {
display: flex;
justify-content: space-between;
}
button {
background: transparent;
border: 0;
cursor: pointer;
}
h1 {
color: blue;
font-family: Arial, sans-serif;
}
iframe {
border: none;
inline-size: 100%;
block-size: 100%;
}
`;
this.shadowRoot.appendChild(style);
}
}
customElements.define('plugin-modal', PluginModalElement);

View file

@ -1,5 +1,5 @@
{
"extends": "../tsconfig.base.json",
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,

14
nx.json
View file

@ -1,4 +1,9 @@
{
"pluginsConfig": {
"@nx/js": {
"analyzeSourceFiles": true
}
},
"extends": "nx/presets/npm.json",
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"targetDefaults": {
@ -26,9 +31,12 @@
}
}
],
"pluginsConfig": {
"@nx/js": {
"analyzeSourceFiles": true
"generators": {
"@nx/web:application": {
"style": "css",
"linter": "eslint",
"unitTestRunner": "vitest",
"e2eTestRunner": "none"
}
}
}

788
package-lock.json generated
View file

@ -12,7 +12,9 @@
"packages/*"
],
"dependencies": {
"tslib": "^2.3.0"
"ses": "^1.1.0",
"tslib": "^2.3.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@commitlint/cli": "^18.6.0",
@ -2411,261 +2413,10 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
"integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
"integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
"integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
"integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
"integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
"integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
"integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
"integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
"integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
"integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
"integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
"integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
"integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
"integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
"integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
"integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
"node_modules/@endo/env-options": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@endo/env-options/-/env-options-1.1.1.tgz",
"integrity": "sha512-uCwlJ8Vkndx/VBBo36BdYHdxSoQPy7ZZpwyJNfv86Rh4B1IZfqzCRPf0u0mPgJdzOr7lShQey60SuYwoMSZ9Xg=="
},
"node_modules/@esbuild/linux-x64": {
"version": "0.19.12",
@ -2683,102 +2434,6 @@
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
"integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
"integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
"integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
"integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
"integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
"integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@ -3348,102 +3003,6 @@
"@nx/eslint": "18.0.2"
}
},
"node_modules/@nx/nx-darwin-arm64": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-18.0.2.tgz",
"integrity": "sha512-zFW5GDrH3GRdm5FePCYuCAEWvJ/G7iiB3jgP0zvLTRe06BQ4Z3bKCQu1v0B/mA7kR+cCY0ZtgHE+9UhK+lWarw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@nx/nx-darwin-x64": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-18.0.2.tgz",
"integrity": "sha512-Iihl8MK7NiDxn6pyhe/sctEv5J2MOK2bLJH3hBgJXbq8h278jAXqM5zLxVO49Kya65K7idAu1g5nvrRtafUIXg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@nx/nx-freebsd-x64": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-18.0.2.tgz",
"integrity": "sha512-D6pFFLRZs5f99oF3nHWMHhEYBVDB7x0kaDuR+96FfQlZXPU2SSQ+fzV1TREeQPhfHf9owgcduiE4utrOgJBTOQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@nx/nx-linux-arm-gnueabihf": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-18.0.2.tgz",
"integrity": "sha512-TCEKHBByEqIjiMNGOWS3maPpqQq1syUKOfp4fLJyE9A+NEK0th/6s65RWtzQR/GBUsi5r5y5g/pt+XFup+DrMA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@nx/nx-linux-arm64-gnu": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-18.0.2.tgz",
"integrity": "sha512-oYWeWtLmtM2LmsTStc6P4xUSJvpZxHZCoHIAFw1Rw7LQRbTyky19XR87F2mbEJbhSPMymeeLDR6SN0JSplODLg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@nx/nx-linux-arm64-musl": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-18.0.2.tgz",
"integrity": "sha512-9I27P5IilvICsLJxmh79OG6Y21uFKaqDAKCDlc608cyAH48Rq9xVM24DEQD0cITbfOjMRBBO2rMl7XX3b81w9Q==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@nx/nx-linux-x64-gnu": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-18.0.2.tgz",
@ -3476,38 +3035,6 @@
"node": ">= 10"
}
},
"node_modules/@nx/nx-win32-arm64-msvc": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-18.0.2.tgz",
"integrity": "sha512-pLc0SC/bEh8TC5H//pD+vHYUNCdYLWsMB9xAdey6V2qmKPrrDuWTs69qh0zCW4S1Jm8C9XK1av5mWIp2Fj8KnA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@nx/nx-win32-x64-msvc": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.0.2.tgz",
"integrity": "sha512-alWijWoroV65IRLdAQhFpINS9SRYSncWVT7CYe1iWwjiT16Un2i4NDoselpADuAsYC+Rgd+4h5Y+XzwtsQ55gg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@nx/vite": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/@nx/vite/-/vite-18.0.2.tgz",
@ -3597,110 +3124,6 @@
}
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz",
"integrity": "sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz",
"integrity": "sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz",
"integrity": "sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz",
"integrity": "sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz",
"integrity": "sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz",
"integrity": "sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz",
"integrity": "sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz",
"integrity": "sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz",
@ -3727,45 +3150,6 @@
"linux"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz",
"integrity": "sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz",
"integrity": "sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.9.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz",
"integrity": "sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rushstack/node-core-library": {
"version": "3.64.2",
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.64.2.tgz",
@ -3987,86 +3371,6 @@
}
}
},
"node_modules/@swc/core-darwin-arm64": {
"version": "1.3.107",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.107.tgz",
"integrity": "sha512-47tD/5vSXWxPd0j/ZllyQUg4bqalbQTsmqSw0J4dDdS82MWqCAwUErUrAZPRjBkjNQ6Kmrf5rpCWaGTtPw+ngw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-darwin-x64": {
"version": "1.3.107",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.107.tgz",
"integrity": "sha512-hwiLJ2ulNkBGAh1m1eTfeY1417OAYbRGcb/iGsJ+LuVLvKAhU/itzsl535CvcwAlt2LayeCFfcI8gdeOLeZa9A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm-gnueabihf": {
"version": "1.3.107",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.107.tgz",
"integrity": "sha512-I2wzcC0KXqh0OwymCmYwNRgZ9nxX7DWnOOStJXV3pS0uB83TXAkmqd7wvMBuIl9qu4Hfomi9aDM7IlEEn9tumQ==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm64-gnu": {
"version": "1.3.107",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.107.tgz",
"integrity": "sha512-HWgnn7JORYlOYnGsdunpSF8A+BCZKPLzLtEUA27/M/ZuANcMZabKL9Zurt7XQXq888uJFAt98Gy+59PU90aHKg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm64-musl": {
"version": "1.3.107",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.107.tgz",
"integrity": "sha512-vfPF74cWfAm8hyhS8yvYI94ucMHIo8xIYU+oFOW9uvDlGQRgnUf/6DEVbLyt/3yfX5723Ln57U8uiMALbX5Pyw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-x64-gnu": {
"version": "1.3.107",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.107.tgz",
@ -4099,54 +3403,6 @@
"node": ">=10"
}
},
"node_modules/@swc/core-win32-arm64-msvc": {
"version": "1.3.107",
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.107.tgz",
"integrity": "sha512-J3P14Ngy/1qtapzbguEH41kY109t6DFxfbK4Ntz9dOWNuVY3o9/RTB841ctnJk0ZHEG+BjfCJjsD2n8H5HcaOA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-ia32-msvc": {
"version": "1.3.107",
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.107.tgz",
"integrity": "sha512-ZBUtgyjTHlz8TPJh7kfwwwFma+ktr6OccB1oXC8fMSopD0AxVnQasgun3l3099wIsAB9eEsJDQ/3lDkOLs1gBA==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-x64-msvc": {
"version": "1.3.107",
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.107.tgz",
"integrity": "sha512-Eyzo2XRqWOxqhE1gk9h7LWmUf4Bp4Xn2Ttb0ayAXFp6YSTxQIThXcT9kipXZqcpxcmDwoq8iWbbf2P8XL743EA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/counter": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz",
@ -6677,20 +5933,6 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@ -9386,6 +8628,14 @@
"randombytes": "^2.1.0"
}
},
"node_modules/ses": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/ses/-/ses-1.2.0.tgz",
"integrity": "sha512-+klZ2zjFPbHAkf9owGeih+ZB1lqUqvVoCeL5IpNXmIZPhI5rGE1tR729EZmfBzmPh8j+CrsLr/+cTZUmHGFr9g==",
"dependencies": {
"@endo/env-options": "^1.1.1"
}
},
"node_modules/set-function-length": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz",
@ -10972,6 +10222,14 @@
"optionalDependencies": {
"commander": "^9.4.1"
}
},
"node_modules/zod": {
"version": "3.22.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
"integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}

View file

@ -3,7 +3,8 @@
"version": "0.0.0",
"license": "MIT",
"scripts": {
"start": "npx nx run plugins-runtime:serve-static",
"start": "npx nx run plugins-runtime:serve-static --port 4200",
"start:example": "npx nx run example-plugin:serve-static --port 4201",
"build": "npx nx build plugins-runtime --emptyOutDir=true",
"lint": "nx run-many --all --target=lint --parallel",
"lint:affected": "npx nx affected --target=lint",
@ -42,7 +43,8 @@
"packages/*"
],
"dependencies": {
"tslib": "^2.3.0"
"ses": "^1.1.0",
"tslib": "^2.3.0",
"zod": "^3.22.4"
}
}

View file

@ -1,23 +0,0 @@
# plugins-runtime
Go to to the [this branch](https://github.com/penpot/penpot/tree/niwinz-poc-plugins) in the Penpot local code.
Open `penpot/frontend/resources/templates/index.mustache` and replace the below:
```html
<script type="importmap">
{ "imports": { "plugins-runtime": "/js/plugins-runtime.mjs" } }
</script>
```
New code:
```
<script type="importmap">
{"imports": {"plugins-runtime": "http://localhost:4200/index.mjs"}}
</script>
```
Run the penpot runtime with `npm start`.
Now you can go to penpot and see the `log` of this file `plugins-runtime/src/index.ts`.

View file

@ -1,13 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export function initialize(api: any) {
console.log('plugin context');
console.log(api);
api.addListener('plugin-page', 'page', (page: any) => {
console.log('Page Changed:', page);
});
api.addListener('plugin file', 'file', (file: any) => {
console.log('File Changed:', file);
});
}

View file

@ -1,5 +0,0 @@
export class PenpotRuntimeElement extends HTMLElement {
// connectedCallback() {}
}
customElements.define('plugins-runtime', PenpotRuntimeElement);

View file

@ -15,7 +15,7 @@
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {
"plugins-runtime": ["plugins-runtime/src/index.ts"],
"plugins-runtime": ["libs/plugins-runtime/src/index.ts"],
"plugins-styles": ["plugins-styles/src/index.ts"]
}
},