@tinycloud/sdk-services 3.2.6-beta.2 → 3.3.0-beta.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 (65) hide show
  1. package/dist/{BaseService-4wwJq1Gn.d.cts → BaseService-Cc6Ueicm.d.cts} +1 -1
  2. package/dist/{BaseService-BGr2slUz.d.ts → BaseService-DOdXd7sr.d.ts} +1 -1
  3. package/dist/encryption/index.cjs +10 -0
  4. package/dist/encryption/index.cjs.map +1 -1
  5. package/dist/encryption/index.d.cts +2 -2
  6. package/dist/encryption/index.d.ts +2 -2
  7. package/dist/encryption/index.js +10 -0
  8. package/dist/encryption/index.js.map +1 -1
  9. package/dist/index.cjs +109 -64
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +38 -12
  12. package/dist/index.d.ts +38 -12
  13. package/dist/index.js +108 -64
  14. package/dist/index.js.map +1 -1
  15. package/dist/internal/decrypt-transport-response-error.d.cts +1 -1
  16. package/dist/internal/decrypt-transport-response-error.d.ts +1 -1
  17. package/dist/kv/index.cjs +68 -21
  18. package/dist/kv/index.cjs.map +1 -1
  19. package/dist/kv/index.d.cts +7 -4
  20. package/dist/kv/index.d.ts +7 -4
  21. package/dist/kv/index.js +68 -21
  22. package/dist/kv/index.js.map +1 -1
  23. package/dist/kv/replication/contractConstants.cjs +115 -0
  24. package/dist/kv/replication/contractConstants.cjs.map +1 -0
  25. package/dist/kv/replication/contractConstants.d.cts +77 -0
  26. package/dist/kv/replication/contractConstants.d.ts +77 -0
  27. package/dist/kv/replication/contractConstants.js +75 -0
  28. package/dist/kv/replication/contractConstants.js.map +1 -0
  29. package/dist/kv/replication/grantPolicy.cjs +82 -0
  30. package/dist/kv/replication/grantPolicy.cjs.map +1 -0
  31. package/dist/kv/replication/grantPolicy.d.cts +19 -0
  32. package/dist/kv/replication/grantPolicy.d.ts +19 -0
  33. package/dist/kv/replication/grantPolicy.js +50 -0
  34. package/dist/kv/replication/grantPolicy.js.map +1 -0
  35. package/dist/kv/replication/grantPolicyConstants.cjs +42 -0
  36. package/dist/kv/replication/grantPolicyConstants.cjs.map +1 -0
  37. package/dist/kv/replication/grantPolicyConstants.d.cts +10 -0
  38. package/dist/kv/replication/grantPolicyConstants.d.ts +10 -0
  39. package/dist/kv/replication/grantPolicyConstants.js +14 -0
  40. package/dist/kv/replication/grantPolicyConstants.js.map +1 -0
  41. package/dist/kv/replication/grantPolicyTypes.cjs +19 -0
  42. package/dist/kv/replication/grantPolicyTypes.cjs.map +1 -0
  43. package/dist/kv/replication/grantPolicyTypes.d.cts +87 -0
  44. package/dist/kv/replication/grantPolicyTypes.d.ts +87 -0
  45. package/dist/kv/replication/grantPolicyTypes.js +1 -0
  46. package/dist/kv/replication/grantPolicyTypes.js.map +1 -0
  47. package/dist/kv/replication/index.cjs +575 -131
  48. package/dist/kv/replication/index.cjs.map +1 -1
  49. package/dist/kv/replication/index.d.cts +6 -3
  50. package/dist/kv/replication/index.d.ts +6 -3
  51. package/dist/kv/replication/index.js +575 -131
  52. package/dist/kv/replication/index.js.map +1 -1
  53. package/dist/scope-B-m6cKH-.d.ts +1962 -0
  54. package/dist/scope-B7oeKdLM.d.cts +1962 -0
  55. package/dist/sql/index.cjs +72 -36
  56. package/dist/sql/index.cjs.map +1 -1
  57. package/dist/sql/index.d.cts +2 -2
  58. package/dist/sql/index.d.ts +2 -2
  59. package/dist/sql/index.js +72 -36
  60. package/dist/sql/index.js.map +1 -1
  61. package/dist/{types-D-9A3Sut.d.cts → types-BjH0ZtGy.d.cts} +8 -0
  62. package/dist/{types-D-9A3Sut.d.ts → types-BjH0ZtGy.d.ts} +8 -0
  63. package/package.json +55 -2
  64. package/dist/scope-CoKKmMiI.d.ts +0 -957
  65. package/dist/scope-D7wmjbMH.d.cts +0 -957
