@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.
- package/README.md +186 -0
- package/docs/ASSISTANT.md +138 -0
- package/docs/GENERATION.md +29 -2
- package/docs/NATIVE_PUSH.md +56 -0
- package/lib/actions/alfredFaq.d.ts +80 -0
- package/lib/actions/alfredFaq.js +206 -0
- package/lib/actions/contentGeneration.d.ts +4 -1
- package/lib/actions/contentGeneration.js +83 -27
- package/lib/actions/contentGenerationErrors.js +1 -1
- package/lib/actions/conversations.d.ts +1 -1
- package/lib/actions/conversations.js +19 -9
- package/lib/actions/crud.js +26 -1
- package/lib/actions/index.d.ts +2 -0
- package/lib/actions/index.js +3 -1
- package/lib/actions/messages.js +23 -7
- package/lib/actions/phoneSupport.d.ts +18 -0
- package/lib/actions/phoneSupport.js +170 -0
- package/lib/actions/users.js +57 -4
- package/lib/assistant/core.d.ts +53 -0
- package/lib/assistant/core.js +123 -0
- package/lib/assistant/faq.d.ts +26 -0
- package/lib/assistant/faq.js +238 -0
- package/lib/assistant/faqCore.d.ts +23 -0
- package/lib/assistant/faqCore.js +20 -0
- package/lib/assistant/index.d.ts +7 -0
- package/lib/assistant/index.js +5 -0
- package/lib/assistant/service.d.ts +35 -0
- package/lib/assistant/service.js +201 -0
- package/lib/config.js +3 -2
- package/lib/durableChat/conversations.d.ts +62 -0
- package/lib/durableChat/conversations.js +729 -0
- package/lib/durableChat/errors.d.ts +6 -0
- package/lib/durableChat/errors.js +11 -0
- package/lib/durableChat/events.d.ts +22 -0
- package/lib/durableChat/events.js +50 -0
- package/lib/durableChat/index.d.ts +8 -0
- package/lib/durableChat/index.js +10 -0
- package/lib/durableChat/membership.d.ts +24 -0
- package/lib/durableChat/membership.js +85 -0
- package/lib/durableChat/messageTypes.d.ts +76 -0
- package/lib/durableChat/messageTypes.js +3 -0
- package/lib/durableChat/messages.d.ts +16 -0
- package/lib/durableChat/messages.js +257 -0
- package/lib/durableChat/transaction.d.ts +10 -0
- package/lib/durableChat/transaction.js +53 -0
- package/lib/durableChat/types.d.ts +81 -0
- package/lib/durableChat/types.js +3 -0
- package/lib/index.d.ts +4 -4
- package/lib/index.js +5 -3
- package/lib/lambdas/actions/websockets.js +4 -4
- package/lib/nativePush/graphql.d.ts +14 -0
- package/lib/nativePush/graphql.js +105 -0
- package/lib/nativePush/index.d.ts +7 -0
- package/lib/nativePush/index.js +9 -0
- package/lib/nativePush/migrations.d.ts +2 -0
- package/lib/nativePush/migrations.js +36 -0
- package/lib/nativePush/nativePushContract.fixture.d.ts +22 -0
- package/lib/nativePush/nativePushContract.fixture.js +27 -0
- package/lib/nativePush/payload.d.ts +2 -0
- package/lib/nativePush/payload.js +106 -0
- package/lib/nativePush/repository.d.ts +9 -0
- package/lib/nativePush/repository.js +120 -0
- package/lib/nativePush/service.d.ts +2 -0
- package/lib/nativePush/service.js +110 -0
- package/lib/nativePush/snsProvider.d.ts +17 -0
- package/lib/nativePush/snsProvider.js +165 -0
- package/lib/nativePush/types.d.ts +89 -0
- package/lib/nativePush/types.js +3 -0
- package/lib/organizations/accountLifecycle.d.ts +7 -0
- package/lib/organizations/accountLifecycle.js +106 -0
- package/lib/organizations/authorization.d.ts +9 -0
- package/lib/organizations/authorization.js +40 -0
- package/lib/organizations/billing.d.ts +38 -0
- package/lib/organizations/billing.js +277 -0
- package/lib/organizations/billingProvider.d.ts +4 -0
- package/lib/organizations/billingProvider.js +287 -0
- package/lib/organizations/billingUpdates.d.ts +9 -0
- package/lib/organizations/billingUpdates.js +388 -0
- package/lib/organizations/index.d.ts +10 -0
- package/lib/organizations/index.js +12 -0
- package/lib/organizations/mail.d.ts +10 -0
- package/lib/organizations/mail.js +60 -0
- package/lib/organizations/memberDirectory.d.ts +15 -0
- package/lib/organizations/memberDirectory.js +28 -0
- package/lib/organizations/membership.d.ts +19 -0
- package/lib/organizations/membership.js +248 -0
- package/lib/organizations/passwordRecovery.d.ts +9 -0
- package/lib/organizations/passwordRecovery.js +50 -0
- package/lib/organizations/plans.d.ts +6 -0
- package/lib/organizations/plans.js +40 -0
- package/lib/organizations/providerPagination.d.ts +6 -0
- package/lib/organizations/providerPagination.js +23 -0
- package/lib/organizations/reconciliation.d.ts +11 -0
- package/lib/organizations/reconciliation.js +400 -0
- package/lib/organizations/signup.d.ts +25 -0
- package/lib/organizations/signup.js +169 -0
- package/lib/organizations/store.d.ts +25 -0
- package/lib/organizations/store.js +167 -0
- package/lib/organizations/types.d.ts +138 -0
- package/lib/organizations/types.js +3 -0
- package/lib/organizations/verification.d.ts +3 -0
- package/lib/organizations/verification.js +51 -0
- 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,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>;
|