@dejadex/web 0.0.0-stage → 0.1.1

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 (113) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +222 -2
  3. package/dist/errors.d.ts +8 -0
  4. package/dist/errors.d.ts.map +1 -0
  5. package/dist/errors.js +9 -0
  6. package/dist/errors.js.map +1 -0
  7. package/dist/geometry/homography.d.ts +75 -0
  8. package/dist/geometry/homography.d.ts.map +1 -0
  9. package/dist/geometry/homography.js +146 -0
  10. package/dist/geometry/homography.js.map +1 -0
  11. package/dist/identify/assets.d.ts +39 -0
  12. package/dist/identify/assets.d.ts.map +1 -0
  13. package/dist/identify/assets.js +167 -0
  14. package/dist/identify/assets.js.map +1 -0
  15. package/dist/identify/decode.d.ts +6 -0
  16. package/dist/identify/decode.d.ts.map +1 -0
  17. package/dist/identify/decode.js +53 -0
  18. package/dist/identify/decode.js.map +1 -0
  19. package/dist/identify/engine.d.ts +32 -0
  20. package/dist/identify/engine.d.ts.map +1 -0
  21. package/dist/identify/engine.js +127 -0
  22. package/dist/identify/engine.js.map +1 -0
  23. package/dist/identify/identifier.d.ts +91 -0
  24. package/dist/identify/identifier.d.ts.map +1 -0
  25. package/dist/identify/identifier.js +332 -0
  26. package/dist/identify/identifier.js.map +1 -0
  27. package/dist/identify/manifest.d.ts +60 -0
  28. package/dist/identify/manifest.d.ts.map +1 -0
  29. package/dist/identify/manifest.js +211 -0
  30. package/dist/identify/manifest.js.map +1 -0
  31. package/dist/identify/preprocess.d.ts +52 -0
  32. package/dist/identify/preprocess.d.ts.map +1 -0
  33. package/dist/identify/preprocess.js +195 -0
  34. package/dist/identify/preprocess.js.map +1 -0
  35. package/dist/identify/router.d.ts +60 -0
  36. package/dist/identify/router.d.ts.map +1 -0
  37. package/dist/identify/router.js +83 -0
  38. package/dist/identify/router.js.map +1 -0
  39. package/dist/identify/runtime.d.ts +69 -0
  40. package/dist/identify/runtime.d.ts.map +1 -0
  41. package/dist/identify/runtime.js +140 -0
  42. package/dist/identify/runtime.js.map +1 -0
  43. package/dist/identify/search.d.ts +35 -0
  44. package/dist/identify/search.d.ts.map +1 -0
  45. package/dist/identify/search.js +99 -0
  46. package/dist/identify/search.js.map +1 -0
  47. package/dist/identify/server.d.ts +60 -0
  48. package/dist/identify/server.d.ts.map +1 -0
  49. package/dist/identify/server.js +149 -0
  50. package/dist/identify/server.js.map +1 -0
  51. package/dist/identify/shard.d.ts +31 -0
  52. package/dist/identify/shard.d.ts.map +1 -0
  53. package/dist/identify/shard.js +146 -0
  54. package/dist/identify/shard.js.map +1 -0
  55. package/dist/identify/types.d.ts +107 -0
  56. package/dist/identify/types.d.ts.map +1 -0
  57. package/dist/identify/types.js +7 -0
  58. package/dist/identify/types.js.map +1 -0
  59. package/dist/identify/worker.d.ts +2 -0
  60. package/dist/identify/worker.d.ts.map +1 -0
  61. package/dist/identify/worker.js +13 -0
  62. package/dist/identify/worker.js.map +1 -0
  63. package/dist/identify/workerProtocol.d.ts +54 -0
  64. package/dist/identify/workerProtocol.d.ts.map +1 -0
  65. package/dist/identify/workerProtocol.js +113 -0
  66. package/dist/identify/workerProtocol.js.map +1 -0
  67. package/dist/index.d.ts +20 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +16 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/lease/verify.d.ts +69 -0
  72. package/dist/lease/verify.d.ts.map +1 -0
  73. package/dist/lease/verify.js +235 -0
  74. package/dist/lease/verify.js.map +1 -0
  75. package/dist/scanner.d.ts +10 -0
  76. package/dist/scanner.d.ts.map +1 -0
  77. package/dist/scanner.js +58 -0
  78. package/dist/scanner.js.map +1 -0
  79. package/dist/types.d.ts +180 -0
  80. package/dist/types.d.ts.map +1 -0
  81. package/dist/types.js +2 -0
  82. package/dist/types.js.map +1 -0
  83. package/dist/usage/meter.d.ts +83 -0
  84. package/dist/usage/meter.d.ts.map +1 -0
  85. package/dist/usage/meter.js +111 -0
  86. package/dist/usage/meter.js.map +1 -0
  87. package/dist/usage/store.d.ts +40 -0
  88. package/dist/usage/store.d.ts.map +1 -0
  89. package/dist/usage/store.js +248 -0
  90. package/dist/usage/store.js.map +1 -0
  91. package/package.json +64 -4
  92. package/src/errors.ts +24 -0
  93. package/src/geometry/homography.ts +178 -0
  94. package/src/identify/assets.ts +189 -0
  95. package/src/identify/decode.ts +54 -0
  96. package/src/identify/engine.ts +167 -0
  97. package/src/identify/identifier.ts +431 -0
  98. package/src/identify/manifest.ts +240 -0
  99. package/src/identify/preprocess.ts +227 -0
  100. package/src/identify/router.ts +115 -0
  101. package/src/identify/runtime.ts +197 -0
  102. package/src/identify/search.ts +115 -0
  103. package/src/identify/server.ts +167 -0
  104. package/src/identify/shard.ts +154 -0
  105. package/src/identify/types.ts +122 -0
  106. package/src/identify/worker.ts +13 -0
  107. package/src/identify/workerProtocol.ts +136 -0
  108. package/src/index.ts +71 -0
  109. package/src/lease/verify.ts +252 -0
  110. package/src/scanner.ts +56 -0
  111. package/src/types.ts +196 -0
  112. package/src/usage/meter.ts +165 -0
  113. package/src/usage/store.ts +282 -0
