@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.
- package/README.md +1 -1
- package/dist/analytics/host.d.ts +2 -2
- package/dist/analytics/host.d.ts.map +1 -1
- package/dist/analytics/host.js.map +1 -1
- package/dist/analytics/read-row.d.ts +33 -0
- package/dist/analytics/read-row.d.ts.map +1 -0
- package/dist/analytics/read-row.js +76 -0
- package/dist/analytics/read-row.js.map +1 -0
- package/dist/analytics/tracker.d.ts +14 -0
- package/dist/analytics/tracker.d.ts.map +1 -1
- package/dist/analytics/tracker.js +55 -17
- package/dist/analytics/tracker.js.map +1 -1
- package/dist/anomaly/catalog.d.ts +4 -0
- package/dist/anomaly/catalog.d.ts.map +1 -0
- package/dist/anomaly/catalog.js +315 -0
- package/dist/anomaly/catalog.js.map +1 -0
- package/dist/anomaly/descriptors.d.ts +11 -0
- package/dist/anomaly/descriptors.d.ts.map +1 -0
- package/dist/anomaly/descriptors.js +113 -0
- package/dist/anomaly/descriptors.js.map +1 -0
- package/dist/anomaly/index.d.ts +6 -0
- package/dist/anomaly/index.d.ts.map +1 -0
- package/dist/anomaly/index.js +5 -0
- package/dist/anomaly/index.js.map +1 -0
- package/dist/anomaly/records.d.ts +28 -0
- package/dist/anomaly/records.d.ts.map +1 -0
- package/dist/anomaly/records.js +384 -0
- package/dist/anomaly/records.js.map +1 -0
- package/dist/anomaly/types.d.ts +116 -0
- package/dist/anomaly/types.d.ts.map +1 -0
- package/dist/anomaly/types.js +24 -0
- package/dist/anomaly/types.js.map +1 -0
- package/dist/anomaly/values.d.ts +31 -0
- package/dist/anomaly/values.d.ts.map +1 -0
- package/dist/anomaly/values.js +171 -0
- package/dist/anomaly/values.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +12 -0
- package/dist/app.js.map +1 -1
- package/dist/catalog-bridge.d.ts +21 -3
- package/dist/catalog-bridge.d.ts.map +1 -1
- package/dist/catalog-bridge.js +148 -34
- package/dist/catalog-bridge.js.map +1 -1
- package/dist/errors.d.ts +5 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -1
- package/dist/knowledge-upstream.d.ts +32 -0
- package/dist/knowledge-upstream.d.ts.map +1 -1
- package/dist/knowledge-upstream.js +86 -2
- package/dist/knowledge-upstream.js.map +1 -1
- package/dist/mcp/nexum-tools.d.ts +1 -1
- package/dist/mcp/nexum-tools.d.ts.map +1 -1
- package/dist/mcp/nexum-tools.js +39 -22
- package/dist/mcp/nexum-tools.js.map +1 -1
- package/dist/metadata-view.d.ts +30 -0
- package/dist/metadata-view.d.ts.map +1 -0
- package/dist/metadata-view.js +67 -0
- package/dist/metadata-view.js.map +1 -0
- package/dist/nexum-analysis/enqueue.d.ts +1 -1
- package/dist/nexum-analysis/enqueue.d.ts.map +1 -1
- package/dist/nexum-analysis/enqueue.js +4 -2
- package/dist/nexum-analysis/enqueue.js.map +1 -1
- package/dist/nexum-analysis/knowledge-read.d.ts +45 -0
- package/dist/nexum-analysis/knowledge-read.d.ts.map +1 -0
- package/dist/nexum-analysis/knowledge-read.js +26 -0
- package/dist/nexum-analysis/knowledge-read.js.map +1 -0
- package/dist/openapi/openapi.json +18458 -17718
- package/dist/patches/access.d.ts +15 -0
- package/dist/patches/access.d.ts.map +1 -0
- package/dist/patches/access.js +27 -0
- package/dist/patches/access.js.map +1 -0
- package/dist/patches/engine.d.ts +67 -0
- package/dist/patches/engine.d.ts.map +1 -0
- package/dist/patches/engine.js +966 -0
- package/dist/patches/engine.js.map +1 -0
- package/dist/patches/guards.d.ts +23 -0
- package/dist/patches/guards.d.ts.map +1 -0
- package/dist/patches/guards.js +77 -0
- package/dist/patches/guards.js.map +1 -0
- package/dist/patches/legacy-rows.d.ts +56 -0
- package/dist/patches/legacy-rows.d.ts.map +1 -0
- package/dist/patches/legacy-rows.js +162 -0
- package/dist/patches/legacy-rows.js.map +1 -0
- package/dist/patches/ops.d.ts +24 -0
- package/dist/patches/ops.d.ts.map +1 -0
- package/dist/patches/ops.js +204 -0
- package/dist/patches/ops.js.map +1 -0
- package/dist/patches/parse.d.ts +5 -0
- package/dist/patches/parse.d.ts.map +1 -0
- package/dist/patches/parse.js +323 -0
- package/dist/patches/parse.js.map +1 -0
- package/dist/patches/paths.d.ts +38 -0
- package/dist/patches/paths.d.ts.map +1 -0
- package/dist/patches/paths.js +204 -0
- package/dist/patches/paths.js.map +1 -0
- package/dist/patches/service.d.ts +16 -0
- package/dist/patches/service.d.ts.map +1 -0
- package/dist/patches/service.js +128 -0
- package/dist/patches/service.js.map +1 -0
- package/dist/patches/store.d.ts +87 -0
- package/dist/patches/store.d.ts.map +1 -0
- package/dist/patches/store.js +27 -0
- package/dist/patches/store.js.map +1 -0
- package/dist/patches/types.d.ts +112 -0
- package/dist/patches/types.d.ts.map +1 -0
- package/dist/patches/types.js +5 -0
- package/dist/patches/types.js.map +1 -0
- package/dist/platform.d.ts +15 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +141 -8
- package/dist/platform.js.map +1 -1
- package/dist/routes/anomaly.d.ts +5 -0
- package/dist/routes/anomaly.d.ts.map +1 -0
- package/dist/routes/anomaly.js +308 -0
- package/dist/routes/anomaly.js.map +1 -0
- package/dist/routes/data.d.ts.map +1 -1
- package/dist/routes/data.js +297 -198
- package/dist/routes/data.js.map +1 -1
- package/dist/routes/knowledge.d.ts.map +1 -1
- package/dist/routes/knowledge.js +6 -22
- package/dist/routes/knowledge.js.map +1 -1
- package/dist/routes/metadata.d.ts.map +1 -1
- package/dist/routes/metadata.js +28 -1
- package/dist/routes/metadata.js.map +1 -1
- package/dist/routes/patches.d.ts +7 -0
- package/dist/routes/patches.d.ts.map +1 -0
- package/dist/routes/patches.js +111 -0
- package/dist/routes/patches.js.map +1 -0
- package/dist/routes/subject-roots-backfill.d.ts +4 -0
- package/dist/routes/subject-roots-backfill.d.ts.map +1 -0
- package/dist/routes/subject-roots-backfill.js +15 -0
- package/dist/routes/subject-roots-backfill.js.map +1 -0
- package/dist/single-read-discriminator.d.ts +17 -0
- package/dist/single-read-discriminator.d.ts.map +1 -0
- package/dist/single-read-discriminator.js +67 -0
- package/dist/single-read-discriminator.js.map +1 -0
- package/dist/subject-roots-backfill.d.ts +24 -0
- package/dist/subject-roots-backfill.d.ts.map +1 -0
- package/dist/subject-roots-backfill.js +133 -0
- package/dist/subject-roots-backfill.js.map +1 -0
- package/dist/write-precondition.d.ts +5 -1
- package/dist/write-precondition.d.ts.map +1 -1
- package/dist/write-precondition.js +11 -3
- package/dist/write-precondition.js.map +1 -1
- package/dist/writes/content-write.d.ts +207 -0
- package/dist/writes/content-write.d.ts.map +1 -0
- package/dist/writes/content-write.js +629 -0
- package/dist/writes/content-write.js.map +1 -0
- package/dist/writes/effects.d.ts +13 -0
- package/dist/writes/effects.d.ts.map +1 -0
- package/dist/writes/effects.js +28 -0
- package/dist/writes/effects.js.map +1 -0
- package/dist/writes/error-shape.d.ts +11 -0
- package/dist/writes/error-shape.d.ts.map +1 -0
- package/dist/writes/error-shape.js +107 -0
- package/dist/writes/error-shape.js.map +1 -0
- package/dist/writes/queued-write.d.ts +38 -0
- package/dist/writes/queued-write.d.ts.map +1 -0
- package/dist/writes/queued-write.js +288 -0
- package/dist/writes/queued-write.js.map +1 -0
- package/dist/writes/receipt-store.d.ts +131 -0
- package/dist/writes/receipt-store.d.ts.map +1 -0
- package/dist/writes/receipt-store.js +360 -0
- package/dist/writes/receipt-store.js.map +1 -0
- package/dist/writes/worker.d.ts +30 -0
- package/dist/writes/worker.d.ts.map +1 -0
- package/dist/writes/worker.js +100 -0
- package/dist/writes/worker.js.map +1 -0
- package/openapi/openapi.json +18458 -17718
- package/package.json +4 -4
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side effects after a content write is stored. A failure here does not hide the receipt.
|
|
3
|
+
*/
|
|
4
|
+
import type { MemorixPlatform } from "../platform.js";
|
|
5
|
+
import type { MemorixScope } from "../scope.js";
|
|
6
|
+
import type { CommittedWrite } from "./content-write.js";
|
|
7
|
+
export declare function commitWriteEffects(args: {
|
|
8
|
+
platform: MemorixPlatform;
|
|
9
|
+
scope: MemorixScope;
|
|
10
|
+
caller: string;
|
|
11
|
+
event: CommittedWrite;
|
|
12
|
+
}): Promise<unknown>;
|
|
13
|
+
//# sourceMappingURL=effects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effects.d.ts","sourceRoot":"","sources":["../../src/writes/effects.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,cAAc,CAAC;CACvB,GAAG,OAAO,CAAC,OAAO,CAAC,CAyBnB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { memorixActivityRing } from "../activity-ring.js";
|
|
2
|
+
import { maybeEnqueueNexumAnalysis } from "../nexum-analysis/enqueue.js";
|
|
3
|
+
export async function commitWriteEffects(args) {
|
|
4
|
+
const indexing = args.event.operation === "removed"
|
|
5
|
+
? undefined
|
|
6
|
+
: await maybeEnqueueNexumAnalysis({
|
|
7
|
+
platform: args.platform,
|
|
8
|
+
scope: args.scope,
|
|
9
|
+
objectType: args.event.objectType,
|
|
10
|
+
contentType: args.event.contentType,
|
|
11
|
+
recordId: args.event.recordId,
|
|
12
|
+
revision: args.event.revision,
|
|
13
|
+
data: args.event.data,
|
|
14
|
+
});
|
|
15
|
+
memorixActivityRing.recordLand({
|
|
16
|
+
orgId: args.scope.orgId,
|
|
17
|
+
caller: args.caller,
|
|
18
|
+
objectType: args.event.objectType,
|
|
19
|
+
contentType: args.event.contentType,
|
|
20
|
+
recordId: args.event.recordId,
|
|
21
|
+
revision: args.event.revision,
|
|
22
|
+
outcome: args.event.operation,
|
|
23
|
+
indexing,
|
|
24
|
+
hooks: args.event.hooks,
|
|
25
|
+
});
|
|
26
|
+
return indexing;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=effects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effects.js","sourceRoot":"","sources":["../../src/writes/effects.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAGzE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAKxC;IACC,MAAM,QAAQ,GACZ,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS;QAChC,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,MAAM,yBAAyB,CAAC;YAC9B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU;YACjC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW;YACnC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ;YAC7B,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ;YAC7B,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;SACtB,CAAC,CAAC;IACT,mBAAmB,CAAC,UAAU,CAAC;QAC7B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;QACvB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU;QACjC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW;QACnC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ;QAC7B,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ;QAC7B,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS;QAC7B,QAAQ;QACR,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;KACxB,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FR-6 — a rejection names the field and says whether the same request can succeed later.
|
|
3
|
+
*/
|
|
4
|
+
export type FailureShape = {
|
|
5
|
+
field: string | null;
|
|
6
|
+
retryable: boolean;
|
|
7
|
+
retryAfterMs?: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function classifyFailure(err: unknown, status: number): FailureShape;
|
|
10
|
+
export declare function httpStatusForCode(code: string, fallback?: number): number;
|
|
11
|
+
//# sourceMappingURL=error-shape.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-shape.d.ts","sourceRoot":"","sources":["../../src/writes/error-shape.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAyBF,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAoD1E;AAUD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAsBtE"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FR-6 — a rejection names the field and says whether the same request can succeed later.
|
|
3
|
+
*/
|
|
4
|
+
const NON_RETRYABLE = new Set([
|
|
5
|
+
"WRITE_IDENTIFIER_ISSUER",
|
|
6
|
+
"DIRECTORY_CONFLICT_OBJECT_TYPE",
|
|
7
|
+
"DIRECTORY_CONFLICT_DATA_CATEGORY",
|
|
8
|
+
"READ_DISCRIMINATOR_REQUIRED",
|
|
9
|
+
"WRITE_DISCRIMINATOR_REQUIRED",
|
|
10
|
+
"WRITE_ID_REUSED",
|
|
11
|
+
"QUEUE_KEY_REUSED",
|
|
12
|
+
"READ_QUERY_INVALID",
|
|
13
|
+
"WRITE_NOT_ABSENT",
|
|
14
|
+
"WRITE_NOT_FOUND",
|
|
15
|
+
"WRITE_STALE_REVISION",
|
|
16
|
+
"WRITE_PRECONDITION_INVALID",
|
|
17
|
+
"WRITE_IDENTITY_MISMATCH",
|
|
18
|
+
"WRITE_IDENTITY_ADOPTION",
|
|
19
|
+
"WRITE_FORMAT_INVALID",
|
|
20
|
+
"WRITE_INTERFACE_BINDING",
|
|
21
|
+
"VALIDATION",
|
|
22
|
+
"SCOPE_INVALID",
|
|
23
|
+
"BODY_TOO_LARGE",
|
|
24
|
+
"PUBLICATION_PINNED",
|
|
25
|
+
]);
|
|
26
|
+
export function classifyFailure(err, status) {
|
|
27
|
+
const code = err && typeof err === "object" && "code" in err && typeof err.code === "string"
|
|
28
|
+
? err.code
|
|
29
|
+
: "";
|
|
30
|
+
const message = err instanceof Error ? err.message : typeof err === "string" ? err : "";
|
|
31
|
+
const details = err && typeof err === "object" && "details" in err ? err.details : undefined;
|
|
32
|
+
const detail = details && typeof details === "object" && !Array.isArray(details)
|
|
33
|
+
? details
|
|
34
|
+
: {};
|
|
35
|
+
let field = null;
|
|
36
|
+
if (typeof detail.field === "string" && detail.field.trim())
|
|
37
|
+
field = detail.field;
|
|
38
|
+
else if (typeof detail.path === "string" && detail.path.trim())
|
|
39
|
+
field = detail.path;
|
|
40
|
+
else if (code === "WRITE_IDENTIFIER_ISSUER")
|
|
41
|
+
field = "concept.identifiers.primary.issuer";
|
|
42
|
+
else if (code === "DIRECTORY_CONFLICT_OBJECT_TYPE" || code === "DIRECTORY_CONFLICT_DATA_CATEGORY") {
|
|
43
|
+
field = "recordId";
|
|
44
|
+
}
|
|
45
|
+
else if (code === "READ_DISCRIMINATOR_REQUIRED" || code === "WRITE_DISCRIMINATOR_REQUIRED") {
|
|
46
|
+
field = "discriminatorValue";
|
|
47
|
+
}
|
|
48
|
+
else if (code === "WRITE_ID_REUSED")
|
|
49
|
+
field = "writeId";
|
|
50
|
+
else if (code === "QUEUE_KEY_REUSED")
|
|
51
|
+
field = "stepId";
|
|
52
|
+
else if (code === "WRITE_NOT_FOUND" || code === "WRITE_NOT_ABSENT")
|
|
53
|
+
field = "recordId";
|
|
54
|
+
else {
|
|
55
|
+
const match = message.match(/filter\[\d+\](?:\.[A-Za-z0-9_]+)?/);
|
|
56
|
+
if (match)
|
|
57
|
+
field = match[0];
|
|
58
|
+
}
|
|
59
|
+
if (detail.retryable === true) {
|
|
60
|
+
return { field, retryable: true, retryAfterMs: retryAfter(message, status, detail) };
|
|
61
|
+
}
|
|
62
|
+
if (detail.retryable === false || NON_RETRYABLE.has(code)) {
|
|
63
|
+
return { field, retryable: false };
|
|
64
|
+
}
|
|
65
|
+
const transient = status === 408 ||
|
|
66
|
+
status === 429 ||
|
|
67
|
+
status === 503 ||
|
|
68
|
+
status === 504 ||
|
|
69
|
+
code === "READ_UNAVAILABLE" ||
|
|
70
|
+
code === "ABSTRACT_WRITE_UNAVAILABLE" ||
|
|
71
|
+
code === "BACKFILL_UNAVAILABLE" ||
|
|
72
|
+
/timeout|timed out|ECONNRESET|EAI_AGAIN|MongoNetwork|server selection|overload|too many requests|ECONNREFUSED/i.test(message);
|
|
73
|
+
if (transient || status >= 500) {
|
|
74
|
+
return { field, retryable: true, retryAfterMs: retryAfter(message, status, detail) };
|
|
75
|
+
}
|
|
76
|
+
return { field, retryable: false };
|
|
77
|
+
}
|
|
78
|
+
function retryAfter(message, status, detail) {
|
|
79
|
+
if (typeof detail.retryAfterMs === "number" && Number.isFinite(detail.retryAfterMs)) {
|
|
80
|
+
return detail.retryAfterMs;
|
|
81
|
+
}
|
|
82
|
+
if (status === 429 || status === 503 || /overload|too many/i.test(message))
|
|
83
|
+
return 5_000;
|
|
84
|
+
return 1_000;
|
|
85
|
+
}
|
|
86
|
+
export function httpStatusForCode(code, fallback = 500) {
|
|
87
|
+
if (code === "WRITE_ID_REUSED" ||
|
|
88
|
+
code === "QUEUE_KEY_REUSED" ||
|
|
89
|
+
code === "WRITE_NOT_ABSENT" ||
|
|
90
|
+
code === "WRITE_STALE_REVISION") {
|
|
91
|
+
return 409;
|
|
92
|
+
}
|
|
93
|
+
if (code === "WRITE_NOT_FOUND" || code === "READ_NOT_FOUND")
|
|
94
|
+
return 404;
|
|
95
|
+
if (code === "READ_UNAVAILABLE" || code === "BACKFILL_UNAVAILABLE")
|
|
96
|
+
return 503;
|
|
97
|
+
if (code.startsWith("WRITE_") ||
|
|
98
|
+
code.startsWith("READ_") ||
|
|
99
|
+
code.startsWith("ROUTE_") ||
|
|
100
|
+
code.startsWith("DIRECTORY_") ||
|
|
101
|
+
code.startsWith("SCOPE_") ||
|
|
102
|
+
code === "VALIDATION") {
|
|
103
|
+
return 400;
|
|
104
|
+
}
|
|
105
|
+
return fallback;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=error-shape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-shape.js","sourceRoot":"","sources":["../../src/writes/error-shape.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type DatasourceWriteInput } from "@x12i/memorix-data";
|
|
2
|
+
import { type ContentWriteBody, type ContentWriteDeps, type ContentWriteOutcome, type ContentWritePorts } from "./content-write.js";
|
|
3
|
+
import { type WriteReceiptRow } from "./receipt-store.js";
|
|
4
|
+
/**
|
|
5
|
+
* A new row is not applied for this long. A second accept for the same key may hold a lower accept
|
|
6
|
+
* number and still be on its way to the database. The wait lets it land first.
|
|
7
|
+
*/
|
|
8
|
+
export declare const QUEUE_SETTLE_MS = 500;
|
|
9
|
+
/** `queue` is absent, or a boolean. */
|
|
10
|
+
export declare function readQueueFlag(value: unknown): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* The queue key of one stored-document address, or null when the address cannot be resolved
|
|
13
|
+
* (for example a discriminated content type read without its discriminator).
|
|
14
|
+
*/
|
|
15
|
+
export declare function queueKeyIdFor(catalog: ContentWritePorts["catalog"], args: {
|
|
16
|
+
objectType: string;
|
|
17
|
+
contentType: string;
|
|
18
|
+
recordId: string;
|
|
19
|
+
discriminatorValue?: string;
|
|
20
|
+
}): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* The record a queued row will write, shaped like a stored read, minus the `revision` it does not have yet.
|
|
23
|
+
*/
|
|
24
|
+
export declare function pendingRecord(row: WriteReceiptRow): Record<string, unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* Accept one row. 202 `queued`, or the answer for a repeat, or a rejection that stored nothing.
|
|
27
|
+
*/
|
|
28
|
+
export declare function runQueuedWrite(deps: ContentWriteDeps, body: ContentWriteBody): Promise<ContentWriteOutcome>;
|
|
29
|
+
/**
|
|
30
|
+
* Accept up to 500 rows in array order. Each row is stored and acknowledged before its result is recorded.
|
|
31
|
+
* One bad row does not reject the batch or drop rows already stored.
|
|
32
|
+
*/
|
|
33
|
+
export declare function runQueuedBatch(deps: ContentWriteDeps, body: unknown, datasourceFor: (body: ContentWriteBody) => DatasourceWriteInput): Promise<{
|
|
34
|
+
results: unknown[];
|
|
35
|
+
}>;
|
|
36
|
+
/** What `GET /api/data/receipts/:id`, the run list, and a repeat of a stored row return for a queued write. */
|
|
37
|
+
export declare function publicQueuedReceipt(row: WriteReceiptRow): Record<string, unknown>;
|
|
38
|
+
//# sourceMappingURL=queued-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queued-write.d.ts","sourceRoot":"","sources":["../../src/writes/queued-write.ts"],"names":[],"mappings":"AAYA,OAAO,EAML,KAAK,oBAAoB,EAE1B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAOL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAE5B;;;GAGG;AACH,eAAO,MAAM,eAAe,MAAM,CAAC;AAInC,uCAAuC;AACvC,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIrD;AAyED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,iBAAiB,CAAC,SAAS,CAAC,EACrC,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/F,MAAM,GAAG,IAAI,CAYf;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAI3E;AAwDD;;GAEG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA4CjH;AAgCD;;;GAGG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,gBAAgB,EACtB,IAAI,EAAE,OAAO,EACb,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,oBAAoB,GAC9D,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC,CAyCjC;AAED,+GAA+G;AAC/G,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBjF"}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Queued content write (docs/async-content-write-FR.md).
|
|
3
|
+
*
|
|
4
|
+
* `queue: true` validates a row, stores one receipt in the operational database, and answers 202.
|
|
5
|
+
* The document is written later by the drain worker, in accept order for each storage key.
|
|
6
|
+
*
|
|
7
|
+
* The idempotency identity is storage key + run id + step id. Memorix derives it, keeps it in the
|
|
8
|
+
* receipt's `writeId`, and the existing unique `(orgId, caller, writeId)` index enforces it.
|
|
9
|
+
* "The same row" is the canonical content hash a synchronous write computes over the whole body:
|
|
10
|
+
* `data`, `_metadata`, `_audit` and the rest. The same tuple with any difference is `409 QUEUE_KEY_REUSED`.
|
|
11
|
+
*/
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
13
|
+
import { adoptRecordMetadata, canonicalJson, resolveContentInstanceFromDraft, resolveContentInstanceSelector, WriterError, } from "@x12i/memorix-data";
|
|
14
|
+
import { ServiceError } from "../errors.js";
|
|
15
|
+
import { normalizeWritePrecondition } from "../write-precondition.js";
|
|
16
|
+
import { asServiceError, batchError, CONTENT_BATCH_LIMIT, prepareWrite, queuedBody, storageKey, } from "./content-write.js";
|
|
17
|
+
import { newReceiptId, } from "./receipt-store.js";
|
|
18
|
+
/**
|
|
19
|
+
* A new row is not applied for this long. A second accept for the same key may hold a lower accept
|
|
20
|
+
* number and still be on its way to the database. The wait lets it land first.
|
|
21
|
+
*/
|
|
22
|
+
export const QUEUE_SETTLE_MS = 500;
|
|
23
|
+
const MAX_ID_LENGTH = 200;
|
|
24
|
+
/** `queue` is absent, or a boolean. */
|
|
25
|
+
export function readQueueFlag(value) {
|
|
26
|
+
if (value === undefined || value === null || value === false)
|
|
27
|
+
return false;
|
|
28
|
+
if (value === true)
|
|
29
|
+
return true;
|
|
30
|
+
throw new ServiceError("VALIDATION", "queue must be a boolean", 400, { field: "queue", retryable: false });
|
|
31
|
+
}
|
|
32
|
+
function validation(field, message) {
|
|
33
|
+
return new ServiceError("VALIDATION", message, 400, { field, retryable: false });
|
|
34
|
+
}
|
|
35
|
+
/** ACCEPT-03: what a queued write may not carry. */
|
|
36
|
+
function assertQueueShape(body) {
|
|
37
|
+
if (body.writeId !== undefined && body.writeId !== null && body.writeId !== "") {
|
|
38
|
+
throw validation("writeId", "writeId is not used with queue: true. Memorix derives the idempotency key from the storage key, run id and step id.");
|
|
39
|
+
}
|
|
40
|
+
if (body.op !== undefined && body.op !== "upsert") {
|
|
41
|
+
throw validation("op", "a queued write is an upsert. patch, replace, add and remove use the synchronous write.");
|
|
42
|
+
}
|
|
43
|
+
if (body.precondition !== undefined && body.precondition !== null) {
|
|
44
|
+
const form = normalizeWritePrecondition(body.precondition, body.expectedRevision).form;
|
|
45
|
+
if (form !== "none") {
|
|
46
|
+
throw validation("precondition", `a queued write uses precondition none, not ${form}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (body.expectedRevision !== undefined && body.expectedRevision !== null) {
|
|
50
|
+
throw validation("expectedRevision", "a queued write has no caller revision. Memorix assigns it.");
|
|
51
|
+
}
|
|
52
|
+
if (!body.record || typeof body.record !== "object" || Array.isArray(body.record)) {
|
|
53
|
+
throw validation("record", "record required");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function readExecutionId(execution, name) {
|
|
57
|
+
const field = `_metadata.execution.${name}`;
|
|
58
|
+
const value = execution[name];
|
|
59
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
60
|
+
throw validation(field, `${field} is required with queue: true`);
|
|
61
|
+
}
|
|
62
|
+
const trimmed = value.trim();
|
|
63
|
+
if (trimmed.length > MAX_ID_LENGTH) {
|
|
64
|
+
throw validation(field, `${field} must be at most ${MAX_ID_LENGTH} characters`);
|
|
65
|
+
}
|
|
66
|
+
return trimmed;
|
|
67
|
+
}
|
|
68
|
+
/** Run id and step id, read after the fold a synchronous write applies to `properties` / `metadata` / `_metadata`. */
|
|
69
|
+
function executionIds(record) {
|
|
70
|
+
const data = record.data && typeof record.data === "object" && !Array.isArray(record.data)
|
|
71
|
+
? record.data
|
|
72
|
+
: {};
|
|
73
|
+
const folded = adoptRecordMetadata({ ...record, data });
|
|
74
|
+
const execution = folded._metadata?.execution;
|
|
75
|
+
if (!execution || typeof execution !== "object" || Array.isArray(execution)) {
|
|
76
|
+
throw validation("_metadata.execution", "_metadata.execution.runId and _metadata.execution.stepId are required with queue: true");
|
|
77
|
+
}
|
|
78
|
+
const bag = execution;
|
|
79
|
+
return { runId: readExecutionId(bag, "runId"), stepId: readExecutionId(bag, "stepId") };
|
|
80
|
+
}
|
|
81
|
+
function keyIdOf(objectType, contentType, address) {
|
|
82
|
+
return `${objectType}\u0000${contentType}\u0000${address}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The queue key of one stored-document address, or null when the address cannot be resolved
|
|
86
|
+
* (for example a discriminated content type read without its discriminator).
|
|
87
|
+
*/
|
|
88
|
+
export function queueKeyIdFor(catalog, args) {
|
|
89
|
+
try {
|
|
90
|
+
const address = resolveContentInstanceSelector({
|
|
91
|
+
recordId: args.recordId,
|
|
92
|
+
contentType: args.contentType,
|
|
93
|
+
discriminatorValue: args.discriminatorValue,
|
|
94
|
+
catalog,
|
|
95
|
+
});
|
|
96
|
+
return keyIdOf(args.objectType, args.contentType, address.storageKey);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The record a queued row will write, shaped like a stored read, minus the `revision` it does not have yet.
|
|
104
|
+
*/
|
|
105
|
+
export function pendingRecord(row) {
|
|
106
|
+
const record = structuredClone(row.request.record ?? {});
|
|
107
|
+
delete record.revision;
|
|
108
|
+
return record;
|
|
109
|
+
}
|
|
110
|
+
function addMs(iso, ms) {
|
|
111
|
+
return new Date(Date.parse(iso) + ms).toISOString();
|
|
112
|
+
}
|
|
113
|
+
function nowOf(deps) {
|
|
114
|
+
return (deps.now ?? (() => new Date().toISOString()))();
|
|
115
|
+
}
|
|
116
|
+
/** Validate the row and derive its identity. Nothing is stored. */
|
|
117
|
+
function prepareQueued(deps, body, now) {
|
|
118
|
+
assertQueueShape(body);
|
|
119
|
+
const { queue: _queue, ...rest } = body;
|
|
120
|
+
void _queue;
|
|
121
|
+
const prepared = prepareWrite(deps, { ...rest, op: "upsert", precondition: "none" }, now);
|
|
122
|
+
const request = prepared.request;
|
|
123
|
+
const catalog = deps.ports.catalog;
|
|
124
|
+
const objectType = catalog.getObjectType(request.objectType);
|
|
125
|
+
if (!objectType) {
|
|
126
|
+
throw new WriterError("ROUTE_UNKNOWN_OBJECT_TYPE", `Unknown objectType ${request.objectType}`);
|
|
127
|
+
}
|
|
128
|
+
if (!objectType.contentTypes.includes(request.contentType)) {
|
|
129
|
+
throw new WriterError("ROUTE_UNKNOWN_CONTENT_TYPE", `contentType ${request.contentType} not allowed for ${request.objectType}`, { objectType: request.objectType, contentType: request.contentType, allowed: objectType.contentTypes });
|
|
130
|
+
}
|
|
131
|
+
if (catalog.getContentProfile && !catalog.getContentProfile(request.contentType)) {
|
|
132
|
+
throw new WriterError("METADATA_DESCRIPTOR_MISSING", `content type ${request.contentType} on ${request.objectType} has no descriptor; ensure the pack at startup before writing`, { objectType: request.objectType, contentType: request.contentType });
|
|
133
|
+
}
|
|
134
|
+
const resolved = resolveContentInstanceFromDraft(request.record, catalog);
|
|
135
|
+
const { runId, stepId } = executionIds(body.record);
|
|
136
|
+
const recordId = resolved.address.recordId;
|
|
137
|
+
const key = storageKey(resolved.address.kind === "discriminated"
|
|
138
|
+
? { ...request, discriminatorValue: resolved.address.discriminatorValue }
|
|
139
|
+
: request, recordId);
|
|
140
|
+
const keyId = keyIdOf(request.objectType, request.contentType, resolved.address.storageKey);
|
|
141
|
+
const writeId = `queue:${createHash("sha256").update(canonicalJson({ keyId, runId, stepId })).digest("hex")}`;
|
|
142
|
+
return { prepared, identity: { keyId, runId, stepId, storageKey: key, writeId } };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Accept one row. 202 `queued`, or the answer for a repeat, or a rejection that stored nothing.
|
|
146
|
+
*/
|
|
147
|
+
export async function runQueuedWrite(deps, body) {
|
|
148
|
+
const now = nowOf(deps);
|
|
149
|
+
let prepared;
|
|
150
|
+
let identity;
|
|
151
|
+
try {
|
|
152
|
+
({ prepared, identity } = prepareQueued(deps, body, now));
|
|
153
|
+
await deps.checkWrite?.(prepared.request);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
return { kind: "rejected", error: asServiceError(err) };
|
|
157
|
+
}
|
|
158
|
+
const seq = await deps.receipts.reserveSeq(deps.scope.orgId, 1);
|
|
159
|
+
const row = {
|
|
160
|
+
receiptId: newReceiptId(),
|
|
161
|
+
orgId: deps.scope.orgId,
|
|
162
|
+
caller: deps.caller,
|
|
163
|
+
writeId: identity.writeId,
|
|
164
|
+
contentHash: prepared.contentHash,
|
|
165
|
+
status: "queued",
|
|
166
|
+
request: prepared.request,
|
|
167
|
+
queue: {
|
|
168
|
+
seq,
|
|
169
|
+
keyId: identity.keyId,
|
|
170
|
+
runId: identity.runId,
|
|
171
|
+
stepId: identity.stepId,
|
|
172
|
+
storageKey: identity.storageKey,
|
|
173
|
+
},
|
|
174
|
+
attempts: 0,
|
|
175
|
+
nextAttemptAt: addMs(now, QUEUE_SETTLE_MS),
|
|
176
|
+
createdAt: now,
|
|
177
|
+
updatedAt: now,
|
|
178
|
+
};
|
|
179
|
+
const inserted = await deps.receipts.insert(row);
|
|
180
|
+
if (inserted === "inserted")
|
|
181
|
+
return { kind: "queued", httpStatus: 202, body: queuedBody(row) };
|
|
182
|
+
const existing = await deps.receipts.findByWriteId(deps.scope.orgId, deps.caller, identity.writeId);
|
|
183
|
+
if (existing)
|
|
184
|
+
return answerRepeat(existing, prepared.contentHash);
|
|
185
|
+
return {
|
|
186
|
+
kind: "rejected",
|
|
187
|
+
error: new ServiceError("WRITE_UNAVAILABLE", "the write queue could not record this row; send it again", 503, {
|
|
188
|
+
retryable: true,
|
|
189
|
+
retryAfterMs: 1_000,
|
|
190
|
+
}),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/** The same tuple again: the original receipt, or 409 when the row differs. */
|
|
194
|
+
function answerRepeat(existing, contentHash) {
|
|
195
|
+
if (existing.contentHash !== contentHash) {
|
|
196
|
+
return {
|
|
197
|
+
kind: "rejected",
|
|
198
|
+
error: new ServiceError("QUEUE_KEY_REUSED", "this storage key, run id and step id was already accepted with different content. Send a correction under a new step id.", 409, { field: "stepId", retryable: false, receiptId: existing.receiptId }),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
if (existing.status === "stored") {
|
|
202
|
+
return { kind: "stored", httpStatus: 200, body: publicQueuedReceipt(existing) };
|
|
203
|
+
}
|
|
204
|
+
if (existing.status === "queued" || existing.status === "pending") {
|
|
205
|
+
return { kind: "queued", httpStatus: 202, body: queuedBody(existing) };
|
|
206
|
+
}
|
|
207
|
+
const error = existing.error;
|
|
208
|
+
return {
|
|
209
|
+
kind: "rejected",
|
|
210
|
+
error: new ServiceError(error?.code ?? "VALIDATION", error?.message ?? "write was rejected", error?.status ?? 400, {
|
|
211
|
+
field: error?.field,
|
|
212
|
+
retryable: false,
|
|
213
|
+
receiptId: existing.receiptId,
|
|
214
|
+
}),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Accept up to 500 rows in array order. Each row is stored and acknowledged before its result is recorded.
|
|
219
|
+
* One bad row does not reject the batch or drop rows already stored.
|
|
220
|
+
*/
|
|
221
|
+
export async function runQueuedBatch(deps, body, datasourceFor) {
|
|
222
|
+
if (!body || typeof body !== "object" || Array.isArray(body) || !Array.isArray(body.writes)) {
|
|
223
|
+
throw new ServiceError("VALIDATION", "writes must be an array", 400, { field: "writes", retryable: false });
|
|
224
|
+
}
|
|
225
|
+
const writes = body.writes;
|
|
226
|
+
if (writes.length > CONTENT_BATCH_LIMIT) {
|
|
227
|
+
throw new ServiceError("VALIDATION", `writes accepts at most ${CONTENT_BATCH_LIMIT} rows`, 400, {
|
|
228
|
+
field: "writes",
|
|
229
|
+
retryable: false,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
const results = [];
|
|
233
|
+
for (const item of writes) {
|
|
234
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) {
|
|
235
|
+
results.push({
|
|
236
|
+
error: { code: "VALIDATION", field: "writes", message: "each write must be an object", retryable: false },
|
|
237
|
+
});
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
const row = item;
|
|
241
|
+
if (row.queue !== undefined) {
|
|
242
|
+
results.push({
|
|
243
|
+
error: {
|
|
244
|
+
code: "VALIDATION",
|
|
245
|
+
field: "queue",
|
|
246
|
+
message: "queue is set on the batch body, not on a row",
|
|
247
|
+
retryable: false,
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
253
|
+
const datasource = datasourceFor(row);
|
|
254
|
+
const outcome = await runQueuedWrite({ ...deps, datasource }, row);
|
|
255
|
+
if (outcome.kind === "rejected")
|
|
256
|
+
results.push(batchError(outcome.error));
|
|
257
|
+
else
|
|
258
|
+
results.push(outcome.body);
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
results.push(batchError(err));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return { results };
|
|
265
|
+
}
|
|
266
|
+
/** What `GET /api/data/receipts/:id`, the run list, and a repeat of a stored row return for a queued write. */
|
|
267
|
+
export function publicQueuedReceipt(row) {
|
|
268
|
+
const queue = row.queue;
|
|
269
|
+
return {
|
|
270
|
+
receiptId: row.receiptId,
|
|
271
|
+
status: row.status,
|
|
272
|
+
...(queue ? { storageKey: queue.storageKey, runId: queue.runId, stepId: queue.stepId } : {}),
|
|
273
|
+
createdAt: row.createdAt,
|
|
274
|
+
updatedAt: row.updatedAt,
|
|
275
|
+
...(row.status === "stored" && row.receipt ? { receipt: row.receipt } : {}),
|
|
276
|
+
...(row.status === "rejected" && row.error
|
|
277
|
+
? {
|
|
278
|
+
error: {
|
|
279
|
+
code: row.error.code,
|
|
280
|
+
field: row.error.field,
|
|
281
|
+
message: row.error.message,
|
|
282
|
+
retryable: row.error.retryable,
|
|
283
|
+
},
|
|
284
|
+
}
|
|
285
|
+
: {}),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=queued-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queued-write.js","sourceRoot":"","sources":["../../src/writes/queued-write.ts"],"names":[],"mappings":"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"}
|