@supatype/cli 0.2.1 → 0.3.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +180 -143
- package/.turbo/turbo-typecheck.log +1 -1
- package/dist/api-config-cache.d.ts +34 -0
- package/dist/api-config-cache.d.ts.map +1 -0
- package/dist/api-config-cache.js +123 -0
- package/dist/api-config-cache.js.map +1 -0
- package/dist/cache-identity-scope.d.ts +38 -0
- package/dist/cache-identity-scope.d.ts.map +1 -0
- package/dist/cache-identity-scope.js +70 -0
- package/dist/cache-identity-scope.js.map +1 -0
- package/dist/cache-provider.d.ts +30 -0
- package/dist/cache-provider.d.ts.map +1 -0
- package/dist/cache-provider.js +60 -0
- package/dist/cache-provider.js.map +1 -0
- package/dist/cli-version-embedded.js +1 -1
- package/dist/commands/add.js +1 -1
- package/dist/commands/add.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/cloud.d.ts.map +1 -1
- package/dist/commands/cloud.js +2 -1
- package/dist/commands/cloud.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +2 -1
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +61 -8
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +2 -1
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/functions.d.ts.map +1 -1
- package/dist/commands/functions.js +6 -2
- package/dist/commands/functions.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +13 -9
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +2 -1
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +52 -1
- package/dist/commands/push.js.map +1 -1
- package/dist/compose-services.d.ts.map +1 -1
- package/dist/compose-services.js +2 -1
- package/dist/compose-services.js.map +1 -1
- package/dist/dev-compose.d.ts.map +1 -1
- package/dist/dev-compose.js +18 -7
- package/dist/dev-compose.js.map +1 -1
- package/dist/engine-floor.d.ts +11 -1
- package/dist/engine-floor.d.ts.map +1 -1
- package/dist/engine-floor.js +49 -16
- package/dist/engine-floor.js.map +1 -1
- package/dist/functions-deno-types.d.ts +9 -0
- package/dist/functions-deno-types.d.ts.map +1 -1
- package/dist/functions-deno-types.js +45 -1
- package/dist/functions-deno-types.js.map +1 -1
- package/dist/functions-router-gen.d.ts.map +1 -1
- package/dist/functions-router-gen.js +113 -81
- package/dist/functions-router-gen.js.map +1 -1
- package/dist/kong-config.d.ts +1 -1
- package/dist/model-cache.d.ts +17 -0
- package/dist/model-cache.d.ts.map +1 -0
- package/dist/model-cache.js +45 -0
- package/dist/model-cache.js.map +1 -0
- package/dist/model-hooks.d.ts +5 -0
- package/dist/model-hooks.d.ts.map +1 -1
- package/dist/model-hooks.js +29 -1
- package/dist/model-hooks.js.map +1 -1
- package/dist/model-versioning.d.ts +80 -0
- package/dist/model-versioning.d.ts.map +1 -0
- package/dist/model-versioning.js +140 -0
- package/dist/model-versioning.js.map +1 -0
- package/dist/postgres-ctl.d.ts +55 -0
- package/dist/postgres-ctl.d.ts.map +1 -1
- package/dist/postgres-ctl.js +84 -8
- package/dist/postgres-ctl.js.map +1 -1
- package/dist/preview-config-check.d.ts +21 -0
- package/dist/preview-config-check.d.ts.map +1 -0
- package/dist/preview-config-check.js +47 -0
- package/dist/preview-config-check.js.map +1 -0
- package/dist/project-config.d.ts +182 -5
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +125 -8
- package/dist/project-config.js.map +1 -1
- package/dist/resolve-target.d.ts +9 -0
- package/dist/resolve-target.d.ts.map +1 -1
- package/dist/resolve-target.js.map +1 -1
- package/dist/rest-cache-admin.d.ts.map +1 -1
- package/dist/rest-cache-admin.js +6 -2
- package/dist/rest-cache-admin.js.map +1 -1
- package/dist/schema-ast-v2.d.ts +32 -1
- package/dist/schema-ast-v2.d.ts.map +1 -1
- package/dist/schema-ast-v2.js +14 -1
- package/dist/schema-ast-v2.js.map +1 -1
- package/dist/self-host-compose.d.ts +20 -1
- package/dist/self-host-compose.d.ts.map +1 -1
- package/dist/self-host-compose.js +181 -27
- package/dist/self-host-compose.js.map +1 -1
- package/dist/studio-admin-roles.d.ts +8 -1
- package/dist/studio-admin-roles.d.ts.map +1 -1
- package/dist/studio-admin-roles.js +16 -2
- package/dist/studio-admin-roles.js.map +1 -1
- package/dist/type-extractor.d.ts +7 -0
- package/dist/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor.js +234 -3
- package/dist/type-extractor.js.map +1 -1
- package/package.json +2 -2
- package/src/api-config-cache.ts +142 -0
- package/src/cache-identity-scope.ts +92 -0
- package/src/cache-provider.ts +61 -0
- package/src/cli-version-embedded.ts +1 -1
- package/src/commands/add.ts +1 -1
- package/src/commands/cache.ts +3 -3
- package/src/commands/cloud.ts +2 -1
- package/src/commands/deploy.ts +2 -1
- package/src/commands/dev.ts +68 -7
- package/src/commands/diff.ts +2 -1
- package/src/commands/functions.ts +6 -2
- package/src/commands/init.ts +13 -9
- package/src/commands/migrate.ts +2 -1
- package/src/commands/push.ts +57 -1
- package/src/compose-services.ts +2 -1
- package/src/dev-compose.ts +18 -7
- package/src/engine-floor.ts +73 -16
- package/src/functions-deno-types.ts +48 -1
- package/src/functions-router-gen.ts +113 -81
- package/src/kong-config.ts +1 -1
- package/src/model-cache.ts +74 -0
- package/src/model-hooks.ts +26 -2
- package/src/model-versioning.ts +167 -0
- package/src/postgres-ctl.ts +103 -9
- package/src/preview-config-check.ts +52 -0
- package/src/project-config.ts +273 -11
- package/src/resolve-target.ts +11 -1
- package/src/rest-cache-admin.ts +8 -2
- package/src/schema-ast-v2.ts +47 -0
- package/src/self-host-compose.ts +204 -27
- package/src/studio-admin-roles.ts +16 -2
- package/src/type-extractor.ts +281 -2
- package/tests/api-config-cache-seed.test.ts +180 -0
- package/tests/cache-identity-scope.test.ts +61 -0
- package/tests/cache-provider-config.test.ts +132 -0
- package/tests/engine-floor.test.ts +43 -0
- package/tests/external-database-compose.test.ts +74 -3
- package/tests/field-masking-tier.test.ts +3 -3
- package/tests/fixtures/identity-scope-corpus.json +42 -0
- package/tests/functions-concurrency.test.ts +71 -0
- package/tests/init.test.ts +36 -2
- package/tests/model-cache-declaration.test.ts +229 -0
- package/tests/model-cache-manifest.test.ts +99 -0
- package/tests/model-hooks.test.ts +55 -0
- package/tests/model-versions.test.ts +229 -0
- package/tests/native-keyspace.test.ts +130 -0
- package/tests/preview-config-check.test.ts +104 -0
- package/tests/rest-cache-admin.test.ts +36 -0
- package/tests/runtime-contract.test.ts +176 -22
- package/tests/studio-admin-roles.test.ts +32 -0
- package/tests/type-extractor.test.ts +113 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which models keep drafts and version history, read from the extracted schema.
|
|
3
|
+
*
|
|
4
|
+
* The answer shapes things decided before any database exists: whether `PGRST_DB_SCHEMA` names the
|
|
5
|
+
* generated `draft` schema, and whether the push refuses a model that also masks a column. So it is
|
|
6
|
+
* read from the AST rather than asked of Postgres, the same way
|
|
7
|
+
* [`field-masking-tier`](./field-masking-tier.ts) decides the masking tier offline.
|
|
8
|
+
*
|
|
9
|
+
* Shaped loosely on purpose: the CLI's AST carries `options` as an opaque record, and nothing here
|
|
10
|
+
* needs more than "is `versions` present, and what did it ask for".
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync } from "node:fs";
|
|
13
|
+
import { loadSchemaAst } from "./config.js";
|
|
14
|
+
import { draftVisibilityRoles, previewLimits, schemaPathFromProject } from "./project-config.js";
|
|
15
|
+
/** Versions kept per record when the model states no retention. */
|
|
16
|
+
export const DEFAULT_VERSIONS_KEPT = 20;
|
|
17
|
+
/**
|
|
18
|
+
* Normalise a `versions` value from the AST.
|
|
19
|
+
*
|
|
20
|
+
* `true` is shorthand for `{ drafts: true }` with the default retention, and a non-positive or
|
|
21
|
+
* unparseable `keep` falls back to the default rather than to "keep nothing": pruning to zero would
|
|
22
|
+
* delete the draft the author is editing.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveVersionsOptions(raw) {
|
|
25
|
+
if (raw === true)
|
|
26
|
+
return { drafts: true, keep: DEFAULT_VERSIONS_KEPT };
|
|
27
|
+
if (typeof raw !== "object" || raw === null)
|
|
28
|
+
return undefined;
|
|
29
|
+
const record = raw;
|
|
30
|
+
const keep = typeof record.keep === "number" && Number.isFinite(record.keep) && record.keep >= 1
|
|
31
|
+
? Math.floor(record.keep)
|
|
32
|
+
: DEFAULT_VERSIONS_KEPT;
|
|
33
|
+
return { drafts: record.drafts !== false, keep };
|
|
34
|
+
}
|
|
35
|
+
/** Every model in the schema that declares `versions`, in declaration order. */
|
|
36
|
+
export function versionedModels(ast) {
|
|
37
|
+
const models = ast?.models;
|
|
38
|
+
if (!Array.isArray(models))
|
|
39
|
+
return [];
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const entry of models) {
|
|
42
|
+
const model = entry;
|
|
43
|
+
if (model === null || typeof model !== "object")
|
|
44
|
+
continue;
|
|
45
|
+
const options = resolveVersionsOptions(model.options?.["versions"]);
|
|
46
|
+
if (options === undefined)
|
|
47
|
+
continue;
|
|
48
|
+
const name = typeof model.name === "string" ? model.name : "";
|
|
49
|
+
const tableName = model.annotations?.db?.tableName;
|
|
50
|
+
out.push({
|
|
51
|
+
name,
|
|
52
|
+
tableName: typeof tableName === "string" ? tableName : name,
|
|
53
|
+
options,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
/** Whether anything in the schema is versioned, which is what exposes the `draft` schema. */
|
|
59
|
+
export function schemaHasVersionedModels(ast) {
|
|
60
|
+
return versionedModels(ast).length > 0;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Models declaring both `versions` and per-column rules, which cannot both be enforced.
|
|
64
|
+
*
|
|
65
|
+
* A version snapshot is opaque `jsonb`. `supatype_mask` is driven by security labels on a specific
|
|
66
|
+
* table's column and rewrites references to *that* column, and the view tier puts the masking
|
|
67
|
+
* expression in a view over the real columns: neither can see inside a snapshot. So a masked value
|
|
68
|
+
* sits in plain sight in the versions table for anyone able to read it, and the push refuses rather
|
|
69
|
+
* than applying a schema whose restrictions have a hole in them.
|
|
70
|
+
*
|
|
71
|
+
* Per model, and that matters: under the view tier the managed schema comes off the exposed list but
|
|
72
|
+
* the API roles keep their privileges on the base tables, so a `security_invoker` view in an exposed
|
|
73
|
+
* schema — which is exactly what `draft.<table>` is — reaches past the `api` layer. A project may
|
|
74
|
+
* hold a masked model and a versioned model at once; one model may not be both.
|
|
75
|
+
*/
|
|
76
|
+
export function modelsWithVersionsAndFieldRules(ast) {
|
|
77
|
+
const models = ast?.models;
|
|
78
|
+
if (!Array.isArray(models))
|
|
79
|
+
return [];
|
|
80
|
+
const out = [];
|
|
81
|
+
for (const entry of models) {
|
|
82
|
+
const model = entry;
|
|
83
|
+
if (model === null || typeof model !== "object")
|
|
84
|
+
continue;
|
|
85
|
+
if (resolveVersionsOptions(model.options?.["versions"]) === undefined)
|
|
86
|
+
continue;
|
|
87
|
+
const fields = model.annotations?.platform?.access?.["fields"];
|
|
88
|
+
if (typeof fields !== "object" || fields === null || Object.keys(fields).length === 0)
|
|
89
|
+
continue;
|
|
90
|
+
out.push(typeof model.name === "string" ? model.name : "(unnamed model)");
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Whether this project on disk has any versioned model.
|
|
96
|
+
*
|
|
97
|
+
* A schema that fails to load reads as "no versioned models", the narrower answer: deciding the
|
|
98
|
+
* exposed-schema list is the wrong moment to report a syntax error, and `push` and `dev` do it
|
|
99
|
+
* properly moments later with the file and line. Narrower rather than wider on purpose, since the
|
|
100
|
+
* failure mode of guessing wrong here is exposing a schema of drafts.
|
|
101
|
+
*/
|
|
102
|
+
export function projectHasVersionedModels(cwd, config) {
|
|
103
|
+
try {
|
|
104
|
+
const schemaPath = schemaPathFromProject(config, cwd);
|
|
105
|
+
if (!existsSync(schemaPath))
|
|
106
|
+
return false;
|
|
107
|
+
return schemaHasVersionedModels(loadSchemaAst(schemaPath, cwd));
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The AST with this project's publishing settings attached, when anything is versioned.
|
|
115
|
+
*
|
|
116
|
+
* The engine compiles draft visibility into the generated policies, and it **refuses** a push whose
|
|
117
|
+
* schema has versioned models and carries no settings rather than applying a default. That refusal
|
|
118
|
+
* is the reason this is safe to add at a handful of call sites instead of somewhere unmissable: a
|
|
119
|
+
* path that forgets fails loudly at push time, naming what is missing, rather than quietly
|
|
120
|
+
* narrowing or widening who can read unpublished content.
|
|
121
|
+
*
|
|
122
|
+
* Returns the AST untouched for a project with no versioned model, so nothing else grows a key it
|
|
123
|
+
* has no use for.
|
|
124
|
+
*/
|
|
125
|
+
export function withPublishing(ast, config) {
|
|
126
|
+
if (!schemaHasVersionedModels(ast))
|
|
127
|
+
return ast;
|
|
128
|
+
const limits = previewLimits(config);
|
|
129
|
+
return {
|
|
130
|
+
...ast,
|
|
131
|
+
publishing: {
|
|
132
|
+
draftVisibility: draftVisibilityRoles(config),
|
|
133
|
+
previewDefaultTtl: limits.defaultTtl,
|
|
134
|
+
previewMaxRecordTtl: limits.maxRecordTtl,
|
|
135
|
+
previewMaxProjectTtl: limits.maxProjectTtl,
|
|
136
|
+
previewAllowProjectScope: limits.allowProjectScope,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=model-versioning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-versioning.js","sourceRoot":"","sources":["../src/model-versioning.ts"],"names":[],"mappings":"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"}
|
package/dist/postgres-ctl.d.ts
CHANGED
|
@@ -11,6 +11,15 @@ export interface PgOptions {
|
|
|
11
11
|
port: number;
|
|
12
12
|
/** Path to write the postgres log file. */
|
|
13
13
|
logPath?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Port for the RESP keyspace, when the native install carries pg_keyspace.
|
|
16
|
+
*
|
|
17
|
+
* Absent means do not serve RESP at all: `supatype dev` then starts the
|
|
18
|
+
* Valkey sidecar instead, as it always has.
|
|
19
|
+
*/
|
|
20
|
+
keyspacePort?: number;
|
|
21
|
+
/** Database durable keys are written to. Ignored while everything is ephemeral. */
|
|
22
|
+
keyspaceDatabase?: string;
|
|
14
23
|
}
|
|
15
24
|
/**
|
|
16
25
|
* Native Postgres bundles are built with prefix /usr/local/supatype-pg; dyld/ld
|
|
@@ -37,6 +46,52 @@ export declare function initdb(opts: PgOptions): void;
|
|
|
37
46
|
* `lib/postgresql/`.
|
|
38
47
|
*/
|
|
39
48
|
export declare function nativeMaskLibraryPresent(pgBinDir: string | null | undefined): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Whether a native Postgres install carries the RESP keyspace.
|
|
51
|
+
*
|
|
52
|
+
* Asked of the filesystem for the same reason as the mask: an archive
|
|
53
|
+
* downloaded before pg_keyspace was bundled has a Postgres without it, and the
|
|
54
|
+
* Windows archive has none at all — pgrx has no Windows target. Naming it in
|
|
55
|
+
* `shared_preload_libraries` anyway would stop the server starting with "could
|
|
56
|
+
* not access file", which would turn a missing cache into no database.
|
|
57
|
+
*/
|
|
58
|
+
export declare function nativeKeyspaceLibraryPresent(pgBinDir: string | null | undefined): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Where the native RESP keyspace looks for a free port, and how far it looks.
|
|
61
|
+
*
|
|
62
|
+
* 6379 first, because that is what a developer's tooling and the Valkey
|
|
63
|
+
* sidecar before it both used, so the familiar port stays the usual answer.
|
|
64
|
+
*/
|
|
65
|
+
export declare const KEYSPACE_PORT_BASE = 6379;
|
|
66
|
+
export declare const KEYSPACE_PORT_SPAN = 10;
|
|
67
|
+
/**
|
|
68
|
+
* The first free port in [base, base + span), or null when they are all taken.
|
|
69
|
+
*
|
|
70
|
+
* Binding a port something else already holds would leave Postgres up and the
|
|
71
|
+
* keyspace silently dead — the failure lands in the postmaster log and nowhere
|
|
72
|
+
* a developer is looking — so the port is chosen before the server starts
|
|
73
|
+
* rather than fixed and hoped for.
|
|
74
|
+
*/
|
|
75
|
+
export declare function firstFreePort(base: number, span: number): Promise<number | null>;
|
|
76
|
+
/**
|
|
77
|
+
* The `-o` options pg_ctl passes to the server.
|
|
78
|
+
*
|
|
79
|
+
* Separated from the spawn so the decision is testable. What goes in here is
|
|
80
|
+
* decided by which libraries the archive happens to carry, which is exactly
|
|
81
|
+
* the kind of thing that is wrong in one combination nobody runs locally.
|
|
82
|
+
*
|
|
83
|
+
* Order in `shared_preload_libraries` is load-bearing: pg_keyspace first, then
|
|
84
|
+
* supatype_mask, so the mask stays outermost. pg_keyspace checks this itself
|
|
85
|
+
* and refuses to serve when the order is wrong — deliberately, since RESP
|
|
86
|
+
* would otherwise hand back rows the mask never rewrote.
|
|
87
|
+
*
|
|
88
|
+
* The sizing is the measured dev profile: ~60 MiB of shared memory, against
|
|
89
|
+
* the extension's own defaults of ~689 MiB before rings and row cache. It is
|
|
90
|
+
* reserved at postmaster start whether or not anything caches, so a local
|
|
91
|
+
* Postgres should not ask for a production keyspace. Durability is ephemeral
|
|
92
|
+
* throughout: nothing in a dev keyspace is the only copy of anything.
|
|
93
|
+
*/
|
|
94
|
+
export declare function pgServerOptions(opts: PgOptions): string;
|
|
40
95
|
export declare function start(opts: PgOptions): void;
|
|
41
96
|
/**
|
|
42
97
|
* Stop Postgres using pg_ctl (fast mode).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-ctl.d.ts","sourceRoot":"","sources":["../src/postgres-ctl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,SAAS;IACxB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAA;IAChB,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAA;IACf,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"postgres-ctl.d.ts","sourceRoot":"","sources":["../src/postgres-ctl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,SAAS;IACxB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAA;IAChB,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAA;IACf,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,MAAM,CAAC,UAAU,CAWnB;AAMD;;;GAGG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAgB5C;AAMD;;;GAGG;AACH;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAErF;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEzF;AAeD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,OAAO,CAAA;AACtC,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKtF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAoBvD;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CA4B3C;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAS1C;AAMD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBlF;AAoDD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGhE"}
|
package/dist/postgres-ctl.js
CHANGED
|
@@ -62,26 +62,102 @@ export function initdb(opts) {
|
|
|
62
62
|
* `lib/postgresql/`.
|
|
63
63
|
*/
|
|
64
64
|
export function nativeMaskLibraryPresent(pgBinDir) {
|
|
65
|
+
return nativeLibraryPresent(pgBinDir, "supatype_mask");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Whether a native Postgres install carries the RESP keyspace.
|
|
69
|
+
*
|
|
70
|
+
* Asked of the filesystem for the same reason as the mask: an archive
|
|
71
|
+
* downloaded before pg_keyspace was bundled has a Postgres without it, and the
|
|
72
|
+
* Windows archive has none at all — pgrx has no Windows target. Naming it in
|
|
73
|
+
* `shared_preload_libraries` anyway would stop the server starting with "could
|
|
74
|
+
* not access file", which would turn a missing cache into no database.
|
|
75
|
+
*/
|
|
76
|
+
export function nativeKeyspaceLibraryPresent(pgBinDir) {
|
|
77
|
+
return nativeLibraryPresent(pgBinDir, "pg_keyspace");
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Two layouts: Linux and macOS put extension libraries in `lib/`, the Windows
|
|
81
|
+
* archive in `lib/postgresql/`.
|
|
82
|
+
*/
|
|
83
|
+
function nativeLibraryPresent(pgBinDir, stem) {
|
|
65
84
|
if (!pgBinDir)
|
|
66
85
|
return false;
|
|
67
86
|
const prefix = resolvePath(pgBinDir, "..");
|
|
68
|
-
return [
|
|
87
|
+
return [`${stem}.so`, `${stem}.dylib`, `${stem}.dll`].some((lib) => existsSync(join(prefix, "lib", lib)) || existsSync(join(prefix, "lib", "postgresql", lib)));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Where the native RESP keyspace looks for a free port, and how far it looks.
|
|
91
|
+
*
|
|
92
|
+
* 6379 first, because that is what a developer's tooling and the Valkey
|
|
93
|
+
* sidecar before it both used, so the familiar port stays the usual answer.
|
|
94
|
+
*/
|
|
95
|
+
export const KEYSPACE_PORT_BASE = 6379;
|
|
96
|
+
export const KEYSPACE_PORT_SPAN = 10;
|
|
97
|
+
/**
|
|
98
|
+
* The first free port in [base, base + span), or null when they are all taken.
|
|
99
|
+
*
|
|
100
|
+
* Binding a port something else already holds would leave Postgres up and the
|
|
101
|
+
* keyspace silently dead — the failure lands in the postmaster log and nowhere
|
|
102
|
+
* a developer is looking — so the port is chosen before the server starts
|
|
103
|
+
* rather than fixed and hoped for.
|
|
104
|
+
*/
|
|
105
|
+
export async function firstFreePort(base, span) {
|
|
106
|
+
for (let port = base; port < base + span; port++) {
|
|
107
|
+
if (!(await isPortInUse(port)))
|
|
108
|
+
return port;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The `-o` options pg_ctl passes to the server.
|
|
114
|
+
*
|
|
115
|
+
* Separated from the spawn so the decision is testable. What goes in here is
|
|
116
|
+
* decided by which libraries the archive happens to carry, which is exactly
|
|
117
|
+
* the kind of thing that is wrong in one combination nobody runs locally.
|
|
118
|
+
*
|
|
119
|
+
* Order in `shared_preload_libraries` is load-bearing: pg_keyspace first, then
|
|
120
|
+
* supatype_mask, so the mask stays outermost. pg_keyspace checks this itself
|
|
121
|
+
* and refuses to serve when the order is wrong — deliberately, since RESP
|
|
122
|
+
* would otherwise hand back rows the mask never rewrote.
|
|
123
|
+
*
|
|
124
|
+
* The sizing is the measured dev profile: ~60 MiB of shared memory, against
|
|
125
|
+
* the extension's own defaults of ~689 MiB before rings and row cache. It is
|
|
126
|
+
* reserved at postmaster start whether or not anything caches, so a local
|
|
127
|
+
* Postgres should not ask for a production keyspace. Durability is ephemeral
|
|
128
|
+
* throughout: nothing in a dev keyspace is the only copy of anything.
|
|
129
|
+
*/
|
|
130
|
+
export function pgServerOptions(opts) {
|
|
131
|
+
const mask = nativeMaskLibraryPresent(opts.pgBinDir);
|
|
132
|
+
const keyspace = opts.keyspacePort !== undefined && nativeKeyspaceLibraryPresent(opts.pgBinDir);
|
|
133
|
+
const libs = [...(keyspace ? ["pg_keyspace"] : []), ...(mask ? ["supatype_mask"] : [])];
|
|
134
|
+
const parts = [`-p ${opts.port}`];
|
|
135
|
+
if (libs.length > 0)
|
|
136
|
+
parts.push(`-c shared_preload_libraries=${libs.join(",")}`);
|
|
137
|
+
if (keyspace) {
|
|
138
|
+
parts.push(`-c pg_keyspace.port=${opts.keyspacePort}`, "-c pg_keyspace.durability=ephemeral", "-c pg_keyspace.keys=50000", "-c pg_keyspace.ring_mb=8", "-c pg_keyspace.rowcache_mb=1");
|
|
139
|
+
if (opts.keyspaceDatabase) {
|
|
140
|
+
parts.push(`-c pg_keyspace.database=${opts.keyspaceDatabase}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return parts.join(" ");
|
|
69
144
|
}
|
|
70
145
|
export function start(opts) {
|
|
71
146
|
const bin = pgBin(opts.pgBinDir, "pg_ctl");
|
|
72
147
|
const logPath = opts.logPath ?? join(opts.dataDir, "postgres.log");
|
|
73
|
-
// `supatype_mask` is a planner hook
|
|
74
|
-
//
|
|
75
|
-
//
|
|
148
|
+
// `supatype_mask` is a planner hook and pg_keyspace registers background
|
|
149
|
+
// workers and shared memory, so both have to be preloaded — `CREATE
|
|
150
|
+
// EXTENSION` alone does nothing for either. Only when the archive actually
|
|
151
|
+
// carries them; see pgServerOptions.
|
|
76
152
|
//
|
|
77
|
-
// Native Postgres was started with no preloaded libraries at all until
|
|
78
|
-
// rules could not be enforced on the default
|
|
79
|
-
|
|
153
|
+
// Native Postgres was started with no preloaded libraries at all until the
|
|
154
|
+
// mask, which is why field rules could not be enforced on the default
|
|
155
|
+
// `supatype dev`.
|
|
80
156
|
const args = [
|
|
81
157
|
"start",
|
|
82
158
|
"-D", opts.dataDir,
|
|
83
159
|
"-l", logPath,
|
|
84
|
-
"-o",
|
|
160
|
+
"-o", pgServerOptions(opts),
|
|
85
161
|
"--wait",
|
|
86
162
|
];
|
|
87
163
|
const result = spawnSync(bin, args, {
|
package/dist/postgres-ctl.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-ctl.js","sourceRoot":"","sources":["../src/postgres-ctl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"postgres-ctl.js","sourceRoot":"","sources":["../src/postgres-ctl.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SupatypeProjectConfig } from "./project-config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Preview addresses that can never resolve, named before a push writes them.
|
|
4
|
+
*
|
|
5
|
+
* A preview address may be a path when this deployment serves the project's app: `app.mode` of
|
|
6
|
+
* `static` or `proxy` puts the app at `/` on the same origin as the API, and Studio resolves the
|
|
7
|
+
* path against the origin it is loaded from. That is the point of allowing a path at all, because
|
|
8
|
+
* the origin is a deployment fact and repeating it in config only lets it go stale.
|
|
9
|
+
*
|
|
10
|
+
* With `app.mode: "none"` nothing is served at `/`. A path then resolves against an origin that
|
|
11
|
+
* answers 404, so the share control hands somebody a link that looks right and opens nothing. The
|
|
12
|
+
* failure surfaces to whoever was sent the link rather than to whoever configured it, which is the
|
|
13
|
+
* worst place for it to land, so it is refused here instead.
|
|
14
|
+
*
|
|
15
|
+
* Returns the models at fault, so a caller can name all of them in one message rather than making
|
|
16
|
+
* an operator fix them one push at a time.
|
|
17
|
+
*/
|
|
18
|
+
export declare function modelsWithUnresolvablePreview(config: SupatypeProjectConfig): string[];
|
|
19
|
+
/** The refusal headline. The two ways out are hints, in the caller, as every other refusal does. */
|
|
20
|
+
export declare function unresolvablePreviewMessage(models: string[]): string;
|
|
21
|
+
//# sourceMappingURL=preview-config-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-config-check.d.ts","sourceRoot":"","sources":["../src/preview-config-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAEhE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAiBrF;AAQD,oGAAoG;AACpG,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAOnE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preview addresses that can never resolve, named before a push writes them.
|
|
3
|
+
*
|
|
4
|
+
* A preview address may be a path when this deployment serves the project's app: `app.mode` of
|
|
5
|
+
* `static` or `proxy` puts the app at `/` on the same origin as the API, and Studio resolves the
|
|
6
|
+
* path against the origin it is loaded from. That is the point of allowing a path at all, because
|
|
7
|
+
* the origin is a deployment fact and repeating it in config only lets it go stale.
|
|
8
|
+
*
|
|
9
|
+
* With `app.mode: "none"` nothing is served at `/`. A path then resolves against an origin that
|
|
10
|
+
* answers 404, so the share control hands somebody a link that looks right and opens nothing. The
|
|
11
|
+
* failure surfaces to whoever was sent the link rather than to whoever configured it, which is the
|
|
12
|
+
* worst place for it to land, so it is refused here instead.
|
|
13
|
+
*
|
|
14
|
+
* Returns the models at fault, so a caller can name all of them in one message rather than making
|
|
15
|
+
* an operator fix them one push at a time.
|
|
16
|
+
*/
|
|
17
|
+
export function modelsWithUnresolvablePreview(config) {
|
|
18
|
+
if (config.app.mode !== "none")
|
|
19
|
+
return [];
|
|
20
|
+
const livePreview = config.admin?.livePreview;
|
|
21
|
+
if (livePreview === undefined)
|
|
22
|
+
return [];
|
|
23
|
+
return Object.entries(livePreview)
|
|
24
|
+
.filter(([, entry]) => {
|
|
25
|
+
const address = entry.urlPattern !== undefined && entry.urlPattern !== "" ? entry.urlPattern : entry.url;
|
|
26
|
+
// Nothing stated at all is not this check's business: Studio asks for the setting, and a
|
|
27
|
+
// project that has not configured previews for a model is not misconfigured.
|
|
28
|
+
if (address === undefined || address === "")
|
|
29
|
+
return false;
|
|
30
|
+
return !namesAnOrigin(address);
|
|
31
|
+
})
|
|
32
|
+
.map(([model]) => model)
|
|
33
|
+
.sort();
|
|
34
|
+
}
|
|
35
|
+
/** True when the address carries its own origin and needs nothing added to it. */
|
|
36
|
+
function namesAnOrigin(address) {
|
|
37
|
+
// Protocol-relative counts: `//example.com/x` already names a host.
|
|
38
|
+
return /^[a-z][a-z0-9+.-]*:\/\//i.test(address) || address.startsWith("//");
|
|
39
|
+
}
|
|
40
|
+
/** The refusal headline. The two ways out are hints, in the caller, as every other refusal does. */
|
|
41
|
+
export function unresolvablePreviewMessage(models) {
|
|
42
|
+
const plural = models.length > 1;
|
|
43
|
+
return (`admin.livePreview gives a path for ${models.join(", ")}, but app.mode is "none", ` +
|
|
44
|
+
`so this deployment serves nothing at / for ${plural ? "those paths" : "that path"} ` +
|
|
45
|
+
`to resolve against.`);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=preview-config-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-config-check.js","sourceRoot":"","sources":["../src/preview-config-check.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAA6B;IACzE,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,EAAE,CAAA;IAEzC,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,EAAE,WAAW,CAAA;IAC7C,IAAI,WAAW,KAAK,SAAS;QAAE,OAAO,EAAE,CAAA;IAExC,OAAO,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;SAC/B,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE;QACpB,MAAM,OAAO,GACX,KAAK,CAAC,UAAU,KAAK,SAAS,IAAI,KAAK,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAA;QAC1F,yFAAyF;QACzF,6EAA6E;QAC7E,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE;YAAE,OAAO,KAAK,CAAA;QACzD,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IAChC,CAAC,CAAC;SACD,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC;SACvB,IAAI,EAAE,CAAA;AACX,CAAC;AAED,kFAAkF;AAClF,SAAS,aAAa,CAAC,OAAe;IACpC,oEAAoE;IACpE,OAAO,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;AAC7E,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,0BAA0B,CAAC,MAAgB;IACzD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAA;IAChC,OAAO,CACL,sCAAsC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,4BAA4B;QACnF,8CAA8C,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,GAAG;QACrF,qBAAqB,CACtB,CAAA;AACH,CAAC"}
|