@gongbaodd/qr-renderer 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 (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -0
  3. package/dist/node.js +3130 -0
  4. package/dist/types/core/artifacts.d.ts +2 -0
  5. package/dist/types/core/assemble.d.ts +36 -0
  6. package/dist/types/core/errors.d.ts +6 -0
  7. package/dist/types/core/export-sizes.d.ts +21 -0
  8. package/dist/types/core/image.d.ts +14 -0
  9. package/dist/types/core/imaging/browser.d.ts +23 -0
  10. package/dist/types/core/imaging/cloudflare.d.ts +2 -0
  11. package/dist/types/core/imaging/index.d.ts +5 -0
  12. package/dist/types/core/imaging/node.d.ts +4 -0
  13. package/dist/types/core/imaging/pixels.d.ts +28 -0
  14. package/dist/types/core/imaging/types.d.ts +45 -0
  15. package/dist/types/core/mask.d.ts +11 -0
  16. package/dist/types/core/module-cut.d.ts +107 -0
  17. package/dist/types/core/palette.d.ts +80 -0
  18. package/dist/types/core/pattern-cut.d.ts +96 -0
  19. package/dist/types/core/pattern.d.ts +119 -0
  20. package/dist/types/core/placement.d.ts +9 -0
  21. package/dist/types/core/qr.d.ts +57 -0
  22. package/dist/types/core/rotate.d.ts +149 -0
  23. package/dist/types/core/squircle.d.ts +2 -0
  24. package/dist/types/core/types.d.ts +475 -0
  25. package/dist/types/engine/engine.d.ts +68 -0
  26. package/dist/types/engine/index.d.ts +34 -0
  27. package/dist/types/engine/mapping.d.ts +14 -0
  28. package/dist/types/engine/pipeline.d.ts +77 -0
  29. package/dist/types/engine/types.d.ts +66 -0
  30. package/dist/types/node.d.ts +17 -0
  31. package/dist/types/png-guard.d.ts +17 -0
  32. package/dist/types/recipe.d.ts +132 -0
  33. package/dist/types/schema.d.ts +211 -0
  34. package/dist/types/worker-shim.d.ts +12 -0
  35. package/package.json +79 -0
  36. package/src/core/artifacts.ts +6 -0
  37. package/src/core/assemble.ts +1195 -0
  38. package/src/core/errors.ts +24 -0
  39. package/src/core/export-sizes.ts +179 -0
  40. package/src/core/image.ts +57 -0
  41. package/src/core/imaging/browser.ts +186 -0
  42. package/src/core/imaging/cloudflare.ts +15 -0
  43. package/src/core/imaging/index.ts +14 -0
  44. package/src/core/imaging/node.ts +95 -0
  45. package/src/core/imaging/pixels.ts +121 -0
  46. package/src/core/imaging/types.ts +56 -0
  47. package/src/core/mask.ts +295 -0
  48. package/src/core/module-cut.ts +523 -0
  49. package/src/core/palette.ts +227 -0
  50. package/src/core/pattern-cut.ts +522 -0
  51. package/src/core/pattern.ts +478 -0
  52. package/src/core/placement.ts +94 -0
  53. package/src/core/qr.ts +695 -0
  54. package/src/core/rotate.ts +267 -0
  55. package/src/core/squircle.ts +53 -0
  56. package/src/core/types.ts +477 -0
  57. package/src/engine/engine.ts +316 -0
  58. package/src/engine/index.ts +58 -0
  59. package/src/engine/mapping.ts +66 -0
  60. package/src/engine/pipeline.ts +501 -0
  61. package/src/engine/types.ts +61 -0
  62. package/src/node.ts +45 -0
  63. package/src/png-guard.ts +66 -0
  64. package/src/recipe.ts +161 -0
  65. package/src/schema.ts +137 -0
  66. package/src/wasm.d.ts +5 -0
  67. package/src/worker-shim.ts +15 -0
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The editor engine: prepares and assembles posters with session state kept in
3
+ * memory, so an edit only re-runs what changed. Runs identically in Node
4
+ * (tests/scripts, sharp-backed imaging) and inside the browser worker (browser
5
+ * imaging) — it depends on neither platform.
6
+ *
7
+ * - Source cache: decoded poster and derived region keyed by the file sha256
8
+ * identity; a placement/seed/settings edit re-runs geometry only, a
9
+ * content/ecc/style edit regenerates the QR only, a new file re-decodes.
10
+ * - Stale suppression: latest-revision-wins. When a newer revision arrives
11
+ * while an older one is still in flight, the older one's settled result is
12
+ * dropped at the outcome boundary — no cancellation machinery is added
13
+ * around codecs or detectors.
14
+ */
15
+ import type { Imaging } from '../core/imaging/types';
16
+ import type { EngineInput, EngineOutcome, PreparedPayload, AssemblePayload, RasterExportPayload } from './types';
17
+ import type { Placement, Settings } from '../schema';
18
+ export declare class EditorEngine {
19
+ private imaging;
20
+ private sources;
21
+ private qrBundles;
22
+ private latestPrepareRevision;
23
+ private latestAssemblyRevision;
24
+ constructor(imaging: Imaging);
25
+ /** Frees every cached source/QR bundle. */
26
+ invalidate(): void;
27
+ /** Step-2 payload for the current editor state. */
28
+ prepare(input: EngineInput, revision: number): Promise<EngineOutcome<PreparedPayload>>;
29
+ /** Step-4 payload: the schema-8 report plus Blob artifacts. */
30
+ assemble(input: EngineInput & {
31
+ placement: Placement;
32
+ seed: number;
33
+ qrMargin: 1;
34
+ plateCorners: Settings['plateCorners'];
35
+ regionMargin?: boolean;
36
+ rimModules?: number;
37
+ rimRounded?: boolean;
38
+ ecc?: Settings['ecc'];
39
+ pixelStyle?: Settings['pixelStyle'];
40
+ finderMarkers?: Settings['finderMarkers'];
41
+ markerSub?: Settings['markerSub'];
42
+ colors?: Settings['colors'];
43
+ }, revision: number): Promise<EngineOutcome<AssemblePayload>>;
44
+ /** Render the first verified smaller poster at or above the requested integer module pitch. */
45
+ exportRaster(input: EngineInput & {
46
+ placement: Placement;
47
+ seed: number;
48
+ qrMargin: 1;
49
+ plateCorners: Settings['plateCorners'];
50
+ regionMargin?: boolean;
51
+ rimModules?: number;
52
+ rimRounded?: boolean;
53
+ ecc?: Settings['ecc'];
54
+ pixelStyle?: Settings['pixelStyle'];
55
+ finderMarkers?: Settings['finderMarkers'];
56
+ markerSub?: Settings['markerSub'];
57
+ colors?: Settings['colors'];
58
+ }, targetPitch: number, revision: number): Promise<EngineOutcome<RasterExportPayload>>;
59
+ /** The settle-time revision check is the only stale gate: superseded runs drop here. */
60
+ private settle;
61
+ /** Shared prepare/assemble resolution with the source and QR caches applied. */
62
+ private resolveLayout;
63
+ /** Poster decode + region detection, keyed by content identity (sha256). */
64
+ private cachedSource;
65
+ private evictSources;
66
+ /** Generated QR bundle keyed by the content and the QR-shaping settings. */
67
+ private cachedQr;
68
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Engine entry point. `createEditorEngine` is the only way to build an engine:
3
+ * callers inject their environment's `Imaging` implementation (sharp in Node,
4
+ * jSquash + resvg in the browser worker), so no platform leak enters the engine.
5
+ */
6
+ import type { Imaging } from '../core/imaging/types';
7
+ import { EditorEngine } from './engine';
8
+ import type { EngineOutcome, PreparedPayload, AssemblePayload, RasterExportPayload, EngineInput, EngineError } from './types';
9
+ import type { Placement, Settings } from '../schema';
10
+ export type { EditorEngine };
11
+ export type { EngineOutcome, PreparedPayload, AssemblePayload, RasterExportPayload, EngineInput, EngineError };
12
+ export type { EngineInput as EngineRequest };
13
+ export type AssembleInput = EngineInput & {
14
+ placement: Placement;
15
+ seed: number;
16
+ qrMargin: 1;
17
+ plateCorners: Settings['plateCorners'];
18
+ regionMargin?: boolean;
19
+ rimModules?: number;
20
+ rimRounded?: boolean;
21
+ ecc?: Settings['ecc'];
22
+ pixelStyle?: Settings['pixelStyle'];
23
+ finderMarkers?: Settings['finderMarkers'];
24
+ markerSub?: Settings['markerSub'];
25
+ colors?: Settings['colors'];
26
+ };
27
+ /** The Comlink-exposed surface: every call goes through {@link EngineOutcome}. */
28
+ export interface EditorEngineApi {
29
+ prepare: (input: EngineInput, revision: number) => Promise<EngineOutcome<PreparedPayload>>;
30
+ assemble: (input: AssembleInput, revision: number) => Promise<EngineOutcome<AssemblePayload>>;
31
+ exportRaster: (input: AssembleInput, targetPitch: number, revision: number) => Promise<EngineOutcome<RasterExportPayload>>;
32
+ invalidate: () => void;
33
+ }
34
+ export declare function createEditorEngine(imaging: Imaging): Promise<EditorEngineApi>;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Error mapping, moved verbatim from the former `src/server/http.ts` catch
3
+ * block (its route handler dies in phase 5). Every engine entry wraps thrown
4
+ * domain errors with the same codes and editor-field mapping, so UI error
5
+ * handling does not change when the pipeline leaves the server.
6
+ */
7
+ import type { EngineError } from './types';
8
+ export declare class EngineMappingError extends Error {
9
+ readonly code: string;
10
+ readonly field: string | undefined;
11
+ constructor(code: string, message: string, field: string | undefined);
12
+ }
13
+ /** Wraps any thrown error with the editor-facing code/message/field. */
14
+ export declare function toEngineError(error: unknown): EngineError;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Environment-agnostic prepare/assemble pipeline for the editor. This is a
3
+ * faithful decomposition of the former `src/server/editor.ts` orchestration;
4
+ * server specifics (sharp metadata checks, multipart bounds) are replaced by
5
+ * the shared `png-guard` header checks and the injected `Imaging` backend.
6
+ *
7
+ * Keep this module independent of Worker, React, HTTP, and Node: it takes the
8
+ * `Imaging` implementation as an argument instead of importing a backend.
9
+ */
10
+ import { normalizeQr } from '../core/qr';
11
+ import { type QrPalette } from '../core/palette';
12
+ import type { Imaging } from '../core/imaging/types';
13
+ import type { LoadedPng } from '../core/image';
14
+ import type { QrMetadata, QrPlacement, RegionMask, ResolvedLayout } from '../core/types';
15
+ import type { Placement, Settings } from '../schema';
16
+ import type { EngineInput, PreparedPayload, AssemblePayload, RasterExportPayload } from './types';
17
+ /** Builds a Blob with the mime type implied by the artifact name (PNG/SVG/JSON). */
18
+ export declare function bytesToBlob(name: string, bytes: Uint8Array): Blob;
19
+ export declare const engineDefaults: Settings;
20
+ /** Client-side replacement for the old sharp-metadata `readImage`. */
21
+ export { normalizeQr };
22
+ export declare function readImage(imaging: Imaging, bytes: Uint8Array, name: string): Promise<LoadedPng>;
23
+ /** Same whole-square constraint and module geometry as assembly; no raster rendering needed. */
24
+ export declare function validatePlacement({ regionMask, qrMetadata, placement, settings, }: {
25
+ regionMask: RegionMask;
26
+ qrMetadata: QrMetadata;
27
+ placement: Placement;
28
+ settings: Settings;
29
+ }): QrPlacement;
30
+ /** The decoded poster and its region: the expensive, source-bound half of resolveBuffers. */
31
+ export interface PreparedSource {
32
+ poster: LoadedPng;
33
+ maskInput?: LoadedPng;
34
+ regionMask: RegionMask;
35
+ }
36
+ export declare function prepareSource(imaging: Imaging, posterBytes: Uint8Array, maskBytes?: Uint8Array): Promise<PreparedSource>;
37
+ /** The content-bound half: the generated QR, its decode round trip, and metadata. */
38
+ export interface QrBundle {
39
+ qrSource: LoadedPng;
40
+ decoded: ResolvedLayout['decoded'];
41
+ qrMetadata: QrMetadata;
42
+ }
43
+ export declare function resolveQr(imaging: Imaging, input: EngineInput): Promise<QrBundle>;
44
+ /** Verbatim placement/recentering/fit logic from the former `resolveBuffers`. */
45
+ export declare function applyPlacement({ source, qr, input, settings, unchecked, }: {
46
+ source: PreparedSource;
47
+ qr: QrBundle;
48
+ input: Pick<EngineInput, 'placement' | 'previousTotalModules'>;
49
+ settings: Settings;
50
+ unchecked?: boolean;
51
+ }): {
52
+ layout: ResolvedLayout;
53
+ validation: string | null;
54
+ bestPlacement: Placement;
55
+ };
56
+ /** Straight composition of the three stages — the uncached path, used by tests and scripts. */
57
+ export declare function resolveBuffers(imaging: Imaging, input: EngineInput): Promise<{
58
+ layout: ResolvedLayout;
59
+ validation: string | null;
60
+ }>;
61
+ export declare function toPreparedPayload(imaging: Imaging, layout: ResolvedLayout, validation: string | null, palette?: QrPalette, bestPlacement?: Placement): Promise<PreparedPayload>;
62
+ /** Identical request merge and verification gate as the former `assembleFromBuffers`. */
63
+ export declare function assemblePayload(imaging: Imaging, input: EngineInput & {
64
+ placement: Placement;
65
+ seed: number;
66
+ qrMargin: 1;
67
+ plateCorners: Settings['plateCorners'];
68
+ regionMargin?: boolean;
69
+ rimModules?: number;
70
+ rimRounded?: boolean;
71
+ ecc?: Settings['ecc'];
72
+ pixelStyle?: Settings['pixelStyle'];
73
+ finderMarkers?: Settings['finderMarkers'];
74
+ markerSub?: Settings['markerSub'];
75
+ colors?: Settings['colors'];
76
+ }): Promise<AssemblePayload>;
77
+ export declare function assembleRasterVariant(imaging: Imaging, original: ResolvedLayout, settings: Settings, originalPlacement: QrPlacement, targetPitch: number, transparentBlank: boolean): Promise<RasterExportPayload>;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Engine contracts shared by the Node test harness and the Comlink worker.
3
+ * Engine operations never throw across an API boundary: they settle to a
4
+ * discriminated {@link EngineOutcome}, so every consumer (the editor store,
5
+ * worker client, tests) handles errors and stale runs the same way.
6
+ */
7
+ import type { Placement, Settings } from '../schema';
8
+ /** An editor-facing error: the exact codes/fields the old HTTP pipeline produced. */
9
+ export interface EngineError {
10
+ code: string;
11
+ message: string;
12
+ /** Editor field the error maps to (`content`, `poster`, `mask`, `placement`). */
13
+ field?: string | undefined;
14
+ }
15
+ /** Engine input: source bytes plus the current editor revision. */
16
+ export interface EngineInput {
17
+ posterBytes: Uint8Array;
18
+ transparentBlank?: boolean;
19
+ content: string;
20
+ maskBytes?: Uint8Array;
21
+ placement?: Placement;
22
+ previousTotalModules?: number | undefined;
23
+ settings?: Partial<Settings>;
24
+ }
25
+ /** The step-2 payload: preview artifacts as Blobs (built in the worker; Blobs cross postMessage by reference). */
26
+ export interface PreparedPayload {
27
+ width: number;
28
+ height: number;
29
+ mask: Blob;
30
+ overlay: Blob;
31
+ qr: Blob;
32
+ qrMetadata: {
33
+ totalModules: number;
34
+ version: number;
35
+ };
36
+ placement: Placement;
37
+ bestPlacement: Placement;
38
+ validation: string | null;
39
+ }
40
+ /** The step-4 payload mirrors the schema-8 envelope: report plus Blob artifacts. */
41
+ export interface AssemblePayload {
42
+ report: import('../core/types').AssembleReport;
43
+ artifacts: Record<string, Blob>;
44
+ recipe?: Blob;
45
+ recipeError?: string;
46
+ }
47
+ export interface RasterExportPayload {
48
+ poster: Blob;
49
+ width: number;
50
+ height: number;
51
+ modulePixels: number;
52
+ bytes: number;
53
+ }
54
+ export type EngineOutcome<T> = {
55
+ ok: true;
56
+ revision: number;
57
+ value: T;
58
+ } | {
59
+ ok: false;
60
+ stale: true;
61
+ revision: number;
62
+ } | {
63
+ ok: false;
64
+ error: EngineError;
65
+ revision: number;
66
+ };
@@ -0,0 +1,17 @@
1
+ import { type PortableRecipe } from './recipe';
2
+ export type RecipeArtifact = 'poster.png' | 'qr.png';
3
+ export interface RenderRecipeOptions {
4
+ artifact?: RecipeArtifact;
5
+ }
6
+ export interface RenderRecipeResult {
7
+ png: Uint8Array;
8
+ filename: RecipeArtifact;
9
+ }
10
+ /** Render an already parsed editor recipe with the Node.js imaging backend. */
11
+ export declare function renderRecipeJson(rawRecipe: unknown, options?: RenderRecipeOptions): Promise<RenderRecipeResult>;
12
+ /**
13
+ * Parse and render UTF-8 JSON bytes/string from the editor's recipe export.
14
+ * Filesystem access stays with the caller so this entry never writes or reads paths.
15
+ */
16
+ export declare function renderRecipeFile(input: Uint8Array | string, options?: RenderRecipeOptions): Promise<RenderRecipeResult>;
17
+ export type { PortableRecipe };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Client-side upload guards with the same semantics as the old server `readImage`:
3
+ * PNG signature, dimensions from IHDR, single-frame (no `acTL` animation chunks),
4
+ * and the byte/megapixel limits. Parses the header bytes only — no full decode.
5
+ */
6
+ export type GuardCode = 'PNG_INVALID' | 'UPLOAD_LIMIT';
7
+ /** Thrown with the exact codes the editor UI maps to field errors. */
8
+ export declare class PngGuardError extends Error {
9
+ readonly code: GuardCode;
10
+ readonly field: string;
11
+ constructor(code: GuardCode, message: string, field: string);
12
+ }
13
+ export interface PngHeaderInfo {
14
+ width: number;
15
+ height: number;
16
+ }
17
+ export declare function parsePngHeader(bytes: Uint8Array, field: string): PngHeaderInfo;
@@ -0,0 +1,132 @@
1
+ import { z } from 'zod';
2
+ import type { Imaging } from './core/imaging/types';
3
+ import type { AssembleInput } from './engine/index';
4
+ export declare const RECIPE_FORMAT = "mahu-qr-recipe";
5
+ export declare const RECIPE_SCHEMA_VERSION = 1;
6
+ export declare const RECIPE_RENDERER_VERSION = "mahu-qr-renderer-1";
7
+ export declare const MAX_RECIPE_BYTES: number;
8
+ export declare const recipeSchema: z.ZodObject<{
9
+ format: z.ZodLiteral<"mahu-qr-recipe">;
10
+ schemaVersion: z.ZodLiteral<1>;
11
+ rendererVersion: z.ZodLiteral<"mahu-qr-renderer-1">;
12
+ content: z.ZodString;
13
+ source: z.ZodObject<{
14
+ poster: z.ZodObject<{
15
+ mimeType: z.ZodLiteral<"image/png">;
16
+ encoding: z.ZodLiteral<"base64">;
17
+ sha256: z.ZodString;
18
+ data: z.ZodString;
19
+ }, z.core.$strict>;
20
+ regionMask: z.ZodObject<{
21
+ mimeType: z.ZodLiteral<"image/png">;
22
+ encoding: z.ZodLiteral<"base64">;
23
+ sha256: z.ZodString;
24
+ data: z.ZodString;
25
+ }, z.core.$strict>;
26
+ width: z.ZodNumber;
27
+ height: z.ZodNumber;
28
+ transparentBlank: z.ZodBoolean;
29
+ }, z.core.$strict>;
30
+ placement: z.ZodObject<{
31
+ x: z.ZodNumber;
32
+ y: z.ZodNumber;
33
+ size: z.ZodNumber;
34
+ rotation: z.ZodDefault<z.ZodNumber>;
35
+ }, z.core.$strict>;
36
+ settings: z.ZodObject<{
37
+ seed: z.ZodNumber;
38
+ qrMargin: z.ZodDefault<z.ZodLiteral<1>>;
39
+ plateCorners: z.ZodDefault<z.ZodEnum<{
40
+ light: "light";
41
+ texture: "texture";
42
+ }>>;
43
+ regionMargin: z.ZodDefault<z.ZodBoolean>;
44
+ rimModules: z.ZodDefault<z.ZodNumber>;
45
+ rimRounded: z.ZodDefault<z.ZodBoolean>;
46
+ ecc: z.ZodDefault<z.ZodEnum<{
47
+ H: "H";
48
+ L: "L";
49
+ M: "M";
50
+ Q: "Q";
51
+ }>>;
52
+ pixelStyle: z.ZodDefault<z.ZodEnum<{
53
+ dot: "dot";
54
+ rounded: "rounded";
55
+ square: "square";
56
+ }>>;
57
+ finderMarkers: z.ZodDefault<z.ZodObject<{
58
+ tl: z.ZodDefault<z.ZodObject<{
59
+ style: z.ZodDefault<z.ZodEnum<{
60
+ rounded: "rounded";
61
+ square: "square";
62
+ }>>;
63
+ shape: z.ZodDefault<z.ZodEnum<{
64
+ circle: "circle";
65
+ octagon: "octagon";
66
+ square: "square";
67
+ squircle: "squircle";
68
+ }>>;
69
+ inner: z.ZodDefault<z.ZodEnum<{
70
+ circle: "circle";
71
+ diamond: "diamond";
72
+ plus: "plus";
73
+ square: "square";
74
+ squircle: "squircle";
75
+ }>>;
76
+ }, z.core.$strip>>;
77
+ tr: z.ZodDefault<z.ZodObject<{
78
+ style: z.ZodDefault<z.ZodEnum<{
79
+ rounded: "rounded";
80
+ square: "square";
81
+ }>>;
82
+ shape: z.ZodDefault<z.ZodEnum<{
83
+ circle: "circle";
84
+ octagon: "octagon";
85
+ square: "square";
86
+ squircle: "squircle";
87
+ }>>;
88
+ inner: z.ZodDefault<z.ZodEnum<{
89
+ circle: "circle";
90
+ diamond: "diamond";
91
+ plus: "plus";
92
+ square: "square";
93
+ squircle: "squircle";
94
+ }>>;
95
+ }, z.core.$strip>>;
96
+ bl: z.ZodDefault<z.ZodObject<{
97
+ style: z.ZodDefault<z.ZodEnum<{
98
+ rounded: "rounded";
99
+ square: "square";
100
+ }>>;
101
+ shape: z.ZodDefault<z.ZodEnum<{
102
+ circle: "circle";
103
+ octagon: "octagon";
104
+ square: "square";
105
+ squircle: "squircle";
106
+ }>>;
107
+ inner: z.ZodDefault<z.ZodEnum<{
108
+ circle: "circle";
109
+ diamond: "diamond";
110
+ plus: "plus";
111
+ square: "square";
112
+ squircle: "squircle";
113
+ }>>;
114
+ }, z.core.$strip>>;
115
+ }, z.core.$strip>>;
116
+ markerSub: z.ZodDefault<z.ZodEnum<{
117
+ circle: "circle";
118
+ square: "square";
119
+ }>>;
120
+ colors: z.ZodDefault<z.ZodObject<{
121
+ pixel: z.ZodString;
122
+ marker: z.ZodString;
123
+ background: z.ZodString;
124
+ }, z.core.$strip>>;
125
+ }, z.core.$strict>;
126
+ }, z.core.$strict>;
127
+ export type PortableRecipe = z.infer<typeof recipeSchema>;
128
+ export declare function createRecipeBlob(input: AssembleInput, finalMask: Blob): Promise<Blob>;
129
+ export declare function renderRecipe(imaging: Imaging, rawRecipe: unknown, artifact: 'poster.png' | 'qr.png'): Promise<{
130
+ png: Blob;
131
+ filename: string;
132
+ }>;
@@ -0,0 +1,211 @@
1
+ import { z } from 'zod';
2
+ export declare const MAX_IMAGE_BYTES: number;
3
+ export declare const MAX_PIXELS = 4000000;
4
+ export declare const MAX_BODY_BYTES: number;
5
+ export declare const contentSchema: z.ZodString;
6
+ export declare const rotationSchema: z.ZodDefault<z.ZodNumber>;
7
+ export declare const placementSchema: z.ZodObject<{
8
+ x: z.ZodNumber;
9
+ y: z.ZodNumber;
10
+ size: z.ZodNumber;
11
+ rotation: z.ZodDefault<z.ZodNumber>;
12
+ }, z.core.$strict>;
13
+ export declare const settingsSchema: z.ZodObject<{
14
+ seed: z.ZodNumber;
15
+ qrMargin: z.ZodDefault<z.ZodLiteral<1>>;
16
+ plateCorners: z.ZodDefault<z.ZodEnum<{
17
+ light: "light";
18
+ texture: "texture";
19
+ }>>;
20
+ regionMargin: z.ZodDefault<z.ZodBoolean>;
21
+ rimModules: z.ZodDefault<z.ZodNumber>;
22
+ rimRounded: z.ZodDefault<z.ZodBoolean>;
23
+ ecc: z.ZodDefault<z.ZodEnum<{
24
+ H: "H";
25
+ L: "L";
26
+ M: "M";
27
+ Q: "Q";
28
+ }>>;
29
+ pixelStyle: z.ZodDefault<z.ZodEnum<{
30
+ dot: "dot";
31
+ rounded: "rounded";
32
+ square: "square";
33
+ }>>;
34
+ finderMarkers: z.ZodDefault<z.ZodObject<{
35
+ tl: z.ZodDefault<z.ZodObject<{
36
+ style: z.ZodDefault<z.ZodEnum<{
37
+ rounded: "rounded";
38
+ square: "square";
39
+ }>>;
40
+ shape: z.ZodDefault<z.ZodEnum<{
41
+ circle: "circle";
42
+ octagon: "octagon";
43
+ square: "square";
44
+ squircle: "squircle";
45
+ }>>;
46
+ inner: z.ZodDefault<z.ZodEnum<{
47
+ circle: "circle";
48
+ diamond: "diamond";
49
+ plus: "plus";
50
+ square: "square";
51
+ squircle: "squircle";
52
+ }>>;
53
+ }, z.core.$strip>>;
54
+ tr: z.ZodDefault<z.ZodObject<{
55
+ style: z.ZodDefault<z.ZodEnum<{
56
+ rounded: "rounded";
57
+ square: "square";
58
+ }>>;
59
+ shape: z.ZodDefault<z.ZodEnum<{
60
+ circle: "circle";
61
+ octagon: "octagon";
62
+ square: "square";
63
+ squircle: "squircle";
64
+ }>>;
65
+ inner: z.ZodDefault<z.ZodEnum<{
66
+ circle: "circle";
67
+ diamond: "diamond";
68
+ plus: "plus";
69
+ square: "square";
70
+ squircle: "squircle";
71
+ }>>;
72
+ }, z.core.$strip>>;
73
+ bl: z.ZodDefault<z.ZodObject<{
74
+ style: z.ZodDefault<z.ZodEnum<{
75
+ rounded: "rounded";
76
+ square: "square";
77
+ }>>;
78
+ shape: z.ZodDefault<z.ZodEnum<{
79
+ circle: "circle";
80
+ octagon: "octagon";
81
+ square: "square";
82
+ squircle: "squircle";
83
+ }>>;
84
+ inner: z.ZodDefault<z.ZodEnum<{
85
+ circle: "circle";
86
+ diamond: "diamond";
87
+ plus: "plus";
88
+ square: "square";
89
+ squircle: "squircle";
90
+ }>>;
91
+ }, z.core.$strip>>;
92
+ }, z.core.$strip>>;
93
+ markerSub: z.ZodDefault<z.ZodEnum<{
94
+ circle: "circle";
95
+ square: "square";
96
+ }>>;
97
+ colors: z.ZodDefault<z.ZodObject<{
98
+ pixel: z.ZodString;
99
+ marker: z.ZodString;
100
+ background: z.ZodString;
101
+ }, z.core.$strip>>;
102
+ }, z.core.$strict>;
103
+ export declare const requestSchema: z.ZodObject<{
104
+ revision: z.ZodNumber;
105
+ content: z.ZodString;
106
+ placement: z.ZodOptional<z.ZodObject<{
107
+ x: z.ZodNumber;
108
+ y: z.ZodNumber;
109
+ size: z.ZodNumber;
110
+ rotation: z.ZodDefault<z.ZodNumber>;
111
+ }, z.core.$strict>>;
112
+ previousTotalModules: z.ZodOptional<z.ZodNumber>;
113
+ settings: z.ZodObject<{
114
+ seed: z.ZodNumber;
115
+ qrMargin: z.ZodDefault<z.ZodLiteral<1>>;
116
+ plateCorners: z.ZodDefault<z.ZodEnum<{
117
+ light: "light";
118
+ texture: "texture";
119
+ }>>;
120
+ regionMargin: z.ZodDefault<z.ZodBoolean>;
121
+ rimModules: z.ZodDefault<z.ZodNumber>;
122
+ rimRounded: z.ZodDefault<z.ZodBoolean>;
123
+ ecc: z.ZodDefault<z.ZodEnum<{
124
+ H: "H";
125
+ L: "L";
126
+ M: "M";
127
+ Q: "Q";
128
+ }>>;
129
+ pixelStyle: z.ZodDefault<z.ZodEnum<{
130
+ dot: "dot";
131
+ rounded: "rounded";
132
+ square: "square";
133
+ }>>;
134
+ finderMarkers: z.ZodDefault<z.ZodObject<{
135
+ tl: z.ZodDefault<z.ZodObject<{
136
+ style: z.ZodDefault<z.ZodEnum<{
137
+ rounded: "rounded";
138
+ square: "square";
139
+ }>>;
140
+ shape: z.ZodDefault<z.ZodEnum<{
141
+ circle: "circle";
142
+ octagon: "octagon";
143
+ square: "square";
144
+ squircle: "squircle";
145
+ }>>;
146
+ inner: z.ZodDefault<z.ZodEnum<{
147
+ circle: "circle";
148
+ diamond: "diamond";
149
+ plus: "plus";
150
+ square: "square";
151
+ squircle: "squircle";
152
+ }>>;
153
+ }, z.core.$strip>>;
154
+ tr: z.ZodDefault<z.ZodObject<{
155
+ style: z.ZodDefault<z.ZodEnum<{
156
+ rounded: "rounded";
157
+ square: "square";
158
+ }>>;
159
+ shape: z.ZodDefault<z.ZodEnum<{
160
+ circle: "circle";
161
+ octagon: "octagon";
162
+ square: "square";
163
+ squircle: "squircle";
164
+ }>>;
165
+ inner: z.ZodDefault<z.ZodEnum<{
166
+ circle: "circle";
167
+ diamond: "diamond";
168
+ plus: "plus";
169
+ square: "square";
170
+ squircle: "squircle";
171
+ }>>;
172
+ }, z.core.$strip>>;
173
+ bl: z.ZodDefault<z.ZodObject<{
174
+ style: z.ZodDefault<z.ZodEnum<{
175
+ rounded: "rounded";
176
+ square: "square";
177
+ }>>;
178
+ shape: z.ZodDefault<z.ZodEnum<{
179
+ circle: "circle";
180
+ octagon: "octagon";
181
+ square: "square";
182
+ squircle: "squircle";
183
+ }>>;
184
+ inner: z.ZodDefault<z.ZodEnum<{
185
+ circle: "circle";
186
+ diamond: "diamond";
187
+ plus: "plus";
188
+ square: "square";
189
+ squircle: "squircle";
190
+ }>>;
191
+ }, z.core.$strip>>;
192
+ }, z.core.$strip>>;
193
+ markerSub: z.ZodDefault<z.ZodEnum<{
194
+ circle: "circle";
195
+ square: "square";
196
+ }>>;
197
+ colors: z.ZodDefault<z.ZodObject<{
198
+ pixel: z.ZodString;
199
+ marker: z.ZodString;
200
+ background: z.ZodString;
201
+ }, z.core.$strip>>;
202
+ }, z.core.$strict>;
203
+ }, z.core.$strict>;
204
+ export type Placement = z.infer<typeof placementSchema>;
205
+ export type Settings = z.infer<typeof settingsSchema>;
206
+ export type EditorRequest = z.infer<typeof requestSchema>;
207
+ /** A placement under construction may omit rotation (canonicalized to 0). */
208
+ export type PlacementInput = z.input<typeof placementSchema>;
209
+ export declare function canonicalPlacement(box: PlacementInput, totalModules: number): Placement;
210
+ export declare function recenterPlacement(box: PlacementInput, previousModules: number, nextModules: number): Placement;
211
+ export declare function fitsMask(mask: Uint8Array, width: number, height: number, box: PlacementInput): boolean;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Dedicated workers have no `window`, but the engine's QR decoder imports
3
+ * ZXing, whose PDF417 tables touch `window.BigInt` at module scope. Aliasing
4
+ * `window` to the worker global keeps that import alive in every bundler
5
+ * (Turbopack shims `window` in worker output; Vite does not). Must be the
6
+ * first import of the worker entry, before the engine evaluates. The check
7
+ * reads the property off `globalThis` so minifiers cannot fold it away, and
8
+ * it is a no-op on the main thread, where `window` already exists.
9
+ */
10
+ declare const workerGlobal: {
11
+ window?: unknown;
12
+ };