@nlabs/reaktor 1.16.0 → 1.18.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 (103) hide show
  1. package/README.md +186 -0
  2. package/docs/ASSISTANT.md +138 -0
  3. package/docs/GENERATION.md +29 -2
  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/contentGeneration.d.ts +4 -1
  8. package/lib/actions/contentGeneration.js +83 -27
  9. package/lib/actions/contentGenerationErrors.js +1 -1
  10. package/lib/actions/conversations.d.ts +1 -1
  11. package/lib/actions/conversations.js +19 -9
  12. package/lib/actions/crud.js +26 -1
  13. package/lib/actions/index.d.ts +2 -0
  14. package/lib/actions/index.js +3 -1
  15. package/lib/actions/messages.js +23 -7
  16. package/lib/actions/phoneSupport.d.ts +18 -0
  17. package/lib/actions/phoneSupport.js +170 -0
  18. package/lib/actions/users.js +57 -4
  19. package/lib/assistant/core.d.ts +53 -0
  20. package/lib/assistant/core.js +123 -0
  21. package/lib/assistant/faq.d.ts +26 -0
  22. package/lib/assistant/faq.js +238 -0
  23. package/lib/assistant/faqCore.d.ts +23 -0
  24. package/lib/assistant/faqCore.js +20 -0
  25. package/lib/assistant/index.d.ts +7 -0
  26. package/lib/assistant/index.js +5 -0
  27. package/lib/assistant/service.d.ts +35 -0
  28. package/lib/assistant/service.js +201 -0
  29. package/lib/config.js +3 -2
  30. package/lib/durableChat/conversations.d.ts +62 -0
  31. package/lib/durableChat/conversations.js +729 -0
  32. package/lib/durableChat/errors.d.ts +6 -0
  33. package/lib/durableChat/errors.js +11 -0
  34. package/lib/durableChat/events.d.ts +22 -0
  35. package/lib/durableChat/events.js +50 -0
  36. package/lib/durableChat/index.d.ts +8 -0
  37. package/lib/durableChat/index.js +10 -0
  38. package/lib/durableChat/membership.d.ts +24 -0
  39. package/lib/durableChat/membership.js +85 -0
  40. package/lib/durableChat/messageTypes.d.ts +76 -0
  41. package/lib/durableChat/messageTypes.js +3 -0
  42. package/lib/durableChat/messages.d.ts +16 -0
  43. package/lib/durableChat/messages.js +257 -0
  44. package/lib/durableChat/transaction.d.ts +10 -0
  45. package/lib/durableChat/transaction.js +53 -0
  46. package/lib/durableChat/types.d.ts +81 -0
  47. package/lib/durableChat/types.js +3 -0
  48. package/lib/index.d.ts +4 -4
  49. package/lib/index.js +5 -3
  50. package/lib/lambdas/actions/websockets.js +4 -4
  51. package/lib/nativePush/graphql.d.ts +14 -0
  52. package/lib/nativePush/graphql.js +105 -0
  53. package/lib/nativePush/index.d.ts +7 -0
  54. package/lib/nativePush/index.js +9 -0
  55. package/lib/nativePush/migrations.d.ts +2 -0
  56. package/lib/nativePush/migrations.js +36 -0
  57. package/lib/nativePush/nativePushContract.fixture.d.ts +22 -0
  58. package/lib/nativePush/nativePushContract.fixture.js +27 -0
  59. package/lib/nativePush/payload.d.ts +2 -0
  60. package/lib/nativePush/payload.js +106 -0
  61. package/lib/nativePush/repository.d.ts +9 -0
  62. package/lib/nativePush/repository.js +120 -0
  63. package/lib/nativePush/service.d.ts +2 -0
  64. package/lib/nativePush/service.js +110 -0
  65. package/lib/nativePush/snsProvider.d.ts +17 -0
  66. package/lib/nativePush/snsProvider.js +165 -0
  67. package/lib/nativePush/types.d.ts +89 -0
  68. package/lib/nativePush/types.js +3 -0
  69. package/lib/organizations/accountLifecycle.d.ts +7 -0
  70. package/lib/organizations/accountLifecycle.js +106 -0
  71. package/lib/organizations/authorization.d.ts +9 -0
  72. package/lib/organizations/authorization.js +40 -0
  73. package/lib/organizations/billing.d.ts +38 -0
  74. package/lib/organizations/billing.js +277 -0
  75. package/lib/organizations/billingProvider.d.ts +4 -0
  76. package/lib/organizations/billingProvider.js +287 -0
  77. package/lib/organizations/billingUpdates.d.ts +9 -0
  78. package/lib/organizations/billingUpdates.js +388 -0
  79. package/lib/organizations/index.d.ts +10 -0
  80. package/lib/organizations/index.js +12 -0
  81. package/lib/organizations/mail.d.ts +10 -0
  82. package/lib/organizations/mail.js +60 -0
  83. package/lib/organizations/memberDirectory.d.ts +15 -0
  84. package/lib/organizations/memberDirectory.js +28 -0
  85. package/lib/organizations/membership.d.ts +19 -0
  86. package/lib/organizations/membership.js +248 -0
  87. package/lib/organizations/passwordRecovery.d.ts +9 -0
  88. package/lib/organizations/passwordRecovery.js +50 -0
  89. package/lib/organizations/plans.d.ts +6 -0
  90. package/lib/organizations/plans.js +40 -0
  91. package/lib/organizations/providerPagination.d.ts +6 -0
  92. package/lib/organizations/providerPagination.js +23 -0
  93. package/lib/organizations/reconciliation.d.ts +11 -0
  94. package/lib/organizations/reconciliation.js +400 -0
  95. package/lib/organizations/signup.d.ts +25 -0
  96. package/lib/organizations/signup.js +169 -0
  97. package/lib/organizations/store.d.ts +25 -0
  98. package/lib/organizations/store.js +167 -0
  99. package/lib/organizations/types.d.ts +138 -0
  100. package/lib/organizations/types.js +3 -0
  101. package/lib/organizations/verification.d.ts +3 -0
  102. package/lib/organizations/verification.js +51 -0
  103. package/package.json +16 -3
