@getstrata/cli 2.2.35 → 2.2.37

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @getstrata/cli changelog
2
2
 
3
+ ## 2.2.37
4
+
5
+ Fix MySQL repository entity-returning mutations with transaction-pinned readback, persisted keys/defaults, honest null and deletion outcomes, complete model event payloads and injected connection ownership. Preserve native Postgres/SQLite RETURNING and conditional affected-row metadata. Close owned generated OpenAPI and failed-job command applications on success and failure before exit; retain both command and cleanup errors. Add mandatory packaged MySQL production column-tenancy CLI and HTTP auth/SCIM acceptance with an owned DML-only account, unchanged route/spec/SDK contracts, native ORM regressions and cleanup tests. Records dogfood issues #232 and #233 without application SQL workarounds.
6
+
7
+ ## 2.2.36
8
+
9
+ Add a mandatory installed-package SQLite column-tenancy CLI/OpenAPI/HTTP profile, including cookie/token/JWT/Basic and repeated SCIM isolation, while preserving existing Postgres security, route inventories, compiler combinations and Docker gates. Reconcile observability/rotation trackers against shipped capabilities and remaining operational qualification.
10
+
11
+ Fix declared default exports missing from nine published core subpaths. Preserve defaults in generated non-shared entries and alias the shared BaseRepository default to its canonical root constructor, retaining named exports and singleton/class identity. Extend declaration/runtime verification with value-default and type-only-default regressions; compile all nine imports across the existing 18 generated compiler combinations and execute them in every installed candidate app. Records the published 2.2.35 reproduction from Q01 dogfooding; no shop adapter or node_modules patch.
12
+
3
13
  ## 2.2.35
4
14
 
5
15
  Retire checked-in HiroApp applications after preserving security, CLI/OpenAPI/HTTP, source, migration and Docker acceptance in generated candidate-package fixtures. Keep all 23 security cases, 40 runtime operations, 22 API/protocol operations, three-engine migration cases and 18 compiler combinations. Make the private root CLI fixture-only, isolate post-commit HTTP databases, and validate the generated production image with restricted runtime credentials, Redis recovery and graceful shutdown. Remove obsolete app regeneration/selectors and update contributor, generator and deployment documentation; retain compatible example preset IDs and explicit application-owned deployment boundaries. Regenerate the sample SDK from the API-only snapshot and verify it against the installed candidate package. Core coverage retains 136 enforced files at 100%; remove only the two deleted private-entrypoint exemptions (272 remaining).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getstrata/cli",
3
- "version": "2.2.35",
3
+ "version": "2.2.37",
4
4
  "description": "Strata CLI: framework commands for Bun apps (dev, start, migrate, run)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -54,8 +54,8 @@
54
54
  ],
55
55
  "scripts": {},
56
56
  "peerDependencies": {
57
- "@getstrata/bootstrap": "^2.2.35",
58
- "@getstrata/core": "^2.2.35"
57
+ "@getstrata/bootstrap": "^2.2.37",
58
+ "@getstrata/core": "^2.2.37"
59
59
  },
