@wairon/cli 5.0.2-dev.6 → 5.0.2-dev.8
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/index.js +226 -36
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +226 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -65,7 +65,7 @@ var init_defaults = __esm({
|
|
|
65
65
|
copilot: ".github/prompts",
|
|
66
66
|
codex: ".codex/agents"
|
|
67
67
|
};
|
|
68
|
-
WAIRON_VERSION = "5.0.2-dev.
|
|
68
|
+
WAIRON_VERSION = "5.0.2-dev.8";
|
|
69
69
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
70
70
|
ARCHITECT_AGENT_ID = "agent-architect";
|
|
71
71
|
ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -703,7 +703,7 @@ var init_template = __esm({
|
|
|
703
703
|
});
|
|
704
704
|
|
|
705
705
|
// src/models/specs.ts
|
|
706
|
-
var import_zod6, SpecIdSchema, SpecStatusSchema, BoundaryItemSchema, RequirementItemSchema, DatabaseSpecSchema, DiagramConfigSchema, SURFACE_AUDIENCES, SurfaceAudienceSchema, SystemPublicInterfaceSchema, SystemSpecSchema, PublicInterfaceTypeSchema, PublicInterfaceSchema, TrustedLinkSchema, LintAllowSchema, LintConfigSchema, ExtDataSchema, LifecycleEntrypointSchema, SubsystemSpecSchema, ComponentTypeSchema, PATTERN_TYPES, PortalTypeSchema, DispatchBindingSchema, DurabilitySchema, PatternRefSchema, EventBindingSchema, ComponentSpecSchema, HttpMethodSchema, TransportSchema, EndpointSchema, SEMANTIC_GUARANTEES, GuaranteeSchema, MethodParamSchema, MethodSignatureSchema, InterfaceSpecSchema, NarrativeStepTypeSchema, LoopKindSchema, SwitchCaseSchema, CatchClauseSchema, ParallelBranchSchema, NarrativeStepSchema, NarrativeDetailSchema, ConformanceTierSchema, MethodImplementationSchema, ImplementationSpecSchema, TypeKindSchema, TypeFieldSchema, TypeMethodSchema, InvariantSchema, TypeSpecSchema, SurfaceOriginSchema, SurfaceTypeDefSchema, SurfaceContractEntrySchema, SurfaceSnapshotSchema, GroupSpecSchema;
|
|
706
|
+
var import_zod6, SpecIdSchema, SpecStatusSchema, BoundaryItemSchema, RequirementItemSchema, DatabaseSpecSchema, DiagramConfigSchema, SURFACE_AUDIENCES, SurfaceAudienceSchema, SystemPublicInterfaceSchema, SystemSpecSchema, PublicInterfaceTypeSchema, PublicInterfaceSchema, TrustedLinkSchema, LintAllowSchema, LintConfigSchema, ExtDataSchema, LifecycleEntrypointSchema, SubsystemSpecSchema, ComponentTypeSchema, PATTERN_TYPES, PortalTypeSchema, DispatchBindingSchema, DurabilitySchema, PatternRefSchema, EventBindingSchema, ExternalLinkTypeSchema, ExternalLinkSchema, PortalAuthSchemeSchema, PortalAuthSchema, ComponentSpecSchema, HttpMethodSchema, TransportSchema, EndpointSchema, SEMANTIC_GUARANTEES, GuaranteeSchema, MethodParamSchema, MethodSignatureSchema, InterfaceSpecSchema, NarrativeStepTypeSchema, LoopKindSchema, SwitchCaseSchema, CatchClauseSchema, ParallelBranchSchema, NarrativeStepSchema, NarrativeDetailSchema, ConformanceTierSchema, MethodImplementationSchema, ImplementationSpecSchema, TypeKindSchema, TypeFieldSchema, TypeMethodSchema, InvariantSchema, TypeSpecSchema, SurfaceOriginSchema, SurfaceTypeDefSchema, SurfaceContractEntrySchema, SurfaceSnapshotSchema, NamedOpenApiSpecSchema, GroupSpecSchema;
|
|
707
707
|
var init_specs = __esm({
|
|
708
708
|
"src/models/specs.ts"() {
|
|
709
709
|
"use strict";
|
|
@@ -907,6 +907,28 @@ var init_specs = __esm({
|
|
|
907
907
|
event: import_zod6.z.string().optional(),
|
|
908
908
|
description: import_zod6.z.string().optional()
|
|
909
909
|
});
|
|
910
|
+
ExternalLinkTypeSchema = import_zod6.z.enum(["implementation", "informative"]);
|
|
911
|
+
ExternalLinkSchema = import_zod6.z.object({
|
|
912
|
+
url: import_zod6.z.string(),
|
|
913
|
+
/** Defaults to 'informative' so an untyped link never silently satisfies the source requirement. */
|
|
914
|
+
type: ExternalLinkTypeSchema.default("informative"),
|
|
915
|
+
label: import_zod6.z.string().optional()
|
|
916
|
+
});
|
|
917
|
+
PortalAuthSchemeSchema = import_zod6.z.enum(["none", "apiKey", "bearer", "basic", "oauth2", "openIdConnect", "custom"]);
|
|
918
|
+
PortalAuthSchema = import_zod6.z.object({
|
|
919
|
+
scheme: PortalAuthSchemeSchema,
|
|
920
|
+
in: import_zod6.z.enum(["header", "query", "cookie"]).optional(),
|
|
921
|
+
name: import_zod6.z.string().optional(),
|
|
922
|
+
bearerFormat: import_zod6.z.string().optional(),
|
|
923
|
+
authorizationUrl: import_zod6.z.string().optional(),
|
|
924
|
+
tokenUrl: import_zod6.z.string().optional(),
|
|
925
|
+
refreshUrl: import_zod6.z.string().optional(),
|
|
926
|
+
scopes: import_zod6.z.array(import_zod6.z.object({ name: import_zod6.z.string(), description: import_zod6.z.string() })).optional(),
|
|
927
|
+
flow: import_zod6.z.enum(["authorizationCode", "clientCredentials", "implicit", "password"]).optional(),
|
|
928
|
+
openIdConnectUrl: import_zod6.z.string().optional(),
|
|
929
|
+
description: import_zod6.z.string().optional(),
|
|
930
|
+
example: import_zod6.z.string().optional()
|
|
931
|
+
});
|
|
910
932
|
ComponentSpecSchema = import_zod6.z.object({
|
|
911
933
|
id: SpecIdSchema,
|
|
912
934
|
name: import_zod6.z.string(),
|
|
@@ -920,6 +942,10 @@ var init_specs = __esm({
|
|
|
920
942
|
dependsOn: import_zod6.z.array(import_zod6.z.string()).default([]),
|
|
921
943
|
portalType: PortalTypeSchema.optional(),
|
|
922
944
|
basePath: import_zod6.z.string().optional(),
|
|
945
|
+
/** Portal-only: the API's authentication scheme (see PortalAuthSchema) — projected
|
|
946
|
+
* into the generated OpenAPI's securitySchemes/security. Portals with different auth
|
|
947
|
+
* must be separate components (one auth per portal ⇒ one OpenAPI spec per portal). */
|
|
948
|
+
auth: PortalAuthSchema.optional(),
|
|
923
949
|
/** Portal-only: capability → component.method dispatch table (see DispatchBindingSchema). */
|
|
924
950
|
dispatch: import_zod6.z.array(DispatchBindingSchema).optional(),
|
|
925
951
|
/** Store-only: whether held state survives restart (see DurabilitySchema). */
|
|
@@ -932,6 +958,11 @@ var init_specs = __esm({
|
|
|
932
958
|
patterns: import_zod6.z.array(PatternRefSchema).optional(),
|
|
933
959
|
/** Optional component variant — a declared, base-anchored specialization of this component's stereotype (resolved against the variant registry; UNKNOWN_VARIANT / VARIANT_BASE_MISMATCH). */
|
|
934
960
|
variant: import_zod6.z.string().optional(),
|
|
961
|
+
/** Opaque external references (see ExternalLinkSchema) — documented URLs wairon does
|
|
962
|
+
* not fetch or validate. An `implementation` link is the external source-of-record and
|
|
963
|
+
* satisfies the source requirement for a source-less implementation (suppresses
|
|
964
|
+
* MISSING_SOURCE_PATH); `informative` links are context only. */
|
|
965
|
+
externalLinks: import_zod6.z.array(ExternalLinkSchema).optional(),
|
|
935
966
|
/** Per-spec lint suppressions (see LintConfigSchema). */
|
|
936
967
|
lint: LintConfigSchema.optional(),
|
|
937
968
|
/** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
|
|
@@ -1280,7 +1311,12 @@ var init_specs = __esm({
|
|
|
1280
1311
|
dispatch: import_zod6.z.array(DispatchBindingSchema).optional(),
|
|
1281
1312
|
details: import_zod6.z.string().default(""),
|
|
1282
1313
|
version: import_zod6.z.string().optional(),
|
|
1283
|
-
stability: import_zod6.z.string().optional()
|
|
1314
|
+
stability: import_zod6.z.string().optional(),
|
|
1315
|
+
/** Projected copy of the backing Portal's auth (see PortalAuthSchema) — the codec
|
|
1316
|
+
* emits it as OpenAPI securitySchemes/security. */
|
|
1317
|
+
auth: PortalAuthSchema.optional(),
|
|
1318
|
+
/** The backing Portal's basePath — becomes the per-portal OpenAPI `servers` url. */
|
|
1319
|
+
basePath: import_zod6.z.string().optional()
|
|
1284
1320
|
});
|
|
1285
1321
|
SurfaceSnapshotSchema = import_zod6.z.object({
|
|
1286
1322
|
/** Producing project/system name — the snapshot's resolution identity. */
|
|
@@ -1295,6 +1331,11 @@ var init_specs = __esm({
|
|
|
1295
1331
|
/** Transitive type closure of every exported signature — self-contained. */
|
|
1296
1332
|
types: import_zod6.z.array(SurfaceTypeDefSchema).default([])
|
|
1297
1333
|
});
|
|
1334
|
+
NamedOpenApiSpecSchema = import_zod6.z.object({
|
|
1335
|
+
portalId: import_zod6.z.string(),
|
|
1336
|
+
name: import_zod6.z.string(),
|
|
1337
|
+
document: import_zod6.z.string()
|
|
1338
|
+
});
|
|
1298
1339
|
GroupSpecSchema = import_zod6.z.object({
|
|
1299
1340
|
kind: import_zod6.z.literal("group"),
|
|
1300
1341
|
id: SpecIdSchema,
|
|
@@ -2652,6 +2693,7 @@ function buildCanvasModel(issues = []) {
|
|
|
2652
2693
|
...ownerOf.has(comp.id) ? { owner: ownerOf.get(comp.id) } : {},
|
|
2653
2694
|
owns: comp.owns.filter((o) => componentIds.has(o)),
|
|
2654
2695
|
dependsOn: comp.dependsOn,
|
|
2696
|
+
...comp.externalLinks && comp.externalLinks.length ? { externalLinks: comp.externalLinks } : {},
|
|
2655
2697
|
interfaces: compInterfaces.map((i) => ({
|
|
2656
2698
|
id: i.id,
|
|
2657
2699
|
name: i.name,
|
|
@@ -6102,7 +6144,7 @@ var MODEL = __MODEL_JSON__;
|
|
|
6102
6144
|
+ (scopeFocus ? staticChip('current view') : '')
|
|
6103
6145
|
+ chip(c.subsystem, 'subsystem', c.subsystem)
|
|
6104
6146
|
+ (scopeFocus ? '' : openViewButton('component', c.id, c.owns.length > 0))
|
|
6105
|
-
+ openApiButton(componentExposesApi(c), c.
|
|
6147
|
+
+ openApiButton(componentExposesApi(c), c.id)
|
|
6106
6148
|
+ openSpecButton('component', c.id);
|
|
6107
6149
|
|
|
6108
6150
|
var linkedTypes = MODEL.types.filter(function (t) { return t.componentClass === c.id; });
|
|
@@ -6113,6 +6155,14 @@ var MODEL = __MODEL_JSON__;
|
|
|
6113
6155
|
}
|
|
6114
6156
|
body += '<p class="desc">' + esc(c.description) + '</p>';
|
|
6115
6157
|
|
|
6158
|
+
if (c.externalLinks && c.externalLinks.length) {
|
|
6159
|
+
body += section('External links', c.externalLinks.length, c.externalLinks.map(function (l) {
|
|
6160
|
+
var label = l.label || l.url;
|
|
6161
|
+
var tag = l.type === 'implementation' ? staticChip('source') : '';
|
|
6162
|
+
return '<div class="method">' + tag + '<a href="' + esc(l.url) + '" target="_blank" rel="noopener" style="color:var(--accent);word-break:break-all">' + esc(label) + ' \\u2197</a></div>';
|
|
6163
|
+
}).join(''), true);
|
|
6164
|
+
}
|
|
6165
|
+
|
|
6116
6166
|
var depInner = (c.dependsOn.length ? c.dependsOn.map(function (d) { return chip(d, 'component', d); }).join('') : '<span class="desc">none</span>')
|
|
6117
6167
|
+ (c.owns.length ? '<div style="margin-top:8px"><b style="font-size:11px">Owns:</b><br>' + c.owns.map(function (d) { return chip(d, 'component', d); }).join('') + '</div>' : '');
|
|
6118
6168
|
body += section('Dependencies', c.dependsOn.length + c.owns.length, depInner, true);
|
|
@@ -6899,11 +6949,63 @@ function operationFor(method2, closureIds) {
|
|
|
6899
6949
|
}
|
|
6900
6950
|
return op;
|
|
6901
6951
|
}
|
|
6902
|
-
function
|
|
6903
|
-
|
|
6904
|
-
const
|
|
6952
|
+
function securitySchemeObject(auth) {
|
|
6953
|
+
if (auth.scheme === "none") return null;
|
|
6954
|
+
const desc = auth.description ? { description: auth.description } : {};
|
|
6955
|
+
switch (auth.scheme) {
|
|
6956
|
+
case "apiKey":
|
|
6957
|
+
return { type: "apiKey", in: auth.in ?? "header", name: auth.name ?? "X-API-Key", ...desc };
|
|
6958
|
+
case "bearer":
|
|
6959
|
+
return { type: "http", scheme: "bearer", ...auth.bearerFormat ? { bearerFormat: auth.bearerFormat } : {}, ...desc };
|
|
6960
|
+
case "basic":
|
|
6961
|
+
return { type: "http", scheme: "basic", ...desc };
|
|
6962
|
+
case "oauth2": {
|
|
6963
|
+
const flow = { scopes: Object.fromEntries((auth.scopes ?? []).map((s) => [s.name, s.description])) };
|
|
6964
|
+
if (auth.authorizationUrl) flow.authorizationUrl = auth.authorizationUrl;
|
|
6965
|
+
if (auth.tokenUrl) flow.tokenUrl = auth.tokenUrl;
|
|
6966
|
+
if (auth.refreshUrl) flow.refreshUrl = auth.refreshUrl;
|
|
6967
|
+
return { type: "oauth2", flows: { [auth.flow ?? "authorizationCode"]: flow }, ...desc };
|
|
6968
|
+
}
|
|
6969
|
+
case "openIdConnect":
|
|
6970
|
+
return { type: "openIdConnect", openIdConnectUrl: auth.openIdConnectUrl ?? "", ...desc };
|
|
6971
|
+
case "custom":
|
|
6972
|
+
return { type: "apiKey", in: auth.in ?? "header", name: auth.name ?? "Authorization", description: auth.description ?? auth.example ?? "Custom authentication scheme." };
|
|
6973
|
+
default:
|
|
6974
|
+
return null;
|
|
6975
|
+
}
|
|
6976
|
+
}
|
|
6977
|
+
function schemeBaseName(scheme) {
|
|
6978
|
+
return { apiKey: "ApiKeyAuth", bearer: "BearerAuth", basic: "BasicAuth", oauth2: "OAuth2", openIdConnect: "OpenIdConnect", custom: "CustomAuth" }[scheme] ?? "Auth";
|
|
6979
|
+
}
|
|
6980
|
+
function buildSecurity(entries) {
|
|
6981
|
+
const schemes = {};
|
|
6982
|
+
const nameByContent = /* @__PURE__ */ new Map();
|
|
6983
|
+
const securityByEntry = /* @__PURE__ */ new Map();
|
|
6984
|
+
for (const entry of entries) {
|
|
6985
|
+
if (!entry.auth) continue;
|
|
6986
|
+
const obj = securitySchemeObject(entry.auth);
|
|
6987
|
+
if (!obj) continue;
|
|
6988
|
+
const content = JSON.stringify(obj);
|
|
6989
|
+
let name = nameByContent.get(content);
|
|
6990
|
+
if (!name) {
|
|
6991
|
+
name = schemeBaseName(entry.auth.scheme);
|
|
6992
|
+
for (let n = 2; schemes[name]; n++) name = schemeBaseName(entry.auth.scheme) + n;
|
|
6993
|
+
schemes[name] = obj;
|
|
6994
|
+
nameByContent.set(content, name);
|
|
6995
|
+
}
|
|
6996
|
+
const scopeNames = entry.auth.scheme === "oauth2" ? (entry.auth.scopes ?? []).map((s) => s.name) : [];
|
|
6997
|
+
securityByEntry.set(entry.id, { [name]: scopeNames });
|
|
6998
|
+
}
|
|
6999
|
+
return { schemes, securityByEntry };
|
|
7000
|
+
}
|
|
7001
|
+
function httpEntriesOf(snapshot) {
|
|
7002
|
+
return snapshot.interfaces.filter((e) => e.type === "REST" || e.methods.some((m) => m.endpoint?.transport === "HTTP"));
|
|
7003
|
+
}
|
|
7004
|
+
function renderDoc(snapshot, entries, closureIds, opts = {}) {
|
|
7005
|
+
const { schemes, securityByEntry } = buildSecurity(entries);
|
|
6905
7006
|
const paths = {};
|
|
6906
|
-
for (const entry of
|
|
7007
|
+
for (const entry of entries) {
|
|
7008
|
+
const security = securityByEntry.get(entry.id);
|
|
6907
7009
|
for (const method2 of entry.methods) {
|
|
6908
7010
|
const endpoint = method2.endpoint;
|
|
6909
7011
|
if (!endpoint || endpoint.transport !== "HTTP") continue;
|
|
@@ -6911,7 +7013,8 @@ function toOpenApi(snapshot) {
|
|
|
6911
7013
|
paths[p] = paths[p] ?? {};
|
|
6912
7014
|
paths[p][endpoint.method.toLowerCase()] = {
|
|
6913
7015
|
tags: [entry.id],
|
|
6914
|
-
...operationFor(method2, closureIds)
|
|
7016
|
+
...operationFor(method2, closureIds),
|
|
7017
|
+
...security ? { security: [security] } : {}
|
|
6915
7018
|
};
|
|
6916
7019
|
}
|
|
6917
7020
|
}
|
|
@@ -6924,19 +7027,41 @@ function toOpenApi(snapshot) {
|
|
|
6924
7027
|
required: t.fields.filter((f) => !f.optional).map((f) => f.name)
|
|
6925
7028
|
};
|
|
6926
7029
|
}
|
|
6927
|
-
const
|
|
7030
|
+
const components = {};
|
|
7031
|
+
if (Object.keys(schemas).length) components.schemas = schemas;
|
|
7032
|
+
if (Object.keys(schemes).length) components.securitySchemes = schemes;
|
|
7033
|
+
const basePaths = [...new Set(entries.map((e) => e.basePath).filter((b) => !!b))];
|
|
7034
|
+
const servers = opts.servers && basePaths.length === 1 ? [{ url: basePaths[0] }] : void 0;
|
|
7035
|
+
return {
|
|
6928
7036
|
openapi: "3.1.0",
|
|
6929
7037
|
info: {
|
|
6930
|
-
title: snapshot.projectName,
|
|
7038
|
+
title: opts.title ?? snapshot.projectName,
|
|
6931
7039
|
version: snapshot.version ?? "0.0.0",
|
|
6932
7040
|
...snapshot.stateId ? { "x-wairon-state-id": snapshot.stateId } : {},
|
|
6933
7041
|
"x-wairon-origin": snapshot.origin,
|
|
6934
7042
|
"x-wairon-generated-at": snapshot.generatedAt
|
|
6935
7043
|
},
|
|
7044
|
+
...servers ? { servers } : {},
|
|
6936
7045
|
paths,
|
|
6937
|
-
...Object.keys(
|
|
7046
|
+
...Object.keys(components).length ? { components } : {}
|
|
6938
7047
|
};
|
|
6939
|
-
|
|
7048
|
+
}
|
|
7049
|
+
function toOpenApiSet(snapshot) {
|
|
7050
|
+
const closureIds = new Set(snapshot.types.map((t) => t.id));
|
|
7051
|
+
const byPortal = /* @__PURE__ */ new Map();
|
|
7052
|
+
const order = [];
|
|
7053
|
+
for (const entry of httpEntriesOf(snapshot)) {
|
|
7054
|
+
if (!byPortal.has(entry.component)) {
|
|
7055
|
+
byPortal.set(entry.component, []);
|
|
7056
|
+
order.push(entry.component);
|
|
7057
|
+
}
|
|
7058
|
+
byPortal.get(entry.component).push(entry);
|
|
7059
|
+
}
|
|
7060
|
+
return order.map((portalId) => {
|
|
7061
|
+
const entries = byPortal.get(portalId);
|
|
7062
|
+
const name = entries[0]?.name ?? portalId;
|
|
7063
|
+
return { portalId, name, document: JSON.stringify(renderDoc(snapshot, entries, closureIds, { title: name, servers: true }), null, 2) };
|
|
7064
|
+
});
|
|
6940
7065
|
}
|
|
6941
7066
|
function isOpenApiDocument(body) {
|
|
6942
7067
|
try {
|
|
@@ -6958,6 +7083,39 @@ function typeRefFromSchema(schema) {
|
|
|
6958
7083
|
if (typeof t === "string" && t !== "object") return t;
|
|
6959
7084
|
return "json";
|
|
6960
7085
|
}
|
|
7086
|
+
function authFromSecurityScheme(scheme) {
|
|
7087
|
+
const desc = typeof scheme.description === "string" ? { description: scheme.description } : {};
|
|
7088
|
+
if (scheme.type === "apiKey") {
|
|
7089
|
+
return {
|
|
7090
|
+
scheme: "apiKey",
|
|
7091
|
+
...scheme.in === "header" || scheme.in === "query" || scheme.in === "cookie" ? { in: scheme.in } : {},
|
|
7092
|
+
...typeof scheme.name === "string" ? { name: scheme.name } : {},
|
|
7093
|
+
...desc
|
|
7094
|
+
};
|
|
7095
|
+
}
|
|
7096
|
+
if (scheme.type === "http") {
|
|
7097
|
+
if (scheme.scheme === "bearer") return { scheme: "bearer", ...typeof scheme.bearerFormat === "string" ? { bearerFormat: scheme.bearerFormat } : {}, ...desc };
|
|
7098
|
+
if (scheme.scheme === "basic") return { scheme: "basic", ...desc };
|
|
7099
|
+
}
|
|
7100
|
+
if (scheme.type === "oauth2") {
|
|
7101
|
+
const flows = scheme.flows ?? {};
|
|
7102
|
+
const flowKey = Object.keys(flows)[0];
|
|
7103
|
+
const f = flows[flowKey] ?? {};
|
|
7104
|
+
return {
|
|
7105
|
+
scheme: "oauth2",
|
|
7106
|
+
...flowKey === "authorizationCode" || flowKey === "clientCredentials" || flowKey === "implicit" || flowKey === "password" ? { flow: flowKey } : {},
|
|
7107
|
+
...typeof f.authorizationUrl === "string" ? { authorizationUrl: f.authorizationUrl } : {},
|
|
7108
|
+
...typeof f.tokenUrl === "string" ? { tokenUrl: f.tokenUrl } : {},
|
|
7109
|
+
...typeof f.refreshUrl === "string" ? { refreshUrl: f.refreshUrl } : {},
|
|
7110
|
+
scopes: Object.entries(f.scopes ?? {}).map(([name, description]) => ({ name, description })),
|
|
7111
|
+
...desc
|
|
7112
|
+
};
|
|
7113
|
+
}
|
|
7114
|
+
if (scheme.type === "openIdConnect") {
|
|
7115
|
+
return { scheme: "openIdConnect", openIdConnectUrl: typeof scheme.openIdConnectUrl === "string" ? scheme.openIdConnectUrl : "", ...desc };
|
|
7116
|
+
}
|
|
7117
|
+
return void 0;
|
|
7118
|
+
}
|
|
6961
7119
|
function fromOpenApi(document, projectName) {
|
|
6962
7120
|
let parsed;
|
|
6963
7121
|
try {
|
|
@@ -7035,6 +7193,9 @@ function fromOpenApi(document, projectName) {
|
|
|
7035
7193
|
}))
|
|
7036
7194
|
});
|
|
7037
7195
|
}
|
|
7196
|
+
const securitySchemes = parsed.components?.securitySchemes ?? {};
|
|
7197
|
+
const firstScheme = Object.values(securitySchemes)[0];
|
|
7198
|
+
const importedAuth = firstScheme ? authFromSecurityScheme(firstScheme) : void 0;
|
|
7038
7199
|
const entry = {
|
|
7039
7200
|
id: `${projectName}-api`,
|
|
7040
7201
|
name: typeof info.title === "string" ? info.title : projectName,
|
|
@@ -7043,7 +7204,8 @@ function fromOpenApi(document, projectName) {
|
|
|
7043
7204
|
component: `${projectName}-api`,
|
|
7044
7205
|
methods,
|
|
7045
7206
|
details: typeof info.description === "string" ? info.description : `Imported OpenAPI surface of ${projectName}.`,
|
|
7046
|
-
...typeof info.version === "string" ? { version: info.version } : {}
|
|
7207
|
+
...typeof info.version === "string" ? { version: info.version } : {},
|
|
7208
|
+
...importedAuth ? { auth: importedAuth } : {}
|
|
7047
7209
|
};
|
|
7048
7210
|
return SurfaceSnapshotSchema.parse({
|
|
7049
7211
|
projectName,
|
|
@@ -7158,6 +7320,10 @@ function projectOwnSurface(maxAudience) {
|
|
|
7158
7320
|
component: comp.id,
|
|
7159
7321
|
methods,
|
|
7160
7322
|
...comp.dispatch && comp.dispatch.length ? { dispatch: comp.dispatch } : {},
|
|
7323
|
+
// Project the backing Portal's auth + basePath so the codec can emit
|
|
7324
|
+
// OpenAPI security + per-portal servers self-contained from the snapshot.
|
|
7325
|
+
...comp.auth && comp.auth.scheme !== "none" ? { auth: comp.auth } : {},
|
|
7326
|
+
...comp.basePath ? { basePath: comp.basePath } : {},
|
|
7161
7327
|
details: raw.details ?? "",
|
|
7162
7328
|
...raw.version ? { version: raw.version } : {},
|
|
7163
7329
|
...raw.stability ? { stability: raw.stability } : {}
|
|
@@ -7201,20 +7367,28 @@ function saveSnapshot(snapshot, rootDir = getProjectRoot()) {
|
|
|
7201
7367
|
function loadSurfaceSnapshots() {
|
|
7202
7368
|
return listSnapshots();
|
|
7203
7369
|
}
|
|
7370
|
+
function renderOpenApiForms(snapshot) {
|
|
7371
|
+
const renderedSet = toOpenApiSet(snapshot);
|
|
7372
|
+
return { renderedSet, ...renderedSet.length === 1 ? { rendered: renderedSet[0].document } : {} };
|
|
7373
|
+
}
|
|
7374
|
+
function writeSurfaceFile(outPath, body, snapshot) {
|
|
7375
|
+
const resolved = path10.resolve(outPath);
|
|
7376
|
+
fs9.mkdirSync(path10.dirname(resolved), { recursive: true });
|
|
7377
|
+
if (body !== void 0) fs9.writeFileSync(resolved, body);
|
|
7378
|
+
else writeYamlFile(resolved, snapshot);
|
|
7379
|
+
return resolved;
|
|
7380
|
+
}
|
|
7204
7381
|
function exportSurface(maxAudience, format, outPath) {
|
|
7205
7382
|
const snapshot = projectOwnSurface(maxAudience);
|
|
7206
|
-
const
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
}
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
writtenTo = path10.resolve(outPath);
|
|
7216
|
-
}
|
|
7217
|
-
return { snapshot, ...rendered !== void 0 ? { rendered } : {}, ...writtenTo ? { writtenTo } : {} };
|
|
7383
|
+
const openapi = format === "openapi" ? renderOpenApiForms(snapshot) : void 0;
|
|
7384
|
+
const body = openapi?.rendered ?? openapi?.renderedSet[0]?.document;
|
|
7385
|
+
const writtenTo = outPath ? writeSurfaceFile(outPath, body, snapshot) : void 0;
|
|
7386
|
+
return {
|
|
7387
|
+
snapshot,
|
|
7388
|
+
...openapi?.rendered !== void 0 ? { rendered: openapi.rendered } : {},
|
|
7389
|
+
...openapi ? { renderedSet: openapi.renderedSet } : {},
|
|
7390
|
+
...writtenTo ? { writtenTo } : {}
|
|
7391
|
+
};
|
|
7218
7392
|
}
|
|
7219
7393
|
function importSurface(sourcePath, origin) {
|
|
7220
7394
|
const resolved = path10.resolve(sourcePath);
|
|
@@ -8474,13 +8648,16 @@ var init_conformance = __esm({
|
|
|
8474
8648
|
if (isInChainedSubproject(component.subsystem, ctx)) continue;
|
|
8475
8649
|
const draft = ctx.isImplementationDraft(impl);
|
|
8476
8650
|
if (!impl.sourcePath) {
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8651
|
+
const hasExternalSource = (component.externalLinks ?? []).some((l) => l.type === "implementation");
|
|
8652
|
+
if (!hasExternalSource) {
|
|
8653
|
+
ctx.addIssue(
|
|
8654
|
+
"warning",
|
|
8655
|
+
"MISSING_SOURCE_PATH",
|
|
8656
|
+
`Implementation "${impl.id}" declares no sourcePath \u2014 its contract "${impl.contract}" cannot be structurally checked against code.`,
|
|
8657
|
+
impl.id,
|
|
8658
|
+
draft
|
|
8659
|
+
);
|
|
8660
|
+
}
|
|
8484
8661
|
continue;
|
|
8485
8662
|
}
|
|
8486
8663
|
const lookup = lookups.get(normalizeSourcePath(impl.sourcePath));
|
|
@@ -32103,7 +32280,7 @@ function getWebProjectCanvasModel(cfg, sessionId, projectId) {
|
|
|
32103
32280
|
}
|
|
32104
32281
|
return runWithProjectRoot(root, () => hostCore.buildCanvasDataModel());
|
|
32105
32282
|
}
|
|
32106
|
-
function getWebProjectOpenApi(cfg, sessionId, projectId) {
|
|
32283
|
+
function getWebProjectOpenApi(cfg, sessionId, projectId, portalId) {
|
|
32107
32284
|
const principal = authenticateSession(cfg.dataDir, sessionId);
|
|
32108
32285
|
if (!principal.authenticated) throw new UnauthenticatedError();
|
|
32109
32286
|
if (!listProjects2(cfg, sessionId).some((r) => r.id === projectId)) {
|
|
@@ -32112,7 +32289,19 @@ function getWebProjectOpenApi(cfg, sessionId, projectId) {
|
|
|
32112
32289
|
const root = resolveProjectRoot(cfg.dataDir, principal, projectId);
|
|
32113
32290
|
if (!root) throw new ForbiddenError("project not authorized or unknown");
|
|
32114
32291
|
const result = runWithProjectRoot(root, () => hostSurfaces.exportBoundSurface("project", "openapi"));
|
|
32115
|
-
|
|
32292
|
+
const specs = result.renderedSet ?? (result.rendered ? [{ portalId: "", name: projectId, document: result.rendered }] : []);
|
|
32293
|
+
if (specs.length === 0) return swaggerUiPage("{}", projectId);
|
|
32294
|
+
if (portalId) {
|
|
32295
|
+
const sel = specs.find((s) => s.portalId === portalId) ?? specs[0];
|
|
32296
|
+
return swaggerUiPage(sel.document, sel.name);
|
|
32297
|
+
}
|
|
32298
|
+
if (specs.length === 1) return swaggerUiPage(specs[0].document, specs[0].name);
|
|
32299
|
+
return openApiIndexPage(projectId, specs);
|
|
32300
|
+
}
|
|
32301
|
+
function openApiIndexPage(projectId, specs) {
|
|
32302
|
+
const esc2 = (s) => s.replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]);
|
|
32303
|
+
const items = specs.map((s) => `<li><a href="/web/openapi?projectId=${encodeURIComponent(projectId)}&spec=${encodeURIComponent(s.portalId)}">${esc2(s.name)}</a> <code>${esc2(s.portalId)}</code></li>`).join("");
|
|
32304
|
+
return `<!doctype html><html><head><meta charset="utf-8"><title>${esc2(projectId)} \u2014 API specs</title><style>body{font-family:system-ui,sans-serif;max-width:680px;margin:48px auto;padding:0 20px;color:#e6e6e6;background:#161616}h1{font-size:20px}a{color:#6ea8fe;text-decoration:none}a:hover{text-decoration:underline}li{margin:10px 0}code{color:#8a94a6;font-size:12px;margin-left:8px}</style></head><body><h1>${esc2(projectId)} \u2014 API specs</h1><p>This project exposes ${specs.length} separate public APIs, each with its own OpenAPI document and auth:</p><ul>${items}</ul></body></html>`;
|
|
32116
32305
|
}
|
|
32117
32306
|
function reshapeLandscapeGraph(model, level) {
|
|
32118
32307
|
const unitNodeIds = new Set(model.nodes.filter((n) => n.nodeKind === "orgUnit").map((n) => n.id));
|
|
@@ -34474,7 +34663,8 @@ async function handleWebRequest(cfg, req, res, body, url, ctx) {
|
|
|
34474
34663
|
}
|
|
34475
34664
|
if (req.method === "GET" && parts.length === 2 && parts[1] === "openapi") {
|
|
34476
34665
|
const projectId = url.searchParams.get("projectId") ?? "";
|
|
34477
|
-
const
|
|
34666
|
+
const spec = url.searchParams.get("spec") ?? void 0;
|
|
34667
|
+
const html = getWebProjectOpenApi(cfg, sessionId, projectId, spec);
|
|
34478
34668
|
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
34479
34669
|
res.end(html);
|
|
34480
34670
|
return;
|