@expressive/mvc 0.73.0 → 0.78.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.
Files changed (53) hide show
  1. package/README.md +137 -0
  2. package/dist/component.d.ts +87 -0
  3. package/dist/component.js +111 -0
  4. package/dist/component.js.map +1 -0
  5. package/dist/context.d.ts +56 -0
  6. package/dist/context.js +201 -0
  7. package/dist/context.js.map +1 -0
  8. package/dist/field/def.d.ts +17 -0
  9. package/dist/field/def.js +29 -0
  10. package/dist/field/def.js.map +1 -0
  11. package/dist/field/get.d.ts +57 -0
  12. package/dist/field/get.js +90 -0
  13. package/dist/field/get.js.map +1 -0
  14. package/dist/field/hot.d.ts +16 -0
  15. package/dist/field/hot.js +98 -0
  16. package/dist/field/hot.js.map +1 -0
  17. package/dist/field/ref.d.ts +78 -0
  18. package/dist/field/ref.js +85 -0
  19. package/dist/field/ref.js.map +1 -0
  20. package/dist/field/set.d.ts +59 -0
  21. package/dist/field/set.js +84 -0
  22. package/dist/field/set.js.map +1 -0
  23. package/dist/index.d.ts +10 -502
  24. package/dist/index.js +11 -872
  25. package/dist/jsx-dev-runtime.d.ts +2 -0
  26. package/dist/jsx-dev-runtime.js +3 -0
  27. package/dist/jsx-runtime.d.ts +90 -0
  28. package/dist/jsx-runtime.js +57 -0
  29. package/dist/jsx-runtime.js.map +1 -0
  30. package/dist/observable.d.ts +58 -0
  31. package/dist/observable.js +184 -0
  32. package/dist/observable.js.map +1 -0
  33. package/dist/state.d.ts +311 -0
  34. package/dist/state.js +424 -0
  35. package/dist/state.js.map +1 -0
  36. package/package.json +35 -18
  37. package/dist/esm/context.d.ts +0 -62
  38. package/dist/esm/context.js +0 -158
  39. package/dist/esm/index.d.ts +0 -8
  40. package/dist/esm/index.js +0 -9
  41. package/dist/esm/instruction/get.d.ts +0 -36
  42. package/dist/esm/instruction/get.js +0 -77
  43. package/dist/esm/instruction/ref.d.ts +0 -71
  44. package/dist/esm/instruction/ref.js +0 -68
  45. package/dist/esm/instruction/set.d.ts +0 -69
  46. package/dist/esm/instruction/set.js +0 -118
  47. package/dist/esm/instruction/use.d.ts +0 -23
  48. package/dist/esm/instruction/use.js +0 -56
  49. package/dist/esm/observable.d.ts +0 -42
  50. package/dist/esm/observable.js +0 -121
  51. package/dist/esm/state.d.ts +0 -234
  52. package/dist/esm/state.js +0 -293
  53. package/dist/index.js.map +0 -1
