@x12i/memorix-service 3.7.1 → 3.7.6

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 (140) hide show
  1. package/dist/activity-ring.d.ts +169 -0
  2. package/dist/activity-ring.d.ts.map +1 -0
  3. package/dist/activity-ring.js +234 -0
  4. package/dist/activity-ring.js.map +1 -0
  5. package/dist/activity-routes.d.ts +3 -0
  6. package/dist/activity-routes.d.ts.map +1 -0
  7. package/dist/activity-routes.js +41 -0
  8. package/dist/activity-routes.js.map +1 -0
  9. package/dist/activity-ui.d.ts +3 -0
  10. package/dist/activity-ui.d.ts.map +1 -0
  11. package/dist/activity-ui.js +899 -0
  12. package/dist/activity-ui.js.map +1 -0
  13. package/dist/app.d.ts.map +1 -1
  14. package/dist/app.js +14 -2
  15. package/dist/app.js.map +1 -1
  16. package/dist/caller-identity.d.ts +3 -2
  17. package/dist/caller-identity.d.ts.map +1 -1
  18. package/dist/caller-identity.js.map +1 -1
  19. package/dist/catalog-bridge.js +1 -1
  20. package/dist/catalog-bridge.js.map +1 -1
  21. package/dist/cli.d.ts.map +1 -1
  22. package/dist/cli.js +4 -0
  23. package/dist/cli.js.map +1 -1
  24. package/dist/connector-catalog.d.ts +1 -1
  25. package/dist/connector-ops/attempt-store.d.ts.map +1 -1
  26. package/dist/connector-ops/attempt-store.js +1 -3
  27. package/dist/connector-ops/attempt-store.js.map +1 -1
  28. package/dist/connector-ops/checkpoint-store.d.ts.map +1 -1
  29. package/dist/connector-ops/checkpoint-store.js +1 -3
  30. package/dist/connector-ops/checkpoint-store.js.map +1 -1
  31. package/dist/connector-ops/override-store.d.ts.map +1 -1
  32. package/dist/connector-ops/override-store.js +1 -3
  33. package/dist/connector-ops/override-store.js.map +1 -1
  34. package/dist/connector-ops/run-store.d.ts.map +1 -1
  35. package/dist/connector-ops/run-store.js +1 -3
  36. package/dist/connector-ops/run-store.js.map +1 -1
  37. package/dist/connector-ops/schedule-lease-store.d.ts.map +1 -1
  38. package/dist/connector-ops/schedule-lease-store.js +1 -3
  39. package/dist/connector-ops/schedule-lease-store.js.map +1 -1
  40. package/dist/data-changes-routes.d.ts +7 -0
  41. package/dist/data-changes-routes.d.ts.map +1 -0
  42. package/dist/data-changes-routes.js +27 -0
  43. package/dist/data-changes-routes.js.map +1 -0
  44. package/dist/data-changes-ui.d.ts +3 -0
  45. package/dist/data-changes-ui.d.ts.map +1 -0
  46. package/dist/data-changes-ui.js +239 -0
  47. package/dist/data-changes-ui.js.map +1 -0
  48. package/dist/data-changes.d.ts +51 -0
  49. package/dist/data-changes.d.ts.map +1 -0
  50. package/dist/data-changes.js +218 -0
  51. package/dist/data-changes.js.map +1 -0
  52. package/dist/errors.d.ts +3 -0
  53. package/dist/errors.d.ts.map +1 -1
  54. package/dist/errors.js +36 -3
  55. package/dist/errors.js.map +1 -1
  56. package/dist/identity-alias.d.ts +12 -0
  57. package/dist/identity-alias.d.ts.map +1 -0
  58. package/dist/identity-alias.js +22 -0
  59. package/dist/identity-alias.js.map +1 -0
  60. package/dist/incremental-state/state-store.d.ts.map +1 -1
  61. package/dist/incremental-state/state-store.js +1 -3
  62. package/dist/incremental-state/state-store.js.map +1 -1
  63. package/dist/integrations/instance-store.d.ts.map +1 -1
  64. package/dist/integrations/instance-store.js +1 -3
  65. package/dist/integrations/instance-store.js.map +1 -1
  66. package/dist/isolation.d.ts.map +1 -1
  67. package/dist/isolation.js +3 -2
  68. package/dist/isolation.js.map +1 -1
  69. package/dist/land-v2-guards.d.ts +22 -0
  70. package/dist/land-v2-guards.d.ts.map +1 -0
  71. package/dist/land-v2-guards.js +57 -0
  72. package/dist/land-v2-guards.js.map +1 -0
  73. package/dist/live.d.ts.map +1 -1
  74. package/dist/nexum-analysis/backfill.d.ts +59 -0
  75. package/dist/nexum-analysis/backfill.d.ts.map +1 -0
  76. package/dist/nexum-analysis/backfill.js +199 -0
  77. package/dist/nexum-analysis/backfill.js.map +1 -0
  78. package/dist/nexum-analysis/enqueue.d.ts +29 -0
  79. package/dist/nexum-analysis/enqueue.d.ts.map +1 -0
  80. package/dist/nexum-analysis/enqueue.js +190 -0
  81. package/dist/nexum-analysis/enqueue.js.map +1 -0
  82. package/dist/nexum-analysis/outbox.d.ts +44 -0
  83. package/dist/nexum-analysis/outbox.d.ts.map +1 -0
  84. package/dist/nexum-analysis/outbox.js +176 -0
  85. package/dist/nexum-analysis/outbox.js.map +1 -0
  86. package/dist/nexum-analysis/policy.d.ts +48 -0
  87. package/dist/nexum-analysis/policy.d.ts.map +1 -0
  88. package/dist/nexum-analysis/policy.js +165 -0
  89. package/dist/nexum-analysis/policy.js.map +1 -0
  90. package/dist/nexum-analysis/reconcile.d.ts +8 -0
  91. package/dist/nexum-analysis/reconcile.d.ts.map +1 -0
  92. package/dist/nexum-analysis/reconcile.js +37 -0
  93. package/dist/nexum-analysis/reconcile.js.map +1 -0
  94. package/dist/openapi/openapi.json +591 -4
  95. package/dist/operational-db.d.ts +6 -0
  96. package/dist/operational-db.d.ts.map +1 -0
  97. package/dist/operational-db.js +22 -0
  98. package/dist/operational-db.js.map +1 -0
  99. package/dist/platform.d.ts +4 -1
  100. package/dist/platform.d.ts.map +1 -1
  101. package/dist/platform.js +67 -14
  102. package/dist/platform.js.map +1 -1
  103. package/dist/request-countex.d.ts +25 -0
  104. package/dist/request-countex.d.ts.map +1 -1
  105. package/dist/request-countex.js +103 -18
  106. package/dist/request-countex.js.map +1 -1
  107. package/dist/restricted-store/object-store.d.ts.map +1 -1
  108. package/dist/restricted-store/object-store.js +1 -3
  109. package/dist/restricted-store/object-store.js.map +1 -1
  110. package/dist/routes/connector-invocations.d.ts.map +1 -1
  111. package/dist/routes/connector-invocations.js +7 -1
  112. package/dist/routes/connector-invocations.js.map +1 -1
  113. package/dist/routes/data.d.ts.map +1 -1
  114. package/dist/routes/data.js +105 -12
  115. package/dist/routes/data.js.map +1 -1
  116. package/dist/routes/knowledge.d.ts +8 -0
  117. package/dist/routes/knowledge.d.ts.map +1 -0
  118. package/dist/routes/knowledge.js +114 -0
  119. package/dist/routes/knowledge.js.map +1 -0
  120. package/dist/routes/memory.d.ts.map +1 -1
  121. package/dist/routes/memory.js +33 -9
  122. package/dist/routes/memory.js.map +1 -1
  123. package/dist/routes/metadata.d.ts.map +1 -1
  124. package/dist/routes/metadata.js +102 -1
  125. package/dist/routes/metadata.js.map +1 -1
  126. package/dist/routes/mgc-landing.d.ts.map +1 -1
  127. package/dist/routes/mgc-landing.js +90 -1
  128. package/dist/routes/mgc-landing.js.map +1 -1
  129. package/dist/routes/operations.d.ts.map +1 -1
  130. package/dist/routes/operations.js +39 -2
  131. package/dist/routes/operations.js.map +1 -1
  132. package/dist/routes/publications.d.ts +4 -0
  133. package/dist/routes/publications.d.ts.map +1 -0
  134. package/dist/routes/publications.js +111 -0
  135. package/dist/routes/publications.js.map +1 -0
  136. package/dist/routes/workflow.d.ts.map +1 -1
  137. package/dist/routes/workflow.js +18 -9
  138. package/dist/routes/workflow.js.map +1 -1
  139. package/openapi/openapi.json +591 -4
  140. package/package.json +5 -5
