@ps-generator-bridge/generator 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/dist/contract-C4vydf6-.d.ts +1270 -0
  3. package/dist/contract.d.ts +3 -0
  4. package/dist/contract.js +19 -0
  5. package/dist/contract.js.map +1 -0
  6. package/dist/index.d.ts +8 -0
  7. package/dist/index.js +2482 -0
  8. package/dist/index.js.map +1 -0
  9. package/jsx/Action/autoCutout.jsx +12 -0
  10. package/jsx/Action/redo.jsx +5 -0
  11. package/jsx/Action/removeBackground.jsx +10 -0
  12. package/jsx/Common/alert.jsx +4 -0
  13. package/jsx/Common/debug.jsx +43 -0
  14. package/jsx/Common/event-dispatch.jsx +4 -0
  15. package/jsx/Document/exportDocument.jsx +128 -0
  16. package/jsx/Document/getDocumentInfo.jsx +222 -0
  17. package/jsx/Document/openPsd.jsx +6 -0
  18. package/jsx/Document/openPsdFile.jsx +7 -0
  19. package/jsx/Document/saveDocument.jsx +37 -0
  20. package/jsx/Layer/addImageLayer.jsx +182 -0
  21. package/jsx/Layer/createSelectionStroke.jsx +44 -0
  22. package/jsx/Layer/getActiveLayerID.jsx +1 -0
  23. package/jsx/Layer/getLayerBounds.jsx +114 -0
  24. package/jsx/Layer/getLayerInfo.jsx +323 -0
  25. package/jsx/Layer/getLayerPixmap.jsx +337 -0
  26. package/jsx/Layer/getSelection.jsx +6 -0
  27. package/jsx/Layer/layer.jsx +284 -0
  28. package/jsx/Layer/saveEngineDataToLayer.jsx +26 -0
  29. package/jsx/Layer/setLayerWorkpathMask.jsx +126 -0
  30. package/jsx/Layer/transformLayer.jsx +121 -0
  31. package/jsx/Selection/getSelectionPath.jsx +389 -0
  32. package/jsx/Selection/pathtosvg.jsx +257 -0
  33. package/jsx/Selection/registerEvent.jsx +10 -0
  34. package/jsx/Selection/selectiontopath.jsx +9 -0
  35. package/jsx/polyfills/Array.js +159 -0
  36. package/jsx/polyfills/Function.js +29 -0
  37. package/jsx/polyfills/JSON.js +182 -0
  38. package/jsx/polyfills/Number.js +24 -0
  39. package/jsx/polyfills/Object.js +80 -0
  40. package/jsx/polyfills/String.js +87 -0
  41. package/jsx/types/extendscript/README.md +34 -0
  42. package/jsx/types/extendscript/actions.d.ts +148 -0
  43. package/jsx/types/extendscript/application.d.ts +74 -0
  44. package/jsx/types/extendscript/channel.d.ts +70 -0
  45. package/jsx/types/extendscript/color.d.ts +92 -0
  46. package/jsx/types/extendscript/document.d.ts +110 -0
  47. package/jsx/types/extendscript/enums.d.ts +796 -0
  48. package/jsx/types/extendscript/index.d.ts +504 -0
  49. package/jsx/types/extendscript/layer.d.ts +530 -0
  50. package/jsx/types/extendscript/misc.d.ts +274 -0
  51. package/jsx/types/extendscript/open-options.d.ts +86 -0
  52. package/jsx/types/extendscript/path.d.ts +196 -0
  53. package/jsx/types/extendscript/save-options.d.ts +144 -0
  54. package/jsx/types/extendscript/selection.d.ts +191 -0
  55. package/jsx/types/extendscript/text.d.ts +169 -0
  56. package/main.js +16 -0
  57. package/package.json +75 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/plugin.ts","../src/server/index.ts","../../sdk/src/protocol.ts","../../sdk/src/photoshop/jsx-runner.ts","../../sdk/src/photoshop/JsxBuilder.ts","../../sdk/src/photoshop/PhotoshopLayer.ts","../../sdk/src/photoshop/PhotoshopLayers.ts","../../sdk/src/photoshop/PhotoshopSelection.ts","../../sdk/src/photoshop/PhotoshopDocument.ts","../../sdk/src/photoshop/PhotoshopApp.ts","../../sdk/src/photoshop/PsPhotoshopProxy.ts","../src/server/dispatch.ts","../src/server/methodTable.ts","../src/server/registry.ts","../src/meta.ts","../src/server/builtins.ts","../../sdk/src/plugin/base.ts","../../sdk/src/plugin/decorators.ts","../src/server/clientStore.ts","../src/server/scopedRegistry.ts","../src/server/pluginManager.ts","../src/utilis/eventManager.ts","../src/server/eventHub.ts","../src/server/pluginLoader.ts","../src/utilis/jsxRunner.ts","../src/modules/base.ts","../src/modules/action/index.ts","../src/modules/document/index.ts","../src/modules/layer/index.ts","../src/modules/image/index.ts","../src/utilis/pixmap.ts","../src/modules/index.ts","../src/services/cos.ts","../src/utilis/logger.ts"],"sourcesContent":["// Bundle entry. main.js requires this file's CJS build, and generator-core calls\n// the exported `init(generator, config, logger)`. We ignore generator-core's own\n// logger argument and inject our own. This is the composition root.\nimport { PsBridgeHost, type PluginConfig } from \"./plugin\";\nimport { createLogger } from \"./utilis/logger\";\nimport type { PsGenerator } from \"./types/generator\";\n\nexport function init(generator: PsGenerator, config?: PluginConfig): void {\n const logger = createLogger();\n // Async init is fire-and-forget; failures are logged, never thrown into core.\n void PsBridgeHost.init(generator, config ?? {}, logger).catch((error) =>\n logger.error(\"plugin init failed\", error)\n );\n}\n\nexport { PsBridgeHost } from \"./plugin\";\nexport type { PluginConfig } from \"./plugin\";\nexport type { PsGenerator } from \"./types/generator\";\nexport { JsxRunner } from \"./utilis/jsxRunner\";\n","import type { PsGenerator, GeneratorMenuChangedEvent } from \"./types/generator\";\nimport type { Logger } from \"./utilis/logger\";\nimport { join } from \"node:path\";\nimport { createServer, DEFAULT_PORT, type PsBridgeServer } from \"./server\";\nimport { bootstrap, type BasePlugin, type PluginHost } from \"@ps-generator-bridge/sdk/plugin\";\nimport { loadPlugins } from \"./server/pluginLoader\";\nimport { JsxRunner } from \"./utilis/jsxRunner\";\nimport { EventManager } from \"./utilis/eventManager\";\nimport { MODULES, ActionModule, DocumentModule, LayerModule, ImageModule } from \"./modules\";\nimport { CosService } from \"./services/cos\";\nimport { PLUGIN_NAME, PLUGIN_VERSION } from \"./meta\";\n\n// The menu id is echoed back on \"generatorMenuChanged\", so it must be a stable,\n// alphanumeric token unique to this plugin.\nconst MENU_ID = \"psGeneratorBridge\";\nconst MENU_LABEL = \"PS Generator Bridge: Server\";\nconst MENU_EVENT = \"generatorMenuChanged\";\n\n// Re-exported for callers that imported it from here before the server module\n// owned the default (now defined in ./server).\nexport { DEFAULT_PORT };\n\n/** Host config handed in by generator-core (self._config[name]). */\nexport interface PluginConfig {\n port?: number;\n /**\n * Directory whose direct child folders are loaded as plugin packages\n * (each a `package.json` with a `main` entry; see the plugin loader).\n * Defaults to `<generator-package>/plugins` — i.e. `packages/generator/plugins`,\n * a symlink to the repo-root `/plugins` in development.\n */\n pluginsDir?: string;\n [key: string]: unknown;\n}\n\n/**\n * Test-only overrides for `JsxRunner` construction. Production callers pass\n * nothing; tests point `polyfillsDir` at the source `jsx/polyfills` tree so\n * `init()` reads real files instead of the bundler's `dist/jsx/polyfills`\n * (which `__dirname`-based resolution can't reach under vitest's source\n * runtime).\n */\nexport interface JsxRunnerOverrides {\n polyfillsDir?: string;\n}\n\n/**\n * The host generator-core loads. Registers a menu item and starts the server's\n * own WebSocket service (ADR 0003). Every call into Photoshop goes through the\n * injected `generator`, which makes the whole init path observable from a test\n * mock (see test/fakeGenerator.ts).\n */\nexport class PsBridgeHost implements PluginHost {\n private server: PsBridgeServer | undefined;\n /** Feature modules, reached by short key (`host.modules.layer`, ADR 0009). */\n public readonly modules: {\n layer: LayerModule;\n document: DocumentModule;\n action: ActionModule;\n image: ImageModule;\n };\n private plugins: BasePlugin[] = [];\n private readonly _jsx: JsxRunner;\n private readonly _events: EventManager;\n /**\n * Optional object-storage upload service (RFC 0008). Set from the environment\n * at construction — present only when the `PS_BRIDGE_COS_*` fields are configured;\n * otherwise undefined. Reached by modules and plugins through `plugin.cos`.\n */\n public readonly cos?: CosService;\n\n private constructor(\n public readonly generator: PsGenerator,\n public readonly config: PluginConfig,\n public readonly logger: Logger,\n overrides?: JsxRunnerOverrides\n ) {\n this.modules = {\n layer: new MODULES.layer(this),\n document: new MODULES.document(this),\n action: new MODULES.action(this),\n image: new MODULES.image(this),\n };\n this._jsx = new JsxRunner(generator, logger, overrides?.polyfillsDir);\n this._events = new EventManager(generator);\n this.cos = CosService.fromEnv(logger);\n logger.info(this.cos ? \"CosService enabled\" : \"CosService disabled (env incomplete)\");\n }\n\n /** Run packaged jsx by name (ADR 0008). Used by modules and other server callers. */\n get jsx(): JsxRunner {\n return this._jsx;\n }\n\n /** Photoshop event subscriptions owned by the host. */\n get events(): EventManager {\n return this._events;\n }\n\n /**\n * Build the host contract for one plugin (RFC 0005). A shallow view that shares\n * the host's `modules` and `events` (both global-singleton semantics — they do\n * not split per plugin) but swaps in a `jsx` scoped to `<pluginDir>/jsx`, so the\n * plugin's `jsx.execute(\"x\")` resolves to its own files while `executeBuiltin`\n * still reaches the built-in tree. Passed to `loadPlugins` as the `hostFor`\n * factory; the plugin never sees the concrete `PsBridgeHost`.\n */\n private hostFor(pluginDir: string): PluginHost {\n return {\n modules: this.modules,\n events: this._events,\n jsx: this._jsx.forPlugin(join(pluginDir, \"jsx\")),\n cos: this.cos,\n };\n }\n\n /** Entry point: construct the host and run its async initialization. */\n static async init(\n generator: PsGenerator,\n config: PluginConfig,\n logger: Logger,\n overrides?: JsxRunnerOverrides\n ): Promise<PsBridgeHost> {\n const host = new PsBridgeHost(generator, config, logger, overrides);\n await host.onInit();\n return host;\n }\n\n private async onInit(): Promise<void> {\n this.logger.info(`${PLUGIN_NAME} v${PLUGIN_VERSION} initializing`);\n this.createMenuItem();\n const port = this.config.port ?? portFromEnv(this.logger) ?? DEFAULT_PORT;\n // Build first, then let modules/plugins register their routes/methods, then\n // listen — fastify requires all HTTP routes before listen (ADR 0006).\n const server = createServer({\n port,\n generator: this.generator,\n jsx: this._jsx,\n events: this._events,\n logger: this.logger,\n });\n this.server = server;\n // Plugins are loaded entirely from `pluginsDir`: scan its direct child\n // folders for `package.json` packages, validate + construct each with its\n // `static id` and this host. A missing dir is the default state (no plugins\n // installed). Modules exist from construction so a plugin can read\n // `this.plugin.modules.<key>` (ADR 0009).\n // Resolution order: explicit `config.pluginsDir`, then the\n // PS_BRIDGE_PLUGINS_DIR env override, else the package-local\n // `plugins/` tree (__dirname is `dist`, so `../plugins`).\n const pluginsDir =\n this.config.pluginsDir ??\n process.env.PS_BRIDGE_PLUGINS_DIR ??\n join(__dirname, \"..\", \"plugins\");\n const { loaded, skipped } = await loadPlugins({\n pluginsDir,\n hostFor: (pluginDir) => this.hostFor(pluginDir),\n knownIds: new Set(),\n logger: this.logger,\n });\n for (const s of skipped) this.logger.warn(`plugin skipped: ${s.path} — ${s.reason}`);\n this.plugins = loaded.map((l) => l.plugin);\n // Register every plugin (scoped table + per-plugin ClientStore + bus +\n // /ws/{id} dispatch + prefixed @api) before module bootstrap, so plugin ids\n // are reserved first path segments — a module @api cannot then steal a\n // plugin's namespace (RFC 0004). All routes land before `listen` (fastify).\n for (const plugin of this.plugins) {\n server.pluginManager.register(plugin);\n }\n server.registry.reservedSegments = new Set(server.pluginManager.ids);\n for (const module of Object.values(this.modules)) {\n bootstrap(module, server.registry);\n }\n // Prime the default ExtendScript engine with polyfills before any client\n // request can drive `jsx.execute` / `jsx.run` (ADR 0008). Module/plugin\n // constructors don't touch jsx — only decorated handlers do, and those fire\n // after `listen` — so priming here is early enough.\n await this._jsx.init();\n await server.listen();\n this.logger.info(`${PLUGIN_NAME} initialized`);\n }\n\n private createMenuItem(): void {\n this.generator.addMenuItem(MENU_ID, MENU_LABEL, true, false);\n this.generator.onPhotoshopEvent(MENU_EVENT, (event: GeneratorMenuChangedEvent) =>\n this.handleMenuClicked(event)\n );\n this.logger.debug(`menu item registered: ${MENU_ID}`);\n }\n\n // \"generatorMenuChanged\" fires for *every* plugin's menu, so we must filter to\n // our own id before acting.\n private handleMenuClicked(event: GeneratorMenuChangedEvent): void {\n if (event?.generatorMenuChanged?.name !== MENU_ID) return;\n const port = this.server?.port ?? this.config.port ?? DEFAULT_PORT;\n this.generator.alert(\n `${PLUGIN_NAME} v${PLUGIN_VERSION} — listening on ws://127.0.0.1:${port}/ws`\n );\n }\n\n /** Stop the WebSocket service (used by tests; PS teardown is process exit). */\n async close(): Promise<void> {\n await this.server?.close();\n this.server = undefined;\n }\n}\n\nfunction portFromEnv(logger: Logger): number | undefined {\n const raw = process.env.PS_BRIDGE_PORT;\n if (!raw) return undefined;\n const port = Number(raw);\n if (Number.isInteger(port) && port > 0 && port <= 65535) return port;\n logger.warn(`ignoring invalid PS_BRIDGE_PORT: ${raw}`);\n return undefined;\n}\n","import Fastify from \"fastify\";\nimport websocket from \"@fastify/websocket\";\nimport { randomUUID } from \"node:crypto\";\nimport type { WebSocket } from \"ws\";\nimport { parseFrame, serializeFrame } from \"@ps-generator-bridge/sdk\";\nimport { Registry } from \"./registry\";\nimport { registerBuiltins } from \"./builtins\";\nimport { PluginManager, type PluginEntry, type PluginInfo } from \"./pluginManager\";\nimport type { ConnectionSession, HandlerContext } from \"./dispatch\";\nimport { ClientStore, type ClientEntry } from \"./clientStore\";\nimport { EventHub } from \"./eventHub\";\nimport type { Logger } from \"../utilis/logger\";\nimport type { PsGenerator } from \"../types/generator\";\nimport type { JsxRunnerApi } from \"../utilis/jsxRunner\";\nimport type { EventManager } from \"../utilis/eventManager\";\n\n/** Port the plugin/dev-server fall back to when no port is configured. */\nexport const DEFAULT_PORT = 7700;\n\nexport interface StartServerOptions {\n /** Port to listen on. Use 0 for an ephemeral port (tests). */\n port: number;\n host?: string;\n generator: PsGenerator;\n jsx?: JsxRunnerApi;\n events?: EventManager;\n logger: Logger;\n}\n\nexport interface PsBridgeServer {\n /** The bound port (resolved after `listen()`; 0 before). */\n readonly port: number;\n /** Global assembly seam: modules + builtins register here before `listen()`. */\n readonly registry: Registry;\n /** Per-plugin manager: the host registers each plugin here before `listen()`. */\n readonly pluginManager: PluginManager;\n /** Start listening. All HTTP/WS routes must be registered before this (fastify). */\n listen(): Promise<void>;\n close(): Promise<void>;\n}\n\n/**\n * Build the server (fastify + plugin manager + routes) **without listening**, so the\n * caller (host) can register modules and plugins before `listen()` — fastify\n * requires all HTTP routes up front (ADR 0006). `/health` is a liveness probe;\n * `GET /plugins` lists loaded plugins; the protocol WebSocket lives at\n * `/ws/{pluginId}` and performs the clientId handshake (ADR 0007 / RFC 0004).\n *\n * The single param route `/ws/:pluginId` serves every plugin: it looks the\n * plugin up in the manager, handshakes against that plugin's own ClientStore, and\n * dispatches scoped-first with global fallback. An unknown plugin id gets an\n * error frame then a close (not a bare 404).\n */\nexport function createServer(options: StartServerOptions): PsBridgeServer {\n const { port, host = \"127.0.0.1\", generator, jsx, events, logger } = options;\n\n // Fastify's own pino logger is disabled: all server logging flows through the\n // injected Logger, keeping one log format and one test seam (ADR 0003).\n const app = Fastify({ logger: false });\n let boundPort = 0;\n\n const pluginManager = new PluginManager(app);\n const registry = new Registry(app);\n registerBuiltins(registry, () => pluginManager.list());\n const rootClients = new ClientStore();\n const rootEvents = events ? new EventHub(events, rootClients) : undefined;\n\n app.get(\"/health\", async () => ({ status: \"ok\" }));\n app.get(\"/plugins\", async () => ({ plugins: pluginManager.list() }));\n\n // websocket must register before the /ws route; the nested plugin guarantees\n // that boot order without awaiting (this function stays synchronous).\n app.register(websocket);\n app.register(async (instance) => {\n instance.get(\"/ws\", { websocket: true }, (socket: WebSocket, req) => {\n const query = req.query as { id?: string } | undefined;\n const requested = query?.id;\n const clientId = requested && requested.length > 0 ? requested : randomUUID();\n rootClients.add(clientId, socket);\n logger.info(`client connected: ${clientId} -> root`);\n socket.send(serializeFrame({ type: \"connected\", data: { clientId } }));\n\n const session: ConnectionSession = {\n clientId,\n subscribe: (type) => {\n const added = rootClients.subscribe(clientId, type);\n if (!added) return;\n try {\n rootEvents?.subscribe(type);\n } catch (error) {\n rootClients.unsubscribe(clientId, type);\n throw error;\n }\n },\n unsubscribe: (type) => {\n const removed = rootClients.unsubscribe(clientId, type);\n if (removed) rootEvents?.unsubscribe(type);\n },\n };\n const ctx: HandlerContext = { generator, jsx, session };\n\n socket.on(\"message\", (data) => {\n void handleRootFrame(socket, String(data), registry, ctx, logger);\n });\n socket.on(\"close\", () => {\n const removed = rootClients.remove(clientId, socket);\n releaseSubscriptions(removed, rootEvents);\n logger.info(`client disconnected: ${clientId} -> root`);\n });\n socket.on(\"error\", (error) => logger.error(\"socket error\", error));\n });\n\n instance.get(\"/ws/:pluginId\", { websocket: true }, (socket: WebSocket, req) => {\n const pluginId = (req.params as { pluginId: string }).pluginId;\n const entry = pluginManager.get(pluginId);\n if (!entry) {\n socket.send(\n serializeFrame({\n type: \"error\",\n data: { code: \"UNKNOWN_PLUGIN\", message: `unknown plugin: ${pluginId}`, pluginId },\n })\n );\n socket.close();\n return;\n }\n const query = req.query as { id?: string } | undefined;\n const requested = query?.id;\n const clientId = requested && requested.length > 0 ? requested : randomUUID();\n entry.clients.add(clientId, socket);\n entry.plugin.onConnect(clientId);\n logger.info(`client connected: ${clientId} -> plugin ${pluginId}`);\n // First frame after connect is the handshake Event carrying the clientId.\n socket.send(serializeFrame({ type: \"connected\", data: { clientId } }));\n const ctx: HandlerContext = { generator, jsx };\n\n socket.on(\"message\", (data) => {\n void handlePluginFrame(socket, String(data), entry, registry, ctx, logger);\n });\n socket.on(\"close\", () => {\n entry.clients.remove(clientId, socket);\n entry.plugin.onDisconnect(clientId);\n logger.info(`client disconnected: ${clientId} -> plugin ${pluginId}`);\n });\n socket.on(\"error\", (error) => logger.error(\"socket error\", error));\n });\n });\n\n return {\n get port() {\n return boundPort;\n },\n registry,\n pluginManager,\n listen: async () => {\n await app.listen({ port, host });\n const address = app.server.address();\n boundPort = typeof address === \"object\" && address ? address.port : port;\n logger.info(\n `PS Generator Bridge server listening on http://${host}:${boundPort} (ws + /health + /plugins)`\n );\n },\n close: () => app.close(),\n };\n}\n\nasync function handleRootFrame(\n socket: WebSocket,\n data: string,\n registry: Registry,\n ctx: HandlerContext,\n logger: Logger\n): Promise<void> {\n let parsed: unknown;\n try {\n parsed = parseFrame(data);\n } catch {\n logger.warn(\"dropping non-JSON frame\");\n return;\n }\n const response = await registry.dispatch(parsed, ctx);\n if (response) {\n socket.send(serializeFrame(response));\n }\n}\n\n/**\n * Convenience: build + listen in one call. Used by the dev-server and tests.\n */\nexport async function startServer(options: StartServerOptions): Promise<PsBridgeServer> {\n const server = createServer(options);\n await server.listen();\n return server;\n}\n\nfunction releaseSubscriptions(entry: ClientEntry | undefined, hub: EventHub | undefined): void {\n if (!entry || !hub) return;\n for (const type of entry.subscriptions) {\n hub.unsubscribe(type);\n }\n}\n\nasync function handlePluginFrame(\n socket: WebSocket,\n data: string,\n entry: PluginEntry,\n registry: Registry,\n ctx: HandlerContext,\n logger: Logger\n): Promise<void> {\n let parsed: unknown;\n try {\n parsed = parseFrame(data);\n } catch {\n logger.warn(\"dropping non-JSON frame\");\n return;\n }\n // Scoped first, global fallback. tryDispatch returns undefined when no scoped\n // handler matches (or the frame is not a request); registry.dispatch then\n // handles modules/builtins or returns UnknownMethod.\n const response =\n (await entry.scoped.tryDispatch(parsed, ctx)) ?? (await registry.dispatch(parsed, ctx));\n if (response) {\n socket.send(serializeFrame(response));\n }\n}\n\n// Re-export so callers that previously imported this from here keep working.\nexport type { PluginInfo };\n","/**\n * The wire contract shared by the SDK client and the server.\n *\n * This package is the single source of truth for the protocol (ADR 0001): the\n * server depends on this module type-only and implements the same shapes. To add\n * a server capability, model it here first (a new entry in `ProtocolMethods`),\n * then implement it on the server and expose a method on the client.\n */\n\n/** Bumped on any breaking change to the envelope or method shapes. */\nexport const PROTOCOL_VERSION = 1;\n\n/**\n * Request method names shared by the sdk type surface and generator registration.\n * Keep new built-in/module Request names here first, then reference these\n * constants from server decorators so the Protocol remains the source of truth.\n */\nexport const ProtocolMethod = {\n GetServerInfo: \"getServerInfo\",\n JsxRun: \"jsx:run\",\n JsxExecute: \"jsx:execute\",\n EventSubscribe: \"event:subscribe\",\n EventUnsubscribe: \"event:unsubscribe\",\n ActionAutoCutout: \"action:autoCutout\",\n ActionRemoveBackground: \"action:removeBackground\",\n LayerGetInfo: \"layer:getInfo\",\n LayerGetInfoById: \"layer:getInfoById\",\n LayerGetInfoByIndex: \"layer:getInfoByIndex\",\n DocumentCurrent: \"document:current\",\n DocumentExport: \"document:export\",\n DocumentSave: \"document:save\",\n ImageExportLayer: \"image:exportLayer\",\n ImageGetPreview: \"image:getPreview\",\n ImageExportDocument: \"image:exportDocument\",\n} as const;\nexport type ProtocolMethod = (typeof ProtocolMethod)[keyof typeof ProtocolMethod];\n\n/** Every method the server exposes, keyed by name -> { params, result }. */\nexport interface ProtocolMethods {\n [ProtocolMethod.GetServerInfo]: {\n params: Record<string, never>;\n result: ServerInfo;\n };\n [ProtocolMethod.JsxRun]: {\n params: { script: string };\n result: unknown;\n };\n [ProtocolMethod.JsxExecute]: {\n params: { name: string; params?: Record<string, unknown> };\n result: unknown;\n };\n [ProtocolMethod.EventSubscribe]: {\n params: { type: PhotoshopEventName };\n result: { ok: true };\n };\n [ProtocolMethod.EventUnsubscribe]: {\n params: { type: PhotoshopEventName };\n result: { ok: true };\n };\n // Feature-module methods (ADR 0006). The `Domain:action` namespace mirrors the\n // packaged jsx layout (`jsx/Action/<name>.jsx`) and keeps module methods from\n // colliding with built-ins as Document/Layer land. Plugin-specific methods\n // (e.g. SidePaint:*) are NOT declared here — a plugin ships its own method type\n // table with its package; callers reach them via the open\n // `Connection.invoke(method: string, params?)` overload or a plugin wrapper.\n [ProtocolMethod.ActionAutoCutout]: {\n params: Record<string, never>;\n result: boolean;\n };\n [ProtocolMethod.ActionRemoveBackground]: {\n params: Record<string, never>;\n result: { success: boolean };\n };\n [ProtocolMethod.LayerGetInfo]: {\n params?: {\n id?: number;\n index?: number;\n getChildren?: boolean;\n getGeneratorSettings?: boolean;\n };\n result: PsLayer;\n };\n [ProtocolMethod.LayerGetInfoById]: {\n params: { layerID: number; options?: { getChildren: boolean } };\n result: PsLayer;\n };\n [ProtocolMethod.LayerGetInfoByIndex]: {\n params: { layerIndex: number; options?: { getChildren: boolean } };\n result: PsLayer;\n };\n [ProtocolMethod.DocumentCurrent]: {\n params: Record<string, never>;\n result: PsDocument;\n };\n [ProtocolMethod.DocumentExport]: {\n params: { filePath: string } & Record<string, unknown>;\n result: unknown;\n };\n [ProtocolMethod.DocumentSave]: {\n params: { savePath?: string };\n result: unknown;\n };\n // Image module methods (RFC 0008). These return a wire-friendly\n // `WsImageResult` (a `data` string, not raw PNG bytes) so they cross the JSON\n // WS protocol cleanly — unlike the module-internal `ImageResult`, whose\n // `buffer` JSON-serializes to garbage. `settings` is widened to\n // `Record<string, unknown>` so the contract does not drag generator-core's\n // `GetPixmapSettings` namespace across the boundary.\n [ProtocolMethod.ImageExportLayer]: {\n params: { documentId?: number; layerSpec: LayerSpec; settings?: Record<string, unknown> };\n result: WsImageResult;\n };\n [ProtocolMethod.ImageGetPreview]: {\n params: { documentId?: number; layerSpec: number };\n result: WsImageResult;\n };\n [ProtocolMethod.ImageExportDocument]: {\n params: { documentId?: number; settings?: Record<string, unknown> };\n result: WsImageResult;\n };\n}\n\nexport type MethodName = keyof ProtocolMethods;\n\n/**\n * A layer spec: either a layer id, or an index range plus the indices of layers\n * to hide (the form Photoshop's `getLayerPixmap.jsx` accepts). Modeled here as a\n * wire type (RFC 0008) so the protocol is self-contained; the generator's image\n * module re-exports it for its plugin-facing API.\n */\nexport type LayerSpec =\n | number\n | { firstLayerIndex: number; lastLayerIndex: number; hidden: number[] };\n\nexport interface PsRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface PsLayer {\n id: number;\n index: number;\n name: string;\n type: number;\n visible: boolean;\n bounds: PsBounds;\n rect: PsRect;\n clip: boolean;\n children?: PsLayer[];\n}\n\nexport interface PsDocument {\n id: number;\n name: string;\n width: number;\n height: number;\n resolution: number;\n isDirty: boolean;\n filePath?: string;\n}\n\n/**\n * The result of an image `@ws` method (RFC 0008). `data` is an out-of-the-box\n * image string the client can drop straight into an `<img src>`:\n * `data:image/png;base64,...` when inlined, or `https://...` when a `CosService`\n * uploaded it. The client tells them apart by the `data`/`http` prefix — there\n * is deliberately no separate discriminator field. `bounds`/`width`/`height`\n * carry the same geometry as the module-internal `ImageResult`.\n */\nexport interface WsImageResult {\n data: string;\n bounds: PsBounds;\n width: number;\n height: number;\n}\n\nexport interface PsBounds {\n left: number;\n right: number;\n top: number;\n bottom: number;\n}\n\nexport interface ServerInfo {\n name: string;\n version: string;\n /** Photoshop version, when the server is connected to PS; omitted otherwise. */\n psVersion?: string;\n plugins?: PluginInfo[];\n}\n\nexport interface PluginInfo {\n id: string;\n}\n\nexport interface Bounds {\n top: number;\n left: number;\n bottom: number;\n right: number;\n}\n\nexport interface ImageChangedLayer {\n id: number;\n pixels?: boolean;\n removed?: boolean;\n bounds?: Bounds;\n}\n\nexport interface ImageChangedEvent {\n version: string;\n timeStamp: number;\n count: number;\n id: number;\n active?: boolean;\n file?: string;\n closed?: boolean;\n metaDataOnly?: boolean;\n selection?: number[];\n layers?: ImageChangedLayer[];\n}\n\nexport interface PhotoshopEventMap {\n workspaceChanged: string;\n toolChanged: string;\n quickMaskStateChanged: string;\n documentChanged: number;\n closedDocument: number;\n newDocumentViewCreated: number;\n activeViewChanged: number;\n currentDocumentChanged: number;\n backgroundColorChanged: string;\n foregroundColorChanged: string;\n imageChanged: ImageChangedEvent;\n}\n\nexport type PhotoshopEventName = keyof PhotoshopEventMap;\n\n/** A request envelope sent client -> server. */\nexport interface RequestEnvelope<M extends MethodName = MethodName> {\n id: string;\n method: M;\n params: ProtocolMethods[M][\"params\"];\n}\n\n/** A response envelope sent server -> client. */\nexport type ResponseEnvelope<M extends MethodName = MethodName> =\n | { id: string; ok: true; result: ProtocolMethods[M][\"result\"] }\n | { id: string; ok: false; error: ProtocolError };\n\n/**\n * Every server -> client push event, keyed by type -> data payload. Open-ended\n * (ADR 0006): declared keys are strongly typed; an undeclared `type` still flows\n * through the looser `on(type: string, ...)` / `EventEnvelope` overloads.\n */\nexport interface ProtocolEvents {\n /** Handshake: the first event after a socket opens, carrying the clientId. */\n connected: { clientId: string };\n workspaceChanged: PhotoshopEventMap[\"workspaceChanged\"];\n toolChanged: PhotoshopEventMap[\"toolChanged\"];\n quickMaskStateChanged: PhotoshopEventMap[\"quickMaskStateChanged\"];\n documentChanged: PhotoshopEventMap[\"documentChanged\"];\n closedDocument: PhotoshopEventMap[\"closedDocument\"];\n newDocumentViewCreated: PhotoshopEventMap[\"newDocumentViewCreated\"];\n activeViewChanged: PhotoshopEventMap[\"activeViewChanged\"];\n currentDocumentChanged: PhotoshopEventMap[\"currentDocumentChanged\"];\n backgroundColorChanged: PhotoshopEventMap[\"backgroundColorChanged\"];\n foregroundColorChanged: PhotoshopEventMap[\"foregroundColorChanged\"];\n imageChanged: PhotoshopEventMap[\"imageChanged\"];\n // Plugin-specific events (e.g. paint_changed/paint_closed) are NOT declared\n // here — a plugin ships its own event type table with its package. The loose\n // `on(type: string, ...)` / `EventEnvelope` overloads still carry undeclared\n // events.\n}\n\nexport type EventName = keyof ProtocolEvents;\n\n/** A one-way event envelope sent server -> client (no id, no response). */\nexport interface EventEnvelope<E extends EventName = EventName> {\n type: E;\n data: ProtocolEvents[E];\n}\n\nexport interface ProtocolError {\n /**\n * Error code. Server-level codes are values of `ErrorCode`; a plugin may throw\n * its own code (defined in its package), which the server surfaces verbatim\n * (open-ended contract, RFC 0006). Typed here as `string` to admit both.\n */\n code: string;\n message: string;\n}\n\n/**\n * Server-level error codes. Plugin-specific codes (e.g. SidePaint's\n * `PAINT_GONE`/`IMPORT_FAILED`/`VALUE_RESOLVE`/`UNSUPPORTED_SCHEME`) live in\n * their plugin package since RFC 0006 and are surfaced verbatim by the server.\n */\nexport const ErrorCode = {\n UnknownMethod: \"UNKNOWN_METHOD\",\n BadRequest: \"BAD_REQUEST\",\n Internal: \"INTERNAL\",\n} as const;\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n/**\n * Frame discriminators shared by both ends (ADR 0005). The three envelope kinds\n * are told apart by characteristic fields: Request has `method`, Response has a\n * boolean `ok`, Event has `type` and no `id`.\n */\nexport function isRequest(value: unknown): value is RequestEnvelope {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Record<string, unknown>;\n return typeof v.id === \"string\" && typeof v.method === \"string\";\n}\n\nexport function isResponse(value: unknown): value is ResponseEnvelope {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Record<string, unknown>;\n return typeof v.id === \"string\" && typeof v.ok === \"boolean\";\n}\n\nexport function isEvent(value: unknown): value is EventEnvelope {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Record<string, unknown>;\n return typeof v.type === \"string\" && v.id === undefined;\n}\n\n/** Decode a raw text frame. Throws on invalid JSON. Shared by both ends. */\nexport function parseFrame(data: string): unknown {\n return JSON.parse(data);\n}\n\n/** Encode a value into a text frame. Shared by both ends. */\nexport function serializeFrame(value: unknown): string {\n return JSON.stringify(value);\n}\n","/**\n * The minimal slice of a JSX runner the Photoshop DOM proxy depends on: run a\n * raw ExtendScript string and resolve its evaluation result. Defined locally\n * (not imported from the generator contract) so the proxy stays transport- and\n * host-agnostic and can be wired to any backend that can evaluate a script.\n *\n * The server's `JsxRunnerApi` satisfies this structurally (`plugin.jsx`), so a\n * plugin passes `this.jsx` straight in. A future client-side backend would\n * supply its own adapter.\n */\nexport interface PsJsxRunner {\n run<T = unknown>(script: string): Promise<T>;\n}\n\n/**\n * Evaluate an ExtendScript expression and JSON-parse its result.\n *\n * `run` returns the evaluation verbatim (a string), so wrapping the expression\n * in `JSON.stringify` on the ExtendScript side is what lets numbers, booleans,\n * strings, arrays and objects all cross the bridge with their real type instead\n * of arriving as untyped strings. `JSON` is available because the default\n * engine is primed with polyfills before any plugin runs.\n */\nexport function evalJson<T>(jsx: PsJsxRunner, expr: string): Promise<T> {\n return jsx.run<string>(`JSON.stringify(${expr})`).then((s) => JSON.parse(s) as T);\n}\n\n/**\n * Read a numeric property, coercing on the ExtendScript side first. Document\n * dimensions are `UnitValue` objects, not plain numbers; `Number(...)` collapses\n * them to their scalar before serialization.\n */\nexport function evalNumber(jsx: PsJsxRunner, expr: string): Promise<number> {\n return evalJson<number>(jsx, `Number(${expr})`);\n}\n\n/** Read a string property (coerced with `String(...)` for safety). */\nexport function evalString(jsx: PsJsxRunner, expr: string): Promise<string> {\n return evalJson<string>(jsx, `String(${expr})`);\n}\n\n/** Read a boolean property (coerced with `Boolean(...)`). */\nexport function evalBool(jsx: PsJsxRunner, expr: string): Promise<boolean> {\n return evalJson<boolean>(jsx, `Boolean(${expr})`);\n}\n","/**\n * Builds ExtendScript fragments from typed values.\n * @internal Used only inside `photoshop/`; not exported from the SDK.\n *\n * Responsibilities: escape string arguments against injection, serialize file\n * paths to `new File(path)`, pass enum strings through verbatim, and serialize\n * numbers, booleans and arrays.\n */\nexport class JsxBuilder {\n /**\n * Escape a string into a JSX string literal. `JSON.stringify` handles quotes,\n * newlines and Unicode.\n *\n * @example JsxBuilder.string(\"O'Brien\") // -> \"\\\"O'Brien\\\"\"\n */\n static string(value: string): string {\n return JSON.stringify(value);\n }\n\n /**\n * Serialize a path to an ExtendScript `File` constructor.\n *\n * @example JsxBuilder.file(\"/path/to/file.psd\") // -> 'new File(\"/path/to/file.psd\")'\n */\n static file(path: string): string {\n return `new File(${JSON.stringify(path)})`;\n }\n\n /** Serialize a number, rejecting NaN/Infinity. */\n static number(value: number): string {\n if (!isFinite(value)) {\n throw new Error(`JsxBuilder.number: invalid value ${value}`);\n }\n return String(value);\n }\n\n /** Serialize a boolean. */\n static boolean(value: boolean): string {\n return value ? \"true\" : \"false\";\n }\n\n /** Pass an enum string through (already in `EnumName.MEMBER` form). */\n static enum_(value: string): string {\n return value;\n }\n\n /**\n * Serialize a numeric array to a JSX array literal (bounds, crop, etc.).\n *\n * @example JsxBuilder.numberArray([0, 0, 100, 100]) // -> '[0,0,100,100]'\n */\n static numberArray(arr: number[]): string {\n return JSON.stringify(arr);\n }\n\n /** Serialize a 2-D numeric array (selection boundary points). */\n static regionArray(region: number[][]): string {\n return JSON.stringify(region);\n }\n\n /**\n * Build a method-call expression from pre-serialized args.\n *\n * @example JsxBuilder.call(\"app.open\", [JsxBuilder.file(path)])\n * // -> 'app.open(new File(\"/path/to/file.psd\"))'\n */\n static call(path: string, args: string[]): string {\n return `${path}(${args.join(\", \")})`;\n }\n\n /**\n * Build a property assignment statement.\n *\n * @example JsxBuilder.assign(\"app.activeDocument.activeLayer.name\", JsxBuilder.string(\"New Name\"))\n * // -> 'app.activeDocument.activeLayer.name = \"New Name\"'\n */\n static assign(path: string, value: string): string {\n return `${path} = ${value}`;\n }\n}\n","import type { PsJsxRunner } from \"./jsx-runner\";\nimport { evalNumber, evalString, evalBool, evalJson } from \"./jsx-runner\";\nimport { JsxBuilder } from \"./JsxBuilder\";\nimport type { BlendModeValue, AnchorPositionValue, ElementPlacementValue } from \"./enums\";\nimport type { PsBounds } from \"./types\";\n\n/**\n * Wraps an ExtendScript Layer / ArtLayer / LayerSet: the shared Layer\n * properties and methods plus ArtLayer-only members such as `kind`.\n *\n * @remarks\n * `activeLayer` may be an ArtLayer or a LayerSet. Read `typename` before\n * touching ArtLayer-only members:\n * - \"ArtLayer\" -> a normal layer, `kind` is valid\n * - \"LayerSet\" -> a group, `kind` is unavailable\n *\n * @example\n * const layer = this.photoshop.activeDocument.activeLayer;\n * const name = await layer.name;\n * await layer.setName(\"Background\");\n * await layer.setVisible(false);\n */\nexport class PhotoshopLayer {\n constructor(\n private readonly _jsx: PsJsxRunner,\n private readonly _path: string // e.g. \"app.activeDocument.activeLayer\"\n ) {}\n\n // --- Layer read-only properties -----------------------------------------\n\n /** Unique layer id. */\n get id(): Promise<number> {\n return evalNumber(this._jsx, `${this._path}.id`);\n }\n\n /** Layer name. */\n get name(): Promise<string> {\n return evalString(this._jsx, `${this._path}.name`);\n }\n\n /** Layer visibility. */\n get visible(): Promise<boolean> {\n return evalBool(this._jsx, `${this._path}.visible`);\n }\n\n /** Layer opacity (0-100). */\n get opacity(): Promise<number> {\n return evalNumber(this._jsx, `${this._path}.opacity`);\n }\n\n /** BlendMode code -> enum-name map (all 27 members, plus newer ones). */\n private static readonly _BLEND_MODE_MAP: Record<number, string> = {\n 1: \"PASSTHROUGH\",\n 2: \"NORMAL\",\n 3: \"DISSOLVE\",\n 4: \"DARKEN\",\n 5: \"MULTIPLY\",\n 6: \"COLORBURN\",\n 7: \"LINEARBURN\",\n 8: \"LIGHTEN\",\n 9: \"SCREEN\",\n 10: \"COLORDODGE\",\n 11: \"LINEARDODGE\",\n 12: \"OVERLAY\",\n 13: \"SOFTLIGHT\",\n 14: \"HARDLIGHT\",\n 15: \"VIVIDLIGHT\",\n 16: \"LINEARLIGHT\",\n 17: \"PINLIGHT\",\n 18: \"DIFFERENCE\",\n 19: \"EXCLUSION\",\n 20: \"HUE\",\n 21: \"SATURATION\",\n 22: \"COLORBLEND\",\n 23: \"LUMINOSITY\",\n 26: \"HARDMIX\",\n 27: \"SUBTRACT\",\n 28: \"DARKERCOLOR\",\n 29: \"LIGHTERCOLOR\",\n 30: \"DIVIDE\",\n };\n\n /**\n * Blend mode as an enum-name string (e.g. \"BlendMode.NORMAL\"). ExtendScript\n * yields the numeric code; the static map turns it into a readable name.\n */\n get blendMode(): Promise<string> {\n return evalNumber(this._jsx, `${this._path}.blendMode`).then(\n (code) => PhotoshopLayer._BLEND_MODE_MAP[code] ?? `BlendMode.UNKNOWN_${code}`\n );\n }\n\n /** Whether the layer is fully locked. */\n get allLocked(): Promise<boolean> {\n return evalBool(this._jsx, `${this._path}.allLocked`);\n }\n\n /**\n * Layer bounds `[left, top, right, bottom]`.\n *\n * @remarks Units follow `rulerUnits`; values are not pixels unless it is\n * `Units.PIXELS`.\n */\n get bounds(): Promise<PsBounds> {\n const expr = `(function(){ var b = ${this._path}.bounds; return [b[0], b[1], b[2], b[3]]; })()`;\n return evalJson<PsBounds>(this._jsx, expr);\n }\n\n // --- ArtLayer-only properties -------------------------------------------\n\n /** LayerKind code -> enum-name map. */\n private static readonly _LAYER_KIND_MAP: Record<number, string> = {\n 1: \"NORMAL\",\n 2: \"TEXT\",\n 3: \"SOLIDFILL\",\n 4: \"GRADIENTFILL\",\n 5: \"LEVELS\",\n 6: \"CURVES\",\n 7: \"COLORBALANCE\",\n 8: \"HUESATURATION\",\n 9: \"BRIGHTNESSCONTRAST\",\n 10: \"THRESHOLD\",\n 11: \"POSTERIZE\",\n 12: \"CHANNELMIXER\",\n 13: \"GRADIENTMAP\",\n 14: \"INVERSION\",\n 15: \"EXPOSURE\",\n 16: \"PHOTOFILTER\",\n 17: \"SELECTIVECOLOR\",\n 18: \"SMARTOBJECT\",\n 20: \"VIBRANCE\",\n 21: \"VIDEO\",\n 22: \"BLACKANDWHITE\",\n 23: \"LAYER3D\",\n 26: \"COLORLOOKUP\",\n };\n\n /**\n * Layer kind as an enum-name string (e.g. \"LayerKind.NORMAL\"). ArtLayer only;\n * reading it on a LayerSet throws. Check `typename` first.\n *\n * @remarks GRADIENTFILL=4 and PATTERNFILL=4 collide in Adobe's enums, so a\n * kind of 4 always maps to GRADIENTFILL.\n */\n get kind(): Promise<string> {\n return evalNumber(this._jsx, `${this._path}.kind`).then(\n (code) => PhotoshopLayer._LAYER_KIND_MAP[code] ?? `LayerKind.UNKNOWN_${code}`\n );\n }\n\n /** Object type name (\"ArtLayer\" or \"LayerSet\"). */\n get typename(): Promise<string> {\n return evalString(this._jsx, `${this._path}.typename`);\n }\n\n // --- Property writes -----------------------------------------------------\n\n /** Set the layer name. */\n async setName(value: string): Promise<void> {\n await this._jsx.run(JsxBuilder.assign(`${this._path}.name`, JsxBuilder.string(value)));\n }\n\n /** Set layer visibility. */\n async setVisible(value: boolean): Promise<void> {\n await this._jsx.run(JsxBuilder.assign(`${this._path}.visible`, JsxBuilder.boolean(value)));\n }\n\n /** Set layer opacity (0-100). */\n async setOpacity(value: number): Promise<void> {\n await this._jsx.run(JsxBuilder.assign(`${this._path}.opacity`, JsxBuilder.number(value)));\n }\n\n /**\n * Set the blend mode.\n *\n * @example\n * import { BlendMode } from \"@ps-generator-bridge/sdk/plugin\";\n * await layer.setBlendMode(BlendMode.MULTIPLY);\n */\n async setBlendMode(value: BlendModeValue): Promise<void> {\n await this._jsx.run(JsxBuilder.assign(`${this._path}.blendMode`, JsxBuilder.enum_(value)));\n }\n\n /** Set whether the layer is fully locked. */\n async setAllLocked(value: boolean): Promise<void> {\n await this._jsx.run(JsxBuilder.assign(`${this._path}.allLocked`, JsxBuilder.boolean(value)));\n }\n\n // --- Methods -------------------------------------------------------------\n\n /** Delete this layer. */\n async remove(): Promise<void> {\n await this._jsx.run(`${this._path}.remove()`);\n }\n\n /** Duplicate this layer (the copy becomes `activeLayer`). */\n async duplicate(): Promise<PhotoshopLayer> {\n await this._jsx.run(`${this._path}.duplicate()`);\n return new PhotoshopLayer(this._jsx, \"app.activeDocument.activeLayer\");\n }\n\n /**\n * Move this layer relative to another.\n *\n * @param relativeObjectJsxPath JSX path of the reference layer (e.g.\n * \"app.activeDocument.layers[0]\").\n * @param insertionLocation placement enum.\n *\n * @remarks Pass a bare JSX path expression. A `PhotoshopLayers.getByName()`\n * path contains quotes and cannot be used as a reference expression here.\n *\n * @example\n * import { ElementPlacement } from \"@ps-generator-bridge/sdk/plugin\";\n * await layer.move(\"app.activeDocument.layers[0]\", ElementPlacement.PLACEBEFORE);\n */\n async move(\n relativeObjectJsxPath: string,\n insertionLocation: ElementPlacementValue\n ): Promise<void> {\n await this._jsx.run(\n `${this._path}.move(${relativeObjectJsxPath}, ${JsxBuilder.enum_(insertionLocation)})`\n );\n }\n\n /** Translate the layer by a pixel delta. */\n async translate(deltaX: number, deltaY: number): Promise<void> {\n await this._jsx.run(\n JsxBuilder.call(`${this._path}.translate`, [\n JsxBuilder.number(deltaX),\n JsxBuilder.number(deltaY),\n ])\n );\n }\n\n /**\n * Scale the layer.\n *\n * @param horizontal horizontal scale percent (150 = 150%).\n * @param vertical vertical scale percent.\n * @param anchor scaling anchor (optional).\n */\n async resize(horizontal: number, vertical: number, anchor?: AnchorPositionValue): Promise<void> {\n const args: string[] = [JsxBuilder.number(horizontal), JsxBuilder.number(vertical)];\n if (anchor !== undefined) args.push(JsxBuilder.enum_(anchor));\n await this._jsx.run(JsxBuilder.call(`${this._path}.resize`, args));\n }\n\n /**\n * Rotate the layer.\n *\n * @param angle degrees, clockwise positive.\n * @param anchor rotation anchor (optional).\n */\n async rotate(angle: number, anchor?: AnchorPositionValue): Promise<void> {\n const args: string[] = [JsxBuilder.number(angle)];\n if (anchor !== undefined) args.push(JsxBuilder.enum_(anchor));\n await this._jsx.run(JsxBuilder.call(`${this._path}.rotate`, args));\n }\n\n /** Move the layer to the end of its stack. */\n async moveToEnd(): Promise<void> {\n await this._jsx.run(`${this._path}.moveToEnd()`);\n }\n}\n","import type { PsJsxRunner } from \"./jsx-runner\";\nimport { evalNumber } from \"./jsx-runner\";\nimport { JsxBuilder } from \"./JsxBuilder\";\nimport { PhotoshopLayer } from \"./PhotoshopLayer\";\n\n/**\n * Wraps an ExtendScript Layers collection (`Document.layers` or\n * `LayerSet.layers`).\n *\n * @example\n * const layers = this.photoshop.activeDocument.layers;\n * const count = await layers.length;\n * const first = layers.at(0);\n * const named = layers.getByName(\"Background\");\n */\nexport class PhotoshopLayers {\n constructor(\n private readonly _jsx: PsJsxRunner,\n private readonly _path: string // e.g. \"app.activeDocument.layers\"\n ) {}\n\n /** Number of layers in the collection. */\n get length(): Promise<number> {\n return evalNumber(this._jsx, `${this._path}.length`);\n }\n\n /**\n * Access a layer by index. The collection is 0-based, matching JavaScript;\n * `layers[0]` is the top-most layer.\n */\n at(index: number): PhotoshopLayer {\n return new PhotoshopLayer(this._jsx, `${this._path}[${index}]`);\n }\n\n /**\n * Look up a layer by name (case-sensitive). The returned wrapper works for\n * property reads/writes but its path contains a `getByName(...)` call, so it\n * must not be passed as `PhotoshopLayer.move()`'s reference path.\n */\n getByName(name: string): PhotoshopLayer {\n const escapedName = JsxBuilder.string(name);\n return new PhotoshopLayer(this._jsx, `${this._path}.getByName(${escapedName})`);\n }\n}\n","import type { PsJsxRunner } from \"./jsx-runner\";\nimport { evalBool, evalJson } from \"./jsx-runner\";\nimport { JsxBuilder } from \"./JsxBuilder\";\nimport type { SelectionTypeValue } from \"./enums\";\nimport type { PsBounds } from \"./types\";\n\n/**\n * Wraps `Document.selection`.\n *\n * @example\n * const sel = this.photoshop.activeDocument.selection;\n * await sel.selectAll();\n * const bounds = await sel.bounds;\n * await sel.deselect();\n */\nexport class PhotoshopSelection {\n constructor(\n private readonly _jsx: PsJsxRunner,\n private readonly _path: string // e.g. \"app.activeDocument.selection\"\n ) {}\n\n /**\n * Selection bounds `[left, top, right, bottom]`. Throws when there is no\n * selection.\n *\n * @remarks Units follow `rulerUnits`.\n */\n get bounds(): Promise<PsBounds> {\n const expr = `(function(){ var b = ${this._path}.bounds; return [b[0], b[1], b[2], b[3]]; })()`;\n return evalJson<PsBounds>(this._jsx, expr);\n }\n\n /** Whether the selection is a solid (un-feathered) rectangle. */\n get solid(): Promise<boolean> {\n return evalBool(this._jsx, `${this._path}.solid`);\n }\n\n // --- Methods -------------------------------------------------------------\n\n /** Select the whole canvas. */\n async selectAll(): Promise<void> {\n await this._jsx.run(`${this._path}.selectAll()`);\n }\n\n /** Deselect. */\n async deselect(): Promise<void> {\n await this._jsx.run(`${this._path}.deselect()`);\n }\n\n /** Invert the selection. */\n async invert(): Promise<void> {\n await this._jsx.run(`${this._path}.invert()`);\n }\n\n /**\n * Create a selection from a region of points.\n *\n * @param region polygon points, e.g. `[[0,0],[100,0],[100,100],[0,100]]`.\n * @param type selection operation (optional, defaults to replace).\n * @param feather feather radius in pixels (optional).\n * @param antiAlias anti-alias the edges (optional).\n *\n * @example\n * import { SelectionType } from \"@ps-generator-bridge/sdk/plugin\";\n * await sel.select([[0,0],[100,0],[100,100],[0,100]], SelectionType.REPLACE, 0, true);\n */\n async select(\n region: number[][],\n type?: SelectionTypeValue,\n feather?: number,\n antiAlias?: boolean\n ): Promise<void> {\n const args: string[] = [JsxBuilder.regionArray(region)];\n if (type !== undefined) args.push(JsxBuilder.enum_(type));\n if (feather !== undefined) args.push(JsxBuilder.number(feather));\n if (antiAlias !== undefined) args.push(JsxBuilder.boolean(antiAlias));\n await this._jsx.run(JsxBuilder.call(`${this._path}.select`, args));\n }\n\n /** Grow the selection by `by` pixels. */\n async expand(by: number): Promise<void> {\n await this._jsx.run(JsxBuilder.call(`${this._path}.expand`, [JsxBuilder.number(by)]));\n }\n\n /** Shrink the selection by `by` pixels. */\n async contract(by: number): Promise<void> {\n await this._jsx.run(JsxBuilder.call(`${this._path}.contract`, [JsxBuilder.number(by)]));\n }\n\n /** Feather the selection edge by `by` pixels. */\n async feather(by: number): Promise<void> {\n await this._jsx.run(JsxBuilder.call(`${this._path}.feather`, [JsxBuilder.number(by)]));\n }\n\n /** Translate the selection boundary (content stays put). */\n async translateBoundary(deltaX: number, deltaY: number): Promise<void> {\n await this._jsx.run(\n JsxBuilder.call(`${this._path}.translateBoundary`, [\n JsxBuilder.number(deltaX),\n JsxBuilder.number(deltaY),\n ])\n );\n }\n}\n","import type { PsJsxRunner } from \"./jsx-runner\";\nimport { evalNumber, evalString, evalBool, evalJson } from \"./jsx-runner\";\nimport { JsxBuilder } from \"./JsxBuilder\";\nimport { PhotoshopLayer } from \"./PhotoshopLayer\";\nimport { PhotoshopLayers } from \"./PhotoshopLayers\";\nimport { PhotoshopSelection } from \"./PhotoshopSelection\";\nimport type { SaveOptionsValue } from \"./enums\";\nimport type { PsBounds } from \"./types\";\n\n/**\n * Wraps an ExtendScript Document.\n *\n * @example\n * const doc = this.photoshop.activeDocument;\n * const name = await doc.name;\n * const [width, height] = await Promise.all([doc.width, doc.height]);\n * await doc.save();\n */\nexport class PhotoshopDocument {\n constructor(\n private readonly _jsx: PsJsxRunner,\n private readonly _path: string // e.g. \"app.activeDocument\"\n ) {}\n\n // --- Read-only properties -----------------------------------------------\n\n /** Document name (file name, without directory). */\n get name(): Promise<string> {\n return evalString(this._jsx, `${this._path}.name`);\n }\n\n /** Unique document id. */\n get id(): Promise<number> {\n return evalNumber(this._jsx, `${this._path}.id`);\n }\n\n /**\n * Document width.\n *\n * @remarks The unit follows Photoshop's current `app.preferences.rulerUnits`.\n * For guaranteed pixels, set `rulerUnits` to `Units.PIXELS` first (e.g. via\n * `this.jsx.run(...)`).\n */\n get width(): Promise<number> {\n return evalNumber(this._jsx, `${this._path}.width`);\n }\n\n /**\n * Document height.\n *\n * @remarks The unit follows `rulerUnits` (see {@link width}).\n */\n get height(): Promise<number> {\n return evalNumber(this._jsx, `${this._path}.height`);\n }\n\n /** Document resolution (PPI). */\n get resolution(): Promise<number> {\n return evalNumber(this._jsx, `${this._path}.resolution`);\n }\n\n /** Document color mode as an enum-name string (e.g. \"DocumentMode.RGB\"). */\n get mode(): Promise<string> {\n const expr = `(function(){\n var m = ${this._path}.mode;\n if (m === DocumentMode.RGB) return \"DocumentMode.RGB\";\n if (m === DocumentMode.CMYK) return \"DocumentMode.CMYK\";\n if (m === DocumentMode.GRAYSCALE) return \"DocumentMode.GRAYSCALE\";\n if (m === DocumentMode.LAB) return \"DocumentMode.LAB\";\n if (m === DocumentMode.BITMAP) return \"DocumentMode.BITMAP\";\n if (m === DocumentMode.INDEXEDCOLOR) return \"DocumentMode.INDEXEDCOLOR\";\n if (m === DocumentMode.MULTICHANNEL) return \"DocumentMode.MULTICHANNEL\";\n if (m === DocumentMode.DUOTONE) return \"DocumentMode.DUOTONE\";\n return String(m);\n })()`;\n return evalJson<string>(this._jsx, expr);\n }\n\n /** Whether the document is saved since its last change. */\n get saved(): Promise<boolean> {\n return evalBool(this._jsx, `${this._path}.saved`);\n }\n\n /**\n * Full document path (native `fsName`). For an unsaved document this may\n * return a temporary path or throw.\n */\n get fullName(): Promise<string> {\n return evalString(this._jsx, `${this._path}.fullName.fsName`);\n }\n\n /** Directory containing the document (native `fsName`). */\n get path(): Promise<string> {\n return evalString(this._jsx, `${this._path}.path.fsName`);\n }\n\n // --- Child navigation (synchronous; no request) -------------------------\n\n /** The active layer. */\n get activeLayer(): PhotoshopLayer {\n return new PhotoshopLayer(this._jsx, `${this._path}.activeLayer`);\n }\n\n /** The Layers collection (ArtLayers + LayerSets). */\n get layers(): PhotoshopLayers {\n return new PhotoshopLayers(this._jsx, `${this._path}.layers`);\n }\n\n /** The selection. */\n get selection(): PhotoshopSelection {\n return new PhotoshopSelection(this._jsx, `${this._path}.selection`);\n }\n\n // --- Methods -------------------------------------------------------------\n\n /** Save the document in its current format. */\n async save(): Promise<void> {\n await this._jsx.run(`${this._path}.save()`);\n }\n\n /**\n * Close the document.\n *\n * @param saving save behavior before closing (defaults to not saving).\n *\n * @example\n * import { SaveOptions } from \"@ps-generator-bridge/sdk/plugin\";\n * await doc.close(SaveOptions.DONOTSAVECHANGES);\n */\n async close(saving: SaveOptionsValue = \"SaveOptions.DONOTSAVECHANGES\"): Promise<void> {\n await this._jsx.run(JsxBuilder.call(`${this._path}.close`, [JsxBuilder.enum_(saving)]));\n }\n\n /**\n * Save to a path. Mirrors ExtendScript\n * `saveAs(saveIn, options?, asCopy?, extensionType?)`; only `saveIn` and\n * `asCopy` are exposed, `options` is undefined and `extensionType` is left to\n * the Photoshop default.\n *\n * @param saveIn destination path.\n * @param asCopy save as a copy (does not change the document's saved state).\n */\n async saveAs(saveIn: string, asCopy?: boolean): Promise<void> {\n const script = `${this._path}.saveAs(${JsxBuilder.file(saveIn)}${\n asCopy !== undefined ? `, undefined, ${JsxBuilder.boolean(asCopy)}` : \"\"\n })`;\n await this._jsx.run(script);\n }\n\n /** Flatten all layers into a single background layer. */\n async flatten(): Promise<void> {\n await this._jsx.run(`${this._path}.flatten()`);\n }\n\n /** Merge all visible layers. */\n async mergeVisibleLayers(): Promise<void> {\n await this._jsx.run(`${this._path}.mergeVisibleLayers()`);\n }\n\n /** Rasterize all layers. */\n async rasterizeAllLayers(): Promise<void> {\n await this._jsx.run(`${this._path}.rasterizeAllLayers()`);\n }\n\n /**\n * Duplicate the document.\n *\n * @param name optional name for the copy.\n * @returns the duplicated document.\n *\n * @remarks Assumes `duplicate()` makes the copy the active document, so the\n * result points at `app.activeDocument`.\n */\n async duplicate(name?: string): Promise<PhotoshopDocument> {\n const args = name !== undefined ? [JsxBuilder.string(name)] : [];\n await this._jsx.run(JsxBuilder.call(`${this._path}.duplicate`, args));\n return new PhotoshopDocument(this._jsx, \"app.activeDocument\");\n }\n\n /**\n * Resize the canvas.\n *\n * @param width new width in pixels.\n * @param height new height in pixels.\n * @param anchor anchor position (optional, defaults to center).\n *\n * @example\n * import { AnchorPosition } from \"@ps-generator-bridge/sdk/plugin\";\n * await doc.resizeCanvas(1920, 1080, AnchorPosition.MIDDLECENTER);\n */\n async resizeCanvas(width: number, height: number, anchor?: string): Promise<void> {\n const args: string[] = [JsxBuilder.number(width), JsxBuilder.number(height)];\n if (anchor !== undefined) args.push(JsxBuilder.enum_(anchor));\n await this._jsx.run(JsxBuilder.call(`${this._path}.resizeCanvas`, args));\n }\n\n /**\n * Resize the image.\n *\n * @param width new width in pixels (optional).\n * @param height new height in pixels (optional).\n * @param resolution new resolution in PPI (optional).\n */\n async resizeImage(width?: number, height?: number, resolution?: number): Promise<void> {\n const args: string[] = [\n width !== undefined ? JsxBuilder.number(width) : \"undefined\",\n height !== undefined ? JsxBuilder.number(height) : \"undefined\",\n resolution !== undefined ? JsxBuilder.number(resolution) : \"undefined\",\n ];\n await this._jsx.run(JsxBuilder.call(`${this._path}.resizeImage`, args));\n }\n\n /** Rotate the canvas by `angle` degrees. */\n async rotateCanvas(angle: number): Promise<void> {\n await this._jsx.run(JsxBuilder.call(`${this._path}.rotateCanvas`, [JsxBuilder.number(angle)]));\n }\n\n /**\n * Crop the document to `bounds` `[left, top, right, bottom]` (pixels).\n *\n * @remarks Only `bounds` is exposed; ExtendScript `crop()` also takes angle,\n * width and height — reach those via `this.jsx.run(...)` if needed.\n */\n async crop(bounds: PsBounds): Promise<void> {\n const script = `${this._path}.crop(${JsxBuilder.numberArray(Array.from(bounds))})`;\n await this._jsx.run(script);\n }\n}\n","import type { PsJsxRunner } from \"./jsx-runner\";\nimport { evalString, evalJson } from \"./jsx-runner\";\nimport { JsxBuilder } from \"./JsxBuilder\";\nimport { PhotoshopDocument } from \"./PhotoshopDocument\";\nimport type { PsColor } from \"./types\";\n\n/**\n * Wraps the ExtendScript global `app` object.\n *\n * @example\n * const version = await this.photoshop.app.version; // \"25.0\"\n * await this.photoshop.app.open(\"/path/to/design.psd\");\n */\nexport class PhotoshopApp {\n private readonly _path = \"app\";\n\n constructor(private readonly _jsx: PsJsxRunner) {}\n\n // --- Read-only properties -----------------------------------------------\n\n /** Photoshop version (e.g. \"25.0\"). */\n get version(): Promise<string> {\n return evalString(this._jsx, `${this._path}.version`);\n }\n\n /** Application locale (e.g. \"zh_CN\"). */\n get locale(): Promise<string> {\n return evalString(this._jsx, `${this._path}.locale`);\n }\n\n /** Application name (e.g. \"Adobe Photoshop\"). */\n get name(): Promise<string> {\n return evalString(this._jsx, `${this._path}.name`);\n }\n\n /** Internal build number. */\n get build(): Promise<string> {\n return evalString(this._jsx, `${this._path}.build`);\n }\n\n /**\n * Install path (native `fsName`). `app.path` is a File in ExtendScript, so the\n * string comes from `.fsName`.\n */\n get path(): Promise<string> {\n return evalString(this._jsx, `${this._path}.path.fsName`);\n }\n\n /**\n * Current foreground color (RGB).\n *\n * @remarks The first version returns only the RGB approximation; in CMYK/Lab\n * documents this is Photoshop's converted RGB and may lose precision. The\n * `cmyk` field is reserved and currently always undefined.\n */\n get foregroundColor(): Promise<PsColor> {\n const expr = `(function(){\n var c = ${this._path}.foregroundColor;\n return {\n model: \"rgb\",\n rgb: { red: c.rgb.red, green: c.rgb.green, blue: c.rgb.blue, hexValue: c.rgb.hexValue }\n };\n })()`;\n return evalJson<PsColor>(this._jsx, expr);\n }\n\n /** Shortcut for `activeDocument` reached through the `app` path. */\n get activeDocument(): PhotoshopDocument {\n return new PhotoshopDocument(this._jsx, `${this._path}.activeDocument`);\n }\n\n // --- Methods -------------------------------------------------------------\n\n /**\n * Open a file and return its Document wrapper. The opened document becomes the\n * active document.\n *\n * @param filePath native or POSIX path.\n *\n * @example\n * const doc = await this.photoshop.app.open(\"/Users/me/design.psd\");\n */\n async open(filePath: string): Promise<PhotoshopDocument> {\n const script = JsxBuilder.call(`${this._path}.open`, [JsxBuilder.file(filePath)]);\n await this._jsx.run(script);\n return new PhotoshopDocument(this._jsx, `${this._path}.activeDocument`);\n }\n\n /** Emit a beep. */\n async beep(): Promise<void> {\n await this._jsx.run(`${this._path}.beep()`);\n }\n}\n","import type { PsJsxRunner } from \"./jsx-runner\";\nimport { PhotoshopApp } from \"./PhotoshopApp\";\nimport { PhotoshopDocument } from \"./PhotoshopDocument\";\n\n/**\n * Entry point of the Photoshop DOM proxy. A plugin reaches it through\n * `this.photoshop`:\n *\n * ```ts\n * const version = await this.photoshop.app.version;\n * const name = await this.photoshop.activeDocument.name;\n * ```\n *\n * Transport-agnostic: every property read and method call lowers to an\n * ExtendScript string run through the injected {@link PsJsxRunner}. The proxy\n * holds no PS state of its own.\n *\n * @remarks\n * - `app` maps to the ExtendScript global `app` (Application).\n * - `activeDocument` is a shortcut for `app.activeDocument`.\n * - With no active document, reading any property of `activeDocument` throws.\n */\nexport class PsPhotoshopProxy {\n /** Application wrapper; its path is fixed to \"app\". */\n readonly app: PhotoshopApp;\n\n private readonly _jsx: PsJsxRunner;\n\n constructor(jsx: PsJsxRunner) {\n this._jsx = jsx;\n this.app = new PhotoshopApp(this._jsx);\n }\n\n /**\n * The active document (shortcut for `app.activeDocument`). A fresh wrapper is\n * created on each access; wrappers are lightweight and stateless.\n */\n get activeDocument(): PhotoshopDocument {\n return new PhotoshopDocument(this._jsx, \"app.activeDocument\");\n }\n}\n","import {\n ErrorCode,\n isRequest,\n type RequestEnvelope,\n type ResponseEnvelope,\n} from \"@ps-generator-bridge/sdk\";\nimport type { MethodHandler } from \"@ps-generator-bridge/sdk/plugin\";\nimport type { PsGenerator } from \"../types/generator\";\nimport type { JsxRunnerApi } from \"../utilis/jsxRunner\";\n\nexport interface ConnectionSession {\n readonly clientId: string;\n subscribe(type: string): void;\n unsubscribe(type: string): void;\n}\n\n/** What method handlers receive: the injected PS generator + future additions. */\nexport interface HandlerContext {\n generator: PsGenerator;\n jsx?: JsxRunnerApi;\n session?: ConnectionSession;\n}\n\n/** Build an UnknownMethod response envelope for a request frame. */\nexport function unknownMethodResponse(id: string, method: string): ResponseEnvelope {\n return {\n id,\n ok: false,\n error: { code: ErrorCode.UnknownMethod, message: `Unknown method: ${method}` },\n };\n}\n\n/**\n * Run one request handler and wrap its result (or thrown error) in a response\n * envelope. Shared by the global Registry and the per-plugin scoped table\n * (RFC 0004) so error-code passthrough stays consistent.\n *\n * Open-ended (ADR 0006 / RFC 0006): a handler may throw a typed Error carrying a\n * string `code`; any string code is surfaced verbatim so external plugins can\n * define their own codes (e.g. SidePaint's `PAINT_GONE`) without the server\n * needing to know them. Errors without a string `code` fall back to INTERNAL.\n */\nexport async function runMethod(\n handler: MethodHandler,\n message: RequestEnvelope,\n ctx: HandlerContext\n): Promise<ResponseEnvelope> {\n try {\n const result = await handler(message.params, ctx);\n // Open-ended contract (ADR 0006): result type is unknown at this layer; the\n // SDK re-applies strong types for declared methods.\n return { id: message.id, ok: true, result } as ResponseEnvelope;\n } catch (error) {\n const thrown = error instanceof Error ? error : new Error(String(error));\n const code = (thrown as { code?: unknown }).code;\n const resolvedCode = typeof code === \"string\" ? code : ErrorCode.Internal;\n return {\n id: message.id,\n ok: false,\n error: {\n code: resolvedCode,\n message: thrown.message,\n },\n };\n }\n}\n\n/** Re-exported for the server's WS handler (frame discrimination). */\nexport { isRequest };\n","import { isRequest, type ResponseEnvelope } from \"@ps-generator-bridge/sdk\";\nimport type { MethodHandler } from \"@ps-generator-bridge/sdk/plugin\";\nimport { runMethod, type HandlerContext } from \"./dispatch\";\n\n/**\n * Shared Request method table for global and scoped dispatch. The adapters keep\n * their miss behaviour: global Registry turns a miss into UNKNOWN_METHOD, while\n * ScopedRegistry returns undefined so callers can fall back.\n */\nexport class MethodTable {\n private readonly methods = new Map<string, MethodHandler>();\n\n register(name: string, handler: MethodHandler): void {\n this.methods.set(name, handler);\n }\n\n async tryDispatch(message: unknown, ctx: HandlerContext): Promise<ResponseEnvelope | undefined> {\n if (!isRequest(message)) return undefined;\n const handler = this.methods.get(message.method);\n if (!handler) return undefined;\n return runMethod(handler, message, ctx);\n }\n}\n","import type { HTTPMethods, RouteHandlerMethod } from \"fastify\";\nimport { isRequest, type ResponseEnvelope } from \"@ps-generator-bridge/sdk\";\nimport type { AssemblyTarget, MethodHandler, ApiRouteSpec } from \"@ps-generator-bridge/sdk/plugin\";\nimport { unknownMethodResponse, type HandlerContext } from \"./dispatch\";\nimport type { FastifyInstance } from \"fastify\";\nimport { MethodTable } from \"./methodTable\";\n\n/**\n * Assembly seam between modules/builtins and the server (ADR 0006 / RFC 0004).\n * Holds the **global** WS Request method table (modules + builtins, including\n * `getServerInfo`) and forwards HTTP routes to fastify. This is the global\n * fallback for per-plugin dispatch: a `/ws/{pluginId}` connection tries the\n * plugin's scoped table first, then falls back here.\n *\n * HTTP routes may only be registered before `listen()` (fastify limitation); WS\n * methods may be added at runtime. Implements the SDK `AssemblyTarget` so\n * `bootstrap(module, registry)` (from `@ps-generator-bridge/sdk/plugin`) works\n * against the same shape the per-plugin scoped assembler implements.\n */\nexport class Registry implements AssemblyTarget {\n private readonly methods = new MethodTable();\n\n /**\n * Reserved first path segments (plugin ids). Set by the plugin after plugins\n * are registered and before modules bootstrap, so a module `@api` whose first\n * segment collides with a plugin id fails loud at init (RFC 0004).\n */\n reservedSegments: Set<string> = new Set();\n\n constructor(private readonly app: FastifyInstance) {}\n\n /** Register (or replace) a WS Request handler. Runtime-capable. */\n registerMethod(method: string, handler: MethodHandler): void {\n this.methods.register(method, handler);\n }\n\n /**\n * Register an HTTP route. Must run before `listen()` (fastify). The handler is\n * the devkit's opaque `ApiHandler`; cast to fastify's `RouteHandlerMethod` at\n * this boundary. Throws if the route's first segment is a reserved plugin id.\n */\n registerApi(route: ApiRouteSpec): void {\n const first = firstSegment(route.url);\n if (first !== undefined && this.reservedSegments.has(first)) {\n throw new Error(`module @api '${route.url}' collides with reserved plugin id '${first}'`);\n }\n this.app.route({\n method: route.method as HTTPMethods | HTTPMethods[],\n url: route.url,\n handler: route.handler as RouteHandlerMethod,\n });\n }\n\n /**\n * Route one parsed frame to its method handler, producing a response envelope.\n * Returns `undefined` for non-request frames (nothing to respond to). This is\n * the global fallback; per-plugin connections try the scoped table first.\n */\n async dispatch(message: unknown, ctx: HandlerContext): Promise<ResponseEnvelope | undefined> {\n if (!isRequest(message)) {\n return undefined;\n }\n const response = await this.methods.tryDispatch(message, ctx);\n if (!response) {\n return unknownMethodResponse(message.id, message.method);\n }\n return response;\n }\n}\n\n/** The first non-empty path segment of a URL, or `undefined` for a bare root. */\nfunction firstSegment(url: string): string | undefined {\n const match = url.match(/^\\/([^/?#]+)/);\n return match ? (match[1] as string) : undefined;\n}\n","// Plugin identity surfaced over the protocol (getServerInfo) and in the PS menu.\nexport const PLUGIN_NAME = \"PS Generator Bridge Service\";\nexport const PLUGIN_VERSION = \"0.1.0\";\n","import { ErrorCode, ProtocolMethod } from \"@ps-generator-bridge/sdk\";\nimport { PLUGIN_NAME, PLUGIN_VERSION } from \"../meta\";\nimport type { Registry } from \"./registry\";\nimport type { HandlerContext } from \"./dispatch\";\nimport type { PluginInfo } from \"./pluginManager\";\n\n/**\n * Register the server's built-in protocol methods — always available, independent\n * of any module or plugin. `getServerInfo` is the minimal vertical slice\n * (protocol -> dispatch -> injected generator) and, since RFC 0004, also carries\n * the loaded-plugin discovery list.\n */\nexport function registerBuiltins(registry: Registry, plugins: () => PluginInfo[]): void {\n registry.registerMethod(ProtocolMethod.GetServerInfo, async (_params, ctx) => {\n const { generator } = ctx as HandlerContext;\n let psVersion: string | undefined;\n try {\n psVersion = await generator.getPhotoshopVersion();\n } catch {\n // Not connected to PS (e.g. the standalone dev-server) — omit psVersion.\n psVersion = undefined;\n }\n return { name: PLUGIN_NAME, version: PLUGIN_VERSION, psVersion, plugins: plugins() };\n });\n registry.registerMethod(ProtocolMethod.JsxRun, async (params, ctx) => {\n const context = ctx as HandlerContext;\n const { script } = params as { script?: unknown };\n if (typeof script !== \"string\") throw badRequest(\"script is required\");\n if (!context.jsx) throw badRequest(\"jsx is not available\");\n return context.jsx.run(script);\n });\n registry.registerMethod(ProtocolMethod.JsxExecute, async (params, ctx) => {\n const context = ctx as HandlerContext;\n const { name, params: jsxParams } = params as {\n name?: unknown;\n params?: Record<string, unknown>;\n };\n if (typeof name !== \"string\") throw badRequest(\"name is required\");\n if (!context.jsx) throw badRequest(\"jsx is not available\");\n return context.jsx.execute(name, jsxParams);\n });\n registry.registerMethod(ProtocolMethod.EventSubscribe, async (params, ctx) => {\n const context = ctx as HandlerContext;\n if (!context.session) throw badRequest(\"event subscription is only available on /ws\");\n const { type } = params as { type?: unknown };\n if (typeof type !== \"string\") throw badRequest(\"type is required\");\n context.session.subscribe(type);\n return { ok: true };\n });\n registry.registerMethod(ProtocolMethod.EventUnsubscribe, async (params, ctx) => {\n const context = ctx as HandlerContext;\n if (!context.session) throw badRequest(\"event subscription is only available on /ws\");\n const { type } = params as { type?: unknown };\n if (typeof type !== \"string\") throw badRequest(\"type is required\");\n context.session.unsubscribe(type);\n return { ok: true };\n });\n}\n\nfunction badRequest(message: string): Error & { code: string } {\n const error = new Error(message) as Error & { code: string };\n error.code = ErrorCode.BadRequest;\n return error;\n}\n","import type { PluginHost } from \"./host\";\nimport type { PluginClientBus } from \"./bus\";\nimport type { JsxRunnerApi, PhotoshopEvents } from \"@ps-generator-bridge/generator/contract\";\nimport { PsPhotoshopProxy } from \"../photoshop\";\n\n// A *global* brand so \"extends BasePlugin\" can be detected across\n// separately-bundled SDK copies (an external plugin bundles its own\n// @ps-generator-bridge/sdk/plugin, so `instanceof BasePlugin` against the\n// server's copy would fail). Stamped on BasePlugin.prototype; any subclass\n// inherits it via the prototype chain. See `isBasePluginClass`.\nconst BASE_PLUGIN_BRAND = Symbol.for(\"ps-generator-bridge.BasePlugin\");\n\n/**\n * Base class for plugins (ADR 0009 / RFC 0003). A plugin is the orchestration\n * layer above feature modules: it composes one or more module calls (reached\n * through `this.modules`, e.g. `this.modules.layer`) and exposes\n * its own `@ws`/`@api` handlers, bootstrapped the same way as modules.\n *\n * Dependency direction is strictly downward: a plugin may depend on modules,\n * never on sibling plugins and never in reverse (modules must not reach\n * plugins). `plugin` is the abstract PluginHost interface — never the\n * concrete server plugin — so a plugin depends only on this SDK subpath.\n *\n * `@ws`/`@api` names are written in full by the developer (e.g.\n * `@ws(\"LayerOps:merge\")`) — `bootstrap` does not inject or derive a namespace.\n * Use a `Domain:action` prefix to keep names from colliding across modules and\n * plugins (ADR 0006 convention); the assembler's `registerMethod` is a silent\n * `Map.set`, so prefix uniqueness is the developer's responsibility.\n *\n * Client push: `broadcast`/`send` reach only this plugin's own online clients,\n * via the PluginClientBus the server attaches after construction. A subclass\n * may override `onConnect`/`onDisconnect` to react to its clients coming and\n * going; the defaults are no-ops.\n */\nexport abstract class BasePlugin {\n /** Stable URL identity of this plugin (read from the class's `static id`). */\n readonly id: string;\n /** The abstract plugin contract (never the concrete server plugin). */\n protected readonly plugin: PluginHost;\n\n private bus: PluginClientBus | undefined;\n private _photoshop: PsPhotoshopProxy | undefined;\n\n constructor(id: string, plugin: PluginHost) {\n this.id = id;\n this.plugin = plugin;\n }\n\n /** Feature modules, reached by short key (shortcut for `this.plugin.modules`). */\n protected get modules(): PluginHost[\"modules\"] {\n return this.plugin.modules;\n }\n\n /**\n * The jsx runner scoped to this plugin's own `jsx/` dir (shortcut for\n * `this.plugin.jsx`, RFC 0005). `jsx.execute(\"x\")` runs `<pluginRoot>/jsx/x.jsx`;\n * `jsx.executeBuiltin(\"Document/getDocumentInfo\")` reaches the host's built-in\n * tree.\n */\n protected get jsx(): JsxRunnerApi {\n return this.plugin.jsx;\n }\n\n /**\n * Typed, listen-only Photoshop event stream (shortcut for `this.plugin.events`).\n * Subscriptions are lazy on the server side: the first `on`/`once` for an event\n * subscribes upstream, and the last `off` unsubscribes.\n */\n protected get events(): PhotoshopEvents {\n return this.plugin.events;\n }\n\n /**\n * Photoshop DOM proxy, a typed object wrapper over `this.jsx`. Read and write\n * the live document through `this.photoshop.app` / `this.photoshop.activeDocument`\n * (e.g. `await this.photoshop.activeDocument.name`) instead of hand-writing\n * ExtendScript. Lazily built once and backed by this plugin's own jsx runner;\n * drop to `this.jsx.run(...)` for anything the proxy does not cover.\n */\n protected get photoshop(): PsPhotoshopProxy {\n return (this._photoshop ??= new PsPhotoshopProxy(this.jsx));\n }\n\n /**\n * Attach the per-plugin client bus. Called by the server's assembler after\n * construction and before `listen`, so `broadcast`/`send` are live by the time\n * any handler can fire. Not part of the public Plugin authoring API.\n */\n _attachBus(bus: PluginClientBus): void {\n this.bus = bus;\n }\n\n /** Push an Event to every online client of this plugin. */\n broadcast(type: string, data: unknown): void {\n this.bus?.broadcast(type, data);\n }\n\n /** Push an Event to one client of this plugin (no-op if not connected). */\n send(clientId: string, type: string, data: unknown): void {\n this.bus?.send(clientId, type, data);\n }\n\n /** Called after a client handshake registers with this plugin. Default no-op. */\n onConnect(_clientId: string): void {}\n\n /** Called after a client socket is removed from this plugin. Default no-op. */\n onDisconnect(_clientId: string): void {}\n}\n\n// Stamp the brand on the prototype (inherited by every subclass) so the loader's\n// isBasePluginClass check works across separately-bundled SDK copies.\nObject.defineProperty(BasePlugin.prototype, BASE_PLUGIN_BRAND, {\n value: true,\n enumerable: false,\n configurable: false,\n writable: false,\n});\n\n/**\n * Whether `S` is a class that extends BasePlugin. Uses the global brand rather\n * than `instanceof` so it works when `S` came from a separately-bundled copy of\n * this SDK (external plugins). The brand is inherited via the prototype chain,\n * so direct and indirect subclasses both qualify.\n */\nexport function isBasePluginClass(S: unknown): boolean {\n if (typeof S !== \"function\") return false;\n const proto = (S as { prototype?: unknown }).prototype;\n return proto != null && Boolean((proto as Record<symbol, unknown>)[BASE_PLUGIN_BRAND]);\n}\n","import type { HttpMethod, ApiRouteSpec, AssemblyTarget } from \"./types\";\n\n// Standard TC39 decorators stash metadata on the class under Symbol.metadata.\n// Node (and PS's Node 18) lacks the well-known symbol at runtime, so we polyfill\n// it once, before any decorated class is defined (this module is imported by\n// every module/plugin file that uses @ws/@api). Verified to work under\n// tsup/esbuild targeting node18. The symbol is captured into a typed const so\n// the rest of the file does not depend on `Symbol.metadata` being present in the\n// TS lib (target is ES2021).\n(Symbol as { metadata?: symbol }).metadata ??= Symbol.for(\"Symbol.metadata\");\nconst METADATA = (Symbol as unknown as { metadata: symbol }).metadata;\n\n// A *global* symbol so the devkit works across separately-bundled SDK copies:\n// an external plugin bundles its own @ps-generator-bridge/sdk/plugin, so its\n// @ws/@api decorator and the server's bootstrap must agree on the handler-stash\n// key even though they are different module identities. A unique Symbol() would\n// not match; Symbol.for is shared across bundles. The stash itself is still\n// per-class (own-property on each class's metadata), so this introduces no\n// cross-class leakage.\nconst HANDLERS = Symbol.for(\"ps-generator-bridge.handlers\");\n\ninterface WsHandlerMeta {\n kind: \"ws\";\n name: string;\n methodKey: string;\n}\n\ninterface ApiHandlerMeta {\n kind: \"api\";\n method: HttpMethod | HttpMethod[];\n url: string;\n methodKey: string;\n}\n\ntype HandlerMeta = WsHandlerMeta | ApiHandlerMeta;\n\ntype MetadataLike = Record<string | symbol, unknown>;\n\n// Push onto the *own* handler array of this class's metadata. `context.metadata`\n// is prototype-chained to the base class, so without the own-property guard a\n// subclass method would append into the base class's array.\nfunction pushHandler(metadata: MetadataLike, meta: HandlerMeta): void {\n if (!Object.prototype.hasOwnProperty.call(metadata, HANDLERS)) {\n metadata[HANDLERS] = [];\n }\n (metadata[HANDLERS] as HandlerMeta[]).push(meta);\n}\n\n/** Mark a method as a WS Request handler registered under `name` (ADR 0006). */\nexport function ws(name: string) {\n return function (_value: unknown, context: ClassMethodDecoratorContext): void {\n pushHandler(context.metadata as MetadataLike, {\n kind: \"ws\",\n name,\n methodKey: String(context.name),\n });\n };\n}\n\n/**\n * Mark a method as an HTTP route handler. `@api(\"/path\")` defaults to GET;\n * `@api({ method, url })` selects the verb(s) (ADR 0006). The route URL is\n * registered verbatim for modules (under `/{path}`) and prefixed with the\n * plugin id for plugins (under `/{pluginId}/{path}`, RFC 0004) — the\n * decorator only collects metadata; the assembly target decides the final URL.\n */\nexport function api(pathOrRoute: string | { method?: HttpMethod | HttpMethod[]; url: string }) {\n const route =\n typeof pathOrRoute === \"string\"\n ? { method: \"GET\" as HttpMethod, url: pathOrRoute }\n : { method: pathOrRoute.method ?? (\"GET\" as HttpMethod), url: pathOrRoute.url };\n return function (_value: unknown, context: ClassMethodDecoratorContext): void {\n pushHandler(context.metadata as MetadataLike, {\n kind: \"api\",\n method: route.method,\n url: route.url,\n methodKey: String(context.name),\n });\n };\n}\n\n/**\n * Second stage of decorator registration (ADR 0006 / 0009): scan a module or\n * plugin instance's collected metadata and register each decorated method\n * against the assembly target, bound to the instance so handlers can reach\n * `this`. Walks the metadata prototype chain so inherited handlers are included.\n * The `@ws`/`@api` name is registered verbatim — developers write the full\n * `Domain:action` name; no namespace is injected. For a plugin, the target is\n * the per-plugin scoped assembler (RFC 0004); for a module, the global Registry.\n */\nexport function bootstrap(instance: object, target: AssemblyTarget): void {\n const ctor = instance.constructor as unknown as Record<symbol, unknown>;\n const collected: HandlerMeta[] = [];\n let metadata = ctor[METADATA] as MetadataLike | undefined;\n while (metadata) {\n if (Object.prototype.hasOwnProperty.call(metadata, HANDLERS)) {\n collected.push(...(metadata[HANDLERS] as HandlerMeta[]));\n }\n metadata = Object.getPrototypeOf(metadata) as MetadataLike | undefined;\n }\n\n for (const meta of collected) {\n const fn = (instance as Record<string, unknown>)[meta.methodKey];\n if (typeof fn !== \"function\") continue;\n const bound = (fn as (...args: unknown[]) => unknown).bind(instance);\n if (meta.kind === \"ws\") {\n target.registerMethod(meta.name, bound);\n } else {\n target.registerApi({ method: meta.method, url: meta.url, handler: bound });\n }\n }\n}\n","import type { WebSocket } from \"ws\";\nimport { serializeFrame } from \"@ps-generator-bridge/sdk\";\n\n/** One connected client, keyed by its stable clientId (ADR 0007). */\nexport interface ClientEntry {\n clientId: string;\n socket: WebSocket;\n connectedAt: number;\n /** Event types this client subscribed to. Reserved; not yet filtered on. */\n subscriptions: Set<string>;\n}\n\n/**\n * Tracks currently-online clients by clientId (ADR 0007), orthogonal to the\n * Registry (which assembles what the server can do). Used to push Events:\n * `emit` to one client, `broadcast` to all.\n */\nexport class ClientStore {\n private readonly clients = new Map<string, ClientEntry>();\n\n /**\n * Register `socket` under `clientId`. If an entry already exists (a reconnect\n * whose old socket is still half-open), the new connection takes over: the old\n * socket is closed and the entry replaced, but subscriptions are preserved.\n */\n add(clientId: string, socket: WebSocket): ClientEntry {\n const existing = this.clients.get(clientId);\n const subscriptions = existing?.subscriptions ?? new Set<string>();\n const entry: ClientEntry = { clientId, socket, connectedAt: Date.now(), subscriptions };\n // Replace the entry first, then close the old socket: its `close` handler runs\n // `remove(clientId, oldSocket)`, which is now a no-op because the entry already\n // points at the new socket.\n this.clients.set(clientId, entry);\n if (existing && existing.socket !== socket) {\n try {\n existing.socket.close();\n } catch {\n // Old socket already dead — nothing to close.\n }\n }\n return entry;\n }\n\n /**\n * Drop the entry for `clientId` — but only if `socket` is still the current\n * one. A taken-over old socket firing `close` must not evict the live entry.\n */\n remove(clientId: string, socket: WebSocket): ClientEntry | undefined {\n const entry = this.clients.get(clientId);\n if (entry && entry.socket === socket) {\n this.clients.delete(clientId);\n return entry;\n }\n return undefined;\n }\n\n subscribe(clientId: string, type: string): boolean {\n const entry = this.clients.get(clientId);\n if (!entry || entry.subscriptions.has(type)) return false;\n entry.subscriptions.add(type);\n return true;\n }\n\n unsubscribe(clientId: string, type: string): boolean {\n const entry = this.clients.get(clientId);\n if (!entry || !entry.subscriptions.has(type)) return false;\n entry.subscriptions.delete(type);\n return true;\n }\n\n /** Push an Event to one client (no-op if it is not connected). */\n emit(clientId: string, type: string, data: unknown): void {\n const entry = this.clients.get(clientId);\n if (entry) {\n sendEvent(entry.socket, type, data);\n }\n }\n\n /** Push an Event to every connected client. */\n broadcast(type: string, data: unknown): void {\n for (const entry of this.clients.values()) {\n sendEvent(entry.socket, type, data);\n }\n }\n\n /** Push an Event only to clients subscribed to that Event type. */\n broadcastSubscribed(type: string, data: unknown): void {\n for (const entry of this.clients.values()) {\n if (entry.subscriptions.has(type)) {\n sendEvent(entry.socket, type, data);\n }\n }\n }\n}\n\nfunction sendEvent(socket: WebSocket, type: string, data: unknown): void {\n socket.send(serializeFrame({ type, data }));\n}\n","import type { ResponseEnvelope } from \"@ps-generator-bridge/sdk\";\nimport type { AssemblyTarget, MethodHandler, ApiRouteSpec } from \"@ps-generator-bridge/sdk/plugin\";\nimport { unknownMethodResponse, type HandlerContext } from \"./dispatch\";\nimport { MethodTable } from \"./methodTable\";\n\n/**\n * Per-plugin scoped method table (RFC 0004). Implements the SDK AssemblyTarget\n * so `bootstrap(plugin, scopedRegistry)` registers a plugin's `@ws` handlers\n * here (not in the global Registry) and collects its `@api` routes for the\n * assembler to flush to fastify under `/{pluginId}/{path}`.\n *\n * Dispatch order on a `/ws/{pluginId}` connection is scoped-then-global: the\n * WS handler calls `tryDispatch` first; it returns `undefined` when no scoped\n * handler matches (or the frame is not a request), so the caller falls back to\n * the global Registry (modules + builtins). A scoped name that collides with a\n * global one overrides it (scoped wins).\n */\nexport class ScopedRegistry implements AssemblyTarget {\n private readonly methods = new MethodTable();\n private readonly apiRoutes: ApiRouteSpec[] = [];\n\n registerMethod(name: string, handler: MethodHandler): void {\n this.methods.register(name, handler);\n }\n\n registerApi(route: ApiRouteSpec): void {\n this.apiRoutes.push(route);\n }\n\n /** The `@api` routes bootstrap collected, for the assembler to flush to fastify. */\n get routes(): readonly ApiRouteSpec[] {\n return this.apiRoutes;\n }\n\n /**\n * Dispatch a frame against the scoped table. Returns `undefined` when there is\n * no scoped handler (caller falls back to the global Registry) or the frame is\n * not a request (nothing to respond to). A found handler always yields an\n * envelope — including an error envelope — so only \"not in this table\" falls\n * through.\n */\n async tryDispatch(message: unknown, ctx: HandlerContext): Promise<ResponseEnvelope | undefined> {\n return this.methods.tryDispatch(message, ctx);\n }\n}\n\n// Re-exported for the assembler, which builds the global UnknownMethod envelope\n// when neither scoped nor global matched — though in practice the global\n// Registry.dispatch already produces it. Kept here for dispatch symmetry.\nexport { unknownMethodResponse };\n","import type { FastifyInstance, HTTPMethods, RouteHandlerMethod } from \"fastify\";\nimport type { BasePlugin, PluginClientBus } from \"@ps-generator-bridge/sdk/plugin\";\nimport { bootstrap } from \"@ps-generator-bridge/sdk/plugin\";\nimport { ClientStore } from \"./clientStore\";\nimport { ScopedRegistry } from \"./scopedRegistry\";\n\n/** One loaded plugin's runtime state: the instance, its scoped table, its clients. */\nexport interface PluginEntry {\n plugin: BasePlugin;\n scoped: ScopedRegistry;\n clients: ClientStore;\n}\n\n/** One entry in the `GET /plugins` discovery list (RFC 0004). */\nexport interface PluginInfo {\n id: string;\n}\n\n/**\n * Owns the loaded plugins and their per-plugin runtime state (RFC 0004). Each\n * plugin gets its own scoped method table and ClientStore; `register` wires\n * them up: attaches a PluginClientBus backed by the ClientStore, bootstraps the\n * plugin's `@ws`/`@api` metadata into the scoped table, and flushes `@api`\n * routes to fastify under `/{pluginId}/{path}`. All before `listen()`.\n *\n * The WS endpoint `/ws/{pluginId}` is a single param route owned by the server\n * (see `createServer`); it looks the plugin up here and dispatches scoped-first\n * with global fallback. This manager does not register WS routes itself.\n */\nexport class PluginManager {\n private readonly plugins = new Map<string, PluginEntry>();\n\n constructor(private readonly app: FastifyInstance) {}\n\n /** All registered plugin ids, in registration order. */\n get ids(): string[] {\n return [...this.plugins.keys()];\n }\n\n /** The discovery list surfaced at `GET /plugins` and in `getServerInfo`. */\n list(): PluginInfo[] {\n return [...this.plugins.values()].map((e) => ({ id: e.plugin.id }));\n }\n\n /** Look up a loaded plugin by id (used by the `/ws/:pluginId` route). */\n get(id: string): PluginEntry | undefined {\n return this.plugins.get(id);\n }\n\n /**\n * Register a plugin: build its scoped table + ClientStore, attach the client\n * bus, bootstrap its handlers, and flush its `@api` routes to fastify. Throws\n * on a duplicate or illegal id. Must run before `listen()`.\n */\n register(plugin: BasePlugin): PluginEntry {\n const id = plugin.id;\n if (!isValidPluginId(id)) {\n throw new Error(`illegal plugin id: '${id}' (must match [A-Za-z0-9_-]+)`);\n }\n if (this.plugins.has(id)) {\n throw new Error(`duplicate plugin id: ${id}`);\n }\n\n const scoped = new ScopedRegistry();\n const clients = new ClientStore();\n const bus: PluginClientBus = {\n broadcast: (type, data) => clients.broadcast(type, data),\n send: (clientId, type, data) => clients.emit(clientId, type, data),\n };\n plugin._attachBus(bus);\n bootstrap(plugin, scoped);\n\n for (const route of scoped.routes) {\n this.app.route({\n method: route.method as HTTPMethods | HTTPMethods[],\n url: `/${id}${route.url}`,\n handler: route.handler as RouteHandlerMethod,\n });\n }\n\n const entry: PluginEntry = { plugin, scoped, clients };\n this.plugins.set(id, entry);\n return entry;\n }\n}\n\n/** A plugin id must be URL-safe and non-empty (RFC 0004 / 0005). */\nexport function isValidPluginId(id: string): boolean {\n return /^[A-Za-z0-9_-]+$/.test(id);\n}\n","import { EventEmitter } from \"node:events\";\nimport type { PsGenerator } from \"../types/generator\";\n\n// Photoshop event contract (RFC 0003). The generator owns these payload shapes\n// (they are our own protocol JSON, not Adobe PS DOM objects); the SDK re-exports\n// them to plugins via src/contract.ts. `EventManager` is the runtime source, so\n// the contract tracks the implementation rather than the other way round.\n\n/**\n * Layer/document bounds in pixels. The console logged this as `[Object]` (not\n * expanded); this is the standard generator bounds shape.\n */\nexport interface Bounds {\n top: number;\n left: number;\n bottom: number;\n right: number;\n}\n\n/** One entry in `imageChanged.layers` — a layer touched by the change. */\nexport interface ImageChangedLayer {\n /** Layer id (stable across the session). */\n id: number;\n /** Present (true) when the layer's pixels changed. */\n pixels?: boolean;\n /** Present (true) when the layer was removed in this change. */\n removed?: boolean;\n /** Layer bounds; present on geometry/pixel changes. */\n bounds?: Bounds;\n}\n\n/**\n * Payload of the `imageChanged` event. Fields are a union of everything PS may\n * send; only `version` / `timeStamp` / `count` / `id` are always present. A\n * single event carries *either* metadata flags (`metaDataOnly`, `selection`),\n * *or* `layers`, *or* document-level flags (`active` / `file` / `closed`).\n */\nexport interface ImageChangedEvent {\n /** Generator protocol version, e.g. \"1.6.1\". */\n version: string;\n /** Seconds since epoch (float), e.g. 1782455135.936. */\n timeStamp: number;\n /** Per-document monotonically increasing change counter (resets per doc id). */\n count: number;\n /** Document id this change belongs to. */\n id: number;\n /** True on the first event for a doc / on activation. */\n active?: boolean;\n /** Document title or full path, e.g. \"Test-恢复的.psd\" or \"C:\\\\...\\\\Test.psd\". */\n file?: string;\n /** True when the document was closed. */\n closed?: boolean;\n /** True when only metadata changed (no pixel/layer body). */\n metaDataOnly?: boolean;\n /** Selected layer indices; empty array when the selection is cleared. */\n selection?: number[];\n /** Layers touched by this change (pixel edits, bounds, removals). */\n layers?: ImageChangedLayer[];\n}\n\n/**\n * Map of Photoshop event name -> payload type passed to the listener. Shapes\n * marked \"observed\" were confirmed from live PS output; the rest are inferred\n * from the generator protocol docs.\n */\nexport interface PhotoshopEventMap {\n /** [workspace display name] (inferred). */\n workspaceChanged: string;\n /** Tool name, e.g. \"paintbrushTool\" / \"moveTool\" (observed). */\n toolChanged: string;\n /** \"enter\" | \"exit\" (inferred). */\n quickMaskStateChanged: string;\n /** Document id (observed). */\n documentChanged: number;\n /** Document id of the closed document (observed). */\n closedDocument: number;\n /** Document id (inferred). */\n newDocumentViewCreated: number;\n /** Document id (inferred). */\n activeViewChanged: number;\n /** Document id of the now-current document (observed). */\n currentDocumentChanged: number;\n /** Color as 6-character hex value (inferred). */\n backgroundColorChanged: string;\n /** Color as 6-character hex value (inferred). */\n foregroundColorChanged: string;\n /** Image/document change descriptor (observed). */\n imageChanged: ImageChangedEvent;\n}\n\n/** Listener for a given Photoshop event key. */\nexport type PhotoshopEventListener<K extends keyof PhotoshopEventMap> = (\n payload: PhotoshopEventMap[K]\n) => void;\n\n/**\n * Listen-only typed surface a Plugin reaches through `plugin.events` /\n * `this.events`. `EventManager` (an `EventEmitter`) `implements` this; `emit` is\n * deliberately excluded — a Plugin subscribes, it never dispatches Photoshop\n * events.\n */\nexport interface PhotoshopEvents {\n on<K extends keyof PhotoshopEventMap>(event: K, listener: PhotoshopEventListener<K>): this;\n once<K extends keyof PhotoshopEventMap>(event: K, listener: PhotoshopEventListener<K>): this;\n off<K extends keyof PhotoshopEventMap>(event: K, listener: PhotoshopEventListener<K>): this;\n}\n\ntype Listener<K extends keyof PhotoshopEventMap> = PhotoshopEventListener<K>;\n\n/** The events callers may listen to — the runtime source for the allowlist. */\nexport const PHOTOSHOP_EVENTS: (keyof PhotoshopEventMap)[] = [\n \"workspaceChanged\",\n \"toolChanged\",\n \"quickMaskStateChanged\",\n \"documentChanged\",\n \"closedDocument\",\n \"newDocumentViewCreated\",\n \"activeViewChanged\",\n \"currentDocumentChanged\",\n \"backgroundColorChanged\",\n \"foregroundColorChanged\",\n \"imageChanged\",\n];\n\nconst ALLOWED = new Set<string>(PHOTOSHOP_EVENTS);\n\n// EventEmitter's own meta/internal event names, which flow through our\n// newListener/removeListener handlers and must bypass the allowlist guard.\nconst META = new Set<string>([\"newListener\", \"removeListener\", \"error\"]);\n\n/**\n * Owns the plugin's Photoshop event subscriptions, exposed as a typed\n * `EventEmitter`. Held by `PsBridgeHost` (see `plugin.events`).\n *\n * Subscriptions are lazy: the manager only calls `generator.onPhotoshopEvent`\n * the first time a caller listens to an event, and `removePhotoshopEventListener`\n * once the last listener for that event goes away. Reference counting rides on\n * the `newListener` / `removeListener` meta-events so every add/remove path\n * (`on` / `once` / `off` / `removeAllListeners`) is covered.\n *\n * The `on` / `once` / `off` / `emit` signatures are narrowed to\n * `PhotoshopEventMap`, so only confirmed events can be listened to at compile\n * time; unknown names throw at runtime.\n */\nexport class EventManager extends EventEmitter implements PhotoshopEvents {\n // One bridge listener per active event, kept so we can detach the exact\n // function from the generator when the last consumer unsubscribes.\n private readonly bridges = new Map<keyof PhotoshopEventMap, (payload: unknown) => void>();\n\n constructor(private readonly generator: PsGenerator) {\n super();\n // super.on: bypass our narrowed override (these are meta events, not PS events).\n super.on(\"newListener\", (event: string | symbol) => this.onAdd(event));\n super.on(\"removeListener\", (event: string | symbol) => this.onRemove(event));\n }\n\n // --- typed surface (narrows EventEmitter's string|symbol signatures) ------\n\n override on<K extends keyof PhotoshopEventMap>(event: K, listener: Listener<K>): this {\n return super.on(event, listener as (...args: unknown[]) => void);\n }\n\n override once<K extends keyof PhotoshopEventMap>(event: K, listener: Listener<K>): this {\n return super.once(event, listener as (...args: unknown[]) => void);\n }\n\n override addListener<K extends keyof PhotoshopEventMap>(event: K, listener: Listener<K>): this {\n return super.addListener(event, listener as (...args: unknown[]) => void);\n }\n\n override off<K extends keyof PhotoshopEventMap>(event: K, listener: Listener<K>): this {\n return super.off(event, listener as (...args: unknown[]) => void);\n }\n\n override removeListener<K extends keyof PhotoshopEventMap>(\n event: K,\n listener: Listener<K>\n ): this {\n return super.removeListener(event, listener as (...args: unknown[]) => void);\n }\n\n /** Dispatch a payload to listeners. Fired by the PS bridge; not for external use. */\n override emit<K extends keyof PhotoshopEventMap>(\n event: K,\n payload: PhotoshopEventMap[K]\n ): boolean;\n override emit(event: string | symbol, ...args: unknown[]): boolean;\n override emit(event: string | symbol, ...args: unknown[]): boolean {\n return super.emit(event, ...args);\n }\n\n // --- lazy subscribe / unsubscribe ----------------------------------------\n\n /** First listener for a PS event -> subscribe upstream once. */\n private onAdd(event: string | symbol): void {\n if (typeof event !== \"string\" || META.has(event)) return;\n if (!ALLOWED.has(event)) {\n throw new Error(`EventManager: unknown Photoshop event \"${event}\"`);\n }\n const key = event as keyof PhotoshopEventMap;\n // newListener fires before the listener is added, so 0 means this is the first.\n if (this.listenerCount(key) !== 0) return;\n const bridge = (payload: unknown) => this.emit(key, payload as PhotoshopEventMap[typeof key]);\n this.bridges.set(key, bridge);\n this.generator.onPhotoshopEvent(event, bridge);\n }\n\n /** Last listener for a PS event removed -> detach the upstream bridge. */\n private onRemove(event: string | symbol): void {\n if (typeof event !== \"string\" || META.has(event)) return;\n const key = event as keyof PhotoshopEventMap;\n // removeListener fires after removal, so 0 means none are left.\n if (this.listenerCount(key) !== 0) return;\n const bridge = this.bridges.get(key);\n if (!bridge) return;\n this.generator.removePhotoshopEventListener(event, bridge);\n this.bridges.delete(key);\n }\n}\n","import type { ClientStore } from \"./clientStore\";\nimport {\n PHOTOSHOP_EVENTS,\n type EventManager,\n type PhotoshopEventMap,\n} from \"../utilis/eventManager\";\n\nconst ALLOWED = new Set<string>(PHOTOSHOP_EVENTS);\n\n/**\n * Root /ws Event hub. It bridges Photoshop events into the root ClientStore only\n * while at least one root client is subscribed to a given Event type.\n */\nexport class EventHub {\n private readonly refs = new Map<keyof PhotoshopEventMap, number>();\n private readonly bridges = new Map<keyof PhotoshopEventMap, (payload: unknown) => void>();\n\n constructor(\n private readonly events: EventManager,\n private readonly clients: ClientStore\n ) {}\n\n subscribe(type: string): void {\n const key = this.assertEvent(type);\n const next = (this.refs.get(key) ?? 0) + 1;\n this.refs.set(key, next);\n if (next !== 1) return;\n const bridge = (payload: unknown) => this.clients.broadcastSubscribed(type, payload);\n this.bridges.set(key, bridge);\n this.events.on(key, bridge as (payload: PhotoshopEventMap[typeof key]) => void);\n }\n\n unsubscribe(type: string): void {\n const key = this.assertEvent(type);\n const current = this.refs.get(key) ?? 0;\n if (current <= 1) {\n this.refs.delete(key);\n const bridge = this.bridges.get(key);\n if (bridge) {\n this.events.off(key, bridge as (payload: PhotoshopEventMap[typeof key]) => void);\n this.bridges.delete(key);\n }\n return;\n }\n this.refs.set(key, current - 1);\n }\n\n private assertEvent(type: string): keyof PhotoshopEventMap {\n if (!ALLOWED.has(type)) {\n throw new Error(`Unknown Photoshop event: ${type}`);\n }\n return type as keyof PhotoshopEventMap;\n }\n}\n","import { readdirSync, readFileSync } from \"node:fs\";\nimport { join, resolve, sep } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport {\n isBasePluginClass,\n type BasePlugin,\n type PluginHost,\n} from \"@ps-generator-bridge/sdk/plugin\";\nimport { isValidPluginId } from \"./pluginManager\";\nimport type { Logger } from \"../utilis/logger\";\n\nexport interface LoadOptions {\n /** Directory whose direct child folders are scanned as plugin packages. */\n pluginsDir: string;\n /**\n * Builds the host contract for a plugin, given that plugin's package dir\n * (RFC 0005). The loader calls it once per plugin and passes the result to the\n * plugin's constructor, so each plugin can receive a `jsx` scoped to its own\n * `<pluginDir>/jsx`. The loader stays ignorant of jsx scoping — `PsBridgeHost`\n * owns the per-plugin wrapper.\n */\n hostFor: (pluginDir: string) => PluginHost;\n /** Plugin ids already taken — enforced unique across the whole load. */\n knownIds: Set<string>;\n logger: Logger;\n}\n\nexport interface LoadedPlugin {\n id: string;\n plugin: BasePlugin;\n /** Absolute path of the package entry (resolved from package.json `main`). */\n path: string;\n}\n\nexport interface SkippedPlugin {\n /** Folder name under pluginsDir, for readable logs. */\n path: string;\n reason: string;\n}\n\nexport interface LoadResult {\n loaded: LoadedPlugin[];\n skipped: SkippedPlugin[];\n}\n\n/**\n * Plugin loader. Scans the *direct* child folders of `pluginsDir` (flat, one\n * level — `node_modules` and dotfolders are ignored), and treats each as an npm\n * package: it reads the folder's `package.json`, resolves the `main` entry, and\n * loads it via dynamic `import()` with CJS interop (`mod.default ?? mod`). The\n * default export must be a `BasePlugin` subclass with a legal, unique `static\n * id`; it is constructed with `(id, host)`.\n *\n * A plugin's own dependencies resolve from its own `node_modules` via Node's\n * native module resolution (the entry's requires walk up from the entry file),\n * so a plugin ships with its dependencies installed beside it — the loader adds\n * no resolution machinery of its own.\n *\n * Invalid or broken packages are skipped with a `logger.warn` naming the folder\n * and reason — one bad package never stops the others or the host. A folder with\n * no `package.json`, or a `package.json` with no `main`, is skipped. A missing\n * `pluginsDir` is the default state (no plugins installed) and is a debug log.\n * `isBasePluginClass` (a global brand) makes validation work even when the\n * package bundles its own SDK copy.\n */\nexport async function loadPlugins(options: LoadOptions): Promise<LoadResult> {\n const { pluginsDir, hostFor, knownIds, logger } = options;\n const loaded: LoadedPlugin[] = [];\n const skipped: SkippedPlugin[] = [];\n const taken = new Set(knownIds);\n\n let dirs: string[];\n try {\n dirs = scanPluginDirs(pluginsDir);\n } catch (err) {\n logger.debug(`pluginsDir not loaded: ${pluginsDir} (${(err as Error).message})`);\n return { loaded, skipped };\n }\n\n for (const name of dirs) {\n const dir = join(pluginsDir, name);\n const outcome = await loadOne(dir, hostFor, taken);\n if (outcome.kind === \"loaded\") {\n loaded.push({ id: outcome.id, plugin: outcome.plugin, path: outcome.path });\n taken.add(outcome.id);\n logger.info(`plugin loaded: ${name} (${outcome.id})`);\n } else {\n skipped.push({ path: name, reason: outcome.reason });\n logger.warn(`plugin skipped: ${name} — ${outcome.reason}`);\n }\n }\n return { loaded, skipped };\n}\n\ntype Outcome =\n | { kind: \"loaded\"; id: string; plugin: BasePlugin; path: string }\n | { kind: \"skipped\"; reason: string };\n\nasync function loadOne(\n dir: string,\n hostFor: (pluginDir: string) => PluginHost,\n taken: Set<string>\n): Promise<Outcome> {\n // Read + parse package.json.\n let pkg: { main?: unknown };\n try {\n pkg = JSON.parse(readFileSync(join(dir, \"package.json\"), \"utf8\")) as { main?: unknown };\n } catch (err) {\n return {\n kind: \"skipped\",\n reason: `package.json missing or invalid: ${(err as Error).message}`,\n };\n }\n\n // The entry is the package's `main`; a package with no `main` is skipped.\n if (typeof pkg.main !== \"string\" || pkg.main.length === 0) {\n return { kind: \"skipped\", reason: 'package.json has no \"main\"' };\n }\n\n // Resolve the entry within the plugin folder; reject a `main` that escapes it.\n const root = resolve(dir);\n const entry = resolve(root, pkg.main);\n if (entry !== root && !entry.startsWith(root + sep)) {\n return { kind: \"skipped\", reason: `\"main\" escapes the plugin directory: ${pkg.main}` };\n }\n\n let mod: Record<string, unknown>;\n try {\n // Node's ESM loader requires a file:// URL for absolute paths; a bare\n // Windows path like `d:\\...` is read as a protocol and rejected.\n mod = (await import(pathToFileURL(entry).href)) as Record<string, unknown>;\n } catch (err) {\n return { kind: \"skipped\", reason: `load failed: ${(err as Error).message}` };\n }\n\n // CJS interop for dynamic import(): node exposes a CJS module's `module.exports`\n // as the namespace `default`. A bundler's `export default` (tsup) yields\n // `module.exports.default = S` which the import() lexer may not flatten, so the\n // namespace `default` is the whole exports object carrying an inner `default`.\n // Unwrap one such inner default; a bare `module.exports = S` (a function/class)\n // is taken as-is.\n let S: unknown = mod.default ?? mod;\n if (S !== null && typeof S === \"object\") {\n const inner = (S as Record<string, unknown>).default;\n if (inner !== undefined) S = inner;\n }\n\n if (!isBasePluginClass(S)) {\n return { kind: \"skipped\", reason: \"default export is not a BasePlugin subclass\" };\n }\n const id = (S as { id?: unknown }).id;\n if (typeof id !== \"string\" || id.length === 0) {\n return { kind: \"skipped\", reason: \"missing static id\" };\n }\n if (!isValidPluginId(id)) {\n return { kind: \"skipped\", reason: `illegal id '${id}' (must match [A-Za-z0-9_-]+)` };\n }\n if (taken.has(id)) {\n return { kind: \"skipped\", reason: `duplicate id '${id}'` };\n }\n try {\n const host = hostFor(dir);\n const plugin = new (S as new (id: string, host: PluginHost) => BasePlugin)(id, host);\n return { kind: \"loaded\", id, plugin, path: entry };\n } catch (err) {\n return { kind: \"skipped\", reason: `construct failed: ${(err as Error).message}` };\n }\n}\n\n/**\n * List the direct child folder names of `pluginsDir`, sorted for deterministic\n * load order. `node_modules` and dotfolders are skipped. Throws if `pluginsDir`\n * itself is missing (caller treats that as \"no plugins installed\").\n */\nfunction scanPluginDirs(dir: string): string[] {\n return readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && e.name !== \"node_modules\" && !e.name.startsWith(\".\"))\n .map((e) => e.name)\n .sort();\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join, relative, sep } from \"node:path\";\nimport type { PsGenerator } from \"../types/generator\";\nimport type { Logger } from \"./logger\";\n\n// Prefix a jsx return value uses to signal failure (LightAi BaseManager\n// convention). `JsxRunner.run` / `execute` turn such a value into a thrown\n// Error.\nconst ERROR_PREFIX = \"Error:\";\n\n/**\n * A single progress notification emitted by Photoshop while a jsx file\n * evaluates via `_sendJSXFile`. `type` is `\"javascript\"` (an evaluation result\n * — e.g. a bounds object), `\"pixmap\"` (a raw pixmap buffer), or `\"iccProfile\"`\n * (a raw ICC profile buffer).\n */\nexport interface JsxProgressMessage {\n type: \"javascript\" | \"pixmap\" | \"iccProfile\" | string;\n value: unknown;\n}\n\n/**\n * Typed handle to an in-flight `_sendJSXFile` evaluation. `onProgress`/`onFail`\n * subscribe to the underlying deferred's streams; `resolve`/`reject` let the\n * caller signal completion (required — the deferred won't settle on its own).\n * Isolates the `_sendJSXFile` touchpoint inside the JSX seam so callers like\n * `ImageModule.getPixmap` never reach generator-core's transport directly.\n */\nexport interface JsxChannel {\n onProgress(fn: (message: JsxProgressMessage) => void): void;\n onFail(fn: (err: unknown) => void): void;\n resolve(): void;\n reject(err?: unknown): void;\n}\n\n/**\n * The slice of JsxRunner a Plugin reaches through `plugin.jsx` (RFC 0003 /\n * RFC 0005). The concrete JsxRunner `implements` this (and `forPlugin` returns a\n * scoped view that also implements it), so the plugin contract can never drift\n * from the implementation; the SDK re-exports it (via src/contract.ts) as the\n * type of `PluginHost.jsx`. Excludes lifecycle (`init`) and the low-level pixmap\n * channel (`openJSXFile`) — plugins only run jsx by name (or raw string).\n *\n * `execute` resolves against *this handle's own* jsx scope: the built-in `jsx/`\n * tree for the host's root runner, or the plugin's own `jsx/` dir for the scoped\n * view `plugin.jsx` returns. `executeBuiltin` always targets the built-in tree,\n * so a plugin can reach a host domain (e.g. `Document/getDocumentInfo`) without\n * knowing its own id or dir. `run` takes a raw script and is scope-independent.\n */\nexport interface JsxRunnerApi {\n execute<T = unknown>(\n name: string,\n params?: Record<string, unknown>,\n sharedEngineSafe?: boolean\n ): Promise<T>;\n executeBuiltin<T = unknown>(\n name: string,\n params?: Record<string, unknown>,\n sharedEngineSafe?: boolean\n ): Promise<T>;\n run<T = unknown>(script: string): Promise<T>;\n}\n\n/**\n * Runs packaged jsx by name (ADR 0008). Resolves a name like\n * `Document/getDocumentInfo` to its physical path under the bundle's `jsx/`\n * directory, hands it to the injected generator's `evaluateJSXFile`, and\n * normalizes the result.\n *\n * Returns `message.value` verbatim — it does NOT `JSON.parse` for the caller;\n * the `T` type parameter is a labelling convenience only. A string value\n * starting with `\"Error:\"` becomes a thrown `Error` carrying the remainder.\n *\n * jsx text caching is handled by generator-core's `_sendJSXCache`, so this seam\n * adds none of its own. `__dirname` is `dist` for all bundled code, so\n * `polyfillsDir` defaults to `dist/jsx/polyfills`.\n *\n * ExtendScript's default engine persists globals across evaluations, so the\n * polyfills injected once in `init()` remain available to every later\n * `execute` (and to `run` when it uses the default engine). The default engine\n * is the only one primed — `sharedEngineSafe` callers use a separate engine\n * that does NOT receive the polyfills.\n */\nexport class JsxRunner implements JsxRunnerApi {\n private readonly jsxDir = join(__dirname, \"..\", \"jsx\");\n private polyfillsCache = \"\";\n\n constructor(\n private readonly generator: PsGenerator,\n private readonly logger: Logger,\n private readonly polyfillsDir = join(__dirname, \"..\", \"jsx\", \"polyfills\")\n ) {}\n\n /**\n * A jsx runner scoped to a plugin's own `jsx/` dir (RFC 0005). The returned\n * handle's `execute` resolves under `dir`, while `executeBuiltin` still targets\n * the built-in tree; `run` is unchanged. The scope is the *only* per-plugin\n * state — there is no shared mutable registry; the host builds one of these per\n * plugin in `hostFor` and injects it as `plugin.jsx`.\n */\n forPlugin(dir: string): JsxRunnerApi {\n return new ScopedJsx(this, dir);\n }\n\n /**\n * Resolve a jsx name to an absolute `.jsx` path under `baseDir`. The name may\n * carry domain subdirs (e.g. `Document/getDocumentInfo`). No escape guard: jsx\n * names come from trusted in-process code (a module or a plugin's own source),\n * which already runs arbitrary JS, so a guard would add no boundary.\n */\n private resolvePath(baseDir: string, name: string): string {\n return join(baseDir, `${name}.jsx`);\n }\n\n /**\n * Prime the default ExtendScript engine with ES polyfills. Reads every\n * `*.js` file under `polyfillsDir` (recursively, sorted by relative path for\n * deterministic concatenation order), concatenates them into `polyfillsCache`,\n * and evaluates the bundle once. Must be awaited before any `execute` call\n * that depends on the polyfills; `PsBridgeHost.onInit` does this before\n * `server.listen`.\n *\n * Missing dir -> throw (packaging bug). Empty dir -> no-op. Injection\n * returning `\"Error:…\"` or rejecting -> throw, so a broken polyfill surfaces\n * at startup rather than as a runtime `find is not a function`.\n */\n async init(): Promise<void> {\n const files = await this.collectPolyfillFiles();\n if (files.length === 0) {\n this.logger.debug(\"polyfills dir empty, skipping injection\");\n this.polyfillsCache = \"\";\n return;\n }\n const parts = await Promise.all(files.map((file) => readFile(file, \"utf8\")));\n this.polyfillsCache = parts.join(\"\\n\");\n const value = await this.generator.evaluateJSXString(this.polyfillsCache);\n if (typeof value === \"string\" && value.startsWith(ERROR_PREFIX)) {\n throw new Error(value.slice(ERROR_PREFIX.length));\n }\n this.logger.debug(`polyfills injected: ${files.length} files`);\n }\n\n /**\n * Run the jsx registered under `name` in the built-in `jsx/` tree (domain\n * subdirs included, e.g. `Document/getDocumentInfo`). `params` are inlined into\n * the script; `sharedEngineSafe` opts into Photoshop's shared script engine.\n * The root runner's own scope *is* the built-in tree, so `execute` and\n * `executeBuiltin` coincide here; a plugin's scoped view (see `forPlugin`)\n * splits them apart.\n */\n async execute<T = unknown>(\n name: string,\n params?: Record<string, unknown>,\n sharedEngineSafe?: boolean\n ): Promise<T> {\n return this.executeIn<T>(this.jsxDir, name, params, sharedEngineSafe);\n }\n\n /**\n * Alias of `execute` on the root runner — always the built-in tree. Present so\n * the root satisfies `JsxRunnerApi` alongside the scoped view; the scoped view\n * overrides `execute` (plugin dir) while delegating `executeBuiltin` here.\n */\n async executeBuiltin<T = unknown>(\n name: string,\n params?: Record<string, unknown>,\n sharedEngineSafe?: boolean\n ): Promise<T> {\n return this.execute<T>(name, params, sharedEngineSafe);\n }\n\n /**\n * Run the jsx under `name` resolved against `baseDir`. The seam through which\n * both the root runner (built-in tree) and the scoped view (a plugin's dir)\n * reach Photoshop; keeps path resolution + result normalization in one place.\n *\n * @internal Server-internal — not on `JsxRunnerApi`, not reachable by plugins.\n * Public only so the sibling `ScopedJsx` can delegate to it.\n */\n async executeIn<T = unknown>(\n baseDir: string,\n name: string,\n params?: Record<string, unknown>,\n sharedEngineSafe?: boolean\n ): Promise<T> {\n const path = this.resolvePath(baseDir, name);\n const value = await this.generator.evaluateJSXFile(path, params, sharedEngineSafe);\n return this.normalizeJsxResult<T>(value);\n }\n\n /**\n * Evaluate an arbitrary jsx string in the default ExtendScript engine (the\n * same engine `init()` primed with polyfills). No `sharedEngineSafe` opt-out:\n * polyfills live only in the default engine, so a shared-engine variant would\n * be silently un-polyfilled. Return value follows the same convention as\n * `run` — verbatim, with `\"Error:\"`-prefixed strings turned into thrown\n * Errors.\n */\n async run<T = unknown>(script: string): Promise<T> {\n const value = await this.generator.evaluateJSXString(script);\n return this.normalizeJsxResult<T>(value);\n }\n\n /**\n * Open a built-in packaged jsx file via the low-level `_sendJSXFile` channel\n * and return a typed handle to its in-flight evaluation. A root-runner-only\n * seam (not on `JsxRunnerApi`): the only caller is `ImageModule.getPixmap`.\n * Plugins reach pixmaps through `plugin.modules.image`, not this channel.\n *\n * Unlike `run` (which\n * awaits a single resolved value), this exposes the raw progress stream so\n * the caller can collect the multi-message responses Photoshop emits for\n * pixmap-producing scripts (bounds + pixmap + optional ICC profile). The\n * caller owns completion: it must call `channel.resolve()` once it has\n * received every message it expected, or `channel.reject(err)` on failure.\n *\n * `sharedEngineSafe` defaults to `true` to match the pixmap protocol\n * (generator-core's `getPixmap` / `getDocumentPixmap` both use the shared\n * engine).\n */\n openJSXFile(name: string, params?: Record<string, unknown>, sharedEngineSafe = true): JsxChannel {\n const path = this.resolvePath(this.jsxDir, name);\n const deferred = this.generator._sendJSXFile(path, params, sharedEngineSafe);\n return {\n onProgress: (fn) => {\n deferred.promise.progress(fn as (message: { type: string; value: unknown }) => void);\n },\n onFail: (fn) => {\n deferred.promise.fail(fn);\n },\n resolve: () => {\n deferred.resolve();\n },\n reject: (err) => {\n deferred.reject(err);\n },\n };\n }\n\n /**\n * Shared result normalization for `run` and `execute`: a string starting with\n * `\"Error:\"` becomes a thrown `Error` carrying the remainder; everything else\n * is returned verbatim (no `JSON.parse` — `T` is a labelling convenience).\n */\n private normalizeJsxResult<T>(value: unknown): T {\n if (typeof value === \"string\" && value.startsWith(ERROR_PREFIX)) {\n throw new Error(value.slice(ERROR_PREFIX.length));\n }\n return value as T;\n }\n\n /**\n * Recursively list `*.js` files under `polyfillsDir`, sorted by relative path\n * (POSIX-normalized) so concatenation order is stable across platforms and\n * polyfills that depend on each other load in a fixed sequence. Throws if the\n * directory itself is missing.\n */\n private async collectPolyfillFiles(): Promise<string[]> {\n const discovered: string[] = [];\n const walk = async (dir: string): Promise<void> => {\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (error: unknown) {\n // ENOENT on the root dir is a packaging bug -> fail loud. Subtree\n // read errors (permissions, etc.) also surface here.\n if (dir === this.polyfillsDir) {\n throw new Error(`polyfills dir not found: ${this.polyfillsDir}`);\n }\n throw error;\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(full);\n } else if (entry.isFile() && entry.name.endsWith(\".js\")) {\n discovered.push(full);\n }\n }\n };\n await walk(this.polyfillsDir);\n return discovered.sort((a, b) => {\n const ra = relative(this.polyfillsDir, a).split(sep).join(\"/\");\n const rb = relative(this.polyfillsDir, b).split(sep).join(\"/\");\n return ra < rb ? -1 : ra > rb ? 1 : 0;\n });\n }\n}\n\n/**\n * A plugin's view of the JsxRunner, scoped to its own `jsx/` dir (RFC 0005).\n * Created by `JsxRunner.forPlugin` and injected as `plugin.jsx`. Stateless apart\n * from `baseDir`: it delegates every call back to the single root runner (which\n * owns the generator handle and the once-primed polyfills), so plugin jsx runs\n * in the same default engine and sees the same polyfills as the built-in tree.\n *\n * `execute` resolves under the plugin's `baseDir`; `executeBuiltin` reaches the\n * built-in tree via the root's `execute`; `run` is forwarded verbatim.\n */\nclass ScopedJsx implements JsxRunnerApi {\n constructor(\n private readonly root: JsxRunner,\n private readonly baseDir: string\n ) {}\n\n execute<T = unknown>(\n name: string,\n params?: Record<string, unknown>,\n sharedEngineSafe?: boolean\n ): Promise<T> {\n return this.root.executeIn<T>(this.baseDir, name, params, sharedEngineSafe);\n }\n\n executeBuiltin<T = unknown>(\n name: string,\n params?: Record<string, unknown>,\n sharedEngineSafe?: boolean\n ): Promise<T> {\n return this.root.execute<T>(name, params, sharedEngineSafe);\n }\n\n run<T = unknown>(script: string): Promise<T> {\n return this.root.run<T>(script);\n }\n}\n","import type { PsBridgeHost } from \"../plugin\";\n\n/**\n * Base class for feature modules (ADR 0006). A module reaches every dependency\n * through `this.plugin` — `this.plugin.generator` for Photoshop, `this.plugin.logger`,\n * and `this.plugin.emit` / `this.plugin.broadcast` to push Events. Methods are\n * exposed via the `@ws` / `@api` decorators and wired up by `bootstrap`.\n */\nexport abstract class BaseModule {\n constructor(\n public readonly name: string,\n public readonly plugin: PsBridgeHost\n ) {}\n}\n","import { ProtocolMethod } from \"@ps-generator-bridge/sdk\";\nimport { ws } from \"@ps-generator-bridge/sdk/plugin\";\nimport { BaseModule } from \"../base\";\nimport type { PsBridgeHost } from \"../../plugin\";\n\n/**\n * Action-domain feature module (ADR 0006). Exposes the `Action:*` WS Request\n * methods, each backed by a packaged `jsx/Action/<name>.jsx` script run through\n * the plugin's `JsxRunner` (ADR 0008). A jsx failure follows the `\"Error:\"`\n * prefix convention: `JsxRunner` throws, and `Registry.dispatch` turns it into an\n * INTERNAL response — the methods themselves do not catch.\n *\n * Migrated from LightAi's `ActionManager`. The `@McpTool` metadata did not carry\n * over (no MCP runtime here — only the `@ws` WS path), but the human-facing\n * descriptions are preserved as method JSDoc.\n */\n/**\n * The Action module surface a Plugin reaches through `plugin.modules.action`\n * (RFC 0003). `ActionModule implements` this; the SDK re-exports it via\n * src/contract.ts.\n */\nexport interface ActionModuleApi {\n autoCutout(): Promise<boolean>;\n removeBackground(): Promise<{ success: boolean }>;\n}\n\nexport class ActionModule extends BaseModule implements ActionModuleApi {\n constructor(plugin: PsBridgeHost) {\n super(\"action\", plugin);\n }\n\n /**\n * Automatically create a selection for the main subject of the current layer.\n * Runs `jsx/Action/autoCutout.jsx`. The jsx return value is not consulted:\n * success is implicit, and a failure surfaces as a thrown error (hence an\n * INTERNAL response), so this always resolves to `true` on the happy path.\n */\n @ws(ProtocolMethod.ActionAutoCutout)\n async autoCutout(): Promise<boolean> {\n await this.plugin.jsx.execute(\"Action/autoCutout\");\n return true;\n }\n\n /**\n * Remove the background of the current layer. Runs `jsx/Action/removeBackground.jsx`\n * and wraps the jsx's boolean result as `{ success }`.\n */\n @ws(ProtocolMethod.ActionRemoveBackground)\n async removeBackground(): Promise<{ success: boolean }> {\n const result = await this.plugin.jsx.execute<boolean>(\"Action/removeBackground\");\n return { success: result };\n }\n}\n","import { ProtocolMethod } from \"@ps-generator-bridge/sdk\";\nimport { ws } from \"@ps-generator-bridge/sdk/plugin\";\nimport { BaseModule } from \"../base\";\nimport type { PsBridgeHost } from \"../../plugin\";\n\nexport type PsDocument = {\n id: number;\n name: string;\n width: number;\n height: number;\n resolution: number;\n isDirty: boolean;\n filePath?: string;\n};\n\n/**\n * The Document module surface a Plugin reaches through `plugin.modules.document`\n * (RFC 0003). `DocumentModule implements` this; the SDK re-exports it via\n * src/contract.ts.\n */\nexport interface DocumentModuleApi {\n getCurrentDocument(): Promise<PsDocument>;\n exportDocument(params: Record<string, unknown>): Promise<unknown>;\n saveDocument(params: { savePath?: string }): Promise<unknown>;\n}\n\nexport class DocumentModule extends BaseModule implements DocumentModuleApi {\n constructor(plugin: PsBridgeHost) {\n super(\"document\", plugin);\n }\n\n public currentDocument: PsDocument | null = null;\n\n @ws(ProtocolMethod.DocumentCurrent)\n async getCurrentDocument() {\n const data = await this.plugin.jsx.execute(\"Document/getDocumentInfo\");\n if (!data) throw new Error(\"No document is opened\");\n return data as PsDocument;\n }\n\n @ws(ProtocolMethod.DocumentExport)\n async exportDocument(params: Record<string, any>) {\n if (!params.filePath) throw new Error(\"filePath is required\");\n return await this.plugin.jsx.execute(\"Document/exportDocument\", params);\n }\n\n @ws(ProtocolMethod.DocumentSave)\n async saveDocument(params: { savePath?: string }) {\n return await this.plugin.jsx.execute(\"Document/saveDocument\", params);\n }\n}\n","import { ProtocolMethod } from \"@ps-generator-bridge/sdk\";\nimport { ws } from \"@ps-generator-bridge/sdk/plugin\";\nimport { BaseModule } from \"../base\";\nimport type { PsBridgeHost } from \"../../plugin\";\nimport type { PsBounds, PsRect } from \"../../types/ps\";\n\nexport class PsLayer {\n declare public id: number;\n declare public index: number;\n declare public name: string;\n declare public type: number;\n declare public visible: boolean;\n declare public bounds: PsBounds;\n declare public rect: PsRect;\n declare public clip: boolean;\n declare public children?: PsLayer[];\n // public declare generatorSettings?: { [key: string]: any };\n\n constructor(init: Partial<PsLayer>) {\n Object.assign(this, init);\n }\n}\nnamespace LayerModule {\n export type LayerPixelOptions = {\n resolution?: number;\n };\n export interface onImageChangedParams {\n count: number;\n id: number;\n metaDataOnly: boolean;\n layers: {\n id: number;\n bounds: PsBounds;\n pixels: boolean;\n removed?: boolean;\n }[];\n selection: number[];\n timeStamp: number;\n version: string;\n }\n}\n\n/**\n * The Layer module surface a Plugin reaches through `plugin.modules.layer`\n * (RFC 0003). `LayerModule implements` this, so the plugin contract tracks the\n * implementation by compiler force; the SDK re-exports it via src/contract.ts.\n */\nexport interface LayerModuleApi {\n getLayerInfo(options?: {\n id?: number;\n index?: number;\n getChildren?: boolean;\n getGeneratorSettings?: boolean;\n }): Promise<PsLayer>;\n getLayerInfoByID(layerID: number, options?: { getChildren: boolean }): Promise<PsLayer>;\n getLayerInfoByIndex(layerIndex: number, options?: { getChildren: boolean }): Promise<PsLayer>;\n}\n\nexport class LayerModule extends BaseModule implements LayerModuleApi {\n constructor(plugin: PsBridgeHost) {\n super(\"layer\", plugin);\n }\n\n @ws(ProtocolMethod.LayerGetInfo)\n public async getLayerInfo(options?: {\n id?: number;\n index?: number;\n getChildren?: boolean;\n getGeneratorSettings?: boolean;\n }): Promise<PsLayer> {\n return await this.plugin.jsx.execute(\"Layer/getLayerInfo\", {\n layerID: options?.id,\n layerIndex: options?.index,\n getChildren: options?.getChildren,\n getGeneratorSettings: options?.getGeneratorSettings,\n });\n }\n\n @ws(ProtocolMethod.LayerGetInfoById)\n public getLayerInfoByID(\n layerIDOrParams: number | { layerID: number; options?: { getChildren: boolean } },\n options?: {\n getChildren: boolean;\n }\n ): Promise<PsLayer> {\n const layerID = typeof layerIDOrParams === \"number\" ? layerIDOrParams : layerIDOrParams.layerID;\n const resolvedOptions = typeof layerIDOrParams === \"number\" ? options : layerIDOrParams.options;\n if (layerID == null) throw new Error(\"Invalid layerID\");\n const params = {\n layerID: layerID,\n getChildren: resolvedOptions?.getChildren,\n };\n return this.plugin.jsx.execute(\"Layer/getLayerInfo\", params);\n }\n\n @ws(ProtocolMethod.LayerGetInfoByIndex)\n public getLayerInfoByIndex(\n layerIndexOrParams: number | { layerIndex: number; options?: { getChildren: boolean } },\n options?: {\n getChildren: boolean;\n }\n ): Promise<PsLayer> {\n const layerIndex =\n typeof layerIndexOrParams === \"number\" ? layerIndexOrParams : layerIndexOrParams.layerIndex;\n const resolvedOptions =\n typeof layerIndexOrParams === \"number\" ? options : layerIndexOrParams.options;\n if (layerIndex == null) throw new Error(\"Invalid layerIndex\");\n // 明确定义参数类型\n const params = {\n layerIndex,\n getChildren: resolvedOptions?.getChildren,\n };\n return this.plugin.jsx.execute(\"Layer/getLayerInfo\", params);\n }\n}\n","import sharp from \"sharp\";\nimport { BaseModule } from \"../base\";\nimport type { PsBridgeHost } from \"../../plugin\";\nimport type { PsGenerator } from \"../../types/generator\";\nimport type { PsBounds, PsPixmap } from \"../../types/ps\";\nimport { Pixmap } from \"../../utilis/pixmap\";\nimport { ws } from \"@ps-generator-bridge/sdk/plugin\";\nimport { ProtocolMethod, type LayerSpec, type WsImageResult } from \"@ps-generator-bridge/sdk\";\n\n// `LayerSpec` is owned by the protocol (RFC 0008); re-export it so the\n// plugin-facing contract barrel (src/contract.ts) keeps surfacing it from here.\nexport type { LayerSpec };\n\n/**\n * Single-layer pixmap export + preview, isolated from the buggy\n * `generator.getPixmap` (generator-core's version omits the\n * `includeAdjustors/Children/ClipBase/Clipped` flags and passes a stray\n * `settings.thread` field). `getPixmap` here is a faithful port of\n * LightAi's `LayerManager.getPixmap` (index.ts:364-482): it calls the plugin's\n * own `Layer/getLayerPixmap.jsx` over the progress channel and collects the\n * bounds + pixmap + ICC profile messages Photoshop streams back.\n *\n * Whole-document export is handled separately by generator-core's\n * `getDocumentPixmap` (to be wired up later); this module only deals with\n * explicit layer specs, which is what `Layer/getLayerPixmap.jsx` requires.\n *\n * Encoding (raw RGBA -> PNG) goes through `sharp`, externalized from the bundle\n * and resolved from node_modules at runtime inside Photoshop's Node.\n */\n/**\n * The Image module surface a Plugin reaches through `plugin.modules.image`\n * (RFC 0003). `ImageModule implements` this; the SDK re-exports it via\n * src/contract.ts. `settings` is widened to `Record<string, unknown>` so the\n * plugin contract does not drag the generator-core `GetPixmapSettings` namespace\n * into the SDK; `buffer` is `Uint8Array` (not `Buffer`) so the SDK stays\n * Node-free.\n */\nexport interface ImageModuleApi {\n exportImage(options: {\n documentId?: number;\n layerSpec: LayerSpec;\n settings?: Record<string, unknown>;\n }): Promise<ImageResult>;\n getPreview(options: { documentId?: number; layerSpec: number }): Promise<ImageResult>;\n exportDocument(options: {\n documentId?: number;\n settings?: Record<string, unknown>;\n }): Promise<ImageResult>;\n}\n\nexport class ImageModule extends BaseModule implements ImageModuleApi {\n constructor(plugin: PsBridgeHost) {\n super(\"image\", plugin);\n }\n\n /**\n * Export a single layer as a PNG buffer plus its bounds and pixel\n * dimensions. `settings` carries the `GetPixmapSettings` Photoshop accepts;\n * the four `include*` flags default to `true` when unspecified (the fix over\n * generator-core). `layerSpec` is required — the underlying jsx needs an\n * explicit layer id or index range.\n */\n async exportImage(options: {\n documentId?: number;\n layerSpec: LayerSpec;\n settings?: PsGenerator.GetPixmapSettings;\n }): Promise<ImageResult> {\n const { documentId, layerSpec, settings = {} } = options;\n const resolvedDocId = this.resolveDocumentId(documentId);\n const pixmap = await this.getPixmap(resolvedDocId, layerSpec, settings);\n const buffer = await this.encodePng(pixmap);\n return {\n buffer,\n bounds: pixmap.bounds,\n width: pixmap.width,\n height: pixmap.height,\n };\n }\n\n /**\n * Export a downscaled preview of a single layer. The scale is computed so\n * the longer edge lands near 300px; scaling is done by Photoshop via\n * `scaleX/scaleY`, not by `sharp`. `includeClipped/ClipBase/Adjustors` are\n * forced to `false` to fetch only the body layer's pixels. `layerSpec` is\n * required (a layer id; the layer's `rect` drives the scale).\n */\n async getPreview(options: { documentId?: number; layerSpec: number }): Promise<ImageResult> {\n const { documentId, layerSpec } = options;\n const resolvedDocId = this.resolveDocumentId(documentId);\n const settings: PsGenerator.GetPixmapSettings = {};\n\n const layer = await this.plugin.modules.layer.getLayerInfoByID(layerSpec);\n if (!layer?.rect) throw new Error(\"Invalid layer info for preview\");\n settings.includeClipped = false;\n settings.includeClipBase = false;\n settings.includeAdjustors = false;\n const scale = getScale(layer.rect.width, layer.rect.height);\n settings.scaleX = scale;\n settings.scaleY = scale;\n const pixmap = await this.getPixmap(resolvedDocId, layerSpec, settings);\n const buffer = await this.encodePng(pixmap);\n return {\n buffer,\n bounds: pixmap.bounds,\n width: pixmap.width,\n height: pixmap.height,\n };\n }\n\n /**\n * Export the whole document (its current visibility state, flattened) as a PNG\n * buffer plus bounds and pixel dimensions. Unlike `exportImage` (a single layer\n * via the `Layer/getLayerPixmap` jsx protocol), this uses generator-core's\n * built-in `getDocumentPixmap`, which returns an already-parsed `PsPixmap`.\n * `documentId` defaults to the current document; `settings` carries the\n * `GetPixmapSettings` Photoshop accepts (e.g. `scaleX`/`scaleY`).\n */\n async exportDocument(options: {\n documentId?: number;\n settings?: PsGenerator.GetPixmapSettings;\n }): Promise<ImageResult> {\n const documentId = this.resolveDocumentId(options.documentId);\n const pixmap = await this.plugin.generator.getDocumentPixmap(\n documentId,\n options.settings ?? {}\n );\n const buffer = await this.encodePng(pixmap);\n return {\n buffer,\n bounds: pixmap.bounds,\n width: pixmap.width,\n height: pixmap.height,\n };\n }\n\n /**\n * `@ws` wrapper over {@link exportImage} (RFC 0008). Returns a wire-friendly\n * {@link WsImageResult}: when `plugin.cos` is enabled the PNG is uploaded and\n * `data` is an https URL, otherwise `data` is a base64 data URI. A COS upload\n * failure throws (no base64 fallback) — a configured channel must be used.\n */\n @ws(ProtocolMethod.ImageExportLayer)\n async exportLayerWs(options: {\n documentId?: number;\n layerSpec: LayerSpec;\n settings?: PsGenerator.GetPixmapSettings;\n }): Promise<WsImageResult> {\n const result = await this.exportImage(options);\n const name = this.plugin.cos ? await this.resolveLayerName(options.layerSpec) : undefined;\n return this.toWsResult(result, { upload: true }, name);\n }\n\n /**\n * `@ws` wrapper over {@link getPreview} (RFC 0008). Always returns base64 —\n * previews are high-frequency, downscaled thumbnails not worth a COS round-trip,\n * so this never uploads even when `plugin.cos` is enabled.\n */\n @ws(ProtocolMethod.ImageGetPreview)\n async getPreviewWs(options: { documentId?: number; layerSpec: number }): Promise<WsImageResult> {\n const result = await this.getPreview(options);\n return this.toWsResult(result, { upload: false });\n }\n\n /**\n * `@ws` wrapper over {@link exportDocument} (RFC 0008). Uploads to COS when\n * enabled (https URL), else base64; a COS failure throws.\n */\n @ws(ProtocolMethod.ImageExportDocument)\n async exportDocumentWs(options: {\n documentId?: number;\n settings?: PsGenerator.GetPixmapSettings;\n }): Promise<WsImageResult> {\n const result = await this.exportDocument(options);\n const name = this.plugin.cos ? this.resolveDocumentName(options.documentId) : undefined;\n return this.toWsResult(result, { upload: true }, name);\n }\n\n /**\n * Turn a module-internal {@link ImageResult} (raw PNG `buffer`) into the\n * wire-friendly {@link WsImageResult} (`data` string). With `upload` set and\n * `plugin.cos` enabled, the buffer is uploaded and `data` is the signed URL;\n * otherwise `data` is a `data:image/png;base64,...` URI. Both forms drop\n * straight into an `<img src>`.\n */\n private async toWsResult(\n result: ImageResult,\n opts: { upload: boolean },\n name?: string\n ): Promise<WsImageResult> {\n let data: string;\n if (opts.upload && this.plugin.cos) {\n data = await this.plugin.cos.uploadObject(result.buffer, name);\n } else {\n data = \"data:image/png;base64,\" + Buffer.from(result.buffer).toString(\"base64\");\n }\n return {\n data,\n bounds: result.bounds,\n width: result.width,\n height: result.height,\n };\n }\n\n /**\n * Resolve a layer's name for the COS object key. A numeric `layerSpec` is\n * looked up via the layer module; an index-range spec has no single name, so it\n * falls back to \"layers\". Lookup failures degrade to `layer-{id}` rather than\n * failing the export.\n */\n private async resolveLayerName(layerSpec: LayerSpec): Promise<string> {\n if (typeof layerSpec !== \"number\") return \"layers\";\n try {\n const layer = await this.plugin.modules.layer.getLayerInfoByID(layerSpec);\n return layer?.name || `layer-${layerSpec}`;\n } catch {\n return `layer-${layerSpec}`;\n }\n }\n\n /**\n * Resolve a document's name for the COS object key. Uses the current document's\n * name when the target is the current document; otherwise falls back to\n * `doc-{id}` rather than spending a jsx round-trip to name an off-screen doc.\n */\n private resolveDocumentName(documentId?: number): string {\n const resolvedId = this.resolveDocumentId(documentId);\n const current = this.plugin.modules.document.currentDocument;\n if (current && current.id === resolvedId && current.name) return current.name;\n return `doc-${resolvedId}`;\n }\n\n /**\n * Faithful port of LightAi `LayerManager.getPixmap` (index.ts:364-482).\n * Builds the params (dropping generator-core's stray `settings.thread` and\n * defaulting the four `include*` flags to `true`), opens the pixmap jsx over\n * the progress channel, and resolves three native promises as the\n * bounds/pixmap/iccProfile messages arrive. Once all expected messages are\n * in, signals the channel to settle and constructs a `Pixmap`.\n */\n private async getPixmap(\n documentId: number,\n layerSpec: LayerSpec,\n settings: PsGenerator.GetPixmapSettings\n ): Promise<Pixmap> {\n const params: Record<string, unknown> = {\n documentId,\n layerSpec,\n compId: settings.compId,\n compIndex: settings.compIndex,\n inputRect: settings.inputRect,\n outputRect: settings.outputRect,\n scaleX: settings.scaleX || 1,\n scaleY: settings.scaleY || 1,\n bounds: true,\n boundsOnly: settings.boundsOnly,\n useJPGEncoding: settings.useJPGEncoding || \"\",\n useSmartScaling: settings.useSmartScaling || false,\n includeAncestorMasks: settings.includeAncestorMasks || false,\n convertToWorkingRGBProfile: settings.convertToWorkingRGBProfile || false,\n useICCProfile: settings.useICCProfile || \"\",\n getICCProfileData: settings.getICCProfileData || false,\n allowDither: settings.allowDither || false,\n useColorSettingsDither: settings.useColorSettingsDither || false,\n interpolationType: settings.interpolationType,\n forceSmartPSDPixelScaling: settings.forceSmartPSDPixelScaling || false,\n clipToDocumentBounds: settings.clipToDocumentBounds || false,\n maxDimension: settings.maxDimension || 10000,\n clipBounds: settings.clipBounds,\n includeAdjustors: settings.includeAdjustors !== undefined ? settings.includeAdjustors : true,\n includeChildren: settings.includeChildren !== undefined ? settings.includeChildren : true,\n includeClipBase: settings.includeClipBase !== undefined ? settings.includeClipBase : true,\n includeClipped: settings.includeClipped !== undefined ? settings.includeClipped : true,\n };\n\n const channel = this.plugin.jsx.openJSXFile(\"Layer/getLayerPixmap\", params, true);\n\n let jsResolve!: (v: { bounds: PsBounds } | undefined) => void;\n let jsReject!: (e: unknown) => void;\n const jsPromise = new Promise<{ bounds: PsBounds } | undefined>((res, rej) => {\n jsResolve = res;\n jsReject = rej;\n });\n\n let pixmapResolve!: (v: Buffer | undefined) => void;\n let pixmapReject!: (e: unknown) => void;\n const pixmapPromise = new Promise<Buffer | undefined>((res, rej) => {\n pixmapResolve = res;\n pixmapReject = rej;\n });\n\n let profileResolve!: (v: Buffer | undefined) => void;\n let profileReject!: (e: unknown) => void;\n const profilePromise = new Promise<Buffer | undefined>((res, rej) => {\n profileResolve = res;\n profileReject = rej;\n });\n\n channel.onProgress((message) => {\n if (message.type === \"javascript\") {\n // Two javascript responses come back: the JSX result and a bounds\n // object. We only care about the bounds one.\n if (\n message.value instanceof Object &&\n Object.prototype.hasOwnProperty.call(message.value, \"bounds\")\n ) {\n jsResolve(message.value as { bounds: PsBounds });\n }\n } else if (message.type === \"pixmap\") {\n pixmapResolve(message.value as Buffer);\n } else if (message.type === \"iccProfile\") {\n profileResolve(message.value as Buffer);\n }\n });\n\n channel.onFail((err) => {\n jsReject(err);\n pixmapReject(err);\n profileReject(err);\n });\n\n // Resolve early when we aren't expecting a pixmap / ICC profile.\n if (params.boundsOnly) {\n pixmapResolve(undefined);\n profileResolve(undefined);\n }\n if (!params.getICCProfileData) {\n profileResolve(undefined);\n }\n\n const [js, iccProfileBuffer, pixmapBuffer] = await Promise.all([\n jsPromise,\n profilePromise,\n pixmapPromise,\n ]);\n channel.resolve();\n\n if (params.boundsOnly && js && js.bounds) {\n // boundsOnly callers want the bounds object, not a pixmap. Current\n // callers (exportImage/getPreview) never set boundsOnly, so this branch\n // is retained for fidelity with the ported source.\n return js as unknown as Pixmap;\n }\n if (js && js.bounds && pixmapBuffer) {\n const pixmap = new Pixmap(pixmapBuffer);\n pixmap.bounds = js.bounds;\n if (iccProfileBuffer) {\n pixmap.iccProfile = iccProfileBuffer;\n }\n return pixmap;\n }\n throw new Error(\n `Unexpected response from PS in getLayerPixmap: js=${JSON.stringify(js)}, ` +\n `pixmap=${pixmapBuffer ? \"truthy\" : \"falsy\"}, ` +\n `iccExpected=${params.getICCProfileData}`\n );\n }\n\n /**\n * Resolve the document id: explicit override, else the document module's\n * current document, else fail loud (matches LightAi's \"No document opened\").\n */\n private resolveDocumentId(documentId?: number): number {\n if (documentId !== undefined) return documentId;\n const current = this.plugin.modules.document.currentDocument;\n if (current) return current.id;\n throw new Error(\"No document opened\");\n }\n\n /**\n * Convert a pixmap's raw pixels into a tightly-packed RGBA buffer. Handles both\n * the single-layer protocol (`getLayerPixmap`: 4-channel, no row padding) and\n * generator-core's `getDocumentPixmap` (which may return 3-channel pixmaps and\n * rows padded to `rowBytes`). 4-channel is Photoshop's `[A,R,G,B]` layout;\n * 3-channel is `[R,G,B]` and gets an opaque alpha. Rows are walked by\n * `rowBytes` so any per-row padding is skipped rather than misaligning the image.\n */\n private parseRawPixels(pixmap: PsPixmap): Buffer {\n const { width, height, channelCount, pixels } = pixmap;\n if (channelCount !== 3 && channelCount !== 4) {\n throw new Error(`Unsupported channelCount: ${channelCount}`);\n }\n // Trust rowBytes only when it can hold a full row; else assume no padding.\n const rowBytes =\n pixmap.rowBytes && pixmap.rowBytes >= width * channelCount\n ? pixmap.rowBytes\n : width * channelCount;\n const output = Buffer.allocUnsafe(width * height * 4);\n let o = 0;\n for (let y = 0; y < height; y++) {\n let p = y * rowBytes;\n for (let x = 0; x < width; x++) {\n if (channelCount === 4) {\n // [A,R,G,B] -> [R,G,B,A]\n output[o++] = pixels.readUInt8(p + 1); // R\n output[o++] = pixels.readUInt8(p + 2); // G\n output[o++] = pixels.readUInt8(p + 3); // B\n output[o++] = pixels.readUInt8(p); // A\n } else {\n // [R,G,B] -> [R,G,B,255]\n output[o++] = pixels.readUInt8(p); // R\n output[o++] = pixels.readUInt8(p + 1); // G\n output[o++] = pixels.readUInt8(p + 2); // B\n output[o++] = 255; // opaque\n }\n p += channelCount;\n }\n }\n return output;\n }\n\n private async encodePng(pixmap: PsPixmap): Promise<Buffer> {\n const rgba = this.parseRawPixels(pixmap);\n return sharp(rgba, {\n raw: {\n width: pixmap.width,\n height: pixmap.height,\n channels: 4,\n },\n })\n .ensureAlpha()\n .png()\n .toBuffer();\n }\n}\n\n/**\n * Result of an image export / preview: PNG bytes plus geometry metadata. The\n * bytes are typed as `Uint8Array` (the implementation returns a `Buffer`, which\n * is a `Uint8Array` subtype) so this type can cross into the Node-free SDK\n * contract unchanged.\n */\nexport interface ImageResult {\n buffer: Uint8Array;\n bounds: PsBounds;\n width: number;\n height: number;\n}\n\n/**\n * Scale so the longer edge lands near 300px; smaller images keep their size.\n * Port of LightAi's `getScale` (index.ts:748-752).\n */\nconst getScale = (width: number, height: number): number => {\n const xScale = Math.floor(width / 300) || 1;\n const yScale = Math.floor(height / 300) || 1;\n return 1 / Math.min(xScale, yScale);\n};\n","import type { PsPixmap, PsBounds } from \"../types/ps\";\n\nexport class Pixmap implements PsPixmap {\n declare format: number;\n declare width: number;\n declare height: number;\n declare rowBytes: number;\n declare colorMode: number;\n declare channelCount: number;\n declare bitsPerChannel: number;\n declare pixels: Buffer;\n declare bytesPerPixel: number;\n declare padding: number;\n declare bounds: PsBounds;\n declare resolution: number;\n\n declare iccProfile: any;\n\n declare getPixel: (n: number) => any;\n declare readChannel: (n?: number) => any;\n constructor(buffer: Buffer) {\n this.format = buffer.readUInt8(0);\n this.width = buffer.readUInt32BE(1);\n this.height = buffer.readUInt32BE(5);\n this.rowBytes = buffer.readUInt32BE(9);\n this.colorMode = buffer.readUInt8(13);\n this.channelCount = buffer.readUInt8(14);\n this.bitsPerChannel = buffer.readUInt8(15);\n this.pixels = buffer.slice(16, 16 + this.width * this.height * this.channelCount);\n this.bytesPerPixel = (this.bitsPerChannel / 8) * this.channelCount;\n this.padding = this.rowBytes - this.width * this.channelCount;\n this.readChannel = this.getReadChannel(this.bitsPerChannel);\n\n this._initGetPixelMethod(this.channelCount);\n }\n\n public getReadChannel(bitsPerChannel: number): (n?: number) => any {\n if (16 === bitsPerChannel) {\n return Buffer.prototype.readUInt16BE;\n }\n if (8 === bitsPerChannel) {\n return Buffer.prototype.readUInt8;\n }\n if (32 === bitsPerChannel) {\n return Buffer.prototype.readUInt32BE;\n }\n throw new Error(`Unsupported pixmap bit depth: ${bitsPerChannel}`);\n }\n\n private getPixel1(n: number) {\n var pixel = this.getRawPixel(n);\n var grey = this.readChannel.call(pixel, 0);\n return {\n r: grey,\n g: grey,\n b: grey,\n a: 255,\n };\n }\n\n private getPixel3(n: number) {\n var pixel = this.getRawPixel(n);\n return {\n r: this.readChannel.call(pixel, 2),\n g: this.readChannel.call(pixel, 1),\n b: this.readChannel.call(pixel),\n a: 255,\n };\n }\n\n private getPixel4(n: number) {\n var pixel = this.getRawPixel(n);\n return {\n r: this.readChannel.call(pixel, 1),\n g: this.readChannel.call(pixel, 2),\n b: this.readChannel.call(pixel, 3),\n a: this.readChannel.call(pixel, 0),\n };\n }\n\n private _initGetPixelMethod(channelCount: number) {\n if (channelCount === 4) {\n this.getPixel = this.getPixel4;\n }\n if (channelCount === 3) {\n this.getPixel = this.getPixel3;\n }\n if (channelCount === 1) {\n this.getPixel = this.getPixel1;\n }\n }\n\n public getRawPixel(n: number) {\n var i = n * this.bytesPerPixel;\n return this.pixels.slice(i, i + this.bytesPerPixel);\n }\n}\n","import type { BaseModule } from \"./base\";\nimport type { PsBridgeHost } from \"../plugin\";\nimport { ActionModule } from \"./action\";\nimport { DocumentModule } from \"./document\";\nimport { LayerModule } from \"./layer\";\nimport { ImageModule } from \"./image\";\n\nexport { ActionModule } from \"./action\";\nexport { DocumentModule } from \"./document\";\nexport { LayerModule } from \"./layer\";\nexport { ImageModule } from \"./image\";\nexport type { BaseModule } from \"./base\";\n\n/** A module class: constructible from the owning plugin (it calls super(name, plugin)). */\nexport type ModuleClass = new (plugin: PsBridgeHost) => BaseModule;\n\n/**\n * Explicit module manifest (ADR 0006). The bundle has no source directory to scan\n * at runtime, so feature modules must be listed here, keyed by the short name the\n * plugin exposes them under (`plugin.modules.<key>`). The plugin instantiates each\n * with itself and bootstraps the decorated handlers. `@ws`/`@api` names are\n * written in full by the developer (`Domain:action`, mirroring the `jsx/<Domain>/`\n * layout and the SDK's declared `ProtocolMethods` contract); `bootstrap` does not\n * inject a namespace.\n */\nexport const MODULES = {\n layer: LayerModule,\n document: DocumentModule,\n action: ActionModule,\n image: ImageModule,\n} satisfies Record<string, ModuleClass>;\n","import COS from \"cos-nodejs-sdk-v5\";\nimport { extname } from \"node:path\";\nimport type { Logger } from \"../utilis/logger\";\n\n/**\n * Plugin-facing COS contract (RFC 0008). The minimal slice modules and plugins\n * reach through `plugin.cos`: upload in-memory bytes or a local file and get back\n * a ready-to-use signed URL. Params use `Uint8Array`/path strings (never `Buffer`\n * or the COS SDK's own types) so the SDK's re-export of this interface stays\n * Node-free, mirroring how `ImageModuleApi` is exposed.\n */\nexport interface CosServiceApi {\n /** Upload raw bytes, returning a signed URL. `name` labels the object key. */\n uploadObject(data: Uint8Array, name?: string): Promise<string>;\n /** Upload a local file by path, returning a signed URL. */\n uploadFile(dir: string, name?: string): Promise<string>;\n}\n\n/** Permanent-key COS config, read from the environment by {@link CosService.fromEnv}. */\ninterface CosConfig {\n secretId: string;\n secretKey: string;\n bucket: string;\n region: string;\n keyPrefix: string;\n urlExpires: number;\n}\n\n// Defaults applied when the optional COS tuning env vars are unset (RFC 0009).\nconst DEFAULT_KEY_PREFIX = \"ps-bridge/exports\";\n// Signed-URL lifetime: 10 years. Permanent keys (not STS temp credentials) are\n// what make a horizon this long meaningful — a temp credential's signature dies\n// with the credential (RFC 0008).\nconst DEFAULT_URL_EXPIRES_SECONDS = 315360000;\nconst MAX_NAME_LENGTH = 64;\n\n/**\n * Optional object-storage upload unit (RFC 0008). Enabled only when the four\n * `PS_BRIDGE_COS_*` env fields are present; otherwise the host leaves `plugin.cos`\n * undefined and image exports fall back to base64. Uses a permanent key pair and\n * returns signed URLs without an attachment disposition, so the image they point\n * at stays inline-displayable.\n */\nexport class CosService implements CosServiceApi {\n private readonly cos: COS;\n\n constructor(\n private readonly config: CosConfig,\n private readonly logger: Logger\n ) {\n this.cos = new COS({ SecretId: config.secretId, SecretKey: config.secretKey });\n }\n\n /**\n * Build a CosService from the environment, or return undefined when COS is not\n * configured. All four `PS_BRIDGE_COS_SECRET_ID/SECRET_KEY/BUCKET/REGION` must be\n * present and non-empty — a missing field means \"not enabled\", decided once at\n * startup rather than failing loudly on the first upload.\n */\n static fromEnv(logger: Logger): CosService | undefined {\n const secretId = process.env.PS_BRIDGE_COS_SECRET_ID?.trim();\n const secretKey = process.env.PS_BRIDGE_COS_SECRET_KEY?.trim();\n const bucket = process.env.PS_BRIDGE_COS_BUCKET?.trim();\n const region = process.env.PS_BRIDGE_COS_REGION?.trim();\n if (!secretId || !secretKey || !bucket || !region) return undefined;\n const keyPrefix = process.env.PS_BRIDGE_COS_KEY_PREFIX?.trim() || DEFAULT_KEY_PREFIX;\n const expiresRaw = Number(process.env.PS_BRIDGE_COS_URL_EXPIRES);\n const urlExpires =\n Number.isFinite(expiresRaw) && expiresRaw > 0 ? expiresRaw : DEFAULT_URL_EXPIRES_SECONDS;\n return new CosService({ secretId, secretKey, bucket, region, keyPrefix, urlExpires }, logger);\n }\n\n async uploadObject(data: Uint8Array, name?: string): Promise<string> {\n const key = this.buildKey(name, \".png\");\n await this.putObject(key, Buffer.from(data));\n return this.signedUrl(key);\n }\n\n async uploadFile(dir: string, name?: string): Promise<string> {\n const key = this.buildKey(name, extname(dir));\n await this.putFile(key, dir);\n return this.signedUrl(key);\n }\n\n /**\n * Compose the object key `{keyPrefix}/{name}-{ts}{ext}` (keyPrefix is env-\n * configurable, default `ps-bridge/exports`). `name` (a layer/document name) is\n * kept verbatim including non-ASCII (e.g. Chinese); only path separators and\n * whitespace are replaced — they would nest the key or break the URL — and the\n * label is length-capped. Uniqueness rides on the timestamp, not the label.\n */\n private buildKey(name: string | undefined, ext: string): string {\n const label = this.sanitizeName(name ?? \"image\");\n return `${this.config.keyPrefix}/${label}-${Date.now()}${ext}`;\n }\n\n private sanitizeName(name: string): string {\n const cleaned = name\n .replace(/[/\\\\\\s]+/g, \"_\")\n .replace(/^_+/, \"\")\n .slice(0, MAX_NAME_LENGTH);\n return cleaned || \"image\";\n }\n\n private putObject(key: string, body: Buffer): Promise<void> {\n return new Promise((resolve, reject) => {\n this.cos.putObject(\n { Bucket: this.config.bucket, Region: this.config.region, Key: key, Body: body },\n (err, data) => {\n if (err) return reject(new Error(err.message ?? String(err)));\n if (data.statusCode !== 200) {\n return reject(new Error(`COS upload failed: status ${data.statusCode}`));\n }\n this.logger.info(`CosService uploaded object ${key}`);\n resolve();\n }\n );\n });\n }\n\n private putFile(key: string, filePath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.cos.uploadFile(\n { Bucket: this.config.bucket, Region: this.config.region, Key: key, FilePath: filePath },\n (err) => {\n if (err) return reject(new Error(err.message ?? String(err)));\n this.logger.info(`CosService uploaded file ${key}`);\n resolve();\n }\n );\n });\n }\n\n private signedUrl(key: string): Promise<string> {\n return new Promise((resolve, reject) => {\n this.cos.getObjectUrl(\n {\n Bucket: this.config.bucket,\n Region: this.config.region,\n Key: key,\n Sign: true,\n Expires: this.config.urlExpires,\n },\n (err, data) => {\n if (err) return reject(err instanceof Error ? err : new Error(String(err)));\n // Deliberately no `response-content-disposition=attachment`: the URL is\n // meant for `<img src>`, and an attachment disposition would force a\n // download instead of inline display (RFC 0008).\n resolve(data.Url);\n }\n );\n });\n }\n}\n","/**\n * Minimal leveled logger. Console-based to keep the scaffold dependency-light;\n * pino (or any sink) can be swapped in later behind this same `Logger` shape.\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\nfunction format(args: unknown[]): string {\n return args\n .map((arg) => {\n if (arg instanceof Error) return `${arg.name}: ${arg.message}`;\n if (typeof arg === \"object\" && arg !== null) return JSON.stringify(arg);\n return String(arg);\n })\n .join(\" \");\n}\n\nexport function createLogger(name = \"ps-bridge\"): Logger {\n const emit = (level: LogLevel, message: string, args: unknown[]): void => {\n const line = `[${level}] ${name}: ${message}${args.length ? ` ${format(args)}` : \"\"}`;\n if (level === \"error\") console.error(line);\n else if (level === \"warn\") console.warn(line);\n else console.log(line);\n };\n return {\n debug: (message, ...args) => emit(\"debug\", message, args),\n info: (message, ...args) => emit(\"info\", message, args),\n warn: (message, ...args) => emit(\"warn\", message, args),\n error: (message, ...args) => emit(\"error\", message, args),\n };\n}\n"],"mappings":"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","names":["import_node_path","ALLOWED","Fastify","websocket","import_node_path","_a","_init","_a","_init","_a","_init","sharp","import_node_path","COS","resolve","module"]}
