@sekyro/web 0.1.0-rc.5 → 0.1.0-rc.7

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/CHANGELOG.md +37 -0
  2. package/LICENSE +3 -3
  3. package/README.md +4 -4
  4. package/dist/chunk-B45J4KC3.js +1 -0
  5. package/dist/chunk-BMA36W2W.js +1 -0
  6. package/dist/chunk-FPXL63KZ.js +1 -0
  7. package/dist/chunk-IYUOYINS.js +1 -0
  8. package/dist/chunk-P7ECRN47.js +1 -0
  9. package/dist/chunk-SXZCL5NO.js +1 -0
  10. package/dist/chunk-YOB4ZTYN.js +1 -0
  11. package/dist/chunk-YQBK6OIM.js +1 -0
  12. package/dist/client/index.cjs +1 -357
  13. package/dist/client/index.d.cts +2 -2
  14. package/dist/client/index.d.ts +2 -2
  15. package/dist/client/index.js +1 -15
  16. package/dist/core/index.cjs +1 -1639
  17. package/dist/core/index.js +1 -139
  18. package/dist/core/v3/detect-worker.cjs +1 -392
  19. package/dist/core/v3/detect-worker.js +1 -13
  20. package/dist/{create-verification-CA-3szPI.d.cts → create-verification-C2JhOO6Y.d.cts} +100 -15
  21. package/dist/{create-verification-c98uAxbl.d.ts → create-verification-CGazwtAh.d.ts} +100 -15
  22. package/dist/detector-scanic-VQFFXKTL.js +1 -0
  23. package/dist/{hosted-client-DWzCRYJK.d.ts → hosted-client-kBeq-mnJ.d.cts} +188 -7
  24. package/dist/{hosted-client-DWzCRYJK.d.cts → hosted-client-kBeq-mnJ.d.ts} +188 -7
  25. package/dist/index.cjs +1 -3020
  26. package/dist/index.d.cts +2 -2
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.js +1 -85
  29. package/dist/internal/index.cjs +1 -4429
  30. package/dist/internal/index.d.cts +10 -7
  31. package/dist/internal/index.d.ts +10 -7
  32. package/dist/internal/index.js +1 -657
  33. package/dist/popup/index.cjs +1 -76
  34. package/dist/popup/index.js +1 -11
  35. package/dist/scanic-ml-stub-KW7IZHUT.js +1 -0
  36. package/package.json +5 -8
  37. package/sbom.cdx.json +195 -0
  38. package/dist/chunk-MWNFSNMP.js +0 -52
  39. package/dist/chunk-MWNFSNMP.js.map +0 -1
  40. package/dist/chunk-NILNKLK6.js +0 -50
  41. package/dist/chunk-NILNKLK6.js.map +0 -1
  42. package/dist/chunk-NWF46H7K.js +0 -359
  43. package/dist/chunk-NWF46H7K.js.map +0 -1
  44. package/dist/chunk-SGDXLAXR.js +0 -1163
  45. package/dist/chunk-SGDXLAXR.js.map +0 -1
  46. package/dist/chunk-TG5IE552.js +0 -1128
  47. package/dist/chunk-TG5IE552.js.map +0 -1
  48. package/dist/chunk-WY6U7AIK.js +0 -193
  49. package/dist/chunk-WY6U7AIK.js.map +0 -1
  50. package/dist/chunk-YVFF4Q4G.js +0 -327
  51. package/dist/chunk-YVFF4Q4G.js.map +0 -1
  52. package/dist/client/index.cjs.map +0 -1
  53. package/dist/client/index.js.map +0 -1
  54. package/dist/core/index.cjs.map +0 -1
  55. package/dist/core/index.js.map +0 -1
  56. package/dist/core/v3/detect-worker.cjs.map +0 -1
  57. package/dist/core/v3/detect-worker.js.map +0 -1
  58. package/dist/detector-scanic-4C6IEW2K.js +0 -787
  59. package/dist/detector-scanic-4C6IEW2K.js.map +0 -1
  60. package/dist/index.cjs.map +0 -1
  61. package/dist/index.js.map +0 -1
  62. package/dist/internal/index.cjs.map +0 -1
  63. package/dist/internal/index.js.map +0 -1
  64. package/dist/popup/index.cjs.map +0 -1
  65. package/dist/popup/index.js.map +0 -1
  66. package/dist/scanic-ml-stub-S2OZ6HEF.js +0 -10
  67. package/dist/scanic-ml-stub-S2OZ6HEF.js.map +0 -1
