@sema-agent/server 7.150.0 → 7.152.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/MIGRATION.md +451 -0
- package/README.md +15 -3
- package/README.zh-CN.md +10 -2
- package/USAGE.md +144 -87
- package/deploy/sema-up/README.md +11 -4
- package/deploy/sema-up/chart/Chart.yaml +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
- package/deploy/sema-up/chart/templates/server.yaml +5 -3
- package/deploy/sema-up/chart/values-full-single.yaml +3 -1
- package/deploy/sema-up/chart/values.yaml +8 -1
- package/deploy/sema-up/cluster-up.sh +7 -6
- package/deploy/sema-up/kube-up.sh +6 -6
- package/deploy/sema-up/lib/flagshape.sh +36 -8
- package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
- package/deploy/sema-up/lib/helm-values-kube.py +2 -0
- package/deploy/sema-up/machines.example.yaml +3 -1
- package/deploy/sema-up/sema-up.sh +22 -16
- package/dist/adoption/import.js +3 -3
- package/dist/approval-ask-audit-store.d.ts +1 -1
- package/dist/approval-ask-machine.d.ts +4 -10
- package/dist/approval-ask-retention.d.ts +1 -1
- package/dist/approval-card.d.ts +12 -14
- package/dist/approval-gate-currency.d.ts +9 -9
- package/dist/approval-gate-currency.js +3 -4
- package/dist/approval-hmac.d.ts +17 -1
- package/dist/approval-hmac.js +7 -1
- package/dist/approval-queue-kind.d.ts +1 -1
- package/dist/approval.d.ts +2 -2
- package/dist/approval.js +2 -2
- package/dist/auth-bridge.d.ts +20 -0
- package/dist/auth-bridge.js +9 -0
- package/dist/background-session-reap.d.ts +1 -1
- package/dist/bake-runner/main.d.ts +4 -2
- package/dist/bind-host.d.ts +3 -6
- package/dist/bind-host.js +4 -7
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/coordinators.d.ts +1 -1
- package/dist/boot/coordinators.js +9 -10
- package/dist/boot/device-lane.js +2 -0
- package/dist/boot/engine-lease.d.ts +5 -0
- package/dist/boot/engine-lease.js +1 -0
- package/dist/boot/execution-env.d.ts +9 -14
- package/dist/boot/execution-env.js +85 -22
- package/dist/boot/execution-lane.js +32 -5
- package/dist/boot/late-binds.d.ts +8 -4
- package/dist/boot/late-binds.js +7 -1
- package/dist/boot/leader.d.ts +31 -30
- package/dist/boot/leader.js +38 -28
- package/dist/boot/leg-path-adjudication.d.ts +40 -0
- package/dist/boot/leg-path-adjudication.js +18 -0
- package/dist/boot/memory-consolidation.d.ts +3 -2
- package/dist/boot/memory-consolidation.js +6 -6
- package/dist/boot/parked-revive-gate.js +3 -15
- package/dist/boot/reapers.d.ts +6 -1
- package/dist/boot/reapers.js +13 -2
- package/dist/boot/resolve-spec.d.ts +3 -3
- package/dist/boot/resolve-spec.js +43 -48
- package/dist/boot/runner-deps.d.ts +46 -35
- package/dist/boot/runner-deps.js +94 -91
- package/dist/boot/session-age-out.d.ts +36 -0
- package/dist/boot/session-age-out.js +101 -0
- package/dist/boot/session-faces.d.ts +5 -14
- package/dist/boot/session-faces.js +9 -5
- package/dist/boot/shutdown.d.ts +6 -0
- package/dist/boot/shutdown.js +10 -4
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-02-web-admin-pull.js +4 -5
- package/dist/boot/stage-05-execution-env.d.ts +5 -3
- package/dist/boot/stage-05-execution-env.js +3 -2
- package/dist/boot/stage-06-runners.d.ts +9 -4
- package/dist/boot/stage-06-runners.js +24 -9
- package/dist/boot/stage-07-capability-layer.d.ts +8 -4
- package/dist/boot/stage-07-capability-layer.js +3 -2
- package/dist/boot/stage-08-reapers.d.ts +8 -4
- package/dist/boot/stage-08-reapers.js +4 -2
- package/dist/boot/stage-09-leader.d.ts +12 -5
- package/dist/boot/stage-09-leader.js +14 -5
- package/dist/boot/stage-10-http-server.d.ts +19 -5
- package/dist/boot/stage-10-http-server.js +14 -21
- package/dist/boot/stores.js +7 -4
- package/dist/boot/web-admin.js +5 -8
- package/dist/boot/workflow-orchestration.d.ts +7 -2
- package/dist/boot/workflow-orchestration.js +24 -7
- package/dist/bounded-rotation.d.ts +29 -0
- package/dist/bounded-rotation.js +24 -0
- package/dist/capabilities/approvals-push.d.ts +3 -3
- package/dist/capabilities/scenarios.d.ts +28 -13
- package/dist/capabilities/scenarios.js +2 -2
- package/dist/capability-facts.d.ts +43 -32
- package/dist/capability-facts.js +45 -51
- package/dist/card-rule-offers.d.ts +32 -0
- package/dist/card-rule-offers.js +130 -0
- package/dist/center-credential.d.ts +25 -6
- package/dist/center-credential.js +25 -5
- package/dist/config-catalog.d.ts +26 -7
- package/dist/config-catalog.js +26 -22
- package/dist/config-dir-trust.js +4 -2
- package/dist/config-invariants.d.ts +20 -8
- package/dist/config-invariants.js +55 -12
- package/dist/config-lkg.d.ts +5 -19
- package/dist/config-lkg.js +8 -62
- package/dist/config-provider.d.ts +1 -1
- package/dist/config-root-migration.d.ts +2 -2
- package/dist/config-types.d.ts +38 -42
- package/dist/config.d.ts +58 -7
- package/dist/config.js +90 -40
- package/dist/control-socket.d.ts +51 -0
- package/dist/control-socket.js +115 -0
- package/dist/deployment-governance.d.ts +2 -1
- package/dist/deployment-shape.d.ts +9 -1
- package/dist/deployment-shape.js +2 -1
- package/dist/device-protocol.d.ts +5 -4
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.d.ts +7 -0
- package/dist/device-ws-hub.js +10 -3
- package/dist/device-ws-protocol.d.ts +63 -10
- package/dist/device-ws-protocol.js +56 -25
- package/dist/elicitation.js +2 -2
- package/dist/engine-identity.d.ts +19 -7
- package/dist/engine-identity.js +10 -2
- package/dist/entry-mode-clamp-notice.d.ts +2 -1
- package/dist/entry-problems.d.ts +40 -3
- package/dist/entry-problems.js +3 -1
- package/dist/execution-env-refusal.d.ts +29 -0
- package/dist/execution-env-refusal.js +8 -0
- package/dist/execution-lane-caps.d.ts +3 -1
- package/dist/field-conflict.d.ts +1 -1
- package/dist/file-history-capture.d.ts +11 -4
- package/dist/file-history-capture.js +9 -6
- package/dist/file-history-disclosure.d.ts +7 -5
- package/dist/file-history-disclosure.js +7 -5
- package/dist/fleet/drain-entry.d.ts +4 -0
- package/dist/fleet/engine-signal.d.ts +12 -29
- package/dist/fleet/engine-signal.js +1 -7
- package/dist/fleet-client.js +2 -5
- package/dist/gate-settlement.d.ts +1 -8
- package/dist/gate-settlement.js +0 -4
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +2 -3
- package/dist/hitl-delivery.js +0 -2
- package/dist/hooks/hook-llm.js +4 -2
- package/dist/hooks/hook-runner.d.ts +3 -2
- package/dist/hooks/hook-runner.js +18 -3
- package/dist/host-decision.d.ts +11 -11
- package/dist/host-lsp-manager.d.ts +2 -2
- package/dist/http/active-run-conflict.d.ts +35 -2
- package/dist/http/active-run-conflict.js +48 -19
- package/dist/http/admission.js +17 -2
- package/dist/http/approval-sweeps.d.ts +1 -1
- package/dist/http/approval-sweeps.js +10 -7
- package/dist/http/checkpoint-ctx.d.ts +4 -0
- package/dist/http/checkpoint-ctx.js +2 -0
- package/dist/http/dispatch.d.ts +8 -3
- package/dist/http/dispatch.js +59 -32
- package/dist/http/durable-run-leg.js +16 -17
- package/dist/http/health-reader.d.ts +16 -9
- package/dist/http/health-reader.js +2 -1
- package/dist/http/health-self-report.d.ts +9 -1
- package/dist/http/health-self-report.js +3 -1
- package/dist/http/owner-access.d.ts +33 -14
- package/dist/http/owner-access.js +40 -10
- package/dist/http/principal-gate.d.ts +49 -21
- package/dist/http/principal-gate.js +61 -11
- package/dist/http/request-channel.d.ts +23 -0
- package/dist/http/request-channel.js +9 -0
- package/dist/http/request-guards.js +17 -2
- package/dist/http/resume-ctx-read.js +42 -3
- package/dist/http/resume-legs.d.ts +4 -3
- package/dist/http/resume-legs.js +367 -117
- package/dist/http/route-ctx.d.ts +91 -15
- package/dist/http/route-ctx.js +17 -0
- package/dist/http/route-table.d.ts +5 -1
- package/dist/http/route-table.js +4 -0
- package/dist/http/routes/admin-config-refresh.js +3 -3
- package/dist/http/routes/admin-drain.d.ts +3 -0
- package/dist/http/routes/admin-drain.js +7 -7
- package/dist/http/routes/admin-memory-optout.d.ts +1 -1
- package/dist/http/routes/admin-memory-optout.js +3 -3
- package/dist/http/routes/adoption.js +3 -5
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.d.ts +2 -1
- package/dist/http/routes/approvals-assistant.js +99 -51
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/capabilities.d.ts +4 -0
- package/dist/http/routes/capabilities.js +38 -10
- package/dist/http/routes/config-catalog.js +2 -2
- package/dist/http/routes/devices.js +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -3
- package/dist/http/routes/diagnostics.js +19 -7
- package/dist/http/routes/fleet.js +10 -8
- package/dist/http/routes/images.js +10 -10
- package/dist/http/routes/memory-bundle.js +3 -3
- package/dist/http/routes/memory-compliance.js +3 -3
- package/dist/http/routes/memory-consolidation.js +2 -2
- package/dist/http/routes/memory-origin.js +3 -3
- package/dist/http/routes/memory-policy.js +2 -2
- package/dist/http/routes/observability.js +3 -3
- package/dist/http/routes/projects.d.ts +3 -2
- package/dist/http/routes/projects.js +4 -5
- package/dist/http/routes/retention-ops.js +3 -3
- package/dist/http/routes/rules.js +5 -5
- package/dist/http/routes/run-permission-mode.d.ts +2 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +4 -9
- package/dist/http/routes/runs.js +171 -65
- package/dist/http/routes/session-sync.d.ts +22 -9
- package/dist/http/routes/session-sync.js +204 -107
- package/dist/http/routes/sessions-list.js +13 -7
- package/dist/http/routes/sessions.js +30 -15
- package/dist/http/routes/tasks.js +46 -41
- package/dist/http/routes/trace-usage.js +2 -2
- package/dist/http/routes/workflows.js +1 -1
- package/dist/http/server.d.ts +30 -30
- package/dist/http/server.js +16 -4
- package/dist/http/submit-ctx.d.ts +1 -1
- package/dist/http/submit-ctx.js +7 -4
- package/dist/http/wire-types.d.ts +14 -4
- package/dist/human-facing-args.d.ts +33 -0
- package/dist/human-facing-args.js +33 -0
- package/dist/identity-source.d.ts +20 -3
- package/dist/identity-source.js +14 -0
- package/dist/index.d.ts +5 -1
- package/dist/k8s-api-credentials.d.ts +29 -0
- package/dist/k8s-api-credentials.js +25 -0
- package/dist/lane-home-probe.d.ts +3 -7
- package/dist/lane-home-probe.js +2 -2
- package/dist/leader/diffup.d.ts +19 -0
- package/dist/leader/diffup.js +7 -0
- package/dist/leader/leader.d.ts +116 -11
- package/dist/leader/leader.js +69 -5
- package/dist/leader/repair-wire.js +2 -2
- package/dist/leader/run-entry.d.ts +2 -1
- package/dist/leader/run-entry.js +1 -1
- package/dist/leader/wire.d.ts +42 -132
- package/dist/leader/wire.js +81 -67
- package/dist/leg-facts.d.ts +13 -5
- package/dist/leg-facts.js +2 -1
- package/dist/memory-scope.d.ts +23 -11
- package/dist/memory-scope.js +18 -6
- package/dist/memory-sync-client.d.ts +30 -2
- package/dist/memory-sync-client.js +16 -9
- package/dist/model-entry-headers.d.ts +9 -10
- package/dist/model-entry-headers.js +0 -4
- package/dist/model-entry-refusal.d.ts +7 -4
- package/dist/model-entry-refusal.js +11 -5
- package/dist/model-plane-face.d.ts +1 -1
- package/dist/model-plane-face.js +3 -1
- package/dist/model-route-endpoint.d.ts +13 -7
- package/dist/model-route-endpoint.js +14 -11
- package/dist/model-select.d.ts +22 -0
- package/dist/model-select.js +9 -0
- package/dist/model-unreachable-notice.d.ts +11 -0
- package/dist/model-unreachable-notice.js +4 -4
- package/dist/object-store-buckets.d.ts +640 -6
- package/dist/object-store-buckets.js +166 -0
- package/dist/observability/err-text.d.ts +7 -0
- package/dist/observability/err-text.js +5 -0
- package/dist/observability/fail-open.d.ts +25 -17
- package/dist/observability/fail-open.js +25 -17
- package/dist/observability/logger.js +3 -1
- package/dist/observability/metrics.js +1 -0
- package/dist/operator-roster.d.ts +68 -0
- package/dist/operator-roster.js +32 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
- package/dist/orchestration/workflow-notify-journal.js +12 -1
- package/dist/orchestration/workflow-park-decision.d.ts +70 -18
- package/dist/orchestration/workflow-park-decision.js +49 -10
- package/dist/orchestration/workflow-park-holder.d.ts +65 -0
- package/dist/orchestration/workflow-park-holder.js +98 -0
- package/dist/orchestration/workflow-record-fence.d.ts +36 -0
- package/dist/orchestration/workflow-record-fence.js +42 -0
- package/dist/outbound-dispatcher.d.ts +71 -8
- package/dist/outbound-dispatcher.js +48 -7
- package/dist/owner-faces.d.ts +2 -2
- package/dist/parked-decide.d.ts +106 -55
- package/dist/parked-decide.js +153 -117
- package/dist/peer-directory.d.ts +2 -2
- package/dist/peer-inbound-face.d.ts +2 -6
- package/dist/peer-inbound-face.js +0 -3
- package/dist/permission-mode-admission.d.ts +74 -5
- package/dist/permission-mode-admission.js +56 -3
- package/dist/plugins/adoption-log-sql.d.ts +3 -1
- package/dist/plugins/adoption-log-sql.js +7 -1
- package/dist/plugins/approval-ask-store-file.d.ts +14 -2
- package/dist/plugins/approval-ask-store-file.js +11 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +10 -1
- package/dist/plugins/approval-ask-store-memory.js +35 -10
- package/dist/plugins/approval-ask-store-sql.d.ts +69 -4
- package/dist/plugins/approval-ask-store-sql.js +45 -5
- package/dist/plugins/approval-exemption-store.js +3 -0
- package/dist/plugins/approval-nonce-store.js +2 -0
- package/dist/plugins/blob-backend.d.ts +83 -7
- package/dist/plugins/blob-backend.js +57 -6
- package/dist/plugins/breaker-state-sql.js +2 -0
- package/dist/plugins/caching-session-store.d.ts +9 -15
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/checkpoint-index-columns.d.ts +20 -16
- package/dist/plugins/checkpoint-index-columns.js +3 -6
- package/dist/plugins/checkpoint-store-face.d.ts +119 -61
- package/dist/plugins/checkpoint-store-face.js +134 -55
- package/dist/plugins/device-store-sql.js +6 -0
- package/dist/plugins/error-origin.d.ts +18 -0
- package/dist/plugins/error-origin.js +10 -0
- package/dist/plugins/execution-placement-sql.js +6 -6
- package/dist/plugins/image-bake-store-sql.js +6 -0
- package/dist/plugins/image-index-sql.js +4 -0
- package/dist/plugins/landed-attendants.d.ts +212 -0
- package/dist/plugins/landed-attendants.js +161 -0
- package/dist/plugins/leader-run-store-sql.js +4 -0
- package/dist/plugins/local-checkpoint-store.d.ts +13 -3
- package/dist/plugins/local-checkpoint-store.js +38 -49
- package/dist/plugins/local-session-live-reference.d.ts +40 -0
- package/dist/plugins/local-session-live-reference.js +39 -0
- package/dist/plugins/local-session-store.d.ts +71 -33
- package/dist/plugins/local-session-store.js +129 -27
- package/dist/plugins/memory-engine-pg.js +4 -0
- package/dist/plugins/memory-engine-sql-apply.js +5 -2
- package/dist/plugins/memory-engine-tidb.js +4 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
- package/dist/plugins/memory-sync-store-pg.js +5 -0
- package/dist/plugins/memory-sync-store-tidb.js +5 -0
- package/dist/plugins/one-time-migrations.d.ts +104 -80
- package/dist/plugins/one-time-migrations.js +226 -132
- package/dist/plugins/org-delivery-quota-store.js +4 -1
- package/dist/plugins/outcome-ledger-sql.js +2 -0
- package/dist/plugins/permission-rule-store-sql.js +11 -4
- package/dist/plugins/pg-cost-quota.js +4 -0
- package/dist/plugins/pg-pool.js +35 -10
- package/dist/plugins/pg-rate-limiter.js +2 -0
- package/dist/plugins/posix-shell-fs.d.ts +6 -1
- package/dist/plugins/posix-shell-fs.js +4 -1
- package/dist/plugins/remote-env-adb.d.ts +19 -15
- package/dist/plugins/remote-env-adb.js +41 -15
- package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
- package/dist/plugins/remote-env-connect-seat.js +72 -0
- package/dist/plugins/remote-env-device.d.ts +22 -5
- package/dist/plugins/remote-env-device.js +106 -8
- package/dist/plugins/remote-env-e2b.d.ts +15 -6
- package/dist/plugins/remote-env-e2b.js +42 -32
- package/dist/plugins/remote-env-file-error.js +6 -2
- package/dist/plugins/remote-env-host.d.ts +46 -10
- package/dist/plugins/remote-env-host.js +124 -52
- package/dist/plugins/remote-env-k8s.d.ts +109 -41
- package/dist/plugins/remote-env-k8s.js +160 -54
- package/dist/plugins/remote-env-local-docker.d.ts +13 -8
- package/dist/plugins/remote-env-local-docker.js +34 -41
- package/dist/plugins/remote-env-ssh.d.ts +18 -12
- package/dist/plugins/remote-env-ssh.js +60 -59
- package/dist/plugins/remote-shell.d.ts +98 -1
- package/dist/plugins/remote-shell.js +218 -0
- package/dist/plugins/replica-registration.d.ts +1 -1
- package/dist/plugins/replica-registration.js +1 -1
- package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
- package/dist/plugins/resume-anchor-store-sql.js +12 -5
- package/dist/plugins/retention-lane-store-sql.js +4 -0
- package/dist/plugins/retention-sql.d.ts +20 -2
- package/dist/plugins/retention-sql.js +11 -0
- package/dist/plugins/run-store-sql.d.ts +21 -2
- package/dist/plugins/run-store-sql.js +31 -7
- package/dist/plugins/s3-presign.d.ts +23 -0
- package/dist/plugins/s3-presign.js +37 -3
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
- package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
- package/dist/plugins/scheduler-support.d.ts +2 -2
- package/dist/plugins/scheduler-support.js +0 -3
- package/dist/plugins/schema-consistency.d.ts +4 -2
- package/dist/plugins/schema-consistency.js +19 -2
- package/dist/plugins/schema-indexes.js +2 -0
- package/dist/plugins/send-file-ledger.d.ts +2 -2
- package/dist/plugins/send-file-ledger.js +5 -2
- package/dist/plugins/send-user-file.d.ts +3 -4
- package/dist/plugins/send-user-file.js +56 -52
- package/dist/plugins/serving-requirement.d.ts +26 -7
- package/dist/plugins/serving-requirement.js +11 -4
- package/dist/plugins/session-birth.d.ts +6 -2
- package/dist/plugins/session-blob-claim-token.d.ts +15 -0
- package/dist/plugins/session-blob-claim-token.js +20 -0
- package/dist/plugins/session-blob-namespace.d.ts +46 -0
- package/dist/plugins/session-blob-namespace.js +116 -0
- package/dist/plugins/session-capture-record-store-sql.js +2 -0
- package/dist/plugins/session-ext-table.d.ts +14 -1
- package/dist/plugins/session-ext-table.js +5 -1
- package/dist/plugins/session-row-sql.d.ts +49 -2
- package/dist/plugins/session-row-sql.js +56 -13
- package/dist/plugins/session-store-sql.d.ts +34 -18
- package/dist/plugins/session-store-sql.js +98 -17
- package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
- package/dist/plugins/shared-memory-store-sql.js +6 -2
- package/dist/plugins/snapshot-bucket-presence.d.ts +25 -2
- package/dist/plugins/snapshot-bucket-presence.js +8 -2
- package/dist/plugins/sql-driver.d.ts +2 -1
- package/dist/plugins/sql-driver.js +18 -3
- package/dist/plugins/sql-errors.d.ts +11 -6
- package/dist/plugins/sql-errors.js +5 -6
- package/dist/plugins/sql-json-column.d.ts +1 -1
- package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
- package/dist/plugins/stop-then-start-sentence.js +14 -10
- package/dist/plugins/stop-then-start.d.ts +109 -0
- package/dist/plugins/stop-then-start.js +104 -0
- package/dist/plugins/store-backend.d.ts +84 -15
- package/dist/plugins/store-backend.js +236 -72
- package/dist/plugins/store-boundary.d.ts +57 -0
- package/dist/plugins/store-boundary.js +139 -0
- package/dist/plugins/store-contracts.d.ts +17 -0
- package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
- package/dist/plugins/store-fault-sentence-m53.js +25 -0
- package/dist/plugins/store-fault.d.ts +26 -7
- package/dist/plugins/store-fault.js +18 -2
- package/dist/plugins/task-attachment-store.d.ts +2 -1
- package/dist/plugins/task-attachment-store.js +14 -1
- package/dist/plugins/task-list-store-sql.d.ts +2 -2
- package/dist/plugins/task-list-store-sql.js +10 -8
- package/dist/plugins/tidb-cost-quota.js +4 -0
- package/dist/plugins/tidb-pool.js +21 -25
- package/dist/plugins/tidb-rate-limiter.js +4 -0
- package/dist/plugins/user-input-ledger-sql.js +4 -0
- package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
- package/dist/plugins/workflow-run-store-sql.js +64 -4
- package/dist/plugins/workspace-custody.d.ts +4 -3
- package/dist/plugins/workspace-fill.d.ts +4 -7
- package/dist/plugins/workspace-fill.js +2 -1
- package/dist/plugins/write-behind-counter.js +5 -0
- package/dist/project-context.d.ts +0 -2
- package/dist/project-context.js +4 -8
- package/dist/project-registry.d.ts +46 -0
- package/dist/project-registry.js +44 -0
- package/dist/question.d.ts +2 -1
- package/dist/question.js +5 -13
- package/dist/request-form.d.ts +6 -1
- package/dist/request-form.js +4 -1
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +4 -0
- package/dist/request-value-closure.js +10 -0
- package/dist/rule-issue-reading.d.ts +1 -1
- package/dist/rules-consent.d.ts +1 -1
- package/dist/run-acceptance.d.ts +3 -2
- package/dist/run-acceptance.js +4 -6
- package/dist/run-local.js +9 -9
- package/dist/runs.d.ts +54 -16
- package/dist/runs.js +67 -13
- package/dist/runtime-governance.d.ts +5 -4
- package/dist/security.d.ts +30 -32
- package/dist/security.js +41 -7
- package/dist/sema-config-dir.d.ts +2 -1
- package/dist/server-secret-env.d.ts +12 -10
- package/dist/server-secret-env.js +24 -15
- package/dist/session-bindings.d.ts +82 -0
- package/dist/session-bindings.js +18 -0
- package/dist/session-children-retire.d.ts +2 -2
- package/dist/session-children-retire.js +2 -6
- package/dist/session-deletion.d.ts +16 -1
- package/dist/session-error-wire.d.ts +3 -3
- package/dist/session-error-wire.js +3 -3
- package/dist/session-incarnation.d.ts +10 -0
- package/dist/session-incarnation.js +10 -1
- package/dist/session-kind.d.ts +57 -0
- package/dist/session-kind.js +22 -0
- package/dist/session-row.d.ts +21 -1
- package/dist/session-row.js +7 -1
- package/dist/session-sync-kernel.d.ts +24 -14
- package/dist/session-sync-kernel.js +3 -6
- package/dist/session-sync.d.ts +25 -103
- package/dist/session-sync.js +14 -76
- package/dist/session-titler.d.ts +10 -3
- package/dist/session-titler.js +19 -6
- package/dist/ssh-host-key.d.ts +5 -0
- package/dist/ssh-host-key.js +3 -0
- package/dist/stores-sql/blob-index-sql.d.ts +30 -9
- package/dist/stores-sql/blob-index-sql.js +40 -21
- package/dist/stores-sql/checkpoint-store-sql.d.ts +54 -27
- package/dist/stores-sql/checkpoint-store-sql.js +70 -146
- package/dist/stores-sql/file-history-store-sql.d.ts +113 -15
- package/dist/stores-sql/file-history-store-sql.js +205 -95
- package/dist/stores-sql/pg-session-storage.d.ts +34 -7
- package/dist/stores-sql/pg-session-storage.js +37 -13
- package/dist/stores-sql/retention-store-sql.d.ts +1 -9
- package/dist/stores-sql/retention-store-sql.js +5 -19
- package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
- package/dist/stores-sql/session-policy-store-sql.js +61 -44
- package/dist/stores-sql/session-write-hooks.d.ts +11 -0
- package/dist/stores-sql/tidb-session-store.d.ts +58 -7
- package/dist/stores-sql/tidb-session-store.js +37 -13
- package/dist/submission-exit.d.ts +3 -2
- package/dist/submission-exit.js +9 -1
- package/dist/task-cwd.d.ts +2 -2
- package/dist/task-settings.d.ts +7 -5
- package/dist/task-settings.js +3 -3
- package/dist/terminal.d.ts +33 -2
- package/dist/terminal.js +139 -9
- package/dist/tool-approval.d.ts +465 -507
- package/dist/tool-approval.js +606 -1222
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/ledger-events.d.ts +3 -3
- package/dist/trace/project.d.ts +2 -3
- package/dist/trace/redact.js +3 -2
- package/dist/trace/self-minted-wire.d.ts +571 -178
- package/dist/trace/self-minted-wire.js +189 -56
- package/dist/web-admin-client/apply-effective.js +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +2 -2
- package/dist/web-admin-client/read-warnings.js +1 -1
- package/dist/web-admin-client/types.d.ts +1 -1
- package/dist/workspace-space.d.ts +10 -4
- package/dist/workspace-space.js +4 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +79 -28
- package/package.json +7 -3
- package/scripts/embed-minimal.mjs +3 -3
- package/wire-changes/server@7.151.0.json +762 -0
- package/wire-changes/server@7.152.0.json +900 -0
- package/dist/config-d-migration.d.ts +0 -37
- package/dist/config-d-migration.js +0 -60
- package/dist/http/session-inherit-env.d.ts +0 -36
- package/dist/http/session-inherit-env.js +0 -6
|
@@ -8,7 +8,7 @@ import { pgSafeJsonStringify } from "../plugins/pg-safe-json.js";
|
|
|
8
8
|
import { toIso } from "../plugins/sql-row-helpers.js";
|
|
9
9
|
import { placementCapabilityOf, LIST_PLACED_BATCH, PLACEMENT_SELECT_COLUMNS, placedRowFromRow, placementFromRow, placementInsertCells, SESSION_DURABILITY, SESSION_PLACEMENTS, } from "../plugins/session-placement.js";
|
|
10
10
|
import { contentForkRelation, fastForwardSharedContentDiverged } from "../session-sync-content.js";
|
|
11
|
-
import { classifySyncRelationshipByIds, SyncConflictError,
|
|
11
|
+
import { classifySyncRelationshipByIds, SyncConflictError, StagedCommitOccupantChangedError, stagingIdFor, STAGING_ID_MARKER, STAGING_GC_GRACE_MS, } from "../session-sync-kernel.js";
|
|
12
12
|
import { isPgUniqueViolation } from "../plugins/sql-errors.js";
|
|
13
13
|
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "../plugins/retention-declaration.js";
|
|
14
14
|
import { SESSION_META_INCARNATION_COLUMN, SESSION_META_LINEAGE_COLUMNS, forkLineageOfRow, headFromRow, incarnationFromCell, mintSessionIncarnation, sessionFaceFromRow } from "../session-incarnation.js";
|
|
@@ -224,14 +224,33 @@ export class PgSessionStore {
|
|
|
224
224
|
async register(sessionId, owner) {
|
|
225
225
|
await this.registerWithReceipt(sessionId, owner);
|
|
226
226
|
}
|
|
227
|
-
async registerWithReceipt(sessionId, owner) {
|
|
227
|
+
async registerWithReceipt(sessionId, owner, kind) {
|
|
228
228
|
if (!isSessionOwnerValue(owner)) {
|
|
229
229
|
if ((await this.headOf(sessionId)) !== undefined)
|
|
230
230
|
return {};
|
|
231
231
|
assertFirstOwnerWritable(sessionId, owner);
|
|
232
232
|
}
|
|
233
233
|
const incarnation = mintSessionIncarnation();
|
|
234
|
-
|
|
234
|
+
if (kind === undefined) {
|
|
235
|
+
await this.insertMeta(sessionId, owner, undefined, incarnation);
|
|
236
|
+
return { minted: { sessionId, owner, incarnation } };
|
|
237
|
+
}
|
|
238
|
+
const conn = await this.pool.connect();
|
|
239
|
+
try {
|
|
240
|
+
await conn.query("BEGIN");
|
|
241
|
+
await this.insertMetaOn(conn, sessionId, owner, undefined, incarnation);
|
|
242
|
+
const res = await conn.query("SELECT incarnation FROM session_meta WHERE session_id = $1 FOR UPDATE", [sessionId]);
|
|
243
|
+
if (res.rows[0]?.incarnation === incarnation)
|
|
244
|
+
await this.hooks.birth.record(statementsOn(conn), { rootSessionId: sessionId, kind });
|
|
245
|
+
await conn.query("COMMIT");
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
await conn.query("ROLLBACK").catch(() => undefined);
|
|
249
|
+
throw err;
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
conn.release();
|
|
253
|
+
}
|
|
235
254
|
return { minted: { sessionId, owner, incarnation } };
|
|
236
255
|
}
|
|
237
256
|
async deleteSessionIf(sessionId, cond) {
|
|
@@ -254,9 +273,12 @@ export class PgSessionStore {
|
|
|
254
273
|
await this.insertMeta(sessionId, placement === undefined ? null : placedSessionOwnerOf(sessionId, placement), placement);
|
|
255
274
|
}
|
|
256
275
|
async insertMeta(sessionId, owner, placement, incarnation = mintSessionIncarnation()) {
|
|
276
|
+
await this.insertMetaOn(this.pool, sessionId, owner, placement, incarnation);
|
|
277
|
+
}
|
|
278
|
+
async insertMetaOn(on, sessionId, owner, placement, incarnation) {
|
|
257
279
|
const now = new Date();
|
|
258
280
|
const placed = placementInsertCells(placement, now);
|
|
259
|
-
await
|
|
281
|
+
await on.query(`INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation, ${placed.columns}) ` +
|
|
260
282
|
"VALUES ($1,$2,$3,$4,NULL,0,$5,$6,$7,$8,$9,$10,$11) ON CONFLICT (session_id) DO NOTHING", [sessionId, owner, now, now, incarnation, ...placed.values]);
|
|
261
283
|
}
|
|
262
284
|
async placementOf(sessionId) {
|
|
@@ -318,7 +340,7 @@ export class PgSessionStore {
|
|
|
318
340
|
}
|
|
319
341
|
throw err instanceof SessionError
|
|
320
342
|
? err
|
|
321
|
-
: new SessionError("storage", `placed session ${sessionId} could not be deleted
|
|
343
|
+
: new SessionError("storage", `placed session ${sessionId} could not be deleted`, err instanceof Error ? err : undefined);
|
|
322
344
|
}
|
|
323
345
|
finally {
|
|
324
346
|
conn.release();
|
|
@@ -420,11 +442,13 @@ export class PgSessionStore {
|
|
|
420
442
|
if (metaRes.rows.length === 0)
|
|
421
443
|
return null;
|
|
422
444
|
const pool = this.pool;
|
|
423
|
-
const batchSize = opts
|
|
445
|
+
const batchSize = opts.batchSize ?? 500;
|
|
424
446
|
async function* gen() {
|
|
425
|
-
let cursor = opts
|
|
447
|
+
let cursor = opts.afterSeq ?? -1;
|
|
426
448
|
for (;;) {
|
|
427
449
|
const res = await pool.query(`SELECT seq, ${jsonColumnText("pg", "payload")} FROM session_event WHERE session_id = $1 AND seq > $2 ORDER BY seq ASC LIMIT $3`, [sessionId, cursor, batchSize]);
|
|
450
|
+
if (res.rows.length > 0)
|
|
451
|
+
await opts.recheck();
|
|
428
452
|
for (const r of res.rows)
|
|
429
453
|
yield decodeSessionEventPayload(r.payload, sessionId, r.seq);
|
|
430
454
|
if (res.rows.length < batchSize)
|
|
@@ -542,7 +566,7 @@ export class PgSessionStore {
|
|
|
542
566
|
this.pending.clear();
|
|
543
567
|
}
|
|
544
568
|
}
|
|
545
|
-
class PgStagingHandle {
|
|
569
|
+
export class PgStagingHandle {
|
|
546
570
|
pool;
|
|
547
571
|
hooks;
|
|
548
572
|
realSessionId;
|
|
@@ -583,11 +607,11 @@ class PgStagingHandle {
|
|
|
583
607
|
await conn.query("BEGIN");
|
|
584
608
|
const now = new Date();
|
|
585
609
|
const minted = mintSessionIncarnation();
|
|
586
|
-
if (opts.
|
|
587
|
-
const cas = await conn.query("UPDATE session_meta SET leaf_seq = leaf_seq + 1 WHERE session_id = $1 AND owner IS NOT DISTINCT FROM $2", [this.realSessionId, opts.
|
|
610
|
+
if (opts.expectedOccupant !== undefined) {
|
|
611
|
+
const cas = await conn.query("UPDATE session_meta SET leaf_seq = leaf_seq + 1 WHERE session_id = $1 AND owner IS NOT DISTINCT FROM $2 AND incarnation = $3", [this.realSessionId, opts.expectedOccupant.owner, opts.expectedOccupant.incarnation]);
|
|
588
612
|
if (cas.rowCount !== 1) {
|
|
589
613
|
await conn.query("ROLLBACK");
|
|
590
|
-
throw new
|
|
614
|
+
throw new StagedCommitOccupantChangedError(this.realSessionId);
|
|
591
615
|
}
|
|
592
616
|
}
|
|
593
617
|
else {
|
|
@@ -595,7 +619,7 @@ class PgStagingHandle {
|
|
|
595
619
|
const claimed = await conn.query("SELECT incarnation FROM session_meta WHERE session_id = $1 FOR UPDATE", [this.realSessionId]);
|
|
596
620
|
if (String(claimed.rows[0]?.incarnation) !== minted) {
|
|
597
621
|
await conn.query("ROLLBACK");
|
|
598
|
-
throw new
|
|
622
|
+
throw new StagedCommitOccupantChangedError(this.realSessionId);
|
|
599
623
|
}
|
|
600
624
|
}
|
|
601
625
|
settleHookVerdict(await this.hooks.beforeCommit(statementsOn(conn), { op: "import", rootSessionId: this.realSessionId }));
|
|
@@ -607,7 +631,7 @@ class PgStagingHandle {
|
|
|
607
631
|
throw new SessionError("placement_refused", `session ${this.realSessionId} belongs to the ${dstMeta.rows[0].placement_kind} placement partition — a session-sync staged commit cannot overwrite a delegation transcript`);
|
|
608
632
|
}
|
|
609
633
|
const srcIds = staged.rows.map((r) => String(r.entry_id));
|
|
610
|
-
const dstIds = opts.
|
|
634
|
+
const dstIds = opts.expectedOccupant !== undefined ? dst.rows.map((r) => String(r.entry_id)) : null;
|
|
611
635
|
const rel = classifySyncRelationshipByIds(srcIds, dstIds);
|
|
612
636
|
if ((rel.relation === "fork" || rel.relation === "stale") && opts.resolution !== "overwrite-dst") {
|
|
613
637
|
await conn.query("ROLLBACK");
|
|
@@ -301,15 +301,7 @@ export declare class SqlRetentionStore implements ManagedRetentionCapability {
|
|
|
301
301
|
* background-agent 活锚 / checkpoint 的 scope+status+deadline 复合索引)是独立一车,已进交接清单。
|
|
302
302
|
*/
|
|
303
303
|
private countPinnedExpiryCandidates;
|
|
304
|
-
/**
|
|
305
|
-
* 会话树的**四条活引用腿**的 SQL 谓词(`sm` = session_meta 的别名)。写成一处的理由与 {@link horizonArms}
|
|
306
|
-
* 相同,而且更重:它同时是「可删候选」的否定谓词与「被保护计数」的肯定谓词,两份手抄必然在某次改动后分家,
|
|
307
|
-
* 而分家的方向是**多删**(候选放宽、计数收紧,两边都不会有人红)。
|
|
308
|
-
*
|
|
309
|
-
* 腿的词表:活跑 claim / 挂起 park / 活着的后台子代(running|parked,三根会话锚)/ 在跑的 workflow
|
|
310
|
-
* (`originatingSessionId` 住在 run blob 里 ⇒ JSON 提取是真方言分叉)。fork 子代**结构上没有边**,
|
|
311
|
-
* 理由见 {@link SqlRetentionStore.deleteExpiredSessions} 的头注。
|
|
312
|
-
*/
|
|
304
|
+
/** 会话树的活引用谓词(`sm` = session_meta 的别名):唯一写法在 `plugins/retention-sql.ts` 的 `sessionLiveReferenceSql`(候选的否定与被保护计数的肯定同读;会话老化的候选面与锁内重判同读)。 */
|
|
313
305
|
private liveReferenceExists;
|
|
314
306
|
/**
|
|
315
307
|
* 本域过视界、**当下被活引用护住**的会话数 = receipt 的 `skipped`。
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { peerSessionBoxHandle } from "@sema-agent/core";
|
|
2
2
|
import { incarnationFromCell } from "../session-incarnation.js";
|
|
3
3
|
import { MANAGED_RETENTION } from "../plugins/retention-declaration.js";
|
|
4
|
-
import { retentionDomainWhere, retentionIdSet } from "../plugins/retention-sql.js";
|
|
4
|
+
import { retentionDomainWhere, retentionIdSet, sessionLiveReferenceSql } from "../plugins/retention-sql.js";
|
|
5
5
|
import { dropMailboxBoxOn } from "./mailbox-store-sql.js";
|
|
6
|
+
import { FILE_HISTORY_SCOPED_TABLES } from "./file-history-store-sql.js";
|
|
6
7
|
import { SEALED_EVENT, eraseSessionPolicyRowsOn } from "./session-policy-store-sql.js";
|
|
7
8
|
export const RETENTION_TOMBSTONE_TABLE = "retention_tombstone";
|
|
8
9
|
export const TIDB_RETENTION_TOMBSTONE_STATEMENTS = [
|
|
@@ -217,15 +218,7 @@ export class SqlRetentionStore {
|
|
|
217
218
|
return Number(rows[0]?.n ?? 0);
|
|
218
219
|
}
|
|
219
220
|
liveReferenceExists() {
|
|
220
|
-
|
|
221
|
-
? `EXISTS (SELECT 1 FROM workflow_run wr WHERE wr.status = 'running' AND JSON_UNQUOTE(JSON_EXTRACT(wr.run, '$.originatingSessionId')) = sm.session_id)`
|
|
222
|
-
: `EXISTS (SELECT 1 FROM workflow_run wr WHERE wr.status = 'running' AND wr.run::json->>'originatingSessionId' = sm.session_id)`;
|
|
223
|
-
return (`(sm.placement_kind IS NOT NULL` +
|
|
224
|
-
` OR EXISTS (SELECT 1 FROM task_active ta WHERE ta.session_id = sm.session_id)` +
|
|
225
|
-
` OR EXISTS (SELECT 1 FROM checkpoint c2 WHERE c2.session_id = sm.session_id AND c2.status = 'pending')` +
|
|
226
|
-
` OR EXISTS (SELECT 1 FROM background_agent ba WHERE ba.status IN ('running','parked')` +
|
|
227
|
-
` AND (ba.session_id = sm.session_id OR ba.parent_session_id = sm.session_id OR ba.root_session_id = sm.session_id))` +
|
|
228
|
-
` OR ${workflow})`);
|
|
221
|
+
return sessionLiveReferenceSql(this.db.dialect);
|
|
229
222
|
}
|
|
230
223
|
async countProtectedSessions(exec, input) {
|
|
231
224
|
const w = this.domainWhere("sm.owner", input.domain, 1);
|
|
@@ -360,15 +353,8 @@ export class SqlRetentionStore {
|
|
|
360
353
|
});
|
|
361
354
|
}
|
|
362
355
|
}
|
|
363
|
-
for (const
|
|
364
|
-
|
|
365
|
-
["file_history_version", "scope"],
|
|
366
|
-
["file_history_boundary", "scope"],
|
|
367
|
-
["file_history_boundary_file", "scope"],
|
|
368
|
-
["file_history_scope", "scope"],
|
|
369
|
-
["file_history_reaped_entry", "scope"],
|
|
370
|
-
]) {
|
|
371
|
-
const s = set(col, 1);
|
|
356
|
+
for (const table of FILE_HISTORY_SCOPED_TABLES) {
|
|
357
|
+
const s = set("scope", 1);
|
|
372
358
|
await conn.query(`DELETE FROM ${table} WHERE ${s.sql}`, s.params);
|
|
373
359
|
}
|
|
374
360
|
if (this.opts.sessionBoxScope !== undefined) {
|
|
@@ -59,10 +59,16 @@ export type SessionPolicyStoreLogger = {
|
|
|
59
59
|
warn(msg: string, fields?: Record<string, unknown>): void;
|
|
60
60
|
};
|
|
61
61
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
62
|
+
* 会话根行的部署格(组合座交入;店目录不认识 `session_meta` 的列,也不认识客户端写计数住的旁表):
|
|
63
|
+
* · `lockRoot` —— 同一连接上锁会话根行(全局锁序首句:根 `session_meta` → 别的表),答行在不在。语句是部署的「锁根行读住客」那一句
|
|
64
|
+
* (组合座交 `plugins/session-row-sql.ts` 的 `SQL_SESSION_ROOT_SEAT`,与落定段、行格写原语、执行放置同一句),店不自写第二份;
|
|
65
|
+
* · `countClientWrite` —— 一次客户端写的计数(会话规则是客户端可见的会话态,提交出口撤回一只刚铸的会话之前读这只计数)。店只在锁住根行、根行在、
|
|
66
|
+
* 所有拒判之后、规则落行之前,同一事务、同一连接调它一次。
|
|
64
67
|
*/
|
|
65
|
-
export
|
|
68
|
+
export interface SessionRootSeat {
|
|
69
|
+
lockRoot(conn: SqlTxConn, dialect: SqlDriver["dialect"], sessionId: string): Promise<boolean>;
|
|
70
|
+
countClientWrite(conn: SqlTxConn, dialect: SqlDriver["dialect"], sessionId: string): Promise<void>;
|
|
71
|
+
}
|
|
66
72
|
/**
|
|
67
73
|
* 按会话抹除规则行的**唯一语句源**(店的 `deleteBySession` 在自己的事务里调;会话删除执行体 `retention-store-sql.ts` 在会话树事务里对一批会话调 ——
|
|
68
74
|
* 同一组语句,`session_policy_rev_mark` 的高水位律只写这一处,core 契约 `session_policy.rev_survives_delete`)。调用方持事务。
|
|
@@ -73,9 +79,9 @@ export declare function eraseSessionPolicyRowsOn(conn: Pick<SqlTxConn, "query">,
|
|
|
73
79
|
/** Dual-dialect durable SessionPolicyStore. See the file header for the dialect-delta ledger. */
|
|
74
80
|
export declare class SqlSessionPolicyStore implements SessionPolicyStore {
|
|
75
81
|
private readonly db;
|
|
76
|
-
private readonly
|
|
82
|
+
private readonly root;
|
|
77
83
|
private readonly logger;
|
|
78
|
-
constructor(db: SqlDriver,
|
|
84
|
+
constructor(db: SqlDriver, root: SessionRootSeat, logger: SessionPolicyStoreLogger);
|
|
79
85
|
/** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
|
|
80
86
|
private q;
|
|
81
87
|
/** 判据属主 = `sql-errors.ts`([ref] P1-①;本站点旧形已是并集形,收编后语义不变)。 */
|
|
@@ -92,6 +98,19 @@ export declare class SqlSessionPolicyStore implements SessionPolicyStore {
|
|
|
92
98
|
listBySession(sessionId: string): Promise<SessionRulesRecord[]>;
|
|
93
99
|
/** Operator/owner write: CAS + tighten-only (unless operator) + rev bump, atomic in one txn; first-write race retried. */
|
|
94
100
|
putRules(sessionId: string, principal: string | undefined, rules: SessionPermissionRules, opts?: PutRulesOptions): Promise<StoredSessionRules>;
|
|
101
|
+
/**
|
|
102
|
+
* 一次规则写的**语句源**(read-check-write 全在调用方的事务里;调用方已锁根行 —— {@link putRules} 自己锁,落定段在段首锁并判过住客):锁读 prior 与记号 →
|
|
103
|
+
* CAS → 引擎写口判官 → 号 → 计客户端写(`how.count`)→ 写。`how.skip(prior)` 为真 ⇒ 不写、不计,答 `{ skipped: true }`(落定重放的等内容跳过)。
|
|
104
|
+
* 首写撞主键(并发首写赢了)照旧抛出,由事务主人的重来臂接住({@link retrying} / 落定段的 `alsoRetry` 读同一只 {@link isDupKey})。
|
|
105
|
+
*/
|
|
106
|
+
putRulesOn(conn: SqlTxConn, sessionId: string, principal: string | undefined, rules: SessionPermissionRules, opts: PutRulesOptions | undefined, how: {
|
|
107
|
+
readonly count: boolean;
|
|
108
|
+
readonly skip?: (prior: StoredSessionRules | null) => boolean;
|
|
109
|
+
}): Promise<StoredSessionRules | {
|
|
110
|
+
readonly skipped: true;
|
|
111
|
+
}>;
|
|
112
|
+
/** 判据属主 = `sql-errors.ts`:并发首写撞主键(落定段的重来臂读它)。 */
|
|
113
|
+
isDupKeyError(e: unknown): boolean;
|
|
95
114
|
/**
|
|
96
115
|
* The store's ONE retry arm: re-run the whole read-check-write transaction while the failure is an engine
|
|
97
116
|
* ARBITRATION artifact rather than an answer. Two such artifacts, and only two:
|
|
@@ -164,6 +183,10 @@ export declare class SqlSessionPolicyStore implements SessionPolicyStore {
|
|
|
164
183
|
* 残余(如实):记号里**已有**的世代若被列外改到 BIGINT 上界,冲突臂的 `记号.gen + 1` 在库里溢出 ⇒ 这次抹除响亮失败
|
|
165
184
|
* (驱动错误;那只记号本来就读不回,`putRules` 同样拒)—— 抹除不读记号,这一形不在本判词射程内。 */
|
|
166
185
|
deleteBySession(sessionId: string): Promise<void>;
|
|
186
|
+
/** 抹除的语句源(调用方的事务里;落定段的擦除腿与 {@link deleteBySession} 同一只):交回被封的键 —— 提交**之后**经 {@link discloseErased} 报。 */
|
|
187
|
+
eraseOn(conn: SqlTxConn, sessionId: string): Promise<readonly SealedEraseKey[]>;
|
|
188
|
+
/** 抹除提交之后的响亮面(封键 ⇒ 一条 warn;无封键 ⇒ 什么都不做)。 */
|
|
189
|
+
discloseErased(sessionId: string, sealed: readonly SealedEraseKey[]): void;
|
|
167
190
|
/**
|
|
168
191
|
* [ref] 封键的响亮面:一次抹除至多一条 warn。走到这里删除已经提交,一次日志故障不许把它报成失败(E21 会因此 500、
|
|
169
192
|
* overwrite-dst 会因此中止;codex 7.105.0 修复验证轮 [medium] 同形)⇒ 日志座抛不往外抛;**也不吞披露**:同一行落日志出口接缝的
|
|
@@ -183,10 +206,10 @@ export declare class SqlSessionPolicyStore implements SessionPolicyStore {
|
|
|
183
206
|
}
|
|
184
207
|
/** MySQL-protocol (TiDB) binding — historical class name + ctor shape preserved. */
|
|
185
208
|
export declare class TiDBSessionPolicyStore extends SqlSessionPolicyStore {
|
|
186
|
-
constructor(pool: MySqlPool,
|
|
209
|
+
constructor(pool: MySqlPool, root: SessionRootSeat, logger: SessionPolicyStoreLogger);
|
|
187
210
|
}
|
|
188
211
|
/** PostgreSQL binding — historical class name + ctor shape preserved. */
|
|
189
212
|
export declare class PgSessionPolicyStore extends SqlSessionPolicyStore {
|
|
190
|
-
constructor(pool: PgPool,
|
|
213
|
+
constructor(pool: PgPool, root: SessionRootSeat, logger: SessionPolicyStoreLogger);
|
|
191
214
|
}
|
|
192
215
|
//# sourceMappingURL=session-policy-store-sql.d.ts.map
|
|
@@ -87,11 +87,11 @@ export async function eraseSessionPolicyRowsOn(conn, dialect, sessionIds) {
|
|
|
87
87
|
}
|
|
88
88
|
export class SqlSessionPolicyStore {
|
|
89
89
|
db;
|
|
90
|
-
|
|
90
|
+
root;
|
|
91
91
|
logger;
|
|
92
|
-
constructor(db,
|
|
92
|
+
constructor(db, root, logger) {
|
|
93
93
|
this.db = db;
|
|
94
|
-
this.
|
|
94
|
+
this.root = root;
|
|
95
95
|
this.logger = logger;
|
|
96
96
|
}
|
|
97
97
|
q(mysql, pg) {
|
|
@@ -124,50 +124,67 @@ export class SqlSessionPolicyStore {
|
|
|
124
124
|
}));
|
|
125
125
|
}
|
|
126
126
|
async putRules(sessionId, principal, rules, opts) {
|
|
127
|
-
const key = policyKey(sessionId, principal);
|
|
128
127
|
return this.retrying(() => this.tx(async (conn) => {
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
throw new SessionPolicyError("conflict", `session rules rev mismatch (expected ${opts.expectedRev}, have ${priorRev})`);
|
|
135
|
-
}
|
|
136
|
-
const { rows: markRows } = await conn.query(this.q("SELECT rev, gen FROM session_policy_rev_mark WHERE policy_key = ? FOR UPDATE", "SELECT rev, gen FROM session_policy_rev_mark WHERE policy_key = $1 FOR UPDATE"), [key]);
|
|
137
|
-
const markRev = markRows[0] ? Number(markRows[0].rev) : 0;
|
|
138
|
-
const markGen = markRows[0] ? Number(markRows[0].gen) : 0;
|
|
139
|
-
if (markRows[0] !== undefined && (!isStoredCounter(markGen, 0) || !isStoredCounter(markRev, 0))) {
|
|
140
|
-
throw new SessionPolicyError("corrupt", `the session rules rev mark for session ${JSON.stringify(sessionId)} is unreadable (rev ${String(markRows[0].rev)}, gen ${String(markRows[0].gen)}) — refusing rather than stamp a rev/lineage nothing proves`);
|
|
141
|
-
}
|
|
142
|
-
const clean = judgeSessionRulesWrite(prior ?? null, rules, opts);
|
|
143
|
-
if (this.db.dialect === "pg" && pgHasUnstorable(clean)) {
|
|
144
|
-
throw new SessionPolicyError("loosen_forbidden", "rules contain unstorable bytes (NUL / lone surrogate) — refused; strip them at the source (authorization rules are never rewritten by the store)");
|
|
145
|
-
}
|
|
146
|
-
const nextRev = Math.max(priorRev, markRev) + 1;
|
|
147
|
-
const nextGen = prior?.gen ?? markGen;
|
|
148
|
-
if (!isStoredCounter(nextRev, 1) || !isStoredCounter(nextGen, 0)) {
|
|
149
|
-
throw new SessionPolicyError("corrupt", `session rules for session ${JSON.stringify(sessionId)}: the next stamp (rev ${nextRev}, gen ${nextGen}) would leave the safe-integer range this store reads back — refusing before writing a row nothing could read`);
|
|
150
|
-
}
|
|
151
|
-
if (root.rows.length > 0)
|
|
152
|
-
await this.countClientWrite(conn, this.db.dialect, sessionId);
|
|
153
|
-
const json = JSON.stringify(clean);
|
|
154
|
-
const now = new Date();
|
|
155
|
-
if (prior) {
|
|
156
|
-
const upd = await conn.query(this.q(`UPDATE session_policy SET principal = ?, ${RULES} = ?, rev = ?, gen = ?, updated_at = ? WHERE policy_key = ? AND rev = ?`, `UPDATE session_policy SET principal = $1, ${RULES} = $2::jsonb, rev = $3, gen = $4, updated_at = $5 WHERE policy_key = $6 AND rev = $7`), [principal ?? null, json, nextRev, nextGen, now, key, priorRev]);
|
|
157
|
-
if (upd.affected !== 1)
|
|
158
|
-
throw new SessionPolicyError("conflict", `session rules rev mismatch (expected ${opts?.expectedRev ?? priorRev}, have ${priorRev})`);
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
await conn.query(this.q(`INSERT INTO session_policy (policy_key, session_id, principal, ${RULES}, rev, gen, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)`, `INSERT INTO session_policy (policy_key, session_id, principal, ${RULES}, rev, gen, created_at, updated_at) VALUES ($1,$2,$3,$4::jsonb,$5,$6,$7,$8)`), [key, sessionId, principal ?? null, json, nextRev, nextGen, now, now]);
|
|
162
|
-
}
|
|
163
|
-
return structuredClone({ ...clean, rev: nextRev, gen: nextGen });
|
|
128
|
+
const present = await this.root.lockRoot(conn, this.db.dialect, sessionId);
|
|
129
|
+
const out = await this.putRulesOn(conn, sessionId, principal, rules, opts, { count: present });
|
|
130
|
+
if ("skipped" in out)
|
|
131
|
+
throw new Error("SqlSessionPolicyStore.putRules: no skip predicate was given, yet the write was skipped");
|
|
132
|
+
return out;
|
|
164
133
|
}));
|
|
165
134
|
}
|
|
135
|
+
async putRulesOn(conn, sessionId, principal, rules, opts, how) {
|
|
136
|
+
const key = policyKey(sessionId, principal);
|
|
137
|
+
const { rows } = await conn.query(this.q(`SELECT ${jsonColumnText("mysql", RULES)}, rev, gen FROM session_policy WHERE policy_key = ? FOR UPDATE`, `SELECT ${jsonColumnText("pg", RULES)}, rev, gen FROM session_policy WHERE policy_key = $1 FOR UPDATE`), [key]);
|
|
138
|
+
const prior = rows[0] ? rowToStored(rows[0], `for session ${JSON.stringify(sessionId)} (pre-write snapshot)`) : undefined;
|
|
139
|
+
if (how.skip?.(prior ?? null) === true)
|
|
140
|
+
return { skipped: true };
|
|
141
|
+
const priorRev = prior?.rev ?? 0;
|
|
142
|
+
if (opts?.expectedRev !== undefined && priorRev !== opts.expectedRev) {
|
|
143
|
+
throw new SessionPolicyError("conflict", `session rules rev mismatch (expected ${opts.expectedRev}, have ${priorRev})`);
|
|
144
|
+
}
|
|
145
|
+
const { rows: markRows } = await conn.query(this.q("SELECT rev, gen FROM session_policy_rev_mark WHERE policy_key = ? FOR UPDATE", "SELECT rev, gen FROM session_policy_rev_mark WHERE policy_key = $1 FOR UPDATE"), [key]);
|
|
146
|
+
const markRev = markRows[0] ? Number(markRows[0].rev) : 0;
|
|
147
|
+
const markGen = markRows[0] ? Number(markRows[0].gen) : 0;
|
|
148
|
+
if (markRows[0] !== undefined && (!isStoredCounter(markGen, 0) || !isStoredCounter(markRev, 0))) {
|
|
149
|
+
throw new SessionPolicyError("corrupt", `the session rules rev mark for session ${JSON.stringify(sessionId)} is unreadable (rev ${String(markRows[0].rev)}, gen ${String(markRows[0].gen)}) — refusing rather than stamp a rev/lineage nothing proves`);
|
|
150
|
+
}
|
|
151
|
+
const clean = judgeSessionRulesWrite(prior ?? null, rules, opts);
|
|
152
|
+
if (this.db.dialect === "pg" && pgHasUnstorable(clean)) {
|
|
153
|
+
throw new SessionPolicyError("loosen_forbidden", "rules contain unstorable bytes (NUL / lone surrogate) — refused; strip them at the source (authorization rules are never rewritten by the store)");
|
|
154
|
+
}
|
|
155
|
+
const nextRev = Math.max(priorRev, markRev) + 1;
|
|
156
|
+
const nextGen = prior?.gen ?? markGen;
|
|
157
|
+
if (!isStoredCounter(nextRev, 1) || !isStoredCounter(nextGen, 0)) {
|
|
158
|
+
throw new SessionPolicyError("corrupt", `session rules for session ${JSON.stringify(sessionId)}: the next stamp (rev ${nextRev}, gen ${nextGen}) would leave the safe-integer range this store reads back — refusing before writing a row nothing could read`);
|
|
159
|
+
}
|
|
160
|
+
if (how.count)
|
|
161
|
+
await this.root.countClientWrite(conn, this.db.dialect, sessionId);
|
|
162
|
+
const json = JSON.stringify(clean);
|
|
163
|
+
const now = new Date();
|
|
164
|
+
if (prior) {
|
|
165
|
+
const upd = await conn.query(this.q(`UPDATE session_policy SET principal = ?, ${RULES} = ?, rev = ?, gen = ?, updated_at = ? WHERE policy_key = ? AND rev = ?`, `UPDATE session_policy SET principal = $1, ${RULES} = $2::jsonb, rev = $3, gen = $4, updated_at = $5 WHERE policy_key = $6 AND rev = $7`), [principal ?? null, json, nextRev, nextGen, now, key, priorRev]);
|
|
166
|
+
if (upd.affected !== 1)
|
|
167
|
+
throw new SessionPolicyError("conflict", `session rules rev mismatch (expected ${opts?.expectedRev ?? priorRev}, have ${priorRev})`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
await conn.query(this.q(`INSERT INTO session_policy (policy_key, session_id, principal, ${RULES}, rev, gen, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?)`, `INSERT INTO session_policy (policy_key, session_id, principal, ${RULES}, rev, gen, created_at, updated_at) VALUES ($1,$2,$3,$4::jsonb,$5,$6,$7,$8)`), [key, sessionId, principal ?? null, json, nextRev, nextGen, now, now]);
|
|
171
|
+
}
|
|
172
|
+
return structuredClone({ ...clean, rev: nextRev, gen: nextGen });
|
|
173
|
+
}
|
|
174
|
+
isDupKeyError(e) {
|
|
175
|
+
return this.isDupKey(e);
|
|
176
|
+
}
|
|
166
177
|
retrying(attempt) {
|
|
167
178
|
return retryOnDeadlock(this.db.dialect, attempt, (e) => this.isDupKey(e));
|
|
168
179
|
}
|
|
169
180
|
async deleteBySession(sessionId) {
|
|
170
|
-
const sealed = await this.retrying(() => this.tx((conn) =>
|
|
181
|
+
const sealed = await this.retrying(() => this.tx((conn) => this.eraseOn(conn, sessionId)));
|
|
182
|
+
this.discloseErased(sessionId, sealed);
|
|
183
|
+
}
|
|
184
|
+
eraseOn(conn, sessionId) {
|
|
185
|
+
return eraseSessionPolicyRowsOn(conn, this.db.dialect, [sessionId]);
|
|
186
|
+
}
|
|
187
|
+
discloseErased(sessionId, sealed) {
|
|
171
188
|
if (sealed.length > 0)
|
|
172
189
|
this.discloseSealed(sessionId, sealed);
|
|
173
190
|
}
|
|
@@ -206,13 +223,13 @@ export class SqlSessionPolicyStore {
|
|
|
206
223
|
}
|
|
207
224
|
}
|
|
208
225
|
export class TiDBSessionPolicyStore extends SqlSessionPolicyStore {
|
|
209
|
-
constructor(pool,
|
|
210
|
-
super(mysqlDriver(pool),
|
|
226
|
+
constructor(pool, root, logger) {
|
|
227
|
+
super(mysqlDriver(pool), root, logger);
|
|
211
228
|
}
|
|
212
229
|
}
|
|
213
230
|
export class PgSessionPolicyStore extends SqlSessionPolicyStore {
|
|
214
|
-
constructor(pool,
|
|
215
|
-
super(pgDriver(pool),
|
|
231
|
+
constructor(pool, root, logger) {
|
|
232
|
+
super(pgDriver(pool), root, logger);
|
|
216
233
|
}
|
|
217
234
|
}
|
|
218
235
|
//# sourceMappingURL=session-policy-store-sql.js.map
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
* 不对别的表的行加锁,也不在 EvalPlanQual 里复判它们。所以是**两句**:店先 `FOR UPDATE` 锁根行(删除 / 重登记 / 改属主都要先拿这把锁),
|
|
14
14
|
* 再在**同一连接**上交出语句面,部署用新语句锁定读(PG 新快照、TiDB 当前读)。钩里的写随店的事务提交或回滚(店拒、或任何一步抛,一起撤)。
|
|
15
15
|
*
|
|
16
|
+
* ## 建行钩(服务扩展,包里没有)
|
|
17
|
+
* 带种类的登记(`registerWithReceipt` 的第三参;会话种类的律在 `session-kind.ts`):店在一只事务里 INSERT、锁定读回化身,读回的 = 本次铸的(这一笔真建了行)⇒
|
|
18
|
+
* {@link SessionWriteHooks.birth} 在同一事务里记下种类;别的(已在的行 / 并发登记里输的那一只)⇒ 零写。包随店搬家时这一组同是向引擎的请托。
|
|
19
|
+
*
|
|
16
20
|
* ## 键控 fork(服务扩展,包里没有)
|
|
17
21
|
* 调用方给目标 id 与键的 fork(`forkTo`)是本服务的扩展:键是部署格,在建目标行的同一事务里由 {@link SessionWriteHooks.keyedFork} 记下;撞上已在的目标时
|
|
18
22
|
* 读它的属主与键。包随店搬家时这一组是向引擎的请托(带目标 id 与键的 fork,或钩表多一组)。
|
|
@@ -61,5 +65,12 @@ export interface SessionWriteHooks {
|
|
|
61
65
|
}): Promise<void>;
|
|
62
66
|
targetOf(sessionId: string): Promise<ForkTargetReading | undefined>;
|
|
63
67
|
};
|
|
68
|
+
/** 建行钩(服务扩展,与键控 fork 同族):带种类的登记里,本事务的 INSERT 真建了这一行(锁定读回的化身 = 本次铸的)⇒ 在同一事务里记下它的种类(部署格的值,座原样转交、不解读;律在部署那一侧)。 */
|
|
69
|
+
readonly birth: {
|
|
70
|
+
record(txn: SessionTxStatements, born: {
|
|
71
|
+
readonly rootSessionId: string;
|
|
72
|
+
readonly kind: string;
|
|
73
|
+
}): Promise<void>;
|
|
74
|
+
};
|
|
64
75
|
}
|
|
65
76
|
//# sourceMappingURL=session-write-hooks.d.ts.map
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
import { type AcquiredSession, type PlacedSessionRow, type SessionHead, type SessionPlacementRecord, type SessionStore, type SessionTreeEntry } from "@sema-agent/core";
|
|
14
14
|
import type { Pool } from "mysql2/promise";
|
|
15
15
|
import type { RetentionDeclaration } from "@sema-agent/core";
|
|
16
|
-
import { type RegisterReceipt, type WithdrawJudgeVerdict, type WithdrawOutcome } from "../session-incarnation.js";
|
|
16
|
+
import { type RegisterReceipt, type SessionFace, type WithdrawJudgeVerdict, type WithdrawOutcome } from "../session-incarnation.js";
|
|
17
17
|
import type { SessionTxStatements, SessionWriteHooks } from "./session-write-hooks.js";
|
|
18
18
|
import { type PlacementAcquireOpts } from "../plugins/session-placement.js";
|
|
19
|
-
import { type StagingHandle } from "../session-sync-kernel.js";
|
|
19
|
+
import { type EntriesStreamOptions, type StagedCommitOptions, type StagingHandle, type SyncRelation } from "../session-sync-kernel.js";
|
|
20
20
|
import { type ForkPlacement, type ForkTarget, type ForkToOutcome } from "../plugins/session-fork.js";
|
|
21
21
|
/**
|
|
22
22
|
* **条件撤回的店那一半**(两方言一形;TiDB 孪生与 PG 孪生 `pg-session-storage.ts` 同调;撤回的规则在 `plugins/session-birth.ts` 头注)。
|
|
@@ -75,7 +75,7 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
75
75
|
* 出生回执面(`plugins/session-birth.ts`):与 {@link register} 同一笔 INSERT;候选化身 = 这一次 INSERT 入参里铸的那一只(不复读)。
|
|
76
76
|
* 已在的行上 INSERT 是 no-op 臂 ⇒ 行上的化身不是候选 ⇒ 撤回在锁内比对时判「留」—— 出生事实只在那里判,这里不分新旧行。
|
|
77
77
|
*/
|
|
78
|
-
registerWithReceipt(sessionId: string, owner: string | null): Promise<RegisterReceipt>;
|
|
78
|
+
registerWithReceipt(sessionId: string, owner: string | null, kind?: string): Promise<RegisterReceipt>;
|
|
79
79
|
/** 条件删除(`plugins/session-birth.ts` 的撤回;本连接开事务 → 店与部署两半同一语句面 → 撤回才提交,否则回滚)。 */
|
|
80
80
|
deleteSessionIf(sessionId: string, cond: SessionDeleteCondition): Promise<WithdrawOutcome>;
|
|
81
81
|
/**
|
|
@@ -88,6 +88,8 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
88
88
|
* **永不被重写**(first-write 不可变,义务 5 的写侧半场)。
|
|
89
89
|
* [ref]:化身与属主同一条 first-write 律 —— 新行铸一只(`mintSessionIncarnation`),已存在的行 no-op 臂一个字节不动。 */
|
|
90
90
|
private insertMeta;
|
|
91
|
+
/** {@link insertMeta} 那一句,发在给定的连接上(带种类的登记在自己的事务连接上发,与锁定读、建行钩同一事务)。 */
|
|
92
|
+
private insertMetaOn;
|
|
91
93
|
/**
|
|
92
94
|
* [ref] 义务 6 的廉价探针 —— 一行 PK SELECT:`undefined` = 普通会话或无此行。
|
|
93
95
|
* (release 的冷缓存腿、包装店的暖命中准入判、诊断面共用这一只。)
|
|
@@ -194,10 +196,7 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
194
196
|
* (按文本投影 + `decodeSessionEventPayload` 恰好解一次码,坏体当场拒). The check is eager (the method is async) because a generator body is lazy — it can't decide
|
|
195
197
|
* `null` vs. iterable on its own first pull.
|
|
196
198
|
*/
|
|
197
|
-
exportEntriesStream(sessionId: string, opts
|
|
198
|
-
afterSeq?: number;
|
|
199
|
-
batchSize?: number;
|
|
200
|
-
}): Promise<AsyncIterable<SessionTreeEntry> | null>;
|
|
199
|
+
exportEntriesStream(sessionId: string, opts: EntriesStreamOptions): Promise<AsyncIterable<SessionTreeEntry> | null>;
|
|
201
200
|
/**
|
|
202
201
|
* 2c session-sync — IMPORT a verbatim entry log (from another backend's {@link exportEntries}) into a
|
|
203
202
|
* (typically NEW) `sessionId`. This is the WRITE half of {@link fork}, surfaced as `SessionRepo.importEntries`,
|
|
@@ -269,5 +268,57 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
269
268
|
get size(): number;
|
|
270
269
|
dispose(): void;
|
|
271
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* 2c session-sync P1d-β (PUSH streaming, §15 + §4) — a TiDB {@link StagingHandle}: stream entry batches into a SHADOW
|
|
273
|
+
* `session_event` partition (the staging id, NO meta row → invisible to wake), then atomically SWAP them into the real
|
|
274
|
+
* session id. Server memory is bounded by the in-flight batch (one txn per batch), not the whole log. The swap is a
|
|
275
|
+
* row-key RENAME (`UPDATE session_event SET session_id`) — metadata-only, NO payload re-copy — so the commit cost is
|
|
276
|
+
* the rename + a DELETE of the (purged) dst rows, in ONE txn; the session_meta row is locked (or, for a fresh push, claimed) first and
|
|
277
|
+
* settled last, and COMMIT is the sole commit point.
|
|
278
|
+
*/
|
|
279
|
+
/** 暂存句柄(会话同步的推送腿逐批写、提交、撤销;由本店的 `stageImport` 交出)。导出只为组合座给它封口(店边界)。 */
|
|
280
|
+
export declare class TiDBStagingHandle implements StagingHandle {
|
|
281
|
+
private readonly pool;
|
|
282
|
+
private readonly hooks;
|
|
283
|
+
readonly realSessionId: string;
|
|
284
|
+
readonly stagingId: string;
|
|
285
|
+
/** Running DENSE seq counter for the staging rows. Advanced ONLY for a logically-NEW entry id (tracked in `seen`), so
|
|
286
|
+
* a re-streamed entry (Phase-B resume) is skipped and the staged seqs stay dense 0..N-1 (NO holes that would collide
|
|
287
|
+
* with a future F2 leaf_seq append on the committed session). */
|
|
288
|
+
private nextSeq;
|
|
289
|
+
/** Entry ids already staged by THIS handle — a resume re-streams from the start, so dedup keeps seqs dense + idempotent. */
|
|
290
|
+
private readonly seen;
|
|
291
|
+
constructor(pool: Pool, hooks: SessionWriteHooks, realSessionId: string, stagingId: string);
|
|
292
|
+
/** Append a batch to the staging id, re-seq'd DENSE from the running counter (skipping ids already staged), IDEMPOTENTLY
|
|
293
|
+
* (ON DUPLICATE KEY UPDATE on the `(session_id, entry_id)` uk is the durable backstop too). One txn per batch
|
|
294
|
+
* (bounded). NO meta row is written (the staging id stays invisible). ts is the entry's own ISO timestamp (verbatim). */
|
|
295
|
+
appendBatch(entries: SessionTreeEntry[]): Promise<void>;
|
|
296
|
+
/**
|
|
297
|
+
* The ATOMIC swap (ONE txn), §15 commit:
|
|
298
|
+
* 0. OWNER CAS FIRST ([ref] — one gate predicate, two phases): the session's owner cell must still be the one the import's gate
|
|
299
|
+
* judged (`opts.expectedOccupant`: owner ∧ incarnation). Like every other writer of a session (append, replace, delete) the staged commit takes the
|
|
300
|
+
* session_meta row FIRST, then the logs — one lock order. A present cell: one conditioned UPDATE (current read; takes the row lock
|
|
301
|
+
* until COMMIT); it bumps `leaf_seq` only as the CAS's always-changing column (a same-value UPDATE can read 0 affected rows on the
|
|
302
|
+
* MySQL protocol depending on driver flags), and step 4 overwrites that column with the real value in the same txn. An absent cell
|
|
303
|
+
* (a fresh push) cannot be locked, so it is CLAIMED: insert this commit's row now (a no-op on an existing key), then a locking read
|
|
304
|
+
* must show the incarnation this commit minted — anything else is a row somebody else created. Either miss ⇒ ROLLBACK → throw
|
|
305
|
+
* StagedCommitOccupantChangedError (route → 409), before anything about the row is read or reported (no placement, no relation,
|
|
306
|
+
* no entry ids).
|
|
307
|
+
* 1. IN-COMMIT RE-CLASSIFY (closes the Phase-A plan→commit TOCTOU): read the dst's CURRENT entry ids + the staged
|
|
308
|
+
* ids under `FOR UPDATE` (row-locks serialize a concurrent commit/run) → classifySyncRelationshipByIds. A flip
|
|
309
|
+
* to fork/stale WITHOUT `resolution:"overwrite-dst"` → ROLLBACK → throw SyncConflictError (route → 409).
|
|
310
|
+
* 2. DELETE the dst's existing session_event rows (the replaceEntries purge).
|
|
311
|
+
* 3. UPDATE session_event SET session_id = real WHERE session_id = staging (the row-key RENAME — metadata only).
|
|
312
|
+
* 4. UPDATE session_meta(owner, leaf_id=replayedLeaf, leaf_seq=N) on the row step 0 locked or claimed; COMMIT is the sole commit point.
|
|
313
|
+
* A crash before COMMIT: the DELETE+rename roll back (dst untouched) and the staging rows keep no meta = invisible
|
|
314
|
+
* orphans (reaped by sweepStagingSessions). `owner` is the re-stamped importing principal (§9).
|
|
315
|
+
*/
|
|
316
|
+
commit(owner: string | null, opts: StagedCommitOptions): Promise<{
|
|
317
|
+
relation: SyncRelation["relation"];
|
|
318
|
+
face: SessionFace;
|
|
319
|
+
}>;
|
|
320
|
+
/** Drop the staging rows (Phase B aborted before commit). Idempotent (a missing staging id deletes 0). */
|
|
321
|
+
abort(): Promise<void>;
|
|
322
|
+
}
|
|
272
323
|
export {};
|
|
273
324
|
//# sourceMappingURL=tidb-session-store.d.ts.map
|