@xano/sdk 1.0.12 → 1.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.
Files changed (121) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +8 -8
  3. package/dist/.build-fingerprint +1 -1
  4. package/dist/{agent-file-refresh-YM5VRRHE.js → agent-file-refresh-DAFGNMQX.js} +4 -4
  5. package/dist/{agent-skill-command-GVVCBAGF.js → agent-skill-command-6M46ZGOL.js} +13 -13
  6. package/dist/{backend-dir-NZOLU7TL.js → backend-dir-J2J7JNS6.js} +4 -4
  7. package/dist/bin.js +13 -13
  8. package/dist/{branch-commands-Q46PCVHU.js → branch-commands-BUKVE637.js} +3 -3
  9. package/dist/{chunk-2PAVJ3QD.js → chunk-5ONWBQ2C.js} +2 -2
  10. package/dist/{chunk-ETMP7SJ3.js → chunk-5SMUND4J.js} +3 -3
  11. package/dist/{chunk-UZ55F3UK.js → chunk-5XDKKE5Y.js} +2 -2
  12. package/dist/{chunk-WXLZCBPG.js → chunk-6HTXQAMG.js} +2 -2
  13. package/dist/{chunk-PBIV4DE2.js → chunk-6OOZJQJK.js} +39 -39
  14. package/dist/{chunk-2RDZDDPR.js → chunk-CGZSF756.js} +12 -12
  15. package/dist/{chunk-G3A3XKCS.js → chunk-DPSR5GRE.js} +20 -20
  16. package/dist/{chunk-DH32QXVI.js → chunk-EKS7SAZS.js} +16 -16
  17. package/dist/{chunk-2K2G5TSR.js → chunk-ENAUSLMP.js} +3 -3
  18. package/dist/{chunk-5RSPMSSQ.js → chunk-ENBGJJJH.js} +3 -3
  19. package/dist/{chunk-5SZSLAAC.js → chunk-FBWMKHLO.js} +1 -1
  20. package/dist/{chunk-MFEO3EHL.js → chunk-GRWYO2MS.js} +2 -2
  21. package/dist/{chunk-OKR66IGL.js → chunk-H6VVSGKN.js} +2 -2
  22. package/dist/{chunk-SAKWZG5I.js → chunk-HDANNK4A.js} +2 -2
  23. package/dist/{chunk-RNVGXJJZ.js → chunk-HEMWBHQS.js} +7 -7
  24. package/dist/{chunk-HA5Y645X.js → chunk-MLKJUEG3.js} +12 -12
  25. package/dist/{chunk-ANBIMJPM.js → chunk-NMHTB346.js} +3 -3
  26. package/dist/{chunk-RFB4EXM5.js → chunk-O6PWEJUV.js} +2 -2
  27. package/dist/{chunk-CPFWVB3V.js → chunk-P6HXDOFG.js} +6 -6
  28. package/dist/{chunk-7XOQXZ6W.js → chunk-QWWQM4XZ.js} +2 -2
  29. package/dist/{chunk-OK7CBTFW.js → chunk-RAGFXELQ.js} +2 -2
  30. package/dist/{chunk-4GSXWOBS.js → chunk-RQHXYL77.js} +2 -2
  31. package/dist/{chunk-HJSAGGHU.js → chunk-SBS2IYTN.js} +2 -2
  32. package/dist/{chunk-AMHAGMJM.js → chunk-TANWE2ZY.js} +53 -53
  33. package/dist/{chunk-EC5P4W2D.js → chunk-U4BGBU3R.js} +15 -15
  34. package/dist/{chunk-4COXXP55.js → chunk-UDCKYLBW.js} +2 -2
  35. package/dist/{chunk-EMAFZROF.js → chunk-UECNKDDA.js} +2 -2
  36. package/dist/{chunk-6IOBEJWA.js → chunk-UKC65HBQ.js} +2 -2
  37. package/dist/{chunk-JPAUQ7MK.js → chunk-VFRL4G72.js} +2 -2
  38. package/dist/{chunk-74NRFGL7.js → chunk-WQZCFVAD.js} +2 -2
  39. package/dist/{chunk-TOW4EJON.js → chunk-XL7EA62X.js} +2 -2
  40. package/dist/{chunk-SAYHY2N3.js → chunk-XYVPF63S.js} +2 -2
  41. package/dist/{chunk-WQNN6WLB.js → chunk-ZACMAKZE.js} +5 -5
  42. package/dist/{chunk-U5CTYBAN.js → chunk-ZGNWMGN3.js} +4 -4
  43. package/dist/{chunk-3XZ44H2E.js → chunk-ZISPEBNM.js} +5 -2
  44. package/dist/{chunk-LDSZPRGV.js → chunk-ZSMHS7BU.js} +2 -2
  45. package/dist/cli.js +12 -12
  46. package/dist/{codegen-command-H3HO7UFA.js → codegen-command-BAFON45M.js} +19 -19
  47. package/dist/{deploy-command-7PWQJ4VV.js → deploy-command-JW7R3BPW.js} +16 -16
  48. package/dist/{deploy-source-CJHEVGOS.js → deploy-source-ZUPLAL7L.js} +7 -7
  49. package/dist/{dev-env-sync-VVLYQUPR.js → dev-env-sync-W7OTV7OD.js} +13 -13
  50. package/dist/{env-example-refresh-GLFC2FTE.js → env-example-refresh-TS7WBVZQ.js} +20 -20
  51. package/dist/{env-pull-command-OY3SXNJC.js → env-pull-command-5IYXQ2WK.js} +13 -13
  52. package/dist/{env-target-PDDDAA5I.js → env-target-TQBPLU2S.js} +2 -2
  53. package/dist/{env-var-command-UTYDJN24.js → env-var-command-AKCWYZPB.js} +13 -13
  54. package/dist/{ephemeral-command-ALIHUF7G.js → ephemeral-command-SJYH6XRS.js} +14 -14
  55. package/dist/{generate-command-S37XFYPD.js → generate-command-FSCFZPOJ.js} +23 -23
  56. package/dist/{gitignore-DKDWGWPS.js → gitignore-6IJ66XME.js} +6 -6
  57. package/dist/{impersonate-command-HPCSKJAV.js → impersonate-command-IH4HMSS3.js} +9 -9
  58. package/dist/{init-command-RWXBXJPG.js → init-command-STB4YSAK.js} +15 -15
  59. package/dist/{init-modules-LFLW2PQC.js → init-modules-YIZYPCMM.js} +2 -2
  60. package/dist/internal.js +4 -4
  61. package/dist/{keep-data-merge-7JGGZKDM.js → keep-data-merge-VRKS64JK.js} +4 -4
  62. package/dist/{landing-record-QJV7KNS4.js → landing-record-5EFK7RI6.js} +5 -5
  63. package/dist/{local-engine-choice-NNSHE5FO.js → local-engine-choice-TRTEJVMV.js} +8 -8
  64. package/dist/{local-engine-command-UGIZ4UO6.js → local-engine-command-2FK2PE2P.js} +9 -9
  65. package/dist/{local-engine-mcp-command-YUSZC7MF.js → local-engine-mcp-command-FB7EOGG6.js} +9 -9
  66. package/dist/{lock-commands-VT4R2DEE.js → lock-commands-7PBZIRWR.js} +13 -13
  67. package/dist/{login-command-4D3KPQUY.js → login-command-2O6GRMTH.js} +9 -9
  68. package/dist/{logout-command-ALKHCJKS.js → logout-command-RZXGW3O2.js} +3 -3
  69. package/dist/{marketplace-command-64TE2NGV.js → marketplace-command-NCMLGIMS.js} +13 -13
  70. package/dist/{meta-client-7MLLUZB4.js → meta-client-DYYM5F5G.js} +2 -2
  71. package/dist/node.js +14 -14
  72. package/dist/{operation-outcome-TYAOVNOM.js → operation-outcome-SHNROAFA.js} +4 -4
  73. package/dist/{output-target-63ECBUX2.js → output-target-PSSR3E4N.js} +7 -7
  74. package/dist/plugin.d.ts +2 -1
  75. package/dist/{preflight-command-OUVAX5IJ.js → preflight-command-6F7JF3YQ.js} +18 -18
  76. package/dist/{profile-command-NUO5U2HQ.js → profile-command-5AOGD6GV.js} +10 -10
  77. package/dist/{promote-command-MGLAYQDY.js → promote-command-O2NRRFLK.js} +26 -26
  78. package/dist/{publish-command-KVGNFBSU.js → publish-command-6VVSJPLI.js} +16 -16
  79. package/dist/{pull-command-OVXIMVUB.js → pull-command-GE2WUEUF.js} +21 -21
  80. package/dist/{release-command-E54WUJKB.js → release-command-55RTR674.js} +18 -18
  81. package/dist/{release-ns-command-SLRL3O3W.js → release-ns-command-5XPZ2B6N.js} +31 -31
  82. package/dist/{routes-manifest-file-IX4TOZCO.js → routes-manifest-file-42FTJHRY.js} +2 -2
  83. package/dist/{secrets-file-4NQWGCJG.js → secrets-file-N5IF265R.js} +5 -5
  84. package/dist/{secrets-fill-command-5NNHSYFX.js → secrets-fill-command-35WKBURT.js} +15 -15
  85. package/dist/{source-resolve-HSJSVKUC.js → source-resolve-JXGOVJD3.js} +3 -3
  86. package/dist/{status-command-UFIMW7SZ.js → status-command-G3DFRMU7.js} +12 -12
  87. package/dist/{sync-contributions-35ZAYBUH.js → sync-contributions-7T4CSPVQ.js} +2 -2
  88. package/dist/{tables-command-TISOU6DR.js → tables-command-7NUOZBHX.js} +10 -10
  89. package/dist/{tenant-command-ITCPN43T.js → tenant-command-JGEHRKN7.js} +32 -32
  90. package/dist/{test-command-7SFAJ6HX.js → test-command-2LNEA6GK.js} +10 -10
  91. package/dist/{token-OXGOA6WE.js → token-DWNH44NW.js} +2 -2
  92. package/dist/{toolchain-modules-Q3Z6APPF.js → toolchain-modules-F4DUMWTO.js} +2 -2
  93. package/dist/{tracked-backend-IYTIZZYV.js → tracked-backend-ZFXVLBBJ.js} +9 -9
  94. package/dist/{update-check-LSCQRDRR.js → update-check-KBHT63GJ.js} +14 -14
  95. package/dist/{upgrade-command-RQEQJO5Y.js → upgrade-command-CI543AZP.js} +16 -16
  96. package/dist/{whoami-command-NT3FVBZM.js → whoami-command-77DXENWD.js} +4 -4
  97. package/dist/{workspace-5RHOJC7K.js → workspace-RI5C77BZ.js} +2 -2
  98. package/dist/{workspace-binding-YUU6KB53.js → workspace-binding-PR57NBGH.js} +3 -3
  99. package/dist/{workspace-command-QSJHX5RS.js → workspace-command-6HHVFQKW.js} +27 -27
  100. package/dist/{workspace-env-M7RYVJB3.js → workspace-env-2APJEASO.js} +5 -5
  101. package/dist/{xanosdk-import-4TLNYFKC.js → xanosdk-import-HBQH3ZBS.js} +2 -2
  102. package/dist/{xanosdk-project-4NH6332J.js → xanosdk-project-W45IR3Q7.js} +5 -5
  103. package/guides/authoring.md +13 -7
  104. package/guides/bundle.md +1 -1
  105. package/guides/cli.md +28 -18
  106. package/guides/codegen.md +3 -2
  107. package/guides/coverage.md +4 -3
  108. package/guides/deploying.md +17 -10
  109. package/guides/environment.md +12 -12
  110. package/guides/marketplace.md +12 -6
  111. package/guides/module-contract.md +11 -6
  112. package/guides/object-kinds.md +8 -5
  113. package/guides/scaffold.md +24 -12
  114. package/guides/typed-frontend.md +7 -6
  115. package/llms/kinds-knowledge.md +2 -2
  116. package/llms/object-kinds.md +2 -2
  117. package/llms-full.txt +6 -6
  118. package/llms.txt +2 -2
  119. package/manifest.json +2 -2
  120. package/package.json +1 -1
  121. package/skills/xano-backend/SKILL.md +2 -2
