@selvajs/platform 0.21.0-beta.3 → 1.0.0-beta.5

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 +11 -8
  2. package/dist/access/index.d.ts +0 -1
  3. package/dist/access/index.js +0 -1
  4. package/dist/access/rules.d.ts +7 -14
  5. package/dist/access/rules.js +22 -26
  6. package/dist/apiTokens/index.d.ts +1 -2
  7. package/dist/apiTokens/index.js +1 -2
  8. package/dist/apiTokens/interface.d.ts +0 -1
  9. package/dist/apiTokens/interface.js +0 -1
  10. package/dist/apiTokens/scope.d.ts +0 -1
  11. package/dist/apiTokens/scope.js +0 -1
  12. package/dist/apiTokens/types.d.ts +0 -1
  13. package/dist/apiTokens/types.js +0 -1
  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 +11 -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 +0 -21
  51. package/dist/definitions/schemas.js +6 -19
  52. package/dist/definitions/types.d.ts +3 -4
  53. package/dist/definitions/types.js +0 -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 +21 -3
  93. package/dist/pagination.js +34 -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 +19 -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
@@ -32,4 +32,3 @@ export interface ProjectMember {
32
32
  updatedBy: string;
33
33
  deletedAt?: string | null;
34
34
  }
35
- //# sourceMappingURL=types.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map
@@ -3,4 +3,3 @@ export type { IShareLinkStore } from './interface.js';
3
3
  export { DEFAULT_SHARE_LINK_MAX_SOLVES } from './types.js';
4
4
  export type { CreateShareLinkInput } from './schemas.js';
5
5
  export { CreateShareLinkInputSchema } from './schemas.js';
6
- //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,2 @@
1
1
  export { DEFAULT_SHARE_LINK_MAX_SOLVES } from './types.js';
2
2
  export { CreateShareLinkInputSchema } from './schemas.js';
3
- //# sourceMappingURL=index.js.map
@@ -6,7 +6,8 @@ import type { OrgShareLink, ShareLink } from './types.js';
6
6
  * (definitionId, channel). The store sees only the HMAC hash; the raw token
7
7
  * is generated and shown to the minter at the route layer.
8
8
  *
9
- * Reads filter `revokedAt IS NULL` defensively.
9
+ * List and token reads treat a revoked or expired link as gone. `getById` does
10
+ * not, so a caller can tell a dead link from a missing one.
10
11
  */
