@sema-agent/server 7.131.0 → 7.133.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 +575 -0
- package/README.md +12 -9
- package/README.zh-CN.md +9 -6
- package/USAGE.md +326 -98
- package/deploy/sema-up/README.md +19 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
- package/deploy/sema-up/chart/templates/server.yaml +5 -2
- package/deploy/sema-up/stack/compose.yaml +3 -0
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
- package/dist/adoption/plan.d.ts +3 -2
- package/dist/adoption/plan.js +7 -5
- package/dist/adoption/runner.js +3 -10
- package/dist/adoption/sql.d.ts +3 -2
- package/dist/adoption/sql.js +3 -5
- package/dist/adoption/wire.d.ts +4 -1
- package/dist/adoption/wire.js +1 -0
- package/dist/approval-ask-audit-store.d.ts +31 -13
- package/dist/approval-ask-audit-store.js +272 -74
- package/dist/approval-ask-machine.d.ts +15 -0
- package/dist/approval-ask-machine.js +6 -0
- package/dist/approval-ask-retention.d.ts +136 -0
- package/dist/approval-ask-retention.js +102 -0
- package/dist/approval-card.d.ts +82 -20
- package/dist/approval-card.js +46 -16
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval.d.ts +9 -0
- package/dist/approval.js +24 -3
- package/dist/audit.d.ts +33 -19
- package/dist/audit.js +12 -16
- package/dist/auth-bridge.d.ts +4 -0
- package/dist/auth-bridge.js +10 -11
- package/dist/bake-runner/main.js +3 -2
- package/dist/boot/deferred-sandbox-path-env.js +1 -1
- package/dist/boot/deployment-mods.d.ts +31 -0
- package/dist/boot/deployment-mods.js +26 -0
- package/dist/boot/execution-env.d.ts +1 -1
- package/dist/boot/execution-env.js +27 -12
- package/dist/boot/execution-lane.js +11 -0
- package/dist/boot/leader.js +2 -0
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-boundary.js +2 -2
- package/dist/boot/memory-consolidation.d.ts +5 -4
- package/dist/boot/memory-consolidation.js +7 -6
- package/dist/boot/org-delivery.d.ts +28 -0
- package/dist/boot/org-delivery.js +20 -0
- package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
- package/dist/boot/read-deny-anchor-audit.js +36 -0
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +21 -1
- package/dist/boot/resolve-spec.d.ts +4 -5
- package/dist/boot/resolve-spec.js +74 -123
- package/dist/boot/runner-deps.d.ts +19 -8
- package/dist/boot/runner-deps.js +15 -2
- package/dist/boot/session-faces.d.ts +2 -7
- package/dist/boot/session-faces.js +4 -2
- package/dist/boot/stage-02-web-admin-pull.js +4 -1
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +4 -4
- package/dist/boot/stage-05-execution-env.js +7 -10
- package/dist/boot/stage-06-runners.d.ts +4 -2
- package/dist/boot/stage-06-runners.js +11 -7
- package/dist/boot/stage-07-capability-layer.d.ts +4 -2
- package/dist/boot/stage-07-capability-layer.js +27 -6
- package/dist/boot/stage-08-reapers.d.ts +4 -2
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +6 -9
- package/dist/boot/stage-10-http-server.d.ts +6 -9
- package/dist/boot/stage-10-http-server.js +7 -9
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/stores.js +7 -8
- package/dist/boot/web-admin.d.ts +4 -3
- package/dist/boot/web-admin.js +186 -98
- package/dist/boot/workflow-orchestration.d.ts +2 -0
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/brain.js +25 -25
- package/dist/breaker-key.d.ts +6 -0
- package/dist/breaker-key.js +29 -0
- package/dist/budget.js +5 -4
- package/dist/caller-text-echo.d.ts +23 -0
- package/dist/caller-text-echo.js +21 -0
- package/dist/capabilities/brand-identity.d.ts +26 -0
- package/dist/capabilities/brand-identity.js +27 -0
- package/dist/capabilities/center-plugins.d.ts +7 -0
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/center-prompts.d.ts +32 -59
- package/dist/capabilities/center-prompts.js +18 -32
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/engine-capabilities.js +2 -1
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +30 -6
- package/dist/capabilities/hands-lane.js +11 -1
- package/dist/capabilities/mcp-probe.d.ts +48 -3
- package/dist/capabilities/mcp-probe.js +47 -135
- package/dist/capabilities/scenarios.d.ts +95 -45
- package/dist/capabilities/scenarios.js +53 -38
- package/dist/capabilities/skills.d.ts +19 -4
- package/dist/capabilities/skills.js +30 -10
- package/dist/capability-facts.d.ts +34 -4
- package/dist/capability-facts.js +28 -2
- package/dist/center-config-tier.d.ts +69 -0
- package/dist/center-config-tier.js +42 -0
- package/dist/checkpoint-identity.d.ts +16 -0
- package/dist/checkpoint-identity.js +19 -0
- package/dist/config-catalog.d.ts +17 -10
- package/dist/config-catalog.js +47 -32
- package/dist/config-d-migration.d.ts +3 -1
- package/dist/config-d-migration.js +2 -2
- package/dist/config-dir-trust.d.ts +114 -0
- package/dist/config-dir-trust.js +388 -0
- package/dist/config-invariants.d.ts +18 -5
- package/dist/config-invariants.js +35 -3
- package/dist/config-lkg.d.ts +9 -9
- package/dist/config-lkg.js +20 -4
- package/dist/config-provider.d.ts +9 -2
- package/dist/config-provider.js +18 -6
- package/dist/config-types.d.ts +75 -20
- package/dist/config-types.js +8 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +137 -62
- package/dist/delegated-session-owner.d.ts +185 -0
- package/dist/delegated-session-owner.js +119 -0
- package/dist/device-protocol.d.ts +5 -3
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.js +21 -2
- package/dist/device-ws-protocol.d.ts +70 -6
- package/dist/device-ws-protocol.js +50 -22
- package/dist/elicitation.js +3 -2
- package/dist/entry-problems.d.ts +34 -0
- package/dist/entry-problems.js +14 -0
- package/dist/env-name-allowlist-knobs.d.ts +12 -2
- package/dist/env-name-allowlist-knobs.js +5 -4
- package/dist/exec-bounds.d.ts +15 -3
- package/dist/exec-bounds.js +4 -0
- package/dist/execution-lane-caps.d.ts +56 -10
- package/dist/execution-lane-caps.js +50 -0
- package/dist/field-conflict.d.ts +43 -0
- package/dist/field-conflict.js +20 -0
- package/dist/fleet/fleet-bus.d.ts +80 -6
- package/dist/fleet/fleet-bus.js +41 -9
- package/dist/hooks/classic-stations.d.ts +91 -0
- package/dist/hooks/classic-stations.js +27 -0
- package/dist/hooks/command-spawn.d.ts +57 -0
- package/dist/hooks/command-spawn.js +139 -0
- package/dist/hooks/hook-llm.d.ts +8 -5
- package/dist/hooks/hook-llm.js +79 -36
- package/dist/hooks/hook-runner.d.ts +349 -95
- package/dist/hooks/hook-runner.js +855 -568
- package/dist/hooks/hook-source.d.ts +44 -0
- package/dist/hooks/hook-source.js +40 -0
- package/dist/http/active-run-conflict.d.ts +5 -13
- package/dist/http/active-run-conflict.js +17 -27
- package/dist/http/admission.d.ts +8 -2
- package/dist/http/admission.js +188 -101
- package/dist/http/approval-sweeps.js +99 -21
- package/dist/http/caller-trust.d.ts +77 -0
- package/dist/http/caller-trust.js +143 -0
- package/dist/http/checkpoint-ctx.d.ts +41 -24
- package/dist/http/checkpoint-ctx.js +23 -16
- package/dist/http/claimed-run.d.ts +14 -0
- package/dist/http/claimed-run.js +15 -0
- package/dist/http/device-placement.d.ts +2 -4
- package/dist/http/device-placement.js +7 -11
- package/dist/http/dispatch.d.ts +0 -4
- package/dist/http/dispatch.js +15 -13
- package/dist/http/durable-run-leg.d.ts +6 -33
- package/dist/http/durable-run-leg.js +36 -10
- package/dist/http/health-self-report.d.ts +7 -5
- package/dist/http/health-self-report.js +4 -18
- package/dist/http/owner-access.d.ts +56 -0
- package/dist/http/owner-access.js +42 -0
- package/dist/http/principal-gate.d.ts +70 -28
- package/dist/http/principal-gate.js +61 -15
- package/dist/http/readiness.d.ts +11 -5
- package/dist/http/readiness.js +10 -3
- package/dist/http/refusal-body.d.ts +21 -0
- package/dist/http/refusal-body.js +4 -0
- package/dist/http/request-guards.d.ts +43 -23
- package/dist/http/request-guards.js +53 -17
- package/dist/http/resume-ctx-read.d.ts +2 -5
- package/dist/http/resume-ctx-read.js +7 -4
- package/dist/http/resume-legs.d.ts +28 -4
- package/dist/http/resume-legs.js +169 -91
- package/dist/http/retired-service-deps.d.ts +43 -0
- package/dist/http/retired-service-deps.js +18 -0
- package/dist/http/route-ctx.d.ts +44 -28
- package/dist/http/route-ctx.js +4 -0
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/a2a-serve.js +3 -4
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.js +1 -1
- package/dist/http/routes/admin-memory-optout.js +5 -1
- package/dist/http/routes/adoption.js +2 -9
- package/dist/http/routes/approvals-assistant.js +49 -48
- package/dist/http/routes/background.js +3 -2
- package/dist/http/routes/capabilities.js +21 -5
- package/dist/http/routes/config-catalog.d.ts +3 -3
- package/dist/http/routes/config-catalog.js +1 -1
- package/dist/http/routes/devices.js +3 -17
- package/dist/http/routes/diagnostics.js +6 -2
- package/dist/http/routes/images.js +6 -7
- package/dist/http/routes/leader.js +1 -8
- package/dist/http/routes/mcp-reconnect.d.ts +1 -1
- package/dist/http/routes/mcp-reconnect.js +3 -2
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-consolidation.js +1 -1
- package/dist/http/routes/memory-origin.js +1 -1
- package/dist/http/routes/memory-policy.d.ts +1 -1
- package/dist/http/routes/memory-policy.js +3 -2
- package/dist/http/routes/notify-wake.js +8 -21
- package/dist/http/routes/observability.js +2 -2
- package/dist/http/routes/principal-inbox.d.ts +39 -0
- package/dist/http/routes/principal-inbox.js +76 -0
- package/dist/http/routes/retention-ops.js +2 -9
- package/dist/http/routes/rules.js +5 -18
- package/dist/http/routes/runs.d.ts +5 -0
- package/dist/http/routes/runs.js +34 -107
- package/dist/http/routes/session-sync.js +15 -26
- package/dist/http/routes/sessions.js +30 -40
- package/dist/http/routes/shared-memory.js +2 -13
- package/dist/http/routes/side-query.js +8 -7
- package/dist/http/routes/tasks.js +67 -21
- package/dist/http/routes/workflows.d.ts +351 -0
- package/dist/http/routes/workflows.js +153 -119
- package/dist/http/send.d.ts +33 -10
- package/dist/http/send.js +21 -4
- package/dist/http/server.d.ts +27 -18
- package/dist/http/server.js +34 -6
- package/dist/http/stored-body-replay.js +17 -4
- package/dist/http/submit-ctx.d.ts +25 -0
- package/dist/http/submit-ctx.js +40 -0
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +5 -4
- package/dist/http/wire-types.d.ts +11 -8
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -2
- package/dist/lane-home-probe.d.ts +112 -0
- package/dist/lane-home-probe.js +101 -0
- package/dist/leader/endpoint.d.ts +4 -1
- package/dist/leader/endpoint.js +11 -10
- package/dist/limit-refusal.d.ts +59 -0
- package/dist/limit-refusal.js +15 -0
- package/dist/main.js +1 -1
- package/dist/mcp-assertion-header.d.ts +32 -19
- package/dist/mcp-assertion-header.js +10 -9
- package/dist/mcp-tool-faces.d.ts +5 -0
- package/dist/mcp-tool-faces.js +6 -4
- package/dist/memory-project-layer.d.ts +37 -0
- package/dist/memory-project-layer.js +46 -0
- package/dist/memory-scope.d.ts +24 -17
- package/dist/memory-scope.js +24 -8
- package/dist/memory-sync-client.d.ts +27 -13
- package/dist/memory-sync-client.js +107 -18
- package/dist/model-entry-refusal.d.ts +9 -1
- package/dist/model-entry-refusal.js +6 -1
- package/dist/model-plane-face.d.ts +51 -0
- package/dist/model-plane-face.js +24 -0
- package/dist/model-provider.d.ts +44 -12
- package/dist/model-provider.js +21 -2
- package/dist/model-route-endpoint.d.ts +9 -12
- package/dist/model-route-endpoint.js +8 -11
- package/dist/model-route-env.d.ts +22 -0
- package/dist/model-route-env.js +2 -0
- package/dist/model-route-gap.d.ts +60 -30
- package/dist/model-route-gap.js +21 -15
- package/dist/observability/corrupt-read-seat.d.ts +7 -0
- package/dist/observability/corrupt-read-seat.js +9 -0
- package/dist/observability/cost-taxonomy.d.ts +7 -7
- package/dist/observability/err-text.d.ts +6 -0
- package/dist/observability/err-text.js +18 -4
- package/dist/observability/fail-open.d.ts +76 -14
- package/dist/observability/fail-open.js +76 -14
- package/dist/observability/metrics.js +4 -1
- package/dist/observability/prompt-manifest.d.ts +33 -82
- package/dist/observability/prompt-manifest.js +122 -17
- package/dist/observability/run-terminal.js +14 -6
- package/dist/observability/secret-env-scrub.d.ts +13 -1
- package/dist/observability/secret-env-scrub.js +13 -1
- package/dist/observability/tool-trace.d.ts +16 -21
- package/dist/observability/tool-trace.js +58 -49
- package/dist/operator-ask.d.ts +10 -0
- package/dist/operator-ask.js +3 -0
- package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
- package/dist/orchestration/workflow-agent-session-index.js +9 -13
- package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
- package/dist/orchestration/workflow-completion-inbox.js +13 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
- package/dist/orchestration/workflow-notify-journal.js +27 -34
- package/dist/orchestration/workflow-park-decision.d.ts +89 -0
- package/dist/orchestration/workflow-park-decision.js +118 -0
- package/dist/org-delivery-gate.d.ts +81 -0
- package/dist/org-delivery-gate.js +59 -0
- package/dist/panel-tool-names.d.ts +23 -0
- package/dist/panel-tool-names.js +8 -0
- package/dist/parked-decide.d.ts +39 -6
- package/dist/parked-decide.js +98 -51
- package/dist/parked-revive-surface.d.ts +9 -2
- package/dist/parked-revive-surface.js +11 -8
- package/dist/per-task-image.d.ts +7 -1
- package/dist/per-task-image.js +3 -3
- package/dist/permission-rule-list.d.ts +1 -1
- package/dist/permission-rule-list.js +2 -2
- package/dist/plain-string-record.d.ts +25 -0
- package/dist/plain-string-record.js +32 -0
- package/dist/plugins/approval-ask-store-file.d.ts +16 -1
- package/dist/plugins/approval-ask-store-file.js +21 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
- package/dist/plugins/approval-ask-store-memory.js +34 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
- package/dist/plugins/approval-ask-store-sql.js +37 -1
- package/dist/plugins/blob-backend.d.ts +83 -15
- package/dist/plugins/blob-backend.js +68 -15
- package/dist/plugins/breaker-state-sql.d.ts +2 -2
- package/dist/plugins/breaker-state-sql.js +4 -4
- package/dist/plugins/caching-session-store.d.ts +3 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +28 -4
- package/dist/plugins/checkpoint-store-sql.js +59 -28
- package/dist/plugins/file-history-store-sql.d.ts +5 -2
- package/dist/plugins/file-history-store-sql.js +3 -1
- package/dist/plugins/file-run-store.d.ts +5 -13
- package/dist/plugins/file-run-store.js +9 -0
- package/dist/plugins/fork-routing-session-store.d.ts +9 -1
- package/dist/plugins/fork-routing-session-store.js +12 -1
- package/dist/plugins/host-platform.d.ts +2 -0
- package/dist/plugins/host-platform.js +2 -1
- package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
- package/dist/plugins/k8s-bg-scripts.js +22 -0
- package/dist/plugins/local-checkpoint-store.d.ts +2 -0
- package/dist/plugins/local-checkpoint-store.js +11 -3
- package/dist/plugins/local-session-store.d.ts +1 -1
- package/dist/plugins/local-session-store.js +1 -1
- package/dist/plugins/local-session-window.d.ts +39 -0
- package/dist/plugins/local-session-window.js +54 -0
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
- package/dist/plugins/mailbox-store-sql.d.ts +30 -48
- package/dist/plugins/mailbox-store-sql.js +77 -52
- package/dist/plugins/memory-embedder-fingerprint.js +2 -1
- package/dist/plugins/memory-run-store.d.ts +5 -13
- package/dist/plugins/memory-run-store.js +8 -0
- package/dist/plugins/one-time-migrations.d.ts +245 -93
- package/dist/plugins/one-time-migrations.js +668 -207
- package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
- package/dist/plugins/org-delivery-quota-store.js +228 -0
- package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
- package/dist/plugins/permission-rule-store-sql.js +4 -18
- package/dist/plugins/pg-pool.js +39 -7
- package/dist/plugins/pg-session-storage.d.ts +20 -8
- package/dist/plugins/pg-session-storage.js +34 -21
- package/dist/plugins/remote-env-adb.d.ts +12 -12
- package/dist/plugins/remote-env-adb.js +21 -6
- package/dist/plugins/remote-env-device.js +3 -0
- package/dist/plugins/remote-env-e2b.d.ts +1 -1
- package/dist/plugins/remote-env-e2b.js +21 -9
- package/dist/plugins/remote-env-host.d.ts +9 -9
- package/dist/plugins/remote-env-host.js +10 -32
- package/dist/plugins/remote-env-k8s.d.ts +103 -38
- package/dist/plugins/remote-env-k8s.js +288 -95
- package/dist/plugins/remote-env-local-docker.d.ts +27 -13
- package/dist/plugins/remote-env-local-docker.js +82 -11
- package/dist/plugins/remote-env-ssh.d.ts +21 -12
- package/dist/plugins/remote-env-ssh.js +117 -5
- package/dist/plugins/remote-shell.d.ts +0 -1
- package/dist/plugins/remote-shell.js +1 -2
- package/dist/plugins/retention-store-sql.js +6 -2
- package/dist/plugins/run-store-sql.d.ts +16 -14
- package/dist/plugins/run-store-sql.js +22 -2
- package/dist/plugins/schema-consistency.d.ts +54 -0
- package/dist/plugins/schema-consistency.js +52 -0
- package/dist/plugins/schema-indexes.js +2 -0
- package/dist/plugins/send-user-file.js +2 -2
- package/dist/plugins/session-epoch-anchor.d.ts +39 -0
- package/dist/plugins/session-epoch-anchor.js +22 -0
- package/dist/plugins/session-store.d.ts +18 -8
- package/dist/plugins/session-store.js +15 -4
- package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
- package/dist/plugins/shared-memory-store-sql.js +5 -16
- package/dist/plugins/sql-driver.d.ts +205 -1
- package/dist/plugins/sql-driver.js +325 -13
- package/dist/plugins/sql-errors.d.ts +64 -0
- package/dist/plugins/sql-errors.js +57 -0
- package/dist/plugins/store-backend.d.ts +36 -1
- package/dist/plugins/store-backend.js +42 -15
- package/dist/plugins/store-contracts.d.ts +42 -0
- package/dist/plugins/store-contracts.js +1 -0
- package/dist/plugins/tidb-pool.d.ts +6 -1
- package/dist/plugins/tidb-pool.js +44 -10
- package/dist/plugins/tidb-session-storage.d.ts +8 -11
- package/dist/plugins/tidb-session-storage.js +6 -16
- package/dist/plugins/tidb-session-store.d.ts +24 -4
- package/dist/plugins/tidb-session-store.js +29 -5
- package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
- package/dist/plugins/workflow-journal-store-sql.js +19 -6
- package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
- package/dist/plugins/workflow-run-store-sql.js +50 -9
- package/dist/posture-source.d.ts +18 -10
- package/dist/posture-source.js +4 -1
- package/dist/project-identity.d.ts +45 -6
- package/dist/project-identity.js +162 -8
- package/dist/project-layer-key.d.ts +28 -0
- package/dist/project-layer-key.js +29 -0
- package/dist/prompts-domain-validate.d.ts +17 -61
- package/dist/prompts-domain-validate.js +9 -119
- package/dist/question.js +3 -2
- package/dist/read-deny-entry.d.ts +25 -0
- package/dist/read-deny-entry.js +12 -0
- package/dist/read-face-posture.d.ts +37 -11
- package/dist/read-face-posture.js +32 -3
- package/dist/request-key-closure.d.ts +9 -2
- package/dist/request-key-closure.js +11 -5
- package/dist/request-value-closure.d.ts +5 -0
- package/dist/request-value-closure.js +11 -3
- package/dist/rule-entry-list.d.ts +38 -11
- package/dist/rule-entry-list.js +106 -30
- package/dist/rules-consent.js +3 -4
- package/dist/run-acceptance.d.ts +19 -3
- package/dist/run-acceptance.js +13 -1
- package/dist/run-local.js +54 -24
- package/dist/runs.d.ts +15 -8
- package/dist/runs.js +35 -1
- package/dist/runtime-caps-resolver.d.ts +16 -6
- package/dist/runtime-caps-resolver.js +18 -5
- package/dist/sandbox-pkg-source.d.ts +19 -1
- package/dist/sandbox-pkg-source.js +29 -7
- package/dist/security.d.ts +87 -9
- package/dist/security.js +52 -9
- package/dist/server-secret-env.d.ts +44 -18
- package/dist/server-secret-env.js +49 -8
- package/dist/session-error-wire.d.ts +19 -2
- package/dist/session-error-wire.js +5 -1
- package/dist/session-incarnation.d.ts +15 -5
- package/dist/session-incarnation.js +16 -9
- package/dist/session-titled-frame.d.ts +33 -0
- package/dist/session-titled-frame.js +4 -0
- package/dist/session-titler.d.ts +9 -1
- package/dist/session-titler.js +27 -6
- package/dist/spec-fields.d.ts +28 -16
- package/dist/spec-fields.js +66 -54
- package/dist/sql-engine-posture.d.ts +31 -4
- package/dist/sql-engine-posture.js +36 -1
- package/dist/stored-request-tool-axes-m19.d.ts +19 -4
- package/dist/stored-request-tool-axes-m19.js +30 -2
- package/dist/task-a2a.d.ts +9 -1
- package/dist/task-a2a.js +73 -47
- package/dist/task-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +46 -58
- package/dist/task-mcp.js +82 -107
- package/dist/task-settings.d.ts +95 -108
- package/dist/task-settings.js +77 -98
- package/dist/text-bidi.d.ts +1 -48
- package/dist/text-bidi.js +3 -5
- package/dist/tighten-only-seats.d.ts +150 -0
- package/dist/tighten-only-seats.js +196 -0
- package/dist/tool-approval.d.ts +304 -88
- package/dist/tool-approval.js +623 -239
- package/dist/trace/core-keyset-guard.d.ts +122 -20
- package/dist/trace/engine-notice-wire.d.ts +11 -3
- package/dist/trace/engine-notice-wire.js +8 -1
- package/dist/trace/exit-seat.d.ts +28 -0
- package/dist/trace/exit-seat.js +76 -0
- package/dist/trace/ledger-events.d.ts +6 -3
- package/dist/trace/ledger-sink.js +4 -1
- package/dist/trace/model-segment.js +1 -1
- package/dist/trace/project.d.ts +98 -17
- package/dist/trace/project.js +98 -50
- package/dist/trace/projection-table.d.ts +100 -0
- package/dist/trace/projection-table.js +130 -0
- package/dist/trace/redact.d.ts +54 -0
- package/dist/trace/redact.js +778 -152
- package/dist/trace/self-minted-wire.d.ts +345 -1
- package/dist/trace/self-minted-wire.js +117 -1
- package/dist/trace/wire-projection-faces.d.ts +377 -3
- package/dist/trace/wire-projection-faces.js +164 -1
- package/dist/url-refusal.js +2 -0
- package/dist/web-admin-client/apply-effective.d.ts +12 -0
- package/dist/web-admin-client/apply-effective.js +56 -5
- package/dist/web-admin-client/candidate-gate.d.ts +6 -6
- package/dist/web-admin-client/candidate-gate.js +3 -3
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/facade.js +1 -1
- package/dist/web-admin-client/http-client.js +0 -6
- package/dist/web-admin-client/read-face.js +5 -9
- package/dist/web-admin-client/read-warnings.d.ts +13 -0
- package/dist/web-admin-client/read-warnings.js +10 -0
- package/dist/web-admin-client/skills-mcp.d.ts +3 -0
- package/dist/web-admin-client/skills-mcp.js +11 -9
- package/dist/web-admin-client/types.d.ts +2 -3
- package/dist/workspace-cache.d.ts +35 -0
- package/dist/workspace-cache.js +36 -0
- package/dist/workspace-space.d.ts +3 -2
- package/dist/workspace-space.js +2 -0
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +65 -10
- package/package.json +8 -4
- package/scripts/drain-check-local.mjs +34 -1
- package/scripts/drain-check.mysql.sql +30 -2
- package/scripts/drain-check.pg.sql +29 -2
- package/dist/capabilities/memory-notice.d.ts +0 -138
- package/dist/capabilities/memory-notice.js +0 -64
- package/dist/capabilities/prompt.d.ts +0 -17
- package/dist/capabilities/prompt.js +0 -6
- package/dist/mcp-content-origin.d.ts +0 -34
- package/dist/mcp-content-origin.js +0 -10
- package/dist/tool-axis-words.d.ts +0 -27
- package/dist/tool-axis-words.js +0 -9
- package/dist/wire-name-bound.d.ts +0 -14
- package/dist/wire-name-bound.js +0 -13
|
@@ -111,6 +111,7 @@
|
|
|
111
111
|
*/
|
|
112
112
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
113
113
|
import type { Pool as PgPool } from "pg";
|
|
114
|
+
import type { Logger } from "../observability/logger.js";
|
|
114
115
|
export type SqlDialect = "tidb" | "pg";
|
|
115
116
|
export type SqlRow = Record<string, unknown>;
|
|
116
117
|
/** Normalized statement result: `rows` for SELECTs, `affected` for INSERT/UPDATE/DELETE. */
|
|
@@ -157,7 +158,168 @@ export interface SqlEngineFacts {
|
|
|
157
158
|
readonly isolation: string;
|
|
158
159
|
/** TiDB's session `tidb_txn_mode`; `null` = this engine has no such indicator (NOT "optimistic"). */
|
|
159
160
|
readonly txnMode: "pessimistic" | null;
|
|
161
|
+
/**
|
|
162
|
+
* The largest single row this engine stores, in bytes — the **one** source of that number in this repo. Every
|
|
163
|
+
* row this service writes from a submitted request (the user message in `session_event`, the resume inputs in
|
|
164
|
+
* `checkpoint_ctx`) has to fit it, so the submit admission reads it (`http/request-guards.ts`
|
|
165
|
+
* `refuseSubmitBody`) instead of carrying a copy of the number.
|
|
166
|
+
* · **TiDB** — the effective `txn-entry-size-limit`, read at initialization: the session variable
|
|
167
|
+
* `@@tidb_txn_entry_size_limit` when it is non-zero (TiDB 7.6+; 0 there means "use the config item"), else
|
|
168
|
+
* `performance.txn-entry-size-limit` from `SHOW CONFIG` (the smallest value across TiDB instances: a request
|
|
169
|
+
* may land on any of them). Neither readable (the config read needs the `CONFIG` privilege; older TiDB has no
|
|
170
|
+
* session variable) ⇒ TiDB's own default {@link TIDB_DEFAULT_TXN_ENTRY_SIZE_LIMIT}, recorded through
|
|
171
|
+
* `recordFailOpen("server.sql.tidb-row-cap-unread")` (a per-hit count and one warn line naming both reads).
|
|
172
|
+
* · **`null`** — this engine has **no single-row wall** below the request cap: PostgreSQL (`jsonb` holds 255 MiB)
|
|
173
|
+
* and InnoDB (it has no row-size wall of this kind; its wall is the statement-level one, a different fact:
|
|
174
|
+
* {@link maxPacketBytes}). `null` is the ONLY spelling of "no wall" — an unreadable value is never folded into it.
|
|
175
|
+
* Only two writes translate a row-size refusal into the coded
|
|
176
|
+
* `StoreRowTooLargeError` (`sql-errors.ts`): the checkpoint store's `putCtx` (resume inputs) and `put` (the INSERT of
|
|
177
|
+
* a pending row). Every other write — the checkpoint store's updates (`resolve` / `reopen` / …), the session log —
|
|
178
|
+
* keeps its existing driver error.
|
|
179
|
+
* **Level**: the TiDB config item is per TiDB instance, read as the minimum across instances (so the reading does not depend
|
|
180
|
+
* on which instance a connection landed on); the 7.6+ variable is read as this connection sees it at initialization. Its
|
|
181
|
+
* readers: the submit admission reads it off {@link SqlDriver.facts} (it has no connection in hand); the SQL snapshot-blob cap
|
|
182
|
+
* reads it off the connection that writes the blob ({@link sqlConnectionFacts}). This version does not change how it is read.
|
|
183
|
+
*/
|
|
184
|
+
readonly maxRowBytes: number | null;
|
|
185
|
+
/**
|
|
186
|
+
* The largest single statement the server accepts on **this connection**, in bytes — its session `@@max_allowed_packet`.
|
|
187
|
+
* A second wall, so a second fact (one fact per wall; `null` always and only means "this engine has no such wall").
|
|
188
|
+
* **Level: one physical connection.** The server copies the session value from the global one when the connection is
|
|
189
|
+
* established and never changes it afterwards: after a DBA changes the global value, connections opened later carry the
|
|
190
|
+
* new value and the ones already pooled keep theirs until the pool replaces them. So the reading lives with the connection
|
|
191
|
+
* that took it: read once at that connection's initialization, kept with it, and judged on it.
|
|
192
|
+
* · **MySQL protocol — InnoDB and TiDB alike**: read at connection initialization, in the same place and with the
|
|
193
|
+
* same unreadable disposition as {@link maxRowBytes} on TiDB: the variable unknown / the query failing / a value that
|
|
194
|
+
* is not a positive integer ⇒ the documented default of that server family
|
|
195
|
+
* ({@link PACKET_CAP_UNREAD_LANDING_BYTES}), recorded through `recordFailOpen("server.sql.packet-cap-unread")` (a per-hit
|
|
196
|
+
* count and one warn line naming the reason). Never `null`: on these engines the wall exists, only its size may be unread.
|
|
197
|
+
* · **`null`** — PostgreSQL: the extended protocol has no statement-size wall.
|
|
198
|
+
* Its final judge: the SQL snapshot-blob cap (`plugins/blob-backend.ts` `SqlBlobBackend.putBlob`), which borrows the connection
|
|
199
|
+
* it will write on through {@link connectJudged}, reads this off it ({@link sqlConnectionFacts}), judges, and writes on that
|
|
200
|
+
* same connection — and when it refuses on a connection opened before the DBA raised the wall, that stale connection is
|
|
201
|
+
* replaced and the write judged once more ({@link connectJudged}). On {@link SqlDriver.facts} the value is the most recently
|
|
202
|
+
* initialized connection's reading (the operator read face `GET /v1/diagnostics/wiring` → `sqlEngine.maxPacketBytes`, and
|
|
203
|
+
* the submit admission's early run of the same rule — `http/request-guards.ts` `refuseSubmitBody`: it has no connection in
|
|
204
|
+
* hand, so it pre-judges against the newest reading the pool has — a cached value that moves only when a connection is
|
|
205
|
+
* initialized, so right after a DBA changes the global value it can lag in either direction; the database on the writing
|
|
206
|
+
* connection stays the final judge of a submitted body). Both readers (the blob cap on the borrowed connection's own facts, the admission on the pool's) read the walls
|
|
207
|
+
* — this one and {@link maxRowBytes} — through the one judge {@link sqlWallsOf}, which also says what holds when the facts themselves are absent.
|
|
208
|
+
*/
|
|
209
|
+
readonly maxPacketBytes: number | null;
|
|
210
|
+
/**
|
|
211
|
+
* Where each wall's number came from — the **one** record of "read, or fell back to a documented default", parallel to {@link maxRowBytes} and
|
|
212
|
+
* {@link maxPacketBytes} (see {@link SqlWallSource}). `"reported"` = the database answered at connection initialization (or, for a `null` wall,
|
|
213
|
+
* the engine has no such wall by construction); `"assumed"` = the reading failed and the documented default of the server family stands in for the
|
|
214
|
+
* number (the same two reads that go through `recordFailOpen`). The submit admission and the SQL snapshot-blob cap report it as `wallSource`, so a
|
|
215
|
+
* refusal never presents a default as the database's own limit.
|
|
216
|
+
*/
|
|
217
|
+
readonly wallSources: SqlWallSources;
|
|
160
218
|
}
|
|
219
|
+
/** TiDB's documented default for `performance.txn-entry-size-limit` (6 MiB): the cap a single row (key + value)
|
|
220
|
+
* may reach. Used only when the engine's own reading cannot be had ({@link SqlEngineFacts.maxRowBytes}). */
|
|
221
|
+
export declare const TIDB_DEFAULT_TXN_ENTRY_SIZE_LIMIT = 6291456;
|
|
222
|
+
/**
|
|
223
|
+
* 一份载荷落进库行时,行里**载荷之外**的那部分的余量(字节)—— **按行的形各一只**:行墙只有一堵(`SqlEngineFacts.maxRowBytes`),余量是落进它的那种行的物理,
|
|
224
|
+
* 两种行的余量差两个数量级,借用就会让一个读者的门限偏离它自己那种行能装下的量。
|
|
225
|
+
* · `json` —— 提交体落进的两种行:会话日志里的用户消息(`session_event.payload`:条目把内联图 / 附件 / objective 包上 id 与时间戳)与 durable 审批部署上的续跑输入
|
|
226
|
+
* (`checkpoint_ctx.ctx`:体 + 写者版本 / memoryScope / 两枚读法记号)。余量盖住其余全部:
|
|
227
|
+
* - 包装键与行上的其余列:几百字节(TiDB 7.5.1 实测:体里带一只 6 815 544 字符串的续跑输入行,库报 6 815 845 字节 —— 比那只串多 301 字节,其中约 105 字节是串外面的 JSON 文本);
|
|
228
|
+
* - TiDB 以二进制形存 JSON,每个数组元素 / 对象成员比文本多约 5–11 字节;一份提交体的结构(三只规则桶各 ≤ 1000 条、agents、skills…)在几千个元素以内 ⇒ 几十 KiB。
|
|
229
|
+
* 64 KiB 盖住这两件还有富余;结构超出它的体照样会被库在写的那一刻拒 —— 提交时写续跑输入的那一笔(durable 审批部署)答同一个 413(店的带码拒,`submit-ctx.ts`),
|
|
230
|
+
* 开跑后的写(会话日志的用户消息)按各自的既有失败面。
|
|
231
|
+
* · `blob` —— SQL 快照 blob 的行(`snapshot_blob` / `file_history_blob`:`blob_hash CHAR(64)` 主键 + `byte_len BIGINT` + `created_at DATETIME(3)` + `bytes LONGBLOB`)。
|
|
232
|
+
* TiDB 的单行上限量的是这一行的键值对。键 ≈ 表前缀 `t` + 8 字节表 id + `_r` + 行句柄(非聚簇 8 字节;聚簇时是 CHAR(64) 主键的可比较编码,每 8 字节加 1 字节组标 = 72 字节)
|
|
233
|
+
* ⇒ 至多约 83 字节;值 = 行格式 v2:头 6 字节 + 4 列的列 id 与偏移(大行形各 4 字节 = 32 字节)+ 三列定长数据(哈希 64 + 长度 8 + 时间 8 = 80 字节)+ 可选行校验 5 字节
|
|
234
|
+
* ⇒ 约 123 字节。合计约 206 字节;字节列按原字节存,没有 JSON 的逐元素开销。取 1 KiB = 实需的近 5 倍(与包墙那只语句余量 {@link STATEMENT_ALLOWANCE_BYTES} 同一量级),
|
|
235
|
+
* 真库读数由 db 组 `sql-txn-semantics-integration` ①c 钉(恰在帽上的 blob 真写得进)。
|
|
236
|
+
*
|
|
237
|
+
* 余量是**墙的物理**:每堵墙、每种行一只余量,各只在这里定义一次;两个读者(提交体受理口读 `json`、blob 缺省帽读 `blob`)经 {@link rowWallPayloadBytes} 按行的形取。
|
|
238
|
+
*/
|
|
239
|
+
export declare const ROW_WALL_ALLOWANCE_BYTES: {
|
|
240
|
+
readonly json: number;
|
|
241
|
+
readonly blob: 1024;
|
|
242
|
+
};
|
|
243
|
+
/** 落进行墙的两种行(见 {@link ROW_WALL_ALLOWANCE_BYTES})。 */
|
|
244
|
+
export type RowWallRowShape = keyof typeof ROW_WALL_ALLOWANCE_BYTES;
|
|
245
|
+
/**
|
|
246
|
+
* 一条语句里**载荷之外**的字节余量 —— 固定语句文本 + 表名 + 64 字符哈希 + 长度 + 时间戳 + 行包装(mysql2 真格式化量过:最长表名
|
|
247
|
+
* `file_history_blob` 的 blob INSERT 在 blob 之外 240 字节)。1 KiB 盖住它的 4 倍还多,又不松到压低可用量(16 MiB 包墙下少 1 KiB)。
|
|
248
|
+
* 不扣的话恰在包墙上的载荷整条语句会超出包墙几百字节:放行、库在写那一刻拒。经 {@link packetWallStatementBytes} 被两个读者共读(同一只规则:blob 帽的终判、提交体受理口的提前一跑)。
|
|
249
|
+
*/
|
|
250
|
+
export declare const STATEMENT_ALLOWANCE_BYTES = 1024;
|
|
251
|
+
/** 行墙下一份载荷最多多少字节:`max(0, 行墙 − 这种行的余量)`({@link ROW_WALL_ALLOWANCE_BYTES})。受理口的提交体门限读 `json`、blob 缺省帽的行墙腿读 `blob`。 */
|
|
252
|
+
export declare function rowWallPayloadBytes(maxRowBytes: number, row: RowWallRowShape): number;
|
|
253
|
+
/**
|
|
254
|
+
* 包墙下一条语句里的载荷最多多少字节:`max(0, 包墙 − {@link STATEMENT_ALLOWANCE_BYTES})` —— 包墙这一只规则的**唯一**算式,两个读者:
|
|
255
|
+
* · blob 缺省帽的包墙腿(再按膨胀律折半),包墙取自将要执行写入的那条连接 —— **终判**;
|
|
256
|
+
* · 提交体受理口(量的是转义后的语句字节,{@link escapedStatementBytes}),包墙取自池里最近初始化的那条连接 —— 同一只规则的**提前一跑**
|
|
257
|
+
* (受理时手里没有将要写入的连接;拒 ⇒ 413 在任何副作用之前,收 ⇒ 写入那条连接上的库仍是终判)。
|
|
258
|
+
*/
|
|
259
|
+
export declare function packetWallStatementBytes(maxPacketBytes: number): number;
|
|
260
|
+
/**
|
|
261
|
+
* 一段文本作为**一只字符串字面**进 MySQL 协议语句时占的字节数(不含外层两只引号)—— 店真正发出去的字节,不是文本自己的字节数。
|
|
262
|
+
* 店用 `query(sql, [text])`,mysql2 在客户端把参数格式化进语句(`sql-escaper` 的 `escapeString`):`\0 \b \t \n \r \x1a " ' \` 九个字符各变成两个字符
|
|
263
|
+
* (多一个反斜杠字节),其余字符原样 —— 多字节 UTF-8 不受影响。所以一份 JSON 里引号 / 反斜杠越多,语句越比文本长(上界 2×:每个字符至多多一字节)。
|
|
264
|
+
*
|
|
265
|
+
* 受理口的包墙腿量它(`http/request-guards.ts` `refuseSubmitBody`):门承诺「按池见过的最新包墙读数写不进去的体在任何副作用之前 413」,量的就必须是语句字节。
|
|
266
|
+
* 这是 mysql2 转义表的**镜像**,不是第二份读法:`test/store-row-cap.test.ts` 把它逐字钉在 mysql2 自己的 `escape` 上(`escapedStatementBytes(s) ===
|
|
267
|
+
* Buffer.byteLength(mysql.escape(s)) − 2`,含全码点表扫),mysql2 升级改转义表时那格先红。不直接调 `escape` 取长度,是因为那会为一份 8 MiB 的体再造一份 8–16 MiB 的字符串。
|
|
268
|
+
*/
|
|
269
|
+
export declare function escapedStatementBytes(text: string): number;
|
|
270
|
+
/**
|
|
271
|
+
* The documented default `max_allowed_packet`, per MySQL-protocol engine family — the landing when the live reading cannot be
|
|
272
|
+
* had ({@link SqlEngineFacts.maxPacketBytes}). Closed over the MySQL-protocol engines (an engine added to {@link SqlEngine} is a
|
|
273
|
+
* compile error here until its row is written).
|
|
274
|
+
* · **tidb** — 64 MiB (67 108 864): TiDB's system-variable reference, `max_allowed_packet`, default `67108864`.
|
|
275
|
+
* · **innodb** — 16 MiB (16 777 216): the smaller of the two documented defaults among the servers behind this word — MariaDB
|
|
276
|
+
* 16 MiB (its server-system-variables reference, `max_allowed_packet`, default `16777216`) and MySQL 8.0 64 MiB (its
|
|
277
|
+
* server-system-variables reference, default `67108864`; 5.7 and before shipped 4 MiB, outside the supported set). A landing above
|
|
278
|
+
* the true wall lets through a write the server refuses; below it only refuses early, so the smaller one is the landing.
|
|
279
|
+
*/
|
|
280
|
+
export declare const PACKET_CAP_UNREAD_LANDING_BYTES: {
|
|
281
|
+
readonly tidb: 67108864;
|
|
282
|
+
readonly innodb: 16777216;
|
|
283
|
+
};
|
|
284
|
+
/** 一份写入要装进的两堵墙 —— {@link SqlEngineFacts} 里的那两位(`null` 恒且只表示「这堵墙不存在」)。 */
|
|
285
|
+
export type SqlWalls = Pick<SqlEngineFacts, "maxRowBytes" | "maxPacketBytes">;
|
|
286
|
+
/**
|
|
287
|
+
* 一个墙数字从哪来(上 wire:413 拒体的 `wallSource`)—— **只看「这个数是不是库自己报的」**:
|
|
288
|
+
* · `reported` = 库报的:引擎在连接初始化时读到的(或按构造没有这堵墙:没有 SQL 后端、PostgreSQL、InnoDB 的行墙);
|
|
289
|
+
* · `assumed` = 不是库报的、是受支持引擎里最保守的缺省顶上的:引擎事实还没建立(连是哪个引擎都不知道,{@link SQL_FACTS_ABSENT_WALLS}),
|
|
290
|
+
* 或事实在场但这一堵墙读失败、退回了文档缺省({@link SqlEngineFacts.wallSources} 逐墙记着,登记过的 fail-open)。
|
|
291
|
+
*/
|
|
292
|
+
export type SqlWallSource = "reported" | "assumed";
|
|
293
|
+
/** 两堵墙各自的出处(与 {@link SqlWalls} 同键):事实里一处记录,判官 {@link sqlWallsOf} 原样带出。 */
|
|
294
|
+
export type SqlWallSources = {
|
|
295
|
+
readonly [K in keyof SqlWalls]: SqlWallSource;
|
|
296
|
+
};
|
|
297
|
+
/** {@link sqlWallsOf} 的读数:两堵墙 + 它们各自从哪来(逐墙:一堵读到、另一堵退缺省时,拒哪一堵就报哪一堵的出处)。 */
|
|
298
|
+
export interface SqlWallsReading extends SqlWalls {
|
|
299
|
+
readonly sources: SqlWallSources;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* 一只 SQL 池的**引擎读口**:方言(SQL 文本轴,装配事实,恒在)+ 此刻的引擎事实(`null` = 没建立)。墙的方言只从这里来 —— 与事实同出一只驱动
|
|
303
|
+
* ({@link SqlDriver} 结构上就是它;`facts` 是活的,池重连后随之换)。HTTP 面的读口(`ServiceDeps.sqlEngine`)与店的写前帽(`SqlBlobBackend`)各读本池的这一只。
|
|
304
|
+
*/
|
|
305
|
+
export type SqlEngineReading = Pick<SqlDriver, "dialect" | "facts">;
|
|
306
|
+
/**
|
|
307
|
+
* MySQL 协议方言上**事实缺席**时的墙(池上还没建立过,或最近一次连接初始化被拒:`SqlDriver.facts === null`)。这时连引擎是哪一个都不知道,
|
|
308
|
+
* 每堵墙各取受支持引擎里最矮的一格:行墙 = TiDB 自己的缺省(InnoDB 没有行墙,保守取有墙的那一个),包墙 = 各引擎族文档缺省里最小的那个
|
|
309
|
+
* ({@link PACKET_CAP_UNREAD_LANDING_BYTES})—— 没读到事实时的墙不会比读到任何一个缺省事实时的墙更松。它们是**假定**的墙(两堵的出处都是 `assumed`),
|
|
310
|
+
* 拒句不能把它们说成库报的墙。
|
|
311
|
+
*/
|
|
312
|
+
export declare const SQL_FACTS_ABSENT_WALLS: SqlWallsReading;
|
|
313
|
+
/**
|
|
314
|
+
* 🔴 **此刻一份写入要装进的墙 —— 唯一判官**。两个读者同调它、不各读 `facts`:提交受理口(`http/request-guards.ts` `refuseSubmitBody`)与 SQL 快照 blob 的缺省帽
|
|
315
|
+
* (`plugins/blob-backend.ts` `sqlBlobCapOf`:店的写前判,读的是**将要执行写入的那条连接**的读口 —— 方言 + 它自己那次初始化的事实;受理口读本池驱动的读口)。输入是一只引擎读口({@link SqlEngineReading}:方言与事实同出),一种读法:
|
|
316
|
+
* · 读口缺席 = 没有 SQL 后端 ⇒ 没有墙(「忘了给」读不成这一臂:后端交出了 SQL 池而没给读口 ⇒ `createHttpServer` 起服拒,见 `ServiceDeps.sqlEngine`);
|
|
317
|
+
* · 事实在场 ⇒ 事实里的两位,出处逐墙取事实里记的那一份({@link SqlEngineFacts.wallSources}:读到的 `reported`,读失败退文档缺省的 `assumed`);
|
|
318
|
+
* · 事实缺席(`null`)⇒ 按读口的方言:PG 没有墙(扩展协议没有这两堵墙 —— 方言事实,不随引擎事实缺席);MySQL 协议 ⇒ {@link SQL_FACTS_ABSENT_WALLS}(两堵都 `assumed`;
|
|
319
|
+
* fail-closed:按最保守的墙,不是「没有墙」)。池拒绝初始化本身已在 {@link establishSession} 里响亮报过。
|
|
320
|
+
* 「没有 SQL 后端」与「事实还没建立」是两个可区分的值:前者是读口缺席,后者是 `facts === null`。
|
|
321
|
+
*/
|
|
322
|
+
export declare function sqlWallsOf(engine: SqlEngineReading | undefined): SqlWallsReading;
|
|
161
323
|
/**
|
|
162
324
|
* **数据库自己的钟**(毫秒),两方言各一句 —— 本仓这口钟在 SQL 面的**唯一**铸点([ref] A7 / [ref] /
|
|
163
325
|
* 合并复审 R2 把 S-280 的 nonce 店并进来)。
|
|
@@ -189,7 +351,10 @@ export declare function sqlDbNowMs(db: Pick<SqlDriver, "dialect" | "query">, sub
|
|
|
189
351
|
export interface SqlDriver extends SqlExec {
|
|
190
352
|
readonly dialect: SqlDialect;
|
|
191
353
|
/**
|
|
192
|
-
* 本池上**最近一次连接初始化的结果**(状态按池存,所以共享一条池的二十多只店 driver 报同一份事实)
|
|
354
|
+
* 本池上**最近一次连接初始化的结果**(状态按池存,所以共享一条池的二十多只店 driver 报同一份事实)—— 运维读面的料。
|
|
355
|
+
* 连接级的事实(包墙 `maxPacketBytes`:会话值,随连接不同)在这里是「最近一次初始化的那条连接的读数」—— 池见过的最新读数,只在有连接初始化时才更新(DBA 调了全局值、
|
|
356
|
+
* 还没有连接重新初始化时它仍是旧值):
|
|
357
|
+
* 提交受理口拿它跑同一只规则的**提前一跑**(手里没有将要写入的连接);终判读的是**将要执行那条语句的连接**的事实({@link sqlConnectionFacts})。
|
|
193
358
|
* 三种读数,含义各不相同:
|
|
194
359
|
* · `null`(还没借出过连接)—— 没有可报的东西,**不猜**;
|
|
195
360
|
* · 事实 —— 最近一次初始化**回读复核**过的值。每条池连接首次借出都重跑一次初始化(记忆化按连接身份),
|
|
@@ -201,6 +366,45 @@ export interface SqlDriver extends SqlExec {
|
|
|
201
366
|
readonly facts: SqlEngineFacts | null;
|
|
202
367
|
connect(): Promise<SqlTxConn>;
|
|
203
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* 一条**借出的**连接自己的引擎事实 —— 它的初始化回读到的那一份(包墙 `maxPacketBytes` 是这条连接的会话值)。判一条语句装不装得下的地方
|
|
371
|
+
* 只读这里:借出连接 → 读它的墙 → 判 → 在同一条连接上执行(`plugins/blob-backend.ts` `SqlBlobBackend.putBlob`)。
|
|
372
|
+
* 只认本模块的 `mysqlDriver` / `pgDriver` 的 `connect()` 借出的连接;别的连接(测试替身、包装体)没有经过初始化,墙没人读过 ⇒ **响亮抛**,不猜一个数。
|
|
373
|
+
*/
|
|
374
|
+
export declare function sqlConnectionFacts(conn: SqlTxConn): SqlEngineFacts;
|
|
375
|
+
/** 旧连接被换掉时的运维日志事件名。 */
|
|
376
|
+
export declare const STALE_PACKET_WALL_EVENT = "sql_connection_packet_wall_stale";
|
|
377
|
+
/**
|
|
378
|
+
* 判官的**唯一借出口**:借出将要执行写入的那条连接,按它自己的事实判(`judge` 交回 `undefined` = 装得下,否则交回拒绝)。装得下 ⇒ 交回这条连接
|
|
379
|
+
* (调用方在它上面写、负责 `release()`)。拒绝 ⇒ 这条连接已归还,交回拒绝。
|
|
380
|
+
*
|
|
381
|
+
* **旧连接首次撞墙即自换**:包墙是会话值,连接建立时从全局拷一份、此后不变 —— DBA 调大包墙之后,池里已有的连接仍带旧值,而本仓的 MySQL 协议池
|
|
382
|
+
* 不按空闲回收连接(`tidb-pool.ts` `maxIdle` = 连接上限)。所以一次拒绝若由这条连接的**包墙**定(`byPacketWall(拒绝)`),先在**同一条连接**上读一次
|
|
383
|
+
* `@@global.max_allowed_packet`:
|
|
384
|
+
* · 全局值大于这条连接的读数 ⇒ 它是调墙之前建立的旧连接,这一拒不是判决:**销毁**它(池补新连接)、记一行 {@link STALE_PACKET_WALL_EVENT}(连接标识 / 旧值 / 新值),
|
|
385
|
+
* 再借一条**不过时**的连接**重判一次**;仍拒 ⇒ 交回拒绝。重借时,读全局值之前就已初始化、包墙又小于那个全局值的连接同样销毁记一行(不再问库)——
|
|
386
|
+
* 池里这样的旧连接是有限的(都在读全局值之前建立),一条条换完,下一条就是之后才初始化的连接,它带的是那之后的全局值,直接在它上面判(没有固定的跳过上限);
|
|
387
|
+
* · 全局值不大于(或读不出 —— 证明不了过时,拒是关闭方向)⇒ 这一拒就是判决。读不出分两种:变量不认识 / 不是正整数是库的答案,不记;
|
|
388
|
+
* **查询本身失败**是故障,记一行 {@link GLOBAL_PACKET_WALL_UNREAD_EVENT}(连接标识 / 这条连接的墙 / 错误类)再按拒收 —— 方向不变,只是原因不再蒸发。
|
|
389
|
+
* 只在拒的那一刻多一次往返,装得下的写零额外语句;读与判在同一条连接上。运维日志写不出(logger 抛)不改判决、不漏连接:先销毁、再记,
|
|
390
|
+
* 记的失败交给 {@link recordFailOpen}(`server.sql.packet-wall-log-unwritten`,计数 + 契约行 + 探针,不依赖那只坏掉的 logger)。
|
|
391
|
+
*/
|
|
392
|
+
export declare function connectJudged<R>(db: SqlDriver, judge: (facts: SqlEngineFacts) => R | undefined, byPacketWall: (refusal: R) => boolean, log: Pick<Logger, "warn">): Promise<{
|
|
393
|
+
readonly conn: SqlTxConn;
|
|
394
|
+
readonly refusal?: undefined;
|
|
395
|
+
} | {
|
|
396
|
+
readonly conn?: undefined;
|
|
397
|
+
readonly refusal: R;
|
|
398
|
+
}>;
|
|
399
|
+
/**
|
|
400
|
+
* 守卫租约的**池**:交出去的每一条连接 —— 池上裸语句(`pool.query`)和直接 `pool.getConnection()` 的店 —— 都是 {@link leaseOf} 的守卫租约。
|
|
401
|
+
* mysql2 的 `pool.query` 在内部借连接、跑、归还,本仓够不着那条连接,所以库关掉的连接(上面的 1153 一类)只能照常回池;这里换成**每条语句租一条连接**
|
|
402
|
+
* (`getConnection` → 守卫租约上执行 → 归还,被守卫销毁的不归还)。语句契约不变:参数原样到连接,结果是 mysql2 的 `[rows, fields]` 元组,`{ sql, timeout }` 对象形
|
|
403
|
+
* 一并支持(原样交给连接);池的其余成员(`end` / `execute` / `on` …)原样转给底池,返回底池自身的方法(`on` 之类)返回本包装体 —— 链式调用不会逃出守卫。
|
|
404
|
+
* 生产池(`createTidbPool`)恒是它;mysql2 自己的 `pool.query` 对只读类错误(1290 / 1792 / 1836)的销毁收在同一张表里({@link isConnectionUnusableError}),不丢。
|
|
405
|
+
* 不覆盖 `pool.execute`(预备语句:今天只有任务附件店一处,语句是小定长行,碰不到语句墙)。
|
|
406
|
+
*/
|
|
407
|
+
export declare function createCloseAwarePool(pool: MySqlPool): MySqlPool;
|
|
204
408
|
/** MySQL-protocol driver (TiDB / MySQL / MariaDB — `dialect` is the SQL TEXT axis, `facts.engine` the
|
|
205
409
|
* runtime one). Transaction control uses mysql2's NATIVE methods — the historical call shape the
|
|
206
410
|
* fake-pool unit suites script around. */
|
|
@@ -1,4 +1,61 @@
|
|
|
1
1
|
import { pgSafeJsonStringify, pgProtocolJsonStringify } from "./pg-safe-json.js";
|
|
2
|
+
import { recordFailOpen } from "../observability/fail-open.js";
|
|
3
|
+
import { errorKindOf } from "../observability/err-text.js";
|
|
4
|
+
import { isConnectionUnusableError } from "./sql-errors.js";
|
|
5
|
+
export const TIDB_DEFAULT_TXN_ENTRY_SIZE_LIMIT = 6_291_456;
|
|
6
|
+
export const ROW_WALL_ALLOWANCE_BYTES = { json: 64 * 1024, blob: 1024 };
|
|
7
|
+
export const STATEMENT_ALLOWANCE_BYTES = 1024;
|
|
8
|
+
export function rowWallPayloadBytes(maxRowBytes, row) {
|
|
9
|
+
return Math.max(0, maxRowBytes - ROW_WALL_ALLOWANCE_BYTES[row]);
|
|
10
|
+
}
|
|
11
|
+
export function packetWallStatementBytes(maxPacketBytes) {
|
|
12
|
+
return Math.max(0, maxPacketBytes - STATEMENT_ALLOWANCE_BYTES);
|
|
13
|
+
}
|
|
14
|
+
export function escapedStatementBytes(text) {
|
|
15
|
+
let escaped = 0;
|
|
16
|
+
for (let i = 0; i < text.length; i++) {
|
|
17
|
+
switch (text.charCodeAt(i)) {
|
|
18
|
+
case 0:
|
|
19
|
+
case 8:
|
|
20
|
+
case 9:
|
|
21
|
+
case 10:
|
|
22
|
+
case 13:
|
|
23
|
+
case 26:
|
|
24
|
+
case 34:
|
|
25
|
+
case 39:
|
|
26
|
+
case 92:
|
|
27
|
+
escaped++;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return Buffer.byteLength(text, "utf8") + escaped;
|
|
31
|
+
}
|
|
32
|
+
export const PACKET_CAP_UNREAD_LANDING_BYTES = {
|
|
33
|
+
tidb: 67_108_864,
|
|
34
|
+
innodb: 16_777_216,
|
|
35
|
+
};
|
|
36
|
+
const NO_WALLS = Object.freeze({ maxRowBytes: null, maxPacketBytes: null, sources: Object.freeze({ maxRowBytes: "reported", maxPacketBytes: "reported" }) });
|
|
37
|
+
export const SQL_FACTS_ABSENT_WALLS = Object.freeze({
|
|
38
|
+
maxRowBytes: TIDB_DEFAULT_TXN_ENTRY_SIZE_LIMIT,
|
|
39
|
+
maxPacketBytes: Math.min(...Object.values(PACKET_CAP_UNREAD_LANDING_BYTES)),
|
|
40
|
+
sources: Object.freeze({ maxRowBytes: "assumed", maxPacketBytes: "assumed" }),
|
|
41
|
+
});
|
|
42
|
+
export function sqlWallsOf(engine) {
|
|
43
|
+
if (engine === undefined)
|
|
44
|
+
return NO_WALLS;
|
|
45
|
+
const facts = engine.facts;
|
|
46
|
+
if (facts !== null)
|
|
47
|
+
return { maxRowBytes: facts.maxRowBytes, maxPacketBytes: facts.maxPacketBytes, sources: facts.wallSources };
|
|
48
|
+
switch (engine.dialect) {
|
|
49
|
+
case "pg":
|
|
50
|
+
return NO_WALLS;
|
|
51
|
+
case "tidb":
|
|
52
|
+
return SQL_FACTS_ABSENT_WALLS;
|
|
53
|
+
default: {
|
|
54
|
+
const unhandled = engine.dialect;
|
|
55
|
+
throw new Error(`sql walls: unknown dialect ${String(unhandled)}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
2
59
|
export const SQL_DB_NOW_MS = {
|
|
3
60
|
tidb: "CAST(UNIX_TIMESTAMP(NOW(3)) * 1000 AS SIGNED)",
|
|
4
61
|
pg: "(EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::bigint",
|
|
@@ -29,9 +86,92 @@ const POOL_SESSIONS = new WeakMap();
|
|
|
29
86
|
function poolSession(pool) {
|
|
30
87
|
let st = POOL_SESSIONS.get(pool);
|
|
31
88
|
if (st === undefined)
|
|
32
|
-
POOL_SESSIONS.set(pool, (st = {
|
|
89
|
+
POOL_SESSIONS.set(pool, (st = { connections: new WeakMap(), facts: null }));
|
|
33
90
|
return st;
|
|
34
91
|
}
|
|
92
|
+
const LENT = new WeakMap();
|
|
93
|
+
export function sqlConnectionFacts(conn) {
|
|
94
|
+
return lentRecord(conn).facts;
|
|
95
|
+
}
|
|
96
|
+
function lentRecord(conn) {
|
|
97
|
+
const lent = LENT.get(conn);
|
|
98
|
+
if (lent === undefined) {
|
|
99
|
+
throw new Error("sql-driver: this connection was not lent by mysqlDriver()/pgDriver().connect(), so no connection initialization read its walls — " +
|
|
100
|
+
"borrow the connection a statement will run on from the driver before judging that statement's size");
|
|
101
|
+
}
|
|
102
|
+
return lent;
|
|
103
|
+
}
|
|
104
|
+
let INIT_ORDINAL = 0;
|
|
105
|
+
export const STALE_PACKET_WALL_EVENT = "sql_connection_packet_wall_stale";
|
|
106
|
+
const GLOBAL_PACKET_WALL_UNREAD_EVENT = "sql_connection_packet_wall_global_unread";
|
|
107
|
+
export async function connectJudged(db, judge, byPacketWall, log) {
|
|
108
|
+
let conn = await db.connect();
|
|
109
|
+
try {
|
|
110
|
+
let refusal = judge(sqlConnectionFacts(conn));
|
|
111
|
+
if (refusal === undefined)
|
|
112
|
+
return { conn };
|
|
113
|
+
if (byPacketWall(refusal)) {
|
|
114
|
+
const lent = lentRecord(conn);
|
|
115
|
+
const wall = lent.facts.maxPacketBytes;
|
|
116
|
+
const global = wall === null ? null : await readGlobalPacketWallLogged(lent, log);
|
|
117
|
+
if (wall !== null && global !== null && global > wall) {
|
|
118
|
+
const initializedBefore = INIT_ORDINAL;
|
|
119
|
+
retireStale(lent, global, log);
|
|
120
|
+
conn = await borrowNotStale(db, global, initializedBefore, log);
|
|
121
|
+
refusal = judge(sqlConnectionFacts(conn));
|
|
122
|
+
if (refusal === undefined)
|
|
123
|
+
return { conn };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
conn.release();
|
|
127
|
+
return { refusal };
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
conn.release();
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function retireStale(lent, globalWallBytes, log) {
|
|
135
|
+
lent.destroy();
|
|
136
|
+
warnPacketWall(log, STALE_PACKET_WALL_EVENT, { connection: lent.id, sessionWallBytes: lent.facts.maxPacketBytes, globalWallBytes });
|
|
137
|
+
}
|
|
138
|
+
async function readGlobalPacketWallLogged(lent, log) {
|
|
139
|
+
try {
|
|
140
|
+
return await lent.readGlobalPacketWall();
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
warnPacketWall(log, GLOBAL_PACKET_WALL_UNREAD_EVENT, { connection: lent.id, sessionWallBytes: lent.facts.maxPacketBytes, errKind: errorKindOf(err) });
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function warnPacketWall(log, event, fields) {
|
|
148
|
+
try {
|
|
149
|
+
log.warn(event, fields);
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
recordFailOpen("server.sql.packet-wall-log-unwritten", `event=${event} err=${errorKindOf(err)}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function borrowNotStale(db, globalWallBytes, initializedBefore, log) {
|
|
156
|
+
for (;;) {
|
|
157
|
+
const conn = await db.connect();
|
|
158
|
+
let lent;
|
|
159
|
+
try {
|
|
160
|
+
lent = lentRecord(conn);
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
conn.release();
|
|
164
|
+
throw err;
|
|
165
|
+
}
|
|
166
|
+
const wall = lent.facts.maxPacketBytes;
|
|
167
|
+
if (wall === null || wall >= globalWallBytes || lent.initOrdinal > initializedBefore)
|
|
168
|
+
return conn;
|
|
169
|
+
retireStale(lent, globalWallBytes, log);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function readGlobalMaxAllowedPacket(c) {
|
|
173
|
+
return positiveIntOf(await mysqlVar(c, "SELECT @@global.max_allowed_packet AS v")) ?? null;
|
|
174
|
+
}
|
|
35
175
|
async function mysqlVar(c, sql) {
|
|
36
176
|
try {
|
|
37
177
|
const r = await mysqlQuery(c, sql);
|
|
@@ -50,16 +190,20 @@ function refuseSession(what) {
|
|
|
50
190
|
`Neither is optional: every "SELECT … FOR UPDATE" decision point in this service is a CURRENT read only under them.`);
|
|
51
191
|
}
|
|
52
192
|
async function establishSession(session, pooled, c, init) {
|
|
53
|
-
|
|
54
|
-
|
|
193
|
+
const known = session.connections.get(pooled);
|
|
194
|
+
if (known !== undefined)
|
|
195
|
+
return known;
|
|
55
196
|
try {
|
|
56
|
-
|
|
57
|
-
|
|
197
|
+
const facts = await init(c);
|
|
198
|
+
const initialized = { facts, initOrdinal: ++INIT_ORDINAL };
|
|
199
|
+
session.facts = facts;
|
|
200
|
+
session.connections.set(pooled, initialized);
|
|
201
|
+
return initialized;
|
|
58
202
|
}
|
|
59
203
|
catch (err) {
|
|
60
204
|
const stale = session.facts;
|
|
61
205
|
session.facts = null;
|
|
62
|
-
session.
|
|
206
|
+
session.connections = new WeakMap();
|
|
63
207
|
if (stale !== null)
|
|
64
208
|
console.warn(`[sql-driver] connection initialization REFUSED — SQL engine facts invalidated (was: ${stale ? `${stale.engine} ${stale.version} ${stale.isolation} txnMode=${stale.txnMode ?? "-"}` : "<absent>"}). GET /v1/diagnostics/wiring -> sqlEngine and GET /v1/capabilities -> sql now report ABSENT, which is the honest ` +
|
|
65
209
|
`reading: this pool cannot currently establish the read semantics every "SELECT … FOR UPDATE" in this repo assumes. Cause: ${err.message}`);
|
|
@@ -90,7 +234,143 @@ async function initMySqlSession(c) {
|
|
|
90
234
|
if (isolation !== "REPEATABLE-READ") {
|
|
91
235
|
throw refuseSession(`this session reports isolation "${isolation}" after SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ`);
|
|
92
236
|
}
|
|
93
|
-
|
|
237
|
+
const version = (await mysqlVar(c, "SELECT VERSION() AS v")) ?? "";
|
|
238
|
+
const rowWall = engine === "tidb" ? await readTidbEntrySizeLimit(c) : null;
|
|
239
|
+
const packetWall = await readMaxAllowedPacket(c, engine);
|
|
240
|
+
return {
|
|
241
|
+
engine,
|
|
242
|
+
version,
|
|
243
|
+
isolation,
|
|
244
|
+
txnMode: engine === "tidb" ? "pessimistic" : null,
|
|
245
|
+
maxRowBytes: rowWall === null ? null : rowWall.bytes,
|
|
246
|
+
maxPacketBytes: packetWall.bytes,
|
|
247
|
+
wallSources: { maxRowBytes: rowWall === null ? "reported" : rowWall.source, maxPacketBytes: packetWall.source },
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function positiveIntOf(v) {
|
|
251
|
+
const n = typeof v === "number" ? v : typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v.trim()) : Number.NaN;
|
|
252
|
+
return Number.isSafeInteger(n) && n > 0 ? n : undefined;
|
|
253
|
+
}
|
|
254
|
+
async function readTidbEntrySizeLimit(c) {
|
|
255
|
+
const unread = [];
|
|
256
|
+
try {
|
|
257
|
+
const v = await mysqlVar(c, "SELECT @@tidb_txn_entry_size_limit AS v");
|
|
258
|
+
const n = positiveIntOf(v);
|
|
259
|
+
if (n !== undefined)
|
|
260
|
+
return { bytes: n, source: "reported" };
|
|
261
|
+
unread.push(v === null ? "@@tidb_txn_entry_size_limit is unknown (TiDB before 7.6)" : `@@tidb_txn_entry_size_limit=${JSON.stringify(v)} (0 = use the config item)`);
|
|
262
|
+
}
|
|
263
|
+
catch (err) {
|
|
264
|
+
unread.push(`@@tidb_txn_entry_size_limit: ${err.message}`);
|
|
265
|
+
}
|
|
266
|
+
try {
|
|
267
|
+
const r = await mysqlQuery(c, "SHOW CONFIG WHERE type = 'tidb' AND name = 'performance.txn-entry-size-limit'");
|
|
268
|
+
const values = r.rows.map((row) => positiveIntOf(row.Value ?? row.value)).filter((n) => n !== undefined);
|
|
269
|
+
if (values.length > 0)
|
|
270
|
+
return { bytes: Math.min(...values), source: "reported" };
|
|
271
|
+
unread.push(`SHOW CONFIG returned no readable performance.txn-entry-size-limit (${r.rows.length} row(s))`);
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
unread.push(`SHOW CONFIG: ${err.message}`);
|
|
275
|
+
}
|
|
276
|
+
recordFailOpen("server.sql.tidb-row-cap-unread", `assumed=${TIDB_DEFAULT_TXN_ENTRY_SIZE_LIMIT} ${unread.join("; ")}`);
|
|
277
|
+
return { bytes: TIDB_DEFAULT_TXN_ENTRY_SIZE_LIMIT, source: "assumed" };
|
|
278
|
+
}
|
|
279
|
+
async function readMaxAllowedPacket(c, engine) {
|
|
280
|
+
const landing = PACKET_CAP_UNREAD_LANDING_BYTES[engine];
|
|
281
|
+
let unread;
|
|
282
|
+
try {
|
|
283
|
+
const v = await mysqlVar(c, "SELECT @@max_allowed_packet AS v");
|
|
284
|
+
const n = positiveIntOf(v);
|
|
285
|
+
if (n !== undefined)
|
|
286
|
+
return { bytes: n, source: "reported" };
|
|
287
|
+
unread = v === null ? "@@max_allowed_packet is unknown" : `@@max_allowed_packet=${JSON.stringify(v)} (not a positive integer)`;
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
unread = `@@max_allowed_packet: ${err.message}`;
|
|
291
|
+
}
|
|
292
|
+
recordFailOpen("server.sql.packet-cap-unread", `assumed=${landing} engine=${engine} ${unread}`);
|
|
293
|
+
return { bytes: landing, source: "assumed" };
|
|
294
|
+
}
|
|
295
|
+
const LEASE_STATEMENT_METHODS = new Set(["query", "execute", "beginTransaction", "commit", "rollback"]);
|
|
296
|
+
const GUARDED_LEASES = new WeakSet();
|
|
297
|
+
const BROKEN_LEASES = new WeakMap();
|
|
298
|
+
function leaseOf(raw) {
|
|
299
|
+
if (GUARDED_LEASES.has(raw))
|
|
300
|
+
return raw;
|
|
301
|
+
let destroyed = false;
|
|
302
|
+
const destroy = () => {
|
|
303
|
+
if (destroyed)
|
|
304
|
+
return;
|
|
305
|
+
destroyed = true;
|
|
306
|
+
raw.destroy();
|
|
307
|
+
};
|
|
308
|
+
let turn = Promise.resolve();
|
|
309
|
+
const guard = (run) => {
|
|
310
|
+
const result = turn.then(async () => {
|
|
311
|
+
try {
|
|
312
|
+
return await run();
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
if (isConnectionUnusableError(err)) {
|
|
316
|
+
destroy();
|
|
317
|
+
BROKEN_LEASES.set(lease, { error: err });
|
|
318
|
+
}
|
|
319
|
+
throw err;
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
turn = result.then(() => undefined, () => undefined);
|
|
323
|
+
return result;
|
|
324
|
+
};
|
|
325
|
+
const lease = new Proxy(raw, {
|
|
326
|
+
get(target, prop) {
|
|
327
|
+
const member = Reflect.get(target, prop, target);
|
|
328
|
+
if (typeof member !== "function")
|
|
329
|
+
return member;
|
|
330
|
+
if (prop === "release")
|
|
331
|
+
return () => (destroyed ? undefined : raw.release());
|
|
332
|
+
if (prop === "destroy")
|
|
333
|
+
return destroy;
|
|
334
|
+
if (prop === "rollback")
|
|
335
|
+
return (...args) => guard(async () => (destroyed ? undefined : member.apply(target, args)));
|
|
336
|
+
if (LEASE_STATEMENT_METHODS.has(prop))
|
|
337
|
+
return (...args) => guard(() => member.apply(target, args));
|
|
338
|
+
return (...args) => {
|
|
339
|
+
const result = member.apply(target, args);
|
|
340
|
+
return result === target ? lease : result;
|
|
341
|
+
};
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
GUARDED_LEASES.add(lease);
|
|
345
|
+
return lease;
|
|
346
|
+
}
|
|
347
|
+
export function createCloseAwarePool(pool) {
|
|
348
|
+
const lend = async () => leaseOf(await pool.getConnection());
|
|
349
|
+
const query = async (...args) => {
|
|
350
|
+
const c = await lend();
|
|
351
|
+
try {
|
|
352
|
+
return await c.query(...args);
|
|
353
|
+
}
|
|
354
|
+
finally {
|
|
355
|
+
c.release();
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
const wrapper = new Proxy(pool, {
|
|
359
|
+
get(target, prop) {
|
|
360
|
+
if (prop === "query")
|
|
361
|
+
return query;
|
|
362
|
+
if (prop === "getConnection")
|
|
363
|
+
return lend;
|
|
364
|
+
const member = Reflect.get(target, prop, target);
|
|
365
|
+
if (typeof member !== "function")
|
|
366
|
+
return member;
|
|
367
|
+
return (...args) => {
|
|
368
|
+
const result = member.apply(target, args);
|
|
369
|
+
return result === target ? wrapper : result;
|
|
370
|
+
};
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
return wrapper;
|
|
94
374
|
}
|
|
95
375
|
export function mysqlDriver(pool) {
|
|
96
376
|
const session = poolSession(pool);
|
|
@@ -101,15 +381,28 @@ export function mysqlDriver(pool) {
|
|
|
101
381
|
},
|
|
102
382
|
query: (sql, params) => mysqlQuery(pool, sql, params),
|
|
103
383
|
async connect() {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
384
|
+
const raw = await pool.getConnection();
|
|
385
|
+
const c = leaseOf(raw);
|
|
386
|
+
const { facts, initOrdinal } = await establishSession(session, raw.connection ?? raw, c, initMySqlSession);
|
|
387
|
+
const broken = BROKEN_LEASES.get(c);
|
|
388
|
+
if (broken !== undefined)
|
|
389
|
+
throw broken.error;
|
|
390
|
+
const conn = {
|
|
107
391
|
query: (sql, params) => mysqlQuery(c, sql, params),
|
|
108
392
|
begin: () => c.beginTransaction(),
|
|
109
393
|
commit: () => c.commit(),
|
|
110
394
|
rollback: () => c.rollback(),
|
|
111
395
|
release: () => c.release(),
|
|
112
396
|
};
|
|
397
|
+
const threadId = c.threadId;
|
|
398
|
+
LENT.set(conn, {
|
|
399
|
+
facts,
|
|
400
|
+
initOrdinal,
|
|
401
|
+
id: typeof threadId === "number" ? threadId : null,
|
|
402
|
+
destroy: () => c.destroy(),
|
|
403
|
+
readGlobalPacketWall: () => readGlobalMaxAllowedPacket(c),
|
|
404
|
+
});
|
|
405
|
+
return conn;
|
|
113
406
|
},
|
|
114
407
|
};
|
|
115
408
|
}
|
|
@@ -130,6 +423,9 @@ async function initPgSession(c) {
|
|
|
130
423
|
version: String(ver.rows[0]?.server_version ?? ""),
|
|
131
424
|
isolation,
|
|
132
425
|
txnMode: null,
|
|
426
|
+
maxRowBytes: null,
|
|
427
|
+
maxPacketBytes: null,
|
|
428
|
+
wallSources: { maxRowBytes: "reported", maxPacketBytes: "reported" },
|
|
133
429
|
};
|
|
134
430
|
}
|
|
135
431
|
export function pgDriver(pool) {
|
|
@@ -142,8 +438,9 @@ export function pgDriver(pool) {
|
|
|
142
438
|
query: (sql, params) => pgQuery(pool, sql, params),
|
|
143
439
|
async connect() {
|
|
144
440
|
const c = await pool.connect();
|
|
145
|
-
await establishSession(session, c, c, initPgSession);
|
|
146
|
-
|
|
441
|
+
const { facts, initOrdinal } = await establishSession(session, c, c, initPgSession);
|
|
442
|
+
let destroyed = false;
|
|
443
|
+
const conn = {
|
|
147
444
|
query: (sql, params) => pgQuery(c, sql, params),
|
|
148
445
|
begin: async () => {
|
|
149
446
|
await c.query("BEGIN");
|
|
@@ -154,8 +451,23 @@ export function pgDriver(pool) {
|
|
|
154
451
|
rollback: async () => {
|
|
155
452
|
await c.query("ROLLBACK");
|
|
156
453
|
},
|
|
157
|
-
release: () =>
|
|
454
|
+
release: () => {
|
|
455
|
+
if (!destroyed)
|
|
456
|
+
c.release();
|
|
457
|
+
},
|
|
158
458
|
};
|
|
459
|
+
const pid = c.processID;
|
|
460
|
+
LENT.set(conn, {
|
|
461
|
+
facts,
|
|
462
|
+
initOrdinal,
|
|
463
|
+
id: typeof pid === "number" ? pid : null,
|
|
464
|
+
destroy: () => {
|
|
465
|
+
destroyed = true;
|
|
466
|
+
c.release(true);
|
|
467
|
+
},
|
|
468
|
+
readGlobalPacketWall: async () => null,
|
|
469
|
+
});
|
|
470
|
+
return conn;
|
|
159
471
|
},
|
|
160
472
|
};
|
|
161
473
|
}
|