@x12i/memorix-service 3.12.4 → 3.14.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 (171) hide show
  1. package/README.md +1 -1
  2. package/dist/analytics/host.d.ts +2 -2
  3. package/dist/analytics/host.d.ts.map +1 -1
  4. package/dist/analytics/host.js.map +1 -1
  5. package/dist/analytics/read-row.d.ts +33 -0
  6. package/dist/analytics/read-row.d.ts.map +1 -0
  7. package/dist/analytics/read-row.js +76 -0
  8. package/dist/analytics/read-row.js.map +1 -0
  9. package/dist/analytics/tracker.d.ts +14 -0
  10. package/dist/analytics/tracker.d.ts.map +1 -1
  11. package/dist/analytics/tracker.js +55 -17
  12. package/dist/analytics/tracker.js.map +1 -1
  13. package/dist/anomaly/catalog.d.ts +4 -0
  14. package/dist/anomaly/catalog.d.ts.map +1 -0
  15. package/dist/anomaly/catalog.js +315 -0
  16. package/dist/anomaly/catalog.js.map +1 -0
  17. package/dist/anomaly/descriptors.d.ts +11 -0
  18. package/dist/anomaly/descriptors.d.ts.map +1 -0
  19. package/dist/anomaly/descriptors.js +113 -0
  20. package/dist/anomaly/descriptors.js.map +1 -0
  21. package/dist/anomaly/index.d.ts +6 -0
  22. package/dist/anomaly/index.d.ts.map +1 -0
  23. package/dist/anomaly/index.js +5 -0
  24. package/dist/anomaly/index.js.map +1 -0
  25. package/dist/anomaly/records.d.ts +28 -0
  26. package/dist/anomaly/records.d.ts.map +1 -0
  27. package/dist/anomaly/records.js +384 -0
  28. package/dist/anomaly/records.js.map +1 -0
  29. package/dist/anomaly/types.d.ts +116 -0
  30. package/dist/anomaly/types.d.ts.map +1 -0
  31. package/dist/anomaly/types.js +24 -0
  32. package/dist/anomaly/types.js.map +1 -0
  33. package/dist/anomaly/values.d.ts +31 -0
  34. package/dist/anomaly/values.d.ts.map +1 -0
  35. package/dist/anomaly/values.js +171 -0
  36. package/dist/anomaly/values.js.map +1 -0
  37. package/dist/app.d.ts.map +1 -1
  38. package/dist/app.js +12 -0
  39. package/dist/app.js.map +1 -1
  40. package/dist/catalog-bridge.d.ts +21 -3
  41. package/dist/catalog-bridge.d.ts.map +1 -1
  42. package/dist/catalog-bridge.js +148 -34
  43. package/dist/catalog-bridge.js.map +1 -1
  44. package/dist/errors.d.ts +5 -0
  45. package/dist/errors.d.ts.map +1 -1
  46. package/dist/errors.js +18 -0
  47. package/dist/errors.js.map +1 -1
  48. package/dist/knowledge-upstream.d.ts +32 -0
  49. package/dist/knowledge-upstream.d.ts.map +1 -1
  50. package/dist/knowledge-upstream.js +86 -2
  51. package/dist/knowledge-upstream.js.map +1 -1
  52. package/dist/mcp/nexum-tools.d.ts +1 -1
  53. package/dist/mcp/nexum-tools.d.ts.map +1 -1
  54. package/dist/mcp/nexum-tools.js +39 -22
  55. package/dist/mcp/nexum-tools.js.map +1 -1
  56. package/dist/metadata-view.d.ts +30 -0
  57. package/dist/metadata-view.d.ts.map +1 -0
  58. package/dist/metadata-view.js +67 -0
  59. package/dist/metadata-view.js.map +1 -0
  60. package/dist/nexum-analysis/enqueue.d.ts +1 -1
  61. package/dist/nexum-analysis/enqueue.d.ts.map +1 -1
  62. package/dist/nexum-analysis/enqueue.js +4 -2
  63. package/dist/nexum-analysis/enqueue.js.map +1 -1
  64. package/dist/nexum-analysis/knowledge-read.d.ts +45 -0
  65. package/dist/nexum-analysis/knowledge-read.d.ts.map +1 -0
  66. package/dist/nexum-analysis/knowledge-read.js +26 -0
  67. package/dist/nexum-analysis/knowledge-read.js.map +1 -0
  68. package/dist/openapi/openapi.json +18458 -17718
  69. package/dist/patches/access.d.ts +15 -0
  70. package/dist/patches/access.d.ts.map +1 -0
  71. package/dist/patches/access.js +27 -0
  72. package/dist/patches/access.js.map +1 -0
  73. package/dist/patches/engine.d.ts +67 -0
  74. package/dist/patches/engine.d.ts.map +1 -0
  75. package/dist/patches/engine.js +966 -0
  76. package/dist/patches/engine.js.map +1 -0
  77. package/dist/patches/guards.d.ts +23 -0
  78. package/dist/patches/guards.d.ts.map +1 -0
  79. package/dist/patches/guards.js +77 -0
  80. package/dist/patches/guards.js.map +1 -0
  81. package/dist/patches/legacy-rows.d.ts +56 -0
  82. package/dist/patches/legacy-rows.d.ts.map +1 -0
  83. package/dist/patches/legacy-rows.js +162 -0
  84. package/dist/patches/legacy-rows.js.map +1 -0
  85. package/dist/patches/ops.d.ts +24 -0
  86. package/dist/patches/ops.d.ts.map +1 -0
  87. package/dist/patches/ops.js +204 -0
  88. package/dist/patches/ops.js.map +1 -0
  89. package/dist/patches/parse.d.ts +5 -0
  90. package/dist/patches/parse.d.ts.map +1 -0
  91. package/dist/patches/parse.js +323 -0
  92. package/dist/patches/parse.js.map +1 -0
  93. package/dist/patches/paths.d.ts +38 -0
  94. package/dist/patches/paths.d.ts.map +1 -0
  95. package/dist/patches/paths.js +204 -0
  96. package/dist/patches/paths.js.map +1 -0
  97. package/dist/patches/service.d.ts +16 -0
  98. package/dist/patches/service.d.ts.map +1 -0
  99. package/dist/patches/service.js +128 -0
  100. package/dist/patches/service.js.map +1 -0
  101. package/dist/patches/store.d.ts +87 -0
  102. package/dist/patches/store.d.ts.map +1 -0
  103. package/dist/patches/store.js +27 -0
  104. package/dist/patches/store.js.map +1 -0
  105. package/dist/patches/types.d.ts +112 -0
  106. package/dist/patches/types.d.ts.map +1 -0
  107. package/dist/patches/types.js +5 -0
  108. package/dist/patches/types.js.map +1 -0
  109. package/dist/platform.d.ts +15 -0
  110. package/dist/platform.d.ts.map +1 -1
  111. package/dist/platform.js +141 -8
  112. package/dist/platform.js.map +1 -1
  113. package/dist/routes/anomaly.d.ts +5 -0
  114. package/dist/routes/anomaly.d.ts.map +1 -0
  115. package/dist/routes/anomaly.js +308 -0
  116. package/dist/routes/anomaly.js.map +1 -0
  117. package/dist/routes/data.d.ts.map +1 -1
  118. package/dist/routes/data.js +297 -198
  119. package/dist/routes/data.js.map +1 -1
  120. package/dist/routes/knowledge.d.ts.map +1 -1
  121. package/dist/routes/knowledge.js +6 -22
  122. package/dist/routes/knowledge.js.map +1 -1
  123. package/dist/routes/metadata.d.ts.map +1 -1
  124. package/dist/routes/metadata.js +28 -1
  125. package/dist/routes/metadata.js.map +1 -1
  126. package/dist/routes/patches.d.ts +7 -0
  127. package/dist/routes/patches.d.ts.map +1 -0
  128. package/dist/routes/patches.js +111 -0
  129. package/dist/routes/patches.js.map +1 -0
  130. package/dist/routes/subject-roots-backfill.d.ts +4 -0
  131. package/dist/routes/subject-roots-backfill.d.ts.map +1 -0
  132. package/dist/routes/subject-roots-backfill.js +15 -0
  133. package/dist/routes/subject-roots-backfill.js.map +1 -0
  134. package/dist/single-read-discriminator.d.ts +17 -0
  135. package/dist/single-read-discriminator.d.ts.map +1 -0
  136. package/dist/single-read-discriminator.js +67 -0
  137. package/dist/single-read-discriminator.js.map +1 -0
  138. package/dist/subject-roots-backfill.d.ts +24 -0
  139. package/dist/subject-roots-backfill.d.ts.map +1 -0
  140. package/dist/subject-roots-backfill.js +133 -0
  141. package/dist/subject-roots-backfill.js.map +1 -0
  142. package/dist/write-precondition.d.ts +5 -1
  143. package/dist/write-precondition.d.ts.map +1 -1
  144. package/dist/write-precondition.js +11 -3
  145. package/dist/write-precondition.js.map +1 -1
  146. package/dist/writes/content-write.d.ts +207 -0
  147. package/dist/writes/content-write.d.ts.map +1 -0
  148. package/dist/writes/content-write.js +629 -0
  149. package/dist/writes/content-write.js.map +1 -0
  150. package/dist/writes/effects.d.ts +13 -0
  151. package/dist/writes/effects.d.ts.map +1 -0
  152. package/dist/writes/effects.js +28 -0
  153. package/dist/writes/effects.js.map +1 -0
  154. package/dist/writes/error-shape.d.ts +11 -0
  155. package/dist/writes/error-shape.d.ts.map +1 -0
  156. package/dist/writes/error-shape.js +107 -0
  157. package/dist/writes/error-shape.js.map +1 -0
  158. package/dist/writes/queued-write.d.ts +38 -0
  159. package/dist/writes/queued-write.d.ts.map +1 -0
  160. package/dist/writes/queued-write.js +288 -0
  161. package/dist/writes/queued-write.js.map +1 -0
  162. package/dist/writes/receipt-store.d.ts +131 -0
  163. package/dist/writes/receipt-store.d.ts.map +1 -0
  164. package/dist/writes/receipt-store.js +360 -0
  165. package/dist/writes/receipt-store.js.map +1 -0
  166. package/dist/writes/worker.d.ts +30 -0
  167. package/dist/writes/worker.d.ts.map +1 -0
  168. package/dist/writes/worker.js +100 -0
  169. package/dist/writes/worker.js.map +1 -0
  170. package/openapi/openapi.json +18458 -17718
  171. package/package.json +4 -4
