@nlabs/reaktor 1.18.0 → 1.20.0-reactorbox.1
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 +290 -0
- package/docs/GENERATION.md +42 -16
- package/lib/actions/alfredFaq.js +1 -1
- package/lib/actions/analytics.js +1 -1
- package/lib/actions/apps.js +17 -2
- package/lib/actions/connections.js +1 -1
- package/lib/actions/content.js +1 -1
- package/lib/actions/contentGeneration.d.ts +22 -1
- package/lib/actions/contentGeneration.js +120 -32
- package/lib/actions/contentGenerationErrors.js +1 -1
- package/lib/actions/contentGenerationSources.d.ts +29 -0
- package/lib/actions/contentGenerationSources.js +103 -0
- package/lib/actions/conversations.js +1 -1
- package/lib/actions/crm.d.ts +6 -2
- package/lib/actions/crm.js +91 -12
- package/lib/actions/crmCanonicalOutcomes.d.ts +88 -0
- package/lib/actions/crmCanonicalOutcomes.js +398 -0
- package/lib/actions/crmCanonicalPolicy.d.ts +92 -0
- package/lib/actions/crmCanonicalPolicy.js +104 -0
- package/lib/actions/crmCheckoutRecovery.d.ts +72 -0
- package/lib/actions/crmCheckoutRecovery.js +413 -0
- package/lib/actions/crmCheckoutRecoveryPolicy.d.ts +38 -0
- package/lib/actions/crmCheckoutRecoveryPolicy.js +61 -0
- package/lib/actions/crmDeliveryEvents.d.ts +24 -0
- package/lib/actions/crmDeliveryEvents.js +207 -0
- package/lib/actions/crmDeliveryEvidence.d.ts +17 -0
- package/lib/actions/crmDeliveryEvidence.js +58 -0
- package/lib/actions/crmExecution.d.ts +125 -0
- package/lib/actions/crmExecution.js +830 -0
- package/lib/actions/crmFinancialEvidence.d.ts +12 -0
- package/lib/actions/crmFinancialEvidence.js +60 -0
- package/lib/actions/crmInsights.d.ts +60 -0
- package/lib/actions/crmInsights.js +225 -0
- package/lib/actions/crmLeadFollowups.d.ts +66 -0
- package/lib/actions/crmLeadFollowups.js +209 -0
- package/lib/actions/crmOutcomes.d.ts +106 -0
- package/lib/actions/crmOutcomes.js +289 -0
- package/lib/actions/crmRecoveryRetention.d.ts +13 -0
- package/lib/actions/crmRecoveryRetention.js +163 -0
- package/lib/actions/crmReminderDispatch.d.ts +10 -0
- package/lib/actions/crmReminderDispatch.js +65 -0
- package/lib/actions/crmSourceOwnership.d.ts +7 -0
- package/lib/actions/crmSourceOwnership.js +27 -0
- package/lib/actions/crmSupportInsights.d.ts +18 -0
- package/lib/actions/crmSupportInsights.js +47 -0
- package/lib/actions/crmWinback.d.ts +71 -0
- package/lib/actions/crmWinback.js +347 -0
- package/lib/actions/crmWinbackConsent.d.ts +29 -0
- package/lib/actions/crmWinbackConsent.js +158 -0
- package/lib/actions/crmWinbackPolicy.d.ts +33 -0
- package/lib/actions/crmWinbackPolicy.js +115 -0
- package/lib/actions/crmWinbackShopSource.d.ts +15 -0
- package/lib/actions/crmWinbackShopSource.js +63 -0
- package/lib/actions/crud.js +1 -1
- package/lib/actions/databaseAccounts.js +1 -1
- package/lib/actions/databaseProvisioningLease.js +1 -1
- package/lib/actions/dynamodb.js +1 -1
- package/lib/actions/email.d.ts +4 -1
- package/lib/actions/email.js +25 -3
- package/lib/actions/files.js +1 -1
- package/lib/actions/flags.js +1 -1
- package/lib/actions/geminiVideo.js +1 -1
- package/lib/actions/groups.js +1 -1
- package/lib/actions/higgsfield.js +1 -1
- package/lib/actions/imageGeneration.js +1 -1
- package/lib/actions/images.js +1 -1
- package/lib/actions/index.d.ts +56 -0
- package/lib/actions/index.js +42 -1
- package/lib/actions/ios.js +1 -1
- package/lib/actions/locations.js +1 -1
- package/lib/actions/merchantAccountExperiment.d.ts +50 -0
- package/lib/actions/merchantAccountExperiment.js +424 -0
- package/lib/actions/merchantAccountExperimentConfig.d.ts +7 -0
- package/lib/actions/merchantAccountExperimentConfig.js +32 -0
- package/lib/actions/merchantAccountExperimentHost.d.ts +69 -0
- package/lib/actions/merchantAccountExperimentHost.js +92 -0
- package/lib/actions/merchantAccountExperimentPolicy.d.ts +66 -0
- package/lib/actions/merchantAccountExperimentPolicy.js +121 -0
- package/lib/actions/merchantAccountExperimentRelay.d.ts +10 -0
- package/lib/actions/merchantAccountExperimentRelay.js +75 -0
- package/lib/actions/merchantCalendar.d.ts +34 -0
- package/lib/actions/merchantCalendar.js +119 -0
- package/lib/actions/merchantCalendarBookings.d.ts +17 -0
- package/lib/actions/merchantCalendarBookings.js +113 -0
- package/lib/actions/merchantCalendarDelegation.d.ts +80 -0
- package/lib/actions/merchantCalendarDelegation.js +353 -0
- package/lib/actions/merchantCalendarDiscovery.d.ts +38 -0
- package/lib/actions/merchantCalendarDiscovery.js +124 -0
- package/lib/actions/merchantCalendarEventHost.d.ts +105 -0
- package/lib/actions/merchantCalendarEventHost.js +16 -0
- package/lib/actions/merchantCalendarEventPrivacy.d.ts +7 -0
- package/lib/actions/merchantCalendarEventPrivacy.js +70 -0
- package/lib/actions/merchantCalendarEventRepository.d.ts +121 -0
- package/lib/actions/merchantCalendarEventRepository.js +295 -0
- package/lib/actions/merchantCalendarEventTransport.d.ts +65 -0
- package/lib/actions/merchantCalendarEventTransport.js +132 -0
- package/lib/actions/merchantCalendarEvents.d.ts +172 -0
- package/lib/actions/merchantCalendarEvents.js +365 -0
- package/lib/actions/merchantCalendarInvitationConsent.d.ts +28 -0
- package/lib/actions/merchantCalendarInvitationConsent.js +118 -0
- package/lib/actions/merchantCalendarManagedSource.d.ts +22 -0
- package/lib/actions/merchantCalendarManagedSource.js +24 -0
- package/lib/actions/merchantCalendarOAuth.d.ts +92 -0
- package/lib/actions/merchantCalendarOAuth.js +502 -0
- package/lib/actions/merchantCalendarOAuthConfig.d.ts +4 -0
- package/lib/actions/merchantCalendarOAuthConfig.js +30 -0
- package/lib/actions/merchantCalendarOAuthRepository.d.ts +57 -0
- package/lib/actions/merchantCalendarOAuthRepository.js +108 -0
- package/lib/actions/merchantCalendarOAuthTransport.d.ts +4 -0
- package/lib/actions/merchantCalendarOAuthTransport.js +25 -0
- package/lib/actions/merchantCalendarScopes.d.ts +4 -0
- package/lib/actions/merchantCalendarScopes.js +31 -0
- package/lib/actions/merchantFinance.d.ts +65 -0
- package/lib/actions/merchantFinance.js +244 -0
- package/lib/actions/merchantFinanceProvider.d.ts +57 -0
- package/lib/actions/merchantFinanceProvider.js +180 -0
- package/lib/actions/merchantOperations.d.ts +94 -0
- package/lib/actions/merchantOperations.js +489 -0
- package/lib/actions/messages.js +1 -1
- package/lib/actions/notifications.js +1 -1
- package/lib/actions/ollamaGeneration.js +1 -1
- package/lib/actions/openaiResponseSession.js +1 -1
- package/lib/actions/payments.js +1 -1
- package/lib/actions/personas.js +1 -1
- package/lib/actions/phoneSupport.js +1 -1
- package/lib/actions/posts.js +1 -1
- package/lib/actions/providerCredentials.d.ts +35 -0
- package/lib/actions/providerCredentials.js +166 -0
- package/lib/actions/query.js +1 -1
- package/lib/actions/reactions.js +1 -1
- package/lib/actions/rum.js +1 -1
- package/lib/actions/s3.d.ts +10 -7
- package/lib/actions/s3.js +59 -14
- package/lib/actions/search.js +1 -1
- package/lib/actions/sms.js +1 -1
- package/lib/actions/statistics.js +1 -1
- package/lib/actions/subscriptions.js +1 -1
- package/lib/actions/supportChannelSources.d.ts +66 -0
- package/lib/actions/supportChannelSources.js +183 -0
- package/lib/actions/supportCommerce.d.ts +62 -0
- package/lib/actions/supportCommerce.js +252 -0
- package/lib/actions/supportConnect.d.ts +39 -0
- package/lib/actions/supportConnect.js +224 -0
- package/lib/actions/supportContext.d.ts +31 -0
- package/lib/actions/supportContext.js +88 -0
- package/lib/actions/supportConversation.d.ts +102 -0
- package/lib/actions/supportConversation.js +100 -0
- package/lib/actions/supportEmailEvents.d.ts +20 -0
- package/lib/actions/supportEmailEvents.js +130 -0
- package/lib/actions/supportEmailHandoff.d.ts +114 -0
- package/lib/actions/supportEmailHandoff.js +356 -0
- package/lib/actions/supportOperations.d.ts +32 -0
- package/lib/actions/supportOperations.js +74 -0
- package/lib/actions/supportPolicy.d.ts +9 -0
- package/lib/actions/supportPolicy.js +44 -0
- package/lib/actions/supportPurposeConsent.d.ts +32 -0
- package/lib/actions/supportPurposeConsent.js +196 -0
- package/lib/actions/supportPurposePrivacy.d.ts +15 -0
- package/lib/actions/supportPurposePrivacy.js +181 -0
- package/lib/actions/supportSemanticReview.d.ts +64 -0
- package/lib/actions/supportSemanticReview.js +239 -0
- package/lib/actions/tags.js +1 -1
- package/lib/actions/users.js +22 -3
- package/lib/actions/videoGeneration.js +1 -1
- package/lib/actions/videos.js +1 -1
- package/lib/adapters/arangoAdapter.js +1 -1
- package/lib/adapters/contentAdapter.js +1 -1
- package/lib/adapters/fileAdapter.js +1 -1
- package/lib/adapters/geminiGenerationAdapter.js +1 -1
- package/lib/adapters/higgsfieldAdapter.js +1 -1
- package/lib/adapters/higgsfieldModelCatalog.js +1 -1
- package/lib/adapters/higgsfieldModels.js +1 -1
- package/lib/adapters/imageAdapter.js +1 -1
- package/lib/adapters/imageGenerationAdapter.js +1 -1
- package/lib/adapters/index.js +1 -1
- package/lib/adapters/messageAdapter.js +1 -1
- package/lib/adapters/postAdapter.js +1 -1
- package/lib/adapters/reaktorAdapter.js +1 -1
- package/lib/adapters/tagAdapter.js +1 -1
- package/lib/adapters/userAdapter.js +1 -1
- package/lib/assistant/core.js +1 -1
- package/lib/assistant/faq.js +1 -1
- package/lib/assistant/faqCore.js +1 -1
- package/lib/assistant/index.js +1 -1
- package/lib/assistant/service.js +1 -1
- package/lib/config.js +1 -1
- package/lib/constants/collections.d.ts +2 -1
- package/lib/constants/collections.js +2 -1
- package/lib/durableChat/conversations.js +1 -1
- package/lib/durableChat/errors.js +1 -1
- package/lib/durableChat/events.js +1 -1
- package/lib/durableChat/index.js +1 -1
- package/lib/durableChat/membership.js +1 -1
- package/lib/durableChat/messageTypes.js +1 -1
- package/lib/durableChat/messages.js +1 -1
- package/lib/durableChat/transaction.js +1 -1
- package/lib/durableChat/types.js +1 -1
- package/lib/handlers/graphqlHandler.js +1 -1
- package/lib/index.js +1 -1
- package/lib/lambdas/actions/websockets.js +1 -1
- package/lib/lambdas/authorizer.js +1 -1
- package/lib/lambdas/connection.js +1 -1
- package/lib/lambdas/utils/message.js +1 -1
- package/lib/lambdas/utils/websocket.js +1 -1
- package/lib/mocks/conversation.js +1 -1
- package/lib/mocks/file.js +1 -1
- package/lib/mocks/group.js +1 -1
- package/lib/mocks/image.js +1 -1
- package/lib/mocks/post.js +1 -1
- package/lib/mocks/tag.js +1 -1
- package/lib/mocks/user.js +1 -1
- package/lib/mocks/video.js +1 -1
- package/lib/mutations/analytics/analytics.js +1 -1
- package/lib/mutations/content/content.js +1 -1
- package/lib/mutations/crm/crm.js +395 -7
- package/lib/mutations/events/events.js +1 -1
- package/lib/mutations/flags/flags.js +1 -1
- package/lib/mutations/groups/groups.js +1 -1
- package/lib/mutations/higgsfield/higgsfield.js +1 -1
- package/lib/mutations/images/images.js +1 -1
- package/lib/mutations/index.js +1 -1
- package/lib/mutations/locations/locations.js +1 -1
- package/lib/mutations/messages/messages.js +1 -1
- package/lib/mutations/personas/personas.js +1 -1
- package/lib/mutations/posts/posts.js +1 -1
- package/lib/mutations/reactions/reactions.js +1 -1
- package/lib/mutations/rum/rum.js +1 -1
- package/lib/mutations/statistics/statistics.js +1 -1
- package/lib/mutations/subscriptions/subscriptions.js +1 -1
- package/lib/mutations/tags/tags.js +1 -1
- package/lib/mutations/users/users.js +1 -1
- package/lib/mutations/videos/videos.js +1 -1
- package/lib/nativePush/graphql.js +1 -1
- package/lib/nativePush/index.js +1 -1
- package/lib/nativePush/migrations.js +1 -1
- package/lib/nativePush/nativePushContract.fixture.js +1 -1
- package/lib/nativePush/payload.js +1 -1
- package/lib/nativePush/repository.js +1 -1
- package/lib/nativePush/service.js +1 -1
- package/lib/nativePush/snsProvider.js +1 -1
- package/lib/nativePush/types.js +1 -1
- package/lib/objectTypes/analytics.js +1 -1
- package/lib/objectTypes/app.js +1 -1
- package/lib/objectTypes/bankAccount.js +1 -1
- package/lib/objectTypes/connection.js +1 -1
- package/lib/objectTypes/content.js +1 -1
- package/lib/objectTypes/contentGeneration.js +1 -1
- package/lib/objectTypes/conversation.js +1 -1
- package/lib/objectTypes/creditCard.js +1 -1
- package/lib/objectTypes/crm.js +1 -1
- package/lib/objectTypes/document.js +1 -1
- package/lib/objectTypes/error.js +1 -1
- package/lib/objectTypes/event.js +1 -1
- package/lib/objectTypes/external.js +1 -1
- package/lib/objectTypes/file.js +1 -1
- package/lib/objectTypes/filter.js +1 -1
- package/lib/objectTypes/flag.js +1 -1
- package/lib/objectTypes/group.js +1 -1
- package/lib/objectTypes/higgsfield.js +1 -1
- package/lib/objectTypes/iapSubscription.js +1 -1
- package/lib/objectTypes/image.js +1 -1
- package/lib/objectTypes/imageGeneration.js +1 -1
- package/lib/objectTypes/index.js +1 -1
- package/lib/objectTypes/location.js +1 -1
- package/lib/objectTypes/message.js +1 -1
- package/lib/objectTypes/passcode.js +1 -1
- package/lib/objectTypes/persona.js +1 -1
- package/lib/objectTypes/plan.js +1 -1
- package/lib/objectTypes/post.js +1 -1
- package/lib/objectTypes/query.js +1 -1
- package/lib/objectTypes/reaction.js +1 -1
- package/lib/objectTypes/relation.js +1 -1
- package/lib/objectTypes/rum.js +1 -1
- package/lib/objectTypes/search.js +1 -1
- package/lib/objectTypes/statistics.js +1 -1
- package/lib/objectTypes/subscription.js +1 -1
- package/lib/objectTypes/tag.js +1 -1
- package/lib/objectTypes/user.js +1 -1
- package/lib/objectTypes/video.js +1 -1
- package/lib/objectTypes/videoGeneration.js +1 -1
- package/lib/organizations/accountLifecycle.js +1 -1
- package/lib/organizations/authorization.js +1 -1
- package/lib/organizations/billing.js +1 -1
- package/lib/organizations/billingProvider.js +1 -1
- package/lib/organizations/billingUpdates.js +1 -1
- package/lib/organizations/index.js +1 -1
- package/lib/organizations/mail.js +1 -1
- package/lib/organizations/memberDirectory.js +1 -1
- package/lib/organizations/membership.js +1 -1
- package/lib/organizations/passwordRecovery.js +1 -1
- package/lib/organizations/plans.js +1 -1
- package/lib/organizations/providerPagination.js +1 -1
- package/lib/organizations/reconciliation.js +1 -1
- package/lib/organizations/signup.js +1 -1
- package/lib/organizations/store.js +1 -1
- package/lib/organizations/types.js +1 -1
- package/lib/organizations/verification.js +1 -1
- package/lib/queries/analytics/analytics.js +1 -1
- package/lib/queries/content/content.js +1 -1
- package/lib/queries/crm/crm.js +251 -5
- package/lib/queries/events/events.js +1 -1
- package/lib/queries/flags/flags.js +1 -1
- package/lib/queries/groups/groups.js +1 -1
- package/lib/queries/higgsfield/higgsfield.js +1 -1
- package/lib/queries/images/images.js +1 -1
- package/lib/queries/index.js +1 -1
- package/lib/queries/locations/locations.js +1 -1
- package/lib/queries/messages/messages.js +1 -1
- package/lib/queries/personas/personas.js +1 -1
- package/lib/queries/posts/posts.js +1 -1
- package/lib/queries/query/query.js +1 -1
- package/lib/queries/reactions/reactions.js +1 -1
- package/lib/queries/statistics/statistics.js +1 -1
- package/lib/queries/subscriptions/subscriptions.js +1 -1
- package/lib/queries/tags/tags.js +1 -1
- package/lib/queries/users/users.js +1 -1
- package/lib/queries/videos/videos.js +1 -1
- package/lib/templates/email/layout.js +1 -1
- package/lib/templates/email/passwordForgot.js +1 -1
- package/lib/templates/email/passwordRecovery.js +1 -1
- package/lib/templates/email/verifyEmail.js +1 -1
- package/lib/templates/email/welcome.js +1 -1
- package/lib/templates/sms/passwordForgot.js +1 -1
- package/lib/templates/sms/passwordRecovery.js +1 -1
- package/lib/templates/sms/verifyEmail.js +1 -1
- package/lib/templates/sms/verifyPhone.js +1 -1
- package/lib/templates/sms/welcome.js +1 -1
- package/lib/types/analytics.types.js +1 -1
- package/lib/types/apps.types.js +1 -1
- package/lib/types/arangodb.types.js +1 -1
- package/lib/types/auth.types.d.ts +2 -0
- package/lib/types/auth.types.js +1 -1
- package/lib/types/connections.types.js +1 -1
- package/lib/types/content.types.js +1 -1
- package/lib/types/conversations.types.js +1 -1
- package/lib/types/crm.types.d.ts +6 -0
- package/lib/types/crm.types.js +1 -1
- package/lib/types/databaseCredentials.types.js +1 -1
- package/lib/types/email.types.js +1 -1
- package/lib/types/error.types.js +1 -1
- package/lib/types/files.types.js +1 -1
- package/lib/types/flags.types.js +1 -1
- package/lib/types/google.types.js +1 -1
- package/lib/types/groups.types.js +1 -1
- package/lib/types/images.types.js +1 -1
- package/lib/types/index.js +1 -1
- package/lib/types/locations.types.js +1 -1
- package/lib/types/messages.types.js +1 -1
- package/lib/types/notifications.types.js +1 -1
- package/lib/types/payments.types.js +1 -1
- package/lib/types/personas.types.js +1 -1
- package/lib/types/posts.types.js +1 -1
- package/lib/types/rum.types.js +1 -1
- package/lib/types/statistics.types.js +1 -1
- package/lib/types/tags.types.js +1 -1
- package/lib/types/users.types.d.ts +2 -0
- package/lib/types/users.types.js +1 -1
- package/lib/types/videos.types.js +1 -1
- package/lib/types/websockets.types.js +1 -1
- package/lib/upload.js +1 -1
- package/lib/utils/adapterUtils.js +1 -1
- package/lib/utils/analyticsUtils.js +1 -1
- package/lib/utils/appContext.js +1 -1
- package/lib/utils/aqlHelpers.js +1 -1
- package/lib/utils/arangodbUtils.js +1 -1
- package/lib/utils/authUtils.js +17 -1
- package/lib/utils/awsUtils.js +1 -1
- package/lib/utils/collectionRegistry.js +1 -1
- package/lib/utils/contextUtils.js +1 -1
- package/lib/utils/databaseCredentials.js +1 -1
- package/lib/utils/dbI18n.example.js +1 -1
- package/lib/utils/dbI18n.js +1 -1
- package/lib/utils/generationCallback.js +1 -1
- package/lib/utils/googleTranslate.js +1 -1
- package/lib/utils/graphqlUtils.d.ts +2 -0
- package/lib/utils/graphqlUtils.js +1 -1
- package/lib/utils/imageUtils.js +1 -1
- package/lib/utils/index.js +1 -1
- package/lib/utils/languageDetection.js +1 -1
- package/lib/utils/localeUtils.example.js +1 -1
- package/lib/utils/localeUtils.js +1 -1
- package/lib/utils/mediaAccess.js +1 -1
- package/lib/utils/middlewareUtils.js +1 -1
- package/lib/utils/nodeRealtime.js +1 -1
- package/lib/utils/opaqueToken.js +1 -1
- package/lib/utils/queryBuilder.js +1 -1
- package/lib/utils/schemaUtils.js +1 -1
- package/lib/utils/secretDatabase.js +1 -1
- package/lib/utils/sessionUtils.js +1 -1
- package/lib/utils/stripeUtils.js +1 -1
- package/lib/utils/templateUtils.js +1 -1
- package/lib/utils/testUtils.js +1 -1
- package/lib/utils/translationQueue.example.js +1 -1
- package/lib/utils/translationQueue.js +1 -1
- package/lib/videoProcessing.js +1 -1
- package/package.json +8 -6
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle -- Native source document revisions. */ import { aql } from 'arangojs';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
+
import { scopeContextToApp } from '../utils/appContext.js';
|
|
4
|
+
import { useDb } from '../utils/arangodbUtils.js';
|
|
5
|
+
import { requireCrmAdministrator } from './crm.js';
|
|
6
|
+
import { ensureOwnerExecutionCollection } from './crmExecution.js';
|
|
7
|
+
export const supportChannelCollections = [
|
|
8
|
+
'supportChannelSources',
|
|
9
|
+
'supportChannelBindings',
|
|
10
|
+
'supportChannelEvents',
|
|
11
|
+
'supportChannelTombstones'
|
|
12
|
+
];
|
|
13
|
+
export const supportChannelHash = (value)=>createHash('sha256').update(JSON.stringify(value)).digest('hex');
|
|
14
|
+
export const supportChannelId = (value)=>typeof value === 'string' && /^[\w.-]{1,160}$/.test(value);
|
|
15
|
+
export const validSupportConnectSource = (source, appId, at)=>Boolean(source && source.appId === appId && source.enabled === true && supportChannelId(source.sourceId) && supportChannelId(source._rev) && source.databaseName && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(source.generation) && Number.isSafeInteger(source.expiresAt) && source.expiresAt > at && /^arn:aws(?:-[a-z]+)?:connect:[a-z0-9-]+:\d{12}:instance\/[a-f0-9-]{36}$/.test(source.instanceArn) && /^arn:aws(?:-[a-z]+)?:iam::\d{12}:role\/[\w+=,.@-]{1,64}$/.test(source.allowedCallerRoleArn) && source.instanceArn.split(':')[1] === source.allowedCallerRoleArn.split(':')[1] && source.instanceArn.split(':')[4] === source.allowedCallerRoleArn.split(':')[4]);
|
|
16
|
+
export const readSupportChannelTicket = async (context, appId, ticketId)=>{
|
|
17
|
+
const scoped = await scopeContextToApp(context, appId);
|
|
18
|
+
const row = await useDb(scoped.databaseName).query(aql`LET ticket = DOCUMENT('supportTickets', ${ticketId})
|
|
19
|
+
LET user = ticket ? DOCUMENT('users', ticket.userId) : null
|
|
20
|
+
RETURN {ticket: ticket ? {_key: ticket._key, _rev: ticket._rev, appId: ticket.appId,
|
|
21
|
+
deleted: ticket.deleted, userId: ticket.userId, status: ticket.status} : null,
|
|
22
|
+
user: user ? {_key: user._key, _rev: user._rev, appId: user.appId, deleted: user.deleted} : null}`).then((cursor)=>cursor.next());
|
|
23
|
+
if (!row?.ticket || !row.user || row.ticket._key !== ticketId || !supportChannelId(row.user._key) || row.ticket.appId !== appId || row.user.appId !== appId || row.ticket.deleted === true || row.user.deleted === true || row.ticket.userId !== row.user._key || !supportChannelId(row.ticket._rev) || !supportChannelId(row.user._rev) || ![
|
|
24
|
+
'submitted',
|
|
25
|
+
'open',
|
|
26
|
+
'in_progress',
|
|
27
|
+
'waiting_on_customer',
|
|
28
|
+
'waiting_on_internal'
|
|
29
|
+
].includes(row.ticket.status)) {
|
|
30
|
+
throw new Error('support_channel_ticket_hold');
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
databaseName: scoped.databaseName,
|
|
34
|
+
ticket: row.ticket,
|
|
35
|
+
user: row.user
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const setup = async (context)=>{
|
|
39
|
+
const db = useDb(context.databaseName);
|
|
40
|
+
await Promise.all(supportChannelCollections.map((name)=>ensureOwnerExecutionCollection(db, name)));
|
|
41
|
+
return db;
|
|
42
|
+
};
|
|
43
|
+
/** Administrator-reviewed source declaration. No AWS credentials or automatic intake/send authority. */ export const configureSupportConnectSource = async (context, input, now = Date.now)=>{
|
|
44
|
+
requireCrmAdministrator(context);
|
|
45
|
+
if (!input || Object.keys(input).some((key)=>![
|
|
46
|
+
'allowedCallerRoleArn',
|
|
47
|
+
'appId',
|
|
48
|
+
'enabled',
|
|
49
|
+
'expectedRevision',
|
|
50
|
+
'expiresAt',
|
|
51
|
+
'instanceArn',
|
|
52
|
+
'sourceId'
|
|
53
|
+
].includes(key)) || !supportChannelId(input.appId) || !supportChannelId(input.sourceId) || typeof input.enabled !== 'boolean' || !Number.isSafeInteger(input.expiresAt) || input.expiresAt <= now() || input.expiresAt - now() > 30 * 86400000 || input.expectedRevision !== undefined && !supportChannelId(input.expectedRevision)) {
|
|
54
|
+
throw new Error('invalid_support_channel_source');
|
|
55
|
+
}
|
|
56
|
+
const scoped = await scopeContextToApp(context, input.appId);
|
|
57
|
+
const candidate = {
|
|
58
|
+
...input,
|
|
59
|
+
_key: supportChannelHash([
|
|
60
|
+
input.appId,
|
|
61
|
+
input.sourceId
|
|
62
|
+
]),
|
|
63
|
+
_rev: 'candidate',
|
|
64
|
+
databaseName: scoped.databaseName,
|
|
65
|
+
enabled: true,
|
|
66
|
+
generation: randomUUID(),
|
|
67
|
+
modifiedAt: now()
|
|
68
|
+
};
|
|
69
|
+
if (!validSupportConnectSource(candidate, input.appId, now())) {
|
|
70
|
+
throw new Error('invalid_support_channel_source');
|
|
71
|
+
}
|
|
72
|
+
const db = await setup(context);
|
|
73
|
+
const { _rev: _revision, expectedRevision, ...stored } = {
|
|
74
|
+
...candidate,
|
|
75
|
+
enabled: input.enabled
|
|
76
|
+
};
|
|
77
|
+
const result = await db.query(expectedRevision ? aql`LET prior = DOCUMENT('supportChannelSources', ${candidate._key})
|
|
78
|
+
FILTER prior._rev == ${expectedRevision}
|
|
79
|
+
REPLACE {_key: ${candidate._key}, _rev: ${expectedRevision}} WITH ${stored}
|
|
80
|
+
IN supportChannelSources OPTIONS {ignoreRevs: false} RETURN NEW` : aql`INSERT ${stored} IN supportChannelSources RETURN NEW`).then((cursor)=>cursor.next());
|
|
81
|
+
if (!result) {
|
|
82
|
+
throw new Error('support_channel_source_changed');
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
appId: input.appId,
|
|
86
|
+
enabled: result.enabled,
|
|
87
|
+
expiresAt: result.expiresAt,
|
|
88
|
+
revision: result._rev,
|
|
89
|
+
sourceId: input.sourceId
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
/** Explicit association; a contact's existence is subsequently checked with Connect, never by email or phone. */ export const bindSupportConnectConversation = async (context, input, now = Date.now)=>{
|
|
93
|
+
requireCrmAdministrator(context);
|
|
94
|
+
if (!input || Object.keys(input).sort().join(',') !== 'appId,contactId,expiresAt,sourceId,sourceRevision,ticketId,ticketRevision' || ![
|
|
95
|
+
input.appId,
|
|
96
|
+
input.sourceId,
|
|
97
|
+
input.sourceRevision,
|
|
98
|
+
input.ticketId,
|
|
99
|
+
input.ticketRevision
|
|
100
|
+
].every(supportChannelId) || !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(input.contactId) || !Number.isSafeInteger(input.expiresAt) || input.expiresAt <= now()) {
|
|
101
|
+
throw new Error('invalid_support_channel_binding');
|
|
102
|
+
}
|
|
103
|
+
const db = await setup(context);
|
|
104
|
+
const source = await db.query(aql`RETURN DOCUMENT('supportChannelSources', ${supportChannelHash([
|
|
105
|
+
input.appId,
|
|
106
|
+
input.sourceId
|
|
107
|
+
])})`).then((cursor)=>cursor.next());
|
|
108
|
+
const row = await readSupportChannelTicket(context, input.appId, input.ticketId);
|
|
109
|
+
if (!validSupportConnectSource(source, input.appId, now()) || source._rev !== input.sourceRevision || source.databaseName !== row.databaseName || row.ticket._rev !== input.ticketRevision || input.expiresAt > source.expiresAt) {
|
|
110
|
+
throw new Error('support_channel_binding_hold');
|
|
111
|
+
}
|
|
112
|
+
const tombstoneKey = supportChannelHash([
|
|
113
|
+
input.appId,
|
|
114
|
+
input.sourceId,
|
|
115
|
+
input.contactId
|
|
116
|
+
]);
|
|
117
|
+
const binding = {
|
|
118
|
+
...input,
|
|
119
|
+
_key: supportChannelHash([
|
|
120
|
+
source.generation,
|
|
121
|
+
input.contactId
|
|
122
|
+
]),
|
|
123
|
+
generation: source.generation,
|
|
124
|
+
nativeUserId: row.user._key,
|
|
125
|
+
nativeUserRevision: row.user._rev,
|
|
126
|
+
tombstoneKey
|
|
127
|
+
};
|
|
128
|
+
const result = await db.query(aql`LET current = DOCUMENT('supportChannelSources', ${source._key})
|
|
129
|
+
LET tombstone = DOCUMENT('supportChannelTombstones', ${tombstoneKey})
|
|
130
|
+
LET prior = DOCUMENT('supportChannelBindings', ${binding._key})
|
|
131
|
+
LET matching = (FOR item IN supportChannelBindings FILTER item.appId == ${input.appId}
|
|
132
|
+
AND item.sourceId == ${input.sourceId} AND item.generation == ${source.generation}
|
|
133
|
+
AND item.contactId == ${input.contactId} LIMIT 2 RETURN item._key)
|
|
134
|
+
FILTER LENGTH(matching) == 0 OR (LENGTH(matching) == 1 AND matching[0] == ${binding._key})
|
|
135
|
+
FILTER current._rev == ${source._rev} AND current.enabled == true AND current.expiresAt > ${now()}
|
|
136
|
+
AND tombstone == null AND (prior == null OR prior == MERGE(${binding}, {_id: prior._id, _rev: prior._rev}))
|
|
137
|
+
UPSERT {_key: ${binding._key}} INSERT ${binding} UPDATE {} IN supportChannelBindings RETURN NEW`).then((cursor)=>cursor.next());
|
|
138
|
+
if (!result) {
|
|
139
|
+
throw new Error('support_channel_binding_changed');
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
appId: input.appId,
|
|
143
|
+
bindingId: result._key,
|
|
144
|
+
expiresAt: result.expiresAt,
|
|
145
|
+
revision: result._rev,
|
|
146
|
+
sourceId: input.sourceId,
|
|
147
|
+
ticketId: input.ticketId,
|
|
148
|
+
ticketRevision: input.ticketRevision
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
/** Administrative privacy erasure keeps an opaque tombstone to prevent old contact evidence being recreated. */ export const eraseSupportConnectEvidence = async (context, input, now = Date.now)=>{
|
|
152
|
+
requireCrmAdministrator(context);
|
|
153
|
+
if (!input || Object.keys(input).sort().join(',') !== 'appId,bindingId' || !supportChannelId(input.appId) || !/^[a-f0-9]{64}$/.test(input.bindingId)) {
|
|
154
|
+
throw new Error('invalid_support_channel_erasure');
|
|
155
|
+
}
|
|
156
|
+
await scopeContextToApp(context, input.appId);
|
|
157
|
+
const db = await setup(context);
|
|
158
|
+
const transaction = await db.beginTransaction({
|
|
159
|
+
exclusive: [
|
|
160
|
+
...supportChannelCollections
|
|
161
|
+
]
|
|
162
|
+
});
|
|
163
|
+
try {
|
|
164
|
+
const result = await transaction.step(()=>db.query(aql`LET binding = DOCUMENT('supportChannelBindings', ${input.bindingId})
|
|
165
|
+
FILTER binding.appId == ${input.appId}
|
|
166
|
+
LET removed = (FOR event IN supportChannelEvents FILTER event.bindingId == ${input.bindingId}
|
|
167
|
+
REMOVE event IN supportChannelEvents RETURN OLD._key)
|
|
168
|
+
UPSERT {_key: binding.tombstoneKey} INSERT {_key: binding.tombstoneKey, appId: ${input.appId}, erasedAt: ${now()}}
|
|
169
|
+
UPDATE {} IN supportChannelTombstones
|
|
170
|
+
REPLACE binding WITH {_key: binding._key, appId: binding.appId, erasedAt: ${now()},
|
|
171
|
+
tombstoneKey: binding.tombstoneKey} IN supportChannelBindings RETURN {erased: true}`)).then((cursor)=>cursor.next());
|
|
172
|
+
if (!result) {
|
|
173
|
+
throw new Error('support_channel_binding_hold');
|
|
174
|
+
}
|
|
175
|
+
await transaction.commit();
|
|
176
|
+
return result;
|
|
177
|
+
} catch (error) {
|
|
178
|
+
await transaction.abort();
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvYWN0aW9ucy9zdXBwb3J0Q2hhbm5lbFNvdXJjZXMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgbm8tdW5kZXJzY29yZS1kYW5nbGUgLS0gTmF0aXZlIHNvdXJjZSBkb2N1bWVudCByZXZpc2lvbnMuICovXG5pbXBvcnQge2FxbH0gZnJvbSAnYXJhbmdvanMnO1xuaW1wb3J0IHtjcmVhdGVIYXNoLCByYW5kb21VVUlEfSBmcm9tICdub2RlOmNyeXB0byc7XG5cbmltcG9ydCB7c2NvcGVDb250ZXh0VG9BcHB9IGZyb20gJy4uL3V0aWxzL2FwcENvbnRleHQuanMnO1xuaW1wb3J0IHt1c2VEYn0gZnJvbSAnLi4vdXRpbHMvYXJhbmdvZGJVdGlscy5qcyc7XG5pbXBvcnQge3JlcXVpcmVDcm1BZG1pbmlzdHJhdG9yfSBmcm9tICcuL2NybS5qcyc7XG5pbXBvcnQge2Vuc3VyZU93bmVyRXhlY3V0aW9uQ29sbGVjdGlvbn0gZnJvbSAnLi9jcm1FeGVjdXRpb24uanMnO1xuXG5pbXBvcnQgdHlwZSB7QXBpQ29udGV4dH0gZnJvbSAnLi4vdHlwZXMvYXV0aC50eXBlcy5qcyc7XG5cbmV4cG9ydCBjb25zdCBzdXBwb3J0Q2hhbm5lbENvbGxlY3Rpb25zID0gWydzdXBwb3J0Q2hhbm5lbFNvdXJjZXMnLCAnc3VwcG9ydENoYW5uZWxCaW5kaW5ncycsXG4gICdzdXBwb3J0Q2hhbm5lbEV2ZW50cycsICdzdXBwb3J0Q2hhbm5lbFRvbWJzdG9uZXMnXSBhcyBjb25zdDtcbmV4cG9ydCBjb25zdCBzdXBwb3J0Q2hhbm5lbEhhc2ggPSAodmFsdWU6IHVua25vd24pOiBzdHJpbmcgPT4gY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKEpTT04uc3RyaW5naWZ5KHZhbHVlKSkuZGlnZXN0KCdoZXgnKTtcbmV4cG9ydCBjb25zdCBzdXBwb3J0Q2hhbm5lbElkID0gKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgc3RyaW5nID0+IHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgL15bXFx3Li1dezEsMTYwfSQvLnRlc3QodmFsdWUpO1xuZXhwb3J0IGludGVyZmFjZSBTdXBwb3J0Q29ubmVjdFNvdXJjZUlucHV0IHtcbiAgYWxsb3dlZENhbGxlclJvbGVBcm46IHN0cmluZztcbiAgYXBwSWQ6IHN0cmluZztcbiAgZW5hYmxlZDogYm9vbGVhbjtcbiAgZXhwZWN0ZWRSZXZpc2lvbj86IHN0cmluZztcbiAgZXhwaXJlc0F0OiBudW1iZXI7XG4gIGluc3RhbmNlQXJuOiBzdHJpbmc7XG4gIHNvdXJjZUlkOiBzdHJpbmc7XG59XG5leHBvcnQgaW50ZXJmYWNlIFN1cHBvcnRDb25uZWN0U291cmNlIGV4dGVuZHMgU3VwcG9ydENvbm5lY3RTb3VyY2VJbnB1dCB7XG4gIF9rZXk6IHN0cmluZztcbiAgX3Jldjogc3RyaW5nO1xuICBkYXRhYmFzZU5hbWU6IHN0cmluZztcbiAgZ2VuZXJhdGlvbjogc3RyaW5nO1xuICBtb2RpZmllZEF0OiBudW1iZXI7XG59XG5leHBvcnQgaW50ZXJmYWNlIFN1cHBvcnRDb25uZWN0QmluZGluZ0lucHV0IHtcbiAgYXBwSWQ6IHN0cmluZztcbiAgY29udGFjdElkOiBzdHJpbmc7XG4gIGV4cGlyZXNBdDogbnVtYmVyO1xuICBzb3VyY2VJZDogc3RyaW5nO1xuICBzb3VyY2VSZXZpc2lvbjogc3RyaW5nO1xuICB0aWNrZXRJZDogc3RyaW5nO1xuICB0aWNrZXRSZXZpc2lvbjogc3RyaW5nO1xufVxuZXhwb3J0IGludGVyZmFjZSBTdXBwb3J0Q29ubmVjdEJpbmRpbmcgZXh0ZW5kcyBTdXBwb3J0Q29ubmVjdEJpbmRpbmdJbnB1dCB7XG4gIF9rZXk6IHN0cmluZztcbiAgX3Jldjogc3RyaW5nO1xuICBnZW5lcmF0aW9uOiBzdHJpbmc7XG4gIG5hdGl2ZVVzZXJJZDogc3RyaW5nO1xuICBuYXRpdmVVc2VyUmV2aXNpb246IHN0cmluZztcbiAgdG9tYnN0b25lS2V5OiBzdHJpbmc7XG59XG5leHBvcnQgY29uc3QgdmFsaWRTdXBwb3J0Q29ubmVjdFNvdXJjZSA9IChzb3VyY2U6IFN1cHBvcnRDb25uZWN0U291cmNlIHwgdW5kZWZpbmVkLCBhcHBJZDogc3RyaW5nLCBhdDogbnVtYmVyKVxuOiBzb3VyY2UgaXMgU3VwcG9ydENvbm5lY3RTb3VyY2UgPT4gQm9vbGVhbihzb3VyY2UgJiYgc291cmNlLmFwcElkID09PSBhcHBJZCAmJiBzb3VyY2UuZW5hYmxlZCA9PT0gdHJ1ZVxuICAmJiBzdXBwb3J0Q2hhbm5lbElkKHNvdXJjZS5zb3VyY2VJZCkgJiYgc3VwcG9ydENoYW5uZWxJZChzb3VyY2UuX3JldikgJiYgc291cmNlLmRhdGFiYXNlTmFtZVxuICAmJiAvXlthLWYwLTldezh9LVthLWYwLTldezR9LVthLWYwLTldezR9LVthLWYwLTldezR9LVthLWYwLTldezEyfSQvLnRlc3Qoc291cmNlLmdlbmVyYXRpb24pICYmIE51bWJlci5pc1NhZmVJbnRlZ2VyKHNvdXJjZS5leHBpcmVzQXQpICYmIHNvdXJjZS5leHBpcmVzQXQgPiBhdFxuICAmJiAvXmFybjphd3MoPzotW2Etel0rKT86Y29ubmVjdDpbYS16MC05LV0rOlxcZHsxMn06aW5zdGFuY2VcXC9bYS1mMC05LV17MzZ9JC8udGVzdChzb3VyY2UuaW5zdGFuY2VBcm4pXG4gICYmIC9eYXJuOmF3cyg/Oi1bYS16XSspPzppYW06OlxcZHsxMn06cm9sZVxcL1tcXHcrPSwuQC1dezEsNjR9JC8udGVzdChzb3VyY2UuYWxsb3dlZENhbGxlclJvbGVBcm4pXG4gICYmIHNvdXJjZS5pbnN0YW5jZUFybi5zcGxpdCgnOicpWzFdID09PSBzb3VyY2UuYWxsb3dlZENhbGxlclJvbGVBcm4uc3BsaXQoJzonKVsxXVxuICAmJiBzb3VyY2UuaW5zdGFuY2VBcm4uc3BsaXQoJzonKVs0XSA9PT0gc291cmNlLmFsbG93ZWRDYWxsZXJSb2xlQXJuLnNwbGl0KCc6JylbNF0pO1xuZXhwb3J0IGNvbnN0IHJlYWRTdXBwb3J0Q2hhbm5lbFRpY2tldCA9IGFzeW5jIChjb250ZXh0OiBBcGlDb250ZXh0LCBhcHBJZDogc3RyaW5nLCB0aWNrZXRJZDogc3RyaW5nKSA9PiB7XG4gIGNvbnN0IHNjb3BlZCA9IGF3YWl0IHNjb3BlQ29udGV4dFRvQXBwKGNvbnRleHQsIGFwcElkKTtcbiAgY29uc3Qgcm93ID0gYXdhaXQgdXNlRGIoc2NvcGVkLmRhdGFiYXNlTmFtZSkucXVlcnkoYXFsYExFVCB0aWNrZXQgPSBET0NVTUVOVCgnc3VwcG9ydFRpY2tldHMnLCAke3RpY2tldElkfSlcbiAgICBMRVQgdXNlciA9IHRpY2tldCA/IERPQ1VNRU5UKCd1c2VycycsIHRpY2tldC51c2VySWQpIDogbnVsbFxuICAgIFJFVFVSTiB7dGlja2V0OiB0aWNrZXQgPyB7X2tleTogdGlja2V0Ll9rZXksIF9yZXY6IHRpY2tldC5fcmV2LCBhcHBJZDogdGlja2V0LmFwcElkLFxuICAgICAgZGVsZXRlZDogdGlja2V0LmRlbGV0ZWQsIHVzZXJJZDogdGlja2V0LnVzZXJJZCwgc3RhdHVzOiB0aWNrZXQuc3RhdHVzfSA6IG51bGwsXG4gICAgICB1c2VyOiB1c2VyID8ge19rZXk6IHVzZXIuX2tleSwgX3JldjogdXNlci5fcmV2LCBhcHBJZDogdXNlci5hcHBJZCwgZGVsZXRlZDogdXNlci5kZWxldGVkfSA6IG51bGx9YClcbiAgICAudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpKTtcbiAgaWYoIXJvdz8udGlja2V0IHx8ICFyb3cudXNlciB8fCByb3cudGlja2V0Ll9rZXkgIT09IHRpY2tldElkIHx8ICFzdXBwb3J0Q2hhbm5lbElkKHJvdy51c2VyLl9rZXkpXG4gICAgfHwgcm93LnRpY2tldC5hcHBJZCAhPT0gYXBwSWQgfHwgcm93LnVzZXIuYXBwSWQgIT09IGFwcElkXG4gICAgfHwgcm93LnRpY2tldC5kZWxldGVkID09PSB0cnVlIHx8IHJvdy51c2VyLmRlbGV0ZWQgPT09IHRydWUgfHwgcm93LnRpY2tldC51c2VySWQgIT09IHJvdy51c2VyLl9rZXlcbiAgICB8fCAhc3VwcG9ydENoYW5uZWxJZChyb3cudGlja2V0Ll9yZXYpIHx8ICFzdXBwb3J0Q2hhbm5lbElkKHJvdy51c2VyLl9yZXYpXG4gICAgfHwgIVsnc3VibWl0dGVkJywgJ29wZW4nLCAnaW5fcHJvZ3Jlc3MnLCAnd2FpdGluZ19vbl9jdXN0b21lcicsICd3YWl0aW5nX29uX2ludGVybmFsJ10uaW5jbHVkZXMocm93LnRpY2tldC5zdGF0dXMpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdzdXBwb3J0X2NoYW5uZWxfdGlja2V0X2hvbGQnKTtcbiAgfVxuICByZXR1cm4ge2RhdGFiYXNlTmFtZTogc2NvcGVkLmRhdGFiYXNlTmFtZSwgdGlja2V0OiByb3cudGlja2V0LCB1c2VyOiByb3cudXNlcn07XG59O1xuY29uc3Qgc2V0dXAgPSBhc3luYyAoY29udGV4dDogQXBpQ29udGV4dCkgPT4ge1xuICBjb25zdCBkYiA9IHVzZURiKGNvbnRleHQuZGF0YWJhc2VOYW1lKTtcbiAgYXdhaXQgUHJvbWlzZS5hbGwoc3VwcG9ydENoYW5uZWxDb2xsZWN0aW9ucy5tYXAoKG5hbWUpID0+IGVuc3VyZU93bmVyRXhlY3V0aW9uQ29sbGVjdGlvbihkYiwgbmFtZSkpKTtcbiAgcmV0dXJuIGRiO1xufTtcbi8qKiBBZG1pbmlzdHJhdG9yLXJldmlld2VkIHNvdXJjZSBkZWNsYXJhdGlvbi4gTm8gQVdTIGNyZWRlbnRpYWxzIG9yIGF1dG9tYXRpYyBpbnRha2Uvc2VuZCBhdXRob3JpdHkuICovXG5leHBvcnQgY29uc3QgY29uZmlndXJlU3VwcG9ydENvbm5lY3RTb3VyY2UgPSBhc3luYyAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsIGlucHV0OiBTdXBwb3J0Q29ubmVjdFNvdXJjZUlucHV0LCBub3cgPSBEYXRlLm5vd1xuKSA9PiB7XG4gIHJlcXVpcmVDcm1BZG1pbmlzdHJhdG9yKGNvbnRleHQpO1xuICBpZighaW5wdXQgfHwgT2JqZWN0LmtleXMoaW5wdXQpLnNvbWUoKGtleSkgPT4gIVsnYWxsb3dlZENhbGxlclJvbGVBcm4nLCAnYXBwSWQnLCAnZW5hYmxlZCcsICdleHBlY3RlZFJldmlzaW9uJyxcbiAgICAnZXhwaXJlc0F0JywgJ2luc3RhbmNlQXJuJywgJ3NvdXJjZUlkJ10uaW5jbHVkZXMoa2V5KSkgfHwgIXN1cHBvcnRDaGFubmVsSWQoaW5wdXQuYXBwSWQpXG4gICAgfHwgIXN1cHBvcnRDaGFubmVsSWQoaW5wdXQuc291cmNlSWQpIHx8IHR5cGVvZiBpbnB1dC5lbmFibGVkICE9PSAnYm9vbGVhbidcbiAgICB8fCAhTnVtYmVyLmlzU2FmZUludGVnZXIoaW5wdXQuZXhwaXJlc0F0KSB8fCBpbnB1dC5leHBpcmVzQXQgPD0gbm93KCkgfHwgaW5wdXQuZXhwaXJlc0F0IC0gbm93KCkgPiAzMCAqIDg2NDAwMDAwXG4gICAgfHwgKGlucHV0LmV4cGVjdGVkUmV2aXNpb24gIT09IHVuZGVmaW5lZCAmJiAhc3VwcG9ydENoYW5uZWxJZChpbnB1dC5leHBlY3RlZFJldmlzaW9uKSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWRfc3VwcG9ydF9jaGFubmVsX3NvdXJjZScpO1xuICB9XG4gIGNvbnN0IHNjb3BlZCA9IGF3YWl0IHNjb3BlQ29udGV4dFRvQXBwKGNvbnRleHQsIGlucHV0LmFwcElkKTtcbiAgY29uc3QgY2FuZGlkYXRlID0gey4uLmlucHV0LCBfa2V5OiBzdXBwb3J0Q2hhbm5lbEhhc2goW2lucHV0LmFwcElkLCBpbnB1dC5zb3VyY2VJZF0pLCBfcmV2OiAnY2FuZGlkYXRlJyxcbiAgICBkYXRhYmFzZU5hbWU6IHNjb3BlZC5kYXRhYmFzZU5hbWUhLCBlbmFibGVkOiB0cnVlLCBnZW5lcmF0aW9uOiByYW5kb21VVUlEKCksIG1vZGlmaWVkQXQ6IG5vdygpfTtcbiAgaWYoIXZhbGlkU3VwcG9ydENvbm5lY3RTb3VyY2UoY2FuZGlkYXRlLCBpbnB1dC5hcHBJZCwgbm93KCkpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkX3N1cHBvcnRfY2hhbm5lbF9zb3VyY2UnKTtcbiAgfVxuICBjb25zdCBkYiA9IGF3YWl0IHNldHVwKGNvbnRleHQpO1xuICBjb25zdCB7X3JldjogX3JldmlzaW9uLCBleHBlY3RlZFJldmlzaW9uLCAuLi5zdG9yZWR9ID0gey4uLmNhbmRpZGF0ZSwgZW5hYmxlZDogaW5wdXQuZW5hYmxlZH07XG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGRiLnF1ZXJ5KGV4cGVjdGVkUmV2aXNpb24gPyBhcWxgTEVUIHByaW9yID0gRE9DVU1FTlQoJ3N1cHBvcnRDaGFubmVsU291cmNlcycsICR7Y2FuZGlkYXRlLl9rZXl9KVxuICAgIEZJTFRFUiBwcmlvci5fcmV2ID09ICR7ZXhwZWN0ZWRSZXZpc2lvbn1cbiAgICBSRVBMQUNFIHtfa2V5OiAke2NhbmRpZGF0ZS5fa2V5fSwgX3JldjogJHtleHBlY3RlZFJldmlzaW9ufX0gV0lUSCAke3N0b3JlZH1cbiAgICAgIElOIHN1cHBvcnRDaGFubmVsU291cmNlcyBPUFRJT05TIHtpZ25vcmVSZXZzOiBmYWxzZX0gUkVUVVJOIE5FV2BcbiAgICA6IGFxbGBJTlNFUlQgJHtzdG9yZWR9IElOIHN1cHBvcnRDaGFubmVsU291cmNlcyBSRVRVUk4gTkVXYClcbiAgICAudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpKTtcbiAgaWYoIXJlc3VsdCkge1xuICAgIHRocm93IG5ldyBFcnJvcignc3VwcG9ydF9jaGFubmVsX3NvdXJjZV9jaGFuZ2VkJyk7XG4gIH1cbiAgcmV0dXJuIHthcHBJZDogaW5wdXQuYXBwSWQsIGVuYWJsZWQ6IHJlc3VsdC5lbmFibGVkLCBleHBpcmVzQXQ6IHJlc3VsdC5leHBpcmVzQXQsXG4gICAgcmV2aXNpb246IHJlc3VsdC5fcmV2LCBzb3VyY2VJZDogaW5wdXQuc291cmNlSWR9O1xufTtcbi8qKiBFeHBsaWNpdCBhc3NvY2lhdGlvbjsgYSBjb250YWN0J3MgZXhpc3RlbmNlIGlzIHN1YnNlcXVlbnRseSBjaGVja2VkIHdpdGggQ29ubmVjdCwgbmV2ZXIgYnkgZW1haWwgb3IgcGhvbmUuICovXG5leHBvcnQgY29uc3QgYmluZFN1cHBvcnRDb25uZWN0Q29udmVyc2F0aW9uID0gYXN5bmMgKFxuICBjb250ZXh0OiBBcGlDb250ZXh0LCBpbnB1dDogU3VwcG9ydENvbm5lY3RCaW5kaW5nSW5wdXQsIG5vdyA9IERhdGUubm93XG4pID0+IHtcbiAgcmVxdWlyZUNybUFkbWluaXN0cmF0b3IoY29udGV4dCk7XG4gIGlmKCFpbnB1dCB8fCBPYmplY3Qua2V5cyhpbnB1dCkuc29ydCgpLmpvaW4oJywnKSAhPT0gJ2FwcElkLGNvbnRhY3RJZCxleHBpcmVzQXQsc291cmNlSWQsc291cmNlUmV2aXNpb24sdGlja2V0SWQsdGlja2V0UmV2aXNpb24nXG4gICAgfHwgIVtpbnB1dC5hcHBJZCwgaW5wdXQuc291cmNlSWQsIGlucHV0LnNvdXJjZVJldmlzaW9uLCBpbnB1dC50aWNrZXRJZCwgaW5wdXQudGlja2V0UmV2aXNpb25dXG4gICAgICAuZXZlcnkoc3VwcG9ydENoYW5uZWxJZClcbiAgICB8fCAhL15bYS1mMC05XXs4fS1bYS1mMC05XXs0fS1bYS1mMC05XXs0fS1bYS1mMC05XXs0fS1bYS1mMC05XXsxMn0kLy50ZXN0KGlucHV0LmNvbnRhY3RJZCkgfHwgIU51bWJlci5pc1NhZmVJbnRlZ2VyKGlucHV0LmV4cGlyZXNBdCkgfHwgaW5wdXQuZXhwaXJlc0F0IDw9IG5vdygpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkX3N1cHBvcnRfY2hhbm5lbF9iaW5kaW5nJyk7XG4gIH1cbiAgY29uc3QgZGIgPSBhd2FpdCBzZXR1cChjb250ZXh0KTtcbiAgY29uc3Qgc291cmNlID0gYXdhaXQgZGIucXVlcnkoYXFsYFJFVFVSTiBET0NVTUVOVCgnc3VwcG9ydENoYW5uZWxTb3VyY2VzJywgJHtzdXBwb3J0Q2hhbm5lbEhhc2goW2lucHV0LmFwcElkLCBpbnB1dC5zb3VyY2VJZF0pfSlgKVxuICAgIC50aGVuKChjdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpIGFzIFN1cHBvcnRDb25uZWN0U291cmNlIHwgdW5kZWZpbmVkO1xuICBjb25zdCByb3cgPSBhd2FpdCByZWFkU3VwcG9ydENoYW5uZWxUaWNrZXQoY29udGV4dCwgaW5wdXQuYXBwSWQsIGlucHV0LnRpY2tldElkKTtcbiAgaWYoIXZhbGlkU3VwcG9ydENvbm5lY3RTb3VyY2Uoc291cmNlLCBpbnB1dC5hcHBJZCwgbm93KCkpIHx8IHNvdXJjZS5fcmV2ICE9PSBpbnB1dC5zb3VyY2VSZXZpc2lvblxuICAgIHx8IHNvdXJjZS5kYXRhYmFzZU5hbWUgIT09IHJvdy5kYXRhYmFzZU5hbWUgfHwgcm93LnRpY2tldC5fcmV2ICE9PSBpbnB1dC50aWNrZXRSZXZpc2lvblxuICAgIHx8IGlucHV0LmV4cGlyZXNBdCA+IHNvdXJjZS5leHBpcmVzQXQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3N1cHBvcnRfY2hhbm5lbF9iaW5kaW5nX2hvbGQnKTtcbiAgfVxuICBjb25zdCB0b21ic3RvbmVLZXkgPSBzdXBwb3J0Q2hhbm5lbEhhc2goW2lucHV0LmFwcElkLCBpbnB1dC5zb3VyY2VJZCwgaW5wdXQuY29udGFjdElkXSk7XG4gIGNvbnN0IGJpbmRpbmcgPSB7Li4uaW5wdXQsIF9rZXk6IHN1cHBvcnRDaGFubmVsSGFzaChbc291cmNlLmdlbmVyYXRpb24sIGlucHV0LmNvbnRhY3RJZF0pLFxuICAgIGdlbmVyYXRpb246IHNvdXJjZS5nZW5lcmF0aW9uLCBuYXRpdmVVc2VySWQ6IHJvdy51c2VyLl9rZXksIG5hdGl2ZVVzZXJSZXZpc2lvbjogcm93LnVzZXIuX3JldiwgdG9tYnN0b25lS2V5fTtcbiAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZGIucXVlcnkoYXFsYExFVCBjdXJyZW50ID0gRE9DVU1FTlQoJ3N1cHBvcnRDaGFubmVsU291cmNlcycsICR7c291cmNlLl9rZXl9KVxuICAgIExFVCB0b21ic3RvbmUgPSBET0NVTUVOVCgnc3VwcG9ydENoYW5uZWxUb21ic3RvbmVzJywgJHt0b21ic3RvbmVLZXl9KVxuICAgIExFVCBwcmlvciA9IERPQ1VNRU5UKCdzdXBwb3J0Q2hhbm5lbEJpbmRpbmdzJywgJHtiaW5kaW5nLl9rZXl9KVxuICAgIExFVCBtYXRjaGluZyA9IChGT1IgaXRlbSBJTiBzdXBwb3J0Q2hhbm5lbEJpbmRpbmdzIEZJTFRFUiBpdGVtLmFwcElkID09ICR7aW5wdXQuYXBwSWR9XG4gICAgICBBTkQgaXRlbS5zb3VyY2VJZCA9PSAke2lucHV0LnNvdXJjZUlkfSBBTkQgaXRlbS5nZW5lcmF0aW9uID09ICR7c291cmNlLmdlbmVyYXRpb259XG4gICAgICBBTkQgaXRlbS5jb250YWN0SWQgPT0gJHtpbnB1dC5jb250YWN0SWR9IExJTUlUIDIgUkVUVVJOIGl0ZW0uX2tleSlcbiAgICBGSUxURVIgTEVOR1RIKG1hdGNoaW5nKSA9PSAwIE9SIChMRU5HVEgobWF0Y2hpbmcpID09IDEgQU5EIG1hdGNoaW5nWzBdID09ICR7YmluZGluZy5fa2V5fSlcbiAgICBGSUxURVIgY3VycmVudC5fcmV2ID09ICR7c291cmNlLl9yZXZ9IEFORCBjdXJyZW50LmVuYWJsZWQgPT0gdHJ1ZSBBTkQgY3VycmVudC5leHBpcmVzQXQgPiAke25vdygpfVxuICAgICAgQU5EIHRvbWJzdG9uZSA9PSBudWxsIEFORCAocHJpb3IgPT0gbnVsbCBPUiBwcmlvciA9PSBNRVJHRSgke2JpbmRpbmd9LCB7X2lkOiBwcmlvci5faWQsIF9yZXY6IHByaW9yLl9yZXZ9KSlcbiAgICBVUFNFUlQge19rZXk6ICR7YmluZGluZy5fa2V5fX0gSU5TRVJUICR7YmluZGluZ30gVVBEQVRFIHt9IElOIHN1cHBvcnRDaGFubmVsQmluZGluZ3MgUkVUVVJOIE5FV2ApXG4gICAgLnRoZW4oKGN1cnNvcikgPT4gY3Vyc29yLm5leHQoKSk7XG4gIGlmKCFyZXN1bHQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3N1cHBvcnRfY2hhbm5lbF9iaW5kaW5nX2NoYW5nZWQnKTtcbiAgfVxuICByZXR1cm4ge2FwcElkOiBpbnB1dC5hcHBJZCwgYmluZGluZ0lkOiByZXN1bHQuX2tleSwgZXhwaXJlc0F0OiByZXN1bHQuZXhwaXJlc0F0LFxuICAgIHJldmlzaW9uOiByZXN1bHQuX3Jldiwgc291cmNlSWQ6IGlucHV0LnNvdXJjZUlkLCB0aWNrZXRJZDogaW5wdXQudGlja2V0SWQsIHRpY2tldFJldmlzaW9uOiBpbnB1dC50aWNrZXRSZXZpc2lvbn07XG59O1xuLyoqIEFkbWluaXN0cmF0aXZlIHByaXZhY3kgZXJhc3VyZSBrZWVwcyBhbiBvcGFxdWUgdG9tYnN0b25lIHRvIHByZXZlbnQgb2xkIGNvbnRhY3QgZXZpZGVuY2UgYmVpbmcgcmVjcmVhdGVkLiAqL1xuZXhwb3J0IGNvbnN0IGVyYXNlU3VwcG9ydENvbm5lY3RFdmlkZW5jZSA9IGFzeW5jIChcbiAgY29udGV4dDogQXBpQ29udGV4dCwgaW5wdXQ6IHthcHBJZDogc3RyaW5nOyBiaW5kaW5nSWQ6IHN0cmluZ30sIG5vdyA9IERhdGUubm93XG4pID0+IHtcbiAgcmVxdWlyZUNybUFkbWluaXN0cmF0b3IoY29udGV4dCk7XG4gIGlmKCFpbnB1dCB8fCBPYmplY3Qua2V5cyhpbnB1dCkuc29ydCgpLmpvaW4oJywnKSAhPT0gJ2FwcElkLGJpbmRpbmdJZCdcbiAgICB8fCAhc3VwcG9ydENoYW5uZWxJZChpbnB1dC5hcHBJZCkgfHwgIS9eW2EtZjAtOV17NjR9JC8udGVzdChpbnB1dC5iaW5kaW5nSWQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkX3N1cHBvcnRfY2hhbm5lbF9lcmFzdXJlJyk7XG4gIH1cbiAgYXdhaXQgc2NvcGVDb250ZXh0VG9BcHAoY29udGV4dCwgaW5wdXQuYXBwSWQpO1xuICBjb25zdCBkYiA9IGF3YWl0IHNldHVwKGNvbnRleHQpO1xuICBjb25zdCB0cmFuc2FjdGlvbiA9IGF3YWl0IGRiLmJlZ2luVHJhbnNhY3Rpb24oe2V4Y2x1c2l2ZTogWy4uLnN1cHBvcnRDaGFubmVsQ29sbGVjdGlvbnNdfSk7XG4gIHRyeSB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdHJhbnNhY3Rpb24uc3RlcCgoKSA9PiBkYi5xdWVyeShhcWxgTEVUIGJpbmRpbmcgPSBET0NVTUVOVCgnc3VwcG9ydENoYW5uZWxCaW5kaW5ncycsICR7aW5wdXQuYmluZGluZ0lkfSlcbiAgICAgIEZJTFRFUiBiaW5kaW5nLmFwcElkID09ICR7aW5wdXQuYXBwSWR9XG4gICAgICBMRVQgcmVtb3ZlZCA9IChGT1IgZXZlbnQgSU4gc3VwcG9ydENoYW5uZWxFdmVudHMgRklMVEVSIGV2ZW50LmJpbmRpbmdJZCA9PSAke2lucHV0LmJpbmRpbmdJZH1cbiAgICAgICAgUkVNT1ZFIGV2ZW50IElOIHN1cHBvcnRDaGFubmVsRXZlbnRzIFJFVFVSTiBPTEQuX2tleSlcbiAgICAgIFVQU0VSVCB7X2tleTogYmluZGluZy50b21ic3RvbmVLZXl9IElOU0VSVCB7X2tleTogYmluZGluZy50b21ic3RvbmVLZXksIGFwcElkOiAke2lucHV0LmFwcElkfSwgZXJhc2VkQXQ6ICR7bm93KCl9fVxuICAgICAgICBVUERBVEUge30gSU4gc3VwcG9ydENoYW5uZWxUb21ic3RvbmVzXG4gICAgICBSRVBMQUNFIGJpbmRpbmcgV0lUSCB7X2tleTogYmluZGluZy5fa2V5LCBhcHBJZDogYmluZGluZy5hcHBJZCwgZXJhc2VkQXQ6ICR7bm93KCl9LFxuICAgICAgICB0b21ic3RvbmVLZXk6IGJpbmRpbmcudG9tYnN0b25lS2V5fSBJTiBzdXBwb3J0Q2hhbm5lbEJpbmRpbmdzIFJFVFVSTiB7ZXJhc2VkOiB0cnVlfWApKVxuICAgICAgLnRoZW4oKGN1cnNvcikgPT4gY3Vyc29yLm5leHQoKSk7XG4gICAgaWYoIXJlc3VsdCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdzdXBwb3J0X2NoYW5uZWxfYmluZGluZ19ob2xkJyk7XG4gICAgfVxuICAgIGF3YWl0IHRyYW5zYWN0aW9uLmNvbW1pdCgpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH0gY2F0Y2goZXJyb3IpIHtcbiAgICBhd2FpdCB0cmFuc2FjdGlvbi5hYm9ydCgpO1xuICAgIHRocm93IGVycm9yO1xuICB9XG59O1xuIl0sIm5hbWVzIjpbImFxbCIsImNyZWF0ZUhhc2giLCJyYW5kb21VVUlEIiwic2NvcGVDb250ZXh0VG9BcHAiLCJ1c2VEYiIsInJlcXVpcmVDcm1BZG1pbmlzdHJhdG9yIiwiZW5zdXJlT3duZXJFeGVjdXRpb25Db2xsZWN0aW9uIiwic3VwcG9ydENoYW5uZWxDb2xsZWN0aW9ucyIsInN1cHBvcnRDaGFubmVsSGFzaCIsInZhbHVlIiwidXBkYXRlIiwiSlNPTiIsInN0cmluZ2lmeSIsImRpZ2VzdCIsInN1cHBvcnRDaGFubmVsSWQiLCJ0ZXN0IiwidmFsaWRTdXBwb3J0Q29ubmVjdFNvdXJjZSIsInNvdXJjZSIsImFwcElkIiwiYXQiLCJCb29sZWFuIiwiZW5hYmxlZCIsInNvdXJjZUlkIiwiX3JldiIsImRhdGFiYXNlTmFtZSIsImdlbmVyYXRpb24iLCJOdW1iZXIiLCJpc1NhZmVJbnRlZ2VyIiwiZXhwaXJlc0F0IiwiaW5zdGFuY2VBcm4iLCJhbGxvd2VkQ2FsbGVyUm9sZUFybiIsInNwbGl0IiwicmVhZFN1cHBvcnRDaGFubmVsVGlja2V0IiwiY29udGV4dCIsInRpY2tldElkIiwic2NvcGVkIiwicm93IiwicXVlcnkiLCJ0aGVuIiwiY3Vyc29yIiwibmV4dCIsInRpY2tldCIsInVzZXIiLCJfa2V5IiwiZGVsZXRlZCIsInVzZXJJZCIsImluY2x1ZGVzIiwic3RhdHVzIiwiRXJyb3IiLCJzZXR1cCIsImRiIiwiUHJvbWlzZSIsImFsbCIsIm1hcCIsIm5hbWUiLCJjb25maWd1cmVTdXBwb3J0Q29ubmVjdFNvdXJjZSIsImlucHV0Iiwibm93IiwiRGF0ZSIsIk9iamVjdCIsImtleXMiLCJzb21lIiwia2V5IiwiZXhwZWN0ZWRSZXZpc2lvbiIsInVuZGVmaW5lZCIsImNhbmRpZGF0ZSIsIm1vZGlmaWVkQXQiLCJfcmV2aXNpb24iLCJzdG9yZWQiLCJyZXN1bHQiLCJyZXZpc2lvbiIsImJpbmRTdXBwb3J0Q29ubmVjdENvbnZlcnNhdGlvbiIsInNvcnQiLCJqb2luIiwic291cmNlUmV2aXNpb24iLCJ0aWNrZXRSZXZpc2lvbiIsImV2ZXJ5IiwiY29udGFjdElkIiwidG9tYnN0b25lS2V5IiwiYmluZGluZyIsIm5hdGl2ZVVzZXJJZCIsIm5hdGl2ZVVzZXJSZXZpc2lvbiIsImJpbmRpbmdJZCIsImVyYXNlU3VwcG9ydENvbm5lY3RFdmlkZW5jZSIsInRyYW5zYWN0aW9uIiwiYmVnaW5UcmFuc2FjdGlvbiIsImV4Y2x1c2l2ZSIsInN0ZXAiLCJjb21taXQiLCJlcnJvciIsImFib3J0Il0sIm1hcHBpbmdzIjoiQUFBQSw0RUFBNEUsR0FDNUUsU0FBUUEsR0FBRyxRQUFPLFdBQVc7QUFDN0IsU0FBUUMsVUFBVSxFQUFFQyxVQUFVLFFBQU8sY0FBYztBQUVuRCxTQUFRQyxpQkFBaUIsUUFBTyx5QkFBeUI7QUFDekQsU0FBUUMsS0FBSyxRQUFPLDRCQUE0QjtBQUNoRCxTQUFRQyx1QkFBdUIsUUFBTyxXQUFXO0FBQ2pELFNBQVFDLDhCQUE4QixRQUFPLG9CQUFvQjtBQUlqRSxPQUFPLE1BQU1DLDRCQUE0QjtJQUFDO0lBQXlCO0lBQ2pFO0lBQXdCO0NBQTJCLENBQVU7QUFDL0QsT0FBTyxNQUFNQyxxQkFBcUIsQ0FBQ0MsUUFBMkJSLFdBQVcsVUFBVVMsTUFBTSxDQUFDQyxLQUFLQyxTQUFTLENBQUNILFFBQVFJLE1BQU0sQ0FBQyxPQUFPO0FBQy9ILE9BQU8sTUFBTUMsbUJBQW1CLENBQUNMLFFBQW9DLE9BQU9BLFVBQVUsWUFBWSxrQkFBa0JNLElBQUksQ0FBQ04sT0FBTztBQWtDaEksT0FBTyxNQUFNTyw0QkFBNEIsQ0FBQ0MsUUFBMENDLE9BQWVDLEtBQy9EQyxRQUFRSCxVQUFVQSxPQUFPQyxLQUFLLEtBQUtBLFNBQVNELE9BQU9JLE9BQU8sS0FBSyxRQUM5RlAsaUJBQWlCRyxPQUFPSyxRQUFRLEtBQUtSLGlCQUFpQkcsT0FBT00sSUFBSSxLQUFLTixPQUFPTyxZQUFZLElBQ3pGLGlFQUFpRVQsSUFBSSxDQUFDRSxPQUFPUSxVQUFVLEtBQUtDLE9BQU9DLGFBQWEs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
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { RequestImplementation } from '@nlabs/rip-hunter/http';
|
|
3
|
+
import type { ApiContext } from '../types/auth.types.js';
|
|
4
|
+
declare const sourceSchema: z.ZodObject<{
|
|
5
|
+
appId: z.ZodString;
|
|
6
|
+
bindings: z.ZodArray<z.ZodObject<{
|
|
7
|
+
nativeOrderId: z.ZodString;
|
|
8
|
+
shopifyOrderId: z.ZodString;
|
|
9
|
+
}, z.core.$strict>>;
|
|
10
|
+
customersAccessApproved: z.ZodLiteral<true>;
|
|
11
|
+
expiresAt: z.ZodNumber;
|
|
12
|
+
id: z.ZodString;
|
|
13
|
+
ordersAccessApproved: z.ZodLiteral<true>;
|
|
14
|
+
ownerId: z.ZodString;
|
|
15
|
+
revision: z.ZodString;
|
|
16
|
+
shop: z.ZodString;
|
|
17
|
+
shopId: z.ZodString;
|
|
18
|
+
token: z.ZodString;
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
export type SupportCommerceSource = z.infer<typeof sourceSchema>;
|
|
21
|
+
export interface SupportCommerceInput {
|
|
22
|
+
appId: string;
|
|
23
|
+
orderId: string;
|
|
24
|
+
orderRevision: string;
|
|
25
|
+
sourceId: string;
|
|
26
|
+
ticketId: string;
|
|
27
|
+
ticketRevision: string;
|
|
28
|
+
}
|
|
29
|
+
export interface SupportCommerceObservation {
|
|
30
|
+
appId: string;
|
|
31
|
+
bindingRevision: string;
|
|
32
|
+
generatedAt: number;
|
|
33
|
+
order: {
|
|
34
|
+
financialStatus: string;
|
|
35
|
+
fulfillmentStatus: string;
|
|
36
|
+
id: string;
|
|
37
|
+
nativeId: string;
|
|
38
|
+
updatedAt: string;
|
|
39
|
+
};
|
|
40
|
+
providerRevision: string;
|
|
41
|
+
provenance: 'verified_shopify_native_record_association';
|
|
42
|
+
schemaVersion: 'support_commerce_v1';
|
|
43
|
+
shop: {
|
|
44
|
+
domain: string;
|
|
45
|
+
id: string;
|
|
46
|
+
};
|
|
47
|
+
sourceId: string;
|
|
48
|
+
sourceRevision: string;
|
|
49
|
+
ticketId: string;
|
|
50
|
+
ticketRevision: string;
|
|
51
|
+
validUntil: number;
|
|
52
|
+
}
|
|
53
|
+
/** Explicit reviewed source/order whitelist. Other purposes do not transfer protected-data approvals. */
|
|
54
|
+
export declare const supportCommerceSources: (raw?: string) => SupportCommerceSource[];
|
|
55
|
+
export declare const SUPPORT_COMMERCE_QUERY = "query SupportCommerceOrder($id: ID!) {\n shop { id myshopifyDomain }\n currentAppInstallation { accessScopes { handle } }\n order(id: $id) { id customer { id } updatedAt displayFinancialStatus displayFulfillmentStatus }\n}";
|
|
56
|
+
/** Read-only native association. No email matching, association mutation or inferred settlement. */
|
|
57
|
+
export declare const readSupportCommerce: (context: ApiContext, input: SupportCommerceInput, options?: {
|
|
58
|
+
now?: () => number;
|
|
59
|
+
requestImplementation?: RequestImplementation;
|
|
60
|
+
sources?: () => readonly SupportCommerceSource[];
|
|
61
|
+
}) => Promise<SupportCommerceObservation>;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle -- Exact native document and graph revision proofs. */ import { httpRequest, readBinaryResponse } from '@nlabs/rip-hunter/http';
|
|
2
|
+
import { aql } from 'arangojs';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { scopeContextToApp } from '../utils/appContext.js';
|
|
5
|
+
import { useDb } from '../utils/arangodbUtils.js';
|
|
6
|
+
import { crmCanonicalDigest as digest } from './crmCanonicalPolicy.js';
|
|
7
|
+
import { authorizeCrmExecutionGrant } from './crmExecution.js';
|
|
8
|
+
const id = z.string().regex(/^[\w.-]{1,160}$/);
|
|
9
|
+
const orderId = z.string().regex(/^gid:\/\/shopify\/Order\/\d+$/);
|
|
10
|
+
const shopId = z.string().regex(/^gid:\/\/shopify\/Shop\/\d+$/);
|
|
11
|
+
const sourceSchema = z.object({
|
|
12
|
+
appId: id,
|
|
13
|
+
bindings: z.array(z.object({
|
|
14
|
+
nativeOrderId: id,
|
|
15
|
+
shopifyOrderId: orderId
|
|
16
|
+
}).strict()).min(1).max(100),
|
|
17
|
+
customersAccessApproved: z.literal(true),
|
|
18
|
+
expiresAt: z.number().int().positive(),
|
|
19
|
+
id,
|
|
20
|
+
ordersAccessApproved: z.literal(true),
|
|
21
|
+
ownerId: id,
|
|
22
|
+
revision: id,
|
|
23
|
+
shop: z.string().regex(/^[a-z0-9][a-z0-9-]*\.myshopify\.com$/),
|
|
24
|
+
shopId,
|
|
25
|
+
token: z.string().min(1).max(4096)
|
|
26
|
+
}).strict();
|
|
27
|
+
/** Explicit reviewed source/order whitelist. Other purposes do not transfer protected-data approvals. */ export const supportCommerceSources = (raw = process.env.SUPPORT_COMMERCE_SOURCES)=>{
|
|
28
|
+
if (!raw) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const sources = z.array(sourceSchema).max(100).parse(JSON.parse(raw));
|
|
33
|
+
if (new Set(sources.map((source)=>source.id)).size !== sources.length || sources.some((source)=>new Set(source.bindings.map((binding)=>binding.nativeOrderId)).size !== source.bindings.length)) {
|
|
34
|
+
throw new Error('ambiguous');
|
|
35
|
+
}
|
|
36
|
+
return sources;
|
|
37
|
+
} catch {
|
|
38
|
+
throw new Error('support_commerce_source_configuration_hold');
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
export const SUPPORT_COMMERCE_QUERY = `query SupportCommerceOrder($id: ID!) {
|
|
42
|
+
shop { id myshopifyDomain }
|
|
43
|
+
currentAppInstallation { accessScopes { handle } }
|
|
44
|
+
order(id: $id) { id customer { id } updatedAt displayFinancialStatus displayFulfillmentStatus }
|
|
45
|
+
}`;
|
|
46
|
+
const providerSchema = z.object({
|
|
47
|
+
currentAppInstallation: z.object({
|
|
48
|
+
accessScopes: z.array(z.object({
|
|
49
|
+
handle: z.string()
|
|
50
|
+
})).max(100)
|
|
51
|
+
}),
|
|
52
|
+
order: z.object({
|
|
53
|
+
customer: z.object({
|
|
54
|
+
id: z.string().regex(/^gid:\/\/shopify\/Customer\/\d+$/)
|
|
55
|
+
}),
|
|
56
|
+
displayFinancialStatus: z.enum([
|
|
57
|
+
'AUTHORIZED',
|
|
58
|
+
'EXPIRED',
|
|
59
|
+
'PAID',
|
|
60
|
+
'PARTIALLY_PAID',
|
|
61
|
+
'PARTIALLY_REFUNDED',
|
|
62
|
+
'PENDING',
|
|
63
|
+
'REFUNDED',
|
|
64
|
+
'VOIDED'
|
|
65
|
+
]),
|
|
66
|
+
displayFulfillmentStatus: z.enum([
|
|
67
|
+
'FULFILLED',
|
|
68
|
+
'IN_PROGRESS',
|
|
69
|
+
'ON_HOLD',
|
|
70
|
+
'OPEN',
|
|
71
|
+
'PARTIALLY_FULFILLED',
|
|
72
|
+
'PENDING_FULFILLMENT',
|
|
73
|
+
'REQUEST_DECLINED',
|
|
74
|
+
'RESTOCKED',
|
|
75
|
+
'SCHEDULED',
|
|
76
|
+
'UNFULFILLED'
|
|
77
|
+
]),
|
|
78
|
+
id: orderId,
|
|
79
|
+
updatedAt: z.string().datetime({
|
|
80
|
+
offset: true
|
|
81
|
+
})
|
|
82
|
+
}).strict(),
|
|
83
|
+
shop: z.object({
|
|
84
|
+
id: shopId,
|
|
85
|
+
myshopifyDomain: z.string()
|
|
86
|
+
}).strict()
|
|
87
|
+
}).strict();
|
|
88
|
+
const external = (value, type)=>{
|
|
89
|
+
if (typeof value !== 'string') {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
if (/^\d+$/.test(value)) {
|
|
93
|
+
return `gid://shopify/${type}/${value}`;
|
|
94
|
+
}
|
|
95
|
+
return new RegExp(`^gid://shopify/${type}/\\d+$`).test(value) ? value : undefined;
|
|
96
|
+
};
|
|
97
|
+
/** Read-only native association. No email matching, association mutation or inferred settlement. */ export const readSupportCommerce = async (context, input, options = {})=>{
|
|
98
|
+
if (!z.object({
|
|
99
|
+
appId: id,
|
|
100
|
+
orderId: id,
|
|
101
|
+
orderRevision: id,
|
|
102
|
+
sourceId: id,
|
|
103
|
+
ticketId: id,
|
|
104
|
+
ticketRevision: id
|
|
105
|
+
}).strict().safeParse(input).success) {
|
|
106
|
+
throw new Error('invalid_support_commerce_input');
|
|
107
|
+
}
|
|
108
|
+
const selection = structuredClone(input);
|
|
109
|
+
const now = options.now || Date.now;
|
|
110
|
+
const sources = options.sources || supportCommerceSources;
|
|
111
|
+
const authority = async ()=>{
|
|
112
|
+
const grant = await authorizeCrmExecutionGrant(context, selection.appId, 'support:commerce', now());
|
|
113
|
+
await authorizeCrmExecutionGrant(context, selection.appId, 'support:read', now());
|
|
114
|
+
const scoped = await scopeContextToApp(context, selection.appId);
|
|
115
|
+
const matches = sources().filter((source)=>source.id === selection.sourceId);
|
|
116
|
+
const source = matches[0];
|
|
117
|
+
const binding = source?.bindings.find((value)=>value.nativeOrderId === selection.orderId);
|
|
118
|
+
if (matches.length !== 1 || !sourceSchema.safeParse(source).success || source.appId !== selection.appId || source.ownerId !== grant.ownerId || source.expiresAt <= now() || !binding || source.bindings.filter((value)=>value.nativeOrderId === selection.orderId).length !== 1 || scoped.databaseName !== grant.databaseName) {
|
|
119
|
+
throw new Error('support_commerce_authority_hold');
|
|
120
|
+
}
|
|
121
|
+
const db = useDb(grant.databaseName);
|
|
122
|
+
const row = await db.query(aql`LET ticket = DOCUMENT('supportTickets', ${selection.ticketId})
|
|
123
|
+
LET user = ticket ? DOCUMENT('users', ticket.userId) : null
|
|
124
|
+
LET order = DOCUMENT('customerOrders', ${selection.orderId})
|
|
125
|
+
LET currentConsent = (FOR record IN supportPurposeConsents
|
|
126
|
+
FILTER record.appId == ${selection.appId} AND record.userId == user._key
|
|
127
|
+
AND record.purpose == 'support_commerce' LIMIT 2 RETURN record)
|
|
128
|
+
LET ticketEdges = (FOR edge IN hasSupportTicket FILTER edge._to == CONCAT('supportTickets/', ${selection.ticketId})
|
|
129
|
+
LIMIT 2 RETURN {from: edge._from, revision: edge._rev})
|
|
130
|
+
LET orderEdges = (FOR edge IN hasCustomerOrder FILTER edge._to == CONCAT('customerOrders/', ${selection.orderId})
|
|
131
|
+
LIMIT 2 RETURN {from: edge._from, revision: edge._rev})
|
|
132
|
+
RETURN {ticket: ticket ? {_key: ticket._key, _rev: ticket._rev, appId: ticket.appId, deleted: ticket.deleted,
|
|
133
|
+
shopifyOrderId: ticket.shopifyOrderId, status: ticket.status, userId: ticket.userId} : null,
|
|
134
|
+
user: user ? {_key: user._key, _rev: user._rev, active: user.active, appId: user.appId,
|
|
135
|
+
crmAnalyticsSuppressed: user.crmAnalyticsSuppressed, deleted: user.deleted,
|
|
136
|
+
shopifyCustomerId: user.shopifyCustomerId} : null,
|
|
137
|
+
order: order ? {_key: order._key, _rev: order._rev, appId: order.appId, deleted: order.deleted,
|
|
138
|
+
shopifyCustomerId: order.shopifyCustomerId, shopifyOrderId: order.shopifyOrderId, userId: order.userId} : null,
|
|
139
|
+
consents: currentConsent, orderEdges, ticketEdges}`).then((cursor)=>cursor.next());
|
|
140
|
+
const { ticket, user, order, consents, orderEdges, ticketEdges } = row || {};
|
|
141
|
+
const active = (record)=>Boolean(record && id.safeParse(record._key).success && id.safeParse(record._rev).success && record.appId === selection.appId && record.deleted !== true);
|
|
142
|
+
const consent = Array.isArray(consents) && consents.length === 1 ? consents[0] : undefined;
|
|
143
|
+
if (!active(ticket) || !active(user) || !active(order) || ticket._key !== selection.ticketId || ticket._rev !== selection.ticketRevision || order._key !== selection.orderId || order._rev !== selection.orderRevision || user.active === false || user.crmAnalyticsSuppressed === true || ticket.userId !== user._key || order.userId !== user._key || ![
|
|
144
|
+
'submitted',
|
|
145
|
+
'open',
|
|
146
|
+
'in_progress',
|
|
147
|
+
'waiting_on_customer',
|
|
148
|
+
'waiting_on_internal'
|
|
149
|
+
].includes(ticket.status) || external(ticket.shopifyOrderId, 'Order') !== binding.shopifyOrderId || external(order.shopifyOrderId, 'Order') !== binding.shopifyOrderId || !external(user.shopifyCustomerId, 'Customer') || external(order.shopifyCustomerId, 'Customer') !== external(user.shopifyCustomerId, 'Customer') || !consent || consent.appId !== selection.appId || consent.userId !== user._key || consent.purpose !== 'support_commerce' || consent._key !== digest([
|
|
150
|
+
selection.appId,
|
|
151
|
+
user._key,
|
|
152
|
+
'support_commerce'
|
|
153
|
+
]) || !id.safeParse(consent._rev).success || consent.source !== 'authenticated_customer' || consent.status !== 'active' || !Number.isSafeInteger(consent.at) || consent.at > now() || !Number.isSafeInteger(consent.expiresAt) || consent.expiresAt <= now() || ![
|
|
154
|
+
orderEdges,
|
|
155
|
+
ticketEdges
|
|
156
|
+
].every((edges)=>Array.isArray(edges) && edges.length === 1 && edges[0].from === `users/${user._key}` && id.safeParse(edges[0].revision).success)) {
|
|
157
|
+
throw new Error('support_commerce_native_identity_or_consent_hold');
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
binding,
|
|
161
|
+
consent,
|
|
162
|
+
grant,
|
|
163
|
+
identity: digest([
|
|
164
|
+
grant.id,
|
|
165
|
+
grant.hash,
|
|
166
|
+
grant.databaseName,
|
|
167
|
+
source,
|
|
168
|
+
row
|
|
169
|
+
]),
|
|
170
|
+
row,
|
|
171
|
+
source
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
const initial = await authority();
|
|
175
|
+
const deadline = now() + 15000;
|
|
176
|
+
const current = await authority();
|
|
177
|
+
if (current.identity !== initial.identity || now() >= deadline) {
|
|
178
|
+
throw new Error('support_commerce_source_changed');
|
|
179
|
+
}
|
|
180
|
+
let data;
|
|
181
|
+
try {
|
|
182
|
+
const response = await httpRequest(`https://${initial.source.shop}/admin/api/2026-10/graphql.json`, {
|
|
183
|
+
body: JSON.stringify({
|
|
184
|
+
query: SUPPORT_COMMERCE_QUERY,
|
|
185
|
+
variables: {
|
|
186
|
+
id: initial.binding.shopifyOrderId
|
|
187
|
+
}
|
|
188
|
+
}),
|
|
189
|
+
headers: {
|
|
190
|
+
'Content-Type': 'application/json',
|
|
191
|
+
'X-Shopify-Access-Token': initial.source.token
|
|
192
|
+
},
|
|
193
|
+
method: 'POST',
|
|
194
|
+
redirect: 'error',
|
|
195
|
+
requestImplementation: options.requestImplementation,
|
|
196
|
+
timeout: Math.max(1, deadline - now())
|
|
197
|
+
}, async (response)=>{
|
|
198
|
+
if (response.status !== 200 || response.redirected) {
|
|
199
|
+
throw new Error('provider');
|
|
200
|
+
}
|
|
201
|
+
const bytes = await readBinaryResponse(response, 1048576);
|
|
202
|
+
const envelope = z.object({
|
|
203
|
+
data: providerSchema,
|
|
204
|
+
errors: z.array(z.unknown()).max(100).optional()
|
|
205
|
+
}).strict().parse(JSON.parse(new TextDecoder().decode(bytes)));
|
|
206
|
+
if (envelope.errors?.length) {
|
|
207
|
+
throw new Error('provider');
|
|
208
|
+
}
|
|
209
|
+
return envelope.data;
|
|
210
|
+
});
|
|
211
|
+
data = response;
|
|
212
|
+
} catch {
|
|
213
|
+
throw new Error('support_commerce_provider_read_hold');
|
|
214
|
+
}
|
|
215
|
+
if (data.shop.id !== initial.source.shopId || data.shop.myshopifyDomain !== initial.source.shop || ![
|
|
216
|
+
'read_orders',
|
|
217
|
+
'read_customers'
|
|
218
|
+
].every((scope)=>data.currentAppInstallation.accessScopes.some((entry)=>entry.handle === scope)) || data.order.id !== initial.binding.shopifyOrderId || data.order.customer.id !== external(initial.row.user.shopifyCustomerId, 'Customer') || Date.parse(data.order.updatedAt) > now()) {
|
|
219
|
+
throw new Error('support_commerce_provider_identity_hold');
|
|
220
|
+
}
|
|
221
|
+
const latest = await authority();
|
|
222
|
+
if (latest.identity !== initial.identity || now() >= deadline) {
|
|
223
|
+
throw new Error('support_commerce_source_changed');
|
|
224
|
+
}
|
|
225
|
+
const generatedAt = now();
|
|
226
|
+
return {
|
|
227
|
+
appId: selection.appId,
|
|
228
|
+
bindingRevision: digest(initial.row),
|
|
229
|
+
generatedAt,
|
|
230
|
+
order: {
|
|
231
|
+
financialStatus: data.order.displayFinancialStatus,
|
|
232
|
+
fulfillmentStatus: data.order.displayFulfillmentStatus,
|
|
233
|
+
id: data.order.id,
|
|
234
|
+
nativeId: selection.orderId,
|
|
235
|
+
updatedAt: data.order.updatedAt
|
|
236
|
+
},
|
|
237
|
+
provenance: 'verified_shopify_native_record_association',
|
|
238
|
+
providerRevision: digest(data),
|
|
239
|
+
schemaVersion: 'support_commerce_v1',
|
|
240
|
+
shop: {
|
|
241
|
+
domain: data.shop.myshopifyDomain,
|
|
242
|
+
id: data.shop.id
|
|
243
|
+
},
|
|
244
|
+
sourceId: selection.sourceId,
|
|
245
|
+
sourceRevision: digest(initial.source),
|
|
246
|
+
ticketId: selection.ticketId,
|
|
247
|
+
ticketRevision: selection.ticketRevision,
|
|
248
|
+
validUntil: Math.min(generatedAt + 300000, latest.grant.expires, latest.consent.expiresAt, latest.source.expiresAt)
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi90bXAvcmVhY3RvcmJveC1zdXBwb3J0LWNvbW1lcmNlLWZyZWV6ZS0yMDI2MTAwOC9pbnB1dC9hY3Rpb25zL3N1cHBvcnRDb21tZXJjZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlcnNjb3JlLWRhbmdsZSAtLSBFeGFjdCBuYXRpdmUgZG9jdW1lbnQgYW5kIGdyYXBoIHJldmlzaW9uIHByb29mcy4gKi9cbmltcG9ydCB7aHR0cFJlcXVlc3QsIHJlYWRCaW5hcnlSZXNwb25zZX0gZnJvbSAnQG5sYWJzL3JpcC1odW50ZXIvaHR0cCc7XG5pbXBvcnQge2FxbH0gZnJvbSAnYXJhbmdvanMnO1xuaW1wb3J0IHt6fSBmcm9tICd6b2QnO1xuXG5pbXBvcnQge3Njb3BlQ29udGV4dFRvQXBwfSBmcm9tICcuLi91dGlscy9hcHBDb250ZXh0LmpzJztcbmltcG9ydCB7dXNlRGJ9IGZyb20gJy4uL3V0aWxzL2FyYW5nb2RiVXRpbHMuanMnO1xuaW1wb3J0IHtjcm1DYW5vbmljYWxEaWdlc3QgYXMgZGlnZXN0fSBmcm9tICcuL2NybUNhbm9uaWNhbFBvbGljeS5qcyc7XG5pbXBvcnQge2F1dGhvcml6ZUNybUV4ZWN1dGlvbkdyYW50fSBmcm9tICcuL2NybUV4ZWN1dGlvbi5qcyc7XG5cbmltcG9ydCB0eXBlIHtSZXF1ZXN0SW1wbGVtZW50YXRpb259IGZyb20gJ0BubGFicy9yaXAtaHVudGVyL2h0dHAnO1xuaW1wb3J0IHR5cGUge0FwaUNvbnRleHR9IGZyb20gJy4uL3R5cGVzL2F1dGgudHlwZXMuanMnO1xuXG5jb25zdCBpZCA9IHouc3RyaW5nKCkucmVnZXgoL15bXFx3Li1dezEsMTYwfSQvKTtcbmNvbnN0IG9yZGVySWQgPSB6LnN0cmluZygpLnJlZ2V4KC9eZ2lkOlxcL1xcL3Nob3BpZnlcXC9PcmRlclxcL1xcZCskLyk7XG5jb25zdCBzaG9wSWQgPSB6LnN0cmluZygpLnJlZ2V4KC9eZ2lkOlxcL1xcL3Nob3BpZnlcXC9TaG9wXFwvXFxkKyQvKTtcbmNvbnN0IHNvdXJjZVNjaGVtYSA9IHoub2JqZWN0KHthcHBJZDogaWQsXG4gIGJpbmRpbmdzOiB6LmFycmF5KHoub2JqZWN0KHtuYXRpdmVPcmRlcklkOiBpZCwgc2hvcGlmeU9yZGVySWQ6IG9yZGVySWR9KS5zdHJpY3QoKSkubWluKDEpLm1heCgxMDApLFxuICBjdXN0b21lcnNBY2Nlc3NBcHByb3ZlZDogei5saXRlcmFsKHRydWUpLCBleHBpcmVzQXQ6IHoubnVtYmVyKCkuaW50KCkucG9zaXRpdmUoKSwgaWQsXG4gIG9yZGVyc0FjY2Vzc0FwcHJvdmVkOiB6LmxpdGVyYWwodHJ1ZSksIG93bmVySWQ6IGlkLCByZXZpc2lvbjogaWQsXG4gIHNob3A6IHouc3RyaW5nKCkucmVnZXgoL15bYS16MC05XVthLXowLTktXSpcXC5teXNob3BpZnlcXC5jb20kLyksIHNob3BJZCxcbiAgdG9rZW46IHouc3RyaW5nKCkubWluKDEpLm1heCg0MDk2KX0pLnN0cmljdCgpO1xuZXhwb3J0IHR5cGUgU3VwcG9ydENvbW1lcmNlU291cmNlID0gei5pbmZlcjx0eXBlb2Ygc291cmNlU2NoZW1hPjtcbmV4cG9ydCBpbnRlcmZhY2UgU3VwcG9ydENvbW1lcmNlSW5wdXQge1xuICBhcHBJZDogc3RyaW5nOyBvcmRlcklkOiBzdHJpbmc7IG9yZGVyUmV2aXNpb246IHN0cmluZzsgc291cmNlSWQ6IHN0cmluZzsgdGlja2V0SWQ6IHN0cmluZzsgdGlja2V0UmV2aXNpb246IHN0cmluZztcbn1cbmV4cG9ydCBpbnRlcmZhY2UgU3VwcG9ydENvbW1lcmNlT2JzZXJ2YXRpb24ge1xuICBhcHBJZDogc3RyaW5nO1xuICBiaW5kaW5nUmV2aXNpb246IHN0cmluZztcbiAgZ2VuZXJhdGVkQXQ6IG51bWJlcjtcbiAgb3JkZXI6IHtmaW5hbmNpYWxTdGF0dXM6IHN0cmluZzsgZnVsZmlsbG1lbnRTdGF0dXM6IHN0cmluZzsgaWQ6IHN0cmluZzsgbmF0aXZlSWQ6IHN0cmluZzsgdXBkYXRlZEF0OiBzdHJpbmd9O1xuICBwcm92aWRlclJldmlzaW9uOiBzdHJpbmc7XG4gIHByb3ZlbmFuY2U6ICd2ZXJpZmllZF9zaG9waWZ5X25hdGl2ZV9yZWNvcmRfYXNzb2NpYXRpb24nO1xuICBzY2hlbWFWZXJzaW9uOiAnc3VwcG9ydF9jb21tZXJjZV92MSc7XG4gIHNob3A6IHtkb21haW46IHN0cmluZzsgaWQ6IHN0cmluZ307XG4gIHNvdXJjZUlkOiBzdHJpbmc7XG4gIHNvdXJjZVJldmlzaW9uOiBzdHJpbmc7XG4gIHRpY2tldElkOiBzdHJpbmc7XG4gIHRpY2tldFJldmlzaW9uOiBzdHJpbmc7XG4gIHZhbGlkVW50aWw6IG51bWJlcjtcbn1cbi8qKiBFeHBsaWNpdCByZXZpZXdlZCBzb3VyY2Uvb3JkZXIgd2hpdGVsaXN0LiBPdGhlciBwdXJwb3NlcyBkbyBub3QgdHJhbnNmZXIgcHJvdGVjdGVkLWRhdGEgYXBwcm92YWxzLiAqL1xuZXhwb3J0IGNvbnN0IHN1cHBvcnRDb21tZXJjZVNvdXJjZXMgPSAocmF3ID0gcHJvY2Vzcy5lbnYuU1VQUE9SVF9DT01NRVJDRV9TT1VSQ0VTKTogU3VwcG9ydENvbW1lcmNlU291cmNlW10gPT4ge1xuICBpZighcmF3KSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG4gIHRyeSB7XG4gICAgY29uc3Qgc291cmNlcyA9IHouYXJyYXkoc291cmNlU2NoZW1hKS5tYXgoMTAwKS5wYXJzZShKU09OLnBhcnNlKHJhdykpO1xuICAgIGlmKG5ldyBTZXQoc291cmNlcy5tYXAoKHNvdXJjZSkgPT4gc291cmNlLmlkKSkuc2l6ZSAhPT0gc291cmNlcy5sZW5ndGhcbiAgICAgIHx8IHNvdXJjZXMuc29tZSgoc291cmNlKSA9PiBuZXcgU2V0KHNvdXJjZS5iaW5kaW5ncy5tYXAoKGJpbmRpbmcpID0+IGJpbmRpbmcubmF0aXZlT3JkZXJJZCkpLnNpemVcbiAgICAgICAgIT09IHNvdXJjZS5iaW5kaW5ncy5sZW5ndGgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2FtYmlndW91cycpO1xuICAgIH1cbiAgICByZXR1cm4gc291cmNlcztcbiAgfSBjYXRjaHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3N1cHBvcnRfY29tbWVyY2Vfc291cmNlX2NvbmZpZ3VyYXRpb25faG9sZCcpO1xuICB9XG59O1xuZXhwb3J0IGNvbnN0IFNVUFBPUlRfQ09NTUVSQ0VfUVVFUlkgPSBgcXVlcnkgU3VwcG9ydENvbW1lcmNlT3JkZXIoJGlkOiBJRCEpIHtcbiAgc2hvcCB7IGlkIG15c2hvcGlmeURvbWFpbiB9XG4gIGN1cnJlbnRBcHBJbnN0YWxsYXRpb24geyBhY2Nlc3NTY29wZXMgeyBoYW5kbGUgfSB9XG4gIG9yZGVyKGlkOiAkaWQpIHsgaWQgY3VzdG9tZXIgeyBpZCB9IHVwZGF0ZWRBdCBkaXNwbGF5RmluYW5jaWFsU3RhdHVzIGRpc3BsYXlGdWxmaWxsbWVudFN0YXR1cyB9XG59YDtcbmNvbnN0IHByb3ZpZGVyU2NoZW1hID0gei5vYmplY3Qoe2N1cnJlbnRBcHBJbnN0YWxsYXRpb246IHoub2JqZWN0KHthY2Nlc3NTY29wZXM6XG4gIHouYXJyYXkoei5vYmplY3Qoe2hhbmRsZTogei5zdHJpbmcoKX0pKS5tYXgoMTAwKX0pLCBvcmRlcjogei5vYmplY3Qoe2N1c3RvbWVyOlxuICB6Lm9iamVjdCh7aWQ6IHouc3RyaW5nKCkucmVnZXgoL15naWQ6XFwvXFwvc2hvcGlmeVxcL0N1c3RvbWVyXFwvXFxkKyQvKX0pLFxuZGlzcGxheUZpbmFuY2lhbFN0YXR1czogei5lbnVtKFsnQVVUSE9SSVpFRCcsICdFWFBJUkVEJywgJ1BBSUQnLCAnUEFSVElBTExZX1BBSUQnLCAnUEFSVElBTExZX1JFRlVOREVEJyxcbiAgJ1BFTkRJTkcnLCAnUkVGVU5ERUQnLCAnVk9JREVEJ10pLFxuZGlzcGxheUZ1bGZpbGxtZW50U3RhdHVzOiB6LmVudW0oWydGVUxGSUxMRUQnLCAnSU5fUFJPR1JFU1MnLCAnT05fSE9MRCcsICdPUEVOJywgJ1BBUlRJQUxMWV9GVUxGSUxMRUQnLFxuICAnUEVORElOR19GVUxGSUxMTUVOVCcsICdSRVFVRVNUX0RFQ0xJTkVEJywgJ1JFU1RPQ0tFRCcsICdTQ0hFRFVMRUQnLCAnVU5GVUxGSUxMRUQnXSksXG5pZDogb3JkZXJJZCwgdXBkYXRlZEF0OiB6LnN0cmluZygpLmRhdGV0aW1lKHtvZmZzZXQ6IHRydWV9KX0pLnN0cmljdCgpLFxuc2hvcDogei5vYmplY3Qoe2lkOiBzaG9wSWQsIG15c2hvcGlmeURvbWFpbjogei5zdHJpbmcoKX0pLnN0cmljdCgpfSkuc3RyaWN0KCk7XG5jb25zdCBleHRlcm5hbCA9ICh2YWx1ZTogdW5rbm93biwgdHlwZTogJ0N1c3RvbWVyJyB8ICdPcmRlcicpOiBzdHJpbmcgfCB1bmRlZmluZWQgPT4ge1xuICBpZih0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICBpZigvXlxcZCskLy50ZXN0KHZhbHVlKSkge1xuICAgIHJldHVybiBgZ2lkOi8vc2hvcGlmeS8ke3R5cGV9LyR7dmFsdWV9YDtcbiAgfVxuICByZXR1cm4gbmV3IFJlZ0V4cChgXmdpZDovL3Nob3BpZnkvJHt0eXBlfS9cXFxcZCskYCkudGVzdCh2YWx1ZSkgPyB2YWx1ZSA6IHVuZGVmaW5lZDtcbn07XG4vKiogUmVhZC1vbmx5IG5hdGl2ZSBhc3NvY2lhdGlvbi4gTm8gZW1haWwgbWF0Y2hpbmcsIGFzc29jaWF0aW9uIG11dGF0aW9uIG9yIGluZmVycmVkIHNldHRsZW1lbnQuICovXG5leHBvcnQgY29uc3QgcmVhZFN1cHBvcnRDb21tZXJjZSA9IGFzeW5jIChjb250ZXh0OiBBcGlDb250ZXh0LCBpbnB1dDogU3VwcG9ydENvbW1lcmNlSW5wdXQsIG9wdGlvbnM6IHtcbiAgbm93PzogKCkgPT4gbnVtYmVyOyByZXF1ZXN0SW1wbGVtZW50YXRpb24/OiBSZXF1ZXN0SW1wbGVtZW50YXRpb247IHNvdXJjZXM/OiAoKSA9PiByZWFkb25seSBTdXBwb3J0Q29tbWVyY2VTb3VyY2VbXTtcbn0gPSB7fSk6IFByb21pc2U8U3VwcG9ydENvbW1lcmNlT2JzZXJ2YXRpb24+ID0+IHtcbiAgaWYoIXoub2JqZWN0KHthcHBJZDogaWQsIG9yZGVySWQ6IGlkLCBvcmRlclJldmlzaW9uOiBpZCwgc291cmNlSWQ6IGlkLCB0aWNrZXRJZDogaWQsXG4gICAgdGlja2V0UmV2aXNpb246IGlkfSkuc3RyaWN0KCkuc2FmZVBhcnNlKGlucHV0KS5zdWNjZXNzKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkX3N1cHBvcnRfY29tbWVyY2VfaW5wdXQnKTtcbiAgfVxuICBjb25zdCBzZWxlY3Rpb24gPSBzdHJ1Y3R1cmVkQ2xvbmUoaW5wdXQpO1xuICBjb25zdCBub3cgPSBvcHRpb25zLm5vdyB8fCBEYXRlLm5vdztcbiAgY29uc3Qgc291cmNlcyA9IG9wdGlvbnMuc291cmNlcyB8fCBzdXBwb3J0Q29tbWVyY2VTb3VyY2VzO1xuICBjb25zdCBhdXRob3JpdHkgPSBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZ3JhbnQgPSBhd2FpdCBhdXRob3JpemVDcm1FeGVjdXRpb25HcmFudChjb250ZXh0LCBzZWxlY3Rpb24uYXBwSWQsICdzdXBwb3J0OmNvbW1lcmNlJywgbm93KCkpO1xuICAgIGF3YWl0IGF1dGhvcml6ZUNybUV4ZWN1dGlvbkdyYW50KGNvbnRleHQsIHNlbGVjdGlvbi5hcHBJZCwgJ3N1cHBvcnQ6cmVhZCcsIG5vdygpKTtcbiAgICBjb25zdCBzY29wZWQgPSBhd2FpdCBzY29wZUNvbnRleHRUb0FwcChjb250ZXh0LCBzZWxlY3Rpb24uYXBwSWQpO1xuICAgIGNvbnN0IG1hdGNoZXMgPSBzb3VyY2VzKCkuZmlsdGVyKChzb3VyY2UpID0+IHNvdXJjZS5pZCA9PT0gc2VsZWN0aW9uLnNvdXJjZUlkKTtcbiAgICBjb25zdCBzb3VyY2UgPSBtYXRjaGVzWzBdO1xuICAgIGNvbnN0IGJpbmRpbmcgPSBzb3VyY2U/LmJpbmRpbmdzLmZpbmQoKHZhbHVlKSA9PiB2YWx1ZS5uYXRpdmVPcmRlcklkID09PSBzZWxlY3Rpb24ub3JkZXJJZCk7XG4gICAgaWYobWF0Y2hlcy5sZW5ndGggIT09IDEgfHwgIXNvdXJjZVNjaGVtYS5zYWZlUGFyc2Uoc291cmNlKS5zdWNjZXNzIHx8IHNvdXJjZS5hcHBJZCAhPT0gc2VsZWN0aW9uLmFwcElkXG4gICAgICB8fCBzb3VyY2Uub3duZXJJZCAhPT0gZ3JhbnQub3duZXJJZCB8fCBzb3VyY2UuZXhwaXJlc0F0IDw9IG5vdygpIHx8ICFiaW5kaW5nXG4gICAgICB8fCBzb3VyY2UuYmluZGluZ3MuZmlsdGVyKCh2YWx1ZSkgPT4gdmFsdWUubmF0aXZlT3JkZXJJZCA9PT0gc2VsZWN0aW9uLm9yZGVySWQpLmxlbmd0aCAhPT0gMVxuICAgICAgfHwgc2NvcGVkLmRhdGFiYXNlTmFtZSAhPT0gZ3JhbnQuZGF0YWJhc2VOYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3N1cHBvcnRfY29tbWVyY2VfYXV0aG9yaXR5X2hvbGQnKTtcbiAgICB9XG4gICAgY29uc3QgZGIgPSB1c2VEYihncmFudC5kYXRhYmFzZU5hbWUpO1xuICAgIGNvbnN0IHJvdyA9IGF3YWl0IGRiLnF1ZXJ5KGFxbGBMRVQgdGlja2V0ID0gRE9DVU1FTlQoJ3N1cHBvcnRUaWNrZXRzJywgJHtzZWxlY3Rpb24udGlja2V0SWR9KVxuICAgICAgTEVUIHVzZXIgPSB0aWNrZXQgPyBET0NVTUVOVCgndXNlcnMnLCB0aWNrZXQudXNlcklkKSA6IG51bGxcbiAgICAgIExFVCBvcmRlciA9IERPQ1VNRU5UKCdjdXN0b21lck9yZGVycycsICR7c2VsZWN0aW9uLm9yZGVySWR9KVxuICAgICAgTEVUIGN1cnJlbnRDb25zZW50ID0gKEZPUiByZWNvcmQgSU4gc3VwcG9ydFB1cnBvc2VDb25zZW50c1xuICAgICAgICBGSUxURVIgcmVjb3JkLmFwcElkID09ICR7c2VsZWN0aW9uLmFwcElkfSBBTkQgcmVjb3JkLnVzZXJJZCA9PSB1c2VyLl9rZXlcbiAgICAgICAgICBBTkQgcmVjb3JkLnB1cnBvc2UgPT0gJ3N1cHBvcnRfY29tbWVyY2UnIExJTUlUIDIgUkVUVVJOIHJlY29yZClcbiAgICAgIExFVCB0aWNrZXRFZGdlcyA9IChGT1IgZWRnZSBJTiBoYXNTdXBwb3J0VGlja2V0IEZJTFRFUiBlZGdlLl90byA9PSBDT05DQVQoJ3N1cHBvcnRUaWNrZXRzLycsICR7c2VsZWN0aW9uLnRpY2tldElkfSlcbiAgICAgICAgTElNSVQgMiBSRVRVUk4ge2Zyb206IGVkZ2UuX2Zyb20sIHJldmlzaW9uOiBlZGdlLl9yZXZ9KVxuICAgICAgTEVUIG9yZGVyRWRnZXMgPSAoRk9SIGVkZ2UgSU4gaGFzQ3VzdG9tZXJPcmRlciBGSUxURVIgZWRnZS5fdG8gPT0gQ09OQ0FUKCdjdXN0b21lck9yZGVycy8nLCAke3NlbGVjdGlvbi5vcmRlcklkfSlcbiAgICAgICAgTElNSVQgMiBSRVRVUk4ge2Zyb206IGVkZ2UuX2Zyb20sIHJldmlzaW9uOiBlZGdlLl9yZXZ9KVxuICAgICAgUkVUVVJOIHt0aWNrZXQ6IHRpY2tldCA/IHtfa2V5OiB0aWNrZXQuX2tleSwgX3JldjogdGlja2V0Ll9yZXYsIGFwcElkOiB0aWNrZXQuYXBwSWQsIGRlbGV0ZWQ6IHRpY2tldC5kZWxldGVkLFxuICAgICAgICBzaG9waWZ5T3JkZXJJZDogdGlja2V0LnNob3BpZnlPcmRlcklkLCBzdGF0dXM6IHRpY2tldC5zdGF0dXMsIHVzZXJJZDogdGlja2V0LnVzZXJJZH0gOiBudWxsLFxuICAgICAgICB1c2VyOiB1c2VyID8ge19rZXk6IHVzZXIuX2tleSwgX3JldjogdXNlci5fcmV2LCBhY3RpdmU6IHVzZXIuYWN0aXZlLCBhcHBJZDogdXNlci5hcHBJZCxcbiAgICAgICAgICBjcm1BbmFseXRpY3NTdXBwcmVzc2VkOiB1c2VyLmNybUFuYWx5dGljc1N1cHByZXNzZWQsIGRlbGV0ZWQ6IHVzZXIuZGVsZXRlZCxcbiAgICAgICAgICBzaG9waWZ5Q3VzdG9tZXJJZDogdXNlci5zaG9waWZ5Q3VzdG9tZXJJZH0gOiBudWxsLFxuICAgICAgICBvcmRlcjogb3JkZXIgPyB7X2tleTogb3JkZXIuX2tleSwgX3Jldjogb3JkZXIuX3JldiwgYXBwSWQ6IG9yZGVyLmFwcElkLCBkZWxldGVkOiBvcmRlci5kZWxldGVkLFxuICAgICAgICAgIHNob3BpZnlDdXN0b21lcklkOiBvcmRlci5zaG9waWZ5Q3VzdG9tZXJJZCwgc2hvcGlmeU9yZGVySWQ6IG9yZGVyLnNob3BpZnlPcmRlcklkLCB1c2VySWQ6IG9yZGVyLnVzZXJJZH0gOiBudWxsLFxuICAgICAgICBjb25zZW50czogY3VycmVudENvbnNlbnQsIG9yZGVyRWRnZXMsIHRpY2tldEVkZ2VzfWApLnRoZW4oKGN1cnNvcikgPT4gY3Vyc29yLm5leHQoKSkgYXMgYW55O1xuICAgIGNvbnN0IHt0aWNrZXQsIHVzZXIsIG9yZGVyLCBjb25zZW50cywgb3JkZXJFZGdlcywgdGlja2V0RWRnZXN9ID0gcm93IHx8IHt9O1xuICAgIGNvbnN0IGFjdGl2ZSA9IChyZWNvcmQ6IGFueSk6IGJvb2xlYW4gPT4gQm9vbGVhbihyZWNvcmQgJiYgaWQuc2FmZVBhcnNlKHJlY29yZC5fa2V5KS5zdWNjZXNzXG4gICAgICAmJiBpZC5zYWZlUGFyc2UocmVjb3JkLl9yZXYpLnN1Y2Nlc3MgJiYgcmVjb3JkLmFwcElkID09PSBzZWxlY3Rpb24uYXBwSWQgJiYgcmVjb3JkLmRlbGV0ZWQgIT09IHRydWUpO1xuICAgIGNvbnN0IGNvbnNlbnQgPSBBcnJheS5pc0FycmF5KGNvbnNlbnRzKSAmJiBjb25zZW50cy5sZW5ndGggPT09IDEgPyBjb25zZW50c1swXSA6IHVuZGVmaW5lZDtcbiAgICBpZighYWN0aXZlKHRpY2tldCkgfHwgIWFjdGl2ZSh1c2VyKSB8fCAhYWN0aXZlKG9yZGVyKSB8fCB0aWNrZXQuX2tleSAhPT0gc2VsZWN0aW9uLnRpY2tldElkXG4gICAgICB8fCB0aWNrZXQuX3JldiAhPT0gc2VsZWN0aW9uLnRpY2tldFJldmlzaW9uIHx8IG9yZGVyLl9rZXkgIT09IHNlbGVjdGlvbi5vcmRlcklkXG4gICAgICB8fCBvcmRlci5fcmV2ICE9PSBzZWxlY3Rpb24ub3JkZXJSZXZpc2lvbiB8fCB1c2VyLmFjdGl2ZSA9PT0gZmFsc2UgfHwgdXNlci5jcm1BbmFseXRpY3NTdXBwcmVzc2VkID09PSB0cnVlXG4gICAgICB8fCB0aWNrZXQudXNlcklkICE9PSB1c2VyLl9rZXkgfHwgb3JkZXIudXNlcklkICE9PSB1c2VyLl9rZXlcbiAgICAgIHx8ICFbJ3N1Ym1pdHRlZCcsICdvcGVuJywgJ2luX3Byb2dyZXNzJywgJ3dhaXRpbmdfb25fY3VzdG9tZXInLCAnd2FpdGluZ19vbl9pbnRlcm5hbCddLmluY2x1ZGVzKHRpY2tldC5zdGF0dXMpXG4gICAgICB8fCBleHRlcm5hbCh0aWNrZXQuc2hvcGlmeU9yZGVySWQsICdPcmRlcicpICE9PSBiaW5kaW5nLnNob3BpZnlPcmRlcklkXG4gICAgICB8fCBleHRlcm5hbChvcmRlci5zaG9waWZ5T3JkZXJJZCwgJ09yZGVyJykgIT09IGJpbmRpbmcuc2hvcGlmeU9yZGVySWRcbiAgICAgIHx8ICFleHRlcm5hbCh1c2VyLnNob3BpZnlDdXN0b21lcklkLCAnQ3VzdG9tZXInKVxuICAgICAgfHwgZXh0ZXJuYWwob3JkZXIuc2hvcGlmeUN1c3RvbWVySWQsICdDdXN0b21lcicpICE9PSBleHRlcm5hbCh1c2VyLnNob3BpZnlDdXN0b21lcklkLCAnQ3VzdG9tZXInKVxuICAgICAgfHwgIWNvbnNlbnQgfHwgY29uc2VudC5hcHBJZCAhPT0gc2VsZWN0aW9uLmFwcElkIHx8IGNvbnNlbnQudXNlcklkICE9PSB1c2VyLl9rZXlcbiAgICAgIHx8IGNvbnNlbnQucHVycG9zZSAhPT0gJ3N1cHBvcnRfY29tbWVyY2UnIHx8IGNvbnNlbnQuX2tleSAhPT0gZGlnZXN0KFtzZWxlY3Rpb24uYXBwSWQsIHVzZXIuX2tleSwgJ3N1cHBvcnRfY29tbWVyY2UnXSlcbiAgICAgIHx8ICFpZC5zYWZlUGFyc2UoY29uc2VudC5fcmV2KS5zdWNjZXNzIHx8IGNvbnNlbnQuc291cmNlICE9PSAnYXV0aGVudGljYXRlZF9jdXN0b21lcidcbiAgICAgIHx8IGNvbnNlbnQuc3RhdHVzICE9PSAnYWN0aXZlJyB8fCAhTnVtYmVyLmlzU2FmZUludGVnZXIoY29uc2VudC5hdCkgfHwgY29uc2VudC5hdCA+IG5vdygpXG4gICAgICB8fCAhTnVtYmVyLmlzU2FmZUludGVnZXIoY29uc2VudC5leHBpcmVzQXQpIHx8IGNvbnNlbnQuZXhwaXJlc0F0IDw9IG5vdygpXG4gICAgICB8fCAhW29yZGVyRWRnZXMsIHRpY2tldEVkZ2VzXS5ldmVyeSgoZWRnZXMpID0+IEFycmF5LmlzQXJyYXkoZWRnZXMpICYmIGVkZ2VzLmxlbmd0aCA9PT0gMVxuICAgICAgICAmJiBlZGdlc1swXS5mcm9tID09PSBgdXNlcnMvJHt1c2VyLl9rZXl9YCAmJiBpZC5zYWZlUGFyc2UoZWRnZXNbMF0ucmV2aXNpb24pLnN1Y2Nlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3N1cHBvcnRfY29tbWVyY2VfbmF0aXZlX2lkZW50aXR5X29yX2NvbnNlbnRfaG9sZCcpO1xuICAgIH1cbiAgICByZXR1cm4ge2JpbmRpbmcsIGNvbnNlbnQsIGdyYW50LCBpZGVudGl0eTogZGlnZXN0KFtncmFudC5pZCwgZ3JhbnQuaGFzaCwgZ3JhbnQuZGF0YWJhc2VOYW1lLCBzb3VyY2UsIHJvd10pLFxuICAgICAgcm93LCBzb3VyY2V9O1xuICB9O1xuICBjb25zdCBpbml0aWFsID0gYXdhaXQgYXV0aG9yaXR5KCk7XG4gIGNvbnN0IGRlYWRsaW5lID0gbm93KCkgKyAxNTAwMDtcbiAgY29uc3QgY3VycmVudCA9IGF3YWl0IGF1dGhvcml0eSgpO1xuICBpZihjdXJyZW50LmlkZW50aXR5ICE9PSBpbml0aWFsLmlkZW50aXR5IHx8IG5vdygpID49IGRlYWRsaW5lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdzdXBwb3J0X2NvbW1lcmNlX3NvdXJjZV9jaGFuZ2VkJyk7XG4gIH1cbiAgbGV0IGRhdGE6IHouaW5mZXI8dHlwZW9mIHByb3ZpZGVyU2NoZW1hPjtcbiAgdHJ5IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGh0dHBSZXF1ZXN0KGBodHRwczovLyR7aW5pdGlhbC5zb3VyY2Uuc2hvcH0vYWRtaW4vYXBpLzIwMjYtMTAvZ3JhcGhxbC5qc29uYCwge1xuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe3F1ZXJ5OiBTVVBQT1JUX0NPTU1FUkNFX1FVRVJZLCB2YXJpYWJsZXM6IHtpZDogaW5pdGlhbC5iaW5kaW5nLnNob3BpZnlPcmRlcklkfX0pLFxuICAgICAgaGVhZGVyczogeydDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsICdYLVNob3BpZnktQWNjZXNzLVRva2VuJzogaW5pdGlhbC5zb3VyY2UudG9rZW59LCBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIHJlZGlyZWN0OiAnZXJyb3InLCByZXF1ZXN0SW1wbGVtZW50YXRpb246IG9wdGlvbnMucmVxdWVzdEltcGxlbWVudGF0aW9uLFxuICAgICAgdGltZW91dDogTWF0aC5tYXgoMSwgZGVhZGxpbmUgLSBub3coKSlcbiAgICB9LCBhc3luYyAocmVzcG9uc2UpID0+IHtcbiAgICAgIGlmKHJlc3BvbnNlLnN0YXR1cyAhPT0gMjAwIHx8IHJlc3BvbnNlLnJlZGlyZWN0ZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdwcm92aWRlcicpO1xuICAgICAgfVxuICAgICAgY29uc3QgYnl0ZXMgPSBhd2FpdCByZWFkQmluYXJ5UmVzcG9uc2UocmVzcG9uc2UsIDEwNDg1NzYpO1xuICAgICAgY29uc3QgZW52ZWxvcGUgPSB6Lm9iamVjdCh7ZGF0YTogcHJvdmlkZXJTY2hlbWEsIGVycm9yczogei5hcnJheSh6LnVua25vd24oKSkubWF4KDEwMCkub3B0aW9uYWwoKX0pXG4gICAgICAgIC5zdHJpY3QoKS5wYXJzZShKU09OLnBhcnNlKG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShieXRlcykpKTtcbiAgICAgIGlmKGVudmVsb3BlLmVycm9ycz8ubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigncHJvdmlkZXInKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBlbnZlbG9wZS5kYXRhO1xuICAgIH0pO1xuICAgIGRhdGEgPSByZXNwb25zZTtcbiAgfSBjYXRjaHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3N1cHBvcnRfY29tbWVyY2VfcHJvdmlkZXJfcmVhZF9ob2xkJyk7XG4gIH1cbiAgaWYoZGF0YS5zaG9wLmlkICE9PSBpbml0aWFsLnNvdXJjZS5zaG9wSWQgfHwgZGF0YS5zaG9wLm15c2hvcGlmeURvbWFpbiAhPT0gaW5pdGlhbC5zb3VyY2Uuc2hvcFxuICAgIHx8ICFbJ3JlYWRfb3JkZXJzJywgJ3JlYWRfY3VzdG9tZXJzJ10uZXZlcnkoKHNjb3BlKSA9PlxuICAgICAgZGF0YS5jdXJyZW50QXBwSW5zdGFsbGF0aW9uLmFjY2Vzc1Njb3Blcy5zb21lKChlbnRyeSkgPT4gZW50cnkuaGFuZGxlID09PSBzY29wZSkpXG4gICAgfHwgZGF0YS5vcmRlci5pZCAhPT0gaW5pdGlhbC5iaW5kaW5nLnNob3BpZnlPcmRlcklkXG4gICAgfHwgZGF0YS5vcmRlci5jdXN0b21lci5pZCAhPT0gZXh0ZXJuYWwoaW5pdGlhbC5yb3cudXNlci5zaG9waWZ5Q3VzdG9tZXJJZCwgJ0N1c3RvbWVyJylcbiAgICB8fCBEYXRlLnBhcnNlKGRhdGEub3JkZXIudXBkYXRlZEF0KSA+IG5vdygpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdzdXBwb3J0X2NvbW1lcmNlX3Byb3ZpZGVyX2lkZW50aXR5X2hvbGQnKTtcbiAgfVxuICBjb25zdCBsYXRlc3QgPSBhd2FpdCBhdXRob3JpdHkoKTtcbiAgaWYobGF0ZXN0LmlkZW50aXR5ICE9PSBpbml0aWFsLmlkZW50aXR5IHx8IG5vdygpID49IGRlYWRsaW5lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdzdXBwb3J0X2NvbW1lcmNlX3NvdXJjZV9jaGFuZ2VkJyk7XG4gIH1cbiAgY29uc3QgZ2VuZXJhdGVkQXQgPSBub3coKTtcbiAgcmV0dXJuIHthcHBJZDogc2VsZWN0aW9uLmFwcElkLCBiaW5kaW5nUmV2aXNpb246IGRpZ2VzdChpbml0aWFsLnJvdyksIGdlbmVyYXRlZEF0LFxuICAgIG9yZGVyOiB7ZmluYW5jaWFsU3RhdHVzOiBkYXRhLm9yZGVyLmRpc3BsYXlGaW5hbmNpYWxTdGF0dXMsIGZ1bGZpbGxtZW50U3RhdHVzOiBkYXRhLm9yZGVyLmRpc3BsYXlGdWxmaWxsbWVudFN0YXR1cyxcbiAgICAgIGlkOiBkYXRhLm9yZGVyLmlkLCBuYXRpdmVJZDogc2VsZWN0aW9uLm9yZGVySWQsIHVwZGF0ZWRBdDogZGF0YS5vcmRlci51cGRhdGVkQXR9LFxuICAgIHByb3ZlbmFuY2U6ICd2ZXJpZmllZF9zaG9waWZ5X25hdGl2ZV9yZWNvcmRfYXNzb2NpYXRpb24nLCBwcm92aWRlclJldmlzaW9uOiBkaWdlc3QoZGF0YSksXG4gICAgc2NoZW1hVmVyc2lvbjogJ3N1cHBvcnRfY29tbWVyY2VfdjEnLCBzaG9wOiB7ZG9tYWluOiBkYXRhLnNob3AubXlzaG9waWZ5RG9tYWluLCBpZDogZGF0YS5zaG9wLmlkfSxcbiAgICBzb3VyY2VJZDogc2VsZWN0aW9uLnNvdXJjZUlkLCBzb3VyY2VSZXZpc2lvbjogZGlnZXN0KGluaXRpYWwuc291cmNlKSwgdGlja2V0SWQ6IHNlbGVjdGlvbi50aWNrZXRJZCxcbiAgICB0aWNrZXRSZXZpc2lvbjogc2VsZWN0aW9uLnRpY2tldFJldmlzaW9uLFxuICAgIHZhbGlkVW50aWw6IE1hdGgubWluKGdlbmVyYXRlZEF0ICsgMzAwMDAwLCBsYXRlc3QuZ3JhbnQuZXhwaXJlcywgbGF0ZXN0LmNvbnNlbnQuZXhwaXJlc0F0LFxuICAgICAgbGF0ZXN0LnNvdXJjZS5leHBpcmVzQXQpfTtcbn07XG4iXSwibmFtZXMiOlsiaHR0cFJlcXVlc3QiLCJyZWFkQmluYXJ5UmVzcG9uc2UiLCJhcWwiLCJ6Iiwic2NvcGVDb250ZXh0VG9BcHAiLCJ1c2VEYiIsImNybUNhbm9uaWNhbERpZ2VzdCIsImRpZ2VzdCIsImF1dGhvcml6ZUNybUV4ZWN1dGlvbkdyYW50IiwiaWQiLCJzdHJpbmciLCJyZWdleCIsIm9yZGVySWQiLCJzaG9wSWQiLCJzb3VyY2VTY2hlbWEiLCJvYmplY3QiLCJhcHBJZCIsImJpbmRpbmdzIiwiYXJyYXkiLCJuYXRpdmVPcmRlcklkIiwic2hvcGlmeU9yZGVySWQiLCJzdHJpY3QiLCJtaW4iLCJtYXgiLCJjdXN0b21lcnNBY2Nlc3NBcHByb3ZlZCIsImxpdGVyYWwiLCJleHBpcmVzQXQiLCJudW1iZXIiLCJpbnQiLCJwb3NpdGl2ZSIsIm9yZGVyc0FjY2Vzc0FwcHJvdmVkIiwib3duZXJJZCIsInJldmlzaW9uIiwic2hvcCIsInRva2VuIiwic3VwcG9ydENvbW1lcmNlU291cmNlcyIsInJhdyIsInByb2Nlc3MiLCJlbnYiLCJTVVBQT1JUX0NPTU1FUkNFX1NPVVJDRVMiLCJzb3VyY2VzIiwicGFyc2UiLCJKU09OIiwiU2V0IiwibWFwIiwic291cmNlIiwic2l6ZSIsImxlbmd0aCIsInNvbWUiLCJiaW5kaW5nIiwiRXJyb3IiLCJTVVBQT1JUX0NPTU1FUkNFX1FVRVJZIiwicHJvdmlkZXJTY2hlbWEiLCJjdXJyZW50QXBwSW5zdGFsbGF0aW9uIiwiYWNjZXNzU2NvcGVzIiwiaGFuZGxlIiwib3JkZXIiLCJjdXN0b21lciIsImRpc3BsYXlGaW5hbmNpYWxTdGF0dXMiLCJlbnVtIiwiZGlzcGxheUZ1bGZpbGxtZW50U3RhdHVzIiwidXBkYXRlZEF0IiwiZGF0ZXRpbWUiLCJvZmZzZXQiLCJteXNob3BpZnlEb21haW4iLCJleHRlcm5hbCIsInZhbHVlIiwidHlwZSIsInVuZGVmaW5lZCIsInRlc3QiLCJSZWdFeHAiLCJyZWFkU3VwcG9ydENvbW1lcmNlIiwiY29udGV4dCIsImlucHV0Iiwib3B0aW9ucyIsIm9yZGVyUmV2aXNpb24iLCJzb3VyY2VJZCIsInRpY2tldElkIiwidGlja2V0UmV2aXNpb24iLCJzYWZlUGFyc2UiLCJzdWNjZXNzIiwic2VsZWN0aW9uIiwic3RydWN0dXJlZENsb25lIiwibm93IiwiRGF0ZSIsImF1dGhvcml0eSIsImdyYW50Iiwic2NvcGVkIiwibWF0Y2hlcyIsImZpbHRlciIsImZpbmQiLCJkYXRhYmFzZU5hbWUiLCJkYiIsInJvdyIsInF1ZXJ5IiwidGhlbiIsImN1cnNvciIsIm5leHQiLCJ0aWNrZXQiLCJ1c2VyIiwiY29uc2VudHMiLCJvcmRlckVkZ2VzIiwidGlja2V0RWRnZXMiLCJhY3RpdmUiLCJyZWNvcmQiLCJCb29sZWFuIiwiX2tleSIsIl9yZXYiLCJkZWxldGVkIiwiY29uc2VudCIsIkFycmF5IiwiaXNBcnJheSIsImNybUFuYWx5dGljc1N1cHByZXNzZWQiLCJ1c2VySWQiLCJpbmNsdWRlcyIsInN0YXR1cyIsInNob3BpZnlDdXN0b21lcklkIiwicHVycG9zZSIsIk51bWJlciIsImlzU2FmZUludGVnZXIiLCJhdCIsImV2ZXJ5IiwiZWRnZXMiLCJmcm9tIiwiaWRlbnRpdHkiLCJoYXNoIiwiaW5pdGlhbCIsImRlYWRsaW5lIiwiY3VycmVudCIsImRhdGEiLCJyZXNwb25zZSIsImJvZHkiLCJzdHJpbmdpZnkiLCJ2YXJpYWJsZXMiLCJoZWFkZXJzIiwibWV0aG9kIiwicmVkaXJlY3QiLCJyZXF1ZXN0SW1wbGVtZW50YXRpb24iLCJ0aW1lb3V0IiwiTWF0aCIsInJlZGlyZWN0ZWQiLCJieXRlcyIsImVudmVsb3BlIiwiZXJyb3JzIiwidW5rbm93biIsIm9wdGlvbmFsIiwiVGV4dERlY29kZXIiLCJkZWNvZGUiLCJzY29wZSIsImVudHJ5IiwibGF0ZXN0IiwiZ2VuZXJhdGVkQXQiLCJiaW5kaW5nUmV2aXNpb24iLCJmaW5hbmNpYWxTdGF0dXMiLCJmdWxmaWxsbWVudFN0YXR1cyIsIm5hdGl2ZUlkIiwicHJvdmVuYW5jZSIsInByb3ZpZGVyUmV2aXNpb24iLCJzY2hlbWFWZXJzaW9uIiwiZG9tYWluIiwic291cmNlUmV2aXNpb24iLCJ2YWxpZFVudGlsIiwiZXhwaXJlcyJdLCJtYXBwaW5ncyI6IkFBQUEsMkZBQTJGLEdBQzNGLFNBQVFBLFdBQVcsRUFBRUMsa0JBQWtCLFFBQU8seUJBQXlCO0FBQ3ZFLFNBQVFDLEdBQUcsUUFBTyxXQUFXO0FBQzdCLFNBQVFDLENBQUMsUUFB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
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ConnectClient } from '@aws-sdk/client-connect';
|
|
2
|
+
import type { ApiContext } from '../types/auth.types.js';
|
|
3
|
+
export interface SupportConnectIngressInput {
|
|
4
|
+
appId: string;
|
|
5
|
+
bindingId: string;
|
|
6
|
+
contactId: string;
|
|
7
|
+
kind: 'contact_observed' | 'contact_ended';
|
|
8
|
+
sourceId: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SupportConnectReadInput {
|
|
11
|
+
appId: string;
|
|
12
|
+
sourceId: string;
|
|
13
|
+
ticketId: string;
|
|
14
|
+
ticketRevision: string;
|
|
15
|
+
}
|
|
16
|
+
export interface SupportConnectEvidence {
|
|
17
|
+
appId: string;
|
|
18
|
+
channel: 'voice';
|
|
19
|
+
generatedAt: number;
|
|
20
|
+
milestones: {
|
|
21
|
+
kind: SupportConnectIngressInput['kind'];
|
|
22
|
+
occurredAt: number;
|
|
23
|
+
}[];
|
|
24
|
+
provenance: 'aws_connect_contact_metadata';
|
|
25
|
+
schemaVersion: 'support_connect_metadata_v1';
|
|
26
|
+
sourceId: string;
|
|
27
|
+
ticketId: string;
|
|
28
|
+
ticketRevision: string;
|
|
29
|
+
validUntil: number;
|
|
30
|
+
}
|
|
31
|
+
/** Host-only ingress. trustedIamPrincipal MUST originate from an AWS_IAM gateway route,
|
|
32
|
+
* never a body/header/GraphQL argument. */
|
|
33
|
+
export declare const ingestSupportConnectMetadata: (context: ApiContext, input: SupportConnectIngressInput, trustedIamPrincipal: string, now?: () => number, client?: Pick<ConnectClient, 'send'>) => Promise<{
|
|
34
|
+
duplicate: boolean;
|
|
35
|
+
kind: SupportConnectIngressInput['kind'];
|
|
36
|
+
occurredAt: number;
|
|
37
|
+
}>;
|
|
38
|
+
/** Ordinary current read authority; provider contact IDs, principals, identities and raw responses are excluded. */
|
|
39
|
+
export declare const readSupportConnectEvidence: (context: ApiContext, input: SupportConnectReadInput, now?: () => number) => Promise<SupportConnectEvidence>;
|