@@ -1,76 +1 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/popup/index.ts
21
- var popup_exports = {};
22
- __export(popup_exports, {
23
- SEKYRO_EVENTS: () => SEKYRO_EVENTS,
24
- open: () => open,
25
- openHosted: () => openHosted
26
- });
27
- module.exports = __toCommonJS(popup_exports);
28
- var SEKYRO_EVENTS = [
29
- "session.completed",
30
- "session.failed",
31
- "session.review_pending",
32
- "session.expired",
33
- "session.cancelled"
34
- ];
35
- var WINDOW_NAME = "sekyro-verify";
36
- var WINDOW_FEATURES = "width=480,height=720,noopener=false";
37
- var EVENT_NAMES = new Set(SEKYRO_EVENTS);
38
- function isSekyroEvent(data) {
39
- if (data === null || typeof data !== "object") return false;
40
- const d = data;
41
- return d.source === "sekyro" && d.version === 1 && typeof d.sessionId === "string" && typeof d.event === "string" && EVENT_NAMES.has(d.event);
42
- }
43
- function open(opts) {
44
- const origin = new URL(opts.hostedUrl).origin;
45
- const popup = window.open(opts.hostedUrl, WINDOW_NAME, WINDOW_FEATURES);
46
- if (!popup) return { error: "popup_blocked" };
47
- const listener = (ev) => {
48
- if (ev.source !== popup) return;
49
- if (ev.origin !== origin) return;
50
- if (!isSekyroEvent(ev.data)) return;
51
- const { source, version, event, sessionId } = ev.data;
52
- opts.onEvent({ source, version, event, sessionId });
53
- };
54
- window.addEventListener("message", listener);
55
- return {
56
- close() {
57
- window.removeEventListener("message", listener);
58
- popup.close();
59
- }
60
- };
61
- }
62
- function openHosted(hostedUrl, opts) {
63
- if (opts.mode === "redirect") {
64
- window.location.assign(hostedUrl);
65
- return { close() {
66
- } };
67
- }
68
- return open({ hostedUrl, onEvent: opts.onEvent ?? (() => void 0) });
69
- }
70
- // Annotate the CommonJS export names for ESM import in node:
71
- 0 && (module.exports = {
72
- SEKYRO_EVENTS,
73
- open,
74
- openHosted
75
- });
76
- //# sourceMappingURL=index.cjs.map
1
+ "use strict";var s=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var f=(n,e)=>{for(var t in e)s(n,t,{get:e[t],enumerable:!0})},y=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of E(e))!l.call(n,o)&&o!==t&&s(n,o,{get:()=>e[o],enumerable:!(r=a(e,o))||r.enumerable});return n};var k=n=>y(s({},"__esModule",{value:!0}),n);var m={};f(m,{SEKYRO_EVENTS:()=>i,open:()=>p,openHosted:()=>x});module.exports=k(m);var i=["session.completed","session.failed","session.review_pending","session.expired","session.cancelled"],S="sekyro-verify",g="width=480,height=720,noopener=false",w=new Set(i);function O(n){if(n===null||typeof n!="object")return!1;let e=n;return e.source==="sekyro"&&e.version===1&&typeof e.sessionId=="string"&&typeof e.event=="string"&&w.has(e.event)}function p(n){let e=new URL(n.hostedUrl).origin,t=window.open(n.hostedUrl,S,g);if(!t)return{error:"popup_blocked"};let r=o=>{if(o.source!==t||o.origin!==e||!O(o.data))return;let{source:d,version:c,event:v,sessionId:u}=o.data;n.onEvent({source:d,version:c,event:v,sessionId:u})};return window.addEventListener("message",r),{close(){window.removeEventListener("message",r),t.close()}}}function x(n,e){return e.mode==="redirect"?(window.location.assign(n),{close(){}}):p({hostedUrl:n,onEvent:e.onEvent??(()=>{})})}0&&(module.exports={SEKYRO_EVENTS,open,openHosted});
@@ -1,11 +1 @@
1
- import {
2
- SEKYRO_EVENTS,
3
- open,
4
- openHosted
5
- } from "../chunk-NILNKLK6.js";
6
- export {
7
- SEKYRO_EVENTS,
8
- open,
9
- openHosted
10
- };
11
- //# sourceMappingURL=index.js.map
1
+ import{a,b,c}from"../chunk-SXZCL5NO.js";export{a as SEKYRO_EVENTS,b as open,c as openHosted};
@@ -0,0 +1 @@
1
+ function e(){throw new Error("scanic ML detector is not vendored (classical pipeline only)")}var t={};export{t as default,e as initMlDetector};
package/package.json CHANGED
@@ -1,17 +1,13 @@
1
1
  {
2
2
  "name": "@sekyro/web",
3
- "version": "0.1.0-rc.5",
4
- "description": "Sekyro web SDK — browser liveness capture, hosted-verification client and popup embed for Sekyro identity verification",
3
+ "version": "0.1.0-rc.7",
4
+ "description": "Sekyro AI web SDK — browser liveness capture, hosted-verification client and popup embed for Sekyro AI identity verification",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git+https://github.com/IBTIKAR-Technologies/sekyro-sdks.git",
8
+ "url": "git+https://github.com/IBTIKAR-Technologies/ibtikar-identity.git",
9
9
  "directory": "packages/sekyro-web"
10
10
  },
