@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.
Files changed (396) hide show
  1. package/README.md +290 -0
  2. package/docs/GENERATION.md +42 -16
  3. package/lib/actions/alfredFaq.js +1 -1
  4. package/lib/actions/analytics.js +1 -1
  5. package/lib/actions/apps.js +17 -2
  6. package/lib/actions/connections.js +1 -1
  7. package/lib/actions/content.js +1 -1
  8. package/lib/actions/contentGeneration.d.ts +22 -1
  9. package/lib/actions/contentGeneration.js +120 -32
  10. package/lib/actions/contentGenerationErrors.js +1 -1
  11. package/lib/actions/contentGenerationSources.d.ts +29 -0
  12. package/lib/actions/contentGenerationSources.js +103 -0
  13. package/lib/actions/conversations.js +1 -1
  14. package/lib/actions/crm.d.ts +6 -2
  15. package/lib/actions/crm.js +91 -12
  16. package/lib/actions/crmCanonicalOutcomes.d.ts +88 -0
  17. package/lib/actions/crmCanonicalOutcomes.js +398 -0
  18. package/lib/actions/crmCanonicalPolicy.d.ts +92 -0
  19. package/lib/actions/crmCanonicalPolicy.js +104 -0
  20. package/lib/actions/crmCheckoutRecovery.d.ts +72 -0
  21. package/lib/actions/crmCheckoutRecovery.js +413 -0
  22. package/lib/actions/crmCheckoutRecoveryPolicy.d.ts +38 -0
  23. package/lib/actions/crmCheckoutRecoveryPolicy.js +61 -0
  24. package/lib/actions/crmDeliveryEvents.d.ts +24 -0
  25. package/lib/actions/crmDeliveryEvents.js +207 -0
  26. package/lib/actions/crmDeliveryEvidence.d.ts +17 -0
  27. package/lib/actions/crmDeliveryEvidence.js +58 -0
  28. package/lib/actions/crmExecution.d.ts +125 -0
  29. package/lib/actions/crmExecution.js +830 -0
  30. package/lib/actions/crmFinancialEvidence.d.ts +12 -0
  31. package/lib/actions/crmFinancialEvidence.js +60 -0
  32. package/lib/actions/crmInsights.d.ts +60 -0
  33. package/lib/actions/crmInsights.js +225 -0
  34. package/lib/actions/crmLeadFollowups.d.ts +66 -0
  35. package/lib/actions/crmLeadFollowups.js +209 -0
  36. package/lib/actions/crmOutcomes.d.ts +106 -0
  37. package/lib/actions/crmOutcomes.js +289 -0
  38. package/lib/actions/crmRecoveryRetention.d.ts +13 -0
  39. package/lib/actions/crmRecoveryRetention.js +163 -0
  40. package/lib/actions/crmReminderDispatch.d.ts +10 -0
  41. package/lib/actions/crmReminderDispatch.js +65 -0
  42. package/lib/actions/crmSourceOwnership.d.ts +7 -0
  43. package/lib/actions/crmSourceOwnership.js +27 -0
  44. package/lib/actions/crmSupportInsights.d.ts +18 -0
  45. package/lib/actions/crmSupportInsights.js +47 -0
  46. package/lib/actions/crmWinback.d.ts +71 -0
  47. package/lib/actions/crmWinback.js +347 -0
  48. package/lib/actions/crmWinbackConsent.d.ts +29 -0
  49. package/lib/actions/crmWinbackConsent.js +158 -0
  50. package/lib/actions/crmWinbackPolicy.d.ts +33 -0
  51. package/lib/actions/crmWinbackPolicy.js +115 -0
  52. package/lib/actions/crmWinbackShopSource.d.ts +15 -0
  53. package/lib/actions/crmWinbackShopSource.js +63 -0
  54. package/lib/actions/crud.js +1 -1
  55. package/lib/actions/databaseAccounts.js +1 -1
  56. package/lib/actions/databaseProvisioningLease.js +1 -1
  57. package/lib/actions/dynamodb.js +1 -1
  58. package/lib/actions/email.d.ts +4 -1
  59. package/lib/actions/email.js +25 -3
  60. package/lib/actions/files.js +1 -1
  61. package/lib/actions/flags.js +1 -1
  62. package/lib/actions/geminiVideo.js +1 -1
  63. package/lib/actions/groups.js +1 -1
  64. package/lib/actions/higgsfield.js +1 -1
  65. package/lib/actions/imageGeneration.js +1 -1
  66. package/lib/actions/images.js +1 -1
  67. package/lib/actions/index.d.ts +56 -0
  68. package/lib/actions/index.js +42 -1
  69. package/lib/actions/ios.js +1 -1
  70. package/lib/actions/locations.js +1 -1
  71. package/lib/actions/merchantAccountExperiment.d.ts +50 -0
  72. package/lib/actions/merchantAccountExperiment.js +424 -0
  73. package/lib/actions/merchantAccountExperimentConfig.d.ts +7 -0
  74. package/lib/actions/merchantAccountExperimentConfig.js +32 -0
  75. package/lib/actions/merchantAccountExperimentHost.d.ts +69 -0
  76. package/lib/actions/merchantAccountExperimentHost.js +92 -0
  77. package/lib/actions/merchantAccountExperimentPolicy.d.ts +66 -0
  78. package/lib/actions/merchantAccountExperimentPolicy.js +121 -0
  79. package/lib/actions/merchantAccountExperimentRelay.d.ts +10 -0
  80. package/lib/actions/merchantAccountExperimentRelay.js +75 -0
  81. package/lib/actions/merchantCalendar.d.ts +34 -0
  82. package/lib/actions/merchantCalendar.js +119 -0
  83. package/lib/actions/merchantCalendarBookings.d.ts +17 -0
  84. package/lib/actions/merchantCalendarBookings.js +113 -0
  85. package/lib/actions/merchantCalendarDelegation.d.ts +80 -0
  86. package/lib/actions/merchantCalendarDelegation.js +353 -0
  87. package/lib/actions/merchantCalendarDiscovery.d.ts +38 -0
  88. package/lib/actions/merchantCalendarDiscovery.js +124 -0
  89. package/lib/actions/merchantCalendarEventHost.d.ts +105 -0
  90. package/lib/actions/merchantCalendarEventHost.js +16 -0
  91. package/lib/actions/merchantCalendarEventPrivacy.d.ts +7 -0
  92. package/lib/actions/merchantCalendarEventPrivacy.js +70 -0
  93. package/lib/actions/merchantCalendarEventRepository.d.ts +121 -0
  94. package/lib/actions/merchantCalendarEventRepository.js +295 -0
  95. package/lib/actions/merchantCalendarEventTransport.d.ts +65 -0
  96. package/lib/actions/merchantCalendarEventTransport.js +132 -0
  97. package/lib/actions/merchantCalendarEvents.d.ts +172 -0
  98. package/lib/actions/merchantCalendarEvents.js +365 -0
  99. package/lib/actions/merchantCalendarInvitationConsent.d.ts +28 -0
  100. package/lib/actions/merchantCalendarInvitationConsent.js +118 -0
  101. package/lib/actions/merchantCalendarManagedSource.d.ts +22 -0
  102. package/lib/actions/merchantCalendarManagedSource.js +24 -0
  103. package/lib/actions/merchantCalendarOAuth.d.ts +92 -0
  104. package/lib/actions/merchantCalendarOAuth.js +502 -0
  105. package/lib/actions/merchantCalendarOAuthConfig.d.ts +4 -0
  106. package/lib/actions/merchantCalendarOAuthConfig.js +30 -0
  107. package/lib/actions/merchantCalendarOAuthRepository.d.ts +57 -0
  108. package/lib/actions/merchantCalendarOAuthRepository.js +108 -0
  109. package/lib/actions/merchantCalendarOAuthTransport.d.ts +4 -0
  110. package/lib/actions/merchantCalendarOAuthTransport.js +25 -0
  111. package/lib/actions/merchantCalendarScopes.d.ts +4 -0
  112. package/lib/actions/merchantCalendarScopes.js +31 -0
  113. package/lib/actions/merchantFinance.d.ts +65 -0
  114. package/lib/actions/merchantFinance.js +244 -0
  115. package/lib/actions/merchantFinanceProvider.d.ts +57 -0
  116. package/lib/actions/merchantFinanceProvider.js +180 -0
  117. package/lib/actions/merchantOperations.d.ts +94 -0
  118. package/lib/actions/merchantOperations.js +489 -0
  119. package/lib/actions/messages.js +1 -1
  120. package/lib/actions/notifications.js +1 -1
  121. package/lib/actions/ollamaGeneration.js +1 -1
  122. package/lib/actions/openaiResponseSession.js +1 -1
  123. package/lib/actions/payments.js +1 -1
  124. package/lib/actions/personas.js +1 -1
  125. package/lib/actions/phoneSupport.js +1 -1
  126. package/lib/actions/posts.js +1 -1
  127. package/lib/actions/providerCredentials.d.ts +35 -0
  128. package/lib/actions/providerCredentials.js +166 -0
  129. package/lib/actions/query.js +1 -1
  130. package/lib/actions/reactions.js +1 -1
  131. package/lib/actions/rum.js +1 -1
  132. package/lib/actions/s3.d.ts +10 -7
  133. package/lib/actions/s3.js +59 -14
  134. package/lib/actions/search.js +1 -1
  135. package/lib/actions/sms.js +1 -1
  136. package/lib/actions/statistics.js +1 -1
  137. package/lib/actions/subscriptions.js +1 -1
  138. package/lib/actions/supportChannelSources.d.ts +66 -0
  139. package/lib/actions/supportChannelSources.js +183 -0
  140. package/lib/actions/supportCommerce.d.ts +62 -0
  141. package/lib/actions/supportCommerce.js +252 -0
  142. package/lib/actions/supportConnect.d.ts +39 -0
  143. package/lib/actions/supportConnect.js +224 -0
  144. package/lib/actions/supportContext.d.ts +31 -0
  145. package/lib/actions/supportContext.js +88 -0
  146. package/lib/actions/supportConversation.d.ts +102 -0
  147. package/lib/actions/supportConversation.js +100 -0
  148. package/lib/actions/supportEmailEvents.d.ts +20 -0
  149. package/lib/actions/supportEmailEvents.js +130 -0
  150. package/lib/actions/supportEmailHandoff.d.ts +114 -0
  151. package/lib/actions/supportEmailHandoff.js +356 -0
  152. package/lib/actions/supportOperations.d.ts +32 -0
  153. package/lib/actions/supportOperations.js +74 -0
  154. package/lib/actions/supportPolicy.d.ts +9 -0
  155. package/lib/actions/supportPolicy.js +44 -0
  156. package/lib/actions/supportPurposeConsent.d.ts +32 -0
  157. package/lib/actions/supportPurposeConsent.js +196 -0
  158. package/lib/actions/supportPurposePrivacy.d.ts +15 -0
  159. package/lib/actions/supportPurposePrivacy.js +181 -0
  160. package/lib/actions/supportSemanticReview.d.ts +64 -0
  161. package/lib/actions/supportSemanticReview.js +239 -0
  162. package/lib/actions/tags.js +1 -1
  163. package/lib/actions/users.js +22 -3
  164. package/lib/actions/videoGeneration.js +1 -1
  165. package/lib/actions/videos.js +1 -1
  166. package/lib/adapters/arangoAdapter.js +1 -1
  167. package/lib/adapters/contentAdapter.js +1 -1
  168. package/lib/adapters/fileAdapter.js +1 -1
  169. package/lib/adapters/geminiGenerationAdapter.js +1 -1
  170. package/lib/adapters/higgsfieldAdapter.js +1 -1
  171. package/lib/adapters/higgsfieldModelCatalog.js +1 -1
  172. package/lib/adapters/higgsfieldModels.js +1 -1
  173. package/lib/adapters/imageAdapter.js +1 -1
  174. package/lib/adapters/imageGenerationAdapter.js +1 -1
  175. package/lib/adapters/index.js +1 -1
  176. package/lib/adapters/messageAdapter.js +1 -1
  177. package/lib/adapters/postAdapter.js +1 -1
  178. package/lib/adapters/reaktorAdapter.js +1 -1
  179. package/lib/adapters/tagAdapter.js +1 -1
  180. package/lib/adapters/userAdapter.js +1 -1
  181. package/lib/assistant/core.js +1 -1
  182. package/lib/assistant/faq.js +1 -1
  183. package/lib/assistant/faqCore.js +1 -1
  184. package/lib/assistant/index.js +1 -1
  185. package/lib/assistant/service.js +1 -1
  186. package/lib/config.js +1 -1
  187. package/lib/constants/collections.d.ts +2 -1
  188. package/lib/constants/collections.js +2 -1
  189. package/lib/durableChat/conversations.js +1 -1
  190. package/lib/durableChat/errors.js +1 -1
  191. package/lib/durableChat/events.js +1 -1
  192. package/lib/durableChat/index.js +1 -1
  193. package/lib/durableChat/membership.js +1 -1
  194. package/lib/durableChat/messageTypes.js +1 -1
  195. package/lib/durableChat/messages.js +1 -1
  196. package/lib/durableChat/transaction.js +1 -1
  197. package/lib/durableChat/types.js +1 -1
  198. package/lib/handlers/graphqlHandler.js +1 -1
  199. package/lib/index.js +1 -1
  200. package/lib/lambdas/actions/websockets.js +1 -1
  201. package/lib/lambdas/authorizer.js +1 -1
  202. package/lib/lambdas/connection.js +1 -1
  203. package/lib/lambdas/utils/message.js +1 -1
  204. package/lib/lambdas/utils/websocket.js +1 -1
  205. package/lib/mocks/conversation.js +1 -1
  206. package/lib/mocks/file.js +1 -1
  207. package/lib/mocks/group.js +1 -1
  208. package/lib/mocks/image.js +1 -1
  209. package/lib/mocks/post.js +1 -1
  210. package/lib/mocks/tag.js +1 -1
  211. package/lib/mocks/user.js +1 -1
  212. package/lib/mocks/video.js +1 -1
  213. package/lib/mutations/analytics/analytics.js +1 -1
  214. package/lib/mutations/content/content.js +1 -1
  215. package/lib/mutations/crm/crm.js +395 -7
  216. package/lib/mutations/events/events.js +1 -1
  217. package/lib/mutations/flags/flags.js +1 -1
  218. package/lib/mutations/groups/groups.js +1 -1
  219. package/lib/mutations/higgsfield/higgsfield.js +1 -1
  220. package/lib/mutations/images/images.js +1 -1
  221. package/lib/mutations/index.js +1 -1
  222. package/lib/mutations/locations/locations.js +1 -1
  223. package/lib/mutations/messages/messages.js +1 -1
  224. package/lib/mutations/personas/personas.js +1 -1
  225. package/lib/mutations/posts/posts.js +1 -1
  226. package/lib/mutations/reactions/reactions.js +1 -1
  227. package/lib/mutations/rum/rum.js +1 -1
  228. package/lib/mutations/statistics/statistics.js +1 -1
  229. package/lib/mutations/subscriptions/subscriptions.js +1 -1
  230. package/lib/mutations/tags/tags.js +1 -1
  231. package/lib/mutations/users/users.js +1 -1
  232. package/lib/mutations/videos/videos.js +1 -1
  233. package/lib/nativePush/graphql.js +1 -1
  234. package/lib/nativePush/index.js +1 -1
  235. package/lib/nativePush/migrations.js +1 -1
  236. package/lib/nativePush/nativePushContract.fixture.js +1 -1
  237. package/lib/nativePush/payload.js +1 -1
  238. package/lib/nativePush/repository.js +1 -1
  239. package/lib/nativePush/service.js +1 -1
  240. package/lib/nativePush/snsProvider.js +1 -1
  241. package/lib/nativePush/types.js +1 -1
  242. package/lib/objectTypes/analytics.js +1 -1
  243. package/lib/objectTypes/app.js +1 -1
  244. package/lib/objectTypes/bankAccount.js +1 -1
  245. package/lib/objectTypes/connection.js +1 -1
  246. package/lib/objectTypes/content.js +1 -1
  247. package/lib/objectTypes/contentGeneration.js +1 -1
  248. package/lib/objectTypes/conversation.js +1 -1
  249. package/lib/objectTypes/creditCard.js +1 -1
  250. package/lib/objectTypes/crm.js +1 -1
  251. package/lib/objectTypes/document.js +1 -1
  252. package/lib/objectTypes/error.js +1 -1
  253. package/lib/objectTypes/event.js +1 -1
  254. package/lib/objectTypes/external.js +1 -1
  255. package/lib/objectTypes/file.js +1 -1
  256. package/lib/objectTypes/filter.js +1 -1
  257. package/lib/objectTypes/flag.js +1 -1
  258. package/lib/objectTypes/group.js +1 -1
  259. package/lib/objectTypes/higgsfield.js +1 -1
  260. package/lib/objectTypes/iapSubscription.js +1 -1
  261. package/lib/objectTypes/image.js +1 -1
  262. package/lib/objectTypes/imageGeneration.js +1 -1
  263. package/lib/objectTypes/index.js +1 -1
  264. package/lib/objectTypes/location.js +1 -1
  265. package/lib/objectTypes/message.js +1 -1
  266. package/lib/objectTypes/passcode.js +1 -1
  267. package/lib/objectTypes/persona.js +1 -1
  268. package/lib/objectTypes/plan.js +1 -1
  269. package/lib/objectTypes/post.js +1 -1
  270. package/lib/objectTypes/query.js +1 -1
  271. package/lib/objectTypes/reaction.js +1 -1
  272. package/lib/objectTypes/relation.js +1 -1
  273. package/lib/objectTypes/rum.js +1 -1
  274. package/lib/objectTypes/search.js +1 -1
  275. package/lib/objectTypes/statistics.js +1 -1
  276. package/lib/objectTypes/subscription.js +1 -1
  277. package/lib/objectTypes/tag.js +1 -1
  278. package/lib/objectTypes/user.js +1 -1
  279. package/lib/objectTypes/video.js +1 -1
  280. package/lib/objectTypes/videoGeneration.js +1 -1
  281. package/lib/organizations/accountLifecycle.js +1 -1
  282. package/lib/organizations/authorization.js +1 -1
  283. package/lib/organizations/billing.js +1 -1
  284. package/lib/organizations/billingProvider.js +1 -1
  285. package/lib/organizations/billingUpdates.js +1 -1
  286. package/lib/organizations/index.js +1 -1
  287. package/lib/organizations/mail.js +1 -1
  288. package/lib/organizations/memberDirectory.js +1 -1
  289. package/lib/organizations/membership.js +1 -1
  290. package/lib/organizations/passwordRecovery.js +1 -1
  291. package/lib/organizations/plans.js +1 -1
  292. package/lib/organizations/providerPagination.js +1 -1
  293. package/lib/organizations/reconciliation.js +1 -1
  294. package/lib/organizations/signup.js +1 -1
  295. package/lib/organizations/store.js +1 -1
  296. package/lib/organizations/types.js +1 -1
  297. package/lib/organizations/verification.js +1 -1
  298. package/lib/queries/analytics/analytics.js +1 -1
  299. package/lib/queries/content/content.js +1 -1
  300. package/lib/queries/crm/crm.js +251 -5
  301. package/lib/queries/events/events.js +1 -1
  302. package/lib/queries/flags/flags.js +1 -1
  303. package/lib/queries/groups/groups.js +1 -1
  304. package/lib/queries/higgsfield/higgsfield.js +1 -1
  305. package/lib/queries/images/images.js +1 -1
  306. package/lib/queries/index.js +1 -1
  307. package/lib/queries/locations/locations.js +1 -1
  308. package/lib/queries/messages/messages.js +1 -1
  309. package/lib/queries/personas/personas.js +1 -1
  310. package/lib/queries/posts/posts.js +1 -1
  311. package/lib/queries/query/query.js +1 -1
  312. package/lib/queries/reactions/reactions.js +1 -1
  313. package/lib/queries/statistics/statistics.js +1 -1
  314. package/lib/queries/subscriptions/subscriptions.js +1 -1
  315. package/lib/queries/tags/tags.js +1 -1
  316. package/lib/queries/users/users.js +1 -1
  317. package/lib/queries/videos/videos.js +1 -1
  318. package/lib/templates/email/layout.js +1 -1
  319. package/lib/templates/email/passwordForgot.js +1 -1
  320. package/lib/templates/email/passwordRecovery.js +1 -1
  321. package/lib/templates/email/verifyEmail.js +1 -1
  322. package/lib/templates/email/welcome.js +1 -1
  323. package/lib/templates/sms/passwordForgot.js +1 -1
  324. package/lib/templates/sms/passwordRecovery.js +1 -1
  325. package/lib/templates/sms/verifyEmail.js +1 -1
  326. package/lib/templates/sms/verifyPhone.js +1 -1
  327. package/lib/templates/sms/welcome.js +1 -1
  328. package/lib/types/analytics.types.js +1 -1
  329. package/lib/types/apps.types.js +1 -1
  330. package/lib/types/arangodb.types.js +1 -1
  331. package/lib/types/auth.types.d.ts +2 -0
  332. package/lib/types/auth.types.js +1 -1
  333. package/lib/types/connections.types.js +1 -1
  334. package/lib/types/content.types.js +1 -1
  335. package/lib/types/conversations.types.js +1 -1
  336. package/lib/types/crm.types.d.ts +6 -0
  337. package/lib/types/crm.types.js +1 -1
  338. package/lib/types/databaseCredentials.types.js +1 -1
  339. package/lib/types/email.types.js +1 -1
  340. package/lib/types/error.types.js +1 -1
  341. package/lib/types/files.types.js +1 -1
  342. package/lib/types/flags.types.js +1 -1
  343. package/lib/types/google.types.js +1 -1
  344. package/lib/types/groups.types.js +1 -1
  345. package/lib/types/images.types.js +1 -1
  346. package/lib/types/index.js +1 -1
  347. package/lib/types/locations.types.js +1 -1
  348. package/lib/types/messages.types.js +1 -1
  349. package/lib/types/notifications.types.js +1 -1
  350. package/lib/types/payments.types.js +1 -1
  351. package/lib/types/personas.types.js +1 -1
  352. package/lib/types/posts.types.js +1 -1
  353. package/lib/types/rum.types.js +1 -1
  354. package/lib/types/statistics.types.js +1 -1
  355. package/lib/types/tags.types.js +1 -1
  356. package/lib/types/users.types.d.ts +2 -0
  357. package/lib/types/users.types.js +1 -1
  358. package/lib/types/videos.types.js +1 -1
  359. package/lib/types/websockets.types.js +1 -1
  360. package/lib/upload.js +1 -1
  361. package/lib/utils/adapterUtils.js +1 -1
  362. package/lib/utils/analyticsUtils.js +1 -1
  363. package/lib/utils/appContext.js +1 -1
  364. package/lib/utils/aqlHelpers.js +1 -1
  365. package/lib/utils/arangodbUtils.js +1 -1
  366. package/lib/utils/authUtils.js +17 -1
  367. package/lib/utils/awsUtils.js +1 -1
  368. package/lib/utils/collectionRegistry.js +1 -1
  369. package/lib/utils/contextUtils.js +1 -1
  370. package/lib/utils/databaseCredentials.js +1 -1
  371. package/lib/utils/dbI18n.example.js +1 -1
  372. package/lib/utils/dbI18n.js +1 -1
  373. package/lib/utils/generationCallback.js +1 -1
  374. package/lib/utils/googleTranslate.js +1 -1
  375. package/lib/utils/graphqlUtils.d.ts +2 -0
  376. package/lib/utils/graphqlUtils.js +1 -1
  377. package/lib/utils/imageUtils.js +1 -1
  378. package/lib/utils/index.js +1 -1
  379. package/lib/utils/languageDetection.js +1 -1
  380. package/lib/utils/localeUtils.example.js +1 -1
  381. package/lib/utils/localeUtils.js +1 -1
  382. package/lib/utils/mediaAccess.js +1 -1
  383. package/lib/utils/middlewareUtils.js +1 -1
  384. package/lib/utils/nodeRealtime.js +1 -1
  385. package/lib/utils/opaqueToken.js +1 -1
  386. package/lib/utils/queryBuilder.js +1 -1
  387. package/lib/utils/schemaUtils.js +1 -1
  388. package/lib/utils/secretDatabase.js +1 -1
  389. package/lib/utils/sessionUtils.js +1 -1
  390. package/lib/utils/stripeUtils.js +1 -1
  391. package/lib/utils/templateUtils.js +1 -1
  392. package/lib/utils/testUtils.js +1 -1
  393. package/lib/utils/translationQueue.example.js +1 -1
  394. package/lib/utils/translationQueue.js +1 -1
  395. package/lib/videoProcessing.js +1 -1
  396. package/package.json +8 -6
