@owlmeans/client-planning 0.1.18-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/agent-meta/manifest.json +16 -0
- package/agent-meta/skills/client-planning/SKILL.md +212 -0
- package/build/client.d.ts +26 -0
- package/build/client.d.ts.map +1 -0
- package/build/client.js +120 -0
- package/build/client.js.map +1 -0
- package/build/commits.d.ts +17 -0
- package/build/commits.d.ts.map +1 -0
- package/build/commits.js +205 -0
- package/build/commits.js.map +1 -0
- package/build/consts.d.ts +27 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +29 -0
- package/build/consts.js.map +1 -0
- package/build/events.d.ts +27 -0
- package/build/events.d.ts.map +1 -0
- package/build/events.js +109 -0
- package/build/events.js.map +1 -0
- package/build/facade.d.ts +19 -0
- package/build/facade.d.ts.map +1 -0
- package/build/facade.js +130 -0
- package/build/facade.js.map +1 -0
- package/build/feed.d.ts +18 -0
- package/build/feed.d.ts.map +1 -0
- package/build/feed.js +123 -0
- package/build/feed.js.map +1 -0
- package/build/helper.d.ts +11 -0
- package/build/helper.d.ts.map +1 -0
- package/build/helper.js +10 -0
- package/build/helper.js.map +1 -0
- package/build/index.d.ts +10 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +9 -0
- package/build/index.js.map +1 -0
- package/build/stores.d.ts +28 -0
- package/build/stores.d.ts.map +1 -0
- package/build/stores.js +61 -0
- package/build/stores.js.map +1 -0
- package/build/types.d.ts +147 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/build/utils/record.d.ts +25 -0
- package/build/utils/record.d.ts.map +1 -0
- package/build/utils/record.js +72 -0
- package/build/utils/record.js.map +1 -0
- package/package.json +55 -0
- package/src/client.ts +153 -0
- package/src/commits.ts +247 -0
- package/src/consts.ts +38 -0
- package/src/events.ts +121 -0
- package/src/facade.ts +169 -0
- package/src/feed.ts +131 -0
- package/src/helper.ts +18 -0
- package/src/index.ts +10 -0
- package/src/stores.ts +81 -0
- package/src/types.ts +163 -0
- package/src/utils/record.ts +91 -0
- package/tests/commits.spec.ts +67 -0
- package/tests/context.ts +301 -0
- package/tests/events.spec.ts +95 -0
- package/tests/facade.spec.ts +83 -0
- package/tests/feed.spec.ts +39 -0
- package/tests/stores.spec.ts +67 -0
- package/tests/tsconfig.json +17 -0
- package/tsconfig.json +15 -0
package/build/commits.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { CommitFailed, CommitState, CommitTimeout, DEFAULT_COMMIT_POLL, DEFAULT_COMMIT_TIMEOUT, MAX_COMMIT_POLL, PLANNING_COMMIT_EVENT, PlanningError, WorkcardKind, } from '@owlmeans/planning';
|
|
2
|
+
import { EARLY_POLL_LADDER, EARLY_POLL_MS, LONG_POLL_GRACE } from './consts.js';
|
|
3
|
+
import { dropCard, putCard, putCommit } from './utils/record.js';
|
|
4
|
+
const matches = (filter, event) => filter == null || ((filter.entityId == null || filter.entityId === event.entityId)
|
|
5
|
+
&& (filter.project == null || filter.project === event.project)
|
|
6
|
+
&& (filter.card == null || filter.card === event.card)
|
|
7
|
+
&& (filter.kind == null || filter.kind === event.kind));
|
|
8
|
+
const delay = (ms) => {
|
|
9
|
+
let handle;
|
|
10
|
+
const promise = new Promise(resolve => { handle = setTimeout(resolve, Math.max(0, ms)); });
|
|
11
|
+
return { promise, cancel: () => clearTimeout(handle) };
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The commit source of a remote facade: the `commit.get` long poll and, when the host injects a
|
|
15
|
+
* socket opener, the `commit.events` feed.
|
|
16
|
+
*
|
|
17
|
+
* `wait` SUBSCRIBES FIRST and only then reads the status — a commit landing between a read and a
|
|
18
|
+
* subscription would otherwise be missed until the deadline. It then long-polls in holds of
|
|
19
|
+
* `min(poll, remaining)` seconds, so a client with no socket (a Node connector) still learns of a
|
|
20
|
+
* commit within one round trip of it landing, and a client with one learns from whichever arrives
|
|
21
|
+
* first. The deadline is a {@link CommitTimeout}; the transition stays pending — nothing is undone.
|
|
22
|
+
*
|
|
23
|
+
* ONE socket serves every subscription of the source; releasing a subscription never closes it.
|
|
24
|
+
*/
|
|
25
|
+
export const makeRemoteCommitSource = (context, protocols, opts) => {
|
|
26
|
+
const poll = Math.max(0, Math.min(MAX_COMMIT_POLL, opts?.poll ?? DEFAULT_COMMIT_POLL));
|
|
27
|
+
const subscriptions = new Set();
|
|
28
|
+
let opening = null;
|
|
29
|
+
let open = null;
|
|
30
|
+
let detach = null;
|
|
31
|
+
const dispatch = async (event) => {
|
|
32
|
+
for (const subscription of [...subscriptions]) {
|
|
33
|
+
if (!matches(subscription.filter, event)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
await subscription.listener(event);
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
console.error('Planning commit listener error:', e);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const socket = async () => {
|
|
45
|
+
const opener = opts?.socket;
|
|
46
|
+
if (opener == null) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
opening ??= (async () => {
|
|
50
|
+
try {
|
|
51
|
+
const connection = await opener(protocols.commit.events, { query: {} });
|
|
52
|
+
if (connection == null) {
|
|
53
|
+
// No socket right now (not signed in yet, say) — the next subscription asks again.
|
|
54
|
+
opening = null;
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
open = connection;
|
|
58
|
+
detach = connection.observe(PLANNING_COMMIT_EVENT, async (message) => {
|
|
59
|
+
await dispatch(message.payload);
|
|
60
|
+
});
|
|
61
|
+
return connection;
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
opening = null;
|
|
65
|
+
console.error('Planning commit socket error:', e);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
})();
|
|
69
|
+
return await opening;
|
|
70
|
+
};
|
|
71
|
+
const endpoint = () => context.entrypoint(protocols.commit.get);
|
|
72
|
+
const status = async (transition) => await endpoint().call({
|
|
73
|
+
params: { transition }, query: { wait: 0 }, timeout: opts?.timeout,
|
|
74
|
+
});
|
|
75
|
+
const hold = async (transition, wait, signal) => {
|
|
76
|
+
try {
|
|
77
|
+
return await endpoint().call({
|
|
78
|
+
params: { transition }, query: { wait }, timeout: wait * 1000 + LONG_POLL_GRACE, signal,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
if (signal.aborted || e instanceof PlanningError) {
|
|
83
|
+
throw e;
|
|
84
|
+
}
|
|
85
|
+
// A dropped hold (a proxy closing an idle response) is not an answer about the commit: one
|
|
86
|
+
// non-holding read replaces it, and a failure of THAT is reported.
|
|
87
|
+
return await status(transition);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
/** Fold a settled status into the mirror, when the host registered one. */
|
|
91
|
+
const fold = async (transition, settled) => {
|
|
92
|
+
const stores = opts?.stores?.();
|
|
93
|
+
if (stores == null) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const known = await stores.commits.load(transition);
|
|
97
|
+
await putCommit(stores.commits, {
|
|
98
|
+
id: transition, state: settled.state, at: settled.at, error: settled.error,
|
|
99
|
+
});
|
|
100
|
+
if (settled.state !== CommitState.Committed) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (settled.card != null) {
|
|
104
|
+
await putCard(stores.cards, settled.card);
|
|
105
|
+
}
|
|
106
|
+
else if (settled.card === null && known?.card != null) {
|
|
107
|
+
await dropCard(stores, known.card, known.kind === WorkcardKind.Project);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const answer = async (transition, settled) => {
|
|
111
|
+
await fold(transition, settled);
|
|
112
|
+
if (settled.state === CommitState.Failed) {
|
|
113
|
+
throw new CommitFailed(settled.error ?? transition);
|
|
114
|
+
}
|
|
115
|
+
return settled.card ?? null;
|
|
116
|
+
};
|
|
117
|
+
const subscribe = async (listener, filter) => {
|
|
118
|
+
const subscription = { listener, filter };
|
|
119
|
+
subscriptions.add(subscription);
|
|
120
|
+
await socket();
|
|
121
|
+
return () => { subscriptions.delete(subscription); };
|
|
122
|
+
};
|
|
123
|
+
const source = {
|
|
124
|
+
status,
|
|
125
|
+
subscribe,
|
|
126
|
+
wait: async (transition, waitOpts) => {
|
|
127
|
+
const deadline = Date.now() + (waitOpts?.timeout ?? DEFAULT_COMMIT_TIMEOUT);
|
|
128
|
+
// Held in an object: a frame writes it from a callback, which flow analysis cannot see.
|
|
129
|
+
const frame = { landed: null };
|
|
130
|
+
let wake = () => { };
|
|
131
|
+
const unsubscribe = await subscribe(event => {
|
|
132
|
+
if (event.transition === transition && event.state !== CommitState.Pending) {
|
|
133
|
+
frame.landed = event;
|
|
134
|
+
wake();
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
/** A frame says it settled; the status read carries the card when the frame does not. */
|
|
138
|
+
const fromFrame = async (event) => event.record !== undefined
|
|
139
|
+
? await answer(transition, {
|
|
140
|
+
transition, state: event.state, at: event.at, error: event.error, card: event.record,
|
|
141
|
+
})
|
|
142
|
+
: await answer(transition, await status(transition));
|
|
143
|
+
try {
|
|
144
|
+
let current = await status(transition);
|
|
145
|
+
let early = 0;
|
|
146
|
+
while (current.state === CommitState.Pending) {
|
|
147
|
+
if (frame.landed != null) {
|
|
148
|
+
return await fromFrame(frame.landed);
|
|
149
|
+
}
|
|
150
|
+
const remaining = deadline - Date.now();
|
|
151
|
+
if (remaining <= 0) {
|
|
152
|
+
throw new CommitTimeout(transition);
|
|
153
|
+
}
|
|
154
|
+
const wait = Math.min(poll, Math.ceil(remaining / 1000));
|
|
155
|
+
const abort = new AbortController();
|
|
156
|
+
const timer = delay(remaining);
|
|
157
|
+
const framed = new Promise(resolve => { wake = () => resolve('frame'); });
|
|
158
|
+
const started = Date.now();
|
|
159
|
+
try {
|
|
160
|
+
const outcome = await Promise.race([
|
|
161
|
+
hold(transition, wait, abort.signal),
|
|
162
|
+
framed,
|
|
163
|
+
timer.promise.then(() => 'deadline'),
|
|
164
|
+
]);
|
|
165
|
+
if (outcome === 'frame' || outcome === 'deadline') {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
current = outcome;
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
abort.abort();
|
|
172
|
+
timer.cancel();
|
|
173
|
+
wake = () => { };
|
|
174
|
+
}
|
|
175
|
+
if (current.state === CommitState.Pending && Date.now() - started < EARLY_POLL_MS) {
|
|
176
|
+
// The server did not hold — pause on a ladder rather than spin until the deadline.
|
|
177
|
+
const pause = delay(Math.min(EARLY_POLL_LADDER[Math.min(early, EARLY_POLL_LADDER.length - 1)], deadline - Date.now()));
|
|
178
|
+
early += 1;
|
|
179
|
+
await Promise.race([pause.promise, new Promise(resolve => { wake = resolve; })]);
|
|
180
|
+
pause.cancel();
|
|
181
|
+
wake = () => { };
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
early = 0;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return await answer(transition, current);
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
unsubscribe();
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
connected: () => open != null,
|
|
194
|
+
close: async () => {
|
|
195
|
+
detach?.();
|
|
196
|
+
detach = null;
|
|
197
|
+
const connection = open;
|
|
198
|
+
open = null;
|
|
199
|
+
opening = null;
|
|
200
|
+
await connection?.close();
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
return source;
|
|
204
|
+
};
|
|
205
|
+
//# sourceMappingURL=commits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commits.js","sourceRoot":"","sources":["../src/commits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Relationship, Workcard } from '@owlmeans/planning';
|
|
2
|
+
import type { StateAlias } from '@owlmeans/state';
|
|
3
|
+
import type { PlanningCommitRecord, PlanningStoreAliases } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* The ONE card store. Projects, cards and specifications share an id space on the server, so they
|
|
6
|
+
* share it here too — a store per kind would let a list reload of one kind drop another's rows.
|
|
7
|
+
*/
|
|
8
|
+
export declare const CARDS: StateAlias<Workcard>;
|
|
9
|
+
export declare const LINKS: StateAlias<Relationship>;
|
|
10
|
+
/** What the client has learned about each transition it wrote or saw, keyed by transition id. */
|
|
11
|
+
export declare const COMMITS: StateAlias<PlanningCommitRecord>;
|
|
12
|
+
export declare const DEFAULT_STORE_ALIASES: Readonly<PlanningStoreAliases>;
|
|
13
|
+
/**
|
|
14
|
+
* How much longer than its own `wait` a long poll's HTTP deadline is, in milliseconds — a held
|
|
15
|
+
* response must outlast the hold, or every quiet poll reads as a broken connection.
|
|
16
|
+
*/
|
|
17
|
+
export declare const LONG_POLL_GRACE = 10000;
|
|
18
|
+
/**
|
|
19
|
+
* The pause ladder between polls that came back pending without holding, in milliseconds.
|
|
20
|
+
*
|
|
21
|
+
* A server that does not hold (an old deployment, a proxy that answers early) would otherwise be
|
|
22
|
+
* polled in a tight loop until the deadline.
|
|
23
|
+
*/
|
|
24
|
+
export declare const EARLY_POLL_LADDER: readonly number[];
|
|
25
|
+
/** A poll that answered faster than this did not hold. */
|
|
26
|
+
export declare const EARLY_POLL_MS = 250;
|
|
27
|
+
//# sourceMappingURL=consts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAE5E;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,UAAU,CAAC,QAAQ,CAA+C,CAAA;AAEtF,eAAO,MAAM,KAAK,EAAE,UAAU,CAAC,YAAY,CAAmD,CAAA;AAE9F,iGAAiG;AACjG,eAAO,MAAM,OAAO,EAAE,UAAU,CAAC,oBAAoB,CAA6D,CAAA;AAElH,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,oBAAoB,CAI/D,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAS,CAAA;AAErC;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAAuC,CAAA;AAEtF,0DAA0D;AAC1D,eAAO,MAAM,aAAa,MAAM,CAAA"}
|
package/build/consts.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { stateAlias } from '@owlmeans/state';
|
|
2
|
+
/**
|
|
3
|
+
* The ONE card store. Projects, cards and specifications share an id space on the server, so they
|
|
4
|
+
* share it here too — a store per kind would let a list reload of one kind drop another's rows.
|
|
5
|
+
*/
|
|
6
|
+
export const CARDS = stateAlias('planning-card-state');
|
|
7
|
+
export const LINKS = stateAlias('planning-link-state');
|
|
8
|
+
/** What the client has learned about each transition it wrote or saw, keyed by transition id. */
|
|
9
|
+
export const COMMITS = stateAlias('planning-commit-state');
|
|
10
|
+
export const DEFAULT_STORE_ALIASES = Object.freeze({
|
|
11
|
+
cards: CARDS,
|
|
12
|
+
links: LINKS,
|
|
13
|
+
commits: COMMITS,
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* How much longer than its own `wait` a long poll's HTTP deadline is, in milliseconds — a held
|
|
17
|
+
* response must outlast the hold, or every quiet poll reads as a broken connection.
|
|
18
|
+
*/
|
|
19
|
+
export const LONG_POLL_GRACE = 10_000;
|
|
20
|
+
/**
|
|
21
|
+
* The pause ladder between polls that came back pending without holding, in milliseconds.
|
|
22
|
+
*
|
|
23
|
+
* A server that does not hold (an old deployment, a proxy that answers early) would otherwise be
|
|
24
|
+
* polled in a tight loop until the deadline.
|
|
25
|
+
*/
|
|
26
|
+
export const EARLY_POLL_LADDER = Object.freeze([250, 1_000, 2_000]);
|
|
27
|
+
/** A poll that answered faster than this did not hold. */
|
|
28
|
+
export const EARLY_POLL_MS = 250;
|
|
29
|
+
//# sourceMappingURL=consts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAI5C;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAyB,UAAU,CAAW,qBAAqB,CAAC,CAAA;AAEtF,MAAM,CAAC,MAAM,KAAK,GAA6B,UAAU,CAAe,qBAAqB,CAAC,CAAA;AAE9F,iGAAiG;AACjG,MAAM,CAAC,MAAM,OAAO,GAAqC,UAAU,CAAuB,uBAAuB,CAAC,CAAA;AAElH,MAAM,CAAC,MAAM,qBAAqB,GAAmC,MAAM,CAAC,MAAM,CAAC;IACjF,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,OAAO;CACjB,CAAC,CAAA;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAA;AAErC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAsB,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;AAEtF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CommitEvent, PlanningFacade, TransitionReceiptView, Workcard } from '@owlmeans/planning';
|
|
2
|
+
import type { PlanningStores } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Fold one commit frame into the mirror.
|
|
5
|
+
*
|
|
6
|
+
* - An OLDER `seq` never overwrites a newer record — frames and list answers race.
|
|
7
|
+
* - A committed `delete` REMOVES the row and every link touching it (and, for a project, the rows
|
|
8
|
+
* under it — the server purged them in the same fold).
|
|
9
|
+
* - A frame for an id the store never saw still writes a row: a card created in another tab
|
|
10
|
+
* appears here without waiting for the next list.
|
|
11
|
+
* - A `failed` commit leaves the card alone; the reason is recorded in the commit store.
|
|
12
|
+
*
|
|
13
|
+
* A frame from a cross-process bus carries ids only. When `record` is absent the card is re-read
|
|
14
|
+
* through `facade`; without one there is nothing to write but the commit itself.
|
|
15
|
+
*/
|
|
16
|
+
export declare const applyCommitEvent: (stores: PlanningStores, event: CommitEvent, facade?: PlanningFacade) => Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Mark a receipt in the mirror the moment the server answers it.
|
|
19
|
+
*
|
|
20
|
+
* A pending transition raises the card's `head` to its `seq`, so `head > seq` — the model's
|
|
21
|
+
* `pending()` — is true before any frame arrives. A receipt that already carries the committed
|
|
22
|
+
* card writes it; a committed delete drops the row.
|
|
23
|
+
*/
|
|
24
|
+
export declare const applyReceipt: (stores: PlanningStores, receipt: TransitionReceiptView) => Promise<void>;
|
|
25
|
+
/** Write cards the caller read on its own, under the same newer-fold-wins rule as a commit. */
|
|
26
|
+
export declare const applyCards: (stores: Pick<PlanningStores, 'cards'>, cards: Workcard[]) => Promise<void>;
|
|
27
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAEtG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAGhD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,WACnB,cAAc,SAAS,WAAW,WAAW,cAAc,KAClE,OAAO,CAAC,IAAI,CAkDd,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,WAAkB,cAAc,WAAW,qBAAqB,KAAG,OAAO,CAAC,IAAI,CAiCvG,CAAA;AAED,+FAA+F;AAC/F,eAAO,MAAM,UAAU,WAAkB,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,SAAS,QAAQ,EAAE,KAAG,OAAO,CAAC,IAAI,CAIvG,CAAA"}
|
package/build/events.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { CommitState, TransitionAction, WorkcardKind } from '@owlmeans/planning';
|
|
2
|
+
import { syncLinks } from './stores.js';
|
|
3
|
+
import { dropCard, putCard, putCommit } from './utils/record.js';
|
|
4
|
+
/**
|
|
5
|
+
* Fold one commit frame into the mirror.
|
|
6
|
+
*
|
|
7
|
+
* - An OLDER `seq` never overwrites a newer record — frames and list answers race.
|
|
8
|
+
* - A committed `delete` REMOVES the row and every link touching it (and, for a project, the rows
|
|
9
|
+
* under it — the server purged them in the same fold).
|
|
10
|
+
* - A frame for an id the store never saw still writes a row: a card created in another tab
|
|
11
|
+
* appears here without waiting for the next list.
|
|
12
|
+
* - A `failed` commit leaves the card alone; the reason is recorded in the commit store.
|
|
13
|
+
*
|
|
14
|
+
* A frame from a cross-process bus carries ids only. When `record` is absent the card is re-read
|
|
15
|
+
* through `facade`; without one there is nothing to write but the commit itself.
|
|
16
|
+
*/
|
|
17
|
+
export const applyCommitEvent = async (stores, event, facade) => {
|
|
18
|
+
const known = await stores.cards.load(event.card);
|
|
19
|
+
await putCommit(stores.commits, {
|
|
20
|
+
id: event.transition,
|
|
21
|
+
card: event.card,
|
|
22
|
+
entityId: event.entityId,
|
|
23
|
+
project: event.project,
|
|
24
|
+
kind: event.kind,
|
|
25
|
+
type: event.type,
|
|
26
|
+
seq: event.seq,
|
|
27
|
+
action: event.action,
|
|
28
|
+
state: event.state,
|
|
29
|
+
at: event.at,
|
|
30
|
+
error: event.error,
|
|
31
|
+
});
|
|
32
|
+
if (event.state === CommitState.Failed) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (event.state === CommitState.Pending) {
|
|
36
|
+
if (known != null && (known.head ?? known.seq) < event.seq) {
|
|
37
|
+
await stores.cards.save({ ...known, head: event.seq });
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (known != null && known.seq > event.seq) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (event.action === TransitionAction.Delete) {
|
|
45
|
+
await dropCard(stores, event.card, event.kind === WorkcardKind.Project);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const record = event.record !== undefined
|
|
49
|
+
? event.record
|
|
50
|
+
: facade != null ? await facade.cards.load(event.card) : undefined;
|
|
51
|
+
if (record === null) {
|
|
52
|
+
// Committed, and gone by the time it was read: a later delete won the race.
|
|
53
|
+
await dropCard(stores, event.card, event.kind === WorkcardKind.Project);
|
|
54
|
+
}
|
|
55
|
+
else if (record !== undefined) {
|
|
56
|
+
await putCard(stores.cards, record);
|
|
57
|
+
}
|
|
58
|
+
if (facade != null && (event.action === TransitionAction.Link || event.action === TransitionAction.Unlink)) {
|
|
59
|
+
const links = await facade.relationships.list({ from: event.card, size: 0 });
|
|
60
|
+
await syncLinks(stores.links, links.items, { from: event.card });
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Mark a receipt in the mirror the moment the server answers it.
|
|
65
|
+
*
|
|
66
|
+
* A pending transition raises the card's `head` to its `seq`, so `head > seq` — the model's
|
|
67
|
+
* `pending()` — is true before any frame arrives. A receipt that already carries the committed
|
|
68
|
+
* card writes it; a committed delete drops the row.
|
|
69
|
+
*/
|
|
70
|
+
export const applyReceipt = async (stores, receipt) => {
|
|
71
|
+
const { transition } = receipt;
|
|
72
|
+
if (transition.id != null) {
|
|
73
|
+
await putCommit(stores.commits, {
|
|
74
|
+
id: transition.id,
|
|
75
|
+
card: transition.card,
|
|
76
|
+
entityId: transition.entityId,
|
|
77
|
+
project: transition.project,
|
|
78
|
+
kind: transition.kind,
|
|
79
|
+
type: transition.type,
|
|
80
|
+
seq: transition.seq,
|
|
81
|
+
action: transition.action,
|
|
82
|
+
state: transition.commit.state,
|
|
83
|
+
at: transition.commit.at,
|
|
84
|
+
error: transition.commit.error,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (transition.commit.state === CommitState.Failed) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (transition.commit.state === CommitState.Committed && transition.action === TransitionAction.Delete) {
|
|
91
|
+
await dropCard(stores, transition.card, transition.kind === WorkcardKind.Project);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (receipt.card != null) {
|
|
95
|
+
await putCard(stores.cards, receipt.card);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const known = await stores.cards.load(transition.card);
|
|
99
|
+
if (known != null && (known.head ?? known.seq) < transition.seq) {
|
|
100
|
+
await stores.cards.save({ ...known, head: transition.seq });
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
/** Write cards the caller read on its own, under the same newer-fold-wins rule as a commit. */
|
|
104
|
+
export const applyCards = async (stores, cards) => {
|
|
105
|
+
for (const card of cards) {
|
|
106
|
+
await putCard(stores.cards, card);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { BasicConfig, BasicContext } from '@owlmeans/context';
|
|
2
|
+
import type { PlanningFacade, PlanningProtocols, PlanningScope } from '@owlmeans/planning';
|
|
3
|
+
import type { RemoteFacadeOptions } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* A {@link PlanningFacade} over the remote protocol tree — every method is one entrypoint call.
|
|
6
|
+
*
|
|
7
|
+
* It is the same interface a server facade implements, so a model (`modelOf`) and everything
|
|
8
|
+
* built on the facade run unchanged in a browser or a Node client. Three things differ, and all
|
|
9
|
+
* three are the server's to decide:
|
|
10
|
+
*
|
|
11
|
+
* - the scope is advisory — the server takes the entity and the actor from the credential, and the
|
|
12
|
+
* execution's own `actor` is never sent;
|
|
13
|
+
* - `execute({ wait: true })` never holds the POST: the receipt comes back at once and the commit is
|
|
14
|
+
* awaited through `commits.wait` (subscribe, then long-poll), so a lost response cannot leave a
|
|
15
|
+
* caller unsure whether the transition was appended;
|
|
16
|
+
* - `cards.count` is a one-row list read for its `total` — the tree declares no count route.
|
|
17
|
+
*/
|
|
18
|
+
export declare const makeRemoteFacade: <C extends BasicConfig, T extends BasicContext<C>>(context: T, protocols: PlanningProtocols, scope: Partial<PlanningScope>, opts: RemoteFacadeOptions) => PlanningFacade;
|
|
19
|
+
//# sourceMappingURL=facade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facade.d.ts","sourceRoot":"","sources":["../src/facade.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAMlE,OAAO,KAAK,EACV,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAEjD,MAAM,oBAAoB,CAAA;AAE3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAErD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WACtE,CAAC,aAAa,iBAAiB,SAAS,OAAO,CAAC,aAAa,CAAC,QAAQ,mBAAmB,KACjG,cA0IF,CAAA"}
|
package/build/facade.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { CommitFailed, CommitState, DEFAULT_COMMIT_TIMEOUT, PlanningError, PlanningUnsupported, WorkcardNotFound, encodeRelationshipQuery, encodeSpecificationQuery, encodeSummaryQuery, encodeTransitionQuery, encodeWorkcardQuery, modelOf, } from '@owlmeans/planning';
|
|
2
|
+
import { applyReceipt } from './events.js';
|
|
3
|
+
/**
|
|
4
|
+
* A {@link PlanningFacade} over the remote protocol tree — every method is one entrypoint call.
|
|
5
|
+
*
|
|
6
|
+
* It is the same interface a server facade implements, so a model (`modelOf`) and everything
|
|
7
|
+
* built on the facade run unchanged in a browser or a Node client. Three things differ, and all
|
|
8
|
+
* three are the server's to decide:
|
|
9
|
+
*
|
|
10
|
+
* - the scope is advisory — the server takes the entity and the actor from the credential, and the
|
|
11
|
+
* execution's own `actor` is never sent;
|
|
12
|
+
* - `execute({ wait: true })` never holds the POST: the receipt comes back at once and the commit is
|
|
13
|
+
* awaited through `commits.wait` (subscribe, then long-poll), so a lost response cannot leave a
|
|
14
|
+
* caller unsure whether the transition was appended;
|
|
15
|
+
* - `cards.count` is a one-row list read for its `total` — the tree declares no count route.
|
|
16
|
+
*/
|
|
17
|
+
export const makeRemoteFacade = (context, protocols, scope, opts) => {
|
|
18
|
+
const timeout = opts.timeout;
|
|
19
|
+
const { commits } = opts;
|
|
20
|
+
const receiptOf = (view) => {
|
|
21
|
+
const id = view.transition.id;
|
|
22
|
+
if (id == null) {
|
|
23
|
+
throw new PlanningError('malformed:receipt-without-transition');
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
transition: view.transition,
|
|
27
|
+
...(view.card !== undefined ? { card: view.card } : {}),
|
|
28
|
+
committed: async (waitOpts) => {
|
|
29
|
+
const { state, error } = view.transition.commit;
|
|
30
|
+
if (state === CommitState.Failed) {
|
|
31
|
+
throw new CommitFailed(error ?? id);
|
|
32
|
+
}
|
|
33
|
+
if (state === CommitState.Committed && view.card !== undefined) {
|
|
34
|
+
return view.card;
|
|
35
|
+
}
|
|
36
|
+
return await commits.wait(id, { timeout: waitOpts?.timeout ?? DEFAULT_COMMIT_TIMEOUT });
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
const facade = {
|
|
41
|
+
scope: { ...scope, entityId: scope.entityId ?? '' },
|
|
42
|
+
schemas: opts.schemas,
|
|
43
|
+
cards: {
|
|
44
|
+
get: async (id) => await context.entrypoint(protocols.card.get).call({ params: { id }, timeout }),
|
|
45
|
+
load: async (id) => {
|
|
46
|
+
try {
|
|
47
|
+
return await facade.cards.get(id);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
if (e instanceof WorkcardNotFound) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
throw e;
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
list: async (query) => await context.entrypoint(protocols.card.list).call({
|
|
57
|
+
query: encodeWorkcardQuery(query), timeout,
|
|
58
|
+
}),
|
|
59
|
+
count: async (query) => {
|
|
60
|
+
const { page: _page, size: _size, sort: _sort, ...where } = query ?? {};
|
|
61
|
+
const answer = await context.entrypoint(protocols.card.list).call({
|
|
62
|
+
query: encodeWorkcardQuery({ ...where, page: 0, size: 1 }), timeout,
|
|
63
|
+
});
|
|
64
|
+
return answer.total;
|
|
65
|
+
},
|
|
66
|
+
summary: async (parents, query) => await context.entrypoint(protocols.card.summary).call({
|
|
67
|
+
query: encodeSummaryQuery({ ...query, parents }), timeout,
|
|
68
|
+
}),
|
|
69
|
+
},
|
|
70
|
+
specifications: {
|
|
71
|
+
current: async (parent, category) => {
|
|
72
|
+
const answer = await context.entrypoint(protocols.card.specifications).call({
|
|
73
|
+
params: { id: parent }, query: encodeSpecificationQuery({ category }), timeout,
|
|
74
|
+
});
|
|
75
|
+
return answer.items[0] ?? null;
|
|
76
|
+
},
|
|
77
|
+
list: async (parent, query) => await context.entrypoint(protocols.card.specifications).call({
|
|
78
|
+
params: { id: parent }, query: encodeSpecificationQuery(query), timeout,
|
|
79
|
+
}),
|
|
80
|
+
get: async (id) => await context.entrypoint(protocols.spec.get).call({ params: { id }, timeout }),
|
|
81
|
+
revisions: async (id, limit) => {
|
|
82
|
+
const answer = await context.entrypoint(protocols.spec.revisions).call({
|
|
83
|
+
params: { id }, query: limit != null ? { limit } : {}, timeout,
|
|
84
|
+
});
|
|
85
|
+
return answer.items;
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
relationships: {
|
|
89
|
+
list: async (query) => await context.entrypoint(protocols.link.list).call({
|
|
90
|
+
query: encodeRelationshipQuery(query), timeout,
|
|
91
|
+
}),
|
|
92
|
+
},
|
|
93
|
+
transitions: {
|
|
94
|
+
get: async (id) => await context.entrypoint(protocols.transition.get).call({
|
|
95
|
+
params: { transition: id }, timeout,
|
|
96
|
+
}),
|
|
97
|
+
list: async (query) => {
|
|
98
|
+
// The tree reads the log through ONE card; a project-wide read has no route to travel.
|
|
99
|
+
if (query.card == null) {
|
|
100
|
+
throw new PlanningUnsupported('client:transitions-without-card');
|
|
101
|
+
}
|
|
102
|
+
return await context.entrypoint(protocols.card.transitions).call({
|
|
103
|
+
params: { id: query.card }, query: encodeTransitionQuery(query), timeout,
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
commits,
|
|
108
|
+
execute: async (exec, executeOpts) => {
|
|
109
|
+
// Neither the actor nor a hold travels: the server decides who wrote, and the wait is ours.
|
|
110
|
+
const { actor: _actor, ...body } = exec;
|
|
111
|
+
const view = await context.entrypoint(protocols.execute).call({ body, timeout });
|
|
112
|
+
const stores = opts.stores?.();
|
|
113
|
+
if (stores != null) {
|
|
114
|
+
await applyReceipt(stores, view);
|
|
115
|
+
}
|
|
116
|
+
const receipt = receiptOf(view);
|
|
117
|
+
if (executeOpts?.wait === true) {
|
|
118
|
+
receipt.card = await receipt.committed({ timeout: executeOpts.timeout });
|
|
119
|
+
}
|
|
120
|
+
return receipt;
|
|
121
|
+
},
|
|
122
|
+
model: async (card) => {
|
|
123
|
+
await opts.loadSchemas?.();
|
|
124
|
+
const record = typeof card === 'string' ? await facade.cards.get(card) : card;
|
|
125
|
+
return modelOf(record, facade);
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
return facade;
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=facade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facade.js","sourceRoot":"","sources":["../src/facade.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EAAE,WAAW,EAAE,sBAAsB,EAAE,aAAa,EAAE,mBAAmB,EAAE,gBAAgB,EACvG,uBAAuB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,qBAAqB,EAC5F,mBAAmB,EAAE,OAAO,GAC7B,MAAM,oBAAoB,CAAA;AAK3B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG1C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,OAAU,EAAE,SAA4B,EAAE,KAA6B,EAAE,IAAyB,EAClF,EAAE;IAClB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;IAC5B,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAExB,MAAM,SAAS,GAAG,CAAC,IAA2B,EAAqB,EAAE;QACnE,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,CAAA;QAC7B,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;YACf,MAAM,IAAI,aAAa,CAAC,sCAAsC,CAAC,CAAA;QACjE,CAAC;QAED,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,SAAS,EAAE,KAAK,EAAC,QAAQ,EAAC,EAAE;gBAC1B,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAA;gBAC/C,IAAI,KAAK,KAAK,WAAW,CAAC,MAAM,EAAE,CAAC;oBACjC,MAAM,IAAI,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;gBACrC,CAAC;gBACD,IAAI,KAAK,KAAK,WAAW,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;oBAC/D,OAAO,IAAI,CAAC,IAAI,CAAA;gBAClB,CAAC;gBAED,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,sBAAsB,EAAE,CAAC,CAAA;YACzF,CAAC;SACF,CAAA;IACH,CAAC,CAAA;IAED,MAAM,MAAM,GAAmB;QAC7B,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE,EAAE;QAEnD,OAAO,EAAE,IAAI,CAAC,OAAO;QAErB,KAAK,EAAE;YACL,GAAG,EAAE,KAAK,EAAC,EAAE,EAAC,EAAE,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;YAE/F,IAAI,EAAE,KAAK,EAAC,EAAE,EAAC,EAAE;gBACf,IAAI,CAAC;oBACH,OAAO,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;gBACnC,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,IAAI,CAAC,YAAY,gBAAgB,EAAE,CAAC;wBAClC,OAAO,IAAI,CAAA;oBACb,CAAC;oBACD,MAAM,CAAC,CAAA;gBACT,CAAC;YACH,CAAC;YAED,IAAI,EAAE,KAAK,EAAC,KAAK,EAAC,EAAE,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;gBACtE,KAAK,EAAE,mBAAmB,CAAC,KAAK,CAAC,EAAE,OAAO;aAC3C,CAAC;YAEF,KAAK,EAAE,KAAK,EAAC,KAAK,EAAC,EAAE;gBACnB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,IAAI,EAAE,CAAA;gBACvE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;oBAChE,KAAK,EAAE,mBAAmB,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO;iBACpE,CAAC,CAAA;gBAEF,OAAO,MAAM,CAAC,KAAK,CAAA;YACrB,CAAC;YAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;gBACvF,KAAK,EAAE,kBAAkB,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO;aAC1D,CAAC;SACH;QAED,cAAc,EAAE;YACd,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;gBAClC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC;oBAC1E,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,wBAAwB,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO;iBAC/E,CAAC,CAAA;gBAEF,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAA;YAChC,CAAC;YAED,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC;gBAC1F,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,wBAAwB,CAAC,KAAK,CAAC,EAAE,OAAO;aACxE,CAAC;YAEF,GAAG,EAAE,KAAK,EAAC,EAAE,EAAC,EAAE,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;YAE/F,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE;gBAC7B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;oBACrE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO;iBAC/D,CAAC,CAAA;gBAEF,OAAO,MAAM,CAAC,KAAK,CAAA;YACrB,CAAC;SACF;QAED,aAAa,EAAE;YACb,IAAI,EAAE,KAAK,EAAC,KAAK,EAAC,EAAE,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;gBACtE,KAAK,EAAE,uBAAuB,CAAC,KAAK,CAAC,EAAE,OAAO;aAC/C,CAAC;SACH;QAED,WAAW,EAAE;YACX,GAAG,EAAE,KAAK,EAAC,EAAE,EAAC,EAAE,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACvE,MAAM,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,OAAO;aACpC,CAAC;YAEF,IAAI,EAAE,KAAK,EAAC,KAAK,EAAC,EAAE;gBAClB,uFAAuF;gBACvF,IAAI,KAAK,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;oBACvB,MAAM,IAAI,mBAAmB,CAAC,iCAAiC,CAAC,CAAA;gBAClE,CAAC;gBAED,OAAO,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC;oBAC/D,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,qBAAqB,CAAC,KAAK,CAAC,EAAE,OAAO;iBACzE,CAAC,CAAA;YACJ,CAAC;SACF;QAED,OAAO;QAEP,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;YACnC,4FAA4F;YAC5F,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAA;YACvC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;YAChF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,CAAA;YAC9B,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;gBACnB,MAAM,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;YAClC,CAAC;YACD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;YAC/B,IAAI,WAAW,EAAE,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC/B,OAAO,CAAC,IAAI,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;YAC1E,CAAC;YAED,OAAO,OAAO,CAAA;QAChB,CAAC;QAED,KAAK,EAAE,KAAK,EAAiC,IAAgB,EAA6B,EAAE;YAC1F,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE,CAAA;YAC1B,MAAM,MAAM,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAM,CAAC,CAAC,CAAC,IAAI,CAAA;YAElF,OAAO,OAAO,CAAI,MAAM,EAAE,MAAM,CAAC,CAAA;QACnC,CAAC;KACF,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC,CAAA"}
|
package/build/feed.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BasicConfig, BasicContext } from '@owlmeans/context';
|
|
2
|
+
import type { PlanningFeed, PlanningFeedOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Keep the state mirror current: subscribe to commits FIRST, then seed from the list, then fold
|
|
5
|
+
* every frame — and, with `refresh`, re-seed on an interval as the authoritative backstop to a
|
|
6
|
+
* socket that can drop frames. React-free: a hook wraps it, a Node process uses it as it is.
|
|
7
|
+
*
|
|
8
|
+
* The seed is `syncCards` over `where` (default `criteriaOf(query)`), never `replace()`: the store
|
|
9
|
+
* holds every kind, and a board's list must not drop the projects beside it. A card a frame wrote
|
|
10
|
+
* while the list was in flight is kept even when the list does not name it yet. A PAGED seed only
|
|
11
|
+
* writes — a page cannot say what does not exist.
|
|
12
|
+
*
|
|
13
|
+
* Without a socket opener the feed is a seed plus its refresh; `commits.wait` still long-polls.
|
|
14
|
+
*
|
|
15
|
+
* @throws {SyntaxError} when the context has no planning client or no planning stores
|
|
16
|
+
*/
|
|
17
|
+
export declare const makePlanningFeed: <C extends BasicConfig, T extends BasicContext<C>>(context: T, opts?: PlanningFeedOptions) => PlanningFeed;
|
|
18
|
+
//# sourceMappingURL=feed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feed.d.ts","sourceRoot":"","sources":["../src/feed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAMlE,OAAO,KAAK,EAAyB,YAAY,EAAE,mBAAmB,EAAqB,MAAM,YAAY,CAAA;AAM7G;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WACtE,CAAC,SAAQ,mBAAmB,KACpC,YAsGF,CAAA"}
|