@ps-generator-bridge/sdk 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.
- package/LICENSE +21 -0
- package/dist/PsPhotoshopProxy-BjnvziWn.d.cts +879 -0
- package/dist/PsPhotoshopProxy-BjnvziWn.d.ts +879 -0
- package/dist/index.cjs +1131 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +210 -0
- package/dist/index.d.ts +210 -0
- package/dist/index.js +1117 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.cjs +915 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +457 -0
- package/dist/plugin.d.ts +457 -0
- package/dist/plugin.js +902 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +64 -0
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { L as LayerSpec, e as PsPhotoshopProxy } from './PsPhotoshopProxy-BjnvziWn.js';
|
|
2
|
+
export { A as AnchorPosition, w as AnchorPositionValue, x as BlendMode, y as BlendModeValue, D as DocumentMode, z as DocumentModeValue, C as ElementPlacement, F as ElementPlacementValue, G as LayerKind, H as LayerKindValue, J as PhotoshopApp, K as PhotoshopDocument, N as PhotoshopLayer, O as PhotoshopLayers, Q as PhotoshopSelection, T as PsBoundsTuple, U as PsColor, V as SaveOptions, X as SaveOptionsValue, Y as SelectionType, Z as SelectionTypeValue } from './PsPhotoshopProxy-BjnvziWn.js';
|
|
3
|
+
|
|
4
|
+
type PsBounds = {
|
|
5
|
+
left: number;
|
|
6
|
+
right: number;
|
|
7
|
+
top: number;
|
|
8
|
+
bottom: number;
|
|
9
|
+
};
|
|
10
|
+
type PsRect = {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The slice of JsxRunner a Plugin reaches through `plugin.jsx` (RFC 0003 /
|
|
19
|
+
* RFC 0005). The concrete JsxRunner `implements` this (and `forPlugin` returns a
|
|
20
|
+
* scoped view that also implements it), so the plugin contract can never drift
|
|
21
|
+
* from the implementation; the SDK re-exports it (via src/contract.ts) as the
|
|
22
|
+
* type of `PluginHost.jsx`. Excludes lifecycle (`init`) and the low-level pixmap
|
|
23
|
+
* channel (`openJSXFile`) — plugins only run jsx by name (or raw string).
|
|
24
|
+
*
|
|
25
|
+
* `execute` resolves against *this handle's own* jsx scope: the built-in `jsx/`
|
|
26
|
+
* tree for the host's root runner, or the plugin's own `jsx/` dir for the scoped
|
|
27
|
+
* view `plugin.jsx` returns. `executeBuiltin` always targets the built-in tree,
|
|
28
|
+
* so a plugin can reach a host domain (e.g. `Document/getDocumentInfo`) without
|
|
29
|
+
* knowing its own id or dir. `run` takes a raw script and is scope-independent.
|
|
30
|
+
*/
|
|
31
|
+
interface JsxRunnerApi {
|
|
32
|
+
execute<T = unknown>(name: string, params?: Record<string, unknown>, sharedEngineSafe?: boolean): Promise<T>;
|
|
33
|
+
executeBuiltin<T = unknown>(name: string, params?: Record<string, unknown>, sharedEngineSafe?: boolean): Promise<T>;
|
|
34
|
+
run<T = unknown>(script: string): Promise<T>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Layer/document bounds in pixels. The console logged this as `[Object]` (not
|
|
39
|
+
* expanded); this is the standard generator bounds shape.
|
|
40
|
+
*/
|
|
41
|
+
interface Bounds {
|
|
42
|
+
top: number;
|
|
43
|
+
left: number;
|
|
44
|
+
bottom: number;
|
|
45
|
+
right: number;
|
|
46
|
+
}
|
|
47
|
+
/** One entry in `imageChanged.layers` — a layer touched by the change. */
|
|
48
|
+
interface ImageChangedLayer {
|
|
49
|
+
/** Layer id (stable across the session). */
|
|
50
|
+
id: number;
|
|
51
|
+
/** Present (true) when the layer's pixels changed. */
|
|
52
|
+
pixels?: boolean;
|
|
53
|
+
/** Present (true) when the layer was removed in this change. */
|
|
54
|
+
removed?: boolean;
|
|
55
|
+
/** Layer bounds; present on geometry/pixel changes. */
|
|
56
|
+
bounds?: Bounds;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Payload of the `imageChanged` event. Fields are a union of everything PS may
|
|
60
|
+
* send; only `version` / `timeStamp` / `count` / `id` are always present. A
|
|
61
|
+
* single event carries *either* metadata flags (`metaDataOnly`, `selection`),
|
|
62
|
+
* *or* `layers`, *or* document-level flags (`active` / `file` / `closed`).
|
|
63
|
+
*/
|
|
64
|
+
interface ImageChangedEvent {
|
|
65
|
+
/** Generator protocol version, e.g. "1.6.1". */
|
|
66
|
+
version: string;
|
|
67
|
+
/** Seconds since epoch (float), e.g. 1782455135.936. */
|
|
68
|
+
timeStamp: number;
|
|
69
|
+
/** Per-document monotonically increasing change counter (resets per doc id). */
|
|
70
|
+
count: number;
|
|
71
|
+
/** Document id this change belongs to. */
|
|
72
|
+
id: number;
|
|
73
|
+
/** True on the first event for a doc / on activation. */
|
|
74
|
+
active?: boolean;
|
|
75
|
+
/** Document title or full path, e.g. "Test-恢复的.psd" or "C:\\...\\Test.psd". */
|
|
76
|
+
file?: string;
|
|
77
|
+
/** True when the document was closed. */
|
|
78
|
+
closed?: boolean;
|
|
79
|
+
/** True when only metadata changed (no pixel/layer body). */
|
|
80
|
+
metaDataOnly?: boolean;
|
|
81
|
+
/** Selected layer indices; empty array when the selection is cleared. */
|
|
82
|
+
selection?: number[];
|
|
83
|
+
/** Layers touched by this change (pixel edits, bounds, removals). */
|
|
84
|
+
layers?: ImageChangedLayer[];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Map of Photoshop event name -> payload type passed to the listener. Shapes
|
|
88
|
+
* marked "observed" were confirmed from live PS output; the rest are inferred
|
|
89
|
+
* from the generator protocol docs.
|
|
90
|
+
*/
|
|
91
|
+
interface PhotoshopEventMap {
|
|
92
|
+
/** [workspace display name] (inferred). */
|
|
93
|
+
workspaceChanged: string;
|
|
94
|
+
/** Tool name, e.g. "paintbrushTool" / "moveTool" (observed). */
|
|
95
|
+
toolChanged: string;
|
|
96
|
+
/** "enter" | "exit" (inferred). */
|
|
97
|
+
quickMaskStateChanged: string;
|
|
98
|
+
/** Document id (observed). */
|
|
99
|
+
documentChanged: number;
|
|
100
|
+
/** Document id of the closed document (observed). */
|
|
101
|
+
closedDocument: number;
|
|
102
|
+
/** Document id (inferred). */
|
|
103
|
+
newDocumentViewCreated: number;
|
|
104
|
+
/** Document id (inferred). */
|
|
105
|
+
activeViewChanged: number;
|
|
106
|
+
/** Document id of the now-current document (observed). */
|
|
107
|
+
currentDocumentChanged: number;
|
|
108
|
+
/** Color as 6-character hex value (inferred). */
|
|
109
|
+
backgroundColorChanged: string;
|
|
110
|
+
/** Color as 6-character hex value (inferred). */
|
|
111
|
+
foregroundColorChanged: string;
|
|
112
|
+
/** Image/document change descriptor (observed). */
|
|
113
|
+
imageChanged: ImageChangedEvent;
|
|
114
|
+
}
|
|
115
|
+
/** Listener for a given Photoshop event key. */
|
|
116
|
+
type PhotoshopEventListener<K extends keyof PhotoshopEventMap> = (payload: PhotoshopEventMap[K]) => void;
|
|
117
|
+
/**
|
|
118
|
+
* Listen-only typed surface a Plugin reaches through `plugin.events` /
|
|
119
|
+
* `this.events`. `EventManager` (an `EventEmitter`) `implements` this; `emit` is
|
|
120
|
+
* deliberately excluded — a Plugin subscribes, it never dispatches Photoshop
|
|
121
|
+
* events.
|
|
122
|
+
*/
|
|
123
|
+
interface PhotoshopEvents {
|
|
124
|
+
on<K extends keyof PhotoshopEventMap>(event: K, listener: PhotoshopEventListener<K>): this;
|
|
125
|
+
once<K extends keyof PhotoshopEventMap>(event: K, listener: PhotoshopEventListener<K>): this;
|
|
126
|
+
off<K extends keyof PhotoshopEventMap>(event: K, listener: PhotoshopEventListener<K>): this;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Action-domain feature module (ADR 0006). Exposes the `Action:*` WS Request
|
|
131
|
+
* methods, each backed by a packaged `jsx/Action/<name>.jsx` script run through
|
|
132
|
+
* the plugin's `JsxRunner` (ADR 0008). A jsx failure follows the `"Error:"`
|
|
133
|
+
* prefix convention: `JsxRunner` throws, and `Registry.dispatch` turns it into an
|
|
134
|
+
* INTERNAL response — the methods themselves do not catch.
|
|
135
|
+
*
|
|
136
|
+
* Migrated from LightAi's `ActionManager`. The `@McpTool` metadata did not carry
|
|
137
|
+
* over (no MCP runtime here — only the `@ws` WS path), but the human-facing
|
|
138
|
+
* descriptions are preserved as method JSDoc.
|
|
139
|
+
*/
|
|
140
|
+
/**
|
|
141
|
+
* The Action module surface a Plugin reaches through `plugin.modules.action`
|
|
142
|
+
* (RFC 0003). `ActionModule implements` this; the SDK re-exports it via
|
|
143
|
+
* src/contract.ts.
|
|
144
|
+
*/
|
|
145
|
+
interface ActionModuleApi {
|
|
146
|
+
autoCutout(): Promise<boolean>;
|
|
147
|
+
removeBackground(): Promise<{
|
|
148
|
+
success: boolean;
|
|
149
|
+
}>;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
type PsDocument = {
|
|
153
|
+
id: number;
|
|
154
|
+
name: string;
|
|
155
|
+
width: number;
|
|
156
|
+
height: number;
|
|
157
|
+
resolution: number;
|
|
158
|
+
isDirty: boolean;
|
|
159
|
+
filePath?: string;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* The Document module surface a Plugin reaches through `plugin.modules.document`
|
|
163
|
+
* (RFC 0003). `DocumentModule implements` this; the SDK re-exports it via
|
|
164
|
+
* src/contract.ts.
|
|
165
|
+
*/
|
|
166
|
+
interface DocumentModuleApi {
|
|
167
|
+
getCurrentDocument(): Promise<PsDocument>;
|
|
168
|
+
exportDocument(params: Record<string, unknown>): Promise<unknown>;
|
|
169
|
+
saveDocument(params: {
|
|
170
|
+
savePath?: string;
|
|
171
|
+
}): Promise<unknown>;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Single-layer pixmap export + preview, isolated from the buggy
|
|
176
|
+
* `generator.getPixmap` (generator-core's version omits the
|
|
177
|
+
* `includeAdjustors/Children/ClipBase/Clipped` flags and passes a stray
|
|
178
|
+
* `settings.thread` field). `getPixmap` here is a faithful port of
|
|
179
|
+
* LightAi's `LayerManager.getPixmap` (index.ts:364-482): it calls the plugin's
|
|
180
|
+
* own `Layer/getLayerPixmap.jsx` over the progress channel and collects the
|
|
181
|
+
* bounds + pixmap + ICC profile messages Photoshop streams back.
|
|
182
|
+
*
|
|
183
|
+
* Whole-document export is handled separately by generator-core's
|
|
184
|
+
* `getDocumentPixmap` (to be wired up later); this module only deals with
|
|
185
|
+
* explicit layer specs, which is what `Layer/getLayerPixmap.jsx` requires.
|
|
186
|
+
*
|
|
187
|
+
* Encoding (raw RGBA -> PNG) goes through `sharp`, externalized from the bundle
|
|
188
|
+
* and resolved from node_modules at runtime inside Photoshop's Node.
|
|
189
|
+
*/
|
|
190
|
+
/**
|
|
191
|
+
* The Image module surface a Plugin reaches through `plugin.modules.image`
|
|
192
|
+
* (RFC 0003). `ImageModule implements` this; the SDK re-exports it via
|
|
193
|
+
* src/contract.ts. `settings` is widened to `Record<string, unknown>` so the
|
|
194
|
+
* plugin contract does not drag the generator-core `GetPixmapSettings` namespace
|
|
195
|
+
* into the SDK; `buffer` is `Uint8Array` (not `Buffer`) so the SDK stays
|
|
196
|
+
* Node-free.
|
|
197
|
+
*/
|
|
198
|
+
interface ImageModuleApi {
|
|
199
|
+
exportImage(options: {
|
|
200
|
+
documentId?: number;
|
|
201
|
+
layerSpec: LayerSpec;
|
|
202
|
+
settings?: Record<string, unknown>;
|
|
203
|
+
}): Promise<ImageResult>;
|
|
204
|
+
getPreview(options: {
|
|
205
|
+
documentId?: number;
|
|
206
|
+
layerSpec: number;
|
|
207
|
+
}): Promise<ImageResult>;
|
|
208
|
+
exportDocument(options: {
|
|
209
|
+
documentId?: number;
|
|
210
|
+
settings?: Record<string, unknown>;
|
|
211
|
+
}): Promise<ImageResult>;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Result of an image export / preview: PNG bytes plus geometry metadata. The
|
|
215
|
+
* bytes are typed as `Uint8Array` (the implementation returns a `Buffer`, which
|
|
216
|
+
* is a `Uint8Array` subtype) so this type can cross into the Node-free SDK
|
|
217
|
+
* contract unchanged.
|
|
218
|
+
*/
|
|
219
|
+
interface ImageResult {
|
|
220
|
+
buffer: Uint8Array;
|
|
221
|
+
bounds: PsBounds;
|
|
222
|
+
width: number;
|
|
223
|
+
height: number;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Plugin-facing COS contract (RFC 0008). The minimal slice modules and plugins
|
|
228
|
+
* reach through `plugin.cos`: upload in-memory bytes or a local file and get back
|
|
229
|
+
* a ready-to-use signed URL. Params use `Uint8Array`/path strings (never `Buffer`
|
|
230
|
+
* or the COS SDK's own types) so the SDK's re-export of this interface stays
|
|
231
|
+
* Node-free, mirroring how `ImageModuleApi` is exposed.
|
|
232
|
+
*/
|
|
233
|
+
interface CosServiceApi {
|
|
234
|
+
/** Upload raw bytes, returning a signed URL. `name` labels the object key. */
|
|
235
|
+
uploadObject(data: Uint8Array, name?: string): Promise<string>;
|
|
236
|
+
/** Upload a local file by path, returning a signed URL. */
|
|
237
|
+
uploadFile(dir: string, name?: string): Promise<string>;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
declare class PsLayer {
|
|
241
|
+
id: number;
|
|
242
|
+
index: number;
|
|
243
|
+
name: string;
|
|
244
|
+
type: number;
|
|
245
|
+
visible: boolean;
|
|
246
|
+
bounds: PsBounds;
|
|
247
|
+
rect: PsRect;
|
|
248
|
+
clip: boolean;
|
|
249
|
+
children?: PsLayer[];
|
|
250
|
+
constructor(init: Partial<PsLayer>);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* The Layer module surface a Plugin reaches through `plugin.modules.layer`
|
|
254
|
+
* (RFC 0003). `LayerModule implements` this, so the plugin contract tracks the
|
|
255
|
+
* implementation by compiler force; the SDK re-exports it via src/contract.ts.
|
|
256
|
+
*/
|
|
257
|
+
interface LayerModuleApi {
|
|
258
|
+
getLayerInfo(options?: {
|
|
259
|
+
id?: number;
|
|
260
|
+
index?: number;
|
|
261
|
+
getChildren?: boolean;
|
|
262
|
+
getGeneratorSettings?: boolean;
|
|
263
|
+
}): Promise<PsLayer>;
|
|
264
|
+
getLayerInfoByID(layerID: number, options?: {
|
|
265
|
+
getChildren: boolean;
|
|
266
|
+
}): Promise<PsLayer>;
|
|
267
|
+
getLayerInfoByIndex(layerIndex: number, options?: {
|
|
268
|
+
getChildren: boolean;
|
|
269
|
+
}): Promise<PsLayer>;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* The plugin contract a Plugin depends on (RFC 0003) — a deliberately narrowed
|
|
274
|
+
* view of the server's `PsBridgeHost`. Exposes only what a Plugin needs: the JSX
|
|
275
|
+
* seam and the feature-module accessors (all typed by the generator's own
|
|
276
|
+
* contract interfaces), plus the listen-only event stream. Excludes
|
|
277
|
+
* broadcast/emit/server/the raw generator handle — a Plugin manages its own
|
|
278
|
+
* clients through BasePlugin.broadcast/send.
|
|
279
|
+
*
|
|
280
|
+
* This is the one hand-written piece of the plugin surface that stays in the
|
|
281
|
+
* SDK: it is a *curation* of the host, not a mirror of it. Its member types are
|
|
282
|
+
* imported (type-only) from the generator contract so they can never drift from
|
|
283
|
+
* the implementation. The server's `PsBridgeHost implements PluginHost`;
|
|
284
|
+
* external Plugins only ever see this interface, so they depend on the SDK alone
|
|
285
|
+
* at runtime, never on the server package.
|
|
286
|
+
*/
|
|
287
|
+
interface PluginHost {
|
|
288
|
+
readonly jsx: JsxRunnerApi;
|
|
289
|
+
/** Feature modules, reached by short key (e.g. `plugin.modules.layer`). */
|
|
290
|
+
readonly modules: {
|
|
291
|
+
layer: LayerModuleApi;
|
|
292
|
+
document: DocumentModuleApi;
|
|
293
|
+
action: ActionModuleApi;
|
|
294
|
+
image: ImageModuleApi;
|
|
295
|
+
};
|
|
296
|
+
/** Typed, listen-only Photoshop event stream (lazy subscribe). */
|
|
297
|
+
readonly events: PhotoshopEvents;
|
|
298
|
+
/**
|
|
299
|
+
* Optional object-storage upload service (RFC 0008). Present only when the host
|
|
300
|
+
* has COS configured via the environment; undefined otherwise. A plugin guards
|
|
301
|
+
* on it: `if (this.plugin.cos) await this.plugin.cos.uploadObject(bytes)`.
|
|
302
|
+
*/
|
|
303
|
+
readonly cos?: CosServiceApi;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Per-plugin client push bus (RFC 0004). BasePlugin.broadcast/send delegate to
|
|
308
|
+
* this; the server's per-plugin assembler attaches a concrete adapter backed by
|
|
309
|
+
* the plugin's own ClientStore after construction. Defined in the SDK so
|
|
310
|
+
* BasePlugin can be implemented without depending on the server.
|
|
311
|
+
*/
|
|
312
|
+
interface PluginClientBus {
|
|
313
|
+
/** Push an Event to every online client of this plugin. */
|
|
314
|
+
broadcast(type: string, data: unknown): void;
|
|
315
|
+
/** Push an Event to one client of this plugin (no-op if not connected). */
|
|
316
|
+
send(clientId: string, type: string, data: unknown): void;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Base class for plugins (ADR 0009 / RFC 0003). A plugin is the orchestration
|
|
321
|
+
* layer above feature modules: it composes one or more module calls (reached
|
|
322
|
+
* through `this.modules`, e.g. `this.modules.layer`) and exposes
|
|
323
|
+
* its own `@ws`/`@api` handlers, bootstrapped the same way as modules.
|
|
324
|
+
*
|
|
325
|
+
* Dependency direction is strictly downward: a plugin may depend on modules,
|
|
326
|
+
* never on sibling plugins and never in reverse (modules must not reach
|
|
327
|
+
* plugins). `plugin` is the abstract PluginHost interface — never the
|
|
328
|
+
* concrete server plugin — so a plugin depends only on this SDK subpath.
|
|
329
|
+
*
|
|
330
|
+
* `@ws`/`@api` names are written in full by the developer (e.g.
|
|
331
|
+
* `@ws("LayerOps:merge")`) — `bootstrap` does not inject or derive a namespace.
|
|
332
|
+
* Use a `Domain:action` prefix to keep names from colliding across modules and
|
|
333
|
+
* plugins (ADR 0006 convention); the assembler's `registerMethod` is a silent
|
|
334
|
+
* `Map.set`, so prefix uniqueness is the developer's responsibility.
|
|
335
|
+
*
|
|
336
|
+
* Client push: `broadcast`/`send` reach only this plugin's own online clients,
|
|
337
|
+
* via the PluginClientBus the server attaches after construction. A subclass
|
|
338
|
+
* may override `onConnect`/`onDisconnect` to react to its clients coming and
|
|
339
|
+
* going; the defaults are no-ops.
|
|
340
|
+
*/
|
|
341
|
+
declare abstract class BasePlugin {
|
|
342
|
+
/** Stable URL identity of this plugin (read from the class's `static id`). */
|
|
343
|
+
readonly id: string;
|
|
344
|
+
/** The abstract plugin contract (never the concrete server plugin). */
|
|
345
|
+
protected readonly plugin: PluginHost;
|
|
346
|
+
private bus;
|
|
347
|
+
private _photoshop;
|
|
348
|
+
constructor(id: string, plugin: PluginHost);
|
|
349
|
+
/** Feature modules, reached by short key (shortcut for `this.plugin.modules`). */
|
|
350
|
+
protected get modules(): PluginHost["modules"];
|
|
351
|
+
/**
|
|
352
|
+
* The jsx runner scoped to this plugin's own `jsx/` dir (shortcut for
|
|
353
|
+
* `this.plugin.jsx`, RFC 0005). `jsx.execute("x")` runs `<pluginRoot>/jsx/x.jsx`;
|
|
354
|
+
* `jsx.executeBuiltin("Document/getDocumentInfo")` reaches the host's built-in
|
|
355
|
+
* tree.
|
|
356
|
+
*/
|
|
357
|
+
protected get jsx(): JsxRunnerApi;
|
|
358
|
+
/**
|
|
359
|
+
* Typed, listen-only Photoshop event stream (shortcut for `this.plugin.events`).
|
|
360
|
+
* Subscriptions are lazy on the server side: the first `on`/`once` for an event
|
|
361
|
+
* subscribes upstream, and the last `off` unsubscribes.
|
|
362
|
+
*/
|
|
363
|
+
protected get events(): PhotoshopEvents;
|
|
364
|
+
/**
|
|
365
|
+
* Photoshop DOM proxy, a typed object wrapper over `this.jsx`. Read and write
|
|
366
|
+
* the live document through `this.photoshop.app` / `this.photoshop.activeDocument`
|
|
367
|
+
* (e.g. `await this.photoshop.activeDocument.name`) instead of hand-writing
|
|
368
|
+
* ExtendScript. Lazily built once and backed by this plugin's own jsx runner;
|
|
369
|
+
* drop to `this.jsx.run(...)` for anything the proxy does not cover.
|
|
370
|
+
*/
|
|
371
|
+
protected get photoshop(): PsPhotoshopProxy;
|
|
372
|
+
/**
|
|
373
|
+
* Attach the per-plugin client bus. Called by the server's assembler after
|
|
374
|
+
* construction and before `listen`, so `broadcast`/`send` are live by the time
|
|
375
|
+
* any handler can fire. Not part of the public Plugin authoring API.
|
|
376
|
+
*/
|
|
377
|
+
_attachBus(bus: PluginClientBus): void;
|
|
378
|
+
/** Push an Event to every online client of this plugin. */
|
|
379
|
+
broadcast(type: string, data: unknown): void;
|
|
380
|
+
/** Push an Event to one client of this plugin (no-op if not connected). */
|
|
381
|
+
send(clientId: string, type: string, data: unknown): void;
|
|
382
|
+
/** Called after a client handshake registers with this plugin. Default no-op. */
|
|
383
|
+
onConnect(_clientId: string): void;
|
|
384
|
+
/** Called after a client socket is removed from this plugin. Default no-op. */
|
|
385
|
+
onDisconnect(_clientId: string): void;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Whether `S` is a class that extends BasePlugin. Uses the global brand rather
|
|
389
|
+
* than `instanceof` so it works when `S` came from a separately-bundled copy of
|
|
390
|
+
* this SDK (external plugins). The brand is inherited via the prototype chain,
|
|
391
|
+
* so direct and indirect subclasses both qualify.
|
|
392
|
+
*/
|
|
393
|
+
declare function isBasePluginClass(S: unknown): boolean;
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Minimal HTTP vocabulary for the @api decorator (ADR 0006 / RFC 0003). The SDK
|
|
397
|
+
* plugin subpath is platform-neutral and must not depend on fastify, so it
|
|
398
|
+
* declares its own string union; the server adapts it to fastify's HTTPMethods
|
|
399
|
+
* at the assembly boundary.
|
|
400
|
+
*/
|
|
401
|
+
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
|
|
402
|
+
/**
|
|
403
|
+
* A WS Request handler as seen by the plugin devkit (ADR 0006 open-ended
|
|
404
|
+
* contract). params/result are `unknown` at this layer; the SDK re-applies
|
|
405
|
+
* strong types for declared methods. `ctx` is opaque here — the server supplies
|
|
406
|
+
* a typed HandlerContext, and a handler accepting `unknown` accepts it.
|
|
407
|
+
*/
|
|
408
|
+
type MethodHandler = (params: unknown, ctx: unknown) => Promise<unknown> | unknown;
|
|
409
|
+
/**
|
|
410
|
+
* An HTTP route handler as seen by the plugin devkit. request/reply are opaque
|
|
411
|
+
* (platform-neutral SDK); the server casts to fastify's request/reply at the
|
|
412
|
+
* assembly boundary.
|
|
413
|
+
*/
|
|
414
|
+
type ApiHandler = (request: unknown, reply: unknown) => Promise<unknown> | unknown;
|
|
415
|
+
/** An HTTP route a module or plugin exposes via @api (ADR 0006). */
|
|
416
|
+
interface ApiRouteSpec {
|
|
417
|
+
method: HttpMethod | HttpMethod[];
|
|
418
|
+
url: string;
|
|
419
|
+
handler: ApiHandler;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Abstract assembly target (ADR 0006 / RFC 0003): the second-stage bootstrap
|
|
423
|
+
* registers scanned @ws/@api metadata against this. The server provides two
|
|
424
|
+
* concrete implementations — the global Registry (modules + builtins) and a
|
|
425
|
+
* per-plugin scoped assembler (RFC 0004). The SDK only depends on this shape,
|
|
426
|
+
* keeping the dependency arrow server -> sdk / plugin -> sdk acyclic.
|
|
427
|
+
*/
|
|
428
|
+
interface AssemblyTarget {
|
|
429
|
+
registerMethod(name: string, handler: MethodHandler): void;
|
|
430
|
+
registerApi(route: ApiRouteSpec): void;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/** Mark a method as a WS Request handler registered under `name` (ADR 0006). */
|
|
434
|
+
declare function ws(name: string): (_value: unknown, context: ClassMethodDecoratorContext) => void;
|
|
435
|
+
/**
|
|
436
|
+
* Mark a method as an HTTP route handler. `@api("/path")` defaults to GET;
|
|
437
|
+
* `@api({ method, url })` selects the verb(s) (ADR 0006). The route URL is
|
|
438
|
+
* registered verbatim for modules (under `/{path}`) and prefixed with the
|
|
439
|
+
* plugin id for plugins (under `/{pluginId}/{path}`, RFC 0004) — the
|
|
440
|
+
* decorator only collects metadata; the assembly target decides the final URL.
|
|
441
|
+
*/
|
|
442
|
+
declare function api(pathOrRoute: string | {
|
|
443
|
+
method?: HttpMethod | HttpMethod[];
|
|
444
|
+
url: string;
|
|
445
|
+
}): (_value: unknown, context: ClassMethodDecoratorContext) => void;
|
|
446
|
+
/**
|
|
447
|
+
* Second stage of decorator registration (ADR 0006 / 0009): scan a module or
|
|
448
|
+
* plugin instance's collected metadata and register each decorated method
|
|
449
|
+
* against the assembly target, bound to the instance so handlers can reach
|
|
450
|
+
* `this`. Walks the metadata prototype chain so inherited handlers are included.
|
|
451
|
+
* The `@ws`/`@api` name is registered verbatim — developers write the full
|
|
452
|
+
* `Domain:action` name; no namespace is injected. For a plugin, the target is
|
|
453
|
+
* the per-plugin scoped assembler (RFC 0004); for a module, the global Registry.
|
|
454
|
+
*/
|
|
455
|
+
declare function bootstrap(instance: object, target: AssemblyTarget): void;
|
|
456
|
+
|
|
457
|
+
export { type ActionModuleApi, type ApiHandler, type ApiRouteSpec, type AssemblyTarget, BasePlugin, type Bounds, type CosServiceApi, type DocumentModuleApi, type HttpMethod, type ImageChangedEvent, type ImageChangedLayer, type ImageModuleApi, type ImageResult, type JsxRunnerApi, type LayerModuleApi, LayerSpec, type MethodHandler, type PhotoshopEventListener, type PhotoshopEventMap, type PhotoshopEvents, type PluginClientBus, type PluginHost, type PsBounds, type PsDocument, PsLayer, PsPhotoshopProxy, type PsRect, api, bootstrap, isBasePluginClass, ws };
|