@selvajs/platform 0.21.0-beta.2 → 1.0.0-beta.4

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 (362) hide show
  1. package/README.md +10 -7
  2. package/dist/access/index.d.ts +1 -2
  3. package/dist/access/index.js +1 -2
  4. package/dist/access/rules.d.ts +11 -12
  5. package/dist/access/rules.js +27 -23
  6. package/dist/apiTokens/index.d.ts +2 -3
  7. package/dist/apiTokens/index.js +2 -3
  8. package/dist/apiTokens/interface.d.ts +0 -1
  9. package/dist/apiTokens/interface.js +0 -1
  10. package/dist/apiTokens/scope.d.ts +3 -2
  11. package/dist/apiTokens/scope.js +9 -5
  12. package/dist/apiTokens/types.d.ts +7 -2
  13. package/dist/apiTokens/types.js +10 -5
  14. package/dist/auth/index.d.ts +0 -1
  15. package/dist/auth/index.js +0 -1
  16. package/dist/auth/interface.d.ts +4 -23
  17. package/dist/auth/interface.js +0 -1
  18. package/dist/auth/types.d.ts +4 -2
  19. package/dist/auth/types.js +0 -1
  20. package/dist/bindings/index.d.ts +0 -1
  21. package/dist/bindings/index.js +0 -1
  22. package/dist/bindings/interface.d.ts +0 -1
  23. package/dist/bindings/interface.js +0 -1
  24. package/dist/computeServer/index.d.ts +1 -7
  25. package/dist/computeServer/index.js +2 -8
  26. package/dist/computeServer/interface.d.ts +9 -6
  27. package/dist/computeServer/interface.js +0 -1
  28. package/dist/computeServer/public.d.ts +6 -0
  29. package/dist/computeServer/public.js +2 -0
  30. package/dist/computeServer/secrets.d.ts +12 -6
  31. package/dist/computeServer/secrets.js +35 -15
  32. package/dist/computeServer/types.d.ts +5 -2
  33. package/dist/computeServer/types.js +4 -1
  34. package/dist/computeServer/utils.d.ts +17 -6
  35. package/dist/computeServer/utils.js +31 -21
  36. package/dist/config.d.ts +1 -2
  37. package/dist/config.js +0 -1
  38. package/dist/context.d.ts +12 -1
  39. package/dist/context.js +51 -2
  40. package/dist/data/index.d.ts +0 -1
  41. package/dist/data/index.js +0 -1
  42. package/dist/data/interface.d.ts +0 -1
  43. package/dist/data/interface.js +0 -1
  44. package/dist/definitions/index.d.ts +2 -3
  45. package/dist/definitions/index.js +2 -3
  46. package/dist/definitions/interface.d.ts +0 -1
  47. package/dist/definitions/interface.js +0 -1
  48. package/dist/definitions/paths.d.ts +0 -1
  49. package/dist/definitions/paths.js +1 -12
  50. package/dist/definitions/schemas.d.ts +2 -21
  51. package/dist/definitions/schemas.js +10 -19
  52. package/dist/definitions/types.d.ts +12 -4
  53. package/dist/definitions/types.js +1 -3
  54. package/dist/errors/interface.d.ts +1 -2
  55. package/dist/errors/interface.js +0 -1
  56. package/dist/errors.d.ts +8 -1
  57. package/dist/errors.js +11 -1
  58. package/dist/events/audit.d.ts +1 -2
  59. package/dist/events/audit.js +0 -1
  60. package/dist/events/index.d.ts +0 -1
  61. package/dist/events/index.js +0 -1
  62. package/dist/events/interface.d.ts +0 -1
  63. package/dist/events/interface.js +0 -1
  64. package/dist/index.d.ts +18 -61
  65. package/dist/index.js +18 -24
  66. package/dist/invites/index.d.ts +0 -1
  67. package/dist/invites/index.js +0 -1
  68. package/dist/invites/interface.d.ts +5 -6
  69. package/dist/invites/interface.js +0 -1
  70. package/dist/invites/types.d.ts +0 -1
  71. package/dist/invites/types.js +0 -1
  72. package/dist/logging/interface.d.ts +0 -1
  73. package/dist/logging/interface.js +0 -1
  74. package/dist/metrics/interface.d.ts +0 -1
  75. package/dist/metrics/interface.js +0 -1
  76. package/dist/notifications/index.d.ts +0 -1
  77. package/dist/notifications/index.js +0 -1
  78. package/dist/notifications/interface.d.ts +1 -3
  79. package/dist/notifications/interface.js +1 -3
  80. package/dist/notifications/types.d.ts +0 -1
  81. package/dist/notifications/types.js +0 -1
  82. package/dist/organizations/index.d.ts +2 -3
  83. package/dist/organizations/index.js +1 -2
  84. package/dist/organizations/interface.d.ts +3 -5
  85. package/dist/organizations/interface.js +0 -1
  86. package/dist/organizations/paths.d.ts +1 -6
  87. package/dist/organizations/paths.js +2 -20
  88. package/dist/organizations/schemas.d.ts +5 -7
  89. package/dist/organizations/schemas.js +20 -13
  90. package/dist/organizations/types.d.ts +0 -1
  91. package/dist/organizations/types.js +0 -1
  92. package/dist/pagination.d.ts +11 -3
  93. package/dist/pagination.js +15 -1
  94. package/dist/permissions/index.d.ts +2 -2
  95. package/dist/permissions/index.js +2 -2
  96. package/dist/permissions/interface.d.ts +4 -4
  97. package/dist/permissions/interface.js +0 -1
  98. package/dist/permissions/types.d.ts +0 -1
  99. package/dist/permissions/types.js +0 -1
  100. package/dist/platformProjects/index.d.ts +1 -3
  101. package/dist/platformProjects/index.js +1 -2
  102. package/dist/platformProjects/interface.d.ts +0 -1
  103. package/dist/platformProjects/interface.js +0 -1
  104. package/dist/platformProjects/schemas.d.ts +0 -1
  105. package/dist/platformProjects/schemas.js +0 -1
  106. package/dist/platformProjects/types.d.ts +3 -2
  107. package/dist/platformProjects/types.js +0 -1
  108. package/dist/projects/index.d.ts +0 -1
  109. package/dist/projects/index.js +0 -1
  110. package/dist/projects/interface.d.ts +0 -1
  111. package/dist/projects/interface.js +0 -1
  112. package/dist/projects/schemas.d.ts +0 -1
  113. package/dist/projects/schemas.js +0 -1
  114. package/dist/projects/types.d.ts +0 -1
  115. package/dist/projects/types.js +0 -1
  116. package/dist/shareLinks/index.d.ts +0 -1
  117. package/dist/shareLinks/index.js +0 -1
  118. package/dist/shareLinks/interface.d.ts +6 -3
  119. package/dist/shareLinks/interface.js +0 -1
  120. package/dist/shareLinks/schemas.d.ts +0 -1
  121. package/dist/shareLinks/schemas.js +4 -2
  122. package/dist/shareLinks/types.d.ts +0 -1
  123. package/dist/shareLinks/types.js +0 -1
  124. package/dist/solveCache/interface.d.ts +2 -3
  125. package/dist/solveCache/interface.js +0 -1
  126. package/dist/storage/assetClasses.d.ts +4 -8
  127. package/dist/storage/assetClasses.js +6 -21
  128. package/dist/storage/cacheBust.d.ts +0 -1
  129. package/dist/storage/cacheBust.js +5 -3
  130. package/dist/storage/image.d.ts +8 -5
  131. package/dist/storage/image.js +74 -12
  132. package/dist/storage/index.d.ts +2 -4
  133. package/dist/storage/index.js +2 -3
  134. package/dist/storage/interface.d.ts +11 -3
  135. package/dist/storage/interface.js +0 -1
  136. package/dist/storage/safeKey.d.ts +7 -0
  137. package/dist/storage/safeKey.js +12 -0
  138. package/dist/testing/index.d.ts +5 -2
  139. package/dist/testing/index.js +3 -2
  140. package/dist/testing/suites/apiTokenStoreSuite.d.ts +0 -1
  141. package/dist/testing/suites/apiTokenStoreSuite.js +0 -1
  142. package/dist/testing/suites/auditQuerySuite.d.ts +18 -0
  143. package/dist/testing/suites/auditQuerySuite.js +73 -0
  144. package/dist/testing/suites/authProviderSuite.d.ts +14 -3
  145. package/dist/testing/suites/authProviderSuite.js +57 -32
  146. package/dist/testing/suites/computeServerStoreSuite.d.ts +1 -2
  147. package/dist/testing/suites/computeServerStoreSuite.js +68 -4
  148. package/dist/testing/suites/definitionStoreSuite.d.ts +2 -1
  149. package/dist/testing/suites/definitionStoreSuite.js +48 -16
  150. package/dist/testing/suites/emailLinkAuthSuite.d.ts +2 -5
  151. package/dist/testing/suites/emailLinkAuthSuite.js +1 -9
  152. package/dist/testing/suites/eventSinkSuite.d.ts +0 -1
  153. package/dist/testing/suites/eventSinkSuite.js +9 -1
  154. package/dist/testing/suites/helpers.d.ts +5 -1
  155. package/dist/testing/suites/helpers.js +7 -1
  156. package/dist/testing/suites/inviteStoreSuite.d.ts +0 -1
  157. package/dist/testing/suites/inviteStoreSuite.js +17 -7
  158. package/dist/testing/suites/oauthAuthSuite.d.ts +18 -0
  159. package/dist/testing/suites/oauthAuthSuite.js +26 -0
  160. package/dist/testing/suites/orgStoreSuite.d.ts +5 -1
  161. package/dist/testing/suites/orgStoreSuite.js +26 -7
  162. package/dist/testing/suites/platformPermissionStoreSuite.d.ts +0 -5
  163. package/dist/testing/suites/platformPermissionStoreSuite.js +12 -63
  164. package/dist/testing/suites/platformProjectGrantStoreSuite.d.ts +0 -1
  165. package/dist/testing/suites/platformProjectGrantStoreSuite.js +0 -5
  166. package/dist/testing/suites/projectStoreSuite.d.ts +5 -1
  167. package/dist/testing/suites/projectStoreSuite.js +6 -6
  168. package/dist/testing/suites/shareLinkStoreSuite.d.ts +2 -1
  169. package/dist/testing/suites/shareLinkStoreSuite.js +22 -25
  170. package/dist/testing/suites/solveMetricSinkSuite.d.ts +0 -1
  171. package/dist/testing/suites/solveMetricSinkSuite.js +2 -2
  172. package/dist/testing/suites/storageProviderSuite.d.ts +0 -1
  173. package/dist/testing/suites/storageProviderSuite.js +15 -10
  174. package/dist/testing/suites/userProfileStoreSuite.d.ts +1 -2
  175. package/dist/testing/suites/userProfileStoreSuite.js +42 -7
  176. package/dist/userProfile/index.d.ts +2 -2
  177. package/dist/userProfile/index.js +2 -2
  178. package/dist/userProfile/interface.d.ts +5 -6
  179. package/dist/userProfile/interface.js +0 -1
  180. package/dist/userProfile/types.d.ts +2 -1
  181. package/dist/userProfile/types.js +2 -1
  182. package/dist/utils/audit.d.ts +0 -1
  183. package/dist/utils/audit.js +0 -1
  184. package/dist/utils/index.d.ts +0 -2
  185. package/dist/utils/index.js +0 -1
  186. package/package.json +7 -6
  187. package/dist/access/index.d.ts.map +0 -1
  188. package/dist/access/index.js.map +0 -1
  189. package/dist/access/rules.d.ts.map +0 -1
  190. package/dist/access/rules.js.map +0 -1
  191. package/dist/apiTokens/index.d.ts.map +0 -1
  192. package/dist/apiTokens/index.js.map +0 -1
  193. package/dist/apiTokens/interface.d.ts.map +0 -1
  194. package/dist/apiTokens/interface.js.map +0 -1
  195. package/dist/apiTokens/scope.d.ts.map +0 -1
  196. package/dist/apiTokens/scope.js.map +0 -1
  197. package/dist/apiTokens/types.d.ts.map +0 -1
  198. package/dist/apiTokens/types.js.map +0 -1
  199. package/dist/auth/index.d.ts.map +0 -1
  200. package/dist/auth/index.js.map +0 -1
  201. package/dist/auth/interface.d.ts.map +0 -1
  202. package/dist/auth/interface.js.map +0 -1
  203. package/dist/auth/types.d.ts.map +0 -1
  204. package/dist/auth/types.js.map +0 -1
  205. package/dist/bindings/index.d.ts.map +0 -1
  206. package/dist/bindings/index.js.map +0 -1
  207. package/dist/bindings/interface.d.ts.map +0 -1
  208. package/dist/bindings/interface.js.map +0 -1
  209. package/dist/computeServer/index.d.ts.map +0 -1
  210. package/dist/computeServer/index.js.map +0 -1
  211. package/dist/computeServer/interface.d.ts.map +0 -1
  212. package/dist/computeServer/interface.js.map +0 -1
  213. package/dist/computeServer/secrets.d.ts.map +0 -1
  214. package/dist/computeServer/secrets.js.map +0 -1
  215. package/dist/computeServer/types.d.ts.map +0 -1
  216. package/dist/computeServer/types.js.map +0 -1
  217. package/dist/computeServer/utils.d.ts.map +0 -1
  218. package/dist/computeServer/utils.js.map +0 -1
  219. package/dist/config.d.ts.map +0 -1
  220. package/dist/config.js.map +0 -1
  221. package/dist/context.d.ts.map +0 -1
  222. package/dist/context.js.map +0 -1
  223. package/dist/data/index.d.ts.map +0 -1
  224. package/dist/data/index.js.map +0 -1
  225. package/dist/data/interface.d.ts.map +0 -1
  226. package/dist/data/interface.js.map +0 -1
  227. package/dist/definitions/index.d.ts.map +0 -1
  228. package/dist/definitions/index.js.map +0 -1
  229. package/dist/definitions/interface.d.ts.map +0 -1
  230. package/dist/definitions/interface.js.map +0 -1
  231. package/dist/definitions/paths.d.ts.map +0 -1
  232. package/dist/definitions/paths.js.map +0 -1
  233. package/dist/definitions/schemas.d.ts.map +0 -1
  234. package/dist/definitions/schemas.js.map +0 -1
  235. package/dist/definitions/types.d.ts.map +0 -1
  236. package/dist/definitions/types.js.map +0 -1
  237. package/dist/errors/interface.d.ts.map +0 -1
  238. package/dist/errors/interface.js.map +0 -1
  239. package/dist/errors.d.ts.map +0 -1
  240. package/dist/errors.js.map +0 -1
  241. package/dist/events/audit.d.ts.map +0 -1
  242. package/dist/events/audit.js.map +0 -1
  243. package/dist/events/index.d.ts.map +0 -1
  244. package/dist/events/index.js.map +0 -1
  245. package/dist/events/interface.d.ts.map +0 -1
  246. package/dist/events/interface.js.map +0 -1
  247. package/dist/index.d.ts.map +0 -1
  248. package/dist/index.js.map +0 -1
  249. package/dist/invites/index.d.ts.map +0 -1
  250. package/dist/invites/index.js.map +0 -1
  251. package/dist/invites/interface.d.ts.map +0 -1
  252. package/dist/invites/interface.js.map +0 -1
  253. package/dist/invites/types.d.ts.map +0 -1
  254. package/dist/invites/types.js.map +0 -1
  255. package/dist/logging/interface.d.ts.map +0 -1
  256. package/dist/logging/interface.js.map +0 -1
  257. package/dist/metrics/interface.d.ts.map +0 -1
  258. package/dist/metrics/interface.js.map +0 -1
  259. package/dist/notifications/index.d.ts.map +0 -1
  260. package/dist/notifications/index.js.map +0 -1
  261. package/dist/notifications/interface.d.ts.map +0 -1
  262. package/dist/notifications/interface.js.map +0 -1
  263. package/dist/notifications/types.d.ts.map +0 -1
  264. package/dist/notifications/types.js.map +0 -1
  265. package/dist/organizations/index.d.ts.map +0 -1
  266. package/dist/organizations/index.js.map +0 -1
  267. package/dist/organizations/interface.d.ts.map +0 -1
  268. package/dist/organizations/interface.js.map +0 -1
  269. package/dist/organizations/paths.d.ts.map +0 -1
  270. package/dist/organizations/paths.js.map +0 -1
  271. package/dist/organizations/schemas.d.ts.map +0 -1
  272. package/dist/organizations/schemas.js.map +0 -1
  273. package/dist/organizations/types.d.ts.map +0 -1
  274. package/dist/organizations/types.js.map +0 -1
  275. package/dist/pagination.d.ts.map +0 -1
  276. package/dist/pagination.js.map +0 -1
  277. package/dist/permissions/index.d.ts.map +0 -1
  278. package/dist/permissions/index.js.map +0 -1
  279. package/dist/permissions/interface.d.ts.map +0 -1
  280. package/dist/permissions/interface.js.map +0 -1
  281. package/dist/permissions/types.d.ts.map +0 -1
  282. package/dist/permissions/types.js.map +0 -1
  283. package/dist/platformProjects/index.d.ts.map +0 -1
  284. package/dist/platformProjects/index.js.map +0 -1
  285. package/dist/platformProjects/interface.d.ts.map +0 -1
  286. package/dist/platformProjects/interface.js.map +0 -1
  287. package/dist/platformProjects/schemas.d.ts.map +0 -1
  288. package/dist/platformProjects/schemas.js.map +0 -1
  289. package/dist/platformProjects/types.d.ts.map +0 -1
  290. package/dist/platformProjects/types.js.map +0 -1
  291. package/dist/projects/index.d.ts.map +0 -1
  292. package/dist/projects/index.js.map +0 -1
  293. package/dist/projects/interface.d.ts.map +0 -1
  294. package/dist/projects/interface.js.map +0 -1
  295. package/dist/projects/schemas.d.ts.map +0 -1
  296. package/dist/projects/schemas.js.map +0 -1
  297. package/dist/projects/types.d.ts.map +0 -1
  298. package/dist/projects/types.js.map +0 -1
  299. package/dist/shareLinks/index.d.ts.map +0 -1
  300. package/dist/shareLinks/index.js.map +0 -1
  301. package/dist/shareLinks/interface.d.ts.map +0 -1
  302. package/dist/shareLinks/interface.js.map +0 -1
  303. package/dist/shareLinks/schemas.d.ts.map +0 -1
  304. package/dist/shareLinks/schemas.js.map +0 -1
  305. package/dist/shareLinks/types.d.ts.map +0 -1
  306. package/dist/shareLinks/types.js.map +0 -1
  307. package/dist/solveCache/interface.d.ts.map +0 -1
  308. package/dist/solveCache/interface.js.map +0 -1
  309. package/dist/storage/assetClasses.d.ts.map +0 -1
  310. package/dist/storage/assetClasses.js.map +0 -1
  311. package/dist/storage/cacheBust.d.ts.map +0 -1
  312. package/dist/storage/cacheBust.js.map +0 -1
  313. package/dist/storage/image.d.ts.map +0 -1
  314. package/dist/storage/image.js.map +0 -1
  315. package/dist/storage/index.d.ts.map +0 -1
  316. package/dist/storage/index.js.map +0 -1
  317. package/dist/storage/interface.d.ts.map +0 -1
  318. package/dist/storage/interface.js.map +0 -1
  319. package/dist/testing/index.d.ts.map +0 -1
  320. package/dist/testing/index.js.map +0 -1
  321. package/dist/testing/suites/apiTokenStoreSuite.d.ts.map +0 -1
  322. package/dist/testing/suites/apiTokenStoreSuite.js.map +0 -1
  323. package/dist/testing/suites/authProviderSuite.d.ts.map +0 -1
  324. package/dist/testing/suites/authProviderSuite.js.map +0 -1
  325. package/dist/testing/suites/computeServerStoreSuite.d.ts.map +0 -1
  326. package/dist/testing/suites/computeServerStoreSuite.js.map +0 -1
  327. package/dist/testing/suites/definitionStoreSuite.d.ts.map +0 -1
  328. package/dist/testing/suites/definitionStoreSuite.js.map +0 -1
  329. package/dist/testing/suites/emailLinkAuthSuite.d.ts.map +0 -1
  330. package/dist/testing/suites/emailLinkAuthSuite.js.map +0 -1
  331. package/dist/testing/suites/eventSinkSuite.d.ts.map +0 -1
  332. package/dist/testing/suites/eventSinkSuite.js.map +0 -1
  333. package/dist/testing/suites/helpers.d.ts.map +0 -1
  334. package/dist/testing/suites/helpers.js.map +0 -1
  335. package/dist/testing/suites/inviteStoreSuite.d.ts.map +0 -1
  336. package/dist/testing/suites/inviteStoreSuite.js.map +0 -1
  337. package/dist/testing/suites/orgStoreSuite.d.ts.map +0 -1
  338. package/dist/testing/suites/orgStoreSuite.js.map +0 -1
  339. package/dist/testing/suites/platformPermissionStoreSuite.d.ts.map +0 -1
  340. package/dist/testing/suites/platformPermissionStoreSuite.js.map +0 -1
  341. package/dist/testing/suites/platformProjectGrantStoreSuite.d.ts.map +0 -1
  342. package/dist/testing/suites/platformProjectGrantStoreSuite.js.map +0 -1
  343. package/dist/testing/suites/projectStoreSuite.d.ts.map +0 -1
  344. package/dist/testing/suites/projectStoreSuite.js.map +0 -1
  345. package/dist/testing/suites/shareLinkStoreSuite.d.ts.map +0 -1
  346. package/dist/testing/suites/shareLinkStoreSuite.js.map +0 -1
  347. package/dist/testing/suites/solveMetricSinkSuite.d.ts.map +0 -1
  348. package/dist/testing/suites/solveMetricSinkSuite.js.map +0 -1
  349. package/dist/testing/suites/storageProviderSuite.d.ts.map +0 -1
  350. package/dist/testing/suites/storageProviderSuite.js.map +0 -1
  351. package/dist/testing/suites/userProfileStoreSuite.d.ts.map +0 -1
  352. package/dist/testing/suites/userProfileStoreSuite.js.map +0 -1
  353. package/dist/userProfile/index.d.ts.map +0 -1
  354. package/dist/userProfile/index.js.map +0 -1
  355. package/dist/userProfile/interface.d.ts.map +0 -1
  356. package/dist/userProfile/interface.js.map +0 -1
  357. package/dist/userProfile/types.d.ts.map +0 -1
  358. package/dist/userProfile/types.js.map +0 -1
  359. package/dist/utils/audit.d.ts.map +0 -1
  360. package/dist/utils/audit.js.map +0 -1
  361. package/dist/utils/index.d.ts.map +0 -1
  362. package/dist/utils/index.js.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @selvajs/platform
