pipework 0.15.0 → 0.16.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 -1
- package/REFERENCE.md +159 -2
- package/dist/REFERENCE.md +159 -2
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +12 -10
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/core/config/base-dir.d.ts +6 -0
- package/dist/core/config/base-dir.d.ts.map +1 -0
- package/dist/core/config/base-dir.js +21 -0
- package/dist/core/config/base-dir.js.map +1 -0
- package/dist/core/config/discover.d.ts.map +1 -1
- package/dist/core/config/discover.js +2 -15
- package/dist/core/config/discover.js.map +1 -1
- package/dist/core/config/env-types.d.ts +70 -0
- package/dist/core/config/env-types.d.ts.map +1 -1
- package/dist/core/config/env.d.ts.map +1 -1
- package/dist/core/config/env.js +10 -6
- package/dist/core/config/env.js.map +1 -1
- package/dist/core/config/import-config.d.ts +3 -0
- package/dist/core/config/import-config.d.ts.map +1 -0
- package/dist/core/config/import-config.js +34 -0
- package/dist/core/config/import-config.js.map +1 -0
- package/dist/core/config/load.d.ts +4 -0
- package/dist/core/config/load.d.ts.map +1 -1
- package/dist/core/config/load.js +14 -5
- package/dist/core/config/load.js.map +1 -1
- package/dist/core/config/resolve.d.ts.map +1 -1
- package/dist/core/config/resolve.js +23 -1
- package/dist/core/config/resolve.js.map +1 -1
- package/dist/core/pipework.d.ts +19 -0
- package/dist/core/pipework.d.ts.map +1 -1
- package/dist/core/pipework.js +25 -0
- package/dist/core/pipework.js.map +1 -1
- package/dist/core/validation/queue-tables.d.ts +8 -0
- package/dist/core/validation/queue-tables.d.ts.map +1 -0
- package/dist/core/validation/queue-tables.js +53 -0
- package/dist/core/validation/queue-tables.js.map +1 -0
- package/dist/core/validation/rls-role.d.ts +16 -0
- package/dist/core/validation/rls-role.d.ts.map +1 -0
- package/dist/core/validation/rls-role.js +54 -0
- package/dist/core/validation/rls-role.js.map +1 -0
- package/dist/core/validation/startup.d.ts +2 -0
- package/dist/core/validation/startup.d.ts.map +1 -1
- package/dist/core/validation/startup.js +6 -0
- package/dist/core/validation/startup.js.map +1 -1
- package/dist/data/db/pool.d.ts +9 -0
- package/dist/data/db/pool.d.ts.map +1 -1
- package/dist/data/db/pool.js +7 -0
- package/dist/data/db/pool.js.map +1 -1
- package/dist/data/migrate/generate.d.ts +1 -1
- package/dist/data/migrate/generate.d.ts.map +1 -1
- package/dist/data/migrate/generate.js +15 -8
- package/dist/data/migrate/generate.js.map +1 -1
- package/dist/lint/resolver.d.ts.map +1 -1
- package/dist/lint/resolver.js +2 -11
- package/dist/lint/resolver.js.map +1 -1
- package/dist/test/setup.d.ts.map +1 -1
- package/dist/test/setup.js +33 -0
- package/dist/test/setup.js.map +1 -1
- package/dist/test/vitest-workspace.d.ts.map +1 -1
- package/dist/test/vitest-workspace.js +2 -11
- package/dist/test/vitest-workspace.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.16.0
|
|
4
|
+
|
|
5
|
+
- **Fix: a queue registered by a module reached only through the schema glob now makes it into `pipework generate`'s output.** The CLI used to snapshot internal definitions (including registered queues) *before* the schema files were imported, so a `createQueue()` living in a glob-matched module — with no side-effect import in the config — was silently dropped from the migration, and consumers worked around it by importing the queue module from `pipework.config.ts`. Internal definitions are now collected after the schema-file imports. Breaking for API consumers: `generateForDatabase`'s `internalDefinitions` parameter is now a thunk (`() => Promise<Record<string, unknown>>`).
|
|
6
|
+
- **Feature: a registered queue whose table is missing from the database is now a loud, actionable failure at startup and at test bootstrap — not a crash at first insert.** Startup validation (`pipework serve`/`dev`, `manifold.start()`) and the test harness's template provisioning both verify every `createQueue()`-registered table exists in the default database (`to_regclass` probe), and refuse with a message naming the table, the schema-glob rule, and the fix (`pipework generate`, then `pipework migrate`).
|
|
7
|
+
- **Behavior change: a database whose `testUrl` resolves to the same connection string as its `url` is refused at config resolution in the test environment.** Identical values mean "tests" run against the real database: the test harness creates/drops databases and rolls back transactions on what it assumes is a dedicated instance, and RLS-inertness goes unnoticed — with zero signal from the framework. The refusal names both env vars and the fix (point the test var at a separate database); `testUrl` naming the *same env var* as `url` is reported as its own case. Applies to both the url/testUrl and appUrl/appTestUrl pairs.
|
|
8
|
+
- **Fix: `pipework generate` surfaces the real config-load error instead of misreporting every failure as "No pipework.config.ts found".**
|
|
9
|
+
- **Behavior change: a database with `rls` configured whose runtime role is SUPERUSER or BYPASSRLS now fails startup validation and test bootstrap.** RLS policies never apply to such a role, so the entire tenant-isolation policy set is silently inert — the framework now says so, naming the database, the role, the flag, and the fix (provision a non-bypassing application role; point the runtime connection at it). At startup the probed connection is `appUrl ?? url`; at test bootstrap it is the connection tests actually execute on — transaction isolation collapses every role onto the resolved `url`, database/container isolation resolves roles normally. Consumers whose test role is the compose superuser are refused until they provision a non-bypassing test role — deliberate: that is exactly the world where an RLS test suite proves nothing.
|
|
10
|
+
- **Feature: `.env.local` and `.env.test.local` are loaded alongside `.env`/`.env.test`, with the `.local` (machine-local, never-committed) variant taking precedence** — the standard dotenv convention.
|
|
11
|
+
- **Docs: the `env` config field is now a first-class section in REFERENCE.md** — every declaration shape (`string`/`number`/`boolean`/`string[]`), `required`/`default`/per-environment `defaults`/`sensitive`, typed `manifold.env` access, and a complete `createManifold` example. Previously it appeared only inside a type signature, leaving the feature undiscoverable while consumers accumulated ad-hoc `process.env` reads. The reference generator now renders multi-line JSDoc and `@example` blocks as fenced code instead of flattening them to one line.
|
|
12
|
+
- **Behavior change: relative `migrations`/`schema` paths now resolve against the directory of `pipework.config.ts`, never against the process working directory.** Previously every consumer of these fields (`pipework generate`, `pipework migrate`'s safety gate, test template provisioning) resolved them against cwd — so `pnpm --filter <module> test` (which cd's into the module) failed at `beforeAll` with "No migration journal found", and the only workaround was hand-absolutizing the paths with `import.meta.url`. `ResolvedDatabase.migrations` is now absolute (resolved once, at config load), `ResolvedDatabase` carries the new `baseDir` field (the config file's directory), and schema globs are matched against `baseDir`. Already-absolute consumer paths are unchanged (`resolve(base, abs) === abs`). Breaking for API consumers: `generateForDatabase` loses its `cwd` parameter — the resolved config is the single source of path truth.
|
|
4
13
|
|
|
5
14
|
- **Fix: the migration tracker now records WHICH migrations have been applied (tag membership), replacing the `max(created_at)` timestamp high-water mark that silently skipped any unapplied migration dated earlier than the newest applied one.** Two real production hits of the old model: (1) two manifolds sharing one physical database under the same tracker table name (both declared database key `app`) — the second manifold's entire journal predated the first's newest entry, so its migrations were silently skipped and its schema never materialized; (2) a migration merged from a branch with an earlier date than migrations already applied was silently skipped ("relation does not exist" at runtime, in CI). The tracker table gains a `tag` column (unique) and `applyMigrations` decides "already applied" by membership: tag recorded → skip (after verifying the recorded content hash still matches — see below), tag absent → apply, in journal order. Existing deployed tracker tables are upgraded in place on the next `migrate`: the `tag` column is added and each legacy row's identity is recovered by matching its recorded content hash against the journal's files; rows matching no current journal entry keep a NULL tag and never participate in membership.
|
|
6
15
|
- **Fix: editing an already-applied migration file is now a loud error instead of silently ignored.** Membership verifies the recorded sha256 against the file: a tag recorded with a different hash aborts with an error naming the migration, the two hashes, and the fix (put schema changes in a NEW migration; if two manifolds share a database and collide on a tag, that is a schema-level collision no tracker can reconcile — separate databases or distinct `migrationTable` names).
|
package/REFERENCE.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# Pipework API Reference
|
|
2
2
|
|
|
3
3
|
> Auto-generated from source JSDoc. Do not edit manually.
|
|
4
|
-
> Generated: 2026-
|
|
4
|
+
> Generated: 2026-07-16
|
|
5
5
|
|
|
6
6
|
## Contents
|
|
7
7
|
|
|
8
8
|
- [Core](#core)
|
|
9
|
+
- [env — Environment Variables](#env-environment-variables)
|
|
9
10
|
- [jobs — Background Jobs](#jobs-background-jobs)
|
|
10
11
|
- [pipeline — Multi-Step Pipelines](#pipeline-multi-step-pipelines)
|
|
11
12
|
- [state — State Machines](#state-state-machines)
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
- [http — Server](#http-server)
|
|
34
35
|
- [openapi — API Documentation](#openapi-api-documentation)
|
|
35
36
|
- [test](#test)
|
|
37
|
+
- [data](#data)
|
|
36
38
|
- [trace](#trace)
|
|
37
39
|
|
|
38
40
|
## Core
|
|
@@ -41,7 +43,29 @@ Application instance and foundational types.
|
|
|
41
43
|
|
|
42
44
|
### `createManifold`
|
|
43
45
|
|
|
44
|
-
Creates the Pipework application instance. This is the entry point for every Pipework app.
|
|
46
|
+
Creates the Pipework application instance. This is the entry point for every Pipework app.
|
|
47
|
+
Define in `pipework.config.ts` and export as default.
|
|
48
|
+
|
|
49
|
+
The `env` field declares the app's environment variables — the canonical
|
|
50
|
+
home for runtime config (ports, service tokens, bucket names, flags) in
|
|
51
|
+
place of scattered `process.env` reads. Each variable is read once at config
|
|
52
|
+
load, validated and coerced to its declared type (loud error on a bad or
|
|
53
|
+
missing-required value), and exposed typed on `manifold.env`.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const manifold = createManifold({
|
|
58
|
+
databases: { app: { url: 'DATABASE_URL', testUrl: 'DATABASE_URL_TEST' } },
|
|
59
|
+
env: {
|
|
60
|
+
PORT: { type: 'number', defaults: { development: '3000', test: '0' } },
|
|
61
|
+
S3_BUCKET: { type: 'string', required: true },
|
|
62
|
+
API_TOKEN: { type: 'string', required: true, sensitive: true },
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
manifold.env.PORT // number — from process.env.PORT, or the per-environment default
|
|
66
|
+
manifold.env.S3_BUCKET // string — startup fails loudly if unset
|
|
67
|
+
export default manifold
|
|
68
|
+
```
|
|
45
69
|
|
|
46
70
|
```typescript
|
|
47
71
|
function createManifold<const TEnv extends EnvDefs = EnvDefs>( raw: Omit<BlueprintInput, 'env'> &
|
|
@@ -79,6 +103,114 @@ interface IsolationState
|
|
|
79
103
|
interface ConnectionTracker
|
|
80
104
|
```
|
|
81
105
|
|
|
106
|
+
## env — Environment Variables
|
|
107
|
+
|
|
108
|
+
Declared environment variables — the canonical home for runtime config (ports, service tokens, bucket names, feature flags). Declare them under the `env` blueprint field; each is read once at config load, validated and coerced to its declared type (loud error on a bad or missing-required value), and exposed typed on `manifold.env` — in place of scattered ad-hoc `process.env` reads.
|
|
109
|
+
|
|
110
|
+
### Types
|
|
111
|
+
|
|
112
|
+
**`StringEnvVar`**
|
|
113
|
+
|
|
114
|
+
A string environment variable — resolved verbatim.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
S3_BUCKET: { type: 'string', required: true }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
interface StringEnvVar extends EnvVarBase
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**`NumberEnvVar`**
|
|
126
|
+
|
|
127
|
+
A number environment variable — parsed with a loud error on a non-numeric value.
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
PORT: { type: 'number', default: 3000 }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
interface NumberEnvVar extends EnvVarBase
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**`BooleanEnvVar`**
|
|
139
|
+
|
|
140
|
+
A boolean environment variable — accepts true/false/1/0, loud error otherwise.
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
FEATURE_GRAPH: { type: 'boolean', default: false }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
interface BooleanEnvVar extends EnvVarBase
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**`StringArrayEnvVar`**
|
|
152
|
+
|
|
153
|
+
A string-array environment variable — the raw value split on `separator`
|
|
154
|
+
(default `,`), each element trimmed.
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
CORS_ORIGINS: { type: 'string[]', separator: ',', default: [] }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
interface StringArrayEnvVar extends EnvVarBase
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**`EnvVarDef`**
|
|
166
|
+
|
|
167
|
+
One declared environment variable: its type, whether it is required, its
|
|
168
|
+
fallbacks, and whether the value is sensitive. Declared under the `env`
|
|
169
|
+
blueprint field; resolved once at config load and exposed typed on
|
|
170
|
+
`manifold.env` — the canonical replacement for ad-hoc `process.env` reads.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
type EnvVarDef = StringEnvVar | NumberEnvVar | BooleanEnvVar | StringArrayEnvVar
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**`EnvDefs`**
|
|
177
|
+
|
|
178
|
+
The `env` blueprint field: environment-variable declarations keyed by
|
|
179
|
+
variable name. Passing this map to `createManifold` is what types
|
|
180
|
+
`manifold.env`.
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
export default createManifold({
|
|
185
|
+
databases: { app: { url: 'DATABASE_URL', testUrl: 'DATABASE_URL_TEST' } },
|
|
186
|
+
env: {
|
|
187
|
+
PORT: { type: 'number', defaults: { development: '3000', test: '0' } },
|
|
188
|
+
S3_BUCKET: { type: 'string', required: true },
|
|
189
|
+
API_TOKEN: { type: 'string', required: true, sensitive: true },
|
|
190
|
+
CORS_ORIGINS: { type: 'string[]', default: [] },
|
|
191
|
+
},
|
|
192
|
+
})
|
|
193
|
+
// manifold.env.PORT → number
|
|
194
|
+
// manifold.env.S3_BUCKET → string
|
|
195
|
+
// manifold.env.CORS_ORIGINS → string[]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
type EnvDefs = Record<string, EnvVarDef>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**`ResolvedEnvType`** — The resolved runtime type of one declaration: 'string' → string, 'number' → number, 'boolean' → boolean, 'string[]' → string[].
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
type ResolvedEnvType<T extends EnvVarDef> =
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**`ResolveEnvDefs`** — Maps a declaration map to the shape of `manifold.env` — each key typed by its declared `type`.
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
type ResolveEnvDefs<T extends EnvDefs> =
|
|
212
|
+
```
|
|
213
|
+
|
|
82
214
|
## jobs — Background Jobs
|
|
83
215
|
|
|
84
216
|
Background job queue namespace — Postgres-backed with SKIP LOCKED, LISTEN/NOTIFY, cron scheduling.
|
|
@@ -564,6 +696,18 @@ interface ValueColumnDef
|
|
|
564
696
|
interface SerializableOptions
|
|
565
697
|
```
|
|
566
698
|
|
|
699
|
+
**`ManagedConnection`** — A standalone pooled connection: the raw postgres.js client, its drizzle handle, and a `close()` that ends the pool.
|
|
700
|
+
|
|
701
|
+
```typescript
|
|
702
|
+
interface ManagedConnection
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
**`ConnectOptions`** — Options for `tap()` — pool size (default 1) and idle timeout in seconds.
|
|
706
|
+
|
|
707
|
+
```typescript
|
|
708
|
+
interface ConnectOptions
|
|
709
|
+
```
|
|
710
|
+
|
|
567
711
|
## jsonb — JSONB Column Helpers
|
|
568
712
|
|
|
569
713
|
JSONB query operators — typed helpers for PostgreSQL JSONB containment, key checks, and field extraction.
|
|
@@ -1022,6 +1166,19 @@ Generates an OpenAPI 3.1 document from route registrations — schemas derived f
|
|
|
1022
1166
|
|
|
1023
1167
|
## test
|
|
1024
1168
|
|
|
1169
|
+
## data
|
|
1170
|
+
|
|
1171
|
+
### `tap`
|
|
1172
|
+
|
|
1173
|
+
Opens a standalone managed connection outside the manifold's pools — the
|
|
1174
|
+
sanctioned door for contexts where `pipe()` structurally cannot resolve:
|
|
1175
|
+
`worker_threads`, detached monitors, one-off scripts. Callers own the
|
|
1176
|
+
lifecycle: always `await conn.close()`.
|
|
1177
|
+
|
|
1178
|
+
```typescript
|
|
1179
|
+
function tap(url: string, options?: ConnectOptions): ManagedConnection
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1025
1182
|
## trace
|
|
1026
1183
|
|
|
1027
1184
|
### `__flowStep`
|
package/dist/REFERENCE.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# Pipework API Reference
|
|
2
2
|
|
|
3
3
|
> Auto-generated from source JSDoc. Do not edit manually.
|
|
4
|
-
> Generated: 2026-
|
|
4
|
+
> Generated: 2026-07-16
|
|
5
5
|
|
|
6
6
|
## Contents
|
|
7
7
|
|
|
8
8
|
- [Core](#core)
|
|
9
|
+
- [env — Environment Variables](#env-environment-variables)
|
|
9
10
|
- [jobs — Background Jobs](#jobs-background-jobs)
|
|
10
11
|
- [pipeline — Multi-Step Pipelines](#pipeline-multi-step-pipelines)
|
|
11
12
|
- [state — State Machines](#state-state-machines)
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
- [http — Server](#http-server)
|
|
34
35
|
- [openapi — API Documentation](#openapi-api-documentation)
|
|
35
36
|
- [test](#test)
|
|
37
|
+
- [data](#data)
|
|
36
38
|
- [trace](#trace)
|
|
37
39
|
|
|
38
40
|
## Core
|
|
@@ -41,7 +43,29 @@ Application instance and foundational types.
|
|
|
41
43
|
|
|
42
44
|
### `createManifold`
|
|
43
45
|
|
|
44
|
-
Creates the Pipework application instance. This is the entry point for every Pipework app.
|
|
46
|
+
Creates the Pipework application instance. This is the entry point for every Pipework app.
|
|
47
|
+
Define in `pipework.config.ts` and export as default.
|
|
48
|
+
|
|
49
|
+
The `env` field declares the app's environment variables — the canonical
|
|
50
|
+
home for runtime config (ports, service tokens, bucket names, flags) in
|
|
51
|
+
place of scattered `process.env` reads. Each variable is read once at config
|
|
52
|
+
load, validated and coerced to its declared type (loud error on a bad or
|
|
53
|
+
missing-required value), and exposed typed on `manifold.env`.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const manifold = createManifold({
|
|
58
|
+
databases: { app: { url: 'DATABASE_URL', testUrl: 'DATABASE_URL_TEST' } },
|
|
59
|
+
env: {
|
|
60
|
+
PORT: { type: 'number', defaults: { development: '3000', test: '0' } },
|
|
61
|
+
S3_BUCKET: { type: 'string', required: true },
|
|
62
|
+
API_TOKEN: { type: 'string', required: true, sensitive: true },
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
manifold.env.PORT // number — from process.env.PORT, or the per-environment default
|
|
66
|
+
manifold.env.S3_BUCKET // string — startup fails loudly if unset
|
|
67
|
+
export default manifold
|
|
68
|
+
```
|
|
45
69
|
|
|
46
70
|
```typescript
|
|
47
71
|
function createManifold<const TEnv extends EnvDefs = EnvDefs>( raw: Omit<BlueprintInput, 'env'> &
|
|
@@ -79,6 +103,114 @@ interface IsolationState
|
|
|
79
103
|
interface ConnectionTracker
|
|
80
104
|
```
|
|
81
105
|
|
|
106
|
+
## env — Environment Variables
|
|
107
|
+
|
|
108
|
+
Declared environment variables — the canonical home for runtime config (ports, service tokens, bucket names, feature flags). Declare them under the `env` blueprint field; each is read once at config load, validated and coerced to its declared type (loud error on a bad or missing-required value), and exposed typed on `manifold.env` — in place of scattered ad-hoc `process.env` reads.
|
|
109
|
+
|
|
110
|
+
### Types
|
|
111
|
+
|
|
112
|
+
**`StringEnvVar`**
|
|
113
|
+
|
|
114
|
+
A string environment variable — resolved verbatim.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
S3_BUCKET: { type: 'string', required: true }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
interface StringEnvVar extends EnvVarBase
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**`NumberEnvVar`**
|
|
126
|
+
|
|
127
|
+
A number environment variable — parsed with a loud error on a non-numeric value.
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
PORT: { type: 'number', default: 3000 }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
interface NumberEnvVar extends EnvVarBase
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**`BooleanEnvVar`**
|
|
139
|
+
|
|
140
|
+
A boolean environment variable — accepts true/false/1/0, loud error otherwise.
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
FEATURE_GRAPH: { type: 'boolean', default: false }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
interface BooleanEnvVar extends EnvVarBase
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**`StringArrayEnvVar`**
|
|
152
|
+
|
|
153
|
+
A string-array environment variable — the raw value split on `separator`
|
|
154
|
+
(default `,`), each element trimmed.
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
CORS_ORIGINS: { type: 'string[]', separator: ',', default: [] }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
interface StringArrayEnvVar extends EnvVarBase
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**`EnvVarDef`**
|
|
166
|
+
|
|
167
|
+
One declared environment variable: its type, whether it is required, its
|
|
168
|
+
fallbacks, and whether the value is sensitive. Declared under the `env`
|
|
169
|
+
blueprint field; resolved once at config load and exposed typed on
|
|
170
|
+
`manifold.env` — the canonical replacement for ad-hoc `process.env` reads.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
type EnvVarDef = StringEnvVar | NumberEnvVar | BooleanEnvVar | StringArrayEnvVar
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**`EnvDefs`**
|
|
177
|
+
|
|
178
|
+
The `env` blueprint field: environment-variable declarations keyed by
|
|
179
|
+
variable name. Passing this map to `createManifold` is what types
|
|
180
|
+
`manifold.env`.
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
export default createManifold({
|
|
185
|
+
databases: { app: { url: 'DATABASE_URL', testUrl: 'DATABASE_URL_TEST' } },
|
|
186
|
+
env: {
|
|
187
|
+
PORT: { type: 'number', defaults: { development: '3000', test: '0' } },
|
|
188
|
+
S3_BUCKET: { type: 'string', required: true },
|
|
189
|
+
API_TOKEN: { type: 'string', required: true, sensitive: true },
|
|
190
|
+
CORS_ORIGINS: { type: 'string[]', default: [] },
|
|
191
|
+
},
|
|
192
|
+
})
|
|
193
|
+
// manifold.env.PORT → number
|
|
194
|
+
// manifold.env.S3_BUCKET → string
|
|
195
|
+
// manifold.env.CORS_ORIGINS → string[]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
type EnvDefs = Record<string, EnvVarDef>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**`ResolvedEnvType`** — The resolved runtime type of one declaration: 'string' → string, 'number' → number, 'boolean' → boolean, 'string[]' → string[].
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
type ResolvedEnvType<T extends EnvVarDef> =
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**`ResolveEnvDefs`** — Maps a declaration map to the shape of `manifold.env` — each key typed by its declared `type`.
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
type ResolveEnvDefs<T extends EnvDefs> =
|
|
212
|
+
```
|
|
213
|
+
|
|
82
214
|
## jobs — Background Jobs
|
|
83
215
|
|
|
84
216
|
Background job queue namespace — Postgres-backed with SKIP LOCKED, LISTEN/NOTIFY, cron scheduling.
|
|
@@ -564,6 +696,18 @@ interface ValueColumnDef
|
|
|
564
696
|
interface SerializableOptions
|
|
565
697
|
```
|
|
566
698
|
|
|
699
|
+
**`ManagedConnection`** — A standalone pooled connection: the raw postgres.js client, its drizzle handle, and a `close()` that ends the pool.
|
|
700
|
+
|
|
701
|
+
```typescript
|
|
702
|
+
interface ManagedConnection
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
**`ConnectOptions`** — Options for `tap()` — pool size (default 1) and idle timeout in seconds.
|
|
706
|
+
|
|
707
|
+
```typescript
|
|
708
|
+
interface ConnectOptions
|
|
709
|
+
```
|
|
710
|
+
|
|
567
711
|
## jsonb — JSONB Column Helpers
|
|
568
712
|
|
|
569
713
|
JSONB query operators — typed helpers for PostgreSQL JSONB containment, key checks, and field extraction.
|
|
@@ -1022,6 +1166,19 @@ Generates an OpenAPI 3.1 document from route registrations — schemas derived f
|
|
|
1022
1166
|
|
|
1023
1167
|
## test
|
|
1024
1168
|
|
|
1169
|
+
## data
|
|
1170
|
+
|
|
1171
|
+
### `tap`
|
|
1172
|
+
|
|
1173
|
+
Opens a standalone managed connection outside the manifold's pools — the
|
|
1174
|
+
sanctioned door for contexts where `pipe()` structurally cannot resolve:
|
|
1175
|
+
`worker_threads`, detached monitors, one-off scripts. Callers own the
|
|
1176
|
+
lifecycle: always `await conn.close()`.
|
|
1177
|
+
|
|
1178
|
+
```typescript
|
|
1179
|
+
function tap(url: string, options?: ConnectOptions): ManagedConnection
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1025
1182
|
## trace
|
|
1026
1183
|
|
|
1027
1184
|
### `__flowStep`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAA;IACtB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAA;IACtB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0D7E"}
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
import { info, success, warn, error as logError } from '../output.js';
|
|
2
2
|
export async function generate(options) {
|
|
3
|
-
const { discoverInstance } = await import('../../core/config/discover.js');
|
|
3
|
+
const { discoverInstance, findConfig } = await import('../../core/config/discover.js');
|
|
4
4
|
const { generateForDatabase } = await import('../../data/migrate/generate.js');
|
|
5
5
|
const { loadInternalDefinitions } = await import('../../data/migrate/internal-definitions.js');
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
instance = await discoverInstance(options.cwd);
|
|
9
|
-
}
|
|
10
|
-
catch {
|
|
6
|
+
if (findConfig(options.cwd) === null) {
|
|
11
7
|
logError('No pipework.config.ts found.\n\n' +
|
|
12
8
|
' Run `pipework init` to create one.\n');
|
|
13
9
|
process.exit(1);
|
|
14
10
|
}
|
|
11
|
+
// A config that exists but fails to load (missing env var, refused
|
|
12
|
+
// url/testUrl identity, …) must surface its real error, not be misreported
|
|
13
|
+
// as a missing config.
|
|
14
|
+
const instance = await discoverInstance(options.cwd);
|
|
15
15
|
const defaultDbName = instance.config.defaultDatabaseName();
|
|
16
16
|
try {
|
|
17
17
|
if (options.db !== undefined) {
|
|
18
18
|
const dbConfig = instance.config.database(options.db);
|
|
19
19
|
info(`Generating migration for database: ${options.db}`);
|
|
20
|
-
|
|
20
|
+
// Passed as a thunk so queue registrations made by glob-imported schema
|
|
21
|
+
// modules (inside generateForDatabase) are visible when it runs.
|
|
22
|
+
const internal = () => loadInternalDefinitions(instance.config.raw, {
|
|
21
23
|
isDefaultDatabase: options.db === defaultDbName,
|
|
22
24
|
});
|
|
23
|
-
const result = await generateForDatabase(dbConfig, options.
|
|
25
|
+
const result = await generateForDatabase(dbConfig, options.name, internal);
|
|
24
26
|
if (result.migrationFile === null) {
|
|
25
27
|
warn(`${options.db}: no schema changes detected`);
|
|
26
28
|
}
|
|
@@ -34,10 +36,10 @@ export async function generate(options) {
|
|
|
34
36
|
for (const [, dbConfig] of instance.config.databases()) {
|
|
35
37
|
if (dbConfig.schema === undefined)
|
|
36
38
|
continue;
|
|
37
|
-
const internal =
|
|
39
|
+
const internal = () => loadInternalDefinitions(instance.config.raw, {
|
|
38
40
|
isDefaultDatabase: dbConfig.name === defaultDbName,
|
|
39
41
|
});
|
|
40
|
-
const result = await generateForDatabase(dbConfig, options.
|
|
42
|
+
const result = await generateForDatabase(dbConfig, options.name, internal);
|
|
41
43
|
if (result.migrationFile === null) {
|
|
42
44
|
warn(`${dbConfig.name}: no schema changes detected`);
|
|
43
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AAQrE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAA+B;IAC5D,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function setConfigBaseDir(dir: string): void;
|
|
2
|
+
/** Read-and-clear. Undefined when no config import is in flight — directly-constructed configs resolve against process.cwd(). */
|
|
3
|
+
export declare function consumeConfigBaseDir(): string | undefined;
|
|
4
|
+
/** Cleared in the importer's finally: an ESM cache hit skips loadConfig, and the stale slot must not leak into a later directly-constructed loadConfig. */
|
|
5
|
+
export declare function clearConfigBaseDir(): void;
|
|
6
|
+
//# sourceMappingURL=base-dir.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-dir.d.ts","sourceRoot":"","sources":["../../../src/core/config/base-dir.ts"],"names":[],"mappings":"AASA,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,iIAAiI;AACjI,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,SAAS,CAIzD;AAED,2JAA2J;AAC3J,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// The directory relative `migrations`/`schema` paths resolve against (D1,
|
|
2
|
+
// subseam audit 2026-07-16). Set from the config file's directory immediately
|
|
3
|
+
// before the config module is imported; consumed exactly once by loadConfig.
|
|
4
|
+
// A module-level slot rather than a parameter because the config file itself
|
|
5
|
+
// calls createManifold() during its own import — there is no call chain to
|
|
6
|
+
// thread the value through.
|
|
7
|
+
let configBaseDir;
|
|
8
|
+
export function setConfigBaseDir(dir) {
|
|
9
|
+
configBaseDir = dir;
|
|
10
|
+
}
|
|
11
|
+
/** Read-and-clear. Undefined when no config import is in flight — directly-constructed configs resolve against process.cwd(). */
|
|
12
|
+
export function consumeConfigBaseDir() {
|
|
13
|
+
const dir = configBaseDir;
|
|
14
|
+
configBaseDir = undefined;
|
|
15
|
+
return dir;
|
|
16
|
+
}
|
|
17
|
+
/** Cleared in the importer's finally: an ESM cache hit skips loadConfig, and the stale slot must not leak into a later directly-constructed loadConfig. */
|
|
18
|
+
export function clearConfigBaseDir() {
|
|
19
|
+
configBaseDir = undefined;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=base-dir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-dir.js","sourceRoot":"","sources":["../../../src/core/config/base-dir.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,8EAA8E;AAC9E,6EAA6E;AAC7E,6EAA6E;AAC7E,2EAA2E;AAC3E,4BAA4B;AAE5B,IAAI,aAAiC,CAAA;AAErC,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,aAAa,GAAG,GAAG,CAAA;AACrB,CAAC;AAED,iIAAiI;AACjI,MAAM,UAAU,oBAAoB;IAClC,MAAM,GAAG,GAAG,aAAa,CAAA;IACzB,aAAa,GAAG,SAAS,CAAA;IACzB,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,2JAA2J;AAC3J,MAAM,UAAU,kBAAkB;IAChC,aAAa,GAAG,SAAS,CAAA;AAC3B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../../src/core/config/discover.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../../src/core/config/discover.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAM9C,wBAAgB,sBAAsB,IAAI,IAAI,CAsD7C;AAED,wBAAsB,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CActE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYtD"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { resolve, dirname } from 'node:path';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
-
import { pathToFileURL } from 'node:url';
|
|
4
3
|
import { register } from 'node:module';
|
|
5
4
|
import { ConfigError } from './errors.js';
|
|
5
|
+
import { importConfig } from './import-config.js';
|
|
6
6
|
const CONFIG_FILENAME = 'pipework.config.ts';
|
|
7
7
|
export function registerTsResolveHooks() {
|
|
8
8
|
{
|
|
@@ -66,20 +66,7 @@ export async function discoverInstance(cwd) {
|
|
|
66
66
|
throw new ConfigError(`No ${CONFIG_FILENAME} found in ${start} or any parent directory.`, `Create one with \`pipework init\`, or see the getting-started guide.`);
|
|
67
67
|
}
|
|
68
68
|
registerTsResolveHooks();
|
|
69
|
-
|
|
70
|
-
const mod = await import(configUrl);
|
|
71
|
-
const exported = mod['default'] ?? mod;
|
|
72
|
-
if (!isManifold(exported)) {
|
|
73
|
-
throw new ConfigError(`${CONFIG_FILENAME} must export a Pipework instance as its default export.`, `Your config should look like:\n\n` +
|
|
74
|
-
` import { createManifold } from 'pipework'\n\n` +
|
|
75
|
-
` export default createManifold({\n` +
|
|
76
|
-
` databases: { app: { url: 'DATABASE_URL' } },\n` +
|
|
77
|
-
` })\n`);
|
|
78
|
-
}
|
|
79
|
-
return exported;
|
|
80
|
-
}
|
|
81
|
-
function isManifold(v) {
|
|
82
|
-
return typeof v === 'object' && v !== null && 'pool' in v && 'config' in v;
|
|
69
|
+
return importConfig(configPath);
|
|
83
70
|
}
|
|
84
71
|
export function findConfig(from) {
|
|
85
72
|
let dir = resolve(from);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/core/config/discover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/core/config/discover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,MAAM,eAAe,GAAG,oBAAoB,CAAA;AAE5C,MAAM,UAAU,sBAAsB;IACpC,CAAC;QACC,+EAA+E;QAC/E,qEAAqE;QACrE,8EAA8E;QAC9E,+EAA+E;QAC/E,+DAA+D;QAC/D,gFAAgF;QAChF,qEAAqE;QACrE,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0CZ,CAAA;QACD,QAAQ,CAAC,wBAAwB,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC9D,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAY;IACjD,MAAM,KAAK,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IAClC,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;IAEpC,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,MAAM,IAAI,WAAW,CACnB,MAAM,eAAe,aAAa,KAAK,2BAA2B,EAClE,sEAAsE,CACvE,CAAA;IACH,CAAC;IAED,sBAAsB,EAAE,CAAA;IAExB,OAAO,YAAY,CAAC,UAAU,CAAC,CAAA;AACjC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IACzB,OAAO,GAAG,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAA;QAC/C,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAA;QAC3C,GAAG,GAAG,MAAM,CAAA;QACZ,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IACvB,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAA;IAC1C,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACjC,OAAO,IAAI,CAAA;AACb,CAAC"}
|