11
- "homepage": "https://github.com/IBTIKAR-Technologies/sekyro-sdks/tree/main/packages/sekyro-web#readme",
12
- "bugs": {
13
- "url": "https://github.com/IBTIKAR-Technologies/sekyro-sdks/issues"
14
- },
15
11
  "keywords": [
16
12
  "sekyro",
17
13
  "kyc",
@@ -96,7 +92,8 @@
96
92
  "dist",
97
93
  "README.md",
98
94
  "CHANGELOG.md",
99
- "LICENSE"
95
+ "LICENSE",
96
+ "sbom.cdx.json"
100
97
  ],
101
98
  "scripts": {
102
99
  "build": "tsup",
package/sbom.cdx.json ADDED
@@ -0,0 +1,195 @@
1
+ {
2
+ "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
3
+ "bomFormat": "CycloneDX",
4
+ "specVersion": "1.6",
5
+ "version": 1,
6
+ "metadata": {
7
+ "tools": {
8
+ "components": [
9
+ {
10
+ "type": "application",
11
+ "name": "npm",
12
+ "version": "11.12.1"
13
+ },
14
+ {
15
+ "type": "library",
16
+ "name": "cyclonedx-library",
17
+ "group": "@cyclonedx",
18
+ "version": "10.3.0",
19
+ "author": "Jan Kowalleck",
20
+ "description": "Core functionality of CycloneDX for JavaScript (Node.js or WebBrowser).",
21
+ "licenses": [
22
+ {
23
+ "license": {
24
+ "id": "Apache-2.0"
25
+ }
26
+ }
27
+ ],
28
+ "externalReferences": [
29
+ {
30
+ "url": "https://github.com/CycloneDX/cyclonedx-javascript-library/issues",
31
+ "type": "issue-tracker",
32
+ "comment": "as detected from PackageJson property \"bugs.url\""
33
+ },
34
+ {
35
+ "url": "git+https://github.com/CycloneDX/cyclonedx-javascript-library.git",
36
+ "type": "vcs",
37
+ "comment": "as detected from PackageJson property \"repository.url\""
38
+ },
39
+ {
40
+ "url": "https://github.com/CycloneDX/cyclonedx-javascript-library#readme",
41
+ "type": "website",
42
+ "comment": "as detected from PackageJson property \"homepage\""
43
+ }
44
+ ],
45
+ "properties": [
46
+ {
47
+ "name": "cdx:npm:package:constraint:engine:node",
48
+ "value": ">=20.18.0"
49
+ }
50
+ ]
51
+ },
52
+ {
53
+ "type": "application",
54
+ "name": "cyclonedx-npm",
55
+ "group": "@cyclonedx",
56
+ "version": "6.0.1",
57
+ "author": "Jan Kowalleck",
58
+ "description": "Create CycloneDX Software Bill of Materials (SBOM) from NPM projects.",
59
+ "licenses": [
60
+ {
61
+ "license": {
62
+ "id": "Apache-2.0"
63
+ }
64
+ }
65
+ ],
66
+ "externalReferences": [
67
+ {
68
+ "url": "https://github.com/CycloneDX/cyclonedx-node-npm/issues",
69
+ "type": "issue-tracker",
70
+ "comment": "as detected from PackageJson property \"bugs.url\""
71
+ },
72
+ {
73
+ "url": "git+https://github.com/CycloneDX/cyclonedx-node-npm.git",
74
+ "type": "vcs",
75
+ "comment": "as detected from PackageJson property \"repository.url\""
76
+ },
77
+ {
78
+ "url": "https://github.com/CycloneDX/cyclonedx-node-npm#readme",
79
+ "type": "website",
80
+ "comment": "as detected from PackageJson property \"homepage\""
81
+ }
82
+ ],
83
+ "properties": [
84
+ {
85
+ "name": "cdx:npm:package:constraint:engine:node",
86
+ "value": ">=20.18.0"
87
+ },
88
+ {
89
+ "name": "cdx:npm:package:constraint:engine:npm",
90
+ "value": ">=9"
91
+ }
92
+ ]
93
+ }
94
+ ]
95
+ },
96
+ "component": {
97
+ "type": "application",
98
+ "name": "web",
99
+ "group": "@sekyro",
100
+ "version": "0.1.0-rc.7",
101
+ "bom-ref": "@sekyro/web@0.1.0-rc.7",
102
+ "description": "Sekyro AI web SDK — browser liveness capture, hosted-verification client and popup embed for Sekyro AI identity verification",
103
+ "licenses": [
104
+ {
105
+ "license": {
106
+ "name": "UNLICENSED",
107
+ "acknowledgement": "declared"
108
+ }
109
+ }
110
+ ],
111
+ "purl": "pkg:npm/%40sekyro/web@0.1.0-rc.7?vcs_url=git%2Bhttps%3A%2F%2Fgithub.com%2FIBTIKAR-Technologies%2Fibtikar-identity.git%23packages%2Fsekyro-web",
112
+ "externalReferences": [
113
+ {
114
+ "url": "https://github.com/IBTIKAR-Technologies/ibtikar-identity/issues",
115
+ "type": "issue-tracker",
116
+ "comment": "as detected from PackageJson property \"bugs.url\""
117
+ },
118
+ {
119
+ "url": "git+https://github.com/IBTIKAR-Technologies/ibtikar-identity.git#packages/sekyro-web",
120
+ "type": "vcs",
121
+ "comment": "as detected from PackageJson property \"repository.url\" and \"repository.directory\""
122
+ },
123
+ {
124
+ "url": "https://github.com/IBTIKAR-Technologies/ibtikar-identity#readme",
125
+ "type": "website",
126
+ "comment": "as detected from PackageJson property \"homepage\""
127
+ }
128
+ ],
129
+ "properties": [
130
+ {
131
+ "name": "cdx:npm:package:constraint:engine:node",
132
+ "value": ">=20"
133
+ },
134
+ {
135
+ "name": "cdx:npm:package:path",
136
+ "value": ""
137
+ }
138
+ ]
139
+ },
140
+ "properties": [
141
+ {
142
+ "name": "cdx:reproducible",
143
+ "value": "true"
144
+ }
145
+ ]
146
+ },
147
+ "components": [
148
+ {
149
+ "type": "library",
150
+ "name": "tasks-vision",
151
+ "group": "@mediapipe",
152
+ "version": "0.10.35",
153
+ "bom-ref": "@sekyro/web@0.1.0-rc.7|@mediapipe/tasks-vision@0.10.35",
154
+ "licenses": [
155
+ {
156
+ "license": {
157
+ "id": "Apache-2.0",
158
+ "acknowledgement": "declared"
159
+ }
160
+ }
161
+ ],
162
+ "purl": "pkg:npm/%40mediapipe/tasks-vision@0.10.35",
163
+ "externalReferences": [
164
+ {
165
+ "url": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.35.tgz",
166
+ "type": "distribution",
167
+ "hashes": [
168
+ {
169
+ "alg": "SHA-512",
170
+ "content": "1cebda77055113a242fb8e67c988669f2c27af987f27c299bce794355386f6aff4f3be6966022dce7141f5b453bcb736eb861226a899d4db08a424ad270fde82"
171
+ }
172
+ ],
173
+ "comment": "as detected from npm-ls property \"resolved\" and property \"integrity\""
174
+ }
175
+ ],
176
+ "properties": [
177
+ {
178
+ "name": "cdx:npm:package:path",
179
+ "value": "node_modules/@mediapipe/tasks-vision"
180
+ }
181
+ ]
182
+ }
183
+ ],
184
+ "dependencies": [
185
+ {
186
+ "ref": "@sekyro/web@0.1.0-rc.7",
187
+ "dependsOn": [
188
+ "@sekyro/web@0.1.0-rc.7|@mediapipe/tasks-vision@0.10.35"
189
+ ]
190
+ },
191
+ {
192
+ "ref": "@sekyro/web@0.1.0-rc.7|@mediapipe/tasks-vision@0.10.35"
193
+ }
194
+ ]
195
+ }
@@ -1,52 +0,0 @@
1
- // src/core/v3/frame-quality.ts
2
- var SHARP_REF = 180;
3
- var EXPOSURE_BAND = [100, 190];
4
- var EXPOSURE_FALLOFF = 64;
5
- function lumaAt(data, index) {
6
- return 0.299 * (data[index] ?? 0) + 0.587 * (data[index + 1] ?? 0) + 0.114 * (data[index + 2] ?? 0);
7
- }
8
- function meanLuma(image) {
9
- const { data, width, height } = image;
10
- const pixels = width * height;
11
- if (pixels === 0) return 0;
12
- let sum = 0;
13
- for (let i = 0; i < pixels; i += 1) sum += lumaAt(data, i * 4);
14
- return sum / pixels;
15
- }
16
- function sharpness(image) {
17
- const { data, width, height } = image;
18
- if (width < 3 || height < 3) return 0;
19
- const gray = new Float32Array(width * height);
20
- for (let i = 0; i < gray.length; i += 1) gray[i] = lumaAt(data, i * 4);
21
- let sum = 0;
22
- let sumSquares = 0;
23
- let count = 0;
24
- for (let y = 1; y < height - 1; y += 1) {
25
- for (let x = 1; x < width - 1; x += 1) {
26
- const i = y * width + x;
27
- const response = (gray[i - width] ?? 0) + (gray[i - 1] ?? 0) + (gray[i + 1] ?? 0) + (gray[i + width] ?? 0) - 4 * (gray[i] ?? 0);
28
- sum += response;
29
- sumSquares += response * response;
30
- count += 1;
31
- }
32
- }
33
- if (count === 0) return 0;
34
- const mean = sum / count;
35
- const variance = sumSquares / count - mean * mean;
36
- return Math.min(1, Math.max(0, variance) / SHARP_REF);
37
- }
38
- function exposure(image) {
39
- const mean = meanLuma(image);
40
- const [low, high] = EXPOSURE_BAND;
41
- const distance = mean < low ? low - mean : mean > high ? mean - high : 0;
42
- return Math.max(0, 1 - distance / EXPOSURE_FALLOFF);
43
- }
44
-
45
- export {
46
- SHARP_REF,
47
- EXPOSURE_BAND,
48
- meanLuma,
49
- sharpness,
50
- exposure
51
- };
52
- //# sourceMappingURL=chunk-MWNFSNMP.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/v3/frame-quality.ts"],"sourcesContent":["// frame-quality (Task 8) — pure, deterministic image measures on a small\n// (≤96px) face crop. No canvas access here: callers hand in ImageData; that\n// keeps these functions golden-testable and worker-portable.\n\n/** Laplacian-variance normalization reference — crops whose edge variance\n * reaches this value (or beyond) count as fully sharp. */\nexport const SHARP_REF = 180;\n\n/** Mean-luma comfort band: inside → exposure 1; outside → linear falloff.\n * Dark bound raised 70→100 (operator ruling 2026-07-07): face crops in the\n * 70–100 range passed the gate but kept drawing dark-face review verdicts —\n * gating them here converts that into pre-capture more_light coaching. */\nexport const EXPOSURE_BAND: readonly [number, number] = [100, 190];\n\n/** Luma distance that zeroes the exposure factor (≈ one stop past the band). */\nconst EXPOSURE_FALLOFF = 64;\n\n/** Rec.601 luma. */\nfunction lumaAt(data: Uint8ClampedArray, index: number): number {\n return (\n 0.299 * (data[index] ?? 0) + 0.587 * (data[index + 1] ?? 0) + 0.114 * (data[index + 2] ?? 0)\n );\n}\n\nexport function meanLuma(image: ImageData): number {\n const { data, width, height } = image;\n const pixels = width * height;\n if (pixels === 0) return 0;\n let sum = 0;\n for (let i = 0; i < pixels; i += 1) sum += lumaAt(data, i * 4);\n return sum / pixels;\n}\n\n/**\n * Sharpness = variance of the 3×3 Laplacian (∇² kernel [0,1,0;1,−4,1;0,1,0])\n * over the interior pixels, normalized 0..1 against SHARP_REF. Flat crop → 0;\n * hard edges → 1 (clamped).\n */\nexport function sharpness(image: ImageData): number {\n const { data, width, height } = image;\n if (width < 3 || height < 3) return 0;\n const gray = new Float32Array(width * height);\n for (let i = 0; i < gray.length; i += 1) gray[i] = lumaAt(data, i * 4);\n let sum = 0;\n let sumSquares = 0;\n let count = 0;\n for (let y = 1; y < height - 1; y += 1) {\n for (let x = 1; x < width - 1; x += 1) {\n const i = y * width + x;\n const response =\n (gray[i - width] ?? 0) +\n (gray[i - 1] ?? 0) +\n (gray[i + 1] ?? 0) +\n (gray[i + width] ?? 0) -\n 4 * (gray[i] ?? 0);\n sum += response;\n sumSquares += response * response;\n count += 1;\n }\n }\n if (count === 0) return 0;\n const mean = sum / count;\n const variance = sumSquares / count - mean * mean;\n // VARIANCE against the reference (the plan's formula). Field lesson\n // (Salem's iPhone, 2026-07-07): sqrt(variance)/REF put every real face\n // crop at ~0.03-0.1 — permanently under the steady_camera threshold and\n // crushing q to zero, so the gate could never fire. Real crops have\n // Laplacian variance well above 180; a genuinely soft/blurred crop does not.\n return Math.min(1, Math.max(0, variance) / SHARP_REF);\n}\n\n/** Exposure factor: 1 inside the band; linear falloff to 0 over\n * EXPOSURE_FALLOFF luma outside it. */\nexport function exposure(image: ImageData): number {\n const mean = meanLuma(image);\n const [low, high] = EXPOSURE_BAND;\n const distance = mean < low ? low - mean : mean > high ? mean - high : 0;\n return Math.max(0, 1 - distance / EXPOSURE_FALLOFF);\n}\n"],"mappings":";AAMO,IAAM,YAAY;AAMlB,IAAM,gBAA2C,CAAC,KAAK,GAAG;AAGjE,IAAM,mBAAmB;AAGzB,SAAS,OAAO,MAAyB,OAAuB;AAC9D,SACE,SAAS,KAAK,KAAK,KAAK,KAAK,SAAS,KAAK,QAAQ,CAAC,KAAK,KAAK,SAAS,KAAK,QAAQ,CAAC,KAAK;AAE9F;AAEO,SAAS,SAAS,OAA0B;AACjD,QAAM,EAAE,MAAM,OAAO,OAAO,IAAI;AAChC,QAAM,SAAS,QAAQ;AACvB,MAAI,WAAW,EAAG,QAAO;AACzB,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK,EAAG,QAAO,OAAO,MAAM,IAAI,CAAC;AAC7D,SAAO,MAAM;AACf;AAOO,SAAS,UAAU,OAA0B;AAClD,QAAM,EAAE,MAAM,OAAO,OAAO,IAAI;AAChC,MAAI,QAAQ,KAAK,SAAS,EAAG,QAAO;AACpC,QAAM,OAAO,IAAI,aAAa,QAAQ,MAAM;AAC5C,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,EAAG,MAAK,CAAC,IAAI,OAAO,MAAM,IAAI,CAAC;AACrE,MAAI,MAAM;AACV,MAAI,aAAa;AACjB,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,SAAS,GAAG,KAAK,GAAG;AACtC,aAAS,IAAI,GAAG,IAAI,QAAQ,GAAG,KAAK,GAAG;AACrC,YAAM,IAAI,IAAI,QAAQ;AACtB,YAAM,YACH,KAAK,IAAI,KAAK,KAAK,MACnB,KAAK,IAAI,CAAC,KAAK,MACf,KAAK,IAAI,CAAC,KAAK,MACf,KAAK,IAAI,KAAK,KAAK,KACpB,KAAK,KAAK,CAAC,KAAK;AAClB,aAAO;AACP,oBAAc,WAAW;AACzB,eAAS;AAAA,IACX;AAAA,EACF;AACA,MAAI,UAAU,EAAG,QAAO;AACxB,QAAM,OAAO,MAAM;AACnB,QAAM,WAAW,aAAa,QAAQ,OAAO;AAM7C,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,QAAQ,IAAI,SAAS;AACtD;AAIO,SAAS,SAAS,OAA0B;AACjD,QAAM,OAAO,SAAS,KAAK;AAC3B,QAAM,CAAC,KAAK,IAAI,IAAI;AACpB,QAAM,WAAW,OAAO,MAAM,MAAM,OAAO,OAAO,OAAO,OAAO,OAAO;AACvE,SAAO,KAAK,IAAI,GAAG,IAAI,WAAW,gBAAgB;AACpD;","names":[]}
@@ -1,50 +0,0 @@
1
- // src/popup/index.ts
2
- var SEKYRO_EVENTS = [
3
- "session.completed",
4
- "session.failed",
5
- "session.review_pending",
6
- "session.expired",
7
- "session.cancelled"
8
- ];
9
- var WINDOW_NAME = "sekyro-verify";
10
- var WINDOW_FEATURES = "width=480,height=720,noopener=false";
11
- var EVENT_NAMES = new Set(SEKYRO_EVENTS);
12
- function isSekyroEvent(data) {
13
- if (data === null || typeof data !== "object") return false;
14
- const d = data;
15
- return d.source === "sekyro" && d.version === 1 && typeof d.sessionId === "string" && typeof d.event === "string" && EVENT_NAMES.has(d.event);
16
- }
17
- function open(opts) {
18
- const origin = new URL(opts.hostedUrl).origin;
19
- const popup = window.open(opts.hostedUrl, WINDOW_NAME, WINDOW_FEATURES);
20
- if (!popup) return { error: "popup_blocked" };
21
- const listener = (ev) => {
22
- if (ev.source !== popup) return;
23
- if (ev.origin !== origin) return;
24
- if (!isSekyroEvent(ev.data)) return;
25
- const { source, version, event, sessionId } = ev.data;
26
- opts.onEvent({ source, version, event, sessionId });
27
- };
28
- window.addEventListener("message", listener);
29
- return {
30
- close() {
31
- window.removeEventListener("message", listener);
32
- popup.close();
33
- }
34
- };
35
- }
36
- function openHosted(hostedUrl, opts) {
37
- if (opts.mode === "redirect") {
38
- window.location.assign(hostedUrl);
39
- return { close() {
40
- } };
41
- }
42
- return open({ hostedUrl, onEvent: opts.onEvent ?? (() => void 0) });
43
- }
44
-
45
- export {
46
- SEKYRO_EVENTS,
47
- open,
48
- openHosted
49
- };
50
- //# sourceMappingURL=chunk-NILNKLK6.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/popup/index.ts"],"sourcesContent":["// @sekyro/web/popup — the partner-facing popup embed wrapper\n// (Plan 6 Task 12). Framework-free browser code.\n//\n// REBRAND-CRITICAL WIRE CONTRACT (frozen on first partner integration):\n// - `source: 'sekyro'`, `version: 1`, window name `'sekyro-verify'`;\n// - event names mirror the webhook catalog (`session.completed` /\n// `session.failed` / `session.review_pending` / `session.expired`) plus the\n// page-only `session.cancelled` (user closed the popup mid-flow);\n// - payload is the event name + sessionId ONLY — never scores, PII, or\n// outcome detail (partners fetch the verdict server-side via API/webhooks).\n//\n// Security posture: the hosted page posts to the org's allowlisted origin\n// (backend `sdkAllowedOrigins`, surfaced as `HostedSessionView.sdkOrigin`) and\n// this listener double-checks BOTH the sender origin (must be the hosted URL's\n// origin) AND the message shape before forwarding anything to the partner.\n\n/** The frozen SDK event-name vocabulary, in catalog order. */\nexport const SEKYRO_EVENTS = [\n \"session.completed\",\n \"session.failed\",\n \"session.review_pending\",\n \"session.expired\",\n \"session.cancelled\",\n] as const;\n\n/** One SDK event name — webhook-catalog terminal names + `session.cancelled`. */\nexport type SekyroEventName = (typeof SEKYRO_EVENTS)[number];\n\n/** The frozen postMessage payload: event name + sessionId ONLY. */\nexport interface SekyroEvent {\n source: \"sekyro\";\n version: 1;\n event: SekyroEventName;\n sessionId: string;\n}\n\nexport interface OpenOptions {\n /** The `hosted_url` returned by `POST /api/v2/sessions` (create result). */\n hostedUrl: string;\n /** Called for every allowlist-validated event posted by the hosted page. */\n onEvent: (event: SekyroEvent) => void;\n}\n\n/** Live popup handle — `close()` detaches the listener and closes the window. */\nexport interface PopupHandle {\n close(): void;\n}\n\n/** `window.open` returned null: blocked by the browser (or a popup blocker). */\nexport interface PopupBlocked {\n error: \"popup_blocked\";\n}\n\n/** FROZEN window name — partners may target it (e.g. to re-focus the popup). */\nconst WINDOW_NAME = \"sekyro-verify\";\n\n/** Popup geometry; `noopener=false` keeps `window.opener` alive for the page's postMessage. */\nconst WINDOW_FEATURES = \"width=480,height=720,noopener=false\";\n\nconst EVENT_NAMES: ReadonlySet<string> = new Set(SEKYRO_EVENTS);\n\n/** True when the payload matches the frozen {@link SekyroEvent} shape exactly. */\nfunction isSekyroEvent(data: unknown): data is SekyroEvent {\n if (data === null || typeof data !== \"object\") return false;\n const d = data as Partial<SekyroEvent>;\n return (\n d.source === \"sekyro\" &&\n d.version === 1 &&\n typeof d.sessionId === \"string\" &&\n typeof d.event === \"string\" &&\n EVENT_NAMES.has(d.event)\n );\n}\n\n/**\n * Open the hosted verification flow in a popup and subscribe to its lifecycle\n * events. Incoming messages are dropped unless ALL hold:\n * - the sender window (`ev.source`) is THIS popup — closes the spoof path of\n * a same-origin iframe/window posting on the hosted origin's behalf\n * (`ev.source` is identity-stable across popup navigations);\n * - the sender origin is exactly the hosted URL's origin;\n * - the payload matches the frozen {@link SekyroEvent} shape (allowlisted\n * event name, string sessionId).\n *\n * Returns `{error: 'popup_blocked'}` when the browser refuses the popup —\n * callers should fall back to a full redirect to `hostedUrl`.\n *\n * Usage notes:\n * - ONE active popup per page: the window name is shared and every `open()`\n * installs a fresh listener, so `close()` the previous handle before\n * reopening (a reused named window would otherwise feed stale listeners).\n * - Events are at-least-once HINTS, not a system of record: a popup reload\n * mid-flow fires `session.cancelled`, and a reload after a terminal state\n * re-posts the terminal event — partners MUST confirm outcomes server-side\n * via webhooks or the sessions API.\n * - The popup `features` geometry is currently fixed ({@link WINDOW_FEATURES});\n * an options field for it is reserved for a later version.\n */\nexport function open(opts: OpenOptions): PopupHandle | PopupBlocked {\n const origin = new URL(opts.hostedUrl).origin;\n const popup = window.open(opts.hostedUrl, WINDOW_NAME, WINDOW_FEATURES);\n if (!popup) return { error: \"popup_blocked\" };\n\n const listener = (ev: MessageEvent): void => {\n if (ev.source !== popup) return;\n if (ev.origin !== origin) return;\n if (!isSekyroEvent(ev.data)) return;\n const { source, version, event, sessionId } = ev.data;\n // Re-project onto the frozen shape so extra properties never reach the partner.\n opts.onEvent({ source, version, event, sessionId });\n };\n window.addEventListener(\"message\", listener);\n\n return {\n close(): void {\n window.removeEventListener(\"message\", listener);\n popup.close();\n },\n };\n}\n\nexport interface OpenHostedOptions {\n /** `'popup'` opens a named window (the `open()` embed); `'redirect'` navigates this tab. */\n mode: \"popup\" | \"redirect\";\n /** Popup mode only — redirect mode never returns to this page. */\n onEvent?: (event: SekyroEvent) => void;\n}\n\n/**\n * Spec §3.1 entry: `openHosted(hostedUrl, { mode, onEvent })`. Popup mode is\n * the `open()` embed; a blocked popup returns `{error: 'popup_blocked'}` so the\n * caller can fall back to `mode: 'redirect'` (never done implicitly — leaving\n * the partner page is their call). Redirect mode navigates and returns a\n * no-op handle.\n */\nexport function openHosted(hostedUrl: string, opts: OpenHostedOptions): PopupHandle | PopupBlocked {\n if (opts.mode === \"redirect\") {\n window.location.assign(hostedUrl);\n return { close(): void {} };\n }\n return open({ hostedUrl, onEvent: opts.onEvent ?? (() => undefined) });\n}\n"],"mappings":";AAiBO,IAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AA+BA,IAAM,cAAc;AAGpB,IAAM,kBAAkB;AAExB,IAAM,cAAmC,IAAI,IAAI,aAAa;AAG9D,SAAS,cAAc,MAAoC;AACzD,MAAI,SAAS,QAAQ,OAAO,SAAS,SAAU,QAAO;AACtD,QAAM,IAAI;AACV,SACE,EAAE,WAAW,YACb,EAAE,YAAY,KACd,OAAO,EAAE,cAAc,YACvB,OAAO,EAAE,UAAU,YACnB,YAAY,IAAI,EAAE,KAAK;AAE3B;AA0BO,SAAS,KAAK,MAA+C;AAClE,QAAM,SAAS,IAAI,IAAI,KAAK,SAAS,EAAE;AACvC,QAAM,QAAQ,OAAO,KAAK,KAAK,WAAW,aAAa,eAAe;AACtE,MAAI,CAAC,MAAO,QAAO,EAAE,OAAO,gBAAgB;AAE5C,QAAM,WAAW,CAAC,OAA2B;AAC3C,QAAI,GAAG,WAAW,MAAO;AACzB,QAAI,GAAG,WAAW,OAAQ;AAC1B,QAAI,CAAC,cAAc,GAAG,IAAI,EAAG;AAC7B,UAAM,EAAE,QAAQ,SAAS,OAAO,UAAU,IAAI,GAAG;AAEjD,SAAK,QAAQ,EAAE,QAAQ,SAAS,OAAO,UAAU,CAAC;AAAA,EACpD;AACA,SAAO,iBAAiB,WAAW,QAAQ;AAE3C,SAAO;AAAA,IACL,QAAc;AACZ,aAAO,oBAAoB,WAAW,QAAQ;AAC9C,YAAM,MAAM;AAAA,IACd;AAAA,EACF;AACF;AAgBO,SAAS,WAAW,WAAmB,MAAqD;AACjG,MAAI,KAAK,SAAS,YAAY;AAC5B,WAAO,SAAS,OAAO,SAAS;AAChC,WAAO,EAAE,QAAc;AAAA,IAAC,EAAE;AAAA,EAC5B;AACA,SAAO,KAAK,EAAE,WAAW,SAAS,KAAK,YAAY,MAAM,QAAW,CAAC;AACvE;","names":[]}