@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,40 @@
|
|
|
1
|
+
/* Stream-transaction steps and ordered retry assertions must execute sequentially. */ /* eslint-disable no-await-in-loop */ import { organizationKey, organizationStoreFor, requireIdentifier } from './store.js';
|
|
2
|
+
export const organizationUserId = (context)=>{
|
|
3
|
+
if (!context.session?.userId) {
|
|
4
|
+
throw new Error('authentication_required');
|
|
5
|
+
}
|
|
6
|
+
return requireIdentifier(context.session.userId.replace(/^users\//, ''));
|
|
7
|
+
};
|
|
8
|
+
export const organizationAccessInTransaction = async (tx, context, organizationId, role)=>{
|
|
9
|
+
const userId = organizationUserId(context);
|
|
10
|
+
const organization = await tx.get('organizations', requireIdentifier(organizationId));
|
|
11
|
+
const membership = await tx.get('organizationMemberships', organizationKey(organizationId, userId));
|
|
12
|
+
const user = await tx.get('users', userId);
|
|
13
|
+
if (!organization || !membership || membership.status !== 'active' || user?.active !== true || role === 'admin' && membership.role !== 'admin' || role === 'owner' && organization.ownerUserId !== userId) {
|
|
14
|
+
throw new Error('organization_access_denied');
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
membership,
|
|
18
|
+
organization,
|
|
19
|
+
userId
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export const requireOrganizationAccess = (context, organizationId, role)=>organizationStoreFor(context).transaction((tx)=>organizationAccessInTransaction(tx, context, organizationId, role));
|
|
23
|
+
export const listOrganizations = (context)=>organizationStoreFor(context).transaction(async (tx)=>{
|
|
24
|
+
const userId = organizationUserId(context);
|
|
25
|
+
const memberships = await tx.find('organizationMemberships', {
|
|
26
|
+
status: 'active',
|
|
27
|
+
userId
|
|
28
|
+
});
|
|
29
|
+
const result = [];
|
|
30
|
+
for (const membership of memberships){
|
|
31
|
+
const access = await organizationAccessInTransaction(tx, context, membership.organizationId, 'member');
|
|
32
|
+
result.push({
|
|
33
|
+
...access.organization,
|
|
34
|
+
canManage: access.membership.role === 'admin'
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}); /* Stream-transaction steps and ordered retry assertions must execute sequentially. */ /* ArangoDB document metadata uses these reserved field names. */ /* eslint no-underscore-dangle: ["warn", {"allow": ["_key", "_rev", "_id"]}] */
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy9hdXRob3JpemF0aW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIFN0cmVhbS10cmFuc2FjdGlvbiBzdGVwcyBhbmQgb3JkZXJlZCByZXRyeSBhc3NlcnRpb25zIG11c3QgZXhlY3V0ZSBzZXF1ZW50aWFsbHkuICovXG4vKiBlc2xpbnQtZGlzYWJsZSBuby1hd2FpdC1pbi1sb29wICovXG5pbXBvcnQge1xuICBvcmdhbml6YXRpb25LZXksXG4gIG9yZ2FuaXphdGlvblN0b3JlRm9yLFxuICByZXF1aXJlSWRlbnRpZmllcixcbiAgdHlwZSBPcmdhbml6YXRpb25UcmFuc2FjdGlvblxufSBmcm9tICcuL3N0b3JlLmpzJztcblxuaW1wb3J0IHR5cGUge0FwaUNvbnRleHR9IGZyb20gJy4uL3R5cGVzL2F1dGgudHlwZXMuanMnO1xuaW1wb3J0IHR5cGUge09yZ2FuaXphdGlvbiwgT3JnYW5pemF0aW9uQWNjZXNzLCBPcmdhbml6YXRpb25NZW1iZXJzaGlwfSBmcm9tICcuL3R5cGVzLmpzJztcblxuZXhwb3J0IGNvbnN0IG9yZ2FuaXphdGlvblVzZXJJZCA9IChjb250ZXh0OiBBcGlDb250ZXh0KTogc3RyaW5nID0+IHtcbiAgaWYoIWNvbnRleHQuc2Vzc2lvbj8udXNlcklkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdhdXRoZW50aWNhdGlvbl9yZXF1aXJlZCcpO1xuICB9XG4gIHJldHVybiByZXF1aXJlSWRlbnRpZmllcihjb250ZXh0LnNlc3Npb24udXNlcklkLnJlcGxhY2UoL151c2Vyc1xcLy8sICcnKSk7XG59O1xuXG5leHBvcnQgY29uc3Qgb3JnYW5pemF0aW9uQWNjZXNzSW5UcmFuc2FjdGlvbiA9IGFzeW5jIChcbiAgdHg6IE9yZ2FuaXphdGlvblRyYW5zYWN0aW9uLFxuICBjb250ZXh0OiBBcGlDb250ZXh0LFxuICBvcmdhbml6YXRpb25JZDogc3RyaW5nLFxuICByb2xlOiAnbWVtYmVyJyB8ICdhZG1pbicgfCAnb3duZXInXG4pOiBQcm9taXNlPE9yZ2FuaXphdGlvbkFjY2Vzcz4gPT4ge1xuICBjb25zdCB1c2VySWQgPSBvcmdhbml6YXRpb25Vc2VySWQoY29udGV4dCk7XG4gIGNvbnN0IG9yZ2FuaXphdGlvbiA9IGF3YWl0IHR4LmdldDxPcmdhbml6YXRpb24+KCdvcmdhbml6YXRpb25zJywgcmVxdWlyZUlkZW50aWZpZXIob3JnYW5pemF0aW9uSWQpKTtcbiAgY29uc3QgbWVtYmVyc2hpcCA9IGF3YWl0IHR4LmdldDxPcmdhbml6YXRpb25NZW1iZXJzaGlwPihcbiAgICAnb3JnYW5pemF0aW9uTWVtYmVyc2hpcHMnLFxuICAgIG9yZ2FuaXphdGlvbktleShvcmdhbml6YXRpb25JZCwgdXNlcklkKVxuICApO1xuICBjb25zdCB1c2VyID0gYXdhaXQgdHguZ2V0PHthY3RpdmU/OiBib29sZWFufT4oJ3VzZXJzJywgdXNlcklkKTtcbiAgaWYoXG4gICAgIW9yZ2FuaXphdGlvbiB8fFxuICAgICFtZW1iZXJzaGlwIHx8XG4gICAgbWVtYmVyc2hpcC5zdGF0dXMgIT09ICdhY3RpdmUnIHx8XG4gICAgdXNlcj8uYWN0aXZlICE9PSB0cnVlIHx8XG4gICAgKHJvbGUgPT09ICdhZG1pbicgJiYgbWVtYmVyc2hpcC5yb2xlICE9PSAnYWRtaW4nKSB8fFxuICAgIChyb2xlID09PSAnb3duZXInICYmIG9yZ2FuaXphdGlvbi5vd25lclVzZXJJZCAhPT0gdXNlcklkKVxuICApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ29yZ2FuaXphdGlvbl9hY2Nlc3NfZGVuaWVkJyk7XG4gIH1cbiAgcmV0dXJuIHttZW1iZXJzaGlwLCBvcmdhbml6YXRpb24sIHVzZXJJZH07XG59O1xuXG5leHBvcnQgY29uc3QgcmVxdWlyZU9yZ2FuaXphdGlvbkFjY2VzcyA9IChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZyxcbiAgcm9sZTogJ21lbWJlcicgfCAnYWRtaW4nIHwgJ293bmVyJ1xuKTogUHJvbWlzZTxPcmdhbml6YXRpb25BY2Nlc3M+ID0+XG4gIG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKCh0eCkgPT5cbiAgICBvcmdhbml6YXRpb25BY2Nlc3NJblRyYW5zYWN0aW9uKHR4LCBjb250ZXh0LCBvcmdhbml6YXRpb25JZCwgcm9sZSlcbiAgKTtcblxuZXhwb3J0IGNvbnN0IGxpc3RPcmdhbml6YXRpb25zID0gKGNvbnRleHQ6IEFwaUNvbnRleHQpOiBQcm9taXNlPChPcmdhbml6YXRpb24gJiB7Y2FuTWFuYWdlOiBib29sZWFufSlbXT4gPT5cbiAgb3JnYW5pemF0aW9uU3RvcmVGb3IoY29udGV4dCkudHJhbnNhY3Rpb24oYXN5bmMgKHR4KSA9PiB7XG4gICAgY29uc3QgdXNlcklkID0gb3JnYW5pemF0aW9uVXNlcklkKGNvbnRleHQpO1xuICAgIGNvbnN0IG1lbWJlcnNoaXBzID0gYXdhaXQgdHguZmluZDxPcmdhbml6YXRpb25NZW1iZXJzaGlwPignb3JnYW5pemF0aW9uTWVtYmVyc2hpcHMnLCB7XG4gICAgICBzdGF0dXM6ICdhY3RpdmUnLFxuICAgICAgdXNlcklkXG4gICAgfSk7XG4gICAgY29uc3QgcmVzdWx0OiAoT3JnYW5pemF0aW9uICYge2Nhbk1hbmFnZTogYm9vbGVhbn0pW10gPSBbXTtcbiAgICBmb3IoY29uc3QgbWVtYmVyc2hpcCBvZiBtZW1iZXJzaGlwcykge1xuICAgICAgY29uc3QgYWNjZXNzID0gYXdhaXQgb3JnYW5pemF0aW9uQWNjZXNzSW5UcmFuc2FjdGlvbih0eCwgY29udGV4dCwgbWVtYmVyc2hpcC5vcmdhbml6YXRpb25JZCwgJ21lbWJlcicpO1xuICAgICAgcmVzdWx0LnB1c2goey4uLmFjY2Vzcy5vcmdhbml6YXRpb24sIGNhbk1hbmFnZTogYWNjZXNzLm1lbWJlcnNoaXAucm9sZSA9PT0gJ2FkbWluJ30pO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9KTtcbi8qIFN0cmVhbS10cmFuc2FjdGlvbiBzdGVwcyBhbmQgb3JkZXJlZCByZXRyeSBhc3NlcnRpb25zIG11c3QgZXhlY3V0ZSBzZXF1ZW50aWFsbHkuICovXG5cbi8qIEFyYW5nb0RCIGRvY3VtZW50IG1ldGFkYXRhIHVzZXMgdGhlc2UgcmVzZXJ2ZWQgZmllbGQgbmFtZXMuICovXG4vKiBlc2xpbnQgbm8tdW5kZXJzY29yZS1kYW5nbGU6IFtcIndhcm5cIiwge1wiYWxsb3dcIjogW1wiX2tleVwiLCBcIl9yZXZcIiwgXCJfaWRcIl19XSAqL1xuIl0sIm5hbWVzIjpbIm9yZ2FuaXphdGlvbktleSIsIm9yZ2FuaXphdGlvblN0b3JlRm9yIiwicmVxdWlyZUlkZW50aWZpZXIiLCJvcmdhbml6YXRpb25Vc2VySWQiLCJjb250ZXh0Iiwic2Vzc2lvbiIsInVzZXJJZCIsIkVycm9yIiwicmVwbGFjZSIsIm9yZ2FuaXphdGlvbkFjY2Vzc0luVHJhbnNhY3Rpb24iLCJ0eCIsIm9yZ2FuaXphdGlvbklkIiwicm9sZSIsIm9yZ2FuaXphdGlvbiIsImdldCIsIm1lbWJlcnNoaXAiLCJ1c2VyIiwic3RhdHVzIiwiYWN0aXZlIiwib3duZXJVc2VySWQiLCJyZXF1aXJlT3JnYW5pemF0aW9uQWNjZXNzIiwidHJhbnNhY3Rpb24iLCJsaXN0T3JnYW5pemF0aW9ucyIsIm1lbWJlcnNoaXBzIiwiZmluZCIsInJlc3VsdCIsImFjY2VzcyIsInB1c2giLCJjYW5NYW5hZ2UiXSwibWFwcGluZ3MiOiJBQUFBLG9GQUFvRixHQUNwRixtQ0FBbUMsR0FDbkMsU0FDRUEsZUFBZSxFQUNmQyxvQkFBb0IsRUFDcEJDLGlCQUFpQixRQUVaLGFBQWE7QUFLcEIsT0FBTyxNQUFNQyxxQkFBcUIsQ0FBQ0M7SUFDakMsSUFBRyxDQUFDQSxRQUFRQyxPQUFPLEVBQUVDLFFBQVE7UUFDM0IsTUFBTSxJQUFJQyxNQUFNO0lBQ2xCO0lBQ0EsT0FBT0wsa0JBQWtCRSxRQUFRQyxPQUFPLENBQUNDLE1BQU0sQ0FBQ0UsT0FBTyxDQUFDLFlBQVk7QUFDdEUsRUFBRTtBQUVGLE9BQU8sTUFBTUMsa0NBQWtDLE9BQzdDQyxJQUNBTixTQUNBTyxnQkFDQUM7SUFFQSxNQUFNTixTQUFTSCxtQkFBbUJDO0lBQ2xDLE1BQU1TLGVBQWUsTUFBTUgsR0FBR0ksR0FBRyxDQUFlLGlCQUFpQlosa0JBQWtCUztJQUNuRixNQUFNSSxhQUFhLE1BQU1MLEdBQUdJLEdBQUcsQ0FDN0IsMkJBQ0FkLGdCQUFnQlcsZ0JBQWdCTDtJQUVsQyxNQUFNVSxPQUFPLE1BQU1OLEdBQUdJLEdBQUcsQ0FBcUIsU0FBU1I7SUFDdkQsSUFDRSxDQUFDTyxnQkFDRCxDQUFDRSxjQUNEQSxXQUFXRSxNQUFNLEtBQUssWUFDdEJELE1BQU1FLFdBQVcsUUFDaEJOLFNBQVMsV0FBV0csV0FBV0gsSUFBSSxLQUFLLFdBQ3hDQSxTQUFTLFdBQVdDLGFBQWFNLFdBQVcsS0FBS2IsUUFDbEQ7UUFDQSxNQUFNLElBQUlDLE1BQU07SUFDbEI7SUFDQSxPQUFPO1FBQUNRO1FBQVlGO1FBQWNQO0lBQU07QUFDMUMsRUFBRTtBQUVGLE9BQU8sTUFBTWMsNEJBQTRCLENBQ3ZDaEIsU0FDQU8sZ0JBQ0FDLE9BRUFYLHFCQUFxQkcsU0FBU2lCLFdBQVcsQ0FBQyxDQUFDWCxLQUN6Q0QsZ0NBQWdDQyxJQUFJTixTQUFTTyxnQkFBZ0JDLE9BQzdEO0FBRUosT0FBTyxNQUFNVSxvQkFBb0IsQ0FBQ2xCLFVBQ2hDSCxxQkFBcUJHLFNBQVNpQixXQUFXLENBQUMsT0FBT1g7UUFDL0MsTUFBTUosU0FBU0gsbUJBQW1CQztRQUNsQyxNQUFNbUIsY0FBYyxNQUFNYixHQUFHYyxJQUFJLENBQXlCLDJCQUEyQjtZQUNuRlAsUUFBUTtZQUNSWDtRQUNGO1FBQ0EsTUFBTW1CLFNBQWtELEVBQUU7UUFDMUQsS0FBSSxNQUFNVixjQUFjUSxZQUFhO1lBQ25DLE1BQU1HLFNBQVMsTUFBTWpCLGdDQUFnQ0MsSUFBSU4sU0FBU1csV0FBV0osY0FBYyxFQUFFO1lBQzdGYyxPQUFPRSxJQUFJLENBQUM7Z0JBQUMsR0FBR0QsT0FBT2IsWUFBWTtnQkFBRWUsV0FBV0YsT0FBT1gsVUFBVSxDQUFDSCxJQUFJLEtBQUs7WUFBTztRQUNwRjtRQUNBLE9BQU9hO0lBQ1QsR0FBRyxDQUNMLG9GQUFvRixJQUVwRiwrREFBK0QsSUFDL0QsNkVBQTZFIn0=
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type OrganizationTransaction } from './store.js';
|
|
2
|
+
import type { ApiContext } from '../types/auth.types.js';
|
|
3
|
+
import type { CheckoutResult, MembershipChange, OrganizationMembership, OveragePreference, PlanKey, ProviderSubscription, SeatChangeQuote, SubscriptionSummary } from './types.js';
|
|
4
|
+
export type CheckoutAttempt = Readonly<{
|
|
5
|
+
generation: number;
|
|
6
|
+
key: string;
|
|
7
|
+
leaseExpires: number;
|
|
8
|
+
owner: string;
|
|
9
|
+
plan: PlanKey;
|
|
10
|
+
quantity: number;
|
|
11
|
+
sequence: number;
|
|
12
|
+
session?: CheckoutResult;
|
|
13
|
+
}>;
|
|
14
|
+
export type OrganizationBilling = Readonly<{
|
|
15
|
+
checkout?: CheckoutAttempt;
|
|
16
|
+
customerId: string;
|
|
17
|
+
organizationId: string;
|
|
18
|
+
overage?: OveragePreference;
|
|
19
|
+
pendingChange?: string | null;
|
|
20
|
+
periodEnd?: number | null;
|
|
21
|
+
plan?: PlanKey | null;
|
|
22
|
+
status?: string;
|
|
23
|
+
subscription?: ProviderSubscription | null;
|
|
24
|
+
}>;
|
|
25
|
+
export declare const requireBillingAdmin: (tx: OrganizationTransaction, context: ApiContext, organizationId: string) => Promise<{
|
|
26
|
+
membership: OrganizationMembership;
|
|
27
|
+
organization: import("./types.js").Organization;
|
|
28
|
+
userId: string;
|
|
29
|
+
email: string;
|
|
30
|
+
}>;
|
|
31
|
+
export declare const getOrganizationSubscription: (context: ApiContext, organizationId: string) => Promise<SubscriptionSummary>;
|
|
32
|
+
export declare const createOrganizationCheckout: (context: ApiContext, organizationId: string, plan: PlanKey, requestId: string) => Promise<{
|
|
33
|
+
url: string;
|
|
34
|
+
}>;
|
|
35
|
+
export declare const createOrganizationBillingPortal: (context: ApiContext, organizationId: string) => Promise<{
|
|
36
|
+
url: string;
|
|
37
|
+
}>;
|
|
38
|
+
export declare const quoteOrganizationSeatChange: (context: ApiContext, organizationId: string, change: MembershipChange) => Promise<SeatChangeQuote>;
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { organizationAccessInTransaction } from './authorization.js';
|
|
3
|
+
import { getOrganizationBillingProvider, organizationBillingMode } from './billingProvider.js';
|
|
4
|
+
import { activeMemberCount } from './membership.js';
|
|
5
|
+
import { calculateSeatCharge, getOrganizationPlan } from './plans.js';
|
|
6
|
+
import { organizationKey, organizationStoreFor, requireIdentifier } from './store.js';
|
|
7
|
+
export const requireBillingAdmin = async (tx, context, organizationId)=>{
|
|
8
|
+
const access = await organizationAccessInTransaction(tx, context, organizationId, 'admin');
|
|
9
|
+
const user = await tx.get('users', access.userId);
|
|
10
|
+
if (!user?.verifiedEmail) {
|
|
11
|
+
throw new Error('email_verification_required');
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
...access,
|
|
15
|
+
email: user.email
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
const requireBillingEnabled = ()=>{
|
|
19
|
+
if (organizationBillingMode() !== 'test') {
|
|
20
|
+
throw new Error('billing_disabled');
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
export const getOrganizationSubscription = (context, organizationId)=>organizationStoreFor(context).transaction(async (tx)=>{
|
|
24
|
+
const access = await organizationAccessInTransaction(tx, context, organizationId, 'member');
|
|
25
|
+
const billing = await tx.get('organizationBilling', organizationId);
|
|
26
|
+
const activeMembers = await activeMemberCount(tx, organizationId);
|
|
27
|
+
const charge = billing?.plan ? calculateSeatCharge(billing.plan, activeMembers) : {
|
|
28
|
+
extraSeats: Math.max(0, activeMembers - 10),
|
|
29
|
+
monthlyCents: 0
|
|
30
|
+
};
|
|
31
|
+
const jobs = await tx.find('organizationBillingJobs', {
|
|
32
|
+
organizationId,
|
|
33
|
+
status: 'pending'
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
activeMembers,
|
|
37
|
+
billingMode: organizationBillingMode(),
|
|
38
|
+
canManage: access.membership.role === 'admin',
|
|
39
|
+
estimatedMonthlyCents: charge.monthlyCents,
|
|
40
|
+
extraSeats: charge.extraSeats,
|
|
41
|
+
metersEnabled: false,
|
|
42
|
+
organizationId,
|
|
43
|
+
overage: billing?.overage || {
|
|
44
|
+
enabled: false,
|
|
45
|
+
monthlyCapCents: 0,
|
|
46
|
+
revision: 0
|
|
47
|
+
},
|
|
48
|
+
pendingChange: billing?.pendingChange || null,
|
|
49
|
+
periodEnd: billing?.periodEnd || null,
|
|
50
|
+
plan: billing?.plan || null,
|
|
51
|
+
reconciliationPending: jobs.some((job)=>job.kind !== 'mail'),
|
|
52
|
+
status: billing?.status || 'none'
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
export const createOrganizationCheckout = async (context, organizationId, plan, requestId)=>{
|
|
56
|
+
getOrganizationPlan(plan);
|
|
57
|
+
requireIdentifier(requestId);
|
|
58
|
+
requireBillingEnabled();
|
|
59
|
+
const store = organizationStoreFor(context);
|
|
60
|
+
const owner = randomUUID();
|
|
61
|
+
const pending = await store.transaction(async (tx)=>{
|
|
62
|
+
const access = await requireBillingAdmin(tx, context, organizationId);
|
|
63
|
+
const old = await tx.get('organizationBilling', organizationId);
|
|
64
|
+
if (old?.plan && ![
|
|
65
|
+
'canceled',
|
|
66
|
+
'incomplete_expired'
|
|
67
|
+
].includes(old.status || '')) {
|
|
68
|
+
throw new Error('subscription_exists');
|
|
69
|
+
}
|
|
70
|
+
if (old?.subscription && (await tx.find('organizationBillingJobs', {
|
|
71
|
+
organizationId,
|
|
72
|
+
status: 'pending'
|
|
73
|
+
})).some((job)=>job.kind !== 'mail')) {
|
|
74
|
+
throw new Error('billing_reconciliation_pending');
|
|
75
|
+
}
|
|
76
|
+
const previous = old?.checkout;
|
|
77
|
+
if (previous?.session && previous.session.expiresAt > Date.now()) {
|
|
78
|
+
if (previous.plan !== plan) {
|
|
79
|
+
throw new Error('checkout_in_progress');
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
cached: previous.session.url
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (previous && previous.leaseExpires > Date.now()) {
|
|
86
|
+
throw new Error('checkout_busy');
|
|
87
|
+
}
|
|
88
|
+
// An unknown provider outcome must retain its key, even beyond Stripe's 24h cache.
|
|
89
|
+
if (previous && !previous.session && previous.plan !== plan) {
|
|
90
|
+
throw new Error('checkout_in_progress');
|
|
91
|
+
}
|
|
92
|
+
const generation = previous ? previous.generation + Number(Boolean(previous.session)) : 1;
|
|
93
|
+
const quantity = calculateSeatCharge(plan, await activeMemberCount(tx, organizationId)).extraSeats;
|
|
94
|
+
const checkout = previous && !previous.session ? {
|
|
95
|
+
...previous,
|
|
96
|
+
leaseExpires: Date.now() + 60000,
|
|
97
|
+
owner
|
|
98
|
+
} : {
|
|
99
|
+
generation,
|
|
100
|
+
key: organizationKey('checkout', organizationId, String(generation)),
|
|
101
|
+
leaseExpires: Date.now() + 60000,
|
|
102
|
+
owner,
|
|
103
|
+
plan,
|
|
104
|
+
quantity,
|
|
105
|
+
sequence: access.organization.revision
|
|
106
|
+
};
|
|
107
|
+
const billing = {
|
|
108
|
+
...old,
|
|
109
|
+
checkout,
|
|
110
|
+
customerId: old?.customerId || '',
|
|
111
|
+
organizationId
|
|
112
|
+
};
|
|
113
|
+
await tx.put('organizationBilling', organizationId, billing, old);
|
|
114
|
+
return {
|
|
115
|
+
billing,
|
|
116
|
+
email: access.email
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
if ('cached' in pending) {
|
|
120
|
+
return {
|
|
121
|
+
url: pending.cached
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const fenced = async (patch)=>store.transaction(async (tx)=>{
|
|
125
|
+
const current = await tx.get('organizationBilling', organizationId);
|
|
126
|
+
if (current?.checkout?.owner !== owner) {
|
|
127
|
+
throw new Error('checkout_lease_lost');
|
|
128
|
+
}
|
|
129
|
+
await tx.put('organizationBilling', organizationId, {
|
|
130
|
+
...current,
|
|
131
|
+
...patch
|
|
132
|
+
}, current);
|
|
133
|
+
});
|
|
134
|
+
try {
|
|
135
|
+
const provider = await getOrganizationBillingProvider();
|
|
136
|
+
let { customerId } = pending.billing;
|
|
137
|
+
if (!customerId) {
|
|
138
|
+
customerId = await provider.customer(organizationId, pending.email);
|
|
139
|
+
await fenced({
|
|
140
|
+
customerId
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (await provider.retrieve(customerId)) {
|
|
144
|
+
throw new Error('subscription_exists');
|
|
145
|
+
}
|
|
146
|
+
const attempt = pending.billing.checkout;
|
|
147
|
+
await store.transaction(async (tx)=>{
|
|
148
|
+
await requireBillingAdmin(tx, context, organizationId);
|
|
149
|
+
const current = await tx.get('organizationBilling', organizationId);
|
|
150
|
+
if (current?.checkout?.owner !== owner) {
|
|
151
|
+
throw new Error('checkout_lease_lost');
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
const session = await provider.checkout(customerId, attempt.plan, attempt.quantity, attempt.key);
|
|
155
|
+
// Persist the exact provider outcome before exposing its redirect.
|
|
156
|
+
await fenced({
|
|
157
|
+
checkout: {
|
|
158
|
+
...attempt,
|
|
159
|
+
leaseExpires: 0,
|
|
160
|
+
owner: '',
|
|
161
|
+
session
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
if (session.expiresAt <= Date.now() || !session.url) {
|
|
165
|
+
throw new Error('checkout_expired');
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
url: session.url
|
|
169
|
+
};
|
|
170
|
+
} catch (error) {
|
|
171
|
+
await store.transaction(async (tx)=>{
|
|
172
|
+
const current = await tx.get('organizationBilling', organizationId);
|
|
173
|
+
if (current?.checkout?.owner === owner) {
|
|
174
|
+
await tx.put('organizationBilling', organizationId, {
|
|
175
|
+
...current,
|
|
176
|
+
checkout: {
|
|
177
|
+
...current.checkout,
|
|
178
|
+
leaseExpires: 0,
|
|
179
|
+
owner: ''
|
|
180
|
+
}
|
|
181
|
+
}, current);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
if (error instanceof Error && [
|
|
185
|
+
'subscription_exists',
|
|
186
|
+
'checkout_expired',
|
|
187
|
+
'checkout_in_progress',
|
|
188
|
+
'checkout_lease_lost'
|
|
189
|
+
].includes(error.message)) {
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
throw new Error('billing_provider_unavailable');
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
export const createOrganizationBillingPortal = async (context, organizationId)=>{
|
|
196
|
+
requireBillingEnabled();
|
|
197
|
+
const customerId = await organizationStoreFor(context).transaction(async (tx)=>{
|
|
198
|
+
await requireBillingAdmin(tx, context, organizationId);
|
|
199
|
+
const billing = await tx.get('organizationBilling', organizationId);
|
|
200
|
+
if (!billing?.customerId) {
|
|
201
|
+
throw new Error('billing_customer_required');
|
|
202
|
+
}
|
|
203
|
+
return billing.customerId;
|
|
204
|
+
});
|
|
205
|
+
const provider = await getOrganizationBillingProvider();
|
|
206
|
+
return {
|
|
207
|
+
url: await provider.portal(customerId)
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
export const quoteOrganizationSeatChange = async (context, organizationId, change)=>{
|
|
211
|
+
requireBillingEnabled();
|
|
212
|
+
const store = organizationStoreFor(context);
|
|
213
|
+
const intent = await store.transaction(async (tx)=>{
|
|
214
|
+
const access = await requireBillingAdmin(tx, context, organizationId);
|
|
215
|
+
const member = await tx.get('organizationMemberships', organizationKey(organizationId, requireIdentifier(change.userId)));
|
|
216
|
+
if (!member || member.revision !== change.expectedRevision || ![
|
|
217
|
+
'admin',
|
|
218
|
+
'member'
|
|
219
|
+
].includes(change.role) || ![
|
|
220
|
+
'active',
|
|
221
|
+
'deactivated'
|
|
222
|
+
].includes(change.status)) {
|
|
223
|
+
throw new Error('invalid_membership');
|
|
224
|
+
}
|
|
225
|
+
if (member.userId === access.organization.ownerUserId && (change.role !== 'admin' || change.status !== 'active')) {
|
|
226
|
+
throw new Error('ownership_transfer_required');
|
|
227
|
+
}
|
|
228
|
+
const user = await tx.get('users', change.userId);
|
|
229
|
+
if (change.status === 'active' && (!user?.active || !user.verifiedEmail)) {
|
|
230
|
+
throw new Error('verified_active_user_required');
|
|
231
|
+
}
|
|
232
|
+
const billing = await tx.get('organizationBilling', organizationId);
|
|
233
|
+
if (!billing?.customerId || billing.status !== 'active') {
|
|
234
|
+
throw new Error('billing_not_ready');
|
|
235
|
+
}
|
|
236
|
+
const quantity = Math.max(0, await activeMemberCount(tx, organizationId) + Number(change.status === 'active') - Number(member.status === 'active') - 10);
|
|
237
|
+
return {
|
|
238
|
+
customerId: billing.customerId,
|
|
239
|
+
organization: access.organization,
|
|
240
|
+
quantity
|
|
241
|
+
};
|
|
242
|
+
});
|
|
243
|
+
const provider = await getOrganizationBillingProvider();
|
|
244
|
+
const subscription = await provider.retrieve(intent.customerId);
|
|
245
|
+
if (!subscription || subscription.status !== 'active') {
|
|
246
|
+
throw new Error('billing_not_ready');
|
|
247
|
+
}
|
|
248
|
+
const effectiveAt = Date.now();
|
|
249
|
+
const prorationCents = await provider.preview(subscription, subscription.plan, intent.quantity, effectiveAt);
|
|
250
|
+
const quote = {
|
|
251
|
+
currency: 'usd',
|
|
252
|
+
expiresAt: effectiveAt + 300000,
|
|
253
|
+
organizationRevision: intent.organization.revision,
|
|
254
|
+
prorationCents,
|
|
255
|
+
quantity: intent.quantity,
|
|
256
|
+
quoteId: randomUUID()
|
|
257
|
+
};
|
|
258
|
+
await store.transaction(async (tx)=>{
|
|
259
|
+
const access = await requireBillingAdmin(tx, context, organizationId);
|
|
260
|
+
if (access.organization.revision !== quote.organizationRevision) {
|
|
261
|
+
throw new Error('revision_conflict');
|
|
262
|
+
}
|
|
263
|
+
await tx.put('organizationBillingQuotes', quote.quoteId, {
|
|
264
|
+
...quote,
|
|
265
|
+
effectiveAt,
|
|
266
|
+
expectedRevision: change.expectedRevision,
|
|
267
|
+
organizationId,
|
|
268
|
+
role: change.role,
|
|
269
|
+
status: change.status,
|
|
270
|
+
used: false,
|
|
271
|
+
userId: change.userId
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
return quote;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy9iaWxsaW5nLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7cmFuZG9tVVVJRH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuXG5pbXBvcnQge29yZ2FuaXphdGlvbkFjY2Vzc0luVHJhbnNhY3Rpb259IGZyb20gJy4vYXV0aG9yaXphdGlvbi5qcyc7XG5pbXBvcnQge2dldE9yZ2FuaXphdGlvbkJpbGxpbmdQcm92aWRlciwgb3JnYW5pemF0aW9uQmlsbGluZ01vZGV9IGZyb20gJy4vYmlsbGluZ1Byb3ZpZGVyLmpzJztcbmltcG9ydCB7YWN0aXZlTWVtYmVyQ291bnR9IGZyb20gJy4vbWVtYmVyc2hpcC5qcyc7XG5pbXBvcnQge2NhbGN1bGF0ZVNlYXRDaGFyZ2UsIGdldE9yZ2FuaXphdGlvblBsYW59IGZyb20gJy4vcGxhbnMuanMnO1xuaW1wb3J0IHtcbiAgb3JnYW5pemF0aW9uS2V5LFxuICBvcmdhbml6YXRpb25TdG9yZUZvcixcbiAgcmVxdWlyZUlkZW50aWZpZXIsXG4gIHR5cGUgT3JnYW5pemF0aW9uVHJhbnNhY3Rpb25cbn0gZnJvbSAnLi9zdG9yZS5qcyc7XG5cbmltcG9ydCB0eXBlIHtBcGlDb250ZXh0fSBmcm9tICcuLi90eXBlcy9hdXRoLnR5cGVzLmpzJztcbmltcG9ydCB0eXBlIHtcbiAgQ2hlY2tvdXRSZXN1bHQsXG4gIE1lbWJlcnNoaXBDaGFuZ2UsXG4gIE9yZ2FuaXphdGlvbk1lbWJlcnNoaXAsXG4gIE92ZXJhZ2VQcmVmZXJlbmNlLFxuICBQbGFuS2V5LFxuICBQcm92aWRlclN1YnNjcmlwdGlvbixcbiAgU2VhdENoYW5nZVF1b3RlLFxuICBTdWJzY3JpcHRpb25TdW1tYXJ5XG59IGZyb20gJy4vdHlwZXMuanMnO1xuXG5leHBvcnQgdHlwZSBDaGVja291dEF0dGVtcHQgPSBSZWFkb25seTx7XG4gIGdlbmVyYXRpb246IG51bWJlcjtcbiAga2V5OiBzdHJpbmc7XG4gIGxlYXNlRXhwaXJlczogbnVtYmVyO1xuICBvd25lcjogc3RyaW5nO1xuICBwbGFuOiBQbGFuS2V5O1xuICBxdWFudGl0eTogbnVtYmVyO1xuICBzZXF1ZW5jZTogbnVtYmVyO1xuICBzZXNzaW9uPzogQ2hlY2tvdXRSZXN1bHQ7XG59PjtcbmV4cG9ydCB0eXBlIE9yZ2FuaXphdGlvbkJpbGxpbmcgPSBSZWFkb25seTx7XG4gIGNoZWNrb3V0PzogQ2hlY2tvdXRBdHRlbXB0O1xuICBjdXN0b21lcklkOiBzdHJpbmc7XG4gIG9yZ2FuaXphdGlvbklkOiBzdHJpbmc7XG4gIG92ZXJhZ2U/OiBPdmVyYWdlUHJlZmVyZW5jZTtcbiAgcGVuZGluZ0NoYW5nZT86IHN0cmluZyB8IG51bGw7XG4gIHBlcmlvZEVuZD86IG51bWJlciB8IG51bGw7XG4gIHBsYW4/OiBQbGFuS2V5IHwgbnVsbDtcbiAgc3RhdHVzPzogc3RyaW5nO1xuICBzdWJzY3JpcHRpb24/OiBQcm92aWRlclN1YnNjcmlwdGlvbiB8IG51bGw7XG59PjtcblxuZXhwb3J0IGNvbnN0IHJlcXVpcmVCaWxsaW5nQWRtaW4gPSBhc3luYyAoXG4gIHR4OiBPcmdhbml6YXRpb25UcmFuc2FjdGlvbixcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZ1xuKSA9PiB7XG4gIGNvbnN0IGFjY2VzcyA9IGF3YWl0IG9yZ2FuaXphdGlvbkFjY2Vzc0luVHJhbnNhY3Rpb24odHgsIGNvbnRleHQsIG9yZ2FuaXphdGlvbklkLCAnYWRtaW4nKTtcbiAgY29uc3QgdXNlciA9IGF3YWl0IHR4LmdldDx7ZW1haWw6IHN0cmluZzsgdmVyaWZpZWRFbWFpbDogYm9vbGVhbn0+KCd1c2VycycsIGFjY2Vzcy51c2VySWQpO1xuICBpZighdXNlcj8udmVyaWZpZWRFbWFpbCkge1xuICAgIHRocm93IG5ldyBFcnJvcignZW1haWxfdmVyaWZpY2F0aW9uX3JlcXVpcmVkJyk7XG4gIH1cbiAgcmV0dXJuIHsuLi5hY2Nlc3MsIGVtYWlsOiB1c2VyLmVtYWlsfTtcbn07XG5jb25zdCByZXF1aXJlQmlsbGluZ0VuYWJsZWQgPSAoKTogdm9pZCA9PiB7XG4gIGlmKG9yZ2FuaXphdGlvbkJpbGxpbmdNb2RlKCkgIT09ICd0ZXN0Jykge1xuICAgIHRocm93IG5ldyBFcnJvcignYmlsbGluZ19kaXNhYmxlZCcpO1xuICB9XG59O1xuZXhwb3J0IGNvbnN0IGdldE9yZ2FuaXphdGlvblN1YnNjcmlwdGlvbiA9IChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZ1xuKTogUHJvbWlzZTxTdWJzY3JpcHRpb25TdW1tYXJ5PiA9PlxuICBvcmdhbml6YXRpb25TdG9yZUZvcihjb250ZXh0KS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICBjb25zdCBhY2Nlc3MgPSBhd2FpdCBvcmdhbml6YXRpb25BY2Nlc3NJblRyYW5zYWN0aW9uKHR4LCBjb250ZXh0LCBvcmdhbml6YXRpb25JZCwgJ21lbWJlcicpO1xuICAgIGNvbnN0IGJpbGxpbmcgPSBhd2FpdCB0eC5nZXQ8T3JnYW5pemF0aW9uQmlsbGluZz4oJ29yZ2FuaXphdGlvbkJpbGxpbmcnLCBvcmdhbml6YXRpb25JZCk7XG4gICAgY29uc3QgYWN0aXZlTWVtYmVycyA9IGF3YWl0IGFjdGl2ZU1lbWJlckNvdW50KHR4LCBvcmdhbml6YXRpb25JZCk7XG4gICAgY29uc3QgY2hhcmdlID0gYmlsbGluZz8ucGxhblxuICAgICAgPyBjYWxjdWxhdGVTZWF0Q2hhcmdlKGJpbGxpbmcucGxhbiwgYWN0aXZlTWVtYmVycylcbiAgICAgIDoge2V4dHJhU2VhdHM6IE1hdGgubWF4KDAsIGFjdGl2ZU1lbWJlcnMgLSAxMCksIG1vbnRobHlDZW50czogMH07XG4gICAgY29uc3Qgam9icyA9IGF3YWl0IHR4LmZpbmQ8e2tpbmQ6IHN0cmluZ30+KCdvcmdhbml6YXRpb25CaWxsaW5nSm9icycsIHtcbiAgICAgIG9yZ2FuaXphdGlvbklkLFxuICAgICAgc3RhdHVzOiAncGVuZGluZydcbiAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgYWN0aXZlTWVtYmVycyxcbiAgICAgIGJpbGxpbmdNb2RlOiBvcmdhbml6YXRpb25CaWxsaW5nTW9kZSgpLFxuICAgICAgY2FuTWFuYWdlOiBhY2Nlc3MubWVtYmVyc2hpcC5yb2xlID09PSAnYWRtaW4nLFxuICAgICAgZXN0aW1hdGVkTW9udGhseUNlbnRzOiBjaGFyZ2UubW9udGhseUNlbnRzLFxuICAgICAgZXh0cmFTZWF0czogY2hhcmdlLmV4dHJhU2VhdHMsXG4gICAgICBtZXRlcnNFbmFibGVkOiBmYWxzZSxcbiAgICAgIG9yZ2FuaXphdGlvbklkLFxuICAgICAgb3ZlcmFnZTogYmlsbGluZz8ub3ZlcmFnZSB8fCB7ZW5hYmxlZDogZmFsc2UsIG1vbnRobHlDYXBDZW50czogMCwgcmV2aXNpb246IDB9LFxuICAgICAgcGVuZGluZ0NoYW5nZTogYmlsbGluZz8ucGVuZGluZ0NoYW5nZSB8fCBudWxsLFxuICAgICAgcGVyaW9kRW5kOiBiaWxsaW5nPy5wZXJpb2RFbmQgfHwgbnVsbCxcbiAgICAgIHBsYW46IGJpbGxpbmc/LnBsYW4gfHwgbnVsbCxcbiAgICAgIHJlY29uY2lsaWF0aW9uUGVuZGluZzogam9icy5zb21lKChqb2IpID0+IGpvYi5raW5kICE9PSAnbWFpbCcpLFxuICAgICAgc3RhdHVzOiBiaWxsaW5nPy5zdGF0dXMgfHwgJ25vbmUnXG4gICAgfTtcbiAgfSk7XG5cbmV4cG9ydCBjb25zdCBjcmVhdGVPcmdhbml6YXRpb25DaGVja291dCA9IGFzeW5jIChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZyxcbiAgcGxhbjogUGxhbktleSxcbiAgcmVxdWVzdElkOiBzdHJpbmdcbik6IFByb21pc2U8e3VybDogc3RyaW5nfT4gPT4ge1xuICBnZXRPcmdhbml6YXRpb25QbGFuKHBsYW4pO1xuICByZXF1aXJlSWRlbnRpZmllcihyZXF1ZXN0SWQpO1xuICByZXF1aXJlQmlsbGluZ0VuYWJsZWQoKTtcbiAgY29uc3Qgc3RvcmUgPSBvcmdhbml6YXRpb25TdG9yZUZvcihjb250ZXh0KTtcbiAgY29uc3Qgb3duZXIgPSByYW5kb21VVUlEKCk7XG4gIGNvbnN0IHBlbmRpbmcgPSBhd2FpdCBzdG9yZS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICBjb25zdCBhY2Nlc3MgPSBhd2FpdCByZXF1aXJlQmlsbGluZ0FkbWluKHR4LCBjb250ZXh0LCBvcmdhbml6YXRpb25JZCk7XG4gICAgY29uc3Qgb2xkID0gYXdhaXQgdHguZ2V0PE9yZ2FuaXphdGlvbkJpbGxpbmc+KCdvcmdhbml6YXRpb25CaWxsaW5nJywgb3JnYW5pemF0aW9uSWQpO1xuICAgIGlmKG9sZD8ucGxhbiAmJiAhWydjYW5jZWxlZCcsICdpbmNvbXBsZXRlX2V4cGlyZWQnXS5pbmNsdWRlcyhvbGQuc3RhdHVzIHx8ICcnKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdzdWJzY3JpcHRpb25fZXhpc3RzJyk7XG4gICAgfVxuICAgIGlmKG9sZD8uc3Vic2NyaXB0aW9uICYmIChhd2FpdCB0eC5maW5kPHtraW5kOiBzdHJpbmd9Pignb3JnYW5pemF0aW9uQmlsbGluZ0pvYnMnLCB7b3JnYW5pemF0aW9uSWQsIHN0YXR1czogJ3BlbmRpbmcnfSkpLnNvbWUoKGpvYikgPT4gam9iLmtpbmQgIT09ICdtYWlsJykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignYmlsbGluZ19yZWNvbmNpbGlhdGlvbl9wZW5kaW5nJyk7XG4gICAgfVxuICAgIGNvbnN0IHByZXZpb3VzID0gb2xkPy5jaGVja291dDtcbiAgICBpZihwcmV2aW91cz8uc2Vzc2lvbiAmJiBwcmV2aW91cy5zZXNzaW9uLmV4cGlyZXNBdCA+IERhdGUubm93KCkpIHtcbiAgICAgIGlmKHByZXZpb3VzLnBsYW4gIT09IHBsYW4pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjaGVja291dF9pbl9wcm9ncmVzcycpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHtjYWNoZWQ6IHByZXZpb3VzLnNlc3Npb24udXJsfTtcbiAgICB9XG4gICAgaWYocHJldmlvdXMgJiYgcHJldmlvdXMubGVhc2VFeHBpcmVzID4gRGF0ZS5ub3coKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjaGVja291dF9idXN5Jyk7XG4gICAgfVxuICAgIC8vIEFuIHVua25vd24gcHJvdmlkZXIgb3V0Y29tZSBtdXN0IHJldGFpbiBpdHMga2V5LCBldmVuIGJleW9uZCBTdHJpcGUncyAyNGggY2FjaGUuXG4gICAgaWYocHJldmlvdXMgJiYgIXByZXZpb3VzLnNlc3Npb24gJiYgcHJldmlvdXMucGxhbiAhPT0gcGxhbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjaGVja291dF9pbl9wcm9ncmVzcycpO1xuICAgIH1cbiAgICBjb25zdCBnZW5lcmF0aW9uID0gcHJldmlvdXMgPyBwcmV2aW91cy5nZW5lcmF0aW9uICsgTnVtYmVyKEJvb2xlYW4ocHJldmlvdXMuc2Vzc2lvbikpIDogMTtcbiAgICBjb25zdCBxdWFudGl0eSA9IGNhbGN1bGF0ZVNlYXRDaGFyZ2UocGxhbiwgYXdhaXQgYWN0aXZlTWVtYmVyQ291bnQodHgsIG9yZ2FuaXphdGlvbklkKSkuZXh0cmFTZWF0cztcbiAgICBjb25zdCBjaGVja291dDogQ2hlY2tvdXRBdHRlbXB0ID1cbiAgICAgIHByZXZpb3VzICYmICFwcmV2aW91cy5zZXNzaW9uXG4gICAgICAgID8gey4uLnByZXZpb3VzLCBsZWFzZUV4cGlyZXM6IERhdGUubm93KCkgKyA2MDAwMCwgb3duZXJ9XG4gICAgICAgIDoge1xuICAgICAgICAgIGdlbmVyYXRpb24sXG4gICAgICAgICAga2V5OiBvcmdhbml6YXRpb25LZXkoJ2NoZWNrb3V0Jywgb3JnYW5pemF0aW9uSWQsIFN0cmluZyhnZW5lcmF0aW9uKSksXG4gICAgICAgICAgbGVhc2VFeHBpcmVzOiBEYXRlLm5vdygpICsgNjAwMDAsXG4gICAgICAgICAgb3duZXIsXG4gICAgICAgICAgcGxhbixcbiAgICAgICAgICBxdWFudGl0eSxcbiAgICAgICAgICBzZXF1ZW5jZTogYWNjZXNzLm9yZ2FuaXphdGlvbi5yZXZpc2lvblxuICAgICAgICB9O1xuICAgIGNvbnN0IGJpbGxpbmc6IE9yZ2FuaXphdGlvbkJpbGxpbmcgPSB7XG4gICAgICAuLi5vbGQsXG4gICAgICBjaGVja291dCxcbiAgICAgIGN1c3RvbWVySWQ6IG9sZD8uY3VzdG9tZXJJZCB8fCAnJyxcbiAgICAgIG9yZ2FuaXphdGlvbklkXG4gICAgfTtcbiAgICBhd2FpdCB0eC5wdXQoJ29yZ2FuaXphdGlvbkJpbGxpbmcnLCBvcmdhbml6YXRpb25JZCwgYmlsbGluZywgb2xkKTtcbiAgICByZXR1cm4ge2JpbGxpbmcsIGVtYWlsOiBhY2Nlc3MuZW1haWx9O1xuICB9KTtcbiAgaWYoJ2NhY2hlZCcgaW4gcGVuZGluZykge1xuICAgIHJldHVybiB7dXJsOiBwZW5kaW5nLmNhY2hlZCF9O1xuICB9XG4gIGNvbnN0IGZlbmNlZCA9IGFzeW5jIChwYXRjaDogUGFydGlhbDxPcmdhbml6YXRpb25CaWxsaW5nPik6IFByb21pc2U8dm9pZD4gPT5cbiAgICBzdG9yZS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICAgIGNvbnN0IGN1cnJlbnQgPSBhd2FpdCB0eC5nZXQ8T3JnYW5pemF0aW9uQmlsbGluZz4oJ29yZ2FuaXphdGlvbkJpbGxpbmcnLCBvcmdhbml6YXRpb25JZCk7XG4gICAgICBpZihjdXJyZW50Py5jaGVja291dD8ub3duZXIgIT09IG93bmVyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignY2hlY2tvdXRfbGVhc2VfbG9zdCcpO1xuICAgICAgfVxuICAgICAgYXdhaXQgdHgucHV0KCdvcmdhbml6YXRpb25CaWxsaW5nJywgb3JnYW5pemF0aW9uSWQsIHsuLi5jdXJyZW50LCAuLi5wYXRjaH0sIGN1cnJlbnQpO1xuICAgIH0pO1xuICB0cnkge1xuICAgIGNvbnN0IHByb3ZpZGVyID0gYXdhaXQgZ2V0T3JnYW5pemF0aW9uQmlsbGluZ1Byb3ZpZGVyKCk7XG4gICAgbGV0IHtjdXN0b21lcklkfSA9IChwZW5kaW5nLmJpbGxpbmchKTtcbiAgICBpZighY3VzdG9tZXJJZCkge1xuICAgICAgY3VzdG9tZXJJZCA9IGF3YWl0IHByb3ZpZGVyLmN1c3RvbWVyKG9yZ2FuaXphdGlvbklkLCBwZW5kaW5nLmVtYWlsISk7XG4gICAgICBhd2FpdCBmZW5jZWQoe2N1c3RvbWVySWR9KTtcbiAgICB9XG4gICAgaWYoYXdhaXQgcHJvdmlkZXIucmV0cmlldmUoY3VzdG9tZXJJZCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignc3Vic2NyaXB0aW9uX2V4aXN0cycpO1xuICAgIH1cbiAgICBjb25zdCBhdHRlbXB0ID0gcGVuZGluZy5iaWxsaW5nIS5jaGVja291dCE7XG4gICAgYXdhaXQgc3RvcmUudHJhbnNhY3Rpb24oYXN5bmMgKHR4KSA9PiB7XG4gICAgICBhd2FpdCByZXF1aXJlQmlsbGluZ0FkbWluKHR4LCBjb250ZXh0LCBvcmdhbml6YXRpb25JZCk7XG4gICAgICBjb25zdCBjdXJyZW50ID0gYXdhaXQgdHguZ2V0PE9yZ2FuaXphdGlvbkJpbGxpbmc+KCdvcmdhbml6YXRpb25CaWxsaW5nJywgb3JnYW5pemF0aW9uSWQpO1xuICAgICAgaWYoY3VycmVudD8uY2hlY2tvdXQ/Lm93bmVyICE9PSBvd25lcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2NoZWNrb3V0X2xlYXNlX2xvc3QnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBjb25zdCBzZXNzaW9uID0gYXdhaXQgcHJvdmlkZXIuY2hlY2tvdXQoY3VzdG9tZXJJZCwgYXR0ZW1wdC5wbGFuLCBhdHRlbXB0LnF1YW50aXR5LCBhdHRlbXB0LmtleSk7XG4gICAgLy8gUGVyc2lzdCB0aGUgZXhhY3QgcHJvdmlkZXIgb3V0Y29tZSBiZWZvcmUgZXhwb3NpbmcgaXRzIHJlZGlyZWN0LlxuICAgIGF3YWl0IGZlbmNlZCh7Y2hlY2tvdXQ6IHsuLi5hdHRlbXB0LCBsZWFzZUV4cGlyZXM6IDAsIG93bmVyOiAnJywgc2Vzc2lvbn19KTtcbiAgICBpZihzZXNzaW9uLmV4cGlyZXNBdCA8PSBEYXRlLm5vdygpIHx8ICFzZXNzaW9uLnVybCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjaGVja291dF9leHBpcmVkJyk7XG4gICAgfVxuICAgIHJldHVybiB7dXJsOiBzZXNzaW9uLnVybH07XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICBhd2FpdCBzdG9yZS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICAgIGNvbnN0IGN1cnJlbnQgPSBhd2FpdCB0eC5nZXQ8T3JnYW5pemF0aW9uQmlsbGluZz4oJ29yZ2FuaXphdGlvbkJpbGxpbmcnLCBvcmdhbml6YXRpb25JZCk7XG4gICAgICBpZihjdXJyZW50Py5jaGVja291dD8ub3duZXIgPT09IG93bmVyKSB7XG4gICAgICAgIGF3YWl0IHR4LnB1dChcbiAgICAgICAgICAnb3JnYW5pemF0aW9uQmlsbGluZycsXG4gICAgICAgICAgb3JnYW5pemF0aW9uSWQsXG4gICAgICAgICAgey4uLmN1cnJlbnQsIGNoZWNrb3V0OiB7Li4uY3VycmVudC5jaGVja291dCwgbGVhc2VFeHBpcmVzOiAwLCBvd25lcjogJyd9fSxcbiAgICAgICAgICBjdXJyZW50XG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgaWYoXG4gICAgICBlcnJvciBpbnN0YW5jZW9mIEVycm9yICYmXG4gICAgICBbJ3N1YnNjcmlwdGlvbl9leGlzdHMnLCAnY2hlY2tvdXRfZXhwaXJlZCcsICdjaGVja291dF9pbl9wcm9ncmVzcycsICdjaGVja291dF9sZWFzZV9sb3N0J10uaW5jbHVkZXMoXG4gICAgICAgIGVycm9yLm1lc3NhZ2VcbiAgICAgIClcbiAgICApIHtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2JpbGxpbmdfcHJvdmlkZXJfdW5hdmFpbGFibGUnKTtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGNyZWF0ZU9yZ2FuaXphdGlvbkJpbGxpbmdQb3J0YWwgPSBhc3luYyAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsXG4gIG9yZ2FuaXphdGlvbklkOiBzdHJpbmdcbik6IFByb21pc2U8e3VybDogc3RyaW5nfT4gPT4ge1xuICByZXF1aXJlQmlsbGluZ0VuYWJsZWQoKTtcbiAgY29uc3QgY3VzdG9tZXJJZCA9IGF3YWl0IG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgIGF3YWl0IHJlcXVpcmVCaWxsaW5nQWRtaW4odHgsIGNvbnRleHQsIG9yZ2FuaXphdGlvbklkKTtcbiAgICBjb25zdCBiaWxsaW5nID0gYXdhaXQgdHguZ2V0PE9yZ2FuaXphdGlvbkJpbGxpbmc+KCdvcmdhbml6YXRpb25CaWxsaW5nJywgb3JnYW5pemF0aW9uSWQpO1xuICAgIGlmKCFiaWxsaW5nPy5jdXN0b21lcklkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2JpbGxpbmdfY3VzdG9tZXJfcmVxdWlyZWQnKTtcbiAgICB9XG4gICAgcmV0dXJuIGJpbGxpbmcuY3VzdG9tZXJJZDtcbiAgfSk7XG4gIGNvbnN0IHByb3ZpZGVyID0gYXdhaXQgZ2V0T3JnYW5pemF0aW9uQmlsbGluZ1Byb3ZpZGVyKCk7XG4gIHJldHVybiB7dXJsOiBhd2FpdCBwcm92aWRlci5wb3J0YWwoY3VzdG9tZXJJZCl9O1xufTtcblxuZXhwb3J0IGNvbnN0IHF1b3RlT3JnYW5pemF0aW9uU2VhdENoYW5nZSA9IGFzeW5jIChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZyxcbiAgY2hhbmdlOiBNZW1iZXJzaGlwQ2hhbmdlXG4pOiBQcm9taXNlPFNlYXRDaGFuZ2VRdW90ZT4gPT4ge1xuICByZXF1aXJlQmlsbGluZ0VuYWJsZWQoKTtcbiAgY29uc3Qgc3RvcmUgPSBvcmdhbml6YXRpb25TdG9yZUZvcihjb250ZXh0KTtcbiAgY29uc3QgaW50ZW50ID0gYXdhaXQgc3RvcmUudHJhbnNhY3Rpb24oYXN5bmMgKHR4KSA9PiB7XG4gICAgY29uc3QgYWNjZXNzID0gYXdhaXQgcmVxdWlyZUJpbGxpbmdBZG1pbih0eCwgY29udGV4dCwgb3JnYW5pemF0aW9uSWQpO1xuICAgIGNvbnN0IG1lbWJlciA9IGF3YWl0IHR4LmdldDxPcmdhbml6YXRpb25NZW1iZXJzaGlwPihcbiAgICAgICdvcmdhbml6YXRpb25NZW1iZXJzaGlwcycsXG4gICAgICBvcmdhbml6YXRpb25LZXkob3JnYW5pemF0aW9uSWQsIHJlcXVpcmVJZGVudGlmaWVyKGNoYW5nZS51c2VySWQpKVxuICAgICk7XG4gICAgaWYoXG4gICAgICAhbWVtYmVyIHx8XG4gICAgICBtZW1iZXIucmV2aXNpb24gIT09IGNoYW5nZS5leHBlY3RlZFJldmlzaW9uIHx8XG4gICAgICAhWydhZG1pbicsICdtZW1iZXInXS5pbmNsdWRlcyhjaGFuZ2Uucm9sZSkgfHxcbiAgICAgICFbJ2FjdGl2ZScsICdkZWFjdGl2YXRlZCddLmluY2x1ZGVzKGNoYW5nZS5zdGF0dXMpXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWRfbWVtYmVyc2hpcCcpO1xuICAgIH1cbiAgICBpZihcbiAgICAgIG1lbWJlci51c2VySWQgPT09IGFjY2Vzcy5vcmdhbml6YXRpb24ub3duZXJVc2VySWQgJiZcbiAgICAgIChjaGFuZ2Uucm9sZSAhPT0gJ2FkbWluJyB8fCBjaGFuZ2Uuc3RhdHVzICE9PSAnYWN0aXZlJylcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignb3duZXJzaGlwX3RyYW5zZmVyX3JlcXVpcmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0eC5nZXQ8e2FjdGl2ZTogYm9vbGVhbjsgdmVyaWZpZWRFbWFpbDogYm9vbGVhbn0+KCd1c2VycycsIGNoYW5nZS51c2VySWQpO1xuICAgIGlmKGNoYW5nZS5zdGF0dXMgPT09ICdhY3RpdmUnICYmICghdXNlcj8uYWN0aXZlIHx8ICF1c2VyLnZlcmlmaWVkRW1haWwpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3ZlcmlmaWVkX2FjdGl2ZV91c2VyX3JlcXVpcmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IGJpbGxpbmcgPSBhd2FpdCB0eC5nZXQ8T3JnYW5pemF0aW9uQmlsbGluZz4oJ29yZ2FuaXphdGlvbkJpbGxpbmcnLCBvcmdhbml6YXRpb25JZCk7XG4gICAgaWYoIWJpbGxpbmc/LmN1c3RvbWVySWQgfHwgYmlsbGluZy5zdGF0dXMgIT09ICdhY3RpdmUnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2JpbGxpbmdfbm90X3JlYWR5Jyk7XG4gICAgfVxuICAgIGNvbnN0IHF1YW50aXR5ID0gTWF0aC5tYXgoXG4gICAgICAwLFxuICAgICAgKGF3YWl0IGFjdGl2ZU1lbWJlckNvdW50KHR4LCBvcmdhbml6YXRpb25JZCkpICtcbiAgICAgICAgTnVtYmVyKGNoYW5nZS5zdGF0dXMgPT09ICdhY3RpdmUnKSAtXG4gICAgICAgIE51bWJlcihtZW1iZXIuc3RhdHVzID09PSAnYWN0aXZlJykgLVxuICAgICAgICAxMFxuICAgICk7XG4gICAgcmV0dXJuIHtjdXN0b21lcklkOiBiaWxsaW5nLmN1c3RvbWVySWQsIG9yZ2FuaXphdGlvbjogYWNjZXNzLm9yZ2FuaXphdGlvbiwgcXVhbnRpdHl9O1xuICB9KTtcbiAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBnZXRPcmdhbml6YXRpb25CaWxsaW5nUHJvdmlkZXIoKTtcbiAgY29uc3Qgc3Vic2NyaXB0aW9uID0gYXdhaXQgcHJvdmlkZXIucmV0cmlldmUoaW50ZW50LmN1c3RvbWVySWQpO1xuICBpZighc3Vic2NyaXB0aW9uIHx8IHN1YnNjcmlwdGlvbi5zdGF0dXMgIT09ICdhY3RpdmUnKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdiaWxsaW5nX25vdF9yZWFkeScpO1xuICB9XG4gIGNvbnN0IGVmZmVjdGl2ZUF0ID0gRGF0ZS5ub3coKTtcbiAgY29uc3QgcHJvcmF0aW9uQ2VudHMgPSBhd2FpdCBwcm92aWRlci5wcmV2aWV3KFxuICAgIHN1YnNjcmlwdGlvbixcbiAgICBzdWJzY3JpcHRpb24ucGxhbixcbiAgICBpbnRlbnQucXVhbnRpdHksXG4gICAgZWZmZWN0aXZlQXRcbiAgKTtcbiAgY29uc3QgcXVvdGU6IFNlYXRDaGFuZ2VRdW90ZSA9IHtcbiAgICBjdXJyZW5jeTogJ3VzZCcsXG4gICAgZXhwaXJlc0F0OiBlZmZlY3RpdmVBdCArIDMwMDAwMCxcbiAgICBvcmdhbml6YXRpb25SZXZpc2lvbjogaW50ZW50Lm9yZ2FuaXphdGlvbi5yZXZpc2lvbixcbiAgICBwcm9yYXRpb25DZW50cyxcbiAgICBxdWFudGl0eTogaW50ZW50LnF1YW50aXR5LFxuICAgIHF1b3RlSWQ6IHJhbmRvbVVVSUQoKVxuICB9O1xuICBhd2FpdCBzdG9yZS50cmFuc2FjdGlvbihhc3luYyAodHgpID0+IHtcbiAgICBjb25zdCBhY2Nlc3MgPSBhd2FpdCByZXF1aXJlQmlsbGluZ0FkbWluKHR4LCBjb250ZXh0LCBvcmdhbml6YXRpb25JZCk7XG4gICAgaWYoYWNjZXNzLm9yZ2FuaXphdGlvbi5yZXZpc2lvbiAhPT0gcXVvdGUub3JnYW5pemF0aW9uUmV2aXNpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigncmV2aXNpb25fY29uZmxpY3QnKTtcbiAgICB9XG4gICAgYXdhaXQgdHgucHV0KCdvcmdhbml6YXRpb25CaWxsaW5nUXVvdGVzJywgcXVvdGUucXVvdGVJZCwge1xuICAgICAgLi4ucXVvdGUsXG4gICAgICBlZmZlY3RpdmVBdCxcbiAgICAgIGV4cGVjdGVkUmV2aXNpb246IGNoYW5nZS5leHBlY3RlZFJldmlzaW9uLFxuICAgICAgb3JnYW5pemF0aW9uSWQsXG4gICAgICByb2xlOiBjaGFuZ2Uucm9sZSxcbiAgICAgIHN0YXR1czogY2hhbmdlLnN0YXR1cyxcbiAgICAgIHVzZWQ6IGZhbHNlLFxuICAgICAgdXNlcklkOiBjaGFuZ2UudXNlcklkXG4gICAgfSk7XG4gIH0pO1xuICByZXR1cm4gcXVvdGU7XG59O1xuIl0sIm5hbWVzIjpbInJhbmRvbVVVSUQiLCJvcmdhbml6YXRpb25BY2Nlc3NJblRyYW5zYWN0aW9uIiwiZ2V0T3JnYW5pemF0aW9uQmlsbGluZ1Byb3ZpZGVyIiwib3JnYW5pemF0aW9uQmlsbGluZ01vZGUiLCJhY3RpdmVNZW1iZXJDb3VudCIsImNhbGN1bGF0ZVNlYXRDaGFyZ2UiLCJnZXRPcmdhbml6YXRpb25QbGFuIiwib3JnYW5pemF0aW9uS2V5Iiwib3JnYW5pemF0aW9uU3RvcmVGb3IiLCJyZXF1aXJlSWRlbnRpZmllciIsInJlcXVpcmVCaWxsaW5nQWRtaW4iLCJ0eCIsImNvbnRleHQiLCJvcmdhbml6YXRpb25JZCIsImFjY2VzcyIsInVzZXIiLCJnZXQiLCJ1c2VySWQiLCJ2ZXJpZmllZEVtYWlsIiwiRXJyb3IiLCJlbWFpbCIsInJlcXVpcmVCaWxsaW5nRW5hYmxlZCIsImdldE9yZ2FuaXphdGlvblN1YnNjcmlwdGlvbiIsInRyYW5zYWN0aW9uIiwiYmlsbGluZyIsImFjdGl2ZU1lbWJlcnMiLCJjaGFyZ2UiLCJwbGFuIiwiZXh0cmFTZWF0cyIsIk1hdGgiLCJtYXgiLCJtb250aGx5Q2VudHMiLCJqb2JzIiwiZmluZCIsInN0YXR1cyIsImJpbGxpbmdNb2RlIiwiY2FuTWFuYWdlIiwibWVtYmVyc2hpcCIsInJvbGUiLCJlc3RpbWF0ZWRNb250aGx5Q2VudHMiLCJtZXRlcnNFbmFibGVkIiwib3ZlcmFnZSIsImVuYWJsZWQiLCJtb250aGx5Q2FwQ2VudHMiLCJyZXZpc2lvbiIsInBlbmRpbmdDaGFuZ2UiLCJwZXJpb2RFbmQiLCJyZWNvbmNpbGlhdGlvblBlbmRpbmciLCJzb21lIiwiam9iIiwia2luZCIsImNyZWF0ZU9yZ2FuaXphdGlvbkNoZWNrb3V0IiwicmVxdWVzdElkIiwic3RvcmUiLCJvd25lciIsInBlbmRpbmciLCJvbGQiLCJpbmNsdWRlcyIsInN1YnNjcmlwdGlvbiIsInByZXZpb3VzIiwiY2hlY2tvdXQiLCJzZXNzaW9uIiwiZXhwaXJlc0F0IiwiRGF0ZSIsIm5vdyIsImNhY2hlZCIsInVybCIsImxlYXNlRXhwaXJlcyIsImdlbmVyYXRpb24iLCJOdW1iZXIiLCJCb29sZWFuIiwicXVhbnRpdHkiLCJrZXkiLCJTdHJpbmciLCJzZXF1ZW5jZSIsIm9yZ2FuaXphdGlvbiIsImN1c3RvbWVySWQiLCJwdXQiLCJmZW5jZWQiLCJwYXRjaCIsImN1cnJlbnQiLCJwcm92aWRlciIsImN1c3RvbWVyIiwicmV0cmlldmUiLCJhdHRlbXB0IiwiZXJyb3IiLCJtZXNzYWdlIiwiY3JlYXRlT3JnYW5pemF0aW9uQmlsbGluZ1BvcnRhbCIsInBvcnRhbCIsInF1b3RlT3JnYW5pemF0aW9uU2VhdENoYW5nZSIsImNoYW5nZSIsImludGVudCIsIm1lbWJlciIsImV4cGVjdGVkUmV2aXNpb24iLCJvd25lclVzZXJJZCIsImFjdGl2ZSIsImVmZmVjdGl2ZUF0IiwicHJvcmF0aW9uQ2VudHMiLCJwcmV2aWV3IiwicXVvdGUiLCJjdXJyZW5jeSIsIm9yZ2FuaXphdGlvblJldmlzaW9uIiwicXVvdGVJZCIsInVzZWQiXSwibWFwcGluZ3MiOiJBQUFBLFNBQVFBLFVBQVUsUUFBTyxjQUFjO0FBRXZDLFNBQVFDLCtCQUErQixRQUFPLHFCQUFxQjtBQUNuRSxTQUFRQyw4QkFBOEIsRUFBRUMsdUJBQXVCLFFBQU8sdUJBQXVCO0FBQzdGLFNBQVFDLGlCQUFpQixRQUFPLGtCQUFrQjtBQUNsRCxTQUFRQyxtQkFBbUIsRUFBRUMsbUJBQW1CLFFBQU8sYUFBYTtBQUNwRSxTQUNFQyxlQUFlLEVBQ2ZDLG9CQUFvQixFQUNwQkMsaUJBQWlCLFFBRVosYUFBYTtBQW9DcEIsT0FBTyxNQUFNQyxzQkFBc0IsT0FDakNDLElBQ0FDLFNBQ0FDO0lBRUEsTUFBTUMsU0FBUyxNQUFNYixnQ0FBZ0NVLElBQUlDLFNBQVNDLGdCQUFnQjtJQUNsRixNQUFNRSxPQUFPLE1BQU1KLEdBQUdLLEdBQUcsQ0FBMEMsU0FBU0YsT0FBT0csTUFBTTtJQUN6RixJQUFHLENBQUNGLE1BQU1HLGVBQWU7UUFDdkIsTUFBTSxJQUFJQyxNQUFNO0lBQ2xCO0lBQ0EsT0FBTztRQUFDLEdBQUdMLE1BQU07UUFBRU0sT0FBT0wsS0FBS0ssS0FBSztJQUFBO0FBQ3RDLEVBQUU7QUFDRixNQUFNQyx3QkFBd0I7SUFDNUIsSUFBR2xCLDhCQUE4QixRQUFRO1FBQ3ZDLE1BQU0sSUFBSWdCLE1BQU07SUFDbEI7QUFDRjtBQUNBLE9BQU8sTUFBTUcsOEJBQThCLENBQ3pDVixTQUNBQyxpQkFFQUwscUJBQXFCSSxTQUFTVyxXQUFXLENBQUMsT0FBT1o7UUFDL0MsTUFBTUcsU0FBUyxNQUFNYixnQ0FBZ0NVLElBQUlDLFNBQVNDLGdCQUFnQjtRQUNsRixNQUFNVyxVQUFVLE1BQU1iLEdBQUdLLEdBQUcsQ0FBc0IsdUJBQXVCSDtRQUN6RSxNQUFNWSxnQkFBZ0IsTUFBTXJCLGtCQUFrQk8sSUFBSUU7UUFDbEQsTUFBTWEsU0FBU0YsU0FBU0csT0FDcEJ0QixvQkFBb0JtQixRQUFRRyxJQUFJLEVBQUVGLGlCQUNsQztZQUFDRyxZQUFZQyxLQUFLQyxHQUFHLENBQUMsR0FBR0wsZ0JBQWdCO1lBQUtNLGNBQWM7UUFBQztRQUNqRSxNQUFNQyxPQUFPLE1BQU1yQixHQUFHc0IsSUFBSSxDQUFpQiwyQkFBMkI7WUFDcEVwQjtZQUNBcUIsUUFBUTtRQUNWO1FBQ0EsT0FBTztZQUNMVDtZQUNBVSxhQUFhaEM7WUFDYmlDLFdBQVd0QixPQUFPdUIsVUFBVSxDQUFDQyxJQUFJLEtBQUs7WUFDdENDLHVCQUF1QmIsT0FBT0ssWUFBWTtZQUMxQ0gsWUFBWUYsT0FBT0UsVUFBVTtZQUM3QlksZUFBZTtZQUNmM0I7WUFDQTRCLFNBQVNqQixTQUFTaUIsV0FBVztnQkFBQ0MsU0FBUztnQkFBT0MsaUJBQWlCO2dCQUFHQyxVQUFVO1lBQUM7WUFDN0VDLGVBQWVyQixTQUFTcUIsaUJBQWlCO1lBQ3pDQyxXQUFXdEIsU0FBU3NCLGFBQWE7WUFDakNuQixNQUFNSCxTQUFTRyxRQUFRO1lBQ3ZCb0IsdUJBQXVCZixLQUFLZ0IsSUFBSSxDQUFDLENBQUNDLE1BQVFBLElBQUlDLElBQUksS0FBSztZQUN2RGhCLFFBQVFWLFNBQVNVLFVBQVU7UUFDN0I7SUFDRixHQUFHO0FBRUwsT0FBTyxNQUFNaUIsNkJBQTZCLE9BQ3hDdkMsU0FDQUMsZ0JBQ0FjLE1BQ0F5QjtJQUVBOUMsb0JBQW9CcUI7SUFDcEJsQixrQkFBa0IyQztJQUNsQi9CO0lBQ0EsTUFBTWdDLFFBQVE3QyxxQkFBcUJJO0lBQ25DLE1BQU0wQyxRQUFRdEQ7SUFDZCxNQUFNdUQsVUFBVSxNQUFNRixNQUFNOUIsV0FBVyxDQUFDLE9BQU9aO1FBQzdDLE1BQU1HLFNBQVMsTUFBTUosb0JBQW9CQyxJQUFJQyxTQUFTQztRQUN0RCxNQUFNMkMsTUFBTSxNQUFNN0MsR0FBR0ssR0FBRyxDQUFzQix1QkFBdUJIO1FBQ3JFLElBQUcyQyxLQUFLN0IsUUFBUSxDQUFDO1lBQUM7WUFBWTtTQUFxQixDQUFDOEIsUUFBUSxDQUFDRCxJQUFJdEIsTUFBTSxJQUFJLEtBQUs7WUFDOUUsTUFBTSxJQUFJZixNQUFNO1FBQ2xCO1FBQ0EsSUFBR3FDLEtBQUtFLGdCQUFnQixBQUFDLENBQUEsTUFBTS9DLEdBQUdzQixJQUFJLENBQWlCLDJCQUEyQjtZQUFDcEI7WUFBZ0JxQixRQUFRO1FBQVMsRUFBQyxFQUFHYyxJQUFJLENBQUMsQ0FBQ0MsTUFBUUEsSUFBSUMsSUFBSSxLQUFLLFNBQVM7WUFDMUosTUFBTSxJQUFJL0IsTUFBTTtRQUNsQjtRQUNBLE1BQU13QyxXQUFXSCxLQUFLSTtRQUN0QixJQUFHRCxVQUFVRSxXQUFXRixTQUFTRSxPQUFPLENBQUNDLFNBQVMsR0FBR0MsS0FBS0MsR0FBRyxJQUFJO1lBQy9ELElBQUdMLFNBQVNoQyxJQUFJLEtBQUtBLE1BQU07Z0JBQ3pCLE1BQU0sSUFBSVIsTUFBTTtZQUNsQjtZQUNBLE9BQU87Z0JBQUM4QyxRQUFRTixTQUFTRSxPQUFPLENBQUNLLEdBQUc7WUFBQTtRQUN0QztRQUNBLElBQUdQLFlBQVlBLFNBQVNRLFlBQVksR0FBR0osS0FBS0MsR0FBRyxJQUFJO1lBQ2pELE1BQU0sSUFBSTdDLE1BQU07UUFDbEI7UUFDQSxtRkFBbUY7UUFDbkYsSUFBR3dDLFlBQVksQ0FBQ0EsU0FBU0UsT0FBTyxJQUFJRixTQUFTaEMsSUFBSSxLQUFLQSxNQUFNO1lBQzFELE1BQU0sSUFBSVIsTUFBTTtRQUNsQjtRQUNBLE1BQU1pRCxhQUFhVCxXQUFXQSxTQUFTUyxVQUFVLEdBQUdDLE9BQU9DLFFBQVFYLFNBQVNFLE9BQU8sS0FBSztRQUN4RixNQUFNVSxXQUFXbEUsb0JBQW9Cc0IsTUFBTSxNQUFNdkIsa0JBQWtCTyxJQUFJRSxpQkFBaUJlLFVBQVU7UUFDbEcsTUFBTWdDLFdBQ0pELFlBQVksQ0FBQ0EsU0FBU0UsT0FBTyxHQUN6QjtZQUFDLEdBQUdGLFFBQVE7WUFBRVEsY0FBY0osS0FBS0MsR0FBRyxLQUFLO1lBQU9WO1FBQUssSUFDckQ7WUFDQWM7WUFDQUksS0FBS2pFLGdCQUFnQixZQUFZTSxnQkFBZ0I0RCxPQUFPTDtZQUN4REQsY0FBY0osS0FBS0MsR0FBRyxLQUFLO1lBQzNCVjtZQUNBM0I7WUFDQTRDO1lBQ0FHLFVBQVU1RCxPQUFPNkQsWUFBWSxDQUFDL0IsUUFBUTtRQUN4QztRQUNKLE1BQU1wQixVQUErQjtZQUNuQyxHQUFHZ0MsR0FBRztZQUNOSTtZQUNBZ0IsWUFBWXBCLEtBQUtvQixjQUFjO1lBQy9CL0Q7UUFDRjtRQUNBLE1BQU1GLEdBQUdrRSxHQUFHLENBQUMsdUJBQXVCaEUsZ0JBQWdCVyxTQUFTZ0M7UUFDN0QsT0FBTztZQUFDaEM7WUFBU0osT0FBT04sT0FBT00sS0FBSztRQUFBO0lBQ3RDO0lBQ0EsSUFBRyxZQUFZbUMsU0FBUztRQUN0QixPQUFPO1lBQUNXLEtBQUtYLFFBQVFVLE1BQU07UUFBQztJQUM5QjtJQUNBLE1BQU1hLFNBQVMsT0FBT0MsUUFDcEIxQixNQUFNOUIsV0FBVyxDQUFDLE9BQU9aO1lBQ3ZCLE1BQU1xRSxVQUFVLE1BQU1yRSxHQUFHSyxHQUFHLENBQXNCLHVCQUF1Qkg7WUFDekUsSUFBR21FLFNBQVNwQixVQUFVTixVQUFVQSxPQUFPO2dCQUNyQyxNQUFNLElBQUluQyxNQUFNO1lBQ2xCO1lBQ0EsTUFBTVIsR0FBR2tFLEdBQUcsQ0FBQyx1QkFBdUJoRSxnQkFBZ0I7Z0JBQUMsR0FBR21FLE9BQU87Z0JBQUUsR0FBR0QsS0FBSztZQUFBLEdBQUdDO1FBQzlFO0lBQ0YsSUFBSTtRQUNGLE1BQU1DLFdBQVcsTUFBTS9FO1FBQ3ZCLElBQUksRUFBQzBFLFVBQVUsRUFBQyxHQUFJckIsUUFBUS9CLE9BQU87UUFDbkMsSUFBRyxDQUFDb0QsWUFBWTtZQUNkQSxhQUFhLE1BQU1LLFNBQVNDLFFBQVEsQ0FBQ3JFLGdCQUFnQjBDLFFBQVFuQyxLQUFLO1lBQ2xFLE1BQU0wRCxPQUFPO2dCQUFDRjtZQUFVO1FBQzFCO1FBQ0EsSUFBRyxNQUFNSyxTQUFTRSxRQUFRLENBQUNQLGFBQWE7WUFDdEMsTUFBTSxJQUFJekQsTUFBTTtRQUNsQjtRQUNBLE1BQU1pRSxVQUFVN0IsUUFBUS9CLE9BQU8sQ0FBRW9DLFFBQVE7UUFDekMsTUFBTVAsTUFBTTlCLFdBQVcsQ0FBQyxPQUFPWjtZQUM3QixNQUFNRCxvQkFBb0JDLElBQUlDLFNBQVNDO1lBQ3ZDLE1BQU1tRSxVQUFVLE1BQU1yRSxHQUFHSyxHQUFHLENBQXNCLHVCQUF1Qkg7WUFDekUsSUFBR21FLFNBQVNwQixVQUFVTixVQUFVQSxPQUFPO2dCQUNyQyxNQUFNLElBQUluQyxNQUFNO1lBQ2xCO1FBQ0Y7UUFDQSxNQUFNMEMsVUFBVSxNQUFNb0IsU0FBU3JCLFFBQVEsQ0FBQ2dCLFlBQVlRLFFBQVF6RCxJQUFJLEVBQUV5RCxRQUFRYixRQUFRLEVBQUVhLFFBQVFaLEdBQUc7UUFDL0YsbUVBQW1FO1FBQ25FLE1BQU1NLE9BQU87WUFBQ2xCLFVBQVU7Z0JBQUMsR0FBR3dCLE9BQU87Z0JBQUVqQixjQUFjO2dCQUFHYixPQUFPO2dCQUFJTztZQUFPO1FBQUM7UUFDekUsSUFBR0EsUUFBUUMsU0FBUyxJQUFJQyxLQUFLQyxHQUFHLE1BQU0sQ0FBQ0gsUUFBUUssR0FBRyxFQUFFO1lBQ2xELE1BQU0sSUFBSS9DLE1BQU07UUFDbEI7UUFDQSxPQUFPO1lBQUMrQyxLQUFLTCxRQUFRSyxHQUFHO1FBQUE7SUFDMUIsRUFBRSxPQUFNbUIsT0FBTztRQUNiLE1BQU1oQyxNQUFNOUIsV0FBVyxDQUFDLE9BQU9aO1lBQzdCLE1BQU1xRSxVQUFVLE1BQU1yRSxHQUFHSyxHQUFHLENBQXNCLHVCQUF1Qkg7WUFDekUsSUFBR21FLFNBQVNwQixVQUFVTixVQUFVQSxPQUFPO2dCQUNyQyxNQUFNM0MsR0FBR2tFLEdBQUcsQ0FDVix1QkFDQWhFLGdCQUNBO29CQUFDLEdBQUdtRSxPQUFPO29CQUFFcEIsVUFBVTt3QkFBQyxHQUFHb0IsUUFBUXBCLFFBQVE7d0JBQUVPLGNBQWM7d0JBQUdiLE9BQU87b0JBQUU7Z0JBQUMsR0FDeEUwQjtZQUVKO1FBQ0Y7UUFDQSxJQUNFSyxpQkFBaUJsRSxTQUNqQjtZQUFDO1lBQXVCO1lBQW9CO1lBQXdCO1NBQXNCLENBQUNzQyxRQUFRLENBQ2pHNEIsTUFBTUMsT0FBTyxHQUVmO1lBQ0EsTUFBTUQ7UUFDUjtRQUNBLE1BQU0sSUFBSWxFLE1BQU07SUFDbEI7QUFDRixFQUFFO0FBRUYsT0FBTyxNQUFNb0Usa0NBQWtDLE9BQzdDM0UsU0FDQUM7SUFFQVE7SUFDQSxNQUFNdUQsYUFBYSxNQUFNcEUscUJBQXFCSSxTQUFTVyxXQUFXLENBQUMsT0FBT1o7UUFDeEUsTUFBTUQsb0JBQW9CQyxJQUFJQyxTQUFTQztRQUN2QyxNQUFNVyxVQUFVLE1BQU1iLEdBQUdLLEdBQUcsQ0FBc0IsdUJBQXVCSDtRQUN6RSxJQUFHLENBQUNXLFNBQVNvRCxZQUFZO1lBQ3ZCLE1BQU0sSUFBSXpELE1BQU07UUFDbEI7UUFDQSxPQUFPSyxRQUFRb0QsVUFBVTtJQUMzQjtJQUNBLE1BQU1LLFdBQVcsTUFBTS9FO0lBQ3ZCLE9BQU87UUFBQ2dFLEtBQUssTUFBTWUsU0FBU08sTUFBTSxDQUFDWjtJQUFXO0FBQ2hELEVBQUU7QUFFRixPQUFPLE1BQU1hLDhCQUE4QixPQUN6QzdFLFNBQ0FDLGdCQUNBNkU7SUFFQXJFO0lBQ0EsTUFBTWdDLFFBQVE3QyxxQkFBcUJJO0lBQ25DLE1BQU0rRSxTQUFTLE1BQU10QyxNQUFNOUIsV0FBVyxDQUFDLE9BQU9aO1FBQzVDLE1BQU1HLFNBQVMsTUFBTUosb0JBQW9CQyxJQUFJQyxTQUFTQztRQUN0RCxNQUFNK0UsU0FBUyxNQUFNakYsR0FBR0ssR0FBRyxDQUN6QiwyQkFDQVQsZ0JBQWdCTSxnQkFBZ0JKLGtCQUFrQmlGLE9BQU96RSxNQUFNO1FBRWpFLElBQ0UsQ0FBQzJFLFVBQ0RBLE9BQU9oRCxRQUFRLEtBQUs4QyxPQUFPRyxnQkFBZ0IsSUFDM0MsQ0FBQztZQUFDO1lBQVM7U0FBUyxDQUFDcEMsUUFBUSxDQUFDaUMsT0FBT3BELElBQUksS0FDekMsQ0FBQztZQUFDO1lBQVU7U0FBYyxDQUFDbUIsUUFBUSxDQUFDaUMsT0FBT3hELE1BQU0sR0FDakQ7WUFDQSxNQUFNLElBQUlmLE1BQU07UUFDbEI7UUFDQSxJQUNFeUUsT0FBTzNFLE1BQU0sS0FBS0gsT0FBTzZELFlBQVksQ0FBQ21CLFdBQVcsSUFDaERKLENBQUFBLE9BQU9wRCxJQUFJLEtBQUssV0FBV29ELE9BQU94RCxNQUFNLEtBQUssUUFBTyxHQUNyRDtZQUNBLE1BQU0sSUFBSWYsTUFBTTtRQUNsQjtRQUNBLE1BQU1KLE9BQU8sTUFBTUosR0FBR0ssR0FBRyxDQUE0QyxTQUFTMEUsT0FBT3pFLE1BQU07UUFDM0YsSUFBR3lFLE9BQU94RCxNQUFNLEtBQUssWUFBYSxDQUFBLENBQUNuQixNQUFNZ0YsVUFBVSxDQUFDaEYsS0FBS0csYUFBYSxBQUFELEdBQUk7WUFDdkUsTUFBTSxJQUFJQyxNQUFNO1FBQ2xCO1FBQ0EsTUFBTUssVUFBVSxNQUFNYixHQUFHSyxHQUFHLENBQXNCLHVCQUF1Qkg7UUFDekUsSUFBRyxDQUFDVyxTQUFTb0QsY0FBY3BELFFBQVFVLE1BQU0sS0FBSyxVQUFVO1lBQ3RELE1BQU0sSUFBSWYsTUFBTTtRQUNsQjtRQUNBLE1BQU1vRCxXQUFXMUMsS0FBS0MsR0FBRyxDQUN2QixHQUNBLEFBQUMsTUFBTTFCLGtCQUFrQk8sSUFBSUUsa0JBQzNCd0QsT0FBT3FCLE9BQU94RCxNQUFNLEtBQUssWUFDekJtQyxPQUFPdUIsT0FBTzFELE1BQU0sS0FBSyxZQUN6QjtRQUVKLE9BQU87WUFBQzBDLFlBQVlwRCxRQUFRb0QsVUFBVTtZQUFFRCxjQUFjN0QsT0FBTzZELFlBQVk7WUFBRUo7UUFBUTtJQUNyRjtJQUNBLE1BQU1VLFdBQVcsTUFBTS9FO0lBQ3ZCLE1BQU13RCxlQUFlLE1BQU11QixTQUFTRSxRQUFRLENBQUNRLE9BQU9mLFVBQVU7SUFDOUQsSUFBRyxDQUFDbEIsZ0JBQWdCQSxhQUFheEIsTUFBTSxLQUFLLFVBQVU7UUFDcEQsTUFBTSxJQUFJZixNQUFNO0lBQ2xCO0lBQ0EsTUFBTTZFLGNBQWNqQyxLQUFLQyxHQUFHO0lBQzVCLE1BQU1pQyxpQkFBaUIsTUFBTWhCLFNBQVNpQixPQUFPLENBQzNDeEMsY0FDQUEsYUFBYS9CLElBQUksRUFDakJnRSxPQUFPcEIsUUFBUSxFQUNmeUI7SUFFRixNQUFNRyxRQUF5QjtRQUM3QkMsVUFBVTtRQUNWdEMsV0FBV2tDLGNBQWM7UUFDekJLLHNCQUFzQlYsT0FBT2hCLFlBQVksQ0FBQy9CLFFBQVE7UUFDbERxRDtRQUNBMUIsVUFBVW9CLE9BQU9wQixRQUFRO1FBQ3pCK0IsU0FBU3RHO0lBQ1g7SUFDQSxNQUFNcUQsTUFBTTlCLFdBQVcsQ0FBQyxPQUFPWjtRQUM3QixNQUFNRyxTQUFTLE1BQU1KLG9CQUFvQkMsSUFBSUMsU0FBU0M7UUFDdEQsSUFBR0MsT0FBTzZELFlBQVksQ0FBQy9CLFFBQVEsS0FBS3VELE1BQU1FLG9CQUFvQixFQUFFO1lBQzlELE1BQU0sSUFBSWxGLE1BQU07UUFDbEI7UUFDQSxNQUFNUixHQUFHa0UsR0FBRyxDQUFDLDZCQUE2QnNCLE1BQU1HLE9BQU8sRUFBRTtZQUN2RCxHQUFHSCxLQUFLO1lBQ1JIO1lBQ0FILGtCQUFrQkgsT0FBT0csZ0JBQWdCO1lBQ3pDaEY7WUFDQXlCLE1BQU1vRCxPQUFPcEQsSUFBSTtZQUNqQkosUUFBUXdELE9BQU94RCxNQUFNO1lBQ3JCcUUsTUFBTTtZQUNOdEYsUUFBUXlFLE9BQU96RSxNQUFNO1FBQ3ZCO0lBQ0Y7SUFDQSxPQUFPa0Y7QUFDVCxFQUFFIn0=
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BillingMode, BillingProvider, VerifiedBillingEvent } from './types.js';
|
|
2
|
+
export declare const organizationBillingMode: () => BillingMode;
|
|
3
|
+
export declare const verifyOrganizationBillingEvent: (body: string | Buffer, signature: string) => VerifiedBillingEvent;
|
|
4
|
+
export declare const getOrganizationBillingProvider: () => Promise<BillingProvider>;
|