optio-api 0.2.10 → 0.2.11
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 +7 -2
- package/dist/adapters/express.js +1 -1
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/fastify.js +1 -1
- package/dist/adapters/fastify.js.map +1 -1
- package/dist/adapters/nextjs-app.js +1 -1
- package/dist/adapters/nextjs-app.js.map +1 -1
- package/dist/adapters/nextjs-pages.js +1 -1
- package/dist/adapters/nextjs-pages.js.map +1 -1
- package/dist/discovery.d.ts +7 -1
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +18 -11
- package/dist/discovery.js.map +1 -1
- package/dist/process-change-hub.d.ts +87 -0
- package/dist/process-change-hub.d.ts.map +1 -0
- package/dist/process-change-hub.js +268 -0
- package/dist/process-change-hub.js.map +1 -0
- package/dist/process-change-relevance.d.ts +57 -0
- package/dist/process-change-relevance.d.ts.map +1 -0
- package/dist/process-change-relevance.js +101 -0
- package/dist/process-change-relevance.js.map +1 -0
- package/dist/stream-poller.d.ts +7 -0
- package/dist/stream-poller.d.ts.map +1 -1
- package/dist/stream-poller.js +288 -278
- package/dist/stream-poller.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { toProcessChange } from './process-change-relevance.js';
|
|
2
|
+
/** The server cannot provide change streams (standalone, or not allowed). */
|
|
3
|
+
export class ChangeStreamsUnavailable extends Error {
|
|
4
|
+
}
|
|
5
|
+
/** MongoDB error codes that mean "cannot watch here": change streams need a
|
|
6
|
+
* replica set (40573); the user may not watch (13, Unauthorized). */
|
|
7
|
+
const UNAVAILABLE_CODES = new Set([40573, 13]);
|
|
8
|
+
export class ProcessChangeHub {
|
|
9
|
+
source;
|
|
10
|
+
entries = new Map();
|
|
11
|
+
minIntervalMs;
|
|
12
|
+
pollIntervalMs;
|
|
13
|
+
retryUnavailableMs;
|
|
14
|
+
backoffMinMs;
|
|
15
|
+
backoffMaxMs;
|
|
16
|
+
_mode = 'idle';
|
|
17
|
+
opening = null;
|
|
18
|
+
handle = null;
|
|
19
|
+
pollTimer = null;
|
|
20
|
+
retryTimer = null;
|
|
21
|
+
backoffMs;
|
|
22
|
+
/** Bumped whenever the current stream (or open attempt) is abandoned, so
|
|
23
|
+
* its late callbacks are ignored. */
|
|
24
|
+
generation = 0;
|
|
25
|
+
constructor(source, opts = {}) {
|
|
26
|
+
this.source = source;
|
|
27
|
+
this.minIntervalMs = opts.minIntervalMs ?? 1000;
|
|
28
|
+
this.pollIntervalMs = opts.pollIntervalMs ?? 1000;
|
|
29
|
+
this.retryUnavailableMs = opts.retryUnavailableMs ?? 300_000;
|
|
30
|
+
this.backoffMinMs = opts.backoffMinMs ?? 1000;
|
|
31
|
+
this.backoffMaxMs = opts.backoffMaxMs ?? 30_000;
|
|
32
|
+
this.backoffMs = this.backoffMinMs;
|
|
33
|
+
}
|
|
34
|
+
get mode() {
|
|
35
|
+
return this._mode;
|
|
36
|
+
}
|
|
37
|
+
/** Number of subscribers. */
|
|
38
|
+
get size() {
|
|
39
|
+
return this.entries.size;
|
|
40
|
+
}
|
|
41
|
+
/** Resolves once the change stream is open or the hub is polling; the
|
|
42
|
+
* subscriber makes its initial read after that, so no change is lost. */
|
|
43
|
+
async subscribe(sub) {
|
|
44
|
+
if (!this.entries.has(sub))
|
|
45
|
+
this.entries.set(sub, { sub, last: -Infinity, timer: null });
|
|
46
|
+
if (this._mode === 'idle') {
|
|
47
|
+
this._mode = 'opening';
|
|
48
|
+
this.opening = this.tryOpen(true);
|
|
49
|
+
}
|
|
50
|
+
if (this._mode === 'opening' && this.opening)
|
|
51
|
+
await this.opening;
|
|
52
|
+
}
|
|
53
|
+
unsubscribe(sub) {
|
|
54
|
+
const entry = this.entries.get(sub);
|
|
55
|
+
if (!entry)
|
|
56
|
+
return;
|
|
57
|
+
if (entry.timer)
|
|
58
|
+
clearTimeout(entry.timer);
|
|
59
|
+
this.entries.delete(sub);
|
|
60
|
+
if (this.entries.size === 0)
|
|
61
|
+
this.shutdown();
|
|
62
|
+
}
|
|
63
|
+
shutdown() {
|
|
64
|
+
this.generation++;
|
|
65
|
+
this.stopPolling();
|
|
66
|
+
if (this.retryTimer)
|
|
67
|
+
clearTimeout(this.retryTimer);
|
|
68
|
+
this.retryTimer = null;
|
|
69
|
+
const handle = this.handle;
|
|
70
|
+
this.handle = null;
|
|
71
|
+
if (handle)
|
|
72
|
+
void handle.close().catch(() => { });
|
|
73
|
+
this.backoffMs = this.backoffMinMs;
|
|
74
|
+
this.opening = null;
|
|
75
|
+
this._mode = 'idle';
|
|
76
|
+
}
|
|
77
|
+
/** `initial`: the first attempt from idle, whose subscribers make their
|
|
78
|
+
* initial reads themselves; every later (re)open re-reads everyone once. */
|
|
79
|
+
async tryOpen(initial) {
|
|
80
|
+
const gen = ++this.generation;
|
|
81
|
+
try {
|
|
82
|
+
const handle = await this.source.open((c) => this.onChange(gen, c), (err) => this.onStreamError(gen, err));
|
|
83
|
+
if (gen !== this.generation) {
|
|
84
|
+
void handle.close().catch(() => { });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.handle = handle;
|
|
88
|
+
this._mode = 'streaming';
|
|
89
|
+
this.stopPolling();
|
|
90
|
+
this.backoffMs = this.backoffMinMs;
|
|
91
|
+
if (!initial)
|
|
92
|
+
this.refreshAll();
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
if (gen !== this.generation)
|
|
96
|
+
return;
|
|
97
|
+
this.enterPolling();
|
|
98
|
+
this.scheduleReopen(err instanceof ChangeStreamsUnavailable ? this.retryUnavailableMs : this.nextBackoff());
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
onChange(gen, c) {
|
|
102
|
+
if (gen !== this.generation)
|
|
103
|
+
return;
|
|
104
|
+
for (const entry of this.entries.values()) {
|
|
105
|
+
if (c.op === 'invalidate' || entry.sub.isRelevant(c))
|
|
106
|
+
this.requestRefresh(entry);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
onStreamError(gen, _err) {
|
|
110
|
+
if (gen !== this.generation)
|
|
111
|
+
return;
|
|
112
|
+
this.generation++;
|
|
113
|
+
const handle = this.handle;
|
|
114
|
+
this.handle = null;
|
|
115
|
+
if (handle)
|
|
116
|
+
void handle.close().catch(() => { });
|
|
117
|
+
this.enterPolling();
|
|
118
|
+
this.scheduleReopen(this.nextBackoff());
|
|
119
|
+
}
|
|
120
|
+
nextBackoff() {
|
|
121
|
+
const delay = this.backoffMs;
|
|
122
|
+
this.backoffMs = Math.min(this.backoffMs * 2, this.backoffMaxMs);
|
|
123
|
+
return delay;
|
|
124
|
+
}
|
|
125
|
+
scheduleReopen(delayMs) {
|
|
126
|
+
if (this.retryTimer)
|
|
127
|
+
clearTimeout(this.retryTimer);
|
|
128
|
+
this.retryTimer = setTimeout(() => {
|
|
129
|
+
this.retryTimer = null;
|
|
130
|
+
if (this.entries.size > 0)
|
|
131
|
+
void this.tryOpen(false);
|
|
132
|
+
}, delayMs);
|
|
133
|
+
}
|
|
134
|
+
enterPolling() {
|
|
135
|
+
this._mode = 'polling';
|
|
136
|
+
if (!this.pollTimer) {
|
|
137
|
+
this.pollTimer = setInterval(() => this.refreshAll(), this.pollIntervalMs);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
stopPolling() {
|
|
141
|
+
if (this.pollTimer)
|
|
142
|
+
clearInterval(this.pollTimer);
|
|
143
|
+
this.pollTimer = null;
|
|
144
|
+
}
|
|
145
|
+
refreshAll() {
|
|
146
|
+
for (const entry of this.entries.values())
|
|
147
|
+
this.requestRefresh(entry);
|
|
148
|
+
}
|
|
149
|
+
/** At most one refresh per minIntervalMs: at once after a quiet interval,
|
|
150
|
+
* else once at its end however many requests arrive meanwhile. */
|
|
151
|
+
requestRefresh(entry) {
|
|
152
|
+
if (entry.timer)
|
|
153
|
+
return;
|
|
154
|
+
const wait = entry.last + this.minIntervalMs - Date.now();
|
|
155
|
+
if (wait <= 0) {
|
|
156
|
+
entry.last = Date.now();
|
|
157
|
+
entry.sub.refresh();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
entry.timer = setTimeout(() => {
|
|
161
|
+
entry.timer = null;
|
|
162
|
+
if (!this.entries.has(entry.sub))
|
|
163
|
+
return;
|
|
164
|
+
entry.last = Date.now();
|
|
165
|
+
entry.sub.refresh();
|
|
166
|
+
}, wait);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function unavailable(err) {
|
|
170
|
+
const code = err?.code;
|
|
171
|
+
return typeof code === 'number' && UNAVAILABLE_CODES.has(code);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Runs inside MongoDB: each change is cut down to what the relevance rules
|
|
175
|
+
* use -- operation, id, the changed top-level field names, an insert's or
|
|
176
|
+
* replace's `rootId` and `originatingSessionId`, an update's new
|
|
177
|
+
* `originatingSessionId` -- so log lines, progress messages and whole new
|
|
178
|
+
* documents never reach the API. `_id` (the resume token) stays.
|
|
179
|
+
*/
|
|
180
|
+
const TRIM_CHANGES = [{
|
|
181
|
+
$project: {
|
|
182
|
+
operationType: 1,
|
|
183
|
+
documentKey: 1,
|
|
184
|
+
'fullDocument.rootId': 1,
|
|
185
|
+
'fullDocument.originatingSessionId': 1,
|
|
186
|
+
changedFields: {
|
|
187
|
+
$concatArrays: [
|
|
188
|
+
{ $map: { input: { $objectToArray: { $ifNull: ['$updateDescription.updatedFields', {}] } }, in: '$$this.k' } },
|
|
189
|
+
{ $ifNull: ['$updateDescription.removedFields', []] },
|
|
190
|
+
{ $map: { input: { $ifNull: ['$updateDescription.truncatedArrays', []] }, in: '$$this.field' } },
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
sessionValue: '$updateDescription.updatedFields.originatingSessionId',
|
|
194
|
+
},
|
|
195
|
+
}];
|
|
196
|
+
/** A ProcessChangeSource over `{prefix}_processes` of `db`. Whether the
|
|
197
|
+
* server can watch is MongoDB's answer to the first read (a standalone
|
|
198
|
+
* mongod refuses with 40573; a replica set or a sharded cluster accepts). */
|
|
199
|
+
export function createMongoProcessChangeSource(db, prefix) {
|
|
200
|
+
return {
|
|
201
|
+
async open(onChange, onError) {
|
|
202
|
+
const hello = await db.admin().command({ hello: 1 });
|
|
203
|
+
// From the cluster time of `hello`: nothing written after open()
|
|
204
|
+
// resolves is missed.
|
|
205
|
+
const startAtOperationTime = hello.operationTime;
|
|
206
|
+
const stream = db.collection(`${prefix}_processes`).watch(TRIM_CHANGES, startAtOperationTime ? { startAtOperationTime } : {});
|
|
207
|
+
let closed = false;
|
|
208
|
+
const deliver = (ev) => {
|
|
209
|
+
const change = ev ? toProcessChange(ev) : null;
|
|
210
|
+
if (change)
|
|
211
|
+
onChange(change);
|
|
212
|
+
};
|
|
213
|
+
try {
|
|
214
|
+
// Creates the cursor on the server now, so a refusal shows here.
|
|
215
|
+
deliver(await stream.tryNext());
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
await stream.close().catch(() => { });
|
|
219
|
+
if (unavailable(err))
|
|
220
|
+
throw new ChangeStreamsUnavailable(String(err));
|
|
221
|
+
throw err;
|
|
222
|
+
}
|
|
223
|
+
void (async () => {
|
|
224
|
+
try {
|
|
225
|
+
while (!closed)
|
|
226
|
+
deliver(await stream.next());
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
if (!closed)
|
|
230
|
+
onError(err);
|
|
231
|
+
}
|
|
232
|
+
})();
|
|
233
|
+
return {
|
|
234
|
+
async close() {
|
|
235
|
+
closed = true;
|
|
236
|
+
await stream.close();
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
const UNAVAILABLE_SOURCE = {
|
|
243
|
+
async open() {
|
|
244
|
+
throw new ChangeStreamsUnavailable('change streams switched off (OPTIO_API_CHANGE_STREAMS=off)');
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
const registry = new WeakMap();
|
|
248
|
+
/** The hub of `{prefix}_processes` in `db`, shared per client, database name
|
|
249
|
+
* and prefix (multi-database mode may create a new Db object per request).
|
|
250
|
+
* OPTIO_API_CHANGE_STREAMS=off makes new hubs poll. */
|
|
251
|
+
export function getProcessChangeHub(db, prefix) {
|
|
252
|
+
let hubs = registry.get(db.client);
|
|
253
|
+
if (!hubs) {
|
|
254
|
+
hubs = new Map();
|
|
255
|
+
registry.set(db.client, hubs);
|
|
256
|
+
}
|
|
257
|
+
const key = `${db.databaseName}\u0000${prefix}`;
|
|
258
|
+
let hub = hubs.get(key);
|
|
259
|
+
if (!hub) {
|
|
260
|
+
const source = process.env.OPTIO_API_CHANGE_STREAMS === 'off'
|
|
261
|
+
? UNAVAILABLE_SOURCE
|
|
262
|
+
: createMongoProcessChangeSource(db, prefix);
|
|
263
|
+
hub = new ProcessChangeHub(source);
|
|
264
|
+
hubs.set(key, hub);
|
|
265
|
+
}
|
|
266
|
+
return hub;
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=process-change-hub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-change-hub.js","sourceRoot":"","sources":["../src/process-change-hub.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which changes of `{prefix}_processes` a live stream must re-read for,
|
|
3
|
+
* decided from the change event alone (no extra read). The rules lean towards
|
|
4
|
+
* "relevant": a false positive costs one read, a false negative a stale stream.
|
|
5
|
+
*
|
|
6
|
+
* Spec: docs/2026-10-09-api-change-streams-design.md ("What is relevant")
|
|
7
|
+
*/
|
|
8
|
+
import type { ChangeStreamDocument, Document } from 'mongodb';
|
|
9
|
+
/**
|
|
10
|
+
* The fields the list stream compares and sends; the list poll reads nothing
|
|
11
|
+
* else (no log, widgetData, params or sessionEvents), so each read stays small.
|
|
12
|
+
*/
|
|
13
|
+
export declare const LIST_PROJECTION: {
|
|
14
|
+
readonly processId: 1;
|
|
15
|
+
readonly name: 1;
|
|
16
|
+
readonly status: 1;
|
|
17
|
+
readonly progress: 1;
|
|
18
|
+
readonly cancellable: 1;
|
|
19
|
+
readonly special: 1;
|
|
20
|
+
readonly warning: 1;
|
|
21
|
+
readonly metadata: 1;
|
|
22
|
+
readonly depth: 1;
|
|
23
|
+
readonly supportsResume: 1;
|
|
24
|
+
readonly hasSavedState: 1;
|
|
25
|
+
readonly supportsResurrect: 1;
|
|
26
|
+
readonly hasUnsavedWork: 1;
|
|
27
|
+
readonly resurrecting: 1;
|
|
28
|
+
readonly autoResumeScheduled: 1;
|
|
29
|
+
readonly browserOpenRequests: 1;
|
|
30
|
+
};
|
|
31
|
+
/** A change of one process document, reduced to what the rules need. Ids are
|
|
32
|
+
* the `_id` as a string (ObjectId hex). `fields` are the top-level keys an
|
|
33
|
+
* update touched; `values` its `updatedFields` as delivered. */
|
|
34
|
+
export type ProcessChange = {
|
|
35
|
+
op: 'insert' | 'replace';
|
|
36
|
+
id: string;
|
|
37
|
+
doc: Record<string, unknown>;
|
|
38
|
+
} | {
|
|
39
|
+
op: 'update';
|
|
40
|
+
id: string;
|
|
41
|
+
fields: Set<string>;
|
|
42
|
+
values: Record<string, unknown>;
|
|
43
|
+
} | {
|
|
44
|
+
op: 'delete';
|
|
45
|
+
id: string;
|
|
46
|
+
} | {
|
|
47
|
+
op: 'invalidate';
|
|
48
|
+
};
|
|
49
|
+
export declare function toProcessChange(ev: ChangeStreamDocument<Document>): ProcessChange | null;
|
|
50
|
+
/** The list stream (`members`: the ids it showed in its last read). */
|
|
51
|
+
export declare function listRelevant(c: ProcessChange, members: Set<string>): boolean;
|
|
52
|
+
/** A tree or multi-tree stream (`roots`: its root ids; `members`: the ids it
|
|
53
|
+
* showed in its last read, flat ids included). */
|
|
54
|
+
export declare function treeRelevant(c: ProcessChange, roots: Set<string>, members: Set<string>): boolean;
|
|
55
|
+
/** The session-events stream of `sessionId` (`members`: the ids it read). */
|
|
56
|
+
export declare function sessionRelevant(c: ProcessChange, sessionId: string, members: Set<string>): boolean;
|
|
57
|
+
//# sourceMappingURL=process-change-relevance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-change-relevance.d.ts","sourceRoot":"","sources":["../src/process-change-relevance.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;CAKlB,CAAC;AAIX;;iEAEiE;AACjE,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,QAAQ,GAAG,SAAS,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GACtE;IAAE,EAAE,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAClF;IAAE,EAAE,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,EAAE,EAAE,YAAY,CAAA;CAAE,CAAC;AAIzB,wBAAgB,eAAe,CAAC,EAAE,EAAE,oBAAoB,CAAC,QAAQ,CAAC,GAAG,aAAa,GAAG,IAAI,CAuCxF;AAOD,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAW5E;AAED;mDACmD;AACnD,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAWhG;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAalG"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fields the list stream compares and sends; the list poll reads nothing
|
|
3
|
+
* else (no log, widgetData, params or sessionEvents), so each read stays small.
|
|
4
|
+
*/
|
|
5
|
+
export const LIST_PROJECTION = {
|
|
6
|
+
processId: 1, name: 1, status: 1, progress: 1, cancellable: 1, special: 1,
|
|
7
|
+
warning: 1, metadata: 1, depth: 1, supportsResume: 1, hasSavedState: 1,
|
|
8
|
+
supportsResurrect: 1, hasUnsavedWork: 1, resurrecting: 1,
|
|
9
|
+
autoResumeScheduled: 1, browserOpenRequests: 1,
|
|
10
|
+
};
|
|
11
|
+
const LIST_FIELDS = new Set(Object.keys(LIST_PROJECTION));
|
|
12
|
+
const topLevel = (path) => path.split('.', 1)[0];
|
|
13
|
+
export function toProcessChange(ev) {
|
|
14
|
+
switch (ev.operationType) {
|
|
15
|
+
case 'insert':
|
|
16
|
+
case 'replace':
|
|
17
|
+
return {
|
|
18
|
+
op: ev.operationType,
|
|
19
|
+
id: String(ev.documentKey._id),
|
|
20
|
+
doc: (ev.fullDocument ?? {}),
|
|
21
|
+
};
|
|
22
|
+
case 'update': {
|
|
23
|
+
const trimmed = ev;
|
|
24
|
+
if (Array.isArray(trimmed.changedFields)) {
|
|
25
|
+
// Cut down by the change stream's own pipeline (process-change-hub.ts).
|
|
26
|
+
return {
|
|
27
|
+
op: 'update',
|
|
28
|
+
id: String(ev.documentKey._id),
|
|
29
|
+
fields: new Set(trimmed.changedFields.map(topLevel)),
|
|
30
|
+
values: 'sessionValue' in trimmed ? { originatingSessionId: trimmed.sessionValue } : {},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const desc = ev.updateDescription ?? {};
|
|
34
|
+
const values = (desc.updatedFields ?? {});
|
|
35
|
+
const fields = new Set([
|
|
36
|
+
...Object.keys(values).map(topLevel),
|
|
37
|
+
...(desc.removedFields ?? []).map(topLevel),
|
|
38
|
+
...(desc.truncatedArrays ?? []).map((t) => topLevel(t.field)),
|
|
39
|
+
]);
|
|
40
|
+
return { op: 'update', id: String(ev.documentKey._id), fields, values };
|
|
41
|
+
}
|
|
42
|
+
case 'delete':
|
|
43
|
+
return { op: 'delete', id: String(ev.documentKey._id) };
|
|
44
|
+
case 'drop':
|
|
45
|
+
case 'rename':
|
|
46
|
+
case 'dropDatabase':
|
|
47
|
+
case 'invalidate':
|
|
48
|
+
return { op: 'invalidate' };
|
|
49
|
+
default:
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const touches = (fields, wanted) => {
|
|
54
|
+
for (const f of fields)
|
|
55
|
+
if (wanted.has(f))
|
|
56
|
+
return true;
|
|
57
|
+
return false;
|
|
58
|
+
};
|
|
59
|
+
/** The list stream (`members`: the ids it showed in its last read). */
|
|
60
|
+
export function listRelevant(c, members) {
|
|
61
|
+
switch (c.op) {
|
|
62
|
+
case 'invalidate':
|
|
63
|
+
case 'insert':
|
|
64
|
+
case 'replace': // may start or stop matching, like an insert
|
|
65
|
+
return true;
|
|
66
|
+
case 'delete':
|
|
67
|
+
return members.has(c.id);
|
|
68
|
+
case 'update':
|
|
69
|
+
return c.fields.has('metadata') || (members.has(c.id) && touches(c.fields, LIST_FIELDS));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** A tree or multi-tree stream (`roots`: its root ids; `members`: the ids it
|
|
73
|
+
* showed in its last read, flat ids included). */
|
|
74
|
+
export function treeRelevant(c, roots, members) {
|
|
75
|
+
switch (c.op) {
|
|
76
|
+
case 'invalidate':
|
|
77
|
+
return true;
|
|
78
|
+
case 'insert':
|
|
79
|
+
case 'replace':
|
|
80
|
+
return members.has(c.id) || roots.has(String(c.doc.rootId));
|
|
81
|
+
case 'delete':
|
|
82
|
+
case 'update':
|
|
83
|
+
return members.has(c.id);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** The session-events stream of `sessionId` (`members`: the ids it read). */
|
|
87
|
+
export function sessionRelevant(c, sessionId, members) {
|
|
88
|
+
switch (c.op) {
|
|
89
|
+
case 'invalidate':
|
|
90
|
+
return true;
|
|
91
|
+
case 'insert':
|
|
92
|
+
case 'replace':
|
|
93
|
+
return c.doc.originatingSessionId === sessionId;
|
|
94
|
+
case 'delete':
|
|
95
|
+
return false; // a deleted process has no new events to send
|
|
96
|
+
case 'update':
|
|
97
|
+
return c.values.originatingSessionId === sessionId
|
|
98
|
+
|| (members.has(c.id) && c.fields.has('sessionEvents'));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=process-change-relevance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-change-relevance.js","sourceRoot":"","sources":["../src/process-change-relevance.ts"],"names":[],"mappings":"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"}
|
package/dist/stream-poller.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ObjectId, type Db } from 'mongodb';
|
|
2
2
|
import type { ProcessMetadataFilter } from 'optio-contracts';
|
|
3
3
|
import type { ScopeFilter } from './auth.js';
|
|
4
|
+
import { type ProcessChangeHub } from './process-change-hub.js';
|
|
4
5
|
export interface StreamPollerOptions {
|
|
5
6
|
db: Db;
|
|
6
7
|
prefix: string;
|
|
@@ -9,6 +10,8 @@ export interface StreamPollerOptions {
|
|
|
9
10
|
metadataFilter?: ProcessMetadataFilter;
|
|
10
11
|
/** Access scope (auth.ts): only processes inside it are emitted. */
|
|
11
12
|
scope?: ScopeFilter | null;
|
|
13
|
+
/** The change hub to follow; default: the shared hub of (db, prefix). */
|
|
14
|
+
hub?: ProcessChangeHub;
|
|
12
15
|
}
|
|
13
16
|
export interface ListPollerHandle {
|
|
14
17
|
start(): void;
|
|
@@ -33,6 +36,8 @@ export interface MultiTreePollerOptions {
|
|
|
33
36
|
treeRoots: MultiTreeRoot[];
|
|
34
37
|
flatIds: ObjectId[];
|
|
35
38
|
maxDepth?: number;
|
|
39
|
+
/** The change hub to follow; default: the shared hub of (db, prefix). */
|
|
40
|
+
hub?: ProcessChangeHub;
|
|
36
41
|
}
|
|
37
42
|
export declare function createMultiTreePoller(opts: MultiTreePollerOptions): ListPollerHandle;
|
|
38
43
|
export interface SessionEventsPollerOptions {
|
|
@@ -43,6 +48,8 @@ export interface SessionEventsPollerOptions {
|
|
|
43
48
|
onError: () => void;
|
|
44
49
|
/** Access scope (auth.ts): only processes inside it are read. */
|
|
45
50
|
scope?: ScopeFilter | null;
|
|
51
|
+
/** The change hub to follow; default: the shared hub of (db, prefix). */
|
|
52
|
+
hub?: ProcessChangeHub;
|
|
46
53
|
}
|
|
47
54
|
/**
|
|
48
55
|
* Poll-backed session-events feed. Each ~1s tick reads processes whose
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-poller.d.ts","sourceRoot":"","sources":["../src/stream-poller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"stream-poller.d.ts","sourceRoot":"","sources":["../src/stream-poller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAI7C,OAAO,EAA2C,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEzG,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,EAAE,CAAC;IACP,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,CAAC,EAAE,qBAAqB,CAAC;IACvC,oEAAoE;IACpE,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,yEAAyE;IACzE,GAAG,CAAC,EAAE,gBAAgB,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,IAAI,CAAC;CACd;AAqED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,mBAAmB,GAAG,gBAAgB,CAyD5E;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,mBAAmB,EAAE,gBAAgB,GAAG,OAAO,CAAC;IAC9F,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,CAoG1E;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,QAAQ,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,EAAE,CAAC;IACP,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,GAAG,CAAC,EAAE,gBAAgB,CAAC;CACxB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,sBAAsB,GAAG,gBAAgB,CAkHpF;AAED,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,EAAE,CAAC;IACP,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,iEAAiE;IACjE,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,yEAAyE;IACzE,GAAG,CAAC,EAAE,gBAAgB,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,0BAA0B,GAAG,gBAAgB,CA6B5F"}
|