@nlabs/reaktor 1.17.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/README.md +182 -0
  2. package/docs/ASSISTANT.md +138 -0
  3. package/docs/GENERATION.md +42 -5
  4. package/docs/NATIVE_PUSH.md +56 -0
  5. package/lib/actions/alfredFaq.d.ts +80 -0
  6. package/lib/actions/alfredFaq.js +206 -0
  7. package/lib/actions/analytics.js +1 -1
  8. package/lib/actions/apps.js +1 -1
  9. package/lib/actions/connections.js +1 -1
  10. package/lib/actions/content.js +1 -1
  11. package/lib/actions/contentGeneration.d.ts +4 -0
  12. package/lib/actions/contentGeneration.js +82 -10
  13. package/lib/actions/contentGenerationErrors.js +1 -1
  14. package/lib/actions/conversations.d.ts +1 -1
  15. package/lib/actions/conversations.js +19 -9
  16. package/lib/actions/crm.js +1 -1
  17. package/lib/actions/crud.js +26 -1
  18. package/lib/actions/databaseAccounts.js +1 -1
  19. package/lib/actions/databaseProvisioningLease.js +1 -1
  20. package/lib/actions/dynamodb.js +1 -1
  21. package/lib/actions/email.js +1 -1
  22. package/lib/actions/files.js +1 -1
  23. package/lib/actions/flags.js +1 -1
  24. package/lib/actions/geminiVideo.js +1 -1
  25. package/lib/actions/groups.js +1 -1
  26. package/lib/actions/higgsfield.js +1 -1
  27. package/lib/actions/imageGeneration.js +1 -1
  28. package/lib/actions/images.js +1 -1
  29. package/lib/actions/index.d.ts +1 -0
  30. package/lib/actions/index.js +2 -1
  31. package/lib/actions/ios.js +1 -1
  32. package/lib/actions/locations.js +1 -1
  33. package/lib/actions/messages.js +23 -7
  34. package/lib/actions/notifications.js +1 -1
  35. package/lib/actions/ollamaGeneration.js +1 -1
  36. package/lib/actions/openaiResponseSession.js +1 -1
  37. package/lib/actions/payments.js +1 -1
  38. package/lib/actions/personas.js +1 -1
  39. package/lib/actions/phoneSupport.js +1 -1
  40. package/lib/actions/posts.js +1 -1
  41. package/lib/actions/query.js +1 -1
  42. package/lib/actions/reactions.js +1 -1
  43. package/lib/actions/rum.js +1 -1
  44. package/lib/actions/s3.js +1 -1
  45. package/lib/actions/search.js +1 -1
  46. package/lib/actions/sms.js +1 -1
  47. package/lib/actions/statistics.js +1 -1
  48. package/lib/actions/subscriptions.js +1 -1
  49. package/lib/actions/tags.js +1 -1
  50. package/lib/actions/users.js +57 -4
  51. package/lib/actions/videoGeneration.js +1 -1
  52. package/lib/actions/videos.js +1 -1
  53. package/lib/adapters/arangoAdapter.js +1 -1
  54. package/lib/adapters/contentAdapter.js +1 -1
  55. package/lib/adapters/fileAdapter.js +1 -1
  56. package/lib/adapters/geminiGenerationAdapter.js +1 -1
  57. package/lib/adapters/higgsfieldAdapter.js +1 -1
  58. package/lib/adapters/higgsfieldModelCatalog.js +1 -1
  59. package/lib/adapters/higgsfieldModels.js +1 -1
  60. package/lib/adapters/imageAdapter.js +1 -1
  61. package/lib/adapters/imageGenerationAdapter.js +1 -1
  62. package/lib/adapters/index.js +1 -1
  63. package/lib/adapters/messageAdapter.js +1 -1
  64. package/lib/adapters/postAdapter.js +1 -1
  65. package/lib/adapters/reaktorAdapter.js +1 -1
  66. package/lib/adapters/tagAdapter.js +1 -1
  67. package/lib/adapters/userAdapter.js +1 -1
  68. package/lib/assistant/core.d.ts +53 -0
  69. package/lib/assistant/core.js +123 -0
  70. package/lib/assistant/faq.d.ts +26 -0
  71. package/lib/assistant/faq.js +238 -0
  72. package/lib/assistant/faqCore.d.ts +23 -0
  73. package/lib/assistant/faqCore.js +20 -0
  74. package/lib/assistant/index.d.ts +7 -0
  75. package/lib/assistant/index.js +5 -0
  76. package/lib/assistant/service.d.ts +35 -0
  77. package/lib/assistant/service.js +201 -0
  78. package/lib/config.js +1 -1
  79. package/lib/constants/collections.js +1 -1
  80. package/lib/durableChat/conversations.d.ts +62 -0
  81. package/lib/durableChat/conversations.js +729 -0
  82. package/lib/durableChat/errors.d.ts +6 -0
  83. package/lib/durableChat/errors.js +11 -0
  84. package/lib/durableChat/events.d.ts +22 -0
  85. package/lib/durableChat/events.js +50 -0
  86. package/lib/durableChat/index.d.ts +8 -0
  87. package/lib/durableChat/index.js +10 -0
  88. package/lib/durableChat/membership.d.ts +24 -0
  89. package/lib/durableChat/membership.js +85 -0
  90. package/lib/durableChat/messageTypes.d.ts +76 -0
  91. package/lib/durableChat/messageTypes.js +3 -0
  92. package/lib/durableChat/messages.d.ts +16 -0
  93. package/lib/durableChat/messages.js +257 -0
  94. package/lib/durableChat/transaction.d.ts +10 -0
  95. package/lib/durableChat/transaction.js +53 -0
  96. package/lib/durableChat/types.d.ts +81 -0
  97. package/lib/durableChat/types.js +3 -0
  98. package/lib/handlers/graphqlHandler.js +1 -1
  99. package/lib/index.d.ts +4 -4
  100. package/lib/index.js +5 -3
  101. package/lib/lambdas/actions/websockets.js +4 -4
  102. package/lib/lambdas/authorizer.js +1 -1
  103. package/lib/lambdas/connection.js +1 -1
  104. package/lib/lambdas/utils/message.js +1 -1
  105. package/lib/lambdas/utils/websocket.js +1 -1
  106. package/lib/mocks/conversation.js +1 -1
  107. package/lib/mocks/file.js +1 -1
  108. package/lib/mocks/group.js +1 -1
  109. package/lib/mocks/image.js +1 -1
  110. package/lib/mocks/post.js +1 -1
  111. package/lib/mocks/tag.js +1 -1
  112. package/lib/mocks/user.js +1 -1
  113. package/lib/mocks/video.js +1 -1
  114. package/lib/mutations/analytics/analytics.js +1 -1
  115. package/lib/mutations/content/content.js +1 -1
  116. package/lib/mutations/crm/crm.js +1 -1
  117. package/lib/mutations/events/events.js +1 -1
  118. package/lib/mutations/flags/flags.js +1 -1
  119. package/lib/mutations/groups/groups.js +1 -1
  120. package/lib/mutations/higgsfield/higgsfield.js +1 -1
  121. package/lib/mutations/images/images.js +1 -1
  122. package/lib/mutations/index.js +1 -1
  123. package/lib/mutations/locations/locations.js +1 -1
  124. package/lib/mutations/messages/messages.js +1 -1
  125. package/lib/mutations/personas/personas.js +1 -1
  126. package/lib/mutations/posts/posts.js +1 -1
  127. package/lib/mutations/reactions/reactions.js +1 -1
  128. package/lib/mutations/rum/rum.js +1 -1
  129. package/lib/mutations/statistics/statistics.js +1 -1
  130. package/lib/mutations/subscriptions/subscriptions.js +1 -1
  131. package/lib/mutations/tags/tags.js +1 -1
  132. package/lib/mutations/users/users.js +1 -1
  133. package/lib/mutations/videos/videos.js +1 -1
  134. package/lib/nativePush/graphql.d.ts +14 -0
  135. package/lib/nativePush/graphql.js +105 -0
  136. package/lib/nativePush/index.d.ts +7 -0
  137. package/lib/nativePush/index.js +9 -0
  138. package/lib/nativePush/migrations.d.ts +2 -0
  139. package/lib/nativePush/migrations.js +36 -0
  140. package/lib/nativePush/nativePushContract.fixture.d.ts +22 -0
  141. package/lib/nativePush/nativePushContract.fixture.js +27 -0
  142. package/lib/nativePush/payload.d.ts +2 -0
  143. package/lib/nativePush/payload.js +106 -0
  144. package/lib/nativePush/repository.d.ts +9 -0
  145. package/lib/nativePush/repository.js +120 -0
  146. package/lib/nativePush/service.d.ts +2 -0
  147. package/lib/nativePush/service.js +110 -0
  148. package/lib/nativePush/snsProvider.d.ts +17 -0
  149. package/lib/nativePush/snsProvider.js +165 -0
  150. package/lib/nativePush/types.d.ts +89 -0
  151. package/lib/nativePush/types.js +3 -0
  152. package/lib/objectTypes/analytics.js +1 -1
  153. package/lib/objectTypes/app.js +1 -1
  154. package/lib/objectTypes/bankAccount.js +1 -1
  155. package/lib/objectTypes/connection.js +1 -1
  156. package/lib/objectTypes/content.js +1 -1
  157. package/lib/objectTypes/contentGeneration.js +1 -1
  158. package/lib/objectTypes/conversation.js +1 -1
  159. package/lib/objectTypes/creditCard.js +1 -1
  160. package/lib/objectTypes/crm.js +1 -1
  161. package/lib/objectTypes/document.js +1 -1
  162. package/lib/objectTypes/error.js +1 -1
  163. package/lib/objectTypes/event.js +1 -1
  164. package/lib/objectTypes/external.js +1 -1
  165. package/lib/objectTypes/file.js +1 -1
  166. package/lib/objectTypes/filter.js +1 -1
  167. package/lib/objectTypes/flag.js +1 -1
  168. package/lib/objectTypes/group.js +1 -1
  169. package/lib/objectTypes/higgsfield.js +1 -1
  170. package/lib/objectTypes/iapSubscription.js +1 -1
  171. package/lib/objectTypes/image.js +1 -1
  172. package/lib/objectTypes/imageGeneration.js +1 -1
  173. package/lib/objectTypes/index.js +1 -1
  174. package/lib/objectTypes/location.js +1 -1
  175. package/lib/objectTypes/message.js +1 -1
  176. package/lib/objectTypes/passcode.js +1 -1
  177. package/lib/objectTypes/persona.js +1 -1
  178. package/lib/objectTypes/plan.js +1 -1
  179. package/lib/objectTypes/post.js +1 -1
  180. package/lib/objectTypes/query.js +1 -1
  181. package/lib/objectTypes/reaction.js +1 -1
  182. package/lib/objectTypes/relation.js +1 -1
  183. package/lib/objectTypes/rum.js +1 -1
  184. package/lib/objectTypes/search.js +1 -1
  185. package/lib/objectTypes/statistics.js +1 -1
  186. package/lib/objectTypes/subscription.js +1 -1
  187. package/lib/objectTypes/tag.js +1 -1
  188. package/lib/objectTypes/user.js +1 -1
  189. package/lib/objectTypes/video.js +1 -1
  190. package/lib/objectTypes/videoGeneration.js +1 -1
  191. package/lib/organizations/accountLifecycle.d.ts +7 -0
  192. package/lib/organizations/accountLifecycle.js +106 -0
  193. package/lib/organizations/authorization.d.ts +9 -0
  194. package/lib/organizations/authorization.js +40 -0
  195. package/lib/organizations/billing.d.ts +38 -0
  196. package/lib/organizations/billing.js +277 -0
  197. package/lib/organizations/billingProvider.d.ts +4 -0
  198. package/lib/organizations/billingProvider.js +287 -0
  199. package/lib/organizations/billingUpdates.d.ts +9 -0
  200. package/lib/organizations/billingUpdates.js +388 -0
  201. package/lib/organizations/index.d.ts +10 -0
  202. package/lib/organizations/index.js +12 -0
  203. package/lib/organizations/mail.d.ts +10 -0
  204. package/lib/organizations/mail.js +60 -0
  205. package/lib/organizations/memberDirectory.d.ts +15 -0
  206. package/lib/organizations/memberDirectory.js +28 -0
  207. package/lib/organizations/membership.d.ts +19 -0
  208. package/lib/organizations/membership.js +248 -0
  209. package/lib/organizations/passwordRecovery.d.ts +9 -0
  210. package/lib/organizations/passwordRecovery.js +50 -0
  211. package/lib/organizations/plans.d.ts +6 -0
  212. package/lib/organizations/plans.js +40 -0
  213. package/lib/organizations/providerPagination.d.ts +6 -0
  214. package/lib/organizations/providerPagination.js +23 -0
  215. package/lib/organizations/reconciliation.d.ts +11 -0
  216. package/lib/organizations/reconciliation.js +400 -0
  217. package/lib/organizations/signup.d.ts +25 -0
  218. package/lib/organizations/signup.js +169 -0
  219. package/lib/organizations/store.d.ts +25 -0
  220. package/lib/organizations/store.js +167 -0
  221. package/lib/organizations/types.d.ts +138 -0
  222. package/lib/organizations/types.js +3 -0
  223. package/lib/organizations/verification.d.ts +3 -0
  224. package/lib/organizations/verification.js +51 -0
  225. package/lib/queries/analytics/analytics.js +1 -1
  226. package/lib/queries/content/content.js +1 -1
  227. package/lib/queries/crm/crm.js +1 -1
  228. package/lib/queries/events/events.js +1 -1
  229. package/lib/queries/flags/flags.js +1 -1
  230. package/lib/queries/groups/groups.js +1 -1
  231. package/lib/queries/higgsfield/higgsfield.js +1 -1
  232. package/lib/queries/images/images.js +1 -1
  233. package/lib/queries/index.js +1 -1
  234. package/lib/queries/locations/locations.js +1 -1
  235. package/lib/queries/messages/messages.js +1 -1
  236. package/lib/queries/personas/personas.js +1 -1
  237. package/lib/queries/posts/posts.js +1 -1
  238. package/lib/queries/query/query.js +1 -1
  239. package/lib/queries/reactions/reactions.js +1 -1
  240. package/lib/queries/statistics/statistics.js +1 -1
  241. package/lib/queries/subscriptions/subscriptions.js +1 -1
  242. package/lib/queries/tags/tags.js +1 -1
  243. package/lib/queries/users/users.js +1 -1
  244. package/lib/queries/videos/videos.js +1 -1
  245. package/lib/templates/email/layout.js +1 -1
  246. package/lib/templates/email/passwordForgot.js +1 -1
  247. package/lib/templates/email/passwordRecovery.js +1 -1
  248. package/lib/templates/email/verifyEmail.js +1 -1
  249. package/lib/templates/email/welcome.js +1 -1
  250. package/lib/templates/sms/passwordForgot.js +1 -1
  251. package/lib/templates/sms/passwordRecovery.js +1 -1
  252. package/lib/templates/sms/verifyEmail.js +1 -1
  253. package/lib/templates/sms/verifyPhone.js +1 -1
  254. package/lib/templates/sms/welcome.js +1 -1
  255. package/lib/types/analytics.types.js +1 -1
  256. package/lib/types/apps.types.js +1 -1
  257. package/lib/types/arangodb.types.js +1 -1
  258. package/lib/types/auth.types.js +1 -1
  259. package/lib/types/connections.types.js +1 -1
  260. package/lib/types/content.types.js +1 -1
  261. package/lib/types/conversations.types.js +1 -1
  262. package/lib/types/crm.types.js +1 -1
  263. package/lib/types/databaseCredentials.types.js +1 -1
  264. package/lib/types/email.types.js +1 -1
  265. package/lib/types/error.types.js +1 -1
  266. package/lib/types/files.types.js +1 -1
  267. package/lib/types/flags.types.js +1 -1
  268. package/lib/types/google.types.js +1 -1
  269. package/lib/types/groups.types.js +1 -1
  270. package/lib/types/images.types.js +1 -1
  271. package/lib/types/index.js +1 -1
  272. package/lib/types/locations.types.js +1 -1
  273. package/lib/types/messages.types.js +1 -1
  274. package/lib/types/notifications.types.js +1 -1
  275. package/lib/types/payments.types.js +1 -1
  276. package/lib/types/personas.types.js +1 -1
  277. package/lib/types/posts.types.js +1 -1
  278. package/lib/types/rum.types.js +1 -1
  279. package/lib/types/statistics.types.js +1 -1
  280. package/lib/types/tags.types.js +1 -1
  281. package/lib/types/users.types.js +1 -1
  282. package/lib/types/videos.types.js +1 -1
  283. package/lib/types/websockets.types.js +1 -1
  284. package/lib/upload.js +1 -1
  285. package/lib/utils/adapterUtils.js +1 -1
  286. package/lib/utils/analyticsUtils.js +1 -1
  287. package/lib/utils/appContext.js +1 -1
  288. package/lib/utils/aqlHelpers.js +1 -1
  289. package/lib/utils/arangodbUtils.js +1 -1
  290. package/lib/utils/authUtils.js +1 -1
  291. package/lib/utils/awsUtils.js +1 -1
  292. package/lib/utils/collectionRegistry.js +1 -1
  293. package/lib/utils/contextUtils.js +1 -1
  294. package/lib/utils/databaseCredentials.js +1 -1
  295. package/lib/utils/dbI18n.example.js +1 -1
  296. package/lib/utils/dbI18n.js +1 -1
  297. package/lib/utils/generationCallback.js +1 -1
  298. package/lib/utils/googleTranslate.js +1 -1
  299. package/lib/utils/graphqlUtils.js +1 -1
  300. package/lib/utils/imageUtils.js +1 -1
  301. package/lib/utils/index.js +1 -1
  302. package/lib/utils/languageDetection.js +1 -1
  303. package/lib/utils/localeUtils.example.js +1 -1
  304. package/lib/utils/localeUtils.js +1 -1
  305. package/lib/utils/mediaAccess.js +1 -1
  306. package/lib/utils/middlewareUtils.js +1 -1
  307. package/lib/utils/nodeRealtime.js +1 -1
  308. package/lib/utils/opaqueToken.js +1 -1
  309. package/lib/utils/queryBuilder.js +1 -1
  310. package/lib/utils/schemaUtils.js +1 -1
  311. package/lib/utils/secretDatabase.js +1 -1
  312. package/lib/utils/sessionUtils.js +1 -1
  313. package/lib/utils/stripeUtils.js +1 -1
  314. package/lib/utils/stripeUtils.ts.bak +1 -1
  315. package/lib/utils/templateUtils.js +1 -1
  316. package/lib/utils/testUtils.js +1 -1
  317. package/lib/utils/translationQueue.example.js +1 -1
  318. package/lib/utils/translationQueue.js +1 -1
  319. package/lib/videoProcessing.js +1 -1
  320. package/package.json +16 -3
