@xanots/sdk 0.0.1

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 (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +384 -0
  3. package/dist/agent-file-refresh-7XCACU34.js +95 -0
  4. package/dist/bin.d.ts +1 -0
  5. package/dist/bin.js +184 -0
  6. package/dist/capture-HUV5BNTC.js +32 -0
  7. package/dist/chunk-26CNBZE2.js +963 -0
  8. package/dist/chunk-33ND6LKO.js +78 -0
  9. package/dist/chunk-3DUAGYGP.js +1550 -0
  10. package/dist/chunk-3IGNIP6R.js +89 -0
  11. package/dist/chunk-47WDWMBJ.js +14 -0
  12. package/dist/chunk-4BXJGVZ3.js +318 -0
  13. package/dist/chunk-4HT3BNZ7.js +675 -0
  14. package/dist/chunk-4YMD2OOZ.js +23 -0
  15. package/dist/chunk-5WGEURVI.js +156 -0
  16. package/dist/chunk-5YTBTF25.js +29 -0
  17. package/dist/chunk-6DHBYBTO.js +166 -0
  18. package/dist/chunk-76QBEIGO.js +66 -0
  19. package/dist/chunk-7DKX2SPN.js +100 -0
  20. package/dist/chunk-7REDODS2.js +468 -0
  21. package/dist/chunk-C56BC2FY.js +254 -0
  22. package/dist/chunk-DGSF2Q5H.js +60 -0
  23. package/dist/chunk-EMCAWMHC.js +3982 -0
  24. package/dist/chunk-EZG76F7R.js +159 -0
  25. package/dist/chunk-FJ6ZS5KB.js +3607 -0
  26. package/dist/chunk-GNPVYOPB.js +17 -0
  27. package/dist/chunk-HJPTWBLH.js +38 -0
  28. package/dist/chunk-IZW6MK3U.js +248 -0
  29. package/dist/chunk-LH6Z6KFV.js +247 -0
  30. package/dist/chunk-MZUI3JNX.js +93 -0
  31. package/dist/chunk-NDZFBZHC.js +167 -0
  32. package/dist/chunk-NOO35BQ2.js +37 -0
  33. package/dist/chunk-NUQCEOKA.js +13 -0
  34. package/dist/chunk-QTNO2WD6.js +56 -0
  35. package/dist/chunk-RVB7ITKN.js +49 -0
  36. package/dist/chunk-TRU5OHQ5.js +6904 -0
  37. package/dist/chunk-VKFQJEMW.js +814 -0
  38. package/dist/chunk-VTIL47DT.js +125 -0
  39. package/dist/chunk-WHOJWOSV.js +112 -0
  40. package/dist/chunk-WKP4D5MO.js +1692 -0
  41. package/dist/chunk-X4DVXBFY.js +38 -0
  42. package/dist/chunk-XQ22GLYS.js +118 -0
  43. package/dist/chunk-YDZYMZBE.js +670 -0
  44. package/dist/chunk-YGPIY3WT.js +1146 -0
  45. package/dist/chunk-YYRDLFSJ.js +602 -0
  46. package/dist/chunk-ZUTSMMAG.js +46 -0
  47. package/dist/cli.d.ts +331 -0
  48. package/dist/cli.js +33 -0
  49. package/dist/codegen-command-OOKK6AZK.js +40 -0
  50. package/dist/codegen.d.ts +114 -0
  51. package/dist/codegen.js +71 -0
  52. package/dist/completion-TIPPZN7H.js +298 -0
  53. package/dist/config-NL33PN4D.js +84 -0
  54. package/dist/deploy-command-4EQ7XX5G.js +451 -0
  55. package/dist/env-target-IFJ5QDHC.js +16 -0
  56. package/dist/ephemeral-command-3X3I4ULC.js +242 -0
  57. package/dist/index.d.ts +4477 -0
  58. package/dist/index.js +300 -0
  59. package/dist/init-command-R6H7ZXW5.js +27 -0
  60. package/dist/internal.d.ts +74 -0
  61. package/dist/internal.js +2065 -0
  62. package/dist/io-AMIKRLPC.js +11 -0
  63. package/dist/live-diff-Y3AKETHE.js +196 -0
  64. package/dist/lock-3CVKALKT.js +37 -0
  65. package/dist/lock-commands-XTR2YKLY.js +232 -0
  66. package/dist/login-command-ACJF6KWQ.js +167 -0
  67. package/dist/logout-command-MX3MJS5U.js +68 -0
  68. package/dist/loop-OM3P2Z6O.js +93 -0
  69. package/dist/marketplace-command-RATXTKXN.js +379 -0
  70. package/dist/meta-client-OW5WKWW7.js +170 -0
  71. package/dist/node.d.ts +59 -0
  72. package/dist/node.js +442 -0
  73. package/dist/profile-command-SWJ3SPKR.js +77 -0
  74. package/dist/release-command-VV5UVZKL.js +427 -0
  75. package/dist/response-CVAE2kMj.d.ts +1915 -0
  76. package/dist/routes-manifest-SP3ZXLMR.js +244 -0
  77. package/dist/runtime-V4C3AC3A.js +13 -0
  78. package/dist/sandbox-details-command-HJE5SPVG.js +18 -0
  79. package/dist/sandbox-export-command-QCJY4GMV.js +24 -0
  80. package/dist/static-host-D6KS7X45.js +138 -0
  81. package/dist/store-BQ97nKIF.d.ts +7760 -0
  82. package/dist/test-command-TSPBQHBM.js +383 -0
  83. package/dist/validate-command-4ERHJSCO.js +122 -0
  84. package/dist/verify-rollout-FAVQ6EJY.js +40 -0
  85. package/dist/workspace-K72NP7SX.js +49 -0
  86. package/dist/workspace-command-OF23DPNI.js +156 -0
  87. package/dist/workspace-export-AJMGN3CQ.js +10 -0
  88. package/llms/fields.md +104 -0
  89. package/llms/filters.md +183 -0
  90. package/llms/kinds-agent-mcp.md +11 -0
  91. package/llms/kinds-core.md +68 -0
  92. package/llms/kinds-realtime.md +76 -0
  93. package/llms/lambda.md +111 -0
  94. package/llms/legacy.md +43 -0
  95. package/llms/object-kinds.md +31 -0
  96. package/llms/statements-calls.md +23 -0
  97. package/llms/statements-catalog.md +309 -0
  98. package/llms/statements-data.md +58 -0
  99. package/llms/statements-runtime.md +48 -0
  100. package/llms/tests.md +58 -0
  101. package/llms/triggers.md +22 -0
  102. package/llms/values.md +29 -0
  103. package/llms-full.txt +1672 -0
  104. package/llms.txt +483 -0
  105. package/manifest.json +9592 -0
  106. package/package.json +110 -0
@@ -0,0 +1,963 @@
1
+ // src/validate/normalize.ts
2
+ var STRIP_KEYS = /* @__PURE__ */ new Set([
3
+ // server columns / persistence
4
+ "id",
5
+ "created_at",
6
+ "updated_at",
7
+ "deleted_at",
8
+ "guid",
9
+ "_draft",
10
+ // auto-generated xsids / runtime keys
11
+ "_xsid",
12
+ "@guid",
13
+ "@index",
14
+ "stack_id",
15
+ "index",
16
+ // deploy-target / market binding (deferred)
17
+ "workspace",
18
+ "branch",
19
+ "market_item",
20
+ // engine-stored source artifact (the raw XanoScript text), not authored data
21
+ "xanoscript",
22
+ // A workflow test's LAST RUN result — when it ran, how long it took, and the
23
+ // pass/fail of each statement. Instance state produced by executing the test,
24
+ // not workspace source, so the SDK neither authors nor emits it. A stored
25
+ // object always carries the key (`null` until the test has been run once), so
26
+ // without this the whole kind reads as a failed round trip.
27
+ "lastRun",
28
+ // storage-mode flag the golden table corpus predates (those fixtures were
29
+ // captured before `use_xdo` was serialized). The SDK always emits it; it
30
+ // doesn't change the authored schema, so drop it from both sides — same as
31
+ // the already-stripped `index`, whose gin entry `use_xdo` only gates.
32
+ "use_xdo",
33
+ // A dead key, dropped for the same reason as `iterator` (see
34
+ // {@link returnWithoutIterator}) and traced the same way.
35
+ //
36
+ // Xano's frontend writes `context: {dbo:{id}, allow_notfound: true}` from ONE
37
+ // place — the auth scaffold generator that builds a signup/login query. No
38
+ // engine class reads it: the `mvp` get-by class consults `dbo`, `output`, and
39
+ // its args and nothing else, and the older non-MVP class reads a differently
40
+ // named `allow_null`. So the member cannot change what a query does.
41
+ //
42
+ // It is deliberately NOT modelled — an authoring surface for a key the engine
43
+ // ignores is the mistake this file already refuses to make elsewhere. But the
44
+ // exclusion was only half-done: the encoder correctly declined to write it
45
+ // while the comparison still demanded it, so a correct decision read as a
46
+ // round-trip failure and sent every scaffolded auth query to `raw()`.
47
+ "allow_notfound"
48
+ ]);
49
+ function isEmptyObject(v) {
50
+ return v !== null && typeof v === "object" && !Array.isArray(v) && Object.keys(v).length === 0;
51
+ }
52
+ function isEmptyCustomize(v) {
53
+ return v === "" || isEmptyObject(v) || isEmptyArray(v);
54
+ }
55
+ function isSavedTest(value) {
56
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
57
+ const rec = value;
58
+ return typeof rec.name === "string" && Array.isArray(rec.expect);
59
+ }
60
+ function isEmptyArray(v) {
61
+ return Array.isArray(v) && v.length === 0;
62
+ }
63
+ function isNumber(v, n) {
64
+ return v === n || typeof v === "string" && v !== "" && Number(v) === n;
65
+ }
66
+ function deepEqual(a, b) {
67
+ if (a === b) return true;
68
+ if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
69
+ const aArr = Array.isArray(a);
70
+ if (aArr !== Array.isArray(b)) return false;
71
+ if (aArr) {
72
+ const x2 = a;
73
+ const y2 = b;
74
+ return x2.length === y2.length && x2.every((v, i) => deepEqual(v, y2[i]));
75
+ }
76
+ const x = a;
77
+ const y = b;
78
+ const keys = Object.keys(x);
79
+ return keys.length === Object.keys(y).length && keys.every((k) => deepEqual(x[k], y[k]));
80
+ }
81
+ var TIMESTAMP_RE = /^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})(?:\.\d+)?(Z|z|[+-]\d{2}:?\d{2})?$/;
82
+ function canonicalizeTimestamp(s) {
83
+ const m = TIMESTAMP_RE.exec(s);
84
+ if (!m) return void 0;
85
+ let tz = m[3] ?? "Z";
86
+ if (tz === "z") tz = "Z";
87
+ if (/^[+-]\d{4}$/.test(tz)) tz = `${tz.slice(0, 3)}:${tz.slice(3)}`;
88
+ const d = /* @__PURE__ */ new Date(`${m[1]}T${m[2]}${tz}`);
89
+ return Number.isNaN(d.getTime()) ? void 0 : d.toISOString();
90
+ }
91
+ var DEFAULT_CONTEXT_RETURN = {
92
+ list: {
93
+ sort: [],
94
+ paging: { page: 1, offset: 0, totals: false, enabled: false, metadata: true, per_page: 25 },
95
+ distinct: "auto"
96
+ },
97
+ type: "list",
98
+ single: { sort: [] },
99
+ stream: { sort: [], paging: { page: 1, enabled: false, per_page: 25 }, distinct: "auto" },
100
+ aggregate: {
101
+ eval: [],
102
+ sort: [],
103
+ group: [],
104
+ index: [],
105
+ paging: { page: 1, enabled: false, metadata: true, per_page: 25 }
106
+ }
107
+ };
108
+ var DEFAULT_RETURN_BLOCKS = {
109
+ list: DEFAULT_CONTEXT_RETURN.list,
110
+ single: DEFAULT_CONTEXT_RETURN.single,
111
+ stream: DEFAULT_CONTEXT_RETURN.stream,
112
+ aggregate: DEFAULT_CONTEXT_RETURN.aggregate
113
+ };
114
+ var MINIMAL_CONTEXT_RETURN = { type: "list" };
115
+ function hasNoListBounds(value) {
116
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
117
+ const entries = Object.entries(value);
118
+ if (entries.length === 0) return false;
119
+ return entries.every(
120
+ ([member, bound]) => (member === "min" || member === "max") && (bound === "" || typeof bound === "object" && bound !== null && isEmptyObject(bound))
121
+ );
122
+ }
123
+ var PAGING_INT_KEYS = /* @__PURE__ */ new Set(["page", "per_page", "offset"]);
124
+ var UNREADABLE_INPUT = /* @__PURE__ */ new Set(["mvp:create_image"]);
125
+ function hasUnreadableInput(name) {
126
+ return typeof name === "string" && UNREADABLE_INPUT.has(name);
127
+ }
128
+ var RETIRED_INPUT = {
129
+ "mvp:datadog_log": ["ddtags"],
130
+ "mvp:datadog_metric": ["ddtags"]
131
+ };
132
+ function retiredInputs(name) {
133
+ return (typeof name === "string" ? RETIRED_INPUT[name] : void 0) ?? [];
134
+ }
135
+ var NAME_KEYED_INPUT = /* @__PURE__ */ new Set([
136
+ "mvp:create_auth",
137
+ "mvp:api_request",
138
+ "mvp:amazon_opensearch_document",
139
+ "mvp:elasticsearch_document"
140
+ ]);
141
+ var EMPTY_SEARCH = { expression: [] };
142
+ function isBlankGroupStatement(v) {
143
+ if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
144
+ const node = v;
145
+ if (node.op !== "=") return false;
146
+ const blankSide = (side) => side !== null && typeof side === "object" && side.tag === "const" && side.operand === "";
147
+ return blankSide(node.left) && blankSide(node.right);
148
+ }
149
+ var RETURN_BLOCKS = ["single", "list", "stream", "aggregate"];
150
+ var RETURN_TYPES = /* @__PURE__ */ new Set([...RETURN_BLOCKS, "count", "exists"]);
151
+ function liveReturnSection(value) {
152
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
153
+ const section = value;
154
+ const type = section.type;
155
+ if (typeof type !== "string" || !RETURN_TYPES.has(type)) return void 0;
156
+ const dead = RETURN_BLOCKS.filter((b) => b !== type && b in section);
157
+ if (dead.length === 0) return void 0;
158
+ const live = {};
159
+ for (const [k, v] of Object.entries(section)) {
160
+ if (!RETURN_BLOCKS.includes(k) || k === type) live[k] = v;
161
+ }
162
+ return live;
163
+ }
164
+ function unboundAuthTable(value) {
165
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
166
+ const block = value;
167
+ if (block.dbo_id !== 0 || !("row_id" in block)) return void 0;
168
+ const rest = { ...block };
169
+ delete rest["dbo_id"];
170
+ return rest;
171
+ }
172
+ function returnWithoutIterator(value) {
173
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
174
+ const section = value;
175
+ if (typeof section.type !== "string" || !RETURN_TYPES.has(section.type)) return void 0;
176
+ let found = false;
177
+ const out = {};
178
+ for (const [k, v] of Object.entries(section)) {
179
+ if (RETURN_BLOCKS.includes(k) && v !== null && typeof v === "object" && !Array.isArray(v) && "iterator" in v) {
180
+ found = true;
181
+ const rest = { ...v };
182
+ delete rest.iterator;
183
+ out[k] = rest;
184
+ continue;
185
+ }
186
+ out[k] = v;
187
+ }
188
+ return found ? out : void 0;
189
+ }
190
+ var DEDICATED_RUNTIME_KEYS = ["cpu", "memory", "timeout", "max_retry"];
191
+ function liveAsyncRuntime(value) {
192
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
193
+ const block = value;
194
+ const mode = block.mode;
195
+ if (typeof mode !== "string") return void 0;
196
+ if (mode === "disabled") return {};
197
+ if (mode !== "async-shared") return void 0;
198
+ if (!DEDICATED_RUNTIME_KEYS.some((k) => k in block)) return void 0;
199
+ const live = {};
200
+ for (const [k, v] of Object.entries(block)) {
201
+ if (!DEDICATED_RUNTIME_KEYS.includes(k)) live[k] = v;
202
+ }
203
+ return live;
204
+ }
205
+ function isDeadResultItem(item, total) {
206
+ if (item === null || typeof item !== "object" || Array.isArray(item)) return false;
207
+ const entry = item;
208
+ if (entry.disabled !== void 0 && entry.disabled !== false) return true;
209
+ return entry.name === "" && total !== 1;
210
+ }
211
+ function isResultList(value) {
212
+ return Array.isArray(value) && value.length > 0 && value.every(
213
+ (e) => e !== null && typeof e === "object" && !Array.isArray(e) && "name" in e && "value" in e && "tag" in e && "filters" in e
214
+ );
215
+ }
216
+ function liveResultItems(value) {
217
+ if (!isResultList(value)) return void 0;
218
+ const live = value.filter((e) => !isDeadResultItem(e, value.length));
219
+ return live.length === value.length ? void 0 : live;
220
+ }
221
+ function isBlankAgentSettings(value) {
222
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
223
+ const settings = value;
224
+ if (settings.type !== "") return false;
225
+ if (settings.structuredOutputs === true) return false;
226
+ const schema = settings.structuredOutputsSchema;
227
+ if (Array.isArray(schema) && schema.length > 0) return false;
228
+ return true;
229
+ }
230
+ function configuredDeadReturnBlocks(value) {
231
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return [];
232
+ const section = value;
233
+ const type = section.type;
234
+ if (typeof type !== "string" || !RETURN_TYPES.has(type)) return [];
235
+ return RETURN_BLOCKS.filter((b) => b !== type && isConfiguredReturnBlock(section[b]));
236
+ }
237
+ function isConfiguredReturnBlock(block) {
238
+ if (block === null || typeof block !== "object" || Array.isArray(block)) return false;
239
+ const b = block;
240
+ for (const list of ["sort", "group", "eval", "index"]) {
241
+ if (Array.isArray(b[list]) && b[list].length > 0) return true;
242
+ }
243
+ const paging = b.paging;
244
+ return paging !== null && typeof paging === "object" && paging.enabled === true;
245
+ }
246
+ var DEFAULT_CONTEXT_EXTERNAL = {
247
+ tag: "input",
248
+ value: "",
249
+ permissions: { page: true, sort: true, search: true, per_page: false }
250
+ };
251
+ function bindsNoPagingFacet(value) {
252
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
253
+ const facets = Object.values(value);
254
+ if (facets.length === 0) return false;
255
+ return facets.every(
256
+ (facet) => facet !== null && typeof facet === "object" && !Array.isArray(facet) && facet.value === "" && (facet.filters ?? []).length === 0
257
+ );
258
+ }
259
+ var DEFAULT_CORS = {
260
+ mode: "default",
261
+ allowOrigins: [],
262
+ allowHeaders: [],
263
+ allowCredentials: false,
264
+ maxAge: 0,
265
+ allowMethods: { delete: false, get: false, head: false, patch: false, post: false, put: false }
266
+ };
267
+ var DEFAULT_DOCUMENTATION = { require_token: false, token: "" };
268
+ var DEFAULT_MIDDLEWARE = { pre: [], post: [], pre_customize: false, post_customize: false };
269
+ function isRawSqlContext(container) {
270
+ return container !== null && typeof container === "object" && typeof container.code === "string";
271
+ }
272
+ function withoutLeadingJoin(v) {
273
+ if (v === null || typeof v !== "object") return v;
274
+ const expression = v.expression;
275
+ if (!Array.isArray(expression)) return v;
276
+ const cleared = expression.map((entry, i) => {
277
+ if (entry === null || typeof entry !== "object") return entry;
278
+ const node = entry;
279
+ const group = "group" in node ? { group: withoutLeadingJoin(node.group) } : {};
280
+ if (i > 0) return { ...node, ...group };
281
+ const rest = Object.fromEntries(Object.entries(node).filter(([key]) => key !== "or"));
282
+ return { ...rest, ...group };
283
+ });
284
+ return { ...v, expression: cleared };
285
+ }
286
+ function isDefaultEnvelopeMember(key, v) {
287
+ switch (key) {
288
+ // An empty `mocks` arrives as `[]` from the engine and `{}` from the SDK — the
289
+ // empty-associative-collection artifact again. Both mean "no mocks".
290
+ case "mocks":
291
+ return isEmptyObject(v) || isEmptyArray(v);
292
+ // An UNSET runtime binding, in both stored spellings: the `null` the engine
293
+ // writes on one generation and the blank-member object it writes on another
294
+ // (`{id: "", mode: ""}` on 6 real `mvp:function` statements). A binding that
295
+ // names anything is preserved and still compares.
296
+ case "runtime":
297
+ return v === null || typeof v === "object" && v !== null && !Array.isArray(v) && Object.values(v).every((member) => member === "");
298
+ case "settings_registry":
299
+ return v === null || isEmptyArray(v);
300
+ case "addon":
301
+ return isEmptyArray(v);
302
+ case "disabled":
303
+ return v === false;
304
+ case "as":
305
+ case "description":
306
+ case "sql_name":
307
+ return v === "";
308
+ // The object-level members below are the same generational gap one level up
309
+ // — an object saved by an older engine generation omits them, while both the
310
+ // current engine and the SDK always write them at a fixed default. They were
311
+ // 1,716 of the 1,744 round-trip mismatches in a 187-workspace sweep, and
312
+ // each default is evidenced twice: the engine reads the absent key as this
313
+ // value, and real workspaces store present-at-default and absent side by
314
+ // side on one instance.
315
+ case "docs":
316
+ case "datasource":
317
+ case "view_alias":
318
+ return v === "";
319
+ // An MCP tool entry's optional metadata, and the agent provider-config
320
+ // members whose unset spelling is the empty string. Both store the empty
321
+ // form and the absent form side by side across the corpus.
322
+ case "tool_meta":
323
+ case "resource_uri":
324
+ case "alias":
325
+ case "baseURL":
326
+ case "safetySettings":
327
+ case "dynamicRetrievalConfig":
328
+ case "apiKey":
329
+ return v === "";
330
+ // `headers` is an empty STRING on an unset agent config and a string[] on an
331
+ // api_request statement — dropping only the string spelling leaves an empty
332
+ // header list comparing as the authored value it is.
333
+ case "headers":
334
+ return v === "";
335
+ // A tool entry's kind. Absent means `tool`; a `resource` or `prompt` entry
336
+ // says so and still compares. Value-distinct from the other `type`
337
+ // discriminators (an expression node, a column type), none of which is `tool`.
338
+ case "type":
339
+ return v === "tool";
340
+ // Four stored spellings of "no thinking budget" across 16 real configs: the
341
+ // empty string, absent, and the block with its budget as either `0` or `""`.
342
+ case "thinkingConfig":
343
+ return v === "" || typeof v === "object" && v !== null && !Array.isArray(v) && v["includeThoughts"] === false && (v["thinkingBudget"] === 0 || v["thinkingBudget"] === "");
344
+ // A query with no declared response type. Type- and value-distinct from the
345
+ // raw-SQL `response_type`, whose values are `list`/`single`/`count` and
346
+ // whose own default (`list`) is spelled differently.
347
+ case "response_type":
348
+ return v === "standard";
349
+ // Empty list members. `tag` is the load-bearing one: it is also the
350
+ // discriminator every tagged value carries, so the rule is restricted to the
351
+ // ARRAY spelling — a `tag: "const:str"` is a string and never matches.
352
+ case "tag":
353
+ case "views":
354
+ case "result":
355
+ return isEmptyArray(v);
356
+ // Two API-group gates with opposite defaults, each the value the engine
357
+ // falls back to when the key is absent: a group serves unless disabled,
358
+ // documentation is off unless turned on.
359
+ case "api_group_enabled":
360
+ return v === true;
361
+ case "swagger":
362
+ return v === false;
363
+ case "documentation":
364
+ return deepEqual(normalize(v), normalize(DEFAULT_DOCUMENTATION));
365
+ // A CORS block is applied ONLY when its `mode` is `"custom"` — the engine
366
+ // reads an absent mode as `""`, which is not custom — so a block that does
367
+ // not say `custom` configures nothing.
368
+ //
369
+ // Two spellings therefore mean the same default. The current one says
370
+ // `mode: "default"`; an older one predates `mode` entirely and carries
371
+ // `enabled: false`, a key that request path never reads.
372
+ case "cors": {
373
+ if (typeof v !== "object" || v === null || Array.isArray(v)) return false;
374
+ const block = { ...v };
375
+ if (block["enabled"] === false) delete block["enabled"];
376
+ block["mode"] ??= "default";
377
+ return deepEqual(normalize(block), normalize(DEFAULT_CORS));
378
+ }
379
+ // Both stored spellings of "no middleware": the engine hands an empty
380
+ // associative map back as a JSON array, the same artifact already absorbed
381
+ // for `mocks`, `customize` and an empty `context`. A phase explicitly
382
+ // customized to run nothing still compares — that is not inheriting.
383
+ case "middleware":
384
+ return isEmptyArray(v) || deepEqual(normalize(v), normalize(DEFAULT_MIDDLEWARE));
385
+ // Two unrelated `offset`s, both at a default. An addon's is the response path
386
+ // its rows are spliced into, `""` when spliced at the root. A list context's
387
+ // paging offset is declared to default to 0. Neither carries information at
388
+ // its default; any other value is preserved.
389
+ case "offset":
390
+ return v === "" || isNumber(v, 0);
391
+ // Return-block paging members, each at its declared default. Type-distinct
392
+ // from their same-named neighbours in a permissions block (`page: true`,
393
+ // `per_page: false`), which are booleans and so untouched.
394
+ case "page":
395
+ return isNumber(v, 1);
396
+ case "per_page":
397
+ return isNumber(v, 25);
398
+ case "metadata":
399
+ return v === true;
400
+ case "totals":
401
+ return v === false;
402
+ case "distinct":
403
+ return v === "auto";
404
+ // `s.setheader`'s duplicate-handling mode. The engine declares it
405
+ // `duplicates?=replace` and reads it as `($data["duplicates"] ?? "replace")`,
406
+ // so an absent key IS "replace"; 3 real statements omit it against 8 that
407
+ // store it present-at-default. The key appears on no other statement.
408
+ case "duplicates":
409
+ return v === "replace";
410
+ // A return sub-block whose every member sat at a default. These are checked
411
+ // against their NORMALIZED form because the member rules above are what empty
412
+ // them — without this the block survives as `{}` and the whole return envelope
413
+ // never collapses, which is the only reason it matters.
414
+ //
415
+ // `list` also names a foreach's iterated value; a tagged value never
416
+ // normalizes to empty, so that one is untouched.
417
+ //
418
+ // `enabled:false` is the one member no rule above empties, deliberately — it
419
+ // is meaningful on a history block, so it cannot be dropped by name. It IS
420
+ // droppable here, where the key says the block is paging: 7 real db.query
421
+ // statements omit `paging` outright against 149 that store it present at
422
+ // `enabled:false`, and the two spellings mean the same thing.
423
+ //
424
+ // Evidenced twice before being trusted. Every engine consumer reads the flag
425
+ // as `["paging"]["enabled"] ?? false`, so an absent block IS a disabled one,
426
+ // and the serializer returns before writing anything when it is off — a
427
+ // disabled block emits no source at all. The siblings are provably inert
428
+ // meanwhile: every read of `page`/`per_page`/`offset`/`metadata` sits behind
429
+ // that same gate.
430
+ //
431
+ // Still narrow: this fires only once every OTHER member has normalized away.
432
+ // A disabled block that customizes something (`{enabled:false, per_page:50}`)
433
+ // keeps both and compares as itself.
434
+ case "paging": {
435
+ const normalized = normalize(v);
436
+ return isEmptyObject(normalized) || deepEqual(normalized, { enabled: false });
437
+ }
438
+ // The same four blocks, plus the residue the member rules above cannot reach.
439
+ //
440
+ // The engine writes ALL FOUR result-shape blocks on every query; the SDK writes
441
+ // only the one its `returnType` selects. Emptiness alone does not collapse a
442
+ // default sibling, because two of its members have no rule that empties them —
443
+ // the paging `enabled:false` gate and an aggregate's empty `group`/`index`
444
+ // lists. So one customized `per_page` left every default sibling mismatching,
445
+ // and a paged query could never verify.
446
+ //
447
+ // Deep-equality against each block's own frozen default is what reaches those
448
+ // members WITHOUT a global rule on their generic names — `enabled:false` is
449
+ // meaningful on a history block, and an empty `group` is a condition default
450
+ // elsewhere. A block with anything authored inside it still compares.
451
+ case "list":
452
+ if (hasNoListBounds(v)) return true;
453
+ // falls through to the result-shape block of the same name
454
+ case "single":
455
+ case "stream":
456
+ case "aggregate":
457
+ return isEmptyObject(normalize(v)) || deepEqual(normalize(v), normalize(DEFAULT_RETURN_BLOCKS[key]));
458
+ // Field-envelope members the engine fills with a fixed default on save. A
459
+ // field saved by an older engine generation omits them entirely, while both
460
+ // the current engine and the SDK always write them — the same lean-vs-full
461
+ // generational gap as the members above, and by far the most common one in
462
+ // the wild: nearly every field in a workspace that has not been re-saved
463
+ // lacks `is_settings_registry`. Without these the decoder cannot prove ANY
464
+ // authored form reproduces such a field, so every one of them degrades to a
465
+ // descriptor literal or `rawField()` — including foreign keys, which lose
466
+ // their `f.tableRef(table)` form and the table import with it.
467
+ case "is_settings_registry":
468
+ case "sensitive":
469
+ return v === false;
470
+ case "mode":
471
+ case "format":
472
+ return v === "";
473
+ // A field's `vector.size` is only authored on a `vector` column; on every
474
+ // other type the engine writes this exact default. Dropping it at the
475
+ // default is symmetric, so a real `vector` column of size 3 still compares
476
+ // equal, and any other size is preserved and still compared.
477
+ case "vector":
478
+ return deepEqual(v, { size: 3 });
479
+ // Agent `agent_settings.model`: the engine persists a top-level empty
480
+ // `model:""` (the real model lives under `configs.<provider>.model`); the SDK
481
+ // omits the empty top-level field. Drop it on both sides when empty.
482
+ case "model":
483
+ return v === "";
484
+ // Statement input-entry members: the lean parser form omits these; the full
485
+ // persisted form carries them. Drop at their defaults (a meaningful
486
+ // `ignore:true` on a system column, or non-empty `children`, is kept).
487
+ case "ignore":
488
+ case "expand":
489
+ return v === false;
490
+ // Expression right-operand flag: the engine schema marks it `?=false` and
491
+ // drops it at the default on save, so the persisted form (and the SDK) omit
492
+ // it; older parser-generation fixtures still carry `ignore_empty:false`.
493
+ case "ignore_empty":
494
+ return v === false;
495
+ case "children":
496
+ return isEmptyArray(v);
497
+ // The two stored generations of an external database connection sit in
498
+ // SEPARATE fields, and a statement that uses one leaves the other at its
499
+ // unset value rather than dropping it: the engine's optional-schema pass
500
+ // gives the bare `connection_string` the text default `""` and leaves the
501
+ // nested `connection_string_flex` as nothing at all. Neither unset spelling
502
+ // says anything about the connection, so both drop on both sides — which is
503
+ // what lets a statement stored in either generation prove against the one
504
+ // field it actually uses (issue #138). A populated field of either
505
+ // generation is preserved and still compared.
506
+ case "connection_string":
507
+ return v === "";
508
+ case "connection_string_flex":
509
+ return v === null || v === "{}" || isEmptyObject(v);
510
+ // A value's filter chain: an empty `filters:[]` is identical to no filter
511
+ // chain. The engine always serializes it on a nested value (e.g. a
512
+ // `context`-nested `filename`); the SDK omits it there. Drop the empty form
513
+ // on both sides so the representational gap doesn't fail an otherwise-equal
514
+ // value. A non-empty chain is preserved and still compared.
515
+ case "filters":
516
+ return isEmptyArray(v);
517
+ // Statement/object input-entry array: the lean parser form omits an empty
518
+ // `input`; the full persisted form carries `input:[]`; and the engine writes
519
+ // `input:null` for a statement that takes no inputs at all. All three are the
520
+ // same "no inputs" state — the SDK emits the `[]` spelling, so without the
521
+ // null arm every input-less statement in a pulled workspace fails to prove
522
+ // and degrades to `raw()`. Drop all three on both sides; a populated `input`
523
+ // is preserved. Same two-spellings-of-empty shape as `settings_registry`.
524
+ case "input":
525
+ return v === null || isEmptyArray(v);
526
+ case "shared_workspace":
527
+ return v !== null && typeof v === "object" && v.is_shared === false;
528
+ // A trigger's `obj_id`: a table trigger's is the referenced table's GUID
529
+ // *string* (authored, derived by the SDK, kept and compared). A workspace /
530
+ // realtime / error trigger has no table, so the engine stores a *numeric*
531
+ // branch/workspace reference (`1`) while the SDK emits a `0` placeholder —
532
+ // deploy-target state, same rationale as the stripped `branch`. Drop the
533
+ // numeric form on both sides; the guid-string form is preserved.
534
+ case "obj_id":
535
+ return typeof v === "number";
536
+ // Toolset/query/function inherit-tier `history` block: when `inherit` is true
537
+ // nothing is customized (the limit/enabled members are the inherited
538
+ // defaults, not authored). The SDK omits it on a toolset; drop the inheriting
539
+ // form on both sides. A customized (`inherit:false`) history is preserved.
540
+ case "history":
541
+ return Array.isArray(v) || v !== null && typeof v === "object" && v.inherit === true;
542
+ // An MCP-server toolset persists `agent_settings:null` (only agents carry a
543
+ // real settings block); the SDK omits it. Drop the null form.
544
+ // `null`, and the engine's BLANK SCAFFOLD — an MCP toolset that configures no
545
+ // model still gets the whole block written, inert (see
546
+ // {@link isBlankAgentSettings}). The SDK spells both by omitting it.
547
+ case "agent_settings":
548
+ return v === null || isBlankAgentSettings(v);
549
+ // An agent's default `agent_settings.telemetry` (all providers off, empty
550
+ // keys): the SDK omits it. Drop when telemetry is disabled.
551
+ case "telemetry":
552
+ return v !== null && typeof v === "object" && v.enabled === false;
553
+ // A tool/query/function `test:[]` scaffold array — the SDK omits it on a tool;
554
+ // an empty test list is identical to none. Drop the empty form both sides.
555
+ case "test":
556
+ return isEmptyArray(v);
557
+ // A query's saved request/response sample at its empty spelling. The SDK
558
+ // writes `{}` whenever no sample is authored and the engine may store the
559
+ // key not at all, or with both halves null. All three mean "no sample".
560
+ // A POPULATED one is preserved and compared (and copied through opaquely —
561
+ // see the `example` branch in the recursion below).
562
+ case "example":
563
+ return v === null || isEmptyArray(v) || typeof v === "object" && Object.values(v).every((half) => half === null);
564
+ // A default `auth:false` (public / no auth table): the engine persists it on a
565
+ // tool where the SDK omits it. Drop the `false` form; `auth:true` and an
566
+ // auth-table id are preserved and still compared.
567
+ // `false` and `""` are both "no auth table"; a guid names one and compares.
568
+ case "auth":
569
+ return v === false || v === "";
570
+ // Default db-query `context` members the engine fills when an addon (or any
571
+ // db context) customizes nothing; the SDK omits them. Empty-collection /
572
+ // false members drop directly; the three structured members below match
573
+ // their exact engine default (a customized context is preserved).
574
+ case "bind":
575
+ case "eval":
576
+ case "sort":
577
+ return isEmptyArray(v);
578
+ case "future":
579
+ return v === false;
580
+ // Compare NORMALIZED against NORMALIZED default: normalize strips empty
581
+ // `sort`/`eval`/`index` members from the nested subtree, so the frozen
582
+ // default must pass through the same reduction to compare equal.
583
+ case "lock":
584
+ return deepEqual(normalize(v), normalize({ tag: "const:bool", value: "" }));
585
+ // A condition container that holds nothing, in either stored spelling: the
586
+ // `{expression: []}` the SDK writes and the empty associative-map form `[]`
587
+ // the engine hands back — the same artifact already absorbed for `mocks`,
588
+ // `customize` and an empty `context`. Both mean "no condition configured".
589
+ // A populated container is untouched and still compares node for node.
590
+ case "expr":
591
+ return isEmptyArray(v) || v !== null && typeof v === "object" && isEmptyArray(v.expression);
592
+ case "search":
593
+ return deepEqual(normalize(v), normalize({ expression: [] }));
594
+ // Two spellings of an all-defaults return block. The engine's declared shape
595
+ // defaults the result type to a list and leaves every sub-block optional, so
596
+ // a query that customizes nothing persists either the whole subtree (when the
597
+ // engine filled it on save) or nothing but the type — and the SDK omits it
598
+ // entirely. Accept both, and preserve any customized paging/sort/distinct.
599
+ case "return":
600
+ return deepEqual(normalize(v), normalize(DEFAULT_CONTEXT_RETURN)) || deepEqual(normalize(v), MINIMAL_CONTEXT_RETURN);
601
+ // A condition entry's nested group. The engine declares it optional with no
602
+ // default, so an entry that nests nothing omits the key while the SDK
603
+ // materializes an empty search. Same state; drop the empty form on both
604
+ // sides. A group that actually nests expressions is preserved and compared.
605
+ case "group":
606
+ return deepEqual(normalize(v), EMPTY_SEARCH);
607
+ // A condition entry's or-flag, declared to default false: the persisted form
608
+ // omits it at the default where the SDK writes it.
609
+ case "or":
610
+ return v === false;
611
+ // Generated-asset visibility, declared to default public wherever it appears.
612
+ case "access":
613
+ return v === "public";
614
+ // A precondition's error class, declared to default to the standard error.
615
+ case "error_type":
616
+ return v === "standard";
617
+ case "external":
618
+ return deepEqual(normalize(v), normalize(DEFAULT_CONTEXT_EXTERNAL));
619
+ case "simpleExternal":
620
+ return bindsNoPagingFacet(v);
621
+ default:
622
+ return false;
623
+ }
624
+ }
625
+ function isEmptyOutput(v) {
626
+ if (v === null) return true;
627
+ if (typeof v !== "object" || Array.isArray(v)) return false;
628
+ const o = v;
629
+ const noItems = o.items === void 0 || Array.isArray(o.items) && o.items.length === 0;
630
+ const noFilters = o.filters === void 0 || Array.isArray(o.filters) && o.filters.length === 0;
631
+ return noItems && noFilters && o.customize !== true;
632
+ }
633
+ function historyWithDefaultLimit(v) {
634
+ if (v === null || typeof v !== "object" || Array.isArray(v)) return void 0;
635
+ const block = v;
636
+ if (block.inherit !== false) return void 0;
637
+ const enabledKey = Object.keys(block).find((key) => key === "enabled" || key.endsWith("_enabled"));
638
+ if (enabledKey === void 0) return void 0;
639
+ const limitKey = enabledKey === "enabled" ? "limit" : `${enabledKey.slice(0, -"_enabled".length)}_limit`;
640
+ if (Object.hasOwn(block, limitKey)) return void 0;
641
+ return { ...block, [limitKey]: ENGINE_HISTORY_LIMIT };
642
+ }
643
+ var ENGINE_HISTORY_LIMIT = 100;
644
+ var LOCAL_DBO_REF = /^dbo=\d+$/;
645
+ function clearLocalDboRefs(value, cleared) {
646
+ if (Array.isArray(value)) {
647
+ return value.map((item) => clearLocalDboRefs(item, cleared));
648
+ }
649
+ if (value === null || typeof value !== "object") return value;
650
+ const next = Object.fromEntries(
651
+ Object.entries(value).map(([key, member]) => [
652
+ key,
653
+ clearLocalDboRefs(member, cleared)
654
+ ])
655
+ );
656
+ if (next.name === "@" && Array.isArray(next.arg)) {
657
+ const target = next.arg[0];
658
+ if (typeof target === "string" && LOCAL_DBO_REF.test(target)) {
659
+ cleared?.add(target);
660
+ return { ...next, arg: ["dbo=", ...next.arg.slice(1)] };
661
+ }
662
+ }
663
+ return next;
664
+ }
665
+ var EMPTY_CONTEXT_FILL = /* @__PURE__ */ new Map([
666
+ // Its name rides the envelope `as`, so the context is the value alone.
667
+ ["mvp:set_var", { tag: "const", named: false }],
668
+ // Standalone classes, each declaring its own default tag.
669
+ ["mvp:sleep", { tag: "const:int", named: false }],
670
+ ["mvp:die", { tag: "input", named: false }],
671
+ ["mvp:setheader", { tag: "input", named: false }],
672
+ // `array_pop`/`array_shift` carry NO `tag`, because they take no operand:
673
+ // popping or shifting reads nothing, their specs route no spread field, and
674
+ // the encoder writes `name` alone. The fill must be exactly what the encoder
675
+ // writes — filling a value they cannot author invents members the comparison
676
+ // then demands forever, which is what shipped once when they were given the
677
+ // full `UpdateVarBase` treatment below.
678
+ //
679
+ // A name-only fill is a different claim from that one, and it is evidenced
680
+ // twice on the engine, both times on the SCALAR `name`:
681
+ // • the statement's own XanoScript schema declares `name?='': context.name`
682
+ // — the default for an absent name IS the empty string; and
683
+ // • the shared base class declares `name` as a plain `text` member and runs
684
+ // it through the same optional-schema pass that licenses every entry here.
685
+ //
686
+ // That second point is exactly where the loops failed (see
687
+ // {@link LOOP_EMPTY_ITERAND}): that pass materializes a SCALAR member but
688
+ // defaults a NESTED object to the literal string `"{}"`. `name` is a scalar,
689
+ // `list`/`cnt` are not, and the shape is what decides. The engine's own
690
+ // statement-transform corpus stores `{"context":{}}` for `mvp:array_shift`.
691
+ ["mvp:array_pop", { named: true }],
692
+ ["mvp:array_shift", { named: true }],
693
+ // The `UpdateVarBase` family: `{name, value, tag, filters}`, `tag` overridden
694
+ // per subclass by `getDefaultTag()`. `test/codegen/spec-inverse` asserts every
695
+ // entry's members against the spec catalog so the two cannot drift.
696
+ ["mvp:update_var", { tag: "const", named: true }],
697
+ ["mvp:array_merge", { tag: "const:array", named: true }],
698
+ ["mvp:array_push", { tag: "const", named: true }],
699
+ ["mvp:array_unshift", { tag: "const", named: true }],
700
+ ["mvp:bitwise_and", { tag: "const:int", named: true }],
701
+ ["mvp:bitwise_or", { tag: "const:int", named: true }],
702
+ ["mvp:bitwise_xor", { tag: "const:int", named: true }],
703
+ ["mvp:math_add", { tag: "const:decimal", named: true }],
704
+ ["mvp:math_sub", { tag: "const:decimal", named: true }],
705
+ ["mvp:math_mul", { tag: "const:decimal", named: true }],
706
+ ["mvp:math_div", { tag: "const:decimal", named: true }],
707
+ ["mvp:math_mod", { tag: "const:int", named: true }],
708
+ ["mvp:text_append", { tag: "const", named: true }],
709
+ ["mvp:text_prepend", { tag: "const", named: true }],
710
+ ["mvp:text_trim", { tag: "const", named: true }],
711
+ ["mvp:text_ltrim", { tag: "const", named: true }],
712
+ ["mvp:text_rtrim", { tag: "const", named: true }],
713
+ ["mvp:text_starts_with", { tag: "const", named: true }],
714
+ ["mvp:text_istarts_with", { tag: "const", named: true }],
715
+ ["mvp:text_ends_with", { tag: "const", named: true }],
716
+ ["mvp:text_iends_with", { tag: "const", named: true }],
717
+ ["mvp:text_contains", { tag: "const", named: true }],
718
+ ["mvp:text_icontains", { tag: "const", named: true }],
719
+ // The file-resource family and `debug_log`: the context IS the value, like
720
+ // `set_var`, but the file resources declare a sibling SCALAR (`access`) that
721
+ // the same optional pass materializes alongside it — so the fill carries it.
722
+ // The nested `filename` is NOT filled: a nested object defaults to the literal
723
+ // string `"{}"` and materializes nothing.
724
+ //
725
+ // `extra` is exactly where the `array_pop` note above applies. `create_attachment`
726
+ // ALSO declares `include_meta?=false`, and filling it failed the round trip —
727
+ // the SDK's spec models no such field, so the encoder never writes it and the
728
+ // fill demanded a member the recovered record could not produce. The fill has
729
+ // to equal what the ENCODER writes, not everything the engine would supply.
730
+ // (A workspace that stores a real `include_meta` still degrades to `raw()`,
731
+ // which is the correct handling for an unmodelled member.)
732
+ //
733
+ // Read off each statement class's own schema, and the default tag is NOT
734
+ // uniform across them — the file resources declare `tag?=input` while
735
+ // `debug_log` declares `tag?=const`, the same split `die`/`setheader` have.
736
+ ["mvp:create_image", { tag: "input", named: false, extra: { access: "public" } }],
737
+ ["mvp:create_audio", { tag: "input", named: false, extra: { access: "public" } }],
738
+ ["mvp:create_attachment", { tag: "input", named: false, extra: { access: "public" } }],
739
+ ["mvp:debug_log", { tag: "const", named: false }]
740
+ ]);
741
+ var LOOP_EMPTY_ITERAND = /* @__PURE__ */ new Map([
742
+ ["mvp:foreach", { member: "list", value: "[]", tag: "const:array" }],
743
+ ["mvp:for", { member: "cnt", value: "0", tag: "const:int" }]
744
+ ]);
745
+ function blankValue(tag) {
746
+ return { value: "", tag, filters: [] };
747
+ }
748
+ function liveSwitchContext(stored) {
749
+ if (stored === null || typeof stored !== "object") return void 0;
750
+ const { name, context } = stored;
751
+ if (name !== "mvp:switch") return void 0;
752
+ if (context === null || typeof context !== "object" || Array.isArray(context)) return void 0;
753
+ const block = context;
754
+ const subject = block.value;
755
+ const nested = subject !== null && typeof subject === "object" && !Array.isArray(subject) && typeof subject.tag === "string";
756
+ if (!nested) return void 0;
757
+ const strays = ["tag", "filters"].filter((key) => key in block);
758
+ if (strays.length === 0) return void 0;
759
+ return Object.fromEntries(Object.entries(block).filter(([k]) => !strays.includes(k)));
760
+ }
761
+ function liveArrayMapContext(stored) {
762
+ if (stored === null || typeof stored !== "object") return void 0;
763
+ const { name, context } = stored;
764
+ if (name !== "mvp:array_map") return void 0;
765
+ if (context === null || typeof context !== "object" || Array.isArray(context)) return void 0;
766
+ const block = context;
767
+ const dead = (block.output_type ?? "value") === "object" ? "transform_value" : "transform_object";
768
+ if (!(dead in block)) return void 0;
769
+ return Object.fromEntries(Object.entries(block).filter(([k]) => k !== dead));
770
+ }
771
+ function filledContext(stored) {
772
+ if (stored === null || typeof stored !== "object") return null;
773
+ const { name, context } = stored;
774
+ if (typeof name !== "string") return null;
775
+ const whole = EMPTY_CONTEXT_FILL.get(name);
776
+ if (whole) {
777
+ const empty = context === null || Array.isArray(context) && context.length === 0 || typeof context === "object" && Object.keys(context).length === 0;
778
+ if (!empty) return null;
779
+ if (whole.tag === void 0) return { name: "" };
780
+ return {
781
+ ...whole.named ? { name: "" } : {},
782
+ ...blankValue(whole.tag),
783
+ ...whole.extra ?? {}
784
+ };
785
+ }
786
+ const loop = LOOP_EMPTY_ITERAND.get(name);
787
+ if (loop) {
788
+ if (context === null || typeof context !== "object" || Array.isArray(context)) return null;
789
+ const block = context;
790
+ if (block[loop.member] !== void 0) return null;
791
+ return { ...block, [loop.member]: { value: loop.value, tag: loop.tag, filters: [] } };
792
+ }
793
+ return null;
794
+ }
795
+ var INERT_TRIGGER_META_GROUPS = {
796
+ database: {
797
+ datasource: [],
798
+ search: { expression: [] },
799
+ action: { delete: false, insert: false, truncate: false, update: false }
800
+ },
801
+ toolset: { action: { connection: false } },
802
+ workspace: { action: { branch_live: false, branch_merge: false, branch_new: false } },
803
+ workspace_realtime_channel: { action: { message: false, join: false } },
804
+ realtime_server: { action: { connect: false, disconnect: false } },
805
+ channel: { action: { join: false, leave: false, deliver: false } }
806
+ };
807
+ function withoutInertTriggerMetaGroups(value) {
808
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
809
+ const entries = Object.entries(value);
810
+ if (entries.length === 0) return void 0;
811
+ if (!entries.every(([k]) => Object.hasOwn(INERT_TRIGGER_META_GROUPS, k))) return void 0;
812
+ const kept = entries.filter(([k, v]) => !deepEqual(v, INERT_TRIGGER_META_GROUPS[k]));
813
+ return kept.length === entries.length ? void 0 : Object.fromEntries(kept);
814
+ }
815
+ function normalize(value) {
816
+ if (Array.isArray(value)) {
817
+ return value.map((v) => normalize(v));
818
+ }
819
+ if (value !== null && typeof value === "object") {
820
+ const out = {};
821
+ const blankObj = value.tag === "const:obj" && "value" in value && (value.value === "" || value.value === null);
822
+ const isTable = "schema" in value && !("context" in value);
823
+ const sortsInput = NAME_KEYED_INPUT.has(value.name);
824
+ const dropsInput = UNREADABLE_INPUT.has(value.name);
825
+ const retired = retiredInputs(value.name);
826
+ const contextFill = filledContext(value);
827
+ const arrayMapContext = liveArrayMapContext(value);
828
+ const switchContext = liveSwitchContext(value);
829
+ const isGroupNode = value.type === "group";
830
+ const isMiddlewareBlock = "pre_customize" in value || "post_customize" in value;
831
+ const isDescriptor = "type" in value && "required" in value;
832
+ const requiredEntry = value.required === true;
833
+ for (const [k, stored] of Object.entries(value)) {
834
+ const v = k === "expr" ? withoutLeadingJoin(stored) : k === "result" ? liveResultItems(stored) ?? stored : k === "return" ? (() => {
835
+ const live = liveReturnSection(stored) ?? stored;
836
+ return returnWithoutIterator(live) ?? live;
837
+ })() : k === "runtime" ? liveAsyncRuntime(stored) ?? stored : stored;
838
+ if (k === "token" && isSavedTest(value)) continue;
839
+ if (k === "id" && isSavedTest(value)) {
840
+ out[k] = v;
841
+ continue;
842
+ }
843
+ if (STRIP_KEYS.has(k)) continue;
844
+ if (isTable && k === "as") continue;
845
+ if (isGroupNode && k === "statement") continue;
846
+ if (isMiddlewareBlock && (k === "pre" || k === "post") && value[`${k}_customize`] !== true) {
847
+ continue;
848
+ }
849
+ if (k === "arg" && isEmptyArray(v) && isRawSqlContext(value)) continue;
850
+ if (isDefaultEnvelopeMember(k, v)) continue;
851
+ if (isDescriptor && k === "default") {
852
+ if (requiredEntry || v === null || v === "") {
853
+ out[k] = null;
854
+ continue;
855
+ }
856
+ }
857
+ if (k === "output" && isEmptyOutput(v)) continue;
858
+ if (k === "history") {
859
+ const filled = historyWithDefaultLimit(v);
860
+ if (filled !== void 0) {
861
+ out[k] = normalize(filled);
862
+ continue;
863
+ }
864
+ }
865
+ if (k === "meta") {
866
+ const reduced = withoutInertTriggerMetaGroups(v);
867
+ if (reduced !== void 0) {
868
+ out[k] = normalize(reduced);
869
+ continue;
870
+ }
871
+ }
872
+ if (k === "customize" && isEmptyCustomize(v)) {
873
+ out[k] = {};
874
+ continue;
875
+ }
876
+ if (k === "customize") {
877
+ out[k] = normalize(clearLocalDboRefs(v));
878
+ continue;
879
+ }
880
+ if (k === "example") {
881
+ out[k] = Object.fromEntries(
882
+ Object.entries(v).filter(([, half]) => half !== null)
883
+ );
884
+ continue;
885
+ }
886
+ if (dropsInput && k === "input") continue;
887
+ if (k === "input" && Array.isArray(v) && retired.length > 0) {
888
+ out[k] = v.filter((entry) => !retired.includes(String(entry?.name ?? ""))).map((entry) => normalize(entry));
889
+ continue;
890
+ }
891
+ if (sortsInput && k === "input" && Array.isArray(v)) {
892
+ out[k] = [...v].sort(
893
+ (a, b) => String(a?.name ?? "").localeCompare(
894
+ String(b?.name ?? "")
895
+ )
896
+ ).map((entry) => normalize(entry));
897
+ continue;
898
+ }
899
+ if (k === "auth") {
900
+ const unbound = unboundAuthTable(v);
901
+ if (unbound) {
902
+ out[k] = normalize(unbound);
903
+ continue;
904
+ }
905
+ }
906
+ if (k === "context" && arrayMapContext) {
907
+ out[k] = normalize(arrayMapContext);
908
+ continue;
909
+ }
910
+ if (k === "context" && switchContext) {
911
+ out[k] = normalize(switchContext);
912
+ continue;
913
+ }
914
+ if (k === "context" && contextFill) {
915
+ out[k] = normalize(contextFill);
916
+ continue;
917
+ }
918
+ if (k === "context" && (isEmptyArray(v) || v === null)) {
919
+ out[k] = {};
920
+ continue;
921
+ }
922
+ if (k === "arg" && Array.isArray(v)) {
923
+ out[k] = v.map((e) => typeof e === "number" ? String(e) : normalize(e));
924
+ continue;
925
+ }
926
+ if (PAGING_INT_KEYS.has(k) && typeof v === "string" && /^-?\d+$/.test(v)) {
927
+ out[k] = Number(v);
928
+ continue;
929
+ }
930
+ if (k === "value" && blankObj) {
931
+ out[k] = "";
932
+ continue;
933
+ }
934
+ out[k] = (k === "value" || k === "operand" || k === "temperature") && (typeof v === "number" || typeof v === "boolean") ? String(v) : normalize(v);
935
+ }
936
+ return out;
937
+ }
938
+ if (typeof value === "string") {
939
+ const ts = canonicalizeTimestamp(value);
940
+ if (ts !== void 0) return ts;
941
+ }
942
+ return value;
943
+ }
944
+
945
+ export {
946
+ isEmptyCustomize,
947
+ deepEqual,
948
+ hasNoListBounds,
949
+ hasUnreadableInput,
950
+ retiredInputs,
951
+ isBlankGroupStatement,
952
+ isDeadResultItem,
953
+ isBlankAgentSettings,
954
+ configuredDeadReturnBlocks,
955
+ isDefaultEnvelopeMember,
956
+ isEmptyOutput,
957
+ ENGINE_HISTORY_LIMIT,
958
+ clearLocalDboRefs,
959
+ liveArrayMapContext,
960
+ filledContext,
961
+ normalize
962
+ };
963
+ //# sourceMappingURL=chunk-26CNBZE2.js.map