diff --git a/frontend/src/app/main/data/plugins.cljs b/frontend/src/app/main/data/plugins.cljs index 5bdcdb776e..990cb2b981 100644 --- a/frontend/src/app/main/data/plugins.cljs +++ b/frontend/src/app/main/data/plugins.cljs @@ -66,22 +66,22 @@ (update-in state [:workspace-local :open-plugins] (fnil disj #{}) id)))) (defn- load-plugin! - [{:keys [plugin-id name description host code icon permissions]}] + [{:keys [plugin-id name version description host code icon permissions]}] (try (st/emit! (save-current-plugin plugin-id) (reset-plugin-flags plugin-id)) - (.ɵloadPlugin - ^js ug/global - #js {:pluginId plugin-id - :name name - :description description - :host host - :code code - :icon icon - :permissions (apply array permissions)} - (fn [] - (st/emit! (remove-current-plugin plugin-id)))) + (.ɵloadPlugin ^js ug/global + #js {:pluginId plugin-id + :name name + :description description + :version version + :host host + :code code + :icon icon + :permissions (apply array permissions)} + (fn [] + (st/emit! (remove-current-plugin plugin-id)))) (catch :default e (st/emit! (remove-current-plugin plugin-id)) diff --git a/frontend/src/app/plugins/register.cljs b/frontend/src/app/plugins/register.cljs index 1bf1a02f33..f6786dfb63 100644 --- a/frontend/src/app/plugins/register.cljs +++ b/frontend/src/app/plugins/register.cljs @@ -78,6 +78,7 @@ (d/without-nils {:plugin-id plugin-id :url (str plugin-url) + :version vers :name name :description desc :host origin diff --git a/plugins/libs/plugins-runtime/src/lib/models/manifest.schema.ts b/plugins/libs/plugins-runtime/src/lib/models/manifest.schema.ts index 54f12e7044..bd5895c02b 100644 --- a/plugins/libs/plugins-runtime/src/lib/models/manifest.schema.ts +++ b/plugins/libs/plugins-runtime/src/lib/models/manifest.schema.ts @@ -6,6 +6,7 @@ export const manifestSchema = z.object({ host: z.string().url(), code: z.string(), icon: z.string().optional(), + version: z.number().optional(), description: z.string().max(200).optional(), permissions: z.array( z.enum([ diff --git a/plugins/libs/plugins-runtime/src/lib/models/open-ui-options.schema.ts b/plugins/libs/plugins-runtime/src/lib/models/open-ui-options.schema.ts index f008033237..1d67ddaeb5 100644 --- a/plugins/libs/plugins-runtime/src/lib/models/open-ui-options.schema.ts +++ b/plugins/libs/plugins-runtime/src/lib/models/open-ui-options.schema.ts @@ -2,5 +2,5 @@ import { z } from 'zod'; export const openUISchema = z.object({ width: z.number().positive(), - height: z.number().positive(), + height: z.number().positive() }); diff --git a/plugins/libs/plugins-runtime/src/lib/parse-manifest.ts b/plugins/libs/plugins-runtime/src/lib/parse-manifest.ts index c5323dd30a..20001c31f7 100644 --- a/plugins/libs/plugins-runtime/src/lib/parse-manifest.ts +++ b/plugins/libs/plugins-runtime/src/lib/parse-manifest.ts @@ -1,8 +1,28 @@ import { Manifest } from './models/manifest.model.js'; import { manifestSchema } from './models/manifest.schema.js'; -export function getValidUrl(host: string, path: string): string { - return new URL(path, host).toString(); +export function getValidUrl(host: string, path: string): URL { + return new URL(path, host); +} + +export function prepareUrl(manifest: Manifest, url: string, params: Object): string { + const result = getValidUrl(manifest.host, url); + for (let [k, v] of Object.entries(params)) { + if (!result.searchParams.has(k)) { + result.searchParams.set(k, v); + } + } + + if (manifest.version === undefined || manifest.version === 1) { + return result.toString(); + } else if (manifest.version === 2) { + const queryString = result.searchParams.toString(); + result.search = ""; + result.hash = `/?${queryString}`; + return result.toString(); + } else { + throw new Error("invalid manifest version"); + } } export function loadManifest(url: string): Promise { diff --git a/plugins/libs/plugins-runtime/src/lib/plugin-manager.spec.ts b/plugins/libs/plugins-runtime/src/lib/plugin-manager.spec.ts index d8661a71d7..068fce583b 100644 --- a/plugins/libs/plugins-runtime/src/lib/plugin-manager.spec.ts +++ b/plugins/libs/plugins-runtime/src/lib/plugin-manager.spec.ts @@ -1,6 +1,6 @@ import { describe, it, vi, expect, beforeEach, afterEach } from 'vitest'; import { createPluginManager } from './plugin-manager'; -import { loadManifestCode, getValidUrl } from './parse-manifest.js'; +import { loadManifestCode, getValidUrl, prepareUrl } from './parse-manifest.js'; import { PluginModalElement } from './modal/plugin-modal.js'; import { openUIApi } from './api/openUI.api.js'; import type { Context, Theme } from '@penpot/plugin-types'; @@ -9,6 +9,7 @@ import type { Manifest } from './models/manifest.model.js'; vi.mock('./parse-manifest.js', () => ({ loadManifestCode: vi.fn(), getValidUrl: vi.fn(), + prepareUrl: vi.fn(), })); vi.mock('./api/openUI.api.js', () => ({ @@ -71,7 +72,8 @@ describe('createPluginManager', () => { vi.mocked(loadManifestCode).mockResolvedValue( 'console.log("Plugin loaded");', ); - vi.mocked(getValidUrl).mockReturnValue('https://example.com/plugin'); + vi.mocked(getValidUrl).mockReturnValue(new URL('https://example.com/plugin')); + vi.mocked(prepareUrl).mockReturnValue('https://example.com/plugin'); }); afterEach(() => { @@ -110,7 +112,7 @@ describe('createPluginManager', () => { height: 300, }); - expect(getValidUrl).toHaveBeenCalledWith(manifest.host, '/test-url'); + expect(prepareUrl).toHaveBeenCalledWith(manifest, '/test-url', {theme: "light"}); expect(openUIApi).toHaveBeenCalledWith( 'Test Modal', 'https://example.com/plugin', diff --git a/plugins/libs/plugins-runtime/src/lib/plugin-manager.ts b/plugins/libs/plugins-runtime/src/lib/plugin-manager.ts index d6af48fc07..df0d227d1e 100644 --- a/plugins/libs/plugins-runtime/src/lib/plugin-manager.ts +++ b/plugins/libs/plugins-runtime/src/lib/plugin-manager.ts @@ -1,6 +1,6 @@ import type { Context, Theme } from '@penpot/plugin-types'; -import { getValidUrl, loadManifestCode } from './parse-manifest.js'; +import { prepareUrl, loadManifestCode } from './parse-manifest.js'; import { Manifest } from './models/manifest.model.js'; import { PluginModalElement } from './modal/plugin-modal.js'; import { openUIApi } from './api/openUI.api.js'; @@ -8,6 +8,7 @@ import { OpenUIOptions } from './models/open-ui-options.model.js'; import { RegisterListener } from './models/plugin.model.js'; import { openUISchema } from './models/open-ui-options.schema.js'; + export async function createPluginManager( context: Context, manifest: Manifest, @@ -80,9 +81,8 @@ export async function createPluginManager( }; const openModal = (name: string, url: string, options?: OpenUIOptions) => { - const theme = context.theme as 'light' | 'dark'; - - const modalUrl = getValidUrl(manifest.host, url); + const theme = context.theme as Theme; + const modalUrl = prepareUrl(manifest, url, {theme}); if (modal?.getAttribute('iframe-src') === modalUrl) { return;