@sealpixel/plugin-sdk 1.0.0-rc.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/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @sealpixel/plugin-sdk
2
+
3
+ Build plugins for the Sealpixel image editor. A plugin adds operations to the edit log, a kernel (JavaScript, a separate WebAssembly module, or one compiled into the core), and optionally a UI tool. The same package runs on the client and the server.
@@ -0,0 +1,55 @@
1
+ import type { AssetDeclaration, Document, DocumentRegistry, KernelDef, Operation, OperationBase, OperationDef, OperationSchema, PlanContext, SealpixelPlugin, SourceDescriptor, StageParams, ToolDef, ValidateContext, ValidateDocumentContext } from '@sealpixel/core';
2
+ import { type OptionsDef } from './options.js';
3
+ export type { AssetDeclaration, Document, DocumentRegistry, KernelContext, KernelDef, OperationDef, OperationSchema, OptionsSchema, PlanContext, PreviewHint, SealpixelPlugin, StageParams, ToolContext, ToolDef, ValidateContext, ValidateDocumentContext, } from '@sealpixel/core';
4
+ export { describeIssues, mergeOptions, type OptionsDef } from './options.js';
5
+ /**
6
+ * Declares one operation: its wire type, a runtime schema and a pure reducer
7
+ * over the plugin's document slice.
8
+ */
9
+ export declare function defineOperation<Doc, Op extends OperationBase<string>>(def: {
10
+ type: Op['type'];
11
+ schema: OperationSchema<Op>;
12
+ reduce: (slice: Doc, op: Op) => Doc;
13
+ migrate?: (fromVersion: number, op: unknown) => unknown;
14
+ }): OperationDef<Doc, Op>;
15
+ export interface PluginInput<Id extends string, Doc, Options = undefined> {
16
+ id: Id;
17
+ version: number;
18
+ operations: ReadonlyArray<OperationDef<Doc, any>>;
19
+ initialDocument: Doc;
20
+ stage: {
21
+ name: string;
22
+ order: number;
23
+ };
24
+ toPlan: (slice: Doc, ctx: PlanContext & {
25
+ options: Options;
26
+ }) => StageParams | null;
27
+ kernel: KernelDef;
28
+ tool?: () => Promise<ToolDef>;
29
+ /** Declared assets, or a function of the options (a sticker library, fonts). */
30
+ assets?: AssetDeclaration[] | ((options: Options) => AssetDeclaration[]);
31
+ /** Options schema and defaults. Omit for plugins without options. */
32
+ options?: OptionsDef<Options>;
33
+ /** Constraint check per operation; return a message to reject. */
34
+ validate?: (op: Operation, ctx: ValidateContext<Doc, Options>) => string | null;
35
+ /** Constraint check on the final state before export or server render. */
36
+ validateDocument?: (slice: Doc, ctx: ValidateDocumentContext<Options>) => string | null;
37
+ /** Ops that seed an empty log from option defaults (a default preset, a locked watermark). */
38
+ initialOps?: (ctx: {
39
+ options: Options;
40
+ source: SourceDescriptor;
41
+ }) => Omit<Operation, 'id'>[];
42
+ }
43
+ /** A plugin whose `options` and `configure` are typed. */
44
+ export type ConfigurablePlugin<Id extends string, Doc, Options> = Omit<SealpixelPlugin<Id, Doc, Options>, 'options' | 'configure'> & {
45
+ options: Options;
46
+ configure: (partial: Partial<Options>) => ConfigurablePlugin<Id, Doc, Options>;
47
+ };
48
+ /** Validates the static shape of a plugin and returns it typed for the registry. */
49
+ export declare function definePlugin<Id extends string, Doc, Options extends object>(input: PluginInput<Id, Doc, Options> & {
50
+ options: OptionsDef<Options>;
51
+ }): ConfigurablePlugin<Id, Doc, Options>;
52
+ export declare function definePlugin<Id extends string, Doc>(input: PluginInput<Id, Doc, undefined>): SealpixelPlugin<Id, Doc>;
53
+ /** Reads a plugin's slice from a document with the right type. */
54
+ export declare function sliceOf<K extends keyof DocumentRegistry>(doc: Document, id: K): DocumentRegistry[K];
55
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,67 @@
1
+ import { describeIssues, mergeOptions } from './options.js';
2
+ export { describeIssues, mergeOptions } from './options.js';
3
+ /**
4
+ * Declares one operation: its wire type, a runtime schema and a pure reducer
5
+ * over the plugin's document slice.
6
+ */
7
+ export function defineOperation(def) {
8
+ if (!def.type.includes('.')) {
9
+ throw new TypeError(`operation type "${def.type}" must be namespaced as "<plugin>.<verb>"`);
10
+ }
11
+ return def;
12
+ }
13
+ // biome-ignore lint/suspicious/noExplicitAny: the overloads above carry the public types
14
+ export function definePlugin(input) {
15
+ if (!/^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)*$/.test(input.id)) {
16
+ throw new TypeError(`plugin id "${input.id}" must be lowercase dot-separated segments`);
17
+ }
18
+ if (!Number.isInteger(input.version) || input.version < 1) {
19
+ throw new TypeError(`plugin "${input.id}" version must be a positive integer`);
20
+ }
21
+ const seen = new Set();
22
+ for (const op of input.operations) {
23
+ if (!op.type.startsWith(`${input.id}.`)) {
24
+ throw new TypeError(`operation "${op.type}" must start with "${input.id}."`);
25
+ }
26
+ if (seen.has(op.type))
27
+ throw new TypeError(`duplicate operation type "${op.type}"`);
28
+ seen.add(op.type);
29
+ }
30
+ if (!Number.isFinite(input.stage.order)) {
31
+ throw new TypeError(`plugin "${input.id}" stage order must be a finite number`);
32
+ }
33
+ const { options: optionsDef, assets, ...rest } = input;
34
+ if (!optionsDef) {
35
+ if (typeof assets === 'function') {
36
+ throw new TypeError(`plugin "${input.id}" declares assets as a function but has no options`);
37
+ }
38
+ return assets ? { ...rest, assets } : rest;
39
+ }
40
+ // biome-ignore lint/suspicious/noExplicitAny: options are validated by the schema at runtime
41
+ const build = (options) => ({
42
+ ...rest,
43
+ assets: typeof assets === 'function' ? assets(options) : (assets ?? []),
44
+ options,
45
+ optionsSchema: optionsDef.schema,
46
+ optionsDescribe: (optionsDef.describe ?? {}),
47
+ optionsDefaults: optionsDef.defaults,
48
+ toPlan: (slice, ctx) => input.toPlan(slice, { ...ctx, options }),
49
+ configure: (partial) => {
50
+ const merged = mergeOptions(options, partial);
51
+ const parsed = optionsDef.schema.safeParse
52
+ ? optionsDef.schema.safeParse(merged)
53
+ : { success: true, data: optionsDef.schema.parse(merged) };
54
+ if (!parsed.success) {
55
+ throw new TypeError(`plugin "${input.id}" options: ${describeIssues(parsed.error)}`);
56
+ }
57
+ return build(parsed.data);
58
+ },
59
+ });
60
+ // Defaults must satisfy the schema themselves: a plugin author's typo fails at definition time.
61
+ return build(optionsDef.schema.parse(optionsDef.defaults));
62
+ }
63
+ /** Reads a plugin's slice from a document with the right type. */
64
+ export function sliceOf(doc, id) {
65
+ return doc[id];
66
+ }
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAmB,MAAM,cAAc,CAAC;AAoB7E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAmB,MAAM,cAAc,CAAC;AAE7E;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAwC,GAKtE;IACC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,SAAS,CAAC,mBAAmB,GAAG,CAAC,IAAI,2CAA2C,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAwCD,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAyB,KAAgC;IACnF,IAAI,CAAC,uCAAuC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,SAAS,CAAC,cAAc,KAAK,CAAC,EAAE,4CAA4C,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,SAAS,CAAC,WAAW,KAAK,CAAC,EAAE,sCAAsC,CAAC,CAAC;IACjF,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QAClC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,CAAC,IAAI,sBAAsB,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,6BAA6B,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC;QACpF,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,SAAS,CAAC,WAAW,KAAK,CAAC,EAAE,uCAAuC,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IACvD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;YACjC,MAAM,IAAI,SAAS,CAAC,WAAW,KAAK,CAAC,EAAE,oDAAoD,CAAC,CAAC;QAC/F,CAAC;QACD,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7C,CAAC;IACD,6FAA6F;IAC7F,MAAM,KAAK,GAAG,CAAC,OAAY,EAAqC,EAAE,CAAC,CAAC;QAClE,GAAG,IAAI;QACP,MAAM,EAAE,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;QACvE,OAAO;QACP,aAAa,EAAE,UAAU,CAAC,MAAM;QAChC,eAAe,EAAE,CAAC,UAAU,CAAC,QAAQ,IAAI,EAAE,CAAqC;QAChF,eAAe,EAAE,UAAU,CAAC,QAAQ;QACpC,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,CAAC;QAChE,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;YACrB,MAAM,MAAM,GAAG,YAAY,CAAC,OAAiB,EAAE,OAAO,CAAC,CAAC;YACxD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,SAAS;gBACxC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;gBACrC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAa,EAAE,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACtE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAM,IAAI,SAAS,CAAC,WAAW,KAAK,CAAC,EAAE,cAAc,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACvF,CAAC;YACD,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;KACF,CAAC,CAAC;IACH,gGAAgG;IAChG,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,OAAO,CACrB,GAAa,EACb,EAAK;IAEL,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC;AACjB,CAAC"}
package/dist/math.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Deterministic helpers for JavaScript kernels. Everything here is integer
3
+ * math or IEEE-754 operations that every engine performs identically (add,
4
+ * subtract, multiply, divide, floor). Avoid `Math.sin`, `Math.pow`,
5
+ * `Math.exp` and friends in kernels: engines are free to differ in their last
6
+ * bits. Precompute such tables in Rust or ship them as constants.
7
+ */
8
+ /** Round half away from zero, the rule the Rust core uses. */
9
+ export declare function roundHalfAwayFromZero(x: number): number;
10
+ export declare function clamp(x: number, lo: number, hi: number): number;
11
+ /** 0..1 to 0..255 with the core's rounding. */
12
+ export declare function toByte(x: number): number;
13
+ /** Builds a 256-entry lookup table from a function on 0..1. */
14
+ export declare function buildLut(fn: (x: number) => number): Uint8Array;
15
+ /** Applies a lookup table to the RGB channels in place, leaving alpha untouched. */
16
+ export declare function applyLut(data: Uint8Array | Uint8ClampedArray, lut: Uint8Array): void;
17
+ /**
18
+ * Integer box blur, one horizontal-then-vertical pass with clamped edges on a
19
+ * single-channel `Uint16Array` plane. Matches the Rust core's `box_blur_pass`.
20
+ */
21
+ export declare function boxBlurPass(src: Uint16Array, dst: Uint16Array, width: number, height: number, radius: number): void;
22
+ /** Three box passes, matching the Rust core's `box_blur3`. */
23
+ export declare function boxBlur3(plane: Uint16Array, width: number, height: number, radius: number): void;
24
+ //# sourceMappingURL=math.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,8DAA8D;AAC9D,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,+CAA+C;AAC/C,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAExC;AAED,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,UAAU,CAI9D;AAED,oFAAoF;AACpF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,iBAAiB,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAMpF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,IAAI,CA2BN;AAED,8DAA8D;AAC9D,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAOhG"}
package/dist/math.js ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Deterministic helpers for JavaScript kernels. Everything here is integer
3
+ * math or IEEE-754 operations that every engine performs identically (add,
4
+ * subtract, multiply, divide, floor). Avoid `Math.sin`, `Math.pow`,
5
+ * `Math.exp` and friends in kernels: engines are free to differ in their last
6
+ * bits. Precompute such tables in Rust or ship them as constants.
7
+ */
8
+ /** Round half away from zero, the rule the Rust core uses. */
9
+ export function roundHalfAwayFromZero(x) {
10
+ return x < 0 ? -Math.floor(-x + 0.5) : Math.floor(x + 0.5);
11
+ }
12
+ export function clamp(x, lo, hi) {
13
+ return x < lo ? lo : x > hi ? hi : x;
14
+ }
15
+ /** 0..1 to 0..255 with the core's rounding. */
16
+ export function toByte(x) {
17
+ return roundHalfAwayFromZero(clamp(x, 0, 1) * 255);
18
+ }
19
+ /** Builds a 256-entry lookup table from a function on 0..1. */
20
+ export function buildLut(fn) {
21
+ const lut = new Uint8Array(256);
22
+ for (let i = 0; i < 256; i++)
23
+ lut[i] = toByte(fn(i / 255));
24
+ return lut;
25
+ }
26
+ /** Applies a lookup table to the RGB channels in place, leaving alpha untouched. */
27
+ export function applyLut(data, lut) {
28
+ for (let i = 0; i < data.length; i += 4) {
29
+ data[i] = lut[data[i]];
30
+ data[i + 1] = lut[data[i + 1]];
31
+ data[i + 2] = lut[data[i + 2]];
32
+ }
33
+ }
34
+ /**
35
+ * Integer box blur, one horizontal-then-vertical pass with clamped edges on a
36
+ * single-channel `Uint16Array` plane. Matches the Rust core's `box_blur_pass`.
37
+ */
38
+ export function boxBlurPass(src, dst, width, height, radius) {
39
+ const tmp = new Uint16Array(width * height);
40
+ const window = 2 * radius + 1;
41
+ for (let y = 0; y < height; y++) {
42
+ const row = y * width;
43
+ let sum = 0;
44
+ for (let i = 0; i <= radius; i++)
45
+ sum += src[row + Math.min(i, width - 1)];
46
+ sum += src[row] * radius;
47
+ for (let x = 0; x < width; x++) {
48
+ tmp[row + x] = Math.floor((sum + Math.floor(window / 2)) / window);
49
+ const add = src[row + Math.min(x + radius + 1, width - 1)];
50
+ const sub = src[row + Math.max(x - radius, 0)];
51
+ sum = sum + add - sub;
52
+ }
53
+ }
54
+ for (let x = 0; x < width; x++) {
55
+ const at = (y) => tmp[Math.min(y, height - 1) * width + x];
56
+ let sum = 0;
57
+ for (let i = 0; i <= radius; i++)
58
+ sum += at(i);
59
+ sum += at(0) * radius;
60
+ for (let y = 0; y < height; y++) {
61
+ dst[y * width + x] = Math.floor((sum + Math.floor(window / 2)) / window);
62
+ const add = at(y + radius + 1);
63
+ const sub = at(Math.max(y - radius, 0));
64
+ sum = sum + add - sub;
65
+ }
66
+ }
67
+ }
68
+ /** Three box passes, matching the Rust core's `box_blur3`. */
69
+ export function boxBlur3(plane, width, height, radius) {
70
+ if (radius === 0)
71
+ return;
72
+ const buf = new Uint16Array(width * height);
73
+ boxBlurPass(plane, buf, width, height, radius);
74
+ boxBlurPass(buf, plane, width, height, radius);
75
+ boxBlurPass(plane, buf, width, height, radius);
76
+ plane.set(buf);
77
+ }
78
+ //# sourceMappingURL=math.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.js","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { SealpixelError as CoreError, OptionsSchema } from '@sealpixel/core';
2
+ /**
3
+ * Declares a plugin's options: a zod (or zod-like) schema for the *complete*
4
+ * options object and the defaults it starts from. `configure(partial)` merges
5
+ * shallowly over the current options and re-validates the result, so a host
6
+ * can override one key without repeating the rest.
7
+ */
8
+ export interface OptionsDef<Options> {
9
+ schema: OptionsSchema<Options>;
10
+ defaults: Options;
11
+ /**
12
+ * Human descriptions per top-level key, used by the docs generator next to
13
+ * the schema-derived type and default.
14
+ */
15
+ describe?: Partial<Record<keyof Options & string, string>>;
16
+ }
17
+ /** Shallow merge with `undefined` entries in `partial` ignored. */
18
+ export declare function mergeOptions<Options extends object>(current: Options, partial: unknown): Options;
19
+ /** Turns a zod-style error into one readable line. */
20
+ export declare function describeIssues(error: unknown): string;
21
+ export type { CoreError };
22
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,IAAI,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAElF;;;;;GAKG;AACH,MAAM,WAAW,UAAU,CAAC,OAAO;IACjC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5D;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,OAAO,SAAS,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAShG;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMrD;AAED,YAAY,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,21 @@
1
+ /** Shallow merge with `undefined` entries in `partial` ignored. */
2
+ export function mergeOptions(current, partial) {
3
+ if (partial === null || typeof partial !== 'object' || Array.isArray(partial)) {
4
+ throw new TypeError('plugin options must be a plain object');
5
+ }
6
+ const out = { ...current };
7
+ for (const [k, v] of Object.entries(partial)) {
8
+ if (v !== undefined)
9
+ out[k] = v;
10
+ }
11
+ return out;
12
+ }
13
+ /** Turns a zod-style error into one readable line. */
14
+ export function describeIssues(error) {
15
+ if (error && typeof error === 'object' && 'issues' in error) {
16
+ const issues = error.issues;
17
+ return issues.map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`).join('; ');
18
+ }
19
+ return error instanceof Error ? error.message : String(error);
20
+ }
21
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAkBA,mEAAmE;AACnE,MAAM,UAAU,YAAY,CAAyB,OAAgB,EAAE,OAAgB;IACrF,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9E,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,GAAG,GAA4B,EAAE,GAAI,OAAmC,EAAE,CAAC;IACjF,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAkC,CAAC,EAAE,CAAC;QACxE,IAAI,CAAC,KAAK,SAAS;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,GAAc,CAAC;AACxB,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;QAC5D,MAAM,MAAM,GAAI,KAAgE,CAAC,MAAM,CAAC;QACxF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@sealpixel/plugin-sdk",
3
+ "version": "1.0.0-rc.0",
4
+ "description": "Build Sealpixel plugins: definePlugin, defineOperation, and deterministic math helpers for JS kernels.",
5
+ "license": "BUSL-1.1",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/9feet/sealpixel.git",
9
+ "directory": "packages/plugin-sdk"
10
+ },
11
+ "homepage": "https://docs.sealpixel.dev",
12
+ "bugs": "https://github.com/9feet/sealpixel/issues",
13
+ "type": "module",
14
+ "sideEffects": false,
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ },
24
+ "./math": {
25
+ "types": "./dist/math.d.ts",
26
+ "default": "./dist/math.js"
27
+ },
28
+ "./package.json": "./package.json"
29
+ },
30
+ "scripts": {
31
+ "build": "tsc -p tsconfig.build.json",
32
+ "typecheck": "tsc -p tsconfig.json --noEmit",
33
+ "test": "vitest run"
34
+ },
35
+ "peerDependencies": {
36
+ "@sealpixel/core": "workspace:*",
37
+ "zod": "^4.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@sealpixel/config": "workspace:*",
41
+ "@sealpixel/core": "workspace:*",
42
+ "@sealpixel/wasm": "workspace:*",
43
+ "@types/node": "^24.0.0",
44
+ "typescript": "^5.9.0",
45
+ "vitest": "^4.0.0",
46
+ "zod": "^4.0.0"
47
+ }
48
+ }