@supatype/cli 0.1.6 → 0.1.7
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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +144 -94
- package/.turbo/turbo-typecheck.log +1 -1
- package/deno.d.ts +52 -0
- package/dist/augmentation-generator.d.ts +22 -0
- package/dist/augmentation-generator.d.ts.map +1 -1
- package/dist/augmentation-generator.js +18 -4
- package/dist/augmentation-generator.js.map +1 -1
- package/dist/binary-cache.d.ts +14 -0
- package/dist/binary-cache.d.ts.map +1 -1
- package/dist/binary-cache.js +33 -13
- package/dist/binary-cache.js.map +1 -1
- package/dist/cache-clean.d.ts +15 -0
- package/dist/cache-clean.d.ts.map +1 -0
- package/dist/cache-clean.js +76 -0
- package/dist/cache-clean.js.map +1 -0
- package/dist/cache-pins.d.ts +51 -0
- package/dist/cache-pins.d.ts.map +1 -0
- package/dist/cache-pins.js +184 -0
- package/dist/cache-pins.js.map +1 -0
- package/dist/cli-install-method.d.ts +19 -0
- package/dist/cli-install-method.d.ts.map +1 -0
- package/dist/cli-install-method.js +60 -0
- package/dist/cli-install-method.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/cloud-credentials.d.ts +34 -0
- package/dist/cloud-credentials.d.ts.map +1 -0
- package/dist/cloud-credentials.js +139 -0
- package/dist/cloud-credentials.js.map +1 -0
- package/dist/commands/admin.d.ts +11 -0
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +121 -19
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/cache.d.ts.map +1 -1
- package/dist/commands/cache.js +67 -71
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/cloud.d.ts.map +1 -1
- package/dist/commands/cloud.js +32 -8
- package/dist/commands/cloud.js.map +1 -1
- package/dist/commands/db.d.ts +1 -0
- package/dist/commands/db.d.ts.map +1 -1
- package/dist/commands/db.js +147 -1
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +50 -10
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts +28 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +60 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/functions.d.ts +7 -0
- package/dist/commands/functions.d.ts.map +1 -1
- package/dist/commands/functions.js +40 -6
- package/dist/commands/functions.js.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +5 -1
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/hooks.d.ts +12 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +118 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +41 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/internal.d.ts +6 -0
- package/dist/commands/internal.d.ts.map +1 -0
- package/dist/commands/internal.js +22 -0
- package/dist/commands/internal.js.map +1 -0
- package/dist/commands/link-helpers.d.ts.map +1 -1
- package/dist/commands/link-helpers.js +8 -2
- package/dist/commands/link-helpers.js.map +1 -1
- package/dist/commands/login.d.ts +7 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +110 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +110 -7
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/self-update.d.ts +7 -0
- package/dist/commands/self-update.d.ts.map +1 -1
- package/dist/commands/self-update.js +18 -11
- package/dist/commands/self-update.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -3
- package/dist/config.js.map +1 -1
- package/dist/db-preflight.d.ts +78 -0
- package/dist/db-preflight.d.ts.map +1 -0
- package/dist/db-preflight.js +452 -0
- package/dist/db-preflight.js.map +1 -0
- package/dist/dev-compose.d.ts +1 -1
- package/dist/dev-compose.d.ts.map +1 -1
- package/dist/dev-compose.js +127 -72
- package/dist/dev-compose.js.map +1 -1
- package/dist/env-file.d.ts +40 -2
- package/dist/env-file.d.ts.map +1 -1
- package/dist/env-file.js +132 -11
- package/dist/env-file.js.map +1 -1
- package/dist/field-masking-tier.d.ts +50 -0
- package/dist/field-masking-tier.d.ts.map +1 -0
- package/dist/field-masking-tier.js +91 -0
- package/dist/field-masking-tier.js.map +1 -0
- package/dist/functions-deno-types.d.ts +24 -0
- package/dist/functions-deno-types.d.ts.map +1 -0
- package/dist/functions-deno-types.js +155 -0
- package/dist/functions-deno-types.js.map +1 -0
- package/dist/hook-upload.d.ts +30 -0
- package/dist/hook-upload.d.ts.map +1 -0
- package/dist/hook-upload.js +86 -0
- package/dist/hook-upload.js.map +1 -0
- package/dist/hooks-generator.d.ts +8 -0
- package/dist/hooks-generator.d.ts.map +1 -0
- package/dist/hooks-generator.js +332 -0
- package/dist/hooks-generator.js.map +1 -0
- package/dist/link.d.ts +4 -0
- package/dist/link.d.ts.map +1 -1
- package/dist/link.js +2 -0
- package/dist/link.js.map +1 -1
- package/dist/local-secrets.d.ts +71 -0
- package/dist/local-secrets.d.ts.map +1 -0
- package/dist/local-secrets.js +100 -0
- package/dist/local-secrets.js.map +1 -0
- package/dist/model-hooks.d.ts +73 -0
- package/dist/model-hooks.d.ts.map +1 -0
- package/dist/model-hooks.js +211 -0
- package/dist/model-hooks.js.map +1 -0
- package/dist/postgres-ctl.d.ts +11 -0
- package/dist/postgres-ctl.d.ts.map +1 -1
- package/dist/postgres-ctl.js +25 -2
- package/dist/postgres-ctl.js.map +1 -1
- package/dist/project-config.d.ts +121 -1
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +150 -1
- package/dist/project-config.js.map +1 -1
- package/dist/resolve-target.d.ts +4 -0
- package/dist/resolve-target.d.ts.map +1 -1
- package/dist/resolve-target.js +69 -73
- package/dist/resolve-target.js.map +1 -1
- package/dist/schema-ast-v2.d.ts +2 -1
- package/dist/schema-ast-v2.d.ts.map +1 -1
- package/dist/schema-ast-v2.js +4 -2
- package/dist/schema-ast-v2.js.map +1 -1
- package/dist/schema-push-lock.d.ts.map +1 -1
- package/dist/schema-push-lock.js +43 -16
- package/dist/schema-push-lock.js.map +1 -1
- package/dist/self-host-compose.d.ts +24 -0
- package/dist/self-host-compose.d.ts.map +1 -1
- package/dist/self-host-compose.js +301 -69
- package/dist/self-host-compose.js.map +1 -1
- package/dist/service-role-check.d.ts +21 -0
- package/dist/service-role-check.d.ts.map +1 -0
- package/dist/service-role-check.js +85 -0
- package/dist/service-role-check.js.map +1 -0
- package/dist/target-client.d.ts +17 -0
- package/dist/target-client.d.ts.map +1 -1
- package/dist/target-client.js +69 -17
- package/dist/target-client.js.map +1 -1
- package/dist/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor.js +736 -32
- package/dist/type-extractor.js.map +1 -1
- package/dist/ui/runtime/command-chrome.js +1 -1
- package/dist/ui/runtime/command-chrome.js.map +1 -1
- package/dist/ui/runtime/stdin-after-ink.d.ts.map +1 -1
- package/dist/ui/runtime/stdin-after-ink.js +3 -1
- package/dist/ui/runtime/stdin-after-ink.js.map +1 -1
- package/package.json +4 -1
- package/scripts/generate-homebrew-formula.mjs +121 -0
- package/src/augmentation-generator.ts +18 -5
- package/src/binary-cache.ts +47 -15
- package/src/cache-clean.ts +81 -0
- package/src/cache-pins.ts +243 -0
- package/src/cli-install-method.ts +67 -0
- package/src/cli.ts +6 -0
- package/src/cloud-credentials.ts +183 -0
- package/src/commands/admin.ts +140 -25
- package/src/commands/cache.ts +90 -75
- package/src/commands/cloud.ts +32 -8
- package/src/commands/db.ts +162 -1
- package/src/commands/dev.ts +57 -8
- package/src/commands/doctor.ts +69 -3
- package/src/commands/functions.ts +42 -5
- package/src/commands/generate.ts +5 -1
- package/src/commands/hooks.ts +138 -0
- package/src/commands/init.ts +42 -8
- package/src/commands/internal.ts +23 -0
- package/src/commands/link-helpers.ts +9 -2
- package/src/commands/login.ts +127 -0
- package/src/commands/push.ts +124 -7
- package/src/commands/self-update.ts +85 -13
- package/src/config.ts +22 -3
- package/src/db-preflight.ts +575 -0
- package/src/dev-compose.ts +142 -73
- package/src/env-file.ts +157 -11
- package/src/field-masking-tier.ts +107 -0
- package/src/functions-deno-types.ts +188 -0
- package/src/hook-upload.ts +107 -0
- package/src/hooks-generator.ts +352 -0
- package/src/link.ts +7 -0
- package/src/local-secrets.ts +104 -0
- package/src/model-hooks.ts +260 -0
- package/src/postgres-ctl.ts +29 -2
- package/src/project-config.ts +236 -2
- package/src/resolve-target.ts +113 -68
- package/src/schema-ast-v2.ts +5 -2
- package/src/schema-push-lock.ts +56 -17
- package/src/self-host-compose.ts +344 -68
- package/src/service-role-check.ts +111 -0
- package/src/target-client.ts +105 -18
- package/src/type-extractor.ts +883 -28
- package/src/ui/runtime/command-chrome.ts +1 -1
- package/src/ui/runtime/stdin-after-ink.ts +3 -1
- package/tests/access-composition.test.ts +667 -0
- package/tests/admin-studio-membership.test.ts +121 -0
- package/tests/api-schemas.test.ts +83 -0
- package/tests/archive-name-alias.test.ts +42 -0
- package/tests/augmentation-generator.test.ts +28 -0
- package/tests/cache-clean.test.ts +206 -0
- package/tests/cli-help.test.ts +3 -0
- package/tests/cli-install-method.test.ts +66 -0
- package/tests/command-chrome-coverage.test.ts +31 -26
- package/tests/command-chrome-wrap.test.ts +1 -0
- package/tests/db-preflight.test.ts +72 -0
- package/tests/doctor-render.test.ts +62 -0
- package/tests/doctor-service-role.test.ts +55 -0
- package/tests/env-file.test.ts +121 -0
- package/tests/external-database-compose.test.ts +184 -0
- package/tests/external-database-config.test.ts +154 -0
- package/tests/field-masking-tier.test.ts +184 -0
- package/tests/functions-deno-types.test.ts +197 -0
- package/tests/homebrew-formula.test.ts +58 -0
- package/tests/hook-upload.test.ts +125 -0
- package/tests/hooks-generator.test.ts +212 -0
- package/tests/init.test.ts +3 -0
- package/tests/local-secrets.test.ts +92 -0
- package/tests/model-hooks.test.ts +322 -0
- package/tests/runtime-contract.test.ts +113 -1
- package/tests/service-role-check.test.ts +109 -0
- package/tests/service-role-routes.test.ts +51 -0
- package/tests/target-client-refresh.test.ts +94 -0
- package/tests/type-extractor.test.ts +187 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/tests/engine-distribution.test.ts +0 -418
package/src/resolve-target.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { ensureEngine, engineRequest } from "./engine-client.js"
|
|
|
6
6
|
import type { SchemaSourcesPayload } from "./schema-sources.js"
|
|
7
7
|
import {
|
|
8
8
|
connectionString,
|
|
9
|
+
pgSchema,
|
|
9
10
|
resolveRuntimeProvider,
|
|
10
11
|
schemaPathFromProject,
|
|
11
12
|
serverBaseUrl,
|
|
@@ -20,7 +21,12 @@ import {
|
|
|
20
21
|
type LocalEnvironment,
|
|
21
22
|
type ProjectLink,
|
|
22
23
|
} from "./link.js"
|
|
23
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
persistCloudSession,
|
|
26
|
+
resolveCloudAccessToken,
|
|
27
|
+
resolveCloudRefreshToken,
|
|
28
|
+
} from "./cloud-credentials.js"
|
|
29
|
+
import { targetFetch, type TargetFetchOptions } from "./target-client.js"
|
|
24
30
|
|
|
25
31
|
export interface ResolveTargetFlags {
|
|
26
32
|
env?: string | undefined
|
|
@@ -38,8 +44,12 @@ export interface DeployTarget {
|
|
|
38
44
|
apiBaseUrl: string
|
|
39
45
|
apiPrefix: "/api/v1" | "/platform/v1"
|
|
40
46
|
token?: string | undefined
|
|
47
|
+
/** Cloud GoTrue refresh token (mode === "cloud" only). */
|
|
48
|
+
refreshToken?: string | undefined
|
|
41
49
|
orgId?: string | undefined
|
|
42
50
|
link: ProjectLink | null
|
|
51
|
+
/** Project cwd — needed to persist refreshed cloud tokens. */
|
|
52
|
+
cwd?: string
|
|
43
53
|
/** Engine subprocess path when mode is direct or local without control plane. */
|
|
44
54
|
databaseUrl?: string
|
|
45
55
|
}
|
|
@@ -147,12 +157,19 @@ export function resolveTarget(cwd: string, flags: ResolveTargetFlags = {}): Depl
|
|
|
147
157
|
)
|
|
148
158
|
}
|
|
149
159
|
|
|
150
|
-
const token =
|
|
160
|
+
const token =
|
|
161
|
+
(link.kind === "cloud" ? resolveCloudAccessToken(link) : undefined) ??
|
|
162
|
+
resolveEnvironmentToken(link, envTarget)
|
|
151
163
|
if (!token) {
|
|
152
|
-
throw new Error(
|
|
164
|
+
throw new Error(
|
|
165
|
+
link.kind === "cloud"
|
|
166
|
+
? `No cloud session for environment "${envName}". Run: supatype login`
|
|
167
|
+
: `No token for environment "${envName}". Re-run supatype link --token ...`,
|
|
168
|
+
)
|
|
153
169
|
}
|
|
154
170
|
|
|
155
171
|
if (link.kind === "cloud") {
|
|
172
|
+
const refreshToken = resolveCloudRefreshToken(link)
|
|
156
173
|
return {
|
|
157
174
|
mode: "cloud",
|
|
158
175
|
environment: envName,
|
|
@@ -161,6 +178,8 @@ export function resolveTarget(cwd: string, flags: ResolveTargetFlags = {}): Depl
|
|
|
161
178
|
apiPrefix: "/api/v1",
|
|
162
179
|
token,
|
|
163
180
|
link,
|
|
181
|
+
cwd,
|
|
182
|
+
...(refreshToken !== undefined ? { refreshToken } : {}),
|
|
164
183
|
...(link.orgId !== undefined ? { orgId: link.orgId } : {}),
|
|
165
184
|
}
|
|
166
185
|
}
|
|
@@ -173,6 +192,44 @@ export function resolveTarget(cwd: string, flags: ResolveTargetFlags = {}): Depl
|
|
|
173
192
|
apiPrefix: "/platform/v1",
|
|
174
193
|
token,
|
|
175
194
|
link,
|
|
195
|
+
cwd,
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function cloudAuthRefresh(target: DeployTarget): TargetFetchOptions["authRefresh"] | undefined {
|
|
200
|
+
if (target.mode !== "cloud" || !target.refreshToken || !target.cwd) return undefined
|
|
201
|
+
const cloudApiUrl = (target.link?.cloudApiUrl ?? target.apiBaseUrl).replace(/\/$/, "")
|
|
202
|
+
const cwd = target.cwd
|
|
203
|
+
return {
|
|
204
|
+
cloudApiUrl,
|
|
205
|
+
refreshToken: target.refreshToken,
|
|
206
|
+
onRefreshed: ({ accessToken, refreshToken }) => {
|
|
207
|
+
persistCloudSession(cwd, {
|
|
208
|
+
apiUrl: cloudApiUrl,
|
|
209
|
+
accessToken,
|
|
210
|
+
...(refreshToken !== undefined ? { refreshToken } : {}),
|
|
211
|
+
})
|
|
212
|
+
target.token = accessToken
|
|
213
|
+
if (refreshToken !== undefined) target.refreshToken = refreshToken
|
|
214
|
+
},
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function apiFetchOpts(
|
|
219
|
+
target: DeployTarget,
|
|
220
|
+
method: string,
|
|
221
|
+
path: string,
|
|
222
|
+
body?: unknown,
|
|
223
|
+
): TargetFetchOptions {
|
|
224
|
+
const authRefresh = cloudAuthRefresh(target)
|
|
225
|
+
return {
|
|
226
|
+
method,
|
|
227
|
+
path,
|
|
228
|
+
token: target.token!,
|
|
229
|
+
...(body !== undefined ? { body } : {}),
|
|
230
|
+
...(target.orgId !== undefined ? { orgId: target.orgId } : {}),
|
|
231
|
+
...(target.mode === "cloud" ? { environment: target.environment } : {}),
|
|
232
|
+
...(authRefresh !== undefined ? { authRefresh } : {}),
|
|
176
233
|
}
|
|
177
234
|
}
|
|
178
235
|
|
|
@@ -194,14 +251,14 @@ export async function targetSchemaDiff(
|
|
|
194
251
|
})
|
|
195
252
|
}
|
|
196
253
|
|
|
197
|
-
return targetFetch<DiffResult>(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
254
|
+
return targetFetch<DiffResult>(
|
|
255
|
+
target.apiBaseUrl,
|
|
256
|
+
target.apiPrefix,
|
|
257
|
+
apiFetchOpts(target, "POST", projectPath(target, "/schema/diff"), {
|
|
258
|
+
ast,
|
|
259
|
+
schema: opts?.schema ?? "public",
|
|
260
|
+
}),
|
|
261
|
+
)
|
|
205
262
|
}
|
|
206
263
|
|
|
207
264
|
export async function targetSchemaPush(
|
|
@@ -236,14 +293,11 @@ export async function targetSchemaPush(
|
|
|
236
293
|
}
|
|
237
294
|
}
|
|
238
295
|
|
|
239
|
-
return targetFetch(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
orgId: target.orgId,
|
|
245
|
-
environment: target.mode === "cloud" ? target.environment : undefined,
|
|
246
|
-
})
|
|
296
|
+
return targetFetch(
|
|
297
|
+
target.apiBaseUrl,
|
|
298
|
+
target.apiPrefix,
|
|
299
|
+
apiFetchOpts(target, "POST", projectPath(target, "/schema/push"), pushBody),
|
|
300
|
+
)
|
|
247
301
|
}
|
|
248
302
|
|
|
249
303
|
export interface SchemaRollbackResult {
|
|
@@ -286,14 +340,13 @@ export async function targetSchemaRollback(
|
|
|
286
340
|
})
|
|
287
341
|
}
|
|
288
342
|
|
|
289
|
-
return targetFetch<SchemaRollbackResult>(
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
})
|
|
343
|
+
return targetFetch<SchemaRollbackResult>(
|
|
344
|
+
target.apiBaseUrl,
|
|
345
|
+
target.apiPrefix,
|
|
346
|
+
apiFetchOpts(target, "POST", projectPath(target, "/schema/rollback"), {
|
|
347
|
+
schema: opts?.schema ?? "public",
|
|
348
|
+
}),
|
|
349
|
+
)
|
|
297
350
|
}
|
|
298
351
|
|
|
299
352
|
export async function targetListMigrations(
|
|
@@ -308,13 +361,11 @@ export async function targetListMigrations(
|
|
|
308
361
|
return Array.isArray(result) ? result : (result.migrations ?? [])
|
|
309
362
|
}
|
|
310
363
|
|
|
311
|
-
return targetFetch<MigrationListEntry[]>(
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
environment: target.mode === "cloud" ? target.environment : undefined,
|
|
317
|
-
})
|
|
364
|
+
return targetFetch<MigrationListEntry[]>(
|
|
365
|
+
target.apiBaseUrl,
|
|
366
|
+
target.apiPrefix,
|
|
367
|
+
apiFetchOpts(target, "GET", projectPath(target, "/schema/migrations")),
|
|
368
|
+
)
|
|
318
369
|
}
|
|
319
370
|
|
|
320
371
|
export async function targetSchemaDoctor(
|
|
@@ -332,14 +383,15 @@ export async function targetSchemaDoctor(
|
|
|
332
383
|
})
|
|
333
384
|
}
|
|
334
385
|
|
|
335
|
-
return targetFetch(
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
386
|
+
return targetFetch(
|
|
387
|
+
target.apiBaseUrl,
|
|
388
|
+
target.apiPrefix,
|
|
389
|
+
apiFetchOpts(target, "POST", projectPath(target, "/schema/doctor"), {
|
|
390
|
+
ast,
|
|
391
|
+
no_cache: opts?.noCache ?? false,
|
|
392
|
+
schema: opts?.schema ?? "public",
|
|
393
|
+
}),
|
|
394
|
+
)
|
|
343
395
|
}
|
|
344
396
|
|
|
345
397
|
export async function targetSchemaIntrospect(
|
|
@@ -354,14 +406,13 @@ export async function targetSchemaIntrospect(
|
|
|
354
406
|
})
|
|
355
407
|
}
|
|
356
408
|
|
|
357
|
-
return targetFetch(
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
})
|
|
409
|
+
return targetFetch(
|
|
410
|
+
target.apiBaseUrl,
|
|
411
|
+
target.apiPrefix,
|
|
412
|
+
apiFetchOpts(target, "POST", projectPath(target, "/schema/introspect"), {
|
|
413
|
+
schema: opts?.schema ?? "public",
|
|
414
|
+
}),
|
|
415
|
+
)
|
|
365
416
|
}
|
|
366
417
|
|
|
367
418
|
export async function targetSchemaAdopt(
|
|
@@ -381,20 +432,17 @@ export async function targetSchemaAdopt(
|
|
|
381
432
|
})
|
|
382
433
|
}
|
|
383
434
|
|
|
384
|
-
return targetFetch(
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
435
|
+
return targetFetch(
|
|
436
|
+
target.apiBaseUrl,
|
|
437
|
+
target.apiPrefix,
|
|
438
|
+
apiFetchOpts(target, "POST", projectPath(target, "/schema/adopt"), {
|
|
388
439
|
ast,
|
|
389
440
|
schema: opts?.schema ?? "public",
|
|
390
441
|
yes: opts?.yes ?? false,
|
|
391
442
|
no_cache: opts?.noCache ?? false,
|
|
392
443
|
...(opts?.names !== undefined ? { names: opts.names } : {}),
|
|
393
|
-
},
|
|
394
|
-
|
|
395
|
-
orgId: target.orgId,
|
|
396
|
-
environment: target.mode === "cloud" ? target.environment : undefined,
|
|
397
|
-
})
|
|
444
|
+
}),
|
|
445
|
+
)
|
|
398
446
|
}
|
|
399
447
|
|
|
400
448
|
export async function targetStatus(target: DeployTarget): Promise<unknown> {
|
|
@@ -402,18 +450,15 @@ export async function targetStatus(target: DeployTarget): Promise<unknown> {
|
|
|
402
450
|
return { mode: "direct", environment: target.environment }
|
|
403
451
|
}
|
|
404
452
|
|
|
405
|
-
return targetFetch(
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
environment: target.mode === "cloud" ? target.environment : undefined,
|
|
411
|
-
})
|
|
453
|
+
return targetFetch(
|
|
454
|
+
target.apiBaseUrl,
|
|
455
|
+
target.apiPrefix,
|
|
456
|
+
apiFetchOpts(target, "GET", projectPath(target, "/status")),
|
|
457
|
+
)
|
|
412
458
|
}
|
|
413
459
|
|
|
414
460
|
export function schemaPgSchema(cwd: string): string {
|
|
415
|
-
|
|
416
|
-
return config.schema?.pg_schema ?? "public"
|
|
461
|
+
return pgSchema(loadConfig(cwd))
|
|
417
462
|
}
|
|
418
463
|
|
|
419
464
|
export { schemaPathFromProject }
|
package/src/schema-ast-v2.ts
CHANGED
|
@@ -88,7 +88,7 @@ export interface ModelAstV2 {
|
|
|
88
88
|
options: Record<string, unknown>
|
|
89
89
|
annotations: {
|
|
90
90
|
db: { tableName: string; indexes: unknown[] }
|
|
91
|
-
platform: { access: Record<string, unknown> }
|
|
91
|
+
platform: { access: Record<string, unknown>; hooks?: Record<string, unknown> }
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -294,6 +294,7 @@ export function emitModel(
|
|
|
294
294
|
tableName: string,
|
|
295
295
|
access: Record<string, unknown>,
|
|
296
296
|
indexes: unknown[] = [],
|
|
297
|
+
hooks: Record<string, unknown> = {},
|
|
297
298
|
): ModelAstV2 {
|
|
298
299
|
return {
|
|
299
300
|
name,
|
|
@@ -301,7 +302,9 @@ export function emitModel(
|
|
|
301
302
|
options,
|
|
302
303
|
annotations: {
|
|
303
304
|
db: { tableName, indexes },
|
|
304
|
-
platform
|
|
305
|
+
// Hooks sit in `platform` beside `access`: they are an API-layer concern, not a column one —
|
|
306
|
+
// supatype-server reads them, Postgres never sees them.
|
|
307
|
+
platform: { access, ...(Object.keys(hooks).length > 0 && { hooks }) },
|
|
305
308
|
},
|
|
306
309
|
}
|
|
307
310
|
}
|
package/src/schema-push-lock.ts
CHANGED
|
@@ -83,16 +83,26 @@ export async function withComposeSchemaPushLock<T>(
|
|
|
83
83
|
composeProject: string,
|
|
84
84
|
fn: () => Promise<T>,
|
|
85
85
|
): Promise<T> {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
// The lock is held by a psql session reading from **stdin**, not by `-c … pg_sleep(86400)`.
|
|
87
|
+
//
|
|
88
|
+
// Killing the local `docker` client does not stop the process inside the container: `docker
|
|
89
|
+
// compose exec` does not forward the signal. With a sleeping session that meant every push
|
|
90
|
+
// left a backend holding this advisory lock for 24 hours — so `supatype push` never exited and
|
|
91
|
+
// the next push blocked on it. Observed end-to-end before this change.
|
|
92
|
+
//
|
|
93
|
+
// Closing stdin *does* propagate: psql sees EOF, exits, and the session ends, which is what
|
|
94
|
+
// releases an advisory lock. Deterministic, and it needs no signal to cross the boundary.
|
|
95
|
+
const args = dbExecArgs(paths, cwd, composeProject, ["-f", "-"])
|
|
90
96
|
|
|
91
97
|
let stderrBuf = ""
|
|
92
98
|
const holder: ChildProcess = spawn("docker", args, {
|
|
93
99
|
cwd,
|
|
94
|
-
stdio: ["
|
|
100
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
95
101
|
})
|
|
102
|
+
holder.stdin?.write(
|
|
103
|
+
`SELECT pg_advisory_lock(${SCHEMA_PUSH_LOCK_CLASSID}, ${SCHEMA_PUSH_LOCK_OBJID});\n`,
|
|
104
|
+
)
|
|
105
|
+
// Deliberately not ended — the open pipe is what keeps the session, and the lock, alive.
|
|
96
106
|
holder.stderr?.on("data", (chunk: Buffer) => {
|
|
97
107
|
stderrBuf += chunk.toString()
|
|
98
108
|
})
|
|
@@ -114,18 +124,47 @@ export async function withComposeSchemaPushLock<T>(
|
|
|
114
124
|
try {
|
|
115
125
|
return await fn()
|
|
116
126
|
} finally {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
await releaseHolder(holder, paths, cwd, composeProject)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* End the holder session, then confirm the lock is actually gone.
|
|
133
|
+
*
|
|
134
|
+
* Closing stdin is the mechanism; the check is because a leaked holder is silent and expensive —
|
|
135
|
+
* it blocks every later push. If EOF did not do it, terminate the backend directly.
|
|
136
|
+
*/
|
|
137
|
+
async function releaseHolder(
|
|
138
|
+
holder: ChildProcess,
|
|
139
|
+
paths: SelfHostComposePaths,
|
|
140
|
+
cwd: string,
|
|
141
|
+
composeProject: string,
|
|
142
|
+
): Promise<void> {
|
|
143
|
+
if (holder.exitCode === null) {
|
|
144
|
+
holder.stdin?.end()
|
|
145
|
+
await new Promise<void>((resolveDone) => {
|
|
146
|
+
const t = setTimeout(() => {
|
|
147
|
+
holder.kill("SIGKILL")
|
|
148
|
+
resolveDone()
|
|
149
|
+
}, 5000)
|
|
150
|
+
holder.once("exit", () => {
|
|
151
|
+
clearTimeout(t)
|
|
152
|
+
resolveDone()
|
|
128
153
|
})
|
|
129
|
-
}
|
|
154
|
+
})
|
|
130
155
|
}
|
|
156
|
+
|
|
157
|
+
if (!schemaPushLockIsHeld(paths, cwd, composeProject)) return
|
|
158
|
+
|
|
159
|
+
// Last resort: the session outlived its client. Ending it releases the lock.
|
|
160
|
+
spawnSync(
|
|
161
|
+
"docker",
|
|
162
|
+
dbExecArgs(paths, cwd, composeProject, [
|
|
163
|
+
"-tAc",
|
|
164
|
+
`SELECT pg_terminate_backend(pid) FROM pg_stat_activity
|
|
165
|
+
WHERE pid <> pg_backend_pid()
|
|
166
|
+
AND query LIKE '%pg_advisory_lock(${SCHEMA_PUSH_LOCK_CLASSID}, ${SCHEMA_PUSH_LOCK_OBJID})%'`,
|
|
167
|
+
]),
|
|
168
|
+
{ cwd, stdio: "ignore" },
|
|
169
|
+
)
|
|
131
170
|
}
|