@burdenoff/microfe-channel 2026.1013.2 → 2026.1107.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 (161) hide show
  1. package/dist/channel/ChannelRoot.d.ts +0 -2
  2. package/dist/channel/ChannelRoot.js +9 -6
  3. package/dist/channel/ChannelRoot.js.map +1 -1
  4. package/dist/channel/ChannelRoutes.d.ts +1 -2
  5. package/dist/channel/ChannelRoutes.js +5 -6
  6. package/dist/channel/ChannelRoutes.js.map +1 -1
  7. package/dist/channel/components/AdapterCredentialsForm.d.ts +2 -4
  8. package/dist/channel/components/AdapterCredentialsForm.js +1 -2
  9. package/dist/channel/components/AdapterCredentialsForm.js.map +1 -1
  10. package/dist/channel/components/FeatureNotEnabled.d.ts +1 -2
  11. package/dist/channel/components/FeatureNotEnabled.js +1 -2
  12. package/dist/channel/components/FeatureNotEnabled.js.map +1 -1
  13. package/dist/channel/components/MarkdownEditor.d.ts +1 -2
  14. package/dist/channel/components/MarkdownEditor.js +2 -5
  15. package/dist/channel/components/MarkdownEditor.js.map +1 -1
  16. package/dist/channel/components/PermissionGuard.d.ts +0 -2
  17. package/dist/channel/components/PermissionGuard.js +1 -2
  18. package/dist/channel/components/PermissionGuard.js.map +1 -1
  19. package/dist/channel/config/adapterCredentials.d.ts +0 -2
  20. package/dist/channel/config/adapterCredentials.js +3 -7
  21. package/dist/channel/config/adapterCredentials.js.map +1 -1
  22. package/dist/channel/constants/permissions.d.ts +0 -1
  23. package/dist/channel/constants/permissions.js +1 -2
  24. package/dist/channel/constants/permissions.js.map +1 -1
  25. package/dist/channel/graphql/global-client.d.ts +0 -2
  26. package/dist/channel/graphql/global-client.js +5 -6
  27. package/dist/channel/graphql/global-client.js.map +1 -1
  28. package/dist/channel/hooks/useChannelOrgSettings.d.ts +0 -2
  29. package/dist/channel/hooks/useChannelOrgSettings.js +20 -21
  30. package/dist/channel/hooks/useChannelOrgSettings.js.map +1 -1
  31. package/dist/channel/hooks/useChannelSubscription.d.ts +0 -1
  32. package/dist/channel/hooks/useChannelSubscription.js +7 -12
  33. package/dist/channel/hooks/useChannelSubscription.js.map +1 -1
  34. package/dist/channel/hooks/useChannels.d.ts +20 -30
  35. package/dist/channel/hooks/useChannels.js +100 -101
  36. package/dist/channel/hooks/useChannels.js.map +1 -1
  37. package/dist/channel/hooks/useTr.d.ts +0 -1
  38. package/dist/channel/hooks/useTr.js +1 -2
  39. package/dist/channel/hooks/useTr.js.map +1 -1
  40. package/dist/channel/index.d.ts +0 -1
  41. package/dist/channel/index.js +3 -2
  42. package/dist/channel/modules/channels/hooks/useExport.d.ts +0 -2
  43. package/dist/channel/modules/channels/hooks/useExport.js +77 -80
  44. package/dist/channel/modules/channels/hooks/useExport.js.map +1 -1
  45. package/dist/channel/modules/channels/i18n.d.ts +0 -2
  46. package/dist/channel/modules/channels/i18n.js +1 -2
  47. package/dist/channel/modules/channels/i18n.js.map +1 -1
  48. package/dist/channel/modules/channels/pages/ChannelDashboardPage.d.ts +1 -2
  49. package/dist/channel/modules/channels/pages/ChannelDashboardPage.js +10 -11
  50. package/dist/channel/modules/channels/pages/ChannelDashboardPage.js.map +1 -1
  51. package/dist/channel/modules/channels/pages/ChannelDetailsPage.d.ts +1 -2
  52. package/dist/channel/modules/channels/pages/ChannelDetailsPage.js +400 -401
  53. package/dist/channel/modules/channels/pages/ChannelDetailsPage.js.map +1 -1
  54. package/dist/channel/modules/channels/pages/ChannelSettingsPage.d.ts +1 -2
  55. package/dist/channel/modules/channels/pages/ChannelSettingsPage.js +8 -7
  56. package/dist/channel/modules/channels/pages/ChannelSettingsPage.js.map +1 -1
  57. package/dist/channel/modules/channels/pages/ChannelUsersPage.d.ts +1 -2
  58. package/dist/channel/modules/channels/pages/ChannelUsersPage.js +5 -10
  59. package/dist/channel/modules/channels/pages/ChannelUsersPage.js.map +1 -1
  60. package/dist/channel/modules/channels/pages/ChannelsListPage.d.ts +1 -2
  61. package/dist/channel/modules/channels/pages/ChannelsListPage.js +287 -288
  62. package/dist/channel/modules/channels/pages/ChannelsListPage.js.map +1 -1
  63. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.d.ts +1 -2
  64. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js +11 -12
  65. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js.map +1 -1
  66. package/dist/channel/modules/channels/pages/ConnectionsListPage.d.ts +1 -2
  67. package/dist/channel/modules/channels/pages/ConnectionsListPage.js +1 -2
  68. package/dist/channel/modules/channels/pages/ConnectionsListPage.js.map +1 -1
  69. package/dist/channel/modules/channels/pages/CreateChannelPage.d.ts +1 -2
  70. package/dist/channel/modules/channels/pages/CreateChannelPage.js +4 -5
  71. package/dist/channel/modules/channels/pages/CreateChannelPage.js.map +1 -1
  72. package/dist/channel/modules/channels/pages/CreateConnectionPage.d.ts +1 -2
  73. package/dist/channel/modules/channels/pages/CreateConnectionPage.js +37 -38
  74. package/dist/channel/modules/channels/pages/CreateConnectionPage.js.map +1 -1
  75. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.d.ts +1 -2
  76. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js +7 -12
  77. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js.map +1 -1
  78. package/dist/channel/modules/channels/pages/EditChannelPage.d.ts +1 -2
  79. package/dist/channel/modules/channels/pages/EditChannelPage.js +105 -103
  80. package/dist/channel/modules/channels/pages/EditChannelPage.js.map +1 -1
  81. package/dist/channel/modules/channels/pages/EditConnectionPage.d.ts +1 -2
  82. package/dist/channel/modules/channels/pages/EditConnectionPage.js +22 -23
  83. package/dist/channel/modules/channels/pages/EditConnectionPage.js.map +1 -1
  84. package/dist/channel/modules/channels/pages/SendMessagePage.d.ts +1 -2
  85. package/dist/channel/modules/channels/pages/SendMessagePage.js +180 -187
  86. package/dist/channel/modules/channels/pages/SendMessagePage.js.map +1 -1
  87. package/dist/channel/modules/channels/pages/WebhookEventsPage.d.ts +1 -2
  88. package/dist/channel/modules/channels/pages/WebhookEventsPage.js +144 -149
  89. package/dist/channel/modules/channels/pages/WebhookEventsPage.js.map +1 -1
  90. package/dist/channel/pages/ChannelLandingPage.d.ts +1 -2
  91. package/dist/channel/pages/ChannelLandingPage.js +20 -21
  92. package/dist/channel/pages/ChannelLandingPage.js.map +1 -1
  93. package/dist/channel/providers/ChannelProvider.d.ts +0 -2
  94. package/dist/channel/providers/ChannelProvider.js +1 -2
  95. package/dist/channel/providers/ChannelProvider.js.map +1 -1
  96. package/dist/channel/types/index.d.ts +0 -2
  97. package/dist/channel/utils/shellBridge.d.ts +0 -1
  98. package/dist/channel/utils/shellBridge.js +1 -2
  99. package/dist/channel/utils/shellBridge.js.map +1 -1
  100. package/dist/dev/App.d.ts +1 -2
  101. package/dist/dev/main.d.ts +0 -2
  102. package/dist/generated/global-operations.d.ts +885 -336
  103. package/dist/generated/global-operations.js +2 -3
  104. package/dist/generated/global-operations.js.map +1 -1
  105. package/dist/generated/global-types.d.ts +2 -22
  106. package/dist/generated/global-types.js +1 -2
  107. package/dist/generated/global-types.js.map +1 -1
  108. package/dist/generated/wspace-operations.d.ts +4 -2
  109. package/dist/generated/wspace-types.d.ts +4 -24
  110. package/dist/index.d.ts +0 -1
  111. package/dist/node_modules/@apollo/client/errors/CombinedGraphQLErrors.js +1 -2
  112. package/dist/node_modules/@apollo/client/errors/CombinedGraphQLErrors.js.map +1 -1
  113. package/dist/node_modules/@apollo/client/errors/utils.js +1 -2
  114. package/dist/node_modules/@apollo/client/errors/utils.js.map +1 -1
  115. package/dist/translations/en.d.ts +0 -1
  116. package/dist/utils/nativeBridge.d.ts +0 -1
  117. package/dist/utils/nativeBridge.js +1 -2
  118. package/package.json +65 -43
  119. package/dist/channel/ChannelRoot.d.ts.map +0 -1
  120. package/dist/channel/ChannelRoutes.d.ts.map +0 -1
  121. package/dist/channel/components/AdapterCredentialsForm.d.ts.map +0 -1
  122. package/dist/channel/components/FeatureNotEnabled.d.ts.map +0 -1
  123. package/dist/channel/components/MarkdownEditor.d.ts.map +0 -1
  124. package/dist/channel/components/PermissionGuard.d.ts.map +0 -1
  125. package/dist/channel/config/adapterCredentials.d.ts.map +0 -1
  126. package/dist/channel/constants/permissions.d.ts.map +0 -1
  127. package/dist/channel/graphql/global-client.d.ts.map +0 -1
  128. package/dist/channel/hooks/useChannelOrgSettings.d.ts.map +0 -1
  129. package/dist/channel/hooks/useChannelSubscription.d.ts.map +0 -1
  130. package/dist/channel/hooks/useChannels.d.ts.map +0 -1
  131. package/dist/channel/hooks/useTr.d.ts.map +0 -1
  132. package/dist/channel/index.d.ts.map +0 -1
  133. package/dist/channel/modules/channels/hooks/useExport.d.ts.map +0 -1
  134. package/dist/channel/modules/channels/i18n.d.ts.map +0 -1
  135. package/dist/channel/modules/channels/pages/ChannelDashboardPage.d.ts.map +0 -1
  136. package/dist/channel/modules/channels/pages/ChannelDetailsPage.d.ts.map +0 -1
  137. package/dist/channel/modules/channels/pages/ChannelSettingsPage.d.ts.map +0 -1
  138. package/dist/channel/modules/channels/pages/ChannelUsersPage.d.ts.map +0 -1
  139. package/dist/channel/modules/channels/pages/ChannelsListPage.d.ts.map +0 -1
  140. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.d.ts.map +0 -1
  141. package/dist/channel/modules/channels/pages/ConnectionsListPage.d.ts.map +0 -1
  142. package/dist/channel/modules/channels/pages/CreateChannelPage.d.ts.map +0 -1
  143. package/dist/channel/modules/channels/pages/CreateConnectionPage.d.ts.map +0 -1
  144. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.d.ts.map +0 -1
  145. package/dist/channel/modules/channels/pages/EditChannelPage.d.ts.map +0 -1
  146. package/dist/channel/modules/channels/pages/EditConnectionPage.d.ts.map +0 -1
  147. package/dist/channel/modules/channels/pages/SendMessagePage.d.ts.map +0 -1
  148. package/dist/channel/modules/channels/pages/WebhookEventsPage.d.ts.map +0 -1
  149. package/dist/channel/pages/ChannelLandingPage.d.ts.map +0 -1
  150. package/dist/channel/providers/ChannelProvider.d.ts.map +0 -1
  151. package/dist/channel/types/index.d.ts.map +0 -1
  152. package/dist/channel/utils/shellBridge.d.ts.map +0 -1
  153. package/dist/dev/App.d.ts.map +0 -1
  154. package/dist/dev/main.d.ts.map +0 -1
  155. package/dist/generated/global-operations.d.ts.map +0 -1
  156. package/dist/generated/global-types.d.ts.map +0 -1
  157. package/dist/generated/wspace-operations.d.ts.map +0 -1
  158. package/dist/generated/wspace-types.d.ts.map +0 -1
  159. package/dist/index.d.ts.map +0 -1
  160. package/dist/translations/en.d.ts.map +0 -1
  161. package/dist/utils/nativeBridge.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"adapterCredentials.js","names":[],"sources":["../../../src/channel/config/adapterCredentials.ts"],"sourcesContent":["/**\n * Adapter Credential Configuration\n *\n * Defines the credential fields required by each adapter type.\n * Field names MUST match exactly what the backend adapters expect.\n *\n * Based on Novu's pattern: https://docs.novu.co/community/add-a-new-provider\n */\n\nimport type { AdapterType } from '../hooks/useChannels';\n\nexport interface CredentialField {\n key: string;\n displayName: string;\n description: string;\n type: 'text' | 'password' | 'textarea' | 'number' | 'boolean' | 'select';\n required: boolean;\n placeholder?: string;\n defaultValue?: string | number | boolean;\n options?: { value: string; label: string }[];\n validation?: {\n pattern?: string;\n minLength?: number;\n maxLength?: number;\n };\n}\n\nexport interface AdapterCredentialSchema {\n displayName: string;\n description: string;\n docUrl?: string;\n logoUrl?: string;\n credentials: CredentialField[];\n platformMetadata?: CredentialField[];\n}\n\n/**\n * Credential schemas for each adapter type.\n * Keys match the AdapterType enum values.\n */\nconst ADAPTER_CREDENTIALS: Partial<Record<AdapterType, AdapterCredentialSchema>> = {\n // ===================\n // SMS ADAPTERS\n // ===================\n TWILIO_SMS: {\n displayName: 'Twilio SMS',\n description: 'Send SMS via Twilio',\n docUrl: 'https://www.twilio.com/docs/sms',\n credentials: [\n {\n key: 'accountSid',\n displayName: 'Account SID',\n description: 'Your Twilio Account SID (starts with AC)',\n type: 'text',\n required: true,\n placeholder: 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n validation: { pattern: '^AC[a-zA-Z0-9]{32}$' },\n },\n {\n key: 'authToken',\n displayName: 'Auth Token',\n description: 'Your Twilio Auth Token',\n type: 'password',\n required: true,\n placeholder: 'Your auth token',\n },\n {\n key: 'fromNumber',\n displayName: 'From Phone Number',\n description: 'Sender phone number in E.164 format',\n type: 'text',\n required: true,\n placeholder: '+1234567890',\n validation: { pattern: '^\\\\+[1-9]\\\\d{1,14}$' },\n },\n ],\n platformMetadata: [\n {\n key: 'statusCallbackUrl',\n displayName: 'Status Callback URL',\n description: 'Webhook URL for delivery status updates (optional)',\n type: 'text',\n required: false,\n placeholder: 'https://your-domain.com/webhooks/twilio',\n },\n ],\n },\n\n AWS_SNS: {\n displayName: 'AWS SNS',\n description: 'Send SMS via Amazon Simple Notification Service',\n docUrl: 'https://docs.aws.amazon.com/sns/',\n credentials: [\n {\n key: 'accessKeyId',\n displayName: 'AWS Access Key ID',\n description: 'Your AWS access key ID',\n type: 'text',\n required: true,\n placeholder: 'AKIAIOSFODNN7EXAMPLE',\n },\n {\n key: 'secretAccessKey',\n displayName: 'AWS Secret Access Key',\n description: 'Your AWS secret access key',\n type: 'password',\n required: true,\n placeholder: 'Your secret access key',\n },\n {\n key: 'region',\n displayName: 'AWS Region',\n description: 'AWS region for SNS service',\n type: 'select',\n required: true,\n defaultValue: 'us-east-1',\n options: [\n { value: 'us-east-1', label: 'US East (N. Virginia)' },\n { value: 'us-east-2', label: 'US East (Ohio)' },\n { value: 'us-west-1', label: 'US West (N. California)' },\n { value: 'us-west-2', label: 'US West (Oregon)' },\n { value: 'ca-central-1', label: 'Canada (Central)' },\n { value: 'ca-west-1', label: 'Canada West (Calgary)' },\n { value: 'eu-west-1', label: 'Europe (Ireland)' },\n { value: 'eu-west-2', label: 'Europe (London)' },\n { value: 'eu-west-3', label: 'Europe (Paris)' },\n { value: 'eu-central-1', label: 'Europe (Frankfurt)' },\n { value: 'eu-central-2', label: 'Europe (Zurich)' },\n { value: 'eu-north-1', label: 'Europe (Stockholm)' },\n { value: 'eu-south-1', label: 'Europe (Milan)' },\n { value: 'eu-south-2', label: 'Europe (Spain)' },\n { value: 'ap-south-1', label: 'Asia Pacific (Mumbai)' },\n { value: 'ap-south-2', label: 'Asia Pacific (Hyderabad)' },\n { value: 'ap-southeast-1', label: 'Asia Pacific (Singapore)' },\n { value: 'ap-southeast-2', label: 'Asia Pacific (Sydney)' },\n { value: 'ap-southeast-3', label: 'Asia Pacific (Jakarta)' },\n { value: 'ap-southeast-4', label: 'Asia Pacific (Melbourne)' },\n { value: 'ap-northeast-1', label: 'Asia Pacific (Tokyo)' },\n { value: 'ap-northeast-2', label: 'Asia Pacific (Seoul)' },\n { value: 'ap-northeast-3', label: 'Asia Pacific (Osaka)' },\n { value: 'ap-east-1', label: 'Asia Pacific (Hong Kong)' },\n { value: 'sa-east-1', label: 'South America (São Paulo)' },\n { value: 'me-south-1', label: 'Middle East (Bahrain)' },\n { value: 'me-central-1', label: 'Middle East (UAE)' },\n { value: 'af-south-1', label: 'Africa (Cape Town)' },\n { value: 'il-central-1', label: 'Israel (Tel Aviv)' },\n ],\n },\n ],\n platformMetadata: [\n {\n key: 'senderId',\n displayName: 'Sender ID',\n description: 'Sender ID for supported regions (optional)',\n type: 'text',\n required: false,\n placeholder: 'YourBrand',\n },\n {\n key: 'messageType',\n displayName: 'Message Type',\n description: 'SMS message type',\n type: 'select',\n required: false,\n defaultValue: 'Transactional',\n options: [\n { value: 'Transactional', label: 'Transactional' },\n { value: 'Promotional', label: 'Promotional' },\n ],\n },\n ],\n },\n\n // ===================\n // EMAIL ADAPTERS\n // ===================\n SENDGRID: {\n displayName: 'SendGrid',\n description: 'Send emails via SendGrid',\n docUrl: 'https://docs.sendgrid.com/',\n credentials: [\n {\n key: 'apiKey',\n displayName: 'API Key',\n description: 'Your SendGrid API Key',\n type: 'password',\n required: true,\n placeholder: 'SG.xxxx...',\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Verified sender email address',\n type: 'text',\n required: true,\n placeholder: 'noreply@yourdomain.com',\n },\n {\n key: 'fromName',\n displayName: 'From Name',\n description: 'Sender display name',\n type: 'text',\n required: false,\n placeholder: 'Your Company',\n defaultValue: 'Notification',\n },\n ],\n },\n\n AWS_SES: {\n displayName: 'AWS SES',\n description: 'Send emails via Amazon Simple Email Service',\n docUrl: 'https://docs.aws.amazon.com/ses/',\n credentials: [\n {\n key: 'accessKeyId',\n displayName: 'AWS Access Key ID',\n description: 'Your AWS access key ID',\n type: 'text',\n required: true,\n placeholder: 'AKIAIOSFODNN7EXAMPLE',\n },\n {\n key: 'secretAccessKey',\n displayName: 'AWS Secret Access Key',\n description: 'Your AWS secret access key',\n type: 'password',\n required: true,\n placeholder: 'Your secret access key',\n },\n {\n key: 'region',\n displayName: 'AWS Region',\n description: 'AWS region for SES service',\n type: 'select',\n required: true,\n defaultValue: 'us-east-1',\n options: [\n { value: 'us-east-1', label: 'US East (N. Virginia)' },\n { value: 'us-east-2', label: 'US East (Ohio)' },\n { value: 'us-west-1', label: 'US West (N. California)' },\n { value: 'us-west-2', label: 'US West (Oregon)' },\n { value: 'ca-central-1', label: 'Canada (Central)' },\n { value: 'ca-west-1', label: 'Canada West (Calgary)' },\n { value: 'eu-west-1', label: 'Europe (Ireland)' },\n { value: 'eu-west-2', label: 'Europe (London)' },\n { value: 'eu-west-3', label: 'Europe (Paris)' },\n { value: 'eu-central-1', label: 'Europe (Frankfurt)' },\n { value: 'eu-central-2', label: 'Europe (Zurich)' },\n { value: 'eu-north-1', label: 'Europe (Stockholm)' },\n { value: 'eu-south-1', label: 'Europe (Milan)' },\n { value: 'eu-south-2', label: 'Europe (Spain)' },\n { value: 'ap-south-1', label: 'Asia Pacific (Mumbai)' },\n { value: 'ap-south-2', label: 'Asia Pacific (Hyderabad)' },\n { value: 'ap-southeast-1', label: 'Asia Pacific (Singapore)' },\n { value: 'ap-southeast-2', label: 'Asia Pacific (Sydney)' },\n { value: 'ap-southeast-3', label: 'Asia Pacific (Jakarta)' },\n { value: 'ap-southeast-4', label: 'Asia Pacific (Melbourne)' },\n { value: 'ap-northeast-1', label: 'Asia Pacific (Tokyo)' },\n { value: 'ap-northeast-2', label: 'Asia Pacific (Seoul)' },\n { value: 'ap-northeast-3', label: 'Asia Pacific (Osaka)' },\n { value: 'ap-east-1', label: 'Asia Pacific (Hong Kong)' },\n { value: 'sa-east-1', label: 'South America (São Paulo)' },\n { value: 'me-south-1', label: 'Middle East (Bahrain)' },\n { value: 'me-central-1', label: 'Middle East (UAE)' },\n { value: 'af-south-1', label: 'Africa (Cape Town)' },\n { value: 'il-central-1', label: 'Israel (Tel Aviv)' },\n ],\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Verified sender email address',\n type: 'text',\n required: false,\n placeholder: 'noreply@yourdomain.com',\n },\n ],\n platformMetadata: [\n {\n key: 'configurationSetName',\n displayName: 'Configuration Set',\n description: 'SES Configuration Set for tracking (optional)',\n type: 'text',\n required: false,\n placeholder: 'my-configuration-set',\n },\n ],\n },\n\n AZURE_ACS: {\n displayName: 'Azure Communication Services',\n description: 'Send emails via Azure Communication Services',\n docUrl: 'https://docs.microsoft.com/azure/communication-services/',\n credentials: [\n {\n key: 'connectionString',\n displayName: 'Connection String',\n description: 'Azure ACS connection string (endpoint=...;accesskey=...)',\n type: 'password',\n required: true,\n placeholder: 'endpoint=https://your-resource.communication.azure.com/;accesskey=...',\n },\n {\n key: 'senderAddress',\n displayName: 'Sender Email',\n description: 'Azure verified sender email address',\n type: 'text',\n required: true,\n placeholder: 'DoNotReply@your-domain.azurecomm.net',\n },\n ],\n },\n\n MAILGUN: {\n displayName: 'Mailgun',\n description: 'Send emails via Mailgun',\n docUrl: 'https://documentation.mailgun.com/',\n credentials: [\n {\n key: 'apiKey',\n displayName: 'API Key',\n description: 'Your Mailgun API Key',\n type: 'password',\n required: true,\n placeholder: 'key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n },\n {\n key: 'domain',\n displayName: 'Domain',\n description: 'Your Mailgun sending domain',\n type: 'text',\n required: true,\n placeholder: 'mg.yourdomain.com',\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Sender email address',\n type: 'text',\n required: true,\n placeholder: 'noreply@mg.yourdomain.com',\n },\n {\n key: 'fromName',\n displayName: 'From Name',\n description: 'Sender display name',\n type: 'text',\n required: false,\n placeholder: 'Your Company',\n },\n ],\n platformMetadata: [\n {\n key: 'region',\n displayName: 'Region',\n description: 'Mailgun region',\n type: 'select',\n required: false,\n defaultValue: 'us',\n options: [\n { value: 'us', label: 'US' },\n { value: 'eu', label: 'EU' },\n ],\n },\n ],\n },\n\n POSTMARK: {\n displayName: 'Postmark',\n description: 'Send emails via Postmark',\n docUrl: 'https://postmarkapp.com/developer',\n credentials: [\n {\n key: 'serverToken',\n displayName: 'Server API Token',\n description: 'Your Postmark Server API Token',\n type: 'password',\n required: true,\n placeholder: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Verified sender email address',\n type: 'text',\n required: true,\n placeholder: 'noreply@yourdomain.com',\n },\n {\n key: 'fromName',\n displayName: 'From Name',\n description: 'Sender display name',\n type: 'text',\n required: false,\n placeholder: 'Your Company',\n },\n ],\n },\n\n RESEND: {\n displayName: 'Resend',\n description: 'Send emails via Resend',\n docUrl: 'https://resend.com/docs',\n credentials: [\n {\n key: 'apiKey',\n displayName: 'API Key',\n description: 'Your Resend API Key',\n type: 'password',\n required: true,\n placeholder: 're_xxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Verified sender email address',\n type: 'text',\n required: true,\n placeholder: 'noreply@yourdomain.com',\n },\n {\n key: 'fromName',\n displayName: 'From Name',\n description: 'Sender display name',\n type: 'text',\n required: false,\n placeholder: 'Your Company',\n },\n ],\n },\n\n SMTP: {\n displayName: 'Custom SMTP',\n description: 'Send emails via custom SMTP server',\n credentials: [\n {\n key: 'host',\n displayName: 'SMTP Host',\n description: 'SMTP server hostname',\n type: 'text',\n required: true,\n placeholder: 'smtp.yourdomain.com',\n },\n {\n key: 'port',\n displayName: 'SMTP Port',\n description: 'SMTP server port (usually 587 for TLS, 465 for SSL)',\n type: 'number',\n required: true,\n defaultValue: 587,\n placeholder: '587',\n },\n {\n key: 'username',\n displayName: 'Username',\n description: 'SMTP authentication username',\n type: 'text',\n required: true,\n placeholder: 'your-username',\n },\n {\n key: 'password',\n displayName: 'Password',\n description: 'SMTP authentication password',\n type: 'password',\n required: true,\n placeholder: 'Your password',\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Sender email address',\n type: 'text',\n required: true,\n placeholder: 'noreply@yourdomain.com',\n },\n {\n key: 'fromName',\n displayName: 'From Name',\n description: 'Sender display name',\n type: 'text',\n required: false,\n placeholder: 'Your Company',\n },\n ],\n platformMetadata: [\n {\n key: 'secure',\n displayName: 'Use SSL/TLS',\n description: 'Use SSL/TLS encryption',\n type: 'boolean',\n required: false,\n defaultValue: true,\n },\n ],\n },\n\n // ===================\n // PUSH NOTIFICATION ADAPTERS\n // ===================\n FCM: {\n displayName: 'Firebase Cloud Messaging',\n description: 'Send push notifications via FCM',\n docUrl: 'https://firebase.google.com/docs/cloud-messaging',\n credentials: [\n {\n key: 'projectId',\n displayName: 'Firebase Project ID',\n description: 'Your Firebase project ID',\n type: 'text',\n required: true,\n placeholder: 'your-project-id',\n },\n {\n key: 'clientEmail',\n displayName: 'Service Account Email',\n description: 'Service account email from Firebase credentials JSON',\n type: 'text',\n required: true,\n placeholder: 'firebase-adminsdk-xxxxx@your-project.iam.gserviceaccount.com',\n },\n {\n key: 'privateKey',\n displayName: 'Private Key',\n description:\n 'Service account private key (PEM format, paste the entire key including BEGIN/END lines)',\n type: 'textarea',\n required: true,\n placeholder: 'Paste the full PEM private key from your service account JSON',\n },\n ],\n },\n\n APNS: {\n displayName: 'Apple Push Notification Service',\n description: 'Send push notifications to iOS devices via APNs',\n docUrl: 'https://developer.apple.com/documentation/usernotifications',\n credentials: [\n {\n key: 'teamId',\n displayName: 'Team ID',\n description: 'Your 10-character Apple Developer Team ID',\n type: 'text',\n required: true,\n placeholder: 'ABCDE12345',\n validation: { pattern: '^[A-Z0-9]{10}$' },\n },\n {\n key: 'keyId',\n displayName: 'Key ID',\n description: 'Your 10-character Key ID from Apple Developer Account',\n type: 'text',\n required: true,\n placeholder: 'ABC123DEFG',\n validation: { pattern: '^[A-Z0-9]{10}$' },\n },\n {\n key: 'privateKey',\n displayName: 'Private Key (.p8)',\n description: 'Content of your .p8 private key file',\n type: 'textarea',\n required: true,\n placeholder: '-----BEGIN PRIVATE KEY-----\\nYour .p8 key content\\n-----END PRIVATE KEY-----',\n },\n {\n key: 'bundleId',\n displayName: 'Bundle ID',\n description: \"Your app's Bundle Identifier\",\n type: 'text',\n required: true,\n placeholder: 'com.yourcompany.yourapp',\n },\n ],\n platformMetadata: [\n {\n key: 'production',\n displayName: 'Production Environment',\n description: 'Use production APNs server (uncheck for sandbox/development)',\n type: 'boolean',\n required: false,\n defaultValue: false,\n },\n ],\n },\n\n ONESIGNAL: {\n displayName: 'OneSignal',\n description: 'Send push notifications via OneSignal',\n docUrl: 'https://documentation.onesignal.com/',\n credentials: [\n {\n key: 'appId',\n displayName: 'App ID',\n description: 'Your OneSignal App ID',\n type: 'text',\n required: true,\n placeholder: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',\n },\n {\n key: 'apiKey',\n displayName: 'REST API Key',\n description: 'Your OneSignal REST API Key',\n type: 'password',\n required: true,\n placeholder: 'Your API key',\n },\n ],\n },\n\n EXPO: {\n displayName: 'Expo Push',\n description: 'Send push notifications via Expo',\n docUrl: 'https://docs.expo.dev/push-notifications/',\n credentials: [\n {\n key: 'accessToken',\n displayName: 'Access Token',\n description: 'Your Expo access token (optional for increased rate limits)',\n type: 'password',\n required: false,\n placeholder: 'Your Expo access token',\n },\n ],\n },\n\n // ===================\n // MESSAGING PLATFORM ADAPTERS\n // ===================\n SLACK_BOT: {\n displayName: 'Slack Bot',\n description: 'Send messages via Slack Bot',\n docUrl: 'https://api.slack.com/bot-users',\n credentials: [\n {\n key: 'botToken',\n displayName: 'Bot Token',\n description: 'Your Slack Bot User OAuth Token (xoxb-...)',\n type: 'password',\n required: true,\n placeholder: 'xoxb-xxxxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx',\n },\n ],\n platformMetadata: [\n {\n key: 'defaultChannel',\n displayName: 'Default Channel',\n description: 'Default channel ID for messages (optional)',\n type: 'text',\n required: false,\n placeholder: 'C0123456789',\n },\n ],\n },\n\n SLACK_WEBHOOK: {\n displayName: 'Slack Webhook',\n description: 'Send messages via Slack Incoming Webhook',\n docUrl: 'https://api.slack.com/messaging/webhooks',\n credentials: [\n {\n key: 'webhookUrl',\n displayName: 'Webhook URL',\n description: 'Your Slack Incoming Webhook URL',\n type: 'password',\n required: true,\n placeholder: 'Paste your Slack Incoming Webhook URL',\n },\n ],\n },\n\n TEAMS_WEBHOOK: {\n displayName: 'Microsoft Teams Webhook',\n description: 'Send messages via Teams Incoming Webhook',\n docUrl: 'https://docs.microsoft.com/microsoftteams/platform/webhooks-and-connectors/',\n credentials: [\n {\n key: 'webhookUrl',\n displayName: 'Webhook URL',\n description: 'Your Microsoft Teams Incoming Webhook URL',\n type: 'password',\n required: true,\n placeholder: 'https://outlook.office.com/webhook/...',\n },\n ],\n },\n\n DISCORD_BOT: {\n displayName: 'Discord Bot',\n description: 'Send messages via Discord Bot',\n docUrl: 'https://discord.com/developers/docs',\n credentials: [\n {\n key: 'botToken',\n displayName: 'Bot Token',\n description: 'Your Discord Bot Token',\n type: 'password',\n required: true,\n placeholder: 'Your Discord bot token',\n },\n ],\n platformMetadata: [\n {\n key: 'defaultChannelId',\n displayName: 'Default Channel ID',\n description: 'Default channel ID for messages (optional)',\n type: 'text',\n required: false,\n placeholder: '123456789012345678',\n },\n ],\n },\n\n DISCORD_WEBHOOK: {\n displayName: 'Discord Webhook',\n description: 'Send messages via Discord Webhook',\n docUrl: 'https://discord.com/developers/docs/resources/webhook',\n credentials: [\n {\n key: 'webhookUrl',\n displayName: 'Webhook URL',\n description: 'Your Discord Webhook URL',\n type: 'password',\n required: true,\n placeholder: 'https://discord.com/api/webhooks/...',\n },\n ],\n },\n\n WHATSAPP_CLOUD: {\n displayName: 'WhatsApp Cloud API',\n description: 'Send messages via WhatsApp Business Cloud API',\n docUrl: 'https://developers.facebook.com/docs/whatsapp/cloud-api',\n credentials: [\n {\n key: 'accessToken',\n displayName: 'Access Token',\n description: 'Your WhatsApp Business API Access Token',\n type: 'password',\n required: true,\n placeholder: 'Your access token',\n },\n {\n key: 'phoneNumberId',\n displayName: 'Phone Number ID',\n description: 'Your WhatsApp Business Phone Number ID',\n type: 'text',\n required: true,\n placeholder: '123456789012345',\n },\n {\n key: 'businessAccountId',\n displayName: 'Business Account ID',\n description: 'Your WhatsApp Business Account ID',\n type: 'text',\n required: true,\n placeholder: '123456789012345',\n },\n ],\n },\n\n WHATSAPP_TWILIO: {\n displayName: 'WhatsApp via Twilio',\n description: 'Send WhatsApp messages via Twilio',\n docUrl: 'https://www.twilio.com/docs/whatsapp',\n credentials: [\n {\n key: 'accountSid',\n displayName: 'Account SID',\n description: 'Your Twilio Account SID (starts with AC)',\n type: 'text',\n required: true,\n placeholder: 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n },\n {\n key: 'authToken',\n displayName: 'Auth Token',\n description: 'Your Twilio Auth Token',\n type: 'password',\n required: true,\n placeholder: 'Your auth token',\n },\n {\n key: 'fromNumber',\n displayName: 'WhatsApp Number',\n description: 'Twilio WhatsApp number (whatsapp:+1234567890)',\n type: 'text',\n required: true,\n placeholder: 'whatsapp:+1234567890',\n },\n ],\n },\n\n // ===================\n // WEBHOOK ADAPTERS\n // ===================\n WEBHOOK_HTTP: {\n displayName: 'HTTP Webhook',\n description: 'Send notifications via HTTP webhook',\n credentials: [\n {\n key: 'webhookUrl',\n displayName: 'Webhook URL',\n description: 'HTTP endpoint to receive notifications',\n type: 'text',\n required: true,\n placeholder: 'https://your-api.com/webhooks/notifications',\n },\n ],\n platformMetadata: [\n {\n key: 'method',\n displayName: 'HTTP Method',\n description: 'HTTP method for the request',\n type: 'select',\n required: false,\n defaultValue: 'POST',\n options: [\n { value: 'POST', label: 'POST' },\n { value: 'PUT', label: 'PUT' },\n ],\n },\n {\n key: 'headers',\n displayName: 'Custom Headers (JSON)',\n description: 'Additional HTTP headers as JSON object',\n type: 'textarea',\n required: false,\n placeholder: '{\"Authorization\": \"Bearer token\", \"X-Custom-Header\": \"value\"}',\n },\n {\n key: 'secret',\n displayName: 'Signing Secret',\n description: 'Secret for HMAC signature verification (optional)',\n type: 'password',\n required: false,\n placeholder: 'Your webhook signing secret',\n },\n ],\n },\n};\n\n/**\n * Get credential schema for an adapter type\n */\nexport function getAdapterCredentialSchema(\n adapterType: AdapterType | undefined\n): AdapterCredentialSchema | null {\n if (!adapterType) return null;\n return ADAPTER_CREDENTIALS[adapterType] || null;\n}\n\n/**\n * Module-level RegExp cache so validateCredentials() doesn't allocate inside its loop.\n */\nconst REGEX_CACHE = new Map<string, RegExp>();\nfunction getCachedRegex(pattern: string): RegExp {\n let r = REGEX_CACHE.get(pattern);\n if (!r) {\n r = new RegExp(pattern);\n REGEX_CACHE.set(pattern, r);\n }\n return r;\n}\n\n/**\n * Validate credentials against adapter schema\n */\nexport function validateCredentials(\n adapterType: AdapterType | undefined,\n credentials: Record<string, unknown>\n): { valid: boolean; errors: string[] } {\n const schema = getAdapterCredentialSchema(adapterType);\n if (!schema) {\n return { valid: false, errors: ['Unknown adapter type'] };\n }\n\n const errors: string[] = [];\n\n for (const field of schema.credentials) {\n const value = credentials[field.key];\n\n // Check required fields\n if (field.required && (value === undefined || value === null || value === '')) {\n errors.push(`${field.displayName} is required`);\n continue;\n }\n\n // Skip validation for empty optional fields\n if (!field.required && (value === undefined || value === null || value === '')) {\n continue;\n }\n\n // Validate pattern if specified\n if (field.validation?.pattern && typeof value === 'string') {\n const regex = getCachedRegex(field.validation.pattern);\n if (!regex.test(value)) {\n errors.push(`${field.displayName} has an invalid format`);\n }\n }\n\n // Validate min/max length\n if (typeof value === 'string') {\n const minLength = field.validation?.minLength;\n const maxLength = field.validation?.maxLength;\n if (minLength && value.length < minLength) {\n errors.push(`${field.displayName} must be at least ${minLength} characters`);\n }\n if (maxLength && value.length > maxLength) {\n errors.push(`${field.displayName} must be at most ${maxLength} characters`);\n }\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Get default values for an adapter's credentials\n */\nexport function getDefaultCredentials(\n adapterType: AdapterType | undefined\n): Record<string, unknown> {\n const schema = getAdapterCredentialSchema(adapterType);\n if (!schema) return {};\n\n const defaults: Record<string, unknown> = {};\n for (const field of [...schema.credentials, ...(schema.platformMetadata || [])]) {\n if (field.defaultValue !== undefined) {\n defaults[field.key] = field.defaultValue;\n }\n }\n return defaults;\n}\n"],"mappings":"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CR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,EACD;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACF;CAED,SAAS;EACP,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACF;EACD,kBAAkB,CAChB;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,cAAc;GACd,SAAS,CACP;IAAE,OAAO;IAAM,OAAO;IAAM,EAC5B;IAAE,OAAO;IAAM,OAAO;IAAM,CAC7B;GACF,CACF;EACF;CAED,UAAU;EACR,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACF;EACF;CAED,QAAQ;EACN,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACF;EACF;CAED,MAAM;EACJ,aAAa;EACb,aAAa;EACb,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,cAAc;IACd,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACF;EACD,kBAAkB,CAChB;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,cAAc;GACf,CACF;EACF;CAKD,KAAK;EACH,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aACE;IACF,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACF;EACF;CAED,MAAM;EACJ,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACb,YAAY,EAAE,SAAS,kBAAkB;IAC1C;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACb,YAAY,EAAE,SAAS,kBAAkB;IAC1C;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACF;EACD,kBAAkB,CAChB;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,cAAc;GACf,CACF;EACF;CAED,WAAW;EACT,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,EACD;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACF;CAED,MAAM;EACJ,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACF;CAKD,WAAW;EACT,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACD,kBAAkB,CAChB;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACF;CAED,eAAe;EACb,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACF;CAED,eAAe;EACb,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACF;CAED,aAAa;EACX,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACD,kBAAkB,CAChB;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACF;CAED,iBAAiB;EACf,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACF;CAED,gBAAgB;EACd,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACF;EACF;CAED,iBAAiB;EACf,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACF;EACF;CAKD,cAAc;EACZ,aAAa;EACb,aAAa;EACb,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;GACd,CACF;EACD,kBAAkB;GAChB;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,cAAc;IACd,SAAS,CACP;KAAE,OAAO;KAAQ,OAAO;KAAQ,EAChC;KAAE,OAAO;KAAO,OAAO;KAAO,CAC/B;IACF;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACD;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACd;GACF;EACF;CACF;AAKD,SAAgB,EACd,GACgC;AAEhC,QADK,KACE,EAAoB,MADF;;AAO3B,IAAM,oBAAc,IAAI,KAAqB;AAC7C,SAAS,EAAe,GAAyB;CAC/C,IAAI,IAAI,EAAY,IAAI,EAAQ;AAKhC,QAJK,MACH,IAAI,IAAI,OAAO,EAAQ,EACvB,EAAY,IAAI,GAAS,EAAE,GAEtB;;AAMT,SAAgB,EACd,GACA,GACsC;CACtC,IAAM,IAAS,EAA2B,EAAY;AACtD,KAAI,CAAC,EACH,QAAO;EAAE,OAAO;EAAO,QAAQ,CAAC,uBAAuB;EAAE;CAG3D,IAAM,IAAmB,EAAE;AAE3B,MAAK,IAAM,KAAS,EAAO,aAAa;EACtC,IAAM,IAAQ,EAAY,EAAM;AAGhC,MAAI,EAAM,aAAa,KAAiC,QAAQ,MAAU,KAAK;AAC7E,KAAO,KAAK,GAAG,EAAM,YAAY,cAAc;AAC/C;;AAIE,SAAC,EAAM,aAAa,KAAiC,QAAQ,MAAU,SAKvE,EAAM,YAAY,WAAW,OAAO,KAAU,aAClC,EAAe,EAAM,WAAW,QAAQ,CAC3C,KAAK,EAAM,IACpB,EAAO,KAAK,GAAG,EAAM,YAAY,wBAAwB,GAKzD,OAAO,KAAU,WAAU;GAC7B,IAAM,IAAY,EAAM,YAAY,WAC9B,IAAY,EAAM,YAAY;AAIpC,GAHI,KAAa,EAAM,SAAS,KAC9B,EAAO,KAAK,GAAG,EAAM,YAAY,oBAAoB,EAAU,aAAa,EAE1E,KAAa,EAAM,SAAS,KAC9B,EAAO,KAAK,GAAG,EAAM,YAAY,mBAAmB,EAAU,aAAa;;;AAKjF,QAAO;EAAE,OAAO,EAAO,WAAW;EAAG;EAAQ;;AAM/C,SAAgB,EACd,GACyB;CACzB,IAAM,IAAS,EAA2B,EAAY;AACtD,KAAI,CAAC,EAAQ,QAAO,EAAE;CAEtB,IAAM,IAAoC,EAAE;AAC5C,MAAK,IAAM,KAAS,CAAC,GAAG,EAAO,aAAa,GAAI,EAAO,oBAAoB,EAAE,CAAE,CAC7E,CAAI,EAAM,iBAAiB,KAAA,MACzB,EAAS,EAAM,OAAO,EAAM;AAGhC,QAAO"}
