@sealpixel/render 1.0.0-rc.13

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.md ADDED
@@ -0,0 +1,59 @@
1
+ # Business Source License 1.1
2
+
3
+ ## Parameters
4
+
5
+ **Licensor:** nine feet UG (haftungsbeschränkt), Germany (https://9feet.io)
6
+
7
+ **Licensed Work:** Sealpixel, in every version the Licensor publishes: the source code, the npm packages under the `@sealpixel` scope and the unscoped `sealpixel` package, the Rust crates, the WebAssembly binaries, the documentation and the example projects. The Licensed Work is (c) 2026 nine feet UG (haftungsbeschränkt).
8
+
9
+ **Additional Use Grant:** You may make production use of the Licensed Work if you are a Small User. You are a Small User if you are a natural person acting for yourself, or if the organization you act for had less than EUR 1,000,000 of gross revenue in its most recent completed financial year. Revenue is counted across the whole group: the organization, everything that controls it, everything it controls, and everything under common control with it. Where the work is done for a client, the client's revenue decides.
10
+
11
+ This Additional Use Grant does not permit offering the Licensed Work, or a work that includes or is derived from it, to third parties as a product or service whose primary purpose is image editing, image cropping, annotation, redaction, watermarking or server-side image rendering.
12
+
13
+ **Change Date:** Four years after the date on which the Licensor first publishes a specific version of the Licensed Work.
14
+
15
+ **Change License:** Apache License, Version 2.0
16
+
17
+ For information about alternative licensing arrangements for the Licensed Work, please visit: https://sealpixel.dev/pricing
18
+
19
+ Organizations, and anyone who develops with the Licensed Work for an organization, obtain the commercial license this License refers to as developer seats under the Sealpixel Developer Seat License, published at https://sealpixel.dev/license#seats and as `LICENSE-COMMERCIAL.md` in the source repository.
20
+
21
+ ## Notice
22
+
23
+ The Business Source License (this document, or the "License") is not an Open Source license. However, the Licensed Work will eventually be made available under an Open Source License, as stated in this License.
24
+
25
+ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. "Business Source License" is a trademark of MariaDB Corporation Ab.
26
+
27
+ ---
28
+
29
+ ## Terms
30
+
31
+ The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use.
32
+
33
+ Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate.
34
+
35
+ If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work.
36
+
37
+ All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor.
38
+
39
+ You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work.
40
+
41
+ Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work.
42
+
43
+ This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License).
44
+
45
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
46
+
47
+ MariaDB hereby grants you permission to use this License's text to license your works, and to refer to it using the trademark "Business Source License", as long as you comply with the Covenants of Licensor below.
48
+
49
+ ## Covenants of Licensor
50
+
51
+ In consideration of the right to use this License's text and the "Business Source License" name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor:
52
+
53
+ 1. To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where "compatible" means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses without limitation.
54
+
55
+ 2. To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text "None".
56
+
57
+ 3. To specify a Change Date.
58
+
59
+ 4. Not to modify this License in any other way.
package/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # @sealpixel/render
2
+
3
+ Renders a Sealpixel edit log on the original with the same WebAssembly core as the browser, so the bytes match a browser export. The original's bytes and the edit log go in. The rendered file comes out. For Node, Deno, Bun and AWS Lambda.
4
+
5
+ ```ts
6
+ import { createRenderer } from '@sealpixel/render';
7
+ import { defaultPlugins } from '@sealpixel/plugins';
8
+
9
+ const renderer = createRenderer({ plugins: defaultPlugins });
10
+
11
+ const { log, index } = saved; // from the editor's getEditLog()
12
+ const result = await renderer.render({
13
+ original, // Uint8Array, the original byte for byte
14
+ editLog: log,
15
+ upTo: index,
16
+ output: { format: 'image/jpeg', quality: 0.9 },
17
+ });
18
+ // { bytes, stream(), hash, width, height, mimeType, timings }
19
+ ```
20
+
21
+ The package checks the limits, the log and the original before it renders. It loads no font or image: pass their bytes as `assets`. Every failure is a `SealpixelError` with a stable code. It does no routing, no CORS and no storage. Put it inside your own route, function or job worker.
22
+
23
+ Documentation: https://docs.sealpixel.dev/render/
@@ -0,0 +1,34 @@
1
+ import { type AnyPlugin, type AssetResolver, type EditLog } from '@sealpixel/core';
2
+ /** The bytes of one font or image, under the id that the ops use. */
3
+ export interface AssetBytes {
4
+ id: string;
5
+ bytes: Uint8Array;
6
+ }
7
+ /** An asset that a render can need. */
8
+ export interface AssetInfo {
9
+ id: string;
10
+ /** The sha256 that the bytes must have. */
11
+ sha256: string;
12
+ /** Where the declaration says the bytes are. Information for the host only. */
13
+ url?: string;
14
+ }
15
+ /**
16
+ * Lists the assets that a render can need: the declarations of the plugins,
17
+ * then the entries of `editLog.assets`. A plugin declaration wins over a log
18
+ * entry with the same id. Pure: it reads and fetches nothing.
19
+ */
20
+ export declare function assetDeclarations(plugins: readonly AnyPlugin[], editLog?: Pick<EditLog, 'assets'> | null): AssetInfo[];
21
+ /**
22
+ * A resolver over bytes the host passed. It never loads anything. An id
23
+ * without bytes is `MISSING_ASSET`. Bytes whose sha256 differs from the
24
+ * declaration are `SOURCE_MISMATCH`. Both carry `details.assetId`.
25
+ */
26
+ export declare function passedAssetResolver(passed: ReadonlyMap<string, Uint8Array>, declarations: readonly AssetInfo[], hashOf: (bytes: Uint8Array) => string): AssetResolver;
27
+ /**
28
+ * The passed assets whose bytes match their declared sha256, or that have no
29
+ * declaration. The renderer puts these into the core before the render, so the
30
+ * pipeline runs once. A mismatched asset stays out: when the render needs it,
31
+ * the resolver throws `SOURCE_MISMATCH`.
32
+ */
33
+ export declare function verifiedAssets(passed: ReadonlyMap<string, Uint8Array>, declarations: readonly AssetInfo[], hashOf: (bytes: Uint8Array) => string): [id: string, bytes: Uint8Array][];
34
+ //# sourceMappingURL=assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,OAAO,EAGb,MAAM,iBAAiB,CAAC;AAEzB,qEAAqE;AACrE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,UAAU,CAAC;CACnB;AAED,uCAAuC;AACvC,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,SAAS,EAAE,EAC7B,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,IAAI,GACvC,SAAS,EAAE,CAWb;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,EACvC,YAAY,EAAE,SAAS,SAAS,EAAE,EAClC,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,MAAM,GACpC,aAAa,CA2Bf;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,EACvC,YAAY,EAAE,SAAS,SAAS,EAAE,EAClC,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,MAAM,GACpC,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,EAAE,CAMnC"}
package/dist/assets.js ADDED
@@ -0,0 +1,59 @@
1
+ import { SealpixelError, staticAssetResolver, } from '@sealpixel/core';
2
+ /**
3
+ * Lists the assets that a render can need: the declarations of the plugins,
4
+ * then the entries of `editLog.assets`. A plugin declaration wins over a log
5
+ * entry with the same id. Pure: it reads and fetches nothing.
6
+ */
7
+ export function assetDeclarations(plugins, editLog) {
8
+ const byId = new Map();
9
+ for (const decl of [...plugins.flatMap((p) => p.assets ?? []), ...(editLog?.assets ?? [])]) {
10
+ if (byId.has(decl.id))
11
+ continue;
12
+ byId.set(decl.id, {
13
+ id: decl.id,
14
+ sha256: decl.hash,
15
+ ...(decl.url === undefined ? {} : { url: decl.url }),
16
+ });
17
+ }
18
+ return [...byId.values()];
19
+ }
20
+ /**
21
+ * A resolver over bytes the host passed. It never loads anything. An id
22
+ * without bytes is `MISSING_ASSET`. Bytes whose sha256 differs from the
23
+ * declaration are `SOURCE_MISMATCH`. Both carry `details.assetId`.
24
+ */
25
+ export function passedAssetResolver(passed, declarations, hashOf) {
26
+ const declared = new Map(declarations.map((d) => [d.id, d.sha256]));
27
+ return {
28
+ declarations: () => declarations.filter((d) => passed.has(d.id)).map((d) => ({ id: d.id, hash: d.sha256 })),
29
+ async resolve(id) {
30
+ const bytes = passed.get(id);
31
+ if (bytes === undefined) {
32
+ throw new SealpixelError('MISSING_ASSET', `asset "${id}" was not passed to the renderer`, {
33
+ assetId: id,
34
+ });
35
+ }
36
+ const expected = declared.get(id);
37
+ const actual = hashOf(bytes);
38
+ if (expected !== undefined && actual !== expected) {
39
+ throw new SealpixelError('SOURCE_MISMATCH', `asset "${id}" has sha256 ${actual}, the declaration expects ${expected}`, { assetId: id });
40
+ }
41
+ // Only the asset asked for is hashed, not every one the host passed.
42
+ return staticAssetResolver([{ declaration: { id, hash: actual }, bytes }], hashOf).resolve(id);
43
+ },
44
+ };
45
+ }
46
+ /**
47
+ * The passed assets whose bytes match their declared sha256, or that have no
48
+ * declaration. The renderer puts these into the core before the render, so the
49
+ * pipeline runs once. A mismatched asset stays out: when the render needs it,
50
+ * the resolver throws `SOURCE_MISMATCH`.
51
+ */
52
+ export function verifiedAssets(passed, declarations, hashOf) {
53
+ const declared = new Map(declarations.map((d) => [d.id, d.sha256]));
54
+ return [...passed].filter(([id, bytes]) => {
55
+ const expected = declared.get(id);
56
+ return expected === undefined || hashOf(bytes) === expected;
57
+ });
58
+ }
59
+ //# sourceMappingURL=assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.js","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { estimateMemoryMB } from '@sealpixel/core';
2
+ export { type AssetBytes, type AssetInfo, assetDeclarations } from './assets.js';
3
+ export { createRenderer, type Renderer, type RendererOptions, type RenderInput, type RenderLimits, type RenderOutput, } from './renderer.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EACL,cAAc,EACd,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { estimateMemoryMB } from '@sealpixel/core';
2
+ export { assetDeclarations } from './assets.js';
3
+ export { createRenderer, } from './renderer.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAmC,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EACL,cAAc,GAMf,MAAM,eAAe,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { type AnyPlugin, type OutputOptions, type PluginOptionsMap } from '@sealpixel/core';
2
+ import { type LoadOptions } from '@sealpixel/wasm';
3
+ import { type AssetBytes } from './assets.js';
4
+ export interface RenderLimits {
5
+ /** Largest original, in megapixels, read from the header before any decode. Default 80. */
6
+ maxMegapixels?: number;
7
+ /** Largest original, in bytes. Default 100e6. */
8
+ maxBytes?: number;
9
+ /** Largest edit log, in UTF-8 bytes of its canonical JSON. Default 2e6. */
10
+ maxLogBytes?: number;
11
+ }
12
+ export interface RendererOptions {
13
+ /** The plugins that interpret the log. Register the same list as the editor. */
14
+ plugins: readonly AnyPlugin[];
15
+ /** `{ pluginId: partialOptions }` applied through `configurePlugins`. Mirror the editor's. */
16
+ pluginOptions?: PluginOptionsMap;
17
+ /**
18
+ * Fonts and images that every render can use, for example the plugins'
19
+ * fonts. The renderer loads no asset itself.
20
+ */
21
+ assets?: readonly AssetBytes[];
22
+ limits?: RenderLimits;
23
+ /** Reject an original whose sha256 differs from `log.source.hash`, when the log has one. Default true. */
24
+ verifySourceHash?: boolean;
25
+ /**
26
+ * Where the WebAssembly binary comes from. Omit it when `@sealpixel/wasm` is
27
+ * installed in `node_modules`. A bundle passes `{ module: <path to sealpixel_core_bg.wasm> }`.
28
+ */
29
+ wasm?: LoadOptions;
30
+ }
31
+ export interface RenderInput {
32
+ /** The original, byte for byte: the file the editor loaded. */
33
+ original: Uint8Array;
34
+ /** The edit log from the editor's `getEditLog().log`. Untrusted: it is parsed and checked. */
35
+ editLog: unknown;
36
+ /** Render `ops[0..upTo)`: the `index` from `getEditLog()`. Default: every op. */
37
+ upTo?: number;
38
+ /** Default `{ format: 'image/png' }`. */
39
+ output?: OutputOptions;
40
+ /** Fonts and images of this log only, for example uploaded stickers. They win over `createRenderer`'s. */
41
+ assets?: readonly AssetBytes[];
42
+ /** Store `{ log, index }` in the file's metadata. Default false. */
43
+ embedEditLog?: boolean;
44
+ signal?: AbortSignal;
45
+ }
46
+ export interface RenderOutput {
47
+ /** The encoded file. */
48
+ bytes: Uint8Array;
49
+ /** A stream over `bytes`. The file is complete before the stream starts, so it saves no memory. */
50
+ stream(): ReadableStream<Uint8Array>;
51
+ /** sha256 of `bytes`, computed inside the core. */
52
+ hash: string;
53
+ width: number;
54
+ height: number;
55
+ mimeType: OutputOptions['format'];
56
+ /** Milliseconds per step: `check`, `decode`, `render`, `encode`, `total`. */
57
+ timings: Record<string, number>;
58
+ }
59
+ export interface Renderer {
60
+ /** Runs every check, then renders. Every failure is a `SealpixelError`. */
61
+ render(input: RenderInput): Promise<RenderOutput>;
62
+ }
63
+ /**
64
+ * Creates a renderer: original bytes and edit log in, rendered file out.
65
+ * Create it once per process. It builds the registry once and loads the
66
+ * WebAssembly core once, on the first render.
67
+ */
68
+ export declare function createRenderer(options: RendererOptions): Renderer;
69
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAMd,KAAK,aAAa,EAClB,KAAK,gBAAgB,EAKtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,KAAK,WAAW,EAAyC,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EACL,KAAK,UAAU,EAIhB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,YAAY;IAC3B,2FAA2F;IAC3F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IAC9B,8FAA8F;IAC9F,aAAa,CAAC,EAAE,gBAAgB,CAAC;IACjC;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,0GAA0G;IAC1G,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,QAAQ,EAAE,UAAU,CAAC;IACrB,8FAA8F;IAC9F,OAAO,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,0GAA0G;IAC1G,MAAM,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,oEAAoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,KAAK,EAAE,UAAU,CAAC;IAClB,mGAAmG;IACnG,MAAM,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC;IACrC,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAClC,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,QAAQ;IACvB,2EAA2E;IAC3E,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACnD;AAID;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,QAAQ,CAkLjE"}
@@ -0,0 +1,190 @@
1
+ import { canonicalJson, compile, configurePlugins, createRegistry, estimateMemoryMB, readImageSize, render, SealpixelError, } from '@sealpixel/core';
2
+ import { loadSealpixelWasm } from '@sealpixel/wasm';
3
+ import { assetDeclarations, passedAssetResolver, verifiedAssets, } from './assets.js';
4
+ const FORMATS = new Set(['image/png', 'image/jpeg', 'image/webp']);
5
+ /**
6
+ * Creates a renderer: original bytes and edit log in, rendered file out.
7
+ * Create it once per process. It builds the registry once and loads the
8
+ * WebAssembly core once, on the first render.
9
+ */
10
+ export function createRenderer(options) {
11
+ const plugins = configurePlugins(options.plugins, options.pluginOptions);
12
+ const registry = createRegistry(plugins);
13
+ let wasmPromise = null;
14
+ const loadWasm = () => {
15
+ wasmPromise ??= loadSealpixelWasm(options.wasm).catch((error) => {
16
+ wasmPromise = null;
17
+ throw error;
18
+ });
19
+ return wasmPromise;
20
+ };
21
+ const limits = {
22
+ maxMegapixels: options.limits?.maxMegapixels ?? 80,
23
+ maxBytes: options.limits?.maxBytes ?? 100e6,
24
+ maxLogBytes: options.limits?.maxLogBytes ?? 2e6,
25
+ };
26
+ const verifySourceHash = options.verifySourceHash ?? true;
27
+ const shared = new Map((options.assets ?? []).map((a) => [a.id, a.bytes]));
28
+ // The bytes given here are hashed once per renderer, the bytes given to
29
+ // render() once per render.
30
+ const sharedBytes = new Set(shared.values());
31
+ const sharedHashes = new WeakMap();
32
+ const pluginDeclarations = assetDeclarations(plugins);
33
+ return {
34
+ async render(input) {
35
+ const started = now();
36
+ throwIfAborted(input.signal);
37
+ const { original } = input;
38
+ if (!(original instanceof Uint8Array)) {
39
+ throw new SealpixelError('INVALID_REQUEST', 'original must be a Uint8Array');
40
+ }
41
+ // 1. The byte limit.
42
+ if (original.byteLength > limits.maxBytes) {
43
+ throw new SealpixelError('TOO_LARGE', `${original.byteLength} bytes exceed ${limits.maxBytes}`);
44
+ }
45
+ // 2. The pixel count from the header, before any decode.
46
+ const size = readImageSize(original);
47
+ const megapixels = (size.width * size.height) / 1e6;
48
+ if (megapixels > limits.maxMegapixels) {
49
+ throw new SealpixelError('TOO_LARGE', `${megapixels.toFixed(1)} MP exceed ${limits.maxMegapixels} MP (needs about ${estimateMemoryMB(size.width, size.height)} MB)`);
50
+ }
51
+ // 3. The log size.
52
+ if (input.editLog === undefined) {
53
+ throw new SealpixelError('INVALID_REQUEST', 'editLog is required');
54
+ }
55
+ let logBytes;
56
+ try {
57
+ logBytes = new TextEncoder().encode(canonicalJson(input.editLog)).byteLength;
58
+ }
59
+ catch (error) {
60
+ throw new SealpixelError('INVALID_EDIT_LOG', `edit log is not JSON: ${String(error)}`);
61
+ }
62
+ if (logBytes > limits.maxLogBytes) {
63
+ throw new SealpixelError('TOO_LARGE', `edit log of ${logBytes} bytes exceeds ${limits.maxLogBytes}`);
64
+ }
65
+ // 4. Parse: schema, known plugins, per-op option checks.
66
+ const log = registry.parseEditLog(input.editLog);
67
+ const upTo = input.upTo ?? log.ops.length;
68
+ if (!Number.isInteger(upTo) || upTo < 0 || upTo > log.ops.length) {
69
+ throw new SealpixelError('INVALID_REQUEST', `upTo must be an integer from 0 to ${log.ops.length}, got ${upTo}`);
70
+ }
71
+ const output = input.output ?? { format: 'image/png' };
72
+ if (!FORMATS.has(output.format)) {
73
+ throw new SealpixelError('INVALID_REQUEST', `output.format must be image/png, image/jpeg or image/webp, got ${String(output.format)}`);
74
+ }
75
+ const wasm = await loadWasm();
76
+ // 5. The original the log was written against.
77
+ if (verifySourceHash && log.source.hash !== undefined) {
78
+ const hash = wasm.sha256Hex(original);
79
+ if (hash !== log.source.hash) {
80
+ throw new SealpixelError('SOURCE_MISMATCH', `edit log source hash ${log.source.hash} does not match the original ${hash}`);
81
+ }
82
+ }
83
+ // The assets of this render. Hashing needs no decode, so it runs here.
84
+ const passed = new Map(shared);
85
+ for (const a of input.assets ?? [])
86
+ passed.set(a.id, a.bytes);
87
+ const declarations = log.assets?.length
88
+ ? assetDeclarations(plugins, log)
89
+ : pluginDeclarations;
90
+ const renderHashes = new WeakMap();
91
+ const hashOf = (bytes) => {
92
+ const cache = sharedBytes.has(bytes) ? sharedHashes : renderHashes;
93
+ let hash = cache.get(bytes);
94
+ if (hash === undefined) {
95
+ hash = wasm.sha256Hex(bytes);
96
+ cache.set(bytes, hash);
97
+ }
98
+ return hash;
99
+ };
100
+ const toPut = verifiedAssets(passed, declarations, hashOf);
101
+ const assets = passedAssetResolver(passed, declarations, hashOf);
102
+ const checkMs = now() - started;
103
+ // One render at a time holds a decoded image: a queued render holds only
104
+ // its encoded bytes.
105
+ const { result, decodeMs } = await exclusive(async () => {
106
+ throwIfAborted(input.signal);
107
+ // 6. The size. Orientation may swap width and height, so the decoded
108
+ // size is authoritative. The render reuses this decode.
109
+ const t0 = now();
110
+ const image = tryCore(() => wasm.decode(original));
111
+ const decodeMs = now() - t0;
112
+ if (image.width !== log.source.width || image.height !== log.source.height) {
113
+ throw new SealpixelError('SOURCE_MISMATCH', `edit log expects ${log.source.width}x${log.source.height}, the original is ${image.width}x${image.height}`);
114
+ }
115
+ // 7. The final state against the configured options.
116
+ const violations = registry.validateDocument(compile(log, registry, upTo), log.source);
117
+ if (violations.length > 0) {
118
+ throw new SealpixelError('OPTION_VIOLATION', violations.map((v) => `${v.plugin}: ${v.message}`).join('; '), violations);
119
+ }
120
+ // 8. Render. The core keeps assets by id for the life of the instance.
121
+ // Start empty and put every passed asset, so this render uses only its
122
+ // own bytes and the pipeline runs once. The resolver then only reports
123
+ // an asset that is missing or has another hash.
124
+ wasm.assetClear();
125
+ for (const [id, bytes] of toPut)
126
+ wasm.assetPut(id, bytes);
127
+ const result = await render(image, log, {
128
+ output,
129
+ registry,
130
+ wasm,
131
+ upTo,
132
+ assets,
133
+ ...(input.embedEditLog ? { embedEditLog: true } : {}),
134
+ ...(input.signal ? { signal: input.signal } : {}),
135
+ });
136
+ return { result, decodeMs };
137
+ });
138
+ const { bytes } = result;
139
+ const { render: renderMs = 0, encode: encodeMs = 0 } = result.timings;
140
+ return {
141
+ bytes,
142
+ stream: () => new ReadableStream({
143
+ start(controller) {
144
+ controller.enqueue(bytes);
145
+ controller.close();
146
+ },
147
+ }),
148
+ hash: result.hash,
149
+ width: result.width,
150
+ height: result.height,
151
+ mimeType: result.mimeType,
152
+ timings: {
153
+ check: checkMs,
154
+ decode: decodeMs,
155
+ render: renderMs,
156
+ encode: encodeMs,
157
+ total: now() - started,
158
+ },
159
+ };
160
+ },
161
+ };
162
+ }
163
+ /**
164
+ * Every renderer in a process shares one core instance and its asset table.
165
+ * The decode and the render run one after another, so no render clears or
166
+ * puts assets while another one uses them, and only one decoded image exists
167
+ * at a time. The core is single-threaded, so this costs no throughput.
168
+ */
169
+ let queue = Promise.resolve();
170
+ function exclusive(fn) {
171
+ const run = queue.then(fn);
172
+ queue = run.catch(() => undefined);
173
+ return run;
174
+ }
175
+ function tryCore(fn) {
176
+ try {
177
+ return fn();
178
+ }
179
+ catch (error) {
180
+ throw SealpixelError.from(error);
181
+ }
182
+ }
183
+ function throwIfAborted(signal) {
184
+ if (signal?.aborted)
185
+ throw new SealpixelError('ABORTED', 'render aborted');
186
+ }
187
+ function now() {
188
+ return typeof performance === 'undefined' ? Date.now() : performance.now();
189
+ }
190
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@sealpixel/render",
3
+ "version": "1.0.0-rc.13",
4
+ "description": "Render a Sealpixel edit log on the original with the same WASM core as the browser: original bytes and edit log in, rendered file out. For Node, Deno, Bun and AWS Lambda.",
5
+ "license": "BUSL-1.1",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/9feet/sealpixel.git",
9
+ "directory": "packages/render"
10
+ },
11
+ "homepage": "https://docs.sealpixel.dev",
12
+ "bugs": "https://github.com/9feet/sealpixel/issues",
13
+ "type": "module",
14
+ "engines": {
15
+ "node": ">=24"
16
+ },
17
+ "sideEffects": false,
18
+ "files": [
19
+ "dist",
20
+ "README.md"
21
+ ],
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/index.js"
26
+ },
27
+ "./package.json": "./package.json"
28
+ },
29
+ "dependencies": {
30
+ "@sealpixel/core": "1.0.0-rc.13",
31
+ "@sealpixel/wasm": "1.0.0-rc.13"
32
+ },
33
+ "devDependencies": {
34
+ "@sealpixel/config": "0.0.0",
35
+ "@sealpixel/plugin-annotate": "1.0.0-rc.13",
36
+ "@sealpixel/plugins": "1.0.0-rc.13",
37
+ "@types/node": "^24.0.0",
38
+ "typescript": "^6.0.0",
39
+ "vitest": "^5.0.0"
40
+ },
41
+ "scripts": {
42
+ "build": "tsc -p tsconfig.build.json",
43
+ "typecheck": "tsc -p tsconfig.json --noEmit",
44
+ "test": "vitest run && deno test --no-check --allow-read --allow-env --quiet test/*.deno.test.ts && bun test test/*.bun.test.ts"
45
+ }
46
+ }