@animastor/orchestration 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/package.json +51 -0
- package/src/host/host-bindings.js +138 -0
- package/src/index.js +99 -0
- package/src/orchestration/index.js +40 -0
- package/src/orchestration/orchestrator.js +630 -0
- package/src/orchestration/runtime-result-consumer.js +54 -0
- package/src/orchestration/scene-callbacks.js +542 -0
- package/src/orchestration/scene-orchestrator.js +601 -0
- package/src/orchestration/scene-restoration.js +129 -0
- package/src/orchestration/scene-utils.js +36 -0
- package/src/runtime/active-scenes-index.js +164 -0
- package/src/runtime/audio-fsm-port.js +187 -0
- package/src/runtime/circuit-breaker.js +588 -0
- package/src/runtime/counter-reconciliation.js +308 -0
- package/src/runtime/dispatch-engine.js +1768 -0
- package/src/runtime/failure-taxonomy.js +125 -0
- package/src/runtime/hub-cancel-port.js +122 -0
- package/src/runtime/layer-config-port.js +136 -0
- package/src/runtime/lease-manager.js +607 -0
- package/src/runtime/persistence-port.js +162 -0
- package/src/runtime/placeholder-audio-port.js +117 -0
- package/src/runtime/progress-events-port.js +121 -0
- package/src/runtime/reconciliation-engine.js +2405 -0
- package/src/runtime/retry-budget-manager.js +229 -0
- package/src/runtime/runtime-metrics.js +427 -0
- package/src/runtime/runtime-result-emitter.js +123 -0
- package/src/runtime/runtime-scheduler.js +629 -0
- package/src/runtime/scene-data-port.js +114 -0
- package/src/runtime/scene-window.js +827 -0
- package/src/runtime/video-fsm-port.js +189 -0
- package/src/runtime/worker-health.js +270 -0
- package/test/counter-reconciliation.test.js +164 -0
- package/test/mocks/redis-mock.js +221 -0
- package/test/test-bindings.js +60 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// ======================================================
|
|
2
|
+
// O-2 PORT: PersistencePort — runtime/orchestration persistence contract
|
|
3
|
+
// ======================================================
|
|
4
|
+
// The runtime and orchestration tiers must not know the persistence
|
|
5
|
+
// implementation. Every PG table, SQL string, repository module and the
|
|
6
|
+
// storage barrel stay HOST-side (backend/src/storage/**); the tiers consume
|
|
7
|
+
// persistence ONLY through this port, wired by the composition root
|
|
8
|
+
// (backend.cjs) at startup.
|
|
9
|
+
//
|
|
10
|
+
// runtime/** + orchestration/** (tier consumers)
|
|
11
|
+
// ↓ consume state operations through
|
|
12
|
+
// runtime/persistence-port ← THIS PORT (tier-owned contract)
|
|
13
|
+
// ↑ wired by the host
|
|
14
|
+
// storage/runtime-persistence-adapter (host PG/Redis adapter)
|
|
15
|
+
//
|
|
16
|
+
// This is the S-6 port convention (ports/generation-config.js): a
|
|
17
|
+
// zero-require contract module, a fail-fast call-time resolver, one
|
|
18
|
+
// set/wired/reset surface. No pg types, no SQL, no repository names and no
|
|
19
|
+
// "future CRUD" cross the boundary — the contract below is EXACTLY the set
|
|
20
|
+
// of persistence operations the two tiers use today (measured at §32.9):
|
|
21
|
+
//
|
|
22
|
+
// tasks — task-status completion + orphan-task checks
|
|
23
|
+
// (runtime-scheduler, reconciliation-engine); createTask
|
|
24
|
+
// is a routes-side concern and stays there
|
|
25
|
+
// sceneAssets — per-asset status truth + version gates + dirty
|
|
26
|
+
// units (orchestrator completeStage version gate,
|
|
27
|
+
// scene-orchestrator dirty reads, scene-window
|
|
28
|
+
// staleness, scene-callbacks markReady/dirty clears,
|
|
29
|
+
// scene-restoration, reconciliation rebuildWorkList);
|
|
30
|
+
// markStale is consumed by state/scene-state-ops
|
|
31
|
+
// (outside the two tiers) and stays a direct repo call
|
|
32
|
+
// iu — image-unit rows (scene-callbacks audio timing
|
|
33
|
+
// recalculation)
|
|
34
|
+
// cancel — generation cancellation tombstones
|
|
35
|
+
// (reconciliation-engine orphan/repair legs)
|
|
36
|
+
// sceneVersions — the two scenes-table version reads every tier does
|
|
37
|
+
// (scene-window, scene-restoration, orchestrator
|
|
38
|
+
// version gate, reconciliation rebuildWorkList)
|
|
39
|
+
// registry — Redis asset-registry reads/writes
|
|
40
|
+
// (reconciliation repair legs, scene-callbacks
|
|
41
|
+
// completion handlers)
|
|
42
|
+
// filesystem — canonical scene audio path composition
|
|
43
|
+
// (reconciliation orphan check, scene-callbacks
|
|
44
|
+
// audio handler)
|
|
45
|
+
// listBooks — distinct book identities from persistent truth
|
|
46
|
+
// (reconciliation rebuildWorkList)
|
|
47
|
+
// (getDirtyMarkers is the two-row-set read the worklist rebuild issues:
|
|
48
|
+
// unit-dirty scenes + per-asset stale/failed/pending markers)
|
|
49
|
+
//
|
|
50
|
+
// Deliberately NOT in the port: transactions, the pool, query handles,
|
|
51
|
+
// CRUD "for later". The host adapter owns every SQL string and every table.
|
|
52
|
+
//
|
|
53
|
+
// Docs: docs/architecture/generation-module-extraction-reconnaissance.md §32.9
|
|
54
|
+
// ======================================================
|
|
55
|
+
|
|
56
|
+
const OPS = [
|
|
57
|
+
'tasks.updateTaskStatus',
|
|
58
|
+
'tasks.hasActiveTaskForScene',
|
|
59
|
+
|
|
60
|
+
'sceneAssets.getAsset',
|
|
61
|
+
'sceneAssets.markReady',
|
|
62
|
+
'sceneAssets.getDirtyUnitIds',
|
|
63
|
+
'sceneAssets.setDirtyUnitIds',
|
|
64
|
+
'sceneAssets.clearDirtyUnitIds',
|
|
65
|
+
'sceneAssets.clearDirtyFlag',
|
|
66
|
+
'sceneAssets.getDirtyScenesByVersion',
|
|
67
|
+
'sceneAssets.getDirtyMarkers',
|
|
68
|
+
|
|
69
|
+
'iu.getImageUnitsForScene',
|
|
70
|
+
'iu.upsertImageUnit',
|
|
71
|
+
|
|
72
|
+
'cancel.isCancelled',
|
|
73
|
+
'cancel.getAllCancelled',
|
|
74
|
+
|
|
75
|
+
'sceneVersions.getSceneVersions',
|
|
76
|
+
'sceneVersions.getAudioConfigVersions',
|
|
77
|
+
'sceneVersions.getVersionStalenessRows',
|
|
78
|
+
|
|
79
|
+
'registry.getSceneAssetsRedis',
|
|
80
|
+
'registry.registerSceneAudioRedis',
|
|
81
|
+
'registry.registerSceneImageRedis',
|
|
82
|
+
'registry.registerSceneVideoRedis',
|
|
83
|
+
|
|
84
|
+
'filesystem.getSceneAudioPath',
|
|
85
|
+
|
|
86
|
+
'listBooks',
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
let impl = null;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Wire the host persistence adapter. Called once by the composition root
|
|
93
|
+
* (backend.cjs) BEFORE any runtime/orchestration persistence consumer runs.
|
|
94
|
+
* @param {object} adapter — nested namespaces (tasks/sceneAssets/iu/cancel/
|
|
95
|
+
* sceneVersions/registry/filesystem) + the top-level listBooks function;
|
|
96
|
+
* every dotted op in OPS must resolve to a function.
|
|
97
|
+
*/
|
|
98
|
+
function setPersistencePort(adapter) {
|
|
99
|
+
if (!adapter) {
|
|
100
|
+
throw new Error('persistence-port: adapter is required');
|
|
101
|
+
}
|
|
102
|
+
for (const op of OPS) {
|
|
103
|
+
if (typeof resolveOp(adapter, op) !== 'function') {
|
|
104
|
+
throw new Error(`persistence-port: adapter must implement ${op}()`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
impl = adapter;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Resolve the port at CALL time — fail-fast when unwired. */
|
|
111
|
+
function persistence() {
|
|
112
|
+
if (!impl) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
'persistence-port: not wired — the composition root must call ' +
|
|
115
|
+
'setPersistencePort(adapter) (storage/runtime-persistence-adapter) ' +
|
|
116
|
+
'before runtime/orchestration persistence consumers run (O-2)'
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return impl;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Dotted-path resolver over the nested adapter namespaces. */
|
|
123
|
+
function resolveOp(adapter, op) {
|
|
124
|
+
let node = adapter;
|
|
125
|
+
for (const part of op.split('.')) {
|
|
126
|
+
node = node?.[part];
|
|
127
|
+
if (node === undefined) return undefined;
|
|
128
|
+
}
|
|
129
|
+
return node;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Shorthand op resolver: `persist('sceneAssets.getAsset')(...)`.
|
|
134
|
+
* Fails fast when the port or the single op is missing — an op silently
|
|
135
|
+
* degrading to a no-op would corrupt persistence semantics.
|
|
136
|
+
* @param {string} op — dotted op name from OPS
|
|
137
|
+
*/
|
|
138
|
+
function persist(op) {
|
|
139
|
+
const fn = resolveOp(persistence(), op);
|
|
140
|
+
if (typeof fn !== 'function') {
|
|
141
|
+
throw new Error(`persistence-port: op '${op}' is not wired (O-2)`);
|
|
142
|
+
}
|
|
143
|
+
return fn;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function isPersistencePortWired() {
|
|
147
|
+
return impl !== null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Test hygiene: drop the wiring (mocha hooks). */
|
|
151
|
+
function _resetPersistencePort() {
|
|
152
|
+
impl = null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
module.exports = {
|
|
156
|
+
OPS,
|
|
157
|
+
setPersistencePort,
|
|
158
|
+
persistence,
|
|
159
|
+
persist,
|
|
160
|
+
isPersistencePortWired,
|
|
161
|
+
_resetPersistencePort,
|
|
162
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// ======================================================
|
|
2
|
+
// O-4 PORT: PlaceholderAudioPort — runtime/orchestration
|
|
3
|
+
// placeholder-audio contract
|
|
4
|
+
// ======================================================
|
|
5
|
+
// The runtime and orchestration tiers must not know the placeholder-audio
|
|
6
|
+
// host service. Every ffmpeg/child-process detail, scene_assets upsert,
|
|
7
|
+
// OUTPUT_DIR path composition and book fallback the service performs stays
|
|
8
|
+
// HOST-side (backend/src/services/placeholder-audio.js); the tiers consume
|
|
9
|
+
// the three placeholder-audio operations they actually use ONLY through
|
|
10
|
+
// this port, wired by the composition root (backend.cjs) at startup.
|
|
11
|
+
//
|
|
12
|
+
// runtime/** + orchestration/** (tier consumers)
|
|
13
|
+
// ↓ consume placeholder-audio ops through
|
|
14
|
+
// runtime/placeholder-audio-port.js ← THIS PORT (tier-owned contract)
|
|
15
|
+
// ↑ wired by the host
|
|
16
|
+
// storage/placeholder-audio-adapter (host service adapter)
|
|
17
|
+
//
|
|
18
|
+
// This is the O-2/O-3 port convention (runtime/persistence-port.js,
|
|
19
|
+
// runtime/scene-data-port.js): a zero-require contract module, a fail-fast
|
|
20
|
+
// call-time resolver, one set/wired/reset surface. No ffmpeg, no fs, no
|
|
21
|
+
// SQL, no scene_assets knowledge and no "future ops" cross the boundary —
|
|
22
|
+
// the contract below is EXACTLY the set of operations the two tiers use
|
|
23
|
+
// today (measured at O-4 reconnaissance, §32.7 O-P7):
|
|
24
|
+
//
|
|
25
|
+
// hasRealAudio — distinguish real TTS from a placeholder on
|
|
26
|
+
// completion/restore/rebuild reads
|
|
27
|
+
// (scene-window ×3 call sites,
|
|
28
|
+
// scene-restoration restore probe,
|
|
29
|
+
// reconciliation rebuildWorkList)
|
|
30
|
+
// ensurePlaceholderAudio — synchronously materialize the silent-MP3
|
|
31
|
+
// placeholder before a scene enters the
|
|
32
|
+
// scheduler (scene-window addToWindow)
|
|
33
|
+
// replacePlaceholderWithRealAudio — register real audio over the
|
|
34
|
+
// placeholder when the audio stage completes
|
|
35
|
+
// (scene-callbacks handleAudioCompleted)
|
|
36
|
+
//
|
|
37
|
+
// Deliberately NOT in the port: estimateSpeechDurationSec (pure text
|
|
38
|
+
// heuristic with its own canonical owner utils/speech-estimation —
|
|
39
|
+
// consumed by the VBook agent pipeline, not by these tiers),
|
|
40
|
+
// ensureAllPlaceholderAudio/getScenesNeedingPlaceholder (routes/import
|
|
41
|
+
// workflow), markPlaceholderStale (state-layer FSM writer),
|
|
42
|
+
// recoverMissingPlaceholders (host recovery routes), and any CRUD "for
|
|
43
|
+
// later". The host adapter owns every ffmpeg call, every path and every
|
|
44
|
+
// scene_assets write.
|
|
45
|
+
//
|
|
46
|
+
// Docs: docs/architecture/generation-module-extraction-reconnaissance.md §32.7 (O-P7, O-4 DONE)
|
|
47
|
+
// ======================================================
|
|
48
|
+
|
|
49
|
+
const OPS = [
|
|
50
|
+
'hasRealAudio',
|
|
51
|
+
'ensurePlaceholderAudio',
|
|
52
|
+
'replacePlaceholderWithRealAudio',
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
let impl = null;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Wire the host placeholder-audio adapter. Called once by the composition
|
|
59
|
+
* root (backend.cjs) BEFORE any runtime/orchestration placeholder-audio
|
|
60
|
+
* consumer runs.
|
|
61
|
+
* @param {object} adapter — flat map with every op in OPS as a function.
|
|
62
|
+
*/
|
|
63
|
+
function setPlaceholderAudioPort(adapter) {
|
|
64
|
+
if (!adapter) {
|
|
65
|
+
throw new Error('placeholder-audio-port: adapter is required');
|
|
66
|
+
}
|
|
67
|
+
for (const op of OPS) {
|
|
68
|
+
if (typeof adapter[op] !== 'function') {
|
|
69
|
+
throw new Error(`placeholder-audio-port: adapter must implement ${op}()`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
impl = adapter;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Resolve the port at CALL time — fail-fast when unwired. */
|
|
76
|
+
function placeholderAudio() {
|
|
77
|
+
if (!impl) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
'placeholder-audio-port: not wired — the composition root must call ' +
|
|
80
|
+
'setPlaceholderAudioPort(adapter) (storage/placeholder-audio-adapter) ' +
|
|
81
|
+
'before runtime/orchestration placeholder-audio consumers run (O-4)'
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return impl;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Shorthand op resolver: `placeholderAudioOp('hasRealAudio')(...)`.
|
|
89
|
+
* Fails fast when the port or the single op is missing — a missing
|
|
90
|
+
* placeholder probe must never silently degrade into `false`.
|
|
91
|
+
* @param {string} op — op name from OPS
|
|
92
|
+
*/
|
|
93
|
+
function placeholderAudioOp(op) {
|
|
94
|
+
const fn = impl?.[op];
|
|
95
|
+
if (typeof fn !== 'function') {
|
|
96
|
+
throw new Error(`placeholder-audio-port: op '${op}' is not wired (O-4)`);
|
|
97
|
+
}
|
|
98
|
+
return fn;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function isPlaceholderAudioPortWired() {
|
|
102
|
+
return impl !== null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Test hygiene: drop the wiring (mocha hooks). */
|
|
106
|
+
function _resetPlaceholderAudioPort() {
|
|
107
|
+
impl = null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module.exports = {
|
|
111
|
+
OPS,
|
|
112
|
+
setPlaceholderAudioPort,
|
|
113
|
+
placeholderAudio,
|
|
114
|
+
placeholderAudioOp,
|
|
115
|
+
isPlaceholderAudioPortWired,
|
|
116
|
+
_resetPlaceholderAudioPort,
|
|
117
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// ======================================================
|
|
2
|
+
// O-5 PORT: ProgressEventsPort — runtime/orchestration
|
|
3
|
+
// progress-observer contract
|
|
4
|
+
// ======================================================
|
|
5
|
+
// The runtime and orchestration tiers must not know the progress host
|
|
6
|
+
// services. The Redis pub/sub channel bytes (`animastor:progress:*`), the
|
|
7
|
+
// task-registry hash key namespace (`animastor:generation-progress:*`),
|
|
8
|
+
// their TTLs and their retention rules stay HOST-side
|
|
9
|
+
// (backend/src/services/progress-pubsub.cjs, backend/src/services/
|
|
10
|
+
// generation-progress.js); the tiers consume progress ONLY through this
|
|
11
|
+
// port, wired by the composition root (backend.cjs) at startup.
|
|
12
|
+
//
|
|
13
|
+
// runtime/** + orchestration/** (tier consumers)
|
|
14
|
+
// ↓ consume progress ops through
|
|
15
|
+
// runtime/progress-events-port.js ← THIS PORT (tier-owned contract)
|
|
16
|
+
// ↑ wired by the host
|
|
17
|
+
// storage/progress-events-adapter (host progress adapter)
|
|
18
|
+
//
|
|
19
|
+
// This is the O-2/O-3/O-4 port convention (runtime/persistence-port.js,
|
|
20
|
+
// runtime/scene-data-port.js, runtime/placeholder-audio-port.js): a
|
|
21
|
+
// zero-require contract module, a fail-fast call-time resolver, one
|
|
22
|
+
// set/wired/reset surface. No Redis key strings, no pub/sub transport, no
|
|
23
|
+
// TTL arithmetic, no SSE knowledge and no "future ops" cross the boundary
|
|
24
|
+
// — the contract below is EXACTLY the set of progress operations the two
|
|
25
|
+
// tiers use today (measured at O-5 reconnaissance, §32.7 O-P4):
|
|
26
|
+
//
|
|
27
|
+
// publishProgress — best-effort per-book progress event (layer
|
|
28
|
+
// advance / generation_complete) consumed by the
|
|
29
|
+
// SSE poller (scene-callbacks ×5 call sites)
|
|
30
|
+
// getSceneTaskState — per-scene selective-task read: which worker
|
|
31
|
+
// types a task-managed scene must run
|
|
32
|
+
// (runtime-scheduler shouldScheduleAssets +
|
|
33
|
+
// markVersionStaleDirty)
|
|
34
|
+
// hasActiveTasks — does the book still have an active
|
|
35
|
+
// generation task (scene-window
|
|
36
|
+
// trySlideWindowOnComplete task_managed gate)
|
|
37
|
+
// reconcileCompletedTasks — mark task records completed once every
|
|
38
|
+
// target asset is ready (runtime-scheduler tick
|
|
39
|
+
// pre-pass; the getAssetStates callback arrives
|
|
40
|
+
// as an argument exactly as pre-O-5)
|
|
41
|
+
//
|
|
42
|
+
// Deliberately NOT in the port: createTasks/listTasks/getTask/updateTask/
|
|
43
|
+
// markCompleted/markCancelled/removeTask/clear (routes-side task CRUD —
|
|
44
|
+
// the HTTP contour owns task lifecycle), getActiveTasksByType,
|
|
45
|
+
// reconcileCompletedTasks' siblings and any CRUD "for later". The host
|
|
46
|
+
// adapter owns every Redis key, every TTL and the pub/sub channel.
|
|
47
|
+
//
|
|
48
|
+
// Docs: docs/architecture/generation-module-extraction-reconnaissance.md §32.7 (O-P4, O-5 DONE)
|
|
49
|
+
// ======================================================
|
|
50
|
+
|
|
51
|
+
const OPS = [
|
|
52
|
+
'publishProgress',
|
|
53
|
+
'getSceneTaskState',
|
|
54
|
+
'hasActiveTasks',
|
|
55
|
+
'reconcileCompletedTasks',
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
let impl = null;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Wire the host progress-events adapter. Called once by the composition
|
|
62
|
+
* root (backend.cjs) BEFORE any runtime/orchestration progress consumer
|
|
63
|
+
* runs.
|
|
64
|
+
* @param {object} adapter — flat map with every op in OPS as a function.
|
|
65
|
+
*/
|
|
66
|
+
function setProgressEventsPort(adapter) {
|
|
67
|
+
if (!adapter) {
|
|
68
|
+
throw new Error('progress-events-port: adapter is required');
|
|
69
|
+
}
|
|
70
|
+
for (const op of OPS) {
|
|
71
|
+
if (typeof adapter[op] !== 'function') {
|
|
72
|
+
throw new Error(`progress-events-port: adapter must implement ${op}()`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
impl = adapter;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Resolve the port at CALL time — fail-fast when unwired. */
|
|
79
|
+
function progressEvents() {
|
|
80
|
+
if (!impl) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
'progress-events-port: not wired — the composition root must call ' +
|
|
83
|
+
'setProgressEventsPort(adapter) (storage/progress-events-adapter) ' +
|
|
84
|
+
'before runtime/orchestration progress consumers run (O-5)'
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
return impl;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Shorthand op resolver: `progressEventsOp('publishProgress')(...)`.
|
|
92
|
+
* Fails fast when the port or the single op is missing — a progress event
|
|
93
|
+
* or task read silently degrading to a no-op would corrupt window-slide
|
|
94
|
+
* and dispatch decisions.
|
|
95
|
+
* @param {string} op — op name from OPS
|
|
96
|
+
*/
|
|
97
|
+
function progressEventsOp(op) {
|
|
98
|
+
const fn = impl?.[op];
|
|
99
|
+
if (typeof fn !== 'function') {
|
|
100
|
+
throw new Error(`progress-events-port: op '${op}' is not wired (O-5)`);
|
|
101
|
+
}
|
|
102
|
+
return fn;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isProgressEventsPortWired() {
|
|
106
|
+
return impl !== null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Test hygiene: drop the wiring (mocha hooks). */
|
|
110
|
+
function _resetProgressEventsPort() {
|
|
111
|
+
impl = null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
module.exports = {
|
|
115
|
+
OPS,
|
|
116
|
+
setProgressEventsPort,
|
|
117
|
+
progressEvents,
|
|
118
|
+
progressEventsOp,
|
|
119
|
+
isProgressEventsPortWired,
|
|
120
|
+
_resetProgressEventsPort,
|
|
121
|
+
};
|