@@ -0,0 +1,115 @@
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/kv/replication/contractConstants.ts
21
+ var contractConstants_exports = {};
22
+ __export(contractConstants_exports, {
23
+ CONSENT_WINDOW_MS: () => CONSENT_WINDOW_MS,
24
+ DEFAULT_GRANT_TTL_MS: () => DEFAULT_GRANT_TTL_MS,
25
+ DEFAULT_MIN_FREE_BYTES: () => DEFAULT_MIN_FREE_BYTES,
26
+ MAX_GRANT_TTL_MS: () => MAX_GRANT_TTL_MS,
27
+ RENEW_BELOW_FRACTION: () => RENEW_BELOW_FRACTION,
28
+ REPLICA_DENY_TOMBSTONE: () => REPLICA_DENY_TOMBSTONE,
29
+ REPLICA_GATE_FILE: () => REPLICA_GATE_FILE,
30
+ REPLICA_KV_CHANNEL: () => REPLICA_KV_CHANNEL,
31
+ REPLICA_KV_DATABASE: () => REPLICA_KV_DATABASE,
32
+ REPLICA_KV_SCHEMA_VERSION: () => REPLICA_KV_SCHEMA_VERSION,
33
+ REPLICA_KV_STORES: () => REPLICA_KV_STORES,
34
+ REPLICA_LOGOUT_MARKER: () => REPLICA_LOGOUT_MARKER,
35
+ REPLICA_PENDING_LOCK_PREFIX: () => REPLICA_PENDING_LOCK_PREFIX,
36
+ ReplicaContractCode: () => ReplicaContractCode
37
+ });
38
+ module.exports = __toCommonJS(contractConstants_exports);
39
+
40
+ // src/kv/replication/grantPolicyConstants.ts
41
+ var HOUR_MS = 60 * 60 * 1e3;
42
+ var DAY_MS = 24 * HOUR_MS;
43
+ var DEFAULT_GRANT_TTL_MS = DAY_MS;
44
+ var MAX_GRANT_TTL_MS = 7 * DAY_MS;
45
+ var CONSENT_WINDOW_MS = 7 * DAY_MS;
46
+ var RENEW_BELOW_FRACTION = 0.25;
47
+
48
+ // src/kv/replication/contractConstants.ts
49
+ var ReplicaContractCode = {
50
+ /**
51
+ * The lifecycle gate refused the operation: the handle's session stamp or principal no longer
52
+ * matches the gate, a purge intent covers the partition, or the logout marker is set. The error
53
+ * carries `gate: ReplicaGateReason`. Read-through answers from the network; nothing is erased.
54
+ */
55
+ REPLICA_GATED: "REPLICA_GATED",
56
+ /**
57
+ * Reserved for handles whose partition was erased (purge or revocation) after they opened. The
58
+ * gate check runs first, so a handle that is both gated and erased reports REPLICA_GATED.
59
+ */
60
+ RESET_REQUIRED: "RESET_REQUIRED",
61
+ /** A page was refused by quota admission (`maxBytes` or the free-space floor). Nothing committed. */
62
+ STORAGE_BUDGET: "STORAGE_BUDGET",
63
+ /** The platform store refused the write (IndexedDB `QuotaExceededError`, ENOSPC). Nothing committed. */
64
+ STORAGE_FULL: "STORAGE_FULL",
65
+ /** The consent deadline has passed: no grant may be minted, renewed or served until re-consent. */
66
+ CONSENT_EXPIRED: "CONSENT_EXPIRED",
67
+ /** The installed grant's effective expiry (not necessarily its signed `exp`) has passed. */
68
+ GRANT_EXPIRED: "GRANT_EXPIRED"
69
+ };
70
+ var DEFAULT_MIN_FREE_BYTES = 64 * 1024 * 1024;
71
+ var REPLICA_KV_DATABASE = "tinycloud-replica-kv";
72
+ var REPLICA_KV_SCHEMA_VERSION = 2;
73
+ var REPLICA_KV_STORES = {
74
+ /** Data: partition meta (opaque fences, sealed config/grants), private gate-HMAC partition id. */
75
+ meta: "meta",
76
+ /** Data: sealed KV entries, key `[privatePartitionId, accountHmac(path)]`. */
77
+ entries: "entries",
78
+ /** Data: AES-GCM content blobs, key `[privatePartitionId, accountHmac(hash)]`. */
79
+ blobs: "blobs",
80
+ /** Data: AES-sealed pending state, key private gate-HMAC `identityKeyHash`. */
81
+ pending: "pending",
82
+ /** Data: sealed owner device, private nonextractable key records and opaque install anchors. */
83
+ device: "device",
84
+ /** Control: the account gate, singleton key `"account"`, value `ReplicaAccountGate`. */
85
+ gate: "gate",
86
+ /** Control: partition index keyed by private `partitionId`; nonunique `byLookupId` index. */
87
+ partitions: "partitions",
88
+ /** Control: purge intents, key `ReplicaPurgeIntent.id`, value `ReplicaPurgeIntent`. */
89
+ purgeIntents: "purgeIntents",
90
+ /** Control: quota ledger, keys owned by the ledger (S5). */
91
+ quota: "quota"
92
+ };
93
+ var REPLICA_LOGOUT_MARKER = "tinycloud-replica:logout-pending";
94
+ var REPLICA_DENY_TOMBSTONE = "tinycloud-replica:deny-tombstone";
95
+ var REPLICA_KV_CHANNEL = "tinycloud-replica-kv";
96
+ var REPLICA_PENDING_LOCK_PREFIX = "tinycloud-replica-kv:pending:";
97
+ var REPLICA_GATE_FILE = "replica-gate.json";
98
+ // Annotate the CommonJS export names for ESM import in node:
99
+ 0 && (module.exports = {
100
+ CONSENT_WINDOW_MS,
101
+ DEFAULT_GRANT_TTL_MS,
102
+ DEFAULT_MIN_FREE_BYTES,
103
+ MAX_GRANT_TTL_MS,
104
+ RENEW_BELOW_FRACTION,
105
+ REPLICA_DENY_TOMBSTONE,
106
+ REPLICA_GATE_FILE,
107
+ REPLICA_KV_CHANNEL,
108
+ REPLICA_KV_DATABASE,
109
+ REPLICA_KV_SCHEMA_VERSION,
110
+ REPLICA_KV_STORES,
111
+ REPLICA_LOGOUT_MARKER,
112
+ REPLICA_PENDING_LOCK_PREFIX,
113
+ ReplicaContractCode
114
+ });
115
+ //# sourceMappingURL=contractConstants.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/kv/replication/contractConstants.ts","../../../src/kv/replication/grantPolicyConstants.ts"],"sourcesContent":["/**\n * Frozen constants of the shared replica contract (TC-858 Phase 2, see CONTRACT.md).\n *\n * Exported via `@tinycloud/sdk-services/kv/replication/contractConstants`, never from the\n * package root. Runtime grant policy imports the numeric-only `grantPolicyConstants` subpath\n * instead, so the default web bundle does not carry browser storage identifiers.\n */\nexport {\n DEFAULT_GRANT_TTL_MS,\n MAX_GRANT_TTL_MS,\n CONSENT_WINDOW_MS,\n RENEW_BELOW_FRACTION,\n} from \"./grantPolicyConstants\";\n\n/** Error codes the contract adds or gives new meaning. Values equal keys. */\nexport const ReplicaContractCode = {\n /**\n * The lifecycle gate refused the operation: the handle's session stamp or principal no longer\n * matches the gate, a purge intent covers the partition, or the logout marker is set. The error\n * carries `gate: ReplicaGateReason`. Read-through answers from the network; nothing is erased.\n */\n REPLICA_GATED: \"REPLICA_GATED\",\n /**\n * Reserved for handles whose partition was erased (purge or revocation) after they opened. The\n * gate check runs first, so a handle that is both gated and erased reports REPLICA_GATED.\n */\n RESET_REQUIRED: \"RESET_REQUIRED\",\n /** A page was refused by quota admission (`maxBytes` or the free-space floor). Nothing committed. */\n STORAGE_BUDGET: \"STORAGE_BUDGET\",\n /** The platform store refused the write (IndexedDB `QuotaExceededError`, ENOSPC). Nothing committed. */\n STORAGE_FULL: \"STORAGE_FULL\",\n /** The consent deadline has passed: no grant may be minted, renewed or served until re-consent. */\n CONSENT_EXPIRED: \"CONSENT_EXPIRED\",\n /** The installed grant's effective expiry (not necessarily its signed `exp`) has passed. */\n GRANT_EXPIRED: \"GRANT_EXPIRED\",\n} as const;\nexport type ReplicaContractCode = (typeof ReplicaContractCode)[keyof typeof ReplicaContractCode];\n\n/** Browser free-space floor in bytes (64 MiB, `navigator.storage.estimate()`); not applied on node/CLI. */\nexport const DEFAULT_MIN_FREE_BYTES = 64 * 1024 * 1024;\n\n/** The single per-origin IndexedDB database of the browser `KVReplicaStorage` adapter. */\nexport const REPLICA_KV_DATABASE = \"tinycloud-replica-kv\";\n/** Origin database schema: v2 destructively replaces v1 plaintext replica-owned stores. */\nexport const REPLICA_KV_SCHEMA_VERSION = 2;\n\n/**\n * Object-store names in {@link REPLICA_KV_DATABASE}. Every store uses out-of-line keys (no\n * `keyPath`, no autoIncrement) so the schema upgrade can create control stores without knowing\n * their record shapes. Data stores are owned by the adapter (S1); control stores by the lifecycle\n * gate (S3) and quota ledger (S5).\n */\nexport const REPLICA_KV_STORES = {\n /** Data: partition meta (opaque fences, sealed config/grants), private gate-HMAC partition id. */\n meta: \"meta\",\n /** Data: sealed KV entries, key `[privatePartitionId, accountHmac(path)]`. */\n entries: \"entries\",\n /** Data: AES-GCM content blobs, key `[privatePartitionId, accountHmac(hash)]`. */\n blobs: \"blobs\",\n /** Data: AES-sealed pending state, key private gate-HMAC `identityKeyHash`. */\n pending: \"pending\",\n /** Data: sealed owner device, private nonextractable key records and opaque install anchors. */\n device: \"device\",\n /** Control: the account gate, singleton key `\"account\"`, value `ReplicaAccountGate`. */\n gate: \"gate\",\n /** Control: partition index keyed by private `partitionId`; nonunique `byLookupId` index. */\n partitions: \"partitions\",\n /** Control: purge intents, key `ReplicaPurgeIntent.id`, value `ReplicaPurgeIntent`. */\n purgeIntents: \"purgeIntents\",\n /** Control: quota ledger, keys owned by the ledger (S5). */\n quota: \"quota\",\n} as const;\n\n/** Synchronous, cross-tab `localStorage` marker set when the deny transaction and fallback delete both failed. */\nexport const REPLICA_LOGOUT_MARKER = \"tinycloud-replica:logout-pending\";\n\n/** Origin-wide deny floor outside the deletable replica database; JSON `{ epoch, deniedAt }`. */\nexport const REPLICA_DENY_TOMBSTONE = \"tinycloud-replica:deny-tombstone\";\n\n/** BroadcastChannel name used for lifecycle nudges and peer-commit notifications. */\nexport const REPLICA_KV_CHANNEL = \"tinycloud-replica-kv\";\n\n/** Web Lock name prefix for pending-write read-modify-write; suffix is the private gate-HMAC identity id. */\nexport const REPLICA_PENDING_LOCK_PREFIX = \"tinycloud-replica-kv:pending:\";\n\n/** Node/CLI gate file name. CLI places it at `<profile>/replica-gate.json`. */\nexport const REPLICA_GATE_FILE = \"replica-gate.json\";\n","/** Grant lifetime constants without browser storage identifiers. */\nconst HOUR_MS = 60 * 60 * 1000;\nconst DAY_MS = 24 * HOUR_MS;\n\n/** Default device-grant lifetime from install (24 h). All durations are milliseconds. */\nexport const DEFAULT_GRANT_TTL_MS = DAY_MS;\n/** `grantTtlMs` above this (7 d) is a config error: TypeError at construction. */\nexport const MAX_GRANT_TTL_MS = 7 * DAY_MS;\n/** Consent deadline = consent anchor + this window (7 d). */\nexport const CONSENT_WINDOW_MS = 7 * DAY_MS;\n/** Silent renewal starts when remaining effective lifetime < this fraction of the effective lifetime. */\nexport const RENEW_BELOW_FRACTION = 0.25;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,IAAM,UAAU,KAAK,KAAK;AAC1B,IAAM,SAAS,KAAK;AAGb,IAAM,uBAAuB;AAE7B,IAAM,mBAAmB,IAAI;AAE7B,IAAM,oBAAoB,IAAI;AAE9B,IAAM,uBAAuB;;;ADI7B,IAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjC,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA,EAKf,gBAAgB;AAAA;AAAA,EAEhB,gBAAgB;AAAA;AAAA,EAEhB,cAAc;AAAA;AAAA,EAEd,iBAAiB;AAAA;AAAA,EAEjB,eAAe;AACjB;AAIO,IAAM,yBAAyB,KAAK,OAAO;AAG3C,IAAM,sBAAsB;AAE5B,IAAM,4BAA4B;AAQlC,IAAM,oBAAoB;AAAA;AAAA,EAE/B,MAAM;AAAA;AAAA,EAEN,SAAS;AAAA;AAAA,EAET,OAAO;AAAA;AAAA,EAEP,SAAS;AAAA;AAAA,EAET,QAAQ;AAAA;AAAA,EAER,MAAM;AAAA;AAAA,EAEN,YAAY;AAAA;AAAA,EAEZ,cAAc;AAAA;AAAA,EAEd,OAAO;AACT;AAGO,IAAM,wBAAwB;AAG9B,IAAM,yBAAyB;AAG/B,IAAM,qBAAqB;AAG3B,IAAM,8BAA8B;AAGpC,IAAM,oBAAoB;","names":[]}
@@ -0,0 +1,77 @@
1
+ export { CONSENT_WINDOW_MS, DEFAULT_GRANT_TTL_MS, MAX_GRANT_TTL_MS, RENEW_BELOW_FRACTION } from './grantPolicyConstants.cjs';
2
+
3
+ /**
4
+ * Frozen constants of the shared replica contract (TC-858 Phase 2, see CONTRACT.md).
5
+ *
6
+ * Exported via `@tinycloud/sdk-services/kv/replication/contractConstants`, never from the
7
+ * package root. Runtime grant policy imports the numeric-only `grantPolicyConstants` subpath
8
+ * instead, so the default web bundle does not carry browser storage identifiers.
9
+ */
10
+
11
+ /** Error codes the contract adds or gives new meaning. Values equal keys. */
12
+ declare const ReplicaContractCode: {
13
+ /**
14
+ * The lifecycle gate refused the operation: the handle's session stamp or principal no longer
15
+ * matches the gate, a purge intent covers the partition, or the logout marker is set. The error
16
+ * carries `gate: ReplicaGateReason`. Read-through answers from the network; nothing is erased.
17
+ */
18
+ readonly REPLICA_GATED: "REPLICA_GATED";
19
+ /**
20
+ * Reserved for handles whose partition was erased (purge or revocation) after they opened. The
21
+ * gate check runs first, so a handle that is both gated and erased reports REPLICA_GATED.
22
+ */
23
+ readonly RESET_REQUIRED: "RESET_REQUIRED";
24
+ /** A page was refused by quota admission (`maxBytes` or the free-space floor). Nothing committed. */
25
+ readonly STORAGE_BUDGET: "STORAGE_BUDGET";
26
+ /** The platform store refused the write (IndexedDB `QuotaExceededError`, ENOSPC). Nothing committed. */
27
+ readonly STORAGE_FULL: "STORAGE_FULL";
28
+ /** The consent deadline has passed: no grant may be minted, renewed or served until re-consent. */
29
+ readonly CONSENT_EXPIRED: "CONSENT_EXPIRED";
30
+ /** The installed grant's effective expiry (not necessarily its signed `exp`) has passed. */
31
+ readonly GRANT_EXPIRED: "GRANT_EXPIRED";
32
+ };
33
+ type ReplicaContractCode = (typeof ReplicaContractCode)[keyof typeof ReplicaContractCode];
34
+ /** Browser free-space floor in bytes (64 MiB, `navigator.storage.estimate()`); not applied on node/CLI. */
35
+ declare const DEFAULT_MIN_FREE_BYTES: number;
36
+ /** The single per-origin IndexedDB database of the browser `KVReplicaStorage` adapter. */
37
+ declare const REPLICA_KV_DATABASE = "tinycloud-replica-kv";
38
+ /** Origin database schema: v2 destructively replaces v1 plaintext replica-owned stores. */
39
+ declare const REPLICA_KV_SCHEMA_VERSION = 2;
40
+ /**
41
+ * Object-store names in {@link REPLICA_KV_DATABASE}. Every store uses out-of-line keys (no
42
+ * `keyPath`, no autoIncrement) so the schema upgrade can create control stores without knowing
43
+ * their record shapes. Data stores are owned by the adapter (S1); control stores by the lifecycle
44
+ * gate (S3) and quota ledger (S5).
45
+ */
46
+ declare const REPLICA_KV_STORES: {
47
+ /** Data: partition meta (opaque fences, sealed config/grants), private gate-HMAC partition id. */
48
+ readonly meta: "meta";
49
+ /** Data: sealed KV entries, key `[privatePartitionId, accountHmac(path)]`. */
50
+ readonly entries: "entries";
51
+ /** Data: AES-GCM content blobs, key `[privatePartitionId, accountHmac(hash)]`. */
52
+ readonly blobs: "blobs";
53
+ /** Data: AES-sealed pending state, key private gate-HMAC `identityKeyHash`. */
54
+ readonly pending: "pending";
55
+ /** Data: sealed owner device, private nonextractable key records and opaque install anchors. */
56
+ readonly device: "device";
57
+ /** Control: the account gate, singleton key `"account"`, value `ReplicaAccountGate`. */
58
+ readonly gate: "gate";
59
+ /** Control: partition index keyed by private `partitionId`; nonunique `byLookupId` index. */
60
+ readonly partitions: "partitions";
61
+ /** Control: purge intents, key `ReplicaPurgeIntent.id`, value `ReplicaPurgeIntent`. */
62
+ readonly purgeIntents: "purgeIntents";
63
+ /** Control: quota ledger, keys owned by the ledger (S5). */
64
+ readonly quota: "quota";
65
+ };
66
+ /** Synchronous, cross-tab `localStorage` marker set when the deny transaction and fallback delete both failed. */
67
+ declare const REPLICA_LOGOUT_MARKER = "tinycloud-replica:logout-pending";
68
+ /** Origin-wide deny floor outside the deletable replica database; JSON `{ epoch, deniedAt }`. */
69
+ declare const REPLICA_DENY_TOMBSTONE = "tinycloud-replica:deny-tombstone";
70
+ /** BroadcastChannel name used for lifecycle nudges and peer-commit notifications. */
71
+ declare const REPLICA_KV_CHANNEL = "tinycloud-replica-kv";
72
+ /** Web Lock name prefix for pending-write read-modify-write; suffix is the private gate-HMAC identity id. */
73
+ declare const REPLICA_PENDING_LOCK_PREFIX = "tinycloud-replica-kv:pending:";
74
+ /** Node/CLI gate file name. CLI places it at `<profile>/replica-gate.json`. */
75
+ declare const REPLICA_GATE_FILE = "replica-gate.json";
76
+
77
+ export { DEFAULT_MIN_FREE_BYTES, REPLICA_DENY_TOMBSTONE, REPLICA_GATE_FILE, REPLICA_KV_CHANNEL, REPLICA_KV_DATABASE, REPLICA_KV_SCHEMA_VERSION, REPLICA_KV_STORES, REPLICA_LOGOUT_MARKER, REPLICA_PENDING_LOCK_PREFIX, ReplicaContractCode };
@@ -0,0 +1,77 @@
1
+ export { CONSENT_WINDOW_MS, DEFAULT_GRANT_TTL_MS, MAX_GRANT_TTL_MS, RENEW_BELOW_FRACTION } from './grantPolicyConstants.js';
2
+
3
+ /**
4
+ * Frozen constants of the shared replica contract (TC-858 Phase 2, see CONTRACT.md).
5
+ *
6
+ * Exported via `@tinycloud/sdk-services/kv/replication/contractConstants`, never from the
7
+ * package root. Runtime grant policy imports the numeric-only `grantPolicyConstants` subpath
8
+ * instead, so the default web bundle does not carry browser storage identifiers.
9
+ */
10
+
11
+ /** Error codes the contract adds or gives new meaning. Values equal keys. */
12
+ declare const ReplicaContractCode: {
13
+ /**
14
+ * The lifecycle gate refused the operation: the handle's session stamp or principal no longer
15
+ * matches the gate, a purge intent covers the partition, or the logout marker is set. The error
16
+ * carries `gate: ReplicaGateReason`. Read-through answers from the network; nothing is erased.
17
+ */
18
+ readonly REPLICA_GATED: "REPLICA_GATED";
19
+ /**
20
+ * Reserved for handles whose partition was erased (purge or revocation) after they opened. The
21
+ * gate check runs first, so a handle that is both gated and erased reports REPLICA_GATED.
22
+ */
23
+ readonly RESET_REQUIRED: "RESET_REQUIRED";
24
+ /** A page was refused by quota admission (`maxBytes` or the free-space floor). Nothing committed. */
25
+ readonly STORAGE_BUDGET: "STORAGE_BUDGET";
26
+ /** The platform store refused the write (IndexedDB `QuotaExceededError`, ENOSPC). Nothing committed. */
27
+ readonly STORAGE_FULL: "STORAGE_FULL";
28
+ /** The consent deadline has passed: no grant may be minted, renewed or served until re-consent. */
29
+ readonly CONSENT_EXPIRED: "CONSENT_EXPIRED";
30
+ /** The installed grant's effective expiry (not necessarily its signed `exp`) has passed. */
31
+ readonly GRANT_EXPIRED: "GRANT_EXPIRED";
32
+ };
33
+ type ReplicaContractCode = (typeof ReplicaContractCode)[keyof typeof ReplicaContractCode];
34
+ /** Browser free-space floor in bytes (64 MiB, `navigator.storage.estimate()`); not applied on node/CLI. */
35
+ declare const DEFAULT_MIN_FREE_BYTES: number;
36
+ /** The single per-origin IndexedDB database of the browser `KVReplicaStorage` adapter. */
37
+ declare const REPLICA_KV_DATABASE = "tinycloud-replica-kv";
38
+ /** Origin database schema: v2 destructively replaces v1 plaintext replica-owned stores. */
39
+ declare const REPLICA_KV_SCHEMA_VERSION = 2;
40
+ /**
41
+ * Object-store names in {@link REPLICA_KV_DATABASE}. Every store uses out-of-line keys (no
42
+ * `keyPath`, no autoIncrement) so the schema upgrade can create control stores without knowing
43
+ * their record shapes. Data stores are owned by the adapter (S1); control stores by the lifecycle
44
+ * gate (S3) and quota ledger (S5).
45
+ */
46
+ declare const REPLICA_KV_STORES: {
47
+ /** Data: partition meta (opaque fences, sealed config/grants), private gate-HMAC partition id. */
48
+ readonly meta: "meta";
49
+ /** Data: sealed KV entries, key `[privatePartitionId, accountHmac(path)]`. */
50
+ readonly entries: "entries";
51
+ /** Data: AES-GCM content blobs, key `[privatePartitionId, accountHmac(hash)]`. */
52
+ readonly blobs: "blobs";
53
+ /** Data: AES-sealed pending state, key private gate-HMAC `identityKeyHash`. */
54
+ readonly pending: "pending";
55
+ /** Data: sealed owner device, private nonextractable key records and opaque install anchors. */
56
+ readonly device: "device";
57
+ /** Control: the account gate, singleton key `"account"`, value `ReplicaAccountGate`. */
58
+ readonly gate: "gate";
59
+ /** Control: partition index keyed by private `partitionId`; nonunique `byLookupId` index. */
60
+ readonly partitions: "partitions";
61
+ /** Control: purge intents, key `ReplicaPurgeIntent.id`, value `ReplicaPurgeIntent`. */
62
+ readonly purgeIntents: "purgeIntents";
63
+ /** Control: quota ledger, keys owned by the ledger (S5). */
64
+ readonly quota: "quota";
65
+ };
66
+ /** Synchronous, cross-tab `localStorage` marker set when the deny transaction and fallback delete both failed. */
67
+ declare const REPLICA_LOGOUT_MARKER = "tinycloud-replica:logout-pending";
68
+ /** Origin-wide deny floor outside the deletable replica database; JSON `{ epoch, deniedAt }`. */
69
+ declare const REPLICA_DENY_TOMBSTONE = "tinycloud-replica:deny-tombstone";
70
+ /** BroadcastChannel name used for lifecycle nudges and peer-commit notifications. */
71
+ declare const REPLICA_KV_CHANNEL = "tinycloud-replica-kv";
72
+ /** Web Lock name prefix for pending-write read-modify-write; suffix is the private gate-HMAC identity id. */
73
+ declare const REPLICA_PENDING_LOCK_PREFIX = "tinycloud-replica-kv:pending:";
74
+ /** Node/CLI gate file name. CLI places it at `<profile>/replica-gate.json`. */
75
+ declare const REPLICA_GATE_FILE = "replica-gate.json";
76
+
77
+ export { DEFAULT_MIN_FREE_BYTES, REPLICA_DENY_TOMBSTONE, REPLICA_GATE_FILE, REPLICA_KV_CHANNEL, REPLICA_KV_DATABASE, REPLICA_KV_SCHEMA_VERSION, REPLICA_KV_STORES, REPLICA_LOGOUT_MARKER, REPLICA_PENDING_LOCK_PREFIX, ReplicaContractCode };
@@ -0,0 +1,75 @@
1
+ // src/kv/replication/grantPolicyConstants.ts
2
+ var HOUR_MS = 60 * 60 * 1e3;
3
+ var DAY_MS = 24 * HOUR_MS;
4
+ var DEFAULT_GRANT_TTL_MS = DAY_MS;
5
+ var MAX_GRANT_TTL_MS = 7 * DAY_MS;
6
+ var CONSENT_WINDOW_MS = 7 * DAY_MS;
7
+ var RENEW_BELOW_FRACTION = 0.25;
8
+
9
+ // src/kv/replication/contractConstants.ts
10
+ var ReplicaContractCode = {
11
+ /**
12
+ * The lifecycle gate refused the operation: the handle's session stamp or principal no longer
13
+ * matches the gate, a purge intent covers the partition, or the logout marker is set. The error
14
+ * carries `gate: ReplicaGateReason`. Read-through answers from the network; nothing is erased.
15
+ */
16
+ REPLICA_GATED: "REPLICA_GATED",
17
+ /**
18
+ * Reserved for handles whose partition was erased (purge or revocation) after they opened. The
19
+ * gate check runs first, so a handle that is both gated and erased reports REPLICA_GATED.
20
+ */
21
+ RESET_REQUIRED: "RESET_REQUIRED",
22
+ /** A page was refused by quota admission (`maxBytes` or the free-space floor). Nothing committed. */
23
+ STORAGE_BUDGET: "STORAGE_BUDGET",
24
+ /** The platform store refused the write (IndexedDB `QuotaExceededError`, ENOSPC). Nothing committed. */
25
+ STORAGE_FULL: "STORAGE_FULL",
26
+ /** The consent deadline has passed: no grant may be minted, renewed or served until re-consent. */
27
+ CONSENT_EXPIRED: "CONSENT_EXPIRED",
28
+ /** The installed grant's effective expiry (not necessarily its signed `exp`) has passed. */
29
+ GRANT_EXPIRED: "GRANT_EXPIRED"
30
+ };
31
+ var DEFAULT_MIN_FREE_BYTES = 64 * 1024 * 1024;
32
+ var REPLICA_KV_DATABASE = "tinycloud-replica-kv";
33
+ var REPLICA_KV_SCHEMA_VERSION = 2;
34
+ var REPLICA_KV_STORES = {
35
+ /** Data: partition meta (opaque fences, sealed config/grants), private gate-HMAC partition id. */
36
+ meta: "meta",
37
+ /** Data: sealed KV entries, key `[privatePartitionId, accountHmac(path)]`. */
38
+ entries: "entries",
39
+ /** Data: AES-GCM content blobs, key `[privatePartitionId, accountHmac(hash)]`. */
40
+ blobs: "blobs",
41
+ /** Data: AES-sealed pending state, key private gate-HMAC `identityKeyHash`. */
42
+ pending: "pending",
43
+ /** Data: sealed owner device, private nonextractable key records and opaque install anchors. */
44
+ device: "device",
45
+ /** Control: the account gate, singleton key `"account"`, value `ReplicaAccountGate`. */
46
+ gate: "gate",
47
+ /** Control: partition index keyed by private `partitionId`; nonunique `byLookupId` index. */
48
+ partitions: "partitions",
49
+ /** Control: purge intents, key `ReplicaPurgeIntent.id`, value `ReplicaPurgeIntent`. */
50
+ purgeIntents: "purgeIntents",
51
+ /** Control: quota ledger, keys owned by the ledger (S5). */
52
+ quota: "quota"
53
+ };
54
+ var REPLICA_LOGOUT_MARKER = "tinycloud-replica:logout-pending";
55
+ var REPLICA_DENY_TOMBSTONE = "tinycloud-replica:deny-tombstone";
56
+ var REPLICA_KV_CHANNEL = "tinycloud-replica-kv";
57
+ var REPLICA_PENDING_LOCK_PREFIX = "tinycloud-replica-kv:pending:";
58
+ var REPLICA_GATE_FILE = "replica-gate.json";
59
+ export {
60
+ CONSENT_WINDOW_MS,
61
+ DEFAULT_GRANT_TTL_MS,
62
+ DEFAULT_MIN_FREE_BYTES,
63
+ MAX_GRANT_TTL_MS,
64
+ RENEW_BELOW_FRACTION,
65
+ REPLICA_DENY_TOMBSTONE,
66
+ REPLICA_GATE_FILE,
67
+ REPLICA_KV_CHANNEL,
68
+ REPLICA_KV_DATABASE,
69
+ REPLICA_KV_SCHEMA_VERSION,
70
+ REPLICA_KV_STORES,
71
+ REPLICA_LOGOUT_MARKER,
72
+ REPLICA_PENDING_LOCK_PREFIX,
73
+ ReplicaContractCode
74
+ };
75
+ //# sourceMappingURL=contractConstants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/kv/replication/grantPolicyConstants.ts","../../../src/kv/replication/contractConstants.ts"],"sourcesContent":["/** Grant lifetime constants without browser storage identifiers. */\nconst HOUR_MS = 60 * 60 * 1000;\nconst DAY_MS = 24 * HOUR_MS;\n\n/** Default device-grant lifetime from install (24 h). All durations are milliseconds. */\nexport const DEFAULT_GRANT_TTL_MS = DAY_MS;\n/** `grantTtlMs` above this (7 d) is a config error: TypeError at construction. */\nexport const MAX_GRANT_TTL_MS = 7 * DAY_MS;\n/** Consent deadline = consent anchor + this window (7 d). */\nexport const CONSENT_WINDOW_MS = 7 * DAY_MS;\n/** Silent renewal starts when remaining effective lifetime < this fraction of the effective lifetime. */\nexport const RENEW_BELOW_FRACTION = 0.25;\n","/**\n * Frozen constants of the shared replica contract (TC-858 Phase 2, see CONTRACT.md).\n *\n * Exported via `@tinycloud/sdk-services/kv/replication/contractConstants`, never from the\n * package root. Runtime grant policy imports the numeric-only `grantPolicyConstants` subpath\n * instead, so the default web bundle does not carry browser storage identifiers.\n */\nexport {\n DEFAULT_GRANT_TTL_MS,\n MAX_GRANT_TTL_MS,\n CONSENT_WINDOW_MS,\n RENEW_BELOW_FRACTION,\n} from \"./grantPolicyConstants\";\n\n/** Error codes the contract adds or gives new meaning. Values equal keys. */\nexport const ReplicaContractCode = {\n /**\n * The lifecycle gate refused the operation: the handle's session stamp or principal no longer\n * matches the gate, a purge intent covers the partition, or the logout marker is set. The error\n * carries `gate: ReplicaGateReason`. Read-through answers from the network; nothing is erased.\n */\n REPLICA_GATED: \"REPLICA_GATED\",\n /**\n * Reserved for handles whose partition was erased (purge or revocation) after they opened. The\n * gate check runs first, so a handle that is both gated and erased reports REPLICA_GATED.\n */\n RESET_REQUIRED: \"RESET_REQUIRED\",\n /** A page was refused by quota admission (`maxBytes` or the free-space floor). Nothing committed. */\n STORAGE_BUDGET: \"STORAGE_BUDGET\",\n /** The platform store refused the write (IndexedDB `QuotaExceededError`, ENOSPC). Nothing committed. */\n STORAGE_FULL: \"STORAGE_FULL\",\n /** The consent deadline has passed: no grant may be minted, renewed or served until re-consent. */\n CONSENT_EXPIRED: \"CONSENT_EXPIRED\",\n /** The installed grant's effective expiry (not necessarily its signed `exp`) has passed. */\n GRANT_EXPIRED: \"GRANT_EXPIRED\",\n} as const;\nexport type ReplicaContractCode = (typeof ReplicaContractCode)[keyof typeof ReplicaContractCode];\n\n/** Browser free-space floor in bytes (64 MiB, `navigator.storage.estimate()`); not applied on node/CLI. */\nexport const DEFAULT_MIN_FREE_BYTES = 64 * 1024 * 1024;\n\n/** The single per-origin IndexedDB database of the browser `KVReplicaStorage` adapter. */\nexport const REPLICA_KV_DATABASE = \"tinycloud-replica-kv\";\n/** Origin database schema: v2 destructively replaces v1 plaintext replica-owned stores. */\nexport const REPLICA_KV_SCHEMA_VERSION = 2;\n\n/**\n * Object-store names in {@link REPLICA_KV_DATABASE}. Every store uses out-of-line keys (no\n * `keyPath`, no autoIncrement) so the schema upgrade can create control stores without knowing\n * their record shapes. Data stores are owned by the adapter (S1); control stores by the lifecycle\n * gate (S3) and quota ledger (S5).\n */\nexport const REPLICA_KV_STORES = {\n /** Data: partition meta (opaque fences, sealed config/grants), private gate-HMAC partition id. */\n meta: \"meta\",\n /** Data: sealed KV entries, key `[privatePartitionId, accountHmac(path)]`. */\n entries: \"entries\",\n /** Data: AES-GCM content blobs, key `[privatePartitionId, accountHmac(hash)]`. */\n blobs: \"blobs\",\n /** Data: AES-sealed pending state, key private gate-HMAC `identityKeyHash`. */\n pending: \"pending\",\n /** Data: sealed owner device, private nonextractable key records and opaque install anchors. */\n device: \"device\",\n /** Control: the account gate, singleton key `\"account\"`, value `ReplicaAccountGate`. */\n gate: \"gate\",\n /** Control: partition index keyed by private `partitionId`; nonunique `byLookupId` index. */\n partitions: \"partitions\",\n /** Control: purge intents, key `ReplicaPurgeIntent.id`, value `ReplicaPurgeIntent`. */\n purgeIntents: \"purgeIntents\",\n /** Control: quota ledger, keys owned by the ledger (S5). */\n quota: \"quota\",\n} as const;\n\n/** Synchronous, cross-tab `localStorage` marker set when the deny transaction and fallback delete both failed. */\nexport const REPLICA_LOGOUT_MARKER = \"tinycloud-replica:logout-pending\";\n\n/** Origin-wide deny floor outside the deletable replica database; JSON `{ epoch, deniedAt }`. */\nexport const REPLICA_DENY_TOMBSTONE = \"tinycloud-replica:deny-tombstone\";\n\n/** BroadcastChannel name used for lifecycle nudges and peer-commit notifications. */\nexport const REPLICA_KV_CHANNEL = \"tinycloud-replica-kv\";\n\n/** Web Lock name prefix for pending-write read-modify-write; suffix is the private gate-HMAC identity id. */\nexport const REPLICA_PENDING_LOCK_PREFIX = \"tinycloud-replica-kv:pending:\";\n\n/** Node/CLI gate file name. CLI places it at `<profile>/replica-gate.json`. */\nexport const REPLICA_GATE_FILE = \"replica-gate.json\";\n"],"mappings":";AACA,IAAM,UAAU,KAAK,KAAK;AAC1B,IAAM,SAAS,KAAK;AAGb,IAAM,uBAAuB;AAE7B,IAAM,mBAAmB,IAAI;AAE7B,IAAM,oBAAoB,IAAI;AAE9B,IAAM,uBAAuB;;;ACI7B,IAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjC,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA,EAKf,gBAAgB;AAAA;AAAA,EAEhB,gBAAgB;AAAA;AAAA,EAEhB,cAAc;AAAA;AAAA,EAEd,iBAAiB;AAAA;AAAA,EAEjB,eAAe;AACjB;AAIO,IAAM,yBAAyB,KAAK,OAAO;AAG3C,IAAM,sBAAsB;AAE5B,IAAM,4BAA4B;AAQlC,IAAM,oBAAoB;AAAA;AAAA,EAE/B,MAAM;AAAA;AAAA,EAEN,SAAS;AAAA;AAAA,EAET,OAAO;AAAA;AAAA,EAEP,SAAS;AAAA;AAAA,EAET,QAAQ;AAAA;AAAA,EAER,MAAM;AAAA;AAAA,EAEN,YAAY;AAAA;AAAA,EAEZ,cAAc;AAAA;AAAA,EAEd,OAAO;AACT;AAGO,IAAM,wBAAwB;AAG9B,IAAM,yBAAyB;AAG/B,IAAM,qBAAqB;AAG3B,IAAM,8BAA8B;AAGpC,IAAM,oBAAoB;","names":[]}
@@ -0,0 +1,82 @@
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/kv/replication/grantPolicy.ts
21
+ var grantPolicy_exports = {};
22
+ __export(grantPolicy_exports, {
23
+ MAX_GRANT_TTL_MS: () => MAX_GRANT_TTL_MS,
24
+ clampConsentAnchor: () => clampConsentAnchor,
25
+ consentDeadlineMs: () => consentDeadlineMs,
26
+ effectiveGrantExpiry: () => effectiveGrantExpiry,
27
+ mintRemainingMs: () => mintRemainingMs,
28
+ needsSilentRenewal: () => needsSilentRenewal
29
+ });
30
+ module.exports = __toCommonJS(grantPolicy_exports);
31
+
32
+ // src/kv/replication/grantPolicyConstants.ts
33
+ var HOUR_MS = 60 * 60 * 1e3;
34
+ var DAY_MS = 24 * HOUR_MS;
35
+ var MAX_GRANT_TTL_MS = 7 * DAY_MS;
36
+ var CONSENT_WINDOW_MS = 7 * DAY_MS;
37
+ var RENEW_BELOW_FRACTION = 0.25;
38
+
39
+ // src/kv/replication/grantPolicy.ts
40
+ var EXPIRED = Number.NEGATIVE_INFINITY;
41
+ var consentDeadlineMs = (anchor) => Number.isFinite(anchor.at) ? anchor.at + CONSENT_WINDOW_MS : EXPIRED;
42
+ var clampConsentAnchor = (anchor, now) => {
43
+ if (anchor === null || !Number.isFinite(anchor.at) || !Number.isFinite(now)) return null;
44
+ return anchor.at > now ? { at: now, source: anchor.source } : anchor;
45
+ };
46
+ var effectiveGrantExpiry = ({
47
+ signedExpiresAt,
48
+ installedAt,
49
+ grantTtlMs,
50
+ consentDeadline
51
+ }) => {
52
+ const signedValid = signedExpiresAt === null || Number.isFinite(signedExpiresAt);
53
+ if (!signedValid || !Number.isFinite(installedAt) || !Number.isFinite(grantTtlMs) || !Number.isFinite(consentDeadline)) {
54
+ return EXPIRED;
55
+ }
56
+ const ttl = Math.min(grantTtlMs, MAX_GRANT_TTL_MS);
57
+ const localBound = Math.min(installedAt + ttl, consentDeadline);
58
+ return signedExpiresAt === null ? localBound : Math.min(signedExpiresAt, localBound);
59
+ };
60
+ var mintRemainingMs = ({ now, grantTtlMs, consentDeadline }) => {
61
+ if (!Number.isFinite(now) || !Number.isFinite(grantTtlMs) || !Number.isFinite(consentDeadline)) return 0;
62
+ return Math.min(Math.min(grantTtlMs, MAX_GRANT_TTL_MS), consentDeadline - now);
63
+ };
64
+ var needsSilentRenewal = ({ now, installedAt, effectiveExpiresAt, consentDeadline }) => {
65
+ if (!Number.isFinite(now) || !Number.isFinite(installedAt) || !Number.isFinite(effectiveExpiresAt) || !Number.isFinite(consentDeadline)) {
66
+ return false;
67
+ }
68
+ if (!(now < consentDeadline)) return false;
69
+ const remaining = effectiveExpiresAt - now;
70
+ const lifetime = effectiveExpiresAt - installedAt;
71
+ return remaining < lifetime * RENEW_BELOW_FRACTION;
72
+ };
73
+ // Annotate the CommonJS export names for ESM import in node:
74
+ 0 && (module.exports = {
75
+ MAX_GRANT_TTL_MS,
76
+ clampConsentAnchor,
77
+ consentDeadlineMs,
78
+ effectiveGrantExpiry,
79
+ mintRemainingMs,
80
+ needsSilentRenewal
81
+ });
82
+ //# sourceMappingURL=grantPolicy.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/kv/replication/grantPolicy.ts","../../../src/kv/replication/grantPolicyConstants.ts"],"sourcesContent":["/**\n * Grant lifetime policy (TC-858 plan §6, CONTRACT.md §3). Pure functions over epoch\n * milliseconds. Types and constants come from the shared contract; this file only implements them.\n *\n * Every function fails closed: a non-finite input yields a value that refuses the mint, renewal or\n * read, never a permissive one.\n */\nimport { CONSENT_WINDOW_MS, MAX_GRANT_TTL_MS, RENEW_BELOW_FRACTION } from \"./grantPolicyConstants\";\nexport { MAX_GRANT_TTL_MS } from \"./grantPolicyConstants\";\nimport type {\n ConsentDeadlineMs,\n EffectiveGrantExpiry,\n MintRemainingMs,\n NeedsSilentRenewal,\n ReplicaConsentAnchor,\n} from \"./grantPolicyTypes\";\n\n/** An instant that has already passed: nothing is minted, renewed or served against it. */\nconst EXPIRED = Number.NEGATIVE_INFINITY;\n\n/**\n * Caller contract: clamp the anchor with {@link clampConsentAnchor} first. A non-finite anchor\n * yields an already-passed deadline.\n */\nexport const consentDeadlineMs: ConsentDeadlineMs = (anchor) =>\n Number.isFinite(anchor.at) ? anchor.at + CONSENT_WINDOW_MS : EXPIRED;\n\n/**\n * Returns the anchor the deadline may be computed from. A non-finite anchor or clock yields\n * `null` (no anchor, so no mint). An anchor dated after `now` is pulled back to `now`, so a\n * future-dated anchor cannot extend the 7 d window.\n */\nexport const clampConsentAnchor = (\n anchor: ReplicaConsentAnchor | null,\n now: number,\n): ReplicaConsentAnchor | null => {\n if (anchor === null || !Number.isFinite(anchor.at) || !Number.isFinite(now)) return null;\n return anchor.at > now ? { at: now, source: anchor.source } : anchor;\n};\n\nexport const effectiveGrantExpiry: EffectiveGrantExpiry = ({\n signedExpiresAt,\n installedAt,\n grantTtlMs,\n consentDeadline,\n}) => {\n const signedValid = signedExpiresAt === null || Number.isFinite(signedExpiresAt);\n if (!signedValid || !Number.isFinite(installedAt) || !Number.isFinite(grantTtlMs) || !Number.isFinite(consentDeadline)) {\n return EXPIRED;\n }\n const ttl = Math.min(grantTtlMs, MAX_GRANT_TTL_MS);\n const localBound = Math.min(installedAt + ttl, consentDeadline);\n return signedExpiresAt === null ? localBound : Math.min(signedExpiresAt, localBound);\n};\n\nexport const mintRemainingMs: MintRemainingMs = ({ now, grantTtlMs, consentDeadline }) => {\n if (!Number.isFinite(now) || !Number.isFinite(grantTtlMs) || !Number.isFinite(consentDeadline)) return 0;\n return Math.min(Math.min(grantTtlMs, MAX_GRANT_TTL_MS), consentDeadline - now);\n};\n\nexport const needsSilentRenewal: NeedsSilentRenewal = ({ now, installedAt, effectiveExpiresAt, consentDeadline }) => {\n if (\n !Number.isFinite(now) ||\n !Number.isFinite(installedAt) ||\n !Number.isFinite(effectiveExpiresAt) ||\n !Number.isFinite(consentDeadline)\n ) {\n return false;\n }\n if (!(now < consentDeadline)) return false;\n const remaining = effectiveExpiresAt - now;\n const lifetime = effectiveExpiresAt - installedAt;\n return remaining < lifetime * RENEW_BELOW_FRACTION;\n};\n","/** Grant lifetime constants without browser storage identifiers. */\nconst HOUR_MS = 60 * 60 * 1000;\nconst DAY_MS = 24 * HOUR_MS;\n\n/** Default device-grant lifetime from install (24 h). All durations are milliseconds. */\nexport const DEFAULT_GRANT_TTL_MS = DAY_MS;\n/** `grantTtlMs` above this (7 d) is a config error: TypeError at construction. */\nexport const MAX_GRANT_TTL_MS = 7 * DAY_MS;\n/** Consent deadline = consent anchor + this window (7 d). */\nexport const CONSENT_WINDOW_MS = 7 * DAY_MS;\n/** Silent renewal starts when remaining effective lifetime < this fraction of the effective lifetime. */\nexport const RENEW_BELOW_FRACTION = 0.25;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,IAAM,UAAU,KAAK,KAAK;AAC1B,IAAM,SAAS,KAAK;AAKb,IAAM,mBAAmB,IAAI;AAE7B,IAAM,oBAAoB,IAAI;AAE9B,IAAM,uBAAuB;;;ADOpC,IAAM,UAAU,OAAO;AAMhB,IAAM,oBAAuC,CAAC,WACnD,OAAO,SAAS,OAAO,EAAE,IAAI,OAAO,KAAK,oBAAoB;AAOxD,IAAM,qBAAqB,CAChC,QACA,QACgC;AAChC,MAAI,WAAW,QAAQ,CAAC,OAAO,SAAS,OAAO,EAAE,KAAK,CAAC,OAAO,SAAS,GAAG,EAAG,QAAO;AACpF,SAAO,OAAO,KAAK,MAAM,EAAE,IAAI,KAAK,QAAQ,OAAO,OAAO,IAAI;AAChE;AAEO,IAAM,uBAA6C,CAAC;AAAA,EACzD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,cAAc,oBAAoB,QAAQ,OAAO,SAAS,eAAe;AAC/E,MAAI,CAAC,eAAe,CAAC,OAAO,SAAS,WAAW,KAAK,CAAC,OAAO,SAAS,UAAU,KAAK,CAAC,OAAO,SAAS,eAAe,GAAG;AACtH,WAAO;AAAA,EACT;AACA,QAAM,MAAM,KAAK,IAAI,YAAY,gBAAgB;AACjD,QAAM,aAAa,KAAK,IAAI,cAAc,KAAK,eAAe;AAC9D,SAAO,oBAAoB,OAAO,aAAa,KAAK,IAAI,iBAAiB,UAAU;AACrF;AAEO,IAAM,kBAAmC,CAAC,EAAE,KAAK,YAAY,gBAAgB,MAAM;AACxF,MAAI,CAAC,OAAO,SAAS,GAAG,KAAK,CAAC,OAAO,SAAS,UAAU,KAAK,CAAC,OAAO,SAAS,eAAe,EAAG,QAAO;AACvG,SAAO,KAAK,IAAI,KAAK,IAAI,YAAY,gBAAgB,GAAG,kBAAkB,GAAG;AAC/E;AAEO,IAAM,qBAAyC,CAAC,EAAE,KAAK,aAAa,oBAAoB,gBAAgB,MAAM;AACnH,MACE,CAAC,OAAO,SAAS,GAAG,KACpB,CAAC,OAAO,SAAS,WAAW,KAC5B,CAAC,OAAO,SAAS,kBAAkB,KACnC,CAAC,OAAO,SAAS,eAAe,GAChC;AACA,WAAO;AAAA,EACT;AACA,MAAI,EAAE,MAAM,iBAAkB,QAAO;AACrC,QAAM,YAAY,qBAAqB;AACvC,QAAM,WAAW,qBAAqB;AACtC,SAAO,YAAY,WAAW;AAChC;","names":[]}
@@ -0,0 +1,19 @@
1
+ export { MAX_GRANT_TTL_MS } from './grantPolicyConstants.cjs';
2
+ import { ReplicaConsentAnchor, ConsentDeadlineMs, EffectiveGrantExpiry, MintRemainingMs, NeedsSilentRenewal } from './grantPolicyTypes.cjs';
3
+
4
+ /**
5
+ * Caller contract: clamp the anchor with {@link clampConsentAnchor} first. A non-finite anchor
6
+ * yields an already-passed deadline.
7
+ */
8
+ declare const consentDeadlineMs: ConsentDeadlineMs;
9
+ /**
10
+ * Returns the anchor the deadline may be computed from. A non-finite anchor or clock yields
11
+ * `null` (no anchor, so no mint). An anchor dated after `now` is pulled back to `now`, so a
12
+ * future-dated anchor cannot extend the 7 d window.
13
+ */
14
+ declare const clampConsentAnchor: (anchor: ReplicaConsentAnchor | null, now: number) => ReplicaConsentAnchor | null;
15
+ declare const effectiveGrantExpiry: EffectiveGrantExpiry;
16
+ declare const mintRemainingMs: MintRemainingMs;
17
+ declare const needsSilentRenewal: NeedsSilentRenewal;
18
+
19
+ export { clampConsentAnchor, consentDeadlineMs, effectiveGrantExpiry, mintRemainingMs, needsSilentRenewal };
@@ -0,0 +1,19 @@
1
+ export { MAX_GRANT_TTL_MS } from './grantPolicyConstants.js';
2
+ import { ReplicaConsentAnchor, ConsentDeadlineMs, EffectiveGrantExpiry, MintRemainingMs, NeedsSilentRenewal } from './grantPolicyTypes.js';
3
+
4
+ /**
5
+ * Caller contract: clamp the anchor with {@link clampConsentAnchor} first. A non-finite anchor
6
+ * yields an already-passed deadline.
7
+ */
8
+ declare const consentDeadlineMs: ConsentDeadlineMs;
9
+ /**
10
+ * Returns the anchor the deadline may be computed from. A non-finite anchor or clock yields
11
+ * `null` (no anchor, so no mint). An anchor dated after `now` is pulled back to `now`, so a
12
+ * future-dated anchor cannot extend the 7 d window.
13
+ */
14
+ declare const clampConsentAnchor: (anchor: ReplicaConsentAnchor | null, now: number) => ReplicaConsentAnchor | null;
15
+ declare const effectiveGrantExpiry: EffectiveGrantExpiry;
16
+ declare const mintRemainingMs: MintRemainingMs;
17
+ declare const needsSilentRenewal: NeedsSilentRenewal;
18
+
19
+ export { clampConsentAnchor, consentDeadlineMs, effectiveGrantExpiry, mintRemainingMs, needsSilentRenewal };
@@ -0,0 +1,50 @@
1
+ // src/kv/replication/grantPolicyConstants.ts
2
+ var HOUR_MS = 60 * 60 * 1e3;
3
+ var DAY_MS = 24 * HOUR_MS;
4
+ var MAX_GRANT_TTL_MS = 7 * DAY_MS;
5
+ var CONSENT_WINDOW_MS = 7 * DAY_MS;
6
+ var RENEW_BELOW_FRACTION = 0.25;
7
+
8
+ // src/kv/replication/grantPolicy.ts
9
+ var EXPIRED = Number.NEGATIVE_INFINITY;
10
+ var consentDeadlineMs = (anchor) => Number.isFinite(anchor.at) ? anchor.at + CONSENT_WINDOW_MS : EXPIRED;
11
+ var clampConsentAnchor = (anchor, now) => {
12
+ if (anchor === null || !Number.isFinite(anchor.at) || !Number.isFinite(now)) return null;
13
+ return anchor.at > now ? { at: now, source: anchor.source } : anchor;
14
+ };
15
+ var effectiveGrantExpiry = ({
16
+ signedExpiresAt,
17
+ installedAt,
18
+ grantTtlMs,
19
+ consentDeadline
20
+ }) => {
21
+ const signedValid = signedExpiresAt === null || Number.isFinite(signedExpiresAt);
22
+ if (!signedValid || !Number.isFinite(installedAt) || !Number.isFinite(grantTtlMs) || !Number.isFinite(consentDeadline)) {
23
+ return EXPIRED;
24
+ }
25
+ const ttl = Math.min(grantTtlMs, MAX_GRANT_TTL_MS);
26
+ const localBound = Math.min(installedAt + ttl, consentDeadline);
27
+ return signedExpiresAt === null ? localBound : Math.min(signedExpiresAt, localBound);
28
+ };
29
+ var mintRemainingMs = ({ now, grantTtlMs, consentDeadline }) => {
30
+ if (!Number.isFinite(now) || !Number.isFinite(grantTtlMs) || !Number.isFinite(consentDeadline)) return 0;
31
+ return Math.min(Math.min(grantTtlMs, MAX_GRANT_TTL_MS), consentDeadline - now);
32
+ };
33
+ var needsSilentRenewal = ({ now, installedAt, effectiveExpiresAt, consentDeadline }) => {
34
+ if (!Number.isFinite(now) || !Number.isFinite(installedAt) || !Number.isFinite(effectiveExpiresAt) || !Number.isFinite(consentDeadline)) {
35
+ return false;
36
+ }
37
+ if (!(now < consentDeadline)) return false;
38
+ const remaining = effectiveExpiresAt - now;
39
+ const lifetime = effectiveExpiresAt - installedAt;
40
+ return remaining < lifetime * RENEW_BELOW_FRACTION;
41
+ };
42
+ export {
43
+ MAX_GRANT_TTL_MS,
44
+ clampConsentAnchor,
45
+ consentDeadlineMs,
46
+ effectiveGrantExpiry,
47
+ mintRemainingMs,
48
+ needsSilentRenewal
49
+ };
50
+ //# sourceMappingURL=grantPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/kv/replication/grantPolicyConstants.ts","../../../src/kv/replication/grantPolicy.ts"],"sourcesContent":["/** Grant lifetime constants without browser storage identifiers. */\nconst HOUR_MS = 60 * 60 * 1000;\nconst DAY_MS = 24 * HOUR_MS;\n\n/** Default device-grant lifetime from install (24 h). All durations are milliseconds. */\nexport const DEFAULT_GRANT_TTL_MS = DAY_MS;\n/** `grantTtlMs` above this (7 d) is a config error: TypeError at construction. */\nexport const MAX_GRANT_TTL_MS = 7 * DAY_MS;\n/** Consent deadline = consent anchor + this window (7 d). */\nexport const CONSENT_WINDOW_MS = 7 * DAY_MS;\n/** Silent renewal starts when remaining effective lifetime < this fraction of the effective lifetime. */\nexport const RENEW_BELOW_FRACTION = 0.25;\n","/**\n * Grant lifetime policy (TC-858 plan §6, CONTRACT.md §3). Pure functions over epoch\n * milliseconds. Types and constants come from the shared contract; this file only implements them.\n *\n * Every function fails closed: a non-finite input yields a value that refuses the mint, renewal or\n * read, never a permissive one.\n */\nimport { CONSENT_WINDOW_MS, MAX_GRANT_TTL_MS, RENEW_BELOW_FRACTION } from \"./grantPolicyConstants\";\nexport { MAX_GRANT_TTL_MS } from \"./grantPolicyConstants\";\nimport type {\n ConsentDeadlineMs,\n EffectiveGrantExpiry,\n MintRemainingMs,\n NeedsSilentRenewal,\n ReplicaConsentAnchor,\n} from \"./grantPolicyTypes\";\n\n/** An instant that has already passed: nothing is minted, renewed or served against it. */\nconst EXPIRED = Number.NEGATIVE_INFINITY;\n\n/**\n * Caller contract: clamp the anchor with {@link clampConsentAnchor} first. A non-finite anchor\n * yields an already-passed deadline.\n */\nexport const consentDeadlineMs: ConsentDeadlineMs = (anchor) =>\n Number.isFinite(anchor.at) ? anchor.at + CONSENT_WINDOW_MS : EXPIRED;\n\n/**\n * Returns the anchor the deadline may be computed from. A non-finite anchor or clock yields\n * `null` (no anchor, so no mint). An anchor dated after `now` is pulled back to `now`, so a\n * future-dated anchor cannot extend the 7 d window.\n */\nexport const clampConsentAnchor = (\n anchor: ReplicaConsentAnchor | null,\n now: number,\n): ReplicaConsentAnchor | null => {\n if (anchor === null || !Number.isFinite(anchor.at) || !Number.isFinite(now)) return null;\n return anchor.at > now ? { at: now, source: anchor.source } : anchor;\n};\n\nexport const effectiveGrantExpiry: EffectiveGrantExpiry = ({\n signedExpiresAt,\n installedAt,\n grantTtlMs,\n consentDeadline,\n}) => {\n const signedValid = signedExpiresAt === null || Number.isFinite(signedExpiresAt);\n if (!signedValid || !Number.isFinite(installedAt) || !Number.isFinite(grantTtlMs) || !Number.isFinite(consentDeadline)) {\n return EXPIRED;\n }\n const ttl = Math.min(grantTtlMs, MAX_GRANT_TTL_MS);\n const localBound = Math.min(installedAt + ttl, consentDeadline);\n return signedExpiresAt === null ? localBound : Math.min(signedExpiresAt, localBound);\n};\n\nexport const mintRemainingMs: MintRemainingMs = ({ now, grantTtlMs, consentDeadline }) => {\n if (!Number.isFinite(now) || !Number.isFinite(grantTtlMs) || !Number.isFinite(consentDeadline)) return 0;\n return Math.min(Math.min(grantTtlMs, MAX_GRANT_TTL_MS), consentDeadline - now);\n};\n\nexport const needsSilentRenewal: NeedsSilentRenewal = ({ now, installedAt, effectiveExpiresAt, consentDeadline }) => {\n if (\n !Number.isFinite(now) ||\n !Number.isFinite(installedAt) ||\n !Number.isFinite(effectiveExpiresAt) ||\n !Number.isFinite(consentDeadline)\n ) {\n return false;\n }\n if (!(now < consentDeadline)) return false;\n const remaining = effectiveExpiresAt - now;\n const lifetime = effectiveExpiresAt - installedAt;\n return remaining < lifetime * RENEW_BELOW_FRACTION;\n};\n"],"mappings":";AACA,IAAM,UAAU,KAAK,KAAK;AAC1B,IAAM,SAAS,KAAK;AAKb,IAAM,mBAAmB,IAAI;AAE7B,IAAM,oBAAoB,IAAI;AAE9B,IAAM,uBAAuB;;;ACOpC,IAAM,UAAU,OAAO;AAMhB,IAAM,oBAAuC,CAAC,WACnD,OAAO,SAAS,OAAO,EAAE,IAAI,OAAO,KAAK,oBAAoB;AAOxD,IAAM,qBAAqB,CAChC,QACA,QACgC;AAChC,MAAI,WAAW,QAAQ,CAAC,OAAO,SAAS,OAAO,EAAE,KAAK,CAAC,OAAO,SAAS,GAAG,EAAG,QAAO;AACpF,SAAO,OAAO,KAAK,MAAM,EAAE,IAAI,KAAK,QAAQ,OAAO,OAAO,IAAI;AAChE;AAEO,IAAM,uBAA6C,CAAC;AAAA,EACzD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,cAAc,oBAAoB,QAAQ,OAAO,SAAS,eAAe;AAC/E,MAAI,CAAC,eAAe,CAAC,OAAO,SAAS,WAAW,KAAK,CAAC,OAAO,SAAS,UAAU,KAAK,CAAC,OAAO,SAAS,eAAe,GAAG;AACtH,WAAO;AAAA,EACT;AACA,QAAM,MAAM,KAAK,IAAI,YAAY,gBAAgB;AACjD,QAAM,aAAa,KAAK,IAAI,cAAc,KAAK,eAAe;AAC9D,SAAO,oBAAoB,OAAO,aAAa,KAAK,IAAI,iBAAiB,UAAU;AACrF;AAEO,IAAM,kBAAmC,CAAC,EAAE,KAAK,YAAY,gBAAgB,MAAM;AACxF,MAAI,CAAC,OAAO,SAAS,GAAG,KAAK,CAAC,OAAO,SAAS,UAAU,KAAK,CAAC,OAAO,SAAS,eAAe,EAAG,QAAO;AACvG,SAAO,KAAK,IAAI,KAAK,IAAI,YAAY,gBAAgB,GAAG,kBAAkB,GAAG;AAC/E;AAEO,IAAM,qBAAyC,CAAC,EAAE,KAAK,aAAa,oBAAoB,gBAAgB,MAAM;AACnH,MACE,CAAC,OAAO,SAAS,GAAG,KACpB,CAAC,OAAO,SAAS,WAAW,KAC5B,CAAC,OAAO,SAAS,kBAAkB,KACnC,CAAC,OAAO,SAAS,eAAe,GAChC;AACA,WAAO;AAAA,EACT;AACA,MAAI,EAAE,MAAM,iBAAkB,QAAO;AACrC,QAAM,YAAY,qBAAqB;AACvC,QAAM,WAAW,qBAAqB;AACtC,SAAO,YAAY,WAAW;AAChC;","names":[]}
@@ -0,0 +1,42 @@
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/kv/replication/grantPolicyConstants.ts
21
+ var grantPolicyConstants_exports = {};
22
+ __export(grantPolicyConstants_exports, {
23
+ CONSENT_WINDOW_MS: () => CONSENT_WINDOW_MS,
24
+ DEFAULT_GRANT_TTL_MS: () => DEFAULT_GRANT_TTL_MS,
25
+ MAX_GRANT_TTL_MS: () => MAX_GRANT_TTL_MS,
26
+ RENEW_BELOW_FRACTION: () => RENEW_BELOW_FRACTION
27
+ });
28
+ module.exports = __toCommonJS(grantPolicyConstants_exports);
29
+ var HOUR_MS = 60 * 60 * 1e3;
30
+ var DAY_MS = 24 * HOUR_MS;
31
+ var DEFAULT_GRANT_TTL_MS = DAY_MS;
32
+ var MAX_GRANT_TTL_MS = 7 * DAY_MS;
33
+ var CONSENT_WINDOW_MS = 7 * DAY_MS;
34
+ var RENEW_BELOW_FRACTION = 0.25;
35
+ // Annotate the CommonJS export names for ESM import in node:
36
+ 0 && (module.exports = {
37
+ CONSENT_WINDOW_MS,
38
+ DEFAULT_GRANT_TTL_MS,
39
+ MAX_GRANT_TTL_MS,
40
+ RENEW_BELOW_FRACTION
41
+ });
42
+ //# sourceMappingURL=grantPolicyConstants.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/kv/replication/grantPolicyConstants.ts"],"sourcesContent":["/** Grant lifetime constants without browser storage identifiers. */\nconst HOUR_MS = 60 * 60 * 1000;\nconst DAY_MS = 24 * HOUR_MS;\n\n/** Default device-grant lifetime from install (24 h). All durations are milliseconds. */\nexport const DEFAULT_GRANT_TTL_MS = DAY_MS;\n/** `grantTtlMs` above this (7 d) is a config error: TypeError at construction. */\nexport const MAX_GRANT_TTL_MS = 7 * DAY_MS;\n/** Consent deadline = consent anchor + this window (7 d). */\nexport const CONSENT_WINDOW_MS = 7 * DAY_MS;\n/** Silent renewal starts when remaining effective lifetime < this fraction of the effective lifetime. */\nexport const RENEW_BELOW_FRACTION = 0.25;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,IAAM,UAAU,KAAK,KAAK;AAC1B,IAAM,SAAS,KAAK;AAGb,IAAM,uBAAuB;AAE7B,IAAM,mBAAmB,IAAI;AAE7B,IAAM,oBAAoB,IAAI;AAE9B,IAAM,uBAAuB;","names":[]}
@@ -0,0 +1,10 @@
1
+ /** Default device-grant lifetime from install (24 h). All durations are milliseconds. */
2
+ declare const DEFAULT_GRANT_TTL_MS: number;
3
+ /** `grantTtlMs` above this (7 d) is a config error: TypeError at construction. */
4
+ declare const MAX_GRANT_TTL_MS: number;
5
+ /** Consent deadline = consent anchor + this window (7 d). */
6
+ declare const CONSENT_WINDOW_MS: number;
7
+ /** Silent renewal starts when remaining effective lifetime < this fraction of the effective lifetime. */
8
+ declare const RENEW_BELOW_FRACTION = 0.25;
9
+
10
+ export { CONSENT_WINDOW_MS, DEFAULT_GRANT_TTL_MS, MAX_GRANT_TTL_MS, RENEW_BELOW_FRACTION };