2
2
 
3
- Pure TypeScript interfaces defining Selva's contract with its backends — no runtime dependency on a specific database, storage, or auth service. Concrete adapters live in their own packages: `@selvajs/local-provider`, `@selvajs/supabase-provider`, `@selvajs/header-auth-provider`.
3
+ Selva's contract with its backends: the interfaces, plus the logic every adapter shares (access rules, API-token scopes, at-rest secret encryption, Zod request schemas, slugs, the image transcoder) and vitest conformance suites. No dependency on a specific database, storage or auth service. Concrete adapters live in their own packages: `@selvajs/local-provider`, `@selvajs/supabase-provider`, `@selvajs/header-auth-provider`.
4
4
 
5
5
  This README is the contract. Read it before writing an adapter.
6
6
 
@@ -20,6 +20,7 @@ This README is the contract. Read it before writing an adapter.
20
20
  | `IShareLinkStore` | Per-definition anonymous-access tokens. | Yes — every method. |
21
21
  | `IInviteStore` | Pending org-membership invitations. | Yes — every method. |
22
22
  | `IComputeServerStore` | Global + per-org compute-server config. | No — not tenant-scoped. |
23
+ | `IApiTokenStore` | API tokens and their revocation. | Yes — every method. |
23
24
  | `IStorageProvider` | Path-based blob storage. Authorization is the caller's responsibility. | No — callers pass already-authorized paths. |
