@xanots/sdk 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +384 -0
  3. package/dist/agent-file-refresh-7XCACU34.js +95 -0
  4. package/dist/bin.d.ts +1 -0
  5. package/dist/bin.js +184 -0
  6. package/dist/capture-HUV5BNTC.js +32 -0
  7. package/dist/chunk-26CNBZE2.js +963 -0
  8. package/dist/chunk-33ND6LKO.js +78 -0
  9. package/dist/chunk-3DUAGYGP.js +1550 -0
  10. package/dist/chunk-3IGNIP6R.js +89 -0
  11. package/dist/chunk-47WDWMBJ.js +14 -0
  12. package/dist/chunk-4BXJGVZ3.js +318 -0
  13. package/dist/chunk-4HT3BNZ7.js +675 -0
  14. package/dist/chunk-4YMD2OOZ.js +23 -0
  15. package/dist/chunk-5WGEURVI.js +156 -0
  16. package/dist/chunk-5YTBTF25.js +29 -0
  17. package/dist/chunk-6DHBYBTO.js +166 -0
  18. package/dist/chunk-76QBEIGO.js +66 -0
  19. package/dist/chunk-7DKX2SPN.js +100 -0
  20. package/dist/chunk-7REDODS2.js +468 -0
  21. package/dist/chunk-C56BC2FY.js +254 -0
  22. package/dist/chunk-DGSF2Q5H.js +60 -0
  23. package/dist/chunk-EMCAWMHC.js +3982 -0
  24. package/dist/chunk-EZG76F7R.js +159 -0
  25. package/dist/chunk-FJ6ZS5KB.js +3607 -0
  26. package/dist/chunk-GNPVYOPB.js +17 -0
  27. package/dist/chunk-HJPTWBLH.js +38 -0
  28. package/dist/chunk-IZW6MK3U.js +248 -0
  29. package/dist/chunk-LH6Z6KFV.js +247 -0
  30. package/dist/chunk-MZUI3JNX.js +93 -0
  31. package/dist/chunk-NDZFBZHC.js +167 -0
  32. package/dist/chunk-NOO35BQ2.js +37 -0
  33. package/dist/chunk-NUQCEOKA.js +13 -0
  34. package/dist/chunk-QTNO2WD6.js +56 -0
  35. package/dist/chunk-RVB7ITKN.js +49 -0
  36. package/dist/chunk-TRU5OHQ5.js +6904 -0
  37. package/dist/chunk-VKFQJEMW.js +814 -0
  38. package/dist/chunk-VTIL47DT.js +125 -0
  39. package/dist/chunk-WHOJWOSV.js +112 -0
  40. package/dist/chunk-WKP4D5MO.js +1692 -0
  41. package/dist/chunk-X4DVXBFY.js +38 -0
  42. package/dist/chunk-XQ22GLYS.js +118 -0
  43. package/dist/chunk-YDZYMZBE.js +670 -0
  44. package/dist/chunk-YGPIY3WT.js +1146 -0
  45. package/dist/chunk-YYRDLFSJ.js +602 -0
  46. package/dist/chunk-ZUTSMMAG.js +46 -0
  47. package/dist/cli.d.ts +331 -0
  48. package/dist/cli.js +33 -0
  49. package/dist/codegen-command-OOKK6AZK.js +40 -0
  50. package/dist/codegen.d.ts +114 -0
  51. package/dist/codegen.js +71 -0
  52. package/dist/completion-TIPPZN7H.js +298 -0
  53. package/dist/config-NL33PN4D.js +84 -0
  54. package/dist/deploy-command-4EQ7XX5G.js +451 -0
  55. package/dist/env-target-IFJ5QDHC.js +16 -0
  56. package/dist/ephemeral-command-3X3I4ULC.js +242 -0
  57. package/dist/index.d.ts +4477 -0
  58. package/dist/index.js +300 -0
  59. package/dist/init-command-R6H7ZXW5.js +27 -0
  60. package/dist/internal.d.ts +74 -0
  61. package/dist/internal.js +2065 -0
  62. package/dist/io-AMIKRLPC.js +11 -0
  63. package/dist/live-diff-Y3AKETHE.js +196 -0
  64. package/dist/lock-3CVKALKT.js +37 -0
  65. package/dist/lock-commands-XTR2YKLY.js +232 -0
  66. package/dist/login-command-ACJF6KWQ.js +167 -0
  67. package/dist/logout-command-MX3MJS5U.js +68 -0
  68. package/dist/loop-OM3P2Z6O.js +93 -0
  69. package/dist/marketplace-command-RATXTKXN.js +379 -0
  70. package/dist/meta-client-OW5WKWW7.js +170 -0
  71. package/dist/node.d.ts +59 -0
  72. package/dist/node.js +442 -0
  73. package/dist/profile-command-SWJ3SPKR.js +77 -0
  74. package/dist/release-command-VV5UVZKL.js +427 -0
  75. package/dist/response-CVAE2kMj.d.ts +1915 -0
  76. package/dist/routes-manifest-SP3ZXLMR.js +244 -0
  77. package/dist/runtime-V4C3AC3A.js +13 -0
  78. package/dist/sandbox-details-command-HJE5SPVG.js +18 -0
  79. package/dist/sandbox-export-command-QCJY4GMV.js +24 -0
  80. package/dist/static-host-D6KS7X45.js +138 -0
  81. package/dist/store-BQ97nKIF.d.ts +7760 -0
  82. package/dist/test-command-TSPBQHBM.js +383 -0
  83. package/dist/validate-command-4ERHJSCO.js +122 -0
  84. package/dist/verify-rollout-FAVQ6EJY.js +40 -0
  85. package/dist/workspace-K72NP7SX.js +49 -0
  86. package/dist/workspace-command-OF23DPNI.js +156 -0
  87. package/dist/workspace-export-AJMGN3CQ.js +10 -0
  88. package/llms/fields.md +104 -0
  89. package/llms/filters.md +183 -0
  90. package/llms/kinds-agent-mcp.md +11 -0
  91. package/llms/kinds-core.md +68 -0
  92. package/llms/kinds-realtime.md +76 -0
  93. package/llms/lambda.md +111 -0
  94. package/llms/legacy.md +43 -0
  95. package/llms/object-kinds.md +31 -0
  96. package/llms/statements-calls.md +23 -0
  97. package/llms/statements-catalog.md +309 -0
  98. package/llms/statements-data.md +58 -0
  99. package/llms/statements-runtime.md +48 -0
  100. package/llms/tests.md +58 -0
  101. package/llms/triggers.md +22 -0
  102. package/llms/values.md +29 -0
  103. package/llms-full.txt +1672 -0
  104. package/llms.txt +483 -0
  105. package/manifest.json +9592 -0
  106. package/package.json +110 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Xano, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,384 @@
