@sema-agent/core 7.51.2 → 7.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +504 -2
- package/dist/agents/agent-transcript-tool.d.ts +1 -1
- package/dist/agents/cascade.js +4 -0
- package/dist/agents/cumulative-stats.d.ts +3 -0
- package/dist/agents/cumulative-stats.js +3 -0
- package/dist/agents/list-agents-tool.d.ts +1 -1
- package/dist/agents/read-inbox-tool.d.ts +1 -1
- package/dist/agents/repair-loop.js +4 -0
- package/dist/agents/send-message-tool.d.ts +11 -16
- package/dist/agents/send-message-tool.js +11 -13
- package/dist/agents/subagent.js +6 -4
- package/dist/agents/tool-filter.d.ts +40 -13
- package/dist/agents/tool-filter.js +28 -14
- package/dist/bench/metrics.d.ts +1 -0
- package/dist/brain/anthropic.js +16 -12
- package/dist/brain/model-presets.d.ts +4 -5
- package/dist/brain/model-presets.js +4 -4
- package/dist/brain/open-responses.js +16 -12
- package/dist/brain/openai.js +16 -12
- package/dist/brain/request-params.d.ts +12 -33
- package/dist/brain/request-params.js +5 -2
- package/dist/brain/request-route.d.ts +9 -8
- package/dist/brain/request-route.js +1 -0
- package/dist/brain/route-adjudicator.d.ts +117 -47
- package/dist/brain/route-adjudicator.js +171 -42
- package/dist/brain/route-conformance.js +2 -2
- package/dist/brain/status-sink.d.ts +18 -0
- package/dist/brain/status-sink.js +7 -0
- package/dist/core/allow-entry.d.ts +40 -8
- package/dist/core/allow-entry.js +23 -16
- package/dist/core/auto-compaction.d.ts +23 -20
- package/dist/core/auto-compaction.js +37 -16
- package/dist/core/auto-promote.d.ts +2 -1
- package/dist/core/auto-promote.js +2 -2
- package/dist/core/caller-tool-name.d.ts +9 -0
- package/dist/core/caller-tool-name.js +13 -0
- package/dist/core/checkpoint-requirements.d.ts +7 -1
- package/dist/core/checkpoint-requirements.js +2 -0
- package/dist/core/checkpoint-store.d.ts +36 -12
- package/dist/core/checkpoint-store.js +1 -1
- package/dist/core/child-clamp-seats.d.ts +6 -0
- package/dist/core/child-clamp-seats.js +2 -1
- package/dist/core/credential-vocabulary.d.ts +33 -8
- package/dist/core/credential-vocabulary.js +32 -7
- package/dist/core/decision-receipt.d.ts +2 -2
- package/dist/core/delegation-frames.d.ts +9 -2
- package/dist/core/delegation-name.d.ts +18 -0
- package/dist/core/delegation-name.js +47 -0
- package/dist/core/engine-capabilities.d.ts +8 -1
- package/dist/core/engine-capabilities.js +1 -1
- package/dist/core/engine-notice.d.ts +36 -19
- package/dist/core/frontmatter-fence.d.ts +10 -0
- package/dist/core/frontmatter-fence.js +6 -0
- package/dist/core/gate-fold.js +5 -23
- package/dist/core/gate-lanes.js +356 -270
- package/dist/core/governance-codes.d.ts +9 -4
- package/dist/core/governance-codes.js +9 -3
- package/dist/core/hooks.d.ts +276 -734
- package/dist/core/hooks.js +97 -192
- package/dist/{tools/fs → core}/image-admission.d.ts +21 -3
- package/dist/{tools/fs → core}/image-admission.js +24 -6
- package/dist/core/mcp-connection-pool.d.ts +4 -1
- package/dist/core/mcp-connection-pool.js +7 -2
- package/dist/core/mcp-probe.d.ts +12 -9
- package/dist/core/mcp-probe.js +2 -2
- package/dist/core/mcp-server-spec.d.ts +16 -0
- package/dist/core/mcp.d.ts +11 -7
- package/dist/core/mcp.js +11 -5
- package/dist/core/memory-engine/data-plane.js +5 -1
- package/dist/core/memory-engine/distiller.js +16 -2
- package/dist/core/memory-engine/engine.d.ts +8 -11
- package/dist/core/memory-engine/engine.js +9 -5
- package/dist/core/memory-engine/frontmatter.d.ts +6 -0
- package/dist/core/memory-engine/frontmatter.js +19 -16
- package/dist/core/memory.d.ts +2 -2
- package/dist/core/mode-policy.d.ts +4 -0
- package/dist/core/mode-policy.js +7 -5
- package/dist/core/model-seat.d.ts +4 -1
- package/dist/core/mods/dollar.d.ts +109 -0
- package/dist/core/mods/dollar.js +154 -0
- package/dist/core/mods/host.d.ts +23 -0
- package/dist/core/mods/host.js +21 -0
- package/dist/core/mods/kernel/budget.d.ts +43 -0
- package/dist/core/mods/kernel/budget.js +83 -0
- package/dist/core/mods/kernel/dispatch.d.ts +100 -0
- package/dist/core/mods/kernel/dispatch.js +701 -0
- package/dist/core/mods/kernel/events.d.ts +242 -0
- package/dist/core/mods/kernel/events.js +210 -0
- package/dist/core/mods/kernel/index.d.ts +6 -0
- package/dist/core/mods/kernel/index.js +5 -0
- package/dist/core/mods/kernel/receive.d.ts +65 -0
- package/dist/core/mods/kernel/receive.js +123 -0
- package/dist/core/mods/kernel/registration.d.ts +131 -0
- package/dist/core/mods/kernel/registration.js +102 -0
- package/dist/core/mods/kernel/site-rules.d.ts +84 -0
- package/dist/core/mods/kernel/site-rules.js +104 -0
- package/dist/core/mods/stations.d.ts +350 -0
- package/dist/core/mods/stations.js +444 -0
- package/dist/core/own-property-receipt.js +11 -23
- package/dist/core/parent-spec-seat.d.ts +18 -7
- package/dist/core/parent-spec-seat.js +6 -2
- package/dist/core/path-identity.js +2 -1
- package/dist/core/permission-rule-syntax.d.ts +15 -0
- package/dist/core/permission-rule-syntax.js +24 -16
- package/dist/core/permission-rules.d.ts +7 -1
- package/dist/core/permission-rules.js +26 -15
- package/dist/core/prompt-section-seat.d.ts +15 -27
- package/dist/core/prompt-section-seat.js +73 -40
- package/dist/core/protocol-http-auth.d.ts +3 -1
- package/dist/core/protocol-http-auth.js +2 -0
- package/dist/core/reminder-mint.d.ts +2 -2
- package/dist/core/remote-env.d.ts +24 -12
- package/dist/core/remote-env.js +1 -0
- package/dist/core/resume-startup-cause.d.ts +16 -1
- package/dist/core/resume-startup-cause.js +4 -1
- package/dist/core/retired-keys.d.ts +4 -0
- package/dist/core/retired-keys.js +3 -0
- package/dist/core/runner/announce-once-ledger.d.ts +31 -1
- package/dist/core/runner/announce-once-ledger.js +22 -0
- package/dist/core/runner/assemble-result.d.ts +9 -0
- package/dist/core/runner/assemble-result.js +3 -1
- package/dist/core/runner/call-hook-stations.d.ts +23 -27
- package/dist/core/runner/call-hook-stations.js +58 -42
- package/dist/core/runner/caller-stop-gate.d.ts +25 -0
- package/dist/core/runner/caller-stop-gate.js +7 -0
- package/dist/core/runner/compaction-seams.d.ts +8 -22
- package/dist/core/runner/compaction-seams.js +28 -53
- package/dist/core/runner/construction-doors.js +11 -1
- package/dist/core/runner/contracts.d.ts +85 -83
- package/dist/core/runner/credential-origin-seat.d.ts +2 -0
- package/dist/core/runner/credential-origin-seat.js +19 -0
- package/dist/core/runner/extra-body-dropped-seat.d.ts +2 -6
- package/dist/core/runner/gate-exit.d.ts +47 -36
- package/dist/core/runner/gate-exit.js +8 -2
- package/dist/core/runner/image.js +1 -2
- package/dist/core/runner/inline-image.js +1 -1
- package/dist/core/runner/notice-seat-input.d.ts +11 -0
- package/dist/core/runner/notice-seat-input.js +1 -0
- package/dist/core/runner/person-path-rows.js +1 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +5 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +5 -7
- package/dist/core/runner/prepare-ask-lane.js +6 -15
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
- package/dist/core/runner/prepare-caps-and-workflow.js +25 -8
- package/dist/core/runner/prepare-config-doors.d.ts +5 -0
- package/dist/core/runner/prepare-config-doors.js +9 -0
- package/dist/core/runner/prepare-defer-classify.js +3 -4
- package/dist/core/runner/prepare-gate-stations.d.ts +8 -11
- package/dist/core/runner/prepare-gate-stations.js +11 -10
- package/dist/core/runner/prepare-inherited-gate.d.ts +8 -12
- package/dist/core/runner/prepare-inherited-gate.js +8 -21
- package/dist/core/runner/prepare-memory-engine-session.js +1 -1
- package/dist/core/runner/prepare-park-ask.js +10 -14
- package/dist/core/runner/prepare-policy-chain.d.ts +17 -15
- package/dist/core/runner/prepare-policy-chain.js +95 -100
- package/dist/core/runner/prepare-project-context.js +7 -10
- package/dist/core/runner/prepare-prompt-assembly.d.ts +45 -40
- package/dist/core/runner/prepare-prompt-assembly.js +134 -101
- package/dist/core/runner/prepare-prompt-inputs.d.ts +18 -19
- package/dist/core/runner/prepare-prompt-inputs.js +5 -7
- package/dist/core/runner/prepare-protocol-tools.d.ts +6 -4
- package/dist/core/runner/prepare-protocol-tools.js +2 -2
- package/dist/core/runner/prepare-safety-scan.js +6 -10
- package/dist/core/runner/prepare-suspend-saga.d.ts +6 -0
- package/dist/core/runner/prepare-suspend-saga.js +7 -5
- package/dist/core/runner/prepare-task.js +33 -15
- package/dist/core/runner/prepare-turn-wiring.d.ts +13 -15
- package/dist/core/runner/prepare-turn-wiring.js +29 -27
- package/dist/core/runner/prepare-wiring-manifest.d.ts +5 -6
- package/dist/core/runner/prepare-wiring-manifest.js +7 -7
- package/dist/core/runner/resume-apply.d.ts +5 -2
- package/dist/core/runner/resume-apply.js +24 -42
- package/dist/core/runner/resume-checkpoint-screen.d.ts +1 -0
- package/dist/core/runner/resume-checkpoint-screen.js +9 -1
- package/dist/core/runner/resume-preflight.js +38 -16
- package/dist/core/runner/retired-runner-deps.js +3 -1
- package/dist/core/runner/run-brain-sinks.d.ts +3 -2
- package/dist/core/runner/run-brain-sinks.js +5 -1
- package/dist/core/runner/run-compaction-machinery.d.ts +7 -1
- package/dist/core/runner/run-compaction-machinery.js +7 -33
- package/dist/core/runner/run-harness-handlers.js +4 -2
- package/dist/core/runner/run-identity-wiring.d.ts +3 -1
- package/dist/core/runner/run-identity-wiring.js +3 -2
- package/dist/core/runner/run-leg.js +62 -84
- package/dist/core/runner/run-notification-lane.js +1 -0
- package/dist/core/runner/run-recovery-lanes.d.ts +3 -0
- package/dist/core/runner/run-recovery-lanes.js +11 -10
- package/dist/core/runner/run-settle-and-teardown.js +9 -28
- package/dist/core/runner/run-stop-and-final-verify.js +18 -25
- package/dist/core/runner/run-terminal-adoption.d.ts +3 -0
- package/dist/core/runner/run-terminal-adoption.js +33 -22
- package/dist/core/runner/run-tool-mount-facts.js +5 -3
- package/dist/core/runner/run-turn-boundary.js +23 -34
- package/dist/core/runner/runtask.d.ts +6 -7
- package/dist/core/runner/runtask.js +14 -72
- package/dist/core/runner/session-rule-policy.d.ts +5 -5
- package/dist/core/runner/session-rule-policy.js +13 -8
- package/dist/core/runner/side-call-account.d.ts +68 -0
- package/dist/core/runner/side-call-account.js +61 -0
- package/dist/core/runner/stream-halt-verbs.js +12 -17
- package/dist/core/runner/stream-lifecycle-verbs.js +8 -5
- package/dist/core/runner/stream-steer-verb.d.ts +1 -1
- package/dist/core/runner/stream-steer-verb.js +20 -38
- package/dist/core/runner/sub-agent-deny-lists.d.ts +121 -22
- package/dist/core/runner/sub-agent-deny-lists.js +228 -71
- package/dist/core/runner/tool-end-body.d.ts +5 -6
- package/dist/core/runner/tool-end-body.js +6 -4
- package/dist/core/runner/tool-not-executed.d.ts +15 -0
- package/dist/core/runner/tool-not-executed.js +30 -0
- package/dist/core/runner/tool-occurrence.d.ts +8 -7
- package/dist/core/runner/tool-occurrence.js +5 -5
- package/dist/core/runner/tool-result-media-seat.d.ts +1 -1
- package/dist/core/runner-deps.d.ts +20 -28
- package/dist/core/safety-merge-corpus.js +18 -2
- package/dist/core/secret-env.d.ts +88 -20
- package/dist/core/secret-env.js +192 -38
- package/dist/core/session-policy-store.d.ts +52 -16
- package/dist/core/session-policy-store.js +118 -28
- package/dist/core/session-reconcile.d.ts +4 -0
- package/dist/core/session-reconcile.js +2 -1
- package/dist/core/shell-read-silence.js +3 -32
- package/dist/core/side-query.d.ts +5 -3
- package/dist/core/skill-grant.d.ts +3 -2
- package/dist/core/skill-grant.js +17 -9
- package/dist/core/skills-directory.d.ts +31 -11
- package/dist/core/skills-directory.js +655 -104
- package/dist/core/task-event.d.ts +13 -3
- package/dist/core/task-result.d.ts +8 -0
- package/dist/core/task-spec.d.ts +20 -19
- package/dist/core/task-stream.d.ts +14 -4
- package/dist/core/tighten-task-spec.d.ts +4 -3
- package/dist/core/tighten-task-spec.js +2 -4
- package/dist/core/tool-check-reading.d.ts +74 -0
- package/dist/core/tool-check-reading.js +80 -0
- package/dist/core/tool-policy.d.ts +59 -18
- package/dist/core/tool-policy.js +77 -12
- package/dist/core/tool-registry.d.ts +20 -0
- package/dist/core/tool-registry.js +4 -0
- package/dist/core/tool-spec.d.ts +10 -6
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +51 -32
- package/dist/core/unc-spelling.d.ts +10 -0
- package/dist/core/unc-spelling.js +3 -0
- package/dist/core/untrusted-egress.d.ts +8 -0
- package/dist/core/untrusted-egress.js +4 -1
- package/dist/core/user-attachment.d.ts +12 -2
- package/dist/core/user-attachment.js +17 -2
- package/dist/core/wiring-manifest.d.ts +14 -13
- package/dist/core/wiring-manifest.js +2 -2
- package/dist/engine/compaction/utils.js +1 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +4 -3
- package/dist/engine/execution-env/symlink-chain.js +1 -1
- package/dist/engine/harness/agent-harness.d.ts +1 -1
- package/dist/engine/harness/agent-harness.js +3 -3
- package/dist/engine/harness/types.d.ts +17 -16
- package/dist/engine/harness/types.js +7 -1
- package/dist/engine/llm/types.d.ts +12 -7
- package/dist/engine/loop/agent-loop.js +1 -1
- package/dist/engine/loop/types.d.ts +1 -1
- package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
- package/dist/engine/session/import-validate.js +3 -10
- package/dist/engine/session/session.d.ts +4 -4
- package/dist/engine/session/session.js +4 -4
- package/dist/index.d.ts +20 -16
- package/dist/index.js +13 -11
- package/dist/internal/harness.d.ts +1 -1
- package/dist/internal/harness.js +1 -1
- package/dist/orchestration/run-spec.d.ts +4 -6
- package/dist/orchestration/run-spec.js +39 -63
- package/dist/orchestration/run-workflow-tool.js +1 -2
- package/dist/orchestration/workflow.d.ts +11 -3
- package/dist/orchestration/workflow.js +11 -2
- package/dist/prompt-assembly/artifact-store.d.ts +37 -56
- package/dist/prompt-assembly/artifact-store.js +31 -49
- package/dist/prompt-assembly/artifact.d.ts +89 -76
- package/dist/prompt-assembly/artifact.js +167 -146
- package/dist/prompt-assembly/assemble.d.ts +34 -29
- package/dist/prompt-assembly/assemble.js +33 -220
- package/dist/prompt-assembly/bands.d.ts +20 -0
- package/dist/prompt-assembly/bands.js +18 -0
- package/dist/prompt-assembly/catalog/constitution.d.ts +23 -0
- package/dist/prompt-assembly/catalog/constitution.js +69 -0
- package/dist/prompt-assembly/catalog/core-behavior.d.ts +9 -0
- package/dist/prompt-assembly/catalog/core-behavior.js +85 -0
- package/dist/prompt-assembly/catalog/index.d.ts +11 -0
- package/dist/prompt-assembly/catalog/index.js +59 -0
- package/dist/prompt-assembly/catalog/modes.d.ts +15 -0
- package/dist/prompt-assembly/catalog/modes.js +137 -0
- package/dist/prompt-assembly/catalog/role.d.ts +10 -0
- package/dist/prompt-assembly/catalog/role.js +157 -0
- package/dist/prompt-assembly/catalog/schema.d.ts +124 -0
- package/dist/prompt-assembly/catalog/schema.js +25 -0
- package/dist/prompt-assembly/catalog/sections.d.ts +9 -0
- package/dist/prompt-assembly/catalog/sections.js +98 -0
- package/dist/prompt-assembly/catalog/team.d.ts +4 -0
- package/dist/prompt-assembly/catalog/team.js +258 -0
- package/dist/prompt-assembly/composer.d.ts +24 -28
- package/dist/prompt-assembly/composer.js +124 -46
- package/dist/prompt-assembly/epoch.d.ts +89 -79
- package/dist/prompt-assembly/epoch.js +115 -142
- package/dist/prompt-assembly/explain.d.ts +58 -34
- package/dist/prompt-assembly/explain.js +21 -24
- package/dist/prompt-assembly/overlay.d.ts +127 -0
- package/dist/prompt-assembly/overlay.js +301 -0
- package/dist/prompt-assembly/renderers.d.ts +21 -0
- package/dist/prompt-assembly/renderers.js +39 -0
- package/dist/prompt-assembly/section-usage.d.ts +3 -3
- package/dist/prompt-assembly/section-usage.js +1 -1
- package/dist/prompt-assembly/select.d.ts +56 -0
- package/dist/prompt-assembly/select.js +69 -0
- package/dist/prompt-assembly/sugar.d.ts +31 -0
- package/dist/prompt-assembly/sugar.js +20 -0
- package/dist/prompt-assembly/turn-snapshot.d.ts +3 -2
- package/dist/prompt-assembly/types.d.ts +45 -148
- package/dist/prompts/coordinator.d.ts +2 -21
- package/dist/prompts/coordinator.js +3 -255
- package/dist/prompts/cowork.d.ts +27 -16
- package/dist/prompts/cowork.js +2 -23
- package/dist/prompts/default.d.ts +38 -500
- package/dist/prompts/default.js +20 -285
- package/dist/prompts/supervisor.d.ts +6 -71
- package/dist/prompts/supervisor.js +6 -117
- package/dist/tools/fs/bash-readonly-classifier.d.ts +6 -5
- package/dist/tools/fs/dir-entries.d.ts +4 -2
- package/dist/tools/fs/dir-entries.js +16 -4
- package/dist/tools/fs/fs-bash.d.ts +1 -1
- package/dist/tools/fs/fs-bash.js +22 -11
- package/dist/tools/fs/fs-pdf.js +17 -13
- package/dist/tools/fs/fs-read.js +4 -3
- package/dist/tools/fs/fs-shared.d.ts +1 -10
- package/dist/tools/fs/fs-shared.js +3 -4
- package/dist/tools/fs/fs-write.js +2 -1
- package/dist/tools/fs/notebook.js +1 -1
- package/dist/tools/fs/pdf.d.ts +20 -10
- package/dist/tools/fs/pdf.js +19 -10
- package/dist/tools/fs/program-read-model.d.ts +68 -8
- package/dist/tools/fs/program-read-model.js +112 -33
- package/dist/tools/fs/program-read-model.rows.js +30 -10
- package/dist/tools/fs/read-deny-home.d.ts +25 -9
- package/dist/tools/fs/read-deny-home.js +28 -27
- package/dist/tools/fs/read-deny.d.ts +41 -11
- package/dist/tools/fs/read-deny.js +51 -5
- package/dist/tools/fs/safety.d.ts +4 -26
- package/dist/tools/fs/safety.js +10 -32
- package/dist/tools/fs/search.js +15 -10
- package/dist/tools/fs/shell-read-argv.d.ts +3 -2
- package/dist/tools/fs/shell-read-argv.js +118 -38
- package/dist/tools/fs/shell-read-establish.d.ts +5 -5
- package/dist/tools/fs/shell-read-establish.js +11 -61
- package/dist/tools/fs/shell-read-identity.js +6 -3
- package/dist/tools/fs/shell-read-judge.d.ts +13 -15
- package/dist/tools/fs/shell-read-judge.js +18 -4
- package/dist/tools/fs/shell-read-plan.d.ts +2 -2
- package/dist/tools/web.js +1 -1
- package/package.json +13 -1
- package/test/export-surface.snapshot.json +242 -99
- package/wire-changes/core@7.52.0.json +5859 -0
- package/dist/core/hook-seats.d.ts +0 -66
- package/dist/core/hook-seats.js +0 -37
- package/dist/prompt-assembly/packs/sema-default.d.ts +0 -2
- package/dist/prompt-assembly/packs/sema-default.js +0 -147
- package/dist/prompts/simple-sections.d.ts +0 -58
- package/dist/prompts/simple-sections.js +0 -43
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
import { CATCH_BUDGET_MS, createSelfBudget, POST_ABORT_GRACE_MS, RUNAWAY_AFTER_MS, unrefTimer, watchRunaway } from "./budget.js";
|
|
2
|
+
import { expandModPattern, isModEventName, MOD_SEATS, nextToRefusal, stationOn } from "./events.js";
|
|
3
|
+
import { ENGINE_ORIGIN, modsInvalid, screenModSeats, } from "./registration.js";
|
|
4
|
+
import { answerUpward, answerViolation, detachedCopy, matcherMatches, matcherViolation, methodAnswerViolation, NEXT_IN_FLIGHT, pinnedKeyChanged, receiveAnswer, receivePayload, } from "./site-rules.js";
|
|
5
|
+
const TIER_RANK = { prepend: 0, user: 1, append: 2, builtin: 3, core: 4 };
|
|
6
|
+
const bypassed = (floors, tier) => floors.some((f) => TIER_RANK[f.from] < TIER_RANK[tier] && TIER_RANK[tier] < TIER_RANK[f.to]);
|
|
7
|
+
export async function admitMods(input) {
|
|
8
|
+
const report = safeReport(input.report);
|
|
9
|
+
const screened = screenModSeats(input.seats, input.side, (err) => report(err));
|
|
10
|
+
const mounted = [];
|
|
11
|
+
const records = [];
|
|
12
|
+
const describe = safeDescribe(input.describeThrown);
|
|
13
|
+
const bus = createBus(input.side, mounted, input.bottoms, report, records, describe, input.isProxy);
|
|
14
|
+
const admitted = Object.freeze({ admitted: true });
|
|
15
|
+
for (const cand of screened) {
|
|
16
|
+
if (input.signal?.aborted === true)
|
|
17
|
+
throw input.signal.reason;
|
|
18
|
+
const e = Object.freeze({
|
|
19
|
+
name: cand.name,
|
|
20
|
+
seat: cand.seat,
|
|
21
|
+
tier: cand.tier,
|
|
22
|
+
...(cand.provenance !== undefined ? { provenance: cand.provenance } : {}),
|
|
23
|
+
uses: Object.freeze({ events: cand.uses.events, calls: cand.uses.calls }),
|
|
24
|
+
});
|
|
25
|
+
const outcome = await bus.dispatch("plugin.register", e, {
|
|
26
|
+
bottom: () => admitted,
|
|
27
|
+
...(input.signal !== undefined ? { signal: input.signal } : {}),
|
|
28
|
+
checkAnswer: (a, judged, by) => a === admitted
|
|
29
|
+
? undefined
|
|
30
|
+
: refusalOf(a) === undefined
|
|
31
|
+
? "takes next(e) or { refuse: <reason> }"
|
|
32
|
+
: MOD_SEATS.indexOf(by.seat) > MOD_SEATS.findIndex((s) => s === judged["seat"])
|
|
33
|
+
? `a ${by.seat} registration may not refuse a ${String(judged["seat"])} registration`
|
|
34
|
+
: undefined,
|
|
35
|
+
});
|
|
36
|
+
if (outcome.kind === "aborted")
|
|
37
|
+
throw input.signal?.reason ?? new Error("admission aborted");
|
|
38
|
+
if (outcome.kind === "failed") {
|
|
39
|
+
records.push(Object.freeze({ name: cand.name, seat: cand.seat, tier: cand.tier, refusedBy: outcome.registration, reason: `${outcome.registration} failed: ${outcome.reason}` }));
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const refused = refusalOf(outcome.answer);
|
|
43
|
+
if (refused !== undefined) {
|
|
44
|
+
records.push(Object.freeze({ name: cand.name, seat: cand.seat, tier: cand.tier, refusedBy: outcome.answeredBy ?? "engine", reason: refused }));
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const own = mountOne(cand, input.side, describe);
|
|
48
|
+
mounted.push(...own);
|
|
49
|
+
const events = unique(own.map((h) => h.pattern));
|
|
50
|
+
const observe = unique(own.filter((h) => h.observe).map((h) => h.pattern));
|
|
51
|
+
records.push(Object.freeze({
|
|
52
|
+
name: cand.name,
|
|
53
|
+
seat: cand.seat,
|
|
54
|
+
tier: cand.tier,
|
|
55
|
+
events,
|
|
56
|
+
...(observe.length > 0 ? { observe } : {}),
|
|
57
|
+
...(outcome.skipped.length > 0 ? { skipped: outcome.skipped } : {}),
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
return bus;
|
|
61
|
+
}
|
|
62
|
+
function refusalOf(a) {
|
|
63
|
+
if (typeof a !== "object" || a === null || !Object.prototype.hasOwnProperty.call(a, "refuse"))
|
|
64
|
+
return undefined;
|
|
65
|
+
const r = Reflect.get(a, "refuse");
|
|
66
|
+
return typeof r === "string" && r !== "" ? r : undefined;
|
|
67
|
+
}
|
|
68
|
+
function unique(xs) {
|
|
69
|
+
return Object.freeze([...new Set(xs)]);
|
|
70
|
+
}
|
|
71
|
+
function safeDescribe(describe) {
|
|
72
|
+
return (err) => {
|
|
73
|
+
try {
|
|
74
|
+
const text = describe(err);
|
|
75
|
+
if (typeof text === "string")
|
|
76
|
+
return text;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
}
|
|
80
|
+
return "a value the host's renderer could not describe";
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function safeReport(report) {
|
|
84
|
+
return (err, classification) => {
|
|
85
|
+
try {
|
|
86
|
+
report(err, classification);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function mountOne(cand, side, describe) {
|
|
93
|
+
const own = [];
|
|
94
|
+
let sealed = false;
|
|
95
|
+
let problem;
|
|
96
|
+
const fail = (why) => {
|
|
97
|
+
problem ??= why;
|
|
98
|
+
throw modsInvalid(`${cand.name}: ${why}`);
|
|
99
|
+
};
|
|
100
|
+
const on = (pattern, a, b, c) => {
|
|
101
|
+
if (sealed)
|
|
102
|
+
throw modsInvalid(`${cand.name}: on() was called after register() returned`);
|
|
103
|
+
const withMatcher = typeof a !== "function";
|
|
104
|
+
const fn = withMatcher ? b : a;
|
|
105
|
+
const opts = withMatcher ? c : b;
|
|
106
|
+
if (typeof fn !== "function")
|
|
107
|
+
fail(`on("${String(pattern)}") takes a handler function`);
|
|
108
|
+
if (withMatcher) {
|
|
109
|
+
const why = matcherViolation(a);
|
|
110
|
+
if (why !== undefined)
|
|
111
|
+
fail(`on("${String(pattern)}"): ${why}`);
|
|
112
|
+
}
|
|
113
|
+
const parsed = handlerOptions(opts);
|
|
114
|
+
if (typeof parsed === "string")
|
|
115
|
+
fail(`on("${String(pattern)}"): ${parsed}`);
|
|
116
|
+
const expanded = expandModPattern(pattern);
|
|
117
|
+
if ("refusal" in expanded)
|
|
118
|
+
return void fail(`on(): ${expanded.refusal}`);
|
|
119
|
+
const outside = expanded.names.filter((n) => !cand.eventsBound.has(n));
|
|
120
|
+
if (outside.length > 0)
|
|
121
|
+
fail(`on("${pattern}") selects ${outside.join(", ")}, outside its uses.events`);
|
|
122
|
+
const events = expanded.names.filter((n) => stationOn(n, side) !== undefined);
|
|
123
|
+
if (events.length === 0)
|
|
124
|
+
fail(`on("${pattern}"): no event it selects is raised on the ${side} bus in this version`);
|
|
125
|
+
if (typeof fn !== "function" || typeof parsed === "string")
|
|
126
|
+
return;
|
|
127
|
+
own.push({
|
|
128
|
+
reg: cand,
|
|
129
|
+
index: own.length,
|
|
130
|
+
pattern,
|
|
131
|
+
events: new Set(events),
|
|
132
|
+
...(withMatcher && isMatcher(a) ? { matcher: Object.freeze({ ...a }) } : {}),
|
|
133
|
+
fn: asHandler(fn),
|
|
134
|
+
...(parsed.onCatch !== undefined ? { onCatch: parsed.onCatch } : {}),
|
|
135
|
+
observe: parsed.observe,
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
let returned;
|
|
139
|
+
try {
|
|
140
|
+
returned = cand.registration.register(on, cand.registration.options);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
if (problem !== undefined)
|
|
144
|
+
throw modsInvalid(`${cand.name}: ${problem}`);
|
|
145
|
+
throw modsInvalid(`${cand.name}: register() threw: ${describe(err)}`);
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
sealed = true;
|
|
149
|
+
}
|
|
150
|
+
if (problem !== undefined)
|
|
151
|
+
throw modsInvalid(`${cand.name}: ${problem}`);
|
|
152
|
+
if (typeof returned === "object" && returned !== null && typeof Reflect.get(returned, "then") === "function") {
|
|
153
|
+
throw modsInvalid(`${cand.name}: register() returned a promise; register is synchronous (hang handlers with on() before it returns)`);
|
|
154
|
+
}
|
|
155
|
+
return own;
|
|
156
|
+
}
|
|
157
|
+
function isMatcher(v) {
|
|
158
|
+
return matcherViolation(v) === undefined;
|
|
159
|
+
}
|
|
160
|
+
function asHandler(fn) {
|
|
161
|
+
return (...args) => (typeof fn === "function" ? Reflect.apply(fn, undefined, args) : undefined);
|
|
162
|
+
}
|
|
163
|
+
function handlerOptions(opts) {
|
|
164
|
+
if (opts === undefined)
|
|
165
|
+
return { observe: false };
|
|
166
|
+
if (typeof opts !== "object" || opts === null)
|
|
167
|
+
return `options are { catch?, observe? }, not ${typeof opts}`;
|
|
168
|
+
for (const k of Object.keys(opts))
|
|
169
|
+
if (k !== "catch" && k !== "observe")
|
|
170
|
+
return `options are { catch?, observe? }; "${k}" is not one`;
|
|
171
|
+
const c = Reflect.get(opts, "catch");
|
|
172
|
+
const o = Reflect.get(opts, "observe");
|
|
173
|
+
if (c !== undefined && typeof c !== "function")
|
|
174
|
+
return "catch is a handler function";
|
|
175
|
+
if (o !== undefined && typeof o !== "boolean")
|
|
176
|
+
return "observe is true or false";
|
|
177
|
+
return { ...(c !== undefined ? { onCatch: asHandler(c) } : {}), observe: o === true };
|
|
178
|
+
}
|
|
179
|
+
const HA = "skipped; what is below it ran in its place";
|
|
180
|
+
const MA = "skipped; its last next() run's result stands";
|
|
181
|
+
function createBus(side, mounted, bottoms, report, records, describe, isProxy) {
|
|
182
|
+
const methods = [];
|
|
183
|
+
for (const name of Object.keys(bottoms)) {
|
|
184
|
+
if (!isModEventName(name) || bottoms[name] === undefined)
|
|
185
|
+
continue;
|
|
186
|
+
const st = stationOn(name, side);
|
|
187
|
+
if (st?.method === undefined)
|
|
188
|
+
continue;
|
|
189
|
+
const dot = name.indexOf(".");
|
|
190
|
+
methods.push({ event: name, ns: name.slice(0, dot), method: name.slice(dot + 1), pauses: st.method.pausesCallerBudget });
|
|
191
|
+
}
|
|
192
|
+
const bus = {
|
|
193
|
+
records,
|
|
194
|
+
mounted: () => Object.freeze(mounted.map((h) => Object.freeze({
|
|
195
|
+
plugin: h.reg.name,
|
|
196
|
+
seat: h.reg.seat,
|
|
197
|
+
pattern: h.pattern,
|
|
198
|
+
...(h.matcher !== undefined ? { matcher: h.matcher } : {}),
|
|
199
|
+
observe: h.observe,
|
|
200
|
+
caught: h.onCatch !== undefined,
|
|
201
|
+
}))),
|
|
202
|
+
hasHandlers: (event, participant) => mounted.some((h) => h.events.has(event) && admits(participant, h)),
|
|
203
|
+
dispatch: (event, e, options) => {
|
|
204
|
+
const st = stationOn(event, side);
|
|
205
|
+
const received = st === undefined ? { refusal: `${event} is not raised on the ${side} bus` } : receivePayload(e);
|
|
206
|
+
if (st === undefined || "refusal" in received) {
|
|
207
|
+
const reason = `${event}: ${"refusal" in received ? received.refusal : "not raised"}`;
|
|
208
|
+
report(new Error(`engine: ${reason} — the dispatch was not run`));
|
|
209
|
+
return Promise.resolve(Object.freeze({ kind: "failed", registration: ENGINE_ORIGIN.plugin, cause: "violation", reason, skipped: Object.freeze([]) }));
|
|
210
|
+
}
|
|
211
|
+
return runDispatch(event, st, received.payload, options);
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
function participants(event, e, frames, participant) {
|
|
215
|
+
const inFrames = (fs, h) => fs.some((f) => f.plugin === h.reg.name && (f.kind === "dollar" || f.handler === h.index));
|
|
216
|
+
const caller = frames.slice(-1);
|
|
217
|
+
const above = frames.slice(0, -1);
|
|
218
|
+
const out = [];
|
|
219
|
+
for (const h of mounted) {
|
|
220
|
+
if (!h.events.has(event) || !admits(participant, h) || !matcherMatches(h.matcher, e))
|
|
221
|
+
continue;
|
|
222
|
+
if (inFrames(caller, h))
|
|
223
|
+
continue;
|
|
224
|
+
if (!inFrames(above, h))
|
|
225
|
+
out.push({ h, reentry: false });
|
|
226
|
+
else if (h.onCatch !== undefined && !h.observe)
|
|
227
|
+
out.push({ h, reentry: true });
|
|
228
|
+
}
|
|
229
|
+
return out;
|
|
230
|
+
}
|
|
231
|
+
async function callMethod(event, args, caller) {
|
|
232
|
+
const seat = bottoms[event];
|
|
233
|
+
if (seat === undefined)
|
|
234
|
+
throw new Error(`${caller.origin.plugin}: $.${event}: no implementation on the ${side} bus`);
|
|
235
|
+
const st = stationOn(event, side);
|
|
236
|
+
if (st === undefined)
|
|
237
|
+
throw new Error(`${caller.origin.plugin}: $.${event}: not raised on the ${side} bus`);
|
|
238
|
+
let e0 = args;
|
|
239
|
+
if (seat.enter !== undefined) {
|
|
240
|
+
const shaped = receivePayload(seat.enter(args), undefined, isProxy);
|
|
241
|
+
if ("refusal" in shaped)
|
|
242
|
+
throw new TypeError(`${caller.origin.plugin}: $.${event}: ${shaped.refusal}`);
|
|
243
|
+
e0 = shaped.payload;
|
|
244
|
+
}
|
|
245
|
+
const outcome = await runDispatch(event, st, e0, {
|
|
246
|
+
bottom: async (e, ctx) => ({ value: await seat.run(e, ctx) }),
|
|
247
|
+
frames: caller.frames,
|
|
248
|
+
origin: caller.origin,
|
|
249
|
+
signal: caller.signal,
|
|
250
|
+
checkAnswer: methodAnswerViolation,
|
|
251
|
+
});
|
|
252
|
+
if (outcome.kind !== "aborted")
|
|
253
|
+
for (const s of outcome.skipped)
|
|
254
|
+
if (s.cause === "violation")
|
|
255
|
+
report(new Error(`${s.registration}: $.${event}: ${s.reason} — skipped`));
|
|
256
|
+
if (outcome.kind === "aborted")
|
|
257
|
+
throw new Error(`${caller.origin.plugin}: $.${event}: aborted`);
|
|
258
|
+
if (outcome.kind === "failed")
|
|
259
|
+
throw new Error(`${caller.origin.plugin}: $.${event}: ${outcome.reason}`);
|
|
260
|
+
const answer = outcome.answer;
|
|
261
|
+
const deny = typeof answer === "object" && answer !== null ? Reflect.get(answer, "deny") : undefined;
|
|
262
|
+
if (typeof deny === "string")
|
|
263
|
+
throw new Error(`${caller.origin.plugin}: $.${event}: ${deny}`);
|
|
264
|
+
return typeof answer === "object" && answer !== null ? Reflect.get(answer, "value") : undefined;
|
|
265
|
+
}
|
|
266
|
+
function dollarFor(reg, frames, budget, signal) {
|
|
267
|
+
const origin = Object.freeze({ plugin: reg.name, tier: reg.tier });
|
|
268
|
+
const callerFrames = Object.freeze([...frames, Object.freeze({ kind: "dollar", plugin: reg.name })]);
|
|
269
|
+
const namespaces = new Map();
|
|
270
|
+
for (const m of methods) {
|
|
271
|
+
const ns = namespaces.get(m.ns) ?? {};
|
|
272
|
+
namespaces.set(m.ns, ns);
|
|
273
|
+
ns[m.method] = async (args) => {
|
|
274
|
+
if (!reg.callsBound.has(m.event))
|
|
275
|
+
throw new Error(`${reg.name}: $.${m.event}: not declared in uses.calls`);
|
|
276
|
+
const received = receivePayload(args === undefined ? {} : args, undefined, isProxy);
|
|
277
|
+
if ("refusal" in received)
|
|
278
|
+
throw new TypeError(`${reg.name}: $.${m.event}: takes one object — ${received.refusal}`);
|
|
279
|
+
if (m.pauses)
|
|
280
|
+
budget.pause();
|
|
281
|
+
try {
|
|
282
|
+
return await callMethod(m.event, received.payload, { frames: callerFrames, origin, signal });
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
if (m.pauses)
|
|
286
|
+
budget.resume();
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
const out = {};
|
|
291
|
+
for (const [ns, fns] of namespaces)
|
|
292
|
+
out[ns] = Object.freeze(fns);
|
|
293
|
+
return Object.freeze({ ...out, plugin: Object.freeze({ name: reg.name }) });
|
|
294
|
+
}
|
|
295
|
+
function runDispatch(event, st, e0, options) {
|
|
296
|
+
const frames = options.frames ?? [];
|
|
297
|
+
const origin = options.origin ?? ENGINE_ORIGIN;
|
|
298
|
+
const all = participants(event, e0, frames, options.participant);
|
|
299
|
+
const observers = all.filter((p) => !p.reentry && p.h.observe).map((p) => p.h);
|
|
300
|
+
const chain = all.filter((p) => !p.h.observe).map((p) => p.h);
|
|
301
|
+
const reentered = new Set(all.filter((p) => p.reentry).map((p) => p.h));
|
|
302
|
+
const skipped = [];
|
|
303
|
+
const producers = new Map();
|
|
304
|
+
const live = new Set();
|
|
305
|
+
const dispatchAc = new AbortController();
|
|
306
|
+
const terminal = { kind: "terminal" };
|
|
307
|
+
let settled = false;
|
|
308
|
+
let graceTimer;
|
|
309
|
+
let resolveOut = () => { };
|
|
310
|
+
let rejectOut = () => { };
|
|
311
|
+
const out = new Promise((res, rej) => {
|
|
312
|
+
resolveOut = res;
|
|
313
|
+
rejectOut = rej;
|
|
314
|
+
});
|
|
315
|
+
const signal = options.signal;
|
|
316
|
+
const onAbort = () => {
|
|
317
|
+
if (settled)
|
|
318
|
+
return;
|
|
319
|
+
if (st.abort === "grace") {
|
|
320
|
+
graceTimer ??= setTimeout(() => finish({ kind: "aborted" }), POST_ABORT_GRACE_MS);
|
|
321
|
+
unrefTimer(graceTimer);
|
|
322
|
+
}
|
|
323
|
+
else
|
|
324
|
+
finish({ kind: "aborted" });
|
|
325
|
+
};
|
|
326
|
+
function finish(o) {
|
|
327
|
+
if (settled)
|
|
328
|
+
return;
|
|
329
|
+
settled = true;
|
|
330
|
+
signal?.removeEventListener("abort", onAbort);
|
|
331
|
+
if (graceTimer !== undefined)
|
|
332
|
+
clearTimeout(graceTimer);
|
|
333
|
+
const why = new Error(`the ${event} dispatch settled`);
|
|
334
|
+
if (!("kind" in o) || o.kind !== "answered")
|
|
335
|
+
dispatchAc.abort(why);
|
|
336
|
+
for (const ac of live)
|
|
337
|
+
ac.abort(why);
|
|
338
|
+
live.clear();
|
|
339
|
+
if ("reject" in o)
|
|
340
|
+
rejectOut(o.reject);
|
|
341
|
+
else
|
|
342
|
+
resolveOut(Object.freeze(o));
|
|
343
|
+
}
|
|
344
|
+
const pendingRuns = new Set();
|
|
345
|
+
const track = (run) => {
|
|
346
|
+
pendingRuns.add(run);
|
|
347
|
+
const drop = () => void pendingRuns.delete(run);
|
|
348
|
+
run.then(drop, drop);
|
|
349
|
+
};
|
|
350
|
+
const handOn = (passed) => {
|
|
351
|
+
if (passed === e0)
|
|
352
|
+
return { snap: e0 };
|
|
353
|
+
const received = receivePayload(passed, e0, isProxy);
|
|
354
|
+
if ("refusal" in received)
|
|
355
|
+
return { violation: `next() takes the event object: ${received.refusal}` };
|
|
356
|
+
const k = pinnedKeyChanged(st.pinned, e0, received.payload);
|
|
357
|
+
return k === undefined ? { snap: received.payload } : { violation: `next() changed the pinned key "${k}"` };
|
|
358
|
+
};
|
|
359
|
+
const takeAnswer = (answer, s, e, h) => {
|
|
360
|
+
let taken = answer;
|
|
361
|
+
if (!s.answers.some((a) => Object.is(a, answer))) {
|
|
362
|
+
const received = receiveAnswer(answer, isProxy);
|
|
363
|
+
if ("refusal" in received)
|
|
364
|
+
return { violation: received.refusal };
|
|
365
|
+
taken = received.answer;
|
|
366
|
+
}
|
|
367
|
+
const below = s.pending > 0 ? [...s.answers, NEXT_IN_FLIGHT] : s.answers;
|
|
368
|
+
const why = answerViolation(taken, options.checkAnswer, e, answererOf(h), below);
|
|
369
|
+
return why !== undefined ? { violation: why } : { answer: taken };
|
|
370
|
+
};
|
|
371
|
+
const traceOf = (sink, index, plugin, tier, outcome, ms) => {
|
|
372
|
+
sink.push(Object.freeze({ index, plugin, tier, outcome, ms }));
|
|
373
|
+
};
|
|
374
|
+
function startBelow(state, selfTime, i, snap, nextFloors, myFrames) {
|
|
375
|
+
if (state.pending++ === 0)
|
|
376
|
+
selfTime.pause();
|
|
377
|
+
const below = [];
|
|
378
|
+
state.below = below;
|
|
379
|
+
const run = invoke(i + 1, snap, nextFloors, myFrames, below);
|
|
380
|
+
state.last = run;
|
|
381
|
+
const stopCounting = () => {
|
|
382
|
+
if (--state.pending === 0)
|
|
383
|
+
selfTime.resume();
|
|
384
|
+
};
|
|
385
|
+
run.then((v) => {
|
|
386
|
+
state.lastValue = { v };
|
|
387
|
+
state.answers.push(v);
|
|
388
|
+
stopCounting();
|
|
389
|
+
}, (err) => {
|
|
390
|
+
state.belowError = err;
|
|
391
|
+
stopCounting();
|
|
392
|
+
});
|
|
393
|
+
track(run);
|
|
394
|
+
return run;
|
|
395
|
+
}
|
|
396
|
+
async function invoke(i, e, floors, fr, sink) {
|
|
397
|
+
if (settled)
|
|
398
|
+
throw new Error(`the ${event} dispatch already settled`);
|
|
399
|
+
const h = chain[i];
|
|
400
|
+
if (h === undefined) {
|
|
401
|
+
const t0 = Date.now();
|
|
402
|
+
try {
|
|
403
|
+
const v = answerUpward(await options.bottom(e, Object.freeze({ frames: fr, signal: dispatchAc.signal, origin })));
|
|
404
|
+
traceOf(sink, i, "core", "core", "returned", Date.now() - t0);
|
|
405
|
+
return v;
|
|
406
|
+
}
|
|
407
|
+
catch (err) {
|
|
408
|
+
traceOf(sink, i, "core", "core", "rejected", Date.now() - t0);
|
|
409
|
+
throw err;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (bypassed(floors, h.reg.tier)) {
|
|
413
|
+
traceOf(sink, i, h.reg.name, h.reg.tier, "bypassed", 0);
|
|
414
|
+
return invoke(i + 1, e, floors, fr, sink);
|
|
415
|
+
}
|
|
416
|
+
return runHandler(h, i, e, floors, fr, sink);
|
|
417
|
+
}
|
|
418
|
+
function makeNext(base, call, to, caught) {
|
|
419
|
+
const next = (e) => call(e);
|
|
420
|
+
Object.defineProperties(next, {
|
|
421
|
+
to: { value: to, enumerable: true },
|
|
422
|
+
origin: { value: origin, enumerable: true },
|
|
423
|
+
signal: { value: base.signal, enumerable: true },
|
|
424
|
+
trace: { get: base.trace, enumerable: true },
|
|
425
|
+
budget: { get: () => base.budget.reading(), enumerable: true },
|
|
426
|
+
...(caught !== undefined ? { error: { value: caught.error, enumerable: true }, called: { value: caught.called, enumerable: true } } : {}),
|
|
427
|
+
});
|
|
428
|
+
const frozen = Object.freeze(next);
|
|
429
|
+
if (!hasNextShape(frozen))
|
|
430
|
+
throw new TypeError("next is malformed");
|
|
431
|
+
return frozen;
|
|
432
|
+
}
|
|
433
|
+
async function runHandler(h, i, e, floors, fr, sink) {
|
|
434
|
+
const name = h.reg.name;
|
|
435
|
+
const ac = new AbortController();
|
|
436
|
+
live.add(ac);
|
|
437
|
+
const budget = createSelfBudget(h.reg.budgetMs, () => ac.abort(new Error(`${name} ran past its ${h.reg.budgetMs}ms budget`)));
|
|
438
|
+
const myFrames = Object.freeze([...fr, Object.freeze({ kind: "handler", plugin: name, handler: h.index })]);
|
|
439
|
+
const state = {
|
|
440
|
+
pending: 0,
|
|
441
|
+
called: false,
|
|
442
|
+
below: [],
|
|
443
|
+
answers: [],
|
|
444
|
+
done: false,
|
|
445
|
+
};
|
|
446
|
+
const descend = (passed, nextFloors) => {
|
|
447
|
+
if (state.done || settled)
|
|
448
|
+
return Promise.reject(new Error(`${name}: next() after it settled`));
|
|
449
|
+
if (state.called) {
|
|
450
|
+
state.violated ??= "next() already called (a handler calls next once; its first run's answer stands)";
|
|
451
|
+
return Promise.reject(new Error(`${name}: next() already called`));
|
|
452
|
+
}
|
|
453
|
+
const handed = handOn(passed);
|
|
454
|
+
if ("violation" in handed) {
|
|
455
|
+
state.violated ??= handed.violation;
|
|
456
|
+
return Promise.reject(new Error(`${name}: ${state.violated}`));
|
|
457
|
+
}
|
|
458
|
+
state.called = true;
|
|
459
|
+
return startBelow(state, budget, i, handed.snap, nextFloors, myFrames);
|
|
460
|
+
};
|
|
461
|
+
const to = (passed, tier) => {
|
|
462
|
+
const why = nextToRefusal(h.reg.tier, tier);
|
|
463
|
+
if (why !== undefined)
|
|
464
|
+
return Promise.reject(new Error(`${name}: ${why}`));
|
|
465
|
+
return descend(passed, [...floors, { from: h.reg.tier, to: tier }]);
|
|
466
|
+
};
|
|
467
|
+
let result;
|
|
468
|
+
let failure;
|
|
469
|
+
let handlerP = Promise.resolve();
|
|
470
|
+
if (reentered.has(h)) {
|
|
471
|
+
failure = { cause: "reentry", reason: "not run: the dispatch re-entered a frame it is part of" };
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
const next = makeNext({ budget, signal: ac.signal, trace: () => Object.freeze([...state.below]) }, (x) => descend(x, floors), to);
|
|
475
|
+
const $ = dollarFor(h.reg, myFrames, budget, ac.signal);
|
|
476
|
+
handlerP = invokeNow(() => h.fn($, e, next));
|
|
477
|
+
try {
|
|
478
|
+
const raced = await Promise.race([handlerP, budget.expired]);
|
|
479
|
+
if (raced === "expired" && budget.isExpired())
|
|
480
|
+
failure = { cause: "timeout", reason: `ran past its ${h.reg.budgetMs}ms budget` };
|
|
481
|
+
else {
|
|
482
|
+
const taken = takeAnswer(raced, state, e, h);
|
|
483
|
+
if ("violation" in taken)
|
|
484
|
+
failure = { cause: "violation", reason: state.violated ?? taken.violation };
|
|
485
|
+
else if (state.violated !== undefined)
|
|
486
|
+
failure = { cause: "violation", reason: state.violated };
|
|
487
|
+
else
|
|
488
|
+
result = taken.answer;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
catch (err) {
|
|
492
|
+
failure = state.violated !== undefined ? { cause: "violation", reason: state.violated } : { cause: "threw", error: err, reason: `threw ${describe(err)}` };
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
state.done = true;
|
|
496
|
+
if (failure?.cause !== "timeout")
|
|
497
|
+
live.delete(ac);
|
|
498
|
+
const ms = budget.usedMs();
|
|
499
|
+
budget.clear();
|
|
500
|
+
if (failure === undefined) {
|
|
501
|
+
const passed = state.lastValue !== undefined && Object.is(state.lastValue.v, result);
|
|
502
|
+
if (!passed)
|
|
503
|
+
producers.set(result, name);
|
|
504
|
+
traceOf(sink, i, name, h.reg.tier, passed ? "passed" : "returned", ms);
|
|
505
|
+
sink.push(...state.below);
|
|
506
|
+
return result;
|
|
507
|
+
}
|
|
508
|
+
if (settled)
|
|
509
|
+
throw failure.error ?? new Error(`${name}: ${failure.reason}`);
|
|
510
|
+
if (failure.error === terminal || (failure.cause === "threw" && state.belowError !== undefined && failure.error === state.belowError && h.onCatch === undefined)) {
|
|
511
|
+
traceOf(sink, i, name, h.reg.tier, "rejected", ms);
|
|
512
|
+
throw failure.error;
|
|
513
|
+
}
|
|
514
|
+
if (failure.cause === "timeout") {
|
|
515
|
+
watchRunaway(handlerP, () => report(new Error(`${name}: ${event}: still running ${RUNAWAY_AFTER_MS}ms after its budget ran out; it ignores its signal`)));
|
|
516
|
+
}
|
|
517
|
+
const caught = h.onCatch !== undefined ? await runCatch(h, i, e, floors, myFrames, state, failure) : undefined;
|
|
518
|
+
if (caught !== undefined && "answer" in caught) {
|
|
519
|
+
if (failure.cause !== "violation" && failure.cause !== "reentry")
|
|
520
|
+
report(new Error(`${name}: ${event}: ${failure.reason}; its .catch answered`));
|
|
521
|
+
producers.set(caught.answer, name);
|
|
522
|
+
traceOf(sink, i, name, h.reg.tier, "caught", ms);
|
|
523
|
+
return caught.answer;
|
|
524
|
+
}
|
|
525
|
+
if (failure.cause === "threw" && state.belowError !== undefined && failure.error === state.belowError) {
|
|
526
|
+
traceOf(sink, i, name, h.reg.tier, "rejected", ms);
|
|
527
|
+
throw failure.error;
|
|
528
|
+
}
|
|
529
|
+
const reason = caught !== undefined ? `${failure.reason}; ${caught.problem}` : failure.reason;
|
|
530
|
+
if (st.failure === "refuse") {
|
|
531
|
+
if (failure.cause !== "violation")
|
|
532
|
+
report(new Error(`${name}: ${event}: ${reason} — failed closed: the dispatch ends here`));
|
|
533
|
+
traceOf(sink, i, name, h.reg.tier, "rejected", ms);
|
|
534
|
+
finish({ kind: "failed", registration: name, cause: failure.cause, reason, skipped: Object.freeze([...skipped]) });
|
|
535
|
+
throw terminal;
|
|
536
|
+
}
|
|
537
|
+
skipped.push(Object.freeze({ registration: name, cause: failure.cause, reason }));
|
|
538
|
+
const effect = state.last !== undefined ? MA : HA;
|
|
539
|
+
if (failure.cause !== "violation")
|
|
540
|
+
report(new Error(`${name}: ${event}: ${reason} — ${effect}`));
|
|
541
|
+
if (state.last !== undefined) {
|
|
542
|
+
traceOf(sink, i, name, h.reg.tier, failure.cause === "timeout" ? "expired" : "kept", ms);
|
|
543
|
+
return state.last;
|
|
544
|
+
}
|
|
545
|
+
traceOf(sink, i, name, h.reg.tier, failure.cause === "timeout" ? "expired" : "skipped", ms);
|
|
546
|
+
return invoke(i + 1, e, floors, fr, sink);
|
|
547
|
+
}
|
|
548
|
+
async function runCatch(h, i, e, floors, myFrames, state, failure) {
|
|
549
|
+
const onCatch = h.onCatch;
|
|
550
|
+
if (onCatch === undefined)
|
|
551
|
+
return { problem: "no .catch" };
|
|
552
|
+
const ac = new AbortController();
|
|
553
|
+
live.add(ac);
|
|
554
|
+
const budget = createSelfBudget(CATCH_BUDGET_MS, () => ac.abort(new Error(`${h.reg.name}: its .catch ran past its ${CATCH_BUDGET_MS}ms budget`)));
|
|
555
|
+
let done = false;
|
|
556
|
+
let violated;
|
|
557
|
+
const replay = (passed, nextFloors) => {
|
|
558
|
+
if (done || settled)
|
|
559
|
+
return Promise.reject(new Error(`${h.reg.name}: next() after its .catch settled`));
|
|
560
|
+
if (state.last !== undefined) {
|
|
561
|
+
const running = state.last;
|
|
562
|
+
budget.pause();
|
|
563
|
+
const resume = () => budget.resume();
|
|
564
|
+
running.then(resume, resume);
|
|
565
|
+
return running;
|
|
566
|
+
}
|
|
567
|
+
const handed = handOn(passed);
|
|
568
|
+
if ("violation" in handed) {
|
|
569
|
+
violated ??= handed.violation;
|
|
570
|
+
return Promise.reject(new Error(`${h.reg.name}: ${violated}`));
|
|
571
|
+
}
|
|
572
|
+
return startBelow(state, budget, i, handed.snap, nextFloors, myFrames);
|
|
573
|
+
};
|
|
574
|
+
const message = failure.cause === "threw" ? describe(failure.error) : failure.cause === "violation" ? failure.reason : undefined;
|
|
575
|
+
const error = Object.freeze({ kind: failure.cause, ...(message !== undefined ? { message } : {}), budget: CATCH_BUDGET_MS });
|
|
576
|
+
const next = makeNext({ budget, signal: ac.signal, trace: () => Object.freeze([...state.below]) }, (x) => replay(x, floors), (x, tier) => {
|
|
577
|
+
const why = nextToRefusal(h.reg.tier, tier);
|
|
578
|
+
return why !== undefined ? Promise.reject(new Error(`${h.reg.name}: ${why}`)) : replay(x, [...floors, { from: h.reg.tier, to: tier }]);
|
|
579
|
+
}, { error, called: state.called });
|
|
580
|
+
try {
|
|
581
|
+
const raced = await Promise.race([invokeNow(() => onCatch(dollarFor(h.reg, myFrames, budget, ac.signal), e, next)), budget.expired]);
|
|
582
|
+
if (raced === "expired" && budget.isExpired())
|
|
583
|
+
return { problem: `its .catch ran past its ${CATCH_BUDGET_MS}ms budget` };
|
|
584
|
+
if (violated !== undefined)
|
|
585
|
+
return { problem: `its .catch ${violated}` };
|
|
586
|
+
const taken = takeAnswer(raced, state, e, h);
|
|
587
|
+
return "violation" in taken ? { problem: `its .catch ${taken.violation}` } : { answer: taken.answer };
|
|
588
|
+
}
|
|
589
|
+
catch (err) {
|
|
590
|
+
return { problem: violated !== undefined ? `its .catch: ${violated}` : `its .catch threw ${describe(err)}` };
|
|
591
|
+
}
|
|
592
|
+
finally {
|
|
593
|
+
done = true;
|
|
594
|
+
if (!budget.isExpired())
|
|
595
|
+
live.delete(ac);
|
|
596
|
+
budget.clear();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
async function runObserver(h, fr) {
|
|
600
|
+
const name = h.reg.name;
|
|
601
|
+
const ac = new AbortController();
|
|
602
|
+
live.add(ac);
|
|
603
|
+
const budget = createSelfBudget(h.reg.budgetMs, () => ac.abort(new Error(`${name} ran past its ${h.reg.budgetMs}ms budget`)));
|
|
604
|
+
const myFrames = Object.freeze([...fr, Object.freeze({ kind: "handler", plugin: name, handler: h.index })]);
|
|
605
|
+
const refuse = () => Promise.reject(new Error(`${name}: an observe handler is not in the chain; next() is unavailable`));
|
|
606
|
+
const next = makeNext({ budget, signal: ac.signal, trace: () => Object.freeze([]) }, refuse, refuse);
|
|
607
|
+
const verdict = (r) => {
|
|
608
|
+
if (r === undefined)
|
|
609
|
+
return;
|
|
610
|
+
report(new Error(`${name}: ${event}: an observe handler returned a verdict — not adopted; an observe handler answers undefined`), "observational-hook-verdict-ignored");
|
|
611
|
+
};
|
|
612
|
+
try {
|
|
613
|
+
const raced = await Promise.race([invokeNow(() => h.fn(dollarFor(h.reg, myFrames, budget, ac.signal), detachedCopy(e0), next)), budget.expired]);
|
|
614
|
+
if (raced === "expired" && budget.isExpired())
|
|
615
|
+
throw new Error(`ran past its ${h.reg.budgetMs}ms budget`);
|
|
616
|
+
verdict(raced);
|
|
617
|
+
}
|
|
618
|
+
catch (err) {
|
|
619
|
+
if (settled)
|
|
620
|
+
return;
|
|
621
|
+
report(new Error(`${name}: ${event}: an observe handler failed (${describe(err)}) — skipped`));
|
|
622
|
+
const onCatch = h.onCatch;
|
|
623
|
+
if (onCatch !== undefined) {
|
|
624
|
+
const cause = budget.isExpired() ? "timeout" : "threw";
|
|
625
|
+
budget.clear();
|
|
626
|
+
const cac = new AbortController();
|
|
627
|
+
live.add(cac);
|
|
628
|
+
const catchBudget = createSelfBudget(CATCH_BUDGET_MS, () => cac.abort(new Error(`${name}: its .catch ran past its ${CATCH_BUDGET_MS}ms budget`)));
|
|
629
|
+
const cnext = makeNext({ budget: catchBudget, signal: cac.signal, trace: () => Object.freeze([]) }, refuse, refuse, {
|
|
630
|
+
error: Object.freeze({ kind: cause, ...(cause === "threw" ? { message: describe(err) } : {}), budget: CATCH_BUDGET_MS }),
|
|
631
|
+
called: false,
|
|
632
|
+
});
|
|
633
|
+
try {
|
|
634
|
+
const caught = await Promise.race([invokeNow(() => onCatch(dollarFor(h.reg, myFrames, catchBudget, cac.signal), detachedCopy(e0), cnext)), catchBudget.expired]);
|
|
635
|
+
if (!(caught === "expired" && catchBudget.isExpired()))
|
|
636
|
+
verdict(caught);
|
|
637
|
+
}
|
|
638
|
+
catch {
|
|
639
|
+
}
|
|
640
|
+
finally {
|
|
641
|
+
if (!catchBudget.isExpired())
|
|
642
|
+
live.delete(cac);
|
|
643
|
+
catchBudget.clear();
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
finally {
|
|
648
|
+
if (!budget.isExpired())
|
|
649
|
+
live.delete(ac);
|
|
650
|
+
budget.clear();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (signal?.aborted === true && st.abort !== "grace") {
|
|
654
|
+
finish({ kind: "aborted" });
|
|
655
|
+
return out;
|
|
656
|
+
}
|
|
657
|
+
const root = [];
|
|
658
|
+
void (async () => {
|
|
659
|
+
for (const o of observers) {
|
|
660
|
+
if (settled)
|
|
661
|
+
return;
|
|
662
|
+
await runObserver(o, frames);
|
|
663
|
+
}
|
|
664
|
+
if (settled)
|
|
665
|
+
return;
|
|
666
|
+
const answer = await invoke(0, e0, [], frames, root);
|
|
667
|
+
while (st.failure === "refuse" && pendingRuns.size > 0 && !settled)
|
|
668
|
+
await Promise.allSettled([...pendingRuns]);
|
|
669
|
+
finish({ kind: "answered", answer, ...(producers.has(answer) ? { answeredBy: producers.get(answer) } : {}), skipped: Object.freeze([...skipped]) });
|
|
670
|
+
})().catch((err) => {
|
|
671
|
+
if (err === terminal || settled)
|
|
672
|
+
return;
|
|
673
|
+
finish({ reject: err });
|
|
674
|
+
});
|
|
675
|
+
if (signal !== undefined) {
|
|
676
|
+
if (signal.aborted)
|
|
677
|
+
queueMicrotask(onAbort);
|
|
678
|
+
else
|
|
679
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
680
|
+
}
|
|
681
|
+
return out;
|
|
682
|
+
}
|
|
683
|
+
return bus;
|
|
684
|
+
}
|
|
685
|
+
function admits(participant, h) {
|
|
686
|
+
return participant === undefined || participant(Object.freeze({ plugin: h.reg.name, seat: h.reg.seat, observe: h.observe }));
|
|
687
|
+
}
|
|
688
|
+
function answererOf(h) {
|
|
689
|
+
return { plugin: h.reg.name, seat: h.reg.seat, tier: h.reg.tier };
|
|
690
|
+
}
|
|
691
|
+
function hasNextShape(f) {
|
|
692
|
+
return typeof f === "function" && "to" in f && "trace" in f && "budget" in f && "signal" in f && "origin" in f;
|
|
693
|
+
}
|
|
694
|
+
function invokeNow(f) {
|
|
695
|
+
try {
|
|
696
|
+
return Promise.resolve(f());
|
|
697
|
+
}
|
|
698
|
+
catch (err) {
|
|
699
|
+
return Promise.reject(err);
|
|
700
|
+
}
|
|
701
|
+
}
|