@@ -128,9 +128,12 @@ your module is only correct against the SDK versions whose shapes it understands
128
128
  range out with a floor and a ceiling, as above: the ceiling is the next major, so a module
129
129
  built for 1.x loads on every 1.x SDK and is refused on 2.0.
130
130
 
131
- That range is **enforced at load**, on every command that discovers modules. An SDK outside it
131
+ That range is **enforced at load**. On `export`, `deploy`, `preflight` and `init`, an SDK outside it
132
132
  is refused by name before your plugin file is imported, naming the range you asked for and the
133
- version it got. So the floor is the version whose shapes your hooks understand, not an
133
+ version it got. The `routes.gen.ts` writers (`routes --emit`, the marketplace's route refresh,
134
+ `pull`, `generate`) and the marketplace reconcile skip the module with a warning instead: it is
135
+ never imported, a routes writer keeps its previous block, and `routes --emit --strict` still
136
+ fails. So the floor is the version whose shapes your hooks understand, not an
134
137
  aspiration — declare it accurately and the SDK will never quietly run your module against a
135
138
  contract it was not built for. Ranges are read as `>=` / `>` / `<=` / `<` / `=` comparators,
136
139
  `^`, `~`, exact pins and `||` unions of those; a shape outside that subset is not refused, it
@@ -394,7 +397,7 @@ read than it is slow.
394
397
  | `BundleContext` | What it carries |
