pipework 0.251.0 → 0.252.1
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/CHANGELOG.md +11 -0
- package/dist/core/config/load.d.ts +2 -0
- package/dist/core/config/load.d.ts.map +1 -1
- package/dist/core/config/load.js +1 -0
- package/dist/core/config/load.js.map +1 -1
- package/dist/core/config/namespace.d.ts +1 -0
- package/dist/core/config/namespace.d.ts.map +1 -1
- package/dist/core/config/schema.d.ts +2 -0
- package/dist/core/config/schema.d.ts.map +1 -1
- package/dist/core/config/schema.js +1 -0
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/surface/types.d.ts +1 -0
- package/dist/core/surface/types.d.ts.map +1 -1
- package/dist/data/db/namespace.d.ts +3 -0
- package/dist/data/db/namespace.d.ts.map +1 -1
- package/dist/data/db/namespace.js +3 -0
- package/dist/data/db/namespace.js.map +1 -1
- package/dist/data/db/pool.d.ts.map +1 -1
- package/dist/data/db/pool.js +6 -1
- package/dist/data/db/pool.js.map +1 -1
- package/dist/data/db/query-label.d.ts +5 -0
- package/dist/data/db/query-label.d.ts.map +1 -0
- package/dist/data/db/query-label.js +11 -0
- package/dist/data/db/query-label.js.map +1 -0
- package/dist/data/db/query-watch.d.ts +21 -0
- package/dist/data/db/query-watch.d.ts.map +1 -0
- package/dist/data/db/query-watch.js +90 -0
- package/dist/data/db/query-watch.js.map +1 -0
- package/dist/data/query/postgres-js/driver.js +1 -1
- package/dist/data/query/postgres-js/driver.js.map +1 -1
- package/dist/data/query/postgres-js/session.d.ts +5 -1
- package/dist/data/query/postgres-js/session.d.ts.map +1 -1
- package/dist/data/query/postgres-js/session.js +16 -11
- package/dist/data/query/postgres-js/session.js.map +1 -1
- package/dist/data/query/utils.d.ts +2 -0
- package/dist/data/query/utils.d.ts.map +1 -1
- package/dist/data/query/utils.js.map +1 -1
- package/dist/infra/credits/schema.d.ts +1 -1
- package/dist/test/plugin.d.ts.map +1 -1
- package/dist/test/plugin.js +10 -4
- package/dist/test/plugin.js.map +1 -1
- package/package.json +4 -3
- package/src/async/jobs/abortable-delay.ts +18 -0
- package/src/async/jobs/claims.ts +52 -0
- package/src/async/jobs/cron.ts +179 -0
- package/src/async/jobs/errors.ts +56 -0
- package/src/async/jobs/exclusion.ts +117 -0
- package/src/async/jobs/execute.ts +219 -0
- package/src/async/jobs/index.ts +10 -0
- package/src/async/jobs/listener.ts +135 -0
- package/src/async/jobs/namespace.ts +20 -0
- package/src/async/jobs/queue-door.ts +44 -0
- package/src/async/jobs/queue.ts +1012 -0
- package/src/async/jobs/run-script.ts +67 -0
- package/src/async/jobs/scheduler.ts +218 -0
- package/src/async/jobs/schedules-table.ts +37 -0
- package/src/async/jobs/serialize-error.ts +48 -0
- package/src/async/jobs/table.ts +191 -0
- package/src/async/pipeline/define.ts +53 -0
- package/src/async/pipeline/errors.ts +35 -0
- package/src/async/pipeline/execute.ts +53 -0
- package/src/async/pipeline/index.ts +13 -0
- package/src/async/pipeline/namespace.ts +12 -0
- package/src/async/pipeline/resume.ts +67 -0
- package/src/async/pipeline/run-steps.ts +98 -0
- package/src/async/pipeline/types.ts +57 -0
- package/src/async/state-machine/define.ts +64 -0
- package/src/async/state-machine/errors.ts +29 -0
- package/src/async/state-machine/index.ts +3 -0
- package/src/async/state-machine/namespace.ts +12 -0
- package/src/async/state-machine/transition.ts +90 -0
- package/src/async/state-machine/types.ts +37 -0
- package/src/async/steps/errors.ts +31 -0
- package/src/async/steps/graph.ts +1214 -0
- package/src/async/steps/hash.ts +40 -0
- package/src/async/steps/index.ts +7 -0
- package/src/async/steps/namespace.ts +7 -0
- package/src/async/steps/table.ts +97 -0
- package/src/async/steps/types.ts +318 -0
- package/src/audit/chain/index.ts +9 -0
- package/src/audit/chain/install.ts +113 -0
- package/src/audit/chain/retire.ts +52 -0
- package/src/audit/chain/verify.ts +257 -0
- package/src/audit/query/cursor.ts +37 -0
- package/src/audit/query/index.ts +9 -0
- package/src/audit/query/query.ts +223 -0
- package/src/audit/schema/audit-record-fields.ts +68 -0
- package/src/audit/schema/audit-record.ts +23 -0
- package/src/auth/auth/audit.ts +31 -0
- package/src/auth/auth/chain.ts +84 -0
- package/src/auth/auth/cookie.ts +136 -0
- package/src/auth/auth/email-links.ts +311 -0
- package/src/auth/auth/guard.ts +128 -0
- package/src/auth/auth/index.ts +18 -0
- package/src/auth/auth/multi-org.ts +337 -0
- package/src/auth/auth/namespace.ts +34 -0
- package/src/auth/auth/parse-expiry.ts +13 -0
- package/src/auth/auth/passwords.ts +110 -0
- package/src/auth/auth/schema.ts +110 -0
- package/src/auth/auth/sessions.ts +565 -0
- package/src/auth/auth/sign-in.ts +156 -0
- package/src/auth/auth/signing-keys.ts +69 -0
- package/src/auth/auth/types.ts +26 -0
- package/src/auth/auth/uuid.ts +10 -0
- package/src/auth/rbac/cache.ts +55 -0
- package/src/auth/rbac/check.ts +30 -0
- package/src/auth/rbac/create.ts +35 -0
- package/src/auth/rbac/index.ts +5 -0
- package/src/auth/rbac/middleware.ts +20 -0
- package/src/auth/rbac/namespace.ts +15 -0
- package/src/auth/rbac/resolve.ts +31 -0
- package/src/auth/rbac/schema.sql +31 -0
- package/src/auth/rbac/seed.ts +67 -0
- package/src/auth/rbac/tables.ts +32 -0
- package/src/auth/rbac/types.ts +65 -0
- package/src/auth/tenant/extract.ts +33 -0
- package/src/auth/tenant/in-tenant.ts +49 -0
- package/src/auth/tenant/index.ts +7 -0
- package/src/auth/tenant/namespace.ts +23 -0
- package/src/auth/tenant/propagate.ts +20 -0
- package/src/auth/tenant/rls.ts +120 -0
- package/src/auth/tenant/scope.ts +33 -0
- package/src/auth/tenant/scoped-db.ts +581 -0
- package/src/auth/tenant/types.ts +14 -0
- package/src/auth/tenant/validate.ts +27 -0
- package/src/cli/commands/add.ts +158 -0
- package/src/cli/commands/alerts.ts +98 -0
- package/src/cli/commands/check.ts +1418 -0
- package/src/cli/commands/codemod.ts +78 -0
- package/src/cli/commands/db.ts +356 -0
- package/src/cli/commands/dev.ts +101 -0
- package/src/cli/commands/generate.ts +75 -0
- package/src/cli/commands/init.ts +36 -0
- package/src/cli/commands/install.ts +28 -0
- package/src/cli/commands/lint.ts +62 -0
- package/src/cli/commands/migrate.ts +132 -0
- package/src/cli/commands/openapi.ts +63 -0
- package/src/cli/commands/remove.ts +72 -0
- package/src/cli/commands/run.ts +50 -0
- package/src/cli/commands/scope.ts +54 -0
- package/src/cli/commands/serve.ts +68 -0
- package/src/cli/commands/shard.ts +31 -0
- package/src/cli/commands/shared/config-pipework-version.ts +28 -0
- package/src/cli/commands/shared/find-config.ts +22 -0
- package/src/cli/commands/shared/load-config.ts +35 -0
- package/src/cli/commands/shared/pnpm-install.ts +95 -0
- package/src/cli/commands/shared/report-removed.ts +8 -0
- package/src/cli/commands/sync.ts +32 -0
- package/src/cli/commands/test.ts +307 -0
- package/src/cli/commands/upgrade.ts +48 -0
- package/src/cli/dev-bootstrap.ts +24 -0
- package/src/cli/errors.ts +10 -0
- package/src/cli/index.ts +303 -0
- package/src/cli/output.ts +17 -0
- package/src/cli/port.ts +15 -0
- package/src/cli/surface-kinds.ts +20 -0
- package/src/client/index.ts +4 -0
- package/src/client/poll.ts +130 -0
- package/src/client/report-fault.ts +119 -0
- package/src/core/config/app-pool.ts +19 -0
- package/src/core/config/aws-env.ts +29 -0
- package/src/core/config/base-dir.ts +24 -0
- package/src/core/config/discover.ts +64 -0
- package/src/core/config/env-resolve.ts +87 -0
- package/src/core/config/env-types.ts +116 -0
- package/src/core/config/env.ts +55 -0
- package/src/core/config/errors.ts +9 -0
- package/src/core/config/import-config.ts +40 -0
- package/src/core/config/index.ts +8 -0
- package/src/core/config/load.ts +417 -0
- package/src/core/config/namespace.ts +14 -0
- package/src/core/config/resolve.ts +195 -0
- package/src/core/config/schema.ts +488 -0
- package/src/core/config/statement-observer.ts +48 -0
- package/src/core/config/ts-inline-hooks.ts +75 -0
- package/src/core/config/ts-register.ts +4 -0
- package/src/core/config/ts-resolve-hooks.ts +101 -0
- package/src/core/errors/base.ts +49 -0
- package/src/core/errors/http.ts +146 -0
- package/src/core/errors/index.ts +2 -0
- package/src/core/errors/namespace.ts +31 -0
- package/src/core/lifecycle/drain.ts +33 -0
- package/src/core/lifecycle/health.ts +72 -0
- package/src/core/lifecycle/index.ts +4 -0
- package/src/core/lifecycle/namespace.ts +7 -0
- package/src/core/lifecycle/startup.ts +102 -0
- package/src/core/lifecycle/types.ts +36 -0
- package/src/core/logging/context.ts +60 -0
- package/src/core/logging/error-chain.ts +68 -0
- package/src/core/logging/index.ts +5 -0
- package/src/core/logging/logger.ts +65 -0
- package/src/core/logging/namespace.ts +16 -0
- package/src/core/logging/proxy.ts +22 -0
- package/src/core/logging/redact-match.ts +24 -0
- package/src/core/logging/types.ts +47 -0
- package/src/core/pipework.ts +566 -0
- package/src/core/runtime/broker.ts +69 -0
- package/src/core/surface/http.ts +133 -0
- package/src/core/surface/index.ts +11 -0
- package/src/core/surface/job-timeout.ts +40 -0
- package/src/core/surface/namespace.ts +13 -0
- package/src/core/surface/script.ts +33 -0
- package/src/core/surface/start.ts +142 -0
- package/src/core/surface/types.ts +225 -0
- package/src/core/surface/validate.ts +88 -0
- package/src/core/surface/worker.ts +528 -0
- package/src/core/validation/connectivity.ts +49 -0
- package/src/core/validation/domain.ts +99 -0
- package/src/core/validation/index.ts +5 -0
- package/src/core/validation/queue-tables.ts +312 -0
- package/src/core/validation/rls-role.ts +138 -0
- package/src/core/validation/startup.ts +51 -0
- package/src/core/validation/surfaces.ts +65 -0
- package/src/core/validation/types.ts +25 -0
- package/src/data/db/advisory-lock.ts +55 -0
- package/src/data/db/aggregates.ts +172 -0
- package/src/data/db/array-elements.ts +111 -0
- package/src/data/db/bulk-set.ts +53 -0
- package/src/data/db/col/index.ts +14 -0
- package/src/data/db/composed.ts +53 -0
- package/src/data/db/db.ts +276 -0
- package/src/data/db/excluded.ts +16 -0
- package/src/data/db/expressions.ts +473 -0
- package/src/data/db/filter.ts +90 -0
- package/src/data/db/function-source.ts +114 -0
- package/src/data/db/identifiers.ts +16 -0
- package/src/data/db/idx/index.ts +9 -0
- package/src/data/db/in-list.ts +49 -0
- package/src/data/db/index.ts +9 -0
- package/src/data/db/insert-split.ts +137 -0
- package/src/data/db/instrumentation.ts +82 -0
- package/src/data/db/maintenance.ts +28 -0
- package/src/data/db/namespace.ts +107 -0
- package/src/data/db/owner-labels.ts +9 -0
- package/src/data/db/pool.ts +187 -0
- package/src/data/db/query-label.ts +13 -0
- package/src/data/db/query-watch.ts +116 -0
- package/src/data/db/raw-client-warning.ts +37 -0
- package/src/data/db/readonly.ts +23 -0
- package/src/data/db/reservation.ts +151 -0
- package/src/data/db/schema-features.ts +14 -0
- package/src/data/db/serializable.ts +83 -0
- package/src/data/db/sql.ts +1 -0
- package/src/data/db/timeouts.ts +76 -0
- package/src/data/db/types.ts +18 -0
- package/src/data/db/unbound.ts +33 -0
- package/src/data/db/values.ts +29 -0
- package/src/data/domain/brand.ts +15 -0
- package/src/data/domain/build-factory.ts +193 -0
- package/src/data/domain/build-schema.ts +161 -0
- package/src/data/domain/build-table.ts +355 -0
- package/src/data/domain/define.ts +239 -0
- package/src/data/domain/external-registry.ts +34 -0
- package/src/data/domain/external.ts +77 -0
- package/src/data/domain/field.ts +279 -0
- package/src/data/domain/index.ts +13 -0
- package/src/data/domain/naming.ts +6 -0
- package/src/data/domain/projections.ts +57 -0
- package/src/data/domain/trace-safe-projection.ts +31 -0
- package/src/data/domain/traits.ts +108 -0
- package/src/data/domain/types.ts +289 -0
- package/src/data/jsonb/composed.ts +18 -0
- package/src/data/jsonb/index.ts +1 -0
- package/src/data/jsonb/namespace.ts +30 -0
- package/src/data/jsonb/query.ts +86 -0
- package/src/data/migrate/append-only-generate.ts +47 -0
- package/src/data/migrate/applied.ts +47 -0
- package/src/data/migrate/apply.ts +309 -0
- package/src/data/migrate/check.ts +119 -0
- package/src/data/migrate/diff.ts +357 -0
- package/src/data/migrate/door-generate.ts +130 -0
- package/src/data/migrate/framework-rls.ts +58 -0
- package/src/data/migrate/generate.ts +201 -0
- package/src/data/migrate/history.ts +215 -0
- package/src/data/migrate/index.ts +9 -0
- package/src/data/migrate/internal-definitions.ts +175 -0
- package/src/data/migrate/post-process.ts +73 -0
- package/src/data/migrate/pragma.ts +73 -0
- package/src/data/migrate/provision-framework.ts +147 -0
- package/src/data/migrate/rls-generate.ts +61 -0
- package/src/data/migrate/run.ts +124 -0
- package/src/data/migrate/safety.ts +167 -0
- package/src/data/migrate/snapshot.ts +368 -0
- package/src/data/migrate/sql-emit.ts +392 -0
- package/src/data/migrate/statements.ts +312 -0
- package/src/data/query/alias.ts +126 -0
- package/src/data/query/batch.ts +8 -0
- package/src/data/query/cache/core/cache.ts +78 -0
- package/src/data/query/cache/core/index.ts +1 -0
- package/src/data/query/cache/core/types.ts +29 -0
- package/src/data/query/cache/readme.md +230 -0
- package/src/data/query/casing.ts +76 -0
- package/src/data/query/collation.ts +11 -0
- package/src/data/query/column-builder.ts +370 -0
- package/src/data/query/column.ts +150 -0
- package/src/data/query/entity.ts +42 -0
- package/src/data/query/errors.ts +33 -0
- package/src/data/query/index.ts +14 -0
- package/src/data/query/logger.ts +47 -0
- package/src/data/query/operations.ts +45 -0
- package/src/data/query/pg-core/alias.ts +12 -0
- package/src/data/query/pg-core/checks.ts +32 -0
- package/src/data/query/pg-core/columns/all.ts +71 -0
- package/src/data/query/pg-core/columns/bigint.ts +110 -0
- package/src/data/query/pg-core/columns/bigserial.ts +128 -0
- package/src/data/query/pg-core/columns/boolean.ts +43 -0
- package/src/data/query/pg-core/columns/char.ts +85 -0
- package/src/data/query/pg-core/columns/cidr.ts +43 -0
- package/src/data/query/pg-core/columns/common.ts +366 -0
- package/src/data/query/pg-core/columns/custom.ts +232 -0
- package/src/data/query/pg-core/columns/date.common.ts +15 -0
- package/src/data/query/pg-core/columns/date.ts +112 -0
- package/src/data/query/pg-core/columns/double-precision.ts +55 -0
- package/src/data/query/pg-core/columns/enum.ts +201 -0
- package/src/data/query/pg-core/columns/index.ts +35 -0
- package/src/data/query/pg-core/columns/inet.ts +43 -0
- package/src/data/query/pg-core/columns/int.common.ts +57 -0
- package/src/data/query/pg-core/columns/integer.ts +53 -0
- package/src/data/query/pg-core/columns/interval.ts +83 -0
- package/src/data/query/pg-core/columns/json.ts +58 -0
- package/src/data/query/pg-core/columns/jsonb.ts +56 -0
- package/src/data/query/pg-core/columns/line.ts +117 -0
- package/src/data/query/pg-core/columns/macaddr.ts +43 -0
- package/src/data/query/pg-core/columns/macaddr8.ts +43 -0
- package/src/data/query/pg-core/columns/numeric.ts +227 -0
- package/src/data/query/pg-core/columns/point.ts +127 -0
- package/src/data/query/pg-core/columns/postgis_extension/geometry.ts +119 -0
- package/src/data/query/pg-core/columns/postgis_extension/utils.ts +47 -0
- package/src/data/query/pg-core/columns/real.ts +58 -0
- package/src/data/query/pg-core/columns/serial.ts +55 -0
- package/src/data/query/pg-core/columns/smallint.ts +53 -0
- package/src/data/query/pg-core/columns/smallserial.ts +60 -0
- package/src/data/query/pg-core/columns/text.ts +67 -0
- package/src/data/query/pg-core/columns/time.ts +72 -0
- package/src/data/query/pg-core/columns/timestamp.ts +163 -0
- package/src/data/query/pg-core/columns/uuid.ts +51 -0
- package/src/data/query/pg-core/columns/varchar.ts +89 -0
- package/src/data/query/pg-core/columns/vector_extension/bit.ts +68 -0
- package/src/data/query/pg-core/columns/vector_extension/halfvec.ts +80 -0
- package/src/data/query/pg-core/columns/vector_extension/sparsevec.ts +67 -0
- package/src/data/query/pg-core/columns/vector_extension/vector.ts +80 -0
- package/src/data/query/pg-core/db.ts +674 -0
- package/src/data/query/pg-core/dialect.ts +1404 -0
- package/src/data/query/pg-core/expressions.ts +25 -0
- package/src/data/query/pg-core/foreign-keys.ts +130 -0
- package/src/data/query/pg-core/index.ts +21 -0
- package/src/data/query/pg-core/indexes.ts +276 -0
- package/src/data/query/pg-core/policies.ts +56 -0
- package/src/data/query/pg-core/primary-keys.ts +62 -0
- package/src/data/query/pg-core/query-builders/count.ts +86 -0
- package/src/data/query/pg-core/query-builders/delete.ts +293 -0
- package/src/data/query/pg-core/query-builders/index.ts +7 -0
- package/src/data/query/pg-core/query-builders/insert.ts +452 -0
- package/src/data/query/pg-core/query-builders/query-builder.ts +123 -0
- package/src/data/query/pg-core/query-builders/query.ts +157 -0
- package/src/data/query/pg-core/query-builders/raw.ts +49 -0
- package/src/data/query/pg-core/query-builders/refresh-materialized-view.ts +108 -0
- package/src/data/query/pg-core/query-builders/select.ts +1346 -0
- package/src/data/query/pg-core/query-builders/select.types.ts +437 -0
- package/src/data/query/pg-core/query-builders/update.ts +626 -0
- package/src/data/query/pg-core/roles.ts +41 -0
- package/src/data/query/pg-core/schema.ts +72 -0
- package/src/data/query/pg-core/sequence.ts +41 -0
- package/src/data/query/pg-core/session.ts +292 -0
- package/src/data/query/pg-core/subquery.ts +46 -0
- package/src/data/query/pg-core/table.ts +252 -0
- package/src/data/query/pg-core/unique-constraint.ts +73 -0
- package/src/data/query/pg-core/utils/array.ts +95 -0
- package/src/data/query/pg-core/utils/index.ts +1 -0
- package/src/data/query/pg-core/utils.ts +104 -0
- package/src/data/query/pg-core/view-base.ts +14 -0
- package/src/data/query/pg-core/view-common.ts +1 -0
- package/src/data/query/pg-core/view.ts +435 -0
- package/src/data/query/pg-core/with-builder.ts +41 -0
- package/src/data/query/postgres-js/README.md +46 -0
- package/src/data/query/postgres-js/array-parser.ts +45 -0
- package/src/data/query/postgres-js/driver-error-boundary.ts +149 -0
- package/src/data/query/postgres-js/driver.ts +163 -0
- package/src/data/query/postgres-js/index.ts +2 -0
- package/src/data/query/postgres-js/session.ts +234 -0
- package/src/data/query/primary-key.ts +11 -0
- package/src/data/query/query-builders/query-builder.ts +19 -0
- package/src/data/query/query-builders/select.types.ts +175 -0
- package/src/data/query/query-promise.ts +35 -0
- package/src/data/query/relations.ts +725 -0
- package/src/data/query/runnable-query.ts +12 -0
- package/src/data/query/selection-proxy.ts +121 -0
- package/src/data/query/session.ts +8 -0
- package/src/data/query/sql/expressions/conditions.ts +741 -0
- package/src/data/query/sql/expressions/index.ts +2 -0
- package/src/data/query/sql/expressions/select.ts +45 -0
- package/src/data/query/sql/functions/aggregate.ts +129 -0
- package/src/data/query/sql/functions/index.ts +2 -0
- package/src/data/query/sql/functions/vector.ts +178 -0
- package/src/data/query/sql/index.ts +3 -0
- package/src/data/query/sql/sql.ts +794 -0
- package/src/data/query/subquery.ts +53 -0
- package/src/data/query/table.ts +208 -0
- package/src/data/query/table.utils.ts +2 -0
- package/src/data/query/tracing-utils.ts +3 -0
- package/src/data/query/tracing.ts +11 -0
- package/src/data/query/utils.ts +357 -0
- package/src/data/query/version.ts +4 -0
- package/src/data/query/view-common.ts +1 -0
- package/src/data/schema/branded.ts +13 -0
- package/src/data/schema/generated/coerce.ts +5 -0
- package/src/data/schema/generated/combinator.ts +6 -0
- package/src/data/schema/generated/encoding.ts +5 -0
- package/src/data/schema/generated/error.ts +6 -0
- package/src/data/schema/generated/format.ts +5 -0
- package/src/data/schema/generated/type-constructor.ts +10 -0
- package/src/data/schema/generated/type.ts +6 -0
- package/src/data/schema/index.ts +6 -0
- package/src/data/schema/json-schema.ts +33 -0
- package/src/data/schema/namespace.ts +55 -0
- package/src/data/schema/parse.ts +39 -0
- package/src/data/schema/types.ts +39 -0
- package/src/data/temporal/append-only.ts +134 -0
- package/src/data/temporal/close.ts +27 -0
- package/src/data/temporal/columns.ts +10 -0
- package/src/data/temporal/definition-queries.ts +70 -0
- package/src/data/temporal/errors.ts +10 -0
- package/src/data/temporal/get-current.ts +22 -0
- package/src/data/temporal/index.ts +9 -0
- package/src/data/temporal/namespace.ts +36 -0
- package/src/data/temporal/query.ts +25 -0
- package/src/data/temporal/resolve.ts +17 -0
- package/src/data/temporal/revise.ts +67 -0
- package/src/data/temporal/types.ts +22 -0
- package/src/data/valve/artifact.ts +33 -0
- package/src/data/valve/contract-diff.ts +21 -0
- package/src/data/valve/cross.ts +57 -0
- package/src/data/valve/crossing-ledger.ts +50 -0
- package/src/data/valve/decision.ts +44 -0
- package/src/data/valve/durable-crossing.ts +52 -0
- package/src/data/valve/execute-crossing.ts +77 -0
- package/src/data/valve/faucet.ts +56 -0
- package/src/data/valve/gate.ts +114 -0
- package/src/data/valve/graph.ts +77 -0
- package/src/data/valve/index.ts +53 -0
- package/src/data/valve/namespace.ts +57 -0
- package/src/data/valve/registry.ts +50 -0
- package/src/data/valve/schema/valve-crossing-fields.ts +23 -0
- package/src/data/valve/schema/valve-crossing.ts +9 -0
- package/src/data/valve/supply.ts +154 -0
- package/src/data/valve/types.ts +143 -0
- package/src/data/vector/columns.ts +27 -0
- package/src/data/vector/index.ts +4 -0
- package/src/data/vector/namespace.ts +33 -0
- package/src/data/vector/query.ts +85 -0
- package/src/data/vector/validate.ts +16 -0
- package/src/data/write/audit/actor.ts +15 -0
- package/src/data/write/audit/audit-columns.ts +18 -0
- package/src/data/write/audit/audit-select.ts +111 -0
- package/src/data/write/audit/bound-transaction.ts +14 -0
- package/src/data/write/audit/cte-compile.ts +32 -0
- package/src/data/write/audit/decode-returning.ts +47 -0
- package/src/data/write/audit/final-select.ts +43 -0
- package/src/data/write/audit/infra-audit.ts +36 -0
- package/src/data/write/audit/primary-key.ts +65 -0
- package/src/data/write/audit/projection.ts +41 -0
- package/src/data/write/audit/read-touches.ts +86 -0
- package/src/data/write/audit/touch-match.ts +78 -0
- package/src/data/write/audit/verb-delete.ts +62 -0
- package/src/data/write/audit/verb-insert.ts +36 -0
- package/src/data/write/audit/verb-select.ts +47 -0
- package/src/data/write/audit/verb-update.ts +60 -0
- package/src/data/write/audit/verb-upsert.ts +104 -0
- package/src/data/write/conflict.ts +43 -0
- package/src/data/write/delete.ts +38 -0
- package/src/data/write/execute.ts +243 -0
- package/src/data/write/index.ts +11 -0
- package/src/data/write/insert.ts +63 -0
- package/src/data/write/state.ts +43 -0
- package/src/data/write/update.ts +54 -0
- package/src/data/write/upsert.ts +58 -0
- package/src/data/write/values.ts +19 -0
- package/src/index.ts +230 -0
- package/src/infra/access-links/code.ts +70 -0
- package/src/infra/access-links/handle.ts +892 -0
- package/src/infra/access-links/index.ts +9 -0
- package/src/infra/access-links/namespace.ts +30 -0
- package/src/infra/access-links/person-check.ts +177 -0
- package/src/infra/access-links/schema.ts +71 -0
- package/src/infra/alerts/async-sources.ts +231 -0
- package/src/infra/alerts/audit.ts +36 -0
- package/src/infra/alerts/beat.ts +123 -0
- package/src/infra/alerts/client-faults.ts +111 -0
- package/src/infra/alerts/faults.ts +156 -0
- package/src/infra/alerts/handle.ts +778 -0
- package/src/infra/alerts/http.ts +192 -0
- package/src/infra/alerts/index.ts +12 -0
- package/src/infra/alerts/infra-sources.ts +180 -0
- package/src/infra/alerts/namespace.ts +81 -0
- package/src/infra/alerts/redact.ts +21 -0
- package/src/infra/alerts/request-faults.ts +41 -0
- package/src/infra/alerts/schema.ts +124 -0
- package/src/infra/alerts/sinks.ts +125 -0
- package/src/infra/alerts/source-options.ts +26 -0
- package/src/infra/alerts/sources.ts +503 -0
- package/src/infra/alerts/subsystem-sources.ts +137 -0
- package/src/infra/audit/emit.ts +87 -0
- package/src/infra/audit/index.ts +2 -0
- package/src/infra/audit/namespace.ts +22 -0
- package/src/infra/audit/schema.sql +35 -0
- package/src/infra/audit/types.ts +18 -0
- package/src/infra/aws/credentials.ts +147 -0
- package/src/infra/aws/sigv4.ts +140 -0
- package/src/infra/cache/create.ts +58 -0
- package/src/infra/cache/entry.ts +81 -0
- package/src/infra/cache/index.ts +4 -0
- package/src/infra/cache/namespace.ts +10 -0
- package/src/infra/cache/tenant.ts +93 -0
- package/src/infra/cache/types.ts +24 -0
- package/src/infra/crawl/audit.ts +35 -0
- package/src/infra/crawl/errors.ts +25 -0
- package/src/infra/crawl/handle.ts +693 -0
- package/src/infra/crawl/index.ts +9 -0
- package/src/infra/crawl/links.ts +160 -0
- package/src/infra/crawl/namespace.ts +36 -0
- package/src/infra/crawl/robots.ts +100 -0
- package/src/infra/crawl/schema.ts +89 -0
- package/src/infra/credit-line/handle.ts +883 -0
- package/src/infra/credit-line/index.ts +6 -0
- package/src/infra/credit-line/namespace.ts +7 -0
- package/src/infra/credit-line/schema.ts +96 -0
- package/src/infra/credits/handle.ts +706 -0
- package/src/infra/credits/index.ts +5 -0
- package/src/infra/credits/namespace.ts +7 -0
- package/src/infra/credits/schema.ts +83 -0
- package/src/infra/email/audit.ts +36 -0
- package/src/infra/email/inbound.ts +622 -0
- package/src/infra/email/index.ts +11 -0
- package/src/infra/email/mail.ts +517 -0
- package/src/infra/email/mime.ts +447 -0
- package/src/infra/email/namespace.ts +22 -0
- package/src/infra/email/providers.ts +111 -0
- package/src/infra/email/schema.ts +96 -0
- package/src/infra/email/sns.ts +200 -0
- package/src/infra/email/unsubscribe.ts +44 -0
- package/src/infra/fetch/address.ts +88 -0
- package/src/infra/fetch/connect-retry.ts +87 -0
- package/src/infra/fetch/handle.ts +329 -0
- package/src/infra/fetch/index.ts +7 -0
- package/src/infra/fetch/namespace.ts +70 -0
- package/src/infra/idempotency/index.ts +3 -0
- package/src/infra/idempotency/middleware.ts +87 -0
- package/src/infra/idempotency/store.ts +92 -0
- package/src/infra/idempotency/types.ts +30 -0
- package/src/infra/join-requests/handle.ts +312 -0
- package/src/infra/join-requests/index.ts +2 -0
- package/src/infra/join-requests/namespace.ts +7 -0
- package/src/infra/join-requests/schema.ts +33 -0
- package/src/infra/outbox/core.ts +165 -0
- package/src/infra/quota/errors.ts +32 -0
- package/src/infra/quota/handle.ts +215 -0
- package/src/infra/quota/index.ts +5 -0
- package/src/infra/quota/namespace.ts +7 -0
- package/src/infra/quota/schema.ts +15 -0
- package/src/infra/storage/backend.ts +34 -0
- package/src/infra/storage/handle.ts +513 -0
- package/src/infra/storage/index.ts +9 -0
- package/src/infra/storage/local.ts +104 -0
- package/src/infra/storage/namespace.ts +13 -0
- package/src/infra/storage/s3.ts +257 -0
- package/src/infra/storage/schema.ts +24 -0
- package/src/infra/support/handle.ts +854 -0
- package/src/infra/support/http.ts +229 -0
- package/src/infra/support/index.ts +7 -0
- package/src/infra/support/namespace.ts +12 -0
- package/src/infra/support/schema.ts +96 -0
- package/src/infra/webhook/inbound.ts +45 -0
- package/src/infra/webhook/index.ts +5 -0
- package/src/infra/webhook/namespace.ts +24 -0
- package/src/infra/webhook/outbound.ts +315 -0
- package/src/infra/webhook/sign.ts +32 -0
- package/src/infra/webhook/verify.ts +82 -0
- package/src/invariants/assert.ts +26 -0
- package/src/invariants/index.ts +1 -0
- package/src/lint/config.ts +56 -0
- package/src/lint/doctrine.ts +163 -0
- package/src/lint/include.ts +97 -0
- package/src/lint/index.ts +3 -0
- package/src/lint/preset.ts +10 -0
- package/src/lint/resolver.ts +218 -0
- package/src/lint/rules/no-reexports.ts +46 -0
- package/src/request/behavior/audited.ts +85 -0
- package/src/request/behavior/cached.ts +62 -0
- package/src/request/behavior/compose.ts +28 -0
- package/src/request/behavior/index.ts +5 -0
- package/src/request/behavior/namespace.ts +16 -0
- package/src/request/behavior/types.ts +26 -0
- package/src/request/behavior/versioned.ts +54 -0
- package/src/request/context/create.ts +103 -0
- package/src/request/context/guard.ts +49 -0
- package/src/request/context/index.ts +4 -0
- package/src/request/context/run-in-transaction.ts +200 -0
- package/src/request/context/store.ts +28 -0
- package/src/request/context/types.ts +50 -0
- package/src/request/di/builder.ts +535 -0
- package/src/request/di/index.ts +8 -0
- package/src/request/di/resolve.ts +271 -0
- package/src/request/di/types.ts +262 -0
- package/src/request/fitting/namespace.ts +7 -0
- package/src/request/fixture/batch.ts +71 -0
- package/src/request/fixture/builder.ts +26 -0
- package/src/request/fixture/errors.ts +10 -0
- package/src/request/fixture/index.ts +8 -0
- package/src/request/fixture/namespace.ts +23 -0
- package/src/request/fixture/paginate.ts +44 -0
- package/src/request/fixture/to-handlers.ts +260 -0
- package/src/request/fixture/types.ts +79 -0
- package/src/request/flow/act-as.ts +78 -0
- package/src/request/flow/namespace.ts +17 -0
- package/src/request/http/error-step.ts +42 -0
- package/src/request/http/file.ts +141 -0
- package/src/request/http/index.ts +4 -0
- package/src/request/http/middleware.ts +141 -0
- package/src/request/http/namespace.ts +5 -0
- package/src/request/http/rate-limit-classes.ts +170 -0
- package/src/request/http/response.ts +82 -0
- package/src/request/http/server.ts +916 -0
- package/src/request/http/sniff.ts +261 -0
- package/src/request/http/types.ts +250 -0
- package/src/request/http/upload.ts +284 -0
- package/src/request/internal/text.ts +6 -0
- package/src/request/openapi/generate.ts +205 -0
- package/src/request/openapi/index.ts +2 -0
- package/src/request/openapi/namespace.ts +7 -0
- package/src/test/auth.ts +13 -0
- package/src/test/auto-setup.ts +45 -0
- package/src/test/context.ts +91 -0
- package/src/test/crawl-fixture.ts +157 -0
- package/src/test/discover-fork.ts +17 -0
- package/src/test/fingerprint.ts +135 -0
- package/src/test/globals.d.ts +7 -0
- package/src/test/index.ts +19 -0
- package/src/test/namespace.ts +87 -0
- package/src/test/plugin.ts +189 -0
- package/src/test/progress.ts +185 -0
- package/src/test/reap-after-run.ts +28 -0
- package/src/test/reap.ts +286 -0
- package/src/test/reset.ts +253 -0
- package/src/test/savepoints.ts +172 -0
- package/src/test/setup.ts +1422 -0
- package/src/test/system-channel.ts +50 -0
- package/src/test/vitest-plugin.ts +142 -0
- package/src/test/vitest-workspace.ts +507 -0
- package/src/test/vitest.ts +333 -0
- package/src/test/watch.ts +105 -0
- package/src/trace/capture/bounded-serializer.ts +146 -0
- package/src/trace/cardinality/analyze.ts +173 -0
- package/src/trace/cardinality/branch-context.ts +214 -0
- package/src/trace/cardinality/check.ts +33 -0
- package/src/trace/cardinality/classify-edge.ts +64 -0
- package/src/trace/cardinality/structural-max.ts +107 -0
- package/src/trace/check/coverage-check.ts +188 -0
- package/src/trace/check/flow-check.ts +103 -0
- package/src/trace/check/flow-step-site.ts +234 -0
- package/src/trace/check/io-pattern.ts +116 -0
- package/src/trace/codemod/add-cardinality.ts +152 -0
- package/src/trace/codemod/run.ts +80 -0
- package/src/trace/entry/child-trace.ts +21 -0
- package/src/trace/entry/close-trace.ts +87 -0
- package/src/trace/entry/finalize-trace.ts +28 -0
- package/src/trace/entry/open-trace.ts +138 -0
- package/src/trace/entry/parent-trace.ts +20 -0
- package/src/trace/entry/parse-traceparent.ts +39 -0
- package/src/trace/entry/process-start.ts +38 -0
- package/src/trace/entry/trace-context.ts +26 -0
- package/src/trace/entry/tracing-enabled.ts +10 -0
- package/src/trace/external/record.ts +195 -0
- package/src/trace/external/report.ts +66 -0
- package/src/trace/namespace.ts +19 -0
- package/src/trace/partition/day.ts +47 -0
- package/src/trace/partition/index.ts +14 -0
- package/src/trace/partition/partition-name.ts +23 -0
- package/src/trace/partition/plan.ts +82 -0
- package/src/trace/partition/schedule.ts +26 -0
- package/src/trace/partition/startup-hook.ts +39 -0
- package/src/trace/partition/sync.ts +154 -0
- package/src/trace/partition/tables.ts +53 -0
- package/src/trace/read/tree.ts +83 -0
- package/src/trace/retain/copy-on-error.ts +76 -0
- package/src/trace/runtime/expire-stale-traces.ts +54 -0
- package/src/trace/runtime/flow-step.ts +147 -0
- package/src/trace/runtime/flush-steps.ts +31 -0
- package/src/trace/runtime/pending-writes.ts +54 -0
- package/src/trace/runtime/step-buffer.ts +298 -0
- package/src/trace/runtime/step-error.ts +21 -0
- package/src/trace/runtime/step-meta.ts +55 -0
- package/src/trace/runtime/thenable.ts +12 -0
- package/src/trace/runtime/truncate-trace.ts +62 -0
- package/src/trace/schema/trace-fields.ts +52 -0
- package/src/trace/schema/trace-retained.ts +22 -0
- package/src/trace/schema/trace-step-fields.ts +44 -0
- package/src/trace/schema/trace-step-retained.ts +25 -0
- package/src/trace/schema/trace-step.ts +18 -0
- package/src/trace/schema/trace.ts +12 -0
- package/src/trace/transformer/apply.ts +79 -0
- package/src/trace/transformer/build-meta-literal.ts +30 -0
- package/src/trace/transformer/find-flow-step-sites.ts +85 -0
- package/src/trace/transformer/inject-flow-step-import.ts +39 -0
- package/src/trace/transformer/transform-error.ts +14 -0
- package/src/trace/transformer/transform-flow-steps.ts +123 -0
- package/src/trace/transformer/wrap-function-declaration.ts +62 -0
- package/src/trace/transformer/wrap-variable-declaration.ts +67 -0
- package/src/workspace/affected.ts +110 -0
- package/src/workspace/changed-files.ts +163 -0
- package/src/workspace/check-deps.ts +213 -0
- package/src/workspace/checksum.ts +20 -0
- package/src/workspace/dependency-graph.ts +67 -0
- package/src/workspace/detect-pipework-copies.ts +93 -0
- package/src/workspace/discover.ts +206 -0
- package/src/workspace/generate.ts +401 -0
- package/src/workspace/index.ts +7 -0
- package/src/workspace/module-imports-pipework.ts +39 -0
- package/src/workspace/module-package-name.ts +12 -0
- package/src/workspace/scrub-git-env.ts +23 -0
- package/src/workspace/source-paths.ts +36 -0
- package/src/workspace/sync.ts +182 -0
- package/dist/REFERENCE.md +0 -1477
- package/dist/infra/access-links/rate-limit.d.ts +0 -10
- package/dist/infra/access-links/rate-limit.d.ts.map +0 -1
- package/dist/infra/access-links/rate-limit.js +0 -28
- package/dist/infra/access-links/rate-limit.js.map +0 -1
- package/dist/infra/email/sigv4.d.ts +0 -24
- package/dist/infra/email/sigv4.d.ts.map +0 -1
- package/dist/infra/email/sigv4.js +0 -55
- package/dist/infra/email/sigv4.js.map +0 -1
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
import type { ResolvedConfig } from './config/load.js'
|
|
2
|
+
import type { ResolvedDatabase } from './config/load.js'
|
|
3
|
+
import { loadConfig as parseConfig } from './config/load.js'
|
|
4
|
+
import type { AcceptReadonly } from '../data/db/readonly.js'
|
|
5
|
+
import type { BlueprintInput } from './config/schema.js'
|
|
6
|
+
import type { EnvDefs, ResolveEnvDefs } from './config/env-types.js'
|
|
7
|
+
import type { ManagedConnection, ConnectionRole } from '../data/db/pool.js'
|
|
8
|
+
import { createManagedConnection } from '../data/db/pool.js'
|
|
9
|
+
import { createReservationPublisher, computeBudget, BUDGET_QUERY, type ConnectionBudget } from '../data/db/reservation.js'
|
|
10
|
+
import { sql } from '../data/db/sql.js'
|
|
11
|
+
import { InvariantViolation } from '../invariants/assert.js'
|
|
12
|
+
import type { Surface, SurfaceContext, SurfaceKind } from './surface/types.js'
|
|
13
|
+
import type { StartResult } from './surface/start.js'
|
|
14
|
+
import { startSurfaces } from './surface/start.js'
|
|
15
|
+
import { runScript } from '../async/jobs/run-script.js'
|
|
16
|
+
import { orchestrateStartup } from './lifecycle/startup.js'
|
|
17
|
+
import type { LifecycleConfig, StartupHook, ShutdownHook } from './lifecycle/types.js'
|
|
18
|
+
import { getBaseLogger } from './logging/index.js'
|
|
19
|
+
import { validateStartup, type ValidationContext } from './validation/startup.js'
|
|
20
|
+
import { ownerSystemChannelWarnings } from './validation/rls-role.js'
|
|
21
|
+
import { createJobContext } from '../request/context/create.js'
|
|
22
|
+
import { runInContext } from '../request/context/store.js'
|
|
23
|
+
|
|
24
|
+
/** The application instance — holds config, connection pools, surfaces, and lifecycle. */
|
|
25
|
+
export interface Manifold<TEnv extends EnvDefs = EnvDefs> {
|
|
26
|
+
/** Resolved configuration derived from the Blueprint passed to createManifold. */
|
|
27
|
+
readonly config: ResolvedConfig
|
|
28
|
+
/** The release this process runs, read from the variable `release.env` names; null when no release is configured or the variable is unset or empty. Written on every trace and on the job row of the worker that ran it. */
|
|
29
|
+
readonly release: string | null
|
|
30
|
+
/** Typed environment variables resolved from the `env` config field. */
|
|
31
|
+
readonly env: Readonly<ResolveEnvDefs<TEnv>>
|
|
32
|
+
/** Database connection pool manager — use `pool.getOrCreate(config.database(name))` outside managed contexts. */
|
|
33
|
+
readonly pool: PoolState
|
|
34
|
+
/** Test isolation lifecycle tracker — used internally by pipework/test. */
|
|
35
|
+
readonly isolation: IsolationState
|
|
36
|
+
/** Connection leak detector — tracks active connections for assertNoLeaks(). */
|
|
37
|
+
readonly connections: ConnectionTracker
|
|
38
|
+
/** Returns the names of all registered surfaces (http, worker, script). */
|
|
39
|
+
surfaceNames(): readonly string[]
|
|
40
|
+
/** Returns a copy of the surface map keyed by surface name. */
|
|
41
|
+
surfaceMap(): Readonly<Record<string, Surface>>
|
|
42
|
+
/**
|
|
43
|
+
* Starts all surfaces and installs SIGTERM/SIGINT handlers. Throws if already started.
|
|
44
|
+
* `options.port` is the port for the http surface that declares none (what `serve --port` / `PORT` set).
|
|
45
|
+
*/
|
|
46
|
+
start(options?: StartOptions): Promise<void>
|
|
47
|
+
/**
|
|
48
|
+
* Runs the startup checks that need no database (domain integrity, surfaces) and throws
|
|
49
|
+
* `StartupValidationError` listing every issue. What `start()` runs first; call it from an
|
|
50
|
+
* app's test to catch what `serve` would refuse.
|
|
51
|
+
*/
|
|
52
|
+
validate(): Promise<void>
|
|
53
|
+
/**
|
|
54
|
+
* Runs pre-shutdown hooks, tells every surface to stop accepting work at once, drains them up to
|
|
55
|
+
* `lifecycle.drainTimeoutMs`, then closes all pools (5s bound). At the deadline the surfaces are forced
|
|
56
|
+
* (open sockets destroyed, in-flight jobs aborted and handed back) and `forced` is true. A SIGTERM/SIGINT
|
|
57
|
+
* handler exits 1 when forced or when this rejects, else 0.
|
|
58
|
+
*/
|
|
59
|
+
stop(): Promise<StopResult>
|
|
60
|
+
/** Runs a callback in a managed job context — the canonical entry point for seed scripts and one-off tasks. */
|
|
61
|
+
seed<T>(fn: () => T | Promise<T>, options?: SeedOptions): Promise<T>
|
|
62
|
+
/**
|
|
63
|
+
* Runs `fn` as a traced process-level flow: its own trace (phase `script`, surfaces `[name]`, job type `name`),
|
|
64
|
+
* opened with a step naming this process (host, pid, release) and closed when `fn` settles. With a tenant, the
|
|
65
|
+
* default database's transaction is bound to the flow. It is what an app uses for work in a standalone script.
|
|
66
|
+
*/
|
|
67
|
+
script<T>(name: string, fn: () => T | Promise<T>, options?: ScriptOptions): Promise<T>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** What {@link Manifold.stop} resolves with: `forced` is true when the drain deadline fired. */
|
|
71
|
+
export interface StopResult {
|
|
72
|
+
readonly forced: boolean
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Options for {@link Manifold.script}. */
|
|
76
|
+
export interface ScriptOptions {
|
|
77
|
+
tenant?: string | null
|
|
78
|
+
auth?: unknown
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Options for {@link Manifold.start}. */
|
|
82
|
+
export interface StartOptions {
|
|
83
|
+
/** The port for the http surface that declares none. */
|
|
84
|
+
port?: number
|
|
85
|
+
/**
|
|
86
|
+
* Start only the surfaces of these kinds (for a worker-only process: `['worker']`). Unset starts
|
|
87
|
+
* every surface. Every surface is still validated; a filter that matches none is a `ConfigError`.
|
|
88
|
+
*/
|
|
89
|
+
kinds?: readonly SurfaceKind[]
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** ALS context the {@link Manifold.seed} callback runs under — tenant scope, auth principal, and job type. */
|
|
93
|
+
export interface SeedOptions {
|
|
94
|
+
tenant?: string | null
|
|
95
|
+
auth?: unknown
|
|
96
|
+
jobType?: string
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Manages database connection pools keyed by database name. */
|
|
100
|
+
export interface PoolState {
|
|
101
|
+
/**
|
|
102
|
+
* Returns existing pool or creates one for this database config and role. With no role the
|
|
103
|
+
* default follows the database's mode: `system` (the platform role, `config.systemUrl`) where
|
|
104
|
+
* `rls.platformRole` is set, `owner` otherwise. The `app` role connects via `config.appUrl`
|
|
105
|
+
* (falling back to `url` when unset). An explicit `'owner'` always gives the owner connection;
|
|
106
|
+
* in platform mode that is for DDL only, and `label` names the caller in the one info line it logs.
|
|
107
|
+
*/
|
|
108
|
+
getOrCreate(config: ResolvedDatabase, role?: ConnectionRole, label?: string): ManagedConnection
|
|
109
|
+
/** How many owner-role connections this pool has created (test overrides excluded). In platform mode a running manifold keeps it at 0. */
|
|
110
|
+
ownerConnectionsCreated(): number
|
|
111
|
+
/**
|
|
112
|
+
* The connections this database's server can still give this process without starving other
|
|
113
|
+
* pipework processes: `max_connections` less the reserved slots, the connections held now, and
|
|
114
|
+
* every other publishing process's unopened reservation. Needs `pool.publishReservation: true` on
|
|
115
|
+
* the databases whose pools should count. Waits for this process's own pending publication first.
|
|
116
|
+
*/
|
|
117
|
+
connectionBudget(name: string): Promise<ConnectionBudget>
|
|
118
|
+
/** Returns pool by name, or undefined if not yet created. */
|
|
119
|
+
get(name: string): ManagedConnection | undefined
|
|
120
|
+
/** True when a test-harness override is registered for this database — collapsed (transaction-isolation) mode, where every role shares the single rolled-back connection. */
|
|
121
|
+
isOverridden(name: string): boolean
|
|
122
|
+
/** Closes all managed connections; with `timeoutSeconds`, queries still running then are cancelled. */
|
|
123
|
+
closeAll(options?: { timeoutSeconds?: number }): Promise<void>
|
|
124
|
+
/** Number of active connection pools. */
|
|
125
|
+
count(): number
|
|
126
|
+
/** Registers a test-mode connection override. getOrCreate() returns overrides before creating new connections. */
|
|
127
|
+
override(name: string, conn: ManagedConnection): void
|
|
128
|
+
/** Removes all test-mode connection overrides. */
|
|
129
|
+
clearOverrides(): void
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Tracks test isolation lifecycle — detects leaked isolation contexts. */
|
|
133
|
+
export interface IsolationState {
|
|
134
|
+
/** Marks the start of an isolation context (e.g. BEGIN in a test). */
|
|
135
|
+
markBegin(): void
|
|
136
|
+
/** Marks the end of an isolation context (e.g. ROLLBACK in a test). */
|
|
137
|
+
markEnd(): void
|
|
138
|
+
/** Throws InvariantViolation if any isolation contexts are still active. */
|
|
139
|
+
assertClean(): void
|
|
140
|
+
/** Returns counts of active, total begins, and total ends. */
|
|
141
|
+
stats(): { active: number; totalBegins: number; totalEnds: number }
|
|
142
|
+
/** Resets all counters — only for test infrastructure. */
|
|
143
|
+
reset(): void
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Tracks active database connections for leak detection. */
|
|
147
|
+
export interface ConnectionTracker {
|
|
148
|
+
/** Records a new active connection with its origin context. */
|
|
149
|
+
track(id: string, name: string, context: string): void
|
|
150
|
+
/** Marks a connection as released. */
|
|
151
|
+
release(id: string): void
|
|
152
|
+
/** Number of currently tracked connections. */
|
|
153
|
+
activeCount(): number
|
|
154
|
+
/** Throws InvariantViolation if active connections exceed maxExpected. */
|
|
155
|
+
assertNoLeaks(maxExpected: number): void
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Creates the Pipework application instance. This is the entry point for every Pipework app.
|
|
160
|
+
* Define in `pipework.config.ts` and export as default.
|
|
161
|
+
*
|
|
162
|
+
* The `env` field declares the app's environment variables — the canonical
|
|
163
|
+
* home for runtime config (ports, service tokens, bucket names, flags) in
|
|
164
|
+
* place of scattered `process.env` reads. Each variable is read once at config
|
|
165
|
+
* load, validated and coerced to its declared type (loud error on a bad or
|
|
166
|
+
* missing-required value), and exposed typed on `manifold.env`.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* const manifold = createManifold({
|
|
170
|
+
* databases: { app: { url: 'DATABASE_URL', testUrl: 'DATABASE_URL_TEST' } },
|
|
171
|
+
* env: {
|
|
172
|
+
* PORT: { type: 'number', defaults: { development: '3000', test: '0' } },
|
|
173
|
+
* S3_BUCKET: { type: 'string', required: true },
|
|
174
|
+
* API_TOKEN: { type: 'string', required: true, sensitive: true },
|
|
175
|
+
* },
|
|
176
|
+
* })
|
|
177
|
+
* manifold.env.PORT // number — from process.env.PORT, or the per-environment default
|
|
178
|
+
* manifold.env.S3_BUCKET // string — startup fails loudly if unset
|
|
179
|
+
* export default manifold
|
|
180
|
+
*/
|
|
181
|
+
export function createManifold<const TEnv extends EnvDefs = EnvDefs>(
|
|
182
|
+
raw: AcceptReadonly<Omit<BlueprintInput, 'env'>> & {
|
|
183
|
+
env?: TEnv | undefined
|
|
184
|
+
surfaces?: Record<string, Surface>
|
|
185
|
+
lifecycle?: LifecycleConfig
|
|
186
|
+
},
|
|
187
|
+
): Manifold<TEnv> {
|
|
188
|
+
const { surfaces: surfacesDef, lifecycle: lifecycleDef, ...blueprintRaw } = raw
|
|
189
|
+
const config = parseConfig(blueprintRaw)
|
|
190
|
+
const pool = createPoolState(config)
|
|
191
|
+
const isolation = createIsolationState()
|
|
192
|
+
const connections = createConnectionTracker()
|
|
193
|
+
const surfaces = surfacesDef ?? {}
|
|
194
|
+
const lifecycleConfig = lifecycleDef ?? {}
|
|
195
|
+
|
|
196
|
+
// The database queue migrations land in: the sole database, or the declared
|
|
197
|
+
// defaultDatabase. Ambiguous multi-DB configs (no default) already fail at
|
|
198
|
+
// `pipework generate`, so skipping there loses nothing.
|
|
199
|
+
const startupContext = (connectivity: boolean): ValidationContext => {
|
|
200
|
+
const names = config.databaseNames()
|
|
201
|
+
const defaultDbName = names.length === 1 ? names[0] : config.raw.defaultDatabase
|
|
202
|
+
return {
|
|
203
|
+
configuredDatabases: names,
|
|
204
|
+
environment: config.environment,
|
|
205
|
+
surfaces,
|
|
206
|
+
defaultDbAvailable: names.length === 1,
|
|
207
|
+
...(connectivity
|
|
208
|
+
? {
|
|
209
|
+
databases: config.databases(),
|
|
210
|
+
defaultDatabase: defaultDbName !== undefined ? config.database(defaultDbName) : undefined,
|
|
211
|
+
}
|
|
212
|
+
: { connectivityCheck: false }),
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let running: StartResult | null = null
|
|
217
|
+
let signalCleanup: (() => void) | null = null
|
|
218
|
+
|
|
219
|
+
const manifold: Manifold<TEnv> = {
|
|
220
|
+
config,
|
|
221
|
+
release: config.release,
|
|
222
|
+
env: config.env as ResolveEnvDefs<TEnv>,
|
|
223
|
+
pool,
|
|
224
|
+
isolation,
|
|
225
|
+
connections,
|
|
226
|
+
|
|
227
|
+
surfaceNames(): readonly string[] {
|
|
228
|
+
return Object.keys(surfaces)
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
surfaceMap(): Readonly<Record<string, Surface>> {
|
|
232
|
+
return { ...surfaces }
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
async start(options?: StartOptions): Promise<void> {
|
|
236
|
+
if (running !== null) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
'[pipework] Manifold is already started.\n\n' +
|
|
239
|
+
' Call stop() before starting again.\n',
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const startupOpts: import('./lifecycle/startup.js').StartupOptions = {}
|
|
244
|
+
if (lifecycleConfig.preStart !== undefined) {
|
|
245
|
+
;(startupOpts as { hooks: readonly StartupHook[] }).hooks = lifecycleConfig.preStart as readonly StartupHook[]
|
|
246
|
+
}
|
|
247
|
+
if (lifecycleConfig.startupTimeoutMs !== undefined) {
|
|
248
|
+
;(startupOpts as { timeoutMs: number }).timeoutMs = lifecycleConfig.startupTimeoutMs
|
|
249
|
+
}
|
|
250
|
+
await orchestrateStartup(manifold, startupOpts)
|
|
251
|
+
|
|
252
|
+
await validateStartup(startupContext(true))
|
|
253
|
+
for (const message of ownerSystemChannelWarnings(config.databases())) getBaseLogger().warn(message)
|
|
254
|
+
|
|
255
|
+
const context: SurfaceContext = manifold
|
|
256
|
+
running = await startSurfaces(context, config, surfaces, {
|
|
257
|
+
...(options?.port === undefined ? {} : { port: options.port }),
|
|
258
|
+
...(options?.kinds === undefined ? {} : { kinds: options.kinds }),
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
signalCleanup = installSignalHandlers(manifold, lifecycleConfig.drainTimeoutMs ?? 30_000)
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
async validate(): Promise<void> {
|
|
265
|
+
await validateStartup(startupContext(false))
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
async seed<T>(fn: () => T | Promise<T>, options?: SeedOptions): Promise<T> {
|
|
269
|
+
const ctx = createJobContext({
|
|
270
|
+
instance: manifold,
|
|
271
|
+
jobType: options?.jobType ?? 'seed',
|
|
272
|
+
auth: options?.auth ?? null,
|
|
273
|
+
tenant: options?.tenant ?? null,
|
|
274
|
+
})
|
|
275
|
+
return runInContext(ctx, fn)
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
async script<T>(name: string, fn: () => T | Promise<T>, options?: ScriptOptions): Promise<T> {
|
|
279
|
+
return runScript(manifold, fn, {
|
|
280
|
+
jobType: name,
|
|
281
|
+
tenant: options?.tenant ?? null,
|
|
282
|
+
auth: options?.auth ?? null,
|
|
283
|
+
process: { phase: 'script', surfaces: [name] },
|
|
284
|
+
})
|
|
285
|
+
},
|
|
286
|
+
|
|
287
|
+
async stop(): Promise<StopResult> {
|
|
288
|
+
const logger = getBaseLogger()
|
|
289
|
+
const deadlineMs = lifecycleConfig.drainTimeoutMs ?? 30_000
|
|
290
|
+
|
|
291
|
+
logger.info({ deadlineMs }, 'Shutdown initiated')
|
|
292
|
+
|
|
293
|
+
if (signalCleanup !== null) {
|
|
294
|
+
signalCleanup()
|
|
295
|
+
signalCleanup = null
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (lifecycleConfig.preShutdown) {
|
|
299
|
+
for (const hook of lifecycleConfig.preShutdown) {
|
|
300
|
+
try {
|
|
301
|
+
logger.info({ hook: hook.name }, 'Running pre-shutdown hook')
|
|
302
|
+
await (hook as ShutdownHook).execute()
|
|
303
|
+
} catch (err) {
|
|
304
|
+
logger.error({ hook: hook.name, err }, 'Pre-shutdown hook failed')
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
let forced = false
|
|
310
|
+
const stopFailure: { failed: boolean; err?: unknown } = { failed: false }
|
|
311
|
+
|
|
312
|
+
if (running !== null) {
|
|
313
|
+
const stopping = running
|
|
314
|
+
logger.info({ surfaces: [...stopping.handles.keys()] }, 'Stopping surfaces')
|
|
315
|
+
const controller = new AbortController()
|
|
316
|
+
const settled = stopping.stop(controller.signal).then(
|
|
317
|
+
() => 'done' as const,
|
|
318
|
+
(err: unknown) => { stopFailure.failed = true; stopFailure.err = err; return 'done' as const },
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
const drained = await raceDelay(settled, deadlineMs)
|
|
322
|
+
if (drained === 'timeout') {
|
|
323
|
+
forced = true
|
|
324
|
+
logger.warn({ label: 'Surface shutdown', deadlineMs }, `Surface shutdown exceeded ${deadlineMs}ms deadline`)
|
|
325
|
+
logger.warn({ deadlineMs }, 'Surface shutdown exceeded deadline — forcing close')
|
|
326
|
+
controller.abort()
|
|
327
|
+
const returned = await raceDelay(settled, FORCE_WAIT_MS)
|
|
328
|
+
if (returned === 'timeout') {
|
|
329
|
+
logger.error(
|
|
330
|
+
{ surfaces: stopping.pending(), waitedMs: FORCE_WAIT_MS },
|
|
331
|
+
'Surfaces still running after forced shutdown; closing pools anyway',
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
running = null
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
logger.info('Closing connection pools')
|
|
339
|
+
await pool.closeAll({ timeoutSeconds: POOL_CLOSE_TIMEOUT_S })
|
|
340
|
+
logger.info('Shutdown complete')
|
|
341
|
+
|
|
342
|
+
if (stopFailure.failed) throw stopFailure.err
|
|
343
|
+
return { forced }
|
|
344
|
+
},
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return manifold
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const FORCE_WAIT_MS = 5_000
|
|
351
|
+
const POOL_CLOSE_TIMEOUT_S = 5
|
|
352
|
+
const EXIT_BACKSTOP_MS = 15_000
|
|
353
|
+
|
|
354
|
+
/** Resolves with `work`'s value, or `'timeout'` after `ms`; the timer never holds the process open. */
|
|
355
|
+
async function raceDelay<T>(work: Promise<T>, ms: number): Promise<T | 'timeout'> {
|
|
356
|
+
let timer: NodeJS.Timeout | undefined
|
|
357
|
+
const timeout = new Promise<'timeout'>((resolve) => {
|
|
358
|
+
timer = setTimeout(() => resolve('timeout'), ms)
|
|
359
|
+
timer.unref()
|
|
360
|
+
})
|
|
361
|
+
try {
|
|
362
|
+
return await Promise.race([work, timeout])
|
|
363
|
+
} finally {
|
|
364
|
+
clearTimeout(timer)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function installSignalHandlers(manifold: Manifold, drainTimeoutMs: number): () => void {
|
|
369
|
+
const logger = getBaseLogger()
|
|
370
|
+
let stopping = false
|
|
371
|
+
|
|
372
|
+
const handler = (signal: string) => {
|
|
373
|
+
if (stopping) return
|
|
374
|
+
stopping = true
|
|
375
|
+
logger.info({ signal }, 'Shutdown signal received')
|
|
376
|
+
|
|
377
|
+
// Backstop: a hang in a pre-shutdown hook or a pool must still end the process.
|
|
378
|
+
const backstop = setTimeout(() => {
|
|
379
|
+
logger.fatal({ signal, backstopMs: drainTimeoutMs + EXIT_BACKSTOP_MS }, 'Shutdown did not finish; exiting')
|
|
380
|
+
process.exit(1)
|
|
381
|
+
}, drainTimeoutMs + EXIT_BACKSTOP_MS)
|
|
382
|
+
backstop.unref()
|
|
383
|
+
|
|
384
|
+
void manifold.stop().then(({ forced }) => {
|
|
385
|
+
process.exit(forced ? 1 : 0)
|
|
386
|
+
}).catch((err) => {
|
|
387
|
+
logger.error({ err }, 'Error during shutdown')
|
|
388
|
+
process.exit(1)
|
|
389
|
+
})
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const sigterm = () => handler('SIGTERM')
|
|
393
|
+
const sigint = () => handler('SIGINT')
|
|
394
|
+
|
|
395
|
+
process.on('SIGTERM', sigterm)
|
|
396
|
+
process.on('SIGINT', sigint)
|
|
397
|
+
|
|
398
|
+
return () => {
|
|
399
|
+
process.removeListener('SIGTERM', sigterm)
|
|
400
|
+
process.removeListener('SIGINT', sigint)
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function createPoolState(resolvedConfig: ResolvedConfig): PoolState {
|
|
405
|
+
const map = new Map<string, ManagedConnection>()
|
|
406
|
+
const overrides = new Map<string, ManagedConnection>()
|
|
407
|
+
let ownerCreated = 0
|
|
408
|
+
const reservations = createReservationPublisher()
|
|
409
|
+
|
|
410
|
+
return {
|
|
411
|
+
getOrCreate(config: ResolvedDatabase, explicitRole?: ConnectionRole, label?: string): ManagedConnection {
|
|
412
|
+
const platform = config.rls?.platformRole !== undefined
|
|
413
|
+
const role: ConnectionRole = explicitRole ?? (platform ? 'system' : 'owner')
|
|
414
|
+
const key = role === 'owner' ? config.name : `${config.name}::${role}`
|
|
415
|
+
|
|
416
|
+
// Role-specific override first; fall back to the base (owner) override so a
|
|
417
|
+
// test running under transaction-isolation keeps every role on the single
|
|
418
|
+
// rolled-back connection. A real app-role connection is only created when no
|
|
419
|
+
// override is registered (i.e. production / database-isolation).
|
|
420
|
+
const overridden = overrides.get(key) ?? overrides.get(config.name)
|
|
421
|
+
if (overridden) return overridden
|
|
422
|
+
|
|
423
|
+
if (platform && explicitRole === 'owner') {
|
|
424
|
+
getBaseLogger().info(
|
|
425
|
+
{ database: config.name, caller: label ?? 'unlabelled' },
|
|
426
|
+
`Owner-role connection requested on platform-mode database "${config.name}" by ${label ?? 'an unlabelled caller'}`,
|
|
427
|
+
)
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const existing = map.get(key)
|
|
431
|
+
if (existing) return existing
|
|
432
|
+
|
|
433
|
+
const roleUrl = role === 'app' ? config.appUrl : role === 'system' ? config.systemUrl : undefined
|
|
434
|
+
const effectiveConfig = roleUrl !== undefined ? { ...config, url: roleUrl } : config
|
|
435
|
+
const publishing = config.pool.publishReservation === true
|
|
436
|
+
const release = publishing ? reservations.reserve(effectiveConfig.url, config.pool.max) : undefined
|
|
437
|
+
const managed = createManagedConnection(
|
|
438
|
+
effectiveConfig,
|
|
439
|
+
() => { map.delete(key); release?.() },
|
|
440
|
+
resolvedConfig.observability,
|
|
441
|
+
publishing ? reservations.poolTag : undefined,
|
|
442
|
+
)
|
|
443
|
+
map.set(key, managed)
|
|
444
|
+
if (role === 'owner') ownerCreated++
|
|
445
|
+
return managed
|
|
446
|
+
},
|
|
447
|
+
|
|
448
|
+
ownerConnectionsCreated(): number {
|
|
449
|
+
return ownerCreated
|
|
450
|
+
},
|
|
451
|
+
|
|
452
|
+
async connectionBudget(name: string): Promise<ConnectionBudget> {
|
|
453
|
+
const config = resolvedConfig.database(name)
|
|
454
|
+
await reservations.settled()
|
|
455
|
+
const rows = await this.getOrCreate(config).drizzle.execute(sql.raw(BUDGET_QUERY))
|
|
456
|
+
const row = rows[0] as unknown as Parameters<typeof computeBudget>[0]
|
|
457
|
+
return computeBudget(row, reservations.id)
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
get(name: string): ManagedConnection | undefined {
|
|
461
|
+
return overrides.get(name) ?? map.get(name)
|
|
462
|
+
},
|
|
463
|
+
|
|
464
|
+
isOverridden(name: string): boolean {
|
|
465
|
+
return overrides.has(name)
|
|
466
|
+
},
|
|
467
|
+
|
|
468
|
+
async closeAll(options?: { timeoutSeconds?: number }): Promise<void> {
|
|
469
|
+
const closing = [...map.values()].map(c => c.close(options))
|
|
470
|
+
await Promise.all(closing)
|
|
471
|
+
await reservations.closeAll()
|
|
472
|
+
overrides.clear()
|
|
473
|
+
},
|
|
474
|
+
|
|
475
|
+
count(): number {
|
|
476
|
+
return map.size + overrides.size
|
|
477
|
+
},
|
|
478
|
+
|
|
479
|
+
override(name: string, conn: ManagedConnection): void {
|
|
480
|
+
overrides.set(name, conn)
|
|
481
|
+
},
|
|
482
|
+
|
|
483
|
+
clearOverrides(): void {
|
|
484
|
+
overrides.clear()
|
|
485
|
+
},
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function createIsolationState(): IsolationState {
|
|
490
|
+
let active = 0
|
|
491
|
+
let totalBegins = 0
|
|
492
|
+
let totalEnds = 0
|
|
493
|
+
|
|
494
|
+
return {
|
|
495
|
+
markBegin() {
|
|
496
|
+
active++
|
|
497
|
+
totalBegins++
|
|
498
|
+
},
|
|
499
|
+
|
|
500
|
+
markEnd() {
|
|
501
|
+
if (active <= 0) {
|
|
502
|
+
throw new InvariantViolation('isolation-end-without-begin', {
|
|
503
|
+
activeIsolationContexts: active,
|
|
504
|
+
totalBegins,
|
|
505
|
+
totalEnds,
|
|
506
|
+
})
|
|
507
|
+
}
|
|
508
|
+
active--
|
|
509
|
+
totalEnds++
|
|
510
|
+
},
|
|
511
|
+
|
|
512
|
+
assertClean() {
|
|
513
|
+
if (active !== 0) {
|
|
514
|
+
throw new InvariantViolation('isolation-context-leak', {
|
|
515
|
+
activeIsolationContexts: active,
|
|
516
|
+
totalBegins,
|
|
517
|
+
totalEnds,
|
|
518
|
+
delta: totalBegins - totalEnds,
|
|
519
|
+
})
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
|
|
523
|
+
stats() {
|
|
524
|
+
return { active, totalBegins, totalEnds }
|
|
525
|
+
},
|
|
526
|
+
|
|
527
|
+
reset() {
|
|
528
|
+
active = 0
|
|
529
|
+
totalBegins = 0
|
|
530
|
+
totalEnds = 0
|
|
531
|
+
},
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function createConnectionTracker(): ConnectionTracker {
|
|
536
|
+
const tracked = new Map<string, { name: string; createdAt: number; context: string }>()
|
|
537
|
+
|
|
538
|
+
return {
|
|
539
|
+
track(id: string, name: string, context: string) {
|
|
540
|
+
tracked.set(id, { name, createdAt: Date.now(), context })
|
|
541
|
+
},
|
|
542
|
+
|
|
543
|
+
release(id: string) {
|
|
544
|
+
tracked.delete(id)
|
|
545
|
+
},
|
|
546
|
+
|
|
547
|
+
activeCount() {
|
|
548
|
+
return tracked.size
|
|
549
|
+
},
|
|
550
|
+
|
|
551
|
+
assertNoLeaks(maxExpected: number) {
|
|
552
|
+
if (tracked.size > maxExpected) {
|
|
553
|
+
throw new InvariantViolation('connection-pool-bounded', {
|
|
554
|
+
active: tracked.size,
|
|
555
|
+
maxExpected,
|
|
556
|
+
connections: [...tracked.entries()].map(([id, c]) => ({
|
|
557
|
+
id,
|
|
558
|
+
name: c.name,
|
|
559
|
+
age_ms: Date.now() - c.createdAt,
|
|
560
|
+
context: c.context,
|
|
561
|
+
})),
|
|
562
|
+
})
|
|
563
|
+
}
|
|
564
|
+
},
|
|
565
|
+
}
|
|
566
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import type { Flow } from '../../request/context/types.js'
|
|
4
|
+
|
|
5
|
+
// The version this physical pipework copy reports. Read from the package.json that
|
|
6
|
+
// sits three levels above this module — correct whether running from `dist/core/
|
|
7
|
+
// runtime/broker.js` (→ dist/../package.json) or `src/core/runtime/broker.ts`
|
|
8
|
+
// under a type-stripping loader (→ repo-root package.json). Falls back to a sentinel
|
|
9
|
+
// if the file can't be resolved (e.g. an esbuild bundle relocates this module); two
|
|
10
|
+
// copies that both fall back compare equal and simply share the slot, which is the
|
|
11
|
+
// desired "N copies behave as one" outcome.
|
|
12
|
+
// Stryker disable all: readVersion runs only at module load (static init); ignoreStatic makes its
|
|
13
|
+
// mutants unreachable. The version it produces is exercised by the runtime() version-guard tests.
|
|
14
|
+
function readVersion(): string {
|
|
15
|
+
try {
|
|
16
|
+
const pkg = JSON.parse(
|
|
17
|
+
readFileSync(new URL('../../../package.json', import.meta.url), 'utf8'),
|
|
18
|
+
) as { version?: string }
|
|
19
|
+
return pkg.version ?? '0.0.0-unknown'
|
|
20
|
+
} catch {
|
|
21
|
+
return '0.0.0-unknown'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Stryker restore all
|
|
25
|
+
|
|
26
|
+
export const VERSION = readVersion()
|
|
27
|
+
|
|
28
|
+
// Cross-realm singleton broker. When a self-contained pipework workspace consumes
|
|
29
|
+
// a shared library that ALSO imports pipework at runtime, pnpm resolves two physical
|
|
30
|
+
// copies of pipework. Each copy's module-level singletons (the request ALS) would
|
|
31
|
+
// otherwise be distinct objects, so a context entered by one copy is invisible to
|
|
32
|
+
// `pipe()` in the other. Pinning the ALS to a process-global slot keyed by a global
|
|
33
|
+
// Symbol makes every physical copy of the SAME version share one AsyncLocalStorage —
|
|
34
|
+
// the property the `link:`-shared-leaf topology needs. Two copies of DIFFERENT
|
|
35
|
+
// versions must not share (their Flow shapes may diverge), so the second one throws
|
|
36
|
+
// an actionable error instead of silently forking.
|
|
37
|
+
// Stryker disable next-line StringLiteral: static module-init constant; ignoreStatic makes the mutant
|
|
38
|
+
// unreachable. The slot's identity is covered by the runtime() broker tests.
|
|
39
|
+
const SLOT = Symbol.for('pipework.runtime')
|
|
40
|
+
|
|
41
|
+
interface RuntimeSlot {
|
|
42
|
+
readonly version: string
|
|
43
|
+
readonly flowStorage: AsyncLocalStorage<Flow>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function runtime(): RuntimeSlot {
|
|
47
|
+
const slots = globalThis as unknown as Record<symbol, RuntimeSlot | undefined>
|
|
48
|
+
const existing = slots[SLOT]
|
|
49
|
+
if (existing !== undefined) {
|
|
50
|
+
if (existing.version !== VERSION) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
'[pipework] Two incompatible pipework versions are loaded in one process:\n\n' +
|
|
53
|
+
` ${existing.version} (already initialized) and ${VERSION} (loading now).\n\n` +
|
|
54
|
+
' A shared library that imports pipework at runtime must resolve the SAME\n' +
|
|
55
|
+
' version as the workspace consuming it. Otherwise their AsyncLocalStorage\n' +
|
|
56
|
+
' contexts and error classes are distinct objects, and a context entered by\n' +
|
|
57
|
+
' one copy is invisible to pipe() in the other (no active context; 403→500).\n\n' +
|
|
58
|
+
' Fix: align the leaf library and the workspace to a single pipework version.\n',
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
return existing
|
|
62
|
+
}
|
|
63
|
+
const fresh: RuntimeSlot = {
|
|
64
|
+
version: VERSION,
|
|
65
|
+
flowStorage: new AsyncLocalStorage<Flow>(),
|
|
66
|
+
}
|
|
67
|
+
slots[SLOT] = fresh
|
|
68
|
+
return fresh
|
|
69
|
+
}
|