@xanots/sdk 0.0.9 → 0.0.11

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.
Files changed (116) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +66 -21
  3. package/dist/.build-fingerprint +1 -1
  4. package/dist/{agent-file-refresh-4W37DGXS.js → agent-file-refresh-QNKN5RYD.js} +3 -3
  5. package/dist/bin.js +10 -8
  6. package/dist/{branch-commands-PBQ36L4A.js → branch-commands-2BLOC2GR.js} +13 -11
  7. package/dist/bundle.d.ts +218 -0
  8. package/dist/bundle.js +143 -0
  9. package/dist/{capture-7PO6SGB4.js → capture-4WVJY4DQ.js} +2 -2
  10. package/dist/{chunk-OW2QZEWL.js → chunk-22TKBSDV.js} +2 -2
  11. package/dist/{chunk-ZOYMZZ3S.js → chunk-3INK4Y4E.js} +1 -1
  12. package/dist/{chunk-NDZFBZHC.js → chunk-3UABJA4X.js} +1 -1
  13. package/dist/{chunk-6Z5CNWFC.js → chunk-4IF54NU5.js} +37 -6
  14. package/dist/{chunk-KSV7VOEX.js → chunk-4Q7ZOHH7.js} +3 -3
  15. package/dist/{chunk-QTNO2WD6.js → chunk-7ZYW652H.js} +1 -1
  16. package/dist/{chunk-4PTSTDIG.js → chunk-AIZKXUNP.js} +2 -2
  17. package/dist/{chunk-P5C2YKAM.js → chunk-ANUDXFEX.js} +18 -27
  18. package/dist/{chunk-4BXJGVZ3.js → chunk-BC2C5GVI.js} +2 -69
  19. package/dist/chunk-BSK7ELHU.js +70 -0
  20. package/dist/chunk-CTD5ZCV6.js +28 -0
  21. package/dist/{chunk-5HCDZ2XN.js → chunk-DBFU47BJ.js} +2 -2
  22. package/dist/{chunk-OKNSR7MT.js → chunk-DIA7CT7J.js} +129 -150
  23. package/dist/chunk-EHP3WPEG.js +21 -0
  24. package/dist/{chunk-JQLR64UC.js → chunk-F6CYJ7TN.js} +21 -6
  25. package/dist/{chunk-BKDJN76G.js → chunk-FE5I6S6N.js} +1 -1
  26. package/dist/{chunk-5YQOIFT4.js → chunk-G4EJMQLD.js} +2 -2
  27. package/dist/{chunk-L6TPHWAU.js → chunk-HYBN4H3F.js} +60 -86
  28. package/dist/{chunk-QIWBCS7N.js → chunk-JGCWTCA7.js} +2 -2
  29. package/dist/{chunk-MDXR5E5Q.js → chunk-K5IOND4K.js} +2 -2
  30. package/dist/{chunk-4PE4ZAB7.js → chunk-KA6G2L7U.js} +5 -5
  31. package/dist/chunk-OHX6MIUZ.js +184 -0
  32. package/dist/{chunk-UDL46O35.js → chunk-OWGCOGKK.js} +155 -3
  33. package/dist/{chunk-QONOJO45.js → chunk-QK7ZQJLP.js} +140 -20
  34. package/dist/{chunk-3QW5NFZJ.js → chunk-QKM4U5UK.js} +3 -3
  35. package/dist/{chunk-7OXFMCTX.js → chunk-QYMAZRAU.js} +7 -7
  36. package/dist/{chunk-K3YSQDXJ.js → chunk-RCT7UX7B.js} +92 -75
  37. package/dist/{chunk-T4XPCJRF.js → chunk-TCFIPDB3.js} +1 -1
  38. package/dist/{chunk-ZZLPTHT5.js → chunk-UOZMSF4C.js} +15 -8
  39. package/dist/{chunk-7JDT4PBU.js → chunk-VAF6A3YD.js} +5 -179
  40. package/dist/{chunk-6DHBYBTO.js → chunk-VNQM3V2C.js} +1 -2
  41. package/dist/chunk-WGPXT2G2.js +22 -0
  42. package/dist/{chunk-6AAT2AYQ.js → chunk-WP4OZZV4.js} +2 -2
  43. package/dist/{chunk-OYMR5AMJ.js → chunk-XEOX6AM7.js} +2 -2
  44. package/dist/{chunk-MU3O43L2.js → chunk-YBC3IKMF.js} +2 -2
  45. package/dist/chunk-ZQ2PKR6R.js +40 -0
  46. package/dist/cli.d.ts +57 -31
  47. package/dist/cli.js +9 -7
  48. package/dist/codegen-command-FUT2KJB6.js +49 -0
  49. package/dist/codegen.d.ts +2 -1
  50. package/dist/{completion-A6BZ3XGU.js → completion-WF46272M.js} +2 -2
  51. package/dist/{config-NL33PN4D.js → config-476F3PT5.js} +1 -1
  52. package/dist/{deploy-command-5TTI4TUP.js → deploy-command-IP7V7GT4.js} +69 -100
  53. package/dist/{ephemeral-command-7TK52YQM.js → ephemeral-command-U4AQ3TXX.js} +25 -28
  54. package/dist/index.d.ts +6 -4
  55. package/dist/index.js +10 -9
  56. package/dist/init-command-NPVL32L6.js +34 -0
  57. package/dist/{onboard-command-EHOHKQQU.js → init-web-3JNFG6GI.js} +10 -10
  58. package/dist/internal.d.ts +4 -4
  59. package/dist/internal.js +86 -73
  60. package/dist/io-P2H75UV2.js +12 -0
  61. package/dist/{live-diff-QK4KC2FJ.js → live-diff-IXKBVG4K.js} +3 -3
  62. package/dist/{lock-GFXD6G2E.js → lock-46FWYE4D.js} +3 -2
  63. package/dist/{lock-commands-ET7NIOLH.js → lock-commands-ZZKZ4LZJ.js} +23 -21
  64. package/dist/{login-command-DFCURZLC.js → login-command-Z6CHTA57.js} +7 -7
  65. package/dist/{logout-command-WXVZQCAV.js → logout-command-ER6IKAYJ.js} +2 -2
  66. package/dist/{loop-7SAIGRCZ.js → loop-D5NPL4VH.js} +3 -3
  67. package/dist/{marketplace-command-BCOAAN2I.js → marketplace-command-P4IPLJ6J.js} +6 -6
  68. package/dist/{meta-client-57ZWVHST.js → meta-client-K2J4XH64.js} +6 -6
  69. package/dist/node.d.ts +5 -4
  70. package/dist/node.js +15 -13
  71. package/dist/{validate-command-SK5FPCV7.js → preflight-command-K346GPTY.js} +20 -18
  72. package/dist/{profile-command-QJAAUZIV.js → profile-command-LJSBDV2L.js} +5 -5
  73. package/dist/{release-command-4EXVLYV2.js → release-command-IMNTIVWK.js} +42 -38
  74. package/dist/response-BQVQ24l1.d.ts +844 -0
  75. package/dist/{routes-manifest-SP3ZXLMR.js → routes-manifest-PWZHDOI5.js} +2 -2
  76. package/dist/scaffold.js +2 -2
  77. package/dist/{static-host-D6KS7X45.js → static-host-3WMV7IZO.js} +1 -1
  78. package/dist/status-command-AL47VG7H.js +162 -0
  79. package/dist/{store-CUCBSYLj.d.ts → store-BLyNeQ8S.d.ts} +21 -8
  80. package/dist/{test-command-2F5LKMI6.js → test-command-YAZLKLGQ.js} +45 -28
  81. package/dist/{upgrade-command-QL523I62.js → upgrade-command-BN3EHAOI.js} +16 -14
  82. package/dist/{workspace-K72NP7SX.js → workspace-2COHDBM3.js} +1 -1
  83. package/dist/{workspace-command-HYA6JEKK.js → workspace-command-MNK7Y7MQ.js} +36 -34
  84. package/dist/{workspace-export-AJMGN3CQ.js → workspace-export-DURY5WYL.js} +2 -2
  85. package/dist/{response-CVAE2kMj.d.ts → xdo-BjJj5W_E.d.ts} +1 -837
  86. package/guides/README.md +2 -2
  87. package/guides/cli.md +17 -19
  88. package/guides/codegen.md +21 -5
  89. package/guides/coverage.md +1 -1
  90. package/guides/deploying.md +31 -34
  91. package/guides/environment.md +4 -4
  92. package/guides/object-kinds.md +3 -3
  93. package/guides/project-structure.md +1 -1
  94. package/guides/scaffold.md +25 -2
  95. package/guides/typed-frontend.md +2 -2
  96. package/llms/filters.md +11 -10
  97. package/llms/kinds-agent-mcp.md +1 -1
  98. package/llms/kinds-core.md +2 -2
  99. package/llms/kinds-realtime.md +1 -1
  100. package/llms/lock.md +5 -5
  101. package/llms/statements-data.md +3 -1
  102. package/llms/tests.md +1 -1
  103. package/llms/values.md +1 -1
  104. package/llms-full.txt +65 -63
  105. package/llms.txt +40 -41
  106. package/manifest.json +96 -427
  107. package/package.json +7 -2
  108. package/dist/chunk-3EYUR3TX.js +0 -100
  109. package/dist/chunk-JQJPFUZI.js +0 -118
  110. package/dist/chunk-YNZFIY4J.js +0 -78
  111. package/dist/codegen-command-YSCSCVT5.js +0 -43
  112. package/dist/env-target-4T7AT347.js +0 -16
  113. package/dist/init-command-OVFFW4QS.js +0 -30
  114. package/dist/io-M7XZEMK7.js +0 -11
  115. package/dist/sandbox-details-command-EDO56IY3.js +0 -18
  116. package/dist/sandbox-export-command-MO6DEZ7Z.js +0 -24
