trellis 3.1.35 → 3.2.2

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 (287) hide show
  1. package/CHANGELOG.md +23 -5
  2. package/README.md +63 -156
  3. package/bin/trellis.mjs +2 -75
  4. package/dist/{better-sqlite-backend-ahx5p0br.js → better-sqlite-backend-2P4F6AOJ.js} +91 -29
  5. package/dist/boot-middleware-MHLHFCUC.js +9 -0
  6. package/dist/browser/index.d.ts +18 -0
  7. package/dist/browser/index.d.ts.map +1 -0
  8. package/dist/browser/index.js +95 -0
  9. package/dist/{index-53f3b8p8.js → chunk-2W3MHTMG.js} +552 -213
  10. package/dist/chunk-44FFQKQX.js +142 -0
  11. package/dist/chunk-4HYPLFJD.js +150 -0
  12. package/dist/chunk-4XIVMVHC.js +361 -0
  13. package/dist/{index-yp88he8n.js → chunk-6CTA6MCE.js} +88 -64
  14. package/dist/chunk-6GEZ6DN5.js +394 -0
  15. package/dist/chunk-7ZFRVCUE.js +211 -0
  16. package/dist/chunk-CAG4FULI.js +121 -0
  17. package/dist/chunk-FF36CQHZ.js +61 -0
  18. package/dist/{index-h32txmxe.js → chunk-FKQO5A3H.js} +6 -13
  19. package/dist/{index-nq520y6k.js → chunk-FWRS4CSC.js} +46 -32
  20. package/dist/chunk-GFZCJ4EH.js +108 -0
  21. package/dist/chunk-GLM4HGN4.js +55 -0
  22. package/dist/{index-4cdr7x2x.js → chunk-GU374KWZ.js} +182 -111
  23. package/dist/chunk-H6JB3PZ3.js +45 -0
  24. package/dist/chunk-IZX2PLIB.js +1240 -0
  25. package/dist/chunk-J2TXUFCZ.js +289 -0
  26. package/dist/chunk-J3WYZO3Q.js +211 -0
  27. package/dist/{index-xzym9w0m.js → chunk-JA7AIHRK.js} +12 -7
  28. package/dist/chunk-JHHEXEDM.js +162 -0
  29. package/dist/chunk-JUEMDWLU.js +233 -0
  30. package/dist/chunk-KFQGP6VL.js +33 -0
  31. package/dist/chunk-KIJITUZB.js +419 -0
  32. package/dist/{index-4wxa8xz4.js → chunk-KQ4A2D2P.js} +162 -23
  33. package/dist/chunk-KSU2GW22.js +958 -0
  34. package/dist/{index-rv1p47gp.js → chunk-L5N5PR2S.js} +3015 -2480
  35. package/dist/{index-h9e2efx4.js → chunk-LNUIGRDZ.js} +71 -55
  36. package/dist/{index-skhn0agf.js → chunk-MLC5BUYO.js} +19 -20
  37. package/dist/chunk-MPXUVGT3.js +104 -0
  38. package/dist/chunk-N6MYZT4O.js +68 -0
  39. package/dist/chunk-O2AV5WMN.js +48 -0
  40. package/dist/chunk-PZ4XYZ4J.js +143 -0
  41. package/dist/chunk-QB5ISE47.js +419 -0
  42. package/dist/chunk-RSWUFTO2.js +857 -0
  43. package/dist/chunk-S3XLFZ27.js +1095 -0
  44. package/dist/{index-w5wccer3.js → chunk-S6GBJ2ZB.js} +28 -12
  45. package/dist/{index-7pjz3tsy.js → chunk-SGMDTWJJ.js} +57 -15
  46. package/dist/chunk-SPSPV5BC.js +390 -0
  47. package/dist/chunk-TCKXSOBP.js +123 -0
  48. package/dist/chunk-UBGUDMUV.js +59 -0
  49. package/dist/{index-wt8rz4gn.js → chunk-UQISRW6T.js} +97 -26
  50. package/dist/chunk-USEINYUL.js +12 -0
  51. package/dist/{index-bmyt7k8n.js → chunk-UZRUP7QW.js} +12 -4
  52. package/dist/{index-xhcp6xrn.js → chunk-VBYUTRXX.js} +695 -514
  53. package/dist/{index-vkpkfwhq.js → chunk-VDAKEOML.js} +234 -194
  54. package/dist/chunk-WXSWA3MV.js +0 -0
  55. package/dist/{index-n9f2qyh5.js → chunk-X5FLTRUB.js} +55 -33
  56. package/dist/{index-h7zxhhhh.js → chunk-XMQ7G77X.js} +46 -38
  57. package/dist/{index-w7ng765c.js → chunk-YCM7ZYEZ.js} +102 -49
  58. package/dist/cli/deploy-cli.d.ts +18 -0
  59. package/dist/cli/deploy-cli.d.ts.map +1 -0
  60. package/dist/cli/errors.d.ts +6 -0
  61. package/dist/cli/errors.d.ts.map +1 -0
  62. package/dist/cli/examples.d.ts +23 -0
  63. package/dist/cli/examples.d.ts.map +1 -0
  64. package/dist/cli/index.d.ts +1 -1
  65. package/dist/cli/index.d.ts.map +1 -1
  66. package/dist/cli/index.js +2426 -6225
  67. package/dist/client/index.browser.d.ts +29 -0
  68. package/dist/client/index.browser.d.ts.map +1 -0
  69. package/dist/client/index.browser.js +64 -0
  70. package/dist/client/index.d.ts +6 -1
  71. package/dist/client/index.d.ts.map +1 -1
  72. package/dist/client/index.js +41 -21
  73. package/dist/client/live.d.ts +67 -0
  74. package/dist/client/live.d.ts.map +1 -0
  75. package/dist/client/reactive.d.ts +31 -0
  76. package/dist/client/reactive.d.ts.map +1 -0
  77. package/dist/client/sdk.browser.d.ts +104 -0
  78. package/dist/client/sdk.browser.d.ts.map +1 -0
  79. package/dist/client/sdk.browser.js +9 -0
  80. package/dist/client/sdk.d.ts +26 -2
  81. package/dist/client/sdk.d.ts.map +1 -1
  82. package/dist/client/sdk.js +9 -0
  83. package/dist/client/vcs-client.d.ts +129 -0
  84. package/dist/client/vcs-client.d.ts.map +1 -0
  85. package/dist/cms/index.js +171 -163
  86. package/dist/{config-8hczw0rs.js → config-PFTP67TR.js} +8 -9
  87. package/dist/core/computation/index.d.ts +5 -0
  88. package/dist/core/computation/index.d.ts.map +1 -0
  89. package/dist/core/computation/rollup.d.ts +18 -0
  90. package/dist/core/computation/rollup.d.ts.map +1 -0
  91. package/dist/core/index.d.ts +5 -0
  92. package/dist/core/index.d.ts.map +1 -1
  93. package/dist/core/index.js +171 -104
  94. package/dist/core/kernel/boot-middleware.d.ts +10 -0
  95. package/dist/core/kernel/boot-middleware.d.ts.map +1 -0
  96. package/dist/core/kernel/logic-middleware.d.ts +7 -1
  97. package/dist/core/kernel/logic-middleware.d.ts.map +1 -1
  98. package/dist/core/kernel/trellis-kernel.d.ts.map +1 -1
  99. package/dist/core/ontology/types.d.ts +5 -0
  100. package/dist/core/ontology/types.d.ts.map +1 -1
  101. package/dist/core/persist/better-sqlite-backend.d.ts +9 -2
  102. package/dist/core/persist/better-sqlite-backend.d.ts.map +1 -1
  103. package/dist/core/persist/factory.d.ts +6 -7
  104. package/dist/core/persist/factory.d.ts.map +1 -1
  105. package/dist/core/persist/factory.js +2 -3
  106. package/dist/core/persist/sqljs-backend.js +2 -3
  107. package/dist/db/index.d.ts +4 -1
  108. package/dist/db/index.d.ts.map +1 -1
  109. package/dist/db/index.js +67 -54
  110. package/dist/db/inspector.js +11 -19
  111. package/dist/db/trellis.css +1 -1
  112. package/dist/decisions/index.js +9 -10
  113. package/dist/deploy-LQ7GUGJ5.js +9 -0
  114. package/dist/deploy-YNVG5E4E.js +9 -0
  115. package/dist/deploy-cli-24BCHAXY.js +67 -0
  116. package/dist/deploy-cli-C35HTITO.js +67 -0
  117. package/dist/embeddings/auto-embed.d.ts +2 -2
  118. package/dist/embeddings/auto-embed.d.ts.map +1 -1
  119. package/dist/embeddings/index.js +20 -22
  120. package/dist/embeddings/search.d.ts +2 -1
  121. package/dist/embeddings/search.d.ts.map +1 -1
  122. package/dist/embeddings/store.d.ts +25 -4
  123. package/dist/embeddings/store.d.ts.map +1 -1
  124. package/dist/engine.d.ts +59 -19
  125. package/dist/engine.d.ts.map +1 -1
  126. package/dist/import-UZEKXU3B.js +10 -0
  127. package/dist/index.js +102 -93
  128. package/dist/launch-explorer-HZ4ZJA4X.js +95 -0
  129. package/dist/links/index.js +24 -26
  130. package/dist/mcp/server.d.ts.map +1 -1
  131. package/dist/plugins/agent-memory/index.js +316 -0
  132. package/dist/plugins/idea-garden/index.js +165 -0
  133. package/dist/plugins/plan-approval/index.js +579 -0
  134. package/dist/plugins/proactive-watcher/index.js +194 -0
  135. package/dist/{index-2r4jxwnb.js → query-XYLTJYSA.js} +14 -15
  136. package/dist/react/index.js +39 -70
  137. package/dist/react/realtime.js +11 -0
  138. package/dist/react/schema-hooks.js +87 -0
  139. package/dist/realtime/broadcast-channel-transport.d.ts +43 -0
  140. package/dist/realtime/broadcast-channel-transport.d.ts.map +1 -0
  141. package/dist/realtime/durable-object-relay-transport.d.ts +96 -0
  142. package/dist/realtime/durable-object-relay-transport.d.ts.map +1 -0
  143. package/dist/realtime/index.d.ts +44 -0
  144. package/dist/realtime/index.d.ts.map +1 -0
  145. package/dist/realtime/index.js +40 -0
  146. package/dist/realtime/memory-hub.d.ts +32 -0
  147. package/dist/realtime/memory-hub.d.ts.map +1 -0
  148. package/dist/realtime/persistent-channel.d.ts +105 -0
  149. package/dist/realtime/persistent-channel.d.ts.map +1 -0
  150. package/dist/realtime/presence.d.ts +73 -0
  151. package/dist/realtime/presence.d.ts.map +1 -0
  152. package/dist/realtime/relay-persistence.d.ts +37 -0
  153. package/dist/realtime/relay-persistence.d.ts.map +1 -0
  154. package/dist/realtime/relay-persistence.js +107 -0
  155. package/dist/realtime/relay-server.d.ts +103 -0
  156. package/dist/realtime/relay-server.d.ts.map +1 -0
  157. package/dist/realtime/room.d.ts +98 -0
  158. package/dist/realtime/room.d.ts.map +1 -0
  159. package/dist/realtime/text.d.ts +73 -0
  160. package/dist/realtime/text.d.ts.map +1 -0
  161. package/dist/realtime/types.d.ts +89 -0
  162. package/dist/realtime/types.d.ts.map +1 -0
  163. package/dist/realtime/websocket-relay-transport.d.ts +28 -0
  164. package/dist/realtime/websocket-relay-transport.d.ts.map +1 -0
  165. package/dist/realtime.bundle.js +1100 -0
  166. package/dist/{remote-manager-xvbg4230.js → remote-manager-ODE3T2KR.js} +25 -15
  167. package/dist/scaffold/seed.d.ts.map +1 -1
  168. package/dist/scaffold/write.d.ts +1 -1
  169. package/dist/scaffold/write.d.ts.map +1 -1
  170. package/dist/schema/define.d.ts +137 -0
  171. package/dist/schema/define.d.ts.map +1 -0
  172. package/dist/schema/entity-projection.d.ts +34 -0
  173. package/dist/schema/entity-projection.d.ts.map +1 -0
  174. package/dist/schema/eql.d.ts +46 -0
  175. package/dist/schema/eql.d.ts.map +1 -0
  176. package/dist/schema/index.d.ts +21 -0
  177. package/dist/schema/index.d.ts.map +1 -0
  178. package/dist/schema/index.js +46 -0
  179. package/dist/schema/kernel-resolve.d.ts +21 -0
  180. package/dist/schema/kernel-resolve.d.ts.map +1 -0
  181. package/dist/schema/mutations.d.ts +20 -0
  182. package/dist/schema/mutations.d.ts.map +1 -0
  183. package/dist/schema/resolve.d.ts +21 -0
  184. package/dist/schema/resolve.d.ts.map +1 -0
  185. package/dist/server/deploy-meta.d.ts +25 -0
  186. package/dist/server/deploy-meta.d.ts.map +1 -0
  187. package/dist/server/deploy.d.ts +7 -2
  188. package/dist/server/deploy.d.ts.map +1 -1
  189. package/dist/server/index.d.ts +7 -2
  190. package/dist/server/index.d.ts.map +1 -1
  191. package/dist/server/index.js +100 -58
  192. package/dist/server/node-adapter.js +5 -104
  193. package/dist/server/realtime.d.ts +14 -3
  194. package/dist/server/realtime.d.ts.map +1 -1
  195. package/dist/server/server.d.ts +8 -16
  196. package/dist/server/server.d.ts.map +1 -1
  197. package/dist/server/sprites.d.ts +18 -1
  198. package/dist/server/sprites.d.ts.map +1 -1
  199. package/dist/server/tenancy.d.ts +4 -0
  200. package/dist/server/tenancy.d.ts.map +1 -1
  201. package/dist/server/usage-meter.d.ts +53 -0
  202. package/dist/server/usage-meter.d.ts.map +1 -0
  203. package/dist/server-MB3OPSPI.js +18 -0
  204. package/dist/server-ZVWGLLRF.js +18 -0
  205. package/dist/sprites-KQGTGM6W.js +27 -0
  206. package/dist/{sprites-vc4qbrp1.js → sprites-RU3E4XQN.js} +6 -7
  207. package/dist/svelte/index.d.ts +17 -0
  208. package/dist/svelte/index.d.ts.map +1 -0
  209. package/dist/svelte/index.js +51 -0
  210. package/dist/svelte/schema-hooks.d.ts +45 -0
  211. package/dist/svelte/schema-hooks.d.ts.map +1 -0
  212. package/dist/svelte/schema-hooks.js +71 -0
  213. package/dist/svelte/stores.d.ts +78 -0
  214. package/dist/svelte/stores.d.ts.map +1 -0
  215. package/dist/sync/http-transport.d.ts +3 -3
  216. package/dist/sync/http-transport.d.ts.map +1 -1
  217. package/dist/sync/index.d.ts +15 -1
  218. package/dist/sync/index.d.ts.map +1 -1
  219. package/dist/sync/index.js +617 -0
  220. package/dist/sync/memory-room.d.ts +37 -0
  221. package/dist/sync/memory-room.d.ts.map +1 -0
  222. package/dist/sync/memory-transport.d.ts +3 -3
  223. package/dist/sync/memory-transport.d.ts.map +1 -1
  224. package/dist/sync/partykit-room.d.ts +40 -0
  225. package/dist/sync/partykit-room.d.ts.map +1 -0
  226. package/dist/sync/partykit-transport.d.ts +84 -0
  227. package/dist/sync/partykit-transport.d.ts.map +1 -0
  228. package/dist/sync/room-core.d.ts +53 -0
  229. package/dist/sync/room-core.d.ts.map +1 -0
  230. package/dist/sync/sync-engine.d.ts +40 -2
  231. package/dist/sync/sync-engine.d.ts.map +1 -1
  232. package/dist/sync/sync-room-server.d.ts +39 -0
  233. package/dist/sync/sync-room-server.d.ts.map +1 -0
  234. package/dist/sync/types.d.ts +70 -3
  235. package/dist/sync/types.d.ts.map +1 -1
  236. package/dist/sync/vcs-sync-peer.d.ts +63 -0
  237. package/dist/sync/vcs-sync-peer.d.ts.map +1 -0
  238. package/dist/sync/ws-transport.d.ts +2 -2
  239. package/dist/sync/ws-transport.d.ts.map +1 -1
  240. package/dist/tenancy-NBLLGCNJ.js +14 -0
  241. package/dist/tenancy-POMWQP6M.js +16 -0
  242. package/dist/ui/client.html +355 -67
  243. package/dist/ui/launch-explorer.d.ts +22 -0
  244. package/dist/ui/launch-explorer.d.ts.map +1 -0
  245. package/dist/ui/server.d.ts +1 -1
  246. package/dist/ui/server.d.ts.map +1 -1
  247. package/dist/vcs/blob-store.d.ts.map +1 -1
  248. package/dist/vcs/idb-op-log.d.ts +67 -0
  249. package/dist/vcs/idb-op-log.d.ts.map +1 -0
  250. package/dist/vcs/index.d.ts +1 -0
  251. package/dist/vcs/index.d.ts.map +1 -1
  252. package/dist/vcs/index.js +81 -72
  253. package/dist/vcs/issue.d.ts +22 -5
  254. package/dist/vcs/issue.d.ts.map +1 -1
  255. package/dist/vcs/lane-materialize.d.ts +5 -0
  256. package/dist/vcs/lane-materialize.d.ts.map +1 -1
  257. package/dist/vcs/op-log.d.ts +28 -2
  258. package/dist/vcs/op-log.d.ts.map +1 -1
  259. package/dist/vcs/ops.d.ts +10 -0
  260. package/dist/vcs/ops.d.ts.map +1 -1
  261. package/dist/vcs/types.d.ts +2 -0
  262. package/dist/vcs/types.d.ts.map +1 -1
  263. package/dist/{vm-config-6xhsj6b3.js → vm-config-JI4OXKDQ.js} +9 -10
  264. package/dist/vue/hooks.d.ts +64 -0
  265. package/dist/vue/hooks.d.ts.map +1 -0
  266. package/dist/vue/index.d.ts +19 -0
  267. package/dist/vue/index.d.ts.map +1 -0
  268. package/dist/vue/index.js +59 -0
  269. package/dist/vue/schema-hooks.d.ts +41 -0
  270. package/dist/vue/schema-hooks.d.ts.map +1 -0
  271. package/dist/vue/schema-hooks.js +64 -0
  272. package/package.json +130 -17
  273. package/dist/deploy-999q207z.js +0 -10
  274. package/dist/engine-y0724kjq.js +0 -8
  275. package/dist/import-s2b8e0ft.js +0 -11
  276. package/dist/index-a76rekgs.js +0 -67
  277. package/dist/index-c9h37r6h.js +0 -1
  278. package/dist/index-hr9qvv77.js +0 -860
  279. package/dist/index-k5b0xskw.js +0 -1
  280. package/dist/index-nzb3am4f.js +0 -80
  281. package/dist/index-wncptktd.js +0 -292
  282. package/dist/index-y6a4kj0p.js +0 -43
  283. package/dist/index-yhwjgfvj.js +0 -342
  284. package/dist/sdk-bepky0xs.js +0 -16
  285. package/dist/server-szdjx0nt.js +0 -13
  286. package/dist/sqlite-backend-0vsmc6qj.js +0 -8
  287. package/dist/tenancy-pjm32b4v.js +0 -14