1
+ {"version":3,"file":"adapterCredentials.js","names":["ADAPTER_CREDENTIALS","getAdapterCredentialSchema","adapterType","REGEX_CACHE","getCachedRegex","r","pattern","validateCredentials","schema","errors","field","value","credentials","minLength","maxLength","getDefaultCredentials","defaults"],"sources":["../../../src/channel/config/adapterCredentials.ts"],"sourcesContent":["/**\n * Adapter Credential Configuration\n *\n * Defines the credential fields required by each adapter type.\n * Field names MUST match exactly what the backend adapters expect.\n *\n * Based on Novu's pattern: https://docs.novu.co/community/add-a-new-provider\n */\n\nimport type { AdapterType } from '../hooks/useChannels';\n\nexport interface CredentialField {\n key: string;\n displayName: string;\n description: string;\n type: 'text' | 'password' | 'textarea' | 'number' | 'boolean' | 'select';\n required: boolean;\n placeholder?: string;\n defaultValue?: string | number | boolean;\n options?: { value: string; label: string }[];\n validation?: {\n pattern?: string;\n minLength?: number;\n maxLength?: number;\n };\n}\n\nexport interface AdapterCredentialSchema {\n displayName: string;\n description: string;\n docUrl?: string;\n logoUrl?: string;\n credentials: CredentialField[];\n platformMetadata?: CredentialField[];\n}\n\n/**\n * Credential schemas for each adapter type.\n * Keys match the AdapterType enum values.\n */\nconst ADAPTER_CREDENTIALS: Partial<Record<AdapterType, AdapterCredentialSchema>> = {\n // ===================\n // SMS ADAPTERS\n // ===================\n TWILIO_SMS: {\n displayName: 'Twilio SMS',\n description: 'Send SMS via Twilio',\n docUrl: 'https://www.twilio.com/docs/sms',\n credentials: [\n {\n key: 'accountSid',\n displayName: 'Account SID',\n description: 'Your Twilio Account SID (starts with AC)',\n type: 'text',\n required: true,\n placeholder: 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n validation: { pattern: '^AC[a-zA-Z0-9]{32}$' },\n },\n {\n key: 'authToken',\n displayName: 'Auth Token',\n description: 'Your Twilio Auth Token',\n type: 'password',\n required: true,\n placeholder: 'Your auth token',\n },\n {\n key: 'fromNumber',\n displayName: 'From Phone Number',\n description: 'Sender phone number in E.164 format',\n type: 'text',\n required: true,\n placeholder: '+1234567890',\n validation: { pattern: '^\\\\+[1-9]\\\\d{1,14}$' },\n },\n ],\n platformMetadata: [\n {\n key: 'statusCallbackUrl',\n displayName: 'Status Callback URL',\n description: 'Webhook URL for delivery status updates (optional)',\n type: 'text',\n required: false,\n placeholder: 'https://your-domain.com/webhooks/twilio',\n },\n ],\n },\n\n AWS_SNS: {\n displayName: 'AWS SNS',\n description: 'Send SMS via Amazon Simple Notification Service',\n docUrl: 'https://docs.aws.amazon.com/sns/',\n credentials: [\n {\n key: 'accessKeyId',\n displayName: 'AWS Access Key ID',\n description: 'Your AWS access key ID',\n type: 'text',\n required: true,\n placeholder: 'AKIAIOSFODNN7EXAMPLE',\n },\n {\n key: 'secretAccessKey',\n displayName: 'AWS Secret Access Key',\n description: 'Your AWS secret access key',\n type: 'password',\n required: true,\n placeholder: 'Your secret access key',\n },\n {\n key: 'region',\n displayName: 'AWS Region',\n description: 'AWS region for SNS service',\n type: 'select',\n required: true,\n defaultValue: 'us-east-1',\n options: [\n { value: 'us-east-1', label: 'US East (N. Virginia)' },\n { value: 'us-east-2', label: 'US East (Ohio)' },\n { value: 'us-west-1', label: 'US West (N. California)' },\n { value: 'us-west-2', label: 'US West (Oregon)' },\n { value: 'ca-central-1', label: 'Canada (Central)' },\n { value: 'ca-west-1', label: 'Canada West (Calgary)' },\n { value: 'eu-west-1', label: 'Europe (Ireland)' },\n { value: 'eu-west-2', label: 'Europe (London)' },\n { value: 'eu-west-3', label: 'Europe (Paris)' },\n { value: 'eu-central-1', label: 'Europe (Frankfurt)' },\n { value: 'eu-central-2', label: 'Europe (Zurich)' },\n { value: 'eu-north-1', label: 'Europe (Stockholm)' },\n { value: 'eu-south-1', label: 'Europe (Milan)' },\n { value: 'eu-south-2', label: 'Europe (Spain)' },\n { value: 'ap-south-1', label: 'Asia Pacific (Mumbai)' },\n { value: 'ap-south-2', label: 'Asia Pacific (Hyderabad)' },\n { value: 'ap-southeast-1', label: 'Asia Pacific (Singapore)' },\n { value: 'ap-southeast-2', label: 'Asia Pacific (Sydney)' },\n { value: 'ap-southeast-3', label: 'Asia Pacific (Jakarta)' },\n { value: 'ap-southeast-4', label: 'Asia Pacific (Melbourne)' },\n { value: 'ap-northeast-1', label: 'Asia Pacific (Tokyo)' },\n { value: 'ap-northeast-2', label: 'Asia Pacific (Seoul)' },\n { value: 'ap-northeast-3', label: 'Asia Pacific (Osaka)' },\n { value: 'ap-east-1', label: 'Asia Pacific (Hong Kong)' },\n { value: 'sa-east-1', label: 'South America (São Paulo)' },\n { value: 'me-south-1', label: 'Middle East (Bahrain)' },\n { value: 'me-central-1', label: 'Middle East (UAE)' },\n { value: 'af-south-1', label: 'Africa (Cape Town)' },\n { value: 'il-central-1', label: 'Israel (Tel Aviv)' },\n ],\n },\n ],\n platformMetadata: [\n {\n key: 'senderId',\n displayName: 'Sender ID',\n description: 'Sender ID for supported regions (optional)',\n type: 'text',\n required: false,\n placeholder: 'YourBrand',\n },\n {\n key: 'messageType',\n displayName: 'Message Type',\n description: 'SMS message type',\n type: 'select',\n required: false,\n defaultValue: 'Transactional',\n options: [\n { value: 'Transactional', label: 'Transactional' },\n { value: 'Promotional', label: 'Promotional' },\n ],\n },\n ],\n },\n\n // ===================\n // EMAIL ADAPTERS\n // ===================\n SENDGRID: {\n displayName: 'SendGrid',\n description: 'Send emails via SendGrid',\n docUrl: 'https://docs.sendgrid.com/',\n credentials: [\n {\n key: 'apiKey',\n displayName: 'API Key',\n description: 'Your SendGrid API Key',\n type: 'password',\n required: true,\n placeholder: 'SG.xxxx...',\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Verified sender email address',\n type: 'text',\n required: true,\n placeholder: 'noreply@yourdomain.com',\n },\n {\n key: 'fromName',\n displayName: 'From Name',\n description: 'Sender display name',\n type: 'text',\n required: false,\n placeholder: 'Your Company',\n defaultValue: 'Notification',\n },\n ],\n },\n\n AWS_SES: {\n displayName: 'AWS SES',\n description: 'Send emails via Amazon Simple Email Service',\n docUrl: 'https://docs.aws.amazon.com/ses/',\n credentials: [\n {\n key: 'accessKeyId',\n displayName: 'AWS Access Key ID',\n description: 'Your AWS access key ID',\n type: 'text',\n required: true,\n placeholder: 'AKIAIOSFODNN7EXAMPLE',\n },\n {\n key: 'secretAccessKey',\n displayName: 'AWS Secret Access Key',\n description: 'Your AWS secret access key',\n type: 'password',\n required: true,\n placeholder: 'Your secret access key',\n },\n {\n key: 'region',\n displayName: 'AWS Region',\n description: 'AWS region for SES service',\n type: 'select',\n required: true,\n defaultValue: 'us-east-1',\n options: [\n { value: 'us-east-1', label: 'US East (N. Virginia)' },\n { value: 'us-east-2', label: 'US East (Ohio)' },\n { value: 'us-west-1', label: 'US West (N. California)' },\n { value: 'us-west-2', label: 'US West (Oregon)' },\n { value: 'ca-central-1', label: 'Canada (Central)' },\n { value: 'ca-west-1', label: 'Canada West (Calgary)' },\n { value: 'eu-west-1', label: 'Europe (Ireland)' },\n { value: 'eu-west-2', label: 'Europe (London)' },\n { value: 'eu-west-3', label: 'Europe (Paris)' },\n { value: 'eu-central-1', label: 'Europe (Frankfurt)' },\n { value: 'eu-central-2', label: 'Europe (Zurich)' },\n { value: 'eu-north-1', label: 'Europe (Stockholm)' },\n { value: 'eu-south-1', label: 'Europe (Milan)' },\n { value: 'eu-south-2', label: 'Europe (Spain)' },\n { value: 'ap-south-1', label: 'Asia Pacific (Mumbai)' },\n { value: 'ap-south-2', label: 'Asia Pacific (Hyderabad)' },\n { value: 'ap-southeast-1', label: 'Asia Pacific (Singapore)' },\n { value: 'ap-southeast-2', label: 'Asia Pacific (Sydney)' },\n { value: 'ap-southeast-3', label: 'Asia Pacific (Jakarta)' },\n { value: 'ap-southeast-4', label: 'Asia Pacific (Melbourne)' },\n { value: 'ap-northeast-1', label: 'Asia Pacific (Tokyo)' },\n { value: 'ap-northeast-2', label: 'Asia Pacific (Seoul)' },\n { value: 'ap-northeast-3', label: 'Asia Pacific (Osaka)' },\n { value: 'ap-east-1', label: 'Asia Pacific (Hong Kong)' },\n { value: 'sa-east-1', label: 'South America (São Paulo)' },\n { value: 'me-south-1', label: 'Middle East (Bahrain)' },\n { value: 'me-central-1', label: 'Middle East (UAE)' },\n { value: 'af-south-1', label: 'Africa (Cape Town)' },\n { value: 'il-central-1', label: 'Israel (Tel Aviv)' },\n ],\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Verified sender email address',\n type: 'text',\n required: false,\n placeholder: 'noreply@yourdomain.com',\n },\n ],\n platformMetadata: [\n {\n key: 'configurationSetName',\n displayName: 'Configuration Set',\n description: 'SES Configuration Set for tracking (optional)',\n type: 'text',\n required: false,\n placeholder: 'my-configuration-set',\n },\n ],\n },\n\n AZURE_ACS: {\n displayName: 'Azure Communication Services',\n description: 'Send emails via Azure Communication Services',\n docUrl: 'https://docs.microsoft.com/azure/communication-services/',\n credentials: [\n {\n key: 'connectionString',\n displayName: 'Connection String',\n description: 'Azure ACS connection string (endpoint=...;accesskey=...)',\n type: 'password',\n required: true,\n placeholder: 'endpoint=https://your-resource.communication.azure.com/;accesskey=...',\n },\n {\n key: 'senderAddress',\n displayName: 'Sender Email',\n description: 'Azure verified sender email address',\n type: 'text',\n required: true,\n placeholder: 'DoNotReply@your-domain.azurecomm.net',\n },\n ],\n },\n\n MAILGUN: {\n displayName: 'Mailgun',\n description: 'Send emails via Mailgun',\n docUrl: 'https://documentation.mailgun.com/',\n credentials: [\n {\n key: 'apiKey',\n displayName: 'API Key',\n description: 'Your Mailgun API Key',\n type: 'password',\n required: true,\n placeholder: 'key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n },\n {\n key: 'domain',\n displayName: 'Domain',\n description: 'Your Mailgun sending domain',\n type: 'text',\n required: true,\n placeholder: 'mg.yourdomain.com',\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Sender email address',\n type: 'text',\n required: true,\n placeholder: 'noreply@mg.yourdomain.com',\n },\n {\n key: 'fromName',\n displayName: 'From Name',\n description: 'Sender display name',\n type: 'text',\n required: false,\n placeholder: 'Your Company',\n },\n ],\n platformMetadata: [\n {\n key: 'region',\n displayName: 'Region',\n description: 'Mailgun region',\n type: 'select',\n required: false,\n defaultValue: 'us',\n options: [\n { value: 'us', label: 'US' },\n { value: 'eu', label: 'EU' },\n ],\n },\n ],\n },\n\n POSTMARK: {\n displayName: 'Postmark',\n description: 'Send emails via Postmark',\n docUrl: 'https://postmarkapp.com/developer',\n credentials: [\n {\n key: 'serverToken',\n displayName: 'Server API Token',\n description: 'Your Postmark Server API Token',\n type: 'password',\n required: true,\n placeholder: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Verified sender email address',\n type: 'text',\n required: true,\n placeholder: 'noreply@yourdomain.com',\n },\n {\n key: 'fromName',\n displayName: 'From Name',\n description: 'Sender display name',\n type: 'text',\n required: false,\n placeholder: 'Your Company',\n },\n ],\n },\n\n RESEND: {\n displayName: 'Resend',\n description: 'Send emails via Resend',\n docUrl: 'https://resend.com/docs',\n credentials: [\n {\n key: 'apiKey',\n displayName: 'API Key',\n description: 'Your Resend API Key',\n type: 'password',\n required: true,\n placeholder: 're_xxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Verified sender email address',\n type: 'text',\n required: true,\n placeholder: 'noreply@yourdomain.com',\n },\n {\n key: 'fromName',\n displayName: 'From Name',\n description: 'Sender display name',\n type: 'text',\n required: false,\n placeholder: 'Your Company',\n },\n ],\n },\n\n SMTP: {\n displayName: 'Custom SMTP',\n description: 'Send emails via custom SMTP server',\n credentials: [\n {\n key: 'host',\n displayName: 'SMTP Host',\n description: 'SMTP server hostname',\n type: 'text',\n required: true,\n placeholder: 'smtp.yourdomain.com',\n },\n {\n key: 'port',\n displayName: 'SMTP Port',\n description: 'SMTP server port (usually 587 for TLS, 465 for SSL)',\n type: 'number',\n required: true,\n defaultValue: 587,\n placeholder: '587',\n },\n {\n key: 'username',\n displayName: 'Username',\n description: 'SMTP authentication username',\n type: 'text',\n required: true,\n placeholder: 'your-username',\n },\n {\n key: 'password',\n displayName: 'Password',\n description: 'SMTP authentication password',\n type: 'password',\n required: true,\n placeholder: 'Your password',\n },\n {\n key: 'fromEmail',\n displayName: 'From Email',\n description: 'Sender email address',\n type: 'text',\n required: true,\n placeholder: 'noreply@yourdomain.com',\n },\n {\n key: 'fromName',\n displayName: 'From Name',\n description: 'Sender display name',\n type: 'text',\n required: false,\n placeholder: 'Your Company',\n },\n ],\n platformMetadata: [\n {\n key: 'secure',\n displayName: 'Use SSL/TLS',\n description: 'Use SSL/TLS encryption',\n type: 'boolean',\n required: false,\n defaultValue: true,\n },\n ],\n },\n\n // ===================\n // PUSH NOTIFICATION ADAPTERS\n // ===================\n FCM: {\n displayName: 'Firebase Cloud Messaging',\n description: 'Send push notifications via FCM',\n docUrl: 'https://firebase.google.com/docs/cloud-messaging',\n credentials: [\n {\n key: 'projectId',\n displayName: 'Firebase Project ID',\n description: 'Your Firebase project ID',\n type: 'text',\n required: true,\n placeholder: 'your-project-id',\n },\n {\n key: 'clientEmail',\n displayName: 'Service Account Email',\n description: 'Service account email from Firebase credentials JSON',\n type: 'text',\n required: true,\n placeholder: 'firebase-adminsdk-xxxxx@your-project.iam.gserviceaccount.com',\n },\n {\n key: 'privateKey',\n displayName: 'Private Key',\n description:\n 'Service account private key (PEM format, paste the entire key including BEGIN/END lines)',\n type: 'textarea',\n required: true,\n placeholder: 'Paste the full PEM private key from your service account JSON',\n },\n ],\n },\n\n APNS: {\n displayName: 'Apple Push Notification Service',\n description: 'Send push notifications to iOS devices via APNs',\n docUrl: 'https://developer.apple.com/documentation/usernotifications',\n credentials: [\n {\n key: 'teamId',\n displayName: 'Team ID',\n description: 'Your 10-character Apple Developer Team ID',\n type: 'text',\n required: true,\n placeholder: 'ABCDE12345',\n validation: { pattern: '^[A-Z0-9]{10}$' },\n },\n {\n key: 'keyId',\n displayName: 'Key ID',\n description: 'Your 10-character Key ID from Apple Developer Account',\n type: 'text',\n required: true,\n placeholder: 'ABC123DEFG',\n validation: { pattern: '^[A-Z0-9]{10}$' },\n },\n {\n key: 'privateKey',\n displayName: 'Private Key (.p8)',\n description: 'Content of your .p8 private key file',\n type: 'textarea',\n required: true,\n placeholder: '-----BEGIN PRIVATE KEY-----\\nYour .p8 key content\\n-----END PRIVATE KEY-----',\n },\n {\n key: 'bundleId',\n displayName: 'Bundle ID',\n description: \"Your app's Bundle Identifier\",\n type: 'text',\n required: true,\n placeholder: 'com.yourcompany.yourapp',\n },\n ],\n platformMetadata: [\n {\n key: 'production',\n displayName: 'Production Environment',\n description: 'Use production APNs server (uncheck for sandbox/development)',\n type: 'boolean',\n required: false,\n defaultValue: false,\n },\n ],\n },\n\n ONESIGNAL: {\n displayName: 'OneSignal',\n description: 'Send push notifications via OneSignal',\n docUrl: 'https://documentation.onesignal.com/',\n credentials: [\n {\n key: 'appId',\n displayName: 'App ID',\n description: 'Your OneSignal App ID',\n type: 'text',\n required: true,\n placeholder: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',\n },\n {\n key: 'apiKey',\n displayName: 'REST API Key',\n description: 'Your OneSignal REST API Key',\n type: 'password',\n required: true,\n placeholder: 'Your API key',\n },\n ],\n },\n\n EXPO: {\n displayName: 'Expo Push',\n description: 'Send push notifications via Expo',\n docUrl: 'https://docs.expo.dev/push-notifications/',\n credentials: [\n {\n key: 'accessToken',\n displayName: 'Access Token',\n description: 'Your Expo access token (optional for increased rate limits)',\n type: 'password',\n required: false,\n placeholder: 'Your Expo access token',\n },\n ],\n },\n\n // ===================\n // MESSAGING PLATFORM ADAPTERS\n // ===================\n SLACK_BOT: {\n displayName: 'Slack Bot',\n description: 'Send messages via Slack Bot',\n docUrl: 'https://api.slack.com/bot-users',\n credentials: [\n {\n key: 'botToken',\n displayName: 'Bot Token',\n description: 'Your Slack Bot User OAuth Token (xoxb-...)',\n type: 'password',\n required: true,\n placeholder: 'xoxb-xxxxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx',\n },\n ],\n platformMetadata: [\n {\n key: 'defaultChannel',\n displayName: 'Default Channel',\n description: 'Default channel ID for messages (optional)',\n type: 'text',\n required: false,\n placeholder: 'C0123456789',\n },\n ],\n },\n\n SLACK_WEBHOOK: {\n displayName: 'Slack Webhook',\n description: 'Send messages via Slack Incoming Webhook',\n docUrl: 'https://api.slack.com/messaging/webhooks',\n credentials: [\n {\n key: 'webhookUrl',\n displayName: 'Webhook URL',\n description: 'Your Slack Incoming Webhook URL',\n type: 'password',\n required: true,\n placeholder: 'Paste your Slack Incoming Webhook URL',\n },\n ],\n },\n\n TEAMS_WEBHOOK: {\n displayName: 'Microsoft Teams Webhook',\n description: 'Send messages via Teams Incoming Webhook',\n docUrl: 'https://docs.microsoft.com/microsoftteams/platform/webhooks-and-connectors/',\n credentials: [\n {\n key: 'webhookUrl',\n displayName: 'Webhook URL',\n description: 'Your Microsoft Teams Incoming Webhook URL',\n type: 'password',\n required: true,\n placeholder: 'https://outlook.office.com/webhook/...',\n },\n ],\n },\n\n DISCORD_BOT: {\n displayName: 'Discord Bot',\n description: 'Send messages via Discord Bot',\n docUrl: 'https://discord.com/developers/docs',\n credentials: [\n {\n key: 'botToken',\n displayName: 'Bot Token',\n description: 'Your Discord Bot Token',\n type: 'password',\n required: true,\n placeholder: 'Your Discord bot token',\n },\n ],\n platformMetadata: [\n {\n key: 'defaultChannelId',\n displayName: 'Default Channel ID',\n description: 'Default channel ID for messages (optional)',\n type: 'text',\n required: false,\n placeholder: '123456789012345678',\n },\n ],\n },\n\n DISCORD_WEBHOOK: {\n displayName: 'Discord Webhook',\n description: 'Send messages via Discord Webhook',\n docUrl: 'https://discord.com/developers/docs/resources/webhook',\n credentials: [\n {\n key: 'webhookUrl',\n displayName: 'Webhook URL',\n description: 'Your Discord Webhook URL',\n type: 'password',\n required: true,\n placeholder: 'https://discord.com/api/webhooks/...',\n },\n ],\n },\n\n WHATSAPP_CLOUD: {\n displayName: 'WhatsApp Cloud API',\n description: 'Send messages via WhatsApp Business Cloud API',\n docUrl: 'https://developers.facebook.com/docs/whatsapp/cloud-api',\n credentials: [\n {\n key: 'accessToken',\n displayName: 'Access Token',\n description: 'Your WhatsApp Business API Access Token',\n type: 'password',\n required: true,\n placeholder: 'Your access token',\n },\n {\n key: 'phoneNumberId',\n displayName: 'Phone Number ID',\n description: 'Your WhatsApp Business Phone Number ID',\n type: 'text',\n required: true,\n placeholder: '123456789012345',\n },\n {\n key: 'businessAccountId',\n displayName: 'Business Account ID',\n description: 'Your WhatsApp Business Account ID',\n type: 'text',\n required: true,\n placeholder: '123456789012345',\n },\n ],\n },\n\n WHATSAPP_TWILIO: {\n displayName: 'WhatsApp via Twilio',\n description: 'Send WhatsApp messages via Twilio',\n docUrl: 'https://www.twilio.com/docs/whatsapp',\n credentials: [\n {\n key: 'accountSid',\n displayName: 'Account SID',\n description: 'Your Twilio Account SID (starts with AC)',\n type: 'text',\n required: true,\n placeholder: 'ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n },\n {\n key: 'authToken',\n displayName: 'Auth Token',\n description: 'Your Twilio Auth Token',\n type: 'password',\n required: true,\n placeholder: 'Your auth token',\n },\n {\n key: 'fromNumber',\n displayName: 'WhatsApp Number',\n description: 'Twilio WhatsApp number (whatsapp:+1234567890)',\n type: 'text',\n required: true,\n placeholder: 'whatsapp:+1234567890',\n },\n ],\n },\n\n // ===================\n // WEBHOOK ADAPTERS\n // ===================\n WEBHOOK_HTTP: {\n displayName: 'HTTP Webhook',\n description: 'Send notifications via HTTP webhook',\n credentials: [\n {\n key: 'webhookUrl',\n displayName: 'Webhook URL',\n description: 'HTTP endpoint to receive notifications',\n type: 'text',\n required: true,\n placeholder: 'https://your-api.com/webhooks/notifications',\n },\n ],\n platformMetadata: [\n {\n key: 'method',\n displayName: 'HTTP Method',\n description: 'HTTP method for the request',\n type: 'select',\n required: false,\n defaultValue: 'POST',\n options: [\n { value: 'POST', label: 'POST' },\n { value: 'PUT', label: 'PUT' },\n ],\n },\n {\n key: 'headers',\n displayName: 'Custom Headers (JSON)',\n description: 'Additional HTTP headers as JSON object',\n type: 'textarea',\n required: false,\n placeholder: '{\"Authorization\": \"Bearer token\", \"X-Custom-Header\": \"value\"}',\n },\n {\n key: 'secret',\n displayName: 'Signing Secret',\n description: 'Secret for HMAC signature verification (optional)',\n type: 'password',\n required: false,\n placeholder: 'Your webhook signing secret',\n },\n ],\n },\n};\n\n/**\n * Get credential schema for an adapter type\n */\nexport function getAdapterCredentialSchema(\n adapterType: AdapterType | undefined\n): AdapterCredentialSchema | null {\n if (!adapterType) return null;\n return ADAPTER_CREDENTIALS[adapterType] || null;\n}\n\n/**\n * Module-level RegExp cache so validateCredentials() doesn't allocate inside its loop.\n */\nconst REGEX_CACHE = new Map<string, RegExp>();\nfunction getCachedRegex(pattern: string): RegExp {\n let r = REGEX_CACHE.get(pattern);\n if (!r) {\n r = new RegExp(pattern);\n REGEX_CACHE.set(pattern, r);\n }\n return r;\n}\n\n/**\n * Validate credentials against adapter schema\n */\nexport function validateCredentials(\n adapterType: AdapterType | undefined,\n credentials: Record<string, unknown>\n): { valid: boolean; errors: string[] } {\n const schema = getAdapterCredentialSchema(adapterType);\n if (!schema) {\n return { valid: false, errors: ['Unknown adapter type'] };\n }\n\n const errors: string[] = [];\n\n for (const field of schema.credentials) {\n const value = credentials[field.key];\n\n // Check required fields\n if (field.required && (value === undefined || value === null || value === '')) {\n errors.push(`${field.displayName} is required`);\n continue;\n }\n\n // Skip validation for empty optional fields\n if (!field.required && (value === undefined || value === null || value === '')) {\n continue;\n }\n\n // Validate pattern if specified\n if (field.validation?.pattern && typeof value === 'string') {\n const regex = getCachedRegex(field.validation.pattern);\n if (!regex.test(value)) {\n errors.push(`${field.displayName} has an invalid format`);\n }\n }\n\n // Validate min/max length\n if (typeof value === 'string') {\n const minLength = field.validation?.minLength;\n const maxLength = field.validation?.maxLength;\n if (minLength && value.length < minLength) {\n errors.push(`${field.displayName} must be at least ${minLength} characters`);\n }\n if (maxLength && value.length > maxLength) {\n errors.push(`${field.displayName} must be at most ${maxLength} characters`);\n }\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Get default values for an adapter's credentials\n */\nexport function getDefaultCredentials(\n adapterType: AdapterType | undefined\n): Record<string, unknown> {\n const schema = getAdapterCredentialSchema(adapterType);\n if (!schema) return {};\n\n const defaults: Record<string, unknown> = {};\n for (const field of [...schema.credentials, ...(schema.platformMetadata || [])]) {\n if (field.defaultValue !== undefined) {\n defaults[field.key] = field.defaultValue;\n }\n }\n return defaults;\n}\n"],"mappings":"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EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,GACA;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;CACF;CAEA,SAAS;EACP,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;EACF;EACA,kBAAkB,CAChB;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,cAAc;GACd,SAAS,CACP;IAAE,OAAO;IAAM,OAAO;GAAK,GAC3B;IAAE,OAAO;IAAM,OAAO;GAAK,CAC7B;EACF,CACF;CACF;CAEA,UAAU;EACR,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;EACF;CACF;CAEA,QAAQ;EACN,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;EACF;CACF;CAEA,MAAM;EACJ,aAAa;EACb,aAAa;EACb,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,cAAc;IACd,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;EACF;EACA,kBAAkB,CAChB;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,cAAc;EAChB,CACF;CACF;CAKA,KAAK;EACH,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aACE;IACF,MAAM;IACN,UAAU;IACV,aAAa;GACf;EACF;CACF;CAEA,MAAM;EACJ,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACb,YAAY,EAAE,SAAS,iBAAiB;GAC1C;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;IACb,YAAY,EAAE,SAAS,iBAAiB;GAC1C;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;EACF;EACA,kBAAkB,CAChB;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,cAAc;EAChB,CACF;CACF;CAEA,WAAW;EACT,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,GACA;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;CACF;CAEA,MAAM;EACJ,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;CACF;CAKA,WAAW;EACT,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;EACA,kBAAkB,CAChB;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;CACF;CAEA,eAAe;EACb,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;CACF;CAEA,eAAe;EACb,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;CACF;CAEA,aAAa;EACX,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;EACA,kBAAkB,CAChB;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;CACF;CAEA,iBAAiB;EACf,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;CACF;CAEA,gBAAgB;EACd,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;EACF;CACF;CAEA,iBAAiB;EACf,aAAa;EACb,aAAa;EACb,QAAQ;EACR,aAAa;GACX;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;EACF;CACF;CAKA,cAAc;EACZ,aAAa;EACb,aAAa;EACb,aAAa,CACX;GACE,KAAK;GACL,aAAa;GACb,aAAa;GACb,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;EACA,kBAAkB;GAChB;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,cAAc;IACd,SAAS,CACP;KAAE,OAAO;KAAQ,OAAO;IAAO,GAC/B;KAAE,OAAO;KAAO,OAAO;IAAM,CAC/B;GACF;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,aAAa;IACb,aAAa;IACb,MAAM;IACN,UAAU;IACV,aAAa;GACf;EACF;CACF;AACF;AAKA,SAAgBC,EACd,GACgC;CAEhC,OADKC,KACEF,EAAoBE,MAAgB;AAC7C;AAKA,IAAMC,oBAAc,IAAI,IAAoB;AAC5C,SAASC,EAAe,GAAyB;CAC/C,IAAIC,IAAIF,EAAY,IAAIG,CAAO;CAK/B,OAJKD,MACH,IAAI,IAAI,OAAOC,CAAO,GACtBH,EAAY,IAAIG,GAASD,CAAC,IAErBA;AACT;AAKA,SAAgBE,EACd,GACA,GACsC;CACtC,IAAMC,IAASP,EAA2BC,CAAW;CACrD,IAAI,CAACM,GACH,OAAO;EAAE,OAAO;EAAO,QAAQ,CAAC,sBAAsB;CAAE;CAG1D,IAAMC,IAAmB,CAAC;CAE1B,KAAK,IAAMC,KAASF,EAAO,aAAa;EACtC,IAAMG,IAAQC,EAAYF,EAAM;EAGhC,IAAIA,EAAM,aAAaC,KAAiC,QAAQA,MAAU,KACxE,EAAO,KAAK,GAAGD,EAAM,YAAY,aAAa;OAKhD,KAAKA,EAAM,YAAaC,KAAiC,QAAQA,MAAU,QAKvED,EAAM,YAAY,WAAW,OAAOC,KAAU,aAClCP,EAAeM,EAAM,WAAW,OACzC,CAAA,CAAM,KAAKC,CAAK,KACnBF,EAAO,KAAK,GAAGC,EAAM,YAAY,uBAAuB,IAKxD,OAAOC,KAAU,WAAU;GAC7B,IAAME,IAAYH,EAAM,YAAY,WAC9BI,IAAYJ,EAAM,YAAY;GAIpC,AAHIG,KAAaF,EAAM,SAASE,KAC9BJ,EAAO,KAAK,GAAGC,EAAM,YAAY,oBAAoBG,EAAU,YAAY,GAEzEC,KAAaH,EAAM,SAASG,KAC9BL,EAAO,KAAK,GAAGC,EAAM,YAAY,mBAAmBI,EAAU,YAAY;EAE9E;CACF;CAEA,OAAO;EAAE,OAAOL,EAAO,WAAW;EAAG;CAAO;AAC9C;AAKA,SAAgBM,EACd,GACyB;CACzB,IAAMP,IAASP,EAA2BC,CAAW;CACrD,IAAI,CAACM,GAAQ,OAAO,CAAC;CAErB,IAAMQ,IAAoC,CAAC;CAC3C,KAAK,IAAMN,KAAS,CAAC,GAAGF,EAAO,aAAa,GAAIA,EAAO,oBAAoB,CAAC,CAAE,GAC5E,AAAIE,EAAM,iBAAiB,KAAA,MACzB,EAASA,EAAM,OAAOA,EAAM;CAGhC,OAAOM;AACT"}
@@ -33,4 +33,3 @@ export declare const CHANNEL_PERMISSIONS: {
33
33
  readonly USER_PLATFORM_CONNECTION_DELETE: "user-platform-connection:delete";
34
34
  };