@@ -0,0 +1,239 @@
1
+ /** HTML for GET /_live/changes — OT×CT change matrix by collection target. */
2
+ export function dataChangesHtml() {
3
+ return `<!DOCTYPE html>
4
+ <html lang="en">
5
+ <head>
6
+ <meta charset="utf-8" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8
+ <title>Memorix · Data changes</title>
9
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
11
+ <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet" />
12
+ <style>
13
+ :root {
14
+ --bg: #0a0c10; --bg-elev: #10141b; --bg-row: #141922; --line: #242b38;
15
+ --text: #e8ebe6; --muted: #8a9288; --dim: #5c645c;
16
+ --ok: #3dba7a; --accent: #c8f082; --accent-ink: #0a0c10;
17
+ --sans: "IBM Plex Sans", system-ui, sans-serif;
18
+ --mono: "IBM Plex Mono", ui-monospace, monospace;
19
+ }
20
+ * { box-sizing: border-box; }
21
+ html, body { height: 100%; margin: 0; }
22
+ body {
23
+ font-family: var(--sans);
24
+ background:
25
+ radial-gradient(1200px 600px at 10% -10%, #1a2214 0%, transparent 55%),
26
+ radial-gradient(900px 500px at 100% 0%, #121820 0%, transparent 50%),
27
+ var(--bg);
28
+ color: var(--text); font-size: 14px; line-height: 1.45;
29
+ }
30
+ a { color: var(--accent); }
31
+ .shell { max-width: 1200px; margin: 0 auto; padding: 36px 28px 64px; }
32
+ header {
33
+ display: flex; align-items: flex-end; justify-content: space-between; gap: 24px;
34
+ margin-bottom: 22px; padding-bottom: 18px; border-bottom: 1px solid var(--line);
35
+ }
36
+ .brand { font-size: 26px; font-weight: 700; letter-spacing: -0.03em; }
37
+ .brand span { color: var(--accent); }
38
+ .sub { margin-top: 8px; color: var(--muted); font-size: 13px; max-width: 62ch; }
39
+ .meta { text-align: right; font-family: var(--mono); font-size: 11px; color: var(--dim); display: grid; gap: 4px; }
40
+ .toolbar {
41
+ display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
42
+ margin-bottom: 16px;
43
+ }
44
+ .tabs { display: flex; gap: 6px; flex-wrap: wrap; }
45
+ .tab, .btn, select, input {
46
+ appearance: none; border: 1px solid var(--line); background: var(--bg-row); color: var(--text);
47
+ font: 500 12px/1 var(--sans); padding: 10px 14px; border-radius: 2px;
48
+ }
49
+ .tab { cursor: pointer; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); background: transparent; }
50
+ .tab[aria-selected="true"] {
51
+ background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
52
+ }
53
+ .btn { cursor: pointer; }
54
+ .btn:hover { border-color: var(--accent); }
55
+ input, select { min-width: 140px; }
56
+ .summary {
57
+ display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 14px;
58
+ font-family: var(--mono); font-size: 12px; color: var(--muted);
59
+ }
60
+ .summary strong { color: var(--text); font-weight: 500; }
61
+ table { width: 100%; border-collapse: collapse; background: var(--bg-elev); border: 1px solid var(--line); }
62
+ th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
63
+ th {
64
+ font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
65
+ color: var(--dim); font-weight: 500; background: #0d1016; position: sticky; top: 0;
66
+ }
67
+ tr:last-child td { border-bottom: 0; }
68
+ tr:hover td { background: var(--bg-row); }
69
+ .mono { font-family: var(--mono); font-size: 12px; color: var(--muted); }
70
+ .num { font-family: var(--mono); font-size: 12px; text-align: right; white-space: nowrap; }
71
+ .db { color: var(--accent); }
72
+ .muted { color: var(--muted); }
73
+ .err { color: #e25a5a; margin: 12px 0; }
74
+ .group-head td {
75
+ background: #0d1016; font-family: var(--mono); font-size: 11px;
76
+ color: var(--dim); letter-spacing: 0.04em; text-transform: uppercase;
77
+ }
78
+ footer { margin-top: 28px; color: var(--dim); font-size: 12px; }
79
+ </style>
80
+ </head>
81
+ <body>
82
+ <div class="shell">
83
+ <header>
84
+ <div>
85
+ <div class="brand">Memorix <span>data changes</span></div>
86
+ <p class="sub">Records touched per collection <strong>target</strong> (database × objectType × contentType), from <span class="mono">_system.modifiedAt</span> / <span class="mono">createdAt</span>.</p>
87
+ </div>
88
+ <div class="meta">
89
+ <div><strong>UI</strong> /_live/changes</div>
90
+ <div><strong>API</strong> /_live/api/data-changes</div>
91
+ <div><a href="/_live">← live view</a> · <a href="/_live/activity">activity</a></div>
92
+ </div>
93
+ </header>
94
+
95
+ <div class="toolbar">
96
+ <nav class="tabs" role="tablist">
97
+ <button class="tab" role="tab" aria-selected="true" data-window="1h">Last hour</button>
98
+ <button class="tab" role="tab" aria-selected="false" data-window="24h">Last 24 hours</button>
99
+ </nav>
100
+ <label class="muted">Org
101
+ <select id="org"></select>
102
+ </label>
103
+ <label class="muted" style="display:flex;align-items:center;gap:6px">
104
+ <input type="checkbox" id="zeros" /> include zeros
105
+ </label>
106
+ <button class="btn" id="refresh" type="button">Refresh</button>
107
+ </div>
108
+
109
+ <div class="summary" id="summary"></div>
110
+ <div id="error" class="err" hidden></div>
111
+ <div id="table-wrap"></div>
112
+ <footer>Counts are live Mongo scans · windows are rolling from request time · reserved collections skipped</footer>
113
+ </div>
114
+ <script>
115
+ const $ = (id) => document.getElementById(id);
116
+ let report = null;
117
+ let activeWindow = "1h";
118
+
119
+ document.querySelectorAll(".tab").forEach((tab) => {
120
+ tab.addEventListener("click", () => {
121
+ document.querySelectorAll(".tab").forEach((t) => t.setAttribute("aria-selected", "false"));
122
+ tab.setAttribute("aria-selected", "true");
123
+ activeWindow = tab.dataset.window;
124
+ render();
125
+ });
126
+ });
127
+ $("refresh").onclick = () => load({ forceOrg: true });
128
+ $("org").onchange = () => load();
129
+ $("zeros").onchange = () => load();
130
+
131
+ function fmt(n) {
132
+ return new Intl.NumberFormat().format(n ?? 0);
133
+ }
134
+
135
+ function escapeHtml(s) {
136
+ return String(s ?? "").replace(/[&<>"']/g, (c) => ({
137
+ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;"
138
+ })[c]);
139
+ }
140
+
141
+ async function load(opts = {}) {
142
+ $("error").hidden = true;
143
+ $("summary").textContent = "Scanning…";
144
+ $("table-wrap").innerHTML = "";
145
+ const params = new URLSearchParams();
146
+ const org = $("org").value;
147
+ if (org && org !== "*") params.set("orgId", org);
148
+ if ($("zeros").checked) params.set("includeZeros", "1");
149
+ try {
150
+ const res = await fetch("/_live/api/data-changes?" + params.toString());
151
+ const body = await res.json();
152
+ if (!res.ok || body.ok === false) {
153
+ throw new Error(body?.error?.message || ("HTTP " + res.status));
154
+ }
155
+ report = body;
156
+ if (opts.forceOrg || $("org").options.length <= 1) {
157
+ fillOrgs(body.orgIds || [], org);
158
+ }
159
+ render();
160
+ } catch (e) {
161
+ $("summary").textContent = "";
162
+ $("error").hidden = false;
163
+ $("error").textContent = e.message || String(e);
164
+ }
165
+ }
166
+
167
+ function fillOrgs(orgIds, selected) {
168
+ const sel = $("org");
169
+ const keep = selected || sel.value || "*";
170
+ sel.innerHTML = "";
171
+ const all = document.createElement("option");
172
+ all.value = "*";
173
+ all.textContent = "All orgs";
174
+ sel.appendChild(all);
175
+ for (const id of orgIds) {
176
+ const o = document.createElement("option");
177
+ o.value = id;
178
+ o.textContent = id;
179
+ sel.appendChild(o);
180
+ }
181
+ sel.value = [...sel.options].some((o) => o.value === keep) ? keep : "*";
182
+ }
183
+
184
+ function render() {
185
+ if (!report) return;
186
+ const win = report.windows?.[activeWindow];
187
+ if (!win) {
188
+ $("summary").textContent = "No window data";
189
+ return;
190
+ }
191
+ $("summary").innerHTML =
192
+ "<span>since <strong>" + escapeHtml(win.since) + "</strong></span>" +
193
+ "<span>collections <strong>" + fmt(win.totals.collections) + "</strong></span>" +
194
+ "<span>with changes <strong>" + fmt(win.totals.changedCollections) + "</strong></span>" +
195
+ "<span>modified <strong>" + fmt(win.totals.changed) + "</strong></span>" +
196
+ "<span>created <strong>" + fmt(win.totals.created) + "</strong></span>" +
197
+ "<span>generated <strong>" + escapeHtml(report.generatedAt) + "</strong></span>";
198
+
199
+ const rows = win.rows || [];
200
+ if (!rows.length) {
201
+ $("table-wrap").innerHTML = "<p class='muted'>No matching content targets in this window.</p>";
202
+ return;
203
+ }
204
+
205
+ let html = "<table><thead><tr>" +
206
+ "<th>Org</th><th>Database</th><th>Kind</th><th>Object type</th><th>Content type</th>" +
207
+ "<th class='num'>Changed</th><th class='num'>Created</th><th class='num'>Total</th><th>Collection target</th>" +
208
+ "</tr></thead><tbody>";
209
+
210
+ let lastDb = "";
211
+ for (const r of rows) {
212
+ if (r.databaseName !== lastDb) {
213
+ lastDb = r.databaseName;
214
+ html += "<tr class='group-head'><td colspan='9'>" +
215
+ escapeHtml(r.orgId) + " · " + escapeHtml(r.databaseName) +
216
+ "</td></tr>";
217
+ }
218
+ html += "<tr>" +
219
+ "<td class='mono'>" + escapeHtml(r.orgId) + "</td>" +
220
+ "<td class='mono db'>" + escapeHtml(r.databaseName) + "</td>" +
221
+ "<td class='mono'>" + escapeHtml(r.kind) + "</td>" +
222
+ "<td>" + escapeHtml(r.objectType) + "</td>" +
223
+ "<td>" + escapeHtml(r.contentType) + "</td>" +
224
+ "<td class='num'>" + fmt(r.changed) + "</td>" +
225
+ "<td class='num'>" + fmt(r.created) + "</td>" +
226
+ "<td class='num'>" + fmt(r.total) + "</td>" +
227
+ "<td class='mono'>" + escapeHtml(r.collectionName) + "</td>" +
228
+ "</tr>";
229
+ }
230
+ html += "</tbody></table>";
231
+ $("table-wrap").innerHTML = html;
232
+ }
233
+
234
+ load({ forceOrg: true });
235
+ </script>
236
+ </body>
237
+ </html>`;
238
+ }
239
+ //# sourceMappingURL=data-changes-ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-changes-ui.js","sourceRoot":"","sources":["../src/data-changes-ui.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,UAAU,eAAe;IAC7B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA0OD,CAAC;AACT,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Scan org category databases for content-collection change counts
3
+ * (`_system.modifiedAt`) over rolling windows, keyed by collection target.
4
+ */
5
+ import type { MongoClient } from "mongodb";
6
+ import { type DatabaseKind } from "@x12i/memorix-data";
7
+ export type DataChangeWindowId = "1h" | "24h";
8
+ export type CollectionChangeTarget = {
9
+ orgId: string;
10
+ kind: DatabaseKind;
11
+ databaseName: string;
12
+ collectionName: string;
13
+ objectType: string;
14
+ contentType: string;
15
+ };
16
+ export type CollectionChangeCounts = CollectionChangeTarget & {
17
+ total: number;
18
+ changed: number;
19
+ created: number;
20
+ };
21
+ export type DataChangesWindowResult = {
22
+ window: DataChangeWindowId;
23
+ since: string;
24
+ until: string;
25
+ rows: CollectionChangeCounts[];
26
+ totals: {
27
+ collections: number;
28
+ changedCollections: number;
29
+ changed: number;
30
+ created: number;
31
+ };
32
+ };
33
+ export type DataChangesReport = {
34
+ generatedAt: string;
35
+ orgIds: string[];
36
+ windows: Record<DataChangeWindowId, DataChangesWindowResult>;
37
+ };
38
+ /** Longest objectType prefix match → contentType remainder. */
39
+ export declare function resolveObjectAndContentType(collectionName: string, objectTypes: readonly string[]): {
40
+ objectType: string;
41
+ contentType: string;
42
+ };
43
+ export type ScanDataChangesOpts = {
44
+ client: MongoClient;
45
+ /** Limit to one org; default all orgs with an operational DB. */
46
+ orgId?: string;
47
+ /** Include rows with zero changes in both windows (default false). */
48
+ includeZeros?: boolean;
49
+ };
50
+ export declare function scanDataChanges(opts: ScanDataChangesOpts): Promise<DataChangesReport>;
51
+ //# sourceMappingURL=data-changes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-changes.d.ts","sourceRoot":"","sources":["../src/data-changes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA4BxE,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,KAAK,CAAC;AAE9C,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,sBAAsB,GAAG;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,sBAAsB,EAAE,CAAC;IAC/B,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,kBAAkB,EAAE,uBAAuB,CAAC,CAAC;CAC9D,CAAC;AAMF,+DAA+D;AAC/D,wBAAgB,2BAA2B,CACzC,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAsB7C;AAiFD,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,WAAW,CAAC;IACpB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,wBAAsB,eAAe,CACnC,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,iBAAiB,CAAC,CAsH5B"}
@@ -0,0 +1,218 @@
1
+ import { databaseNameFor } from "@x12i/memorix-data";
2
+ import { isOperationalDbName, orgIdFromOperationalDbName, } from "./operational-db.js";
3
+ const DATABASE_KINDS = [
4
+ "entity",
5
+ "event",
6
+ "knowledge",
7
+ "operational",
8
+ ];
9
+ const RESERVED_COLLECTIONS = new Set([
10
+ "relationships",
11
+ "record-directory",
12
+ "system.profile",
13
+ ]);
14
+ /** Skip ops / underscore collections that are not OT-CT content targets. */
15
+ function isContentCollectionName(name) {
16
+ if (!name || RESERVED_COLLECTIONS.has(name))
17
+ return false;
18
+ if (name.startsWith("system."))
19
+ return false;
20
+ if (name.includes("_"))
21
+ return false;
22
+ if (!name.includes("-"))
23
+ return false;
24
+ return /^[a-z][a-z0-9-]*$/.test(name);
25
+ }
26
+ function windowMs(id) {
27
+ return id === "1h" ? 3_600_000 : 86_400_000;
28
+ }
29
+ /** Longest objectType prefix match → contentType remainder. */
30
+ export function resolveObjectAndContentType(collectionName, objectTypes) {
31
+ const sorted = [...objectTypes].sort((a, b) => b.length - a.length);
32
+ for (const objectType of sorted) {
33
+ const prefix = `${objectType}-`;
34
+ if (collectionName.startsWith(prefix) &&
35
+ collectionName.length > prefix.length) {
36
+ return {
37
+ objectType,
38
+ contentType: collectionName.slice(prefix.length),
39
+ };
40
+ }
41
+ }
42
+ const i = collectionName.lastIndexOf("-");
43
+ if (i > 0) {
44
+ return {
45
+ objectType: collectionName.slice(0, i),
46
+ contentType: collectionName.slice(i + 1),
47
+ };
48
+ }
49
+ return { objectType: collectionName, contentType: "" };
50
+ }
51
+ async function listOrgIds(client) {
52
+ const listed = await client.db().admin().listDatabases();
53
+ const ids = new Set();
54
+ for (const db of listed.databases ?? []) {
55
+ const name = String(db.name ?? "");
56
+ if (!isOperationalDbName(name))
57
+ continue;
58
+ const orgId = orgIdFromOperationalDbName(name);
59
+ if (orgId)
60
+ ids.add(orgId);
61
+ }
62
+ return [...ids].sort((a, b) => a.localeCompare(b));
63
+ }
64
+ async function objectTypesForOrg(client, orgId) {
65
+ const dbName = databaseNameFor(orgId, "operational");
66
+ try {
67
+ const types = await client
68
+ .db(dbName)
69
+ .collection("record-directory")
70
+ .distinct("objectType");
71
+ return types
72
+ .map((t) => String(t))
73
+ .filter((t) => t.length > 0)
74
+ .sort((a, b) => b.length - a.length || a.localeCompare(b));
75
+ }
76
+ catch {
77
+ return [];
78
+ }
79
+ }
80
+ async function countBothWindows(client, target, since1h, since24h) {
81
+ const coll = client
82
+ .db(target.databaseName)
83
+ .collection(target.collectionName);
84
+ const [total, changed1h, created1h, changed24h, created24h] = await Promise.all([
85
+ coll.estimatedDocumentCount(),
86
+ coll.countDocuments({ "_system.modifiedAt": { $gte: since1h } }),
87
+ coll.countDocuments({ "_system.createdAt": { $gte: since1h } }),
88
+ coll.countDocuments({ "_system.modifiedAt": { $gte: since24h } }),
89
+ coll.countDocuments({ "_system.createdAt": { $gte: since24h } }),
90
+ ]);
91
+ return { total, changed1h, created1h, changed24h, created24h };
92
+ }
93
+ function sortRows(rows) {
94
+ rows.sort((a, b) => {
95
+ if (a.orgId !== b.orgId)
96
+ return a.orgId.localeCompare(b.orgId);
97
+ if (a.databaseName !== b.databaseName) {
98
+ return a.databaseName.localeCompare(b.databaseName);
99
+ }
100
+ if (b.changed !== a.changed)
101
+ return b.changed - a.changed;
102
+ return a.collectionName.localeCompare(b.collectionName);
103
+ });
104
+ }
105
+ function summarize(rows) {
106
+ return {
107
+ collections: rows.length,
108
+ changedCollections: rows.filter((r) => r.changed > 0).length,
109
+ changed: rows.reduce((n, r) => n + r.changed, 0),
110
+ created: rows.reduce((n, r) => n + r.created, 0),
111
+ };
112
+ }
113
+ export async function scanDataChanges(opts) {
114
+ const until = new Date();
115
+ const untilIso = until.toISOString();
116
+ const since1h = new Date(until.getTime() - windowMs("1h")).toISOString();
117
+ const since24h = new Date(until.getTime() - windowMs("24h")).toISOString();
118
+ let orgIds = await listOrgIds(opts.client);
119
+ if (opts.orgId?.trim()) {
120
+ const want = opts.orgId.trim().toLowerCase();
121
+ orgIds = orgIds.filter((id) => id.toLowerCase() === want);
122
+ if (orgIds.length === 0)
123
+ orgIds = [opts.orgId.trim()];
124
+ }
125
+ const targets = [];
126
+ for (const orgId of orgIds) {
127
+ const objectTypes = await objectTypesForOrg(opts.client, orgId);
128
+ for (const kind of DATABASE_KINDS) {
129
+ const databaseName = databaseNameFor(orgId, kind);
130
+ let names = [];
131
+ try {
132
+ const cols = await opts.client
133
+ .db(databaseName)
134
+ .listCollections()
135
+ .toArray();
136
+ names = cols.map((c) => String(c.name));
137
+ }
138
+ catch {
139
+ continue;
140
+ }
141
+ if (names.length === 0)
142
+ continue;
143
+ for (const collectionName of names) {
144
+ if (!isContentCollectionName(collectionName))
145
+ continue;
146
+ const { objectType, contentType } = resolveObjectAndContentType(collectionName, objectTypes);
147
+ targets.push({
148
+ orgId,
149
+ kind,
150
+ databaseName,
151
+ collectionName,
152
+ objectType,
153
+ contentType,
154
+ });
155
+ }
156
+ }
157
+ }
158
+ const rows1h = [];
159
+ const rows24h = [];
160
+ const concurrency = 8;
161
+ let idx = 0;
162
+ async function worker() {
163
+ while (idx < targets.length) {
164
+ const my = idx++;
165
+ const target = targets[my];
166
+ try {
167
+ const counts = await countBothWindows(opts.client, target, since1h, since24h);
168
+ const has1h = counts.changed1h > 0 || counts.created1h > 0;
169
+ const has24h = counts.changed24h > 0 || counts.created24h > 0;
170
+ if (!opts.includeZeros && !has1h && !has24h)
171
+ continue;
172
+ if (opts.includeZeros || has1h) {
173
+ rows1h.push({
174
+ ...target,
175
+ total: counts.total,
176
+ changed: counts.changed1h,
177
+ created: counts.created1h,
178
+ });
179
+ }
180
+ if (opts.includeZeros || has24h) {
181
+ rows24h.push({
182
+ ...target,
183
+ total: counts.total,
184
+ changed: counts.changed24h,
185
+ created: counts.created24h,
186
+ });
187
+ }
188
+ }
189
+ catch {
190
+ /* skip unreadable collections */
191
+ }
192
+ }
193
+ }
194
+ await Promise.all(Array.from({ length: Math.min(concurrency, Math.max(targets.length, 1)) }, () => worker()));
195
+ sortRows(rows1h);
196
+ sortRows(rows24h);
197
+ return {
198
+ generatedAt: untilIso,
199
+ orgIds,
200
+ windows: {
201
+ "1h": {
202
+ window: "1h",
203
+ since: since1h,
204
+ until: untilIso,
205
+ rows: rows1h,
206
+ totals: summarize(rows1h),
207
+ },
208
+ "24h": {
209
+ window: "24h",
210
+ since: since24h,
211
+ until: untilIso,
212
+ rows: rows24h,
213
+ totals: summarize(rows24h),
214
+ },
215
+ },
216
+ };
217
+ }
218
+ //# sourceMappingURL=data-changes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-changes.js","sourceRoot":"","sources":["../src/data-changes.ts"],"names":[],"mappings":"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"}
package/dist/errors.d.ts CHANGED
@@ -10,6 +10,9 @@ export type ServiceErrorBody = {
10
10
  };