11
12
  export interface IShareLinkStore {
12
13
  /** Caller has already hashed the raw token. */
@@ -29,7 +30,10 @@ export interface IShareLinkStore {
29
30
  getById(ctx: RequestContext, id: string): Promise<ShareLink | null>;
30
31
  /** Returns null when the link doesn't exist, is revoked, or its parent definition is soft-deleted. */
31
32
  getByTokenHash(ctx: RequestContext, tokenHash: string): Promise<ShareLink | null>;
32
- /** Soft-delete (set `revokedAt`). Idempotent. */
33
+ /**
34
+ * Soft-delete (set `revokedAt`). Idempotent: emits once, and a repeat is a no-op.
35
+ * Throws `ProviderError` when the caller may not revoke it.
36
+ */
33
37
  revoke(ctx: RequestContext, id: string): Promise<void>;
34
38
  /**
35
39
  * Atomic check-and-increment; must be a single statement, since
@@ -38,4 +42,3 @@ export interface IShareLinkStore {
38
42
  */
39
43
  tryIncrementSolveCount(ctx: RequestContext, id: string): Promise<number | null>;
40
44
  }
41
- //# sourceMappingURL=interface.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=interface.js.map
@@ -14,4 +14,3 @@ export declare const CreateShareLinkInputSchema: z.ZodObject<{
14
14
  expiresAt: z.ZodOptional<z.ZodNullable<z.ZodISODateTime>>;
15
15
  }, z.core.$strip>;
16
16
  export type CreateShareLinkInput = z.infer<typeof CreateShareLinkInputSchema>;
17
- //# sourceMappingURL=schemas.d.ts.map
@@ -8,8 +8,10 @@ export const CreateShareLinkInputSchema = z.object({
8
8
  channel: DefinitionChannelSchema.default('live'),
9
9
  name: z.string().max(128).optional(),
10
10
  allowSolve: z.boolean().default(true),
11
- /** Null is the minter's deliberate "uncap" choice; omitted applies the default cap. */
11
+ /**
12
+ * Null is the minter's deliberate "uncap" choice. Omitted stays undefined here:
13
+ * the mint handler applies `DEFAULT_SHARE_LINK_MAX_SOLVES`.
14
+ */
12
15
  maxSolves: z.number().int().min(1).nullable().optional(),
13
16
  expiresAt: z.iso.datetime().nullable().optional()
14
17
  });
15
- //# sourceMappingURL=schemas.js.map
@@ -46,4 +46,3 @@ export interface OrgShareLink extends Omit<ShareLink, 'tokenHash'> {
46
46
  * worst-case denial-of-wallet damage.
47
47
  */
48
48
  export declare const DEFAULT_SHARE_LINK_MAX_SOLVES = 1000;
49
- //# sourceMappingURL=types.d.ts.map
@@ -4,4 +4,3 @@
4
4
  * worst-case denial-of-wallet damage.
5
5
  */
6
6
  export const DEFAULT_SHARE_LINK_MAX_SOLVES = 1000;
7
- //# sourceMappingURL=types.js.map
@@ -6,8 +6,8 @@ import type { RequestContext } from '../context.js';
6
6
  *
7
7
  * Design contract:
8
8
  *
9
- * - **Async from day one.** The in-memory backend returns promises too, so a
10
- * network store (Redis) drops in later without any call site changing shape.
9
+ * - **Async.** The in-memory backend returns promises too, so a network store
10
+ * (Redis) fits without any call site changing shape.
11
11
  * - **Entries are opaque bytes** — the pre-gzipped response envelope plus a
12
12
  * small metadata header. The backend never inspects them, so a hit stays
13
13
  * near-CPU-free in either backend and there's no serialization drift between
@@ -81,4 +81,3 @@ export declare class NoopSolveResultCache implements ISolveResultCache {
81
81
  get(_ctx: RequestContext, _key: SolveCacheKey): Promise<Uint8Array | null>;
82
82
  set(_ctx: RequestContext, _key: SolveCacheKey, _bytes: Uint8Array, _opts: SolveCacheSetOptions): Promise<void>;
83
83
  }
84
- //# sourceMappingURL=interface.d.ts.map
@@ -9,4 +9,3 @@ export class NoopSolveResultCache {
9
9
  }
10
10
  async set(_ctx, _key, _bytes, _opts) { }
11
11
  }
12
- //# sourceMappingURL=interface.js.map
@@ -4,16 +4,15 @@
4
4
  * entry in {@link ASSET_CLASSES} rather than a new route.
5
5
  *
6
6
  * - `public` — anyone, including logged-out visitors (branding: logo, favicon).
7
- * - `org` — members of the owning org only; route resolves orgId from the path.
8
7
  * - `project` — members of the owning project only; route resolves the
9
8
  * definition guid to its project (cover images, per-definition blobs).
10
9
  */
11
- export type AssetVisibility = 'public' | 'org' | 'project';
10
+ export type AssetVisibility = 'public' | 'project';
12
11
  /**
13
12
  * What scope id the route must authorize against. `none` for public assets
14
- * (no scope to check); `org`/`project` carry the id extracted from the path.
13
+ * (no scope to check); `project` carries the guid extracted from the path.
15
14
  */
16
- export type AssetScope = 'none' | 'org' | 'project';
15
+ export type AssetScope = 'none' | 'project';
17
16
  export interface AssetClass {
18
17
  /** Stable identifier — for logging and tests, not user-facing. */
19
18
  readonly id: string;
@@ -21,7 +20,7 @@ export interface AssetClass {
21
20
  readonly scope: AssetScope;
22
21
  /**
23
22
  * Anchored matcher for this class's storage paths. Capture group 1 (when
24
- * present) is the scope id (orgId or guid) the route authorizes against.
23
+ * present) is the scope id the route authorizes against.
25
24
  */
26
25
  readonly pattern: RegExp;
27
26
  }
@@ -46,6 +45,3 @@ export declare const ASSET_CLASSES: readonly AssetClass[];
46
45
  * captures an id (e.g. `org-branding` captures orgId but is public).
47
46
  */
48
47
  export declare function classifyAssetPath(storagePath: string): AssetMatch | null;
49
- /** True when the path belongs to a `public` asset class (CDN-servable, no auth). */
50
- export declare function isPublicAssetPath(storagePath: string): boolean;
51
- //# sourceMappingURL=assetClasses.d.ts.map
@@ -1,15 +1,9 @@
1
1
  import { ALL_ORG_ASSET_KINDS } from '../organizations/schemas.js';
2
- import { COVER_IMAGE_EXTENSIONS } from '../definitions/types.js';
2
+ import { UUID_REGEX } from '../definitions/schemas.js';
3
+ import { SAFE_SEGMENT } from './safeKey.js';
3
4
  // Built from the schema enum so a new branding kind extends this pattern automatically.
4
5
  const BRANDING_KINDS = ALL_ORG_ASSET_KINDS.join('|');
5
- // Derived from COVER_IMAGE_EXTENSIONS so a new cover format propagates here
6
- // instead of silently 404ing legit covers.
7
- const COVER_EXTS = COVER_IMAGE_EXTENSIONS.map((ext) => ext.replace(/^\./, '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
8
- // SAFE_SEGMENT mirrors the assertSafeKey alphabet in the path helpers
9
- // (traversal/empty segments are rejected separately by hasUnsafeSegment);
10
- // GUID is kept in sync with UUID_REGEX in definitions/schemas.ts.
11
- const SAFE_SEGMENT = String.raw `[A-Za-z0-9._-]+`;
12
- const GUID = String.raw `[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`;
6
+ const GUID = UUID_REGEX.source.slice(1, -1);
13
7
  /**
14
8
  * The closed registry of servable asset classes. Patterns are mutually
15
9
  * exclusive by prefix, order doesn't matter. Anything matching no class is
@@ -22,17 +16,13 @@ export const ASSET_CLASSES = [
22
16
  scope: 'none',
23
17
  pattern: new RegExp(String.raw `^orgs\/(${SAFE_SEGMENT})\/branding\/(?:${BRANDING_KINDS})\.webp$`)
24
18
  },
25
- {
26
- id: 'org-private',
27
- visibility: 'org',
28
- scope: 'org',
29
- pattern: new RegExp(String.raw `^orgs\/(${SAFE_SEGMENT})\/private\/${SAFE_SEGMENT}$`)
30
- },
31
19
  {
32
20
  id: 'definition-cover',
33
21
  visibility: 'project',
34
22
  scope: 'project',
35
- pattern: new RegExp(String.raw `^definitions\/(${GUID})\/cover\.(?:${COVER_EXTS})$`, 'i')
23
+ // `put` transcodes every cover and `definitionPaths.image` names it, so this is
24
+ // the only cover that can exist.
25
+ pattern: new RegExp(String.raw `^definitions\/(${GUID})\/cover\.webp$`, 'i')
36
26
  }
37
27
  ];
38
28
  /**
@@ -72,8 +62,3 @@ export function classifyAssetPath(storagePath) {
72
62
  }
73
63
  return null;
74
64
  }
75
- /** True when the path belongs to a `public` asset class (CDN-servable, no auth). */
76
- export function isPublicAssetPath(storagePath) {
77
- return classifyAssetPath(storagePath)?.class.visibility === 'public';
78
- }
79
- //# sourceMappingURL=assetClasses.js.map
@@ -16,4 +16,3 @@
16
16
  * degrades to "no cache-bust" rather than `?v=`.
17
17
  */
18
18
  export declare function withCacheBust(url: string, token: string | number | undefined | null): string;
19
- //# sourceMappingURL=cacheBust.d.ts.map
@@ -21,7 +21,9 @@ export function withCacheBust(url, token) {
21
21
  const value = String(token).trim();
22
22
  if (value === '')
23
23
  return url;
24
- const sep = url.includes('?') ? '&' : '?';
25
- return `${url}${sep}v=${encodeURIComponent(value)}`;
24
+ const hash = url.indexOf('#');
25
+ const base = hash === -1 ? url : url.slice(0, hash);
26
+ const fragment = hash === -1 ? '' : url.slice(hash);
27
+ const sep = base.includes('?') ? '&' : '?';
28
+ return `${base}${sep}v=${encodeURIComponent(value)}${fragment}`;
26
29
  }
27
- //# sourceMappingURL=cacheBust.js.map
@@ -1,20 +1,21 @@
1
1
  /**
2
2
  * Shared image-transcoding helper for `IStorageProvider` implementations.
3
- * Normalizes uploads to WebP (capped at 1200px, quality 85) so storage,
4
- * bandwidth, and the viewer path stay predictable.
3
+ * Normalizes uploads to WebP (at most 1200px on either side, quality 85) so
4
+ * storage, bandwidth, and the viewer path stay predictable.
5
5
  *
6
6
  * `sharp` is a dynamic import, not a hard dependency of this package —
7
7
  * providers that need transcoding install it themselves.
8
8
  */
9
9
  export declare const IMAGE_MAX_WIDTH = 1200;
10
10
  export declare const IMAGE_WEBP_QUALITY = 85;
11
+ export declare const MAX_CONCURRENT_TRANSCODES = 2;
11
12
  export interface TranscodeResult {
12
13
  data: Uint8Array;
13
14
  contentType: string;
14
15
  /** Possibly-rewritten path (non-webp inputs become `.webp`). */
15
16
  path: string;
16
17
  }
17
- /** True if the input looks like an image to process — by content type or path extension. */
18
+ /** True if the input is an image to process. The content type decides, unless it says nothing. */
18
19
  export declare function isImageUpload(contentType: string | undefined, storagePath: string): boolean;
19
20
  /**
20
21
  * Rewrites a path's extension to `.webp`; unchanged for non-image extensions.
@@ -26,7 +27,9 @@ export declare function toWebpPath(storagePath: string): string;
26
27
  * Transcodes images to WebP; passes non-images through unchanged, so
27
28
  * providers can call this unconditionally before `put`.
28
29
  *
29
- * Throws if `sharp` isn't installed — a config error, not a fallback.
30
+ * Throws `ProviderError(422)` for bytes it won't process, and a plain error if
31
+ * `sharp` isn't installed, which is a config problem rather than a bad upload.
30
32
  */
31
33
  export declare function transcodeImageIfNeeded(data: Uint8Array, contentType: string | undefined, storagePath: string): Promise<TranscodeResult>;
32
- //# sourceMappingURL=image.d.ts.map
34
+ /** Runs `fn` when a slot is free. A finishing transcode hands its slot straight to the next. */
35
+ export declare function withTranscodeSlot<T>(fn: () => Promise<T>): Promise<T>;
@@ -1,17 +1,26 @@
1
1
  /**
2
2
  * Shared image-transcoding helper for `IStorageProvider` implementations.
3
- * Normalizes uploads to WebP (capped at 1200px, quality 85) so storage,
4
- * bandwidth, and the viewer path stay predictable.
3
+ * Normalizes uploads to WebP (at most 1200px on either side, quality 85) so
4
+ * storage, bandwidth, and the viewer path stay predictable.
5
5
  *
6
6
  * `sharp` is a dynamic import, not a hard dependency of this package —
7
7
  * providers that need transcoding install it themselves.
8
8
  */
9
+ import { ProviderError } from '../errors.js';
9
10
  export const IMAGE_MAX_WIDTH = 1200;
10
11
  export const IMAGE_WEBP_QUALITY = 85;
11
- /** True if the input looks like an image to process — by content type or path extension. */
12
+ // A small upload can decode to gigabytes or burn seconds of CPU: the size cap on
13
+ // the request says nothing about either. 60 MP covers a phone camera's full frame.
14
+ const MAX_INPUT_PIXELS = 60_000_000;
15
+ const TRANSCODE_TIMEOUT_SECONDS = 10;
16
+ export const MAX_CONCURRENT_TRANSCODES = 2;
17
+ // What `metadata()` found in the bytes, whatever the client declared.
18
+ const ALLOWED_FORMATS = new Set(['jpeg', 'png', 'webp', 'gif', 'tiff', 'svg']);
19
+ /** True if the input is an image to process. The content type decides, unless it says nothing. */
12
20
  export function isImageUpload(contentType, storagePath) {
13
- if (contentType?.startsWith('image/'))
14
- return true;
21
+ if (contentType && contentType !== 'application/octet-stream') {
22
+ return contentType.startsWith('image/');
23
+ }
15
24
  return /\.(webp|png|jpe?g|gif|bmp|tif?f|svg)$/i.test(storagePath);
16
25
  }
17
26
  /**
@@ -26,29 +35,83 @@ export function toWebpPath(storagePath) {
26
35
  * Transcodes images to WebP; passes non-images through unchanged, so
27
36
  * providers can call this unconditionally before `put`.
28
37
  *
29
- * Throws if `sharp` isn't installed — a config error, not a fallback.
38
+ * Throws `ProviderError(422)` for bytes it won't process, and a plain error if
39
+ * `sharp` isn't installed, which is a config problem rather than a bad upload.
30
40
  */
31
41
  export async function transcodeImageIfNeeded(data, contentType, storagePath) {
32
42
  if (!isImageUpload(contentType, storagePath)) {
33
43
  return { data, contentType: contentType ?? 'application/octet-stream', path: storagePath };
34
44
  }
35
45
  const sharp = await loadSharp();
36
- const compressed = await sharp(Buffer.from(data))
37
- .resize({ width: IMAGE_MAX_WIDTH, withoutEnlargement: true })
38
- .webp({ quality: IMAGE_WEBP_QUALITY })
39
- .toBuffer();
46
+ const compressed = await withTranscodeSlot(() => rasterize(sharp, Buffer.from(data), contentType, storagePath));
40
47
  return {
41
48
  data: new Uint8Array(compressed),
42
49
  contentType: 'image/webp',
43
50
  path: toWebpPath(storagePath)
44
51
  };
45
52
  }
53
+ async function rasterize(sharp, input, contentType, storagePath) {
54
+ try {
55
+ // Unlimited here: this only reads the header, and sharp's own limit would hide
56
+ // the reason from the check below.
57
+ const header = sharp(input, { limitInputPixels: false });
58
+ const { format, width = 0, height = 0 } = await header.metadata();
59
+ // SVG is the expensive format, so it has to be asked for: a route that only
60
+ // checks the declared type must not let one in as a PNG.
61
+ const declaredSvg = contentType === 'image/svg+xml' || /\.svg$/i.test(storagePath);
62
+ if (!ALLOWED_FORMATS.has(format) || (format === 'svg' && !declaredSvg)) {
63
+ throw new ProviderError(`Unsupported image format: ${format}`, 422);
64
+ }
65
+ if (width * height > MAX_INPUT_PIXELS) {
66
+ throw new ProviderError('Image has too many pixels', 422);
67
+ }
68
+ return await sharp(input, { limitInputPixels: MAX_INPUT_PIXELS })
69
+ .autoOrient()
70
+ .resize({
71
+ width: IMAGE_MAX_WIDTH,
72
+ height: IMAGE_MAX_WIDTH,
73
+ fit: 'inside',
74
+ withoutEnlargement: true
75
+ })
76
+ .webp({ quality: IMAGE_WEBP_QUALITY })
77
+ .timeout({ seconds: TRANSCODE_TIMEOUT_SECONDS })
78
+ .toBuffer();
79
+ }
80
+ catch (err) {
81
+ if (err instanceof ProviderError)
82
+ throw err;
83
+ throw new ProviderError('The image could not be read', 422);
84
+ }
85
+ }
86
+ let activeTranscodes = 0;
87
+ const waitingTranscodes = [];
88
+ /** Runs `fn` when a slot is free. A finishing transcode hands its slot straight to the next. */
89
+ export async function withTranscodeSlot(fn) {
90
+ if (activeTranscodes < MAX_CONCURRENT_TRANSCODES) {
91
+ activeTranscodes += 1;
92
+ }
93
+ else {
94
+ await new Promise((resolve) => waitingTranscodes.push(resolve));
95
+ }
96
+ try {
97
+ return await fn();
98
+ }
99
+ finally {
100
+ const next = waitingTranscodes.shift();
101
+ if (next)
102
+ next();
103
+ else
104
+ activeTranscodes -= 1;
105
+ }
106
+ }
107
+ // Not a literal: a browser build of the root barrel would try to resolve it.
108
+ const SHARP_MODULE = 'sharp';
46
109
  let cachedSharp = null;
47
110
  async function loadSharp() {
48
111
  if (cachedSharp)
49
112
  return cachedSharp;
50
113
  try {
51
- const mod = (await import('sharp'));
114
+ const mod = (await import(/* @vite-ignore */ SHARP_MODULE));
52
115
  cachedSharp = mod.default ?? mod;
53
116
  return cachedSharp;
54
117
  }
@@ -56,4 +119,3 @@ async function loadSharp() {
56
119
  throw new Error('Image transcoding requires `sharp` to be installed. Add it as a dependency in your provider package.', { cause: err });
57
120
  }
58
121
  }
59
- //# sourceMappingURL=image.js.map
@@ -1,7 +1,5 @@
1
1
  export type { IStorageProvider } from './interface.js';
2
- export { IMAGE_MAX_WIDTH, IMAGE_WEBP_QUALITY, isImageUpload, toWebpPath, transcodeImageIfNeeded } from './image.js';
2
+ export { transcodeImageIfNeeded } from './image.js';
3
3
  export type { TranscodeResult } from './image.js';
4
- export { ASSET_CLASSES, classifyAssetPath, isPublicAssetPath } from './assetClasses.js';
5
- export type { AssetVisibility, AssetScope, AssetClass, AssetMatch } from './assetClasses.js';
4
+ export { ASSET_CLASSES, classifyAssetPath } from './assetClasses.js';
6
5
  export { withCacheBust } from './cacheBust.js';
7
- //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,3 @@
1
- export { IMAGE_MAX_WIDTH, IMAGE_WEBP_QUALITY, isImageUpload, toWebpPath, transcodeImageIfNeeded } from './image.js';
2
- export { ASSET_CLASSES, classifyAssetPath, isPublicAssetPath } from './assetClasses.js';
1
+ export { transcodeImageIfNeeded } from './image.js';
2
+ export { ASSET_CLASSES, classifyAssetPath } from './assetClasses.js';
3
3
  export { withCacheBust } from './cacheBust.js';
4
- //# sourceMappingURL=index.js.map
@@ -10,10 +10,19 @@
10
10
  export interface IStorageProvider {
11
11
  /** Returns null if the path does not exist. */
12
12
  get(path: string): Promise<Uint8Array | null>;
13
- put(path: string, data: Uint8Array, contentType?: string): Promise<void>;
13
+ /**
14
+ * Stores the bytes, replacing what is there, and returns the path they landed
15
+ * at. Images go through `transcodeImageIfNeeded` first: they are stored as WebP
16
+ * and a `.png` or similar path becomes `.webp`, so read back with the returned
17
+ * path. Throws `ProviderError(422)` for an image the transcoder refuses.
18
+ */
19
+ put(path: string, data: Uint8Array, contentType?: string): Promise<string>;
14
20
  /** No-op if the path does not exist. */
15
21
  delete(path: string): Promise<void>;
16
- /** Delete every file whose path starts with `prefix`. */
22
+ /**
23
+ * Delete every file under the directory `prefix`, so `a/b` does not reach
24
+ * `a/bc`. Throws on an empty prefix or `/`, which would name the whole store.
25
+ */
17
26
  deletePrefix(prefix: string): Promise<void>;
18
27
  /**
19
28
  * Public URL for a stored file. Local: a relative API path; S3/CDN: a
@@ -21,4 +30,3 @@ export interface IStorageProvider {
21
30
  */
22
31
  getPublicUrl(path: string): string;
23
32
  }
24
- //# sourceMappingURL=interface.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=interface.js.map
@@ -0,0 +1,7 @@
1
+ /** Alphabet of one storage path segment, as regex source. Covers GUIDs and sanitized refs. */
2
+ export declare const SAFE_SEGMENT: string;
3
+ /**
4
+ * Blocks traversal, separators, NUL and empty segments, so a malicious id can't
5
+ * escape its prefix. The alphabet admits `.` and `..`, so those need their own check.
6
+ */
7
+ export declare function assertSafeKey(value: string, label: string): void;
@@ -0,0 +1,12 @@
1
+ /** Alphabet of one storage path segment, as regex source. Covers GUIDs and sanitized refs. */
2
+ export const SAFE_SEGMENT = String.raw `[A-Za-z0-9._-]+`;
3
+ const SAFE_SEGMENT_ONLY = new RegExp(`^${SAFE_SEGMENT}$`);
4
+ /**
5
+ * Blocks traversal, separators, NUL and empty segments, so a malicious id can't
6
+ * escape its prefix. The alphabet admits `.` and `..`, so those need their own check.
7
+ */
8
+ export function assertSafeKey(value, label) {
9
+ if (!value || !SAFE_SEGMENT_ONLY.test(value) || value === '.' || value === '..') {
10
+ throw new Error(`Unsafe ${label}: ${JSON.stringify(value)}`);
11
+ }
12
+ }
@@ -1,5 +1,9 @@
1
- export { runAuthProviderConformance } from './suites/authProviderSuite.js';
1
+ export { runAuthCoreConformance, runAuthProviderConformance, runPasswordAuthConformance } from './suites/authProviderSuite.js';
2
2
  export type { AuthProviderConformanceOptions } from './suites/authProviderSuite.js';
3
+ export { runOAuthAuthConformance } from './suites/oauthAuthSuite.js';
4
+ export type { OAuthAuthConformanceOptions } from './suites/oauthAuthSuite.js';
5
+ export { runAuditQueryConformance } from './suites/auditQuerySuite.js';
6
+ export type { AuditQueryConformanceOptions } from './suites/auditQuerySuite.js';
3
7
  export { runEmailLinkAuthConformance } from './suites/emailLinkAuthSuite.js';
4
8
  export type { EmailLinkAuthConformanceOptions } from './suites/emailLinkAuthSuite.js';
5
9
  export { runDefinitionStoreConformance } from './suites/definitionStoreSuite.js';
@@ -28,4 +32,3 @@ export { runPlatformProjectGrantStoreConformance } from './suites/platformProjec
28
32
  export type { PlatformProjectGrantStoreConformanceOptions } from './suites/platformProjectGrantStoreSuite.js';
29
33
  export { runApiTokenStoreConformance } from './suites/apiTokenStoreSuite.js';
30
34
  export type { ApiTokenStoreConformanceOptions, ApiTokenTestScope } from './suites/apiTokenStoreSuite.js';
31
- //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,6 @@
1
- export { runAuthProviderConformance } from './suites/authProviderSuite.js';
1
+ export { runAuthCoreConformance, runAuthProviderConformance, runPasswordAuthConformance } from './suites/authProviderSuite.js';
2
+ export { runOAuthAuthConformance } from './suites/oauthAuthSuite.js';
3
+ export { runAuditQueryConformance } from './suites/auditQuerySuite.js';
2
4
  export { runEmailLinkAuthConformance } from './suites/emailLinkAuthSuite.js';
3
5
  export { runDefinitionStoreConformance } from './suites/definitionStoreSuite.js';
4
6
  export { runOrgStoreConformance } from './suites/orgStoreSuite.js';
@@ -13,4 +15,3 @@ export { runSolveMetricSinkConformance } from './suites/solveMetricSinkSuite.js'
13
15
  export { runPlatformPermissionStoreConformance } from './suites/platformPermissionStoreSuite.js';
14
16
  export { runPlatformProjectGrantStoreConformance } from './suites/platformProjectGrantStoreSuite.js';
15
17
  export { runApiTokenStoreConformance } from './suites/apiTokenStoreSuite.js';
16
- //# sourceMappingURL=index.js.map
@@ -26,4 +26,3 @@ export interface ApiTokenStoreConformanceOptions {
26
26
  seedUser?: SeedUserFn;
27
27
  }
28
28
  export declare function runApiTokenStoreConformance(opts: ApiTokenStoreConformanceOptions): void;
29
- //# sourceMappingURL=apiTokenStoreSuite.d.ts.map
@@ -203,4 +203,3 @@ export function runApiTokenStoreConformance(opts) {
203
203
  });
204
204
  });
205
205
  }
