@sema-agent/server 7.150.0 → 7.151.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 +185 -0
- package/USAGE.md +53 -25
- package/deploy/sema-up/README.md +7 -1
- 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 +1 -0
- package/deploy/sema-up/kube-up.sh +1 -1
- package/deploy/sema-up/lib/flagshape.sh +1 -1
- package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
- package/deploy/sema-up/lib/helm-values-kube.py +2 -0
- package/dist/adoption/import.js +3 -3
- package/dist/approval-ask-machine.d.ts +1 -1
- package/dist/approval-card.d.ts +2 -2
- package/dist/approval-gate-currency.d.ts +1 -1
- 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 +2 -3
- package/dist/bind-host.js +2 -4
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/engine-lease.d.ts +5 -0
- package/dist/boot/engine-lease.js +1 -0
- package/dist/boot/execution-env.d.ts +8 -14
- package/dist/boot/execution-env.js +54 -17
- 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/memory-consolidation.d.ts +3 -2
- package/dist/boot/memory-consolidation.js +6 -6
- package/dist/boot/reapers.d.ts +5 -0
- package/dist/boot/reapers.js +12 -1
- package/dist/boot/resolve-spec.d.ts +3 -3
- package/dist/boot/resolve-spec.js +31 -22
- package/dist/boot/runner-deps.d.ts +9 -2
- package/dist/boot/runner-deps.js +3 -3
- 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/stage-01-config.js +2 -0
- package/dist/boot/stage-05-execution-env.d.ts +5 -3
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +7 -4
- package/dist/boot/stage-06-runners.js +15 -6
- package/dist/boot/stage-07-capability-layer.d.ts +7 -4
- package/dist/boot/stage-07-capability-layer.js +2 -1
- package/dist/boot/stage-08-reapers.d.ts +7 -4
- package/dist/boot/stage-08-reapers.js +4 -2
- package/dist/boot/stage-09-leader.d.ts +11 -5
- package/dist/boot/stage-09-leader.js +12 -3
- package/dist/boot/stage-10-http-server.d.ts +11 -5
- package/dist/boot/stage-10-http-server.js +3 -6
- package/dist/boot/web-admin.js +3 -1
- 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/capability-facts.d.ts +22 -13
- package/dist/capability-facts.js +28 -18
- 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 +14 -11
- package/dist/config-invariants.d.ts +2 -1
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +10 -4
- package/dist/config.d.ts +51 -2
- package/dist/config.js +35 -24
- 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.js +3 -2
- package/dist/device-ws-protocol.d.ts +63 -10
- package/dist/device-ws-protocol.js +56 -25
- 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/execution-env-refusal.d.ts +23 -0
- package/dist/execution-env-refusal.js +5 -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/hooks/hook-runner.js +2 -2
- package/dist/host-lsp-manager.d.ts +2 -2
- package/dist/http/admission.js +17 -2
- package/dist/http/approval-sweeps.js +5 -5
- package/dist/http/checkpoint-ctx.d.ts +2 -0
- package/dist/http/checkpoint-ctx.js +1 -0
- package/dist/http/dispatch.d.ts +2 -1
- package/dist/http/dispatch.js +34 -27
- package/dist/http/durable-run-leg.js +16 -16
- package/dist/http/health-self-report.d.ts +9 -1
- package/dist/http/health-self-report.js +2 -0
- package/dist/http/owner-access.d.ts +31 -11
- package/dist/http/owner-access.js +37 -6
- package/dist/http/resume-ctx-read.js +25 -3
- package/dist/http/resume-legs.d.ts +2 -1
- package/dist/http/resume-legs.js +259 -79
- package/dist/http/route-ctx.d.ts +18 -8
- package/dist/http/route-table.d.ts +1 -1
- package/dist/http/routes/admin-memory-optout.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.js +4 -3
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/capabilities.js +8 -5
- package/dist/http/routes/fleet.js +10 -8
- package/dist/http/routes/projects.d.ts +3 -2
- package/dist/http/routes/projects.js +4 -5
- package/dist/http/routes/runs.js +102 -36
- package/dist/http/routes/session-sync.d.ts +4 -3
- package/dist/http/routes/session-sync.js +172 -77
- package/dist/http/routes/sessions-list.js +13 -7
- package/dist/http/routes/sessions.js +10 -6
- package/dist/http/routes/tasks.js +30 -16
- package/dist/http/routes/trace-usage.js +2 -2
- package/dist/http/server.d.ts +21 -27
- package/dist/http/server.js +2 -2
- package/dist/http/submit-ctx.js +5 -4
- package/dist/http/wire-types.d.ts +14 -4
- package/dist/identity-source.d.ts +20 -3
- package/dist/identity-source.js +14 -0
- package/dist/index.d.ts +4 -0
- package/dist/lane-home-probe.d.ts +3 -7
- package/dist/lane-home-probe.js +0 -1
- package/dist/leader/leader.d.ts +2 -1
- package/dist/leg-facts.d.ts +13 -5
- package/dist/leg-facts.js +2 -1
- package/dist/memory-scope.d.ts +5 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-sync-client.d.ts +30 -2
- package/dist/memory-sync-client.js +16 -9
- package/dist/observability/err-text.d.ts +7 -0
- package/dist/observability/err-text.js +5 -0
- package/dist/observability/fail-open.d.ts +7 -3
- package/dist/observability/fail-open.js +7 -3
- package/dist/observability/metrics.js +1 -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/owner-faces.d.ts +1 -1
- package/dist/parked-decide.d.ts +104 -53
- 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 +41 -5
- package/dist/permission-mode-admission.js +29 -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 +10 -2
- package/dist/plugins/approval-ask-store-file.js +8 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -1
- package/dist/plugins/approval-ask-store-memory.js +28 -9
- package/dist/plugins/approval-ask-store-sql.d.ts +43 -2
- package/dist/plugins/approval-ask-store-sql.js +34 -5
- package/dist/plugins/approval-exemption-store.js +3 -0
- package/dist/plugins/approval-nonce-store.js +2 -0
- 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/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-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 +57 -63
- package/dist/plugins/one-time-migrations.js +162 -90
- 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 +24 -1
- 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 +17 -0
- package/dist/plugins/remote-env-host.js +30 -38
- package/dist/plugins/remote-env-k8s.d.ts +41 -39
- package/dist/plugins/remote-env-k8s.js +53 -30
- 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/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/scenario-prefix-switch-m42.d.ts +1 -1
- package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
- package/dist/plugins/schema-consistency.d.ts +4 -2
- package/dist/plugins/schema-consistency.js +19 -2
- package/dist/plugins/send-file-ledger.js +3 -0
- 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-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/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/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 +40 -13
- package/dist/plugins/store-backend.js +169 -27
- 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.js +9 -0
- 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 +2 -1
- 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-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/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/run-acceptance.d.ts +3 -2
- package/dist/run-acceptance.js +4 -6
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +37 -8
- package/dist/runs.js +53 -12
- package/dist/runtime-governance.d.ts +5 -4
- package/dist/security.d.ts +30 -32
- package/dist/security.js +41 -7
- 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 +4 -98
- package/dist/session-sync.js +1 -71
- 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/file-history-store-sql.d.ts +52 -2
- package/dist/stores-sql/file-history-store-sql.js +108 -70
- 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 +2 -10
- 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 +6 -5
- package/dist/terminal.d.ts +33 -2
- package/dist/terminal.js +139 -9
- package/dist/tool-approval.d.ts +140 -6
- package/dist/tool-approval.js +165 -72
- package/dist/trace/self-minted-wire.d.ts +290 -27
- package/dist/trace/self-minted-wire.js +101 -13
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +78 -27
- package/package.json +2 -2
- package/wire-changes/server@7.151.0.json +762 -0
- package/dist/http/session-inherit-env.d.ts +0 -36
- package/dist/http/session-inherit-env.js +0 -6
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { captureFileBackupViaEnv, applyFileRestoreViaEnv, fileHistoryModeProvenDifferent, worldStillMatchesMint, annulProofFailure, boundaryPublishVerdict, fileHistoryDescribeTrackKey, fileHistoryTrackKeyOf, fileHistoryResolveTrackKey, fileHistoryExportDigest, validateFileHistoryExport, resolveFileHistoryRetention, fileHistoryBoundariesToKeep, } from "@sema-agent/core";
|
|
3
3
|
import { BlobTooLargeError, SqlBlobIndex } from "./blob-index-sql.js";
|
|
4
4
|
import { mysqlDriver, pgDriver } from "../plugins/sql-driver.js";
|
|
5
|
-
import { isMissingColumnError, retryOnDeadlock } from "../plugins/sql-errors.js";
|
|
5
|
+
import { isMissingColumnError, retryOnDeadlock, SqlArbitrationLostError } from "../plugins/sql-errors.js";
|
|
6
6
|
import { probedMissingColumnRefusal } from "../plugins/schema-drift-sentence.js";
|
|
7
7
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
8
8
|
import { foldCaughtFailure } from "../file-history-disclosure.js";
|
|
@@ -12,8 +12,9 @@ const sha256hex = (s) => createHash("sha256").update(s).digest("hex");
|
|
|
12
12
|
const truthy = (v) => v === true || v === 1 || v === "1";
|
|
13
13
|
class StagedRefGoneError extends Error {
|
|
14
14
|
}
|
|
15
|
-
class ScopeSentinelVanishedError extends
|
|
15
|
+
class ScopeSentinelVanishedError extends SqlArbitrationLostError {
|
|
16
16
|
}
|
|
17
|
+
const FILE_HISTORY_SCOPED_TABLES = ["file_history_boundary_file", "file_history_boundary", "file_history_reaped_entry", "file_history_version", "file_history_tracked", "file_history_scope"];
|
|
17
18
|
function reapedEntryRefusal(entryId) {
|
|
18
19
|
return {
|
|
19
20
|
ok: false,
|
|
@@ -67,14 +68,17 @@ export class SqlFileHistoryStore {
|
|
|
67
68
|
await conn.begin();
|
|
68
69
|
}
|
|
69
70
|
restart = true;
|
|
70
|
-
|
|
71
|
-
await conn.query(this.q("INSERT INTO file_history_scope (scope, created_at_ms) VALUES (?,?) ON DUPLICATE KEY UPDATE scope = scope", "INSERT INTO file_history_scope (scope, created_at_ms) VALUES ($1,$2) ON CONFLICT (scope) DO NOTHING"), [scope, Date.now()]);
|
|
72
|
-
const r = await conn.query(this.q("SELECT scope FROM file_history_scope WHERE scope = ? FOR UPDATE", "SELECT scope FROM file_history_scope WHERE scope = $1 FOR UPDATE"), [scope]);
|
|
73
|
-
if (!r.rows[0])
|
|
74
|
-
throw new ScopeSentinelVanishedError(`could not acquire the scope write lock for "${scope}" (sentinel row kept vanishing)`);
|
|
75
|
-
}
|
|
71
|
+
await this.lockScopeOn(conn, ordered);
|
|
76
72
|
}, (err) => err instanceof ScopeSentinelVanishedError);
|
|
77
73
|
}
|
|
74
|
+
async lockScopeOn(conn, scopes) {
|
|
75
|
+
for (const scope of [...new Set(scopes)].sort()) {
|
|
76
|
+
await conn.query(this.q("INSERT INTO file_history_scope (scope, created_at_ms) VALUES (?,?) ON DUPLICATE KEY UPDATE scope = scope", "INSERT INTO file_history_scope (scope, created_at_ms) VALUES ($1,$2) ON CONFLICT (scope) DO NOTHING"), [scope, Date.now()]);
|
|
77
|
+
const r = await conn.query(this.q("SELECT scope FROM file_history_scope WHERE scope = ? FOR UPDATE", "SELECT scope FROM file_history_scope WHERE scope = $1 FOR UPDATE"), [scope]);
|
|
78
|
+
if (!r.rows[0])
|
|
79
|
+
throw new ScopeSentinelVanishedError(`could not acquire the scope write lock for "${scope}" (sentinel row kept vanishing)`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
78
82
|
async markObserved(scope, keyHash) {
|
|
79
83
|
const r = await this.db.query(this.q("UPDATE file_history_tracked SET observed_later = 1 WHERE scope = ? AND key_hash = ? AND observed_later = 0", "UPDATE file_history_tracked SET observed_later = TRUE WHERE scope = $1 AND key_hash = $2 AND observed_later = FALSE"), [scope, keyHash]);
|
|
80
84
|
return r.affected;
|
|
@@ -134,7 +138,7 @@ export class SqlFileHistoryStore {
|
|
|
134
138
|
return { ok: false, error: { code: "track_failed", message: `first-touch record for ${absPath} kept racing a concurrent retraction — retry` } };
|
|
135
139
|
}
|
|
136
140
|
catch (err) {
|
|
137
|
-
const f = foldCaughtFailure(err);
|
|
141
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.trackEdit");
|
|
138
142
|
return { ok: false, error: { code: "track_failed", message: `first-touch record for ${absPath} could not be persisted: ${f.text}`, ...f.fault } };
|
|
139
143
|
}
|
|
140
144
|
}
|
|
@@ -201,7 +205,7 @@ export class SqlFileHistoryStore {
|
|
|
201
205
|
return { ok: false, error: { code: "conflict", message: `first-touch record for ${absPath} was replaced while this retraction was being proven` } };
|
|
202
206
|
}
|
|
203
207
|
catch (err) {
|
|
204
|
-
const f = foldCaughtFailure(err);
|
|
208
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.annulTrack");
|
|
205
209
|
return { ok: false, error: { code: "track_failed", message: `annulling the first-touch record for ${absPath} failed: ${f.text}`, ...f.fault } };
|
|
206
210
|
}
|
|
207
211
|
}
|
|
@@ -309,7 +313,7 @@ export class SqlFileHistoryStore {
|
|
|
309
313
|
}
|
|
310
314
|
}
|
|
311
315
|
catch (err) {
|
|
312
|
-
const f = foldCaughtFailure(err);
|
|
316
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.snapshot");
|
|
313
317
|
return { ok: false, error: { code: "snapshot_failed", message: f.text, ...f.fault } };
|
|
314
318
|
}
|
|
315
319
|
this.activeAttempts.add(lease);
|
|
@@ -412,7 +416,7 @@ export class SqlFileHistoryStore {
|
|
|
412
416
|
catch (err) {
|
|
413
417
|
await conn.rollback().catch(() => undefined);
|
|
414
418
|
this.spentAttempts.add(lease);
|
|
415
|
-
const f = foldCaughtFailure(err);
|
|
419
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.snapshot");
|
|
416
420
|
return { ok: false, error: { code: "snapshot_failed", message: `boundary for entry "${entryId}" could not be committed: ${f.text}`, ...f.fault } };
|
|
417
421
|
}
|
|
418
422
|
finally {
|
|
@@ -423,7 +427,7 @@ export class SqlFileHistoryStore {
|
|
|
423
427
|
}
|
|
424
428
|
catch (err) {
|
|
425
429
|
this.spentAttempts.add(lease);
|
|
426
|
-
const f = foldCaughtFailure(err);
|
|
430
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.snapshot");
|
|
427
431
|
return { ok: false, error: { code: "snapshot_failed", message: f.text, ...f.fault } };
|
|
428
432
|
}
|
|
429
433
|
finally {
|
|
@@ -491,7 +495,7 @@ export class SqlFileHistoryStore {
|
|
|
491
495
|
});
|
|
492
496
|
}
|
|
493
497
|
catch (err) {
|
|
494
|
-
applied = { outcome: "failed", reason: foldCaughtFailure(err).text };
|
|
498
|
+
applied = { outcome: "failed", reason: foldCaughtFailure(err, "sql-file-history-store.restore").text };
|
|
495
499
|
}
|
|
496
500
|
if (applied.outcome === "applied")
|
|
497
501
|
ledger.filesChanged.push(t.trackKey);
|
|
@@ -508,7 +512,7 @@ export class SqlFileHistoryStore {
|
|
|
508
512
|
}
|
|
509
513
|
catch (err) {
|
|
510
514
|
const touched = empty.filesChanged.length > 0 || empty.identicalSkipped.length > 0 || empty.refused.length > 0 || empty.failed.length > 0;
|
|
511
|
-
const f = foldCaughtFailure(err);
|
|
515
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.restore");
|
|
512
516
|
return { outcome: touched ? "partial" : "failed", ...empty, error: { code: "restore_failed", message: f.text, ...f.fault } };
|
|
513
517
|
}
|
|
514
518
|
}
|
|
@@ -578,11 +582,7 @@ export class SqlFileHistoryStore {
|
|
|
578
582
|
try {
|
|
579
583
|
await conn.begin();
|
|
580
584
|
await this.lockScope(conn, scope);
|
|
581
|
-
|
|
582
|
-
for (const table of ["file_history_boundary_file", "file_history_boundary", "file_history_reaped_entry", "file_history_version", "file_history_tracked", "file_history_scope"]) {
|
|
583
|
-
const r = await conn.query(this.q(`DELETE FROM ${table} WHERE scope = ?`, `DELETE FROM ${table} WHERE scope = $1`), [scope]);
|
|
584
|
-
total += r.affected;
|
|
585
|
-
}
|
|
585
|
+
const total = await this.deleteScopeRowsOn(conn, scope, FILE_HISTORY_SCOPED_TABLES);
|
|
586
586
|
await conn.commit();
|
|
587
587
|
return total;
|
|
588
588
|
}
|
|
@@ -594,6 +594,18 @@ export class SqlFileHistoryStore {
|
|
|
594
594
|
conn.release();
|
|
595
595
|
}
|
|
596
596
|
}
|
|
597
|
+
async deleteScopeOn(conn, scope) {
|
|
598
|
+
await this.lockScopeOn(conn, [scope]);
|
|
599
|
+
return this.deleteScopeRowsOn(conn, scope, FILE_HISTORY_SCOPED_TABLES);
|
|
600
|
+
}
|
|
601
|
+
async deleteScopeRowsOn(conn, scope, tables) {
|
|
602
|
+
let total = 0;
|
|
603
|
+
for (const table of tables) {
|
|
604
|
+
const r = await conn.query(this.q(`DELETE FROM ${table} WHERE scope = ?`, `DELETE FROM ${table} WHERE scope = $1`), [scope]);
|
|
605
|
+
total += r.affected;
|
|
606
|
+
}
|
|
607
|
+
return total;
|
|
608
|
+
}
|
|
597
609
|
async sweepOrphanBlobs() {
|
|
598
610
|
const { rows } = await this.db.query("SELECT blob_hash FROM file_history_blob WHERE blob_hash NOT IN (SELECT blob_hash FROM file_history_version WHERE blob_hash IS NOT NULL)");
|
|
599
611
|
const orphans = rows.map((r) => String(r.blob_hash));
|
|
@@ -612,7 +624,7 @@ export class SqlFileHistoryStore {
|
|
|
612
624
|
catch (err) {
|
|
613
625
|
if (err instanceof BlobTooLargeError)
|
|
614
626
|
return { ok: false, error: { code: "adopt_failed", message: err.message, permanence: "terminal", blobCap: { wallSource: err.cap.source } } };
|
|
615
|
-
const f = foldCaughtFailure(err);
|
|
627
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.putExchangedBlob");
|
|
616
628
|
return { ok: false, error: { code: "snapshot_failed", message: `blob ${hash} write/upload failed: ${f.text}`, ...f.fault } };
|
|
617
629
|
}
|
|
618
630
|
}
|
|
@@ -650,7 +662,7 @@ export class SqlFileHistoryStore {
|
|
|
650
662
|
}
|
|
651
663
|
}
|
|
652
664
|
catch (err) {
|
|
653
|
-
const f = foldCaughtFailure(err);
|
|
665
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.adoptScope");
|
|
654
666
|
return { ok: false, error: { code: "adopt_failed", message: `adoptScope failed: ${f.text}`, ...f.fault } };
|
|
655
667
|
}
|
|
656
668
|
}
|
|
@@ -707,10 +719,10 @@ export class SqlFileHistoryStore {
|
|
|
707
719
|
const conn = await this.db.connect();
|
|
708
720
|
try {
|
|
709
721
|
await conn.begin();
|
|
710
|
-
await this.
|
|
711
|
-
const
|
|
722
|
+
const held = await conn.query(this.q("SELECT scope FROM file_history_scope WHERE scope = ? FOR UPDATE", "SELECT scope FROM file_history_scope WHERE scope = $1 FOR UPDATE"), [scope]);
|
|
723
|
+
const history = held.rows[0] === undefined ? null : await this.exportOf(conn, scope, true);
|
|
712
724
|
await conn.commit();
|
|
713
|
-
return { ok: true, history
|
|
725
|
+
return { ok: true, history };
|
|
714
726
|
}
|
|
715
727
|
catch (err) {
|
|
716
728
|
await conn.rollback().catch(() => undefined);
|
|
@@ -732,7 +744,7 @@ export class SqlFileHistoryStore {
|
|
|
732
744
|
bytes = await srcGetBlob(hash);
|
|
733
745
|
}
|
|
734
746
|
catch (err) {
|
|
735
|
-
const f = foldCaughtFailure(err);
|
|
747
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.verifySourceBlobs");
|
|
736
748
|
return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} fetch failed: ${f.text}`, ...f.fault } };
|
|
737
749
|
}
|
|
738
750
|
if (bytes === undefined)
|
|
@@ -745,6 +757,40 @@ export class SqlFileHistoryStore {
|
|
|
745
757
|
return { ok: true };
|
|
746
758
|
}
|
|
747
759
|
async importHistory(scope, data, srcGetBlob) {
|
|
760
|
+
const plan = await this.prepareImport(scope, data, srcGetBlob, { replace: false });
|
|
761
|
+
if (!plan.ok)
|
|
762
|
+
return plan;
|
|
763
|
+
if (plan.mode === "same")
|
|
764
|
+
return { ok: true };
|
|
765
|
+
try {
|
|
766
|
+
const conn = await this.db.connect();
|
|
767
|
+
try {
|
|
768
|
+
await conn.begin();
|
|
769
|
+
await this.lockScope(conn, scope);
|
|
770
|
+
const out = await this.publishImportLockedOn(conn, scope, data, { replace: false });
|
|
771
|
+
if (out.ok)
|
|
772
|
+
await conn.commit();
|
|
773
|
+
else
|
|
774
|
+
await conn.rollback();
|
|
775
|
+
return out;
|
|
776
|
+
}
|
|
777
|
+
catch (err) {
|
|
778
|
+
await conn.rollback().catch(() => undefined);
|
|
779
|
+
throw err;
|
|
780
|
+
}
|
|
781
|
+
finally {
|
|
782
|
+
conn.release();
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
catch (err) {
|
|
786
|
+
return { ok: false, error: this.importFailureOf(err) };
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
importFailureOf(err) {
|
|
790
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.importHistory");
|
|
791
|
+
return { code: "adopt_failed", message: `importHistory failed: ${f.text}`, ...f.fault };
|
|
792
|
+
}
|
|
793
|
+
async prepareImport(scope, data, srcGetBlob, opts) {
|
|
748
794
|
try {
|
|
749
795
|
const shaped = validateFileHistoryExport(data);
|
|
750
796
|
if (!shaped.ok)
|
|
@@ -762,59 +808,51 @@ export class SqlFileHistoryStore {
|
|
|
762
808
|
return exported;
|
|
763
809
|
const existing = exported.history;
|
|
764
810
|
const sameGraph = existing !== null && fileHistoryExportDigest(existing) === fileHistoryExportDigest(data);
|
|
765
|
-
if (existing !== null && !sameGraph) {
|
|
811
|
+
if (existing !== null && !sameGraph && !opts.replace) {
|
|
766
812
|
return { ok: false, error: { code: "conflict", message: `importHistory target "${scope}" already holds a DIFFERENT history — a first import requires an empty target and a retry is legal only for the identical envelope (atomic visibility prevents half-graphs; this law prevents publishing the wrong complete graph over locally-grown history)` } };
|
|
767
813
|
}
|
|
768
814
|
const verified = await this.verifySourceBlobs(data, srcGetBlob, sameGraph ? undefined : (hash, bytes) => this.blobs.put(hash, bytes));
|
|
769
815
|
if (!verified.ok)
|
|
770
816
|
return verified;
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
for (const t of data.tracked) {
|
|
788
|
-
const keyHash = sha256hex(t.relOrAbsPath);
|
|
789
|
-
await conn.query(this.q("INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES (?,?,?,?,?,?,0,?)", "INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES ($1,$2,$3,$4,$5,$6,FALSE,$7)"), [scope, keyHash, t.relOrAbsPath, t.keyKind, t.keyFamily, this.bool(t.baseAvailable), now]);
|
|
790
|
-
for (const v of t.versions) {
|
|
791
|
-
await conn.query(this.q("INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES (?,?,?,?,?,?,?)", "INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES ($1,$2,$3,$4,$5,$6,$7)"), [scope, keyHash, v.version, v.blobHash, v.mode ?? null, v.parentIdent ?? null, v.backupTime]);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
const seqBase = await conn.query(this.q("SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = ?", "SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = $1"), [scope]);
|
|
795
|
-
let publishSeq = Number(seqBase.rows[0].s);
|
|
796
|
-
for (const b of data.boundaries) {
|
|
797
|
-
publishSeq += 1;
|
|
798
|
-
await conn.query(this.q("INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, now, publishSeq]);
|
|
799
|
-
for (const f of b.files) {
|
|
800
|
-
await conn.query(this.q("INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, sha256hex(f.relOrAbsPath), f.version]);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
await conn.commit();
|
|
817
|
+
return { ok: true, mode: sameGraph ? "same" : "publish" };
|
|
818
|
+
}
|
|
819
|
+
catch (err) {
|
|
820
|
+
return { ok: false, error: this.importFailureOf(err) };
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
async publishImportOn(conn, scope, data, plan, opts) {
|
|
824
|
+
if (plan.mode === "same")
|
|
825
|
+
return { ok: true };
|
|
826
|
+
await this.lockScopeOn(conn, [scope]);
|
|
827
|
+
return this.publishImportLockedOn(conn, scope, data, opts);
|
|
828
|
+
}
|
|
829
|
+
async publishImportLockedOn(conn, scope, data, opts) {
|
|
830
|
+
if (!(await this.scopeEmpty(conn, scope, true))) {
|
|
831
|
+
const held = await this.exportOf(conn, scope, true);
|
|
832
|
+
if (held !== null && fileHistoryExportDigest(held) === fileHistoryExportDigest(data))
|
|
804
833
|
return { ok: true };
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
834
|
+
if (!opts.replace)
|
|
835
|
+
return { ok: false, error: { code: "conflict", message: `importHistory target "${scope}" gained a DIFFERENT history while this import was fetching blobs — nothing was published` } };
|
|
836
|
+
await this.deleteScopeRowsOn(conn, scope, FILE_HISTORY_SCOPED_TABLES.filter((t) => t !== "file_history_scope"));
|
|
837
|
+
}
|
|
838
|
+
const now = Date.now();
|
|
839
|
+
for (const t of data.tracked) {
|
|
840
|
+
const keyHash = sha256hex(t.relOrAbsPath);
|
|
841
|
+
await conn.query(this.q("INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES (?,?,?,?,?,?,0,?)", "INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES ($1,$2,$3,$4,$5,$6,FALSE,$7)"), [scope, keyHash, t.relOrAbsPath, t.keyKind, t.keyFamily, this.bool(t.baseAvailable), now]);
|
|
842
|
+
for (const v of t.versions) {
|
|
843
|
+
await conn.query(this.q("INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES (?,?,?,?,?,?,?)", "INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES ($1,$2,$3,$4,$5,$6,$7)"), [scope, keyHash, v.version, v.blobHash, v.mode ?? null, v.parentIdent ?? null, v.backupTime]);
|
|
812
844
|
}
|
|
813
845
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
846
|
+
const seqBase = await conn.query(this.q("SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = ?", "SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = $1"), [scope]);
|
|
847
|
+
let publishSeq = Number(seqBase.rows[0].s);
|
|
848
|
+
for (const b of data.boundaries) {
|
|
849
|
+
publishSeq += 1;
|
|
850
|
+
await conn.query(this.q("INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, now, publishSeq]);
|
|
851
|
+
for (const f of b.files) {
|
|
852
|
+
await conn.query(this.q("INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, sha256hex(f.relOrAbsPath), f.version]);
|
|
853
|
+
}
|
|
817
854
|
}
|
|
855
|
+
return { ok: true };
|
|
818
856
|
}
|
|
819
857
|
}
|
|
820
858
|
export class TiDBFileHistoryStore extends SqlFileHistoryStore {
|
|
@@ -2,9 +2,9 @@ import { type AcquiredSession, type PlacedSessionRow, type SessionHead, type Ses
|
|
|
2
2
|
import type { Pool, PoolClient } from "pg";
|
|
3
3
|
import { WindowedSessionStorage } from "./windowed-session-storage.js";
|
|
4
4
|
import { type PlacementAcquireOpts } from "../plugins/session-placement.js";
|
|
5
|
-
import { type StagingHandle } from "../session-sync-kernel.js";
|
|
5
|
+
import { type EntriesStreamOptions, type StagedCommitOptions, type StagingHandle, type SyncRelation } from "../session-sync-kernel.js";
|
|
6
6
|
import type { RetentionDeclaration } from "@sema-agent/core";
|
|
7
|
-
import { type RegisterReceipt, type WithdrawOutcome } from "../session-incarnation.js";
|
|
7
|
+
import { type RegisterReceipt, type SessionFace, type WithdrawOutcome } from "../session-incarnation.js";
|
|
8
8
|
import type { SessionWriteHooks } from "./session-write-hooks.js";
|
|
9
9
|
import { type IndexSpec } from "../plugins/ensure-index.js";
|
|
10
10
|
import { type SessionDeleteCondition } from "./tidb-session-store.js";
|
|
@@ -78,7 +78,7 @@ export declare class PgSessionStore implements SessionStore {
|
|
|
78
78
|
/** Idempotently create a session_meta row with an owner (core `SessionStore.register`). Existing owner is never overwritten. */
|
|
79
79
|
register(sessionId: string, owner: string | null): Promise<void>;
|
|
80
80
|
/** 出生回执面(TiDB 孪生 {@link TiDBSessionStore.registerWithReceipt} 同义:候选 = 这一次 INSERT 入参里铸的化身)。 */
|
|
81
|
-
registerWithReceipt(sessionId: string, owner: string | null): Promise<RegisterReceipt>;
|
|
81
|
+
registerWithReceipt(sessionId: string, owner: string | null, kind?: string): Promise<RegisterReceipt>;
|
|
82
82
|
/** 条件删除(TiDB 孪生 {@link TiDBSessionStore.deleteSessionIf} 同义)。 */
|
|
83
83
|
deleteSessionIf(sessionId: string, cond: SessionDeleteCondition): Promise<WithdrawOutcome>;
|
|
84
84
|
/** acquire 的建行(唯一一处;placed 会话的属主 = `placement.owner` 原样,core 7.62.0 [ref] 盒义务 7 —— TiDB 孪生同名方法同注)。 */
|
|
@@ -86,6 +86,8 @@ export declare class PgSessionStore implements SessionStore {
|
|
|
86
86
|
/** The one session_meta INSERT. Existing owner is never overwritten.
|
|
87
87
|
* [ref]:`placement` 与行同一条 INSERT;`DO NOTHING` 臂 ⇒ 已存在行的元组永不被重写(first-write 不可变)。 */
|
|
88
88
|
private insertMeta;
|
|
89
|
+
/** {@link insertMeta} 那一句,发在给定的连接上(带种类的登记在自己的事务连接上发)。 */
|
|
90
|
+
private insertMetaOn;
|
|
89
91
|
/** [ref] 义务 6 的廉价探针(TiDB 孪生 {@link TiDBSessionStore.placementOf} 同义)。 */
|
|
90
92
|
placementOf(sessionId: string): Promise<SessionPlacementRecord | undefined>;
|
|
91
93
|
/** [ref] 义务 5 —— placed 分区枚举(年龄锚/上界/tupleIncomplete 三条读法与 TiDB 孪生逐字同义,
|
|
@@ -128,10 +130,7 @@ export declare class PgSessionStore implements SessionStore {
|
|
|
128
130
|
* held connection across the stream → a slow consumer can't pin one). Start cursor = afterSeq ?? -1 (0-based dense).
|
|
129
131
|
* Resolves to null (NOT an empty iterable) for a missing session — eager `session_meta` probe (BIGINT seq comes
|
|
130
132
|
* back as a STRING in node-pg → always Number(...) the cursor advance). */
|
|
131
|
-
exportEntriesStream(sessionId: string, opts
|
|
132
|
-
afterSeq?: number;
|
|
133
|
-
batchSize?: number;
|
|
134
|
-
}): Promise<AsyncIterable<SessionTreeEntry> | null>;
|
|
133
|
+
exportEntriesStream(sessionId: string, opts: EntriesStreamOptions): Promise<AsyncIterable<SessionTreeEntry> | null>;
|
|
135
134
|
/** @see TiDBSessionStore.importEntries — 2c session-sync IMPORT: core `validateEntriesForImport` gate FIRST (fail-closed),
|
|
136
135
|
* then persist its verbatim output (re-seq dense from 0, ids/parents/payload/ts unchanged) in ONE txn, **lock-or-create, meta first**
|
|
137
136
|
* (占行 → 锁行判是不是本次占下的 → 部署的事务内钩 `import` → 事件);owner = the RE-STAMPED authenticated principal (never the bundle's). */
|
|
@@ -160,4 +159,32 @@ export declare class PgSessionStore implements SessionStore {
|
|
|
160
159
|
get size(): number;
|
|
161
160
|
dispose(): void;
|
|
162
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* 2c session-sync P1d-β — the PG twin of {@link TiDBStagingHandle} (behaviourally identical; only the SQL dialect
|
|
164
|
+
* differs: `$n` placeholders, `$n::jsonb`, `ON CONFLICT (session_id, entry_id) DO NOTHING`, rowCount, FOR UPDATE,
|
|
165
|
+
* BEGIN/COMMIT handle). Streams entry batches into a shadow session_event partition, then atomically RENAMEs them
|
|
166
|
+
* onto the real session id in ONE txn; session_meta is locked (or claimed, for a fresh push) first and settled last, COMMIT = the commit point.
|
|
167
|
+
*/
|
|
168
|
+
/** 暂存句柄(会话同步的推送腿逐批写、提交、撤销;由本店的 `stageImport` 交出)。导出只为组合座给它封口(店边界)。 */
|
|
169
|
+
export declare class PgStagingHandle implements StagingHandle {
|
|
170
|
+
private readonly pool;
|
|
171
|
+
private readonly hooks;
|
|
172
|
+
readonly realSessionId: string;
|
|
173
|
+
readonly stagingId: string;
|
|
174
|
+
private nextSeq;
|
|
175
|
+
private readonly seen;
|
|
176
|
+
constructor(pool: Pool, hooks: SessionWriteHooks, realSessionId: string, stagingId: string);
|
|
177
|
+
/** @see TiDBStagingHandle.appendBatch — DENSE re-seq (skip already-staged ids), idempotent ON CONFLICT (session_id,
|
|
178
|
+
* entry_id) DO NOTHING, one txn/batch. */
|
|
179
|
+
appendBatch(entries: SessionTreeEntry[]): Promise<void>;
|
|
180
|
+
/** @see TiDBStagingHandle.commit — the atomic swap: owner CAS first (lock / claim the session_meta row) → in-commit re-classify (FOR UPDATE)
|
|
181
|
+
* → purge dst → rename staging→real → settle session_meta. Throws StagedCommitOccupantChangedError when the owner cell is not the judged one,
|
|
182
|
+
* SyncConflictError on an unconsented fork/stale flip. */
|
|
183
|
+
commit(owner: string | null, opts: StagedCommitOptions): Promise<{
|
|
184
|
+
relation: SyncRelation["relation"];
|
|
185
|
+
face: SessionFace;
|
|
186
|
+
}>;
|
|
187
|
+
/** @see TiDBStagingHandle.abort — DELETE the staging rows. Idempotent. */
|
|
188
|
+
abort(): Promise<void>;
|
|
189
|
+
}
|
|
163
190
|
//# sourceMappingURL=pg-session-storage.d.ts.map
|
|
@@ -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,7 +1,7 @@
|
|
|
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
6
|
import { SEALED_EVENT, eraseSessionPolicyRowsOn } from "./session-policy-store-sql.js";
|
|
7
7
|
export const RETENTION_TOMBSTONE_TABLE = "retention_tombstone";
|
|
@@ -217,15 +217,7 @@ export class SqlRetentionStore {
|
|
|
217
217
|
return Number(rows[0]?.n ?? 0);
|
|
218
218
|
}
|
|
219
219
|
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})`);
|
|
220
|
+
return sessionLiveReferenceSql(this.db.dialect);
|
|
229
221
|
}
|
|
230
222
|
async countProtectedSessions(exec, input) {
|
|
231
223
|
const w = this.domainWhere("sm.owner", input.domain, 1);
|
|
@@ -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
|