@base44-preview/cli 0.1.32-pr.663.463d401 → 0.1.32-pr.663.60cadbf

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 CHANGED
@@ -45,8 +45,8 @@ The CLI will guide you through project setup. For step-by-step tutorials, see th
45
45
  | ------- | ----------- |
46
46
  | `api catalog [area]` | List the API's areas, or every operation in one area |
47
47
  | `api search <text>` | Search every public Base44 API operation by what it does |
48
- | `api grep <pattern>` | Search the raw API spec with a regular expression; `--area` narrows it to one area |
49
- | `api fetch <METHOD> <path>` | Call any public Base44 API operation, like curl; `--help` after a path prints its contract |
48
+ | `api grep <pattern>` | Search the API spec with a regular expression, for when search misses |
49
+ | `api fetch <METHOD> <path>` | Call any public Base44 API operation; `--help` after a path prints its contract |
50
50
  | [`create`](https://docs.base44.com/developers/references/cli/commands/create) | Create a new Base44 project from a template |
51
51
  | [`deploy`](https://docs.base44.com/developers/references/cli/commands/deploy) | Deploy all project resources and site to Base44 |
52
52
  | [`eject`](https://docs.base44.com/developers/references/cli/commands/eject) | Download the code for an existing Base44 project |
package/dist/cli/index.js CHANGED
@@ -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 = { path: 8, summary: 5, description: 2, parameters: 0.5 };
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 summaryCoverage(query, op) {
249130
- const terms = tokenize(query.toLowerCase());
249131
- if (!op || terms.length === 0) {
249132
- return 0;
249133
- }
249134
- const words = tokenize(op.summary.toLowerCase());
249135
- return terms.filter((term) => words.some((word) => word.startsWith(term))).length / terms.length;
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
- ...hit,
249146
- score: hit.score * (1 + summaryCoverage(query, operations[hit.id]))
249147
- })).sort((a, b) => b.score - a.score);
249148
- const baseline = (hits[0]?.score ?? 0) * MIN_RELATIVE_SCORE;
249149
- return hits.filter((hit) => hit.score >= baseline).slice(0, options.limit ?? 5).flatMap((hit) => {
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 readsFirst(ops) {
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: readsFirst(ops).slice(0, AREA_SAMPLE_MAX).map((op) => op.summary)
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",
@@ -249422,9 +249401,50 @@ function leftoverRefs(node, schemas, found = new Map) {
249422
249401
  }
249423
249402
  return found;
249424
249403
  }
249404
+ var SCHEMA_DATA_KEYS = new Set([
249405
+ "example",
249406
+ "examples",
249407
+ "default",
249408
+ "enum",
249409
+ "const"
249410
+ ]);
249411
+ var DOCS_CALLOUT = /<(Info|Note|Tip|Check|Warning)>([\s\S]*?)<\/\1>/g;
249412
+ var RELATIVE_LINK = /\[([^\]]+)\]\(\/[^)]*\)/g;
249413
+ function cleanText(text) {
249414
+ return text.replace(DOCS_CALLOUT, (_, kind, body) => kind === "Warning" ? `Warning: ${body}` : body).replace(RELATIVE_LINK, "$1");
249415
+ }
249416
+ function slimSchema(node, isPropertyMap = false) {
249417
+ if (Array.isArray(node)) {
249418
+ return node.map((item) => slimSchema(item));
249419
+ }
249420
+ if (node === null || typeof node !== "object") {
249421
+ return node;
249422
+ }
249423
+ const entries = Object.entries(node);
249424
+ if (isPropertyMap) {
249425
+ return Object.fromEntries(entries.map(([name, value]) => [name, slimSchema(value)]));
249426
+ }
249427
+ const slim = {};
249428
+ for (const [key, value] of entries) {
249429
+ if (key === "title" && typeof value === "string") {
249430
+ continue;
249431
+ }
249432
+ slim[key] = SCHEMA_DATA_KEYS.has(key) ? value : key === "properties" ? slimSchema(value, true) : key === "description" && typeof value === "string" ? cleanText(value) : slimSchema(value);
249433
+ }
249434
+ const { anyOf, ...rest } = slim;
249435
+ const nullable = Array.isArray(anyOf) && anyOf.length === 2 ? nullableType(anyOf) : undefined;
249436
+ return nullable ? { type: [nullable, "null"], ...rest } : slim;
249437
+ }
249438
+ function nullableType(variants) {
249439
+ const types = variants.map((variant) => variant !== null && typeof variant === "object" && Object.keys(variant).length === 1 && typeof variant.type === "string" ? variant.type : undefined);
249440
+ if (types.includes(undefined) || !types.includes("null")) {
249441
+ return;
249442
+ }
249443
+ return types.find((type) => type !== "null");
249444
+ }
249425
249445
  function getOperationContract(spec, op) {
249426
249446
  const schemas = spec.components?.schemas ?? {};
249427
- const inline = (node) => node === undefined ? null : inlineRefs(node, schemas);
249447
+ const inline = (node) => node === undefined ? null : slimSchema(inlineRefs(node, schemas));
249428
249448
  const responses = Object.entries(op.operation.responses ?? {}).flatMap(([status, response]) => {
249429
249449
  const parsed = ResponseObjectSchema.safeParse(response);
249430
249450
  return parsed.success ? [[status, parsed.data]] : [];
@@ -249437,7 +249457,7 @@ function getOperationContract(spec, op) {
249437
249457
  method: op.method,
249438
249458
  path: op.path,
249439
249459
  summary: op.summary,
249440
- description: op.description,
249460
+ description: cleanText(op.description),
249441
249461
  parameters: (op.operation.parameters ?? []).flatMap((parameter) => {
249442
249462
  const parsed = ParameterSchema.safeParse(parameter);
249443
249463
  if (!parsed.success) {
@@ -249451,7 +249471,7 @@ function getOperationContract(spec, op) {
249451
249471
  in: location2,
249452
249472
  required: required ?? false,
249453
249473
  schema: inline(schema ?? {}),
249454
- ...description && !inSchema ? { description } : {},
249474
+ ...description && !inSchema ? { description: cleanText(description) } : {},
249455
249475
  ..."example" in parsed.data ? { example: parsed.data.example } : {}
249456
249476
  }
249457
249477
  ];
@@ -249459,14 +249479,25 @@ function getOperationContract(spec, op) {
249459
249479
  ...requestBody.contentType && requestBody.contentType !== "application/json" ? { requestBodyContentType: requestBody.contentType } : {},
249460
249480
  requestBodySchema: inline(requestBody.schema),
249461
249481
  responseSchema: inline(success),
249462
- errors: Object.fromEntries(errors.map(([status, response]) => [status, response.description ?? ""]))
249482
+ errors: Object.fromEntries(errors.map(([status, response]) => [
249483
+ status,
249484
+ cleanText(response.description ?? "")
249485
+ ]))
249463
249486
  };
249464
249487
  const refs = leftoverRefs(contract, schemas);
249465
249488
  return {
249466
249489
  ...contract,
249467
- ...refs.size > 0 ? { refs: Object.fromEntries(refs) } : {}
249490
+ ...refs.size > 0 ? {
249491
+ refs: Object.fromEntries([...refs].map(([ref, schema]) => [ref, slimSchema(schema)]))
249492
+ } : {}
249468
249493
  };
249469
249494
  }
249495
+
249496
+ // src/core/api-spec/grep.ts
249497
+ function grepOperations(spec, operations, pattern, options = {}) {
249498
+ const regex = new RegExp(pattern, options.ignoreCase ? "i" : "");
249499
+ return operations.filter((op) => regex.test(JSON.stringify(getOperationContract(spec, op)))).slice(0, options.limit ?? 20).map(toOperationSummary);
249500
+ }
249470
249501
  // src/core/api-spec/request.ts
249471
249502
  var MAX_ERROR_BODY_CHARS = 4000;
249472
249503
  async function readBody(response) {
@@ -249493,7 +249524,8 @@ async function sendApiRequest(method, path, body) {
249493
249524
  } catch (error) {
249494
249525
  const apiError = await ApiError.fromHttpError(error, `calling ${method} ${path}`);
249495
249526
  const raw = error instanceof HTTPError ? await readBody(error.response) : undefined;
249496
- throw new ApiError(apiError.message, {
249527
+ const message = raw && apiError.statusCode !== undefined ? `Error calling ${method} ${path}: HTTP ${apiError.statusCode}` : apiError.message;
249528
+ throw new ApiError(message, {
249497
249529
  statusCode: apiError.statusCode,
249498
249530
  requestUrl: apiError.requestUrl,
249499
249531
  requestMethod: apiError.requestMethod,
@@ -249604,21 +249636,17 @@ function isPipedStdin() {
249604
249636
  return false;
249605
249637
  }
249606
249638
  }
249607
- async function readRequestBody(method, flag) {
249639
+ async function readRequestBody(flag, log) {
249608
249640
  if (flag === "@-") {
249609
249641
  return readStdin("--body @-", { trim: false });
249610
249642
  }
249611
249643
  if (flag?.startsWith("@")) {
249612
249644
  return readTextFile(flag.slice(1));
249613
249645
  }
249614
- if (flag !== undefined) {
249615
- return flag;
249646
+ if (flag === undefined && isPipedStdin()) {
249647
+ log.warn("stdin is ignored; pass --body @- to send it as the body.");
249616
249648
  }
249617
- if (method === "GET" || method === "HEAD" || !isPipedStdin()) {
249618
- return;
249619
- }
249620
- const piped = await readStdin("--body", { trim: false });
249621
- return piped.trim() ? piped : undefined;
249649
+ return flag;
249622
249650
  }
249623
249651
 
249624
249652
  // src/cli/commands/api/catalog.ts
@@ -249640,7 +249668,7 @@ function getApiCatalogCommand() {
249640
249668
  }
249641
249669
 
249642
249670
  // src/cli/commands/api/fetch.ts
249643
- async function findOperation(ctx, method, path, refresh) {
249671
+ async function findOperation(ctx, method, path, { refresh, flag }) {
249644
249672
  const { spec } = await loadSpecTask(ctx, refresh);
249645
249673
  const op = matchOperation(listOperations(spec), method, path);
249646
249674
  if (!op) {
@@ -249648,7 +249676,7 @@ async function findOperation(ctx, method, path, refresh) {
249648
249676
  hints: [
249649
249677
  {
249650
249678
  message: "The cached spec may predate this route; fetch it again",
249651
- command: "base44 api fetch <METHOD> <path> --help --refresh"
249679
+ command: `base44 api fetch ${method} ${path} ${flag} --refresh`
249652
249680
  },
249653
249681
  {
249654
249682
  message: "Find the operation and its path template",
@@ -249707,11 +249735,17 @@ async function fetchAction(ctx, methodArg, path, options, command) {
249707
249735
  }
249708
249736
  const method = methodArg.toUpperCase();
249709
249737
  if (options.help) {
249710
- const { spec, op } = await findOperation(ctx, method, path, options.refresh);
249738
+ const { spec, op } = await findOperation(ctx, method, path, {
249739
+ refresh: options.refresh,
249740
+ flag: "--help"
249741
+ });
249711
249742
  return { stdout: formatJson(getOperationContract(spec, op)) };
249712
249743
  }
249713
249744
  if (options.readOnly) {
249714
- const { op } = await findOperation(ctx, method, path, options.refresh);
249745
+ const { op } = await findOperation(ctx, method, path, {
249746
+ refresh: options.refresh,
249747
+ flag: "--read-only"
249748
+ });
249715
249749
  if (!op.readOnly) {
249716
249750
  throw new InvalidInputError(`Refused under --read-only: ${op.method} ${op.path} is not a read-only operation. Nothing was sent.`);
249717
249751
  }
@@ -249724,7 +249758,7 @@ async function fetchAction(ctx, methodArg, path, options, command) {
249724
249758
  }
249725
249759
  });
249726
249760
  await ensureAuth(ctx);
249727
- const body = await readRequestBody(method, options.body);
249761
+ const body = await readRequestBody(options.body, ctx.log);
249728
249762
  const response = await ctx.runTask(`Calling ${method} ${path}`, () => sendApiRequest(method, path, body), {
249729
249763
  successMessage: `Called ${method} ${path}`,
249730
249764
  errorMessage: "Request failed"
@@ -249737,7 +249771,7 @@ function getApiFetchCommand() {
249737
249771
  return new Base44Command("fetch", {
249738
249772
  requireAuth: false,
249739
249773
  requireAppContext: false
249740
- }).description("Call a Base44 API operation, like curl; 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 @- for stdin (piped stdin is read too)").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").action(fetchAction);
249774
+ }).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").action(fetchAction);
249741
249775
  }
249742
249776
 
249743
249777
  // src/cli/commands/api/grep.ts
@@ -249759,11 +249793,9 @@ async function grepAction(ctx, pattern, options) {
249759
249793
  if (options.readOnly) {
249760
249794
  operations = operations.filter((op) => op.readOnly);
249761
249795
  }
249762
- const narrowed = options.area !== undefined || options.readOnly === true;
249763
- const hits = grepSpec(spec, operations, pattern, {
249796
+ const hits = grepOperations(spec, operations, pattern, {
249764
249797
  ignoreCase: options.ignoreCase,
249765
- limit,
249766
- schemas: !narrowed
249798
+ limit
249767
249799
  });
249768
249800
  return { stdout: formatJson(hits) };
249769
249801
  }
@@ -249771,7 +249803,7 @@ function getApiGrepCommand() {
249771
249803
  return new Base44Command("grep", {
249772
249804
  requireAuth: false,
249773
249805
  requireAppContext: false
249774
- }).description("Search the raw 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 or schemas to return (default 20)").option("--read-only", READ_ONLY_FILTER_HELP).option("--refresh", REFRESH_OPTION_HELP).action(grepAction);
249806
+ }).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
249807
  }
249776
249808
 
249777
249809
  // src/cli/commands/api/search.ts
@@ -262331,7 +262363,7 @@ var nativeEnumType = ZodNativeEnum.create;
262331
262363
  var promiseType = ZodPromise.create;
262332
262364
  var effectsType = ZodEffects.create;
262333
262365
  var optionalType = ZodOptional2.create;
262334
- var nullableType = ZodNullable2.create;
262366
+ var nullableType2 = ZodNullable2.create;
262335
262367
  var preprocessType = ZodEffects.createWithPreprocess;
262336
262368
  var pipelineType = ZodPipeline.create;
262337
262369
  // ../functions-compiler/src/contracts.ts
@@ -273333,4 +273365,4 @@ export {
273333
273365
  runCLI
273334
273366
  };
273335
273367
 
273336
- //# debugId=CD2605865A84BE8564756E2164756E21
273368
+ //# debugId=34B2FE9173AAC44664756E2164756E21