@@ -0,0 +1,19 @@
1
+ import { type OrganizationTransaction, type Stored } from './store.js';
2
+ import type { ApiContext } from '../types/auth.types.js';
3
+ import type { MembershipChange, Organization, OrganizationMembership } from './types.js';
4
+ export declare const activeMemberCount: (tx: OrganizationTransaction, organizationId: string) => Promise<number>;
5
+ export declare const writeSeatChange: (tx: OrganizationTransaction, org: Stored<Organization>, quantity: number, effectiveAt: number, previousQuantity: number) => Promise<void>;
6
+ export declare const validateSeatQuote: (tx: OrganizationTransaction, org: Organization, change: MembershipChange, quantity: number) => Promise<void>;
7
+ export declare const changeOrganizationMember: (context: ApiContext, organizationId: string, change: MembershipChange) => Promise<OrganizationMembership>;
8
+ export declare const requestOwnershipTransfer: (context: ApiContext, organizationId: string, recipientUserId: string) => Promise<{
9
+ transferId: string;
10
+ }>;
11
+ export declare const acceptOwnershipTransfer: (context: ApiContext, transferId: string) => Promise<Organization>;
12
+ export declare const inviteOrganizationMember: (context: ApiContext, organizationId: string, email: string, acceptsAdditionalSeatCharge: boolean) => Promise<{
13
+ invitationId: string;
14
+ token: string;
15
+ }>;
16
+ export declare const acceptOrganizationInvitation: (context: ApiContext, invitationId: string, token: string) => Promise<OrganizationMembership>;
17
+ export declare const revokeOrganizationInvitation: (context: ApiContext, invitationId: string) => Promise<void>;
18
+ export declare const assertOrganizationAccountRemovalAllowed: (context: ApiContext, userId: string) => Promise<void>;
19
+ export declare const listOrganizationMembers: (context: ApiContext, organizationId: string) => Promise<OrganizationMembership[]>;
@@ -0,0 +1,248 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { organizationAccessInTransaction, organizationUserId } from './authorization.js';
3
+ import { newOrganizationId, organizationKey, organizationStoreFor, requireIdentifier } from './store.js';
4
+ export const activeMemberCount = async (tx, organizationId)=>(await tx.find('organizationMemberships', {
5
+ organizationId,
6
+ status: 'active'
7
+ })).length;
8
+ export const writeSeatChange = async (tx, org, quantity, effectiveAt, previousQuantity)=>{
9
+ const revision = org.revision + 1;
10
+ await tx.put('organizations', org.organizationId, {
11
+ ...org,
12
+ revision,
13
+ updatedAt: effectiveAt
14
+ }, org);
15
+ const jobId = organizationKey(org.organizationId, String(revision));
16
+ const job = {
17
+ attempts: 0,
18
+ desired: {
19
+ extraSeats: Math.max(0, quantity - 10),
20
+ previousExtraSeats: Math.max(0, previousQuantity - 10)
21
+ },
22
+ effectiveAt,
23
+ jobId,
24
+ kind: 'seats',
25
+ leaseExpires: 0,
26
+ organizationId: org.organizationId,
27
+ owner: '',
28
+ priceVersion: '2026-10-v1',
29
+ sequence: revision,
30
+ status: 'pending'
31
+ };
32
+ await tx.put('organizationBillingJobs', jobId, job);
33
+ };
34
+ export const validateSeatQuote = async (tx, org, change, quantity)=>{
35
+ const quote = change.confirmedQuoteId ? await tx.get('organizationBillingQuotes', change.confirmedQuoteId) : null;
36
+ if (!quote || quote.used || quote.organizationRevision !== org.revision || quote.organizationId !== org.organizationId || quote.expectedRevision !== change.expectedRevision || quote.role !== change.role || quote.expiresAt <= Date.now() || quote.userId !== change.userId || quote.status !== change.status || quote.quantity !== quantity) {
37
+ throw new Error('seat_quote_required');
38
+ }
39
+ await tx.put('organizationBillingQuotes', quote._key, {
40
+ ...quote,
41
+ used: true
42
+ }, quote);
43
+ };
44
+ export const changeOrganizationMember = (context, organizationId, change)=>organizationStoreFor(context).transaction(async (tx)=>{
45
+ const access = await organizationAccessInTransaction(tx, context, organizationId, 'admin');
46
+ const org = await tx.get('organizations', organizationId);
47
+ const member = await tx.get('organizationMemberships', organizationKey(organizationId, requireIdentifier(change.userId)));
48
+ if (![
49
+ 'admin',
50
+ 'member'
51
+ ].includes(change.role) || ![
52
+ 'active',
53
+ 'deactivated'
54
+ ].includes(change.status) || !Number.isSafeInteger(change.expectedRevision)) {
55
+ throw new Error('invalid_membership');
56
+ }
57
+ if (!org || !member || member.revision !== change.expectedRevision) {
58
+ throw new Error('revision_conflict');
59
+ }
60
+ if (access.organization.ownerUserId === member.userId && (change.role !== 'admin' || change.status !== 'active')) {
61
+ throw new Error('ownership_transfer_required');
62
+ }
63
+ const user = await tx.get('users', member.userId);
64
+ if (change.status === 'active' && (!user?.active || !user.verifiedEmail)) {
65
+ throw new Error('verified_active_user_required');
66
+ }
67
+ const count = await activeMemberCount(tx, organizationId);
68
+ const nextCount = count + Number(change.status === 'active') - Number(member.status === 'active');
69
+ const billing = await tx.get('organizationBilling', organizationId);
70
+ if (nextCount > count && nextCount > 10 && billing?.plan) {
71
+ if (billing.status !== 'active') {
72
+ throw new Error('billing_not_ready');
73
+ }
74
+ await validateSeatQuote(tx, org, change, Math.max(0, nextCount - 10));
75
+ }
76
+ const now = Date.now();
77
+ const updated = {
78
+ ...member,
79
+ revision: member.revision + 1,
80
+ role: change.role,
81
+ status: change.status,
82
+ updatedAt: now
83
+ };
84
+ await tx.put('organizationMemberships', member._key, updated, member);
85
+ await writeSeatChange(tx, org, nextCount, now, count);
86
+ return updated;
87
+ });
88
+ export const requestOwnershipTransfer = (context, organizationId, recipientUserId)=>organizationStoreFor(context).transaction(async (tx)=>{
89
+ const { organization } = await organizationAccessInTransaction(tx, context, organizationId, 'owner');
90
+ const recipient = await tx.get('organizationMemberships', organizationKey(organizationId, requireIdentifier(recipientUserId)));
91
+ if (!recipient || recipient.status !== 'active' || recipientUserId === organization.ownerUserId) {
92
+ throw new Error('active_recipient_required');
93
+ }
94
+ const transferId = newOrganizationId();
95
+ await tx.put('organizationOwnerTransfers', transferId, {
96
+ expiresAt: Date.now() + 48 * 3600000,
97
+ organizationId,
98
+ ownerUserId: organization.ownerUserId,
99
+ recipientUserId,
100
+ revision: organization.revision,
101
+ used: false
102
+ });
103
+ return {
104
+ transferId
105
+ };
106
+ });
107
+ export const acceptOwnershipTransfer = (context, transferId)=>organizationStoreFor(context).transaction(async (tx)=>{
108
+ const transfer = await tx.get('organizationOwnerTransfers', requireIdentifier(transferId));
109
+ if (!transfer || transfer.used || transfer.expiresAt <= Date.now() || transfer.recipientUserId !== organizationUserId(context)) {
110
+ throw new Error('invalid_transfer');
111
+ }
112
+ const access = await organizationAccessInTransaction(tx, context, transfer.organizationId, 'member');
113
+ const org = await tx.get('organizations', transfer.organizationId);
114
+ const member = await tx.get('organizationMemberships', organizationKey(transfer.organizationId, access.userId));
115
+ if (!org || !member || org.ownerUserId !== transfer.ownerUserId || org.revision !== transfer.revision) {
116
+ throw new Error('invalid_transfer');
117
+ }
118
+ const now = Date.now();
119
+ const updated = {
120
+ ...org,
121
+ ownerUserId: access.userId,
122
+ revision: org.revision + 1,
123
+ updatedAt: now
124
+ };
125
+ await tx.put('organizations', org._key, updated, org);
126
+ await tx.put('organizationMemberships', member._key, {
127
+ ...member,
128
+ revision: member.revision + 1,
129
+ role: 'admin',
130
+ updatedAt: now
131
+ }, member);
132
+ await tx.put('organizationOwnerTransfers', transfer._key, {
133
+ ...transfer,
134
+ used: true
135
+ }, transfer);
136
+ const user = await tx.get('users', access.userId);
137
+ if (!user) {
138
+ throw new Error('organization_state_invalid');
139
+ }
140
+ await tx.put('users', access.userId, {
141
+ ...user,
142
+ organizationAccount: true
143
+ }, user);
144
+ return updated;
145
+ });
146
+ export const inviteOrganizationMember = (context, organizationId, email, acceptsAdditionalSeatCharge)=>organizationStoreFor(context).transaction(async (tx)=>{
147
+ const access = await organizationAccessInTransaction(tx, context, organizationId, 'admin');
148
+ const normalized = email.trim().toLowerCase();
149
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalized) || !acceptsAdditionalSeatCharge) {
150
+ throw new Error('invitation_charge_disclosure_required');
151
+ }
152
+ const existing = (await tx.find('organizationInvitations', {
153
+ email: normalized,
154
+ organizationId
155
+ })).find((invitation)=>!invitation.used && !invitation.revoked && invitation.expiresAt > Date.now());
156
+ if (existing) {
157
+ throw new Error('invitation_exists');
158
+ }
159
+ const invitationId = newOrganizationId();
160
+ const token = randomBytes(32).toString('base64url');
161
+ await tx.put('organizationInvitations', invitationId, {
162
+ email: normalized,
163
+ expiresAt: Date.now() + 7 * 86400000,
164
+ invitedBy: access.userId,
165
+ organizationId,
166
+ revoked: false,
167
+ tokenHash: organizationKey(token),
168
+ used: false
169
+ });
170
+ return {
171
+ invitationId,
172
+ token
173
+ };
174
+ });
175
+ export const acceptOrganizationInvitation = (context, invitationId, token)=>organizationStoreFor(context).transaction(async (tx)=>{
176
+ const userId = organizationUserId(context);
177
+ const invitation = await tx.get('organizationInvitations', requireIdentifier(invitationId));
178
+ const user = await tx.get('users', userId);
179
+ if (!invitation || invitation.revoked || invitation.used || invitation.expiresAt <= Date.now() || invitation.tokenHash !== organizationKey(token) || !user?.active || !user.verifiedEmail || user.email.toLowerCase() !== invitation.email) {
180
+ throw new Error('invalid_invitation');
181
+ }
182
+ await organizationAccessInTransaction(tx, {
183
+ session: {
184
+ userId: invitation.invitedBy
185
+ }
186
+ }, invitation.organizationId, 'admin');
187
+ const org = await tx.get('organizations', invitation.organizationId);
188
+ if (!org) {
189
+ throw new Error('organization_access_denied');
190
+ }
191
+ const key = organizationKey(invitation.organizationId, userId);
192
+ const previous = await tx.get('organizationMemberships', key);
193
+ if (previous?.status === 'active') {
194
+ throw new Error('already_active');
195
+ }
196
+ const now = Date.now();
197
+ const member = {
198
+ createdAt: previous?.createdAt || now,
199
+ organizationId: org.organizationId,
200
+ revision: (previous?.revision || 0) + 1,
201
+ role: previous?.role || 'member',
202
+ status: 'active',
203
+ updatedAt: now,
204
+ userId
205
+ };
206
+ const previousCount = await activeMemberCount(tx, org.organizationId);
207
+ const billing = await tx.get('organizationBilling', org.organizationId);
208
+ if (previousCount >= 10 && billing?.plan && billing.status !== 'active') {
209
+ throw new Error('billing_not_ready');
210
+ }
211
+ await tx.put('organizationMemberships', key, member, previous);
212
+ await tx.put('users', userId, {
213
+ ...user,
214
+ organizationAccount: true
215
+ }, user);
216
+ await writeSeatChange(tx, org, previousCount + 1, now, previousCount);
217
+ await tx.put('organizationInvitations', invitationId, {
218
+ ...invitation,
219
+ used: true
220
+ }, invitation);
221
+ return member;
222
+ });
223
+ export const revokeOrganizationInvitation = (context, invitationId)=>organizationStoreFor(context).transaction(async (tx)=>{
224
+ const invitation = await tx.get('organizationInvitations', requireIdentifier(invitationId));
225
+ if (!invitation) {
226
+ throw new Error('invalid_invitation');
227
+ }
228
+ await organizationAccessInTransaction(tx, context, invitation.organizationId, 'admin');
229
+ await tx.put('organizationInvitations', invitationId, {
230
+ ...invitation,
231
+ revoked: true
232
+ }, invitation);
233
+ });
234
+ export const assertOrganizationAccountRemovalAllowed = (context, userId)=>organizationStoreFor(context).transaction(async (tx)=>{
235
+ if ((await tx.find('organizations', {
236
+ ownerUserId: requireIdentifier(userId.replace(/^users\//, ''))
237
+ })).length) {
238
+ throw new Error('ownership_transfer_required');
239
+ }
240
+ });
241
+ export const listOrganizationMembers = (context, organizationId)=>organizationStoreFor(context).transaction(async (tx)=>{
242
+ await organizationAccessInTransaction(tx, context, organizationId, 'member');
243
+ return tx.find('organizationMemberships', {
244
+ organizationId
245
+ });
246
+ }); /* ArangoDB document metadata uses these reserved field names. */ /* eslint no-underscore-dangle: ["warn", {"allow": ["_key", "_rev", "_id"]}] */
247
+
248
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy9tZW1iZXJzaGlwLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7cmFuZG9tQnl0ZXN9IGZyb20gJ25vZGU6Y3J5cHRvJztcblxuaW1wb3J0IHtvcmdhbml6YXRpb25BY2Nlc3NJblRyYW5zYWN0aW9uLCBvcmdhbml6YXRpb25Vc2VySWR9IGZyb20gJy4vYXV0aG9yaXphdGlvbi5qcyc7XG5pbXBvcnQge1xuICBuZXdPcmdhbml6YXRpb25JZCxcbiAgb3JnYW5pemF0aW9uS2V5LFxuICBvcmdhbml6YXRpb25TdG9yZUZvcixcbiAgcmVxdWlyZUlkZW50aWZpZXIsXG4gIHR5cGUgT3JnYW5pemF0aW9uVHJhbnNhY3Rpb24sXG4gIHR5cGUgU3RvcmVkXG59IGZyb20gJy4vc3RvcmUuanMnO1xuXG5pbXBvcnQgdHlwZSB7QXBpQ29udGV4dH0gZnJvbSAnLi4vdHlwZXMvYXV0aC50eXBlcy5qcyc7XG5pbXBvcnQgdHlwZSB7XG4gIEJpbGxpbmdKb2IsXG4gIE1lbWJlcnNoaXBDaGFuZ2UsXG4gIE9yZ2FuaXphdGlvbixcbiAgT3JnYW5pemF0aW9uTWVtYmVyc2hpcCxcbiAgU2VhdENoYW5nZVF1b3RlXG59IGZyb20gJy4vdHlwZXMuanMnO1xuXG5leHBvcnQgY29uc3QgYWN0aXZlTWVtYmVyQ291bnQgPSBhc3luYyAoXG4gIHR4OiBPcmdhbml6YXRpb25UcmFuc2FjdGlvbixcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZ1xuKTogUHJvbWlzZTxudW1iZXI+ID0+XG4gIChhd2FpdCB0eC5maW5kPE9yZ2FuaXphdGlvbk1lbWJlcnNoaXA+KCdvcmdhbml6YXRpb25NZW1iZXJzaGlwcycsIHtvcmdhbml6YXRpb25JZCwgc3RhdHVzOiAnYWN0aXZlJ30pKVxuICAgIC5sZW5ndGg7XG5cbmV4cG9ydCBjb25zdCB3cml0ZVNlYXRDaGFuZ2UgPSBhc3luYyAoXG4gIHR4OiBPcmdhbml6YXRpb25UcmFuc2FjdGlvbixcbiAgb3JnOiBTdG9yZWQ8T3JnYW5pemF0aW9uPixcbiAgcXVhbnRpdHk6IG51bWJlcixcbiAgZWZmZWN0aXZlQXQ6IG51bWJlcixcbiAgcHJldmlvdXNRdWFudGl0eTogbnVtYmVyXG4pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgY29uc3QgcmV2aXNpb24gPSBvcmcucmV2aXNpb24gKyAxO1xuICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbnMnLCBvcmcub3JnYW5pemF0aW9uSWQsIHsuLi5vcmcsIHJldmlzaW9uLCB1cGRhdGVkQXQ6IGVmZmVjdGl2ZUF0fSwgb3JnKTtcbiAgY29uc3Qgam9iSWQgPSBvcmdhbml6YXRpb25LZXkob3JnLm9yZ2FuaXphdGlvbklkLCBTdHJpbmcocmV2aXNpb24pKTtcbiAgY29uc3Qgam9iOiBCaWxsaW5nSm9iID0ge1xuICAgIGF0dGVtcHRzOiAwLFxuICAgIGRlc2lyZWQ6IHtleHRyYVNlYXRzOiBNYXRoLm1heCgwLCBxdWFudGl0eSAtIDEwKSwgcHJldmlvdXNFeHRyYVNlYXRzOiBNYXRoLm1heCgwLCBwcmV2aW91c1F1YW50aXR5IC0gMTApfSxcbiAgICBlZmZlY3RpdmVBdCxcbiAgICBqb2JJZCxcbiAgICBraW5kOiAnc2VhdHMnLFxuICAgIGxlYXNlRXhwaXJlczogMCxcbiAgICBvcmdhbml6YXRpb25JZDogb3JnLm9yZ2FuaXphdGlvbklkLFxuICAgIG93bmVyOiAnJyxcbiAgICBwcmljZVZlcnNpb246ICcyMDI2LTEwLXYxJyxcbiAgICBzZXF1ZW5jZTogcmV2aXNpb24sXG4gICAgc3RhdHVzOiAncGVuZGluZydcbiAgfTtcbiAgYXdhaXQgdHgucHV0KCdvcmdhbml6YXRpb25CaWxsaW5nSm9icycsIGpvYklkLCBqb2IpO1xufTtcblxuZXhwb3J0IGNvbnN0IHZhbGlkYXRlU2VhdFF1b3RlID0gYXN5bmMgKFxuICB0eDogT3JnYW5pemF0aW9uVHJhbnNhY3Rpb24sXG4gIG9yZzogT3JnYW5pemF0aW9uLFxuICBjaGFuZ2U6IE1lbWJlcnNoaXBDaGFuZ2UsXG4gIHF1YW50aXR5OiBudW1iZXJcbik6IFByb21pc2U8dm9pZD4gPT4ge1xuICBjb25zdCBxdW90ZSA9IGNoYW5nZS5jb25maXJtZWRRdW90ZUlkXG4gICAgPyBhd2FpdCB0eC5nZXQ8XG4gICAgICAgIFNlYXRDaGFuZ2VRdW90ZSAmIHtcbiAgICAgICAgICBleHBlY3RlZFJldmlzaW9uOiBudW1iZXI7XG4gICAgICAgICAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZztcbiAgICAgICAgICByb2xlOiBzdHJpbmc7XG4gICAgICAgICAgdXNlcklkOiBzdHJpbmc7XG4gICAgICAgICAgc3RhdHVzOiBzdHJpbmc7XG4gICAgICAgICAgdXNlZDogYm9vbGVhbjtcbiAgICAgICAgfVxuICAgID4oJ29yZ2FuaXphdGlvbkJpbGxpbmdRdW90ZXMnLCBjaGFuZ2UuY29uZmlybWVkUXVvdGVJZClcbiAgICA6IG51bGw7XG4gIGlmKFxuICAgICFxdW90ZSB8fFxuICAgIHF1b3RlLnVzZWQgfHxcbiAgICBxdW90ZS5vcmdhbml6YXRpb25SZXZpc2lvbiAhPT0gb3JnLnJldmlzaW9uIHx8XG4gICAgcXVvdGUub3JnYW5pemF0aW9uSWQgIT09IG9yZy5vcmdhbml6YXRpb25JZCB8fFxuICAgIHF1b3RlLmV4cGVjdGVkUmV2aXNpb24gIT09IGNoYW5nZS5leHBlY3RlZFJldmlzaW9uIHx8XG4gICAgcXVvdGUucm9sZSAhPT0gY2hhbmdlLnJvbGUgfHxcbiAgICBxdW90ZS5leHBpcmVzQXQgPD0gRGF0ZS5ub3coKSB8fFxuICAgIHF1b3RlLnVzZXJJZCAhPT0gY2hhbmdlLnVzZXJJZCB8fFxuICAgIHF1b3RlLnN0YXR1cyAhPT0gY2hhbmdlLnN0YXR1cyB8fFxuICAgIHF1b3RlLnF1YW50aXR5ICE9PSBxdWFudGl0eVxuICApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3NlYXRfcXVvdGVfcmVxdWlyZWQnKTtcbiAgfVxuICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbkJpbGxpbmdRdW90ZXMnLCBxdW90ZS5fa2V5LCB7Li4ucXVvdGUsIHVzZWQ6IHRydWV9LCBxdW90ZSk7XG59O1xuXG5leHBvcnQgY29uc3QgY2hhbmdlT3JnYW5pemF0aW9uTWVtYmVyID0gKFxuICBjb250ZXh0OiBBcGlDb250ZXh0LFxuICBvcmdhbml6YXRpb25JZDogc3RyaW5nLFxuICBjaGFuZ2U6IE1lbWJlcnNoaXBDaGFuZ2Vcbik6IFByb21pc2U8T3JnYW5pemF0aW9uTWVtYmVyc2hpcD4gPT5cbiAgb3JnYW5pemF0aW9uU3RvcmVGb3IoY29udGV4dCkudHJhbnNhY3Rpb24oYXN5bmMgKHR4KSA9PiB7XG4gICAgY29uc3QgYWNjZXNzID0gYXdhaXQgb3JnYW5pemF0aW9uQWNjZXNzSW5UcmFuc2FjdGlvbih0eCwgY29udGV4dCwgb3JnYW5pemF0aW9uSWQsICdhZG1pbicpO1xuICAgIGNvbnN0IG9yZyA9IGF3YWl0IHR4LmdldDxPcmdhbml6YXRpb24+KCdvcmdhbml6YXRpb25zJywgb3JnYW5pemF0aW9uSWQpO1xuICAgIGNvbnN0IG1lbWJlciA9IGF3YWl0IHR4LmdldDxPcmdhbml6YXRpb25NZW1iZXJzaGlwPihcbiAgICAgICdvcmdhbml6YXRpb25NZW1iZXJzaGlwcycsXG4gICAgICBvcmdhbml6YXRpb25LZXkob3JnYW5pemF0aW9uSWQsIHJlcXVpcmVJZGVudGlmaWVyKGNoYW5nZS51c2VySWQpKVxuICAgICk7XG4gICAgaWYoXG4gICAgICAhWydhZG1pbicsICdtZW1iZXInXS5pbmNsdWRlcyhjaGFuZ2Uucm9sZSkgfHxcbiAgICAgICFbJ2FjdGl2ZScsICdkZWFjdGl2YXRlZCddLmluY2x1ZGVzKGNoYW5nZS5zdGF0dXMpIHx8XG4gICAgICAhTnVtYmVyLmlzU2FmZUludGVnZXIoY2hhbmdlLmV4cGVjdGVkUmV2aXNpb24pXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWRfbWVtYmVyc2hpcCcpO1xuICAgIH1cbiAgICBpZighb3JnIHx8ICFtZW1iZXIgfHwgbWVtYmVyLnJldmlzaW9uICE9PSBjaGFuZ2UuZXhwZWN0ZWRSZXZpc2lvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdyZXZpc2lvbl9jb25mbGljdCcpO1xuICAgIH1cbiAgICBpZihcbiAgICAgIGFjY2Vzcy5vcmdhbml6YXRpb24ub3duZXJVc2VySWQgPT09IG1lbWJlci51c2VySWQgJiZcbiAgICAgIChjaGFuZ2Uucm9sZSAhPT0gJ2FkbWluJyB8fCBjaGFuZ2Uuc3RhdHVzICE9PSAnYWN0aXZlJylcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignb3duZXJzaGlwX3RyYW5zZmVyX3JlcXVpcmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0eC5nZXQ8e2FjdGl2ZTogYm9vbGVhbjsgdmVyaWZpZWRFbWFpbDogYm9vbGVhbn0+KCd1c2VycycsIG1lbWJlci51c2VySWQpO1xuICAgIGlmKGNoYW5nZS5zdGF0dXMgPT09ICdhY3RpdmUnICYmICghdXNlcj8uYWN0aXZlIHx8ICF1c2VyLnZlcmlmaWVkRW1haWwpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmaWVkX2FjdGl2ZV91c2VyX3JlcXVpcmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGNvdW50ID0gYXdhaXQgYWN0aXZlTWVtYmVyQ291bnQodHgsIG9yZ2FuaXphdGlvbklkKTtcbiAgICBjb25zdCBuZXh0Q291bnQgPSBjb3VudCArIE51bWJlcihjaGFuZ2Uuc3RhdHVzID09PSAnYWN0aXZlJykgLSBOdW1iZXIobWVtYmVyLnN0YXR1cyA9PT0gJ2FjdGl2ZScpO1xuICAgIGNvbnN0IGJpbGxpbmcgPSBhd2FpdCB0eC5nZXQ8e3BsYW4/OiBzdHJpbmc7IHN0YXR1cz86IHN0cmluZ30+KCdvcmdhbml6YXRpb25CaWxsaW5nJywgb3JnYW5pemF0aW9uSWQpO1xuICAgIGlmKG5leHRDb3VudCA+IGNvdW50ICYmIG5leHRDb3VudCA+IDEwICYmIGJpbGxpbmc/LnBsYW4pIHtcbiAgICAgIGlmKGJpbGxpbmcuc3RhdHVzICE9PSAnYWN0aXZlJykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2JpbGxpbmdfbm90X3JlYWR5Jyk7XG4gICAgICB9XG4gICAgICBhd2FpdCB2YWxpZGF0ZVNlYXRRdW90ZSh0eCwgb3JnLCBjaGFuZ2UsIE1hdGgubWF4KDAsIG5leHRDb3VudCAtIDEwKSk7XG4gICAgfVxuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgY29uc3QgdXBkYXRlZCA9IHtcbiAgICAgIC4uLm1lbWJlcixcbiAgICAgIHJldmlzaW9uOiBtZW1iZXIucmV2aXNpb24gKyAxLFxuICAgICAgcm9sZTogY2hhbmdlLnJvbGUsXG4gICAgICBzdGF0dXM6IGNoYW5nZS5zdGF0dXMsXG4gICAgICB1cGRhdGVkQXQ6IG5vd1xuICAgIH07XG4gICAgYXdhaXQgdHgucHV0KCdvcmdhbml6YXRpb25NZW1iZXJzaGlwcycsIG1lbWJlci5fa2V5LCB1cGRhdGVkLCBtZW1iZXIpO1xuICAgIGF3YWl0IHdyaXRlU2VhdENoYW5nZSh0eCwgb3JnLCBuZXh0Q291bnQsIG5vdywgY291bnQpO1xuICAgIHJldHVybiB1cGRhdGVkO1xuICB9KTtcblxudHlwZSBUcmFuc2ZlciA9IHtcbiAgZXhwaXJlc0F0OiBudW1iZXI7XG4gIG9yZ2FuaXphdGlvbklkOiBzdHJpbmc7XG4gIG93bmVyVXNlcklkOiBzdHJpbmc7XG4gIHJlY2lwaWVudFVzZXJJZDogc3RyaW5nO1xuICByZXZpc2lvbjogbnVtYmVyO1xuICB1c2VkOiBib29sZWFuO1xufTtcbmV4cG9ydCBjb25zdCByZXF1ZXN0T3duZXJzaGlwVHJhbnNmZXIgPSAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4gIG9yZ2FuaXphdGlvbklkOiBzdHJpbmcsXG4gIHJlY2lwaWVudFVzZXJJZDogc3RyaW5nXG4pOiBQcm9taXNlPHt0cmFuc2ZlcklkOiBzdHJpbmd9PiA9PlxuICBvcmdhbml6YXRpb25TdG9yZUZvcihjb250ZXh0KS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICBjb25zdCB7b3JnYW5pemF0aW9ufSA9IGF3YWl0IG9yZ2FuaXphdGlvbkFjY2Vzc0luVHJhbnNhY3Rpb24odHgsIGNvbnRleHQsIG9yZ2FuaXphdGlvbklkLCAnb3duZXInKTtcbiAgICBjb25zdCByZWNpcGllbnQgPSBhd2FpdCB0eC5nZXQ8T3JnYW5pemF0aW9uTWVtYmVyc2hpcD4oXG4gICAgICAnb3JnYW5pemF0aW9uTWVtYmVyc2hpcHMnLFxuICAgICAgb3JnYW5pemF0aW9uS2V5KG9yZ2FuaXphdGlvbklkLCByZXF1aXJlSWRlbnRpZmllcihyZWNpcGllbnRVc2VySWQpKVxuICAgICk7XG4gICAgaWYoIXJlY2lwaWVudCB8fCByZWNpcGllbnQuc3RhdHVzICE9PSAnYWN0aXZlJyB8fCByZWNpcGllbnRVc2VySWQgPT09IG9yZ2FuaXphdGlvbi5vd25lclVzZXJJZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdhY3RpdmVfcmVjaXBpZW50X3JlcXVpcmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IHRyYW5zZmVySWQgPSBuZXdPcmdhbml6YXRpb25JZCgpO1xuICAgIGF3YWl0IHR4LnB1dCgnb3JnYW5pemF0aW9uT3duZXJUcmFuc2ZlcnMnLCB0cmFuc2ZlcklkLCB7XG4gICAgICBleHBpcmVzQXQ6IERhdGUubm93KCkgKyAoNDggKiAzNjAwMDAwKSxcbiAgICAgIG9yZ2FuaXphdGlvbklkLFxuICAgICAgb3duZXJVc2VySWQ6IG9yZ2FuaXphdGlvbi5vd25lclVzZXJJZCxcbiAgICAgIHJlY2lwaWVudFVzZXJJZCxcbiAgICAgIHJldmlzaW9uOiBvcmdhbml6YXRpb24ucmV2aXNpb24sXG4gICAgICB1c2VkOiBmYWxzZVxuICAgIH0pO1xuICAgIHJldHVybiB7dHJhbnNmZXJJZH07XG4gIH0pO1xuXG5leHBvcnQgY29uc3QgYWNjZXB0T3duZXJzaGlwVHJhbnNmZXIgPSAoY29udGV4dDogQXBpQ29udGV4dCwgdHJhbnNmZXJJZDogc3RyaW5nKTogUHJvbWlzZTxPcmdhbml6YXRpb24+ID0+XG4gIG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgIGNvbnN0IHRyYW5zZmVyID0gYXdhaXQgdHguZ2V0PFRyYW5zZmVyPignb3JnYW5pemF0aW9uT3duZXJUcmFuc2ZlcnMnLCByZXF1aXJlSWRlbnRpZmllcih0cmFuc2ZlcklkKSk7XG4gICAgaWYoXG4gICAgICAhdHJhbnNmZXIgfHxcbiAgICAgIHRyYW5zZmVyLnVzZWQgfHxcbiAgICAgIHRyYW5zZmVyLmV4cGlyZXNBdCA8PSBEYXRlLm5vdygpIHx8XG4gICAgICB0cmFuc2Zlci5yZWNpcGllbnRVc2VySWQgIT09IG9yZ2FuaXphdGlvblVzZXJJZChjb250ZXh0KVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkX3RyYW5zZmVyJyk7XG4gICAgfVxuICAgIGNvbnN0IGFjY2VzcyA9IGF3YWl0IG9yZ2FuaXphdGlvbkFjY2Vzc0luVHJhbnNhY3Rpb24odHgsIGNvbnRleHQsIHRyYW5zZmVyLm9yZ2FuaXphdGlvbklkLCAnbWVtYmVyJyk7XG4gICAgY29uc3Qgb3JnID0gYXdhaXQgdHguZ2V0PE9yZ2FuaXphdGlvbj4oJ29yZ2FuaXphdGlvbnMnLCB0cmFuc2Zlci5vcmdhbml6YXRpb25JZCk7XG4gICAgY29uc3QgbWVtYmVyID0gYXdhaXQgdHguZ2V0PE9yZ2FuaXphdGlvbk1lbWJlcnNoaXA+KFxuICAgICAgJ29yZ2FuaXphdGlvbk1lbWJlcnNoaXBzJyxcbiAgICAgIG9yZ2FuaXphdGlvbktleSh0cmFuc2Zlci5vcmdhbml6YXRpb25JZCwgYWNjZXNzLnVzZXJJZClcbiAgICApO1xuICAgIGlmKCFvcmcgfHwgIW1lbWJlciB8fCBvcmcub3duZXJVc2VySWQgIT09IHRyYW5zZmVyLm93bmVyVXNlcklkIHx8IG9yZy5yZXZpc2lvbiAhPT0gdHJhbnNmZXIucmV2aXNpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZF90cmFuc2ZlcicpO1xuICAgIH1cbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IHVwZGF0ZWQgPSB7Li4ub3JnLCBvd25lclVzZXJJZDogYWNjZXNzLnVzZXJJZCwgcmV2aXNpb246IG9yZy5yZXZpc2lvbiArIDEsIHVwZGF0ZWRBdDogbm93fTtcbiAgICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbnMnLCBvcmcuX2tleSwgdXBkYXRlZCwgb3JnKTtcbiAgICBhd2FpdCB0eC5wdXQoXG4gICAgICAnb3JnYW5pemF0aW9uTWVtYmVyc2hpcHMnLFxuICAgICAgbWVtYmVyLl9rZXksXG4gICAgICB7Li4ubWVtYmVyLCByZXZpc2lvbjogbWVtYmVyLnJldmlzaW9uICsgMSwgcm9sZTogJ2FkbWluJywgdXBkYXRlZEF0OiBub3d9LFxuICAgICAgbWVtYmVyXG4gICAgKTtcbiAgICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbk93bmVyVHJhbnNmZXJzJywgdHJhbnNmZXIuX2tleSwgey4uLnRyYW5zZmVyLCB1c2VkOiB0cnVlfSwgdHJhbnNmZXIpO1xuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0eC5nZXQoJ3VzZXJzJywgYWNjZXNzLnVzZXJJZCk7XG4gICAgaWYoIXVzZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignb3JnYW5pemF0aW9uX3N0YXRlX2ludmFsaWQnKTtcbiAgICB9XG4gICAgYXdhaXQgdHgucHV0KCd1c2VycycsIGFjY2Vzcy51c2VySWQsIHsuLi51c2VyLCBvcmdhbml6YXRpb25BY2NvdW50OiB0cnVlfSwgdXNlcik7XG4gICAgcmV0dXJuIHVwZGF0ZWQ7XG4gIH0pO1xuXG50eXBlIEludml0YXRpb24gPSB7XG4gIGVtYWlsOiBzdHJpbmc7XG4gIGV4cGlyZXNBdDogbnVtYmVyO1xuICBpbnZpdGVkQnk6IHN0cmluZztcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZztcbiAgcmV2b2tlZDogYm9vbGVhbjtcbiAgdG9rZW5IYXNoOiBzdHJpbmc7XG4gIHVzZWQ6IGJvb2xlYW47XG59O1xuZXhwb3J0IGNvbnN0IGludml0ZU9yZ2FuaXphdGlvbk1lbWJlciA9IChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZyxcbiAgZW1haWw6IHN0cmluZyxcbiAgYWNjZXB0c0FkZGl0aW9uYWxTZWF0Q2hhcmdlOiBib29sZWFuXG4pOiBQcm9taXNlPHtpbnZpdGF0aW9uSWQ6IHN0cmluZzsgdG9rZW46IHN0cmluZ30+ID0+XG4gIG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgIGNvbnN0IGFjY2VzcyA9IGF3YWl0IG9yZ2FuaXphdGlvbkFjY2Vzc0luVHJhbnNhY3Rpb24odHgsIGNvbnRleHQsIG9yZ2FuaXphdGlvbklkLCAnYWRtaW4nKTtcbiAgICBjb25zdCBub3JtYWxpemVkID0gZW1haWwudHJpbSgpLnRvTG93ZXJDYXNlKCk7XG4gICAgaWYoIS9eW15cXHNAXStAW15cXHNAXStcXC5bXlxcc0BdKyQvLnRlc3Qobm9ybWFsaXplZCkgfHwgIWFjY2VwdHNBZGRpdGlvbmFsU2VhdENoYXJnZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZpdGF0aW9uX2NoYXJnZV9kaXNjbG9zdXJlX3JlcXVpcmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGV4aXN0aW5nID0gKFxuICAgICAgYXdhaXQgdHguZmluZDxJbnZpdGF0aW9uPignb3JnYW5pemF0aW9uSW52aXRhdGlvbnMnLCB7ZW1haWw6IG5vcm1hbGl6ZWQsIG9yZ2FuaXphdGlvbklkfSlcbiAgICApLmZpbmQoKGludml0YXRpb24pID0+ICFpbnZpdGF0aW9uLnVzZWQgJiYgIWludml0YXRpb24ucmV2b2tlZCAmJiBpbnZpdGF0aW9uLmV4cGlyZXNBdCA+IERhdGUubm93KCkpO1xuICAgIGlmKGV4aXN0aW5nKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludml0YXRpb25fZXhpc3RzJyk7XG4gICAgfVxuICAgIGNvbnN0IGludml0YXRpb25JZCA9IG5ld09yZ2FuaXphdGlvbklkKCk7XG4gICAgY29uc3QgdG9rZW4gPSByYW5kb21CeXRlcygzMikudG9TdHJpbmcoJ2Jhc2U2NHVybCcpO1xuICAgIGF3YWl0IHR4LnB1dCgnb3JnYW5pemF0aW9uSW52aXRhdGlvbnMnLCBpbnZpdGF0aW9uSWQsIHtcbiAgICAgIGVtYWlsOiBub3JtYWxpemVkLFxuICAgICAgZXhwaXJlc0F0OiBEYXRlLm5vdygpICsgKDcgKiA4NjQwMDAwMCksXG4gICAgICBpbnZpdGVkQnk6IGFjY2Vzcy51c2VySWQsXG4gICAgICBvcmdhbml6YXRpb25JZCxcbiAgICAgIHJldm9rZWQ6IGZhbHNlLFxuICAgICAgdG9rZW5IYXNoOiBvcmdhbml6YXRpb25LZXkodG9rZW4pLFxuICAgICAgdXNlZDogZmFsc2VcbiAgICB9KTtcbiAgICByZXR1cm4ge2ludml0YXRpb25JZCwgdG9rZW59O1xuICB9KTtcblxuZXhwb3J0IGNvbnN0IGFjY2VwdE9yZ2FuaXphdGlvbkludml0YXRpb24gPSAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4gIGludml0YXRpb25JZDogc3RyaW5nLFxuICB0b2tlbjogc3RyaW5nXG4pOiBQcm9taXNlPE9yZ2FuaXphdGlvbk1lbWJlcnNoaXA+ID0+XG4gIG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgIGNvbnN0IHVzZXJJZCA9IG9yZ2FuaXphdGlvblVzZXJJZChjb250ZXh0KTtcbiAgICBjb25zdCBpbnZpdGF0aW9uID0gYXdhaXQgdHguZ2V0PEludml0YXRpb24+KCdvcmdhbml6YXRpb25JbnZpdGF0aW9ucycsIHJlcXVpcmVJZGVudGlmaWVyKGludml0YXRpb25JZCkpO1xuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0eC5nZXQ8e2FjdGl2ZTogYm9vbGVhbjsgZW1haWw6IHN0cmluZzsgdmVyaWZpZWRFbWFpbDogYm9vbGVhbn0+KCd1c2VycycsIHVzZXJJZCk7XG4gICAgaWYoXG4gICAgICAhaW52aXRhdGlvbiB8fFxuICAgICAgaW52aXRhdGlvbi5yZXZva2VkIHx8XG4gICAgICBpbnZpdGF0aW9uLnVzZWQgfHxcbiAgICAgIGludml0YXRpb24uZXhwaXJlc0F0IDw9IERhdGUubm93KCkgfHxcbiAgICAgIGludml0YXRpb24udG9rZW5IYXNoICE9PSBvcmdhbml6YXRpb25LZXkodG9rZW4pIHx8XG4gICAgICAhdXNlcj8uYWN0aXZlIHx8XG4gICAgICAhdXNlci52ZXJpZmllZEVtYWlsIHx8XG4gICAgICB1c2VyLmVtYWlsLnRvTG93ZXJDYXNlKCkgIT09IGludml0YXRpb24uZW1haWxcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZF9pbnZpdGF0aW9uJyk7XG4gICAgfVxuICAgIGF3YWl0IG9yZ2FuaXphdGlvbkFjY2Vzc0luVHJhbnNhY3Rpb24oXG4gICAgICB0eCxcbiAgICAgIHtzZXNzaW9uOiB7dXNlcklkOiBpbnZpdGF0aW9uLmludml0ZWRCeX19LFxuICAgICAgaW52aXRhdGlvbi5vcmdhbml6YXRpb25JZCxcbiAgICAgICdhZG1pbidcbiAgICApO1xuICAgIGNvbnN0IG9yZyA9IGF3YWl0IHR4LmdldDxPcmdhbml6YXRpb24+KCdvcmdhbml6YXRpb25zJywgaW52aXRhdGlvbi5vcmdhbml6YXRpb25JZCk7XG4gICAgaWYoIW9yZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdvcmdhbml6YXRpb25fYWNjZXNzX2RlbmllZCcpO1xuICAgIH1cbiAgICBjb25zdCBrZXkgPSBvcmdhbml6YXRpb25LZXkoaW52aXRhdGlvbi5vcmdhbml6YXRpb25JZCwgdXNlcklkKTtcbiAgICBjb25zdCBwcmV2aW91cyA9IGF3YWl0IHR4LmdldDxPcmdhbml6YXRpb25NZW1iZXJzaGlwPignb3JnYW5pemF0aW9uTWVtYmVyc2hpcHMnLCBrZXkpO1xuICAgIGlmKHByZXZpb3VzPy5zdGF0dXMgPT09ICdhY3RpdmUnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2FscmVhZHlfYWN0aXZlJyk7XG4gICAgfVxuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgY29uc3QgbWVtYmVyOiBPcmdhbml6YXRpb25NZW1iZXJzaGlwID0ge1xuICAgICAgY3JlYXRlZEF0OiBwcmV2aW91cz8uY3JlYXRlZEF0IHx8IG5vdyxcbiAgICAgIG9yZ2FuaXphdGlvbklkOiBvcmcub3JnYW5pemF0aW9uSWQsXG4gICAgICByZXZpc2lvbjogKHByZXZpb3VzPy5yZXZpc2lvbiB8fCAwKSArIDEsXG4gICAgICByb2xlOiBwcmV2aW91cz8ucm9sZSB8fCAnbWVtYmVyJyxcbiAgICAgIHN0YXR1czogJ2FjdGl2ZScsXG4gICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgIHVzZXJJZFxuICAgIH07XG4gICAgY29uc3QgcHJldmlvdXNDb3VudCA9IGF3YWl0IGFjdGl2ZU1lbWJlckNvdW50KHR4LCBvcmcub3JnYW5pemF0aW9uSWQpO1xuICAgIGNvbnN0IGJpbGxpbmcgPSBhd2FpdCB0eC5nZXQ8e3BsYW4/OiBzdHJpbmc7IHN0YXR1cz86IHN0cmluZ30+KCdvcmdhbml6YXRpb25CaWxsaW5nJywgb3JnLm9yZ2FuaXphdGlvbklkKTtcbiAgICBpZihwcmV2aW91c0NvdW50ID49IDEwICYmIGJpbGxpbmc/LnBsYW4gJiYgYmlsbGluZy5zdGF0dXMgIT09ICdhY3RpdmUnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2JpbGxpbmdfbm90X3JlYWR5Jyk7XG4gICAgfVxuICAgIGF3YWl0IHR4LnB1dCgnb3JnYW5pemF0aW9uTWVtYmVyc2hpcHMnLCBrZXksIG1lbWJlciwgcHJldmlvdXMpO1xuICAgIGF3YWl0IHR4LnB1dCgndXNlcnMnLCB1c2VySWQsIHsuLi51c2VyLCBvcmdhbml6YXRpb25BY2NvdW50OiB0cnVlfSwgdXNlcik7XG4gICAgYXdhaXQgd3JpdGVTZWF0Q2hhbmdlKHR4LCBvcmcsIHByZXZpb3VzQ291bnQgKyAxLCBub3csIHByZXZpb3VzQ291bnQpO1xuICAgIGF3YWl0IHR4LnB1dCgnb3JnYW5pemF0aW9uSW52aXRhdGlvbnMnLCBpbnZpdGF0aW9uSWQsIHsuLi5pbnZpdGF0aW9uLCB1c2VkOiB0cnVlfSwgaW52aXRhdGlvbik7XG4gICAgcmV0dXJuIG1lbWJlcjtcbiAgfSk7XG5cbmV4cG9ydCBjb25zdCByZXZva2VPcmdhbml6YXRpb25JbnZpdGF0aW9uID0gKGNvbnRleHQ6IEFwaUNvbnRleHQsIGludml0YXRpb25JZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiA9PlxuICBvcmdhbml6YXRpb25TdG9yZUZvcihjb250ZXh0KS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICBjb25zdCBpbnZpdGF0aW9uID0gYXdhaXQgdHguZ2V0PEludml0YXRpb24+KCdvcmdhbml6YXRpb25JbnZpdGF0aW9ucycsIHJlcXVpcmVJZGVudGlmaWVyKGludml0YXRpb25JZCkpO1xuICAgIGlmKCFpbnZpdGF0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWRfaW52aXRhdGlvbicpO1xuICAgIH1cbiAgICBhd2FpdCBvcmdhbml6YXRpb25BY2Nlc3NJblRyYW5zYWN0aW9uKHR4LCBjb250ZXh0LCBpbnZpdGF0aW9uLm9yZ2FuaXphdGlvbklkLCAnYWRtaW4nKTtcbiAgICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbkludml0YXRpb25zJywgaW52aXRhdGlvbklkLCB7Li4uaW52aXRhdGlvbiwgcmV2b2tlZDogdHJ1ZX0sIGludml0YXRpb24pO1xuICB9KTtcblxuZXhwb3J0IGNvbnN0IGFzc2VydE9yZ2FuaXphdGlvbkFjY291bnRSZW1vdmFsQWxsb3dlZCA9IChjb250ZXh0OiBBcGlDb250ZXh0LCB1c2VySWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4gPT5cbiAgb3JnYW5pemF0aW9uU3RvcmVGb3IoY29udGV4dCkudHJhbnNhY3Rpb24oYXN5bmMgKHR4KSA9PiB7XG4gICAgaWYoXG4gICAgICAoXG4gICAgICAgIGF3YWl0IHR4LmZpbmQ8T3JnYW5pemF0aW9uPignb3JnYW5pemF0aW9ucycsIHtcbiAgICAgICAgICBvd25lclVzZXJJZDogcmVxdWlyZUlkZW50aWZpZXIodXNlcklkLnJlcGxhY2UoL151c2Vyc1xcLy8sICcnKSlcbiAgICAgICAgfSlcbiAgICAgICkubGVuZ3RoXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ293bmVyc2hpcF90cmFuc2Zlcl9yZXF1aXJlZCcpO1xuICAgIH1cbiAgfSk7XG5cbmV4cG9ydCBjb25zdCBsaXN0T3JnYW5pemF0aW9uTWVtYmVycyA9IChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZ1xuKTogUHJvbWlzZTxPcmdhbml6YXRpb25NZW1iZXJzaGlwW10+ID0+XG4gIG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgIGF3YWl0IG9yZ2FuaXphdGlvbkFjY2Vzc0luVHJhbnNhY3Rpb24odHgsIGNvbnRleHQsIG9yZ2FuaXphdGlvbklkLCAnbWVtYmVyJyk7XG4gICAgcmV0dXJuIHR4LmZpbmQ8T3JnYW5pemF0aW9uTWVtYmVyc2hpcD4oJ29yZ2FuaXphdGlvbk1lbWJlcnNoaXBzJywge29yZ2FuaXphdGlvbklkfSk7XG4gIH0pO1xuLyogQXJhbmdvREIgZG9jdW1lbnQgbWV0YWRhdGEgdXNlcyB0aGVzZSByZXNlcnZlZCBmaWVsZCBuYW1lcy4gKi9cbi8qIGVzbGludCBuby11bmRlcnNjb3JlLWRhbmdsZTogW1wid2FyblwiLCB7XCJhbGxvd1wiOiBbXCJfa2V5XCIsIFwiX3JldlwiLCBcIl9pZFwiXX1dICovXG4iXSwibmFtZXMiOlsicmFuZG9tQnl0ZXMiLCJvcmdhbml6YXRpb25BY2Nlc3NJblRyYW5zYWN0aW9uIiwib3JnYW5pemF0aW9uVXNlcklkIiwibmV3T3JnYW5pemF0aW9uSWQiLCJvcmdhbml6YXRpb25LZXkiLCJvcmdhbml6YXRpb25TdG9yZUZvciIsInJlcXVpcmVJZGVudGlmaWVyIiwiYWN0aXZlTWVtYmVyQ291bnQiLCJ0eCIsIm9yZ2FuaXphdGlvbklkIiwiZmluZCIsInN0YXR1cyIsImxlbmd0aCIsIndyaXRlU2VhdENoYW5nZSIsIm9yZyIsInF1YW50aXR5IiwiZWZmZWN0aXZlQXQiLCJwcmV2aW91c1F1YW50aXR5IiwicmV2aXNpb24iLCJwdXQiLCJ1cGRhdGVkQXQiLCJqb2JJZCIsIlN0cmluZyIsImpvYiIsImF0dGVtcHRzIiwiZGVzaXJlZCIsImV4dHJhU2VhdHMiLCJNYXRoIiwibWF4IiwicHJldmlvdXNFeHRyYVNlYXRzIiwia2luZCIsImxlYXNlRXhwaXJlcyIsIm93bmVyIiwicHJpY2VWZXJzaW9uIiwic2VxdWVuY2UiLCJ2YWxpZGF0ZVNlYXRRdW90ZSIsImNoYW5nZSIsInF1b3RlIiwiY29uZmlybWVkUXVvdGVJZCIsImdldCIsInVzZWQiLCJvcmdhbml6YXRpb25SZXZpc2lvbiIsImV4cGVjdGVkUmV2aXNpb24iLCJyb2xlIiwiZXhwaXJlc0F0IiwiRGF0ZSIsIm5vdyIsInVzZXJJZCIsIkVycm9yIiwiX2tleSIsImNoYW5nZU9yZ2FuaXphdGlvbk1lbWJlciIsImNvbnRleHQiLCJ0cmFuc2FjdGlvbiIsImFjY2VzcyIsIm1lbWJlciIsImluY2x1ZGVzIiwiTnVtYmVyIiwiaXNTYWZlSW50ZWdlciIsIm9yZ2FuaXphdGlvbiIsIm93bmVyVXNlcklkIiwidXNlciIsImFjdGl2ZSIsInZlcmlmaWVkRW1haWwiLCJjb3VudCIsIm5leHRDb3VudCIsImJpbGxpbmciLCJwbGFuIiwidXBkYXRlZCIsInJlcXVlc3RPd25lcnNoaXBUcmFuc2ZlciIsInJlY2lwaWVudFVzZXJJZCIsInJlY2lwaWVudCIsInRyYW5zZmVySWQiLCJhY2NlcHRPd25lcnNoaXBUcmFuc2ZlciIsInRyYW5zZmVyIiwib3JnYW5pemF0aW9uQWNjb3VudCIsImludml0ZU9yZ2FuaXphdGlvbk1lbWJlciIsImVtYWlsIiwiYWNjZXB0c0FkZGl0aW9uYWxTZWF0Q2hhcmdlIiwibm9ybWFsaXplZCIsInRyaW0iLCJ0b0xvd2VyQ2FzZSIsInRlc3QiLCJleGlzdGluZyIsImludml0YXRpb24iLCJyZXZva2VkIiwiaW52aXRhdGlvbklkIiwidG9rZW4iLCJ0b1N0cmluZyIsImludml0ZWRCeSIsInRva2VuSGFzaCIsImFjY2VwdE9yZ2FuaXphdGlvbkludml0YXRpb24iLCJzZXNzaW9uIiwia2V5IiwicHJldmlvdXMiLCJjcmVhdGVkQXQiLCJwcmV2aW91c0NvdW50IiwicmV2b2tlT3JnYW5pemF0aW9uSW52aXRhdGlvbiIsImFzc2VydE9yZ2FuaXphdGlvbkFjY291bnRSZW1vdmFsQWxsb3dlZCIsInJlcGxhY2UiLCJsaXN0T3JnYW5pemF0aW9uTWVtYmVycyJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBUUEsV0FBVyxRQUFPLGNBQWM7QUFFeEMsU0FBUUMsK0JBQStCLEVBQUVDLGtCQUFrQixRQUFPLHFCQUFxQjtBQUN2RixTQUNFQyxpQkFBaUIsRUFDakJDLGVBQWUsRUFDZkMsb0JBQW9CLEVBQ3BCQyxpQkFBaUIsUUFHWixhQUFhO0FBV3BCLE9BQU8sTUFBTUMsb0JBQW9CLE9BQy9CQyxJQUNBQyxpQkFFQSxBQUFDLENBQUEsTUFBTUQsR0FBR0UsSUFBSSxDQUF5QiwyQkFBMkI7UUFBQ0Q7UUFBZ0JFLFFBQVE7SUFBUSxFQUFDLEVBQ2pHQyxNQUFNLENBQUM7QUFFWixPQUFPLE1BQU1DLGtCQUFrQixPQUM3QkwsSUFDQU0sS0FDQUMsVUFDQUMsYUFDQUM7SUFFQSxNQUFNQyxXQUFXSixJQUFJSSxRQUFRLEdBQUc7SUFDaEMsTUFBTVYsR0FBR1csR0FBRyxDQUFDLGlCQUFpQkwsSUFBSUwsY0FBYyxFQUFFO1FBQUMsR0FBR0ssR0FBRztRQUFFSTtRQUFVRSxXQUFXSjtJQUFXLEdBQUdGO0lBQzlGLE1BQU1PLFFBQVFqQixnQkFBZ0JVLElBQUlMLGNBQWMsRUFBRWEsT0FBT0o7SUFDekQsTUFBTUssTUFBa0I7UUFDdEJDLFVBQVU7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
@@ -0,0 +1,9 @@
1
+ import type { ApiContext } from '../types/auth.types.js';
2
+ /** Internal recovery capability. Never exposed through generic profile updates. */
3
+ export declare const organizationPasswordRecovery: (context: ApiContext, userId: string, operation: 'consume' | 'issue', input: Readonly<{
4
+ code: number;
5
+ email?: string;
6
+ expires?: number;
7
+ password?: string;
8
+ phone?: string;
9
+ }>) => Promise<boolean | null>;
@@ -0,0 +1,50 @@
1
+ import { createPassword, parsePassword } from '@nlabs/utils/parsers/strings';
2
+ import { organizationStoreFor } from './store.js';
3
+ /** Internal recovery capability. Never exposed through generic profile updates. */ export const organizationPasswordRecovery = async (context, userId, operation, input)=>{
4
+ if (!process.env.ARANGODB_DATABASE || context.databaseName !== process.env.ARANGODB_DATABASE) {
5
+ return null;
6
+ }
7
+ const key = userId.replace(/^users\//, '');
8
+ return organizationStoreFor(context).transaction(async (tx)=>{
9
+ const user = await tx.get('users', key);
10
+ const memberships = await tx.find('organizationMemberships', {
11
+ userId: key
12
+ });
13
+ const owners = await tx.find('organizations', {
14
+ ownerUserId: key
15
+ });
16
+ if (!user || !user.organizationAccount && !memberships.length && !owners.length) {
17
+ return null;
18
+ }
19
+ const email = Boolean(input.email && user.verifiedEmail && user.email === input.email);
20
+ const phone = Boolean(input.phone && user.verifiedPhone && user.phone === input.phone);
21
+ if (!user.active || !email && !phone || !Number.isSafeInteger(input.code) || input.code < 100000 || input.code > 999999) {
22
+ return false;
23
+ }
24
+ const codeField = phone ? 'verifiedSmsCode' : 'verifiedEmailCode';
25
+ const expiryField = phone ? 'verifiedPhoneExpires' : 'verifiedEmailExpires';
26
+ if (operation === 'issue') {
27
+ if (!Number.isSafeInteger(input.expires) || input.expires <= Date.now() || input.expires > Date.now() + 900000) {
28
+ return false;
29
+ }
30
+ await tx.put('users', key, {
31
+ ...user,
32
+ [codeField]: input.code,
33
+ [expiryField]: input.expires
34
+ }, user);
35
+ return true;
36
+ }
37
+ if (user[codeField] !== input.code || Number(user[expiryField] || 0) <= Date.now() || !input.password || !user.salt) {
38
+ return false;
39
+ }
40
+ await tx.put('users', key, {
41
+ ...user,
42
+ [codeField]: 0,
43
+ [expiryField]: 0,
44
+ password: createPassword(parsePassword(input.password), user.salt)
45
+ }, user);
46
+ return true;
47
+ });
48
+ };
49
+
50
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy9wYXNzd29yZFJlY292ZXJ5LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Y3JlYXRlUGFzc3dvcmQsIHBhcnNlUGFzc3dvcmR9IGZyb20gJ0BubGFicy91dGlscy9wYXJzZXJzL3N0cmluZ3MnO1xuXG5pbXBvcnQge29yZ2FuaXphdGlvblN0b3JlRm9yfSBmcm9tICcuL3N0b3JlLmpzJztcblxuaW1wb3J0IHR5cGUge0FwaUNvbnRleHR9IGZyb20gJy4uL3R5cGVzL2F1dGgudHlwZXMuanMnO1xuaW1wb3J0IHR5cGUge1VzZXJUeXBlfSBmcm9tICcuLi90eXBlcy91c2Vycy50eXBlcy5qcyc7XG5cbi8qKiBJbnRlcm5hbCByZWNvdmVyeSBjYXBhYmlsaXR5LiBOZXZlciBleHBvc2VkIHRocm91Z2ggZ2VuZXJpYyBwcm9maWxlIHVwZGF0ZXMuICovXG5leHBvcnQgY29uc3Qgb3JnYW5pemF0aW9uUGFzc3dvcmRSZWNvdmVyeSA9IGFzeW5jIChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgdXNlcklkOiBzdHJpbmcsXG4gIG9wZXJhdGlvbjogJ2NvbnN1bWUnIHwgJ2lzc3VlJyxcbiAgaW5wdXQ6IFJlYWRvbmx5PHtjb2RlOiBudW1iZXI7IGVtYWlsPzogc3RyaW5nOyBleHBpcmVzPzogbnVtYmVyOyBwYXNzd29yZD86IHN0cmluZzsgcGhvbmU/OiBzdHJpbmd9PlxuKTogUHJvbWlzZTxib29sZWFuIHwgbnVsbD4gPT4ge1xuICBpZighcHJvY2Vzcy5lbnYuQVJBTkdPREJfREFUQUJBU0UgfHwgY29udGV4dC5kYXRhYmFzZU5hbWUgIT09IHByb2Nlc3MuZW52LkFSQU5HT0RCX0RBVEFCQVNFKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgY29uc3Qga2V5ID0gdXNlcklkLnJlcGxhY2UoL151c2Vyc1xcLy8sICcnKTtcbiAgcmV0dXJuIG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0eC5nZXQ8VXNlclR5cGUgJiB7b3JnYW5pemF0aW9uQWNjb3VudD86IGJvb2xlYW59PigndXNlcnMnLCBrZXkpO1xuICAgIGNvbnN0IG1lbWJlcnNoaXBzID0gYXdhaXQgdHguZmluZCgnb3JnYW5pemF0aW9uTWVtYmVyc2hpcHMnLCB7dXNlcklkOiBrZXl9KTtcbiAgICBjb25zdCBvd25lcnMgPSBhd2FpdCB0eC5maW5kKCdvcmdhbml6YXRpb25zJywge293bmVyVXNlcklkOiBrZXl9KTtcbiAgICBpZighdXNlciB8fCAoIXVzZXIub3JnYW5pemF0aW9uQWNjb3VudCAmJiAhbWVtYmVyc2hpcHMubGVuZ3RoICYmICFvd25lcnMubGVuZ3RoKSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGNvbnN0IGVtYWlsID0gQm9vbGVhbihpbnB1dC5lbWFpbCAmJiB1c2VyLnZlcmlmaWVkRW1haWwgJiYgdXNlci5lbWFpbCA9PT0gaW5wdXQuZW1haWwpO1xuICAgIGNvbnN0IHBob25lID0gQm9vbGVhbihpbnB1dC5waG9uZSAmJiB1c2VyLnZlcmlmaWVkUGhvbmUgJiYgdXNlci5waG9uZSA9PT0gaW5wdXQucGhvbmUpO1xuICAgIGlmKCF1c2VyLmFjdGl2ZSB8fCAoIWVtYWlsICYmICFwaG9uZSkgfHwgIU51bWJlci5pc1NhZmVJbnRlZ2VyKGlucHV0LmNvZGUpXG4gICAgICB8fCBpbnB1dC5jb2RlIDwgMTAwMDAwIHx8IGlucHV0LmNvZGUgPiA5OTk5OTkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY29uc3QgY29kZUZpZWxkID0gcGhvbmUgPyAndmVyaWZpZWRTbXNDb2RlJyA6ICd2ZXJpZmllZEVtYWlsQ29kZSc7XG4gICAgY29uc3QgZXhwaXJ5RmllbGQgPSBwaG9uZSA/ICd2ZXJpZmllZFBob25lRXhwaXJlcycgOiAndmVyaWZpZWRFbWFpbEV4cGlyZXMnO1xuICAgIGlmKG9wZXJhdGlvbiA9PT0gJ2lzc3VlJykge1xuICAgICAgaWYoIU51bWJlci5pc1NhZmVJbnRlZ2VyKGlucHV0LmV4cGlyZXMpIHx8IGlucHV0LmV4cGlyZXMhIDw9IERhdGUubm93KCkgfHwgaW5wdXQuZXhwaXJlcyEgPiBEYXRlLm5vdygpICsgOTAwMDAwKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGF3YWl0IHR4LnB1dCgndXNlcnMnLCBrZXksIHsuLi51c2VyLCBbY29kZUZpZWxkXTogaW5wdXQuY29kZSwgW2V4cGlyeUZpZWxkXTogaW5wdXQuZXhwaXJlc30sIHVzZXIpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmKHVzZXJbY29kZUZpZWxkXSAhPT0gaW5wdXQuY29kZSB8fCBOdW1iZXIodXNlcltleHBpcnlGaWVsZF0gfHwgMCkgPD0gRGF0ZS5ub3coKVxuICAgICAgfHwgIWlucHV0LnBhc3N3b3JkIHx8ICF1c2VyLnNhbHQpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgYXdhaXQgdHgucHV0KCd1c2VycycsIGtleSwge1xuICAgICAgLi4udXNlciwgW2NvZGVGaWVsZF06IDAsIFtleHBpcnlGaWVsZF06IDAsIHBhc3N3b3JkOiBjcmVhdGVQYXNzd29yZChwYXJzZVBhc3N3b3JkKGlucHV0LnBhc3N3b3JkKSwgdXNlci5zYWx0KVxuICAgIH0sIHVzZXIpO1xuICAgIHJldHVybiB0cnVlO1xuICB9KTtcbn07XG4iXSwibmFtZXMiOlsiY3JlYXRlUGFzc3dvcmQiLCJwYXJzZVBhc3N3b3JkIiwib3JnYW5pemF0aW9uU3RvcmVGb3IiLCJvcmdhbml6YXRpb25QYXNzd29yZFJlY292ZXJ5IiwiY29udGV4dCIsInVzZXJJZCIsIm9wZXJhdGlvbiIsImlucHV0IiwicHJvY2VzcyIsImVudiIsIkFSQU5HT0RCX0RBVEFCQVNFIiwiZGF0YWJhc2VOYW1lIiwia2V5IiwicmVwbGFjZSIsInRyYW5zYWN0aW9uIiwidHgiLCJ1c2VyIiwiZ2V0IiwibWVtYmVyc2hpcHMiLCJmaW5kIiwib3duZXJzIiwib3duZXJVc2VySWQiLCJvcmdhbml6YXRpb25BY2NvdW50IiwibGVuZ3RoIiwiZW1haWwiLCJCb29sZWFuIiwidmVyaWZpZWRFbWFpbCIsInBob25lIiwidmVyaWZpZWRQaG9uZSIsImFjdGl2ZSIsIk51bWJlciIsImlzU2FmZUludGVnZXIiLCJjb2RlIiwiY29kZUZpZWxkIiwiZXhwaXJ5RmllbGQiLCJleHBpcmVzIiwiRGF0ZSIsIm5vdyIsInB1dCIsInBhc3N3b3JkIiwic2FsdCJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBUUEsY0FBYyxFQUFFQyxhQUFhLFFBQU8sK0JBQStCO0FBRTNFLFNBQVFDLG9CQUFvQixRQUFPLGFBQWE7QUFLaEQsaUZBQWlGLEdBQ2pGLE9BQU8sTUFBTUMsK0JBQStCLE9BQzFDQyxTQUNBQyxRQUNBQyxXQUNBQztJQUVBLElBQUcsQ0FBQ0MsUUFBUUMsR0FBRyxDQUFDQyxpQkFBaUIsSUFBSU4sUUFBUU8sWUFBWSxLQUFLSCxRQUFRQyxHQUFHLENBQUNDLGlCQUFpQixFQUFFO1FBQzNGLE9BQU87SUFDVDtJQUNBLE1BQU1FLE1BQU1QLE9BQU9RLE9BQU8sQ0FBQyxZQUFZO0lBQ3ZDLE9BQU9YLHFCQUFxQkUsU0FBU1UsV0FBVyxDQUFDLE9BQU9DO1FBQ3RELE1BQU1DLE9BQU8sTUFBTUQsR0FBR0UsR0FBRyxDQUE2QyxTQUFTTDtRQUMvRSxNQUFNTSxjQUFjLE1BQU1ILEdBQUdJLElBQUksQ0FBQywyQkFBMkI7WUFBQ2QsUUFBUU87UUFBRztRQUN6RSxNQUFNUSxTQUFTLE1BQU1MLEdBQUdJLElBQUksQ0FBQyxpQkFBaUI7WUFBQ0UsYUFBYVQ7UUFBRztRQUMvRCxJQUFHLENBQUNJLFFBQVMsQ0FBQ0EsS0FBS00sbUJBQW1CLElBQUksQ0FBQ0osWUFBWUssTUFBTSxJQUFJLENBQUNILE9BQU9HLE1BQU0sRUFBRztZQUNoRixPQUFPO1FBQ1Q7UUFDQSxNQUFNQyxRQUFRQyxRQUFRbEIsTUFBTWlCLEtBQUssSUFBSVIsS0FBS1UsYUFBYSxJQUFJVixLQUFLUSxLQUFLLEtBQUtqQixNQUFNaUIsS0FBSztRQUNyRixNQUFNRyxRQUFRRixRQUFRbEIsTUFBTW9CLEtBQUssSUFBSVgsS0FBS1ksYUFBYSxJQUFJWixLQUFLVyxLQUFLLEtBQUtwQixNQUFNb0IsS0FBSztRQUNyRixJQUFHLENBQUNYLEtBQUthLE1BQU0sSUFBSyxDQUFDTCxTQUFTLENBQUNHLFNBQVUsQ0FBQ0csT0FBT0MsYUFBYSxDQUFDeEIsTUFBTXlCLElBQUksS0FDcEV6QixNQUFNeUIsSUFBSSxHQUFHLFVBQVV6QixNQUFNeUIsSUFBSSxHQUFHLFFBQVE7WUFDL0MsT0FBTztRQUNUO1FBQ0EsTUFBTUMsWUFBWU4sUUFBUSxvQkFBb0I7UUFDOUMsTUFBTU8sY0FBY1AsUUFBUSx5QkFBeUI7UUFDckQsSUFBR3JCLGNBQWMsU0FBUztZQUN4QixJQUFHLENBQUN3QixPQUFPQyxhQUFhLENBQUN4QixNQUFNNEIsT0FBTyxLQUFLNUIsTUFBTTRCLE9BQU8sSUFBS0MsS0FBS0MsR0FBRyxNQUFNOUIsTUFBTTRCLE9BQU8sR0FBSUMsS0FBS0MsR0FBRyxLQUFLLFFBQVE7Z0JBQy9HLE9BQU87WUFDVDtZQUNBLE1BQU10QixHQUFHdUIsR0FBRyxDQUFDLFNBQVMxQixLQUFLO2dCQUFDLEdBQUdJLElBQUk7Z0JBQUUsQ0FBQ2lCLFVBQVUsRUFBRTFCLE1BQU15QixJQUFJO2dCQUFFLENBQUNFLFlBQVksRUFBRTNCLE1BQU00QixPQUFPO1lBQUEsR0FBR25CO1lBQzdGLE9BQU87UUFDVDtRQUNBLElBQUdBLElBQUksQ0FBQ2lCLFVBQVUsS0FBSzFCLE1BQU15QixJQUFJLElBQUlGLE9BQU9kLElBQUksQ0FBQ2tCLFlBQVksSUFBSSxNQUFNRSxLQUFLQyxHQUFHLE1BQzFFLENBQUM5QixNQUFNZ0MsUUFBUSxJQUFJLENBQUN2QixLQUFLd0IsSUFBSSxFQUFFO1lBQ2xDLE9BQU87UUFDVDtRQUNBLE1BQU16QixHQUFHdUIsR0FBRyxDQUFDLFNBQVMxQixLQUFLO1lBQ3pCLEdBQUdJLElBQUk7WUFBRSxDQUFDaUIsVUFBVSxFQUFFO1lBQUcsQ0FBQ0MsWUFBWSxFQUFFO1lBQUdLLFVBQVV2QyxlQUFlQyxjQUFjTSxNQUFNZ0MsUUFBUSxHQUFHdkIsS0FBS3dCLElBQUk7UUFDOUcsR0FBR3hCO1FBQ0gsT0FBTztJQUNUO0FBQ0YsRUFBRSJ9
@@ -0,0 +1,6 @@
1
+ import type { OrganizationPlan, PlanKey } from './types.js';
2
+ export declare const getOrganizationPlan: (plan: PlanKey) => OrganizationPlan;
3
+ export declare const calculateSeatCharge: (plan: PlanKey, activeMembers: number) => {
4
+ extraSeats: number;
5
+ monthlyCents: number;
6
+ };
@@ -0,0 +1,40 @@
1
+ const catalog = Object.freeze({
2
+ pro: Object.freeze({
3
+ additionalSeatCents: 800,
4
+ baseCents: 14900,
5
+ currency: 'usd',
6
+ includedSeats: 10,
7
+ interval: 'month',
8
+ key: 'pro',
9
+ version: '2026-10-v1'
10
+ }),
11
+ starter: Object.freeze({
12
+ additionalSeatCents: 800,
13
+ baseCents: 4900,
14
+ currency: 'usd',
15
+ includedSeats: 10,
16
+ interval: 'month',
17
+ key: 'starter',
18
+ version: '2026-10-v1'
19
+ })
20
+ });
21
+ export const getOrganizationPlan = (plan)=>{
22
+ if (plan !== 'starter' && plan !== 'pro') {
23
+ throw new Error('invalid_plan');
24
+ }
25
+ return catalog[plan];
26
+ };
27
+ export const calculateSeatCharge = (plan, activeMembers)=>{
28
+ const config = getOrganizationPlan(plan);
29
+ const extraSeats = Math.max(0, activeMembers - config.includedSeats);
30
+ const monthlyCents = config.baseCents + extraSeats * config.additionalSeatCents;
31
+ if (!Number.isSafeInteger(activeMembers) || activeMembers < 0 || !Number.isSafeInteger(monthlyCents)) {
32
+ throw new Error('invalid_member_count');
33
+ }
34
+ return {
35
+ extraSeats,
36
+ monthlyCents
37
+ };
38
+ };
39
+
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy9wbGFucy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7T3JnYW5pemF0aW9uUGxhbiwgUGxhbktleX0gZnJvbSAnLi90eXBlcy5qcyc7XG5cbmNvbnN0IGNhdGFsb2c6IFJlYWRvbmx5PFJlY29yZDxQbGFuS2V5LCBPcmdhbml6YXRpb25QbGFuPj4gPSBPYmplY3QuZnJlZXplKHtcbiAgcHJvOiBPYmplY3QuZnJlZXplKHtcbiAgICBhZGRpdGlvbmFsU2VhdENlbnRzOiA4MDAsXG4gICAgYmFzZUNlbnRzOiAxNDkwMCxcbiAgICBjdXJyZW5jeTogJ3VzZCcsXG4gICAgaW5jbHVkZWRTZWF0czogMTAsXG4gICAgaW50ZXJ2YWw6ICdtb250aCcsXG4gICAga2V5OiAncHJvJyxcbiAgICB2ZXJzaW9uOiAnMjAyNi0xMC12MSdcbiAgfSksXG4gIHN0YXJ0ZXI6IE9iamVjdC5mcmVlemUoe1xuICAgIGFkZGl0aW9uYWxTZWF0Q2VudHM6IDgwMCxcbiAgICBiYXNlQ2VudHM6IDQ5MDAsXG4gICAgY3VycmVuY3k6ICd1c2QnLFxuICAgIGluY2x1ZGVkU2VhdHM6IDEwLFxuICAgIGludGVydmFsOiAnbW9udGgnLFxuICAgIGtleTogJ3N0YXJ0ZXInLFxuICAgIHZlcnNpb246ICcyMDI2LTEwLXYxJ1xuICB9KVxufSk7XG5cbmV4cG9ydCBjb25zdCBnZXRPcmdhbml6YXRpb25QbGFuID0gKHBsYW46IFBsYW5LZXkpOiBPcmdhbml6YXRpb25QbGFuID0+IHtcbiAgaWYocGxhbiAhPT0gJ3N0YXJ0ZXInICYmIHBsYW4gIT09ICdwcm8nKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkX3BsYW4nKTtcbiAgfVxuICByZXR1cm4gY2F0YWxvZ1twbGFuXTtcbn07XG5cbmV4cG9ydCBjb25zdCBjYWxjdWxhdGVTZWF0Q2hhcmdlID0gKFxuICBwbGFuOiBQbGFuS2V5LFxuICBhY3RpdmVNZW1iZXJzOiBudW1iZXJcbik6IHtleHRyYVNlYXRzOiBudW1iZXI7IG1vbnRobHlDZW50czogbnVtYmVyfSA9PiB7XG4gIGNvbnN0IGNvbmZpZyA9IGdldE9yZ2FuaXphdGlvblBsYW4ocGxhbik7XG4gIGNvbnN0IGV4dHJhU2VhdHMgPSBNYXRoLm1heCgwLCBhY3RpdmVNZW1iZXJzIC0gY29uZmlnLmluY2x1ZGVkU2VhdHMpO1xuICBjb25zdCBtb250aGx5Q2VudHMgPSBjb25maWcuYmFzZUNlbnRzICsgKGV4dHJhU2VhdHMgKiBjb25maWcuYWRkaXRpb25hbFNlYXRDZW50cyk7XG4gIGlmKCFOdW1iZXIuaXNTYWZlSW50ZWdlcihhY3RpdmVNZW1iZXJzKSB8fCBhY3RpdmVNZW1iZXJzIDwgMCB8fCAhTnVtYmVyLmlzU2FmZUludGVnZXIobW9udGhseUNlbnRzKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZF9tZW1iZXJfY291bnQnKTtcbiAgfVxuICByZXR1cm4ge2V4dHJhU2VhdHMsIG1vbnRobHlDZW50c307XG59O1xuIl0sIm5hbWVzIjpbImNhdGFsb2ciLCJPYmplY3QiLCJmcmVlemUiLCJwcm8iLCJhZGRpdGlvbmFsU2VhdENlbnRzIiwiYmFzZUNlbnRzIiwiY3VycmVuY3kiLCJpbmNsdWRlZFNlYXRzIiwiaW50ZXJ2YWwiLCJrZXkiLCJ2ZXJzaW9uIiwic3RhcnRlciIsImdldE9yZ2FuaXphdGlvblBsYW4iLCJwbGFuIiwiRXJyb3IiLCJjYWxjdWxhdGVTZWF0Q2hhcmdlIiwiYWN0aXZlTWVtYmVycyIsImNvbmZpZyIsImV4dHJhU2VhdHMiLCJNYXRoIiwibWF4IiwibW9udGhseUNlbnRzIiwiTnVtYmVyIiwiaXNTYWZlSW50ZWdlciJdLCJtYXBwaW5ncyI6IkFBRUEsTUFBTUEsVUFBdURDLE9BQU9DLE1BQU0sQ0FBQztJQUN6RUMsS0FBS0YsT0FBT0MsTUFBTSxDQUFDO1FBQ2pCRSxxQkFBcUI7UUFDckJDLFdBQVc7UUFDWEMsVUFBVTtRQUNWQyxlQUFlO1FBQ2ZDLFVBQVU7UUFDVkMsS0FBSztRQUNMQyxTQUFTO0lBQ1g7SUFDQUMsU0FBU1YsT0FBT0MsTUFBTSxDQUFDO1FBQ3JCRSxxQkFBcUI7UUFDckJDLFdBQVc7UUFDWEMsVUFBVTtRQUNWQyxlQUFlO1FBQ2ZDLFVBQVU7UUFDVkMsS0FBSztRQUNMQyxTQUFTO0lBQ1g7QUFDRjtBQUVBLE9BQU8sTUFBTUUsc0JBQXNCLENBQUNDO0lBQ2xDLElBQUdBLFNBQVMsYUFBYUEsU0FBUyxPQUFPO1FBQ3ZDLE1BQU0sSUFBSUMsTUFBTTtJQUNsQjtJQUNBLE9BQU9kLE9BQU8sQ0FBQ2EsS0FBSztBQUN0QixFQUFFO0FBRUYsT0FBTyxNQUFNRSxzQkFBc0IsQ0FDakNGLE1BQ0FHO0lBRUEsTUFBTUMsU0FBU0wsb0JBQW9CQztJQUNuQyxNQUFNSyxhQUFhQyxLQUFLQyxHQUFHLENBQUMsR0FBR0osZ0JBQWdCQyxPQUFPVixhQUFhO0lBQ25FLE1BQU1jLGVBQWVKLE9BQU9aLFNBQVMsR0FBSWEsYUFBYUQsT0FBT2IsbUJBQW1CO0lBQ2hGLElBQUcsQ0FBQ2tCLE9BQU9DLGFBQWEsQ0FBQ1Asa0JBQWtCQSxnQkFBZ0IsS0FBSyxDQUFDTSxPQUFPQyxhQUFhLENBQUNGLGVBQWU7UUFDbkcsTUFBTSxJQUFJUCxNQUFNO0lBQ2xCO0lBQ0EsT0FBTztRQUFDSTtRQUFZRztJQUFZO0FBQ2xDLEVBQUUifQ==
@@ -0,0 +1,6 @@
1
+ export declare const listAllProviderRecords: <T extends {
2
+ id: string;
3
+ }>(load: (after?: string) => Promise<{
4
+ data: T[];
5
+ has_more: boolean;
6
+ }>) => Promise<T[]>;
@@ -0,0 +1,23 @@
1
+ /* Each provider page requires the previous page's cursor; incomplete recovery must fail closed. */ /* eslint-disable no-await-in-loop */ export const listAllProviderRecords = async (load)=>{
2
+ let after;
3
+ const records = [];
4
+ const seen = new Set();
5
+ for(let page = 0; page < 100; page++){
6
+ const response = await load(after);
7
+ if (response.data.some((record)=>seen.has(record.id)) || new Set(response.data.map((record)=>record.id)).size !== response.data.length) {
8
+ throw new Error('billing_lookup_incomplete');
9
+ }
10
+ response.data.forEach((record)=>seen.add(record.id));
11
+ records.push(...response.data);
12
+ if (!response.has_more) {
13
+ return records;
14
+ }
15
+ if (!response.data.length) {
16
+ throw new Error('billing_lookup_incomplete');
17
+ }
18
+ after = response.data.at(-1).id;
19
+ }
20
+ throw new Error('billing_lookup_incomplete');
21
+ };
22
+
23
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy9wcm92aWRlclBhZ2luYXRpb24udHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyogRWFjaCBwcm92aWRlciBwYWdlIHJlcXVpcmVzIHRoZSBwcmV2aW91cyBwYWdlJ3MgY3Vyc29yOyBpbmNvbXBsZXRlIHJlY292ZXJ5IG11c3QgZmFpbCBjbG9zZWQuICovXG4vKiBlc2xpbnQtZGlzYWJsZSBuby1hd2FpdC1pbi1sb29wICovXG5leHBvcnQgY29uc3QgbGlzdEFsbFByb3ZpZGVyUmVjb3JkcyA9IGFzeW5jIDxUIGV4dGVuZHMge2lkOiBzdHJpbmd9PihcbiAgbG9hZDogKGFmdGVyPzogc3RyaW5nKSA9PiBQcm9taXNlPHtkYXRhOiBUW107IGhhc19tb3JlOiBib29sZWFufT5cbik6IFByb21pc2U8VFtdPiA9PiB7XG4gIGxldCBhZnRlcjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBjb25zdCByZWNvcmRzOiBUW10gPSBbXTtcbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBmb3IobGV0IHBhZ2UgPSAwOyBwYWdlIDwgMTAwOyBwYWdlKyspIHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGxvYWQoYWZ0ZXIpO1xuICAgIGlmKHJlc3BvbnNlLmRhdGEuc29tZSgocmVjb3JkKSA9PiBzZWVuLmhhcyhyZWNvcmQuaWQpKVxuICAgICAgfHwgbmV3IFNldChyZXNwb25zZS5kYXRhLm1hcCgocmVjb3JkKSA9PiByZWNvcmQuaWQpKS5zaXplICE9PSByZXNwb25zZS5kYXRhLmxlbmd0aCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdiaWxsaW5nX2xvb2t1cF9pbmNvbXBsZXRlJyk7XG4gICAgfVxuICAgIHJlc3BvbnNlLmRhdGEuZm9yRWFjaCgocmVjb3JkKSA9PiBzZWVuLmFkZChyZWNvcmQuaWQpKTtcbiAgICByZWNvcmRzLnB1c2goLi4ucmVzcG9uc2UuZGF0YSk7XG4gICAgaWYoIXJlc3BvbnNlLmhhc19tb3JlKSB7XG4gICAgICByZXR1cm4gcmVjb3JkcztcbiAgICB9XG4gICAgaWYoIXJlc3BvbnNlLmRhdGEubGVuZ3RoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2JpbGxpbmdfbG9va3VwX2luY29tcGxldGUnKTtcbiAgICB9XG4gICAgYWZ0ZXIgPSByZXNwb25zZS5kYXRhLmF0KC0xKSEuaWQ7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKCdiaWxsaW5nX2xvb2t1cF9pbmNvbXBsZXRlJyk7XG59O1xuIl0sIm5hbWVzIjpbImxpc3RBbGxQcm92aWRlclJlY29yZHMiLCJsb2FkIiwiYWZ0ZXIiLCJyZWNvcmRzIiwic2VlbiIsIlNldCIsInBhZ2UiLCJyZXNwb25zZSIsImRhdGEiLCJzb21lIiwicmVjb3JkIiwiaGFzIiwiaWQiLCJtYXAiLCJzaXplIiwibGVuZ3RoIiwiRXJyb3IiLCJmb3JFYWNoIiwiYWRkIiwicHVzaCIsImhhc19tb3JlIiwiYXQiXSwibWFwcGluZ3MiOiJBQUFBLGlHQUFpRyxHQUNqRyxtQ0FBbUMsR0FDbkMsT0FBTyxNQUFNQSx5QkFBeUIsT0FDcENDO0lBRUEsSUFBSUM7SUFDSixNQUFNQyxVQUFlLEVBQUU7SUFDdkIsTUFBTUMsT0FBTyxJQUFJQztJQUNqQixJQUFJLElBQUlDLE9BQU8sR0FBR0EsT0FBTyxLQUFLQSxPQUFRO1FBQ3BDLE1BQU1DLFdBQVcsTUFBTU4sS0FBS0M7UUFDNUIsSUFBR0ssU0FBU0MsSUFBSSxDQUFDQyxJQUFJLENBQUMsQ0FBQ0MsU0FBV04sS0FBS08sR0FBRyxDQUFDRCxPQUFPRSxFQUFFLE1BQy9DLElBQUlQLElBQUlFLFNBQVNDLElBQUksQ0FBQ0ssR0FBRyxDQUFDLENBQUNILFNBQVdBLE9BQU9FLEVBQUUsR0FBR0UsSUFBSSxLQUFLUCxTQUFTQyxJQUFJLENBQUNPLE1BQU0sRUFBRTtZQUNwRixNQUFNLElBQUlDLE1BQU07UUFDbEI7UUFDQVQsU0FBU0MsSUFBSSxDQUFDUyxPQUFPLENBQUMsQ0FBQ1AsU0FBV04sS0FBS2MsR0FBRyxDQUFDUixPQUFPRSxFQUFFO1FBQ3BEVCxRQUFRZ0IsSUFBSSxJQUFJWixTQUFTQyxJQUFJO1FBQzdCLElBQUcsQ0FBQ0QsU0FBU2EsUUFBUSxFQUFFO1lBQ3JCLE9BQU9qQjtRQUNUO1FBQ0EsSUFBRyxDQUFDSSxTQUFTQyxJQUFJLENBQUNPLE1BQU0sRUFBRTtZQUN4QixNQUFNLElBQUlDLE1BQU07UUFDbEI7UUFDQWQsUUFBUUssU0FBU0MsSUFBSSxDQUFDYSxFQUFFLENBQUMsQ0FBQyxHQUFJVCxFQUFFO0lBQ2xDO0lBQ0EsTUFBTSxJQUFJSSxNQUFNO0FBQ2xCLEVBQUUifQ==
@@ -0,0 +1,11 @@
1
+ import type { ApiContext } from '../types/auth.types.js';
2
+ import type { OveragePreference, PlanKey, SeatChangeQuote, SubscriptionSummary, VerifiedBillingEvent } from './types.js';
3
+ export declare const reconcileOrganizationBillingEvent: (context: ApiContext, event: VerifiedBillingEvent) => Promise<void>;
4
+ export declare const processOrganizationBillingJobs: (context: ApiContext, limit: number) => Promise<{
5
+ completed: number;
6
+ pending: number;
7
+ }>;
8
+ export declare const quoteOrganizationPlanChange: (context: ApiContext, organizationId: string, plan: PlanKey) => Promise<SeatChangeQuote>;
9
+ export declare const changeOrganizationPlan: (context: ApiContext, organizationId: string, plan: PlanKey, confirmedQuoteId: string) => Promise<SubscriptionSummary>;
10
+ export declare const cancelOrganizationSubscription: (context: ApiContext, organizationId: string) => Promise<SubscriptionSummary>;
11
+ export declare const setOrganizationOveragePreference: (context: ApiContext, organizationId: string, preference: OveragePreference) => Promise<SubscriptionSummary>;