206
- //# sourceMappingURL=apiTokenStoreSuite.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Adapter conformance suite for IAuditQuery, read through the sink that writes the
3
+ * rows. Also holds an IEventSink to what the query shows: per-actor order.
4
+ */
5
+ import type { IAuditQuery } from '../../events/audit.js';
6
+ import type { IEventSink } from '../../events/interface.js';
7
+ export interface AuditQueryConformanceOptions {
8
+ name: string;
9
+ /** A query and the sink that feeds it, over storage that starts empty. */
10
+ createStores: () => Promise<{
11
+ query: IAuditQuery;
12
+ sink: IEventSink;
13
+ }> | {
14
+ query: IAuditQuery;
15
+ sink: IEventSink;
16
+ };
17
+ }
18
+ export declare function runAuditQueryConformance(opts: AuditQueryConformanceOptions): void;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Adapter conformance suite for IAuditQuery, read through the sink that writes the
3
+ * rows. Also holds an IEventSink to what the query shows: per-actor order.
4
+ */
5
+ import { describe, it, expect } from 'vitest';
6
+ import { makeSystemCtx, makeUuid } from './helpers.js';
7
+ const ctx = makeSystemCtx();
8
+ const deleted = (orgId, actorId) => ({
9
+ type: 'org.deleted',
10
+ orgId,
11
+ actorId
12
+ });
13
+ const created = (orgId, actorId) => ({
14
+ type: 'org.created',
15
+ orgId,
16
+ actorId
17
+ });
18
+ export function runAuditQueryConformance(opts) {
19
+ const { name, createStores } = opts;
20
+ describe(`IAuditQuery conformance: ${name}`, () => {
21
+ it("returns one actor's events newest first, in the order they were emitted", async () => {
22
+ const { query, sink } = await createStores();
23
+ const actor = makeUuid();
24
+ const orgs = [makeUuid(), makeUuid(), makeUuid()];
25
+ for (const org of orgs)
26
+ await sink.emit(deleted(org, actor));
27
+ const { rows } = await query.list(ctx, { actorId: actor });
28
+ expect(rows.map((r) => r.data.orgId)).toEqual([...orgs].reverse());
29
+ });
30
+ it('filters by type and actor', async () => {
31
+ const { query, sink } = await createStores();
32
+ const actor = makeUuid();
33
+ await sink.emit(created(makeUuid(), actor));
34
+ await sink.emit(deleted(makeUuid(), actor));
35
+ await sink.emit(deleted(makeUuid(), makeUuid()));
36
+ const { rows } = await query.list(ctx, { actorId: actor, types: ['org.deleted'] });
37
+ expect(rows.map((r) => r.type)).toEqual(['org.deleted']);
38
+ });
39
+ it('honours the time bounds', async () => {
40
+ const { query, sink } = await createStores();
41
+ const actor = makeUuid();
42
+ await sink.emit(deleted(makeUuid(), actor));
43
+ const future = new Date(Date.now() + 60_000).toISOString();
44
+ const past = new Date(Date.now() - 60_000).toISOString();
45
+ expect((await query.list(ctx, { actorId: actor, sinceIso: future })).rows).toEqual([]);
46
+ expect((await query.list(ctx, { actorId: actor, untilIso: past })).rows).toEqual([]);
47
+ });
48
+ it('pages through every row exactly once', async () => {
49
+ const { query, sink } = await createStores();
50
+ const actor = makeUuid();
51
+ for (let i = 0; i < 5; i++)
52
+ await sink.emit(deleted(makeUuid(), actor));
53
+ const seen = [];
54
+ let cursor;
55
+ for (;;) {
56
+ const page = await query.list(ctx, { actorId: actor, limit: 2, cursor });
57
+ seen.push(...page.rows.map((r) => r.id));
58
+ if (!page.nextCursor)
59
+ break;
60
+ cursor = page.nextCursor;
61
+ }
62
+ expect(seen).toHaveLength(5);
63
+ expect(new Set(seen).size).toBe(5);
64
+ });
65
+ it('still returns a row for a fractional limit', async () => {
66
+ const { query, sink } = await createStores();
67
+ const actor = makeUuid();
68
+ await sink.emit(deleted(makeUuid(), actor));
69
+ const { rows } = await query.list(ctx, { actorId: actor, limit: 0.5 });
70
+ expect(rows).toHaveLength(1);
71
+ });
72
+ });
73
+ }
@@ -8,8 +8,8 @@ export interface AuthProviderConformanceOptions {
8
8
  * for password-capable providers. The factory is responsible for seeding
9
9
  * the admin user (e.g. via `createUserWithPassword`) before returning.
10
10
  *
11
- * `adminEmail` defaults to `''` for legacy reasons; new providers should
12
- * always return the seeded admin's email.
11
+ * `adminEmail` defaults to `''`; a password provider should return the seeded
12
+ * admin's email.
13
13
  */
14
14
  createProvider: () => Promise<{
15
15
  provider: IAuthProvider;
@@ -26,6 +26,17 @@ export interface AuthProviderConformanceOptions {
26
26
  * When false those methods are expected to return null / 'not_supported'.
27
27
  */
28
28
  userManagement?: boolean;
29
+ /** The provider has no `passwordAuth`, so only the core cases apply. */
30
+ passwordless?: boolean;
31
+ /** `passwordAuth.registerUser` is on, so its cases run. */
32
+ selfRegistration?: boolean;
29
33
  }
34
+ /** Cases every auth provider must pass, password or not. */
35
+ export declare function runAuthCoreConformance(opts: Pick<AuthProviderConformanceOptions, 'name' | 'createProvider'>): void;
36
+ /** Cases for a provider with `passwordAuth`. */
37
+ export declare function runPasswordAuthConformance(opts: AuthProviderConformanceOptions): void;
38
+ /**
39
+ * Both of the above, gated on what the provider has. New cases go behind an option
40
+ * so a third-party adapter does not turn red on upgrade.
41
+ */
30
42
  export declare function runAuthProviderConformance(opts: AuthProviderConformanceOptions): void;
31
- //# sourceMappingURL=authProviderSuite.d.ts.map