@@ -0,0 +1,413 @@
1
+ /* eslint-disable no-await-in-loop, no-underscore-dangle -- Bounded native/provider reads stay ordered. */ import { post } from '@nlabs/rip-hunter';
2
+ import { aql } from 'arangojs';
3
+ import { scopeContextToApp } from '../utils/appContext.js';
4
+ import { useDb } from '../utils/arangodbUtils.js';
5
+ import { requireCrmAdministrator } from './crm.js';
6
+ import { CRM_CHECKOUT_RECOVERY_QUERY, crmCheckoutRecoveryProof, crmRecoveryDigest as hash, crmRecoveryIdentifier as key, validCrmCheckoutRecoveryBounds } from './crmCheckoutRecoveryPolicy.js';
7
+ import { authorizeCrmExecutionGrant, ensureOwnerExecutionCollection, readCrmExecutionTarget } from './crmExecution.js';
8
+ const sources = ()=>{
9
+ try {
10
+ const parsed = JSON.parse(process.env.CRM_CHECKOUT_RECOVERY_SOURCES || '[]');
11
+ if (!Array.isArray(parsed) || parsed.length > 100 || parsed.some((value)=>!value || Object.keys(value).sort().join(',') !== 'appId,customersAccessApproved,expiresAt,id,ordersAccessApproved,organizationId,projectId,shop,token' || ![
12
+ value.id,
13
+ value.appId,
14
+ value.organizationId,
15
+ value.projectId
16
+ ].every(key) || !/^[a-z0-9][a-z0-9-]{0,61}\.myshopify\.com$/.test(value.shop) || typeof value.token !== 'string' || !value.token.trim() || value.token.length > 8192 || !Number.isSafeInteger(value.expiresAt) || value.ordersAccessApproved !== true || value.customersAccessApproved !== true) || new Set(parsed.map((value)=>value.id)).size !== parsed.length) {
17
+ throw new Error('invalid');
18
+ }
19
+ return parsed;
20
+ } catch {
21
+ throw new Error('crm_checkout_recovery_configuration_hold');
22
+ }
23
+ };
24
+ const sourceFor = (binding, at)=>{
25
+ const matches = sources().filter((value)=>value.id === binding.sourceId && value.appId === binding.appId && value.organizationId === binding.organizationId && value.projectId === binding.projectId && value.expiresAt > at);
26
+ if (matches.length !== 1) {
27
+ throw new Error('crm_checkout_recovery_source_hold');
28
+ }
29
+ return matches[0];
30
+ };
31
+ const bounds = (grant, input)=>{
32
+ const value = grant.recoveryBounds;
33
+ if (!grant.scopes.includes('crm:checkout_recovery') || !grant.scopes.includes('crm:outreach') || !validCrmCheckoutRecoveryBounds(value) || grant.appId !== input.appId || value.organizationId !== input.organizationId || value.projectId !== input.projectId || !value.campaignIds.includes(input.campaignId) || !value.sourceIds.includes(input.sourceId)) {
34
+ throw new Error('crm_checkout_recovery_scope_required');
35
+ }
36
+ };
37
+ const read = async (source, binding, email, at, request = post)=>{
38
+ const numeric = /^gid:\/\/shopify\/AbandonedCheckout\/(\d+)$/.exec(binding.checkoutId)?.[1];
39
+ if (!numeric || !/^gid:\/\/shopify\/Customer\/\d+$/.test(binding.customerId)) {
40
+ throw new Error('crm_checkout_recovery_identity_hold');
41
+ }
42
+ let response;
43
+ try {
44
+ response = await request(`https://${source.shop}/admin/api/2026-10/graphql.json`, {
45
+ query: CRM_CHECKOUT_RECOVERY_QUERY,
46
+ variables: {
47
+ query: `id:${numeric} status:open recovery_state:not_recovered email_state:not_sent`
48
+ }
49
+ }, {
50
+ cache: false,
51
+ headers: new Headers({
52
+ 'X-Shopify-Access-Token': source.token
53
+ }),
54
+ timeout: 5000
55
+ });
56
+ } catch {
57
+ throw new Error('crm_checkout_recovery_provider_hold');
58
+ }
59
+ const proof = crmCheckoutRecoveryProof(response, source, binding.checkoutId, binding.customerId, email, at);
60
+ if (!proof) {
61
+ throw new Error('crm_checkout_recovery_current_checkout_hold');
62
+ }
63
+ return proof;
64
+ };
65
+ const load = async (db, id, query = db.query.bind(db))=>query(aql`
66
+ LET binding = DOCUMENT('crmCheckoutRecoveryBindings', ${id})
67
+ LET association = binding ? DOCUMENT('hasCrmCampaignOutcome', binding.associationId) : null
68
+ LET user = binding ? DOCUMENT('users', binding.userId) : null
69
+ LET organization = binding ? DOCUMENT('groups', binding.organizationId) : null
70
+ RETURN {association, binding, organization, user}`).then((cursor)=>cursor.next());
71
+ const eligible = (row, at)=>{
72
+ const { association, binding, organization, user } = row || {};
73
+ const consent = user?.checkoutRecoveryConsent;
74
+ const customerId = /^\d+$/.test(user?.shopifyCustomerId || '') ? `gid://shopify/Customer/${user.shopifyCustomerId}` : user?.shopifyCustomerId;
75
+ return Boolean(binding && user && organization && association && binding.status === 'active' && Number.isSafeInteger(binding.expiresAt) && binding.expiresAt > at && user.deleted !== true && user.active !== false && user.crmAnalyticsSuppressed !== true && user.marketingOptIn === true && Number.isFinite(user.marketingOptInAt) && user.marketingOptInAt <= at && user.marketingConsentSource && (user.marketingOptOutAt === undefined || Number.isFinite(user.marketingOptOutAt) && user.marketingOptOutAt < user.marketingOptInAt) && user._key === binding.userId && user._rev === binding.userRevision && customerId === binding.customerId && consent?.purpose === 'checkout_recovery' && consent.source === 'authenticated_customer' && consent.revoked !== true && Number.isSafeInteger(consent.at) && consent.at <= at && Number.isSafeInteger(consent.expiresAt) && consent.expiresAt > at && consent.expiresAt === binding.consentExpiresAt && association.status === 'active' && association._rev === binding.associationRevision && association.appId === binding.appId && association.userId === binding.userId && association.organizationId === binding.organizationId && association.projectId === binding.projectId && association.campaignId === binding.campaignId && association.consent?.purpose === 'campaign_outcomes' && association.consent.expiresAt > at);
76
+ };
77
+ const cadence = async (db, grant, binding, at, query = db.query.bind(db), receiptId)=>{
78
+ const cutoff = at - grant.recoveryBounds.cooldownHours * 3600000;
79
+ const recent = await query(aql`FOR receipt IN crmExecutionReceipts
80
+ FILTER receipt.appId == ${binding.appId} AND receipt.targetId == ${binding.userId}
81
+ AND receipt.kind == 'crm_outreach' AND receipt.id != ${receiptId || ''}
82
+ AND (receipt.state IN ['unknown', 'submitting'] OR (receipt.state == 'applied'
83
+ AND (!IS_NUMBER(receipt.providerAcceptedAt) OR receipt.providerAcceptedAt >= ${cutoff})))
84
+ LIMIT 1 RETURN true`).then((cursor)=>cursor.next());
85
+ if (recent) {
86
+ throw new Error('crm_checkout_recovery_cadence_hold');
87
+ }
88
+ };
89
+ /** Only the authenticated customer can record this independent purpose; administrators cannot imply consent. */ export const recordCrmCheckoutRecoveryConsent = async (context, input, now = Date.now)=>{
90
+ if (!input || Object.keys(input).sort().join(',') !== 'appId,consent,expectedUserRevision,expiresAt' || !key(input.appId) || typeof input.consent !== 'boolean' || !key(input.expectedUserRevision) || !Number.isSafeInteger(input.expiresAt) || input.expiresAt <= now() || input.expiresAt > now() + 30 * 86400000 || !key(context.session?.userId)) {
91
+ throw new Error('invalid_crm_checkout_recovery_consent');
92
+ }
93
+ const scoped = await scopeContextToApp(context, input.appId);
94
+ const saved = await useDb(scoped.databaseName).query(aql`FOR user IN users
95
+ FILTER user._key == ${context.session.userId} AND user._rev == ${input.expectedUserRevision} AND user.deleted != true
96
+ AND (${!input.consent} OR user.active != false)
97
+ UPDATE user WITH {checkoutRecoveryConsent: ${{
98
+ at: now(),
99
+ expiresAt: input.expiresAt,
100
+ purpose: 'checkout_recovery',
101
+ revoked: !input.consent,
102
+ source: 'authenticated_customer'
103
+ }}} IN users OPTIONS {ignoreRevs: false} RETURN true`).then((cursor)=>cursor.next());
104
+ if (!saved) {
105
+ throw new Error('crm_checkout_recovery_consent_revision_conflict');
106
+ }
107
+ return true;
108
+ };
109
+ /** Registration binds verified existing source identities; it neither grants consent nor sends a message. */ export const registerCrmCheckoutRecoveryBinding = async (context, input, now = Date.now, request = post)=>{
110
+ requireCrmAdministrator(context);
111
+ if (!input || Object.keys(input).sort().join(',') !== [
112
+ 'appId',
113
+ 'associationId',
114
+ 'checkoutId',
115
+ 'expectedAssociationRevision',
116
+ 'expectedUserRevision',
117
+ 'sourceId',
118
+ 'userId'
119
+ ].join(',') || ![
120
+ input.appId,
121
+ input.associationId,
122
+ input.expectedAssociationRevision,
123
+ input.expectedUserRevision,
124
+ input.sourceId,
125
+ input.userId
126
+ ].every(key) || !/^gid:\/\/shopify\/AbandonedCheckout\/\d+$/.test(input.checkoutId)) {
127
+ throw new Error('invalid_crm_checkout_recovery_binding');
128
+ }
129
+ const scoped = await scopeContextToApp(context, input.appId);
130
+ const db = useDb(scoped.databaseName);
131
+ const row = await db.query(aql`RETURN {association: DOCUMENT('hasCrmCampaignOutcome', ${input.associationId}),
132
+ user: DOCUMENT('users', ${input.userId})}`).then((cursor)=>cursor.next());
133
+ const { association, user } = row || {};
134
+ const consent = user?.checkoutRecoveryConsent;
135
+ const customerId = /^\d+$/.test(user?.shopifyCustomerId || '') ? `gid://shopify/Customer/${user.shopifyCustomerId}` : user?.shopifyCustomerId;
136
+ const binding = {
137
+ _key: '',
138
+ _rev: '',
139
+ appId: input.appId,
140
+ associationId: input.associationId,
141
+ associationRevision: input.expectedAssociationRevision,
142
+ campaignId: association?.campaignId,
143
+ checkoutId: input.checkoutId,
144
+ consentExpiresAt: consent?.expiresAt,
145
+ customerId,
146
+ expiresAt: Math.min(consent?.expiresAt, association?.consent?.expiresAt),
147
+ organizationId: association?.organizationId,
148
+ projectId: association?.projectId,
149
+ sourceHash: '',
150
+ sourceId: input.sourceId,
151
+ status: 'active',
152
+ userId: input.userId,
153
+ userRevision: input.expectedUserRevision
154
+ };
155
+ const organization = key(binding.organizationId) ? await db.query(aql`RETURN DOCUMENT('groups', ${binding.organizationId})`).then((cursor)=>cursor.next()) : undefined;
156
+ if (!eligible({
157
+ association,
158
+ binding,
159
+ organization,
160
+ user
161
+ }, now()) || !key(binding.campaignId)) {
162
+ throw new Error('crm_checkout_recovery_consent_or_identity_hold');
163
+ }
164
+ const source = sourceFor(binding, now());
165
+ await read(source, binding, user.email, now(), request);
166
+ binding.sourceHash = hash(source);
167
+ binding._key = hash([
168
+ binding.appId,
169
+ binding.organizationId,
170
+ binding.projectId,
171
+ binding.campaignId,
172
+ source.shop,
173
+ binding.checkoutId,
174
+ binding.customerId
175
+ ]);
176
+ const current = await db.query(aql`RETURN {association: DOCUMENT('hasCrmCampaignOutcome', ${input.associationId}),
177
+ user: DOCUMENT('users', ${input.userId})}`).then((cursor)=>cursor.next());
178
+ if (hash(sourceFor(binding, now())) !== binding.sourceHash || !eligible({
179
+ ...current,
180
+ binding,
181
+ organization
182
+ }, now())) {
183
+ throw new Error('crm_checkout_recovery_authority_changed');
184
+ }
185
+ for (const [name, edge] of [
186
+ [
187
+ 'crmCheckoutRecoveryBindings',
188
+ false
189
+ ],
190
+ [
191
+ 'hasCrmCheckoutRecoveryBinding',
192
+ true
193
+ ]
194
+ ]){
195
+ await ensureOwnerExecutionCollection(db, name, edge);
196
+ }
197
+ for (const name of [
198
+ 'crmCheckoutRecoveryBindings',
199
+ 'hasCrmCheckoutRecoveryBinding'
200
+ ]){
201
+ await db.collection(name).ensureIndex({
202
+ expireAfter: 0,
203
+ fields: [
204
+ 'retireAt'
205
+ ],
206
+ type: 'ttl'
207
+ });
208
+ }
209
+ const { _rev, ...record } = binding;
210
+ const stored = {
211
+ ...record,
212
+ retireAt: Math.floor(binding.expiresAt / 1000)
213
+ };
214
+ await db.query(aql`UPSERT {_key: ${binding._key}} INSERT ${stored} UPDATE ${stored} IN crmCheckoutRecoveryBindings`);
215
+ await db.query(aql`UPSERT {_key: ${binding._key}} INSERT ${{
216
+ _from: `users/${binding.userId}`,
217
+ _key: binding._key,
218
+ _to: `crmCheckoutRecoveryBindings/${binding._key}`,
219
+ appId: binding.appId,
220
+ projectId: binding.projectId,
221
+ retireAt: stored.retireAt
222
+ }}
223
+ UPDATE ${{
224
+ retireAt: stored.retireAt
225
+ }} IN hasCrmCheckoutRecoveryBinding`);
226
+ return {
227
+ id: binding._key,
228
+ status: 'registered'
229
+ };
230
+ };
231
+ /** Every review and execution repeats protected source and native identity checks. */ export const validateCrmCheckoutRecoveryCandidate = async (db, grant, value, now = Date.now, query = db.query.bind(db), request = post, receiptId)=>{
232
+ if (!value || Object.keys(value).sort().join(',') !== 'candidateId,revision' || !/^[a-f0-9]{64}$/.test(value.candidateId) || !/^[a-f0-9]{64}$/.test(value.revision)) {
233
+ throw new Error('invalid_crm_checkout_recovery_candidate');
234
+ }
235
+ const candidate = await query(aql`RETURN DOCUMENT('crmCheckoutRecoveryCandidates', ${value.candidateId})`).then((cursor)=>cursor.next());
236
+ if (!candidate || candidate.revision !== value.revision || !Number.isFinite(Date.parse(candidate.expiresAt)) || Date.parse(candidate.expiresAt) <= now()) {
237
+ throw new Error('crm_checkout_recovery_candidate_hold');
238
+ }
239
+ const row = await load(db, candidate.bindingId, query);
240
+ if (!eligible(row, now()) || row.binding._rev !== candidate.bindingRevision) {
241
+ throw new Error('crm_checkout_recovery_identity_hold');
242
+ }
243
+ const { binding } = row;
244
+ bounds(grant, binding);
245
+ const source = sourceFor(binding, now());
246
+ if (hash(source) !== binding.sourceHash) {
247
+ throw new Error('crm_checkout_recovery_source_hold');
248
+ }
249
+ await cadence(db, grant, binding, now(), query, receiptId);
250
+ const proof = await read(source, binding, candidate.email, now(), request);
251
+ const after = await load(db, candidate.bindingId, query);
252
+ if (proof.revision !== candidate.proofRevision || hash(sourceFor(binding, now())) !== binding.sourceHash || !eligible(after, now()) || after.binding._rev !== candidate.bindingRevision) {
253
+ throw new Error('crm_checkout_recovery_authority_changed');
254
+ }
255
+ return {
256
+ ...candidate,
257
+ verifiedRecoveryUrl: proof.recoveryLinkHash === candidate.recoveryLinkHash ? proof.recoveryUrl : undefined
258
+ };
259
+ };
260
+ export const generateCrmCheckoutRecoveryCandidates = async (context, input, now = Date.now, request = post)=>{
261
+ if (!input || Object.keys(input).sort().join(',') !== 'appId,campaignId,limit,organizationId,projectId,sourceId' || ![
262
+ input.appId,
263
+ input.campaignId,
264
+ input.organizationId,
265
+ input.projectId,
266
+ input.sourceId
267
+ ].every(key) || !Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 25) {
268
+ throw new Error('invalid_crm_checkout_recovery_request');
269
+ }
270
+ const grant = await authorizeCrmExecutionGrant(context, input.appId, 'crm:checkout_recovery', now());
271
+ bounds(grant, input);
272
+ const db = useDb(grant.databaseName);
273
+ for (const [name, edge] of [
274
+ [
275
+ 'crmCheckoutRecoveryCandidates',
276
+ false
277
+ ],
278
+ [
279
+ 'hasCrmCheckoutRecoveryCandidate',
280
+ true
281
+ ],
282
+ [
283
+ 'hasCrmCheckoutRecoveryExecution',
284
+ true
285
+ ],
286
+ [
287
+ 'crmExecutionReceipts',
288
+ false
289
+ ]
290
+ ]){
291
+ await ensureOwnerExecutionCollection(db, name, edge);
292
+ }
293
+ for (const name of [
294
+ 'crmCheckoutRecoveryCandidates',
295
+ 'hasCrmCheckoutRecoveryCandidate'
296
+ ]){
297
+ await db.collection(name).ensureIndex({
298
+ expireAfter: 0,
299
+ fields: [
300
+ 'expiresAt'
301
+ ],
302
+ type: 'ttl'
303
+ });
304
+ }
305
+ const rows = await db.collection('crmCheckoutRecoveryBindings').exists() ? await db.query(aql`
306
+ FOR binding IN crmCheckoutRecoveryBindings
307
+ FILTER binding.appId == ${input.appId} AND binding.projectId == ${input.projectId}
308
+ AND binding.organizationId == ${input.organizationId} AND binding.campaignId == ${input.campaignId}
309
+ AND binding.sourceId == ${input.sourceId} AND binding.status == 'active'
310
+ SORT binding._key LIMIT 101 RETURN binding._key`).then((cursor)=>cursor.all()) : [];
311
+ const candidates = [];
312
+ const held = {
313
+ claimed: 0,
314
+ ineligible: 0
315
+ };
316
+ const deadline = Date.now() + 8000;
317
+ let budgetHeld = false;
318
+ for (const id of rows.slice(0, 100)){
319
+ if (Date.now() >= deadline) {
320
+ budgetHeld = true;
321
+ break;
322
+ }
323
+ try {
324
+ const row = await load(db, id);
325
+ if (!eligible(row, now())) {
326
+ throw new Error('crm_checkout_recovery_identity_hold');
327
+ }
328
+ const { binding } = row;
329
+ bounds(grant, binding);
330
+ const claimed = await db.query(aql`RETURN DOCUMENT('hasCrmCheckoutRecoveryExecution', ${id})`).then((cursor)=>cursor.next());
331
+ if (claimed) {
332
+ held.claimed += 1;
333
+ continue;
334
+ }
335
+ const source = sourceFor(binding, now());
336
+ if (hash(source) !== binding.sourceHash) {
337
+ throw new Error('crm_checkout_recovery_source_hold');
338
+ }
339
+ await cadence(db, grant, binding, now());
340
+ const target = await readCrmExecutionTarget(context, input.appId, 'crm_outreach', binding.userId, now);
341
+ const proof = await read(source, binding, target.email, now(), request);
342
+ const after = await load(db, id);
343
+ if (!eligible(after, now()) || binding._rev !== after.binding._rev || hash(sourceFor(binding, now())) !== binding.sourceHash) {
344
+ throw new Error('crm_checkout_recovery_authority_changed');
345
+ }
346
+ const candidate = {
347
+ _key: id,
348
+ appId: input.appId,
349
+ bindingId: id,
350
+ bindingRevision: binding._rev,
351
+ campaignId: input.campaignId,
352
+ email: target.email,
353
+ expiresAt: new Date(Math.min(now() + 900000, grant.expires, source.expiresAt, binding.expiresAt)).toISOString(),
354
+ id,
355
+ observedAt: proof.createdAt,
356
+ organizationId: input.organizationId,
357
+ projectId: input.projectId,
358
+ proofRevision: proof.revision,
359
+ reason: 'verified_unrecovered_checkout',
360
+ recoveryLinkHash: proof.recoveryLinkHash,
361
+ revision: '',
362
+ sourceId: input.sourceId,
363
+ targetId: target.id,
364
+ targetRevision: target.revision
365
+ };
366
+ candidate.revision = hash([
367
+ candidate.bindingRevision,
368
+ candidate.proofRevision,
369
+ candidate.targetRevision
370
+ ]);
371
+ await db.query(aql`UPSERT {_key: ${id}} INSERT ${candidate} UPDATE ${candidate} IN crmCheckoutRecoveryCandidates`);
372
+ await db.query(aql`UPSERT {_key: ${id}} INSERT ${{
373
+ _from: `crmCheckoutRecoveryBindings/${id}`,
374
+ _key: id,
375
+ _to: `crmCheckoutRecoveryCandidates/${id}`,
376
+ appId: input.appId,
377
+ expiresAt: candidate.expiresAt
378
+ }}
379
+ UPDATE ${{
380
+ expiresAt: candidate.expiresAt
381
+ }} IN hasCrmCheckoutRecoveryCandidate`);
382
+ const { _key, bindingId, bindingRevision, proofRevision, ...result } = candidate;
383
+ candidates.push(result);
384
+ if (candidates.length === input.limit) {
385
+ break;
386
+ }
387
+ } catch (error) {
388
+ if (!(error instanceof Error) || !error.message.startsWith('crm_checkout_recovery_') && !error.message.startsWith('crm_recipient_')) {
389
+ throw error;
390
+ }
391
+ held.ineligible += 1;
392
+ }
393
+ }
394
+ const current = await authorizeCrmExecutionGrant(context, input.appId, 'crm:checkout_recovery', now());
395
+ bounds(current, input);
396
+ if (hash(current) !== hash(grant)) {
397
+ throw new Error('crm_checkout_recovery_authority_changed');
398
+ }
399
+ return {
400
+ appId: input.appId,
401
+ campaignId: input.campaignId,
402
+ candidates,
403
+ generatedAt: new Date(now()).toISOString(),
404
+ held,
405
+ organizationId: input.organizationId,
406
+ projectId: input.projectId,
407
+ schemaVersion: 'crm_checkout_recovery_v1',
408
+ sourceId: input.sourceId,
409
+ truncated: budgetHeld || rows.length > 100 || candidates.length === input.limit
410
+ };
411
+ };
412
+
413
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvYWN0aW9ucy9jcm1DaGVja291dFJlY292ZXJ5LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIG5vLWF3YWl0LWluLWxvb3AsIG5vLXVuZGVyc2NvcmUtZGFuZ2xlIC0tIEJvdW5kZWQgbmF0aXZlL3Byb3ZpZGVyIHJlYWRzIHN0YXkgb3JkZXJlZC4gKi9cbmltcG9ydCB7cG9zdH0gZnJvbSAnQG5sYWJzL3JpcC1odW50ZXInO1xuaW1wb3J0IHthcWx9IGZyb20gJ2FyYW5nb2pzJztcblxuaW1wb3J0IHtzY29wZUNvbnRleHRUb0FwcH0gZnJvbSAnLi4vdXRpbHMvYXBwQ29udGV4dC5qcyc7XG5pbXBvcnQge3VzZURifSBmcm9tICcuLi91dGlscy9hcmFuZ29kYlV0aWxzLmpzJztcbmltcG9ydCB7cmVxdWlyZUNybUFkbWluaXN0cmF0b3J9IGZyb20gJy4vY3JtLmpzJztcbmltcG9ydCB7Q1JNX0NIRUNLT1VUX1JFQ09WRVJZX1FVRVJZLCBjcm1DaGVja291dFJlY292ZXJ5UHJvb2YsIGNybVJlY292ZXJ5RGlnZXN0IGFzIGhhc2gsXG4gIGNybVJlY292ZXJ5SWRlbnRpZmllciBhcyBrZXksIHZhbGlkQ3JtQ2hlY2tvdXRSZWNvdmVyeUJvdW5kc30gZnJvbSAnLi9jcm1DaGVja291dFJlY292ZXJ5UG9saWN5LmpzJztcbmltcG9ydCB7YXV0aG9yaXplQ3JtRXhlY3V0aW9uR3JhbnQsIGVuc3VyZU93bmVyRXhlY3V0aW9uQ29sbGVjdGlvbiwgcmVhZENybUV4ZWN1dGlvblRhcmdldH0gZnJvbSAnLi9jcm1FeGVjdXRpb24uanMnO1xuXG5pbXBvcnQgdHlwZSB7QXBpQ29udGV4dH0gZnJvbSAnLi4vdHlwZXMvYXV0aC50eXBlcy5qcyc7XG5pbXBvcnQgdHlwZSB7Q3JtQ2hlY2tvdXRSZWNvdmVyeUJpbmRpbmcsIENybUNoZWNrb3V0UmVjb3ZlcnlTb3VyY2V9IGZyb20gJy4vY3JtQ2hlY2tvdXRSZWNvdmVyeVBvbGljeS5qcyc7XG5cbnR5cGUgRGIgPSBSZXR1cm5UeXBlPHR5cGVvZiB1c2VEYj47XG50eXBlIEdyYW50ID0gQXdhaXRlZDxSZXR1cm5UeXBlPHR5cGVvZiBhdXRob3JpemVDcm1FeGVjdXRpb25HcmFudD4+O1xuZXhwb3J0IGludGVyZmFjZSBDcm1DaGVja291dFJlY292ZXJ5Q2FuZGlkYXRlIHtcbiAgYXBwSWQ6IHN0cmluZzsgY2FtcGFpZ25JZDogc3RyaW5nOyBlbWFpbDogc3RyaW5nOyBleHBpcmVzQXQ6IHN0cmluZzsgaWQ6IHN0cmluZzsgb2JzZXJ2ZWRBdDogc3RyaW5nO1xuICBvcmdhbml6YXRpb25JZDogc3RyaW5nOyBwcm9qZWN0SWQ6IHN0cmluZzsgcmVhc29uOiAndmVyaWZpZWRfdW5yZWNvdmVyZWRfY2hlY2tvdXQnOyByZWNvdmVyeUxpbmtIYXNoPzogc3RyaW5nOyByZXZpc2lvbjogc3RyaW5nO1xuICBzb3VyY2VJZDogc3RyaW5nOyB0YXJnZXRJZDogc3RyaW5nOyB0YXJnZXRSZXZpc2lvbjogc3RyaW5nO1xufVxuaW50ZXJmYWNlIEJpbmRpbmcge1xuICBfa2V5OiBzdHJpbmc7IF9yZXY6IHN0cmluZzsgYXBwSWQ6IHN0cmluZzsgYXNzb2NpYXRpb25JZDogc3RyaW5nOyBhc3NvY2lhdGlvblJldmlzaW9uOiBzdHJpbmc7IGNhbXBhaWduSWQ6IHN0cmluZztcbiAgY2hlY2tvdXRJZDogc3RyaW5nOyBjb25zZW50RXhwaXJlc0F0OiBudW1iZXI7IGN1c3RvbWVySWQ6IHN0cmluZzsgZXhwaXJlc0F0OiBudW1iZXI7IG9yZ2FuaXphdGlvbklkOiBzdHJpbmc7XG4gIHByb2plY3RJZDogc3RyaW5nO1xuICBzb3VyY2VIYXNoOiBzdHJpbmc7IHNvdXJjZUlkOiBzdHJpbmc7IHN0YXR1czogJ2FjdGl2ZScgfCAncmV2b2tlZCc7IHVzZXJJZDogc3RyaW5nOyB1c2VyUmV2aXNpb246IHN0cmluZztcbn1cbmludGVyZmFjZSBDYW5kaWRhdGUgZXh0ZW5kcyBDcm1DaGVja291dFJlY292ZXJ5Q2FuZGlkYXRlIHtcbiAgX2tleTogc3RyaW5nOyBiaW5kaW5nSWQ6IHN0cmluZzsgYmluZGluZ1JldmlzaW9uOiBzdHJpbmc7IHByb29mUmV2aXNpb246IHN0cmluZztcbn1cbmNvbnN0IHNvdXJjZXMgPSAoKTogQ3JtQ2hlY2tvdXRSZWNvdmVyeVNvdXJjZVtdID0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKHByb2Nlc3MuZW52LkNSTV9DSEVDS09VVF9SRUNPVkVSWV9TT1VSQ0VTIHx8ICdbXScpO1xuICAgIGlmKCFBcnJheS5pc0FycmF5KHBhcnNlZCkgfHwgcGFyc2VkLmxlbmd0aCA+IDEwMCB8fCBwYXJzZWQuc29tZSgodmFsdWUpID0+ICF2YWx1ZVxuXG4gICAgfHwgT2JqZWN0LmtleXModmFsdWUpLnNvcnQoKS5qb2luKCcsJykgIT09ICdhcHBJZCxjdXN0b21lcnNBY2Nlc3NBcHByb3ZlZCxleHBpcmVzQXQsaWQsb3JkZXJzQWNjZXNzQXBwcm92ZWQsb3JnYW5pemF0aW9uSWQscHJvamVjdElkLHNob3AsdG9rZW4nXG4gICAgICB8fCAhW3ZhbHVlLmlkLCB2YWx1ZS5hcHBJZCwgdmFsdWUub3JnYW5pemF0aW9uSWQsIHZhbHVlLnByb2plY3RJZF0uZXZlcnkoa2V5KVxuICAgICAgfHwgIS9eW2EtejAtOV1bYS16MC05LV17MCw2MX1cXC5teXNob3BpZnlcXC5jb20kLy50ZXN0KHZhbHVlLnNob3ApXG4gICAgICB8fCB0eXBlb2YgdmFsdWUudG9rZW4gIT09ICdzdHJpbmcnIHx8ICF2YWx1ZS50b2tlbi50cmltKCkgfHwgdmFsdWUudG9rZW4ubGVuZ3RoID4gODE5MlxuICAgICAgfHwgIU51bWJlci5pc1NhZmVJbnRlZ2VyKHZhbHVlLmV4cGlyZXNBdCkgfHwgdmFsdWUub3JkZXJzQWNjZXNzQXBwcm92ZWQgIT09IHRydWVcbiAgICAgIHx8IHZhbHVlLmN1c3RvbWVyc0FjY2Vzc0FwcHJvdmVkICE9PSB0cnVlKSB8fCBuZXcgU2V0KHBhcnNlZC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS5pZCkpLnNpemUgIT09IHBhcnNlZC5sZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCcpO1xuICAgIH1cbiAgICByZXR1cm4gcGFyc2VkO1xuICB9IGNhdGNoe1xuICAgIHRocm93IG5ldyBFcnJvcignY3JtX2NoZWNrb3V0X3JlY292ZXJ5X2NvbmZpZ3VyYXRpb25faG9sZCcpO1xuICB9XG59O1xuY29uc3Qgc291cmNlRm9yID0gKGJpbmRpbmc6IFBpY2s8QmluZGluZywgJ2FwcElkJyB8ICdzb3VyY2VJZCcgfCAnb3JnYW5pemF0aW9uSWQnIHwgJ3Byb2plY3RJZCc+LCBhdDogbnVtYmVyKSA9PiB7XG4gIGNvbnN0IG1hdGNoZXMgPSBzb3VyY2VzKCkuZmlsdGVyKCh2YWx1ZSkgPT4gdmFsdWUuaWQgPT09IGJpbmRpbmcuc291cmNlSWRcbiAgICAmJiB2YWx1ZS5hcHBJZCA9PT0gYmluZGluZy5hcHBJZFxuICAgICYmIHZhbHVlLm9yZ2FuaXphdGlvbklkID09PSBiaW5kaW5nLm9yZ2FuaXphdGlvbklkICYmIHZhbHVlLnByb2plY3RJZCA9PT0gYmluZGluZy5wcm9qZWN0SWRcbiAgICAmJiB2YWx1ZS5leHBpcmVzQXQgPiBhdCk7XG4gIGlmKG1hdGNoZXMubGVuZ3RoICE9PSAxKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjcm1fY2hlY2tvdXRfcmVjb3Zlcnlfc291cmNlX2hvbGQnKTtcbiAgfVxuICByZXR1cm4gbWF0Y2hlc1swXSE7XG59O1xuY29uc3QgYm91bmRzID0gKGdyYW50OiBHcmFudCwgaW5wdXQ6IFBpY2s8QmluZGluZywgJ2FwcElkJyB8ICdvcmdhbml6YXRpb25JZCcgfCAncHJvamVjdElkJyB8ICdjYW1wYWlnbklkJyB8ICdzb3VyY2VJZCc+KSA9PiB7XG4gIGNvbnN0IHZhbHVlID0gZ3JhbnQucmVjb3ZlcnlCb3VuZHM7XG4gIGlmKCFncmFudC5zY29wZXMuaW5jbHVkZXMoJ2NybTpjaGVja291dF9yZWNvdmVyeScpIHx8ICFncmFudC5zY29wZXMuaW5jbHVkZXMoJ2NybTpvdXRyZWFjaCcpXG4gICAgfHwgIXZhbGlkQ3JtQ2hlY2tvdXRSZWNvdmVyeUJvdW5kcyh2YWx1ZSkgfHwgZ3JhbnQuYXBwSWQgIT09IGlucHV0LmFwcElkXG4gICAgfHwgdmFsdWUhLm9yZ2FuaXphdGlvbklkICE9PSBpbnB1dC5vcmdhbml6YXRpb25JZCB8fCB2YWx1ZSEucHJvamVjdElkICE9PSBpbnB1dC5wcm9qZWN0SWRcbiAgICB8fCAhdmFsdWUhLmNhbXBhaWduSWRzLmluY2x1ZGVzKGlucHV0LmNhbXBhaWduSWQpIHx8ICF2YWx1ZSEuc291cmNlSWRzLmluY2x1ZGVzKGlucHV0LnNvdXJjZUlkKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignY3JtX2NoZWNrb3V0X3JlY292ZXJ5X3Njb3BlX3JlcXVpcmVkJyk7XG4gIH1cbn07XG5jb25zdCByZWFkID0gYXN5bmMgKHNvdXJjZTogQ3JtQ2hlY2tvdXRSZWNvdmVyeVNvdXJjZSwgYmluZGluZzogQmluZGluZywgZW1haWw6IHN0cmluZywgYXQ6IG51bWJlciwgcmVxdWVzdCA9IHBvc3QpID0+IHtcbiAgY29uc3QgbnVtZXJpYyA9IC9eZ2lkOlxcL1xcL3Nob3BpZnlcXC9BYmFuZG9uZWRDaGVja291dFxcLyhcXGQrKSQvLmV4ZWMoYmluZGluZy5jaGVja291dElkKT8uWzFdO1xuICBpZighbnVtZXJpYyB8fCAhL15naWQ6XFwvXFwvc2hvcGlmeVxcL0N1c3RvbWVyXFwvXFxkKyQvLnRlc3QoYmluZGluZy5jdXN0b21lcklkKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignY3JtX2NoZWNrb3V0X3JlY292ZXJ5X2lkZW50aXR5X2hvbGQnKTtcbiAgfVxuICBsZXQgcmVzcG9uc2U6IHVua25vd247XG4gIHRyeSB7XG4gICAgcmVzcG9uc2UgPSBhd2FpdCByZXF1ZXN0KGBodHRwczovLyR7c291cmNlLnNob3B9L2FkbWluL2FwaS8yMDI2LTEwL2dyYXBocWwuanNvbmAsXG4gICAgICB7cXVlcnk6IENSTV9DSEVDS09VVF9SRUNPVkVSWV9RVUVSWSxcbiAgICAgICAgdmFyaWFibGVzOiB7cXVlcnk6IGBpZDoke251bWVyaWN9IHN0YXR1czpvcGVuIHJlY292ZXJ5X3N0YXRlOm5vdF9yZWNvdmVyZWQgZW1haWxfc3RhdGU6bm90X3NlbnRgfX0sXG4gICAgICB7Y2FjaGU6IGZhbHNlLCBoZWFkZXJzOiBuZXcgSGVhZGVycyh7J1gtU2hvcGlmeS1BY2Nlc3MtVG9rZW4nOiBzb3VyY2UudG9rZW59KSwgdGltZW91dDogNTAwMH0pO1xuICB9IGNhdGNoe1xuICAgIHRocm93IG5ldyBFcnJvcignY3JtX2NoZWNrb3V0X3JlY292ZXJ5X3Byb3ZpZGVyX2hvbGQnKTtcbiAgfVxuICBjb25zdCBwcm9vZiA9IGNybUNoZWNrb3V0UmVjb3ZlcnlQcm9vZihyZXNwb25zZSwgc291cmNlLCBiaW5kaW5nLmNoZWNrb3V0SWQsIGJpbmRpbmcuY3VzdG9tZXJJZCwgZW1haWwsIGF0KTtcbiAgaWYoIXByb29mKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjcm1fY2hlY2tvdXRfcmVjb3ZlcnlfY3VycmVudF9jaGVja291dF9ob2xkJyk7XG4gIH1cbiAgcmV0dXJuIHByb29mO1xufTtcbmNvbnN0IGxvYWQgPSBhc3luYyAoZGI6IERiLCBpZDogc3RyaW5nLCBxdWVyeSA9IGRiLnF1ZXJ5LmJpbmQoZGIpKSA9PiBxdWVyeShhcWxgXG4gIExFVCBiaW5kaW5nID0gRE9DVU1FTlQoJ2NybUNoZWNrb3V0UmVjb3ZlcnlCaW5kaW5ncycsICR7aWR9KVxuICBMRVQgYXNzb2NpYXRpb24gPSBiaW5kaW5nID8gRE9DVU1FTlQoJ2hhc0NybUNhbXBhaWduT3V0Y29tZScsIGJpbmRpbmcuYXNzb2NpYXRpb25JZCkgOiBudWxsXG4gIExFVCB1c2VyID0gYmluZGluZyA/IERPQ1VNRU5UKCd1c2VycycsIGJpbmRpbmcudXNlcklkKSA6IG51bGxcbiAgTEVUIG9yZ2FuaXphdGlvbiA9IGJpbmRpbmcgPyBET0NVTUVOVCgnZ3JvdXBzJywgYmluZGluZy5vcmdhbml6YXRpb25JZCkgOiBudWxsXG4gIFJFVFVSTiB7YXNzb2NpYXRpb24sIGJpbmRpbmcsIG9yZ2FuaXphdGlvbiwgdXNlcn1gKS50aGVuKChjdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpIGFzIFByb21pc2U8YW55PjtcbmNvbnN0IGVsaWdpYmxlID0gKHJvdzogYW55LCBhdDogbnVtYmVyKTogYm9vbGVhbiA9PiB7XG4gIGNvbnN0IHthc3NvY2lhdGlvbiwgYmluZGluZywgb3JnYW5pemF0aW9uLCB1c2VyfSA9IHJvdyB8fCB7fTtcbiAgY29uc3QgY29uc2VudCA9IHVzZXI/LmNoZWNrb3V0UmVjb3ZlcnlDb25zZW50O1xuICBjb25zdCBjdXN0b21lcklkID0gL15cXGQrJC8udGVzdCh1c2VyPy5zaG9waWZ5Q3VzdG9tZXJJZCB8fCAnJylcbiAgICA/IGBnaWQ6Ly9zaG9waWZ5L0N1c3RvbWVyLyR7dXNlci5zaG9waWZ5Q3VzdG9tZXJJZH1gIDogdXNlcj8uc2hvcGlmeUN1c3RvbWVySWQ7XG4gIHJldHVybiBCb29sZWFuKGJpbmRpbmcgJiYgdXNlciAmJiBvcmdhbml6YXRpb24gJiYgYXNzb2NpYXRpb24gJiYgYmluZGluZy5zdGF0dXMgPT09ICdhY3RpdmUnXG4gICAgJiYgTnVtYmVyLmlzU2FmZUludGVnZXIoYmluZGluZy5leHBpcmVzQXQpICYmIGJpbmRpbmcuZXhwaXJlc0F0ID4gYXQgJiYgdXNlci5kZWxldGVkICE9PSB0cnVlXG4gICAgJiYgdXNlci5hY3RpdmUgIT09IGZhbHNlICYmIHVzZXIuY3JtQW5hbHl0aWNzU3VwcHJlc3NlZCAhPT0gdHJ1ZVxuICAgICYmIHVzZXIubWFya2V0aW5nT3B0SW4gPT09IHRydWUgJiYgTnVtYmVyLmlzRmluaXRlKHVzZXIubWFya2V0aW5nT3B0SW5BdClcbiAgICAmJiB1c2VyLm1hcmtldGluZ09wdEluQXQgPD0gYXQgJiYgdXNlci5tYXJrZXRpbmdDb25zZW50U291cmNlXG4gICAgJiYgKHVzZXIubWFya2V0aW5nT3B0T3V0QXQgPT09IHVuZGVmaW5lZCB8fCAoTnVtYmVyLmlzRmluaXRlKHVzZXIubWFya2V0aW5nT3B0T3V0QXQpXG4gICAgICAmJiB1c2VyLm1hcmtldGluZ09wdE91dEF0IDwgdXNlci5tYXJrZXRpbmdPcHRJbkF0KSlcbiAgICAmJiB1c2VyLl9rZXkgPT09IGJpbmRpbmcudXNlcklkICYmIHVzZXIuX3JldiA9PT0gYmluZGluZy51c2VyUmV2aXNpb24gJiYgY3VzdG9tZXJJZCA9PT0gYmluZGluZy5jdXN0b21lcklkXG4gICAgJiYgY29uc2VudD8ucHVycG9zZSA9PT0gJ2NoZWNrb3V0X3JlY292ZXJ5JyAmJiBjb25zZW50LnNvdXJjZSA9PT0gJ2F1dGhlbnRpY2F0ZWRfY3VzdG9tZXInXG4gICAgJiYgY29uc2VudC5yZXZva2VkICE9PSB0cnVlICYmIE51bWJlci5pc1NhZmVJbnRlZ2VyKGNvbnNlbnQuYXQpICYmIGNvbnNlbnQuYXQgPD0gYXRcbiAgICAmJiBOdW1iZXIuaXNTYWZlSW50ZWdlcihjb25zZW50LmV4cGlyZXNBdCkgJiYgY29uc2VudC5leHBpcmVzQXQgPiBhdFxuICAgICYmIGNvbnNlbnQuZXhwaXJlc0F0ID09PSBiaW5kaW5nLmNvbnNlbnRFeHBpcmVzQXQgJiYgYXNzb2NpYXRpb24uc3RhdHVzID09PSAnYWN0aXZlJ1xuICAgICYmIGFzc29jaWF0aW9uLl9yZXYgPT09IGJpbmRpbmcuYXNzb2NpYXRpb25SZXZpc2lvbiAmJiBhc3NvY2lhdGlvbi5hcHBJZCA9PT0gYmluZGluZy5hcHBJZFxuICAgICYmIGFzc29jaWF0aW9uLnVzZXJJZCA9PT0gYmluZGluZy51c2VySWQgJiYgYXNzb2NpYXRpb24ub3JnYW5pemF0aW9uSWQgPT09IGJpbmRpbmcub3JnYW5pemF0aW9uSWRcbiAgICAmJiBhc3NvY2lhdGlvbi5wcm9qZWN0SWQgPT09IGJpbmRpbmcucHJvamVjdElkICYmIGFzc29jaWF0aW9uLmNhbXBhaWduSWQgPT09IGJpbmRpbmcuY2FtcGFpZ25JZFxuICAgICYmIGFzc29jaWF0aW9uLmNvbnNlbnQ/LnB1cnBvc2UgPT09ICdjYW1wYWlnbl9vdXRjb21lcycgJiYgYXNzb2NpYXRpb24uY29uc2VudC5leHBpcmVzQXQgPiBhdCk7XG59O1xuY29uc3QgY2FkZW5jZSA9IGFzeW5jIChcbiAgZGI6IERiLCBncmFudDogR3JhbnQsIGJpbmRpbmc6IEJpbmRpbmcsIGF0OiBudW1iZXIsIHF1ZXJ5ID0gZGIucXVlcnkuYmluZChkYiksIHJlY2VpcHRJZD86IHN0cmluZ1xuKSA9PiB7XG4gIGNvbnN0IGN1dG9mZiA9IGF0IC0gKGdyYW50LnJlY292ZXJ5Qm91bmRzIS5jb29sZG93bkhvdXJzICogMzYwMDAwMCk7XG4gIGNvbnN0IHJlY2VudCA9IGF3YWl0IHF1ZXJ5KGFxbGBGT1IgcmVjZWlwdCBJTiBjcm1FeGVjdXRpb25SZWNlaXB0c1xuICAgIEZJTFRFUiByZWNlaXB0LmFwcElkID09ICR7YmluZGluZy5hcHBJZH0gQU5EIHJlY2VpcHQudGFyZ2V0SWQgPT0gJHtiaW5kaW5nLnVzZXJJZH1cbiAgICAgIEFORCByZWNlaXB0LmtpbmQgPT0gJ2NybV9vdXRyZWFjaCcgQU5EIHJlY2VpcHQuaWQgIT0gJHtyZWNlaXB0SWQgfHwgJyd9XG4gICAgICBBTkQgKHJlY2VpcHQuc3RhdGUgSU4gWyd1bmtub3duJywgJ3N1Ym1pdHRpbmcnXSBPUiAocmVjZWlwdC5zdGF0ZSA9PSAnYXBwbGllZCdcbiAgICAgICAgQU5EICghSVNfTlVNQkVSKHJlY2VpcHQucHJvdmlkZXJBY2NlcHRlZEF0KSBPUiByZWNlaXB0LnByb3ZpZGVyQWNjZXB0ZWRBdCA+PSAke2N1dG9mZn0pKSlcbiAgICBMSU1JVCAxIFJFVFVSTiB0cnVlYCkudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpKTtcbiAgaWYocmVjZW50KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjcm1fY2hlY2tvdXRfcmVjb3ZlcnlfY2FkZW5jZV9ob2xkJyk7XG4gIH1cbn07XG5cbi8qKiBPbmx5IHRoZSBhdXRoZW50aWNhdGVkIGN1c3RvbWVyIGNhbiByZWNvcmQgdGhpcyBpbmRlcGVuZGVudCBwdXJwb3NlOyBhZG1pbmlzdHJhdG9ycyBjYW5ub3QgaW1wbHkgY29uc2VudC4gKi9cbmV4cG9ydCBjb25zdCByZWNvcmRDcm1DaGVja291dFJlY292ZXJ5Q29uc2VudCA9IGFzeW5jIChcbiAgY29udGV4dDogQXBpQ29udGV4dCwgaW5wdXQ6IHthcHBJZDogc3RyaW5nOyBjb25zZW50OiBib29sZWFuOyBleHBlY3RlZFVzZXJSZXZpc2lvbjogc3RyaW5nOyBleHBpcmVzQXQ6IG51bWJlcn0sXG4gIG5vdyA9IERhdGUubm93XG4pOiBQcm9taXNlPGJvb2xlYW4+ID0+IHtcbiAgaWYoIWlucHV0IHx8IE9iamVjdC5rZXlzKGlucHV0KS5zb3J0KCkuam9pbignLCcpICE9PSAnYXBwSWQsY29uc2VudCxleHBlY3RlZFVzZXJSZXZpc2lvbixleHBpcmVzQXQnXG4gICAgfHwgIWtleShpbnB1dC5hcHBJZCkgfHwgdHlwZW9mIGlucHV0LmNvbnNlbnQgIT09ICdib29sZWFuJyB8fCAha2V5KGlucHV0LmV4cGVjdGVkVXNlclJldmlzaW9uKVxuICAgIHx8ICFOdW1iZXIuaXNTYWZlSW50ZWdlcihpbnB1dC5leHBpcmVzQXQpIHx8IGlucHV0LmV4cGlyZXNBdCA8PSBub3coKSB8fCBpbnB1dC5leHBpcmVzQXQgPiBub3coKSArICgzMCAqIDg2NDAwMDAwKVxuICAgIHx8ICFrZXkoY29udGV4dC5zZXNzaW9uPy51c2VySWQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkX2NybV9jaGVja291dF9yZWNvdmVyeV9jb25zZW50Jyk7XG4gIH1cbiAgY29uc3Qgc2NvcGVkID0gYXdhaXQgc2NvcGVDb250ZXh0VG9BcHAoY29udGV4dCwgaW5wdXQuYXBwSWQpO1xuICBjb25zdCBzYXZlZCA9IGF3YWl0IHVzZURiKHNjb3BlZC5kYXRhYmFzZU5hbWUpLnF1ZXJ5KGFxbGBGT1IgdXNlciBJTiB1c2Vyc1xuICAgIEZJTFRFUiB1c2VyLl9rZXkgPT0gJHtjb250ZXh0LnNlc3Npb24udXNlcklkfSBBTkQgdXNlci5fcmV2ID09ICR7aW5wdXQuZXhwZWN0ZWRVc2VyUmV2aXNpb259IEFORCB1c2VyLmRlbGV0ZWQgIT0gdHJ1ZVxuICAgICAgQU5EICgkeyFpbnB1dC5jb25zZW50fSBPUiB1c2VyLmFjdGl2ZSAhPSBmYWxzZSlcbiAgICBVUERBVEUgdXNlciBXSVRIIHtjaGVja291dFJlY292ZXJ5Q29uc2VudDogJHt7YXQ6IG5vdygpLCBleHBpcmVzQXQ6IGlucHV0LmV4cGlyZXNBdCwgcHVycG9zZTogJ2NoZWNrb3V0X3JlY292ZXJ5JyxcbiAgICAgIHJldm9rZWQ6ICFpbnB1dC5jb25zZW50LCBzb3VyY2U6ICdhdXRoZW50aWNhdGVkX2N1c3RvbWVyJ319fSBJTiB1c2VycyBPUFRJT05TIHtpZ25vcmVSZXZzOiBmYWxzZX0gUkVUVVJOIHRydWVgKVxuICAgIC50aGVuKChjdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpO1xuICBpZighc2F2ZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2NybV9jaGVja291dF9yZWNvdmVyeV9jb25zZW50X3JldmlzaW9uX2NvbmZsaWN0Jyk7XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59O1xuXG4vKiogUmVnaXN0cmF0aW9uIGJpbmRzIHZlcmlmaWVkIGV4aXN0aW5nIHNvdXJjZSBpZGVudGl0aWVzOyBpdCBuZWl0aGVyIGdyYW50cyBjb25zZW50IG5vciBzZW5kcyBhIG1lc3NhZ2UuICovXG5leHBvcnQgY29uc3QgcmVnaXN0ZXJDcm1DaGVja291dFJlY292ZXJ5QmluZGluZyA9IGFzeW5jIChcbiAgY29udGV4dDogQXBpQ29udGV4dCwgaW5wdXQ6IHthcHBJZDogc3RyaW5nOyBhc3NvY2lhdGlvbklkOiBzdHJpbmc7IGNoZWNrb3V0SWQ6IHN0cmluZztcbiAgICBleHBlY3RlZEFzc29jaWF0aW9uUmV2aXNpb246IHN0cmluZzsgZXhwZWN0ZWRVc2VyUmV2aXNpb246IHN0cmluZzsgc291cmNlSWQ6IHN0cmluZzsgdXNlcklkOiBzdHJpbmc7fSxcbiAgbm93ID0gRGF0ZS5ub3csIHJlcXVlc3QgPSBwb3N0XG4pID0+IHtcbiAgcmVxdWlyZUNybUFkbWluaXN0cmF0b3IoY29udGV4dCk7XG4gIGlmKCFpbnB1dFxuICAgIHx8IE9iamVjdC5rZXlzKGlucHV0KS5zb3J0KCkuam9pbignLCcpICE9PSBbJ2FwcElkJywgJ2Fzc29jaWF0aW9uSWQnLCAnY2hlY2tvdXRJZCcsXG4gICAgICAnZXhwZWN0ZWRBc3NvY2lhdGlvblJldmlzaW9uJywgJ2V4cGVjdGVkVXNlclJldmlzaW9uJywgJ3NvdXJjZUlkJywgJ3VzZXJJZCddLmpvaW4oJywnKVxuICAgIHx8ICFbaW5wdXQuYXBwSWQsIGlucHV0LmFzc29jaWF0aW9uSWQsIGlucHV0LmV4cGVjdGVkQXNzb2NpYXRpb25SZXZpc2lvbiwgaW5wdXQuZXhwZWN0ZWRVc2VyUmV2aXNpb24sXG4gICAgICBpbnB1dC5zb3VyY2VJZCwgaW5wdXQudXNlcklkXS5ldmVyeShrZXkpIHx8ICEvXmdpZDpcXC9cXC9zaG9waWZ5XFwvQWJhbmRvbmVkQ2hlY2tvdXRcXC9cXGQrJC8udGVzdChpbnB1dC5jaGVja291dElkKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZF9jcm1fY2hlY2tvdXRfcmVjb3ZlcnlfYmluZGluZycpO1xuICB9XG4gIGNvbnN0IHNjb3BlZCA9IGF3YWl0IHNjb3BlQ29udGV4dFRvQXBwKGNvbnRleHQsIGlucHV0LmFwcElkKTtcbiAgY29uc3QgZGIgPSB1c2VEYihzY29wZWQuZGF0YWJhc2VOYW1lKTtcbiAgY29uc3Qgcm93ID0gYXdhaXQgZGIucXVlcnkoYXFsYFJFVFVSTiB7YXNzb2NpYXRpb246IERPQ1VNRU5UKCdoYXNDcm1DYW1wYWlnbk91dGNvbWUnLCAke2lucHV0LmFzc29jaWF0aW9uSWR9KSxcbiAgICB1c2VyOiBET0NVTUVOVCgndXNlcnMnLCAke2lucHV0LnVzZXJJZH0pfWApLnRoZW4oKGN1cnNvcikgPT4gY3Vyc29yLm5leHQoKSkgYXMgYW55O1xuICBjb25zdCB7YXNzb2NpYXRpb24sIHVzZXJ9ID0gcm93IHx8IHt9O1xuICBjb25zdCBjb25zZW50ID0gdXNlcj8uY2hlY2tvdXRSZWNvdmVyeUNvbnNlbnQ7XG4gIGNvbnN0IGN1c3RvbWVySWQgPSAvXlxcZCskLy50ZXN0KHVzZXI/LnNob3BpZnlDdXN0b21lcklkIHx8ICcnKVxuICAgID8gYGdpZDovL3Nob3BpZnkvQ3VzdG9tZXIvJHt1c2VyLnNob3BpZnlDdXN0b21lcklkfWAgOiB1c2VyPy5zaG9waWZ5Q3VzdG9tZXJJZDtcbiAgY29uc3QgYmluZGluZzogQmluZGluZyA9IHtfa2V5OiAnJywgX3JldjogJycsIGFwcElkOiBpbnB1dC5hcHBJZCwgYXNzb2NpYXRpb25JZDogaW5wdXQuYXNzb2NpYXRpb25JZCxcbiAgICBhc3NvY2lhdGlvblJldmlzaW9uOiBpbnB1dC5leHBlY3RlZEFzc29jaWF0aW9uUmV2aXNpb24sIGNhbXBhaWduSWQ6IGFzc29jaWF0aW9uPy5jYW1wYWlnbklkLFxuICAgIGNoZWNrb3V0SWQ6IGlucHV0LmNoZWNrb3V0SWQsIGNvbnNlbnRFeHBpcmVzQXQ6IGNvbnNlbnQ/LmV4cGlyZXNBdCwgY3VzdG9tZXJJZCxcbiAgICBleHBpcmVzQXQ6IE1hdGgubWluKGNvbnNlbnQ/LmV4cGlyZXNBdCwgYXNzb2NpYXRpb24/LmNvbnNlbnQ/LmV4cGlyZXNBdCksXG4gICAgb3JnYW5pemF0aW9uSWQ6IGFzc29jaWF0aW9uPy5vcmdhbml6YXRpb25JZCxcbiAgICBwcm9qZWN0SWQ6IGFzc29jaWF0aW9uPy5wcm9qZWN0SWQsIHNvdXJjZUhhc2g6ICcnLCBzb3VyY2VJZDogaW5wdXQuc291cmNlSWQsIHN0YXR1czogJ2FjdGl2ZScsXG4gICAgdXNlcklkOiBpbnB1dC51c2VySWQsIHVzZXJSZXZpc2lvbjogaW5wdXQuZXhwZWN0ZWRVc2VyUmV2aXNpb259O1xuICBjb25zdCBvcmdhbml6YXRpb24gPSBrZXkoYmluZGluZy5vcmdhbml6YXRpb25JZCkgPyBhd2FpdCBkYi5xdWVyeShhcWxgUkVUVVJOIERPQ1VNRU5UKCdncm91cHMnLCAke2JpbmRpbmcub3JnYW5pemF0aW9uSWR9KWApXG4gICAgLnRoZW4oKGN1cnNvcikgPT4gY3Vyc29yLm5leHQoKSkgOiB1bmRlZmluZWQ7XG4gIGlmKCFlbGlnaWJsZSh7YXNzb2NpYXRpb24sIGJpbmRpbmcsIG9yZ2FuaXphdGlvbiwgdXNlcn0sIG5vdygpKSB8fCAha2V5KGJpbmRpbmcuY2FtcGFpZ25JZCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2NybV9jaGVja291dF9yZWNvdmVyeV9jb25zZW50X29yX2lkZW50aXR5X2hvbGQnKTtcbiAgfVxuICBjb25zdCBzb3VyY2UgPSBzb3VyY2VGb3IoYmluZGluZywgbm93KCkpO1xuICBhd2FpdCByZWFkKHNvdXJjZSwgYmluZGluZywgdXNlci5lbWFpbCwgbm93KCksIHJlcXVlc3QpO1xuICBiaW5kaW5nLnNvdXJjZUhhc2ggPSBoYXNoKHNvdXJjZSk7XG4gIGJpbmRpbmcuX2tleSA9IGhhc2goW2JpbmRpbmcuYXBwSWQsIGJpbmRpbmcub3JnYW5pemF0aW9uSWQsIGJpbmRpbmcucHJvamVjdElkLCBiaW5kaW5nLmNhbXBhaWduSWQsXG4gICAgc291cmNlLnNob3AsIGJpbmRpbmcuY2hlY2tvdXRJZCwgYmluZGluZy5jdXN0b21lcklkXSk7XG4gIGNvbnN0IGN1cnJlbnQgPSBhd2FpdCBkYi5xdWVyeShhcWxgUkVUVVJOIHthc3NvY2lhdGlvbjogRE9DVU1FTlQoJ2hhc0NybUNhbXBhaWduT3V0Y29tZScsICR7aW5wdXQuYXNzb2NpYXRpb25JZH0pLFxuICAgIHVzZXI6IERPQ1VNRU5UKCd1c2VycycsICR7aW5wdXQudXNlcklkfSl9YCkudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpKSBhcyBhbnk7XG4gIGlmKGhhc2goc291cmNlRm9yKGJpbmRpbmcsIG5vdygpKSkgIT09IGJpbmRpbmcuc291cmNlSGFzaFxuICAgIHx8ICFlbGlnaWJsZSh7Li4uY3VycmVudCwgYmluZGluZywgb3JnYW5pemF0aW9ufSwgbm93KCkpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjcm1fY2hlY2tvdXRfcmVjb3ZlcnlfYXV0aG9yaXR5X2NoYW5nZWQnKTtcbiAgfVxuICBmb3IoY29uc3QgW25hbWUsIGVkZ2VdIG9mIFtbJ2NybUNoZWNrb3V0UmVjb3ZlcnlCaW5kaW5ncycsIGZhbHNlXSwgWydoYXNDcm1DaGVja291dFJlY292ZXJ5QmluZGluZycsIHRydWVdXSBhcyBjb25zdCkge1xuICAgIGF3YWl0IGVuc3VyZU93bmVyRXhlY3V0aW9uQ29sbGVjdGlvbihkYiwgbmFtZSwgZWRnZSk7XG4gIH1cbiAgZm9yKGNvbnN0IG5hbWUgb2YgWydjcm1DaGVja291dFJlY292ZXJ5QmluZGluZ3MnLCAnaGFzQ3JtQ2hlY2tvdXRSZWNvdmVyeUJpbmRpbmcnXSkge1xuICAgIGF3YWl0IGRiLmNvbGxlY3Rpb24obmFtZSkuZW5zdXJlSW5kZXgoe2V4cGlyZUFmdGVyOiAwLCBmaWVsZHM6IFsncmV0aXJlQXQnXSwgdHlwZTogJ3R0bCd9KTtcbiAgfVxuICBjb25zdCB7X3JldiwgLi4ucmVjb3JkfSA9IGJpbmRpbmc7XG4gIGNvbnN0IHN0b3JlZCA9IHsuLi5yZWNvcmQsIHJldGlyZUF0OiBNYXRoLmZsb29yKGJpbmRpbmcuZXhwaXJlc0F0IC8gMTAwMCl9O1xuICBhd2FpdCBkYi5xdWVyeShhcWxgVVBTRVJUIHtfa2V5OiAke2JpbmRpbmcuX2tleX19IElOU0VSVCAke3N0b3JlZH0gVVBEQVRFICR7c3RvcmVkfSBJTiBjcm1DaGVja291dFJlY292ZXJ5QmluZGluZ3NgKTtcbiAgYXdhaXQgZGIucXVlcnkoYXFsYFVQU0VSVCB7X2tleTogJHtiaW5kaW5nLl9rZXl9fSBJTlNFUlQgJHt7X2Zyb206IGB1c2Vycy8ke2JpbmRpbmcudXNlcklkfWAsIF9rZXk6IGJpbmRpbmcuX2tleSxcbiAgICBfdG86IGBjcm1DaGVja291dFJlY292ZXJ5QmluZGluZ3MvJHtiaW5kaW5nLl9rZXl9YCwgYXBwSWQ6IGJpbmRpbmcuYXBwSWQsIHByb2plY3RJZDogYmluZGluZy5wcm9qZWN0SWQsXG4gICAgcmV0aXJlQXQ6IHN0b3JlZC5yZXRpcmVBdH19XG4gICAgVVBEQVRFICR7e3JldGlyZUF0OiBzdG9yZWQucmV0aXJlQXR9fSBJTiBoYXNDcm1DaGVja291dFJlY292ZXJ5QmluZGluZ2ApO1xuICByZXR1cm4ge2lkOiBiaW5kaW5nLl9rZXksIHN0YXR1czogJ3JlZ2lzdGVyZWQnIGFzIGNvbnN0fTtcbn07XG5cbi8qKiBFdmVyeSByZXZpZXcgYW5kIGV4ZWN1dGlvbiByZXBlYXRzIHByb3RlY3RlZCBzb3VyY2UgYW5kIG5hdGl2ZSBpZGVudGl0eSBjaGVja3MuICovXG5leHBvcnQgY29uc3QgdmFsaWRhdGVDcm1DaGVja291dFJlY292ZXJ5Q2FuZGlkYXRlID0gYXN5bmMgKFxuICBkYjogRGIsIGdyYW50OiBHcmFudCwgdmFsdWU6IENybUNoZWNrb3V0UmVjb3ZlcnlCaW5kaW5nLCBub3cgPSBEYXRlLm5vdyxcbiAgcXVlcnkgPSBkYi5xdWVyeS5iaW5kKGRiKSwgcmVxdWVzdCA9IHBvc3QsIHJlY2VpcHRJZD86IHN0cmluZ1xuKTogUHJvbWlzZTxDYW5kaWRhdGUgJiB7dmVyaWZpZWRSZWNvdmVyeVVybD86IHN0cmluZ30+ID0+IHtcbiAgaWYoIXZhbHVlIHx8IE9iamVjdC5rZXlzKHZhbHVlKS5zb3J0KCkuam9pbignLCcpICE9PSAnY2FuZGlkYXRlSWQscmV2aXNpb24nXG4gICAgfHwgIS9eW2EtZjAtOV17NjR9JC8udGVzdCh2YWx1ZS5jYW5kaWRhdGVJZCkgfHwgIS9eW2EtZjAtOV17NjR9JC8udGVzdCh2YWx1ZS5yZXZpc2lvbikpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWRfY3JtX2NoZWNrb3V0X3JlY292ZXJ5X2NhbmRpZGF0ZScpO1xuICB9XG4gIGNvbnN0IGNhbmRpZGF0ZSA9IGF3YWl0IHF1ZXJ5KGFxbGBSRVRVUk4gRE9DVU1FTlQoJ2NybUNoZWNrb3V0UmVjb3ZlcnlDYW5kaWRhdGVzJywgJHt2YWx1ZS5jYW5kaWRhdGVJZH0pYClcbiAgICAudGhlbigoY3Vyc29yKSA9PiBjdXJzb3IubmV4dCgpKSBhcyBDYW5kaWRhdGUgfCB1bmRlZmluZWQ7XG4gIGlmKCFjYW5kaWRhdGUgfHwgY2FuZGlkYXRlLnJldmlzaW9uICE9PSB2YWx1ZS5yZXZpc2lvblxuICAgIHx8ICFOdW1iZXIuaXNGaW5pdGUoRGF0ZS5wYXJzZShjYW5kaWRhdGUuZXhwaXJlc0F0KSkgfHwgRGF0ZS5wYXJzZShjYW5kaWRhdGUuZXhwaXJlc0F0KSA8PSBub3coKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignY3JtX2NoZWNrb3V0X3JlY292ZXJ5X2NhbmRpZGF0ZV9ob2xkJyk7XG4gIH1cbiAgY29uc3Qgcm93ID0gYXdhaXQgbG9hZChkYiwgY2FuZGlkYXRlLmJpbmRpbmdJZCwgcXVlcnkpO1xuICBpZighZWxpZ2libGUocm93LCBub3coKSkgfHwgcm93LmJpbmRpbmcuX3JldiAhPT0gY2FuZGlkYXRlLmJpbmRpbmdSZXZpc2lvbikge1xuICAgIHRocm93IG5ldyBFcnJvcignY3JtX2NoZWNrb3V0X3JlY292ZXJ5X2lkZW50aXR5X2hvbGQnKTtcbiAgfVxuICBjb25zdCB7YmluZGluZ30gPSByb3c7XG4gIGJvdW5kcyhncmFudCwgYmluZGluZyk7XG4gIGNvbnN0IHNvdXJjZSA9IHNvdXJjZUZvcihiaW5kaW5nLCBub3coKSk7XG4gIGlmKGhhc2goc291cmNlKSAhPT0gYmluZGluZy5zb3VyY2VIYXNoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjcm1fY2hlY2tvdXRfcmVjb3Zlcnlfc291cmNlX2hvbGQnKTtcbiAgfVxuICBhd2FpdCBjYWRlbmNlKGRiLCBncmFudCwgYmluZGluZywgbm93KCksIHF1ZXJ5LCByZWNlaXB0SWQpO1xuICBjb25zdCBwcm9vZiA9IGF3YWl0IHJlYWQoc291cmNlLCBiaW5kaW5nLCBjYW5kaWRhdGUuZW1haWwsIG5vdygpLCByZXF1ZXN0KTtcbiAgY29uc3QgYWZ0ZXIgPSBhd2FpdCBsb2FkKGRiLCBjYW5kaWRhdGUuYmluZGluZ0lkLCBxdWVyeSk7XG4gIGlmKHByb29mLnJldmlzaW9uICE9PSBjYW5kaWRhdGUucHJvb2ZSZXZpc2lvbiB8fCBoYXNoKHNvdXJjZUZvcihiaW5kaW5nLCBub3coKSkpICE9PSBiaW5kaW5nLnNvdXJjZUhhc2hcbiAgICB8fCAhZWxpZ2libGUoYWZ0ZXIsIG5vdygpKSB8fCBhZnRlci5iaW5kaW5nLl9yZXYgIT09IGNhbmRpZGF0ZS5iaW5kaW5nUmV2aXNpb24pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2NybV9jaGVja291dF9yZWNvdmVyeV9hdXRob3JpdHlfY2hhbmdlZCcpO1xuICB9XG4gIHJldHVybiB7Li4uY2FuZGlkYXRlLCB2ZXJpZmllZFJlY292ZXJ5VXJsOiBwcm9vZi5yZWNvdmVyeUxpbmtIYXNoID09PSBjYW5kaWRhdGUucmVjb3ZlcnlMaW5rSGFzaFxuICAgID8gcHJvb2YucmVjb3ZlcnlVcmwgOiB1bmRlZmluZWR9O1xufTtcblxuZXhwb3J0IGNvbnN0IGdlbmVyYXRlQ3JtQ2hlY2tvdXRSZWNvdmVyeUNhbmRpZGF0ZXMgPSBhc3luYyAoXG4gIGNvbnRleHQ6IEFwaUNvbnRleHQsIGlucHV0OiB7YXBwSWQ6IHN0cmluZzsgY2FtcGFpZ25JZDogc3RyaW5nOyBsaW1pdDogbnVtYmVyO1xuICAgIG9yZ2FuaXphdGlvbklkOiBzdHJpbmc7IHByb2plY3RJZDogc3RyaW5nOyBzb3VyY2VJZDogc3RyaW5nO30sIG5vdyA9IERhdGUubm93LCByZXF1ZXN0ID0gcG9zdFxuKSA9PiB7XG4gIGlmKCFpbnB1dCB8fCBPYmplY3Qua2V5cyhpbnB1dCkuc29ydCgpLmpvaW4oJywnKSAhPT0gJ2FwcElkLGNhbXBhaWduSWQsbGltaXQsb3JnYW5pemF0aW9uSWQscHJvamVjdElkLHNvdXJjZUlkJ1xuICAgIHx8ICFbaW5wdXQuYXBwSWQsIGlucHV0LmNhbXBhaWduSWQsIGlucHV0Lm9yZ2FuaXphdGlvbklkLCBpbnB1dC5wcm9qZWN0SWQsIGlucHV0LnNvdXJjZUlkXS5ldmVyeShrZXkpXG4gICAgfHwgIU51bWJlci5pc1NhZmVJbnRlZ2VyKGlucHV0LmxpbWl0KSB8fCBpbnB1dC5saW1pdCA8IDEgfHwgaW5wdXQubGltaXQgPiAyNSkge1xuICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZF9jcm1fY2hlY2tvdXRfcmVjb3ZlcnlfcmVxdWVzdCcpO1xuICB9XG4gIGNvbnN0IGdyYW50ID0gYXdhaXQgYXV0aG9yaXplQ3JtRXhlY3V0aW9uR3JhbnQoY29udGV4dCwgaW5wdXQuYXBwSWQsICdjcm06Y2hlY2tvdXRfcmVjb3ZlcnknLCBub3coKSk7XG4gIGJvdW5kcyhncmFudCwgaW5wdXQpO1xuICBjb25zdCBkYiA9IHVzZURiKGdyYW50LmRhdGFiYXNlTmFtZSk7XG4gIGZvcihjb25zdCBbbmFtZSwgZWRnZV0gb2YgW1snY3JtQ2hlY2tvdXRSZWNvdmVyeUNhbmRpZGF0ZXMnLCBmYWxzZV0sIFsnaGFzQ3JtQ2hlY2tvdXRSZWNvdmVyeUNhbmRpZGF0ZScsIHRydWVdLFxuICAgIFsnaGFzQ3JtQ2hlY2tvdXRSZWNvdmVyeUV4ZWN1dGlvbicsIHRydWVdLCBbJ2NybUV4ZWN1dGlvblJlY2VpcHRzJywgZmFsc2VdXSBhcyBjb25zdCkge1xuICAgIGF3YWl0IGVuc3VyZU93bmVyRXhlY3V0aW9uQ29sbGVjdGlvbihkYiwgbmFtZSwgZWRnZSk7XG4gIH1cbiAgZm9yKGNvbnN0IG5hbWUgb2YgWydjcm1DaGVja291dFJlY292ZXJ5Q2FuZGlkYXRlcycsICdoYXNDcm1DaGVja291dFJlY292ZXJ5Q2FuZGlkYXRlJ10pIHtcbiAgICBhd2FpdCBkYi5jb2xsZWN0aW9uKG5hbWUpLmVuc3VyZUluZGV4KHtleHBpcmVBZnRlcjogMCwgZmllbGRzOiBbJ2V4cGlyZXNBdCddLCB0eXBlOiAndHRsJ30pO1xuICB9XG4gIGNvbnN0IHJvd3MgPSBhd2FpdCBkYi5jb2xsZWN0aW9uKCdjcm1DaGVja291dFJlY292ZXJ5QmluZGluZ3MnKS5leGlzdHMoKSA/IGF3YWl0IGRiLnF1ZXJ5KGFxbGBcbiAgICBGT1IgYmluZGluZyBJTiBjcm1DaGVja291dFJlY292ZXJ5QmluZGluZ3NcbiAgICAgIEZJTFRFUiBiaW5kaW5nLmFwcElkID09ICR7aW5wdXQuYXBwSWR9IEFORCBiaW5kaW5nLnByb2plY3RJZCA9PSAke2lucHV0LnByb2plY3RJZH1cbiAgICAgICAgQU5EIGJpbmRpbmcub3JnYW5pemF0aW9uSWQgPT0gJHtpbnB1dC5vcmdhbml6YXRpb25JZH0gQU5EIGJpbmRpbmcuY2FtcGFpZ25JZCA9PSAke2lucHV0LmNhbXBhaWduSWR9XG4gICAgICAgIEFORCBiaW5kaW5nLnNvdXJjZUlkID09ICR7aW5wdXQuc291cmNlSWR9IEFORCBiaW5kaW5nLnN0YXR1cyA9PSAnYWN0aXZlJ1xuICAgICAgU09SVCBiaW5kaW5nLl9rZXkgTElNSVQgMTAxIFJFVFVSTiBiaW5kaW5nLl9rZXlgKS50aGVuKChjdXJzb3IpID0+IGN1cnNvci5hbGwoKSkgYXMgc3RyaW5nW10gOiBbXTtcbiAgY29uc3QgY2FuZGlkYXRlczogQ3JtQ2hlY2tvdXRSZWNvdmVyeUNhbmRpZGF0ZVtdID0gW107XG4gIGNvbnN0IGhlbGQ6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7Y2xhaW1lZDogMCwgaW5lbGlnaWJsZTogMH07XG4gIGNvbnN0IGRlYWRsaW5lID0gRGF0ZS5ub3coKSArIDgwMDA7XG4gIGxldCBidWRnZXRIZWxkID0gZmFsc2U7XG4gIGZvcihjb25zdCBpZCBvZiByb3dzLnNsaWNlKDAsIDEwMCkpIHtcbiAgICBpZihEYXRlLm5vdygpID49IGRlYWRsaW5lKSB7XG4gICAgICBidWRnZXRIZWxkID0gdHJ1ZTtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgY29uc3Qgcm93ID0gYXdhaXQgbG9hZChkYiwgaWQpO1xuICAgICAgaWYoIWVsaWdpYmxlKHJvdywgbm93KCkpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignY3JtX2NoZWNrb3V0X3JlY292ZXJ5X2lkZW50aXR5X2hvbGQnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHtiaW5kaW5nfSA9IHJvdztcbiAgICAgIGJvdW5kcyhncmFudCwgYmluZGluZyk7XG4gICAgICBjb25zdCBjbGFpbWVkID0gYXdhaXQgZGIucXVlcnkoYXFsYFJFVFVSTiBET0NVTUVOVCgnaGFzQ3JtQ2hlY2tvdXRSZWNvdmVyeUV4ZWN1dGlvbicsICR7aWR9KWApXG4gICAgICAgIC50aGVuKChjdXJzb3IpID0+IGN1cnNvci5uZXh0KCkpO1xuICAgICAgaWYoY2xhaW1lZCkge1xuICAgICAgICBoZWxkLmNsYWltZWQgKz0gMTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCBzb3VyY2UgPSBzb3VyY2VGb3IoYmluZGluZywgbm93KCkpO1xuICAgICAgaWYoaGFzaChzb3VyY2UpICE9PSBiaW5kaW5nLnNvdXJjZUhhc2gpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdjcm1fY2hlY2tvdXRfcmVjb3Zlcnlfc291cmNlX2hvbGQnKTtcbiAgICAgIH1cbiAgICAgIGF3YWl0IGNhZGVuY2UoZGIsIGdyYW50LCBiaW5kaW5nLCBub3coKSk7XG4gICAgICBjb25zdCB0YXJnZXQgPSBhd2FpdCByZWFkQ3JtRXhlY3V0aW9uVGFyZ2V0KGNvbnRleHQsIGlucHV0LmFwcElkLCAnY3JtX291dHJlYWNoJywgYmluZGluZy51c2VySWQsIG5vdyk7XG4gICAgICBjb25zdCBwcm9vZiA9IGF3YWl0IHJlYWQoc291cmNlLCBiaW5kaW5nLCB0YXJnZXQuZW1haWwsIG5vdygpLCByZXF1ZXN0KTtcbiAgICAgIGNvbnN0IGFmdGVyID0gYXdhaXQgbG9hZChkYiwgaWQpO1xuICAgICAgaWYoIWVsaWdpYmxlKGFmdGVyLCBub3coKSkgfHwgYmluZGluZy5fcmV2ICE9PSBhZnRlci5iaW5kaW5nLl9yZXZcbiAgICAgICAgfHwgaGFzaChzb3VyY2VGb3IoYmluZGluZywgbm93KCkpKSAhPT0gYmluZGluZy5zb3VyY2VIYXNoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignY3JtX2NoZWNrb3V0X3JlY292ZXJ5X2F1dGhvcml0eV9jaGFuZ2VkJyk7XG4gICAgICB9XG4gICAgICBjb25zdCBjYW5kaWRhdGU6IENhbmRpZGF0ZSA9IHtfa2V5OiBpZCwgYXBwSWQ6IGlucHV0LmFwcElkLCBiaW5kaW5nSWQ6IGlkLCBiaW5kaW5nUmV2aXNpb246IGJpbmRpbmcuX3JldixcbiAgICAgICAgY2FtcGFpZ25JZDogaW5wdXQuY2FtcGFpZ25JZCwgZW1haWw6IHRhcmdldC5lbWFpbCxcbiAgICAgICAgZXhwaXJlc0F0OiBuZXcgRGF0ZShNYXRoLm1pbihub3coKSArIDkwMDAwMCwgZ3JhbnQuZXhwaXJlcywgc291cmNlLmV4cGlyZXNBdCwgYmluZGluZy5leHBpcmVzQXQpKVxuICAgICAgICAgIC50b0lTT1N0cmluZygpLFxuICAgICAgICBpZCwgb2JzZXJ2ZWRBdDogcHJvb2YuY3JlYXRlZEF0LCBvcmdhbml6YXRpb25JZDogaW5wdXQub3JnYW5pemF0aW9uSWQsIHByb2plY3RJZDogaW5wdXQucHJvamVjdElkLFxuICAgICAgICBwcm9vZlJldmlzaW9uOiBwcm9vZi5yZXZpc2lvbiwgcmVhc29uOiAndmVyaWZpZWRfdW5yZWNvdmVyZWRfY2hlY2tvdXQnLCByZWNvdmVyeUxpbmtIYXNoOiBwcm9vZi5yZWNvdmVyeUxpbmtIYXNoLCByZXZpc2lvbjogJycsIHNvdXJjZUlkOiBpbnB1dC5zb3VyY2VJZCxcbiAgICAgICAgdGFyZ2V0SWQ6IHRhcmdldC5pZCwgdGFyZ2V0UmV2aXNpb246IHRhcmdldC5yZXZpc2lvbn07XG4gICAgICBjYW5kaWRhdGUucmV2aXNpb24gPSBoYXNoKFtjYW5kaWRhdGUuYmluZGluZ1JldmlzaW9uLCBjYW5kaWRhdGUucHJvb2ZSZXZpc2lvbiwgY2FuZGlkYXRlLnRhcmdldFJldmlzaW9uXSk7XG4gICAgICBhd2FpdCBkYi5xdWVyeShhcWxgVVBTRVJUIHtfa2V5OiAke2lkfX0gSU5TRVJUICR7Y2FuZGlkYXRlfSBVUERBVEUgJHtjYW5kaWRhdGV9IElOIGNybUNoZWNrb3V0UmVjb3ZlcnlDYW5kaWRhdGVzYCk7XG4gICAgICBhd2FpdCBkYi5xdWVyeShhcWxgVVBTRVJUIHtfa2V5OiAke2lkfX0gSU5TRVJUICR7e19mcm9tOiBgY3JtQ2hlY2tvdXRSZWNvdmVyeUJpbmRpbmdzLyR7aWR9YCwgX2tleTogaWQsXG4gICAgICAgIF90bzogYGNybUNoZWNrb3V0UmVjb3ZlcnlDYW5kaWRhdGVzLyR7aWR9YCwgYXBwSWQ6IGlucHV0LmFwcElkLCBleHBpcmVzQXQ6IGNhbmRpZGF0ZS5leHBpcmVzQXR9fVxuICAgICAgICBVUERBVEUgJHt7ZXhwaXJlc0F0OiBjYW5kaWRhdGUuZXhwaXJlc0F0fX0gSU4gaGFzQ3JtQ2hlY2tvdXRSZWNvdmVyeUNhbmRpZGF0ZWApO1xuICAgICAgY29uc3Qge19rZXksIGJpbmRpbmdJZCwgYmluZGluZ1JldmlzaW9uLCBwcm9vZlJldmlzaW9uLCAuLi5yZXN1bHR9ID0gY2FuZGlkYXRlO1xuICAgICAgY2FuZGlkYXRlcy5wdXNoKHJlc3VsdCk7XG4gICAgICBpZihjYW5kaWRhdGVzLmxlbmd0aCA9PT0gaW5wdXQubGltaXQpIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgaWYoIShlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB8fCAoIWVycm9yLm1lc3NhZ2Uuc3RhcnRzV2l0aCgnY3JtX2NoZWNrb3V0X3JlY292ZXJ5XycpXG4gICAgICAgICYmICFlcnJvci5tZXNzYWdlLnN0YXJ0c1dpdGgoJ2NybV9yZWNpcGllbnRfJykpKSB7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuICAgICAgaGVsZC5pbmVsaWdpYmxlICs9IDE7XG4gICAgfVxuICB9XG4gIGNvbnN0IGN1cnJlbnQgPSBhd2FpdCBhdXRob3JpemVDcm1FeGVjdXRpb25HcmFudChjb250ZXh0LCBpbnB1dC5hcHBJZCwgJ2NybTpjaGVja291dF9yZWNvdmVyeScsIG5vdygpKTtcbiAgYm91bmRzKGN1cnJlbnQsIGlucHV0KTtcbiAgaWYoaGFzaChjdXJyZW50KSAhPT0gaGFzaChncmFudCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2NybV9jaGVja291dF9yZWNvdmVyeV9hdXRob3JpdHlfY2hhbmdlZCcpO1xuICB9XG4gIHJldHVybiB7YXBwSWQ6IGlucHV0LmFwcElkLCBjYW1wYWlnbklkOiBpbnB1dC5jYW1wYWlnbklkLCBjYW5kaWRhdGVzLCBnZW5lcmF0ZWRBdDogbmV3IERhdGUobm93KCkpLnRvSVNPU3RyaW5nKCksXG4gICAgaGVsZCxcbiAgICBvcmdhbml6YXRpb25JZDogaW5wdXQub3JnYW5pemF0aW9uSWQsIHByb2plY3RJZDogaW5wdXQucHJvamVjdElkLCBzY2hlbWFWZXJzaW9uOiAnY3JtX2NoZWNrb3V0X3JlY292ZXJ5X3YxJyxcbiAgICBzb3VyY2VJZDogaW5wdXQuc291cmNlSWQsIHRydW5jYXRlZDogYnVkZ2V0SGVsZCB8fCByb3dzLmxlbmd0aCA+IDEwMCB8fCBjYW5kaWRhdGVzLmxlbmd0aCA9PT0gaW5wdXQubGltaXR9O1xufTtcbiJdLCJuYW1lcyI6WyJwb3N0IiwiYXFsIiwic2NvcGVDb250ZXh0VG9BcHAiLCJ1c2VEYiIsInJlcXVpcmVDcm1BZG1pbmlzdHJhdG9yIiwiQ1JNX0NIRUNLT1VUX1JFQ09WRVJZX1FVRVJZIiwiY3JtQ2hlY2tvdXRSZWNvdmVyeVByb29mIiwiY3JtUmVjb3ZlcnlEaWdlc3QiLCJoYXNoIiwiY3JtUmVjb3ZlcnlJZGVudGlmaWVyIiwia2V5IiwidmFsaWRDcm1DaGVja291dFJlY292ZXJ5Qm91bmRzIiwiYXV0aG9yaXplQ3JtRXhlY3V0aW9uR3JhbnQiLCJlbnN1cmVPd25lckV4ZWN1dGlvbkNvbGxlY3Rpb24iLCJyZWFkQ3JtRXhlY3V0aW9uVGFyZ2V0Iiwic291cmNlcyIsInBhcnNlZCIsIkpTT04iLCJwYXJzZSIsInByb2Nlc3MiLCJlbnYiLCJDUk1fQ0hFQ0tPVVRfUkVDT1ZFUllfU09VUkNFUyIsIkFycmF5IiwiaXNBcnJheSIsImxlbmd0aCIsInNvbWUiLCJ2YWx1ZSIsIk9iamVjdCIsImtleXMiLCJzb3J0Iiwiam9pbiIsImlkIiwiYXBwSWQiLCJvcmdhbml6YXRpb25JZCIsInByb2plY3RJZCIsImV2ZXJ5IiwidGVzdCIsInNob3AiLCJ0b2tlbiIsInRyaW0iLCJOdW1iZXIiLCJpc1NhZmVJbnRlZ2VyIiwiZXhwaXJlc0F0Iiwib3JkZXJzQWNjZXNzQXBwcm92ZWQiLCJjdXN0b21lcnNBY2Nlc3NBcHByb3ZlZCIsIlNldCIsIm1hcCIsInNpemUiLCJFcnJvciIsInNvdXJjZUZvciIsImJpbmRpbmciLCJhdCIsIm1hdGNoZXMiLCJmaWx0ZXIiLCJzb3VyY2VJZCIsImJvdW5kcyIsImdyYW50IiwiaW5wdXQiLCJyZWNvdmVyeUJvdW5kcyIsInNjb3BlcyIsImluY2x1ZGVzIiwiY2FtcGFpZ25JZHMiLCJjYW1wYWlnbklkIiwic291cmNlSWRzIiwicmVhZCIsInNvdXJjZSIsImVtYWlsIiwicmVxdWVzdCIsIm51bWVyaWMiLCJleGVjIiwiY2hlY2tvdXRJZCIsImN1c3RvbWVySWQiLCJyZXNwb25zZSIsInF1ZXJ5IiwidmFyaWFibGVzIiwiY2FjaGUiLCJoZWFkZXJzIiwiSGVhZGVycyIsInRpbWVvdXQiLCJwcm9vZiIsImxvYWQiLCJkYiIsImJpbmQiLCJ0aGVuIiwiY3Vyc29yIiwibmV4dCIsImVsaWdpYmxlIiwicm93IiwiYXNzb2NpYXRpb24iLCJvcmdhbml6YXRpb24iLCJ1c2VyIiwiY29uc2VudCIsImNoZWNrb3V0UmVjb3ZlcnlDb25zZW50Iiwic2hvcGlmeUN1c3RvbWVySWQiLCJCb29sZWFuIiwic3RhdHVzIiwiZGVsZXRlZCIsImFjdGl2ZSIsImNybUFuYWx5dGljc1N1cHByZXNzZWQiLCJtYXJrZXRpbmdPcHRJbiIsImlzRmluaXRlIiwibWFya2V0aW5nT3B0SW5BdCIsIm1hcmtldGluZ0NvbnNlbnRTb3VyY2UiLCJtYXJrZXRpbmdPcHRPdXRBdCIsInVuZGVmaW5lZCIsIl9rZXkiLCJ1c2VySWQiLCJfcmV2IiwidXNlclJldmlzaW9uIiwicHVycG9zZSIsInJldm9rZWQiLCJjb25zZW50RXhwaXJlc0F0IiwiYXNzb2NpYXRpb25SZXZpc2lvbiIsImNhZGVuY2UiLCJyZWNlaXB0SWQiLCJjdXRvZmYiLCJjb29sZG93bkhvdXJzIiwicmVjZW50IiwicmVjb3JkQ3JtQ2hlY2tvdXRSZWNvdmVyeUNvbnNlbnQiLCJjb250ZXh0Iiwibm93IiwiRGF0ZSIsImV4cGVjdGVkVXNlclJldmlzaW9uIiwic2Vzc2lvbiIsInNjb3BlZCIsInNhdmVkIiwiZGF0YWJhc2VOYW1lIiwicmVnaXN0ZXJDcm1DaGVja291dFJlY292ZXJ5QmluZGluZyIsImFzc29jaWF0aW9uSWQiLCJleHBlY3RlZEFzc29jaWF0aW9uUmV2aXNpb24iLCJNYXRoIiwibWluIiwic291cmNlSGFzaCIsImN1cnJlbnQiLCJuYW1lIiwiZWRnZSIsImNvbGxlY3Rpb24iLCJlbnN1cmVJbmRleCIsImV4cGlyZUFmdGVyIiwiZmllbGRzIiwidHlwZSIsInJlY29yZCIsInN0b3JlZCIsInJldGlyZUF0IiwiZmxvb3IiLCJfZnJvbSIsIl90byIsInZhbGlkYXRlQ3JtQ2hlY2tvdXRSZWNvdmVyeUNhbmRpZGF0ZSIsImNhbmRpZGF0ZUlkIiwicmV2aXNpb24iLCJjYW5kaWRhdGUiLCJiaW5kaW5nSWQiLCJiaW5kaW5nUmV2aXNpb24iLCJhZnRlciIsInByb29mUmV2aXNpb24iLCJ2ZXJpZmllZFJlY292ZXJ5VXJsIiwicmVjb3ZlcnlMaW5rSGFzaCIsInJlY292ZXJ5VXJsIiwiZ2VuZXJhdGVDcm1DaGVja291dFJlY292ZXJ5Q2FuZGlkYXRlcyIsImxpbWl0Iiwicm93cyIsImV4aXN0cyIsImFsbCIsImNhbmRpZGF0ZXMiLCJoZWxkIiwiY2xhaW1lZCIsImluZWxpZ2libGUiLCJkZWFkbGluZSIsImJ1ZGdldEhlbGQiLCJzbGljZSIsInRhcmdldCIsImV4cGlyZXMiLCJ0b0lTT1N0cmluZyIsIm9ic2VydmVkQXQiLCJjcmVhdGVkQXQiLCJyZWFzb24iLCJ0YXJnZXRJZCIsInRhcmdldFJldmlzaW9uIiwicmVzdWx0IiwicHVzaCIsImVycm9yIiwibWVzc2FnZSIsInN0YXJ0c1dpdGgiLCJnZW5lcmF0ZWRBdCIsInNjaGVtYVZlcnNpb24iLCJ0cnVuY2F0ZWQiXSwibWFwcGluZ3MiOiJBQUFBLHdHQUF3RyxHQUN4RyxTQUFRQSxJQUFJLFFBQU8sb0JBQW9CO0FBQ3ZDLFNBQVFDLEdBQUcsUUFBTyxXQUFXO0FBRTdCLFNBQVFDLGlCQUFpQixRQUFPLHlCQUF5QjtBQUN6RCxTQUFRQyxLQUFLLFFBQU8sNEJBQTRCO0FBQ2hELFNBQVFDLHVCQUF1QixRQUFPLFdBQVc7QUFDakQsU0FBUUMsMkJBQTJCLEVBQUVDLHdCQUF3QixFQUFFQyxxQkFBcUJDLElBQUksRUFDdEZDLHlCQUF5QkMsR0FBRyxFQUFFQyw4QkFBOEIsUUFBTyxpQ0FBaUM7QUFDdEcsU0FBUUMsMEJBQTBCLEVBQUVDLDhCQUE4QixFQUFFQyxzQkFBc0IsUUFBTyxvQkFBb0I7QUFxQnJILE1BQU1DLFVBQVU7SUFDZCxJQUFJO1FBQ0YsTUFBTUMsU0FBU0MsS0FBS0MsS0FBSyxDQUFDQyxRQUFRQyxHQUFHLENBQUNDLDZCQUE2QixJQUFJO1FBQ3ZFLElBQUcsQ0FBQ0MsTUFBTUMsT0FBTyxDQUFDUCxXQUFXQSxPQUFPUSxNQUFNLEdBQUcsT0FBT1IsT0FBT1MsSUFBSSxDQUFDLENBQUNDLFFBQVUsQ0FBQ0EsU0FFekVDLE9BQU9DLElBQUksQ0FBQ0YsT0FBT0csSUFBSSxHQUFHQyxJQUFJLENBQUMsU0FBUyx5R0FDdEMsQ0FBQztnQkFBQ0osTUFBTUssRUFBRTtnQkFBRUwsTUFBTU0sS0FBSztnQkFBRU4sTUFBTU8sY0FBYztnQkFBRVAsTUFBTVEsU0FBUzthQUFDLENBQUNDLEtBQUssQ0FBQ3pCLFFBQ3RFLENBQUMsNENBQTRDMEIsSUFBSSxDQUFDVixNQUFNVyxJQUFJLEtBQzVELE9BQU9YLE1BQU1ZLEtBQUssS0FBSyxZQUFZLENBQUNa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
@@ -0,0 +1,38 @@
1
+ export interface CrmCheckoutRecoveryBounds {
2
+ campaignIds: string[];
3
+ cooldownHours: number;
4
+ organizationId: string;
5
+ projectId: string;
6
+ sourceIds: string[];
7
+ }
8
+ export interface CrmCheckoutRecoveryBinding {
9
+ candidateId: string;
10
+ revision: string;
11
+ }
12
+ export interface CrmCheckoutRecoverySource {
13
+ appId: string;
14
+ customersAccessApproved: boolean;
15
+ expiresAt: number;
16
+ id: string;
17
+ ordersAccessApproved: boolean;
18
+ organizationId: string;
19
+ projectId: string;
20
+ shop: string;
21
+ token: string;
22
+ }
23
+ export interface CrmCheckoutRecoveryProof {
24
+ checkoutId: string;
25
+ createdAt: string;
26
+ customerId: string;
27
+ email: string;
28
+ recoveryLinkHash?: string;
29
+ recoveryUrl?: string;
30
+ revision: string;
31
+ shopId: string;
32
+ }
33
+ export declare const crmRecoveryDigest: (value: unknown) => string;
34
+ export declare const crmRecoveryIdentifier: (value: unknown) => value is string;
35
+ export declare const validCrmCheckoutRecoveryBounds: (value: CrmCheckoutRecoveryBounds | undefined) => boolean;
36
+ export declare const CRM_CHECKOUT_RECOVERY_QUERY = "query CrmCheckoutRecovery($query: String!) {\n shop { id myshopifyDomain primaryDomain { host } }\n currentAppInstallation { accessScopes { handle } }\n abandonedCheckouts(first: 2, query: $query) {\n nodes { abandonedCheckoutUrl id createdAt updatedAt completedAt customer { id\n defaultEmailAddress { emailAddress marketingState marketingUpdatedAt validFormat } } }\n pageInfo { hasNextPage }\n }\n}";
37
+ /** Current filtered provider data proves one unresolved opportunity, never an inactivity inference. */
38
+ export declare const crmCheckoutRecoveryProof: (response: unknown, source: CrmCheckoutRecoverySource, checkoutId: string, customerId: string, email: string, at: number) => CrmCheckoutRecoveryProof | undefined;
@@ -0,0 +1,61 @@
1
+ import { createHash } from 'node:crypto';
2
+ export const crmRecoveryDigest = (value)=>createHash('sha256').update(JSON.stringify(value)).digest('hex');
3
+ export const crmRecoveryIdentifier = (value)=>typeof value === 'string' && /^[\w.-]{1,160}$/.test(value);
4
+ export const validCrmCheckoutRecoveryBounds = (value)=>Boolean(value && Object.keys(value).sort().join(',') === 'campaignIds,cooldownHours,organizationId,projectId,sourceIds' && crmRecoveryIdentifier(value.organizationId) && crmRecoveryIdentifier(value.projectId) && Number.isInteger(value.cooldownHours) && value.cooldownHours >= 24 && value.cooldownHours <= 720 && [
5
+ value.campaignIds,
6
+ value.sourceIds
7
+ ].every((items)=>Array.isArray(items) && items.length > 0 && items.length <= 100 && items.every(crmRecoveryIdentifier) && new Set(items).size === items.length));
8
+ export const CRM_CHECKOUT_RECOVERY_QUERY = `query CrmCheckoutRecovery($query: String!) {
9
+ shop { id myshopifyDomain primaryDomain { host } }
10
+ currentAppInstallation { accessScopes { handle } }
11
+ abandonedCheckouts(first: 2, query: $query) {
12
+ nodes { abandonedCheckoutUrl id createdAt updatedAt completedAt customer { id
13
+ defaultEmailAddress { emailAddress marketingState marketingUpdatedAt validFormat } } }
14
+ pageInfo { hasNextPage }
15
+ }
16
+ }`;
17
+ /** Current filtered provider data proves one unresolved opportunity, never an inactivity inference. */ export const crmCheckoutRecoveryProof = (response, source, checkoutId, customerId, email, at)=>{
18
+ const body = response;
19
+ const data = body?.data;
20
+ const row = data?.abandonedCheckouts?.nodes?.[0];
21
+ const address = row?.customer?.defaultEmailAddress;
22
+ const scopes = data?.currentAppInstallation?.accessScopes;
23
+ if (!body || body.errors?.length || !data || data.shop?.myshopifyDomain !== source.shop || !/^gid:\/\/shopify\/Shop\/\d+$/.test(data.shop?.id || '') || !Array.isArray(scopes) || ![
24
+ 'read_orders',
25
+ 'read_customers'
26
+ ].every((scope)=>scopes.some((value)=>value?.handle === scope)) || !Array.isArray(data.abandonedCheckouts?.nodes) || data.abandonedCheckouts.nodes.length !== 1 || data.abandonedCheckouts.pageInfo?.hasNextPage !== false || row.id !== checkoutId || row.completedAt !== null || row.customer?.id !== customerId || address?.emailAddress !== email || address.validFormat !== true || address.marketingState !== 'SUBSCRIBED' || !Number.isFinite(Date.parse(address.marketingUpdatedAt)) || Date.parse(address.marketingUpdatedAt) > at || !Number.isFinite(Date.parse(row.createdAt)) || !Number.isFinite(Date.parse(row.updatedAt)) || Date.parse(row.createdAt) > at || Date.parse(row.updatedAt) < Date.parse(row.createdAt) || Date.parse(row.updatedAt) > at) {
27
+ return undefined;
28
+ }
29
+ let recoveryUrl;
30
+ if (typeof row.abandonedCheckoutUrl === 'string' && row.abandonedCheckoutUrl.length <= 2048 && !/[\s\u0000-\u001f\u007f]/.test(row.abandonedCheckoutUrl)) {
31
+ try {
32
+ const url = new URL(row.abandonedCheckoutUrl);
33
+ const host = data.shop.primaryDomain?.host;
34
+ if (url.protocol === 'https:' && !url.username && !url.password && !url.hash && !url.port && [
35
+ source.shop,
36
+ host
37
+ ].includes(url.hostname) && url.pathname !== '/') {
38
+ recoveryUrl = row.abandonedCheckoutUrl;
39
+ }
40
+ } catch {
41
+ // Unsupported capability URLs cannot be included in a reviewed message.
42
+ }
43
+ }
44
+ return {
45
+ checkoutId,
46
+ createdAt: new Date(row.createdAt).toISOString(),
47
+ customerId,
48
+ email,
49
+ recoveryLinkHash: recoveryUrl ? crmRecoveryDigest(recoveryUrl) : undefined,
50
+ recoveryUrl,
51
+ revision: crmRecoveryDigest([
52
+ source,
53
+ row,
54
+ data.shop,
55
+ scopes
56
+ ]),
57
+ shopId: data.shop.id
58
+ };
59
+ };
60
+
61
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L3JlYWt0b3IvcGFja2FnZXMvcmVha3Rvci9zcmMvYWN0aW9ucy9jcm1DaGVja291dFJlY292ZXJ5UG9saWN5LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Y3JlYXRlSGFzaH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuXG5leHBvcnQgaW50ZXJmYWNlIENybUNoZWNrb3V0UmVjb3ZlcnlCb3VuZHMge1xuICBjYW1wYWlnbklkczogc3RyaW5nW107XG4gIGNvb2xkb3duSG91cnM6IG51bWJlcjtcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZztcbiAgcHJvamVjdElkOiBzdHJpbmc7XG4gIHNvdXJjZUlkczogc3RyaW5nW107XG59XG5leHBvcnQgaW50ZXJmYWNlIENybUNoZWNrb3V0UmVjb3ZlcnlCaW5kaW5nIHtjYW5kaWRhdGVJZDogc3RyaW5nOyByZXZpc2lvbjogc3RyaW5nfVxuZXhwb3J0IGludGVyZmFjZSBDcm1DaGVja291dFJlY292ZXJ5U291cmNlIHtcbiAgYXBwSWQ6IHN0cmluZztcbiAgY3VzdG9tZXJzQWNjZXNzQXBwcm92ZWQ6IGJvb2xlYW47XG4gIGV4cGlyZXNBdDogbnVtYmVyO1xuICBpZDogc3RyaW5nO1xuICBvcmRlcnNBY2Nlc3NBcHByb3ZlZDogYm9vbGVhbjtcbiAgb3JnYW5pemF0aW9uSWQ6IHN0cmluZztcbiAgcHJvamVjdElkOiBzdHJpbmc7XG4gIHNob3A6IHN0cmluZztcbiAgdG9rZW46IHN0cmluZztcbn1cbmV4cG9ydCBpbnRlcmZhY2UgQ3JtQ2hlY2tvdXRSZWNvdmVyeVByb29mIHtcbiAgY2hlY2tvdXRJZDogc3RyaW5nO1xuICBjcmVhdGVkQXQ6IHN0cmluZztcbiAgY3VzdG9tZXJJZDogc3RyaW5nO1xuICBlbWFpbDogc3RyaW5nO1xuICByZWNvdmVyeUxpbmtIYXNoPzogc3RyaW5nO1xuICByZWNvdmVyeVVybD86IHN0cmluZztcbiAgcmV2aXNpb246IHN0cmluZztcbiAgc2hvcElkOiBzdHJpbmc7XG59XG5leHBvcnQgY29uc3QgY3JtUmVjb3ZlcnlEaWdlc3QgPSAodmFsdWU6IHVua25vd24pOiBzdHJpbmcgPT4gY3JlYXRlSGFzaCgnc2hhMjU2JylcbiAgLnVwZGF0ZShKU09OLnN0cmluZ2lmeSh2YWx1ZSkpLmRpZ2VzdCgnaGV4Jyk7XG5leHBvcnQgY29uc3QgY3JtUmVjb3ZlcnlJZGVudGlmaWVyID0gKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgc3RyaW5nID0+IHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZydcbiAgJiYgL15bXFx3Li1dezEsMTYwfSQvLnRlc3QodmFsdWUpO1xuZXhwb3J0IGNvbnN0IHZhbGlkQ3JtQ2hlY2tvdXRSZWNvdmVyeUJvdW5kcyA9ICh2YWx1ZTogQ3JtQ2hlY2tvdXRSZWNvdmVyeUJvdW5kcyB8IHVuZGVmaW5lZCk6IGJvb2xlYW4gPT4gQm9vbGVhbih2YWx1ZVxuICAmJiBPYmplY3Qua2V5cyh2YWx1ZSkuc29ydCgpLmpvaW4oJywnKSA9PT0gJ2NhbXBhaWduSWRzLGNvb2xkb3duSG91cnMsb3JnYW5pemF0aW9uSWQscHJvamVjdElkLHNvdXJjZUlkcydcbiAgJiYgY3JtUmVjb3ZlcnlJZGVudGlmaWVyKHZhbHVlLm9yZ2FuaXphdGlvbklkKSAmJiBjcm1SZWNvdmVyeUlkZW50aWZpZXIodmFsdWUucHJvamVjdElkKVxuICAmJiBOdW1iZXIuaXNJbnRlZ2VyKHZhbHVlLmNvb2xkb3duSG91cnMpICYmIHZhbHVlLmNvb2xkb3duSG91cnMgPj0gMjQgJiYgdmFsdWUuY29vbGRvd25Ib3VycyA8PSA3MjBcbiAgJiYgW3ZhbHVlLmNhbXBhaWduSWRzLCB2YWx1ZS5zb3VyY2VJZHNdLmV2ZXJ5KChpdGVtcykgPT4gQXJyYXkuaXNBcnJheShpdGVtcylcbiAgICAmJiBpdGVtcy5sZW5ndGggPiAwICYmIGl0ZW1zLmxlbmd0aCA8PSAxMDBcbiAgICAmJiBpdGVtcy5ldmVyeShjcm1SZWNvdmVyeUlkZW50aWZpZXIpICYmIG5ldyBTZXQoaXRlbXMpLnNpemUgPT09IGl0ZW1zLmxlbmd0aCkpO1xuZXhwb3J0IGNvbnN0IENSTV9DSEVDS09VVF9SRUNPVkVSWV9RVUVSWSA9IGBxdWVyeSBDcm1DaGVja291dFJlY292ZXJ5KCRxdWVyeTogU3RyaW5nISkge1xuICBzaG9wIHsgaWQgbXlzaG9waWZ5RG9tYWluIHByaW1hcnlEb21haW4geyBob3N0IH0gfVxuICBjdXJyZW50QXBwSW5zdGFsbGF0aW9uIHsgYWNjZXNzU2NvcGVzIHsgaGFuZGxlIH0gfVxuICBhYmFuZG9uZWRDaGVja291dHMoZmlyc3Q6IDIsIHF1ZXJ5OiAkcXVlcnkpIHtcbiAgICBub2RlcyB7IGFiYW5kb25lZENoZWNrb3V0VXJsIGlkIGNyZWF0ZWRBdCB1cGRhdGVkQXQgY29tcGxldGVkQXQgY3VzdG9tZXIgeyBpZFxuICAgICAgZGVmYXVsdEVtYWlsQWRkcmVzcyB7IGVtYWlsQWRkcmVzcyBtYXJrZXRpbmdTdGF0ZSBtYXJrZXRpbmdVcGRhdGVkQXQgdmFsaWRGb3JtYXQgfSB9IH1cbiAgICBwYWdlSW5mbyB7IGhhc05leHRQYWdlIH1cbiAgfVxufWA7XG5cbi8qKiBDdXJyZW50IGZpbHRlcmVkIHByb3ZpZGVyIGRhdGEgcHJvdmVzIG9uZSB1bnJlc29sdmVkIG9wcG9ydHVuaXR5LCBuZXZlciBhbiBpbmFjdGl2aXR5IGluZmVyZW5jZS4gKi9cbmV4cG9ydCBjb25zdCBjcm1DaGVja291dFJlY292ZXJ5UHJvb2YgPSAoXG4gIHJlc3BvbnNlOiB1bmtub3duLCBzb3VyY2U6IENybUNoZWNrb3V0UmVjb3ZlcnlTb3VyY2UsIGNoZWNrb3V0SWQ6IHN0cmluZyxcbiAgY3VzdG9tZXJJZDogc3RyaW5nLCBlbWFpbDogc3RyaW5nLCBhdDogbnVtYmVyXG4pOiBDcm1DaGVja291dFJlY292ZXJ5UHJvb2YgfCB1bmRlZmluZWQgPT4ge1xuICBjb25zdCBib2R5ID0gcmVzcG9uc2UgYXMge2RhdGE/OiBhbnk7IGVycm9ycz86IHVua25vd25bXX07XG4gIGNvbnN0IGRhdGEgPSBib2R5Py5kYXRhO1xuICBjb25zdCByb3cgPSBkYXRhPy5hYmFuZG9uZWRDaGVja291dHM/Lm5vZGVzPy5bMF07XG4gIGNvbnN0IGFkZHJlc3MgPSByb3c/LmN1c3RvbWVyPy5kZWZhdWx0RW1haWxBZGRyZXNzO1xuICBjb25zdCBzY29wZXMgPSBkYXRhPy5jdXJyZW50QXBwSW5zdGFsbGF0aW9uPy5hY2Nlc3NTY29wZXM7XG4gIGlmKCFib2R5IHx8IGJvZHkuZXJyb3JzPy5sZW5ndGggfHwgIWRhdGEgfHwgZGF0YS5zaG9wPy5teXNob3BpZnlEb21haW4gIT09IHNvdXJjZS5zaG9wXG4gICAgfHwgIS9eZ2lkOlxcL1xcL3Nob3BpZnlcXC9TaG9wXFwvXFxkKyQvLnRlc3QoZGF0YS5zaG9wPy5pZCB8fCAnJykgfHwgIUFycmF5LmlzQXJyYXkoc2NvcGVzKVxuICAgIHx8ICFbJ3JlYWRfb3JkZXJzJywgJ3JlYWRfY3VzdG9tZXJzJ10uZXZlcnkoKHNjb3BlKSA9PiBzY29wZXMuc29tZSgodmFsdWUpID0+IHZhbHVlPy5oYW5kbGUgPT09IHNjb3BlKSlcbiAgICB8fCAhQXJyYXkuaXNBcnJheShkYXRhLmFiYW5kb25lZENoZWNrb3V0cz8ubm9kZXMpIHx8IGRhdGEuYWJhbmRvbmVkQ2hlY2tvdXRzLm5vZGVzLmxlbmd0aCAhPT0gMVxuICAgIHx8IGRhdGEuYWJhbmRvbmVkQ2hlY2tvdXRzLnBhZ2VJbmZvPy5oYXNOZXh0UGFnZSAhPT0gZmFsc2UgfHwgcm93LmlkICE9PSBjaGVja291dElkIHx8IHJvdy5jb21wbGV0ZWRBdCAhPT0gbnVsbFxuICAgIHx8IHJvdy5jdXN0b21lcj8uaWQgIT09IGN1c3RvbWVySWQgfHwgYWRkcmVzcz8uZW1haWxBZGRyZXNzICE9PSBlbWFpbCB8fCBhZGRyZXNzLnZhbGlkRm9ybWF0ICE9PSB0cnVlXG4gICAgfHwgYWRkcmVzcy5tYXJrZXRpbmdTdGF0ZSAhPT0gJ1NVQlNDUklCRUQnIHx8ICFOdW1iZXIuaXNGaW5pdGUoRGF0ZS5wYXJzZShhZGRyZXNzLm1hcmtldGluZ1VwZGF0ZWRBdCkpXG4gICAgfHwgRGF0ZS5wYXJzZShhZGRyZXNzLm1hcmtldGluZ1VwZGF0ZWRBdCkgPiBhdCB8fCAhTnVtYmVyLmlzRmluaXRlKERhdGUucGFyc2Uocm93LmNyZWF0ZWRBdCkpXG4gICAgfHwgIU51bWJlci5pc0Zpbml0ZShEYXRlLnBhcnNlKHJvdy51cGRhdGVkQXQpKSB8fCBEYXRlLnBhcnNlKHJvdy5jcmVhdGVkQXQpID4gYXRcbiAgICB8fCBEYXRlLnBhcnNlKHJvdy51cGRhdGVkQXQpIDwgRGF0ZS5wYXJzZShyb3cuY3JlYXRlZEF0KSB8fCBEYXRlLnBhcnNlKHJvdy51cGRhdGVkQXQpID4gYXQpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGxldCByZWNvdmVyeVVybDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBpZih0eXBlb2Ygcm93LmFiYW5kb25lZENoZWNrb3V0VXJsID09PSAnc3RyaW5nJyAmJiByb3cuYWJhbmRvbmVkQ2hlY2tvdXRVcmwubGVuZ3RoIDw9IDIwNDhcbiAgICAmJiAhL1tcXHNcXHUwMDAwLVxcdTAwMWZcXHUwMDdmXS8udGVzdChyb3cuYWJhbmRvbmVkQ2hlY2tvdXRVcmwpKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHVybCA9IG5ldyBVUkwocm93LmFiYW5kb25lZENoZWNrb3V0VXJsKTtcbiAgICAgIGNvbnN0IGhvc3QgPSBkYXRhLnNob3AucHJpbWFyeURvbWFpbj8uaG9zdDtcbiAgICAgIGlmKHVybC5wcm90b2NvbCA9PT0gJ2h0dHBzOicgJiYgIXVybC51c2VybmFtZSAmJiAhdXJsLnBhc3N3b3JkICYmICF1cmwuaGFzaCAmJiAhdXJsLnBvcnRcbiAgICAgICAgJiYgW3NvdXJjZS5zaG9wLCBob3N0XS5pbmNsdWRlcyh1cmwuaG9zdG5hbWUpICYmIHVybC5wYXRobmFtZSAhPT0gJy8nKSB7XG4gICAgICAgIHJlY292ZXJ5VXJsID0gcm93LmFiYW5kb25lZENoZWNrb3V0VXJsO1xuICAgICAgfVxuICAgIH0gY2F0Y2h7XG4gICAgICAvLyBVbnN1cHBvcnRlZCBjYXBhYmlsaXR5IFVSTHMgY2Fubm90IGJlIGluY2x1ZGVkIGluIGEgcmV2aWV3ZWQgbWVzc2FnZS5cbiAgICB9XG4gIH1cbiAgcmV0dXJuIHtjaGVja291dElkLCBjcmVhdGVkQXQ6IG5ldyBEYXRlKHJvdy5jcmVhdGVkQXQpLnRvSVNPU3RyaW5nKCksIGN1c3RvbWVySWQsIGVtYWlsLFxuICAgIHJlY292ZXJ5TGlua0hhc2g6IHJlY292ZXJ5VXJsID8gY3JtUmVjb3ZlcnlEaWdlc3QocmVjb3ZlcnlVcmwpIDogdW5kZWZpbmVkLCByZWNvdmVyeVVybCxcbiAgICByZXZpc2lvbjogY3JtUmVjb3ZlcnlEaWdlc3QoW3NvdXJjZSwgcm93LCBkYXRhLnNob3AsIHNjb3Blc10pLCBzaG9wSWQ6IGRhdGEuc2hvcC5pZH07XG59O1xuIl0sIm5hbWVzIjpbImNyZWF0ZUhhc2giLCJjcm1SZWNvdmVyeURpZ2VzdCIsInZhbHVlIiwidXBkYXRlIiwiSlNPTiIsInN0cmluZ2lmeSIsImRpZ2VzdCIsImNybVJlY292ZXJ5SWRlbnRpZmllciIsInRlc3QiLCJ2YWxpZENybUNoZWNrb3V0UmVjb3ZlcnlCb3VuZHMiLCJCb29sZWFuIiwiT2JqZWN0Iiwia2V5cyIsInNvcnQiLCJqb2luIiwib3JnYW5pemF0aW9uSWQiLCJwcm9qZWN0SWQiLCJOdW1iZXIiLCJpc0ludGVnZXIiLCJjb29sZG93bkhvdXJzIiwiY2FtcGFpZ25JZHMiLCJzb3VyY2VJZHMiLCJldmVyeSIsIml0ZW1zIiwiQXJyYXkiLCJpc0FycmF5IiwibGVuZ3RoIiwiU2V0Iiwic2l6ZSIsIkNSTV9DSEVDS09VVF9SRUNPVkVSWV9RVUVSWSIsImNybUNoZWNrb3V0UmVjb3ZlcnlQcm9vZiIsInJlc3BvbnNlIiwic291cmNlIiwiY2hlY2tvdXRJZCIsImN1c3RvbWVySWQiLCJlbWFpbCIsImF0IiwiYm9keSIsImRhdGEiLCJyb3ciLCJhYmFuZG9uZWRDaGVja291dHMiLCJub2RlcyIsImFkZHJlc3MiLCJjdXN0b21lciIsImRlZmF1bHRFbWFpbEFkZHJlc3MiLCJzY29wZXMiLCJjdXJyZW50QXBwSW5zdGFsbGF0aW9uIiwiYWNjZXNzU2NvcGVzIiwiZXJyb3JzIiwic2hvcCIsIm15c2hvcGlmeURvbWFpbiIsImlkIiwic2NvcGUiLCJzb21lIiwiaGFuZGxlIiwicGFnZUluZm8iLCJoYXNOZXh0UGFnZSIsImNvbXBsZXRlZEF0IiwiZW1haWxBZGRyZXNzIiwidmFsaWRGb3JtYXQiLCJtYXJrZXRpbmdTdGF0ZSIsImlzRmluaXRlIiwiRGF0ZSIsInBhcnNlIiwibWFya2V0aW5nVXBkYXRlZEF0IiwiY3JlYXRlZEF0IiwidXBkYXRlZEF0IiwidW5kZWZpbmVkIiwicmVjb3ZlcnlVcmwiLCJhYmFuZG9uZWRDaGVja291dFVybCIsInVybCIsIlVSTCIsImhvc3QiLCJwcmltYXJ5RG9tYWluIiwicHJvdG9jb2wiLCJ1c2VybmFtZSIsInBhc3N3b3JkIiwiaGFzaCIsInBvcnQiLCJpbmNsdWRlcyIsImhvc3RuYW1lIiwicGF0aG5hbWUiLCJ0b0lTT1N0cmluZyIsInJlY292ZXJ5TGlua0hhc2giLCJyZXZpc2lvbiIsInNob3BJZCJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBUUEsVUFBVSxRQUFPLGNBQWM7QUErQnZDLE9BQU8sTUFBTUMsb0JBQW9CLENBQUNDLFFBQTJCRixXQUFXLFVBQ3JFRyxNQUFNLENBQUNDLEtBQUtDLFNBQVMsQ0FBQ0gsUUFBUUksTUFBTSxDQUFDLE9BQU87QUFDL0MsT0FBTyxNQUFNQyx3QkFBd0IsQ0FBQ0wsUUFBb0MsT0FBT0EsVUFBVSxZQUN0RixrQkFBa0JNLElBQUksQ0FBQ04sT0FBTztBQUNuQyxPQUFPLE1BQU1PLGlDQUFpQyxDQUFDUCxRQUEwRFEsUUFBUVIsU0FDNUdTLE9BQU9DLElBQUksQ0FBQ1YsT0FBT1csSUFBSSxHQUFHQyxJQUFJLENBQUMsU0FBUyxrRUFDeENQLHNCQUFzQkwsTUFBTWEsY0FBYyxLQUFLUixzQkFBc0JMLE1BQU1jLFNBQVMsS0FDcEZDLE9BQU9DLFNBQVMsQ0FBQ2hCLE1B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