@arkyc/liveness 1.0.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.
@@ -0,0 +1,19 @@
1
+ import { LivenessChallenge } from "@arkyc/types";
2
+
3
+ //#region src/challenges.d.ts
4
+ /** The full pool of active-liveness challenges the server can issue. */
5
+ declare const LIVENESS_CHALLENGE_POOL: readonly LivenessChallenge[];
6
+ /**
7
+ * Generate a randomized active-liveness challenge sequence of `count` distinct
8
+ * challenges (a partial Fisher–Yates shuffle of the pool). Issued per session so
9
+ * a recorded video can't be replayed against a different challenge order.
10
+ *
11
+ * @param count How many challenges to issue (clamped to the pool size).
12
+ * @param random Injectable RNG (defaults to `Math.random`); pass a seeded fn in tests.
13
+ */
14
+ declare function randomChallenges(count?: number, random?: () => number): LivenessChallenge[];
15
+ /** Whether the `performed` sequence exactly matches the `issued` one (order matters). */
16
+ declare function challengesMatch(issued: readonly LivenessChallenge[], performed: readonly LivenessChallenge[]): boolean;
17
+ //#endregion
18
+ export { LIVENESS_CHALLENGE_POOL, challengesMatch, randomChallenges };
19
+ //# sourceMappingURL=challenges.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"challenges.d.mts","names":[],"sources":["../src/challenges.ts"],"mappings":";;;;cAGa,uBAAA,WAAkC,iBAAiB;AAAhE;;;;AAAgE;AAiBhE;;;AAjBA,iBAiBgB,gBAAA,CAAiB,KAAA,WAAW,MAAA,kBAAqC,iBAAiB;;iBAUlF,eAAA,CACd,MAAA,WAAiB,iBAAA,IACjB,SAAA,WAAoB,iBAAiB"}
@@ -0,0 +1,34 @@
1
+ //#region src/challenges.ts
2
+ /** The full pool of active-liveness challenges the server can issue. */
3
+ const LIVENESS_CHALLENGE_POOL = [
4
+ "turn_left",
5
+ "turn_right",
6
+ "blink",
7
+ "smile",
8
+ "nod",
9
+ "move_closer"
10
+ ];
11
+ /**
12
+ * Generate a randomized active-liveness challenge sequence of `count` distinct
13
+ * challenges (a partial Fisher–Yates shuffle of the pool). Issued per session so
14
+ * a recorded video can't be replayed against a different challenge order.
15
+ *
16
+ * @param count How many challenges to issue (clamped to the pool size).
17
+ * @param random Injectable RNG (defaults to `Math.random`); pass a seeded fn in tests.
18
+ */
19
+ function randomChallenges(count = 3, random = Math.random) {
20
+ const pool = [...LIVENESS_CHALLENGE_POOL];
21
+ for (let i = pool.length - 1; i > 0; i -= 1) {
22
+ const j = Math.floor(random() * (i + 1));
23
+ [pool[i], pool[j]] = [pool[j], pool[i]];
24
+ }
25
+ return pool.slice(0, Math.max(0, Math.min(count, pool.length)));
26
+ }
27
+ /** Whether the `performed` sequence exactly matches the `issued` one (order matters). */
28
+ function challengesMatch(issued, performed) {
29
+ return issued.length > 0 && issued.length === performed.length && issued.every((challenge, index) => challenge === performed[index]);
30
+ }
31
+ //#endregion
32
+ export { LIVENESS_CHALLENGE_POOL, challengesMatch, randomChallenges };
33
+
34
+ //# sourceMappingURL=challenges.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"challenges.mjs","names":[],"sources":["../src/challenges.ts"],"sourcesContent":["import type { LivenessChallenge } from '@arkyc/types'\n\n/** The full pool of active-liveness challenges the server can issue. */\nexport const LIVENESS_CHALLENGE_POOL: readonly LivenessChallenge[] = [\n 'turn_left',\n 'turn_right',\n 'blink',\n 'smile',\n 'nod',\n 'move_closer',\n]\n\n/**\n * Generate a randomized active-liveness challenge sequence of `count` distinct\n * challenges (a partial Fisher–Yates shuffle of the pool). Issued per session so\n * a recorded video can't be replayed against a different challenge order.\n *\n * @param count How many challenges to issue (clamped to the pool size).\n * @param random Injectable RNG (defaults to `Math.random`); pass a seeded fn in tests.\n */\nexport function randomChallenges(count = 3, random: () => number = Math.random): LivenessChallenge[] {\n const pool = [...LIVENESS_CHALLENGE_POOL]\n for (let i = pool.length - 1; i > 0; i -= 1) {\n const j = Math.floor(random() * (i + 1))\n ;[pool[i], pool[j]] = [pool[j]!, pool[i]!]\n }\n return pool.slice(0, Math.max(0, Math.min(count, pool.length)))\n}\n\n/** Whether the `performed` sequence exactly matches the `issued` one (order matters). */\nexport function challengesMatch(\n issued: readonly LivenessChallenge[],\n performed: readonly LivenessChallenge[],\n): boolean {\n return (\n issued.length > 0 &&\n issued.length === performed.length &&\n issued.every((challenge, index) => challenge === performed[index])\n )\n}\n"],"mappings":";;AAGA,MAAa,0BAAwD;CACnE;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;;AAUA,SAAgB,iBAAiB,QAAQ,GAAG,SAAuB,KAAK,QAA6B;CACnG,MAAM,OAAO,CAAC,GAAG,uBAAuB;CACxC,KAAK,IAAI,IAAI,KAAK,SAAS,GAAG,IAAI,GAAG,KAAK,GAAG;EAC3C,MAAM,IAAI,KAAK,MAAM,OAAO,KAAK,IAAI,EAAE;EACtC,CAAC,KAAK,IAAI,KAAK,MAAM,CAAC,KAAK,IAAK,KAAK,EAAG;CAC3C;CACA,OAAO,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC;AAChE;;AAGA,SAAgB,gBACd,QACA,WACS;CACT,OACE,OAAO,SAAS,KAChB,OAAO,WAAW,UAAU,UAC5B,OAAO,OAAO,WAAW,UAAU,cAAc,UAAU,MAAM;AAErE"}
@@ -0,0 +1,17 @@
1
+ import { LivenessConfig, LivenessDriver, LivenessRequest } from "../types.mjs";
2
+ import { LivenessResultData } from "@arkyc/types";
3
+
4
+ //#region src/drivers/external.d.ts
5
+ /**
6
+ * Generic HTTP liveness driver: POSTs the base64 selfie to a configured
7
+ * endpoint and expects a {@link LivenessResultData}-shaped JSON response.
8
+ */
9
+ declare class ExternalLivenessDriver implements LivenessDriver {
10
+ private readonly config;
11
+ readonly name = "external";
12
+ constructor(config: LivenessConfig);
13
+ check(request: LivenessRequest): Promise<LivenessResultData>;
14
+ }
15
+ //#endregion
16
+ export { ExternalLivenessDriver };
17
+ //# sourceMappingURL=external.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external.d.mts","names":[],"sources":["../../src/drivers/external.ts"],"mappings":";;;;;;AAOA;;cAAa,sBAAA,YAAkC,cAAA;EAAA,iBAGhB,MAAA;EAAA,SAFpB,IAAA;cAEoB,MAAA,EAAQ,cAAA;EAI/B,KAAA,CAAM,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,kBAAA;AAAA"}
@@ -0,0 +1,29 @@
1
+ //#region src/drivers/external.ts
2
+ /**
3
+ * Generic HTTP liveness driver: POSTs the base64 selfie to a configured
4
+ * endpoint and expects a {@link LivenessResultData}-shaped JSON response.
5
+ */
6
+ var ExternalLivenessDriver = class {
7
+ config;
8
+ name = "external";
9
+ constructor(config) {
10
+ this.config = config;
11
+ if (!config.endpoint) throw new Error("ExternalLivenessDriver requires config.endpoint");
12
+ }
13
+ async check(request) {
14
+ const res = await fetch(this.config.endpoint, {
15
+ method: "POST",
16
+ headers: {
17
+ "content-type": "application/json",
18
+ ...this.config.apiKey ? { authorization: `Bearer ${this.config.apiKey}` } : {}
19
+ },
20
+ body: JSON.stringify({ selfie: Buffer.from(request.selfie).toString("base64") })
21
+ });
22
+ if (!res.ok) throw new Error(`ExternalLivenessDriver request failed with status ${res.status}`);
23
+ return await res.json();
24
+ }
25
+ };
26
+ //#endregion
27
+ export { ExternalLivenessDriver };
28
+
29
+ //# sourceMappingURL=external.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external.mjs","names":[],"sources":["../../src/drivers/external.ts"],"sourcesContent":["import type { LivenessResultData } from '@arkyc/types'\nimport type { LivenessConfig, LivenessDriver, LivenessRequest } from '../types'\n\n/**\n * Generic HTTP liveness driver: POSTs the base64 selfie to a configured\n * endpoint and expects a {@link LivenessResultData}-shaped JSON response.\n */\nexport class ExternalLivenessDriver implements LivenessDriver {\n readonly name = 'external'\n\n constructor(private readonly config: LivenessConfig) {\n if (!config.endpoint) throw new Error('ExternalLivenessDriver requires config.endpoint')\n }\n\n async check(request: LivenessRequest): Promise<LivenessResultData> {\n const res = await fetch(this.config.endpoint as string, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(this.config.apiKey ? { authorization: `Bearer ${this.config.apiKey}` } : {}),\n },\n body: JSON.stringify({ selfie: Buffer.from(request.selfie).toString('base64') }),\n })\n\n if (!res.ok) {\n throw new Error(`ExternalLivenessDriver request failed with status ${res.status}`)\n }\n\n return (await res.json()) as LivenessResultData\n }\n}\n"],"mappings":";;;;;AAOA,IAAa,yBAAb,MAA8D;CAG/B;CAF7B,OAAgB;CAEhB,YAAY,QAAyC;EAAxB,KAAA,SAAA;EAC3B,IAAI,CAAC,OAAO,UAAU,MAAM,IAAI,MAAM,iDAAiD;CACzF;CAEA,MAAM,MAAM,SAAuD;EACjE,MAAM,MAAM,MAAM,MAAM,KAAK,OAAO,UAAoB;GACtD,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,GAAI,KAAK,OAAO,SAAS,EAAE,eAAe,UAAU,KAAK,OAAO,SAAS,IAAI,CAAC;GAChF;GACA,MAAM,KAAK,UAAU,EAAE,QAAQ,OAAO,KAAK,QAAQ,MAAM,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC;EACjF,CAAC;EAED,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,MAAM,qDAAqD,IAAI,QAAQ;EAGnF,OAAQ,MAAM,IAAI,KAAK;CACzB;AACF"}
@@ -0,0 +1,17 @@
1
+ import { LivenessDriver, LivenessRequest } from "../types.mjs";
2
+ import { LivenessResultData } from "@arkyc/types";
3
+
4
+ //#region src/drivers/mock.d.ts
5
+ /**
6
+ * Deterministic liveness driver for development + tests. Passes by default;
7
+ * `hints` steer the score, verdict, and multiple-face spoof signal. In `active`
8
+ * mode it also requires the performed challenge sequence to match the one issued
9
+ * — a mismatch reads as a replay attempt and fails the check.
10
+ */
11
+ declare class MockLivenessDriver implements LivenessDriver {
12
+ readonly name = "mock";
13
+ check(request: LivenessRequest): Promise<LivenessResultData>;
14
+ }
15
+ //#endregion
16
+ export { MockLivenessDriver };
17
+ //# sourceMappingURL=mock.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.d.mts","names":[],"sources":["../../src/drivers/mock.ts"],"mappings":";;;;;;AAYA;;;;cAAa,kBAAA,YAA8B,cAAA;EAAA,SAChC,IAAA;EAEH,KAAA,CAAM,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,kBAAA;AAAA"}
@@ -0,0 +1,41 @@
1
+ import { challengesMatch } from "../challenges.mjs";
2
+ //#region src/drivers/mock.ts
3
+ const clamp01 = (n) => Math.min(1, Math.max(0, n));
4
+ /**
5
+ * Deterministic liveness driver for development + tests. Passes by default;
6
+ * `hints` steer the score, verdict, and multiple-face spoof signal. In `active`
7
+ * mode it also requires the performed challenge sequence to match the one issued
8
+ * — a mismatch reads as a replay attempt and fails the check.
9
+ */
10
+ var MockLivenessDriver = class {
11
+ name = "mock";
12
+ async check(request) {
13
+ const score = clamp01(request.hints?.score ?? .94);
14
+ let passed = request.hints?.passed ?? score >= .5;
15
+ const active = request.mode === "active";
16
+ const sequenceOk = active ? challengesMatch(request.challenges ?? [], request.performedChallenges ?? []) : true;
17
+ if (active && !sequenceOk) passed = false;
18
+ return {
19
+ passed,
20
+ score: sequenceOk ? score : Math.min(score, .3),
21
+ spoofSignals: {
22
+ screenReplay: active && !sequenceOk,
23
+ printedPhoto: false,
24
+ maskDetected: false,
25
+ multipleFaces: request.hints?.multipleFaces ?? false,
26
+ faceNotCentered: false,
27
+ poorLighting: false
28
+ },
29
+ raw: {
30
+ provider: "mock",
31
+ score,
32
+ mode: request.mode ?? "passive",
33
+ sequenceOk
34
+ }
35
+ };
36
+ }
37
+ };
38
+ //#endregion
39
+ export { MockLivenessDriver };
40
+
41
+ //# sourceMappingURL=mock.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.mjs","names":[],"sources":["../../src/drivers/mock.ts"],"sourcesContent":["import type { LivenessResultData } from '@arkyc/types'\nimport type { LivenessDriver, LivenessRequest } from '../types'\nimport { challengesMatch } from '../challenges'\n\nconst clamp01 = (n: number): number => Math.min(1, Math.max(0, n))\n\n/**\n * Deterministic liveness driver for development + tests. Passes by default;\n * `hints` steer the score, verdict, and multiple-face spoof signal. In `active`\n * mode it also requires the performed challenge sequence to match the one issued\n * — a mismatch reads as a replay attempt and fails the check.\n */\nexport class MockLivenessDriver implements LivenessDriver {\n readonly name = 'mock'\n\n async check(request: LivenessRequest): Promise<LivenessResultData> {\n const score = clamp01(request.hints?.score ?? 0.94)\n let passed = request.hints?.passed ?? score >= 0.5\n\n // Active liveness: the recorded challenge order must match what was issued.\n const active = request.mode === 'active'\n const sequenceOk = active ? challengesMatch(request.challenges ?? [], request.performedChallenges ?? []) : true\n if (active && !sequenceOk) passed = false\n\n return {\n passed,\n score: sequenceOk ? score : Math.min(score, 0.3),\n spoofSignals: {\n screenReplay: active && !sequenceOk,\n printedPhoto: false,\n maskDetected: false,\n multipleFaces: request.hints?.multipleFaces ?? false,\n faceNotCentered: false,\n poorLighting: false,\n },\n raw: { provider: 'mock', score, mode: request.mode ?? 'passive', sequenceOk },\n }\n }\n}\n"],"mappings":";;AAIA,MAAM,WAAW,MAAsB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;;;;;;;AAQjE,IAAa,qBAAb,MAA0D;CACxD,OAAgB;CAEhB,MAAM,MAAM,SAAuD;EACjE,MAAM,QAAQ,QAAQ,QAAQ,OAAO,SAAS,GAAI;EAClD,IAAI,SAAS,QAAQ,OAAO,UAAU,SAAS;EAG/C,MAAM,SAAS,QAAQ,SAAS;EAChC,MAAM,aAAa,SAAS,gBAAgB,QAAQ,cAAc,CAAC,GAAG,QAAQ,uBAAuB,CAAC,CAAC,IAAI;EAC3G,IAAI,UAAU,CAAC,YAAY,SAAS;EAEpC,OAAO;GACL;GACA,OAAO,aAAa,QAAQ,KAAK,IAAI,OAAO,EAAG;GAC/C,cAAc;IACZ,cAAc,UAAU,CAAC;IACzB,cAAc;IACd,cAAc;IACd,eAAe,QAAQ,OAAO,iBAAiB;IAC/C,iBAAiB;IACjB,cAAc;GAChB;GACA,KAAK;IAAE,UAAU;IAAQ;IAAO,MAAM,QAAQ,QAAQ;IAAW;GAAW;EAC9E;CACF;AACF"}
@@ -0,0 +1,6 @@
1
+ import { LivenessConfig, LivenessDriver, LivenessDriverName, LivenessRequest } from "./types.mjs";
2
+ import { LivenessDriverFactory } from "./registry.mjs";
3
+ import { LIVENESS_CHALLENGE_POOL, challengesMatch, randomChallenges } from "./challenges.mjs";
4
+ import { MockLivenessDriver } from "./drivers/mock.mjs";
5
+ import { ExternalLivenessDriver } from "./drivers/external.mjs";
6
+ export { ExternalLivenessDriver, LIVENESS_CHALLENGE_POOL, LivenessConfig, LivenessDriver, LivenessDriverFactory, LivenessDriverName, LivenessRequest, MockLivenessDriver, challengesMatch, randomChallenges };
package/dist/index.mjs ADDED
@@ -0,0 +1,5 @@
1
+ import { ExternalLivenessDriver } from "./drivers/external.mjs";
2
+ import { LIVENESS_CHALLENGE_POOL, challengesMatch, randomChallenges } from "./challenges.mjs";
3
+ import { MockLivenessDriver } from "./drivers/mock.mjs";
4
+ import { LivenessDriverFactory } from "./registry.mjs";
5
+ export { ExternalLivenessDriver, LIVENESS_CHALLENGE_POOL, LivenessDriverFactory, MockLivenessDriver, challengesMatch, randomChallenges };
@@ -0,0 +1,18 @@
1
+ import { LivenessConfig, LivenessDriver } from "./types.mjs";
2
+
3
+ //#region src/registry.d.ts
4
+ /**
5
+ * Selects a liveness driver from config.
6
+ */
7
+ declare class LivenessDriverFactory {
8
+ /**
9
+ * Resolve the liveness driver named by `config`.
10
+ *
11
+ * @param config
12
+ * @returns
13
+ */
14
+ static create(config: LivenessConfig): LivenessDriver;
15
+ }
16
+ //#endregion
17
+ export { LivenessDriverFactory };
18
+ //# sourceMappingURL=registry.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.mts","names":[],"sources":["../src/registry.ts"],"mappings":";;;;;AAQA;cAAa,qBAAA;;;;;;;SAOJ,MAAA,CAAO,MAAA,EAAQ,cAAA,GAAiB,cAAc;AAAA"}
@@ -0,0 +1,25 @@
1
+ import { ExternalLivenessDriver } from "./drivers/external.mjs";
2
+ import { MockLivenessDriver } from "./drivers/mock.mjs";
3
+ //#region src/registry.ts
4
+ /**
5
+ * Selects a liveness driver from config.
6
+ */
7
+ var LivenessDriverFactory = class {
8
+ /**
9
+ * Resolve the liveness driver named by `config`.
10
+ *
11
+ * @param config
12
+ * @returns
13
+ */
14
+ static create(config) {
15
+ switch (config.driver) {
16
+ case "mock": return new MockLivenessDriver();
17
+ case "external": return new ExternalLivenessDriver(config);
18
+ default: throw new Error(`Unknown liveness driver: ${config.driver}`);
19
+ }
20
+ }
21
+ };
22
+ //#endregion
23
+ export { LivenessDriverFactory };
24
+
25
+ //# sourceMappingURL=registry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.mjs","names":[],"sources":["../src/registry.ts"],"sourcesContent":["import type { LivenessConfig, LivenessDriver } from './types'\n\nimport { ExternalLivenessDriver } from './drivers/external'\nimport { MockLivenessDriver } from './drivers/mock'\n\n/**\n * Selects a liveness driver from config.\n */\nexport class LivenessDriverFactory {\n /**\n * Resolve the liveness driver named by `config`.\n *\n * @param config\n * @returns\n */\n static create(config: LivenessConfig): LivenessDriver {\n switch (config.driver) {\n case 'mock':\n return new MockLivenessDriver()\n case 'external':\n return new ExternalLivenessDriver(config)\n default:\n throw new Error(`Unknown liveness driver: ${(config as LivenessConfig).driver}`)\n }\n }\n}\n"],"mappings":";;;;;;AAQA,IAAa,wBAAb,MAAmC;;;;;;;CAOjC,OAAO,OAAO,QAAwC;EACpD,QAAQ,OAAO,QAAf;GACE,KAAK,QACH,OAAO,IAAI,mBAAmB;GAChC,KAAK,YACH,OAAO,IAAI,uBAAuB,MAAM;GAC1C,SACE,MAAM,IAAI,MAAM,4BAA6B,OAA0B,QAAQ;EACnF;CACF;AACF"}
@@ -0,0 +1,41 @@
1
+ import { LivenessChallenge, LivenessMode, LivenessResultData } from "@arkyc/types";
2
+
3
+ //#region src/types.d.ts
4
+ /** The selfie/video bytes + context handed to a liveness driver. */
5
+ interface LivenessRequest {
6
+ /** Raw selfie frame bytes. */
7
+ selfie: Uint8Array;
8
+ /** Optional short liveness video bytes (active mode). */
9
+ video?: Uint8Array | null;
10
+ /** Passive (selfie) or active (challenge video). Defaults to passive. */
11
+ mode?: LivenessMode;
12
+ /** The challenge sequence the server issued for this session (active mode). */
13
+ challenges?: readonly LivenessChallenge[];
14
+ /** The challenge sequence the client reports having performed (active mode). */
15
+ performedChallenges?: readonly LivenessChallenge[];
16
+ /**
17
+ * Optional deterministic signals (used by the `mock` driver and tests to
18
+ * steer the score / verdict). Ignored by real drivers.
19
+ */
20
+ hints?: {
21
+ score?: number;
22
+ passed?: boolean;
23
+ multipleFaces?: boolean;
24
+ };
25
+ }
26
+ /** A pluggable liveness provider (passive selfie or active challenge video). */
27
+ interface LivenessDriver {
28
+ readonly name: string;
29
+ check(request: LivenessRequest): Promise<LivenessResultData>;
30
+ }
31
+ /** Identifier for a registered liveness driver. */
32
+ type LivenessDriverName = 'mock' | 'external';
33
+ /** Configuration selecting + parameterising the active liveness driver. */
34
+ interface LivenessConfig {
35
+ driver: LivenessDriverName;
36
+ endpoint?: string;
37
+ apiKey?: string;
38
+ }
39
+ //#endregion
40
+ export { LivenessConfig, LivenessDriver, LivenessDriverName, LivenessRequest };
41
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;UAGiB,eAAA;EAAA;EAEf,MAAA,EAAQ,UAAA;;EAER,KAAA,GAAQ,UAAA;EAAA;EAER,IAAA,GAAO,YAAA;EAEe;EAAtB,UAAA,YAAsB,iBAAA;EAE0B;EAAhD,mBAAA,YAA+B,iBAAA;EAR/B;;;;EAaA,KAAA;IAAU,KAAA;IAAgB,MAAA;IAAkB,aAAA;EAAA;AAAA;;UAI7B,cAAA;EAAA,SACN,IAAA;EACT,KAAA,CAAM,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,kBAAA;AAAA;AANgB;AAAA,KAU/C,kBAAA;;UAGK,cAAA;EACf,MAAA,EAAQ,kBAAkB;EAC1B,QAAA;EACA,MAAA;AAAA"}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@arkyc/liveness",
3
+ "version": "1.0.0",
4
+ "description": "Driver-based passive liveness detection",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.mjs",
8
+ "module": "./dist/index.mjs",
9
+ "types": "./dist/index.d.mts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.mts",
13
+ "import": "./dist/index.mjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "dependencies": {
20
+ "@arkyc/types": "^1.0.0"
21
+ },
22
+ "scripts": {
23
+ "typecheck": "tsc --noEmit",
24
+ "test": "vitest run",
25
+ "lint": "eslint src",
26
+ "clean": "rm -rf dist"
27
+ }
28
+ }