35
35
  export type ChannelPermission = (typeof CHANNEL_PERMISSIONS)[keyof typeof CHANNEL_PERMISSIONS];
36
- //# sourceMappingURL=permissions.d.ts.map
@@ -1,4 +1,4 @@
1
- //#region src/channel/constants/permissions.ts
1
+ // src/channel/constants/permissions.ts
2
2
  var e = {
3
3
  CHANNEL_READ: "channel:read",
4
4
  CHANNEL_CREATE: "channel:create",
@@ -27,7 +27,6 @@ var e = {
27
27
  USER_PLATFORM_CONNECTION_UPDATE: "user-platform-connection:update",
28
28
  USER_PLATFORM_CONNECTION_DELETE: "user-platform-connection:delete"
29
29
  };
30
- //#endregion
31
30
  export { e as CHANNEL_PERMISSIONS };
32
31
 
33
32
  //# sourceMappingURL=permissions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"permissions.js","names":[],"sources":["../../../src/channel/constants/permissions.ts"],"sourcesContent":["/**\n * RBAC permission constants for the Channel microfrontend.\n * Mirrors the @rbac directives in global-channel-svc.\n */\n\nexport const CHANNEL_PERMISSIONS = {\n // channel resource\n CHANNEL_READ: 'channel:read',\n CHANNEL_CREATE: 'channel:create',\n CHANNEL_UPDATE: 'channel:update',\n CHANNEL_DELETE: 'channel:delete',\n CHANNEL_ARCHIVE: 'channel:archive',\n CHANNEL_EXECUTE: 'channel:execute',\n /** Per-resource CSV export permissions — match the backend @rbac(action:\"export\", resource:...). */\n CHANNEL_EXPORT: 'channel:export',\n CHANNEL_DELIVERY_EXPORT: 'channel-delivery:export',\n CHANNEL_WEBHOOK_EXPORT: 'channel-webhook:export',\n CHANNEL_USER_EXPORT: 'channel-user:export',\n /** @deprecated alias of channel:update — do NOT use for export gating (use the *_EXPORT perms). */\n CHANNEL_ADMIN: 'channel:update',\n\n // channel-connection resource\n CHANNEL_CONNECTION_READ: 'channel-connection:read',\n CHANNEL_CONNECTION_CREATE: 'channel-connection:create',\n CHANNEL_CONNECTION_UPDATE: 'channel-connection:update',\n CHANNEL_CONNECTION_DELETE: 'channel-connection:delete',\n\n // channel-delivery resource\n CHANNEL_DELIVERY_READ: 'channel-delivery:read',\n CHANNEL_DELIVERY_SEND: 'channel-delivery:send',\n CHANNEL_DELIVERY_EXECUTE: 'channel-delivery:execute',\n CHANNEL_DELIVERY_DELETE: 'channel-delivery:delete',\n\n // channel-webhook resource\n CHANNEL_WEBHOOK_READ: 'channel-webhook:read',\n CHANNEL_WEBHOOK_EXECUTE: 'channel-webhook:execute',\n CHANNEL_WEBHOOK_UPDATE: 'channel-webhook:update',\n\n // user-platform-connection resource\n USER_PLATFORM_CONNECTION_READ: 'user-platform-connection:read',\n USER_PLATFORM_CONNECTION_CREATE: 'user-platform-connection:create',\n USER_PLATFORM_CONNECTION_UPDATE: 'user-platform-connection:update',\n USER_PLATFORM_CONNECTION_DELETE: 'user-platform-connection:delete',\n} as const;\n\nexport type ChannelPermission = (typeof CHANNEL_PERMISSIONS)[keyof typeof CHANNEL_PERMISSIONS];\n"],"mappings":";AAKA,IAAa,IAAsB;CAEjC,cAAc;CACd,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAChB,iBAAiB;CACjB,iBAAiB;CAEjB,gBAAgB;CAChB,yBAAyB;CACzB,wBAAwB;CACxB,qBAAqB;CAErB,eAAe;CAGf,yBAAyB;CACzB,2BAA2B;CAC3B,2BAA2B;CAC3B,2BAA2B;CAG3B,uBAAuB;CACvB,uBAAuB;CACvB,0BAA0B;CAC1B,yBAAyB;CAGzB,sBAAsB;CACtB,yBAAyB;CACzB,wBAAwB;CAGxB,+BAA+B;CAC/B,iCAAiC;CACjC,iCAAiC;CACjC,iCAAiC;CAClC"}
1
+ {"version":3,"file":"permissions.js","names":["CHANNEL_PERMISSIONS"],"sources":["../../../src/channel/constants/permissions.ts"],"sourcesContent":["/**\n * RBAC permission constants for the Channel microfrontend.\n * Mirrors the @rbac directives in global-channel-svc.\n */\n\nexport const CHANNEL_PERMISSIONS = {\n // channel resource\n CHANNEL_READ: 'channel:read',\n CHANNEL_CREATE: 'channel:create',\n CHANNEL_UPDATE: 'channel:update',\n CHANNEL_DELETE: 'channel:delete',\n CHANNEL_ARCHIVE: 'channel:archive',\n CHANNEL_EXECUTE: 'channel:execute',\n /** Per-resource CSV export permissions — match the backend @rbac(action:\"export\", resource:...). */\n CHANNEL_EXPORT: 'channel:export',\n CHANNEL_DELIVERY_EXPORT: 'channel-delivery:export',\n CHANNEL_WEBHOOK_EXPORT: 'channel-webhook:export',\n CHANNEL_USER_EXPORT: 'channel-user:export',\n /** @deprecated alias of channel:update — do NOT use for export gating (use the *_EXPORT perms). */\n CHANNEL_ADMIN: 'channel:update',\n\n // channel-connection resource\n CHANNEL_CONNECTION_READ: 'channel-connection:read',\n CHANNEL_CONNECTION_CREATE: 'channel-connection:create',\n CHANNEL_CONNECTION_UPDATE: 'channel-connection:update',\n CHANNEL_CONNECTION_DELETE: 'channel-connection:delete',\n\n // channel-delivery resource\n CHANNEL_DELIVERY_READ: 'channel-delivery:read',\n CHANNEL_DELIVERY_SEND: 'channel-delivery:send',\n CHANNEL_DELIVERY_EXECUTE: 'channel-delivery:execute',\n CHANNEL_DELIVERY_DELETE: 'channel-delivery:delete',\n\n // channel-webhook resource\n CHANNEL_WEBHOOK_READ: 'channel-webhook:read',\n CHANNEL_WEBHOOK_EXECUTE: 'channel-webhook:execute',\n CHANNEL_WEBHOOK_UPDATE: 'channel-webhook:update',\n\n // user-platform-connection resource\n USER_PLATFORM_CONNECTION_READ: 'user-platform-connection:read',\n USER_PLATFORM_CONNECTION_CREATE: 'user-platform-connection:create',\n USER_PLATFORM_CONNECTION_UPDATE: 'user-platform-connection:update',\n USER_PLATFORM_CONNECTION_DELETE: 'user-platform-connection:delete',\n} as const;\n\nexport type ChannelPermission = (typeof CHANNEL_PERMISSIONS)[keyof typeof CHANNEL_PERMISSIONS];\n"],"mappings":";AAKA,IAAaA,IAAsB;CAEjC,cAAc;CACd,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAChB,iBAAiB;CACjB,iBAAiB;CAEjB,gBAAgB;CAChB,yBAAyB;CACzB,wBAAwB;CACxB,qBAAqB;CAErB,eAAe;CAGf,yBAAyB;CACzB,2BAA2B;CAC3B,2BAA2B;CAC3B,2BAA2B;CAG3B,uBAAuB;CACvB,uBAAuB;CACvB,0BAA0B;CAC1B,yBAAyB;CAGzB,sBAAsB;CACtB,yBAAyB;CACzB,wBAAwB;CAGxB,+BAA+B;CAC/B,iCAAiC;CACjC,iCAAiC;CACjC,iCAAiC;AACnC"}
@@ -1,5 +1,4 @@
1
1
  import { ApolloClient } from '@apollo/client/core';
2
-
3
2
  /**
4
3
  * Get or create the singleton Apollo client for global channel operations
5
4
  *
@@ -8,4 +7,3 @@ import { ApolloClient } from '@apollo/client/core';
8
7
  * @param organizationId - Optional organization ID for RBAC checks
9
8
  */
10
9
  export declare function getGlobalChannelClient(globalGatewayUrl?: string, authToken?: string, organizationId?: string): ApolloClient;
11
- //# sourceMappingURL=global-client.d.ts.map
@@ -3,7 +3,7 @@ import { ApolloClient as t, HttpLink as n, InMemoryCache as r, from as i } from
3
3
  import { setContext as a } from "@apollo/client/link/context";
4
4
  import { onError as o } from "@apollo/client/link/error";
5
5
  import { isAuthNetworkError as s, redirectToLogin as c } from "@burdenoff/fe-libs/shared/utils";
6
- //#region src/channel/graphql/global-client.ts
6
+ // src/channel/graphql/global-client.ts
7
7
  function l(e = []) {
8
8
  return e.some((e) => {
9
9
  let t = typeof e.extensions?.code == "string" ? e.extensions.code : "", n = typeof e.extensions?.errorCode == "string" ? e.extensions.errorCode : "", r = (e.message ?? "").toLowerCase();
@@ -21,12 +21,12 @@ function h(h, g, _) {
21
21
  } })), x = a((e, { headers: t }) => ({ headers: {
22
22
  ...t,
23
23
  ..._ ? { "x-org-id": _ } : {}
24
- } }));
24
+ } })), S = o(({ error: t }) => {
25
+ e.is(t) ? l(t.errors) && c() : t instanceof Error && s(t) && c();
26
+ });
25
27
  return u = new t({
26
28
  link: i([
27
- o(({ error: t }) => {
28
- e.is(t) ? l(t.errors) && c() : t instanceof Error && s(t) && c();
29
- }),
29
+ S,
30
30
  b,
31
31
  x,
32
32
  y
@@ -50,7 +50,6 @@ function h(h, g, _) {
50
50
  }
51
51
  }), u;
52
52
  }
53
- //#endregion
54
53
  export { h as getGlobalChannelClient };
55
54
 
56
55
  //# sourceMappingURL=global-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"global-client.js","names":[],"sources":["../../../src/channel/graphql/global-client.ts"],"sourcesContent":["import { ApolloClient, InMemoryCache, HttpLink, from } from '@apollo/client/core';\nimport { setContext } from '@apollo/client/link/context';\nimport { onError } from '@apollo/client/link/error';\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport type { GraphQLFormattedError } from 'graphql';\nimport { isAuthNetworkError, redirectToLogin } from '@burdenoff/fe-libs/shared/utils';\n\nfunction hasSessionAuthErrors(errors: ReadonlyArray<GraphQLFormattedError> = []): boolean {\n return errors.some((gqlError) => {\n const code =\n typeof gqlError.extensions?.['code'] === 'string' ? gqlError.extensions['code'] : '';\n const errorCode =\n typeof gqlError.extensions?.['errorCode'] === 'string'\n ? gqlError.extensions['errorCode']\n : '';\n const message = (gqlError.message ?? '').toLowerCase();\n\n // Only match genuine session-expiry/missing-token conditions.\n // Do NOT match RBAC permission errors (e.g. FORBIDDEN) — those should show\n // an AccessDenied panel, not force a logout.\n return (\n code === 'UNAUTHENTICATED' ||\n errorCode === 'TOKEN_EXPIRED' ||\n message.includes('token_expired') ||\n message.includes('token expired') ||\n message.includes('session expired') ||\n message.includes('unauthenticated')\n );\n });\n}\n\nlet globalClientInstance: ApolloClient | null = null;\nlet currentGlobalUrl: string | null = null;\nlet currentAuthToken: string | null = null;\nlet currentOrgId: string | null = null;\n\n/**\n * Default Global Gateway URL\n * Channel is a GLOBAL service and must use the global gateway\n */\nconst DEFAULT_GLOBAL_GATEWAY_URL = 'https://gw-global.local.burdenoff.com/global/graphql';\n\n/**\n * Get or create the singleton Apollo client for global channel operations\n *\n * @param globalGatewayUrl - Global Gateway GraphQL URL (default: https://gw-global.local.burdenoff.com/global/graphql)\n * @param authToken - Optional JWT auth token\n * @param organizationId - Optional organization ID for RBAC checks\n */\nexport function getGlobalChannelClient(\n globalGatewayUrl?: string,\n authToken?: string,\n organizationId?: string\n): ApolloClient {\n // The shell passes the base gateway URL (e.g., 'http://localhost:4000').\n // We need to ensure it points to the global GraphQL endpoint.\n let url = globalGatewayUrl || DEFAULT_GLOBAL_GATEWAY_URL;\n if (url && !url.includes('/global/graphql')) {\n url = `${url.replace(/\\/+$/, '')}/global/graphql`;\n }\n\n // Return existing instance if config hasn't changed\n if (\n globalClientInstance &&\n currentGlobalUrl === url &&\n currentAuthToken === authToken &&\n currentOrgId === organizationId\n ) {\n return globalClientInstance;\n }\n\n // Update current config\n currentGlobalUrl = url;\n currentAuthToken = authToken ?? null;\n currentOrgId = organizationId ?? null;\n\n const httpLink = new HttpLink({\n uri: url,\n });\n\n // Auth Link - sets authorization header\n const authLink = setContext((_, { headers }) => {\n return {\n headers: {\n ...headers,\n authorization: authToken ? `Bearer ${authToken}` : '',\n },\n };\n });\n\n // Organization Link - sets x-org-id header for RBAC checks on global services.\n // Gateway reads x-org-id (not x-organization-id) from client requests.\n const organizationLink = setContext((_, { headers }) => {\n return {\n headers: {\n ...headers,\n ...(organizationId ? { 'x-org-id': organizationId } : {}),\n },\n };\n });\n\n // Apollo Client v4: onError receives { error } — a CombinedGraphQLErrors for\n // GraphQL errors, or a plain Error for network failures.\n const errorLink = onError(({ error }) => {\n if (CombinedGraphQLErrors.is(error)) {\n if (hasSessionAuthErrors(error.errors)) {\n redirectToLogin();\n }\n } else if (error instanceof Error && isAuthNetworkError(error)) {\n redirectToLogin();\n }\n });\n\n globalClientInstance = new ApolloClient({\n link: from([errorLink, authLink, organizationLink, httpLink]),\n cache: new InMemoryCache({\n typePolicies: {\n Query: {\n fields: {\n channels: {\n merge(existing, incoming) {\n return incoming;\n },\n },\n connections: {\n merge(existing, incoming) {\n return incoming;\n },\n },\n },\n },\n Channel: {\n keyFields: ['id'],\n },\n ChannelConnection: {\n keyFields: ['id'],\n },\n },\n }),\n defaultOptions: {\n watchQuery: {\n fetchPolicy: 'cache-and-network',\n },\n query: {\n fetchPolicy: 'network-only',\n },\n mutate: {\n fetchPolicy: 'network-only',\n },\n },\n });\n\n return globalClientInstance;\n}\n"],"mappings":";;;;;;AAOA,SAAS,EAAqB,IAA+C,EAAE,EAAW;AACxF,QAAO,EAAO,MAAM,MAAa;EAC/B,IAAM,IACJ,OAAO,EAAS,YAAa,QAAY,WAAW,EAAS,WAAW,OAAU,IAC9E,IACJ,OAAO,EAAS,YAAa,aAAiB,WAC1C,EAAS,WAAW,YACpB,IACA,KAAW,EAAS,WAAW,IAAI,aAAa;AAKtD,SACE,MAAS,qBACT,MAAc,mBACd,EAAQ,SAAS,gBAAgB,IACjC,EAAQ,SAAS,gBAAgB,IACjC,EAAQ,SAAS,kBAAkB,IACnC,EAAQ,SAAS,kBAAkB;GAErC;;AAGJ,IAAI,IAA4C,MAC5C,IAAkC,MAClC,IAAkC,MAClC,IAA8B,MAM5B,IAA6B;AASnC,SAAgB,EACd,GACA,GACA,GACc;CAGd,IAAI,IAAM,KAAoB;AAM9B,KALI,KAAO,CAAC,EAAI,SAAS,kBAAkB,KACzC,IAAM,GAAG,EAAI,QAAQ,QAAQ,GAAG,CAAC,mBAKjC,KACA,MAAqB,KACrB,MAAqB,KACrB,MAAiB,EAEjB,QAAO;AAMT,CAFA,IAAmB,GACnB,IAAmB,KAAa,MAChC,IAAe,KAAkB;CAEjC,IAAM,IAAW,IAAI,EAAS,EAC5B,KAAK,GACN,CAAC,EAGI,IAAW,GAAY,GAAG,EAAE,kBACzB,EACL,SAAS;EACP,GAAG;EACH,eAAe,IAAY,UAAU,MAAc;EACpD,EACF,EACD,EAII,IAAmB,GAAY,GAAG,EAAE,kBACjC,EACL,SAAS;EACP,GAAG;EACH,GAAI,IAAiB,EAAE,YAAY,GAAgB,GAAG,EAAE;EACzD,EACF,EACD;AAqDF,QAvCA,IAAuB,IAAI,EAAa;EACtC,MAAM,EAAK;GAXK,GAAS,EAAE,eAAY;AACvC,IAAI,EAAsB,GAAG,EAAM,GAC7B,EAAqB,EAAM,OAAO,IACpC,GAAiB,GAEV,aAAiB,SAAS,EAAmB,EAAM,IAC5D,GAAiB;KAEnB;GAGuB;GAAU;GAAkB;GAAS,CAAC;EAC7D,OAAO,IAAI,EAAc,EACvB,cAAc;GACZ,OAAO,EACL,QAAQ;IACN,UAAU,EACR,MAAM,GAAU,GAAU;AACxB,YAAO;OAEV;IACD,aAAa,EACX,MAAM,GAAU,GAAU;AACxB,YAAO;OAEV;IACF,EACF;GACD,SAAS,EACP,WAAW,CAAC,KAAK,EAClB;GACD,mBAAmB,EACjB,WAAW,CAAC,KAAK,EAClB;GACF,EACF,CAAC;EACF,gBAAgB;GACd,YAAY,EACV,aAAa,qBACd;GACD,OAAO,EACL,aAAa,gBACd;GACD,QAAQ,EACN,aAAa,gBACd;GACF;EACF,CAAC,EAEK"}
1
+ {"version":3,"file":"global-client.js","names":["hasSessionAuthErrors","errors","code","gqlError","\"code\"","errorCode","\"errorCode\"","message","globalClientInstance","currentGlobalUrl","currentAuthToken","currentOrgId","DEFAULT_GLOBAL_GATEWAY_URL","getGlobalChannelClient","url","globalGatewayUrl","authToken","organizationId","httpLink","HttpLink","authLink","setContext","headers","organizationLink","errorLink","onError","CombinedGraphQLErrors","error","redirectToLogin","isAuthNetworkError","ApolloClient","from","InMemoryCache","incoming"],"sources":["../../../src/channel/graphql/global-client.ts"],"sourcesContent":["import { ApolloClient, InMemoryCache, HttpLink, from } from '@apollo/client/core';\nimport { setContext } from '@apollo/client/link/context';\nimport { onError } from '@apollo/client/link/error';\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport type { GraphQLFormattedError } from 'graphql';\nimport { isAuthNetworkError, redirectToLogin } from '@burdenoff/fe-libs/shared/utils';\n\nfunction hasSessionAuthErrors(errors: ReadonlyArray<GraphQLFormattedError> = []): boolean {\n return errors.some((gqlError) => {\n const code =\n typeof gqlError.extensions?.['code'] === 'string' ? gqlError.extensions['code'] : '';\n const errorCode =\n typeof gqlError.extensions?.['errorCode'] === 'string'\n ? gqlError.extensions['errorCode']\n : '';\n const message = (gqlError.message ?? '').toLowerCase();\n\n // Only match genuine session-expiry/missing-token conditions.\n // Do NOT match RBAC permission errors (e.g. FORBIDDEN) — those should show\n // an AccessDenied panel, not force a logout.\n return (\n code === 'UNAUTHENTICATED' ||\n errorCode === 'TOKEN_EXPIRED' ||\n message.includes('token_expired') ||\n message.includes('token expired') ||\n message.includes('session expired') ||\n message.includes('unauthenticated')\n );\n });\n}\n\nlet globalClientInstance: ApolloClient | null = null;\nlet currentGlobalUrl: string | null = null;\nlet currentAuthToken: string | null = null;\nlet currentOrgId: string | null = null;\n\n/**\n * Default Global Gateway URL\n * Channel is a GLOBAL service and must use the global gateway\n */\nconst DEFAULT_GLOBAL_GATEWAY_URL = 'https://gw-global.local.burdenoff.com/global/graphql';\n\n/**\n * Get or create the singleton Apollo client for global channel operations\n *\n * @param globalGatewayUrl - Global Gateway GraphQL URL (default: https://gw-global.local.burdenoff.com/global/graphql)\n * @param authToken - Optional JWT auth token\n * @param organizationId - Optional organization ID for RBAC checks\n */\nexport function getGlobalChannelClient(\n globalGatewayUrl?: string,\n authToken?: string,\n organizationId?: string\n): ApolloClient {\n // The shell passes the base gateway URL (e.g., 'http://localhost:4000').\n // We need to ensure it points to the global GraphQL endpoint.\n let url = globalGatewayUrl || DEFAULT_GLOBAL_GATEWAY_URL;\n if (url && !url.includes('/global/graphql')) {\n url = `${url.replace(/\\/+$/, '')}/global/graphql`;\n }\n\n // Return existing instance if config hasn't changed\n if (\n globalClientInstance &&\n currentGlobalUrl === url &&\n currentAuthToken === authToken &&\n currentOrgId === organizationId\n ) {\n return globalClientInstance;\n }\n\n // Update current config\n currentGlobalUrl = url;\n currentAuthToken = authToken ?? null;\n currentOrgId = organizationId ?? null;\n\n const httpLink = new HttpLink({\n uri: url,\n });\n\n // Auth Link - sets authorization header\n const authLink = setContext((_, { headers }) => {\n return {\n headers: {\n ...headers,\n authorization: authToken ? `Bearer ${authToken}` : '',\n },\n };\n });\n\n // Organization Link - sets x-org-id header for RBAC checks on global services.\n // Gateway reads x-org-id (not x-organization-id) from client requests.\n const organizationLink = setContext((_, { headers }) => {\n return {\n headers: {\n ...headers,\n ...(organizationId ? { 'x-org-id': organizationId } : {}),\n },\n };\n });\n\n // Apollo Client v4: onError receives { error } — a CombinedGraphQLErrors for\n // GraphQL errors, or a plain Error for network failures.\n const errorLink = onError(({ error }) => {\n if (CombinedGraphQLErrors.is(error)) {\n if (hasSessionAuthErrors(error.errors)) {\n redirectToLogin();\n }\n } else if (error instanceof Error && isAuthNetworkError(error)) {\n redirectToLogin();\n }\n });\n\n globalClientInstance = new ApolloClient({\n link: from([errorLink, authLink, organizationLink, httpLink]),\n cache: new InMemoryCache({\n typePolicies: {\n Query: {\n fields: {\n channels: {\n merge(existing, incoming) {\n return incoming;\n },\n },\n connections: {\n merge(existing, incoming) {\n return incoming;\n },\n },\n },\n },\n Channel: {\n keyFields: ['id'],\n },\n ChannelConnection: {\n keyFields: ['id'],\n },\n },\n }),\n defaultOptions: {\n watchQuery: {\n fetchPolicy: 'cache-and-network',\n },\n query: {\n fetchPolicy: 'network-only',\n },\n mutate: {\n fetchPolicy: 'network-only',\n },\n },\n });\n\n return globalClientInstance;\n}\n"],"mappings":";;;;;;AAOA,SAASA,EAAqB,IAA+C,CAAC,GAAY;CACxF,OAAOC,EAAO,MAAM,MAAa;EAC/B,IAAMC,IACJ,OAAOC,EAAS,YAAaC,QAAY,WAAWD,EAAS,WAAWC,OAAU,IAC9EC,IACJ,OAAOF,EAAS,YAAaG,aAAiB,WAC1CH,EAAS,WAAWG,YACpB,IACAC,KAAWJ,EAAS,WAAW,GAAA,CAAI,YAAY;EAKrD,OACED,MAAS,qBACTG,MAAc,mBACdE,EAAQ,SAAS,eAAe,KAChCA,EAAQ,SAAS,eAAe,KAChCA,EAAQ,SAAS,iBAAiB,KAClCA,EAAQ,SAAS,iBAAiB;CAEtC,CAAC;AACH;AAEA,IAAIC,IAA4C,MAC5CC,IAAkC,MAClCC,IAAkC,MAClCC,IAA8B,MAM5BC,IAA6B;AASnC,SAAgBC,EACd,GACA,GACA,GACc;CAGd,IAAIC,IAAMC,KAAoBH;CAM9B,IALIE,KAAO,CAACA,EAAI,SAAS,iBAAiB,MACxC,IAAM,GAAGA,EAAI,QAAQ,QAAQ,EAAE,EAAE,mBAKjCN,KACAC,MAAqBK,KACrBJ,MAAqBM,KACrBL,MAAiBM,GAEjB,OAAOT;CAMT,AAFA,IAAmBM,GACnB,IAAmBE,KAAa,MAChC,IAAeC,KAAkB;CAEjC,IAAMC,IAAW,IAAIC,EAAS,EAC5B,KAAKL,EACP,CAAC,GAGKM,IAAWC,GAAY,GAAG,EAAE,kBACzB,EACL,SAAS;EACP,GAAGC;EACH,eAAeN,IAAY,UAAUA,MAAc;CACrD,EACF,EACD,GAIKO,IAAmBF,GAAY,GAAG,EAAE,kBACjC,EACL,SAAS;EACP,GAAGC;EACH,GAAIL,IAAiB,EAAE,YAAYA,EAAe,IAAI,CAAC;CACzD,EACF,EACD,GAIKO,IAAYC,GAAS,EAAE,eAAY;EACvC,AAAIC,EAAsB,GAAGC,CAAK,IAC5B3B,EAAqB2B,EAAM,MAAM,KACnCC,EAAgB,IAETD,aAAiB,SAASE,EAAmBF,CAAK,KAC3DC,EAAgB;CAEpB,CAAC;CAyCD,OAvCA,IAAuB,IAAIE,EAAa;EACtC,MAAMC,EAAK;GAACP;GAAWJ;GAAUG;GAAkBL;EAAQ,CAAC;EAC5D,OAAO,IAAIc,EAAc,EACvB,cAAc;GACZ,OAAO,EACL,QAAQ;IACN,UAAU,EACR,MAAM,GAAU,GAAU;KACxB,OAAOC;IACT,EACF;IACA,aAAa,EACX,MAAM,GAAU,GAAU;KACxB,OAAOA;IACT,EACF;GACF,EACF;GACA,SAAS,EACP,WAAW,CAAC,IAAI,EAClB;GACA,mBAAmB,EACjB,WAAW,CAAC,IAAI,EAClB;EACF,EACF,CAAC;EACD,gBAAgB;GACd,YAAY,EACV,aAAa,oBACf;GACA,OAAO,EACL,aAAa,eACf;GACA,QAAQ,EACN,aAAa,eACf;EACF;CACF,CAAC,GAEMzB;AACT"}
@@ -1,5 +1,4 @@
1
1
  import { ChannelOrgSettingsInput } from '../../generated/global-types';
2
-
3
2
  export interface ChannelOrgSettings {
4
3
  organizationId: string;
5
4
  defaultPriority: number;
@@ -19,4 +18,3 @@ export declare function useChannelOrgSettings(): {
19
18
  refetch: () => Promise<void>;
20
19
  saveSettings: (input: ChannelOrgSettingsInput) => Promise<ChannelOrgSettings | null>;
21
20
  };
22
- //# sourceMappingURL=useChannelOrgSettings.d.ts.map
@@ -1,33 +1,33 @@
1
- import { useChannel as e } from "../providers/ChannelProvider.js";
2
- import { getGlobalChannelClient as t } from "../graphql/global-client.js";
1
+ import { getGlobalChannelClient as e } from "../graphql/global-client.js";
2
+ import { useChannel as t } from "../providers/ChannelProvider.js";
3
3
  import { GetChannelOrgSettingsDocument as n, UpdateChannelOrgSettingsDocument as r } from "../../generated/global-operations.js";
4
4
  import { useCallback as i, useEffect as a, useState as o } from "react";
5
- //#region src/channel/hooks/useChannelOrgSettings.ts
5
+ // src/channel/hooks/useChannelOrgSettings.ts
6
6
  function s(e, t) {
7
7
  console.error(`[channel-org-settings] ${t}`, e);
8
8
  }
9
9
  function c() {
10
- let { authToken: c, apiGatewayUrl: l, organizationId: u } = e(), [d, f] = o(null), [p, m] = o(!0), [h, g] = o(null), _ = i(() => t(l, c, u), [
10
+ let { authToken: c, apiGatewayUrl: l, organizationId: u } = t(), [d, f] = o(null), [p, m] = o(!0), [h, g] = o(null), _ = i(() => e(l, c, u), [
11
11
  l,
12
12
  c,
13
13
  u
14
14
  ]), v = i(async () => {
15
- if (!u) {
16
- m(!1);
17
- return;
18
- }
19
- m(!0), g(null);
20
- try {
21
- f((await _().query({
22
- query: n,
23
- variables: { organizationId: u },
24
- fetchPolicy: "network-only"
25
- })).data?.getChannelOrgSettings ?? null);
26
- } catch (e) {
27
- let t = e instanceof Error ? e.message : "Failed to fetch settings";
28
- s(e, "fetchSettings"), g(t);
29
- } finally {
30
- m(!1);
15
+ if (!u) m(!1);
16
+ else {
17
+ m(!0), g(null);
18
+ try {
19
+ let e = await _().query({
20
+ query: n,
21
+ variables: { organizationId: u },
22
+ fetchPolicy: "network-only"
23
+ });
24
+ f(e.data?.getChannelOrgSettings ?? null);
25
+ } catch (e) {
26
+ let t = e instanceof Error ? e.message : "Failed to fetch settings";
27
+ s(e, "fetchSettings"), g(t);
28
+ } finally {
29
+ m(!1);
30
+ }
31
31
  }
32
32
  }, [_, u]);
33
33
  return a(() => {
@@ -55,7 +55,6 @@ function c() {
55
55
  }, [_, u])
56
56
  };
57
57
  }
58
- //#endregion
59
58
  export { c as useChannelOrgSettings };
60
59
 
61
60
  //# sourceMappingURL=useChannelOrgSettings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useChannelOrgSettings.js","names":[],"sources":["../../../src/channel/hooks/useChannelOrgSettings.ts"],"sourcesContent":["/**\n * Channel Org Settings Hook\n * GraphQL query and mutation for organization-level channel settings.\n */\n\nimport { useState, useCallback, useEffect } from 'react';\nimport { getGlobalChannelClient } from '../graphql/global-client';\nimport { useChannel as useChannelContext } from '../providers/ChannelProvider';\nimport {\n GetChannelOrgSettingsDocument,\n UpdateChannelOrgSettingsDocument,\n type GetChannelOrgSettingsQuery,\n type UpdateChannelOrgSettingsMutation,\n} from '../../generated/global-operations';\nimport type { ChannelOrgSettingsInput } from '../../generated/global-types';\n\nexport interface ChannelOrgSettings {\n organizationId: string;\n defaultPriority: number;\n rateLimitPerMinute: number;\n rateLimitPerHour: number;\n healthCheckIntervalMinutes: number;\n enableAuditLogging: boolean;\n enableWebhookVerification: boolean;\n sessionTimeoutMinutes: number;\n updatedAt: string;\n}\n\nexport type { ChannelOrgSettingsInput };\n\nfunction report(error: unknown, action: string) {\n console.error(`[channel-org-settings] ${action}`, error);\n}\n\nexport function useChannelOrgSettings() {\n const { authToken, apiGatewayUrl, organizationId } = useChannelContext();\n const [settings, setSettings] = useState<ChannelOrgSettings | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const getClient = useCallback(\n () => getGlobalChannelClient(apiGatewayUrl, authToken, organizationId),\n [apiGatewayUrl, authToken, organizationId]\n );\n\n const fetchSettings = useCallback(async () => {\n if (!organizationId) {\n setIsLoading(false);\n return;\n }\n setIsLoading(true);\n setError(null);\n try {\n const client = getClient();\n const result = await client.query<GetChannelOrgSettingsQuery>({\n query: GetChannelOrgSettingsDocument,\n variables: { organizationId },\n fetchPolicy: 'network-only',\n });\n setSettings(result.data?.getChannelOrgSettings ?? null);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to fetch settings';\n report(err, 'fetchSettings');\n setError(message);\n } finally {\n setIsLoading(false);\n }\n }, [getClient, organizationId]);\n\n useEffect(() => {\n void Promise.resolve().then(() => fetchSettings());\n }, [fetchSettings]);\n\n const saveSettings = useCallback(\n async (input: ChannelOrgSettingsInput): Promise<ChannelOrgSettings | null> => {\n if (!organizationId) return null;\n try {\n const client = getClient();\n const result = await client.mutate<UpdateChannelOrgSettingsMutation>({\n mutation: UpdateChannelOrgSettingsDocument,\n variables: { organizationId, input },\n });\n const updated = result.data?.updateChannelOrgSettings ?? null;\n if (updated) setSettings(updated);\n return updated;\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to save settings';\n report(err, 'saveSettings');\n throw new Error(message, { cause: err });\n }\n },\n [getClient, organizationId]\n );\n\n return { settings, isLoading, error, refetch: fetchSettings, saveSettings };\n}\n"],"mappings":";;;;;AA8BA,SAAS,EAAO,GAAgB,GAAgB;AAC9C,SAAQ,MAAM,0BAA0B,KAAU,EAAM;;AAG1D,SAAgB,IAAwB;CACtC,IAAM,EAAE,cAAW,kBAAe,sBAAmB,GAAmB,EAClE,CAAC,GAAU,KAAe,EAAoC,KAAK,EACnE,CAAC,GAAW,KAAgB,EAAS,GAAK,EAC1C,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAY,QACV,EAAuB,GAAe,GAAW,EAAe,EACtE;EAAC;EAAe;EAAW;EAAe,CAC3C,EAEK,IAAgB,EAAY,YAAY;AAC5C,MAAI,CAAC,GAAgB;AACnB,KAAa,GAAM;AACnB;;AAGF,EADA,EAAa,GAAK,EAClB,EAAS,KAAK;AACd,MAAI;AAOF,MALe,MADA,GAAW,CACE,MAAkC;IAC5D,OAAO;IACP,WAAW,EAAE,mBAAgB;IAC7B,aAAa;IACd,CAAC,EACiB,MAAM,yBAAyB,KAAK;WAChD,GAAc;GACrB,IAAM,IAAU,aAAe,QAAQ,EAAI,UAAU;AAErD,GADA,EAAO,GAAK,gBAAgB,EAC5B,EAAS,EAAQ;YACT;AACR,KAAa,GAAM;;IAEpB,CAAC,GAAW,EAAe,CAAC;AA2B/B,QAzBA,QAAgB;AACT,UAAQ,SAAS,CAAC,WAAW,GAAe,CAAC;IACjD,CAAC,EAAc,CAAC,EAuBZ;EAAE;EAAU;EAAW;EAAO,SAAS;EAAe,cArBxC,EACnB,OAAO,MAAuE;AAC5E,OAAI,CAAC,EAAgB,QAAO;AAC5B,OAAI;IAMF,IAAM,KAJS,MADA,GAAW,CACE,OAAyC;KACnE,UAAU;KACV,WAAW;MAAE;MAAgB;MAAO;KACrC,CAAC,EACqB,MAAM,4BAA4B;AAEzD,WADI,KAAS,EAAY,EAAQ,EAC1B;YACA,GAAc;IACrB,IAAM,IAAU,aAAe,QAAQ,EAAI,UAAU;AAErD,UADA,EAAO,GAAK,eAAe,EACjB,MAAM,GAAS,EAAE,OAAO,GAAK,CAAC;;KAG5C,CAAC,GAAW,EAAe,CAC5B;EAE0E"}
1
+ {"version":3,"file":"useChannelOrgSettings.js","names":["useChannelContext","report","action","error","useChannelOrgSettings","useChannel","settings","setSettings","useState","isLoading","setIsLoading","setError","getClient","useCallback","getGlobalChannelClient","apiGatewayUrl","authToken","organizationId","fetchSettings","result","GetChannelOrgSettingsDocument","err","message","useEffect","updated","UpdateChannelOrgSettingsDocument"],"sources":["../../../src/channel/hooks/useChannelOrgSettings.ts"],"sourcesContent":["/**\n * Channel Org Settings Hook\n * GraphQL query and mutation for organization-level channel settings.\n */\n\nimport { useState, useCallback, useEffect } from 'react';\nimport { getGlobalChannelClient } from '../graphql/global-client';\nimport { useChannel as useChannelContext } from '../providers/ChannelProvider';\nimport {\n GetChannelOrgSettingsDocument,\n UpdateChannelOrgSettingsDocument,\n type GetChannelOrgSettingsQuery,\n type UpdateChannelOrgSettingsMutation,\n} from '../../generated/global-operations';\nimport type { ChannelOrgSettingsInput } from '../../generated/global-types';\n\nexport interface ChannelOrgSettings {\n organizationId: string;\n defaultPriority: number;\n rateLimitPerMinute: number;\n rateLimitPerHour: number;\n healthCheckIntervalMinutes: number;\n enableAuditLogging: boolean;\n enableWebhookVerification: boolean;\n sessionTimeoutMinutes: number;\n updatedAt: string;\n}\n\nexport type { ChannelOrgSettingsInput };\n\nfunction report(error: unknown, action: string) {\n console.error(`[channel-org-settings] ${action}`, error);\n}\n\nexport function useChannelOrgSettings() {\n const { authToken, apiGatewayUrl, organizationId } = useChannelContext();\n const [settings, setSettings] = useState<ChannelOrgSettings | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const getClient = useCallback(\n () => getGlobalChannelClient(apiGatewayUrl, authToken, organizationId),\n [apiGatewayUrl, authToken, organizationId]\n );\n\n const fetchSettings = useCallback(async () => {\n if (!organizationId) {\n setIsLoading(false);\n return;\n }\n setIsLoading(true);\n setError(null);\n try {\n const client = getClient();\n const result = await client.query<GetChannelOrgSettingsQuery>({\n query: GetChannelOrgSettingsDocument,\n variables: { organizationId },\n fetchPolicy: 'network-only',\n });\n setSettings(result.data?.getChannelOrgSettings ?? null);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to fetch settings';\n report(err, 'fetchSettings');\n setError(message);\n } finally {\n setIsLoading(false);\n }\n }, [getClient, organizationId]);\n\n useEffect(() => {\n void Promise.resolve().then(() => fetchSettings());\n }, [fetchSettings]);\n\n const saveSettings = useCallback(\n async (input: ChannelOrgSettingsInput): Promise<ChannelOrgSettings | null> => {\n if (!organizationId) return null;\n try {\n const client = getClient();\n const result = await client.mutate<UpdateChannelOrgSettingsMutation>({\n mutation: UpdateChannelOrgSettingsDocument,\n variables: { organizationId, input },\n });\n const updated = result.data?.updateChannelOrgSettings ?? null;\n if (updated) setSettings(updated);\n return updated;\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to save settings';\n report(err, 'saveSettings');\n throw new Error(message, { cause: err });\n }\n },\n [getClient, organizationId]\n );\n\n return { settings, isLoading, error, refetch: fetchSettings, saveSettings };\n}\n"],"mappings":";;;;;AA8BA,SAASC,EAAO,GAAgB,GAAgB;CAC9C,QAAQ,MAAM,0BAA0BC,KAAUC,CAAK;AACzD;AAEA,SAAgBC,IAAwB;CACtC,IAAM,EAAE,cAAW,kBAAe,sBAAmBJ,EAAkB,GACjE,CAACM,GAAUC,KAAeC,EAAoC,IAAI,GAClE,CAACC,GAAWC,KAAgBF,EAAS,EAAI,GACzC,CAACL,GAAOQ,KAAYH,EAAwB,IAAI,GAEhDI,IAAYC,QACVC,EAAuBC,GAAeC,GAAWC,CAAc,GACrE;EAACF;EAAeC;EAAWC;CAAc,CAC3C,GAEMC,IAAgBL,EAAY,YAAY;EAC5C,IAAI,CAACI,GACH,EAAa,EAAK;OAGpB;GACA,AADAP,EAAa,EAAI,GACjBC,EAAS,IAAI;GACb,IAAI;IAEF,IAAMQ,IAAS,MADAP,EACM,CAAA,CAAO,MAAkC;KAC5D,OAAOQ;KACP,WAAW,EAAE,kBAAe;KAC5B,aAAa;IACf,CAAC;IACD,EAAYD,EAAO,MAAM,yBAAyB,IAAI;GACxD,SAASE,GAAc;IACrB,IAAMC,IAAUD,aAAe,QAAQA,EAAI,UAAU;IAErD,AADApB,EAAOoB,GAAK,eAAe,GAC3BV,EAASW,CAAO;GAClB,UAAU;IACR,EAAa,EAAK;GACpB;EAhBiB;CAiBnB,GAAG,CAACV,GAAWK,CAAc,CAAC;CA2B9B,OAzBAM,QAAgB;EACd,QAAa,QAAQ,CAAC,CAAC,WAAWL,EAAc,CAAC;CACnD,GAAG,CAACA,CAAa,CAAC,GAuBX;EAAE;EAAU;EAAW;EAAO,SAASA;EAAe,cArBxCL,EACnB,OAAO,MAAuE;GAC5E,IAAI,CAACI,GAAgB,OAAO;GAC5B,IAAI;IAMF,IAAMO,KAAU,MALDZ,EACM,CAAA,CAAO,OAAyC;KACnE,UAAUa;KACV,WAAW;MAAE;MAAgB;KAAM;IACrC,CAAC,EAAA,CACsB,MAAM,4BAA4B;IAEzD,OADID,KAASjB,EAAYiB,CAAO,GACzBA;GACT,SAASH,GAAc;IACrB,IAAMC,IAAUD,aAAe,QAAQA,EAAI,UAAU;IAErD,MADApB,EAAOoB,GAAK,cAAc,GAChB,MAAMC,GAAS,EAAE,OAAOD,EAAI,CAAC;GACzC;EACF,GACA,CAACT,GAAWK,CAAc,CAGiC;CAAa;AAC5E"}
@@ -31,4 +31,3 @@ export interface UseChannelSubscriptionArgs<TData> {
31
31
  export declare function useChannelSubscription<TData = unknown>({ query, variables, operationName, onData, pollFn, pollIntervalMs, enabled, }: UseChannelSubscriptionArgs<TData>): void;
32
32
  export declare const CHANNEL_HEALTH_CHANGED_SUBSCRIPTION = "\n subscription ChannelHealthChanged($organizationId: ID!) {\n channelHealthChanged(organizationId: $organizationId) {\n channelId\n previousHealth\n newHealth\n changedAt\n reason\n }\n }\n";
33
33
  export declare const WEBHOOK_RECEIVED_SUBSCRIPTION = "\n subscription WebhookReceived($channelId: ID!) {\n webhookReceived(channelId: $channelId) {\n channelId\n organizationId\n webhookEventId\n receivedAt\n platform\n processingStatus\n }\n }\n";
34
- //# sourceMappingURL=useChannelSubscription.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { getGraphqlWsClient as e, reportShellError as t } from "../utils/shellBridge.js";
2
2
  import { useEffect as n, useMemo as r, useRef as i } from "react";
3
- //#region src/channel/hooks/useChannelSubscription.ts
3
+ // src/channel/hooks/useChannelSubscription.ts
4
4
  function a(e) {
5
5
  let t = (e instanceof Error ? e.message : typeof e == "string" ? e : e?.message ?? "").toLowerCase();
6
6
  return t.includes("cannot query field") || t.includes("unknown field") || t.includes("subscription not supported") || t.includes("not implemented");
@@ -13,7 +13,9 @@ function o({ query: o, variables: s, operationName: c, onData: l, pollFn: u, pol
13
13
  l,
14
14
  u,
15
15
  s
16
- ]), n(() => {
16
+ ]);
17
+ let g = r(() => JSON.stringify(s ?? {}), [s]);
18
+ n(() => {
17
19
  if (!f) return;
18
20
  let n = e(), r = null, i = null, s = !1, l = () => {
19
21
  r ||= (Promise.resolve(m.current()).catch(() => {}), setInterval(() => {
@@ -49,9 +51,7 @@ function o({ query: o, variables: s, operationName: c, onData: l, pollFn: u, pol
49
51
  errors: e.errors
50
52
  }
51
53
  }, `[channel] subscription ${c} errors`);
52
- return;
53
- }
54
- if (e?.data) try {
54
+ } else if (e?.data) try {
55
55
  p.current(e.data);
56
56
  } catch (e) {
57
57
  t(e, {
@@ -65,11 +65,7 @@ function o({ query: o, variables: s, operationName: c, onData: l, pollFn: u, pol
65
65
  }
66
66
  },
67
67
  error: (e) => {
68
- if (a(e)) {
69
- l();
70
- return;
71
- }
72
- t(e, {
68
+ a(e) || t(e, {
73
69
  module: "channel",
74
70
  context: {
75
71
  operationName: c,
@@ -100,12 +96,11 @@ function o({ query: o, variables: s, operationName: c, onData: l, pollFn: u, pol
100
96
  f,
101
97
  o,
102
98
  c,
103
- r(() => JSON.stringify(s ?? {}), [s]),
99
+ g,
104
100
  d
105
101
  ]);
106
102
  }
107
103
  var s = "\n subscription ChannelHealthChanged($organizationId: ID!) {\n channelHealthChanged(organizationId: $organizationId) {\n channelId\n previousHealth\n newHealth\n changedAt\n reason\n }\n }\n", c = "\n subscription WebhookReceived($channelId: ID!) {\n webhookReceived(channelId: $channelId) {\n channelId\n organizationId\n webhookEventId\n receivedAt\n platform\n processingStatus\n }\n }\n";
108
- //#endregion
109
104
  export { s as CHANNEL_HEALTH_CHANGED_SUBSCRIPTION, c as WEBHOOK_RECEIVED_SUBSCRIPTION, o as useChannelSubscription };
110
105
 
111
106
  //# sourceMappingURL=useChannelSubscription.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useChannelSubscription.js","names":[],"sources":["../../../src/channel/hooks/useChannelSubscription.ts"],"sourcesContent":["/**\n * useChannelSubscription\n *\n * Defensive subscription wrapper. Probes the shell-provided graphql-ws client\n * (`globalThis.__burdenoffShell.graphqlWsClient`); if present, opens a\n * subscription and dispatches each payload to `onData`. If absent — or if the\n * subscription errors with a clear \"unknown field\" / \"not implemented\" signal\n * (the operation isn't on the gateway yet) — silently falls back to a polling\n * loop driven by the caller's `pollFn` at `pollIntervalMs`.\n *\n * Per task 5: backends may grow `webhookReceived`, `connectionStatusChanged`\n * etc. independently; this hook lets the FE wire all four pages without\n * crashing when a subscription isn't yet on the federated schema.\n */\n\nimport { useEffect, useMemo, useRef } from 'react';\nimport { getGraphqlWsClient } from '../utils/shellBridge';\nimport { reportShellError } from '../utils/shellBridge';\n\nexport interface UseChannelSubscriptionArgs<TData> {\n /** GraphQL subscription document (string SDL). */\n query: string;\n /** Variables for the subscription. */\n variables?: Record<string, unknown>;\n /** Stable identifier for this subscription, used in error context. */\n operationName: string;\n /** Called for each payload received from the subscription. */\n onData: (data: TData) => void;\n /** Polling fallback invoked when subscription is unavailable / failed. */\n pollFn: () => Promise<void> | void;\n /** Polling interval in ms (default 15s). */\n pollIntervalMs?: number;\n /** Whether to enable the hook at all. */\n enabled?: boolean;\n}\n\n/** Best-effort detector for \"subscription field not found\" errors. */\nfunction isUnknownFieldError(err: unknown): boolean {\n const msg =\n err instanceof Error\n ? err.message\n : typeof err === 'string'\n ? err\n : ((err as { message?: string } | null)?.message ?? '');\n const lower = msg.toLowerCase();\n return (\n lower.includes('cannot query field') ||\n lower.includes('unknown field') ||\n lower.includes('subscription not supported') ||\n lower.includes('not implemented')\n );\n}\n\nexport function useChannelSubscription<TData = unknown>({\n query,\n variables,\n operationName,\n onData,\n pollFn,\n pollIntervalMs = 15_000,\n enabled = true,\n}: UseChannelSubscriptionArgs<TData>) {\n // Refs to onData / pollFn / variables so we don't re-subscribe on every\n // render. Updates happen inside an effect (not during render) per\n // react-hooks/refs.\n const onDataRef = useRef(onData);\n const pollFnRef = useRef(pollFn);\n const variablesRef = useRef(variables);\n useEffect(() => {\n onDataRef.current = onData;\n pollFnRef.current = pollFn;\n variablesRef.current = variables;\n }, [onData, pollFn, variables]);\n\n // Stable JSON of variables for the dependency array — avoids re-subscribing\n // when callers pass a new object literal each render with the same shape.\n const variablesKey = useMemo(() => JSON.stringify(variables ?? {}), [variables]);\n\n useEffect(() => {\n if (!enabled) return;\n\n const wsClient = getGraphqlWsClient();\n let pollTimer: ReturnType<typeof setInterval> | null = null;\n let unsubSub: (() => void) | null = null;\n let cancelled = false;\n\n const startPolling = () => {\n if (pollTimer) return;\n // Kick once immediately, then on interval.\n void Promise.resolve(pollFnRef.current()).catch(() => {});\n pollTimer = setInterval(() => {\n if (cancelled) return;\n void Promise.resolve(pollFnRef.current()).catch(() => {});\n }, pollIntervalMs);\n };\n\n if (!wsClient) {\n // No graphql-ws on the shell yet — fall back to polling.\n startPolling();\n return () => {\n cancelled = true;\n if (pollTimer) clearInterval(pollTimer);\n };\n }\n\n try {\n unsubSub = wsClient.subscribe(\n { query, variables: variablesRef.current, operationName },\n {\n next: (msg) => {\n if (cancelled) return;\n if (msg?.errors && msg.errors.length > 0) {\n // Probe error: if the field doesn't exist, fall back to polling.\n if (msg.errors.some(isUnknownFieldError)) {\n if (unsubSub) {\n try {\n unsubSub();\n } catch {\n /* noop */\n }\n unsubSub = null;\n }\n startPolling();\n return;\n }\n // Other errors — surface to SRE but keep the subscription open.\n reportShellError(\n new Error(`Subscription ${operationName} returned errors`),\n { module: 'channel', context: { operationName, errors: msg.errors } },\n `[channel] subscription ${operationName} errors`\n );\n return;\n }\n if (msg?.data) {\n try {\n onDataRef.current(msg.data as TData);\n } catch (handlerErr) {\n reportShellError(\n handlerErr,\n { module: 'channel', context: { operationName, phase: 'handler' } },\n `[channel] subscription ${operationName} handler threw`\n );\n }\n }\n },\n error: (err) => {\n // Subscription couldn't be opened (closed/unknown-field/etc).\n if (isUnknownFieldError(err)) {\n startPolling();\n return;\n }\n // Real transport error — log and fall back to polling defensively.\n reportShellError(\n err,\n { module: 'channel', context: { operationName, phase: 'transport' } },\n `[channel] subscription ${operationName} transport error`\n );\n startPolling();\n },\n complete: () => {\n // Server closed the stream cleanly — keep data fresh via polling.\n if (!cancelled) startPolling();\n },\n }\n );\n } catch (err) {\n // Defensive: client.subscribe threw synchronously — fall back.\n reportShellError(\n err,\n { module: 'channel', context: { operationName, phase: 'subscribe' } },\n `[channel] subscription ${operationName} subscribe threw`\n );\n startPolling();\n }\n\n return () => {\n cancelled = true;\n if (unsubSub) {\n try {\n unsubSub();\n } catch {\n /* noop */\n }\n }\n if (pollTimer) clearInterval(pollTimer);\n };\n // Only re-create when key inputs change. variablesKey is the stable\n // JSON projection of variables.\n }, [enabled, query, operationName, variablesKey, pollIntervalMs]);\n}\n\n// Subscription documents — kept inline as strings to avoid coupling codegen\n// to subscriptions that aren't always on the gateway. The defensive hook\n// detects \"unknown field\" responses and falls back to polling automatically.\n\nexport const CHANNEL_HEALTH_CHANGED_SUBSCRIPTION = /* GraphQL */ `\n subscription ChannelHealthChanged($organizationId: ID!) {\n channelHealthChanged(organizationId: $organizationId) {\n channelId\n previousHealth\n newHealth\n changedAt\n reason\n }\n }\n`;\n\nexport const WEBHOOK_RECEIVED_SUBSCRIPTION = /* GraphQL */ `\n subscription WebhookReceived($channelId: ID!) {\n webhookReceived(channelId: $channelId) {\n channelId\n organizationId\n webhookEventId\n receivedAt\n platform\n processingStatus\n }\n }\n`;\n"],"mappings":";;;AAqCA,SAAS,EAAoB,GAAuB;CAOlD,IAAM,KALJ,aAAe,QACX,EAAI,UACJ,OAAO,KAAQ,WACb,IACE,GAAqC,WAAW,IACxC,aAAa;AAC/B,QACE,EAAM,SAAS,qBAAqB,IACpC,EAAM,SAAS,gBAAgB,IAC/B,EAAM,SAAS,6BAA6B,IAC5C,EAAM,SAAS,kBAAkB;;AAIrC,SAAgB,EAAwC,EACtD,UACA,cACA,kBACA,WACA,WACA,oBAAiB,MACjB,aAAU,MAC0B;CAIpC,IAAM,IAAY,EAAO,EAAO,EAC1B,IAAY,EAAO,EAAO,EAC1B,IAAe,EAAO,EAAU;AAWtC,CAVA,QAAgB;AAGd,EAFA,EAAU,UAAU,GACpB,EAAU,UAAU,GACpB,EAAa,UAAU;IACtB;EAAC;EAAQ;EAAQ;EAAU,CAAC,EAM/B,QAAgB;AACd,MAAI,CAAC,EAAS;EAEd,IAAM,IAAW,GAAoB,EACjC,IAAmD,MACnD,IAAgC,MAChC,IAAY,IAEV,UAAqB;AACrB,GAGJ,OADK,QAAQ,QAAQ,EAAU,SAAS,CAAC,CAAC,YAAY,GAAG,EAC7C,kBAAkB;AACxB,SACC,QAAQ,QAAQ,EAAU,SAAS,CAAC,CAAC,YAAY,GAAG;MACxD,EAAe;;AAGpB,MAAI,CAAC,EAGH,QADA,GAAc,QACD;AAEX,GADA,IAAY,IACR,KAAW,cAAc,EAAU;;AAI3C,MAAI;AACF,OAAW,EAAS,UAClB;IAAE;IAAO,WAAW,EAAa;IAAS;IAAe,EACzD;IACE,OAAO,MAAQ;AACT,aACJ;UAAI,GAAK,UAAU,EAAI,OAAO,SAAS,GAAG;AAExC,WAAI,EAAI,OAAO,KAAK,EAAoB,EAAE;AACxC,YAAI,GAAU;AACZ,aAAI;AACF,aAAU;iBACJ;AAGR,aAAW;;AAEb,WAAc;AACd;;AAGF,SACE,gBAAI,MAAM,gBAAgB,EAAc,kBAAkB,EAC1D;QAAE,QAAQ;QAAW,SAAS;SAAE;SAAe,QAAQ,EAAI;SAAQ;QAAE,EACrE,0BAA0B,EAAc,SACzC;AACD;;AAEF,UAAI,GAAK,KACP,KAAI;AACF,SAAU,QAAQ,EAAI,KAAc;eAC7B,GAAY;AACnB,SACE,GACA;QAAE,QAAQ;QAAW,SAAS;SAAE;SAAe,OAAO;SAAW;QAAE,EACnE,0BAA0B,EAAc,gBACzC;;;;IAIP,QAAQ,MAAQ;AAEd,SAAI,EAAoB,EAAI,EAAE;AAC5B,SAAc;AACd;;AAQF,KALA,EACE,GACA;MAAE,QAAQ;MAAW,SAAS;OAAE;OAAe,OAAO;OAAa;MAAE,EACrE,0BAA0B,EAAc,kBACzC,EACD,GAAc;;IAEhB,gBAAgB;AAEd,KAAK,KAAW,GAAc;;IAEjC,CACF;WACM,GAAK;AAOZ,GALA,EACE,GACA;IAAE,QAAQ;IAAW,SAAS;KAAE;KAAe,OAAO;KAAa;IAAE,EACrE,0BAA0B,EAAc,kBACzC,EACD,GAAc;;AAGhB,eAAa;AAEX,OADA,IAAY,IACR,EACF,KAAI;AACF,OAAU;WACJ;AAIV,GAAI,KAAW,cAAc,EAAU;;IAIxC;EAAC;EAAS;EAAO;EAhHC,QAAc,KAAK,UAAU,KAAa,EAAE,CAAC,EAAE,CAAC,EAAU,CAAC;EAgH/B;EAAe,CAAC;;AAOnE,IAAa,IAAoD,mOAYpD,IAA8C"}
1
+ {"version":3,"file":"useChannelSubscription.js","names":["isUnknownFieldError","lower","err","useChannelSubscription","onDataRef","useRef","onData","pollFnRef","pollFn","variablesRef","variables","variablesKey","useMemo","enabled","wsClient","getGraphqlWsClient","pollTimer","unsubSub","cancelled","startPolling","pollIntervalMs","msg","operationName","handlerErr","reportShellError","query","CHANNEL_HEALTH_CHANGED_SUBSCRIPTION","WEBHOOK_RECEIVED_SUBSCRIPTION"],"sources":["../../../src/channel/hooks/useChannelSubscription.ts"],"sourcesContent":["/**\n * useChannelSubscription\n *\n * Defensive subscription wrapper. Probes the shell-provided graphql-ws client\n * (`globalThis.__burdenoffShell.graphqlWsClient`); if present, opens a\n * subscription and dispatches each payload to `onData`. If absent — or if the\n * subscription errors with a clear \"unknown field\" / \"not implemented\" signal\n * (the operation isn't on the gateway yet) — silently falls back to a polling\n * loop driven by the caller's `pollFn` at `pollIntervalMs`.\n *\n * Per task 5: backends may grow `webhookReceived`, `connectionStatusChanged`\n * etc. independently; this hook lets the FE wire all four pages without\n * crashing when a subscription isn't yet on the federated schema.\n */\n\nimport { useEffect, useMemo, useRef } from 'react';\nimport { getGraphqlWsClient } from '../utils/shellBridge';\nimport { reportShellError } from '../utils/shellBridge';\n\nexport interface UseChannelSubscriptionArgs<TData> {\n /** GraphQL subscription document (string SDL). */\n query: string;\n /** Variables for the subscription. */\n variables?: Record<string, unknown>;\n /** Stable identifier for this subscription, used in error context. */\n operationName: string;\n /** Called for each payload received from the subscription. */\n onData: (data: TData) => void;\n /** Polling fallback invoked when subscription is unavailable / failed. */\n pollFn: () => Promise<void> | void;\n /** Polling interval in ms (default 15s). */\n pollIntervalMs?: number;\n /** Whether to enable the hook at all. */\n enabled?: boolean;\n}\n\n/** Best-effort detector for \"subscription field not found\" errors. */\nfunction isUnknownFieldError(err: unknown): boolean {\n const msg =\n err instanceof Error\n ? err.message\n : typeof err === 'string'\n ? err\n : ((err as { message?: string } | null)?.message ?? '');\n const lower = msg.toLowerCase();\n return (\n lower.includes('cannot query field') ||\n lower.includes('unknown field') ||\n lower.includes('subscription not supported') ||\n lower.includes('not implemented')\n );\n}\n\nexport function useChannelSubscription<TData = unknown>({\n query,\n variables,\n operationName,\n onData,\n pollFn,\n pollIntervalMs = 15_000,\n enabled = true,\n}: UseChannelSubscriptionArgs<TData>) {\n // Refs to onData / pollFn / variables so we don't re-subscribe on every\n // render. Updates happen inside an effect (not during render) per\n // react-hooks/refs.\n const onDataRef = useRef(onData);\n const pollFnRef = useRef(pollFn);\n const variablesRef = useRef(variables);\n useEffect(() => {\n onDataRef.current = onData;\n pollFnRef.current = pollFn;\n variablesRef.current = variables;\n }, [onData, pollFn, variables]);\n\n // Stable JSON of variables for the dependency array — avoids re-subscribing\n // when callers pass a new object literal each render with the same shape.\n const variablesKey = useMemo(() => JSON.stringify(variables ?? {}), [variables]);\n\n useEffect(() => {\n if (!enabled) return;\n\n const wsClient = getGraphqlWsClient();\n let pollTimer: ReturnType<typeof setInterval> | null = null;\n let unsubSub: (() => void) | null = null;\n let cancelled = false;\n\n const startPolling = () => {\n if (pollTimer) return;\n // Kick once immediately, then on interval.\n void Promise.resolve(pollFnRef.current()).catch(() => {});\n pollTimer = setInterval(() => {\n if (cancelled) return;\n void Promise.resolve(pollFnRef.current()).catch(() => {});\n }, pollIntervalMs);\n };\n\n if (!wsClient) {\n // No graphql-ws on the shell yet — fall back to polling.\n startPolling();\n return () => {\n cancelled = true;\n if (pollTimer) clearInterval(pollTimer);\n };\n }\n\n try {\n unsubSub = wsClient.subscribe(\n { query, variables: variablesRef.current, operationName },\n {\n next: (msg) => {\n if (cancelled) return;\n if (msg?.errors && msg.errors.length > 0) {\n // Probe error: if the field doesn't exist, fall back to polling.\n if (msg.errors.some(isUnknownFieldError)) {\n if (unsubSub) {\n try {\n unsubSub();\n } catch {\n /* noop */\n }\n unsubSub = null;\n }\n startPolling();\n return;\n }\n // Other errors — surface to SRE but keep the subscription open.\n reportShellError(\n new Error(`Subscription ${operationName} returned errors`),\n { module: 'channel', context: { operationName, errors: msg.errors } },\n `[channel] subscription ${operationName} errors`\n );\n return;\n }\n if (msg?.data) {\n try {\n onDataRef.current(msg.data as TData);\n } catch (handlerErr) {\n reportShellError(\n handlerErr,\n { module: 'channel', context: { operationName, phase: 'handler' } },\n `[channel] subscription ${operationName} handler threw`\n );\n }\n }\n },\n error: (err) => {\n // Subscription couldn't be opened (closed/unknown-field/etc).\n if (isUnknownFieldError(err)) {\n startPolling();\n return;\n }\n // Real transport error — log and fall back to polling defensively.\n reportShellError(\n err,\n { module: 'channel', context: { operationName, phase: 'transport' } },\n `[channel] subscription ${operationName} transport error`\n );\n startPolling();\n },\n complete: () => {\n // Server closed the stream cleanly — keep data fresh via polling.\n if (!cancelled) startPolling();\n },\n }\n );\n } catch (err) {\n // Defensive: client.subscribe threw synchronously — fall back.\n reportShellError(\n err,\n { module: 'channel', context: { operationName, phase: 'subscribe' } },\n `[channel] subscription ${operationName} subscribe threw`\n );\n startPolling();\n }\n\n return () => {\n cancelled = true;\n if (unsubSub) {\n try {\n unsubSub();\n } catch {\n /* noop */\n }\n }\n if (pollTimer) clearInterval(pollTimer);\n };\n // Only re-create when key inputs change. variablesKey is the stable\n // JSON projection of variables.\n }, [enabled, query, operationName, variablesKey, pollIntervalMs]);\n}\n\n// Subscription documents — kept inline as strings to avoid coupling codegen\n// to subscriptions that aren't always on the gateway. The defensive hook\n// detects \"unknown field\" responses and falls back to polling automatically.\n\nexport const CHANNEL_HEALTH_CHANGED_SUBSCRIPTION = /* GraphQL */ `\n subscription ChannelHealthChanged($organizationId: ID!) {\n channelHealthChanged(organizationId: $organizationId) {\n channelId\n previousHealth\n newHealth\n changedAt\n reason\n }\n }\n`;\n\nexport const WEBHOOK_RECEIVED_SUBSCRIPTION = /* GraphQL */ `\n subscription WebhookReceived($channelId: ID!) {\n webhookReceived(channelId: $channelId) {\n channelId\n organizationId\n webhookEventId\n receivedAt\n platform\n processingStatus\n }\n }\n`;\n"],"mappings":";;;AAqCA,SAASA,EAAoB,GAAuB;CAOlD,IAAMC,KALJC,aAAe,QACXA,EAAI,UACJ,OAAOA,KAAQ,WACbA,IACEA,GAAqC,WAAW,GAAA,CACxC,YAAY;CAC9B,OACED,EAAM,SAAS,oBAAoB,KACnCA,EAAM,SAAS,eAAe,KAC9BA,EAAM,SAAS,4BAA4B,KAC3CA,EAAM,SAAS,iBAAiB;AAEpC;AAEA,SAAgBE,EAAwC,EACtD,UACA,cACA,kBACA,WACA,WACA,oBAAiB,MACjB,aAAU,MAC0B;CAIpC,IAAMC,IAAYC,EAAOC,CAAM,GACzBC,IAAYF,EAAOG,CAAM,GACzBC,IAAeJ,EAAOK,CAAS;CACrC,QAAgB;EAGd,AAFA,EAAU,UAAUJ,GACpB,EAAU,UAAUE,GACpB,EAAa,UAAUE;CACzB,GAAG;EAACJ;EAAQE;EAAQE;CAAS,CAAC;CAI9B,IAAMC,IAAeC,QAAc,KAAK,UAAUF,KAAa,CAAC,CAAC,GAAG,CAACA,CAAS,CAAC;CAE/E,QAAgB;EACd,IAAI,CAACG,GAAS;EAEd,IAAMC,IAAWC,EAAmB,GAChCC,IAAmD,MACnDC,IAAgC,MAChCC,IAAY,IAEVC,UAAqB;GACzB,AAGAH,OADA,QAAa,QAAQT,EAAU,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAC5C,kBAAkB;IAC5B,AAAIW,KACJ,QAAa,QAAQX,EAAU,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;GAC1D,GAAGa,CAAc;EACnB;EAEA,IAAI,CAACN,GAGH,OADAK,EAAa,SACA;GAEX,AADA,IAAY,IACRH,KAAW,cAAcA,CAAS;EACxC;EAGF,IAAI;GACF,IAAWF,EAAS,UAClB;IAAE;IAAO,WAAWL,EAAa;IAAS;GAAc,GACxD;IACE,OAAO,MAAQ;KACb,IAAI,IACJ;UAAIY,GAAK,UAAUA,EAAI,OAAO,SAAS,GAAG;OAExC,IAAIA,EAAI,OAAO,KAAKrB,CAAmB,GAAG;QACxC,IAAIiB,GAAU;SACZ,IAAI;UACF,EAAS;SACX,QAAQ,CAER;SACA,IAAW;QACb;QACA,EAAa;QACb;OACF;OAEA,EACE,gBAAI,MAAM,gBAAgBK,EAAc,iBAAiB,GACzD;QAAE,QAAQ;QAAW,SAAS;SAAE;SAAe,QAAQD,EAAI;QAAO;OAAE,GACpE,0BAA0BC,EAAc,QAC1C;MAEF,OACA,IAAID,GAAK,MACP,IAAI;OACF,EAAU,QAAQA,EAAI,IAAa;MACrC,SAASE,GAAY;OACnB,EACEA,GACA;QAAE,QAAQ;QAAW,SAAS;SAAE;SAAe,OAAO;QAAU;OAAE,GAClE,0BAA0BD,EAAc,eAC1C;MACF;KAVF;IAYF;IACA,QAAQ,MAAQ;KAEd,AAAItB,EAAoBE,CAAG,KAK3BsB,EACEtB,GACA;MAAE,QAAQ;MAAW,SAAS;OAAE;OAAe,OAAO;MAAY;KAAE,GACpE,0BAA0BoB,EAAc,iBAC1C,GACAH,EAAa;IACf;IACA,gBAAgB;KAEd,AAAKD,KAAWC,EAAa;IAC/B;GACF,CACF;EACF,SAASjB,GAAK;GAOZ,AALAsB,EACEtB,GACA;IAAE,QAAQ;IAAW,SAAS;KAAE;KAAe,OAAO;IAAY;GAAE,GACpE,0BAA0BoB,EAAc,iBAC1C,GACAH,EAAa;EACf;EAEA,aAAa;GAEX,IADA,IAAY,IACRF,GACF,IAAI;IACF,EAAS;GACX,QAAQ,CAER;GAEF,AAAID,KAAW,cAAcA,CAAS;EACxC;CAGF,GAAG;EAACH;EAASY;EAAOH;EAAeX;EAAcS;CAAc,CAAC;AAClE;AAMA,IAAaM,IAAoD,mOAYpDC,IAA8C"}