@nlabs/reaktor 1.16.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +186 -0
  2. package/docs/ASSISTANT.md +138 -0
  3. package/docs/GENERATION.md +29 -2
  4. package/docs/NATIVE_PUSH.md +56 -0
  5. package/lib/actions/alfredFaq.d.ts +80 -0
  6. package/lib/actions/alfredFaq.js +206 -0
  7. package/lib/actions/contentGeneration.d.ts +4 -1
  8. package/lib/actions/contentGeneration.js +83 -27
  9. package/lib/actions/contentGenerationErrors.js +1 -1
  10. package/lib/actions/conversations.d.ts +1 -1
  11. package/lib/actions/conversations.js +19 -9
  12. package/lib/actions/crud.js +26 -1
  13. package/lib/actions/index.d.ts +2 -0
  14. package/lib/actions/index.js +3 -1
  15. package/lib/actions/messages.js +23 -7
  16. package/lib/actions/phoneSupport.d.ts +18 -0
  17. package/lib/actions/phoneSupport.js +170 -0
  18. package/lib/actions/users.js +57 -4
  19. package/lib/assistant/core.d.ts +53 -0
  20. package/lib/assistant/core.js +123 -0
  21. package/lib/assistant/faq.d.ts +26 -0
  22. package/lib/assistant/faq.js +238 -0
  23. package/lib/assistant/faqCore.d.ts +23 -0
  24. package/lib/assistant/faqCore.js +20 -0
  25. package/lib/assistant/index.d.ts +7 -0
  26. package/lib/assistant/index.js +5 -0
  27. package/lib/assistant/service.d.ts +35 -0
  28. package/lib/assistant/service.js +201 -0
  29. package/lib/config.js +3 -2
  30. package/lib/durableChat/conversations.d.ts +62 -0
  31. package/lib/durableChat/conversations.js +729 -0
  32. package/lib/durableChat/errors.d.ts +6 -0
  33. package/lib/durableChat/errors.js +11 -0
  34. package/lib/durableChat/events.d.ts +22 -0
  35. package/lib/durableChat/events.js +50 -0
  36. package/lib/durableChat/index.d.ts +8 -0
  37. package/lib/durableChat/index.js +10 -0
  38. package/lib/durableChat/membership.d.ts +24 -0
  39. package/lib/durableChat/membership.js +85 -0
  40. package/lib/durableChat/messageTypes.d.ts +76 -0
  41. package/lib/durableChat/messageTypes.js +3 -0
  42. package/lib/durableChat/messages.d.ts +16 -0
  43. package/lib/durableChat/messages.js +257 -0
  44. package/lib/durableChat/transaction.d.ts +10 -0
  45. package/lib/durableChat/transaction.js +53 -0
  46. package/lib/durableChat/types.d.ts +81 -0
  47. package/lib/durableChat/types.js +3 -0
  48. package/lib/index.d.ts +4 -4
  49. package/lib/index.js +5 -3
  50. package/lib/lambdas/actions/websockets.js +4 -4
  51. package/lib/nativePush/graphql.d.ts +14 -0
  52. package/lib/nativePush/graphql.js +105 -0
  53. package/lib/nativePush/index.d.ts +7 -0
  54. package/lib/nativePush/index.js +9 -0
  55. package/lib/nativePush/migrations.d.ts +2 -0
  56. package/lib/nativePush/migrations.js +36 -0
  57. package/lib/nativePush/nativePushContract.fixture.d.ts +22 -0
  58. package/lib/nativePush/nativePushContract.fixture.js +27 -0
  59. package/lib/nativePush/payload.d.ts +2 -0
  60. package/lib/nativePush/payload.js +106 -0
  61. package/lib/nativePush/repository.d.ts +9 -0
  62. package/lib/nativePush/repository.js +120 -0
  63. package/lib/nativePush/service.d.ts +2 -0
  64. package/lib/nativePush/service.js +110 -0
  65. package/lib/nativePush/snsProvider.d.ts +17 -0
  66. package/lib/nativePush/snsProvider.js +165 -0
  67. package/lib/nativePush/types.d.ts +89 -0
  68. package/lib/nativePush/types.js +3 -0
  69. package/lib/organizations/accountLifecycle.d.ts +7 -0
  70. package/lib/organizations/accountLifecycle.js +106 -0
  71. package/lib/organizations/authorization.d.ts +9 -0
  72. package/lib/organizations/authorization.js +40 -0
  73. package/lib/organizations/billing.d.ts +38 -0
  74. package/lib/organizations/billing.js +277 -0
  75. package/lib/organizations/billingProvider.d.ts +4 -0
  76. package/lib/organizations/billingProvider.js +287 -0
  77. package/lib/organizations/billingUpdates.d.ts +9 -0
  78. package/lib/organizations/billingUpdates.js +388 -0
  79. package/lib/organizations/index.d.ts +10 -0
  80. package/lib/organizations/index.js +12 -0
  81. package/lib/organizations/mail.d.ts +10 -0
  82. package/lib/organizations/mail.js +60 -0
  83. package/lib/organizations/memberDirectory.d.ts +15 -0
  84. package/lib/organizations/memberDirectory.js +28 -0
  85. package/lib/organizations/membership.d.ts +19 -0
  86. package/lib/organizations/membership.js +248 -0
  87. package/lib/organizations/passwordRecovery.d.ts +9 -0
  88. package/lib/organizations/passwordRecovery.js +50 -0
  89. package/lib/organizations/plans.d.ts +6 -0
  90. package/lib/organizations/plans.js +40 -0
  91. package/lib/organizations/providerPagination.d.ts +6 -0
  92. package/lib/organizations/providerPagination.js +23 -0
  93. package/lib/organizations/reconciliation.d.ts +11 -0
  94. package/lib/organizations/reconciliation.js +400 -0
  95. package/lib/organizations/signup.d.ts +25 -0
  96. package/lib/organizations/signup.js +169 -0
  97. package/lib/organizations/store.d.ts +25 -0
  98. package/lib/organizations/store.js +167 -0
  99. package/lib/organizations/types.d.ts +138 -0
  100. package/lib/organizations/types.js +3 -0
  101. package/lib/organizations/verification.d.ts +3 -0
  102. package/lib/organizations/verification.js +51 -0
  103. package/package.json +16 -3