395
398
  |---|---|
396
399
  | `bundle.payload` | The compiled payload, keyed by payload key (`table`, `query`, `app`, ...). |
397
- | `entry` | The entry file the bundle came from. **Absent** on the `--bundle <path>` branch. |
400
+ | `entry` | The entry file the bundle came from. **Absent** on the `--bundle <path>` branch, and when `deploy` fetches a remote source (`release:main`). |
398
401
  | `cwd` | The project root every relative path resolves against. |
399
402
  | `command` | `"export"` or `"deploy"`. |
400
403
  | `frozen` | The run is `--frozen-lock` (or `export --check` / `deploy --to … --dry-run`, which imply it): a verification, not a write. |
@@ -403,7 +406,7 @@ read than it is slow.
403
406
 
404
407
  **`entry` is optional rather than a made-up path** so a plugin may decline the
405
408
  `--bundle <path>` branch, where the input is already-serialized text with no entry and no
406
- registry behind it. A tree rendered from a bundle the project did not compile describes
409
+ registry behind it, and a `deploy` from a fetched source, where nothing local was compiled. A tree rendered from a bundle the project did not compile describes
407
410
  something other than the source beside it.
408
411
 
409
412
  **Under `frozen` a plugin must compare and report, never write.** It is also the mode in which
@@ -470,8 +473,10 @@ const plugin: ToolchainPlugin = {
470
473
 
471
474
  Your module's section of the route manifest, `xano/routes.gen.ts`. It runs wherever that file
472
475
  is written: `xanosdk routes ./xano/index.ts --emit xano/routes.gen.ts` (the scaffold's
473
- `xano:routes`), `pull`, `generate`, and the refresh `marketplace install`, `reinstall` and
474
- `remove` make, so your block lands with your module.
476
+ `xano:routes`), `init --marketplace` when it writes the project's first manifest, `pull`,
477
+ `generate`, and the refresh `marketplace install`, `reinstall` and `remove` make, so your
478
+ block lands with your module. Not `init --from`: a project it creates has no module installed
479
+ yet, and the first `xano:routes` after an install adds your section.
475
480
 
476
481
  | `RoutesManifestContext` | What it carries |
477
482
  |---|---|
@@ -14,11 +14,14 @@ and the seven trigger factories below. Signatures and payload keys are in
14
14
  the types don't tell you.
15
15
 
16
16
  **A knowledge item's body is a file, and `mode` is a running cost.** `knowledge()` is the
17
- markdown a workspace's AI agents read before they act, and it is the one kind whose payload
17
+ markdown shared by every AI that builds this backend — Xano's AI builder, people authoring in
18
+ XanoScript, and your local coding agent, which reads the same `.md` files in the repo (deploy
19
+ and `pull` keep them in sync). An `agent()` run never reads it; put what that agent needs in
20
+ its `llm.systemPrompt`. It is the one kind whose payload
18
21
  is prose — so the body is named by path (`knowledgeFile("./runbook.md", import.meta.url)`)
19
- rather than written as a string, and `refs: knowledgeDir(...)` ships a whole folder the
20
- agent searches on demand — UTF-8 text files only (other content is refused), and a
21
- symlink is not followed. What the agent actually receives is decided by `type` and `mode`,
22
+ rather than written as a string, and `refs: knowledgeDir(...)` ships a whole folder Xano's AI
23
+ builder searches on demand — UTF-8 text files only (other content is refused), and a
24
+ symlink is not followed. What the builder actually receives is decided by `type` and `mode`,
22
25
  and nothing in the types warns you: an `agents.md` item is injected in full on every turn
23
26
  whatever `mode` says, `mode: "always"` spends the body's whole length on every request, and
24
27
  the default `mode: "auto"` sends only the name and `description` until a request matches.
@@ -173,7 +176,7 @@ realtimeMessage({
173
176
  name: "send", // `input` types the message PAYLOAD
174
177
  channel: room, // the handle carries the server too
175
178
  input: { body: input.text({ required: true }) },
176
- deliverTo: "channel", // or "sender" (request/response) / "others"
179
+ deliverTo: "channel", // or "sender" (request/response) / "others" / "explicit"
177
180
  stack: [s.debug.log({ value: inp("body") })],
178
181
  });
