@nanobpm/urban 0.29.0 → 0.30.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/dist/openapi/spec.d.ts +127 -0
- package/dist/openapi/spec.js +444 -0
- package/dist/runtime/core/modules/api.d.ts +61 -0
- package/dist/runtime/core/modules/api.js +359 -0
- package/dist/runtime/core/modules/cancel.d.ts +31 -0
- package/dist/runtime/core/modules/cancel.js +90 -0
- package/dist/runtime/core/modules/datasource.d.ts +5 -2
- package/dist/runtime/core/modules/datasource.js +5 -4
- package/dist/runtime/core/modules/instance-tracking.d.ts +8 -0
- package/dist/runtime/core/modules/instance-tracking.js +28 -11
- package/dist/runtime/core/modules/pages.d.ts +8 -0
- package/dist/runtime/core/modules/pages.js +17 -1
- package/dist/runtime/core/modules/surfaces.js +9 -0
- package/dist/runtime/engine/nanosdk.js +41 -7
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/index.js +2 -0
- package/dist/toolkit/artifact.d.ts +5 -0
- package/dist/toolkit/artifact.js +7 -0
- package/dist/toolkit/derivers/api.d.ts +19 -0
- package/dist/toolkit/derivers/api.js +224 -0
- package/dist/toolkit/gen.js +23 -4
- package/dist/toolkit/index.d.ts +5 -0
- package/dist/toolkit/index.js +12 -1
- package/package.json +1 -1
- package/src/openapi/spec.test.ts +292 -0
- package/src/openapi/spec.ts +540 -0
- package/src/runtime/core/modules/api.test.ts +445 -0
- package/src/runtime/core/modules/api.ts +453 -0
- package/src/runtime/core/modules/cancel.test.ts +310 -0
- package/src/runtime/core/modules/cancel.ts +119 -0
- package/src/runtime/core/modules/datasource.ts +5 -4
- package/src/runtime/core/modules/instance-tracking.ts +33 -11
- package/src/runtime/core/modules/pages.test.ts +46 -2
- package/src/runtime/core/modules/pages.ts +23 -1
- package/src/runtime/core/modules/surfaces.ts +10 -0
- package/src/runtime/engine/nanosdk.test.ts +45 -5
- package/src/runtime/engine/nanosdk.ts +39 -7
- package/src/runtime/index.ts +12 -0
- package/src/toolkit/artifact.ts +8 -0
- package/src/toolkit/derivers/api.test.ts +219 -0
- package/src/toolkit/derivers/api.ts +255 -0
- package/src/toolkit/gen.test.ts +39 -0
- package/src/toolkit/gen.ts +24 -4
- package/src/toolkit/index.ts +41 -1
package/src/toolkit/gen.test.ts
CHANGED
|
@@ -165,3 +165,42 @@ test("the sweep never touches an authored (un-stamped) .bpmn", async () => {
|
|
|
165
165
|
await runGen({ root: "/cf", io });
|
|
166
166
|
assert.ok(io.files["/cf/processes/authored.bpmn"], "authored .bpmn must survive the sweep");
|
|
167
167
|
});
|
|
168
|
+
|
|
169
|
+
test("collectArtifacts trims api.spec whitespace so gen matches the runtime (no gen/runtime drift)", async () => {
|
|
170
|
+
const manifest = JSON.stringify({ id: "demo", data: { default: "app" }, api: { spec: " openapi.json " } });
|
|
171
|
+
const openapi = JSON.stringify({
|
|
172
|
+
openapi: "3.0.0",
|
|
173
|
+
paths: { "/ping": { get: { operationId: "ping", responses: { "200": {} } } } },
|
|
174
|
+
});
|
|
175
|
+
const io = memIO({ "/app/nano.app.json": manifest, "/app/openapi.json": openapi });
|
|
176
|
+
const res = await collectArtifacts({ root: "/app", io });
|
|
177
|
+
const paths = res.map((a) => a.path);
|
|
178
|
+
// The whitespace-padded spec path still resolved and derived the endpoint contracts.
|
|
179
|
+
assert.ok(paths.includes("nano-generated/api-io.d.ts"));
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("collectArtifacts resolves an api.spec with Windows-style separators (no gen/runtime drift)", async () => {
|
|
183
|
+
const manifest = JSON.stringify({ id: "demo", data: { default: "app" }, api: { spec: "specs\\openapi.json" } });
|
|
184
|
+
const openapi = JSON.stringify({
|
|
185
|
+
openapi: "3.0.0",
|
|
186
|
+
paths: { "/ping": { get: { operationId: "ping", responses: { "200": {} } } } },
|
|
187
|
+
});
|
|
188
|
+
const io = memIO({ "/app/nano.app.json": manifest, "/app/specs/openapi.json": openapi });
|
|
189
|
+
const res = await collectArtifacts({ root: "/app", io });
|
|
190
|
+
assert.ok(res.map((a) => a.path).includes("nano-generated/api-io.d.ts"));
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("collectArtifacts resolves an ABSOLUTE api.spec at its own path, not root-relative (no gen/runtime drift)", async () => {
|
|
194
|
+
// An absolute manifest spec path must resolve to itself — mirroring the runtime's resolveAppPath
|
|
195
|
+
// — not be stripped to a root-relative "/app/abs/openapi.json". Otherwise gen would read/derive a
|
|
196
|
+
// different file than the runtime dispatches against.
|
|
197
|
+
const manifest = JSON.stringify({ id: "demo", data: { default: "app" }, api: { spec: "/abs/openapi.json" } });
|
|
198
|
+
const openapi = JSON.stringify({
|
|
199
|
+
openapi: "3.0.0",
|
|
200
|
+
paths: { "/ping": { get: { operationId: "ping", responses: { "200": {} } } } },
|
|
201
|
+
});
|
|
202
|
+
// Only the absolute location holds the spec; a root-relative read would ENOENT.
|
|
203
|
+
const io = memIO({ "/app/nano.app.json": manifest, "/abs/openapi.json": openapi });
|
|
204
|
+
const res = await collectArtifacts({ root: "/app", io });
|
|
205
|
+
assert.ok(res.map((a) => a.path).includes("nano-generated/api-io.d.ts"));
|
|
206
|
+
});
|
package/src/toolkit/gen.ts
CHANGED
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
// pure; all IO is confined here behind a tiny FS port so the same code runs on Node and Deno.
|
|
5
5
|
|
|
6
6
|
import type { DerivedArtifact } from "./artifact.ts";
|
|
7
|
-
import { sortArtifacts } from "./artifact.ts";
|
|
7
|
+
import { isAbsolutePath, sortArtifacts } from "./artifact.ts";
|
|
8
8
|
import { deriveMigrations, type ToolkitManifest } from "./derivers/migrations.ts";
|
|
9
9
|
import { deriveDomain } from "./derivers/domain.ts";
|
|
10
10
|
import { deriveWorkerBindings, type ModelSource } from "./derivers/worker-io.ts";
|
|
11
11
|
import { deriveMeta } from "./derivers/meta.ts";
|
|
12
12
|
import { deriveMessageBindings } from "./derivers/messages.ts";
|
|
13
|
+
import { deriveApi } from "./derivers/api.ts";
|
|
14
|
+
import { parseSpec } from "../openapi/spec.ts";
|
|
13
15
|
import { deriveModels, type DerivedModels, type ModelError, MODEL_PROVENANCE } from "./models.ts";
|
|
14
16
|
|
|
15
17
|
/** Minimal filesystem port. Node/Deno impls live in `fsio.ts`. */
|
|
@@ -56,9 +58,17 @@ export interface GenResult {
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
function join(root: string, rel: string): string {
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
|
|
61
|
+
// Normalize Windows-style separators to forward slashes (GenIO uses forward slashes on all
|
|
62
|
+
// platforms — matching the runtime's resolveAppPath) and trim edge separators, so callers may
|
|
63
|
+
// pass either style without gen/runtime drift over where a file resolves.
|
|
64
|
+
const norm = (s: string): string => s.replace(/\\/g, "/");
|
|
65
|
+
// An absolute `rel` resolves to itself — never prefixed with `root` — mirroring the runtime's
|
|
66
|
+
// resolveAppPath (isAbsolutePath is the shared SoT in artifact.ts). Without this an absolute
|
|
67
|
+
// manifest path (e.g. "/abs/openapi.json") would be stripped to root-relative and gen would
|
|
68
|
+
// read/derive a different file than the runtime resolves. Trailing edge separators are still
|
|
69
|
+
// trimmed for stable, comparable artifact keys.
|
|
70
|
+
if (isAbsolutePath(rel)) return norm(rel).replace(/\/+$/, "");
|
|
71
|
+
return `${norm(root).replace(/\/+$/, "")}/${norm(rel).replace(/^\/+/, "")}`;
|
|
62
72
|
}
|
|
63
73
|
|
|
64
74
|
function dirOf(p: string): string {
|
|
@@ -112,6 +122,7 @@ async function collectAll(opts: GenOptions): Promise<{ artifacts: DerivedArtifac
|
|
|
112
122
|
const manifestPath = join(root, opts.manifestFile ?? "nano.app.json");
|
|
113
123
|
const manifest: ToolkitManifest & {
|
|
114
124
|
models?: { processes?: string[]; workflows?: string[] };
|
|
125
|
+
api?: { spec?: string };
|
|
115
126
|
} = JSON.parse(await io.readText(manifestPath));
|
|
116
127
|
|
|
117
128
|
const artifacts: DerivedArtifact[] = [];
|
|
@@ -142,6 +153,15 @@ async function collectAll(opts: GenOptions): Promise<{ artifacts: DerivedArtifac
|
|
|
142
153
|
}
|
|
143
154
|
}
|
|
144
155
|
|
|
156
|
+
// 4. OpenAPI `api` binding → typed endpoint contracts (ADR 0058). Fail-closed: a declared spec
|
|
157
|
+
// that is missing or malformed throws here so `urban gen`/`urban check` surfaces it. Trim the
|
|
158
|
+
// spec path so benign whitespace matches the runtime's readApiBinding (no gen/runtime drift).
|
|
159
|
+
const specRef = typeof manifest.api?.spec === "string" ? manifest.api.spec.trim() : "";
|
|
160
|
+
if (!opts.modelsOnly && specRef.length > 0) {
|
|
161
|
+
const specText = await io.readText(join(root, specRef));
|
|
162
|
+
artifacts.push(...deriveApi(parseSpec(specText)));
|
|
163
|
+
}
|
|
164
|
+
|
|
145
165
|
return { artifacts: sortArtifacts(artifacts), derived };
|
|
146
166
|
}
|
|
147
167
|
|
package/src/toolkit/index.ts
CHANGED
|
@@ -98,13 +98,53 @@ export {
|
|
|
98
98
|
} from "./derivers/messages.ts";
|
|
99
99
|
export type { MessageIo, MessageBindingDecl } from "./derivers/messages.ts";
|
|
100
100
|
|
|
101
|
+
export {
|
|
102
|
+
apiDeriver,
|
|
103
|
+
deriveApi,
|
|
104
|
+
emitApiBindings,
|
|
105
|
+
emitApiBindingsRuntime,
|
|
106
|
+
schemaToTs,
|
|
107
|
+
API_BINDINGS_DTS,
|
|
108
|
+
API_BINDINGS_TS,
|
|
109
|
+
} from "./derivers/api.ts";
|
|
110
|
+
|
|
111
|
+
// The OpenAPI machinery the deriver + runtime share (ADR 0058).
|
|
112
|
+
export {
|
|
113
|
+
collectOperations,
|
|
114
|
+
HTTP_METHODS,
|
|
115
|
+
isSafeOperationId,
|
|
116
|
+
operationsWithoutId,
|
|
117
|
+
operationsWithUnsafeId,
|
|
118
|
+
parseSpec,
|
|
119
|
+
refName,
|
|
120
|
+
resolveSchema,
|
|
121
|
+
toRouteMatcher,
|
|
122
|
+
undeclaredPathParams,
|
|
123
|
+
validateValue,
|
|
124
|
+
} from "../openapi/spec.ts";
|
|
125
|
+
export type {
|
|
126
|
+
HttpMethodLower,
|
|
127
|
+
OpenApiDoc,
|
|
128
|
+
OpenApiParameter,
|
|
129
|
+
OpenApiSchema,
|
|
130
|
+
OperationInfo,
|
|
131
|
+
} from "../openapi/spec.ts";
|
|
132
|
+
|
|
101
133
|
// The registry of all derivers (for discovery / IDE migration).
|
|
102
134
|
import { migrationsDeriver } from "./derivers/migrations.ts";
|
|
103
135
|
import { domainDeriver } from "./derivers/domain.ts";
|
|
104
136
|
import { workerIoDeriver } from "./derivers/worker-io.ts";
|
|
105
137
|
import { metaDeriver } from "./derivers/meta.ts";
|
|
106
138
|
import { messagesDeriver } from "./derivers/messages.ts";
|
|
107
|
-
|
|
139
|
+
import { apiDeriver } from "./derivers/api.ts";
|
|
140
|
+
export const DERIVERS = [
|
|
141
|
+
migrationsDeriver,
|
|
142
|
+
domainDeriver,
|
|
143
|
+
workerIoDeriver,
|
|
144
|
+
metaDeriver,
|
|
145
|
+
messagesDeriver,
|
|
146
|
+
apiDeriver,
|
|
147
|
+
] as const;
|
|
108
148
|
|
|
109
149
|
// Gen orchestrator + IO
|
|
110
150
|
export { collectArtifacts, runGen, joinPath, readModels, expandPattern, previewModels } from "./gen.ts";
|