@@ -0,0 +1,289 @@
1
+ // src/client/sdk.browser.ts
2
+ function isRemote(opts) {
3
+ return "url" in opts;
4
+ }
5
+ function browserOnlyRemoteError(feature) {
6
+ return new Error(
7
+ `${feature} is not available in browser bundles. Use remote mode with \`new TrellisDb({ url })\`, or import \`trellis/client\` in Node.`
8
+ );
9
+ }
10
+ var TrellisDb = class {
11
+ opts;
12
+ _ws = null;
13
+ /** In-flight connect — concurrent subscribe() shares one socket open. */
14
+ _wsPromise = null;
15
+ _subCallbacks = /* @__PURE__ */ new Map();
16
+ constructor(opts) {
17
+ if (!isRemote(opts)) {
18
+ throw browserOnlyRemoteError("TrellisDb local mode");
19
+ }
20
+ this.opts = opts;
21
+ }
22
+ /**
23
+ * Browser bundles cannot read `.trellis-db.json`.
24
+ */
25
+ static async fromConfig(_dir = ".") {
26
+ throw browserOnlyRemoteError("TrellisDb.fromConfig()");
27
+ }
28
+ // -------------------------------------------------------------------------
29
+ // CRUD
30
+ // -------------------------------------------------------------------------
31
+ /**
32
+ * Create a new entity.
33
+ * Returns the generated entity ID.
34
+ */
35
+ async create(type, attributes = {}, links) {
36
+ const res = await this._fetch("POST", "/entities", {
37
+ type,
38
+ attributes,
39
+ links
40
+ });
41
+ return res.id;
42
+ }
43
+ /**
44
+ * Read an entity by ID.
45
+ * Returns null if not found.
46
+ */
47
+ async read(id) {
48
+ try {
49
+ return await this._fetch(
50
+ "GET",
51
+ `/entities/${encodeURIComponent(id)}`
52
+ );
53
+ } catch (err) {
54
+ if (err?.status === 404) return null;
55
+ throw err;
56
+ }
57
+ }
58
+ /**
59
+ * Update an entity's attributes (partial update).
60
+ */
61
+ async update(id, attributes) {
62
+ await this._fetch(
63
+ "PUT",
64
+ `/entities/${encodeURIComponent(id)}`,
65
+ attributes
66
+ );
67
+ }
68
+ /**
69
+ * Delete an entity by ID.
70
+ */
71
+ async delete(id) {
72
+ await this._fetch("DELETE", `/entities/${encodeURIComponent(id)}`);
73
+ }
74
+ /**
75
+ * List entities of a given type.
76
+ */
77
+ async list(type, opts = {}) {
78
+ const params = new URLSearchParams();
79
+ if (type) params.set("type", type);
80
+ if (opts.limit) params.set("limit", String(opts.limit));
81
+ if (opts.offset) params.set("offset", String(opts.offset));
82
+ const qs = params.toString() ? `?${params}` : "";
83
+ return await this._fetch("GET", `/entities${qs}`);
84
+ }
85
+ // -------------------------------------------------------------------------
86
+ // Query
87
+ // -------------------------------------------------------------------------
88
+ /**
89
+ * Run an EQL-S query string.
90
+ */
91
+ async query(eql) {
92
+ return await this._fetch("POST", "/query", {
93
+ query: eql
94
+ });
95
+ }
96
+ // -------------------------------------------------------------------------
97
+ // Schema registration
98
+ // -------------------------------------------------------------------------
99
+ /**
100
+ * Register a user/system-tier ontology schema with a remote Trellis server.
101
+ */
102
+ async registerType(schema) {
103
+ const def = "@id" in schema ? schema : schema.definition;
104
+ try {
105
+ await this._fetch("POST", "/ontologies", def);
106
+ } catch (err) {
107
+ if (err instanceof FetchError && err.status === 409) return;
108
+ throw err;
109
+ }
110
+ }
111
+ // -------------------------------------------------------------------------
112
+ // File upload
113
+ // -------------------------------------------------------------------------
114
+ /**
115
+ * Upload a file to the blob store.
116
+ * Returns a content-addressed hash.
117
+ */
118
+ async upload(data, contentType = "application/octet-stream") {
119
+ const raw = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
120
+ const cleanBuf = raw.buffer.slice(
121
+ raw.byteOffset,
122
+ raw.byteOffset + raw.byteLength
123
+ );
124
+ const res = await fetch(`${this.opts.url}/upload`, {
125
+ method: "POST",
126
+ headers: {
127
+ "Content-Type": contentType,
128
+ ...this.opts.apiKey ? { Authorization: `Bearer ${this.opts.apiKey}` } : {}
129
+ },
130
+ body: cleanBuf
131
+ });
132
+ if (!res.ok) throw new FetchError(res.status, await res.text());
133
+ return await res.json();
134
+ }
135
+ /**
136
+ * Download a file by its blob hash.
137
+ */
138
+ async getFile(hash) {
139
+ const res = await fetch(
140
+ `${this.opts.url}/files/${encodeURIComponent(hash)}`,
141
+ {
142
+ headers: this.opts.apiKey ? { Authorization: `Bearer ${this.opts.apiKey}` } : {}
143
+ }
144
+ );
145
+ if (res.status === 404) return null;
146
+ if (!res.ok) throw new FetchError(res.status, await res.text());
147
+ return new Uint8Array(await res.arrayBuffer());
148
+ }
149
+ // -------------------------------------------------------------------------
150
+ // Auth helpers
151
+ // -------------------------------------------------------------------------
152
+ async register(email, password, name) {
153
+ return await this._fetch("POST", "/auth/register", {
154
+ email,
155
+ password,
156
+ name
157
+ });
158
+ }
159
+ async login(email, password) {
160
+ return await this._fetch("POST", "/auth/login", {
161
+ email,
162
+ password
163
+ });
164
+ }
165
+ /**
166
+ * Set the active API key / JWT token for subsequent requests.
167
+ */
168
+ setToken(token) {
169
+ this.opts.apiKey = token;
170
+ }
171
+ // -------------------------------------------------------------------------
172
+ // Realtime
173
+ // -------------------------------------------------------------------------
174
+ /**
175
+ * Subscribe to a live EQL-S query.
176
+ * Callback is fired immediately with the initial result, then on every update.
177
+ */
178
+ subscribe(eql, callback, opts) {
179
+ const subId = `sub_${crypto.randomUUID()}`;
180
+ this._subCallbacks.set(subId, callback);
181
+ this._ensureWs().then((ws) => {
182
+ ws.send(
183
+ JSON.stringify({
184
+ type: "subscribe",
185
+ id: subId,
186
+ query: eql,
187
+ ...opts?.entityType ? { entityType: opts.entityType } : {},
188
+ ...opts?.resolve ? { resolve: opts.resolve } : {}
189
+ })
190
+ );
191
+ });
192
+ return {
193
+ unsubscribe: () => {
194
+ this._subCallbacks.delete(subId);
195
+ this._ws?.send(JSON.stringify({ type: "unsubscribe", id: subId }));
196
+ }
197
+ };
198
+ }
199
+ /**
200
+ * Close the WebSocket connection.
201
+ */
202
+ disconnect() {
203
+ const ws = this._ws;
204
+ this._ws = null;
205
+ this._wsPromise = null;
206
+ ws?.close();
207
+ }
208
+ /**
209
+ * Close open client resources.
210
+ */
211
+ close() {
212
+ this.disconnect();
213
+ }
214
+ // -------------------------------------------------------------------------
215
+ // Private
216
+ // -------------------------------------------------------------------------
217
+ async _fetch(method, path, body) {
218
+ const url = `${this.opts.url}${path}`;
219
+ const res = await fetch(url, {
220
+ method,
221
+ headers: {
222
+ "Content-Type": "application/json",
223
+ ...this.opts.apiKey ? { Authorization: `Bearer ${this.opts.apiKey}` } : {}
224
+ },
225
+ body: body !== void 0 ? JSON.stringify(body) : void 0
226
+ });
227
+ const data = await res.json();
228
+ if (!res.ok)
229
+ throw new FetchError(
230
+ res.status,
231
+ data?.message ?? res.statusText,
232
+ data
233
+ );
234
+ return data;
235
+ }
236
+ _ensureWs() {
237
+ if (this._ws?.readyState === WebSocket.OPEN) {
238
+ return Promise.resolve(this._ws);
239
+ }
240
+ if (this._wsPromise) {
241
+ return this._wsPromise;
242
+ }
243
+ const wsUrl = this.opts.url.replace(
244
+ /^https?/,
245
+ this.opts.url.startsWith("https") ? "wss" : "ws"
246
+ ) + "/realtime";
247
+ this._wsPromise = new Promise((resolve, reject) => {
248
+ const ws = new WebSocket(wsUrl);
249
+ ws.onopen = () => {
250
+ this._ws = ws;
251
+ resolve(ws);
252
+ };
253
+ ws.onerror = (e) => {
254
+ reject(e instanceof Error ? e : new Error("WebSocket error"));
255
+ };
256
+ ws.onmessage = (e) => {
257
+ try {
258
+ const msg = JSON.parse(e.data);
259
+ if (msg.type === "data" && this._subCallbacks.has(msg.id)) {
260
+ const meta = msg.resolved === true ? { resolved: true } : void 0;
261
+ this._subCallbacks.get(msg.id)(msg.result, msg.diff, meta);
262
+ }
263
+ } catch {
264
+ }
265
+ };
266
+ ws.onclose = () => {
267
+ if (this._ws === ws) {
268
+ this._ws = null;
269
+ }
270
+ };
271
+ }).finally(() => {
272
+ this._wsPromise = null;
273
+ });
274
+ return this._wsPromise;
275
+ }
276
+ };
277
+ var FetchError = class extends Error {
278
+ constructor(status, message, body) {
279
+ super(`HTTP ${status}: ${message}`);
280
+ this.status = status;
281
+ this.body = body;
282
+ this.name = "FetchError";
283
+ }
284
+ };
285
+
286
+ export {
287
+ TrellisDb,
288
+ FetchError
289
+ };
@@ -0,0 +1,211 @@
1
+ import {
2
+ bindingEntityId,
3
+ bindingToEntity,
4
+ entitiesQuery,
5
+ entityQuery,
6
+ isSparseBinding,
7
+ resolveRelations
8
+ } from "./chunk-JUEMDWLU.js";
9
+ import {
10
+ Signal
11
+ } from "./chunk-UBGUDMUV.js";
12
+
13
+ // src/client/live.ts
14
+ function liveQuery(client, eql) {
15
+ const signal = new Signal({
16
+ data: [],
17
+ loading: true,
18
+ error: null
19
+ });
20
+ let sub = null;
21
+ return {
22
+ signal,
23
+ start() {
24
+ if (sub) return () => stop();
25
+ try {
26
+ sub = client.subscribe(eql, (rows) => {
27
+ signal.value = { data: rows, loading: false, error: null };
28
+ });
29
+ } catch (err) {
30
+ signal.value = {
31
+ data: [],
32
+ loading: false,
33
+ error: err instanceof Error ? err : new Error(String(err))
34
+ };
35
+ }
36
+ return () => stop();
37
+ }
38
+ };
39
+ function stop() {
40
+ sub?.unsubscribe();
41
+ sub = null;
42
+ }
43
+ }
44
+ function normalizeLiveEntitiesOpts(whereOrOpts) {
45
+ if (!whereOrOpts) return {};
46
+ if ("resolve" in whereOrOpts || "where" in whereOrOpts) {
47
+ return whereOrOpts;
48
+ }
49
+ return { where: whereOrOpts };
50
+ }
51
+ function liveEntities(client, typeOrSchema, whereOrOpts) {
52
+ const schema = typeof typeOrSchema === "string" ? void 0 : typeOrSchema;
53
+ const type = typeof typeOrSchema === "string" ? typeOrSchema : typeOrSchema.type;
54
+ const { where, resolve } = normalizeLiveEntitiesOpts(whereOrOpts);
55
+ const signal = new Signal({
56
+ data: [],
57
+ loading: true,
58
+ error: null
59
+ });
60
+ let sub = null;
61
+ let token = 0;
62
+ return {
63
+ signal,
64
+ start() {
65
+ if (sub) return () => stop();
66
+ try {
67
+ const serverResolve = schema && resolve && Object.keys(resolve).length > 0;
68
+ sub = client.subscribe(
69
+ entitiesQuery(type, where),
70
+ (rows, _diff, meta) => {
71
+ const turn = ++token;
72
+ const hydrate = async () => hydrateSubscriptionRows(client, rows, meta);
73
+ hydrate().then(async (entities) => {
74
+ if (turn !== token) return;
75
+ let data = entities;
76
+ if (schema && resolve && Object.keys(resolve).length > 0 && !meta?.resolved) {
77
+ data = await resolveRelations(
78
+ client,
79
+ schema,
80
+ data,
81
+ resolve
82
+ );
83
+ }
84
+ if (turn !== token) return;
85
+ signal.value = { data, loading: false, error: null };
86
+ }).catch((err) => {
87
+ if (turn !== token) return;
88
+ signal.value = {
89
+ data: signal.peek().data,
90
+ loading: false,
91
+ error: err instanceof Error ? err : new Error(String(err))
92
+ };
93
+ });
94
+ },
95
+ serverResolve ? { entityType: type, resolve } : void 0
96
+ );
97
+ } catch (err) {
98
+ signal.value = {
99
+ data: [],
100
+ loading: false,
101
+ error: err instanceof Error ? err : new Error(String(err))
102
+ };
103
+ }
104
+ return () => stop();
105
+ }
106
+ };
107
+ function stop() {
108
+ token++;
109
+ sub?.unsubscribe();
110
+ sub = null;
111
+ }
112
+ }
113
+ async function hydrateSubscriptionRows(client, rows, meta) {
114
+ if (rows.length === 0) return [];
115
+ if (meta?.resolved) return rows;
116
+ if (rows.some((r) => isSparseBinding(r))) {
117
+ const ids = rows.map((r) => bindingEntityId(r)).filter((id) => Boolean(id));
118
+ const loaded = await Promise.all(ids.map((id) => client.read(id)));
119
+ return loaded.filter((e) => e != null);
120
+ }
121
+ return rows.map((r) => bindingToEntity(r));
122
+ }
123
+ async function pickEntityFromRows(client, rows, entityId, meta) {
124
+ const hydrated = await hydrateSubscriptionRows(client, rows, meta);
125
+ const hit = hydrated.find((r) => r.id === entityId);
126
+ if (hit) return hit;
127
+ if (hydrated.length === 0) return client.read(entityId);
128
+ return null;
129
+ }
130
+ function liveEntity(client, typeOrSchema, id, opts) {
131
+ const schema = typeof typeOrSchema === "string" ? void 0 : typeOrSchema;
132
+ const type = typeof typeOrSchema === "string" ? typeOrSchema : typeOrSchema.type;
133
+ const { resolve } = opts ?? {};
134
+ const signal = new Signal({
135
+ data: null,
136
+ loading: Boolean(id),
137
+ error: null
138
+ });
139
+ let sub = null;
140
+ let token = 0;
141
+ return {
142
+ signal,
143
+ start() {
144
+ if (!id) {
145
+ signal.value = { data: null, loading: false, error: null };
146
+ return () => {
147
+ };
148
+ }
149
+ if (sub) return () => stop();
150
+ const entityId = id;
151
+ const serverResolve = Boolean(schema) && Boolean(resolve && Object.keys(resolve).length > 0);
152
+ const applyRow = async (row, turn) => {
153
+ if (turn !== token) return;
154
+ if (!row) {
155
+ signal.value = { data: null, loading: false, error: null };
156
+ return;
157
+ }
158
+ let data = row;
159
+ if (schema && resolve && Object.keys(resolve).length > 0 && !serverResolve) {
160
+ const [resolved] = await resolveRelations(client, schema, [data], resolve);
161
+ data = resolved ?? data;
162
+ }
163
+ if (turn !== token) return;
164
+ signal.value = { data, loading: false, error: null };
165
+ };
166
+ const readGen = token;
167
+ client.read(entityId).then((row) => applyRow(row, readGen)).catch((err) => {
168
+ signal.value = {
169
+ data: signal.peek().data,
170
+ loading: false,
171
+ error: err instanceof Error ? err : new Error(String(err))
172
+ };
173
+ });
174
+ try {
175
+ sub = client.subscribe(
176
+ entityQuery(type, entityId),
177
+ (rows, _diff, meta) => {
178
+ const turn = ++token;
179
+ pickEntityFromRows(client, rows, entityId, meta).then((row) => applyRow(row, turn)).catch((err) => {
180
+ if (turn !== token) return;
181
+ signal.value = {
182
+ data: signal.peek().data,
183
+ loading: false,
184
+ error: err instanceof Error ? err : new Error(String(err))
185
+ };
186
+ });
187
+ },
188
+ serverResolve ? { entityType: type, resolve } : void 0
189
+ );
190
+ } catch (err) {
191
+ signal.value = {
192
+ data: null,
193
+ loading: false,
194
+ error: err instanceof Error ? err : new Error(String(err))
195
+ };
196
+ }
197
+ return () => stop();
198
+ }
199
+ };
200
+ function stop() {
201
+ token++;
202
+ sub?.unsubscribe();
203
+ sub = null;
204
+ }
205
+ }
206
+
207
+ export {
208
+ liveQuery,
209
+ liveEntities,
210
+ liveEntity
211
+ };
@@ -1,4 +1,3 @@
1
- // @bun
2
1
  // src/client/config.ts