@@ -0,0 +1,107 @@
1
+ /**
2
+ * The identifier: card crops in, catalogue ids out. This is the snapshot half
3
+ * of the SDK, usable on its own before the live pipeline (`createScanner`)
4
+ * exists. Its answer has the same shape whichever side identified the crops,
5
+ * the device or `POST /v1/identify`, so a host never needs to know which.
6
+ *
7
+ * Wire contract of the server route, which `httpIdentify` speaks:
8
+ *
9
+ * POST {serverUrl}/v1/identify multipart/form-data: crop0..crop8 (JPEG, one
10
+ * card each) and the optional text fields
11
+ * `top` (1..20), `purpose`, `session`
12
+ * Authorization: Bearer <lease token>
13
+ * → 200 { modelVersion,
14
+ * results: [ { index, kind?: 'card' | 'not_a_card', confident,
15
+ * candidates: [ { cardId, score } ], identificationId? } ] }
16
+ *
17
+ * Non-2xx answers are RFC 9457 Problem Details.
18
+ */
19
+ import type { DomainCode, LeaseClaims } from '../types.js';
20
+ /** At most this many crops per call, as on the server route. */
21
+ export declare const MAX_CROPS_PER_REQUEST = 9;
22
+ /** Candidates per crop when `top` is not given. */
23
+ export declare const DEFAULT_TOP = 5;
24
+ /** The most candidates a call may ask for. */
25
+ export declare const MAX_TOP = 20;
26
+ export interface IdentifyCandidate {
27
+ /** The catalogue id of the row (the shard's row id). */
28
+ readonly cardId: string;
29
+ /** Cosine similarity, the max over the orientations tried. Higher is closer. */
30
+ readonly score: number;
31
+ }
32
+ /**
33
+ * What a crop is: a card (identified, or not confidently), or not a card at
34
+ * all. There is no "unknown": a card with no confident match is
35
+ * `kind: 'card', confident: false`.
36
+ */
37
+ export type IdentifyKind = 'card' | 'not_a_card';
38
+ export interface IdentifyResult {
39
+ /** Position of the crop in the call. */
40
+ readonly index: number;
41
+ /** `not_a_card` when the best score is below the model version's `notACardBelow`. */
42
+ readonly kind: IdentifyKind;
43
+ /** `top1 - top2 >= confidentMargin`; always false for `not_a_card`. */
44
+ readonly confident: boolean;
45
+ /** Best first; `top` of them (candidates are returned for `not_a_card` too). */
46
+ readonly candidates: readonly IdentifyCandidate[];
47
+ /**
48
+ * Set when the service counted this answer as an identification itself
49
+ * (usage-metering): the SDK then writes no usage event for it.
50
+ */
51
+ readonly identificationId?: string;
52
+ }
53
+ /** Where an answer came from. Informational: results are the same shape either way. */
54
+ export type IdentifySource = 'device' | 'server';
55
+ export type IdentifyFailureReason = 'unavailable' | 'timeout' | 'rejected';
56
+ export type IdentifyOutcome = {
57
+ readonly ok: true;
58
+ /** The model version the thresholds and the candidates belong to. */
59
+ readonly modelVersion: string;
60
+ readonly results: readonly IdentifyResult[];
61
+ readonly source: IdentifySource;
62
+ } | {
63
+ readonly ok: false;
64
+ readonly reason: IdentifyFailureReason;
65
+ /** A stable code first where there is one, e.g. `ALLOWANCE_EXHAUSTED: …`. */
66
+ readonly detail?: string;
67
+ };
68
+ /** Why a crop is being identified; `retry` answers are never charged. */
69
+ export type IdentifyPurpose = 'live' | 'still' | 'retry';
70
+ export interface IdentifyCallOptions {
71
+ readonly signal?: AbortSignal;
72
+ /** Candidates per crop, 1..20. Default 5. */
73
+ readonly top?: number;
74
+ /**
75
+ * The host's scan session id (≤ 128 printable characters). Usage counts one
76
+ * identification per distinct card per session. Default: the identifier's
77
+ * own session, renewed by `newSession()`.
78
+ */
79
+ readonly session?: string;
80
+ readonly purpose?: IdentifyPurpose;
81
+ }
82
+ /** Where identification may run. `local` never sends an image anywhere. */
83
+ export type IdentificationMode = 'auto' | 'local' | 'server';
84
+ /** What the on-device engine is running on, once loaded. */
85
+ export interface DeviceEngineInfo {
86
+ readonly backend: 'webgpu' | 'wasm';
87
+ readonly precision: 'fp16' | 'fp32';
88
+ /** WASM threads in use (1 when the page is not cross-origin isolated). */
89
+ readonly threads: number;
90
+ /** Measured at warm-up: one crop, every orientation, embed + search. */
91
+ readonly perCropMs: number;
92
+ readonly modelVersion: string;
93
+ readonly indexVersion: string;
94
+ readonly shard: DomainCode;
95
+ readonly rows: number;
96
+ }
97
+ export interface IdentifierStatus {
98
+ readonly lease: LeaseClaims | null;
99
+ /** `idle` until the first load is asked for; `failed` keeps the server path usable. */
100
+ readonly device: 'idle' | 'loading' | 'ready' | 'failed';
101
+ readonly deviceInfo: DeviceEngineInfo | null;
102
+ /** Why the device engine failed to load, when it did. */
103
+ readonly deviceError: string | null;
104
+ /** Why the server route is skipped right now, or null when it is usable. */
105
+ readonly serverPaused: string | null;
106
+ }
107
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/identify/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE1D,gEAAgE;AAChE,eAAO,MAAM,qBAAqB,IAAI,CAAA;AAEtC,mDAAmD;AACnD,eAAO,MAAM,WAAW,IAAI,CAAA;AAE5B,8CAA8C;AAC9C,eAAO,MAAM,OAAO,KAAK,CAAA;AAEzB,MAAM,WAAW,iBAAiB;IAChC,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,YAAY,CAAA;AAEhD,MAAM,WAAW,cAAc;IAC7B,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,qFAAqF;IACrF,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,UAAU,EAAE,SAAS,iBAAiB,EAAE,CAAA;IACjD;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CACnC;AAED,uFAAuF;AACvF,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAEhD,MAAM,MAAM,qBAAqB,GAAG,aAAa,GAAG,SAAS,GAAG,UAAU,CAAA;AAE1E,MAAM,MAAM,eAAe,GACvB;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;IACjB,qEAAqE;IACrE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,CAAA;IAC3C,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAChC,GACD;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAA;IAClB,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAA;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAEL,yEAAyE;AACzE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAExD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;IAC7B,6CAA6C;IAC7C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CACnC;AAED,2EAA2E;AAC3E,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AAE5D,4DAA4D;AAC5D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAA;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IAClC,uFAAuF;IACvF,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAA;IACxD,QAAQ,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC5C,yDAAyD;IACzD,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CACrC"}
@@ -0,0 +1,7 @@
1
+ /** At most this many crops per call, as on the server route. */
2
+ export const MAX_CROPS_PER_REQUEST = 9;
3
+ /** Candidates per crop when `top` is not given. */
4
+ export const DEFAULT_TOP = 5;
5
+ /** The most candidates a call may ask for. */
6
+ export const MAX_TOP = 20;
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/identify/types.ts"],"names":[],"mappings":"AAoBA,gEAAgE;AAChE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAA;AAEtC,mDAAmD;AACnD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAA;AAE5B,8CAA8C;AAC9C,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/identify/worker.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The identification Worker's entry point. `createIdentifier` starts it with
3
+ * `new Worker(new URL('./worker.js', import.meta.url), { type: 'module' })`,
4
+ * the pattern Vite, webpack 5 and Rollup bundle without configuration. A host
5
+ * that builds its own Worker points it at `@dejadex/web/identify-worker`.
6
+ *
7
+ * Everything that touches the model runs here: decoding the crops, the
8
+ * resize, the session and the search. The main thread only routes.
9
+ */
10
+ import { defaultEngineDeps } from './engine.js';
11
+ import { serveEngine } from './workerProtocol.js';
12
+ serveEngine(self, defaultEngineDeps);
13
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/identify/worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAwB,MAAM,qBAAqB,CAAA;AAEvE,WAAW,CAAC,IAAkC,EAAE,iBAAiB,CAAC,CAAA"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The device engine across a Worker boundary: a request/response protocol by
3
+ * id, the Worker side (`serveEngine`) and the main-thread side
4
+ * (`connectWorkerEngine`). Crops cross as `Blob`s (structured-cloned, not
5
+ * decoded on the main thread); answers come back as plain data.
6
+ */
7
+ import { type ScannerErrorCode } from '../errors.js';
8
+ import type { DeviceEngine, EngineConfig, EngineDeps } from './engine.js';
9
+ import type { DeviceEngineInfo, IdentifyResult } from './types.js';
10
+ export type EngineRequest = {
11
+ readonly id: number;
12
+ readonly op: 'load';
13
+ readonly config: EngineConfig;
14
+ } | {
15
+ readonly id: number;
16
+ readonly op: 'identify';
17
+ readonly crops: readonly Blob[];
18
+ readonly top: number;
19
+ } | {
20
+ readonly id: number;
21
+ readonly op: 'release';
22
+ };
23
+ export type EngineResponse = {
24
+ readonly id: number;
25
+ readonly ok: true;
26
+ readonly info: DeviceEngineInfo | null;
27
+ readonly results?: readonly IdentifyResult[];
28
+ } | {
29
+ readonly id: number;
30
+ readonly ok: false;
31
+ readonly code: ScannerErrorCode | 'ERROR';
32
+ readonly message: string;
33
+ };
34
+ /** What `serveEngine` needs of `self` in a Worker. */
35
+ export interface WorkerScopeLike {
36
+ addEventListener(type: 'message', listener: (event: {
37
+ readonly data: unknown;
38
+ }) => void): void;
39
+ postMessage(message: EngineResponse): void;
40
+ }
41
+ /** What `connectWorkerEngine` needs of a `Worker`. */
42
+ export interface WorkerLike {
43
+ addEventListener(type: 'message' | 'error' | 'messageerror', listener: (event: {
44
+ readonly data?: unknown;
45
+ readonly message?: string;
46
+ }) => void): void;
47
+ postMessage(message: EngineRequest): void;
48
+ terminate(): void;
49
+ }
50
+ /** Runs in the Worker: answers requests one at a time, in order. */
51
+ export declare function serveEngine(scope: WorkerScopeLike, deps: () => Promise<EngineDeps>): void;
52
+ /** Main thread: loads the engine in `worker` and returns a `DeviceEngine` that forwards to it. */
53
+ export declare function connectWorkerEngine(worker: WorkerLike, config: EngineConfig): Promise<DeviceEngine>;
54
+ //# sourceMappingURL=workerProtocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workerProtocol.d.ts","sourceRoot":"","sources":["../../src/identify/workerProtocol.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAElE,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GAC3E;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACvG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAA;CAAE,CAAA;AAEnD,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,cAAc,EAAE,CAAA;CAAE,GAChI;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAIpH,sDAAsD;AACtD,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAA;IAC9F,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;CAC3C;AAED,sDAAsD;AACtD,MAAM,WAAW,UAAU;IACzB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,cAAc,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAA;IACrJ,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAA;IACzC,SAAS,IAAI,IAAI,CAAA;CAClB;AAOD,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAoCzF;AAED,kGAAkG;AAClG,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAuDnG"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The device engine across a Worker boundary: a request/response protocol by
3
+ * id, the Worker side (`serveEngine`) and the main-thread side
4
+ * (`connectWorkerEngine`). Crops cross as `Blob`s (structured-cloned, not
5
+ * decoded on the main thread); answers come back as plain data.
6
+ */
7
+ import { ScannerError } from '../errors.js';
8
+ import { loadDeviceEngine } from './engine.js';
9
+ const failure = (id, err) => err instanceof ScannerError
10
+ ? { id, ok: false, code: err.code, message: err.message }
11
+ : { id, ok: false, code: 'ERROR', message: err instanceof Error ? err.message || err.name : String(err) };
12
+ /** Runs in the Worker: answers requests one at a time, in order. */
13
+ export function serveEngine(scope, deps) {
14
+ let engine = null;
15
+ let queue = Promise.resolve();
16
+ const handle = async (req) => {
17
+ switch (req.op) {
18
+ case 'load':
19
+ await engine?.release();
20
+ engine = null;
21
+ engine = await loadDeviceEngine(req.config, await deps());
22
+ return { id: req.id, ok: true, info: engine.info };
23
+ case 'identify': {
24
+ if (!engine)
25
+ throw new ScannerError('INVALID_OPTIONS', 'the device engine is not loaded');
26
+ const results = await engine.identify(req.crops, req.top);
27
+ return { id: req.id, ok: true, info: engine.info, results };
28
+ }
29
+ case 'release':
30
+ await engine?.release();
31
+ engine = null;
32
+ return { id: req.id, ok: true, info: null };
33
+ }
34
+ };
35
+ scope.addEventListener('message', (event) => {
36
+ const req = event.data;
37
+ if (typeof req !== 'object' || req === null || typeof req.id !== 'number')
38
+ return;
39
+ queue = queue.then(async () => {
40
+ let res;
41
+ try {
42
+ res = await handle(req);
43
+ }
44
+ catch (err) {
45
+ res = failure(req.id, err);
46
+ }
47
+ scope.postMessage(res);
48
+ });
49
+ });
50
+ }
51
+ /** Main thread: loads the engine in `worker` and returns a `DeviceEngine` that forwards to it. */
52
+ export function connectWorkerEngine(worker, config) {
53
+ let nextId = 1;
54
+ const pending = new Map();
55
+ let dead = null;
56
+ const failAll = (err) => {
57
+ dead = err;
58
+ for (const p of pending.values())
59
+ p.reject(err);
60
+ pending.clear();
61
+ };
62
+ worker.addEventListener('message', (event) => {
63
+ const res = event.data;
64
+ const p = typeof res === 'object' && res !== null ? pending.get(res.id) : undefined;
65
+ if (!p)
66
+ return;
67
+ pending.delete(res.id);
68
+ if (res.ok)
69
+ p.resolve(res);
70
+ else
71
+ p.reject(new ScannerError(res.code === 'ERROR' ? 'UNSUPPORTED_DEVICE' : res.code, res.message));
72
+ });
73
+ worker.addEventListener('error', (event) => {
74
+ failAll(new ScannerError('UNSUPPORTED_DEVICE', `the identification Worker failed: ${event.message ?? 'unknown error'}`));
75
+ });
76
+ worker.addEventListener('messageerror', () => {
77
+ failAll(new ScannerError('UNSUPPORTED_DEVICE', 'the identification Worker sent a message that could not be read'));
78
+ });
79
+ const call = (req) => {
80
+ if (dead)
81
+ return Promise.reject(dead);
82
+ const id = nextId++;
83
+ return new Promise((resolve, reject) => {
84
+ pending.set(id, { resolve, reject });
85
+ worker.postMessage({ ...req, id });
86
+ });
87
+ };
88
+ return call({ op: 'load', config }).then((loaded) => {
89
+ let info = loaded.info;
90
+ return {
91
+ get info() {
92
+ return info;
93
+ },
94
+ async identify(crops, top) {
95
+ const res = await call({ op: 'identify', crops, top });
96
+ if (res.info)
97
+ info = res.info;
98
+ return [...(res.results ?? [])];
99
+ },
100
+ async release() {
101
+ try {
102
+ if (!dead)
103
+ await call({ op: 'release' });
104
+ }
105
+ finally {
106
+ worker.terminate();
107
+ failAll(new ScannerError('INVALID_OPTIONS', 'the device engine was released'));
108
+ }
109
+ },
110
+ };
111
+ });
112
+ }
113
+ //# sourceMappingURL=workerProtocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workerProtocol.js","sourceRoot":"","sources":["../../src/identify/workerProtocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Public entry point of the web SDK.
3
+ *
4
+ * Real today: the homography maths (`geometry/`), and identification of card
5
+ * crops (`createIdentifier`: on the device or through the server, under a
6
+ * verified lease, with usage counted on the device). Stubbed with final
7
+ * shapes: `createScanner` (the live pipeline). See README.md.
8
+ */
9
+ export { createScanner } from './scanner.js';
10
+ export { createIdentifier, type Identifier, type IdentifierOptions } from './identify/identifier.js';
11
+ export { DEFAULT_TOP, MAX_CROPS_PER_REQUEST, MAX_TOP, type DeviceEngineInfo, type IdentificationMode, type IdentifierStatus, type IdentifyCallOptions, type IdentifyCandidate, type IdentifyFailureReason, type IdentifyKind, type IdentifyOutcome, type IdentifyPurpose, type IdentifyResult, type IdentifySource, } from './identify/types.js';
12
+ export type { RuntimeOptions } from './identify/runtime.js';
13
+ export type { WorkerLike } from './identify/workerProtocol.js';
14
+ export { LeaseVerificationError, verifyLease, type LeaseFailure, type LeasePublicKey, type VerifyLeaseOptions, } from './lease/verify.js';
15
+ export type { DrainResult } from './usage/meter.js';
16
+ export { indexedDbUsageStore, memoryUsageStore, type UsageStore } from './usage/store.js';
17
+ export { ScannerError, type ScannerErrorCode } from './errors.js';
18
+ export { IDENTITY, UNIT_QUAD, applyHomography, invertHomography, multiplyHomography, quadToCssMatrix3d, toCssMatrix3d, unitSquareToQuad, type ElementSize, type Homography, type Point, type Quad, } from './geometry/homography.js';
19
+ export type { Candidate, DeviceTier, DomainCode, ExternalIds, FrameSourceInput, Lease, LeaseClaims, LeaseGrant, LeaseRequest, PrintId, Scanner, ScannerOptions, ScannerState, TrackResult, UsageBatch, UsageReport, VariantCode, } from './types.js';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AACpG,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,OAAO,EACP,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC3D,YAAY,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAC9D,OAAO,EACL,sBAAsB,EACtB,WAAW,EACX,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AACzF,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACjE,OAAO,EACL,QAAQ,EACR,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,IAAI,GACV,MAAM,0BAA0B,CAAA;AACjC,YAAY,EACV,SAAS,EACT,UAAU,EACV,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,KAAK,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,OAAO,EACP,OAAO,EACP,cAAc,EACd,YAAY,EACZ,WAAW,EACX,UAAU,EACV,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Public entry point of the web SDK.
3
+ *
4
+ * Real today: the homography maths (`geometry/`), and identification of card
5
+ * crops (`createIdentifier`: on the device or through the server, under a
6
+ * verified lease, with usage counted on the device). Stubbed with final
7
+ * shapes: `createScanner` (the live pipeline). See README.md.
8
+ */
9
+ export { createScanner } from './scanner.js';
10
+ export { createIdentifier } from './identify/identifier.js';
11
+ export { DEFAULT_TOP, MAX_CROPS_PER_REQUEST, MAX_TOP, } from './identify/types.js';
12
+ export { LeaseVerificationError, verifyLease, } from './lease/verify.js';
13
+ export { indexedDbUsageStore, memoryUsageStore } from './usage/store.js';
14
+ export { ScannerError } from './errors.js';
15
+ export { IDENTITY, UNIT_QUAD, applyHomography, invertHomography, multiplyHomography, quadToCssMatrix3d, toCssMatrix3d, unitSquareToQuad, } from './geometry/homography.js';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAA2C,MAAM,0BAA0B,CAAA;AACpG,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,OAAO,GAYR,MAAM,qBAAqB,CAAA;AAG5B,OAAO,EACL,sBAAsB,EACtB,WAAW,GAIZ,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAmB,MAAM,kBAAkB,CAAA;AACzF,OAAO,EAAE,YAAY,EAAyB,MAAM,aAAa,CAAA;AACjE,OAAO,EACL,QAAQ,EACR,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,GAKjB,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Lease verification on the device: an Ed25519 compact JWS (RFC 7515,
3
+ * `alg: EdDSA` per RFC 8037), `typ: dejadex-lease+jwt`, checked against the
4
+ * public keys the host embeds. Mirrors `service/src/leases/jws.ts` check for
5
+ * check, in the same order:
6
+ *
7
+ * structure → header → signature (over the raw bytes) → claims shape →
8
+ * time → origin → domains
9
+ *
10
+ * Nothing in an unsigned payload is looked at before the signature holds, and
11
+ * the algorithm comes from this code, never from the token.
12
+ *
13
+ * Signature: WebCrypto Ed25519 where the browser has it (Chrome 137+, Safari
14
+ * 17+, Firefox 129+, Node 22); elsewhere `@noble/ed25519` (MIT, audited,
15
+ * zero dependencies), loaded only then.
16
+ *
17
+ * The browser is untrusted: this check keeps an honest host from running on a
18
+ * lease it should not, and bounds what a dishonest one gets. The service
19
+ * checks every lease again.
20
+ */
21
+ import { ScannerError } from '../errors.js';
22
+ import type { Lease } from '../types.js';
23
+ export declare const LEASE_ALG = "EdDSA";
24
+ export declare const LEASE_TYP = "dejadex-lease+jwt";
25
+ export declare const MAX_LEASE_TTL_SECONDS = 86400;
26
+ export declare const DEFAULT_CLOCK_SKEW_SECONDS = 60;
27
+ /** An Ed25519 public key as a JWK (`kty: OKP`, `crv: Ed25519`), or just its `x`. */
28
+ export interface LeasePublicKey {
29
+ readonly kty?: 'OKP';
30
+ readonly crv?: 'Ed25519';
31
+ /** The raw 32-byte key, base64url. */
32
+ readonly x: string;
33
+ /** When set, only leases whose header names this `kid` are checked against it. */
34
+ readonly kid?: string;
35
+ /** Carried by a JWKS entry; `EdDSA` / `sig` when present. */
36
+ readonly alg?: string;
37
+ readonly use?: string;
38
+ }
39
+ export type Ed25519Verify = (publicKey: Uint8Array<ArrayBuffer>, message: Uint8Array<ArrayBuffer>, signature: Uint8Array<ArrayBuffer>) => Promise<boolean>;
40
+ export interface VerifyLeaseOptions {
41
+ readonly publicKeys: readonly LeasePublicKey[];
42
+ /** The page origin, matched exactly against `origins`; null skips the check (no page). */
43
+ readonly origin: string | null;
44
+ /** Domains the caller wants; each must be granted. */
45
+ readonly domains: readonly string[];
46
+ /** Unix seconds. Default: the device clock. */
47
+ readonly now?: number;
48
+ readonly clockSkewSeconds?: number;
49
+ /** Test seam; default WebCrypto, then `@noble/ed25519`. */
50
+ readonly verify?: Ed25519Verify;
51
+ }
52
+ /** The service's reason, first in every message, so support can match the two sides. */
53
+ export type LeaseFailure = 'LEASE_MALFORMED' | 'LEASE_BAD_SIGNATURE' | 'LEASE_EXPIRED' | 'LEASE_NOT_YET_VALID' | 'LEASE_ORIGIN_NOT_ALLOWED' | 'LEASE_DOMAIN_NOT_ALLOWED';
54
+ export declare class LeaseVerificationError extends ScannerError {
55
+ readonly reason: LeaseFailure;
56
+ constructor(reason: LeaseFailure, message: string);
57
+ }
58
+ /** Strict unpadded base64url: one decoding and one encoding per string, or null. */
59
+ export declare function base64urlDecodeStrict(s: string): Uint8Array<ArrayBuffer> | null;
60
+ export declare function base64urlEncode(bytes: Uint8Array): string;
61
+ /** Whether this runtime's WebCrypto does Ed25519, probed once with a known-good key. */
62
+ export declare function hasWebCryptoEd25519(): Promise<boolean>;
63
+ /** WebCrypto Ed25519 when the runtime has it, else `@noble/ed25519`. Any error is "does not verify". */
64
+ export declare const defaultEd25519Verify: Ed25519Verify;
65
+ /** The fallback on its own, for runtimes without WebCrypto Ed25519 (and its tests). */
66
+ export declare const nobleEd25519Verify: Ed25519Verify;
67
+ /** Verifies `token` and returns the lease, or throws a `LeaseVerificationError`. */
68
+ export declare function verifyLease(token: string, options: VerifyLeaseOptions): Promise<Lease>;
69
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/lease/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,aAAa,CAAA;AAErD,eAAO,MAAM,SAAS,UAAU,CAAA;AAChC,eAAO,MAAM,SAAS,sBAAsB,CAAA;AAC5C,eAAO,MAAM,qBAAqB,QAAS,CAAA;AAC3C,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAE5C,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,CAAA;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAA;IACxB,sCAAsC;IACtC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;IAClB,kFAAkF;IAClF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAE1J,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAA;IAC9C,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAA;CAChC;AAED,wFAAwF;AACxF,MAAM,MAAM,YAAY,GACpB,iBAAiB,GACjB,qBAAqB,GACrB,eAAe,GACf,qBAAqB,GACrB,0BAA0B,GAC1B,0BAA0B,CAAA;AAW9B,qBAAa,sBAAuB,SAAQ,YAAY;IAEpD,QAAQ,CAAC,MAAM,EAAE,YAAY;gBAApB,MAAM,EAAE,YAAY,EAC7B,OAAO,EAAE,MAAM;CAIlB;AASD,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,IAAI,CAc/E;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIzD;AAyDD,wFAAwF;AACxF,wBAAgB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAYtD;AAED,wGAAwG;AACxG,eAAO,MAAM,oBAAoB,EAAE,aAWlC,CAAA;AAED,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,EAAE,aAOhC,CAAA;AAED,oFAAoF;AACpF,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,KAAK,CAAC,CA2C5F"}