11
11
  };
12
12
  };
13
+ /** Actionable next step for undeclared OT/CT or a rejected metadata ensure handshake. */
14
+ export declare const METADATA_ENSURE_NEXT = "POST /api/metadata/ensure with your metadata pack and confirm:true before writing. pack.agentId must be one of x-memorix-agent-ids. Then retry this write. A 404 on /api/metadata/ensure means this host is older than @x12i/memorix-service@3.7.6.";
15
+ export declare const METADATA_ENSURE_BODY_NEXT = "Call POST /api/metadata/ensure with body { pack: <MetadataPack>, confirm: true }. pack.agentId must be one of x-memorix-agent-ids. Do not invent objectType/contentType on POST /api/data/content.";
13
16
  export declare class ServiceError extends Error {
14
17
  readonly code: string;
15
18
  readonly statusCode: number;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;QACtB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;KAC/C,CAAC;CACH,CAAC;AAEF,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;gBAEf,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,SAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAO/E;AA+DD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,gBAAgB,CAAC;CACxB,CAoDA;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CA2BrD"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;QACtB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;KAC/C,CAAC;CACH,CAAC;AAEF,yFAAyF;AACzF,eAAO,MAAM,oBAAoB,wPACsN,CAAC;AAExP,eAAO,MAAM,yBAAyB,uMACgK,CAAC;AAEvM,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;gBAEf,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,SAAM,EAAE,OAAO,CAAC,EAAE,OAAO;CAO/E;AAwFD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,gBAAgB,CAAC;CACxB,CAkEA;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CA2BrD"}