@@ -0,0 +1,110 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { buildNativePushPayload } from './payload.js';
3
+ import { createSnsPushProvider, NativePushProviderError } from './snsProvider.js';
4
+ const validId = (value)=>typeof value === 'string' && value.length > 0 && value.length <= 256;
5
+ const checkActor = (actor)=>{
6
+ if (!validId(actor?.userId) || !validId(actor?.sessionId)) {
7
+ throw new Error('Authenticated push session required');
8
+ }
9
+ };
10
+ export const createNativePushService = (options)=>{
11
+ const { canDeliver, isSessionEligible, repository, scope } = options;
12
+ if (!validId(scope?.appId) || !validId(scope?.environment)) {
13
+ throw new Error('Invalid push scope');
14
+ }
15
+ const provider = createSnsPushProvider(options);
16
+ const now = options.now ?? (()=>new Date());
17
+ const sessionRequired = async (actor)=>{
18
+ checkActor(actor);
19
+ if (!await isSessionEligible(scope, actor)) {
20
+ throw new Error('Active push session required');
21
+ }
22
+ };
23
+ return {
24
+ register: async (actor, input)=>{
25
+ await sessionRequired(actor);
26
+ if (!validId(input?.installationId) || !validId(input?.platform) || typeof input.token !== 'string' || !input.token || input.token.length > 8192) {
27
+ throw new Error('Invalid push registration');
28
+ }
29
+ const { token } = input;
30
+ const safeInput = {
31
+ ...input.platform === 'IOS' && {
32
+ apnsEnvironment: input.apnsEnvironment
33
+ },
34
+ installationId: input.installationId,
35
+ platform: input.platform
36
+ };
37
+ const tokenHash = createHash('sha256').update(token).digest('hex');
38
+ const revision = await repository.reserveBinding(scope, actor, safeInput, tokenHash);
39
+ // Create/reconcile by token, never retarget an installation's previous endpoint.
40
+ // A delayed old operation must not change the token on a newer SNS binding.
41
+ const arn = await provider.ensureEndpoint(input);
42
+ await sessionRequired(actor);
43
+ const registration = await repository.replaceBinding(scope, actor, safeInput, arn, tokenHash, revision);
44
+ try {
45
+ await sessionRequired(actor);
46
+ return registration;
47
+ } catch (error) {
48
+ await repository.disableBinding(scope, actor, registration.registrationId, registration.revision);
49
+ throw error;
50
+ }
51
+ },
52
+ send: async (userId, notification, pushOptions = {})=>{
53
+ if (!validId(userId)) {
54
+ throw new Error('Invalid push recipient');
55
+ }
56
+ const results = [];
57
+ const records = await repository.listEnabled(scope, userId);
58
+ // Sequential dispatch bounds provider load and keeps eligibility checks near each publish.
59
+ /* eslint-disable no-await-in-loop */ for (const registration of records){
60
+ const result = {
61
+ registrationId: registration.registrationId,
62
+ status: 'SKIPPED'
63
+ };
64
+ results.push(result);
65
+ if (!registration.enabled || registration.appId !== scope.appId || registration.environment !== scope.environment || registration.userId !== userId) {
66
+ continue;
67
+ }
68
+ try {
69
+ if (canDeliver && !await canDeliver(registration, notification)) {
70
+ continue;
71
+ }
72
+ if (!await isSessionEligible(scope, registration) || !await repository.isCurrent(registration)) {
73
+ continue;
74
+ }
75
+ const payload = buildNativePushPayload(registration.platform, registration.apnsEnvironment, {
76
+ notification,
77
+ recipientUserId: userId,
78
+ scope
79
+ }, pushOptions, now());
80
+ const response = await provider.publish(registration.endpointArn, payload);
81
+ result.status = 'ACCEPTED';
82
+ result.providerMessageId = response.messageId;
83
+ } catch (error) {
84
+ const code = error instanceof NativePushProviderError ? error.code : 'DeliveryFailed';
85
+ result.code = code;
86
+ if ([
87
+ 'EndpointDisabledException',
88
+ 'NotFoundException'
89
+ ].includes(code)) {
90
+ result.status = 'INVALID_ENDPOINT';
91
+ await repository.disableBinding(scope, registration, registration.registrationId, registration.revision);
92
+ } else {
93
+ result.status = error instanceof NativePushProviderError && error.transient ? 'TRANSIENT_FAILURE' : 'PERMANENT_FAILURE';
94
+ }
95
+ }
96
+ }
97
+ /* eslint-enable no-await-in-loop */ return results;
98
+ },
99
+ unregister: async (actor, registrationId, revision)=>{
100
+ checkActor(actor);
101
+ if (!validId(registrationId) || revision !== undefined && (!Number.isInteger(revision) || revision < 1)) {
102
+ throw new Error('Invalid push registration identity');
103
+ }
104
+ // Local binding only: shared SNS endpoints must not be disabled by logout.
105
+ return repository.disableBinding(scope, actor, registrationId, revision);
106
+ }
107
+ };
108
+ };
109
+
110
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvbmF0aXZlUHVzaC9zZXJ2aWNlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Y3JlYXRlSGFzaH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuXG5pbXBvcnQge2J1aWxkTmF0aXZlUHVzaFBheWxvYWR9IGZyb20gJy4vcGF5bG9hZC5qcyc7XG5pbXBvcnQge2NyZWF0ZVNuc1B1c2hQcm92aWRlciwgTmF0aXZlUHVzaFByb3ZpZGVyRXJyb3J9IGZyb20gJy4vc25zUHJvdmlkZXIuanMnO1xuXG5pbXBvcnQgdHlwZSB7RGVsaXZlcnlPdXRjb21lLCBOYXRpdmVQdXNoU2VydmljZSwgTmF0aXZlUHVzaFNlcnZpY2VPcHRpb25zLCBQdXNoQWN0b3J9IGZyb20gJy4vdHlwZXMuanMnO1xuXG5jb25zdCB2YWxpZElkID0gKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgc3RyaW5nID0+IHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUubGVuZ3RoID4gMCAmJiB2YWx1ZS5sZW5ndGggPD0gMjU2O1xuY29uc3QgY2hlY2tBY3RvciA9IChhY3RvcjogUHVzaEFjdG9yKTogdm9pZCA9PiB7XG4gIGlmKCF2YWxpZElkKGFjdG9yPy51c2VySWQpIHx8ICF2YWxpZElkKGFjdG9yPy5zZXNzaW9uSWQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdBdXRoZW50aWNhdGVkIHB1c2ggc2Vzc2lvbiByZXF1aXJlZCcpO1xuICB9XG59O1xuXG5leHBvcnQgY29uc3QgY3JlYXRlTmF0aXZlUHVzaFNlcnZpY2UgPSAob3B0aW9uczogTmF0aXZlUHVzaFNlcnZpY2VPcHRpb25zKTogTmF0aXZlUHVzaFNlcnZpY2UgPT4ge1xuICBjb25zdCB7Y2FuRGVsaXZlciwgaXNTZXNzaW9uRWxpZ2libGUsIHJlcG9zaXRvcnksIHNjb3BlfSA9IG9wdGlvbnM7XG4gIGlmKCF2YWxpZElkKHNjb3BlPy5hcHBJZCkgfHwgIXZhbGlkSWQoc2NvcGU/LmVudmlyb25tZW50KSkge1xuICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBwdXNoIHNjb3BlJyk7XG4gIH1cbiAgY29uc3QgcHJvdmlkZXIgPSBjcmVhdGVTbnNQdXNoUHJvdmlkZXIob3B0aW9ucyk7XG4gIGNvbnN0IG5vdyA9IG9wdGlvbnMubm93ID8/ICgoKSA9PiBuZXcgRGF0ZSgpKTtcbiAgY29uc3Qgc2Vzc2lvblJlcXVpcmVkID0gYXN5bmMgKGFjdG9yOiBQdXNoQWN0b3IpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICBjaGVja0FjdG9yKGFjdG9yKTtcbiAgICBpZighYXdhaXQgaXNTZXNzaW9uRWxpZ2libGUoc2NvcGUsIGFjdG9yKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBY3RpdmUgcHVzaCBzZXNzaW9uIHJlcXVpcmVkJyk7XG4gICAgfVxuICB9O1xuICByZXR1cm4ge1xuICAgIHJlZ2lzdGVyOiBhc3luYyAoYWN0b3IsIGlucHV0KSA9PiB7XG4gICAgICBhd2FpdCBzZXNzaW9uUmVxdWlyZWQoYWN0b3IpO1xuICAgICAgaWYoIXZhbGlkSWQoaW5wdXQ/Lmluc3RhbGxhdGlvbklkKSB8fCAhdmFsaWRJZChpbnB1dD8ucGxhdGZvcm0pIHx8XG4gICAgICAgIHR5cGVvZiBpbnB1dC50b2tlbiAhPT0gJ3N0cmluZycgfHwgIWlucHV0LnRva2VuIHx8IGlucHV0LnRva2VuLmxlbmd0aCA+IDgxOTIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHB1c2ggcmVnaXN0cmF0aW9uJyk7XG4gICAgICB9XG4gICAgICBjb25zdCB7dG9rZW59ID0gaW5wdXQ7XG4gICAgICBjb25zdCBzYWZlSW5wdXQgPSB7XG4gICAgICAgIC4uLihpbnB1dC5wbGF0Zm9ybSA9PT0gJ0lPUycgJiYge2FwbnNFbnZpcm9ubWVudDogaW5wdXQuYXBuc0Vudmlyb25tZW50fSksXG4gICAgICAgIGluc3RhbGxhdGlvbklkOiBpbnB1dC5pbnN0YWxsYXRpb25JZCxcbiAgICAgICAgcGxhdGZvcm06IGlucHV0LnBsYXRmb3JtXG4gICAgICB9O1xuICAgICAgY29uc3QgdG9rZW5IYXNoID0gY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKHRva2VuKS5kaWdlc3QoJ2hleCcpO1xuICAgICAgY29uc3QgcmV2aXNpb24gPSBhd2FpdCByZXBvc2l0b3J5LnJlc2VydmVCaW5kaW5nKHNjb3BlLCBhY3Rvciwgc2FmZUlucHV0LCB0b2tlbkhhc2gpO1xuICAgICAgLy8gQ3JlYXRlL3JlY29uY2lsZSBieSB0b2tlbiwgbmV2ZXIgcmV0YXJnZXQgYW4gaW5zdGFsbGF0aW9uJ3MgcHJldmlvdXMgZW5kcG9pbnQuXG4gICAgICAvLyBBIGRlbGF5ZWQgb2xkIG9wZXJhdGlvbiBtdXN0IG5vdCBjaGFuZ2UgdGhlIHRva2VuIG9uIGEgbmV3ZXIgU05TIGJpbmRpbmcuXG4gICAgICBjb25zdCBhcm4gPSBhd2FpdCBwcm92aWRlci5lbnN1cmVFbmRwb2ludChpbnB1dCk7XG4gICAgICBhd2FpdCBzZXNzaW9uUmVxdWlyZWQoYWN0b3IpO1xuICAgICAgY29uc3QgcmVnaXN0cmF0aW9uID0gYXdhaXQgcmVwb3NpdG9yeS5yZXBsYWNlQmluZGluZyhzY29wZSwgYWN0b3IsIHNhZmVJbnB1dCwgYXJuLFxuICAgICAgICB0b2tlbkhhc2gsIHJldmlzaW9uKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHNlc3Npb25SZXF1aXJlZChhY3Rvcik7XG4gICAgICAgIHJldHVybiByZWdpc3RyYXRpb247XG4gICAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgIGF3YWl0IHJlcG9zaXRvcnkuZGlzYWJsZUJpbmRpbmcoc2NvcGUsIGFjdG9yLCByZWdpc3RyYXRpb24ucmVnaXN0cmF0aW9uSWQsIHJlZ2lzdHJhdGlvbi5yZXZpc2lvbik7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuICAgIH0sXG4gICAgc2VuZDogYXN5bmMgKHVzZXJJZCwgbm90aWZpY2F0aW9uLCBwdXNoT3B0aW9ucyA9IHt9KSA9PiB7XG4gICAgICBpZighdmFsaWRJZCh1c2VySWQpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBwdXNoIHJlY2lwaWVudCcpO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVzdWx0czogRGVsaXZlcnlPdXRjb21lW10gPSBbXTtcbiAgICAgIGNvbnN0IHJlY29yZHMgPSBhd2FpdCByZXBvc2l0b3J5Lmxpc3RFbmFibGVkKHNjb3BlLCB1c2VySWQpO1xuICAgICAgLy8gU2VxdWVudGlhbCBkaXNwYXRjaCBib3VuZHMgcHJvdmlkZXIgbG9hZCBhbmQga2VlcHMgZWxpZ2liaWxpdHkgY2hlY2tzIG5lYXIgZWFjaCBwdWJsaXNoLlxuICAgICAgLyogZXNsaW50LWRpc2FibGUgbm8tYXdhaXQtaW4tbG9vcCAqL1xuICAgICAgZm9yKGNvbnN0IHJlZ2lzdHJhdGlvbiBvZiByZWNvcmRzKSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdDogRGVsaXZlcnlPdXRjb21lID0ge3JlZ2lzdHJhdGlvbklkOiByZWdpc3RyYXRpb24ucmVnaXN0cmF0aW9uSWQsIHN0YXR1czogJ1NLSVBQRUQnfTtcbiAgICAgICAgcmVzdWx0cy5wdXNoKHJlc3VsdCk7XG4gICAgICAgIGlmKCFyZWdpc3RyYXRpb24uZW5hYmxlZCB8fCByZWdpc3RyYXRpb24uYXBwSWQgIT09IHNjb3BlLmFwcElkIHx8XG4gICAgICAgICAgcmVnaXN0cmF0aW9uLmVudmlyb25tZW50ICE9PSBzY29wZS5lbnZpcm9ubWVudCB8fCByZWdpc3RyYXRpb24udXNlcklkICE9PSB1c2VySWQpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmKGNhbkRlbGl2ZXIgJiYgIWF3YWl0IGNhbkRlbGl2ZXIocmVnaXN0cmF0aW9uLCBub3RpZmljYXRpb24pKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYoIWF3YWl0IGlzU2Vzc2lvbkVsaWdpYmxlKHNjb3BlLCByZWdpc3RyYXRpb24pIHx8ICFhd2FpdCByZXBvc2l0b3J5LmlzQ3VycmVudChyZWdpc3RyYXRpb24pKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgcGF5bG9hZCA9IGJ1aWxkTmF0aXZlUHVzaFBheWxvYWQocmVnaXN0cmF0aW9uLnBsYXRmb3JtLCByZWdpc3RyYXRpb24uYXBuc0Vudmlyb25tZW50LFxuICAgICAgICAgICAge25vdGlmaWNhdGlvbiwgcmVjaXBpZW50VXNlcklkOiB1c2VySWQsIHNjb3BlfSwgcHVzaE9wdGlvbnMsIG5vdygpKTtcbiAgICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHByb3ZpZGVyLnB1Ymxpc2gocmVnaXN0cmF0aW9uLmVuZHBvaW50QXJuLCBwYXlsb2FkKTtcbiAgICAgICAgICByZXN1bHQuc3RhdHVzID0gJ0FDQ0VQVEVEJztcbiAgICAgICAgICByZXN1bHQucHJvdmlkZXJNZXNzYWdlSWQgPSByZXNwb25zZS5tZXNzYWdlSWQ7XG4gICAgICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgICAgICBjb25zdCBjb2RlID0gZXJyb3IgaW5zdGFuY2VvZiBOYXRpdmVQdXNoUHJvdmlkZXJFcnJvciA/IGVycm9yLmNvZGUgOiAnRGVsaXZlcnlGYWlsZWQnO1xuICAgICAgICAgIHJlc3VsdC5jb2RlID0gY29kZTtcbiAgICAgICAgICBpZihbJ0VuZHBvaW50RGlzYWJsZWRFeGNlcHRpb24nLCAnTm90Rm91bmRFeGNlcHRpb24nXS5pbmNsdWRlcyhjb2RlKSkge1xuICAgICAgICAgICAgcmVzdWx0LnN0YXR1cyA9ICdJTlZBTElEX0VORFBPSU5UJztcbiAgICAgICAgICAgIGF3YWl0IHJlcG9zaXRvcnkuZGlzYWJsZUJpbmRpbmcoc2NvcGUsIHJlZ2lzdHJhdGlvbiwgcmVnaXN0cmF0aW9uLnJlZ2lzdHJhdGlvbklkLCByZWdpc3RyYXRpb24ucmV2aXNpb24pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXN1bHQuc3RhdHVzID0gZXJyb3IgaW5zdGFuY2VvZiBOYXRpdmVQdXNoUHJvdmlkZXJFcnJvciAmJiBlcnJvci50cmFuc2llbnRcbiAgICAgICAgICAgICAgPyAnVFJBTlNJRU5UX0ZBSUxVUkUnIDogJ1BFUk1BTkVOVF9GQUlMVVJFJztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIC8qIGVzbGludC1lbmFibGUgbm8tYXdhaXQtaW4tbG9vcCAqL1xuICAgICAgcmV0dXJuIHJlc3VsdHM7XG4gICAgfSxcbiAgICB1bnJlZ2lzdGVyOiBhc3luYyAoYWN0b3IsIHJlZ2lzdHJhdGlvbklkLCByZXZpc2lvbikgPT4ge1xuICAgICAgY2hlY2tBY3RvcihhY3Rvcik7XG4gICAgICBpZighdmFsaWRJZChyZWdpc3RyYXRpb25JZCkgfHwgKHJldmlzaW9uICE9PSB1bmRlZmluZWQgJiYgKCFOdW1iZXIuaXNJbnRlZ2VyKHJldmlzaW9uKSB8fCByZXZpc2lvbiA8IDEpKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcHVzaCByZWdpc3RyYXRpb24gaWRlbnRpdHknKTtcbiAgICAgIH1cbiAgICAgIC8vIExvY2FsIGJpbmRpbmcgb25seTogc2hhcmVkIFNOUyBlbmRwb2ludHMgbXVzdCBub3QgYmUgZGlzYWJsZWQgYnkgbG9nb3V0LlxuICAgICAgcmV0dXJuIHJlcG9zaXRvcnkuZGlzYWJsZUJpbmRpbmcoc2NvcGUsIGFjdG9yLCByZWdpc3RyYXRpb25JZCwgcmV2aXNpb24pO1xuICAgIH1cbiAgfTtcbn07XG4iXSwibmFtZXMiOlsiY3JlYXRlSGFzaCIsImJ1aWxkTmF0aXZlUHVzaFBheWxvYWQiLCJjcmVhdGVTbnNQdXNoUHJvdmlkZXIiLCJOYXRpdmVQdXNoUHJvdmlkZXJFcnJvciIsInZhbGlkSWQiLCJ2YWx1ZSIsImxlbmd0aCIsImNoZWNrQWN0b3IiLCJhY3RvciIsInVzZXJJZCIsInNlc3Npb25JZCIsIkVycm9yIiwiY3JlYXRlTmF0aXZlUHVzaFNlcnZpY2UiLCJvcHRpb25zIiwiY2FuRGVsaXZlciIsImlzU2Vzc2lvbkVsaWdpYmxlIiwicmVwb3NpdG9yeSIsInNjb3BlIiwiYXBwSWQiLCJlbnZpcm9ubWVudCIsInByb3ZpZGVyIiwibm93IiwiRGF0ZSIsInNlc3Npb25SZXF1aXJlZCIsInJlZ2lzdGVyIiwiaW5wdXQiLCJpbnN0YWxsYXRpb25JZCIsInBsYXRmb3JtIiwidG9rZW4iLCJzYWZlSW5wdXQiLCJhcG5zRW52aXJvbm1lbnQiLCJ0b2tlbkhhc2giLCJ1cGRhdGUiLCJkaWdlc3QiLCJyZXZpc2lvbiIsInJlc2VydmVCaW5kaW5nIiwiYXJuIiwiZW5zdXJlRW5kcG9pbnQiLCJyZWdpc3RyYXRpb24iLCJyZXBsYWNlQmluZGluZyIsImVycm9yIiwiZGlzYWJsZUJpbmRpbmciLCJyZWdpc3RyYXRpb25JZCIsInNlbmQiLCJub3RpZmljYXRpb24iLCJwdXNoT3B0aW9ucyIsInJlc3VsdHMiLCJyZWNvcmRzIiwibGlzdEVuYWJsZWQiLCJyZXN1bHQiLCJzdGF0dXMiLCJwdXNoIiwiZW5hYmxlZCIsImlzQ3VycmVudCIsInBheWxvYWQiLCJyZWNpcGllbnRVc2VySWQiLCJyZXNwb25zZSIsInB1Ymxpc2giLCJlbmRwb2ludEFybiIsInByb3ZpZGVyTWVzc2FnZUlkIiwibWVzc2FnZUlkIiwiY29kZSIsImluY2x1ZGVzIiwidHJhbnNpZW50IiwidW5yZWdpc3RlciIsInVuZGVmaW5lZCIsIk51bWJlciIsImlzSW50ZWdlciJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBUUEsVUFBVSxRQUFPLGNBQWM7QUFFdkMsU0FBUUMsc0JBQXNCLFFBQU8sZUFBZTtBQUNwRCxTQUFRQyxxQkFBcUIsRUFBRUMsdUJBQXVCLFFBQU8sbUJBQW1CO0FBSWhGLE1BQU1DLFVBQVUsQ0FBQ0MsUUFBb0MsT0FBT0EsVUFBVSxZQUFZQSxNQUFNQyxNQUFNLEdBQUcsS0FBS0QsTUFB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
@@ -0,0 +1,17 @@
1
+ import type { NativePushPayload, NativePushRegistrationInput, PlatformApplicationArns, SnsSender } from './types.js';
2
+ export declare class NativePushProviderError extends Error {
3
+ readonly code: string;
4
+ readonly transient: boolean;
5
+ constructor(code: string, transient?: boolean);
6
+ }
7
+ export declare const createSnsPushProvider: ({ sns, platformApplicationArns, delay }: {
8
+ delay?: (milliseconds: number) => Promise<void>;
9
+ platformApplicationArns: PlatformApplicationArns;
10
+ sns: SnsSender;
11
+ }) => {
12
+ disableEndpoint: (endpointArn: string) => Promise<void>;
13
+ ensureEndpoint: (input: NativePushRegistrationInput, existingEndpointArn?: string) => Promise<string>;
14
+ publish: (endpointArn: string, payload: NativePushPayload) => Promise<{
15
+ messageId: string;
16
+ }>;
17
+ };
@@ -0,0 +1,165 @@
1
+ import { CreatePlatformEndpointCommand, GetEndpointAttributesCommand, PublishCommand, SetEndpointAttributesCommand } from '@aws-sdk/client-sns';
2
+ export class NativePushProviderError extends Error {
3
+ code;
4
+ transient;
5
+ constructor(code, transient = false){
6
+ super(`Native push provider error: ${code}`);
7
+ this.code = code;
8
+ this.name = 'NativePushProviderError';
9
+ this.transient = transient;
10
+ }
11
+ }
12
+ const errorCode = (error)=>{
13
+ const name = error?.name;
14
+ return typeof name === 'string' && /^[A-Za-z]{1,80}$/.test(name) ? name : 'UnknownProviderError';
15
+ };
16
+ const transientCodes = new Set([
17
+ 'ThrottledException',
18
+ 'ThrottlingException',
19
+ 'InternalErrorException',
20
+ 'ServiceUnavailableException',
21
+ 'TimeoutError',
22
+ 'NetworkingError'
23
+ ]);
24
+ export const createSnsPushProvider = ({ sns, platformApplicationArns, delay = (ms)=>new Promise((resolve)=>setTimeout(resolve, ms)) })=>{
25
+ const applicationFor = (input)=>{
26
+ let arn;
27
+ let expected;
28
+ if (input.platform === 'ANDROID') {
29
+ arn = platformApplicationArns.android;
30
+ expected = 'GCM';
31
+ } else if (input.platform === 'IOS' && input.apnsEnvironment === 'sandbox') {
32
+ arn = platformApplicationArns.iosSandbox;
33
+ expected = 'APNS_SANDBOX';
34
+ } else if (input.platform === 'IOS' && input.apnsEnvironment === 'production') {
35
+ arn = platformApplicationArns.iosProduction;
36
+ expected = 'APNS';
37
+ }
38
+ if (!arn || !new RegExp(`^arn:[a-z0-9-]+:sns:[a-z0-9-]+:[0-9]{12}:app/${expected}/[A-Za-z0-9_.-]+$`).test(arn)) {
39
+ throw new NativePushProviderError('InvalidApplicationConfiguration');
40
+ }
41
+ return arn;
42
+ };
43
+ const endpointMatches = (arn, application)=>{
44
+ const prefix = `${application.replace(':app/', ':endpoint/')}/`;
45
+ return arn.startsWith(prefix) && /^[A-Za-z0-9-]+$/.test(arn.slice(prefix.length));
46
+ };
47
+ const endpointAllowed = (arn)=>Object.values(platformApplicationArns).some((application)=>application && endpointMatches(arn, application));
48
+ const call = async (command)=>{
49
+ for(let attempt = 0;; attempt++){
50
+ try {
51
+ // Sequential retries deliberately wait for the preceding attempt.
52
+ // eslint-disable-next-line no-await-in-loop
53
+ return await sns.send(command);
54
+ } catch (error) {
55
+ const code = errorCode(error);
56
+ if (transientCodes.has(code) && attempt < 2) {
57
+ // eslint-disable-next-line no-await-in-loop
58
+ await delay(100 * 2 ** attempt);
59
+ continue;
60
+ }
61
+ throw new NativePushProviderError(code, transientCodes.has(code));
62
+ }
63
+ }
64
+ };
65
+ const ensureEndpoint = async (input, existingEndpointArn)=>{
66
+ const application = applicationFor(input);
67
+ if (!input.token || typeof input.token !== 'string' || input.token.length > 8192) {
68
+ throw new NativePushProviderError('InvalidDeviceToken');
69
+ }
70
+ if (existingEndpointArn && !endpointMatches(existingEndpointArn, application)) {
71
+ throw new NativePushProviderError('InvalidEndpointScope');
72
+ }
73
+ const create = async ()=>{
74
+ let arn;
75
+ for(let attempt = 0;; attempt++){
76
+ try {
77
+ // Keep the AWS duplicate-endpoint diagnostic local; never expose it or its token.
78
+ // eslint-disable-next-line no-await-in-loop
79
+ const result = await sns.send(new CreatePlatformEndpointCommand({
80
+ PlatformApplicationArn: application,
81
+ Token: input.token
82
+ }));
83
+ arn = result.EndpointArn;
84
+ break;
85
+ } catch (error) {
86
+ if (errorCode(error) === 'InvalidParameterException') {
87
+ const diagnostic = error.message ?? '';
88
+ arn = diagnostic.match(/Endpoint (arn:[^\s]+) already exists with the same Token/)?.[1];
89
+ }
90
+ if (arn) {
91
+ break;
92
+ }
93
+ if (transientCodes.has(errorCode(error)) && attempt < 2) {
94
+ // eslint-disable-next-line no-await-in-loop
95
+ await delay(100 * 2 ** attempt);
96
+ continue;
97
+ }
98
+ throw new NativePushProviderError(errorCode(error), transientCodes.has(errorCode(error)));
99
+ }
100
+ }
101
+ if (!arn || !endpointMatches(arn, application)) {
102
+ throw new NativePushProviderError('InvalidEndpointScope');
103
+ }
104
+ return arn;
105
+ };
106
+ let arn = existingEndpointArn ?? await create();
107
+ let result;
108
+ try {
109
+ result = await call(new GetEndpointAttributesCommand({
110
+ EndpointArn: arn
111
+ }));
112
+ } catch (error) {
113
+ if (error.code !== 'NotFoundException') {
114
+ throw error;
115
+ }
116
+ arn = await create();
117
+ result = await call(new GetEndpointAttributesCommand({
118
+ EndpointArn: arn
119
+ }));
120
+ }
121
+ if (result.Attributes?.Token !== input.token || result.Attributes?.Enabled !== 'true') {
122
+ await call(new SetEndpointAttributesCommand({
123
+ Attributes: {
124
+ Enabled: 'true',
125
+ Token: input.token
126
+ },
127
+ EndpointArn: arn
128
+ }));
129
+ }
130
+ return arn;
131
+ };
132
+ return {
133
+ disableEndpoint: async (endpointArn)=>{
134
+ if (!endpointAllowed(endpointArn)) {
135
+ throw new NativePushProviderError('InvalidEndpointScope');
136
+ }
137
+ await call(new SetEndpointAttributesCommand({
138
+ Attributes: {
139
+ Enabled: 'false'
140
+ },
141
+ EndpointArn: endpointArn
142
+ }));
143
+ },
144
+ ensureEndpoint,
145
+ publish: async (endpointArn, payload)=>{
146
+ if (!endpointAllowed(endpointArn)) {
147
+ throw new NativePushProviderError('InvalidEndpointScope');
148
+ }
149
+ const result = await call(new PublishCommand({
150
+ Message: payload.message,
151
+ MessageAttributes: payload.attributes,
152
+ MessageStructure: 'json',
153
+ TargetArn: endpointArn
154
+ }));
155
+ if (!result.MessageId) {
156
+ throw new NativePushProviderError('MissingProviderMessageId');
157
+ }
158
+ return {
159
+ messageId: result.MessageId
160
+ };
161
+ }
162
+ };
163
+ };
164
+
165
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvbmF0aXZlUHVzaC9zbnNQcm92aWRlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDcmVhdGVQbGF0Zm9ybUVuZHBvaW50Q29tbWFuZCwgR2V0RW5kcG9pbnRBdHRyaWJ1dGVzQ29tbWFuZCwgUHVibGlzaENvbW1hbmQsIFNldEVuZHBvaW50QXR0cmlidXRlc0NvbW1hbmRcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LXNucyc7XG5cbmltcG9ydCB0eXBlIHtOYXRpdmVQdXNoUGF5bG9hZCwgTmF0aXZlUHVzaFJlZ2lzdHJhdGlvbklucHV0LCBQbGF0Zm9ybUFwcGxpY2F0aW9uQXJucywgU25zU2VuZGVyfSBmcm9tICcuL3R5cGVzLmpzJztcblxuZXhwb3J0IGNsYXNzIE5hdGl2ZVB1c2hQcm92aWRlckVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICByZWFkb25seSBjb2RlOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHRyYW5zaWVudDogYm9vbGVhbjtcblxuICBjb25zdHJ1Y3Rvcihjb2RlOiBzdHJpbmcsIHRyYW5zaWVudCA9IGZhbHNlKSB7XG4gICAgc3VwZXIoYE5hdGl2ZSBwdXNoIHByb3ZpZGVyIGVycm9yOiAke2NvZGV9YCk7XG4gICAgdGhpcy5jb2RlID0gY29kZTtcbiAgICB0aGlzLm5hbWUgPSAnTmF0aXZlUHVzaFByb3ZpZGVyRXJyb3InO1xuICAgIHRoaXMudHJhbnNpZW50ID0gdHJhbnNpZW50O1xuICB9XG59XG5cbmNvbnN0IGVycm9yQ29kZSA9IChlcnJvcjogdW5rbm93bik6IHN0cmluZyA9PiB7XG4gIGNvbnN0IG5hbWUgPSAoZXJyb3IgYXMge25hbWU/OiBzdHJpbmd9KT8ubmFtZTtcbiAgcmV0dXJuIHR5cGVvZiBuYW1lID09PSAnc3RyaW5nJyAmJiAvXltBLVphLXpdezEsODB9JC8udGVzdChuYW1lKSA/IG5hbWUgOiAnVW5rbm93blByb3ZpZGVyRXJyb3InO1xufTtcbmNvbnN0IHRyYW5zaWVudENvZGVzID0gbmV3IFNldChbXG4gICdUaHJvdHRsZWRFeGNlcHRpb24nLCAnVGhyb3R0bGluZ0V4Y2VwdGlvbicsICdJbnRlcm5hbEVycm9yRXhjZXB0aW9uJyxcbiAgJ1NlcnZpY2VVbmF2YWlsYWJsZUV4Y2VwdGlvbicsICdUaW1lb3V0RXJyb3InLCAnTmV0d29ya2luZ0Vycm9yJ1xuXSk7XG5cbmV4cG9ydCBjb25zdCBjcmVhdGVTbnNQdXNoUHJvdmlkZXIgPSAoe1xuICBzbnMsIHBsYXRmb3JtQXBwbGljYXRpb25Bcm5zLCBkZWxheSA9IChtcykgPT4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKVxufToge1xuICBkZWxheT86IChtaWxsaXNlY29uZHM6IG51bWJlcikgPT4gUHJvbWlzZTx2b2lkPjtcbiAgcGxhdGZvcm1BcHBsaWNhdGlvbkFybnM6IFBsYXRmb3JtQXBwbGljYXRpb25Bcm5zO1xuICBzbnM6IFNuc1NlbmRlcjtcbn0pID0+IHtcbiAgY29uc3QgYXBwbGljYXRpb25Gb3IgPSAoaW5wdXQ6IE5hdGl2ZVB1c2hSZWdpc3RyYXRpb25JbnB1dCk6IHN0cmluZyA9PiB7XG4gICAgbGV0IGFybjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGxldCBleHBlY3RlZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGlmKGlucHV0LnBsYXRmb3JtID09PSAnQU5EUk9JRCcpIHtcbiAgICAgIGFybiA9IHBsYXRmb3JtQXBwbGljYXRpb25Bcm5zLmFuZHJvaWQ7XG4gICAgICBleHBlY3RlZCA9ICdHQ00nO1xuICAgIH0gZWxzZSBpZihpbnB1dC5wbGF0Zm9ybSA9PT0gJ0lPUycgJiYgaW5wdXQuYXBuc0Vudmlyb25tZW50ID09PSAnc2FuZGJveCcpIHtcbiAgICAgIGFybiA9IHBsYXRmb3JtQXBwbGljYXRpb25Bcm5zLmlvc1NhbmRib3g7XG4gICAgICBleHBlY3RlZCA9ICdBUE5TX1NBTkRCT1gnO1xuICAgIH0gZWxzZSBpZihpbnB1dC5wbGF0Zm9ybSA9PT0gJ0lPUycgJiYgaW5wdXQuYXBuc0Vudmlyb25tZW50ID09PSAncHJvZHVjdGlvbicpIHtcbiAgICAgIGFybiA9IHBsYXRmb3JtQXBwbGljYXRpb25Bcm5zLmlvc1Byb2R1Y3Rpb247XG4gICAgICBleHBlY3RlZCA9ICdBUE5TJztcbiAgICB9XG4gICAgaWYoIWFybiB8fCAhbmV3IFJlZ0V4cChgXmFybjpbYS16MC05LV0rOnNuczpbYS16MC05LV0rOlswLTldezEyfTphcHAvJHtleHBlY3RlZH0vW0EtWmEtejAtOV8uLV0rJGApLnRlc3QoYXJuKSkge1xuICAgICAgdGhyb3cgbmV3IE5hdGl2ZVB1c2hQcm92aWRlckVycm9yKCdJbnZhbGlkQXBwbGljYXRpb25Db25maWd1cmF0aW9uJyk7XG4gICAgfVxuICAgIHJldHVybiBhcm47XG4gIH07XG4gIGNvbnN0IGVuZHBvaW50TWF0Y2hlcyA9IChhcm46IHN0cmluZywgYXBwbGljYXRpb246IHN0cmluZyk6IGJvb2xlYW4gPT4ge1xuICAgIGNvbnN0IHByZWZpeCA9IGAke2FwcGxpY2F0aW9uLnJlcGxhY2UoJzphcHAvJywgJzplbmRwb2ludC8nKX0vYDtcbiAgICByZXR1cm4gYXJuLnN0YXJ0c1dpdGgocHJlZml4KSAmJiAvXltBLVphLXowLTktXSskLy50ZXN0KGFybi5zbGljZShwcmVmaXgubGVuZ3RoKSk7XG4gIH07XG4gIGNvbnN0IGVuZHBvaW50QWxsb3dlZCA9IChhcm46IHN0cmluZyk6IGJvb2xlYW4gPT4gT2JqZWN0LnZhbHVlcyhwbGF0Zm9ybUFwcGxpY2F0aW9uQXJucylcbiAgICAuc29tZSgoYXBwbGljYXRpb24pID0+IGFwcGxpY2F0aW9uICYmIGVuZHBvaW50TWF0Y2hlcyhhcm4sIGFwcGxpY2F0aW9uKSk7XG4gIGNvbnN0IGNhbGwgPSBhc3luYyAoY29tbWFuZDogUGFyYW1ldGVyczxTbnNTZW5kZXJbJ3NlbmQnXT5bMF0pOiBQcm9taXNlPGFueT4gPT4ge1xuICAgIGZvcihsZXQgYXR0ZW1wdCA9IDA7IDsgYXR0ZW1wdCsrKSB7XG4gICAgICB0cnkge1xuICAgICAgICAvLyBTZXF1ZW50aWFsIHJldHJpZXMgZGVsaWJlcmF0ZWx5IHdhaXQgZm9yIHRoZSBwcmVjZWRpbmcgYXR0ZW1wdC5cbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWF3YWl0LWluLWxvb3BcbiAgICAgICAgcmV0dXJuIGF3YWl0IHNucy5zZW5kKGNvbW1hbmQgYXMgYW55KTtcbiAgICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgICAgY29uc3QgY29kZSA9IGVycm9yQ29kZShlcnJvcik7XG4gICAgICAgIGlmKHRyYW5zaWVudENvZGVzLmhhcyhjb2RlKSAmJiBhdHRlbXB0IDwgMikge1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1hd2FpdC1pbi1sb29wXG4gICAgICAgICAgYXdhaXQgZGVsYXkoMTAwICogKDIgKiogYXR0ZW1wdCkpO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IG5ldyBOYXRpdmVQdXNoUHJvdmlkZXJFcnJvcihjb2RlLCB0cmFuc2llbnRDb2Rlcy5oYXMoY29kZSkpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcbiAgY29uc3QgZW5zdXJlRW5kcG9pbnQgPSBhc3luYyAoaW5wdXQ6IE5hdGl2ZVB1c2hSZWdpc3RyYXRpb25JbnB1dCwgZXhpc3RpbmdFbmRwb2ludEFybj86IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiA9PiB7XG4gICAgY29uc3QgYXBwbGljYXRpb24gPSBhcHBsaWNhdGlvbkZvcihpbnB1dCk7XG4gICAgaWYoIWlucHV0LnRva2VuIHx8IHR5cGVvZiBpbnB1dC50b2tlbiAhPT0gJ3N0cmluZycgfHwgaW5wdXQudG9rZW4ubGVuZ3RoID4gODE5Mikge1xuICAgICAgdGhyb3cgbmV3IE5hdGl2ZVB1c2hQcm92aWRlckVycm9yKCdJbnZhbGlkRGV2aWNlVG9rZW4nKTtcbiAgICB9XG4gICAgaWYoZXhpc3RpbmdFbmRwb2ludEFybiAmJiAhZW5kcG9pbnRNYXRjaGVzKGV4aXN0aW5nRW5kcG9pbnRBcm4sIGFwcGxpY2F0aW9uKSkge1xuICAgICAgdGhyb3cgbmV3IE5hdGl2ZVB1c2hQcm92aWRlckVycm9yKCdJbnZhbGlkRW5kcG9pbnRTY29wZScpO1xuICAgIH1cbiAgICBjb25zdCBjcmVhdGUgPSBhc3luYyAoKTogUHJvbWlzZTxzdHJpbmc+ID0+IHtcbiAgICAgIGxldCBhcm46IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgIGZvcihsZXQgYXR0ZW1wdCA9IDA7IDsgYXR0ZW1wdCsrKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gS2VlcCB0aGUgQVdTIGR1cGxpY2F0ZS1lbmRwb2ludCBkaWFnbm9zdGljIGxvY2FsOyBuZXZlciBleHBvc2UgaXQgb3IgaXRzIHRva2VuLlxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1hd2FpdC1pbi1sb29wXG4gICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgc25zLnNlbmQobmV3IENyZWF0ZVBsYXRmb3JtRW5kcG9pbnRDb21tYW5kKHtcbiAgICAgICAgICAgIFBsYXRmb3JtQXBwbGljYXRpb25Bcm46IGFwcGxpY2F0aW9uLCBUb2tlbjogaW5wdXQudG9rZW5cbiAgICAgICAgICB9KSk7XG4gICAgICAgICAgYXJuID0gcmVzdWx0LkVuZHBvaW50QXJuO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgICAgaWYoZXJyb3JDb2RlKGVycm9yKSA9PT0gJ0ludmFsaWRQYXJhbWV0ZXJFeGNlcHRpb24nKSB7XG4gICAgICAgICAgICBjb25zdCBkaWFnbm9zdGljID0gKGVycm9yIGFzIHttZXNzYWdlPzogc3RyaW5nfSkubWVzc2FnZSA/PyAnJztcbiAgICAgICAgICAgIGFybiA9IGRpYWdub3N0aWMubWF0Y2goL0VuZHBvaW50IChhcm46W15cXHNdKykgYWxyZWFkeSBleGlzdHMgd2l0aCB0aGUgc2FtZSBUb2tlbi8pPy5bMV07XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmKGFybikge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmKHRyYW5zaWVudENvZGVzLmhhcyhlcnJvckNvZGUoZXJyb3IpKSAmJiBhdHRlbXB0IDwgMikge1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWF3YWl0LWluLWxvb3BcbiAgICAgICAgICAgIGF3YWl0IGRlbGF5KDEwMCAqICgyICoqIGF0dGVtcHQpKTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aHJvdyBuZXcgTmF0aXZlUHVzaFByb3ZpZGVyRXJyb3IoZXJyb3JDb2RlKGVycm9yKSwgdHJhbnNpZW50Q29kZXMuaGFzKGVycm9yQ29kZShlcnJvcikpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYoIWFybiB8fCAhZW5kcG9pbnRNYXRjaGVzKGFybiwgYXBwbGljYXRpb24pKSB7XG4gICAgICAgIHRocm93IG5ldyBOYXRpdmVQdXNoUHJvdmlkZXJFcnJvcignSW52YWxpZEVuZHBvaW50U2NvcGUnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBhcm47XG4gICAgfTtcbiAgICBsZXQgYXJuID0gZXhpc3RpbmdFbmRwb2ludEFybiA/PyBhd2FpdCBjcmVhdGUoKTtcbiAgICBsZXQgcmVzdWx0O1xuICAgIHRyeSB7XG4gICAgICByZXN1bHQgPSBhd2FpdCBjYWxsKG5ldyBHZXRFbmRwb2ludEF0dHJpYnV0ZXNDb21tYW5kKHtFbmRwb2ludEFybjogYXJufSkpO1xuICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgIGlmKChlcnJvciBhcyBOYXRpdmVQdXNoUHJvdmlkZXJFcnJvcikuY29kZSAhPT0gJ05vdEZvdW5kRXhjZXB0aW9uJykge1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cbiAgICAgIGFybiA9IGF3YWl0IGNyZWF0ZSgpO1xuICAgICAgcmVzdWx0ID0gYXdhaXQgY2FsbChuZXcgR2V0RW5kcG9pbnRBdHRyaWJ1dGVzQ29tbWFuZCh7RW5kcG9pbnRBcm46IGFybn0pKTtcbiAgICB9XG4gICAgaWYocmVzdWx0LkF0dHJpYnV0ZXM/LlRva2VuICE9PSBpbnB1dC50b2tlbiB8fCByZXN1bHQuQXR0cmlidXRlcz8uRW5hYmxlZCAhPT0gJ3RydWUnKSB7XG4gICAgICBhd2FpdCBjYWxsKG5ldyBTZXRFbmRwb2ludEF0dHJpYnV0ZXNDb21tYW5kKHtBdHRyaWJ1dGVzOiB7RW5hYmxlZDogJ3RydWUnLCBUb2tlbjogaW5wdXQudG9rZW59LCBFbmRwb2ludEFybjogYXJufSkpO1xuICAgIH1cbiAgICByZXR1cm4gYXJuO1xuICB9O1xuICByZXR1cm4ge1xuICAgIGRpc2FibGVFbmRwb2ludDogYXN5bmMgKGVuZHBvaW50QXJuOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgIGlmKCFlbmRwb2ludEFsbG93ZWQoZW5kcG9pbnRBcm4pKSB7XG4gICAgICAgIHRocm93IG5ldyBOYXRpdmVQdXNoUHJvdmlkZXJFcnJvcignSW52YWxpZEVuZHBvaW50U2NvcGUnKTtcbiAgICAgIH1cbiAgICAgIGF3YWl0IGNhbGwobmV3IFNldEVuZHBvaW50QXR0cmlidXRlc0NvbW1hbmQoe0F0dHJpYnV0ZXM6IHtFbmFibGVkOiAnZmFsc2UnfSwgRW5kcG9pbnRBcm46IGVuZHBvaW50QXJufSkpO1xuICAgIH0sXG4gICAgZW5zdXJlRW5kcG9pbnQsXG4gICAgcHVibGlzaDogYXN5bmMgKGVuZHBvaW50QXJuOiBzdHJpbmcsIHBheWxvYWQ6IE5hdGl2ZVB1c2hQYXlsb2FkKTogUHJvbWlzZTx7bWVzc2FnZUlkOiBzdHJpbmd9PiA9PiB7XG4gICAgICBpZighZW5kcG9pbnRBbGxvd2VkKGVuZHBvaW50QXJuKSkge1xuICAgICAgICB0aHJvdyBuZXcgTmF0aXZlUHVzaFByb3ZpZGVyRXJyb3IoJ0ludmFsaWRFbmRwb2ludFNjb3BlJyk7XG4gICAgICB9XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjYWxsKG5ldyBQdWJsaXNoQ29tbWFuZCh7TWVzc2FnZTogcGF5bG9hZC5tZXNzYWdlLCBNZXNzYWdlQXR0cmlidXRlczogcGF5bG9hZC5hdHRyaWJ1dGVzLCBNZXNzYWdlU3RydWN0dXJlOiAnanNvbicsIFRhcmdldEFybjogZW5kcG9pbnRBcm59KSk7XG4gICAgICBpZighcmVzdWx0Lk1lc3NhZ2VJZCkge1xuICAgICAgICB0aHJvdyBuZXcgTmF0aXZlUHVzaFByb3ZpZGVyRXJyb3IoJ01pc3NpbmdQcm92aWRlck1lc3NhZ2VJZCcpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHttZXNzYWdlSWQ6IHJlc3VsdC5NZXNzYWdlSWR9O1xuICAgIH1cbiAgfTtcbn07XG4iXSwibmFtZXMiOlsiQ3JlYXRlUGxhdGZvcm1FbmRwb2ludENvbW1hbmQiLCJHZXRFbmRwb2ludEF0dHJpYnV0ZXNDb21tYW5kIiwiUHVibGlzaENvbW1hbmQiLCJTZXRFbmRwb2ludEF0dHJpYnV0ZXNDb21tYW5kIiwiTmF0aXZlUHVzaFByb3ZpZGVyRXJyb3IiLCJFcnJvciIsImNvZGUiLCJ0cmFuc2llbnQiLCJuYW1lIiwiZXJyb3JDb2RlIiwiZXJyb3IiLCJ0ZXN0IiwidHJhbnNpZW50Q29kZXMiLCJTZXQiLCJjcmVhdGVTbnNQdXNoUHJvdmlkZXIiLCJzbnMiLCJwbGF0Zm9ybUFwcGxpY2F0aW9uQXJucyIsImRlbGF5IiwibXMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInNldFRpbWVvdXQiLCJhcHBsaWNhdGlvbkZvciIsImlucHV0IiwiYXJuIiwiZXhwZWN0ZWQiLCJwbGF0Zm9ybSIsImFuZHJvaWQiLCJhcG5zRW52aXJvbm1lbnQiLCJpb3NTYW5kYm94IiwiaW9zUHJvZHVjdGlvbiIsIlJlZ0V4cCIsImVuZHBvaW50TWF0Y2hlcyIsImFwcGxpY2F0aW9uIiwicHJlZml4IiwicmVwbGFjZSIsInN0YXJ0c1dpdGgiLCJzbGljZSIsImxlbmd0aCIsImVuZHBvaW50QWxsb3dlZCIsIk9iamVjdCIsInZhbHVlcyIsInNvbWUiLCJjYWxsIiwiY29tbWFuZCIsImF0dGVtcHQiLCJzZW5kIiwiaGFzIiwiZW5zdXJlRW5kcG9pbnQiLCJleGlzdGluZ0VuZHBvaW50QXJuIiwidG9rZW4iLCJjcmVhdGUiLCJyZXN1bHQiLCJQbGF0Zm9ybUFwcGxpY2F0aW9uQXJuIiwiVG9rZW4iLCJFbmRwb2ludEFybiIsImRpYWdub3N0aWMiLCJtZXNzYWdlIiwibWF0Y2giLCJBdHRyaWJ1dGVzIiwiRW5hYmxlZCIsImRpc2FibGVFbmRwb2ludCIsImVuZHBvaW50QXJuIiwicHVibGlzaCIsInBheWxvYWQiLCJNZXNzYWdlIiwiTWVzc2FnZUF0dHJpYnV0ZXMiLCJhdHRyaWJ1dGVzIiwiTWVzc2FnZVN0cnVjdHVyZSIsIlRhcmdldEFybiIsIk1lc3NhZ2VJZCIsIm1lc3NhZ2VJZCJdLCJtYXBwaW5ncyI6IkFBQUEsU0FDRUEsNkJBQTZCLEVBQUVDLDRCQUE0QixFQUFFQyxjQUFjLEVBQUVDLDRCQUE0QixRQUNwRyxzQkFBc0I7QUFJN0IsT0FBTyxNQUFNQyxnQ0FBZ0NDO0lBQ2xDQyxLQUFhO0lBQ2JDLFVBQW1CO0lBRTVCLFlBQVlELElBQVksRUFBRUMsWUFBWSxLQUFLLENBQUU7UUFDM0MsS0FBSyxDQUFDLENBQUMsNEJBQTRCLEVBQUVELE1BQU07UUFDM0MsSUFBSSxDQUFDQSxJQUFJLEdBQUdBO1FBQ1osSUFBSSxDQUFDRSxJQUFJLEdBQUc7UUFDWixJQUFJLENBQUNELFNBQVMsR0FBR0E7SUFDbkI7QUFDRjtBQUVBLE1BQU1FLFlBQVksQ0FBQ0M7SUFDakIsTUFBTUYsT0FBUUUsT0FBMkJGO0lBQ3pDLE9BQU8sT0FBT0EsU0FBUyxZQUFZLG1CQUFtQkcsSUFBSSxDQUFDSCxRQUFRQSxPQUFPO0FBQzVFO0FBQ0EsTUFBTUksaUJBQWlCLElBQUlDLElBQUk7SUFDN0I7SUFBc0I7SUFBdUI7SUFDN0M7SUFBK0I7SUFBZ0I7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
@@ -0,0 +1,89 @@
1
+ import type { SNSClient } from '@aws-sdk/client-sns';
2
+ export type JsonValue = null | boolean | number | string | JsonValue[] | {
3
+ [key: string]: JsonValue;
4
+ };
5
+ export type PushScope = {
6
+ appId: string;
7
+ environment: string;
8
+ };
9
+ export type PushActor = {
10
+ sessionId: string;
11
+ userId: string;
12
+ };
13
+ export type NativePlatform = 'ANDROID' | 'IOS';
14
+ export type NativePushRegistrationInput = {
15
+ apnsEnvironment?: 'production' | 'sandbox';
16
+ installationId: string;
17
+ platform: NativePlatform;
18
+ token: string;
19
+ };
20
+ export type NativePushRegistration = PushScope & PushActor & Omit<NativePushRegistrationInput, 'token'> & {
21
+ createdAt: string;
22
+ enabled: boolean;
23
+ endpointArn: string;
24
+ registrationId: string;
25
+ revision: number;
26
+ tokenHash: string;
27
+ updatedAt: string;
28
+ };
29
+ export type NativeNotification = {
30
+ body: string;
31
+ createdAt: string;
32
+ data?: Record<string, JsonValue>;
33
+ kind: string;
34
+ notificationId: string;
35
+ title: string;
36
+ version: 1;
37
+ };
38
+ export type NativePushEnvelope = {
39
+ notification: NativeNotification;
40
+ recipientUserId: string;
41
+ scope: PushScope;
42
+ };
43
+ export type NativePushOptions = {
44
+ badge?: number;
45
+ expiresAt?: string;
46
+ };
47
+ export type NativePushPayload = {
48
+ attributes: Record<string, {
49
+ DataType: string;
50
+ StringValue: string;
51
+ }>;
52
+ message: string;
53
+ };
54
+ export type PlatformApplicationArns = {
55
+ android?: string;
56
+ iosProduction?: string;
57
+ iosSandbox?: string;
58
+ };
59
+ export type SnsSender = Pick<SNSClient, 'send'>;
60
+ export type DeliveryOutcome = {
61
+ code?: string;
62
+ providerMessageId?: string;
63
+ registrationId: string;
64
+ status: 'ACCEPTED' | 'INVALID_ENDPOINT' | 'PERMANENT_FAILURE' | 'SKIPPED' | 'TRANSIENT_FAILURE';
65
+ };
66
+ export interface NativePushRepository {
67
+ disableBinding(scope: PushScope, actor: PushActor, registrationId: string, revision?: number): Promise<boolean>;
68
+ disableEndpoint(scope: PushScope, endpointArn: string): Promise<void>;
69
+ hasActiveEndpointBinding(scope: PushScope, endpointArn: string): Promise<boolean>;
70
+ isCurrent(registration: NativePushRegistration): Promise<boolean>;
71
+ listEnabled(scope: PushScope, userId: string): Promise<NativePushRegistration[]>;
72
+ reserveBinding(scope: PushScope, actor: PushActor, input: Omit<NativePushRegistrationInput, 'token'>, tokenHash: string): Promise<number>;
73
+ replaceBinding(scope: PushScope, actor: PushActor, input: Omit<NativePushRegistrationInput, 'token'>, endpointArn: string, tokenHash: string, expectedRevision?: number): Promise<NativePushRegistration>;
74
+ }
75
+ export type NativePushServiceOptions = {
76
+ canDeliver?: (registration: NativePushRegistration, notification: NativeNotification) => Promise<boolean>;
77
+ delay?: (milliseconds: number) => Promise<void>;
78
+ isSessionEligible: (scope: PushScope, actor: PushActor) => Promise<boolean>;
79
+ now?: () => Date;
80
+ platformApplicationArns: PlatformApplicationArns;
81
+ repository: NativePushRepository;
82
+ scope: PushScope;
83
+ sns: SnsSender;
84
+ };
85
+ export interface NativePushService {
86
+ register(actor: PushActor, input: NativePushRegistrationInput): Promise<NativePushRegistration>;
87
+ send(userId: string, notification: NativeNotification, options?: NativePushOptions): Promise<DeliveryOutcome[]>;
88
+ unregister(actor: PushActor, registrationId: string, revision?: number): Promise<boolean>;
89
+ }
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvbmF0aXZlUHVzaC90eXBlcy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7U05TQ2xpZW50fSBmcm9tICdAYXdzLXNkay9jbGllbnQtc25zJztcblxuZXhwb3J0IHR5cGUgSnNvblZhbHVlID0gbnVsbCB8IGJvb2xlYW4gfCBudW1iZXIgfCBzdHJpbmcgfCBKc29uVmFsdWVbXSB8IHtba2V5OiBzdHJpbmddOiBKc29uVmFsdWV9O1xuZXhwb3J0IHR5cGUgUHVzaFNjb3BlID0ge2FwcElkOiBzdHJpbmc7IGVudmlyb25tZW50OiBzdHJpbmd9O1xuZXhwb3J0IHR5cGUgUHVzaEFjdG9yID0ge3Nlc3Npb25JZDogc3RyaW5nOyB1c2VySWQ6IHN0cmluZ307XG5leHBvcnQgdHlwZSBOYXRpdmVQbGF0Zm9ybSA9ICdBTkRST0lEJyB8ICdJT1MnO1xuZXhwb3J0IHR5cGUgTmF0aXZlUHVzaFJlZ2lzdHJhdGlvbklucHV0ID0ge1xuICBhcG5zRW52aXJvbm1lbnQ/OiAncHJvZHVjdGlvbicgfCAnc2FuZGJveCc7XG4gIGluc3RhbGxhdGlvbklkOiBzdHJpbmc7XG4gIHBsYXRmb3JtOiBOYXRpdmVQbGF0Zm9ybTtcbiAgdG9rZW46IHN0cmluZztcbn07XG5leHBvcnQgdHlwZSBOYXRpdmVQdXNoUmVnaXN0cmF0aW9uID0gUHVzaFNjb3BlICYgUHVzaEFjdG9yICYgT21pdDxOYXRpdmVQdXNoUmVnaXN0cmF0aW9uSW5wdXQsICd0b2tlbic+ICYge1xuICBjcmVhdGVkQXQ6IHN0cmluZztcbiAgZW5hYmxlZDogYm9vbGVhbjtcbiAgZW5kcG9pbnRBcm46IHN0cmluZztcbiAgcmVnaXN0cmF0aW9uSWQ6IHN0cmluZztcbiAgcmV2aXNpb246IG51bWJlcjtcbiAgdG9rZW5IYXNoOiBzdHJpbmc7XG4gIHVwZGF0ZWRBdDogc3RyaW5nO1xufTtcbmV4cG9ydCB0eXBlIE5hdGl2ZU5vdGlmaWNhdGlvbiA9IHtcbiAgYm9keTogc3RyaW5nO1xuICBjcmVhdGVkQXQ6IHN0cmluZztcbiAgZGF0YT86IFJlY29yZDxzdHJpbmcsIEpzb25WYWx1ZT47XG4gIGtpbmQ6IHN0cmluZztcbiAgbm90aWZpY2F0aW9uSWQ6IHN0cmluZztcbiAgdGl0bGU6IHN0cmluZztcbiAgdmVyc2lvbjogMTtcbn07XG5leHBvcnQgdHlwZSBOYXRpdmVQdXNoRW52ZWxvcGUgPSB7bm90aWZpY2F0aW9uOiBOYXRpdmVOb3RpZmljYXRpb247IHJlY2lwaWVudFVzZXJJZDogc3RyaW5nOyBzY29wZTogUHVzaFNjb3BlfTtcbmV4cG9ydCB0eXBlIE5hdGl2ZVB1c2hPcHRpb25zID0ge2JhZGdlPzogbnVtYmVyOyBleHBpcmVzQXQ/OiBzdHJpbmd9O1xuZXhwb3J0IHR5cGUgTmF0aXZlUHVzaFBheWxvYWQgPSB7XG4gIGF0dHJpYnV0ZXM6IFJlY29yZDxzdHJpbmcsIHtEYXRhVHlwZTogc3RyaW5nOyBTdHJpbmdWYWx1ZTogc3RyaW5nfT47XG4gIG1lc3NhZ2U6IHN0cmluZztcbn07XG5leHBvcnQgdHlwZSBQbGF0Zm9ybUFwcGxpY2F0aW9uQXJucyA9IHthbmRyb2lkPzogc3RyaW5nOyBpb3NQcm9kdWN0aW9uPzogc3RyaW5nOyBpb3NTYW5kYm94Pzogc3RyaW5nfTtcbmV4cG9ydCB0eXBlIFNuc1NlbmRlciA9IFBpY2s8U05TQ2xpZW50LCAnc2VuZCc+O1xuZXhwb3J0IHR5cGUgRGVsaXZlcnlPdXRjb21lID0ge1xuICBjb2RlPzogc3RyaW5nO1xuICBwcm92aWRlck1lc3NhZ2VJZD86IHN0cmluZztcbiAgcmVnaXN0cmF0aW9uSWQ6IHN0cmluZztcbiAgc3RhdHVzOiAnQUNDRVBURUQnIHwgJ0lOVkFMSURfRU5EUE9JTlQnIHwgJ1BFUk1BTkVOVF9GQUlMVVJFJyB8ICdTS0lQUEVEJyB8ICdUUkFOU0lFTlRfRkFJTFVSRSc7XG59O1xuZXhwb3J0IGludGVyZmFjZSBOYXRpdmVQdXNoUmVwb3NpdG9yeSB7XG4gIGRpc2FibGVCaW5kaW5nKHNjb3BlOiBQdXNoU2NvcGUsIGFjdG9yOiBQdXNoQWN0b3IsIHJlZ2lzdHJhdGlvbklkOiBzdHJpbmcsIHJldmlzaW9uPzogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPjtcbiAgZGlzYWJsZUVuZHBvaW50KHNjb3BlOiBQdXNoU2NvcGUsIGVuZHBvaW50QXJuOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+O1xuICBoYXNBY3RpdmVFbmRwb2ludEJpbmRpbmcoc2NvcGU6IFB1c2hTY29wZSwgZW5kcG9pbnRBcm46IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj47XG4gIGlzQ3VycmVudChyZWdpc3RyYXRpb246IE5hdGl2ZVB1c2hSZWdpc3RyYXRpb24pOiBQcm9taXNlPGJvb2xlYW4+O1xuICBsaXN0RW5hYmxlZChzY29wZTogUHVzaFNjb3BlLCB1c2VySWQ6IHN0cmluZyk6IFByb21pc2U8TmF0aXZlUHVzaFJlZ2lzdHJhdGlvbltdPjtcbiAgcmVzZXJ2ZUJpbmRpbmcoc2NvcGU6IFB1c2hTY29wZSwgYWN0b3I6IFB1c2hBY3RvciwgaW5wdXQ6IE9taXQ8TmF0aXZlUHVzaFJlZ2lzdHJhdGlvbklucHV0LCAndG9rZW4nPiwgdG9rZW5IYXNoOiBzdHJpbmcpOiBQcm9taXNlPG51bWJlcj47XG4gIHJlcGxhY2VCaW5kaW5nKHNjb3BlOiBQdXNoU2NvcGUsIGFjdG9yOiBQdXNoQWN0b3IsIGlucHV0OiBPbWl0PE5hdGl2ZVB1c2hSZWdpc3RyYXRpb25JbnB1dCwgJ3Rva2VuJz4sIGVuZHBvaW50QXJuOiBzdHJpbmcsIHRva2VuSGFzaDogc3RyaW5nLCBleHBlY3RlZFJldmlzaW9uPzogbnVtYmVyKTogUHJvbWlzZTxOYXRpdmVQdXNoUmVnaXN0cmF0aW9uPjtcbn1cbmV4cG9ydCB0eXBlIE5hdGl2ZVB1c2hTZXJ2aWNlT3B0aW9ucyA9IHtcbiAgY2FuRGVsaXZlcj86IChyZWdpc3RyYXRpb246IE5hdGl2ZVB1c2hSZWdpc3RyYXRpb24sIG5vdGlmaWNhdGlvbjogTmF0aXZlTm90aWZpY2F0aW9uKSA9PiBQcm9taXNlPGJvb2xlYW4+O1xuICBkZWxheT86IChtaWxsaXNlY29uZHM6IG51bWJlcikgPT4gUHJvbWlzZTx2b2lkPjtcbiAgaXNTZXNzaW9uRWxpZ2libGU6IChzY29wZTogUHVzaFNjb3BlLCBhY3RvcjogUHVzaEFjdG9yKSA9PiBQcm9taXNlPGJvb2xlYW4+O1xuICBub3c/OiAoKSA9PiBEYXRlO1xuICBwbGF0Zm9ybUFwcGxpY2F0aW9uQXJuczogUGxhdGZvcm1BcHBsaWNhdGlvbkFybnM7XG4gIHJlcG9zaXRvcnk6IE5hdGl2ZVB1c2hSZXBvc2l0b3J5O1xuICBzY29wZTogUHVzaFNjb3BlO1xuICBzbnM6IFNuc1NlbmRlcjtcbn07XG5leHBvcnQgaW50ZXJmYWNlIE5hdGl2ZVB1c2hTZXJ2aWNlIHtcbiAgcmVnaXN0ZXIoYWN0b3I6IFB1c2hBY3RvciwgaW5wdXQ6IE5hdGl2ZVB1c2hSZWdpc3RyYXRpb25JbnB1dCk6IFByb21pc2U8TmF0aXZlUHVzaFJlZ2lzdHJhdGlvbj47XG4gIHNlbmQodXNlcklkOiBzdHJpbmcsIG5vdGlmaWNhdGlvbjogTmF0aXZlTm90aWZpY2F0aW9uLCBvcHRpb25zPzogTmF0aXZlUHVzaE9wdGlvbnMpOiBQcm9taXNlPERlbGl2ZXJ5T3V0Y29tZVtdPjtcbiAgdW5yZWdpc3RlcihhY3RvcjogUHVzaEFjdG9yLCByZWdpc3RyYXRpb25JZDogc3RyaW5nLCByZXZpc2lvbj86IG51bWJlcik6IFByb21pc2U8Ym9vbGVhbj47XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBK0RBLFdBSUMifQ==
@@ -0,0 +1,7 @@
1
+ import { literal } from 'arangojs/aql';
2
+ import type { ApiContext } from '../types/auth.types.js';
3
+ import type { UserType } from '../types/users.types.js';
4
+ /** Recheck atomic enrollment at the legacy write, after an earlier unassociated-account lookup. */
5
+ export declare const organizationAccountWriteGuard: (context: ApiContext, collection: string, variable?: 'doc' | 'u') => ReturnType<typeof literal>;
6
+ /** Protect control-plane accounts under the same lock as ownership changes. */
7
+ export declare const organizationAccountMutation: (context: ApiContext, userId: string, operation: 'deactivate' | 'delete' | 'update', patch: Record<string, unknown>) => Promise<UserType | null>;
@@ -0,0 +1,106 @@
1
+ /* Stream-transaction steps and ordered retry assertions must execute sequentially. */ /* eslint-disable no-await-in-loop */ import { literal } from 'arangojs/aql';
2
+ import { organizationUserId } from './authorization.js';
3
+ import { activeMemberCount, writeSeatChange } from './membership.js';
4
+ import { organizationEdgeCollections, organizationStoreFor } from './store.js';
5
+ /** Recheck atomic enrollment at the legacy write, after an earlier unassociated-account lookup. */ export const organizationAccountWriteGuard = (context, collection, variable = 'doc')=>literal(collection === 'users' && process.env.ARANGODB_DATABASE && context.databaseName === process.env.ARANGODB_DATABASE ? `${variable}.organizationAccount != true` : 'true');
6
+ /** Protect control-plane accounts under the same lock as ownership changes. */ export const organizationAccountMutation = async (context, userId, operation, patch)=>{
7
+ if (!process.env.ARANGODB_DATABASE || context.databaseName !== process.env.ARANGODB_DATABASE) {
8
+ return null;
9
+ }
10
+ const key = userId.replace(/^users\//, '');
11
+ return organizationStoreFor(context).transaction(async (tx)=>{
12
+ const user = await tx.get('users', key);
13
+ const organizations = await tx.find('organizations', {
14
+ ownerUserId: key
15
+ });
16
+ const related = await tx.find('organizationMemberships', {
17
+ userId: key
18
+ });
19
+ if (!user || !user.organizationAccount && !organizations.length && !related.length) {
20
+ return null;
21
+ }
22
+ if (!context.session?.userId || organizationUserId(context) !== key) {
23
+ throw new Error('account_access_denied');
24
+ }
25
+ if (operation === 'update') {
26
+ if ([
27
+ 'organizationAccount',
28
+ 'verifiedEmail',
29
+ 'verifiedEmailCode',
30
+ 'verifiedEmailExpires',
31
+ 'verifiedPhone',
32
+ 'verifiedPhoneExpires',
33
+ 'verifiedSmsCode',
34
+ 'email',
35
+ 'phone',
36
+ 'active',
37
+ 'userAccess',
38
+ 'salt',
39
+ 'type',
40
+ 'username',
41
+ 'deleted',
42
+ '_key',
43
+ '_id',
44
+ '_rev'
45
+ ].some((field)=>patch[field] !== undefined)) {
46
+ throw new Error('protected_account_field');
47
+ }
48
+ if (patch.userId !== undefined && patch.userId !== key || patch.id !== undefined && patch.id !== `users/${key}`) {
49
+ throw new Error('protected_account_field');
50
+ }
51
+ const { id, userId: ignoredUserId, ...safePatch } = patch;
52
+ const updated = {
53
+ ...user,
54
+ ...safePatch
55
+ };
56
+ await tx.put('users', key, updated, user);
57
+ return updated;
58
+ }
59
+ if (organizations.length) {
60
+ throw new Error('ownership_transfer_required');
61
+ }
62
+ const memberships = related.filter((membership)=>membership.status === 'active');
63
+ for (const membership of memberships){
64
+ const org = await tx.get('organizations', membership.organizationId);
65
+ if (!org) {
66
+ throw new Error('organization_state_invalid');
67
+ }
68
+ const previousCount = await activeMemberCount(tx, org.organizationId);
69
+ await tx.put('organizationMemberships', membership._key, {
70
+ ...membership,
71
+ revision: membership.revision + 1,
72
+ status: 'deactivated',
73
+ updatedAt: Date.now()
74
+ }, membership);
75
+ await writeSeatChange(tx, org, previousCount - 1, Date.now(), previousCount);
76
+ }
77
+ if (operation === 'delete') {
78
+ for (const collection of organizationEdgeCollections){
79
+ const edges = [
80
+ ...await tx.find(collection, {
81
+ _from: `users/${key}`
82
+ }),
83
+ ...await tx.find(collection, {
84
+ _to: `users/${key}`
85
+ })
86
+ ];
87
+ const unique = new Map(edges.map((edge)=>[
88
+ edge._key,
89
+ edge
90
+ ]));
91
+ for (const edge of unique.values()){
92
+ await tx.remove(collection, edge);
93
+ }
94
+ }
95
+ await tx.remove('users', user);
96
+ } else {
97
+ await tx.put('users', key, {
98
+ ...user,
99
+ active: false
100
+ }, user);
101
+ }
102
+ return user;
103
+ });
104
+ }; /* 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"]}] */
105
+
106
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvb3JnYW5pemF0aW9ucy9hY2NvdW50TGlmZWN5Y2xlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIFN0cmVhbS10cmFuc2FjdGlvbiBzdGVwcyBhbmQgb3JkZXJlZCByZXRyeSBhc3NlcnRpb25zIG11c3QgZXhlY3V0ZSBzZXF1ZW50aWFsbHkuICovXG4vKiBlc2xpbnQtZGlzYWJsZSBuby1hd2FpdC1pbi1sb29wICovXG5pbXBvcnQge2xpdGVyYWx9IGZyb20gJ2FyYW5nb2pzL2FxbCc7XG5cbmltcG9ydCB7b3JnYW5pemF0aW9uVXNlcklkfSBmcm9tICcuL2F1dGhvcml6YXRpb24uanMnO1xuaW1wb3J0IHthY3RpdmVNZW1iZXJDb3VudCwgd3JpdGVTZWF0Q2hhbmdlfSBmcm9tICcuL21lbWJlcnNoaXAuanMnO1xuaW1wb3J0IHtvcmdhbml6YXRpb25FZGdlQ29sbGVjdGlvbnMsIG9yZ2FuaXphdGlvblN0b3JlRm9yfSBmcm9tICcuL3N0b3JlLmpzJztcblxuaW1wb3J0IHR5cGUge0FwaUNvbnRleHR9IGZyb20gJy4uL3R5cGVzL2F1dGgudHlwZXMuanMnO1xuaW1wb3J0IHR5cGUge1VzZXJUeXBlfSBmcm9tICcuLi90eXBlcy91c2Vycy50eXBlcy5qcyc7XG5pbXBvcnQgdHlwZSB7T3JnYW5pemF0aW9uLCBPcmdhbml6YXRpb25NZW1iZXJzaGlwfSBmcm9tICcuL3R5cGVzLmpzJztcblxuLyoqIFJlY2hlY2sgYXRvbWljIGVucm9sbG1lbnQgYXQgdGhlIGxlZ2FjeSB3cml0ZSwgYWZ0ZXIgYW4gZWFybGllciB1bmFzc29jaWF0ZWQtYWNjb3VudCBsb29rdXAuICovXG5leHBvcnQgY29uc3Qgb3JnYW5pemF0aW9uQWNjb3VudFdyaXRlR3VhcmQgPSAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsIGNvbGxlY3Rpb246IHN0cmluZywgdmFyaWFibGU6ICdkb2MnIHwgJ3UnID0gJ2RvYydcbik6IFJldHVyblR5cGU8dHlwZW9mIGxpdGVyYWw+ID0+IGxpdGVyYWwoXG4gIGNvbGxlY3Rpb24gPT09ICd1c2VycycgJiYgcHJvY2Vzcy5lbnYuQVJBTkdPREJfREFUQUJBU0UgJiYgY29udGV4dC5kYXRhYmFzZU5hbWUgPT09IHByb2Nlc3MuZW52LkFSQU5HT0RCX0RBVEFCQVNFXG4gICAgPyBgJHt2YXJpYWJsZX0ub3JnYW5pemF0aW9uQWNjb3VudCAhPSB0cnVlYCA6ICd0cnVlJ1xuKTtcblxuLyoqIFByb3RlY3QgY29udHJvbC1wbGFuZSBhY2NvdW50cyB1bmRlciB0aGUgc2FtZSBsb2NrIGFzIG93bmVyc2hpcCBjaGFuZ2VzLiAqL1xuZXhwb3J0IGNvbnN0IG9yZ2FuaXphdGlvbkFjY291bnRNdXRhdGlvbiA9IGFzeW5jIChcbiAgY29udGV4dDogQXBpQ29udGV4dCxcbiAgdXNlcklkOiBzdHJpbmcsXG4gIG9wZXJhdGlvbjogJ2RlYWN0aXZhdGUnIHwgJ2RlbGV0ZScgfCAndXBkYXRlJyxcbiAgcGF0Y2g6IFJlY29yZDxzdHJpbmcsIHVua25vd24+XG4pOiBQcm9taXNlPFVzZXJUeXBlIHwgbnVsbD4gPT4ge1xuICBpZighcHJvY2Vzcy5lbnYuQVJBTkdPREJfREFUQUJBU0UgfHwgY29udGV4dC5kYXRhYmFzZU5hbWUgIT09IHByb2Nlc3MuZW52LkFSQU5HT0RCX0RBVEFCQVNFKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgY29uc3Qga2V5ID0gdXNlcklkLnJlcGxhY2UoL151c2Vyc1xcLy8sICcnKTtcbiAgcmV0dXJuIG9yZ2FuaXphdGlvblN0b3JlRm9yKGNvbnRleHQpLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0eC5nZXQ8VXNlclR5cGUgJiB7b3JnYW5pemF0aW9uQWNjb3VudD86IGJvb2xlYW59PigndXNlcnMnLCBrZXkpO1xuICAgIGNvbnN0IG9yZ2FuaXphdGlvbnMgPSBhd2FpdCB0eC5maW5kPE9yZ2FuaXphdGlvbj4oJ29yZ2FuaXphdGlvbnMnLCB7b3duZXJVc2VySWQ6IGtleX0pO1xuICAgIGNvbnN0IHJlbGF0ZWQgPSBhd2FpdCB0eC5maW5kPE9yZ2FuaXphdGlvbk1lbWJlcnNoaXA+KCdvcmdhbml6YXRpb25NZW1iZXJzaGlwcycsIHt1c2VySWQ6IGtleX0pO1xuICAgIGlmKCF1c2VyIHx8ICghdXNlci5vcmdhbml6YXRpb25BY2NvdW50ICYmICFvcmdhbml6YXRpb25zLmxlbmd0aCAmJiAhcmVsYXRlZC5sZW5ndGgpKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgaWYoIWNvbnRleHQuc2Vzc2lvbj8udXNlcklkIHx8IG9yZ2FuaXphdGlvblVzZXJJZChjb250ZXh0KSAhPT0ga2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2FjY291bnRfYWNjZXNzX2RlbmllZCcpO1xuICAgIH1cbiAgICBpZihvcGVyYXRpb24gPT09ICd1cGRhdGUnKSB7XG4gICAgICBpZihcbiAgICAgICAgW1xuICAgICAgICAgICdvcmdhbml6YXRpb25BY2NvdW50JyxcbiAgICAgICAgICAndmVyaWZpZWRFbWFpbCcsXG4gICAgICAgICAgJ3ZlcmlmaWVkRW1haWxDb2RlJyxcbiAgICAgICAgICAndmVyaWZpZWRFbWFpbEV4cGlyZXMnLFxuICAgICAgICAgICd2ZXJpZmllZFBob25lJyxcbiAgICAgICAgICAndmVyaWZpZWRQaG9uZUV4cGlyZXMnLFxuICAgICAgICAgICd2ZXJpZmllZFNtc0NvZGUnLFxuICAgICAgICAgICdlbWFpbCcsXG4gICAgICAgICAgJ3Bob25lJyxcbiAgICAgICAgICAnYWN0aXZlJyxcbiAgICAgICAgICAndXNlckFjY2VzcycsXG4gICAgICAgICAgJ3NhbHQnLFxuICAgICAgICAgICd0eXBlJyxcbiAgICAgICAgICAndXNlcm5hbWUnLFxuICAgICAgICAgICdkZWxldGVkJyxcbiAgICAgICAgICAnX2tleScsXG4gICAgICAgICAgJ19pZCcsXG4gICAgICAgICAgJ19yZXYnXG4gICAgICAgIF0uc29tZSgoZmllbGQpID0+IHBhdGNoW2ZpZWxkXSAhPT0gdW5kZWZpbmVkKVxuICAgICAgKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigncHJvdGVjdGVkX2FjY291bnRfZmllbGQnKTtcbiAgICAgIH1cbiAgICAgIGlmKFxuICAgICAgICAocGF0Y2gudXNlcklkICE9PSB1bmRlZmluZWQgJiYgcGF0Y2gudXNlcklkICE9PSBrZXkpIHx8XG4gICAgICAgIChwYXRjaC5pZCAhPT0gdW5kZWZpbmVkICYmIHBhdGNoLmlkICE9PSBgdXNlcnMvJHtrZXl9YClcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb3RlY3RlZF9hY2NvdW50X2ZpZWxkJyk7XG4gICAgICB9XG4gICAgICBjb25zdCB7aWQsIHVzZXJJZDogaWdub3JlZFVzZXJJZCwgLi4uc2FmZVBhdGNofSA9IHBhdGNoO1xuICAgICAgY29uc3QgdXBkYXRlZCA9IHsuLi51c2VyLCAuLi5zYWZlUGF0Y2h9O1xuICAgICAgYXdhaXQgdHgucHV0KCd1c2VycycsIGtleSwgdXBkYXRlZCwgdXNlcik7XG4gICAgICByZXR1cm4gdXBkYXRlZDtcbiAgICB9XG4gICAgaWYob3JnYW5pemF0aW9ucy5sZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignb3duZXJzaGlwX3RyYW5zZmVyX3JlcXVpcmVkJyk7XG4gICAgfVxuICAgIGNvbnN0IG1lbWJlcnNoaXBzID0gcmVsYXRlZC5maWx0ZXIoKG1lbWJlcnNoaXApID0+IG1lbWJlcnNoaXAuc3RhdHVzID09PSAnYWN0aXZlJyk7XG4gICAgZm9yKGNvbnN0IG1lbWJlcnNoaXAgb2YgbWVtYmVyc2hpcHMpIHtcbiAgICAgIGNvbnN0IG9yZyA9IGF3YWl0IHR4LmdldDxPcmdhbml6YXRpb24+KCdvcmdhbml6YXRpb25zJywgbWVtYmVyc2hpcC5vcmdhbml6YXRpb25JZCk7XG4gICAgICBpZighb3JnKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignb3JnYW5pemF0aW9uX3N0YXRlX2ludmFsaWQnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHByZXZpb3VzQ291bnQgPSBhd2FpdCBhY3RpdmVNZW1iZXJDb3VudCh0eCwgb3JnLm9yZ2FuaXphdGlvbklkKTtcbiAgICAgIGF3YWl0IHR4LnB1dChcbiAgICAgICAgJ29yZ2FuaXphdGlvbk1lbWJlcnNoaXBzJyxcbiAgICAgICAgbWVtYmVyc2hpcC5fa2V5LFxuICAgICAgICB7Li4ubWVtYmVyc2hpcCwgcmV2aXNpb246IG1lbWJlcnNoaXAucmV2aXNpb24gKyAxLCBzdGF0dXM6ICdkZWFjdGl2YXRlZCcsIHVwZGF0ZWRBdDogRGF0ZS5ub3coKX0sXG4gICAgICAgIG1lbWJlcnNoaXBcbiAgICAgICk7XG4gICAgICBhd2FpdCB3cml0ZVNlYXRDaGFuZ2UodHgsIG9yZywgcHJldmlvdXNDb3VudCAtIDEsIERhdGUubm93KCksIHByZXZpb3VzQ291bnQpO1xuICAgIH1cbiAgICBpZihvcGVyYXRpb24gPT09ICdkZWxldGUnKSB7XG4gICAgICBmb3IoY29uc3QgY29sbGVjdGlvbiBvZiBvcmdhbml6YXRpb25FZGdlQ29sbGVjdGlvbnMpIHtcbiAgICAgICAgY29uc3QgZWRnZXMgPSBbXG4gICAgICAgICAgLi4uKGF3YWl0IHR4LmZpbmQoY29sbGVjdGlvbiwge19mcm9tOiBgdXNlcnMvJHtrZXl9YH0pKSxcbiAgICAgICAgICAuLi4oYXdhaXQgdHguZmluZChjb2xsZWN0aW9uLCB7X3RvOiBgdXNlcnMvJHtrZXl9YH0pKVxuICAgICAgICBdO1xuICAgICAgICBjb25zdCB1bmlxdWUgPSBuZXcgTWFwKGVkZ2VzLm1hcCgoZWRnZSkgPT4gW2VkZ2UuX2tleSwgZWRnZV0pKTtcbiAgICAgICAgZm9yKGNvbnN0IGVkZ2Ugb2YgdW5pcXVlLnZhbHVlcygpKSB7XG4gICAgICAgICAgYXdhaXQgdHgucmVtb3ZlKGNvbGxlY3Rpb24sIGVkZ2UpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBhd2FpdCB0eC5yZW1vdmUoJ3VzZXJzJywgdXNlcik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHR4LnB1dCgndXNlcnMnLCBrZXksIHsuLi51c2VyLCBhY3RpdmU6IGZhbHNlfSwgdXNlcik7XG4gICAgfVxuICAgIHJldHVybiB1c2VyO1xuICB9KTtcbn07XG4vKiBTdHJlYW0tdHJhbnNhY3Rpb24gc3RlcHMgYW5kIG9yZGVyZWQgcmV0cnkgYXNzZXJ0aW9ucyBtdXN0IGV4ZWN1dGUgc2VxdWVudGlhbGx5LiAqL1xuXG4vKiBBcmFuZ29EQiBkb2N1bWVudCBtZXRhZGF0YSB1c2VzIHRoZXNlIHJlc2VydmVkIGZpZWxkIG5hbWVzLiAqL1xuLyogZXNsaW50IG5vLXVuZGVyc2NvcmUtZGFuZ2xlOiBbXCJ3YXJuXCIsIHtcImFsbG93XCI6IFtcIl9rZXlcIiwgXCJfcmV2XCIsIFwiX2lkXCJdfV0gKi9cbiJdLCJuYW1lcyI6WyJsaXRlcmFsIiwib3JnYW5pemF0aW9uVXNlcklkIiwiYWN0aXZlTWVtYmVyQ291bnQiLCJ3cml0ZVNlYXRDaGFuZ2UiLCJvcmdhbml6YXRpb25FZGdlQ29sbGVjdGlvbnMiLCJvcmdhbml6YXRpb25TdG9yZUZvciIsIm9yZ2FuaXphdGlvbkFjY291bnRXcml0ZUd1YXJkIiwiY29udGV4dCIsImNvbGxlY3Rpb24iLCJ2YXJpYWJsZSIsInByb2Nlc3MiLCJlbnYiLCJBUkFOR09EQl9EQVRBQkFTRSIsImRhdGFiYXNlTmFtZSIsIm9yZ2FuaXphdGlvbkFjY291bnRNdXRhdGlvbiIsInVzZXJJZCIsIm9wZXJhdGlvbiIsInBhdGNoIiwia2V5IiwicmVwbGFjZSIsInRyYW5zYWN0aW9uIiwidHgiLCJ1c2VyIiwiZ2V0Iiwib3JnYW5pemF0aW9ucyIsImZpbmQiLCJvd25lclVzZXJJZCIsInJlbGF0ZWQiLCJvcmdhbml6YXRpb25BY2NvdW50IiwibGVuZ3RoIiwic2Vzc2lvbiIsIkVycm9yIiwic29tZSIsImZpZWxkIiwidW5kZWZpbmVkIiwiaWQiLCJpZ25vcmVkVXNlcklkIiwic2FmZVBhdGNoIiwidXBkYXRlZCIsInB1dCIsIm1lbWJlcnNoaXBzIiwiZmlsdGVyIiwibWVtYmVyc2hpcCIsInN0YXR1cyIsIm9yZyIsIm9yZ2FuaXphdGlvbklkIiwicHJldmlvdXNDb3VudCIsIl9rZXkiLCJyZXZpc2lvbiIsInVwZGF0ZWRBdCIsIkRhdGUiLCJub3ciLCJlZGdlcyIsIl9mcm9tIiwiX3RvIiwidW5pcXVlIiwiTWFwIiwibWFwIiwiZWRnZSIsInZhbHVlcyIsInJlbW92ZSIsImFjdGl2ZSJdLCJtYXBwaW5ncyI6IkFBQUEsb0ZBQW9GLEdBQ3BGLG1DQUFtQyxHQUNuQyxTQUFRQSxPQUFPLFFBQU8sZUFBZTtBQUVyQyxTQUFRQyxrQkFBa0IsUUFBTyxxQkFBcUI7QUFDdEQsU0FBUUMsaUJBQWlCLEVBQUVDLGVBQWUsUUFBTyxrQkFBa0I7QUFDbkUsU0FBUUMsMkJBQTJCLEVBQUVDLG9CQUFvQixRQUFPLGFBQWE7QUFNN0UsaUdBQWlHLEdBQ2pHLE9BQU8sTUFBTUMsZ0NBQWdDLENBQzNDQyxTQUFxQkMsWUFBb0JDLFdBQXdCLEtBQUssR0FDdkNULFFBQy9CUSxlQUFlLFdBQVdFLFFBQVFDLEdBQUcsQ0FBQ0MsaUJBQWlCLElBQUlMLFFBQVFNLFlBQVksS0FBS0gsUUFBUUMsR0FBRyxDQUFDQyxpQkFBaUIsR0FDN0csR0FBR0gsU0FBUyw0QkFBNEIsQ0FBQyxHQUFHLFFBQ2hEO0FBRUYsNkVBQTZFLEdBQzdFLE9BQU8sTUFBTUssOEJBQThCLE9BQ3pDUCxTQUNBUSxRQUNBQyxXQUNBQztJQUVBLElBQUcsQ0FBQ1AsUUFBUUMsR0FBRyxDQUFDQyxpQkFBaUIsSUFBSUwsUUFBUU0sWUFBWSxLQUFLSCxRQUFRQyxHQUFHLENBQUNDLGlCQUFpQixFQUFFO1FBQzNGLE9BQU87SUFDVDtJQUNBLE1BQU1NLE1BQU1ILE9BQU9JLE9BQU8sQ0FBQyxZQUFZO0lBQ3ZDLE9BQU9kLHFCQUFxQkUsU0FBU2EsV0FBVyxDQUFDLE9BQU9DO1FBQ3RELE1BQU1DLE9BQU8sTUFBTUQsR0FBR0UsR0FBRyxDQUE2QyxT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
@@ -0,0 +1,9 @@
1
+ import { type OrganizationTransaction } from './store.js';
2
+ import type { ApiContext } from '../types/auth.types.js';
3
+ import type { Organization, OrganizationAccess } from './types.js';
4
+ export declare const organizationUserId: (context: ApiContext) => string;
5
+ export declare const organizationAccessInTransaction: (tx: OrganizationTransaction, context: ApiContext, organizationId: string, role: 'member' | 'admin' | 'owner') => Promise<OrganizationAccess>;
6
+ export declare const requireOrganizationAccess: (context: ApiContext, organizationId: string, role: 'member' | 'admin' | 'owner') => Promise<OrganizationAccess>;
7
+ export declare const listOrganizations: (context: ApiContext) => Promise<(Organization & {
8
+ canManage: boolean;
9
+ })[]>;