@opendatalabs/personal-server-ts-server 1.34.2 → 1.35.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 (180) hide show
  1. package/dist/api-auth.d.ts +1 -0
  2. package/dist/api-auth.d.ts.map +1 -1
  3. package/dist/api-auth.js.map +1 -1
  4. package/dist/api.d.ts +3 -0
  5. package/dist/api.d.ts.map +1 -1
  6. package/dist/api.js +3 -0
  7. package/dist/api.js.map +1 -1
  8. package/dist/app.d.ts +14 -2
  9. package/dist/app.d.ts.map +1 -1
  10. package/dist/app.js +64 -8
  11. package/dist/app.js.map +1 -1
  12. package/dist/bootstrap.d.ts +19 -0
  13. package/dist/bootstrap.d.ts.map +1 -1
  14. package/dist/bootstrap.js +87 -4
  15. package/dist/bootstrap.js.map +1 -1
  16. package/dist/client.d.ts +1 -1
  17. package/dist/client.d.ts.map +1 -1
  18. package/dist/client.js +7 -0
  19. package/dist/client.js.map +1 -1
  20. package/dist/enclave-main.d.ts.map +1 -1
  21. package/dist/enclave-main.js +0 -2
  22. package/dist/enclave-main.js.map +1 -1
  23. package/dist/mcp/durable-state.d.ts +2 -1
  24. package/dist/mcp/durable-state.d.ts.map +1 -1
  25. package/dist/mcp/durable-state.js +35 -1
  26. package/dist/mcp/durable-state.js.map +1 -1
  27. package/dist/pdpp/bootstrap.d.ts.map +1 -1
  28. package/dist/pdpp/bootstrap.js +1 -0
  29. package/dist/pdpp/bootstrap.js.map +1 -1
  30. package/dist/pdpp/records-bootstrap.d.ts +47 -1
  31. package/dist/pdpp/records-bootstrap.d.ts.map +1 -1
  32. package/dist/pdpp/records-bootstrap.js +78 -2
  33. package/dist/pdpp/records-bootstrap.js.map +1 -1
  34. package/dist/pdpp/replica-authorization.d.ts +35 -0
  35. package/dist/pdpp/replica-authorization.d.ts.map +1 -0
  36. package/dist/pdpp/replica-authorization.js +234 -0
  37. package/dist/pdpp/replica-authorization.js.map +1 -0
  38. package/dist/pending-blob-deletions.d.ts +1 -0
  39. package/dist/pending-blob-deletions.d.ts.map +1 -1
  40. package/dist/pending-blob-deletions.js +8 -4
  41. package/dist/pending-blob-deletions.js.map +1 -1
  42. package/dist/routes/mcp.d.ts +18 -2
  43. package/dist/routes/mcp.d.ts.map +1 -1
  44. package/dist/routes/mcp.js +111 -11
  45. package/dist/routes/mcp.js.map +1 -1
  46. package/dist/routes/oura.d.ts +6 -0
  47. package/dist/routes/oura.d.ts.map +1 -0
  48. package/dist/routes/oura.js +272 -0
  49. package/dist/routes/oura.js.map +1 -0
  50. package/dist/routes/pdpp-auth-query-keys.d.ts +7 -0
  51. package/dist/routes/pdpp-auth-query-keys.d.ts.map +1 -0
  52. package/dist/routes/pdpp-auth-query-keys.js +25 -0
  53. package/dist/routes/pdpp-auth-query-keys.js.map +1 -0
  54. package/dist/routes/pdpp-auth.d.ts +3 -1
  55. package/dist/routes/pdpp-auth.d.ts.map +1 -1
  56. package/dist/routes/pdpp-auth.js +126 -45
  57. package/dist/routes/pdpp-auth.js.map +1 -1
  58. package/dist/routes/pdpp-blobs.d.ts +13 -1
  59. package/dist/routes/pdpp-blobs.d.ts.map +1 -1
  60. package/dist/routes/pdpp-blobs.js +100 -65
  61. package/dist/routes/pdpp-blobs.js.map +1 -1
  62. package/dist/routes/pdpp-connections.d.ts.map +1 -1
  63. package/dist/routes/pdpp-connections.js +24 -1
  64. package/dist/routes/pdpp-connections.js.map +1 -1
  65. package/dist/routes/pdpp-instance-bindings.d.ts +3 -0
  66. package/dist/routes/pdpp-instance-bindings.d.ts.map +1 -1
  67. package/dist/routes/pdpp-instance-bindings.js +63 -0
  68. package/dist/routes/pdpp-instance-bindings.js.map +1 -1
  69. package/dist/routes/pdpp-record-query.d.ts +19 -0
  70. package/dist/routes/pdpp-record-query.d.ts.map +1 -0
  71. package/dist/routes/pdpp-record-query.js +51 -0
  72. package/dist/routes/pdpp-record-query.js.map +1 -0
  73. package/dist/routes/pdpp-records.d.ts +12 -1
  74. package/dist/routes/pdpp-records.d.ts.map +1 -1
  75. package/dist/routes/pdpp-records.js +120 -233
  76. package/dist/routes/pdpp-records.js.map +1 -1
  77. package/dist/routes/pdpp-replica-quarantine-fixture.d.ts +65 -0
  78. package/dist/routes/pdpp-replica-quarantine-fixture.d.ts.map +1 -0
  79. package/dist/routes/pdpp-replica-quarantine-fixture.js +389 -0
  80. package/dist/routes/pdpp-replica-quarantine-fixture.js.map +1 -0
  81. package/dist/storage/claude-method-transition.d.ts +12 -0
  82. package/dist/storage/claude-method-transition.d.ts.map +1 -0
  83. package/dist/storage/claude-method-transition.js +139 -0
  84. package/dist/storage/claude-method-transition.js.map +1 -0
  85. package/dist/storage/import-operations.d.ts +16 -0
  86. package/dist/storage/import-operations.d.ts.map +1 -1
  87. package/dist/storage/import-operations.js +54 -1
  88. package/dist/storage/import-operations.js.map +1 -1
  89. package/dist/storage/index-schema.d.ts +1 -1
  90. package/dist/storage/index-schema.d.ts.map +1 -1
  91. package/dist/storage/index-schema.js +22 -5
  92. package/dist/storage/index-schema.js.map +1 -1
  93. package/dist/storage/legacy-scope-authority.d.ts.map +1 -1
  94. package/dist/storage/legacy-scope-authority.js +83 -11
  95. package/dist/storage/legacy-scope-authority.js.map +1 -1
  96. package/dist/storage/node-data-storage.d.ts.map +1 -1
  97. package/dist/storage/node-data-storage.js +58 -2
  98. package/dist/storage/node-data-storage.js.map +1 -1
  99. package/dist/storage/pdpp-binary-chunks.d.ts +120 -0
  100. package/dist/storage/pdpp-binary-chunks.d.ts.map +1 -0
  101. package/dist/storage/pdpp-binary-chunks.js +480 -0
  102. package/dist/storage/pdpp-binary-chunks.js.map +1 -0
  103. package/dist/storage/pdpp-records-sqlite-store.d.ts +96 -15
  104. package/dist/storage/pdpp-records-sqlite-store.d.ts.map +1 -1
  105. package/dist/storage/pdpp-records-sqlite-store.js +616 -211
  106. package/dist/storage/pdpp-records-sqlite-store.js.map +1 -1
  107. package/dist/storage/pdpp-replica-canonical-port.d.ts +202 -0
  108. package/dist/storage/pdpp-replica-canonical-port.d.ts.map +1 -0
  109. package/dist/storage/pdpp-replica-canonical-port.js +451 -0
  110. package/dist/storage/pdpp-replica-canonical-port.js.map +1 -0
  111. package/dist/storage/pdpp-replica-coordinator-state.d.ts +16 -0
  112. package/dist/storage/pdpp-replica-coordinator-state.d.ts.map +1 -0
  113. package/dist/storage/pdpp-replica-coordinator-state.js +25 -0
  114. package/dist/storage/pdpp-replica-coordinator-state.js.map +1 -0
  115. package/dist/storage/pdpp-replica-copies.d.ts +81 -0
  116. package/dist/storage/pdpp-replica-copies.d.ts.map +1 -0
  117. package/dist/storage/pdpp-replica-copies.js +59 -0
  118. package/dist/storage/pdpp-replica-copies.js.map +1 -0
  119. package/dist/storage/pdpp-replica-reconciler.d.ts +96 -0
  120. package/dist/storage/pdpp-replica-reconciler.d.ts.map +1 -0
  121. package/dist/storage/pdpp-replica-reconciler.js +710 -0
  122. package/dist/storage/pdpp-replica-reconciler.js.map +1 -0
  123. package/dist/storage/pdpp-replica-sql.d.ts +13 -0
  124. package/dist/storage/pdpp-replica-sql.d.ts.map +1 -0
  125. package/dist/storage/pdpp-replica-sql.js +43 -0
  126. package/dist/storage/pdpp-replica-sql.js.map +1 -0
  127. package/dist/storage/pdpp-replica-staging.d.ts +36 -0
  128. package/dist/storage/pdpp-replica-staging.d.ts.map +1 -0
  129. package/dist/storage/pdpp-replica-staging.js +202 -0
  130. package/dist/storage/pdpp-replica-staging.js.map +1 -0
  131. package/dist/storage/pdpp-replica-visibility-view.d.ts +64 -0
  132. package/dist/storage/pdpp-replica-visibility-view.d.ts.map +1 -0
  133. package/dist/storage/pdpp-replica-visibility-view.js +1397 -0
  134. package/dist/storage/pdpp-replica-visibility-view.js.map +1 -0
  135. package/dist/storage/pdpp-replica-writer-identity.d.ts +64 -0
  136. package/dist/storage/pdpp-replica-writer-identity.d.ts.map +1 -0
  137. package/dist/storage/pdpp-replica-writer-identity.js +81 -0
  138. package/dist/storage/pdpp-replica-writer-identity.js.map +1 -0
  139. package/dist/storage/pdpp-replication-door.d.ts +60 -0
  140. package/dist/storage/pdpp-replication-door.d.ts.map +1 -0
  141. package/dist/storage/pdpp-replication-door.js +203 -0
  142. package/dist/storage/pdpp-replication-door.js.map +1 -0
  143. package/dist/storage/pdpp-replication-host.d.ts +67 -0
  144. package/dist/storage/pdpp-replication-host.d.ts.map +1 -0
  145. package/dist/storage/pdpp-replication-host.js +159 -0
  146. package/dist/storage/pdpp-replication-host.js.map +1 -0
  147. package/dist/storage/pdpp-replication-memory.fixture.d.ts +2 -0
  148. package/dist/storage/pdpp-replication-memory.fixture.d.ts.map +1 -0
  149. package/dist/storage/pdpp-replication-memory.fixture.js +267 -0
  150. package/dist/storage/pdpp-replication-memory.fixture.js.map +1 -0
  151. package/dist/storage/pdpp-replication-preparation.d.ts +3 -0
  152. package/dist/storage/pdpp-replication-preparation.d.ts.map +1 -0
  153. package/dist/storage/pdpp-replication-preparation.js +3 -0
  154. package/dist/storage/pdpp-replication-preparation.js.map +1 -0
  155. package/dist/storage/pdpp-replication-promotion-memory.fixture.d.ts +2 -0
  156. package/dist/storage/pdpp-replication-promotion-memory.fixture.d.ts.map +1 -0
  157. package/dist/storage/pdpp-replication-promotion-memory.fixture.js +65 -0
  158. package/dist/storage/pdpp-replication-promotion-memory.fixture.js.map +1 -0
  159. package/dist/storage/pdpp-replication-receiver.d.ts +230 -0
  160. package/dist/storage/pdpp-replication-receiver.d.ts.map +1 -0
  161. package/dist/storage/pdpp-replication-receiver.js +950 -0
  162. package/dist/storage/pdpp-replication-receiver.js.map +1 -0
  163. package/dist/storage/pdpp-replication-sqlite.d.ts +95 -0
  164. package/dist/storage/pdpp-replication-sqlite.d.ts.map +1 -0
  165. package/dist/storage/pdpp-replication-sqlite.js +615 -0
  166. package/dist/storage/pdpp-replication-sqlite.js.map +1 -0
  167. package/dist/storage/pdpp-replication-transport.d.ts +39 -0
  168. package/dist/storage/pdpp-replication-transport.d.ts.map +1 -0
  169. package/dist/storage/pdpp-replication-transport.js +196 -0
  170. package/dist/storage/pdpp-replication-transport.js.map +1 -0
  171. package/dist/storage/schema-versions.d.ts +5 -0
  172. package/dist/storage/schema-versions.d.ts.map +1 -0
  173. package/dist/storage/schema-versions.js +26 -0
  174. package/dist/storage/schema-versions.js.map +1 -0
  175. package/dist/storage/strava-method-transition.d.ts +18 -0
  176. package/dist/storage/strava-method-transition.d.ts.map +1 -0
  177. package/dist/storage/strava-method-transition.js +209 -0
  178. package/dist/storage/strava-method-transition.js.map +1 -0
  179. package/dist/ui/ps-lite-debug.js +154938 -124896
  180. package/package.json +3 -3
