@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
@@ -1,4 +1,4 @@
1
1
  export type { PlatformPermission } from './types.js';
2
- export { PlatformPermissionSchema, ALL_PLATFORM_PERMISSIONS } from './types.js';
2
+ export { PlatformPermissionSchema, ALL_PLATFORM_PERMISSIONS, OPERATOR_PLATFORM_PERMISSIONS } from './types.js';
3
3
  export type { IPlatformPermissionStore } from './interface.js';
4
- //# sourceMappingURL=index.d.ts.map
4
+ export { assertCanManagePermissions, assertCanReadPermissions, assertCanReadPermissionsBatch } from '../context.js';
@@ -1,2 +1,2 @@
1
- export { PlatformPermissionSchema, ALL_PLATFORM_PERMISSIONS } from './types.js';
2
- //# sourceMappingURL=index.js.map
1
+ export { PlatformPermissionSchema, ALL_PLATFORM_PERMISSIONS, OPERATOR_PLATFORM_PERMISSIONS } from './types.js';
2
+ export { assertCanManagePermissions, assertCanReadPermissions, assertCanReadPermissionsBatch } from '../context.js';
@@ -27,7 +27,9 @@ export interface IPlatformPermissionStore {
27
27
  set(ctx: RequestContext, userId: string, permissions: readonly PlatformPermission[]): Promise<UserManagementResult>;
28
28
  /**
29
29
  * True if at least one *enabled* user holds `instance_admin`. Adapters
30
- * must exclude disabled users — over-count is safer than under-count.
30
+ * must exclude disabled users. One that can't see the disabled flag, like local,
31
+ * relies on the routes: disabling revokes `instance_admin` first, and a disabled
32
+ * user can't be granted it.
31
33
  */
32
34
  hasInstanceAdmin(ctx: RequestContext): Promise<boolean>;
33
35
  /**
@@ -45,8 +47,7 @@ export interface IPlatformPermissionStore {
45
47
  * write: on a fresh single-tenant install with no
46
48
  * `BOOTSTRAP_INSTANCE_ADMIN_EMAIL` configured, any signer is eligible, so
47
49
  * two people signing in at the same moment both observe "no admin" and both
48
- * become permanent platform admins. §2 promises "first signer wins" — this
49
- * is what makes that true rather than aspirational.
50
+ * become permanent platform admins. This is what makes first signer win.
50
51
  *
51
52
  * Same shape as the sole-admin invariant (`set`), pointing the other way:
52
53
  * that one refuses to drop the last admin, this one refuses to create a
@@ -54,4 +55,3 @@ export interface IPlatformPermissionStore {
54
55
  */
55
56
  claimFirstInstanceAdmin(ctx: RequestContext, userId: string, permissions: readonly PlatformPermission[]): Promise<boolean>;
56
57
  }
57
- //# sourceMappingURL=interface.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=interface.js.map
@@ -23,4 +23,3 @@ export declare const ALL_PLATFORM_PERMISSIONS: readonly PlatformPermission[];
23
23
  * `manage_api_tokens` is granted to ordinary users, who have no business there.
24
24
  */
25
25
  export declare const OPERATOR_PLATFORM_PERMISSIONS: readonly PlatformPermission[];
26
- //# sourceMappingURL=types.d.ts.map
@@ -22,4 +22,3 @@ export const ALL_PLATFORM_PERMISSIONS = PlatformPermissionSchema.options;
22
22
  * `manage_api_tokens` is granted to ordinary users, who have no business there.
23
23
  */
24
24
  export const OPERATOR_PLATFORM_PERMISSIONS = ALL_PLATFORM_PERMISSIONS.filter((p) => p !== 'manage_api_tokens');
25
- //# sourceMappingURL=types.js.map
@@ -1,4 +1,2 @@
1
- export type { PlatformProjectGrant, PlatformProjectGranteeType } from './types.js';
1
+ export type { PlatformProjectGrant } from './types.js';
2
2
  export type { IPlatformProjectGrantStore } from './interface.js';
3
- export { PlatformProjectGrantSchema, PlatformProjectGranteeTypeSchema } from './schemas.js';
4
- //# sourceMappingURL=index.d.ts.map
@@ -1,2 +1 @@
1
- export { PlatformProjectGrantSchema, PlatformProjectGranteeTypeSchema } from './schemas.js';
2
- //# sourceMappingURL=index.js.map
1
+ export {};
@@ -22,4 +22,3 @@ export interface IPlatformProjectGrantStore {
22
22
  */
23
23
  deleteByGranteeOrg(ctx: RequestContext, orgId: string): Promise<void>;
24
24
  }
25
- //# sourceMappingURL=interface.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=interface.js.map
@@ -15,4 +15,3 @@ export declare const PlatformProjectGrantSchema: z.ZodObject<{
15
15
  createdBy: z.ZodString;
16
16
  createdAt: z.ZodString;
17
17
  }, z.core.$strip>;
18
- //# sourceMappingURL=schemas.d.ts.map
@@ -9,4 +9,3 @@ export const PlatformProjectGrantSchema = z.object({
9
9
  createdBy: z.string(),
10
10
  createdAt: z.string()
11
11
  });
12
- //# sourceMappingURL=schemas.js.map
@@ -1,4 +1,6 @@
1
- export type PlatformProjectGranteeType = 'org' | 'user';
1
+ import type { z } from 'zod';
2
+ import type { PlatformProjectGranteeTypeSchema } from './schemas.js';
3
+ export type PlatformProjectGranteeType = z.infer<typeof PlatformProjectGranteeTypeSchema>;
2
4
  /**
3
5
  * Grants view-only or view+solve access to a `platform`-visibility project
4
6
  * for an org or an individual user, without creating project membership rows.
@@ -16,4 +18,3 @@ export interface PlatformProjectGrant {
16
18
  createdBy: string;
17
19
  createdAt: string;
18
20
  }
19
- //# sourceMappingURL=types.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map
@@ -2,4 +2,3 @@ export type { Project, ProjectMember } from './types.js';
2
2
  export type { IProjectStore } from './interface.js';
3
3
  export type { ProjectVisibility, ProjectRole } from './schemas.js';
4
4
  export { ProjectVisibilitySchema, ProjectRoleSchema, validateProjectFlags } from './schemas.js';
5
- //# sourceMappingURL=index.d.ts.map
@@ -1,2 +1 @@
1
1
  export { ProjectVisibilitySchema, ProjectRoleSchema, validateProjectFlags } from './schemas.js';
2
- //# sourceMappingURL=index.js.map
@@ -38,4 +38,3 @@ export interface IProjectStore {
38
38
  updateProjectMemberRole(ctx: RequestContext, projectId: string, userId: string, role: ProjectRole): Promise<void>;
39
39
  removeProjectMember(ctx: RequestContext, projectId: string, userId: string): Promise<void>;
40
40
  }
41
- //# sourceMappingURL=interface.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=interface.js.map
@@ -20,4 +20,3 @@ export declare function validateProjectFlags(merged: {
20
20
  path: string;
21
21
  message: string;
22
22
  }[];
23
- //# sourceMappingURL=schemas.d.ts.map
@@ -18,4 +18,3 @@ export function validateProjectFlags(merged) {
18
18
  }
19
19
  return issues;
20
20
  }
21
- //# sourceMappingURL=schemas.js.map
@@ -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