@wairon/cli 5.0.2-dev.7 → 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 +195 -29
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +191 -26
- 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, ExternalLinkTypeSchema, ExternalLinkSchema, 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";
|
|
@@ -914,6 +914,21 @@ var init_specs = __esm({
|
|
|
914
914
|
type: ExternalLinkTypeSchema.default("informative"),
|
|
915
915
|
label: import_zod6.z.string().optional()
|
|
916
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
|
+
});
|
|
917
932
|
ComponentSpecSchema = import_zod6.z.object({
|
|
918
933
|
id: SpecIdSchema,
|
|
919
934
|
name: import_zod6.z.string(),
|
|
@@ -927,6 +942,10 @@ var init_specs = __esm({
|
|
|
927
942
|
dependsOn: import_zod6.z.array(import_zod6.z.string()).default([]),
|
|
928
943
|
portalType: PortalTypeSchema.optional(),
|
|
929
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(),
|
|
930
949
|
/** Portal-only: capability → component.method dispatch table (see DispatchBindingSchema). */
|
|
931
950
|
dispatch: import_zod6.z.array(DispatchBindingSchema).optional(),
|
|
932
951
|
/** Store-only: whether held state survives restart (see DurabilitySchema). */
|
|
@@ -1292,7 +1311,12 @@ var init_specs = __esm({
|
|
|
1292
1311
|
dispatch: import_zod6.z.array(DispatchBindingSchema).optional(),
|
|
1293
1312
|
details: import_zod6.z.string().default(""),
|
|
1294
1313
|
version: import_zod6.z.string().optional(),
|
|
1295
|
-
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()
|
|
1296
1320
|
});
|
|
1297
1321
|
SurfaceSnapshotSchema = import_zod6.z.object({
|
|
1298
1322
|
/** Producing project/system name — the snapshot's resolution identity. */
|
|
@@ -1307,6 +1331,11 @@ var init_specs = __esm({
|
|
|
1307
1331
|
/** Transitive type closure of every exported signature — self-contained. */
|
|
1308
1332
|
types: import_zod6.z.array(SurfaceTypeDefSchema).default([])
|
|
1309
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
|
+
});
|
|
1310
1339
|
GroupSpecSchema = import_zod6.z.object({
|
|
1311
1340
|
kind: import_zod6.z.literal("group"),
|
|
1312
1341
|
id: SpecIdSchema,
|
|
@@ -6115,7 +6144,7 @@ var MODEL = __MODEL_JSON__;
|
|
|
6115
6144
|
+ (scopeFocus ? staticChip('current view') : '')
|
|
6116
6145
|
+ chip(c.subsystem, 'subsystem', c.subsystem)
|
|
6117
6146
|
+ (scopeFocus ? '' : openViewButton('component', c.id, c.owns.length > 0))
|
|
6118
|
-
+ openApiButton(componentExposesApi(c), c.
|
|
6147
|
+
+ openApiButton(componentExposesApi(c), c.id)
|
|
6119
6148
|
+ openSpecButton('component', c.id);
|
|
6120
6149
|
|
|
6121
6150
|
var linkedTypes = MODEL.types.filter(function (t) { return t.componentClass === c.id; });
|
|
@@ -6920,11 +6949,63 @@ function operationFor(method2, closureIds) {
|
|
|
6920
6949
|
}
|
|
6921
6950
|
return op;
|
|
6922
6951
|
}
|
|
6923
|
-
function
|
|
6924
|
-
|
|
6925
|
-
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);
|
|
6926
7006
|
const paths = {};
|
|
6927
|
-
for (const entry of
|
|
7007
|
+
for (const entry of entries) {
|
|
7008
|
+
const security = securityByEntry.get(entry.id);
|
|
6928
7009
|
for (const method2 of entry.methods) {
|
|
6929
7010
|
const endpoint = method2.endpoint;
|
|
6930
7011
|
if (!endpoint || endpoint.transport !== "HTTP") continue;
|
|
@@ -6932,7 +7013,8 @@ function toOpenApi(snapshot) {
|
|
|
6932
7013
|
paths[p] = paths[p] ?? {};
|
|
6933
7014
|
paths[p][endpoint.method.toLowerCase()] = {
|
|
6934
7015
|
tags: [entry.id],
|
|
6935
|
-
...operationFor(method2, closureIds)
|
|
7016
|
+
...operationFor(method2, closureIds),
|
|
7017
|
+
...security ? { security: [security] } : {}
|
|
6936
7018
|
};
|
|
6937
7019
|
}
|
|
6938
7020
|
}
|
|
@@ -6945,19 +7027,41 @@ function toOpenApi(snapshot) {
|
|
|
6945
7027
|
required: t.fields.filter((f) => !f.optional).map((f) => f.name)
|
|
6946
7028
|
};
|
|
6947
7029
|
}
|
|
6948
|
-
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 {
|
|
6949
7036
|
openapi: "3.1.0",
|
|
6950
7037
|
info: {
|
|
6951
|
-
title: snapshot.projectName,
|
|
7038
|
+
title: opts.title ?? snapshot.projectName,
|
|
6952
7039
|
version: snapshot.version ?? "0.0.0",
|
|
6953
7040
|
...snapshot.stateId ? { "x-wairon-state-id": snapshot.stateId } : {},
|
|
6954
7041
|
"x-wairon-origin": snapshot.origin,
|
|
6955
7042
|
"x-wairon-generated-at": snapshot.generatedAt
|
|
6956
7043
|
},
|
|
7044
|
+
...servers ? { servers } : {},
|
|
6957
7045
|
paths,
|
|
6958
|
-
...Object.keys(
|
|
7046
|
+
...Object.keys(components).length ? { components } : {}
|
|
6959
7047
|
};
|
|
6960
|
-
|
|
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
|
+
});
|
|
6961
7065
|
}
|
|
6962
7066
|
function isOpenApiDocument(body) {
|
|
6963
7067
|
try {
|
|
@@ -6979,6 +7083,39 @@ function typeRefFromSchema(schema) {
|
|
|
6979
7083
|
if (typeof t === "string" && t !== "object") return t;
|
|
6980
7084
|
return "json";
|
|
6981
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
|
+
}
|
|
6982
7119
|
function fromOpenApi(document, projectName) {
|
|
6983
7120
|
let parsed;
|
|
6984
7121
|
try {
|
|
@@ -7056,6 +7193,9 @@ function fromOpenApi(document, projectName) {
|
|
|
7056
7193
|
}))
|
|
7057
7194
|
});
|
|
7058
7195
|
}
|
|
7196
|
+
const securitySchemes = parsed.components?.securitySchemes ?? {};
|
|
7197
|
+
const firstScheme = Object.values(securitySchemes)[0];
|
|
7198
|
+
const importedAuth = firstScheme ? authFromSecurityScheme(firstScheme) : void 0;
|
|
7059
7199
|
const entry = {
|
|
7060
7200
|
id: `${projectName}-api`,
|
|
7061
7201
|
name: typeof info.title === "string" ? info.title : projectName,
|
|
@@ -7064,7 +7204,8 @@ function fromOpenApi(document, projectName) {
|
|
|
7064
7204
|
component: `${projectName}-api`,
|
|
7065
7205
|
methods,
|
|
7066
7206
|
details: typeof info.description === "string" ? info.description : `Imported OpenAPI surface of ${projectName}.`,
|
|
7067
|
-
...typeof info.version === "string" ? { version: info.version } : {}
|
|
7207
|
+
...typeof info.version === "string" ? { version: info.version } : {},
|
|
7208
|
+
...importedAuth ? { auth: importedAuth } : {}
|
|
7068
7209
|
};
|
|
7069
7210
|
return SurfaceSnapshotSchema.parse({
|
|
7070
7211
|
projectName,
|
|
@@ -7179,6 +7320,10 @@ function projectOwnSurface(maxAudience) {
|
|
|
7179
7320
|
component: comp.id,
|
|
7180
7321
|
methods,
|
|
7181
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 } : {},
|
|
7182
7327
|
details: raw.details ?? "",
|
|
7183
7328
|
...raw.version ? { version: raw.version } : {},
|
|
7184
7329
|
...raw.stability ? { stability: raw.stability } : {}
|
|
@@ -7222,20 +7367,28 @@ function saveSnapshot(snapshot, rootDir = getProjectRoot()) {
|
|
|
7222
7367
|
function loadSurfaceSnapshots() {
|
|
7223
7368
|
return listSnapshots();
|
|
7224
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
|
+
}
|
|
7225
7381
|
function exportSurface(maxAudience, format, outPath) {
|
|
7226
7382
|
const snapshot = projectOwnSurface(maxAudience);
|
|
7227
|
-
const
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
}
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
writtenTo = path10.resolve(outPath);
|
|
7237
|
-
}
|
|
7238
|
-
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
|
+
};
|
|
7239
7392
|
}
|
|
7240
7393
|
function importSurface(sourcePath, origin) {
|
|
7241
7394
|
const resolved = path10.resolve(sourcePath);
|
|
@@ -32127,7 +32280,7 @@ function getWebProjectCanvasModel(cfg, sessionId, projectId) {
|
|
|
32127
32280
|
}
|
|
32128
32281
|
return runWithProjectRoot(root, () => hostCore.buildCanvasDataModel());
|
|
32129
32282
|
}
|
|
32130
|
-
function getWebProjectOpenApi(cfg, sessionId, projectId) {
|
|
32283
|
+
function getWebProjectOpenApi(cfg, sessionId, projectId, portalId) {
|
|
32131
32284
|
const principal = authenticateSession(cfg.dataDir, sessionId);
|
|
32132
32285
|
if (!principal.authenticated) throw new UnauthenticatedError();
|
|
32133
32286
|
if (!listProjects2(cfg, sessionId).some((r) => r.id === projectId)) {
|
|
@@ -32136,7 +32289,19 @@ function getWebProjectOpenApi(cfg, sessionId, projectId) {
|
|
|
32136
32289
|
const root = resolveProjectRoot(cfg.dataDir, principal, projectId);
|
|
32137
32290
|
if (!root) throw new ForbiddenError("project not authorized or unknown");
|
|
32138
32291
|
const result = runWithProjectRoot(root, () => hostSurfaces.exportBoundSurface("project", "openapi"));
|
|
32139
|
-
|
|
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>`;
|
|
32140
32305
|
}
|
|
32141
32306
|
function reshapeLandscapeGraph(model, level) {
|
|
32142
32307
|
const unitNodeIds = new Set(model.nodes.filter((n) => n.nodeKind === "orgUnit").map((n) => n.id));
|
|
@@ -34498,7 +34663,8 @@ async function handleWebRequest(cfg, req, res, body, url, ctx) {
|
|
|
34498
34663
|
}
|
|
34499
34664
|
if (req.method === "GET" && parts.length === 2 && parts[1] === "openapi") {
|
|
34500
34665
|
const projectId = url.searchParams.get("projectId") ?? "";
|
|
34501
|
-
const
|
|
34666
|
+
const spec = url.searchParams.get("spec") ?? void 0;
|
|
34667
|
+
const html = getWebProjectOpenApi(cfg, sessionId, projectId, spec);
|
|
34502
34668
|
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
34503
34669
|
res.end(html);
|
|
34504
34670
|
return;
|