@@ -0,0 +1,169 @@
1
+ import { createHash, createPassword, parsePassword } from '@nlabs/utils/parsers/strings';
2
+ import { createHmac, randomBytes } from 'node:crypto';
3
+ import { organizationUserId } from './authorization.js';
4
+ import { encodeOrganizationMail, organizationMailKey } from './mail.js';
5
+ import { newOrganizationId, organizationKey, organizationStoreFor, requireIdentifier } from './store.js';
6
+ export const queueOrganizationVerification = async (tx, registration, previous)=>{
7
+ const now = Date.now();
8
+ const token = randomBytes(32).toString('base64url');
9
+ const withinHour = previous && now - previous.resendWindow < 3600000;
10
+ const verification = {
11
+ attemptWindow: previous?.attemptWindow || now,
12
+ attempts: previous?.attempts || 0,
13
+ expiresAt: now + 24 * 3600000,
14
+ lastSent: now,
15
+ resendCount: withinHour ? previous.resendCount + 1 : 1,
16
+ resendWindow: withinHour ? previous.resendWindow : now,
17
+ tokenHash: organizationKey(token),
18
+ used: false,
19
+ userId: registration.userId
20
+ };
21
+ await tx.put('organizationVerificationTokens', registration.registrationId, verification, previous);
22
+ const jobId = newOrganizationId();
23
+ const job = {
24
+ attempts: 0,
25
+ desired: {
26
+ ciphertext: encodeOrganizationMail({
27
+ email: registration.email,
28
+ registrationId: registration.registrationId,
29
+ token
30
+ })
31
+ },
32
+ effectiveAt: now,
33
+ jobId,
34
+ kind: 'mail',
35
+ leaseExpires: 0,
36
+ organizationId: registration.organizationId,
37
+ owner: '',
38
+ priceVersion: '2026-10-v1',
39
+ sequence: -now,
40
+ status: 'pending'
41
+ };
42
+ await tx.put('organizationBillingJobs', jobId, job);
43
+ };
44
+ const insertOrganization = async (tx, name, userId)=>{
45
+ const now = Date.now();
46
+ const organization = {
47
+ createdAt: now,
48
+ name,
49
+ organizationId: newOrganizationId(),
50
+ ownerUserId: userId,
51
+ revision: 0,
52
+ updatedAt: now
53
+ };
54
+ const membership = {
55
+ createdAt: now,
56
+ organizationId: organization.organizationId,
57
+ revision: 0,
58
+ role: 'admin',
59
+ status: 'active',
60
+ updatedAt: now,
61
+ userId
62
+ };
63
+ await tx.put('organizations', organization.organizationId, organization);
64
+ await tx.put('organizationMemberships', organizationKey(organization.organizationId, userId), membership);
65
+ return organization;
66
+ };
67
+ export const registerOrganization = async (input, controlContext)=>{
68
+ if (!input || Object.keys(input).some((key)=>![
69
+ 'email',
70
+ 'organizationName',
71
+ 'password',
72
+ 'requestId'
73
+ ].includes(key)) || typeof input.email !== 'string' || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.email) || input.email.length > 254 || typeof input.password !== 'string' || input.password.length < 12 || input.password.length > 128 || typeof input.organizationName !== 'string' || !input.organizationName.trim() || input.organizationName.length > 160) {
74
+ throw new Error('invalid_signup');
75
+ }
76
+ requireIdentifier(input.requestId);
77
+ const email = input.email.trim().toLowerCase();
78
+ const fingerprint = createHmac('sha256', organizationMailKey()).update(JSON.stringify({
79
+ ...input,
80
+ email
81
+ })).digest('hex');
82
+ const registrationId = organizationKey('registration', email, input.requestId);
83
+ return organizationStoreFor(controlContext).transaction(async (tx)=>{
84
+ const previous = await tx.get('organizationRegistrations', registrationId);
85
+ if (previous) {
86
+ if (previous.fingerprint !== fingerprint) {
87
+ throw new Error('registration_conflict');
88
+ }
89
+ return {
90
+ registrationId,
91
+ verificationRequired: true
92
+ };
93
+ }
94
+ const users = await tx.find('users', {
95
+ email
96
+ });
97
+ const userId = createHash(email);
98
+ const collision = await tx.get('users', userId);
99
+ const existing = users.length > 0 || Boolean(collision);
100
+ let organizationId = '';
101
+ if (!existing) {
102
+ const salt = randomBytes(32).toString('hex');
103
+ await tx.put('users', userId, {
104
+ active: true,
105
+ added: Date.now(),
106
+ email,
107
+ locale: 'en',
108
+ organizationAccount: true,
109
+ password: createPassword(parsePassword(input.password), salt),
110
+ salt,
111
+ type: 'user',
112
+ userAccess: 0,
113
+ username: email,
114
+ verifiedEmail: false
115
+ });
116
+ ({ organizationId } = await insertOrganization(tx, input.organizationName.trim(), userId));
117
+ }
118
+ const registration = {
119
+ email,
120
+ fingerprint,
121
+ organizationId,
122
+ registrationId,
123
+ requestId: input.requestId,
124
+ userId: existing ? '' : userId
125
+ };
126
+ await tx.put('organizationRegistrations', registrationId, registration);
127
+ if (!existing) {
128
+ await queueOrganizationVerification(tx, registration);
129
+ }
130
+ return {
131
+ registrationId,
132
+ verificationRequired: true
133
+ };
134
+ });
135
+ };
136
+ export const createOrganization = (context, name, requestId)=>organizationStoreFor(context).transaction(async (tx)=>{
137
+ const userId = organizationUserId(context);
138
+ const user = await tx.get('users', userId);
139
+ if (!user?.active || !user.verifiedEmail) {
140
+ throw new Error('email_verification_required');
141
+ }
142
+ if (typeof name !== 'string' || !name.trim() || name.length > 160) {
143
+ throw new Error('invalid_organization_name');
144
+ }
145
+ const key = organizationKey('authenticated-organization', userId, requireIdentifier(requestId));
146
+ const previous = await tx.get('organizationRegistrations', key);
147
+ if (previous) {
148
+ if (previous.name !== name.trim()) {
149
+ throw new Error('registration_conflict');
150
+ }
151
+ const existing = await tx.get('organizations', previous.organizationId);
152
+ const { _key, _rev, ...organization } = existing;
153
+ return organization;
154
+ }
155
+ const org = await insertOrganization(tx, name.trim(), userId);
156
+ await tx.put('organizationRegistrations', key, {
157
+ name: name.trim(),
158
+ organizationId: org.organizationId,
159
+ requestId: key,
160
+ userId
161
+ });
162
+ await tx.put('users', userId, {
163
+ ...user,
164
+ organizationAccount: true
165
+ }, user);
166
+ return org;
167
+ });
168
+
169
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9wcml2YXRlL3RtcC92YXVsdC1yZWFrdG9yLWNvbXBsZXRpb24vcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy9zaWdudXAudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtjcmVhdGVIYXNoLCBjcmVhdGVQYXNzd29yZCwgcGFyc2VQYXNzd29yZH0gZnJvbSAnQG5sYWJzL3V0aWxzL3BhcnNlcnMvc3RyaW5ncyc7XG5pbXBvcnQge2NyZWF0ZUhtYWMsIHJhbmRvbUJ5dGVzfSBmcm9tICdub2RlOmNyeXB0byc7XG5cbmltcG9ydCB7b3JnYW5pemF0aW9uVXNlcklkfSBmcm9tICcuL2F1dGhvcml6YXRpb24uanMnO1xuaW1wb3J0IHtlbmNvZGVPcmdhbml6YXRpb25NYWlsLCBvcmdhbml6YXRpb25NYWlsS2V5fSBmcm9tICcuL21haWwuanMnO1xuaW1wb3J0IHtcbiAgbmV3T3JnYW5pemF0aW9uSWQsXG4gIG9yZ2FuaXphdGlvbktleSxcbiAgb3JnYW5pemF0aW9uU3RvcmVGb3IsXG4gIHJlcXVpcmVJZGVudGlmaWVyLFxuICB0eXBlIE9yZ2FuaXphdGlvblRyYW5zYWN0aW9uXG59IGZyb20gJy4vc3RvcmUuanMnO1xuXG5pbXBvcnQgdHlwZSB7QXBpQ29udGV4dH0gZnJvbSAnLi4vdHlwZXMvYXV0aC50eXBlcy5qcyc7XG5pbXBvcnQgdHlwZSB7QmlsbGluZ0pvYiwgT3JnYW5pemF0aW9uLCBPcmdhbml6YXRpb25NZW1iZXJzaGlwLCBTaWdudXBJbnB1dCwgU2lnbnVwUmVzdWx0fSBmcm9tICcuL3R5cGVzLmpzJztcblxuZXhwb3J0IHR5cGUgUmVnaXN0cmF0aW9uID0ge1xuICBlbWFpbDogc3RyaW5nO1xuICBmaW5nZXJwcmludDogc3RyaW5nO1xuICBvcmdhbml6YXRpb25JZDogc3RyaW5nO1xuICByZWdpc3RyYXRpb25JZDogc3RyaW5nO1xuICByZXF1ZXN0SWQ6IHN0cmluZztcbiAgdXNlcklkOiBzdHJpbmc7XG59O1xuZXhwb3J0IHR5cGUgVmVyaWZpY2F0aW9uID0ge1xuICBhdHRlbXB0czogbnVtYmVyO1xuICBhdHRlbXB0V2luZG93OiBudW1iZXI7XG4gIGV4cGlyZXNBdDogbnVtYmVyO1xuICBsYXN0U2VudDogbnVtYmVyO1xuICByZXNlbmRDb3VudDogbnVtYmVyO1xuICByZXNlbmRXaW5kb3c6IG51bWJlcjtcbiAgdG9rZW5IYXNoOiBzdHJpbmc7XG4gIHVzZWQ6IGJvb2xlYW47XG4gIHVzZXJJZDogc3RyaW5nO1xufTtcbmV4cG9ydCBjb25zdCBxdWV1ZU9yZ2FuaXphdGlvblZlcmlmaWNhdGlvbiA9IGFzeW5jIChcbiAgdHg6IE9yZ2FuaXphdGlvblRyYW5zYWN0aW9uLFxuICByZWdpc3RyYXRpb246IFJlZ2lzdHJhdGlvbixcbiAgcHJldmlvdXM/OiBpbXBvcnQoJy4vc3RvcmUuanMnKS5TdG9yZWQ8VmVyaWZpY2F0aW9uPiB8IG51bGxcbik6IFByb21pc2U8dm9pZD4gPT4ge1xuICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICBjb25zdCB0b2tlbiA9IHJhbmRvbUJ5dGVzKDMyKS50b1N0cmluZygnYmFzZTY0dXJsJyk7XG4gIGNvbnN0IHdpdGhpbkhvdXIgPSBwcmV2aW91cyAmJiBub3cgLSBwcmV2aW91cy5yZXNlbmRXaW5kb3cgPCAzNjAwMDAwO1xuICBjb25zdCB2ZXJpZmljYXRpb246IFZlcmlmaWNhdGlvbiA9IHtcbiAgICBhdHRlbXB0V2luZG93OiBwcmV2aW91cz8uYXR0ZW1wdFdpbmRvdyB8fCBub3csXG4gICAgYXR0ZW1wdHM6IHByZXZpb3VzPy5hdHRlbXB0cyB8fCAwLFxuICAgIGV4cGlyZXNBdDogbm93ICsgKDI0ICogMzYwMDAwMCksXG4gICAgbGFzdFNlbnQ6IG5vdyxcbiAgICByZXNlbmRDb3VudDogd2l0aGluSG91ciA/IHByZXZpb3VzLnJlc2VuZENvdW50ICsgMSA6IDEsXG4gICAgcmVzZW5kV2luZG93OiB3aXRoaW5Ib3VyID8gcHJldmlvdXMucmVzZW5kV2luZG93IDogbm93LFxuICAgIHRva2VuSGFzaDogb3JnYW5pemF0aW9uS2V5KHRva2VuKSxcbiAgICB1c2VkOiBmYWxzZSxcbiAgICB1c2VySWQ6IHJlZ2lzdHJhdGlvbi51c2VySWRcbiAgfTtcbiAgYXdhaXQgdHgucHV0KCdvcmdhbml6YXRpb25WZXJpZmljYXRpb25Ub2tlbnMnLCByZWdpc3RyYXRpb24ucmVnaXN0cmF0aW9uSWQsIHZlcmlmaWNhdGlvbiwgcHJldmlvdXMpO1xuICBjb25zdCBqb2JJZCA9IG5ld09yZ2FuaXphdGlvbklkKCk7XG4gIGNvbnN0IGpvYjogQmlsbGluZ0pvYiA9IHtcbiAgICBhdHRlbXB0czogMCxcbiAgICBkZXNpcmVkOiB7XG4gICAgICBjaXBoZXJ0ZXh0OiBlbmNvZGVPcmdhbml6YXRpb25NYWlsKHtcbiAgICAgICAgZW1haWw6IHJlZ2lzdHJhdGlvbi5lbWFpbCxcbiAgICAgICAgcmVnaXN0cmF0aW9uSWQ6IHJlZ2lzdHJhdGlvbi5yZWdpc3RyYXRpb25JZCxcbiAgICAgICAgdG9rZW5cbiAgICAgIH0pXG4gICAgfSxcbiAgICBlZmZlY3RpdmVBdDogbm93LFxuICAgIGpvYklkLFxuICAgIGtpbmQ6ICdtYWlsJyxcbiAgICBsZWFzZUV4cGlyZXM6IDAsXG4gICAgb3JnYW5pemF0aW9uSWQ6IHJlZ2lzdHJhdGlvbi5vcmdhbml6YXRpb25JZCxcbiAgICBvd25lcjogJycsXG4gICAgcHJpY2VWZXJzaW9uOiAnMjAyNi0xMC12MScsXG4gICAgc2VxdWVuY2U6IC1ub3csXG4gICAgc3RhdHVzOiAncGVuZGluZydcbiAgfTtcbiAgYXdhaXQgdHgucHV0KCdvcmdhbml6YXRpb25CaWxsaW5nSm9icycsIGpvYklkLCBqb2IpO1xufTtcblxuY29uc3QgaW5zZXJ0T3JnYW5pemF0aW9uID0gYXN5bmMgKFxuICB0eDogT3JnYW5pemF0aW9uVHJhbnNhY3Rpb24sXG4gIG5hbWU6IHN0cmluZyxcbiAgdXNlcklkOiBzdHJpbmdcbik6IFByb21pc2U8T3JnYW5pemF0aW9uPiA9PiB7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gIGNvbnN0IG9yZ2FuaXphdGlvbjogT3JnYW5pemF0aW9uID0ge1xuICAgIGNyZWF0ZWRBdDogbm93LFxuICAgIG5hbWUsXG4gICAgb3JnYW5pemF0aW9uSWQ6IG5ld09yZ2FuaXphdGlvbklkKCksXG4gICAgb3duZXJVc2VySWQ6IHVzZXJJZCxcbiAgICByZXZpc2lvbjogMCxcbiAgICB1cGRhdGVkQXQ6IG5vd1xuICB9O1xuICBjb25zdCBtZW1iZXJzaGlwOiBPcmdhbml6YXRpb25NZW1iZXJzaGlwID0ge1xuICAgIGNyZWF0ZWRBdDogbm93LFxuICAgIG9yZ2FuaXphdGlvbklkOiBvcmdhbml6YXRpb24ub3JnYW5pemF0aW9uSWQsXG4gICAgcmV2aXNpb246IDAsXG4gICAgcm9sZTogJ2FkbWluJyxcbiAgICBzdGF0dXM6ICdhY3RpdmUnLFxuICAgIHVwZGF0ZWRBdDogbm93LFxuICAgIHVzZXJJZFxuICB9O1xuICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbnMnLCBvcmdhbml6YXRpb24ub3JnYW5pemF0aW9uSWQsIG9yZ2FuaXphdGlvbik7XG4gIGF3YWl0IHR4LnB1dCgnb3JnYW5pemF0aW9uTWVtYmVyc2hpcHMnLCBvcmdhbml6YXRpb25LZXkob3JnYW5pemF0aW9uLm9yZ2FuaXphdGlvbklkLCB1c2VySWQpLCBtZW1iZXJzaGlwKTtcbiAgcmV0dXJuIG9yZ2FuaXphdGlvbjtcbn07XG5cbmV4cG9ydCBjb25zdCByZWdpc3Rlck9yZ2FuaXphdGlvbiA9IGFzeW5jIChcbiAgaW5wdXQ6IFNpZ251cElucHV0LFxuICBjb250cm9sQ29udGV4dDogQXBpQ29udGV4dFxuKTogUHJvbWlzZTxTaWdudXBSZXN1bHQ+ID0+IHtcbiAgaWYoXG4gICAgIWlucHV0IHx8XG4gICAgT2JqZWN0LmtleXMoaW5wdXQpLnNvbWUoKGtleSkgPT4gIVsnZW1haWwnLCAnb3JnYW5pemF0aW9uTmFtZScsICdwYXNzd29yZCcsICdyZXF1ZXN0SWQnXS5pbmNsdWRlcyhrZXkpKSB8fFxuICAgIHR5cGVvZiBpbnB1dC5lbWFpbCAhPT0gJ3N0cmluZycgfHxcbiAgICAhL15bXlxcc0BdK0BbXlxcc0BdK1xcLlteXFxzQF0rJC8udGVzdChpbnB1dC5lbWFpbCkgfHxcbiAgICBpbnB1dC5lbWFpbC5sZW5ndGggPiAyNTQgfHxcbiAgICB0eXBlb2YgaW5wdXQucGFzc3dvcmQgIT09ICdzdHJpbmcnIHx8XG4gICAgaW5wdXQucGFzc3dvcmQubGVuZ3RoIDwgMTIgfHxcbiAgICBpbnB1dC5wYXNzd29yZC5sZW5ndGggPiAxMjggfHxcbiAgICB0eXBlb2YgaW5wdXQub3JnYW5pemF0aW9uTmFtZSAhPT0gJ3N0cmluZycgfHxcbiAgICAhaW5wdXQub3JnYW5pemF0aW9uTmFtZS50cmltKCkgfHxcbiAgICBpbnB1dC5vcmdhbml6YXRpb25OYW1lLmxlbmd0aCA+IDE2MFxuICApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWRfc2lnbnVwJyk7XG4gIH1cbiAgcmVxdWlyZUlkZW50aWZpZXIoaW5wdXQucmVxdWVzdElkKTtcbiAgY29uc3QgZW1haWwgPSBpbnB1dC5lbWFpbC50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgY29uc3QgZmluZ2VycHJpbnQgPSBjcmVhdGVIbWFjKCdzaGEyNTYnLCBvcmdhbml6YXRpb25NYWlsS2V5KCkpXG4gICAgLnVwZGF0ZShKU09OLnN0cmluZ2lmeSh7Li4uaW5wdXQsIGVtYWlsfSkpXG4gICAgLmRpZ2VzdCgnaGV4Jyk7XG4gIGNvbnN0IHJlZ2lzdHJhdGlvbklkID0gb3JnYW5pemF0aW9uS2V5KCdyZWdpc3RyYXRpb24nLCBlbWFpbCwgaW5wdXQucmVxdWVzdElkKTtcbiAgcmV0dXJuIG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRyb2xDb250ZXh0KS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICBjb25zdCBwcmV2aW91cyA9IGF3YWl0IHR4LmdldDxSZWdpc3RyYXRpb24+KCdvcmdhbml6YXRpb25SZWdpc3RyYXRpb25zJywgcmVnaXN0cmF0aW9uSWQpO1xuICAgIGlmKHByZXZpb3VzKSB7XG4gICAgICBpZihwcmV2aW91cy5maW5nZXJwcmludCAhPT0gZmluZ2VycHJpbnQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdyZWdpc3RyYXRpb25fY29uZmxpY3QnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB7cmVnaXN0cmF0aW9uSWQsIHZlcmlmaWNhdGlvblJlcXVpcmVkOiB0cnVlfTtcbiAgICB9XG4gICAgY29uc3QgdXNlcnMgPSBhd2FpdCB0eC5maW5kKCd1c2VycycsIHtlbWFpbH0pO1xuICAgIGNvbnN0IHVzZXJJZCA9IGNyZWF0ZUhhc2goZW1haWwpO1xuICAgIGNvbnN0IGNvbGxpc2lvbiA9IGF3YWl0IHR4LmdldCgndXNlcnMnLCB1c2VySWQpO1xuICAgIGNvbnN0IGV4aXN0aW5nID0gdXNlcnMubGVuZ3RoID4gMCB8fCBCb29sZWFuKGNvbGxpc2lvbik7XG4gICAgbGV0IG9yZ2FuaXphdGlvbklkID0gJyc7XG4gICAgaWYoIWV4aXN0aW5nKSB7XG4gICAgICBjb25zdCBzYWx0ID0gcmFuZG9tQnl0ZXMoMzIpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGF3YWl0IHR4LnB1dCgndXNlcnMnLCB1c2VySWQsIHtcbiAgICAgICAgYWN0aXZlOiB0cnVlLFxuICAgICAgICBhZGRlZDogRGF0ZS5ub3coKSxcbiAgICAgICAgZW1haWwsXG4gICAgICAgIGxvY2FsZTogJ2VuJyxcbiAgICAgICAgb3JnYW5pemF0aW9uQWNjb3VudDogdHJ1ZSxcbiAgICAgICAgcGFzc3dvcmQ6IGNyZWF0ZVBhc3N3b3JkKHBhcnNlUGFzc3dvcmQoaW5wdXQucGFzc3dvcmQpLCBzYWx0KSxcbiAgICAgICAgc2FsdCxcbiAgICAgICAgdHlwZTogJ3VzZXInLFxuICAgICAgICB1c2VyQWNjZXNzOiAwLFxuICAgICAgICB1c2VybmFtZTogZW1haWwsXG4gICAgICAgIHZlcmlmaWVkRW1haWw6IGZhbHNlXG4gICAgICB9KTtcbiAgICAgICh7b3JnYW5pemF0aW9uSWR9ID0gYXdhaXQgaW5zZXJ0T3JnYW5pemF0aW9uKHR4LCBpbnB1dC5vcmdhbml6YXRpb25OYW1lLnRyaW0oKSwgdXNlcklkKSk7XG4gICAgfVxuICAgIGNvbnN0IHJlZ2lzdHJhdGlvbjogUmVnaXN0cmF0aW9uID0ge1xuICAgICAgZW1haWwsXG4gICAgICBmaW5nZXJwcmludCxcbiAgICAgIG9yZ2FuaXphdGlvbklkLFxuICAgICAgcmVnaXN0cmF0aW9uSWQsXG4gICAgICByZXF1ZXN0SWQ6IGlucHV0LnJlcXVlc3RJZCxcbiAgICAgIHVzZXJJZDogZXhpc3RpbmcgPyAnJyA6IHVzZXJJZFxuICAgIH07XG4gICAgYXdhaXQgdHgucHV0KCdvcmdhbml6YXRpb25SZWdpc3RyYXRpb25zJywgcmVnaXN0cmF0aW9uSWQsIHJlZ2lzdHJhdGlvbik7XG4gICAgaWYoIWV4aXN0aW5nKSB7XG4gICAgICBhd2FpdCBxdWV1ZU9yZ2FuaXphdGlvblZlcmlmaWNhdGlvbih0eCwgcmVnaXN0cmF0aW9uKTtcbiAgICB9XG4gICAgcmV0dXJuIHtyZWdpc3RyYXRpb25JZCwgdmVyaWZpY2F0aW9uUmVxdWlyZWQ6IHRydWV9O1xuICB9KTtcbn07XG5cbmV4cG9ydCBjb25zdCBjcmVhdGVPcmdhbml6YXRpb24gPSAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4gIG5hbWU6IHN0cmluZyxcbiAgcmVxdWVzdElkOiBzdHJpbmdcbik6IFByb21pc2U8T3JnYW5pemF0aW9uPiA9PlxuICBvcmdhbml6YXRpb25TdG9yZUZvcihjb250ZXh0KS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICBjb25zdCB1c2VySWQgPSBvcmdhbml6YXRpb25Vc2VySWQoY29udGV4dCk7XG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHR4LmdldDx7YWN0aXZlOiBib29sZWFuOyB2ZXJpZmllZEVtYWlsOiBib29sZWFufT4oJ3VzZXJzJywgdXNlcklkKTtcbiAgICBpZighdXNlcj8uYWN0aXZlIHx8ICF1c2VyLnZlcmlmaWVkRW1haWwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZW1haWxfdmVyaWZpY2F0aW9uX3JlcXVpcmVkJyk7XG4gICAgfVxuICAgIGlmKHR5cGVvZiBuYW1lICE9PSAnc3RyaW5nJyB8fCAhbmFtZS50cmltKCkgfHwgbmFtZS5sZW5ndGggPiAxNjApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZF9vcmdhbml6YXRpb25fbmFtZScpO1xuICAgIH1cbiAgICBjb25zdCBrZXkgPSBvcmdhbml6YXRpb25LZXkoJ2F1dGhlbnRpY2F0ZWQtb3JnYW5pemF0aW9uJywgdXNlcklkLCByZXF1aXJlSWRlbnRpZmllcihyZXF1ZXN0SWQpKTtcbiAgICBjb25zdCBwcmV2aW91cyA9IGF3YWl0IHR4LmdldDx7bmFtZTogc3RyaW5nOyBvcmdhbml6YXRpb25JZDogc3RyaW5nfT4oJ29yZ2FuaXphdGlvblJlZ2lzdHJhdGlvbnMnLCBrZXkpO1xuICAgIGlmKHByZXZpb3VzKSB7XG4gICAgICBpZihwcmV2aW91cy5uYW1lICE9PSBuYW1lLnRyaW0oKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3JlZ2lzdHJhdGlvbl9jb25mbGljdCcpO1xuICAgICAgfVxuICAgICAgY29uc3QgZXhpc3RpbmcgPSAoYXdhaXQgdHguZ2V0PE9yZ2FuaXphdGlvbj4oJ29yZ2FuaXphdGlvbnMnLCBwcmV2aW91cy5vcmdhbml6YXRpb25JZCkpITtcbiAgICAgIGNvbnN0IHtfa2V5LCBfcmV2LCAuLi5vcmdhbml6YXRpb259ID0gZXhpc3Rpbmc7XG4gICAgICByZXR1cm4gb3JnYW5pemF0aW9uO1xuICAgIH1cbiAgICBjb25zdCBvcmcgPSBhd2FpdCBpbnNlcnRPcmdhbml6YXRpb24odHgsIG5hbWUudHJpbSgpLCB1c2VySWQpO1xuICAgIGF3YWl0IHR4LnB1dCgnb3JnYW5pemF0aW9uUmVnaXN0cmF0aW9ucycsIGtleSwge1xuICAgICAgbmFtZTogbmFtZS50cmltKCksXG4gICAgICBvcmdhbml6YXRpb25JZDogb3JnLm9yZ2FuaXphdGlvbklkLFxuICAgICAgcmVxdWVzdElkOiBrZXksXG4gICAgICB1c2VySWRcbiAgICB9KTtcbiAgICBhd2FpdCB0eC5wdXQoJ3VzZXJzJywgdXNlcklkLCB7Li4udXNlciwgb3JnYW5pemF0aW9uQWNjb3VudDogdHJ1ZX0sIHVzZXIpO1xuICAgIHJldHVybiBvcmc7XG4gIH0pO1xuIl0sIm5hbWVzIjpbImNyZWF0ZUhhc2giLCJjcmVhdGVQYXNzd29yZCIsInBhcnNlUGFzc3dvcmQiLCJjcmVhdGVIbWFjIiwicmFuZG9tQnl0ZXMiLCJvcmdhbml6YXRpb25Vc2VySWQiLCJlbmNvZGVPcmdhbml6YXRpb25NYWlsIiwib3JnYW5pemF0aW9uTWFpbEtleSIsIm5ld09yZ2FuaXphdGlvbklkIiwib3JnYW5pemF0aW9uS2V5Iiwib3JnYW5pemF0aW9uU3RvcmVGb3IiLCJyZXF1aXJlSWRlbnRpZmllciIsInF1ZXVlT3JnYW5pemF0aW9uVmVyaWZpY2F0aW9uIiwidHgiLCJyZWdpc3RyYXRpb24iLCJwcmV2aW91cyIsIm5vdyIsIkRhdGUiLCJ0b2tlbiIsInRvU3RyaW5nIiwid2l0aGluSG91ciIsInJlc2VuZFdpbmRvdyIsInZlcmlmaWNhdGlvbiIsImF0dGVtcHRXaW5kb3ciLCJhdHRlbXB0cyIsImV4cGlyZXNBdCIsImxhc3RTZW50IiwicmVzZW5kQ291bnQiLCJ0b2tlbkhhc2giLCJ1c2VkIiwidXNlcklkIiwicHV0IiwicmVnaXN0cmF0aW9uSWQiLCJqb2JJZCIsImpvYiIsImRlc2lyZWQiLCJjaXBoZXJ0ZXh0IiwiZW1haWwiLCJlZmZlY3RpdmVBdCIsImtpbmQiLCJsZWFzZUV4cGlyZXMiLCJvcmdhbml6YXRpb25JZCIsIm93bmVyIiwicHJpY2VWZXJzaW9uIiwic2VxdWVuY2UiLCJzdGF0dXMiLCJpbnNlcnRPcmdhbml6YXRpb24iLCJuYW1lIiwib3JnYW5pemF0aW9uIiwiY3JlYXRlZEF0Iiwib3duZXJVc2VySWQiLCJyZXZpc2lvbiIsInVwZGF0ZWRBdCIsIm1lbWJlcnNoaXAiLCJyb2xlIiwicmVnaXN0ZXJPcmdhbml6YXRpb24iLCJpbnB1dCIsImNvbnRyb2xDb250ZXh0IiwiT2JqZWN0Iiwia2V5cyIsInNvbWUiLCJrZXkiLCJpbmNsdWRlcyIsInRlc3QiLCJsZW5ndGgiLCJwYXNzd29yZCIsIm9yZ2FuaXphdGlvbk5hbWUiLCJ0cmltIiwiRXJyb3IiLCJyZXF1ZXN0SWQiLCJ0b0xvd2VyQ2FzZSIsImZpbmdlcnByaW50IiwidXBkYXRlIiwiSlNPTiIsInN0cmluZ2lmeSIsImRpZ2VzdCIsInRyYW5zYWN0aW9uIiwiZ2V0IiwidmVyaWZpY2F0aW9uUmVxdWlyZWQiLCJ1c2VycyIsImZpbmQiLCJjb2xsaXNpb24iLCJleGlzdGluZyIsIkJvb2xlYW4iLCJzYWx0IiwiYWN0aXZlIiwiYWRkZWQiLCJsb2NhbGUiLCJvcmdhbml6YXRpb25BY2NvdW50IiwidHlwZSIsInVzZXJBY2Nlc3MiLCJ1c2VybmFtZSIsInZlcmlmaWVkRW1haWwiLCJjcmVhdGVPcmdhbml6YXRpb24iLCJjb250ZXh0IiwidXNlciIsIl9rZXkiLCJfcmV2Iiwib3JnIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFRQSxVQUFVLEVBQUVDLGNBQWMsRUFBRUMsYUFBYSxRQUFPLCtCQUErQjtBQUN2RixTQUFRQyxVQUFVLEVBQUVDLFdBQVcsUUFBTyxjQUFjO0FBRXBELFNBQVFDLGtCQUFrQixRQUFPLHFCQUFxQjtBQUN0RCxTQUFRQyxzQkFBc0IsRUFBRUMsbUJBQW1CLFFBQU8sWUFBWTtBQUN0RSxTQUNFQyxpQkFBaUIsRUFDakJDLGVBQWUsRUFDZkMsb0JBQW9CLEVBQ3BCQyxpQkFBaUIsUUFFWixhQUFhO0FBd0JwQixPQUFPLE1BQU1DLGdDQUFnQyxPQUMzQ0MsSUFDQUMsY0FDQUM7SUFFQSxNQUFNQyxNQUFNQyxLQUFLRCxHQUFHO0lBQ3BCLE1BQU1FLFFBQVFkLFlBQVksSUFBSWUsUUFBUSxDQUFDO0lBQ3ZDLE1BQU1DLGFBQWFMLFlBQVlDLE1BQU1ELFNBQVNNLFlBQVksR0FBRztJQUM3RCxNQUFNQyxlQUE2QjtR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
@@ -0,0 +1,25 @@
1
+ import { type Database } from 'arangojs';
2
+ import type { ApiContext } from '../types/auth.types.js';
3
+ export declare const organizationCollections: readonly ['organizations', 'organizationMemberships', 'organizationApps', 'organizationRegistrations', 'organizationVerificationTokens', 'organizationInvitations', 'organizationOwnerTransfers', 'organizationBilling', 'organizationBillingJobs', 'organizationBillingEvents', 'organizationBillingPeriods', 'organizationBillingQuotes'];
4
+ export declare const organizationEdgeCollections: readonly ("hasConnection" | "hasConversation" | "hasCustomerNotification" | "hasCustomerOrder" | "hasFile" | "hasLocation" | "hasMailingList" | "hasMedia" | "hasPayment" | "hasPersona" | "hasPurchasedProduct" | "hasReaction" | "hasSupportTicket" | "hasSupportTicketEvent" | "hasSupportTicketMessage" | "isPosted" | "isTagged")[];
5
+ export type OrganizationCollection = (typeof organizationCollections)[number] | (typeof organizationEdgeCollections)[number] | 'users';
6
+ export type Stored<T> = T & {
7
+ _key: string;
8
+ _rev?: string;
9
+ };
10
+ export type OrganizationTransaction = Readonly<{
11
+ find: <T>(collection: OrganizationCollection, filter: Readonly<Record<string, unknown>>) => Promise<Stored<T>[]>;
12
+ get: <T>(collection: OrganizationCollection, key: string) => Promise<Stored<T> | null>;
13
+ put: <T extends object>(collection: OrganizationCollection, key: string, document: T, previous?: Stored<object> | null) => Promise<void>;
14
+ remove: (collection: OrganizationCollection, document: Stored<object>) => Promise<void>;
15
+ }>;
16
+ export type OrganizationStore = Readonly<{
17
+ initialize: () => Promise<void>;
18
+ transaction: <T>(action: (tx: OrganizationTransaction) => Promise<T>) => Promise<T>;
19
+ }>;
20
+ export declare const organizationKey: (...parts: string[]) => string;
21
+ export declare const newOrganizationId: () => string;
22
+ export declare const requireIdentifier: (value: unknown) => string;
23
+ export declare const controlDatabaseName: () => string;
24
+ export declare const organizationStoreFor: (_context: ApiContext) => OrganizationStore;
25
+ export declare const createOrganizationStore: (controlName: string, database?: Database) => OrganizationStore;
@@ -0,0 +1,167 @@
1
+ /* Stream-transaction steps and ordered retry assertions must execute sequentially. */ /* eslint-disable no-await-in-loop */ import { aql } from 'arangojs';
2
+ import { createHash, randomUUID } from 'node:crypto';
3
+ import { DEFAULT_EDGE_COLLECTIONS } from '../constants/collections.js';
4
+ import { useDb } from '../utils/arangodbUtils.js';
5
+ export const organizationCollections = [
6
+ 'organizations',
7
+ 'organizationMemberships',
8
+ 'organizationApps',
9
+ 'organizationRegistrations',
10
+ 'organizationVerificationTokens',
11
+ 'organizationInvitations',
12
+ 'organizationOwnerTransfers',
13
+ 'organizationBilling',
14
+ 'organizationBillingJobs',
15
+ 'organizationBillingEvents',
16
+ 'organizationBillingPeriods',
17
+ 'organizationBillingQuotes'
18
+ ];
19
+ export const organizationEdgeCollections = DEFAULT_EDGE_COLLECTIONS;
20
+ export const organizationKey = (...parts)=>createHash('sha256').update(JSON.stringify(parts)).digest('hex');
21
+ export const newOrganizationId = ()=>randomUUID();
22
+ export const requireIdentifier = (value)=>{
23
+ if (typeof value !== 'string' || !/^[a-zA-Z0-9_-]{1,128}$/.test(value)) {
24
+ throw new Error('invalid_identifier');
25
+ }
26
+ return value;
27
+ };
28
+ export const controlDatabaseName = ()=>{
29
+ const name = process.env.ARANGODB_DATABASE;
30
+ if (!name || !/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/.test(name) || name === '_system') {
31
+ throw new Error('organization_control_database_required');
32
+ }
33
+ return name;
34
+ };
35
+ export const organizationStoreFor = (_context)=>createOrganizationStore(controlDatabaseName());
36
+ const indexes = {
37
+ organizationApps: [
38
+ [
39
+ 'appId'
40
+ ]
41
+ ],
42
+ organizationBilling: [
43
+ [
44
+ 'organizationId'
45
+ ]
46
+ ],
47
+ organizationBillingEvents: [
48
+ [
49
+ 'eventId'
50
+ ]
51
+ ],
52
+ organizationBillingJobs: [
53
+ [
54
+ 'organizationId',
55
+ 'sequence'
56
+ ]
57
+ ],
58
+ organizationMemberships: [
59
+ [
60
+ 'organizationId',
61
+ 'userId'
62
+ ]
63
+ ],
64
+ organizations: [
65
+ [
66
+ 'organizationId'
67
+ ]
68
+ ]
69
+ };
70
+ export const createOrganizationStore = (controlName, database = useDb(controlName))=>{
71
+ if (!controlName || controlName === '_system' || !/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/.test(controlName)) {
72
+ throw new Error('organization_control_database_required');
73
+ }
74
+ let initialized = false;
75
+ const initialize = async ()=>{
76
+ if (initialized) {
77
+ return;
78
+ }
79
+ for (const name of [
80
+ ...organizationCollections,
81
+ 'users',
82
+ ...organizationEdgeCollections
83
+ ]){
84
+ const collection = database.collection(name);
85
+ if (!await collection.exists()) {
86
+ try {
87
+ await collection.create(organizationEdgeCollections.includes(name) ? {
88
+ type: 3
89
+ } : {});
90
+ } catch (error) {
91
+ if (error.errorNum !== 1207) {
92
+ throw error;
93
+ }
94
+ }
95
+ }
96
+ for (const fields of indexes[name] || []){
97
+ await collection.ensureIndex({
98
+ fields,
99
+ type: 'persistent',
100
+ unique: true
101
+ });
102
+ }
103
+ }
104
+ initialized = true;
105
+ };
106
+ const transaction = async (action)=>{
107
+ await initialize();
108
+ const trx = await database.beginTransaction({
109
+ exclusive: [
110
+ ...organizationCollections,
111
+ 'users',
112
+ ...organizationEdgeCollections
113
+ ]
114
+ }, {
115
+ lockTimeout: 10
116
+ });
117
+ const tx = {
118
+ find: async (name, filter)=>{
119
+ const cursor = await trx.step(()=>database.query(aql`FOR doc IN ${database.collection(name)} FILTER MATCHES(doc, ${filter}) RETURN doc`));
120
+ return await cursor.all();
121
+ },
122
+ get: async (name, key)=>{
123
+ const cursor = await trx.step(()=>database.query(aql`RETURN DOCUMENT(${name}, ${requireIdentifier(key)})`));
124
+ return await cursor.next();
125
+ },
126
+ put: async (name, key, document, previous)=>{
127
+ const collection = database.collection(name);
128
+ const { _id, _key, _rev, ...safe } = document;
129
+ if (previous) {
130
+ await trx.step(()=>collection.replace({
131
+ _key: requireIdentifier(key),
132
+ _rev: previous._rev
133
+ }, safe, {
134
+ ignoreRevs: false
135
+ }));
136
+ } else {
137
+ await trx.step(()=>collection.save({
138
+ ...safe,
139
+ _key: requireIdentifier(key)
140
+ }));
141
+ }
142
+ },
143
+ remove: async (name, document)=>{
144
+ await trx.step(()=>database.collection(name).remove({
145
+ _key: document._key,
146
+ _rev: document._rev
147
+ }, {
148
+ ignoreRevs: false
149
+ }));
150
+ }
151
+ };
152
+ try {
153
+ const result = await action(tx);
154
+ await trx.commit();
155
+ return result;
156
+ } catch (error) {
157
+ await trx.abort().catch(()=>undefined);
158
+ throw error;
159
+ }
160
+ };
161
+ return {
162
+ initialize,
163
+ transaction
164
+ };
165
+ }; /* Stream-transaction steps and ordered retry assertions must execute sequentially. */ /* ArangoDB document metadata uses these reserved field names. */ /* eslint no-underscore-dangle: ["warn", {"allow": ["_key", "_rev", "_id"]}] */
166
+
167
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9wcml2YXRlL3RtcC92YXVsdC1yZWFrdG9yLWNvbXBsZXRpb24vcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy9zdG9yZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBTdHJlYW0tdHJhbnNhY3Rpb24gc3RlcHMgYW5kIG9yZGVyZWQgcmV0cnkgYXNzZXJ0aW9ucyBtdXN0IGV4ZWN1dGUgc2VxdWVudGlhbGx5LiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tYXdhaXQtaW4tbG9vcCAqL1xuaW1wb3J0IHthcWwsIHR5cGUgRGF0YWJhc2V9IGZyb20gJ2FyYW5nb2pzJztcbmltcG9ydCB7Y3JlYXRlSGFzaCwgcmFuZG9tVVVJRH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuXG5pbXBvcnQge0RFRkFVTFRfRURHRV9DT0xMRUNUSU9OU30gZnJvbSAnLi4vY29uc3RhbnRzL2NvbGxlY3Rpb25zLmpzJztcbmltcG9ydCB7dXNlRGJ9IGZyb20gJy4uL3V0aWxzL2FyYW5nb2RiVXRpbHMuanMnO1xuXG5pbXBvcnQgdHlwZSB7QXBpQ29udGV4dH0gZnJvbSAnLi4vdHlwZXMvYXV0aC50eXBlcy5qcyc7XG5cbmV4cG9ydCBjb25zdCBvcmdhbml6YXRpb25Db2xsZWN0aW9ucyA9IFtcbiAgJ29yZ2FuaXphdGlvbnMnLFxuICAnb3JnYW5pemF0aW9uTWVtYmVyc2hpcHMnLFxuICAnb3JnYW5pemF0aW9uQXBwcycsXG4gICdvcmdhbml6YXRpb25SZWdpc3RyYXRpb25zJyxcbiAgJ29yZ2FuaXphdGlvblZlcmlmaWNhdGlvblRva2VucycsXG4gICdvcmdhbml6YXRpb25JbnZpdGF0aW9ucycsXG4gICdvcmdhbml6YXRpb25Pd25lclRyYW5zZmVycycsXG4gICdvcmdhbml6YXRpb25CaWxsaW5nJyxcbiAgJ29yZ2FuaXphdGlvbkJpbGxpbmdKb2JzJyxcbiAgJ29yZ2FuaXphdGlvbkJpbGxpbmdFdmVudHMnLFxuICAnb3JnYW5pemF0aW9uQmlsbGluZ1BlcmlvZHMnLFxuICAnb3JnYW5pemF0aW9uQmlsbGluZ1F1b3Rlcydcbl0gYXMgY29uc3Q7XG5leHBvcnQgY29uc3Qgb3JnYW5pemF0aW9uRWRnZUNvbGxlY3Rpb25zID0gREVGQVVMVF9FREdFX0NPTExFQ1RJT05TO1xuZXhwb3J0IHR5cGUgT3JnYW5pemF0aW9uQ29sbGVjdGlvbiA9XG4gICh0eXBlb2Ygb3JnYW5pemF0aW9uQ29sbGVjdGlvbnMpW251bWJlcl0gfCAodHlwZW9mIG9yZ2FuaXphdGlvbkVkZ2VDb2xsZWN0aW9ucylbbnVtYmVyXSB8ICd1c2Vycyc7XG5leHBvcnQgdHlwZSBTdG9yZWQ8VD4gPSBUICYge19rZXk6IHN0cmluZzsgX3Jldj86IHN0cmluZ307XG5leHBvcnQgdHlwZSBPcmdhbml6YXRpb25UcmFuc2FjdGlvbiA9IFJlYWRvbmx5PHtcbiAgZmluZDogPFQ+KFxuICAgIGNvbGxlY3Rpb246IE9yZ2FuaXphdGlvbkNvbGxlY3Rpb24sXG4gICAgZmlsdGVyOiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj5cbiAgKSA9PiBQcm9taXNlPFN0b3JlZDxUPltdPjtcbiAgZ2V0OiA8VD4oY29sbGVjdGlvbjogT3JnYW5pemF0aW9uQ29sbGVjdGlvbiwga2V5OiBzdHJpbmcpID0+IFByb21pc2U8U3RvcmVkPFQ+IHwgbnVsbD47XG4gIHB1dDogPFQgZXh0ZW5kcyBvYmplY3Q+KFxuICAgIGNvbGxlY3Rpb246IE9yZ2FuaXphdGlvbkNvbGxlY3Rpb24sXG4gICAga2V5OiBzdHJpbmcsXG4gICAgZG9jdW1lbnQ6IFQsXG4gICAgcHJldmlvdXM/OiBTdG9yZWQ8b2JqZWN0PiB8IG51bGxcbiAgKSA9PiBQcm9taXNlPHZvaWQ+O1xuICByZW1vdmU6IChjb2xsZWN0aW9uOiBPcmdhbml6YXRpb25Db2xsZWN0aW9uLCBkb2N1bWVudDogU3RvcmVkPG9iamVjdD4pID0+IFByb21pc2U8dm9pZD47XG59PjtcbmV4cG9ydCB0eXBlIE9yZ2FuaXphdGlvblN0b3JlID0gUmVhZG9ubHk8e1xuICBpbml0aWFsaXplOiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICB0cmFuc2FjdGlvbjogPFQ+KGFjdGlvbjogKHR4OiBPcmdhbml6YXRpb25UcmFuc2FjdGlvbikgPT4gUHJvbWlzZTxUPikgPT4gUHJvbWlzZTxUPjtcbn0+O1xuZXhwb3J0IGNvbnN0IG9yZ2FuaXphdGlvbktleSA9ICguLi5wYXJ0czogc3RyaW5nW10pOiBzdHJpbmcgPT5cbiAgY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKEpTT04uc3RyaW5naWZ5KHBhcnRzKSkuZGlnZXN0KCdoZXgnKTtcbmV4cG9ydCBjb25zdCBuZXdPcmdhbml6YXRpb25JZCA9ICgpOiBzdHJpbmcgPT4gcmFuZG9tVVVJRCgpO1xuZXhwb3J0IGNvbnN0IHJlcXVpcmVJZGVudGlmaWVyID0gKHZhbHVlOiB1bmtub3duKTogc3RyaW5nID0+IHtcbiAgaWYodHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJyB8fCAhL15bYS16QS1aMC05Xy1dezEsMTI4fSQvLnRlc3QodmFsdWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkX2lkZW50aWZpZXInKTtcbiAgfVxuICByZXR1cm4gdmFsdWU7XG59O1xuZXhwb3J0IGNvbnN0IGNvbnRyb2xEYXRhYmFzZU5hbWUgPSAoKTogc3RyaW5nID0+IHtcbiAgY29uc3QgbmFtZSA9IHByb2Nlc3MuZW52LkFSQU5HT0RCX0RBVEFCQVNFO1xuICBpZighbmFtZSB8fCAhL15bYS16QS1aXVthLXpBLVowLTlfLV17MCw2M30kLy50ZXN0KG5hbWUpIHx8IG5hbWUgPT09ICdfc3lzdGVtJykge1xuICAgIHRocm93IG5ldyBFcnJvcignb3JnYW5pemF0aW9uX2NvbnRyb2xfZGF0YWJhc2VfcmVxdWlyZWQnKTtcbiAgfVxuICByZXR1cm4gbmFtZTtcbn07XG5leHBvcnQgY29uc3Qgb3JnYW5pemF0aW9uU3RvcmVGb3IgPSAoX2NvbnRleHQ6IEFwaUNvbnRleHQpOiBPcmdhbml6YXRpb25TdG9yZSA9PlxuICBjcmVhdGVPcmdhbml6YXRpb25TdG9yZShjb250cm9sRGF0YWJhc2VOYW1lKCkpO1xuXG5jb25zdCBpbmRleGVzOiBQYXJ0aWFsPFJlY29yZDxPcmdhbml6YXRpb25Db2xsZWN0aW9uLCBzdHJpbmdbXVtdPj4gPSB7XG4gIG9yZ2FuaXphdGlvbkFwcHM6IFtbJ2FwcElkJ11dLFxuICBvcmdhbml6YXRpb25CaWxsaW5nOiBbWydvcmdhbml6YXRpb25JZCddXSxcbiAgb3JnYW5pemF0aW9uQmlsbGluZ0V2ZW50czogW1snZXZlbnRJZCddXSxcbiAgb3JnYW5pemF0aW9uQmlsbGluZ0pvYnM6IFtbJ29yZ2FuaXphdGlvbklkJywgJ3NlcXVlbmNlJ11dLFxuICBvcmdhbml6YXRpb25NZW1iZXJzaGlwczogW1snb3JnYW5pemF0aW9uSWQnLCAndXNlcklkJ11dLFxuICBvcmdhbml6YXRpb25zOiBbWydvcmdhbml6YXRpb25JZCddXVxufTtcblxuZXhwb3J0IGNvbnN0IGNyZWF0ZU9yZ2FuaXphdGlvblN0b3JlID0gKFxuICBjb250cm9sTmFtZTogc3RyaW5nLFxuICBkYXRhYmFzZTogRGF0YWJhc2UgPSB1c2VEYihjb250cm9sTmFtZSlcbik6IE9yZ2FuaXphdGlvblN0b3JlID0+IHtcbiAgaWYoIWNvbnRyb2xOYW1lIHx8IGNvbnRyb2xOYW1lID09PSAnX3N5c3RlbScgfHwgIS9eW2EtekEtWl1bYS16QS1aMC05Xy1dezAsNjN9JC8udGVzdChjb250cm9sTmFtZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ29yZ2FuaXphdGlvbl9jb250cm9sX2RhdGFiYXNlX3JlcXVpcmVkJyk7XG4gIH1cbiAgbGV0IGluaXRpYWxpemVkID0gZmFsc2U7XG4gIGNvbnN0IGluaXRpYWxpemUgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgaWYoaW5pdGlhbGl6ZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZm9yKGNvbnN0IG5hbWUgb2YgW1xuICAgICAgLi4ub3JnYW5pemF0aW9uQ29sbGVjdGlvbnMsXG4gICAgICAndXNlcnMnLFxuICAgICAgLi4ub3JnYW5pemF0aW9uRWRnZUNvbGxlY3Rpb25zXG4gICAgXSBhcyBPcmdhbml6YXRpb25Db2xsZWN0aW9uW10pIHtcbiAgICAgIGNvbnN0IGNvbGxlY3Rpb24gPSBkYXRhYmFzZS5jb2xsZWN0aW9uKG5hbWUpO1xuICAgICAgaWYoIShhd2FpdCBjb2xsZWN0aW9uLmV4aXN0cygpKSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGNvbGxlY3Rpb24uY3JlYXRlKFxuICAgICAgICAgICAgb3JnYW5pemF0aW9uRWRnZUNvbGxlY3Rpb25zLmluY2x1ZGVzKG5hbWUgYXMgKHR5cGVvZiBvcmdhbml6YXRpb25FZGdlQ29sbGVjdGlvbnMpW251bWJlcl0pXG4gICAgICAgICAgICAgID8ge3R5cGU6IDN9XG4gICAgICAgICAgICAgIDoge31cbiAgICAgICAgICApO1xuICAgICAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgICAgaWYoKGVycm9yIGFzIHtlcnJvck51bT86IG51bWJlcn0pLmVycm9yTnVtICE9PSAxMjA3KSB7XG4gICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGZvcihjb25zdCBmaWVsZHMgb2YgaW5kZXhlc1tuYW1lXSB8fCBbXSkge1xuICAgICAgICBhd2FpdCBjb2xsZWN0aW9uLmVuc3VyZUluZGV4KHtmaWVsZHMsIHR5cGU6ICdwZXJzaXN0ZW50JywgdW5pcXVlOiB0cnVlfSk7XG4gICAgICB9XG4gICAgfVxuICAgIGluaXRpYWxpemVkID0gdHJ1ZTtcbiAgfTtcbiAgY29uc3QgdHJhbnNhY3Rpb24gPSBhc3luYyA8VD4oYWN0aW9uOiAodHg6IE9yZ2FuaXphdGlvblRyYW5zYWN0aW9uKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUPiA9PiB7XG4gICAgYXdhaXQgaW5pdGlhbGl6ZSgpO1xuICAgIGNvbnN0IHRyeCA9IGF3YWl0IGRhdGFiYXNlLmJlZ2luVHJhbnNhY3Rpb24oXG4gICAgICB7ZXhjbHVzaXZlOiBbLi4ub3JnYW5pemF0aW9uQ29sbGVjdGlvbnMsICd1c2VycycsIC4uLm9yZ2FuaXphdGlvbkVkZ2VDb2xsZWN0aW9uc119LFxuICAgICAge2xvY2tUaW1lb3V0OiAxMH1cbiAgICApO1xuICAgIGNvbnN0IHR4OiBPcmdhbml6YXRpb25UcmFuc2FjdGlvbiA9IHtcbiAgICAgIGZpbmQ6IGFzeW5jIDxEPihuYW1lOiBPcmdhbml6YXRpb25Db2xsZWN0aW9uLCBmaWx0ZXI6IFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHVua25vd24+PikgPT4ge1xuICAgICAgICBjb25zdCBjdXJzb3IgPSBhd2FpdCB0cnguc3RlcCgoKSA9PlxuICAgICAgICAgIGRhdGFiYXNlLnF1ZXJ5KFxuICAgICAgICAgICAgYXFsYEZPUiBkb2MgSU4gJHtkYXRhYmFzZS5jb2xsZWN0aW9uKG5hbWUpfSBGSUxURVIgTUFUQ0hFUyhkb2MsICR7ZmlsdGVyfSkgUkVUVVJOIGRvY2BcbiAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiAoYXdhaXQgY3Vyc29yLmFsbCgpKSBhcyBTdG9yZWQ8RD5bXTtcbiAgICAgIH0sXG4gICAgICBnZXQ6IGFzeW5jIDxEPihuYW1lOiBPcmdhbml6YXRpb25Db2xsZWN0aW9uLCBrZXk6IHN0cmluZykgPT4ge1xuICAgICAgICBjb25zdCBjdXJzb3IgPSBhd2FpdCB0cnguc3RlcCgoKSA9PlxuICAgICAgICAgIGRhdGFiYXNlLnF1ZXJ5KGFxbGBSRVRVUk4gRE9DVU1FTlQoJHtuYW1lfSwgJHtyZXF1aXJlSWRlbnRpZmllcihrZXkpfSlgKVxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gKGF3YWl0IGN1cnNvci5uZXh0KCkpIGFzIFN0b3JlZDxEPiB8IG51bGw7XG4gICAgICB9LFxuICAgICAgcHV0OiBhc3luYyA8RCBleHRlbmRzIG9iamVjdD4oXG4gICAgICAgIG5hbWU6IE9yZ2FuaXphdGlvbkNvbGxlY3Rpb24sXG4gICAgICAgIGtleTogc3RyaW5nLFxuICAgICAgICBkb2N1bWVudDogRCxcbiAgICAgICAgcHJldmlvdXM/OiBTdG9yZWQ8b2JqZWN0PiB8IG51bGxcbiAgICAgICkgPT4ge1xuICAgICAgICBjb25zdCBjb2xsZWN0aW9uID0gZGF0YWJhc2UuY29sbGVjdGlvbihuYW1lKTtcbiAgICAgICAgY29uc3Qge19pZCwgX2tleSwgX3JldiwgLi4uc2FmZX0gPSBkb2N1bWVudCBhcyBEICYge19pZD86IHN0cmluZzsgX2tleT86IHN0cmluZzsgX3Jldj86IHN0cmluZ307XG4gICAgICAgIGlmKHByZXZpb3VzKSB7XG4gICAgICAgICAgYXdhaXQgdHJ4LnN0ZXAoKCkgPT5cbiAgICAgICAgICAgIGNvbGxlY3Rpb24ucmVwbGFjZSh7X2tleTogcmVxdWlyZUlkZW50aWZpZXIoa2V5KSwgX3JldjogcHJldmlvdXMuX3Jldn0sIHNhZmUsIHtpZ25vcmVSZXZzOiBmYWxzZX0pXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBhd2FpdCB0cnguc3RlcCgoKSA9PiBjb2xsZWN0aW9uLnNhdmUoey4uLnNhZmUsIF9rZXk6IHJlcXVpcmVJZGVudGlmaWVyKGtleSl9KSk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICByZW1vdmU6IGFzeW5jIChuYW1lLCBkb2N1bWVudCkgPT4ge1xuICAgICAgICBhd2FpdCB0cnguc3RlcCgoKSA9PlxuICAgICAgICAgIGRhdGFiYXNlLmNvbGxlY3Rpb24obmFtZSkucmVtb3ZlKHtfa2V5OiBkb2N1bWVudC5fa2V5LCBfcmV2OiBkb2N1bWVudC5fcmV2fSwge2lnbm9yZVJldnM6IGZhbHNlfSlcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBhY3Rpb24odHgpO1xuICAgICAgYXdhaXQgdHJ4LmNvbW1pdCgpO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICBhd2FpdCB0cnguYWJvcnQoKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9O1xuICByZXR1cm4ge2luaXRpYWxpemUsIHRyYW5zYWN0aW9ufTtcbn07XG4vKiBTdHJlYW0tdHJhbnNhY3Rpb24gc3RlcHMgYW5kIG9yZGVyZWQgcmV0cnkgYXNzZXJ0aW9ucyBtdXN0IGV4ZWN1dGUgc2VxdWVudGlhbGx5LiAqL1xuXG4vKiBBcmFuZ29EQiBkb2N1bWVudCBtZXRhZGF0YSB1c2VzIHRoZXNlIHJlc2VydmVkIGZpZWxkIG5hbWVzLiAqL1xuLyogZXNsaW50IG5vLXVuZGVyc2NvcmUtZGFuZ2xlOiBbXCJ3YXJuXCIsIHtcImFsbG93XCI6IFtcIl9rZXlcIiwgXCJfcmV2XCIsIFwiX2lkXCJdfV0gKi9cbiJdLCJuYW1lcyI6WyJhcWwiLCJjcmVhdGVIYXNoIiwicmFuZG9tVVVJRCIsIkRFRkFVTFRfRURHRV9DT0xMRUNUSU9OUyIsInVzZURiIiwib3JnYW5pemF0aW9uQ29sbGVjdGlvbnMiLCJvcmdhbml6YXRpb25FZGdlQ29sbGVjdGlvbnMiLCJvcmdhbml6YXRpb25LZXkiLCJwYXJ0cyIsInVwZGF0ZSIsIkpTT04iLCJzdHJpbmdpZnkiLCJkaWdlc3QiLCJuZXdPcmdhbml6YXRpb25JZCIsInJlcXVpcmVJZGVudGlmaWVyIiwidmFsdWUiLCJ0ZXN0IiwiRXJyb3IiLCJjb250cm9sRGF0YWJhc2VOYW1lIiwibmFtZSIsInByb2Nlc3MiLCJlbnYiLCJBUkFOR09EQl9EQVRBQkFTRSIsIm9yZ2FuaXphdGlvblN0b3JlRm9yIiwiX2NvbnRleHQiLCJjcmVhdGVPcmdhbml6YXRpb25TdG9yZSIsImluZGV4ZXMiLCJvcmdhbml6YXRpb25BcHBzIiwib3JnYW5pemF0aW9uQmlsbGluZyIsIm9yZ2FuaXphdGlvbkJpbGxpbmdFdmVudHMiLCJvcmdhbml6YXRpb25CaWxsaW5nSm9icyIsIm9yZ2FuaXphdGlvbk1lbWJlcnNoaXBzIiwib3JnYW5pemF0aW9ucyIsImNvbnRyb2xOYW1lIiwiZGF0YWJhc2UiLCJpbml0aWFsaXplZCIsImluaXRpYWxpemUiLCJjb2xsZWN0aW9uIiwiZXhpc3RzIiwiY3JlYXRlIiwiaW5jbHVkZXMiLCJ0eXBlIiwiZXJyb3IiLCJlcnJvck51bSIsImZpZWxkcyIsImVuc3VyZUluZGV4IiwidW5pcXVlIiwidHJhbnNhY3Rpb24iLCJhY3Rpb24iLCJ0cngiLCJiZWdpblRyYW5zYWN0aW9uIiwiZXhjbHVzaXZlIiwibG9ja1RpbWVvdXQiLCJ0eCIsImZpbmQiLCJmaWx0ZXIiLCJjdXJzb3IiLCJzdGVwIiwicXVlcnkiLCJhbGwiLCJnZXQiLCJrZXkiLCJuZXh0IiwicHV0IiwiZG9jdW1lbnQiLCJwcmV2aW91cyIsIl9pZCIsIl9rZXkiLCJfcmV2Iiwic2FmZSIsInJlcGxhY2UiLCJpZ25vcmVSZXZzIiwic2F2ZSIsInJlbW92ZSIsInJlc3VsdCIsImNvbW1pdCIsImFib3J0IiwiY2F0Y2giLCJ1bmRlZmluZWQiXSwibWFwcGluZ3MiOiJBQUFBLG9GQUFvRixHQUNwRixtQ0FBbUMsR0FDbkMsU0FBUUEsR0FBRyxRQUFzQixXQUFXO0FBQzVDLFNBQVFDLFVBQVUsRUFBRUMsVUFBVSxRQUFPLGNBQWM7QUFFbkQsU0FBUUMsd0JBQXdCLFFBQU8sOEJBQThCO0FBQ3JFLFNBQVFDLEtBQUssUUFBTyw0QkFBNEI7QUFJaEQsT0FBTyxNQUFNQywwQkFBMEI7SUFDckM7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0NBQ0QsQ0FBVTtBQUNYLE9BQU8sTUFBTUMsOEJBQThCSCx5QkFBeUI7QUFzQnBFLE9BQU8sTUFBTUksa0JBQWtCLENBQUMsR0FBR0MsUUFDakNQLFdBQVcsVUFBVVEsTUFBTSxDQUFDQyxLQUFLQyxTQUFTLENBQUNILFFBQVFJLE1BQU0sQ0FBQyxPQUFPO0FBQ25FLE9BQU8sTUFBTUMsb0JBQW9CLElBQWNYLGFBQWE7QUFDNUQsT0FBTyxNQUFNWSxvQkFBb0IsQ0FBQ0M7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
@@ -0,0 +1,138 @@
1
+ import type { ApiContext } from '../types/auth.types.js';
2
+ export type PlanKey = 'starter' | 'pro';
3
+ export type BillingMode = 'disabled' | 'test';
4
+ export type MembershipRole = 'admin' | 'member';
5
+ export type MembershipStatus = 'pending' | 'active' | 'deactivated';
6
+ export type Organization = Readonly<{
7
+ createdAt: number;
8
+ name: string;
9
+ organizationId: string;
10
+ ownerUserId: string;
11
+ revision: number;
12
+ updatedAt: number;
13
+ }>;
14
+ export type OrganizationMembership = Readonly<{
15
+ createdAt: number;
16
+ organizationId: string;
17
+ revision: number;
18
+ role: MembershipRole;
19
+ status: MembershipStatus;
20
+ updatedAt: number;
21
+ userId: string;
22
+ }>;
23
+ export type OrganizationAccess = Readonly<{
24
+ membership: OrganizationMembership;
25
+ organization: Organization;
26
+ userId: string;
27
+ }>;
28
+ export type OrganizationPlan = Readonly<{
29
+ additionalSeatCents: number;
30
+ baseCents: number;
31
+ currency: 'usd';
32
+ includedSeats: 10;
33
+ interval: 'month';
34
+ key: PlanKey;
35
+ version: '2026-10-v1';
36
+ }>;
37
+ export type OveragePreference = Readonly<{
38
+ enabled: boolean;
39
+ monthlyCapCents: number;
40
+ revision: number;
41
+ }>;
42
+ export type SubscriptionSummary = Readonly<{
43
+ activeMembers: number;
44
+ billingMode: BillingMode;
45
+ canManage: boolean;
46
+ estimatedMonthlyCents: number;
47
+ extraSeats: number;
48
+ metersEnabled: false;
49
+ organizationId: string;
50
+ overage: OveragePreference;
51
+ pendingChange: string | null;
52
+ periodEnd: number | null;
53
+ plan: PlanKey | null;
54
+ reconciliationPending: boolean;
55
+ status: string;
56
+ }>;
57
+ export type MembershipChange = Readonly<{
58
+ confirmedQuoteId?: string;
59
+ expectedRevision: number;
60
+ role: MembershipRole;
61
+ status: MembershipStatus;
62
+ userId: string;
63
+ }>;
64
+ export type SeatChangeQuote = Readonly<{
65
+ currency: 'usd';
66
+ expiresAt: number;
67
+ organizationRevision: number;
68
+ prorationCents: number;
69
+ quantity: number;
70
+ quoteId: string;
71
+ }>;
72
+ export type SignupInput = Readonly<{
73
+ email: string;
74
+ organizationName: string;
75
+ password: string;
76
+ requestId: string;
77
+ }>;
78
+ export type SignupResult = Readonly<{
79
+ registrationId: string;
80
+ verificationRequired: true;
81
+ }>;
82
+ export type BillingJob = Readonly<{
83
+ attempts: number;
84
+ desired: Record<string, unknown>;
85
+ effectiveAt: number;
86
+ jobId: string;
87
+ kind: 'cancel' | 'mail' | 'plan' | 'reconcile' | 'seats';
88
+ leaseExpires: number;
89
+ organizationId: string;
90
+ owner: string;
91
+ priceVersion: '2026-10-v1';
92
+ sequence: number;
93
+ status: 'complete' | 'pending';
94
+ }>;
95
+ export type ProviderSubscription = Readonly<{
96
+ cancelAtPeriodEnd?: boolean;
97
+ baseItemId: string;
98
+ customerId: string;
99
+ extraSeats: number;
100
+ id: string;
101
+ lastJobId?: string;
102
+ pendingPlan?: PlanKey | null;
103
+ periodEnd: number;
104
+ periodStart: number;
105
+ plan: PlanKey;
106
+ seatItemId: string;
107
+ status: string;
108
+ startedAt?: number;
109
+ }>;
110
+ export type CheckoutResult = Readonly<{
111
+ expiresAt: number;
112
+ id: string;
113
+ url: string;
114
+ }>;
115
+ export type VerifiedBillingEvent = Readonly<{
116
+ customerId: string;
117
+ eventId: string;
118
+ type: string;
119
+ }>;
120
+ export type BillingAdjustment = Readonly<{
121
+ amountCents: number;
122
+ periodEnd: number;
123
+ periodStart: number;
124
+ providerId: string;
125
+ }>;
126
+ export type BillingUpdateResult = Readonly<{
127
+ adjustments: readonly BillingAdjustment[];
128
+ }>;
129
+ export type BillingProvider = Readonly<{
130
+ checkout: (customerId: string, plan: PlanKey, extraSeats: number, key: string) => Promise<CheckoutResult>;
131
+ customer: (organizationId: string, email: string) => Promise<string>;
132
+ portal: (customerId: string) => Promise<string>;
133
+ preview: (subscription: ProviderSubscription, plan: PlanKey, seats: number, effectiveAt: number) => Promise<number>;
134
+ retrieve: (customerId: string, subscriptionId?: string) => Promise<ProviderSubscription | null>;
135
+ update: (subscription: ProviderSubscription, job: BillingJob, fence: () => Promise<void>) => Promise<BillingUpdateResult>;
136
+ verify: (body: string | Buffer, signature: string) => VerifiedBillingEvent;
137
+ }>;
138
+ export type OrganizationContext = ApiContext;
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9wcml2YXRlL3RtcC92YXVsdC1yZWFrdG9yLWNvbXBsZXRpb24vcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy90eXBlcy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7QXBpQ29udGV4dH0gZnJvbSAnLi4vdHlwZXMvYXV0aC50eXBlcy5qcyc7XG5cbmV4cG9ydCB0eXBlIFBsYW5LZXkgPSAnc3RhcnRlcicgfCAncHJvJztcbmV4cG9ydCB0eXBlIEJpbGxpbmdNb2RlID0gJ2Rpc2FibGVkJyB8ICd0ZXN0JztcbmV4cG9ydCB0eXBlIE1lbWJlcnNoaXBSb2xlID0gJ2FkbWluJyB8ICdtZW1iZXInO1xuZXhwb3J0IHR5cGUgTWVtYmVyc2hpcFN0YXR1cyA9ICdwZW5kaW5nJyB8ICdhY3RpdmUnIHwgJ2RlYWN0aXZhdGVkJztcbmV4cG9ydCB0eXBlIE9yZ2FuaXphdGlvbiA9IFJlYWRvbmx5PHtcbiAgY3JlYXRlZEF0OiBudW1iZXI7XG4gIG5hbWU6IHN0cmluZztcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZztcbiAgb3duZXJVc2VySWQ6IHN0cmluZztcbiAgcmV2aXNpb246IG51bWJlcjtcbiAgdXBkYXRlZEF0OiBudW1iZXI7XG59PjtcbmV4cG9ydCB0eXBlIE9yZ2FuaXphdGlvbk1lbWJlcnNoaXAgPSBSZWFkb25seTx7XG4gIGNyZWF0ZWRBdDogbnVtYmVyO1xuICBvcmdhbml6YXRpb25JZDogc3RyaW5nO1xuICByZXZpc2lvbjogbnVtYmVyO1xuICByb2xlOiBNZW1iZXJzaGlwUm9sZTtcbiAgc3RhdHVzOiBNZW1iZXJzaGlwU3RhdHVzO1xuICB1cGRhdGVkQXQ6IG51bWJlcjtcbiAgdXNlcklkOiBzdHJpbmc7XG59PjtcbmV4cG9ydCB0eXBlIE9yZ2FuaXphdGlvbkFjY2VzcyA9IFJlYWRvbmx5PHtcbiAgbWVtYmVyc2hpcDogT3JnYW5pemF0aW9uTWVtYmVyc2hpcDtcbiAgb3JnYW5pemF0aW9uOiBPcmdhbml6YXRpb247XG4gIHVzZXJJZDogc3RyaW5nO1xufT47XG5leHBvcnQgdHlwZSBPcmdhbml6YXRpb25QbGFuID0gUmVhZG9ubHk8e1xuICBhZGRpdGlvbmFsU2VhdENlbnRzOiBudW1iZXI7XG4gIGJhc2VDZW50czogbnVtYmVyO1xuICBjdXJyZW5jeTogJ3VzZCc7XG4gIGluY2x1ZGVkU2VhdHM6IDEwO1xuICBpbnRlcnZhbDogJ21vbnRoJztcbiAga2V5OiBQbGFuS2V5O1xuICB2ZXJzaW9uOiAnMjAyNi0xMC12MSc7XG59PjtcbmV4cG9ydCB0eXBlIE92ZXJhZ2VQcmVmZXJlbmNlID0gUmVhZG9ubHk8e2VuYWJsZWQ6IGJvb2xlYW47IG1vbnRobHlDYXBDZW50czogbnVtYmVyOyByZXZpc2lvbjogbnVtYmVyfT47XG5leHBvcnQgdHlwZSBTdWJzY3JpcHRpb25TdW1tYXJ5ID0gUmVhZG9ubHk8e1xuICBhY3RpdmVNZW1iZXJzOiBudW1iZXI7XG4gIGJpbGxpbmdNb2RlOiBCaWxsaW5nTW9kZTtcbiAgY2FuTWFuYWdlOiBib29sZWFuO1xuICBlc3RpbWF0ZWRNb250aGx5Q2VudHM6IG51bWJlcjtcbiAgZXh0cmFTZWF0czogbnVtYmVyO1xuICBtZXRlcnNFbmFibGVkOiBmYWxzZTtcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZztcbiAgb3ZlcmFnZTogT3ZlcmFnZVByZWZlcmVuY2U7XG4gIHBlbmRpbmdDaGFuZ2U6IHN0cmluZyB8IG51bGw7XG4gIHBlcmlvZEVuZDogbnVtYmVyIHwgbnVsbDtcbiAgcGxhbjogUGxhbktleSB8IG51bGw7XG4gIHJlY29uY2lsaWF0aW9uUGVuZGluZzogYm9vbGVhbjtcbiAgc3RhdHVzOiBzdHJpbmc7XG59PjtcbmV4cG9ydCB0eXBlIE1lbWJlcnNoaXBDaGFuZ2UgPSBSZWFkb25seTx7XG4gIGNvbmZpcm1lZFF1b3RlSWQ/OiBzdHJpbmc7XG4gIGV4cGVjdGVkUmV2aXNpb246IG51bWJlcjtcbiAgcm9sZTogTWVtYmVyc2hpcFJvbGU7XG4gIHN0YXR1czogTWVtYmVyc2hpcFN0YXR1cztcbiAgdXNlcklkOiBzdHJpbmc7XG59PjtcbmV4cG9ydCB0eXBlIFNlYXRDaGFuZ2VRdW90ZSA9IFJlYWRvbmx5PHtcbiAgY3VycmVuY3k6ICd1c2QnO1xuICBleHBpcmVzQXQ6IG51bWJlcjtcbiAgb3JnYW5pemF0aW9uUmV2aXNpb246IG51bWJlcjtcbiAgcHJvcmF0aW9uQ2VudHM6IG51bWJlcjtcbiAgcXVhbnRpdHk6IG51bWJlcjtcbiAgcXVvdGVJZDogc3RyaW5nO1xufT47XG5leHBvcnQgdHlwZSBTaWdudXBJbnB1dCA9IFJlYWRvbmx5PHtcbiAgZW1haWw6IHN0cmluZztcbiAgb3JnYW5pemF0aW9uTmFtZTogc3RyaW5nO1xuICBwYXNzd29yZDogc3RyaW5nO1xuICByZXF1ZXN0SWQ6IHN0cmluZztcbn0+O1xuZXhwb3J0IHR5cGUgU2lnbnVwUmVzdWx0ID0gUmVhZG9ubHk8e3JlZ2lzdHJhdGlvbklkOiBzdHJpbmc7IHZlcmlmaWNhdGlvblJlcXVpcmVkOiB0cnVlfT47XG5leHBvcnQgdHlwZSBCaWxsaW5nSm9iID0gUmVhZG9ubHk8e1xuICBhdHRlbXB0czogbnVtYmVyO1xuICBkZXNpcmVkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgZWZmZWN0aXZlQXQ6IG51bWJlcjtcbiAgam9iSWQ6IHN0cmluZztcbiAga2luZDogJ2NhbmNlbCcgfCAnbWFpbCcgfCAncGxhbicgfCAncmVjb25jaWxlJyB8ICdzZWF0cyc7XG4gIGxlYXNlRXhwaXJlczogbnVtYmVyO1xuICBvcmdhbml6YXRpb25JZDogc3RyaW5nO1xuICBvd25lcjogc3RyaW5nO1xuICBwcmljZVZlcnNpb246ICcyMDI2LTEwLXYxJztcbiAgc2VxdWVuY2U6IG51bWJlcjtcbiAgc3RhdHVzOiAnY29tcGxldGUnIHwgJ3BlbmRpbmcnO1xufT47XG5leHBvcnQgdHlwZSBQcm92aWRlclN1YnNjcmlwdGlvbiA9IFJlYWRvbmx5PHtcbiAgY2FuY2VsQXRQZXJpb2RFbmQ/OiBib29sZWFuO1xuICBiYXNlSXRlbUlkOiBzdHJpbmc7XG4gIGN1c3RvbWVySWQ6IHN0cmluZztcbiAgZXh0cmFTZWF0czogbnVtYmVyO1xuICBpZDogc3RyaW5nO1xuICBsYXN0Sm9iSWQ/OiBzdHJpbmc7XG4gIHBlbmRpbmdQbGFuPzogUGxhbktleSB8IG51bGw7XG4gIHBlcmlvZEVuZDogbnVtYmVyO1xuICBwZXJpb2RTdGFydDogbnVtYmVyO1xuICBwbGFuOiBQbGFuS2V5O1xuICBzZWF0SXRlbUlkOiBzdHJpbmc7XG4gIHN0YXR1czogc3RyaW5nO1xuICBzdGFydGVkQXQ/OiBudW1iZXI7XG59PjtcbmV4cG9ydCB0eXBlIENoZWNrb3V0UmVzdWx0ID0gUmVhZG9ubHk8e2V4cGlyZXNBdDogbnVtYmVyOyBpZDogc3RyaW5nOyB1cmw6IHN0cmluZ30+O1xuZXhwb3J0IHR5cGUgVmVyaWZpZWRCaWxsaW5nRXZlbnQgPSBSZWFkb25seTx7Y3VzdG9tZXJJZDogc3RyaW5nOyBldmVudElkOiBzdHJpbmc7IHR5cGU6IHN0cmluZ30+O1xuZXhwb3J0IHR5cGUgQmlsbGluZ0FkanVzdG1lbnQgPSBSZWFkb25seTx7XG4gIGFtb3VudENlbnRzOiBudW1iZXI7XG4gIHBlcmlvZEVuZDogbnVtYmVyO1xuICBwZXJpb2RTdGFydDogbnVtYmVyO1xuICBwcm92aWRlcklkOiBzdHJpbmc7XG59PjtcbmV4cG9ydCB0eXBlIEJpbGxpbmdVcGRhdGVSZXN1bHQgPSBSZWFkb25seTx7YWRqdXN0bWVudHM6IHJlYWRvbmx5IEJpbGxpbmdBZGp1c3RtZW50W119PjtcbmV4cG9ydCB0eXBlIEJpbGxpbmdQcm92aWRlciA9IFJlYWRvbmx5PHtcbiAgY2hlY2tvdXQ6IChjdXN0b21lcklkOiBzdHJpbmcsIHBsYW46IFBsYW5LZXksIGV4dHJhU2VhdHM6IG51bWJlciwga2V5OiBzdHJpbmcpID0+IFByb21pc2U8Q2hlY2tvdXRSZXN1bHQ+O1xuICBjdXN0b21lcjogKG9yZ2FuaXphdGlvbklkOiBzdHJpbmcsIGVtYWlsOiBzdHJpbmcpID0+IFByb21pc2U8c3RyaW5nPjtcbiAgcG9ydGFsOiAoY3VzdG9tZXJJZDogc3RyaW5nKSA9PiBQcm9taXNlPHN0cmluZz47XG4gIHByZXZpZXc6IChcbiAgICBzdWJzY3JpcHRpb246IFByb3ZpZGVyU3Vic2NyaXB0aW9uLFxuICAgIHBsYW46IFBsYW5LZXksXG4gICAgc2VhdHM6IG51bWJlcixcbiAgICBlZmZlY3RpdmVBdDogbnVtYmVyXG4gICkgPT4gUHJvbWlzZTxudW1iZXI+O1xuICByZXRyaWV2ZTogKGN1c3RvbWVySWQ6IHN0cmluZywgc3Vic2NyaXB0aW9uSWQ/OiBzdHJpbmcpID0+IFByb21pc2U8UHJvdmlkZXJTdWJzY3JpcHRpb24gfCBudWxsPjtcbiAgdXBkYXRlOiAoXG4gICAgc3Vic2NyaXB0aW9uOiBQcm92aWRlclN1YnNjcmlwdGlvbixcbiAgICBqb2I6IEJpbGxpbmdKb2IsXG4gICAgZmVuY2U6ICgpID0+IFByb21pc2U8dm9pZD5cbiAgKSA9PiBQcm9taXNlPEJpbGxpbmdVcGRhdGVSZXN1bHQ+O1xuICB2ZXJpZnk6IChib2R5OiBzdHJpbmcgfCBCdWZmZXIsIHNpZ25hdHVyZTogc3RyaW5nKSA9PiBWZXJpZmllZEJpbGxpbmdFdmVudDtcbn0+O1xuZXhwb3J0IHR5cGUgT3JnYW5pemF0aW9uQ29udGV4dCA9IEFwaUNvbnRleHQ7XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBa0lBLFdBQTZDIn0=
@@ -0,0 +1,3 @@
1
+ import type { ApiContext } from '../types/auth.types.js';
2
+ export declare const verifyOrganizationEmail: (registrationId: string, token: string, context: ApiContext) => Promise<void>;
3
+ export declare const resendOrganizationVerification: (registrationId: string, context: ApiContext) => Promise<void>;
@@ -0,0 +1,51 @@
1
+ import { queueOrganizationVerification } from './signup.js';
2
+ import { organizationKey, organizationStoreFor, requireIdentifier } from './store.js';
3
+ export const verifyOrganizationEmail = async (registrationId, token, context)=>{
4
+ const error = await organizationStoreFor(context).transaction(async (tx)=>{
5
+ const previous = await tx.get('organizationVerificationTokens', requireIdentifier(registrationId));
6
+ if (!previous || previous.used || previous.expiresAt <= Date.now()) {
7
+ return 'invalid_verification';
8
+ }
9
+ const now = Date.now();
10
+ const attempts = now - previous.attemptWindow < 3600000 ? previous.attempts : 0;
11
+ if (attempts >= 10) {
12
+ return 'verification_rate_limited';
13
+ }
14
+ const valid = typeof token === 'string' && token.length <= 128 && previous.tokenHash === organizationKey(token);
15
+ await tx.put('organizationVerificationTokens', registrationId, {
16
+ ...previous,
17
+ attemptWindow: attempts ? previous.attemptWindow : now,
18
+ attempts: attempts + 1,
19
+ used: valid
20
+ }, previous);
21
+ if (!valid) {
22
+ return 'invalid_verification';
23
+ }
24
+ const user = await tx.get('users', previous.userId);
25
+ if (!user) {
26
+ throw new Error('invalid_verification');
27
+ }
28
+ await tx.put('users', previous.userId, {
29
+ ...user,
30
+ verifiedEmail: true
31
+ }, user);
32
+ return '';
33
+ });
34
+ if (error) {
35
+ throw new Error(error);
36
+ }
37
+ };
38
+ export const resendOrganizationVerification = (registrationId, context)=>organizationStoreFor(context).transaction(async (tx)=>{
39
+ const registration = await tx.get('organizationRegistrations', requireIdentifier(registrationId));
40
+ const previous = await tx.get('organizationVerificationTokens', registrationId);
41
+ if (!registration?.userId || !previous || previous.used) {
42
+ return;
43
+ }
44
+ const now = Date.now();
45
+ if (now - previous.lastSent < 60000 || now - previous.resendWindow < 3600000 && previous.resendCount >= 5) {
46
+ throw new Error('verification_rate_limited');
47
+ }
48
+ await queueOrganizationVerification(tx, registration, previous);
49
+ });
50
+
51
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9wcml2YXRlL3RtcC92YXVsdC1yZWFrdG9yLWNvbXBsZXRpb24vcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy92ZXJpZmljYXRpb24udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtxdWV1ZU9yZ2FuaXphdGlvblZlcmlmaWNhdGlvbiwgdHlwZSBSZWdpc3RyYXRpb24sIHR5cGUgVmVyaWZpY2F0aW9ufSBmcm9tICcuL3NpZ251cC5qcyc7XG5pbXBvcnQge29yZ2FuaXphdGlvbktleSwgb3JnYW5pemF0aW9uU3RvcmVGb3IsIHJlcXVpcmVJZGVudGlmaWVyfSBmcm9tICcuL3N0b3JlLmpzJztcblxuaW1wb3J0IHR5cGUge0FwaUNvbnRleHR9IGZyb20gJy4uL3R5cGVzL2F1dGgudHlwZXMuanMnO1xuXG5leHBvcnQgY29uc3QgdmVyaWZ5T3JnYW5pemF0aW9uRW1haWwgPSBhc3luYyAoXG4gIHJlZ2lzdHJhdGlvbklkOiBzdHJpbmcsXG4gIHRva2VuOiBzdHJpbmcsXG4gIGNvbnRleHQ6IEFwaUNvbnRleHRcbik6IFByb21pc2U8dm9pZD4gPT4ge1xuICBjb25zdCBlcnJvciA9IGF3YWl0IG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgIGNvbnN0IHByZXZpb3VzID0gYXdhaXQgdHguZ2V0PFZlcmlmaWNhdGlvbj4oXG4gICAgICAnb3JnYW5pemF0aW9uVmVyaWZpY2F0aW9uVG9rZW5zJyxcbiAgICAgIHJlcXVpcmVJZGVudGlmaWVyKHJlZ2lzdHJhdGlvbklkKVxuICAgICk7XG4gICAgaWYoIXByZXZpb3VzIHx8IHByZXZpb3VzLnVzZWQgfHwgcHJldmlvdXMuZXhwaXJlc0F0IDw9IERhdGUubm93KCkpIHtcbiAgICAgIHJldHVybiAnaW52YWxpZF92ZXJpZmljYXRpb24nO1xuICAgIH1cbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IGF0dGVtcHRzID0gbm93IC0gcHJldmlvdXMuYXR0ZW1wdFdpbmRvdyA8IDM2MDAwMDAgPyBwcmV2aW91cy5hdHRlbXB0cyA6IDA7XG4gICAgaWYoYXR0ZW1wdHMgPj0gMTApIHtcbiAgICAgIHJldHVybiAndmVyaWZpY2F0aW9uX3JhdGVfbGltaXRlZCc7XG4gICAgfVxuICAgIGNvbnN0IHZhbGlkID1cbiAgICAgIHR5cGVvZiB0b2tlbiA9PT0gJ3N0cmluZycgJiYgdG9rZW4ubGVuZ3RoIDw9IDEyOCAmJiBwcmV2aW91cy50b2tlbkhhc2ggPT09IG9yZ2FuaXphdGlvbktleSh0b2tlbik7XG4gICAgYXdhaXQgdHgucHV0KFxuICAgICAgJ29yZ2FuaXphdGlvblZlcmlmaWNhdGlvblRva2VucycsXG4gICAgICByZWdpc3RyYXRpb25JZCxcbiAgICAgIHtcbiAgICAgICAgLi4ucHJldmlvdXMsXG4gICAgICAgIGF0dGVtcHRXaW5kb3c6IGF0dGVtcHRzID8gcHJldmlvdXMuYXR0ZW1wdFdpbmRvdyA6IG5vdyxcbiAgICAgICAgYXR0ZW1wdHM6IGF0dGVtcHRzICsgMSxcbiAgICAgICAgdXNlZDogdmFsaWRcbiAgICAgIH0sXG4gICAgICBwcmV2aW91c1xuICAgICk7XG4gICAgaWYoIXZhbGlkKSB7XG4gICAgICByZXR1cm4gJ2ludmFsaWRfdmVyaWZpY2F0aW9uJztcbiAgICB9XG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHR4LmdldCgndXNlcnMnLCBwcmV2aW91cy51c2VySWQpO1xuICAgIGlmKCF1c2VyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWRfdmVyaWZpY2F0aW9uJyk7XG4gICAgfVxuICAgIGF3YWl0IHR4LnB1dCgndXNlcnMnLCBwcmV2aW91cy51c2VySWQsIHsuLi51c2VyLCB2ZXJpZmllZEVtYWlsOiB0cnVlfSwgdXNlcik7XG4gICAgcmV0dXJuICcnO1xuICB9KTtcbiAgaWYoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3IpO1xuICB9XG59O1xuXG5leHBvcnQgY29uc3QgcmVzZW5kT3JnYW5pemF0aW9uVmVyaWZpY2F0aW9uID0gKHJlZ2lzdHJhdGlvbklkOiBzdHJpbmcsIGNvbnRleHQ6IEFwaUNvbnRleHQpOiBQcm9taXNlPHZvaWQ+ID0+XG4gIG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgIGNvbnN0IHJlZ2lzdHJhdGlvbiA9IGF3YWl0IHR4LmdldDxSZWdpc3RyYXRpb24+KFxuICAgICAgJ29yZ2FuaXphdGlvblJlZ2lzdHJhdGlvbnMnLFxuICAgICAgcmVxdWlyZUlkZW50aWZpZXIocmVnaXN0cmF0aW9uSWQpXG4gICAgKTtcbiAgICBjb25zdCBwcmV2aW91cyA9IGF3YWl0IHR4LmdldDxWZXJpZmljYXRpb24+KCdvcmdhbml6YXRpb25WZXJpZmljYXRpb25Ub2tlbnMnLCByZWdpc3RyYXRpb25JZCk7XG4gICAgaWYoIXJlZ2lzdHJhdGlvbj8udXNlcklkIHx8ICFwcmV2aW91cyB8fCBwcmV2aW91cy51c2VkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgaWYoXG4gICAgICBub3cgLSBwcmV2aW91cy5sYXN0U2VudCA8IDYwMDAwIHx8XG4gICAgICAobm93IC0gcHJldmlvdXMucmVzZW5kV2luZG93IDwgMzYwMDAwMCAmJiBwcmV2aW91cy5yZXNlbmRDb3VudCA+PSA1KVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd2ZXJpZmljYXRpb25fcmF0ZV9saW1pdGVkJyk7XG4gICAgfVxuICAgIGF3YWl0IHF1ZXVlT3JnYW5pemF0aW9uVmVyaWZpY2F0aW9uKHR4LCByZWdpc3RyYXRpb24sIHByZXZpb3VzKTtcbiAgfSk7XG4iXSwibmFtZXMiOlsicXVldWVPcmdhbml6YXRpb25WZXJpZmljYXRpb24iLCJvcmdhbml6YXRpb25LZXkiLCJvcmdhbml6YXRpb25TdG9yZUZvciIsInJlcXVpcmVJZGVudGlmaWVyIiwidmVyaWZ5T3JnYW5pemF0aW9uRW1haWwiLCJyZWdpc3RyYXRpb25JZCIsInRva2VuIiwiY29udGV4dCIsImVycm9yIiwidHJhbnNhY3Rpb24iLCJ0eCIsInByZXZpb3VzIiwiZ2V0IiwidXNlZCIsImV4cGlyZXNBdCIsIkRhdGUiLCJub3ciLCJhdHRlbXB0cyIsImF0dGVtcHRXaW5kb3ciLCJ2YWxpZCIsImxlbmd0aCIsInRva2VuSGFzaCIsInB1dCIsInVzZXIiLCJ1c2VySWQiLCJFcnJvciIsInZlcmlmaWVkRW1haWwiLCJyZXNlbmRPcmdhbml6YXRpb25WZXJpZmljYXRpb24iLCJyZWdpc3RyYXRpb24iLCJsYXN0U2VudCIsInJlc2VuZFdpbmRvdyIsInJlc2VuZENvdW50Il0sIm1hcHBpbmdzIjoiQUFBQSxTQUFRQSw2QkFBNkIsUUFBNkMsY0FBYztBQUNoRyxTQUFRQyxlQUFlLEVBQUVDLG9CQUFvQixFQUFFQyxpQkFBaUIsUUFBTyxhQUFhO0FBSXBGLE9BQU8sTUFBTUMsMEJBQTBCLE9BQ3JDQyxnQkFDQUMsT0FDQUM7SUFFQSxNQUFNQyxRQUFRLE1BQU1OLHFCQUFxQkssU0FBU0UsV0FBVyxDQUFDLE9BQU9DO1FBQ25FLE1BQU1DLFdBQVcsTUFBTUQsR0FBR0UsR0FBRyxDQUMzQixrQ0FDQVQsa0JBQWtCRTtRQUVwQixJQUFHLENBQUNNLFlBQVlBLFNBQVNFLElBQUksSUFBSUYsU0FBU0csU0FBUyxJQUFJQyxLQUFLQyxHQUFHLElBQUk7WUFDakUsT0FBTztRQUNUO1FBQ0EsTUFBTUEsTUFBTUQsS0FBS0MsR0FBRztRQUNwQixNQUFNQyxXQUFXRCxNQUFNTCxTQUFTTyxhQUFhLEdBQUcsVUFBVVAsU0FBU00sUUFBUSxHQUFHO1FBQzlFLElBQUdBLFlBQVksSUFBSTtZQUNqQixPQUFPO1FBQ1Q7UUFDQSxNQUFNRSxRQUNKLE9BQU9iLFVBQVUsWUFBWUEsTUFBTWMsTUFBTSxJQUFJLE9BQU9ULFNBQVNVLFNBQVMsS0FBS3BCLGdCQUFnQks7UUFDN0YsTUFBTUksR0FBR1ksR0FBRyxDQUNWLGtDQUNBakIsZ0JBQ0E7WUFDRSxHQUFHTSxRQUFRO1lBQ1hPLGVBQWVELFdBQVdOLFNBQVNPLGFBQWEsR0FBR0Y7WUFDbkRDLFVBQVVBLFdBQVc7WUFDckJKLE1BQU1NO1FBQ1IsR0FDQVI7UUFFRixJQUFHLENBQUNRLE9BQU87WUFDVCxPQUFPO1FBQ1Q7UUFDQSxNQUFNSSxPQUFPLE1BQU1iLEdBQUdFLEdBQUcsQ0FBQyxTQUFTRCxTQUFTYSxNQUFNO1FBQ2xELElBQUcsQ0FBQ0QsTUFBTTtZQUNSLE1BQU0sSUFBSUUsTUFBTTtRQUNsQjtRQUNBLE1BQU1mLEdBQUdZLEdBQUcsQ0FBQyxTQUFTWCxTQUFTYSxNQUFNLEVBQUU7WUFBQyxHQUFHRCxJQUFJO1lBQUVHLGVBQWU7UUFBSSxHQUFHSDtRQUN2RSxPQUFPO0lBQ1Q7SUFDQSxJQUFHZixPQUFPO1FBQ1IsTUFBTSxJQUFJaUIsTUFBTWpCO0lBQ2xCO0FBQ0YsRUFBRTtBQUVGLE9BQU8sTUFBTW1CLGlDQUFpQyxDQUFDdEIsZ0JBQXdCRSxVQUNyRUwscUJBQXFCSyxTQUFTRSxXQUFXLENBQUMsT0FBT0M7UUFDL0MsTUFBTWtCLGVBQWUsTUFBTWxCLEdBQUdFLEdBQUcsQ0FDL0IsNkJBQ0FULGtCQUFrQkU7UUFFcEIsTUFBTU0sV0FBVyxNQUFNRCxHQUFHRSxHQUFHLENBQWUsa0NBQWtDUDtRQUM5RSxJQUFHLENBQUN1QixjQUFjSixVQUFVLENBQUNiLFlBQVlBLFNBQVNFLElBQUksRUFBRTtZQUN0RDtRQUNGO1FBQ0EsTUFBTUcsTUFBTUQsS0FBS0MsR0FBRztRQUNwQixJQUNFQSxNQUFNTCxTQUFTa0IsUUFBUSxHQUFHLFNBQ3pCYixNQUFNTCxTQUFTbUIsWUFBWSxHQUFHLFdBQVduQixTQUFTb0IsV0FBVyxJQUFJLEdBQ2xFO1lBQ0EsTUFBTSxJQUFJTixNQUFNO1FBQ2xCO1FBQ0EsTUFBTXpCLDhCQUE4QlUsSUFBSWtCLGNBQWNqQjtJQUN4RCxHQUFHIn0=