package/dist/errors.js CHANGED
@@ -1,3 +1,6 @@
1
+ /** Actionable next step for undeclared OT/CT or a rejected metadata ensure handshake. */
2
+ export const METADATA_ENSURE_NEXT = "POST /api/metadata/ensure with your metadata pack and confirm:true before writing. pack.agentId must be one of x-memorix-agent-ids. Then retry this write. A 404 on /api/metadata/ensure means this host is older than @x12i/memorix-service@3.7.6.";
3
+ export const METADATA_ENSURE_BODY_NEXT = "Call POST /api/metadata/ensure with body { pack: <MetadataPack>, confirm: true }. pack.agentId must be one of x-memorix-agent-ids. Do not invent objectType/contentType on POST /api/data/content.";
1
4
  export class ServiceError extends Error {
2
5
  code;
3
6
  statusCode;
@@ -27,6 +30,16 @@ const DATA_PLANE_STATUS = {
27
30
  DIRECTORY_CONFLICT_DATA_CATEGORY: 409,
28
31
  DIRECTORY_IDENTITY_REUSE_FORBIDDEN: 409,
29
32
  DIRECTORY_NOT_RESERVED: 409,
33
+ PUBLICATION_NOT_FOUND: 404,
34
+ PUBLICATION_MEMBER_UNAVAILABLE: 409,
35
+ PUBLICATION_NOT_COMMITTED: 409,
36
+ PUBLICATION_NOT_DRAFT: 409,
37
+ PUBLICATION_PINNED: 409,
38
+ PUBLICATION_EXISTS: 409,
39
+ WRITE_DIRECTORY_INCONSISTENT: 409,
40
+ WRITE_IDENTITY_ADOPTION: 400,
41
+ WRITE_IDENTITY_MISMATCH: 400,
42
+ WRITE_INTERFACE_BINDING: 400,
30
43
  // Unavailable / dependency
31
44
  READ_UNAVAILABLE: 503,
32
45
  ABSTRACT_WRITE_UNAVAILABLE: 503,
@@ -37,6 +50,7 @@ const DATA_PLANE_ERROR_NAMES = new Set([
37
50
  "ReaderError",
38
51
  "WriterError",
39
52
  "AbstractWriteError",
53
+ "PublicationError",
40
54
  ]);
41
55
  function dataPlaneStatus(code) {
42
56
  if (DATA_PLANE_STATUS[code] !== undefined)
@@ -47,7 +61,8 @@ function dataPlaneStatus(code) {
47
61
  code.startsWith("ROUTE_") ||
48
62
  code.startsWith("SCOPE_") ||
49
63
  code.startsWith("ABSTRACT_WRITE_") ||
50
- code.startsWith("DIRECTORY_")) {
64
+ code.startsWith("DIRECTORY_") ||
65
+ code.startsWith("PUBLICATION_")) {
51
66
  return 400;
52
67
  }
53
68
  return undefined;
@@ -64,9 +79,23 @@ function isDataPlaneLike(err) {
64
79
  // Duck-type when packages are duplicated across bundles
65
80
  return dataPlaneStatus(err.code) !== undefined;
66
81
  }
82
+ function mergeDetails(details, extra) {
83
+ const base = details && typeof details === "object" && !Array.isArray(details)
84
+ ? { ...details }
85
+ : details !== undefined
86
+ ? { value: details }
87
+ : {};
88
+ return { ...base, ...extra };
89
+ }
67
90
  export function mapErrorToHttp(err, correlationId) {
68
91
  if (err && typeof err === "object" && "code" in err && "statusCode" in err) {
69
92
  const e = err;
93
+ const details = e.code === "CONFIRMATION_REQUIRED" ||
94
+ (e.code === "VALIDATION" &&
95
+ typeof e.message === "string" &&
96
+ /pack(\.agentId)? required|must be one of x-memorix-agent-ids/i.test(e.message))
97
+ ? mergeDetails(e.details, { next: METADATA_ENSURE_BODY_NEXT })
98
+ : e.details;
70
99
  return {
71
100
  status: e.statusCode,
72
101
  body: {
@@ -74,7 +103,7 @@ export function mapErrorToHttp(err, correlationId) {
74
103
  code: e.code,
75
104
  message: e.message,
76
105
  correlationId,
77
- details: e.details,
106
+ details,
78
107
  },
79
108
  },
80
109
  };
@@ -93,6 +122,10 @@ export function mapErrorToHttp(err, correlationId) {
93
122
  }
94
123
  if (isDataPlaneLike(err)) {
95
124
  const status = dataPlaneStatus(err.code) ?? 500;
125
+ const details = err.code === "ROUTE_UNKNOWN_OBJECT_TYPE" ||
126
+ err.code === "ROUTE_UNKNOWN_CONTENT_TYPE"
127
+ ? mergeDetails(err.details, { next: METADATA_ENSURE_NEXT })
128
+ : err.details;
96
129
  return {
97
130
  status,
98
131
  body: {
@@ -100,7 +133,7 @@ export function mapErrorToHttp(err, correlationId) {
100
133
  code: err.code,
101
134
  message: err.message,
102
135
  correlationId,
103
- details: err.details,
136
+ details,
104
137
  },
105
138
  },
106
139
  };