@cedarjs/pg 0.2.0-alpha.0 → 0.2.0-beta.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/README.md +250 -229
- package/dist/cli.cjs +89 -39
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +73 -23
- package/dist/cli.mjs.map +1 -1
- package/dist/dev-env.cjs +1 -1
- package/dist/dev-env.mjs +1 -1
- package/dist/index.cjs +9 -8
- package/dist/index.d.cts +31 -3
- package/dist/index.d.mts +31 -3
- package/dist/index.mjs +7 -7
- package/dist/jest-teardown.cjs +1 -1
- package/dist/jest-teardown.mjs +1 -1
- package/dist/jest-template.cjs +4 -1
- package/dist/jest-template.cjs.map +1 -1
- package/dist/jest-template.d.cts +4 -1
- package/dist/jest-template.d.mts +4 -1
- package/dist/jest-template.mjs +4 -1
- package/dist/jest-template.mjs.map +1 -1
- package/dist/jest.cjs +1 -1
- package/dist/jest.mjs +1 -1
- package/dist/{lease-BSBBpaR4.mjs → lease-DS1SX8U_.mjs} +23 -3
- package/dist/lease-DS1SX8U_.mjs.map +1 -0
- package/dist/{lease-Bq9wKwQa.cjs → lease-WlmOnNDi.cjs} +41 -3
- package/dist/lease-WlmOnNDi.cjs.map +1 -0
- package/dist/{lifecycle-DEJ4GgWV.cjs → lifecycle-BbrvFQvg.cjs} +175 -78
- package/dist/lifecycle-BbrvFQvg.cjs.map +1 -0
- package/dist/{lifecycle-BOo6xBjD.mjs → lifecycle-BvIx0xqq.mjs} +175 -78
- package/dist/lifecycle-BvIx0xqq.mjs.map +1 -0
- package/dist/{load-dev-env-7UjMHhw7.mjs → load-dev-env-BULkXyen.mjs} +2 -2
- package/dist/{load-dev-env-7UjMHhw7.mjs.map → load-dev-env-BULkXyen.mjs.map} +1 -1
- package/dist/{load-dev-env-cII6N4ZP.cjs → load-dev-env-Bl6Ddv1U.cjs} +2 -2
- package/dist/{load-dev-env-cII6N4ZP.cjs.map → load-dev-env-Bl6Ddv1U.cjs.map} +1 -1
- package/dist/{load-mode-env-B0qO9DZx.cjs → load-mode-env-CX9vd56X.cjs} +2 -2
- package/dist/{load-mode-env-B0qO9DZx.cjs.map → load-mode-env-CX9vd56X.cjs.map} +1 -1
- package/dist/{load-mode-env-C8gy4v9V.mjs → load-mode-env-Ce9ujisN.mjs} +2 -2
- package/dist/{load-mode-env-C8gy4v9V.mjs.map → load-mode-env-Ce9ujisN.mjs.map} +1 -1
- package/dist/{load-test-env-C34wpkIX.mjs → load-test-env-BqtA6V-d.mjs} +2 -2
- package/dist/{load-test-env-C34wpkIX.mjs.map → load-test-env-BqtA6V-d.mjs.map} +1 -1
- package/dist/{load-test-env-CkdUjTpV.cjs → load-test-env-Dcgh6YHV.cjs} +2 -2
- package/dist/{load-test-env-CkdUjTpV.cjs.map → load-test-env-Dcgh6YHV.cjs.map} +1 -1
- package/dist/nx.cjs +12 -14
- package/dist/nx.cjs.map +1 -1
- package/dist/nx.mjs +10 -12
- package/dist/nx.mjs.map +1 -1
- package/dist/status-4Uz6A3LB.cjs +31 -0
- package/dist/status-4Uz6A3LB.cjs.map +1 -0
- package/dist/status-Dcnpgnlz.mjs +26 -0
- package/dist/status-Dcnpgnlz.mjs.map +1 -0
- package/dist/studio-DIFw1qWC.mjs +173 -0
- package/dist/studio-DIFw1qWC.mjs.map +1 -0
- package/dist/studio-oJE30_PO.cjs +208 -0
- package/dist/studio-oJE30_PO.cjs.map +1 -0
- package/dist/{tasks-Caud9yHr.cjs → tasks-CNHvvlsN.cjs} +4 -4
- package/dist/{tasks-Caud9yHr.cjs.map → tasks-CNHvvlsN.cjs.map} +1 -1
- package/dist/{tasks-KherHLac.mjs → tasks-D5iWIdlo.mjs} +2 -2
- package/dist/{tasks-KherHLac.mjs.map → tasks-D5iWIdlo.mjs.map} +1 -1
- package/dist/{template-CGw3C1Ob.mjs → template-BiJ-0TIF.mjs} +3 -3
- package/dist/{template-CGw3C1Ob.mjs.map → template-BiJ-0TIF.mjs.map} +1 -1
- package/dist/{template-D0gJ_MS2.cjs → template-CXMpODzK.cjs} +3 -3
- package/dist/{template-D0gJ_MS2.cjs.map → template-CXMpODzK.cjs.map} +1 -1
- package/dist/{template-mode-IjlFOG4O.mjs → template-mode-BTUsdBtA.mjs} +27 -13
- package/dist/template-mode-BTUsdBtA.mjs.map +1 -0
- package/dist/{template-mode-CcxV_Iju.d.cts → template-mode-CzyVwHsi.d.cts} +4 -1
- package/dist/{template-mode-CcxV_Iju.d.mts → template-mode-CzyVwHsi.d.mts} +4 -1
- package/dist/{template-mode-BkEs9LnY.cjs → template-mode-JTOxrEgE.cjs} +27 -13
- package/dist/template-mode-JTOxrEgE.cjs.map +1 -0
- package/dist/test-env.cjs +1 -1
- package/dist/test-env.mjs +1 -1
- package/dist/vite-plus.cjs +107 -4
- package/dist/vite-plus.cjs.map +1 -1
- package/dist/vite-plus.d.cts +25 -1
- package/dist/vite-plus.d.mts +25 -1
- package/dist/vite-plus.mjs +108 -5
- package/dist/vite-plus.mjs.map +1 -1
- package/dist/vitest-template.cjs +1 -1
- package/dist/vitest-template.d.cts +1 -1
- package/dist/vitest-template.d.mts +1 -1
- package/dist/vitest-template.mjs +1 -1
- package/dist/vitest.cjs +1 -1
- package/dist/vitest.mjs +1 -1
- package/package.json +11 -2
- package/dist/constants-Ct8myrEn.cjs +0 -41
- package/dist/constants-Ct8myrEn.cjs.map +0 -1
- package/dist/constants-NLR0U4NR.mjs +0 -24
- package/dist/constants-NLR0U4NR.mjs.map +0 -1
- package/dist/lease-BSBBpaR4.mjs.map +0 -1
- package/dist/lease-Bq9wKwQa.cjs.map +0 -1
- package/dist/lifecycle-BOo6xBjD.mjs.map +0 -1
- package/dist/lifecycle-DEJ4GgWV.cjs.map +0 -1
- package/dist/template-mode-BkEs9LnY.cjs.map +0 -1
- package/dist/template-mode-IjlFOG4O.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,95 +1,62 @@
|
|
|
1
1
|
# cedar-pg
|
|
2
2
|
|
|
3
|
-
Worktree-isolated local Postgres for
|
|
3
|
+
Worktree-isolated local Postgres for Vite+, Nx, and CedarJS. The host is [autopg](https://github.com/automagik-dev/autopg) (embedded PostgreSQL 18). cedar-pg creates one database and role per git worktree so parallel checkouts do not share a DB.
|
|
4
4
|
|
|
5
|
-
Published
|
|
5
|
+
Published as `@cedarjs/pg`. CLI: `cedarpg`. Beta (`0.2.0-beta.0`, `beta` dist-tag). Public APIs may still change.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
autopg runs embedded PostgreSQL 18 (not WASM) with real concurrent connections. No credentials, zero config, and databases are provisioned on first use. Any client works (`psql`, `node-postgres`, Prisma, Drizzle, TypeORM).
|
|
12
|
-
|
|
13
|
-
### Development & testing
|
|
14
|
-
|
|
15
|
-
| Use case | What you get |
|
|
16
|
-
| ----------------------- | ------------------------------------------ |
|
|
17
|
-
| **Local development** | PostgreSQL without Docker |
|
|
18
|
-
| **Integration testing** | Real PostgreSQL, not mocks |
|
|
19
|
-
| **CI/CD pipelines** | Fresh databases per test run |
|
|
20
|
-
| **E2E testing** | Isolated database for Playwright / Cypress |
|
|
21
|
-
|
|
22
|
-
## What cedar-pg adds
|
|
23
|
-
|
|
24
|
-
**cedar-pg** gives each **git worktree** its own database and role on that autopg host (readable names, leases, teardown) so parallel checkouts do not share one DB:
|
|
25
|
-
|
|
26
|
-
- **1 database per git worktree** (visible in `\l` as `cpg_…`)
|
|
27
|
-
- **dev** DBs persist across restarts; **test** DBs drop on dispose
|
|
28
|
-
- First-class **Vite+ Task** + **Nx** / Vitest / Jest adapters
|
|
29
|
-
- `postinstall` ensures the pinned `autopg` binary when missing
|
|
30
|
-
|
|
31
|
-
| Layer | Responsibility |
|
|
32
|
-
| ------------ | ------------------------------------------------------------------- |
|
|
33
|
-
| **autopg** | Embedded Postgres host (concurrent, zero-config, auto-provision) |
|
|
34
|
-
| **cedar-pg** | Per-worktree `CREATE DATABASE` / role, `DATABASE_URL`, dispose + GC |
|
|
7
|
+
| Layer | Owns |
|
|
8
|
+
| -------- | --------------------------------------------------------------------------------- |
|
|
9
|
+
| autopg | Postgres process, port, concurrent connections |
|
|
10
|
+
| cedar-pg | Per-worktree `CREATE DATABASE` and role, lease files, `DATABASE_URL`, dispose, GC |
|
|
35
11
|
|
|
36
12
|
## Install
|
|
37
13
|
|
|
38
|
-
|
|
39
|
-
npm install -D @cedarjs/pg@alpha
|
|
40
|
-
# or: pnpm add -D @cedarjs/pg@alpha
|
|
41
|
-
# or: yarn add -D @cedarjs/pg@alpha
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Database names (observability)
|
|
14
|
+
Node `>=24`.
|
|
45
15
|
|
|
46
|
-
```
|
|
47
|
-
|
|
16
|
+
```bash
|
|
17
|
+
npm install -D @cedarjs/pg@beta
|
|
18
|
+
# pnpm add -D @cedarjs/pg@beta
|
|
19
|
+
# yarn add -D @cedarjs/pg@beta
|
|
48
20
|
```
|
|
49
21
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
| Name | Meaning |
|
|
53
|
-
| ----------------------------------- | -------------------------- |
|
|
54
|
-
| `cpg_cedar_cedar_dev_a1b2c3d4` | main `cedar` checkout, dev |
|
|
55
|
-
| `cpg_cedar_feat_auth_test_e5f67890` | worktree `feat-auth`, test |
|
|
22
|
+
`postinstall` installs the pinned autopg binary when it is missing. The pin is `scripts/autopg-version`. To bump autopg, change that file.
|
|
56
23
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
A running [autopg](https://github.com/automagik-dev/autopg) host (installed automatically by `postinstall`, or manually).
|
|
60
|
-
The release pin lives in **`scripts/autopg-version`** (single source of truth for postinstall, CI binary install, and docs). Bump that file to upgrade:
|
|
24
|
+
To install the host by hand (local, non-CI; upstream `install.sh` may use pm2):
|
|
61
25
|
|
|
62
26
|
```bash
|
|
63
|
-
# local / non-CI (upstream install.sh; may use pm2)
|
|
64
27
|
VER=$(tr -d '[:space:]' < scripts/autopg-version)
|
|
65
28
|
curl -fsSL "https://raw.githubusercontent.com/automagik-dev/autopg/${VER}/install.sh" \
|
|
66
29
|
| AUTOPG_VERSION="$VER" bash
|
|
67
30
|
```
|
|
68
31
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
## Develop this package (Vite+)
|
|
32
|
+
Once per machine, run the host (`autopg daemon`, or your usual install). Then per worktree:
|
|
72
33
|
|
|
73
34
|
```bash
|
|
74
|
-
|
|
75
|
-
vp check
|
|
76
|
-
vp test
|
|
77
|
-
vp pack # → dist/ (dts + esm + cjs)
|
|
78
|
-
vp run smoke # build → npm-pack tarball → install + resolve exports
|
|
79
|
-
vp run smoke:pg # pack → Vitest + Jest adapters against real ephemeral Postgres
|
|
35
|
+
cedarpg acquire --mode=dev
|
|
80
36
|
```
|
|
81
37
|
|
|
82
|
-
|
|
38
|
+
Connect with the printed `DATABASE_URL`.
|
|
39
|
+
|
|
40
|
+
From another checkout of this repo, pack first, then depend on the build:
|
|
83
41
|
|
|
84
42
|
```bash
|
|
85
|
-
# in this repo
|
|
86
43
|
vp pack
|
|
44
|
+
# in the app: yarn add @cedarjs/pg@file:../cedar-pg
|
|
45
|
+
# or install the tarball vp pack writes (name includes the version in package.json)
|
|
46
|
+
```
|
|
87
47
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
48
|
+
## Acquire a database
|
|
49
|
+
|
|
50
|
+
`dev` databases persist across restarts. `test` databases drop on `dispose`.
|
|
51
|
+
|
|
52
|
+
Names look like this (visible in `psql` `\l`):
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
cpg_<repo>_<worktree>_<mode>_<pathHash8>
|
|
91
56
|
```
|
|
92
57
|
|
|
58
|
+
Worktree state lives in `.cedarpg`. Import `STATE_DIRNAME` instead of hardcoding that string. `gc` uses `~/.cedarpg/registry`.
|
|
59
|
+
|
|
93
60
|
## CLI
|
|
94
61
|
|
|
95
62
|
```bash
|
|
@@ -99,24 +66,69 @@ cedarpg run --mode=dev -- yarn tsx scripts/apiServer/dev.ts
|
|
|
99
66
|
cedarpg run --mode=test -- vitest run
|
|
100
67
|
cedarpg dispose --mode=test
|
|
101
68
|
cedarpg print-url --mode=dev
|
|
102
|
-
cedarpg
|
|
69
|
+
cedarpg status --mode=dev
|
|
70
|
+
cedarpg studio --mode=dev # Prisma or Drizzle Studio (--prisma / --drizzle)
|
|
71
|
+
cedarpg gc # drop DBs whose worktree root is gone
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`status` and `studio` are read-only. They do not acquire. `studio` walks from cwd up to the worktree.
|
|
75
|
+
|
|
76
|
+
`cedarpg run` acquires or attaches the lease, then execs the command. The child always gets `DATABASE_URL` from the lease. In test mode it also gets `TEST_DATABASE_URL`. `--force` only sets `CEDAR_PG_FORCE=1`, so nested adapters do not treat an ambient URL as an escape hatch.
|
|
77
|
+
|
|
78
|
+
If two targets run `cedarpg acquire` or `cedarpg run` on the same worktree, role and database DDL can race. Use one acquire, then `run` wrappers.
|
|
79
|
+
|
|
80
|
+
## Vite+
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// vite.config.ts
|
|
84
|
+
import { defineConfig } from "vite-plus";
|
|
85
|
+
import { cedarPgTasks, cedarPgDev } from "@cedarjs/pg/vite-plus";
|
|
86
|
+
|
|
87
|
+
export default defineConfig({
|
|
88
|
+
plugins: [cedarPgDev()],
|
|
89
|
+
run: {
|
|
90
|
+
tasks: {
|
|
91
|
+
...cedarPgTasks(),
|
|
92
|
+
test: {
|
|
93
|
+
command: "vp test",
|
|
94
|
+
dependsOn: ["db:acquire-test"],
|
|
95
|
+
env: ["DATABASE_URL", "TEST_DATABASE_URL"],
|
|
96
|
+
},
|
|
97
|
+
dev: {
|
|
98
|
+
command: "vp dev",
|
|
99
|
+
dependsOn: ["db:acquire"],
|
|
100
|
+
env: ["DATABASE_URL"],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
});
|
|
103
105
|
```
|
|
104
106
|
|
|
105
|
-
`
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
`cedarPgDev()` does not acquire. Keep `dependsOn: ["db:acquire"]`. On listen it prints a status panel (TTY, non-CI). Vite CLI shortcuts (`key` then Enter; also listed under `h`):
|
|
108
|
+
|
|
109
|
+
| Key | Action |
|
|
110
|
+
| --- | ---------------------------------------------------------------------- |
|
|
111
|
+
| `d` | Reprint status (name, port, `DATABASE_URL`, env file) |
|
|
112
|
+
| `s` | Open Prisma Studio or Drizzle Kit Studio with the lease `DATABASE_URL` |
|
|
113
|
+
|
|
114
|
+
Options: `cedarPgDev({ mode, root, cwd, studio: "prisma" | "drizzle" | false })`. Studio walks from `cwd` (default Vite `config.root`) up to the worktree, so an Nx `apps/...` package is found without moving the lease. `prisma` wins when both ORMs sit in the same package.
|
|
108
115
|
|
|
109
|
-
|
|
116
|
+
Shortcuts bind on Vite 8 and vite-plus. Vite 7 and Cedar print the listen panel only. Use `cedarpg status` and `cedarpg studio` for Nx and other non-Vite hosts.
|
|
110
117
|
|
|
111
|
-
Nx
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
## Nx
|
|
119
|
+
|
|
120
|
+
Nx `dependsOn` does not forward env from an acquire task into dependents. Vite+ `env: [...]` does. Canonical shape:
|
|
121
|
+
|
|
122
|
+
1. One `db:ready` (or `createAcquireTask`) that acquires and migrates.
|
|
123
|
+
2. Wrap API, dev, and e2e children with `cedarpg run --mode=dev --force -- <cmd>`.
|
|
124
|
+
|
|
125
|
+
Pointing Nx `envFile` at `.cedarpg/<mode>.env` after acquire still loses to an ambient `.env` unless you also force or overwrite.
|
|
114
126
|
|
|
115
127
|
```ts
|
|
116
128
|
import { cedarPgNxTargets, cedarPgRunCommand, relativeEnvFile } from "@cedarjs/pg/nx";
|
|
117
129
|
|
|
118
130
|
cedarPgNxTargets();
|
|
119
|
-
// { "db:acquire": { command: "cedarpg acquire --mode=dev", cache: false },
|
|
131
|
+
// { "db:acquire": { command: "cedarpg acquire --mode=dev", cache: false }, ... }
|
|
120
132
|
|
|
121
133
|
cedarPgRunCommand("dev", "yarn tsx scripts/apiServer/dev.ts");
|
|
122
134
|
// "cedarpg run --mode=dev -- yarn tsx scripts/apiServer/dev.ts"
|
|
@@ -127,20 +139,20 @@ relativeEnvFile("dev"); // ".cedarpg/dev.env"
|
|
|
127
139
|
```json
|
|
128
140
|
{
|
|
129
141
|
"targets": {
|
|
142
|
+
"db:ready": { "command": "tsx tools/db-ready.ts", "cache": false },
|
|
130
143
|
"dev": {
|
|
131
|
-
"
|
|
144
|
+
"dependsOn": ["db:ready"],
|
|
145
|
+
"command": "cedarpg run --mode=dev --force -- yarn tsx scripts/apiServer/dev.ts"
|
|
132
146
|
},
|
|
133
|
-
"db:acquire": { "command": "cedarpg acquire --mode=dev" },
|
|
134
147
|
"serve": {
|
|
135
|
-
"dependsOn": ["db:
|
|
136
|
-
"command": "node dist/server.js"
|
|
137
|
-
"options": { "envFile": ".cedarpg/dev.env" }
|
|
148
|
+
"dependsOn": ["db:ready"],
|
|
149
|
+
"command": "cedarpg run --mode=dev --force -- node dist/server.js"
|
|
138
150
|
}
|
|
139
151
|
}
|
|
140
152
|
}
|
|
141
153
|
```
|
|
142
154
|
|
|
143
|
-
|
|
155
|
+
Migrate hook (same compose shape as Jest `createGlobalSetup`):
|
|
144
156
|
|
|
145
157
|
```ts
|
|
146
158
|
// tools/db-ready.ts
|
|
@@ -148,42 +160,19 @@ import { createAcquireTask } from "@cedarjs/pg";
|
|
|
148
160
|
|
|
149
161
|
await createAcquireTask({
|
|
150
162
|
mode: "dev",
|
|
163
|
+
// Need this when .env already has DATABASE_URL
|
|
164
|
+
force: true,
|
|
151
165
|
afterAcquire: async ({ databaseUrl }) => {
|
|
152
|
-
// prisma migrate deploy
|
|
166
|
+
// prisma migrate deploy, drizzle push, ...
|
|
153
167
|
},
|
|
154
168
|
})();
|
|
155
169
|
```
|
|
156
170
|
|
|
157
|
-
|
|
158
|
-
`import "@cedarjs/pg/dev-env"`. Absolute path helper: `envFilePath(root, mode)`.
|
|
171
|
+
If you cannot wrap with `run`, use `loadDevEnv({ overwrite: true })` or `import "@cedarjs/pg/dev-env"`. Absolute path helper: `envFilePath(root, mode)`.
|
|
159
172
|
|
|
160
|
-
##
|
|
161
|
-
|
|
162
|
-
```ts
|
|
163
|
-
// vite.config.ts
|
|
164
|
-
import { defineConfig } from "vite-plus";
|
|
165
|
-
import { cedarPgTasks } from "@cedarjs/pg/vite-plus";
|
|
166
|
-
|
|
167
|
-
export default defineConfig({
|
|
168
|
-
run: {
|
|
169
|
-
tasks: {
|
|
170
|
-
...cedarPgTasks(),
|
|
171
|
-
test: {
|
|
172
|
-
command: "vp test",
|
|
173
|
-
dependsOn: ["db:acquire-test"],
|
|
174
|
-
env: ["DATABASE_URL", "TEST_DATABASE_URL"],
|
|
175
|
-
},
|
|
176
|
-
dev: {
|
|
177
|
-
command: "vp dev",
|
|
178
|
-
dependsOn: ["db:acquire"],
|
|
179
|
-
env: ["DATABASE_URL"],
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
});
|
|
184
|
-
```
|
|
173
|
+
## Vitest and Jest
|
|
185
174
|
|
|
186
|
-
|
|
175
|
+
Stock `@cedarjs/pg/vitest` and `@cedarjs/pg/jest` only acquire and dispose. One shared test DB. They do not migrate, and they do not clone per worker. For migrate-once plus clones, see [TEMPLATE clones](#template-clones).
|
|
187
176
|
|
|
188
177
|
```ts
|
|
189
178
|
// vitest.config.ts
|
|
@@ -196,142 +185,80 @@ export default defineConfig({
|
|
|
196
185
|
});
|
|
197
186
|
```
|
|
198
187
|
|
|
188
|
+
Vitest runs `globalSetup` in the main process, then workers inherit `process.env`. Add `setupFiles: ["@cedarjs/pg/test-env"]` only if your pool does not inherit env.
|
|
189
|
+
|
|
199
190
|
```js
|
|
200
|
-
// jest.config.cjs
|
|
191
|
+
// jest.config.cjs
|
|
201
192
|
module.exports = {
|
|
202
193
|
globalSetup: require.resolve("@cedarjs/pg/jest"),
|
|
203
194
|
globalTeardown: require.resolve("@cedarjs/pg/jest-teardown"),
|
|
204
|
-
// Jest globalSetup is a separate process
|
|
195
|
+
// Jest globalSetup is a separate process. Workers load DATABASE_URL from .cedarpg/test.env.
|
|
205
196
|
setupFiles: [require.resolve("@cedarjs/pg/test-env")],
|
|
206
197
|
};
|
|
207
198
|
```
|
|
208
199
|
|
|
209
|
-
|
|
200
|
+
`loadTestEnv` and `loadDevEnv` fill undefined keys by default. Pass `{ overwrite: true }` (or import `@cedarjs/pg/dev-env`) when a local `.env` URL should lose to cedar-pg. That is not the same as `CEDAR_PG_FORCE` or `{ force: true }` (external-URL escape hatch).
|
|
201
|
+
|
|
202
|
+
## CedarJS and custom globalSetup
|
|
210
203
|
|
|
211
|
-
If
|
|
204
|
+
If the runner already owns `globalSetup` (Prisma push or migrate after acquire), do not replace it with `@cedarjs/pg/jest`. Compose:
|
|
212
205
|
|
|
213
|
-
1. In
|
|
214
|
-
2. Add `setupFiles: [require.resolve(
|
|
215
|
-
3. In
|
|
206
|
+
1. In `globalSetup`, call `acquireIfNeeded` when opted in, then migrate.
|
|
207
|
+
2. Add `setupFiles: [require.resolve("@cedarjs/pg/test-env")]` so Jest workers see `DATABASE_URL`.
|
|
208
|
+
3. In `globalTeardown`, call `dispose({ mode: "test", root })`.
|
|
216
209
|
|
|
217
210
|
```ts
|
|
218
|
-
// framework globalSetup (sketch)
|
|
219
211
|
import { acquireIfNeeded } from "@cedarjs/pg";
|
|
220
212
|
|
|
221
213
|
if (process.env.CEDAR_PG === "1" || process.env.CEDAR_PG === "true") {
|
|
222
214
|
await acquireIfNeeded({
|
|
223
215
|
root: projectRoot, // e.g. getPaths().base
|
|
224
216
|
mode: "test",
|
|
225
|
-
setEnv: true, // this process (prisma)
|
|
217
|
+
setEnv: true, // this process (prisma). Workers use @cedarjs/pg/test-env.
|
|
226
218
|
url: process.env.TEST_DATABASE_URL,
|
|
227
219
|
force: process.env.CEDAR_PG_FORCE === "1",
|
|
228
|
-
disabled: false, // framework opt-in
|
|
220
|
+
disabled: false, // framework opt-in. Stock adapters use CEDAR_PG=0 opt-out.
|
|
229
221
|
});
|
|
230
222
|
}
|
|
231
|
-
// … prisma db push / migrate …
|
|
232
223
|
```
|
|
233
224
|
|
|
234
|
-
|
|
235
|
-
// jest-preset
|
|
236
|
-
setupFiles: [require.resolve("@cedarjs/pg/test-env")],
|
|
237
|
-
```
|
|
225
|
+
## TEMPLATE clones
|
|
238
226
|
|
|
239
|
-
|
|
240
|
-
`envFilePath(root, mode)` instead of hardcoding the lease dir.
|
|
227
|
+
Migrate stays app-owned via `createGlobalSetup({ migrate })`. The adapter then marks TEMPLATE and clones per worker.
|
|
241
228
|
|
|
242
|
-
`
|
|
243
|
-
`{ overwrite: true }` (or import `@cedarjs/pg/dev-env`) when a local `.env`
|
|
244
|
-
`DATABASE_URL` / `TEST_DATABASE_URL` should lose to cedar-pg. That is not the
|
|
245
|
-
same as `CEDAR_PG_FORCE` / acquire `{ force }` (external-URL escape hatch).
|
|
229
|
+
Point `globalSetup` at a local module that calls `createGlobalSetup`. String-resolving the package entry without a migrate hook throws.
|
|
246
230
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
```ts
|
|
250
|
-
import { acquire, dispose, loadTestEnv, loadDevEnv, envFilePath, STATE_DIRNAME } from "@cedarjs/pg";
|
|
251
|
-
|
|
252
|
-
const { databaseUrl, adminUrl, databaseName, dispose: drop } = await acquire({ mode: "test" });
|
|
253
|
-
// … tests …
|
|
254
|
-
await drop();
|
|
255
|
-
|
|
256
|
-
loadDevEnv({ overwrite: true }); // override .env DATABASE_URL from .cedarpg/dev.env
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### Host startup (CI ephemeral)
|
|
260
|
-
|
|
261
|
-
By default cedar-pg **attaches** to a live autopg host (`autopg status`). If none is live it runs bare `autopg install` (pm2) — fine for local machines, hostile to GitHub Actions (no pm2) and slower than RAM-backed CI.
|
|
262
|
-
|
|
263
|
-
In CI, cedar-pg starts an **opinionated ephemeral host** automatically when `CI=true` (or when forced). Callers just use `acquire` — no host options bag:
|
|
264
|
-
|
|
265
|
-
```ts
|
|
266
|
-
import { acquire } from "@cedarjs/pg";
|
|
267
|
-
|
|
268
|
-
// CI=true → install --no-pm2 --no-ui + detached postmaster (--ram on Linux /dev/shm)
|
|
269
|
-
const { databaseUrl } = await acquire({ mode: "test" });
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
| Signal | Effect |
|
|
273
|
-
| --------------------------- | ------------------------------------------------------------------- |
|
|
274
|
-
| `CEDAR_PG_EPHEMERAL_HOST=1` | Prefer ephemeral start when **no** host is live (attach still wins) |
|
|
275
|
-
| `CEDAR_PG_EPHEMERAL_HOST=0` | Force local attach / pm2 install (even if `CI=true`) |
|
|
276
|
-
| unset + `CI=true` | Prefer ephemeral when no host is live |
|
|
277
|
-
| otherwise | Local: attach if live, else bare `autopg install` |
|
|
278
|
-
|
|
279
|
-
Ephemeral recipe (not configurable via cedar-pg):
|
|
280
|
-
|
|
281
|
-
- `autopg install --no-pm2 --no-ui --port 55432 --data DIR`
|
|
282
|
-
- detached `autopg postmaster --port 55432 --socket-dir DIR --data DIR`
|
|
283
|
-
- Linux when `/dev/shm` exists → also `--ram` and `DIR=/dev/shm/cedar-pg-<uid>`
|
|
284
|
-
- otherwise → disk `DIR` under the OS temp dir (still owned, no pm2)
|
|
285
|
-
- Ready when TCP accepts on the recipe port (not merely `autopg status` after install)
|
|
286
|
-
|
|
287
|
-
If a host is already live, cedar-pg attaches and does not start another. The **CI job owns** ephemeral postmaster lifetime (runner teardown / `/dev/shm`); there is no cedar-pg host dispose API.
|
|
288
|
-
|
|
289
|
-
### CI setup (GitHub Actions)
|
|
290
|
-
|
|
291
|
-
Prefer the composite action (cache + attested binary install, no pm2). Version defaults to this repo’s `scripts/autopg-version`:
|
|
292
|
-
|
|
293
|
-
```yaml
|
|
294
|
-
- uses: actions/checkout@v6
|
|
295
|
-
# In cedar-pg:
|
|
296
|
-
- uses: ./.github/actions/setup-autopg
|
|
297
|
-
# From another repo (pin to a tag when publishing the action):
|
|
298
|
-
# - uses: cedarjs/cedar-pg/.github/actions/setup-autopg@main
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
See [`.github/actions/setup-autopg`](.github/actions/setup-autopg/README.md) for inputs (`version`, `cache`, `token`) and outputs.
|
|
302
|
-
|
|
303
|
-
The action runs `scripts/ci-install-autopg.sh` under the hood. For published-package consumers under `CI=true` without the Action, set `CEDAR_PG_INSTALL_AUTOPG=1` so `postinstall` runs that same script (not upstream `install.sh`) — that flag alone is not enough when the package manager disables lifecycle scripts (`--ignore-scripts`, `YARN_ENABLE_SCRIPTS=false`, etc.). Prefer this Action, or bake the binary into the image.
|
|
304
|
-
|
|
305
|
-
### Migrate-once + TEMPLATE clones (Jest / Vitest)
|
|
306
|
-
|
|
307
|
-
Stock `@cedarjs/pg/jest` and `@cedarjs/pg/vitest` only run `acquireIfNeeded` + `dispose` (one shared test DB). They are **not** a full replacement for Redwood-style globalSetup that migrates once and clones per worker. For that, use template mode.
|
|
308
|
-
|
|
309
|
-
Migrate stays app-owned via `createGlobalSetup({ migrate })`, then the adapter marks TEMPLATE and clones per worker. Point `globalSetup` at a **local** module that calls `createGlobalSetup` — string-resolving the package entry without a migrate hook throws.
|
|
310
|
-
|
|
311
|
-
**Jest (template mode):**
|
|
231
|
+
### Jest
|
|
312
232
|
|
|
313
233
|
```js
|
|
314
234
|
// jest.cedar-global.cjs
|
|
315
235
|
const { createGlobalSetup } = require("@cedarjs/pg/jest/template");
|
|
316
236
|
module.exports = createGlobalSetup({
|
|
317
237
|
migrate: async ({ databaseUrl }) => {
|
|
318
|
-
// prisma migrate reset
|
|
238
|
+
// prisma migrate reset, drizzle push
|
|
319
239
|
},
|
|
320
240
|
});
|
|
321
241
|
|
|
322
242
|
// jest.config.cjs
|
|
243
|
+
// When .env has a real TEST_DATABASE_URL, set FORCE once here so it
|
|
244
|
+
// inherits into globalSetup and workers (dotenv will not override existing keys).
|
|
245
|
+
process.env.CEDAR_PG_FORCE = "1";
|
|
246
|
+
|
|
323
247
|
module.exports = {
|
|
324
248
|
globalSetup: "<rootDir>/jest.cedar-global.cjs",
|
|
325
249
|
globalTeardown: require.resolve("@cedarjs/pg/jest-teardown"),
|
|
250
|
+
// Prefer setupFilesAfterEnv so you can use beforeAll (Jest globals).
|
|
326
251
|
setupFilesAfterEnv: ["<rootDir>/jest.cedar-worker.cjs"],
|
|
327
252
|
};
|
|
328
253
|
|
|
329
|
-
// jest.cedar-worker.cjs
|
|
254
|
+
// jest.cedar-worker.cjs
|
|
330
255
|
const { cloneWorkerDatabase } = require("@cedarjs/pg/jest/template");
|
|
331
256
|
beforeAll(() => cloneWorkerDatabase());
|
|
332
257
|
```
|
|
333
258
|
|
|
334
|
-
|
|
259
|
+
`cloneWorkerDatabase` memos on `globalThis`, so Jest `setupFiles` (module reload per file) still shares one clone per worker.
|
|
260
|
+
|
|
261
|
+
### Vitest
|
|
335
262
|
|
|
336
263
|
```ts
|
|
337
264
|
// vitest.cedar-global.ts
|
|
@@ -350,12 +277,14 @@ export default defineConfig({
|
|
|
350
277
|
},
|
|
351
278
|
});
|
|
352
279
|
|
|
353
|
-
// vitest.cedar-worker.ts
|
|
280
|
+
// vitest.cedar-worker.ts
|
|
354
281
|
import { cloneWorkerDatabase } from "@cedarjs/pg/vitest/template";
|
|
355
282
|
await cloneWorkerDatabase();
|
|
356
283
|
```
|
|
357
284
|
|
|
358
|
-
|
|
285
|
+
### Core API
|
|
286
|
+
|
|
287
|
+
No runner adapters.
|
|
359
288
|
|
|
360
289
|
```ts
|
|
361
290
|
import { acquire, markTemplate, cloneFromTemplate, dispose } from "@cedarjs/pg";
|
|
@@ -369,36 +298,128 @@ const worker = await cloneFromTemplate({
|
|
|
369
298
|
name: "1",
|
|
370
299
|
setEnv: true,
|
|
371
300
|
});
|
|
372
|
-
// … tests …
|
|
373
301
|
await worker.dropClone(); // optional: drop one clone only
|
|
374
|
-
await dispose({ root: acquired.root, mode: "test" }); //
|
|
302
|
+
await dispose({ root: acquired.root, mode: "test" }); // TEMPLATE + all clones + role
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
`acquire` returns `adminUrl` for migrate hooks and privileged DDL. `markTemplate` and `cloneFromTemplate` accept it, or rediscover the host when it is omitted. `cloneFromTemplate` uses the admin connection (`CREATE DATABASE ... TEMPLATE`). Test roles stay `LOGIN`-only.
|
|
306
|
+
|
|
307
|
+
`setEnv` defaults to false on `cloneFromTemplate`. It defaults to true on `cloneFromTemplateIfNeeded` (same as `acquireIfNeeded`). Worker adapters call `cloneFromTemplateIfNeeded` via `cloneWorkerDatabase`.
|
|
308
|
+
|
|
309
|
+
`dispose` is role-scoped suite teardown, not `dropClone`. It unsets `IS_TEMPLATE` and drops every database owned by the lease role.
|
|
310
|
+
|
|
311
|
+
## Host and CI
|
|
312
|
+
|
|
313
|
+
`acquire` attaches when TCP accepts on the port from `autopg status --json`. Registration is not liveness. An installed-but-stopped host still reports a port.
|
|
314
|
+
|
|
315
|
+
When nothing is listening, cedar-pg brings up the registered local host. It runs `autopg restart`, then `autopg install` if the host was never registered. It attaches once TCP accepts. Same port, same `~/.autopg/data`. It does not start a second local Postgres. If neither verb produces a listener, `acquire` fails with what it tried.
|
|
316
|
+
|
|
317
|
+
Callers use `acquire` (and `adminUrl`). There is no public host-options object. Ephemeral behavior is env-driven.
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
import { acquire } from "@cedarjs/pg";
|
|
321
|
+
|
|
322
|
+
// CI=true: detached postmaster (--ram on Linux /dev/shm). Does not rewrite ~/.autopg.
|
|
323
|
+
const { databaseUrl } = await acquire({ mode: "test" });
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
| Signal | Effect (attach always wins when something is listening) |
|
|
327
|
+
| --------------------------- | ----------------------------------------------------------------------------- |
|
|
328
|
+
| `CEDAR_PG_EPHEMERAL_HOST=1` | Ephemeral owned postmaster on 55432 |
|
|
329
|
+
| `CEDAR_PG_EPHEMERAL_HOST=0` | Never own a postmaster (even when `CI=true`). Local autopg host only, or fail |
|
|
330
|
+
| unset and `CI=true` | Ephemeral |
|
|
331
|
+
| unset | Local: `autopg restart`, then `autopg install`, then fail |
|
|
332
|
+
|
|
333
|
+
Ephemeral recipe (not configurable via cedar-pg):
|
|
334
|
+
|
|
335
|
+
- Detached `autopg postmaster --port 55432 --socket-dir DIR --data DIR`
|
|
336
|
+
- Does not run `autopg install` (that rewrites `~/.autopg/admin.json` and conflicts with a local pm2 host)
|
|
337
|
+
- Linux when `/dev/shm` exists: also `--ram` and `DIR=/dev/shm/cedar-pg-<uid>`
|
|
338
|
+
- Otherwise: disk `DIR` under the OS temp dir
|
|
339
|
+
- Ready when TCP accepts on the recipe port
|
|
340
|
+
- Before cold-start, if the recipe port is not live, cedar-pg prunes leftover `/dev/shm/cedar-pg-*`, `pgserve-*`, and `PostgreSQL.*` (OOM-killed runs filling tmpfs). Safe on isolated CI VMs. On shared self-hosted runners another job's leftovers could match those globs.
|
|
341
|
+
|
|
342
|
+
If TCP already accepts on the discovered autopg port, or in ephemeral mode on 55432, cedar-pg attaches and does not start another. The CI job owns ephemeral postmaster lifetime (runner teardown, `/dev/shm`). There is no cedar-pg host dispose API.
|
|
343
|
+
|
|
344
|
+
Cloud VMs often ship `/dev/shm` at about 64MB, too small for `--ram`. Remount before tests if needed (`sudo mount -o remount,size=6G /dev/shm`). See [Troubleshooting](#troubleshooting).
|
|
345
|
+
|
|
346
|
+
### GitHub Actions
|
|
347
|
+
|
|
348
|
+
Prefer the composite action (cache plus attested binary install, no pm2). Version defaults to this repo's `scripts/autopg-version`. Inputs and outputs: [`.github/actions/setup-autopg`](.github/actions/setup-autopg/README.md).
|
|
349
|
+
|
|
350
|
+
```yaml
|
|
351
|
+
- uses: actions/checkout@v6
|
|
352
|
+
# In cedar-pg:
|
|
353
|
+
- uses: ./.github/actions/setup-autopg
|
|
354
|
+
# From another repo (pin to a tag when publishing the action):
|
|
355
|
+
# - uses: cedarjs/cedar-pg/.github/actions/setup-autopg@main
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The action runs `scripts/ci-install-autopg.sh`. For published-package consumers under `CI=true` without the Action, set `CEDAR_PG_INSTALL_AUTOPG=1` so `postinstall` runs that script (not upstream `install.sh`). That flag is not enough when the package manager disables lifecycle scripts (`--ignore-scripts`, `YARN_ENABLE_SCRIPTS=false`). Prefer the Action, or bake the binary into the image.
|
|
359
|
+
|
|
360
|
+
Yarn Berry or ignore-scripts, when you cannot use the Action. Requires a real `node_modules` tree (`nodeLinker: node-modules` or pnpm). Default Yarn PnP has no `node_modules/@cedarjs/pg/...` path. Resolve via `yarn node` or `require.resolve`, or prefer the Action.
|
|
361
|
+
|
|
362
|
+
```yaml
|
|
363
|
+
- name: Ensure autopg binary
|
|
364
|
+
run: |
|
|
365
|
+
set -euo pipefail
|
|
366
|
+
echo "${HOME}/.local/bin" >> "${GITHUB_PATH}"
|
|
367
|
+
export PATH="${HOME}/.local/bin:${PATH}"
|
|
368
|
+
bash node_modules/@cedarjs/pg/scripts/ci-install-autopg.sh
|
|
369
|
+
env:
|
|
370
|
+
GH_TOKEN: ${{ github.token }}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## Environment variables
|
|
374
|
+
|
|
375
|
+
| Var | Meaning |
|
|
376
|
+
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
377
|
+
| `AUTOPG_BIN` | Path to the autopg binary |
|
|
378
|
+
| `AUTOPG_PG_USER`, `AUTOPG_PG_PASSWORD` | Autopg superuser for admin URL (default user `postgres`, password `postgres`) |
|
|
379
|
+
| `CEDAR_PG=0` | Disable auto-acquire in adapters |
|
|
380
|
+
| `TEST_DATABASE_URL` | Default escape hatch for `acquireIfNeeded`. Skip acquire for a real external DB (not `cpg_*`, `file:`, or `{...}` or `<...>` placeholders). Callers may pass `url` (`DATABASE_URL` is common in dev) |
|
|
381
|
+
| `CEDAR_PG_FORCE=1` | Ignore the external-URL escape hatch (adapters, `cedarpg acquire --force`, `cedarpg run --force`) |
|
|
382
|
+
| `CEDAR_PG_EPHEMERAL_HOST` | `1` owned postmaster. `0` never own one (even in CI). Unset and `CI=true` means ephemeral |
|
|
383
|
+
| `CEDAR_PG_REGISTRY_DIR` | Override the global lease registry (for `gc`) |
|
|
384
|
+
| `CEDAR_PG_SKIP_POSTINSTALL=1` | Skip the autopg install hook |
|
|
385
|
+
| `CEDAR_PG_INSTALL_AUTOPG=1` | Under `CI=true`, run binary-only `ci-install-autopg.sh` from postinstall |
|
|
386
|
+
|
|
387
|
+
`force`, `overwrite`, and `run` are different knobs. Do not collapse them.
|
|
388
|
+
|
|
389
|
+
## Programmatic API
|
|
390
|
+
|
|
391
|
+
```ts
|
|
392
|
+
import { acquire, loadDevEnv } from "@cedarjs/pg";
|
|
393
|
+
|
|
394
|
+
const { databaseUrl, adminUrl, databaseName, dispose } = await acquire({ mode: "test" });
|
|
395
|
+
await dispose();
|
|
396
|
+
|
|
397
|
+
loadDevEnv({ overwrite: true }); // override .env DATABASE_URL from .cedarpg/dev.env
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Unit tests in this repo do not start Postgres. CI runs `vp run smoke:pg` for Vitest and Jest adapters against real Postgres (ephemeral cold-start when the runner has no live host; attach wins otherwise).
|
|
401
|
+
|
|
402
|
+
## Develop this package
|
|
403
|
+
|
|
404
|
+
Vite+, Node `>=24` (`.node-version`), `pnpm@11`. Contributor rules: [AGENTS.md](AGENTS.md). User-visible API changes: [CHANGELOG.md](CHANGELOG.md).
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
vp install
|
|
408
|
+
vp check
|
|
409
|
+
vp test
|
|
410
|
+
vp pack # dist/ (dts + esm + cjs)
|
|
411
|
+
vp run smoke # pack, then tarball install, then resolve exports
|
|
412
|
+
vp run smoke:pg # pack, then Vitest and Jest adapters against real ephemeral Postgres
|
|
375
413
|
```
|
|
376
414
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
|
385
|
-
|
|
|
386
|
-
| `
|
|
387
|
-
| `
|
|
388
|
-
| `CEDAR_PG=0` | Disable auto-acquire in adapters |
|
|
389
|
-
| `TEST_DATABASE_URL` | Escape hatch: skip acquire for real external DBs (not `cpg_*` / `file:` / `{…}` / `<…>` template placeholders) |
|
|
390
|
-
| `CEDAR_PG_FORCE=1` | Ignore external-URL escape hatch (adapters + `cedarpg acquire --force` / `run --force`) |
|
|
391
|
-
| `CEDAR_PG_EPHEMERAL_HOST` | `1` force / `0` disable ephemeral host (auto when `CI=true`) |
|
|
392
|
-
| `CEDAR_PG_REGISTRY_DIR` | Override global lease registry (for `gc`) |
|
|
393
|
-
| `CEDAR_PG_SKIP_POSTINSTALL=1` | Skip autopg install hook |
|
|
394
|
-
| `CEDAR_PG_INSTALL_AUTOPG=1` | Under `CI=true`, run binary-only `ci-install-autopg.sh` from postinstall |
|
|
395
|
-
|
|
396
|
-
## Alpha caveats
|
|
397
|
-
|
|
398
|
-
- Public API may change before `0.1.0`.
|
|
399
|
-
- End-to-end Postgres flows assume a working local `autopg` host; unit tests do not start Postgres.
|
|
400
|
-
CI runs `vp run smoke:pg` for Vitest/Jest adapters against real Postgres
|
|
401
|
-
(ephemeral cold-start when the runner has no live host; attach-wins otherwise).
|
|
402
|
-
- State lives in product-owned `.cedarpg` (worktree + `~/.cedarpg/registry`), not under autopg's `~/.autopg/` or a generic `.pg`.
|
|
403
|
-
- Role passwords are derived from `roleName` (`cedar-pg\\0` + roleName, scheme v2) so TEMPLATE clones that reuse a role keep working; bump the scheme id to change the derivation.
|
|
404
|
-
- Test TEMPLATE flow: `acquire` → app migrate → `markTemplate` → `cloneFromTemplate` → role-scoped `dispose`. Optional `@cedarjs/pg/jest/template` + `@cedarjs/pg/vitest/template` adapters orchestrate that pipeline via `createGlobalSetup({ migrate })`; migrate stays app-owned.
|
|
415
|
+
## Troubleshooting
|
|
416
|
+
|
|
417
|
+
| Symptom | Fix |
|
|
418
|
+
| --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
419
|
+
| `ECONNREFUSED 127.0.0.1:25432` on `cedarpg acquire` | autopg is registered but not listening. cedar-pg runs `autopg restart` (then `install`) and attaches once TCP accepts. `restart` exiting 0 is not proof. When pm2 is missing it still prints "respawned daemon". If both verbs fail, install pm2 or fix the supervisor (`pm2 logs autopg-server`). |
|
|
420
|
+
| `database already exists: ..._c_<workerId>` in Jest | Use current `@cedarjs/pg` (`cloneWorkerDatabase` memos on `globalThis`). Prefer `setupFilesAfterEnv` + `beforeAll`. Avoid passing bare `JEST_WORKER_ID` as an explicit `name`. |
|
|
421
|
+
| Acquire skipped. Tests hit shared or stale Postgres | A real `.env` `TEST_DATABASE_URL` (or a `url` the caller passed) trips the escape hatch. Set `CEDAR_PG_FORCE=1` once in `jest.config.js`, or `force: true`, or `cedarpg run --force`. |
|
|
422
|
+
| `Disk quota exceeded` / `No space left on device` / Postgres `53100` on ephemeral start | Enlarge `/dev/shm` (`sudo mount -o remount,size=6G /dev/shm`). On isolated runners only: `rm -rf /dev/shm/cedar-pg-* /dev/shm/pgserve-* /dev/shm/PostgreSQL.*`. Cold-start also prunes these when the recipe port is dead. |
|
|
423
|
+
| `autopg: command not found` in CI with Yarn `YARN_ENABLE_SCRIPTS=false` | `CEDAR_PG_INSTALL_AUTOPG=1` is not enough when lifecycle scripts are off. With `nodeLinker: node-modules`, run `bash node_modules/@cedarjs/pg/scripts/ci-install-autopg.sh` and put `~/.local/bin` on `PATH` (or use `setup-autopg`). PnP: resolve the script path via Yarn, or prefer the Action. |
|
|
424
|
+
| Nx child still uses `.env` `DATABASE_URL` | `dependsOn` does not forward acquire env. Wrap with `cedarpg run --mode=dev --force -- <cmd>`, or `loadDevEnv({ overwrite: true })`. |
|
|
425
|
+
| Role or DB errors under parallel Nx targets | Do not run concurrent `acquire` or `run` on the same worktree. One `db:ready`, then `run` wrappers. |
|