@@ -10,9 +10,10 @@ import {
10
10
  isQueryExpressionFilter,
11
11
  isSeedFileSource,
12
12
  middlewareEntryGuid,
13
+ reversedRegexOperands,
13
14
  stackReferencesAuth,
14
15
  tableColumns
15
- } from "./chunk-QONOJO45.js";
16
+ } from "./chunk-QK7ZQJLP.js";
16
17
  import {
17
18
  CANONICAL_PAYLOAD_KEYS,
18
19
  REFERENCEABLE_KINDS,
@@ -25,7 +26,7 @@ import {
25
26
  mintCanonical,
26
27
  recordObserved,
27
28
  resolveRef
28
- } from "./chunk-7JDT4PBU.js";
29
+ } from "./chunk-VAF6A3YD.js";
29
30
 
30
31
  // src/workspace/seed-coerce.ts
31
32
  function coerceScalarValue(label, column, type, value, values) {
@@ -295,6 +296,91 @@ function checkInternalColumnReads(statements, owner, tablesByGuid, bag) {
295
296
  );
296
297
  }
297
298
  }
299
+ var DB_GET_BY_ID = "mvp:dbo_get";
300
+ var ROW_BINDING_STATEMENTS = /* @__PURE__ */ new Set([DB_GET, DB_GET_BY_ID]);
301
+ var INT_COLUMN_TYPES = /* @__PURE__ */ new Set(["int"]);
302
+ function isZeroDefault(value) {
303
+ return value === 0 || value === "0";
304
+ }
305
+ function checkGetByIdZero(record, statements, owner, tablesByGuid, bag) {
306
+ const zeroDefaultInputs = /* @__PURE__ */ new Set();
307
+ if (Array.isArray(record.input)) {
308
+ for (const entry of record.input) {
309
+ const declared = entry;
310
+ if (typeof declared?.name === "string" && isZeroDefault(declared.default)) {
311
+ zeroDefaultInputs.add(declared.name);
312
+ }
313
+ }
314
+ }
315
+ const bindings = /* @__PURE__ */ new Map();
316
+ for (const statement of statements) {
317
+ if (!ROW_BINDING_STATEMENTS.has(statement.name)) continue;
318
+ const as = statement.as;
319
+ if (typeof as !== "string" || as === "") continue;
320
+ const guid = statementTableGuid(statement);
321
+ const def = guid === void 0 ? void 0 : tablesByGuid.get(guid);
322
+ if (def) bindings.set(as, def);
323
+ }
324
+ const tested = /* @__PURE__ */ new Set();
325
+ for (const statement of statements) {
326
+ walkNodes(statement, (node) => {
327
+ if (typeof node.operand === "string") tested.add(node.operand);
328
+ });
329
+ }
330
+ const reported = /* @__PURE__ */ new Set();
331
+ for (const statement of statements) {
332
+ if (statement.name !== DB_GET_BY_ID || !Array.isArray(statement.input)) continue;
333
+ for (const entry of statement.input) {
334
+ const cell = entry;
335
+ if (cell?.name !== "id") continue;
336
+ if (Array.isArray(cell.filters) && cell.filters.length > 0) continue;
337
+ const source = zeroIdSource(cell, zeroDefaultInputs, bindings);
338
+ if (!source) continue;
339
+ if (source.reference !== void 0 && tested.has(source.reference)) continue;
340
+ if (reported.has(source.key)) continue;
341
+ reported.add(source.key);
342
+ bag.warn(
343
+ "db.get-by-id-zero",
344
+ `${owner}: the \`id\` of \`s.db.get_by_id\` ${source.because}, and the engine validates that key as \`>= 1\` \u2014 a \`0\` does not miss, it fails the whole request with HTTP 400 \`Value is less than the minimum value of 1\` naming a \`param\` the caller never sent. Inside a \`foreach\` that 400 ends the request, so one unset key loses every other row's work. Read a nullable foreign key with the field-match form, which binds \`null\` on \`0\` instead: \`s.db.get({ table, fieldName: "id", fieldValue: ${source.operand}, as })\`.`
345
+ );
346
+ }
347
+ }
348
+ }
349
+ function zeroIdSource(cell, zeroDefaultInputs, bindings) {
350
+ const value = typeof cell.value === "string" ? cell.value : "";
351
+ if ((cell.tag === "const:int" || cell.tag === "const:decimal") && Number(value) === 0) {
352
+ return {
353
+ key: "literal:0",
354
+ because: "is the literal `c.int(0)`",
355
+ operand: "c.int(0)"
356
+ };
357
+ }
358
+ if (cell.tag === "input" && zeroDefaultInputs.has(inputBase(value))) {
359
+ return {
360
+ key: `input:${value}`,
361
+ reference: value,
362
+ because: `is \`inp("${value}")\`, whose declared input default is \`0\` \u2014 an omitted input stands the sentinel up with nobody having written it`,
363
+ operand: `inp("${value}")`
364
+ };
365
+ }
366
+ if (cell.tag === "var") {
367
+ const dot = value.indexOf(".");
368
+ if (dot > 0) {
369
+ const def = bindings.get(value.slice(0, dot));
370
+ const column = value.slice(dot + 1);
371
+ const col = def && tableColumns(def).find((candidate) => candidate.name === column);
372
+ if (col && INT_COLUMN_TYPES.has(col.type) && isZeroDefault(col.default)) {
373
+ return {
374
+ key: `var:${value}`,
375
+ reference: value,
376
+ because: `is \`ref("${value}")\`, and "${column}" on table "${def.name}" is declared \`default: 0\` \u2014 every row that never set the link carries the sentinel`,
377
+ operand: `ref("${value}")`
378
+ };
379
+ }
380
+ }
381
+ }
382
+ return null;
383
+ }
298
384
  function collectInputRefs(node, out) {
299
385
  walkNodes(node, (record) => {
300
386
  if (record.tag !== "input") return;
@@ -435,6 +521,7 @@ function checkStacks(tables, sections, bag) {
435
521
  }
436
522
  }
437
523
  checkInternalColumnReads(statements, owner, tablesByGuid, bag);
524
+ checkGetByIdZero(obj, statements, owner, tablesByGuid, bag);
438
525
  }
439
526
  }
