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,173 @@
|
|
|
1
|
+
// The cardinality analyzer. Given the `@flow_step` sites of a source set, it
|
|
2
|
+
// classifies every `@downstream` edge structurally (classify-edge.ts), reports
|
|
3
|
+
// the edges whose declared cardinality disagrees with the structure or whose
|
|
4
|
+
// cardinality could not be resolved, and derives the Q7 `structuralMax` step
|
|
5
|
+
// cap from the resulting graph. Pure over its inputs — file I/O lives in
|
|
6
|
+
// check.ts. See PLAN.tracing.md, component 3.
|
|
7
|
+
|
|
8
|
+
import type { FlowStepSite } from '../check/flow-step-site.js'
|
|
9
|
+
import { classifyEdge, type EdgeClassification } from './classify-edge.js'
|
|
10
|
+
import { computeStructuralMax, type StepEdge } from './structural-max.js'
|
|
11
|
+
import type { BranchKind } from './branch-context.js'
|
|
12
|
+
|
|
13
|
+
/** A `@flow_step` site paired with the source path it was found in. */
|
|
14
|
+
export interface AnalyzerEntry {
|
|
15
|
+
/** Source path relative to `cwd` — the node-id prefix and the diagnostic file. */
|
|
16
|
+
readonly file: string
|
|
17
|
+
readonly site: FlowStepSite
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CardinalityViolation {
|
|
21
|
+
readonly rule: string
|
|
22
|
+
readonly file: string
|
|
23
|
+
readonly line: number
|
|
24
|
+
readonly message: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface CardinalityResult {
|
|
28
|
+
/** Structural verdict for every `@downstream` edge across the input. */
|
|
29
|
+
readonly classifications: readonly EdgeClassification[]
|
|
30
|
+
readonly violations: readonly CardinalityViolation[]
|
|
31
|
+
/** The Q7 step cap: longest chain of `step` edges through the flow graph. */
|
|
32
|
+
readonly structuralMax: number
|
|
33
|
+
/** Count of flow-step sites the analyzer classified. */
|
|
34
|
+
readonly analyzed: number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The `path:symbol` flow-graph node id — the single place ids are composed. */
|
|
38
|
+
function nodeId(path: string, symbol: string): string {
|
|
39
|
+
return `${path}:${symbol}`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Classifies every `@downstream` edge across `entries` and derives the step cap. */
|
|
43
|
+
export function analyzeCardinality(entries: readonly AnalyzerEntry[]): CardinalityResult {
|
|
44
|
+
const classifications: EdgeClassification[] = []
|
|
45
|
+
const violations: CardinalityViolation[] = []
|
|
46
|
+
const nodeIds: string[] = []
|
|
47
|
+
const stepEdges: StepEdge[] = []
|
|
48
|
+
// Keyed `${from}\n${target}` so a `step`-cycle violation can recover the
|
|
49
|
+
// exact classification of the edge that closes the ring.
|
|
50
|
+
const stepEdgeIndex = new Map<string, EdgeClassification>()
|
|
51
|
+
|
|
52
|
+
for (const { file, site } of entries) {
|
|
53
|
+
// An orphan annotation documents no function, and an invalid one never
|
|
54
|
+
// parsed into edges — both are the `flow` check's diagnostics, not this
|
|
55
|
+
// one's. Nothing here to classify.
|
|
56
|
+
if (site.subject.node === null) continue
|
|
57
|
+
if (site.annotation.kind !== 'annotation') continue
|
|
58
|
+
|
|
59
|
+
const from = nodeId(file, site.subject.name)
|
|
60
|
+
nodeIds.push(from)
|
|
61
|
+
|
|
62
|
+
for (const edge of site.annotation.annotation.downstream) {
|
|
63
|
+
const classification = classifyEdge(file, site, edge)
|
|
64
|
+
classifications.push(classification)
|
|
65
|
+
const violation = violationFor(classification, site)
|
|
66
|
+
if (violation !== null) violations.push(violation)
|
|
67
|
+
|
|
68
|
+
if (classification.structural === 'step') {
|
|
69
|
+
const to = nodeId(edge.path, edge.symbol)
|
|
70
|
+
stepEdges.push({ from, to })
|
|
71
|
+
stepEdgeIndex.set(`${from}\n${to}`, classification)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const { value, cycles } = computeStructuralMax(nodeIds, stepEdges)
|
|
77
|
+
for (const cycle of cycles) {
|
|
78
|
+
violations.push(cycleViolation(cycle, stepEdgeIndex))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
classifications,
|
|
83
|
+
violations,
|
|
84
|
+
structuralMax: value,
|
|
85
|
+
analyzed: nodeIds.length,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The violation a single classified edge raises, or `null` when it is sound. */
|
|
90
|
+
function violationFor(
|
|
91
|
+
classification: EdgeClassification,
|
|
92
|
+
site: FlowStepSite,
|
|
93
|
+
): CardinalityViolation | null {
|
|
94
|
+
const { edge, structural, branchKind } = classification
|
|
95
|
+
const target = nodeId(edge.path, edge.symbol)
|
|
96
|
+
const file = classification.file
|
|
97
|
+
const line = classification.line ?? site.commentLine
|
|
98
|
+
|
|
99
|
+
if (edge.cardinality === null) {
|
|
100
|
+
// A missing cardinality the analyzer *can* resolve is the `flow` check's
|
|
101
|
+
// `missing-cardinality` warning, and the classification is what the codemod
|
|
102
|
+
// consumes to fill it in. Only an unresolved one is this check's to raise.
|
|
103
|
+
if (structural !== 'ambiguous') return null
|
|
104
|
+
return {
|
|
105
|
+
rule: 'cardinality/unannotated-ambiguity',
|
|
106
|
+
file,
|
|
107
|
+
line,
|
|
108
|
+
message:
|
|
109
|
+
`@downstream ${target} has no cardinality and the analyzer cannot locate the call — `
|
|
110
|
+
+ `${edge.symbol} is reached through indirection (a bare callback, dynamic dispatch). `
|
|
111
|
+
+ `Declare it explicitly: "@downstream ${target} step" or "@downstream ${target} branch".`,
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// The author declared a cardinality the analyzer could not verify — the
|
|
116
|
+
// annotation is the source of truth for indirection it cannot follow.
|
|
117
|
+
if (structural === 'ambiguous') return null
|
|
118
|
+
if (structural === edge.cardinality) return null
|
|
119
|
+
|
|
120
|
+
if (structural === 'branch') {
|
|
121
|
+
const phrase = branchPhrase(branchKind!)
|
|
122
|
+
return {
|
|
123
|
+
rule: 'cardinality/mismatch',
|
|
124
|
+
file,
|
|
125
|
+
line,
|
|
126
|
+
message:
|
|
127
|
+
`@downstream ${target} is declared "step" but ${edge.symbol} is called inside `
|
|
128
|
+
+ `${phrase} — that call site is traversed more than once, which is a `
|
|
129
|
+
+ `branch. Change the cardinality to "branch", or hoist the call out of ${phrase}.`,
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
rule: 'cardinality/mismatch',
|
|
134
|
+
file,
|
|
135
|
+
line,
|
|
136
|
+
message:
|
|
137
|
+
`@downstream ${target} is declared "branch" but every located call to ${edge.symbol} is `
|
|
138
|
+
+ `linear — it is traversed at most once, which is a step. Change the cardinality to "step".`,
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** The violation for one `step`-edge cycle, attributed to the edge that opens it. */
|
|
143
|
+
function cycleViolation(
|
|
144
|
+
cycle: readonly string[],
|
|
145
|
+
stepEdgeIndex: ReadonlyMap<string, EdgeClassification>,
|
|
146
|
+
): CardinalityViolation {
|
|
147
|
+
// A `step`-edge cycle has at least two nodes — a self `step` edge is
|
|
148
|
+
// impossible, since a self-call is always classified `recursion` (a branch).
|
|
149
|
+
const source = cycle[0]!
|
|
150
|
+
const target = cycle[1]!
|
|
151
|
+
// Every node in a `step`-edge cycle is the `from` of a `step` edge in the
|
|
152
|
+
// ring, so the closing edge is always indexed.
|
|
153
|
+
const edge = stepEdgeIndex.get(`${source}\n${target}`)!
|
|
154
|
+
const ring = [...cycle, source].join(' → ')
|
|
155
|
+
return {
|
|
156
|
+
rule: 'cardinality/step-cycle',
|
|
157
|
+
file: edge.file,
|
|
158
|
+
line: edge.line!,
|
|
159
|
+
message:
|
|
160
|
+
`@downstream forms a cycle of "step" edges: ${ring}. A step edge that loops back makes the `
|
|
161
|
+
+ `per-trace step count unbounded — one edge in this ring is a branch (mutual recursion is a `
|
|
162
|
+
+ `branch). Re-classify the edge that closes the loop.`,
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function branchPhrase(kind: BranchKind): string {
|
|
167
|
+
switch (kind) {
|
|
168
|
+
case 'loop': return 'a loop'
|
|
169
|
+
case 'iteration-method': return 'an iteration callback (.map, .forEach, …)'
|
|
170
|
+
case 'fan-out': return 'a Promise combinator (Promise.all, …)'
|
|
171
|
+
case 'recursion': return 'a recursive call'
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// Locates every call to a target symbol inside a flow-step function body and
|
|
2
|
+
// classifies each call's traversal context. A call reached through a loop, an
|
|
3
|
+
// iteration method, a Promise-combinator fan-out, or a self-recursive edge is
|
|
4
|
+
// "branching" — the single call site is traversed more than once per execution
|
|
5
|
+
// of the parent. Anything else is linear. This is the structural half of the
|
|
6
|
+
// cardinality analyzer: it reads AST shape only, never runtime behaviour, and
|
|
7
|
+
// never resolves imports or types. See PLAN.tracing.md, Q1.
|
|
8
|
+
|
|
9
|
+
import { isNode, type AstNode } from '../check/flow-step-site.js'
|
|
10
|
+
|
|
11
|
+
/** The construct that makes a call site traversed more than once. */
|
|
12
|
+
export type BranchKind = 'loop' | 'iteration-method' | 'fan-out' | 'recursion'
|
|
13
|
+
|
|
14
|
+
/** One located call to the target symbol, with its traversal context. */
|
|
15
|
+
export interface CallSite {
|
|
16
|
+
/** 1-based file line of the call. */
|
|
17
|
+
readonly line: number
|
|
18
|
+
/** The branching construct enclosing the call, or `null` when the call is linear. */
|
|
19
|
+
readonly branchKind: BranchKind | null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Array methods whose callback argument is invoked once per element — a
|
|
23
|
+
// downstream call inside the callback is traversed more than once. Lexical:
|
|
24
|
+
// `.map` on a non-array still reads as iteration, by design (Q1).
|
|
25
|
+
const ITERATION_METHODS = new Set([
|
|
26
|
+
'map', 'forEach', 'flatMap', 'filter',
|
|
27
|
+
'reduce', 'reduceRight',
|
|
28
|
+
'some', 'every',
|
|
29
|
+
'find', 'findIndex', 'findLast', 'findLastIndex',
|
|
30
|
+
])
|
|
31
|
+
|
|
32
|
+
// Promise combinators that run their arguments as concurrent siblings.
|
|
33
|
+
const PROMISE_COMBINATORS = new Set(['all', 'allSettled', 'race', 'any'])
|
|
34
|
+
|
|
35
|
+
const FUNCTION_TYPES = new Set([
|
|
36
|
+
'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression',
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
const SKIP_KEYS = new Set(['loc', 'range', 'parent'])
|
|
40
|
+
|
|
41
|
+
interface Context {
|
|
42
|
+
/** Name of the enclosing flow step — a call to it is recursion. */
|
|
43
|
+
readonly ownName: string
|
|
44
|
+
/** Symbol the `@downstream` edge points at. */
|
|
45
|
+
readonly target: string
|
|
46
|
+
/** The branching construct currently in scope, or `null` at linear depth. */
|
|
47
|
+
readonly branchKind: BranchKind | null
|
|
48
|
+
readonly out: CallSite[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Every call to `target` inside `body`, each tagged with its traversal context. */
|
|
52
|
+
export function findCallSites(body: AstNode, ownName: string, target: string): CallSite[] {
|
|
53
|
+
const out: CallSite[] = []
|
|
54
|
+
visit(body, { ownName, target, branchKind: null, out })
|
|
55
|
+
return out
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function visit(node: AstNode, ctx: Context): void {
|
|
59
|
+
// A nested closure reached by ordinary descent is indirection the analyzer
|
|
60
|
+
// does not follow. Iteration-method callbacks are the one exception, and
|
|
61
|
+
// those are entered explicitly from `visitCall`.
|
|
62
|
+
if (FUNCTION_TYPES.has(node.type)) return
|
|
63
|
+
|
|
64
|
+
switch (node.type) {
|
|
65
|
+
case 'CallExpression':
|
|
66
|
+
visitCall(node, ctx)
|
|
67
|
+
return
|
|
68
|
+
case 'ForStatement':
|
|
69
|
+
visitForStatement(node, ctx)
|
|
70
|
+
return
|
|
71
|
+
case 'ForOfStatement':
|
|
72
|
+
case 'ForInStatement':
|
|
73
|
+
visitForInOf(node, ctx)
|
|
74
|
+
return
|
|
75
|
+
case 'WhileStatement':
|
|
76
|
+
case 'DoWhileStatement':
|
|
77
|
+
visitWhile(node, ctx)
|
|
78
|
+
return
|
|
79
|
+
default:
|
|
80
|
+
for (const child of childNodes(node)) visit(child, ctx)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function visitCall(node: AstNode, ctx: Context): void {
|
|
85
|
+
const callee = node['callee']
|
|
86
|
+
const name = calleeName(callee)
|
|
87
|
+
if (name === ctx.target) {
|
|
88
|
+
ctx.out.push({
|
|
89
|
+
line: node.loc.start.line,
|
|
90
|
+
branchKind: name === ctx.ownName ? 'recursion' : ctx.branchKind,
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const args = nodeArray(node['arguments'])
|
|
95
|
+
|
|
96
|
+
if (isPromiseCombinator(callee)) {
|
|
97
|
+
// Each argument runs as a concurrent sibling — a fan-out.
|
|
98
|
+
for (const arg of args) visit(arg, branched(ctx, 'fan-out'))
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (isIterationMethod(callee)) {
|
|
103
|
+
// The receiver is evaluated once; the callback runs once per element.
|
|
104
|
+
if (isNode(callee)) visitChild(callee['object'], ctx)
|
|
105
|
+
for (const arg of args) visitIterationArg(arg, ctx)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// An ordinary call: callee and arguments stay at the current depth.
|
|
110
|
+
visitChild(callee, ctx)
|
|
111
|
+
for (const arg of args) visit(arg, ctx)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function visitIterationArg(arg: AstNode, ctx: Context): void {
|
|
115
|
+
if (arg.type === 'Identifier' && arg['name'] === ctx.target) {
|
|
116
|
+
// `items.map(downstream)` — the symbol is itself the per-element callback.
|
|
117
|
+
ctx.out.push({
|
|
118
|
+
line: arg.loc.start.line,
|
|
119
|
+
branchKind: arg['name'] === ctx.ownName ? 'recursion' : 'iteration-method',
|
|
120
|
+
})
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
if (FUNCTION_TYPES.has(arg.type)) {
|
|
124
|
+
visitChild(arg['body'], branched(ctx, 'iteration-method'))
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
// A non-callback argument (e.g. `reduce`'s seed) runs at the current depth.
|
|
128
|
+
visit(arg, ctx)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function visitForStatement(node: AstNode, ctx: Context): void {
|
|
132
|
+
// `init` runs once; `test`, `update`, and `body` run every iteration.
|
|
133
|
+
visitChild(node['init'], ctx)
|
|
134
|
+
const looped = branched(ctx, 'loop')
|
|
135
|
+
visitChild(node['test'], looped)
|
|
136
|
+
visitChild(node['update'], looped)
|
|
137
|
+
visitChild(node['body'], looped)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function visitForInOf(node: AstNode, ctx: Context): void {
|
|
141
|
+
// `right` (the iterable) is evaluated once; `body` runs once per element.
|
|
142
|
+
visitChild(node['right'], ctx)
|
|
143
|
+
visitChild(node['body'], branched(ctx, 'loop'))
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function visitWhile(node: AstNode, ctx: Context): void {
|
|
147
|
+
// Both `test` and `body` run every iteration.
|
|
148
|
+
const looped = branched(ctx, 'loop')
|
|
149
|
+
visitChild(node['test'], looped)
|
|
150
|
+
visitChild(node['body'], looped)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Enters `branchKind` scope, keeping the outermost construct already in scope. */
|
|
154
|
+
function branched(ctx: Context, kind: BranchKind): Context {
|
|
155
|
+
return { ...ctx, branchKind: ctx.branchKind ?? kind }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function visitChild(value: unknown, ctx: Context): void {
|
|
159
|
+
if (isNode(value)) visit(value, ctx)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function calleeName(callee: unknown): string | null {
|
|
163
|
+
if (!isNode(callee)) return null
|
|
164
|
+
if (callee.type === 'Identifier') {
|
|
165
|
+
const name = callee['name']
|
|
166
|
+
return typeof name === 'string' ? name : null
|
|
167
|
+
}
|
|
168
|
+
if (callee.type === 'MemberExpression' && callee['computed'] === false) {
|
|
169
|
+
const prop = callee['property']
|
|
170
|
+
if (isNode(prop) && prop.type === 'Identifier' && typeof prop['name'] === 'string') {
|
|
171
|
+
return prop['name']
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return null
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function isPromiseCombinator(callee: unknown): boolean {
|
|
178
|
+
if (!isNode(callee) || callee.type !== 'MemberExpression' || callee['computed'] !== false) {
|
|
179
|
+
return false
|
|
180
|
+
}
|
|
181
|
+
const obj = callee['object']
|
|
182
|
+
const prop = callee['property']
|
|
183
|
+
return isNode(obj) && obj.type === 'Identifier' && obj['name'] === 'Promise'
|
|
184
|
+
&& isNode(prop) && prop.type === 'Identifier'
|
|
185
|
+
&& typeof prop['name'] === 'string' && PROMISE_COMBINATORS.has(prop['name'])
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function isIterationMethod(callee: unknown): boolean {
|
|
189
|
+
if (!isNode(callee) || callee.type !== 'MemberExpression' || callee['computed'] !== false) {
|
|
190
|
+
return false
|
|
191
|
+
}
|
|
192
|
+
const prop = callee['property']
|
|
193
|
+
return isNode(prop) && prop.type === 'Identifier'
|
|
194
|
+
&& typeof prop['name'] === 'string' && ITERATION_METHODS.has(prop['name'])
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function nodeArray(value: unknown): AstNode[] {
|
|
198
|
+
if (!Array.isArray(value)) return []
|
|
199
|
+
return value.filter(isNode)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function* childNodes(node: AstNode): Generator<AstNode> {
|
|
203
|
+
for (const key of Object.keys(node)) {
|
|
204
|
+
if (SKIP_KEYS.has(key)) continue
|
|
205
|
+
const value = node[key]
|
|
206
|
+
if (Array.isArray(value)) {
|
|
207
|
+
for (const item of value) {
|
|
208
|
+
if (isNode(item)) yield item
|
|
209
|
+
}
|
|
210
|
+
} else if (isNode(value)) {
|
|
211
|
+
yield value
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// File-scanning wrapper around the cardinality analyzer: reads each source
|
|
2
|
+
// file, collects its `@flow_step` sites, and runs `analyzeCardinality` over
|
|
3
|
+
// the lot. Mirrors flow-check.ts — the analyzer itself is pure (analyze.ts);
|
|
4
|
+
// this is the only part of the cardinality check that touches the filesystem.
|
|
5
|
+
|
|
6
|
+
import { readFileSync } from 'node:fs'
|
|
7
|
+
import { join } from 'node:path'
|
|
8
|
+
import { collectFlowStepSites } from '../check/flow-step-site.js'
|
|
9
|
+
import { analyzeCardinality, type AnalyzerEntry, type CardinalityResult } from './analyze.js'
|
|
10
|
+
|
|
11
|
+
/** Analyzes `@downstream` cardinality across `sourceFiles` (paths relative to `cwd`). */
|
|
12
|
+
export function checkCardinality(cwd: string, sourceFiles: readonly string[]): CardinalityResult {
|
|
13
|
+
const entries: AnalyzerEntry[] = []
|
|
14
|
+
|
|
15
|
+
for (const file of sourceFiles) {
|
|
16
|
+
const abs = join(cwd, file)
|
|
17
|
+
|
|
18
|
+
let sites
|
|
19
|
+
try {
|
|
20
|
+
sites = collectFlowStepSites(readFileSync(abs, 'utf-8'), file)
|
|
21
|
+
} catch {
|
|
22
|
+
// Missing or unparseable file — nothing to analyze; a syntax error is
|
|
23
|
+
// the type checker's diagnostic, not this check's.
|
|
24
|
+
continue
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
for (const site of sites) {
|
|
28
|
+
entries.push({ file, site })
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return analyzeCardinality(entries)
|
|
33
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Structural cardinality verdict for one declared `@downstream` edge: locate
|
|
2
|
+
// the edge's call sites in the flow-step body and decide whether the edge is a
|
|
3
|
+
// plain `step`, a `branch` (a single call site reached through a loop, an
|
|
4
|
+
// iteration method, a fan-out, or recursion), or `ambiguous` — reached through
|
|
5
|
+
// indirection the analyzer cannot follow. See PLAN.tracing.md, Q1.
|
|
6
|
+
|
|
7
|
+
import type { DownstreamEdge } from 'pipework-flow-parser'
|
|
8
|
+
import type { FlowStepSite } from '../check/flow-step-site.js'
|
|
9
|
+
import { findCallSites, type BranchKind } from './branch-context.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The analyzer's structural verdict for a `@downstream` edge.
|
|
13
|
+
*
|
|
14
|
+
* - `step` — every located call site is linear; traversed at most once.
|
|
15
|
+
* - `branch` — at least one call site is reached through a loop, an iteration
|
|
16
|
+
* method, a Promise-combinator fan-out, or recursion.
|
|
17
|
+
* - `ambiguous` — no call site could be located. The edge is reached through
|
|
18
|
+
* indirection the analyzer does not follow (a bare callback, dynamic
|
|
19
|
+
* dispatch), so its cardinality must be declared by hand. See Q1.
|
|
20
|
+
*/
|
|
21
|
+
export type StructuralCardinality = 'step' | 'branch' | 'ambiguous'
|
|
22
|
+
|
|
23
|
+
export interface EdgeClassification {
|
|
24
|
+
/** Source path of the flow step the edge is declared on, relative to `cwd`. */
|
|
25
|
+
readonly file: string
|
|
26
|
+
/** Name of the flow step the edge is declared on. */
|
|
27
|
+
readonly from: string
|
|
28
|
+
/** The declared edge, verbatim from the annotation. */
|
|
29
|
+
readonly edge: DownstreamEdge
|
|
30
|
+
/** The analyzer's structural verdict. */
|
|
31
|
+
readonly structural: StructuralCardinality
|
|
32
|
+
/** The branching construct, when `structural` is `branch`; otherwise `null`. */
|
|
33
|
+
readonly branchKind: BranchKind | null
|
|
34
|
+
/** 1-based file line of the call site driving the verdict; `null` when none was located. */
|
|
35
|
+
readonly line: number | null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Classifies one `@downstream` edge of `site` against the flow-step body. */
|
|
39
|
+
export function classifyEdge(
|
|
40
|
+
file: string,
|
|
41
|
+
site: FlowStepSite,
|
|
42
|
+
edge: DownstreamEdge,
|
|
43
|
+
): EdgeClassification {
|
|
44
|
+
const from = site.subject.name
|
|
45
|
+
const base = { file, from, edge }
|
|
46
|
+
|
|
47
|
+
const body = site.subject.body
|
|
48
|
+
if (body === null) {
|
|
49
|
+
// An orphan annotation — no function body to walk. The `flow` check owns
|
|
50
|
+
// the diagnostic; here the edge is simply unresolvable.
|
|
51
|
+
return { ...base, structural: 'ambiguous', branchKind: null, line: null }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const sites = findCallSites(body, from, edge.symbol)
|
|
55
|
+
if (sites.length === 0) {
|
|
56
|
+
return { ...base, structural: 'ambiguous', branchKind: null, line: null }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const branching = sites.find(s => s.branchKind !== null)
|
|
60
|
+
if (branching !== undefined) {
|
|
61
|
+
return { ...base, structural: 'branch', branchKind: branching.branchKind, line: branching.line }
|
|
62
|
+
}
|
|
63
|
+
return { ...base, structural: 'step', branchKind: null, line: sites[0]!.line }
|
|
64
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// The Q7 step-cap derivation. Once batching is forced to branch, a single
|
|
2
|
+
// trace's step count is bounded by the static flow graph: a `branch` edge
|
|
3
|
+
// opens a *child* trace, so only `step` edges extend the current one.
|
|
4
|
+
// `structuralMax` is the longest chain of `step` edges, counted in nodes.
|
|
5
|
+
//
|
|
6
|
+
// A cycle of `step` edges is unbounded — and a bug. A direct self-call is
|
|
7
|
+
// caught as recursion by branch-context, but *mutual* recursion (A step-calls
|
|
8
|
+
// B, B step-calls A) is invisible to single-function analysis; it surfaces
|
|
9
|
+
// here as a `step`-edge cycle. One of the edges that close the loop should
|
|
10
|
+
// have been a branch. See PLAN.tracing.md, Q7.
|
|
11
|
+
|
|
12
|
+
/** One `step` edge of the flow graph, both endpoints as `path:symbol` node ids. */
|
|
13
|
+
export interface StepEdge {
|
|
14
|
+
readonly from: string
|
|
15
|
+
readonly to: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface StructuralMax {
|
|
19
|
+
/** Longest chain of `step` edges through the graph, counted in nodes. */
|
|
20
|
+
readonly value: number
|
|
21
|
+
/** Every `step`-edge cycle found — each a ring of `path:symbol` node ids. */
|
|
22
|
+
readonly cycles: readonly (readonly string[])[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Longest `step`-edge chain across the flow graph, plus any `step`-edge cycles. */
|
|
26
|
+
export function computeStructuralMax(
|
|
27
|
+
nodeIds: readonly string[],
|
|
28
|
+
edges: readonly StepEdge[],
|
|
29
|
+
): StructuralMax {
|
|
30
|
+
const adjacency = buildAdjacency(nodeIds, edges)
|
|
31
|
+
const longest = new Map<string, number>()
|
|
32
|
+
const visiting = new Set<string>()
|
|
33
|
+
const cycles: string[][] = []
|
|
34
|
+
|
|
35
|
+
function dfs(node: string, stack: string[]): number {
|
|
36
|
+
const cached = longest.get(node)
|
|
37
|
+
if (cached !== undefined) return cached
|
|
38
|
+
if (visiting.has(node)) {
|
|
39
|
+
// Back-edge: record the ring and treat this edge as contributing nothing,
|
|
40
|
+
// so the walk terminates. The node's own length is left uncached.
|
|
41
|
+
cycles.push([...stack.slice(stack.indexOf(node)), node])
|
|
42
|
+
return 0
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
visiting.add(node)
|
|
46
|
+
stack.push(node)
|
|
47
|
+
let best = 0
|
|
48
|
+
// `node` is always an adjacency key — it came from `keys()` or from a
|
|
49
|
+
// neighbour set, and `buildAdjacency` ensures every endpoint is a key.
|
|
50
|
+
for (const target of adjacency.get(node)!) {
|
|
51
|
+
best = Math.max(best, dfs(target, stack))
|
|
52
|
+
}
|
|
53
|
+
stack.pop()
|
|
54
|
+
visiting.delete(node)
|
|
55
|
+
|
|
56
|
+
const result = 1 + best
|
|
57
|
+
longest.set(node, result)
|
|
58
|
+
return result
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let value = 0
|
|
62
|
+
for (const node of adjacency.keys()) {
|
|
63
|
+
value = Math.max(value, dfs(node, []))
|
|
64
|
+
}
|
|
65
|
+
return { value, cycles: dedupeCycles(cycles) }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The `step`-edge adjacency of the flow graph. Every analyzed flow step is a
|
|
70
|
+
* node; a `step` edge to a target that is not itself an analyzed flow step
|
|
71
|
+
* still adds that target as a terminal node, so the cap stays an upper bound.
|
|
72
|
+
*/
|
|
73
|
+
function buildAdjacency(
|
|
74
|
+
nodeIds: readonly string[],
|
|
75
|
+
edges: readonly StepEdge[],
|
|
76
|
+
): Map<string, Set<string>> {
|
|
77
|
+
const adjacency = new Map<string, Set<string>>()
|
|
78
|
+
const ensure = (id: string): Set<string> => {
|
|
79
|
+
let targets = adjacency.get(id)
|
|
80
|
+
if (targets === undefined) {
|
|
81
|
+
targets = new Set()
|
|
82
|
+
adjacency.set(id, targets)
|
|
83
|
+
}
|
|
84
|
+
return targets
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (const id of nodeIds) ensure(id)
|
|
88
|
+
for (const { from, to } of edges) {
|
|
89
|
+
ensure(to)
|
|
90
|
+
ensure(from).add(to)
|
|
91
|
+
}
|
|
92
|
+
return adjacency
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Collapses rotations and re-discoveries of the same ring to one entry each. */
|
|
96
|
+
function dedupeCycles(cycles: readonly string[][]): string[][] {
|
|
97
|
+
const seen = new Map<string, string[]>()
|
|
98
|
+
for (const cycle of cycles) {
|
|
99
|
+
// Drop the repeated closing node, then rotate so the smallest id leads —
|
|
100
|
+
// a canonical form shared by every rotation and rediscovery of the ring.
|
|
101
|
+
const ring = cycle.slice(0, -1)
|
|
102
|
+
const pivot = ring.indexOf([...ring].sort()[0]!)
|
|
103
|
+
const canonical = [...ring.slice(pivot), ...ring.slice(0, pivot)]
|
|
104
|
+
seen.set(canonical.join(' '), canonical)
|
|
105
|
+
}
|
|
106
|
+
return [...seen.values()]
|
|
107
|
+
}
|