@graphrefly/graphrefly 0.47.0 → 0.47.2
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/dist/base/composition/index.cjs +24 -16
- package/dist/base/composition/index.cjs.map +1 -1
- package/dist/base/composition/index.js +6 -6
- package/dist/base/index.cjs +142 -86
- package/dist/base/index.cjs.map +1 -1
- package/dist/base/index.js +11 -11
- package/dist/base/io/index.cjs +114 -68
- package/dist/base/io/index.cjs.map +1 -1
- package/dist/base/io/index.js +5 -5
- package/dist/base/sources/browser/index.cjs +13 -9
- package/dist/base/sources/browser/index.cjs.map +1 -1
- package/dist/base/sources/browser/index.js +13 -9
- package/dist/base/sources/browser/index.js.map +1 -1
- package/dist/base/sources/event/index.cjs +1 -1
- package/dist/base/sources/event/index.cjs.map +1 -1
- package/dist/base/sources/event/index.js +1 -1
- package/dist/base/sources/index.cjs +21 -13
- package/dist/base/sources/index.cjs.map +1 -1
- package/dist/base/sources/index.js +3 -3
- package/dist/base/sources/node/index.cjs +43 -37
- package/dist/base/sources/node/index.cjs.map +1 -1
- package/dist/base/sources/node/index.js +43 -37
- package/dist/base/sources/node/index.js.map +1 -1
- package/dist/{chunk-VLAGJZSL.js → chunk-3O3NKZJW.js} +2 -2
- package/dist/{chunk-YJ4U2D2C.js → chunk-446I4EGD.js} +9 -7
- package/dist/chunk-446I4EGD.js.map +1 -0
- package/dist/{chunk-DKNHAICT.js → chunk-5GVURVIG.js} +14 -8
- package/dist/chunk-5GVURVIG.js.map +1 -0
- package/dist/{chunk-2OB3CEJS.js → chunk-6MRSX3YK.js} +2 -2
- package/dist/{chunk-EVYY4X5A.js → chunk-6ZLCPUXS.js} +2 -2
- package/dist/{chunk-ZVXXDWIB.js → chunk-7AVQIGF6.js} +514 -33
- package/dist/chunk-7AVQIGF6.js.map +1 -0
- package/dist/{chunk-7EGRP2VX.js → chunk-7BULJTL6.js} +2 -2
- package/dist/{chunk-7EGRP2VX.js.map → chunk-7BULJTL6.js.map} +1 -1
- package/dist/{chunk-FW23JYNQ.js → chunk-CEVNQ74M.js} +2 -2
- package/dist/{chunk-CGHORL6G.js → chunk-DDTS7F5O.js} +7 -5
- package/dist/chunk-DDTS7F5O.js.map +1 -0
- package/dist/{chunk-OCUDSN63.js → chunk-EL5VHUGK.js} +79 -47
- package/dist/chunk-EL5VHUGK.js.map +1 -0
- package/dist/{chunk-4GYMCUDZ.js → chunk-EP4WVQLX.js} +5 -5
- package/dist/{chunk-SOOKUYVM.js → chunk-F7EKHR32.js} +13 -9
- package/dist/chunk-F7EKHR32.js.map +1 -0
- package/dist/{chunk-JKTC747G.js → chunk-FQSQONOU.js} +4 -4
- package/dist/{chunk-JGFRAFDL.js → chunk-FVINAAKA.js} +3 -3
- package/dist/{chunk-RAGGHLCV.js → chunk-GUNIRPEJ.js} +8 -6
- package/dist/{chunk-RAGGHLCV.js.map → chunk-GUNIRPEJ.js.map} +1 -1
- package/dist/{chunk-BU3SEFA5.js → chunk-IOJDYUA7.js} +2 -2
- package/dist/{chunk-Y52CS6YA.js → chunk-JA67ZQG2.js} +2 -2
- package/dist/{chunk-Y52CS6YA.js.map → chunk-JA67ZQG2.js.map} +1 -1
- package/dist/{chunk-DM4OMPWK.js → chunk-KNU73RZW.js} +2 -2
- package/dist/{chunk-GWRNLJNW.js → chunk-KRFGO5QH.js} +19 -15
- package/dist/{chunk-GWRNLJNW.js.map → chunk-KRFGO5QH.js.map} +1 -1
- package/dist/{chunk-Z4YXAUDN.js → chunk-KUFXLAEY.js} +11 -7
- package/dist/{chunk-Z4YXAUDN.js.map → chunk-KUFXLAEY.js.map} +1 -1
- package/dist/{chunk-Z6EGP5D7.js → chunk-LDCSZ72P.js} +2 -2
- package/dist/{chunk-5IMMNARC.js → chunk-MS3WPRJR.js} +37 -25
- package/dist/chunk-MS3WPRJR.js.map +1 -0
- package/dist/{chunk-CXANAIZU.js → chunk-N65E26UL.js} +3 -3
- package/dist/{chunk-O3MT7DYI.js → chunk-N6MNJNHB.js} +2 -2
- package/dist/{chunk-Q3EYOCZB.js → chunk-NPRP3MCV.js} +111 -2
- package/dist/chunk-NPRP3MCV.js.map +1 -0
- package/dist/{chunk-A7KV5UK4.js → chunk-OXD5LFQP.js} +2 -2
- package/dist/{chunk-ZT4WMQW4.js → chunk-PTWADEH3.js} +9 -7
- package/dist/chunk-PTWADEH3.js.map +1 -0
- package/dist/{chunk-IHTWQEDR.js → chunk-QFE5BQH7.js} +2 -2
- package/dist/{chunk-IHTWQEDR.js.map → chunk-QFE5BQH7.js.map} +1 -1
- package/dist/{chunk-22SG74BD.js → chunk-R6ZCSXKX.js} +3 -3
- package/dist/{chunk-PZWISPIQ.js → chunk-S7HN5FHL.js} +17 -11
- package/dist/chunk-S7HN5FHL.js.map +1 -0
- package/dist/{chunk-RJOG4IJU.js → chunk-T7SP3EYR.js} +18 -12
- package/dist/chunk-T7SP3EYR.js.map +1 -0
- package/dist/{chunk-4S53H2KR.js → chunk-VAZXUK6G.js} +2 -2
- package/dist/{chunk-IJRR6YAI.js → chunk-VLDRAMP7.js} +18 -12
- package/dist/chunk-VLDRAMP7.js.map +1 -0
- package/dist/{chunk-TNX5ZGDJ.js → chunk-VNXAF2KE.js} +4 -4
- package/dist/{chunk-EHRRQ4IC.js → chunk-VP3TIUDF.js} +2 -2
- package/dist/{chunk-6XZYT4SW.js → chunk-WGDEBIP4.js} +5 -5
- package/dist/{chunk-E5OZPDIW.js → chunk-X7BA5PWG.js} +7 -5
- package/dist/chunk-X7BA5PWG.js.map +1 -0
- package/dist/compat/index.cjs +1 -1
- package/dist/compat/index.cjs.map +1 -1
- package/dist/compat/index.js +2 -2
- package/dist/compat/nestjs/index.cjs +1 -1
- package/dist/compat/nestjs/index.cjs.map +1 -1
- package/dist/compat/nestjs/index.js +2 -2
- package/dist/index.cjs +1657 -982
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +58 -36
- package/dist/index.js.map +1 -1
- package/dist/presets/ai/index.cjs +42 -26
- package/dist/presets/ai/index.cjs.map +1 -1
- package/dist/presets/ai/index.js +11 -11
- package/dist/presets/harness/index.cjs +53 -33
- package/dist/presets/harness/index.cjs.map +1 -1
- package/dist/presets/harness/index.js +22 -22
- package/dist/presets/index.cjs +76 -48
- package/dist/presets/index.cjs.map +1 -1
- package/dist/presets/index.js +28 -28
- package/dist/presets/inspect/index.cjs.map +1 -1
- package/dist/presets/inspect/index.js +4 -4
- package/dist/presets/resilience/index.cjs +35 -23
- package/dist/presets/resilience/index.cjs.map +1 -1
- package/dist/presets/resilience/index.js +5 -5
- package/dist/solutions/index.cjs +71 -45
- package/dist/solutions/index.cjs.map +1 -1
- package/dist/solutions/index.js +24 -24
- package/dist/{timeout-U5O4ESK3.js → timeout-BEABACRP.js} +2 -2
- package/dist/utils/ai/browser.cjs.map +1 -1
- package/dist/utils/ai/browser.js +9 -9
- package/dist/utils/ai/index.cjs +41 -25
- package/dist/utils/ai/index.cjs.map +1 -1
- package/dist/utils/ai/index.js +18 -18
- package/dist/utils/ai/node.js +3 -3
- package/dist/utils/domain-templates/index.cjs +1 -1
- package/dist/utils/domain-templates/index.cjs.map +1 -1
- package/dist/utils/domain-templates/index.js +2 -2
- package/dist/utils/graphspec/index.cjs +1 -1
- package/dist/utils/graphspec/index.cjs.map +1 -1
- package/dist/utils/graphspec/index.js +2 -2
- package/dist/utils/harness/index.cjs +16 -10
- package/dist/utils/harness/index.cjs.map +1 -1
- package/dist/utils/harness/index.js +1 -1
- package/dist/utils/index.cjs +1069 -452
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.cts +2 -2
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +45 -23
- package/dist/utils/inspect/index.cjs.map +1 -1
- package/dist/utils/inspect/index.js +2 -2
- package/dist/utils/memory/index.cjs +513 -37
- package/dist/utils/memory/index.cjs.map +1 -1
- package/dist/utils/memory/index.d.cts +641 -3
- package/dist/utils/memory/index.d.ts +641 -3
- package/dist/utils/memory/index.js +19 -1
- package/dist/utils/messaging/index.cjs +109 -0
- package/dist/utils/messaging/index.cjs.map +1 -1
- package/dist/utils/messaging/index.d.cts +115 -2
- package/dist/utils/messaging/index.d.ts +115 -2
- package/dist/utils/messaging/index.js +5 -1
- package/dist/utils/orchestration/index.cjs +5 -3
- package/dist/utils/orchestration/index.cjs.map +1 -1
- package/dist/utils/orchestration/index.js +2 -2
- package/dist/utils/process/index.js +2 -2
- package/dist/utils/reduction/index.cjs +1 -1
- package/dist/utils/reduction/index.cjs.map +1 -1
- package/dist/utils/reduction/index.js +1 -1
- package/dist/utils/resilience/index.cjs +35 -23
- package/dist/utils/resilience/index.cjs.map +1 -1
- package/dist/utils/resilience/index.js +4 -4
- package/dist/utils/surface/index.cjs +1 -1
- package/dist/utils/surface/index.cjs.map +1 -1
- package/dist/utils/surface/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-5IMMNARC.js.map +0 -1
- package/dist/chunk-CGHORL6G.js.map +0 -1
- package/dist/chunk-DKNHAICT.js.map +0 -1
- package/dist/chunk-E5OZPDIW.js.map +0 -1
- package/dist/chunk-IJRR6YAI.js.map +0 -1
- package/dist/chunk-OCUDSN63.js.map +0 -1
- package/dist/chunk-PZWISPIQ.js.map +0 -1
- package/dist/chunk-Q3EYOCZB.js.map +0 -1
- package/dist/chunk-RJOG4IJU.js.map +0 -1
- package/dist/chunk-SOOKUYVM.js.map +0 -1
- package/dist/chunk-YJ4U2D2C.js.map +0 -1
- package/dist/chunk-ZT4WMQW4.js.map +0 -1
- package/dist/chunk-ZVXXDWIB.js.map +0 -1
- /package/dist/{chunk-VLAGJZSL.js.map → chunk-3O3NKZJW.js.map} +0 -0
- /package/dist/{chunk-2OB3CEJS.js.map → chunk-6MRSX3YK.js.map} +0 -0
- /package/dist/{chunk-EVYY4X5A.js.map → chunk-6ZLCPUXS.js.map} +0 -0
- /package/dist/{chunk-FW23JYNQ.js.map → chunk-CEVNQ74M.js.map} +0 -0
- /package/dist/{chunk-4GYMCUDZ.js.map → chunk-EP4WVQLX.js.map} +0 -0
- /package/dist/{chunk-JKTC747G.js.map → chunk-FQSQONOU.js.map} +0 -0
- /package/dist/{chunk-JGFRAFDL.js.map → chunk-FVINAAKA.js.map} +0 -0
- /package/dist/{chunk-BU3SEFA5.js.map → chunk-IOJDYUA7.js.map} +0 -0
- /package/dist/{chunk-DM4OMPWK.js.map → chunk-KNU73RZW.js.map} +0 -0
- /package/dist/{chunk-Z6EGP5D7.js.map → chunk-LDCSZ72P.js.map} +0 -0
- /package/dist/{chunk-CXANAIZU.js.map → chunk-N65E26UL.js.map} +0 -0
- /package/dist/{chunk-O3MT7DYI.js.map → chunk-N6MNJNHB.js.map} +0 -0
- /package/dist/{chunk-A7KV5UK4.js.map → chunk-OXD5LFQP.js.map} +0 -0
- /package/dist/{chunk-22SG74BD.js.map → chunk-R6ZCSXKX.js.map} +0 -0
- /package/dist/{chunk-4S53H2KR.js.map → chunk-VAZXUK6G.js.map} +0 -0
- /package/dist/{chunk-TNX5ZGDJ.js.map → chunk-VNXAF2KE.js.map} +0 -0
- /package/dist/{chunk-EHRRQ4IC.js.map → chunk-VP3TIUDF.js.map} +0 -0
- /package/dist/{chunk-6XZYT4SW.js.map → chunk-WGDEBIP4.js.map} +0 -0
- /package/dist/{timeout-U5O4ESK3.js.map → timeout-BEABACRP.js.map} +0 -0
package/dist/base/io/index.js
CHANGED
|
@@ -46,19 +46,19 @@ import {
|
|
|
46
46
|
toSqlite,
|
|
47
47
|
toTempo,
|
|
48
48
|
toWebSocket
|
|
49
|
-
} from "../../chunk-
|
|
49
|
+
} from "../../chunk-EL5VHUGK.js";
|
|
50
50
|
import {
|
|
51
51
|
fromSSE,
|
|
52
52
|
parseSSEStream,
|
|
53
53
|
toReadableStream,
|
|
54
54
|
toSSE,
|
|
55
55
|
toSSEBytes
|
|
56
|
-
} from "../../chunk-
|
|
57
|
-
import "../../chunk-
|
|
58
|
-
import "../../chunk-
|
|
56
|
+
} from "../../chunk-F7EKHR32.js";
|
|
57
|
+
import "../../chunk-JA67ZQG2.js";
|
|
58
|
+
import "../../chunk-KUFXLAEY.js";
|
|
59
59
|
import "../../chunk-TSBFTJKM.js";
|
|
60
60
|
import "../../chunk-P5LBT622.js";
|
|
61
|
-
import "../../chunk-
|
|
61
|
+
import "../../chunk-VLDRAMP7.js";
|
|
62
62
|
import "../../chunk-AZDQPQ3V.js";
|
|
63
63
|
export {
|
|
64
64
|
checkpointToRedis,
|
|
@@ -86,7 +86,7 @@ function fromRaf(opts) {
|
|
|
86
86
|
};
|
|
87
87
|
if (signal?.aborted) {
|
|
88
88
|
onAbort();
|
|
89
|
-
return
|
|
89
|
+
return;
|
|
90
90
|
}
|
|
91
91
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
92
92
|
abortListenerAdded = signal !== void 0;
|
|
@@ -95,7 +95,7 @@ function fromRaf(opts) {
|
|
|
95
95
|
visibilityListenerAdded = true;
|
|
96
96
|
}
|
|
97
97
|
scheduleNext();
|
|
98
|
-
return cleanup;
|
|
98
|
+
return { onDeactivation: cleanup };
|
|
99
99
|
}, sourceOpts(rest));
|
|
100
100
|
}
|
|
101
101
|
function fromEvent(target, type, opts) {
|
|
@@ -106,7 +106,7 @@ function fromEvent(target, type, opts) {
|
|
|
106
106
|
};
|
|
107
107
|
const options = { capture, passive, once };
|
|
108
108
|
target.addEventListener(type, handler, options);
|
|
109
|
-
return () => target.removeEventListener(type, handler, options);
|
|
109
|
+
return { onDeactivation: () => target.removeEventListener(type, handler, options) };
|
|
110
110
|
}, sourceOpts(rest));
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -131,9 +131,11 @@ function fromIDBRequest(req) {
|
|
|
131
131
|
clear();
|
|
132
132
|
a.down([[import_core2.ERROR, req.error ?? new Error("IndexedDB request failed")]]);
|
|
133
133
|
};
|
|
134
|
-
return
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
return {
|
|
135
|
+
onDeactivation: () => {
|
|
136
|
+
done = true;
|
|
137
|
+
clear();
|
|
138
|
+
}
|
|
137
139
|
};
|
|
138
140
|
});
|
|
139
141
|
}
|
|
@@ -163,9 +165,11 @@ function fromIDBTransaction(tx) {
|
|
|
163
165
|
clear();
|
|
164
166
|
a.down([[import_core2.ERROR, tx.error ?? new Error("IndexedDB transaction aborted")]]);
|
|
165
167
|
};
|
|
166
|
-
return
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
return {
|
|
169
|
+
onDeactivation: () => {
|
|
170
|
+
done = true;
|
|
171
|
+
clear();
|
|
172
|
+
}
|
|
169
173
|
};
|
|
170
174
|
});
|
|
171
175
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/base/sources/browser/index.ts","../../../../src/base/sources/event/dom.ts","../../../../src/base/sources/browser/idb.ts"],"sourcesContent":["/**\n * Browser-only sources — IDB (IndexedDB) reactive adapters, DOM events.\n *\n * All entries in this subpath may use DOM globals.\n * Import via @graphrefly/graphrefly/base/sources/browser.\n *\n * @module\n */\n\nexport * from \"../event/dom.js\";\nexport * from \"./idb.js\";\n","/**\n * DOM-based reactive event sources (browser-layer).\n *\n * Moved from extra/sources/event.ts (fromEvent, fromRaf) during cleave A2.\n */\n\nimport { ERROR, type Node, type NodeOptions, node } from \"@graphrefly/pure-ts/core\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\ntype AsyncSourceOpts = ExtraOpts & { signal?: AbortSignal };\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\n/** DOM-style event target (browser or `node:events`). */\nexport type EventTargetLike = {\n\taddEventListener(\n\t\ttype: string,\n\t\tlistener: (ev: unknown) => void,\n\t\toptions?: boolean | { capture?: boolean; passive?: boolean; once?: boolean },\n\t): void;\n\tremoveEventListener(\n\t\ttype: string,\n\t\tlistener: (ev: unknown) => void,\n\t\toptions?: boolean | { capture?: boolean; passive?: boolean; once?: boolean },\n\t): void;\n};\n\nexport function fromRaf(opts?: AsyncSourceOpts): Node<number> {\n\tconst { signal, ...rest } = opts ?? {};\n\treturn node<number>((_data, a) => {\n\t\tlet done = false;\n\t\tlet rafId: number | undefined;\n\t\tlet fallbackTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tlet abortListenerAdded = false;\n\t\tlet visibilityListenerAdded = false;\n\n\t\tconst raf: typeof requestAnimationFrame | undefined =\n\t\t\ttypeof requestAnimationFrame === \"function\" ? requestAnimationFrame : undefined;\n\t\tconst caf: typeof cancelAnimationFrame | undefined =\n\t\t\ttypeof cancelAnimationFrame === \"function\" ? cancelAnimationFrame : undefined;\n\t\tconst doc: Document | undefined = typeof document !== \"undefined\" ? document : undefined;\n\n\t\tconst clearPending = () => {\n\t\t\tif (rafId !== undefined && caf) caf(rafId);\n\t\t\tif (fallbackTimer !== undefined) clearTimeout(fallbackTimer);\n\t\t\trafId = undefined;\n\t\t\tfallbackTimer = undefined;\n\t\t};\n\t\tconst cleanup = () => {\n\t\t\tdone = true;\n\t\t\tclearPending();\n\t\t\tif (abortListenerAdded) {\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\tabortListenerAdded = false;\n\t\t\t}\n\t\t\tif (visibilityListenerAdded && doc) {\n\t\t\t\tdoc.removeEventListener(\"visibilitychange\", onVisibilityChange);\n\t\t\t\tvisibilityListenerAdded = false;\n\t\t\t}\n\t\t};\n\t\tconst onAbort = () => {\n\t\t\tif (done) return;\n\t\t\tcleanup();\n\t\t\ta.down([[ERROR, signal!.reason]]);\n\t\t};\n\t\tconst tick = (now: number) => {\n\t\t\tif (done) return;\n\t\t\ta.emit(now);\n\t\t\tscheduleNext();\n\t\t};\n\t\tconst scheduleNext = () => {\n\t\t\tif (done) return;\n\t\t\t// Prefer rAF for display-synced ticks when the tab is visible; when\n\t\t\t// hidden, rAF is throttled to ~0 by the browser, so fall back to\n\t\t\t// setTimeout so downstream state continues updating.\n\t\t\tif (raf && (!doc || doc.visibilityState !== \"hidden\")) {\n\t\t\t\trafId = raf(tick);\n\t\t\t} else {\n\t\t\t\tfallbackTimer = setTimeout(() => tick(performance.now()), 16);\n\t\t\t}\n\t\t};\n\t\tconst onVisibilityChange = () => {\n\t\t\tif (done) return;\n\t\t\t// Cancel any pending schedule and re-schedule via the path now\n\t\t\t// appropriate for the current visibility state.\n\t\t\tclearPending();\n\t\t\tscheduleNext();\n\t\t};\n\n\t\tif (signal?.aborted) {\n\t\t\tonAbort();\n\t\t\treturn cleanup;\n\t\t}\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tabortListenerAdded = signal !== undefined;\n\t\tif (doc && raf) {\n\t\t\tdoc.addEventListener(\"visibilitychange\", onVisibilityChange);\n\t\t\tvisibilityListenerAdded = true;\n\t\t}\n\t\tscheduleNext();\n\t\treturn cleanup;\n\t}, sourceOpts(rest));\n}\n\n/**\n * Wraps a DOM-style `addEventListener` target; each event becomes a `DATA` emission.\n *\n * @param target - Object with `addEventListener` / `removeEventListener`.\n * @param type - Event name (e.g. `\"click\"`).\n * @param opts - Producer options plus listener options (`capture`, `passive`, `once`).\n * @returns `Node<T>` — event payloads; teardown removes the listener.\n *\n * @example\n * ```ts\n * import { fromEvent } from \"@graphrefly/graphrefly-ts\";\n *\n * fromEvent(document.body, \"click\");\n * ```\n *\n * @category extra\n */\nexport function fromEvent<T = unknown>(\n\ttarget: EventTargetLike,\n\ttype: string,\n\topts?: ExtraOpts & { capture?: boolean; passive?: boolean; once?: boolean },\n): Node<T> {\n\tconst { capture, passive, once, ...rest } = opts ?? {};\n\treturn node<T>((_data, a) => {\n\t\tconst handler = (e: unknown) => {\n\t\t\ta.emit(e as T);\n\t\t};\n\t\tconst options = { capture, passive, once };\n\t\ttarget.addEventListener(type, handler, options);\n\t\treturn () => target.removeEventListener(type, handler, options);\n\t}, sourceOpts(rest));\n}\n","/**\n * Browser-only IndexedDB reactive sources.\n *\n * `fromIDBRequest` / `fromIDBTransaction` wrap raw IDB primitives as reactive\n * sources. The old `indexedDbStorage` kv adapter has been replaced by\n * `indexedDbKv` in `./storage-tiers-browser.js` (Audit 4, 2026-04-24).\n *\n * Imports require the DOM lib — not safe to pull into Node-only bundles\n * without `lib: [\"dom\"]` in the consumer's tsconfig.\n *\n * @module\n */\n/// <reference lib=\"dom\" />\n\nimport { COMPLETE, DATA, ERROR, type Node, node } from \"@graphrefly/pure-ts/core\";\n\n// IndexedDbStorageSpec is no longer needed here — it's defined in storage-tiers-browser.ts.\n\n/**\n * Wraps an `IDBRequest` as a one-shot reactive source.\n *\n * @param req - Request whose callbacks are converted to protocol messages.\n * @returns `Node<T>` that emits `DATA` once on success then `COMPLETE`;\n * emits `ERROR` on failure.\n *\n * @category extra\n */\nexport function fromIDBRequest<T>(req: IDBRequest<T>): Node<T> {\n\treturn node<T>((_data, a) => {\n\t\tlet done = false;\n\t\tconst clear = () => {\n\t\t\treq.onsuccess = null;\n\t\t\treq.onerror = null;\n\t\t};\n\t\treq.onsuccess = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[DATA, req.result], [COMPLETE]]);\n\t\t};\n\t\treq.onerror = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, req.error ?? new Error(\"IndexedDB request failed\")]]);\n\t\t};\n\t\treturn () => {\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t};\n\t});\n}\n\n/**\n * Wraps an `IDBTransaction` terminal lifecycle as a one-shot reactive source.\n *\n * @param tx - Transaction to observe.\n * @returns `Node<void>` that emits `DATA` (`undefined`) then `COMPLETE` on\n * success; emits `ERROR` on `error`/`abort`.\n *\n * @category extra\n */\nexport function fromIDBTransaction(tx: IDBTransaction): Node<void> {\n\treturn node<void>((_data, a) => {\n\t\tlet done = false;\n\t\tconst clear = () => {\n\t\t\ttx.oncomplete = null;\n\t\t\ttx.onerror = null;\n\t\t\ttx.onabort = null;\n\t\t};\n\t\ttx.oncomplete = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[DATA, undefined], [COMPLETE]]);\n\t\t};\n\t\ttx.onerror = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, tx.error ?? new Error(\"IndexedDB transaction failed\")]]);\n\t\t};\n\t\ttx.onabort = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, tx.error ?? new Error(\"IndexedDB transaction aborted\")]]);\n\t\t};\n\t\treturn () => {\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t};\n\t});\n}\n\n// The old `indexedDbStorage` kv adapter has been removed.\n// Use `indexedDbKv` from `./storage-tiers-browser.js` instead (Audit 4, 2026-04-24).\n"],"mappings":"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","names":["import_core"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/base/sources/browser/index.ts","../../../../src/base/sources/event/dom.ts","../../../../src/base/sources/browser/idb.ts"],"sourcesContent":["/**\n * Browser-only sources — IDB (IndexedDB) reactive adapters, DOM events.\n *\n * All entries in this subpath may use DOM globals.\n * Import via @graphrefly/graphrefly/base/sources/browser.\n *\n * @module\n */\n\nexport * from \"../event/dom.js\";\nexport * from \"./idb.js\";\n","/**\n * DOM-based reactive event sources (browser-layer).\n *\n * Moved from extra/sources/event.ts (fromEvent, fromRaf) during cleave A2.\n */\n\nimport { ERROR, type Node, type NodeOptions, node } from \"@graphrefly/pure-ts/core\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\ntype AsyncSourceOpts = ExtraOpts & { signal?: AbortSignal };\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\n/** DOM-style event target (browser or `node:events`). */\nexport type EventTargetLike = {\n\taddEventListener(\n\t\ttype: string,\n\t\tlistener: (ev: unknown) => void,\n\t\toptions?: boolean | { capture?: boolean; passive?: boolean; once?: boolean },\n\t): void;\n\tremoveEventListener(\n\t\ttype: string,\n\t\tlistener: (ev: unknown) => void,\n\t\toptions?: boolean | { capture?: boolean; passive?: boolean; once?: boolean },\n\t): void;\n};\n\nexport function fromRaf(opts?: AsyncSourceOpts): Node<number> {\n\tconst { signal, ...rest } = opts ?? {};\n\treturn node<number>((_data, a) => {\n\t\tlet done = false;\n\t\tlet rafId: number | undefined;\n\t\tlet fallbackTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tlet abortListenerAdded = false;\n\t\tlet visibilityListenerAdded = false;\n\n\t\tconst raf: typeof requestAnimationFrame | undefined =\n\t\t\ttypeof requestAnimationFrame === \"function\" ? requestAnimationFrame : undefined;\n\t\tconst caf: typeof cancelAnimationFrame | undefined =\n\t\t\ttypeof cancelAnimationFrame === \"function\" ? cancelAnimationFrame : undefined;\n\t\tconst doc: Document | undefined = typeof document !== \"undefined\" ? document : undefined;\n\n\t\tconst clearPending = () => {\n\t\t\tif (rafId !== undefined && caf) caf(rafId);\n\t\t\tif (fallbackTimer !== undefined) clearTimeout(fallbackTimer);\n\t\t\trafId = undefined;\n\t\t\tfallbackTimer = undefined;\n\t\t};\n\t\tconst cleanup = () => {\n\t\t\tdone = true;\n\t\t\tclearPending();\n\t\t\tif (abortListenerAdded) {\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\tabortListenerAdded = false;\n\t\t\t}\n\t\t\tif (visibilityListenerAdded && doc) {\n\t\t\t\tdoc.removeEventListener(\"visibilitychange\", onVisibilityChange);\n\t\t\t\tvisibilityListenerAdded = false;\n\t\t\t}\n\t\t};\n\t\tconst onAbort = () => {\n\t\t\tif (done) return;\n\t\t\tcleanup();\n\t\t\ta.down([[ERROR, signal!.reason]]);\n\t\t};\n\t\tconst tick = (now: number) => {\n\t\t\tif (done) return;\n\t\t\ta.emit(now);\n\t\t\tscheduleNext();\n\t\t};\n\t\tconst scheduleNext = () => {\n\t\t\tif (done) return;\n\t\t\t// Prefer rAF for display-synced ticks when the tab is visible; when\n\t\t\t// hidden, rAF is throttled to ~0 by the browser, so fall back to\n\t\t\t// setTimeout so downstream state continues updating.\n\t\t\tif (raf && (!doc || doc.visibilityState !== \"hidden\")) {\n\t\t\t\trafId = raf(tick);\n\t\t\t} else {\n\t\t\t\tfallbackTimer = setTimeout(() => tick(performance.now()), 16);\n\t\t\t}\n\t\t};\n\t\tconst onVisibilityChange = () => {\n\t\t\tif (done) return;\n\t\t\t// Cancel any pending schedule and re-schedule via the path now\n\t\t\t// appropriate for the current visibility state.\n\t\t\tclearPending();\n\t\t\tscheduleNext();\n\t\t};\n\n\t\tif (signal?.aborted) {\n\t\t\t// Already aborted before activation — `onAbort()` ran `cleanup()`\n\t\t\t// and emitted ERROR. No listeners/timers were registered yet, so\n\t\t\t// there is nothing to tear down on deactivation; returning a\n\t\t\t// cleanup here would just re-run the (idempotent) no-op.\n\t\t\tonAbort();\n\t\t\treturn;\n\t\t}\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tabortListenerAdded = signal !== undefined;\n\t\tif (doc && raf) {\n\t\t\tdoc.addEventListener(\"visibilitychange\", onVisibilityChange);\n\t\t\tvisibilityListenerAdded = true;\n\t\t}\n\t\tscheduleNext();\n\t\treturn { onDeactivation: cleanup };\n\t}, sourceOpts(rest));\n}\n\n/**\n * Wraps a DOM-style `addEventListener` target; each event becomes a `DATA` emission.\n *\n * @param target - Object with `addEventListener` / `removeEventListener`.\n * @param type - Event name (e.g. `\"click\"`).\n * @param opts - Producer options plus listener options (`capture`, `passive`, `once`).\n * @returns `Node<T>` — event payloads; teardown removes the listener.\n *\n * @example\n * ```ts\n * import { fromEvent } from \"@graphrefly/graphrefly-ts\";\n *\n * fromEvent(document.body, \"click\");\n * ```\n *\n * @category extra\n */\nexport function fromEvent<T = unknown>(\n\ttarget: EventTargetLike,\n\ttype: string,\n\topts?: ExtraOpts & { capture?: boolean; passive?: boolean; once?: boolean },\n): Node<T> {\n\tconst { capture, passive, once, ...rest } = opts ?? {};\n\treturn node<T>((_data, a) => {\n\t\tconst handler = (e: unknown) => {\n\t\t\ta.emit(e as T);\n\t\t};\n\t\tconst options = { capture, passive, once };\n\t\ttarget.addEventListener(type, handler, options);\n\t\treturn { onDeactivation: () => target.removeEventListener(type, handler, options) };\n\t}, sourceOpts(rest));\n}\n","/**\n * Browser-only IndexedDB reactive sources.\n *\n * `fromIDBRequest` / `fromIDBTransaction` wrap raw IDB primitives as reactive\n * sources. The old `indexedDbStorage` kv adapter has been replaced by\n * `indexedDbKv` in `./storage-tiers-browser.js` (Audit 4, 2026-04-24).\n *\n * Imports require the DOM lib — not safe to pull into Node-only bundles\n * without `lib: [\"dom\"]` in the consumer's tsconfig.\n *\n * @module\n */\n/// <reference lib=\"dom\" />\n\nimport { COMPLETE, DATA, ERROR, type Node, node } from \"@graphrefly/pure-ts/core\";\n\n// IndexedDbStorageSpec is no longer needed here — it's defined in storage-tiers-browser.ts.\n\n/**\n * Wraps an `IDBRequest` as a one-shot reactive source.\n *\n * @param req - Request whose callbacks are converted to protocol messages.\n * @returns `Node<T>` that emits `DATA` once on success then `COMPLETE`;\n * emits `ERROR` on failure.\n *\n * @category extra\n */\nexport function fromIDBRequest<T>(req: IDBRequest<T>): Node<T> {\n\treturn node<T>((_data, a) => {\n\t\tlet done = false;\n\t\tconst clear = () => {\n\t\t\treq.onsuccess = null;\n\t\t\treq.onerror = null;\n\t\t};\n\t\treq.onsuccess = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[DATA, req.result], [COMPLETE]]);\n\t\t};\n\t\treq.onerror = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, req.error ?? new Error(\"IndexedDB request failed\")]]);\n\t\t};\n\t\treturn {\n\t\t\tonDeactivation: () => {\n\t\t\t\tdone = true;\n\t\t\t\tclear();\n\t\t\t},\n\t\t};\n\t});\n}\n\n/**\n * Wraps an `IDBTransaction` terminal lifecycle as a one-shot reactive source.\n *\n * @param tx - Transaction to observe.\n * @returns `Node<void>` that emits `DATA` (`undefined`) then `COMPLETE` on\n * success; emits `ERROR` on `error`/`abort`.\n *\n * @category extra\n */\nexport function fromIDBTransaction(tx: IDBTransaction): Node<void> {\n\treturn node<void>((_data, a) => {\n\t\tlet done = false;\n\t\tconst clear = () => {\n\t\t\ttx.oncomplete = null;\n\t\t\ttx.onerror = null;\n\t\t\ttx.onabort = null;\n\t\t};\n\t\ttx.oncomplete = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[DATA, undefined], [COMPLETE]]);\n\t\t};\n\t\ttx.onerror = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, tx.error ?? new Error(\"IndexedDB transaction failed\")]]);\n\t\t};\n\t\ttx.onabort = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, tx.error ?? new Error(\"IndexedDB transaction aborted\")]]);\n\t\t};\n\t\treturn {\n\t\t\tonDeactivation: () => {\n\t\t\t\tdone = true;\n\t\t\t\tclear();\n\t\t\t},\n\t\t};\n\t});\n}\n\n// The old `indexedDbStorage` kv adapter has been removed.\n// Use `indexedDbKv` from `./storage-tiers-browser.js` instead (Audit 4, 2026-04-24).\n"],"mappings":"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","names":["import_core"]}
|
|
@@ -59,7 +59,7 @@ function fromRaf(opts) {
|
|
|
59
59
|
};
|
|
60
60
|
if (signal?.aborted) {
|
|
61
61
|
onAbort();
|
|
62
|
-
return
|
|
62
|
+
return;
|
|
63
63
|
}
|
|
64
64
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
65
65
|
abortListenerAdded = signal !== void 0;
|
|
@@ -68,7 +68,7 @@ function fromRaf(opts) {
|
|
|
68
68
|
visibilityListenerAdded = true;
|
|
69
69
|
}
|
|
70
70
|
scheduleNext();
|
|
71
|
-
return cleanup;
|
|
71
|
+
return { onDeactivation: cleanup };
|
|
72
72
|
}, sourceOpts(rest));
|
|
73
73
|
}
|
|
74
74
|
function fromEvent(target, type, opts) {
|
|
@@ -79,7 +79,7 @@ function fromEvent(target, type, opts) {
|
|
|
79
79
|
};
|
|
80
80
|
const options = { capture, passive, once };
|
|
81
81
|
target.addEventListener(type, handler, options);
|
|
82
|
-
return () => target.removeEventListener(type, handler, options);
|
|
82
|
+
return { onDeactivation: () => target.removeEventListener(type, handler, options) };
|
|
83
83
|
}, sourceOpts(rest));
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -104,9 +104,11 @@ function fromIDBRequest(req) {
|
|
|
104
104
|
clear();
|
|
105
105
|
a.down([[ERROR2, req.error ?? new Error("IndexedDB request failed")]]);
|
|
106
106
|
};
|
|
107
|
-
return
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
return {
|
|
108
|
+
onDeactivation: () => {
|
|
109
|
+
done = true;
|
|
110
|
+
clear();
|
|
111
|
+
}
|
|
110
112
|
};
|
|
111
113
|
});
|
|
112
114
|
}
|
|
@@ -136,9 +138,11 @@ function fromIDBTransaction(tx) {
|
|
|
136
138
|
clear();
|
|
137
139
|
a.down([[ERROR2, tx.error ?? new Error("IndexedDB transaction aborted")]]);
|
|
138
140
|
};
|
|
139
|
-
return
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
return {
|
|
142
|
+
onDeactivation: () => {
|
|
143
|
+
done = true;
|
|
144
|
+
clear();
|
|
145
|
+
}
|
|
142
146
|
};
|
|
143
147
|
});
|
|
144
148
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/base/sources/event/dom.ts","../../../../src/base/sources/browser/idb.ts"],"sourcesContent":["/**\n * DOM-based reactive event sources (browser-layer).\n *\n * Moved from extra/sources/event.ts (fromEvent, fromRaf) during cleave A2.\n */\n\nimport { ERROR, type Node, type NodeOptions, node } from \"@graphrefly/pure-ts/core\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\ntype AsyncSourceOpts = ExtraOpts & { signal?: AbortSignal };\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\n/** DOM-style event target (browser or `node:events`). */\nexport type EventTargetLike = {\n\taddEventListener(\n\t\ttype: string,\n\t\tlistener: (ev: unknown) => void,\n\t\toptions?: boolean | { capture?: boolean; passive?: boolean; once?: boolean },\n\t): void;\n\tremoveEventListener(\n\t\ttype: string,\n\t\tlistener: (ev: unknown) => void,\n\t\toptions?: boolean | { capture?: boolean; passive?: boolean; once?: boolean },\n\t): void;\n};\n\nexport function fromRaf(opts?: AsyncSourceOpts): Node<number> {\n\tconst { signal, ...rest } = opts ?? {};\n\treturn node<number>((_data, a) => {\n\t\tlet done = false;\n\t\tlet rafId: number | undefined;\n\t\tlet fallbackTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tlet abortListenerAdded = false;\n\t\tlet visibilityListenerAdded = false;\n\n\t\tconst raf: typeof requestAnimationFrame | undefined =\n\t\t\ttypeof requestAnimationFrame === \"function\" ? requestAnimationFrame : undefined;\n\t\tconst caf: typeof cancelAnimationFrame | undefined =\n\t\t\ttypeof cancelAnimationFrame === \"function\" ? cancelAnimationFrame : undefined;\n\t\tconst doc: Document | undefined = typeof document !== \"undefined\" ? document : undefined;\n\n\t\tconst clearPending = () => {\n\t\t\tif (rafId !== undefined && caf) caf(rafId);\n\t\t\tif (fallbackTimer !== undefined) clearTimeout(fallbackTimer);\n\t\t\trafId = undefined;\n\t\t\tfallbackTimer = undefined;\n\t\t};\n\t\tconst cleanup = () => {\n\t\t\tdone = true;\n\t\t\tclearPending();\n\t\t\tif (abortListenerAdded) {\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\tabortListenerAdded = false;\n\t\t\t}\n\t\t\tif (visibilityListenerAdded && doc) {\n\t\t\t\tdoc.removeEventListener(\"visibilitychange\", onVisibilityChange);\n\t\t\t\tvisibilityListenerAdded = false;\n\t\t\t}\n\t\t};\n\t\tconst onAbort = () => {\n\t\t\tif (done) return;\n\t\t\tcleanup();\n\t\t\ta.down([[ERROR, signal!.reason]]);\n\t\t};\n\t\tconst tick = (now: number) => {\n\t\t\tif (done) return;\n\t\t\ta.emit(now);\n\t\t\tscheduleNext();\n\t\t};\n\t\tconst scheduleNext = () => {\n\t\t\tif (done) return;\n\t\t\t// Prefer rAF for display-synced ticks when the tab is visible; when\n\t\t\t// hidden, rAF is throttled to ~0 by the browser, so fall back to\n\t\t\t// setTimeout so downstream state continues updating.\n\t\t\tif (raf && (!doc || doc.visibilityState !== \"hidden\")) {\n\t\t\t\trafId = raf(tick);\n\t\t\t} else {\n\t\t\t\tfallbackTimer = setTimeout(() => tick(performance.now()), 16);\n\t\t\t}\n\t\t};\n\t\tconst onVisibilityChange = () => {\n\t\t\tif (done) return;\n\t\t\t// Cancel any pending schedule and re-schedule via the path now\n\t\t\t// appropriate for the current visibility state.\n\t\t\tclearPending();\n\t\t\tscheduleNext();\n\t\t};\n\n\t\tif (signal?.aborted) {\n\t\t\tonAbort();\n\t\t\treturn cleanup;\n\t\t}\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tabortListenerAdded = signal !== undefined;\n\t\tif (doc && raf) {\n\t\t\tdoc.addEventListener(\"visibilitychange\", onVisibilityChange);\n\t\t\tvisibilityListenerAdded = true;\n\t\t}\n\t\tscheduleNext();\n\t\treturn cleanup;\n\t}, sourceOpts(rest));\n}\n\n/**\n * Wraps a DOM-style `addEventListener` target; each event becomes a `DATA` emission.\n *\n * @param target - Object with `addEventListener` / `removeEventListener`.\n * @param type - Event name (e.g. `\"click\"`).\n * @param opts - Producer options plus listener options (`capture`, `passive`, `once`).\n * @returns `Node<T>` — event payloads; teardown removes the listener.\n *\n * @example\n * ```ts\n * import { fromEvent } from \"@graphrefly/graphrefly-ts\";\n *\n * fromEvent(document.body, \"click\");\n * ```\n *\n * @category extra\n */\nexport function fromEvent<T = unknown>(\n\ttarget: EventTargetLike,\n\ttype: string,\n\topts?: ExtraOpts & { capture?: boolean; passive?: boolean; once?: boolean },\n): Node<T> {\n\tconst { capture, passive, once, ...rest } = opts ?? {};\n\treturn node<T>((_data, a) => {\n\t\tconst handler = (e: unknown) => {\n\t\t\ta.emit(e as T);\n\t\t};\n\t\tconst options = { capture, passive, once };\n\t\ttarget.addEventListener(type, handler, options);\n\t\treturn () => target.removeEventListener(type, handler, options);\n\t}, sourceOpts(rest));\n}\n","/**\n * Browser-only IndexedDB reactive sources.\n *\n * `fromIDBRequest` / `fromIDBTransaction` wrap raw IDB primitives as reactive\n * sources. The old `indexedDbStorage` kv adapter has been replaced by\n * `indexedDbKv` in `./storage-tiers-browser.js` (Audit 4, 2026-04-24).\n *\n * Imports require the DOM lib — not safe to pull into Node-only bundles\n * without `lib: [\"dom\"]` in the consumer's tsconfig.\n *\n * @module\n */\n/// <reference lib=\"dom\" />\n\nimport { COMPLETE, DATA, ERROR, type Node, node } from \"@graphrefly/pure-ts/core\";\n\n// IndexedDbStorageSpec is no longer needed here — it's defined in storage-tiers-browser.ts.\n\n/**\n * Wraps an `IDBRequest` as a one-shot reactive source.\n *\n * @param req - Request whose callbacks are converted to protocol messages.\n * @returns `Node<T>` that emits `DATA` once on success then `COMPLETE`;\n * emits `ERROR` on failure.\n *\n * @category extra\n */\nexport function fromIDBRequest<T>(req: IDBRequest<T>): Node<T> {\n\treturn node<T>((_data, a) => {\n\t\tlet done = false;\n\t\tconst clear = () => {\n\t\t\treq.onsuccess = null;\n\t\t\treq.onerror = null;\n\t\t};\n\t\treq.onsuccess = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[DATA, req.result], [COMPLETE]]);\n\t\t};\n\t\treq.onerror = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, req.error ?? new Error(\"IndexedDB request failed\")]]);\n\t\t};\n\t\treturn () => {\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t};\n\t});\n}\n\n/**\n * Wraps an `IDBTransaction` terminal lifecycle as a one-shot reactive source.\n *\n * @param tx - Transaction to observe.\n * @returns `Node<void>` that emits `DATA` (`undefined`) then `COMPLETE` on\n * success; emits `ERROR` on `error`/`abort`.\n *\n * @category extra\n */\nexport function fromIDBTransaction(tx: IDBTransaction): Node<void> {\n\treturn node<void>((_data, a) => {\n\t\tlet done = false;\n\t\tconst clear = () => {\n\t\t\ttx.oncomplete = null;\n\t\t\ttx.onerror = null;\n\t\t\ttx.onabort = null;\n\t\t};\n\t\ttx.oncomplete = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[DATA, undefined], [COMPLETE]]);\n\t\t};\n\t\ttx.onerror = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, tx.error ?? new Error(\"IndexedDB transaction failed\")]]);\n\t\t};\n\t\ttx.onabort = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, tx.error ?? new Error(\"IndexedDB transaction aborted\")]]);\n\t\t};\n\t\treturn () => {\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t};\n\t});\n}\n\n// The old `indexedDbStorage` kv adapter has been removed.\n// Use `indexedDbKv` from `./storage-tiers-browser.js` instead (Audit 4, 2026-04-24).\n"],"mappings":"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","names":["ERROR","node"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/base/sources/event/dom.ts","../../../../src/base/sources/browser/idb.ts"],"sourcesContent":["/**\n * DOM-based reactive event sources (browser-layer).\n *\n * Moved from extra/sources/event.ts (fromEvent, fromRaf) during cleave A2.\n */\n\nimport { ERROR, type Node, type NodeOptions, node } from \"@graphrefly/pure-ts/core\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\ntype AsyncSourceOpts = ExtraOpts & { signal?: AbortSignal };\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\n/** DOM-style event target (browser or `node:events`). */\nexport type EventTargetLike = {\n\taddEventListener(\n\t\ttype: string,\n\t\tlistener: (ev: unknown) => void,\n\t\toptions?: boolean | { capture?: boolean; passive?: boolean; once?: boolean },\n\t): void;\n\tremoveEventListener(\n\t\ttype: string,\n\t\tlistener: (ev: unknown) => void,\n\t\toptions?: boolean | { capture?: boolean; passive?: boolean; once?: boolean },\n\t): void;\n};\n\nexport function fromRaf(opts?: AsyncSourceOpts): Node<number> {\n\tconst { signal, ...rest } = opts ?? {};\n\treturn node<number>((_data, a) => {\n\t\tlet done = false;\n\t\tlet rafId: number | undefined;\n\t\tlet fallbackTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tlet abortListenerAdded = false;\n\t\tlet visibilityListenerAdded = false;\n\n\t\tconst raf: typeof requestAnimationFrame | undefined =\n\t\t\ttypeof requestAnimationFrame === \"function\" ? requestAnimationFrame : undefined;\n\t\tconst caf: typeof cancelAnimationFrame | undefined =\n\t\t\ttypeof cancelAnimationFrame === \"function\" ? cancelAnimationFrame : undefined;\n\t\tconst doc: Document | undefined = typeof document !== \"undefined\" ? document : undefined;\n\n\t\tconst clearPending = () => {\n\t\t\tif (rafId !== undefined && caf) caf(rafId);\n\t\t\tif (fallbackTimer !== undefined) clearTimeout(fallbackTimer);\n\t\t\trafId = undefined;\n\t\t\tfallbackTimer = undefined;\n\t\t};\n\t\tconst cleanup = () => {\n\t\t\tdone = true;\n\t\t\tclearPending();\n\t\t\tif (abortListenerAdded) {\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\tabortListenerAdded = false;\n\t\t\t}\n\t\t\tif (visibilityListenerAdded && doc) {\n\t\t\t\tdoc.removeEventListener(\"visibilitychange\", onVisibilityChange);\n\t\t\t\tvisibilityListenerAdded = false;\n\t\t\t}\n\t\t};\n\t\tconst onAbort = () => {\n\t\t\tif (done) return;\n\t\t\tcleanup();\n\t\t\ta.down([[ERROR, signal!.reason]]);\n\t\t};\n\t\tconst tick = (now: number) => {\n\t\t\tif (done) return;\n\t\t\ta.emit(now);\n\t\t\tscheduleNext();\n\t\t};\n\t\tconst scheduleNext = () => {\n\t\t\tif (done) return;\n\t\t\t// Prefer rAF for display-synced ticks when the tab is visible; when\n\t\t\t// hidden, rAF is throttled to ~0 by the browser, so fall back to\n\t\t\t// setTimeout so downstream state continues updating.\n\t\t\tif (raf && (!doc || doc.visibilityState !== \"hidden\")) {\n\t\t\t\trafId = raf(tick);\n\t\t\t} else {\n\t\t\t\tfallbackTimer = setTimeout(() => tick(performance.now()), 16);\n\t\t\t}\n\t\t};\n\t\tconst onVisibilityChange = () => {\n\t\t\tif (done) return;\n\t\t\t// Cancel any pending schedule and re-schedule via the path now\n\t\t\t// appropriate for the current visibility state.\n\t\t\tclearPending();\n\t\t\tscheduleNext();\n\t\t};\n\n\t\tif (signal?.aborted) {\n\t\t\t// Already aborted before activation — `onAbort()` ran `cleanup()`\n\t\t\t// and emitted ERROR. No listeners/timers were registered yet, so\n\t\t\t// there is nothing to tear down on deactivation; returning a\n\t\t\t// cleanup here would just re-run the (idempotent) no-op.\n\t\t\tonAbort();\n\t\t\treturn;\n\t\t}\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tabortListenerAdded = signal !== undefined;\n\t\tif (doc && raf) {\n\t\t\tdoc.addEventListener(\"visibilitychange\", onVisibilityChange);\n\t\t\tvisibilityListenerAdded = true;\n\t\t}\n\t\tscheduleNext();\n\t\treturn { onDeactivation: cleanup };\n\t}, sourceOpts(rest));\n}\n\n/**\n * Wraps a DOM-style `addEventListener` target; each event becomes a `DATA` emission.\n *\n * @param target - Object with `addEventListener` / `removeEventListener`.\n * @param type - Event name (e.g. `\"click\"`).\n * @param opts - Producer options plus listener options (`capture`, `passive`, `once`).\n * @returns `Node<T>` — event payloads; teardown removes the listener.\n *\n * @example\n * ```ts\n * import { fromEvent } from \"@graphrefly/graphrefly-ts\";\n *\n * fromEvent(document.body, \"click\");\n * ```\n *\n * @category extra\n */\nexport function fromEvent<T = unknown>(\n\ttarget: EventTargetLike,\n\ttype: string,\n\topts?: ExtraOpts & { capture?: boolean; passive?: boolean; once?: boolean },\n): Node<T> {\n\tconst { capture, passive, once, ...rest } = opts ?? {};\n\treturn node<T>((_data, a) => {\n\t\tconst handler = (e: unknown) => {\n\t\t\ta.emit(e as T);\n\t\t};\n\t\tconst options = { capture, passive, once };\n\t\ttarget.addEventListener(type, handler, options);\n\t\treturn { onDeactivation: () => target.removeEventListener(type, handler, options) };\n\t}, sourceOpts(rest));\n}\n","/**\n * Browser-only IndexedDB reactive sources.\n *\n * `fromIDBRequest` / `fromIDBTransaction` wrap raw IDB primitives as reactive\n * sources. The old `indexedDbStorage` kv adapter has been replaced by\n * `indexedDbKv` in `./storage-tiers-browser.js` (Audit 4, 2026-04-24).\n *\n * Imports require the DOM lib — not safe to pull into Node-only bundles\n * without `lib: [\"dom\"]` in the consumer's tsconfig.\n *\n * @module\n */\n/// <reference lib=\"dom\" />\n\nimport { COMPLETE, DATA, ERROR, type Node, node } from \"@graphrefly/pure-ts/core\";\n\n// IndexedDbStorageSpec is no longer needed here — it's defined in storage-tiers-browser.ts.\n\n/**\n * Wraps an `IDBRequest` as a one-shot reactive source.\n *\n * @param req - Request whose callbacks are converted to protocol messages.\n * @returns `Node<T>` that emits `DATA` once on success then `COMPLETE`;\n * emits `ERROR` on failure.\n *\n * @category extra\n */\nexport function fromIDBRequest<T>(req: IDBRequest<T>): Node<T> {\n\treturn node<T>((_data, a) => {\n\t\tlet done = false;\n\t\tconst clear = () => {\n\t\t\treq.onsuccess = null;\n\t\t\treq.onerror = null;\n\t\t};\n\t\treq.onsuccess = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[DATA, req.result], [COMPLETE]]);\n\t\t};\n\t\treq.onerror = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, req.error ?? new Error(\"IndexedDB request failed\")]]);\n\t\t};\n\t\treturn {\n\t\t\tonDeactivation: () => {\n\t\t\t\tdone = true;\n\t\t\t\tclear();\n\t\t\t},\n\t\t};\n\t});\n}\n\n/**\n * Wraps an `IDBTransaction` terminal lifecycle as a one-shot reactive source.\n *\n * @param tx - Transaction to observe.\n * @returns `Node<void>` that emits `DATA` (`undefined`) then `COMPLETE` on\n * success; emits `ERROR` on `error`/`abort`.\n *\n * @category extra\n */\nexport function fromIDBTransaction(tx: IDBTransaction): Node<void> {\n\treturn node<void>((_data, a) => {\n\t\tlet done = false;\n\t\tconst clear = () => {\n\t\t\ttx.oncomplete = null;\n\t\t\ttx.onerror = null;\n\t\t\ttx.onabort = null;\n\t\t};\n\t\ttx.oncomplete = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[DATA, undefined], [COMPLETE]]);\n\t\t};\n\t\ttx.onerror = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, tx.error ?? new Error(\"IndexedDB transaction failed\")]]);\n\t\t};\n\t\ttx.onabort = () => {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tclear();\n\t\t\ta.down([[ERROR, tx.error ?? new Error(\"IndexedDB transaction aborted\")]]);\n\t\t};\n\t\treturn {\n\t\t\tonDeactivation: () => {\n\t\t\t\tdone = true;\n\t\t\t\tclear();\n\t\t\t},\n\t\t};\n\t});\n}\n\n// The old `indexedDbStorage` kv adapter has been removed.\n// Use `indexedDbKv` from `./storage-tiers-browser.js` instead (Audit 4, 2026-04-24).\n"],"mappings":"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","names":["ERROR","node"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/base/sources/event/index.ts","../../../../src/base/sources/event/cron.ts"],"sourcesContent":["/**\n * Event sources — cron (presentation) and DOM (browser-only).\n *\n * For the DOM subpath, import from @graphrefly/graphrefly/base/sources/browser.\n * fromTimer is substrate; import from @graphrefly/pure-ts/extra.\n *\n * @module\n */\n\nexport * from \"./cron.js\";\n// dom.ts is browser-only; exposed via the browser subpath entry\n","/**\n * Cron-based reactive sources and schedule types.\n *\n * Merged from extra/cron.ts + extra/sources/event.ts (fromCron) during cleave A2.\n * `fromCron` relocated here from `dom.ts` (post-cleave /qa A1): it uses zero DOM\n * APIs (only `setInterval` + `new Date()`), so it belongs on the universal\n * `event/index.ts` barrel, not the browser-only `dom.ts` subpath.\n */\n\nimport { type Node, type NodeOptions, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\n/** Options for {@link fromCron}. */\nexport type FromCronOptions = ExtraOpts & {\n\t/** Polling interval in ms. Default `60_000`. */\n\ttickMs?: number;\n\t/** Output format: `\"timestamp_ns\"` (default) emits wall-clock nanoseconds; `\"date\"` emits a `Date` object. */\n\toutput?: \"timestamp_ns\" | \"date\";\n};\n\n/**\n * Minimal 5-field cron parser and matcher (minute hour day-of-month month day-of-week).\n * Ported from callbag-recharge `extra/cron.ts` for `fromCron` (roadmap §2.3).\n */\nexport interface CronSchedule {\n\tminutes: Set<number>;\n\thours: Set<number>;\n\tdaysOfMonth: Set<number>;\n\tmonths: Set<number>;\n\tdaysOfWeek: Set<number>;\n}\n\nfunction parseField(field: string, min: number, max: number): Set<number> {\n\tconst result = new Set<number>();\n\tfor (const part of field.split(\",\")) {\n\t\tconst [range, stepStr] = part.split(\"/\");\n\t\tconst step = stepStr ? Number.parseInt(stepStr, 10) : 1;\n\t\tif (Number.isNaN(step) || step < 1) throw new Error(`Invalid cron step: ${part}`);\n\t\tlet start: number;\n\t\tlet end: number;\n\t\tif (range === \"*\") {\n\t\t\tstart = min;\n\t\t\tend = max;\n\t\t} else if (range.includes(\"-\")) {\n\t\t\tconst [a, b] = range.split(\"-\");\n\t\t\tstart = Number.parseInt(a, 10);\n\t\t\tend = Number.parseInt(b, 10);\n\t\t} else {\n\t\t\tstart = Number.parseInt(range, 10);\n\t\t\tend = start;\n\t\t}\n\t\tif (Number.isNaN(start) || Number.isNaN(end)) throw new Error(`Invalid cron field: ${field}`);\n\t\tif (start < min || end > max)\n\t\t\tthrow new Error(`Cron field out of range: ${field} (${min}-${max})`);\n\t\tif (start > end) throw new Error(`Invalid cron range: ${start}-${end} in ${field}`);\n\t\tfor (let i = start; i <= end; i += step) result.add(i);\n\t}\n\treturn result;\n}\n\n/**\n * Parses a standard 5-field cron expression into a {@link CronSchedule}.\n *\n * Supports `*`, ranges (`1-5`), steps (`*\\/5`, `0-30/10`), and comma-separated\n * lists. Fields are: minute (0–59), hour (0–23), day-of-month (1–31),\n * month (1–12), day-of-week (0–6, Sunday = 0).\n *\n * @param expr - Five-field whitespace-separated cron string (e.g. `\"0 9 * * 1-5\"`).\n * @returns Parsed {@link CronSchedule} with one `Set<number>` per field.\n * @throws Error when the expression does not have exactly 5 fields, contains\n * out-of-range values, or uses an invalid step.\n *\n * @example\n * ```ts\n * import { parseCron } from \"@graphrefly/graphrefly-ts\";\n *\n * const sched = parseCron(\"0 9 * * 1-5\"); // weekdays at 09:00\n * sched.hours; // Set { 9 }\n * sched.daysOfWeek; // Set { 1, 2, 3, 4, 5 }\n * ```\n */\nexport function parseCron(expr: string): CronSchedule {\n\tconst parts = expr.trim().split(/\\s+/);\n\tif (parts.length !== 5) throw new Error(`Invalid cron: expected 5 fields, got ${parts.length}`);\n\treturn {\n\t\tminutes: parseField(parts[0], 0, 59),\n\t\thours: parseField(parts[1], 0, 23),\n\t\tdaysOfMonth: parseField(parts[2], 1, 31),\n\t\tmonths: parseField(parts[3], 1, 12),\n\t\tdaysOfWeek: parseField(parts[4], 0, 6),\n\t};\n}\n\n/**\n * Returns `true` if `date` satisfies every field of `schedule`.\n *\n * @param schedule - Parsed schedule from {@link parseCron}.\n * @param date - Moment to test (local time via `getMinutes`, `getHours`, etc.).\n * @returns `true` when all five cron fields match the given date.\n *\n * @example\n * ```ts\n * import { parseCron, matchesCron } from \"@graphrefly/graphrefly-ts\";\n *\n * const sched = parseCron(\"30 8 * * 1\"); // Mondays at 08:30\n * const monday = new Date(\"2026-03-30T08:30:00\"); // a Monday\n * matchesCron(sched, monday); // true\n * ```\n */\nexport function matchesCron(schedule: CronSchedule, date: Date): boolean {\n\treturn (\n\t\tschedule.minutes.has(date.getMinutes()) &&\n\t\tschedule.hours.has(date.getHours()) &&\n\t\tschedule.daysOfMonth.has(date.getDate()) &&\n\t\tschedule.months.has(date.getMonth() + 1) &&\n\t\tschedule.daysOfWeek.has(date.getDay())\n\t);\n}\n\n/**\n * Polls on an interval; when the current minute matches a 5-field cron expression, emits once (see {@link parseCron}).\n *\n * @param expr - Cron string (`min hour dom month dow`).\n * @param opts - Producer options plus `tickMs` (default `60_000`) and `output` (`timestamp_ns` default, or `date` for `Date` values).\n * @returns `Node<number>` (nanosecond timestamp) or `Node<Date>` when `output: \"date\"`.\n *\n * @example\n * ```ts\n * import { fromCron } from \"@graphrefly/graphrefly\";\n *\n * fromCron(\"0 9 * * 1\");\n * ```\n *\n * @category extra\n */\nexport function fromCron(expr: string, opts?: FromCronOptions & { output: \"date\" }): Node<Date>;\nexport function fromCron(expr: string, opts?: FromCronOptions): Node<number>;\nexport function fromCron(expr: string, opts?: FromCronOptions): Node<number | Date> {\n\tconst schedule: CronSchedule = parseCron(expr);\n\tconst { tickMs: tickOpt, output, ...rest } = opts ?? {};\n\tconst tickMs = tickOpt ?? 60_000;\n\tconst emitDate = output === \"date\";\n\treturn node<number | Date>(\n\t\t(_data, a) => {\n\t\t\tlet lastFiredKey = -1;\n\t\t\tconst check = () => {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst key =\n\t\t\t\t\tnow.getFullYear() * 100_000_000 +\n\t\t\t\t\t(now.getMonth() + 1) * 1_000_000 +\n\t\t\t\t\tnow.getDate() * 10_000 +\n\t\t\t\t\tnow.getHours() * 100 +\n\t\t\t\t\tnow.getMinutes();\n\t\t\t\tif (key !== lastFiredKey && matchesCron(schedule, now)) {\n\t\t\t\t\tlastFiredKey = key;\n\t\t\t\t\ta.emit(emitDate ? now : wallClockNs());\n\t\t\t\t}\n\t\t\t};\n\t\t\tcheck();\n\t\t\tconst id = setInterval(check, tickMs);\n\t\t\treturn () => clearInterval(id);\n\t\t},\n\t\t{ ...sourceOpts(rest), name: rest.name ?? `cron:${expr}` },\n\t);\n}\n"],"mappings":"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
|
|
1
|
+
{"version":3,"sources":["../../../../src/base/sources/event/index.ts","../../../../src/base/sources/event/cron.ts"],"sourcesContent":["/**\n * Event sources — cron (presentation) and DOM (browser-only).\n *\n * For the DOM subpath, import from @graphrefly/graphrefly/base/sources/browser.\n * fromTimer is substrate; import from @graphrefly/pure-ts/extra.\n *\n * @module\n */\n\nexport * from \"./cron.js\";\n// dom.ts is browser-only; exposed via the browser subpath entry\n","/**\n * Cron-based reactive sources and schedule types.\n *\n * Merged from extra/cron.ts + extra/sources/event.ts (fromCron) during cleave A2.\n * `fromCron` relocated here from `dom.ts` (post-cleave /qa A1): it uses zero DOM\n * APIs (only `setInterval` + `new Date()`), so it belongs on the universal\n * `event/index.ts` barrel, not the browser-only `dom.ts` subpath.\n */\n\nimport { type Node, type NodeOptions, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\n/** Options for {@link fromCron}. */\nexport type FromCronOptions = ExtraOpts & {\n\t/** Polling interval in ms. Default `60_000`. */\n\ttickMs?: number;\n\t/** Output format: `\"timestamp_ns\"` (default) emits wall-clock nanoseconds; `\"date\"` emits a `Date` object. */\n\toutput?: \"timestamp_ns\" | \"date\";\n};\n\n/**\n * Minimal 5-field cron parser and matcher (minute hour day-of-month month day-of-week).\n * Ported from callbag-recharge `extra/cron.ts` for `fromCron` (roadmap §2.3).\n */\nexport interface CronSchedule {\n\tminutes: Set<number>;\n\thours: Set<number>;\n\tdaysOfMonth: Set<number>;\n\tmonths: Set<number>;\n\tdaysOfWeek: Set<number>;\n}\n\nfunction parseField(field: string, min: number, max: number): Set<number> {\n\tconst result = new Set<number>();\n\tfor (const part of field.split(\",\")) {\n\t\tconst [range, stepStr] = part.split(\"/\");\n\t\tconst step = stepStr ? Number.parseInt(stepStr, 10) : 1;\n\t\tif (Number.isNaN(step) || step < 1) throw new Error(`Invalid cron step: ${part}`);\n\t\tlet start: number;\n\t\tlet end: number;\n\t\tif (range === \"*\") {\n\t\t\tstart = min;\n\t\t\tend = max;\n\t\t} else if (range.includes(\"-\")) {\n\t\t\tconst [a, b] = range.split(\"-\");\n\t\t\tstart = Number.parseInt(a, 10);\n\t\t\tend = Number.parseInt(b, 10);\n\t\t} else {\n\t\t\tstart = Number.parseInt(range, 10);\n\t\t\tend = start;\n\t\t}\n\t\tif (Number.isNaN(start) || Number.isNaN(end)) throw new Error(`Invalid cron field: ${field}`);\n\t\tif (start < min || end > max)\n\t\t\tthrow new Error(`Cron field out of range: ${field} (${min}-${max})`);\n\t\tif (start > end) throw new Error(`Invalid cron range: ${start}-${end} in ${field}`);\n\t\tfor (let i = start; i <= end; i += step) result.add(i);\n\t}\n\treturn result;\n}\n\n/**\n * Parses a standard 5-field cron expression into a {@link CronSchedule}.\n *\n * Supports `*`, ranges (`1-5`), steps (`*\\/5`, `0-30/10`), and comma-separated\n * lists. Fields are: minute (0–59), hour (0–23), day-of-month (1–31),\n * month (1–12), day-of-week (0–6, Sunday = 0).\n *\n * @param expr - Five-field whitespace-separated cron string (e.g. `\"0 9 * * 1-5\"`).\n * @returns Parsed {@link CronSchedule} with one `Set<number>` per field.\n * @throws Error when the expression does not have exactly 5 fields, contains\n * out-of-range values, or uses an invalid step.\n *\n * @example\n * ```ts\n * import { parseCron } from \"@graphrefly/graphrefly-ts\";\n *\n * const sched = parseCron(\"0 9 * * 1-5\"); // weekdays at 09:00\n * sched.hours; // Set { 9 }\n * sched.daysOfWeek; // Set { 1, 2, 3, 4, 5 }\n * ```\n */\nexport function parseCron(expr: string): CronSchedule {\n\tconst parts = expr.trim().split(/\\s+/);\n\tif (parts.length !== 5) throw new Error(`Invalid cron: expected 5 fields, got ${parts.length}`);\n\treturn {\n\t\tminutes: parseField(parts[0], 0, 59),\n\t\thours: parseField(parts[1], 0, 23),\n\t\tdaysOfMonth: parseField(parts[2], 1, 31),\n\t\tmonths: parseField(parts[3], 1, 12),\n\t\tdaysOfWeek: parseField(parts[4], 0, 6),\n\t};\n}\n\n/**\n * Returns `true` if `date` satisfies every field of `schedule`.\n *\n * @param schedule - Parsed schedule from {@link parseCron}.\n * @param date - Moment to test (local time via `getMinutes`, `getHours`, etc.).\n * @returns `true` when all five cron fields match the given date.\n *\n * @example\n * ```ts\n * import { parseCron, matchesCron } from \"@graphrefly/graphrefly-ts\";\n *\n * const sched = parseCron(\"30 8 * * 1\"); // Mondays at 08:30\n * const monday = new Date(\"2026-03-30T08:30:00\"); // a Monday\n * matchesCron(sched, monday); // true\n * ```\n */\nexport function matchesCron(schedule: CronSchedule, date: Date): boolean {\n\treturn (\n\t\tschedule.minutes.has(date.getMinutes()) &&\n\t\tschedule.hours.has(date.getHours()) &&\n\t\tschedule.daysOfMonth.has(date.getDate()) &&\n\t\tschedule.months.has(date.getMonth() + 1) &&\n\t\tschedule.daysOfWeek.has(date.getDay())\n\t);\n}\n\n/**\n * Polls on an interval; when the current minute matches a 5-field cron expression, emits once (see {@link parseCron}).\n *\n * @param expr - Cron string (`min hour dom month dow`).\n * @param opts - Producer options plus `tickMs` (default `60_000`) and `output` (`timestamp_ns` default, or `date` for `Date` values).\n * @returns `Node<number>` (nanosecond timestamp) or `Node<Date>` when `output: \"date\"`.\n *\n * @example\n * ```ts\n * import { fromCron } from \"@graphrefly/graphrefly\";\n *\n * fromCron(\"0 9 * * 1\");\n * ```\n *\n * @category extra\n */\nexport function fromCron(expr: string, opts?: FromCronOptions & { output: \"date\" }): Node<Date>;\nexport function fromCron(expr: string, opts?: FromCronOptions): Node<number>;\nexport function fromCron(expr: string, opts?: FromCronOptions): Node<number | Date> {\n\tconst schedule: CronSchedule = parseCron(expr);\n\tconst { tickMs: tickOpt, output, ...rest } = opts ?? {};\n\tconst tickMs = tickOpt ?? 60_000;\n\tconst emitDate = output === \"date\";\n\treturn node<number | Date>(\n\t\t(_data, a) => {\n\t\t\tlet lastFiredKey = -1;\n\t\t\tconst check = () => {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst key =\n\t\t\t\t\tnow.getFullYear() * 100_000_000 +\n\t\t\t\t\t(now.getMonth() + 1) * 1_000_000 +\n\t\t\t\t\tnow.getDate() * 10_000 +\n\t\t\t\t\tnow.getHours() * 100 +\n\t\t\t\t\tnow.getMinutes();\n\t\t\t\tif (key !== lastFiredKey && matchesCron(schedule, now)) {\n\t\t\t\t\tlastFiredKey = key;\n\t\t\t\t\ta.emit(emitDate ? now : wallClockNs());\n\t\t\t\t}\n\t\t\t};\n\t\t\tcheck();\n\t\t\tconst id = setInterval(check, tickMs);\n\t\t\treturn { onDeactivation: () => clearInterval(id) };\n\t\t},\n\t\t{ ...sourceOpts(rest), name: rest.name ?? `cron:${expr}` },\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSA,kBAA+D;AAI/D,SAAS,WAAwB,MAAkC;AAClE,SAAO,EAAE,cAAc,YAAY,GAAG,KAAK;AAC5C;AAsBA,SAAS,WAAW,OAAe,KAAa,KAA0B;AACzE,QAAM,SAAS,oBAAI,IAAY;AAC/B,aAAW,QAAQ,MAAM,MAAM,GAAG,GAAG;AACpC,UAAM,CAAC,OAAO,OAAO,IAAI,KAAK,MAAM,GAAG;AACvC,UAAM,OAAO,UAAU,OAAO,SAAS,SAAS,EAAE,IAAI;AACtD,QAAI,OAAO,MAAM,IAAI,KAAK,OAAO,EAAG,OAAM,IAAI,MAAM,sBAAsB,IAAI,EAAE;AAChF,QAAI;AACJ,QAAI;AACJ,QAAI,UAAU,KAAK;AAClB,cAAQ;AACR,YAAM;AAAA,IACP,WAAW,MAAM,SAAS,GAAG,GAAG;AAC/B,YAAM,CAAC,GAAG,CAAC,IAAI,MAAM,MAAM,GAAG;AAC9B,cAAQ,OAAO,SAAS,GAAG,EAAE;AAC7B,YAAM,OAAO,SAAS,GAAG,EAAE;AAAA,IAC5B,OAAO;AACN,cAAQ,OAAO,SAAS,OAAO,EAAE;AACjC,YAAM;AAAA,IACP;AACA,QAAI,OAAO,MAAM,KAAK,KAAK,OAAO,MAAM,GAAG,EAAG,OAAM,IAAI,MAAM,uBAAuB,KAAK,EAAE;AAC5F,QAAI,QAAQ,OAAO,MAAM;AACxB,YAAM,IAAI,MAAM,4BAA4B,KAAK,KAAK,GAAG,IAAI,GAAG,GAAG;AACpE,QAAI,QAAQ,IAAK,OAAM,IAAI,MAAM,uBAAuB,KAAK,IAAI,GAAG,OAAO,KAAK,EAAE;AAClF,aAAS,IAAI,OAAO,KAAK,KAAK,KAAK,KAAM,QAAO,IAAI,CAAC;AAAA,EACtD;AACA,SAAO;AACR;AAuBO,SAAS,UAAU,MAA4B;AACrD,QAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK;AACrC,MAAI,MAAM,WAAW,EAAG,OAAM,IAAI,MAAM,wCAAwC,MAAM,MAAM,EAAE;AAC9F,SAAO;AAAA,IACN,SAAS,WAAW,MAAM,CAAC,GAAG,GAAG,EAAE;AAAA,IACnC,OAAO,WAAW,MAAM,CAAC,GAAG,GAAG,EAAE;AAAA,IACjC,aAAa,WAAW,MAAM,CAAC,GAAG,GAAG,EAAE;AAAA,IACvC,QAAQ,WAAW,MAAM,CAAC,GAAG,GAAG,EAAE;AAAA,IAClC,YAAY,WAAW,MAAM,CAAC,GAAG,GAAG,CAAC;AAAA,EACtC;AACD;AAkBO,SAAS,YAAY,UAAwB,MAAqB;AACxE,SACC,SAAS,QAAQ,IAAI,KAAK,WAAW,CAAC,KACtC,SAAS,MAAM,IAAI,KAAK,SAAS,CAAC,KAClC,SAAS,YAAY,IAAI,KAAK,QAAQ,CAAC,KACvC,SAAS,OAAO,IAAI,KAAK,SAAS,IAAI,CAAC,KACvC,SAAS,WAAW,IAAI,KAAK,OAAO,CAAC;AAEvC;AAoBO,SAAS,SAAS,MAAc,MAA6C;AACnF,QAAM,WAAyB,UAAU,IAAI;AAC7C,QAAM,EAAE,QAAQ,SAAS,QAAQ,GAAG,KAAK,IAAI,QAAQ,CAAC;AACtD,QAAM,SAAS,WAAW;AAC1B,QAAM,WAAW,WAAW;AAC5B,aAAO;AAAA,IACN,CAAC,OAAO,MAAM;AACb,UAAI,eAAe;AACnB,YAAM,QAAQ,MAAM;AACnB,cAAM,MAAM,oBAAI,KAAK;AACrB,cAAM,MACL,IAAI,YAAY,IAAI,OACnB,IAAI,SAAS,IAAI,KAAK,MACvB,IAAI,QAAQ,IAAI,MAChB,IAAI,SAAS,IAAI,MACjB,IAAI,WAAW;AAChB,YAAI,QAAQ,gBAAgB,YAAY,UAAU,GAAG,GAAG;AACvD,yBAAe;AACf,YAAE,KAAK,WAAW,UAAM,yBAAY,CAAC;AAAA,QACtC;AAAA,MACD;AACA,YAAM;AACN,YAAM,KAAK,YAAY,OAAO,MAAM;AACpC,aAAO,EAAE,gBAAgB,MAAM,cAAc,EAAE,EAAE;AAAA,IAClD;AAAA,IACA,EAAE,GAAG,WAAW,IAAI,GAAG,MAAM,KAAK,QAAQ,QAAQ,IAAI,GAAG;AAAA,EAC1D;AACD;","names":[]}
|
|
@@ -304,11 +304,13 @@ function withTimeout(source, opts, extraOpts) {
|
|
|
304
304
|
if (latestOpts != null) {
|
|
305
305
|
attachSource();
|
|
306
306
|
}
|
|
307
|
-
return
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
307
|
+
return {
|
|
308
|
+
onDeactivation: () => {
|
|
309
|
+
stopped = true;
|
|
310
|
+
timer.cancel();
|
|
311
|
+
if (srcUnsub) srcUnsub();
|
|
312
|
+
if (optsUnsub) optsUnsub();
|
|
313
|
+
}
|
|
312
314
|
};
|
|
313
315
|
},
|
|
314
316
|
{
|
|
@@ -394,9 +396,11 @@ function defer(thunk, opts) {
|
|
|
394
396
|
const safe = err === void 0 ? new Error("defer: thunk threw undefined") : err;
|
|
395
397
|
a.down([[import_core.ERROR, safe]]);
|
|
396
398
|
}
|
|
397
|
-
return
|
|
398
|
-
|
|
399
|
-
|
|
399
|
+
return {
|
|
400
|
+
onDeactivation: () => {
|
|
401
|
+
stopped = true;
|
|
402
|
+
unsub?.();
|
|
403
|
+
}
|
|
400
404
|
};
|
|
401
405
|
}, merged);
|
|
402
406
|
}
|
|
@@ -452,8 +456,10 @@ function toArray(source, opts) {
|
|
|
452
456
|
}
|
|
453
457
|
function share(source, opts) {
|
|
454
458
|
return (0, import_core.node)(
|
|
455
|
-
(_data, a) =>
|
|
456
|
-
|
|
459
|
+
(_data, a) => ({
|
|
460
|
+
onDeactivation: source.subscribe((msgs) => {
|
|
461
|
+
a.down(msgs);
|
|
462
|
+
})
|
|
457
463
|
}),
|
|
458
464
|
{ ...(0, import_extra.sourceOpts)(opts), initial: source.cache }
|
|
459
465
|
);
|
|
@@ -461,8 +467,10 @@ function share(source, opts) {
|
|
|
461
467
|
function replay(source, bufferSize, opts) {
|
|
462
468
|
if (bufferSize < 1) throw new RangeError("replay expects bufferSize >= 1");
|
|
463
469
|
return (0, import_core.node)(
|
|
464
|
-
(_data, a) =>
|
|
465
|
-
|
|
470
|
+
(_data, a) => ({
|
|
471
|
+
onDeactivation: source.subscribe((msgs) => {
|
|
472
|
+
a.down(msgs);
|
|
473
|
+
})
|
|
466
474
|
}),
|
|
467
475
|
{ ...(0, import_extra.sourceOpts)(opts), initial: source.cache, replayBuffer: bufferSize }
|
|
468
476
|
);
|
|
@@ -536,7 +544,7 @@ function fromCron(expr, opts) {
|
|
|
536
544
|
};
|
|
537
545
|
check();
|
|
538
546
|
const id = setInterval(check, tickMs);
|
|
539
|
-
return () => clearInterval(id);
|
|
547
|
+
return { onDeactivation: () => clearInterval(id) };
|
|
540
548
|
},
|
|
541
549
|
{ ...sourceOpts2(rest), name: rest.name ?? `cron:${expr}` }
|
|
542
550
|
);
|