@stigmer/server 3.24.0 → 3.26.0

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 (341) hide show
  1. package/dist/authorization/authorizer.d.ts +10 -4
  2. package/dist/authorization/authorizer.d.ts.map +1 -1
  3. package/dist/authorization/authorizer.js +11 -4
  4. package/dist/authorization/authorizer.js.map +1 -1
  5. package/dist/authorization/model/index.d.ts +4 -4
  6. package/dist/authorization/model/index.d.ts.map +1 -1
  7. package/dist/authorization/model/index.js +2 -0
  8. package/dist/authorization/model/index.js.map +1 -1
  9. package/dist/authorization/model/oauth_app.d.ts.map +1 -1
  10. package/dist/authorization/model/oauth_app.js +3 -2
  11. package/dist/authorization/model/oauth_app.js.map +1 -1
  12. package/dist/authorization/model/platform_client.d.ts +2 -0
  13. package/dist/authorization/model/platform_client.d.ts.map +1 -0
  14. package/dist/authorization/model/platform_client.js +31 -0
  15. package/dist/authorization/model/platform_client.js.map +1 -0
  16. package/dist/boot/compose.d.ts.map +1 -1
  17. package/dist/boot/compose.js +99 -13
  18. package/dist/boot/compose.js.map +1 -1
  19. package/dist/boot/list-indexes.d.ts +3 -0
  20. package/dist/boot/list-indexes.d.ts.map +1 -0
  21. package/dist/boot/list-indexes.js +24 -0
  22. package/dist/boot/list-indexes.js.map +1 -0
  23. package/dist/boot/route-shadowing.d.ts +25 -0
  24. package/dist/boot/route-shadowing.d.ts.map +1 -0
  25. package/dist/boot/route-shadowing.js +17 -0
  26. package/dist/boot/route-shadowing.js.map +1 -0
  27. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  28. package/dist/domain/agentexecution/controller.js +6 -8
  29. package/dist/domain/agentexecution/controller.js.map +1 -1
  30. package/dist/domain/agentexecution/list-index.d.ts +2 -0
  31. package/dist/domain/agentexecution/list-index.d.ts.map +1 -0
  32. package/dist/domain/agentexecution/list-index.js +23 -0
  33. package/dist/domain/agentexecution/list-index.js.map +1 -0
  34. package/dist/domain/agentexecution/steps.d.ts +17 -33
  35. package/dist/domain/agentexecution/steps.d.ts.map +1 -1
  36. package/dist/domain/agentexecution/steps.js +94 -95
  37. package/dist/domain/agentexecution/steps.js.map +1 -1
  38. package/dist/domain/agentexecution/usage.d.ts.map +1 -1
  39. package/dist/domain/agentexecution/usage.js +37 -14
  40. package/dist/domain/agentexecution/usage.js.map +1 -1
  41. package/dist/domain/artifact/controller.d.ts.map +1 -1
  42. package/dist/domain/artifact/controller.js +27 -15
  43. package/dist/domain/artifact/controller.js.map +1 -1
  44. package/dist/domain/artifact/list-index.d.ts +2 -0
  45. package/dist/domain/artifact/list-index.d.ts.map +1 -0
  46. package/dist/domain/artifact/list-index.js +21 -0
  47. package/dist/domain/artifact/list-index.js.map +1 -0
  48. package/dist/domain/iampolicy/membership.d.ts +6 -1
  49. package/dist/domain/iampolicy/membership.d.ts.map +1 -1
  50. package/dist/domain/iampolicy/membership.js +8 -2
  51. package/dist/domain/iampolicy/membership.js.map +1 -1
  52. package/dist/domain/identityaccount/constants.d.ts +13 -0
  53. package/dist/domain/identityaccount/constants.d.ts.map +1 -1
  54. package/dist/domain/identityaccount/constants.js +17 -0
  55. package/dist/domain/identityaccount/constants.js.map +1 -1
  56. package/dist/domain/identityaccount/controller.d.ts +3 -1
  57. package/dist/domain/identityaccount/controller.d.ts.map +1 -1
  58. package/dist/domain/identityaccount/controller.js +15 -6
  59. package/dist/domain/identityaccount/controller.js.map +1 -1
  60. package/dist/domain/identityaccount/operator.d.ts.map +1 -1
  61. package/dist/domain/identityaccount/operator.js +1 -0
  62. package/dist/domain/identityaccount/operator.js.map +1 -1
  63. package/dist/domain/identityaccount/provisioning.d.ts +18 -0
  64. package/dist/domain/identityaccount/provisioning.d.ts.map +1 -1
  65. package/dist/domain/identityaccount/provisioning.js +1 -0
  66. package/dist/domain/identityaccount/provisioning.js.map +1 -1
  67. package/dist/domain/identityaccount/resource-store.js +9 -5
  68. package/dist/domain/identityaccount/resource-store.js.map +1 -1
  69. package/dist/domain/identityaccount/steps.d.ts +11 -2
  70. package/dist/domain/identityaccount/steps.d.ts.map +1 -1
  71. package/dist/domain/identityaccount/steps.js +42 -4
  72. package/dist/domain/identityaccount/steps.js.map +1 -1
  73. package/dist/domain/identityaccount/store-contract.d.ts.map +1 -1
  74. package/dist/domain/identityaccount/store-contract.js +33 -0
  75. package/dist/domain/identityaccount/store-contract.js.map +1 -1
  76. package/dist/domain/identityaccount/store.d.ts +7 -5
  77. package/dist/domain/identityaccount/store.d.ts.map +1 -1
  78. package/dist/domain/identityaccount/store.js.map +1 -1
  79. package/dist/domain/platform/controller.d.ts +10 -0
  80. package/dist/domain/platform/controller.d.ts.map +1 -1
  81. package/dist/domain/platform/controller.js +2 -1
  82. package/dist/domain/platform/controller.js.map +1 -1
  83. package/dist/domain/platformclient/constants.d.ts +60 -0
  84. package/dist/domain/platformclient/constants.d.ts.map +1 -0
  85. package/dist/domain/platformclient/constants.js +78 -0
  86. package/dist/domain/platformclient/constants.js.map +1 -0
  87. package/dist/domain/platformclient/controller.d.ts +59 -0
  88. package/dist/domain/platformclient/controller.d.ts.map +1 -0
  89. package/dist/domain/platformclient/controller.js +191 -0
  90. package/dist/domain/platformclient/controller.js.map +1 -0
  91. package/dist/domain/platformclient/credentials.d.ts +13 -0
  92. package/dist/domain/platformclient/credentials.d.ts.map +1 -0
  93. package/dist/domain/platformclient/credentials.js +56 -0
  94. package/dist/domain/platformclient/credentials.js.map +1 -0
  95. package/dist/domain/platformclient/mint.d.ts +23 -0
  96. package/dist/domain/platformclient/mint.d.ts.map +1 -0
  97. package/dist/domain/platformclient/mint.js +254 -0
  98. package/dist/domain/platformclient/mint.js.map +1 -0
  99. package/dist/domain/platformclient/origin-guard.d.ts +9 -0
  100. package/dist/domain/platformclient/origin-guard.d.ts.map +1 -0
  101. package/dist/domain/platformclient/origin-guard.js +81 -0
  102. package/dist/domain/platformclient/origin-guard.js.map +1 -0
  103. package/dist/domain/platformclient/resource-store.d.ts +4 -0
  104. package/dist/domain/platformclient/resource-store.d.ts.map +1 -0
  105. package/dist/domain/platformclient/resource-store.js +117 -0
  106. package/dist/domain/platformclient/resource-store.js.map +1 -0
  107. package/dist/domain/platformclient/steps.d.ts +51 -0
  108. package/dist/domain/platformclient/steps.d.ts.map +1 -0
  109. package/dist/domain/platformclient/steps.js +339 -0
  110. package/dist/domain/platformclient/steps.js.map +1 -0
  111. package/dist/domain/platformclient/store-contract.d.ts +8 -0
  112. package/dist/domain/platformclient/store-contract.d.ts.map +1 -0
  113. package/dist/domain/platformclient/store-contract.js +208 -0
  114. package/dist/domain/platformclient/store-contract.js.map +1 -0
  115. package/dist/domain/platformclient/store.d.ts +58 -0
  116. package/dist/domain/platformclient/store.d.ts.map +1 -0
  117. package/dist/domain/platformclient/store.js +13 -0
  118. package/dist/domain/platformclient/store.js.map +1 -0
  119. package/dist/domain/platformclient/system-managed.d.ts +18 -0
  120. package/dist/domain/platformclient/system-managed.d.ts.map +1 -0
  121. package/dist/domain/platformclient/system-managed.js +80 -0
  122. package/dist/domain/platformclient/system-managed.js.map +1 -0
  123. package/dist/domain/platformclient/token-controller.d.ts +11 -0
  124. package/dist/domain/platformclient/token-controller.d.ts.map +1 -0
  125. package/dist/domain/platformclient/token-controller.js +32 -0
  126. package/dist/domain/platformclient/token-controller.js.map +1 -0
  127. package/dist/domain/platformclient/verifier.d.ts +10 -0
  128. package/dist/domain/platformclient/verifier.d.ts.map +1 -0
  129. package/dist/domain/platformclient/verifier.js +76 -0
  130. package/dist/domain/platformclient/verifier.js.map +1 -0
  131. package/dist/domain/session/list-index.d.ts +4 -0
  132. package/dist/domain/session/list-index.d.ts.map +1 -0
  133. package/dist/domain/session/list-index.js +26 -0
  134. package/dist/domain/session/list-index.js.map +1 -0
  135. package/dist/domain/session/steps.d.ts +7 -8
  136. package/dist/domain/session/steps.d.ts.map +1 -1
  137. package/dist/domain/session/steps.js +76 -78
  138. package/dist/domain/session/steps.js.map +1 -1
  139. package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
  140. package/dist/domain/workflowexecution/controller.js +53 -55
  141. package/dist/domain/workflowexecution/controller.js.map +1 -1
  142. package/dist/domain/workflowexecution/execution-filter.d.ts +4 -0
  143. package/dist/domain/workflowexecution/execution-filter.d.ts.map +1 -1
  144. package/dist/domain/workflowexecution/execution-filter.js +11 -5
  145. package/dist/domain/workflowexecution/execution-filter.js.map +1 -1
  146. package/dist/domain/workflowexecution/get-execution-summary.d.ts.map +1 -1
  147. package/dist/domain/workflowexecution/get-execution-summary.js +23 -17
  148. package/dist/domain/workflowexecution/get-execution-summary.js.map +1 -1
  149. package/dist/domain/workflowexecution/list-index.d.ts +2 -0
  150. package/dist/domain/workflowexecution/list-index.d.ts.map +1 -0
  151. package/dist/domain/workflowexecution/list-index.js +21 -0
  152. package/dist/domain/workflowexecution/list-index.js.map +1 -0
  153. package/dist/domain/workflowexecution/list-pending-approvals.d.ts.map +1 -1
  154. package/dist/domain/workflowexecution/list-pending-approvals.js +69 -32
  155. package/dist/domain/workflowexecution/list-pending-approvals.js.map +1 -1
  156. package/dist/domain/workflowexecution/queries.d.ts +30 -4
  157. package/dist/domain/workflowexecution/queries.d.ts.map +1 -1
  158. package/dist/domain/workflowexecution/queries.js +76 -22
  159. package/dist/domain/workflowexecution/queries.js.map +1 -1
  160. package/dist/encryption/key-manager.d.ts +20 -3
  161. package/dist/encryption/key-manager.d.ts.map +1 -1
  162. package/dist/encryption/key-manager.js +64 -42
  163. package/dist/encryption/key-manager.js.map +1 -1
  164. package/dist/extensions/caller-guards.d.ts +8 -3
  165. package/dist/extensions/caller-guards.d.ts.map +1 -1
  166. package/dist/extensions/drivers.d.ts +37 -0
  167. package/dist/extensions/drivers.d.ts.map +1 -1
  168. package/dist/extensions/guest-token-minting.d.ts +26 -0
  169. package/dist/extensions/guest-token-minting.d.ts.map +1 -0
  170. package/dist/extensions/guest-token-minting.js +2 -0
  171. package/dist/extensions/guest-token-minting.js.map +1 -0
  172. package/dist/extensions/identity.d.ts +6 -4
  173. package/dist/extensions/identity.d.ts.map +1 -1
  174. package/dist/extensions/identity.js.map +1 -1
  175. package/dist/extensions/list-read-scope.d.ts +9 -12
  176. package/dist/extensions/list-read-scope.d.ts.map +1 -1
  177. package/dist/extensions/list-read-scope.js.map +1 -1
  178. package/dist/extensions/registry.d.ts +30 -1
  179. package/dist/extensions/registry.d.ts.map +1 -1
  180. package/dist/extensions/registry.js +34 -1
  181. package/dist/extensions/registry.js.map +1 -1
  182. package/dist/index.d.ts +15 -2
  183. package/dist/index.d.ts.map +1 -1
  184. package/dist/index.js +6 -0
  185. package/dist/index.js.map +1 -1
  186. package/dist/pipeline/interceptors/auth.d.ts +14 -0
  187. package/dist/pipeline/interceptors/auth.d.ts.map +1 -1
  188. package/dist/pipeline/interceptors/auth.js +24 -0
  189. package/dist/pipeline/interceptors/auth.js.map +1 -1
  190. package/dist/pipeline/steps/build-update-state.d.ts +11 -1
  191. package/dist/pipeline/steps/build-update-state.d.ts.map +1 -1
  192. package/dist/pipeline/steps/build-update-state.js +5 -2
  193. package/dist/pipeline/steps/build-update-state.js.map +1 -1
  194. package/dist/pipeline/steps/list-page.d.ts +63 -0
  195. package/dist/pipeline/steps/list-page.d.ts.map +1 -0
  196. package/dist/pipeline/steps/list-page.js +187 -0
  197. package/dist/pipeline/steps/list-page.js.map +1 -0
  198. package/dist/platformtoken/envelope.d.ts +100 -0
  199. package/dist/platformtoken/envelope.d.ts.map +1 -0
  200. package/dist/platformtoken/envelope.js +184 -0
  201. package/dist/platformtoken/envelope.js.map +1 -0
  202. package/dist/platformtoken/key-ring.d.ts +85 -0
  203. package/dist/platformtoken/key-ring.d.ts.map +1 -0
  204. package/dist/platformtoken/key-ring.js +164 -0
  205. package/dist/platformtoken/key-ring.js.map +1 -0
  206. package/dist/query/activity/handler.d.ts +6 -7
  207. package/dist/query/activity/handler.d.ts.map +1 -1
  208. package/dist/query/activity/handler.js +42 -59
  209. package/dist/query/activity/handler.js.map +1 -1
  210. package/dist/store/interface.d.ts +29 -0
  211. package/dist/store/interface.d.ts.map +1 -1
  212. package/dist/store/interface.js.map +1 -1
  213. package/dist/store/list-index.d.ts +123 -0
  214. package/dist/store/list-index.d.ts.map +1 -0
  215. package/dist/store/list-index.js +277 -0
  216. package/dist/store/list-index.js.map +1 -0
  217. package/dist/store/logger.d.ts +3 -0
  218. package/dist/store/logger.d.ts.map +1 -1
  219. package/dist/store/logger.js +5 -1
  220. package/dist/store/logger.js.map +1 -1
  221. package/dist/store/postgres/migrations.d.ts +10 -6
  222. package/dist/store/postgres/migrations.d.ts.map +1 -1
  223. package/dist/store/postgres/migrations.js +64 -6
  224. package/dist/store/postgres/migrations.js.map +1 -1
  225. package/dist/store/postgres/store.d.ts +26 -5
  226. package/dist/store/postgres/store.d.ts.map +1 -1
  227. package/dist/store/postgres/store.js +377 -22
  228. package/dist/store/postgres/store.js.map +1 -1
  229. package/dist/store/sqlite/migrations.d.ts +11 -5
  230. package/dist/store/sqlite/migrations.d.ts.map +1 -1
  231. package/dist/store/sqlite/migrations.js +50 -4
  232. package/dist/store/sqlite/migrations.js.map +1 -1
  233. package/dist/store/sqlite/store.d.ts +18 -3
  234. package/dist/store/sqlite/store.d.ts.map +1 -1
  235. package/dist/store/sqlite/store.js +321 -15
  236. package/dist/store/sqlite/store.js.map +1 -1
  237. package/package.json +6 -6
  238. package/src/authorization/README.md +1 -1
  239. package/src/authorization/__tests__/authorizer.test.ts +6 -2
  240. package/src/authorization/__tests__/drivers.ts +6 -1
  241. package/src/authorization/__tests__/wire-permissions.test.ts +1 -0
  242. package/src/authorization/authorizer.ts +11 -4
  243. package/src/authorization/model/__tests__/registry.test.ts +8 -1
  244. package/src/authorization/model/index.ts +6 -4
  245. package/src/authorization/model/oauth_app.ts +3 -2
  246. package/src/authorization/model/platform_client.ts +43 -0
  247. package/src/boot/__tests__/auth-enabled-composition.test.ts +2 -1
  248. package/src/boot/__tests__/list-indexes.test.ts +65 -0
  249. package/src/boot/__tests__/route-shadowing.test.ts +67 -0
  250. package/src/boot/compose.ts +113 -18
  251. package/src/boot/list-indexes.ts +25 -0
  252. package/src/boot/route-shadowing.ts +47 -0
  253. package/src/domain/agentexecution/__tests__/agentexecution.test.ts +85 -3
  254. package/src/domain/agentexecution/controller.ts +8 -10
  255. package/src/domain/agentexecution/list-index.ts +24 -0
  256. package/src/domain/agentexecution/steps.ts +118 -115
  257. package/src/domain/agentexecution/usage.ts +38 -17
  258. package/src/domain/artifact/controller.ts +28 -18
  259. package/src/domain/artifact/list-index.ts +22 -0
  260. package/src/domain/iampolicy/__tests__/membership.test.ts +7 -0
  261. package/src/domain/iampolicy/membership.ts +8 -2
  262. package/src/domain/identityaccount/__tests__/platform-client-accounts.test.ts +124 -0
  263. package/src/domain/identityaccount/__tests__/resource-store.test.ts +1 -0
  264. package/src/domain/identityaccount/constants.ts +20 -0
  265. package/src/domain/identityaccount/controller.ts +16 -4
  266. package/src/domain/identityaccount/operator.ts +1 -0
  267. package/src/domain/identityaccount/provisioning.ts +17 -0
  268. package/src/domain/identityaccount/resource-store.ts +9 -5
  269. package/src/domain/identityaccount/steps.ts +58 -3
  270. package/src/domain/identityaccount/store-contract.ts +51 -0
  271. package/src/domain/identityaccount/store.ts +7 -5
  272. package/src/domain/platform/__tests__/platform.test.ts +7 -1
  273. package/src/domain/platform/controller.ts +12 -1
  274. package/src/domain/platformclient/__tests__/controller.test.ts +397 -0
  275. package/src/domain/platformclient/__tests__/credentials.test.ts +46 -0
  276. package/src/domain/platformclient/__tests__/mint.test.ts +415 -0
  277. package/src/domain/platformclient/__tests__/resource-store.test.ts +140 -0
  278. package/src/domain/platformclient/__tests__/system-managed.test.ts +101 -0
  279. package/src/domain/platformclient/__tests__/verifier-and-guard.test.ts +207 -0
  280. package/src/domain/platformclient/constants.ts +120 -0
  281. package/src/domain/platformclient/controller.ts +449 -0
  282. package/src/domain/platformclient/credentials.ts +68 -0
  283. package/src/domain/platformclient/mint.ts +412 -0
  284. package/src/domain/platformclient/origin-guard.ts +117 -0
  285. package/src/domain/platformclient/resource-store.ts +150 -0
  286. package/src/domain/platformclient/steps.ts +472 -0
  287. package/src/domain/platformclient/store-contract.ts +318 -0
  288. package/src/domain/platformclient/store.ts +63 -0
  289. package/src/domain/platformclient/system-managed.ts +115 -0
  290. package/src/domain/platformclient/token-controller.ts +49 -0
  291. package/src/domain/platformclient/verifier.ts +106 -0
  292. package/src/domain/session/list-index.ts +28 -0
  293. package/src/domain/session/steps.ts +108 -123
  294. package/src/domain/workflowexecution/__tests__/list-read-scope-summaries.test.ts +155 -99
  295. package/src/domain/workflowexecution/__tests__/workflowexecution.test.ts +193 -31
  296. package/src/domain/workflowexecution/controller.ts +54 -82
  297. package/src/domain/workflowexecution/execution-filter.ts +20 -7
  298. package/src/domain/workflowexecution/get-execution-summary.ts +31 -24
  299. package/src/domain/workflowexecution/list-index.ts +22 -0
  300. package/src/domain/workflowexecution/list-pending-approvals.ts +82 -25
  301. package/src/domain/workflowexecution/queries.ts +134 -23
  302. package/src/encryption/key-manager.ts +87 -44
  303. package/src/extensions/__tests__/extension-composition.test.ts +3 -2
  304. package/src/extensions/__tests__/platform-client-composed.test.ts +288 -0
  305. package/src/extensions/__tests__/registry.test.ts +4 -1
  306. package/src/extensions/__tests__/tier-truthfulness.test.ts +8 -0
  307. package/src/extensions/caller-guards.ts +8 -3
  308. package/src/extensions/drivers.ts +37 -0
  309. package/src/extensions/guest-token-minting.ts +32 -0
  310. package/src/extensions/identity.ts +6 -4
  311. package/src/extensions/list-read-scope.ts +9 -12
  312. package/src/extensions/registry.ts +77 -3
  313. package/src/index.ts +65 -1
  314. package/src/pipeline/interceptors/auth.ts +27 -0
  315. package/src/pipeline/steps/__tests__/list-page.test.ts +186 -0
  316. package/src/pipeline/steps/__tests__/references.test.ts +2 -0
  317. package/src/pipeline/steps/build-update-state.ts +5 -2
  318. package/src/pipeline/steps/list-page.ts +284 -0
  319. package/src/platformtoken/__tests__/envelope.test.ts +277 -0
  320. package/src/platformtoken/__tests__/key-ring.test.ts +205 -0
  321. package/src/platformtoken/envelope.ts +276 -0
  322. package/src/platformtoken/key-ring.ts +266 -0
  323. package/src/query/activity/handler.ts +57 -78
  324. package/src/runnerauth/__tests__/runner-subject-composed.test.ts +9 -3
  325. package/src/store/README.md +51 -32
  326. package/src/store/__tests__/list-index.measure.test.ts +293 -0
  327. package/src/store/__tests__/list-index.test.ts +328 -0
  328. package/src/store/__tests__/store-contract.ts +346 -3
  329. package/src/store/interface.ts +39 -0
  330. package/src/store/list-index.ts +465 -0
  331. package/src/store/logger.ts +8 -1
  332. package/src/store/postgres/__tests__/list-index-repair.test.ts +133 -0
  333. package/src/store/postgres/__tests__/migrations.test.ts +27 -19
  334. package/src/store/postgres/__tests__/store-contract.test.ts +50 -3
  335. package/src/store/postgres/migrations.ts +69 -7
  336. package/src/store/postgres/store.ts +485 -29
  337. package/src/store/sqlite/__tests__/migrations.test.ts +51 -7
  338. package/src/store/sqlite/__tests__/store-contract.test.ts +70 -16
  339. package/src/store/sqlite/__tests__/support.ts +12 -3
  340. package/src/store/sqlite/migrations.ts +57 -6
  341. package/src/store/sqlite/store.ts +462 -21
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Raised by `save` when the id, the (org, slug) pair or the client_id is
3
+ * already held, so the create chain answers ALREADY_EXISTS. `cause`
4
+ * carries a driver's own error (the cloud's SQLSTATE 23505) for the logs;
5
+ * the message is the port's.
6
+ */
7
+ export class DuplicatePlatformClientError extends Error {
8
+ constructor(message, options) {
9
+ super(message, options);
10
+ this.name = "DuplicatePlatformClientError";
11
+ }
12
+ }
13
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/domain/platformclient/store.ts"],"names":[],"mappings":"AAiCA;;;;;GAKG;AACH,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IACrD,YAAY,OAAe,EAAE,OAA6B;QACxD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;IAC7C,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ import type { PlatformClient } from "@stigmer/protos/ai/stigmer/iam/platformclient/v1/api_pb";
2
+ export interface SystemManagedPlatformClientInput {
3
+ /** The owning organization. */
4
+ readonly org: string;
5
+ /** A reserved slug (RESERVED_PLATFORM_CLIENT_SLUGS); anything else throws. */
6
+ readonly slug: string;
7
+ /** The display name a console would show. */
8
+ readonly name: string;
9
+ /** The creation instant stamped on both audit slots; defaults to the wall clock. */
10
+ readonly now?: Date;
11
+ }
12
+ /**
13
+ * A new system-managed client, ready for a store's `save`. Throws on an
14
+ * empty organization or a slug that is not reserved — an edition's
15
+ * programming error, never a request's.
16
+ */
17
+ export declare function newSystemManagedPlatformClient(input: SystemManagedPlatformClientInput): PlatformClient;
18
+ //# sourceMappingURL=system-managed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-managed.d.ts","sourceRoot":"","sources":["../../../src/domain/platformclient/system-managed.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yDAAyD,CAAC;AAsB9F,MAAM,WAAW,gCAAgC;IAC/C,+BAA+B;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,gCAAgC,GACtC,cAAc,CAuChB"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * The one builder of a system-managed PlatformClient: the row an edition
3
+ * creates for itself, never through the create chain, so the tokens it
4
+ * signs on the platform's own behalf (a guest's, a schedule fire's) name a
5
+ * client that exists. Stigmer Cloud keeps one per organization under
6
+ * SYSTEM_SHARE_CLIENT_SLUG and persists it through its store driver.
7
+ *
8
+ * The domain already owns what such a client is — the create chain refuses
9
+ * its reserved slug (RefuseReservedSlug) and every mutation refuses its
10
+ * label (RefuseSystemManaged) — so the row is built here too, and the
11
+ * rules that make it safe hold by construction:
12
+ * - it lives only under a reserved slug, which no user can create, so a
13
+ * user client can never be mistaken for one;
14
+ * - it carries the reserved `stigmer.ai/system-managed` label, so update,
15
+ * delete and rotate refuse it;
16
+ * - its credentials are real (a `client_id` unique like any other, a
17
+ * hash, a fingerprint), but the secret is discarded here: nobody ever
18
+ * authenticates as the platform's own client;
19
+ * - its id is spelled like every other (`pcl_` + ULID, generateId);
20
+ * - its audit names no actor, because no caller made it: the platform did.
21
+ *
22
+ * Who decides when one exists, and where it is stored, is the edition's:
23
+ * this function writes nothing. It writes no authorization tuples either —
24
+ * nothing authorizes against a system-managed client, and with none it
25
+ * stays out of every list and reference read a person makes.
26
+ */
27
+ import { create } from "@bufbuild/protobuf";
28
+ import { timestampFromDate } from "@bufbuild/protobuf/wkt";
29
+ import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
30
+ import { ApiResourceAuditInfoSchema, ApiResourceAuditSchema, } from "@stigmer/protos/ai/stigmer/commons/apiresource/status_pb";
31
+ import { PlatformClientSchema } from "@stigmer/protos/ai/stigmer/iam/platformclient/v1/api_pb";
32
+ import { RESERVED_LABEL_TRUE, SYSTEM_MANAGED_LABEL, } from "../../pipeline/apiresource-labels.js";
33
+ import { defaultVisibilityFor, getIdPrefix, } from "../../pipeline/apiresource-meta.js";
34
+ import { generateId } from "../../pipeline/steps/defaults.js";
35
+ import { PLATFORM_CLIENT_KIND_NAME, RESERVED_PLATFORM_CLIENT_SLUGS, } from "./constants.js";
36
+ import { generateClientId, generateClientSecret, hashClientSecret, secretFingerprint, } from "./credentials.js";
37
+ /**
38
+ * A new system-managed client, ready for a store's `save`. Throws on an
39
+ * empty organization or a slug that is not reserved — an edition's
40
+ * programming error, never a request's.
41
+ */
42
+ export function newSystemManagedPlatformClient(input) {
43
+ if (input.org === "") {
44
+ throw new Error("a system-managed platform client needs an organization");
45
+ }
46
+ if (!RESERVED_PLATFORM_CLIENT_SLUGS.has(input.slug)) {
47
+ throw new Error(`'${input.slug}' is not a reserved platform-client slug; a system-managed client lives only under one (${[...RESERVED_PLATFORM_CLIENT_SLUGS].join(", ")})`);
48
+ }
49
+ const secret = generateClientSecret();
50
+ const created = timestampFromDate(input.now ?? new Date());
51
+ const audit = create(ApiResourceAuditInfoSchema, {
52
+ createdAt: created,
53
+ updatedAt: created,
54
+ event: "created",
55
+ });
56
+ return create(PlatformClientSchema, {
57
+ apiVersion: "iam.stigmer.ai/v1",
58
+ kind: PLATFORM_CLIENT_KIND_NAME,
59
+ metadata: {
60
+ id: generateId(getIdPrefix(ApiResourceKind.platform_client)),
61
+ org: input.org,
62
+ name: input.name,
63
+ slug: input.slug,
64
+ labels: { [SYSTEM_MANAGED_LABEL]: RESERVED_LABEL_TRUE },
65
+ visibility: defaultVisibilityFor(ApiResourceKind.platform_client),
66
+ },
67
+ spec: {
68
+ clientId: generateClientId(),
69
+ clientSecretHash: hashClientSecret(secret),
70
+ secretFingerprint: secretFingerprint(secret),
71
+ },
72
+ status: {
73
+ audit: create(ApiResourceAuditSchema, {
74
+ specAudit: audit,
75
+ statusAudit: audit,
76
+ }),
77
+ },
78
+ });
79
+ }
80
+ //# sourceMappingURL=system-managed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-managed.js","sourceRoot":"","sources":["../../../src/domain/platformclient/system-managed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,qFAAqF,CAAC;AACtH,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,0DAA0D,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yDAAyD,CAAC;AAG/F,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,WAAW,GACZ,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EACL,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAa1B;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAC5C,KAAuC;IAEvC,IAAI,KAAK,CAAC,GAAG,KAAK,EAAE,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,CAAC,8BAA8B,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CACb,IAAI,KAAK,CAAC,IAAI,2FAA2F,CAAC,GAAG,8BAA8B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC3J,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,0BAA0B,EAAE;QAC/C,SAAS,EAAE,OAAO;QAClB,SAAS,EAAE,OAAO;QAClB,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,oBAAoB,EAAE;QAClC,UAAU,EAAE,mBAAmB;QAC/B,IAAI,EAAE,yBAAyB;QAC/B,QAAQ,EAAE;YACR,EAAE,EAAE,UAAU,CAAC,WAAW,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;YAC5D,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,EAAE,CAAC,oBAAoB,CAAC,EAAE,mBAAmB,EAAE;YACvD,UAAU,EAAE,oBAAoB,CAAC,eAAe,CAAC,eAAe,CAAC;SAClE;QACD,IAAI,EAAE;YACJ,QAAQ,EAAE,gBAAgB,EAAE;YAC5B,gBAAgB,EAAE,gBAAgB,CAAC,MAAM,CAAC;YAC1C,iBAAiB,EAAE,iBAAiB,CAAC,MAAM,CAAC;SAC7C;QACD,MAAM,EAAE;YACN,KAAK,EAAE,MAAM,CAAC,sBAAsB,EAAE;gBACpC,SAAS,EAAE,KAAK;gBAChB,WAAW,EAAE,KAAK;aACnB,CAAC;SACH;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { ConnectRouter } from "@connectrpc/connect";
2
+ import type { GuestTokenMinting } from "../../extensions/guest-token-minting.js";
3
+ import type { PlatformClientMintDeps } from "./mint.js";
4
+ export interface PlatformClientTokenControllerDeps {
5
+ readonly mint: PlatformClientMintDeps;
6
+ /** The composed capability; undefined = mintGuestToken refuses UNIMPLEMENTED. */
7
+ readonly guestTokenMinting: GuestTokenMinting | undefined;
8
+ }
9
+ /** Registers the token service on the router (routes stage). */
10
+ export declare function registerPlatformClientTokenService(router: ConnectRouter, deps: PlatformClientTokenControllerDeps): void;
11
+ //# sourceMappingURL=token-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-controller.d.ts","sourceRoot":"","sources":["../../../src/domain/platformclient/token-controller.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAGjF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,iFAAiF;IACjF,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,GAAG,SAAS,CAAC;CAC3D;AAED,gEAAgE;AAChE,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,iCAAiC,GACtC,IAAI,CAaN"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * PlatformClientTokenController — the two public token RPCs, registered in
3
+ * every composition so the service has one owner (the routes stage refuses
4
+ * an extension that registers it again, boot/route-shadowing.ts):
5
+ *
6
+ * - mintUserToken: the PlatformClient mint (mint.ts). Public on the wire
7
+ * — the client authenticates with its credentials in the body, not a
8
+ * bearer token — so there is no annotation to evaluate; the mint never
9
+ * reads the chain's caller.
10
+ * - mintGuestToken: the credential-free mint for anonymous visitors of a
11
+ * shared agent's hosted page, dispatched to the composed guest-token
12
+ * capability (extensions/guest-token-minting.ts). Without one — open
13
+ * source hosts no shared-agent pages — it answers UNIMPLEMENTED with
14
+ * the edition sentence, the identityFederation absent shape.
15
+ */
16
+ import { Code, ConnectError } from "@connectrpc/connect";
17
+ import { PlatformClientTokenController } from "@stigmer/protos/ai/stigmer/iam/platformclient/v1/token_pb";
18
+ import { GUEST_MINT_UNIMPLEMENTED_MESSAGE } from "./constants.js";
19
+ import { mintUserToken } from "./mint.js";
20
+ /** Registers the token service on the router (routes stage). */
21
+ export function registerPlatformClientTokenService(router, deps) {
22
+ router.service(PlatformClientTokenController, {
23
+ mintUserToken: (request) => mintUserToken(deps.mint, request),
24
+ mintGuestToken: (request, ctx) => {
25
+ if (deps.guestTokenMinting === undefined) {
26
+ throw new ConnectError(GUEST_MINT_UNIMPLEMENTED_MESSAGE, Code.Unimplemented);
27
+ }
28
+ return deps.guestTokenMinting.mintGuestToken(request, ctx.requestHeader);
29
+ },
30
+ });
31
+ }
32
+ //# sourceMappingURL=token-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-controller.js","sourceRoot":"","sources":["../../../src/domain/platformclient/token-controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,EAAE,6BAA6B,EAAE,MAAM,2DAA2D,CAAC;AAG1G,OAAO,EAAE,gCAAgC,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAS1C,gEAAgE;AAChE,MAAM,UAAU,kCAAkC,CAChD,MAAqB,EACrB,IAAuC;IAEvC,MAAM,CAAC,OAAO,CAAC,6BAA6B,EAAE;QAC5C,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;QAC7D,cAAc,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;YAC/B,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;gBACzC,MAAM,IAAI,YAAY,CACpB,gCAAgC,EAChC,IAAI,CAAC,aAAa,CACnB,CAAC;YACJ,CAAC;YACD,OAAO,IAAI,CAAC,iBAAiB,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;QAC3E,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { IdentityVerifier } from "../../extensions/identity.js";
2
+ import type { PlatformTokenKeyRing } from "../../platformtoken/key-ring.js";
3
+ import type { PlatformClientStore } from "./store.js";
4
+ export interface PlatformClientTokenVerifierDeps {
5
+ readonly keys: PlatformTokenKeyRing;
6
+ readonly clients: Pick<PlatformClientStore, "findById">;
7
+ readonly now?: () => Date;
8
+ }
9
+ export declare function newPlatformClientTokenVerifier(deps: PlatformClientTokenVerifierDeps): IdentityVerifier;
10
+ //# sourceMappingURL=verifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../../src/domain/platformclient/verifier.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AAOtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAM5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,CAAC;IACxD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,+BAA+B,GACpC,gBAAgB,CA8ClB"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The PlatformClient user-token verifier: open source's one platform-token
3
+ * lane. It claims a token with `iss: "stigmer"` and NO `token_type` — the
4
+ * user token the mint signs — and passes every other token on:
5
+ * - a token that is not a platform token is another verifier's (the
6
+ * OIDC verifier's, an API key's);
7
+ * - a typed platform token (guest, schedule, channel, the sandbox
8
+ * family) belongs to the edition that mints it; open source verifies
9
+ * only its own vocabulary, and on a server with no verifier for that
10
+ * lane the chain refuses it as unclaimed.
11
+ * A platform token whose signature, expiry, audience or subject fails is
12
+ * refused here with the envelope's pinned copy, whichever lane it names —
13
+ * the refusal the cloud's verifier has always answered for it.
14
+ *
15
+ * Liveness is the verifier's (not a guard's), so every lane that
16
+ * authenticates — the serving chain and the extension HTTP edges that run
17
+ * the verifier chain without guards — refuses a deleted client's tokens on
18
+ * the next request, with the cloud's copy. A store fault propagates as the
19
+ * infrastructure fault it is, never as a revocation.
20
+ *
21
+ * Composed between `apikey` and `oidc`, only under an authentication
22
+ * posture (compose.ts): the OIDC verifier claims every JWT-shaped token and
23
+ * throws on one it cannot verify, so a platform token must be claimed
24
+ * before it gets there (stigmer#1137's lesson).
25
+ *
26
+ * The identity is the account the token was minted for: `sub` IS the
27
+ * account id (the mint signs it), so no account read is needed; class
28
+ * `user`, issuer "stigmer", the token carried (the memory-capture gate and
29
+ * the origin guard read its `platform_client_id`), and the email and name
30
+ * the platform asserted, for display only.
31
+ */
32
+ import { Code, ConnectError } from "@connectrpc/connect";
33
+ import { PLATFORM_TOKEN_ISSUER, platformTokenRefusalError, stringClaim, verifyPlatformToken, } from "../../platformtoken/envelope.js";
34
+ import { DELETED_CLIENT_MESSAGE, TOKEN_NAMES_NO_CLIENT_MESSAGE, USER_TOKEN_CLAIMS, } from "./constants.js";
35
+ export function newPlatformClientTokenVerifier(deps) {
36
+ return {
37
+ name: "platform-client",
38
+ async verify(token) {
39
+ const result = verifyPlatformToken(deps.keys, token, deps.now?.());
40
+ switch (result.outcome) {
41
+ case "foreign":
42
+ return null;
43
+ case "refused":
44
+ throw platformTokenRefusalError(result.refusal);
45
+ case "verified":
46
+ break;
47
+ default: {
48
+ const exhaustive = result;
49
+ throw new Error(`unknown verification ${JSON.stringify(exhaustive)}`);
50
+ }
51
+ }
52
+ const verified = result.token;
53
+ if (verified.tokenType !== undefined) {
54
+ return null;
55
+ }
56
+ const platformClientId = stringClaim(verified.payload, USER_TOKEN_CLAIMS.platformClientId);
57
+ if (platformClientId === undefined) {
58
+ throw new ConnectError(TOKEN_NAMES_NO_CLIENT_MESSAGE, Code.Unauthenticated);
59
+ }
60
+ if ((await deps.clients.findById(platformClientId)) === undefined) {
61
+ throw new ConnectError(DELETED_CLIENT_MESSAGE, Code.Unauthenticated);
62
+ }
63
+ const email = stringClaim(verified.payload, USER_TOKEN_CLAIMS.email);
64
+ const displayName = stringClaim(verified.payload, USER_TOKEN_CLAIMS.name);
65
+ return {
66
+ identityId: verified.subject,
67
+ callerClass: "user",
68
+ issuer: PLATFORM_TOKEN_ISSUER,
69
+ rawToken: token,
70
+ ...(email !== undefined ? { email } : {}),
71
+ ...(displayName !== undefined ? { displayName } : {}),
72
+ };
73
+ },
74
+ };
75
+ }
76
+ //# sourceMappingURL=verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.js","sourceRoot":"","sources":["../../../src/domain/platformclient/verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAMzD,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,mBAAmB,GACpB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,sBAAsB,EACtB,6BAA6B,EAC7B,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AASxB,MAAM,UAAU,8BAA8B,CAC5C,IAAqC;IAErC,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,KAAK,CAAC,MAAM,CAAC,KAAa;YACxB,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACnE,QAAQ,MAAM,CAAC,OAAO,EAAE,CAAC;gBACvB,KAAK,SAAS;oBACZ,OAAO,IAAI,CAAC;gBACd,KAAK,SAAS;oBACZ,MAAM,yBAAyB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAClD,KAAK,UAAU;oBACb,MAAM;gBACR,OAAO,CAAC,CAAC,CAAC;oBACR,MAAM,UAAU,GAAU,MAAM,CAAC;oBACjC,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC;YAC9B,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;gBACrC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,gBAAgB,GAAG,WAAW,CAClC,QAAQ,CAAC,OAAO,EAChB,iBAAiB,CAAC,gBAAgB,CACnC,CAAC;YACF,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;gBACnC,MAAM,IAAI,YAAY,CACpB,6BAA6B,EAC7B,IAAI,CAAC,eAAe,CACrB,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;gBAClE,MAAM,IAAI,YAAY,CAAC,sBAAsB,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;YACvE,CAAC;YACD,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;YACrE,MAAM,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAC1E,OAAO;gBACL,UAAU,EAAE,QAAQ,CAAC,OAAO;gBAC5B,WAAW,EAAE,MAAM;gBACnB,MAAM,EAAE,qBAAqB;gBAC7B,QAAQ,EAAE,KAAK;gBACf,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzC,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtD,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** The label the channel lanes stamp on every session they open. */
2
+ export declare const SESSION_CHANNEL_ID_LABEL = "stigmer.ai/channel-id";
3
+ export declare const sessionListIndex: import("../../store/list-index.js").ListIndexDeclaration<"agent_instance" | "channel">;
4
+ //# sourceMappingURL=list-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-index.d.ts","sourceRoot":"","sources":["../../../src/domain/session/list-index.ts"],"names":[],"mappings":"AAgBA,oEAAoE;AACpE,eAAO,MAAM,wBAAwB,0BAA0B,CAAC;AAEhE,eAAO,MAAM,gBAAgB,wFAQ3B,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The session list index (store/list-index.ts): `agent_instance` is the
3
+ * key `listByAgentInstance` reads, `channel` the one `listByChannel` reads
4
+ * (the channel's id is stamped as a label by the channel lanes, not held
5
+ * in the spec). A session belongs to one organization, which is every
6
+ * declaration's first fact, so `session.list` narrows by it when the
7
+ * request names one.
8
+ *
9
+ * A change to `keys` bumps `revision` (boot/__tests__/list-indexes.test.ts
10
+ * pins the pair).
11
+ */
12
+ import { SessionSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
13
+ import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
14
+ import { declareListIndex, field, label } from "../../store/list-index.js";
15
+ /** The label the channel lanes stamp on every session they open. */
16
+ export const SESSION_CHANNEL_ID_LABEL = "stigmer.ai/channel-id";
17
+ export const sessionListIndex = declareListIndex({
18
+ kind: ApiResourceKind.session,
19
+ schema: SessionSchema,
20
+ revision: 1,
21
+ keys: {
22
+ agent_instance: field("spec.agent_instance_id"),
23
+ channel: label(SESSION_CHANNEL_ID_LABEL),
24
+ },
25
+ });
26
+ //# sourceMappingURL=list-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-index.js","sourceRoot":"","sources":["../../../src/domain/session/list-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,qFAAqF,CAAC;AAEtH,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAE3E,oEAAoE;AACpE,MAAM,CAAC,MAAM,wBAAwB,GAAG,uBAAuB,CAAC;AAEhE,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;IAC/C,IAAI,EAAE,eAAe,CAAC,OAAO;IAC7B,MAAM,EAAE,aAAa;IACrB,QAAQ,EAAE,CAAC;IACX,IAAI,EAAE;QACJ,cAAc,EAAE,KAAK,CAAC,wBAAwB,CAAC;QAC/C,OAAO,EAAE,KAAK,CAAC,wBAAwB,CAAC;KACzC;CACF,CAAC,CAAC"}
@@ -31,14 +31,13 @@ export declare function newRejectDeleteWithActiveExecutionsStep<Desc extends Des
31
31
  */
32
32
  export declare function newCascadeDeleteAgentExecutionsStep<Desc extends DescMessage>(store: Store, logger: Logger): PipelineStep<Desc>;
33
33
  /**
34
- * ListAllSessions — all sessions, newest first by spec-audit created_at
35
- * (seconds then nanos; timestamped entries before untimestamped ones).
36
- * Malformed rows warn and are skipped.
34
+ * ListAllSessions — one page of sessions, the request's organization when
35
+ * it names one, newest first. Malformed rows warn and are skipped.
37
36
  */
38
37
  export declare function newListAllSessionsStep(store: Store, logger: Logger, listReadScope: ListReadScope | undefined): PipelineStep<typeof SessionQueryController.method.list.input>;
39
38
  /**
40
- * FilterByAgentInstance — steps/filter_by_agent_instance.go: sessions
41
- * whose spec.agent_instance_id matches. No sorting (Go doesn't sort here).
39
+ * FilterByAgentInstance — steps/filter_by_agent_instance.go: one page of
40
+ * the sessions whose spec.agent_instance_id matches, newest first.
42
41
  */
43
42
  export declare function newFilterByAgentInstanceStep(store: Store, logger: Logger, listReadScope: ListReadScope | undefined): PipelineStep<typeof SessionQueryController.method.listByAgentInstance.input>;
44
43
  /**
@@ -54,9 +53,9 @@ export declare function newFilterByAgentInstanceStep(store: Store, logger: Logge
54
53
  */
55
54
  export declare function newAuthorizeChannelAccessStep(authorizer: Authorizer): PipelineStep<typeof SessionQueryController.method.listByChannel.input>;
56
55
  /**
57
- * FilterByChannel — steps/filter_by_channel.go: sessions whose
58
- * metadata.labels carry the channel's stigmer.ai/channel-id stamp. No
59
- * sorting. Channel sessions are created by the cloud channel runtime
56
+ * FilterByChannel — steps/filter_by_channel.go: one page of the sessions
57
+ * whose metadata.labels carry the channel's stigmer.ai/channel-id stamp,
58
+ * newest first. Channel sessions are created by the cloud channel runtime
60
59
  * (Slack/WhatsApp inbound turns), which stamps the label at create time;
61
60
  * the OSS runtime has no channel broker, so this filter typically matches
62
61
  * nothing — the RPC exists for contract parity with Stigmer Cloud (which
@@ -1 +1 @@
1
- {"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../../src/domain/session/steps.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKtD,OAAO,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAOrF,OAAO,EAAE,sBAAsB,EAAE,MAAM,wDAAwD,CAAC;AAIhG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AAMzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAOzE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAEtD,KAAK,WAAW,GAAG,OAAO,aAAa,CAAC;AAExC,0DAA0D;AAC1D,eAAO,MAAM,eAAe,eAAe,CAAC;AAoB5C,wBAAgB,kCAAkC,IAAI,YAAY,CAAC,WAAW,CAAC,CAyC9E;AAkCD,wBAAgB,0CAA0C,CACxD,cAAc,EAAE,4BAA4B,GAC3C,YAAY,CAAC,WAAW,CAAC,CAqC3B;AAuBD,wBAAgB,gCAAgC,IAAI,YAAY,CAAC,WAAW,CAAC,CA+B5E;AAiED;;;;;;;GAOG;AACH,wBAAgB,uCAAuC,CACrD,IAAI,SAAS,WAAW,EACxB,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CA8BlD;AAED;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CAAC,IAAI,SAAS,WAAW,EAC1E,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,GACb,YAAY,CAAC,IAAI,CAAC,CAiDpB;AA4BD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,GAAG,SAAS,GACvC,YAAY,CAAC,OAAO,sBAAsB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CA6B/D;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,GAAG,SAAS,GACvC,YAAY,CACb,OAAO,sBAAsB,CAAC,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAC/D,CA2CA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,UAAU,GACrB,YAAY,CAAC,OAAO,sBAAsB,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAgBxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,GAAG,SAAS,GACvC,YAAY,CAAC,OAAO,sBAAsB,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CA2CxE"}
1
+ {"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../../src/domain/session/steps.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKtD,OAAO,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAQrF,OAAO,EAAE,sBAAsB,EAAE,MAAM,wDAAwD,CAAC;AAIhG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AAMzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAWzE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAKtD,KAAK,WAAW,GAAG,OAAO,aAAa,CAAC;AAExC,0DAA0D;AAC1D,eAAO,MAAM,eAAe,eAAe,CAAC;AAa5C,wBAAgB,kCAAkC,IAAI,YAAY,CAAC,WAAW,CAAC,CAyC9E;AAkCD,wBAAgB,0CAA0C,CACxD,cAAc,EAAE,4BAA4B,GAC3C,YAAY,CAAC,WAAW,CAAC,CAqC3B;AAuBD,wBAAgB,gCAAgC,IAAI,YAAY,CAAC,WAAW,CAAC,CA+B5E;AA+DD;;;;;;;GAOG;AACH,wBAAgB,uCAAuC,CACrD,IAAI,SAAS,WAAW,EACxB,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CA8BlD;AAED;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CAAC,IAAI,SAAS,WAAW,EAC1E,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,GACb,YAAY,CAAC,IAAI,CAAC,CAiDpB;AA6BD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,GAAG,SAAS,GACvC,YAAY,CAAC,OAAO,sBAAsB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAyB/D;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,GAAG,SAAS,GACvC,YAAY,CACb,OAAO,sBAAsB,CAAC,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAC/D,CA+BA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,UAAU,GACrB,YAAY,CAAC,OAAO,sBAAsB,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAgBxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,GAAG,SAAS,GACvC,YAAY,CAAC,OAAO,sBAAsB,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CA4BxE"}
@@ -28,16 +28,12 @@ import { failedPreconditionError, internalError, invalidArgumentError, } from ".
28
28
  import { restrictListByReadScope } from "../../extensions/list-read-scope.js";
29
29
  import { newAuthorizeResolvedTargetStep } from "../../pipeline/steps/authorize-resolved-target.js";
30
30
  import { RESOURCE_ID_KEY } from "../../pipeline/steps/delete.js";
31
- import { compareCreatedAtDesc } from "../../pipeline/steps/helpers.js";
31
+ import { listPageFingerprint, readListPage, } from "../../pipeline/steps/list-page.js";
32
32
  import { EXISTING_RESOURCE_KEY } from "../../pipeline/steps/load-existing.js";
33
+ import { agentExecutionListIndex } from "../agentexecution/list-index.js";
34
+ import { sessionListIndex } from "./list-index.js";
33
35
  /** Context key for the list result (Go listResultKey). */
34
36
  export const LIST_RESULT_KEY = "listResult";
35
- /**
36
- * The session label the channel runtime stamps at create time to record
37
- * which agent channel originated the conversation. Mirrors
38
- * ChannelRuntimeConstants.CHANNEL_ID_METADATA_KEY in Stigmer Cloud.
39
- */
40
- const CHANNEL_ID_LABEL_KEY = "stigmer.ai/channel-id";
41
37
  // ---------------------------------------------------------------------------
42
38
  // ValidateHarnessImmutability — validate_harness_immutability.go: rejects
43
39
  // session updates that attempt to change the harness after the session has
@@ -213,32 +209,30 @@ function isActiveExecutionPhase(phase) {
213
209
  }
214
210
  }
215
211
  /**
216
- * Loads every agent execution whose spec.session_id matches the given
217
- * session; malformed rows warn and are skipped. Shared by the guard and
218
- * cascade steps (Go listExecutionsBySession).
212
+ * Every agent execution of the given session, through the list index's
213
+ * session key (exact whoever wrote the rows, store/interface.ts); malformed
214
+ * rows warn and are skipped. Shared by the guard and cascade steps (Go
215
+ * listExecutionsBySession).
219
216
  */
220
217
  async function listExecutionsBySession(store, logger, sessionId) {
221
218
  let rows;
222
219
  try {
223
- rows = await store.listResources(ApiResourceKind.agent_execution);
220
+ rows = await store.queryResources(agentExecutionListIndex, {
221
+ anyKey: [{ name: "session", value: sessionId }],
222
+ });
224
223
  }
225
224
  catch (error) {
226
225
  throw internalError(error, "failed to list agent executions");
227
226
  }
228
227
  const executions = [];
229
- for (const data of rows) {
230
- let execution;
228
+ for (const row of rows) {
231
229
  try {
232
- execution = fromBinary(AgentExecutionSchema, data);
230
+ executions.push(fromBinary(AgentExecutionSchema, row.data));
233
231
  }
234
232
  catch (error) {
235
233
  logger.warn("Failed to unmarshal execution, skipping", {
236
234
  error: error instanceof Error ? error.message : String(error),
237
235
  });
238
- continue;
239
- }
240
- if ((execution.spec?.sessionId ?? "") === sessionId) {
241
- executions.push(execution);
242
236
  }
243
237
  }
244
238
  return executions;
@@ -320,33 +314,39 @@ function requireSessionId(ctx) {
320
314
  return sessionId;
321
315
  }
322
316
  // ---------------------------------------------------------------------------
323
- // List steps — list.go and the steps/ package. Full scans with client-side
324
- // filtering, exactly Go (no pagination; no scope composed = no authorization
325
- // filtering, the OSS single-user posture). With a composed ListReadScope
326
- // (20260830.01) each lane narrows to the caller's authorized sessions —
317
+ // List steps — list.go and the steps/ package. Each lane reads its page
318
+ // through the list index (pipeline/steps/list-page.ts): the store narrows
319
+ // by the request's organization or parent key and orders newest first
320
+ // (spec-audit created_at, unstamped last, ties by id); the read scope, when
321
+ // composed, narrows each batch to the caller's authorized sessions last —
327
322
  // the Java list handlers' FGA-ids pattern, guest cookie rule included
328
- // driver-side; the request org is deliberately NOT intersected (the Java
329
- // session lanes never consult it — census lanes 1–3).
323
+ // driver-side. No scope composed = the OSS single-user posture, every
324
+ // matching session.
330
325
  // ---------------------------------------------------------------------------
331
326
  /**
332
- * ListAllSessions — all sessions, newest first by spec-audit created_at
333
- * (seconds then nanos; timestamped entries before untimestamped ones).
334
- * Malformed rows warn and are skipped.
327
+ * ListAllSessions — one page of sessions, the request's organization when
328
+ * it names one, newest first. Malformed rows warn and are skipped.
335
329
  */
336
330
  export function newListAllSessionsStep(store, logger, listReadScope) {
337
331
  return {
338
332
  name: "ListAllSessions",
339
333
  async execute(ctx) {
340
- const sessions = await restrictListByReadScope(listReadScope, ctx.callerIdentity, ApiResourceKind.session, await loadAllSessions(store, logger, ctx.apiResourceKind), "");
341
- sessions.sort((a, b) => compareCreatedAtDesc(a.status?.audit?.specAudit?.createdAt, b.status?.audit?.specAudit?.createdAt));
342
- logger.info("Loaded sessions from database", { count: sessions.length });
343
- ctx.set(LIST_RESULT_KEY, create(SessionListSchema, { entries: sessions }));
334
+ const input = ctx.input;
335
+ const page = await readSessionPage(store, logger, listReadScope, ctx.callerIdentity, ctx.input, {
336
+ query: { org: input.org },
337
+ fingerprint: {
338
+ lane: "session.list",
339
+ org: input.org,
340
+ tags: input.tags,
341
+ },
342
+ });
343
+ ctx.set(LIST_RESULT_KEY, page);
344
344
  },
345
345
  };
346
346
  }
347
347
  /**
348
- * FilterByAgentInstance — steps/filter_by_agent_instance.go: sessions
349
- * whose spec.agent_instance_id matches. No sorting (Go doesn't sort here).
348
+ * FilterByAgentInstance — steps/filter_by_agent_instance.go: one page of
349
+ * the sessions whose spec.agent_instance_id matches, newest first.
350
350
  */
351
351
  export function newFilterByAgentInstanceStep(store, logger, listReadScope) {
352
352
  return {
@@ -356,16 +356,15 @@ export function newFilterByAgentInstanceStep(store, logger, listReadScope) {
356
356
  if (agentInstanceId === "") {
357
357
  throw invalidArgumentError("agent_instance_id is required");
358
358
  }
359
- // The instance's sessions first, the scope last (census lane 2): a
360
- // composed driver is asked about one instance's rows, not the kind.
361
- const sessions = await loadAllSessions(store, logger, ctx.apiResourceKind);
362
- const filtered = await restrictListByReadScope(listReadScope, ctx.callerIdentity, ApiResourceKind.session, sessions.filter((session) => (session.spec?.agentInstanceId ?? "") === agentInstanceId), "");
363
- logger.info("Filtered sessions by agent instance", {
364
- agentInstanceId,
365
- totalSessions: sessions.length,
366
- filteredSessions: filtered.length,
359
+ // The instance's sessions through its key, the scope last (census
360
+ // lane 2): a composed driver is asked about one instance's rows.
361
+ const page = await readSessionPage(store, logger, listReadScope, ctx.callerIdentity, ctx.input, {
362
+ query: {
363
+ anyKey: [{ name: "agent_instance", value: agentInstanceId }],
364
+ },
365
+ fingerprint: { lane: "session.listByAgentInstance", agentInstanceId },
367
366
  });
368
- ctx.set(LIST_RESULT_KEY, create(SessionListSchema, { entries: filtered }));
367
+ ctx.set(LIST_RESULT_KEY, page);
369
368
  },
370
369
  };
371
370
  }
@@ -393,9 +392,9 @@ export function newAuthorizeChannelAccessStep(authorizer) {
393
392
  ], "AuthorizeChannelAccess");
394
393
  }
395
394
  /**
396
- * FilterByChannel — steps/filter_by_channel.go: sessions whose
397
- * metadata.labels carry the channel's stigmer.ai/channel-id stamp. No
398
- * sorting. Channel sessions are created by the cloud channel runtime
395
+ * FilterByChannel — steps/filter_by_channel.go: one page of the sessions
396
+ * whose metadata.labels carry the channel's stigmer.ai/channel-id stamp,
397
+ * newest first. Channel sessions are created by the cloud channel runtime
399
398
  * (Slack/WhatsApp inbound turns), which stamps the label at create time;
400
399
  * the OSS runtime has no channel broker, so this filter typically matches
401
400
  * nothing — the RPC exists for contract parity with Stigmer Cloud (which
@@ -410,42 +409,41 @@ export function newFilterByChannelStep(store, logger, listReadScope) {
410
409
  if (channelId === "") {
411
410
  throw invalidArgumentError("channel_id is required");
412
411
  }
413
- // The channel's sessions first, the scope last (census lane 3).
414
- const sessions = await loadAllSessions(store, logger, ctx.apiResourceKind);
415
- const filtered = await restrictListByReadScope(listReadScope, ctx.callerIdentity, ApiResourceKind.session, sessions.filter((session) => (session.metadata?.labels ?? {})[CHANNEL_ID_LABEL_KEY] ===
416
- channelId), "");
417
- logger.info("Filtered sessions by channel", {
418
- channelId,
419
- totalSessions: sessions.length,
420
- filteredSessions: filtered.length,
412
+ // The channel's sessions through its key, the scope last (census lane 3).
413
+ const page = await readSessionPage(store, logger, listReadScope, ctx.callerIdentity, ctx.input, {
414
+ query: { anyKey: [{ name: "channel", value: channelId }] },
415
+ fingerprint: { lane: "session.listByChannel", channelId },
421
416
  });
422
- ctx.set(LIST_RESULT_KEY, create(SessionListSchema, { entries: filtered }));
417
+ ctx.set(LIST_RESULT_KEY, page);
423
418
  },
424
419
  };
425
420
  }
426
- /** Full-scan session load shared by the list steps; malformed rows warn + skip. */
427
- async function loadAllSessions(store, logger, kind) {
428
- let rows;
429
- try {
430
- rows = await store.listResources(kind);
431
- }
432
- catch (error) {
433
- throw internalError(error, "failed to list sessions");
434
- }
435
- const sessions = [];
436
- for (const data of rows) {
437
- let session;
438
- try {
439
- session = fromBinary(SessionSchema, data);
440
- }
441
- catch (error) {
442
- logger.warn("Failed to unmarshal session, skipping", {
443
- error: error instanceof Error ? error.message : String(error),
444
- });
445
- continue;
446
- }
447
- sessions.push(session);
448
- }
449
- return sessions;
421
+ /** The three session lanes' shared read: one page, the scope last, as a SessionList. */
422
+ async function readSessionPage(store, logger, listReadScope, caller, request, lane) {
423
+ const page = await readListPage({
424
+ store,
425
+ declaration: sessionListIndex,
426
+ query: lane.query,
427
+ request,
428
+ fingerprint: listPageFingerprint(lane.fingerprint),
429
+ decode: (data) => {
430
+ try {
431
+ return fromBinary(SessionSchema, data);
432
+ }
433
+ catch (error) {
434
+ logger.warn("Failed to unmarshal session, skipping", {
435
+ error: error instanceof Error ? error.message : String(error),
436
+ });
437
+ return undefined;
438
+ }
439
+ },
440
+ scope: (sessions) => restrictListByReadScope(listReadScope, caller, ApiResourceKind.session, sessions, ""),
441
+ failure: "failed to list sessions",
442
+ });
443
+ return create(SessionListSchema, {
444
+ entries: page.entries,
445
+ nextPageToken: page.nextPageToken,
446
+ totalPages: page.nextPageToken === "" ? 1 : 0,
447
+ });
450
448
  }
451
449
  //# sourceMappingURL=steps.js.map