@edgeproc/privacy-core 0.2.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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +190 -0
  3. package/dist/detect/checksums.d.ts +5 -0
  4. package/dist/detect/checksums.d.ts.map +1 -0
  5. package/dist/detect/checksums.js +37 -0
  6. package/dist/detect/checksums.js.map +1 -0
  7. package/dist/detect/detector.d.ts +12 -0
  8. package/dist/detect/detector.d.ts.map +1 -0
  9. package/dist/detect/detector.js +57 -0
  10. package/dist/detect/detector.js.map +1 -0
  11. package/dist/detect/patterns.d.ts +22 -0
  12. package/dist/detect/patterns.d.ts.map +1 -0
  13. package/dist/detect/patterns.js +40 -0
  14. package/dist/detect/patterns.js.map +1 -0
  15. package/dist/egress.d.ts +85 -0
  16. package/dist/egress.d.ts.map +1 -0
  17. package/dist/egress.js +115 -0
  18. package/dist/egress.js.map +1 -0
  19. package/dist/egressReceipt.d.ts +67 -0
  20. package/dist/egressReceipt.d.ts.map +1 -0
  21. package/dist/egressReceipt.js +41 -0
  22. package/dist/egressReceipt.js.map +1 -0
  23. package/dist/errors.d.ts +62 -0
  24. package/dist/errors.d.ts.map +1 -0
  25. package/dist/errors.js +80 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/index.d.ts +24 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +29 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/providers/factory.d.ts +20 -0
  32. package/dist/providers/factory.d.ts.map +1 -0
  33. package/dist/providers/factory.js +27 -0
  34. package/dist/providers/factory.js.map +1 -0
  35. package/dist/providers/nollm.d.ts +12 -0
  36. package/dist/providers/nollm.d.ts.map +1 -0
  37. package/dist/providers/nollm.js +28 -0
  38. package/dist/providers/nollm.js.map +1 -0
  39. package/dist/providers/openrouter.d.ts +18 -0
  40. package/dist/providers/openrouter.d.ts.map +1 -0
  41. package/dist/providers/openrouter.js +43 -0
  42. package/dist/providers/openrouter.js.map +1 -0
  43. package/dist/redact.d.ts +14 -0
  44. package/dist/redact.d.ts.map +1 -0
  45. package/dist/redact.js +79 -0
  46. package/dist/redact.js.map +1 -0
  47. package/dist/rehydrate.d.ts +21 -0
  48. package/dist/rehydrate.d.ts.map +1 -0
  49. package/dist/rehydrate.js +36 -0
  50. package/dist/rehydrate.js.map +1 -0
  51. package/dist/testing.d.ts +14 -0
  52. package/dist/testing.d.ts.map +1 -0
  53. package/dist/testing.js +31 -0
  54. package/dist/testing.js.map +1 -0
  55. package/dist/types.d.ts +27 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +2 -0
  58. package/dist/types.js.map +1 -0
  59. package/dist/vault.d.ts +21 -0
  60. package/dist/vault.d.ts.map +1 -0
  61. package/dist/vault.js +38 -0
  62. package/dist/vault.js.map +1 -0
  63. package/package.json +54 -0
