@kestack/kabuki 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +274 -2
- package/dist/core/actor/actor.d.ts +42 -0
- package/dist/core/actor/actor.d.ts.map +1 -0
- package/dist/core/actor/actor.js +168 -0
- package/dist/core/actor/command.d.ts +24 -0
- package/dist/core/actor/command.d.ts.map +1 -0
- package/dist/core/actor/command.js +31 -0
- package/dist/core/actor/index.d.ts +6 -0
- package/dist/core/actor/index.d.ts.map +1 -0
- package/dist/core/actor/index.js +3 -0
- package/dist/core/actor/types.d.ts +295 -0
- package/dist/core/actor/types.d.ts.map +1 -0
- package/dist/core/actor/types.js +2 -0
- package/dist/core/history/history.d.ts +67 -0
- package/dist/core/history/history.d.ts.map +1 -0
- package/dist/core/history/history.js +145 -0
- package/dist/core/history/index.d.ts +5 -0
- package/dist/core/history/index.d.ts.map +1 -0
- package/dist/core/history/index.js +2 -0
- package/dist/core/history/replay.d.ts +34 -0
- package/dist/core/history/replay.d.ts.map +1 -0
- package/dist/core/history/replay.js +82 -0
- package/dist/core/history/saved.d.ts +7 -0
- package/dist/core/history/saved.d.ts.map +1 -0
- package/dist/core/history/saved.js +126 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +4 -0
- package/dist/core/runtime/index.d.ts +4 -0
- package/dist/core/runtime/index.d.ts.map +1 -0
- package/dist/core/runtime/index.js +1 -0
- package/dist/core/runtime/instance/command.d.ts +4 -0
- package/dist/core/runtime/instance/command.d.ts.map +1 -0
- package/dist/core/runtime/instance/command.js +12 -0
- package/dist/core/runtime/instance/index.d.ts +4 -0
- package/dist/core/runtime/instance/index.d.ts.map +1 -0
- package/dist/core/runtime/instance/index.js +1 -0
- package/dist/core/runtime/instance/instance.d.ts +16 -0
- package/dist/core/runtime/instance/instance.d.ts.map +1 -0
- package/dist/core/runtime/instance/instance.js +113 -0
- package/dist/core/runtime/instance/self.d.ts +35 -0
- package/dist/core/runtime/instance/self.d.ts.map +1 -0
- package/dist/core/runtime/instance/self.js +42 -0
- package/dist/core/runtime/instance/worker.d.ts +16 -0
- package/dist/core/runtime/instance/worker.d.ts.map +1 -0
- package/dist/core/runtime/instance/worker.js +52 -0
- package/dist/core/runtime/mailbox.d.ts +10 -0
- package/dist/core/runtime/mailbox.d.ts.map +1 -0
- package/dist/core/runtime/mailbox.js +64 -0
- package/dist/core/runtime/runtime.d.ts +36 -0
- package/dist/core/runtime/runtime.d.ts.map +1 -0
- package/dist/core/runtime/runtime.js +93 -0
- package/dist/core/runtime/time.d.ts +11 -0
- package/dist/core/runtime/time.d.ts.map +1 -0
- package/dist/core/runtime/time.js +22 -0
- package/dist/core/snapshot/handle.d.ts +14 -0
- package/dist/core/snapshot/handle.d.ts.map +1 -0
- package/dist/core/snapshot/handle.js +70 -0
- package/dist/core/snapshot/index.d.ts +8 -0
- package/dist/core/snapshot/index.d.ts.map +1 -0
- package/dist/core/snapshot/index.js +4 -0
- package/dist/core/snapshot/invoke.d.ts +17 -0
- package/dist/core/snapshot/invoke.d.ts.map +1 -0
- package/dist/core/snapshot/invoke.js +119 -0
- package/dist/core/snapshot/restore.d.ts +16 -0
- package/dist/core/snapshot/restore.d.ts.map +1 -0
- package/dist/core/snapshot/restore.js +63 -0
- package/dist/core/snapshot/snapshot.d.ts +61 -0
- package/dist/core/snapshot/snapshot.d.ts.map +1 -0
- package/dist/core/snapshot/snapshot.js +4 -0
- package/dist/core/snapshot/tree.d.ts +26 -0
- package/dist/core/snapshot/tree.d.ts.map +1 -0
- package/dist/core/snapshot/tree.js +77 -0
- package/dist/react/app.d.ts +49 -0
- package/dist/react/app.d.ts.map +1 -0
- package/dist/react/app.js +214 -0
- package/dist/react/child.d.ts +32 -0
- package/dist/react/child.d.ts.map +1 -0
- package/dist/react/child.js +80 -0
- package/dist/react/drawn.d.ts +4 -0
- package/dist/react/drawn.d.ts.map +1 -0
- package/dist/react/drawn.js +118 -0
- package/dist/react/index.d.ts +7 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +3 -0
- package/dist/react/registry.d.ts +12 -0
- package/dist/react/registry.d.ts.map +1 -0
- package/dist/react/registry.js +25 -0
- package/dist/react/view.d.ts +80 -0
- package/dist/react/view.d.ts.map +1 -0
- package/dist/react/view.js +47 -0
- package/package.json +55 -3
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import { actorAt, handle, init, isRestore } from '../snapshot/index.js';
|
|
3
|
+
const make = (root, input, { budget = 8, every = 100 } = {}) => {
|
|
4
|
+
const played = new Map([[null, init(root, input)]]);
|
|
5
|
+
/** How many entries of `branch` are already played, and the Snapshot after them. */
|
|
6
|
+
const nearest = (branch) => {
|
|
7
|
+
const count = branch.findLastIndex((entry) => played.has(entry.id)) + 1;
|
|
8
|
+
const after = count === 0 ? null : branch[count - 1].id;
|
|
9
|
+
return { count, snapshot: played.get(after) };
|
|
10
|
+
};
|
|
11
|
+
const at = (branch) => {
|
|
12
|
+
const { count, snapshot } = nearest(branch);
|
|
13
|
+
return branch.slice(count).reduce((before, entry) => {
|
|
14
|
+
const after = play(root, before, entry);
|
|
15
|
+
played.set(entry.id, after);
|
|
16
|
+
return after;
|
|
17
|
+
}, snapshot);
|
|
18
|
+
};
|
|
19
|
+
const seek = (branch) => Effect.gen(function* () {
|
|
20
|
+
let { count, snapshot } = nearest(branch);
|
|
21
|
+
let since = performance.now();
|
|
22
|
+
for (const entry of branch.slice(count)) {
|
|
23
|
+
snapshot = play(root, snapshot, entry);
|
|
24
|
+
if (++count % every === 0 || count === branch.length)
|
|
25
|
+
played.set(entry.id, snapshot);
|
|
26
|
+
if (performance.now() - since >= budget) {
|
|
27
|
+
yield* Effect.yieldNow;
|
|
28
|
+
since = performance.now();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return snapshot;
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
at,
|
|
35
|
+
seek,
|
|
36
|
+
remember: (entry, snapshot) => void played.set(entry, snapshot),
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Handle an Envelope from the History: first check its Message against its
|
|
41
|
+
* Actor's Schema, as a Send does. Throws when either no longer fits, because
|
|
42
|
+
* the code changed under the History.
|
|
43
|
+
*/
|
|
44
|
+
const replayed = (root, snapshot, envelope) => {
|
|
45
|
+
const { destination, message } = envelope;
|
|
46
|
+
if (!isRestore(message))
|
|
47
|
+
actorAt(root, snapshot, destination)?.check.message(message, `Message ${JSON.stringify(message._tag)}`);
|
|
48
|
+
return handle(root, snapshot, envelope);
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* What came of an Envelope on this Snapshot: worked out by handling it again,
|
|
52
|
+
* never kept. One that no longer fits the code, which Replay skips, counts as
|
|
53
|
+
* ignored.
|
|
54
|
+
*/
|
|
55
|
+
export const outcomeOf = (root, snapshot, envelope) => {
|
|
56
|
+
try {
|
|
57
|
+
return replayed(root, snapshot, envelope).outcome;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return 'ignored';
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
/** The Snapshot right after one entry, from the one before it. */
|
|
64
|
+
const play = (root, snapshot, entry) => {
|
|
65
|
+
try {
|
|
66
|
+
return replayed(root, snapshot, entry).snapshot;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
diverged(entry, error);
|
|
70
|
+
return snapshot;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
/** The Snapshot right after a whole Branch, played now from init with the root's Input. */
|
|
74
|
+
const fold = (root, branch, input) => branch.reduce((snapshot, entry) => play(root, snapshot, entry), init(root, input));
|
|
75
|
+
export const Replay = { make, fold };
|
|
76
|
+
const warned = new WeakSet();
|
|
77
|
+
const diverged = (entry, error) => {
|
|
78
|
+
if (warned.has(entry))
|
|
79
|
+
return;
|
|
80
|
+
warned.add(entry);
|
|
81
|
+
console.warn(`[@kestack/kabuki] Replay diverged at entry ${entry.id}, ${entry.message._tag} for ${entry.destination}, and skips it: ${error.message}`);
|
|
82
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ActorDefinition } from '../actor/index.ts';
|
|
2
|
+
import type { Entry, SavedHistory } from './history.ts';
|
|
3
|
+
export declare const encodeEntry: (root: ActorDefinition, entry: Entry) => Entry;
|
|
4
|
+
export declare const decodeEntry: (root: ActorDefinition, entry: Entry) => Entry;
|
|
5
|
+
/** Throws, saying what is wrong, unless `saved` is a History's shape: entries by position, each after an earlier one, and a Head among them. */
|
|
6
|
+
export declare const checkSaved: (saved: SavedHistory) => void;
|
|
7
|
+
//# sourceMappingURL=saved.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saved.d.ts","sourceRoot":"","sources":["../../../src/core/history/saved.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAoB,MAAM,mBAAmB,CAAC;AAG3E,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAexD,eAAO,MAAM,WAAW,SAAU,eAAe,SAAS,KAAK,KAAG,KAqBjE,CAAC;AAGF,eAAO,MAAM,WAAW,SAAU,eAAe,SAAS,KAAK,KAAG,KAmBjE,CAAC;AAwDF,gJAAgJ;AAChJ,eAAO,MAAM,UAAU,UAAW,YAAY,KAAG,IAsBhD,CAAC"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { isMany, isRestore, restore } from '../snapshot/index.js';
|
|
2
|
+
/*
|
|
3
|
+
* Saved: a History as plain JSON. In memory every value is decoded; saved,
|
|
4
|
+
* each Message, and each Instance of a Restore's Snapshot, is its Actor's
|
|
5
|
+
* Schemas' encoded side. So only that side must be JSON-safe.
|
|
6
|
+
*
|
|
7
|
+
* 1. Encode an entry, through the Schemas of the Actor it is for. One that
|
|
8
|
+
* does not fit is saved as it is: it never plays.
|
|
9
|
+
* 2. Decode an entry read back. One that no longer fits the code is kept
|
|
10
|
+
* as it was saved: Replay warns of it and skips it.
|
|
11
|
+
* 3. Check a saved History's shape before it is read.
|
|
12
|
+
*/
|
|
13
|
+
// 1. Encode
|
|
14
|
+
export const encodeEntry = (root, entry) => {
|
|
15
|
+
const { message } = entry;
|
|
16
|
+
// A value that does not fit its Schema is saved as it is: it was dropped
|
|
17
|
+
// live, or Replay skips it, so it never plays.
|
|
18
|
+
if (isRestore(message))
|
|
19
|
+
try {
|
|
20
|
+
return {
|
|
21
|
+
...entry,
|
|
22
|
+
message: restore(convert(root, message.snapshot, 'encode')),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return entry;
|
|
27
|
+
}
|
|
28
|
+
for (const definition of actorsAt(root, entry.destination))
|
|
29
|
+
try {
|
|
30
|
+
return {
|
|
31
|
+
...entry,
|
|
32
|
+
message: definition.encoding.message.encode(message),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch { }
|
|
36
|
+
return entry;
|
|
37
|
+
};
|
|
38
|
+
// 2. Decode
|
|
39
|
+
export const decodeEntry = (root, entry) => {
|
|
40
|
+
const { message } = entry;
|
|
41
|
+
try {
|
|
42
|
+
if (isRestore(message))
|
|
43
|
+
return {
|
|
44
|
+
...entry,
|
|
45
|
+
message: restore(convert(root, message.snapshot, 'decode')),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return entry;
|
|
50
|
+
}
|
|
51
|
+
for (const definition of actorsAt(root, entry.destination))
|
|
52
|
+
try {
|
|
53
|
+
return {
|
|
54
|
+
...entry,
|
|
55
|
+
message: definition.encoding.message.decode(message),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch { }
|
|
59
|
+
return entry;
|
|
60
|
+
};
|
|
61
|
+
/** An Instance and every Child under it, each through its own Actor's Schemas. */
|
|
62
|
+
const convert = (definition, instance, way) => {
|
|
63
|
+
const { model, state, props } = definition.encoding;
|
|
64
|
+
const next = state[way](instance.state);
|
|
65
|
+
const slots = definition.children[next._tag] ?? {};
|
|
66
|
+
const child = (slot, held) => {
|
|
67
|
+
const wanted = slots[slot];
|
|
68
|
+
if (!wanted)
|
|
69
|
+
throw new Error(`no Child "${slot}" in ${next._tag}`);
|
|
70
|
+
return convert(wanted.definition, held, way);
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
...instance,
|
|
74
|
+
state: next,
|
|
75
|
+
model: model[way](instance.model),
|
|
76
|
+
...('props' in instance ? { props: props[way](instance.props) } : {}),
|
|
77
|
+
children: Object.fromEntries(Object.entries(instance.children).map(([slot, held]) => [
|
|
78
|
+
slot,
|
|
79
|
+
isMany(held) ? held.map((one) => child(slot, one)) : child(slot, held),
|
|
80
|
+
])),
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Every Actor an Instance with this ID can be, read from the ID alone: the
|
|
85
|
+
* Actor of the slot at each step down, in any State. Usually one; a slot
|
|
86
|
+
* name written in two States for two Actors gives both.
|
|
87
|
+
*/
|
|
88
|
+
const actorsAt = (root, id) => {
|
|
89
|
+
const [first, ...steps] = id.split('/');
|
|
90
|
+
if (first !== root.name)
|
|
91
|
+
return [];
|
|
92
|
+
let at = [root];
|
|
93
|
+
for (const step of steps) {
|
|
94
|
+
const slot = step.slice(0, step.search(/[[#]/));
|
|
95
|
+
const next = new Set();
|
|
96
|
+
for (const definition of at)
|
|
97
|
+
for (const slots of Object.values(definition.children)) {
|
|
98
|
+
const found = slots?.[slot]?.definition;
|
|
99
|
+
if (found)
|
|
100
|
+
next.add(found);
|
|
101
|
+
}
|
|
102
|
+
at = [...next];
|
|
103
|
+
}
|
|
104
|
+
return at;
|
|
105
|
+
};
|
|
106
|
+
// 3. Check
|
|
107
|
+
/** Throws, saying what is wrong, unless `saved` is a History's shape: entries by position, each after an earlier one, and a Head among them. */
|
|
108
|
+
export const checkSaved = (saved) => {
|
|
109
|
+
const fail = (why) => {
|
|
110
|
+
throw new TypeError(`[@kestack/kabuki] the saved History is corrupt: ${why}`);
|
|
111
|
+
};
|
|
112
|
+
if (!saved || !Array.isArray(saved.entries))
|
|
113
|
+
fail('it has no entries');
|
|
114
|
+
saved.entries.forEach((entry, index) => {
|
|
115
|
+
if (entry?.id !== index)
|
|
116
|
+
fail(`entry ${index} has the id ${entry?.id}`);
|
|
117
|
+
const { parent } = entry;
|
|
118
|
+
if (parent !== null &&
|
|
119
|
+
!(Number.isInteger(parent) && parent >= 0 && parent < index))
|
|
120
|
+
fail(`entry ${index} follows ${parent}, not an entry before it`);
|
|
121
|
+
});
|
|
122
|
+
const { head } = saved;
|
|
123
|
+
if (head !== null &&
|
|
124
|
+
!(Number.isInteger(head) && head >= 0 && head < saved.entries.length))
|
|
125
|
+
fail(`its Head ${head} is not one of its ${saved.entries.length} entries`);
|
|
126
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { Actor, Command } from './actor/index.ts';
|
|
2
|
+
export type { ActorOf, AnyActor, Data, Defined, ActorDefinition, Many, Only, Self, Tagged, Types, Worker, WorkerDefinition, Workers, } from './actor/index.ts';
|
|
3
|
+
export { RESTORE, handle, init, instanceAt, isMany, isRestore, restore, } from './snapshot/index.ts';
|
|
4
|
+
export type { Envelope, Handled, Instance, Restore, Snapshot, Source, } from './snapshot/index.ts';
|
|
5
|
+
export { History, Replay, outcomeOf } from './history/index.ts';
|
|
6
|
+
export type { Entry, HistoryOptions, ReplayOptions, SavedHistory, } from './history/index.ts';
|
|
7
|
+
export { Runtime } from './runtime/index.ts';
|
|
8
|
+
export type { Needs, Running, WorkerStatus } from './runtime/index.ts';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EACV,OAAO,EACP,QAAQ,EACR,IAAI,EACJ,OAAO,EACP,eAAe,EACf,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,KAAK,EACL,MAAM,EACN,gBAAgB,EAChB,OAAO,GACR,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,OAAO,EACP,MAAM,EACN,IAAI,EACJ,UAAU,EACV,MAAM,EACN,SAAS,EACT,OAAO,GACR,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,MAAM,GACP,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAChE,YAAY,EACV,KAAK,EACL,cAAc,EACd,aAAa,EACb,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Runtime } from './runtime.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/core/runtime/instance/command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAGpC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAUrC,eAAO,MAAM,WAAW,aACZ,aAAa,CAAC,OAAO,CAAC,OAC3B,GAAG,SACD,KAAK,CAAC,KAAK,SAanB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Effect, Schema } from 'effect';
|
|
2
|
+
import { RUN } from '../../actor/index.js';
|
|
3
|
+
/*
|
|
4
|
+
* Commands: errands an Update asked for. Each runs once, in its Instance's
|
|
5
|
+
* Scope, and Sends the Message it ends with. Nothing stops one but its
|
|
6
|
+
* Instance stopping.
|
|
7
|
+
*/
|
|
8
|
+
const isMessage = Schema.is(Schema.Struct({ _tag: Schema.String }));
|
|
9
|
+
export const runCommands = (commands, own, scope) => {
|
|
10
|
+
for (const { name, [RUN]: run } of commands)
|
|
11
|
+
own.fork(scope, `command ${name}`, { kind: 'command', instance: own.self.id, name }, Effect.flatMap(run, (result) => isMessage(result) ? own.self.send(result) : Effect.void));
|
|
12
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/runtime/instance/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ActorInstance } from './instance.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Effect, Scope } from 'effect';
|
|
2
|
+
import type { ActorDefinition } from '../../actor/index.ts';
|
|
3
|
+
import type { Envelope, Handled, Snapshot } from '../../snapshot/index.ts';
|
|
4
|
+
import type { Host } from './self.ts';
|
|
5
|
+
import type { WorkerStatus } from './worker.ts';
|
|
6
|
+
export interface ActorInstance {
|
|
7
|
+
readonly receive: (envelope: Envelope) => Handled;
|
|
8
|
+
readonly workers: (instance: string) => ReadonlyArray<WorkerStatus>;
|
|
9
|
+
readonly stop: () => Effect.Effect<void>;
|
|
10
|
+
}
|
|
11
|
+
declare const start: (definition: ActorDefinition, snapshot: Snapshot, host: Host, scope: Scope.Scope) => ActorInstance;
|
|
12
|
+
export declare const ActorInstance: {
|
|
13
|
+
start: typeof start;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=instance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../../../src/core/runtime/instance/instance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,MAAM,EAAe,KAAK,EAAE,MAAM,QAAQ,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,sBAAsB,CAAC;AAE5E,OAAO,KAAK,EACV,QAAQ,EACR,OAAO,EAEP,QAAQ,EACT,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,IAAI,EAAiB,MAAM,WAAW,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAiBhD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC,YAAY,CAAC,CAAC;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CAC1C;AAoBD,QAAA,MAAM,KAAK,eACG,eAAe,YACjB,QAAQ,QACZ,IAAI,SACH,KAAK,CAAC,KAAK,KACjB,aAmJF,CAAC;AAcF,eAAO,MAAM,aAAa;;CAAY,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Context, Deferred, Effect, Exit, Layer, Scope } from 'effect';
|
|
2
|
+
import { handle, isMany, within } from '../../snapshot/index.js';
|
|
3
|
+
import { runCommands } from './command.js';
|
|
4
|
+
import { dataOf, forkIn, makeOwn } from './self.js';
|
|
5
|
+
import { makeWorkers } from './worker.js';
|
|
6
|
+
/** What an Instance's own code reads; a change to any of it reaches its Self and its Workers. */
|
|
7
|
+
const DATA = ['model', 'state', 'props'];
|
|
8
|
+
const start = (definition, snapshot, host, scope) => {
|
|
9
|
+
// 1. Start
|
|
10
|
+
const live = (definition, instance, parent) => {
|
|
11
|
+
const own = makeOwn(instance, host, parent.services);
|
|
12
|
+
const inside = open(parent, definition.provides, own);
|
|
13
|
+
const workers = makeWorkers(definition.workers, own, inside.scope);
|
|
14
|
+
workers.sync(dataOf(instance));
|
|
15
|
+
const top = children(slotsAt(definition, instance, 'top'), instance, inside);
|
|
16
|
+
/** A State lasts while the Instance is in it: a Scope inside the Instance's, what it Provides, and its Children. */
|
|
17
|
+
const enter = (instance) => {
|
|
18
|
+
const place = open(inside, definition.stateProvides[instance.state._tag], own);
|
|
19
|
+
return {
|
|
20
|
+
children: children(slotsAt(definition, instance, 'state'), instance, place),
|
|
21
|
+
stop: () => Effect.runFork(Scope.close(place.scope, Exit.void)),
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
let state = enter(instance);
|
|
25
|
+
let current = instance;
|
|
26
|
+
// 3. Follow
|
|
27
|
+
const follow = (next) => {
|
|
28
|
+
if (next === current)
|
|
29
|
+
return;
|
|
30
|
+
const before = current;
|
|
31
|
+
current = next;
|
|
32
|
+
const entered = before.state._tag !== next.state._tag;
|
|
33
|
+
if (entered)
|
|
34
|
+
state.stop();
|
|
35
|
+
if (DATA.some((field) => before[field] !== next[field])) {
|
|
36
|
+
own.set(next);
|
|
37
|
+
workers.sync(dataOf(next));
|
|
38
|
+
}
|
|
39
|
+
if (entered)
|
|
40
|
+
state = enter(next);
|
|
41
|
+
else
|
|
42
|
+
state.children.follow(next);
|
|
43
|
+
top.follow(next);
|
|
44
|
+
};
|
|
45
|
+
const living = {
|
|
46
|
+
follow,
|
|
47
|
+
find: (id) => id === instance.id ? living : (top.find(id) ?? state.children.find(id)),
|
|
48
|
+
command: (commands) => runCommands(commands, own, inside.scope),
|
|
49
|
+
workers: workers.statuses,
|
|
50
|
+
// 4. Stop
|
|
51
|
+
stop: () => Scope.close(inside.scope, Exit.void),
|
|
52
|
+
};
|
|
53
|
+
return living;
|
|
54
|
+
};
|
|
55
|
+
/** A Scope inside `outer`, and the Capabilities below it: the ones from above, with what is Provided there built over them. */
|
|
56
|
+
const open = (outer, provide, own) => {
|
|
57
|
+
const scope = Scope.forkUnsafe(outer.scope);
|
|
58
|
+
if (!provide)
|
|
59
|
+
return { scope, services: outer.services };
|
|
60
|
+
const services = Deferred.makeUnsafe();
|
|
61
|
+
forkIn(host, scope, `${own.self.id} provides`, Deferred.await(outer.services).pipe(Effect.flatMap((above) => Layer.buildWithScope(provide(own.self), scope).pipe(Effect.provideContext(above), Effect.map((built) => Context.merge(above, built)))), Effect.flatMap((below) => Deferred.succeed(services, below))));
|
|
62
|
+
return { scope, services };
|
|
63
|
+
};
|
|
64
|
+
/** The Children held in some slots, alive in one Place: they start, follow and stop as the slots change. */
|
|
65
|
+
const children = (slots, instance, place) => {
|
|
66
|
+
const alive = new Map();
|
|
67
|
+
const held = (parent) => Object.keys(slots).flatMap((slot) => {
|
|
68
|
+
const kids = parent.children[slot];
|
|
69
|
+
const all = !kids ? [] : isMany(kids) ? kids : [kids];
|
|
70
|
+
return all.map((kid) => ({ kid, definition: slots[slot].definition }));
|
|
71
|
+
});
|
|
72
|
+
const add = ({ kid, definition }) => alive.set(kid.id, live(definition, kid, place));
|
|
73
|
+
held(instance).forEach(add);
|
|
74
|
+
return {
|
|
75
|
+
follow: (parent) => {
|
|
76
|
+
const next = held(parent);
|
|
77
|
+
const kept = new Set(next.map(({ kid }) => kid.id));
|
|
78
|
+
for (const [id, gone] of alive)
|
|
79
|
+
if (!kept.has(id)) {
|
|
80
|
+
alive.delete(id);
|
|
81
|
+
Effect.runFork(gone.stop());
|
|
82
|
+
}
|
|
83
|
+
for (const each of next) {
|
|
84
|
+
const known = alive.get(each.kid.id);
|
|
85
|
+
if (known)
|
|
86
|
+
known.follow(each.kid);
|
|
87
|
+
else
|
|
88
|
+
add(each);
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
find: (id) => [...alive].find(([kid]) => within(kid, id))?.[1].find(id),
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
const services = Deferred.makeUnsafe();
|
|
95
|
+
Deferred.doneUnsafe(services, Effect.succeed(host.services));
|
|
96
|
+
const root = live(definition, snapshot, { scope, services });
|
|
97
|
+
let current = snapshot;
|
|
98
|
+
return {
|
|
99
|
+
// 2. Receive
|
|
100
|
+
receive: (envelope) => {
|
|
101
|
+
const handled = handle(definition, current, envelope);
|
|
102
|
+
current = handled.snapshot;
|
|
103
|
+
root.follow(current);
|
|
104
|
+
root.find(envelope.destination)?.command(handled.commands);
|
|
105
|
+
return handled;
|
|
106
|
+
},
|
|
107
|
+
workers: (id) => root.find(id)?.workers() ?? [],
|
|
108
|
+
stop: root.stop,
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
/** The slots of an Instance's current State written at its top, or in the State itself. */
|
|
112
|
+
const slotsAt = (definition, instance, where) => Object.fromEntries(Object.entries(definition.children[instance.state._tag] ?? {}).filter(([slot]) => definition.lasting.includes(slot) === (where === 'top')));
|
|
113
|
+
export const ActorInstance = { start };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Cause, Context, Deferred, Effect, Scope } from 'effect';
|
|
2
|
+
import type { Data, Self, Tagged } from '../../actor/index.ts';
|
|
3
|
+
import type { Instance, Source } from '../../snapshot/index.ts';
|
|
4
|
+
/** What the Runtime gives the Instances it runs. */
|
|
5
|
+
export interface Host {
|
|
6
|
+
/** Hand a Message to any Instance, through the one Mailbox. */
|
|
7
|
+
readonly send: (instance: string, message: Tagged, source: Source) => void;
|
|
8
|
+
/** The app's Time. */
|
|
9
|
+
readonly now: () => number;
|
|
10
|
+
/** The Capabilities of the app's Layer. */
|
|
11
|
+
readonly services: Context.Context<never>;
|
|
12
|
+
}
|
|
13
|
+
/** Capabilities that may still be building: the ones from above, or the ones handed below. */
|
|
14
|
+
export type Services = Deferred.Deferred<Context.Context<never>>;
|
|
15
|
+
export type AnySelf = Self<unknown, Tagged, Tagged, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* An Instance's own code: its Self, always reading its current data, and a
|
|
18
|
+
* way to run its Workers, Commands and Provides as that Instance, once the
|
|
19
|
+
* Capabilities from above are built.
|
|
20
|
+
*/
|
|
21
|
+
export declare const makeOwn: (instance: Instance, host: Host, above: Services) => {
|
|
22
|
+
self: AnySelf;
|
|
23
|
+
set: (next: Instance) => void;
|
|
24
|
+
fork: (scope: Scope.Scope, label: string, source: Source, effect: Effect.Effect<unknown, never, any>) => import("effect/Fiber").Fiber<unknown, never>;
|
|
25
|
+
};
|
|
26
|
+
export type Own = ReturnType<typeof makeOwn>;
|
|
27
|
+
/** Run an Effect in a Scope, reporting any failure but being stopped. */
|
|
28
|
+
export declare const forkIn: (host: Host, scope: Scope.Scope, label: string, effect: Effect.Effect<unknown>) => import("effect/Fiber").Fiber<unknown, never>;
|
|
29
|
+
/**
|
|
30
|
+
* Being stopped. In effect 4.0.0 an interrupted Stream of a SubscriptionRef's
|
|
31
|
+
* changes ends in `Done` instead of an interrupt.
|
|
32
|
+
*/
|
|
33
|
+
export declare const stopped: (cause: Cause.Cause<unknown>) => boolean;
|
|
34
|
+
export declare const dataOf: ({ model, state, props, }: Instance) => Data<unknown, Tagged, unknown>;
|
|
35
|
+
//# sourceMappingURL=self.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self.d.ts","sourceRoot":"","sources":["../../../../src/core/runtime/instance/self.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EAGN,KAAK,EAEN,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEhE,oDAAoD;AACpD,MAAM,WAAW,IAAI;IACnB,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3E,sBAAsB;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,2CAA2C;IAC3C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;CAC3C;AAED,8FAA8F;AAC9F,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AAEjE,MAAM,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAU7D;;;;GAIG;AACH,eAAO,MAAM,OAAO,aAAc,QAAQ,QAAQ,IAAI,SAAS,QAAQ;;gBA4CvD,QAAQ;kBApBb,KAAK,CAAC,KAAK,SACX,MAAM,UACL,MAAM,UACN,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC;CAuB7C,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAE7C,yEAAyE;AACzE,eAAO,MAAM,MAAM,SACX,IAAI,SACH,KAAK,CAAC,KAAK,SACX,MAAM,UACL,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,iDAU/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,OAAO,UAAW,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,YACQ,CAAC;AAE5D,eAAO,MAAM,MAAM,6BAIhB,QAAQ,KAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAA8B,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Cause, Context, Deferred, Effect, Exit, Pull, Scope, SubscriptionRef, } from 'effect';
|
|
2
|
+
/** The work running now, which `self.send` stamps as the Message's Source. */
|
|
3
|
+
const Sending = Context.Reference('@kestack/kabuki/Sending', {
|
|
4
|
+
defaultValue: () => undefined,
|
|
5
|
+
});
|
|
6
|
+
/**
|
|
7
|
+
* An Instance's own code: its Self, always reading its current data, and a
|
|
8
|
+
* way to run its Workers, Commands and Provides as that Instance, once the
|
|
9
|
+
* Capabilities from above are built.
|
|
10
|
+
*/
|
|
11
|
+
export const makeOwn = (instance, host, above) => {
|
|
12
|
+
const data = Effect.runSyncWith(host.services)(SubscriptionRef.make(dataOf(instance)));
|
|
13
|
+
const self = {
|
|
14
|
+
id: instance.id,
|
|
15
|
+
// Outside any Worker or Command, what the Instance Provides Sent it.
|
|
16
|
+
send: (message) => Effect.flatMap(Effect.service(Sending), (source) => Effect.sync(() => host.send(instance.id, message, source ?? { kind: 'provide', instance: instance.id }))),
|
|
17
|
+
get: SubscriptionRef.get(data),
|
|
18
|
+
changes: SubscriptionRef.changes(data),
|
|
19
|
+
now: Effect.sync(host.now),
|
|
20
|
+
};
|
|
21
|
+
const fork = (scope, label, source, effect) => forkIn(host, scope, `${instance.id} ${label}`, Effect.flatMap(Deferred.await(above), (services) => effect.pipe(Effect.provideService(Sending, source), Effect.provideService(Scope.Scope, scope), Effect.provideContext(services))));
|
|
22
|
+
return {
|
|
23
|
+
self,
|
|
24
|
+
set: (next) => Effect.runSyncWith(host.services)(SubscriptionRef.set(data, dataOf(next))),
|
|
25
|
+
fork,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
/** Run an Effect in a Scope, reporting any failure but being stopped. */
|
|
29
|
+
export const forkIn = (host, scope, label, effect) => {
|
|
30
|
+
const fiber = Effect.runSyncWith(host.services)(Effect.forkIn(effect, scope));
|
|
31
|
+
fiber.addObserver((exit) => {
|
|
32
|
+
if (Exit.isFailure(exit) && !stopped(exit.cause))
|
|
33
|
+
console.error(`[@kestack/kabuki] ${label} failed:\n${Cause.pretty(exit.cause)}`);
|
|
34
|
+
});
|
|
35
|
+
return fiber;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Being stopped. In effect 4.0.0 an interrupted Stream of a SubscriptionRef's
|
|
39
|
+
* changes ends in `Done` instead of an interrupt.
|
|
40
|
+
*/
|
|
41
|
+
export const stopped = (cause) => Cause.hasInterruptsOnly(cause) || Pull.isDoneCause(cause);
|
|
42
|
+
export const dataOf = ({ model, state, props, }) => ({ model, state, props });
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Scope } from 'effect';
|
|
2
|
+
import type { Data, Tagged, WorkerDefinition } from '../../actor/index.ts';
|
|
3
|
+
import type { Own } from './self.ts';
|
|
4
|
+
/** What a Worker is doing, live. */
|
|
5
|
+
export interface WorkerStatus {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
/** The key it runs for; `''` for the one Worker of a kind other than `each`. */
|
|
8
|
+
readonly key: string;
|
|
9
|
+
readonly status: 'running' | 'finished' | 'failed';
|
|
10
|
+
}
|
|
11
|
+
export declare const makeWorkers: (definitions: Readonly<Record<string, WorkerDefinition>>, own: Own, scope: Scope.Scope) => {
|
|
12
|
+
/** Start the Workers whose keys appeared, and stop those whose keys went. */
|
|
13
|
+
sync: (data: Data<unknown, Tagged, unknown>) => void;
|
|
14
|
+
statuses: () => ReadonlyArray<WorkerStatus>;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../../src/core/runtime/instance/worker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE3E,OAAO,KAAK,EAAW,GAAG,EAAE,MAAM,WAAW,CAAC;AAS9C,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;CACpD;AAOD,eAAO,MAAM,WAAW,gBACT,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,OAClD,GAAG,SACD,KAAK,CAAC,KAAK;IAsDhB,6EAA6E;IAC7E,IAAI,SAAS,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC;IAa3C,QAAQ,QAAM,aAAa,CAAC,YAAY,CAAC;CAK5C,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Effect, Exit } from 'effect';
|
|
2
|
+
import { stopped } from './self.js';
|
|
3
|
+
export const makeWorkers = (definitions, own, scope) => {
|
|
4
|
+
const running = new Map(Object.keys(definitions).map((name) => [name, new Map()]));
|
|
5
|
+
const start = (name, worker, key) => {
|
|
6
|
+
const label = key === '' ? name : `${name}#${key}`;
|
|
7
|
+
let closing = false;
|
|
8
|
+
let status = 'running';
|
|
9
|
+
const self = {
|
|
10
|
+
...own.self,
|
|
11
|
+
send: (message) => Effect.suspend(() => closing
|
|
12
|
+
? Effect.die(new Error(`[@kestack/kabuki] Worker ${label} of ${own.self.id} sent a Message after it stopped. Finalizers may not send.`))
|
|
13
|
+
: own.self.send(message)),
|
|
14
|
+
};
|
|
15
|
+
const ended = (exit) => Effect.sync(() => {
|
|
16
|
+
closing = true;
|
|
17
|
+
status =
|
|
18
|
+
Exit.isFailure(exit) && !stopped(exit.cause) ? 'failed' : 'finished';
|
|
19
|
+
});
|
|
20
|
+
const fiber = own.fork(scope, `worker ${label}`, {
|
|
21
|
+
kind: 'worker',
|
|
22
|
+
instance: own.self.id,
|
|
23
|
+
name,
|
|
24
|
+
...(key === '' ? {} : { key }),
|
|
25
|
+
}, Effect.scoped(worker.run(self, key).pipe(Effect.onExit(ended))));
|
|
26
|
+
return {
|
|
27
|
+
status: () => status,
|
|
28
|
+
stop: () => {
|
|
29
|
+
closing = true;
|
|
30
|
+
fiber.interruptUnsafe();
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
/** Start the Workers whose keys appeared, and stop those whose keys went. */
|
|
36
|
+
sync: (data) => {
|
|
37
|
+
for (const [name, worker] of Object.entries(definitions)) {
|
|
38
|
+
const wanted = new Set(worker.keys(data));
|
|
39
|
+
const live = running.get(name);
|
|
40
|
+
for (const [key, each] of live)
|
|
41
|
+
if (!wanted.has(key)) {
|
|
42
|
+
each.stop();
|
|
43
|
+
live.delete(key);
|
|
44
|
+
}
|
|
45
|
+
for (const key of wanted)
|
|
46
|
+
if (!live.has(key))
|
|
47
|
+
live.set(key, start(name, worker, key));
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
statuses: () => [...running].flatMap(([name, live]) => [...live].map(([key, each]) => ({ name, key, status: each.status() }))),
|
|
51
|
+
};
|
|
52
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Tagged } from '../actor/index.ts';
|
|
2
|
+
import type { Envelope, Source } from '../snapshot/index.ts';
|
|
3
|
+
export declare const makeMailbox: (now: () => number, deliver: (envelope: Envelope) => void, drained: () => void) => {
|
|
4
|
+
open: () => void;
|
|
5
|
+
close: () => void;
|
|
6
|
+
send: (destination: string, message: Tagged, source: Source) => void;
|
|
7
|
+
/** Run `f` without handling Messages, then handle what it sent. */
|
|
8
|
+
hold: (f: () => void) => void;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=mailbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailbox.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/mailbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAY7D,eAAO,MAAM,WAAW,QACjB,MAAM,MAAM,WACR,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,WAC5B,MAAM,IAAI;IAyBjB,IAAI;IAGJ,KAAK;IAIL,IAAI,gBAAgB,MAAM,WAAW,MAAM,UAAU,MAAM;IAK3D,mEAAmE;IACnE,IAAI,MAAM,MAAM,IAAI;CAWvB,CAAC"}
|