@graview/core 0.1.30 → 0.1.33
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 +11 -1
- package/dist/app.d.ts +8 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js.map +1 -1
- package/dist/capabilities.js +1 -1
- package/dist/capabilities.js.map +1 -1
- package/dist/catalog.d.ts +312 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +459 -0
- package/dist/catalog.js.map +1 -0
- package/dist/cli/document-schema.d.ts.map +1 -1
- package/dist/cli/document-schema.js +9 -0
- package/dist/cli/document-schema.js.map +1 -1
- package/dist/days.d.ts +7 -1
- package/dist/days.d.ts.map +1 -1
- package/dist/days.js +10 -4
- package/dist/days.js.map +1 -1
- package/dist/document/compile-checked.d.ts.map +1 -1
- package/dist/document/compile-checked.js +3 -2
- package/dist/document/compile-checked.js.map +1 -1
- package/dist/document/compiled.d.ts.map +1 -1
- package/dist/document/compiled.js +2 -0
- package/dist/document/compiled.js.map +1 -1
- package/dist/document/connection-findings.d.ts +6 -0
- package/dist/document/connection-findings.d.ts.map +1 -0
- package/dist/document/connection-findings.js +110 -0
- package/dist/document/connection-findings.js.map +1 -0
- package/dist/document/connection-spec.d.ts +38 -0
- package/dist/document/connection-spec.d.ts.map +1 -0
- package/dist/document/connection-spec.js +43 -0
- package/dist/document/connection-spec.js.map +1 -0
- package/dist/document/schema.d.ts +6 -5
- package/dist/document/schema.d.ts.map +1 -1
- package/dist/document/schema.js +7 -0
- package/dist/document/schema.js.map +1 -1
- package/dist/document/to-document.d.ts.map +1 -1
- package/dist/document/to-document.js +1 -0
- package/dist/document/to-document.js.map +1 -1
- package/dist/document.schema.json +149 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/installation.d.ts +1 -1
- package/dist/mutations/arg-shape.d.ts +2 -0
- package/dist/mutations/arg-shape.d.ts.map +1 -1
- package/dist/mutations/arg-shape.js +4 -0
- package/dist/mutations/arg-shape.js.map +1 -1
- package/dist/mutations/form.d.ts +2 -0
- package/dist/mutations/form.d.ts.map +1 -1
- package/dist/mutations/form.js +1 -1
- package/dist/mutations/form.js.map +1 -1
- package/dist/ops/lineage.d.ts +7 -0
- package/dist/ops/lineage.d.ts.map +1 -1
- package/dist/ops/lineage.js +5 -4
- package/dist/ops/lineage.js.map +1 -1
- package/dist/scaffold/project.d.ts.map +1 -1
- package/dist/scaffold/project.js +3 -0
- package/dist/scaffold/project.js.map +1 -1
- package/dist/scaffold/ui.d.ts.map +1 -1
- package/dist/scaffold/ui.js +3 -0
- package/dist/scaffold/ui.js.map +1 -1
- package/dist/subscription-shape.d.ts +135 -0
- package/dist/subscription-shape.d.ts.map +1 -0
- package/dist/subscription-shape.js +55 -0
- package/dist/subscription-shape.js.map +1 -0
- package/dist/subscriptions.d.ts +68 -0
- package/dist/subscriptions.d.ts.map +1 -0
- package/dist/subscriptions.js +425 -0
- package/dist/subscriptions.js.map +1 -0
- package/dist/sync/connection-filter.d.ts +12 -0
- package/dist/sync/connection-filter.d.ts.map +1 -0
- package/dist/sync/connection-filter.js +34 -0
- package/dist/sync/connection-filter.js.map +1 -0
- package/dist/sync/connection.d.ts +65 -0
- package/dist/sync/connection.d.ts.map +1 -0
- package/dist/sync/connection.js +148 -0
- package/dist/sync/connection.js.map +1 -0
- package/dist/sync/engine.d.ts +27 -6
- package/dist/sync/engine.d.ts.map +1 -1
- package/dist/sync/engine.js +49 -26
- package/dist/sync/engine.js.map +1 -1
- package/dist/sync/google-calendar.d.ts +27 -2
- package/dist/sync/google-calendar.d.ts.map +1 -1
- package/dist/sync/google-calendar.js +55 -14
- package/dist/sync/google-calendar.js.map +1 -1
- package/dist/sync/index.d.ts +4 -2
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +1 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wall-time.d.ts +60 -0
- package/dist/wall-time.d.ts.map +1 -0
- package/dist/wall-time.js +111 -0
- package/dist/wall-time.js.map +1 -0
- package/dist/when-typed.d.ts +15 -0
- package/dist/when-typed.d.ts.map +1 -0
- package/dist/when-typed.js +158 -0
- package/dist/when-typed.js.map +1 -0
- package/dist/words.d.ts +6 -1
- package/dist/words.d.ts.map +1 -1
- package/dist/words.js +6 -1
- package/dist/words.js.map +1 -1
- package/package.json +9 -1
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@graview/core/subscriptions` — NOTIFY ME WHEN X HAPPENS
|
|
3
|
+
* (Roadmap f-notify-subscriptions).
|
|
4
|
+
*
|
|
5
|
+
* A person says once what they want to hear about — an act being run (any,
|
|
6
|
+
* one by name, or one on one record), a record of a kind being added, a
|
|
7
|
+
* record of a kind or one record changing, or a record coming to satisfy a
|
|
8
|
+
* condition in the app's own expression language (`done == true`) — and
|
|
9
|
+
* every committed batch is judged against it AS THAT PERSON MAY SEE IT. A
|
|
10
|
+
* change to a record they cannot see is never a match, and what a match
|
|
11
|
+
* says is only what their sight shows: the same lens the log is served
|
|
12
|
+
* through (`seatLens`, `redact`), so a notification cannot tell anybody
|
|
13
|
+
* more than their own Activity would.
|
|
14
|
+
*
|
|
15
|
+
* The framework stops at a hook. `matchSubscriptions` is pure: a store, the
|
|
16
|
+
* ops one commit landed, the subscriptions — and back come the matches, at
|
|
17
|
+
* most one per batch per subscription, each with what changed. A host calls
|
|
18
|
+
* it where commits happen (`watchSubscriptions` over a store, `@graview/
|
|
19
|
+
* ship`'s handler over a served one) and hands each match to its own
|
|
20
|
+
* `onSubscriptionMatch` — Graview Cloud delivers it by email or push.
|
|
21
|
+
*
|
|
22
|
+
* WHERE SUBSCRIPTIONS ARE KEPT is a seam (`SubscriptionStore`: `list`,
|
|
23
|
+
* `add`, `remove`), never the graph: a subscription is about the app, not
|
|
24
|
+
* part of it, so it is not in the op log, not undone with a change, not in
|
|
25
|
+
* an export and not visible to anybody else. `memorySubscriptions()` (on the main entry, `@graview/core`) keeps
|
|
26
|
+
* them for one page or one process; `@graview/ship` keeps them in a file
|
|
27
|
+
* beside the store (`fileSubscriptions`) and serves them on the wire; a host
|
|
28
|
+
* keeps them wherever it keeps its users.
|
|
29
|
+
*
|
|
30
|
+
* Its own entry: a page that never subscribes carries none of it.
|
|
31
|
+
*/
|
|
32
|
+
import { parseExpr } from "./document/expr/parse.js";
|
|
33
|
+
import { evaluateExpr, ExprEvalError } from "./document/expr/evaluate.js";
|
|
34
|
+
import { shapesOfSchema } from "./document/rules.js";
|
|
35
|
+
import { isUnset } from "./graph/primitives.js";
|
|
36
|
+
import { isWithheld, redact, WITHHELD_AUTHOR } from "./ops/withheld.js";
|
|
37
|
+
import { actingAs } from "./permissions/policy.js";
|
|
38
|
+
import { actTitle, fieldWords, humanizeField, labelOf, nounOf, pluralOf, withArticle } from "./schema/define-node.js";
|
|
39
|
+
import { seatLens, seenBy } from "./seen.js";
|
|
40
|
+
import { nameOfAuthor } from "./who.js";
|
|
41
|
+
/**
|
|
42
|
+
* WHETHER A SUBSCRIPTION CAN EVER BE TOLD ANYTHING: its kind is a kind of
|
|
43
|
+
* the app, its act one of the app's acts, its record one the subscriber
|
|
44
|
+
* sees (in `store`, which is the store as they see it), and its condition
|
|
45
|
+
* an expression the rule language reads. Answers the sentence that says
|
|
46
|
+
* what is wrong, or undefined.
|
|
47
|
+
*/
|
|
48
|
+
export function subscriptionProblem(store, when) {
|
|
49
|
+
const kinds = store.schema.kinds;
|
|
50
|
+
const kind = "kind" in when ? when.kind : undefined;
|
|
51
|
+
if (kind !== undefined && !kinds.includes(kind))
|
|
52
|
+
return `There is no kind "${kind}" in this app. Its kinds are: ${kinds.join(", ")}.`;
|
|
53
|
+
if (when.on === "act" && when.act !== undefined && store.allMutations && !store.allMutations().some((act) => act.name === when.act)) {
|
|
54
|
+
return `There is no act "${when.act}" in this app.`;
|
|
55
|
+
}
|
|
56
|
+
const record = "record" in when ? when.record : undefined;
|
|
57
|
+
if (record !== undefined && store.graph && !store.graph.getNode(record))
|
|
58
|
+
return `No record "${record}" is here to be told about.`;
|
|
59
|
+
if (record !== undefined && kind !== undefined && store.graph && store.graph.getNode(record)?.kind !== kind)
|
|
60
|
+
return `“${record}” is not ${withArticle(kind)}.`;
|
|
61
|
+
if (when.on === "changed" && when.kind === undefined && when.record === undefined)
|
|
62
|
+
return "Say which kind, or which record, to be told about.";
|
|
63
|
+
if (when.on === "reaches") {
|
|
64
|
+
if (when.condition.trim() === "")
|
|
65
|
+
return "Say what it should reach: a condition like done == true.";
|
|
66
|
+
try {
|
|
67
|
+
parseExpr(when.condition);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return `The condition does not read: ${error instanceof Error ? error.message : String(error)}.`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
/** A record's name, from the store as a seat sees it, else its id. */
|
|
76
|
+
function nameIn(store, id) {
|
|
77
|
+
const node = store.graph?.getNode(id);
|
|
78
|
+
return node ? labelOf(store.schema.tryDefinition(node.kind), node) : id;
|
|
79
|
+
}
|
|
80
|
+
/** An act's own title, else its name said. */
|
|
81
|
+
function actWords(store, act) {
|
|
82
|
+
const declared = store.allMutations?.().find((one) => one.name === act);
|
|
83
|
+
return declared ? actTitle(declared) : humanizeField(act);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A SUBSCRIPTION IN WORDS: "When “Buy milk” changes", "When a task is
|
|
87
|
+
* added", "When someone runs “Mark it done” on “Buy milk”", "When a task
|
|
88
|
+
* reaches done == true". What the sheet, the list and a tool say it as.
|
|
89
|
+
*/
|
|
90
|
+
export function subscriptionWords(store, subscription) {
|
|
91
|
+
const { when } = subscription;
|
|
92
|
+
const someone = subscription.alsoMine ? "anyone" : "someone else";
|
|
93
|
+
const noun = (kind) => nounOf(store.schema.tryDefinition(kind), kind);
|
|
94
|
+
const a = (kind) => {
|
|
95
|
+
const word = noun(kind);
|
|
96
|
+
return `${/^[aeiou]/i.test(word) ? "an" : "a"} ${word}`;
|
|
97
|
+
};
|
|
98
|
+
switch (when.on) {
|
|
99
|
+
case "act": {
|
|
100
|
+
const what = when.act !== undefined ? `“${actWords(store, when.act)}”` : "an act";
|
|
101
|
+
return `When ${someone} runs ${what}${when.record !== undefined ? ` on “${nameIn(store, when.record)}”` : ""}`;
|
|
102
|
+
}
|
|
103
|
+
case "created":
|
|
104
|
+
return `When ${someone} adds ${a(when.kind)}`;
|
|
105
|
+
case "changed":
|
|
106
|
+
return when.record !== undefined ? `When ${someone} changes “${nameIn(store, when.record)}”` : `When ${someone} changes any of the ${pluralOf(store.schema, when.kind)}`;
|
|
107
|
+
case "reaches":
|
|
108
|
+
return `When ${when.record !== undefined ? `“${nameIn(store, when.record)}”` : a(when.kind)} reaches ${when.condition}${subscription.alsoMine ? "" : " (by someone else)"}`;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// ── the matcher ─────────────────────────────────────────────────────────────
|
|
112
|
+
const SHAPES = new WeakMap();
|
|
113
|
+
const shapesFor = (schema) => {
|
|
114
|
+
let shapes = SHAPES.get(schema);
|
|
115
|
+
if (!shapes)
|
|
116
|
+
SHAPES.set(schema, (shapes = shapesOfSchema(schema)));
|
|
117
|
+
return shapes;
|
|
118
|
+
};
|
|
119
|
+
const PARSED = new Map();
|
|
120
|
+
/** A condition parsed once; null when it does not read. */
|
|
121
|
+
function parsed(condition) {
|
|
122
|
+
let held = PARSED.get(condition);
|
|
123
|
+
if (held === undefined) {
|
|
124
|
+
try {
|
|
125
|
+
held = parseExpr(condition);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// A condition that does not read can never be reached: `subscriptionProblem` says so when it is made.
|
|
129
|
+
held = null;
|
|
130
|
+
}
|
|
131
|
+
if (PARSED.size > 500)
|
|
132
|
+
PARSED.clear();
|
|
133
|
+
PARSED.set(condition, held);
|
|
134
|
+
}
|
|
135
|
+
return held;
|
|
136
|
+
}
|
|
137
|
+
/** The ids a primitive is about. */
|
|
138
|
+
function aboutOf(primitive) {
|
|
139
|
+
switch (primitive.op) {
|
|
140
|
+
case "add-node":
|
|
141
|
+
case "remove-node":
|
|
142
|
+
return [primitive.node.id];
|
|
143
|
+
case "patch-node":
|
|
144
|
+
return [primitive.id];
|
|
145
|
+
case "add-edge":
|
|
146
|
+
case "remove-edge":
|
|
147
|
+
return [primitive.edge.from, primitive.edge.to];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/** Whether a value names an id anywhere in it. */
|
|
151
|
+
function names(value, id) {
|
|
152
|
+
if (value === id)
|
|
153
|
+
return true;
|
|
154
|
+
if (Array.isArray(value))
|
|
155
|
+
return value.some((one) => names(one, id));
|
|
156
|
+
if (value !== null && typeof value === "object")
|
|
157
|
+
return Object.values(value).some((one) => names(one, id));
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* ONE RECORD AS IT STOOD JUST AFTER `seq`: the graph's record now, with what
|
|
162
|
+
* the log did to it after `seq` taken back — so a batch judged a moment
|
|
163
|
+
* later (a host whose subscriptions answer a promise) is judged as it was.
|
|
164
|
+
*/
|
|
165
|
+
function nodeAfter(store, id, seq) {
|
|
166
|
+
let node = store.graph.getNode(id);
|
|
167
|
+
const ops = store.log.all();
|
|
168
|
+
for (let at = ops.length - 1; at >= 0 && ops[at].seq > seq; at--) {
|
|
169
|
+
const primitives = ops[at].primitives;
|
|
170
|
+
for (let one = primitives.length - 1; one >= 0; one--) {
|
|
171
|
+
const primitive = primitives[one];
|
|
172
|
+
if (primitive.op === "add-node" && primitive.node.id === id)
|
|
173
|
+
node = undefined;
|
|
174
|
+
else if (primitive.op === "remove-node" && primitive.node.id === id)
|
|
175
|
+
node = primitive.node;
|
|
176
|
+
else if (primitive.op === "patch-node" && primitive.id === id && node)
|
|
177
|
+
node = patched(node, primitive.before);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return node;
|
|
181
|
+
}
|
|
182
|
+
/** A record with these values written over it; a value that says "unset" takes the field off. */
|
|
183
|
+
function patched(node, values) {
|
|
184
|
+
const next = { ...node };
|
|
185
|
+
for (const [field, value] of Object.entries(values)) {
|
|
186
|
+
if (isUnset(value))
|
|
187
|
+
delete next[field];
|
|
188
|
+
else
|
|
189
|
+
next[field] = value;
|
|
190
|
+
}
|
|
191
|
+
return next;
|
|
192
|
+
}
|
|
193
|
+
/** A record as it stood before a batch, from how it stood after and the batch's primitives on it; undefined when the batch made it. */
|
|
194
|
+
function nodeBefore(after, id, primitives) {
|
|
195
|
+
let node = after;
|
|
196
|
+
for (let one = primitives.length - 1; one >= 0; one--) {
|
|
197
|
+
const primitive = primitives[one];
|
|
198
|
+
if (primitive.op === "add-node" && primitive.node.id === id)
|
|
199
|
+
node = undefined;
|
|
200
|
+
else if (primitive.op === "remove-node" && primitive.node.id === id)
|
|
201
|
+
node = primitive.node;
|
|
202
|
+
else if (primitive.op === "patch-node" && primitive.id === id && node)
|
|
203
|
+
node = patched(node, primitive.before);
|
|
204
|
+
}
|
|
205
|
+
return node;
|
|
206
|
+
}
|
|
207
|
+
/** Whether a condition holds of a record, read as the subscriber sees the app; a mistake or a missing record is false. */
|
|
208
|
+
function holds(condition, node, graph, schema) {
|
|
209
|
+
if (!node)
|
|
210
|
+
return false;
|
|
211
|
+
try {
|
|
212
|
+
return evaluateExpr(condition, { graph, subject: node, kinds: shapesFor(schema) }) === true;
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
if (error instanceof ExprEvalError)
|
|
216
|
+
return false;
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/** A batch's ops, in the order they landed, grouped by batch id. */
|
|
221
|
+
function batchesIn(ops) {
|
|
222
|
+
const groups = new Map();
|
|
223
|
+
for (const op of ops) {
|
|
224
|
+
const group = groups.get(op.batch);
|
|
225
|
+
if (group)
|
|
226
|
+
group.push(op);
|
|
227
|
+
else
|
|
228
|
+
groups.set(op.batch, [op]);
|
|
229
|
+
}
|
|
230
|
+
return [...groups.values()];
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* WHICH SUBSCRIPTIONS A COMMIT MATCHES — pure, and judged as each
|
|
234
|
+
* subscriber may see. `ops` are the ops one commit landed (what a store's
|
|
235
|
+
* `subscribe` hands its listener); a commit of several batches is judged
|
|
236
|
+
* batch by batch. For each subscription, the batch is read through its
|
|
237
|
+
* subscriber's lens: an op that touched a record they cannot see is
|
|
238
|
+
* withheld from them and matches nothing, a record they cannot see is never
|
|
239
|
+
* in a match, and a field kept from them is neither said nor read by a
|
|
240
|
+
* condition. A batch the subscriber made is no match unless `alsoMine`.
|
|
241
|
+
* At most one match per batch per subscription.
|
|
242
|
+
*/
|
|
243
|
+
export function matchSubscriptions(store, ops, subscriptions, options = {}) {
|
|
244
|
+
const any = store;
|
|
245
|
+
const judged = subscriptions.filter((one) => options.app === undefined || one.app === options.app);
|
|
246
|
+
if (judged.length === 0 || ops.length === 0)
|
|
247
|
+
return [];
|
|
248
|
+
const matches = [];
|
|
249
|
+
for (const batch of batchesIn(ops)) {
|
|
250
|
+
const first = batch[0];
|
|
251
|
+
// A suggestion that waits changes nothing; a batch of no change is nobody's news.
|
|
252
|
+
if (batch.every((op) => op.primitives.length === 0))
|
|
253
|
+
continue;
|
|
254
|
+
const by = first.author;
|
|
255
|
+
const maker = actingAs(by).id;
|
|
256
|
+
for (const subscription of judged) {
|
|
257
|
+
const who = subscription.who;
|
|
258
|
+
if (!subscription.alsoMine && maker !== undefined && maker === who.id)
|
|
259
|
+
continue;
|
|
260
|
+
const lens = seatLens(any, who);
|
|
261
|
+
/*
|
|
262
|
+
* THE BATCH AS THE SUBSCRIBER IS SERVED IT. An op that touched what
|
|
263
|
+
* they may not see is withheld from them: it says nothing of who or
|
|
264
|
+
* why, and carries only the changes to records they may see (none, for
|
|
265
|
+
* a record they cannot see at all) — so it can match what changed, and
|
|
266
|
+
* never an act, and its maker is "Someone".
|
|
267
|
+
*/
|
|
268
|
+
const served = redact(batch, lens);
|
|
269
|
+
if (served.every((op) => op.primitives.length === 0))
|
|
270
|
+
continue;
|
|
271
|
+
const seen = seenBy(any, who);
|
|
272
|
+
const records = matchOne(any, seen, subscription, served);
|
|
273
|
+
if (!records)
|
|
274
|
+
continue;
|
|
275
|
+
const last = batch.at(-1);
|
|
276
|
+
const open = served.filter((op) => !isWithheld(op));
|
|
277
|
+
const whole = open.length === served.length;
|
|
278
|
+
const shownBy = whole ? by : WITHHELD_AUTHOR;
|
|
279
|
+
const byName = whole ? nameOfAuthor(by, { graph: seen.graph, schema: any.schema, ...(options.seats ? { seats: options.seats } : {}) }) : (WITHHELD_AUTHOR.name ?? "Someone");
|
|
280
|
+
const intent = (whole ? first.batchIntent : undefined) ?? (open.length > 0 ? open.map((op) => op.intent).join("; ") : recordsSaid(records));
|
|
281
|
+
matches.push({
|
|
282
|
+
subscription,
|
|
283
|
+
app: subscription.app,
|
|
284
|
+
batch: first.batch,
|
|
285
|
+
ops: served.map((op) => op.id),
|
|
286
|
+
seq: last.seq,
|
|
287
|
+
by: shownBy,
|
|
288
|
+
byName,
|
|
289
|
+
intent,
|
|
290
|
+
acts: [...new Set(open.flatMap((op) => (op.mutation ? [op.mutation.name] : [])))],
|
|
291
|
+
records,
|
|
292
|
+
said: `${byName}: ${intent}`,
|
|
293
|
+
at: last.at,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return matches;
|
|
298
|
+
}
|
|
299
|
+
/** What happened to the records, said without who or why: "Added “Call the plumber”". */
|
|
300
|
+
function recordsSaid(records) {
|
|
301
|
+
const verb = { created: "Added", changed: "Changed", removed: "Removed" };
|
|
302
|
+
return records.map((record) => `${verb[record.change]} “${record.label}”`).join("; ") || "A change";
|
|
303
|
+
}
|
|
304
|
+
/** The records a batch, as the subscriber is served it, touched that the subscription is about — or undefined when it is no match. */
|
|
305
|
+
function matchOne(store, seen, subscription, ops) {
|
|
306
|
+
const { when } = subscription;
|
|
307
|
+
const primitives = ops.flatMap((op) => op.primitives);
|
|
308
|
+
const last = ops.at(-1).seq;
|
|
309
|
+
const kindOf = (id) => {
|
|
310
|
+
for (const primitive of primitives)
|
|
311
|
+
if ((primitive.op === "add-node" || primitive.op === "remove-node") && primitive.node.id === id)
|
|
312
|
+
return primitive.node.kind;
|
|
313
|
+
return seen.graph.getNode(id)?.kind;
|
|
314
|
+
};
|
|
315
|
+
/** A record the batch touched, as the subscriber is served it now — or as it was removed. */
|
|
316
|
+
const record = (id) => {
|
|
317
|
+
const kind = kindOf(id);
|
|
318
|
+
if (kind === undefined)
|
|
319
|
+
return undefined;
|
|
320
|
+
const added = primitives.some((p) => p.op === "add-node" && p.node.id === id);
|
|
321
|
+
const removed = primitives.some((p) => p.op === "remove-node" && p.node.id === id);
|
|
322
|
+
const now = seen.graph.getNode(id);
|
|
323
|
+
const gone = primitives.find((p) => p.op === "remove-node" && p.node.id === id)?.node;
|
|
324
|
+
const node = now ?? gone;
|
|
325
|
+
const definition = store.schema.tryDefinition(kind);
|
|
326
|
+
const label = node ? labelOf(definition, node) : id;
|
|
327
|
+
const change = added && !removed ? "created" : removed && !now ? "removed" : "changed";
|
|
328
|
+
const fields = new Map();
|
|
329
|
+
for (const primitive of primitives) {
|
|
330
|
+
if (primitive.op !== "patch-node" || primitive.id !== id)
|
|
331
|
+
continue;
|
|
332
|
+
for (const [field, after] of Object.entries(primitive.after)) {
|
|
333
|
+
const held = fields.get(field);
|
|
334
|
+
const before = held ? held.before : primitive.before[field];
|
|
335
|
+
fields.set(field, { ...(isUnset(before) ? {} : { before }), ...(isUnset(after) ? {} : { after }) });
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
id,
|
|
340
|
+
kind,
|
|
341
|
+
label,
|
|
342
|
+
change,
|
|
343
|
+
...(fields.size > 0 ? { fields: [...fields].map(([field, values]) => ({ field, words: fieldWords(definition, field), ...values })) } : {}),
|
|
344
|
+
};
|
|
345
|
+
};
|
|
346
|
+
const touched = [...new Set(primitives.flatMap(aboutOf))];
|
|
347
|
+
const records = (ids) => ids.flatMap((id) => record(id) ?? []);
|
|
348
|
+
switch (when.on) {
|
|
349
|
+
case "act": {
|
|
350
|
+
const ran = ops.filter((op) => !isWithheld(op) && op.mutation !== null && op.undoes === undefined && (when.act === undefined || op.mutation.name === when.act));
|
|
351
|
+
const on = when.record === undefined ? ran : ran.filter((op) => op.writes.includes(when.record) || names(op.mutation.args, when.record));
|
|
352
|
+
if (on.length === 0)
|
|
353
|
+
return undefined;
|
|
354
|
+
const ids = when.record !== undefined ? [when.record] : [...new Set(on.flatMap((op) => op.primitives.flatMap(aboutOf)))];
|
|
355
|
+
return records(ids.filter((id) => kindOf(id) !== undefined));
|
|
356
|
+
}
|
|
357
|
+
case "created": {
|
|
358
|
+
const made = ops.filter((op) => op.undoes === undefined).flatMap((op) => op.primitives.flatMap((p) => (p.op === "add-node" && p.node.kind === when.kind ? [p.node.id] : [])));
|
|
359
|
+
return made.length > 0 ? records([...new Set(made)]) : undefined;
|
|
360
|
+
}
|
|
361
|
+
case "changed": {
|
|
362
|
+
const ids = touched.filter((id) => (when.record !== undefined ? id === when.record : kindOf(id) === when.kind));
|
|
363
|
+
return ids.length > 0 ? records(ids) : undefined;
|
|
364
|
+
}
|
|
365
|
+
case "reaches": {
|
|
366
|
+
const condition = parsed(when.condition);
|
|
367
|
+
if (!condition)
|
|
368
|
+
return undefined;
|
|
369
|
+
const candidates = touched.filter((id) => (when.record !== undefined ? id === when.record : true) && kindOf(id) === when.kind);
|
|
370
|
+
const reached = candidates.filter((id) => {
|
|
371
|
+
// As the subscriber is served it: a field kept from them is not there to be read.
|
|
372
|
+
const after = nodeAfter(store, id, last);
|
|
373
|
+
const servedAfter = after ? (seen.graph.getNode(id) === undefined ? undefined : servedAs(seen, after)) : undefined;
|
|
374
|
+
const before = nodeBefore(after, id, primitives);
|
|
375
|
+
const servedBefore = before ? servedAs(seen, before) : undefined;
|
|
376
|
+
return holds(condition, servedAfter, seen.graph, store.schema) && !holds(condition, servedBefore, seen.graph, store.schema);
|
|
377
|
+
});
|
|
378
|
+
return reached.length > 0 ? records(reached) : undefined;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/** A record as the subscriber is served it: only the fields their view of it carries. */
|
|
383
|
+
function servedAs(seen, node) {
|
|
384
|
+
const shown = seen.graph.getNode(node.id);
|
|
385
|
+
if (!shown)
|
|
386
|
+
return undefined;
|
|
387
|
+
return Object.fromEntries(Object.entries(node).filter(([field]) => field === "id" || field === "kind" || field in shown));
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* EVERY COMMIT OF A STORE, MATCHED: subscribes to the store, lists the
|
|
391
|
+
* subscriptions on each commit, and hands each match to the hook. A store
|
|
392
|
+
* that lists at once is matched at once; one that answers a promise is
|
|
393
|
+
* matched when it answers, against each record as it stood just after the
|
|
394
|
+
* batch. Answers the way to stop.
|
|
395
|
+
*/
|
|
396
|
+
export function watchSubscriptions(store, options) {
|
|
397
|
+
const report = options.onError ?? ((error) => console.error("A subscription could not be judged:", error));
|
|
398
|
+
const tell = (matches) => {
|
|
399
|
+
for (const match of matches) {
|
|
400
|
+
try {
|
|
401
|
+
const told = options.onSubscriptionMatch(match);
|
|
402
|
+
if (told && typeof told.then === "function")
|
|
403
|
+
told.catch(report);
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
report(error);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
return store.subscribe((_diff, ops) => {
|
|
411
|
+
if (ops.length === 0)
|
|
412
|
+
return;
|
|
413
|
+
try {
|
|
414
|
+
const listed = options.subscriptions.list();
|
|
415
|
+
if (Array.isArray(listed))
|
|
416
|
+
tell(matchSubscriptions(store, ops, listed, options));
|
|
417
|
+
else
|
|
418
|
+
void listed.then((all) => tell(matchSubscriptions(store, ops, all, options)), report);
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
report(error);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
//# sourceMappingURL=subscriptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptions.js","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ConnectionSpec } from "../document/connection-spec.js";
|
|
2
|
+
/** Google's event colors by the names its calendar shows, and the `colorId` each one is. */
|
|
3
|
+
export declare const GOOGLE_COLORS: Readonly<Record<string, string>>;
|
|
4
|
+
/** A tag is one word, `#` and letters, digits or hyphens: `#graview`, `#team-sync`. */
|
|
5
|
+
export declare const CONNECTION_TAG: RegExp;
|
|
6
|
+
/** The private extended property every event made here carries, naming the app. */
|
|
7
|
+
export declare const MADE_BY_GRAVIEW = "graview";
|
|
8
|
+
/** A title tag, matched as a whole word anywhere in a title, in any case. */
|
|
9
|
+
export declare const tagPattern: (tag: string) => RegExp;
|
|
10
|
+
/** Whether a Google event is one this connection keeps: its color, or its title's tag. */
|
|
11
|
+
export declare function inConnectionFilter(declaration: ConnectionSpec, item: Readonly<Record<string, unknown>>): boolean;
|
|
12
|
+
//# sourceMappingURL=connection-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-filter.d.ts","sourceRoot":"","sources":["../../src/sync/connection-filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAOrE,4FAA4F;AAC5F,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAY1D,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,cAAc,QAAiC,CAAC;AAE7D,mFAAmF;AACnF,eAAO,MAAM,eAAe,YAAY,CAAC;AAEzC,6EAA6E;AAC7E,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,WAAsF,CAAC;AAE7H,0FAA0F;AAC1F,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAKhH"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* What a declared connection's filter means, apart from the engine — so the
|
|
3
|
+
* checker (`graview check`) can judge a color or a tag without reaching it.
|
|
4
|
+
*/
|
|
5
|
+
/** Google's event colors by the names its calendar shows, and the `colorId` each one is. */
|
|
6
|
+
export const GOOGLE_COLORS = {
|
|
7
|
+
Lavender: "1",
|
|
8
|
+
Sage: "2",
|
|
9
|
+
Grape: "3",
|
|
10
|
+
Flamingo: "4",
|
|
11
|
+
Banana: "5",
|
|
12
|
+
Tangerine: "6",
|
|
13
|
+
Peacock: "7",
|
|
14
|
+
Graphite: "8",
|
|
15
|
+
Blueberry: "9",
|
|
16
|
+
Basil: "10",
|
|
17
|
+
Tomato: "11",
|
|
18
|
+
};
|
|
19
|
+
/** A tag is one word, `#` and letters, digits or hyphens: `#graview`, `#team-sync`. */
|
|
20
|
+
export const CONNECTION_TAG = /^#[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
21
|
+
/** The private extended property every event made here carries, naming the app. */
|
|
22
|
+
export const MADE_BY_GRAVIEW = "graview";
|
|
23
|
+
/** A title tag, matched as a whole word anywhere in a title, in any case. */
|
|
24
|
+
export const tagPattern = (tag) => new RegExp(`(^|\\s)${tag.replace(/[.*+?^${}()|[\]\\-]/g, "\\$&")}(?=\\s|$)`, "i");
|
|
25
|
+
/** Whether a Google event is one this connection keeps: its color, or its title's tag. */
|
|
26
|
+
export function inConnectionFilter(declaration, item) {
|
|
27
|
+
const filter = declaration.filter;
|
|
28
|
+
if (filter?.color)
|
|
29
|
+
return String(item["colorId"] ?? "") === GOOGLE_COLORS[filter.color];
|
|
30
|
+
if (filter?.tag)
|
|
31
|
+
return tagPattern(filter.tag).test(String(item["summary"] ?? ""));
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=connection-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-filter.js","sourceRoot":"","sources":["../../src/sync/connection-filter.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,4FAA4F;AAC5F,MAAM,CAAC,MAAM,aAAa,GAAqC;IAC7D,QAAQ,EAAE,GAAG;IACb,IAAI,EAAE,GAAG;IACT,KAAK,EAAE,GAAG;IACV,QAAQ,EAAE,GAAG;IACb,MAAM,EAAE,GAAG;IACX,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE,GAAG;IACb,SAAS,EAAE,GAAG;IACd,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;CACb,CAAC;AAEF,uFAAuF;AACvF,MAAM,CAAC,MAAM,cAAc,GAAG,8BAA8B,CAAC;AAE7D,mFAAmF;AACnF,MAAM,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC;AAEzC,6EAA6E;AAC7E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AAE7H,0FAA0F;AAC1F,MAAM,UAAU,kBAAkB,CAAC,WAA2B,EAAE,IAAuC;IACrG,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;IAClC,IAAI,MAAM,EAAE,KAAK;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,KAAK,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACxF,IAAI,MAAM,EAAE,GAAG;QAAE,OAAO,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACnF,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { GraviewApp } from "../app.js";
|
|
2
|
+
import type { AnySchema } from "../schema/schema.js";
|
|
3
|
+
import type { Store } from "../store.js";
|
|
4
|
+
import type { ConnectionSpec } from "../document/connection-spec.js";
|
|
5
|
+
import { SyncEngine } from "./engine.js";
|
|
6
|
+
import { type Fetcher, type GoogleTokenRequest } from "./google-calendar.js";
|
|
7
|
+
import type { RemoteSystem, SyncMapping, SyncState } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* A DECLARED CONNECTION, RUN.
|
|
10
|
+
*
|
|
11
|
+
* `connections.<name>` in a declaration says which calendar, which kind,
|
|
12
|
+
* which fields, which of its events and which way; this turns that into the
|
|
13
|
+
* engine, the mapping and the transport, so a host (`graview serve`, the
|
|
14
|
+
* preview, Graview Cloud) supplies only a token and a place to keep the
|
|
15
|
+
* engine's state. Everything it decides is said here once:
|
|
16
|
+
*
|
|
17
|
+
* - A field's TYPE says what kind of event it is: a `date` field is an
|
|
18
|
+
* all-day event's day (`start.date`; the end day is inclusive here and
|
|
19
|
+
* exclusive at Google, so it is moved by one each way), a `datetime`
|
|
20
|
+
* field a timed event's instant (`start.dateTime`, read back as one UTC
|
|
21
|
+
* instant however Google says it).
|
|
22
|
+
* - A FILTER is applied as events arrive, because Google refuses a sync
|
|
23
|
+
* token beside a search: an event outside it is not news, and one that
|
|
24
|
+
* leaves it is gone here. An event made here is given what the filter
|
|
25
|
+
* needs (the color; the tag in its title) so it stays in it, and a
|
|
26
|
+
* private extended property naming the app.
|
|
27
|
+
* - READ means the calendar owns the kind: an act here that would change a
|
|
28
|
+
* record of it is refused with a sentence saying so (`SyncEngine.guard`),
|
|
29
|
+
* rather than accepted and never sent.
|
|
30
|
+
* - Inbound changes land through the app's own acts — the one that creates
|
|
31
|
+
* the kind, `edit-<kind>` and `remove-<kind>` — authored by the system
|
|
32
|
+
* `google-calendar`, so Activity credits the calendar and undo works.
|
|
33
|
+
*/
|
|
34
|
+
export { CONNECTION_TAG, GOOGLE_COLORS, MADE_BY_GRAVIEW, inConnectionFilter } from "./connection-filter.js";
|
|
35
|
+
export type ConnectionDeclaration = ConnectionSpec;
|
|
36
|
+
export interface ConnectionRun<S extends AnySchema> {
|
|
37
|
+
/** The connection's name in the declaration (`connections.<name>`). */
|
|
38
|
+
readonly name: string;
|
|
39
|
+
readonly declaration: ConnectionDeclaration;
|
|
40
|
+
readonly app: GraviewApp<S>;
|
|
41
|
+
readonly store: Store<S>;
|
|
42
|
+
/** The calendar's id, resolved from the declaration (its `env`, when it names one). */
|
|
43
|
+
readonly calendarId: string;
|
|
44
|
+
/** An access token; asked again with `{ refresh: true }` when Google refuses the last one. */
|
|
45
|
+
token(request?: GoogleTokenRequest): Promise<string> | string;
|
|
46
|
+
readonly fetch?: Fetcher;
|
|
47
|
+
/** What the engine kept from the last run: its cursor, its links. */
|
|
48
|
+
readonly state?: SyncState;
|
|
49
|
+
}
|
|
50
|
+
export interface Connection<S extends AnySchema> {
|
|
51
|
+
readonly engine: SyncEngine<S>;
|
|
52
|
+
readonly mapping: SyncMapping;
|
|
53
|
+
readonly remote: RemoteSystem;
|
|
54
|
+
/** For a read connection, the guard that refuses acts on the kind here; call it to lift. Absent for "both". */
|
|
55
|
+
readonly unguard?: () => void;
|
|
56
|
+
}
|
|
57
|
+
/** Whether a field of the kind is a `date` (an all-day event's day) rather than a `datetime`. */
|
|
58
|
+
export declare function isDayField(app: GraviewApp, kind: string, field: string): boolean;
|
|
59
|
+
/** The mapping a declaration says: field types decide the paths, the filter's tag is kept or stripped. */
|
|
60
|
+
export declare function connectionMapping(app: GraviewApp, declaration: ConnectionDeclaration): SyncMapping;
|
|
61
|
+
/** The act that makes a record of the kind: `add-<kind>` when there is one, else the first that creates it. */
|
|
62
|
+
export declare function creatingAct(app: GraviewApp, kind: string): string | undefined;
|
|
63
|
+
/** The engine, the mapping and the transport for one declared connection. */
|
|
64
|
+
export declare function connection<S extends AnySchema>(run: ConnectionRun<S>): Connection<S>;
|
|
65
|
+
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/sync/connection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAkB,KAAK,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,KAAK,EAAE,YAAY,EAAmB,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5G,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC;AAEnD,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,SAAS;IAChD,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAC;IAC5C,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,uFAAuF;IACvF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,8FAA8F;IAC9F,KAAK,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,SAAS;IAC7C,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,+GAA+G;IAC/G,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAaD,iGAAiG;AACjG,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAIhF;AAED,0GAA0G;AAC1G,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,qBAAqB,GAAG,WAAW,CA0ClG;AAED,+GAA+G;AAC/G,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG7E;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CA8CpF"}
|