179
182
  ```
@@ -9,7 +9,10 @@ backend alone — see [No frontend, and existing apps](#no-frontend-and-existing
9
9
  (default: the folder name), `--theme <id>` / `--radius <len>` / `--dark <mode>` /
10
10
  `--font <id>` / `--font-mono <id>` / `--font-heading <id>` / `--icons <id>`
11
11
  (the look — see [Theming](#theming)), `--no-agents-md` (skip the `AGENTS.md`
12
- agent brief, which every coding agent reads and `init` writes by default),
12
+ agent brief, which every coding agent reads and `init` writes by default, and the
13
+ `.mcp.json` / `.cursor/mcp.json` configs that connect agents to the `xano-local`
14
+ MCP server), `--ai <preset|none>` (for scripted callers: `none` is `--no-agents-md`, and
15
+ any other value writes the one `AGENTS.md` every agent reads),
13
16
  `--marketplace <pkg>` (repeatable, comma-separated; installs add-ons and
14
17
  registers them — below), `--force` (write over what clashes when adding the backend to
15
18
  a non-empty folder; it lists the files and scripts it would overwrite and asks, `--yes`
@@ -109,11 +112,12 @@ the add-on puts on your workspace, what you have to supply, and the
109
112
  `xano/index.ts` registration to copy. Piped, it emits JSON; `--prompt` emits
110
113
  instructions written to be handed straight to a coding agent.
111
114
 
112
- That is `npm install` with two additions: add-ons are discoverable from `xanosdk
113
- --help`, and the command refuses before npm runs when you are not standing in a
114
- project — the mistake npm answers by silently writing to the wrong `package.json`.
115
- The package name is passed through exactly as typed, so version specifiers, tags,
116
- and third-party packages all work.
115
+ `install` resolves its argument through the marketplace before npm runs — a module's
116
+ package or its slug (`auth`), keeping any version or tag — and refuses a name the
117
+ marketplace does not list with **exit 8**; local paths, `file:`, tarball and git specs
118
+ install as given. It also refuses before npm runs when you are not standing in a project,
119
+ and reconciles afterwards, asking any toolchain module that arrived its questions. See
120
+ [Installing](marketplace.md#installing).
117
121
 
118
122
  ## No frontend, and existing apps
119
123
 
@@ -123,7 +127,8 @@ is a **new** project, and `--framework` decides its frontend. Any other director
123
127
 
124
128
  **A new project with `--framework none`** (or "No frontend" at the prompt) gets everything
125
129
  above except the frontend: `xano/`, a `package.json` with only the backend's scripts and
126
- dependencies, `.gitignore`, `.gitattributes`, the CI check, a README and `AGENTS.md`. There is
130
+ dependencies, `.gitignore`, `.gitattributes`, the CI check, a README, `AGENTS.md`, and the
131
+ `.mcp.json` / `.cursor/mcp.json` agent configs. There is
127
132
  no `frontend/` and no root `tsconfig.json`; `xano/` type-checks under its own
128
133
  `xano/tsconfig.json`, and `npm run xano:typecheck` checks it and its lambdas.
129
134
  `xano:deploy:ephemeral` deploys the backend alone, and there is no `dev`, `build` or
@@ -143,6 +148,11 @@ no `frontend/` and no root `tsconfig.json`; `xano/` type-checks under its own
143
148
  - A marked block in `.gitignore` (created when missing) and in `AGENTS.md`, added or
144
149
  refreshed in place; the rest of each file is left as it was. A symlinked `AGENTS.md` is left
145
150
  alone, and `--no-agents-md` skips it.
151
+ - The `xano-local` MCP server merged by key into `.mcp.json` and `.cursor/mcp.json` (created
152
+ when missing): the other servers a config declares are kept. A config that already declares
153
+ `xano-local`, or is not valid JSON, is left alone and is not a clash; a symlinked one is
154
+ skipped. `--no-agents-md` skips both. See
155
+ [Connecting a coding agent](deploying.md#connecting-a-coding-agent).
146
156
  - No frontend, README, CI workflow or root `tsconfig.json`. The line-ending rule goes in
147
157
  `xano/.gitattributes`, scoped to `xano/`, so the project's own files are not renormalized.
148
158
 
@@ -177,17 +187,19 @@ The workflow installs with the project's package manager (npm, pnpm, yarn or bun
177
187
  `init` detected it), frozen to the committed lockfile, then runs `xano:check` on every push
178
188
  and pull request. In a monorepo workspace member it installs at the workspace root and checks
179
189
  in the member's directory; move the file to the repository root's `.github/workflows/`, the
180
- only place GitHub reads it. That script
181
- runs `xanosdk export ./xano/index.ts --check --strict`: every check an export runs (a build warning fails it), under
190
+ only place GitHub reads it. That script runs three steps in order:
191
+ `xanosdk routes ./xano/index.ts --emit xano/routes.gen.ts --strict`, which fails when the
192
+ committed route manifest the frontend takes its paths from is stale or missing; the project's
193
+ typecheck (`tsc` on React, `svelte-kit sync && svelte-check` on Svelte, `tsc -p xano` with no
194
+ frontend, each followed by `tsc -p xano/lambdas`); and
195
+ `xanosdk export ./xano/index.ts --check --strict`: every check an export runs (a build warning fails it), under
182
196
  `--frozen-lock`, writing nothing — no bundle, no lock. Because nothing is written, it
183
197
  reads no `xano/.env` or `xano/.secrets.json`, so the workflow needs no repository
184
198
  secrets, even for an API group whose docs are token-gated. It fails instead of
185
199
  rewriting when `xano.lock` disagrees with the source, naming what would change. A
186
200
  project with nothing to record yet (a fresh scaffold) passes without a lock. It also fails while the lock
187
201
  carries an entry no exported object matches — the state a rename leaves until
188
- `lock rename` moves the identity across, or `lock prune` drops it. It first runs
189
- `xanosdk routes ./xano/index.ts --emit xano/routes.gen.ts --strict`, which fails when
190
- the committed route manifest the frontend takes its paths from is stale or missing.
202
+ `lock rename` moves the identity across, or `lock prune` drops it.
191
203
  `dev`, `build` and `typecheck` regenerate that file, so after adding or renaming an
192
204
  endpoint run `npm run xano:routes` (or any of them) and commit it. `init --from` and
193
205
  `pull` write it with the decoded backend, and `init --marketplace` writes it (and
@@ -36,6 +36,9 @@ Every type and helper a frontend gets from a deployed def — path resolution, i
36
36
  one group and verb that a single path can reach (`query.route-shadowed`). Make the paths
37
37
  disjoint (`"runs/by-id/{id}"`), or declare a numeric param `input.int({ required: true })`:
38
38
  only a REQUIRED int/decimal segment matches digits only, and an optional one matches any text.
39
+
40
+ ## Inferring the response type
41
+
39
42
  - **`InferRow<typeof post>`** → the table's row type. Rename or retype a column and every
40
43
  consumer breaks at compile time — exactly where you want it.
41
44
  - **`InferResponse<typeof someQuery>`** → the endpoint's **response** type, closing the round
@@ -46,9 +49,6 @@ Every type and helper a frontend gets from a deployed def — path resolution, i
46
49
  yielding null — `NotFound`/404 for `edit`/`patch`, a unique-constraint error for `add`, while
47
50
  `add_or_edit` upserts and never misses), `Row | null` for `db.get` (it binds
48
51
  `null` on a miss rather than throwing — handle the not-found path), a row list for
49
-
50
- ## Inferring the response type
51
-
52
52
  `db.query`/`db.bulk.patch` (→ `Row[]`), a `boolean` for `db.has`, a `number` count for
53
53
  `db.bulk.delete`, and a `get`/`query` `output: [...]` selection narrows to a `Pick` (still
54
54
  `| null` for `get`). A dotted entry selects sub-keys of an object column
@@ -64,7 +64,7 @@ Every type and helper a frontend gets from a deployed def — path resolution, i
64
64
  `response: { user: obj({ id: ref("row.id") }) }` and the raw literal
65
65
  `response: { user: { id: ref("row.id") } }` both derive `{ user: { id: number | null } }`.
66
66
  A **call** carries the shape across: `s.function.call`/`s.function.run`, `s.tool.call` and
67
- `s.api.call` (workflow-test only, above) given a def **handle** bind their `as` with the
67
+ `s.api.call` (workflow-test only — see [Object kinds](object-kinds.md)) given a def **handle** bind their `as` with the
68
68
  target's own `InferResponse`,
69
69
  so `ref("discount_result.discount_cents")` in the caller types to that field instead of
70
70
  `unknown`. What the target resolves to is what propagates, so declaring `responseShape` on
@@ -89,7 +89,7 @@ For a **computed or multi-key object response**, author it as a *record of value
89
89
  `response: { success: c.bool(true), id: inp("id") }` — **not** `c.obj({ ... })`. `c.obj` builds a
90
90
  *constant*, so a tagged value nested inside it would serialize as internal representation the
91
91
  engine can't decode (a runtime 500); nesting one is now a compile error that points you at the
92
- record form (issue #42). A **nested plain object** in a record
92
+ record form. A **nested plain object** in a record
93
93
  response (`response: { user: { id: ref("u"), age: 3 } }`) is auto-wrapped for you — no manual
94
94
  `obj({ ... })` — and raw literals in a call/agent `input` map coerce too
95
95
  (`s.function.run({ fn, input: { max_age_days: 3 } })` — no `c.int(3)`).
@@ -250,7 +250,8 @@ const connectUrl = mcpUrl("notes_mcp", XANO_HOST); // https://host/x2/mcp/<canon
250
250
  ```
