@sequenceholdings/orm 0.1.0 → 0.1.1
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/dist/cli.cjs +35 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +35 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +25 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +25 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -24,7 +24,7 @@ var WIRE_TYPES = {
|
|
|
24
24
|
};
|
|
25
25
|
function generateNamespaceTypes(definition) {
|
|
26
26
|
const lines = [
|
|
27
|
-
`// Generated by \`seq-studio orm
|
|
27
|
+
`// Generated by \`seq-studio orm apply\` from the '${definition.namespace}' definitions \u2014 do not edit.`,
|
|
28
28
|
"",
|
|
29
29
|
`export type ${typesInterfaceName(definition.namespace)} = {`
|
|
30
30
|
];
|
|
@@ -2054,10 +2054,12 @@ var USAGE = `usage:
|
|
|
2054
2054
|
seq-studio orm plan [dir] -e <env> offline dry run: compile definitions and diff against the registry (no database, no writes)
|
|
2055
2055
|
seq-studio orm apply [dir] -e <env> author the migration, register, apply, and refresh types.gen.ts (the everyday command)
|
|
2056
2056
|
seq-studio orm apply --dry-run -e <env> rehearse the migration on a copy of the environment's real data, then discard it (no real apply)
|
|
2057
|
+
seq-studio orm apply --no-create -e <env> apply only if the namespace is already registered (CI guard; never provisions a new namespace)
|
|
2057
2058
|
seq-studio orm diff [dir] write/verify the committed migration standalone (--check is the offline CI gate; --allow-destructive consents)
|
|
2058
2059
|
|
|
2059
2060
|
A namespace directory holds one <table>.yaml per table (see the scaffold).
|
|
2060
|
-
|
|
2061
|
+
Environments: see \`seq-studio envs list\` (discovered after you authenticate).
|
|
2062
|
+
Authenticate with: seq-studio login
|
|
2061
2063
|
`;
|
|
2062
2064
|
var tokenProvider = null;
|
|
2063
2065
|
function setTokenProvider(provider) {
|
|
@@ -2159,7 +2161,7 @@ async function planCommand(rest) {
|
|
|
2159
2161
|
`);
|
|
2160
2162
|
const registry = await fetchRegistryState(loaded.definition.namespace, loaded.contentHash);
|
|
2161
2163
|
if (registry.kind === "offline") {
|
|
2162
|
-
console.log("-- registry: pass -e <env> (and
|
|
2164
|
+
console.log("-- registry: pass -e <env> (and seq-studio login) to compare against a deployment");
|
|
2163
2165
|
return 0;
|
|
2164
2166
|
}
|
|
2165
2167
|
if (registry.kind === "missing") {
|
|
@@ -2177,6 +2179,7 @@ async function applyCommand(rest) {
|
|
|
2177
2179
|
const dir = positional(rest) ?? ".";
|
|
2178
2180
|
const allowDestructive = rest.includes("--allow-destructive");
|
|
2179
2181
|
const dryRun = rest.includes("--dry-run");
|
|
2182
|
+
const noCreate = rest.includes("--no-create");
|
|
2180
2183
|
if (await diffCommand({ dir, allowDestructive, check: false, log: (line) => console.log(line) }) !== 0) return 1;
|
|
2181
2184
|
if (!await requireValidated(dir)) return 1;
|
|
2182
2185
|
const loaded = await loadNamespaceDefinition(dir);
|
|
@@ -2186,7 +2189,13 @@ async function applyCommand(rest) {
|
|
|
2186
2189
|
const registered = await apiRequestStrict(
|
|
2187
2190
|
"POST",
|
|
2188
2191
|
"/api/orm/namespaces",
|
|
2189
|
-
{
|
|
2192
|
+
{
|
|
2193
|
+
files: await readDefinitionFiles(dir, loaded.files),
|
|
2194
|
+
...migration ? { migration } : {},
|
|
2195
|
+
// The server refuses to create a new namespace under --no-create, atomically
|
|
2196
|
+
// inside the register transaction (no preflight TOCTOU).
|
|
2197
|
+
...noCreate ? { no_create: true } : {}
|
|
2198
|
+
}
|
|
2190
2199
|
);
|
|
2191
2200
|
console.log(
|
|
2192
2201
|
(registered.created ? `registered ${namespace}@${registered.content_hash.slice(0, 12)}` : `already registered ${namespace}@${registered.content_hash.slice(0, 12)}`) + (migration ? ` with committed migration ${migration.name}` : "")
|
|
@@ -2213,12 +2222,18 @@ async function applyCommand(rest) {
|
|
|
2213
2222
|
var APPLY_POLL_INTERVAL_MS = 2500;
|
|
2214
2223
|
async function waitForQueuedApply(namespace, contentHash, runId) {
|
|
2215
2224
|
let lastStatus = null;
|
|
2225
|
+
const MISSING_RUN_POLL_LIMIT = 8;
|
|
2226
|
+
let missingRunPolls = 0;
|
|
2216
2227
|
for (; ; ) {
|
|
2217
2228
|
await new Promise((resolve) => setTimeout(resolve, APPLY_POLL_INTERVAL_MS));
|
|
2218
|
-
const run = runId ? await
|
|
2229
|
+
const run = runId ? await apiRequest(
|
|
2219
2230
|
"GET",
|
|
2220
|
-
`/api/orm/namespaces/${namespace}/apply?run=${runId}
|
|
2231
|
+
`/api/orm/namespaces/${namespace}/apply?run=${runId}`,
|
|
2232
|
+
void 0,
|
|
2233
|
+
{ allow404: true }
|
|
2221
2234
|
) : null;
|
|
2235
|
+
if (run) missingRunPolls = 0;
|
|
2236
|
+
else if (runId) missingRunPolls++;
|
|
2222
2237
|
if (run && run.verdict === null) {
|
|
2223
2238
|
if (run.status !== lastStatus) {
|
|
2224
2239
|
lastStatus = run.status;
|
|
@@ -2228,6 +2243,7 @@ async function waitForQueuedApply(namespace, contentHash, runId) {
|
|
|
2228
2243
|
}
|
|
2229
2244
|
const body = await apiRequestStrict("GET", `/api/orm/namespaces/${namespace}?hash=${contentHash}`);
|
|
2230
2245
|
const version = body.hash_version;
|
|
2246
|
+
const isActive = version != null && body.namespace.active_version_id === version.id;
|
|
2231
2247
|
if (run?.verdict === "failed") {
|
|
2232
2248
|
const detail = version?.status_detail ?? "no detail recorded";
|
|
2233
2249
|
console.error(`apply failed (run ${run.status.toLowerCase()}): ${detail}`);
|
|
@@ -2236,14 +2252,24 @@ async function waitForQueuedApply(namespace, contentHash, runId) {
|
|
|
2236
2252
|
}
|
|
2237
2253
|
return 1;
|
|
2238
2254
|
}
|
|
2239
|
-
if (run?.verdict === "succeeded" ||
|
|
2255
|
+
if (run?.verdict === "succeeded" || isActive) {
|
|
2240
2256
|
console.log(`applied ${namespace} \u2014 the version is now active`);
|
|
2241
2257
|
return 0;
|
|
2242
2258
|
}
|
|
2243
|
-
if (version?.status === "failed") {
|
|
2259
|
+
if (!runId && version?.status === "failed") {
|
|
2244
2260
|
console.error(`apply failed: ${version.status_detail ?? "no detail recorded"}`);
|
|
2245
2261
|
return 1;
|
|
2246
2262
|
}
|
|
2263
|
+
if (runId && missingRunPolls >= MISSING_RUN_POLL_LIMIT) {
|
|
2264
|
+
if (version?.status === "failed") {
|
|
2265
|
+
console.error(`apply failed: ${version.status_detail ?? "no detail recorded"}`);
|
|
2266
|
+
} else {
|
|
2267
|
+
console.error(
|
|
2268
|
+
`apply status unknown \u2014 run ${runId} is no longer retrievable and ${namespace} is not active at this version (last durable status: ${version?.status ?? "unknown"}). Re-run \`seq-studio orm apply\`.`
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
return 1;
|
|
2272
|
+
}
|
|
2247
2273
|
}
|
|
2248
2274
|
}
|
|
2249
2275
|
async function dryRunRehearsal({
|
|
@@ -2322,7 +2348,7 @@ async function apiRequest(method, path, body, options) {
|
|
|
2322
2348
|
const baseUrl = process.env[BASE_URL_ENV]?.trim();
|
|
2323
2349
|
const token = await resolveToken();
|
|
2324
2350
|
if (!baseUrl) throw new Error("no environment resolved \u2014 pass -e <env>");
|
|
2325
|
-
if (!token) throw new Error("not authenticated \u2014 run:
|
|
2351
|
+
if (!token) throw new Error("not authenticated \u2014 run: seq-studio login");
|
|
2326
2352
|
const response = await fetch(`${baseUrl}${path}`, {
|
|
2327
2353
|
method,
|
|
2328
2354
|
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|