440
527
  }
@@ -493,6 +580,28 @@ function checkInterpolatedValues(sections, bag) {
493
580
  }
494
581
  }
495
582
  }
583
+ function checkRegexOperandOrder(sections, bag) {
584
+ for (const [payloadKey, arr] of Object.entries(sections)) {
585
+ for (const obj of arr ?? []) {
586
+ if (!obj || typeof obj !== "object") continue;
587
+ const name = obj.name;
588
+ const seen = /* @__PURE__ */ new Set();
589
+ walkNodes(obj, (record) => {
590
+ if (typeof record.tag !== "string" || typeof record.value !== "string") return;
591
+ if (!Array.isArray(record.filters)) return;
592
+ const reversed = reversedRegexOperands(record);
593
+ if (!reversed) return;
594
+ seen.add(`\`${reversed.filter}\` (pattern ${JSON.stringify(reversed.subject)})`);
595
+ });
596
+ if (seen.size === 0) continue;
597
+ const owner = `${payloadKey} "${typeof name === "string" ? name : "?"}"`;
598
+ bag.warn(
599
+ "value.regex-operands-reversed",
600
+ `${owner} pipes a regex filter's SUBJECT and passes its PATTERN as the argument: ${[...seen].join("; ")}. The regex family is pattern-piped \u2014 the piped value is the PATTERN and the argument is the text tested against it, the reverse of every other filter \u2014 so this answers false for every input with HTTP 200 and no error, and a precondition built on it lets through the values it exists to refuse. Swap the operands: \`withFilters(c.regex(\u2026), fl.regex_test(subject))\`.`
601
+ );
602
+ }
603
+ }
604
+ }
496
605
  function checkSeed(tables, bag) {
497
606
  for (const def of tables) {
498
607
  const source = def.seed;
@@ -506,6 +615,18 @@ function checkSeed(tables, bag) {
506
615
  }
507
616
  }
508
617
  }