251
251
 
252
252
  Run `xanosdk routes ./xano/index.ts` without `--emit` to see every address the file carries:
253
- each route, socket, channel and MCP server, with the call that builds it.
253
+ each route in its `api:<canonical>/<name>` form, and each socket, channel and MCP server with
254
+ the call that builds it.
254
255
 
255
256
  **Request types come from the same file.** It exports four types-only maps, keyed exactly
256
257
  like the runtime tables they sit beside, so a frontend types what it sends without importing a
@@ -1,8 +1,8 @@
1
1
  # Knowledge def shape
2
2
 
3
- > Read when the workspace defines a `knowledge()` item for its AI agents.
3
+ > Read when the workspace defines a `knowledge()` item.
4
4
 
5
- - `knowledge({ name, description?, type?, mode?, enabled?, body, refs?, guid?, tags? })` — markdown Xano's own AI reads before it acts — the workspace's builder agent, and outside agents reading the workspace through the Meta API or MCP. It does NOT reach an `agent()` run by `s.ai.agent.run`, whatever its `type` or `mode`: put what such an agent must know in its `llm.systemPrompt`. Takes `registerKnowledge`.
5
+ - `knowledge({ name, description?, type?, mode?, enabled?, body, refs?, guid?, tags? })` — markdown shared by every AI that builds the backend: Xano's own AI reads it before it acts — the workspace's builder agent, and outside agents reading the workspace through the Meta API or MCP — and a local coding agent reads the same `.md` files in the repo; deploy and `pull` keep the copies in sync. It does NOT reach an `agent()` run by `s.ai.agent.run`, whatever its `type` or `mode`: put what such an agent must know in its `llm.systemPrompt`. Takes `registerKnowledge`.
6
6
  - `body` (REQUIRED): `knowledgeFile("./runbook.md", import.meta.url)` — a path to a real markdown FILE. There is no inline-string form. The path resolves relative to the MODULE THAT DECLARES the item, not the process working directory and not the workspace entry; `import.meta.url` is required and is what makes that true.