1
+ <div align="center">
2
+
3
+ # XanoTS
4
+
5
+ ### The official TypeScript SDK for [Xano](https://xano.com).
6
+
7
+ **Write your app in TypeScript — the database, the APIs, even AI agents. Or let an
8
+ AI write it for you. Then run one command and it's live on Xano's cloud, with its own
9
+ URL. No servers, no setup, no config. That's it.**
10
+
11
+ [![npm](https://img.shields.io/npm/v/@xanots/sdk?color=%230055FF&label=%40xanots%2Fsdk)](https://www.npmjs.com/package/@xanots/sdk)
12
+ [![node](https://img.shields.io/node/v/@xanots/sdk)](https://nodejs.org)
13
+ [![license](https://img.shields.io/npm/l/@xanots/sdk)](LICENSE)
14
+
15
+ </div>
16
+
17
+ ```bash
18
+ npx @xanots/sdk login # 1. sign in (opens your browser)
19
+ npx @xanots/sdk init my-app && cd my-app # 2. scaffold your backend + frontend
20
+ npm run build # 3. build your frontend → frontend/dist
21
+ npx xanots deploy ./xano/index.ts --static ./frontend/dist # 4. deploy both → live URLs
22
+ ```
23
+
24
+ ```
25
+ → Deploying ./xano/index.ts → new ephemeral "my-app"
26
+ ✓ Ephemeral e4f2-9ab1 deployed
27
+ ! New ephemeral URL:
28
+ https://e4f2-9ab1.xano.io ← backend, live
29
+ Expires in 1h 0m
30
+ ✓ Static host deployed
31
+ https://my-app.xano.io ← frontend, live
32
+ ```
33
+
34
+ <div align="center">
35
+
36
+ **From an empty folder to a live full-stack app.** `init` sets up your project — a
37
+ TypeScript backend and a React or Svelte frontend. `npm run build` builds your frontend, then
38
+ `deploy` puts both online and hands you a live URL. Change your code — yourself or with
39
+ an AI — and deploy again; your app updates in seconds. No servers to set up, nothing to
40
+ configure, no glue code between your backend and your frontend.
41
+
42
+ [Why](#why-xanots) ·
43
+ [Quickstart](#quickstart) ·
44
+ [The model](#the-model) ·
45
+ [Deploying](#deploying) ·
46
+ [Type-safe frontend](#a-type-safe-frontend-for-free) ·
47
+ [Reference](#reference)
48
+
49
+ </div>
50
+
51
+ ---
52
+
53
+ ## Why XanoTS
54
+
55
+ Xano gives you a genuinely scalable backend — Postgres, serverless functions, background
56
+ tasks, realtime, MCP servers, AI agents — without you running a single server. XanoTS is
57
+ Xano's **officially supported** TypeScript SDK, and it gives you that backend **as code you
58
+ own**:
59
+
60
+ - **📦 TypeScript is the source of truth.** Your whole workspace — tables, indexes, API
61
+ endpoints, functions, triggers, tasks, middleware, AI toolsets — is typed TS in your repo.
62
+ Version it, review it in PRs, diff it, roll it back. No more clicking through a dashboard
63
+ and hoping prod matches staging.
64
+
65
+ - **🚀 Deploy is built in.** `xanots deploy` compiles your code and ships it to a live Xano
66
+ environment over an authenticated connection, then prints its URL. Backend **and** static
67
+ frontend in one command — no export/import dance, no upload script to maintain.
68
+
69
+ - **⚡ Fast, safe iteration.** Ephemeral environments are disposable and auto-expiring, so
70
+ you rebuild as often as you like. Deploys are identity-stable: re-running never duplicates
71
+ objects, and with a committed `xano.lock` renames stay renames instead of
72
+ delete-and-recreate.
73
+
74
+ - **🧩 The types flow to your frontend.** Import a `query()` def into your React/Svelte/Angular
75
+ app and get the endpoint path, HTTP verb, and a fully-typed request payload — with **zero
76
+ codegen**. Rename a column and every consumer lights up red.
77
+
78
+ - **🤖 AI-first by design.** A deterministic, fully-typed authoring surface: an agent (or
79
+ you) emits well-typed TS that always compiles to a valid, importable workspace. It ships
80
+ with machine-readable grounding an agent reads instead of your source — see
81
+ [Coverage & agent grounding](https://github.com/xanots/sdk/blob/main/guides/coverage.md).
82
+
83
+ ---
84
+
85
+ ## Quickstart
86
+
87
+ The four commands at the top of this page are the whole loop. Here they are one at a time.
88
+
89
+ **1. Sign in.** OAuth in your browser — no API keys to copy around. The CLI refreshes tokens
90
+ for you, and the target instance comes from your token rather than a flag.
91
+
92
+ ```bash
93
+ npx @xanots/sdk login
94
+ ```
95
+
96
+ **2. Scaffold.** `init` writes a complete project: a Vite frontend under `frontend/` (React
97
+ 19 + shadcn/ui by default, or SvelteKit with `--framework svelte`), a XanoTS backend under
98
+ `xano/`, and the `xano:export` / `xano:deploy` scripts already wired.
99
+
100
+ ```bash
101
+ npx @xanots/sdk init my-app && cd my-app
102
+ npm run dev # the frontend runs immediately
103
+ ```
104
+
105
+ The starter backend is empty but already compiles and deploys — grow it from the walkthrough
106
+ in `xano/EXAMPLE.md`. For the flags, the two presets, and add-ons, see
107
+ [The scaffolded project](https://github.com/xanots/sdk/blob/main/guides/scaffold.md).
108
+
109
+ **3. Build the frontend.**
110
+
111
+ ```bash
112
+ npm run build # → frontend/dist
113
+ ```
114
+
115
+ **4. Deploy both.** One authenticated call ships your database schema, your APIs, your
116
+ functions and triggers, **and** your compiled web app.
117
+
118
+ ```bash
119
+ npx xanots deploy ./xano/index.ts --static ./frontend/dist
120
+ ```
121
+
122
+ ```
123
+ → Deploying ./xano/index.ts → new ephemeral "my-app"
124
+ ✓ Ephemeral e4f2-9ab1 deployed
125
+ ! New ephemeral URL:
126
+ https://e4f2-9ab1.xano.io ← backend, live
127
+ Expires in 1h 0m
128
+ ✓ Config injected into 1 document: window.XANO_HOST ← backend URL, wired in
129
+ ✓ Static host deployed
130
+ https://my-app.xano.io ← frontend, live
131
+ ✓ Frontend is live ← edge confirmed serving THIS build
132
+ ```
133
+
134
+ That's the dev loop. Change your code and run step 4 again; the environment refreshes in
135
+ seconds. The deploy bakes the backend URL into your build as `window.XANO_HOST`, so the
136
+ frontend never needs to know it ahead of time — read it with a build-time fallback:
137
+
138
+ ```ts
139
+ const HOST = (typeof window !== "undefined" && window.XANO_HOST) || import.meta.env.VITE_XANO_HOST;
140
+ ```
141
+
142
+ > Deploying again keeps the **backend** URL; the **frontend** one changes, because a deploy
143
+ > is a full replace and clears the environment's static hosting along with its workspace.
144
+ > Hand out the URL from the latest run. [Signing in & deploying](https://github.com/xanots/sdk/blob/main/guides/deploying.md) covers
145
+ > the injection rules, serving stored files, and headless CI runs.
146
+
147
+ **Prefer to wire it by hand?** Skip `init` — `npm install @xanots/sdk`, write your workspace
148
+ in `xano/index.ts`, and steps 1 and 4 are unchanged. The entry must be an ES module (XanoTS
149
+ defs are ESM-only); on Node ≥ 22.6 a `.ts` entry loads natively, and older Node wants
150
+ [`tsx`](https://tsx.is).
151
+
152
+ ---
153
+
154
+ ## The model
155
+
156
+ You author declarative def-objects, register them on one `Xano` instance, and XanoTS
157
+ compiles the whole thing into Xano's importable bundle.
158
+
159
+ ```ts
160
+ import { workspace, table, query, apiGroup, f, s, ref, c, expr, col } from "@xanots/sdk";
161
+
162
+ // A database table — `id` + `created_at` auto-inject, so declare only your own columns.
163
+ const user = table({
164
+ name: "user",
165
+ auth: true,
166
+ schema: {
167
+ email: f.email({ required: true, methods: ["trim", "lower"] }),
168
+ name: f.text(),
169
+ },
170
+ });
171
+
172
+ const post = table({
173
+ name: "post",
174
+ schema: {
175
+ title: f.text({ required: true }),
176
+ body: f.text(),
177
+ published: f.bool({ default: false }),
178
+ author: f.tableRef(user), // a real foreign key, type-checked
179
+ },
180
+ });
181
+
182
+ // A public API group + endpoint. This query def is also the contract your frontend imports.
183
+ const blog = apiGroup({ name: "blog", canonical: "blog" });
184
+
185
+ const listPosts = query({
186
+ verb: "GET",
187
+ apiGroup: blog,
188
+ name: "list_posts",
189
+ stack: [
190
+ s.db.query({ table: post, where: expr(col("published"), "=", c.bool(true)), as: "rows" }),
191
+ ],
192
+ response: ref("rows"),
193
+ });
194
+
195
+ export default workspace("blog")
196
+ .registerApiGroups([blog])
197
+ .registerTables([user, post])
198
+ .registerQueries([listPosts]);
199
+ ```
200
+
201
+ Tab-complete `s.` to discover the entire statement catalog — `s.db.*`, `s.math.*`,
202
+ `s.array.*`, `s.text.*`, `s.storage.*`, `s.api.*`, `s.cloud.*`, control flow, AI agent runs,
203
+ and more. **All 214 engine statement surfaces are authorable** — every field name matches
204
+ the Xano engine, and the output is proven byte-for-byte against the engine's own golden
205
+ fixtures.
206
+
207
+ Give a table a `seed` array and those rows ship into the database on deploy, so a fresh
208
+ environment comes up with its lookup tables and fixtures already in place. Tables, fields,
209
+ statements, values, inputs, and middleware are all in the
210
+ [Authoring reference](https://github.com/xanots/sdk/blob/main/guides/authoring.md); every kind you can author is in
211
+ [Object kinds](https://github.com/xanots/sdk/blob/main/guides/object-kinds.md).
212
+
213
+ ---
214
+
215
+ ## Deploying
216
+
217
+ **Two targets**, so the dev loop and the production step stay distinct:
218
+
219
+ | Command | Where it goes |
220
+ |---|---|
221
+ | `xanots deploy` | A disposable **ephemeral** environment (default) — create-or-refreshed each run, auto-expiring, with its own URL. `--dest sandbox` targets your throwaway singleton instead. |
222
+ | `xanots release` | Your **main Xano instance** workspace — the production target. **Merges** by default: objects are updated in place or added, and your table data is never touched unless you ask. |
223
+
224
+ Every `deploy` is a **full replace** of the disposable environment — always fresh, no merge
225
+ mode, no flags to get wrong. A `release` is the opposite by design: it changes what your code
226
+ defines and leaves the rest of the workspace, including every row in every table, alone. An
227
+ unchanged project is a no-op, which makes `release` safe to run on a schedule or in CI on
228
+ every merge.
229
+
230
+ Anything destructive is **previewed first** — the CLI fetches the plan, prints what would
231
+ change, and asks. `--yes` skips the prompt for CI but never skips the preview. Start with
232
+ `xanots release ./xano/index.ts --dry-run` to see the plan without committing to it.
233
+
234
+ > ⚠️ A deploy is a full replace of the target environment, **including its table records**,
235
+ > before importing. The blast radius is your own disposable ephemeral or sandbox — but
236
+ > anything you only ever created by hand in it is gone. That is exactly why production has a
237
+ > separate `release` path.
238
+
239
+ Every flag, the `--prune` rules, the identity model, and headless CI runs are in
240
+ [Signing in & deploying](https://github.com/xanots/sdk/blob/main/guides/deploying.md). Environment management is
241
+ `xanots ephemeral <list|get|delete|export>`.
242
+
243
+ ### Testing
244
+
245
+ The tests you author — a `tests` entry on a query, function, or middleware, or a standalone
246
+ `workflowTest()` — run against a deployed environment:
247
+
248
+ ```bash
249
+ npx xanots test run-all # the ephemeral you last deployed to
250
+ npx xanots test run-all --dest workspace # or your real workspace (this only reads)
251
+ ```
252
+
253
+ `xanots test list` shows what is there without running it, and `xanots test run "<name>"`
254
+ runs one. A failing suite exits **5**, distinct from a crash, so CI can tell the two apart.
255
+ To deploy and prove it in one step, `xanots deploy ./xano/index.ts --test` — a failing test
256
+ exits 5 **without** retracting the deploy, so the environment is live either way.
257
+
258
+ ---
259
+
260
+ ## A type-safe frontend, for free
261
+
262
+ Because your API is a typed def, the code that *calls* it can reuse that def instead of
263
+ re-typing URLs and request bodies. Import the `query()` into your frontend:
264
+
265
+ ```ts
266
+ import { listPosts } from "../xano/index.js"; // the same def you deployed
267
+ import { post } from "../xano/tables.js";
268
+ import type { InferRow } from "@xanots/sdk";
269
+
270
+ const BASE = window.XANO_HOST; // injected by the deploy
271
+
272
+ type Post = InferRow<typeof post>; // { id: number; created_at: number; title: string; … }
273
+
274
+ async function fetchPosts(): Promise<Post[]> {
275
+ const res = await fetch(BASE + listPosts.getPath(), { method: listPosts.verb });
276
+ return res.json(); // typed end to end
277
+ }
278
+ ```
279
+
280
+ - **`listPosts.getPath()`** → the endpoint path, resolved from your code (or the frozen
281
+ `xano.lock`). No hardcoded strings. `{param}` segments fill from `getPath({ params })`,
282
+ percent-encoded.
283
+ - **`listPosts.verb`** → the HTTP method, straight from the def.
284
+ - **`InferInput<typeof someQuery>`** → the request-payload type, derived from a query's
285
+ `input` map at compile time. Required inputs are required keys; enums become literal
286
+ unions. **No codegen, always in sync.**
287
+ - **`InferRow<typeof post>`** → the table's row type. Rename or retype a column and every
288
+ consumer breaks at compile time — exactly where you want it.
289
+ - **`InferResponse<typeof someQuery>`** → the endpoint's **response** type, closing the round
290
+ trip. It auto-derives the common shapes with no codegen, mirroring the static walk the
291
+ engine itself does, and degrades to `unknown` in exactly the cases the engine cannot
292
+ resolve either — declare `responseShape` there.
293
+
294
+ The `@xanots/sdk` entry has **zero Node dependencies**, so importing your workspace graph
295
+ into a browser bundle just works. The `node:fs`-backed emitters live in the separate
296
+ `@xanots/sdk/node` entry a frontend never pulls in.
297
+
298
+ Importing a def carries the SDK runtime with it. When that matters, emit a route manifest
299
+ instead — plain data plus one interpolator, importing nothing:
300
+
301
+ ```bash
302
+ xanots paths ./xano/index.ts --emit xano/routes.gen.ts
303
+ ```
304
+
305
+ Route names and their `{param}` keys are still checked at compile time, so a backend rename
306
+ is a compile error rather than a 404. The measured bundle numbers, the full response-inference
307
+ rules, endpoint-name constraints, and the realtime helpers are in
308
+ [The typed frontend surface](https://github.com/xanots/sdk/blob/main/guides/typed-frontend.md).
309
+
310
+ ---
311
+
312
+ ## Already have a Xano workspace?
313
+
314
+ `codegen` runs the loop the other way: it reads a workspace and writes it back out as
315
+ readable XanoTS source — real `s.db.query(...)`, `f.email()`, typed defs — not a JSON dump.
316
+ And not a loose pile of files either: you get the same runnable project `xanots init`
317
+ scaffolds, with the pulled workspace filling `xano/`. So a pull deploys:
318
+
319
+ ```bash
320
+ xanots workspace codegen my-app # your real workspace (the one your login is scoped to)
321
+ cd my-app
322
+ npm run build
323
+ npm run xano:deploy # → a live ephemeral URL
324
+ ```
325
+
326
+ The other three sources are the same command with a different origin — `xanots sandbox
327
+ codegen`, `xanots ephemeral codegen`, and `xanots codegen ws.json` for a bundle already on
328
+ disk (offline, no login).
329
+
330
+ Object identities are preserved, so cross-references stay intact, and a statement this SDK
331
+ does not model yet round-trips verbatim rather than breaking the pull. Then it checks its own
332
+ work: the tree it just wrote is loaded, exported, and diffed against the workspace it came
333
+ from, so "it compiled" and "it means the same thing" are separate claims and you get both.
334
+
335
+ > ⚠️ **`xano/` is a scratch surface.** Regenerating rewrites it, it carries schema only — no
336
+ > table rows — and deploying it is a *full replace* of the target. Pull from your real
337
+ > workspace, edit, and `deploy` to a disposable ephemeral or sandbox. Workspace env var
338
+ > **values** ride inline in `xano/workspace.ts`, so treat a pulled tree as secret-bearing
339
+ > before you commit it.
340
+
341
+ What the generated tree looks like, how faithful the pull is, and how to read its report are
342
+ in [Pulling an existing workspace](https://github.com/xanots/sdk/blob/main/guides/codegen.md).
343
+
344
+ ---
345
+
346
+ ## Reference
347
+
348
+ Every kind, statement, filter, and field type is typed, so your editor's autocomplete is
349
+ the fastest lookup — tab-complete `s.`, `f.`, `c.`, `fl.`, `input.`. For the written
350
+ reference, the guides carry the shape of a project and the behavior that will bite you:
351
+
352
+ | Guide | What's in it |
353
+ |---|---|
354
+ | [Project structure](https://github.com/xanots/sdk/blob/main/guides/project-structure.md) | How a `xano/` project is laid out, and why registration is explicit |
355
+ | [The scaffolded project](https://github.com/xanots/sdk/blob/main/guides/scaffold.md) | What `xanots init` writes, the two frontend presets, add-ons, SvelteKit rules |
356
+ | [Object kinds](https://github.com/xanots/sdk/blob/main/guides/object-kinds.md) | Every authorable kind, and splitting a workspace across microservices |
357
+ | [Authoring reference](https://github.com/xanots/sdk/blob/main/guides/authoring.md) | Tables and fields, statements, values, inputs, middleware, seed data |
358
+ | [CLI](https://github.com/xanots/sdk/blob/main/guides/cli.md) | Every command, shell completion, and what failures look like |
359
+ | [Signing in & deploying](https://github.com/xanots/sdk/blob/main/guides/deploying.md) | Auth, ephemerals, `--static`, releasing to production, `xanots validate` |
360
+ | [Environment & identity](https://github.com/xanots/sdk/blob/main/guides/environment.md) | Every environment variable, and how `xano.lock` pins identity |
361
+ | [The typed frontend surface](https://github.com/xanots/sdk/blob/main/guides/typed-frontend.md) | Path resolution, input/response inference, bundle cost, the route manifest |
362
+ | [Pulling an existing workspace](https://github.com/xanots/sdk/blob/main/guides/codegen.md) | What `xanots codegen` writes, how faithful it is, and how to read its report |
363
+ | [Coverage & agent grounding](https://github.com/xanots/sdk/blob/main/guides/coverage.md) | What is covered, what is out of scope, and the files agents read |
364
+
365
+ The package also ships two machine-readable descriptions of the same surface, generated from
366
+ the SDK's own sources so they cannot drift from it: `llms.txt` (the router — the mental model
367
+ and the gotchas, plus a map of the `llms/*.md` topic files) and `manifest.json` (per-entry
368
+ detail: field schemas with engine defaults, filter argument lists, stored-name mappings).
369
+ Both are readable by people too.
370
+
371
+ ---
372
+
373
+ <div align="center">
374
+
375
+ **Write TypeScript. Run `xanots deploy`. See it live.**
376
+
377
+ [npm](https://www.npmjs.com/package/@xanots/sdk) ·
378
+ [GitHub](https://github.com/xanots/sdk) ·
379
+ [Issues](https://github.com/xanots/sdk/issues) ·
380
+ [`llms.txt`](llms.txt) — the agent-facing router, mapping the `llms/` topic files
381
+
382
+ XanoTS is the official TypeScript SDK for [Xano](https://xano.com). MIT licensed.
383
+
384
+ </div>
@@ -0,0 +1,95 @@
1
+ import {
2
+ AI_PRESETS,
3
+ CODEGEN_MARKER,
4
+ managedBlockVersion,
5
+ presetFilePath,
6
+ renderPreset,
7
+ upsertManagedBlock
8
+ } from "./chunk-VKFQJEMW.js";
9
+ import "./chunk-47WDWMBJ.js";
10
+ import {
11
+ warn
12
+ } from "./chunk-EZG76F7R.js";
13
+
14
+ // src/emit/agent-file-refresh.ts
15
+ import { existsSync, readFileSync, writeFileSync } from "fs";
16
+ import { basename, join } from "path";
17
+ var AGENT_ENV_VARS = [
18
+ "CLAUDECODE",
19
+ "CLAUDE_CODE",
20
+ "CURSOR_TRACE_ID",
21
+ "CURSOR_AGENT",
22
+ "CODEX_SANDBOX",
23
+ "AIDER_MODEL",
24
+ "GITHUB_COPILOT_AGENT"
25
+ ];
26
+ function codingAgentDetected(env = process.env) {
27
+ return AGENT_ENV_VARS.some((name) => (env[name] ?? "") !== "");
28
+ }
29
+ var CI_ENV_VARS = [
30
+ "CI",
31
+ "GITHUB_ACTIONS",
32
+ "GITLAB_CI",
33
+ "BUILDKITE",
34
+ "TEAMCITY_VERSION"
35
+ ];
36
+ function isCI(env = process.env) {
37
+ return CI_ENV_VARS.some((name) => (env[name] ?? "") !== "");
38
+ }
39
+ function guidanceModeFor(projectDir) {
40
+ return existsSync(join(projectDir, CODEGEN_MARKER)) ? "generated" : "authored";
41
+ }
42
+ function appNameFor(projectDir) {
43
+ try {
44
+ const pkg = JSON.parse(readFileSync(join(projectDir, "package.json"), "utf8"));
45
+ if (typeof pkg.name === "string" && pkg.name.length > 0) return pkg.name;
46
+ } catch {
47
+ }
48
+ return basename(projectDir);
49
+ }
50
+ function refreshAgentFiles(opts) {
51
+ const env = opts.env ?? process.env;
52
+ if (isCI(env) || !codingAgentDetected(env)) return [];
53
+ const mode = opts.mode ?? guidanceModeFor(opts.projectDir);
54
+ const appName = opts.appName ?? appNameFor(opts.projectDir);
55
+ const managed = [];
56
+ for (const preset of AI_PRESETS) {
57
+ const path = presetFilePath(preset);
58
+ const absolute = join(opts.projectDir, path);
59
+ if (!existsSync(absolute)) continue;
60
+ try {
61
+ const existing = readFileSync(absolute, "utf8");
62
+ const version = managedBlockVersion(existing);
63
+ if (version === null) continue;
64
+ managed.push({ preset, path, existing, version });
65
+ } catch (err) {
66
+ warn(`could not read ${path}: ${err instanceof Error ? err.message : String(err)}`);
67
+ }
68
+ }
69
+ const selected = managed.map((m) => m.preset);
70
+ const refreshed = [];
71
+ for (const { preset, path, existing, version } of managed) {
72
+ const absolute = join(opts.projectDir, path);
73
+ try {
74
+ if (version === opts.sdkVersion) continue;
75
+ const rendered = renderPreset(preset, appName, mode, {
76
+ selected,
77
+ version: opts.sdkVersion
78
+ });
79
+ const updated = upsertManagedBlock(existing, rendered);
80
+ if (updated === existing) continue;
81
+ writeFileSync(absolute, updated);
82
+ refreshed.push(path);
83
+ } catch (err) {
84
+ warn(`could not refresh ${path}: ${err instanceof Error ? err.message : String(err)}`);
85
+ }
86
+ }
87
+ return refreshed;
88
+ }
89
+ export {
90
+ CI_ENV_VARS,
91
+ codingAgentDetected,
92
+ isCI,
93
+ refreshAgentFiles
94
+ };
95
+ //# sourceMappingURL=agent-file-refresh-7XCACU34.js.map
package/dist/bin.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/bin.js ADDED
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ readVersion,
4
+ run
5
+ } from "./chunk-YGPIY3WT.js";
6
+ import {
7
+ exitCodeOf,
8
+ reportFailure
9
+ } from "./chunk-IZW6MK3U.js";
10
+ import {
11
+ blank,
12
+ clearProgress,
13
+ detail,
14
+ error,
15
+ style,
16
+ warn
17
+ } from "./chunk-EZG76F7R.js";
18
+ import "./chunk-3DUAGYGP.js";
19
+ import "./chunk-YYRDLFSJ.js";
20
+ import "./chunk-EMCAWMHC.js";
21
+ import "./chunk-WHOJWOSV.js";
22
+ import "./chunk-LH6Z6KFV.js";
23
+ import "./chunk-HJPTWBLH.js";
24
+ import {
25
+ atomicWrite
26
+ } from "./chunk-GNPVYOPB.js";
27
+ import "./chunk-4HT3BNZ7.js";
28
+
29
+ // src/emit/update-check.ts
30
+ import { existsSync, readFileSync, mkdirSync } from "fs";
31
+ import { homedir } from "os";
32
+ import { dirname, join } from "path";
33
+ import { createRequire } from "module";
34
+ function registryUrl() {
35
+ return process.env.XANOTS_UPDATE_REGISTRY ?? "https://registry.npmjs.org/@xanots/sdk/latest";
36
+ }
37
+ function cachePath() {
38
+ return process.env.XANOTS_UPDATE_CACHE ?? join(homedir(), ".xanots", "update-check.json");
39
+ }
40
+ var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
41
+ var FETCH_TIMEOUT_MS = 2e3;
42
+ function isNewer(candidate, current) {
43
+ const a = parseSemver(candidate);
44
+ const b = parseSemver(current);
45
+ if (!a || !b) return false;
46
+ for (let i = 0; i < 3; i++) {
47
+ if (a.nums[i] !== b.nums[i]) return a.nums[i] > b.nums[i];
48
+ }
49
+ if (a.pre.length === 0) return b.pre.length > 0;
50
+ if (b.pre.length === 0) return false;
51
+ return comparePre(a.pre, b.pre) > 0;
52
+ }
53
+ function parseSemver(v) {
54
+ const m = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(v.trim());
55
+ if (!m) return null;
56
+ return {
57
+ nums: [Number(m[1]), Number(m[2]), Number(m[3])],
58
+ pre: m[4] ? m[4].split(".") : []
59
+ };
60
+ }
61
+ function comparePre(a, b) {
62
+ const len = Math.max(a.length, b.length);
63
+ for (let i = 0; i < len; i++) {
64
+ if (i >= a.length) return -1;
65
+ if (i >= b.length) return 1;
66
+ const x = a[i];
67
+ const y = b[i];
68
+ const xn = /^\d+$/.test(x);
69
+ const yn = /^\d+$/.test(y);
70
+ if (xn && yn) {
71
+ if (Number(x) !== Number(y)) return Number(x) < Number(y) ? -1 : 1;
72
+ } else if (xn !== yn) {
73
+ return xn ? -1 : 1;
74
+ } else if (x !== y) {
75
+ return x < y ? -1 : 1;
76
+ }
77
+ }
78
+ return 0;
79
+ }
80
+ function readCache() {
81
+ const path = cachePath();
82
+ if (!existsSync(path)) return void 0;
83
+ try {
84
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
85
+ if (typeof parsed.latest === "string" && typeof parsed.checkedAt === "number") {
86
+ return { latest: parsed.latest, checkedAt: parsed.checkedAt };
87
+ }
88
+ } catch {
89
+ }
90
+ return void 0;
91
+ }
92
+ function writeCache(cache) {
93
+ try {
94
+ const path = cachePath();
95
+ mkdirSync(dirname(path), { recursive: true });
96
+ atomicWrite(path, JSON.stringify(cache, null, 2) + "\n");
97
+ } catch {
98
+ }
99
+ }
100
+ async function fetchLatest() {
101
+ try {
102
+ const res = await fetch(registryUrl(), {
103
+ headers: { accept: "application/json" },
104
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
105
+ });
106
+ if (!res.ok) return null;
107
+ const data = await res.json();
108
+ return typeof data.version === "string" ? data.version : null;
109
+ } catch {
110
+ return null;
111
+ }
112
+ }
113
+ function disabled() {
114
+ return Boolean(
115
+ process.env.XANOTS_NO_UPDATE_CHECK || process.env.NO_UPDATE_NOTIFIER || process.env.CI
116
+ );
117
+ }
118
+ async function resolveUpdateNotice(opts) {
119
+ if (!opts?.force && disabled()) return null;
120
+ const current = opts?.current ?? readVersion();
121
+ if (current === "unknown") return null;
122
+ const cache = readCache();
123
+ let latest = cache?.latest;
124
+ const now = Date.now();
125
+ if (!cache || now - cache.checkedAt > CHECK_INTERVAL_MS) {
126
+ const fetched = await fetchLatest();
127
+ if (fetched) {
128
+ latest = fetched;
129
+ writeCache({ latest: fetched, checkedAt: now });
130
+ }
131
+ }
132
+ return latest && isNewer(latest, current) ? { current, latest } : null;
133
+ }
134
+ function detectInstallMode() {
135
+ const override = process.env.XANOTS_INSTALL_MODE;
136
+ if (override === "global" || override === "local") return override;
137
+ try {
138
+ const requireFromCwd = createRequire(join(process.cwd(), "package.json"));
139
+ requireFromCwd.resolve("@xanots/sdk/package.json");
140
+ return "local";
141
+ } catch {
142
+ return "global";
143
+ }
144
+ }
145
+ function upgradeCommand(mode) {
146
+ return mode === "global" ? "npm i -g @xanots/sdk@latest" : "npm i -D @xanots/sdk@latest";
147
+ }
148
+ function printUpdateNotice(notice) {
149
+ blank();
150
+ warn(
151
+ `A new @xanots/sdk is available: ${style.dim(notice.current)} \u2192 ${style.green(notice.latest)}`
152
+ );
153
+ detail(`update: ${upgradeCommand(detectInstallMode())}`);
154
+ }
155
+ function runExitedClean(code = process.exitCode) {
156
+ return code === void 0 || code === 0;
157
+ }
158
+ async function maybeNotifyUpdate() {
159
+ try {
160
+ if (disabled() || process.stderr.isTTY !== true || !runExitedClean()) return;
161
+ const notice = await resolveUpdateNotice();
162
+ if (notice) printUpdateNotice(notice);
163
+ } catch {
164
+ }
165
+ }
166
+
167
+ // src/emit/interrupt.ts
168
+ var EXIT_SIGINT = 130;
169
+ function handleInterrupt(exit = process.exit) {
170
+ clearProgress();
171
+ error("Cancelled.");
172
+ exit(EXIT_SIGINT);
173
+ }
174
+ function installInterruptHandler() {
175
+ process.on("SIGINT", () => handleInterrupt());
176
+ }
177
+
178
+ // src/emit/bin.ts
179
+ installInterruptHandler();
180
+ run(process.argv.slice(2)).then(() => maybeNotifyUpdate()).catch((err) => {
181
+ reportFailure(err, readVersion());
182
+ process.exit(exitCodeOf(err));
183
+ });
184
+ //# sourceMappingURL=bin.js.map