@@ -0,0 +1,451 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { CursorExpiredError, InvalidCursorError, } from "@opendatalabs/personal-server-ts-core/storage/pdpp-records";
3
+ import { BINARY_CHUNKS_MIGRATION, binaryLength, clearMalformedManifest, readBinary, verifyBinary, writeCanonicalBinary, } from "./pdpp-binary-chunks.js";
4
+ import { REPLICA_COPY_MIGRATION } from "./pdpp-replica-copies.js";
5
+ import { RECEIVER_MIGRATION, REPLICA_FACT_REMOVAL_MIGRATION, REPLICA_INTEGRITY_MIGRATION, } from "./pdpp-replication-receiver.js";
6
+ import { createReplicationJournal, REPLICATION_MIGRATION, REPLICA_BINDING_HISTORY_MIGRATION, REPLICA_BLOB_CLAIM_INDEX_MIGRATION, } from "./pdpp-replication-sqlite.js";
7
+ import { currentReplicaWriterIdentity, REPLICA_WRITER_IDENTITY_MIGRATION, } from "./pdpp-replica-writer-identity.js";
8
+ import { createSqliteRecordStore, PdppBindingError, } from "./pdpp-records-sqlite-store.js";
9
+ import { admitReplication, captureWrites } from "./pdpp-replication-door.js";
10
+ /**
11
+ * The replica schema. It is versioned by `pdpp_replica_schema_version`, apart
12
+ * from the canonical `MIGRATIONS` chain, and only `ensureReplicaSchema` applies
13
+ * it. A database that never enabled replication has none of these tables, and
14
+ * a canonical build that knows nothing of them still opens one that did.
15
+ */
16
+ export const REPLICA_MIGRATIONS = [
17
+ // r1: installation writer and the log of its own writes. The owner's local view
18
+ // of a binding-conflicted connection projects the log
19
+ // (pdpp-replica-visibility-view.ts).
20
+ `
21
+ CREATE TABLE IF NOT EXISTS pdpp_installation_writer (
22
+ id INTEGER PRIMARY KEY CHECK (id = 1),
23
+ writer_id TEXT NOT NULL UNIQUE
24
+ );
25
+ CREATE TABLE IF NOT EXISTS pdpp_replica_own_writes (
26
+ sequence INTEGER PRIMARY KEY AUTOINCREMENT,
27
+ operation_id TEXT NOT NULL UNIQUE,
28
+ writer_id TEXT NOT NULL,
29
+ source_id TEXT,
30
+ connection_id TEXT NOT NULL,
31
+ method TEXT,
32
+ generation INTEGER CHECK (generation > 0),
33
+ stream TEXT NOT NULL,
34
+ record_key TEXT NOT NULL,
35
+ operation TEXT NOT NULL CHECK (operation IN ('upsert', 'delete')),
36
+ value_json TEXT NOT NULL,
37
+ blob_ids_json TEXT NOT NULL
38
+ );
39
+ -- REPLACE's implicit delete need not fire DELETE triggers. Guard both identities
40
+ -- before insertion as well, independent of recursive_triggers configuration.
41
+ CREATE TRIGGER IF NOT EXISTS pdpp_replica_own_writes_no_replace BEFORE INSERT ON pdpp_replica_own_writes
42
+ WHEN EXISTS (SELECT 1 FROM pdpp_replica_own_writes
43
+ WHERE sequence = NEW.sequence OR operation_id = NEW.operation_id)
44
+ BEGIN SELECT RAISE(ABORT, 'local write log is append-only'); END;
45
+ CREATE TRIGGER IF NOT EXISTS pdpp_replica_own_writes_no_update BEFORE UPDATE ON pdpp_replica_own_writes
46
+ BEGIN SELECT RAISE(ABORT, 'local write log is append-only'); END;
47
+ CREATE TRIGGER IF NOT EXISTS pdpp_replica_own_writes_no_delete BEFORE DELETE ON pdpp_replica_own_writes
48
+ BEGIN SELECT RAISE(ABORT, 'local write log is append-only'); END;
49
+ `,
50
+ REPLICATION_MIGRATION,
51
+ RECEIVER_MIGRATION,
52
+ // Earlier builds also created the persistent trigger
53
+ // `pdpp_canonical_chunks_delete` on `pdpp_blobs` here. It would fire on a
54
+ // plain open's blob deletes, so `ensureReplicaSchema` drops it and the
55
+ // port recreates it as a TEMP trigger. See `CANONICAL_CHUNKS_TRIGGER`.
56
+ BINARY_CHUNKS_MIGRATION,
57
+ // Integrity fences and binding-conflict facts.
58
+ REPLICA_INTEGRITY_MIGRATION,
59
+ // Batch copies, finalized facts, dispositions, receipts.
60
+ REPLICA_COPY_MIGRATION,
61
+ // Removing a quarantine fact raises the integrity epoch.
62
+ REPLICA_FACT_REMOVAL_MIGRATION,
63
+ // Indexed blob-claim existence lookup for captureBlob.
64
+ REPLICA_BLOB_CLAIM_INDEX_MIGRATION,
65
+ // Writer ids derived from the registered server key (host contract §3.2).
66
+ REPLICA_WRITER_IDENTITY_MIGRATION,
67
+ // Binding generations and declaration history (host contract §4.5).
68
+ REPLICA_BINDING_HISTORY_MIGRATION,
69
+ // Capture pins that reference canonical chunks instead of copying them.
70
+ // See `pinReferenceKeepsBytes`.
71
+ `CREATE TABLE IF NOT EXISTS pdpp_replica_blob_pins (blob_id TEXT PRIMARY KEY);`,
72
+ ];
73
+ /**
74
+ * Apply the replica schema. Call it only when replication is enabled, after
75
+ * the canonical store migrated the database. Idempotent.
76
+ */
77
+ export function ensureReplicaSchema(db) {
78
+ db.transaction(() => {
79
+ db.exec(`
80
+ CREATE TABLE IF NOT EXISTS pdpp_replica_schema_version (
81
+ id INTEGER PRIMARY KEY CHECK (id = 1),
82
+ version INTEGER NOT NULL
83
+ );
84
+ INSERT OR IGNORE INTO pdpp_replica_schema_version (id, version) VALUES (1, 0);
85
+ `);
86
+ const { version } = db
87
+ .prepare("SELECT version FROM pdpp_replica_schema_version WHERE id = 1")
88
+ .get();
89
+ if (version > REPLICA_MIGRATIONS.length)
90
+ throw new Error(`PDPP replica schema version ${version} is newer than this build supports (${REPLICA_MIGRATIONS.length}). Refusing to open.`);
91
+ for (let v = version; v < REPLICA_MIGRATIONS.length; v++) {
92
+ db.exec(REPLICA_MIGRATIONS[v]);
93
+ if (v === 0)
94
+ db.prepare("INSERT OR IGNORE INTO pdpp_installation_writer (id, writer_id) VALUES (1, ?)").run(randomUUID());
95
+ }
96
+ db.prepare("UPDATE pdpp_replica_schema_version SET version = ? WHERE id = 1").run(REPLICA_MIGRATIONS.length);
97
+ // A database a canary build opened has the chunk trigger as a persistent
98
+ // object. Replica triggers on canonical tables must exist only on a
99
+ // connection that enabled replication, so remove it.
100
+ db.exec("DROP TRIGGER IF EXISTS pdpp_canonical_chunks_delete");
101
+ // A plain open can delete a blob without clearing its replica chunks.
102
+ // Clear what such deletes left, on every enabled open; a pin keeps them.
103
+ const orphans = `SELECT blob_id FROM pdpp_binary_manifests WHERE namespace='canonical' AND blob_id NOT IN (SELECT blob_id FROM pdpp_blobs)`;
104
+ const keep = pinReferenceKeepsBytes("@id").map((sql) => db.prepare(sql));
105
+ for (const { blob_id } of db.prepare(orphans).all())
106
+ for (const statement of keep)
107
+ statement.run({ id: blob_id });
108
+ db.exec(`
109
+ DELETE FROM pdpp_binary_chunks WHERE namespace='canonical' AND blob_id NOT IN (SELECT blob_id FROM pdpp_blobs);
110
+ DELETE FROM pdpp_binary_manifests WHERE namespace='canonical' AND blob_id NOT IN (SELECT blob_id FROM pdpp_blobs);
111
+ `);
112
+ }).immediate();
113
+ }
114
+ /**
115
+ * A capture pin of a large blob references its canonical chunks; it holds no
116
+ * copy (`captureBlob`). Before canonical storage drops such a blob, its
117
+ * chunks change namespace to `pinned`, so export can still read them. No byte
118
+ * is copied, and the pin row goes: the pinned copy now holds the bytes.
119
+ */
120
+ function pinReferenceKeepsBytes(id) {
121
+ const pinOnly = `EXISTS (SELECT 1 FROM pdpp_replica_blob_pins WHERE blob_id=${id}) AND NOT EXISTS (SELECT 1 FROM pdpp_binary_manifests WHERE namespace='pinned' AND blob_id=${id})`;
122
+ return [
123
+ `UPDATE pdpp_binary_chunks SET namespace='pinned' WHERE namespace='canonical' AND blob_id=${id} AND ${pinOnly};`,
124
+ `INSERT INTO pdpp_binary_manifests SELECT 'pinned',blob_id,size_bytes FROM pdpp_binary_manifests WHERE namespace='canonical' AND blob_id=${id} AND ${pinOnly};`,
125
+ `DELETE FROM pdpp_replica_blob_pins WHERE blob_id=${id} AND EXISTS (SELECT 1 FROM pdpp_binary_manifests WHERE namespace='pinned' AND blob_id=${id});`,
126
+ ];
127
+ }
128
+ /**
129
+ * Deleting a canonical blob deletes its replica chunks. TEMP, so it lives on
130
+ * the connection that enabled replication and never fires for a plain open's
131
+ * writes; a plain open leaves the chunks, and the next enabled open clears
132
+ * them (see `ensureReplicaSchema`).
133
+ */
134
+ const CANONICAL_CHUNKS_TRIGGER = `CREATE TEMP TRIGGER IF NOT EXISTS pdpp_canonical_chunks_delete AFTER DELETE ON pdpp_blobs BEGIN ${pinReferenceKeepsBytes("OLD.blob_id").join(" ")} DELETE FROM pdpp_binary_chunks WHERE namespace='canonical' AND blob_id=OLD.blob_id; DELETE FROM pdpp_binary_manifests WHERE namespace='canonical' AND blob_id=OLD.blob_id; END`;
135
+ function assertReplicaSchema(db) {
136
+ const row = db
137
+ .prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'pdpp_replica_schema_version'")
138
+ .get()
139
+ ? db
140
+ .prepare("SELECT version FROM pdpp_replica_schema_version WHERE id = 1")
141
+ .get()
142
+ : undefined;
143
+ if (row?.version !== REPLICA_MIGRATIONS.length)
144
+ throw new Error("Readonly PDPP replica store requires the current schema");
145
+ }
146
+ /**
147
+ * Shared read predicate for canonical, replica-preview, and known-local
148
+ * projections. A key fact hides rows of exactly its generation. Without
149
+ * `generationSql` that is the binding's current generation (canonical rows).
150
+ * With it, it is the row's own generation, for overlay and local rows that can
151
+ * belong to a generation a pending reset introduces. Both halves use
152
+ * equality, so an overlay row and the canonical row of one generation always
153
+ * agree.
154
+ */
155
+ export function unquarantinedRecordSql(alias, generationSql) {
156
+ const connection = `NOT EXISTS (SELECT 1 FROM pdpp_replica_quarantined_connections q WHERE q.instance = ${alias}.instance)`;
157
+ const key = (scope) => `NOT EXISTS (SELECT 1 FROM pdpp_replica_quarantined_keys q ${scope} q.instance=${alias}.instance AND q.stream=${alias}.stream AND q.record_key=${alias}.record_key`;
158
+ return generationSql === undefined
159
+ ? `${connection} AND ${key("JOIN pdpp_instance_binding b ON b.instance=q.instance AND b.generation=q.generation WHERE")})`
160
+ : `${connection} AND ${key("WHERE")} AND q.generation = (${generationSql}))`;
161
+ }
162
+ /**
163
+ * Build the replica port of a canonical database. Applies the replica schema
164
+ * first (readonly handles must already have it).
165
+ */
166
+ export function createReplicaCanonicalPort(db) {
167
+ if (db.readonly)
168
+ assertReplicaSchema(db);
169
+ else {
170
+ // Refuse behind a closed door before any replica write.
171
+ admitReplication(db);
172
+ ensureReplicaSchema(db);
173
+ db.exec(CANONICAL_CHUNKS_TRIGGER);
174
+ }
175
+ const writerId = db
176
+ .prepare("SELECT writer_id FROM pdpp_installation_writer WHERE id = 1")
177
+ .get().writer_id;
178
+ // Captured operations name the derived operation writer. Before the first
179
+ // enable they name the installation writer and stay local: no receiver
180
+ // accepts them, and enabling refuses a journal that has them.
181
+ let journalObserver;
182
+ const journal = createReplicationJournal(db, () => currentReplicaWriterIdentity(db)?.operationWriter ?? writerId, () => journalObserver?.());
183
+ const insertLocalWrite = db.prepare(`
184
+ INSERT INTO pdpp_replica_own_writes
185
+ (operation_id, writer_id, source_id, connection_id, method, generation,
186
+ stream, record_key, operation, value_json, blob_ids_json)
187
+ VALUES (@operation_id, @writer_id, @source_id, @connection_id, @method, @generation,
188
+ @stream, @record_key, @operation, @value_json, @blob_ids_json)
189
+ `);
190
+ let visibilityObserver;
191
+ let writeBoundary;
192
+ let readBoundary;
193
+ let localWriteObserver;
194
+ // Keys written since the last settle. A TEMP table, so a rolled-back write
195
+ // (at any transaction or savepoint depth) takes its queued key with it and is
196
+ // never reconciled. It lives on this connection only and is not part of the
197
+ // database file.
198
+ db.exec("CREATE TEMP TABLE IF NOT EXISTS pdpp_replica_unsettled_writes (instance TEXT NOT NULL, stream TEXT NOT NULL, record_key TEXT NOT NULL, PRIMARY KEY (instance, stream, record_key))");
199
+ const queueLocalWrite = db.prepare("INSERT OR IGNORE INTO pdpp_replica_unsettled_writes VALUES (?, ?, ?)");
200
+ const takeLocalWrites = db.prepare("DELETE FROM pdpp_replica_unsettled_writes RETURNING instance, stream, record_key");
201
+ function replicaIntegrityEpoch(connectionKey) {
202
+ return db
203
+ .prepare(`SELECT coalesce((SELECT fences FROM pdpp_replica_integrity_fences WHERE instance = ?), 0)
204
+ + coalesce((SELECT reset_clock FROM pdpp_instance_binding WHERE instance = ?), 0) AS epoch`)
205
+ .get(connectionKey, connectionKey).epoch;
206
+ }
207
+ function replicaVisibilityEpoch(instanceIds) {
208
+ if (instanceIds) {
209
+ const ids = [...new Set(instanceIds)].sort();
210
+ const state = ids.map((id) => [id, replicaIntegrityEpoch(id)]);
211
+ return createHash("sha256").update(JSON.stringify(state)).digest("hex");
212
+ }
213
+ const exists = db
214
+ .prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='pdpp_replica_visibility_epoch'")
215
+ .get();
216
+ if (!exists)
217
+ return "uninitialized";
218
+ const row = db
219
+ .prepare("SELECT epoch FROM pdpp_replica_visibility_epoch WHERE id=1")
220
+ .get();
221
+ return row ? String(row.epoch) : "uninitialized";
222
+ }
223
+ function fenceReplicaConnection(connectionKey) {
224
+ if (!db.inTransaction)
225
+ throw new Error("an integrity fence requires the hiding transaction");
226
+ db.prepare("INSERT INTO pdpp_replica_integrity_fences VALUES (?, 1) ON CONFLICT(instance) DO UPDATE SET fences = fences + 1").run(connectionKey);
227
+ }
228
+ function cursorBinding(instanceIds, fields) {
229
+ const ids = [...new Set(instanceIds)].sort();
230
+ const integrity = Object.fromEntries(ids.map((id) => [id, replicaIntegrityEpoch(id)]));
231
+ return {
232
+ query: createHash("sha256")
233
+ .update(JSON.stringify([ids, fields ? [...fields].sort() : null]))
234
+ .digest("hex"),
235
+ integrity,
236
+ visibilityEpoch: replicaVisibilityEpoch(ids),
237
+ };
238
+ }
239
+ const port = {
240
+ unquarantinedRecordSql,
241
+ replicaVisibilityEpoch,
242
+ assertKeyWritable(instance, stream, recordKey) {
243
+ if (db
244
+ .prepare("SELECT 1 FROM pdpp_replica_quarantined_keys q JOIN pdpp_instance_binding b ON q.instance = b.instance AND q.generation = b.generation WHERE q.instance = ? AND q.stream = ? AND q.record_key = ?")
245
+ .get(instance, stream, recordKey))
246
+ throw new PdppBindingError("replica_integrity_quarantine");
247
+ },
248
+ assertConnectionWritable(instance) {
249
+ if (db
250
+ .prepare("SELECT 1 FROM pdpp_replica_quarantined_connections WHERE instance = ?")
251
+ .get(instance))
252
+ throw new PdppBindingError("replica_integrity_quarantine");
253
+ },
254
+ assertMethodTransitionAllowed() {
255
+ if (db.prepare("SELECT 1 FROM pdpp_replica_settings").get())
256
+ throw new PdppBindingError("replica_method_transition_unsupported");
257
+ },
258
+ assertStreamWritable(instance, stream, generation) {
259
+ if (db
260
+ .prepare("SELECT 1 FROM pdpp_replica_quarantined_keys WHERE instance = ? AND stream = ? AND generation = ? LIMIT 1")
261
+ .get(instance, stream, generation))
262
+ throw new PdppBindingError("replica_integrity_quarantine");
263
+ },
264
+ recordWritten(instance, stream, recordKey, semantics, primaryKey, decl) {
265
+ // Do not use getInstanceBinding's synthetic defaults for a missing legacy row.
266
+ const binding = db
267
+ .prepare("SELECT source_id, method, generation FROM pdpp_instance_binding WHERE instance = ?")
268
+ .get(instance);
269
+ const row = db
270
+ .prepare("SELECT * FROM pdpp_records WHERE instance = ? AND stream = ? AND record_key = ?")
271
+ .get(instance, stream, recordKey);
272
+ const value = row.deleted
273
+ ? {
274
+ instance,
275
+ stream,
276
+ recordKey,
277
+ version: row.version,
278
+ deletedAt: row.deleted_at ?? row.emitted_at,
279
+ emittedAt: row.emitted_at,
280
+ deleted: true,
281
+ }
282
+ : {
283
+ instance,
284
+ stream,
285
+ recordKey,
286
+ data: row.data ? JSON.parse(row.data) : {},
287
+ version: row.version,
288
+ emittedAt: row.emitted_at,
289
+ deleted: false,
290
+ };
291
+ const blobId = row.deleted ? null : row.blob_id;
292
+ insertLocalWrite.run({
293
+ operation_id: randomUUID(),
294
+ writer_id: writerId,
295
+ source_id: binding?.source_id ?? null,
296
+ connection_id: instance,
297
+ method: binding?.method ?? null,
298
+ generation: binding?.generation ?? null,
299
+ stream,
300
+ record_key: recordKey,
301
+ operation: row.deleted ? "delete" : "upsert",
302
+ value_json: JSON.stringify(value),
303
+ blob_ids_json: JSON.stringify(blobId ? [blobId] : []),
304
+ });
305
+ journal.captureRecord(instance, stream, recordKey, semantics, primaryKey, decl);
306
+ queueLocalWrite.run(instance, stream, recordKey);
307
+ visibilityObserver?.();
308
+ },
309
+ settleLocalWrites() {
310
+ const writes = takeLocalWrites.all();
311
+ for (const { instance, stream, record_key } of writes)
312
+ localWriteObserver?.(instance, stream, record_key);
313
+ },
314
+ captureInvalidation: journal.captureInvalidation,
315
+ captureCompletion: journal.captureCompletion,
316
+ captureLifecycle: (instance, kind) => journal.captureLifecycle(instance, kind),
317
+ captureBlob: journal.captureBlob,
318
+ notifyVisibility: () => visibilityObserver?.(),
319
+ exclusive: (write) => {
320
+ const captured = () => captureWrites(db, write);
321
+ return writeBoundary
322
+ ? writeBoundary(captured)
323
+ : db.transaction(captured).immediate();
324
+ },
325
+ snapshot: (read) => readBoundary ? readBoundary(read) : db.transaction(read).deferred(),
326
+ cursorBinding,
327
+ assertCursorIntegrity(payload, instanceIds, fields) {
328
+ const current = cursorBinding(instanceIds, fields);
329
+ if (payload.query !== undefined && payload.query !== current.query)
330
+ throw new InvalidCursorError();
331
+ if (payload.query === undefined ||
332
+ JSON.stringify(payload.integrity) !==
333
+ JSON.stringify(current.integrity) ||
334
+ payload.visibilityEpoch !== current.visibilityEpoch)
335
+ throw new CursorExpiredError();
336
+ },
337
+ blobBytes: {
338
+ has: (blobId) => db
339
+ .prepare("SELECT 1 FROM pdpp_blob_bytes WHERE blob_id = ?")
340
+ .get(blobId) !== undefined ||
341
+ binaryLength(db, "canonical", blobId) !== undefined,
342
+ // A forged or incomplete manifest cannot force a whole-value allocation.
343
+ readVerified: (meta) => {
344
+ const hasChunkCopy = db
345
+ .prepare("SELECT 1 FROM pdpp_binary_manifests WHERE namespace = 'canonical' AND blob_id = ?")
346
+ .get(meta.blobId) !== undefined;
347
+ if (verifyBinary(db, "canonical", meta.blobId, `sha256:${meta.sha256}`, meta.sizeBytes)) {
348
+ const chunked = readBinary(db, "canonical", meta.blobId);
349
+ if (chunked)
350
+ return chunked;
351
+ }
352
+ if (hasChunkCopy)
353
+ return undefined;
354
+ const row = db
355
+ .prepare("SELECT bytes FROM pdpp_blob_bytes WHERE blob_id = ?")
356
+ .get(meta.blobId);
357
+ if (!row || row.bytes.length !== meta.sizeBytes)
358
+ return undefined;
359
+ const bytes = new Uint8Array(row.bytes);
360
+ return createHash("sha256").update(bytes).digest("hex") === meta.sha256
361
+ ? bytes
362
+ : undefined;
363
+ },
364
+ // A malformed manifest vetoes every reader; a blob write repairs it.
365
+ clearMalformed: (blobId) => clearMalformedManifest(db, "canonical", blobId),
366
+ write: (blobId, bytes) => writeCanonicalBinary(db, blobId, bytes),
367
+ },
368
+ };
369
+ return {
370
+ port,
371
+ writerId,
372
+ exporter: journal.exporter,
373
+ setReplicaVisibilityObserver(observer) {
374
+ visibilityObserver = observer;
375
+ },
376
+ /** The visibility view's `exclusive` and `snapshot`: where canonical transactions begin. */
377
+ setReplicaWriteBoundary(write, read) {
378
+ writeBoundary = write;
379
+ readBoundary = read;
380
+ },
381
+ /**
382
+ * Called for each operation appended to the local journal (a record,
383
+ * blob, completion or lifecycle write; never an import), inside the
384
+ * write's transaction. The observer must defer its effect past the
385
+ * transaction: a rolled-back write may still have called it.
386
+ */
387
+ setReplicaJournalObserver(observer) {
388
+ journalObserver = observer;
389
+ },
390
+ /** Called for each locally written key when the store settles, inside the write's transaction. */
391
+ setReplicaLocalWriteObserver(observer) {
392
+ localWriteObserver = observer;
393
+ },
394
+ replicaIntegrityEpoch,
395
+ replicaVisibilityEpoch,
396
+ fenceReplicaConnection,
397
+ replicaBindingConflict(connectionId) {
398
+ return !!db
399
+ .prepare("SELECT 1 FROM pdpp_replica_binding_conflicts WHERE instance = ?")
400
+ .get(connectionId);
401
+ },
402
+ /**
403
+ * Record that a connection's evidence disagrees with its binding. The
404
+ * fact is append-only and puts the connection in the conflicted state
405
+ * (the visibility view hides it from apps; the owner sees local rows),
406
+ * and it raises the integrity epoch in the same transaction. Idempotent:
407
+ * returns true only when this call recorded it.
408
+ */
409
+ markReplicaBindingConflict(input) {
410
+ return db.transaction(() => {
411
+ const recorded = db
412
+ .prepare("INSERT OR IGNORE INTO pdpp_replica_binding_conflicts VALUES (?, ?, ?)")
413
+ .run(input.connectionId, input.reason, JSON.stringify(input.evidence)).changes > 0;
414
+ if (!recorded)
415
+ return false;
416
+ fenceReplicaConnection(input.connectionId);
417
+ return true;
418
+ })();
419
+ },
420
+ cursorBinding,
421
+ };
422
+ }
423
+ /**
424
+ * The canonical store with replication enabled: replica schema applied,
425
+ * captures, quarantine guards and integrity-bound cursors on. Only the
426
+ * replication composition and replica tests construct it.
427
+ */
428
+ export function createReplicaRecordStore(db, options = {}) {
429
+ let replica;
430
+ const store = createSqliteRecordStore(db, {
431
+ ...options,
432
+ replica: () => (replica = createReplicaCanonicalPort(db)).port,
433
+ });
434
+ const r = replica;
435
+ return Object.assign(store, {
436
+ unquarantinedRecordSql,
437
+ replication: r.exporter,
438
+ getInstallationWriterId: () => r.writerId,
439
+ setReplicaVisibilityObserver: r.setReplicaVisibilityObserver,
440
+ setReplicaWriteBoundary: r.setReplicaWriteBoundary,
441
+ setReplicaLocalWriteObserver: r.setReplicaLocalWriteObserver,
442
+ setReplicaJournalObserver: r.setReplicaJournalObserver,
443
+ replicaIntegrityEpoch: r.replicaIntegrityEpoch,
444
+ replicaVisibilityEpoch: r.replicaVisibilityEpoch,
445
+ fenceReplicaConnection: r.fenceReplicaConnection,
446
+ replicaBindingConflict: r.replicaBindingConflict,
447
+ markReplicaBindingConflict: r.markReplicaBindingConflict,
448
+ cursorBinding: r.cursorBinding,
449
+ });
450
+ }
451
+ //# sourceMappingURL=pdpp-replica-canonical-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdpp-replica-canonical-port.js","sourceRoot":"","sources":["../../src/storage/pdpp-replica-canonical-port.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GAEnB,MAAM,4DAA4D,CAAC;AACpE,OAAO,EACL,uBAAuB,EACvB,YAAY,EACZ,sBAAsB,EACtB,UAAU,EACV,YAAY,EACZ,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACL,kBAAkB,EAClB,8BAA8B,EAC9B,2BAA2B,GAC5B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,iCAAiC,EACjC,kCAAkC,GAEnC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,4BAA4B,EAC5B,iCAAiC,GAClC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,uBAAuB,EACvB,gBAAgB,GAGjB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE7E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,gFAAgF;IAChF,sDAAsD;IACtD,qCAAqC;IACrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BD;IACC,qBAAqB;IACrB,kBAAkB;IAClB,qDAAqD;IACrD,0EAA0E;IAC1E,uEAAuE;IACvE,uEAAuE;IACvE,uBAAuB;IACvB,+CAA+C;IAC/C,2BAA2B;IAC3B,yDAAyD;IACzD,sBAAsB;IACtB,yDAAyD;IACzD,8BAA8B;IAC9B,uDAAuD;IACvD,kCAAkC;IAClC,0EAA0E;IAC1E,iCAAiC;IACjC,oEAAoE;IACpE,iCAAiC;IACjC,wEAAwE;IACxE,gCAAgC;IAChC,+EAA+E;CAChF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAY;IAC9C,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;QAClB,EAAE,CAAC,IAAI,CAAC;;;;;;KAMP,CAAC,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE;aACnB,OAAO,CAAC,8DAA8D,CAAC;aACvE,GAAG,EAAyB,CAAC;QAChC,IAAI,OAAO,GAAG,kBAAkB,CAAC,MAAM;YACrC,MAAM,IAAI,KAAK,CACb,+BAA+B,OAAO,uCAAuC,kBAAkB,CAAC,MAAM,sBAAsB,CAC7H,CAAC;QACJ,KAAK,IAAI,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,kBAAkB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzD,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC;gBACT,EAAE,CAAC,OAAO,CACR,8EAA8E,CAC/E,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;QACxB,CAAC;QACD,EAAE,CAAC,OAAO,CACR,iEAAiE,CAClE,CAAC,GAAG,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACjC,yEAAyE;QACzE,oEAAoE;QACpE,qDAAqD;QACrD,EAAE,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;QAC/D,sEAAsE;QACtE,yEAAyE;QACzE,MAAM,OAAO,GAAG,2HAA2H,CAAC;QAC5I,MAAM,IAAI,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QACzE,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAE9C;YACD,KAAK,MAAM,SAAS,IAAI,IAAI;gBAAE,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/D,EAAE,CAAC,IAAI,CAAC;;;KAGP,CAAC,CAAC;IACL,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,SAAS,sBAAsB,CAAC,EAAU;IACxC,MAAM,OAAO,GAAG,8DAA8D,EAAE,8FAA8F,EAAE,GAAG,CAAC;IACpL,OAAO;QACL,4FAA4F,EAAE,QAAQ,OAAO,GAAG;QAChH,2IAA2I,EAAE,QAAQ,OAAO,GAAG;QAC/J,oDAAoD,EAAE,yFAAyF,EAAE,IAAI;KACtJ,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,wBAAwB,GAAG,mGAAmG,sBAAsB,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,iLAAiL,CAAC;AAErW,SAAS,mBAAmB,CAAC,EAAY;IACvC,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CACN,2FAA2F,CAC5F;SACA,GAAG,EAAE;QACN,CAAC,CAAE,EAAE;aACA,OAAO,CAAC,8DAA8D,CAAC;aACvE,GAAG,EAAsC;QAC9C,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,GAAG,EAAE,OAAO,KAAK,kBAAkB,CAAC,MAAM;QAC5C,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;AAC/E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CACpC,KAAa,EACb,aAAsB;IAEtB,MAAM,UAAU,GAAG,uFAAuF,KAAK,YAAY,CAAC;IAC5H,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,EAAE,CAC5B,6DAA6D,KAAK,eAAe,KAAK,0BAA0B,KAAK,4BAA4B,KAAK,aAAa,CAAC;IACtK,OAAO,aAAa,KAAK,SAAS;QAChC,CAAC,CAAC,GAAG,UAAU,QAAQ,GAAG,CAAC,2FAA2F,CAAC,GAAG;QAC1H,CAAC,CAAC,GAAG,UAAU,QAAQ,GAAG,CAAC,OAAO,CAAC,wBAAwB,aAAa,IAAI,CAAC;AACjF,CAAC;AAqFD;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAC,EAAY;IACrD,IAAI,EAAE,CAAC,QAAQ;QAAE,mBAAmB,CAAC,EAAE,CAAC,CAAC;SACpC,CAAC;QACJ,wDAAwD;QACxD,gBAAgB,CAAC,EAAE,CAAC,CAAC;QACrB,mBAAmB,CAAC,EAAE,CAAC,CAAC;QACxB,EAAE,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,QAAQ,GACZ,EAAE;SACC,OAAO,CAAC,6DAA6D,CAAC;SACtE,GAAG,EACP,CAAC,SAAS,CAAC;IACZ,0EAA0E;IAC1E,uEAAuE;IACvE,8DAA8D;IAC9D,IAAI,eAAyC,CAAC;IAC9C,MAAM,OAAO,GAAG,wBAAwB,CACtC,EAAE,EACF,GAAG,EAAE,CAAC,4BAA4B,CAAC,EAAE,CAAC,EAAE,eAAe,IAAI,QAAQ,EACnE,GAAG,EAAE,CAAC,eAAe,EAAE,EAAE,CAC1B,CAAC;IACF,MAAM,gBAAgB,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;GAMnC,CAAC,CAAC;IACH,IAAI,kBAA4C,CAAC;IACjD,IAAI,aAAqD,CAAC;IAC1D,IAAI,YAAmD,CAAC;IACxD,IAAI,kBACyE,CAAC;IAC9E,2EAA2E;IAC3E,8EAA8E;IAC9E,4EAA4E;IAC5E,iBAAiB;IACjB,EAAE,CAAC,IAAI,CACL,oLAAoL,CACrL,CAAC;IACF,MAAM,eAAe,GAAG,EAAE,CAAC,OAAO,CAChC,sEAAsE,CACvE,CAAC;IACF,MAAM,eAAe,GAAG,EAAE,CAAC,OAAO,CAChC,kFAAkF,CACnF,CAAC;IAEF,SAAS,qBAAqB,CAAC,aAAqB;QAClD,OACE,EAAE;aACC,OAAO,CACN;sGAC4F,CAC7F;aACA,GAAG,CAAC,aAAa,EAAE,aAAa,CACpC,CAAC,KAAK,CAAC;IACV,CAAC;IACD,SAAS,sBAAsB,CAAC,WAAsB;QACpD,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,qBAAqB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/D,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1E,CAAC;QACD,MAAM,MAAM,GAAG,EAAE;aACd,OAAO,CACN,yFAAyF,CAC1F;aACA,GAAG,EAAE,CAAC;QACT,IAAI,CAAC,MAAM;YAAE,OAAO,eAAe,CAAC;QACpC,MAAM,GAAG,GAAG,EAAE;aACX,OAAO,CAAC,4DAA4D,CAAC;aACrE,GAAG,EAAmC,CAAC;QAC1C,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC;IACnD,CAAC;IACD,SAAS,sBAAsB,CAAC,aAAqB;QACnD,IAAI,CAAC,EAAE,CAAC,aAAa;YACnB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACxE,EAAE,CAAC,OAAO,CACR,iHAAiH,CAClH,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACvB,CAAC;IACD,SAAS,aAAa,CACpB,WAAqB,EACrB,MAA4B;QAE5B,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAClC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,qBAAqB,CAAC,EAAE,CAAC,CAAC,CAAC,CACjD,CAAC;QACF,OAAO;YACL,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC;iBACxB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;iBACjE,MAAM,CAAC,KAAK,CAAC;YAChB,SAAS;YACT,eAAe,EAAE,sBAAsB,CAAC,GAAG,CAAC;SAC7C,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAyB;QACjC,sBAAsB;QACtB,sBAAsB;QACtB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS;YAC3C,IACE,EAAE;iBACC,OAAO,CACN,kMAAkM,CACnM;iBACA,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC;gBAEnC,MAAM,IAAI,gBAAgB,CAAC,8BAA8B,CAAC,CAAC;QAC/D,CAAC;QACD,wBAAwB,CAAC,QAAQ;YAC/B,IACE,EAAE;iBACC,OAAO,CACN,uEAAuE,CACxE;iBACA,GAAG,CAAC,QAAQ,CAAC;gBAEhB,MAAM,IAAI,gBAAgB,CAAC,8BAA8B,CAAC,CAAC;QAC/D,CAAC;QACD,6BAA6B;YAC3B,IAAI,EAAE,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC,GAAG,EAAE;gBACzD,MAAM,IAAI,gBAAgB,CAAC,uCAAuC,CAAC,CAAC;QACxE,CAAC;QACD,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU;YAC/C,IACE,EAAE;iBACC,OAAO,CACN,0GAA0G,CAC3G;iBACA,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC;gBAEpC,MAAM,IAAI,gBAAgB,CAAC,8BAA8B,CAAC,CAAC;QAC/D,CAAC;QACD,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI;YACpE,+EAA+E;YAC/E,MAAM,OAAO,GAAG,EAAE;iBACf,OAAO,CACN,oFAAoF,CACrF;iBACA,GAAG,CAAC,QAAQ,CAMF,CAAC;YACd,MAAM,GAAG,GAAG,EAAE;iBACX,OAAO,CACN,iFAAiF,CAClF;iBACA,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAOjC,CAAC;YACF,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO;gBACvB,CAAC,CAAC;oBACE,QAAQ;oBACR,MAAM;oBACN,SAAS;oBACT,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,SAAS,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,UAAU;oBAC3C,SAAS,EAAE,GAAG,CAAC,UAAU;oBACzB,OAAO,EAAE,IAAI;iBACd;gBACH,CAAC,CAAC;oBACE,QAAQ;oBACR,MAAM;oBACN,SAAS;oBACT,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;oBAC1C,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,SAAS,EAAE,GAAG,CAAC,UAAU;oBACzB,OAAO,EAAE,KAAK;iBACf,CAAC;YACN,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;YAChD,gBAAgB,CAAC,GAAG,CAAC;gBACnB,YAAY,EAAE,UAAU,EAAE;gBAC1B,SAAS,EAAE,QAAQ;gBACnB,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI;gBACrC,aAAa,EAAE,QAAQ;gBACvB,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,IAAI;gBAC/B,UAAU,EAAE,OAAO,EAAE,UAAU,IAAI,IAAI;gBACvC,MAAM;gBACN,UAAU,EAAE,SAAS;gBACrB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;gBAC5C,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;gBACjC,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aACtD,CAAC,CAAC;YACH,OAAO,CAAC,aAAa,CACnB,QAAQ,EACR,MAAM,EACN,SAAS,EACT,SAAS,EACT,UAAU,EACV,IAAI,CACL,CAAC;YACF,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;YACjD,kBAAkB,EAAE,EAAE,CAAC;QACzB,CAAC;QACD,iBAAiB;YACf,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,EAI/B,CAAC;YACJ,KAAK,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,MAAM;gBACnD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;QACvD,CAAC;QACD,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;QAChD,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,gBAAgB,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CACnC,OAAO,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC;QAC1C,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,gBAAgB,EAAE,GAAG,EAAE,CAAC,kBAAkB,EAAE,EAAE;QAC9C,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YACnB,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAChD,OAAO,aAAa;gBAClB,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,CAAC;QAC3C,CAAC;QACD,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CACjB,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;QACrE,aAAa;QACb,qBAAqB,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM;YAChD,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YACnD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK;gBAChE,MAAM,IAAI,kBAAkB,EAAE,CAAC;YACjC,IACE,OAAO,CAAC,KAAK,KAAK,SAAS;gBAC3B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;oBAC/B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;gBACnC,OAAO,CAAC,eAAe,KAAK,OAAO,CAAC,eAAe;gBAEnD,MAAM,IAAI,kBAAkB,EAAE,CAAC;QACnC,CAAC;QACD,SAAS,EAAE;YACT,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,CACd,EAAE;iBACC,OAAO,CAAC,iDAAiD,CAAC;iBAC1D,GAAG,CAAC,MAAM,CAAC,KAAK,SAAS;gBAC5B,YAAY,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,KAAK,SAAS;YACrD,yEAAyE;YACzE,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE;gBACrB,MAAM,YAAY,GAChB,EAAE;qBACC,OAAO,CACN,mFAAmF,CACpF;qBACA,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC;gBACpC,IACE,YAAY,CACV,EAAE,EACF,WAAW,EACX,IAAI,CAAC,MAAM,EACX,UAAU,IAAI,CAAC,MAAM,EAAE,EACvB,IAAI,CAAC,SAAS,CACf,EACD,CAAC;oBACD,MAAM,OAAO,GAAG,UAAU,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;oBACzD,IAAI,OAAO;wBAAE,OAAO,OAAO,CAAC;gBAC9B,CAAC;gBACD,IAAI,YAAY;oBAAE,OAAO,SAAS,CAAC;gBACnC,MAAM,GAAG,GAAG,EAAE;qBACX,OAAO,CAAC,qDAAqD,CAAC;qBAC9D,GAAG,CAAC,IAAI,CAAC,MAAM,CAAkC,CAAC;gBACrD,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS;oBAAE,OAAO,SAAS,CAAC;gBAClE,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACxC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,MAAM;oBACrE,CAAC,CAAE,KAAiC;oBACpC,CAAC,CAAC,SAAS,CAAC;YAChB,CAAC;YACD,qEAAqE;YACrE,cAAc,EAAE,CAAC,MAAM,EAAE,EAAE,CACzB,sBAAsB,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC;YACjD,KAAK,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC;SAClE;KACF,CAAC;IAEF,OAAO;QACL,IAAI;QACJ,QAAQ;QACR,QAAQ,EAAE,OAAO,CAAC,QAA6B;QAC/C,4BAA4B,CAAC,QAAoB;YAC/C,kBAAkB,GAAG,QAAQ,CAAC;QAChC,CAAC;QACD,4FAA4F;QAC5F,uBAAuB,CACrB,KAA+B,EAC/B,IAA6B;YAE7B,aAAa,GAAG,KAAK,CAAC;YACtB,YAAY,GAAG,IAAI,CAAC;QACtB,CAAC;QACD;;;;;WAKG;QACH,yBAAyB,CAAC,QAAoB;YAC5C,eAAe,GAAG,QAAQ,CAAC;QAC7B,CAAC;QACD,kGAAkG;QAClG,4BAA4B,CAC1B,QAAuE;YAEvE,kBAAkB,GAAG,QAAQ,CAAC;QAChC,CAAC;QACD,qBAAqB;QACrB,sBAAsB;QACtB,sBAAsB;QACtB,sBAAsB,CAAC,YAAoB;YACzC,OAAO,CAAC,CAAC,EAAE;iBACR,OAAO,CACN,iEAAiE,CAClE;iBACA,GAAG,CAAC,YAAY,CAAC,CAAC;QACvB,CAAC;QACD;;;;;;WAMG;QACH,0BAA0B,CAAC,KAI1B;YACC,OAAO,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;gBACzB,MAAM,QAAQ,GACZ,EAAE;qBACC,OAAO,CACN,uEAAuE,CACxE;qBACA,GAAG,CACF,KAAK,CAAC,YAAY,EAClB,KAAK,CAAC,MAAM,EACZ,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAC/B,CAAC,OAAO,GAAG,CAAC,CAAC;gBAClB,IAAI,CAAC,QAAQ;oBAAE,OAAO,KAAK,CAAC;gBAC5B,sBAAsB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;gBAC3C,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,EAAE,CAAC;QACP,CAAC;QACD,aAAa;KACd,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,EAAY,EACZ,UAAqD,EAAE;IAEvD,IAAI,OAAkE,CAAC;IACvE,MAAM,KAAK,GAAG,uBAAuB,CAAC,EAAE,EAAE;QACxC,GAAG,OAAO;QACV,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,GAAG,0BAA0B,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;KAC/D,CAAC,CAAC;IACH,MAAM,CAAC,GAAG,OAAQ,CAAC;IACnB,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QAC1B,sBAAsB;QACtB,WAAW,EAAE,CAAC,CAAC,QAAQ;QACvB,uBAAuB,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ;QACzC,4BAA4B,EAAE,CAAC,CAAC,4BAA4B;QAC5D,uBAAuB,EAAE,CAAC,CAAC,uBAAuB;QAClD,4BAA4B,EAAE,CAAC,CAAC,4BAA4B;QAC5D,yBAAyB,EAAE,CAAC,CAAC,yBAAyB;QACtD,qBAAqB,EAAE,CAAC,CAAC,qBAAqB;QAC9C,sBAAsB,EAAE,CAAC,CAAC,sBAAsB;QAChD,sBAAsB,EAAE,CAAC,CAAC,sBAAsB;QAChD,sBAAsB,EAAE,CAAC,CAAC,sBAAsB;QAChD,0BAA0B,EAAE,CAAC,CAAC,0BAA0B;QACxD,aAAa,EAAE,CAAC,CAAC,aAAa;KAC/B,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { Database } from "better-sqlite3";
2
+ import type { ReplicaCoordinatorStatePort } from "@opendatalabs/personal-server-ts-core/replication/coordinator";
3
+ export { REPLICA_COORDINATOR_SCHEMA } from "@opendatalabs/personal-server-ts-core/replication/coordinator-state";
4
+ /**
5
+ * This adapter does NOT acquire or replace Node's exclusive writer lock.
6
+ * It only fences the existing token inside the receiver's write transaction.
7
+ * Registration intent/recovery tables and their state machine are untouched.
8
+ * The rotation rules are core's, shared with PS-Lite's adapter.
9
+ */
10
+ export declare function createSqliteReplicaCoordinatorState(input: {
11
+ db: Database;
12
+ owner: () => string | undefined;
13
+ /** Use receiver.atomically: all attempt projection work shares this boundary. */
14
+ atomically: <T>(run: () => T) => T;
15
+ }): ReplicaCoordinatorStatePort;
16
+ //# sourceMappingURL=pdpp-replica-coordinator-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdpp-replica-coordinator-state.d.ts","sourceRoot":"","sources":["../../src/storage/pdpp-replica-coordinator-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+DAA+D,CAAC;AAQjH,OAAO,EAAE,0BAA0B,EAAE,MAAM,qEAAqE,CAAC;AAEjH;;;;;GAKG;AACH,wBAAgB,mCAAmC,CAAC,KAAK,EAAE;IACzD,EAAE,EAAE,QAAQ,CAAC;IACb,KAAK,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAChC,iFAAiF;IACjF,UAAU,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;CACpC,GAAG,2BAA2B,CAmB9B"}
@@ -0,0 +1,25 @@
1
+ import { commitReplicaCoordinatorState, loadReplicaCoordinatorState, } from "@opendatalabs/personal-server-ts-core/replication/coordinator-state";
2
+ import { runEffectSync } from "@opendatalabs/personal-server-ts-core/replication/effects";
3
+ import { nodeReplicaContext } from "./pdpp-replica-sql.js";
4
+ export { REPLICA_COORDINATOR_SCHEMA } from "@opendatalabs/personal-server-ts-core/replication/coordinator-state";
5
+ /**
6
+ * This adapter does NOT acquire or replace Node's exclusive writer lock.
7
+ * It only fences the existing token inside the receiver's write transaction.
8
+ * Registration intent/recovery tables and their state machine are untouched.
9
+ * The rotation rules are core's, shared with PS-Lite's adapter.
10
+ */
11
+ export function createSqliteReplicaCoordinatorState(input) {
12
+ const { db } = input;
13
+ const context = nodeReplicaContext(db);
14
+ return {
15
+ load: () => runEffectSync(loadReplicaCoordinatorState(input.owner), context),
16
+ commit(expected, next, checkpoint) {
17
+ return input.atomically(() => {
18
+ if (!db.inTransaction)
19
+ throw new Error("coordinator requires a write transaction");
20
+ return runEffectSync(commitReplicaCoordinatorState(input.owner, expected, next, () => checkpoint()), context);
21
+ });
22
+ },
23
+ };
24
+ }
25
+ //# sourceMappingURL=pdpp-replica-coordinator-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdpp-replica-coordinator-state.js","sourceRoot":"","sources":["../../src/storage/pdpp-replica-coordinator-state.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,6BAA6B,EAC7B,2BAA2B,GAC5B,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,2DAA2D,CAAC;AAC1F,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,qEAAqE,CAAC;AAEjH;;;;;GAKG;AACH,MAAM,UAAU,mCAAmC,CAAC,KAKnD;IACC,MAAM,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC;IACrB,MAAM,OAAO,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAAC;IACvC,OAAO;QACL,IAAI,EAAE,GAAG,EAAE,CACT,aAAa,CAAC,2BAA2B,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAClE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,UAAU;YAC/B,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE;gBAC3B,IAAI,CAAC,EAAE,CAAC,aAAa;oBACnB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;gBAC9D,OAAO,aAAa,CAClB,6BAA6B,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,CAC9D,UAAU,EAAE,CACb,EACD,OAAO,CACR,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,81 @@
1
+ import type { Database } from "better-sqlite3";
2
+ import type { ReplicaEnvelope } from "@opendatalabs/personal-server-ts-core/replication/envelope";
3
+ import type { CopyDecision, FinalizedFact } from "@opendatalabs/personal-server-ts-core/replication/copy-promotion";
4
+ import { type StagedCopy } from "@opendatalabs/personal-server-ts-core/replication/copies";
5
+ /**
6
+ * Batch-copy retention, finalized-fact history and batch disposition
7
+ * (contract v3.1, replica-copy-promotion-contract-1021-v3.md) on Node. The
8
+ * transitions are core's (`core/replication/copies.ts`), shared with PS-Lite;
9
+ * this binds them to one better-sqlite3 connection. Every transition is one
10
+ * SQLite transaction and idempotent under replay.
11
+ */
12
+ export { REPLICA_COPY_MIGRATION, ReplicaCopyRefused, type CopyFragment, type CopyPromotion, type StagedCopy, } from "@opendatalabs/personal-server-ts-core/replication/copies";
13
+ export { REPLICA_REFETCH_BUDGET } from "@opendatalabs/personal-server-ts-core/replication/copy-promotion";
14
+ export declare function createReplicaCopies(deps: {
15
+ db: Database;
16
+ owner: string;
17
+ /** Import an envelope into canonical state (the receiver's import). */
18
+ importEnvelope(envelope: ReplicaEnvelope, blobs: StagedCopy["blobs"], id: string): void;
19
+ /**
20
+ * Withdraw a connection from every reader: connection quarantine, canonical
21
+ * withdrawal and an integrity epoch raise, in the caller's transaction.
22
+ */
23
+ quarantineConnection(instance: string): void;
24
+ /**
25
+ * The single pending preview of a batch, keyed by id: at most one copy is
26
+ * ever `pending` (contract B), so the read side keeps its id key.
27
+ */
28
+ preview: {
29
+ show(id: string, envelope: ReplicaEnvelope, blobsJson: string): void;
30
+ hide(id: string, state: "confirmed" | "quarantined"): void;
31
+ };
32
+ /** Drop pending custody bytes no retained copy still needs. */
33
+ releaseBytes(id: string, blobIds: readonly string[]): void;
34
+ now: () => number;
35
+ }): {
36
+ REPLICA_COPY_MIGRATION: string;
37
+ decide: (id: string, refetch: {
38
+ attempts: number;
39
+ budget: number;
40
+ }) => CopyDecision;
41
+ disposition: (id: string) => import("@opendatalabs/personal-server-ts-core/replication/copy-promotion").CopyDisposition;
42
+ copies: (id: string) => {
43
+ copyKey: import("@opendatalabs/personal-server-ts-core/replication/copy-promotion").Hex;
44
+ state: "confirmed" | "pending" | "quarantined";
45
+ reason: "finalized_conflict" | "copy_conflict" | null;
46
+ envelopeDigest: string;
47
+ }[];
48
+ /**
49
+ * Retain one valid copy (contract §3 "Stage copy", amendment C), then
50
+ * decide and apply the quarantine set. Returns the copy key and decision.
51
+ * An input failing a validity check is recorded as a reject only.
52
+ */
53
+ stage: (copy: StagedCopy, refetch: {
54
+ attempts: number;
55
+ budget: number;
56
+ }) => {
57
+ copyKey: import("@opendatalabs/personal-server-ts-core/replication/copy-promotion").Hex | undefined;
58
+ decision: CopyDecision;
59
+ };
60
+ /**
61
+ * Append a verified finalized fact for one registered slot (F2). A fact
62
+ * from another owner is refused (a diagnostic, never a fact). Returns
63
+ * true when it is new.
64
+ */
65
+ recordFact: (input: {
66
+ id: string;
67
+ scope: string;
68
+ fragmentIndex: number;
69
+ fact: FinalizedFact;
70
+ }) => boolean;
71
+ /** Apply a non-promoting decision's durable effects (coordinator step). */
72
+ apply(id: string, decision: CopyDecision): void;
73
+ terminate(id: string, reason: string): void;
74
+ /** Promote one copy (contract §3, amendments E and F). */
75
+ promote: (input: {
76
+ id: string;
77
+ copyKey?: string;
78
+ }) => import("@opendatalabs/personal-server-ts-core/replication/copies").CopyPromotion;
79
+ };
80
+ export type ReplicaCopies = ReturnType<typeof createReplicaCopies>;
81
+ //# sourceMappingURL=pdpp-replica-copies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdpp-replica-copies.d.ts","sourceRoot":"","sources":["../../src/storage/pdpp-replica-copies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4DAA4D,CAAC;AAClG,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACd,MAAM,kEAAkE,CAAC;AAM1E,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,0DAA0D,CAAC;AAGlE;;;;;;GAMG;AACH,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,0DAA0D,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kEAAkE,CAAC;AAE1G,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,EAAE,EAAE,QAAQ,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,cAAc,CACZ,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,EAC1B,EAAE,EAAE,MAAM,GACT,IAAI,CAAC;IACR;;;OAGG;IACH,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C;;;OAGG;IACH,OAAO,EAAE;QACP,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACrE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,aAAa,GAAG,IAAI,CAAC;KAC5D,CAAC;IACF,+DAA+D;IAC/D,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IAC3D,GAAG,EAAE,MAAM,MAAM,CAAC;CACnB;;iBA0BgB,MAAM,WAAW;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;sBAEhD,MAAM;iBACX,MAAM;;;;;;IACnB;;;;OAIG;kBACW,UAAU,WAAW;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;;;;IAEvE;;;;OAIG;wBACiB;QAClB,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,aAAa,CAAC;KACrB;IACD,2EAA2E;cACjE,MAAM,YAAY,YAAY;kBAG1B,MAAM,UAAU,MAAM;IAGpC,0DAA0D;qBACzC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;EAGpD;AACD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC"}