@@ -0,0 +1,131 @@
1
+ import type { Db } from "mongodb";
2
+ export declare const WRITE_RECEIPTS_COLLECTION = "write-receipts";
3
+ export declare const RECEIPT_SEQ_COLLECTION = "write-receipt-seq";
4
+ export declare const REJECTED_RECEIPT_TTL_MS: number;
5
+ export declare const WRITE_ATTEMPT_LEASE_MS = 30000;
6
+ export type WriteOperation = "created" | "updated" | "removed" | "unchanged";
7
+ export type WriteReceipt = {
8
+ storageKey: {
9
+ objectType: string;
10
+ contentType: string;
11
+ recordId: string;
12
+ discriminator?: string;
13
+ };
14
+ revision: number;
15
+ writtenAt: string;
16
+ operation: WriteOperation;
17
+ };
18
+ export type StoredContentWrite = {
19
+ scope: {
20
+ orgId: string;
21
+ agentIds: string[];
22
+ };
23
+ caller: string;
24
+ op: "add" | "upsert" | "patch" | "replace" | "remove";
25
+ objectType: string;
26
+ contentType: string;
27
+ precondition: "absent" | "exact-revision" | "none";
28
+ expectedRevision?: number;
29
+ discriminatorValue?: string;
30
+ suppressHooks: boolean;
31
+ record?: Record<string, unknown>;
32
+ patch?: unknown;
33
+ subject?: {
34
+ objectType: string;
35
+ recordId: string;
36
+ };
37
+ datasourceDeclared: boolean;
38
+ datasourceDeclaration?: unknown;
39
+ };
40
+ export type ReceiptError = {
41
+ code: string;
42
+ field: string | null;
43
+ message: string;
44
+ retryable: boolean;
45
+ retryAfterMs?: number;
46
+ status: number;
47
+ };
48
+ /**
49
+ * What a queued row adds to its receipt. A synchronous receipt has none of this.
50
+ */
51
+ export type QueuedWriteInfo = {
52
+ /** Accept number, monotonic per org. Rows for one key apply in this order. */
53
+ seq: number;
54
+ /** The storage key the row lands on. Rows with the same `keyId` apply one at a time. */
55
+ keyId: string;
56
+ runId: string;
57
+ stepId: string;
58
+ storageKey: WriteReceipt["storageKey"];
59
+ };
60
+ export type RunReceiptStatus = "queued" | "stored" | "rejected";
61
+ export type RunSummary = {
62
+ queued: number;
63
+ stored: number;
64
+ rejected: number;
65
+ };
66
+ export type WriteReceiptRow = {
67
+ receiptId: string;
68
+ orgId: string;
69
+ caller: string;
70
+ writeId?: string;
71
+ contentHash: string;
72
+ /**
73
+ * `pending` is a synchronous write that failed in a way a retry can fix.
74
+ * `queued` is a row that was accepted with `queue: true` and is not applied yet.
75
+ */
76
+ status: "pending" | "queued" | "stored" | "rejected";
77
+ receipt?: WriteReceipt;
78
+ error?: ReceiptError;
79
+ request: StoredContentWrite;
80
+ queue?: QueuedWriteInfo;
81
+ attempts: number;
82
+ nextAttemptAt: string;
83
+ createdAt: string;
84
+ updatedAt: string;
85
+ expireAt?: string;
86
+ };
87
+ export type WriteReceiptStore = {
88
+ findByWriteId(orgId: string, caller: string, writeId: string): Promise<WriteReceiptRow | null>;
89
+ get(orgId: string, receiptId: string): Promise<WriteReceiptRow | null>;
90
+ /** `conflict` when this caller already has that writeId. */
91
+ insert(row: WriteReceiptRow): Promise<"inserted" | "conflict">;
92
+ save(row: WriteReceiptRow): Promise<void>;
93
+ list(args: {
94
+ orgId: string;
95
+ caller: string;
96
+ status?: "pending" | "queued" | "stored" | "rejected";
97
+ limit: number;
98
+ }): Promise<WriteReceiptRow[]>;
99
+ claimDue(orgId: string, now: string, limit: number, leaseMs: number): Promise<WriteReceiptRow[]>;
100
+ /** The first of `count` consecutive accept numbers for this org. */
101
+ reserveSeq(orgId: string, count: number): Promise<number>;
102
+ /**
103
+ * Queued rows that are due and have no earlier open row on the same key.
104
+ * Each returned row is leased: no other claim returns it until the lease ends.
105
+ */
106
+ claimQueued(orgId: string, now: string, limit: number, leaseMs: number): Promise<WriteReceiptRow[]>;
107
+ /** Queued-write receipts of one run for one caller, in accept order, after the cursor. */
108
+ listByRun(args: {
109
+ orgId: string;
110
+ caller: string;
111
+ runId: string;
112
+ stepId?: string;
113
+ status?: RunReceiptStatus;
114
+ /** Return rows whose accept number is greater than this. */
115
+ after?: number;
116
+ limit: number;
117
+ }): Promise<WriteReceiptRow[]>;
118
+ summarizeRun(args: {
119
+ orgId: string;
120
+ caller: string;
121
+ runId: string;
122
+ stepId?: string;
123
+ }): Promise<RunSummary>;
124
+ /** The newest accepted row for a key that has not been applied. */
125
+ latestQueuedForKey(orgId: string, keyId: string): Promise<WriteReceiptRow | null>;
126
+ };
127
+ export declare function newReceiptId(): string;
128
+ export declare function rejectedExpiry(nowIso: string): string;
129
+ export declare function createMemoryWriteReceiptStore(): WriteReceiptStore;
130
+ export declare function createMongoWriteReceiptStore(db: Db): WriteReceiptStore;
131
+ //# sourceMappingURL=receipt-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipt-store.d.ts","sourceRoot":"","sources":["../../src/writes/receipt-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,360 @@
1
+ /**
2
+ * FR-2 / FR-4 — durable write receipts. Rejected rows stay listable for 7 days.
3
+ */
4
+ import { randomBytes } from "node:crypto";
5
+ export const WRITE_RECEIPTS_COLLECTION = "write-receipts";
6
+ export const RECEIPT_SEQ_COLLECTION = "write-receipt-seq";
7
+ export const REJECTED_RECEIPT_TTL_MS = 7 * 24 * 60 * 60 * 1000;
8
+ export const WRITE_ATTEMPT_LEASE_MS = 30_000;
9
+ export function newReceiptId() {
10
+ return `wr_${randomBytes(16).toString("hex")}`;
11
+ }
12
+ export function rejectedExpiry(nowIso) {
13
+ return new Date(Date.parse(nowIso) + REJECTED_RECEIPT_TTL_MS).toISOString();
14
+ }
15
+ function matchesRun(row, args) {
16
+ return (row.caller === args.caller &&
17
+ row.queue?.runId === args.runId &&
18
+ (args.stepId === undefined || row.queue.stepId === args.stepId));
19
+ }
20
+ export function createMemoryWriteReceiptStore() {
21
+ const buckets = new Map();
22
+ function bucket(orgId) {
23
+ let found = buckets.get(orgId);
24
+ if (!found) {
25
+ found = { byId: new Map(), byWriteId: new Map(), seq: 0 };
26
+ buckets.set(orgId, found);
27
+ }
28
+ return found;
29
+ }
30
+ function writeKey(caller, writeId) {
31
+ return `${caller}\n${writeId}`;
32
+ }
33
+ return {
34
+ async findByWriteId(orgId, caller, writeId) {
35
+ const id = bucket(orgId).byWriteId.get(writeKey(caller, writeId));
36
+ if (!id)
37
+ return null;
38
+ return structuredClone(bucket(orgId).byId.get(id) ?? null);
39
+ },
40
+ async get(orgId, receiptId) {
41
+ return structuredClone(bucket(orgId).byId.get(receiptId) ?? null);
42
+ },
43
+ async insert(row) {
44
+ const box = bucket(row.orgId);
45
+ if (row.writeId) {
46
+ const key = writeKey(row.caller, row.writeId);
47
+ if (box.byWriteId.has(key))
48
+ return "conflict";
49
+ box.byWriteId.set(key, row.receiptId);
50
+ }
51
+ box.byId.set(row.receiptId, structuredClone(row));
52
+ return "inserted";
53
+ },
54
+ async save(row) {
55
+ const box = bucket(row.orgId);
56
+ box.byId.set(row.receiptId, structuredClone(row));
57
+ if (row.writeId)
58
+ box.byWriteId.set(writeKey(row.caller, row.writeId), row.receiptId);
59
+ },
60
+ async list(args) {
61
+ const cutoff = Date.now() - REJECTED_RECEIPT_TTL_MS;
62
+ return [...bucket(args.orgId).byId.values()]
63
+ .filter((row) => row.caller === args.caller)
64
+ .filter((row) => (args.status ? row.status === args.status : true))
65
+ .filter((row) => row.status !== "rejected" || Date.parse(row.createdAt) >= cutoff)
66
+ .sort((a, b) => b.createdAt.localeCompare(a.createdAt))
67
+ .slice(0, args.limit)
68
+ .map((row) => structuredClone(row));
69
+ },
70
+ async claimDue(orgId, now, limit, leaseMs) {
71
+ const until = new Date(Date.parse(now) + leaseMs).toISOString();
72
+ const due = [...bucket(orgId).byId.values()]
73
+ .filter((row) => row.status === "pending" && row.nextAttemptAt <= now)
74
+ .sort((a, b) => a.nextAttemptAt.localeCompare(b.nextAttemptAt))
75
+ .slice(0, limit);
76
+ const claimed = [];
77
+ for (const row of due) {
78
+ if (row.status !== "pending" || row.nextAttemptAt > now)
79
+ continue;
80
+ row.nextAttemptAt = until;
81
+ row.attempts += 1;
82
+ row.updatedAt = now;
83
+ claimed.push(structuredClone(row));
84
+ }
85
+ return claimed;
86
+ },
87
+ async reserveSeq(orgId, count) {
88
+ const box = bucket(orgId);
89
+ const first = box.seq + 1;
90
+ box.seq += count;
91
+ return first;
92
+ },
93
+ async claimQueued(orgId, now, limit, leaseMs) {
94
+ const until = new Date(Date.parse(now) + leaseMs).toISOString();
95
+ const open = [...bucket(orgId).byId.values()].filter((row) => row.status === "queued" && row.queue);
96
+ const earliestOpen = new Map();
97
+ for (const row of open) {
98
+ const seen = earliestOpen.get(row.queue.keyId);
99
+ if (seen === undefined || row.queue.seq < seen)
100
+ earliestOpen.set(row.queue.keyId, row.queue.seq);
101
+ }
102
+ const claimed = [];
103
+ const due = open
104
+ .filter((row) => row.nextAttemptAt <= now)
105
+ .sort((a, b) => a.queue.seq - b.queue.seq);
106
+ for (const row of due) {
107
+ if (claimed.length >= limit)
108
+ break;
109
+ if (earliestOpen.get(row.queue.keyId) !== row.queue.seq)
110
+ continue;
111
+ row.nextAttemptAt = until;
112
+ row.attempts += 1;
113
+ row.updatedAt = now;
114
+ claimed.push(structuredClone(row));
115
+ }
116
+ return claimed;
117
+ },
118
+ async listByRun(args) {
119
+ return [...bucket(args.orgId).byId.values()]
120
+ .filter((row) => matchesRun(row, args))
121
+ .filter((row) => (args.status ? row.status === args.status : true))
122
+ .filter((row) => (args.after === undefined ? true : row.queue.seq > args.after))
123
+ .sort((a, b) => a.queue.seq - b.queue.seq)
124
+ .slice(0, args.limit)
125
+ .map((row) => structuredClone(row));
126
+ },
127
+ async summarizeRun(args) {
128
+ const summary = { queued: 0, stored: 0, rejected: 0 };
129
+ for (const row of bucket(args.orgId).byId.values()) {
130
+ if (!matchesRun(row, args))
131
+ continue;
132
+ if (row.status === "queued" || row.status === "stored" || row.status === "rejected") {
133
+ summary[row.status] += 1;
134
+ }
135
+ }
136
+ return summary;
137
+ },
138
+ async latestQueuedForKey(orgId, keyId) {
139
+ let latest = null;
140
+ for (const row of bucket(orgId).byId.values()) {
141
+ if (row.status !== "queued" || row.queue?.keyId !== keyId)
142
+ continue;
143
+ if (!latest || row.queue.seq > latest.queue.seq)
144
+ latest = row;
145
+ }
146
+ return latest ? structuredClone(latest) : null;
147
+ },
148
+ };
149
+ }
150
+ export function createMongoWriteReceiptStore(db) {
151
+ const coll = db.collection(WRITE_RECEIPTS_COLLECTION);
152
+ let ready = null;
153
+ function ensure() {
154
+ ready ??= Promise.all([
155
+ coll.createIndex({ orgId: 1, caller: 1, writeId: 1 }, {
156
+ unique: true,
157
+ name: "write_id",
158
+ partialFilterExpression: { writeId: { $type: "string" } },
159
+ }),
160
+ coll.createIndex({ orgId: 1, caller: 1, status: 1, createdAt: -1 }, { name: "caller_status" }),
161
+ coll.createIndex({ orgId: 1, status: 1, nextAttemptAt: 1 }, { name: "pending_due" }),
162
+ coll.createIndex({ expireAtDate: 1 }, { expireAfterSeconds: 0, name: "rejected_ttl" }),
163
+ ]).then(() => undefined);
164
+ return ready;
165
+ }
166
+ /**
167
+ * Indexes for queued writes only. They are separate from `ensure()` so a synchronous write never
168
+ * waits for them: on a large `write-receipts` collection the first build scans every row once.
169
+ * Partial filters keep synchronous receipts out of these indexes, and each query on one of them
170
+ * states the field its filter names, so the planner can use it.
171
+ * A failed build is tried again on the next queue call.
172
+ */
173
+ let queueReady = null;
174
+ function ensureQueue() {
175
+ queueReady ??= Promise.all([
176
+ ensure(),
177
+ coll.createIndex({ orgId: 1, status: 1, "queue.seq": 1 }, { name: "queue_seq", partialFilterExpression: { "queue.seq": { $exists: true } } }),
178
+ coll.createIndex({ orgId: 1, "queue.keyId": 1, status: 1, "queue.seq": 1 }, { name: "queue_key", partialFilterExpression: { "queue.keyId": { $exists: true } } }),
179
+ coll.createIndex({ orgId: 1, caller: 1, "queue.runId": 1, status: 1, "queue.seq": 1 }, { name: "queue_run_status", partialFilterExpression: { "queue.runId": { $exists: true } } }),
180
+ coll.createIndex({ orgId: 1, caller: 1, "queue.runId": 1, "queue.seq": 1 }, { name: "queue_run", partialFilterExpression: { "queue.runId": { $exists: true } } }),
181
+ ]).then(() => undefined, (err) => {
182
+ queueReady = null;
183
+ throw err;
184
+ });
185
+ return queueReady;
186
+ }
187
+ /** One counter document per org. `$inc` is atomic, so two processes never share a number. */
188
+ const counters = db.collection(RECEIPT_SEQ_COLLECTION);
189
+ return {
190
+ async findByWriteId(orgId, caller, writeId) {
191
+ await ensure();
192
+ const doc = await coll.findOne({ orgId, caller, writeId });
193
+ return doc ? fromDoc(doc) : null;
194
+ },
195
+ async get(orgId, receiptId) {
196
+ await ensure();
197
+ const doc = await coll.findOne({ _id: receiptId, orgId });
198
+ return doc ? fromDoc(doc) : null;
199
+ },
200
+ async insert(row) {
201
+ // A synchronous receipt never waits for the queue indexes.
202
+ await (row.queue ? ensureQueue() : ensure());
203
+ try {
204
+ await coll.insertOne(toDoc(row));
205
+ return "inserted";
206
+ }
207
+ catch (err) {
208
+ const message = err instanceof Error ? err.message : String(err);
209
+ if (message.includes("E11000") || message.includes("duplicate"))
210
+ return "conflict";
211
+ throw err;
212
+ }
213
+ },
214
+ async save(row) {
215
+ await ensure();
216
+ await coll.replaceOne({ _id: row.receiptId }, toDoc(row), { upsert: true });
217
+ },
218
+ async list(args) {
219
+ await ensure();
220
+ const cutoff = new Date(Date.now() - REJECTED_RECEIPT_TTL_MS).toISOString();
221
+ const filter = { orgId: args.orgId, caller: args.caller };
222
+ if (args.status)
223
+ filter.status = args.status;
224
+ if (args.status === "rejected")
225
+ filter.createdAt = { $gte: cutoff };
226
+ const docs = await coll.find(filter).sort({ createdAt: -1 }).limit(args.limit).toArray();
227
+ return docs.map(fromDoc);
228
+ },
229
+ async claimDue(orgId, now, limit, leaseMs) {
230
+ await ensure();
231
+ const until = new Date(Date.parse(now) + leaseMs).toISOString();
232
+ const due = await coll
233
+ .find({ orgId, status: "pending", nextAttemptAt: { $lte: now } })
234
+ .sort({ nextAttemptAt: 1 })
235
+ .limit(limit)
236
+ .toArray();
237
+ const claimed = [];
238
+ for (const doc of due) {
239
+ const updated = await coll.updateOne({ _id: doc._id, status: "pending", nextAttemptAt: doc.nextAttemptAt }, { $set: { nextAttemptAt: until, updatedAt: now }, $inc: { attempts: 1 } });
240
+ if (updated.modifiedCount !== 1)
241
+ continue;
242
+ const fresh = await coll.findOne({ _id: doc._id });
243
+ if (fresh)
244
+ claimed.push(fromDoc(fresh));
245
+ }
246
+ return claimed;
247
+ },
248
+ async reserveSeq(orgId, count) {
249
+ const after = await counters.findOneAndUpdate({ _id: orgId }, { $inc: { seq: count } }, { upsert: true, returnDocument: "after" });
250
+ if (!after)
251
+ throw new Error("receipt sequence counter did not return a document");
252
+ return after.seq - count + 1;
253
+ },
254
+ async claimQueued(orgId, now, limit, leaseMs) {
255
+ await ensureQueue();
256
+ const until = new Date(Date.parse(now) + leaseMs).toISOString();
257
+ const claimed = [];
258
+ const taken = new Set();
259
+ const pageSize = Math.max(limit * 4, 16);
260
+ // Rows waiting behind an earlier row on the same key fill the front of the order.
261
+ // Keep paging past them, up to a cap, so other keys are not starved.
262
+ const SCAN_CAP = 4_000;
263
+ let scanned = 0;
264
+ let after = 0;
265
+ while (claimed.length < limit && scanned < SCAN_CAP) {
266
+ // Only what the claim needs. The full row, with its request body, is read once it is claimed.
267
+ const page = await coll
268
+ .find({ orgId, status: "queued", "queue.seq": { $gt: after }, nextAttemptAt: { $lte: now } }, { projection: { _id: 1, "queue.seq": 1, "queue.keyId": 1, nextAttemptAt: 1 } })
269
+ .sort({ "queue.seq": 1 })
270
+ .limit(pageSize)
271
+ .toArray();
272
+ if (page.length === 0)
273
+ break;
274
+ for (const doc of page) {
275
+ scanned += 1;
276
+ after = doc.queue.seq;
277
+ if (claimed.length >= limit)
278
+ break;
279
+ const keyId = doc.queue.keyId;
280
+ if (taken.has(keyId))
281
+ continue;
282
+ const ahead = await coll.findOne({
283
+ orgId,
284
+ status: "queued",
285
+ "queue.keyId": keyId,
286
+ "queue.seq": { $lt: doc.queue.seq },
287
+ }, { projection: { _id: 1 } });
288
+ if (ahead)
289
+ continue;
290
+ const updated = await coll.updateOne({ _id: doc._id, status: "queued", nextAttemptAt: doc.nextAttemptAt }, { $set: { nextAttemptAt: until, updatedAt: now }, $inc: { attempts: 1 } });
291
+ if (updated.modifiedCount !== 1)
292
+ continue;
293
+ taken.add(keyId);
294
+ const fresh = await coll.findOne({ _id: doc._id });
295
+ if (fresh)
296
+ claimed.push(fromDoc(fresh));
297
+ }
298
+ if (page.length < pageSize)
299
+ break;
300
+ }
301
+ return claimed;
302
+ },
303
+ async listByRun(args) {
304
+ await ensureQueue();
305
+ const filter = {
306
+ orgId: args.orgId,
307
+ caller: args.caller,
308
+ "queue.runId": args.runId,
309
+ "queue.seq": { $gt: args.after ?? 0 },
310
+ };
311
+ if (args.stepId !== undefined)
312
+ filter["queue.stepId"] = args.stepId;
313
+ if (args.status)
314
+ filter.status = args.status;
315
+ const docs = await coll.find(filter).sort({ "queue.seq": 1 }).limit(args.limit).toArray();
316
+ return docs.map(fromDoc);
317
+ },
318
+ async summarizeRun(args) {
319
+ await ensureQueue();
320
+ const match = {
321
+ orgId: args.orgId,
322
+ caller: args.caller,
323
+ "queue.runId": args.runId,
324
+ };
325
+ if (args.stepId !== undefined)
326
+ match["queue.stepId"] = args.stepId;
327
+ const groups = await coll
328
+ .aggregate([
329
+ { $match: match },
330
+ { $group: { _id: "$status", n: { $sum: 1 } } },
331
+ ])
332
+ .toArray();
333
+ const summary = { queued: 0, stored: 0, rejected: 0 };
334
+ for (const group of groups) {
335
+ if (group._id === "queued" || group._id === "stored" || group._id === "rejected") {
336
+ summary[group._id] = group.n;
337
+ }
338
+ }
339
+ return summary;
340
+ },
341
+ async latestQueuedForKey(orgId, keyId) {
342
+ await ensureQueue();
343
+ const doc = await coll.findOne({ orgId, status: "queued", "queue.keyId": keyId, "queue.seq": { $gt: 0 } }, { sort: { "queue.seq": -1 } });
344
+ return doc ? fromDoc(doc) : null;
345
+ },
346
+ };
347
+ }
348
+ function toDoc(row) {
349
+ const doc = { ...row, _id: row.receiptId };
350
+ if (row.expireAt)
351
+ doc.expireAtDate = new Date(row.expireAt);
352
+ return doc;
353
+ }
354
+ function fromDoc(doc) {
355
+ const { _id: _drop, expireAtDate: _date, ...rest } = doc;
356
+ void _drop;
357
+ void _date;
358
+ return rest;
359
+ }
360
+ //# sourceMappingURL=receipt-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipt-store.js","sourceRoot":"","sources":["../../src/writes/receipt-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { type WriteReceiptRow, type WriteReceiptStore } from "./receipt-store.js";
2
+ /** Finish writes Memorix already accepted. */
3
+ export declare function tickWriteReceipts(args: {
4
+ orgIds: string[];
5
+ now: string;
6
+ storeFor: (orgId: string) => WriteReceiptStore;
7
+ replay: (row: WriteReceiptRow) => Promise<void>;
8
+ }): Promise<void>;
9
+ export declare const QUEUE_DEFAULT_CONCURRENCY = 8;
10
+ /**
11
+ * Apply queued rows until none is due, or the budget ends.
12
+ *
13
+ * Rows for one storage key apply one at a time in accept order, because `claimQueued` never returns a
14
+ * row while an earlier open row for its key exists. Rows for different keys apply at the same time, up
15
+ * to `concurrency`. A claim is a compare-and-set on the receipt, so a second process draining the same
16
+ * database cannot apply the same row.
17
+ */
18
+ export declare function drainQueuedWrites(args: {
19
+ orgIds: string[];
20
+ now: () => string;
21
+ storeFor: (orgId: string) => WriteReceiptStore;
22
+ replay: (row: WriteReceiptRow) => Promise<void>;
23
+ concurrency?: number;
24
+ /** After this long the drain returns. The next tick starts another, so the org list stays fresh. */
25
+ budgetMs?: number;
26
+ shouldStop?: () => boolean;
27
+ }): Promise<{
28
+ applied: number;
29
+ }>;
30
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/writes/worker.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,8CAA8C;AAC9C,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,iBAAiB,CAAC;IAC/C,MAAM,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD,GAAG,OAAO,CAAC,IAAI,CAAC,CAehB;AAED,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAG3C;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,iBAAiB,CAAC;IAC/C,MAAM,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;CAC5B,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAgE/B"}
@@ -0,0 +1,100 @@
1
+ import { QUEUE_MAX_ATTEMPTS } from "./content-write.js";
2
+ import { rejectedExpiry, WRITE_ATTEMPT_LEASE_MS, } from "./receipt-store.js";
3
+ /** Finish writes Memorix already accepted. */
4
+ export async function tickWriteReceipts(args) {
5
+ for (const orgId of args.orgIds) {
6
+ const store = args.storeFor(orgId);
7
+ const due = await store.claimDue(orgId, args.now, 20, WRITE_ATTEMPT_LEASE_MS);
8
+ for (const row of due) {
9
+ try {
10
+ await args.replay(row);
11
+ }
12
+ catch {
13
+ row.status = "pending";
14
+ row.nextAttemptAt = new Date(Date.parse(args.now) + 5_000).toISOString();
15
+ row.updatedAt = args.now;
16
+ await store.save(row);
17
+ }
18
+ }
19
+ }
20
+ }
21
+ export const QUEUE_DEFAULT_CONCURRENCY = 8;
22
+ const QUEUE_REPLAY_FAILURE_DELAY_MS = 5_000;
23
+ /**
24
+ * Apply queued rows until none is due, or the budget ends.
25
+ *
26
+ * Rows for one storage key apply one at a time in accept order, because `claimQueued` never returns a
27
+ * row while an earlier open row for its key exists. Rows for different keys apply at the same time, up
28
+ * to `concurrency`. A claim is a compare-and-set on the receipt, so a second process draining the same
29
+ * database cannot apply the same row.
30
+ */
31
+ export async function drainQueuedWrites(args) {
32
+ const concurrency = Math.max(1, Math.floor(args.concurrency ?? QUEUE_DEFAULT_CONCURRENCY));
33
+ const deadline = Date.now() + (args.budgetMs ?? 20_000);
34
+ const stopped = () => args.shouldStop?.() === true || Date.now() > deadline;
35
+ let applied = 0;
36
+ for (const orgId of args.orgIds) {
37
+ if (stopped())
38
+ break;
39
+ const store = args.storeFor(orgId);
40
+ const inFlight = new Set();
41
+ const apply = async (row) => {
42
+ try {
43
+ await args.replay(row);
44
+ applied += 1;
45
+ }
46
+ catch (err) {
47
+ // `finish` records its own failures. This is a failure around it, such as the database being down.
48
+ const now = args.now();
49
+ try {
50
+ if (row.attempts >= QUEUE_MAX_ATTEMPTS) {
51
+ row.status = "rejected";
52
+ row.error = {
53
+ code: "WRITE_FAILED",
54
+ field: null,
55
+ message: `gave up after ${row.attempts} attempts: ${err instanceof Error ? err.message : String(err)}`,
56
+ retryable: false,
57
+ status: 500,
58
+ };
59
+ row.expireAt = rejectedExpiry(now);
60
+ }
61
+ else {
62
+ row.status = "queued";
63
+ row.nextAttemptAt = new Date(Date.parse(now) + QUEUE_REPLAY_FAILURE_DELAY_MS).toISOString();
64
+ }
65
+ row.updatedAt = now;
66
+ await store.save(row);
67
+ }
68
+ catch {
69
+ /* the lease runs out and the row is claimed again */
70
+ }
71
+ }
72
+ };
73
+ try {
74
+ while (!stopped()) {
75
+ const free = concurrency - inFlight.size;
76
+ let claimed = 0;
77
+ if (free > 0) {
78
+ const rows = await store.claimQueued(orgId, args.now(), free, WRITE_ATTEMPT_LEASE_MS);
79
+ claimed = rows.length;
80
+ for (const row of rows) {
81
+ const task = apply(row).finally(() => {
82
+ inFlight.delete(task);
83
+ });
84
+ inFlight.add(task);
85
+ }
86
+ }
87
+ if (inFlight.size === 0)
88
+ break;
89
+ // A finished apply can free the next row for its key, so wait for one slot before claiming again.
90
+ if (claimed === 0 || inFlight.size >= concurrency)
91
+ await Promise.race(inFlight);
92
+ }
93
+ }
94
+ finally {
95
+ await Promise.all(inFlight);
96
+ }
97
+ }
98
+ return { applied };
99
+ }
100
+ //# sourceMappingURL=worker.js.map