@qlever-llc/trellis 0.8.3 → 0.9.0-rc.10

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 (693) hide show
  1. package/README.md +1 -1
  2. package/bin/trellis-generate.js +132 -0
  3. package/esm/auth/browser/login.d.ts.map +1 -1
  4. package/esm/auth/browser/login.js +46 -3
  5. package/esm/auth/browser/portal.d.ts.map +1 -1
  6. package/esm/auth/browser/portal.js +5 -1
  7. package/esm/auth/browser/session.d.ts +18 -7
  8. package/esm/auth/browser/session.d.ts.map +1 -1
  9. package/esm/auth/browser/session.js +47 -11
  10. package/esm/auth/browser/storage.d.ts +6 -1
  11. package/esm/auth/browser/storage.d.ts.map +1 -1
  12. package/esm/auth/browser/storage.js +15 -3
  13. package/esm/auth/browser.d.ts +2 -2
  14. package/esm/auth/browser.d.ts.map +1 -1
  15. package/esm/auth/browser.js +1 -1
  16. package/esm/auth/device_activation.d.ts +36 -33
  17. package/esm/auth/device_activation.d.ts.map +1 -1
  18. package/esm/auth/device_activation.js +26 -22
  19. package/esm/auth/mod.d.ts +4 -4
  20. package/esm/auth/mod.d.ts.map +1 -1
  21. package/esm/auth/mod.js +2 -2
  22. package/esm/auth/proof.d.ts +3 -1
  23. package/esm/auth/proof.d.ts.map +1 -1
  24. package/esm/auth/proof.js +21 -15
  25. package/esm/auth/protocol.d.ts +2457 -941
  26. package/esm/auth/protocol.d.ts.map +1 -1
  27. package/esm/auth/protocol.js +747 -375
  28. package/esm/auth/schemas.d.ts +25 -4
  29. package/esm/auth/schemas.d.ts.map +1 -1
  30. package/esm/auth/schemas.js +14 -4
  31. package/esm/auth/session_auth.d.ts +1 -1
  32. package/esm/auth/session_auth.d.ts.map +1 -1
  33. package/esm/auth/session_auth.js +7 -1
  34. package/esm/client_connect.d.ts +2 -0
  35. package/esm/client_connect.d.ts.map +1 -1
  36. package/esm/client_connect.js +76 -15
  37. package/esm/contract.d.ts +3 -0
  38. package/esm/contract.d.ts.map +1 -1
  39. package/esm/contract_support/mod.d.ts +422 -43
  40. package/esm/contract_support/mod.d.ts.map +1 -1
  41. package/esm/contract_support/mod.js +734 -33
  42. package/esm/contract_support/protocol.d.ts +20 -5
  43. package/esm/contract_support/protocol.d.ts.map +1 -1
  44. package/esm/contract_support/protocol.js +18 -10
  45. package/esm/contract_support/runtime.d.ts +11 -0
  46. package/esm/contract_support/runtime.d.ts.map +1 -1
  47. package/esm/contract_support/schema_pointers.d.ts.map +1 -1
  48. package/esm/contract_support/schema_pointers.js +32 -14
  49. package/esm/device.d.ts +2 -0
  50. package/esm/device.d.ts.map +1 -1
  51. package/esm/device.js +3 -0
  52. package/esm/errors/AuthError.d.ts +2 -1
  53. package/esm/errors/AuthError.d.ts.map +1 -1
  54. package/esm/errors/AuthError.js +8 -3
  55. package/esm/errors/index.d.ts +4 -4
  56. package/esm/errors/index.d.ts.map +1 -1
  57. package/esm/errors/index.js +1 -0
  58. package/esm/generated-sdk/auth/api.d.ts +27 -9
  59. package/esm/generated-sdk/auth/api.d.ts.map +1 -1
  60. package/esm/generated-sdk/auth/api.js +16 -590
  61. package/esm/generated-sdk/auth/client.d.ts +91 -85
  62. package/esm/generated-sdk/auth/client.d.ts.map +1 -1
  63. package/esm/generated-sdk/auth/contract.d.ts +1 -1
  64. package/esm/generated-sdk/auth/contract.d.ts.map +1 -1
  65. package/esm/generated-sdk/auth/contract.js +4 -2
  66. package/esm/generated-sdk/auth/mod.d.ts +1 -0
  67. package/esm/generated-sdk/auth/mod.d.ts.map +1 -1
  68. package/esm/generated-sdk/auth/owned_api.d.ts +3 -0
  69. package/esm/generated-sdk/auth/owned_api.d.ts.map +1 -0
  70. package/esm/generated-sdk/auth/owned_api.js +594 -0
  71. package/esm/generated-sdk/auth/schemas.d.ts +9959 -5160
  72. package/esm/generated-sdk/auth/schemas.d.ts.map +1 -1
  73. package/esm/generated-sdk/auth/schemas.js +136 -137
  74. package/esm/generated-sdk/auth/types.d.ts +2418 -1557
  75. package/esm/generated-sdk/auth/types.d.ts.map +1 -1
  76. package/esm/generated-sdk/auth/types.js +1 -1
  77. package/esm/generated-sdk/health/api.d.ts +24 -9
  78. package/esm/generated-sdk/health/api.d.ts.map +1 -1
  79. package/esm/generated-sdk/health/api.js +12 -20
  80. package/esm/generated-sdk/health/client.d.ts +2 -1
  81. package/esm/generated-sdk/health/client.d.ts.map +1 -1
  82. package/esm/generated-sdk/health/contract.d.ts.map +1 -1
  83. package/esm/generated-sdk/health/contract.js +2 -0
  84. package/esm/generated-sdk/health/owned_api.d.ts +3 -0
  85. package/esm/generated-sdk/health/owned_api.d.ts.map +1 -0
  86. package/esm/generated-sdk/health/owned_api.js +16 -0
  87. package/esm/generated-sdk/health/types.d.ts +2 -0
  88. package/esm/generated-sdk/health/types.d.ts.map +1 -1
  89. package/esm/generated-sdk/jobs/api.d.ts +33 -9
  90. package/esm/generated-sdk/jobs/api.d.ts.map +1 -1
  91. package/esm/generated-sdk/jobs/api.js +22 -87
  92. package/esm/generated-sdk/jobs/client.d.ts +9 -2
  93. package/esm/generated-sdk/jobs/client.d.ts.map +1 -1
  94. package/esm/generated-sdk/jobs/contract.d.ts +1 -1
  95. package/esm/generated-sdk/jobs/contract.d.ts.map +1 -1
  96. package/esm/generated-sdk/jobs/contract.js +4 -2
  97. package/esm/generated-sdk/jobs/owned_api.d.ts +3 -0
  98. package/esm/generated-sdk/jobs/owned_api.d.ts.map +1 -0
  99. package/esm/generated-sdk/jobs/owned_api.js +118 -0
  100. package/esm/generated-sdk/jobs/schemas.d.ts +336 -123
  101. package/esm/generated-sdk/jobs/schemas.d.ts.map +1 -1
  102. package/esm/generated-sdk/jobs/schemas.js +17 -15
  103. package/esm/generated-sdk/jobs/types.d.ts +144 -34
  104. package/esm/generated-sdk/jobs/types.d.ts.map +1 -1
  105. package/esm/generated-sdk/jobs/types.js +36 -1
  106. package/esm/generated-sdk/state/api.d.ts +27 -9
  107. package/esm/generated-sdk/state/api.d.ts.map +1 -1
  108. package/esm/generated-sdk/state/api.js +16 -71
  109. package/esm/generated-sdk/state/client.d.ts +4 -2
  110. package/esm/generated-sdk/state/client.d.ts.map +1 -1
  111. package/esm/generated-sdk/state/contract.d.ts +1 -1
  112. package/esm/generated-sdk/state/contract.d.ts.map +1 -1
  113. package/esm/generated-sdk/state/contract.js +4 -2
  114. package/esm/generated-sdk/state/owned_api.d.ts +3 -0
  115. package/esm/generated-sdk/state/owned_api.d.ts.map +1 -0
  116. package/esm/generated-sdk/state/owned_api.js +66 -0
  117. package/esm/generated-sdk/state/schemas.d.ts +264 -284
  118. package/esm/generated-sdk/state/schemas.d.ts.map +1 -1
  119. package/esm/generated-sdk/state/schemas.js +6 -6
  120. package/esm/generated-sdk/state/types.d.ts +24 -23
  121. package/esm/generated-sdk/state/types.d.ts.map +1 -1
  122. package/esm/generated-sdk/state/types.js +1 -1
  123. package/esm/generated-sdk/trellis-core/api.d.ts +27 -9
  124. package/esm/generated-sdk/trellis-core/api.d.ts.map +1 -1
  125. package/esm/generated-sdk/trellis-core/api.js +16 -39
  126. package/esm/generated-sdk/trellis-core/client.d.ts +5 -2
  127. package/esm/generated-sdk/trellis-core/client.d.ts.map +1 -1
  128. package/esm/generated-sdk/trellis-core/contract.d.ts +1 -1
  129. package/esm/generated-sdk/trellis-core/contract.d.ts.map +1 -1
  130. package/esm/generated-sdk/trellis-core/contract.js +4 -2
  131. package/esm/generated-sdk/trellis-core/owned_api.d.ts +3 -0
  132. package/esm/generated-sdk/trellis-core/owned_api.d.ts.map +1 -0
  133. package/esm/generated-sdk/trellis-core/owned_api.js +42 -0
  134. package/esm/generated-sdk/trellis-core/schemas.d.ts +259 -11
  135. package/esm/generated-sdk/trellis-core/schemas.d.ts.map +1 -1
  136. package/esm/generated-sdk/trellis-core/schemas.js +5 -3
  137. package/esm/generated-sdk/trellis-core/types.d.ts +56 -1
  138. package/esm/generated-sdk/trellis-core/types.d.ts.map +1 -1
  139. package/esm/generated-sdk/trellis-core/types.js +1 -1
  140. package/esm/helpers.d.ts.map +1 -1
  141. package/esm/index.d.ts +4 -3
  142. package/esm/index.d.ts.map +1 -1
  143. package/esm/index.js +1 -0
  144. package/esm/jobs.d.ts +10 -1
  145. package/esm/jobs.d.ts.map +1 -1
  146. package/esm/jobs.js +16 -1
  147. package/esm/kv.d.ts.map +1 -1
  148. package/esm/kv.js +10 -4
  149. package/esm/models/auth/rpc/Logout.d.ts +4 -4
  150. package/esm/models/auth/rpc/Logout.d.ts.map +1 -1
  151. package/esm/models/auth/rpc/Logout.js +2 -2
  152. package/esm/models/trellis/Page.d.ts +2 -0
  153. package/esm/models/trellis/Page.d.ts.map +1 -0
  154. package/esm/models/trellis/Page.js +1 -0
  155. package/esm/models/trellis/State.d.ts +1 -0
  156. package/esm/models/trellis/State.d.ts.map +1 -1
  157. package/esm/models/trellis/State.js +1 -0
  158. package/esm/models/trellis/rpc/StateList.d.ts +9 -12
  159. package/esm/models/trellis/rpc/StateList.d.ts.map +1 -1
  160. package/esm/models/trellis/rpc/StateList.js +16 -18
  161. package/esm/npm/src/auth/browser/login.d.ts.map +1 -1
  162. package/esm/npm/src/auth/browser/login.js +46 -3
  163. package/esm/npm/src/auth/browser/portal.d.ts.map +1 -1
  164. package/esm/npm/src/auth/browser/portal.js +5 -1
  165. package/esm/npm/src/auth/browser/session.d.ts +18 -7
  166. package/esm/npm/src/auth/browser/session.d.ts.map +1 -1
  167. package/esm/npm/src/auth/browser/session.js +47 -11
  168. package/esm/npm/src/auth/browser/storage.d.ts +6 -1
  169. package/esm/npm/src/auth/browser/storage.d.ts.map +1 -1
  170. package/esm/npm/src/auth/browser/storage.js +15 -3
  171. package/esm/npm/src/auth/browser.d.ts +2 -2
  172. package/esm/npm/src/auth/browser.d.ts.map +1 -1
  173. package/esm/npm/src/auth/browser.js +1 -1
  174. package/esm/npm/src/auth/device_activation.d.ts +36 -33
  175. package/esm/npm/src/auth/device_activation.d.ts.map +1 -1
  176. package/esm/npm/src/auth/device_activation.js +26 -22
  177. package/esm/npm/src/auth/mod.d.ts +4 -4
  178. package/esm/npm/src/auth/mod.d.ts.map +1 -1
  179. package/esm/npm/src/auth/mod.js +2 -2
  180. package/esm/npm/src/auth/proof.d.ts +3 -1
  181. package/esm/npm/src/auth/proof.d.ts.map +1 -1
  182. package/esm/npm/src/auth/proof.js +21 -15
  183. package/esm/npm/src/auth/protocol.d.ts +2457 -941
  184. package/esm/npm/src/auth/protocol.d.ts.map +1 -1
  185. package/esm/npm/src/auth/protocol.js +747 -375
  186. package/esm/npm/src/auth/schemas.d.ts +25 -4
  187. package/esm/npm/src/auth/schemas.d.ts.map +1 -1
  188. package/esm/npm/src/auth/schemas.js +14 -4
  189. package/esm/npm/src/auth/session_auth.d.ts +1 -1
  190. package/esm/npm/src/auth/session_auth.d.ts.map +1 -1
  191. package/esm/npm/src/auth/session_auth.js +7 -1
  192. package/esm/npm/src/client_connect.d.ts +2 -0
  193. package/esm/npm/src/client_connect.d.ts.map +1 -1
  194. package/esm/npm/src/client_connect.js +76 -15
  195. package/esm/npm/src/contract.d.ts +3 -0
  196. package/esm/npm/src/contract.d.ts.map +1 -1
  197. package/esm/npm/src/contract_support/mod.d.ts +422 -43
  198. package/esm/npm/src/contract_support/mod.d.ts.map +1 -1
  199. package/esm/npm/src/contract_support/mod.js +734 -33
  200. package/esm/npm/src/contract_support/protocol.d.ts +20 -5
  201. package/esm/npm/src/contract_support/protocol.d.ts.map +1 -1
  202. package/esm/npm/src/contract_support/protocol.js +18 -10
  203. package/esm/npm/src/contract_support/runtime.d.ts +11 -0
  204. package/esm/npm/src/contract_support/runtime.d.ts.map +1 -1
  205. package/esm/npm/src/contract_support/schema_pointers.d.ts.map +1 -1
  206. package/esm/npm/src/contract_support/schema_pointers.js +32 -14
  207. package/esm/npm/src/device/deno.d.ts.map +1 -1
  208. package/esm/npm/src/device/deno.js +6 -0
  209. package/esm/npm/src/device.d.ts +2 -0
  210. package/esm/npm/src/device.d.ts.map +1 -1
  211. package/esm/npm/src/device.js +3 -0
  212. package/esm/npm/src/errors/AuthError.d.ts +2 -1
  213. package/esm/npm/src/errors/AuthError.d.ts.map +1 -1
  214. package/esm/npm/src/errors/AuthError.js +8 -3
  215. package/esm/npm/src/errors/index.d.ts +4 -4
  216. package/esm/npm/src/errors/index.d.ts.map +1 -1
  217. package/esm/npm/src/errors/index.js +1 -0
  218. package/esm/npm/src/generate.js +54 -24
  219. package/esm/npm/src/helpers.d.ts.map +1 -1
  220. package/esm/npm/src/index.d.ts +4 -3
  221. package/esm/npm/src/index.d.ts.map +1 -1
  222. package/esm/npm/src/index.js +1 -0
  223. package/esm/npm/src/jobs.d.ts +10 -1
  224. package/esm/npm/src/jobs.d.ts.map +1 -1
  225. package/esm/npm/src/jobs.js +16 -1
  226. package/esm/npm/src/kv.d.ts.map +1 -1
  227. package/esm/npm/src/kv.js +10 -4
  228. package/esm/npm/src/models/auth/rpc/Logout.d.ts +4 -4
  229. package/esm/npm/src/models/auth/rpc/Logout.d.ts.map +1 -1
  230. package/esm/npm/src/models/auth/rpc/Logout.js +2 -2
  231. package/esm/npm/src/models/trellis/Page.d.ts +2 -0
  232. package/esm/npm/src/models/trellis/Page.d.ts.map +1 -0
  233. package/esm/npm/src/models/trellis/Page.js +1 -0
  234. package/esm/npm/src/models/trellis/State.d.ts +1 -0
  235. package/esm/npm/src/models/trellis/State.d.ts.map +1 -1
  236. package/esm/npm/src/models/trellis/State.js +1 -0
  237. package/esm/npm/src/models/trellis/rpc/StateList.d.ts +9 -12
  238. package/esm/npm/src/models/trellis/rpc/StateList.d.ts.map +1 -1
  239. package/esm/npm/src/models/trellis/rpc/StateList.js +16 -18
  240. package/esm/npm/src/operations.d.ts +16 -7
  241. package/esm/npm/src/operations.d.ts.map +1 -1
  242. package/esm/npm/src/operations.js +84 -19
  243. package/esm/npm/src/runtime_transport.d.ts +2 -0
  244. package/esm/npm/src/runtime_transport.d.ts.map +1 -1
  245. package/esm/npm/src/runtime_transport.js +1 -0
  246. package/esm/npm/src/server/internal_jobs/active-job.d.ts +2 -1
  247. package/esm/npm/src/server/internal_jobs/active-job.d.ts.map +1 -1
  248. package/esm/npm/src/server/internal_jobs/active-job.js +3 -0
  249. package/esm/npm/src/server/internal_jobs/job-manager.d.ts +4 -1
  250. package/esm/npm/src/server/internal_jobs/job-manager.d.ts.map +1 -1
  251. package/esm/npm/src/server/internal_jobs/job-manager.js +61 -1
  252. package/esm/npm/src/server/internal_jobs/projection.js +1 -0
  253. package/esm/npm/src/server/internal_jobs/runtime-worker.d.ts +13 -1
  254. package/esm/npm/src/server/internal_jobs/runtime-worker.d.ts.map +1 -1
  255. package/esm/npm/src/server/internal_jobs/runtime-worker.js +73 -13
  256. package/esm/npm/src/server/internal_jobs/types.d.ts +19 -0
  257. package/esm/npm/src/server/internal_jobs/types.d.ts.map +1 -1
  258. package/esm/npm/src/server/internal_jobs/types.js +10 -0
  259. package/esm/npm/src/server/runtime.d.ts +1 -0
  260. package/esm/npm/src/server/runtime.d.ts.map +1 -1
  261. package/esm/npm/src/server/service.d.ts +10 -1
  262. package/esm/npm/src/server/service.d.ts.map +1 -1
  263. package/esm/npm/src/server/service.js +210 -64
  264. package/esm/npm/src/server/transfer.d.ts.map +1 -1
  265. package/esm/npm/src/server/transfer.js +4 -0
  266. package/esm/npm/src/server.d.ts.map +1 -1
  267. package/esm/npm/src/server.js +337 -34
  268. package/esm/npm/src/store.d.ts +8 -1
  269. package/esm/npm/src/store.d.ts.map +1 -1
  270. package/esm/npm/src/store.js +46 -8
  271. package/esm/npm/src/transfer.d.ts +3 -0
  272. package/esm/npm/src/transfer.d.ts.map +1 -1
  273. package/esm/npm/src/transfer.js +20 -30
  274. package/esm/npm/src/trellis.d.ts +85 -22
  275. package/esm/npm/src/trellis.d.ts.map +1 -1
  276. package/esm/npm/src/trellis.js +525 -61
  277. package/esm/operations.d.ts +16 -7
  278. package/esm/operations.d.ts.map +1 -1
  279. package/esm/operations.js +84 -19
  280. package/esm/runtime_transport.d.ts +2 -0
  281. package/esm/runtime_transport.d.ts.map +1 -1
  282. package/esm/runtime_transport.js +1 -0
  283. package/esm/store.d.ts +8 -1
  284. package/esm/store.d.ts.map +1 -1
  285. package/esm/store.js +46 -8
  286. package/esm/transfer.d.ts +3 -0
  287. package/esm/transfer.d.ts.map +1 -1
  288. package/esm/transfer.js +20 -30
  289. package/esm/trellis.d.ts +85 -22
  290. package/esm/trellis.d.ts.map +1 -1
  291. package/esm/trellis.js +525 -61
  292. package/package.json +6 -4
  293. package/script/auth/browser/login.d.ts.map +1 -1
  294. package/script/auth/browser/login.js +46 -3
  295. package/script/auth/browser/portal.d.ts.map +1 -1
  296. package/script/auth/browser/portal.js +5 -1
  297. package/script/auth/browser/session.d.ts +18 -7
  298. package/script/auth/browser/session.d.ts.map +1 -1
  299. package/script/auth/browser/session.js +47 -11
  300. package/script/auth/browser/storage.d.ts +6 -1
  301. package/script/auth/browser/storage.d.ts.map +1 -1
  302. package/script/auth/browser/storage.js +15 -3
  303. package/script/auth/browser.d.ts +2 -2
  304. package/script/auth/browser.d.ts.map +1 -1
  305. package/script/auth/browser.js +2 -1
  306. package/script/auth/device_activation.d.ts +36 -33
  307. package/script/auth/device_activation.d.ts.map +1 -1
  308. package/script/auth/device_activation.js +25 -21
  309. package/script/auth/mod.d.ts +4 -4
  310. package/script/auth/mod.d.ts.map +1 -1
  311. package/script/auth/mod.js +132 -137
  312. package/script/auth/proof.d.ts +3 -1
  313. package/script/auth/proof.d.ts.map +1 -1
  314. package/script/auth/proof.js +21 -15
  315. package/script/auth/protocol.d.ts +2457 -941
  316. package/script/auth/protocol.d.ts.map +1 -1
  317. package/script/auth/protocol.js +749 -377
  318. package/script/auth/schemas.d.ts +25 -4
  319. package/script/auth/schemas.d.ts.map +1 -1
  320. package/script/auth/schemas.js +16 -5
  321. package/script/auth/session_auth.d.ts +1 -1
  322. package/script/auth/session_auth.d.ts.map +1 -1
  323. package/script/auth/session_auth.js +7 -1
  324. package/script/client_connect.d.ts +2 -0
  325. package/script/client_connect.d.ts.map +1 -1
  326. package/script/client_connect.js +76 -15
  327. package/script/contract.d.ts +3 -0
  328. package/script/contract.d.ts.map +1 -1
  329. package/script/contract_support/mod.d.ts +422 -43
  330. package/script/contract_support/mod.d.ts.map +1 -1
  331. package/script/contract_support/mod.js +757 -51
  332. package/script/contract_support/protocol.d.ts +20 -5
  333. package/script/contract_support/protocol.d.ts.map +1 -1
  334. package/script/contract_support/protocol.js +20 -11
  335. package/script/contract_support/runtime.d.ts +11 -0
  336. package/script/contract_support/runtime.d.ts.map +1 -1
  337. package/script/contract_support/schema_pointers.d.ts.map +1 -1
  338. package/script/contract_support/schema_pointers.js +32 -14
  339. package/script/device.d.ts +2 -0
  340. package/script/device.d.ts.map +1 -1
  341. package/script/device.js +3 -0
  342. package/script/errors/AuthError.d.ts +2 -1
  343. package/script/errors/AuthError.d.ts.map +1 -1
  344. package/script/errors/AuthError.js +8 -3
  345. package/script/errors/index.d.ts +4 -4
  346. package/script/errors/index.d.ts.map +1 -1
  347. package/script/errors/index.js +1 -0
  348. package/script/generated-sdk/auth/api.d.ts +27 -9
  349. package/script/generated-sdk/auth/api.d.ts.map +1 -1
  350. package/script/generated-sdk/auth/api.js +17 -591
  351. package/script/generated-sdk/auth/client.d.ts +91 -85
  352. package/script/generated-sdk/auth/client.d.ts.map +1 -1
  353. package/script/generated-sdk/auth/contract.d.ts +1 -1
  354. package/script/generated-sdk/auth/contract.d.ts.map +1 -1
  355. package/script/generated-sdk/auth/contract.js +4 -2
  356. package/script/generated-sdk/auth/mod.d.ts +1 -0
  357. package/script/generated-sdk/auth/mod.d.ts.map +1 -1
  358. package/script/generated-sdk/auth/owned_api.d.ts +3 -0
  359. package/script/generated-sdk/auth/owned_api.d.ts.map +1 -0
  360. package/script/generated-sdk/auth/owned_api.js +597 -0
  361. package/script/generated-sdk/auth/schemas.d.ts +9959 -5160
  362. package/script/generated-sdk/auth/schemas.d.ts.map +1 -1
  363. package/script/generated-sdk/auth/schemas.js +139 -140
  364. package/script/generated-sdk/auth/types.d.ts +2418 -1557
  365. package/script/generated-sdk/auth/types.d.ts.map +1 -1
  366. package/script/generated-sdk/auth/types.js +1 -1
  367. package/script/generated-sdk/health/api.d.ts +24 -9
  368. package/script/generated-sdk/health/api.d.ts.map +1 -1
  369. package/script/generated-sdk/health/api.js +13 -21
  370. package/script/generated-sdk/health/client.d.ts +2 -1
  371. package/script/generated-sdk/health/client.d.ts.map +1 -1
  372. package/script/generated-sdk/health/contract.d.ts.map +1 -1
  373. package/script/generated-sdk/health/contract.js +2 -0
  374. package/script/generated-sdk/health/owned_api.d.ts +3 -0
  375. package/script/generated-sdk/health/owned_api.d.ts.map +1 -0
  376. package/script/generated-sdk/health/owned_api.js +19 -0
  377. package/script/generated-sdk/health/types.d.ts +2 -0
  378. package/script/generated-sdk/health/types.d.ts.map +1 -1
  379. package/script/generated-sdk/jobs/api.d.ts +33 -9
  380. package/script/generated-sdk/jobs/api.d.ts.map +1 -1
  381. package/script/generated-sdk/jobs/api.js +23 -88
  382. package/script/generated-sdk/jobs/client.d.ts +9 -2
  383. package/script/generated-sdk/jobs/client.d.ts.map +1 -1
  384. package/script/generated-sdk/jobs/contract.d.ts +1 -1
  385. package/script/generated-sdk/jobs/contract.d.ts.map +1 -1
  386. package/script/generated-sdk/jobs/contract.js +4 -2
  387. package/script/generated-sdk/jobs/owned_api.d.ts +3 -0
  388. package/script/generated-sdk/jobs/owned_api.d.ts.map +1 -0
  389. package/script/generated-sdk/jobs/owned_api.js +154 -0
  390. package/script/generated-sdk/jobs/schemas.d.ts +336 -123
  391. package/script/generated-sdk/jobs/schemas.d.ts.map +1 -1
  392. package/script/generated-sdk/jobs/schemas.js +18 -16
  393. package/script/generated-sdk/jobs/types.d.ts +144 -34
  394. package/script/generated-sdk/jobs/types.d.ts.map +1 -1
  395. package/script/generated-sdk/jobs/types.js +38 -2
  396. package/script/generated-sdk/state/api.d.ts +27 -9
  397. package/script/generated-sdk/state/api.d.ts.map +1 -1
  398. package/script/generated-sdk/state/api.js +17 -72
  399. package/script/generated-sdk/state/client.d.ts +4 -2
  400. package/script/generated-sdk/state/client.d.ts.map +1 -1
  401. package/script/generated-sdk/state/contract.d.ts +1 -1
  402. package/script/generated-sdk/state/contract.d.ts.map +1 -1
  403. package/script/generated-sdk/state/contract.js +4 -2
  404. package/script/generated-sdk/state/owned_api.d.ts +3 -0
  405. package/script/generated-sdk/state/owned_api.d.ts.map +1 -0
  406. package/script/generated-sdk/state/owned_api.js +69 -0
  407. package/script/generated-sdk/state/schemas.d.ts +264 -284
  408. package/script/generated-sdk/state/schemas.d.ts.map +1 -1
  409. package/script/generated-sdk/state/schemas.js +6 -6
  410. package/script/generated-sdk/state/types.d.ts +24 -23
  411. package/script/generated-sdk/state/types.d.ts.map +1 -1
  412. package/script/generated-sdk/state/types.js +1 -1
  413. package/script/generated-sdk/trellis-core/api.d.ts +27 -9
  414. package/script/generated-sdk/trellis-core/api.d.ts.map +1 -1
  415. package/script/generated-sdk/trellis-core/api.js +17 -40
  416. package/script/generated-sdk/trellis-core/client.d.ts +5 -2
  417. package/script/generated-sdk/trellis-core/client.d.ts.map +1 -1
  418. package/script/generated-sdk/trellis-core/contract.d.ts +1 -1
  419. package/script/generated-sdk/trellis-core/contract.d.ts.map +1 -1
  420. package/script/generated-sdk/trellis-core/contract.js +4 -2
  421. package/script/generated-sdk/trellis-core/owned_api.d.ts +3 -0
  422. package/script/generated-sdk/trellis-core/owned_api.d.ts.map +1 -0
  423. package/script/generated-sdk/trellis-core/owned_api.js +45 -0
  424. package/script/generated-sdk/trellis-core/schemas.d.ts +259 -11
  425. package/script/generated-sdk/trellis-core/schemas.d.ts.map +1 -1
  426. package/script/generated-sdk/trellis-core/schemas.js +6 -4
  427. package/script/generated-sdk/trellis-core/types.d.ts +56 -1
  428. package/script/generated-sdk/trellis-core/types.d.ts.map +1 -1
  429. package/script/generated-sdk/trellis-core/types.js +1 -1
  430. package/script/helpers.d.ts.map +1 -1
  431. package/script/index.d.ts +4 -3
  432. package/script/index.d.ts.map +1 -1
  433. package/script/index.js +5 -2
  434. package/script/jobs.d.ts +10 -1
  435. package/script/jobs.d.ts.map +1 -1
  436. package/script/jobs.js +17 -2
  437. package/script/kv.d.ts.map +1 -1
  438. package/script/kv.js +10 -4
  439. package/script/models/auth/rpc/Logout.d.ts +4 -4
  440. package/script/models/auth/rpc/Logout.d.ts.map +1 -1
  441. package/script/models/auth/rpc/Logout.js +3 -3
  442. package/script/models/trellis/Page.d.ts +2 -0
  443. package/script/models/trellis/Page.d.ts.map +1 -0
  444. package/script/models/trellis/Page.js +6 -0
  445. package/script/models/trellis/State.d.ts +1 -0
  446. package/script/models/trellis/State.d.ts.map +1 -1
  447. package/script/models/trellis/State.js +1 -0
  448. package/script/models/trellis/rpc/StateList.d.ts +9 -12
  449. package/script/models/trellis/rpc/StateList.d.ts.map +1 -1
  450. package/script/models/trellis/rpc/StateList.js +16 -18
  451. package/script/npm/src/auth/browser/login.d.ts.map +1 -1
  452. package/script/npm/src/auth/browser/login.js +46 -3
  453. package/script/npm/src/auth/browser/portal.d.ts.map +1 -1
  454. package/script/npm/src/auth/browser/portal.js +5 -1
  455. package/script/npm/src/auth/browser/session.d.ts +18 -7
  456. package/script/npm/src/auth/browser/session.d.ts.map +1 -1
  457. package/script/npm/src/auth/browser/session.js +47 -11
  458. package/script/npm/src/auth/browser/storage.d.ts +6 -1
  459. package/script/npm/src/auth/browser/storage.d.ts.map +1 -1
  460. package/script/npm/src/auth/browser/storage.js +15 -3
  461. package/script/npm/src/auth/browser.d.ts +2 -2
  462. package/script/npm/src/auth/browser.d.ts.map +1 -1
  463. package/script/npm/src/auth/browser.js +2 -1
  464. package/script/npm/src/auth/device_activation.d.ts +36 -33
  465. package/script/npm/src/auth/device_activation.d.ts.map +1 -1
  466. package/script/npm/src/auth/device_activation.js +25 -21
  467. package/script/npm/src/auth/mod.d.ts +4 -4
  468. package/script/npm/src/auth/mod.d.ts.map +1 -1
  469. package/script/npm/src/auth/mod.js +132 -137
  470. package/script/npm/src/auth/proof.d.ts +3 -1
  471. package/script/npm/src/auth/proof.d.ts.map +1 -1
  472. package/script/npm/src/auth/proof.js +21 -15
  473. package/script/npm/src/auth/protocol.d.ts +2457 -941
  474. package/script/npm/src/auth/protocol.d.ts.map +1 -1
  475. package/script/npm/src/auth/protocol.js +749 -377
  476. package/script/npm/src/auth/schemas.d.ts +25 -4
  477. package/script/npm/src/auth/schemas.d.ts.map +1 -1
  478. package/script/npm/src/auth/schemas.js +16 -5
  479. package/script/npm/src/auth/session_auth.d.ts +1 -1
  480. package/script/npm/src/auth/session_auth.d.ts.map +1 -1
  481. package/script/npm/src/auth/session_auth.js +7 -1
  482. package/script/npm/src/client_connect.d.ts +2 -0
  483. package/script/npm/src/client_connect.d.ts.map +1 -1
  484. package/script/npm/src/client_connect.js +76 -15
  485. package/script/npm/src/contract.d.ts +3 -0
  486. package/script/npm/src/contract.d.ts.map +1 -1
  487. package/script/npm/src/contract_support/mod.d.ts +422 -43
  488. package/script/npm/src/contract_support/mod.d.ts.map +1 -1
  489. package/script/npm/src/contract_support/mod.js +757 -51
  490. package/script/npm/src/contract_support/protocol.d.ts +20 -5
  491. package/script/npm/src/contract_support/protocol.d.ts.map +1 -1
  492. package/script/npm/src/contract_support/protocol.js +20 -11
  493. package/script/npm/src/contract_support/runtime.d.ts +11 -0
  494. package/script/npm/src/contract_support/runtime.d.ts.map +1 -1
  495. package/script/npm/src/contract_support/schema_pointers.d.ts.map +1 -1
  496. package/script/npm/src/contract_support/schema_pointers.js +32 -14
  497. package/script/npm/src/device/deno.d.ts.map +1 -1
  498. package/script/npm/src/device/deno.js +6 -0
  499. package/script/npm/src/device.d.ts +2 -0
  500. package/script/npm/src/device.d.ts.map +1 -1
  501. package/script/npm/src/device.js +3 -0
  502. package/script/npm/src/errors/AuthError.d.ts +2 -1
  503. package/script/npm/src/errors/AuthError.d.ts.map +1 -1
  504. package/script/npm/src/errors/AuthError.js +8 -3
  505. package/script/npm/src/errors/index.d.ts +4 -4
  506. package/script/npm/src/errors/index.d.ts.map +1 -1
  507. package/script/npm/src/errors/index.js +1 -0
  508. package/script/npm/src/generate.js +54 -57
  509. package/script/npm/src/helpers.d.ts.map +1 -1
  510. package/script/npm/src/index.d.ts +4 -3
  511. package/script/npm/src/index.d.ts.map +1 -1
  512. package/script/npm/src/index.js +5 -2
  513. package/script/npm/src/jobs.d.ts +10 -1
  514. package/script/npm/src/jobs.d.ts.map +1 -1
  515. package/script/npm/src/jobs.js +17 -2
  516. package/script/npm/src/kv.d.ts.map +1 -1
  517. package/script/npm/src/kv.js +10 -4
  518. package/script/npm/src/models/auth/rpc/Logout.d.ts +4 -4
  519. package/script/npm/src/models/auth/rpc/Logout.d.ts.map +1 -1
  520. package/script/npm/src/models/auth/rpc/Logout.js +3 -3
  521. package/script/npm/src/models/trellis/Page.d.ts +2 -0
  522. package/script/npm/src/models/trellis/Page.d.ts.map +1 -0
  523. package/script/npm/src/models/trellis/Page.js +6 -0
  524. package/script/npm/src/models/trellis/State.d.ts +1 -0
  525. package/script/npm/src/models/trellis/State.d.ts.map +1 -1
  526. package/script/npm/src/models/trellis/State.js +1 -0
  527. package/script/npm/src/models/trellis/rpc/StateList.d.ts +9 -12
  528. package/script/npm/src/models/trellis/rpc/StateList.d.ts.map +1 -1
  529. package/script/npm/src/models/trellis/rpc/StateList.js +16 -18
  530. package/script/npm/src/operations.d.ts +16 -7
  531. package/script/npm/src/operations.d.ts.map +1 -1
  532. package/script/npm/src/operations.js +84 -19
  533. package/script/npm/src/runtime_transport.d.ts +2 -0
  534. package/script/npm/src/runtime_transport.d.ts.map +1 -1
  535. package/script/npm/src/runtime_transport.js +2 -1
  536. package/script/npm/src/server/internal_jobs/active-job.d.ts +2 -1
  537. package/script/npm/src/server/internal_jobs/active-job.d.ts.map +1 -1
  538. package/script/npm/src/server/internal_jobs/active-job.js +3 -0
  539. package/script/npm/src/server/internal_jobs/job-manager.d.ts +4 -1
  540. package/script/npm/src/server/internal_jobs/job-manager.d.ts.map +1 -1
  541. package/script/npm/src/server/internal_jobs/job-manager.js +61 -1
  542. package/script/npm/src/server/internal_jobs/projection.js +1 -0
  543. package/script/npm/src/server/internal_jobs/runtime-worker.d.ts +13 -1
  544. package/script/npm/src/server/internal_jobs/runtime-worker.d.ts.map +1 -1
  545. package/script/npm/src/server/internal_jobs/runtime-worker.js +74 -13
  546. package/script/npm/src/server/internal_jobs/types.d.ts +19 -0
  547. package/script/npm/src/server/internal_jobs/types.d.ts.map +1 -1
  548. package/script/npm/src/server/internal_jobs/types.js +11 -1
  549. package/script/npm/src/server/runtime.d.ts +1 -0
  550. package/script/npm/src/server/runtime.d.ts.map +1 -1
  551. package/script/npm/src/server/service.d.ts +10 -1
  552. package/script/npm/src/server/service.d.ts.map +1 -1
  553. package/script/npm/src/server/service.js +208 -62
  554. package/script/npm/src/server/transfer.d.ts.map +1 -1
  555. package/script/npm/src/server/transfer.js +4 -0
  556. package/script/npm/src/server.d.ts.map +1 -1
  557. package/script/npm/src/server.js +336 -33
  558. package/script/npm/src/store.d.ts +8 -1
  559. package/script/npm/src/store.d.ts.map +1 -1
  560. package/script/npm/src/store.js +46 -8
  561. package/script/npm/src/transfer.d.ts +3 -0
  562. package/script/npm/src/transfer.d.ts.map +1 -1
  563. package/script/npm/src/transfer.js +19 -29
  564. package/script/npm/src/trellis.d.ts +85 -22
  565. package/script/npm/src/trellis.d.ts.map +1 -1
  566. package/script/npm/src/trellis.js +525 -61
  567. package/script/operations.d.ts +16 -7
  568. package/script/operations.d.ts.map +1 -1
  569. package/script/operations.js +84 -19
  570. package/script/runtime_transport.d.ts +2 -0
  571. package/script/runtime_transport.d.ts.map +1 -1
  572. package/script/runtime_transport.js +2 -1
  573. package/script/store.d.ts +8 -1
  574. package/script/store.d.ts.map +1 -1
  575. package/script/store.js +46 -8
  576. package/script/transfer.d.ts +3 -0
  577. package/script/transfer.d.ts.map +1 -1
  578. package/script/transfer.js +19 -29
  579. package/script/trellis.d.ts +85 -22
  580. package/script/trellis.d.ts.map +1 -1
  581. package/script/trellis.js +525 -61
  582. package/src/_dnt.polyfills.ts +274 -0
  583. package/src/_dnt.shims.ts +64 -0
  584. package/src/auth/browser/login.ts +295 -0
  585. package/src/auth/browser/portal.ts +75 -0
  586. package/src/auth/browser/session.ts +197 -0
  587. package/src/auth/browser/storage.ts +105 -0
  588. package/src/auth/browser.ts +82 -0
  589. package/src/auth/device_activation.ts +715 -0
  590. package/src/auth/keys.ts +116 -0
  591. package/src/auth/mod.ts +298 -0
  592. package/src/auth/proof.ts +111 -0
  593. package/src/auth/protocol.ts +1629 -0
  594. package/src/auth/schemas.ts +145 -0
  595. package/src/auth/session_auth.ts +167 -0
  596. package/src/auth/time.ts +15 -0
  597. package/src/auth/trellis_id.ts +9 -0
  598. package/src/auth/types.ts +4 -0
  599. package/src/auth/utils.ts +87 -0
  600. package/src/auth.ts +2 -0
  601. package/src/browser.ts +8 -0
  602. package/src/client.ts +164 -0
  603. package/src/client_connect.ts +1328 -0
  604. package/src/codec.ts +107 -0
  605. package/src/connection.ts +466 -0
  606. package/src/contract.ts +84 -0
  607. package/src/contract_support/canonical.ts +217 -0
  608. package/src/contract_support/mod.ts +5079 -0
  609. package/src/contract_support/protocol.ts +213 -0
  610. package/src/contract_support/runtime.ts +129 -0
  611. package/src/contract_support/schema_pointers.ts +161 -0
  612. package/src/contracts.ts +9 -0
  613. package/src/device/deno.ts +941 -0
  614. package/src/device.ts +989 -0
  615. package/src/env.ts +1 -0
  616. package/src/errors/AuthError.ts +82 -0
  617. package/src/errors/KVError.ts +47 -0
  618. package/src/errors/RemoteError.ts +111 -0
  619. package/src/errors/StoreError.ts +43 -0
  620. package/src/errors/TransferError.ts +43 -0
  621. package/src/errors/TransportError.ts +48 -0
  622. package/src/errors/TrellisError.ts +20 -0
  623. package/src/errors/ValidationError.ts +80 -0
  624. package/src/errors/index.ts +195 -0
  625. package/src/generate.ts +329 -0
  626. package/src/globals.ts +26 -0
  627. package/src/health.ts +28 -0
  628. package/src/helpers.ts +63 -0
  629. package/src/host/mod.ts +9 -0
  630. package/src/host/node.ts +9 -0
  631. package/src/index.ts +233 -0
  632. package/src/jobs.ts +344 -0
  633. package/src/kv.ts +564 -0
  634. package/src/models/auth/rpc/Logout.ts +15 -0
  635. package/src/models/trellis/Page.ts +6 -0
  636. package/src/models/trellis/State.ts +55 -0
  637. package/src/models/trellis/TrellisError.ts +21 -0
  638. package/src/models/trellis/rpc/StateDelete.ts +13 -0
  639. package/src/models/trellis/rpc/StateGet.ts +25 -0
  640. package/src/models/trellis/rpc/StateList.ts +26 -0
  641. package/src/models/trellis/rpc/StatePut.ts +42 -0
  642. package/src/operations.ts +1508 -0
  643. package/src/runtime_transport.ts +132 -0
  644. package/src/sdk/auth.ts +2 -0
  645. package/src/sdk/core.ts +2 -0
  646. package/src/sdk/health.ts +2 -0
  647. package/src/sdk/jobs.ts +2 -0
  648. package/src/sdk/state.ts +2 -0
  649. package/src/server/health.ts +379 -0
  650. package/src/server/health_rpc.ts +51 -0
  651. package/src/server/health_schemas.ts +61 -0
  652. package/src/server/internal_jobs/active-job.ts +115 -0
  653. package/src/server/internal_jobs/bindings.ts +26 -0
  654. package/src/server/internal_jobs/cancellation-registry.ts +71 -0
  655. package/src/server/internal_jobs/heartbeat.ts +120 -0
  656. package/src/server/internal_jobs/job-manager.ts +456 -0
  657. package/src/server/internal_jobs/projection.ts +48 -0
  658. package/src/server/internal_jobs/runtime-worker.ts +741 -0
  659. package/src/server/internal_jobs/types.ts +124 -0
  660. package/src/server/runtime.ts +27 -0
  661. package/src/server/service.ts +2377 -0
  662. package/src/server/subscription.ts +143 -0
  663. package/src/server/transfer.ts +962 -0
  664. package/src/server.ts +1725 -0
  665. package/src/server_logger.ts +10 -0
  666. package/src/service/deno.ts +18 -0
  667. package/src/service/mod.ts +68 -0
  668. package/src/service/node.ts +18 -0
  669. package/src/store.ts +658 -0
  670. package/src/tasks.ts +34 -0
  671. package/src/telemetry/carrier.ts +35 -0
  672. package/src/telemetry/core.ts +31 -0
  673. package/src/telemetry/env.ts +23 -0
  674. package/src/telemetry/mod.ts +26 -0
  675. package/src/telemetry/nats.ts +15 -0
  676. package/src/telemetry/result.ts +20 -0
  677. package/src/telemetry/trace.ts +39 -0
  678. package/src/telemetry/trellis.ts +1 -0
  679. package/src/tracing.ts +28 -0
  680. package/src/transfer.ts +602 -0
  681. package/src/trellis.ts +3650 -0
  682. package/esm/models/trellis/Paginate.d.ts +0 -7
  683. package/esm/models/trellis/Paginate.d.ts.map +0 -1
  684. package/esm/models/trellis/Paginate.js +0 -5
  685. package/esm/npm/src/models/trellis/Paginate.d.ts +0 -7
  686. package/esm/npm/src/models/trellis/Paginate.d.ts.map +0 -1
  687. package/esm/npm/src/models/trellis/Paginate.js +0 -5
  688. package/script/models/trellis/Paginate.d.ts +0 -7
  689. package/script/models/trellis/Paginate.d.ts.map +0 -1
  690. package/script/models/trellis/Paginate.js +0 -11
  691. package/script/npm/src/models/trellis/Paginate.d.ts +0 -7
  692. package/script/npm/src/models/trellis/Paginate.d.ts.map +0 -1
  693. package/script/npm/src/models/trellis/Paginate.js +0 -11
