@x12i/memorix-service 3.9.2 → 3.11.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/dist/analytics/content-allow.d.ts +17 -0
- package/dist/analytics/content-allow.d.ts.map +1 -0
- package/dist/analytics/content-allow.js +39 -0
- package/dist/analytics/content-allow.js.map +1 -0
- package/dist/analytics/definition.d.ts +179 -0
- package/dist/analytics/definition.d.ts.map +1 -0
- package/dist/analytics/definition.js +524 -0
- package/dist/analytics/definition.js.map +1 -0
- package/dist/analytics/engine.d.ts +63 -0
- package/dist/analytics/engine.d.ts.map +1 -0
- package/dist/analytics/engine.js +181 -0
- package/dist/analytics/engine.js.map +1 -0
- package/dist/analytics/host.d.ts +15 -0
- package/dist/analytics/host.d.ts.map +1 -0
- package/dist/analytics/host.js +143 -0
- package/dist/analytics/host.js.map +1 -0
- package/dist/analytics/index-store.d.ts +98 -0
- package/dist/analytics/index-store.d.ts.map +1 -0
- package/dist/analytics/index-store.js +295 -0
- package/dist/analytics/index-store.js.map +1 -0
- package/dist/analytics/materializer.d.ts +88 -0
- package/dist/analytics/materializer.d.ts.map +1 -0
- package/dist/analytics/materializer.js +364 -0
- package/dist/analytics/materializer.js.map +1 -0
- package/dist/analytics/pipeline-port.d.ts +10 -0
- package/dist/analytics/pipeline-port.d.ts.map +1 -0
- package/dist/analytics/pipeline-port.js +42 -0
- package/dist/analytics/pipeline-port.js.map +1 -0
- package/dist/analytics/projector.d.ts +60 -0
- package/dist/analytics/projector.d.ts.map +1 -0
- package/dist/analytics/projector.js +270 -0
- package/dist/analytics/projector.js.map +1 -0
- package/dist/analytics/property-index.d.ts +87 -0
- package/dist/analytics/property-index.d.ts.map +1 -0
- package/dist/analytics/property-index.js +537 -0
- package/dist/analytics/property-index.js.map +1 -0
- package/dist/analytics/state.d.ts +83 -0
- package/dist/analytics/state.d.ts.map +1 -0
- package/dist/analytics/state.js +273 -0
- package/dist/analytics/state.js.map +1 -0
- package/dist/analytics/tracker.d.ts +215 -0
- package/dist/analytics/tracker.d.ts.map +1 -0
- package/dist/analytics/tracker.js +1515 -0
- package/dist/analytics/tracker.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +6 -0
- package/dist/app.js.map +1 -1
- package/dist/content-census-countex.d.ts +15 -0
- package/dist/content-census-countex.d.ts.map +1 -0
- package/dist/content-census-countex.js +18 -0
- package/dist/content-census-countex.js.map +1 -0
- package/dist/datasource-backfill.d.ts +2 -0
- package/dist/datasource-backfill.d.ts.map +1 -1
- package/dist/datasource-backfill.js +5 -1
- package/dist/datasource-backfill.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/openapi/openapi.json +955 -210
- package/dist/platform.d.ts +6 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +69 -4
- package/dist/platform.js.map +1 -1
- package/dist/routes/analytics-counters.d.ts +8 -0
- package/dist/routes/analytics-counters.d.ts.map +1 -0
- package/dist/routes/analytics-counters.js +100 -0
- package/dist/routes/analytics-counters.js.map +1 -0
- package/dist/routes/analytics-indexes.d.ts +8 -0
- package/dist/routes/analytics-indexes.d.ts.map +1 -0
- package/dist/routes/analytics-indexes.js +80 -0
- package/dist/routes/analytics-indexes.js.map +1 -0
- package/dist/routes/data.d.ts.map +1 -1
- package/dist/routes/data.js +22 -0
- package/dist/routes/data.js.map +1 -1
- package/dist/routes/datasource-backfill.d.ts.map +1 -1
- package/dist/routes/datasource-backfill.js +8 -1
- package/dist/routes/datasource-backfill.js.map +1 -1
- package/openapi/openapi.json +955 -210
- package/package.json +5 -5
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An agent names stored paths. Memorix keeps one index of those paths for that agent set
|
|
3
|
+
* and answers counters and eq/in/exists reads from it.
|
|
4
|
+
*/
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import { decodeCursor, encodeCursor, queryShapeHash, ReaderError, } from "@x12i/memorix-data";
|
|
7
|
+
import { ServiceError } from "../errors.js";
|
|
8
|
+
import { whereList, } from "./definition.js";
|
|
9
|
+
const ANALYTICS_SERVICE = "memorix-analytics";
|
|
10
|
+
const ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
11
|
+
const UNSAFE_PATH = /\$|\0/;
|
|
12
|
+
function stable(value) {
|
|
13
|
+
if (Array.isArray(value))
|
|
14
|
+
return value.map(stable);
|
|
15
|
+
if (value && typeof value === "object") {
|
|
16
|
+
const out = {};
|
|
17
|
+
for (const key of Object.keys(value).sort()) {
|
|
18
|
+
out[key] = stable(value[key]);
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
export function propertyIndexHash(def) {
|
|
25
|
+
return createHash("sha1").update(JSON.stringify(stable(def))).digest("hex").slice(0, 16);
|
|
26
|
+
}
|
|
27
|
+
function isSafePath(path) {
|
|
28
|
+
if (!path || path.startsWith("@") || path === "_id" || path.startsWith("$"))
|
|
29
|
+
return false;
|
|
30
|
+
if (UNSAFE_PATH.test(path) || path.includes("..") || path.startsWith(".") || path.endsWith("."))
|
|
31
|
+
return false;
|
|
32
|
+
return path.split(".").every((part) => part.length > 0);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Validates a stored-path index. Never consults abstracts, so it cannot emit META-REF-ABSTRACT.
|
|
36
|
+
*/
|
|
37
|
+
export function validatePropertyIndex(raw, catalog) {
|
|
38
|
+
const issues = [];
|
|
39
|
+
const push = (path, code, message) => issues.push({ path, code, message });
|
|
40
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
41
|
+
push("definition", "META-TYPE", "definition must be an object");
|
|
42
|
+
return issues;
|
|
43
|
+
}
|
|
44
|
+
const body = raw;
|
|
45
|
+
if ("abstractType" in body) {
|
|
46
|
+
push("abstractType", "META-ANALYTICS", "an index names stored paths, not an abstract");
|
|
47
|
+
}
|
|
48
|
+
if ("range" in body || "min" in body || "max" in body) {
|
|
49
|
+
push("definition", "META-ANALYTICS", "an index does not add a numeric range");
|
|
50
|
+
}
|
|
51
|
+
if (typeof body.id !== "string" || !body.id.trim())
|
|
52
|
+
push("id", "META-REQUIRED", "id must be a non-empty string");
|
|
53
|
+
else if (!ID_PATTERN.test(body.id.trim())) {
|
|
54
|
+
push("id", "META-TYPE", "id may contain letters, digits, dot, underscore, and dash");
|
|
55
|
+
}
|
|
56
|
+
if (typeof body.objectType !== "string" || !body.objectType.trim()) {
|
|
57
|
+
push("objectType", "META-REQUIRED", "objectType must be a non-empty string");
|
|
58
|
+
}
|
|
59
|
+
else if (!catalog.hasObjectType(body.objectType.trim())) {
|
|
60
|
+
push("objectType", "META-REF-OBJECT", `unknown object type "${body.objectType.trim()}"`);
|
|
61
|
+
}
|
|
62
|
+
if (typeof body.contentType !== "string" || !body.contentType.trim()) {
|
|
63
|
+
push("contentType", "META-REQUIRED", "contentType must be a non-empty string");
|
|
64
|
+
}
|
|
65
|
+
else if (typeof body.objectType === "string" && body.objectType.trim() && catalog.hasObjectType(body.objectType.trim())) {
|
|
66
|
+
const types = catalog.contentTypes(body.objectType.trim());
|
|
67
|
+
if (!types?.includes(body.contentType.trim())) {
|
|
68
|
+
push("contentType", "META-REF-CONTENT", `content type "${body.contentType.trim()}" is not registered on "${body.objectType.trim()}"`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!Array.isArray(body.properties) || body.properties.length === 0) {
|
|
72
|
+
push("properties", "META-REQUIRED", "properties must be a non-empty array of stored paths");
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
body.properties.forEach((property, i) => {
|
|
76
|
+
if (typeof property !== "string" || !isSafePath(property.trim())) {
|
|
77
|
+
push(`properties[${i}]`, "META-ANALYTICS", "properties must be stored paths such as data.responsePriority");
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return issues;
|
|
82
|
+
}
|
|
83
|
+
export function normalizePropertyIndex(raw) {
|
|
84
|
+
return {
|
|
85
|
+
id: raw.id.trim(),
|
|
86
|
+
objectType: raw.objectType.trim(),
|
|
87
|
+
contentType: raw.contentType.trim(),
|
|
88
|
+
properties: [...new Set(raw.properties.map((p) => p.trim()))].sort((a, b) => a.localeCompare(b)),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Paths a content measure, group, or split reads for one stored population. */
|
|
92
|
+
export function contentPaths(def, objectType, contentType) {
|
|
93
|
+
const paths = new Set();
|
|
94
|
+
const take = (node) => {
|
|
95
|
+
if (node.abstractType?.trim())
|
|
96
|
+
return;
|
|
97
|
+
if (node.objectType?.trim() !== objectType || node.contentType?.trim() !== contentType)
|
|
98
|
+
return;
|
|
99
|
+
const add = (property) => {
|
|
100
|
+
const path = property?.trim();
|
|
101
|
+
if (path)
|
|
102
|
+
paths.add(path);
|
|
103
|
+
};
|
|
104
|
+
add(node.property);
|
|
105
|
+
for (const pred of whereList(node.where))
|
|
106
|
+
add(pred.property);
|
|
107
|
+
add(node.split?.property);
|
|
108
|
+
for (const pred of whereList(node.subset))
|
|
109
|
+
add(pred.property);
|
|
110
|
+
};
|
|
111
|
+
for (const measure of def.measures ?? [])
|
|
112
|
+
take(measure);
|
|
113
|
+
for (const group of def.groups ?? [])
|
|
114
|
+
take(group);
|
|
115
|
+
for (const split of def.splits ?? [])
|
|
116
|
+
take(split);
|
|
117
|
+
return [...paths];
|
|
118
|
+
}
|
|
119
|
+
export function readStoredPath(record, path) {
|
|
120
|
+
let cur = record;
|
|
121
|
+
for (const part of path.split(".")) {
|
|
122
|
+
if (!cur || typeof cur !== "object" || Array.isArray(cur))
|
|
123
|
+
return null;
|
|
124
|
+
cur = cur[part];
|
|
125
|
+
if (cur === undefined)
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
return cur;
|
|
129
|
+
}
|
|
130
|
+
export function recordFromIndexValues(recordId, objectType, contentType, values) {
|
|
131
|
+
const root = { recordId, objectType, contentType };
|
|
132
|
+
for (const [path, value] of Object.entries(values)) {
|
|
133
|
+
if (value === null || value === undefined)
|
|
134
|
+
continue;
|
|
135
|
+
const parts = path.split(".");
|
|
136
|
+
let cur = root;
|
|
137
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
138
|
+
const key = parts[i];
|
|
139
|
+
const next = cur[key];
|
|
140
|
+
if (!next || typeof next !== "object" || Array.isArray(next))
|
|
141
|
+
cur[key] = {};
|
|
142
|
+
cur = cur[key];
|
|
143
|
+
}
|
|
144
|
+
cur[parts[parts.length - 1]] = value;
|
|
145
|
+
}
|
|
146
|
+
return root;
|
|
147
|
+
}
|
|
148
|
+
function sameAgents(a, b) {
|
|
149
|
+
if (a.length !== b.length)
|
|
150
|
+
return false;
|
|
151
|
+
return a.every((id, i) => id === b[i]);
|
|
152
|
+
}
|
|
153
|
+
function sortedAgents(agentIds) {
|
|
154
|
+
return [...new Set(agentIds)].sort((x, y) => x.localeCompare(y));
|
|
155
|
+
}
|
|
156
|
+
function writingService(record) {
|
|
157
|
+
const service = record?._system?._datasource
|
|
158
|
+
?.service;
|
|
159
|
+
return typeof service === "string" ? service : null;
|
|
160
|
+
}
|
|
161
|
+
function isGone(err) {
|
|
162
|
+
const code = err && typeof err === "object" && "code" in err ? String(err.code) : "";
|
|
163
|
+
return code === "READ_NOT_FOUND" || code === "WRITE_NOT_FOUND";
|
|
164
|
+
}
|
|
165
|
+
function serves(filters) {
|
|
166
|
+
return Boolean(filters?.length &&
|
|
167
|
+
filters.every((f) => f.op === "eq" || f.op === "in" || f.op === "exists"));
|
|
168
|
+
}
|
|
169
|
+
function predicateOf(filter) {
|
|
170
|
+
if (filter.op === "exists")
|
|
171
|
+
return { op: "exists", value: filter.value };
|
|
172
|
+
if (filter.op === "in")
|
|
173
|
+
return { op: "in", value: filter.value };
|
|
174
|
+
return { op: "eq", value: filter.value };
|
|
175
|
+
}
|
|
176
|
+
function concreteShape(query) {
|
|
177
|
+
return queryShapeHash({
|
|
178
|
+
kind: "concrete",
|
|
179
|
+
objectType: query.objectType,
|
|
180
|
+
contentType: query.contentType,
|
|
181
|
+
filters: query.filters ?? [],
|
|
182
|
+
sort: query.sort ?? [],
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function sortStaysOnRecordId(query) {
|
|
186
|
+
const sort = query.sort ?? [];
|
|
187
|
+
return sort.length === 0 || (sort.length === 1 && sort[0].field === "recordId");
|
|
188
|
+
}
|
|
189
|
+
export class PropertyIndexService {
|
|
190
|
+
o;
|
|
191
|
+
backfills = new Map();
|
|
192
|
+
constructor(o) {
|
|
193
|
+
this.o = o;
|
|
194
|
+
}
|
|
195
|
+
busy() {
|
|
196
|
+
return this.backfills.size > 0;
|
|
197
|
+
}
|
|
198
|
+
pending() {
|
|
199
|
+
return [...this.backfills.values()];
|
|
200
|
+
}
|
|
201
|
+
validate(agentIds, raw) {
|
|
202
|
+
return validatePropertyIndex(raw, this.o.catalogFor(agentIds));
|
|
203
|
+
}
|
|
204
|
+
async list(scope) {
|
|
205
|
+
const agents = sortedAgents(scope.agentIds);
|
|
206
|
+
const rows = await this.o.storeFor(scope.orgId).listIndexes();
|
|
207
|
+
return rows
|
|
208
|
+
.filter((row) => sameAgents(row.agentIds, agents))
|
|
209
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
210
|
+
}
|
|
211
|
+
async get(scope, id) {
|
|
212
|
+
const row = await this.o.storeFor(scope.orgId).getIndex(id);
|
|
213
|
+
if (!row || !sameAgents(row.agentIds, sortedAgents(scope.agentIds)))
|
|
214
|
+
return null;
|
|
215
|
+
return row;
|
|
216
|
+
}
|
|
217
|
+
async register(scope, raw, opts) {
|
|
218
|
+
const agents = sortedAgents(scope.agentIds);
|
|
219
|
+
const issues = this.validate(agents, raw);
|
|
220
|
+
if (issues.length > 0) {
|
|
221
|
+
throw new ServiceError("ANALYTICS_DEFINITION_INVALID", "property index is invalid", 400, { issues });
|
|
222
|
+
}
|
|
223
|
+
const def = normalizePropertyIndex(raw);
|
|
224
|
+
if (def.id.startsWith("@")) {
|
|
225
|
+
throw new ServiceError("ANALYTICS_DEFINITION_INVALID", "index ids starting with @ are reserved", 400);
|
|
226
|
+
}
|
|
227
|
+
const store = this.o.storeFor(scope.orgId);
|
|
228
|
+
const existing = await store.getIndex(def.id);
|
|
229
|
+
const hash = propertyIndexHash(def);
|
|
230
|
+
if (existing && !sameAgents(existing.agentIds, agents)) {
|
|
231
|
+
throw new ServiceError("ANALYTICS_INDEX_CONFLICT", `index "${def.id}" is registered for another agent`, 409);
|
|
232
|
+
}
|
|
233
|
+
if (existing && existing.hash === hash && existing.status !== "error") {
|
|
234
|
+
return existing;
|
|
235
|
+
}
|
|
236
|
+
if (existing && !opts.replace) {
|
|
237
|
+
throw new ServiceError("ANALYTICS_INDEX_EXISTS", `index "${def.id}" exists with a different definition; pass replace: true to rebuild it`, 409);
|
|
238
|
+
}
|
|
239
|
+
const at = this.o.now().toISOString();
|
|
240
|
+
const record = {
|
|
241
|
+
id: def.id,
|
|
242
|
+
orgId: scope.orgId,
|
|
243
|
+
agentIds: agents,
|
|
244
|
+
definition: def,
|
|
245
|
+
hash,
|
|
246
|
+
generation: (existing?.generation ?? 0) + 1,
|
|
247
|
+
status: "backfilling",
|
|
248
|
+
backfill: { cursor: null, done: false, seen: 0 },
|
|
249
|
+
registeredAt: existing?.registeredAt ?? at,
|
|
250
|
+
updatedAt: at,
|
|
251
|
+
registeredBy: opts.registeredBy ?? existing?.registeredBy ?? null,
|
|
252
|
+
liveAt: null,
|
|
253
|
+
error: null,
|
|
254
|
+
};
|
|
255
|
+
await store.saveIndex(record);
|
|
256
|
+
await store.dropRows(def.id, record.generation);
|
|
257
|
+
this.startBackfill(scope.orgId, def.id);
|
|
258
|
+
return record;
|
|
259
|
+
}
|
|
260
|
+
async remove(scope, id) {
|
|
261
|
+
const store = this.o.storeFor(scope.orgId);
|
|
262
|
+
const existing = await store.getIndex(id);
|
|
263
|
+
if (!existing || !sameAgents(existing.agentIds, sortedAgents(scope.agentIds)))
|
|
264
|
+
return false;
|
|
265
|
+
await store.deleteIndex(id);
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
async populationSource(orgId, agentIds, objectType, contentType, def) {
|
|
269
|
+
const needed = contentPaths(def, objectType, contentType);
|
|
270
|
+
const agents = sortedAgents(agentIds);
|
|
271
|
+
const rows = (await this.o.storeFor(orgId).listIndexes()).filter((row) => sameAgents(row.agentIds, agents) &&
|
|
272
|
+
row.definition.objectType === objectType &&
|
|
273
|
+
row.definition.contentType === contentType &&
|
|
274
|
+
needed.every((path) => row.definition.properties.includes(path)));
|
|
275
|
+
const live = rows.find((row) => row.status === "live");
|
|
276
|
+
if (live)
|
|
277
|
+
return { mode: "indexed", index: live };
|
|
278
|
+
if (rows.some((row) => row.status === "backfilling"))
|
|
279
|
+
return { mode: "pending" };
|
|
280
|
+
return { mode: "scan" };
|
|
281
|
+
}
|
|
282
|
+
async waitUntilCovered(orgId, agentIds, objectType, contentType, def) {
|
|
283
|
+
const deadline = Date.now() + 60_000;
|
|
284
|
+
for (;;) {
|
|
285
|
+
if (this.o.isClosed())
|
|
286
|
+
return;
|
|
287
|
+
const source = await this.populationSource(orgId, agentIds, objectType, contentType, def);
|
|
288
|
+
if (source.mode !== "pending")
|
|
289
|
+
return;
|
|
290
|
+
if (Date.now() > deadline)
|
|
291
|
+
throw new Error("property index backfill did not finish");
|
|
292
|
+
await new Promise((resolve) => setTimeout(resolve, 15));
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async pageSubjects(orgId, indexId, generation, afterRecordId, limit) {
|
|
296
|
+
const store = this.o.storeFor(orgId);
|
|
297
|
+
const index = await store.getIndex(indexId);
|
|
298
|
+
const property = index?.definition.properties[0];
|
|
299
|
+
if (!index || index.generation !== generation || !property) {
|
|
300
|
+
return { subjects: [], nextCursor: null };
|
|
301
|
+
}
|
|
302
|
+
const page = await store.pageRecords({ indexId, generation, property, afterRecordId, limit });
|
|
303
|
+
const values = await store.valuesFor(indexId, generation, page.recordIds);
|
|
304
|
+
return {
|
|
305
|
+
subjects: page.recordIds.map((recordId) => ({ recordId, values: values.get(recordId) ?? {} })),
|
|
306
|
+
nextCursor: page.hasMore ? page.recordIds[page.recordIds.length - 1] : null,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
async applyWrite(scope, event) {
|
|
310
|
+
const store = this.o.storeFor(scope.orgId);
|
|
311
|
+
const indexes = (await store.listIndexes()).filter((row) => row.status !== "error" &&
|
|
312
|
+
row.definition.objectType === event.objectType &&
|
|
313
|
+
row.definition.contentType === event.contentType);
|
|
314
|
+
if (indexes.length === 0)
|
|
315
|
+
return;
|
|
316
|
+
const reader = this.o.readerFor(scope);
|
|
317
|
+
let record;
|
|
318
|
+
try {
|
|
319
|
+
record = await reader.getContent(scope, {
|
|
320
|
+
objectType: event.objectType,
|
|
321
|
+
contentType: event.contentType,
|
|
322
|
+
recordId: event.recordId,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
catch (err) {
|
|
326
|
+
if (!isGone(err))
|
|
327
|
+
throw err;
|
|
328
|
+
record = null;
|
|
329
|
+
}
|
|
330
|
+
for (const index of indexes) {
|
|
331
|
+
if (!record || writingService(record) === ANALYTICS_SERVICE) {
|
|
332
|
+
await store.deleteRecord(index.id, index.generation, event.recordId);
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
const values = {};
|
|
336
|
+
for (const path of index.definition.properties)
|
|
337
|
+
values[path] = readStoredPath(record, path);
|
|
338
|
+
await store.writeRecord(index.id, index.generation, event.recordId, values);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
async countIndexed(scope, query) {
|
|
342
|
+
const covered = await this.cover(scope, query.objectType, query.contentType, query.filters);
|
|
343
|
+
if (!covered)
|
|
344
|
+
return null;
|
|
345
|
+
return this.countCovered(scope.orgId, covered.index, covered.filters);
|
|
346
|
+
}
|
|
347
|
+
async explainIndexed(scope, query) {
|
|
348
|
+
const covered = await this.cover(scope, query.objectType, query.contentType, query.filters);
|
|
349
|
+
if (!covered || covered.filters.length !== 1)
|
|
350
|
+
return null;
|
|
351
|
+
const filter = covered.filters[0];
|
|
352
|
+
return this.o.storeFor(scope.orgId).explainMatch({
|
|
353
|
+
indexId: covered.index.id,
|
|
354
|
+
generation: covered.index.generation,
|
|
355
|
+
property: filter.field,
|
|
356
|
+
predicate: predicateOf(filter),
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
async listFromIndex(scope, query, reader) {
|
|
360
|
+
if (!sortStaysOnRecordId(query))
|
|
361
|
+
return null;
|
|
362
|
+
const covered = await this.cover(scope, query.objectType, query.contentType, query.filters);
|
|
363
|
+
if (!covered)
|
|
364
|
+
return null;
|
|
365
|
+
const shape = concreteShape(query);
|
|
366
|
+
let after = null;
|
|
367
|
+
if (query.cursor) {
|
|
368
|
+
const cursor = decodeCursor(query.cursor);
|
|
369
|
+
if (cursor.kind !== "concrete" || cursor.shape !== shape) {
|
|
370
|
+
throw new ReaderError("READ_CURSOR_MISMATCH", "Cursor does not match the current query shape");
|
|
371
|
+
}
|
|
372
|
+
after = cursor.storageKey;
|
|
373
|
+
}
|
|
374
|
+
const limit = Math.max(query.limit ?? 50, 1);
|
|
375
|
+
const ids = await this.matchCovered(scope.orgId, covered.index, covered.filters, after, limit + 1);
|
|
376
|
+
const page = ids.slice(0, limit);
|
|
377
|
+
const items = [];
|
|
378
|
+
for (const recordId of page) {
|
|
379
|
+
try {
|
|
380
|
+
items.push((await reader.getContent(scope, { objectType: query.objectType, contentType: query.contentType, recordId }, query.include ? { include: query.include } : undefined)));
|
|
381
|
+
}
|
|
382
|
+
catch (err) {
|
|
383
|
+
if (!isGone(err))
|
|
384
|
+
throw err;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
const nextCursor = ids.length > limit
|
|
388
|
+
? encodeCursor({
|
|
389
|
+
v: 1,
|
|
390
|
+
kind: "concrete",
|
|
391
|
+
shape,
|
|
392
|
+
storageKey: page[page.length - 1],
|
|
393
|
+
sortValues: [],
|
|
394
|
+
})
|
|
395
|
+
: undefined;
|
|
396
|
+
return { items, nextCursor };
|
|
397
|
+
}
|
|
398
|
+
async cover(scope, objectType, contentType, filters) {
|
|
399
|
+
if (!serves(filters))
|
|
400
|
+
return null;
|
|
401
|
+
const fields = [...new Set(filters.map((f) => f.field))];
|
|
402
|
+
const agents = sortedAgents(scope.agentIds);
|
|
403
|
+
const index = (await this.o.storeFor(scope.orgId).listIndexes()).find((row) => row.status === "live" &&
|
|
404
|
+
sameAgents(row.agentIds, agents) &&
|
|
405
|
+
row.definition.objectType === objectType &&
|
|
406
|
+
row.definition.contentType === contentType &&
|
|
407
|
+
fields.every((field) => row.definition.properties.includes(field)));
|
|
408
|
+
return index ? { index, filters } : null;
|
|
409
|
+
}
|
|
410
|
+
async matchCovered(orgId, index, filters, after, limit) {
|
|
411
|
+
const store = this.o.storeFor(orgId);
|
|
412
|
+
if (filters.length === 1) {
|
|
413
|
+
const filter = filters[0];
|
|
414
|
+
const page = await store.matchRecords({
|
|
415
|
+
indexId: index.id,
|
|
416
|
+
generation: index.generation,
|
|
417
|
+
property: filter.field,
|
|
418
|
+
predicate: predicateOf(filter),
|
|
419
|
+
afterRecordId: after,
|
|
420
|
+
limit,
|
|
421
|
+
});
|
|
422
|
+
return page.recordIds;
|
|
423
|
+
}
|
|
424
|
+
let ids = null;
|
|
425
|
+
for (const filter of filters) {
|
|
426
|
+
const matched = await store.recordIdsFor({
|
|
427
|
+
indexId: index.id,
|
|
428
|
+
generation: index.generation,
|
|
429
|
+
property: filter.field,
|
|
430
|
+
predicate: predicateOf(filter),
|
|
431
|
+
});
|
|
432
|
+
const set = new Set(matched);
|
|
433
|
+
ids = ids ? ids.filter((id) => set.has(id)) : matched;
|
|
434
|
+
}
|
|
435
|
+
const ordered = (ids ?? []).filter((id) => !after || id > after).sort((a, b) => a.localeCompare(b));
|
|
436
|
+
return ordered.slice(0, limit);
|
|
437
|
+
}
|
|
438
|
+
async countCovered(orgId, index, filters) {
|
|
439
|
+
const store = this.o.storeFor(orgId);
|
|
440
|
+
if (filters.length === 1) {
|
|
441
|
+
const filter = filters[0];
|
|
442
|
+
return store.countRecords({
|
|
443
|
+
indexId: index.id,
|
|
444
|
+
generation: index.generation,
|
|
445
|
+
property: filter.field,
|
|
446
|
+
predicate: predicateOf(filter),
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
return (await this.matchCovered(orgId, index, filters, null, Number.MAX_SAFE_INTEGER)).length;
|
|
450
|
+
}
|
|
451
|
+
startBackfill(orgId, id) {
|
|
452
|
+
const key = `${orgId}\u001f${id}`;
|
|
453
|
+
if (this.backfills.has(key) || this.o.isClosed())
|
|
454
|
+
return;
|
|
455
|
+
const run = this.runBackfill(orgId, id)
|
|
456
|
+
.catch(async (err) => {
|
|
457
|
+
this.o.log("analytics: index backfill failed", { orgId, indexId: id, error: String(err) });
|
|
458
|
+
const store = this.o.storeFor(orgId);
|
|
459
|
+
const current = await store.getIndex(id);
|
|
460
|
+
if (current) {
|
|
461
|
+
await store.patchIndex(id, {
|
|
462
|
+
status: "error",
|
|
463
|
+
error: err instanceof Error ? err.message : String(err),
|
|
464
|
+
updatedAt: this.o.now().toISOString(),
|
|
465
|
+
}, current.generation);
|
|
466
|
+
}
|
|
467
|
+
})
|
|
468
|
+
.finally(() => {
|
|
469
|
+
this.backfills.delete(key);
|
|
470
|
+
});
|
|
471
|
+
this.backfills.set(key, run);
|
|
472
|
+
}
|
|
473
|
+
async runBackfill(orgId, id) {
|
|
474
|
+
const store = this.o.storeFor(orgId);
|
|
475
|
+
let index = await store.getIndex(id);
|
|
476
|
+
if (!index || index.status !== "backfilling")
|
|
477
|
+
return;
|
|
478
|
+
const generation = index.generation;
|
|
479
|
+
const still = async () => {
|
|
480
|
+
const current = await store.getIndex(id);
|
|
481
|
+
return current && current.generation === generation && current.status === "backfilling" && !this.o.isClosed()
|
|
482
|
+
? current
|
|
483
|
+
: null;
|
|
484
|
+
};
|
|
485
|
+
const scope = { orgId, agentIds: index.agentIds };
|
|
486
|
+
const reader = this.o.readerFor(scope);
|
|
487
|
+
let cursor = index.backfill.cursor;
|
|
488
|
+
let seen = index.backfill.seen;
|
|
489
|
+
for (;;) {
|
|
490
|
+
index = await still();
|
|
491
|
+
if (!index)
|
|
492
|
+
return;
|
|
493
|
+
const page = await reader.listContent(scope, {
|
|
494
|
+
objectType: index.definition.objectType,
|
|
495
|
+
contentType: index.definition.contentType,
|
|
496
|
+
limit: this.o.backfillPageSize,
|
|
497
|
+
...(cursor ? { cursor } : {}),
|
|
498
|
+
});
|
|
499
|
+
for (const record of page.items) {
|
|
500
|
+
if (writingService(record) === ANALYTICS_SERVICE)
|
|
501
|
+
continue;
|
|
502
|
+
const values = {};
|
|
503
|
+
for (const path of index.definition.properties)
|
|
504
|
+
values[path] = readStoredPath(record, path);
|
|
505
|
+
await store.writeRecord(index.id, generation, record.recordId, values);
|
|
506
|
+
}
|
|
507
|
+
seen += page.items.length;
|
|
508
|
+
cursor = page.nextCursor ?? null;
|
|
509
|
+
const done = !page.nextCursor;
|
|
510
|
+
const patched = await store.patchIndex(id, { backfill: { cursor, done, seen }, updatedAt: this.o.now().toISOString() }, generation);
|
|
511
|
+
if (!patched)
|
|
512
|
+
return;
|
|
513
|
+
if (done)
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
const at = this.o.now().toISOString();
|
|
517
|
+
const promoted = await store.patchIndex(id, { status: "live", liveAt: at, updatedAt: at, error: null }, generation);
|
|
518
|
+
if (!promoted)
|
|
519
|
+
return;
|
|
520
|
+
const live = await store.getIndex(id);
|
|
521
|
+
if (live && live.generation === generation && live.status === "live")
|
|
522
|
+
await this.o.onLive(orgId, live);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
/** Filtered listContent uses the caller's index. Anything else is the reader's own query. */
|
|
526
|
+
export function withIndexedContentReads(reader, scope, indexed) {
|
|
527
|
+
return {
|
|
528
|
+
...reader,
|
|
529
|
+
async listContent(queryScope, query) {
|
|
530
|
+
const page = await indexed.listFromIndex(queryScope ?? scope, query, reader);
|
|
531
|
+
if (page)
|
|
532
|
+
return page;
|
|
533
|
+
return reader.listContent(queryScope, query);
|
|
534
|
+
},
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
//# sourceMappingURL=property-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-index.js","sourceRoot":"","sources":["../../src/analytics/property-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable state behind the counters: the registry, the per-subject fact ledger, and the
|
|
3
|
+
* covering pairs seen per counter generation. Stored in `{orgId}_operational`.
|
|
4
|
+
*/
|
|
5
|
+
import type { Db } from "mongodb";
|
|
6
|
+
import type { CounterDefinition } from "./definition.js";
|
|
7
|
+
import type { Fact } from "./projector.js";
|
|
8
|
+
export type CounterOrigin = "pack" | "api" | "builtin";
|
|
9
|
+
export type CounterStatus = "backfilling" | "live" | "error";
|
|
10
|
+
export type BackfillProgress = {
|
|
11
|
+
cursor: string | null;
|
|
12
|
+
done: boolean;
|
|
13
|
+
seen: number;
|
|
14
|
+
};
|
|
15
|
+
export type CounterRecord = {
|
|
16
|
+
id: string;
|
|
17
|
+
orgId: string;
|
|
18
|
+
origin: CounterOrigin;
|
|
19
|
+
agentIds: string[];
|
|
20
|
+
definition: CounterDefinition;
|
|
21
|
+
hash: string;
|
|
22
|
+
generation: number;
|
|
23
|
+
status: CounterStatus;
|
|
24
|
+
backfill: Record<string, BackfillProgress>;
|
|
25
|
+
registeredAt: string;
|
|
26
|
+
updatedAt: string;
|
|
27
|
+
registeredBy?: string | null;
|
|
28
|
+
liveAt?: string | null;
|
|
29
|
+
lastMaterializedAt?: string | null;
|
|
30
|
+
error?: string | null;
|
|
31
|
+
};
|
|
32
|
+
/** What a subject currently contributes to one counter generation. */
|
|
33
|
+
export type SubjectState = {
|
|
34
|
+
scope: string;
|
|
35
|
+
at: string;
|
|
36
|
+
facts: Fact[];
|
|
37
|
+
track: Record<string, unknown>;
|
|
38
|
+
};
|
|
39
|
+
export type LedgerRow = SubjectState & {
|
|
40
|
+
key: string;
|
|
41
|
+
seq: number;
|
|
42
|
+
pending?: (SubjectState | {
|
|
43
|
+
removed: true;
|
|
44
|
+
}) | null;
|
|
45
|
+
pendingAt?: string | null;
|
|
46
|
+
};
|
|
47
|
+
export type LedgerIntent = {
|
|
48
|
+
key: string;
|
|
49
|
+
/** Sequence read before projecting; `null` when the row did not exist. */
|
|
50
|
+
expectedSeq: number | null;
|
|
51
|
+
next: SubjectState | null;
|
|
52
|
+
};
|
|
53
|
+
export type PairRow = {
|
|
54
|
+
scope: string;
|
|
55
|
+
counterId: string;
|
|
56
|
+
generation: number;
|
|
57
|
+
pair: [string, string] | null;
|
|
58
|
+
firstSeenAt: string;
|
|
59
|
+
};
|
|
60
|
+
export interface AnalyticsStateStore {
|
|
61
|
+
listCounters(): Promise<CounterRecord[]>;
|
|
62
|
+
getCounter(id: string): Promise<CounterRecord | null>;
|
|
63
|
+
saveCounter(record: CounterRecord): Promise<void>;
|
|
64
|
+
/** Partial update; with `generation` set, applies only while the counter is still on it. */
|
|
65
|
+
patchCounter(id: string, patch: Partial<CounterRecord>, generation?: number): Promise<boolean>;
|
|
66
|
+
deleteCounter(id: string): Promise<void>;
|
|
67
|
+
readLedger(counterId: string, generation: number, keys: string[]): Promise<Map<string, LedgerRow>>;
|
|
68
|
+
/** Records intents stamped `at`; returns keys whose sequence moved since they were read. */
|
|
69
|
+
writeIntents(counterId: string, generation: number, intents: LedgerIntent[], at: string): Promise<string[]>;
|
|
70
|
+
commitIntents(counterId: string, generation: number, keys: string[]): Promise<void>;
|
|
71
|
+
/** Counter ids with intents recorded before `olderThan` and never committed. */
|
|
72
|
+
stalePending(olderThan: Date): Promise<string[]>;
|
|
73
|
+
/** Drops ledger rows and pairs of generations below `belowGeneration` (all when omitted). */
|
|
74
|
+
dropGenerations(counterId: string, belowGeneration?: number): Promise<void>;
|
|
75
|
+
/** Registers a covering pair (keeping the earliest `firstSeenAt`); true when it was not known yet. */
|
|
76
|
+
touchPair(row: PairRow): Promise<boolean>;
|
|
77
|
+
/** Pairs of a generation, most recently first-seen first. */
|
|
78
|
+
listPairs(counterId: string, generation: number, limit: number): Promise<PairRow[]>;
|
|
79
|
+
}
|
|
80
|
+
export declare function createMemoryAnalyticsState(): AnalyticsStateStore;
|
|
81
|
+
export declare function createMongoAnalyticsState(db: Db): AnalyticsStateStore;
|
|
82
|
+
export declare function mongoAnalyticsStateFactory(dbFor: (orgId: string) => Db): (orgId: string) => AnalyticsStateStore;
|
|
83
|
+
//# sourceMappingURL=state.d.ts.map
|