7
7
  - `refs?`: `knowledgeDir("./runbook", import.meta.url)` — a directory whose WHOLE tree ships, recursively, paths preserved: UTF-8 text only (else refused; binary `.DS_Store` skipped), symlinks not followed. Keep the body OUT of it, or it ships as a reference file.
8
8
  - `type?`: `"skill"` (default) | `"doc"` | `"agents.md"`. `skill` and `doc` differ in how they are filed, not in what an agent receives.
@@ -12,7 +12,7 @@ Choose by who or what starts the work. Each rule names the kind that fits and th
12
12
  - **Work on a timer** → `task` (cron or interval). **Work a request starts but does not wait for** → `s.function.run({ fn, runtime: { mode: "async-shared" } })`, which binds a job id, not the result (collect with `s.await`). **Work that follows a row change** → `tableTrigger`: it fires on every insert/update/delete of the table, whichever stack writes it, so the same side effect placed in one endpoint's stack misses every other write path.
13
13
  - **The same steps before or after many objects** (an auth check, a rate limit, logging) → `middleware`, attached per host (`middleware: { pre, post }` on a query, function, task, tool or API group) or to every host of a kind with `workspaceConfig({ middleware: { query, function, task, tool } })` — not a function call repeated at the top of each stack.
14
14
  - **Related rows on returned rows** → an `addon` attached to the read through its `addon: [{ addon, as, input }]` option (`db.query`/`get`/`add`/`edit`/`patch`), merged onto each row under `as` and typed in `InferResponse` — not a second read plus a loop that stitches rows together.
15
- - **AI.** An LLM running inside the backend → `agent()`, started from a stack with `s.ai.agent.run`; it has no public endpoint. An external AI client (Claude, Cursor, any MCP client) calling the backend → `mcpServer()`. Standing instructions for Xano's own builder AI → `knowledge()`; an `agent()` run never reads it. The actions either one calls → `tool()`. What an MCP server serves besides tools (`prompt()`, `resource()`) and when each fits: `llms/kinds-agent-mcp.md`.
15
+ - **AI.** An LLM running inside the backend → `agent()`, started from a stack with `s.ai.agent.run`; it has no public endpoint. An external AI client (Claude, Cursor, any MCP client) calling the backend → `mcpServer()`. Standing instructions for Xano's own builder AI → `knowledge()` (a local coding agent reads the same files in the repo); an `agent()` run never reads it. The actions either one calls → `tool()`. What an MCP server serves besides tools (`prompt()`, `resource()`) and when each fits: `llms/kinds-agent-mcp.md`.
16
16
  - **Pushing to connected clients** → `realtimeServer` → `realtimeChannel` → `realtimeMessage` (the handler for a frame a client sends — the realtime analogue of a query). A server-side push from any stack is `s.realtime.publish`; a client polling a `query` is the substitute this replaces.
17
17
  - **Code the typed surface cannot express** → a lambda (`s.lambda`, `fl.lambda`) for a short JavaScript body, LAST, after native filters and expressions (`llms/lambda.md`); a `microservice` for a long-running container or another language; `s.api.request` for a service that already has an HTTP API.
18
18
  - **Tests** → `tests` on a `query`/`defineFunction`/`middleware` for that one object's input → output; a `workflowTest` for a flow across objects (`s.function.call`, `s.api.call`, `s.task.call`) asserted with `s.expect.*`.
@@ -44,5 +44,5 @@ Choose by who or what starts the work. Each rule names the kind that fits and th
44
44
  - channel: `realtimeChannel` → `Xano.registerRealtimeChannels` → payload `channel` — A realtime channel: a joinable path on a realtime server (`rooms/{room_id}`) with typed path params, join/publish policy, a client-visible conversation transcript, and delivery semantics. Owns message handlers. Returns a handle with `getChannel(params)` for the path a client joins.
45
45
  - message: `realtimeMessage` → `Xano.registerRealtimeMessages` → payload `message` — A realtime message handler: a named message type on a channel with its own typed payload and stack — the realtime analogue of a query. Pass the `realtimeChannel()` handle as `channel` and the owning server comes with it.
46
46
  - microservice: `microservice` → `Xano.registerMicroservices` → payload `microservice` — A container workload deployed alongside the workspace, called from a stack with `s.microservice.request`. Def shapes (`builtin` containers vs a `helm` chart) and the SECRET-handling rules its config carries: `llms/statements-calls.md`.
47
- - knowledge: `knowledge` → `Xano.registerKnowledge` → payload `knowledge` — Markdown Xano's own AI (the builder agent, and Meta API / MCP readers) reads before it acts — never an `agent()` run — an `agents.md` of standing instructions, a `skill`, or a `doc`. The body is a real markdown FILE via `knowledgeFile("./x.md", import.meta.url)`, and `mode` decides how much of it reaches the agent.
47
+ - knowledge: `knowledge` → `Xano.registerKnowledge` → payload `knowledge` — Markdown shared by every AI that builds the backend — Xano's own AI (the builder agent, Meta API / MCP readers) and a local coding agent reading the same files — never an `agent()` run: an `agents.md` of standing instructions, a `skill`, or a `doc`. The body is a real markdown FILE via `knowledgeFile("./x.md", import.meta.url)`, and `mode` decides how much of it reaches the agent.
48
48
  - workspace: `workspaceConfig` → `Xano.registerWorkspace` → payload `workspace` — Workspace-level configuration such as default middleware chains and request-history defaults per host kind.
package/llms-full.txt CHANGED
@@ -1,4 +1,4 @@
1
- # xanosdk v1.0.12
1
+ # xanosdk v1.0.13
2
2
 
3
3
  > TypeScript SDK that compiles a typed Xano workspace into the importable packageExport JSON bundle.
4
4
 
@@ -45,7 +45,7 @@ plain file read resolves them at the version you have.
45
45
  - [Error index](llms/errors.md): Read when a request, test, build, or pull fails with a message you did not write — the string, its cause, and where the fix is.