@@ -0,0 +1,5079 @@
1
+ import Type, {
2
+ type Static,
3
+ type TObject,
4
+ type TProperties,
5
+ type TSchema,
6
+ } from "typebox";
7
+ import { Value } from "typebox/value";
8
+ import type { BaseError } from "@qlever-llc/result";
9
+ import type { AuthSessionsMeResponse } from "../auth/protocol.js";
10
+ import { TrellisError } from "../errors/TrellisError.js";
11
+ import type {
12
+ AuthSessionsLogoutInput,
13
+ AuthSessionsLogoutResponse,
14
+ } from "../models/auth/rpc/Logout.js";
15
+ import type {
16
+ StateDeleteInput,
17
+ StateDeleteResponse,
18
+ } from "../models/trellis/rpc/StateDelete.js";
19
+ import type {
20
+ StateGetInput,
21
+ StateGetResponse,
22
+ } from "../models/trellis/rpc/StateGet.js";
23
+ import type {
24
+ StateListInput,
25
+ StateListResponse,
26
+ } from "../models/trellis/rpc/StateList.js";
27
+ import type {
28
+ StatePutInput,
29
+ StatePutResponse,
30
+ } from "../models/trellis/rpc/StatePut.js";
31
+ import {
32
+ canonicalizeJson,
33
+ digestJson,
34
+ isJsonValue,
35
+ type JsonValue,
36
+ sha256Base64urlSync,
37
+ } from "./canonical.js";
38
+ import {
39
+ type EventDesc,
40
+ type FeedDesc,
41
+ type InferRuntimeRpcError,
42
+ type InferSchemaType,
43
+ type OperationDesc,
44
+ type RPCDesc,
45
+ type RpcErrorClass,
46
+ type RuntimeRpcErrorDesc,
47
+ type Schema,
48
+ schema,
49
+ type SchemaLike,
50
+ type SerializableErrorData,
51
+ type TrellisAPI,
52
+ unwrapSchema,
53
+ } from "./runtime.js";
54
+ import {
55
+ assertDataPointersExistAndAreTokenable,
56
+ getSubschemaAtDataPointer,
57
+ type SubjectParam,
58
+ } from "./schema_pointers.js";
59
+ import {
60
+ ContractJobQueueSchema,
61
+ ContractResourcesSchema,
62
+ ContractSchemaRefSchema,
63
+ ContractStateSchema,
64
+ } from "./protocol.js";
65
+
66
+ export {
67
+ ContractJobQueueSchema,
68
+ ContractJobsSchema,
69
+ ContractKvResourceSchema,
70
+ ContractResourceBindingsSchema,
71
+ ContractResourcesSchema,
72
+ ContractSchemaRefSchema,
73
+ ContractStateSchema,
74
+ ContractStateStoreSchema,
75
+ ContractStoreResourceSchema,
76
+ type EventHeader,
77
+ EventHeaderSchema,
78
+ type InstalledServiceContract,
79
+ InstalledServiceContractSchema,
80
+ IsoDateSchema,
81
+ type JobsQueueBinding,
82
+ JobsQueueBindingSchema,
83
+ type JobsResourceBinding,
84
+ JobsResourceBindingSchema,
85
+ type KvResourceBinding,
86
+ KvResourceBindingSchema,
87
+ type PageRequest,
88
+ PageRequestSchema,
89
+ type PageResponse,
90
+ PageResponseSchema,
91
+ type StoreResourceBinding,
92
+ StoreResourceBindingSchema,
93
+ } from "./protocol.js";
94
+
95
+ export const CONTRACT_FORMAT_V1 = "trellis.contract.v1" as const;
96
+ export const CATALOG_FORMAT_V1 = "trellis.catalog.v1" as const;
97
+
98
+ const NonEmptyStringSchema = Type.String({ minLength: 1 });
99
+ const VersionSchema = Type.String({ pattern: "^v[0-9]+$" });
100
+ const PointerStringSchema = Type.String({ pattern: "^/.*" });
101
+ const CapabilityListSchema = Type.Array(NonEmptyStringSchema);
102
+ const JsonSchemaValueSchema = Type.Union([
103
+ Type.Object({}, { additionalProperties: true }),
104
+ Type.Boolean(),
105
+ ]);
106
+
107
+ export const ContractCapabilityMetadataSchema = Type.Object({
108
+ displayName: NonEmptyStringSchema,
109
+ description: NonEmptyStringSchema,
110
+ consequence: Type.Optional(NonEmptyStringSchema),
111
+ });
112
+
113
+ export const ContractCapabilitiesSchema = Type.Record(
114
+ NonEmptyStringSchema,
115
+ ContractCapabilityMetadataSchema,
116
+ );
117
+
118
+ export const ContractExportsSchema = Type.Object({
119
+ schemas: Type.Optional(
120
+ Type.Array(NonEmptyStringSchema, { uniqueItems: true }),
121
+ ),
122
+ });
123
+
124
+ const ContractUseRpcSchema = Type.Object({
125
+ call: Type.Optional(CapabilityListSchema),
126
+ });
127
+
128
+ const ContractUsePubSubSchema = Type.Object({
129
+ publish: Type.Optional(CapabilityListSchema),
130
+ subscribe: Type.Optional(CapabilityListSchema),
131
+ });
132
+
133
+ const ContractUseFeedSchema = Type.Object({
134
+ subscribe: Type.Optional(CapabilityListSchema),
135
+ });
136
+
137
+ const ContractUseSchema = Type.Object({
138
+ contract: NonEmptyStringSchema,
139
+ rpc: Type.Optional(ContractUseRpcSchema),
140
+ operations: Type.Optional(ContractUseRpcSchema),
141
+ events: Type.Optional(ContractUsePubSubSchema),
142
+ feeds: Type.Optional(ContractUseFeedSchema),
143
+ });
144
+
145
+ const ContractUsesFlatSchema = Type.Record(
146
+ NonEmptyStringSchema,
147
+ ContractUseSchema,
148
+ );
149
+
150
+ export const ContractUsesSchema = Type.Object({
151
+ required: Type.Optional(ContractUsesFlatSchema),
152
+ optional: Type.Optional(ContractUsesFlatSchema),
153
+ });
154
+
155
+ const ContractErrorDeclSchema = Type.Object({
156
+ type: NonEmptyStringSchema,
157
+ schema: Type.Optional(ContractSchemaRefSchema),
158
+ });
159
+
160
+ const ContractErrorRefSchema = Type.Object({
161
+ type: NonEmptyStringSchema,
162
+ });
163
+
164
+ const RpcCapabilitiesSchema = Type.Object({
165
+ call: Type.Optional(CapabilityListSchema),
166
+ });
167
+
168
+ const OperationCapabilitiesSchema = Type.Object({
169
+ call: Type.Optional(CapabilityListSchema),
170
+ read: Type.Optional(CapabilityListSchema),
171
+ cancel: Type.Optional(CapabilityListSchema),
172
+ control: Type.Optional(CapabilityListSchema),
173
+ });
174
+
175
+ const PubSubCapabilitiesSchema = Type.Object({
176
+ publish: Type.Optional(CapabilityListSchema),
177
+ subscribe: Type.Optional(CapabilityListSchema),
178
+ });
179
+
180
+ const FeedCapabilitiesSchema = Type.Object({
181
+ subscribe: Type.Optional(CapabilityListSchema),
182
+ });
183
+
184
+ const RpcTransferSchema = Type.Object({
185
+ direction: Type.Literal("receive"),
186
+ });
187
+
188
+ const OperationTransferSchema = Type.Object({
189
+ direction: Type.Literal("send"),
190
+ store: NonEmptyStringSchema,
191
+ key: PointerStringSchema,
192
+ contentType: Type.Optional(PointerStringSchema),
193
+ metadata: Type.Optional(PointerStringSchema),
194
+ expiresInMs: Type.Optional(Type.Integer({ minimum: 1 })),
195
+ maxBytes: Type.Optional(Type.Integer({ minimum: 1 })),
196
+ });
197
+
198
+ const ContractRpcMethodSchema = Type.Object({
199
+ version: VersionSchema,
200
+ subject: NonEmptyStringSchema,
201
+ input: ContractSchemaRefSchema,
202
+ output: ContractSchemaRefSchema,
203
+ capabilities: Type.Optional(RpcCapabilitiesSchema),
204
+ errors: Type.Optional(Type.Array(ContractErrorRefSchema)),
205
+ transfer: Type.Optional(RpcTransferSchema),
206
+ });
207
+
208
+ const ContractOperationSignalSchema = Type.Object({
209
+ input: ContractSchemaRefSchema,
210
+ });
211
+
212
+ const ContractOperationSchema = Type.Object({
213
+ version: VersionSchema,
214
+ subject: NonEmptyStringSchema,
215
+ input: ContractSchemaRefSchema,
216
+ progress: Type.Optional(ContractSchemaRefSchema),
217
+ output: ContractSchemaRefSchema,
218
+ transfer: Type.Optional(OperationTransferSchema),
219
+ capabilities: Type.Optional(OperationCapabilitiesSchema),
220
+ signals: Type.Optional(
221
+ Type.Record(NonEmptyStringSchema, ContractOperationSignalSchema),
222
+ ),
223
+ cancel: Type.Optional(Type.Boolean()),
224
+ });
225
+
226
+ const ContractEventSchema = Type.Object({
227
+ version: VersionSchema,
228
+ subject: NonEmptyStringSchema,
229
+ params: Type.Optional(Type.Array(PointerStringSchema)),
230
+ event: ContractSchemaRefSchema,
231
+ capabilities: Type.Optional(PubSubCapabilitiesSchema),
232
+ });
233
+
234
+ const ContractFeedSchema = Type.Object({
235
+ version: VersionSchema,
236
+ subject: NonEmptyStringSchema,
237
+ input: ContractSchemaRefSchema,
238
+ event: ContractSchemaRefSchema,
239
+ capabilities: Type.Optional(FeedCapabilitiesSchema),
240
+ });
241
+
242
+ export const TrellisContractV1Schema = Type.Object({
243
+ format: Type.Literal(CONTRACT_FORMAT_V1),
244
+ id: NonEmptyStringSchema,
245
+ displayName: NonEmptyStringSchema,
246
+ description: NonEmptyStringSchema,
247
+ kind: Type.Union([
248
+ Type.Literal("service"),
249
+ Type.Literal("app"),
250
+ Type.Literal("device"),
251
+ Type.Literal("agent"),
252
+ ]),
253
+ capabilities: Type.Optional(ContractCapabilitiesSchema),
254
+ schemas: Type.Optional(
255
+ Type.Record(NonEmptyStringSchema, JsonSchemaValueSchema),
256
+ ),
257
+ exports: Type.Optional(ContractExportsSchema),
258
+ uses: Type.Optional(ContractUsesSchema),
259
+ state: Type.Optional(ContractStateSchema),
260
+ rpc: Type.Optional(
261
+ Type.Record(NonEmptyStringSchema, ContractRpcMethodSchema),
262
+ ),
263
+ operations: Type.Optional(
264
+ Type.Record(NonEmptyStringSchema, ContractOperationSchema),
265
+ ),
266
+ events: Type.Optional(Type.Record(NonEmptyStringSchema, ContractEventSchema)),
267
+ feeds: Type.Optional(Type.Record(NonEmptyStringSchema, ContractFeedSchema)),
268
+ errors: Type.Optional(
269
+ Type.Record(NonEmptyStringSchema, ContractErrorDeclSchema),
270
+ ),
271
+ jobs: Type.Optional(
272
+ Type.Record(NonEmptyStringSchema, ContractJobQueueSchema),
273
+ ),
274
+ resources: Type.Optional(ContractResourcesSchema),
275
+ });
276
+
277
+ export const TrellisCatalogV1Schema = Type.Object({
278
+ format: Type.Literal(CATALOG_FORMAT_V1),
279
+ contracts: Type.Array(Type.Object({
280
+ id: NonEmptyStringSchema,
281
+ digest: Type.String({ pattern: "^[A-Za-z0-9_-]+$" }),
282
+ displayName: NonEmptyStringSchema,
283
+ description: NonEmptyStringSchema,
284
+ })),
285
+ });
286
+
287
+ const CONTRACT_MODULE_METADATA = Symbol.for(
288
+ "@qlever-llc/trellis/contracts/contract-module",
289
+ );
290
+ export const CONTRACT_JOBS_METADATA = Symbol.for(
291
+ "@qlever-llc/trellis/contracts/jobs",
292
+ );
293
+ export const CONTRACT_KV_METADATA = Symbol.for(
294
+ "@qlever-llc/trellis/contracts/kv",
295
+ );
296
+ export const CONTRACT_STATE_METADATA = Symbol.for(
297
+ "@qlever-llc/trellis/contracts/state",
298
+ );
299
+ const CONTRACT_ERROR_RUNTIME_METADATA = Symbol.for(
300
+ "@qlever-llc/trellis/contracts/error-runtime",
301
+ );
302
+
303
+ type UnionToIntersection<U> =
304
+ (U extends unknown ? (value: U) => void : never) extends
305
+ (value: infer I) => void ? I
306
+ : never;
307
+
308
+ type Simplify<T> = { [K in keyof T]: T[K] } & {};
309
+ type StringKeyOf<T> = Extract<keyof T, string>;
310
+ type KeysFromList<T> = T extends readonly (infer K)[] ? Extract<K, string>
311
+ : never;
312
+
313
+ type ReservedDefinedErrorFieldName =
314
+ | "id"
315
+ | "type"
316
+ | "message"
317
+ | "context"
318
+ | "traceId"
319
+ | "cause";
320
+
321
+ const RESERVED_DEFINED_ERROR_FIELD_NAMES: ReadonlySet<
322
+ ReservedDefinedErrorFieldName
323
+ > = new Set([
324
+ "id",
325
+ "type",
326
+ "message",
327
+ "context",
328
+ "traceId",
329
+ "cause",
330
+ ]);
331
+
332
+ const DEFINED_ERROR_PAYLOAD = Symbol.for(
333
+ "@qlever-llc/trellis/contracts/defined-error-payload",
334
+ );
335
+
336
+ export type ContractManifestMetadata = {
337
+ displayName: string;
338
+ description: string;
339
+ };
340
+
341
+ export type ContractKind = "service" | "app" | "device" | "agent";
342
+
343
+ export type Capability = string;
344
+ export type PlatformCapability = "admin" | "service";
345
+ export type GlobalCapability = `${string}::${string}`;
346
+ export type ContractCapabilityMetadata = {
347
+ displayName: string;
348
+ description: string;
349
+ consequence?: string;
350
+ };
351
+ export type ContractCapabilities = Record<string, ContractCapabilityMetadata>;
352
+ type DeclaredCapabilityName<TCapabilities> = [TCapabilities] extends [undefined]
353
+ ? never
354
+ : Extract<keyof NonNullable<TCapabilities>, string>;
355
+ type CapabilityRef<TCapabilities> =
356
+ | DeclaredCapabilityName<TCapabilities>
357
+ | GlobalCapability
358
+ | PlatformCapability;
359
+ export type JsonSchema = JsonValue | boolean;
360
+
361
+ export type ContractSchemaRef<TSchemaName extends string = string> = {
362
+ schema: TSchemaName;
363
+ };
364
+
365
+ function createSchemaRef<
366
+ const TSchemas extends Readonly<Record<string, TSchema>>,
367
+ >(_schemas: TSchemas) {
368
+ void _schemas;
369
+ return <const TName extends keyof TSchemas & string>(
370
+ schemaName: TName,
371
+ ): ContractSchemaRef<TName> => ({ schema: schemaName });
372
+ }
373
+
374
+ export type BuiltinContractErrorName =
375
+ | "UnexpectedError"
376
+ | "TransportError"
377
+ | "AuthError"
378
+ | "ValidationError"
379
+ | "KVError"
380
+ | "StoreError"
381
+ | "TransferError";
382
+
383
+ type ErrorNameOf<TErrors> =
384
+ | Extract<keyof NonNullable<TErrors>, string>
385
+ | BuiltinContractErrorName;
386
+
387
+ export type ContractRefBuilder<
388
+ TSchemas extends Readonly<Record<string, TSchema>> | undefined = undefined,
389
+ TErrors extends
390
+ | Readonly<Record<string, ErrorClass>>
391
+ | undefined = undefined,
392
+ > = {
393
+ schema<const TName extends SchemaNameOf<TSchemas>>(
394
+ schemaName: TName,
395
+ ): ContractSchemaRef<TName>;
396
+ error<const TName extends ErrorNameOf<TErrors>>(
397
+ errorName: TName,
398
+ ): TName;
399
+ capability<const TName extends GlobalCapability | PlatformCapability>(
400
+ capabilityName: TName,
401
+ ): TName;
402
+ };
403
+
404
+ export type ContractSchemas = Record<string, JsonSchema>;
405
+
406
+ export type ContractExports<TSchemaName extends string = string> = {
407
+ schemas?: TSchemaName[];
408
+ };
409
+
410
+ export type ContractStateKind = "value" | "map";
411
+
412
+ export type ContractStateStore = {
413
+ kind: ContractStateKind;
414
+ schema: ContractSchemaRef;
415
+ stateVersion?: string;
416
+ acceptedVersions?: Record<string, ContractSchemaRef>;
417
+ };
418
+
419
+ export type ContractState = Record<string, ContractStateStore>;
420
+
421
+ type ContractIdentityFields = {
422
+ id: string;
423
+ displayName: string;
424
+ description: string;
425
+ };
426
+
427
+ export type ContractErrorDecl = {
428
+ type: string;
429
+ schema?: ContractSchemaRef;
430
+ };
431
+
432
+ export type ContractErrorRef = {
433
+ type: string;
434
+ };
435
+
436
+ export type ContractRpcMethod = {
437
+ version: `v${number}`;
438
+ subject: string;
439
+ input: ContractSchemaRef;
440
+ output: ContractSchemaRef;
441
+ transfer?: { direction: "receive" };
442
+ capabilities?: { call?: Capability[] };
443
+ errors?: ContractErrorRef[];
444
+ };
445
+
446
+ export type ContractOperation = {
447
+ version: `v${number}`;
448
+ subject: string;
449
+ input: ContractSchemaRef;
450
+ progress?: ContractSchemaRef;
451
+ output: ContractSchemaRef;
452
+ transfer?: {
453
+ direction: "send";
454
+ store: string;
455
+ key: `/${string}`;
456
+ contentType?: `/${string}`;
457
+ metadata?: `/${string}`;
458
+ expiresInMs?: number;
459
+ maxBytes?: number;
460
+ };
461
+ capabilities?: {
462
+ call?: Capability[];
463
+ read?: Capability[];
464
+ cancel?: Capability[];
465
+ control?: Capability[];
466
+ };
467
+ signals?: Record<string, { input: ContractSchemaRef }>;
468
+ cancel?: boolean;
469
+ };
470
+
471
+ export type ContractEvent = {
472
+ version: `v${number}`;
473
+ subject: string;
474
+ params?: string[];
475
+ event: ContractSchemaRef;
476
+ capabilities?: { publish?: Capability[]; subscribe?: Capability[] };
477
+ };
478
+
479
+ export type ContractFeed = {
480
+ version: `v${number}`;
481
+ subject: string;
482
+ input: ContractSchemaRef;
483
+ event: ContractSchemaRef;
484
+ capabilities?: { subscribe?: Capability[] };
485
+ };
486
+
487
+ export type ContractJobQueueResource = {
488
+ payload: ContractSchemaRef;
489
+ result?: ContractSchemaRef;
490
+ maxDeliver?: number;
491
+ backoffMs?: number[];
492
+ ackWaitMs?: number;
493
+ defaultDeadlineMs?: number;
494
+ progress?: boolean;
495
+ logs?: boolean;
496
+ dlq?: boolean;
497
+ concurrency?: number;
498
+ };
499
+
500
+ export type ContractJobQueue = ContractJobQueueResource;
501
+
502
+ export type ContractJobs = Record<string, ContractJobQueue>;
503
+
504
+ export type ContractKvResource = {
505
+ purpose: string;
506
+ schema: ContractSchemaRef;
507
+ required?: boolean;
508
+ history?: number;
509
+ ttlMs?: number;
510
+ maxValueBytes?: number;
511
+ };
512
+
513
+ export type ContractStoreResource = {
514
+ purpose: string;
515
+ required?: boolean;
516
+ ttlMs?: number;
517
+ maxObjectBytes?: number;
518
+ maxTotalBytes?: number;
519
+ };
520
+
521
+ export type ContractResources = {
522
+ kv?: Record<string, ContractKvResource>;
523
+ store?: Record<string, ContractStoreResource>;
524
+ };
525
+
526
+ export type ContractUsesRpc = {
527
+ call?: string[];
528
+ };
529
+
530
+ export type ContractUsesPubSub = {
531
+ publish?: string[];
532
+ subscribe?: string[];
533
+ };
534
+
535
+ export type ContractUse = {
536
+ contract: string;
537
+ rpc?: ContractUsesRpc;
538
+ operations?: ContractUsesRpc;
539
+ events?: ContractUsesPubSub;
540
+ feeds?: { subscribe?: string[] };
541
+ };
542
+
543
+ type ContractUsesFlat = Record<string, ContractUse>;
544
+
545
+ export type ContractUsesGrouped = {
546
+ required?: Record<string, ContractUse>;
547
+ optional?: Record<string, ContractUse>;
548
+ };
549
+
550
+ export type ContractUses = ContractUsesGrouped;
551
+
552
+ export type TrellisContractV1 = {
553
+ format: typeof CONTRACT_FORMAT_V1;
554
+ id: string;
555
+ displayName: string;
556
+ description: string;
557
+ kind: ContractKind;
558
+ capabilities?: ContractCapabilities;
559
+ schemas?: ContractSchemas;
560
+ exports?: ContractExports;
561
+ state?: ContractState;
562
+ uses?: ContractUses;
563
+ rpc?: Record<string, ContractRpcMethod>;
564
+ operations?: Record<string, ContractOperation>;
565
+ events?: Record<string, ContractEvent>;
566
+ feeds?: Record<string, ContractFeed>;
567
+ errors?: Record<string, ContractErrorDecl>;
568
+ jobs?: ContractJobs;
569
+ resources?: ContractResources;
570
+ };
571
+
572
+ export type TrellisCatalogEntry = {
573
+ id: string;
574
+ digest: string;
575
+ displayName: string;
576
+ description: string;
577
+ };
578
+
579
+ export type TrellisCatalogV1 = {
580
+ format: typeof CATALOG_FORMAT_V1;
581
+ contracts: TrellisCatalogEntry[];
582
+ };
583
+
584
+ export type ContractSourceErrorDecl<TSchemaName extends string = string> = {
585
+ type: string;
586
+ schema?: ContractSchemaRef<TSchemaName>;
587
+ };
588
+
589
+ type ExtractErrorClasses<TErrors> = TErrors extends
590
+ Readonly<Record<string, unknown>> ? {
591
+ [
592
+ K in keyof TErrors as TErrors[K] extends ErrorClass ? K
593
+ : never
594
+ ]: Extract<TErrors[K], ErrorClass>;
595
+ }
596
+ : undefined;
597
+
598
+ type ContractErrorRuntimeMarker<
599
+ TClass extends RpcErrorClass = RpcErrorClass,
600
+ > = {
601
+ readonly [CONTRACT_ERROR_RUNTIME_METADATA]: TClass;
602
+ };
603
+
604
+ export type ErrorClass<
605
+ TData extends SerializableErrorData = SerializableErrorData,
606
+ TError extends BaseError = BaseError,
607
+ TRuntimeSchema extends TSchema = TSchema,
608
+ > = RpcErrorClass<TData, TError> & {
609
+ readonly name: string;
610
+ readonly schema: TRuntimeSchema;
611
+ readonly type?: string;
612
+ };
613
+
614
+ type DefinedErrorPayload<TFields extends TProperties> =
615
+ & Static<TObject<TFields>>
616
+ & object;
617
+
618
+ type DefinedErrorData<TType extends string, TFields extends TProperties> =
619
+ & SerializableErrorData
620
+ & { type: TType }
621
+ & DefinedErrorPayload<TFields>;
622
+
623
+ type DefinedErrorSchema = TObject<TProperties>;
624
+
625
+ type DefinedErrorPayloadCarrier<TPayload extends object> = {
626
+ [DEFINED_ERROR_PAYLOAD]: Readonly<TPayload>;
627
+ };
628
+
629
+ export type DefineErrorOptions<
630
+ TType extends string,
631
+ TFields extends TProperties,
632
+ > = {
633
+ type: TType;
634
+ fields: TFields;
635
+ message:
636
+ | string
637
+ | ((payload: Readonly<DefinedErrorPayload<TFields>>) => string);
638
+ };
639
+
640
+ export type DefinedErrorInit<TFields extends TProperties> =
641
+ & DefinedErrorPayload<TFields>
642
+ & ErrorOptions
643
+ & {
644
+ context?: Record<string, unknown>;
645
+ id?: string;
646
+ traceId?: string;
647
+ };
648
+
649
+ export type DefinedErrorInstance<
650
+ TType extends string,
651
+ TFields extends TProperties,
652
+ > =
653
+ & TrellisError<DefinedErrorData<TType, TFields>>
654
+ & DefinedErrorPayloadCarrier<DefinedErrorPayload<TFields>>
655
+ & Readonly<DefinedErrorPayload<TFields>>;
656
+
657
+ export type DefinedErrorClass<
658
+ TType extends string,
659
+ TFields extends TProperties,
660
+ > =
661
+ & ErrorClass<
662
+ DefinedErrorData<TType, TFields>,
663
+ DefinedErrorInstance<TType, TFields>,
664
+ DefinedErrorSchema
665
+ >
666
+ & {
667
+ new (
668
+ options: DefinedErrorInit<TFields>,
669
+ ): DefinedErrorInstance<TType, TFields>;
670
+ readonly type: TType;
671
+ readonly schema: DefinedErrorSchema;
672
+ fromSerializable(
673
+ data: DefinedErrorData<TType, TFields>,
674
+ ): DefinedErrorInstance<TType, TFields>;
675
+ };
676
+
677
+ function getContractErrorType(errorClass: ErrorClass): string {
678
+ const explicitType = Reflect.get(errorClass, "type");
679
+ return typeof explicitType === "string" ? explicitType : errorClass.name;
680
+ }
681
+
682
+ function isSerializableErrorData(
683
+ value: unknown,
684
+ ): value is SerializableErrorData {
685
+ return !!value && typeof value === "object" &&
686
+ typeof (value as { id?: unknown }).id === "string" &&
687
+ typeof (value as { type?: unknown }).type === "string" &&
688
+ typeof (value as { message?: unknown }).message === "string";
689
+ }
690
+
691
+ function isErrorClass(value: unknown): value is ErrorClass {
692
+ return typeof value === "function" &&
693
+ typeof Reflect.get(value, "name") === "string" &&
694
+ typeof Reflect.get(value, "fromSerializable") === "function" &&
695
+ typeof Reflect.get(value, "schema") === "object";
696
+ }
697
+
698
+ function assertNoReservedDefinedErrorFieldNames(fields: TProperties): void {
699
+ for (const fieldName of Object.keys(fields)) {
700
+ if (
701
+ RESERVED_DEFINED_ERROR_FIELD_NAMES.has(
702
+ fieldName as ReservedDefinedErrorFieldName,
703
+ )
704
+ ) {
705
+ throw new Error(`Defined error field '${fieldName}' is reserved`);
706
+ }
707
+ }
708
+ }
709
+
710
+ function createDefinedErrorSchema<
711
+ TType extends string,
712
+ TFields extends TProperties,
713
+ >(
714
+ type: TType,
715
+ fields: TFields,
716
+ ): DefinedErrorSchema {
717
+ return Type.Object({
718
+ id: Type.String(),
719
+ type: Type.Literal(type),
720
+ message: Type.String(),
721
+ ...fields,
722
+ context: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
723
+ traceId: Type.Optional(Type.String()),
724
+ });
725
+ }
726
+
727
+ function definedErrorPayloadFieldNames<TFields extends TProperties>(
728
+ fields: TFields,
729
+ ): readonly (keyof DefinedErrorPayload<TFields> & string)[] {
730
+ return Object.keys(fields) as Array<
731
+ keyof DefinedErrorPayload<TFields> & string
732
+ >;
733
+ }
734
+
735
+ function pickDefinedErrorPayload<TPayload extends object>(
736
+ fieldNames: readonly (keyof TPayload & string)[],
737
+ source: TPayload,
738
+ ): Readonly<TPayload> {
739
+ return Object.fromEntries(
740
+ fieldNames.map((fieldName) => [fieldName, source[fieldName]]),
741
+ ) as TPayload;
742
+ }
743
+
744
+ function definedErrorBaseOptions<TPayload extends object>(
745
+ options: TPayload & {
746
+ context?: Record<string, unknown>;
747
+ id?: string;
748
+ traceId?: string;
749
+ cause?: unknown;
750
+ },
751
+ ): ErrorOptions & {
752
+ context?: Record<string, unknown>;
753
+ id?: string;
754
+ traceId?: string;
755
+ } {
756
+ const baseOptions: ErrorOptions & {
757
+ context?: Record<string, unknown>;
758
+ id?: string;
759
+ traceId?: string;
760
+ } = {};
761
+ if (options.cause !== undefined) {
762
+ baseOptions.cause = options.cause;
763
+ }
764
+ if (options.context !== undefined) {
765
+ baseOptions.context = options.context;
766
+ }
767
+ if (options.id !== undefined) {
768
+ baseOptions.id = options.id;
769
+ }
770
+ if (options.traceId !== undefined) {
771
+ baseOptions.traceId = options.traceId;
772
+ }
773
+ return baseOptions;
774
+ }
775
+
776
+ function attachDefinedErrorPayload<
777
+ TError extends TrellisError<SerializableErrorData>,
778
+ TPayload extends object,
779
+ >(
780
+ error: TError & DefinedErrorPayloadCarrier<TPayload>,
781
+ payload: Readonly<TPayload>,
782
+ ): TError & Readonly<TPayload> & DefinedErrorPayloadCarrier<TPayload> {
783
+ error[DEFINED_ERROR_PAYLOAD] = payload;
784
+ return Object.assign(error, payload);
785
+ }
786
+
787
+ export type ContractSourceSchemas = Record<string, TSchema>;
788
+
789
+ export type ContractSourceExports<TSchemaName extends string = string> = {
790
+ schemas?: readonly TSchemaName[];
791
+ };
792
+
793
+ export type ContractSourceStateStore<TSchemaName extends string = string> = {
794
+ kind: ContractStateKind;
795
+ schema: ContractSchemaRef<TSchemaName>;
796
+ stateVersion?: string;
797
+ acceptedVersions?: Record<string, ContractSchemaRef<TSchemaName>>;
798
+ };
799
+
800
+ export type ContractSourceState<TSchemaName extends string = string> = Record<
801
+ string,
802
+ ContractSourceStateStore<TSchemaName>
803
+ >;
804
+
805
+ export type ContractSourceRpcMethod<
806
+ TSchemaName extends string = string,
807
+ TErrorName extends string = string,
808
+ TCapability extends string = Capability,
809
+ > = {
810
+ version: `v${number}`;
811
+ input: ContractSchemaRef<TSchemaName>;
812
+ output: ContractSchemaRef<TSchemaName>;
813
+ capabilities?: { call?: readonly TCapability[] };
814
+ transfer?: { direction: "receive" };
815
+ errors?: readonly TErrorName[];
816
+ authRequired?: boolean;
817
+ subject?: string;
818
+ };
819
+
820
+ export type ContractSourceOperation<
821
+ TSchemaName extends string = string,
822
+ TCapability extends string = Capability,
823
+ > = {
824
+ version: `v${number}`;
825
+ input: ContractSchemaRef<TSchemaName>;
826
+ progress?: ContractSchemaRef<TSchemaName>;
827
+ output: ContractSchemaRef<TSchemaName>;
828
+ transfer?: {
829
+ direction: "send";
830
+ store: string;
831
+ key: `/${string}`;
832
+ contentType?: `/${string}`;
833
+ metadata?: `/${string}`;
834
+ expiresInMs?: number;
835
+ maxBytes?: number;
836
+ };
837
+ capabilities?: {
838
+ call?: readonly TCapability[];
839
+ read?: readonly TCapability[];
840
+ cancel?: readonly TCapability[];
841
+ control?: readonly TCapability[];
842
+ };
843
+ signals?: Record<string, { input: ContractSchemaRef<TSchemaName> }>;
844
+ cancel?: boolean;
845
+ subject?: string;
846
+ };
847
+
848
+ export type ContractSourceEvent<
849
+ TSchemaName extends string = string,
850
+ TCapability extends string = Capability,
851
+ > = {
852
+ version: `v${number}`;
853
+ event: ContractSchemaRef<TSchemaName>;
854
+ params?: readonly SubjectParam[];
855
+ capabilities?: {
856
+ publish?: readonly TCapability[];
857
+ subscribe?: readonly TCapability[];
858
+ };
859
+ subject?: string;
860
+ };
861
+
862
+ export type ContractSourceFeed<
863
+ TSchemaName extends string = string,
864
+ TCapability extends string = Capability,
865
+ > = {
866
+ version: `v${number}`;
867
+ input: ContractSchemaRef<TSchemaName>;
868
+ event: ContractSchemaRef<TSchemaName>;
869
+ capabilities?: { subscribe?: readonly TCapability[] };
870
+ subject?: string;
871
+ };
872
+
873
+ export type ContractSourceJobQueue<
874
+ TSchemaName extends string = string,
875
+ > = {
876
+ payload: ContractSchemaRef<TSchemaName>;
877
+ result?: ContractSchemaRef<TSchemaName>;
878
+ maxDeliver?: number;
879
+ backoffMs?: readonly number[];
880
+ ackWaitMs?: number;
881
+ defaultDeadlineMs?: number;
882
+ progress?: boolean;
883
+ logs?: boolean;
884
+ dlq?: boolean;
885
+ concurrency?: number;
886
+ };
887
+
888
+ export type ContractSourceJobs<TSchemaName extends string = string> = Record<
889
+ string,
890
+ ContractSourceJobQueue<TSchemaName>
891
+ >;
892
+
893
+ export type ContractSourceKvResource<TSchemaName extends string = string> = {
894
+ purpose: string;
895
+ schema: ContractSchemaRef<TSchemaName>;
896
+ required?: boolean;
897
+ history?: number;
898
+ ttlMs?: number;
899
+ maxValueBytes?: number;
900
+ };
901
+
902
+ export type ContractSourceStoreResource = {
903
+ purpose: string;
904
+ required?: boolean;
905
+ ttlMs?: number;
906
+ maxObjectBytes?: number;
907
+ maxTotalBytes?: number;
908
+ };
909
+
910
+ export type ContractSourceResources<TSchemaName extends string = string> = {
911
+ kv?: Record<string, ContractSourceKvResource<TSchemaName>>;
912
+ store?: Record<string, ContractSourceStoreResource>;
913
+ };
914
+
915
+ export type ContractSourceUse = {
916
+ contract: string;
917
+ rpc?: { call?: readonly string[] };
918
+ operations?: { call?: readonly string[] };
919
+ events?: { publish?: readonly string[]; subscribe?: readonly string[] };
920
+ feeds?: { subscribe?: readonly string[] };
921
+ };
922
+
923
+ type ContractSourceUsesFlat = Record<string, ContractSourceUse>;
924
+
925
+ export type ContractSourceUsesGrouped = {
926
+ required?: Record<string, ContractSourceUse>;
927
+ optional?: Record<string, ContractSourceUse>;
928
+ };
929
+
930
+ export type ContractSourceUses = ContractSourceUsesGrouped;
931
+
932
+ export type TrellisContractSource = {
933
+ id: string;
934
+ displayName: string;
935
+ description: string;
936
+ kind: ContractKind;
937
+ capabilities?: ContractCapabilities;
938
+ schemas?: ContractSourceSchemas;
939
+ exports?: ContractSourceExports;
940
+ state?: ContractSourceState;
941
+ uses?: ContractSourceUses;
942
+ rpc?: Record<string, ContractSourceRpcMethod>;
943
+ operations?: Record<string, ContractSourceOperation>;
944
+ events?: Record<string, ContractSourceEvent>;
945
+ feeds?: Record<string, ContractSourceFeed>;
946
+ errors?: Record<string, ContractSourceErrorDecl>;
947
+ jobs?: ContractSourceJobs;
948
+ resources?: ContractSourceResources;
949
+ };
950
+
951
+ export type TrellisApiLike = {
952
+ rpc: Record<string, RPCDesc>;
953
+ operations: Record<string, OperationDesc>;
954
+ events: Record<string, EventDesc>;
955
+ feeds?: Record<string, FeedDesc>;
956
+ subjects: Record<string, unknown>;
957
+ };
958
+
959
+ type ApiShape = {
960
+ rpc: Record<string, unknown>;
961
+ operations: Record<string, unknown>;
962
+ events: Record<string, unknown>;
963
+ feeds?: Record<string, unknown>;
964
+ subjects: Record<string, unknown>;
965
+ };
966
+
967
+ export type EmptyApi = {
968
+ rpc: {};
969
+ operations: {};
970
+ events: {};
971
+ feeds?: {};
972
+ subjects: {};
973
+ };
974
+
975
+ type BaselineAuthApi = {
976
+ rpc: {
977
+ "Auth.Sessions.Me": RPCDesc<
978
+ Schema<Record<string, never>>,
979
+ Schema<AuthSessionsMeResponse>
980
+ >;
981
+ "Auth.Sessions.Logout": RPCDesc<
982
+ Schema<AuthSessionsLogoutInput>,
983
+ Schema<AuthSessionsLogoutResponse>
984
+ >;
985
+ };
986
+ operations: {};
987
+ events: {};
988
+ feeds: {};
989
+ subjects: {};
990
+ };
991
+
992
+ type BaselineStateApi = {
993
+ rpc: {
994
+ "State.Get": RPCDesc<Schema<StateGetInput>, Schema<StateGetResponse>>;
995
+ "State.Put": RPCDesc<Schema<StatePutInput>, Schema<StatePutResponse>>;
996
+ "State.Delete": RPCDesc<
997
+ Schema<StateDeleteInput>,
998
+ Schema<StateDeleteResponse>
999
+ >;
1000
+ "State.List": RPCDesc<Schema<StateListInput>, Schema<StateListResponse>>;
1001
+ };
1002
+ operations: {};
1003
+ events: {};
1004
+ feeds: {};
1005
+ subjects: {};
1006
+ };
1007
+
1008
+ type BaselineHealthApi = {
1009
+ rpc: {};
1010
+ operations: {};
1011
+ events: {
1012
+ "Health.Heartbeat": EventDesc<Schema<Record<string, unknown>>>;
1013
+ };
1014
+ feeds: {};
1015
+ subjects: {};
1016
+ };
1017
+
1018
+ export type ContractApiViews<
1019
+ TOwnedApi extends ApiShape,
1020
+ TUsedApi extends ApiShape,
1021
+ TTrellisApi extends ApiShape,
1022
+ > = {
1023
+ owned: TOwnedApi;
1024
+ used: TUsedApi;
1025
+ trellis: TTrellisApi;
1026
+ };
1027
+
1028
+ export type UseSpec<TApi extends ApiShape> = {
1029
+ rpc?: {
1030
+ call?: readonly StringKeyOf<TApi["rpc"]>[];
1031
+ };
1032
+ operations?: {
1033
+ call?: readonly StringKeyOf<TApi["operations"]>[];
1034
+ };
1035
+ events?: {
1036
+ publish?: readonly StringKeyOf<TApi["events"]>[];
1037
+ subscribe?: readonly StringKeyOf<TApi["events"]>[];
1038
+ };
1039
+ feeds?: {
1040
+ subscribe?: readonly StringKeyOf<NonNullable<TApi["feeds"]>>[];
1041
+ };
1042
+ };
1043
+
1044
+ type UseRpcCall<TSpec> =
1045
+ NonNullable<TSpec extends { rpc?: infer TRpc } ? TRpc : never> extends
1046
+ { call?: infer TCall extends readonly string[] | undefined } ? TCall
1047
+ : never;
1048
+ type UseEventsPublish<TSpec> = NonNullable<
1049
+ TSpec extends { events?: infer TEvents } ? TEvents : never
1050
+ > extends { publish?: infer TPublish extends readonly string[] | undefined }
1051
+ ? TPublish
1052
+ : never;
1053
+ type UseOperationsCall<TSpec> = NonNullable<
1054
+ TSpec extends { operations?: infer TOperations } ? TOperations : never
1055
+ > extends { call?: infer TCall extends readonly string[] | undefined } ? TCall
1056
+ : never;
1057
+ type UseEventsSubscribe<TSpec> = NonNullable<
1058
+ TSpec extends { events?: infer TEvents } ? TEvents : never
1059
+ > extends { subscribe?: infer TSubscribe extends readonly string[] | undefined }
1060
+ ? TSubscribe
1061
+ : never;
1062
+ type UseFeedsSubscribe<TSpec> = NonNullable<
1063
+ TSpec extends { feeds?: infer TFeeds } ? TFeeds : never
1064
+ > extends { subscribe?: infer TSubscribe extends readonly string[] | undefined }
1065
+ ? TSubscribe
1066
+ : never;
1067
+ type ContractModuleMarker<
1068
+ TContractModule = ContractModule<
1069
+ string,
1070
+ TrellisApiLike,
1071
+ TrellisApiLike,
1072
+ TrellisApiLike
1073
+ >,
1074
+ > = {
1075
+ readonly [CONTRACT_MODULE_METADATA]: TContractModule;
1076
+ };
1077
+
1078
+ export type ContractDependencyUse<
1079
+ TContractId extends string,
1080
+ TApi extends ApiShape,
1081
+ TSpec extends UseSpec<TApi> = UseSpec<TApi>,
1082
+ > = {
1083
+ contract: TContractId;
1084
+ readonly [CONTRACT_MODULE_METADATA]?: ContractModule<
1085
+ TContractId,
1086
+ TApi,
1087
+ ApiShape,
1088
+ ApiShape
1089
+ >;
1090
+ rpc?: { call?: UseRpcCall<TSpec> };
1091
+ operations?: { call?: UseOperationsCall<TSpec> };
1092
+ events?: {
1093
+ publish?: UseEventsPublish<TSpec>;
1094
+ subscribe?: UseEventsSubscribe<TSpec>;
1095
+ };
1096
+ feeds?: { subscribe?: UseFeedsSubscribe<TSpec> };
1097
+ };
1098
+
1099
+ type InternalContractDependencyUse<
1100
+ TContractId extends string,
1101
+ TApi extends ApiShape,
1102
+ TSpec extends UseSpec<TApi> = UseSpec<TApi>,
1103
+ > = ContractDependencyUse<TContractId, TApi, TSpec> & ContractModuleMarker;
1104
+
1105
+ type AnyContractDependencyUse = InternalContractDependencyUse<
1106
+ string,
1107
+ TrellisApiLike,
1108
+ UseSpec<TrellisApiLike>
1109
+ >;
1110
+
1111
+ type AuthorContractDependencyUse = ContractDependencyUse<
1112
+ string,
1113
+ ApiShape,
1114
+ UseSpec<ApiShape>
1115
+ >;
1116
+
1117
+ type AuthorContractUsesFlat = Readonly<
1118
+ Record<string, AuthorContractDependencyUse>
1119
+ >;
1120
+
1121
+ type AuthorContractUsesGrouped = {
1122
+ required?: AuthorContractUsesFlat;
1123
+ optional?: AuthorContractUsesFlat;
1124
+ };
1125
+
1126
+ type AuthorContractUses = AuthorContractUsesGrouped;
1127
+
1128
+ export type ContractUseFn<TContractId extends string, TApi extends ApiShape> = <
1129
+ const TSpec extends UseSpec<TApi>,
1130
+ >(spec: TSpec) => ContractDependencyUse<TContractId, TApi, TSpec>;
1131
+
1132
+ type MergeRecordUnion<U> = [U] extends [never] ? {}
1133
+ : Simplify<UnionToIntersection<U>>;
1134
+
1135
+ type SchemaNameOf<TSchemas> = Extract<keyof NonNullable<TSchemas>, string>;
1136
+
1137
+ type ResolveSchemaFromMap<
1138
+ TSchemas,
1139
+ TRef,
1140
+ > = TRef extends { schema: infer TName }
1141
+ ? TName extends SchemaNameOf<TSchemas>
1142
+ ? NonNullable<TSchemas>[TName] extends TSchema ? Schema<
1143
+ import("./runtime.js").InferSchemaType<NonNullable<TSchemas>[TName]>
1144
+ >
1145
+ : Schema<unknown>
1146
+ : Schema<unknown>
1147
+ : Schema<unknown>;
1148
+
1149
+ type ResolveSchemaTypeFromMap<
1150
+ TSchemas,
1151
+ TRef,
1152
+ > = TRef extends { schema: infer TName }
1153
+ ? TName extends SchemaNameOf<TSchemas>
1154
+ ? NonNullable<TSchemas>[TName] extends TSchema
1155
+ ? InferSchemaType<NonNullable<TSchemas>[TName]>
1156
+ : unknown
1157
+ : unknown
1158
+ : unknown;
1159
+
1160
+ export type ContractJobsMetadata = Record<string, {
1161
+ payload: unknown;
1162
+ result: unknown;
1163
+ }>;
1164
+ export type ContractKvMetadata = Record<string, {
1165
+ required: boolean;
1166
+ value: unknown;
1167
+ schema: TSchema;
1168
+ }>;
1169
+ export type ContractStateMetadata = Record<string, {
1170
+ kind: ContractStateKind;
1171
+ value: unknown;
1172
+ schema: unknown;
1173
+ stateVersion: string;
1174
+ acceptedVersions: Record<string, unknown>;
1175
+ }>;
1176
+
1177
+ type ResolveTypeBoxSchemaFromMap<TSchemas, TRef> = TRef extends {
1178
+ schema: infer TName;
1179
+ }
1180
+ ? TName extends SchemaNameOf<TSchemas>
1181
+ ? NonNullable<TSchemas>[TName] extends TSchema
1182
+ ? NonNullable<TSchemas>[TName]
1183
+ : TSchema
1184
+ : TSchema
1185
+ : TSchema;
1186
+
1187
+ type ProjectedJobs<
1188
+ T extends ContractSourceJobs<string> | undefined,
1189
+ TSchemas,
1190
+ > = T extends ContractSourceJobs<string> ? {
1191
+ [K in keyof T]: {
1192
+ payload: ResolveSchemaTypeFromMap<TSchemas, T[K]["payload"]>;
1193
+ result: ResolveSchemaTypeFromMap<TSchemas, T[K]["result"]>;
1194
+ };
1195
+ }
1196
+ : {};
1197
+
1198
+ type ProjectedState<
1199
+ T extends ContractSourceState<string> | undefined,
1200
+ TSchemas,
1201
+ > = T extends ContractSourceState<string> ? {
1202
+ [K in keyof T]: T[K] extends { kind: infer TKind extends ContractStateKind }
1203
+ ? {
1204
+ kind: TKind;
1205
+ value: ResolveSchemaTypeFromMap<TSchemas, T[K]["schema"]>;
1206
+ schema: unknown;
1207
+ stateVersion: T[K] extends
1208
+ { stateVersion: infer TVersion extends string } ? TVersion
1209
+ : "v1";
1210
+ acceptedVersions: T[K] extends { acceptedVersions: infer TVersions }
1211
+ ? TVersions
1212
+ : {};
1213
+ }
1214
+ : never;
1215
+ }
1216
+ : {};
1217
+
1218
+ type ProjectedKvResources<
1219
+ T extends ContractSourceResources<string> | undefined,
1220
+ TSchemas,
1221
+ > = T extends { kv?: infer TKv } ? TKv extends Record<
1222
+ string,
1223
+ { schema: ContractSchemaRef<string>; required?: boolean }
1224
+ > ? {
1225
+ [K in keyof TKv]: {
1226
+ required: TKv[K] extends { required: infer TRequired extends boolean }
1227
+ ? TRequired
1228
+ : true;
1229
+ value: ResolveSchemaTypeFromMap<TSchemas, TKv[K]["schema"]>;
1230
+ schema: ResolveTypeBoxSchemaFromMap<TSchemas, TKv[K]["schema"]>;
1231
+ };
1232
+ }
1233
+ : {}
1234
+ : {};
1235
+
1236
+ type JobsFromSource<T> = T extends { jobs?: infer TJobs }
1237
+ ? Extract<TJobs, ContractSourceJobs<string> | undefined>
1238
+ : undefined;
1239
+ type ResourcesFromSource<T> = T extends { resources?: infer TResources }
1240
+ ? Extract<TResources, ContractSourceResources<string> | undefined>
1241
+ : undefined;
1242
+ type StateFromSource<T> = T extends { state?: infer TState }
1243
+ ? Extract<TState, ContractSourceState<string> | undefined>
1244
+ : undefined;
1245
+
1246
+ type SchemasFromSource<T> = T extends { schemas?: infer TSchemas } ? TSchemas
1247
+ : undefined;
1248
+
1249
+ type RuntimeErrorFromSourceDecl<TDecl, TSchemas> = TDecl extends {
1250
+ type: infer TType extends string;
1251
+ schema?: infer TSchemaRef;
1252
+ }
1253
+ ? TDecl extends ContractErrorRuntimeMarker<infer TClass>
1254
+ ? TClass extends RpcErrorClass<SerializableErrorData, infer TError>
1255
+ ? RuntimeRpcErrorDesc<
1256
+ TType,
1257
+ ResolveSchemaFromMap<TSchemas, TSchemaRef>,
1258
+ TError
1259
+ >
1260
+ : never
1261
+ : never
1262
+ : never;
1263
+
1264
+ type RuntimeErrorsForNames<TNames, TErrors, TSchemas> = TNames extends
1265
+ readonly string[] ? readonly RuntimeErrorFromSourceDecl<
1266
+ NonNullable<TErrors>[Extract<TNames[number], keyof NonNullable<TErrors>>],
1267
+ TSchemas
1268
+ >[]
1269
+ : undefined;
1270
+
1271
+ type ProjectedRpcMethod<
1272
+ TMethod extends ContractSourceRpcMethod,
1273
+ TSchemas,
1274
+ _TErrors,
1275
+ > =
1276
+ & {
1277
+ subject: string;
1278
+ input: ResolveSchemaFromMap<TSchemas, TMethod["input"]>;
1279
+ output: ResolveSchemaFromMap<TSchemas, TMethod["output"]>;
1280
+ callerCapabilities: readonly string[];
1281
+ authRequired?: boolean;
1282
+ errors?: TMethod["errors"];
1283
+ runtimeErrors?: readonly RuntimeRpcErrorDesc[];
1284
+ declaredErrorTypes?: readonly string[];
1285
+ }
1286
+ & (TMethod extends { transfer: infer TTransfer } ? { transfer: TTransfer }
1287
+ : {});
1288
+
1289
+ type BuiltRuntimeErrorDesc = {
1290
+ type: string;
1291
+ schema?: Schema<unknown>;
1292
+ fromSerializable(data: SerializableErrorData): BaseError;
1293
+ };
1294
+
1295
+ type BuiltRpcDesc = {
1296
+ subject: string;
1297
+ input: Schema<unknown>;
1298
+ output: Schema<unknown>;
1299
+ callerCapabilities: readonly string[];
1300
+ transfer?: { direction: "receive" };
1301
+ authRequired?: boolean;
1302
+ errors?: readonly string[];
1303
+ declaredErrorTypes?: readonly string[];
1304
+ runtimeErrors?: readonly BuiltRuntimeErrorDesc[];
1305
+ };
1306
+
1307
+ const TRELLIS_AUTH_CONTRACT_ID = "trellis.auth@v1";
1308
+ const TRELLIS_STATE_CONTRACT_ID = "trellis.state@v1";
1309
+ const TRELLIS_HEALTH_CONTRACT_ID = "trellis.health@v1";
1310
+
1311
+ const BASELINE_AUTH_RPC_CALL = [
1312
+ "Auth.Sessions.Me",
1313
+ "Auth.Sessions.Logout",
1314
+ ] as const;
1315
+ const BASELINE_STATE_RPC_CALL = [
1316
+ "State.Get",
1317
+ "State.Put",
1318
+ "State.Delete",
1319
+ "State.List",
1320
+ ] as const;
1321
+ const BASELINE_HEALTH_EVENTS_PUBLISH = ["Health.Heartbeat"] as const;
1322
+
1323
+ const UnknownRuntimeSchema = schema(Type.Unknown());
1324
+
1325
+ function typedUnknownRuntimeSchema<T>(): Schema<T> {
1326
+ return UnknownRuntimeSchema as Schema<T>;
1327
+ }
1328
+
1329
+ function trellisRpcDesc<TInput, TOutput>(
1330
+ name: string,
1331
+ ): RPCDesc<Schema<TInput>, Schema<TOutput>> {
1332
+ return {
1333
+ subject: rpcSubject(name, "v1"),
1334
+ input: typedUnknownRuntimeSchema<TInput>(),
1335
+ output: typedUnknownRuntimeSchema<TOutput>(),
1336
+ callerCapabilities: [],
1337
+ };
1338
+ }
1339
+
1340
+ function trellisEventDesc<TEvent>(
1341
+ name: string,
1342
+ ): EventDesc<Schema<TEvent>> {
1343
+ return {
1344
+ subject: eventSubject(name, "v1", undefined),
1345
+ event: typedUnknownRuntimeSchema<TEvent>(),
1346
+ publishCapabilities: [],
1347
+ subscribeCapabilities: [],
1348
+ };
1349
+ }
1350
+
1351
+ const BASELINE_AUTH_API: BaselineAuthApi = {
1352
+ rpc: {
1353
+ "Auth.Sessions.Me": trellisRpcDesc<
1354
+ Record<string, never>,
1355
+ AuthSessionsMeResponse
1356
+ >(
1357
+ "Auth.Sessions.Me",
1358
+ ),
1359
+ "Auth.Sessions.Logout": trellisRpcDesc<
1360
+ AuthSessionsLogoutInput,
1361
+ AuthSessionsLogoutResponse
1362
+ >(
1363
+ "Auth.Sessions.Logout",
1364
+ ),
1365
+ },
1366
+ operations: {},
1367
+ events: {},
1368
+ feeds: {},
1369
+ subjects: {},
1370
+ };
1371
+
1372
+ const BASELINE_STATE_API: BaselineStateApi = {
1373
+ rpc: {
1374
+ "State.Get": trellisRpcDesc<StateGetInput, StateGetResponse>("State.Get"),
1375
+ "State.Put": trellisRpcDesc<StatePutInput, StatePutResponse>("State.Put"),
1376
+ "State.Delete": trellisRpcDesc<StateDeleteInput, StateDeleteResponse>(
1377
+ "State.Delete",
1378
+ ),
1379
+ "State.List": trellisRpcDesc<StateListInput, StateListResponse>(
1380
+ "State.List",
1381
+ ),
1382
+ },
1383
+ operations: {},
1384
+ events: {},
1385
+ feeds: {},
1386
+ subjects: {},
1387
+ };
1388
+
1389
+ const BASELINE_HEALTH_API: BaselineHealthApi = {
1390
+ rpc: {},
1391
+ operations: {},
1392
+ events: {
1393
+ "Health.Heartbeat": trellisEventDesc<Record<string, unknown>>(
1394
+ "Health.Heartbeat",
1395
+ ),
1396
+ },
1397
+ feeds: {},
1398
+ subjects: {},
1399
+ };
1400
+
1401
+ type ProjectedRpc<
1402
+ T,
1403
+ TSchemas,
1404
+ TErrors,
1405
+ > = T extends Readonly<Record<string, ContractSourceRpcMethod>> ? {
1406
+ [K in keyof T]: ProjectedRpcMethod<T[K], TSchemas, TErrors>;
1407
+ }
1408
+ : {};
1409
+
1410
+ type ProjectedOperations<
1411
+ T,
1412
+ TSchemas,
1413
+ > = T extends Readonly<Record<string, ContractSourceOperation>> ? {
1414
+ [K in keyof T]:
1415
+ & OperationDesc<
1416
+ ResolveSchemaFromMap<TSchemas, T[K]["input"]>,
1417
+ ResolveSchemaFromMap<TSchemas, T[K]["progress"]>,
1418
+ ResolveSchemaFromMap<TSchemas, T[K]["output"]>
1419
+ >
1420
+ & (T[K]["transfer"] extends undefined ? {}
1421
+ : { transfer: T[K]["transfer"] });
1422
+ }
1423
+ : {};
1424
+
1425
+ type ProjectedEvents<
1426
+ T,
1427
+ TSchemas,
1428
+ > = T extends Readonly<Record<string, ContractSourceEvent>> ? {
1429
+ [K in keyof T]: EventDesc<
1430
+ ResolveSchemaFromMap<TSchemas, T[K]["event"]>
1431
+ >;
1432
+ }
1433
+ : {};
1434
+
1435
+ type ProjectedFeeds<
1436
+ T,
1437
+ TSchemas,
1438
+ > = T extends Readonly<Record<string, ContractSourceFeed>> ? {
1439
+ [K in keyof T]: FeedDesc<
1440
+ ResolveSchemaFromMap<TSchemas, T[K]["input"]>,
1441
+ ResolveSchemaFromMap<TSchemas, T[K]["event"]>
1442
+ >;
1443
+ }
1444
+ : {};
1445
+
1446
+ export type OwnedApiFromSource<
1447
+ T extends {
1448
+ schemas?: Readonly<Record<string, TSchema>>;
1449
+ errors?: unknown;
1450
+ rpc?: unknown;
1451
+ operations?: unknown;
1452
+ events?: unknown;
1453
+ feeds?: unknown;
1454
+ },
1455
+ > = {
1456
+ rpc: ProjectedRpc<T["rpc"], T["schemas"], T["errors"]>;
1457
+ operations: ProjectedOperations<T["operations"], T["schemas"]>;
1458
+ events: ProjectedEvents<T["events"], T["schemas"]>;
1459
+ feeds: ProjectedFeeds<T["feeds"], T["schemas"]>;
1460
+ subjects: {};
1461
+ };
1462
+
1463
+ type RpcKeysFromSpec<TSpec> = TSpec extends { rpc?: { call?: infer TCall } }
1464
+ ? KeysFromList<TCall>
1465
+ : never;
1466
+ type EventKeysFromSpec<TSpec> =
1467
+ | (TSpec extends { events?: { publish?: infer TPublish } }
1468
+ ? KeysFromList<TPublish>
1469
+ : never)
1470
+ | (TSpec extends { events?: { subscribe?: infer TSubscribe } }
1471
+ ? KeysFromList<TSubscribe>
1472
+ : never);
1473
+ type OperationKeysFromSpec<TSpec> = TSpec extends
1474
+ { operations?: { call?: infer TCall } } ? KeysFromList<TCall>
1475
+ : never;
1476
+ type FeedKeysFromSpec<TSpec> = TSpec extends
1477
+ { feeds?: { subscribe?: infer TSubscribe } } ? KeysFromList<TSubscribe>
1478
+ : never;
1479
+ type ApiFromDependencyUse<TUse> = TUse extends
1480
+ ContractDependencyUse<string, infer TApi, infer TSpec> ? {
1481
+ rpc: Pick<TApi["rpc"], RpcKeysFromSpec<TSpec>>;
1482
+ operations: Pick<TApi["operations"], OperationKeysFromSpec<TSpec>>;
1483
+ events: Pick<TApi["events"], EventKeysFromSpec<TSpec>>;
1484
+ feeds: Pick<NonNullable<TApi["feeds"]>, FeedKeysFromSpec<TSpec>>;
1485
+ subjects: {};
1486
+ }
1487
+ : EmptyApi;
1488
+ type DependencyUsesFromUses<TUses> = TUses extends {
1489
+ required?: AuthorContractUsesFlat;
1490
+ optional?: AuthorContractUsesFlat;
1491
+ } ?
1492
+ | NonNullable<TUses["required"]>[keyof NonNullable<TUses["required"]>]
1493
+ | NonNullable<TUses["optional"]>[keyof NonNullable<TUses["optional"]>]
1494
+ : never;
1495
+
1496
+ export type UsedApiFromUses<TUses> = [TUses] extends [undefined] ? EmptyApi
1497
+ : TUses extends Record<string, unknown> ? {
1498
+ rpc: MergeRecordUnion<
1499
+ ApiFromDependencyUse<DependencyUsesFromUses<TUses>>["rpc"]
1500
+ >;
1501
+ operations: MergeRecordUnion<
1502
+ ApiFromDependencyUse<DependencyUsesFromUses<TUses>>["operations"]
1503
+ >;
1504
+ events: MergeRecordUnion<
1505
+ ApiFromDependencyUse<DependencyUsesFromUses<TUses>>["events"]
1506
+ >;
1507
+ feeds: MergeRecordUnion<
1508
+ ApiFromDependencyUse<DependencyUsesFromUses<TUses>>["feeds"]
1509
+ >;
1510
+ subjects: MergeRecordUnion<
1511
+ ApiFromDependencyUse<DependencyUsesFromUses<TUses>>["subjects"]
1512
+ >;
1513
+ }
1514
+ : EmptyApi;
1515
+
1516
+ type ImplicitAuthApiForKind<TKind> = TKind extends "app" | "agent" | "device"
1517
+ ? BaselineAuthApi
1518
+ : EmptyApi;
1519
+
1520
+ type ImplicitStateApiForSource<T> = [StateFromSource<T>] extends [undefined]
1521
+ ? EmptyApi
1522
+ : BaselineStateApi;
1523
+
1524
+ type ImplicitHealthApiForSource<T> = T extends {
1525
+ kind: infer TKind;
1526
+ id: infer TId;
1527
+ } ? TId extends "trellis.health@v1" ? EmptyApi
1528
+ : TKind extends "service" | "device" ? BaselineHealthApi
1529
+ : EmptyApi
1530
+ : EmptyApi;
1531
+
1532
+ type ImplicitTrellisApiFromSource<T> = T extends { kind: infer TKind }
1533
+ ? MergeApis<
1534
+ MergeApis<ImplicitAuthApiForKind<TKind>, ImplicitStateApiForSource<T>>,
1535
+ ImplicitHealthApiForSource<T>
1536
+ >
1537
+ : EmptyApi;
1538
+
1539
+ export type UsedApiFromSource<T extends { uses?: unknown }> = MergeApis<
1540
+ UsedApiFromUses<T["uses"]>,
1541
+ ImplicitTrellisApiFromSource<T>
1542
+ >;
1543
+
1544
+ export type MergeApis<TOwnedApi extends ApiShape, TUsedApi extends ApiShape> = {
1545
+ rpc: Simplify<TUsedApi["rpc"] & TOwnedApi["rpc"]>;
1546
+ operations: Simplify<TUsedApi["operations"] & TOwnedApi["operations"]>;
1547
+ events: Simplify<TUsedApi["events"] & TOwnedApi["events"]>;
1548
+ feeds: Simplify<TUsedApi["feeds"] & TOwnedApi["feeds"]>;
1549
+ subjects: Simplify<TUsedApi["subjects"] & TOwnedApi["subjects"]>;
1550
+ };
1551
+
1552
+ export type ContractModule<
1553
+ TContractId extends string,
1554
+ TOwnedApi extends ApiShape,
1555
+ TUsedApi extends ApiShape,
1556
+ TTrellisApi extends ApiShape,
1557
+ TJobs extends ContractJobsMetadata = {},
1558
+ TState extends ContractStateMetadata = {},
1559
+ TKv extends ContractKvMetadata = ContractKvMetadata,
1560
+ > = {
1561
+ CONTRACT_ID: TContractId;
1562
+ CONTRACT: TrellisContractV1;
1563
+ CONTRACT_DIGEST: string;
1564
+ API: ContractApiViews<TOwnedApi, TUsedApi, TTrellisApi>;
1565
+ use: ContractUseFn<TContractId, TOwnedApi>;
1566
+ readonly [CONTRACT_JOBS_METADATA]?: TJobs;
1567
+ readonly [CONTRACT_STATE_METADATA]?: TState;
1568
+ readonly [CONTRACT_KV_METADATA]?: TKv;
1569
+ };
1570
+
1571
+ export type SdkContractModule<
1572
+ TContractId extends string,
1573
+ TOwnedApi extends ApiShape,
1574
+ TJobs extends ContractJobsMetadata = {},
1575
+ TState extends ContractStateMetadata = {},
1576
+ TKv extends ContractKvMetadata = ContractKvMetadata,
1577
+ > =
1578
+ & Omit<
1579
+ ContractModule<
1580
+ TContractId,
1581
+ TOwnedApi,
1582
+ EmptyApi,
1583
+ TOwnedApi,
1584
+ TJobs,
1585
+ TState,
1586
+ TKv
1587
+ >,
1588
+ "use"
1589
+ >
1590
+ & {
1591
+ use: ContractUseFn<TContractId, TOwnedApi>;
1592
+ };
1593
+
1594
+ export type DefinedContract<
1595
+ TOwnedApi extends ApiShape,
1596
+ TUsedApi extends ApiShape,
1597
+ TTrellisApi extends ApiShape,
1598
+ TContractId extends string = string,
1599
+ TJobs extends ContractJobsMetadata = {},
1600
+ TState extends ContractStateMetadata = {},
1601
+ TKv extends ContractKvMetadata = ContractKvMetadata,
1602
+ > = ContractModule<
1603
+ TContractId,
1604
+ TOwnedApi,
1605
+ TUsedApi,
1606
+ TTrellisApi,
1607
+ TJobs,
1608
+ TState,
1609
+ TKv
1610
+ >;
1611
+
1612
+ export type DefineContractInput<
1613
+ TCapabilities extends ContractCapabilities | undefined =
1614
+ | ContractCapabilities
1615
+ | undefined,
1616
+ TSchemas extends Readonly<Record<string, TSchema>> | undefined = undefined,
1617
+ TUses extends
1618
+ | AuthorContractUses
1619
+ | undefined = undefined,
1620
+ TErrors extends
1621
+ | Readonly<Record<string, ErrorClass>>
1622
+ | undefined = undefined,
1623
+ TRpc extends
1624
+ | Readonly<
1625
+ Record<
1626
+ string,
1627
+ ContractSourceRpcMethod<
1628
+ SchemaNameOf<TSchemas>,
1629
+ ErrorNameOf<TErrors>,
1630
+ CapabilityRef<TCapabilities>
1631
+ >
1632
+ >
1633
+ >
1634
+ | undefined = undefined,
1635
+ TOperations extends
1636
+ | Readonly<
1637
+ Record<
1638
+ string,
1639
+ ContractSourceOperation<
1640
+ SchemaNameOf<TSchemas>,
1641
+ CapabilityRef<TCapabilities>
1642
+ >
1643
+ >
1644
+ >
1645
+ | undefined = undefined,
1646
+ TEvents extends
1647
+ | Readonly<
1648
+ Record<
1649
+ string,
1650
+ ContractSourceEvent<
1651
+ SchemaNameOf<TSchemas>,
1652
+ CapabilityRef<TCapabilities>
1653
+ >
1654
+ >
1655
+ >
1656
+ | undefined = undefined,
1657
+ > = {
1658
+ id: string;
1659
+ displayName: string;
1660
+ description: string;
1661
+ kind: ContractKind;
1662
+ capabilities?: ContractCapabilities;
1663
+ schemas?: TSchemas;
1664
+ exports?: ContractSourceExports<SchemaNameOf<TSchemas>>;
1665
+ state?: ContractSourceState<SchemaNameOf<TSchemas>>;
1666
+ uses?: TUses;
1667
+ errors?: TErrors;
1668
+ rpc?: TRpc;
1669
+ operations?: TOperations;
1670
+ events?: TEvents;
1671
+ feeds?: Readonly<
1672
+ Record<
1673
+ string,
1674
+ ContractSourceFeed<
1675
+ SchemaNameOf<TSchemas>,
1676
+ CapabilityRef<TCapabilities>
1677
+ >
1678
+ >
1679
+ >;
1680
+ jobs?: ContractSourceJobs<SchemaNameOf<TSchemas>>;
1681
+ resources?: ContractSourceResources<SchemaNameOf<TSchemas>>;
1682
+ };
1683
+
1684
+ type DefineContractSource = {
1685
+ id: string;
1686
+ displayName: string;
1687
+ description: string;
1688
+ kind: ContractKind;
1689
+ capabilities?: ContractCapabilities;
1690
+ schemas?: Readonly<Record<string, TSchema>>;
1691
+ exports?: ContractSourceExports;
1692
+ state?: ContractSourceState;
1693
+ uses?: AuthorContractUses;
1694
+ errors?: Readonly<Record<string, ContractSourceErrorDecl>>;
1695
+ rpc?: Readonly<Record<string, ContractSourceRpcMethod>>;
1696
+ operations?: Readonly<Record<string, ContractSourceOperation>>;
1697
+ events?: Readonly<Record<string, ContractSourceEvent>>;
1698
+ feeds?: Readonly<Record<string, ContractSourceFeed>>;
1699
+ jobs?: ContractSourceJobs;
1700
+ resources?: ContractSourceResources;
1701
+ };
1702
+
1703
+ type ConstrainSection<TSection, TExpected> = [TSection] extends [undefined]
1704
+ ? undefined
1705
+ : TSection & TExpected;
1706
+
1707
+ type ValidateDefineContractInput<T extends DefineContractSource> =
1708
+ & T
1709
+ & DefineContractInput<
1710
+ T["capabilities"],
1711
+ T["schemas"],
1712
+ ConstrainSection<
1713
+ T["uses"],
1714
+ AuthorContractUses
1715
+ >,
1716
+ ConstrainSection<
1717
+ T["errors"],
1718
+ Readonly<Record<string, ErrorClass>>
1719
+ >,
1720
+ ConstrainSection<
1721
+ T["rpc"],
1722
+ Readonly<
1723
+ Record<
1724
+ string,
1725
+ ContractSourceRpcMethod<
1726
+ SchemaNameOf<T["schemas"]>,
1727
+ ErrorNameOf<T["errors"]>,
1728
+ CapabilityRef<T["capabilities"]>
1729
+ >
1730
+ >
1731
+ >
1732
+ >,
1733
+ ConstrainSection<
1734
+ T["operations"],
1735
+ Readonly<
1736
+ Record<
1737
+ string,
1738
+ ContractSourceOperation<
1739
+ SchemaNameOf<T["schemas"]>,
1740
+ CapabilityRef<T["capabilities"]>
1741
+ >
1742
+ >
1743
+ >
1744
+ >,
1745
+ ConstrainSection<
1746
+ T["events"],
1747
+ Readonly<
1748
+ Record<
1749
+ string,
1750
+ ContractSourceEvent<
1751
+ SchemaNameOf<T["schemas"]>,
1752
+ CapabilityRef<T["capabilities"]>
1753
+ >
1754
+ >
1755
+ >
1756
+ >
1757
+ >;
1758
+
1759
+ type DefineContractRegistry<
1760
+ TSchemas extends Readonly<Record<string, TSchema>> | undefined = undefined,
1761
+ TErrors extends
1762
+ | Readonly<Record<string, unknown>>
1763
+ | undefined = undefined,
1764
+ > = {
1765
+ schemas?: TSchemas;
1766
+ errors?: TErrors;
1767
+ };
1768
+
1769
+ type AnyDefineContractRegistry = DefineContractRegistry<
1770
+ Readonly<Record<string, TSchema>> | undefined,
1771
+ Readonly<Record<string, unknown>> | undefined
1772
+ >;
1773
+
1774
+ type ClientContractRegistry<
1775
+ TSchemas extends Readonly<Record<string, TSchema>> | undefined = undefined,
1776
+ > = {
1777
+ schemas?: TSchemas;
1778
+ };
1779
+
1780
+ type RegistrySchemas<TRegistry extends AnyDefineContractRegistry> =
1781
+ TRegistry extends { schemas?: infer TSchemas }
1782
+ ? TSchemas extends Readonly<Record<string, TSchema>> | undefined ? TSchemas
1783
+ : undefined
1784
+ : undefined;
1785
+
1786
+ type RegistryErrors<TRegistry extends AnyDefineContractRegistry> =
1787
+ TRegistry extends { errors?: infer TErrors }
1788
+ ? TErrors extends Readonly<Record<string, unknown>> | undefined
1789
+ ? ExtractErrorClasses<
1790
+ TErrors
1791
+ >
1792
+ : undefined
1793
+ : undefined;
1794
+
1795
+ type RegistryUses = AuthorContractUses | undefined;
1796
+
1797
+ type RegistryRpcMethods<TRegistry extends AnyDefineContractRegistry> =
1798
+ | Readonly<
1799
+ Record<
1800
+ string,
1801
+ ContractSourceRpcMethod<
1802
+ SchemaNameOf<RegistrySchemas<TRegistry>>,
1803
+ ErrorNameOf<RegistryErrors<TRegistry>>
1804
+ >
1805
+ >
1806
+ >
1807
+ | undefined;
1808
+
1809
+ type RegistryOperations<TRegistry extends AnyDefineContractRegistry> =
1810
+ | Readonly<
1811
+ Record<
1812
+ string,
1813
+ ContractSourceOperation<SchemaNameOf<RegistrySchemas<TRegistry>>>
1814
+ >
1815
+ >
1816
+ | undefined;
1817
+
1818
+ type RegistryEvents<TRegistry extends AnyDefineContractRegistry> =
1819
+ | Readonly<
1820
+ Record<
1821
+ string,
1822
+ ContractSourceEvent<SchemaNameOf<RegistrySchemas<TRegistry>>>
1823
+ >
1824
+ >
1825
+ | undefined;
1826
+
1827
+ type BodyCapabilities<TBody> = Extract<
1828
+ TBody extends { capabilities: infer TCapabilities } ? TCapabilities
1829
+ : undefined,
1830
+ ContractCapabilities | undefined
1831
+ >;
1832
+
1833
+ type BodyRpcMethods<TBody, TRegistry extends AnyDefineContractRegistry> =
1834
+ TBody extends { rpc?: infer TRpc } ? ConstrainSection<
1835
+ TRpc,
1836
+ Readonly<
1837
+ Record<
1838
+ string,
1839
+ ContractSourceRpcMethod<
1840
+ SchemaNameOf<RegistrySchemas<TRegistry>>,
1841
+ ErrorNameOf<RegistryErrors<TRegistry>>,
1842
+ CapabilityRef<BodyCapabilities<TBody>>
1843
+ >
1844
+ >
1845
+ >
1846
+ >
1847
+ : undefined;
1848
+
1849
+ type BodyOperations<TBody, TRegistry extends AnyDefineContractRegistry> =
1850
+ TBody extends { operations?: infer TOperations } ? ConstrainSection<
1851
+ TOperations,
1852
+ Readonly<
1853
+ Record<
1854
+ string,
1855
+ ContractSourceOperation<
1856
+ SchemaNameOf<RegistrySchemas<TRegistry>>,
1857
+ CapabilityRef<BodyCapabilities<TBody>>
1858
+ >
1859
+ >
1860
+ >
1861
+ >
1862
+ : undefined;
1863
+
1864
+ type BodyEvents<TBody, TRegistry extends AnyDefineContractRegistry> =
1865
+ TBody extends { events?: infer TEvents } ? ConstrainSection<
1866
+ TEvents,
1867
+ Readonly<
1868
+ Record<
1869
+ string,
1870
+ ContractSourceEvent<
1871
+ SchemaNameOf<RegistrySchemas<TRegistry>>,
1872
+ CapabilityRef<BodyCapabilities<TBody>>
1873
+ >
1874
+ >
1875
+ >
1876
+ >
1877
+ : undefined;
1878
+
1879
+ type ValidateCapabilitySections<
1880
+ TBody,
1881
+ TRegistry extends AnyDefineContractRegistry,
1882
+ > = {
1883
+ rpc?: BodyRpcMethods<TBody, TRegistry>;
1884
+ operations?: BodyOperations<TBody, TRegistry>;
1885
+ events?: BodyEvents<TBody, TRegistry>;
1886
+ };
1887
+
1888
+ type UsedApiOf<TBody extends { uses?: unknown }> = UsedApiFromUses<
1889
+ TBody["uses"]
1890
+ >;
1891
+
1892
+ type DefineContractBodyInput<
1893
+ TCapabilities extends ContractCapabilities | undefined =
1894
+ | ContractCapabilities
1895
+ | undefined,
1896
+ TSchemas extends Readonly<Record<string, TSchema>> | undefined = undefined,
1897
+ TUses extends AuthorContractUses | undefined = undefined,
1898
+ TErrors extends
1899
+ | Readonly<Record<string, ErrorClass>>
1900
+ | undefined = undefined,
1901
+ TRpc extends
1902
+ | Readonly<
1903
+ Record<
1904
+ string,
1905
+ ContractSourceRpcMethod<
1906
+ SchemaNameOf<TSchemas>,
1907
+ ErrorNameOf<TErrors>,
1908
+ CapabilityRef<TCapabilities>
1909
+ >
1910
+ >
1911
+ >
1912
+ | undefined = undefined,
1913
+ TOperations extends
1914
+ | Readonly<
1915
+ Record<
1916
+ string,
1917
+ ContractSourceOperation<
1918
+ SchemaNameOf<TSchemas>,
1919
+ CapabilityRef<TCapabilities>
1920
+ >
1921
+ >
1922
+ >
1923
+ | undefined = undefined,
1924
+ TEvents extends
1925
+ | Readonly<
1926
+ Record<
1927
+ string,
1928
+ ContractSourceEvent<
1929
+ SchemaNameOf<TSchemas>,
1930
+ CapabilityRef<TCapabilities>
1931
+ >
1932
+ >
1933
+ >
1934
+ | undefined = undefined,
1935
+ > =
1936
+ & Omit<
1937
+ DefineContractInput<
1938
+ TCapabilities,
1939
+ TSchemas,
1940
+ TUses,
1941
+ TErrors,
1942
+ TRpc,
1943
+ TOperations,
1944
+ TEvents
1945
+ >,
1946
+ "schemas" | "errors"
1947
+ >
1948
+ & {
1949
+ schemas?: never;
1950
+ errors?: never;
1951
+ };
1952
+
1953
+ type ServiceContractBodyInput<
1954
+ TCapabilities extends ContractCapabilities | undefined =
1955
+ | ContractCapabilities
1956
+ | undefined,
1957
+ TSchemas extends Readonly<Record<string, TSchema>> | undefined = undefined,
1958
+ TUses extends AuthorContractUses | undefined = undefined,
1959
+ TErrors extends
1960
+ | Readonly<Record<string, ErrorClass>>
1961
+ | undefined = undefined,
1962
+ TRpc extends
1963
+ | Readonly<
1964
+ Record<
1965
+ string,
1966
+ ContractSourceRpcMethod<
1967
+ SchemaNameOf<TSchemas>,
1968
+ ErrorNameOf<TErrors>,
1969
+ CapabilityRef<TCapabilities>
1970
+ >
1971
+ >
1972
+ >
1973
+ | undefined = undefined,
1974
+ TOperations extends
1975
+ | Readonly<
1976
+ Record<
1977
+ string,
1978
+ ContractSourceOperation<
1979
+ SchemaNameOf<TSchemas>,
1980
+ CapabilityRef<TCapabilities>
1981
+ >
1982
+ >
1983
+ >
1984
+ | undefined = undefined,
1985
+ TEvents extends
1986
+ | Readonly<
1987
+ Record<
1988
+ string,
1989
+ ContractSourceEvent<
1990
+ SchemaNameOf<TSchemas>,
1991
+ CapabilityRef<TCapabilities>
1992
+ >
1993
+ >
1994
+ >
1995
+ | undefined = undefined,
1996
+ > =
1997
+ & Omit<
1998
+ DefineContractBodyInput<
1999
+ TCapabilities,
2000
+ TSchemas,
2001
+ TUses,
2002
+ TErrors,
2003
+ TRpc,
2004
+ TOperations,
2005
+ TEvents
2006
+ >,
2007
+ "kind"
2008
+ >
2009
+ & { kind?: never; subjects?: never };
2010
+
2011
+ type ClientContractBodyInput<
2012
+ TSchemas extends Readonly<Record<string, TSchema>> | undefined = undefined,
2013
+ TUses extends AuthorContractUses | undefined = undefined,
2014
+ > = ContractIdentityFields & {
2015
+ capabilities?: ContractCapabilities;
2016
+ exports?: ContractSourceExports<SchemaNameOf<TSchemas>>;
2017
+ state?: ContractSourceState<SchemaNameOf<TSchemas>>;
2018
+ uses?: TUses;
2019
+ kind?: never;
2020
+ schemas?: never;
2021
+ errors?: never;
2022
+ rpc?: never;
2023
+ operations?: never;
2024
+ events?: never;
2025
+ subjects?: never;
2026
+ resources?: never;
2027
+ };
2028
+
2029
+ type BuiltContractSource<
2030
+ TRegistry extends AnyDefineContractRegistry,
2031
+ TBody extends { id: string },
2032
+ > = Simplify<
2033
+ & Omit<TBody, "schemas" | "errors">
2034
+ & (TRegistry extends { schemas?: infer TSchemas } ? { schemas?: TSchemas }
2035
+ : {})
2036
+ & (TRegistry extends { errors?: infer TErrors } ? { errors?: TErrors } : {})
2037
+ >;
2038
+
2039
+ type WithKind<TBody extends { id: string }, TKind extends ContractKind> =
2040
+ Simplify<
2041
+ Omit<TBody, "kind"> & { kind: TKind }
2042
+ >;
2043
+
2044
+ function createContractRefBuilder<
2045
+ TSchemas extends Readonly<Record<string, TSchema>> | undefined,
2046
+ TErrors extends Readonly<Record<string, ErrorClass>> | undefined,
2047
+ >(
2048
+ registry: DefineContractRegistry<TSchemas, TErrors>,
2049
+ ): ContractRefBuilder<TSchemas, TErrors> {
2050
+ const schemaRef = registry.schemas
2051
+ ? createSchemaRef(registry.schemas)
2052
+ : undefined;
2053
+ return {
2054
+ schema<const TName extends SchemaNameOf<TSchemas>>(
2055
+ schemaName: TName,
2056
+ ): ContractSchemaRef<TName> {
2057
+ if (!schemaRef) {
2058
+ throw new Error(
2059
+ `Contract builder ref.schema('${schemaName}') requires a schemas registry`,
2060
+ );
2061
+ }
2062
+ return schemaRef(schemaName);
2063
+ },
2064
+ error<const TName extends ErrorNameOf<TErrors>>(errorName: TName): TName {
2065
+ return errorName;
2066
+ },
2067
+ capability<const TName extends GlobalCapability | PlatformCapability>(
2068
+ capabilityName: TName,
2069
+ ): TName {
2070
+ return capabilityName;
2071
+ },
2072
+ };
2073
+ }
2074
+
2075
+ function cloneSchema(schemaValue: TSchema): JsonSchema {
2076
+ const cloned = JSON.parse(JSON.stringify(schemaValue));
2077
+ if (!isJsonValue(cloned)) {
2078
+ throw new Error("Contract schema is not JSON-serializable");
2079
+ }
2080
+ return cloned;
2081
+ }
2082
+
2083
+ function cloneSchemas(
2084
+ schemas: ContractSourceSchemas | undefined,
2085
+ ): ContractSchemas | undefined {
2086
+ if (!schemas) {
2087
+ return undefined;
2088
+ }
2089
+
2090
+ return Object.fromEntries(
2091
+ Object.entries(schemas).map((
2092
+ [name, schemaValue],
2093
+ ) => [name, cloneSchema(schemaValue)]),
2094
+ );
2095
+ }
2096
+
2097
+ function cloneContractExports(
2098
+ contractExports: ContractSourceExports | undefined,
2099
+ ): ContractExports | undefined {
2100
+ if (!contractExports) {
2101
+ return undefined;
2102
+ }
2103
+
2104
+ return {
2105
+ ...(contractExports.schemas
2106
+ ? { schemas: [...contractExports.schemas] }
2107
+ : {}),
2108
+ };
2109
+ }
2110
+
2111
+ function getErrorRuntimeSchema(
2112
+ errorDecl: ContractSourceErrorDecl,
2113
+ ): TSchema | undefined {
2114
+ const errorClass = getContractErrorRuntimeClass(errorDecl);
2115
+ const runtimeSchema = errorClass
2116
+ ? Reflect.get(errorClass, "schema")
2117
+ : undefined;
2118
+ if (!runtimeSchema || typeof runtimeSchema !== "object") {
2119
+ return undefined;
2120
+ }
2121
+
2122
+ return runtimeSchema as TSchema;
2123
+ }
2124
+
2125
+ function createContractErrorDecl<TClass extends ErrorClass>(
2126
+ errorClass: TClass,
2127
+ ): ContractSourceErrorDecl<string> & ContractErrorRuntimeMarker<TClass> {
2128
+ const errorDecl: ContractSourceErrorDecl<string> = {
2129
+ type: getContractErrorType(errorClass),
2130
+ };
2131
+ return attachContractErrorRuntimeMetadata(errorDecl, errorClass);
2132
+ }
2133
+
2134
+ function normalizeErrorRegistry(
2135
+ errors: Readonly<Record<string, unknown>> | undefined,
2136
+ ): Readonly<Record<string, ContractSourceErrorDecl>> | undefined {
2137
+ if (!errors) {
2138
+ return undefined;
2139
+ }
2140
+
2141
+ const normalizedEntries = Object.entries(errors).flatMap(([key, value]) =>
2142
+ isErrorClass(value) ? [[key, createContractErrorDecl(value)]] : []
2143
+ );
2144
+ if (normalizedEntries.length === 0) {
2145
+ return undefined;
2146
+ }
2147
+
2148
+ return Object.fromEntries(normalizedEntries);
2149
+ }
2150
+
2151
+ function getErrorClassRegistry(
2152
+ errors: Readonly<Record<string, unknown>> | undefined,
2153
+ ): Readonly<Record<string, ErrorClass>> | undefined {
2154
+ if (!errors) {
2155
+ return undefined;
2156
+ }
2157
+
2158
+ const classEntries = Object.entries(errors).flatMap(([key, value]) =>
2159
+ isErrorClass(value) ? [[key, value]] : []
2160
+ );
2161
+ if (classEntries.length === 0) {
2162
+ return undefined;
2163
+ }
2164
+
2165
+ return Object.fromEntries(classEntries);
2166
+ }
2167
+
2168
+ function findMatchingSchemaName(
2169
+ schemas: ContractSourceSchemas | undefined,
2170
+ targetSchema: TSchema,
2171
+ ): string | undefined {
2172
+ if (!schemas) {
2173
+ return undefined;
2174
+ }
2175
+
2176
+ const targetDigest = digestCanonicalJson(cloneSchema(targetSchema));
2177
+ for (const [schemaName, schemaValue] of Object.entries(schemas)) {
2178
+ if (schemaValue === targetSchema) {
2179
+ return schemaName;
2180
+ }
2181
+
2182
+ if (digestCanonicalJson(cloneSchema(schemaValue)) === targetDigest) {
2183
+ return schemaName;
2184
+ }
2185
+ }
2186
+
2187
+ return undefined;
2188
+ }
2189
+
2190
+ function chooseDerivedErrorSchemaName(
2191
+ schemas: ContractSourceSchemas,
2192
+ errorName: string,
2193
+ errorType: string,
2194
+ ): string {
2195
+ const baseNames = [`${errorType}Data`, `${errorName}Data`];
2196
+
2197
+ for (const baseName of baseNames) {
2198
+ if (!Object.hasOwn(schemas, baseName)) {
2199
+ return baseName;
2200
+ }
2201
+ }
2202
+
2203
+ let suffix = 2;
2204
+ while (true) {
2205
+ const candidate = `${errorType}Data${suffix}`;
2206
+ if (!Object.hasOwn(schemas, candidate)) {
2207
+ return candidate;
2208
+ }
2209
+ suffix += 1;
2210
+ }
2211
+ }
2212
+
2213
+ function materializeErrorSchemas(
2214
+ schemas: ContractSourceSchemas | undefined,
2215
+ errors: Record<string, ContractSourceErrorDecl> | undefined,
2216
+ ): ContractSourceSchemas | undefined {
2217
+ if (!errors) {
2218
+ return schemas;
2219
+ }
2220
+
2221
+ let mergedSchemas = schemas;
2222
+ for (const [errorName, errorDecl] of Object.entries(errors)) {
2223
+ if (errorDecl.schema) {
2224
+ continue;
2225
+ }
2226
+
2227
+ const runtimeSchema = getErrorRuntimeSchema(errorDecl);
2228
+ if (!runtimeSchema) {
2229
+ continue;
2230
+ }
2231
+
2232
+ if (findMatchingSchemaName(mergedSchemas, runtimeSchema)) {
2233
+ continue;
2234
+ }
2235
+
2236
+ mergedSchemas = { ...(mergedSchemas ?? {}) };
2237
+ const derivedSchemaName = chooseDerivedErrorSchemaName(
2238
+ mergedSchemas,
2239
+ errorName,
2240
+ errorDecl.type,
2241
+ );
2242
+ mergedSchemas[derivedSchemaName] = runtimeSchema;
2243
+ }
2244
+
2245
+ return mergedSchemas;
2246
+ }
2247
+
2248
+ function assertSchemaRefExists(
2249
+ schemas: ContractSourceSchemas | undefined,
2250
+ ref: ContractSchemaRef,
2251
+ context: string,
2252
+ ): void {
2253
+ if (!schemas || !Object.hasOwn(schemas, ref.schema)) {
2254
+ throw new Error(`${context} references unknown schema '${ref.schema}'`);
2255
+ }
2256
+ }
2257
+
2258
+ function assertExportedSchemasExist(
2259
+ schemas: ContractSourceSchemas | undefined,
2260
+ contractExports: ContractSourceExports | undefined,
2261
+ ): void {
2262
+ for (const schemaName of contractExports?.schemas ?? []) {
2263
+ if (!schemas || !Object.hasOwn(schemas, schemaName)) {
2264
+ throw new Error(
2265
+ `contract exports reference unknown schema '${schemaName}'`,
2266
+ );
2267
+ }
2268
+ }
2269
+ }
2270
+
2271
+ function assertRegistryDoesNotDeclareExports(
2272
+ registry: AnyDefineContractRegistry,
2273
+ ): void {
2274
+ if (Object.hasOwn(registry, "exports")) {
2275
+ throw new Error(
2276
+ "contract exports must be declared in the callback body, not the registry argument",
2277
+ );
2278
+ }
2279
+ }
2280
+
2281
+ function assertRegistryDoesNotDeclareCapabilities(
2282
+ registry: AnyDefineContractRegistry,
2283
+ ): void {
2284
+ if (Object.hasOwn(registry, "capabilities")) {
2285
+ throw new Error(
2286
+ "contract capabilities must be declared in the callback body, not the registry argument",
2287
+ );
2288
+ }
2289
+ }
2290
+
2291
+ function resolveSchemaRef(
2292
+ schemas: ContractSourceSchemas | undefined,
2293
+ ref: ContractSchemaRef,
2294
+ context: string,
2295
+ ): JsonSchema {
2296
+ assertSchemaRefExists(schemas, ref, context);
2297
+ const schema = schemas?.[ref.schema];
2298
+ if (!schema) {
2299
+ throw new Error(`${context} references missing schema '${ref.schema}'`);
2300
+ }
2301
+ return cloneSchema(schema);
2302
+ }
2303
+
2304
+ function digestCanonicalJson(value: JsonValue): string {
2305
+ return sha256Base64urlSync(canonicalizeJson(value));
2306
+ }
2307
+
2308
+ function sortedUnique(values: readonly string[]): string[] {
2309
+ return [...new Set(values)].sort();
2310
+ }
2311
+
2312
+ /** Return the global capability namespace for a contract id. */
2313
+ export function contractCapabilityNamespace(contractId: string): string {
2314
+ return contractId.replace(/@v\d+$/, "");
2315
+ }
2316
+
2317
+ /** Return the globally qualified name for a contract-local capability. */
2318
+ export function globalCapabilityName(
2319
+ contractId: string,
2320
+ localCapability: string,
2321
+ ): string {
2322
+ return `${contractCapabilityNamespace(contractId)}::${localCapability}`;
2323
+ }
2324
+
2325
+ function projectCapabilities(
2326
+ capabilities: readonly Capability[] | undefined,
2327
+ contractId: string,
2328
+ declaredCapabilities: ContractCapabilities | undefined,
2329
+ context: string,
2330
+ ): string[] | undefined {
2331
+ if (!capabilities) {
2332
+ return undefined;
2333
+ }
2334
+ return sortedUnique(
2335
+ capabilities.map((capability) => {
2336
+ if (
2337
+ declaredCapabilities && Object.hasOwn(declaredCapabilities, capability)
2338
+ ) {
2339
+ return globalCapabilityName(contractId, capability);
2340
+ }
2341
+ if (
2342
+ capability === "admin" || capability === "service" ||
2343
+ capability.includes("::")
2344
+ ) {
2345
+ return capability;
2346
+ }
2347
+ throw new Error(
2348
+ `${context} references undeclared local capability '${capability}'`,
2349
+ );
2350
+ }),
2351
+ );
2352
+ }
2353
+
2354
+ function emitCapabilities(
2355
+ contractId: string,
2356
+ capabilities: ContractCapabilities | undefined,
2357
+ ): ContractCapabilities | undefined {
2358
+ if (!capabilities) {
2359
+ return undefined;
2360
+ }
2361
+
2362
+ const entries: [string, ContractCapabilityMetadata][] = Object.entries(
2363
+ capabilities,
2364
+ )
2365
+ .map(([localCapability, metadata]) => [
2366
+ globalCapabilityName(contractId, localCapability),
2367
+ { ...metadata },
2368
+ ]);
2369
+ entries.sort(([left], [right]) => left.localeCompare(right));
2370
+ return Object.fromEntries(entries);
2371
+ }
2372
+
2373
+ function collectSchemaRef(
2374
+ reachableSchemas: Set<string>,
2375
+ ref: ContractSchemaRef | undefined,
2376
+ ): void {
2377
+ if (ref) {
2378
+ reachableSchemas.add(ref.schema);
2379
+ }
2380
+ }
2381
+
2382
+ function collectReachableSchemaNames(contract: TrellisContractV1): Set<string> {
2383
+ const reachableSchemas = new Set<string>();
2384
+
2385
+ for (const store of Object.values(contract.state ?? {})) {
2386
+ collectSchemaRef(reachableSchemas, store.schema);
2387
+ for (const accepted of Object.values(store.acceptedVersions ?? {})) {
2388
+ collectSchemaRef(reachableSchemas, accepted);
2389
+ }
2390
+ }
2391
+
2392
+ for (const method of Object.values(contract.rpc ?? {})) {
2393
+ collectSchemaRef(reachableSchemas, method.input);
2394
+ collectSchemaRef(reachableSchemas, method.output);
2395
+ for (const error of method.errors ?? []) {
2396
+ const declaration = Object.values(contract.errors ?? {}).find((decl) =>
2397
+ decl.type === error.type
2398
+ );
2399
+ collectSchemaRef(reachableSchemas, declaration?.schema);
2400
+ }
2401
+ }
2402
+
2403
+ for (const operation of Object.values(contract.operations ?? {})) {
2404
+ collectSchemaRef(reachableSchemas, operation.input);
2405
+ collectSchemaRef(reachableSchemas, operation.progress);
2406
+ collectSchemaRef(reachableSchemas, operation.output);
2407
+ for (const signal of Object.values(operation.signals ?? {})) {
2408
+ collectSchemaRef(reachableSchemas, signal.input);
2409
+ }
2410
+ }
2411
+
2412
+ for (const event of Object.values(contract.events ?? {})) {
2413
+ collectSchemaRef(reachableSchemas, event.event);
2414
+ }
2415
+
2416
+ for (const feed of Object.values(contract.feeds ?? {})) {
2417
+ collectSchemaRef(reachableSchemas, feed.input);
2418
+ collectSchemaRef(reachableSchemas, feed.event);
2419
+ }
2420
+
2421
+ for (const job of Object.values(contract.jobs ?? {})) {
2422
+ collectSchemaRef(reachableSchemas, job.payload);
2423
+ collectSchemaRef(reachableSchemas, job.result);
2424
+ }
2425
+
2426
+ for (const resource of Object.values(contract.resources?.kv ?? {})) {
2427
+ collectSchemaRef(reachableSchemas, resource.schema);
2428
+ }
2429
+
2430
+ return reachableSchemas;
2431
+ }
2432
+
2433
+ function projectReachableSchemas(
2434
+ contract: TrellisContractV1,
2435
+ ): ContractSchemas | undefined {
2436
+ const reachableNames = collectReachableSchemaNames(contract);
2437
+ if (!contract.schemas || reachableNames.size === 0) {
2438
+ return undefined;
2439
+ }
2440
+
2441
+ const entries = Object.entries(contract.schemas).filter(([name]) =>
2442
+ reachableNames.has(name)
2443
+ );
2444
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
2445
+ }
2446
+
2447
+ function projectRpcDeclaredErrors(
2448
+ contract: TrellisContractV1,
2449
+ ): Record<string, ContractErrorDecl> | undefined {
2450
+ if (!contract.errors) {
2451
+ return undefined;
2452
+ }
2453
+
2454
+ const declaredErrorTypes = new Set<string>();
2455
+ for (const method of Object.values(contract.rpc ?? {})) {
2456
+ for (const error of method.errors ?? []) {
2457
+ declaredErrorTypes.add(error.type);
2458
+ }
2459
+ }
2460
+
2461
+ const entries = Object.entries(contract.errors).filter(([, error]) =>
2462
+ declaredErrorTypes.has(error.type)
2463
+ );
2464
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
2465
+ }
2466
+
2467
+ function projectDigestResources(
2468
+ resources: ContractResources | undefined,
2469
+ ): ContractResources | undefined {
2470
+ if (!resources?.kv && !resources?.store) {
2471
+ return undefined;
2472
+ }
2473
+ return {
2474
+ ...(resources.kv ? { kv: resources.kv } : {}),
2475
+ ...(resources.store ? { store: resources.store } : {}),
2476
+ };
2477
+ }
2478
+
2479
+ function projectDigestUsesFlat(
2480
+ uses: ContractUsesFlat | undefined,
2481
+ ): ContractUsesFlat | undefined {
2482
+ if (!uses) {
2483
+ return undefined;
2484
+ }
2485
+
2486
+ return Object.fromEntries(
2487
+ Object.entries(uses).map(([alias, use]) => [
2488
+ alias,
2489
+ {
2490
+ contract: use.contract,
2491
+ ...(use.rpc?.call ? { rpc: { call: sortedUnique(use.rpc.call) } } : {}),
2492
+ ...(use.operations?.call
2493
+ ? { operations: { call: sortedUnique(use.operations.call) } }
2494
+ : {}),
2495
+ ...((use.events?.publish || use.events?.subscribe)
2496
+ ? {
2497
+ events: {
2498
+ ...(use.events.publish
2499
+ ? { publish: sortedUnique(use.events.publish) }
2500
+ : {}),
2501
+ ...(use.events.subscribe
2502
+ ? { subscribe: sortedUnique(use.events.subscribe) }
2503
+ : {}),
2504
+ },
2505
+ }
2506
+ : {}),
2507
+ ...(use.feeds?.subscribe
2508
+ ? { feeds: { subscribe: sortedUnique(use.feeds.subscribe) } }
2509
+ : {}),
2510
+ } satisfies ContractUse,
2511
+ ]),
2512
+ );
2513
+ }
2514
+
2515
+ function omitRequiredUseAliases<TUse>(
2516
+ optional: Record<string, TUse> | undefined,
2517
+ required: Record<string, TUse> | undefined,
2518
+ ): Record<string, TUse> | undefined {
2519
+ if (!optional) {
2520
+ return undefined;
2521
+ }
2522
+ if (!required) {
2523
+ return optional;
2524
+ }
2525
+ const requiredAliases = new Set(Object.keys(required));
2526
+ const entries = Object.entries(optional).filter(([alias]) =>
2527
+ !requiredAliases.has(alias)
2528
+ );
2529
+ return entries.length > 0 ? Object.fromEntries(entries) : undefined;
2530
+ }
2531
+
2532
+ function projectDigestUses(
2533
+ uses: ContractUses | undefined,
2534
+ ): ContractUses | undefined {
2535
+ if (!uses) {
2536
+ return undefined;
2537
+ }
2538
+
2539
+ const required = projectDigestUsesFlat(uses.required);
2540
+ const optional = omitRequiredUseAliases(
2541
+ projectDigestUsesFlat(uses.optional),
2542
+ required,
2543
+ );
2544
+ if (!required && !optional) {
2545
+ return undefined;
2546
+ }
2547
+ return {
2548
+ ...(required ? { required } : {}),
2549
+ ...(optional ? { optional } : {}),
2550
+ };
2551
+ }
2552
+
2553
+ function projectDigestRpc(
2554
+ rpc: Record<string, ContractRpcMethod> | undefined,
2555
+ ): Record<string, ContractRpcMethod> | undefined {
2556
+ if (!rpc) {
2557
+ return undefined;
2558
+ }
2559
+
2560
+ return Object.fromEntries(
2561
+ Object.entries(rpc).map(([name, method]) => [
2562
+ name,
2563
+ {
2564
+ ...method,
2565
+ ...(method.capabilities?.call
2566
+ ? { capabilities: { call: sortedUnique(method.capabilities.call) } }
2567
+ : {}),
2568
+ ...(method.errors
2569
+ ? {
2570
+ errors: sortedUnique(method.errors.map((error) => error.type)).map((
2571
+ type,
2572
+ ) => ({ type })),
2573
+ }
2574
+ : {}),
2575
+ } satisfies ContractRpcMethod,
2576
+ ]),
2577
+ );
2578
+ }
2579
+
2580
+ function projectDigestOperations(
2581
+ operations: Record<string, ContractOperation> | undefined,
2582
+ ): Record<string, ContractOperation> | undefined {
2583
+ if (!operations) {
2584
+ return undefined;
2585
+ }
2586
+
2587
+ return Object.fromEntries(
2588
+ Object.entries(operations).map(([name, operation]) => [
2589
+ name,
2590
+ {
2591
+ ...operation,
2592
+ ...((operation.capabilities?.call || operation.capabilities?.read ||
2593
+ operation.capabilities?.cancel || operation.capabilities?.control)
2594
+ ? {
2595
+ capabilities: {
2596
+ ...(operation.capabilities.call
2597
+ ? { call: sortedUnique(operation.capabilities.call) }
2598
+ : {}),
2599
+ ...(operation.capabilities.read
2600
+ ? { read: sortedUnique(operation.capabilities.read) }
2601
+ : {}),
2602
+ ...(operation.capabilities.cancel
2603
+ ? { cancel: sortedUnique(operation.capabilities.cancel) }
2604
+ : {}),
2605
+ ...(operation.capabilities.control
2606
+ ? { control: sortedUnique(operation.capabilities.control) }
2607
+ : {}),
2608
+ },
2609
+ }
2610
+ : {}),
2611
+ } satisfies ContractOperation,
2612
+ ]),
2613
+ );
2614
+ }
2615
+
2616
+ function projectDigestEvents(
2617
+ events: Record<string, ContractEvent> | undefined,
2618
+ ): Record<string, ContractEvent> | undefined {
2619
+ if (!events) {
2620
+ return undefined;
2621
+ }
2622
+
2623
+ return Object.fromEntries(
2624
+ Object.entries(events).map(([name, event]) => [
2625
+ name,
2626
+ {
2627
+ ...event,
2628
+ ...((event.capabilities?.publish || event.capabilities?.subscribe)
2629
+ ? {
2630
+ capabilities: {
2631
+ ...(event.capabilities.publish
2632
+ ? { publish: sortedUnique(event.capabilities.publish) }
2633
+ : {}),
2634
+ ...(event.capabilities.subscribe
2635
+ ? { subscribe: sortedUnique(event.capabilities.subscribe) }
2636
+ : {}),
2637
+ },
2638
+ }
2639
+ : {}),
2640
+ } satisfies ContractEvent,
2641
+ ]),
2642
+ );
2643
+ }
2644
+
2645
+ function projectDigestFeeds(
2646
+ feeds: Record<string, ContractFeed> | undefined,
2647
+ ): Record<string, ContractFeed> | undefined {
2648
+ if (!feeds) {
2649
+ return undefined;
2650
+ }
2651
+
2652
+ return Object.fromEntries(
2653
+ Object.entries(feeds).map(([name, feed]) => [
2654
+ name,
2655
+ {
2656
+ ...feed,
2657
+ ...(feed.capabilities?.subscribe
2658
+ ? {
2659
+ capabilities: {
2660
+ subscribe: sortedUnique(feed.capabilities.subscribe),
2661
+ },
2662
+ }
2663
+ : {}),
2664
+ } satisfies ContractFeed,
2665
+ ]),
2666
+ );
2667
+ }
2668
+
2669
+ function mapValues<TInput, TOutput>(
2670
+ values: Record<string, TInput> | undefined,
2671
+ map: (value: TInput) => TOutput,
2672
+ ): Record<string, TOutput> | undefined {
2673
+ if (!values) return undefined;
2674
+ return Object.fromEntries(
2675
+ Object.entries(values).map(([key, value]) => [key, map(value)]),
2676
+ );
2677
+ }
2678
+
2679
+ function schemaRef(ref: ContractSchemaRef): ContractSchemaRef {
2680
+ return { schema: ref.schema };
2681
+ }
2682
+
2683
+ function capabilityMetadata(
2684
+ metadata: ContractCapabilityMetadata,
2685
+ ): ContractCapabilityMetadata {
2686
+ return {
2687
+ displayName: metadata.displayName,
2688
+ description: metadata.description,
2689
+ ...(metadata.consequence ? { consequence: metadata.consequence } : {}),
2690
+ };
2691
+ }
2692
+
2693
+ function useRpc(use: ContractUsesRpc | undefined): ContractUsesRpc | undefined {
2694
+ if (!use) return undefined;
2695
+ return {
2696
+ ...(use.call ? { call: [...use.call] } : {}),
2697
+ };
2698
+ }
2699
+
2700
+ function usePubSub(
2701
+ use: ContractUsesPubSub | undefined,
2702
+ ): ContractUsesPubSub | undefined {
2703
+ if (!use) return undefined;
2704
+ return {
2705
+ ...(use.publish ? { publish: [...use.publish] } : {}),
2706
+ ...(use.subscribe ? { subscribe: [...use.subscribe] } : {}),
2707
+ };
2708
+ }
2709
+
2710
+ function contractUse(use: ContractUse): ContractUse {
2711
+ return {
2712
+ contract: use.contract,
2713
+ ...(use.rpc ? { rpc: useRpc(use.rpc) } : {}),
2714
+ ...(use.operations ? { operations: useRpc(use.operations) } : {}),
2715
+ ...(use.events ? { events: usePubSub(use.events) } : {}),
2716
+ ...(use.feeds
2717
+ ? {
2718
+ feeds: {
2719
+ ...(use.feeds.subscribe
2720
+ ? { subscribe: [...use.feeds.subscribe] }
2721
+ : {}),
2722
+ },
2723
+ }
2724
+ : {}),
2725
+ };
2726
+ }
2727
+
2728
+ function contractUses(
2729
+ uses: ContractUses | undefined,
2730
+ ): ContractUses | undefined {
2731
+ if (!uses) return undefined;
2732
+ return {
2733
+ ...(uses.required
2734
+ ? { required: mapValues(uses.required, contractUse) }
2735
+ : {}),
2736
+ ...(uses.optional
2737
+ ? { optional: mapValues(uses.optional, contractUse) }
2738
+ : {}),
2739
+ };
2740
+ }
2741
+
2742
+ function stateStore(store: ContractStateStore): ContractStateStore {
2743
+ return {
2744
+ kind: store.kind,
2745
+ schema: schemaRef(store.schema),
2746
+ ...(store.stateVersion ? { stateVersion: store.stateVersion } : {}),
2747
+ ...(store.acceptedVersions
2748
+ ? { acceptedVersions: mapValues(store.acceptedVersions, schemaRef) }
2749
+ : {}),
2750
+ };
2751
+ }
2752
+
2753
+ function rpcMethod(method: ContractRpcMethod): ContractRpcMethod {
2754
+ return {
2755
+ version: method.version,
2756
+ subject: method.subject,
2757
+ input: schemaRef(method.input),
2758
+ output: schemaRef(method.output),
2759
+ ...(method.transfer
2760
+ ? { transfer: { direction: method.transfer.direction } }
2761
+ : {}),
2762
+ ...(method.capabilities?.call
2763
+ ? { capabilities: { call: [...method.capabilities.call] } }
2764
+ : {}),
2765
+ ...(method.errors
2766
+ ? { errors: method.errors.map((error) => ({ type: error.type })) }
2767
+ : {}),
2768
+ };
2769
+ }
2770
+
2771
+ function operation(operation: ContractOperation): ContractOperation {
2772
+ return {
2773
+ version: operation.version,
2774
+ subject: operation.subject,
2775
+ input: schemaRef(operation.input),
2776
+ ...(operation.progress ? { progress: schemaRef(operation.progress) } : {}),
2777
+ output: schemaRef(operation.output),
2778
+ ...(operation.transfer
2779
+ ? {
2780
+ transfer: {
2781
+ direction: operation.transfer.direction,
2782
+ store: operation.transfer.store,
2783
+ key: operation.transfer.key,
2784
+ ...(operation.transfer.contentType
2785
+ ? { contentType: operation.transfer.contentType }
2786
+ : {}),
2787
+ ...(operation.transfer.metadata
2788
+ ? { metadata: operation.transfer.metadata }
2789
+ : {}),
2790
+ ...(operation.transfer.expiresInMs !== undefined
2791
+ ? { expiresInMs: operation.transfer.expiresInMs }
2792
+ : {}),
2793
+ ...(operation.transfer.maxBytes !== undefined
2794
+ ? { maxBytes: operation.transfer.maxBytes }
2795
+ : {}),
2796
+ },
2797
+ }
2798
+ : {}),
2799
+ ...(operation.capabilities
2800
+ ? {
2801
+ capabilities: {
2802
+ ...(operation.capabilities.call
2803
+ ? { call: [...operation.capabilities.call] }
2804
+ : {}),
2805
+ ...(operation.capabilities.read
2806
+ ? { read: [...operation.capabilities.read] }
2807
+ : {}),
2808
+ ...(operation.capabilities.cancel
2809
+ ? { cancel: [...operation.capabilities.cancel] }
2810
+ : {}),
2811
+ ...(operation.capabilities.control
2812
+ ? { control: [...operation.capabilities.control] }
2813
+ : {}),
2814
+ },
2815
+ }
2816
+ : {}),
2817
+ ...(operation.signals
2818
+ ? {
2819
+ signals: mapValues(
2820
+ operation.signals,
2821
+ (signal) => ({ input: schemaRef(signal.input) }),
2822
+ ),
2823
+ }
2824
+ : {}),
2825
+ ...(operation.cancel !== undefined ? { cancel: operation.cancel } : {}),
2826
+ };
2827
+ }
2828
+
2829
+ function event(event: ContractEvent): ContractEvent {
2830
+ return {
2831
+ version: event.version,
2832
+ subject: event.subject,
2833
+ ...(event.params ? { params: [...event.params] } : {}),
2834
+ event: schemaRef(event.event),
2835
+ ...(event.capabilities
2836
+ ? {
2837
+ capabilities: {
2838
+ ...(event.capabilities.publish
2839
+ ? { publish: [...event.capabilities.publish] }
2840
+ : {}),
2841
+ ...(event.capabilities.subscribe
2842
+ ? { subscribe: [...event.capabilities.subscribe] }
2843
+ : {}),
2844
+ },
2845
+ }
2846
+ : {}),
2847
+ };
2848
+ }
2849
+
2850
+ function feed(feed: ContractFeed): ContractFeed {
2851
+ return {
2852
+ version: feed.version,
2853
+ subject: feed.subject,
2854
+ input: schemaRef(feed.input),
2855
+ event: schemaRef(feed.event),
2856
+ ...(feed.capabilities?.subscribe
2857
+ ? { capabilities: { subscribe: [...feed.capabilities.subscribe] } }
2858
+ : {}),
2859
+ };
2860
+ }
2861
+
2862
+ function errorDecl(error: ContractErrorDecl): ContractErrorDecl {
2863
+ return {
2864
+ type: error.type,
2865
+ ...(error.schema ? { schema: schemaRef(error.schema) } : {}),
2866
+ };
2867
+ }
2868
+
2869
+ function jobQueue(queue: ContractJobQueue): ContractJobQueue {
2870
+ return {
2871
+ payload: schemaRef(queue.payload),
2872
+ ...(queue.result ? { result: schemaRef(queue.result) } : {}),
2873
+ ...(queue.maxDeliver !== undefined ? { maxDeliver: queue.maxDeliver } : {}),
2874
+ ...(queue.backoffMs ? { backoffMs: [...queue.backoffMs] } : {}),
2875
+ ...(queue.ackWaitMs !== undefined ? { ackWaitMs: queue.ackWaitMs } : {}),
2876
+ ...(queue.defaultDeadlineMs !== undefined
2877
+ ? { defaultDeadlineMs: queue.defaultDeadlineMs }
2878
+ : {}),
2879
+ ...(queue.progress !== undefined ? { progress: queue.progress } : {}),
2880
+ ...(queue.logs !== undefined ? { logs: queue.logs } : {}),
2881
+ ...(queue.dlq !== undefined ? { dlq: queue.dlq } : {}),
2882
+ ...(queue.concurrency !== undefined
2883
+ ? { concurrency: queue.concurrency }
2884
+ : {}),
2885
+ };
2886
+ }
2887
+
2888
+ function kvResource(resource: ContractKvResource): ContractKvResource {
2889
+ return {
2890
+ purpose: resource.purpose,
2891
+ schema: schemaRef(resource.schema),
2892
+ ...(resource.required !== undefined ? { required: resource.required } : {}),
2893
+ ...(resource.history !== undefined ? { history: resource.history } : {}),
2894
+ ...(resource.ttlMs !== undefined ? { ttlMs: resource.ttlMs } : {}),
2895
+ ...(resource.maxValueBytes !== undefined
2896
+ ? { maxValueBytes: resource.maxValueBytes }
2897
+ : {}),
2898
+ };
2899
+ }
2900
+
2901
+ function storeResource(resource: ContractStoreResource): ContractStoreResource {
2902
+ return {
2903
+ purpose: resource.purpose,
2904
+ ...(resource.required !== undefined ? { required: resource.required } : {}),
2905
+ ...(resource.ttlMs !== undefined ? { ttlMs: resource.ttlMs } : {}),
2906
+ ...(resource.maxObjectBytes !== undefined
2907
+ ? { maxObjectBytes: resource.maxObjectBytes }
2908
+ : {}),
2909
+ ...(resource.maxTotalBytes !== undefined
2910
+ ? { maxTotalBytes: resource.maxTotalBytes }
2911
+ : {}),
2912
+ };
2913
+ }
2914
+
2915
+ /**
2916
+ * Return the canonical manifest shape used by Trellis runtimes before
2917
+ * validation, persistence, and digesting.
2918
+ *
2919
+ * This is not the digest projection: human-facing fields such as
2920
+ * `displayName` and `description` are preserved here even though they are not
2921
+ * part of contract identity. Unknown extension fields are intentionally omitted
2922
+ * until the runtime explicitly supports them.
2923
+ */
2924
+ export function normalizeContractManifest(
2925
+ contract: TrellisContractV1,
2926
+ ): TrellisContractV1 {
2927
+ return {
2928
+ format: contract.format,
2929
+ id: contract.id,
2930
+ displayName: contract.displayName,
2931
+ description: contract.description,
2932
+ kind: contract.kind,
2933
+ ...(contract.capabilities
2934
+ ? { capabilities: mapValues(contract.capabilities, capabilityMetadata) }
2935
+ : {}),
2936
+ ...(contract.schemas ? { schemas: contract.schemas } : {}),
2937
+ ...(contract.exports
2938
+ ? {
2939
+ exports: {
2940
+ ...(contract.exports.schemas
2941
+ ? { schemas: [...contract.exports.schemas] }
2942
+ : {}),
2943
+ },
2944
+ }
2945
+ : {}),
2946
+ ...(contract.uses ? { uses: contractUses(contract.uses) } : {}),
2947
+ ...(contract.state ? { state: mapValues(contract.state, stateStore) } : {}),
2948
+ ...(contract.rpc ? { rpc: mapValues(contract.rpc, rpcMethod) } : {}),
2949
+ ...(contract.operations
2950
+ ? { operations: mapValues(contract.operations, operation) }
2951
+ : {}),
2952
+ ...(contract.events ? { events: mapValues(contract.events, event) } : {}),
2953
+ ...(contract.feeds ? { feeds: mapValues(contract.feeds, feed) } : {}),
2954
+ ...(contract.jobs ? { jobs: mapValues(contract.jobs, jobQueue) } : {}),
2955
+ ...(contract.resources
2956
+ ? {
2957
+ resources: {
2958
+ ...(contract.resources.kv
2959
+ ? { kv: mapValues(contract.resources.kv, kvResource) }
2960
+ : {}),
2961
+ ...(contract.resources.store
2962
+ ? { store: mapValues(contract.resources.store, storeResource) }
2963
+ : {}),
2964
+ },
2965
+ }
2966
+ : {}),
2967
+ ...(contract.errors
2968
+ ? { errors: mapValues(contract.errors, errorDecl) }
2969
+ : {}),
2970
+ };
2971
+ }
2972
+
2973
+ /**
2974
+ * Parse untrusted contract JSON into the current Trellis v1 manifest shape.
2975
+ *
2976
+ * Unknown extension fields are accepted for forward compatibility but are not
2977
+ * returned. Callers must use the returned value for persistence and digesting.
2978
+ */
2979
+ export function parseContractManifest(value: unknown): TrellisContractV1 {
2980
+ try {
2981
+ return normalizeContractManifest(
2982
+ Value.Parse(TrellisContractV1Schema, value) as TrellisContractV1,
2983
+ );
2984
+ } catch (error) {
2985
+ const details = [...Value.Errors(TrellisContractV1Schema, value)].map((
2986
+ entry,
2987
+ ) => `${entry.instancePath || "#"}: ${entry.message}`);
2988
+ throw new TypeError(
2989
+ `Invalid contract${details.length > 0 ? `:\n${details.join("\n")}` : ""}`,
2990
+ { cause: error },
2991
+ );
2992
+ }
2993
+ }
2994
+
2995
+ /**
2996
+ * Build the normalized runtime/interface projection used for contract identity.
2997
+ */
2998
+ export function projectContractDigestManifest(
2999
+ contract: TrellisContractV1,
3000
+ ): JsonValue {
3001
+ const schemas = projectReachableSchemas(contract);
3002
+ const errors = projectRpcDeclaredErrors(contract);
3003
+ const resources = projectDigestResources(contract.resources);
3004
+ const uses = projectDigestUses(contract.uses);
3005
+ const rpc = projectDigestRpc(contract.rpc);
3006
+ const operations = projectDigestOperations(contract.operations);
3007
+ const events = projectDigestEvents(contract.events);
3008
+ const feeds = projectDigestFeeds(contract.feeds);
3009
+
3010
+ return {
3011
+ format: contract.format,
3012
+ id: contract.id,
3013
+ kind: contract.kind,
3014
+ ...(contract.capabilities ? { capabilities: contract.capabilities } : {}),
3015
+ ...(schemas ? { schemas } : {}),
3016
+ ...(contract.state ? { state: contract.state } : {}),
3017
+ ...(uses ? { uses } : {}),
3018
+ ...(rpc ? { rpc } : {}),
3019
+ ...(operations ? { operations } : {}),
3020
+ ...(events ? { events } : {}),
3021
+ ...(feeds ? { feeds } : {}),
3022
+ ...(errors ? { errors } : {}),
3023
+ ...(contract.jobs ? { jobs: contract.jobs } : {}),
3024
+ ...(resources ? { resources } : {}),
3025
+ };
3026
+ }
3027
+
3028
+ /** Compute the v1 contract digest from the normalized digest projection. */
3029
+ export function digestContractManifest(contract: TrellisContractV1): string {
3030
+ return digestCanonicalJson(
3031
+ projectContractDigestManifest(normalizeContractManifest(contract)),
3032
+ );
3033
+ }
3034
+
3035
+ function rpcSubject(name: string, version: `v${number}`): string {
3036
+ return `rpc.${version}.${name}`;
3037
+ }
3038
+
3039
+ function operationSubject(name: string, version: `v${number}`): string {
3040
+ return `operations.${version}.${name}`;
3041
+ }
3042
+
3043
+ function feedSubject(name: string, version: `v${number}`): string {
3044
+ return `feeds.${version}.${name}`;
3045
+ }
3046
+
3047
+ function eventSubject(
3048
+ name: string,
3049
+ version: `v${number}`,
3050
+ params: readonly SubjectParam[] | undefined,
3051
+ ): string {
3052
+ const suffix = params && params.length > 0
3053
+ ? `.${params.map((pointer) => `{${pointer}}`).join(".")}`
3054
+ : "";
3055
+ return `events.${version}.${name}${suffix}`;
3056
+ }
3057
+
3058
+ function emitResources(
3059
+ resources: ContractSourceResources | undefined,
3060
+ ): ContractResources | undefined {
3061
+ if (!resources?.kv && !resources?.store) {
3062
+ return undefined;
3063
+ }
3064
+
3065
+ return {
3066
+ ...(resources.kv
3067
+ ? {
3068
+ kv: Object.fromEntries(
3069
+ Object.entries(resources.kv).map(([alias, resource]) => [
3070
+ alias,
3071
+ {
3072
+ purpose: resource.purpose,
3073
+ schema: { ...resource.schema },
3074
+ required: resource.required ?? true,
3075
+ history: resource.history ?? 1,
3076
+ ttlMs: resource.ttlMs ?? 0,
3077
+ ...(resource.maxValueBytes
3078
+ ? { maxValueBytes: resource.maxValueBytes }
3079
+ : {}),
3080
+ } satisfies ContractKvResource,
3081
+ ]),
3082
+ ),
3083
+ }
3084
+ : {}),
3085
+ ...(resources.store
3086
+ ? {
3087
+ store: Object.fromEntries(
3088
+ Object.entries(resources.store).map(([alias, resource]) => [
3089
+ alias,
3090
+ {
3091
+ purpose: resource.purpose,
3092
+ required: resource.required ?? true,
3093
+ ttlMs: resource.ttlMs ?? 0,
3094
+ ...(resource.maxObjectBytes !== undefined
3095
+ ? { maxObjectBytes: resource.maxObjectBytes }
3096
+ : {}),
3097
+ ...(resource.maxTotalBytes !== undefined
3098
+ ? { maxTotalBytes: resource.maxTotalBytes }
3099
+ : {}),
3100
+ } satisfies ContractStoreResource,
3101
+ ]),
3102
+ ),
3103
+ }
3104
+ : {}),
3105
+ };
3106
+ }
3107
+
3108
+ function emitJobs(
3109
+ jobs: ContractSourceJobs | undefined,
3110
+ ): ContractJobs | undefined {
3111
+ if (!jobs) {
3112
+ return undefined;
3113
+ }
3114
+
3115
+ return Object.fromEntries(
3116
+ Object.entries(jobs).map(([queueType, queue]) => [
3117
+ queueType,
3118
+ {
3119
+ payload: { ...queue.payload },
3120
+ ...(queue.result ? { result: { ...queue.result } } : {}),
3121
+ ...(queue.maxDeliver !== undefined
3122
+ ? { maxDeliver: queue.maxDeliver }
3123
+ : {}),
3124
+ ...(queue.backoffMs ? { backoffMs: [...queue.backoffMs] } : {}),
3125
+ ...(queue.ackWaitMs !== undefined
3126
+ ? { ackWaitMs: queue.ackWaitMs }
3127
+ : {}),
3128
+ ...(queue.defaultDeadlineMs !== undefined
3129
+ ? { defaultDeadlineMs: queue.defaultDeadlineMs }
3130
+ : {}),
3131
+ ...(queue.progress !== undefined ? { progress: queue.progress } : {}),
3132
+ ...(queue.logs !== undefined ? { logs: queue.logs } : {}),
3133
+ ...(queue.dlq !== undefined ? { dlq: queue.dlq } : {}),
3134
+ ...(queue.concurrency !== undefined
3135
+ ? { concurrency: queue.concurrency }
3136
+ : {}),
3137
+ } satisfies ContractJobQueue,
3138
+ ]),
3139
+ );
3140
+ }
3141
+
3142
+ function buildContractJobsMetadata(
3143
+ jobs: ContractSourceJobs | undefined,
3144
+ ): ContractJobsMetadata {
3145
+ if (!jobs) {
3146
+ return {};
3147
+ }
3148
+
3149
+ return Object.fromEntries(
3150
+ Object.keys(jobs).map((queueType) => [queueType, {
3151
+ payload: undefined,
3152
+ result: undefined,
3153
+ }]),
3154
+ ) as ContractJobsMetadata;
3155
+ }
3156
+
3157
+ function buildContractKvMetadata(
3158
+ resources: ContractSourceResources | undefined,
3159
+ schemas: ContractSourceSchemas | undefined,
3160
+ ): ContractKvMetadata {
3161
+ const kv = resources?.kv;
3162
+ if (!kv) {
3163
+ return {};
3164
+ }
3165
+
3166
+ const metadata: ContractKvMetadata = {};
3167
+ for (const [alias, resource] of Object.entries(kv)) {
3168
+ assertSchemaRefExists(schemas, resource.schema, `kv resource '${alias}'`);
3169
+ const schema = schemas?.[resource.schema.schema];
3170
+ if (!schema) {
3171
+ throw new Error(
3172
+ `kv resource '${alias}' references missing schema '${resource.schema.schema}'`,
3173
+ );
3174
+ }
3175
+ metadata[alias] = {
3176
+ required: resource.required ?? true,
3177
+ value: undefined,
3178
+ schema,
3179
+ };
3180
+ }
3181
+ return metadata;
3182
+ }
3183
+
3184
+ function buildContractStateMetadata(
3185
+ state: ContractSourceState | undefined,
3186
+ schemas: ContractSourceSchemas | undefined,
3187
+ ): ContractStateMetadata {
3188
+ if (!state) {
3189
+ return {};
3190
+ }
3191
+
3192
+ return Object.fromEntries(
3193
+ Object.entries(state).map(([storeName, store]) => [storeName, {
3194
+ kind: store.kind,
3195
+ value: undefined,
3196
+ schema: resolveSchemaRef(
3197
+ schemas,
3198
+ store.schema,
3199
+ `state store '${storeName}'`,
3200
+ ),
3201
+ stateVersion: store.stateVersion ?? "v1",
3202
+ acceptedVersions: Object.fromEntries(
3203
+ Object.entries(store.acceptedVersions ?? {}).map((
3204
+ [version, schema],
3205
+ ) => [
3206
+ version,
3207
+ resolveSchemaRef(
3208
+ schemas,
3209
+ schema,
3210
+ `state store '${storeName}' accepted version '${version}'`,
3211
+ ),
3212
+ ]),
3213
+ ),
3214
+ }]),
3215
+ ) as ContractStateMetadata;
3216
+ }
3217
+
3218
+ function emitState(
3219
+ state: ContractSourceState | undefined,
3220
+ ): ContractState | undefined {
3221
+ if (!state) {
3222
+ return undefined;
3223
+ }
3224
+
3225
+ return Object.fromEntries(
3226
+ Object.entries(state).map(([storeName, store]) => [
3227
+ storeName,
3228
+ {
3229
+ kind: store.kind,
3230
+ schema: { ...store.schema },
3231
+ ...(store.stateVersion === undefined
3232
+ ? {}
3233
+ : { stateVersion: store.stateVersion }),
3234
+ ...(store.acceptedVersions === undefined
3235
+ ? {}
3236
+ : { acceptedVersions: store.acceptedVersions }),
3237
+ } satisfies ContractStateStore,
3238
+ ]),
3239
+ );
3240
+ }
3241
+
3242
+ function emitUsesFlat(
3243
+ uses: ContractSourceUsesFlat | undefined,
3244
+ ): ContractUsesFlat | undefined {
3245
+ if (!uses) {
3246
+ return undefined;
3247
+ }
3248
+
3249
+ return Object.fromEntries(
3250
+ Object.entries(uses).map(([alias, use]) => [
3251
+ alias,
3252
+ {
3253
+ contract: use.contract,
3254
+ ...(use.rpc?.call ? { rpc: { call: sortedUnique(use.rpc.call) } } : {}),
3255
+ ...(use.operations?.call
3256
+ ? { operations: { call: sortedUnique(use.operations.call) } }
3257
+ : {}),
3258
+ ...((use.events?.publish || use.events?.subscribe)
3259
+ ? {
3260
+ events: {
3261
+ ...(use.events.publish
3262
+ ? { publish: sortedUnique(use.events.publish) }
3263
+ : {}),
3264
+ ...(use.events.subscribe
3265
+ ? { subscribe: sortedUnique(use.events.subscribe) }
3266
+ : {}),
3267
+ },
3268
+ }
3269
+ : {}),
3270
+ ...(use.feeds?.subscribe
3271
+ ? { feeds: { subscribe: sortedUnique(use.feeds.subscribe) } }
3272
+ : {}),
3273
+ } satisfies ContractUse,
3274
+ ]),
3275
+ );
3276
+ }
3277
+
3278
+ function emitUses(
3279
+ uses: ContractSourceUses | undefined,
3280
+ ): ContractUses | undefined {
3281
+ if (!uses) {
3282
+ return undefined;
3283
+ }
3284
+
3285
+ const required = emitUsesFlat(uses.required);
3286
+ const optional = omitRequiredUseAliases(
3287
+ emitUsesFlat(uses.optional),
3288
+ required,
3289
+ );
3290
+ if (!required && !optional) {
3291
+ return undefined;
3292
+ }
3293
+ return {
3294
+ ...(required ? { required } : {}),
3295
+ ...(optional ? { optional } : {}),
3296
+ };
3297
+ }
3298
+
3299
+ function emitContract(source: TrellisContractSource): TrellisContractV1 {
3300
+ const capabilities = emitCapabilities(source.id, source.capabilities);
3301
+ const rpc = source.rpc
3302
+ ? Object.fromEntries(
3303
+ Object.entries(source.rpc).map(([name, method]) => {
3304
+ const emitted: ContractRpcMethod = {
3305
+ version: method.version,
3306
+ subject: method.subject ?? rpcSubject(name, method.version),
3307
+ input: { ...method.input },
3308
+ output: { ...method.output },
3309
+ };
3310
+ if (method.capabilities?.call) {
3311
+ emitted.capabilities = {
3312
+ call: projectCapabilities(
3313
+ method.capabilities.call,
3314
+ source.id,
3315
+ source.capabilities,
3316
+ `rpc '${name}' call capabilities`,
3317
+ ) ?? [],
3318
+ };
3319
+ }
3320
+ if (method.transfer) {
3321
+ emitted.transfer = { ...method.transfer };
3322
+ }
3323
+ if (method.errors && method.errors.length > 0) {
3324
+ emitted.errors = sortedUnique(
3325
+ method.errors.map((errorName) =>
3326
+ source.errors?.[errorName]?.type ?? errorName
3327
+ ),
3328
+ ).map((type) => ({ type }));
3329
+ }
3330
+ return [name, emitted];
3331
+ }),
3332
+ )
3333
+ : undefined;
3334
+
3335
+ const operations = source.operations
3336
+ ? Object.fromEntries(
3337
+ Object.entries(source.operations).map(([name, operation]) => {
3338
+ if (operation.transfer) {
3339
+ const store = source.resources?.store?.[operation.transfer.store];
3340
+ if (!store) {
3341
+ throw new Error(
3342
+ `Operation '${name}' references unknown store resource '${operation.transfer.store}'`,
3343
+ );
3344
+ }
3345
+
3346
+ const inputSchema = resolveSchemaRef(
3347
+ source.schemas,
3348
+ operation.input,
3349
+ `operation '${name}' input`,
3350
+ );
3351
+ for (
3352
+ const pointer of [
3353
+ operation.transfer.key,
3354
+ operation.transfer.contentType,
3355
+ operation.transfer.metadata,
3356
+ ]
3357
+ ) {
3358
+ if (!pointer) {
3359
+ continue;
3360
+ }
3361
+ if (getSubschemaAtDataPointer(inputSchema, pointer) === undefined) {
3362
+ throw new Error(
3363
+ `Invalid transfer pointer '${pointer}' for operation '${name}' (path not found in input schema)`,
3364
+ );
3365
+ }
3366
+ }
3367
+ }
3368
+
3369
+ const emitted: ContractOperation = {
3370
+ version: operation.version,
3371
+ subject: operation.subject ??
3372
+ operationSubject(name, operation.version),
3373
+ input: { ...operation.input },
3374
+ output: { ...operation.output },
3375
+ };
3376
+ if (operation.progress) {
3377
+ emitted.progress = { ...operation.progress };
3378
+ }
3379
+ if (operation.transfer) {
3380
+ emitted.transfer = { ...operation.transfer, direction: "send" };
3381
+ }
3382
+ if (
3383
+ operation.capabilities?.call || operation.capabilities?.read ||
3384
+ operation.capabilities?.cancel || operation.capabilities?.control
3385
+ ) {
3386
+ emitted.capabilities = {
3387
+ ...(operation.capabilities.call
3388
+ ? {
3389
+ call: projectCapabilities(
3390
+ operation.capabilities.call,
3391
+ source.id,
3392
+ source.capabilities,
3393
+ `operation '${name}' call capabilities`,
3394
+ ) ?? [],
3395
+ }
3396
+ : {}),
3397
+ ...(operation.capabilities.read
3398
+ ? {
3399
+ read: projectCapabilities(
3400
+ operation.capabilities.read,
3401
+ source.id,
3402
+ source.capabilities,
3403
+ `operation '${name}' read capabilities`,
3404
+ ) ?? [],
3405
+ }
3406
+ : {}),
3407
+ ...(operation.capabilities.cancel
3408
+ ? {
3409
+ cancel: projectCapabilities(
3410
+ operation.capabilities.cancel,
3411
+ source.id,
3412
+ source.capabilities,
3413
+ `operation '${name}' cancel capabilities`,
3414
+ ) ?? [],
3415
+ }
3416
+ : {}),
3417
+ ...(operation.capabilities.control
3418
+ ? {
3419
+ control: projectCapabilities(
3420
+ operation.capabilities.control,
3421
+ source.id,
3422
+ source.capabilities,
3423
+ `operation '${name}' control capabilities`,
3424
+ ) ?? [],
3425
+ }
3426
+ : {}),
3427
+ };
3428
+ }
3429
+ if (operation.signals) {
3430
+ emitted.signals = Object.fromEntries(
3431
+ Object.entries(operation.signals).map(([signalName, signal]) => [
3432
+ signalName,
3433
+ { input: { ...signal.input } },
3434
+ ]),
3435
+ );
3436
+ }
3437
+ if (operation.cancel !== undefined) {
3438
+ emitted.cancel = operation.cancel;
3439
+ }
3440
+ return [name, emitted];
3441
+ }),
3442
+ )
3443
+ : undefined;
3444
+
3445
+ const events = source.events
3446
+ ? Object.fromEntries(
3447
+ Object.entries(source.events).map(([name, event]) => {
3448
+ if (event.params && event.params.length > 0) {
3449
+ assertDataPointersExistAndAreTokenable(
3450
+ name,
3451
+ resolveSchemaRef(source.schemas, event.event, `event '${name}'`),
3452
+ event.params,
3453
+ );
3454
+ }
3455
+
3456
+ const emitted: ContractEvent = {
3457
+ version: event.version,
3458
+ subject: event.subject ??
3459
+ eventSubject(name, event.version, event.params),
3460
+ event: { ...event.event },
3461
+ };
3462
+ if (event.params && event.params.length > 0) {
3463
+ emitted.params = [...event.params];
3464
+ }
3465
+ if (event.capabilities?.publish || event.capabilities?.subscribe) {
3466
+ emitted.capabilities = {
3467
+ ...(event.capabilities.publish
3468
+ ? {
3469
+ publish: projectCapabilities(
3470
+ event.capabilities.publish,
3471
+ source.id,
3472
+ source.capabilities,
3473
+ `event '${name}' publish capabilities`,
3474
+ ) ?? [],
3475
+ }
3476
+ : {}),
3477
+ ...(event.capabilities.subscribe
3478
+ ? {
3479
+ subscribe: projectCapabilities(
3480
+ event.capabilities.subscribe,
3481
+ source.id,
3482
+ source.capabilities,
3483
+ `event '${name}' subscribe capabilities`,
3484
+ ) ?? [],
3485
+ }
3486
+ : {}),
3487
+ };
3488
+ }
3489
+
3490
+ return [name, emitted];
3491
+ }),
3492
+ )
3493
+ : undefined;
3494
+
3495
+ const feeds = source.feeds
3496
+ ? Object.fromEntries(
3497
+ Object.entries(source.feeds).map(([name, feed]) => {
3498
+ const emitted: ContractFeed = {
3499
+ version: feed.version,
3500
+ subject: feed.subject ?? feedSubject(name, feed.version),
3501
+ input: { ...feed.input },
3502
+ event: { ...feed.event },
3503
+ };
3504
+ if (feed.capabilities?.subscribe) {
3505
+ emitted.capabilities = {
3506
+ subscribe: projectCapabilities(
3507
+ feed.capabilities.subscribe,
3508
+ source.id,
3509
+ source.capabilities,
3510
+ `feed '${name}' subscribe capabilities`,
3511
+ ) ?? [],
3512
+ };
3513
+ }
3514
+ return [name, emitted];
3515
+ }),
3516
+ )
3517
+ : undefined;
3518
+
3519
+ const errors = source.errors
3520
+ ? Object.fromEntries(
3521
+ Object.entries(source.errors).map(([name, error]) => {
3522
+ const emitted: ContractErrorDecl = { type: error.type };
3523
+ const schemaRef = resolveErrorSchemaRef(source.schemas, name, error);
3524
+ if (schemaRef) {
3525
+ emitted.schema = { ...schemaRef };
3526
+ }
3527
+ return [name, emitted];
3528
+ }),
3529
+ )
3530
+ : undefined;
3531
+
3532
+ const jobs = emitJobs(source.jobs);
3533
+ const state = emitState(source.state);
3534
+ const resources = emitResources(source.resources);
3535
+ const uses = emitUses(source.uses);
3536
+
3537
+ return {
3538
+ format: CONTRACT_FORMAT_V1,
3539
+ id: source.id,
3540
+ displayName: source.displayName,
3541
+ description: source.description,
3542
+ kind: source.kind,
3543
+ ...(capabilities ? { capabilities } : {}),
3544
+ ...(source.schemas ? { schemas: cloneSchemas(source.schemas) } : {}),
3545
+ ...(source.exports
3546
+ ? { exports: cloneContractExports(source.exports) }
3547
+ : {}),
3548
+ ...(state ? { state } : {}),
3549
+ ...(uses ? { uses } : {}),
3550
+ ...(rpc ? { rpc } : {}),
3551
+ ...(operations ? { operations } : {}),
3552
+ ...(events ? { events } : {}),
3553
+ ...(feeds ? { feeds } : {}),
3554
+ ...(errors ? { errors } : {}),
3555
+ ...(jobs ? { jobs } : {}),
3556
+ ...(resources ? { resources } : {}),
3557
+ };
3558
+ }
3559
+
3560
+ function buildOwnedApi(source: TrellisContractSource): ApiShape {
3561
+ const localRuntimeErrors: Record<string, BuiltRuntimeErrorDesc> = {};
3562
+ for (const [name, errorDecl] of Object.entries(source.errors ?? {})) {
3563
+ const errorClass = getContractErrorRuntimeClass(errorDecl);
3564
+ if (!errorClass) {
3565
+ continue;
3566
+ }
3567
+
3568
+ const errorSchemaRef = resolveErrorSchemaRef(
3569
+ source.schemas,
3570
+ name,
3571
+ errorDecl,
3572
+ );
3573
+ localRuntimeErrors[name] = {
3574
+ type: errorDecl.type,
3575
+ ...(errorSchemaRef
3576
+ ? {
3577
+ schema: schema(
3578
+ resolveSchemaRef(
3579
+ source.schemas,
3580
+ errorSchemaRef,
3581
+ `error '${name}' schema`,
3582
+ ),
3583
+ ),
3584
+ }
3585
+ : {}),
3586
+ fromSerializable(data: SerializableErrorData) {
3587
+ if (!isSerializableErrorData(data)) {
3588
+ throw new Error(
3589
+ `Transport error '${errorDecl.type}' is missing base error fields`,
3590
+ );
3591
+ }
3592
+ return errorClass.fromSerializable(data);
3593
+ },
3594
+ };
3595
+ }
3596
+
3597
+ const rpc: Record<string, BuiltRpcDesc> = {};
3598
+ for (const [name, method] of Object.entries(source.rpc ?? {})) {
3599
+ rpc[name] = {
3600
+ subject: method.subject ?? rpcSubject(name, method.version),
3601
+ input: schema(
3602
+ resolveSchemaRef(source.schemas, method.input, `rpc '${name}' input`),
3603
+ ),
3604
+ output: schema(
3605
+ resolveSchemaRef(
3606
+ source.schemas,
3607
+ method.output,
3608
+ `rpc '${name}' output`,
3609
+ ),
3610
+ ),
3611
+ callerCapabilities: projectCapabilities(
3612
+ method.capabilities?.call,
3613
+ source.id,
3614
+ source.capabilities,
3615
+ `rpc '${name}' call capabilities`,
3616
+ ) ?? [],
3617
+ transfer: method.transfer ? { ...method.transfer } : undefined,
3618
+ authRequired: method.authRequired ?? true,
3619
+ errors: method.errors,
3620
+ declaredErrorTypes: method.errors?.map((errorName) =>
3621
+ source.errors?.[errorName]?.type ?? errorName
3622
+ ),
3623
+ runtimeErrors: method.errors?.flatMap((errorName) => {
3624
+ const runtimeError = localRuntimeErrors[errorName];
3625
+ return runtimeError ? [runtimeError] : [];
3626
+ }),
3627
+ };
3628
+ }
3629
+
3630
+ const operations = Object.fromEntries(
3631
+ Object.entries(source.operations ?? {}).map(([name, operation]) => [
3632
+ name,
3633
+ {
3634
+ subject: operation.subject ?? operationSubject(name, operation.version),
3635
+ input: schema(
3636
+ resolveSchemaRef(
3637
+ source.schemas,
3638
+ operation.input,
3639
+ `operation '${name}' input`,
3640
+ ),
3641
+ ),
3642
+ progress: operation.progress
3643
+ ? schema(
3644
+ resolveSchemaRef(
3645
+ source.schemas,
3646
+ operation.progress,
3647
+ `operation '${name}' progress`,
3648
+ ),
3649
+ )
3650
+ : undefined,
3651
+ output: operation.output
3652
+ ? schema(
3653
+ resolveSchemaRef(
3654
+ source.schemas,
3655
+ operation.output,
3656
+ `operation '${name}' output`,
3657
+ ),
3658
+ )
3659
+ : undefined,
3660
+ transfer: operation.transfer
3661
+ ? { ...operation.transfer, direction: "send" }
3662
+ : undefined,
3663
+ signals: operation.signals
3664
+ ? Object.fromEntries(
3665
+ Object.entries(operation.signals).map(([signalName, signal]) => [
3666
+ signalName,
3667
+ {
3668
+ input: schema(
3669
+ resolveSchemaRef(
3670
+ source.schemas,
3671
+ signal.input,
3672
+ `operation '${name}' signal '${signalName}' input`,
3673
+ ),
3674
+ ),
3675
+ },
3676
+ ]),
3677
+ )
3678
+ : undefined,
3679
+ callerCapabilities: projectCapabilities(
3680
+ operation.capabilities?.call,
3681
+ source.id,
3682
+ source.capabilities,
3683
+ `operation '${name}' call capabilities`,
3684
+ ) ?? [],
3685
+ readCapabilities: projectCapabilities(
3686
+ operation.capabilities?.read,
3687
+ source.id,
3688
+ source.capabilities,
3689
+ `operation '${name}' read capabilities`,
3690
+ ) ?? [],
3691
+ cancelCapabilities: projectCapabilities(
3692
+ operation.capabilities?.cancel,
3693
+ source.id,
3694
+ source.capabilities,
3695
+ `operation '${name}' cancel capabilities`,
3696
+ ) ?? [],
3697
+ controlCapabilities: projectCapabilities(
3698
+ operation.capabilities?.control,
3699
+ source.id,
3700
+ source.capabilities,
3701
+ `operation '${name}' control capabilities`,
3702
+ ) ?? [],
3703
+ cancel: operation.cancel,
3704
+ },
3705
+ ]),
3706
+ ) as Record<string, OperationDesc>;
3707
+
3708
+ const events = Object.fromEntries(
3709
+ Object.entries(source.events ?? {}).map(([name, event]) => {
3710
+ if (event.params && event.params.length > 0) {
3711
+ assertDataPointersExistAndAreTokenable(
3712
+ name,
3713
+ resolveSchemaRef(source.schemas, event.event, `event '${name}'`),
3714
+ event.params,
3715
+ );
3716
+ }
3717
+
3718
+ return [
3719
+ name,
3720
+ {
3721
+ subject: event.subject ??
3722
+ eventSubject(name, event.version, event.params),
3723
+ params: event.params,
3724
+ event: schema(
3725
+ resolveSchemaRef(source.schemas, event.event, `event '${name}'`),
3726
+ ),
3727
+ publishCapabilities: projectCapabilities(
3728
+ event.capabilities?.publish,
3729
+ source.id,
3730
+ source.capabilities,
3731
+ `event '${name}' publish capabilities`,
3732
+ ) ?? [],
3733
+ subscribeCapabilities: projectCapabilities(
3734
+ event.capabilities?.subscribe,
3735
+ source.id,
3736
+ source.capabilities,
3737
+ `event '${name}' subscribe capabilities`,
3738
+ ) ?? [],
3739
+ },
3740
+ ];
3741
+ }),
3742
+ ) as Record<string, EventDesc>;
3743
+
3744
+ const feeds = Object.fromEntries(
3745
+ Object.entries(source.feeds ?? {}).map(([name, feed]) => [
3746
+ name,
3747
+ {
3748
+ subject: feed.subject ?? feedSubject(name, feed.version),
3749
+ input: schema(
3750
+ resolveSchemaRef(source.schemas, feed.input, `feed '${name}' input`),
3751
+ ),
3752
+ event: schema(
3753
+ resolveSchemaRef(source.schemas, feed.event, `feed '${name}' event`),
3754
+ ),
3755
+ subscribeCapabilities: projectCapabilities(
3756
+ feed.capabilities?.subscribe,
3757
+ source.id,
3758
+ source.capabilities,
3759
+ `feed '${name}' subscribe capabilities`,
3760
+ ) ?? [],
3761
+ },
3762
+ ]),
3763
+ ) as Record<string, FeedDesc>;
3764
+
3765
+ return { rpc, operations, events, feeds, subjects: {} } as ApiShape;
3766
+ }
3767
+
3768
+ function mergeRecord(
3769
+ kind: "rpc" | "operations" | "events" | "feeds" | "subjects",
3770
+ out: Record<string, unknown>,
3771
+ next: Record<string, unknown>,
3772
+ ) {
3773
+ for (const [key, value] of Object.entries(next)) {
3774
+ if (Object.hasOwn(out, key)) {
3775
+ throw new Error(
3776
+ `Duplicate ${kind} key '${key}' while deriving contract API`,
3777
+ );
3778
+ }
3779
+ out[key] = value;
3780
+ }
3781
+ }
3782
+
3783
+ function assertSelectedKeysExist(
3784
+ contractId: string,
3785
+ kind: "rpc" | "operations" | "events" | "feeds" | "subjects",
3786
+ keys: readonly string[] | undefined,
3787
+ api: Record<string, unknown>,
3788
+ ) {
3789
+ if (!keys) {
3790
+ return;
3791
+ }
3792
+
3793
+ for (const key of keys) {
3794
+ if (!Object.hasOwn(api, key)) {
3795
+ throw new Error(
3796
+ `Contract '${contractId}' does not expose ${kind} key '${key}'`,
3797
+ );
3798
+ }
3799
+ }
3800
+ }
3801
+
3802
+ function assertValidUseSpec<TApi extends TrellisApiLike>(
3803
+ contractId: string,
3804
+ spec: UseSpec<TApi>,
3805
+ api: TApi,
3806
+ ) {
3807
+ assertSelectedKeysExist(contractId, "rpc", spec.rpc?.call, api.rpc);
3808
+ assertSelectedKeysExist(
3809
+ contractId,
3810
+ "operations",
3811
+ spec.operations?.call,
3812
+ api.operations,
3813
+ );
3814
+ assertSelectedKeysExist(
3815
+ contractId,
3816
+ "events",
3817
+ spec.events?.publish,
3818
+ api.events,
3819
+ );
3820
+ assertSelectedKeysExist(
3821
+ contractId,
3822
+ "events",
3823
+ spec.events?.subscribe,
3824
+ api.events,
3825
+ );
3826
+ assertSelectedKeysExist(
3827
+ contractId,
3828
+ "feeds",
3829
+ spec.feeds?.subscribe,
3830
+ api.feeds ?? {},
3831
+ );
3832
+ }
3833
+
3834
+ function attachContractModuleMetadata<
3835
+ TValue extends object,
3836
+ TContractModule,
3837
+ >(
3838
+ value: TValue,
3839
+ contractModule: TContractModule,
3840
+ ): TValue & ContractModuleMarker<TContractModule> {
3841
+ Object.defineProperty(value, CONTRACT_MODULE_METADATA, {
3842
+ value: contractModule,
3843
+ enumerable: false,
3844
+ });
3845
+ return value as TValue & ContractModuleMarker<TContractModule>;
3846
+ }
3847
+
3848
+ function attachContractErrorRuntimeMetadata<
3849
+ TValue extends object,
3850
+ TClass extends RpcErrorClass,
3851
+ >(
3852
+ value: TValue,
3853
+ errorClass: TClass,
3854
+ ): TValue & ContractErrorRuntimeMarker<TClass> {
3855
+ Object.defineProperty(value, CONTRACT_ERROR_RUNTIME_METADATA, {
3856
+ value: errorClass,
3857
+ enumerable: false,
3858
+ });
3859
+ return value as TValue & ContractErrorRuntimeMarker<TClass>;
3860
+ }
3861
+
3862
+ function getContractErrorRuntimeClass(
3863
+ errorDecl: ContractSourceErrorDecl,
3864
+ ): ErrorClass | undefined {
3865
+ const value = Object.getOwnPropertyDescriptor(
3866
+ errorDecl,
3867
+ CONTRACT_ERROR_RUNTIME_METADATA,
3868
+ )?.value;
3869
+ if (isErrorClass(value)) {
3870
+ return value;
3871
+ }
3872
+ return undefined;
3873
+ }
3874
+
3875
+ function resolveErrorSchemaRef(
3876
+ schemas: ContractSourceSchemas | undefined,
3877
+ errorName: string,
3878
+ errorDecl: ContractSourceErrorDecl,
3879
+ ): ContractSchemaRef | undefined {
3880
+ if (errorDecl.schema) {
3881
+ return errorDecl.schema;
3882
+ }
3883
+
3884
+ const runtimeSchema = getErrorRuntimeSchema(errorDecl);
3885
+ if (!runtimeSchema) {
3886
+ return undefined;
3887
+ }
3888
+
3889
+ const schemaName = findMatchingSchemaName(schemas, runtimeSchema);
3890
+ if (schemaName) {
3891
+ return { schema: schemaName };
3892
+ }
3893
+
3894
+ throw new Error(
3895
+ `error '${errorName}' schema must be declared in contract.schemas`,
3896
+ );
3897
+ }
3898
+
3899
+ /**
3900
+ * Define a transportable Trellis error class from a payload-object schema.
3901
+ *
3902
+ * The returned value is a real runtime error class that carries the wire schema
3903
+ * and reconstruction logic needed by `defineServiceContract(...)`.
3904
+ */
3905
+ export function defineError<
3906
+ const TType extends string,
3907
+ const TFields extends TProperties,
3908
+ >(
3909
+ options: DefineErrorOptions<TType, TFields>,
3910
+ ): DefinedErrorClass<TType, TFields> {
3911
+ assertNoReservedDefinedErrorFieldNames(options.fields);
3912
+
3913
+ const errorSchema = createDefinedErrorSchema(options.type, options.fields);
3914
+ const fieldNames = definedErrorPayloadFieldNames(options.fields);
3915
+
3916
+ type TPayload = DefinedErrorPayload<TFields>;
3917
+ type TData = DefinedErrorData<TType, TFields>;
3918
+ type TInit = DefinedErrorInit<TFields>;
3919
+
3920
+ class DefinedErrorImpl extends TrellisError<SerializableErrorData>
3921
+ implements DefinedErrorPayloadCarrier<TPayload> {
3922
+ static readonly type = options.type;
3923
+ static readonly schema = errorSchema;
3924
+ override readonly name = options.type;
3925
+ [DEFINED_ERROR_PAYLOAD]: Readonly<TPayload>;
3926
+
3927
+ constructor(payload: TInit) {
3928
+ const customPayload = pickDefinedErrorPayload(fieldNames, payload);
3929
+ const message = typeof options.message === "function"
3930
+ ? options.message(customPayload)
3931
+ : options.message;
3932
+ super(message, definedErrorBaseOptions(payload));
3933
+ this[DEFINED_ERROR_PAYLOAD] = customPayload;
3934
+ Object.assign(this, customPayload);
3935
+ }
3936
+
3937
+ static fromSerializable(data: TData): DefinedErrorInstance<TType, TFields> {
3938
+ const customPayload = pickDefinedErrorPayload(fieldNames, data);
3939
+ const ErrorCtor = DefinedErrorImpl as new (
3940
+ payload: object,
3941
+ ) =>
3942
+ & TrellisError<SerializableErrorData>
3943
+ & DefinedErrorPayloadCarrier<Record<string, unknown>>;
3944
+ const error = new ErrorCtor({
3945
+ ...customPayload,
3946
+ id: data.id,
3947
+ context: data.context,
3948
+ traceId: data.traceId,
3949
+ });
3950
+ error[DEFINED_ERROR_PAYLOAD] = customPayload;
3951
+ return Object.assign(error, customPayload) as DefinedErrorInstance<
3952
+ TType,
3953
+ TFields
3954
+ >;
3955
+ }
3956
+
3957
+ override toSerializable(): SerializableErrorData {
3958
+ return {
3959
+ ...this.baseSerializable(),
3960
+ type: this.name,
3961
+ ...this[DEFINED_ERROR_PAYLOAD],
3962
+ };
3963
+ }
3964
+ }
3965
+
3966
+ // @ts-expect-error TypeScript cannot model the dynamically assigned payload
3967
+ // fields on the generated class instance constructor return type.
3968
+ return DefinedErrorImpl;
3969
+ }
3970
+
3971
+ function createUseHelper<
3972
+ TContractId extends string,
3973
+ TOwnedApi extends TrellisApiLike,
3974
+ TUsedApi extends ApiShape,
3975
+ TTrellisApi extends ApiShape,
3976
+ >(
3977
+ getContractModule: () => ContractModule<
3978
+ TContractId,
3979
+ TOwnedApi,
3980
+ TUsedApi,
3981
+ TTrellisApi
3982
+ >,
3983
+ ) {
3984
+ return ((spec) => {
3985
+ const contractModule = getContractModule();
3986
+ assertValidUseSpec(
3987
+ contractModule.CONTRACT_ID,
3988
+ spec,
3989
+ contractModule.API.owned,
3990
+ );
3991
+
3992
+ const dependencyUse = {
3993
+ contract: contractModule.CONTRACT_ID,
3994
+ ...(spec.rpc?.call ? { rpc: { call: [...spec.rpc.call] } } : {}),
3995
+ ...(spec.operations?.call
3996
+ ? { operations: { call: [...spec.operations.call] } }
3997
+ : {}),
3998
+ ...((spec.events?.publish || spec.events?.subscribe)
3999
+ ? {
4000
+ events: {
4001
+ ...(spec.events.publish
4002
+ ? { publish: [...spec.events.publish] }
4003
+ : {}),
4004
+ ...(spec.events.subscribe
4005
+ ? { subscribe: [...spec.events.subscribe] }
4006
+ : {}),
4007
+ },
4008
+ }
4009
+ : {}),
4010
+ ...(spec.feeds?.subscribe
4011
+ ? { feeds: { subscribe: [...spec.feeds.subscribe] } }
4012
+ : {}),
4013
+ };
4014
+
4015
+ return attachContractModuleMetadata(
4016
+ dependencyUse,
4017
+ contractModule,
4018
+ );
4019
+ }) as ContractUseFn<TContractId, TOwnedApi>;
4020
+ }
4021
+
4022
+ function getContractModuleFromUse(
4023
+ alias: string,
4024
+ useValue: ContractSourceUse | AuthorContractDependencyUse,
4025
+ ): ContractModule<string, TrellisApiLike, TrellisApiLike, TrellisApiLike> {
4026
+ const contractModule = Object.getOwnPropertyDescriptor(
4027
+ useValue,
4028
+ CONTRACT_MODULE_METADATA,
4029
+ )?.value as
4030
+ | ContractModule<
4031
+ string,
4032
+ TrellisApiLike,
4033
+ TrellisApiLike,
4034
+ TrellisApiLike
4035
+ >
4036
+ | undefined;
4037
+ if (!contractModule) {
4038
+ throw new Error(
4039
+ `Contract use '${alias}' must be created with contractModule.use(...) from @qlever-llc/trellis/contracts`,
4040
+ );
4041
+ }
4042
+ return contractModule;
4043
+ }
4044
+
4045
+ function normalizeUseEntries(
4046
+ uses: AuthorContractUsesFlat | undefined,
4047
+ ): {
4048
+ manifestUses: Record<string, ContractSourceUse> | undefined;
4049
+ usedApi: TrellisApiLike;
4050
+ } {
4051
+ if (!uses) {
4052
+ return {
4053
+ manifestUses: undefined,
4054
+ usedApi: { rpc: {}, operations: {}, events: {}, feeds: {}, subjects: {} },
4055
+ };
4056
+ }
4057
+
4058
+ const manifestUses: Record<string, ContractSourceUse> = {};
4059
+ const usedApi: TrellisApiLike = {
4060
+ rpc: {},
4061
+ operations: {},
4062
+ events: {},
4063
+ feeds: {},
4064
+ subjects: {},
4065
+ };
4066
+
4067
+ for (const [alias, useValue] of Object.entries(uses)) {
4068
+ const contractModule = getContractModuleFromUse(alias, useValue);
4069
+ const rpcCall = useValue.rpc?.call as readonly string[] | undefined;
4070
+ const operationsCall = useValue.operations?.call as
4071
+ | readonly string[]
4072
+ | undefined;
4073
+ const eventsPublish = useValue.events?.publish as
4074
+ | readonly string[]
4075
+ | undefined;
4076
+ const eventsSubscribe = useValue.events?.subscribe as
4077
+ | readonly string[]
4078
+ | undefined;
4079
+ const feedsSubscribe = useValue.feeds?.subscribe as
4080
+ | readonly string[]
4081
+ | undefined;
4082
+ if (useValue.contract !== contractModule.CONTRACT_ID) {
4083
+ throw new Error(
4084
+ `Contract use '${alias}' references '${useValue.contract}' but module id is '${contractModule.CONTRACT_ID}'`,
4085
+ );
4086
+ }
4087
+
4088
+ assertValidUseSpec(
4089
+ contractModule.CONTRACT_ID,
4090
+ {
4091
+ ...(rpcCall ? { rpc: { call: rpcCall } } : {}),
4092
+ ...(operationsCall ? { operations: { call: operationsCall } } : {}),
4093
+ ...((eventsPublish || eventsSubscribe)
4094
+ ? {
4095
+ events: {
4096
+ ...(eventsPublish ? { publish: eventsPublish } : {}),
4097
+ ...(eventsSubscribe ? { subscribe: eventsSubscribe } : {}),
4098
+ },
4099
+ }
4100
+ : {}),
4101
+ ...(feedsSubscribe ? { feeds: { subscribe: feedsSubscribe } } : {}),
4102
+ },
4103
+ contractModule.API.owned,
4104
+ );
4105
+
4106
+ manifestUses[alias] = {
4107
+ contract: contractModule.CONTRACT_ID,
4108
+ ...(rpcCall ? { rpc: { call: [...rpcCall] } } : {}),
4109
+ ...(operationsCall ? { operations: { call: [...operationsCall] } } : {}),
4110
+ ...((eventsPublish || eventsSubscribe)
4111
+ ? {
4112
+ events: {
4113
+ ...(eventsPublish ? { publish: [...eventsPublish] } : {}),
4114
+ ...(eventsSubscribe ? { subscribe: [...eventsSubscribe] } : {}),
4115
+ },
4116
+ }
4117
+ : {}),
4118
+ ...(feedsSubscribe ? { feeds: { subscribe: [...feedsSubscribe] } } : {}),
4119
+ };
4120
+
4121
+ const rpcKeys = selectedKeys(
4122
+ rpcCall,
4123
+ );
4124
+ if (rpcKeys.length > 0) {
4125
+ mergeRecord(
4126
+ "rpc",
4127
+ usedApi.rpc,
4128
+ Object.fromEntries(
4129
+ rpcKeys.map((key) => [key, contractModule.API.owned.rpc[key]]),
4130
+ ),
4131
+ );
4132
+ }
4133
+
4134
+ const operationKeys = selectedKeys(
4135
+ operationsCall,
4136
+ );
4137
+ if (operationKeys.length > 0) {
4138
+ mergeRecord(
4139
+ "operations",
4140
+ usedApi.operations,
4141
+ Object.fromEntries(
4142
+ operationKeys.map((
4143
+ key,
4144
+ ) => [key, contractModule.API.owned.operations[key]]),
4145
+ ),
4146
+ );
4147
+ }
4148
+
4149
+ const eventKeys = new Set([
4150
+ ...selectedKeys(eventsPublish),
4151
+ ...selectedKeys(eventsSubscribe),
4152
+ ]);
4153
+ if (eventKeys.size > 0) {
4154
+ mergeRecord(
4155
+ "events",
4156
+ usedApi.events,
4157
+ Object.fromEntries(
4158
+ [...eventKeys].map((
4159
+ key,
4160
+ ) => [key, contractModule.API.owned.events[key]]),
4161
+ ),
4162
+ );
4163
+ }
4164
+
4165
+ const feedKeys = selectedKeys(feedsSubscribe);
4166
+ if (feedKeys.length > 0) {
4167
+ mergeRecord(
4168
+ "feeds",
4169
+ usedApi.feeds ?? {},
4170
+ Object.fromEntries(
4171
+ feedKeys.map((key) => [key, contractModule.API.owned.feeds?.[key]]),
4172
+ ),
4173
+ );
4174
+ }
4175
+ }
4176
+
4177
+ return { manifestUses, usedApi };
4178
+ }
4179
+
4180
+ function normalizeUses(
4181
+ uses: AuthorContractUses | undefined,
4182
+ ): {
4183
+ manifestUses: ContractSourceUses | undefined;
4184
+ usedApi: TrellisApiLike;
4185
+ } {
4186
+ if (!uses) {
4187
+ return {
4188
+ manifestUses: undefined,
4189
+ usedApi: emptyApi(),
4190
+ };
4191
+ }
4192
+
4193
+ const required = normalizeUseEntries(uses.required);
4194
+ const optional = normalizeUseEntries(
4195
+ omitRequiredUseAliases(uses.optional, uses.required),
4196
+ );
4197
+ const usedApi = emptyApi();
4198
+ mergeUseIntoApi(usedApi, required.usedApi);
4199
+ mergeUseIntoApi(usedApi, optional.usedApi);
4200
+
4201
+ return {
4202
+ manifestUses: {
4203
+ ...(required.manifestUses ? { required: required.manifestUses } : {}),
4204
+ ...(optional.manifestUses ? { optional: optional.manifestUses } : {}),
4205
+ },
4206
+ usedApi,
4207
+ };
4208
+ }
4209
+
4210
+ type NormalizedUse = {
4211
+ manifestUse: ContractSourceUse;
4212
+ api: TrellisApiLike;
4213
+ };
4214
+
4215
+ function emptyApi(): TrellisApiLike {
4216
+ return { rpc: {}, operations: {}, events: {}, feeds: {}, subjects: {} };
4217
+ }
4218
+
4219
+ function addUniqueStrings(target: string[], values: readonly string[]): void {
4220
+ for (const value of values) {
4221
+ if (!target.includes(value)) {
4222
+ target.push(value);
4223
+ }
4224
+ }
4225
+ }
4226
+
4227
+ function mergeUseIntoManifest(
4228
+ manifestUses: Record<string, ContractSourceUse>,
4229
+ alias: string,
4230
+ use: ContractSourceUse,
4231
+ ): void {
4232
+ const existing = manifestUses[alias];
4233
+ if (!existing) {
4234
+ manifestUses[alias] = use;
4235
+ return;
4236
+ }
4237
+
4238
+ if (existing.contract !== use.contract) {
4239
+ throw new Error(
4240
+ `Contract use '${alias}' references both '${existing.contract}' and '${use.contract}'`,
4241
+ );
4242
+ }
4243
+
4244
+ const rpcCall = [...(existing.rpc?.call ?? [])];
4245
+ addUniqueStrings(rpcCall, use.rpc?.call ?? []);
4246
+ const operationsCall = [...(existing.operations?.call ?? [])];
4247
+ addUniqueStrings(operationsCall, use.operations?.call ?? []);
4248
+ const eventsPublish = [...(existing.events?.publish ?? [])];
4249
+ addUniqueStrings(eventsPublish, use.events?.publish ?? []);
4250
+ const eventsSubscribe = [...(existing.events?.subscribe ?? [])];
4251
+ addUniqueStrings(eventsSubscribe, use.events?.subscribe ?? []);
4252
+ const feedsSubscribe = [...(existing.feeds?.subscribe ?? [])];
4253
+ addUniqueStrings(feedsSubscribe, use.feeds?.subscribe ?? []);
4254
+ manifestUses[alias] = {
4255
+ contract: existing.contract,
4256
+ ...(rpcCall.length > 0 ? { rpc: { call: rpcCall } } : {}),
4257
+ ...(operationsCall.length > 0
4258
+ ? { operations: { call: operationsCall } }
4259
+ : {}),
4260
+ ...((eventsPublish.length > 0 || eventsSubscribe.length > 0)
4261
+ ? {
4262
+ events: {
4263
+ ...(eventsPublish.length > 0 ? { publish: eventsPublish } : {}),
4264
+ ...(eventsSubscribe.length > 0 ? { subscribe: eventsSubscribe } : {}),
4265
+ },
4266
+ }
4267
+ : {}),
4268
+ ...(feedsSubscribe.length > 0
4269
+ ? { feeds: { subscribe: feedsSubscribe } }
4270
+ : {}),
4271
+ };
4272
+ }
4273
+
4274
+ function mergeApiAllowDuplicateSubject(
4275
+ kind: "rpc" | "operations" | "events" | "feeds" | "subjects",
4276
+ out: Record<string, unknown>,
4277
+ next: Record<string, unknown>,
4278
+ ): void {
4279
+ for (const [key, value] of Object.entries(next)) {
4280
+ const existing = out[key];
4281
+ if (existing !== undefined) {
4282
+ const existingSubject = typeof existing === "object" && existing !== null
4283
+ ? (existing as { subject?: unknown }).subject
4284
+ : undefined;
4285
+ const nextSubject = typeof value === "object" && value !== null
4286
+ ? (value as { subject?: unknown }).subject
4287
+ : undefined;
4288
+ if (
4289
+ typeof existingSubject === "string" && existingSubject === nextSubject
4290
+ ) {
4291
+ continue;
4292
+ }
4293
+ throw new Error(
4294
+ `Duplicate ${kind} key '${key}' while deriving contract API`,
4295
+ );
4296
+ }
4297
+ out[key] = value;
4298
+ }
4299
+ }
4300
+
4301
+ function mergeUseIntoApi(target: TrellisApiLike, api: TrellisApiLike): void {
4302
+ mergeApiAllowDuplicateSubject("rpc", target.rpc, api.rpc);
4303
+ mergeApiAllowDuplicateSubject(
4304
+ "operations",
4305
+ target.operations,
4306
+ api.operations,
4307
+ );
4308
+ mergeApiAllowDuplicateSubject("events", target.events, api.events);
4309
+ mergeApiAllowDuplicateSubject("feeds", target.feeds ?? {}, api.feeds ?? {});
4310
+ mergeApiAllowDuplicateSubject("subjects", target.subjects, api.subjects);
4311
+ }
4312
+
4313
+ function baselineUse(
4314
+ contract: string,
4315
+ use: Omit<ContractSourceUse, "contract">,
4316
+ api: TrellisApiLike,
4317
+ ): NormalizedUse {
4318
+ return { manifestUse: { contract, ...use }, api };
4319
+ }
4320
+
4321
+ function deriveImplicitTrellisUses(source: DefineContractSource): Record<
4322
+ string,
4323
+ NormalizedUse
4324
+ > {
4325
+ const uses: Record<string, NormalizedUse> = {};
4326
+
4327
+ if (
4328
+ source.kind === "app" || source.kind === "agent" || source.kind === "device"
4329
+ ) {
4330
+ uses.auth = baselineUse(
4331
+ TRELLIS_AUTH_CONTRACT_ID,
4332
+ { rpc: { call: [...BASELINE_AUTH_RPC_CALL] } },
4333
+ BASELINE_AUTH_API,
4334
+ );
4335
+ }
4336
+
4337
+ if (source.state) {
4338
+ uses.state = baselineUse(
4339
+ TRELLIS_STATE_CONTRACT_ID,
4340
+ { rpc: { call: [...BASELINE_STATE_RPC_CALL] } },
4341
+ BASELINE_STATE_API,
4342
+ );
4343
+ }
4344
+
4345
+ if (
4346
+ (source.kind === "service" || source.kind === "device") &&
4347
+ source.id !== TRELLIS_HEALTH_CONTRACT_ID
4348
+ ) {
4349
+ uses.health = baselineUse(
4350
+ TRELLIS_HEALTH_CONTRACT_ID,
4351
+ { events: { publish: [...BASELINE_HEALTH_EVENTS_PUBLISH] } },
4352
+ BASELINE_HEALTH_API,
4353
+ );
4354
+ }
4355
+
4356
+ return uses;
4357
+ }
4358
+
4359
+ function normalizeContractUses(source: DefineContractSource): {
4360
+ manifestUses: ContractSourceUses | undefined;
4361
+ usedApi: TrellisApiLike;
4362
+ } {
4363
+ const explicit = normalizeUses(source.uses);
4364
+ const usedApi = emptyApi();
4365
+ mergeUseIntoApi(usedApi, explicit.usedApi);
4366
+
4367
+ const required: Record<string, ContractSourceUse> = {
4368
+ ...(explicit.manifestUses?.required ?? {}),
4369
+ };
4370
+ const optional = explicit.manifestUses?.optional
4371
+ ? { ...explicit.manifestUses.optional }
4372
+ : undefined;
4373
+
4374
+ for (
4375
+ const [alias, use] of Object.entries(deriveImplicitTrellisUses(source))
4376
+ ) {
4377
+ mergeUseIntoManifest(required, alias, use.manifestUse);
4378
+ mergeUseIntoApi(usedApi, use.api);
4379
+ }
4380
+
4381
+ return {
4382
+ manifestUses: Object.keys(required).length > 0 ||
4383
+ (optional && Object.keys(optional).length > 0)
4384
+ ? {
4385
+ ...(Object.keys(required).length > 0 ? { required } : {}),
4386
+ ...(optional && Object.keys(optional).length > 0 ? { optional } : {}),
4387
+ }
4388
+ : undefined,
4389
+ usedApi,
4390
+ };
4391
+ }
4392
+
4393
+ function selectedKeys(keys: readonly string[] | undefined): readonly string[] {
4394
+ return keys ?? [];
4395
+ }
4396
+
4397
+ function mergeApiSection(
4398
+ kind: keyof TrellisApiLike,
4399
+ usedEntries: Record<string, unknown>,
4400
+ ownedEntries: Record<string, unknown>,
4401
+ ): Record<string, unknown> {
4402
+ const merged: Record<string, unknown> = {};
4403
+ mergeRecord(kind, merged, usedEntries);
4404
+ mergeRecord(kind, merged, ownedEntries);
4405
+ return merged;
4406
+ }
4407
+
4408
+ function mergeDerivedApis<
4409
+ TOwnedApi extends TrellisApiLike,
4410
+ TUsedApi extends TrellisApiLike,
4411
+ >(
4412
+ ownedApi: TOwnedApi,
4413
+ usedApi: TUsedApi,
4414
+ ): MergeApis<TOwnedApi, TUsedApi> {
4415
+ return {
4416
+ rpc: mergeApiSection("rpc", usedApi.rpc, ownedApi.rpc) as MergeApis<
4417
+ TOwnedApi,
4418
+ TUsedApi
4419
+ >["rpc"],
4420
+ operations: mergeApiSection(
4421
+ "operations",
4422
+ usedApi.operations,
4423
+ ownedApi.operations,
4424
+ ) as MergeApis<TOwnedApi, TUsedApi>["operations"],
4425
+ events: mergeApiSection(
4426
+ "events",
4427
+ usedApi.events,
4428
+ ownedApi.events,
4429
+ ) as MergeApis<TOwnedApi, TUsedApi>["events"],
4430
+ feeds: mergeApiSection(
4431
+ "feeds",
4432
+ usedApi.feeds ?? {},
4433
+ ownedApi.feeds ?? {},
4434
+ ) as MergeApis<TOwnedApi, TUsedApi>["feeds"],
4435
+ subjects: mergeApiSection(
4436
+ "subjects",
4437
+ usedApi.subjects,
4438
+ ownedApi.subjects,
4439
+ ) as MergeApis<TOwnedApi, TUsedApi>["subjects"],
4440
+ };
4441
+ }
4442
+
4443
+ function defineContract(
4444
+ registry: AnyDefineContractRegistry,
4445
+ build: (
4446
+ ref: ContractRefBuilder,
4447
+ ) => Omit<DefineContractSource, "schemas" | "errors">,
4448
+ ): DefinedContract<TrellisApiLike, ApiShape, ApiShape, string>;
4449
+ function defineContract(
4450
+ registry: AnyDefineContractRegistry,
4451
+ build: (
4452
+ ref: ContractRefBuilder,
4453
+ ) => Omit<DefineContractSource, "schemas" | "errors">,
4454
+ ): DefinedContract<
4455
+ TrellisApiLike,
4456
+ ApiShape,
4457
+ ApiShape,
4458
+ string
4459
+ > {
4460
+ assertRegistryDoesNotDeclareExports(registry);
4461
+ assertRegistryDoesNotDeclareCapabilities(registry);
4462
+ const errorClasses = getErrorClassRegistry(registry.errors);
4463
+ const normalizedErrors = normalizeErrorRegistry(registry.errors);
4464
+ const body = build(createContractRefBuilder({
4465
+ ...(registry.schemas ? { schemas: registry.schemas } : {}),
4466
+ ...(errorClasses ? { errors: errorClasses } : {}),
4467
+ }));
4468
+ const materializedSchemas = materializeErrorSchemas(
4469
+ registry.schemas,
4470
+ normalizedErrors,
4471
+ );
4472
+ const source: DefineContractSource = {
4473
+ ...body,
4474
+ ...(materializedSchemas ? { schemas: materializedSchemas } : {}),
4475
+ ...(normalizedErrors ? { errors: normalizedErrors } : {}),
4476
+ };
4477
+ assertExportedSchemasExist(source.schemas, source.exports);
4478
+
4479
+ const { manifestUses, usedApi } = normalizeContractUses(source);
4480
+ const emittedSource: TrellisContractSource = {
4481
+ id: source.id,
4482
+ displayName: source.displayName,
4483
+ description: source.description,
4484
+ kind: source.kind,
4485
+ ...(source.capabilities ? { capabilities: source.capabilities } : {}),
4486
+ ...(source.schemas ? { schemas: source.schemas } : {}),
4487
+ ...(source.exports ? { exports: source.exports } : {}),
4488
+ ...(source.state ? { state: source.state } : {}),
4489
+ ...(manifestUses ? { uses: manifestUses } : {}),
4490
+ ...(source.rpc ? { rpc: source.rpc } : {}),
4491
+ ...(source.operations ? { operations: source.operations } : {}),
4492
+ ...(source.events ? { events: source.events } : {}),
4493
+ ...(source.feeds ? { feeds: source.feeds } : {}),
4494
+ ...(source.errors ? { errors: source.errors } : {}),
4495
+ ...(source.jobs ? { jobs: source.jobs } : {}),
4496
+ ...(source.resources ? { resources: source.resources } : {}),
4497
+ };
4498
+
4499
+ const ownedApi = buildOwnedApi(emittedSource);
4500
+ const trellisApi = mergeDerivedApis(
4501
+ ownedApi as ApiShape & TrellisApiLike,
4502
+ usedApi as ApiShape & TrellisApiLike,
4503
+ ) as ApiShape;
4504
+ const CONTRACT = emitContract(emittedSource);
4505
+ const CONTRACT_DIGEST = digestContractManifest(CONTRACT);
4506
+
4507
+ type ConcreteDefinedContract = DefinedContract<
4508
+ TrellisApiLike,
4509
+ ApiShape,
4510
+ ApiShape,
4511
+ string
4512
+ >;
4513
+
4514
+ let contract!: ConcreteDefinedContract;
4515
+ contract = {
4516
+ CONTRACT_ID: source.id,
4517
+ CONTRACT,
4518
+ CONTRACT_DIGEST,
4519
+ API: {
4520
+ owned: ownedApi as TrellisApiLike,
4521
+ used: usedApi as ApiShape,
4522
+ trellis: trellisApi,
4523
+ },
4524
+ use: createUseHelper(
4525
+ () => contract,
4526
+ ),
4527
+ [CONTRACT_JOBS_METADATA]: buildContractJobsMetadata(source.jobs),
4528
+ [CONTRACT_KV_METADATA]: buildContractKvMetadata(
4529
+ source.resources,
4530
+ source.schemas,
4531
+ ),
4532
+ [CONTRACT_STATE_METADATA]: buildContractStateMetadata(
4533
+ source.state,
4534
+ source.schemas,
4535
+ ),
4536
+ };
4537
+
4538
+ return contract;
4539
+ }
4540
+
4541
+ export function defineServiceContract<
4542
+ const TErrors extends Readonly<Record<string, unknown>> | undefined,
4543
+ const TRegistry extends DefineContractRegistry<
4544
+ Readonly<Record<string, TSchema>> | undefined,
4545
+ TErrors
4546
+ >,
4547
+ const TCapabilities extends ContractCapabilities | undefined,
4548
+ const TUses extends AuthorContractUses | undefined,
4549
+ const TRpc extends
4550
+ | Readonly<
4551
+ Record<
4552
+ string,
4553
+ ContractSourceRpcMethod<
4554
+ SchemaNameOf<RegistrySchemas<TRegistry>>,
4555
+ ErrorNameOf<RegistryErrors<TRegistry>>,
4556
+ CapabilityRef<TCapabilities>
4557
+ >
4558
+ >
4559
+ >
4560
+ | undefined,
4561
+ const TOperations extends
4562
+ | Readonly<
4563
+ Record<
4564
+ string,
4565
+ ContractSourceOperation<
4566
+ SchemaNameOf<RegistrySchemas<TRegistry>>,
4567
+ CapabilityRef<TCapabilities>
4568
+ >
4569
+ >
4570
+ >
4571
+ | undefined,
4572
+ const TEvents extends
4573
+ | Readonly<
4574
+ Record<
4575
+ string,
4576
+ ContractSourceEvent<
4577
+ SchemaNameOf<RegistrySchemas<TRegistry>>,
4578
+ CapabilityRef<TCapabilities>
4579
+ >
4580
+ >
4581
+ >
4582
+ | undefined,
4583
+ const TBody extends ServiceContractBodyInput<
4584
+ TCapabilities,
4585
+ RegistrySchemas<TRegistry>,
4586
+ TUses,
4587
+ RegistryErrors<TRegistry>,
4588
+ TRpc,
4589
+ TOperations,
4590
+ TEvents
4591
+ >,
4592
+ >(
4593
+ registry: TRegistry & { capabilities?: never; exports?: never },
4594
+ build: (
4595
+ ref: ContractRefBuilder<
4596
+ RegistrySchemas<TRegistry>,
4597
+ RegistryErrors<TRegistry>
4598
+ >,
4599
+ ) => TBody,
4600
+ ): DefinedContract<
4601
+ OwnedApiFromSource<
4602
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4603
+ >,
4604
+ UsedApiFromSource<BuiltContractSource<TRegistry, WithKind<TBody, "service">>>,
4605
+ MergeApis<
4606
+ OwnedApiFromSource<
4607
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4608
+ >,
4609
+ UsedApiFromSource<
4610
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4611
+ >
4612
+ >,
4613
+ TBody["id"],
4614
+ ProjectedJobs<
4615
+ JobsFromSource<BuiltContractSource<TRegistry, WithKind<TBody, "service">>>,
4616
+ SchemasFromSource<
4617
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4618
+ >
4619
+ >,
4620
+ ProjectedState<
4621
+ StateFromSource<BuiltContractSource<TRegistry, WithKind<TBody, "service">>>,
4622
+ SchemasFromSource<
4623
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4624
+ >
4625
+ >,
4626
+ ProjectedKvResources<
4627
+ ResourcesFromSource<
4628
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4629
+ >,
4630
+ SchemasFromSource<
4631
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4632
+ >
4633
+ >
4634
+ > {
4635
+ return defineContract(
4636
+ registry,
4637
+ (ref) => ({
4638
+ ...build(ref),
4639
+ kind: "service",
4640
+ }),
4641
+ ) as unknown as DefinedContract<
4642
+ OwnedApiFromSource<
4643
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4644
+ >,
4645
+ UsedApiFromSource<
4646
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4647
+ >,
4648
+ MergeApis<
4649
+ OwnedApiFromSource<
4650
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4651
+ >,
4652
+ UsedApiFromSource<
4653
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4654
+ >
4655
+ >,
4656
+ TBody["id"],
4657
+ ProjectedJobs<
4658
+ JobsFromSource<
4659
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4660
+ >,
4661
+ SchemasFromSource<
4662
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4663
+ >
4664
+ >,
4665
+ ProjectedState<
4666
+ StateFromSource<
4667
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4668
+ >,
4669
+ SchemasFromSource<
4670
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4671
+ >
4672
+ >,
4673
+ ProjectedKvResources<
4674
+ ResourcesFromSource<
4675
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4676
+ >,
4677
+ SchemasFromSource<
4678
+ BuiltContractSource<TRegistry, WithKind<TBody, "service">>
4679
+ >
4680
+ >
4681
+ >;
4682
+ }
4683
+
4684
+ function defineClientContract<
4685
+ const TKind extends Exclude<ContractKind, "service">,
4686
+ const TSchemas extends Readonly<Record<string, TSchema>> | undefined,
4687
+ const TUses extends AuthorContractUses | undefined,
4688
+ const TBody extends ClientContractBodyInput<TSchemas, TUses>,
4689
+ >(
4690
+ kind: TKind,
4691
+ registry: ClientContractRegistry<TSchemas> & {
4692
+ capabilities?: never;
4693
+ exports?: never;
4694
+ },
4695
+ build: (ref: ContractRefBuilder<TSchemas>) => TBody,
4696
+ ): DefinedContract<
4697
+ OwnedApiFromSource<
4698
+ BuiltContractSource<
4699
+ ClientContractRegistry<TSchemas>,
4700
+ WithKind<TBody, TKind>
4701
+ >
4702
+ >,
4703
+ UsedApiFromSource<
4704
+ BuiltContractSource<
4705
+ ClientContractRegistry<TSchemas>,
4706
+ WithKind<TBody, TKind>
4707
+ >
4708
+ >,
4709
+ MergeApis<
4710
+ OwnedApiFromSource<
4711
+ BuiltContractSource<
4712
+ ClientContractRegistry<TSchemas>,
4713
+ WithKind<TBody, TKind>
4714
+ >
4715
+ >,
4716
+ UsedApiFromSource<
4717
+ BuiltContractSource<
4718
+ ClientContractRegistry<TSchemas>,
4719
+ WithKind<TBody, TKind>
4720
+ >
4721
+ >
4722
+ >,
4723
+ TBody["id"],
4724
+ {},
4725
+ ProjectedState<
4726
+ StateFromSource<
4727
+ BuiltContractSource<
4728
+ ClientContractRegistry<TSchemas>,
4729
+ WithKind<TBody, TKind>
4730
+ >
4731
+ >,
4732
+ SchemasFromSource<
4733
+ BuiltContractSource<
4734
+ ClientContractRegistry<TSchemas>,
4735
+ WithKind<TBody, TKind>
4736
+ >
4737
+ >
4738
+ >
4739
+ > {
4740
+ return defineContract(
4741
+ registry,
4742
+ (ref) => ({ ...build(ref), kind }),
4743
+ ) as unknown as DefinedContract<
4744
+ OwnedApiFromSource<
4745
+ BuiltContractSource<
4746
+ ClientContractRegistry<TSchemas>,
4747
+ WithKind<TBody, TKind>
4748
+ >
4749
+ >,
4750
+ UsedApiFromSource<
4751
+ BuiltContractSource<
4752
+ ClientContractRegistry<TSchemas>,
4753
+ WithKind<TBody, TKind>
4754
+ >
4755
+ >,
4756
+ MergeApis<
4757
+ OwnedApiFromSource<
4758
+ BuiltContractSource<
4759
+ ClientContractRegistry<TSchemas>,
4760
+ WithKind<TBody, TKind>
4761
+ >
4762
+ >,
4763
+ UsedApiFromSource<
4764
+ BuiltContractSource<
4765
+ ClientContractRegistry<TSchemas>,
4766
+ WithKind<TBody, TKind>
4767
+ >
4768
+ >
4769
+ >,
4770
+ TBody["id"],
4771
+ {},
4772
+ ProjectedState<
4773
+ StateFromSource<
4774
+ BuiltContractSource<
4775
+ ClientContractRegistry<TSchemas>,
4776
+ WithKind<TBody, TKind>
4777
+ >
4778
+ >,
4779
+ SchemasFromSource<
4780
+ BuiltContractSource<
4781
+ ClientContractRegistry<TSchemas>,
4782
+ WithKind<TBody, TKind>
4783
+ >
4784
+ >
4785
+ >
4786
+ >;
4787
+ }
4788
+
4789
+ export function defineAppContract<
4790
+ const TSchemas extends Readonly<Record<string, TSchema>> | undefined,
4791
+ const TUses extends AuthorContractUses | undefined,
4792
+ const TBody extends ClientContractBodyInput<TSchemas, TUses>,
4793
+ >(
4794
+ registry: ClientContractRegistry<TSchemas> & {
4795
+ capabilities?: never;
4796
+ exports?: never;
4797
+ },
4798
+ build: (ref: ContractRefBuilder<TSchemas>) => TBody,
4799
+ ): DefinedContract<
4800
+ OwnedApiFromSource<
4801
+ BuiltContractSource<
4802
+ ClientContractRegistry<TSchemas>,
4803
+ WithKind<TBody, "app">
4804
+ >
4805
+ >,
4806
+ UsedApiFromSource<
4807
+ BuiltContractSource<
4808
+ ClientContractRegistry<TSchemas>,
4809
+ WithKind<TBody, "app">
4810
+ >
4811
+ >,
4812
+ MergeApis<
4813
+ OwnedApiFromSource<
4814
+ BuiltContractSource<
4815
+ ClientContractRegistry<TSchemas>,
4816
+ WithKind<TBody, "app">
4817
+ >
4818
+ >,
4819
+ UsedApiFromSource<
4820
+ BuiltContractSource<
4821
+ ClientContractRegistry<TSchemas>,
4822
+ WithKind<TBody, "app">
4823
+ >
4824
+ >
4825
+ >,
4826
+ TBody["id"],
4827
+ {},
4828
+ ProjectedState<
4829
+ StateFromSource<
4830
+ BuiltContractSource<
4831
+ ClientContractRegistry<TSchemas>,
4832
+ WithKind<TBody, "app">
4833
+ >
4834
+ >,
4835
+ SchemasFromSource<
4836
+ BuiltContractSource<
4837
+ ClientContractRegistry<TSchemas>,
4838
+ WithKind<TBody, "app">
4839
+ >
4840
+ >
4841
+ >
4842
+ >;
4843
+ export function defineAppContract<
4844
+ const TUses extends AuthorContractUses | undefined,
4845
+ const TBody extends ClientContractBodyInput<undefined, TUses>,
4846
+ >(build: () => TBody): DefinedContract<
4847
+ OwnedApiFromSource<WithKind<TBody, "app">>,
4848
+ UsedApiFromSource<WithKind<TBody, "app">>,
4849
+ MergeApis<
4850
+ OwnedApiFromSource<WithKind<TBody, "app">>,
4851
+ UsedApiFromSource<WithKind<TBody, "app">>
4852
+ >,
4853
+ TBody["id"],
4854
+ {},
4855
+ ProjectedState<
4856
+ StateFromSource<WithKind<TBody, "app">>,
4857
+ SchemasFromSource<WithKind<TBody, "app">>
4858
+ >
4859
+ >;
4860
+ export function defineAppContract(
4861
+ ...args:
4862
+ | [() => ContractIdentityFields & Record<string, unknown>]
4863
+ | [
4864
+ ClientContractRegistry<Readonly<Record<string, TSchema>>> & {
4865
+ capabilities?: never;
4866
+ exports?: never;
4867
+ },
4868
+ (
4869
+ ref: ContractRefBuilder<Readonly<Record<string, TSchema>>>,
4870
+ ) => ContractIdentityFields & Record<string, unknown>,
4871
+ ]
4872
+ ) {
4873
+ const [registryOrBuild, maybeBuild] = args;
4874
+ if (typeof registryOrBuild === "function") {
4875
+ return defineClientContract("app", {}, () => registryOrBuild());
4876
+ }
4877
+
4878
+ return defineClientContract("app", registryOrBuild, maybeBuild!);
4879
+ }
4880
+
4881
+ export function defineAgentContract<
4882
+ const TSchemas extends Readonly<Record<string, TSchema>> | undefined,
4883
+ const TUses extends AuthorContractUses | undefined,
4884
+ const TBody extends ClientContractBodyInput<TSchemas, TUses>,
4885
+ >(
4886
+ registry: ClientContractRegistry<TSchemas> & {
4887
+ capabilities?: never;
4888
+ exports?: never;
4889
+ },
4890
+ build: (ref: ContractRefBuilder<TSchemas>) => TBody,
4891
+ ): DefinedContract<
4892
+ OwnedApiFromSource<
4893
+ BuiltContractSource<
4894
+ ClientContractRegistry<TSchemas>,
4895
+ WithKind<TBody, "agent">
4896
+ >
4897
+ >,
4898
+ UsedApiFromSource<
4899
+ BuiltContractSource<
4900
+ ClientContractRegistry<TSchemas>,
4901
+ WithKind<TBody, "agent">
4902
+ >
4903
+ >,
4904
+ MergeApis<
4905
+ OwnedApiFromSource<
4906
+ BuiltContractSource<
4907
+ ClientContractRegistry<TSchemas>,
4908
+ WithKind<TBody, "agent">
4909
+ >
4910
+ >,
4911
+ UsedApiFromSource<
4912
+ BuiltContractSource<
4913
+ ClientContractRegistry<TSchemas>,
4914
+ WithKind<TBody, "agent">
4915
+ >
4916
+ >
4917
+ >,
4918
+ TBody["id"],
4919
+ {},
4920
+ ProjectedState<
4921
+ StateFromSource<
4922
+ BuiltContractSource<
4923
+ ClientContractRegistry<TSchemas>,
4924
+ WithKind<TBody, "agent">
4925
+ >
4926
+ >,
4927
+ SchemasFromSource<
4928
+ BuiltContractSource<
4929
+ ClientContractRegistry<TSchemas>,
4930
+ WithKind<TBody, "agent">
4931
+ >
4932
+ >
4933
+ >
4934
+ >;
4935
+ export function defineAgentContract<
4936
+ const TUses extends AuthorContractUses | undefined,
4937
+ const TBody extends ClientContractBodyInput<undefined, TUses>,
4938
+ >(build: () => TBody): DefinedContract<
4939
+ OwnedApiFromSource<WithKind<TBody, "agent">>,
4940
+ UsedApiFromSource<WithKind<TBody, "agent">>,
4941
+ MergeApis<
4942
+ OwnedApiFromSource<WithKind<TBody, "agent">>,
4943
+ UsedApiFromSource<WithKind<TBody, "agent">>
4944
+ >,
4945
+ TBody["id"],
4946
+ {},
4947
+ ProjectedState<
4948
+ StateFromSource<WithKind<TBody, "agent">>,
4949
+ SchemasFromSource<WithKind<TBody, "agent">>
4950
+ >
4951
+ >;
4952
+ export function defineAgentContract(
4953
+ ...args:
4954
+ | [() => ContractIdentityFields & Record<string, unknown>]
4955
+ | [
4956
+ ClientContractRegistry<Readonly<Record<string, TSchema>>> & {
4957
+ capabilities?: never;
4958
+ exports?: never;
4959
+ },
4960
+ (
4961
+ ref: ContractRefBuilder<Readonly<Record<string, TSchema>>>,
4962
+ ) => ContractIdentityFields & Record<string, unknown>,
4963
+ ]
4964
+ ) {
4965
+ const [registryOrBuild, maybeBuild] = args;
4966
+ if (typeof registryOrBuild === "function") {
4967
+ return defineClientContract("agent", {}, () => registryOrBuild());
4968
+ }
4969
+
4970
+ return defineClientContract("agent", registryOrBuild, maybeBuild!);
4971
+ }
4972
+
4973
+ export function defineDeviceContract<
4974
+ const TSchemas extends Readonly<Record<string, TSchema>> | undefined,
4975
+ const TUses extends AuthorContractUses | undefined,
4976
+ const TBody extends ClientContractBodyInput<TSchemas, TUses>,
4977
+ >(
4978
+ registry: ClientContractRegistry<TSchemas> & {
4979
+ capabilities?: never;
4980
+ exports?: never;
4981
+ },
4982
+ build: (ref: ContractRefBuilder<TSchemas>) => TBody,
4983
+ ): DefinedContract<
4984
+ OwnedApiFromSource<
4985
+ BuiltContractSource<
4986
+ ClientContractRegistry<TSchemas>,
4987
+ WithKind<TBody, "device">
4988
+ >
4989
+ >,
4990
+ UsedApiFromSource<
4991
+ BuiltContractSource<
4992
+ ClientContractRegistry<TSchemas>,
4993
+ WithKind<TBody, "device">
4994
+ >
4995
+ >,
4996
+ MergeApis<
4997
+ OwnedApiFromSource<
4998
+ BuiltContractSource<
4999
+ ClientContractRegistry<TSchemas>,
5000
+ WithKind<TBody, "device">
5001
+ >
5002
+ >,
5003
+ UsedApiFromSource<
5004
+ BuiltContractSource<
5005
+ ClientContractRegistry<TSchemas>,
5006
+ WithKind<TBody, "device">
5007
+ >
5008
+ >
5009
+ >,
5010
+ TBody["id"],
5011
+ {},
5012
+ ProjectedState<
5013
+ StateFromSource<
5014
+ BuiltContractSource<
5015
+ ClientContractRegistry<TSchemas>,
5016
+ WithKind<TBody, "device">
5017
+ >
5018
+ >,
5019
+ SchemasFromSource<
5020
+ BuiltContractSource<
5021
+ ClientContractRegistry<TSchemas>,
5022
+ WithKind<TBody, "device">
5023
+ >
5024
+ >
5025
+ >
5026
+ >;
5027
+ export function defineDeviceContract<
5028
+ const TUses extends AuthorContractUses | undefined,
5029
+ const TBody extends ClientContractBodyInput<undefined, TUses>,
5030
+ >(build: () => TBody): DefinedContract<
5031
+ OwnedApiFromSource<WithKind<TBody, "device">>,
5032
+ UsedApiFromSource<WithKind<TBody, "device">>,
5033
+ MergeApis<
5034
+ OwnedApiFromSource<WithKind<TBody, "device">>,
5035
+ UsedApiFromSource<WithKind<TBody, "device">>
5036
+ >,
5037
+ TBody["id"],
5038
+ {},
5039
+ ProjectedState<
5040
+ StateFromSource<WithKind<TBody, "device">>,
5041
+ SchemasFromSource<WithKind<TBody, "device">>
5042
+ >
5043
+ >;
5044
+ export function defineDeviceContract(
5045
+ ...args:
5046
+ | [() => ContractIdentityFields & Record<string, unknown>]
5047
+ | [
5048
+ ClientContractRegistry<Readonly<Record<string, TSchema>>> & {
5049
+ capabilities?: never;
5050
+ exports?: never;
5051
+ },
5052
+ (
5053
+ ref: ContractRefBuilder<Readonly<Record<string, TSchema>>>,
5054
+ ) => ContractIdentityFields & Record<string, unknown>,
5055
+ ]
5056
+ ) {
5057
+ const [registryOrBuild, maybeBuild] = args;
5058
+ if (typeof registryOrBuild === "function") {
5059
+ return defineClientContract("device", {}, () => registryOrBuild());
5060
+ }
5061
+
5062
+ return defineClientContract("device", registryOrBuild, maybeBuild!);
5063
+ }
5064
+
5065
+ export type {
5066
+ EventDesc,
5067
+ FeedDesc,
5068
+ InferRuntimeRpcError,
5069
+ InferSchemaType,
5070
+ JsonValue,
5071
+ RPCDesc,
5072
+ RpcErrorClass,
5073
+ RuntimeRpcErrorDesc,
5074
+ Schema,
5075
+ SchemaLike,
5076
+ SerializableErrorData,
5077
+ TrellisAPI,
5078
+ };
5079
+ export { canonicalizeJson, digestJson, isJsonValue, schema, unwrapSchema };