@@ -0,0 +1,12 @@
1
+ try {
2
+ function autoCutout() {
3
+ var idautoCutout = stringIDToTypeID("autoCutout");
4
+ var desc1 = new ActionDescriptor();
5
+ var idsampleAllLayers = stringIDToTypeID("sampleAllLayers");
6
+ desc1.putBoolean(idsampleAllLayers, false);
7
+ executeAction(idautoCutout, desc1, DialogModes.NO);
8
+ }
9
+ app.activeDocument.suspendHistory("autoCutout", "autoCutout()");
10
+ } catch (error) {
11
+ alert("[AutoCutout] " + error.message);
12
+ }
@@ -0,0 +1,5 @@
1
+ var desc1 = new ActionDescriptor();
2
+ var ref1 = new ActionReference();
3
+ ref1.putEnumerated(charIDToTypeID("HstS"), charIDToTypeID("Ordn"), charIDToTypeID("Prvs"));
4
+ desc1.putReference(charIDToTypeID("null"), ref1);
5
+ executeAction(charIDToTypeID("slct"), desc1, DialogModes.NO);
@@ -0,0 +1,10 @@
1
+ var _result = (function () {
2
+ try {
3
+ var idremoveBackground = stringIDToTypeID("removeBackground");
4
+ executeAction(idremoveBackground, undefined, DialogModes.NO);
5
+ return true;
6
+ } catch (error) {
7
+ return false;
8
+ }
9
+ })();
10
+ _result;
@@ -0,0 +1,4 @@
1
+ var message = params.message || "";
2
+ var title = params.title || "LightAi PS";
3
+
4
+ alert(message, title);
@@ -0,0 +1,43 @@
1
+ /**
2
+ * 这个函数接受一个AD的对象,返回这个对象所有属性值的JSON结构
3
+ * @param desc [ActionDescriptor]
4
+ * @return JSON
5
+ */
6
+ function ADToJson(desc) {
7
+ var json = {};
8
+ for (var i = 0; i < desc.count; i++) {
9
+ var typeID = desc.getKey(i);
10
+ var stringID = typeIDToStringID(typeID);
11
+ var typeString = desc.getType(typeID).toString();
12
+ alert(stringID + " " + typeString);
13
+ switch (typeString) {
14
+ case "DescValueType.BOOLEANTYPE":
15
+ json[stringID] = desc.getBoolean(typeID);
16
+ break;
17
+ case "DescValueType.DOUBLETYPE":
18
+ json[stringID] = desc.getDouble(typeID);
19
+ break;
20
+ case "DescValueType.INTEGERTYPE":
21
+ json[stringID] = desc.getInteger(typeID);
22
+ break;
23
+ case "DescValueType.STRINGTYPE":
24
+ json[stringID] = desc.getString(typeID);
25
+ break;
26
+ case "DescValueType.OBJECTTYPE":
27
+ var objectValue = desc.getObjectValue(typeID);
28
+ json[stringID] = ADToJson(objectValue);
29
+ break;
30
+ case "DescValueType.UNITDOUBLE":
31
+ json[stringID] = desc.getUnitDoubleValue(typeID);
32
+ break;
33
+ case "DescValueType.CLASSTYPE":
34
+ case "DescValueType.LISTTYPE":
35
+ case "DescValueType.REFERENCETYPE":
36
+ // 剩下这些留给你去补充完成
37
+ break;
38
+ default:
39
+ break;
40
+ }
41
+ }
42
+ return json;
43
+ }
@@ -0,0 +1,4 @@
1
+ var eventObj = new CSXSEvent();
2
+ eventObj.type = "com.posidon.generator.plugin";
3
+ eventObj.data = params;
4
+ eventObj.dispatch();