618
+ var RESERVED_COLUMN_NAMES = /* @__PURE__ */ new Set(["run"]);
619
+ function checkReservedColumnNames(tables, bag) {
620
+ for (const def of tables) {
621
+ for (const col of tableColumns(def)) {
622
+ if (!RESERVED_COLUMN_NAMES.has(col.name)) continue;
623
+ bag.warn(
624
+ "table.reserved-column-name",
625
+ `table "${def.name}": the column name \`${col.name}\` is reserved by the engine \u2014 it is the key a block statement stores its sub-stack under, and an insert's parameter map collides with it. The table deploys and reads back correctly, and then EVERY \`s.db.add\` into it fails with HTTP 400 naming \`${col.name}\` and complaining about the value \u2014 at every column type, and whether the statement supplies a value or leaves the default to stand in. Rename the column (\`${col.name}_id\`, \`${col.name}s\`); the match is exact and case sensitive, so nothing else is affected.`
626
+ );
627
+ }
628
+ }
629
+ }
509
630
  var GATING_ACTIONS = {
510
631
  realtime_server: ["connect"],
511
632
  channel: ["join"]
@@ -728,6 +849,34 @@ function checkNullMatchArgs(sections, bag) {
728
849
  }
729
850
  }
730
851
  }
852
+ var URL_ONLY_VERBS = /* @__PURE__ */ new Set(["GET", "DELETE", "HEAD"]);
853
+ function checkPathSegmentCandidates(sections, bag) {
854
+ for (const obj of sections["query"] ?? []) {
855
+ if (!obj || typeof obj !== "object") continue;
856
+ const query = obj;
857
+ const name = typeof query.name === "string" ? query.name : "";
858
+ const verb = typeof query.verb === "string" ? query.verb : "";
859
+ if (!URL_ONLY_VERBS.has(verb)) continue;
860
+ const statements = [];
861
+ collectStatements(obj, statements);
862
+ const addressing = /* @__PURE__ */ new Set();
863
+ for (const statement of statements) {
864
+ const matchArg = DB_MATCH_ARG[statement.name];
865
+ if (matchArg === void 0) continue;
866
+ const cell = statementInput(statement, matchArg);
867
+ if (cell?.tag !== "input") continue;
868
+ if (typeof cell?.value !== "string" || cell.value === "") continue;
869
+ if (name.includes(`{${cell.value}}`)) continue;
870
+ addressing.add(cell.value);
871
+ }
872
+ for (const param of addressing) {
873
+ bag.warn(
874
+ "query.path-segment-candidate",
875
+ `query "${name}" (${verb}) looks up one row by the \`${param}\` input, but the path declares no \`{${param}}\` segment \u2014 so the value arrives as \`?${param}=\u2026\` instead of addressing the resource. The endpoint works, but the route is not addressable the way a REST client expects, and \`getPath()\` types as static, so a caller cannot pass the value positionally. Put it in the path: \`name: "${name}/{${param}}"\` (the segment may sit anywhere \u2014 \`"${name}/{${param}}/edit"\` routes too), keeping the \`${param}\` input as it is; the segment binds to the input of the same name. Leave it as-is if \`${param}\` really is a query-string param rather than part of the address.`
876
+ );
877
+ }
878
+ }
879
+ }
731
880
  function checkSameNameSiblings(sections, bag) {
732
881
  const appNames = appNamesByGuid(sections["app"]);
733
882
  for (const [payloadKey, arr] of Object.entries(sections)) {
@@ -1457,6 +1606,7 @@ var Xano = class {
1457
1606
  checkStacks(this.tableDefs, sections, bag);
1458
1607
  checkExpressionOperands(sections, bag);
1459
1608
  checkInterpolatedValues(sections, bag);
1609
+ checkRegexOperandOrder(sections, bag);
1460
1610
  checkReferences(this.bundleType, sections, this.workspaceConfig.guid, bag);
1461
1611
  checkDecodeOnlyStatements(sections, bag);
1462
1612
  checkRunFamilyHosts(sections, bag);
@@ -1469,8 +1619,10 @@ var Xano = class {
1469
1619
  checkUnboundVarRefs(sections, bag);
1470
1620
  checkSafeRefMatchArgs(sections, bag);
1471
1621
  checkNullMatchArgs(sections, bag);
1622
+ checkPathSegmentCandidates(sections, bag);
1472
1623
  checkSameNameSiblings(sections, bag);
1473
1624
  checkSeed(this.tableDefs, bag);
1625
+ checkReservedColumnNames(this.tableDefs, bag);
1474
1626
  checkKnowledge(sections, bag, { resolved: options.knowledge !== void 0 });
1475
1627
  checkRealtimePublish(this.bundleType, sections, bag);
1476
1628
  bag.flush();
@@ -1706,4 +1858,4 @@ export {
1706
1858
  Xano,
1707
1859
  workspace
1708
1860
  };
1709
- //# sourceMappingURL=chunk-UDL46O35.js.map
1861
+ //# sourceMappingURL=chunk-OWGCOGKK.js.map
@@ -3,6 +3,16 @@ import {
3
3
  fillPathParams,
4
4
  parsePathParams
5
5
  } from "./chunk-WHOJWOSV.js";
6
+ import {
7
+ appNamesByGuid,
8
+ deriveGuid,
9
+ deriveQueryGuid,
10
+ getLockedCanonical,
11
+ lockKey,
12
+ lockNameForObject,
13
+ queryGroupComponent,
14
+ resolveRef
15
+ } from "./chunk-VAF6A3YD.js";
6
16
  import {
7
17
  COLUMN_CONTEXT,
8
18
  INPUT_CONTEXT,
@@ -14,16 +24,8 @@ import {
14
24
  registerStatement
15
25
  } from "./chunk-5XZ744TS.js";
16
26
  import {
17
- appNamesByGuid,
18
- deriveGuid,
19
- deriveQueryGuid,
20
- getLockedCanonical,
21
- lockKey,
22
- lockNameForObject,
23
- queryGroupComponent,
24
- resolveRef,
25
27
  sha1Bytes
26
- } from "./chunk-7JDT4PBU.js";
28
+ } from "./chunk-OHX6MIUZ.js";
27
29
 
28
30
  // src/types/xdo.ts
29
31
  var TAGS = [
@@ -287,15 +289,41 @@ function barePatternRefusal(value) {
287
289
  if (isValidPcreLiteral(value.value)) return null;
288
290
  return `${JSON.stringify(value.value)} is a BARE regex pattern. PHP \`preg_*\` reads the first character as the delimiter, so the engine matches nothing for every input \u2014 the assertion or precondition built on it fails (or passes) against text that plainly should not. Build it with c.regex(${JSON.stringify(value.value)}) instead of c.text(...), which wraps and escapes it into a valid PCRE literal`;
289
291
  }
290
- var REGEX_PATTERN_FILTERS = /* @__PURE__ */ new Set([
291
- "regex_test",
292
- "regex_match",
293
- "regex_match_all",
294
- "regex_matches",
295
- "regex_replace",
296
- "regex_get_all_matches",
297
- "regex_get_first_match"
298
- ]);
292
+ var REGEX_SUBJECT_SLOT = {
293
+ regex_test: 0,
294
+ regex_match: 0,
295
+ regex_match_all: 0,
296
+ regex_matches: 0,
297
+ regex_replace: 1,
298
+ regex_get_all_matches: 0,
299
+ regex_get_first_match: 0
300
+ };
301
+ var REGEX_PATTERN_FILTERS = new Set(Object.keys(REGEX_SUBJECT_SLOT));
302
+ var REGEX_METACHARACTERS = /[\\^$.|?*+()[\]{}]/;
303
+ function readablePattern(value) {
304
+ if (!value || value.tag !== "const") return null;
305
+ if (Array.isArray(value.filters) && value.filters.length > 0) return null;
306
+ return isValidPcreLiteral(value.value) ? value.value : null;
307
+ }
308
+ function reversedOperandRefusal(pattern, subject) {
309
+ const misplaced = readablePattern(subject);
310
+ if (misplaced === null || !REGEX_METACHARACTERS.test(misplaced)) return null;
311
+ if (readablePattern(pattern) !== null) return null;
312
+ return `the OPERANDS are reversed. ${JSON.stringify(misplaced)} is a delimiter-wrapped regex pattern sitting in the SUBJECT slot, which means the pattern and the text it tests were written the other way round. The regex family is pattern-piped \u2014 the piped value is the PATTERN and the argument is the text matched against it, the reverse of every other filter \u2014 so this runs the subject as a pattern and answers false for every input, with HTTP 200 and no error. Swap them: pipe the c.regex(...) pattern and pass the subject as the argument`;
313
+ }
314
+ function reversedRegexOperands(v2) {
315
+ const chain = Array.isArray(v2.filters) ? v2.filters : [];
316
+ for (const [i, applied] of chain.entries()) {
317
+ const slot = REGEX_SUBJECT_SLOT[applied.name];
318
+ if (slot === void 0) continue;
319
+ const pattern = { value: v2.value, tag: v2.tag, filters: chain.slice(0, i) };
320
+ const message = reversedOperandRefusal(pattern, applied.arg?.[slot]);
321
+ if (message !== null) {
322
+ return { filter: applied.name, slot, subject: applied.arg?.[slot]?.value ?? "", message };
323
+ }
324
+ }
325
+ return null;
326
+ }
299
327
  function intLiteral(n) {
300
328
  if (typeof n === "bigint") return String(n);
301
329
  if (typeof n === "string") {
@@ -665,6 +693,16 @@ function withFilters(value, ...filters) {
665
693
  `withFilters: argument ${malformed} of the filter chain is not a filter \u2014 got ${JSON.stringify(got) ?? String(got)}. Each entry must come from an \`fl.*\` factory (or \`filter(name, ...)\`), which returns \`{name, arg, disabled}\`. A tagged value is not a filter: to pipe one value through another, pass it as a filter ARGUMENT (\`fl.concat(other)\`), not as a chain member.`
666
694
  );
667
695
  }
696
+ const reversed = reversedRegexOperands({
697
+ value: value.value,
698
+ tag: value.tag,
699
+ filters: [...value.filters, ...added]
700
+ });
701
+ if (reversed) {
702
+ throw new Error(
703
+ `Regex filter \`${reversed.filter}\`: ${reversed.message} \u2014 \`withFilters(c.regex(\u2026), fl.${reversed.filter}(${reversed.slot === 0 ? "" : "\u2026, "}subject))\`. Naming the argument says which slot is which: \`fl.${reversed.filter}({ subject: \u2026 })\`. (issue #298)`
704
+ );
705
+ }
668
706
  const pipedIsBarePattern = barePatternRefusal(value) !== null;
669
707
  const offending = pipedIsBarePattern ? added.find((filter2) => REGEX_PATTERN_FILTERS.has(filter2.name)) : void 0;
670
708
  if (offending) {
@@ -1559,8 +1597,79 @@ function encodeInput(name, descriptor2) {
1559
1597
  // src/values/obj.ts
1560
1598
  var IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
1561
1599
  function serializeValue(v2, path) {
1600
+ const record = objSetRecord(v2, path);
1601
+ if (record) return record;
1562
1602
  return serializeAtom(v2, path) + serializeFilters(v2, path);
1563
1603
  }
1604
+ function objSetRecord(v2, path) {
1605
+ if (v2.tag !== "const:obj") return null;
1606
+ if (v2.value === "") {
1607
+ throw new Error(
1608
+ `obj(): \`${path}\` is \`c.obj(null)\`, the legacy BLANK object form \u2014 the engine evaluates it to null, not to {}. Write \`c.null()\` for the null, or \`c.obj()\` for an empty object.`
1609
+ );
1610
+ }
1611
+ if (v2.value !== "{}") {
1612
+ const parsed = parseJson(v2.value);
1613
+ if (parsed === NOT_JSON) return null;
1614
+ return serializeJson(parsed, path) + serializeFilters(v2, path);
1615
+ }
1616
+ const parts = [];
1617
+ const keys = /* @__PURE__ */ new Set();
1618
+ let i = 0;
1619
+ for (; i < v2.filters.length; i++) {
1620
+ const f2 = v2.filters[i];
1621
+ if (f2.name !== "set" || f2.disabled || f2.arg.length !== 2) break;
1622
+ const [pathArg, member] = f2.arg;
1623
+ if (pathArg.tag !== "const" || pathArg.filters.length > 0) break;
1624
+ const bracketed = pathArg.value.startsWith("[");
1625
+ const key = parseSetPath(pathArg.value);
1626
+ if (!IDENT.test(key)) {
1627
+ if (!bracketed) break;
1628
+ throw new Error(
1629
+ `obj(): key "${key}" inside the \`c.obj\` at \`${path}\` must be a bare identifier ([A-Za-z_][A-Za-z0-9_]*) \u2014 XanoScript object keys aren't quoted.`
1630
+ );
1631
+ }
1632
+ if (keys.has(key)) break;
1633
+ keys.add(key);
1634
+ parts.push(`${key}: ${serializeValue(member, `${path}.${key}`)}`);
1635
+ }
1636
+ const rendered = parts.length === 0 ? "{}" : `{ ${parts.join(", ")} }`;
1637
+ const rest = { ...v2, filters: v2.filters.slice(i) };
1638
+ return rendered + serializeFilters(rest, path);
1639
+ }
1640
+ function parseSetPath(stored) {
1641
+ const bracketed = /^\["(.*)"\]$/s.exec(stored);
1642
+ return bracketed ? bracketed[1].replace(/\\(["\\])/g, "$1") : stored;
1643
+ }
1644
+ var NOT_JSON = /* @__PURE__ */ Symbol("not-json");
1645
+ function parseJson(text) {
1646
+ try {
1647
+ return JSON.parse(text);
1648
+ } catch {
1649
+ return NOT_JSON;
1650
+ }
1651
+ }
1652
+ function serializeJson(value, path) {
1653
+ if (value === null) return "null";
1654
+ if (typeof value === "string") return JSON.stringify(value);
1655
+ if (typeof value === "boolean") return value ? "true" : "false";
1656
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : "null";
1657
+ if (Array.isArray(value)) {
1658
+ return `[${value.map((el, i) => serializeJson(el, `${path}[${i}]`)).join(", ")}]`;
1659
+ }
1660
+ if (typeof value === "object") {
1661
+ const parts = Object.entries(value).map(([key, member]) => {
1662
+ if (!IDENT.test(key)) {
1663
+ throw new Error(
1664
+ `obj(): key "${key}" at \`${path}\` must be a bare identifier ([A-Za-z_][A-Za-z0-9_]*) \u2014 XanoScript object keys aren't quoted.`
1665
+ );
1666
+ }
1667
+ return `${key}: ${serializeJson(member, `${path}.${key}`)}`;
1668
+ });
1669
+ return parts.length === 0 ? "{}" : `{ ${parts.join(", ")} }`;
1670
+ }
1671
+ return "null";
1672
+ }
1564
1673
  function serializeFilters(v2, path) {
1565
1674
  let out2 = "";
1566
1675
  for (const f2 of v2.filters) {
@@ -1614,9 +1723,18 @@ function serializeAtom(v2, path) {
1614
1723
  case "const:epochms":
1615
1724
  if (v2.value === "now") return "now";
1616
1725
  break;
1726
+ // `c.array([…])` stores plain JSON, and the literal grammar spells the same
1727
+ // list — so it renders to the identical bytes a bare `[…]` member does. The
1728
+ // bare form always worked and this one used to throw, which made the empty
1729
+ // list (`c.array([])`) an export failure with no named way through (#295).
1730
+ case "const:array": {
1731
+ const parsed = parseJson(v2.value);
1732
+ if (parsed !== NOT_JSON) return serializeJson(parsed, path);
1733
+ break;
1734
+ }
1617
1735
  }
1618
1736
  throw new Error(
1619
- `obj(): value tag "${v2.tag}" at \`${path}\` isn't supported in a dynamic object literal yet. Supported: inp(), ref(), auth(), col(), env()/setting()/sys.*, c.now(), and c.text/int/decimal/bool/null \u2014 each optionally carrying a filter chain.`
1737
+ `obj(): value tag "${v2.tag}" at \`${path}\` isn't supported in a dynamic object literal yet. Supported: inp(), ref(), auth(), col(), env()/setting()/sys.*, c.now(), c.text/int/decimal/bool/null, and c.obj()/c.array() \u2014 each optionally carrying a filter chain. A constant record or list can also be written bare: \`{ a: 1 }\`, \`[]\`.`
1620
1738
  );
1621
1739
  }
1622
1740
  function serializeMember(m, path) {
@@ -4006,6 +4124,8 @@ export {
4006
4124
  DiagnosticBag,
4007
4125
  isTaggedValue,
4008
4126
  barePatternRefusal,
4127
+ reversedOperandRefusal,
4128
+ reversedRegexOperands,
4009
4129
  c,
4010
4130
  ref,
4011
4131
  inp,
@@ -4117,4 +4237,4 @@ export {
4117
4237
  serializeBundle,
4118
4238
  emitBundle
4119
4239
  };
4120
- //# sourceMappingURL=chunk-QONOJO45.js.map
4240
+ //# sourceMappingURL=chunk-QK7ZQJLP.js.map
@@ -14,7 +14,7 @@ import {
14
14
  resolveOAuthErrorCode,
15
15
  resolveScope,
16
16
  writeCredential
17
- } from "./chunk-BKDJN76G.js";
17
+ } from "./chunk-FE5I6S6N.js";
18
18
  import {
19
19
  detail,
20
20
  hostLabel,
@@ -161,7 +161,7 @@ The refresh token may be expired or already spent \u2014 refresh tokens rotate o
161
161
  );
162
162
  }
163
163
  assertHttpsOrigin(instance2, "instance");
164
- const { resolveScopedWorkspaceId } = await import("./workspace-K72NP7SX.js");
164
+ const { resolveScopedWorkspaceId } = await import("./workspace-2COHDBM3.js");
165
165
  const workspaceId = await resolveScopedWorkspaceId({ access_token: set.access_token, instance: instance2 });
166
166
  return { access_token: set.access_token, instance: instance2, workspaceId, credentialType: "oauth" };
167
167
  }
@@ -272,4 +272,4 @@ export {
272
272
  envMetaCredentialVarsSet,
273
273
  getAccessToken
274
274
  };
275
- //# sourceMappingURL=chunk-3QW5NFZJ.js.map
275
+ //# sourceMappingURL=chunk-QKM4U5UK.js.map
@@ -6,7 +6,7 @@ import {
6
6
  realtimeChannelGuid,
7
7
  realtimeServerRefName,
8
8
  resolveRealtimeServerRef
9
- } from "./chunk-ZZLPTHT5.js";
9
+ } from "./chunk-UOZMSF4C.js";
10
10
  import {
11
11
  assertCanonical,
12
12
  assertOneOf,
@@ -25,17 +25,17 @@ import {
25
25
  resolveAuthRef,
26
26
  resolveMockKeys,
27
27
  warnLiveDatasource
28
- } from "./chunk-QONOJO45.js";
29
- import {
30
- encodeStatement
31
- } from "./chunk-5XZ744TS.js";
28
+ } from "./chunk-QK7ZQJLP.js";
32
29
  import {
33
30
  deriveGuid,
34
31
  getLockedCanonical,
35
32
  lockKey,
36
33
  realtimeMessageSeedName,
37
34
  resolveRef
38
- } from "./chunk-7JDT4PBU.js";
35
+ } from "./chunk-VAF6A3YD.js";
36
+ import {
37
+ encodeStatement
38
+ } from "./chunk-5XZ744TS.js";
39
39
 
40
40
  // src/kinds/canonical.ts
41
41
  function resolveCanonicalToken(label, payloadKey, accessor, def, override) {
@@ -667,4 +667,4 @@ export {
667
667
  addonKind,
668
668
  addon
669
669
  };
670
- //# sourceMappingURL=chunk-7OXFMCTX.js.map
670
+ //# sourceMappingURL=chunk-QYMAZRAU.js.map