@xanots/sdk 0.0.12 → 0.0.13
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/CHANGELOG.md +21 -0
- package/README.md +5 -3
- package/dist/.build-fingerprint +1 -1
- package/dist/bin.js +3 -3
- package/dist/{chunk-AG5GCZDD.js → chunk-2AY3PKF4.js} +2 -2
- package/dist/{chunk-GSP2BY4F.js → chunk-BYQHCCYU.js} +1 -1
- package/dist/{chunk-QYSQ3UDO.js → chunk-MEFMTICH.js} +76 -1
- package/dist/{chunk-ELK7UALJ.js → chunk-OONT4ZL4.js} +2 -2
- package/dist/{chunk-VRNZ2NVV.js → chunk-PJNWOZMT.js} +2 -2
- package/dist/{chunk-XT3XQ4PF.js → chunk-RLI6XD4O.js} +10 -10
- package/dist/{chunk-VPAWRBK5.js → chunk-S3DOJOW4.js} +32 -8
- package/dist/{chunk-PLE5QQOZ.js → chunk-SS2V2QOG.js} +4 -4
- package/dist/cli.js +2 -2
- package/dist/{codegen-command-Y2SPMAUW.js → codegen-command-ZDHMGFWZ.js} +6 -6
- package/dist/{deploy-command-XHS5PKPV.js → deploy-command-CGVKRWUE.js} +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/{init-command-23FFNUFT.js → init-command-DNDONP3O.js} +4 -4
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +11 -11
- package/dist/{lock-commands-WCRC56ME.js → lock-commands-6U7UIJGR.js} +3 -3
- package/dist/node.d.ts +2 -2
- package/dist/node.js +4 -4
- package/dist/{preflight-command-TZWPHBXY.js → preflight-command-UYE7SUQV.js} +4 -4
- package/dist/{release-command-WEFYRTCI.js → release-command-CMMYT6XK.js} +6 -6
- package/dist/{routes-manifest-5ZFKUQWA.js → routes-manifest-MN6XBYRE.js} +24 -13
- package/dist/{store-DAnUIi1T.d.ts → store-9Psd0jiF.d.ts} +34 -16
- package/dist/{upgrade-command-GYEIMJBG.js → upgrade-command-A75DOIUH.js} +4 -4
- package/dist/{workspace-command-2ZTGT26W.js → workspace-command-YELP47SJ.js} +6 -6
- package/guides/typed-frontend.md +20 -3
- package/llms/kinds-realtime.md +2 -2
- package/llms/tests.md +1 -1
- package/llms/triggers.md +2 -2
- package/llms-full.txt +10 -10
- package/llms.txt +5 -5
- package/manifest.json +1 -1
- package/package.json +1 -1
package/dist/internal.js
CHANGED
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
taskKind,
|
|
30
30
|
toolKind,
|
|
31
31
|
workflowTestKind
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-PJNWOZMT.js";
|
|
33
33
|
import {
|
|
34
34
|
GENERATED_SPECS,
|
|
35
35
|
GENERATED_STATEMENT_NAMES,
|
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
registerSpec,
|
|
52
52
|
triggerKind,
|
|
53
53
|
workspaceKind
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-BYQHCCYU.js";
|
|
55
55
|
import {
|
|
56
56
|
IMPLEMENTED_STATEMENTS,
|
|
57
57
|
STATEMENT_SURFACES,
|
|
@@ -776,7 +776,7 @@ function renderTestsSection() {
|
|
|
776
776
|
"",
|
|
777
777
|
"- The run uses an EMPTY datasource, so **no `table({ seed })` rows exist while it runs** and every `db` read misses. A test that buys seeded row 1 fails with its own precondition message, which reads as a wrong id rather than an empty database. Create what the test needs INSIDE the test \u2014 typically a `defineFunction` fixture the stack calls first.",
|
|
778
778
|
'- `s.api.call` does NOT raise when the endpoint answers with an error. It BINDS the error envelope (`{code, message}`) to its `as` and carries on, so a later `s.expect.to_be_defined({ expr: ref("r.field") })` reports the ASSERTION while the real failure was the call, four statements up. Assert on the envelope \u2014 `s.expect.to_contain({ expr: ref("r.code"), value: c.text("ERROR_CODE_INPUT_ERROR") })` \u2014 when a call may fail. `s.function.run` raises instead; the two disagree.',
|
|
779
|
-
'- `s.expect.to_throw({ body, exception? })` runs `body` in an ISOLATED var stack, so a variable bound EARLIER in the test is not visible inside it \u2014 bind what the body needs inside the body. `exception` is a `Value` whose text the raised message must CONTAIN (`c.text("already exists")`, not a bare string); omit it to accept any error.',
|
|
779
|
+
'- `s.expect.to_throw({ body, exception? })` runs `body` in an ISOLATED var stack, so a variable bound EARLIER in the test is not visible inside it \u2014 bind what the body needs inside the body. An outer one raises `Missing var entry: <name>` there, which the test reports as `to_throw` not matching (`export()` warns). `exception` is a `Value` whose text the raised message must CONTAIN (`c.text("already exists")`, not a bare string); omit it to accept any error.',
|
|
780
780
|
"- `s.expect.to_throw` catches such a call only when the error carries a MESSAGE. `ERROR_CODE_ACCESS_DENIED` arrives with an empty one, so `to_throw` around an auth-refused call reports `to_throw failed - response is ok` \u2014 which reads as a broken auth gate on a gate that works.",
|
|
781
781
|
"- An endpoint's `auth` gate is NOT enforced on `s.api.call`. A `query({ auth: users })` runs anyway and fails only where its stack dereferences `auth(...)`. A stack that never touches `auth(...)` runs unauthenticated and passes.",
|
|
782
782
|
"- Neither `auth.token` nor an `Authorization` entry in `headers` authenticates the call \u2014 a token that answers 200 over real HTTP is refused here. To cover auth-gated logic, move the body into a `defineFunction` taking the user id and `s.function.call` that; the gate itself is not reachable from a workflow test.",
|
|
@@ -1116,10 +1116,10 @@ function renderSections(m) {
|
|
|
1116
1116
|
" `getPath()`/`verb`/`getUrl()`/`getChannel()` also pulls whatever its `stack` references:",
|
|
1117
1117
|
" the `s.*`/`c.*` factory CALLS run at module load to BUILD it. Types are free.",
|
|
1118
1118
|
" \u26A0 A FLOOR \u2014 **~267 kB minified (~65 kB gzipped)** for the FIRST def; splitting modules",
|
|
1119
|
-
" never removes it. The floor is the RUNTIME, not the def: a second
|
|
1120
|
-
"
|
|
1119
|
+
" never removes it. The floor is the RUNTIME, not the def: a second or much richer def",
|
|
1120
|
+
" adds ~2 kB, so trimming a def does not shrink it.",
|
|
1121
1121
|
" Fix: `xanots routes <entry> --emit xano/routes.gen.ts` (`paths` is an accepted alias) \u2014 verbs, paths, and sockets as",
|
|
1122
|
-
' plain data importing NOTHING, still compile-checked: `routePath("blog/{slug}", { slug })
|
|
1122
|
+
' plain data importing NOTHING, still compile-checked: `routePath("GET blog/{slug}", { slug })`',
|
|
1123
1123
|
' `channelPath("rooms/{room_id}", { room_id })`, `socketUrl("chat", baseUrl)` (tenant base',
|
|
1124
1124
|
" URLs lifted to `wss://h/ws/<tenant>:<canonical>`). A rename is a type error, not a 404.",
|
|
1125
1125
|
"- **Intra-workspace imports use `.js` specifiers** (`../tables/links.js`), not",
|
|
@@ -1196,7 +1196,7 @@ function renderSections(m) {
|
|
|
1196
1196
|
" submission on bind, so `s.security.check_password` compares two different hashes",
|
|
1197
1197
|
" and a correct password always fails (`ok:false` on a found row). Take the submitted",
|
|
1198
1198
|
" password as `input.text()` on both signup and login and pass the plaintext straight",
|
|
1199
|
-
" to `check_password` (which does the comparison hash itself).",
|
|
1199
|
+
" to `check_password` (which does the comparison hash itself). `export()` warns.",
|
|
1200
1200
|
"- **Agents authenticate with env vars \u2014 never `xanots login`.** `login` blocks on a",
|
|
1201
1201
|
" browser consent no agent can complete. Set `$XANO_INSTANCE_URL` + `$XANO_WORKSPACE_ID`",
|
|
1202
1202
|
" + `$XANO_META_TOKEN` and run `deploy`/`release` directly: no disk, no rotation, so it",
|
|
@@ -1365,11 +1365,11 @@ function renderSections(m) {
|
|
|
1365
1365
|
' - `deliverTo?`: `"channel"` (default) | `"sender"` | `"others"` | `"explicit"`. \u26A0 `"explicit"` still delivers to NOBODY \u2014 nothing selects recipients from inside a handler, and `s.realtime.publish` (which originates an event INTO a channel) is not a substitute.',
|
|
1366
1366
|
' - Only `"channel"`/`"others"` fan out AND are written to the `conversation` transcript \u2014 a `"sender"` response is invisible to every future joiner.',
|
|
1367
1367
|
' - **Both input surfaces read as ordinary inputs:** `inp("body")` for a payload field, `inp("room_id")` for the channel\'s `{room_id}`. No session lookup, no frame parsing.',
|
|
1368
|
-
" - A path param is bound ONCE at join and read from the connection thereafter, never from the frame \u2014 a sender cannot claim a room it did not join.
|
|
1368
|
+
" - A path param is bound ONCE at join and read from the connection thereafter, never from the frame \u2014 a sender cannot claim a room it did not join.",
|
|
1369
1369
|
" - `s.realtime.get_session({ as })` \u2014 the CALLER's realtime session for the current frame. FLAT shape:",
|
|
1370
1370
|
' - `authenticated` bool \xB7 `client_id` text (the AUTHED ROW ID as text, `""` anonymous) \xB7 `dbo_id` int (the auth TABLE\'s id \u2014 NOT the user\'s row id; `0` anonymous \u2014 to look the caller up use `client_id`. `dbo_id` is an int in the same position and typechecks, so a gate that keys on it finds no user and refuses EVERYONE) \xB7 `socket_id` int (transport id) \xB7 `channel` text (resolved path, `""` in a server trigger) \xB7 `params` object (bound path params, `{}` when none \u2014 `ref("session.params.room_id")`) \xB7 `extras` object \xB7 `opened_at` decimal.',
|
|
1371
1371
|
" - Works in a realtime MESSAGE stack and in CHANNEL and SERVER trigger stacks; off that path it degrades to an anonymous session.",
|
|
1372
|
-
' - For a path param prefer `inp("room_id")
|
|
1372
|
+
' - For a path param prefer `inp("room_id")` in a MESSAGE; a lifecycle TRIGGER has only the session. Reach for the session when you need the CONNECTION (identity/extras) \u2014 "who is this sender" on an anonymous-client channel.',
|
|
1373
1373
|
" - \u26A0 THREE UNRELATED THINGS ARE CALLED A CLIENT ID: `session.client_id` (app-facing identity), `session.socket_id` (transport), and a frame's `options.client_id` (the at_least_once CURSOR handle). Conflating the first and last breaks at_least_once for anonymous clients.",
|
|
1374
1374
|
" - `s.realtime.publish({ server, channel, data, message?, authTable?, authId? })` \u2014 the PUSH direction: originate a server-authored event onto a channel from ANY stack, no client frame first.",
|
|
1375
1375
|
" - `server` is the handle or its NAME (resolved by name, not guid); `channel` is the FILLED-IN path (`channel.getChannel({ room_id: 42 })`), never the template \u2014 a constant still carrying `{param}` THROWS at author time, and a constant `server`/`channel` naming nothing this workspace registers WARNS at export.",
|
|
@@ -1437,8 +1437,8 @@ function renderSections(m) {
|
|
|
1437
1437
|
"errorTrigger}({ name, guid?, description?, active?, tags?, ... })`.",
|
|
1438
1438
|
"",
|
|
1439
1439
|
'- `tableTrigger({ name, table?, datasources?, actions?: {insert?,update?,delete?,truncate?}, stack })` \u2014 database/table trigger. `t.new` / `t.old` are the row **after** / **before** the change; `t.action` (`insert|update|delete|truncate`), `t.datasource`. Bind `table` to a `table()` handle and `t.new("col")` / `t.old("col")` are typed to that row (misspelled column = compile error). Nullability follows the enabled actions: insert \u2192 `old` is null, delete \u2192 `new` is null, update \u2192 both, truncate \u2192 neither. Config-only (no response).',
|
|
1440
|
-
"- `realtimeServerTrigger({ name, realtimeServer, actions?: {connect?,disconnect?}, stack?, response?, responseShape? })` \u2014 realtime SERVER lifecycle (a client connecting to / disconnecting from the server, not a message). Inputs: `t.action` (`connect|disconnect`), `t.realtime_server`, `t.client`. Bind `realtimeServer` to a `realtimeServer()` handle (or its name). `connect` GATES the connection \u2014 a denial sends an `error` and CLOSES the socket with code 4401 before it is ever ready, so it is a real front door, not an observer; same return shape as a channel `join`
|
|
1441
|
-
'- `realtimeChannelTrigger({ name, channel, actions?: {join?,leave?,deliver?}, stack?, response?, responseShape? })` \u2014 realtime CHANNEL lifecycle. Inputs: `t.action` (`join|leave|deliver`), `t.channel`, `t.client`. Bind `channel` to a `realtimeChannel()` handle \u2014 a bare path is NOT accepted (it is unique only within its server). The three actions have DIFFERENT postures, and the posture decides what the stack should return: `join` GATES the join (it runs BEFORE the client becomes a member, so a denial means it never sees a fan-out) \u2014 return `{ allowed: c.bool(true) }` (optional `reason` reaches the client) or any truthy value to admit, and an EMPTY OR FALSY RETURN DENIES, so a stack that just falls through \u2014 or a gating trigger with NO `response` \u2014 refuses everyone, and a CRASH DENIES too. That is the inverse of a
|
|
1440
|
+
"- `realtimeServerTrigger({ name, realtimeServer, actions?: {connect?,disconnect?}, stack?, response?, responseShape? })` \u2014 realtime SERVER lifecycle (a client connecting to / disconnecting from the server, not a message). Inputs: `t.action` (`connect|disconnect`), `t.realtime_server`, `t.client`. Bind `realtimeServer` to a `realtimeServer()` handle (or its name). `connect` GATES the connection \u2014 a denial sends an `error` and CLOSES the socket with code 4401 before it is ever ready, so it is a real front door, not an observer; same return shape as a channel `join` below (EMPTY/FALSY DENIES \u2014 INCLUDING a gating trigger with NO `response`, which returns nothing and so refuses every client). A CRASH DENIES too \u2014 a gate that cannot answer must not admit. Both failure modes lock the door, so plan for a self-inflicted LOCKOUT (an unguarded drill into a null `db.get` raises \u2192 everyone refused), not a breach. Gating is OPT-IN: a server with no `connect` trigger accepts every connection. `disconnect` is OBSERVATIONAL (return ignored, throws swallowed \u2014 cleanup must always complete). Both are SERVER-scoped, so `s.realtime.get_session` works but carries no channel path and no bound params.",
|
|
1441
|
+
'- `realtimeChannelTrigger({ name, channel, actions?: {join?,leave?,deliver?}, stack?, response?, responseShape? })` \u2014 realtime CHANNEL lifecycle. Inputs: `t.action` (`join|leave|deliver`), `t.channel`, `t.payload`, `t.client`. Bind `channel` to a `realtimeChannel()` handle \u2014 a bare path is NOT accepted (it is unique only within its server). The three actions have DIFFERENT postures, and the posture decides what the stack should return: `join` GATES the join (it runs BEFORE the client becomes a member, so a denial means it never sees a fan-out) \u2014 return `{ allowed: c.bool(true) }` (optional `reason` reaches the client) or any truthy value to admit, and an EMPTY OR FALSY RETURN DENIES, so a stack that just falls through \u2014 or a gating trigger with NO `response` \u2014 refuses everyone, and a CRASH DENIES too. ONCE the object carries an `allowed` key admission needs STRICTLY `true` \u2014 a computed `1`/`"yes"` there DENIES. That is the inverse of a crashing message, which still delivers, and of `deliver` below. A lifecycle trigger\'s inputs are PINNED to those four, so a channel PATH PARAM is NOT among them \u2014 `inp("room_id")` RAISES, which crashes the gate and so REFUSES every client; take the param from `s.realtime.get_session` (`ref("session.params.room_id")`). A gate establishes NO auth, so `ref("auth.id")` reads 0 even when authenticated \u2014 identity is `t.client("permissions.dbo_id")` or the session. A SERVER connect/disconnect has no channel, so no params at all; `leave` is OBSERVATIONAL (return ignored, throws swallowed); `deliver` GATES delivery PER RECIPIENT \u2014 the per-viewer redaction tool and the most expensive action here (a stack per recipient per message), and it needs `delivery.perRecipient` on the channel to run at all \u2014 BOTH HALVES are required, so a `deliver` trigger on a channel without the flag NEVER RUNS and every subscriber receives the UNREDACTED payload (no error, no log line); `export()` warns on each half alone. **`deliver`\'s RETURN VALUES DO NOT READ LIKE A FILTER:** ONLY an explicit NULL drops the message for that recipient; an OBJECT replaces that recipient\'s payload; ANYTHING ELSE \u2014 INCLUDING `false`, `0`, `""` \u2014 DELIVERS IT UNCHANGED, as does a crash. So `return false` from a yes/no redaction check SENDS the message it was written to suppress \u2014 return null instead. The delivered payload arrives NESTED, so read `t.payload("<field>")`, and `t.client` is the SENDER while `s.realtime.get_session` describes the RECIPIENT this run is for.',
|
|
1442
1442
|
'- `mcpServerTrigger({ name, mcpServer, stack?, response?, responseShape? })` / `agentTrigger({ name, agent, stack?, response?, responseShape? })` \u2014 toolset connection. Bind with the `mcpServer()`/`agent()` def handle (or its name) \u2014 it resolves to the toolset guid at export. Raw numeric `objId` is the escape hatch, rarely right: ids are assigned at import, so a handle passed to `objId` is a type error, and binding nothing deploys a trigger that never fires. Inputs: `t.toolset` (`t.toolset("name")`), `t.tools`. Response-bearing; the default stack copies `toolset`/`tools` into vars and returns them.',
|
|
1443
1443
|
"- `workspaceTrigger({ name, actions?: {branch_live?,branch_merge?,branch_new?}, stack? })` \u2014 branch lifecycle. Inputs: `t.to_branch`, `t.from_branch`, `t.action`. Config-only.",
|
|
1444
1444
|
'- `errorTrigger({ name, stack? })` \u2014 error-signature trigger. Inputs: `t.event` (`new|regression|fixed`), `t.id`, `t.signature`, `t.error` (`t.error("code")`/`t.error("message")`), `t.caller`, `t.statement`, `t.actor`, `t.count`, `t.first_seen`, `t.last_seen`, `t.fixed_at`. Config-only.',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadDefault
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RLI6XD4O.js";
|
|
4
4
|
import "./chunk-7WRJPKGK.js";
|
|
5
5
|
import {
|
|
6
6
|
readLockFile,
|
|
@@ -15,7 +15,7 @@ import "./chunk-GNPVYOPB.js";
|
|
|
15
15
|
import "./chunk-EZG76F7R.js";
|
|
16
16
|
import {
|
|
17
17
|
Xano
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-MEFMTICH.js";
|
|
19
19
|
import "./chunk-V5Y7D4LH.js";
|
|
20
20
|
import "./chunk-N74KDCBD.js";
|
|
21
21
|
import "./chunk-EETVJZAZ.js";
|
|
@@ -231,4 +231,4 @@ ${lines}
|
|
|
231
231
|
export {
|
|
232
232
|
runLockCommand
|
|
233
233
|
};
|
|
234
|
-
//# sourceMappingURL=lock-commands-
|
|
234
|
+
//# sourceMappingURL=lock-commands-6U7UIJGR.js.map
|
package/dist/node.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { aZ as LambdaOptions, a_ as CaptureValue, a$ as LambdaSurface, b0 as CaptureRecord, b1 as LambdaBindings, F as FunctionDef, b2 as Xano, i as LockFile } from './store-
|
|
2
|
-
export { b3 as AddonDef, b4 as AddonXdo, A as AdoptChange, a as AdoptResult, b5 as AgentDef, b6 as AgentHandle, b7 as AgentOutput, b8 as AgentSettingsXdo, b9 as AgentXdo, ba as AmbientBindings, bb as AnthropicLlm, bc as ApiGroupDef, bd as ApiGroupXdo, be as AuthRef, bf as Authored, B as Bundle, b as BundlePayload, c as BundleType, bg as Capturable, bh as ChannelConversationDef, bi as ChannelDeliveryDef, bj as ChannelDeliveryGuarantee, bk as ChannelPublishDef, bl as ChannelPublishWho, bm as ChannelRateLimitDef, bn as ColumnDef, bo as Comparison, bp as ContainerEnv, bq as ContainerPort, br as ContainerResources, bs as ContainerVolume, bt as CorsConfig, bu as CorsMode, bv as DatabaseActions, bw as DatabaseInputs, bx as DbEval, by as DbEvalFilter, bz as DbWhere, bA as ErrorInputs, bB as ExceptionPolicy, bC as FieldAccessor, bD as FieldRule, bE as GoogleGenAiLlm, bF as HistoryInput, bG as HttpVerb, bH as IndexDef, bI as IndexLang, bJ as IndexOp, bK as IndexType, bL as IndexXdo, bM as InferRow, bN as InputDescriptor, bO as InputOptions, bP as IteratingBindings, bQ as KnowledgeDef, bR as KnowledgeDirSource, bS as KnowledgeFileSource, bT as KnowledgeMode, bU as KnowledgeType, bV as LAMBDA_BINDINGS, bW as LAMBDA_CODE_FILTERS, bX as LAMBDA_GLOBALS, bY as LAMBDA_MODULE_GLOBALS, bZ as LAMBDA_STATEMENTS, b_ as LambdaBody, b$ as LlmPrompt, c0 as LlmProvider, c1 as LlmSettings, g as LockEntry, h as LockExportContext, M as Manifest, j as ManifestField, k as ManifestKind, l as ManifestStatement, c2 as ManifestValue, c3 as McpPathOptions, c4 as McpServerDef, c5 as McpServerHandle, c6 as McpServerXdo, m as MergeResult, c7 as MessageDeliverTo, c8 as MicroserviceChart, c9 as MicroserviceConfig, ca as MicroserviceContainer, cb as MicroserviceDef, cc as MicroserviceDeployment, cd as MicroserviceIngress, ce as MicroserviceRegistryAuth, cf as MicroserviceVolume, cg as MicroserviceXdo, ch as MiddlewareAttach, ci as MiddlewareAttachEntry, cj as MiddlewareDef, ck as MiddlewareXdo, O as ObjectKind, cl as OpenAiLlm, n as PayloadArrayKey, cm as QueryDef, cn as QueryFilterName, co as QueryHandle, cp as QueryResponseType, cq as QueryXdo, cr as RealtimeActions, cs as RealtimeChannelActions, ct as RealtimeChannelDef, cu as RealtimeChannelHandle, cv as RealtimeChannelRef, cw as RealtimeChannelTriggerInputs, cx as RealtimeChannelXdo, cy as RealtimeClient, cz as RealtimeInputs, cA as RealtimeMessageDef, cB as RealtimeMessageXdo, cC as RealtimeServerActions, cD as RealtimeServerDef, cE as RealtimeServerHandle, cF as RealtimeServerRef, cG as RealtimeServerTriggerInputs, cH as RealtimeServerXdo, cI as RealtimeUrlOptions, R as RenameResult, cJ as ResultStrategy, cK as Route, cL as RowOf, cM as ScheduleDef, cN as SchemaCols, cO as SchemaDef, cP as SearchComparison, cQ as SearchGroup, cR as SearchNode, cS as SearchOp, cT as SearchParamValue, cU as SeedFileSource, cV as SeedRow, cW as SeedSource, cX as SortDir, cY as SortDirective, S as StatementSpec, cZ as TableDef, c_ as TableXdo, c$ as TaskDef, d0 as TaskXdo, d1 as ToolDef, d2 as ToolXdo, d3 as ToolsetBaseDef, d4 as ToolsetBaseXdo, d5 as ToolsetInputs, d6 as ToolsetToolEntry, d7 as ToolsetToolRef, d8 as TriggerDef, d9 as TriggerObjType, da as TriggerXdo, db as ViewDef, dc as ViewXdo, dd as WorkflowTestDef, de as WorkflowTestXdo, df as WorkspaceActions, dg as WorkspaceConfigDef, dh as WorkspaceConfigXdo, di as WorkspaceHistoryDef, dj as WorkspaceHistoryXdo, dk as WorkspaceInputs, dl as WorkspaceMiddlewareDef, dm as WorkspaceMiddlewareXdo, dn as XanoFreeLlm, dp as addon, dq as agent, dr as agentTrigger, ds as and, dt as apiGroup, du as assertLambdaBody, dv as bitwiseAnd, dw as bitwiseOr, dx as bitwiseXor, dy as cmp, dz as defineFunction, dA as emit, dB as emitBundle, dC as errorTrigger, dD as expr, dE as fl, dF as input, dG as knowledge, dH as knowledgeDir, dI as knowledgeFile, dJ as mathAdd, dK as mathDiv, dL as mathMul, dM as mathSub, dN as mcpServer, dO as mcpServerTrigger, dP as microservice, dQ as middleware, dR as mixed, dS as objectEntries, dT as objectKeys, dU as objectValues, dV as or, dW as query, dX as realtimeChannel, dY as realtimeChannelTrigger, dZ as realtimeMessage, d_ as realtimeServer, d$ as realtimeServerTrigger, e0 as realtimeTrigger, e1 as resetLockOverrides, e2 as seedFile, e3 as seedLockOverrides, e4 as table, e5 as tableTrigger, e6 as task, e7 as textAppend, e8 as textPrepend, e9 as toSearchParams, ea as tool, eb as workflowTest, ec as workspace, ed as workspaceConfig, ee as workspaceTrigger } from './store-
|
|
1
|
+
import { aZ as LambdaOptions, a_ as CaptureValue, a$ as LambdaSurface, b0 as CaptureRecord, b1 as LambdaBindings, F as FunctionDef, b2 as Xano, i as LockFile } from './store-9Psd0jiF.js';
|
|
2
|
+
export { b3 as AddonDef, b4 as AddonXdo, A as AdoptChange, a as AdoptResult, b5 as AgentDef, b6 as AgentHandle, b7 as AgentOutput, b8 as AgentSettingsXdo, b9 as AgentXdo, ba as AmbientBindings, bb as AnthropicLlm, bc as ApiGroupDef, bd as ApiGroupXdo, be as AuthRef, bf as Authored, B as Bundle, b as BundlePayload, c as BundleType, bg as Capturable, bh as ChannelConversationDef, bi as ChannelDeliveryDef, bj as ChannelDeliveryGuarantee, bk as ChannelPublishDef, bl as ChannelPublishWho, bm as ChannelRateLimitDef, bn as ColumnDef, bo as Comparison, bp as ContainerEnv, bq as ContainerPort, br as ContainerResources, bs as ContainerVolume, bt as CorsConfig, bu as CorsMode, bv as DatabaseActions, bw as DatabaseInputs, bx as DbEval, by as DbEvalFilter, bz as DbWhere, bA as ErrorInputs, bB as ExceptionPolicy, bC as FieldAccessor, bD as FieldRule, bE as GoogleGenAiLlm, bF as HistoryInput, bG as HttpVerb, bH as IndexDef, bI as IndexLang, bJ as IndexOp, bK as IndexType, bL as IndexXdo, bM as InferRow, bN as InputDescriptor, bO as InputOptions, bP as IteratingBindings, bQ as KnowledgeDef, bR as KnowledgeDirSource, bS as KnowledgeFileSource, bT as KnowledgeMode, bU as KnowledgeType, bV as LAMBDA_BINDINGS, bW as LAMBDA_CODE_FILTERS, bX as LAMBDA_GLOBALS, bY as LAMBDA_MODULE_GLOBALS, bZ as LAMBDA_STATEMENTS, b_ as LambdaBody, b$ as LlmPrompt, c0 as LlmProvider, c1 as LlmSettings, g as LockEntry, h as LockExportContext, M as Manifest, j as ManifestField, k as ManifestKind, l as ManifestStatement, c2 as ManifestValue, c3 as McpPathOptions, c4 as McpServerDef, c5 as McpServerHandle, c6 as McpServerXdo, m as MergeResult, c7 as MessageDeliverTo, c8 as MicroserviceChart, c9 as MicroserviceConfig, ca as MicroserviceContainer, cb as MicroserviceDef, cc as MicroserviceDeployment, cd as MicroserviceIngress, ce as MicroserviceRegistryAuth, cf as MicroserviceVolume, cg as MicroserviceXdo, ch as MiddlewareAttach, ci as MiddlewareAttachEntry, cj as MiddlewareDef, ck as MiddlewareXdo, O as ObjectKind, cl as OpenAiLlm, n as PayloadArrayKey, cm as QueryDef, cn as QueryFilterName, co as QueryHandle, cp as QueryResponseType, cq as QueryXdo, cr as RealtimeActions, cs as RealtimeChannelActions, ct as RealtimeChannelDef, cu as RealtimeChannelHandle, cv as RealtimeChannelRef, cw as RealtimeChannelTriggerInputs, cx as RealtimeChannelXdo, cy as RealtimeClient, cz as RealtimeInputs, cA as RealtimeMessageDef, cB as RealtimeMessageXdo, cC as RealtimeServerActions, cD as RealtimeServerDef, cE as RealtimeServerHandle, cF as RealtimeServerRef, cG as RealtimeServerTriggerInputs, cH as RealtimeServerXdo, cI as RealtimeUrlOptions, R as RenameResult, cJ as ResultStrategy, cK as Route, cL as RowOf, cM as ScheduleDef, cN as SchemaCols, cO as SchemaDef, cP as SearchComparison, cQ as SearchGroup, cR as SearchNode, cS as SearchOp, cT as SearchParamValue, cU as SeedFileSource, cV as SeedRow, cW as SeedSource, cX as SortDir, cY as SortDirective, S as StatementSpec, cZ as TableDef, c_ as TableXdo, c$ as TaskDef, d0 as TaskXdo, d1 as ToolDef, d2 as ToolXdo, d3 as ToolsetBaseDef, d4 as ToolsetBaseXdo, d5 as ToolsetInputs, d6 as ToolsetToolEntry, d7 as ToolsetToolRef, d8 as TriggerDef, d9 as TriggerObjType, da as TriggerXdo, db as ViewDef, dc as ViewXdo, dd as WorkflowTestDef, de as WorkflowTestXdo, df as WorkspaceActions, dg as WorkspaceConfigDef, dh as WorkspaceConfigXdo, di as WorkspaceHistoryDef, dj as WorkspaceHistoryXdo, dk as WorkspaceInputs, dl as WorkspaceMiddlewareDef, dm as WorkspaceMiddlewareXdo, dn as XanoFreeLlm, dp as addon, dq as agent, dr as agentTrigger, ds as and, dt as apiGroup, du as assertLambdaBody, dv as bitwiseAnd, dw as bitwiseOr, dx as bitwiseXor, dy as cmp, dz as defineFunction, dA as emit, dB as emitBundle, dC as errorTrigger, dD as expr, dE as fl, dF as input, dG as knowledge, dH as knowledgeDir, dI as knowledgeFile, dJ as mathAdd, dK as mathDiv, dL as mathMul, dM as mathSub, dN as mcpServer, dO as mcpServerTrigger, dP as microservice, dQ as middleware, dR as mixed, dS as objectEntries, dT as objectKeys, dU as objectValues, dV as or, dW as query, dX as realtimeChannel, dY as realtimeChannelTrigger, dZ as realtimeMessage, d_ as realtimeServer, d$ as realtimeServerTrigger, e0 as realtimeTrigger, e1 as resetLockOverrides, e2 as seedFile, e3 as seedLockOverrides, e4 as table, e5 as tableTrigger, e6 as task, e7 as textAppend, e8 as textPrepend, e9 as toSearchParams, ea as tool, eb as workflowTest, ec as workspace, ed as workspaceConfig, ee as workspaceTrigger } from './store-9Psd0jiF.js';
|
|
3
3
|
export { ActionCallArgs, AddonCallArgs, AddonSpec, AgentRunResult, AiAgentRunArgs, AnyAddonDef, AnyFunctionDef, AnyQueryDef, AnyTableDef, ApiCallArgs, ApplyFilter, ApplyFilters, ArrayMapArgs, CloudJobArgs, CloudJobAwaitArgs, CloudJobStatusArgs, CreateAuthTokenArgs, DbAddArgs, DbAddOrEditArgs, DbAggregate, DbAggregatePaging, DbBind, DbBulkAddArgs, DbBulkDeleteArgs, DbBulkWriteArgs, DbDelArgs, DbDirectQueryArgs, DbDistinct, DbEditArgs, DbExternal, DbExternalPermissions, DbExternalQueryArgs, DbField, DbGetArgs, DbHasArgs, DbJoin, DbPaging, DbPatchArgs, DbQueryArgs, DbResponseType, DbReturnType, DbSchemaArgs, DbTransactionArgs, DbTruncateArgs, ExpectToThrowArgs, ExternalSqlEngine, ForArgs, ForeachArgs, FunctionCallArgs, FunctionRunArgs, GetRawInputArgs, HeaderMap, HttpMethod, InferInput, InferResponse, IpLookupArgs, IpLookupResult, MiddlewareCallArgs, RealtimeEventArgs, StackTupleWidened, SwitchArgs, SwitchCaseArgs, TaskCallArgs, ToolCallArgs, TriggerCallArgs, TryCatchArgs, WhileArgs, WorkflowTestCallArgs, actionCall, actionPackageCall, addonCall, aiAgentRun, apiCall, arrayMap, arrayUnion, cloudJob, cloudJobAwait, cloudJobStatus, comment, compile, conditional, createAuthToken, dbAdd, dbAddOrEdit, dbBulkAdd, dbBulkDelete, dbBulkPatch, dbBulkUpdate, dbDel, dbDirectQuery, dbEdit, dbExternalQuery, dbGet, dbHas, dbPatch, dbQuery, dbSchema, dbTransaction, dbTruncate, debugLog, die, expectToThrow, fileUrl, forLoop, foreachBreak, foreachContinue, foreachLoop, foreachRemove, functionCall, functionRun, getRawInput, group, ignored, ipLookup, middlewareCall, postProcess, realtimeEvent, returnValue, s, setVar, switchCase, switchStatement, taskCall, toolCall, triggerCall, tryCatch, updateVar, whileLoop, workflowTestCall } from './index.js';
|
|
4
4
|
export { B as BrandOpts, b as BrandValue, D as DecimalMethod, E as EmailMethod, c as FieldAccess, f as FieldDescriptor, h as FieldMap, j as FieldOpts, k as FieldStyleType, l as FromFieldMap, I as IntMethod, M as MethodArg, m as MethodOpts, n as MethodSpec, o as MockEntry, p as MockMap, q as MockXdo, O as ObjInput, s as ObjMember, u as ObjValue, v as ObjectRef, P as PasswordMethod, w as ResponseDef, x as RowFromFieldMap, S as Statement, y as StatementAnnotations, z as StatementOptions, T as TableRefMethod, A as TextFormat, C as TextMethod, G as TypeBrand, V as ValueOf, H as VectorMethod, X as XanoFileRef, J as XanoGeoPosition, K as XanoGeoValue, L as annotate, N as f, Q as obj, U as statements } from './response-D6xGLEIn.js';
|
|
5
5
|
import { V as Value } from './xdo-ODuJklk6.js';
|
package/dist/node.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
task,
|
|
18
18
|
tool,
|
|
19
19
|
workflowTest
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-PJNWOZMT.js";
|
|
21
21
|
import {
|
|
22
22
|
actionCall,
|
|
23
23
|
actionPackageCall,
|
|
@@ -100,7 +100,7 @@ import {
|
|
|
100
100
|
workflowTestCall,
|
|
101
101
|
workspaceConfig,
|
|
102
102
|
workspaceTrigger
|
|
103
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-BYQHCCYU.js";
|
|
104
104
|
import {
|
|
105
105
|
exportBundleJson,
|
|
106
106
|
loadDefault,
|
|
@@ -108,7 +108,7 @@ import {
|
|
|
108
108
|
run,
|
|
109
109
|
writeArtifact,
|
|
110
110
|
writeBundle
|
|
111
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-RLI6XD4O.js";
|
|
112
112
|
import "./chunk-7WRJPKGK.js";
|
|
113
113
|
import {
|
|
114
114
|
readLockFile,
|
|
@@ -120,7 +120,7 @@ import "./chunk-EZG76F7R.js";
|
|
|
120
120
|
import {
|
|
121
121
|
Xano,
|
|
122
122
|
workspace
|
|
123
|
-
} from "./chunk-
|
|
123
|
+
} from "./chunk-MEFMTICH.js";
|
|
124
124
|
import "./chunk-V5Y7D4LH.js";
|
|
125
125
|
import {
|
|
126
126
|
LAMBDA_BINDINGS,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
assertBundleInput,
|
|
3
3
|
loadBundleText
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-OONT4ZL4.js";
|
|
5
|
+
import "./chunk-RLI6XD4O.js";
|
|
6
6
|
import "./chunk-7WRJPKGK.js";
|
|
7
7
|
import "./chunk-3LQGF2WS.js";
|
|
8
8
|
import "./chunk-Z2ZIE5CO.js";
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
success,
|
|
16
16
|
warn
|
|
17
17
|
} from "./chunk-EZG76F7R.js";
|
|
18
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-MEFMTICH.js";
|
|
19
19
|
import "./chunk-V5Y7D4LH.js";
|
|
20
20
|
import "./chunk-N74KDCBD.js";
|
|
21
21
|
import "./chunk-EETVJZAZ.js";
|
|
@@ -121,4 +121,4 @@ function fmt(v) {
|
|
|
121
121
|
export {
|
|
122
122
|
runPreflightCommand
|
|
123
123
|
};
|
|
124
|
-
//# sourceMappingURL=preflight-command-
|
|
124
|
+
//# sourceMappingURL=preflight-command-UYE7SUQV.js.map
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
assertBundleInput,
|
|
8
8
|
loadBundleText
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-OONT4ZL4.js";
|
|
10
10
|
import {
|
|
11
11
|
sharedSchemaChanges
|
|
12
12
|
} from "./chunk-AOFFKSJC.js";
|
|
@@ -37,7 +37,7 @@ import "./chunk-NDP7OUPS.js";
|
|
|
37
37
|
import "./chunk-AE3PDSDS.js";
|
|
38
38
|
import {
|
|
39
39
|
resolveLockPath
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-RLI6XD4O.js";
|
|
41
41
|
import "./chunk-7WRJPKGK.js";
|
|
42
42
|
import {
|
|
43
43
|
readLockFile
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
success,
|
|
58
58
|
warn
|
|
59
59
|
} from "./chunk-EZG76F7R.js";
|
|
60
|
-
import "./chunk-
|
|
60
|
+
import "./chunk-MEFMTICH.js";
|
|
61
61
|
import "./chunk-V5Y7D4LH.js";
|
|
62
62
|
import "./chunk-N74KDCBD.js";
|
|
63
63
|
import "./chunk-EETVJZAZ.js";
|
|
@@ -447,7 +447,7 @@ async function runReleaseCommand(args) {
|
|
|
447
447
|
{ withSeed: req.records === true }
|
|
448
448
|
);
|
|
449
449
|
if (args.static !== void 0) {
|
|
450
|
-
const { assertNoSeedLeaks } = await import("./deploy-command-
|
|
450
|
+
const { assertNoSeedLeaks } = await import("./deploy-command-CGVKRWUE.js");
|
|
451
451
|
await assertNoSeedLeaks(args.static, nonPublicSeedValues, args.allowSeedInStatic);
|
|
452
452
|
}
|
|
453
453
|
const workspaceId = auth.workspaceId;
|
|
@@ -589,7 +589,7 @@ Retry, or drop \`--backup-branch\` to release without one.`,
|
|
|
589
589
|
...backupLabel !== void 0 ? { backupBranch: backupLabel } : {}
|
|
590
590
|
};
|
|
591
591
|
if (args.static !== void 0) {
|
|
592
|
-
const { buildStaticEnv, deployStaticTo } = await import("./deploy-command-
|
|
592
|
+
const { buildStaticEnv, deployStaticTo } = await import("./deploy-command-CGVKRWUE.js");
|
|
593
593
|
const env = buildStaticEnv(auth.instance, args.staticEnv);
|
|
594
594
|
const explicit = Object.keys(args.staticEnv).length > 0;
|
|
595
595
|
summary.static = await deployStaticTo(
|
|
@@ -608,4 +608,4 @@ Retry, or drop \`--backup-branch\` to release without one.`,
|
|
|
608
608
|
export {
|
|
609
609
|
runReleaseCommand
|
|
610
610
|
};
|
|
611
|
-
//# sourceMappingURL=release-command-
|
|
611
|
+
//# sourceMappingURL=release-command-CMMYT6XK.js.map
|
|
@@ -5,6 +5,9 @@ import {
|
|
|
5
5
|
// src/emit/routes-manifest.ts
|
|
6
6
|
var RouteManifestError = class extends Error {
|
|
7
7
|
};
|
|
8
|
+
function routeKey(route) {
|
|
9
|
+
return `${route.verb} ${route.name}`;
|
|
10
|
+
}
|
|
8
11
|
function literal(value) {
|
|
9
12
|
return JSON.stringify(value);
|
|
10
13
|
}
|
|
@@ -70,31 +73,33 @@ ${REALTIME_IMPLEMENTATION}`;
|
|
|
70
73
|
}
|
|
71
74
|
function renderRouteManifest(routes, realtime) {
|
|
72
75
|
const sorted = [...routes].sort(
|
|
73
|
-
(a, b) => a.canonical.localeCompare(b.canonical) || a.name.localeCompare(b.name)
|
|
76
|
+
(a, b) => a.canonical.localeCompare(b.canonical) || a.name.localeCompare(b.name) || a.verb.localeCompare(b.verb)
|
|
74
77
|
);
|
|
75
|
-
const seen = /* @__PURE__ */ new
|
|
78
|
+
const seen = /* @__PURE__ */ new Map();
|
|
76
79
|
const rows = sorted.map((route) => {
|
|
77
|
-
|
|
80
|
+
const key = routeKey(route);
|
|
81
|
+
const clash = seen.get(key);
|
|
82
|
+
if (clash !== void 0) {
|
|
78
83
|
throw new RouteManifestError(
|
|
79
|
-
`Two endpoints are both
|
|
84
|
+
`Two endpoints are both "${key}" \u2014 one in the api group whose canonical is "${clash}", one in "${route.canonical}". The route manifest keys on "<VERB> <name>", so a verb+name pair must be unique across api groups. Rename one, or give it a different verb.`
|
|
80
85
|
);
|
|
81
86
|
}
|
|
82
|
-
seen.
|
|
83
|
-
const params = parsePathParams(`route "${
|
|
87
|
+
seen.set(key, route.canonical);
|
|
88
|
+
const params = parsePathParams(`route "${key}"`, route.name);
|
|
84
89
|
const path = `/api:${route.canonical}/${route.name.replace(/^\/+/, "")}`;
|
|
85
|
-
return { ...route, params, path };
|
|
90
|
+
return { ...route, key, params, path };
|
|
86
91
|
});
|
|
87
92
|
const entries = rows.map(
|
|
88
|
-
(r) => ` ${literal(r.
|
|
93
|
+
(r) => ` ${literal(r.key)}: { verb: ${literal(r.verb)}, path: ${literal(r.path)} },`
|
|
89
94
|
);
|
|
90
95
|
const realtimeSection = realtime && (realtime.servers.length > 0 || realtime.channels.length > 0) ? renderRealtime(realtime) : "";
|
|
91
96
|
return `${HEADER}${FILL_PARAMS}
|
|
92
97
|
export const ROUTES = ${objectLiteral(entries)} as const;
|
|
93
98
|
|
|
94
|
-
/** Every endpoint
|
|
99
|
+
/** Every endpoint in this workspace, keyed \`"<VERB> <name>"\` (e.g. \`"GET listings"\`). */
|
|
95
100
|
export type RouteName = keyof typeof ROUTES;
|
|
96
101
|
|
|
97
|
-
${overloadsFor("routePath", rows)}
|
|
102
|
+
${overloadsFor("routePath", rows.map((r) => ({ name: r.key, params: r.params })))}
|
|
98
103
|
${IMPLEMENTATION}${realtimeSection}`;
|
|
99
104
|
}
|
|
100
105
|
var HEADER = `/**
|
|
@@ -157,7 +162,12 @@ export function routePath(name: RouteName, params?: Record<string, string | numb
|
|
|
157
162
|
// Read through a widened view: a workspace with no endpoints at all makes
|
|
158
163
|
// \`RouteName\` \`never\`, which cannot index the literal type.
|
|
159
164
|
const route = (ROUTES as Record<string, { verb: string; path: string } | undefined>)[name];
|
|
160
|
-
if (!route)
|
|
165
|
+
if (!route) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
\`routePath: unknown route "\${String(name)}". Routes are keyed "<VERB> <name>", \` +
|
|
168
|
+
'e.g. "GET listings" \u2014 regenerate the manifest if the endpoint is new.',
|
|
169
|
+
);
|
|
170
|
+
}
|
|
161
171
|
return fillParams(\`routePath("\${String(name)}")\`, "route", route.path, params, true);
|
|
162
172
|
}
|
|
163
173
|
`;
|
|
@@ -239,6 +249,7 @@ export function socketUrl(
|
|
|
239
249
|
`;
|
|
240
250
|
export {
|
|
241
251
|
RouteManifestError,
|
|
242
|
-
renderRouteManifest
|
|
252
|
+
renderRouteManifest,
|
|
253
|
+
routeKey
|
|
243
254
|
};
|
|
244
|
-
//# sourceMappingURL=routes-manifest-
|
|
255
|
+
//# sourceMappingURL=routes-manifest-MN6XBYRE.js.map
|
|
@@ -4763,13 +4763,24 @@ interface RealtimeServerTriggerInputs {
|
|
|
4763
4763
|
/** The connecting client — `permissions` gates its realtime row/table access. */
|
|
4764
4764
|
client: RealtimeClient;
|
|
4765
4765
|
}
|
|
4766
|
-
/** Realtime channel lifecycle trigger inputs (join / leave). */
|
|
4766
|
+
/** Realtime channel lifecycle trigger inputs (join / leave / deliver). */
|
|
4767
4767
|
interface RealtimeChannelTriggerInputs {
|
|
4768
|
-
/** The membership action (`"join"` | `"leave"`). */
|
|
4768
|
+
/** The membership action (`"join"` | `"leave"` | `"deliver"`). */
|
|
4769
4769
|
action: Value;
|
|
4770
4770
|
/** The channel path the client addressed. */
|
|
4771
4771
|
channel: Value;
|
|
4772
|
-
/**
|
|
4772
|
+
/**
|
|
4773
|
+
* The message body on a `deliver` run, null on join/leave. It arrives NESTED,
|
|
4774
|
+
* so read a field as `t.payload("text")`. A flat `inp("text")` names an input
|
|
4775
|
+
* this trigger does not declare and RAISES at runtime, which for `deliver`
|
|
4776
|
+
* means the hook fails open and the recipient gets the original.
|
|
4777
|
+
*/
|
|
4778
|
+
payload: FieldAccessor;
|
|
4779
|
+
/**
|
|
4780
|
+
* The client — the JOINING client on join/leave, and the SENDING client on
|
|
4781
|
+
* `deliver` (the recipient that run is for is `s.realtime.get_session`).
|
|
4782
|
+
* `permissions` gates its realtime row/table access.
|
|
4783
|
+
*/
|
|
4773
4784
|
client: RealtimeClient;
|
|
4774
4785
|
}
|
|
4775
4786
|
/** Toolset trigger inputs (MCP server / agent). */
|
|
@@ -5414,8 +5425,7 @@ interface RealtimeActions {
|
|
|
5414
5425
|
* Same return shape as a channel `join`: `{ allowed: c.bool(true) }` or any truthy value
|
|
5415
5426
|
* admits, and an EMPTY OR FALSY return DENIES — including a gating trigger with
|
|
5416
5427
|
* no `response`, which returns nothing and so refuses every client. A CRASH also
|
|
5417
|
-
* DENIES:
|
|
5418
|
-
* it when the stack throws, because a gate that cannot answer must not admit.
|
|
5428
|
+
* DENIES: a gate that cannot answer must not admit.
|
|
5419
5429
|
*
|
|
5420
5430
|
* So both failure modes lock the door rather than open it, and the risk to plan
|
|
5421
5431
|
* for is a self-inflicted lockout — an unguarded drill into a `db.get` that
|
|
@@ -5444,16 +5454,24 @@ interface RealtimeServerActions {
|
|
|
5444
5454
|
* optional `reason` surfaces in the client's error frame) or any other truthy
|
|
5445
5455
|
* value to admit. AN EMPTY OR FALSY RETURN DENIES — a stack that just falls
|
|
5446
5456
|
* through, or a gating trigger with no `response`, refuses the join. A CRASH
|
|
5447
|
-
* DENIES TOO
|
|
5448
|
-
*
|
|
5449
|
-
*
|
|
5450
|
-
*
|
|
5451
|
-
*
|
|
5452
|
-
*
|
|
5453
|
-
* `
|
|
5454
|
-
*
|
|
5455
|
-
*
|
|
5456
|
-
*
|
|
5457
|
+
* DENIES TOO, which is the INVERSE of a normal message: a message whose
|
|
5458
|
+
* stack crashes still delivers, so one workspace bug cannot black-hole a
|
|
5459
|
+
* channel. Note the asymmetry with `deliver` below, which is a hook that
|
|
5460
|
+
* fails OPEN.
|
|
5461
|
+
*
|
|
5462
|
+
* A lifecycle trigger's inputs are PINNED to `action`/`channel`/`payload`/
|
|
5463
|
+
* `client`, so a channel path param is NOT among them: `inp("room_id")`
|
|
5464
|
+
* RAISES inside a gate, which crashes it and so refuses every client. Take
|
|
5465
|
+
* the param from `s.realtime.get_session` under `params`
|
|
5466
|
+
* (`ref("session.params.room_id")`) and the gate can decide per room. A
|
|
5467
|
+
* SERVER `connect`/`disconnect` trigger has no channel and so no params
|
|
5468
|
+
* at all.
|
|
5469
|
+
*
|
|
5470
|
+
* A gate also establishes NO auth, so `ref("auth.id")` reads 0 even for an
|
|
5471
|
+
* authenticated client — identity is `t.client("permissions.dbo_id")` (0 is
|
|
5472
|
+
* anonymous) or the session. And once the returned object carries an
|
|
5473
|
+
* `allowed` key, admission needs STRICTLY `true`: a computed `1` or `"yes"`
|
|
5474
|
+
* in that shape DENIES, so produce a real bool.
|
|
5457
5475
|
* - `leave` is OBSERVATIONAL (return ignored, throws swallowed).
|
|
5458
5476
|
* - `deliver` GATES delivery PER RECIPIENT — it runs once for each client the
|
|
5459
5477
|
* message is about to reach. It is the heaviest of the three by a wide
|
|
@@ -5468,7 +5486,7 @@ interface RealtimeServerActions {
|
|
|
5468
5486
|
* null instead.
|
|
5469
5487
|
*
|
|
5470
5488
|
* The delivered payload arrives NESTED under `payload`, so read
|
|
5471
|
-
* `
|
|
5489
|
+
* `t.payload("<field>")`. And the two identities differ: `t.client` is the
|
|
5472
5490
|
* SENDER, while `s.realtime.get_session` describes the RECIPIENT this run is
|
|
5473
5491
|
* for — per-viewer redaction needs both, and reaching for the wrong one is
|
|
5474
5492
|
* silent.
|
|
@@ -21,8 +21,8 @@ import {
|
|
|
21
21
|
registryUrl,
|
|
22
22
|
suppressUpdateNotice,
|
|
23
23
|
upgradeCommand
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-2AY3PKF4.js";
|
|
25
|
+
import "./chunk-RLI6XD4O.js";
|
|
26
26
|
import "./chunk-7WRJPKGK.js";
|
|
27
27
|
import "./chunk-3LQGF2WS.js";
|
|
28
28
|
import "./chunk-Z2ZIE5CO.js";
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
success,
|
|
36
36
|
warn
|
|
37
37
|
} from "./chunk-EZG76F7R.js";
|
|
38
|
-
import "./chunk-
|
|
38
|
+
import "./chunk-MEFMTICH.js";
|
|
39
39
|
import "./chunk-V5Y7D4LH.js";
|
|
40
40
|
import "./chunk-N74KDCBD.js";
|
|
41
41
|
import "./chunk-EETVJZAZ.js";
|
|
@@ -175,4 +175,4 @@ function messageOf(err) {
|
|
|
175
175
|
export {
|
|
176
176
|
runUpgradeCommand
|
|
177
177
|
};
|
|
178
|
-
//# sourceMappingURL=upgrade-command-
|
|
178
|
+
//# sourceMappingURL=upgrade-command-A75DOIUH.js.map
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "./chunk-NUQCEOKA.js";
|
|
12
12
|
import {
|
|
13
13
|
fetchWorkspaceBundle
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-SS2V2QOG.js";
|
|
15
15
|
import "./chunk-RQ3FXV4K.js";
|
|
16
16
|
import "./chunk-K5IOND4K.js";
|
|
17
17
|
import {
|
|
@@ -26,18 +26,18 @@ import {
|
|
|
26
26
|
fetchOrExplain,
|
|
27
27
|
httpFailure
|
|
28
28
|
} from "./chunk-NDP7OUPS.js";
|
|
29
|
-
import "./chunk-
|
|
29
|
+
import "./chunk-S3DOJOW4.js";
|
|
30
30
|
import "./chunk-VK26K7AY.js";
|
|
31
31
|
import "./chunk-ZSYZTGJH.js";
|
|
32
32
|
import "./chunk-YX22LKQE.js";
|
|
33
33
|
import "./chunk-6VNRMKFJ.js";
|
|
34
34
|
import "./chunk-RQNMTDXD.js";
|
|
35
35
|
import "./chunk-PR7OXHGZ.js";
|
|
36
|
-
import "./chunk-
|
|
36
|
+
import "./chunk-BYQHCCYU.js";
|
|
37
37
|
import "./chunk-EHP3WPEG.js";
|
|
38
38
|
import "./chunk-AE3PDSDS.js";
|
|
39
39
|
import "./chunk-DCMANKMX.js";
|
|
40
|
-
import "./chunk-
|
|
40
|
+
import "./chunk-RLI6XD4O.js";
|
|
41
41
|
import "./chunk-7WRJPKGK.js";
|
|
42
42
|
import "./chunk-3LQGF2WS.js";
|
|
43
43
|
import {
|
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
step,
|
|
52
52
|
success
|
|
53
53
|
} from "./chunk-EZG76F7R.js";
|
|
54
|
-
import "./chunk-
|
|
54
|
+
import "./chunk-MEFMTICH.js";
|
|
55
55
|
import "./chunk-V5Y7D4LH.js";
|
|
56
56
|
import "./chunk-N74KDCBD.js";
|
|
57
57
|
import "./chunk-EETVJZAZ.js";
|
|
@@ -160,4 +160,4 @@ async function runExport(args) {
|
|
|
160
160
|
export {
|
|
161
161
|
runWorkspaceCommand
|
|
162
162
|
};
|
|
163
|
-
//# sourceMappingURL=workspace-command-
|
|
163
|
+
//# sourceMappingURL=workspace-command-YELP47SJ.js.map
|
package/guides/typed-frontend.md
CHANGED
|
@@ -172,15 +172,32 @@ xanots routes ./xano/index.ts --emit xano/routes.gen.ts
|
|
|
172
172
|
```
|
|
173
173
|
|
|
174
174
|
The emitted file is plain data plus one interpolator and imports nothing at all — the same
|
|
175
|
-
app builds to 1.3 kB, a ~200x saving, with no SDK code in the output. Route
|
|
176
|
-
time, so a backend rename is a compile error
|
|
175
|
+
app builds to 1.3 kB, a ~200x saving, with no SDK code in the output. Route keys and their
|
|
176
|
+
`{param}` names are still checked at compile time, so a backend rename is a compile error
|
|
177
|
+
rather than a 404:
|
|
177
178
|
|
|
178
179
|
```ts
|
|
179
180
|
import { routePath, ROUTES } from "../xano/routes.gen";
|
|
180
181
|
|
|
181
|
-
fetch(BASE + routePath("blog/{slug}", { slug }), {
|
|
182
|
+
fetch(BASE + routePath("GET blog/{slug}", { slug }), {
|
|
183
|
+
method: ROUTES["GET blog/{slug}"].verb,
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
A route key is `"<VERB> <name>"`, which is the endpoint identity the engine itself uses —
|
|
188
|
+
so verb-differentiated siblings are ordinary, and a REST-shaped group emits without
|
|
189
|
+
renaming anything:
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
routePath("GET listings"); // list
|
|
193
|
+
routePath("POST listings"); // create
|
|
194
|
+
routePath("PATCH listings/{id}", { id }); // update
|
|
182
195
|
```
|
|
183
196
|
|
|
197
|
+
The verb comes first so the key is stable: adding a `POST` sibling never renames the `GET`
|
|
198
|
+
that was already there. Two api groups holding the same verb AND name is the one shape a
|
|
199
|
+
single manifest cannot express, and the emit fails naming both rather than picking one.
|
|
200
|
+
|
|
184
201
|
Realtime is in the same file when the workspace has any: `socketUrl(server, baseUrl)` for the
|
|
185
202
|
websocket URL and `channelPath(channel, params)` for the path a frame's `channel` field takes,
|
|
186
203
|
both keyed and `{param}`-checked exactly like the routes. `socketUrl` is the equivalent of
|
package/llms/kinds-realtime.md
CHANGED
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
- `deliverTo?`: `"channel"` (default) | `"sender"` | `"others"` | `"explicit"`. ⚠ `"explicit"` still delivers to NOBODY — nothing selects recipients from inside a handler, and `s.realtime.publish` (which originates an event INTO a channel) is not a substitute.
|
|
21
21
|
- Only `"channel"`/`"others"` fan out AND are written to the `conversation` transcript — a `"sender"` response is invisible to every future joiner.
|
|
22
22
|
- **Both input surfaces read as ordinary inputs:** `inp("body")` for a payload field, `inp("room_id")` for the channel's `{room_id}`. No session lookup, no frame parsing.
|
|
23
|
-
- A path param is bound ONCE at join and read from the connection thereafter, never from the frame — a sender cannot claim a room it did not join.
|
|
23
|
+
- A path param is bound ONCE at join and read from the connection thereafter, never from the frame — a sender cannot claim a room it did not join.
|
|
24
24
|
- `s.realtime.get_session({ as })` — the CALLER's realtime session for the current frame. FLAT shape:
|
|
25
25
|
- `authenticated` bool · `client_id` text (the AUTHED ROW ID as text, `""` anonymous) · `dbo_id` int (the auth TABLE's id — NOT the user's row id; `0` anonymous — to look the caller up use `client_id`. `dbo_id` is an int in the same position and typechecks, so a gate that keys on it finds no user and refuses EVERYONE) · `socket_id` int (transport id) · `channel` text (resolved path, `""` in a server trigger) · `params` object (bound path params, `{}` when none — `ref("session.params.room_id")`) · `extras` object · `opened_at` decimal.
|
|
26
26
|
- Works in a realtime MESSAGE stack and in CHANNEL and SERVER trigger stacks; off that path it degrades to an anonymous session.
|
|
27
|
-
- For a path param prefer `inp("room_id")
|
|
27
|
+
- For a path param prefer `inp("room_id")` in a MESSAGE; a lifecycle TRIGGER has only the session. Reach for the session when you need the CONNECTION (identity/extras) — "who is this sender" on an anonymous-client channel.
|
|
28
28
|
- ⚠ THREE UNRELATED THINGS ARE CALLED A CLIENT ID: `session.client_id` (app-facing identity), `session.socket_id` (transport), and a frame's `options.client_id` (the at_least_once CURSOR handle). Conflating the first and last breaks at_least_once for anonymous clients.
|
|
29
29
|
- `s.realtime.publish({ server, channel, data, message?, authTable?, authId? })` — the PUSH direction: originate a server-authored event onto a channel from ANY stack, no client frame first.
|
|
30
30
|
- `server` is the handle or its NAME (resolved by name, not guid); `channel` is the FILLED-IN path (`channel.getChannel({ room_id: 42 })`), never the template — a constant still carrying `{param}` THROWS at author time, and a constant `server`/`channel` naming nothing this workspace registers WARNS at export.
|
package/llms/tests.md
CHANGED
|
@@ -42,7 +42,7 @@ The run is isolated in ways that make a correct test fail for reasons the failur
|
|
|
42
42
|
|
|
43
43
|
- The run uses an EMPTY datasource, so **no `table({ seed })` rows exist while it runs** and every `db` read misses. A test that buys seeded row 1 fails with its own precondition message, which reads as a wrong id rather than an empty database. Create what the test needs INSIDE the test — typically a `defineFunction` fixture the stack calls first.
|
|
44
44
|
- `s.api.call` does NOT raise when the endpoint answers with an error. It BINDS the error envelope (`{code, message}`) to its `as` and carries on, so a later `s.expect.to_be_defined({ expr: ref("r.field") })` reports the ASSERTION while the real failure was the call, four statements up. Assert on the envelope — `s.expect.to_contain({ expr: ref("r.code"), value: c.text("ERROR_CODE_INPUT_ERROR") })` — when a call may fail. `s.function.run` raises instead; the two disagree.
|
|
45
|
-
- `s.expect.to_throw({ body, exception? })` runs `body` in an ISOLATED var stack, so a variable bound EARLIER in the test is not visible inside it — bind what the body needs inside the body. `exception` is a `Value` whose text the raised message must CONTAIN (`c.text("already exists")`, not a bare string); omit it to accept any error.
|
|
45
|
+
- `s.expect.to_throw({ body, exception? })` runs `body` in an ISOLATED var stack, so a variable bound EARLIER in the test is not visible inside it — bind what the body needs inside the body. An outer one raises `Missing var entry: <name>` there, which the test reports as `to_throw` not matching (`export()` warns). `exception` is a `Value` whose text the raised message must CONTAIN (`c.text("already exists")`, not a bare string); omit it to accept any error.
|
|
46
46
|
- `s.expect.to_throw` catches such a call only when the error carries a MESSAGE. `ERROR_CODE_ACCESS_DENIED` arrives with an empty one, so `to_throw` around an auth-refused call reports `to_throw failed - response is ok` — which reads as a broken auth gate on a gate that works.
|
|
47
47
|
- An endpoint's `auth` gate is NOT enforced on `s.api.call`. A `query({ auth: users })` runs anyway and fails only where its stack dereferences `auth(...)`. A stack that never touches `auth(...)` runs unauthenticated and passes.
|
|
48
48
|
- Neither `auth.token` nor an `Authorization` entry in `headers` authenticates the call — a token that answers 200 over real HTTP is refused here. To cover auth-gated logic, move the body into a `defineFunction` taking the user id and `s.function.call` that; the gate itself is not reachable from a workflow test.
|
package/llms/triggers.md
CHANGED
|
@@ -15,8 +15,8 @@ realtimeChannelTrigger, mcpServerTrigger, agentTrigger, workspaceTrigger,
|
|
|
15
15
|
errorTrigger}({ name, guid?, description?, active?, tags?, ... })`.
|
|
16
16
|
|
|
17
17
|
- `tableTrigger({ name, table?, datasources?, actions?: {insert?,update?,delete?,truncate?}, stack })` — database/table trigger. `t.new` / `t.old` are the row **after** / **before** the change; `t.action` (`insert|update|delete|truncate`), `t.datasource`. Bind `table` to a `table()` handle and `t.new("col")` / `t.old("col")` are typed to that row (misspelled column = compile error). Nullability follows the enabled actions: insert → `old` is null, delete → `new` is null, update → both, truncate → neither. Config-only (no response).
|
|
18
|
-
- `realtimeServerTrigger({ name, realtimeServer, actions?: {connect?,disconnect?}, stack?, response?, responseShape? })` — realtime SERVER lifecycle (a client connecting to / disconnecting from the server, not a message). Inputs: `t.action` (`connect|disconnect`), `t.realtime_server`, `t.client`. Bind `realtimeServer` to a `realtimeServer()` handle (or its name). `connect` GATES the connection — a denial sends an `error` and CLOSES the socket with code 4401 before it is ever ready, so it is a real front door, not an observer; same return shape as a channel `join`
|
|
19
|
-
- `realtimeChannelTrigger({ name, channel, actions?: {join?,leave?,deliver?}, stack?, response?, responseShape? })` — realtime CHANNEL lifecycle. Inputs: `t.action` (`join|leave|deliver`), `t.channel`, `t.client`. Bind `channel` to a `realtimeChannel()` handle — a bare path is NOT accepted (it is unique only within its server). The three actions have DIFFERENT postures, and the posture decides what the stack should return: `join` GATES the join (it runs BEFORE the client becomes a member, so a denial means it never sees a fan-out) — return `{ allowed: c.bool(true) }` (optional `reason` reaches the client) or any truthy value to admit, and an EMPTY OR FALSY RETURN DENIES, so a stack that just falls through — or a gating trigger with NO `response` — refuses everyone, and a CRASH DENIES too. That is the inverse of a
|
|
18
|
+
- `realtimeServerTrigger({ name, realtimeServer, actions?: {connect?,disconnect?}, stack?, response?, responseShape? })` — realtime SERVER lifecycle (a client connecting to / disconnecting from the server, not a message). Inputs: `t.action` (`connect|disconnect`), `t.realtime_server`, `t.client`. Bind `realtimeServer` to a `realtimeServer()` handle (or its name). `connect` GATES the connection — a denial sends an `error` and CLOSES the socket with code 4401 before it is ever ready, so it is a real front door, not an observer; same return shape as a channel `join` below (EMPTY/FALSY DENIES — INCLUDING a gating trigger with NO `response`, which returns nothing and so refuses every client). A CRASH DENIES too — a gate that cannot answer must not admit. Both failure modes lock the door, so plan for a self-inflicted LOCKOUT (an unguarded drill into a null `db.get` raises → everyone refused), not a breach. Gating is OPT-IN: a server with no `connect` trigger accepts every connection. `disconnect` is OBSERVATIONAL (return ignored, throws swallowed — cleanup must always complete). Both are SERVER-scoped, so `s.realtime.get_session` works but carries no channel path and no bound params.
|
|
19
|
+
- `realtimeChannelTrigger({ name, channel, actions?: {join?,leave?,deliver?}, stack?, response?, responseShape? })` — realtime CHANNEL lifecycle. Inputs: `t.action` (`join|leave|deliver`), `t.channel`, `t.payload`, `t.client`. Bind `channel` to a `realtimeChannel()` handle — a bare path is NOT accepted (it is unique only within its server). The three actions have DIFFERENT postures, and the posture decides what the stack should return: `join` GATES the join (it runs BEFORE the client becomes a member, so a denial means it never sees a fan-out) — return `{ allowed: c.bool(true) }` (optional `reason` reaches the client) or any truthy value to admit, and an EMPTY OR FALSY RETURN DENIES, so a stack that just falls through — or a gating trigger with NO `response` — refuses everyone, and a CRASH DENIES too. ONCE the object carries an `allowed` key admission needs STRICTLY `true` — a computed `1`/`"yes"` there DENIES. That is the inverse of a crashing message, which still delivers, and of `deliver` below. A lifecycle trigger's inputs are PINNED to those four, so a channel PATH PARAM is NOT among them — `inp("room_id")` RAISES, which crashes the gate and so REFUSES every client; take the param from `s.realtime.get_session` (`ref("session.params.room_id")`). A gate establishes NO auth, so `ref("auth.id")` reads 0 even when authenticated — identity is `t.client("permissions.dbo_id")` or the session. A SERVER connect/disconnect has no channel, so no params at all; `leave` is OBSERVATIONAL (return ignored, throws swallowed); `deliver` GATES delivery PER RECIPIENT — the per-viewer redaction tool and the most expensive action here (a stack per recipient per message), and it needs `delivery.perRecipient` on the channel to run at all — BOTH HALVES are required, so a `deliver` trigger on a channel without the flag NEVER RUNS and every subscriber receives the UNREDACTED payload (no error, no log line); `export()` warns on each half alone. **`deliver`'s RETURN VALUES DO NOT READ LIKE A FILTER:** ONLY an explicit NULL drops the message for that recipient; an OBJECT replaces that recipient's payload; ANYTHING ELSE — INCLUDING `false`, `0`, `""` — DELIVERS IT UNCHANGED, as does a crash. So `return false` from a yes/no redaction check SENDS the message it was written to suppress — return null instead. The delivered payload arrives NESTED, so read `t.payload("<field>")`, and `t.client` is the SENDER while `s.realtime.get_session` describes the RECIPIENT this run is for.
|
|
20
20
|
- `mcpServerTrigger({ name, mcpServer, stack?, response?, responseShape? })` / `agentTrigger({ name, agent, stack?, response?, responseShape? })` — toolset connection. Bind with the `mcpServer()`/`agent()` def handle (or its name) — it resolves to the toolset guid at export. Raw numeric `objId` is the escape hatch, rarely right: ids are assigned at import, so a handle passed to `objId` is a type error, and binding nothing deploys a trigger that never fires. Inputs: `t.toolset` (`t.toolset("name")`), `t.tools`. Response-bearing; the default stack copies `toolset`/`tools` into vars and returns them.
|
|
21
21
|
- `workspaceTrigger({ name, actions?: {branch_live?,branch_merge?,branch_new?}, stack? })` — branch lifecycle. Inputs: `t.to_branch`, `t.from_branch`, `t.action`. Config-only.
|
|
22
22
|
- `errorTrigger({ name, stack? })` — error-signature trigger. Inputs: `t.event` (`new|regression|fixed`), `t.id`, `t.signature`, `t.error` (`t.error("code")`/`t.error("message")`), `t.caller`, `t.statement`, `t.actor`, `t.count`, `t.first_seen`, `t.last_seen`, `t.fixed_at`. Config-only.
|