@pellux/goodvibes-sdk 1.0.0 → 1.1.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/dist/contracts/artifacts/operator-contract.json +1320 -10
- package/dist/events/communication.d.ts +1 -1
- package/dist/platform/agents/orchestrator-runner.d.ts +5 -5
- package/dist/platform/agents/orchestrator-runner.js +6 -6
- package/dist/platform/agents/orchestrator.d.ts +4 -4
- package/dist/platform/agents/orchestrator.js +2 -2
- package/dist/platform/agents/wrfc-controller.d.ts +1 -1
- package/dist/platform/agents/wrfc-controller.js +3 -3
- package/dist/platform/calendar/index.d.ts +2 -2
- package/dist/platform/calendar/index.js +3 -3
- package/dist/platform/calendar/oauth-providers.d.ts +1 -1
- package/dist/platform/calendar/oauth-providers.js +1 -1
- package/dist/platform/calendar/oauth-types.d.ts +1 -1
- package/dist/platform/calendar/oauth-types.js +1 -1
- package/dist/platform/companion/companion-chat-branching.d.ts +66 -0
- package/dist/platform/companion/companion-chat-branching.d.ts.map +1 -0
- package/dist/platform/companion/companion-chat-branching.js +142 -0
- package/dist/platform/companion/companion-chat-broker-bridge.d.ts +1 -1
- package/dist/platform/companion/companion-chat-broker-bridge.d.ts.map +1 -1
- package/dist/platform/companion/companion-chat-broker-sync.d.ts +2 -2
- package/dist/platform/companion/companion-chat-broker-sync.d.ts.map +1 -1
- package/dist/platform/companion/companion-chat-broker-sync.js +1 -1
- package/dist/platform/companion/companion-chat-manager.d.ts +26 -5
- package/dist/platform/companion/companion-chat-manager.d.ts.map +1 -1
- package/dist/platform/companion/companion-chat-manager.js +67 -81
- package/dist/platform/companion/companion-chat-routes.d.ts.map +1 -1
- package/dist/platform/companion/companion-chat-routes.js +77 -1
- package/dist/platform/companion/companion-chat-turn-execution.d.ts +61 -0
- package/dist/platform/companion/companion-chat-turn-execution.d.ts.map +1 -0
- package/dist/platform/companion/companion-chat-turn-execution.js +107 -0
- package/dist/platform/companion/companion-chat-types.d.ts +67 -0
- package/dist/platform/companion/companion-chat-types.d.ts.map +1 -1
- package/dist/platform/config/credential-status.d.ts +1 -1
- package/dist/platform/config/credential-status.js +1 -1
- package/dist/platform/config/index.d.ts +1 -1
- package/dist/platform/config/index.js +1 -1
- package/dist/platform/config/manager.d.ts +1 -1
- package/dist/platform/config/manager.js +1 -1
- package/dist/platform/config/migrations.d.ts +2 -2
- package/dist/platform/config/migrations.js +2 -2
- package/dist/platform/config/schema-domain-runtime.d.ts +8 -0
- package/dist/platform/config/schema-domain-runtime.d.ts.map +1 -1
- package/dist/platform/config/schema-domain-runtime.js +32 -0
- package/dist/platform/config/schema-types.d.ts +10 -2
- package/dist/platform/config/schema-types.d.ts.map +1 -1
- package/dist/platform/control-plane/gateway-scope-enforcement.js +2 -2
- package/dist/platform/control-plane/index.d.ts +2 -0
- package/dist/platform/control-plane/index.d.ts.map +1 -1
- package/dist/platform/control-plane/index.js +5 -1
- package/dist/platform/control-plane/invoke-input-validation.d.ts +1 -1
- package/dist/platform/control-plane/invoke-input-validation.js +1 -1
- package/dist/platform/control-plane/method-catalog-calendar.d.ts +2 -2
- package/dist/platform/control-plane/method-catalog-calendar.js +2 -2
- package/dist/platform/control-plane/method-catalog-channels.js +3 -3
- package/dist/platform/control-plane/method-catalog-control-automation.js +4 -4
- package/dist/platform/control-plane/method-catalog-control-companion.d.ts +1 -1
- package/dist/platform/control-plane/method-catalog-control-companion.d.ts.map +1 -1
- package/dist/platform/control-plane/method-catalog-control-companion.js +43 -0
- package/dist/platform/control-plane/method-catalog-control-core.js +3 -3
- package/dist/platform/control-plane/method-catalog-email.d.ts +1 -1
- package/dist/platform/control-plane/method-catalog-email.js +1 -1
- package/dist/platform/control-plane/method-catalog-fleet.d.ts +1 -1
- package/dist/platform/control-plane/method-catalog-push.d.ts +30 -0
- package/dist/platform/control-plane/method-catalog-push.d.ts.map +1 -0
- package/dist/platform/control-plane/method-catalog-push.js +80 -0
- package/dist/platform/control-plane/method-catalog-route-reconcile.d.ts +1 -1
- package/dist/platform/control-plane/method-catalog-runtime.d.ts.map +1 -1
- package/dist/platform/control-plane/method-catalog-runtime.js +83 -1
- package/dist/platform/control-plane/method-catalog.d.ts.map +1 -1
- package/dist/platform/control-plane/method-catalog.js +2 -0
- package/dist/platform/control-plane/operator-contract-schemas-fleet.js +1 -1
- package/dist/platform/control-plane/operator-contract-schemas-runtime.d.ts +8 -0
- package/dist/platform/control-plane/operator-contract-schemas-runtime.d.ts.map +1 -1
- package/dist/platform/control-plane/operator-contract-schemas-runtime.js +43 -0
- package/dist/platform/control-plane/routes/checkpoints.d.ts +1 -1
- package/dist/platform/control-plane/routes/fleet.d.ts +2 -2
- package/dist/platform/control-plane/routes/fleet.js +1 -1
- package/dist/platform/control-plane/routes/gateway-verb-error.d.ts +1 -1
- package/dist/platform/control-plane/routes/gateway-verb-error.js +1 -1
- package/dist/platform/control-plane/routes/index.js +1 -1
- package/dist/platform/control-plane/routes/invocation-params.d.ts +1 -1
- package/dist/platform/control-plane/routes/push.d.ts +26 -0
- package/dist/platform/control-plane/routes/push.d.ts.map +1 -0
- package/dist/platform/control-plane/routes/push.js +104 -0
- package/dist/platform/control-plane/routes/register-gateway-verb-groups.d.ts +31 -0
- package/dist/platform/control-plane/routes/register-gateway-verb-groups.d.ts.map +1 -0
- package/dist/platform/control-plane/routes/register-gateway-verb-groups.js +16 -0
- package/dist/platform/control-plane/routes/register-w3-s2.d.ts +2 -2
- package/dist/platform/control-plane/routes/session-search.d.ts +4 -4
- package/dist/platform/control-plane/session-broker.d.ts +1 -1
- package/dist/platform/control-plane/session-broker.js +1 -1
- package/dist/platform/control-plane/session-store-importer.d.ts +1 -1
- package/dist/platform/control-plane/session-store-importer.js +1 -1
- package/dist/platform/control-plane/session-types.d.ts +1 -1
- package/dist/platform/core/orchestrator-runtime.d.ts +4 -4
- package/dist/platform/core/orchestrator-tool-runtime.d.ts +1 -1
- package/dist/platform/core/orchestrator-turn-loop.d.ts +6 -6
- package/dist/platform/core/orchestrator-turn-loop.d.ts.map +1 -1
- package/dist/platform/core/orchestrator-turn-loop.js +23 -22
- package/dist/platform/core/orchestrator.d.ts +10 -10
- package/dist/platform/core/orchestrator.d.ts.map +1 -1
- package/dist/platform/core/orchestrator.js +8 -8
- package/dist/platform/daemon/boot.d.ts +6 -0
- package/dist/platform/daemon/boot.d.ts.map +1 -1
- package/dist/platform/daemon/boot.js +1 -0
- package/dist/platform/daemon/control-plane.js +2 -2
- package/dist/platform/daemon/facade.d.ts +4 -7
- package/dist/platform/daemon/facade.d.ts.map +1 -1
- package/dist/platform/daemon/facade.js +5 -7
- package/dist/platform/daemon/http/router-session-broker-adapter.d.ts +1 -1
- package/dist/platform/daemon/http/router.d.ts +1 -0
- package/dist/platform/daemon/http/router.d.ts.map +1 -1
- package/dist/platform/daemon/http/router.js +36 -19
- package/dist/platform/daemon/http/runtime-route-types.d.ts +1 -1
- package/dist/platform/daemon/http/runtime-route-types.d.ts.map +1 -1
- package/dist/platform/daemon/http/webui-serving.d.ts +68 -0
- package/dist/platform/daemon/http/webui-serving.d.ts.map +1 -0
- package/dist/platform/daemon/http/webui-serving.js +230 -0
- package/dist/platform/knowledge/knowledge-api.d.ts +1 -1
- package/dist/platform/orchestration/budget.d.ts +2 -2
- package/dist/platform/orchestration/cancellation.d.ts +2 -2
- package/dist/platform/orchestration/controller-compat.d.ts +2 -3
- package/dist/platform/orchestration/controller-compat.d.ts.map +1 -1
- package/dist/platform/orchestration/dirty-guard.js +1 -1
- package/dist/platform/orchestration/engine.d.ts.map +1 -1
- package/dist/platform/orchestration/engine.js +3 -4
- package/dist/platform/orchestration/persistence.js +2 -2
- package/dist/platform/orchestration/phase-runner.d.ts +4 -4
- package/dist/platform/orchestration/scheduler.d.ts +1 -1
- package/dist/platform/orchestration/types.d.ts +3 -3
- package/dist/platform/presentation/glyphs.d.ts +1 -1
- package/dist/platform/presentation/glyphs.js +1 -1
- package/dist/platform/presentation/index.d.ts +3 -3
- package/dist/platform/presentation/index.js +3 -3
- package/dist/platform/presentation/thinking-phrases.d.ts +1 -1
- package/dist/platform/presentation/thinking-phrases.js +1 -1
- package/dist/platform/presentation/waiting-wording.d.ts +1 -1
- package/dist/platform/presentation/waiting-wording.js +1 -1
- package/dist/platform/push/delivery.d.ts +48 -0
- package/dist/platform/push/delivery.d.ts.map +1 -0
- package/dist/platform/push/delivery.js +117 -0
- package/dist/platform/push/encryption.d.ts +41 -0
- package/dist/platform/push/encryption.d.ts.map +1 -0
- package/dist/platform/push/encryption.js +82 -0
- package/dist/platform/push/index.d.ts +17 -0
- package/dist/platform/push/index.d.ts.map +1 -0
- package/dist/platform/push/index.js +10 -0
- package/dist/platform/push/service.d.ts +75 -0
- package/dist/platform/push/service.d.ts.map +1 -0
- package/dist/platform/push/service.js +95 -0
- package/dist/platform/push/subscription-store.d.ts +50 -0
- package/dist/platform/push/subscription-store.d.ts.map +1 -0
- package/dist/platform/push/subscription-store.js +123 -0
- package/dist/platform/push/types.d.ts +68 -0
- package/dist/platform/push/types.d.ts.map +1 -0
- package/dist/platform/push/types.js +13 -0
- package/dist/platform/push/vapid.d.ts +54 -0
- package/dist/platform/push/vapid.d.ts.map +1 -0
- package/dist/platform/push/vapid.js +113 -0
- package/dist/platform/runtime/feature-flags/flags.js +3 -3
- package/dist/platform/runtime/fleet/adapters/agent.d.ts +2 -2
- package/dist/platform/runtime/fleet/adapters/agent.d.ts.map +1 -1
- package/dist/platform/runtime/fleet/adapters/agent.js +4 -4
- package/dist/platform/runtime/fleet/adapters/automation.d.ts +1 -1
- package/dist/platform/runtime/fleet/adapters/automation.js +1 -1
- package/dist/platform/runtime/fleet/adapters/code-index.d.ts +1 -1
- package/dist/platform/runtime/fleet/adapters/code-index.js +1 -1
- package/dist/platform/runtime/fleet/adapters/orchestration.js +1 -1
- package/dist/platform/runtime/fleet/adapters/schedule.d.ts +4 -4
- package/dist/platform/runtime/fleet/adapters/schedule.js +4 -4
- package/dist/platform/runtime/fleet/adapters/trigger.d.ts +3 -4
- package/dist/platform/runtime/fleet/adapters/trigger.d.ts.map +1 -1
- package/dist/platform/runtime/fleet/adapters/trigger.js +3 -4
- package/dist/platform/runtime/fleet/adapters/wrfc.js +1 -1
- package/dist/platform/runtime/fleet/registry.d.ts +7 -7
- package/dist/platform/runtime/fleet/registry.d.ts.map +1 -1
- package/dist/platform/runtime/fleet/registry.js +3 -3
- package/dist/platform/runtime/fleet/types.d.ts +9 -9
- package/dist/platform/runtime/fleet/types.d.ts.map +1 -1
- package/dist/platform/runtime/memory-spine/client.d.ts +127 -0
- package/dist/platform/runtime/memory-spine/client.d.ts.map +1 -0
- package/dist/platform/runtime/memory-spine/client.js +113 -0
- package/dist/platform/runtime/memory-spine/index.d.ts +11 -0
- package/dist/platform/runtime/memory-spine/index.d.ts.map +1 -0
- package/dist/platform/runtime/memory-spine/index.js +10 -0
- package/dist/platform/runtime/operator-client.d.ts +1 -1
- package/dist/platform/runtime/services.d.ts +6 -6
- package/dist/platform/runtime/services.d.ts.map +1 -1
- package/dist/platform/runtime/services.js +9 -9
- package/dist/platform/runtime/session-spine/union-cache.d.ts +1 -1
- package/dist/platform/runtime/session-spine/union-cache.js +1 -1
- package/dist/platform/state/canonical-memory.d.ts +7 -7
- package/dist/platform/state/canonical-memory.js +8 -8
- package/dist/platform/state/code-index-chunking.js +1 -1
- package/dist/platform/state/code-index-db.d.ts +1 -1
- package/dist/platform/state/code-index-store.js +1 -1
- package/dist/platform/state/index.d.ts +2 -2
- package/dist/platform/state/index.d.ts.map +1 -1
- package/dist/platform/state/index.js +1 -1
- package/dist/platform/state/memory-recall-contract.d.ts +59 -4
- package/dist/platform/state/memory-recall-contract.d.ts.map +1 -1
- package/dist/platform/state/memory-recall-contract.js +79 -3
- package/dist/platform/state/memory-registry.d.ts +8 -0
- package/dist/platform/state/memory-registry.d.ts.map +1 -1
- package/dist/platform/state/memory-registry.js +10 -0
- package/dist/platform/state/memory-vector-store.js +1 -1
- package/dist/platform/state/sqlite-vec-loader.d.ts +1 -1
- package/dist/platform/state/sqlite-vec-loader.js +1 -1
- package/dist/platform/state/vibe-projection.d.ts +3 -3
- package/dist/platform/state/vibe-projection.js +3 -3
- package/dist/platform/tools/agent/manager.d.ts +10 -10
- package/dist/platform/tools/agent/manager.js +7 -7
- package/dist/platform/tools/exec/runtime.js +5 -5
- package/dist/platform/tools/exec/schema.d.ts +1 -1
- package/dist/platform/tools/exec/schema.d.ts.map +1 -1
- package/dist/platform/tools/fetch/runtime.d.ts +1 -1
- package/dist/platform/tools/registry.d.ts +1 -1
- package/dist/platform/tools/registry.js +1 -1
- package/dist/platform/types/tools.d.ts +1 -1
- package/dist/platform/utils/request-body.d.ts.map +1 -1
- package/dist/platform/utils/request-body.js +50 -5
- package/dist/platform/version.js +1 -1
- package/package.json +13 -9
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
|
|
2
2
|
/**
|
|
3
|
-
* Controller-compat (
|
|
4
|
-
* migration
|
|
5
|
-
* divergences section).
|
|
3
|
+
* Controller-compat (see CHANGELOG 0.38.0) — stage 1 of the 3-stage WrfcController
|
|
4
|
+
* migration.
|
|
6
5
|
*
|
|
7
6
|
* `fromChainSpec()` produces the canned two-phase engineer->review
|
|
8
7
|
* WORKSTREAM SPEC that a `WrfcController.createChain(ownerRecord)` call
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller-compat.d.ts","sourceRoot":"","sources":["../../../src/platform/orchestration/controller-compat.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF
|
|
1
|
+
{"version":3,"file":"controller-compat.d.ts","sourceRoot":"","sources":["../../../src/platform/orchestration/controller-compat.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,eAAe,EAAE,QAAQ,SAAI,GAAG,SAAS,EAAE,CAK5F;AAED,wBAAgB,aAAa,CAC3B,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,EAC7C,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,aAAa,CAAC,GACxD,qBAAqB,CAOvB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
|
|
2
2
|
/**
|
|
3
|
-
* Dirty-residue guard (
|
|
3
|
+
* Dirty-residue guard (see CHANGELOG 0.38.0) — prevents an orchestration
|
|
4
4
|
* engine run's scoped commit from sweeping in uncommitted changes that were
|
|
5
5
|
* ALREADY sitting in the working tree before this engine launched (typically
|
|
6
6
|
* residue left behind by a previously killed run sharing the same
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/platform/orchestration/engine.ts"],"names":[],"mappings":"AAAA,qFAAqF;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/platform/orchestration/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
|
|
2
2
|
/**
|
|
3
|
-
* OrchestrationEngine (
|
|
3
|
+
* OrchestrationEngine (see CHANGELOG 0.38.0) — owns Workstream state and drives the
|
|
4
4
|
* pipeline. WRAPS a canned/authored workstream; does not rewrite or touch
|
|
5
|
-
* WrfcController (stage 1 of the 3-stage migration — see controller-compat.ts
|
|
6
|
-
* and the work-order report).
|
|
5
|
+
* WrfcController (stage 1 of the 3-stage migration — see controller-compat.ts).
|
|
7
6
|
*
|
|
8
7
|
* The tick loop is reactive, not timer-driven: `start()` runs one tick;
|
|
9
8
|
* every phase-run completion re-runs tick() for its workstream. Because JS
|
|
@@ -49,7 +48,7 @@ export function createOrchestrationEngine(deps) {
|
|
|
49
48
|
listeners.add(listener);
|
|
50
49
|
return () => listeners.delete(listener);
|
|
51
50
|
}
|
|
52
|
-
// Dirty-residue guard (
|
|
51
|
+
// Dirty-residue guard (see CHANGELOG 0.38.0): snapshot the working tree's
|
|
53
52
|
// dirty paths + content hashes ONCE, right at engine launch (synchronous —
|
|
54
53
|
// see dirty-guard.ts's doc comment for why this must not be a promise
|
|
55
54
|
// backed by real subprocess I/O), before any phase of this run has had a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
|
|
2
2
|
/**
|
|
3
|
-
* Persistence (
|
|
3
|
+
* Persistence (see CHANGELOG 0.38.0) — mirrors the WrfcController chain seams
|
|
4
4
|
* exactly: serializeChain:323 / deserializeChain:345 (including the
|
|
5
5
|
* future-schemaVersion-reject guard at :364) / importChain:402. Writes to
|
|
6
6
|
* `.goodvibes/orchestration/<workstreamId>.json` — SEPARATE from the TUI's
|
|
@@ -164,7 +164,7 @@ export function attachDebouncedWriter(projectRoot, getWorkstream, getCompletedRe
|
|
|
164
164
|
timers.set(workstreamId, timer);
|
|
165
165
|
}
|
|
166
166
|
const unsubscribe = subscribe((event) => {
|
|
167
|
-
// 'dirty-tree-at-launch' (
|
|
167
|
+
// 'dirty-tree-at-launch' (see CHANGELOG 0.38.0) is engine-wide, not
|
|
168
168
|
// workstream-scoped — it has no workstreamId to schedule a write for.
|
|
169
169
|
if (event.type === 'dirty-tree-at-launch')
|
|
170
170
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
|
|
2
2
|
/**
|
|
3
|
-
* Phase-runner (
|
|
3
|
+
* Phase-runner (see CHANGELOG 0.38.0) — runs one WorkItem through one Phase: spawn
|
|
4
4
|
* agent, await completion, verify claims, run gates, commit, cleanup.
|
|
5
5
|
*
|
|
6
6
|
* REUSES the hardened WRFC primitives verbatim (same functions WrfcController
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* itself has either. This module therefore mirrors WrfcController's ACTUAL
|
|
27
27
|
* (shared-directory) behavior rather than the brief's aspirational
|
|
28
28
|
* per-item-isolated-worktree fan-out; true fan-out isolation is a valuable,
|
|
29
|
-
* separately-scoped follow-up
|
|
29
|
+
* separately-scoped follow-up.
|
|
30
30
|
*
|
|
31
31
|
* SECOND REALITY-WINS DIVERGENCE: AgentManager.spawn()'s root-spawn
|
|
32
32
|
* normalization (tools/agent/wrfc-batch-policy.ts isRootReviewRoleTask) force
|
|
@@ -84,8 +84,8 @@ export interface PhaseRunnerDeps {
|
|
|
84
84
|
readonly priceUsage?: ((model: string | undefined, usage: WorkItemUsage) => number | null) | undefined;
|
|
85
85
|
readonly skipClaimVerification?: boolean | undefined;
|
|
86
86
|
/**
|
|
87
|
-
* The dirty-tree snapshot taken synchronously at engine launch (
|
|
88
|
-
*
|
|
87
|
+
* The dirty-tree snapshot taken synchronously at engine launch (see
|
|
88
|
+
* CHANGELOG 0.38.0 and dirty-guard.ts). Absent (undefined) degrades to
|
|
89
89
|
* today's behavior: no exclusion, every candidate path is committed.
|
|
90
90
|
*/
|
|
91
91
|
readonly launchDirtySnapshot?: DirtyLaunchSnapshot | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
|
|
2
2
|
/**
|
|
3
|
-
* Scheduler (
|
|
3
|
+
* Scheduler (see CHANGELOG 0.38.0) — pure capacity-matching helpers, no side
|
|
4
4
|
* effects. The hard departure from WrfcController's pairwise
|
|
5
5
|
* engineer<->reviewer binding (startReview:883/startFix:1042): each tick,
|
|
6
6
|
* for every phase in ordinal order, free capacity slots (capacity minus
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
|
|
2
2
|
/**
|
|
3
|
-
* Orchestration engine — the model (
|
|
3
|
+
* Orchestration engine — the model (see CHANGELOG 0.38.0).
|
|
4
4
|
*
|
|
5
5
|
* A phase/work-item pipeline layered OVER (not replacing) WrfcController. The
|
|
6
6
|
* hard departure from WrfcController is pipeline semantics: an item advances
|
|
@@ -297,7 +297,7 @@ export interface GateOutcome {
|
|
|
297
297
|
readonly unsatisfiedConstraintIds?: readonly string[] | undefined;
|
|
298
298
|
}
|
|
299
299
|
/**
|
|
300
|
-
* Recorded on a PhaseResult when a scoped commit (
|
|
300
|
+
* Recorded on a PhaseResult when a scoped commit (see CHANGELOG 0.38.0)
|
|
301
301
|
* excluded one or more candidate paths because they were already dirty
|
|
302
302
|
* before this engine run launched and this phase never actually touched
|
|
303
303
|
* them (see dirty-guard.ts's excludeUntouchedLaunchResidue). `skipped: true`
|
|
@@ -521,7 +521,7 @@ export type OrchestrationEvent = {
|
|
|
521
521
|
readonly disposition: 'adopted' | 'reported';
|
|
522
522
|
}
|
|
523
523
|
/**
|
|
524
|
-
* Emitted once per engine instance (
|
|
524
|
+
* Emitted once per engine instance (see CHANGELOG 0.38.0), right after the
|
|
525
525
|
* launch-time dirty-tree snapshot resolves, ONLY when it is non-empty.
|
|
526
526
|
* Engine-wide, not workstream-scoped — `workstreamId` is absent (unlike
|
|
527
527
|
* every other variant above) because it fires before any workstream is
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and src/renderer/status-glyphs.ts (STATE_GLYPHS).
|
|
5
5
|
*
|
|
6
6
|
* This is one of the four genuinely-duplicated presentation tables named by the
|
|
7
|
-
*
|
|
7
|
+
* renderer/input parity audit (see CHANGELOG 1.0.0; both the TUI and the agent shipped a near-twin
|
|
8
8
|
* copy). The TUI is the reference: it is the more-complete, more-recently-fixed
|
|
9
9
|
* copy, and per the presentation-contract decision record its `status` group is
|
|
10
10
|
* the one both renderers converge on.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and src/renderer/status-glyphs.ts (STATE_GLYPHS).
|
|
5
5
|
*
|
|
6
6
|
* This is one of the four genuinely-duplicated presentation tables named by the
|
|
7
|
-
*
|
|
7
|
+
* renderer/input parity audit (see CHANGELOG 1.0.0; both the TUI and the agent shipped a near-twin
|
|
8
8
|
* copy). The TUI is the reference: it is the more-complete, more-recently-fixed
|
|
9
9
|
* copy, and per the presentation-contract decision record its `status` group is
|
|
10
10
|
* the one both renderers converge on.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @pellux/goodvibes-sdk/platform/presentation
|
|
3
3
|
*
|
|
4
4
|
* The presentation contract — the four genuinely-duplicated presentation
|
|
5
|
-
* tables named by the
|
|
5
|
+
* tables named by the renderer/input parity audit (see CHANGELOG 1.0.0; goodvibes-tui vs
|
|
6
6
|
* goodvibes-agent), hoisted into one pure, dependency-free module per Mike's
|
|
7
7
|
* SDK-boundary rule (machinery needed by 2+ surfaces => SDK):
|
|
8
8
|
*
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* The TUI is the reference for every value here; dark stays byte-identical to
|
|
16
16
|
* today's TUI. See docs/decisions/2026-07-05-presentation-contract-sdk-extraction.md
|
|
17
17
|
* for the full decision record, including the GLYPHS status-group reconciliation
|
|
18
|
-
* ruling and the consumption plan (agent this
|
|
19
|
-
* a
|
|
18
|
+
* ruling and the consumption plan (the agent picks this up via R4; the TUI swap is
|
|
19
|
+
* deferred to a future coherence pass).
|
|
20
20
|
*
|
|
21
21
|
* PURE — no fs, no terminal I/O, no process globals. Painting stays
|
|
22
22
|
* renderer-owned; this module owns only tokens and pure wording functions.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @pellux/goodvibes-sdk/platform/presentation
|
|
3
3
|
*
|
|
4
4
|
* The presentation contract — the four genuinely-duplicated presentation
|
|
5
|
-
* tables named by the
|
|
5
|
+
* tables named by the renderer/input parity audit (see CHANGELOG 1.0.0; goodvibes-tui vs
|
|
6
6
|
* goodvibes-agent), hoisted into one pure, dependency-free module per Mike's
|
|
7
7
|
* SDK-boundary rule (machinery needed by 2+ surfaces => SDK):
|
|
8
8
|
*
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* The TUI is the reference for every value here; dark stays byte-identical to
|
|
16
16
|
* today's TUI. See docs/decisions/2026-07-05-presentation-contract-sdk-extraction.md
|
|
17
17
|
* for the full decision record, including the GLYPHS status-group reconciliation
|
|
18
|
-
* ruling and the consumption plan (agent this
|
|
19
|
-
* a
|
|
18
|
+
* ruling and the consumption plan (the agent picks this up via R4; the TUI swap is
|
|
19
|
+
* deferred to a future coherence pass).
|
|
20
20
|
*
|
|
21
21
|
* PURE — no fs, no terminal I/O, no process globals. Painting stays
|
|
22
22
|
* renderer-owned; this module owns only tokens and pure wording functions.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* thinking-phrases.ts — the rotating "thinking" phrase pool, hoisted from
|
|
3
3
|
* `goodvibes-tui` src/renderer/ui-factory.ts (THINKING_PHRASES). Verbatim
|
|
4
|
-
* identical to the agent's copy today (per the
|
|
4
|
+
* identical to the agent's copy today (per the renderer/input parity audit) — a pure
|
|
5
5
|
* move, no reconciliation needed.
|
|
6
6
|
*
|
|
7
7
|
* Vaporwave / good-vibes themed; shown by waitingPhrase()'s 'thinking' case
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* thinking-phrases.ts — the rotating "thinking" phrase pool, hoisted from
|
|
3
3
|
* `goodvibes-tui` src/renderer/ui-factory.ts (THINKING_PHRASES). Verbatim
|
|
4
|
-
* identical to the agent's copy today (per the
|
|
4
|
+
* identical to the agent's copy today (per the renderer/input parity audit) — a pure
|
|
5
5
|
* move, no reconciliation needed.
|
|
6
6
|
*
|
|
7
7
|
* Vaporwave / good-vibes themed; shown by waitingPhrase()'s 'thinking' case
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* TUI's precedence order — approval beats reconnect beats pre-first-token
|
|
12
12
|
* beats stalled beats thinking) and calls waitingPhrase(state, ctx) for the
|
|
13
13
|
* exact wording. Neither renderer should carry its own copy of these five
|
|
14
|
-
* strings/rotation — that duplication is exactly what the
|
|
14
|
+
* strings/rotation — that duplication is exactly what the renderer/input parity audit found
|
|
15
15
|
* (the agent's ui-factory.ts:308-313 was rotating-only, with no honest
|
|
16
16
|
* stall/reconnect/approval split at all).
|
|
17
17
|
*
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* TUI's precedence order — approval beats reconnect beats pre-first-token
|
|
12
12
|
* beats stalled beats thinking) and calls waitingPhrase(state, ctx) for the
|
|
13
13
|
* exact wording. Neither renderer should carry its own copy of these five
|
|
14
|
-
* strings/rotation — that duplication is exactly what the
|
|
14
|
+
* strings/rotation — that duplication is exactly what the renderer/input parity audit found
|
|
15
15
|
* (the agent's ui-factory.ts:308-313 was rotating-only, with no honest
|
|
16
16
|
* stall/reconnect/approval split at all).
|
|
17
17
|
*
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* push/delivery.ts
|
|
3
|
+
*
|
|
4
|
+
* The single place a push message is actually encrypted and sent. Every send —
|
|
5
|
+
* a `push.subscriptions.verify` test, or an approval/completion fan-out — flows
|
|
6
|
+
* through `deliverToSubscription`, so the honesty rules live in one spot:
|
|
7
|
+
*
|
|
8
|
+
* - A push service that answers 404/410 means the browser subscription is gone;
|
|
9
|
+
* the record is pruned and the receipt says `pruned`, never a fake success.
|
|
10
|
+
* - Any other non-2xx (or a transport error) is reported as `failed` with the
|
|
11
|
+
* status/reason, never swallowed into a success.
|
|
12
|
+
* - The request carries the RFC 8188 `Content-Encoding: aes128gcm` body plus
|
|
13
|
+
* the `TTL`, `Urgency`, and VAPID `Authorization` headers a push service
|
|
14
|
+
* requires.
|
|
15
|
+
*
|
|
16
|
+
* The endpoint is whatever the browser registered. In tests that is a local
|
|
17
|
+
* HTTP sink; in production it is the browser vendor's push service. This module
|
|
18
|
+
* never contacts a hard-coded external service of its own.
|
|
19
|
+
*/
|
|
20
|
+
import type { VapidManager } from './vapid.js';
|
|
21
|
+
import type { PushSubscriptionStore } from './subscription-store.js';
|
|
22
|
+
import type { PushDeliveryReceipt, PushMessage, StoredPushSubscription } from './types.js';
|
|
23
|
+
/** The `fetch` slice used to POST an encrypted payload. Injectable for tests. */
|
|
24
|
+
export type PushTransport = (url: string, init: {
|
|
25
|
+
method: string;
|
|
26
|
+
headers: Record<string, string>;
|
|
27
|
+
body: Buffer;
|
|
28
|
+
}) => Promise<{
|
|
29
|
+
status: number;
|
|
30
|
+
}>;
|
|
31
|
+
export interface DeliveryDeps {
|
|
32
|
+
readonly vapid: VapidManager;
|
|
33
|
+
readonly store: PushSubscriptionStore;
|
|
34
|
+
readonly transport?: PushTransport | undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Encrypt and send one message to one subscription, prune-on-gone, and return
|
|
38
|
+
* an honest receipt. The subscription's `lastOutcome` is stamped either way.
|
|
39
|
+
*/
|
|
40
|
+
export declare function deliverToSubscription(subscription: StoredPushSubscription, message: PushMessage, deps: DeliveryDeps): Promise<PushDeliveryReceipt>;
|
|
41
|
+
/**
|
|
42
|
+
* Fan one message out to every stored subscription, delivering (and pruning) in
|
|
43
|
+
* sequence. Returns one receipt per subscription — an empty array when there
|
|
44
|
+
* are no subscriptions at all (the honest "nobody to notify" result, not a
|
|
45
|
+
* silent success).
|
|
46
|
+
*/
|
|
47
|
+
export declare function deliverToAll(message: PushMessage, deps: DeliveryDeps): Promise<PushDeliveryReceipt[]>;
|
|
48
|
+
//# sourceMappingURL=delivery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../../src/platform/push/delivery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EACX,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,iFAAiF;AACjF,MAAM,MAAM,aAAa,GAAG,CAC1B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,KACpE,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAgCjC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAChD;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,sBAAsB,EACpC,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,mBAAmB,CAAC,CAyD9B;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAOhC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* push/delivery.ts
|
|
3
|
+
*
|
|
4
|
+
* The single place a push message is actually encrypted and sent. Every send —
|
|
5
|
+
* a `push.subscriptions.verify` test, or an approval/completion fan-out — flows
|
|
6
|
+
* through `deliverToSubscription`, so the honesty rules live in one spot:
|
|
7
|
+
*
|
|
8
|
+
* - A push service that answers 404/410 means the browser subscription is gone;
|
|
9
|
+
* the record is pruned and the receipt says `pruned`, never a fake success.
|
|
10
|
+
* - Any other non-2xx (or a transport error) is reported as `failed` with the
|
|
11
|
+
* status/reason, never swallowed into a success.
|
|
12
|
+
* - The request carries the RFC 8188 `Content-Encoding: aes128gcm` body plus
|
|
13
|
+
* the `TTL`, `Urgency`, and VAPID `Authorization` headers a push service
|
|
14
|
+
* requires.
|
|
15
|
+
*
|
|
16
|
+
* The endpoint is whatever the browser registered. In tests that is a local
|
|
17
|
+
* HTTP sink; in production it is the browser vendor's push service. This module
|
|
18
|
+
* never contacts a hard-coded external service of its own.
|
|
19
|
+
*/
|
|
20
|
+
import { encryptPushPayload } from './encryption.js';
|
|
21
|
+
const DEFAULT_TTL_SECONDS = 24 * 60 * 60;
|
|
22
|
+
const GONE_STATUSES = new Set([404, 410]);
|
|
23
|
+
function defaultTransport() {
|
|
24
|
+
return async (url, init) => {
|
|
25
|
+
// Re-wrap over a plain ArrayBuffer so the body matches fetch's BodyInit.
|
|
26
|
+
const res = await fetch(url, {
|
|
27
|
+
method: init.method,
|
|
28
|
+
headers: init.headers,
|
|
29
|
+
body: new Uint8Array(init.body),
|
|
30
|
+
});
|
|
31
|
+
return { status: res.status };
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function endpointOrigin(endpoint) {
|
|
35
|
+
try {
|
|
36
|
+
return new URL(endpoint).origin;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return 'invalid';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function messagePlaintext(message) {
|
|
43
|
+
return Buffer.from(JSON.stringify({ title: message.title, body: message.body, data: message.data ?? {} }), 'utf8');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Encrypt and send one message to one subscription, prune-on-gone, and return
|
|
47
|
+
* an honest receipt. The subscription's `lastOutcome` is stamped either way.
|
|
48
|
+
*/
|
|
49
|
+
export async function deliverToSubscription(subscription, message, deps) {
|
|
50
|
+
const origin = endpointOrigin(subscription.endpoint);
|
|
51
|
+
const transport = deps.transport ?? defaultTransport();
|
|
52
|
+
let httpStatus;
|
|
53
|
+
try {
|
|
54
|
+
const encrypted = encryptPushPayload(subscription.keys, messagePlaintext(message));
|
|
55
|
+
const authorization = await deps.vapid.buildAuthorizationHeader(subscription.endpoint);
|
|
56
|
+
const headers = {
|
|
57
|
+
'content-encoding': encrypted.contentEncoding,
|
|
58
|
+
'content-type': 'application/octet-stream',
|
|
59
|
+
ttl: String(message.ttlSeconds ?? DEFAULT_TTL_SECONDS),
|
|
60
|
+
urgency: message.urgency ?? 'normal',
|
|
61
|
+
authorization,
|
|
62
|
+
};
|
|
63
|
+
const result = await transport(subscription.endpoint, {
|
|
64
|
+
method: 'POST',
|
|
65
|
+
headers,
|
|
66
|
+
body: encrypted.body,
|
|
67
|
+
});
|
|
68
|
+
httpStatus = result.status;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
await deps.store.recordOutcome(subscription.id, 'failed');
|
|
72
|
+
return {
|
|
73
|
+
subscriptionId: subscription.id,
|
|
74
|
+
endpointOrigin: origin,
|
|
75
|
+
outcome: 'failed',
|
|
76
|
+
detail: `delivery request failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (httpStatus >= 200 && httpStatus < 300) {
|
|
80
|
+
await deps.store.recordOutcome(subscription.id, 'delivered');
|
|
81
|
+
return { subscriptionId: subscription.id, endpointOrigin: origin, outcome: 'delivered', httpStatus };
|
|
82
|
+
}
|
|
83
|
+
if (GONE_STATUSES.has(httpStatus)) {
|
|
84
|
+
// The subscription is gone at the push service — prune it (delete means
|
|
85
|
+
// delete) and report the prune with the status that proved it dead.
|
|
86
|
+
await deps.store.remove(subscription.id);
|
|
87
|
+
return {
|
|
88
|
+
subscriptionId: subscription.id,
|
|
89
|
+
endpointOrigin: origin,
|
|
90
|
+
outcome: 'pruned',
|
|
91
|
+
httpStatus,
|
|
92
|
+
detail: `push endpoint reported ${httpStatus} gone; subscription removed`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
await deps.store.recordOutcome(subscription.id, 'failed');
|
|
96
|
+
return {
|
|
97
|
+
subscriptionId: subscription.id,
|
|
98
|
+
endpointOrigin: origin,
|
|
99
|
+
outcome: 'failed',
|
|
100
|
+
httpStatus,
|
|
101
|
+
detail: `push service returned ${httpStatus}`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Fan one message out to every stored subscription, delivering (and pruning) in
|
|
106
|
+
* sequence. Returns one receipt per subscription — an empty array when there
|
|
107
|
+
* are no subscriptions at all (the honest "nobody to notify" result, not a
|
|
108
|
+
* silent success).
|
|
109
|
+
*/
|
|
110
|
+
export async function deliverToAll(message, deps) {
|
|
111
|
+
const subscriptions = await deps.store.all();
|
|
112
|
+
const receipts = [];
|
|
113
|
+
for (const subscription of subscriptions) {
|
|
114
|
+
receipts.push(await deliverToSubscription(subscription, message, deps));
|
|
115
|
+
}
|
|
116
|
+
return receipts;
|
|
117
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* push/encryption.ts
|
|
3
|
+
*
|
|
4
|
+
* Browser-push payload encryption, implemented with Node's built-in crypto
|
|
5
|
+
* (node:crypto) — no third-party web-push dependency. This is the daemon-side
|
|
6
|
+
* (Node/Bun) delivery path only; nothing here is imported by the runtime-neutral
|
|
7
|
+
* or browser bundles (see scripts/browser-compat-check.ts).
|
|
8
|
+
*
|
|
9
|
+
* Two standards are combined here, exactly as a browser Push service expects:
|
|
10
|
+
*
|
|
11
|
+
* - RFC 8291 (Message Encryption for Web Push): derive a shared secret from an
|
|
12
|
+
* ephemeral P-256 keypair and the subscription's public key + auth secret.
|
|
13
|
+
* - RFC 8188 (aes128gcm content encoding): expand that secret into a
|
|
14
|
+
* content-encryption key + nonce and encrypt one record, then frame it with
|
|
15
|
+
* the salt / record-size / sender-public-key header the receiver reads back.
|
|
16
|
+
*
|
|
17
|
+
* The output Buffer is the raw request body sent to the subscription endpoint
|
|
18
|
+
* with `Content-Encoding: aes128gcm`.
|
|
19
|
+
*/
|
|
20
|
+
/** The subscription's own key material, base64url-encoded (browser PushSubscription shape). */
|
|
21
|
+
export interface SubscriptionKeyMaterial {
|
|
22
|
+
/** The receiver's public key — 65-byte uncompressed P-256 point, base64url. */
|
|
23
|
+
readonly p256dh: string;
|
|
24
|
+
/** The receiver's 16-byte authentication secret, base64url. */
|
|
25
|
+
readonly auth: string;
|
|
26
|
+
}
|
|
27
|
+
export interface EncryptedPushPayload {
|
|
28
|
+
/** The aes128gcm request body: header || ciphertext || GCM tag. */
|
|
29
|
+
readonly body: Buffer;
|
|
30
|
+
/** Always `aes128gcm` — the value for the Content-Encoding request header. */
|
|
31
|
+
readonly contentEncoding: 'aes128gcm';
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Encrypt `plaintext` for a subscription's key material.
|
|
35
|
+
*
|
|
36
|
+
* A fresh ephemeral sender keypair and salt are generated per call (RFC 8291
|
|
37
|
+
* requires this — the same salt/key pair must never encrypt two messages), so
|
|
38
|
+
* the result is non-deterministic by design.
|
|
39
|
+
*/
|
|
40
|
+
export declare function encryptPushPayload(keys: SubscriptionKeyMaterial, plaintext: Buffer): EncryptedPushPayload;
|
|
41
|
+
//# sourceMappingURL=encryption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../../src/platform/push/encryption.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,+FAA+F;AAC/F,MAAM,WAAW,uBAAuB;IACtC,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC;CACvC;AAyBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,uBAAuB,EAC7B,SAAS,EAAE,MAAM,GAChB,oBAAoB,CA2CtB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* push/encryption.ts
|
|
3
|
+
*
|
|
4
|
+
* Browser-push payload encryption, implemented with Node's built-in crypto
|
|
5
|
+
* (node:crypto) — no third-party web-push dependency. This is the daemon-side
|
|
6
|
+
* (Node/Bun) delivery path only; nothing here is imported by the runtime-neutral
|
|
7
|
+
* or browser bundles (see scripts/browser-compat-check.ts).
|
|
8
|
+
*
|
|
9
|
+
* Two standards are combined here, exactly as a browser Push service expects:
|
|
10
|
+
*
|
|
11
|
+
* - RFC 8291 (Message Encryption for Web Push): derive a shared secret from an
|
|
12
|
+
* ephemeral P-256 keypair and the subscription's public key + auth secret.
|
|
13
|
+
* - RFC 8188 (aes128gcm content encoding): expand that secret into a
|
|
14
|
+
* content-encryption key + nonce and encrypt one record, then frame it with
|
|
15
|
+
* the salt / record-size / sender-public-key header the receiver reads back.
|
|
16
|
+
*
|
|
17
|
+
* The output Buffer is the raw request body sent to the subscription endpoint
|
|
18
|
+
* with `Content-Encoding: aes128gcm`.
|
|
19
|
+
*/
|
|
20
|
+
import { createCipheriv, createECDH, createHmac, randomBytes } from 'node:crypto';
|
|
21
|
+
/**
|
|
22
|
+
* Single fixed record size. Push payloads here (an approval summary, a
|
|
23
|
+
* completion note) are far below this, so one aes128gcm record always
|
|
24
|
+
* suffices; a payload that would not fit is rejected honestly rather than
|
|
25
|
+
* silently truncated or split.
|
|
26
|
+
*/
|
|
27
|
+
const RECORD_SIZE = 4096;
|
|
28
|
+
const KEY_INFO_PREFIX = Buffer.from('WebPush: info\0', 'utf8');
|
|
29
|
+
const CEK_INFO = Buffer.from('Content-Encoding: aes128gcm\0', 'utf8');
|
|
30
|
+
const NONCE_INFO = Buffer.from('Content-Encoding: nonce\0', 'utf8');
|
|
31
|
+
/** HKDF (RFC 5869) specialized to a single output block (length <= 32). */
|
|
32
|
+
function hkdf(salt, ikm, info, length) {
|
|
33
|
+
const prk = createHmac('sha256', salt).update(ikm).digest();
|
|
34
|
+
const okm = createHmac('sha256', prk).update(Buffer.concat([info, Buffer.from([0x01])])).digest();
|
|
35
|
+
return okm.subarray(0, length);
|
|
36
|
+
}
|
|
37
|
+
function base64UrlToBuffer(value) {
|
|
38
|
+
return Buffer.from(value, 'base64url');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Encrypt `plaintext` for a subscription's key material.
|
|
42
|
+
*
|
|
43
|
+
* A fresh ephemeral sender keypair and salt are generated per call (RFC 8291
|
|
44
|
+
* requires this — the same salt/key pair must never encrypt two messages), so
|
|
45
|
+
* the result is non-deterministic by design.
|
|
46
|
+
*/
|
|
47
|
+
export function encryptPushPayload(keys, plaintext) {
|
|
48
|
+
const receiverPublic = base64UrlToBuffer(keys.p256dh);
|
|
49
|
+
const authSecret = base64UrlToBuffer(keys.auth);
|
|
50
|
+
if (receiverPublic.length !== 65) {
|
|
51
|
+
throw new Error('Push subscription p256dh key is not a 65-byte uncompressed P-256 point');
|
|
52
|
+
}
|
|
53
|
+
if (authSecret.length !== 16) {
|
|
54
|
+
throw new Error('Push subscription auth secret is not 16 bytes');
|
|
55
|
+
}
|
|
56
|
+
// Ephemeral sender (application-server) keypair for this one message.
|
|
57
|
+
const sender = createECDH('prime256v1');
|
|
58
|
+
sender.generateKeys();
|
|
59
|
+
const senderPublic = sender.getPublicKey();
|
|
60
|
+
const sharedSecret = sender.computeSecret(receiverPublic);
|
|
61
|
+
const salt = randomBytes(16);
|
|
62
|
+
// RFC 8291: mix the shared secret with the auth secret and both public keys.
|
|
63
|
+
const keyInfo = Buffer.concat([KEY_INFO_PREFIX, receiverPublic, senderPublic]);
|
|
64
|
+
const ikm = hkdf(authSecret, sharedSecret, keyInfo, 32);
|
|
65
|
+
// RFC 8188: expand into the content-encryption key and nonce.
|
|
66
|
+
const contentEncryptionKey = hkdf(salt, ikm, CEK_INFO, 16);
|
|
67
|
+
const nonce = hkdf(salt, ikm, NONCE_INFO, 12);
|
|
68
|
+
// One record: plaintext followed by the 0x02 last-record delimiter.
|
|
69
|
+
const record = Buffer.concat([plaintext, Buffer.from([0x02])]);
|
|
70
|
+
if (record.length + 16 > RECORD_SIZE) {
|
|
71
|
+
throw new Error(`Push payload too large for a single aes128gcm record (max ${RECORD_SIZE - 17} bytes)`);
|
|
72
|
+
}
|
|
73
|
+
const cipher = createCipheriv('aes-128-gcm', contentEncryptionKey, nonce);
|
|
74
|
+
const ciphertext = Buffer.concat([cipher.update(record), cipher.final(), cipher.getAuthTag()]);
|
|
75
|
+
// aes128gcm header: salt(16) | record-size(4, big-endian) | keyid-len(1) | keyid(=senderPublic).
|
|
76
|
+
const header = Buffer.alloc(16 + 4 + 1 + senderPublic.length);
|
|
77
|
+
salt.copy(header, 0);
|
|
78
|
+
header.writeUInt32BE(RECORD_SIZE, 16);
|
|
79
|
+
header.writeUInt8(senderPublic.length, 20);
|
|
80
|
+
senderPublic.copy(header, 21);
|
|
81
|
+
return { body: Buffer.concat([header, ciphertext]), contentEncoding: 'aes128gcm' };
|
|
82
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* push/index.ts — the browser-push module barrel (VAPID custody, subscription
|
|
3
|
+
* store, RFC 8291 encryption, and the delivery path). Daemon-side only; not
|
|
4
|
+
* part of the runtime-neutral or browser bundles.
|
|
5
|
+
*/
|
|
6
|
+
export { encryptPushPayload } from './encryption.js';
|
|
7
|
+
export type { SubscriptionKeyMaterial, EncryptedPushPayload } from './encryption.js';
|
|
8
|
+
export { VapidManager, VAPID_SECRET_KEY } from './vapid.js';
|
|
9
|
+
export type { VapidSecretStore, VapidManagerOptions } from './vapid.js';
|
|
10
|
+
export { PushSubscriptionStore, toPublicSubscription } from './subscription-store.js';
|
|
11
|
+
export type { RegisterSubscriptionInput } from './subscription-store.js';
|
|
12
|
+
export { deliverToSubscription, deliverToAll } from './delivery.js';
|
|
13
|
+
export type { PushTransport, DeliveryDeps } from './delivery.js';
|
|
14
|
+
export { PushService } from './service.js';
|
|
15
|
+
export type { PushServiceDeps, SubscribeInput, ApprovalSource, ApprovalNotice } from './service.js';
|
|
16
|
+
export type { StoredPushSubscription, PublicPushSubscription, PushDeliveryOutcome, PushDeliveryReceipt, PushUrgency, PushMessage, } from './types.js';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/platform/push/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC5D,YAAY,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACtF,YAAY,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACpE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACpG,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* push/index.ts — the browser-push module barrel (VAPID custody, subscription
|
|
3
|
+
* store, RFC 8291 encryption, and the delivery path). Daemon-side only; not
|
|
4
|
+
* part of the runtime-neutral or browser bundles.
|
|
5
|
+
*/
|
|
6
|
+
export { encryptPushPayload } from './encryption.js';
|
|
7
|
+
export { VapidManager, VAPID_SECRET_KEY } from './vapid.js';
|
|
8
|
+
export { PushSubscriptionStore, toPublicSubscription } from './subscription-store.js';
|
|
9
|
+
export { deliverToSubscription, deliverToAll } from './delivery.js';
|
|
10
|
+
export { PushService } from './service.js';
|