46
46
  - [Saved unit tests, assertions, and mocks](llms/tests.md): Read when authoring a `workflowTest()` stack, when a query/function/middleware carries `tests`, when a statement needs a `mock`, or when running a deployed environment's tests.
47
47
  - [Agent and MCP def shapes](llms/kinds-agent-mcp.md): Read when building an MCP server (tools, prompts, resources) or an `agent()`.
48
- - [Knowledge def shape](llms/kinds-knowledge.md): Read when the workspace defines a `knowledge()` item for its AI agents.
48
+ - [Knowledge def shape](llms/kinds-knowledge.md): Read when the workspace defines a `knowledge()` item.
49
49
  - [Realtime def shapes](llms/kinds-realtime.md): Read when the workspace defines a `realtimeServer()`, `realtimeChannel()`, or `realtimeMessage()` handler.
50
50
  - [Triggers](llms/triggers.md): Read when authoring any trigger. A trigger's `stack` is a callback rather than the plain array every other kind takes, so the shape does not carry over.
51
51
  - [Array and database statements](llms/statements-data.md): Read when the stack reads or writes rows (`s.db.*`), or transforms an array in place (`s.array.map`, `s.array.union`).
@@ -507,7 +507,7 @@ Choose by who or what starts the work. Each rule names the kind that fits and th
507
507
  - **Work on a timer** → `task` (cron or interval). **Work a request starts but does not wait for** → `s.function.run({ fn, runtime: { mode: "async-shared" } })`, which binds a job id, not the result (collect with `s.await`). **Work that follows a row change** → `tableTrigger`: it fires on every insert/update/delete of the table, whichever stack writes it, so the same side effect placed in one endpoint's stack misses every other write path.
508
508
  - **The same steps before or after many objects** (an auth check, a rate limit, logging) → `middleware`, attached per host (`middleware: { pre, post }` on a query, function, task, tool or API group) or to every host of a kind with `workspaceConfig({ middleware: { query, function, task, tool } })` — not a function call repeated at the top of each stack.
509
509
  - **Related rows on returned rows** → an `addon` attached to the read through its `addon: [{ addon, as, input }]` option (`db.query`/`get`/`add`/`edit`/`patch`), merged onto each row under `as` and typed in `InferResponse` — not a second read plus a loop that stitches rows together.
510
- - **AI.** An LLM running inside the backend → `agent()`, started from a stack with `s.ai.agent.run`; it has no public endpoint. An external AI client (Claude, Cursor, any MCP client) calling the backend → `mcpServer()`. Standing instructions for Xano's own builder AI → `knowledge()`; an `agent()` run never reads it. The actions either one calls → `tool()`. What an MCP server serves besides tools (`prompt()`, `resource()`) and when each fits: `llms/kinds-agent-mcp.md`.
510
+ - **AI.** An LLM running inside the backend → `agent()`, started from a stack with `s.ai.agent.run`; it has no public endpoint. An external AI client (Claude, Cursor, any MCP client) calling the backend → `mcpServer()`. Standing instructions for Xano's own builder AI → `knowledge()` (a local coding agent reads the same files in the repo); an `agent()` run never reads it. The actions either one calls → `tool()`. What an MCP server serves besides tools (`prompt()`, `resource()`) and when each fits: `llms/kinds-agent-mcp.md`.
511
511
  - **Pushing to connected clients** → `realtimeServer` → `realtimeChannel` → `realtimeMessage` (the handler for a frame a client sends — the realtime analogue of a query). A server-side push from any stack is `s.realtime.publish`; a client polling a `query` is the substitute this replaces.
512
512
  - **Code the typed surface cannot express** → a lambda (`s.lambda`, `fl.lambda`) for a short JavaScript body, LAST, after native filters and expressions (`llms/lambda.md`); a `microservice` for a long-running container or another language; `s.api.request` for a service that already has an HTTP API.
513
513
  - **Tests** → `tests` on a `query`/`defineFunction`/`middleware` for that one object's input → output; a `workflowTest` for a flow across objects (`s.function.call`, `s.api.call`, `s.task.call`) asserted with `s.expect.*`.
@@ -539,7 +539,7 @@ Choose by who or what starts the work. Each rule names the kind that fits and th
539
539
  - channel: `realtimeChannel` → `Xano.registerRealtimeChannels` → payload `channel` — A realtime channel: a joinable path on a realtime server (`rooms/{room_id}`) with typed path params, join/publish policy, a client-visible conversation transcript, and delivery semantics. Owns message handlers. Returns a handle with `getChannel(params)` for the path a client joins.
540
540
  - message: `realtimeMessage` → `Xano.registerRealtimeMessages` → payload `message` — A realtime message handler: a named message type on a channel with its own typed payload and stack — the realtime analogue of a query. Pass the `realtimeChannel()` handle as `channel` and the owning server comes with it.
541
541
  - microservice: `microservice` → `Xano.registerMicroservices` → payload `microservice` — A container workload deployed alongside the workspace, called from a stack with `s.microservice.request`. Def shapes (`builtin` containers vs a `helm` chart) and the SECRET-handling rules its config carries: `llms/statements-calls.md`.
542
- - knowledge: `knowledge` → `Xano.registerKnowledge` → payload `knowledge` — Markdown Xano's own AI (the builder agent, and Meta API / MCP readers) reads before it acts — never an `agent()` run — an `agents.md` of standing instructions, a `skill`, or a `doc`. The body is a real markdown FILE via `knowledgeFile("./x.md", import.meta.url)`, and `mode` decides how much of it reaches the agent.
542
+ - knowledge: `knowledge` → `Xano.registerKnowledge` → payload `knowledge` — Markdown shared by every AI that builds the backend — Xano's own AI (the builder agent, Meta API / MCP readers) and a local coding agent reading the same files — never an `agent()` run: an `agents.md` of standing instructions, a `skill`, or a `doc`. The body is a real markdown FILE via `knowledgeFile("./x.md", import.meta.url)`, and `mode` decides how much of it reaches the agent.
543
543
  - workspace: `workspaceConfig` → `Xano.registerWorkspace` → payload `workspace` — Workspace-level configuration such as default middleware chains and request-history defaults per host kind.