24
25
 
25
26
  `IDataProvider` composes every store, plus optional `auditQuery` / `events` hooks, an optional `verifySchemaVersion` handshake (for adapters whose schema migrates out-of-band), and the `ensureUser` / `onUserDeleted` lifecycle methods. An adapter typically implements one class per store and aggregates them.
@@ -49,12 +50,12 @@ Providers are two-phase: a metadata store (`IDataProvider`) and a blob store (`I
49
50
 
50
51
  List queries filter `'pending'` and `'archived'` by default (`DefinitionListOptions.includePending` / `includeArchived` opt in). If step 2 fails, the record stays `'pending'` and is invisible to consumers.
51
52
 
52
- **Delete — blob-first:**
53
+ **Delete — metadata-first:**
53
54
 
54
- 1. `storage.deletePrefix(prefix)`.
55
- 2. `data.delete(guid)`.
55
+ 1. `data.delete(guid)`, which hides the record at once.
56
+ 2. `storage.deletePrefix(prefix)`.
56
57
 
57
- If step 2 fails, a retry re-deletes blobs (no-op) and succeeds.
58
+ If step 2 fails, the blobs are orphans no reader can reach. The reverse order would leave a live record with its blobs gone.
58
59
 
59
60
  ---
60
61
 
@@ -84,7 +85,7 @@ The Selva app normally picks bundled providers from `SELVA_AUTH_PROVIDER` / `SEL
84
85
 
85
86
  ## Testing your adapter
86
87
 
87
- `@selvajs/platform/testing` ships a conformance suite per store. Adapters import it and run it against their own instance — passing means the adapter behaves the same as the in-memory reference.
88
+ `@selvajs/platform/testing` ships a conformance suite per store. Adapters import it and run it against their own instance — passing means the adapter honours the contract the bundled providers do.
88
89
 
89
90
  ```ts
90
91
  import { runDefinitionStoreConformance } from '@selvajs/platform/testing';
@@ -96,7 +97,9 @@ runDefinitionStoreConformance({
96
97
  });
97
98
  ```
98
99
 
99
- A suite exists per store, plus auth, email-link auth, storage, event sink, and solve-metric sink. They cover `ctx` scoping, `pending` filtering, `includePending` opt-in, and `ProviderError` shapes; they do not cover performance or concurrency.
100
+ A suite exists per store, plus auth, email-link auth, storage, event sink and solve-metric sink. `runAuthProviderConformance` wraps `runAuthCoreConformance` and `runPasswordAuthConformance`, so a provider without passwords can run the core alone or pass `passwordless`. New cases go behind an option, so an upgrade doesn't turn a third-party adapter red. The suites cover `ctx` scoping, `pending` filtering, `includePending` opt-in, `ProviderError` shapes, and the races a store exists to prevent, such as the share-link solve cap. They don't cover performance.
101
+
102
+ `sharp` is an optional peer dependency. An adapter that calls `transcodeImageIfNeeded` has to install it.
100
103
 
101
104
  ---
102
105
 
@@ -1,3 +1,2 @@
1
1
  export type { ProjectAccessInput, DefinitionAccessInput, VisibilityChangeInput, ReclaimAccessInput, CreateProjectAccessInput, OrgOwnerAuthorityInput, OwnerRemovalInput, OwnerRemovalCheck } from './rules.js';
2
- export { canView, canSolve, canEdit, canManage, canEditProjectSettings, canChangeVisibilityToPublic, canEditDefinition, canReclaim, canCreateProject, canChangeOrgRole, checkOwnerRemoval, withAdminBypass } from './rules.js';
3
- //# sourceMappingURL=index.d.ts.map
2
+ export { canView, canSolve, canEdit, canCreateDefinition, canManage, canEditProjectSettings, canChangeVisibilityToPublic, canEditDefinition, canReclaim, canCreateProject, canChangeOrgRole, checkOwnerRemoval, withAdminBypass } from './rules.js';
@@ -1,2 +1 @@
1
- export { canView, canSolve, canEdit, canManage, canEditProjectSettings, canChangeVisibilityToPublic, canEditDefinition, canReclaim, canCreateProject, canChangeOrgRole, checkOwnerRemoval, withAdminBypass } from './rules.js';
2
- //# sourceMappingURL=index.js.map
1
+ export { canView, canSolve, canEdit, canCreateDefinition, canManage, canEditProjectSettings, canChangeVisibilityToPublic, canEditDefinition, canReclaim, canCreateProject, canChangeOrgRole, checkOwnerRemoval, withAdminBypass } from './rules.js';
@@ -50,6 +50,12 @@ export declare function canSolve(input: ProjectAccessInput): boolean;
50
50
  * All other visibilities: project owner/editor.
51
51
  */
52
52
  export declare function canEdit(input: ProjectAccessInput): boolean;
53
+ /**
54
+ * Adding a new definition. Commons projects (`autoJoinOnUpload`) take uploads
55
+ * from anyone who can {@link canView} them, and the uploader owns what they
56
+ * upload; everywhere else it needs {@link canEdit}.
57
+ */
58
+ export declare function canCreateDefinition(input: ProjectAccessInput): boolean;
53
59
  /** Platform projects: `instance_admin` only. All other visibilities: project owner. */
54
60
  export declare function canManage(input: ProjectAccessInput): boolean;
55
61
  /** Platform projects: `instance_admin` only. All other visibilities: project owner. */
@@ -125,18 +131,12 @@ export interface OrgOwnerAuthorityInput {
125
131
  role: OrgRole;
126
132
  }
127
133
  /**
128
- * Whether the actor may hand out or take away org `owner`/`admin` standing (§3).
129
- *
130
- * Three routes decide this — inviting someone as owner/admin, changing an
131
- * existing member's role, and removing an owner — and all three had written it
132
- * out longhand. Two of them had drifted by the time the access audit found
133
- * them: the invite route let an admin mint an `owner` invite for themselves,
134
- * and DELETE let an admin remove an owner that PATCH would not let them demote.
135
- * They are one rule, so they read it from one place.
134
+ * Whether the actor may hand out or take away org `owner`/`admin` standing.
135
+ * Inviting someone as owner/admin, changing a member's role and removing an owner
136
+ * are one rule, so all three read it here.
136
137
  *
137
- * Reads the actor's **membership row**. `Organization.ownerId` is a separate
138
- * field that can disagree with it — see the sole-`instance_admin` finding — and
139
- * is not authority for this decision.
138
+ * Reads the actor's **membership row**. `Organization.ownerId` is a separate field
139
+ * that can disagree with it and is not authority for this decision.
140
140
  */
141
141
  export declare function canChangeOrgRole(input: OrgOwnerAuthorityInput): boolean;
142
142
  /**
@@ -157,4 +157,3 @@ export interface OwnerRemovalInput {
157
157
  confirmed: boolean;
158
158
  }
159
159
  export declare function checkOwnerRemoval(input: OwnerRemovalInput): OwnerRemovalCheck;
160
- //# sourceMappingURL=rules.d.ts.map
@@ -33,10 +33,12 @@ export function canView(input) {
33
33
  return platformGrants.some((g) => (g.granteeType === 'user' && g.granteeId === userId) ||
34
34
  (g.granteeType === 'org' && g.granteeId === actingOrgId));
35
35
  }
36
- if (project.visibility === 'private')
37
- return member !== null;
36
+ // A project member sees the project at any visibility. Leaving the org ends the
37
+ // membership, so this only widens access for someone who reclaimed from outside.
38
+ if (member !== null)
39
+ return true;
38
40
  if (project.visibility === 'org')
39
- return orgMember !== null;
41
+ return orgMember !== null && actingOrgId === project.orgId;
40
42
  if (project.visibility === 'public')
41
43
  return allowCrossOrgPublic ? true : orgMember !== null;
42
44
  return false;
@@ -69,16 +71,28 @@ export function canSolve(input) {
69
71
  */
70
72
  export function canEdit(input) {
71
73
  const { member, project, enablePlatformProjects, platformPermissions } = input;
72
- if (project?.visibility === 'platform') {
74
+ if (!project)
75
+ return false;
76
+ if (project.visibility === 'platform') {
73
77
  if (!enablePlatformProjects)
74
78
  return false;
75
79
  return isInstanceAdmin(platformPermissions);
76
80
  }
77
81
  return member?.role === 'owner' || member?.role === 'editor';
78
82
  }
83
+ /**
84
+ * Adding a new definition. Commons projects (`autoJoinOnUpload`) take uploads
85
+ * from anyone who can {@link canView} them, and the uploader owns what they
86
+ * upload; everywhere else it needs {@link canEdit}.
87
+ */
88
+ export function canCreateDefinition(input) {
89
+ return (input.project?.autoJoinOnUpload === true && canView(input)) || canEdit(input);
90
+ }
79
91
  /** Platform projects: `instance_admin` only. All other visibilities: project owner. */
80
92
  export function canManage(input) {
81
- if (input.project?.visibility === 'platform') {
93
+ if (!input.project)
94
+ return false;
95
+ if (input.project.visibility === 'platform') {
82
96
  if (!input.enablePlatformProjects)
83
97
  return false;
84
98
  return isInstanceAdmin(input.platformPermissions);
@@ -87,12 +101,7 @@ export function canManage(input) {
87
101
  }
88
102
  /** Platform projects: `instance_admin` only. All other visibilities: project owner. */
89
103
  export function canEditProjectSettings(input) {
90
- if (input.project?.visibility === 'platform') {
91
- if (!input.enablePlatformProjects)
92
- return false;
93
- return isInstanceAdmin(input.platformPermissions);
94
- }
95
- return input.member?.role === 'owner';
104
+ return canManage(input);
96
105
  }
97
106
  /**
98
107
  * Authorization to flip a project to `public`. The `ALLOW_CROSS_ORG_PUBLIC`
@@ -113,6 +122,8 @@ export function canEditDefinition(input) {
113
122
  const { project, definition, member, orgMember, userId, platformPermissions, enablePlatformProjects } = input;
114
123
  if (!project || !definition)
115
124
  return false;
125
+ if (definition.projectId !== project.id)
126
+ return false;
116
127
  if (project.visibility === 'platform') {
117
128
  if (!enablePlatformProjects)
118
129
  return false;
@@ -166,18 +177,12 @@ export function canCreateProject(input) {
166
177
  return false;
167
178
  }
168
179
  /**
169
- * Whether the actor may hand out or take away org `owner`/`admin` standing (§3).
170
- *
171
- * Three routes decide this — inviting someone as owner/admin, changing an
172
- * existing member's role, and removing an owner — and all three had written it
173
- * out longhand. Two of them had drifted by the time the access audit found
174
- * them: the invite route let an admin mint an `owner` invite for themselves,
175
- * and DELETE let an admin remove an owner that PATCH would not let them demote.
176
- * They are one rule, so they read it from one place.
180
+ * Whether the actor may hand out or take away org `owner`/`admin` standing.
181
+ * Inviting someone as owner/admin, changing a member's role and removing an owner
182
+ * are one rule, so all three read it here.
177
183
  *
178
- * Reads the actor's **membership row**. `Organization.ownerId` is a separate
179
- * field that can disagree with it — see the sole-`instance_admin` finding — and
180
- * is not authority for this decision.
184
+ * Reads the actor's **membership row**. `Organization.ownerId` is a separate field
185
+ * that can disagree with it and is not authority for this decision.
181
186
  */
182
187
  export function canChangeOrgRole(input) {
183
188
  if (input.role === 'member')
@@ -194,4 +199,3 @@ export function checkOwnerRemoval(input) {
194
199
  return 'needs_confirm';
195
200
  return 'ok';
196
201
  }
197
- //# sourceMappingURL=rules.js.map
@@ -1,6 +1,5 @@
1
1
  export type { ApiScope, ApiScopeAction, ApiScopeResource, ApiToken, ApiTokenSummary, ApiTokenRevokeReason, ApiTokenLifetimeDays } from './types.js';
2
- export { ApiScopeActionSchema, ApiScopeStringSchema, ApiTokenRevokeReasonSchema, API_TOKEN_LIFETIME_DAYS, parseApiScope, formatApiScope, describeApiScope } from './types.js';
2
+ export { ApiScopeActionSchema, ApiScopeStringSchema, API_TOKEN_LIFETIME_DAYS, parseApiScope, formatApiScope, describeApiScope } from './types.js';
3
3
  export type { IApiTokenStore } from './interface.js';
4
4
  export type { ScopeTarget } from './scope.js';
5
- export { scopeAllows, narrowApiTokenContext, outsideTokenOrg } from './scope.js';
6
- //# sourceMappingURL=index.d.ts.map
5
+ export { scopeAllows, apiScopeActionCovers, narrowApiTokenContext, outsideTokenOrg } from './scope.js';
@@ -1,3 +1,2 @@
1
- export { ApiScopeActionSchema, ApiScopeStringSchema, ApiTokenRevokeReasonSchema, API_TOKEN_LIFETIME_DAYS, parseApiScope, formatApiScope, describeApiScope } from './types.js';
2
- export { scopeAllows, narrowApiTokenContext, outsideTokenOrg } from './scope.js';
3
- //# sourceMappingURL=index.js.map
1
+ export { ApiScopeActionSchema, ApiScopeStringSchema, API_TOKEN_LIFETIME_DAYS, parseApiScope, formatApiScope, describeApiScope } from './types.js';
2
+ export { scopeAllows, apiScopeActionCovers, narrowApiTokenContext, outsideTokenOrg } from './scope.js';
@@ -34,4 +34,3 @@ export interface IApiTokenStore {
34
34
  /** Called from the `deleteOrg` cascade. */
35
35
  deleteByOrg(ctx: RequestContext, orgId: string): Promise<void>;
36
36
  }
37
- //# sourceMappingURL=interface.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=interface.js.map
@@ -14,6 +14,8 @@ export interface ScopeTarget {
14
14
  * checked elsewhere.
15
15
  */
16
16
  export declare function scopeAllows(ctx: RequestContext, action: ApiScopeAction, target?: ScopeTarget): boolean;
17
+ /** Does a scope granting `granted` allow `wanted`? */
18
+ export declare function apiScopeActionCovers(granted: ApiScopeAction, wanted: ApiScopeAction): boolean;
17
19
  /**
18
20
  * Narrow the owner's live context to what the token grants. Only removes
19
21
  * rights:
@@ -24,7 +26,7 @@ export declare function scopeAllows(ctx: RequestContext, action: ApiScopeAction,
24
26
  *
25
27
  * Scopes this version can't parse are dropped, so they grant nothing.
26
28
  */
27
- export declare function narrowApiTokenContext(ctx: RequestContext, token: Pick<ApiToken, 'id' | 'orgId' | 'scopes'>): RequestContext;
29
+ export declare function narrowApiTokenContext(ctx: RequestContext, token: Pick<ApiToken, 'id' | 'orgId' | 'scopes' | 'expiresAt'>): RequestContext;
28
30
  /**
29
31
  * True when an API-token request reaches for something owned by an org other
30
32
  * than the token's. A token is bound to one org, so that resource doesn't
@@ -32,4 +34,3 @@ export declare function narrowApiTokenContext(ctx: RequestContext, token: Pick<A
32
34
  * not found. Session requests are never outside.
33
35
  */
34
36
  export declare function outsideTokenOrg(ctx: RequestContext, orgId: string): boolean;
35
- //# sourceMappingURL=scope.d.ts.map
@@ -12,10 +12,11 @@ export function scopeAllows(ctx, action, target) {
12
12
  const api = ctx.apiScope;
13
13
  if (!api)
14
14
  return true;
15
- return api.scopes.some((s) => actionCovers(s.action, action) && resourceCovers(s, ctx, target));
15
+ return api.scopes.some((s) => apiScopeActionCovers(s.action, action) && resourceCovers(s, ctx, target));
16
16
  }
17
- function actionCovers(granted, wanted) {
18
- return granted === wanted || wanted === 'read';
17
+ /** Does a scope granting `granted` allow `wanted`? */
18
+ export function apiScopeActionCovers(granted, wanted) {
19
+ return granted === wanted || wanted === 'read' || (granted === 'write' && wanted === 'upload');
19
20
  }
20
21
  function resourceCovers(scope, ctx, target) {
21
22
  const { resource } = scope;
@@ -45,7 +46,11 @@ export function narrowApiTokenContext(ctx, token) {
45
46
  throw new ProviderError('API token context must act in the token’s org', 500);
46
47
  }
47
48
  const scopes = token.scopes.map(parseApiScope).filter((s) => s !== null);
48
- return { ...ctx, platformPermissions: [], apiScope: { tokenId: token.id, scopes } };
49
+ return {
50
+ ...ctx,
51
+ platformPermissions: [],
52
+ apiScope: { tokenId: token.id, scopes, expiresAt: token.expiresAt }
53
+ };
49
54
  }
50
55
  /**
51
56
  * True when an API-token request reaches for something owned by an org other
@@ -56,4 +61,3 @@ export function narrowApiTokenContext(ctx, token) {
56
61
  export function outsideTokenOrg(ctx, orgId) {
57
62
  return ctx.apiScope !== undefined && orgId !== ctx.actingOrgId;
58
63
  }
59
- //# sourceMappingURL=scope.js.map
@@ -1,9 +1,15 @@
1
1
  import { z } from 'zod';
2
- /** `write` and `solve` each include `read`; neither includes the other. */
2
+ /**
3
+ * `write`, `solve` and `upload` each include `read`, and `write` includes
4
+ * `upload`. `upload` covers only creating definitions, uploading versions,
5
+ * checking a file's schema before upload and making a version live: it can't
6
+ * edit metadata, delete or share.
7
+ */
3
8
  export declare const ApiScopeActionSchema: z.ZodEnum<{
4
9
  read: "read";
5
10
  write: "write";
6
11
  solve: "solve";
12
+ upload: "upload";
7
13
  }>;
8
14
  export type ApiScopeAction = z.infer<typeof ApiScopeActionSchema>;
9
15
  /**
@@ -76,4 +82,3 @@ export declare const API_TOKEN_LIFETIME_DAYS: readonly [30, 90, 180];
76
82
  export type ApiTokenLifetimeDays = (typeof API_TOKEN_LIFETIME_DAYS)[number];
77
83
  /** "Read and change everything in the org". Names no ids, so it suits an email. */
78
84
  export declare function describeApiScope(value: string): string;
79
- //# sourceMappingURL=types.d.ts.map
@@ -1,9 +1,14 @@
1
1
  import { z } from 'zod';
2
- /** `write` and `solve` each include `read`; neither includes the other. */
3
- export const ApiScopeActionSchema = z.enum(['read', 'write', 'solve']);
2
+ /**
3
+ * `write`, `solve` and `upload` each include `read`, and `write` includes
4
+ * `upload`. `upload` covers only creating definitions, uploading versions,
5
+ * checking a file's schema before upload and making a version live: it can't
6
+ * edit metadata, delete or share.
7
+ */
8
+ export const ApiScopeActionSchema = z.enum(['read', 'write', 'solve', 'upload']);
4
9
  // Ids are uuids or guids in practice; the charset only has to keep `:` out so
5
10
  // the string form stays unambiguous.
6
- const SCOPE_PATTERN = /^(read|write|solve):(all|(org|project|definition):([A-Za-z0-9_-]{1,128}))$/;
11
+ const SCOPE_PATTERN = /^(read|write|solve|upload):(all|(org|project|definition):([A-Za-z0-9_-]{1,128}))$/;
7
12
  /** `read:all`, `write:org:<id>`, `solve:project:<id>`, `read:definition:<guid>`. */
8
13
  export function parseApiScope(value) {
9
14
  const m = SCOPE_PATTERN.exec(value);
@@ -37,7 +42,8 @@ export const API_TOKEN_LIFETIME_DAYS = [30, 90, 180];
37
42
  const ACTION_WORDS = {
38
43
  read: 'Read',
39
44
  write: 'Read and change',
40
- solve: 'Read and run solves on'
45
+ solve: 'Read and run solves on',
46
+ upload: 'Read and upload definitions to'
41
47
  };
42
48
  /** "Read and change everything in the org". Names no ids, so it suits an email. */
43
49
  export function describeApiScope(value) {
@@ -51,4 +57,3 @@ export function describeApiScope(value) {
51
57
  : 'everything in the org';
52
58
  return `${ACTION_WORDS[scope.action]} ${what}`;
53
59
  }
54
- //# sourceMappingURL=types.js.map
@@ -1,3 +1,2 @@
1
1
  export type { AuthUser, UserManagementResult, LoginResult } from './types.js';
2
2
  export type { IAuthProvider, IOAuthAuth, ISessionRefresh, IPasswordAuth, IEmailLinkAuth, IProxyAuth, IDelegatedSession, DelegatedSessionStatus } from './interface.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=index.js.map
@@ -30,9 +30,8 @@ export interface IPasswordAuth {
30
30
  * `getOAuthAuthorizationUrl` and 303s to the result.
31
31
  * 2. IdP redirects back to `/auth/{provider}/callback?code=...` → server
32
32
  * calls `exchangeOAuthCode` to mint the session pair.
33
- * 3. When the access token expires, session-refresh middleware in
34
- * `hooks.server.ts` calls `refreshSession` to swap in a fresh pair
35
- * without bouncing the user.
33
+ *
34
+ * Keeping the session alive afterwards is `ISessionRefresh`'s job.
36
35
  *
37
36
  * Each method returns `null` rather than throwing on irrecoverable
38
37
  * credential failures, so the route layer can pick the right HTTP shape
@@ -64,23 +63,6 @@ export interface IOAuthAuth {
64
63
  sessionToken: string;
65
64
  refreshToken: string;
66
65
  } | null>;
67
- /**
68
- * Swap a refresh token for a fresh access/refresh pair. Returns null on
69
- * irrecoverable failure (revoked, expired, signed by a different secret);
70
- * the session-refresh middleware treats null as "force re-login" by
71
- * clearing the refresh cookie.
72
- *
73
- * @deprecated Session refresh is session lifecycle, not OAuth — a consumer
74
- * that brokers no OAuth still needs it (refreshing a password session, or
75
- * revoking on logout). Moved to `IAuthProvider.sessionRefresh`
76
- * (`ISessionRefresh`). This member delegates for one release and will be
77
- * removed in the next minor; migrate callers to
78
- * `auth.sessionRefresh?.refreshSession(...)`.
79
- */
80
- refreshSession(refreshToken: string): Promise<{
81
- sessionToken: string;
82
- refreshToken: string;
83
- } | null>;
84
66
  }
85
67
  /**
86
68
  * Optional session-lifecycle surface: refresh an expiring session, revoke one
@@ -245,8 +227,8 @@ export interface IDelegatedSession {
245
227
  */
246
228
  status(): Promise<DelegatedSessionStatus>;
247
229
  /**
248
- * A session token acting as `userId` inside `orgId`, valid for about a
249
- * minute. It carries no instance-admin rights, whatever the user holds: those
230
+ * A session token acting as `userId` inside `orgId`, valid for `ttlSeconds`
231
+ * (default 60 s). It carries no instance-admin rights, whatever the user holds: those
250
232
  * never ride on a bearer key. Throws if `status` isn't ok.
251
233
  */
252
234
  mint(userId: string, opts: {
@@ -327,4 +309,3 @@ export interface IAuthProvider {
327
309
  */
328
310
  touchLastLogin?(id: string): Promise<void>;
329
311
  }
330
- //# sourceMappingURL=interface.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=interface.js.map
@@ -21,7 +21,10 @@ export interface AuthUser {
21
21
  * - `last_admin` — refused; would leave zero `instance_admin` users
22
22
  */
23
23
  export type UserManagementResult = 'ok' | 'not_found' | 'not_supported' | 'last_admin';
24
- /** `success` includes the session token the provider minted. */
24
+ /**
25
+ * `success` includes the session token the provider minted. `rate_limited` is for
26
+ * providers that throttle logins; no bundled provider returns it.
27
+ */
25
28
  export type LoginResult = {
26
29
  kind: 'success';
27
30
  user: AuthUser;
@@ -30,4 +33,3 @@ export type LoginResult = {
30
33
  kind: 'failed';
31
34
  reason?: 'invalid_credentials' | 'disabled' | 'rate_limited';
32
35
  };
33
- //# sourceMappingURL=types.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map
@@ -1,3 +1,2 @@
1
1
  export type { IBindingResolver } from './interface.js';
2
2
  export { NoopBindingResolver } from './interface.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,2 +1 @@
1
1
  export { NoopBindingResolver } from './interface.js';
2
- //# sourceMappingURL=index.js.map
@@ -37,4 +37,3 @@ export interface IBindingResolver {
37
37
  export declare class NoopBindingResolver implements IBindingResolver {
38
38
  resolve(): Promise<Map<string, unknown>>;
39
39
  }
40
- //# sourceMappingURL=interface.d.ts.map
@@ -17,4 +17,3 @@ export class NoopBindingResolver {
17
17
  return new Map();
18
18
  }
19
19
  }
20
- //# sourceMappingURL=interface.js.map
@@ -1,8 +1,2 @@
1
- export type { ComputeServerConfig, ComputeConfig, PlatformComputeServer, OrgComputeServer } from './types.js';
2
- export { isPlatformServer, isOrgServer } from './types.js';
3
- export type { IComputeServerStore, GetConfigOptions } from './interface.js';
1
+ export * from './public.js';
4
2
  export { isEncryptedSecret, encryptSecret, decryptSecret, decodeSecretKey } from './secrets.js';
5
- export type { SecretVerificationReport, SecretVerificationFailure, SecretVerificationFailureReason } from './secrets.js';
6
- export type { ResolveOptions } from './utils.js';
7
- export { serversVisibleTo, defaultServerIdFor, resolveServerForOrg, findServerById, platformServers, orgServersFor, scopeConfigToOrg } from './utils.js';
8
- //# sourceMappingURL=index.d.ts.map
@@ -1,9 +1,3 @@
1
- export { isPlatformServer, isOrgServer } from './types.js';
2
- // At-rest secret crypto (uses `node:crypto`). Server-only — deliberately NOT
3
- // re-exported from the root barrel, which client `.svelte` code imports and
4
- // where a browser bundle can't resolve `node:crypto`. Import these from
5
- // `@selvajs/platform/computeServer` in server code. The report TYPES are erased
6
- // at build, so they also stay re-exported from the root barrel for convenience.
1
+ export * from './public.js';
2
+ // Server-only: import these from `@selvajs/platform/computeServer`.
7
3
  export { isEncryptedSecret, encryptSecret, decryptSecret, decodeSecretKey } from './secrets.js';
8
- export { serversVisibleTo, defaultServerIdFor, resolveServerForOrg, findServerById, platformServers, orgServersFor, scopeConfigToOrg } from './utils.js';
9
- //# sourceMappingURL=index.js.map
@@ -28,10 +28,9 @@ export interface GetConfigOptions {
28
28
  *
29
29
  * Org-facing surfaces must pass this. Without it the store hands back every
30
30
  * platform server and every *other* org's private servers, leaving each
31
- * caller to re-apply a filter it can silently forget — the global
32
- * `defaultServerId` in particular passed straight through before this
33
- * existed. Admin surfaces, boot health and the save-diff handlers omit it
34
- * deliberately; they act instance-wide.
31
+ * caller to re-apply a filter it can silently forget. Admin surfaces, boot
32
+ * health and the save-diff handlers omit it deliberately; they act
33
+ * instance-wide.
35
34
  */
36
35
  scopeToOrgId?: string;
37
36
  }
@@ -53,6 +52,10 @@ export interface IComputeServerStore {
53
52
  * authenticated under the current `SELVA_AT_REST_KEY` (the solve fails
54
53
  * later at Rhino.Compute rather than here).
55
54
  *
55
+ * A plaintext key at rest is adapter-defined: local throws, because it never
56
+ * writes one, and Supabase warns and returns it, because rows can predate
57
+ * encryption. Both report it through `verifySecrets`.
58
+ *
56
59
  * The narrow path onto the solve hot path: resolve a server from the
57
60
  * key-free config, then fetch that one key.
58
61
  */
@@ -61,7 +64,8 @@ export interface IComputeServerStore {
61
64
  savePlatformServers(ctx: RequestContext, servers: ComputeServerConfig[], defaultServerId: string | undefined): Promise<void>;
62
65
  /**
63
66
  * Replaces the org-private server set for `orgId` and (optionally) updates
64
- * `orgDefaults[orgId]`. Platform rows are left untouched.
67
+ * `orgDefaults[orgId]`. Platform rows are left untouched, and any non-org entry
68
+ * in `servers` is ignored.
65
69
  *
66
70
  * `defaultServerId: null` clears the org's override; `undefined` leaves
67
71
  * the existing value alone.
@@ -90,4 +94,3 @@ export interface IComputeServerStore {
90
94
  */
91
95
  verifySecrets?(): Promise<SecretVerificationReport>;
92
96
  }
93
- //# sourceMappingURL=interface.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=interface.js.map
@@ -0,0 +1,6 @@
1
+ export type { ComputeServerConfig, ComputeConfig, PlatformComputeServer, OrgComputeServer } from './types.js';
2
+ export { COMPUTE_RETRY_MAX, COMPUTE_TIMEOUT_DEFAULT_MS, COMPUTE_TIMEOUT_MAX_MS, COMPUTE_TIMEOUT_MIN_MS, isPlatformServer, isOrgServer } from './types.js';
3
+ export type { IComputeServerStore, GetConfigOptions } from './interface.js';
4
+ export type { ResolveOptions } from './utils.js';
5
+ export { serversVisibleTo, defaultServerIdFor, clampRetryCount, clampTimeoutMs, pickServer, resolveServerForOrg, findServerById, platformServers, scopeConfigToOrg } from './utils.js';
6
+ export type { SecretVerificationReport, SecretVerificationFailure, SecretVerificationFailureReason } from './secrets.js';
@@ -0,0 +1,2 @@
1
+ export { COMPUTE_RETRY_MAX, COMPUTE_TIMEOUT_DEFAULT_MS, COMPUTE_TIMEOUT_MAX_MS, COMPUTE_TIMEOUT_MIN_MS, isPlatformServer, isOrgServer } from './types.js';
2
+ export { serversVisibleTo, defaultServerIdFor, clampRetryCount, clampTimeoutMs, pickServer, resolveServerForOrg, findServerById, platformServers, scopeConfigToOrg } from './utils.js';
@@ -1,8 +1,12 @@
1
+ export declare function isEncryptedSecret(value: string): boolean;
1
2
  /**
2
3
  * AES-256-GCM envelope for at-rest secrets (e.g. compute API keys).
3
4
  *
4
- * Wire format: `enc:v1:<base64(iv|tag|ciphertext)>`. The version prefix lets
5
- * a future migration to a new algorithm tell old and new envelopes apart.
5
+ * Wire format: `enc:v2:<base64(iv|tag|ciphertext)>`. `v2` authenticates the
6
+ * record the secret belongs to as AAD, so ciphertext copied onto another record
7
+ * fails to decrypt instead of handing the plaintext to that record's URL.
8
+ * `enc:v1:` envelopes have no AAD and still read: a store rewrites them as `v2`
9
+ * on its next save.
6
10
  *
7
11
  * Defends against backup leaks, accidental file/DB sharing, and read-only
8
12
  * storage access — not against an attacker who also has the master key
@@ -11,10 +15,13 @@
11
15
  *
12
16
  * Pure `node:crypto`, no fs or DB coupling, so the local and Supabase
13
17
  * compute-server stores share this one implementation.
18
+ *
19
+ * Pass `aad` to bind the secret to its record. {@link decryptSecret} then needs the
20
+ * same value.
14
21
  */
15
- export declare function isEncryptedSecret(value: string): boolean;
16
- export declare function encryptSecret(plaintext: string, key: Buffer): string;
17
- export declare function decryptSecret(envelope: string, key: Buffer): string;
22
+ export declare function encryptSecret(plaintext: string, key: Buffer, aad?: string): string;
23
+ /** `aad` is ignored for an `enc:v1:` envelope and required for an `enc:v2:` one. */
24
+ export declare function decryptSecret(envelope: string, key: Buffer, aad?: string): string;
18
25
  /**
19
26
  * Decodes a `SELVA_AT_REST_KEY` env var into a 32-byte buffer (64-char hex or
20
27
  * base64, with or without padding). Throws on anything else so a
@@ -46,4 +53,3 @@ export interface SecretVerificationReport {
46
53
  /** True if at least one row holds an unencrypted apiKey at rest. */
47
54
  plaintextFound: boolean;
48
55
  }
49
- //# sourceMappingURL=secrets.d.ts.map