@supatype/cli 0.1.7 → 0.1.10
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 +125 -122
- package/.turbo/turbo-typecheck.log +1 -1
- package/LICENSE +202 -0
- package/deno.d.ts +1 -1
- package/dist/app/framework.js +1 -1
- package/dist/app/framework.js.map +1 -1
- package/dist/augmentation-generator.d.ts +1 -1
- package/dist/augmentation-generator.js +3 -3
- package/dist/augmentation-generator.js.map +1 -1
- package/dist/binary-cache.d.ts +30 -8
- package/dist/binary-cache.d.ts.map +1 -1
- package/dist/binary-cache.js +47 -35
- package/dist/binary-cache.js.map +1 -1
- package/dist/cache-pins.d.ts +1 -1
- package/dist/cache-pins.js +2 -2
- package/dist/cache-pins.js.map +1 -1
- package/dist/cli-artifacts.d.ts +32 -0
- package/dist/cli-artifacts.d.ts.map +1 -0
- package/dist/cli-artifacts.js +49 -0
- package/dist/cli-artifacts.js.map +1 -0
- package/dist/cli-install-method.d.ts +17 -1
- package/dist/cli-install-method.d.ts.map +1 -1
- package/dist/cli-install-method.js +32 -4
- package/dist/cli-install-method.js.map +1 -1
- package/dist/cli-package-version.d.ts +1 -1
- package/dist/cli-package-version.d.ts.map +1 -1
- package/dist/cli-package-version.js +6 -1
- package/dist/cli-package-version.js.map +1 -1
- package/dist/cli-standalone.d.ts +13 -4
- package/dist/cli-standalone.d.ts.map +1 -1
- package/dist/cli-standalone.js +86 -31
- package/dist/cli-standalone.js.map +1 -1
- package/dist/cli-version-embedded.d.ts +10 -0
- package/dist/cli-version-embedded.d.ts.map +1 -0
- package/dist/cli-version-embedded.js +13 -0
- package/dist/cli-version-embedded.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/add.js +4 -3
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/admin.js +6 -6
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/adopt.js +1 -1
- package/dist/commands/adopt.js.map +1 -1
- package/dist/commands/app.js +2 -2
- package/dist/commands/app.js.map +1 -1
- package/dist/commands/cache.d.ts +1 -1
- package/dist/commands/cache.js +3 -3
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/db.d.ts +3 -3
- package/dist/commands/db.d.ts.map +1 -1
- package/dist/commands/db.js +12 -11
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.d.ts +9 -9
- package/dist/commands/deploy.js +12 -12
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +3 -3
- package/dist/commands/dev.js +17 -17
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/engine.d.ts +1 -1
- package/dist/commands/engine.js +1 -1
- package/dist/commands/functions.d.ts.map +1 -1
- package/dist/commands/functions.js +8 -7
- package/dist/commands/functions.js.map +1 -1
- package/dist/commands/hooks.d.ts +2 -2
- package/dist/commands/hooks.js +4 -4
- package/dist/commands/hooks.js.map +1 -1
- package/dist/commands/init.js +28 -28
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/internal.d.ts.map +1 -1
- package/dist/commands/internal.js +37 -0
- package/dist/commands/internal.js.map +1 -1
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logs.d.ts +1 -1
- package/dist/commands/migrate.js +5 -5
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/pg.d.ts +1 -1
- package/dist/commands/pg.js +1 -1
- package/dist/commands/plugins.js +1 -1
- package/dist/commands/plugins.js.map +1 -1
- package/dist/commands/pull.js +2 -2
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.js +3 -3
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/self-host.d.ts +1 -1
- package/dist/commands/self-host.js +1 -1
- package/dist/commands/self-update.d.ts +2 -8
- package/dist/commands/self-update.d.ts.map +1 -1
- package/dist/commands/self-update.js +20 -12
- package/dist/commands/self-update.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/update.d.ts +1 -1
- package/dist/commands/update.js +1 -1
- package/dist/config.d.ts +23 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +37 -18
- package/dist/config.js.map +1 -1
- package/dist/db-preflight.d.ts +4 -4
- package/dist/db-preflight.js +14 -14
- package/dist/db-preflight.js.map +1 -1
- package/dist/dev-compose.d.ts +3 -3
- package/dist/dev-compose.js +27 -27
- package/dist/dev-compose.js.map +1 -1
- package/dist/dev-log-filter.d.ts +1 -1
- package/dist/dev-log-filter.d.ts.map +1 -1
- package/dist/dev-log-filter.js +1 -1
- package/dist/dev-log-filter.js.map +1 -1
- package/dist/dev-ports.d.ts +2 -2
- package/dist/dev-ports.d.ts.map +1 -1
- package/dist/dev-ports.js +2 -2
- package/dist/dev-ports.js.map +1 -1
- package/dist/dev-session.d.ts +5 -5
- package/dist/dev-session.d.ts.map +1 -1
- package/dist/dev-session.js +6 -6
- package/dist/dev-session.js.map +1 -1
- package/dist/dev-shutdown.d.ts +5 -5
- package/dist/dev-shutdown.d.ts.map +1 -1
- package/dist/dev-shutdown.js +7 -7
- package/dist/dev-shutdown.js.map +1 -1
- package/dist/dev-task-colors.d.ts +1 -1
- package/dist/dev-task-colors.d.ts.map +1 -1
- package/dist/dev-task-colors.js +1 -1
- package/dist/dev-task-colors.js.map +1 -1
- package/dist/docker-postgres.d.ts +5 -5
- package/dist/docker-postgres.d.ts.map +1 -1
- package/dist/docker-postgres.js +5 -5
- package/dist/docker-postgres.js.map +1 -1
- package/dist/docker-runtime.d.ts +2 -2
- package/dist/docker-runtime.d.ts.map +1 -1
- package/dist/docker-runtime.js +5 -5
- package/dist/docker-runtime.js.map +1 -1
- package/dist/engine-client.d.ts +1 -1
- package/dist/engine-client.js +3 -3
- package/dist/engine-client.js.map +1 -1
- package/dist/engine-push-output.js +1 -1
- package/dist/engine-push-output.js.map +1 -1
- package/dist/ensure-binary.d.ts.map +1 -1
- package/dist/ensure-binary.js +17 -0
- package/dist/ensure-binary.js.map +1 -1
- package/dist/ensure-component-binaries.js +1 -1
- package/dist/ensure-component-binaries.js.map +1 -1
- package/dist/env-file.d.ts +2 -2
- package/dist/env-file.d.ts.map +1 -1
- package/dist/env-file.js +1 -1
- package/dist/env-file.js.map +1 -1
- package/dist/field-masking-tier.d.ts +5 -5
- package/dist/field-masking-tier.d.ts.map +1 -1
- package/dist/field-masking-tier.js +6 -6
- package/dist/field-masking-tier.js.map +1 -1
- package/dist/functions-deno-types.d.ts +1 -1
- package/dist/functions-deno-types.d.ts.map +1 -1
- package/dist/functions-deno-types.js +3 -3
- package/dist/functions-deno-types.js.map +1 -1
- package/dist/functions-router-gen.js +1 -1
- package/dist/gitignore.d.ts +2 -2
- package/dist/gitignore.d.ts.map +1 -1
- package/dist/gitignore.js +3 -3
- package/dist/gitignore.js.map +1 -1
- package/dist/hook-upload.d.ts +1 -1
- package/dist/hook-upload.js +3 -3
- package/dist/hooks-generator.d.ts +1 -1
- package/dist/hooks-generator.js +9 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/init-project-detect.d.ts +1 -1
- package/dist/init-project-detect.d.ts.map +1 -1
- package/dist/init-project-detect.js +1 -1
- package/dist/init-project-detect.js.map +1 -1
- package/dist/link.d.ts +1 -1
- package/dist/link.d.ts.map +1 -1
- package/dist/local-secrets.d.ts +5 -5
- package/dist/local-secrets.js +5 -5
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +20 -0
- package/dist/main.js.map +1 -0
- package/dist/model-hooks.d.ts +3 -3
- package/dist/model-hooks.js +4 -4
- package/dist/pgbouncer-userlist.d.ts +1 -1
- package/dist/pgbouncer-userlist.d.ts.map +1 -1
- package/dist/pgbouncer-userlist.js +2 -2
- package/dist/pgbouncer-userlist.js.map +1 -1
- package/dist/postgres-ctl.d.ts +1 -1
- package/dist/postgres-ctl.js +4 -4
- package/dist/postgres-ctl.js.map +1 -1
- package/dist/process-manager.d.ts +2 -2
- package/dist/process-manager.d.ts.map +1 -1
- package/dist/process-manager.js +4 -4
- package/dist/process-manager.js.map +1 -1
- package/dist/project-config.d.ts +12 -12
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +9 -9
- package/dist/project-config.js.map +1 -1
- package/dist/pull-utils.d.ts +2 -2
- package/dist/pull-utils.d.ts.map +1 -1
- package/dist/pull-utils.js +4 -4
- package/dist/pull-utils.js.map +1 -1
- package/dist/realtime-launch.js +1 -1
- package/dist/realtime-launch.js.map +1 -1
- package/dist/release-pins.d.ts +1 -1
- package/dist/release-pins.js +2 -2
- package/dist/release-pins.js.map +1 -1
- package/dist/resolve-api-url.d.ts.map +1 -1
- package/dist/resolve-api-url.js +4 -3
- package/dist/resolve-api-url.js.map +1 -1
- package/dist/resolve-target.d.ts +1 -1
- package/dist/resolve-target.d.ts.map +1 -1
- package/dist/rest-cache-admin.js +2 -2
- package/dist/rest-cache-admin.js.map +1 -1
- package/dist/runtime-routes.d.ts +1 -1
- package/dist/runtime-routes.js +1 -1
- package/dist/schema-ast-v2.d.ts +3 -3
- package/dist/schema-ast-v2.d.ts.map +1 -1
- package/dist/schema-ast-v2.js +2 -2
- package/dist/schema-ast-v2.js.map +1 -1
- package/dist/schema-push-lock.js +3 -3
- package/dist/schema-push-lock.js.map +1 -1
- package/dist/scripts/postinstall.d.ts +1 -1
- package/dist/scripts/postinstall.js +1 -1
- package/dist/self-host-compose.d.ts +5 -5
- package/dist/self-host-compose.d.ts.map +1 -1
- package/dist/self-host-compose.js +24 -24
- package/dist/self-host-compose.js.map +1 -1
- package/dist/service-role-check.js +3 -3
- package/dist/service-role-check.js.map +1 -1
- package/dist/storage-provision.d.ts +1 -1
- package/dist/storage-provision.js +3 -3
- package/dist/storage-provision.js.map +1 -1
- package/dist/studio-dev-server.d.ts +1 -1
- package/dist/studio-dev-server.d.ts.map +1 -1
- package/dist/systemd.d.ts +1 -1
- package/dist/systemd.js +1 -1
- package/dist/target-client.js +1 -1
- package/dist/target-client.js.map +1 -1
- package/dist/tsx-runner.d.ts +12 -0
- package/dist/tsx-runner.d.ts.map +1 -1
- package/dist/tsx-runner.js +36 -2
- package/dist/tsx-runner.js.map +1 -1
- package/dist/type-extractor.js +27 -27
- package/dist/type-extractor.js.map +1 -1
- package/dist/type-resolver.js +1 -1
- package/dist/type-resolver.js.map +1 -1
- package/dist/ui/brand.d.ts +1 -1
- package/dist/ui/brand.js +1 -1
- package/dist/ui/components/LogoWordmark.d.ts +1 -1
- package/dist/ui/components/LogoWordmark.d.ts.map +1 -1
- package/dist/ui/components/LogoWordmark.js +1 -1
- package/dist/ui/components/LogoWordmark.js.map +1 -1
- package/dist/ui/components/SelectField.js +1 -1
- package/dist/ui/components/SelectField.js.map +1 -1
- package/dist/ui/confirm.d.ts +1 -1
- package/dist/ui/confirm.js +1 -1
- package/dist/ui/fatal.d.ts +1 -1
- package/dist/ui/fatal.d.ts.map +1 -1
- package/dist/ui/fatal.js +1 -1
- package/dist/ui/fatal.js.map +1 -1
- package/dist/ui/flows/prompt-fields.js +1 -1
- package/dist/ui/flows/prompt-fields.js.map +1 -1
- package/dist/ui/interactive.d.ts +1 -1
- package/dist/ui/interactive.d.ts.map +1 -1
- package/dist/ui/interactive.js +1 -1
- package/dist/ui/interactive.js.map +1 -1
- package/dist/ui/progress.d.ts +1 -1
- package/dist/ui/progress.js +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/run-clack-flow.js +1 -1
- package/dist/ui/runtime/run-clack-flow.js.map +1 -1
- package/dist/ui/runtime/stdin-after-ink.js +1 -1
- package/dist/ui/runtime/stdin-after-ink.js.map +1 -1
- package/dist/ui/theme.d.ts +1 -1
- package/dist/ui/theme.js +1 -1
- package/dist/valkey-sidecar.d.ts +1 -1
- package/dist/valkey-sidecar.d.ts.map +1 -1
- package/dist/valkey-sidecar.js +2 -2
- package/dist/valkey-sidecar.js.map +1 -1
- package/package.json +3 -2
- package/scripts/build-release-artifacts.sh +112 -0
- package/scripts/generate-homebrew-formula.mjs +47 -45
- package/scripts/mirror-deno-release.sh +1 -1
- package/src/TYPE-RESOLUTION.md +31 -31
- package/src/app/framework.ts +1 -1
- package/src/augmentation-generator.ts +3 -3
- package/src/binary-cache.ts +51 -36
- package/src/cache-pins.ts +2 -2
- package/src/cli-artifacts.ts +65 -0
- package/src/cli-install-method.ts +35 -4
- package/src/cli-package-version.ts +5 -1
- package/src/cli-standalone.ts +116 -34
- package/src/cli-version-embedded.ts +12 -0
- package/src/cli.ts +1 -1
- package/src/commands/add.ts +4 -3
- package/src/commands/admin.ts +6 -6
- package/src/commands/adopt.ts +1 -1
- package/src/commands/app.ts +2 -2
- package/src/commands/cache.ts +3 -3
- package/src/commands/db.ts +12 -11
- package/src/commands/deploy.ts +12 -12
- package/src/commands/dev.ts +19 -19
- package/src/commands/doctor.ts +3 -3
- package/src/commands/engine.ts +1 -1
- package/src/commands/functions.ts +8 -7
- package/src/commands/hooks.ts +6 -6
- package/src/commands/init.ts +28 -28
- package/src/commands/internal.ts +37 -0
- package/src/commands/login.ts +2 -2
- package/src/commands/logs.ts +1 -1
- package/src/commands/migrate.ts +5 -5
- package/src/commands/pg.ts +1 -1
- package/src/commands/plugins.ts +1 -1
- package/src/commands/pull.ts +2 -2
- package/src/commands/push.ts +3 -3
- package/src/commands/self-host.ts +1 -1
- package/src/commands/self-update.ts +23 -73
- package/src/commands/status.ts +1 -1
- package/src/commands/update.ts +1 -1
- package/src/config.ts +39 -18
- package/src/db-preflight.ts +15 -15
- package/src/dev-compose.ts +27 -27
- package/src/dev-log-filter.ts +1 -1
- package/src/dev-ports.ts +3 -3
- package/src/dev-session.ts +6 -6
- package/src/dev-shutdown.ts +8 -8
- package/src/dev-task-colors.ts +1 -1
- package/src/docker-postgres.ts +6 -6
- package/src/docker-runtime.ts +5 -5
- package/src/engine-client.ts +3 -3
- package/src/engine-push-output.ts +1 -1
- package/src/ensure-binary.ts +20 -0
- package/src/ensure-component-binaries.ts +1 -1
- package/src/env-file.ts +2 -2
- package/src/field-masking-tier.ts +6 -6
- package/src/functions-deno-types.ts +3 -3
- package/src/functions-router-gen.ts +1 -1
- package/src/gitignore.ts +3 -3
- package/src/hook-upload.ts +3 -3
- package/src/hooks-generator.ts +9 -9
- package/src/index.ts +1 -1
- package/src/init-project-detect.ts +1 -1
- package/src/link.ts +1 -1
- package/src/local-secrets.ts +5 -5
- package/src/main.ts +20 -0
- package/src/model-hooks.ts +4 -4
- package/src/pgbouncer-userlist.ts +2 -2
- package/src/postgres-ctl.ts +4 -4
- package/src/process-manager.ts +4 -4
- package/src/project-config.ts +16 -16
- package/src/pull-utils.ts +4 -4
- package/src/realtime-launch.ts +1 -1
- package/src/release-pins.ts +2 -2
- package/src/resolve-api-url.ts +4 -3
- package/src/resolve-target.ts +1 -1
- package/src/rest-cache-admin.ts +2 -2
- package/src/runtime-routes.ts +2 -2
- package/src/schema-ast-v2.ts +4 -4
- package/src/schema-push-lock.ts +3 -3
- package/src/scripts/postinstall.ts +1 -1
- package/src/self-host-compose.ts +25 -25
- package/src/service-role-check.ts +3 -3
- package/src/storage-provision.ts +3 -3
- package/src/studio-dev-server.ts +1 -1
- package/src/systemd.ts +1 -1
- package/src/target-client.ts +1 -1
- package/src/tsx-runner.ts +41 -2
- package/src/type-extractor.ts +27 -27
- package/src/type-resolver.ts +1 -1
- package/src/ui/README.md +1 -1
- package/src/ui/brand.ts +1 -1
- package/src/ui/components/LogoWordmark.tsx +1 -1
- package/src/ui/components/SelectField.tsx +1 -1
- package/src/ui/confirm.ts +1 -1
- package/src/ui/fatal.ts +1 -1
- package/src/ui/flows/prompt-fields.tsx +1 -1
- package/src/ui/interactive.ts +1 -1
- package/src/ui/progress.ts +1 -1
- package/src/ui/runtime/command-chrome.ts +1 -1
- package/src/ui/runtime/run-clack-flow.tsx +1 -1
- package/src/ui/runtime/stdin-after-ink.ts +1 -1
- package/src/ui/theme.ts +1 -1
- package/src/valkey-sidecar.ts +2 -2
- package/tests/access-composition.test.ts +6 -6
- package/tests/admin-studio-membership.test.ts +1 -1
- package/tests/api-schemas.test.ts +1 -1
- package/tests/archive-name-alias.test.ts +1 -1
- package/tests/cli-help.test.ts +8 -2
- package/tests/config-load-failure.test.ts +44 -0
- package/tests/db-preflight.test.ts +1 -1
- package/tests/doctor-render.test.ts +3 -3
- package/tests/doctor-service-role.test.ts +2 -2
- package/tests/engine-push-output.test.ts +1 -1
- package/tests/env-file.test.ts +3 -3
- package/tests/external-database-compose.test.ts +5 -5
- package/tests/external-database-config.test.ts +2 -2
- package/tests/field-masking-tier.test.ts +1 -1
- package/tests/homebrew-formula.test.ts +68 -26
- package/tests/hook-upload.test.ts +1 -1
- package/tests/hooks-generator.test.ts +1 -1
- package/tests/init.test.ts +2 -2
- package/tests/keys.test.ts +8 -2
- package/tests/local-secrets.test.ts +3 -3
- package/tests/model-hooks.test.ts +6 -6
- package/tests/runtime-contract.test.ts +2 -2
- package/tests/service-role-check.test.ts +3 -3
- package/tests/storage-provision.test.ts +1 -1
- package/tests/type-extractor.test.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +7 -1
- package/scripts/build-release-bundle.mjs +0 -27
package/src/ui/progress.ts
CHANGED
|
@@ -89,7 +89,7 @@ export function isCommandChromeActive(): boolean {
|
|
|
89
89
|
return getActiveFlowApi() !== null
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
/** Commands that mount their own Ink UI
|
|
92
|
+
/** Commands that mount their own Ink UI, do not wrap with command chrome. */
|
|
93
93
|
const WIZARD_COMMAND_PATHS = new Set(["dev", "init", "link", "login", "_postinstall"])
|
|
94
94
|
|
|
95
95
|
/** Prefixes for subcommands that call `runClackFlow` internally. */
|
|
@@ -10,7 +10,7 @@ export function restoreStdinAfterInk(): void {
|
|
|
10
10
|
try {
|
|
11
11
|
if (stdin.isRaw) stdin.setRawMode?.(false)
|
|
12
12
|
} catch {
|
|
13
|
-
// ignore
|
|
13
|
+
// ignore: stdin may already be restored
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// Pause so one-shot Ink flows (cache list, keys, …) can exit; resume() would keep the
|
package/src/ui/theme.ts
CHANGED
package/src/valkey-sidecar.ts
CHANGED
|
@@ -100,7 +100,7 @@ export function ensureValkeySidecar(projectName: string): ValkeySidecarResult {
|
|
|
100
100
|
sleepMs(100)
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
console.warn("[supatype] ⚠ Valkey sidecar started but not reachable yet
|
|
103
|
+
console.warn("[supatype] ⚠ Valkey sidecar started but not reachable yet, cache may bypass initially.")
|
|
104
104
|
return { addr, containerName: name, started: true }
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -109,7 +109,7 @@ export function stopValkeySidecar(containerName: string | null): void {
|
|
|
109
109
|
spawnSync("docker", ["rm", "-f", containerName], { stdio: "ignore" })
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
/** @internal Test helper
|
|
112
|
+
/** @internal Test helper: probe without subprocess. */
|
|
113
113
|
export function probeTcp(host: string, port: number): Promise<boolean> {
|
|
114
114
|
return new Promise((resolve) => {
|
|
115
115
|
const s = createConnection({ host, port })
|
|
@@ -24,7 +24,7 @@ function access(model: ModelAstV2 | undefined): Record<string, unknown> {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Without OR-composition the rule set is a closed list of single shapes, and the
|
|
27
|
-
// commonest real requirement
|
|
27
|
+
// commonest real requirement: "an admin, or the owner", cannot be written at all.
|
|
28
28
|
describe("Any<[…]>", () => {
|
|
29
29
|
it("composes rules into an OR-join", () => {
|
|
30
30
|
const post = extract(
|
|
@@ -81,7 +81,7 @@ export type Post = Model<{
|
|
|
81
81
|
})
|
|
82
82
|
|
|
83
83
|
// An empty list reads like a grant and compiles to a policy that grants
|
|
84
|
-
// nothing
|
|
84
|
+
// nothing: exactly the silent denial the unknown-rule error exists to prevent.
|
|
85
85
|
it("rejects an empty list", () => {
|
|
86
86
|
expect(() =>
|
|
87
87
|
extract(
|
|
@@ -350,7 +350,7 @@ export type Post = Model<{ id: UUID }, { access: { read: In<"a", Rows<"a b; drop
|
|
|
350
350
|
})
|
|
351
351
|
|
|
352
352
|
// The plan's headline parameterisation: the type-level equivalent of Payload's
|
|
353
|
-
// access-control factory. Before this, any named alias
|
|
353
|
+
// access-control factory. Before this, any named alias, even unparameterised,
|
|
354
354
|
// was reported as an unknown rule and had to be written inline at every use.
|
|
355
355
|
describe("parameterised rule aliases", () => {
|
|
356
356
|
it("expands a generic alias at the point of use", () => {
|
|
@@ -480,7 +480,7 @@ export type Post = Model<{ id: UUID }, { access: { update: { using: Public; wat:
|
|
|
480
480
|
})
|
|
481
481
|
|
|
482
482
|
|
|
483
|
-
// "Publish at 09:00 next Tuesday" is *data
|
|
483
|
+
// "Publish at 09:00 next Tuesday" is *data*, the row carries `published_at` and the
|
|
484
484
|
// rule is the same for every row. There is deliberately no literal-timestamp
|
|
485
485
|
// operand; the policy re-evaluates per query, so the row starts matching at 09:00
|
|
486
486
|
// with no cron and no publish worker.
|
|
@@ -589,7 +589,7 @@ export type Post = Model<{ id: UUID }, { access: { read: Gte<"a", Ago<${n}, "day
|
|
|
589
589
|
`
|
|
590
590
|
expect(() => extract(bad("0.5"), "ago-frac")).toThrow(/whole number/)
|
|
591
591
|
// A negative literal is a prefix-unary expression, not a numeric literal, so it
|
|
592
|
-
// needs its own branch
|
|
592
|
+
// needs its own branch, otherwise the message misses the real advice.
|
|
593
593
|
expect(() => extract(bad("-5"), "ago-neg")).toThrow(/does not take a negative amount/)
|
|
594
594
|
})
|
|
595
595
|
|
|
@@ -619,7 +619,7 @@ export type Post = Model<{ id: UUID }, { access: { read: Gte<"a", StartOf<"fortn
|
|
|
619
619
|
})
|
|
620
620
|
|
|
621
621
|
// `In<>` asks "is this row's value in the set". Payload's site-access rule guards on
|
|
622
|
-
// `user.sites?.length > 0` first
|
|
622
|
+
// `user.sites?.length > 0` first, without that, an editor with no sites still
|
|
623
623
|
// matches the unassigned-rows branch.
|
|
624
624
|
describe("Exists<> non-empty guard", () => {
|
|
625
625
|
it("expresses the Payload site-access rule in full", () => {
|
|
@@ -68,7 +68,7 @@ async function seedFirstAdmin(): Promise<Recorded[]> {
|
|
|
68
68
|
|
|
69
69
|
// Capability checks refuse a role they do not recognise, so the CLI's set has to
|
|
70
70
|
// match the server's (`studioRolePermissions`) and the control plane's
|
|
71
|
-
// (`STUDIO_ROLE_PERMISSIONS`) exactly
|
|
71
|
+
// (`STUDIO_ROLE_PERMISSIONS`) exactly: a role only this side knows about creates
|
|
72
72
|
// a user who is locked out of the panel they were made for.
|
|
73
73
|
describe("STUDIO_ROLES", () => {
|
|
74
74
|
it("matches the roles the servers understand", () => {
|
|
@@ -42,7 +42,7 @@ describe("apiSchemas", () => {
|
|
|
42
42
|
|
|
43
43
|
it("leads with the managed schema when pg_schema moves", () => {
|
|
44
44
|
// First entry is what PostgREST serves as the default profile, so the managed schema has to
|
|
45
|
-
// lead
|
|
45
|
+
// lead: otherwise unprefixed requests would resolve against `supatype`.
|
|
46
46
|
expect(apiSchemaList(project({ pg_schema: "app" }))).toBe(
|
|
47
47
|
"app, supatype, graphql_public, auth",
|
|
48
48
|
)
|
|
@@ -4,7 +4,7 @@ import { archiveNameCandidates } from "../src/binary-cache.js"
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* `supatype-postgres` published the Intel macOS archive as `darwin-x86_64` while the CLI asks for
|
|
7
|
-
* `darwin-amd64
|
|
7
|
+
* `darwin-amd64`: the spelling it derives from `process.arch === "x64"` on every platform. So
|
|
8
8
|
* `supatype dev` on an Intel Mac failed with "Checksum not found", and had done for as long as both
|
|
9
9
|
* sides existed: CI could not run Docker on a macOS runner, so the path was never exercised.
|
|
10
10
|
*
|
package/tests/cli-help.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Subprocess tests
|
|
2
|
+
* Subprocess tests: spawn the compiled CLI binary and verify commands are
|
|
3
3
|
* registered. Requires `pnpm build` to have run first (turbo handles this).
|
|
4
4
|
*/
|
|
5
5
|
import { describe, it, expect } from "vitest"
|
|
@@ -17,8 +17,14 @@ const PACKAGE_VERSION = (
|
|
|
17
17
|
function runCli(args: string[]): { stdout: string; stderr: string; exitCode: number } {
|
|
18
18
|
const result = spawnSync(process.execPath, [CLI_BIN, ...args], {
|
|
19
19
|
encoding: "utf8",
|
|
20
|
-
timeout:
|
|
20
|
+
timeout: 60_000,
|
|
21
21
|
})
|
|
22
|
+
if (result.signal) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
`CLI subprocess killed by ${result.signal} after the spawn timeout. `
|
|
25
|
+
+ `Args: ${args.join(" ")}. This is usually machine contention, not a CLI fault.`,
|
|
26
|
+
)
|
|
27
|
+
}
|
|
22
28
|
return {
|
|
23
29
|
stdout: String(result.stdout ?? ""),
|
|
24
30
|
stderr: String(result.stderr ?? ""),
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import { tmpdir } from "node:os"
|
|
4
|
+
import { spawnSync } from "node:child_process"
|
|
5
|
+
import { describe, expect, it } from "vitest"
|
|
6
|
+
|
|
7
|
+
const CLI = join(import.meta.dirname, "../bin/supatype.js")
|
|
8
|
+
|
|
9
|
+
function runIn(dir: string, args: string[]): { out: string; code: number } {
|
|
10
|
+
const r = spawnSync(process.execPath, [CLI, ...args], {
|
|
11
|
+
cwd: dir,
|
|
12
|
+
encoding: "utf8",
|
|
13
|
+
timeout: 60_000,
|
|
14
|
+
})
|
|
15
|
+
if (r.signal) throw new Error(`CLI killed by ${r.signal}, usually machine contention`)
|
|
16
|
+
return { out: `${r.stdout ?? ""}${r.stderr ?? ""}`, code: r.status ?? 1 }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("a config that cannot be read", () => {
|
|
20
|
+
// A broken config used to be indistinguishable from no config: the call sites that catch
|
|
21
|
+
// loadConfig so the CLI works outside a project swallowed both. That is why a standalone
|
|
22
|
+
// binary which could read no config at all still looked like it was working, for a whole
|
|
23
|
+
// release.
|
|
24
|
+
it("is reported, rather than treated as absent", () => {
|
|
25
|
+
const dir = mkdtempSync(join(tmpdir(), "supatype-broken-config-"))
|
|
26
|
+
writeFileSync(
|
|
27
|
+
join(dir, "supatype.config.ts"),
|
|
28
|
+
'throw new Error("deliberately broken")\n',
|
|
29
|
+
"utf8",
|
|
30
|
+
)
|
|
31
|
+
const { out, code } = runIn(dir, ["db", "check"])
|
|
32
|
+
expect(out).toContain("Failed to load supatype.config.ts")
|
|
33
|
+
expect(out).not.toContain("No connection. Pass --connection")
|
|
34
|
+
expect(code).not.toBe(0)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it("does not stop the CLI working with no config at all", () => {
|
|
38
|
+
const dir = mkdtempSync(join(tmpdir(), "supatype-no-config-"))
|
|
39
|
+
mkdirSync(join(dir, "empty"), { recursive: true })
|
|
40
|
+
const { out } = runIn(join(dir, "empty"), ["db", "check"])
|
|
41
|
+
expect(out).toContain("No connection. Pass --connection")
|
|
42
|
+
expect(out).not.toContain("Failed to load")
|
|
43
|
+
})
|
|
44
|
+
})
|
|
@@ -44,7 +44,7 @@ describe("splitting remedies", () => {
|
|
|
44
44
|
|
|
45
45
|
describe("the authenticator password guard", () => {
|
|
46
46
|
// The credential is the operator's by decision. Executing the placeholder would create a role
|
|
47
|
-
// with a password from our source code
|
|
47
|
+
// with a password from our source code, worse than refusing, and harder to notice.
|
|
48
48
|
it("detects a remedy that would execute the placeholder", () => {
|
|
49
49
|
const remedies = [
|
|
50
50
|
result({ remedy: `CREATE ROLE authenticator LOGIN NOINHERIT PASSWORD '${PASSWORD_PLACEHOLDER}';` }),
|
|
@@ -5,7 +5,7 @@ import { printSection } from "../src/commands/doctor.js"
|
|
|
5
5
|
* How a drift item reads to the operator.
|
|
6
6
|
*
|
|
7
7
|
* Items are keyed `table` + `name`, which for an index or constraint are different things and for a
|
|
8
|
-
* *table* are the same
|
|
8
|
+
* *table* are the same, so the natural `table.name` form printed "widget.widget". Tables only
|
|
9
9
|
* started appearing in this report when the ownership gate got its reporting (E17), and a report an
|
|
10
10
|
* operator distrusts is worse than no report.
|
|
11
11
|
*/
|
|
@@ -30,7 +30,7 @@ describe("printSection", () => {
|
|
|
30
30
|
table: "widget",
|
|
31
31
|
name: "widget",
|
|
32
32
|
fields: [],
|
|
33
|
-
message: "Unmanaged table widget
|
|
33
|
+
message: "Unmanaged table widget, push will not drop; manual decision required",
|
|
34
34
|
},
|
|
35
35
|
])
|
|
36
36
|
const text = captured.join("\n")
|
|
@@ -48,7 +48,7 @@ describe("printSection", () => {
|
|
|
48
48
|
table: "widget",
|
|
49
49
|
name: "widget_name_idx",
|
|
50
50
|
fields: ["name"],
|
|
51
|
-
message: "Unmanaged index widget_name_idx on widget
|
|
51
|
+
message: "Unmanaged index widget_name_idx on widget, push will not drop",
|
|
52
52
|
},
|
|
53
53
|
])
|
|
54
54
|
expect(captured.join("\n")).toContain("• widget.widget_name_idx (name)")
|
|
@@ -36,7 +36,7 @@ describe("printServiceRoleGrants", () => {
|
|
|
36
36
|
|
|
37
37
|
it("marks a grant that matches no function", () => {
|
|
38
38
|
printServiceRoleGrants(
|
|
39
|
-
{ ...empty, errors: [' "send-emial"
|
|
39
|
+
{ ...empty, errors: [' "send-emial", no functions/send-emial/index.ts'], missing: ["send-emial"] },
|
|
40
40
|
["send-emial", "audit"],
|
|
41
41
|
)
|
|
42
42
|
const out = lines.join("\n")
|
|
@@ -47,7 +47,7 @@ describe("printServiceRoleGrants", () => {
|
|
|
47
47
|
|
|
48
48
|
it("passes a redundant-entry warning through", () => {
|
|
49
49
|
printServiceRoleGrants(
|
|
50
|
-
{ ...empty, warnings: [' "hooks/x" is not needed
|
|
50
|
+
{ ...empty, warnings: [' "hooks/x" is not needed, a hook receives the key'] },
|
|
51
51
|
["hooks/x"],
|
|
52
52
|
)
|
|
53
53
|
expect(lines.join("\n")).toContain("is not needed")
|
|
@@ -38,7 +38,7 @@ describe("formatEnginePushMessage()", () => {
|
|
|
38
38
|
it("formats up_to_date with admin refresh", () => {
|
|
39
39
|
expect(
|
|
40
40
|
formatEnginePushMessage({ status: "up_to_date", operations: 0, admin_refreshed: true }),
|
|
41
|
-
).toBe("Schema up to date
|
|
41
|
+
).toBe("Schema up to date, Studio metadata synced.")
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
it("formats up_to_date without admin refresh", () => {
|
package/tests/env-file.test.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { MANAGED_MARKER, readEnvFile, upsertEnvFile } from "../src/env-file.js"
|
|
|
10
10
|
* Two defects motivated this: the rewrite rebuilt the file from its assignments alone, so every
|
|
11
11
|
* comment and blank line vanished; and the image keys derivable from `versions` were deleted
|
|
12
12
|
* unconditionally, so `SUPATYPE_REALTIME_IMAGE` could be overridden from `.env` and
|
|
13
|
-
* `SUPATYPE_SERVER_IMAGE` could not. Same file, same shape, different rules
|
|
13
|
+
* `SUPATYPE_SERVER_IMAGE` could not. Same file, same shape, different rules, which is how an hour
|
|
14
14
|
* goes into wondering why a locally built image is ignored.
|
|
15
15
|
*/
|
|
16
16
|
let dir: string
|
|
@@ -63,7 +63,7 @@ JWT_SECRET=abc
|
|
|
63
63
|
|
|
64
64
|
it("does clean up a value it wrote itself", () => {
|
|
65
65
|
// Otherwise removing a pin from config leaves a stale image reference that silently keeps
|
|
66
|
-
// running the old version
|
|
66
|
+
// running the old version, the reason the deletion existed at all.
|
|
67
67
|
upsertEnvFile(
|
|
68
68
|
dir,
|
|
69
69
|
{ SUPATYPE_SERVER_IMAGE: "supatype/server:v1.2.3" },
|
|
@@ -112,7 +112,7 @@ JWT_SECRET=abc
|
|
|
112
112
|
})
|
|
113
113
|
|
|
114
114
|
it("does not treat a commented-out assignment as a value", () => {
|
|
115
|
-
// `# FOO=bar` is a note, not a setting
|
|
115
|
+
// `# FOO=bar` is a note, not a setting, the old parser kept it as a key called "# FOO".
|
|
116
116
|
write("# FOO=bar\nREAL=1\n")
|
|
117
117
|
upsertEnvFile(dir, { REAL: "2" })
|
|
118
118
|
expect(read()).toContain("# FOO=bar")
|
|
@@ -30,7 +30,7 @@ const project = (database: unknown): SupatypeProjectConfig =>
|
|
|
30
30
|
const external = (url = EXTERNAL_URL) => project({ external: { url } })
|
|
31
31
|
const managed = () => project({ provider: "docker" })
|
|
32
32
|
|
|
33
|
-
describe("external database
|
|
33
|
+
describe("external database: compose", () => {
|
|
34
34
|
it("omits the db service and says why", () => {
|
|
35
35
|
const compose = renderSelfHostCompose(external())
|
|
36
36
|
expect(compose).not.toMatch(/^ {2}db:$/m)
|
|
@@ -88,12 +88,12 @@ describe("external database — compose", () => {
|
|
|
88
88
|
it("appends GoTrue's search_path with the right separator", () => {
|
|
89
89
|
// A URL that already has a query string needs `&`; a second `?` produces a DSN that fails to
|
|
90
90
|
// parse, and GoTrue would exit rather than run its auth migrations.
|
|
91
|
-
expect(renderSelfHostCompose(external())).toContain('${DATABASE_URL:?DATABASE_URL is missing from .env
|
|
91
|
+
expect(renderSelfHostCompose(external())).toContain('${DATABASE_URL:?DATABASE_URL is missing from .env, required by database.external}?search_path=auth"')
|
|
92
92
|
expect(
|
|
93
93
|
renderSelfHostCompose(
|
|
94
94
|
external("postgres://owner:secret@db.example.com:5432/app?sslmode=require"),
|
|
95
95
|
),
|
|
96
|
-
).toContain('${DATABASE_URL:?DATABASE_URL is missing from .env
|
|
96
|
+
).toContain('${DATABASE_URL:?DATABASE_URL is missing from .env, required by database.external}&search_path=auth"')
|
|
97
97
|
})
|
|
98
98
|
|
|
99
99
|
it("omits realtime entirely when the project turns it off", () => {
|
|
@@ -109,7 +109,7 @@ describe("external database — compose", () => {
|
|
|
109
109
|
})
|
|
110
110
|
|
|
111
111
|
it("keeps realtime when the flag is unset", () => {
|
|
112
|
-
// Unset means "probe it", not "assume it is broken"
|
|
112
|
+
// Unset means "probe it", not "assume it is broken", the service reports its own capability.
|
|
113
113
|
const compose = renderSelfHostCompose(external())
|
|
114
114
|
expect(compose).toMatch(/^ {2}realtime:$/m)
|
|
115
115
|
expect(compose).toContain("SUPATYPE_REALTIME_URL: http://realtime:4000")
|
|
@@ -157,7 +157,7 @@ describe("external database — compose", () => {
|
|
|
157
157
|
|
|
158
158
|
describe("a loopback external URL", () => {
|
|
159
159
|
// Found by rehearsing a push against a real external Postgres: `db check` passed and `push`
|
|
160
|
-
// applied the schema, because the CLI runs on the host
|
|
160
|
+
// applied the schema, because the CLI runs on the host, then storage, realtime and the server all
|
|
161
161
|
// died with ECONNREFUSED against their own loopback, because inside a container `127.0.0.1` is
|
|
162
162
|
// that container. A retry loop would only have hidden it.
|
|
163
163
|
it("is detected, whatever form it takes", () => {
|
|
@@ -28,7 +28,7 @@ const raw = (database: unknown, rest: Record<string, unknown> = {}): unknown =>
|
|
|
28
28
|
const validate = (database: unknown, rest?: Record<string, unknown>) =>
|
|
29
29
|
validateProjectConfig(raw(database, rest), "supatype.config.ts")
|
|
30
30
|
|
|
31
|
-
describe("database.external
|
|
31
|
+
describe("database.external: accepted", () => {
|
|
32
32
|
it("accepts a url on its own, with no database.provider", () => {
|
|
33
33
|
const cfg = validate({ external: { url: EXTERNAL_URL } })
|
|
34
34
|
expect(externalDatabaseUrl(cfg)).toBe(EXTERNAL_URL)
|
|
@@ -52,7 +52,7 @@ describe("database.external — accepted", () => {
|
|
|
52
52
|
})
|
|
53
53
|
})
|
|
54
54
|
|
|
55
|
-
describe("database.external
|
|
55
|
+
describe("database.external: rejected", () => {
|
|
56
56
|
it("rejects a missing url", () => {
|
|
57
57
|
expect(() => validate({ external: {} })).toThrow(/database\.external\.url is required/)
|
|
58
58
|
expect(() => validate({ external: { url: " " } })).toThrow(
|
|
@@ -20,7 +20,7 @@ import { apiSchemaList, validateProjectConfig, type SupatypeProjectConfig } from
|
|
|
20
20
|
*
|
|
21
21
|
* The rule is deliberately **not** "is the database external". A native `supatype dev` has no
|
|
22
22
|
* extension either, and calling that tier 1 would point PostgREST at a schema whose tables the API
|
|
23
|
-
* roles no longer hold privileges on
|
|
23
|
+
* roles no longer hold privileges on, every request denied.
|
|
24
24
|
*/
|
|
25
25
|
const project = (database: unknown, rest: Record<string, unknown> = {}): SupatypeProjectConfig =>
|
|
26
26
|
validateProjectConfig(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
|
2
|
+
import { createHash } from "node:crypto"
|
|
2
3
|
import { join } from "node:path"
|
|
3
4
|
import { tmpdir } from "node:os"
|
|
4
5
|
import { spawnSync } from "node:child_process"
|
|
@@ -7,19 +8,36 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"
|
|
|
7
8
|
let counter = 0
|
|
8
9
|
let tmpDir: string
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"supatype-cli-
|
|
14
|
-
"supatype-cli-
|
|
11
|
+
// The published artefacts: one archive per platform, plus the musl variants Homebrew does not
|
|
12
|
+
// use, since Homebrew on Linux is glibc.
|
|
13
|
+
const ARCHIVES = [
|
|
14
|
+
"supatype-cli-darwin-arm64.tar.gz",
|
|
15
|
+
"supatype-cli-darwin-amd64.tar.gz",
|
|
16
|
+
"supatype-cli-linux-arm64.tar.gz",
|
|
17
|
+
"supatype-cli-linux-amd64.tar.gz",
|
|
18
|
+
"supatype-cli-linux-amd64-musl.tar.gz",
|
|
19
|
+
"supatype-cli-windows-amd64.zip",
|
|
15
20
|
]
|
|
16
21
|
|
|
22
|
+
const script = () => join(import.meta.dirname, "../scripts/generate-homebrew-formula.mjs")
|
|
23
|
+
|
|
24
|
+
/** Write stub archives and the checksums manifest that build-release-artifacts.sh produces. */
|
|
25
|
+
function writeArtifacts(names: string[]): Record<string, string> {
|
|
26
|
+
const hashes: Record<string, string> = {}
|
|
27
|
+
const lines: string[] = []
|
|
28
|
+
for (const name of names) {
|
|
29
|
+
const body = `stub-${name}\n`
|
|
30
|
+
writeFileSync(join(tmpDir, name), body, "utf8")
|
|
31
|
+
hashes[name] = createHash("sha256").update(body).digest("hex")
|
|
32
|
+
lines.push(`${hashes[name]} ${name}`)
|
|
33
|
+
}
|
|
34
|
+
writeFileSync(join(tmpDir, "checksums.sha256"), lines.join("\n") + "\n", "utf8")
|
|
35
|
+
return hashes
|
|
36
|
+
}
|
|
37
|
+
|
|
17
38
|
beforeEach(() => {
|
|
18
39
|
tmpDir = join(tmpdir(), `homebrew-formula-${Date.now()}-${++counter}`)
|
|
19
40
|
mkdirSync(tmpDir, { recursive: true })
|
|
20
|
-
for (const name of PLATFORMS) {
|
|
21
|
-
writeFileSync(join(tmpDir, name), `stub-${name}\n`, "utf8")
|
|
22
|
-
}
|
|
23
41
|
})
|
|
24
42
|
|
|
25
43
|
afterEach(() => {
|
|
@@ -27,32 +45,56 @@ afterEach(() => {
|
|
|
27
45
|
})
|
|
28
46
|
|
|
29
47
|
describe("generate-homebrew-formula.mjs", () => {
|
|
30
|
-
it("
|
|
48
|
+
it("points at the published archives, with the hashes from the manifest", () => {
|
|
49
|
+
const hashes = writeArtifacts(ARCHIVES)
|
|
31
50
|
const outPath = join(tmpDir, "supatype.rb")
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
process.
|
|
35
|
-
|
|
36
|
-
{
|
|
37
|
-
encoding: "utf8",
|
|
38
|
-
env: { ...process.env, HOMEBREW_FORMULA_OUT: outPath },
|
|
39
|
-
},
|
|
40
|
-
)
|
|
51
|
+
const result = spawnSync(process.execPath, [script(), "9.9.9", tmpDir], {
|
|
52
|
+
encoding: "utf8",
|
|
53
|
+
env: { ...process.env, HOMEBREW_FORMULA_OUT: outPath },
|
|
54
|
+
})
|
|
41
55
|
|
|
42
56
|
expect(result.status, result.stderr).toBe(0)
|
|
43
57
|
const formula = readFileSync(outPath, "utf8")
|
|
58
|
+
|
|
44
59
|
expect(formula).toContain('version "9.9.9"')
|
|
45
|
-
expect(formula).toContain("
|
|
46
|
-
expect(formula).
|
|
60
|
+
expect(formula).toContain('license "Apache-2.0"')
|
|
61
|
+
expect(formula).toContain(
|
|
62
|
+
"https://releases.supatype.com/cli/v9.9.9/supatype-cli-darwin-arm64.tar.gz",
|
|
63
|
+
)
|
|
64
|
+
// The hash has to be the manifest's, not one the generator computed for itself: the manifest
|
|
65
|
+
// is the signed record of what was published.
|
|
66
|
+
expect(formula).toContain(`sha256 "${hashes["supatype-cli-darwin-arm64.tar.gz"]}"`)
|
|
67
|
+
// Every archive holds one executable called `supatype`, so there is no per-platform rename.
|
|
68
|
+
expect(formula).toContain('bin.install "supatype"')
|
|
47
69
|
expect(formula).toContain('system bin/"supatype", "_postinstall"')
|
|
48
|
-
expect(formula).toContain('bin.install "supatype-cli-#{arch}" => "supatype"')
|
|
49
70
|
})
|
|
50
71
|
|
|
51
|
-
it("
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const result = spawnSync(process.execPath, [script, "
|
|
72
|
+
it("does not reference the musl or windows artefacts", () => {
|
|
73
|
+
writeArtifacts(ARCHIVES)
|
|
74
|
+
const outPath = join(tmpDir, "supatype.rb")
|
|
75
|
+
const result = spawnSync(process.execPath, [script(), "9.9.9", tmpDir], {
|
|
76
|
+
encoding: "utf8",
|
|
77
|
+
env: { ...process.env, HOMEBREW_FORMULA_OUT: outPath },
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
expect(result.status, result.stderr).toBe(0)
|
|
81
|
+
const formula = readFileSync(outPath, "utf8")
|
|
82
|
+
expect(formula).not.toContain("musl")
|
|
83
|
+
expect(formula).not.toContain("windows")
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it("fails when the manifest is missing, rather than hashing the files itself", () => {
|
|
87
|
+
writeArtifacts(ARCHIVES)
|
|
88
|
+
rmSync(join(tmpDir, "checksums.sha256"))
|
|
89
|
+
const result = spawnSync(process.execPath, [script(), "1.0.0", tmpDir], { encoding: "utf8" })
|
|
90
|
+
expect(result.status).not.toBe(0)
|
|
91
|
+
expect(result.stderr).toContain("checksums.sha256")
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it("fails when the manifest omits a platform it needs", () => {
|
|
95
|
+
writeArtifacts(ARCHIVES.filter((n) => n !== "supatype-cli-linux-amd64.tar.gz"))
|
|
96
|
+
const result = spawnSync(process.execPath, [script(), "1.0.0", tmpDir], { encoding: "utf8" })
|
|
55
97
|
expect(result.status).not.toBe(0)
|
|
56
|
-
expect(result.stderr).toContain("
|
|
98
|
+
expect(result.stderr).toContain("No checksum for supatype-cli-linux-amd64.tar.gz")
|
|
57
99
|
})
|
|
58
100
|
})
|
|
@@ -86,7 +86,7 @@ describe("readHookUpload", () => {
|
|
|
86
86
|
})
|
|
87
87
|
|
|
88
88
|
it("refuses a hook with a second file rather than dropping it", () => {
|
|
89
|
-
// Silent truncation would deploy successfully and fail at import
|
|
89
|
+
// Silent truncation would deploy successfully and fail at import, which reads to the caller as
|
|
90
90
|
// that table's writes being broken for no visible reason.
|
|
91
91
|
const { cwd, hooks } = project()
|
|
92
92
|
writeHook(hooks, "moderate-post", HANDLER, { "helpers.ts": "export const x = 1\n" })
|
|
@@ -71,7 +71,7 @@ export type Post = Model<{ id: UUID }, { tableName: "posts" }>
|
|
|
71
71
|
describe("the generated module compiles", () => {
|
|
72
72
|
/**
|
|
73
73
|
* The generator emits TypeScript, so the only test that really proves it works is a compiler.
|
|
74
|
-
* A missing brace or a type that does not resolve would otherwise reach a user's editor
|
|
74
|
+
* A missing brace or a type that does not resolve would otherwise reach a user's editor, and this
|
|
75
75
|
* file is imported by their hook, so a broken emit breaks their function rather than our build.
|
|
76
76
|
*/
|
|
77
77
|
it("typechecks under strict mode, together with a handler that uses it", () => {
|
package/tests/init.test.ts
CHANGED
|
@@ -329,7 +329,7 @@ describe("scaffold()", () => {
|
|
|
329
329
|
expect(config).toContain('provider: "local"')
|
|
330
330
|
expect(config).toContain("Production storage: external S3")
|
|
331
331
|
const env = readFileSync(join(tmpRoot, ".env"), "utf8")
|
|
332
|
-
expect(env).toContain("local development
|
|
333
|
-
expect(env).toContain("production
|
|
332
|
+
expect(env).toContain("local development, MinIO")
|
|
333
|
+
expect(env).toContain("production, external bucket")
|
|
334
334
|
})
|
|
335
335
|
})
|
package/tests/keys.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for `supatype keys
|
|
2
|
+
* Tests for `supatype keys`, JWT generation command.
|
|
3
3
|
* Uses subprocess tests (requires built dist/) for the CLI integration,
|
|
4
4
|
* plus direct module tests for the signing logic.
|
|
5
5
|
*/
|
|
@@ -20,10 +20,16 @@ function runCli(
|
|
|
20
20
|
): { stdout: string; stderr: string; exitCode: number } {
|
|
21
21
|
const result = spawnSync(process.execPath, [CLI_BIN, ...args], {
|
|
22
22
|
encoding: "utf8",
|
|
23
|
-
timeout:
|
|
23
|
+
timeout: 60_000,
|
|
24
24
|
cwd: opts.cwd,
|
|
25
25
|
env: { ...process.env, ...opts.env },
|
|
26
26
|
})
|
|
27
|
+
if (result.signal) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`CLI subprocess killed by ${result.signal} after the spawn timeout. `
|
|
30
|
+
+ `Args: ${args.join(" ")}. This is usually machine contention, not a CLI fault.`,
|
|
31
|
+
)
|
|
32
|
+
}
|
|
27
33
|
return {
|
|
28
34
|
stdout: String(result.stdout ?? ""),
|
|
29
35
|
stderr: String(result.stderr ?? ""),
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import { upsertEnvFile } from "../src/env-file.js"
|
|
15
15
|
|
|
16
16
|
// The bug these exist to prevent: `supatype dev` used to pin POSTGRES_PASSWORD and JWT_SECRET
|
|
17
|
-
// to published constants in `.env` on every run
|
|
17
|
+
// to published constants in `.env` on every run, the same `.env` a self-host deployment reads.
|
|
18
18
|
// A generated secret survived until the developer's next `dev`, then reverted silently, and the
|
|
19
19
|
// deployment went out with a secret anyone can look up.
|
|
20
20
|
|
|
@@ -32,7 +32,7 @@ describe("resolving local secrets", () => {
|
|
|
32
32
|
expect(devAuthenticatorPassword(dir)).toBe("auth-mine")
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
// A project with no `.env` still has to start, so the constants remain
|
|
35
|
+
// A project with no `.env` still has to start, so the constants remain, as fallbacks only.
|
|
36
36
|
it("falls back when the project has none", () => {
|
|
37
37
|
const dir = project()
|
|
38
38
|
expect(devJwtSecret(dir)).toBe(FALLBACK_JWT_SECRET)
|
|
@@ -43,7 +43,7 @@ describe("resolving local secrets", () => {
|
|
|
43
43
|
|
|
44
44
|
describe("the dev env write does not clobber secrets", () => {
|
|
45
45
|
// This is the regression. `upsertEnvFile` replaces any key handed to it, so the guarantee has
|
|
46
|
-
// to be that the dev path never hands it these
|
|
46
|
+
// to be that the dev path never hands it these, asserted here at the level that matters:
|
|
47
47
|
// write what dev writes, then check the secrets are byte-identical.
|
|
48
48
|
it("leaves generated secrets untouched across repeated writes", () => {
|
|
49
49
|
const dir = project(
|