60
60
  "publishConfig": {
61
61
  "access": "public"
@@ -0,0 +1,25 @@
1
+ /** One-shot commands own only the cleanup explicitly supplied by their application. */
2
+ async function withCommandCleanup<T>(
3
+ operation: () => Promise<T>,
4
+ close?: () => void | Promise<void>,
5
+ ): Promise<T> {
6
+ let result: { ok: true; value: T } | { ok: false; error: unknown };
7
+ try {
8
+ result = { ok: true, value: await operation() };
9
+ } catch (error) {
10
+ result = { ok: false, error };
11
+ }
12
+ try {
13
+ await close?.();
14
+ } catch (error) {
15
+ if (!result.ok)
16
+ throw new AggregateError([result.error, error], "Command and application cleanup failed.", {
17
+ cause: result.error,
18
+ });
19
+ throw error;
20
+ }
21
+ if (!result.ok) throw result.error;
22
+ return result.value;
23
+ }
24
+
25
+ export { withCommandCleanup };
package/src/openapi.ts CHANGED
@@ -6,6 +6,9 @@ import { generateOpenApiSpec, renderOpenApiDocument } from "@getstrata/core/open
6
6
  import { validateOpenApiSpec } from "@getstrata/core/openapi/validate";
7
7
  import { readSpaPrefix } from "@getstrata/core/runtime/frontendMode";
8
8
 
9
+ import { withCommandCleanup } from "./commandCleanup.ts";
10
+
11
+ type AppCleanup = () => void | Promise<void>;
9
12
  type AppBootstrap = () => Promise<{ routes: Record<string, unknown> }>;
10
13
 
11
14
  function isSpaDocumentedPath(path: string, spaPrefix: string): boolean {
@@ -62,71 +65,94 @@ async function registerAppOpenApiRoutes(bootstrap: AppBootstrap): Promise<void>
62
65
  registerOpenApiRouteMap(unregisteredKeepers, ["global", "api"]);
63
66
  }
64
67
 
65
- function createOpenApiGenerateCommand(bootstrap: AppBootstrap) {
66
- return async function openapiGenerateCommand(): Promise<void> {
67
- await registerAppOpenApiRoutes(bootstrap);
68
-
69
- const spec = generateOpenApiSpec(routeRegistry.list());
70
- const jsonPath = join(process.cwd(), "docs/openapi.json");
71
- await mkdir(dirname(jsonPath), { recursive: true });
72
- await writeFile(jsonPath, renderOpenApiDocument(spec), "utf8");
73
-
74
- console.log(`OpenAPI spec written to ${jsonPath} (${routeRegistry.list().length} routes).`);
68
+ function createOpenApiCommand(
69
+ bootstrap: AppBootstrap,
70
+ operation: () => Promise<number | undefined>,
71
+ close?: AppCleanup,
72
+ ) {
73
+ return async (): Promise<void> => {
74
+ const exitCode = await withCommandCleanup(async () => {
75
+ await registerAppOpenApiRoutes(bootstrap);
76
+ return operation();
77
+ }, close);
78
+ if (exitCode === 1) process.exit(1);
75
79
  };
76
80
  }
77
81
 
78
- function createOpenApiValidateCommand(bootstrap: AppBootstrap) {
79
- return async function openapiValidateCommand(): Promise<void> {
80
- await registerAppOpenApiRoutes(bootstrap);
81
-
82
- const spec = generateOpenApiSpec(routeRegistry.list());
83
- const errors = validateOpenApiSpec(spec);
82
+ function createOpenApiGenerateCommand(bootstrap: AppBootstrap, close?: AppCleanup) {
83
+ return createOpenApiCommand(
84
+ bootstrap,
85
+ async () => {
86
+ const spec = generateOpenApiSpec(routeRegistry.list());
87
+ const jsonPath = join(process.cwd(), "docs/openapi.json");
88
+ await mkdir(dirname(jsonPath), { recursive: true });
89
+ await writeFile(jsonPath, renderOpenApiDocument(spec), "utf8");
90
+
91
+ console.log(`OpenAPI spec written to ${jsonPath} (${routeRegistry.list().length} routes).`);
92
+ return undefined;
93
+ },
94
+ close,
95
+ );
96
+ }
84
97
 
85
- if (errors.length > 0) {
86
- console.error("OpenAPI validation failed:");
87
- for (const error of errors) {
88
- console.error(`- ${error}`);
98
+ function createOpenApiValidateCommand(bootstrap: AppBootstrap, close?: AppCleanup) {
99
+ return createOpenApiCommand(
100
+ bootstrap,
101
+ async () => {
102
+ const spec = generateOpenApiSpec(routeRegistry.list());
103
+ const errors = validateOpenApiSpec(spec);
104
+
105
+ if (errors.length > 0) {
106
+ console.error("OpenAPI validation failed:");
107
+ for (const error of errors) {
108
+ console.error(`- ${error}`);
109
+ }
110
+ return 1;
89
111
  }
90
- process.exit(1);
91
- }
92
112
 
93
- console.log(`OpenAPI spec valid (${routeRegistry.list().length} routes).`);
94
- };
113
+ console.log(`OpenAPI spec valid (${routeRegistry.list().length} routes).`);
114
+ return undefined;
115
+ },
116
+ close,
117
+ );
95
118
  }
96
119
 
97
- function createOpenApiCheckCommand(bootstrap: AppBootstrap) {
98
- return async function openapiCheckCommand(): Promise<void> {
99
- await registerAppOpenApiRoutes(bootstrap);
100
-
101
- const spec = generateOpenApiSpec(routeRegistry.list());
102
- const errors = validateOpenApiSpec(spec);
103
-
104
- if (errors.length > 0) {
105
- console.error("OpenAPI validation failed:");
106
- for (const error of errors) {
107
- console.error(`- ${error}`);
120
+ function createOpenApiCheckCommand(bootstrap: AppBootstrap, close?: AppCleanup) {
121
+ return createOpenApiCommand(
122
+ bootstrap,
123
+ async () => {
124
+ const spec = generateOpenApiSpec(routeRegistry.list());
125
+ const errors = validateOpenApiSpec(spec);
126
+
127
+ if (errors.length > 0) {
128
+ console.error("OpenAPI validation failed:");
129
+ for (const error of errors) {
130
+ console.error(`- ${error}`);
131
+ }
132
+ return 1;
108
133
  }
109
- process.exit(1);
110
- }
111
134
 
112
- const generated = renderOpenApiDocument(spec);
113
- const jsonPath = join(process.cwd(), "docs/openapi.json");
114
- const committed = await readFile(jsonPath, "utf8");
115
-
116
- if (committed !== generated) {
117
- console.error("OpenAPI spec drift detected.");
118
- console.error("Run `strata openapi:generate` and commit docs/openapi.json.");
119
- console.error(
120
- "Add that generate step next to `strata openapi:check` in CI so new routes cannot ship undocumented.",
121
- );
122
- process.exit(1);
123
- }
135
+ const generated = renderOpenApiDocument(spec);
136
+ const jsonPath = join(process.cwd(), "docs/openapi.json");
137
+ const committed = await readFile(jsonPath, "utf8");
138
+
139
+ if (committed !== generated) {
140
+ console.error("OpenAPI spec drift detected.");
141
+ console.error("Run `strata openapi:generate` and commit docs/openapi.json.");
142
+ console.error(
143
+ "Add that generate step next to `strata openapi:check` in CI so new routes cannot ship undocumented.",
144
+ );
145
+ return 1;
146
+ }
124
147
 
125
- console.log(`OpenAPI spec matches committed file (${routeRegistry.list().length} routes).`);
126
- };
148
+ console.log(`OpenAPI spec matches committed file (${routeRegistry.list().length} routes).`);
149
+ return undefined;
150
+ },
151
+ close,
152
+ );
127
153
  }
128
154
 
129
- export type { AppBootstrap };
155
+ export type { AppBootstrap, AppCleanup };
130
156
  export {
131
157
  createOpenApiCheckCommand,
132
158
  createOpenApiGenerateCommand,
@@ -5,6 +5,7 @@ import {
5
5
  } from "@getstrata/core/queue/createAppQueue";
6
6
  import { jobRegistry } from "@getstrata/core/queue/jobRegistry";
7
7
  import { resolveApplicationQueue } from "@getstrata/core/runtime/applicationRegistry";
8
+ import { withCommandCleanup } from "./commandCleanup.ts";
8
9
  import type { StrataCommand } from "./types.ts";
9
10
 
10
11
  type QueueFailedBoot = () => unknown | Promise<unknown>;
@@ -61,15 +62,20 @@ async function queueFlushFailedCommand(boot?: QueueFailedBoot): Promise<void> {
61
62
  console.log(`Removed ${deleted} failed job(s).`);
62
63
  }
63
64
 
64
- function createQueueFailedCommands(boot?: QueueFailedBoot): {
65
+ function createQueueFailedCommands(
66
+ boot?: QueueFailedBoot,
67
+ close?: () => void | Promise<void>,
68
+ ): {
65
69
  queueFailedCommand: StrataCommand;
66
70
  queueRetryCommand: StrataCommand;
67
71
  queueFlushFailedCommand: StrataCommand;
68
72
  } {
69
73
  return {
70
- queueFailedCommand: async () => queueFailedCommand(boot),
71
- queueRetryCommand: async (id?: string) => queueRetryCommand(id, boot),
72
- queueFlushFailedCommand: async () => queueFlushFailedCommand(boot),
74
+ queueFailedCommand: async () => withCommandCleanup(() => queueFailedCommand(boot), close),
75
+ queueRetryCommand: async (id?: string) =>
76
+ withCommandCleanup(() => queueRetryCommand(id, boot), close),
77
+ queueFlushFailedCommand: async () =>
78
+ withCommandCleanup(() => queueFlushFailedCommand(boot), close),
73
79
  };
74
80
  }
75
81