pipework 0.252.0 → 0.253.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/CHANGELOG.md +10 -0
- package/dist/infra/support/handle.d.ts +8 -1
- package/dist/infra/support/handle.d.ts.map +1 -1
- package/dist/infra/support/handle.js +9 -2
- package/dist/infra/support/handle.js.map +1 -1
- package/dist/infra/support/namespace.d.ts.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 +869 -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,78 @@
|
|
|
1
|
+
// The `pipework codemod` command. Today it runs one codemod: filling missing
|
|
2
|
+
// `@downstream <kind>` cardinalities (Phase 4a). It uses the same module
|
|
3
|
+
// discovery as `pipework check`, so the codemod's scope matches the corpus
|
|
4
|
+
// the flow / cardinality checks would validate.
|
|
5
|
+
|
|
6
|
+
import { findSourceFiles } from '../../lint/doctrine.js'
|
|
7
|
+
import { runFlowCardinalityCodemod, type FileResult } from '../../trace/codemod/run.js'
|
|
8
|
+
import { info, success, warn } from '../output.js'
|
|
9
|
+
import { resolveModulePaths } from './check.js'
|
|
10
|
+
|
|
11
|
+
export interface CodemodOptions {
|
|
12
|
+
readonly cwd: string
|
|
13
|
+
readonly dryRun: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function codemod(options: CodemodOptions): Promise<void> {
|
|
17
|
+
const { paths: modulePaths } = await resolveModulePaths(options.cwd, { kind: 'all' })
|
|
18
|
+
if (modulePaths.length === 0) {
|
|
19
|
+
success('No source modules — nothing to codemod')
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const files = findSourceFiles(options.cwd, modulePaths)
|
|
24
|
+
if (files.length === 0) {
|
|
25
|
+
success('No TypeScript sources — nothing to codemod')
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
info(options.dryRun ? 'Cardinality codemod (dry run)' : 'Cardinality codemod')
|
|
30
|
+
|
|
31
|
+
const result = runFlowCardinalityCodemod({
|
|
32
|
+
cwd: options.cwd,
|
|
33
|
+
files,
|
|
34
|
+
dryRun: options.dryRun,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
reportFills(result.files)
|
|
38
|
+
reportUnresolved(result.files)
|
|
39
|
+
|
|
40
|
+
const verb = options.dryRun ? 'would update' : 'updated'
|
|
41
|
+
if (result.totalFills > 0) {
|
|
42
|
+
success(
|
|
43
|
+
`Cardinality codemod (${verb} ${String(result.filesChanged)} `
|
|
44
|
+
+ `file${result.filesChanged === 1 ? '' : 's'}, `
|
|
45
|
+
+ `${String(result.totalFills)} edge${result.totalFills === 1 ? '' : 's'} filled)`,
|
|
46
|
+
)
|
|
47
|
+
} else {
|
|
48
|
+
success('Cardinality codemod (no fillable edges)')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (result.totalUnresolved > 0) {
|
|
52
|
+
warn(
|
|
53
|
+
`Cardinality codemod: ${String(result.totalUnresolved)} edge`
|
|
54
|
+
+ `${result.totalUnresolved === 1 ? '' : 's'} need human attention `
|
|
55
|
+
+ `(see "unresolved" output above)`,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function reportFills(files: readonly FileResult[]): void {
|
|
61
|
+
for (const fr of files) {
|
|
62
|
+
if (fr.fills.length === 0) continue
|
|
63
|
+
info(` ${fr.file} (${String(fr.fills.length)} filled)`)
|
|
64
|
+
for (const fill of fr.fills) {
|
|
65
|
+
info(` ${String(fill.line)}: @downstream ${fill.target} ${fill.kind}`)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function reportUnresolved(files: readonly FileResult[]): void {
|
|
71
|
+
for (const fr of files) {
|
|
72
|
+
if (fr.unresolved.length === 0) continue
|
|
73
|
+
warn(` ${fr.file} (${String(fr.unresolved.length)} unresolved)`)
|
|
74
|
+
for (const u of fr.unresolved) {
|
|
75
|
+
warn(` ${String(u.line)}: @downstream ${u.target} — ${u.reason}`)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto'
|
|
2
|
+
import { resolve, join } from 'node:path'
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs'
|
|
4
|
+
import { bold, info, success, error as logError, warn } from '../output.js'
|
|
5
|
+
import { loadConfig } from './shared/load-config.js'
|
|
6
|
+
import type { Blueprint, DatabaseConfig } from '../../core/config/schema.js'
|
|
7
|
+
|
|
8
|
+
export interface DbOptions {
|
|
9
|
+
readonly cwd: string
|
|
10
|
+
readonly subcommand: string | undefined
|
|
11
|
+
readonly db?: string | undefined
|
|
12
|
+
readonly test?: boolean | undefined
|
|
13
|
+
readonly confirm?: boolean | undefined
|
|
14
|
+
readonly adminUrl?: string | undefined
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function db(opts: DbOptions): Promise<void> {
|
|
18
|
+
switch (opts.subcommand) {
|
|
19
|
+
case 'setup':
|
|
20
|
+
await setup(opts)
|
|
21
|
+
break
|
|
22
|
+
case 'teardown':
|
|
23
|
+
await teardown(opts)
|
|
24
|
+
break
|
|
25
|
+
case 'reset':
|
|
26
|
+
await teardown(opts)
|
|
27
|
+
await setup(opts)
|
|
28
|
+
break
|
|
29
|
+
default: {
|
|
30
|
+
const sub = opts.subcommand ?? '(none)'
|
|
31
|
+
logError('Unknown db subcommand: ' + sub)
|
|
32
|
+
process.stderr.write('\n Usage: ' + bold('pipework db <setup|teardown|reset>') + '\n\n')
|
|
33
|
+
process.stderr.write(' setup Create databases, roles, extensions, run migrations\n')
|
|
34
|
+
process.stderr.write(' setup --test Create test database with isolated credentials\n')
|
|
35
|
+
process.stderr.write(' teardown Drop databases and roles\n')
|
|
36
|
+
process.stderr.write(' reset Teardown + setup\n\n')
|
|
37
|
+
process.exit(1)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function setup(opts: DbOptions): Promise<void> {
|
|
43
|
+
{
|
|
44
|
+
const { config } = await loadConfig(resolve(opts.cwd))
|
|
45
|
+
const databases = filterDatabases(config, opts.db)
|
|
46
|
+
|
|
47
|
+
for (const [name, dbConfig] of databases) {
|
|
48
|
+
info('Setting up database: ' + name)
|
|
49
|
+
|
|
50
|
+
const adminUrl = resolveAdminUrl(opts, dbConfig)
|
|
51
|
+
if (adminUrl === null) {
|
|
52
|
+
const envName = dbConfig.adminUrl ?? 'ADMIN_DATABASE_URL'
|
|
53
|
+
logError('No admin URL for database "' + name + '". Set ' + envName + ' or pass --admin-url.')
|
|
54
|
+
process.exit(1)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const isTest = opts.test === true
|
|
58
|
+
const dbName = isTest ? name + '_test' : name
|
|
59
|
+
const ownerRole = name + '_owner'
|
|
60
|
+
const runtimeRole = name + '_app'
|
|
61
|
+
const ownerPassword = randomBytes(16).toString('hex')
|
|
62
|
+
const runtimePassword = randomBytes(16).toString('hex')
|
|
63
|
+
const ownerUrl = buildConnectionUrl(adminUrl, dbName, ownerRole, ownerPassword)
|
|
64
|
+
const runtimeUrl = buildConnectionUrl(adminUrl, dbName, runtimeRole, runtimePassword)
|
|
65
|
+
const ownerEnvVar = isTest ? dbConfig.testUrl : dbConfig.url
|
|
66
|
+
const runtimeEnvVar = isTest ? dbConfig.appTestUrl : dbConfig.appUrl
|
|
67
|
+
// Platform mode: the platform role is named in config (generated policies
|
|
68
|
+
// name it), created here like the runtime role, and written to systemUrl.
|
|
69
|
+
const platformRole = dbConfig.rls?.platformRole
|
|
70
|
+
const platformPassword = randomBytes(16).toString('hex')
|
|
71
|
+
const platformUrl = platformRole !== undefined ? buildConnectionUrl(adminUrl, dbName, platformRole, platformPassword) : undefined
|
|
72
|
+
const platformEnvVar = isTest ? dbConfig.systemTestUrl : dbConfig.systemUrl
|
|
73
|
+
|
|
74
|
+
let adminClient: AdminClient | null = null
|
|
75
|
+
try {
|
|
76
|
+
adminClient = await connectAdmin(adminUrl)
|
|
77
|
+
|
|
78
|
+
await ensureRole(adminClient, ownerRole, ownerPassword, { bypassRls: true })
|
|
79
|
+
await ensureRole(adminClient, runtimeRole, runtimePassword, { bypassRls: false })
|
|
80
|
+
if (platformRole !== undefined) await ensureRole(adminClient, platformRole, platformPassword, { bypassRls: false })
|
|
81
|
+
await ensureDatabase(adminClient, dbName, ownerRole)
|
|
82
|
+
await grantConnect(adminClient, dbName, runtimeRole)
|
|
83
|
+
if (platformRole !== undefined) await grantConnect(adminClient, dbName, platformRole)
|
|
84
|
+
|
|
85
|
+
// Extensions and the runtime grants run as the owner so the database
|
|
86
|
+
// objects (and the owner-scoped default privileges) belong to the owner.
|
|
87
|
+
const ownerClient = await connectAdmin(ownerUrl)
|
|
88
|
+
try {
|
|
89
|
+
if (dbConfig.extensions !== undefined) {
|
|
90
|
+
for (const ext of dbConfig.extensions) {
|
|
91
|
+
await ensureExtension(ownerClient, ext)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const stmt of buildRuntimeGrants('public', ownerRole, runtimeRole)) {
|
|
95
|
+
await ownerClient.query(stmt)
|
|
96
|
+
}
|
|
97
|
+
// The platform role gets the runtime role's privileges; which rows it
|
|
98
|
+
// sees is the policies' business (a door, or none).
|
|
99
|
+
if (platformRole !== undefined) {
|
|
100
|
+
for (const stmt of buildRuntimeGrants('public', ownerRole, platformRole)) {
|
|
101
|
+
await ownerClient.query(stmt)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} finally {
|
|
105
|
+
await ownerClient.close()
|
|
106
|
+
}
|
|
107
|
+
info('Granted runtime DML to role: ' + runtimeRole)
|
|
108
|
+
if (platformRole !== undefined) info('Granted runtime DML to platform role: ' + platformRole)
|
|
109
|
+
|
|
110
|
+
success('Database "' + dbName + '" ready (owner: ' + ownerRole + ', runtime: ' + runtimeRole + ')')
|
|
111
|
+
|
|
112
|
+
if (ownerEnvVar !== undefined) {
|
|
113
|
+
writeEnvVar(opts.cwd, ownerEnvVar, ownerUrl)
|
|
114
|
+
success('Wrote ' + ownerEnvVar + ' to .env')
|
|
115
|
+
}
|
|
116
|
+
if (runtimeEnvVar !== undefined) {
|
|
117
|
+
writeEnvVar(opts.cwd, runtimeEnvVar, runtimeUrl)
|
|
118
|
+
success('Wrote ' + runtimeEnvVar + ' to .env')
|
|
119
|
+
}
|
|
120
|
+
if (platformUrl !== undefined && platformEnvVar !== undefined) {
|
|
121
|
+
writeEnvVar(opts.cwd, platformEnvVar, platformUrl)
|
|
122
|
+
success('Wrote ' + platformEnvVar + ' to .env')
|
|
123
|
+
}
|
|
124
|
+
if (runtimeEnvVar === undefined) {
|
|
125
|
+
warn('No appUrl configured for "' + name + '" — runtime would fall back to the owner connection and RLS would be inert. Set appUrl/appTestUrl in the database config to enable role separation.')
|
|
126
|
+
}
|
|
127
|
+
} catch (err) {
|
|
128
|
+
logError('Failed to setup "' + name + '": ' + (err instanceof Error ? err.message : String(err)))
|
|
129
|
+
process.exit(1)
|
|
130
|
+
} finally {
|
|
131
|
+
if (adminClient !== null) {
|
|
132
|
+
await adminClient.close()
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
success('Database setup complete')
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function teardown(opts: DbOptions): Promise<void> {
|
|
142
|
+
{
|
|
143
|
+
const { config } = await loadConfig(resolve(opts.cwd))
|
|
144
|
+
const databases = filterDatabases(config, opts.db)
|
|
145
|
+
|
|
146
|
+
if (config.environment === 'production' && opts.confirm !== true) {
|
|
147
|
+
logError('Teardown in production requires --confirm flag.')
|
|
148
|
+
process.exit(1)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
for (const [name, dbConfig] of databases) {
|
|
152
|
+
const adminUrl = resolveAdminUrl(opts, dbConfig)
|
|
153
|
+
if (adminUrl === null) {
|
|
154
|
+
warn('No admin URL for database "' + name + '" — skipping teardown')
|
|
155
|
+
continue
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let adminClient: AdminClient | null = null
|
|
159
|
+
try {
|
|
160
|
+
adminClient = await connectAdmin(adminUrl)
|
|
161
|
+
|
|
162
|
+
const dbName = name
|
|
163
|
+
const testDbName = name + '_test'
|
|
164
|
+
const ownerRole = name + '_owner'
|
|
165
|
+
const runtimeRole = name + '_app'
|
|
166
|
+
|
|
167
|
+
// Databases first: dropping them removes the in-database grants and
|
|
168
|
+
// owner-scoped default privileges, so the roles drop cleanly afterwards.
|
|
169
|
+
await dropDatabaseIfExists(adminClient, testDbName)
|
|
170
|
+
await dropDatabaseIfExists(adminClient, dbName)
|
|
171
|
+
await dropRoleIfExists(adminClient, runtimeRole)
|
|
172
|
+
if (dbConfig.rls?.platformRole !== undefined) await dropRoleIfExists(adminClient, dbConfig.rls.platformRole)
|
|
173
|
+
await dropRoleIfExists(adminClient, ownerRole)
|
|
174
|
+
|
|
175
|
+
success('Torn down: ' + name)
|
|
176
|
+
} catch (err) {
|
|
177
|
+
logError('Failed to teardown "' + name + '": ' + (err instanceof Error ? err.message : String(err)))
|
|
178
|
+
} finally {
|
|
179
|
+
if (adminClient !== null) {
|
|
180
|
+
await adminClient.close()
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
success('Database teardown complete')
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function filterDatabases(config: Blueprint, dbFilter?: string): Array<[string, DatabaseConfig]> {
|
|
190
|
+
const entries = Object.entries(config.databases)
|
|
191
|
+
if (dbFilter !== undefined) {
|
|
192
|
+
const filtered = entries.filter(([name]) => name === dbFilter)
|
|
193
|
+
if (filtered.length === 0) {
|
|
194
|
+
logError('Database "' + dbFilter + '" not found in config. Available: ' + entries.map(([n]) => n).join(', '))
|
|
195
|
+
process.exit(1)
|
|
196
|
+
}
|
|
197
|
+
return filtered
|
|
198
|
+
}
|
|
199
|
+
return entries
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function resolveAdminUrl(opts: DbOptions, dbConfig: DatabaseConfig): string | null {
|
|
203
|
+
if (opts.adminUrl !== undefined) return opts.adminUrl
|
|
204
|
+
if (dbConfig.adminUrl !== undefined) {
|
|
205
|
+
const fromEnv = process.env[dbConfig.adminUrl]
|
|
206
|
+
if (fromEnv !== undefined && fromEnv !== '') return fromEnv
|
|
207
|
+
}
|
|
208
|
+
const fallback = process.env['ADMIN_DATABASE_URL']
|
|
209
|
+
if (fallback !== undefined && fallback !== '') return fallback
|
|
210
|
+
return null
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function buildConnectionUrl(adminUrl: string, dbName: string, role: string, password: string): string {
|
|
214
|
+
try {
|
|
215
|
+
const url = new URL(adminUrl)
|
|
216
|
+
url.username = role
|
|
217
|
+
url.password = password
|
|
218
|
+
url.pathname = '/' + dbName
|
|
219
|
+
return url.toString()
|
|
220
|
+
} catch {
|
|
221
|
+
const match = adminUrl.match(/^postgresql:\/\/([^@]+@)?([^/]+)/)
|
|
222
|
+
if (match !== null) {
|
|
223
|
+
return 'postgresql://' + role + ':' + password + '@' + String(match[2]) + '/' + dbName
|
|
224
|
+
}
|
|
225
|
+
return 'postgresql://' + role + ':' + password + '@localhost:5432/' + dbName
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
interface AdminClient {
|
|
230
|
+
query(sql: string, params?: unknown[]): Promise<unknown[]>
|
|
231
|
+
close(): Promise<void>
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function connectAdmin(url: string): Promise<AdminClient> {
|
|
235
|
+
const { default: postgres } = await import('postgres')
|
|
236
|
+
const client = postgres(url, { max: 1, onnotice: () => {} })
|
|
237
|
+
return {
|
|
238
|
+
async query(sqlStr: string, params?: unknown[]) {
|
|
239
|
+
if (params !== undefined && params.length > 0) {
|
|
240
|
+
return client.unsafe(sqlStr, params as never[])
|
|
241
|
+
}
|
|
242
|
+
return client.unsafe(sqlStr)
|
|
243
|
+
},
|
|
244
|
+
async close() {
|
|
245
|
+
await client.end()
|
|
246
|
+
},
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
interface RoleAttributes {
|
|
251
|
+
/** Owner roles carry BYPASSRLS so migrations/bootstrap span tenants regardless of FORCE; runtime roles must not, or RLS is inert. */
|
|
252
|
+
readonly bypassRls: boolean
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Both roles are LOGIN, non-superuser, and cannot create databases or roles.
|
|
256
|
+
// The single discriminator is BYPASSRLS: the owner has it (DDL/bootstrap reads
|
|
257
|
+
// and writes across every tenant), the non-owner runtime role explicitly does
|
|
258
|
+
// not, so generated RLS policies actually bind to it.
|
|
259
|
+
function roleAttributeClause(attrs: RoleAttributes): string {
|
|
260
|
+
return 'NOSUPERUSER NOCREATEDB NOCREATEROLE ' + (attrs.bypassRls ? 'BYPASSRLS' : 'NOBYPASSRLS')
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async function ensureRole(client: AdminClient, name: string, password: string, attrs: RoleAttributes): Promise<void> {
|
|
264
|
+
const clause = roleAttributeClause(attrs)
|
|
265
|
+
const rows = await client.query('SELECT 1 FROM pg_roles WHERE rolname = $1', [name]) as unknown[]
|
|
266
|
+
if (rows.length === 0) {
|
|
267
|
+
await client.query('CREATE ROLE ' + quoteIdent(name) + ' WITH LOGIN PASSWORD \'' + escapePassword(password) + '\' ' + clause)
|
|
268
|
+
info('Created role: ' + name)
|
|
269
|
+
} else {
|
|
270
|
+
await client.query('ALTER ROLE ' + quoteIdent(name) + ' WITH LOGIN PASSWORD \'' + escapePassword(password) + '\' ' + clause)
|
|
271
|
+
info('Updated role: ' + name)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async function grantConnect(client: AdminClient, dbName: string, role: string): Promise<void> {
|
|
276
|
+
await client.query('GRANT CONNECT ON DATABASE ' + quoteIdent(dbName) + ' TO ' + quoteIdent(role))
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* The DML grants for the non-owner runtime role, applied at provision time on a
|
|
281
|
+
* connection authenticated as the owner. The two ALTER DEFAULT PRIVILEGES lines
|
|
282
|
+
* are the drift guard: every future table the owner creates via migrations is
|
|
283
|
+
* granted to the runtime role automatically, so an RLS-enabled table can never
|
|
284
|
+
* be left ungranted — which would blank the rows the app is entitled to.
|
|
285
|
+
*/
|
|
286
|
+
export function buildRuntimeGrants(schema: string, ownerRole: string, runtimeRole: string): string[] {
|
|
287
|
+
const s = quoteIdent(schema)
|
|
288
|
+
const owner = quoteIdent(ownerRole)
|
|
289
|
+
const runtime = quoteIdent(runtimeRole)
|
|
290
|
+
return [
|
|
291
|
+
'GRANT USAGE ON SCHEMA ' + s + ' TO ' + runtime,
|
|
292
|
+
'GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA ' + s + ' TO ' + runtime,
|
|
293
|
+
'GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA ' + s + ' TO ' + runtime,
|
|
294
|
+
'ALTER DEFAULT PRIVILEGES FOR ROLE ' + owner + ' IN SCHEMA ' + s + ' GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO ' + runtime,
|
|
295
|
+
'ALTER DEFAULT PRIVILEGES FOR ROLE ' + owner + ' IN SCHEMA ' + s + ' GRANT USAGE, SELECT ON SEQUENCES TO ' + runtime,
|
|
296
|
+
]
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
async function ensureDatabase(client: AdminClient, dbName: string, owner: string): Promise<void> {
|
|
301
|
+
const rows = await client.query('SELECT 1 FROM pg_database WHERE datname = $1', [dbName]) as unknown[]
|
|
302
|
+
if (rows.length === 0) {
|
|
303
|
+
await client.query('CREATE DATABASE ' + quoteIdent(dbName) + ' OWNER ' + quoteIdent(owner))
|
|
304
|
+
info('Created database: ' + dbName)
|
|
305
|
+
} else {
|
|
306
|
+
info('Database "' + dbName + '" already exists')
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async function ensureExtension(client: AdminClient, ext: string): Promise<void> {
|
|
311
|
+
await client.query('CREATE EXTENSION IF NOT EXISTS ' + quoteIdent(ext))
|
|
312
|
+
info('Extension: ' + ext)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async function dropDatabaseIfExists(client: AdminClient, dbName: string): Promise<void> {
|
|
316
|
+
const rows = await client.query('SELECT 1 FROM pg_database WHERE datname = $1', [dbName]) as unknown[]
|
|
317
|
+
if (rows.length > 0) {
|
|
318
|
+
await client.query('DROP DATABASE ' + quoteIdent(dbName))
|
|
319
|
+
info('Dropped database: ' + dbName)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async function dropRoleIfExists(client: AdminClient, name: string): Promise<void> {
|
|
324
|
+
const rows = await client.query('SELECT 1 FROM pg_roles WHERE rolname = $1', [name]) as unknown[]
|
|
325
|
+
if (rows.length > 0) {
|
|
326
|
+
await client.query('DROP ROLE ' + quoteIdent(name))
|
|
327
|
+
info('Dropped role: ' + name)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function quoteIdent(name: string): string {
|
|
332
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
|
|
333
|
+
throw new Error('[pipework] Invalid identifier: "' + name + '"')
|
|
334
|
+
}
|
|
335
|
+
return '"' + name + '"'
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function escapePassword(password: string): string {
|
|
339
|
+
return password.replace(/'/g, "''")
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function writeEnvVar(cwd: string, key: string, value: string): void {
|
|
343
|
+
const envPath = join(cwd, '.env')
|
|
344
|
+
let content = ''
|
|
345
|
+
if (existsSync(envPath)) {
|
|
346
|
+
content = readFileSync(envPath, 'utf-8')
|
|
347
|
+
const pattern = new RegExp('^' + key + '=.*$', 'm')
|
|
348
|
+
if (pattern.test(content)) {
|
|
349
|
+
content = content.replace(pattern, key + '=' + value)
|
|
350
|
+
writeFileSync(envPath, content, 'utf-8')
|
|
351
|
+
return
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const newLine = content.length > 0 && !content.endsWith('\n') ? '\n' : ''
|
|
355
|
+
writeFileSync(envPath, content + newLine + key + '=' + value + '\n', 'utf-8')
|
|
356
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import { resolve, dirname } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { info, bold, cyan, yellow } from '../output.js'
|
|
5
|
+
|
|
6
|
+
export interface DevOptions {
|
|
7
|
+
port: string | undefined
|
|
8
|
+
cwd: string
|
|
9
|
+
entry: string | undefined
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function dev(options: DevOptions): void {
|
|
13
|
+
if (options.entry !== undefined) {
|
|
14
|
+
startLegacy(options)
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
startSurfaceAware(options)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// dev.js compiles to dist/cli/commands/dev.js. The TS loader and the dev
|
|
22
|
+
// bootstrap are sibling build outputs, NOT source files — once pipework is
|
|
23
|
+
// installed they live under node_modules. Both must be resolved as the
|
|
24
|
+
// compiled `.js`: the loader source is src/core/config/ts-register.ts →
|
|
25
|
+
// dist/core/config/ts-register.js (two levels up to dist, then core/config),
|
|
26
|
+
// and the bootstrap is src/cli/dev-bootstrap.ts → dist/cli/dev-bootstrap.js
|
|
27
|
+
// (one level up to dist/cli). Referencing the bootstrap as `.ts` only works in
|
|
28
|
+
// pipework's own repo (source not under node_modules) and is doubly broken
|
|
29
|
+
// once installed: the `.ts` isn't shipped, and Node refuses to strip types for
|
|
30
|
+
// any file under node_modules.
|
|
31
|
+
export function resolveRegisterPath(cliDir: string): string {
|
|
32
|
+
return resolve(cliDir, '..', '..', 'core', 'config', 'ts-register.js')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function resolveBootstrapPath(cliDir: string): string {
|
|
36
|
+
return resolve(cliDir, '..', 'dev-bootstrap.js')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
function startSurfaceAware(options: DevOptions): void {
|
|
41
|
+
{
|
|
42
|
+
const cliDir = dirname(fileURLToPath(import.meta.url))
|
|
43
|
+
const bootstrapPath = resolveBootstrapPath(cliDir)
|
|
44
|
+
const registerPath = resolveRegisterPath(cliDir)
|
|
45
|
+
|
|
46
|
+
const env: Record<string, string | undefined> = { ...process.env, 'PIPEWORK_CWD': options.cwd }
|
|
47
|
+
if (options.port !== undefined) {
|
|
48
|
+
env['PORT'] = options.port
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
printBanner()
|
|
52
|
+
|
|
53
|
+
const args = ['--watch', '--import', registerPath, bootstrapPath]
|
|
54
|
+
|
|
55
|
+
const child = spawn('node', args, {
|
|
56
|
+
cwd: options.cwd,
|
|
57
|
+
stdio: 'inherit',
|
|
58
|
+
env,
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
child.on('exit', (code, signal) => {
|
|
62
|
+
if (signal === 'SIGTERM' || signal === 'SIGINT') {
|
|
63
|
+
process.exit(0)
|
|
64
|
+
}
|
|
65
|
+
process.exit(code ?? 0)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
process.on('SIGTERM', () => child.kill('SIGTERM'))
|
|
69
|
+
process.on('SIGINT', () => child.kill('SIGINT'))
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function startLegacy(options: DevOptions): void {
|
|
74
|
+
{
|
|
75
|
+
const cliDir = dirname(fileURLToPath(import.meta.url))
|
|
76
|
+
const registerPath = resolveRegisterPath(cliDir)
|
|
77
|
+
const entry = options.entry ?? 'src/server.ts'
|
|
78
|
+
const args = ['--watch', '--import', registerPath, entry]
|
|
79
|
+
|
|
80
|
+
if (options.port !== undefined) {
|
|
81
|
+
process.env['PORT'] = options.port
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
info(`Starting dev server: node ${args.join(' ')}`)
|
|
85
|
+
|
|
86
|
+
const child = spawn('node', args, {
|
|
87
|
+
cwd: options.cwd,
|
|
88
|
+
stdio: 'inherit',
|
|
89
|
+
env: process.env,
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
child.on('exit', (code) => {
|
|
93
|
+
process.exit(code ?? 0)
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function printBanner(): void {
|
|
99
|
+
process.stderr.write(`\n ${bold(cyan('pipework dev'))}\n`)
|
|
100
|
+
process.stderr.write(` ${yellow('watching for changes...')}\n\n`)
|
|
101
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ResolvedConfig, ResolvedDoor } from '../../core/config/load.js'
|
|
2
|
+
import { queueFrameworkDoors } from '../../async/jobs/queue-door.js'
|
|
3
|
+
import { info, success, warn, error as logError } from '../output.js'
|
|
4
|
+
|
|
5
|
+
export interface GenerateCommandOptions {
|
|
6
|
+
db: string | undefined
|
|
7
|
+
name: string | undefined
|
|
8
|
+
cwd: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Evaluated after the schema files load: queue tables register when a worker surface or graph is constructed. */
|
|
12
|
+
function doorsOf(config: ResolvedConfig, database: string): () => ResolvedDoor[] {
|
|
13
|
+
return () => [...Object.values(config.doors), ...Object.values(config.frameworkDoors), ...Object.values(queueFrameworkDoors(config))]
|
|
14
|
+
.filter(door => door.database === database)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function generate(options: GenerateCommandOptions): Promise<void> {
|
|
18
|
+
const { discoverInstance, findConfig } = await import('../../core/config/discover.js')
|
|
19
|
+
const { generateForDatabase } = await import('../../data/migrate/generate.js')
|
|
20
|
+
const { loadInternalDefinitions } = await import('../../data/migrate/internal-definitions.js')
|
|
21
|
+
|
|
22
|
+
if (findConfig(options.cwd) === null) {
|
|
23
|
+
logError(
|
|
24
|
+
'No pipework.config.ts found.\n\n' +
|
|
25
|
+
' Run `pipework init` to create one.\n'
|
|
26
|
+
)
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// A config that exists but fails to load (missing env var, refused
|
|
31
|
+
// url/testUrl identity, …) must surface its real error, not be misreported
|
|
32
|
+
// as a missing config.
|
|
33
|
+
const instance = await discoverInstance(options.cwd)
|
|
34
|
+
|
|
35
|
+
const defaultDbName = instance.config.defaultDatabaseName()
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
if (options.db !== undefined) {
|
|
39
|
+
const dbConfig = instance.config.database(options.db)
|
|
40
|
+
info(`Generating migration for database: ${options.db}`)
|
|
41
|
+
// Passed as a thunk so queue registrations made by glob-imported schema
|
|
42
|
+
// modules (inside generateForDatabase) are visible when it runs.
|
|
43
|
+
const internal = () => loadInternalDefinitions(instance.config.raw, {
|
|
44
|
+
isDefaultDatabase: options.db === defaultDbName,
|
|
45
|
+
})
|
|
46
|
+
const result = await generateForDatabase(dbConfig, options.name, internal, doorsOf(instance.config, dbConfig.name))
|
|
47
|
+
if (result.migrationFile === null) {
|
|
48
|
+
warn(`${options.db}: no schema changes detected`)
|
|
49
|
+
} else {
|
|
50
|
+
success(`${options.db}: generated ${result.migrationFile}`)
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
info('Generating migrations for all databases...')
|
|
54
|
+
let generated = 0
|
|
55
|
+
for (const [, dbConfig] of instance.config.databases()) {
|
|
56
|
+
if (dbConfig.schema === undefined) continue
|
|
57
|
+
const internal = () => loadInternalDefinitions(instance.config.raw, {
|
|
58
|
+
isDefaultDatabase: dbConfig.name === defaultDbName,
|
|
59
|
+
})
|
|
60
|
+
const result = await generateForDatabase(dbConfig, options.name, internal, doorsOf(instance.config, dbConfig.name))
|
|
61
|
+
if (result.migrationFile === null) {
|
|
62
|
+
warn(`${dbConfig.name}: no schema changes detected`)
|
|
63
|
+
} else {
|
|
64
|
+
success(`${dbConfig.name}: generated ${result.migrationFile}`)
|
|
65
|
+
generated++
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (generated === 0) {
|
|
69
|
+
warn('No schema changes detected in any database.')
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} finally {
|
|
73
|
+
await instance.pool.closeAll()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { success, warn } from '../output.js'
|
|
4
|
+
|
|
5
|
+
const CONFIG_TEMPLATE = `import { createManifold } from 'pipework'
|
|
6
|
+
|
|
7
|
+
export default createManifold({
|
|
8
|
+
databases: {
|
|
9
|
+
app: {
|
|
10
|
+
url: 'DATABASE_URL',
|
|
11
|
+
testUrl: 'DATABASE_URL_TEST',
|
|
12
|
+
schema: './src/db/schema.ts',
|
|
13
|
+
migrations: './migrations/app',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
})
|
|
17
|
+
`
|
|
18
|
+
|
|
19
|
+
export function init(cwd: string): void {
|
|
20
|
+
const configPath = join(cwd, 'pipework.config.ts')
|
|
21
|
+
const migrationsPath = join(cwd, 'migrations', 'app')
|
|
22
|
+
|
|
23
|
+
if (existsSync(configPath)) {
|
|
24
|
+
warn('pipework.config.ts already exists — skipping')
|
|
25
|
+
} else {
|
|
26
|
+
writeFileSync(configPath, CONFIG_TEMPLATE, 'utf-8')
|
|
27
|
+
success('Created pipework.config.ts')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!existsSync(migrationsPath)) {
|
|
31
|
+
mkdirSync(migrationsPath, { recursive: true })
|
|
32
|
+
success(`Created ${migrationsPath}`)
|
|
33
|
+
} else {
|
|
34
|
+
warn(`${migrationsPath} already exists — skipping`)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
import { sync as syncWorkspace } from '../../workspace/sync.js'
|
|
3
|
+
import { loadConfig } from './shared/load-config.js'
|
|
4
|
+
import { reportRemoved } from './shared/report-removed.js'
|
|
5
|
+
import { runPnpmInstall } from './shared/pnpm-install.js'
|
|
6
|
+
import { info, success, error } from '../output.js'
|
|
7
|
+
|
|
8
|
+
export async function install(cwd: string, pipeworkVersion?: string): Promise<void> {
|
|
9
|
+
const resolved = resolve(cwd)
|
|
10
|
+
const { config, appName } = await loadConfig(resolved)
|
|
11
|
+
|
|
12
|
+
info('Syncing workspace...')
|
|
13
|
+
const syncInput = { config, cwd: resolved, appName }
|
|
14
|
+
const result = syncWorkspace(
|
|
15
|
+
pipeworkVersion !== undefined ? { ...syncInput, pipeworkVersion } : syncInput,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
success(`Generated ${String(result.files.length)} file(s).`)
|
|
19
|
+
reportRemoved(result)
|
|
20
|
+
|
|
21
|
+
info('Running pnpm install...')
|
|
22
|
+
const outcome = runPnpmInstall({ cwd: resolved, requiredPipeworkVersion: result.pipeworkVersion })
|
|
23
|
+
if (!outcome.ok) {
|
|
24
|
+
error(outcome.message)
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
27
|
+
success(`Install complete — pipework@${outcome.installedPipeworkVersion} in node_modules.`)
|
|
28
|
+
}
|