544
544
 
545
545
  # Core def shapes
@@ -901,9 +901,9 @@ The run is isolated in ways that make a correct test fail for reasons the failur
901
901
 
902
902
  # Knowledge def shape
903
903
 
904
- > Read when the workspace defines a `knowledge()` item for its AI agents.
904
+ > Read when the workspace defines a `knowledge()` item.
905
905
 
906
- - `knowledge({ name, description?, type?, mode?, enabled?, body, refs?, guid?, tags? })` — markdown Xano's own AI reads before it acts — the workspace's builder agent, and outside agents reading the workspace through the Meta API or MCP. It does NOT reach an `agent()` run by `s.ai.agent.run`, whatever its `type` or `mode`: put what such an agent must know in its `llm.systemPrompt`. Takes `registerKnowledge`.
906
+ - `knowledge({ name, description?, type?, mode?, enabled?, body, refs?, guid?, tags? })` — markdown shared by every AI that builds the backend: Xano's own AI reads it before it acts — the workspace's builder agent, and outside agents reading the workspace through the Meta API or MCP — and a local coding agent reads the same `.md` files in the repo; deploy and `pull` keep the copies in sync. It does NOT reach an `agent()` run by `s.ai.agent.run`, whatever its `type` or `mode`: put what such an agent must know in its `llm.systemPrompt`. Takes `registerKnowledge`.
907
907
  - `body` (REQUIRED): `knowledgeFile("./runbook.md", import.meta.url)` — a path to a real markdown FILE. There is no inline-string form. The path resolves relative to the MODULE THAT DECLARES the item, not the process working directory and not the workspace entry; `import.meta.url` is required and is what makes that true.
908
908
  - `refs?`: `knowledgeDir("./runbook", import.meta.url)` — a directory whose WHOLE tree ships, recursively, paths preserved: UTF-8 text only (else refused; binary `.DS_Store` skipped), symlinks not followed. Keep the body OUT of it, or it ships as a reference file.
909
909
  - `type?`: `"skill"` (default) | `"doc"` | `"agents.md"`. `skill` and `doc` differ in how they are filed, not in what an agent receives.
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # xanosdk v1.0.12
1
+ # xanosdk v1.0.13
2
2
 
3
3
  > TypeScript SDK that compiles a typed Xano workspace into the importable packageExport JSON bundle.
4
4
 
@@ -45,7 +45,7 @@ plain file read resolves them at the version you have.
45
45
  - [Error index](llms/errors.md): Read when a request, test, build, or pull fails with a message you did not write — the string, its cause, and where the fix is.
46
46
  - [Saved unit tests, assertions, and mocks](llms/tests.md): Read when authoring a `workflowTest()` stack, when a query/function/middleware carries `tests`, when a statement needs a `mock`, or when running a deployed environment's tests.
47
47
  - [Agent and MCP def shapes](llms/kinds-agent-mcp.md): Read when building an MCP server (tools, prompts, resources) or an `agent()`.
48
- - [Knowledge def shape](llms/kinds-knowledge.md): Read when the workspace defines a `knowledge()` item for its AI agents.
48
+ - [Knowledge def shape](llms/kinds-knowledge.md): Read when the workspace defines a `knowledge()` item.
49
49
  - [Realtime def shapes](llms/kinds-realtime.md): Read when the workspace defines a `realtimeServer()`, `realtimeChannel()`, or `realtimeMessage()` handler.
50
50
  - [Triggers](llms/triggers.md): Read when authoring any trigger. A trigger's `stack` is a callback rather than the plain array every other kind takes, so the shape does not carry over.
51
51
  - [Array and database statements](llms/statements-data.md): Read when the stack reads or writes rows (`s.db.*`), or transforms an array in place (`s.array.map`, `s.array.union`).
package/manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xanosdk",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "TypeScript SDK that compiles a typed Xano workspace into the importable packageExport JSON bundle.",
5
5
  "coverage": {
6
6
  "objectKinds": {
@@ -382,7 +382,7 @@
382
382
  "kind": "knowledge",
383
383
  "payloadKey": "knowledge",
384
384
  "authorFactory": "knowledge",
385
- "description": "Markdown Xano's own AI (the builder agent, and Meta API / MCP readers) reads before it acts — never an `agent()` run — an `agents.md` of standing instructions, a `skill`, or a `doc`. The body is a real markdown FILE via `knowledgeFile(\"./x.md\", import.meta.url)`, and `mode` decides how much of it reaches the agent.",
385
+ "description": "Markdown shared by every AI that builds the backend — Xano's own AI (the builder agent, Meta API / MCP readers) and a local coding agent reading the same files — never an `agent()` run: an `agents.md` of standing instructions, a `skill`, or a `doc`. The body is a real markdown FILE via `knowledgeFile(\"./x.md\", import.meta.url)`, and `mode` decides how much of it reaches the agent.",
386
386
  "registerMethod": "registerKnowledge",
387
387
  "registered": true
388
388
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xano/sdk",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "The official TypeScript SDK for Xano, one platform to build, run and govern AI-built software. Your coding agent writes the backend in TypeScript, you run it on the Xano Engine on your machine, then deploy it to Xano.",
5
5
  "keywords": [
6
6
  "xanosdk",
@@ -14,8 +14,8 @@ description: >-
14
14
  FastAPI) unless the user asks for Xano.
15
15
  license: MIT
16
16
  metadata:
17
- xanosdk-version: "1.0.12"
18
- xanosdk-digest: "sha256:b9408ac6a9bbac98148718e4e8ce34f0cfa97b8767d91420d387a678e456da9a"
17
+ xanosdk-version: "1.0.13"
18
+ xanosdk-digest: "sha256:5af311994df498c279a5f24b3f605468a690f046d8bddf612c938142ee46c759"
19
19
  ---
20
20
 
21
21
  # Xano backend