@@ -0,0 +1,21 @@
1
+ import type { VaultRef } from "./types.js";
2
+ import type { Vault } from "./vault.js";
3
+ /**
4
+ * Restore real values locally: walk every [TYPE_n] placeholder in the text and
5
+ * swap in its raw value from the vault. This is the close of the loop — it runs
6
+ * on-device, after the provider replied, so the real values are restored
7
+ * without ever having crossed the wire.
8
+ *
9
+ * Vault binding is MANDATORY: pass the payload's `vaultRef` so the restore is
10
+ * bound to the vault the text was actually redacted with. This fails closed in
11
+ * two ways instead of ever silently substituting a wrong value:
12
+ *
13
+ * - Wrong vault → {@link VaultMismatchError}. Without the binding, an
14
+ * overlapping `[NAME_1]`/`[CARD_1]` from a *different* vault would resolve to
15
+ * the wrong person's real value.
16
+ * - A placeholder the bound vault cannot resolve → {@link
17
+ * UnresolvedPlaceholderError}. A model-invented `[CARD_9]`, or text redacted
18
+ * with another vault, is an anomaly — stop, don't leave a lookalike token.
19
+ */
20
+ export declare function rehydrate(redactedText: string, vault: Vault, expectedRef: VaultRef): string;
21
+ //# sourceMappingURL=rehydrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehydrate.d.ts","sourceRoot":"","sources":["../src/rehydrate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAKxC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CACvB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,QAAQ,GACpB,MAAM,CAkBR"}
@@ -0,0 +1,36 @@
1
+ import { UnresolvedPlaceholderError, VaultMismatchError } from "./errors.js";
2
+ /** The placeholder grammar `rehydrate` restores (same shape `redact` mints). */
3
+ const PLACEHOLDER = /\[[A-Z]+_\d+\]/g;
4
+ /**
5
+ * Restore real values locally: walk every [TYPE_n] placeholder in the text and
6
+ * swap in its raw value from the vault. This is the close of the loop — it runs
7
+ * on-device, after the provider replied, so the real values are restored
8
+ * without ever having crossed the wire.
9
+ *
10
+ * Vault binding is MANDATORY: pass the payload's `vaultRef` so the restore is
11
+ * bound to the vault the text was actually redacted with. This fails closed in
12
+ * two ways instead of ever silently substituting a wrong value:
13
+ *
14
+ * - Wrong vault → {@link VaultMismatchError}. Without the binding, an
15
+ * overlapping `[NAME_1]`/`[CARD_1]` from a *different* vault would resolve to
16
+ * the wrong person's real value.
17
+ * - A placeholder the bound vault cannot resolve → {@link
18
+ * UnresolvedPlaceholderError}. A model-invented `[CARD_9]`, or text redacted
19
+ * with another vault, is an anomaly — stop, don't leave a lookalike token.
20
+ */
21
+ export function rehydrate(redactedText, vault, expectedRef) {
22
+ if (vault.ref.id !== expectedRef.id) {
23
+ throw new VaultMismatchError(`vault "${vault.ref.id}" does not match the payload's vault ` +
24
+ `"${expectedRef.id}" — restoring with the wrong vault yields wrong values`);
25
+ }
26
+ return redactedText.replace(PLACEHOLDER, (token) => {
27
+ const value = vault.resolve(token);
28
+ if (value === undefined) {
29
+ throw new UnresolvedPlaceholderError(`placeholder ${token} is not in vault "${vault.ref.id}" — under a bound ` +
30
+ "vault an unresolvable token is an anomaly (a model-invented token, or " +
31
+ "text redacted with a different vault), so rehydrate fails closed");
32
+ }
33
+ return value;
34
+ });
35
+ }
36
+ //# sourceMappingURL=rehydrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehydrate.js","sourceRoot":"","sources":["../src/rehydrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAI7E,gFAAgF;AAChF,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAEtC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,SAAS,CACvB,YAAoB,EACpB,KAAY,EACZ,WAAqB;IAErB,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,WAAW,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,kBAAkB,CAC1B,UAAU,KAAK,CAAC,GAAG,CAAC,EAAE,uCAAuC;YAC3D,IAAI,WAAW,CAAC,EAAE,wDAAwD,CAC7E,CAAC;IACJ,CAAC;IACD,OAAO,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,0BAA0B,CAClC,eAAe,KAAK,qBAAqB,KAAK,CAAC,GAAG,CAAC,EAAE,oBAAoB;gBACvE,wEAAwE;gBACxE,kEAAkE,CACrE,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Test-only fixtures, exposed via the `@edgeproc/privacy-core/testing` subpath.
3
+ * These are NOT part of the production barrel — keep synthetic data out of the
4
+ * front door so consumers never ship a fixture by accident.
5
+ */
6
+ /**
7
+ * SYNTHETIC, INVENTED bank statement. Contains NO real PII.
8
+ * - Card 4242…4242 is the canonical Stripe test card (Luhn-valid, not issued).
9
+ * - IBAN GB82 WEST… is the public mod-97 IBAN example from Wikipedia.
10
+ * - SSN 123-45-6789 is a textbook placeholder.
11
+ * - Routing 021000021 is a published ABA test routing number (JPMorgan Chase).
12
+ */
13
+ export declare const SYNTHETIC_STATEMENT = "MONTHLY STATEMENT \u2014 FIRST INVENTED BANK\n\nAccount holder: Ada Lovelace\nEmail: ada.lovelace@example.com\nPhone: (415) 555-0132\nSSN on file: 123-45-6789\n\nAccount number: 000123456789\nRouting number: 021000021\nLinked IBAN: GB82 WEST 1234 5698 7654 32\nCard on file: 4242 4242 4242 4242\n\nTransactions:\n 01/05/2026 Whole Foods $1,482.10\n 01/09/2026 Starbucks $7.45\n 01/14/2026 Amazon $329.00\n\nPlease review the charge to Whole Foods.";
14
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,sfAiBS,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Test-only fixtures, exposed via the `@edgeproc/privacy-core/testing` subpath.
3
+ * These are NOT part of the production barrel — keep synthetic data out of the
4
+ * front door so consumers never ship a fixture by accident.
5
+ */
6
+ /**
7
+ * SYNTHETIC, INVENTED bank statement. Contains NO real PII.
8
+ * - Card 4242…4242 is the canonical Stripe test card (Luhn-valid, not issued).
9
+ * - IBAN GB82 WEST… is the public mod-97 IBAN example from Wikipedia.
10
+ * - SSN 123-45-6789 is a textbook placeholder.
11
+ * - Routing 021000021 is a published ABA test routing number (JPMorgan Chase).
12
+ */
13
+ export const SYNTHETIC_STATEMENT = `MONTHLY STATEMENT — FIRST INVENTED BANK
14
+
15
+ Account holder: Ada Lovelace
16
+ Email: ada.lovelace@example.com
17
+ Phone: (415) 555-0132
18
+ SSN on file: 123-45-6789
19
+
20
+ Account number: 000123456789
21
+ Routing number: 021000021
22
+ Linked IBAN: GB82 WEST 1234 5698 7654 32
23
+ Card on file: 4242 4242 4242 4242
24
+
25
+ Transactions:
26
+ 01/05/2026 Whole Foods $1,482.10
27
+ 01/09/2026 Starbucks $7.45
28
+ 01/14/2026 Amazon $329.00
29
+
30
+ Please review the charge to Whole Foods.`;
31
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;yCAiBM,CAAC"}
@@ -0,0 +1,27 @@
1
+ /** The PII categories the Tier-1 deterministic detector recognizes. */
2
+ export type EntityType = "CARD" | "IBAN" | "SSN" | "EMAIL" | "PHONE" | "ACCOUNT" | "ROUTING" | "AMOUNT" | "DATE" | "NAME" | "MERCHANT";
3
+ /** A detected PII span in the source text. */
4
+ export interface Span {
5
+ readonly type: EntityType;
6
+ readonly value: string;
7
+ readonly start: number;
8
+ readonly end: number;
9
+ }
10
+ /** Opaque handle to a vault holding token -> raw-value mappings. */
11
+ export interface VaultRef {
12
+ readonly id: string;
13
+ }
14
+ /** An audit record — metadata only, never raw PII (except the explicit bypass case). */
15
+ export interface AuditEntry {
16
+ readonly kind: "redact" | "approve" | "unsafe-bypass";
17
+ readonly at: number;
18
+ readonly placeholders?: readonly string[];
19
+ readonly reason?: string;
20
+ }
21
+ /** A sink the caller supplies to receive append-only audit entries. */
22
+ export type AuditSink = (entry: AuditEntry) => void;
23
+ /** A provider's reply, still in placeholder form until rehydrated locally. */
24
+ export interface RedactedResponse {
25
+ readonly redactedText: string;
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,MAAM,GACN,KAAK,GACL,OAAO,GACP,OAAO,GACP,SAAS,GACT,SAAS,GACT,QAAQ,GACR,MAAM,GACN,MAAM,GACN,UAAU,CAAC;AAEf,8CAA8C;AAC9C,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,oEAAoE;AACpE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,wFAAwF;AACxF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,eAAe,CAAC;IACtD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,uEAAuE;AACvE,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;AAEpD,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import type { EntityType, VaultRef } from "./types.js";
2
+ /**
3
+ * In-memory reversible token<->value map (v0 scope).
4
+ *
5
+ * Stable placeholders: the same raw value always maps to the same token, and
6
+ * each entity type gets its own counter ([CARD_1], [NAME_2], ...). The encrypted
7
+ * IndexedDB vault (AES-GCM + passphrase KDF) is deferred — see Roadmap. This v0
8
+ * vault is in-memory and clears on reload, by design.
9
+ */
10
+ export declare class Vault {
11
+ readonly ref: VaultRef;
12
+ private readonly tokenForValue;
13
+ private readonly valueForToken;
14
+ private readonly counters;
15
+ constructor();
16
+ /** Return the stable placeholder for a (type, value), minting one on first sight. */
17
+ tokenize(type: EntityType, value: string): string;
18
+ /** Resolve a placeholder back to its raw value, or undefined if unknown. */
19
+ resolve(token: string): string | undefined;
20
+ }
21
+ //# sourceMappingURL=vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAIvD;;;;;;;GAOG;AACH,qBAAa,KAAK;IAChB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAE1D,cAIC;IAED,qFAAqF;IACrF,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUhD;IAED,4EAA4E;IAC5E,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEzC;CACF"}
package/dist/vault.js ADDED
@@ -0,0 +1,38 @@
1
+ let nextVaultId = 1;
2
+ /**
3
+ * In-memory reversible token<->value map (v0 scope).
4
+ *
5
+ * Stable placeholders: the same raw value always maps to the same token, and
6
+ * each entity type gets its own counter ([CARD_1], [NAME_2], ...). The encrypted
7
+ * IndexedDB vault (AES-GCM + passphrase KDF) is deferred — see Roadmap. This v0
8
+ * vault is in-memory and clears on reload, by design.
9
+ */
10
+ export class Vault {
11
+ ref;
12
+ tokenForValue = new Map();
13
+ valueForToken = new Map();
14
+ counters = new Map();
15
+ constructor() {
16
+ // Frozen: `payload.vaultRef` aliases this object, so the rehydrate binding
17
+ // (VaultMismatchError) cannot be defeated by rewriting the id after the fact.
18
+ this.ref = Object.freeze({ id: `vault-${nextVaultId++}` });
19
+ }
20
+ /** Return the stable placeholder for a (type, value), minting one on first sight. */
21
+ tokenize(type, value) {
22
+ const key = `${type}::${value}`;
23
+ const existing = this.tokenForValue.get(key);
24
+ if (existing)
25
+ return existing;
26
+ const n = (this.counters.get(type) ?? 0) + 1;
27
+ this.counters.set(type, n);
28
+ const token = `[${type}_${n}]`;
29
+ this.tokenForValue.set(key, token);
30
+ this.valueForToken.set(token, value);
31
+ return token;
32
+ }
33
+ /** Resolve a placeholder back to its raw value, or undefined if unknown. */
34
+ resolve(token) {
35
+ return this.valueForToken.get(token);
36
+ }
37
+ }
38
+ //# sourceMappingURL=vault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.js","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"AAEA,IAAI,WAAW,GAAG,CAAC,CAAC;AAEpB;;;;;;;GAOG;AACH,MAAM,OAAO,KAAK;IACP,GAAG,CAAW;IACN,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,QAAQ,GAAG,IAAI,GAAG,EAAsB,CAAC;IAE1D;QACE,2EAA2E;QAC3E,8EAA8E;QAC9E,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,SAAS,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,qFAAqF;IACrF,QAAQ,CAAC,IAAgB,EAAE,KAAa;QACtC,MAAM,GAAG,GAAG,GAAG,IAAI,KAAK,KAAK,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3B,MAAM,KAAK,GAAG,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACrC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,4EAA4E;IAC5E,OAAO,CAAC,KAAa;QACnB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@edgeproc/privacy-core",
3
+ "version": "0.2.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "type": "module",
8
+ "description": "A browser-side privacy boundary for LLM calls: redact on-device, send only placeholders, rehydrate locally — enforced by a type-checked Egress Guard.",
9
+ "license": "MIT",
10
+ "author": "Harish Seshadri",
11
+ "packageManager": "pnpm@11.5.0",
12
+ "engines": {
13
+ "node": ">=22.13"
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "main": "./dist/index.js",
19
+ "module": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
25
+ },
26
+ "./testing": {
27
+ "types": "./dist/testing.d.ts",
28
+ "import": "./dist/testing.js"
29
+ }
30
+ },
31
+ "sideEffects": false,
32
+ "dependencies": {
33
+ "@edgeproc/avow": "^0.1.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.build.json",
37
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p examples/demo/tsconfig.json --noEmit",
38
+ "test": "vitest run --coverage",
39
+ "test:watch": "vitest",
40
+ "test:e2e": "playwright test",
41
+ "lint": "biome check .",
42
+ "lint:fix": "biome check --write .",
43
+ "demo": "pnpm --filter @edgeproc/privacy-core-demo dev",
44
+ "gate": "pnpm lint && pnpm typecheck && pnpm test && pnpm test:e2e && pnpm build"
45
+ },
46
+ "devDependencies": {
47
+ "@biomejs/biome": "^2.4.16",
48
+ "@playwright/test": "^1.60.0",
49
+ "@types/node": "^26.1.1",
50
+ "@vitest/coverage-v8": "^4.1.7",
51
+ "typescript": "^7.0.2",
52
+ "vitest": "^4.1.7"
53
+ }
54
+ }