@@ -0,0 +1,29 @@
1
+ import { listener } from "../observable.js";
2
+ import { STORE, State, apply, uid } from "../state.js";
3
+
4
+ //#region src/field/def.ts
5
+ const APPLY = /* @__PURE__ */ new Map();
6
+ function def(arg1) {
7
+ const token = Symbol("field-" + uid());
8
+ APPLY.set(token, arg1);
9
+ return token;
10
+ }
11
+ State.on((self) => {
12
+ const store = STORE.get(self);
13
+ for (const key in self) {
14
+ const property = Object.getOwnPropertyDescriptor(self, key);
15
+ const instruction = APPLY.get(property.value);
16
+ if (!instruction) continue;
17
+ APPLY.delete(property.value);
18
+ delete self[key];
19
+ const output = instruction.call(self, key, self, store);
20
+ if (!output) continue;
21
+ const desc = typeof output == "function" ? { destroy: output } : output;
22
+ if (desc.destroy) listener(self, desc.destroy, null);
23
+ apply(self, key, desc, true);
24
+ }
25
+ });
26
+
27
+ //#endregion
28
+ export { def };
29
+ //# sourceMappingURL=def.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"def.js","names":[],"sources":["../../src/field/def.ts"],"sourcesContent":["import { listener } from '../observable';\nimport { State, STORE, uid, apply } from '../state';\n\ndeclare namespace def {\n /**\n * Property initializer, will run upon instance creation.\n * Optional returned callback will run when once upon first access.\n */\n type Factory<T = any, M extends State = any> = (\n this: M,\n key: Extract<State.Field<M>, string>,\n thisArg: M,\n state: State.Values<M>\n ) => def.Config<T> | (() => void) | void;\n\n interface Config<T = any> extends State.Apply<T> {\n destroy?: () => void;\n }\n}\n\nconst APPLY = new Map<symbol, def.Factory>();\n\nfunction def<T>(arg1: def.Factory<T>) {\n const token = Symbol('field-' + uid());\n APPLY.set(token, arg1);\n return token as T extends void ? unknown : T;\n}\n\nState.on((self) => {\n const store = STORE.get(self)!;\n\n for (const key in self) {\n const property = Object.getOwnPropertyDescriptor(self, key)!;\n const instruction = APPLY.get(property.value);\n\n if (!instruction) continue;\n\n APPLY.delete(property.value);\n delete (self as any)[key];\n\n const output = instruction.call(self, key, self, store);\n\n if (!output) continue;\n\n const desc = typeof output == 'function' ? { destroy: output } : output;\n\n if (desc.destroy) listener(self, desc.destroy, null);\n\n apply(self, key, desc, true);\n }\n});\n\nexport { def };\n"],"mappings":";;;;AAoBA,MAAM,wBAAQ,IAAI,KAA0B;AAE5C,SAAS,IAAO,MAAsB;CACpC,MAAM,QAAQ,OAAO,WAAW,KAAK,CAAC;AACtC,OAAM,IAAI,OAAO,KAAK;AACtB,QAAO;;AAGT,MAAM,IAAI,SAAS;CACjB,MAAM,QAAQ,MAAM,IAAI,KAAK;AAE7B,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,WAAW,OAAO,yBAAyB,MAAM,IAAI;EAC3D,MAAM,cAAc,MAAM,IAAI,SAAS,MAAM;AAE7C,MAAI,CAAC,YAAa;AAElB,QAAM,OAAO,SAAS,MAAM;AAC5B,SAAQ,KAAa;EAErB,MAAM,SAAS,YAAY,KAAK,MAAM,KAAK,MAAM,MAAM;AAEvD,MAAI,CAAC,OAAQ;EAEb,MAAM,OAAO,OAAO,UAAU,aAAa,EAAE,SAAS,QAAQ,GAAG;AAEjE,MAAI,KAAK,QAAS,UAAS,MAAM,KAAK,SAAS,KAAK;AAEpD,QAAM,MAAM,KAAK,MAAM,KAAK;;EAE9B"}
@@ -0,0 +1,57 @@
1
+ import { State } from "../state.js";
2
+
3
+ //#region src/field/get.d.ts
4
+ declare namespace get {
5
+ type Callback<T = any> = (state: T, subject: State) => void | boolean | (() => void);
6
+ }
7
+ /**
8
+ * Fetches upstream State from context with optional lifecycle callback.
9
+ * Callback runs on mount and can return cleanup function for unmount.
10
+ *
11
+ * @param Type - Type of State to fetch.
12
+ * @param callback - Optional lifecycle callback, receives (state, subject). Can return cleanup function.
13
+ */
14
+ declare function get<T extends State>(Type: State.Extends<T>, callback?: get.Callback<T>): T;
15
+ /**
16
+ * Fetches and assigns the controller which spawned this host.
17
+ * When parent assigns an instance via `use()` directive, it
18
+ * will be made available to child upon this request.
19
+ *
20
+ * @param Type - Type of controller compatible with this class.
21
+ * @param required - If false, property may be undefined. Otherwise will throw.
22
+ */
23
+ declare function get<T extends State>(Type: State.Extends<T>, required: false): T | undefined;
24
+ /**
25
+ * Collects downstream States, accumulating all instances of specified type
26
+ * for which this is an ancestor. Returns an array that updates as States
27
+ * are added or removed. Callback runs on each registration and can return
28
+ * cleanup or false to prevent registration.
29
+ *
30
+ * @param Type - Type of State to collect.
31
+ * @param downstream - Must be true to enable downstream mode.
32
+ * @param callback - Optional lifecycle callback, receives (state, subject). May return false to prevent registration.
33
+ */
34
+ declare function get<T extends State>(Type: State.Extends<T>, downstream: true, callback?: get.Callback<T>): T[];
35
+ /**
36
+ * Fetches a single downstream State of specified type.
37
+ * Updates when a matching child appears or is removed.
38
+ * Throws if not found.
39
+ *
40
+ * @param Type - Type of State to fetch.
41
+ * @param downstream - Must be true to enable downstream mode.
42
+ * @param required - Throw if no match found.
43
+ */
44
+ declare function get<T extends State>(Type: State.Extends<T>, downstream: true, single: true): T;
45
+ /**
46
+ * Fetches a single downstream State of specified type.
47
+ * Updates when a matching child appears or is removed.
48
+ * Returns undefined if not found.
49
+ *
50
+ * @param Type - Type of State to fetch.
51
+ * @param downstream - Must be true to enable downstream mode.
52
+ * @param required - If false, returns undefined if no match found.
53
+ */
54
+ declare function get<T extends State>(Type: State.Extends<T>, downstream: true, required: false): T | undefined;
55
+ //#endregion
56
+ export { get };
57
+ //# sourceMappingURL=get.d.ts.map
@@ -0,0 +1,90 @@
1
+ import { capture } from "../observable.js";
2
+ import { parent, update } from "../state.js";
3
+ import { Context } from "../context.js";
4
+ import { def } from "./def.js";
5
+
6
+ //#region src/field/get.ts
7
+ function get(Type, arg1, arg2) {
8
+ return arg1 === true ? below(Type, arg2) : above(Type, arg1);
9
+ }
10
+ function above(Type, argument) {
11
+ return def((key, subject) => {
12
+ const hasParent = parent(subject);
13
+ const callback = typeof argument === "function" ? argument : void 0;
14
+ function assign(value) {
15
+ if (callback) {
16
+ const result = callback(value, subject);
17
+ if (typeof result === "function") subject.set(null, result);
18
+ }
19
+ update(subject, key, value);
20
+ }
21
+ if (hasParent && hasParent instanceof Type) {
22
+ assign(hasParent);
23
+ return {};
24
+ }
25
+ const ctx = Context.get(subject);
26
+ let found = false;
27
+ ctx.get(Type, (state) => {
28
+ found = true;
29
+ assign(state);
30
+ }, false, subject);
31
+ if (!found && argument !== false) throw new Error(`Required ${Type} not found in context for ${subject}.`);
32
+ return {
33
+ get: argument !== false,
34
+ enumerable: false
35
+ };
36
+ });
37
+ }
38
+ function below(Type, arg) {
39
+ return def((key, subject) => {
40
+ const context = Context.get(subject);
41
+ if (typeof arg == "boolean") {
42
+ context.get(Type, (state) => {
43
+ update(subject, key, state);
44
+ return state.set(null, () => {
45
+ update(subject, key, void 0);
46
+ });
47
+ }, true);
48
+ return {
49
+ get: arg,
50
+ value: void 0,
51
+ enumerable: false
52
+ };
53
+ }
54
+ const applied = /* @__PURE__ */ new Set();
55
+ context.get(Type, (state) => {
56
+ let remove;
57
+ let release;
58
+ if (applied.has(state)) return;
59
+ if (arg) {
60
+ let rejected = false;
61
+ capture((fn) => {
62
+ const done = arg(state, subject);
63
+ if (done === false) rejected = true;
64
+ else if (typeof done == "function") remove = done;
65
+ release = fn;
66
+ });
67
+ if (rejected) return;
68
+ }
69
+ applied.add(state);
70
+ update(subject, key, [...applied]);
71
+ function done() {
72
+ if (release) release();
73
+ ignore();
74
+ applied.delete(state);
75
+ update(subject, key, [...applied]);
76
+ if (typeof remove == "function") remove();
77
+ }
78
+ const ignore = state.set(null, done);
79
+ return done;
80
+ }, true);
81
+ return {
82
+ value: [],
83
+ enumerable: false
84
+ };
85
+ });
86
+ }
87
+
88
+ //#endregion
89
+ export { get };
90
+ //# sourceMappingURL=get.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get.js","names":[],"sources":["../../src/field/get.ts"],"sourcesContent":["import { capture } from '../observable';\nimport { Context } from '../context';\nimport { State, parent, update } from '../state';\nimport { def } from './def';\n\ndeclare namespace get {\n type Callback<T = any> = (\n state: T,\n subject: State\n ) => void | boolean | (() => void);\n}\n\n/**\n * Fetches upstream State from context with optional lifecycle callback.\n * Callback runs on mount and can return cleanup function for unmount.\n *\n * @param Type - Type of State to fetch.\n * @param callback - Optional lifecycle callback, receives (state, subject). Can return cleanup function.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n callback?: get.Callback<T>\n): T;\n\n/**\n * Fetches and assigns the controller which spawned this host.\n * When parent assigns an instance via `use()` directive, it\n * will be made available to child upon this request.\n *\n * @param Type - Type of controller compatible with this class.\n * @param required - If false, property may be undefined. Otherwise will throw.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n required: false\n): T | undefined;\n\n/**\n * Collects downstream States, accumulating all instances of specified type\n * for which this is an ancestor. Returns an array that updates as States\n * are added or removed. Callback runs on each registration and can return\n * cleanup or false to prevent registration.\n *\n * @param Type - Type of State to collect.\n * @param downstream - Must be true to enable downstream mode.\n * @param callback - Optional lifecycle callback, receives (state, subject). May return false to prevent registration.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n downstream: true,\n callback?: get.Callback<T>\n): T[];\n\n/**\n * Fetches a single downstream State of specified type.\n * Updates when a matching child appears or is removed.\n * Throws if not found.\n *\n * @param Type - Type of State to fetch.\n * @param downstream - Must be true to enable downstream mode.\n * @param required - Throw if no match found.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n downstream: true,\n single: true\n): T;\n\n/**\n * Fetches a single downstream State of specified type.\n * Updates when a matching child appears or is removed.\n * Returns undefined if not found.\n *\n * @param Type - Type of State to fetch.\n * @param downstream - Must be true to enable downstream mode.\n * @param required - If false, returns undefined if no match found.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n downstream: true,\n required: false\n): T | undefined;\n\nfunction get<T extends State>(\n Type: State.Extends<T>,\n arg1?: get.Callback<T> | boolean,\n arg2?: get.Callback<T> | boolean\n) {\n return arg1 === true ? below(Type, arg2) : above(Type, arg1);\n}\n\nfunction above<T extends State>(\n Type: State.Extends<T>,\n argument: get.Callback<T> | boolean | undefined\n) {\n return def<T>((key, subject) => {\n const hasParent = parent(subject);\n const callback =\n typeof argument === 'function'\n ? (argument as get.Callback<T>)\n : undefined;\n\n function assign(value: T) {\n if (callback) {\n const result = callback(value, subject);\n if (typeof result === 'function') subject.set(null, result);\n }\n update(subject, key, value);\n }\n\n if (hasParent && hasParent instanceof Type) {\n assign(hasParent as T);\n return {};\n }\n\n const ctx = Context.get(subject);\n let found = false;\n\n ctx.get(Type, (state) => {\n found = true;\n assign(state);\n }, false, subject);\n\n if (!found && argument !== false)\n throw new Error(`Required ${Type} not found in context for ${subject}.`);\n\n return {\n get: argument !== false,\n enumerable: false\n };\n });\n}\n\nfunction below<T extends State>(\n Type: State.Extends<T>,\n arg: get.Callback<T> | boolean | undefined\n) {\n return def<T[]>((key, subject) => {\n const context = Context.get(subject);\n\n if (typeof arg == 'boolean') {\n context.get(\n Type,\n (state) => {\n update(subject, key, state);\n return state.set(null, () => {\n update(subject, key, undefined);\n });\n },\n true\n );\n\n return {\n get: arg,\n value: undefined,\n enumerable: false\n };\n }\n\n const applied = new Set<State>();\n\n context.get(\n Type,\n (state) => {\n let remove: (() => void) | undefined;\n let release: (() => void) | undefined;\n\n if (applied.has(state)) return;\n\n if (arg) {\n let rejected = false;\n\n capture((fn) => {\n const done = arg(state, subject);\n\n if (done === false) rejected = true;\n else if (typeof done == 'function') remove = done;\n\n release = fn;\n });\n\n if (rejected) return;\n }\n\n applied.add(state);\n update(subject, key, [...applied]);\n\n function done() {\n if (release) release();\n ignore();\n\n applied.delete(state);\n update(subject, key, [...applied]);\n\n if (typeof remove == 'function') remove();\n }\n\n const ignore = state.set(null, done);\n\n return done;\n },\n true\n );\n\n return {\n value: [],\n enumerable: false\n };\n });\n}\n\nexport { get };\n"],"mappings":";;;;;;AAmFA,SAAS,IACP,MACA,MACA,MACA;AACA,QAAO,SAAS,OAAO,MAAM,MAAM,KAAK,GAAG,MAAM,MAAM,KAAK;;AAG9D,SAAS,MACP,MACA,UACA;AACA,QAAO,KAAQ,KAAK,YAAY;EAC9B,MAAM,YAAY,OAAO,QAAQ;EACjC,MAAM,WACJ,OAAO,aAAa,aACf,WACD;EAEN,SAAS,OAAO,OAAU;AACxB,OAAI,UAAU;IACZ,MAAM,SAAS,SAAS,OAAO,QAAQ;AACvC,QAAI,OAAO,WAAW,WAAY,SAAQ,IAAI,MAAM,OAAO;;AAE7D,UAAO,SAAS,KAAK,MAAM;;AAG7B,MAAI,aAAa,qBAAqB,MAAM;AAC1C,UAAO,UAAe;AACtB,UAAO,EAAE;;EAGX,MAAM,MAAM,QAAQ,IAAI,QAAQ;EAChC,IAAI,QAAQ;AAEZ,MAAI,IAAI,OAAO,UAAU;AACvB,WAAQ;AACR,UAAO,MAAM;KACZ,OAAO,QAAQ;AAElB,MAAI,CAAC,SAAS,aAAa,MACzB,OAAM,IAAI,MAAM,YAAY,KAAK,4BAA4B,QAAQ,GAAG;AAE1E,SAAO;GACL,KAAK,aAAa;GAClB,YAAY;GACb;GACD;;AAGJ,SAAS,MACP,MACA,KACA;AACA,QAAO,KAAU,KAAK,YAAY;EAChC,MAAM,UAAU,QAAQ,IAAI,QAAQ;AAEpC,MAAI,OAAO,OAAO,WAAW;AAC3B,WAAQ,IACN,OACC,UAAU;AACT,WAAO,SAAS,KAAK,MAAM;AAC3B,WAAO,MAAM,IAAI,YAAY;AAC3B,YAAO,SAAS,KAAK,OAAU;MAC/B;MAEJ,KACD;AAED,UAAO;IACL,KAAK;IACL,OAAO;IACP,YAAY;IACb;;EAGH,MAAM,0BAAU,IAAI,KAAY;AAEhC,UAAQ,IACN,OACC,UAAU;GACT,IAAI;GACJ,IAAI;AAEJ,OAAI,QAAQ,IAAI,MAAM,CAAE;AAExB,OAAI,KAAK;IACP,IAAI,WAAW;AAEf,aAAS,OAAO;KACd,MAAM,OAAO,IAAI,OAAO,QAAQ;AAEhC,SAAI,SAAS,MAAO,YAAW;cACtB,OAAO,QAAQ,WAAY,UAAS;AAE7C,eAAU;MACV;AAEF,QAAI,SAAU;;AAGhB,WAAQ,IAAI,MAAM;AAClB,UAAO,SAAS,KAAK,CAAC,GAAG,QAAQ,CAAC;GAElC,SAAS,OAAO;AACd,QAAI,QAAS,UAAS;AACtB,YAAQ;AAER,YAAQ,OAAO,MAAM;AACrB,WAAO,SAAS,KAAK,CAAC,GAAG,QAAQ,CAAC;AAElC,QAAI,OAAO,UAAU,WAAY,SAAQ;;GAG3C,MAAM,SAAS,MAAM,IAAI,MAAM,KAAK;AAEpC,UAAO;KAET,KACD;AAED,SAAO;GACL,OAAO,EAAE;GACT,YAAY;GACb;GACD"}
@@ -0,0 +1,16 @@
1
+ //#region src/field/hot.d.ts
2
+ /**
3
+ * Wrap an array or object as a reactive Proxy.
4
+ *
5
+ * Reads register subscriptions in active watch contexts; writes fire keyed events.
6
+ * Single-level only - nested objects are not wrapped recursively. Use a child State
7
+ * (or a separate `hot()` call) for nested reactivity.
8
+ *
9
+ * Storage is shared with the input value: external mutation of the original
10
+ * collection bypasses dispatch. Pass a fresh value when this matters.
11
+ */
12
+ declare function hot<T>(value: T[]): T[];
13
+ declare function hot<T extends object>(value: T): T;
14
+ //#endregion
15
+ export { hot };
16
+ //# sourceMappingURL=hot.d.ts.map
@@ -0,0 +1,98 @@
1
+ import { event, touch } from "../observable.js";
2
+
3
+ //#region src/field/hot.ts
4
+ function hot(value) {
5
+ if (typeof value !== "object" || !value) throw new Error("hot() requires an array or object");
6
+ return Array.isArray(value) ? array(value) : object(value);
7
+ }
8
+ const MAX_INDEX = 2 ** 32 - 2;
9
+ const DELETES = new Set([
10
+ "pop",
11
+ "shift",
12
+ "splice"
13
+ ]);
14
+ function array(value) {
15
+ function index(key) {
16
+ const value = typeof key == "symbol" ? -1 : +key;
17
+ return String(value) === key && value >= 0 && value <= MAX_INDEX ? value : -1;
18
+ }
19
+ function deny() {
20
+ throw new Error("hot() arrays must be dense. Use undefined/null placeholders or splice().");
21
+ }
22
+ for (let i = 0; i < value.length; i++) if (!(i in value)) deny();
23
+ const get = () => Object.freeze(value.slice());
24
+ let internal = false;
25
+ const proxy = new Proxy(value, {
26
+ has,
27
+ get(target, key, receiver) {
28
+ if (key === "get") return get;
29
+ const result = Reflect.get(target, key, receiver);
30
+ if (typeof key === "symbol") return result;
31
+ if (typeof result === "function") return DELETES.has(key) ? (...args) => {
32
+ internal = true;
33
+ try {
34
+ return result.apply(receiver, args);
35
+ } finally {
36
+ internal = false;
37
+ }
38
+ } : result;
39
+ return touch(receiver, key, result);
40
+ },
41
+ set(target, key, value) {
42
+ const oldLength = target.length;
43
+ if (key === "length" && value > oldLength) deny();
44
+ const grows = index(key) >= target.length;
45
+ if (grows && index(key) > target.length) deny();
46
+ const ok = assign(proxy, target, key, value);
47
+ if (ok && grows && typeof key !== "symbol") event(proxy, "length");
48
+ if (ok && key === "length") for (let i = target.length; i < oldLength; i++) event(proxy, String(i));
49
+ return ok;
50
+ },
51
+ deleteProperty(target, key) {
52
+ if (!(key in target)) return true;
53
+ if (index(key) >= 0 && !internal) deny();
54
+ return remove(proxy, target, key);
55
+ }
56
+ });
57
+ event(proxy);
58
+ return proxy;
59
+ }
60
+ function object(value) {
61
+ const get = () => Object.freeze({ ...value });
62
+ const proxy = new Proxy(value, {
63
+ has,
64
+ get(target, key, receiver) {
65
+ if (key === "get" && !(key in target)) return get;
66
+ const result = Reflect.get(target, key, receiver);
67
+ if (typeof key === "symbol" || typeof result === "function") return result;
68
+ return touch(receiver, key, result);
69
+ },
70
+ set(target, key, value) {
71
+ return assign(proxy, target, key, value);
72
+ },
73
+ deleteProperty(target, key) {
74
+ return remove(proxy, target, key);
75
+ }
76
+ });
77
+ event(proxy);
78
+ return proxy;
79
+ }
80
+ function has(target, key) {
81
+ return key === "get" || key in target;
82
+ }
83
+ function assign(proxy, target, key, value) {
84
+ const old = target[key];
85
+ const ok = Reflect.set(target, key, value);
86
+ if (ok && typeof key !== "symbol" && old !== value) event(proxy, key);
87
+ return ok;
88
+ }
89
+ function remove(proxy, target, key) {
90
+ if (!(key in target)) return true;
91
+ const ok = Reflect.deleteProperty(target, key);
92
+ if (ok && typeof key !== "symbol") event(proxy, key);
93
+ return ok;
94
+ }
95
+
96
+ //#endregion
97
+ export { hot };
98
+ //# sourceMappingURL=hot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hot.js","names":[],"sources":["../../src/field/hot.ts"],"sourcesContent":["import { event, touch } from '../observable';\n\n/**\n * Wrap an array or object as a reactive Proxy.\n *\n * Reads register subscriptions in active watch contexts; writes fire keyed events.\n * Single-level only - nested objects are not wrapped recursively. Use a child State\n * (or a separate `hot()` call) for nested reactivity.\n *\n * Storage is shared with the input value: external mutation of the original\n * collection bypasses dispatch. Pass a fresh value when this matters.\n */\nfunction hot<T>(value: T[]): T[];\nfunction hot<T extends object>(value: T): T;\nfunction hot(value: any) {\n if (typeof value !== 'object' || !value)\n throw new Error('hot() requires an array or object');\n\n return Array.isArray(value) ? array(value) : object(value);\n}\n\nconst MAX_INDEX = 2 ** 32 - 2;\nconst DELETES = new Set(['pop', 'shift', 'splice']);\n\nfunction array<T>(value: T[]) {\n function index(key: string | symbol) {\n const value = typeof key == 'symbol' ? -1 : +key;\n return String(value) === key && value >= 0 && value <= MAX_INDEX ? value : -1;\n }\n\n function deny() {\n throw new Error(\n 'hot() arrays must be dense. Use undefined/null placeholders or splice().'\n );\n }\n\n for (let i = 0; i < value.length; i++)\n if (!(i in value)) deny();\n\n const get = () => Object.freeze(value.slice());\n let internal = false;\n\n const proxy: any = new Proxy(value, {\n has,\n get(target: T[], key, receiver) {\n if (key === 'get') return get;\n\n const result = Reflect.get(target, key, receiver);\n\n if (typeof key === 'symbol') return result;\n if (typeof result === 'function')\n return DELETES.has(key) ? (...args: unknown[]) => {\n internal = true;\n\n try {\n return result.apply(receiver, args);\n } finally {\n internal = false;\n }\n } : result;\n\n return touch(receiver, key, result);\n },\n set(target: T[], key, value) {\n const oldLength = target.length;\n if (key === 'length' && value > oldLength) deny();\n\n const grows = index(key) >= target.length;\n if (grows && index(key) > target.length) deny();\n\n const ok = assign(proxy, target, key, value);\n if (ok && grows && typeof key !== 'symbol') event(proxy, 'length');\n if (ok && key === 'length')\n for (let i = target.length; i < oldLength; i++) event(proxy, String(i));\n\n return ok;\n },\n deleteProperty(target, key) {\n if (!(key in target)) return true;\n if (index(key) >= 0 && !internal) deny();\n\n return remove(proxy, target, key);\n }\n });\n\n event(proxy);\n return proxy;\n}\n\nfunction object<T extends object>(value: T) {\n const get = () => Object.freeze({ ...value });\n\n const proxy: any = new Proxy(value, {\n has,\n get(target, key, receiver) {\n if (key === 'get' && !(key in target)) return get;\n\n const result = Reflect.get(target, key, receiver);\n\n if (typeof key === 'symbol' || typeof result === 'function')\n return result;\n\n return touch(receiver, key, result);\n },\n set(target, key, value) {\n return assign(proxy, target, key, value);\n },\n deleteProperty(target, key) {\n return remove(proxy, target, key);\n }\n });\n\n event(proxy);\n return proxy;\n}\n\nfunction has(target: object, key: string | symbol) {\n return key === 'get' || key in target;\n}\n\nfunction assign(proxy: object, target: object, key: string | symbol, value: any) {\n const old = (target as any)[key];\n const ok = Reflect.set(target, key, value);\n\n if (ok && typeof key !== 'symbol' && old !== value) event(proxy, key);\n\n return ok;\n}\n\nfunction remove(proxy: object, target: object, key: string | symbol) {\n if (!(key in target)) return true;\n\n const ok = Reflect.deleteProperty(target, key);\n if (ok && typeof key !== 'symbol') event(proxy, key);\n\n return ok;\n}\n\nexport { hot };\n"],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { State } from "../state.js";
2
+
3
+ //#region src/field/ref.d.ts
4
+ declare namespace ref {
5
+ type Map<T extends State, R> = (this: T, key: State.Field<T> & string, state: T) => R;
6
+ type Callback<T> = (argument: T) => ((next: T | null) => void) | Promise<void> | void | boolean;
7
+ /** Callable ref that also exposes ref-object properties. */
8
+ interface Object<T = any> {
9
+ /** Set the current value of this reference. */
10
+ (value: T | null): void;
11
+ /** Current value held by this reference. */
12
+ current: T;
13
+ /** State instance this reference belongs to. */
14
+ is: State;
15
+ /** Key of property on state this reference belongs to. */
16
+ key: string;
17
+ /**
18
+ * Subscribe to changes of this reference.
19
+ *
20
+ * @param callback - Callback to invoke with the current value when it changes.
21
+ * @returns Unsubscribe function to stop listening to changes.
22
+ */
23
+ get(callback: (value: T) => void): () => void;
24
+ /** Retrieve current value. */
25
+ get(): T | null;
26
+ }
27
+ /** Object with references to all managed values of `T`. */
28
+ type Proxy<T extends State> = { [P in State.Field<T>]-?: Object<T[P]> } & {
29
+ get(): T;
30
+ };
31
+ type CustomProxy<T extends State, R> = { [P in State.Field<T>]-?: R } & {
32
+ get(): T;
33
+ };
34
+ }
35
+ /**
36
+ * Creates an object with references to all managed values.
37
+ * Each property is a function to set value in state when invoked.
38
+ *
39
+ * *Properties are simultaneously a ref-function and ref-object, use as needed.*
40
+ *
41
+ * Non-enumerable; excluded from snapshots and `ref(this)`.
42
+ *
43
+ * @param state - Source state from which to reference values.
44
+ */
45
+ declare function ref<T extends State>(state: T): ref.Proxy<T>;
46
+ /**
47
+ * Creates an object with values based on managed values.
48
+ * Each property will invoke map function on first access supply
49
+ * the its return value going forward.
50
+ *
51
+ * Non-enumerable; excluded from snapshots and `ref(this)`.
52
+ *
53
+ * @param state - Source state from which to reference values.
54
+ * @param map - Function producing the placeholder value for any given property.
55
+ */
56
+ declare function ref<T extends State, R>(state: T, map: ref.Map<T, R>): ref.CustomProxy<T, R>;
57
+ /**
58
+ * Creates a ref-compatible property.
59
+ * Callable to set the value, with ref-object properties for reading and subscribing.
60
+ *
61
+ * Non-enumerable; excluded from snapshots and `ref(this)`.
62
+ *
63
+ * @param callback - Optional callback to synchronously fire when reference is first set or does update.
64
+ */
65
+ declare function ref<T>(callback?: ref.Callback<T>): ref.Object<T>;
66
+ /**
67
+ * Creates a ref-compatible property.
68
+ * Callable to set the value, with ref-object properties for reading and subscribing.
69
+ *
70
+ * Non-enumerable; excluded from snapshots and `ref(this)`.
71
+ *
72
+ * @param callback - Optional callback to synchronously fire when reference is first set or does update.
73
+ * @param ignoreNull - Default `true`. If `false`, will still callback with `null`.
74
+ */
75
+ declare function ref<T>(callback: ref.Callback<T | null>, ignoreNull: boolean): ref.Object<T>;
76
+ //#endregion
77
+ export { ref };
78
+ //# sourceMappingURL=ref.d.ts.map
@@ -0,0 +1,85 @@
1
+ import { capture, listener } from "../observable.js";
2
+ import { State, update } from "../state.js";
3
+ import { def } from "./def.js";
4
+
5
+ //#region src/field/ref.ts
6
+ const { defineProperty, defineProperties } = Object;
7
+ function ref(arg, arg2) {
8
+ if (arg instanceof State) return proxy(arg, arg2);
9
+ if (typeof arg == "object") throw new Error("ref instruction requires a State instance, got a plain object");
10
+ return property(arg, arg2);
11
+ }
12
+ function defaultMap(key) {
13
+ const source = this;
14
+ const set = (x) => source[key] = x;
15
+ const get = (cb) => cb ? listener(this, () => cb(source[key]), key) : source[key];
16
+ defineProperties(set, {
17
+ current: {
18
+ get,
19
+ set
20
+ },
21
+ get: { value: get },
22
+ is: { value: this },
23
+ key: { value: key }
24
+ });
25
+ return set;
26
+ }
27
+ function proxy(target, map = defaultMap) {
28
+ return def((_key, _subject) => {
29
+ const value = {};
30
+ const source = target;
31
+ listener(target, () => {
32
+ for (const key in source) defineProperty(value, key, {
33
+ configurable: true,
34
+ get() {
35
+ const out = map.call(target, key, target);
36
+ defineProperty(value, key, { value: out });
37
+ return out;
38
+ }
39
+ });
40
+ return null;
41
+ });
42
+ return {
43
+ get: () => value,
44
+ enumerable: false
45
+ };
46
+ });
47
+ }
48
+ function property(callback, ignoreNull) {
49
+ return def((key, subject, state) => {
50
+ let unset;
51
+ function get(cb) {
52
+ return cb ? listener(subject, () => cb(state[key]), key) : state[key];
53
+ }
54
+ function set(value) {
55
+ if (!update(subject, key, value) || !callback) return;
56
+ if (unset) unset = void unset(value);
57
+ if (value === null && ignoreNull !== false) return;
58
+ capture((release) => {
59
+ const out = callback.call(subject, value);
60
+ unset = (next) => {
61
+ if (typeof out == "function") out(next);
62
+ release();
63
+ };
64
+ });
65
+ }
66
+ state[key] = null;
67
+ defineProperties(set, {
68
+ current: {
69
+ get,
70
+ set
71
+ },
72
+ get: { value: get },
73
+ is: { value: subject },
74
+ key: { value: key }
75
+ });
76
+ return {
77
+ get: () => set,
78
+ enumerable: false
79
+ };
80
+ });
81
+ }
82
+
83
+ //#endregion
84
+ export { ref };
85
+ //# sourceMappingURL=ref.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref.js","names":[],"sources":["../../src/field/ref.ts"],"sourcesContent":["import { listener, capture } from '../observable';\nimport { State, update } from '../state';\nimport { def } from './def';\n\nconst { defineProperty, defineProperties } = Object;\n\ndeclare namespace ref {\n type Map<T extends State, R> = (\n this: T,\n key: State.Field<T> & string,\n state: T\n ) => R;\n\n type Callback<T> = (\n argument: T\n ) => ((next: T | null) => void) | Promise<void> | void | boolean;\n\n /** Callable ref that also exposes ref-object properties. */\n interface Object<T = any> {\n /** Set the current value of this reference. */\n (value: T | null): void;\n\n /** Current value held by this reference. */\n current: T;\n\n /** State instance this reference belongs to. */\n is: State;\n\n /** Key of property on state this reference belongs to. */\n key: string;\n\n /**\n * Subscribe to changes of this reference.\n *\n * @param callback - Callback to invoke with the current value when it changes.\n * @returns Unsubscribe function to stop listening to changes.\n */\n get(callback: (value: T) => void): () => void;\n\n /** Retrieve current value. */\n get(): T | null;\n }\n\n /** Object with references to all managed values of `T`. */\n type Proxy<T extends State> = { [P in State.Field<T>]-?: Object<T[P]> } & {\n get(): T;\n };\n\n type CustomProxy<T extends State, R> = { [P in State.Field<T>]-?: R } & {\n get(): T;\n };\n}\n\n/**\n * Creates an object with references to all managed values.\n * Each property is a function to set value in state when invoked.\n *\n * *Properties are simultaneously a ref-function and ref-object, use as needed.*\n *\n * Non-enumerable; excluded from snapshots and `ref(this)`.\n *\n * @param state - Source state from which to reference values.\n */\nfunction ref<T extends State>(state: T): ref.Proxy<T>;\n\n/**\n * Creates an object with values based on managed values.\n * Each property will invoke map function on first access supply\n * the its return value going forward.\n *\n * Non-enumerable; excluded from snapshots and `ref(this)`.\n *\n * @param state - Source state from which to reference values.\n * @param map - Function producing the placeholder value for any given property.\n */\nfunction ref<T extends State, R>(\n state: T,\n map: ref.Map<T, R>\n): ref.CustomProxy<T, R>;\n\n/**\n * Creates a ref-compatible property.\n * Callable to set the value, with ref-object properties for reading and subscribing.\n *\n * Non-enumerable; excluded from snapshots and `ref(this)`.\n *\n * @param callback - Optional callback to synchronously fire when reference is first set or does update.\n */\nfunction ref<T>(callback?: ref.Callback<T>): ref.Object<T>;\n\n/**\n * Creates a ref-compatible property.\n * Callable to set the value, with ref-object properties for reading and subscribing.\n *\n * Non-enumerable; excluded from snapshots and `ref(this)`.\n *\n * @param callback - Optional callback to synchronously fire when reference is first set or does update.\n * @param ignoreNull - Default `true`. If `false`, will still callback with `null`.\n */\nfunction ref<T>(\n callback: ref.Callback<T | null>,\n ignoreNull: boolean\n): ref.Object<T>;\n\nfunction ref<T extends State>(\n arg?: ref.Callback<T> | T,\n arg2?: ref.Map<T, any> | boolean\n) {\n if (arg instanceof State)\n return proxy(arg, arg2 as ref.Map<T, any> | undefined);\n\n if (typeof arg == 'object')\n throw new Error(\n 'ref instruction requires a State instance, got a plain object'\n );\n\n return property(arg, arg2 as boolean | undefined);\n}\n\nfunction defaultMap(this: State, key: string) {\n const source = this as any as Record<string, any>;\n const set = (x: any) => (source[key] = x);\n const get = (cb?: (value: any) => void) =>\n cb ? listener(this, () => cb(source[key]), key) : source[key];\n\n defineProperties(set, {\n current: { get, set },\n get: { value: get },\n is: { value: this },\n key: { value: key }\n });\n\n return set;\n}\n\nfunction proxy(target: State, map: ref.Map<any, any> = defaultMap) {\n return def((_key, _subject) => {\n const value = {} as Record<string, any>;\n const source = target as any as Record<string, any>;\n\n listener(target, () => {\n for (const key in source)\n defineProperty(value, key, {\n configurable: true,\n get() {\n const out = map.call(target, key, target);\n defineProperty(value, key, { value: out });\n return out;\n }\n });\n\n return null;\n });\n\n return {\n get: () => value,\n enumerable: false\n };\n });\n}\n\nfunction property<T>(callback?: ref.Callback<T>, ignoreNull?: boolean) {\n return def((key, subject, state) => {\n let unset: ((next: T) => void) | undefined;\n\n function get(cb?: (value: T) => void) {\n return cb ? listener(subject, () => cb(state[key]), key) : state[key];\n }\n\n function set(value?: any) {\n if (!update(subject, key, value) || !callback) return;\n if (unset) unset = void unset(value);\n if (value === null && ignoreNull !== false) return;\n\n capture((release) => {\n const out = callback.call(subject, value);\n\n unset = (next) => {\n if (typeof out == 'function') out(next);\n release();\n };\n });\n }\n\n state[key] = null;\n\n defineProperties(set, {\n current: { get, set },\n get: { value: get },\n is: { value: subject },\n key: { value: key }\n });\n\n return {\n get: () => set,\n enumerable: false\n };\n });\n}\n\nexport { ref };\n"],"mappings":";;;;;AAIA,MAAM,EAAE,gBAAgB,qBAAqB;AAoG7C,SAAS,IACP,KACA,MACA;AACA,KAAI,eAAe,MACjB,QAAO,MAAM,KAAK,KAAoC;AAExD,KAAI,OAAO,OAAO,SAChB,OAAM,IAAI,MACR,gEACD;AAEH,QAAO,SAAS,KAAK,KAA4B;;AAGnD,SAAS,WAAwB,KAAa;CAC5C,MAAM,SAAS;CACf,MAAM,OAAO,MAAY,OAAO,OAAO;CACvC,MAAM,OAAO,OACX,KAAK,SAAS,YAAY,GAAG,OAAO,KAAK,EAAE,IAAI,GAAG,OAAO;AAE3D,kBAAiB,KAAK;EACpB,SAAS;GAAE;GAAK;GAAK;EACrB,KAAK,EAAE,OAAO,KAAK;EACnB,IAAI,EAAE,OAAO,MAAM;EACnB,KAAK,EAAE,OAAO,KAAK;EACpB,CAAC;AAEF,QAAO;;AAGT,SAAS,MAAM,QAAe,MAAyB,YAAY;AACjE,QAAO,KAAK,MAAM,aAAa;EAC7B,MAAM,QAAQ,EAAE;EAChB,MAAM,SAAS;AAEf,WAAS,cAAc;AACrB,QAAK,MAAM,OAAO,OAChB,gBAAe,OAAO,KAAK;IACzB,cAAc;IACd,MAAM;KACJ,MAAM,MAAM,IAAI,KAAK,QAAQ,KAAK,OAAO;AACzC,oBAAe,OAAO,KAAK,EAAE,OAAO,KAAK,CAAC;AAC1C,YAAO;;IAEV,CAAC;AAEJ,UAAO;IACP;AAEF,SAAO;GACL,WAAW;GACX,YAAY;GACb;GACD;;AAGJ,SAAS,SAAY,UAA4B,YAAsB;AACrE,QAAO,KAAK,KAAK,SAAS,UAAU;EAClC,IAAI;EAEJ,SAAS,IAAI,IAAyB;AACpC,UAAO,KAAK,SAAS,eAAe,GAAG,MAAM,KAAK,EAAE,IAAI,GAAG,MAAM;;EAGnE,SAAS,IAAI,OAAa;AACxB,OAAI,CAAC,OAAO,SAAS,KAAK,MAAM,IAAI,CAAC,SAAU;AAC/C,OAAI,MAAO,SAAQ,KAAK,MAAM,MAAM;AACpC,OAAI,UAAU,QAAQ,eAAe,MAAO;AAE5C,YAAS,YAAY;IACnB,MAAM,MAAM,SAAS,KAAK,SAAS,MAAM;AAEzC,aAAS,SAAS;AAChB,SAAI,OAAO,OAAO,WAAY,KAAI,KAAK;AACvC,cAAS;;KAEX;;AAGJ,QAAM,OAAO;AAEb,mBAAiB,KAAK;GACpB,SAAS;IAAE;IAAK;IAAK;GACrB,KAAK,EAAE,OAAO,KAAK;GACnB,IAAI,EAAE,OAAO,SAAS;GACtB,KAAK,EAAE,OAAO,KAAK;GACpB,CAAC;AAEF,SAAO;GACL,WAAW;GACX,YAAY;GACb;GACD"}
@@ -0,0 +1,59 @@
1
+ //#region src/field/set.d.ts
2
+ declare namespace set {
3
+ type Callback<T, S = any> = (this: S, next: T, previous: T) => ((next: T) => void) | Promise<any> | void | boolean;
4
+ type Factory<T, S = any> = (this: S, property: string) => Promise<T> | T;
5
+ }
6
+ /**
7
+ * Set a property as a placeholder, initially `undefined` but required.
8
+ *
9
+ * Property cannot be accessed until it is defined. If accessed while undefined, a hybrid
10
+ * `Promise`/`Error` (aka: [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html)) will be thrown.
11
+ *
12
+ * Non-enumerable; writable only if `onUpdate` callback is provided.
13
+ *
14
+ * @param value - Starting value (undefined for suspense placeholder).
15
+ * @param onUpdate - Callback run when property is set.
16
+ */
17
+ declare function set<T>(value?: undefined, onUpdate?: set.Callback<T>): T;
18
+ /**
19
+ * Set property with an async factory function.
20
+ * If required is not defined, factory runs lazily on first access.
21
+ * If async, or returns a promise, suspense is thrown upon access until resolved.
22
+ *
23
+ * Non-enumerable and read-only.
24
+ *
25
+ * @param factory - Zero-arg async callback to produce property value.
26
+ * @param required - Pass `true` to run factory immediately and require value.
27
+ */
28
+ declare function set<T>(factory: () => T | Promise<T>, required?: true): T;
29
+ /**
30
+ * Set property with a lazy factory, no suspense.
31
+ *
32
+ * Non-enumerable and read-only.
33
+ *
34
+ * @param factory - Zero-arg callback to produce property value.
35
+ * @param required - Pass `false` to allow undefined while pending.
36
+ */
37
+ declare function set<T>(factory: () => T | Promise<T>, required: boolean): T | undefined;
38
+ /**
39
+ * Set property with a factory and update callback.
40
+ *
41
+ * Non-enumerable but writable via the callback.
42
+ *
43
+ * @param factory - Callback to produce initial value.
44
+ * @param onUpdate - Callback run when property is updated.
45
+ */
46
+ declare function set<T>(factory: () => T | Promise<T>, onUpdate: set.Callback<T>): T;
47
+ /**
48
+ * Set a property with a non-function, non-Promise value.
49
+ *
50
+ * Non-enumerable but writable. Unlike plain assignment (`= value`), this
51
+ * property is excluded from snapshots and `ref(this)`.
52
+ *
53
+ * @param value - Starting value for property.
54
+ * @param onUpdate - Optional callback run when property is set.
55
+ */
56
+ declare function set<T>(value: T extends Promise<any> ? never : T, onUpdate?: set.Callback<T>): T;
57
+ //#endregion
58
+ export { set };
59
+ //# sourceMappingURL=set.d.ts.map
@@ -0,0 +1,84 @@
1
+ import { capture, event, listener } from "../observable.js";
2
+ import { access, update } from "../state.js";
3
+ import { def } from "./def.js";
4
+
5
+ //#region src/field/set.ts
6
+ function set(value, argument) {
7
+ return def((key, subject) => {
8
+ if (value instanceof Promise) throw new TypeError(`Direct promises are not supported in set(${subject}.${key}). Use set(() => promise) instead.`);
9
+ const config = {
10
+ enumerable: false,
11
+ set: false
12
+ };
13
+ let computed = false;
14
+ if (typeof value == "function") {
15
+ const factory = value.bind(subject, key);
16
+ computed = true;
17
+ function init() {
18
+ let output;
19
+ try {
20
+ output = attempt(factory);
21
+ } catch (err) {
22
+ console.warn(`Generating initial value for ${subject}.${key} failed.`);
23
+ throw err;
24
+ }
25
+ config.get = argument !== false;
26
+ function assign(next, silent) {
27
+ if (typeof argument == "function") subject[key] = next;
28
+ else update(subject, key, next, silent);
29
+ }
30
+ if (output instanceof Promise) output.then(assign, (error) => {
31
+ event(subject, key);
32
+ config.get = () => {
33
+ throw error;
34
+ };
35
+ });
36
+ else assign(output, true);
37
+ if (argument) return null;
38
+ if (output instanceof Promise && argument !== false) return access(subject, key, true);
39
+ return subject[key];
40
+ }
41
+ if (argument) listener(subject, () => {
42
+ init();
43
+ return null;
44
+ });
45
+ else config.get = init;
46
+ } else if (value !== void 0) config.value = value;
47
+ if (typeof argument == "function") {
48
+ let unset;
49
+ config.set = function(value, previous) {
50
+ capture((release) => {
51
+ const returns = argument.call(this, value, previous);
52
+ if (unset) unset(value);
53
+ unset = (next) => {
54
+ if (typeof returns == "function") returns(next);
55
+ release();
56
+ };
57
+ });
58
+ };
59
+ } else if (!computed) config.set = () => {
60
+ config.get = void 0;
61
+ config.set = void 0;
62
+ };
63
+ return config;
64
+ });
65
+ }
66
+ function attempt(fn) {
67
+ function retry(err) {
68
+ if (err instanceof Promise) return err.then(compute);
69
+ else throw err;
70
+ }
71
+ function compute() {
72
+ try {
73
+ const output = fn();
74
+ return output instanceof Promise ? output.catch(retry) : output;
75
+ } catch (err) {
76
+ return retry(err);
77
+ }
78
+ }
79
+ return compute();
80
+ }
81
+
82
+ //#endregion
83
+ export { set };
84
+ //# sourceMappingURL=set.js.map