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