@cleocode/core 2026.10.1 → 2026.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-provenance.json +2 -2
- package/dist/cloud/journal.d.ts +9 -5
- package/dist/cloud/journal.d.ts.map +1 -1
- package/dist/cloud/journal.js +29 -8
- package/dist/cloud/journal.js.map +1 -1
- package/dist/cloud/manifest-check.d.ts +140 -4
- package/dist/cloud/manifest-check.d.ts.map +1 -1
- package/dist/cloud/manifest-check.js +309 -10
- package/dist/cloud/manifest-check.js.map +1 -1
- package/dist/cloud/nexus-attach.d.ts +25 -0
- package/dist/cloud/nexus-attach.d.ts.map +1 -1
- package/dist/cloud/nexus-attach.js +81 -6
- package/dist/cloud/nexus-attach.js.map +1 -1
- package/dist/cloud/nexus-cloud-activity.d.ts +37 -0
- package/dist/cloud/nexus-cloud-activity.d.ts.map +1 -0
- package/dist/cloud/nexus-cloud-activity.js +79 -0
- package/dist/cloud/nexus-cloud-activity.js.map +1 -0
- package/dist/cloud/nexus-cloud-status.d.ts.map +1 -1
- package/dist/cloud/nexus-cloud-status.js +36 -0
- package/dist/cloud/nexus-cloud-status.js.map +1 -1
- package/dist/cloud/nexus-device.d.ts +1 -1
- package/dist/cloud/nexus-enrol.d.ts.map +1 -1
- package/dist/cloud/nexus-enrol.js +5 -0
- package/dist/cloud/nexus-enrol.js.map +1 -1
- package/dist/cloud/nexus-home.d.ts +74 -0
- package/dist/cloud/nexus-home.d.ts.map +1 -0
- package/dist/cloud/nexus-home.js +97 -0
- package/dist/cloud/nexus-home.js.map +1 -0
- package/dist/cloud/nexus-vault-keys.d.ts +129 -0
- package/dist/cloud/nexus-vault-keys.d.ts.map +1 -0
- package/dist/cloud/nexus-vault-keys.js +277 -0
- package/dist/cloud/nexus-vault-keys.js.map +1 -0
- package/dist/cloud/nexus-vault-state.d.ts +121 -0
- package/dist/cloud/nexus-vault-state.d.ts.map +1 -0
- package/dist/cloud/nexus-vault-state.js +274 -0
- package/dist/cloud/nexus-vault-state.js.map +1 -0
- package/dist/cloud/nexus-vault.d.ts +160 -0
- package/dist/cloud/nexus-vault.d.ts.map +1 -0
- package/dist/cloud/nexus-vault.js +1733 -0
- package/dist/cloud/nexus-vault.js.map +1 -0
- package/dist/cloud/signing.d.ts +24 -8
- package/dist/cloud/signing.d.ts.map +1 -1
- package/dist/cloud/signing.js +61 -15
- package/dist/cloud/signing.js.map +1 -1
- package/dist/docs/export-document.js +8137 -3318
- package/dist/docs/export-document.js.map +3 -3
- package/dist/doctor/migrations.d.ts +75 -0
- package/dist/doctor/migrations.d.ts.map +1 -0
- package/dist/doctor/migrations.js +136 -0
- package/dist/doctor/migrations.js.map +1 -0
- package/dist/doctor/sync-sealer.d.ts +48 -0
- package/dist/doctor/sync-sealer.d.ts.map +1 -0
- package/dist/doctor/sync-sealer.js +109 -0
- package/dist/doctor/sync-sealer.js.map +1 -0
- package/dist/doctor/sync-triggers.d.ts +53 -0
- package/dist/doctor/sync-triggers.d.ts.map +1 -0
- package/dist/doctor/sync-triggers.js +157 -0
- package/dist/doctor/sync-triggers.js.map +1 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +5 -1
- package/dist/init.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/llm/plugin-facade.js +8442 -3623
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/nexus/projects-clean.d.ts +3 -0
- package/dist/nexus/projects-clean.d.ts.map +1 -1
- package/dist/nexus/projects-clean.js +9 -3
- package/dist/nexus/projects-clean.js.map +1 -1
- package/dist/nexus/registry-roots.d.ts +3 -1
- package/dist/nexus/registry-roots.d.ts.map +1 -1
- package/dist/nexus/registry-roots.js +5 -2
- package/dist/nexus/registry-roots.js.map +1 -1
- package/dist/nexus/registry.d.ts +8 -1
- package/dist/nexus/registry.d.ts.map +1 -1
- package/dist/nexus/registry.js +24 -10
- package/dist/nexus/registry.js.map +1 -1
- package/dist/nexus/workspace.d.ts +4 -1
- package/dist/nexus/workspace.d.ts.map +1 -1
- package/dist/nexus/workspace.js +10 -4
- package/dist/nexus/workspace.js.map +1 -1
- package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
- package/dist/orchestrate/spawn-ops.js +7 -2
- package/dist/orchestrate/spawn-ops.js.map +1 -1
- package/dist/orchestrate/worker-verify.d.ts +121 -12
- package/dist/orchestrate/worker-verify.d.ts.map +1 -1
- package/dist/orchestrate/worker-verify.js +172 -21
- package/dist/orchestrate/worker-verify.js.map +1 -1
- package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
- package/dist/orchestration/spawn-prompt.js +15 -9
- package/dist/orchestration/spawn-prompt.js.map +1 -1
- package/dist/release/ci-evidence.d.ts +9 -0
- package/dist/release/ci-evidence.d.ts.map +1 -1
- package/dist/release/ci-evidence.js +9 -2
- package/dist/release/ci-evidence.js.map +1 -1
- package/dist/resources/backend.d.ts +15 -3
- package/dist/resources/backend.d.ts.map +1 -1
- package/dist/resources/backend.js +7 -3
- package/dist/resources/backend.js.map +1 -1
- package/dist/resources/darwin-backend.d.ts +142 -0
- package/dist/resources/darwin-backend.d.ts.map +1 -0
- package/dist/resources/darwin-backend.js +288 -0
- package/dist/resources/darwin-backend.js.map +1 -0
- package/dist/resources/governor.d.ts +44 -1
- package/dist/resources/governor.d.ts.map +1 -1
- package/dist/resources/governor.js +100 -36
- package/dist/resources/governor.js.map +1 -1
- package/dist/resources/heavy-command.d.ts +132 -0
- package/dist/resources/heavy-command.d.ts.map +1 -0
- package/dist/resources/heavy-command.js +768 -0
- package/dist/resources/heavy-command.js.map +1 -0
- package/dist/resources/monitor.d.ts +50 -1
- package/dist/resources/monitor.d.ts.map +1 -1
- package/dist/resources/monitor.js +83 -1
- package/dist/resources/monitor.js.map +1 -1
- package/dist/resources/run-admission.d.ts +303 -0
- package/dist/resources/run-admission.d.ts.map +1 -0
- package/dist/resources/run-admission.js +648 -0
- package/dist/resources/run-admission.js.map +1 -0
- package/dist/resources/run-class.d.ts +111 -0
- package/dist/resources/run-class.d.ts.map +1 -0
- package/dist/resources/run-class.js +658 -0
- package/dist/resources/run-class.js.map +1 -0
- package/dist/resources/run-governed.d.ts +158 -0
- package/dist/resources/run-governed.d.ts.map +1 -0
- package/dist/resources/run-governed.js +406 -0
- package/dist/resources/run-governed.js.map +1 -0
- package/dist/resources/slot-holder.d.ts +267 -0
- package/dist/resources/slot-holder.d.ts.map +1 -0
- package/dist/resources/slot-holder.js +505 -0
- package/dist/resources/slot-holder.js.map +1 -0
- package/dist/resources/tool-groups.d.ts +74 -0
- package/dist/resources/tool-groups.d.ts.map +1 -0
- package/dist/resources/tool-groups.js +118 -0
- package/dist/resources/tool-groups.js.map +1 -0
- package/dist/routing/build-command-groups.d.ts.map +1 -1
- package/dist/routing/build-command-groups.js +1 -0
- package/dist/routing/build-command-groups.js.map +1 -1
- package/dist/selfimprove/fix-gen.js +8446 -3627
- package/dist/selfimprove/fix-gen.js.map +3 -3
- package/dist/sentient/cross-project-hygiene.d.ts +3 -2
- package/dist/sentient/cross-project-hygiene.d.ts.map +1 -1
- package/dist/sentient/cross-project-hygiene.js +5 -2
- package/dist/sentient/cross-project-hygiene.js.map +1 -1
- package/dist/sentient/state.d.ts +7 -0
- package/dist/sentient/state.d.ts.map +1 -1
- package/dist/sentient/state.js.map +1 -1
- package/dist/sentient/tick.d.ts +14 -2
- package/dist/sentient/tick.d.ts.map +1 -1
- package/dist/sentient/tick.js +63 -4
- package/dist/sentient/tick.js.map +1 -1
- package/dist/store/backup-recover.d.ts.map +1 -1
- package/dist/store/backup-recover.js +5 -0
- package/dist/store/backup-recover.js.map +1 -1
- package/dist/store/data-accessor.d.ts +1 -0
- package/dist/store/data-accessor.d.ts.map +1 -1
- package/dist/store/data-accessor.js +7 -0
- package/dist/store/data-accessor.js.map +1 -1
- package/dist/store/dual-scope-db.d.ts +23 -1
- package/dist/store/dual-scope-db.d.ts.map +1 -1
- package/dist/store/dual-scope-db.js +126 -36
- package/dist/store/dual-scope-db.js.map +1 -1
- package/dist/store/exodus/recovery.d.ts.map +1 -1
- package/dist/store/exodus/recovery.js +15 -0
- package/dist/store/exodus/recovery.js.map +1 -1
- package/dist/store/legacy-tasks-lineage.d.ts.map +1 -1
- package/dist/store/legacy-tasks-lineage.js +5 -0
- package/dist/store/legacy-tasks-lineage.js.map +1 -1
- package/dist/store/lock.d.ts +8 -1
- package/dist/store/lock.d.ts.map +1 -1
- package/dist/store/lock.js +10 -2
- package/dist/store/lock.js.map +1 -1
- package/dist/store/migration-manager.d.ts +5 -0
- package/dist/store/migration-manager.d.ts.map +1 -1
- package/dist/store/migration-manager.js +11 -0
- package/dist/store/migration-manager.js.map +1 -1
- package/dist/store/migration-runner.d.ts +158 -0
- package/dist/store/migration-runner.d.ts.map +1 -0
- package/dist/store/migration-runner.js +493 -0
- package/dist/store/migration-runner.js.map +1 -0
- package/dist/store/portable-bundle-import.d.ts +15 -1
- package/dist/store/portable-bundle-import.d.ts.map +1 -1
- package/dist/store/portable-bundle-import.js +24 -4
- package/dist/store/portable-bundle-import.js.map +1 -1
- package/dist/store/portable-bundle-relocate.d.ts +43 -0
- package/dist/store/portable-bundle-relocate.d.ts.map +1 -1
- package/dist/store/portable-bundle-relocate.js +79 -5
- package/dist/store/portable-bundle-relocate.js.map +1 -1
- package/dist/store/portable-bundle-scan.d.ts +20 -0
- package/dist/store/portable-bundle-scan.d.ts.map +1 -1
- package/dist/store/portable-bundle-scan.js +38 -3
- package/dist/store/portable-bundle-scan.js.map +1 -1
- package/dist/store/portable-bundle.d.ts +33 -0
- package/dist/store/portable-bundle.d.ts.map +1 -1
- package/dist/store/portable-bundle.js +34 -7
- package/dist/store/portable-bundle.js.map +1 -1
- package/dist/store/row-identity-registry.d.ts +137 -7
- package/dist/store/row-identity-registry.d.ts.map +1 -1
- package/dist/store/row-identity-registry.js +364 -9
- package/dist/store/row-identity-registry.js.map +1 -1
- package/dist/store/row-identity.d.ts.map +1 -1
- package/dist/store/row-identity.js +9 -10
- package/dist/store/row-identity.js.map +1 -1
- package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
- package/dist/store/sqlite-data-accessor.js +10 -0
- package/dist/store/sqlite-data-accessor.js.map +1 -1
- package/dist/store/sqlite.d.ts +31 -0
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +5 -1
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/sync/capture.d.ts +203 -0
- package/dist/store/sync/capture.d.ts.map +1 -0
- package/dist/store/sync/capture.js +562 -0
- package/dist/store/sync/capture.js.map +1 -0
- package/dist/store/sync/clock-store.d.ts.map +1 -1
- package/dist/store/sync/clock-store.js +2 -0
- package/dist/store/sync/clock-store.js.map +1 -1
- package/dist/store/sync/fk-orphans.d.ts +133 -0
- package/dist/store/sync/fk-orphans.d.ts.map +1 -0
- package/dist/store/sync/fk-orphans.js +265 -0
- package/dist/store/sync/fk-orphans.js.map +1 -0
- package/dist/store/sync/flags.d.ts +7 -0
- package/dist/store/sync/flags.d.ts.map +1 -1
- package/dist/store/sync/flags.js +16 -0
- package/dist/store/sync/flags.js.map +1 -1
- package/dist/store/sync/hlc.d.ts.map +1 -1
- package/dist/store/sync/hlc.js +4 -0
- package/dist/store/sync/hlc.js.map +1 -1
- package/dist/store/sync/identity-fill.d.ts +45 -0
- package/dist/store/sync/identity-fill.d.ts.map +1 -0
- package/dist/store/sync/identity-fill.js +85 -0
- package/dist/store/sync/identity-fill.js.map +1 -0
- package/dist/store/sync/machinery.d.ts +27 -0
- package/dist/store/sync/machinery.d.ts.map +1 -0
- package/dist/store/sync/machinery.js +44 -0
- package/dist/store/sync/machinery.js.map +1 -0
- package/dist/store/sync/netting.d.ts +120 -0
- package/dist/store/sync/netting.d.ts.map +1 -0
- package/dist/store/sync/netting.js +336 -0
- package/dist/store/sync/netting.js.map +1 -0
- package/dist/store/sync/replica.d.ts +27 -2
- package/dist/store/sync/replica.d.ts.map +1 -1
- package/dist/store/sync/replica.js +47 -3
- package/dist/store/sync/replica.js.map +1 -1
- package/dist/store/sync/schema.d.ts +12 -0
- package/dist/store/sync/schema.d.ts.map +1 -1
- package/dist/store/sync/schema.js +21 -0
- package/dist/store/sync/schema.js.map +1 -1
- package/dist/store/sync/seal-backlog.d.ts +21 -0
- package/dist/store/sync/seal-backlog.d.ts.map +1 -0
- package/dist/store/sync/seal-backlog.js +24 -0
- package/dist/store/sync/seal-backlog.js.map +1 -0
- package/dist/store/sync/sealer-values.d.ts +34 -0
- package/dist/store/sync/sealer-values.d.ts.map +1 -0
- package/dist/store/sync/sealer-values.js +53 -0
- package/dist/store/sync/sealer-values.js.map +1 -0
- package/dist/store/sync/sealer.d.ts +145 -0
- package/dist/store/sync/sealer.d.ts.map +1 -0
- package/dist/store/sync/sealer.js +906 -0
- package/dist/store/sync/sealer.js.map +1 -0
- package/dist/store/sync/structural.d.ts +63 -0
- package/dist/store/sync/structural.d.ts.map +1 -0
- package/dist/store/sync/structural.js +180 -0
- package/dist/store/sync/structural.js.map +1 -0
- package/dist/store/sync/timestamps.d.ts +92 -0
- package/dist/store/sync/timestamps.d.ts.map +1 -0
- package/dist/store/sync/timestamps.js +228 -0
- package/dist/store/sync/timestamps.js.map +1 -0
- package/dist/store/sync/tombstones.d.ts +75 -0
- package/dist/store/sync/tombstones.d.ts.map +1 -0
- package/dist/store/sync/tombstones.js +103 -0
- package/dist/store/sync/tombstones.js.map +1 -0
- package/dist/store/sync/trigger-classes.d.ts +221 -0
- package/dist/store/sync/trigger-classes.d.ts.map +1 -0
- package/dist/store/sync/trigger-classes.js +441 -0
- package/dist/store/sync/trigger-classes.js.map +1 -0
- package/dist/store/sync/trigger-suspend-at-path.d.ts +23 -0
- package/dist/store/sync/trigger-suspend-at-path.d.ts.map +1 -0
- package/dist/store/sync/trigger-suspend-at-path.js +44 -0
- package/dist/store/sync/trigger-suspend-at-path.js.map +1 -0
- package/dist/store/sync/writer-version.d.ts +43 -0
- package/dist/store/sync/writer-version.d.ts.map +1 -0
- package/dist/store/sync/writer-version.js +90 -0
- package/dist/store/sync/writer-version.js.map +1 -0
- package/dist/store/table-classification.d.ts.map +1 -1
- package/dist/store/table-classification.js +102 -0
- package/dist/store/table-classification.js.map +1 -1
- package/dist/store/trigger-suspend-schema.d.ts +44 -0
- package/dist/store/trigger-suspend-schema.d.ts.map +1 -0
- package/dist/store/trigger-suspend-schema.js +25 -0
- package/dist/store/trigger-suspend-schema.js.map +1 -0
- package/dist/store/vault-manifest.d.ts +365 -0
- package/dist/store/vault-manifest.d.ts.map +1 -0
- package/dist/store/vault-manifest.js +812 -0
- package/dist/store/vault-manifest.js.map +1 -0
- package/dist/store/writer-lease.d.ts +31 -0
- package/dist/store/writer-lease.d.ts.map +1 -1
- package/dist/store/writer-lease.js +65 -2
- package/dist/store/writer-lease.js.map +1 -1
- package/dist/system/health.d.ts.map +1 -1
- package/dist/system/health.js +21 -0
- package/dist/system/health.js.map +1 -1
- package/dist/system/project-health.d.ts.map +1 -1
- package/dist/system/project-health.js +3 -1
- package/dist/system/project-health.js.map +1 -1
- package/dist/tasks/affected-packages.d.ts +58 -0
- package/dist/tasks/affected-packages.d.ts.map +1 -1
- package/dist/tasks/affected-packages.js +75 -6
- package/dist/tasks/affected-packages.js.map +1 -1
- package/dist/tasks/affected-scope.d.ts +150 -23
- package/dist/tasks/affected-scope.d.ts.map +1 -1
- package/dist/tasks/affected-scope.js +320 -32
- package/dist/tasks/affected-scope.js.map +1 -1
- package/dist/tasks/change-set.d.ts +96 -0
- package/dist/tasks/change-set.d.ts.map +1 -1
- package/dist/tasks/change-set.js +169 -4
- package/dist/tasks/change-set.js.map +1 -1
- package/dist/tasks/complete-ci.d.ts +115 -0
- package/dist/tasks/complete-ci.d.ts.map +1 -0
- package/dist/tasks/complete-ci.js +171 -0
- package/dist/tasks/complete-ci.js.map +1 -0
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +50 -17
- package/dist/tasks/complete.js.map +1 -1
- package/dist/tasks/compute-task-view.d.ts.map +1 -1
- package/dist/tasks/compute-task-view.js +7 -0
- package/dist/tasks/compute-task-view.js.map +1 -1
- package/dist/tasks/done-plan.d.ts.map +1 -1
- package/dist/tasks/done-plan.js +51 -30
- package/dist/tasks/done-plan.js.map +1 -1
- package/dist/tasks/done-record.d.ts +6 -0
- package/dist/tasks/done-record.d.ts.map +1 -1
- package/dist/tasks/done-record.js +9 -3
- package/dist/tasks/done-record.js.map +1 -1
- package/dist/tasks/evidence.d.ts +3 -2
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js +143 -12
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/tasks/gate-notes.d.ts +22 -0
- package/dist/tasks/gate-notes.d.ts.map +1 -0
- package/dist/tasks/gate-notes.js +33 -0
- package/dist/tasks/gate-notes.js.map +1 -0
- package/dist/tasks/index.d.ts +2 -1
- package/dist/tasks/index.d.ts.map +1 -1
- package/dist/tasks/index.js +2 -1
- package/dist/tasks/index.js.map +1 -1
- package/dist/tasks/test-run-binding.d.ts +117 -0
- package/dist/tasks/test-run-binding.d.ts.map +1 -0
- package/dist/tasks/test-run-binding.js +365 -0
- package/dist/tasks/test-run-binding.js.map +1 -0
- package/dist/tasks/tool-cache-env.d.ts +123 -0
- package/dist/tasks/tool-cache-env.d.ts.map +1 -0
- package/dist/tasks/tool-cache-env.js +287 -0
- package/dist/tasks/tool-cache-env.js.map +1 -0
- package/dist/tasks/tool-cache-failed-first.d.ts +155 -0
- package/dist/tasks/tool-cache-failed-first.d.ts.map +1 -0
- package/dist/tasks/tool-cache-failed-first.js +285 -0
- package/dist/tasks/tool-cache-failed-first.js.map +1 -0
- package/dist/tasks/tool-cache.d.ts +375 -55
- package/dist/tasks/tool-cache.d.ts.map +1 -1
- package/dist/tasks/tool-cache.js +912 -303
- package/dist/tasks/tool-cache.js.map +1 -1
- package/dist/tasks/tool-resolver.d.ts +4 -3
- package/dist/tasks/tool-resolver.d.ts.map +1 -1
- package/dist/tasks/tool-resolver.js +15 -4
- package/dist/tasks/tool-resolver.js.map +1 -1
- package/dist/tasks/tool-semaphore.d.ts +67 -7
- package/dist/tasks/tool-semaphore.d.ts.map +1 -1
- package/dist/tasks/tool-semaphore.js +134 -56
- package/dist/tasks/tool-semaphore.js.map +1 -1
- package/dist/upgrade.d.ts.map +1 -1
- package/dist/upgrade.js +4 -0
- package/dist/upgrade.js.map +1 -1
- package/dist/validation/engine-ops.d.ts +6 -0
- package/dist/validation/engine-ops.d.ts.map +1 -1
- package/dist/validation/engine-ops.js +8 -0
- package/dist/validation/engine-ops.js.map +1 -1
- package/migrations/drizzle-cleo-project/20260930170000_t12819-trigger-suspend-clause/migration.sql +367 -0
- package/migrations/sync-journal/20260930120000_t12343-capture/migration.sql +47 -0
- package/migrations/sync-journal/20261001170000_t12984-sealer/migration.sql +101 -0
- package/package.json +13 -13
- package/templates/CLEO-INJECTION.md +5 -5
- package/templates/CLEO-REFERENCE.md +8 -4
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This device's global CLEO store (the main brain) on Cleo Nexus: bind its
|
|
3
|
+
* global-scope replica and attach it to the account's `home:` stream with
|
|
4
|
+
* presence (T12952, cleo-nexus T084). `cleo login nexus` runs it after a
|
|
5
|
+
* device login, so login stays the only setup step; `cleo cloud status`
|
|
6
|
+
* reads the attachments back.
|
|
7
|
+
*
|
|
8
|
+
* A server that does not have the home-replica endpoints yet answers 404:
|
|
9
|
+
* that is reported as a warning, never a failure.
|
|
10
|
+
*
|
|
11
|
+
* @task T12952
|
|
12
|
+
* @epic T12323
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { NexusError } from './http.js';
|
|
16
|
+
import { attachHomeReplica } from './nexus-attach.js';
|
|
17
|
+
import { resolveNexusApiUrl } from './nexus-auth.js';
|
|
18
|
+
import { connectNexusCloud } from './nexus-cloud.js';
|
|
19
|
+
import { isNexusDeviceEnabled } from './nexus-device.js';
|
|
20
|
+
import { ensureNexusDeviceCredential } from './nexus-enrol.js';
|
|
21
|
+
/** Warning code: the server has no home-replica endpoints yet. */
|
|
22
|
+
export const W_NEXUS_HOME_UNSUPPORTED = 'W_NEXUS_HOME_UNSUPPORTED';
|
|
23
|
+
/**
|
|
24
|
+
* Attach this device's global store to the account's home stream.
|
|
25
|
+
*
|
|
26
|
+
* @param opts - API URL, stores and overrides.
|
|
27
|
+
* @returns The attachment (or `null` when the server does not support it) and warnings.
|
|
28
|
+
* @throws {NexusAccountError} Not signed in, or `E_NEXUS_REPLICA_COPIED`.
|
|
29
|
+
*/
|
|
30
|
+
export async function attachNexusGlobalStore(opts = {}) {
|
|
31
|
+
if (!isNexusDeviceEnabled())
|
|
32
|
+
return { replica: null, warnings: [] };
|
|
33
|
+
const apiUrl = resolveNexusApiUrl(opts.apiUrl);
|
|
34
|
+
const handle = await ensureNexusDeviceCredential({ ...opts, apiUrl });
|
|
35
|
+
const bearer = handle.device.currentBearer();
|
|
36
|
+
if (bearer === null)
|
|
37
|
+
return { replica: null, warnings: [...handle.warnings] };
|
|
38
|
+
let cliVersion = opts.cliVersion;
|
|
39
|
+
if (cliVersion === undefined) {
|
|
40
|
+
const { getCleoVersion } = await import('../scaffold/ensure-config.js');
|
|
41
|
+
cliVersion = getCleoVersion();
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const r = await attachHomeReplica({
|
|
45
|
+
apiUrl,
|
|
46
|
+
bearer,
|
|
47
|
+
deviceId: handle.device.deviceId,
|
|
48
|
+
cliVersion,
|
|
49
|
+
...(opts.binder ? { binder: opts.binder } : {}),
|
|
50
|
+
...(opts.fetch ? { fetch: opts.fetch } : {}),
|
|
51
|
+
});
|
|
52
|
+
return { replica: r.replica, warnings: [...handle.warnings, ...r.warnings] };
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
if (err instanceof NexusError && err.status === 404) {
|
|
56
|
+
return {
|
|
57
|
+
replica: null,
|
|
58
|
+
warnings: [
|
|
59
|
+
...handle.warnings,
|
|
60
|
+
`${W_NEXUS_HOME_UNSUPPORTED}: this Cleo Nexus server does not attach global stores yet`,
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** One home-stream replica as `GET /v1/account/home/replicas` lists it. */
|
|
68
|
+
export const nexusHomeReplicaSchema = z.looseObject({
|
|
69
|
+
replicaId: z.string(),
|
|
70
|
+
deviceId: z.string(),
|
|
71
|
+
deviceState: z.string().optional(),
|
|
72
|
+
presenceAt: z.string().nullable().optional(),
|
|
73
|
+
lastSyncAt: z.string().nullable().optional(),
|
|
74
|
+
attachedAt: z.string().optional(),
|
|
75
|
+
});
|
|
76
|
+
/** `GET /v1/account/home/replicas`. */
|
|
77
|
+
export const nexusHomeReplicaListSchema = z.looseObject({
|
|
78
|
+
replicas: z.array(nexusHomeReplicaSchema),
|
|
79
|
+
});
|
|
80
|
+
/**
|
|
81
|
+
* Read the account's global-store attachments (GET only).
|
|
82
|
+
*
|
|
83
|
+
* @param opts - API URL, stores and overrides.
|
|
84
|
+
* @returns The attachments; `supported: false` when the server has no such endpoint.
|
|
85
|
+
*/
|
|
86
|
+
export async function nexusGlobalStoreStatus(opts = {}) {
|
|
87
|
+
const conn = await connectNexusCloud(opts);
|
|
88
|
+
const list = await conn.find('/v1/account/home/replicas', nexusHomeReplicaListSchema);
|
|
89
|
+
if (list === null)
|
|
90
|
+
return { supported: false, thisDevice: null, replicas: [] };
|
|
91
|
+
return {
|
|
92
|
+
supported: true,
|
|
93
|
+
thisDevice: list.replicas.find((r) => r.deviceId === conn.device.deviceId) ?? null,
|
|
94
|
+
replicas: list.replicas,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=nexus-home.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nexus-home.js","sourceRoot":"","sources":["../../src/cloud/nexus-home.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vault's connection and keys: a read-write device connection, the
|
|
3
|
+
* account master key, this device's certificate, and the stream data keys.
|
|
4
|
+
*
|
|
5
|
+
* Owner decision (2026-10-01): adding a device needs only `cleo login` and
|
|
6
|
+
* the one-time browser approval; that approval also hands the device the
|
|
7
|
+
* encryption key. So the account master key (MK) is escrowed on Cleo Nexus:
|
|
8
|
+
*
|
|
9
|
+
* 1. `GET /v1/account/keys/escrow` returns MK sealed to this device's X25519
|
|
10
|
+
* key (`sealTo`), released only to an approved, active device. The client
|
|
11
|
+
* opens it with the device's private key and checks it against the
|
|
12
|
+
* escrow's verifier.
|
|
13
|
+
* 2. No escrow and no account keys: this is the account's first vault use.
|
|
14
|
+
* The client mints MK and escrows it (`PUT`, insert-only). A concurrent
|
|
15
|
+
* first device loses the insert with 409 and reads the winner's key.
|
|
16
|
+
* 3. The device certifies itself under MK (a self-grant, `PUT
|
|
17
|
+
* /v1/devices/:id/key`), so other devices can verify its snapshots.
|
|
18
|
+
* 4. Signer trust comes from `certifiedSigners` over `GET /v1/devices/trust`,
|
|
19
|
+
* with the trust state persisted in {@link NexusVaultState}.
|
|
20
|
+
*
|
|
21
|
+
* Threat model (cleo-nexus T082): the escrow `PUT` sends MK to the server
|
|
22
|
+
* over TLS, and the server stores it encrypted under a server-held key
|
|
23
|
+
* (`KEY_ESCROW_SECRET`). Snapshots are therefore encrypted at rest with keys
|
|
24
|
+
* Cleo Nexus can recover: this is server-escrowed encryption, not
|
|
25
|
+
* zero-knowledge end-to-end encryption. What the escrow does guarantee is
|
|
26
|
+
* that MK is released only to an approved, active device of the account,
|
|
27
|
+
* sealed to that device's key.
|
|
28
|
+
*
|
|
29
|
+
* A project's data key (PDK) is minted by its first pusher and stored
|
|
30
|
+
* wrapped by MK (`PUT /v1/projects/:id/keys/:userId`); the home stream key
|
|
31
|
+
* is derived from MK.
|
|
32
|
+
*
|
|
33
|
+
* No function here logs a key, and no error carries one.
|
|
34
|
+
*
|
|
35
|
+
* @task T12336
|
|
36
|
+
* @epic T12322
|
|
37
|
+
*/
|
|
38
|
+
import type { CloudWarning } from '@cleocode/contracts';
|
|
39
|
+
import { type KeyPair } from './crypto.js';
|
|
40
|
+
import { type FetchLike, Http, type ResponseSchema } from './http.js';
|
|
41
|
+
import { type TrustedSigners } from './keys.js';
|
|
42
|
+
import { resolveNexusApiUrl } from './nexus-auth.js';
|
|
43
|
+
import { type NexusCloudOptions } from './nexus-cloud.js';
|
|
44
|
+
import type { SealedNexusDevice } from './nexus-device.js';
|
|
45
|
+
import { NexusVaultState } from './nexus-vault-state.js';
|
|
46
|
+
/** Timeout of a snapshot blob upload or download. */
|
|
47
|
+
export declare const NEXUS_VAULT_BLOB_TIMEOUT_MS: number;
|
|
48
|
+
/** The sealed-box context of an escrow release (must match the server, cleo-nexus T082). */
|
|
49
|
+
export declare const escrowContext: (userId: string, deviceId: string) => string;
|
|
50
|
+
/** Options of every vault command. */
|
|
51
|
+
export interface NexusVaultOptions extends NexusCloudOptions {
|
|
52
|
+
/** Vault state store (tests). */
|
|
53
|
+
vaultState?: NexusVaultState;
|
|
54
|
+
/** Timeout of a blob transfer; default {@link NEXUS_VAULT_BLOB_TIMEOUT_MS}. */
|
|
55
|
+
blobTimeoutMs?: number;
|
|
56
|
+
}
|
|
57
|
+
/** A read-write connection with this machine's device credential and keys. */
|
|
58
|
+
export interface NexusVaultConnection {
|
|
59
|
+
readonly apiUrl: string;
|
|
60
|
+
readonly userId: string;
|
|
61
|
+
readonly deviceId: string;
|
|
62
|
+
readonly device: SealedNexusDevice;
|
|
63
|
+
/** Device keys: X25519 for sealed boxes, Ed25519 for signatures. */
|
|
64
|
+
readonly keys: {
|
|
65
|
+
encryption: KeyPair;
|
|
66
|
+
signing: KeyPair;
|
|
67
|
+
};
|
|
68
|
+
/** The authenticated client (sends `X-Cleo-Device-Id`). For the journal. */
|
|
69
|
+
readonly http: Http;
|
|
70
|
+
/** `fetch` for presigned blob transfers (long timeout, no credential). */
|
|
71
|
+
readonly blobFetch: FetchLike;
|
|
72
|
+
readonly state: NexusVaultState;
|
|
73
|
+
readonly warnings: CloudWarning[];
|
|
74
|
+
/** A request whose failure stays a raw {@link NexusError} (callers handle server codes). */
|
|
75
|
+
raw<T>(method: string, path: string, schema: ResponseSchema<T>, body?: unknown): Promise<T>;
|
|
76
|
+
/** {@link NexusVaultConnection.raw}, with failures mapped to {@link NexusAccountError}. */
|
|
77
|
+
call<T>(method: string, path: string, schema: ResponseSchema<T>, body?: unknown): Promise<T>;
|
|
78
|
+
/** `GET`, mapped; a 404 answers `null`. */
|
|
79
|
+
find<T>(path: string, schema: ResponseSchema<T>): Promise<T | null>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Open a read-write vault connection with this machine's device credential.
|
|
83
|
+
*
|
|
84
|
+
* @param opts - API URL, account, stores and test overrides.
|
|
85
|
+
* @returns The connection.
|
|
86
|
+
* @throws {NexusAccountError} Not signed in, device mode off, or no device keys.
|
|
87
|
+
*/
|
|
88
|
+
export declare function connectNexusVault(opts?: NexusVaultOptions): Promise<NexusVaultConnection>;
|
|
89
|
+
/** The unlocked account key and the signers this device trusts. */
|
|
90
|
+
export interface NexusAccountKey {
|
|
91
|
+
masterKey: Buffer;
|
|
92
|
+
keyVersion: number;
|
|
93
|
+
signers: TrustedSigners;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get the account master key for this device, minting and escrowing it on
|
|
97
|
+
* the account's first vault use, and certify this device under it.
|
|
98
|
+
*
|
|
99
|
+
* @param conn - A vault connection.
|
|
100
|
+
* @param opts - `readOnly`: never mint, escrow or certify (GET only); a missing escrow is
|
|
101
|
+
* `E_NEXUS_VAULT_EMPTY`.
|
|
102
|
+
* @returns The key, its version and the trusted signers.
|
|
103
|
+
* @throws {NexusAccountError} `E_NEXUS_VAULT_KEY_UNAVAILABLE` when the key
|
|
104
|
+
* cannot be obtained or verified; a mapped API error otherwise.
|
|
105
|
+
*/
|
|
106
|
+
export declare function unlockNexusAccountKey(conn: NexusVaultConnection, opts?: {
|
|
107
|
+
readOnly?: boolean;
|
|
108
|
+
}): Promise<NexusAccountKey>;
|
|
109
|
+
/**
|
|
110
|
+
* The data key of a project stream: unwrap the newest wrapped key, or mint
|
|
111
|
+
* and store one when the project has none yet (its first push).
|
|
112
|
+
*
|
|
113
|
+
* @param conn - A vault connection.
|
|
114
|
+
* @param mk - The unlocked master key.
|
|
115
|
+
* @param projectId - The server's project id.
|
|
116
|
+
* @param mint - Whether a missing key may be created (push: yes; restore: no).
|
|
117
|
+
* @returns The project data key, or `null` when none exists and `mint` is false.
|
|
118
|
+
*/
|
|
119
|
+
export declare function nexusProjectDataKey(conn: NexusVaultConnection, mk: Buffer, projectId: string, mint: boolean): Promise<Buffer | null>;
|
|
120
|
+
/**
|
|
121
|
+
* The data key of the account's `home:` stream (derived from MK, never stored).
|
|
122
|
+
*
|
|
123
|
+
* @param mk - The unlocked master key.
|
|
124
|
+
* @returns The home stream key.
|
|
125
|
+
*/
|
|
126
|
+
export declare function nexusHomeDataKey(mk: Buffer): Buffer;
|
|
127
|
+
/** Re-export for callers that only need the URL resolver. */
|
|
128
|
+
export { resolveNexusApiUrl };
|
|
129
|
+
//# sourceMappingURL=nexus-vault-keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nexus-vault-keys.d.ts","sourceRoot":"","sources":["../../src/cloud/nexus-vault-keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vault's connection and keys: a read-write device connection, the
|
|
3
|
+
* account master key, this device's certificate, and the stream data keys.
|
|
4
|
+
*
|
|
5
|
+
* Owner decision (2026-10-01): adding a device needs only `cleo login` and
|
|
6
|
+
* the one-time browser approval; that approval also hands the device the
|
|
7
|
+
* encryption key. So the account master key (MK) is escrowed on Cleo Nexus:
|
|
8
|
+
*
|
|
9
|
+
* 1. `GET /v1/account/keys/escrow` returns MK sealed to this device's X25519
|
|
10
|
+
* key (`sealTo`), released only to an approved, active device. The client
|
|
11
|
+
* opens it with the device's private key and checks it against the
|
|
12
|
+
* escrow's verifier.
|
|
13
|
+
* 2. No escrow and no account keys: this is the account's first vault use.
|
|
14
|
+
* The client mints MK and escrows it (`PUT`, insert-only). A concurrent
|
|
15
|
+
* first device loses the insert with 409 and reads the winner's key.
|
|
16
|
+
* 3. The device certifies itself under MK (a self-grant, `PUT
|
|
17
|
+
* /v1/devices/:id/key`), so other devices can verify its snapshots.
|
|
18
|
+
* 4. Signer trust comes from `certifiedSigners` over `GET /v1/devices/trust`,
|
|
19
|
+
* with the trust state persisted in {@link NexusVaultState}.
|
|
20
|
+
*
|
|
21
|
+
* Threat model (cleo-nexus T082): the escrow `PUT` sends MK to the server
|
|
22
|
+
* over TLS, and the server stores it encrypted under a server-held key
|
|
23
|
+
* (`KEY_ESCROW_SECRET`). Snapshots are therefore encrypted at rest with keys
|
|
24
|
+
* Cleo Nexus can recover: this is server-escrowed encryption, not
|
|
25
|
+
* zero-knowledge end-to-end encryption. What the escrow does guarantee is
|
|
26
|
+
* that MK is released only to an approved, active device of the account,
|
|
27
|
+
* sealed to that device's key.
|
|
28
|
+
*
|
|
29
|
+
* A project's data key (PDK) is minted by its first pusher and stored
|
|
30
|
+
* wrapped by MK (`PUT /v1/projects/:id/keys/:userId`); the home stream key
|
|
31
|
+
* is derived from MK.
|
|
32
|
+
*
|
|
33
|
+
* No function here logs a key, and no error carries one.
|
|
34
|
+
*
|
|
35
|
+
* @task T12336
|
|
36
|
+
* @epic T12322
|
|
37
|
+
*/
|
|
38
|
+
import { nexusProjectKeysSchema, nexusUserKeysSchema } from '@cleocode/contracts';
|
|
39
|
+
import { DeviceTrust as DeviceTrustSchema, KeyEscrowGrant, PutKeyEscrowResult, } from '@cleocode/contracts/cloud';
|
|
40
|
+
import { z } from 'zod';
|
|
41
|
+
import { openSealed, randomKey } from './crypto.js';
|
|
42
|
+
import { Http, NexusError } from './http.js';
|
|
43
|
+
import { certifiedSigners, createDeviceGrant, homeStreamKey, masterKeyVerifier, newProjectKey, unwrapProjectKey, wrapProjectKey, } from './keys.js';
|
|
44
|
+
import { NexusAccountError, resolveNexusApiUrl } from './nexus-auth.js';
|
|
45
|
+
import { assertNexusCloudDeviceMode, NEXUS_CLOUD_TIMEOUT_MS, nexusCredentialWarnings, } from './nexus-cloud.js';
|
|
46
|
+
import { ensureNexusDeviceCredential, nexusApiErrorToAccountError } from './nexus-enrol.js';
|
|
47
|
+
import { NexusVaultState } from './nexus-vault-state.js';
|
|
48
|
+
/** Timeout of a snapshot blob upload or download. */
|
|
49
|
+
export const NEXUS_VAULT_BLOB_TIMEOUT_MS = 10 * 60_000;
|
|
50
|
+
/** The sealed-box context of an escrow release (must match the server, cleo-nexus T082). */
|
|
51
|
+
export const escrowContext = (userId, deviceId) => `cleo-nexus/escrow/v1:${userId}:${deviceId}`;
|
|
52
|
+
const b64 = (s) => Buffer.from(s, 'base64');
|
|
53
|
+
function keyPairOf(kp) {
|
|
54
|
+
return { publicKey: b64(kp.publicKey), privateKey: b64(kp.privateKey) };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Open a read-write vault connection with this machine's device credential.
|
|
58
|
+
*
|
|
59
|
+
* @param opts - API URL, account, stores and test overrides.
|
|
60
|
+
* @returns The connection.
|
|
61
|
+
* @throws {NexusAccountError} Not signed in, device mode off, or no device keys.
|
|
62
|
+
*/
|
|
63
|
+
export async function connectNexusVault(opts = {}) {
|
|
64
|
+
assertNexusCloudDeviceMode();
|
|
65
|
+
const apiUrl = resolveNexusApiUrl(opts.apiUrl);
|
|
66
|
+
const handle = await ensureNexusDeviceCredential({ ...opts, apiUrl });
|
|
67
|
+
const device = handle.device;
|
|
68
|
+
const bearer = device.currentBearer();
|
|
69
|
+
if (bearer === null) {
|
|
70
|
+
throw new NexusAccountError('E_NEXUS_NOT_SIGNED_IN', `not signed in to Cleo Nexus at ${apiUrl}`, 'run `cleo login nexus`');
|
|
71
|
+
}
|
|
72
|
+
const entryKeys = device.unseal().keys;
|
|
73
|
+
if (entryKeys === null) {
|
|
74
|
+
throw new NexusAccountError('E_NEXUS_VAULT_KEY_UNAVAILABLE', 'this device has no key pair (it was enrolled before device keys existed)', 'run `cleo logout nexus --revoke` and then `cleo login nexus` to enrol it again');
|
|
75
|
+
}
|
|
76
|
+
const base = opts.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
77
|
+
const timeoutMs = opts.timeoutMs ?? NEXUS_CLOUD_TIMEOUT_MS;
|
|
78
|
+
const blobTimeoutMs = opts.blobTimeoutMs ?? NEXUS_VAULT_BLOB_TIMEOUT_MS;
|
|
79
|
+
const http = new Http({
|
|
80
|
+
baseUrl: apiUrl,
|
|
81
|
+
token: bearer,
|
|
82
|
+
deviceId: device.deviceId,
|
|
83
|
+
fetch: (input, init) => base(input, { ...init, signal: AbortSignal.timeout(timeoutMs) }),
|
|
84
|
+
maxAttempts: 2,
|
|
85
|
+
});
|
|
86
|
+
const raw = (method, path, schema, body) => http.request(method, path, schema, body);
|
|
87
|
+
return {
|
|
88
|
+
apiUrl,
|
|
89
|
+
userId: device.userId,
|
|
90
|
+
deviceId: device.deviceId,
|
|
91
|
+
device,
|
|
92
|
+
keys: { encryption: keyPairOf(entryKeys.encryption), signing: keyPairOf(entryKeys.signing) },
|
|
93
|
+
http,
|
|
94
|
+
blobFetch: (input, init) => base(input, { ...init, signal: AbortSignal.timeout(blobTimeoutMs) }),
|
|
95
|
+
state: opts.vaultState ?? new NexusVaultState(),
|
|
96
|
+
warnings: nexusCredentialWarnings(handle.warnings),
|
|
97
|
+
raw,
|
|
98
|
+
async call(method, path, schema, body) {
|
|
99
|
+
try {
|
|
100
|
+
return await raw(method, path, schema, body);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
throw nexusApiErrorToAccountError(err);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
async find(path, schema) {
|
|
107
|
+
try {
|
|
108
|
+
return await raw('GET', path, schema);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (err instanceof NexusError && err.status === 404)
|
|
112
|
+
return null;
|
|
113
|
+
throw nexusApiErrorToAccountError(err);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const isConflict = (err, reason) => err instanceof NexusError &&
|
|
119
|
+
err.status === 409 &&
|
|
120
|
+
(reason === undefined || err.details?.['reason'] === reason);
|
|
121
|
+
function keyUnavailable(message, fix) {
|
|
122
|
+
return new NexusAccountError('E_NEXUS_VAULT_KEY_UNAVAILABLE', message, fix);
|
|
123
|
+
}
|
|
124
|
+
async function openEscrow(conn) {
|
|
125
|
+
const grant = await conn.find('/v1/account/keys/escrow', KeyEscrowGrant);
|
|
126
|
+
if (grant === null)
|
|
127
|
+
return null;
|
|
128
|
+
if (grant.deviceId !== conn.deviceId) {
|
|
129
|
+
throw keyUnavailable('the server released the account key to another device id');
|
|
130
|
+
}
|
|
131
|
+
let mk;
|
|
132
|
+
try {
|
|
133
|
+
mk = openSealed(conn.keys.encryption, b64(grant.sealedMasterKey), escrowContext(conn.userId, conn.deviceId));
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
throw keyUnavailable('the escrowed account key does not open with this device key', 'run `cleo logout nexus --revoke` and `cleo login nexus` to enrol this machine again');
|
|
137
|
+
}
|
|
138
|
+
if (mk.length !== 32 || masterKeyVerifier(mk) !== grant.masterKeyVerifier) {
|
|
139
|
+
throw keyUnavailable('the escrowed account key does not match its verifier');
|
|
140
|
+
}
|
|
141
|
+
return { mk, kv: grant.keyVersion };
|
|
142
|
+
}
|
|
143
|
+
async function mintEscrow(conn) {
|
|
144
|
+
const existing = await conn.find('/v1/account/keys', nexusUserKeysSchema);
|
|
145
|
+
if (existing !== null) {
|
|
146
|
+
throw keyUnavailable('this account has an encryption key that is not escrowed, so it cannot be handed to this device', 'run `cleo cloud push` once on a device that already holds the key, so it escrows it');
|
|
147
|
+
}
|
|
148
|
+
const mk = randomKey();
|
|
149
|
+
try {
|
|
150
|
+
await conn.raw('PUT', '/v1/account/keys/escrow', PutKeyEscrowResult, {
|
|
151
|
+
masterKey: mk.toString('base64url'),
|
|
152
|
+
keyVersion: 1,
|
|
153
|
+
masterKeyVerifier: masterKeyVerifier(mk),
|
|
154
|
+
});
|
|
155
|
+
return { mk, kv: 1 };
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
if (!isConflict(err))
|
|
159
|
+
throw nexusApiErrorToAccountError(err);
|
|
160
|
+
// Another device escrowed first: use its key.
|
|
161
|
+
const won = await openEscrow(conn);
|
|
162
|
+
if (won === null)
|
|
163
|
+
throw keyUnavailable('the account key was escrowed concurrently but is not readable');
|
|
164
|
+
return won;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function ensureCertified(conn, mk, kv) {
|
|
168
|
+
const trust = await conn.call('GET', '/v1/devices/trust', DeviceTrustSchema);
|
|
169
|
+
const mine = conn.keys.signing.publicKey.toString('base64');
|
|
170
|
+
const certified = trust.certificates.some((c) => c.deviceId === conn.deviceId && c.keyVersion === kv && c.signingPublicKey === mine && c.live);
|
|
171
|
+
if (certified)
|
|
172
|
+
return trust;
|
|
173
|
+
const grant = createDeviceGrant({
|
|
174
|
+
masterKey: mk,
|
|
175
|
+
userId: conn.userId,
|
|
176
|
+
keyVersion: kv,
|
|
177
|
+
recipient: {
|
|
178
|
+
deviceId: conn.deviceId,
|
|
179
|
+
encryptionPublicKey: conn.keys.encryption.publicKey,
|
|
180
|
+
signingPublicKey: conn.keys.signing.publicKey,
|
|
181
|
+
},
|
|
182
|
+
signer: { deviceId: conn.deviceId, signing: conn.keys.signing },
|
|
183
|
+
});
|
|
184
|
+
await conn.call('PUT', `/v1/devices/${encodeURIComponent(conn.deviceId)}/key`, z.looseObject({}), grant);
|
|
185
|
+
return conn.call('GET', '/v1/devices/trust', DeviceTrustSchema);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Get the account master key for this device, minting and escrowing it on
|
|
189
|
+
* the account's first vault use, and certify this device under it.
|
|
190
|
+
*
|
|
191
|
+
* @param conn - A vault connection.
|
|
192
|
+
* @param opts - `readOnly`: never mint, escrow or certify (GET only); a missing escrow is
|
|
193
|
+
* `E_NEXUS_VAULT_EMPTY`.
|
|
194
|
+
* @returns The key, its version and the trusted signers.
|
|
195
|
+
* @throws {NexusAccountError} `E_NEXUS_VAULT_KEY_UNAVAILABLE` when the key
|
|
196
|
+
* cannot be obtained or verified; a mapped API error otherwise.
|
|
197
|
+
*/
|
|
198
|
+
export async function unlockNexusAccountKey(conn, opts = {}) {
|
|
199
|
+
const escrowed = await openEscrow(conn);
|
|
200
|
+
if (escrowed === null && opts.readOnly === true) {
|
|
201
|
+
// Nothing was ever pushed from any device: a read has nothing to read, and
|
|
202
|
+
// must not mint the account key as a side effect.
|
|
203
|
+
throw new NexusAccountError('E_NEXUS_VAULT_EMPTY', 'the cloud vault is empty: no device has pushed a snapshot to this account yet', 'run `cleo cloud push` on a device that has the data');
|
|
204
|
+
}
|
|
205
|
+
const unlocked = escrowed ?? (await mintEscrow(conn));
|
|
206
|
+
const trust = opts.readOnly === true
|
|
207
|
+
? await conn.call('GET', '/v1/devices/trust', DeviceTrustSchema)
|
|
208
|
+
: await ensureCertified(conn, unlocked.mk, unlocked.kv);
|
|
209
|
+
// Read, evaluate and persist the trust state under one lock, so two
|
|
210
|
+
// concurrent commands cannot interleave and lose a narrowed pin.
|
|
211
|
+
const evaluation = conn.state.updateTrust(conn.apiUrl, conn.userId, (current) => {
|
|
212
|
+
const e = certifiedSigners(new Map([[unlocked.kv, unlocked.mk]]), conn.userId, trust, current, unlocked.kv);
|
|
213
|
+
return { trust: e.keyRotated || e.serverError ? current : e.state, result: e };
|
|
214
|
+
});
|
|
215
|
+
if (evaluation.keyRotated || evaluation.serverError) {
|
|
216
|
+
throw keyUnavailable(evaluation.keyRotated
|
|
217
|
+
? 'the account key was rotated and this device does not hold the new one'
|
|
218
|
+
: 'the server declared an account key version no rotation explains');
|
|
219
|
+
}
|
|
220
|
+
return { masterKey: unlocked.mk, keyVersion: unlocked.kv, signers: evaluation.signers };
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* The data key of a project stream: unwrap the newest wrapped key, or mint
|
|
224
|
+
* and store one when the project has none yet (its first push).
|
|
225
|
+
*
|
|
226
|
+
* @param conn - A vault connection.
|
|
227
|
+
* @param mk - The unlocked master key.
|
|
228
|
+
* @param projectId - The server's project id.
|
|
229
|
+
* @param mint - Whether a missing key may be created (push: yes; restore: no).
|
|
230
|
+
* @returns The project data key, or `null` when none exists and `mint` is false.
|
|
231
|
+
*/
|
|
232
|
+
export async function nexusProjectDataKey(conn, mk, projectId, mint) {
|
|
233
|
+
const path = `/v1/projects/${encodeURIComponent(projectId)}/keys`;
|
|
234
|
+
const read = async () => {
|
|
235
|
+
const list = await conn.find(path, nexusProjectKeysSchema);
|
|
236
|
+
const newest = list?.keys[0];
|
|
237
|
+
if (!newest)
|
|
238
|
+
return null;
|
|
239
|
+
try {
|
|
240
|
+
return unwrapProjectKey(mk, newest.wrappedProjectKey, projectId, newest.keyVersion);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
throw keyUnavailable(`the project key of ${projectId} does not open with this account's key`);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const have = await read();
|
|
247
|
+
if (have !== null || !mint)
|
|
248
|
+
return have;
|
|
249
|
+
const pdk = newProjectKey();
|
|
250
|
+
try {
|
|
251
|
+
await conn.raw('PUT', `${path}/${encodeURIComponent(conn.userId)}`, z.looseObject({}), {
|
|
252
|
+
wrappedProjectKey: wrapProjectKey(mk, pdk, projectId, 1),
|
|
253
|
+
keyVersion: 1,
|
|
254
|
+
});
|
|
255
|
+
return pdk;
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
if (!isConflict(err))
|
|
259
|
+
throw nexusApiErrorToAccountError(err);
|
|
260
|
+
const won = await read();
|
|
261
|
+
if (won === null)
|
|
262
|
+
throw keyUnavailable(`the project key of ${projectId} is not readable`);
|
|
263
|
+
return won;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* The data key of the account's `home:` stream (derived from MK, never stored).
|
|
268
|
+
*
|
|
269
|
+
* @param mk - The unlocked master key.
|
|
270
|
+
* @returns The home stream key.
|
|
271
|
+
*/
|
|
272
|
+
export function nexusHomeDataKey(mk) {
|
|
273
|
+
return homeStreamKey(mk);
|
|
274
|
+
}
|
|
275
|
+
/** Re-export for callers that only need the URL resolver. */
|
|
276
|
+
export { resolveNexusApiUrl };
|
|
277
|
+
//# sourceMappingURL=nexus-vault-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nexus-vault-keys.js","sourceRoot":"","sources":["../../src/cloud/nexus-vault-keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This machine's cloud vault state (`<cleoHome>/nexus-vault.json`):
|
|
3
|
+
* secret-free, machine-local bookkeeping the vault needs between runs.
|
|
4
|
+
*
|
|
5
|
+
* - Per account: the signer {@link TrustState} learned from
|
|
6
|
+
* `certifiedSigners` (trust only tightens, so it must survive restarts).
|
|
7
|
+
* - Per (stream, local store): the snapshot this store last pushed or
|
|
8
|
+
* restored, which decides "behind" (another device pushed since) and
|
|
9
|
+
* "pending changes" (this store changed since).
|
|
10
|
+
*
|
|
11
|
+
* Every read-modify-write runs under a lock file and writes atomically (temp
|
|
12
|
+
* file + rename). A file this version cannot read (truncated, invalid, or
|
|
13
|
+
* written by a newer CLEO) is moved aside with a warning, never reset in
|
|
14
|
+
* place, so a downgrade or a torn write cannot silently discard the signer
|
|
15
|
+
* pins. Nothing here is secret: keys and tokens stay in the sealed device
|
|
16
|
+
* store.
|
|
17
|
+
*
|
|
18
|
+
* @task T12336
|
|
19
|
+
* @epic T12322
|
|
20
|
+
*/
|
|
21
|
+
import type { CloudWarning } from '@cleocode/contracts';
|
|
22
|
+
import { z } from 'zod';
|
|
23
|
+
import { type TrustState } from './keys.js';
|
|
24
|
+
declare const streamStateSchema: z.ZodObject<{
|
|
25
|
+
/** The snapshot this store last pushed or restored. */
|
|
26
|
+
lastCheckpointId: z.ZodNullable<z.ZodString>;
|
|
27
|
+
/** Its coversSeq: an older snapshot is never restored over it without `--checkpoint`. */
|
|
28
|
+
lastCoversSeq: z.ZodNumber;
|
|
29
|
+
updatedAt: z.ZodString;
|
|
30
|
+
/**
|
|
31
|
+
* A push from this store that had not recorded its snapshot yet: the parent it
|
|
32
|
+
* pushed over (T13007). Cleared when the snapshot is recorded.
|
|
33
|
+
*/
|
|
34
|
+
pushInFlight: z.ZodOptional<z.ZodObject<{
|
|
35
|
+
parentCheckpointId: z.ZodNullable<z.ZodString>;
|
|
36
|
+
at: z.ZodString;
|
|
37
|
+
gitTracked: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
38
|
+
files: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
39
|
+
}, z.core.$strip>>;
|
|
40
|
+
/**
|
|
41
|
+
* Paths (relative to the section root) the last synced snapshot marks as
|
|
42
|
+
* git-tracked: git's job, so they are left out of every file comparison
|
|
43
|
+
* with it, and a machine without git carries the marks on (T13019).
|
|
44
|
+
*/
|
|
45
|
+
gitTracked: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
46
|
+
/**
|
|
47
|
+
* The last synced snapshot's plain files, path to digest (a prefix of the
|
|
48
|
+
* vault file digest), so a later comparison judges each file on its own,
|
|
49
|
+
* whatever either side's git tracks (T13038).
|
|
50
|
+
*/
|
|
51
|
+
files: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
52
|
+
}, z.core.$loose>;
|
|
53
|
+
/** What a store last synced with on a stream. */
|
|
54
|
+
export type VaultStreamState = z.infer<typeof streamStateSchema>;
|
|
55
|
+
/** Key of one local store on one stream. */
|
|
56
|
+
export declare const vaultStreamKey: (streamId: string, storeRoot: string) => string;
|
|
57
|
+
/** Warning code: the state file was unreadable or newer, and was moved aside. */
|
|
58
|
+
export declare const W_NEXUS_VAULT_STATE_MOVED = "W_NEXUS_VAULT_STATE_MOVED";
|
|
59
|
+
/**
|
|
60
|
+
* Read/modify/write access to the vault state file.
|
|
61
|
+
*/
|
|
62
|
+
export declare class NexusVaultState {
|
|
63
|
+
/** Absolute path of the state file. */
|
|
64
|
+
readonly path: string;
|
|
65
|
+
private warnings;
|
|
66
|
+
/** @param filePath - Override for tests; defaults to {@link resolveNexusVaultStatePath}. */
|
|
67
|
+
constructor(filePath?: string);
|
|
68
|
+
/** Warnings raised since the last call (a moved-aside file), for the command's result. */
|
|
69
|
+
drainWarnings(): CloudWarning[];
|
|
70
|
+
/** Run `fn` holding the state file's lock. */
|
|
71
|
+
private locked;
|
|
72
|
+
/** Move an unusable file aside (never overwrite it) and start empty. */
|
|
73
|
+
private moveAside;
|
|
74
|
+
private read;
|
|
75
|
+
private write;
|
|
76
|
+
/** Read, let `fn` change the state, and write it back, all under the lock. */
|
|
77
|
+
private update;
|
|
78
|
+
/** Read under the lock (moving an unusable file aside). */
|
|
79
|
+
private snapshot;
|
|
80
|
+
private account;
|
|
81
|
+
/** The account's persisted signer trust state. */
|
|
82
|
+
trust(apiUrl: string, userId: string): TrustState;
|
|
83
|
+
/** Persist the trust state returned by `certifiedSigners`. */
|
|
84
|
+
saveTrust(apiUrl: string, userId: string, trust: TrustState): void;
|
|
85
|
+
/**
|
|
86
|
+
* Read the account's trust state, let `fn` evaluate it, and persist the
|
|
87
|
+
* trust it returns, all under one lock.
|
|
88
|
+
*
|
|
89
|
+
* @param apiUrl - Account API URL.
|
|
90
|
+
* @param userId - Account user id.
|
|
91
|
+
* @param fn - Receives the current trust; returns the trust to store and a result.
|
|
92
|
+
* @returns `fn`'s result.
|
|
93
|
+
*/
|
|
94
|
+
updateTrust<T>(apiUrl: string, userId: string, fn: (current: TrustState) => {
|
|
95
|
+
trust: TrustState;
|
|
96
|
+
result: T;
|
|
97
|
+
}): T;
|
|
98
|
+
/** What `storeRoot` last synced with on `streamId`, or `null`. */
|
|
99
|
+
stream(apiUrl: string, userId: string, streamId: string, storeRoot: string): VaultStreamState | null;
|
|
100
|
+
/**
|
|
101
|
+
* Record that a push from `storeRoot` is about to create a snapshot over
|
|
102
|
+
* `parentCheckpointId` (T13007). {@link saveStream} clears the mark; when a
|
|
103
|
+
* crash loses that write, the mark tells the next command that the head
|
|
104
|
+
* this device and replica pushed over that parent is this store's own, and
|
|
105
|
+
* what that snapshot marks and holds (`pushed`), so recovering it loses no
|
|
106
|
+
* per-path digest.
|
|
107
|
+
*/
|
|
108
|
+
markPushInFlight(apiUrl: string, userId: string, streamId: string, storeRoot: string, parentCheckpointId: string | null, pushed?: {
|
|
109
|
+
gitTracked?: readonly string[];
|
|
110
|
+
files?: Readonly<Record<string, string>>;
|
|
111
|
+
}): void;
|
|
112
|
+
/** Record that `storeRoot` now holds `checkpointId` on `streamId`. */
|
|
113
|
+
saveStream(apiUrl: string, userId: string, streamId: string, storeRoot: string, value: {
|
|
114
|
+
lastCheckpointId: string;
|
|
115
|
+
lastCoversSeq: number;
|
|
116
|
+
gitTracked?: readonly string[];
|
|
117
|
+
files?: Readonly<Record<string, string>>;
|
|
118
|
+
}): void;
|
|
119
|
+
}
|
|
120
|
+
export {};
|
|
121
|
+
//# sourceMappingURL=nexus-vault-state.d.ts.map
|