@base44-preview/cli 0.1.32-pr.663.463d401 → 0.1.32-pr.663.539e770
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/README.md +2 -2
- package/dist/cli/index.js +246 -204
- package/dist/cli/index.js.map +14 -12
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -39570,9 +39570,9 @@ function tm(e, t, r) {
|
|
|
39570
39570
|
return l(["<", r("name"), r("typeArguments"), " ", ...e.map(r, "attributes"), n.selfClosing ? " />" : ">"]);
|
|
39571
39571
|
let i = n.attributes?.some((u) => V3(u.value) && u.value.value.includes(`
|
|
39572
39572
|
`)), o = t.singleAttributePerLine && n.attributes.length > 1 ? E : A;
|
|
39573
|
-
return l(["<", r("name"), r("typeArguments"), m(e.map(() => [o, r()], "attributes")), ...
|
|
39573
|
+
return l(["<", r("name"), r("typeArguments"), m(e.map(() => [o, r()], "attributes")), ...rm3(n, t, s)], { shouldBreak: i });
|
|
39574
39574
|
}
|
|
39575
|
-
function
|
|
39575
|
+
function rm3(e, t, r) {
|
|
39576
39576
|
return e.selfClosing ? [A, "/>"] : nm(e, t, r) ? [">"] : [f, ">"];
|
|
39577
39577
|
}
|
|
39578
39578
|
function nm(e, t, r) {
|
|
@@ -111521,7 +111521,7 @@ function N62(e) {
|
|
|
111521
111521
|
function nm2(e, t, a) {
|
|
111522
111522
|
return ie10(t, a, e.typeParameters) || ie10(t, a, e.parameters) || S7(t, e.type);
|
|
111523
111523
|
}
|
|
111524
|
-
function
|
|
111524
|
+
function rm4(e, t, a) {
|
|
111525
111525
|
return ie10(t, a, e.types);
|
|
111526
111526
|
}
|
|
111527
111527
|
function im2(e, t, a) {
|
|
@@ -114489,7 +114489,7 @@ ${Me.join(`
|
|
|
114489
114489
|
return S7(a, t.elementType);
|
|
114490
114490
|
}, 190: function(t, a, _) {
|
|
114491
114491
|
return ie10(a, _, t.elements);
|
|
114492
|
-
}, 193:
|
|
114492
|
+
}, 193: rm4, 194: rm4, 195: function(t, a, _) {
|
|
114493
114493
|
return S7(a, t.checkType) || S7(a, t.extendsType) || S7(a, t.trueType) || S7(a, t.falseType);
|
|
114494
114494
|
}, 196: function(t, a, _) {
|
|
114495
114495
|
return S7(a, t.typeParameter);
|
|
@@ -249102,23 +249102,30 @@ var wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
249102
249102
|
var SPACE_OR_PUNCTUATION = /[\n\r\p{Z}\p{P}]+/u;
|
|
249103
249103
|
|
|
249104
249104
|
// src/core/api-spec/search.ts
|
|
249105
|
-
var BOOST = {
|
|
249105
|
+
var BOOST = {
|
|
249106
|
+
method: 1,
|
|
249107
|
+
path: 8,
|
|
249108
|
+
summary: 5,
|
|
249109
|
+
description: 2,
|
|
249110
|
+
parameters: 0.5
|
|
249111
|
+
};
|
|
249106
249112
|
var MIN_RELATIVE_SCORE = 0.2;
|
|
249107
249113
|
var TOKEN_SEPARATOR = /[\n\r\p{Z}\p{P}\p{S}]+/u;
|
|
249108
|
-
var STOPWORDS = new Set("a an and are at be by do does for from how i in is it its me my of on or our that the this to we what who with you your".split(" "));
|
|
249114
|
+
var STOPWORDS = new Set("a an and are at be by do does for from how i id in is it its me my of on or our that the this to we what who with you your".split(" "));
|
|
249109
249115
|
function tokenize(text) {
|
|
249110
|
-
return text.split(TOKEN_SEPARATOR).filter((word) => word && !STOPWORDS.has(word.toLowerCase()));
|
|
249116
|
+
return text.split(TOKEN_SEPARATOR).filter((word) => word.length >= 2 && !STOPWORDS.has(word.toLowerCase()));
|
|
249111
249117
|
}
|
|
249112
249118
|
function toOperationSummary(op) {
|
|
249113
249119
|
return { endpoint: op.endpoint, summary: op.summary };
|
|
249114
249120
|
}
|
|
249115
249121
|
function buildSearchIndex(operations) {
|
|
249116
249122
|
const index = new MiniSearch({
|
|
249117
|
-
fields: ["path", "summary", "description", "parameters"],
|
|
249123
|
+
fields: ["method", "path", "summary", "description", "parameters"],
|
|
249118
249124
|
tokenize
|
|
249119
249125
|
});
|
|
249120
249126
|
index.addAll(operations.map((op, id) => ({
|
|
249121
249127
|
id,
|
|
249128
|
+
method: op.method,
|
|
249122
249129
|
path: op.path.replace(/\{[^}]*\}/g, ""),
|
|
249123
249130
|
summary: op.summary,
|
|
249124
249131
|
description: op.description,
|
|
@@ -249126,27 +249133,37 @@ function buildSearchIndex(operations) {
|
|
|
249126
249133
|
})));
|
|
249127
249134
|
return index;
|
|
249128
249135
|
}
|
|
249129
|
-
function
|
|
249130
|
-
const
|
|
249131
|
-
|
|
249132
|
-
|
|
249133
|
-
|
|
249134
|
-
|
|
249135
|
-
|
|
249136
|
+
function summaryMatch(terms, op) {
|
|
249137
|
+
const words = tokenize(op?.summary.toLowerCase() ?? "");
|
|
249138
|
+
const named = (word) => terms.some((term) => word.startsWith(term));
|
|
249139
|
+
return {
|
|
249140
|
+
coverage: terms.filter((term) => words.some((word) => word.startsWith(term))).length / terms.length,
|
|
249141
|
+
precision: words.length ? words.filter(named).length / words.length : 0
|
|
249142
|
+
};
|
|
249136
249143
|
}
|
|
249144
|
+
var readsFirst = (op) => op?.method === "GET" ? 0 : 1;
|
|
249137
249145
|
function searchOperations(operations, query, options = {}) {
|
|
249146
|
+
const terms = tokenize(query.toLowerCase());
|
|
249147
|
+
if (terms.length === 0) {
|
|
249148
|
+
return [];
|
|
249149
|
+
}
|
|
249138
249150
|
const index = buildSearchIndex(operations);
|
|
249139
249151
|
const hits = index.search(query, {
|
|
249140
249152
|
prefix: (term) => term.length >= 3,
|
|
249141
249153
|
fuzzy: (term) => term.length >= 4 ? 0.2 : false,
|
|
249142
249154
|
boost: BOOST,
|
|
249143
249155
|
filter: options.readOnly ? (hit) => operations[hit.id]?.readOnly === true : undefined
|
|
249144
|
-
}).map((hit) =>
|
|
249145
|
-
|
|
249146
|
-
|
|
249147
|
-
|
|
249148
|
-
|
|
249149
|
-
|
|
249156
|
+
}).map((hit) => {
|
|
249157
|
+
const match = summaryMatch(terms, operations[hit.id]);
|
|
249158
|
+
return {
|
|
249159
|
+
...hit,
|
|
249160
|
+
...match,
|
|
249161
|
+
full: match.coverage === 1,
|
|
249162
|
+
score: hit.score * (1 + match.coverage)
|
|
249163
|
+
};
|
|
249164
|
+
}).sort((a, b) => Number(b.full) - Number(a.full) || (a.full ? b.precision - a.precision || readsFirst(operations[a.id]) - readsFirst(operations[b.id]) : 0) || b.score - a.score);
|
|
249165
|
+
const baseline = Math.max(0, ...hits.map((hit) => hit.score)) * MIN_RELATIVE_SCORE;
|
|
249166
|
+
return hits.filter((hit) => hit.full || hit.score >= baseline).slice(0, options.limit ?? 5).flatMap((hit) => {
|
|
249150
249167
|
const op = operations[hit.id];
|
|
249151
249168
|
return op ? [toOperationSummary(op)] : [];
|
|
249152
249169
|
});
|
|
@@ -249177,7 +249194,7 @@ function groupByArea(operations) {
|
|
|
249177
249194
|
}
|
|
249178
249195
|
return new Map([...areas].sort(([a], [b]) => byCodePoint(a, b)));
|
|
249179
249196
|
}
|
|
249180
|
-
function
|
|
249197
|
+
function readsFirst2(ops) {
|
|
249181
249198
|
const isRead = (op) => op.method === "GET" ? 0 : 1;
|
|
249182
249199
|
return [...ops].sort((a, b) => isRead(a) - isRead(b));
|
|
249183
249200
|
}
|
|
@@ -249185,7 +249202,7 @@ function catalogIndex(operations) {
|
|
|
249185
249202
|
const areas = [...groupByArea(operations)].map(([area, ops]) => ops.length <= INLINE_AREA_MAX ? { area, operations: ops.map(toOperationSummary) } : {
|
|
249186
249203
|
area,
|
|
249187
249204
|
operationCount: ops.length,
|
|
249188
|
-
sample:
|
|
249205
|
+
sample: readsFirst2(ops).slice(0, AREA_SAMPLE_MAX).map((op) => op.summary)
|
|
249189
249206
|
});
|
|
249190
249207
|
return { areas, total: operations.length };
|
|
249191
249208
|
}
|
|
@@ -249197,44 +249214,6 @@ function areaListing(area, operations, max = AREA_OPERATIONS_MAX) {
|
|
|
249197
249214
|
truncated: operations.length > max
|
|
249198
249215
|
};
|
|
249199
249216
|
}
|
|
249200
|
-
// src/core/api-spec/grep.ts
|
|
249201
|
-
var CONTEXT_CHARS = 40;
|
|
249202
|
-
var MAX_SNIPPETS = 3;
|
|
249203
|
-
var MAX_SNIPPET_CHARS = 200;
|
|
249204
|
-
function unescapeJson(snippet) {
|
|
249205
|
-
return snippet.replace(/\\[nrt]/g, " ").replace(/\\"/g, '"');
|
|
249206
|
-
}
|
|
249207
|
-
function snippets(text, pattern) {
|
|
249208
|
-
const found = [];
|
|
249209
|
-
for (const match of text.matchAll(pattern)) {
|
|
249210
|
-
const start = Math.max(0, match.index - CONTEXT_CHARS);
|
|
249211
|
-
const end = match.index + match[0].length + CONTEXT_CHARS;
|
|
249212
|
-
found.push(unescapeJson(text.slice(start, Math.min(end, start + MAX_SNIPPET_CHARS))));
|
|
249213
|
-
if (found.length === MAX_SNIPPETS || match[0].length === 0) {
|
|
249214
|
-
break;
|
|
249215
|
-
}
|
|
249216
|
-
}
|
|
249217
|
-
return found;
|
|
249218
|
-
}
|
|
249219
|
-
function grepSpec(spec, operations, pattern, options = {}) {
|
|
249220
|
-
const regex = new RegExp(pattern, options.ignoreCase ? "gi" : "g");
|
|
249221
|
-
const hits = [];
|
|
249222
|
-
for (const op of operations) {
|
|
249223
|
-
const { summary, description, parameters, requestBody, responses } = op.operation;
|
|
249224
|
-
const matches = snippets(`${op.endpoint} ${JSON.stringify({ summary, description, parameters, requestBody, responses })}`, regex);
|
|
249225
|
-
if (matches.length > 0) {
|
|
249226
|
-
hits.push({ ...toOperationSummary(op), matches });
|
|
249227
|
-
}
|
|
249228
|
-
}
|
|
249229
|
-
const schemas = options.schemas === false ? {} : spec.components?.schemas;
|
|
249230
|
-
for (const [schema, definition] of Object.entries(schemas ?? {})) {
|
|
249231
|
-
const matches = snippets(JSON.stringify(definition), regex);
|
|
249232
|
-
if (matches.length > 0) {
|
|
249233
|
-
hits.push({ schema, matches });
|
|
249234
|
-
}
|
|
249235
|
-
}
|
|
249236
|
-
return hits.slice(0, options.limit ?? 20);
|
|
249237
|
-
}
|
|
249238
249217
|
// src/core/api-spec/schema.ts
|
|
249239
249218
|
var HTTP_METHODS = [
|
|
249240
249219
|
"get",
|
|
@@ -249255,7 +249234,7 @@ var ParameterSchema = looseObject({
|
|
|
249255
249234
|
example: unknown().optional()
|
|
249256
249235
|
});
|
|
249257
249236
|
var MediaTypesSchema = record(string2(), looseObject({ schema: unknown().optional() }));
|
|
249258
|
-
var
|
|
249237
|
+
var MediaContentSchema = looseObject({
|
|
249259
249238
|
content: MediaTypesSchema.optional()
|
|
249260
249239
|
});
|
|
249261
249240
|
var ResponseObjectSchema = looseObject({
|
|
@@ -249285,91 +249264,16 @@ var OpenApiSpecSchema = looseObject({
|
|
|
249285
249264
|
security: array(SecurityRequirementSchema).optional()
|
|
249286
249265
|
});
|
|
249287
249266
|
|
|
249288
|
-
// src/core/api-spec/
|
|
249289
|
-
var
|
|
249290
|
-
var
|
|
249291
|
-
function
|
|
249292
|
-
|
|
249293
|
-
return security.some((requirement) => requirement[PERSONAL_ACCESS_TOKEN_SCHEME]?.includes(READ_ONLY_SCOPE));
|
|
249294
|
-
}
|
|
249295
|
-
function parameterText(operation) {
|
|
249296
|
-
return (operation.parameters ?? []).flatMap((parameter) => {
|
|
249297
|
-
const parsed = ParameterSchema.safeParse(parameter);
|
|
249298
|
-
return parsed.success ? [parsed.data.name, parsed.data.description ?? ""] : [];
|
|
249299
|
-
}).join(" ");
|
|
249300
|
-
}
|
|
249301
|
-
function mergeParameters(shared, own) {
|
|
249302
|
-
if (!shared?.length) {
|
|
249303
|
-
return own;
|
|
249304
|
-
}
|
|
249305
|
-
const key = (parameter) => {
|
|
249306
|
-
const parsed = ParameterSchema.safeParse(parameter);
|
|
249307
|
-
return parsed.success ? `${parsed.data.in}:${parsed.data.name}` : undefined;
|
|
249308
|
-
};
|
|
249309
|
-
const ownKeys = new Set((own ?? []).map(key));
|
|
249310
|
-
return [
|
|
249311
|
-
...shared.filter((parameter) => !ownKeys.has(key(parameter))),
|
|
249312
|
-
...own ?? []
|
|
249313
|
-
];
|
|
249314
|
-
}
|
|
249315
|
-
function listOperations(spec) {
|
|
249316
|
-
return Object.entries(spec.paths).flatMap(([path, item]) => HTTP_METHODS.flatMap((method) => {
|
|
249317
|
-
const declared = item[method];
|
|
249318
|
-
if (!declared) {
|
|
249319
|
-
return [];
|
|
249320
|
-
}
|
|
249321
|
-
const operation = {
|
|
249322
|
-
...declared,
|
|
249323
|
-
parameters: mergeParameters(item.parameters, declared.parameters)
|
|
249324
|
-
};
|
|
249325
|
-
return [
|
|
249326
|
-
{
|
|
249327
|
-
endpoint: `${method.toUpperCase()} ${path}`,
|
|
249328
|
-
method: method.toUpperCase(),
|
|
249329
|
-
path,
|
|
249330
|
-
summary: operation.summary ?? "",
|
|
249331
|
-
description: operation.description ?? "",
|
|
249332
|
-
parameterText: parameterText(operation),
|
|
249333
|
-
readOnly: isReadOnly(operation, spec),
|
|
249334
|
-
operation
|
|
249335
|
-
}
|
|
249336
|
-
];
|
|
249337
|
-
}));
|
|
249338
|
-
}
|
|
249339
|
-
function pathSegments(path) {
|
|
249340
|
-
const pathname = path.split(/[?#]/, 1)[0] ?? "";
|
|
249341
|
-
return pathname.split("/").filter(Boolean);
|
|
249342
|
-
}
|
|
249343
|
-
function segmentPattern(segment) {
|
|
249344
|
-
const source = segment.split(/(\{[^}]+\})/).map((part) => part.startsWith("{") ? "[^/]+" : part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("");
|
|
249345
|
-
return new RegExp(`^${source}$`);
|
|
249346
|
-
}
|
|
249347
|
-
function specificity(templateSegments) {
|
|
249348
|
-
return templateSegments.map((segment) => segment.includes("{") ? 0 : 1);
|
|
249349
|
-
}
|
|
249350
|
-
function compareSpecificity(a, b) {
|
|
249351
|
-
for (let i = 0;i < a.length; i++) {
|
|
249352
|
-
if (a[i] !== b[i]) {
|
|
249353
|
-
return (b[i] ?? 0) - (a[i] ?? 0);
|
|
249354
|
-
}
|
|
249355
|
-
}
|
|
249356
|
-
return 0;
|
|
249357
|
-
}
|
|
249358
|
-
function matchOperation(operations, method, concretePath) {
|
|
249359
|
-
const upperMethod = method.toUpperCase();
|
|
249360
|
-
const segments = pathSegments(concretePath);
|
|
249361
|
-
const candidates = operations.filter((op) => {
|
|
249362
|
-
if (op.method !== upperMethod) {
|
|
249363
|
-
return false;
|
|
249364
|
-
}
|
|
249365
|
-
const template = pathSegments(op.path);
|
|
249366
|
-
return template.length === segments.length && template.every((part, i) => segmentPattern(part).test(segments[i] ?? ""));
|
|
249367
|
-
});
|
|
249368
|
-
return candidates.sort((a, b) => compareSpecificity(specificity(pathSegments(a.path)), specificity(pathSegments(b.path))))[0];
|
|
249267
|
+
// src/core/api-spec/text.ts
|
|
249268
|
+
var DOCS_CALLOUT = /<(Info|Note|Tip|Check|Warning)>([\s\S]*?)<\/\1>/g;
|
|
249269
|
+
var RELATIVE_LINK = /\[([^\]]+)\]\(\/[^)]*\)/g;
|
|
249270
|
+
function cleanText(text) {
|
|
249271
|
+
return text.replace(DOCS_CALLOUT, (_, kind, body) => kind === "Warning" ? `Warning: ${body}` : body).replace(RELATIVE_LINK, "$1");
|
|
249369
249272
|
}
|
|
249273
|
+
|
|
249274
|
+
// src/core/api-spec/contract.ts
|
|
249370
249275
|
var SCHEMA_REF_PREFIX = "#/components/schemas/";
|
|
249371
249276
|
var MAX_REF_DEPTH = 4;
|
|
249372
|
-
var FRAMEWORK_VALIDATION_ERROR = "Validation Error";
|
|
249373
249277
|
function inlineRefs(node, schemas, seen = new Set, depth = 0) {
|
|
249374
249278
|
if (depth > MAX_REF_DEPTH) {
|
|
249375
249279
|
return node;
|
|
@@ -249394,12 +249298,8 @@ function inlineRefs(node, schemas, seen = new Set, depth = 0) {
|
|
|
249394
249298
|
inlineRefs(value, schemas, seen, depth)
|
|
249395
249299
|
]));
|
|
249396
249300
|
}
|
|
249397
|
-
function
|
|
249398
|
-
const parsed =
|
|
249399
|
-
return parsed.success ? parsed.data.content?.["application/json"]?.schema : undefined;
|
|
249400
|
-
}
|
|
249401
|
-
function requestBodyOf(value) {
|
|
249402
|
-
const parsed = RequestBodySchema.safeParse(value);
|
|
249301
|
+
function bodyOf(value) {
|
|
249302
|
+
const parsed = MediaContentSchema.safeParse(value);
|
|
249403
249303
|
const content = parsed.success ? parsed.data.content ?? {} : {};
|
|
249404
249304
|
const contentType = "application/json" in content ? "application/json" : Object.keys(content)[0];
|
|
249405
249305
|
return contentType ? { contentType, schema: content[contentType]?.schema } : {};
|
|
@@ -249413,8 +249313,10 @@ function leftoverRefs(node, schemas, found = new Map) {
|
|
|
249413
249313
|
for (const [key, value] of Object.entries(node)) {
|
|
249414
249314
|
if (key === "$ref" && typeof value === "string" && value.startsWith(SCHEMA_REF_PREFIX) && !found.has(value)) {
|
|
249415
249315
|
const schema = schemas[value.slice(SCHEMA_REF_PREFIX.length)];
|
|
249416
|
-
|
|
249417
|
-
|
|
249316
|
+
if (schema !== undefined) {
|
|
249317
|
+
found.set(value, schema);
|
|
249318
|
+
leftoverRefs(schema, schemas, found);
|
|
249319
|
+
}
|
|
249418
249320
|
} else {
|
|
249419
249321
|
leftoverRefs(value, schemas, found);
|
|
249420
249322
|
}
|
|
@@ -249422,16 +249324,51 @@ function leftoverRefs(node, schemas, found = new Map) {
|
|
|
249422
249324
|
}
|
|
249423
249325
|
return found;
|
|
249424
249326
|
}
|
|
249327
|
+
var SCHEMA_DATA_KEYS = new Set([
|
|
249328
|
+
"example",
|
|
249329
|
+
"examples",
|
|
249330
|
+
"default",
|
|
249331
|
+
"enum",
|
|
249332
|
+
"const"
|
|
249333
|
+
]);
|
|
249334
|
+
function slimSchema(node, isPropertyMap = false) {
|
|
249335
|
+
if (Array.isArray(node)) {
|
|
249336
|
+
return node.map((item) => slimSchema(item));
|
|
249337
|
+
}
|
|
249338
|
+
if (node === null || typeof node !== "object") {
|
|
249339
|
+
return node;
|
|
249340
|
+
}
|
|
249341
|
+
const entries = Object.entries(node);
|
|
249342
|
+
if (isPropertyMap) {
|
|
249343
|
+
return Object.fromEntries(entries.map(([name, value]) => [name, slimSchema(value)]));
|
|
249344
|
+
}
|
|
249345
|
+
const slim = {};
|
|
249346
|
+
for (const [key, value] of entries) {
|
|
249347
|
+
if (key === "title" && typeof value === "string") {
|
|
249348
|
+
continue;
|
|
249349
|
+
}
|
|
249350
|
+
slim[key] = SCHEMA_DATA_KEYS.has(key) ? value : key === "properties" ? slimSchema(value, true) : key === "description" && typeof value === "string" ? cleanText(value) : slimSchema(value);
|
|
249351
|
+
}
|
|
249352
|
+
const { anyOf, ...rest } = slim;
|
|
249353
|
+
const nullable = Array.isArray(anyOf) && anyOf.length === 2 ? nullableType(anyOf) : undefined;
|
|
249354
|
+
return nullable ? { type: [nullable, "null"], ...rest } : slim;
|
|
249355
|
+
}
|
|
249356
|
+
function nullableType(variants) {
|
|
249357
|
+
const types = variants.map((variant) => variant !== null && typeof variant === "object" && Object.keys(variant).length === 1 && typeof variant.type === "string" ? variant.type : undefined);
|
|
249358
|
+
if (types.includes(undefined) || !types.includes("null")) {
|
|
249359
|
+
return;
|
|
249360
|
+
}
|
|
249361
|
+
return types.find((type) => type !== "null");
|
|
249362
|
+
}
|
|
249425
249363
|
function getOperationContract(spec, op) {
|
|
249426
249364
|
const schemas = spec.components?.schemas ?? {};
|
|
249427
|
-
const inline = (node) => node === undefined ? null : inlineRefs(node, schemas);
|
|
249365
|
+
const inline = (node) => node === undefined ? null : slimSchema(inlineRefs(node, schemas));
|
|
249428
249366
|
const responses = Object.entries(op.operation.responses ?? {}).flatMap(([status, response]) => {
|
|
249429
249367
|
const parsed = ResponseObjectSchema.safeParse(response);
|
|
249430
249368
|
return parsed.success ? [[status, parsed.data]] : [];
|
|
249431
249369
|
});
|
|
249432
|
-
const success = responses.filter(([status]) => status.startsWith("2")).sort(([a], [b]) => a.localeCompare(b)).map(([, response]) =>
|
|
249433
|
-
const
|
|
249434
|
-
const requestBody = requestBodyOf(op.operation.requestBody);
|
|
249370
|
+
const success = responses.filter(([status]) => status.startsWith("2")).sort(([a], [b]) => a.localeCompare(b)).map(([, response]) => bodyOf(response).schema).find(Boolean);
|
|
249371
|
+
const requestBody = bodyOf(op.operation.requestBody);
|
|
249435
249372
|
const contract = {
|
|
249436
249373
|
endpoint: op.endpoint,
|
|
249437
249374
|
method: op.method,
|
|
@@ -249451,24 +249388,105 @@ function getOperationContract(spec, op) {
|
|
|
249451
249388
|
in: location2,
|
|
249452
249389
|
required: required ?? false,
|
|
249453
249390
|
schema: inline(schema ?? {}),
|
|
249454
|
-
...description && !inSchema ? { description } : {},
|
|
249391
|
+
...description && !inSchema ? { description: cleanText(description) } : {},
|
|
249455
249392
|
..."example" in parsed.data ? { example: parsed.data.example } : {}
|
|
249456
249393
|
}
|
|
249457
249394
|
];
|
|
249458
249395
|
}),
|
|
249459
249396
|
...requestBody.contentType && requestBody.contentType !== "application/json" ? { requestBodyContentType: requestBody.contentType } : {},
|
|
249460
249397
|
requestBodySchema: inline(requestBody.schema),
|
|
249461
|
-
responseSchema: inline(success)
|
|
249462
|
-
errors: Object.fromEntries(errors.map(([status, response]) => [status, response.description ?? ""]))
|
|
249398
|
+
responseSchema: inline(success)
|
|
249463
249399
|
};
|
|
249464
249400
|
const refs = leftoverRefs(contract, schemas);
|
|
249465
249401
|
return {
|
|
249466
249402
|
...contract,
|
|
249467
|
-
...refs.size > 0 ? {
|
|
249403
|
+
...refs.size > 0 ? {
|
|
249404
|
+
refs: Object.fromEntries([...refs].map(([ref, schema]) => [ref, slimSchema(schema)]))
|
|
249405
|
+
} : {}
|
|
249468
249406
|
};
|
|
249469
249407
|
}
|
|
249408
|
+
// src/core/api-spec/grep.ts
|
|
249409
|
+
function grepOperations(spec, operations, pattern, options = {}) {
|
|
249410
|
+
const regex = new RegExp(pattern, options.ignoreCase ? "i" : "");
|
|
249411
|
+
return operations.filter((op) => regex.test(JSON.stringify(getOperationContract(spec, op)))).slice(0, options.limit ?? 20).map(toOperationSummary);
|
|
249412
|
+
}
|
|
249413
|
+
// src/core/api-spec/operations.ts
|
|
249414
|
+
var PERSONAL_ACCESS_TOKEN_SCHEME = "PersonalAccessTokenAuth";
|
|
249415
|
+
var READ_ONLY_SCOPE = "read_only";
|
|
249416
|
+
function isReadOnly(operation, spec) {
|
|
249417
|
+
const security = operation.security ?? spec.security ?? [];
|
|
249418
|
+
return security.some((requirement) => requirement[PERSONAL_ACCESS_TOKEN_SCHEME]?.includes(READ_ONLY_SCOPE));
|
|
249419
|
+
}
|
|
249420
|
+
function parameterText(operation) {
|
|
249421
|
+
return (operation.parameters ?? []).flatMap((parameter) => {
|
|
249422
|
+
const parsed = ParameterSchema.safeParse(parameter);
|
|
249423
|
+
return parsed.success ? [parsed.data.name, cleanText(parsed.data.description ?? "")] : [];
|
|
249424
|
+
}).join(" ");
|
|
249425
|
+
}
|
|
249426
|
+
function mergeParameters(shared, own) {
|
|
249427
|
+
if (!shared?.length) {
|
|
249428
|
+
return own;
|
|
249429
|
+
}
|
|
249430
|
+
const key = (parameter) => {
|
|
249431
|
+
const parsed = ParameterSchema.safeParse(parameter);
|
|
249432
|
+
return parsed.success ? `${parsed.data.in}:${parsed.data.name}` : undefined;
|
|
249433
|
+
};
|
|
249434
|
+
const ownKeys = new Set((own ?? []).map(key));
|
|
249435
|
+
return [
|
|
249436
|
+
...shared.filter((parameter) => !ownKeys.has(key(parameter))),
|
|
249437
|
+
...own ?? []
|
|
249438
|
+
];
|
|
249439
|
+
}
|
|
249440
|
+
function listOperations(spec) {
|
|
249441
|
+
return Object.entries(spec.paths).flatMap(([path, item]) => HTTP_METHODS.flatMap((method) => {
|
|
249442
|
+
const declared = item[method];
|
|
249443
|
+
if (!declared) {
|
|
249444
|
+
return [];
|
|
249445
|
+
}
|
|
249446
|
+
const operation = {
|
|
249447
|
+
...declared,
|
|
249448
|
+
parameters: mergeParameters(item.parameters, declared.parameters)
|
|
249449
|
+
};
|
|
249450
|
+
return [
|
|
249451
|
+
{
|
|
249452
|
+
endpoint: `${method.toUpperCase()} ${path}`,
|
|
249453
|
+
method: method.toUpperCase(),
|
|
249454
|
+
path,
|
|
249455
|
+
summary: operation.summary ?? "",
|
|
249456
|
+
description: cleanText(operation.description ?? ""),
|
|
249457
|
+
parameterText: parameterText(operation),
|
|
249458
|
+
readOnly: isReadOnly(operation, spec),
|
|
249459
|
+
operation
|
|
249460
|
+
}
|
|
249461
|
+
];
|
|
249462
|
+
}));
|
|
249463
|
+
}
|
|
249464
|
+
function pathSegments(path) {
|
|
249465
|
+
const pathname = path.split(/[?#]/, 1)[0] ?? "";
|
|
249466
|
+
return pathname.split("/").filter(Boolean);
|
|
249467
|
+
}
|
|
249468
|
+
function segmentPattern(segment) {
|
|
249469
|
+
const source = segment.split(/(\{[^}]+\})/).map((part) => part.startsWith("{") ? "[^/]+" : part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("");
|
|
249470
|
+
return new RegExp(`^${source}$`);
|
|
249471
|
+
}
|
|
249472
|
+
function literalSegments(path) {
|
|
249473
|
+
return pathSegments(path).map((segment) => segment.includes("{") ? "0" : "1").join("");
|
|
249474
|
+
}
|
|
249475
|
+
function matchOperation(operations, method, concretePath) {
|
|
249476
|
+
const upperMethod = method.toUpperCase();
|
|
249477
|
+
const segments = pathSegments(concretePath);
|
|
249478
|
+
const candidates = operations.filter((op) => {
|
|
249479
|
+
if (op.method !== upperMethod) {
|
|
249480
|
+
return false;
|
|
249481
|
+
}
|
|
249482
|
+
const template = pathSegments(op.path);
|
|
249483
|
+
return template.length === segments.length && template.every((part, i) => segmentPattern(part).test(segments[i] ?? ""));
|
|
249484
|
+
});
|
|
249485
|
+
return candidates.sort((a, b) => literalSegments(b.path).localeCompare(literalSegments(a.path)))[0];
|
|
249486
|
+
}
|
|
249470
249487
|
// src/core/api-spec/request.ts
|
|
249471
249488
|
var MAX_ERROR_BODY_CHARS = 4000;
|
|
249489
|
+
var QUERY_STRING = /\?\S*/g;
|
|
249472
249490
|
async function readBody(response) {
|
|
249473
249491
|
try {
|
|
249474
249492
|
const text = (await response.clone().text()).trim();
|
|
@@ -249483,7 +249501,8 @@ async function sendApiRequest(method, path, body) {
|
|
|
249483
249501
|
method,
|
|
249484
249502
|
body,
|
|
249485
249503
|
headers: body === undefined ? {} : { "Content-Type": "application/json" },
|
|
249486
|
-
timeout: false
|
|
249504
|
+
timeout: false,
|
|
249505
|
+
retry: { methods: ["get", "head"] }
|
|
249487
249506
|
});
|
|
249488
249507
|
return {
|
|
249489
249508
|
status: response.status,
|
|
@@ -249493,18 +249512,23 @@ async function sendApiRequest(method, path, body) {
|
|
|
249493
249512
|
} catch (error) {
|
|
249494
249513
|
const apiError = await ApiError.fromHttpError(error, `calling ${method} ${path}`);
|
|
249495
249514
|
const raw = error instanceof HTTPError ? await readBody(error.response) : undefined;
|
|
249496
|
-
throw
|
|
249497
|
-
statusCode: apiError.statusCode,
|
|
249498
|
-
requestUrl: apiError.requestUrl,
|
|
249499
|
-
requestMethod: apiError.requestMethod,
|
|
249500
|
-
requestId: apiError.requestId,
|
|
249501
|
-
hints: apiError.hints,
|
|
249502
|
-
details: raw ? [`Response body: ${raw}`] : apiError.details
|
|
249503
|
-
});
|
|
249515
|
+
throw redactedApiError(apiError, raw, method, path);
|
|
249504
249516
|
}
|
|
249505
249517
|
}
|
|
249518
|
+
function redactedApiError(apiError, raw, method, path) {
|
|
249519
|
+
const reason = apiError.statusCode !== undefined ? `HTTP ${apiError.statusCode}` : (apiError.cause?.message ?? "request failed").replace(QUERY_STRING, "");
|
|
249520
|
+
const message = `Error calling ${method} ${path.split("?", 1)[0]}: ${reason}`;
|
|
249521
|
+
return new ApiError(message, {
|
|
249522
|
+
statusCode: apiError.statusCode,
|
|
249523
|
+
requestUrl: apiError.requestUrl?.split("?", 1)[0],
|
|
249524
|
+
requestMethod: apiError.requestMethod,
|
|
249525
|
+
requestId: apiError.requestId,
|
|
249526
|
+
hints: apiError.hints,
|
|
249527
|
+
details: raw ? [`Response body: ${raw}`] : apiError.details
|
|
249528
|
+
});
|
|
249529
|
+
}
|
|
249506
249530
|
// src/core/api-spec/spec.ts
|
|
249507
|
-
import { rename, stat as stat3 } from "node:fs/promises";
|
|
249531
|
+
import { rename, rm, stat as stat3 } from "node:fs/promises";
|
|
249508
249532
|
import { join as join22 } from "node:path";
|
|
249509
249533
|
var SPEC_CACHE_TTL_MS = 60 * 60 * 1000;
|
|
249510
249534
|
function getSpecCachePath(apiUrl = getBase44ApiUrl()) {
|
|
@@ -249559,8 +249583,14 @@ async function loadSpec(options = {}) {
|
|
|
249559
249583
|
const text = await downloadSpec();
|
|
249560
249584
|
const spec = parseSpec(text);
|
|
249561
249585
|
const partial = `${path}.${process.pid}.tmp`;
|
|
249562
|
-
|
|
249563
|
-
|
|
249586
|
+
try {
|
|
249587
|
+
await writeFile(partial, text);
|
|
249588
|
+
await rename(partial, path);
|
|
249589
|
+
} catch {
|
|
249590
|
+
await rm(partial, { force: true }).catch(() => {
|
|
249591
|
+
return;
|
|
249592
|
+
});
|
|
249593
|
+
}
|
|
249564
249594
|
return { text, spec };
|
|
249565
249595
|
}
|
|
249566
249596
|
// src/cli/commands/api/shared.ts
|
|
@@ -249604,21 +249634,30 @@ function isPipedStdin() {
|
|
|
249604
249634
|
return false;
|
|
249605
249635
|
}
|
|
249606
249636
|
}
|
|
249607
|
-
async function readRequestBody(
|
|
249637
|
+
async function readRequestBody(flag, log) {
|
|
249608
249638
|
if (flag === "@-") {
|
|
249609
249639
|
return readStdin("--body @-", { trim: false });
|
|
249610
249640
|
}
|
|
249611
249641
|
if (flag?.startsWith("@")) {
|
|
249612
249642
|
return readTextFile(flag.slice(1));
|
|
249613
249643
|
}
|
|
249614
|
-
if (flag
|
|
249615
|
-
|
|
249616
|
-
}
|
|
249617
|
-
if (method === "GET" || method === "HEAD" || !isPipedStdin()) {
|
|
249618
|
-
return;
|
|
249644
|
+
if (flag === undefined && isPipedStdin()) {
|
|
249645
|
+
log.warn("stdin is ignored; pass --body @- to send it as the body.");
|
|
249619
249646
|
}
|
|
249620
|
-
|
|
249621
|
-
|
|
249647
|
+
return flag;
|
|
249648
|
+
}
|
|
249649
|
+
function withoutQuery(path) {
|
|
249650
|
+
return path.split("?", 1)[0] ?? "";
|
|
249651
|
+
}
|
|
249652
|
+
function reportedFetchCommand(method, path, options) {
|
|
249653
|
+
return {
|
|
249654
|
+
name: "api fetch",
|
|
249655
|
+
args: [method, withoutQuery(path)],
|
|
249656
|
+
options: {
|
|
249657
|
+
...options,
|
|
249658
|
+
...options.body === undefined ? {} : { body: "[not reported]" }
|
|
249659
|
+
}
|
|
249660
|
+
};
|
|
249622
249661
|
}
|
|
249623
249662
|
|
|
249624
249663
|
// src/cli/commands/api/catalog.ts
|
|
@@ -249640,15 +249679,15 @@ function getApiCatalogCommand() {
|
|
|
249640
249679
|
}
|
|
249641
249680
|
|
|
249642
249681
|
// src/cli/commands/api/fetch.ts
|
|
249643
|
-
async function findOperation(ctx, method, path, refresh) {
|
|
249682
|
+
async function findOperation(ctx, method, path, { refresh, flag }) {
|
|
249644
249683
|
const { spec } = await loadSpecTask(ctx, refresh);
|
|
249645
249684
|
const op = matchOperation(listOperations(spec), method, path);
|
|
249646
249685
|
if (!op) {
|
|
249647
|
-
throw new InvalidInputError(`No operation in the API spec matches ${method} ${path}.`, {
|
|
249686
|
+
throw new InvalidInputError(`No operation in the API spec matches ${method} ${withoutQuery(path)}.`, {
|
|
249648
249687
|
hints: [
|
|
249649
249688
|
{
|
|
249650
249689
|
message: "The cached spec may predate this route; fetch it again",
|
|
249651
|
-
command:
|
|
249690
|
+
command: `base44 api fetch ${method} ${path} ${flag} --refresh`
|
|
249652
249691
|
},
|
|
249653
249692
|
{
|
|
249654
249693
|
message: "Find the operation and its path template",
|
|
@@ -249659,6 +249698,8 @@ async function findOperation(ctx, method, path, refresh) {
|
|
|
249659
249698
|
}
|
|
249660
249699
|
return { spec, op };
|
|
249661
249700
|
}
|
|
249701
|
+
var CONTRACT_HELP = `
|
|
249702
|
+
The contract is JSON; cut it down with e.g. | jq '.parameters, .requestBodySchema'`;
|
|
249662
249703
|
var TEXT_CONTENT_TYPES = [
|
|
249663
249704
|
"json",
|
|
249664
249705
|
"text/",
|
|
@@ -249698,33 +249739,36 @@ async function formatResponse({ status, contentType, body }, output, jsonMode) {
|
|
|
249698
249739
|
}
|
|
249699
249740
|
}
|
|
249700
249741
|
async function fetchAction(ctx, methodArg, path, options, command) {
|
|
249742
|
+
ctx.errorReporter.setContext({
|
|
249743
|
+
command: reportedFetchCommand(methodArg ?? "", path ?? "", { ...options })
|
|
249744
|
+
});
|
|
249701
249745
|
if (!methodArg || !path) {
|
|
249702
249746
|
if (options.help) {
|
|
249703
|
-
const usage = command.helpInformation()
|
|
249747
|
+
const usage = `${command.helpInformation()}${CONTRACT_HELP}
|
|
249748
|
+
`;
|
|
249704
249749
|
return { stdout: ctx.jsonMode ? formatJson({ usage }) : usage };
|
|
249705
249750
|
}
|
|
249706
249751
|
throw new InvalidInputError("Provide a method and a path, e.g. GET /api/apps.");
|
|
249707
249752
|
}
|
|
249708
249753
|
const method = methodArg.toUpperCase();
|
|
249709
249754
|
if (options.help) {
|
|
249710
|
-
const { spec, op } = await findOperation(ctx, method, path,
|
|
249755
|
+
const { spec, op } = await findOperation(ctx, method, path, {
|
|
249756
|
+
refresh: options.refresh,
|
|
249757
|
+
flag: "--help"
|
|
249758
|
+
});
|
|
249711
249759
|
return { stdout: formatJson(getOperationContract(spec, op)) };
|
|
249712
249760
|
}
|
|
249713
249761
|
if (options.readOnly) {
|
|
249714
|
-
const { op } = await findOperation(ctx, method, path,
|
|
249762
|
+
const { op } = await findOperation(ctx, method, path, {
|
|
249763
|
+
refresh: options.refresh,
|
|
249764
|
+
flag: "--read-only"
|
|
249765
|
+
});
|
|
249715
249766
|
if (!op.readOnly) {
|
|
249716
249767
|
throw new InvalidInputError(`Refused under --read-only: ${op.method} ${op.path} is not a read-only operation. Nothing was sent.`);
|
|
249717
249768
|
}
|
|
249718
249769
|
}
|
|
249719
|
-
ctx.errorReporter.setContext({
|
|
249720
|
-
command: {
|
|
249721
|
-
name: "api fetch",
|
|
249722
|
-
args: [method, path.split("?", 1)[0] ?? ""],
|
|
249723
|
-
options: { ...options, body: options.body && "[not reported]" }
|
|
249724
|
-
}
|
|
249725
|
-
});
|
|
249726
249770
|
await ensureAuth(ctx);
|
|
249727
|
-
const body = await readRequestBody(
|
|
249771
|
+
const body = await readRequestBody(options.body, ctx.log);
|
|
249728
249772
|
const response = await ctx.runTask(`Calling ${method} ${path}`, () => sendApiRequest(method, path, body), {
|
|
249729
249773
|
successMessage: `Called ${method} ${path}`,
|
|
249730
249774
|
errorMessage: "Request failed"
|
|
@@ -249737,7 +249781,7 @@ function getApiFetchCommand() {
|
|
|
249737
249781
|
return new Base44Command("fetch", {
|
|
249738
249782
|
requireAuth: false,
|
|
249739
249783
|
requireAppContext: false
|
|
249740
|
-
}).description("Call a Base44 API operation
|
|
249784
|
+
}).description("Call a Base44 API operation; add --help after a path for its contract").helpOption(false).argument("[method]", "HTTP method, e.g. GET or POST").argument("[path]", 'Concrete path with any query string, e.g. "/api/apps/<app-id>/workflows/runs?status=failed"').option("--body <json>", "Request body: JSON, @file.json, or @- to read it from stdin").option("--output <file>", "Save the response body to a file").option("--read-only", "Refuse, before sending, any operation the spec does not mark read-only").option("--refresh", REFRESH_OPTION_HELP).option("-h, --help", "With a method and path, print that operation's contract; otherwise this help").addHelpText("after", CONTRACT_HELP).action(fetchAction);
|
|
249741
249785
|
}
|
|
249742
249786
|
|
|
249743
249787
|
// src/cli/commands/api/grep.ts
|
|
@@ -249759,11 +249803,9 @@ async function grepAction(ctx, pattern, options) {
|
|
|
249759
249803
|
if (options.readOnly) {
|
|
249760
249804
|
operations = operations.filter((op) => op.readOnly);
|
|
249761
249805
|
}
|
|
249762
|
-
const
|
|
249763
|
-
const hits = grepSpec(spec, operations, pattern, {
|
|
249806
|
+
const hits = grepOperations(spec, operations, pattern, {
|
|
249764
249807
|
ignoreCase: options.ignoreCase,
|
|
249765
|
-
limit
|
|
249766
|
-
schemas: !narrowed
|
|
249808
|
+
limit
|
|
249767
249809
|
});
|
|
249768
249810
|
return { stdout: formatJson(hits) };
|
|
249769
249811
|
}
|
|
@@ -249771,7 +249813,7 @@ function getApiGrepCommand() {
|
|
|
249771
249813
|
return new Base44Command("grep", {
|
|
249772
249814
|
requireAuth: false,
|
|
249773
249815
|
requireAppContext: false
|
|
249774
|
-
}).description("Search the
|
|
249816
|
+
}).description("Search the API spec with a regular expression, for when search misses").argument("<pattern>", 'Regular expression, e.g. "runs.*status"').option("--area <area>", "Search only one area's operations (see base44 api catalog)").option("-i, --ignore-case", "Case-insensitive match").option("--limit <n>", "Most operations to return (default 20)").option("--read-only", READ_ONLY_FILTER_HELP).option("--refresh", REFRESH_OPTION_HELP).action(grepAction);
|
|
249775
249817
|
}
|
|
249776
249818
|
|
|
249777
249819
|
// src/cli/commands/api/search.ts
|
|
@@ -262331,7 +262373,7 @@ var nativeEnumType = ZodNativeEnum.create;
|
|
|
262331
262373
|
var promiseType = ZodPromise.create;
|
|
262332
262374
|
var effectsType = ZodEffects.create;
|
|
262333
262375
|
var optionalType = ZodOptional2.create;
|
|
262334
|
-
var
|
|
262376
|
+
var nullableType2 = ZodNullable2.create;
|
|
262335
262377
|
var preprocessType = ZodEffects.createWithPreprocess;
|
|
262336
262378
|
var pipelineType = ZodPipeline.create;
|
|
262337
262379
|
// ../functions-compiler/src/contracts.ts
|
|
@@ -262361,7 +262403,7 @@ var bundleAppRequestSchema = objectType({
|
|
|
262361
262403
|
var ACTIVATION_MODE = "pull";
|
|
262362
262404
|
|
|
262363
262405
|
// ../functions-compiler/src/deno-bundle.ts
|
|
262364
|
-
import { mkdtemp, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
262406
|
+
import { mkdtemp, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
|
|
262365
262407
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
262366
262408
|
import path21 from "node:path";
|
|
262367
262409
|
|
|
@@ -262968,7 +263010,7 @@ async function bundleToModule(prepared, nodeModulesDir = "none") {
|
|
|
262968
263010
|
warnings: result.warnings.map((w) => w.text)
|
|
262969
263011
|
};
|
|
262970
263012
|
} finally {
|
|
262971
|
-
await
|
|
263013
|
+
await rm2(dir, { recursive: true, force: true });
|
|
262972
263014
|
}
|
|
262973
263015
|
}
|
|
262974
263016
|
function buildFailureErrors(e, dir) {
|
|
@@ -273333,4 +273375,4 @@ export {
|
|
|
273333
273375
|
runCLI
|
|
273334
273376
|
};
|
|
273335
273377
|
|
|
273336
|
-
//# debugId=
|
|
273378
|
+
//# debugId=A6B266663FAD34EF64756E2164756E21
|