3
2
  import { existsSync, readFileSync, writeFileSync } from "fs";
4
3
  import { resolve, join } from "path";
@@ -11,8 +10,7 @@ function hasConfig(dir = ".") {
11
10
  }
12
11
  function readConfig(dir = ".") {
13
12
  const path = configPath(dir);
14
- if (!existsSync(path))
15
- return null;
13
+ if (!existsSync(path)) return null;
16
14
  try {
17
15
  return JSON.parse(readFileSync(path, "utf8"));
18
16
  } catch {
@@ -21,8 +19,7 @@ function readConfig(dir = ".") {
21
19
  }
22
20
  function writeConfig(config, dir = ".") {
23
21
  const path = configPath(dir);
24
- writeFileSync(path, JSON.stringify(config, null, 2) + `
25
- `, "utf8");
22
+ writeFileSync(path, JSON.stringify(config, null, 2) + "\n", "utf8");
26
23
  }
27
24
  function updateConfig(updates, dir = ".") {
28
25
  const existing = readConfig(dir) ?? { mode: "local" };
@@ -34,10 +31,18 @@ function defaultLocalConfig(dbPath, opts = {}) {
34
31
  return {
35
32
  mode: "local",
36
33
  dbPath,
37
- port: 3000,
34
+ port: 3e3,
38
35
  multiTenant: false,
39
36
  ...opts
40
37
  };
41
38
  }
42
39
 
43
- export { CONFIG_FILE, configPath, hasConfig, readConfig, writeConfig, updateConfig, defaultLocalConfig };
40
+ export {
41
+ CONFIG_FILE,
42
+ configPath,
43
+ hasConfig,
44
+ readConfig,
45
+ writeConfig,
46
+ updateConfig,
47
+ defaultLocalConfig
48
+ };
@@ -0,0 +1,162 @@
1
+ import {
2
+ attachStandardMiddleware
3
+ } from "./chunk-SPSPV5BC.js";
4
+ import {
5
+ SqliteKernelBackend
6
+ } from "./chunk-XMQ7G77X.js";
7
+ import {
8
+ TrellisKernel
9
+ } from "./chunk-KQ4A2D2P.js";
10
+
11
+ // src/server/tenancy.ts
12
+ import { existsSync, mkdirSync } from "fs";
13
+ import { join, resolve } from "path";
14
+ var DEFAULT_TENANT = "default";
15
+ var TENANTS_DIR = "tenants";
16
+ function resolvePoolBackendFromEnv() {
17
+ const backend = process.env.TRELLIS_BACKEND;
18
+ if (backend === "sqljs") return { backend: "sqljs" };
19
+ if (backend === "better-sqlite") return { backend: "better-sqlite" };
20
+ return void 0;
21
+ }
22
+ var TenantPool = class {
23
+ pool = /* @__PURE__ */ new Map();
24
+ dbPath;
25
+ agentId;
26
+ backendOpts;
27
+ constructor(dbPath, agentIdOrOpts = "trellis-db") {
28
+ this.dbPath = resolve(dbPath);
29
+ if (typeof agentIdOrOpts === "string") {
30
+ this.agentId = agentIdOrOpts;
31
+ this.backendOpts = void 0;
32
+ } else {
33
+ this.agentId = agentIdOrOpts.agentId ?? "trellis-db";
34
+ this.backendOpts = agentIdOrOpts.backend;
35
+ }
36
+ this._ensureDirs();
37
+ }
38
+ // -------------------------------------------------------------------------
39
+ // Public API
40
+ // -------------------------------------------------------------------------
41
+ /**
42
+ * Get (or create) the kernel for a tenant.
43
+ * Pass `null` or `undefined` to get the default tenant.
44
+ *
45
+ * Uses the synchronous bun:sqlite backend. To use an async backend
46
+ * (better-sqlite3, sql.js) call `preload(tenantId)` first; subsequent
47
+ * `get()` calls will return the preloaded kernel from the pool.
48
+ */
49
+ get(tenantId) {
50
+ const id = tenantId ?? DEFAULT_TENANT;
51
+ if (!this.pool.has(id)) {
52
+ const isBun = typeof process !== "undefined" && Boolean(process.versions?.bun);
53
+ if (!isBun) {
54
+ throw new Error(
55
+ "TenantPool.get() on Node requires `await pool.preload()` first. `trellis db serve` preloads automatically; custom servers should call preload before get()."
56
+ );
57
+ }
58
+ this.pool.set(id, this._createKernelSync(id));
59
+ }
60
+ return this.pool.get(id);
61
+ }
62
+ /**
63
+ * Pre-create a tenant's kernel using the runtime-selected backend.
64
+ * Required when running with an async-only backend (sql.js / WebContainer
65
+ * / browser). Idempotent — safe to call multiple times.
66
+ *
67
+ * After `preload()`, subsequent `get(tenantId)` returns the same kernel
68
+ * synchronously from the pool.
69
+ */
70
+ async preload(tenantId) {
71
+ const id = tenantId ?? DEFAULT_TENANT;
72
+ const cached = this.pool.get(id);
73
+ if (cached) return cached;
74
+ const kernel = await this._createKernelAsync(id);
75
+ this.pool.set(id, kernel);
76
+ return kernel;
77
+ }
78
+ /**
79
+ * Check whether a tenant has been initialized (kernel created).
80
+ */
81
+ has(tenantId) {
82
+ return this.pool.has(tenantId);
83
+ }
84
+ /**
85
+ * List all active tenant IDs (those with open kernels).
86
+ */
87
+ activeTenants() {
88
+ return Array.from(this.pool.keys());
89
+ }
90
+ /**
91
+ * Close a specific tenant's kernel and remove it from the pool.
92
+ */
93
+ close(tenantId) {
94
+ const kernel = this.pool.get(tenantId);
95
+ if (kernel) {
96
+ kernel.close();
97
+ this.pool.delete(tenantId);
98
+ }
99
+ }
100
+ /**
101
+ * Close all kernels and clear the pool.
102
+ */
103
+ closeAll() {
104
+ for (const kernel of this.pool.values()) {
105
+ kernel.close();
106
+ }
107
+ this.pool.clear();
108
+ }
109
+ /** Absolute path to the tenant data directory. */
110
+ dataPath() {
111
+ return this.dbPath;
112
+ }
113
+ /**
114
+ * Return the SQLite file path for a given tenant.
115
+ */
116
+ dbFilePath(tenantId) {
117
+ const id = tenantId ?? DEFAULT_TENANT;
118
+ if (id === DEFAULT_TENANT) {
119
+ return join(this.dbPath, "default.sqlite");
120
+ }
121
+ return join(this.dbPath, TENANTS_DIR, `${id}.sqlite`);
122
+ }
123
+ // -------------------------------------------------------------------------
124
+ // Private
125
+ // -------------------------------------------------------------------------
126
+ _createKernelSync(tenantId) {
127
+ const sqlitePath = this.dbFilePath(tenantId);
128
+ const backend = new SqliteKernelBackend(sqlitePath);
129
+ return this._wrapKernel(backend);
130
+ }
131
+ async _createKernelAsync(tenantId) {
132
+ const sqlitePath = this.dbFilePath(tenantId);
133
+ const { createKernelBackend } = await import("./core/persist/factory.js");
134
+ const backend = await createKernelBackend(sqlitePath, this.backendOpts);
135
+ return this._wrapKernel(backend);
136
+ }
137
+ _wrapKernel(backend) {
138
+ const kernel = new TrellisKernel({
139
+ backend,
140
+ agentId: this.agentId,
141
+ snapshotThreshold: 1e3
142
+ });
143
+ kernel.boot();
144
+ attachStandardMiddleware(kernel);
145
+ return kernel;
146
+ }
147
+ _ensureDirs() {
148
+ if (!existsSync(this.dbPath)) {
149
+ mkdirSync(this.dbPath, { recursive: true });
150
+ }
151
+ const tenantsPath = join(this.dbPath, TENANTS_DIR);
152
+ if (!existsSync(tenantsPath)) {
153
+ mkdirSync(tenantsPath, { recursive: true });
154
+ }
155
+ }
156
+ };
157
+
158
+ export {
159
+ DEFAULT_TENANT,
160
+ resolvePoolBackendFromEnv,
161
+ TenantPool
162
+ };