@automagik/omni 2.260804.2 → 2.260830.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/db/drizzle/0048_message_threads.sql +45 -0
- package/db/drizzle/0049_scheduled_messages.sql +73 -0
- package/db/drizzle/0050_slack_user_token.sql +30 -0
- package/db/drizzle/0051_message_pin_star.sql +27 -0
- package/db/drizzle/meta/_journal.json +28 -0
- package/dist/commands/_setup-helpers.d.ts +50 -0
- package/dist/commands/_setup-helpers.d.ts.map +1 -0
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/events.d.ts.map +1 -1
- package/dist/commands/instances.d.ts +3 -0
- package/dist/commands/instances.d.ts.map +1 -1
- package/dist/commands/schedule.d.ts +24 -0
- package/dist/commands/schedule.d.ts.map +1 -0
- package/dist/commands/setup.d.ts +21 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/slack.d.ts +12 -0
- package/dist/commands/slack.d.ts.map +1 -0
- package/dist/index.js +531 -23
- package/dist/sdk/client.d.ts +68 -0
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +87 -0
- package/dist/server/index.js +1998 -351
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -24040,6 +24040,8 @@ var init_instance = __esm(() => {
|
|
|
24040
24040
|
sessionIdPrefix: exports_external.string().max(50).nullable(),
|
|
24041
24041
|
discordBotToken: exports_external.string().nullable(),
|
|
24042
24042
|
slackBotToken: exports_external.string().nullable(),
|
|
24043
|
+
slackUserToken: exports_external.string().nullable(),
|
|
24044
|
+
slackAuthMode: exports_external.string().nullable(),
|
|
24043
24045
|
slackAppToken: exports_external.string().nullable(),
|
|
24044
24046
|
slackSigningSecret: exports_external.string().nullable(),
|
|
24045
24047
|
telegramBotToken: exports_external.string().nullable(),
|
|
@@ -37375,6 +37377,82 @@ var init_download_guard = __esm(() => {
|
|
|
37375
37377
|
};
|
|
37376
37378
|
});
|
|
37377
37379
|
|
|
37380
|
+
// ../channel-sdk/src/interactive-plan.ts
|
|
37381
|
+
function buttonId(btn, index) {
|
|
37382
|
+
return (btn.data ?? btn.text ?? `btn_${index}`).slice(0, MAX_ID);
|
|
37383
|
+
}
|
|
37384
|
+
function planInteractive(bodyText, buttons, listButtonLabel, listOptions = {}) {
|
|
37385
|
+
const replyButtons = buttons.filter((b2) => !b2.url);
|
|
37386
|
+
const urlButtons = buttons.filter((b2) => b2.url);
|
|
37387
|
+
const soleCta = replyButtons.length === 0 && urlButtons.length === 1 ? urlButtons[0] : undefined;
|
|
37388
|
+
if (soleCta) {
|
|
37389
|
+
return {
|
|
37390
|
+
interactive: {
|
|
37391
|
+
type: "cta_url",
|
|
37392
|
+
body: { text: bodyText },
|
|
37393
|
+
action: {
|
|
37394
|
+
name: "cta_url",
|
|
37395
|
+
parameters: { display_text: truncate(soleCta.text, MAX_BUTTON_TITLE), url: soleCta.url }
|
|
37396
|
+
}
|
|
37397
|
+
},
|
|
37398
|
+
body: bodyText,
|
|
37399
|
+
droppedRows: 0
|
|
37400
|
+
};
|
|
37401
|
+
}
|
|
37402
|
+
let body = bodyText;
|
|
37403
|
+
if (urlButtons.length > 0) {
|
|
37404
|
+
const lines = urlButtons.map((b2) => `${b2.text}: ${b2.url}`);
|
|
37405
|
+
body = body ? `${body}
|
|
37406
|
+
|
|
37407
|
+
${lines.join(`
|
|
37408
|
+
`)}` : lines.join(`
|
|
37409
|
+
`);
|
|
37410
|
+
}
|
|
37411
|
+
if (replyButtons.length === 0) {
|
|
37412
|
+
return { interactive: null, body, droppedRows: 0 };
|
|
37413
|
+
}
|
|
37414
|
+
const wantsList = listOptions.forceList === true || listOptions.sectionTitle !== undefined || replyButtons.some((b2) => b2.description !== undefined);
|
|
37415
|
+
if (replyButtons.length <= MAX_REPLY_BUTTONS && !wantsList) {
|
|
37416
|
+
return {
|
|
37417
|
+
interactive: {
|
|
37418
|
+
type: "button",
|
|
37419
|
+
body: { text: body },
|
|
37420
|
+
action: {
|
|
37421
|
+
buttons: replyButtons.map((b2, i) => ({
|
|
37422
|
+
type: "reply",
|
|
37423
|
+
reply: { id: buttonId(b2, i), title: truncate(b2.text, MAX_BUTTON_TITLE) }
|
|
37424
|
+
}))
|
|
37425
|
+
}
|
|
37426
|
+
},
|
|
37427
|
+
body,
|
|
37428
|
+
droppedRows: 0
|
|
37429
|
+
};
|
|
37430
|
+
}
|
|
37431
|
+
const rows = replyButtons.slice(0, MAX_LIST_ROWS);
|
|
37432
|
+
return {
|
|
37433
|
+
interactive: {
|
|
37434
|
+
type: "list",
|
|
37435
|
+
body: { text: body },
|
|
37436
|
+
action: {
|
|
37437
|
+
button: truncate(listButtonLabel, MAX_BUTTON_TITLE),
|
|
37438
|
+
sections: [
|
|
37439
|
+
{
|
|
37440
|
+
...listOptions.sectionTitle ? { title: truncate(listOptions.sectionTitle, MAX_SECTION_TITLE) } : {},
|
|
37441
|
+
rows: rows.map((b2, i) => ({
|
|
37442
|
+
id: buttonId(b2, i),
|
|
37443
|
+
title: truncate(b2.text, MAX_ROW_TITLE),
|
|
37444
|
+
...b2.description ? { description: truncate(b2.description, MAX_ROW_DESCRIPTION) } : {}
|
|
37445
|
+
}))
|
|
37446
|
+
}
|
|
37447
|
+
]
|
|
37448
|
+
}
|
|
37449
|
+
},
|
|
37450
|
+
body,
|
|
37451
|
+
droppedRows: replyButtons.length - rows.length
|
|
37452
|
+
};
|
|
37453
|
+
}
|
|
37454
|
+
var MAX_REPLY_BUTTONS = 3, MAX_LIST_ROWS = 10, MAX_BUTTON_TITLE = 20, MAX_ROW_TITLE = 24, MAX_ROW_DESCRIPTION = 72, MAX_SECTION_TITLE = 24, MAX_ID = 256, truncate = (s, max) => s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
|
|
37455
|
+
|
|
37378
37456
|
// ../channel-sdk/src/media-backends/config.ts
|
|
37379
37457
|
function boolFromEnv(defaultValue) {
|
|
37380
37458
|
return exports_external.string().optional().transform((value) => {
|
|
@@ -37929,6 +38007,7 @@ __export(exports_src2, {
|
|
|
37929
38007
|
sanitizeOutboundText: () => sanitizeOutboundText,
|
|
37930
38008
|
sanitizeMessage: () => sanitizeMessage,
|
|
37931
38009
|
resolveMediaBackendConfig: () => resolveMediaBackendConfig,
|
|
38010
|
+
planInteractive: () => planInteractive,
|
|
37932
38011
|
parseSubject: () => parseSubject,
|
|
37933
38012
|
parseAssumeRoleWithWebIdentityResponse: () => parseAssumeRoleWithWebIdentityResponse,
|
|
37934
38013
|
matchesPattern: () => matchesPattern,
|
|
@@ -138163,11 +138242,11 @@ var require_applyToDefaults = __commonJS((exports, module) => {
|
|
|
138163
138242
|
return Merge(copy, source, { nullOverride, mergeArrays: false });
|
|
138164
138243
|
};
|
|
138165
138244
|
internals.reachCopy = function(dst, src, path) {
|
|
138166
|
-
for (const
|
|
138167
|
-
if (!(
|
|
138245
|
+
for (const segment2 of path) {
|
|
138246
|
+
if (!(segment2 in src)) {
|
|
138168
138247
|
return;
|
|
138169
138248
|
}
|
|
138170
|
-
const val = src[
|
|
138249
|
+
const val = src[segment2];
|
|
138171
138250
|
if (typeof val !== "object" || val === null) {
|
|
138172
138251
|
return;
|
|
138173
138252
|
}
|
|
@@ -138176,11 +138255,11 @@ var require_applyToDefaults = __commonJS((exports, module) => {
|
|
|
138176
138255
|
const value = src;
|
|
138177
138256
|
let ref = dst;
|
|
138178
138257
|
for (let i = 0;i < path.length - 1; ++i) {
|
|
138179
|
-
const
|
|
138180
|
-
if (typeof ref[
|
|
138181
|
-
ref[
|
|
138258
|
+
const segment2 = path[i];
|
|
138259
|
+
if (typeof ref[segment2] !== "object") {
|
|
138260
|
+
ref[segment2] = {};
|
|
138182
138261
|
}
|
|
138183
|
-
ref = ref[
|
|
138262
|
+
ref = ref[segment2];
|
|
138184
138263
|
}
|
|
138185
138264
|
ref[path[path.length - 1]] = value;
|
|
138186
138265
|
};
|
|
@@ -156479,11 +156558,11 @@ var require_applyToDefaults2 = __commonJS((exports, module) => {
|
|
|
156479
156558
|
return Merge(copy, source, { nullOverride, mergeArrays: false });
|
|
156480
156559
|
};
|
|
156481
156560
|
internals.reachCopy = function(dst, src, path) {
|
|
156482
|
-
for (const
|
|
156483
|
-
if (!(
|
|
156561
|
+
for (const segment2 of path) {
|
|
156562
|
+
if (!(segment2 in src)) {
|
|
156484
156563
|
return;
|
|
156485
156564
|
}
|
|
156486
|
-
const val = src[
|
|
156565
|
+
const val = src[segment2];
|
|
156487
156566
|
if (typeof val !== "object" || val === null) {
|
|
156488
156567
|
return;
|
|
156489
156568
|
}
|
|
@@ -156492,11 +156571,11 @@ var require_applyToDefaults2 = __commonJS((exports, module) => {
|
|
|
156492
156571
|
const value = src;
|
|
156493
156572
|
let ref = dst;
|
|
156494
156573
|
for (let i = 0;i < path.length - 1; ++i) {
|
|
156495
|
-
const
|
|
156496
|
-
if (typeof ref[
|
|
156497
|
-
ref[
|
|
156574
|
+
const segment2 = path[i];
|
|
156575
|
+
if (typeof ref[segment2] !== "object") {
|
|
156576
|
+
ref[segment2] = {};
|
|
156498
156577
|
}
|
|
156499
|
-
ref = ref[
|
|
156578
|
+
ref = ref[segment2];
|
|
156500
156579
|
}
|
|
156501
156580
|
ref[path[path.length - 1]] = value;
|
|
156502
156581
|
};
|
|
@@ -164262,6 +164341,9 @@ __export(exports_schema, {
|
|
|
164262
164341
|
settingValueTypes: () => settingValueTypes,
|
|
164263
164342
|
settingChangeHistoryRelations: () => settingChangeHistoryRelations,
|
|
164264
164343
|
settingChangeHistory: () => settingChangeHistory,
|
|
164344
|
+
scheduledMessages: () => scheduledMessages,
|
|
164345
|
+
scheduledMessageStatuses: () => scheduledMessageStatuses,
|
|
164346
|
+
scheduledMessageDeliveryModes: () => scheduledMessageDeliveryModes,
|
|
164265
164347
|
ruleTypes: () => ruleTypes,
|
|
164266
164348
|
replyFilterMode: () => replyFilterMode,
|
|
164267
164349
|
providerSchemas: () => providerSchemas,
|
|
@@ -164362,7 +164444,7 @@ __export(exports_schema, {
|
|
|
164362
164444
|
accessRules: () => accessRules,
|
|
164363
164445
|
accessModes: () => accessModes
|
|
164364
164446
|
});
|
|
164365
|
-
var channelTypes, agentTypes, agentSystems, agentEntityTypes, debounceMode, splitDelayMode, supersedeMode, replyFilterMode, agentSessionStrategies, ruleTypes, accessModes, settingValueTypes, apiKeyStatuses, apiKeyProfiles, eventTypes, contentTypes, chatTypes, messageSources, messageTypes, messageStatuses, deliveryStatuses, jobStatuses, providerSchemas, agentProviders, agents, agentRoutes, agentSessions, apiKeys, apiKeyAuditLogs, apiKeysRelations, apiKeyAuditLogsRelations, instances, whatsappTemplates, whatsappFlowKeys, persons, platformIdentities, conversations, chats, chatParticipants, omniGroups, messages2, omniEvents, handoffLogs, closeContactOutcomes, closeContactLogs, accessRules, globalSettings, settingChangeHistory, batchJobs, syncJobTypes, syncJobs, mediaContent, chatIdMappings, pluginStorage, agentProvidersRelations, agentsRelations, instancesRelations, syncJobsRelations, personsRelations, platformIdentitiesRelations, conversationsRelations, chatsRelations, chatParticipantsRelations, messagesRelations, omniEventsRelations, accessRulesRelations, globalSettingsRelations, settingChangeHistoryRelations, batchJobsRelations, mediaContentRelations, chatIdMappingsRelations, deadLetterStatuses, deadLetterEvents, payloadStorageConfig, payloadStages, eventPayloads, webhookSources, conditionOperators, actionTypes, automationDebounceModes, automations2, automationLogStatuses, automationLogs, consumerOffsets, automationsRelations, automationLogsRelations, triggerLogs, triggerLogsRelations, agentRoutesRelations, agentTaskStatuses, agentTasks, agentTasksRelations, turnStatuses, turnActions, turns, turnsRelations, followUpDisarmReasons, chatFollowUpState, chatFollowUpStateRelations, processedEvents, genieHosts, tenantStatuses, principalTypes, principalStatuses, tenantRoles, membershipStatuses, credentialClasses, authCredentialStatuses, platformApiKeyStatuses, tenants, principals, tenantMemberships, tenantRolePolicies, platformApiKeys, tenantKeyLineage, authCredentials, tenantAuditLogs, platformAuditLogs, platformProviderCatalog, tenantProviderConfig, platformSettings, tenantSettings, platformSettingChangeHistory, tenantSettingChangeHistory, platformPluginStorage, tenantPluginStorage, platformPayloadStorageConfig, tenantPayloadStorageOverrides, tenantMigrationLedger, tenantMigrationLedgerHistory;
|
|
164447
|
+
var channelTypes, agentTypes, agentSystems, agentEntityTypes, debounceMode, splitDelayMode, supersedeMode, replyFilterMode, agentSessionStrategies, ruleTypes, accessModes, settingValueTypes, apiKeyStatuses, apiKeyProfiles, eventTypes, contentTypes, chatTypes, messageSources, messageTypes, messageStatuses, deliveryStatuses, scheduledMessageDeliveryModes, scheduledMessageStatuses, jobStatuses, providerSchemas, agentProviders, agents, agentRoutes, agentSessions, apiKeys, apiKeyAuditLogs, apiKeysRelations, apiKeyAuditLogsRelations, instances, whatsappTemplates, whatsappFlowKeys, scheduledMessages, persons, platformIdentities, conversations, chats, chatParticipants, omniGroups, messages2, omniEvents, handoffLogs, closeContactOutcomes, closeContactLogs, accessRules, globalSettings, settingChangeHistory, batchJobs, syncJobTypes, syncJobs, mediaContent, chatIdMappings, pluginStorage, agentProvidersRelations, agentsRelations, instancesRelations, syncJobsRelations, personsRelations, platformIdentitiesRelations, conversationsRelations, chatsRelations, chatParticipantsRelations, messagesRelations, omniEventsRelations, accessRulesRelations, globalSettingsRelations, settingChangeHistoryRelations, batchJobsRelations, mediaContentRelations, chatIdMappingsRelations, deadLetterStatuses, deadLetterEvents, payloadStorageConfig, payloadStages, eventPayloads, webhookSources, conditionOperators, actionTypes, automationDebounceModes, automations2, automationLogStatuses, automationLogs, consumerOffsets, automationsRelations, automationLogsRelations, triggerLogs, triggerLogsRelations, agentRoutesRelations, agentTaskStatuses, agentTasks, agentTasksRelations, turnStatuses, turnActions, turns, turnsRelations, followUpDisarmReasons, chatFollowUpState, chatFollowUpStateRelations, processedEvents, genieHosts, tenantStatuses, principalTypes, principalStatuses, tenantRoles, membershipStatuses, credentialClasses, authCredentialStatuses, platformApiKeyStatuses, tenants, principals, tenantMemberships, tenantRolePolicies, platformApiKeys, tenantKeyLineage, authCredentials, tenantAuditLogs, platformAuditLogs, platformProviderCatalog, tenantProviderConfig, platformSettings, tenantSettings, platformSettingChangeHistory, tenantSettingChangeHistory, platformPluginStorage, tenantPluginStorage, platformPayloadStorageConfig, tenantPayloadStorageOverrides, tenantMigrationLedger, tenantMigrationLedgerHistory;
|
|
164366
164448
|
var init_schema2 = __esm(() => {
|
|
164367
164449
|
init_events();
|
|
164368
164450
|
init_types5();
|
|
@@ -164437,6 +164519,8 @@ var init_schema2 = __esm(() => {
|
|
|
164437
164519
|
];
|
|
164438
164520
|
messageStatuses = ["active", "edited", "deleted", "expired"];
|
|
164439
164521
|
deliveryStatuses = ["pending", "sent", "delivered", "read", "failed"];
|
|
164522
|
+
scheduledMessageDeliveryModes = ["platform", "local"];
|
|
164523
|
+
scheduledMessageStatuses = ["pending", "sending", "sent", "canceled", "failed"];
|
|
164440
164524
|
jobStatuses = ["pending", "running", "completed", "failed", "cancelled"];
|
|
164441
164525
|
providerSchemas = [
|
|
164442
164526
|
"agno",
|
|
@@ -164639,6 +164723,8 @@ var init_schema2 = __esm(() => {
|
|
|
164639
164723
|
guildConfigOverrides: jsonb("guild_config_overrides").$type(),
|
|
164640
164724
|
discordPresence: jsonb("discord_presence").$type(),
|
|
164641
164725
|
slackBotToken: text("slack_bot_token"),
|
|
164726
|
+
slackUserToken: text("slack_user_token"),
|
|
164727
|
+
slackAuthMode: varchar("slack_auth_mode", { length: 10 }),
|
|
164642
164728
|
slackAppToken: text("slack_app_token"),
|
|
164643
164729
|
slackSigningSecret: text("slack_signing_secret"),
|
|
164644
164730
|
telegramBotToken: text("telegram_bot_token"),
|
|
@@ -164783,6 +164869,31 @@ var init_schema2 = __esm(() => {
|
|
|
164783
164869
|
}, (t) => ({
|
|
164784
164870
|
instanceUnique: uniqueIndex("idx_wa_flow_keys_instance").on(t.instanceId)
|
|
164785
164871
|
}));
|
|
164872
|
+
scheduledMessages = pgTable("scheduled_messages", {
|
|
164873
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
164874
|
+
instanceId: uuid("instance_id").notNull().references(() => instances.id, { onDelete: "cascade" }),
|
|
164875
|
+
chatExternalId: varchar("chat_external_id", { length: 255 }).notNull(),
|
|
164876
|
+
threadExternalId: varchar("thread_external_id", { length: 255 }),
|
|
164877
|
+
isThreadBroadcast: boolean("is_thread_broadcast").notNull().default(false),
|
|
164878
|
+
content: jsonb("content").$type().notNull(),
|
|
164879
|
+
sendAt: timestamp("send_at", { withTimezone: true }).notNull(),
|
|
164880
|
+
deliveryMode: varchar("delivery_mode", { length: 20 }).notNull().$type(),
|
|
164881
|
+
status: varchar("status", { length: 20 }).notNull().default("pending").$type(),
|
|
164882
|
+
externalScheduledId: varchar("external_scheduled_id", { length: 255 }),
|
|
164883
|
+
sentExternalId: varchar("sent_external_id", { length: 255 }),
|
|
164884
|
+
sentAt: timestamp("sent_at", { withTimezone: true }),
|
|
164885
|
+
canceledAt: timestamp("canceled_at", { withTimezone: true }),
|
|
164886
|
+
failedAt: timestamp("failed_at", { withTimezone: true }),
|
|
164887
|
+
lastError: text("last_error"),
|
|
164888
|
+
attemptCount: integer("attempt_count").notNull().default(0),
|
|
164889
|
+
createdByAgentId: uuid("created_by_agent_id"),
|
|
164890
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
164891
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
164892
|
+
}, (t) => ({
|
|
164893
|
+
dueIdx: index("scheduled_messages_due_idx").on(t.status, t.sendAt),
|
|
164894
|
+
instanceIdx: index("scheduled_messages_instance_idx").on(t.instanceId, t.status),
|
|
164895
|
+
chatIdx: index("scheduled_messages_chat_idx").on(t.instanceId, t.chatExternalId)
|
|
164896
|
+
}));
|
|
164786
164897
|
persons = pgTable("persons", {
|
|
164787
164898
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
164788
164899
|
displayName: varchar("display_name", { length: 255 }),
|
|
@@ -164967,6 +165078,15 @@ var init_schema2 = __esm(() => {
|
|
|
164967
165078
|
replyToExternalId: varchar("reply_to_external_id", { length: 255 }),
|
|
164968
165079
|
quotedText: text("quoted_text"),
|
|
164969
165080
|
quotedSenderName: varchar("quoted_sender_name", { length: 255 }),
|
|
165081
|
+
threadExternalId: varchar("thread_external_id", { length: 255 }),
|
|
165082
|
+
threadRootMessageId: uuid("thread_root_message_id"),
|
|
165083
|
+
isThreadBroadcast: boolean("is_thread_broadcast").notNull().default(false),
|
|
165084
|
+
replyCount: integer("reply_count").notNull().default(0),
|
|
165085
|
+
latestReplyAt: timestamp("latest_reply_at", { withTimezone: true }),
|
|
165086
|
+
permalink: text("permalink"),
|
|
165087
|
+
pinnedAt: timestamp("pinned_at", { withTimezone: true }),
|
|
165088
|
+
pinnedBy: varchar("pinned_by", { length: 255 }),
|
|
165089
|
+
starredAt: timestamp("starred_at", { withTimezone: true }),
|
|
164970
165090
|
forwardedFromMessageId: uuid("forwarded_from_message_id"),
|
|
164971
165091
|
forwardedFromExternalId: varchar("forwarded_from_external_id", { length: 255 }),
|
|
164972
165092
|
forwardCount: integer("forward_count").notNull().default(0),
|
|
@@ -165004,6 +165124,8 @@ var init_schema2 = __esm(() => {
|
|
|
165004
165124
|
platformTimestampIdx: index("messages_platform_timestamp_idx").on(table3.platformTimestamp),
|
|
165005
165125
|
replyToIdx: index("messages_reply_to_idx").on(table3.replyToMessageId),
|
|
165006
165126
|
replyToExternalIdx: index("messages_reply_to_external_idx").on(table3.chatId, table3.replyToExternalId, table3.isFromMe),
|
|
165127
|
+
threadExternalIdx: index("messages_thread_external_idx").on(table3.chatId, table3.threadExternalId, table3.platformTimestamp),
|
|
165128
|
+
threadRootIdx: index("messages_thread_root_idx").on(table3.threadRootMessageId),
|
|
165007
165129
|
hasMediaIdx: index("messages_has_media_idx").on(table3.hasMedia),
|
|
165008
165130
|
originalEventIdx: index("messages_original_event_idx").on(table3.originalEventId)
|
|
165009
165131
|
}));
|
|
@@ -169905,6 +170027,9 @@ __export(exports_src3, {
|
|
|
169905
170027
|
settingChangeHistoryRelations: () => settingChangeHistoryRelations,
|
|
169906
170028
|
settingChangeHistory: () => settingChangeHistory,
|
|
169907
170029
|
scrubDdlCredential: () => scrubDdlCredential,
|
|
170030
|
+
scheduledMessages: () => scheduledMessages,
|
|
170031
|
+
scheduledMessageStatuses: () => scheduledMessageStatuses,
|
|
170032
|
+
scheduledMessageDeliveryModes: () => scheduledMessageDeliveryModes,
|
|
169908
170033
|
ruleTypes: () => ruleTypes,
|
|
169909
170034
|
roleAttributeViolations: () => roleAttributeViolations,
|
|
169910
170035
|
revertTenantRlsEnforcement: () => revertTenantRlsEnforcement,
|
|
@@ -170620,80 +170745,7 @@ var init_reaction = __esm(() => {
|
|
|
170620
170745
|
});
|
|
170621
170746
|
|
|
170622
170747
|
// ../channel-whatsapp-business/src/senders/interactive.ts
|
|
170623
|
-
function
|
|
170624
|
-
return (btn.data ?? btn.text ?? `btn_${index2}`).slice(0, MAX_ID);
|
|
170625
|
-
}
|
|
170626
|
-
function planInteractive(bodyText, buttons, listButtonLabel, listOptions = {}) {
|
|
170627
|
-
const replyButtons = buttons.filter((b3) => !b3.url);
|
|
170628
|
-
const urlButtons = buttons.filter((b3) => b3.url);
|
|
170629
|
-
const soleCta = replyButtons.length === 0 && urlButtons.length === 1 ? urlButtons[0] : undefined;
|
|
170630
|
-
if (soleCta) {
|
|
170631
|
-
return {
|
|
170632
|
-
interactive: {
|
|
170633
|
-
type: "cta_url",
|
|
170634
|
-
body: { text: bodyText },
|
|
170635
|
-
action: {
|
|
170636
|
-
name: "cta_url",
|
|
170637
|
-
parameters: { display_text: truncate2(soleCta.text, MAX_BUTTON_TITLE), url: soleCta.url }
|
|
170638
|
-
}
|
|
170639
|
-
},
|
|
170640
|
-
body: bodyText,
|
|
170641
|
-
droppedRows: 0
|
|
170642
|
-
};
|
|
170643
|
-
}
|
|
170644
|
-
let body = bodyText;
|
|
170645
|
-
if (urlButtons.length > 0) {
|
|
170646
|
-
const lines = urlButtons.map((b3) => `${b3.text}: ${b3.url}`);
|
|
170647
|
-
body = body ? `${body}
|
|
170648
|
-
|
|
170649
|
-
${lines.join(`
|
|
170650
|
-
`)}` : lines.join(`
|
|
170651
|
-
`);
|
|
170652
|
-
}
|
|
170653
|
-
if (replyButtons.length === 0) {
|
|
170654
|
-
return { interactive: null, body, droppedRows: 0 };
|
|
170655
|
-
}
|
|
170656
|
-
const wantsList = listOptions.forceList === true || listOptions.sectionTitle !== undefined || replyButtons.some((b3) => b3.description !== undefined);
|
|
170657
|
-
if (replyButtons.length <= MAX_REPLY_BUTTONS && !wantsList) {
|
|
170658
|
-
return {
|
|
170659
|
-
interactive: {
|
|
170660
|
-
type: "button",
|
|
170661
|
-
body: { text: body },
|
|
170662
|
-
action: {
|
|
170663
|
-
buttons: replyButtons.map((b3, i) => ({
|
|
170664
|
-
type: "reply",
|
|
170665
|
-
reply: { id: buttonId(b3, i), title: truncate2(b3.text, MAX_BUTTON_TITLE) }
|
|
170666
|
-
}))
|
|
170667
|
-
}
|
|
170668
|
-
},
|
|
170669
|
-
body,
|
|
170670
|
-
droppedRows: 0
|
|
170671
|
-
};
|
|
170672
|
-
}
|
|
170673
|
-
const rows = replyButtons.slice(0, MAX_LIST_ROWS);
|
|
170674
|
-
return {
|
|
170675
|
-
interactive: {
|
|
170676
|
-
type: "list",
|
|
170677
|
-
body: { text: body },
|
|
170678
|
-
action: {
|
|
170679
|
-
button: truncate2(listButtonLabel, MAX_BUTTON_TITLE),
|
|
170680
|
-
sections: [
|
|
170681
|
-
{
|
|
170682
|
-
...listOptions.sectionTitle ? { title: truncate2(listOptions.sectionTitle, MAX_SECTION_TITLE) } : {},
|
|
170683
|
-
rows: rows.map((b3, i) => ({
|
|
170684
|
-
id: buttonId(b3, i),
|
|
170685
|
-
title: truncate2(b3.text, MAX_ROW_TITLE),
|
|
170686
|
-
...b3.description ? { description: truncate2(b3.description, MAX_ROW_DESCRIPTION) } : {}
|
|
170687
|
-
}))
|
|
170688
|
-
}
|
|
170689
|
-
]
|
|
170690
|
-
}
|
|
170691
|
-
},
|
|
170692
|
-
body,
|
|
170693
|
-
droppedRows: replyButtons.length - rows.length
|
|
170694
|
-
};
|
|
170695
|
-
}
|
|
170696
|
-
async function sendLocationRequest(client, to, bodyText, replyTo) {
|
|
170748
|
+
async function sendLocationRequest2(client, to, bodyText, replyTo) {
|
|
170697
170749
|
const payload = {
|
|
170698
170750
|
messaging_product: "whatsapp",
|
|
170699
170751
|
recipient_type: "individual",
|
|
@@ -170728,8 +170780,9 @@ async function sendInteractive(client, to, bodyText, buttons, replyTo, listButto
|
|
|
170728
170780
|
payload.context = { message_id: replyTo };
|
|
170729
170781
|
return { response: await client.sendMessage(payload), droppedRows: plan.droppedRows };
|
|
170730
170782
|
}
|
|
170731
|
-
var
|
|
170732
|
-
|
|
170783
|
+
var init_interactive = __esm(() => {
|
|
170784
|
+
init_src2();
|
|
170785
|
+
});
|
|
170733
170786
|
|
|
170734
170787
|
// ../channel-whatsapp-business/src/senders/flow.ts
|
|
170735
170788
|
async function sendFlow(client, to, flow, replyTo) {
|
|
@@ -170807,7 +170860,7 @@ var init_senders = __esm(() => {
|
|
|
170807
170860
|
async function dispatchOutbound2(client, message2, logger6) {
|
|
170808
170861
|
const { content, to, replyTo } = message2;
|
|
170809
170862
|
if (content.type === "text") {
|
|
170810
|
-
return { ok: true, response: await
|
|
170863
|
+
return { ok: true, response: await dispatchOutboundText2(client, message2, logger6) };
|
|
170811
170864
|
}
|
|
170812
170865
|
if (META_MEDIA_TYPES.has(content.type)) {
|
|
170813
170866
|
return {
|
|
@@ -170833,7 +170886,7 @@ async function dispatchOutbound2(client, message2, logger6) {
|
|
|
170833
170886
|
return { ok: true, response: await sendReaction3(client, to, content.targetMessageId ?? "", content.emoji ?? "") };
|
|
170834
170887
|
}
|
|
170835
170888
|
if (content.type === "location_request") {
|
|
170836
|
-
return { ok: true, response: await
|
|
170889
|
+
return { ok: true, response: await sendLocationRequest2(client, to, content.text ?? "", replyTo) };
|
|
170837
170890
|
}
|
|
170838
170891
|
if (content.type === "template") {
|
|
170839
170892
|
return dispatchOutboundTemplate2(client, message2);
|
|
@@ -170854,7 +170907,7 @@ async function dispatchOutboundFlow(client, message2) {
|
|
|
170854
170907
|
const { response } = await sendFlow(client, message2.to, parsed.data, message2.replyTo);
|
|
170855
170908
|
return { ok: true, response };
|
|
170856
170909
|
}
|
|
170857
|
-
async function
|
|
170910
|
+
async function dispatchOutboundText2(client, message2, logger6) {
|
|
170858
170911
|
const { content, to, replyTo } = message2;
|
|
170859
170912
|
const formatMode = message2.metadata?.messageFormatMode ?? "convert";
|
|
170860
170913
|
const text3 = content.text ?? "";
|
|
@@ -171385,6 +171438,7 @@ var init_plugin = __esm(() => {
|
|
|
171385
171438
|
type: content.type,
|
|
171386
171439
|
text: content.text ?? content.caption,
|
|
171387
171440
|
mediaUrl: content.mediaUrl,
|
|
171441
|
+
mediaId: content.mediaId,
|
|
171388
171442
|
mimeType: content.mimeType,
|
|
171389
171443
|
isVoiceNote: content.isVoiceNote
|
|
171390
171444
|
},
|
|
@@ -188043,7 +188097,7 @@ function shouldIgnoreSpansForIncomingRequest(request, {
|
|
|
188043
188097
|
ignoreStaticAssets,
|
|
188044
188098
|
ignoreIncomingRequests
|
|
188045
188099
|
}) {
|
|
188046
|
-
if (
|
|
188100
|
+
if (import_core61.isTracingSuppressed(import_api7.context.active())) {
|
|
188047
188101
|
return true;
|
|
188048
188102
|
}
|
|
188049
188103
|
const urlPath = request.url;
|
|
@@ -188095,7 +188149,7 @@ function getIncomingRequestAttributesOnResponse(request, response) {
|
|
|
188095
188149
|
[import_semantic_conventions.SEMATTRS_HTTP_STATUS_CODE]: statusCode,
|
|
188096
188150
|
"http.status_text": statusMessage?.toUpperCase()
|
|
188097
188151
|
};
|
|
188098
|
-
const rpcMetadata =
|
|
188152
|
+
const rpcMetadata = import_core61.getRPCMetadata(import_api7.context.active());
|
|
188099
188153
|
if (socket) {
|
|
188100
188154
|
const { localAddress, localPort, remoteAddress, remotePort } = socket;
|
|
188101
188155
|
newAttributes[import_semantic_conventions.SEMATTRS_NET_HOST_IP] = localAddress;
|
|
@@ -188105,7 +188159,7 @@ function getIncomingRequestAttributesOnResponse(request, response) {
|
|
|
188105
188159
|
}
|
|
188106
188160
|
newAttributes[import_semantic_conventions.SEMATTRS_HTTP_STATUS_CODE] = statusCode;
|
|
188107
188161
|
newAttributes["http.status_text"] = (statusMessage || "").toUpperCase();
|
|
188108
|
-
if (rpcMetadata?.type ===
|
|
188162
|
+
if (rpcMetadata?.type === import_core61.RPCType.HTTP && rpcMetadata.route !== undefined) {
|
|
188109
188163
|
const routeName = rpcMetadata.route;
|
|
188110
188164
|
newAttributes[import_semantic_conventions.ATTR_HTTP_ROUTE] = routeName;
|
|
188111
188165
|
}
|
|
@@ -188120,7 +188174,7 @@ function shouldFilterStatusCode(statusCode, dropForStatusCodes) {
|
|
|
188120
188174
|
return statusCode >= min && statusCode <= max;
|
|
188121
188175
|
});
|
|
188122
188176
|
}
|
|
188123
|
-
var import_api7,
|
|
188177
|
+
var import_api7, import_core61, import_semantic_conventions, INTEGRATION_NAME8 = "Http.ServerSpans", _httpServerSpansIntegration = (options = {}) => {
|
|
188124
188178
|
const ignoreStaticAssets = options.ignoreStaticAssets ?? true;
|
|
188125
188179
|
const ignoreIncomingRequests = options.ignoreIncomingRequests;
|
|
188126
188180
|
const ignoreStatusCodes = options.ignoreStatusCodes ?? [
|
|
@@ -188185,10 +188239,10 @@ var import_api7, import_core60, import_semantic_conventions, INTEGRATION_NAME8 =
|
|
|
188185
188239
|
applyCustomAttributesOnSpan?.(span, request, response);
|
|
188186
188240
|
onSpanCreated?.(span, request, response);
|
|
188187
188241
|
const rpcMetadata = {
|
|
188188
|
-
type:
|
|
188242
|
+
type: import_core61.RPCType.HTTP,
|
|
188189
188243
|
span
|
|
188190
188244
|
};
|
|
188191
|
-
return import_api7.context.with(
|
|
188245
|
+
return import_api7.context.with(import_core61.setRPCMetadata(import_api7.trace.setSpan(import_api7.context.active(), span), rpcMetadata), () => {
|
|
188192
188246
|
import_api7.context.bind(import_api7.context.active(), request);
|
|
188193
188247
|
import_api7.context.bind(import_api7.context.active(), response);
|
|
188194
188248
|
let isEnded = false;
|
|
@@ -188250,7 +188304,7 @@ var init_httpServerSpansIntegration = __esm(() => {
|
|
|
188250
188304
|
init_debug_build2();
|
|
188251
188305
|
init_httpServerIntegration();
|
|
188252
188306
|
import_api7 = __toESM(require_src(), 1);
|
|
188253
|
-
|
|
188307
|
+
import_core61 = __toESM(require_src6(), 1);
|
|
188254
188308
|
import_semantic_conventions = __toESM(require_src5(), 1);
|
|
188255
188309
|
httpServerSpansIntegration = _httpServerSpansIntegration;
|
|
188256
188310
|
});
|
|
@@ -190084,13 +190138,13 @@ import { subscribe as subscribe2 } from "diagnostics_channel";
|
|
|
190084
190138
|
import { errorMonitor as errorMonitor2 } from "events";
|
|
190085
190139
|
import * as http from "http";
|
|
190086
190140
|
import * as https from "https";
|
|
190087
|
-
var import_api8,
|
|
190141
|
+
var import_api8, import_core64, import_instrumentation, FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL, SentryHttpInstrumentation;
|
|
190088
190142
|
var init_SentryHttpInstrumentation = __esm(() => {
|
|
190089
190143
|
init_esm();
|
|
190090
190144
|
init_constants10();
|
|
190091
190145
|
init_nodeVersion();
|
|
190092
190146
|
import_api8 = __toESM(require_src(), 1);
|
|
190093
|
-
|
|
190147
|
+
import_core64 = __toESM(require_src6(), 1);
|
|
190094
190148
|
import_instrumentation = __toESM(require_src8(), 1);
|
|
190095
190149
|
FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL = NODE_VERSION.major === 22 && NODE_VERSION.minor >= 12 || NODE_VERSION.major === 23 && NODE_VERSION.minor >= 2 || NODE_VERSION.major >= 24;
|
|
190096
190150
|
SentryHttpInstrumentation = class SentryHttpInstrumentation extends import_instrumentation.InstrumentationBase {
|
|
@@ -190105,7 +190159,7 @@ var init_SentryHttpInstrumentation = __esm(() => {
|
|
|
190105
190159
|
...options,
|
|
190106
190160
|
spans: options.createSpansForOutgoingRequests && (options.spans ?? true),
|
|
190107
190161
|
ignoreOutgoingRequests(url, request) {
|
|
190108
|
-
return
|
|
190162
|
+
return import_core64.isTracingSuppressed(import_api8.context.active()) || !!options.ignoreOutgoingRequests?.(url, getRequestOptions(request));
|
|
190109
190163
|
},
|
|
190110
190164
|
outgoingRequestHook(span, request) {
|
|
190111
190165
|
options.outgoingRequestHook?.(span, request);
|
|
@@ -190325,13 +190379,13 @@ var init_outgoingFetchRequest = __esm(() => {
|
|
|
190325
190379
|
|
|
190326
190380
|
// ../../node_modules/.bun/@sentry+node-core@10.52.0+6488de8736d8e524/node_modules/@sentry/node-core/build/esm/integrations/node-fetch/SentryNodeFetchInstrumentation.js
|
|
190327
190381
|
import * as diagch from "diagnostics_channel";
|
|
190328
|
-
var import_api9,
|
|
190382
|
+
var import_api9, import_core67, import_instrumentation2, SentryNodeFetchInstrumentation;
|
|
190329
190383
|
var init_SentryNodeFetchInstrumentation = __esm(() => {
|
|
190330
190384
|
init_esm();
|
|
190331
190385
|
init_nodeVersion();
|
|
190332
190386
|
init_outgoingFetchRequest();
|
|
190333
190387
|
import_api9 = __toESM(require_src(), 1);
|
|
190334
|
-
|
|
190388
|
+
import_core67 = __toESM(require_src6(), 1);
|
|
190335
190389
|
import_instrumentation2 = __toESM(require_src8(), 1);
|
|
190336
190390
|
SentryNodeFetchInstrumentation = class SentryNodeFetchInstrumentation extends import_instrumentation2.InstrumentationBase {
|
|
190337
190391
|
constructor(config2 = {}) {
|
|
@@ -190402,7 +190456,7 @@ var init_SentryNodeFetchInstrumentation = __esm(() => {
|
|
|
190402
190456
|
});
|
|
190403
190457
|
}
|
|
190404
190458
|
_shouldIgnoreOutgoingRequest(request) {
|
|
190405
|
-
if (
|
|
190459
|
+
if (import_core67.isTracingSuppressed(import_api9.context.active())) {
|
|
190406
190460
|
return true;
|
|
190407
190461
|
}
|
|
190408
190462
|
const url = getAbsoluteUrl2(request.origin, request.path);
|
|
@@ -192762,7 +192816,7 @@ function makeTraceState({
|
|
|
192762
192816
|
sampled
|
|
192763
192817
|
}) {
|
|
192764
192818
|
const dscString = dsc ? dynamicSamplingContextToSentryBaggageHeader(dsc) : undefined;
|
|
192765
|
-
const traceStateBase = new
|
|
192819
|
+
const traceStateBase = new import_core70.TraceState;
|
|
192766
192820
|
const traceStateWithDsc = dscString ? traceStateBase.set(SENTRY_TRACE_STATE_DSC, dscString) : traceStateBase;
|
|
192767
192821
|
return sampled === false ? traceStateWithDsc.set(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING, "1") : traceStateWithDsc;
|
|
192768
192822
|
}
|
|
@@ -192886,13 +192940,13 @@ function _startSpan(options, callback, autoEnd) {
|
|
|
192886
192940
|
return wrapper(() => {
|
|
192887
192941
|
const activeCtx = getContext(options.scope, options.forceTransaction);
|
|
192888
192942
|
const missingRequiredParent = options.onlyIfParent && !import_api10.trace.getSpan(activeCtx);
|
|
192889
|
-
const ctx = missingRequiredParent ?
|
|
192943
|
+
const ctx = missingRequiredParent ? import_core70.suppressTracing(activeCtx) : activeCtx;
|
|
192890
192944
|
if (missingRequiredParent) {
|
|
192891
192945
|
getClient()?.recordDroppedEvent("no_parent_span", "span");
|
|
192892
192946
|
}
|
|
192893
192947
|
const spanOptions = getSpanOptions(options);
|
|
192894
192948
|
if (!hasSpansEnabled()) {
|
|
192895
|
-
const suppressedCtx =
|
|
192949
|
+
const suppressedCtx = import_core70.isTracingSuppressed(ctx) ? ctx : import_core70.suppressTracing(ctx);
|
|
192896
192950
|
return import_api10.context.with(suppressedCtx, () => {
|
|
192897
192951
|
return tracer2.startActiveSpan(name, spanOptions, suppressedCtx, (span) => {
|
|
192898
192952
|
patchSpanEnd(span);
|
|
@@ -192929,13 +192983,13 @@ function startInactiveSpan2(options) {
|
|
|
192929
192983
|
return wrapper(() => {
|
|
192930
192984
|
const activeCtx = getContext(options.scope, options.forceTransaction);
|
|
192931
192985
|
const missingRequiredParent = options.onlyIfParent && !import_api10.trace.getSpan(activeCtx);
|
|
192932
|
-
let ctx = missingRequiredParent ?
|
|
192986
|
+
let ctx = missingRequiredParent ? import_core70.suppressTracing(activeCtx) : activeCtx;
|
|
192933
192987
|
if (missingRequiredParent) {
|
|
192934
192988
|
getClient()?.recordDroppedEvent("no_parent_span", "span");
|
|
192935
192989
|
}
|
|
192936
192990
|
const spanOptions = getSpanOptions(options);
|
|
192937
192991
|
if (!hasSpansEnabled()) {
|
|
192938
|
-
ctx =
|
|
192992
|
+
ctx = import_core70.isTracingSuppressed(ctx) ? ctx : import_core70.suppressTracing(ctx);
|
|
192939
192993
|
}
|
|
192940
192994
|
const span = tracer2.startSpan(name, spanOptions, ctx);
|
|
192941
192995
|
patchSpanEnd(span);
|
|
@@ -193044,7 +193098,7 @@ function getActiveSpanWrapper2(parentSpan) {
|
|
|
193044
193098
|
} : (callback) => callback();
|
|
193045
193099
|
}
|
|
193046
193100
|
function suppressTracing2(callback) {
|
|
193047
|
-
const ctx =
|
|
193101
|
+
const ctx = import_core70.suppressTracing(import_api10.context.active());
|
|
193048
193102
|
return import_api10.context.with(ctx, callback);
|
|
193049
193103
|
}
|
|
193050
193104
|
function setupEventContextTrace(client) {
|
|
@@ -193731,7 +193785,7 @@ function wrapSamplingDecision({
|
|
|
193731
193785
|
function getBaseTraceState(context8, spanAttributes) {
|
|
193732
193786
|
const parentSpan = import_api10.trace.getSpan(context8);
|
|
193733
193787
|
const parentContext = parentSpan?.spanContext();
|
|
193734
|
-
let traceState = parentContext?.traceState || new
|
|
193788
|
+
let traceState = parentContext?.traceState || new import_core70.TraceState;
|
|
193735
193789
|
const url = spanAttributes[import_semantic_conventions2.SEMATTRS_HTTP_URL] || spanAttributes[import_semantic_conventions2.ATTR_URL_FULL];
|
|
193736
193790
|
if (url && typeof url === "string") {
|
|
193737
193791
|
traceState = traceState.set(SENTRY_TRACE_STATE_URL, url);
|
|
@@ -193792,12 +193846,12 @@ function getSentryResource(serviceNameFallback) {
|
|
|
193792
193846
|
...otelResourceAttrs,
|
|
193793
193847
|
...otelServiceName ? { [import_semantic_conventions2.ATTR_SERVICE_NAME]: otelServiceName } : {},
|
|
193794
193848
|
[import_semantic_conventions2.ATTR_SERVICE_VERSION]: SDK_VERSION,
|
|
193795
|
-
[import_semantic_conventions2.ATTR_TELEMETRY_SDK_LANGUAGE]:
|
|
193796
|
-
[import_semantic_conventions2.ATTR_TELEMETRY_SDK_NAME]:
|
|
193797
|
-
[import_semantic_conventions2.ATTR_TELEMETRY_SDK_VERSION]:
|
|
193849
|
+
[import_semantic_conventions2.ATTR_TELEMETRY_SDK_LANGUAGE]: import_core70.SDK_INFO[import_semantic_conventions2.ATTR_TELEMETRY_SDK_LANGUAGE],
|
|
193850
|
+
[import_semantic_conventions2.ATTR_TELEMETRY_SDK_NAME]: import_core70.SDK_INFO[import_semantic_conventions2.ATTR_TELEMETRY_SDK_NAME],
|
|
193851
|
+
[import_semantic_conventions2.ATTR_TELEMETRY_SDK_VERSION]: import_core70.SDK_INFO[import_semantic_conventions2.ATTR_TELEMETRY_SDK_VERSION]
|
|
193798
193852
|
});
|
|
193799
193853
|
}
|
|
193800
|
-
var api, import_api10, import_semantic_conventions2,
|
|
193854
|
+
var api, import_api10, import_semantic_conventions2, import_core70, import_sdk_trace_base, SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE = "sentry.parentIsRemote", SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION = "sentry.graphql.operation", SENTRY_TRACE_HEADER2 = "sentry-trace", SENTRY_BAGGAGE_HEADER2 = "baggage", SENTRY_TRACE_STATE_DSC = "sentry.dsc", SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING = "sentry.sampled_not_recording", SENTRY_TRACE_STATE_URL = "sentry.url", SENTRY_TRACE_STATE_SAMPLE_RAND = "sentry.sample_rand", SENTRY_TRACE_STATE_SAMPLE_RATE = "sentry.sample_rate", SENTRY_TRACE_STATE_CHILD_IGNORED = "sentry.ignored", SENTRY_TRACE_STATE_SEGMENT_IGNORED = "sentry.segment_ignored", SENTRY_SCOPES_CONTEXT_KEY, SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY, SENTRY_FORK_SET_SCOPE_CONTEXT_KEY, SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY, SCOPE_CONTEXT_FIELD = "_scopeContext", setupElements, SentryPropagator, canonicalGrpcErrorCodesMap, isStatusErrorMessageValid = (message2) => {
|
|
193801
193855
|
return Object.values(canonicalGrpcErrorCodesMap).includes(message2);
|
|
193802
193856
|
}, MAX_SPAN_COUNT2 = 1000, DEFAULT_TIMEOUT = 300;
|
|
193803
193857
|
var init_resource_Bhpm2sLf = __esm(() => {
|
|
@@ -193806,21 +193860,21 @@ var init_resource_Bhpm2sLf = __esm(() => {
|
|
|
193806
193860
|
api = __toESM(require_src(), 1);
|
|
193807
193861
|
import_api10 = __toESM(require_src(), 1);
|
|
193808
193862
|
import_semantic_conventions2 = __toESM(require_src5(), 1);
|
|
193809
|
-
|
|
193863
|
+
import_core70 = __toESM(require_src6(), 1);
|
|
193810
193864
|
import_sdk_trace_base = __toESM(require_src10(), 1);
|
|
193811
193865
|
SENTRY_SCOPES_CONTEXT_KEY = import_api10.createContextKey("sentry_scopes");
|
|
193812
193866
|
SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY = import_api10.createContextKey("sentry_fork_isolation_scope");
|
|
193813
193867
|
SENTRY_FORK_SET_SCOPE_CONTEXT_KEY = import_api10.createContextKey("sentry_fork_set_scope");
|
|
193814
193868
|
SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY = import_api10.createContextKey("sentry_fork_set_isolation_scope");
|
|
193815
193869
|
setupElements = new Set;
|
|
193816
|
-
SentryPropagator = class SentryPropagator extends
|
|
193870
|
+
SentryPropagator = class SentryPropagator extends import_core70.W3CBaggagePropagator {
|
|
193817
193871
|
constructor() {
|
|
193818
193872
|
super();
|
|
193819
193873
|
setIsSetup("SentryPropagator");
|
|
193820
193874
|
this._urlMatchesTargetsMap = new LRUMap(100);
|
|
193821
193875
|
}
|
|
193822
193876
|
inject(context8, carrier, setter) {
|
|
193823
|
-
if (
|
|
193877
|
+
if (import_core70.isTracingSuppressed(context8)) {
|
|
193824
193878
|
DEBUG_BUILD3 && debug32.log("[Tracing] Not injecting trace data for url because tracing is suppressed.");
|
|
193825
193879
|
return;
|
|
193826
193880
|
}
|
|
@@ -196669,12 +196723,12 @@ var init_http3 = __esm(() => {
|
|
|
196669
196723
|
// ../../node_modules/.bun/@sentry+node@10.52.0+1b9a589cee1ff949/node_modules/@sentry/node/build/esm/integrations/node-fetch/vendored/undici.js
|
|
196670
196724
|
import * as diagch2 from "diagnostics_channel";
|
|
196671
196725
|
import { URL as URL4 } from "url";
|
|
196672
|
-
var import_instrumentation5, import_api15,
|
|
196726
|
+
var import_instrumentation5, import_api15, import_core99, import_semantic_conventions3, PACKAGE_NAME = "@sentry/instrumentation-undici", UndiciInstrumentation;
|
|
196673
196727
|
var init_undici = __esm(() => {
|
|
196674
196728
|
init_esm();
|
|
196675
196729
|
import_instrumentation5 = __toESM(require_src8(), 1);
|
|
196676
196730
|
import_api15 = __toESM(require_src(), 1);
|
|
196677
|
-
|
|
196731
|
+
import_core99 = __toESM(require_src6(), 1);
|
|
196678
196732
|
import_semantic_conventions3 = __toESM(require_src5(), 1);
|
|
196679
196733
|
UndiciInstrumentation = class UndiciInstrumentation extends import_instrumentation5.InstrumentationBase {
|
|
196680
196734
|
__init() {
|
|
@@ -196773,7 +196827,7 @@ var init_undici = __esm(() => {
|
|
|
196773
196827
|
if (shouldIgnoreReq) {
|
|
196774
196828
|
return;
|
|
196775
196829
|
}
|
|
196776
|
-
const startTime =
|
|
196830
|
+
const startTime = import_core99.hrTime();
|
|
196777
196831
|
let requestUrl;
|
|
196778
196832
|
try {
|
|
196779
196833
|
requestUrl = new URL4(request2.path, request2.origin);
|
|
@@ -196946,7 +197000,7 @@ var init_undici = __esm(() => {
|
|
|
196946
197000
|
metricsAttributes[key] = attributes[key];
|
|
196947
197001
|
}
|
|
196948
197002
|
});
|
|
196949
|
-
const durationSeconds =
|
|
197003
|
+
const durationSeconds = import_core99.hrTimeToMilliseconds(import_core99.hrTimeDuration(startTime, import_core99.hrTime())) / 1000;
|
|
196950
197004
|
this._httpClientDurationHistogram.record(durationSeconds, metricsAttributes);
|
|
196951
197005
|
}
|
|
196952
197006
|
getRequestMethod(original) {
|
|
@@ -197491,7 +197545,7 @@ var init_debug_build3 = __esm(() => {
|
|
|
197491
197545
|
});
|
|
197492
197546
|
|
|
197493
197547
|
// ../../node_modules/.bun/@sentry+node@10.52.0+1b9a589cee1ff949/node_modules/@sentry/node/build/esm/integrations/tracing/express.js
|
|
197494
|
-
var import_instrumentation6, import_api16,
|
|
197548
|
+
var import_instrumentation6, import_api16, import_core102, INTEGRATION_NAME23 = "Express", SUPPORTED_VERSIONS, instrumentExpress, ExpressInstrumentation, _expressIntegration = (options) => {
|
|
197495
197549
|
return {
|
|
197496
197550
|
name: INTEGRATION_NAME23,
|
|
197497
197551
|
setupOnce() {
|
|
@@ -197505,7 +197559,7 @@ var init_express2 = __esm(() => {
|
|
|
197505
197559
|
init_debug_build3();
|
|
197506
197560
|
import_instrumentation6 = __toESM(require_src8(), 1);
|
|
197507
197561
|
import_api16 = __toESM(require_src(), 1);
|
|
197508
|
-
|
|
197562
|
+
import_core102 = __toESM(require_src6(), 1);
|
|
197509
197563
|
SUPPORTED_VERSIONS = [">=4.0.0 <6"];
|
|
197510
197564
|
instrumentExpress = generateInstrumentOnce(INTEGRATION_NAME23, (options) => new ExpressInstrumentation(options));
|
|
197511
197565
|
ExpressInstrumentation = class ExpressInstrumentation extends import_instrumentation6.InstrumentationBase {
|
|
@@ -197518,8 +197572,8 @@ var init_express2 = __esm(() => {
|
|
|
197518
197572
|
patchExpressModule(express, () => ({
|
|
197519
197573
|
...this.getConfig(),
|
|
197520
197574
|
onRouteResolved(route) {
|
|
197521
|
-
const rpcMetadata =
|
|
197522
|
-
if (route && rpcMetadata?.type ===
|
|
197575
|
+
const rpcMetadata = import_core102.getRPCMetadata(import_api16.context.active());
|
|
197576
|
+
if (route && rpcMetadata?.type === import_core102.RPCType.HTTP) {
|
|
197523
197577
|
rpcMetadata.route = route;
|
|
197524
197578
|
}
|
|
197525
197579
|
}
|
|
@@ -201415,13 +201469,13 @@ function addFastifyV3SpanAttributes(span) {
|
|
|
201415
201469
|
span.updateName(updatedName);
|
|
201416
201470
|
}
|
|
201417
201471
|
}
|
|
201418
|
-
var import_api18,
|
|
201472
|
+
var import_api18, import_core104, import_instrumentation7, import_semantic_conventions4, PACKAGE_VERSION = "0.1.0", PACKAGE_NAME2 = "@sentry/instrumentation-fastify-v3", ANONYMOUS_NAME = "anonymous", hooksNamesToWrap, FastifyInstrumentationV3;
|
|
201419
201473
|
var init_instrumentation = __esm(() => {
|
|
201420
201474
|
init_esm();
|
|
201421
201475
|
init_AttributeNames();
|
|
201422
201476
|
init_utils14();
|
|
201423
201477
|
import_api18 = __toESM(require_src(), 1);
|
|
201424
|
-
|
|
201478
|
+
import_core104 = __toESM(require_src6(), 1);
|
|
201425
201479
|
import_instrumentation7 = __toESM(require_src8(), 1);
|
|
201426
201480
|
import_semantic_conventions4 = __toESM(require_src5(), 1);
|
|
201427
201481
|
hooksNamesToWrap = new Set([
|
|
@@ -201454,9 +201508,9 @@ var init_instrumentation = __esm(() => {
|
|
|
201454
201508
|
}
|
|
201455
201509
|
instrumentation._wrap(reply, "send", instrumentation._patchSend());
|
|
201456
201510
|
const anyRequest = request2;
|
|
201457
|
-
const rpcMetadata =
|
|
201511
|
+
const rpcMetadata = import_core104.getRPCMetadata(import_api18.context.active());
|
|
201458
201512
|
const routeName = anyRequest.routeOptions ? anyRequest.routeOptions.url : request2.routerPath;
|
|
201459
|
-
if (routeName && rpcMetadata?.type ===
|
|
201513
|
+
if (routeName && rpcMetadata?.type === import_core104.RPCType.HTTP) {
|
|
201460
201514
|
rpcMetadata.route = routeName;
|
|
201461
201515
|
}
|
|
201462
201516
|
const method = request2.method || "GET";
|
|
@@ -242831,7 +242885,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
242831
242885
|
var require_package7 = __commonJS((exports, module) => {
|
|
242832
242886
|
module.exports = {
|
|
242833
242887
|
name: "@omni/api",
|
|
242834
|
-
version: "2.
|
|
242888
|
+
version: "2.260830.1",
|
|
242835
242889
|
type: "module",
|
|
242836
242890
|
exports: {
|
|
242837
242891
|
".": {
|
|
@@ -278800,7 +278854,7 @@ var require_channelz = __commonJS((exports) => {
|
|
|
278800
278854
|
return (0, net_1.isIPv6)(ipAddress) && ipAddress.toLowerCase().startsWith("::ffff:") && (0, net_1.isIPv4)(ipAddress.substring(7));
|
|
278801
278855
|
}
|
|
278802
278856
|
function ipv4AddressStringToBuffer(ipAddress) {
|
|
278803
|
-
return Buffer.from(Uint8Array.from(ipAddress.split(".").map((
|
|
278857
|
+
return Buffer.from(Uint8Array.from(ipAddress.split(".").map((segment2) => Number.parseInt(segment2))));
|
|
278804
278858
|
}
|
|
278805
278859
|
function ipAddressStringToBuffer(ipAddress) {
|
|
278806
278860
|
if ((0, net_1.isIPv4)(ipAddress)) {
|
|
@@ -289937,21 +289991,21 @@ var splitPath2 = (path2) => {
|
|
|
289937
289991
|
const segments = path2.split("/");
|
|
289938
289992
|
const results = [];
|
|
289939
289993
|
let basePath = "";
|
|
289940
|
-
segments.forEach((
|
|
289941
|
-
if (
|
|
289942
|
-
basePath += "/" +
|
|
289943
|
-
} else if (/\:/.test(
|
|
289944
|
-
if (/\?/.test(
|
|
289994
|
+
segments.forEach((segment2) => {
|
|
289995
|
+
if (segment2 !== "" && !/\:/.test(segment2)) {
|
|
289996
|
+
basePath += "/" + segment2;
|
|
289997
|
+
} else if (/\:/.test(segment2)) {
|
|
289998
|
+
if (/\?/.test(segment2)) {
|
|
289945
289999
|
if (results.length === 0 && basePath === "") {
|
|
289946
290000
|
results.push("/");
|
|
289947
290001
|
} else {
|
|
289948
290002
|
results.push(basePath);
|
|
289949
290003
|
}
|
|
289950
|
-
const optionalSegment =
|
|
290004
|
+
const optionalSegment = segment2.replace("?", "");
|
|
289951
290005
|
basePath += "/" + optionalSegment;
|
|
289952
290006
|
results.push(basePath);
|
|
289953
290007
|
} else {
|
|
289954
|
-
basePath += "/" +
|
|
290008
|
+
basePath += "/" + segment2;
|
|
289955
290009
|
}
|
|
289956
290010
|
}
|
|
289957
290011
|
});
|
|
@@ -291483,11 +291537,11 @@ var defaultJoin = (...paths) => {
|
|
|
291483
291537
|
result = result.replace(/(?<=\/)\/+/g, "");
|
|
291484
291538
|
const segments = result.split("/");
|
|
291485
291539
|
const resolved = [];
|
|
291486
|
-
for (const
|
|
291487
|
-
if (
|
|
291540
|
+
for (const segment2 of segments) {
|
|
291541
|
+
if (segment2 === ".." && resolved.length > 0 && resolved.at(-1) !== "..") {
|
|
291488
291542
|
resolved.pop();
|
|
291489
|
-
} else if (
|
|
291490
|
-
resolved.push(
|
|
291543
|
+
} else if (segment2 !== ".") {
|
|
291544
|
+
resolved.push(segment2);
|
|
291491
291545
|
}
|
|
291492
291546
|
}
|
|
291493
291547
|
return resolved.join("/") || ".";
|
|
@@ -293276,9 +293330,13 @@ var init_profiles = __esm(() => {
|
|
|
293276
293330
|
});
|
|
293277
293331
|
|
|
293278
293332
|
// ../api/src/middleware/output-redactor.ts
|
|
293333
|
+
import { createHash as createHash12 } from "crypto";
|
|
293279
293334
|
function escapeRegex(literal) {
|
|
293280
293335
|
return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
293281
293336
|
}
|
|
293337
|
+
function hashPattern(source) {
|
|
293338
|
+
return createHash12("sha256").update(source).digest("hex").slice(0, 12);
|
|
293339
|
+
}
|
|
293282
293340
|
function compilePatterns(literals) {
|
|
293283
293341
|
const out = [];
|
|
293284
293342
|
for (const literal of literals) {
|
|
@@ -293448,7 +293506,7 @@ async function emitRedactionEvents(c, apiKey, presetKey, hits) {
|
|
|
293448
293506
|
keyId: apiKey.id,
|
|
293449
293507
|
profile: apiKey.profile ?? null,
|
|
293450
293508
|
presetKey,
|
|
293451
|
-
|
|
293509
|
+
patternHash: hashPattern(hit.pattern),
|
|
293452
293510
|
field: hit.field,
|
|
293453
293511
|
count: hit.count,
|
|
293454
293512
|
route: c.req.path,
|
|
@@ -293457,7 +293515,7 @@ async function emitRedactionEvents(c, apiKey, presetKey, hits) {
|
|
|
293457
293515
|
} catch (err2) {
|
|
293458
293516
|
log60.warn("output-redactor: failed to publish secret.redacted", {
|
|
293459
293517
|
keyId: apiKey.id,
|
|
293460
|
-
|
|
293518
|
+
patternHash: hashPattern(hit.pattern),
|
|
293461
293519
|
error: String(err2)
|
|
293462
293520
|
});
|
|
293463
293521
|
}
|
|
@@ -293648,6 +293706,9 @@ var init_scopes = __esm(() => {
|
|
|
293648
293706
|
"GET /instances/:id/status": "instances:read",
|
|
293649
293707
|
"GET /instances/:id/qr": "instances:read",
|
|
293650
293708
|
"POST /instances/:id/pair": "instances:write",
|
|
293709
|
+
"GET /instances/:id/passkey": "instances:read",
|
|
293710
|
+
"POST /instances/:id/passkey/response": "instances:write",
|
|
293711
|
+
"POST /instances/:id/passkey/confirm": "instances:write",
|
|
293651
293712
|
"POST /instances/:id/connect": "instances:write",
|
|
293652
293713
|
"POST /instances/:id/disconnect": "instances:write",
|
|
293653
293714
|
"POST /instances/:id/restart": "instances:write",
|
|
@@ -294372,17 +294433,18 @@ var init_route_ownership = __esm(() => {
|
|
|
294372
294433
|
"DELETE /api/v2/follow-up/chats/:id",
|
|
294373
294434
|
"DELETE /api/v2/follow-up/instances/:id",
|
|
294374
294435
|
"DELETE /api/v2/instances/:id",
|
|
294375
|
-
"DELETE /api/v2/instances/:id/whatsapp-flows/:flowId",
|
|
294376
294436
|
"DELETE /api/v2/instances/:id/block",
|
|
294377
294437
|
"DELETE /api/v2/instances/:id/guilds/:guildId/config",
|
|
294378
294438
|
"DELETE /api/v2/instances/:id/profile/picture",
|
|
294379
294439
|
"DELETE /api/v2/instances/:id/whatsapp-business/connection",
|
|
294440
|
+
"DELETE /api/v2/instances/:id/whatsapp-flows/:flowId",
|
|
294380
294441
|
"DELETE /api/v2/instances/:id/whatsapp-templates/:templateId",
|
|
294381
294442
|
"DELETE /api/v2/instances/:instanceId/routes/:id",
|
|
294382
294443
|
"DELETE /api/v2/messages/:id",
|
|
294383
294444
|
"DELETE /api/v2/messages/:id/reactions",
|
|
294384
294445
|
"DELETE /api/v2/messages/:id/star",
|
|
294385
294446
|
"DELETE /api/v2/providers/:id",
|
|
294447
|
+
"DELETE /api/v2/scheduled-messages/:id",
|
|
294386
294448
|
"DELETE /api/v2/settings/:key",
|
|
294387
294449
|
"DELETE /api/v2/webhook-sources/:id",
|
|
294388
294450
|
"GET /api/v2",
|
|
@@ -294451,6 +294513,7 @@ var init_route_ownership = __esm(() => {
|
|
|
294451
294513
|
"GET /api/v2/instances/:id/guilds/:guildId/audit",
|
|
294452
294514
|
"GET /api/v2/instances/:id/guilds/:guildId/config",
|
|
294453
294515
|
"GET /api/v2/instances/:id/pairing-requests",
|
|
294516
|
+
"GET /api/v2/instances/:id/passkey",
|
|
294454
294517
|
"GET /api/v2/instances/:id/privacy",
|
|
294455
294518
|
"GET /api/v2/instances/:id/qr",
|
|
294456
294519
|
"GET /api/v2/instances/:id/status",
|
|
@@ -294475,6 +294538,7 @@ var init_route_ownership = __esm(() => {
|
|
|
294475
294538
|
"GET /api/v2/media/:instanceId/*",
|
|
294476
294539
|
"GET /api/v2/messages",
|
|
294477
294540
|
"GET /api/v2/messages/:id",
|
|
294541
|
+
"GET /api/v2/messages/:id/permalink",
|
|
294478
294542
|
"GET /api/v2/messages/by-external",
|
|
294479
294543
|
"GET /api/v2/messages/tts/voices",
|
|
294480
294544
|
"GET /api/v2/payload-config",
|
|
@@ -294490,9 +294554,12 @@ var init_route_ownership = __esm(() => {
|
|
|
294490
294554
|
"GET /api/v2/providers/:id/teams",
|
|
294491
294555
|
"GET /api/v2/providers/:id/workflows",
|
|
294492
294556
|
"GET /api/v2/routes/metrics",
|
|
294557
|
+
"GET /api/v2/scheduled-messages",
|
|
294558
|
+
"GET /api/v2/scheduled-messages/:id",
|
|
294493
294559
|
"GET /api/v2/settings",
|
|
294494
294560
|
"GET /api/v2/settings/:key",
|
|
294495
294561
|
"GET /api/v2/settings/:key/history",
|
|
294562
|
+
"GET /api/v2/slack/search",
|
|
294496
294563
|
"GET /api/v2/turns",
|
|
294497
294564
|
"GET /api/v2/turns/:id",
|
|
294498
294565
|
"GET /api/v2/turns/stats",
|
|
@@ -294584,6 +294651,8 @@ var init_route_ownership = __esm(() => {
|
|
|
294584
294651
|
"POST /api/v2/instances/:id/groups/join",
|
|
294585
294652
|
"POST /api/v2/instances/:id/logout",
|
|
294586
294653
|
"POST /api/v2/instances/:id/pair",
|
|
294654
|
+
"POST /api/v2/instances/:id/passkey/confirm",
|
|
294655
|
+
"POST /api/v2/instances/:id/passkey/response",
|
|
294587
294656
|
"POST /api/v2/instances/:id/pairing-requests/:requestId/action",
|
|
294588
294657
|
"POST /api/v2/instances/:id/replay",
|
|
294589
294658
|
"POST /api/v2/instances/:id/restart",
|
|
@@ -294638,6 +294707,8 @@ var init_route_ownership = __esm(() => {
|
|
|
294638
294707
|
"POST /api/v2/persons/unlink",
|
|
294639
294708
|
"POST /api/v2/providers",
|
|
294640
294709
|
"POST /api/v2/providers/:id/health",
|
|
294710
|
+
"POST /api/v2/scheduled-messages",
|
|
294711
|
+
"POST /api/v2/slack/dm/open",
|
|
294641
294712
|
"POST /api/v2/turns/:id/close",
|
|
294642
294713
|
"POST /api/v2/turns/close",
|
|
294643
294714
|
"POST /api/v2/turns/close-all",
|
|
@@ -294656,9 +294727,9 @@ var init_route_ownership = __esm(() => {
|
|
|
294656
294727
|
"PUT /api/v2/instances/:id/presence",
|
|
294657
294728
|
"PUT /api/v2/instances/:id/profile/name",
|
|
294658
294729
|
"PUT /api/v2/instances/:id/profile/picture",
|
|
294730
|
+
"PUT /api/v2/instances/:id/profile/status",
|
|
294659
294731
|
"PUT /api/v2/instances/:id/whatsapp-business/profile",
|
|
294660
294732
|
"PUT /api/v2/instances/:id/whatsapp-flows/:flowId",
|
|
294661
|
-
"PUT /api/v2/instances/:id/profile/status",
|
|
294662
294733
|
"PUT /api/v2/payload-config/:eventType",
|
|
294663
294734
|
"PUT /api/v2/settings/:key"
|
|
294664
294735
|
];
|
|
@@ -316516,10 +316587,10 @@ var import_p_retry, import_google_auth_library, _defaultBaseGeminiUrl = undefine
|
|
|
316516
316587
|
invalidSegments.sort((a, b3) => a.start - b3.start);
|
|
316517
316588
|
if (invalidSegments.length > 0) {
|
|
316518
316589
|
let lastEnd = 0;
|
|
316519
|
-
const underline = invalidSegments.reduce((acc,
|
|
316520
|
-
const spaces = " ".repeat(
|
|
316521
|
-
const arrows = "^".repeat(
|
|
316522
|
-
lastEnd =
|
|
316590
|
+
const underline = invalidSegments.reduce((acc, segment2) => {
|
|
316591
|
+
const spaces = " ".repeat(segment2.start - lastEnd);
|
|
316592
|
+
const arrows = "^".repeat(segment2.length);
|
|
316593
|
+
lastEnd = segment2.start + segment2.length;
|
|
316523
316594
|
return acc + spaces + arrows;
|
|
316524
316595
|
}, "");
|
|
316525
316596
|
throw new GeminiNextGenAPIClientError(`Path parameters result in path with invalid segments:
|
|
@@ -322495,10 +322566,10 @@ function extractSegments(buffer3) {
|
|
|
322495
322566
|
const splitIndex = remaining.indexOf(`
|
|
322496
322567
|
|
|
322497
322568
|
`);
|
|
322498
|
-
const
|
|
322569
|
+
const segment2 = remaining.slice(0, splitIndex).trim();
|
|
322499
322570
|
remaining = remaining.slice(splitIndex + 2);
|
|
322500
|
-
if (
|
|
322501
|
-
segments.push(
|
|
322571
|
+
if (segment2)
|
|
322572
|
+
segments.push(segment2);
|
|
322502
322573
|
}
|
|
322503
322574
|
return [segments, remaining];
|
|
322504
322575
|
}
|
|
@@ -322513,8 +322584,8 @@ async function* processStreamChunks(streamGenerator, enableSplit) {
|
|
|
322513
322584
|
`)) {
|
|
322514
322585
|
const [segments, remaining] = extractSegments(buffer3);
|
|
322515
322586
|
buffer3 = remaining;
|
|
322516
|
-
for (const
|
|
322517
|
-
yield
|
|
322587
|
+
for (const segment2 of segments) {
|
|
322588
|
+
yield segment2;
|
|
322518
322589
|
}
|
|
322519
322590
|
}
|
|
322520
322591
|
if (chunk2.isComplete && buffer3.trim()) {
|
|
@@ -327226,12 +327297,12 @@ var is_array, hex_table, limit = 1024, encode3 = (str, _defaultEncoder, charset,
|
|
|
327226
327297
|
}
|
|
327227
327298
|
let out = "";
|
|
327228
327299
|
for (let j2 = 0;j2 < string.length; j2 += limit) {
|
|
327229
|
-
const
|
|
327300
|
+
const segment2 = string.length >= limit ? string.slice(j2, j2 + limit) : string;
|
|
327230
327301
|
const arr = [];
|
|
327231
|
-
for (let i = 0;i <
|
|
327232
|
-
let c =
|
|
327302
|
+
for (let i = 0;i < segment2.length; ++i) {
|
|
327303
|
+
let c = segment2.charCodeAt(i);
|
|
327233
327304
|
if (c === 45 || c === 46 || c === 95 || c === 126 || c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122 || format === RFC1738 && (c === 40 || c === 41)) {
|
|
327234
|
-
arr[arr.length] =
|
|
327305
|
+
arr[arr.length] = segment2.charAt(i);
|
|
327235
327306
|
continue;
|
|
327236
327307
|
}
|
|
327237
327308
|
if (c < 128) {
|
|
@@ -327247,7 +327318,7 @@ var is_array, hex_table, limit = 1024, encode3 = (str, _defaultEncoder, charset,
|
|
|
327247
327318
|
continue;
|
|
327248
327319
|
}
|
|
327249
327320
|
i += 1;
|
|
327250
|
-
c = 65536 + ((c & 1023) << 10 |
|
|
327321
|
+
c = 65536 + ((c & 1023) << 10 | segment2.charCodeAt(i) & 1023);
|
|
327251
327322
|
arr[arr.length] = hex_table[240 | c >> 18] + hex_table[128 | c >> 12 & 63] + hex_table[128 | c >> 6 & 63] + hex_table[128 | c & 63];
|
|
327252
327323
|
}
|
|
327253
327324
|
out += arr.join("");
|
|
@@ -346308,6 +346379,7 @@ var init_instances = __esm(() => {
|
|
|
346308
346379
|
SEALED_CREDENTIAL_COLUMNS = [
|
|
346309
346380
|
"discordBotToken",
|
|
346310
346381
|
"slackBotToken",
|
|
346382
|
+
"slackUserToken",
|
|
346311
346383
|
"slackAppToken",
|
|
346312
346384
|
"slackSigningSecret",
|
|
346313
346385
|
"telegramBotToken",
|
|
@@ -346463,7 +346535,7 @@ class MessageService {
|
|
|
346463
346535
|
return result;
|
|
346464
346536
|
}
|
|
346465
346537
|
async hasBotRepliedInThread(chatId, threadExternalId) {
|
|
346466
|
-
const [result] = await this.db.select({ id: messages2.id }).from(messages2).where(and2(eq(messages2.chatId, chatId), eq(messages2.isFromMe, true), or2(eq(messages2.replyToExternalId, threadExternalId), eq(messages2.externalId, threadExternalId)))).limit(1);
|
|
346538
|
+
const [result] = await this.db.select({ id: messages2.id }).from(messages2).where(and2(eq(messages2.chatId, chatId), eq(messages2.isFromMe, true), or2(eq(messages2.threadExternalId, threadExternalId), eq(messages2.replyToExternalId, threadExternalId), eq(messages2.externalId, threadExternalId)))).limit(1);
|
|
346467
346539
|
return !!result;
|
|
346468
346540
|
}
|
|
346469
346541
|
async getByExternalId(chatId, externalId) {
|
|
@@ -346552,6 +346624,8 @@ class MessageService {
|
|
|
346552
346624
|
quotedSenderName: options.quotedSenderName,
|
|
346553
346625
|
isForwarded: options.isForwarded ?? false,
|
|
346554
346626
|
forwardedFromExternalId: options.forwardedFromExternalId,
|
|
346627
|
+
threadExternalId: options.threadExternalId,
|
|
346628
|
+
isThreadBroadcast: options.isThreadBroadcast ?? false,
|
|
346555
346629
|
rawPayload: options.rawPayload,
|
|
346556
346630
|
originalEventId: options.originalEventId,
|
|
346557
346631
|
latestEventId: options.originalEventId
|
|
@@ -346755,6 +346829,19 @@ class MessageService {
|
|
|
346755
346829
|
const [replyToMessage] = await this.db.select({ id: messages2.id }).from(messages2).where(and2(eq(messages2.chatId, chatId), eq(messages2.externalId, replyToExternalId))).limit(1);
|
|
346756
346830
|
return replyToMessage?.id ?? null;
|
|
346757
346831
|
}
|
|
346832
|
+
async setStarred(chatId, externalId, starred) {
|
|
346833
|
+
await this.db.update(messages2).set({ starredAt: starred ? new Date : null, updatedAt: new Date }).where(and2(eq(messages2.chatId, chatId), eq(messages2.externalId, externalId)));
|
|
346834
|
+
}
|
|
346835
|
+
async setPinned(chatId, externalId, pinned, pinnedBy) {
|
|
346836
|
+
await this.db.update(messages2).set({
|
|
346837
|
+
pinnedAt: pinned ? new Date : null,
|
|
346838
|
+
pinnedBy: pinned ? pinnedBy ?? null : null,
|
|
346839
|
+
updatedAt: new Date
|
|
346840
|
+
}).where(and2(eq(messages2.chatId, chatId), eq(messages2.externalId, externalId)));
|
|
346841
|
+
}
|
|
346842
|
+
async setPermalink(chatId, externalId, permalink) {
|
|
346843
|
+
await this.db.update(messages2).set({ permalink, updatedAt: new Date }).where(and2(eq(messages2.chatId, chatId), eq(messages2.externalId, externalId)));
|
|
346844
|
+
}
|
|
346758
346845
|
async updateReplyToReference(id, replyToMessageId) {
|
|
346759
346846
|
await this.db.update(messages2).set({ replyToMessageId, updatedAt: new Date }).where(eq(messages2.id, id));
|
|
346760
346847
|
}
|
|
@@ -346936,7 +347023,92 @@ var init_payload_store2 = __esm(() => {
|
|
|
346936
347023
|
log97 = createLogger("payload-store");
|
|
346937
347024
|
});
|
|
346938
347025
|
|
|
347026
|
+
// ../api/src/utils/phone.ts
|
|
347027
|
+
function isValidE164Phone(phone) {
|
|
347028
|
+
const bare = phone.replace(/^\+/, "");
|
|
347029
|
+
if (!/^\d+$/.test(bare))
|
|
347030
|
+
return false;
|
|
347031
|
+
return bare.length >= 7 && bare.length <= 15;
|
|
347032
|
+
}
|
|
347033
|
+
function isLidFormat(platformUserId) {
|
|
347034
|
+
const bare = platformUserId.split("@")[0] || platformUserId;
|
|
347035
|
+
return /^\d{14,}$/.test(bare);
|
|
347036
|
+
}
|
|
347037
|
+
function validateContactPhone(phone, platformUserId) {
|
|
347038
|
+
if (!phone)
|
|
347039
|
+
return;
|
|
347040
|
+
if (!isValidE164Phone(phone))
|
|
347041
|
+
return;
|
|
347042
|
+
const barePhone = phone.replace(/^\+/, "");
|
|
347043
|
+
const barePuid = platformUserId.split("@")[0] || platformUserId;
|
|
347044
|
+
if (isLidFormat(platformUserId) && barePhone === barePuid)
|
|
347045
|
+
return;
|
|
347046
|
+
return phone;
|
|
347047
|
+
}
|
|
347048
|
+
|
|
347049
|
+
// ../api/src/utils/canonical-handle.ts
|
|
347050
|
+
function isWhatsAppFamily(channel5) {
|
|
347051
|
+
return WHATSAPP_FAMILY_CHANNELS.has(channel5);
|
|
347052
|
+
}
|
|
347053
|
+
function isPersonlessChannel(channel5) {
|
|
347054
|
+
return PERSONLESS_CHANNELS.has(channel5);
|
|
347055
|
+
}
|
|
347056
|
+
function stripProviderPrefix(raw2) {
|
|
347057
|
+
return raw2.replace(/^whatsapp:/i, "").trim();
|
|
347058
|
+
}
|
|
347059
|
+
function stripDeviceSuffix2(local) {
|
|
347060
|
+
const colon = local.indexOf(":");
|
|
347061
|
+
return colon === -1 ? local : local.slice(0, colon);
|
|
347062
|
+
}
|
|
347063
|
+
function canonicalizeHandle(channel5, rawUserId) {
|
|
347064
|
+
if (!rawUserId)
|
|
347065
|
+
return { platformUserId: rawUserId };
|
|
347066
|
+
if (!isWhatsAppFamily(channel5))
|
|
347067
|
+
return { platformUserId: rawUserId };
|
|
347068
|
+
const stripped = stripProviderPrefix(rawUserId);
|
|
347069
|
+
const atIndex = stripped.indexOf("@");
|
|
347070
|
+
const suffix = atIndex === -1 ? "" : stripped.slice(atIndex);
|
|
347071
|
+
const localRaw = atIndex === -1 ? stripped : stripped.slice(0, atIndex);
|
|
347072
|
+
if (suffix === "@lid") {
|
|
347073
|
+
return { platformUserId: `${stripDeviceSuffix2(localRaw)}@lid` };
|
|
347074
|
+
}
|
|
347075
|
+
if (suffix === "@g.us" || suffix === "@broadcast" || suffix === "@newsletter") {
|
|
347076
|
+
return { platformUserId: stripped };
|
|
347077
|
+
}
|
|
347078
|
+
const digits = stripDeviceSuffix2(localRaw).replace(/^\+/, "");
|
|
347079
|
+
if (isValidE164Phone(digits)) {
|
|
347080
|
+
return { platformUserId: `${digits}${WA_PHONE_SUFFIX}`, phone: `+${digits}` };
|
|
347081
|
+
}
|
|
347082
|
+
return { platformUserId: rawUserId };
|
|
347083
|
+
}
|
|
347084
|
+
var WHATSAPP_FAMILY_CHANNELS, PERSONLESS_CHANNELS, WA_PHONE_SUFFIX = "@s.whatsapp.net";
|
|
347085
|
+
var init_canonical_handle = __esm(() => {
|
|
347086
|
+
WHATSAPP_FAMILY_CHANNELS = new Set([
|
|
347087
|
+
"whatsapp-baileys",
|
|
347088
|
+
"whatsapp-business",
|
|
347089
|
+
"twilio-whatsapp",
|
|
347090
|
+
"gupshup",
|
|
347091
|
+
"hermes"
|
|
347092
|
+
]);
|
|
347093
|
+
PERSONLESS_CHANNELS = new Set(["internal", "a2a"]);
|
|
347094
|
+
});
|
|
347095
|
+
|
|
346939
347096
|
// ../api/src/services/persons.ts
|
|
347097
|
+
function canonicalizeIdentityInput(rawData, rawLinkOptions) {
|
|
347098
|
+
const data = {
|
|
347099
|
+
...rawData,
|
|
347100
|
+
platformUserId: canonicalizeHandle(rawData.channel, rawData.platformUserId).platformUserId
|
|
347101
|
+
};
|
|
347102
|
+
if (rawLinkOptions?.matchByPlatformUserId === undefined) {
|
|
347103
|
+
return { data, linkOptions: rawLinkOptions };
|
|
347104
|
+
}
|
|
347105
|
+
const linkOptions = {
|
|
347106
|
+
...rawLinkOptions,
|
|
347107
|
+
matchByPlatformUserId: canonicalizeHandle(rawData.channel, rawLinkOptions.matchByPlatformUserId).platformUserId
|
|
347108
|
+
};
|
|
347109
|
+
return { data, linkOptions };
|
|
347110
|
+
}
|
|
347111
|
+
|
|
346940
347112
|
class PersonService {
|
|
346941
347113
|
pool;
|
|
346942
347114
|
eventBus;
|
|
@@ -347029,8 +347201,8 @@ class PersonService {
|
|
|
347029
347201
|
`);
|
|
347030
347202
|
return result;
|
|
347031
347203
|
}
|
|
347032
|
-
async getById(id) {
|
|
347033
|
-
const [result] = await
|
|
347204
|
+
async getById(id, handle = this.db) {
|
|
347205
|
+
const [result] = await handle.select().from(persons).where(eq(persons.id, id)).limit(1);
|
|
347034
347206
|
if (!result) {
|
|
347035
347207
|
throw new NotFoundError("Person", id);
|
|
347036
347208
|
}
|
|
@@ -347096,8 +347268,8 @@ class PersonService {
|
|
|
347096
347268
|
const [mapping] = await this.db.select({ phoneId: chatIdMappings.phoneId }).from(chatIdMappings).where(and2(eq(chatIdMappings.instanceId, instanceId), eq(chatIdMappings.lidId, lidId))).limit(1);
|
|
347097
347269
|
return mapping?.phoneId ?? null;
|
|
347098
347270
|
}
|
|
347099
|
-
async findPersonByPhone(phone) {
|
|
347100
|
-
const [existing] = await
|
|
347271
|
+
async findPersonByPhone(phone, handle = this.db) {
|
|
347272
|
+
const [existing] = await handle.select().from(persons).where(eq(persons.primaryPhone, phone)).limit(1);
|
|
347101
347273
|
return existing ? { personId: existing.id, wasLinked: true } : null;
|
|
347102
347274
|
}
|
|
347103
347275
|
async findPersonToLink(linkOptions) {
|
|
@@ -347130,9 +347302,9 @@ class PersonService {
|
|
|
347130
347302
|
return { wasLinked: false };
|
|
347131
347303
|
return this.createPersonWithConflictHandling(linkOptions);
|
|
347132
347304
|
}
|
|
347133
|
-
async createPersonWithConflictHandling(linkOptions) {
|
|
347305
|
+
async createPersonWithConflictHandling(linkOptions, handle = this.db) {
|
|
347134
347306
|
try {
|
|
347135
|
-
const [newPerson] = await
|
|
347307
|
+
const [newPerson] = await handle.insert(persons).values({
|
|
347136
347308
|
displayName: linkOptions.displayName,
|
|
347137
347309
|
primaryPhone: linkOptions.matchByPhone,
|
|
347138
347310
|
primaryEmail: linkOptions.matchByEmail
|
|
@@ -347140,17 +347312,17 @@ class PersonService {
|
|
|
347140
347312
|
if (newPerson)
|
|
347141
347313
|
return { personId: newPerson.id, wasLinked: false };
|
|
347142
347314
|
if (linkOptions.matchByPhone) {
|
|
347143
|
-
return await this.findPersonByPhone(linkOptions.matchByPhone) ?? { wasLinked: false };
|
|
347315
|
+
return await this.findPersonByPhone(linkOptions.matchByPhone, handle) ?? { wasLinked: false };
|
|
347144
347316
|
}
|
|
347145
347317
|
} catch {
|
|
347146
347318
|
if (linkOptions.matchByPhone) {
|
|
347147
|
-
return await this.findPersonByPhone(linkOptions.matchByPhone) ?? { wasLinked: false };
|
|
347319
|
+
return await this.findPersonByPhone(linkOptions.matchByPhone, handle) ?? { wasLinked: false };
|
|
347148
347320
|
}
|
|
347149
347321
|
}
|
|
347150
347322
|
return { wasLinked: false };
|
|
347151
347323
|
}
|
|
347152
|
-
async updateExistingIdentity(existing, data) {
|
|
347153
|
-
const [updated] = await
|
|
347324
|
+
async updateExistingIdentity(existing, data, handle = this.db) {
|
|
347325
|
+
const [updated] = await handle.update(platformIdentities).set({
|
|
347154
347326
|
platformUsername: data.platformUsername ?? existing.platformUsername,
|
|
347155
347327
|
profilePicUrl: data.profilePicUrl ?? existing.profilePicUrl,
|
|
347156
347328
|
profileData: data.profileData ?? existing.profileData,
|
|
@@ -347162,23 +347334,24 @@ class PersonService {
|
|
|
347162
347334
|
}
|
|
347163
347335
|
let person2 = null;
|
|
347164
347336
|
if (updated.personId) {
|
|
347165
|
-
person2 = await this.getById(updated.personId);
|
|
347337
|
+
person2 = await this.getById(updated.personId, handle);
|
|
347166
347338
|
}
|
|
347167
347339
|
return { identity: updated, person: person2, isNew: false, wasLinked: false };
|
|
347168
347340
|
}
|
|
347169
|
-
async findOrCreateIdentity(
|
|
347170
|
-
const instanceId =
|
|
347341
|
+
async findOrCreateIdentity(rawData, rawLinkOptions) {
|
|
347342
|
+
const instanceId = rawData.instanceId;
|
|
347171
347343
|
if (!instanceId) {
|
|
347172
347344
|
throw new Error("instanceId is required");
|
|
347173
347345
|
}
|
|
347346
|
+
const { data, linkOptions } = canonicalizeIdentityInput(rawData, rawLinkOptions);
|
|
347174
347347
|
const existing = await this.db.select().from(platformIdentities).where(and2(eq(platformIdentities.channel, data.channel), eq(platformIdentities.instanceId, instanceId), eq(platformIdentities.platformUserId, data.platformUserId))).limit(1);
|
|
347175
347348
|
if (existing[0]) {
|
|
347176
347349
|
return this.updateExistingIdentity(existing[0], data);
|
|
347177
347350
|
}
|
|
347178
347351
|
let personId = data.personId;
|
|
347179
347352
|
let wasLinked = false;
|
|
347353
|
+
let resolvedLinkOptions = linkOptions;
|
|
347180
347354
|
if (!personId && linkOptions) {
|
|
347181
|
-
let resolvedLinkOptions = linkOptions;
|
|
347182
347355
|
if (!linkOptions.matchByPhone && data.platformUserId.endsWith("@lid") && instanceId) {
|
|
347183
347356
|
const phoneFromLid = await this.resolvePhoneFromLid(instanceId, data.platformUserId);
|
|
347184
347357
|
if (phoneFromLid) {
|
|
@@ -347186,31 +347359,63 @@ class PersonService {
|
|
|
347186
347359
|
resolvedLinkOptions = { ...linkOptions, matchByPhone: phoneNumber };
|
|
347187
347360
|
}
|
|
347188
347361
|
}
|
|
347189
|
-
const linkResult = await this.findPersonToLink({ ...resolvedLinkOptions, instanceId });
|
|
347362
|
+
const linkResult = await this.findPersonToLink({ ...resolvedLinkOptions, instanceId, createPerson: false });
|
|
347190
347363
|
personId = linkResult.personId;
|
|
347191
347364
|
wasLinked = linkResult.wasLinked;
|
|
347192
347365
|
}
|
|
347193
347366
|
const matchType = linkOptions?.matchByPhone ? "phone" : linkOptions?.matchByEmail ? "email" : "platform_id";
|
|
347194
347367
|
const linkedBy = wasLinked ? `${matchType}_match` : personId ? "initial" : undefined;
|
|
347195
347368
|
const linkReason = wasLinked ? `Matched by ${matchType}` : undefined;
|
|
347196
|
-
const
|
|
347197
|
-
|
|
347369
|
+
const createPersonOptions = !personId && resolvedLinkOptions?.createPerson ? {
|
|
347370
|
+
matchByPhone: resolvedLinkOptions.matchByPhone,
|
|
347371
|
+
matchByEmail: resolvedLinkOptions.matchByEmail,
|
|
347372
|
+
displayName: resolvedLinkOptions.displayName
|
|
347373
|
+
} : undefined;
|
|
347374
|
+
return this.secureIdentity({
|
|
347375
|
+
data,
|
|
347198
347376
|
personId,
|
|
347377
|
+
wasLinked,
|
|
347199
347378
|
linkedBy,
|
|
347379
|
+
linkReason,
|
|
347200
347380
|
confidence: wasLinked ? 90 : 100,
|
|
347201
|
-
|
|
347202
|
-
})
|
|
347203
|
-
|
|
347204
|
-
|
|
347205
|
-
}
|
|
347206
|
-
|
|
347207
|
-
|
|
347208
|
-
|
|
347209
|
-
|
|
347210
|
-
|
|
347381
|
+
createPersonOptions
|
|
347382
|
+
});
|
|
347383
|
+
}
|
|
347384
|
+
async secureIdentity(params) {
|
|
347385
|
+
const { data, personId, wasLinked, linkedBy, linkReason, confidence, createPersonOptions } = params;
|
|
347386
|
+
const { instanceId, channel: channel5, platformUserId } = data;
|
|
347387
|
+
return this.db.transaction(async (tx) => {
|
|
347388
|
+
const txDb = tx;
|
|
347389
|
+
const [inserted] = await txDb.insert(platformIdentities).values({
|
|
347390
|
+
...data,
|
|
347391
|
+
personId,
|
|
347392
|
+
linkedBy,
|
|
347393
|
+
confidence,
|
|
347394
|
+
linkReason
|
|
347395
|
+
}).onConflictDoNothing().returning();
|
|
347396
|
+
if (!inserted) {
|
|
347397
|
+
const [existing] = await txDb.select().from(platformIdentities).where(and2(eq(platformIdentities.channel, channel5), eq(platformIdentities.instanceId, instanceId ?? ""), eq(platformIdentities.platformUserId, platformUserId))).limit(1);
|
|
347398
|
+
if (!existing) {
|
|
347399
|
+
throw new Error("Failed to resolve identity after conflict");
|
|
347400
|
+
}
|
|
347401
|
+
return this.updateExistingIdentity(existing, data, txDb);
|
|
347402
|
+
}
|
|
347403
|
+
if (inserted.personId || !createPersonOptions) {
|
|
347404
|
+
const person3 = inserted.personId ? await this.getById(inserted.personId, txDb) : null;
|
|
347405
|
+
return { identity: inserted, person: person3, isNew: true, wasLinked };
|
|
347406
|
+
}
|
|
347407
|
+
const created = await this.createPersonWithConflictHandling(createPersonOptions, txDb);
|
|
347408
|
+
if (!created.personId) {
|
|
347409
|
+
return { identity: inserted, person: null, isNew: true, wasLinked };
|
|
347410
|
+
}
|
|
347411
|
+
const [linked] = await txDb.update(platformIdentities).set({ personId: created.personId, linkedBy: "initial", confidence: 100, updatedAt: new Date }).where(eq(platformIdentities.id, inserted.id)).returning();
|
|
347412
|
+
const person2 = await this.getById(created.personId, txDb);
|
|
347413
|
+
return { identity: linked ?? inserted, person: person2, isNew: true, wasLinked: created.wasLinked };
|
|
347414
|
+
});
|
|
347211
347415
|
}
|
|
347212
347416
|
async getIdentityByPlatformId(channel5, instanceId, platformUserId) {
|
|
347213
|
-
const
|
|
347417
|
+
const canonicalUserId = canonicalizeHandle(channel5, platformUserId).platformUserId;
|
|
347418
|
+
const [identity] = await this.db.select().from(platformIdentities).where(and2(eq(platformIdentities.channel, channel5), eq(platformIdentities.instanceId, instanceId), eq(platformIdentities.platformUserId, canonicalUserId))).limit(1);
|
|
347214
347419
|
return identity || null;
|
|
347215
347420
|
}
|
|
347216
347421
|
async listIdentitiesByInstance(instanceId, options = {}) {
|
|
@@ -347387,6 +347592,7 @@ var init_persons = __esm(() => {
|
|
|
347387
347592
|
init_src5();
|
|
347388
347593
|
init_drizzle_orm();
|
|
347389
347594
|
init_tenant_scope();
|
|
347595
|
+
init_canonical_handle();
|
|
347390
347596
|
});
|
|
347391
347597
|
|
|
347392
347598
|
// ../api/src/lib/agent-key-name.ts
|
|
@@ -348358,16 +348564,6 @@ function buildSentChatPreview(payload) {
|
|
|
348358
348564
|
const badge = payload.content.type !== "text" ? MEDIA_BADGES2[payload.content.type] ?? `[${payload.content.type}]` : "";
|
|
348359
348565
|
return badge ? text3 ? `${badge} ${text3}` : badge : text3;
|
|
348360
348566
|
}
|
|
348361
|
-
function extractPhoneFromSender(senderId, channel5) {
|
|
348362
|
-
if (!channel5.startsWith("whatsapp"))
|
|
348363
|
-
return;
|
|
348364
|
-
const bare = senderId.split("@")[0] || senderId;
|
|
348365
|
-
if (!/^\d+$/.test(bare))
|
|
348366
|
-
return;
|
|
348367
|
-
if (bare.length < 7 || bare.length > 15)
|
|
348368
|
-
return;
|
|
348369
|
-
return `+${bare}`;
|
|
348370
|
-
}
|
|
348371
348567
|
async function processSenderIdentity(services, payload, metadata, channel5, trustedTenantId) {
|
|
348372
348568
|
if (metadata.platformIdentityId) {
|
|
348373
348569
|
return { personId: metadata.personId, platformIdentityId: metadata.platformIdentityId };
|
|
@@ -348375,11 +348571,15 @@ async function processSenderIdentity(services, payload, metadata, channel5, trus
|
|
|
348375
348571
|
if (!payload.from) {
|
|
348376
348572
|
return { personId: metadata.personId, platformIdentityId: undefined };
|
|
348377
348573
|
}
|
|
348574
|
+
if (isPersonlessChannel(channel5)) {
|
|
348575
|
+
return { personId: metadata.personId, platformIdentityId: metadata.platformIdentityId };
|
|
348576
|
+
}
|
|
348378
348577
|
const displayName = truncate4(payload.senderName ?? payload.rawPayload?.pushName, 255);
|
|
348379
|
-
const
|
|
348578
|
+
const canonical = canonicalizeHandle(channel5, payload.from);
|
|
348579
|
+
const platformUserId = truncate4(canonical.platformUserId, 255) ?? canonical.platformUserId;
|
|
348380
348580
|
const isLidAddressed = payload.rawPayload?.addressingMode === "lid" || payload.rawPayload?.senderIsLid === true;
|
|
348381
348581
|
const resolvedPhone = isLidAddressed ? payload.rawPayload?.resolvedSenderPhone : undefined;
|
|
348382
|
-
const phoneNumber = isLidAddressed ? resolvedPhone ? `+${resolvedPhone}` : undefined :
|
|
348582
|
+
const phoneNumber = isLidAddressed ? resolvedPhone ? `+${resolvedPhone}` : undefined : canonical.phone;
|
|
348383
348583
|
const { identity, person: person2, isNew } = await services.persons.findOrCreateIdentity({ channel: channel5, instanceId: metadata.instanceId, platformUserId, platformUsername: displayName }, {
|
|
348384
348584
|
createPerson: true,
|
|
348385
348585
|
displayName,
|
|
@@ -348554,6 +348754,22 @@ async function resolveOrCreateChat(services, instanceId, chatExternalId, chatTyp
|
|
|
348554
348754
|
canonicalId
|
|
348555
348755
|
});
|
|
348556
348756
|
}
|
|
348757
|
+
async function linkReplyTarget(services, chatId, messageId, replyToExternalId) {
|
|
348758
|
+
if (!replyToExternalId)
|
|
348759
|
+
return;
|
|
348760
|
+
try {
|
|
348761
|
+
const replyToMessageId = await services.messages.resolveReplyToMessage(chatId, replyToExternalId);
|
|
348762
|
+
if (replyToMessageId) {
|
|
348763
|
+
await services.messages.updateReplyToReference(messageId, replyToMessageId);
|
|
348764
|
+
}
|
|
348765
|
+
} catch (error3) {
|
|
348766
|
+
log103.debug("Could not resolve reply target", {
|
|
348767
|
+
chatId,
|
|
348768
|
+
replyToExternalId,
|
|
348769
|
+
error: error3 instanceof Error ? error3.message : String(error3)
|
|
348770
|
+
});
|
|
348771
|
+
}
|
|
348772
|
+
}
|
|
348557
348773
|
async function handleMessageReceived(services, payload, metadata, eventTimestamp, trustedTenantId, identity) {
|
|
348558
348774
|
const channel5 = metadata.channelType ?? "whatsapp";
|
|
348559
348775
|
const isHistorySync = metadata.ingestMode === "history-sync";
|
|
@@ -348597,12 +348813,15 @@ async function handleMessageReceived(services, payload, metadata, eventTimestamp
|
|
|
348597
348813
|
replyToExternalId: truncate4(payload.replyToId, 255),
|
|
348598
348814
|
quotedText: quotedMessage?.conversation,
|
|
348599
348815
|
quotedSenderName: truncate4(quotedMessage?.pushName, 255),
|
|
348816
|
+
threadExternalId: truncate4(payload.threadId, 255),
|
|
348817
|
+
isThreadBroadcast: rawPayload?.isThreadBroadcast === true,
|
|
348600
348818
|
isForwarded: !!(rawPayload?.isForwarded || rawPayload?.forwardingScore),
|
|
348601
348819
|
rawPayload
|
|
348602
348820
|
});
|
|
348603
348821
|
await maybeRecordMessageEdit(services, created, rawPayload, message2.id, sanitizeText(payload.content.text) ?? undefined, platformTimestamp ?? new Date(eventTimestamp), payload.from);
|
|
348604
348822
|
if (created) {
|
|
348605
348823
|
log103.debug("Created message", { externalId: payload.externalId, chatId: chat2.id });
|
|
348824
|
+
await linkReplyTarget(services, chat2.id, message2.id, payload.replyToId);
|
|
348606
348825
|
}
|
|
348607
348826
|
await maybeRecordParticipantActivity(services, chat2.id, payload.from);
|
|
348608
348827
|
maybeUpdateRecency(services, metadata.instanceId, chat2.id, rawPayload, payload, platformTimestamp ?? new Date(eventTimestamp), trustedTenantId);
|
|
@@ -348700,7 +348919,8 @@ async function setupMessagePersistence(eventBus, services) {
|
|
|
348700
348919
|
mediaLocalPath: sentContent.mediaLocalPath,
|
|
348701
348920
|
mediaMetadata: sentContent.mediaMetadata,
|
|
348702
348921
|
rawPayload: sentContent.rawPayload,
|
|
348703
|
-
replyToExternalId: truncate4(payload.replyToId, 255)
|
|
348922
|
+
replyToExternalId: truncate4(payload.replyToId, 255),
|
|
348923
|
+
threadExternalId: truncate4(payload.threadId, 255)
|
|
348704
348924
|
});
|
|
348705
348925
|
return { chat: chat3, message: message3, created: created2 };
|
|
348706
348926
|
});
|
|
@@ -348898,6 +349118,7 @@ var init_message_persistence = __esm(() => {
|
|
|
348898
349118
|
init_esm5();
|
|
348899
349119
|
init_sentry_scrub();
|
|
348900
349120
|
init_worker_tenant_context();
|
|
349121
|
+
init_canonical_handle();
|
|
348901
349122
|
init_loader2();
|
|
348902
349123
|
log103 = createLogger("message-persistence");
|
|
348903
349124
|
CONTENT_TYPE_MAP = {
|
|
@@ -349033,12 +349254,12 @@ var init_session_storage = __esm(() => {
|
|
|
349033
349254
|
});
|
|
349034
349255
|
|
|
349035
349256
|
// ../api/src/plugins/agent-dispatcher.ts
|
|
349036
|
-
import { createHash as
|
|
349257
|
+
import { createHash as createHash13 } from "crypto";
|
|
349037
349258
|
import { unlink, writeFile as writeFile5 } from "fs/promises";
|
|
349038
349259
|
import { tmpdir as tmpdir12 } from "os";
|
|
349039
349260
|
import { join as join22, resolve as resolve3 } from "path";
|
|
349040
349261
|
function sha256Digest(value) {
|
|
349041
|
-
return `sha256:${
|
|
349262
|
+
return `sha256:${createHash13("sha256").update(value).digest("hex")}`;
|
|
349042
349263
|
}
|
|
349043
349264
|
function redactLifecycleText(value) {
|
|
349044
349265
|
return value.replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, "[EMAIL]").replace(/\b\+?\d[\d\s().-]{5,}\d\b/g, "[PHONE]").replace(/\b\d{6,}\b/g, "[NUMBER]").replace(/\b[^\s@]+@(s\.whatsapp\.net|g\.us|lid|newsletter)\b/gi, "[JID]");
|
|
@@ -365900,6 +366121,10 @@ function sanitizeInstance(instance4) {
|
|
|
365900
366121
|
function applySlackProfileMetadata(opts, metadata) {
|
|
365901
366122
|
if (!metadata)
|
|
365902
366123
|
return;
|
|
366124
|
+
if (metadata.mode)
|
|
366125
|
+
opts.mode = metadata.mode;
|
|
366126
|
+
if (metadata.httpPort)
|
|
366127
|
+
opts.httpPort = metadata.httpPort;
|
|
365903
366128
|
if (metadata.replyToMode)
|
|
365904
366129
|
opts.replyToMode = metadata.replyToMode;
|
|
365905
366130
|
if (metadata.streamMode)
|
|
@@ -365913,6 +366138,12 @@ function applySlackConnectOptions(opts, instance4, overrides) {
|
|
|
365913
366138
|
const botToken = overrides?.slackBotToken ?? instance4.slackBotToken ?? opts.token;
|
|
365914
366139
|
if (botToken)
|
|
365915
366140
|
opts.botToken = botToken;
|
|
366141
|
+
const userToken = overrides?.slackUserToken ?? instance4.slackUserToken;
|
|
366142
|
+
if (userToken)
|
|
366143
|
+
opts.userToken = userToken;
|
|
366144
|
+
const authMode = overrides?.slackAuthMode ?? instance4.slackAuthMode;
|
|
366145
|
+
if (authMode)
|
|
366146
|
+
opts.authMode = authMode;
|
|
365916
366147
|
const appToken = overrides?.slackAppToken ?? instance4.slackAppToken;
|
|
365917
366148
|
if (appToken)
|
|
365918
366149
|
opts.appToken = appToken;
|
|
@@ -365937,8 +366168,13 @@ function applyTelegramConnectionOptions(options, input) {
|
|
|
365937
366168
|
options.telegramReactionLevel = input.telegramReactionLevel;
|
|
365938
366169
|
}
|
|
365939
366170
|
function applySlackConnectionOptions(options, input) {
|
|
366171
|
+
applySlackProfileMetadata(options, input.profileMetadata);
|
|
365940
366172
|
if (input.token)
|
|
365941
366173
|
options.botToken = input.token;
|
|
366174
|
+
if (input.slackUserToken)
|
|
366175
|
+
options.userToken = input.slackUserToken;
|
|
366176
|
+
if (input.slackAuthMode)
|
|
366177
|
+
options.authMode = input.slackAuthMode;
|
|
365942
366178
|
if (input.slackAppToken)
|
|
365943
366179
|
options.appToken = input.slackAppToken;
|
|
365944
366180
|
if (input.slackSigningSecret)
|
|
@@ -366049,6 +366285,10 @@ function buildTokenPersistUpdates(channel5, body) {
|
|
|
366049
366285
|
if (channel5 === "slack") {
|
|
366050
366286
|
if (body.slackBotToken)
|
|
366051
366287
|
updates.slackBotToken = body.slackBotToken;
|
|
366288
|
+
if (body.slackUserToken)
|
|
366289
|
+
updates.slackUserToken = body.slackUserToken;
|
|
366290
|
+
if (body.slackAuthMode)
|
|
366291
|
+
updates.slackAuthMode = body.slackAuthMode;
|
|
366052
366292
|
if (body.slackAppToken)
|
|
366053
366293
|
updates.slackAppToken = body.slackAppToken;
|
|
366054
366294
|
if (body.slackSigningSecret)
|
|
@@ -366108,6 +366348,9 @@ async function handleAgentKeyProvisioning(services, instanceId, newAgentId, oldA
|
|
|
366108
366348
|
}
|
|
366109
366349
|
}
|
|
366110
366350
|
}
|
|
366351
|
+
function supportsPasskey(plugin10) {
|
|
366352
|
+
return "getPasskeyState" in plugin10 && "submitPasskeyResponse" in plugin10 && "confirmPasskey" in plugin10;
|
|
366353
|
+
}
|
|
366111
366354
|
function buildConnectConnectionOptions(instance4, body, forceNewQr) {
|
|
366112
366355
|
const connectToken = body.token ?? persistedTokenForChannel(instance4);
|
|
366113
366356
|
return buildInstanceConnectionOptions({
|
|
@@ -366115,8 +366358,11 @@ function buildConnectConnectionOptions(instance4, body, forceNewQr) {
|
|
|
366115
366358
|
forceNewQr,
|
|
366116
366359
|
token: connectToken,
|
|
366117
366360
|
telegramReactionLevel: instance4.telegramReactionLevel,
|
|
366361
|
+
slackUserToken: body.slackUserToken ?? instance4.slackUserToken,
|
|
366362
|
+
slackAuthMode: body.slackAuthMode ?? instance4.slackAuthMode,
|
|
366118
366363
|
slackAppToken: body.slackAppToken ?? instance4.slackAppToken,
|
|
366119
366364
|
slackSigningSecret: body.slackSigningSecret ?? instance4.slackSigningSecret,
|
|
366365
|
+
profileMetadata: instance4.profileMetadata,
|
|
366120
366366
|
whatsapp: body.whatsapp,
|
|
366121
366367
|
gupshupCallbackUrl: instance4.gupshupCallbackUrl,
|
|
366122
366368
|
gupshupAuthToken: instance4.gupshupAuthToken,
|
|
@@ -366274,7 +366520,7 @@ function getCacheKey(instanceId, guildId) {
|
|
|
366274
366520
|
function invalidateGuildCache(instanceId, guildId) {
|
|
366275
366521
|
guildConfigCache.delete(getCacheKey(instanceId, guildId));
|
|
366276
366522
|
}
|
|
366277
|
-
var log115, instancesRoutes, instanceAccess2, listQuerySchema12, agentReplyFilterSchema, createInstanceSchema, updateInstanceSchema, DEFAULT_AGENT_REPLY_FILTER, SENSITIVE_INSTANCE_FIELDS, pairingCodeSchema, connectInstanceSchema, syncRequestSchema, listContactsQuerySchema, listGroupsQuerySchema, checkNumberSchema, updateBioSchema, blockContactSchema, groupParticipantActionSchema, groupSettingSchema, groupParticipantsSchema, groupParticipantsPatchSchema, updateGroupSubjectSchema, updateGroupDescriptionSchema, updateGroupSettingsSchema, patchGroupSchema, resyncSchema, replaySchema, pairingActionSchema, guildConfigOverrideSchema, guildConfigCache, GUILD_CONFIG_TTL, presenceSchema;
|
|
366523
|
+
var log115, instancesRoutes, instanceAccess2, listQuerySchema12, agentReplyFilterSchema, createInstanceSchema, updateInstanceSchema, DEFAULT_AGENT_REPLY_FILTER, SENSITIVE_INSTANCE_FIELDS, pairingCodeSchema, passkeyBase64UrlSchema, passkeyCredentialSchema, connectInstanceSchema, syncRequestSchema, listContactsQuerySchema, listGroupsQuerySchema, checkNumberSchema, updateBioSchema, blockContactSchema, groupParticipantActionSchema, groupSettingSchema, groupParticipantsSchema, groupParticipantsPatchSchema, updateGroupSubjectSchema, updateGroupDescriptionSchema, updateGroupSettingsSchema, patchGroupSchema, resyncSchema, replaySchema, pairingActionSchema, guildConfigOverrideSchema, guildConfigCache, GUILD_CONFIG_TTL, presenceSchema;
|
|
366278
366524
|
var init_instances3 = __esm(() => {
|
|
366279
366525
|
init_dist6();
|
|
366280
366526
|
init_src();
|
|
@@ -366341,6 +366587,8 @@ var init_instances3 = __esm(() => {
|
|
|
366341
366587
|
agentGatePrompt: exports_external.string().nullable().default(null).describe("Custom prompt for response gate (null = use default)"),
|
|
366342
366588
|
telegramBotToken: exports_external.string().optional().nullable().describe("Telegram bot token (persisted for reconnection)"),
|
|
366343
366589
|
discordBotToken: exports_external.string().optional().nullable().describe("Discord bot token (persisted for reconnection)"),
|
|
366590
|
+
slackUserToken: exports_external.string().optional().nullable().describe("Slack user token xoxp (required when slackAuthMode is user)"),
|
|
366591
|
+
slackAuthMode: exports_external.enum(["bot", "user"]).optional().nullable().describe("Slack identity for outbound actions"),
|
|
366344
366592
|
slackBotToken: exports_external.string().optional().nullable().describe("Slack bot token (persisted for reconnection)"),
|
|
366345
366593
|
slackAppToken: exports_external.string().optional().nullable().describe("Slack app token (persisted for reconnection)"),
|
|
366346
366594
|
slackSigningSecret: exports_external.string().optional().nullable().describe("Slack signing secret (persisted for reconnection)"),
|
|
@@ -366372,6 +366620,7 @@ var init_instances3 = __esm(() => {
|
|
|
366372
366620
|
allowFirstParty: exports_external.boolean().default(false).describe(`When true, this instance processes (does not drop) inbound messages whose sender matches another active instance owner. Lets an "assistant" instance reply to messages from the operator's own personal number. Default: false (loop-protection drop).`)
|
|
366373
366621
|
});
|
|
366374
366622
|
updateInstanceSchema = createInstanceSchema.partial().extend({
|
|
366623
|
+
profileMetadata: exports_external.record(exports_external.unknown()).nullable().optional(),
|
|
366375
366624
|
agentId: exports_external.string().uuid().nullable().optional(),
|
|
366376
366625
|
agentErrorMessages: exports_external.array(exports_external.string()).nullable().optional(),
|
|
366377
366626
|
agentReplyFilter: agentReplyFilterSchema.nullable().optional(),
|
|
@@ -366379,6 +366628,8 @@ var init_instances3 = __esm(() => {
|
|
|
366379
366628
|
telegramBotToken: exports_external.string().nullable().optional(),
|
|
366380
366629
|
discordBotToken: exports_external.string().nullable().optional(),
|
|
366381
366630
|
slackBotToken: exports_external.string().nullable().optional(),
|
|
366631
|
+
slackUserToken: exports_external.string().nullable().optional(),
|
|
366632
|
+
slackAuthMode: exports_external.enum(["bot", "user"]).nullable().optional(),
|
|
366382
366633
|
slackAppToken: exports_external.string().nullable().optional(),
|
|
366383
366634
|
gupshupCallbackUrl: exports_external.string().nullable().optional(),
|
|
366384
366635
|
gupshupAuthToken: exports_external.string().nullable().optional(),
|
|
@@ -366413,6 +366664,7 @@ var init_instances3 = __esm(() => {
|
|
|
366413
366664
|
"telegramBotToken",
|
|
366414
366665
|
"discordBotToken",
|
|
366415
366666
|
"slackBotToken",
|
|
366667
|
+
"slackUserToken",
|
|
366416
366668
|
"slackAppToken",
|
|
366417
366669
|
"slackSigningSecret",
|
|
366418
366670
|
"gupshupAuthToken",
|
|
@@ -366504,8 +366756,11 @@ var init_instances3 = __esm(() => {
|
|
|
366504
366756
|
forceNewQr: true,
|
|
366505
366757
|
token: connectToken,
|
|
366506
366758
|
telegramReactionLevel: instance4.telegramReactionLevel,
|
|
366759
|
+
slackUserToken: instance4.slackUserToken,
|
|
366760
|
+
slackAuthMode: instance4.slackAuthMode,
|
|
366507
366761
|
slackAppToken: instance4.slackAppToken,
|
|
366508
366762
|
slackSigningSecret: instance4.slackSigningSecret,
|
|
366763
|
+
profileMetadata: instance4.profileMetadata,
|
|
366509
366764
|
gupshupCallbackUrl: instance4.gupshupCallbackUrl,
|
|
366510
366765
|
gupshupAuthToken: instance4.gupshupAuthToken,
|
|
366511
366766
|
gupshupEventId: instance4.gupshupEventId,
|
|
@@ -366651,6 +366906,18 @@ var init_instances3 = __esm(() => {
|
|
|
366651
366906
|
pairingCodeSchema = exports_external.object({
|
|
366652
366907
|
phoneNumber: exports_external.string().min(10).max(20).describe("Phone number in international format (e.g., +5511999999999)")
|
|
366653
366908
|
});
|
|
366909
|
+
passkeyBase64UrlSchema = exports_external.string().min(1).regex(/^[A-Za-z0-9_-]+$/);
|
|
366910
|
+
passkeyCredentialSchema = exports_external.object({
|
|
366911
|
+
id: passkeyBase64UrlSchema,
|
|
366912
|
+
rawId: passkeyBase64UrlSchema,
|
|
366913
|
+
type: exports_external.literal("public-key"),
|
|
366914
|
+
response: exports_external.object({
|
|
366915
|
+
clientDataJSON: passkeyBase64UrlSchema,
|
|
366916
|
+
authenticatorData: passkeyBase64UrlSchema,
|
|
366917
|
+
signature: passkeyBase64UrlSchema,
|
|
366918
|
+
userHandle: passkeyBase64UrlSchema.nullable()
|
|
366919
|
+
})
|
|
366920
|
+
});
|
|
366654
366921
|
instancesRoutes.post("/:id/pair", instanceAccess2, zValidator("json", pairingCodeSchema), async (c) => {
|
|
366655
366922
|
const id = c.req.param("id");
|
|
366656
366923
|
const { phoneNumber } = c.req.valid("json");
|
|
@@ -366686,9 +366953,59 @@ var init_instances3 = __esm(() => {
|
|
|
366686
366953
|
return c.json({ error: { code: "PAIRING_FAILED", message: message2 } }, 500);
|
|
366687
366954
|
}
|
|
366688
366955
|
});
|
|
366956
|
+
instancesRoutes.get("/:id/passkey", instanceAccess2, async (c) => {
|
|
366957
|
+
const id = c.req.param("id");
|
|
366958
|
+
const services = c.get("services");
|
|
366959
|
+
const channelRegistry2 = c.get("channelRegistry");
|
|
366960
|
+
const instance4 = await services.instances.getById(id);
|
|
366961
|
+
if (!instance4.channel.startsWith("whatsapp")) {
|
|
366962
|
+
return c.json({ error: { code: "INVALID_OPERATION", message: "Passkey is only available for WhatsApp." } }, 400);
|
|
366963
|
+
}
|
|
366964
|
+
const plugin10 = channelRegistry2?.get(instance4.channel);
|
|
366965
|
+
if (!plugin10 || !supportsPasskey(plugin10)) {
|
|
366966
|
+
return c.json({ error: { code: "NOT_SUPPORTED", message: "This WhatsApp connector does not support passkey." } }, 400);
|
|
366967
|
+
}
|
|
366968
|
+
return c.json({ data: plugin10.getPasskeyState(id) });
|
|
366969
|
+
});
|
|
366970
|
+
instancesRoutes.post("/:id/passkey/response", instanceAccess2, zValidator("json", passkeyCredentialSchema), async (c) => {
|
|
366971
|
+
const id = c.req.param("id");
|
|
366972
|
+
const services = c.get("services");
|
|
366973
|
+
const channelRegistry2 = c.get("channelRegistry");
|
|
366974
|
+
const instance4 = await services.instances.getById(id);
|
|
366975
|
+
const plugin10 = channelRegistry2?.get(instance4.channel);
|
|
366976
|
+
if (!instance4.channel.startsWith("whatsapp") || !plugin10 || !supportsPasskey(plugin10)) {
|
|
366977
|
+
return c.json({ error: { code: "NOT_SUPPORTED", message: "Passkey is not available for this instance." } }, 400);
|
|
366978
|
+
}
|
|
366979
|
+
try {
|
|
366980
|
+
await plugin10.submitPasskeyResponse(id, c.req.valid("json"));
|
|
366981
|
+
return c.json({ data: { status: "submitted" } });
|
|
366982
|
+
} catch (error3) {
|
|
366983
|
+
const message2 = error3 instanceof Error ? error3.message : "Unable to submit passkey response.";
|
|
366984
|
+
return c.json({ error: { code: "PASSKEY_FAILED", message: message2 } }, 500);
|
|
366985
|
+
}
|
|
366986
|
+
});
|
|
366987
|
+
instancesRoutes.post("/:id/passkey/confirm", instanceAccess2, async (c) => {
|
|
366988
|
+
const id = c.req.param("id");
|
|
366989
|
+
const services = c.get("services");
|
|
366990
|
+
const channelRegistry2 = c.get("channelRegistry");
|
|
366991
|
+
const instance4 = await services.instances.getById(id);
|
|
366992
|
+
const plugin10 = channelRegistry2?.get(instance4.channel);
|
|
366993
|
+
if (!instance4.channel.startsWith("whatsapp") || !plugin10 || !supportsPasskey(plugin10)) {
|
|
366994
|
+
return c.json({ error: { code: "NOT_SUPPORTED", message: "Passkey is not available for this instance." } }, 400);
|
|
366995
|
+
}
|
|
366996
|
+
try {
|
|
366997
|
+
await plugin10.confirmPasskey(id);
|
|
366998
|
+
return c.json({ data: { status: "confirmed" } });
|
|
366999
|
+
} catch (error3) {
|
|
367000
|
+
const message2 = error3 instanceof Error ? error3.message : "Unable to confirm passkey pairing.";
|
|
367001
|
+
return c.json({ error: { code: "PASSKEY_FAILED", message: message2 } }, 500);
|
|
367002
|
+
}
|
|
367003
|
+
});
|
|
366689
367004
|
connectInstanceSchema = exports_external.object({
|
|
366690
367005
|
token: exports_external.string().optional().describe("Bot token for Discord/Telegram instances"),
|
|
366691
367006
|
slackBotToken: exports_external.string().optional().describe("Slack bot token (xoxb-...)"),
|
|
367007
|
+
slackUserToken: exports_external.string().optional().describe("Slack user token (xoxp-...), for authMode user"),
|
|
367008
|
+
slackAuthMode: exports_external.enum(["bot", "user"]).optional().describe("Act as the bot (default) or as the authorizing user"),
|
|
366692
367009
|
slackAppToken: exports_external.string().optional().describe("Slack app-level token (xapp-...)"),
|
|
366693
367010
|
slackSigningSecret: exports_external.string().optional().describe("Slack signing secret"),
|
|
366694
367011
|
forceNewQr: exports_external.boolean().optional().describe("Force new QR code for WhatsApp (re-authentication)"),
|
|
@@ -366782,11 +367099,6 @@ var init_instances3 = __esm(() => {
|
|
|
366782
367099
|
restartOptions.token = restartToken;
|
|
366783
367100
|
if (instance4.channel === "telegram") {
|
|
366784
367101
|
restartOptions.telegramReactionLevel = instance4.telegramReactionLevel;
|
|
366785
|
-
} else if (instance4.channel === "slack") {
|
|
366786
|
-
if (restartToken)
|
|
366787
|
-
restartOptions.botToken = restartToken;
|
|
366788
|
-
if (instance4.slackAppToken)
|
|
366789
|
-
restartOptions.appToken = instance4.slackAppToken;
|
|
366790
367102
|
}
|
|
366791
367103
|
if (instance4.channel === "slack") {
|
|
366792
367104
|
applySlackConnectOptions(restartOptions, instance4);
|
|
@@ -369491,8 +369803,8 @@ var init_media2 = __esm(() => {
|
|
|
369491
369803
|
return c.json({ error: { code: "INVALID_PATH", message: "No path specified" } }, 400);
|
|
369492
369804
|
}
|
|
369493
369805
|
const pathSegments = path3.split("/");
|
|
369494
|
-
for (const
|
|
369495
|
-
if (!isValidPathComponent(
|
|
369806
|
+
for (const segment2 of pathSegments) {
|
|
369807
|
+
if (!isValidPathComponent(segment2)) {
|
|
369496
369808
|
return c.json({ error: { code: "INVALID_PATH", message: "Invalid path" } }, 400);
|
|
369497
369809
|
}
|
|
369498
369810
|
}
|
|
@@ -369680,6 +369992,13 @@ async function resolveRecipient(to, channelType, services) {
|
|
|
369680
369992
|
recoverable: false
|
|
369681
369993
|
});
|
|
369682
369994
|
}
|
|
369995
|
+
async function persistStarState(services, instanceId, channelExternalId, messageExternalId, starred) {
|
|
369996
|
+
try {
|
|
369997
|
+
const chat2 = await services.chats.getByExternalId(instanceId, channelExternalId);
|
|
369998
|
+
if (chat2)
|
|
369999
|
+
await services.messages.setStarred(chat2.id, messageExternalId, starred);
|
|
370000
|
+
} catch {}
|
|
370001
|
+
}
|
|
369683
370002
|
async function getPluginForInstance2(services, channelRegistry2, instanceId, requiredCapability) {
|
|
369684
370003
|
const instance4 = await services.instances.getById(instanceId);
|
|
369685
370004
|
if (!channelRegistry2) {
|
|
@@ -369845,7 +370164,7 @@ async function computeCloseContactTerminalState(db2, chatUuid, outcome, auditRow
|
|
|
369845
370164
|
return { terminal: false, escalated: false, closeUntil };
|
|
369846
370165
|
}
|
|
369847
370166
|
function hasPresenceStatusSender(plugin10) {
|
|
369848
|
-
return typeof plugin10 === "object" && plugin10 !== null &&
|
|
370167
|
+
return typeof plugin10 === "object" && plugin10 !== null && typeof plugin10.sendPresenceStatus === "function";
|
|
369849
370168
|
}
|
|
369850
370169
|
async function verifyMessageInstanceOwnership(services, message2, instanceId) {
|
|
369851
370170
|
if (!message2.chatId)
|
|
@@ -369868,7 +370187,7 @@ async function resolveChannelMessageId(services, messageId, instanceId) {
|
|
|
369868
370187
|
log117.debug("Resolved internal UUID to external ID", { messageId, externalId: message2.externalId });
|
|
369869
370188
|
return message2.externalId;
|
|
369870
370189
|
}
|
|
369871
|
-
var log117, mediaDownloadLog, messagesRoutes, MIME_BY_EXTENSION, DEFAULT_MIME_BY_MEDIA_TYPE, UUID_REGEX2, MessageSourceSchema, MessageTypeSchema, MessageStatusSchema, DeliveryStatusSchema, listQuerySchema14, createMessageSchema, updateMessageSchema, recordEditSchema, addReactionSchema, removeReactionSchema, updateDeliveryStatusSchema, MentionSchema, sendTextSchema, sendMediaSchema, sendReactionSchema, sendStickerSchema, sendContactSchema, sendLocationSchema, sendHandoffSchema, sendCloseContactSchema, messageRefSchema, _mediaStorageForDownload = null, sendTtsSchema, forwardMessageSchema, sendPresenceSchema, markMessageReadSchema, markBatchReadSchema, sendPollSchema, sendEmbedSchema, editMessageChannelSchema, deleteMessageChannelSchema, starMessageSchema;
|
|
370190
|
+
var log117, mediaDownloadLog, messagesRoutes, MIME_BY_EXTENSION, DEFAULT_MIME_BY_MEDIA_TYPE, UUID_REGEX2, permalinkQuerySchema, MessageSourceSchema, MessageTypeSchema, MessageStatusSchema, DeliveryStatusSchema, listQuerySchema14, createMessageSchema, updateMessageSchema, recordEditSchema, addReactionSchema, removeReactionSchema, updateDeliveryStatusSchema, MentionSchema, sendTextSchema, sendMediaSchema, sendReactionSchema, sendStickerSchema, sendContactSchema, sendLocationSchema, sendHandoffSchema, sendCloseContactSchema, messageRefSchema, _mediaStorageForDownload = null, sendTtsSchema, forwardMessageSchema, sendPresenceSchema, markMessageReadSchema, markBatchReadSchema, sendPollSchema, sendEmbedSchema, editMessageChannelSchema, deleteMessageChannelSchema, starMessageSchema;
|
|
369872
370191
|
var init_messages5 = __esm(() => {
|
|
369873
370192
|
init_dist6();
|
|
369874
370193
|
init_src2();
|
|
@@ -369911,6 +370230,42 @@ var init_messages5 = __esm(() => {
|
|
|
369911
370230
|
document: "application/octet-stream"
|
|
369912
370231
|
};
|
|
369913
370232
|
UUID_REGEX2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
370233
|
+
permalinkQuerySchema = exports_external.object({
|
|
370234
|
+
instanceId: exports_external.string().uuid(),
|
|
370235
|
+
channelId: exports_external.string().min(1).describe("Platform chat/channel id containing the message")
|
|
370236
|
+
});
|
|
370237
|
+
messagesRoutes.get("/:id/permalink", zValidator("query", permalinkQuerySchema), async (c) => {
|
|
370238
|
+
const messageId = c.req.param("id");
|
|
370239
|
+
const { instanceId, channelId } = c.req.valid("query");
|
|
370240
|
+
checkInstanceAccess2(c.get("apiKey"), instanceId);
|
|
370241
|
+
const services = c.get("services");
|
|
370242
|
+
const chat2 = await services.chats.getByExternalId(instanceId, channelId);
|
|
370243
|
+
const stored = chat2 ? await services.messages.getByExternalId(chat2.id, messageId) : null;
|
|
370244
|
+
if (stored?.permalink) {
|
|
370245
|
+
return c.json({ data: { messageId, permalink: stored.permalink, cached: true } });
|
|
370246
|
+
}
|
|
370247
|
+
const { instance: instance4, plugin: plugin10 } = await getPluginForInstance2(services, c.get("channelRegistry"), instanceId);
|
|
370248
|
+
if (typeof plugin10.getPermalink !== "function") {
|
|
370249
|
+
throw new OmniError({
|
|
370250
|
+
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
370251
|
+
message: `Channel ${instance4.channel} cannot resolve permalinks`,
|
|
370252
|
+
context: { channelType: instance4.channel },
|
|
370253
|
+
recoverable: false
|
|
370254
|
+
});
|
|
370255
|
+
}
|
|
370256
|
+
const permalink = await plugin10.getPermalink(instanceId, channelId, messageId);
|
|
370257
|
+
if (!permalink) {
|
|
370258
|
+
throw new OmniError({
|
|
370259
|
+
code: ERROR_CODES.NOT_FOUND,
|
|
370260
|
+
message: `No permalink available for message ${messageId}`,
|
|
370261
|
+
recoverable: false
|
|
370262
|
+
});
|
|
370263
|
+
}
|
|
370264
|
+
if (chat2) {
|
|
370265
|
+
await services.messages.setPermalink(chat2.id, messageId, permalink).catch(() => {});
|
|
370266
|
+
}
|
|
370267
|
+
return c.json({ data: { messageId, permalink, cached: false } });
|
|
370268
|
+
});
|
|
369914
370269
|
MessageSourceSchema = exports_external.enum(["realtime", "sync", "api", "import"]);
|
|
369915
370270
|
MessageTypeSchema = exports_external.enum([
|
|
369916
370271
|
"text",
|
|
@@ -370923,7 +371278,7 @@ var init_messages5 = __esm(() => {
|
|
|
370923
371278
|
stability: data.stability,
|
|
370924
371279
|
similarityBoost: data.similarityBoost
|
|
370925
371280
|
});
|
|
370926
|
-
if (
|
|
371281
|
+
if (typeof plugin10.sendTyping === "function") {
|
|
370927
371282
|
const presenceDuration = data.presenceDelay ?? Math.min(ttsResult.durationMs, 15000);
|
|
370928
371283
|
try {
|
|
370929
371284
|
await plugin10.sendTyping(data.instanceId, resolvedTo, presenceDuration);
|
|
@@ -371100,7 +371455,7 @@ var init_messages5 = __esm(() => {
|
|
|
371100
371455
|
status,
|
|
371101
371456
|
loadingMessages
|
|
371102
371457
|
}) : await (async () => {
|
|
371103
|
-
if (
|
|
371458
|
+
if (typeof plugin10.sendTyping !== "function") {
|
|
371104
371459
|
throw new OmniError({
|
|
371105
371460
|
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
371106
371461
|
message: `Channel ${instance4.channel} plugin does not implement sendTyping`,
|
|
@@ -371152,7 +371507,7 @@ var init_messages5 = __esm(() => {
|
|
|
371152
371507
|
});
|
|
371153
371508
|
}
|
|
371154
371509
|
const { instance: instance4, plugin: plugin10 } = await getPluginForInstance2(services, channelRegistry2, instanceId, "canReceiveReadReceipts");
|
|
371155
|
-
if (
|
|
371510
|
+
if (typeof plugin10.markAsRead !== "function") {
|
|
371156
371511
|
throw new OmniError({
|
|
371157
371512
|
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
371158
371513
|
message: `Channel ${instance4.channel} plugin does not implement markAsRead`,
|
|
@@ -371178,7 +371533,7 @@ var init_messages5 = __esm(() => {
|
|
|
371178
371533
|
const channelRegistry2 = c.get("channelRegistry");
|
|
371179
371534
|
checkInstanceAccess2(c.get("apiKey"), instanceId);
|
|
371180
371535
|
const { instance: instance4, plugin: plugin10 } = await getPluginForInstance2(services, channelRegistry2, instanceId, "canReceiveReadReceipts");
|
|
371181
|
-
if (
|
|
371536
|
+
if (typeof plugin10.markAsRead !== "function") {
|
|
371182
371537
|
throw new OmniError({
|
|
371183
371538
|
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
371184
371539
|
message: `Channel ${instance4.channel} plugin does not implement markAsRead`,
|
|
@@ -371414,7 +371769,7 @@ var init_messages5 = __esm(() => {
|
|
|
371414
371769
|
recoverable: false
|
|
371415
371770
|
});
|
|
371416
371771
|
}
|
|
371417
|
-
if (
|
|
371772
|
+
if (typeof plugin10.editMessage !== "function") {
|
|
371418
371773
|
throw new OmniError({
|
|
371419
371774
|
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
371420
371775
|
message: `Channel ${instance4.channel} plugin does not implement editMessage`,
|
|
@@ -371470,7 +371825,7 @@ var init_messages5 = __esm(() => {
|
|
|
371470
371825
|
recoverable: false
|
|
371471
371826
|
});
|
|
371472
371827
|
}
|
|
371473
|
-
if (
|
|
371828
|
+
if (typeof plugin10.deleteMessage !== "function") {
|
|
371474
371829
|
throw new OmniError({
|
|
371475
371830
|
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
371476
371831
|
message: `Channel ${instance4.channel} plugin does not implement deleteMessage`,
|
|
@@ -371513,7 +371868,7 @@ var init_messages5 = __esm(() => {
|
|
|
371513
371868
|
recoverable: false
|
|
371514
371869
|
});
|
|
371515
371870
|
}
|
|
371516
|
-
if (
|
|
371871
|
+
if (typeof plugin10.starMessage !== "function") {
|
|
371517
371872
|
throw new OmniError({
|
|
371518
371873
|
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
371519
371874
|
message: `Channel ${instance4.channel} does not support starring messages`,
|
|
@@ -371522,6 +371877,7 @@ var init_messages5 = __esm(() => {
|
|
|
371522
371877
|
});
|
|
371523
371878
|
}
|
|
371524
371879
|
await plugin10.starMessage(instanceId, channelId, messageId, true, fromMe);
|
|
371880
|
+
await persistStarState(services, instanceId, channelId, messageId, true);
|
|
371525
371881
|
return c.json({
|
|
371526
371882
|
success: true,
|
|
371527
371883
|
data: { messageId, starred: true }
|
|
@@ -371550,7 +371906,7 @@ var init_messages5 = __esm(() => {
|
|
|
371550
371906
|
recoverable: false
|
|
371551
371907
|
});
|
|
371552
371908
|
}
|
|
371553
|
-
if (
|
|
371909
|
+
if (typeof plugin10.starMessage !== "function") {
|
|
371554
371910
|
throw new OmniError({
|
|
371555
371911
|
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
371556
371912
|
message: `Channel ${instance4.channel} does not support starring messages`,
|
|
@@ -371559,6 +371915,7 @@ var init_messages5 = __esm(() => {
|
|
|
371559
371915
|
});
|
|
371560
371916
|
}
|
|
371561
371917
|
await plugin10.starMessage(instanceId, channelId, messageId, false, fromMe);
|
|
371918
|
+
await persistStarState(services, instanceId, channelId, messageId, false);
|
|
371562
371919
|
return c.json({
|
|
371563
371920
|
success: true,
|
|
371564
371921
|
data: { messageId, starred: false }
|
|
@@ -372024,15 +372381,345 @@ var init_providers4 = __esm(() => {
|
|
|
372024
372381
|
});
|
|
372025
372382
|
});
|
|
372026
372383
|
|
|
372384
|
+
// ../api/src/services/scheduled-messages.ts
|
|
372385
|
+
function accumulate(total, pass) {
|
|
372386
|
+
total.scanned += pass.scanned;
|
|
372387
|
+
total.sent += pass.sent;
|
|
372388
|
+
total.failed += pass.failed;
|
|
372389
|
+
}
|
|
372390
|
+
function parseOutgoingContent(raw2, scheduledMessageId) {
|
|
372391
|
+
if (!raw2 || typeof raw2 !== "object" || Array.isArray(raw2)) {
|
|
372392
|
+
throw callerError(`Scheduled message ${scheduledMessageId} has non-object content`);
|
|
372393
|
+
}
|
|
372394
|
+
const type = raw2.type;
|
|
372395
|
+
if (typeof type !== "string" || type.length === 0) {
|
|
372396
|
+
throw callerError(`Scheduled message ${scheduledMessageId} has content without a 'type' discriminant`);
|
|
372397
|
+
}
|
|
372398
|
+
return raw2;
|
|
372399
|
+
}
|
|
372400
|
+
function callerError(message2) {
|
|
372401
|
+
return new OmniError({ code: ERROR_CODES.VALIDATION, message: message2, recoverable: false });
|
|
372402
|
+
}
|
|
372403
|
+
|
|
372404
|
+
class ScheduledMessageService {
|
|
372405
|
+
db;
|
|
372406
|
+
resolvePlugin;
|
|
372407
|
+
logger;
|
|
372408
|
+
authPlaneDb;
|
|
372409
|
+
warnedMissingAuthPlane = false;
|
|
372410
|
+
constructor(db2, resolvePlugin, logger7) {
|
|
372411
|
+
this.db = db2;
|
|
372412
|
+
this.resolvePlugin = resolvePlugin;
|
|
372413
|
+
this.logger = logger7 ?? createLogger("services:scheduled-messages");
|
|
372414
|
+
}
|
|
372415
|
+
async schedule(input) {
|
|
372416
|
+
if (input.sendAt.getTime() <= Date.now()) {
|
|
372417
|
+
throw callerError(`sendAt must be in the future (got ${input.sendAt.toISOString()})`);
|
|
372418
|
+
}
|
|
372419
|
+
parseOutgoingContent(input.content, "(new)");
|
|
372420
|
+
const plugin10 = await this.resolvePlugin(input.instanceId);
|
|
372421
|
+
if (!plugin10) {
|
|
372422
|
+
throw new Error(`No channel plugin for instance ${input.instanceId}`);
|
|
372423
|
+
}
|
|
372424
|
+
const native = plugin10.capabilities.canScheduleMessage === true && typeof plugin10.scheduleMessage === "function";
|
|
372425
|
+
const deliveryMode = native ? "platform" : "local";
|
|
372426
|
+
const maxAhead = plugin10.capabilities.maxScheduleAheadMs;
|
|
372427
|
+
if (native && typeof maxAhead === "number" && input.sendAt.getTime() - Date.now() > maxAhead) {
|
|
372428
|
+
throw callerError(`sendAt exceeds what ${plugin10.id} accepts natively (${Math.round(maxAhead / 86400000)} days ahead).`);
|
|
372429
|
+
}
|
|
372430
|
+
let externalScheduledId;
|
|
372431
|
+
if (native) {
|
|
372432
|
+
externalScheduledId = await plugin10.scheduleMessage?.(input.instanceId, this.toOutgoingMessage(input), input.sendAt);
|
|
372433
|
+
}
|
|
372434
|
+
try {
|
|
372435
|
+
const [row] = await this.db.insert(scheduledMessages).values({
|
|
372436
|
+
instanceId: input.instanceId,
|
|
372437
|
+
chatExternalId: input.chatExternalId,
|
|
372438
|
+
threadExternalId: input.threadExternalId,
|
|
372439
|
+
isThreadBroadcast: input.isThreadBroadcast ?? false,
|
|
372440
|
+
content: input.content,
|
|
372441
|
+
sendAt: input.sendAt,
|
|
372442
|
+
deliveryMode,
|
|
372443
|
+
status: "pending",
|
|
372444
|
+
externalScheduledId,
|
|
372445
|
+
createdByAgentId: input.createdByAgentId
|
|
372446
|
+
}).returning();
|
|
372447
|
+
if (!row)
|
|
372448
|
+
throw new Error("Failed to persist scheduled message");
|
|
372449
|
+
return row;
|
|
372450
|
+
} catch (error3) {
|
|
372451
|
+
if (native && externalScheduledId) {
|
|
372452
|
+
try {
|
|
372453
|
+
await plugin10.cancelScheduledMessage?.(input.instanceId, input.chatExternalId, externalScheduledId);
|
|
372454
|
+
} catch (cancelError) {
|
|
372455
|
+
this.logger.warn("Failed to roll back native schedule after a row-insert failure", {
|
|
372456
|
+
instanceId: input.instanceId,
|
|
372457
|
+
externalScheduledId,
|
|
372458
|
+
error: cancelError instanceof Error ? cancelError.message : String(cancelError)
|
|
372459
|
+
});
|
|
372460
|
+
}
|
|
372461
|
+
}
|
|
372462
|
+
throw error3;
|
|
372463
|
+
}
|
|
372464
|
+
}
|
|
372465
|
+
async cancel(id) {
|
|
372466
|
+
const row = await this.getById(id);
|
|
372467
|
+
if (!row)
|
|
372468
|
+
return null;
|
|
372469
|
+
if (row.status !== "pending")
|
|
372470
|
+
return row;
|
|
372471
|
+
if (row.deliveryMode === "platform" && row.externalScheduledId) {
|
|
372472
|
+
const plugin10 = await this.resolvePlugin(row.instanceId);
|
|
372473
|
+
try {
|
|
372474
|
+
await plugin10?.cancelScheduledMessage?.(row.instanceId, row.chatExternalId, row.externalScheduledId);
|
|
372475
|
+
} catch (error3) {
|
|
372476
|
+
this.logger.warn("Platform refused the cancel; marking canceled locally anyway", {
|
|
372477
|
+
scheduledMessageId: id,
|
|
372478
|
+
error: error3 instanceof Error ? error3.message : String(error3)
|
|
372479
|
+
});
|
|
372480
|
+
}
|
|
372481
|
+
}
|
|
372482
|
+
const [updated] = await this.db.update(scheduledMessages).set({ status: "canceled", canceledAt: new Date, updatedAt: new Date }).where(and2(eq(scheduledMessages.id, id), eq(scheduledMessages.status, "pending"))).returning();
|
|
372483
|
+
return updated ?? row;
|
|
372484
|
+
}
|
|
372485
|
+
async getById(id) {
|
|
372486
|
+
const [row] = await this.db.select().from(scheduledMessages).where(eq(scheduledMessages.id, id)).limit(1);
|
|
372487
|
+
return row ?? null;
|
|
372488
|
+
}
|
|
372489
|
+
async listPending(instanceId, limit2 = 100) {
|
|
372490
|
+
return this.db.select().from(scheduledMessages).where(and2(eq(scheduledMessages.instanceId, instanceId), eq(scheduledMessages.status, "pending"))).orderBy(asc(scheduledMessages.sendAt)).limit(limit2);
|
|
372491
|
+
}
|
|
372492
|
+
setAuthPlane(db2) {
|
|
372493
|
+
this.authPlaneDb = db2;
|
|
372494
|
+
}
|
|
372495
|
+
async sweep() {
|
|
372496
|
+
if (!isMultitenancyEnabled()) {
|
|
372497
|
+
return this.sweepWorld({ kind: "all" });
|
|
372498
|
+
}
|
|
372499
|
+
const totals = { scanned: 0, sent: 0, failed: 0 };
|
|
372500
|
+
if (this.authPlaneDb) {
|
|
372501
|
+
for (const tenantId of await enumerateActiveWorkTenants(this.authPlaneDb)) {
|
|
372502
|
+
try {
|
|
372503
|
+
accumulate(totals, await this.sweepWorld({ kind: "tenant", tenantId }));
|
|
372504
|
+
} catch (error3) {
|
|
372505
|
+
this.logger.warn("scheduled-message sweeper: tenant pass failed", {
|
|
372506
|
+
tenantId,
|
|
372507
|
+
error: error3 instanceof Error ? error3.message : String(error3)
|
|
372508
|
+
});
|
|
372509
|
+
}
|
|
372510
|
+
}
|
|
372511
|
+
} else if (!this.warnedMissingAuthPlane) {
|
|
372512
|
+
this.warnedMissingAuthPlane = true;
|
|
372513
|
+
this.logger.warn("scheduled-message sweeper: multitenancy is enabled but no auth-plane connection was injected \u2014 tenant rows will not be swept");
|
|
372514
|
+
}
|
|
372515
|
+
if (resolveEnforcementMode(process.env) !== "enforced") {
|
|
372516
|
+
accumulate(totals, await this.sweepWorld({ kind: "legacy-rows" }));
|
|
372517
|
+
}
|
|
372518
|
+
return totals;
|
|
372519
|
+
}
|
|
372520
|
+
worldPredicate(world) {
|
|
372521
|
+
if (world.kind === "tenant") {
|
|
372522
|
+
return [
|
|
372523
|
+
sql`EXISTS (SELECT 1 FROM ${instances} WHERE ${instances.id} = ${scheduledMessages.instanceId} AND ${instances.tenantId} = ${world.tenantId})`
|
|
372524
|
+
];
|
|
372525
|
+
}
|
|
372526
|
+
if (world.kind === "legacy-rows") {
|
|
372527
|
+
return [
|
|
372528
|
+
sql`EXISTS (SELECT 1 FROM ${instances} WHERE ${instances.id} = ${scheduledMessages.instanceId} AND ${instances.tenantId} IS NULL)`
|
|
372529
|
+
];
|
|
372530
|
+
}
|
|
372531
|
+
return [];
|
|
372532
|
+
}
|
|
372533
|
+
async sweepWorld(world) {
|
|
372534
|
+
const stats = { scanned: 0, sent: 0, failed: 0 };
|
|
372535
|
+
const now = new Date;
|
|
372536
|
+
const claimCutoff = new Date(now.getTime() - CLAIM_LEASE_MS);
|
|
372537
|
+
const due = await this.db.transaction(async (tx) => {
|
|
372538
|
+
const locked = await tx.select({ id: scheduledMessages.id }).from(scheduledMessages).where(and2(eq(scheduledMessages.deliveryMode, "local"), lte(scheduledMessages.sendAt, now), or2(eq(scheduledMessages.status, "pending"), and2(eq(scheduledMessages.status, "sending"), lte(scheduledMessages.updatedAt, claimCutoff))), ...this.worldPredicate(world))).orderBy(asc(scheduledMessages.sendAt)).limit(MAX_PER_TICK).for("update", { skipLocked: true });
|
|
372539
|
+
if (locked.length === 0)
|
|
372540
|
+
return [];
|
|
372541
|
+
return tx.update(scheduledMessages).set({ status: "sending", updatedAt: now }).where(inArray(scheduledMessages.id, locked.map((r) => r.id))).returning();
|
|
372542
|
+
});
|
|
372543
|
+
stats.scanned = due.length;
|
|
372544
|
+
for (const row of due) {
|
|
372545
|
+
try {
|
|
372546
|
+
const plugin10 = await this.resolvePlugin(row.instanceId);
|
|
372547
|
+
if (!plugin10)
|
|
372548
|
+
throw new Error(`No channel plugin for instance ${row.instanceId}`);
|
|
372549
|
+
const result = await plugin10.sendMessage(row.instanceId, {
|
|
372550
|
+
to: row.chatExternalId,
|
|
372551
|
+
threadId: row.threadExternalId ?? undefined,
|
|
372552
|
+
content: parseOutgoingContent(row.content, row.id),
|
|
372553
|
+
metadata: { isThreadBroadcast: row.isThreadBroadcast }
|
|
372554
|
+
});
|
|
372555
|
+
if (!result.success) {
|
|
372556
|
+
throw new Error(result.error ?? "sendMessage reported failure without an error");
|
|
372557
|
+
}
|
|
372558
|
+
await this.db.update(scheduledMessages).set({
|
|
372559
|
+
status: "sent",
|
|
372560
|
+
sentAt: new Date,
|
|
372561
|
+
sentExternalId: result.messageId,
|
|
372562
|
+
attemptCount: row.attemptCount + 1,
|
|
372563
|
+
updatedAt: new Date
|
|
372564
|
+
}).where(and2(eq(scheduledMessages.id, row.id), eq(scheduledMessages.status, "sending")));
|
|
372565
|
+
stats.sent++;
|
|
372566
|
+
} catch (error3) {
|
|
372567
|
+
const message2 = error3 instanceof Error ? error3.message : String(error3);
|
|
372568
|
+
const attempts = row.attemptCount + 1;
|
|
372569
|
+
const exhausted = attempts >= MAX_ATTEMPTS;
|
|
372570
|
+
await this.db.update(scheduledMessages).set({
|
|
372571
|
+
status: exhausted ? "failed" : "pending",
|
|
372572
|
+
failedAt: exhausted ? new Date : null,
|
|
372573
|
+
lastError: message2,
|
|
372574
|
+
attemptCount: attempts,
|
|
372575
|
+
updatedAt: new Date
|
|
372576
|
+
}).where(and2(eq(scheduledMessages.id, row.id), eq(scheduledMessages.status, "sending")));
|
|
372577
|
+
stats.failed++;
|
|
372578
|
+
this.logger.warn("Scheduled message delivery failed", {
|
|
372579
|
+
scheduledMessageId: row.id,
|
|
372580
|
+
attempts,
|
|
372581
|
+
exhausted,
|
|
372582
|
+
error: message2
|
|
372583
|
+
});
|
|
372584
|
+
}
|
|
372585
|
+
}
|
|
372586
|
+
return stats;
|
|
372587
|
+
}
|
|
372588
|
+
async pruneTerminal(olderThan) {
|
|
372589
|
+
const result = await this.db.delete(scheduledMessages).where(and2(sql`${scheduledMessages.status} IN ('sent', 'canceled', 'failed')`, lte(scheduledMessages.updatedAt, olderThan))).returning({ id: scheduledMessages.id });
|
|
372590
|
+
return result.length;
|
|
372591
|
+
}
|
|
372592
|
+
toOutgoingMessage(input) {
|
|
372593
|
+
return {
|
|
372594
|
+
to: input.chatExternalId,
|
|
372595
|
+
threadId: input.threadExternalId,
|
|
372596
|
+
content: parseOutgoingContent(input.content, "(new)"),
|
|
372597
|
+
metadata: { isThreadBroadcast: input.isThreadBroadcast ?? false }
|
|
372598
|
+
};
|
|
372599
|
+
}
|
|
372600
|
+
}
|
|
372601
|
+
function createPluginResolver(db2, getPlugin2) {
|
|
372602
|
+
return async (instanceId) => {
|
|
372603
|
+
const [row] = await db2.select({ channel: instances.channel }).from(instances).where(eq(instances.id, instanceId)).limit(1);
|
|
372604
|
+
if (!row)
|
|
372605
|
+
return null;
|
|
372606
|
+
return getPlugin2(row.channel) ?? null;
|
|
372607
|
+
};
|
|
372608
|
+
}
|
|
372609
|
+
var MAX_PER_TICK = 50, MAX_ATTEMPTS = 3, CLAIM_LEASE_MS;
|
|
372610
|
+
var init_scheduled_messages = __esm(() => {
|
|
372611
|
+
init_src();
|
|
372612
|
+
init_src5();
|
|
372613
|
+
init_drizzle_orm();
|
|
372614
|
+
init_periodic_tenant_work();
|
|
372615
|
+
CLAIM_LEASE_MS = 5 * 60000;
|
|
372616
|
+
});
|
|
372617
|
+
|
|
372618
|
+
// ../api/src/routes/v2/scheduled-messages.ts
|
|
372619
|
+
function getService(c) {
|
|
372620
|
+
const db2 = c.get("db");
|
|
372621
|
+
const registry5 = c.get("channelRegistry");
|
|
372622
|
+
if (!registry5) {
|
|
372623
|
+
throw new OmniError({
|
|
372624
|
+
code: ERROR_CODES.CHANNEL_NOT_CONNECTED,
|
|
372625
|
+
message: "Channel registry not available",
|
|
372626
|
+
recoverable: false
|
|
372627
|
+
});
|
|
372628
|
+
}
|
|
372629
|
+
return new ScheduledMessageService(db2, createPluginResolver(db2, (channel5) => registry5.get(channel5)));
|
|
372630
|
+
}
|
|
372631
|
+
var scheduledMessagesRoutes, scheduleSchema, listQuerySchema17;
|
|
372632
|
+
var init_scheduled_messages2 = __esm(() => {
|
|
372633
|
+
init_dist6();
|
|
372634
|
+
init_src();
|
|
372635
|
+
init_dist2();
|
|
372636
|
+
init_zod();
|
|
372637
|
+
init_scheduled_messages();
|
|
372638
|
+
scheduledMessagesRoutes = new Hono2;
|
|
372639
|
+
scheduleSchema = exports_external.object({
|
|
372640
|
+
instanceId: exports_external.string().uuid(),
|
|
372641
|
+
chatId: exports_external.string().min(1).describe("Platform chat/channel id (e.g. Slack C\u2026/D\u2026)"),
|
|
372642
|
+
content: exports_external.record(exports_external.unknown()).describe("OutgoingContent, e.g. { type: 'text', text: 'oi' }"),
|
|
372643
|
+
sendAt: exports_external.string().datetime().describe("ISO-8601 delivery time (UTC-aware)"),
|
|
372644
|
+
threadId: exports_external.string().optional().describe("Post into this thread (Slack thread_ts)"),
|
|
372645
|
+
isThreadBroadcast: exports_external.boolean().optional().describe("Also surface it in the channel (Slack reply_broadcast)")
|
|
372646
|
+
});
|
|
372647
|
+
listQuerySchema17 = exports_external.object({
|
|
372648
|
+
instanceId: exports_external.string().uuid(),
|
|
372649
|
+
limit: exports_external.coerce.number().int().min(1).max(500).default(100)
|
|
372650
|
+
});
|
|
372651
|
+
scheduledMessagesRoutes.post("/", zValidator("json", scheduleSchema), async (c) => {
|
|
372652
|
+
const body = c.req.valid("json");
|
|
372653
|
+
const sendAt = new Date(body.sendAt);
|
|
372654
|
+
try {
|
|
372655
|
+
const row = await getService(c).schedule({
|
|
372656
|
+
instanceId: body.instanceId,
|
|
372657
|
+
chatExternalId: body.chatId,
|
|
372658
|
+
content: body.content,
|
|
372659
|
+
sendAt,
|
|
372660
|
+
threadExternalId: body.threadId,
|
|
372661
|
+
isThreadBroadcast: body.isThreadBroadcast
|
|
372662
|
+
});
|
|
372663
|
+
return c.json({ success: true, data: row }, 201);
|
|
372664
|
+
} catch (error3) {
|
|
372665
|
+
if (error3 instanceof OmniError)
|
|
372666
|
+
throw error3;
|
|
372667
|
+
throw new OmniError({
|
|
372668
|
+
code: ERROR_CODES.UNKNOWN,
|
|
372669
|
+
message: error3 instanceof Error ? error3.message : String(error3),
|
|
372670
|
+
recoverable: false,
|
|
372671
|
+
cause: error3 instanceof Error ? error3 : undefined
|
|
372672
|
+
});
|
|
372673
|
+
}
|
|
372674
|
+
});
|
|
372675
|
+
scheduledMessagesRoutes.get("/", zValidator("query", listQuerySchema17), async (c) => {
|
|
372676
|
+
const { instanceId, limit: limit2 } = c.req.valid("query");
|
|
372677
|
+
const rows = await getService(c).listPending(instanceId, limit2);
|
|
372678
|
+
return c.json({
|
|
372679
|
+
data: rows,
|
|
372680
|
+
meta: {
|
|
372681
|
+
count: rows.length,
|
|
372682
|
+
scope: "scheduled-via-omni"
|
|
372683
|
+
}
|
|
372684
|
+
});
|
|
372685
|
+
});
|
|
372686
|
+
scheduledMessagesRoutes.get("/:id", async (c) => {
|
|
372687
|
+
const row = await getService(c).getById(c.req.param("id"));
|
|
372688
|
+
if (!row) {
|
|
372689
|
+
throw new OmniError({
|
|
372690
|
+
code: ERROR_CODES.NOT_FOUND,
|
|
372691
|
+
message: `Scheduled message ${c.req.param("id")} not found`,
|
|
372692
|
+
recoverable: false
|
|
372693
|
+
});
|
|
372694
|
+
}
|
|
372695
|
+
return c.json({ data: row });
|
|
372696
|
+
});
|
|
372697
|
+
scheduledMessagesRoutes.delete("/:id", async (c) => {
|
|
372698
|
+
const id = c.req.param("id");
|
|
372699
|
+
const row = await getService(c).cancel(id);
|
|
372700
|
+
if (!row) {
|
|
372701
|
+
throw new OmniError({
|
|
372702
|
+
code: ERROR_CODES.NOT_FOUND,
|
|
372703
|
+
message: `Scheduled message ${id} not found`,
|
|
372704
|
+
recoverable: false
|
|
372705
|
+
});
|
|
372706
|
+
}
|
|
372707
|
+
return c.json({
|
|
372708
|
+
success: true,
|
|
372709
|
+
data: { id: row.id, status: row.status, canceledAt: row.canceledAt }
|
|
372710
|
+
});
|
|
372711
|
+
});
|
|
372712
|
+
});
|
|
372713
|
+
|
|
372027
372714
|
// ../api/src/routes/v2/settings.ts
|
|
372028
|
-
var settingsRoutes,
|
|
372715
|
+
var settingsRoutes, listQuerySchema18, setSettingSchema, bulkUpdateSchema, historyQuerySchema;
|
|
372029
372716
|
var init_settings3 = __esm(() => {
|
|
372030
372717
|
init_dist6();
|
|
372031
372718
|
init_dist2();
|
|
372032
372719
|
init_zod();
|
|
372033
372720
|
init_date_query();
|
|
372034
372721
|
settingsRoutes = new Hono2;
|
|
372035
|
-
|
|
372722
|
+
listQuerySchema18 = exports_external.object({
|
|
372036
372723
|
category: exports_external.string().optional()
|
|
372037
372724
|
});
|
|
372038
372725
|
setSettingSchema = exports_external.object({
|
|
@@ -372047,7 +372734,7 @@ var init_settings3 = __esm(() => {
|
|
|
372047
372734
|
limit: exports_external.coerce.number().int().min(1).max(100).default(50),
|
|
372048
372735
|
since: optionalDateParam("since")
|
|
372049
372736
|
});
|
|
372050
|
-
settingsRoutes.get("/", zValidator("query",
|
|
372737
|
+
settingsRoutes.get("/", zValidator("query", listQuerySchema18), async (c) => {
|
|
372051
372738
|
const { category } = c.req.valid("query");
|
|
372052
372739
|
const services = c.get("services");
|
|
372053
372740
|
const settings = await services.settings.list(category);
|
|
@@ -372122,6 +372809,116 @@ var init_settings3 = __esm(() => {
|
|
|
372122
372809
|
});
|
|
372123
372810
|
});
|
|
372124
372811
|
|
|
372812
|
+
// ../api/src/routes/v2/slack.ts
|
|
372813
|
+
function checkInstanceAccess3(apiKey, instanceId) {
|
|
372814
|
+
if (apiKey && !ApiKeyService.instanceAllowed(apiKey.instanceIds, instanceId)) {
|
|
372815
|
+
throw new OmniError({
|
|
372816
|
+
code: ERROR_CODES.FORBIDDEN,
|
|
372817
|
+
message: "API key does not have access to this instance",
|
|
372818
|
+
context: { instanceId },
|
|
372819
|
+
recoverable: false
|
|
372820
|
+
});
|
|
372821
|
+
}
|
|
372822
|
+
}
|
|
372823
|
+
async function getSlackPlugin(c, instanceId) {
|
|
372824
|
+
checkInstanceAccess3(c.get("apiKey"), instanceId);
|
|
372825
|
+
const services = c.get("services");
|
|
372826
|
+
const registry5 = c.get("channelRegistry");
|
|
372827
|
+
const instance4 = await services.instances.getById(instanceId);
|
|
372828
|
+
if (instance4.channel !== "slack") {
|
|
372829
|
+
throw new OmniError({
|
|
372830
|
+
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
372831
|
+
message: `Instance ${instanceId} is a ${instance4.channel} instance; these endpoints are Slack-only`,
|
|
372832
|
+
context: { channelType: instance4.channel },
|
|
372833
|
+
recoverable: false
|
|
372834
|
+
});
|
|
372835
|
+
}
|
|
372836
|
+
if (!registry5) {
|
|
372837
|
+
throw new OmniError({
|
|
372838
|
+
code: ERROR_CODES.CHANNEL_NOT_CONNECTED,
|
|
372839
|
+
message: "Channel registry not available",
|
|
372840
|
+
recoverable: false
|
|
372841
|
+
});
|
|
372842
|
+
}
|
|
372843
|
+
const plugin10 = registry5.get("slack");
|
|
372844
|
+
if (!plugin10) {
|
|
372845
|
+
throw new OmniError({
|
|
372846
|
+
code: ERROR_CODES.CHANNEL_NOT_CONNECTED,
|
|
372847
|
+
message: "Slack plugin not registered",
|
|
372848
|
+
recoverable: false
|
|
372849
|
+
});
|
|
372850
|
+
}
|
|
372851
|
+
return plugin10;
|
|
372852
|
+
}
|
|
372853
|
+
var slackRoutes, openDmSchema, searchSchema;
|
|
372854
|
+
var init_slack = __esm(() => {
|
|
372855
|
+
init_dist6();
|
|
372856
|
+
init_src();
|
|
372857
|
+
init_dist2();
|
|
372858
|
+
init_zod();
|
|
372859
|
+
init_api_keys();
|
|
372860
|
+
slackRoutes = new Hono2;
|
|
372861
|
+
openDmSchema = exports_external.object({
|
|
372862
|
+
instanceId: exports_external.string().uuid(),
|
|
372863
|
+
userId: exports_external.string().min(1).describe("Slack user id (U\u2026) to open a DM with")
|
|
372864
|
+
});
|
|
372865
|
+
searchSchema = exports_external.object({
|
|
372866
|
+
instanceId: exports_external.string().uuid(),
|
|
372867
|
+
query: exports_external.string().min(1),
|
|
372868
|
+
count: exports_external.coerce.number().int().min(1).max(100).default(20),
|
|
372869
|
+
page: exports_external.coerce.number().int().min(1).default(1)
|
|
372870
|
+
});
|
|
372871
|
+
slackRoutes.post("/dm/open", zValidator("json", openDmSchema), async (c) => {
|
|
372872
|
+
const { instanceId, userId } = c.req.valid("json");
|
|
372873
|
+
const plugin10 = await getSlackPlugin(c, instanceId);
|
|
372874
|
+
if (typeof plugin10.openDirectMessage !== "function") {
|
|
372875
|
+
throw new OmniError({
|
|
372876
|
+
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
372877
|
+
message: "Slack plugin does not implement openDirectMessage",
|
|
372878
|
+
recoverable: false
|
|
372879
|
+
});
|
|
372880
|
+
}
|
|
372881
|
+
try {
|
|
372882
|
+
const channelId = await plugin10.openDirectMessage(instanceId, userId);
|
|
372883
|
+
return c.json({ success: true, data: { userId, channelId } });
|
|
372884
|
+
} catch (error3) {
|
|
372885
|
+
throw new OmniError({
|
|
372886
|
+
code: ERROR_CODES.CHANNEL_SEND_FAILED,
|
|
372887
|
+
message: error3 instanceof Error ? error3.message : String(error3),
|
|
372888
|
+
recoverable: true
|
|
372889
|
+
});
|
|
372890
|
+
}
|
|
372891
|
+
});
|
|
372892
|
+
slackRoutes.get("/search", zValidator("query", searchSchema), async (c) => {
|
|
372893
|
+
const { instanceId, query, count: count3, page } = c.req.valid("query");
|
|
372894
|
+
const plugin10 = await getSlackPlugin(c, instanceId);
|
|
372895
|
+
if (typeof plugin10.searchMessages !== "function") {
|
|
372896
|
+
throw new OmniError({
|
|
372897
|
+
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
372898
|
+
message: "Slack plugin does not implement searchMessages",
|
|
372899
|
+
recoverable: false
|
|
372900
|
+
});
|
|
372901
|
+
}
|
|
372902
|
+
try {
|
|
372903
|
+
const matches = await plugin10.searchMessages(instanceId, query, { count: count3, page });
|
|
372904
|
+
return c.json({
|
|
372905
|
+
data: matches,
|
|
372906
|
+
meta: {
|
|
372907
|
+
count: matches.length,
|
|
372908
|
+
page,
|
|
372909
|
+
scope: "authorizing-user"
|
|
372910
|
+
}
|
|
372911
|
+
});
|
|
372912
|
+
} catch (error3) {
|
|
372913
|
+
throw new OmniError({
|
|
372914
|
+
code: ERROR_CODES.CAPABILITY_NOT_SUPPORTED,
|
|
372915
|
+
message: error3 instanceof Error ? error3.message : String(error3),
|
|
372916
|
+
recoverable: false
|
|
372917
|
+
});
|
|
372918
|
+
}
|
|
372919
|
+
});
|
|
372920
|
+
});
|
|
372921
|
+
|
|
372125
372922
|
// ../api/src/routes/v2/templates.ts
|
|
372126
372923
|
function jsonError(message2, code = "BAD_REQUEST", _status = 400) {
|
|
372127
372924
|
return { error: { code, message: message2 } };
|
|
@@ -372146,7 +372943,7 @@ function makeClient(cfg) {
|
|
|
372146
372943
|
function variablesToBodyParameters(variables) {
|
|
372147
372944
|
return Object.entries(variables).map(([k2, v2]) => [Number.parseInt(k2, 10), v2]).filter(([n2]) => Number.isFinite(n2) && n2 >= 1).sort((a, b3) => a[0] - b3[0]).map(([, v2]) => v2);
|
|
372148
372945
|
}
|
|
372149
|
-
var log118, templatesRoutes, instanceAccess3, idParamSchema6, templateIdParamSchema, templateNameParamSchema,
|
|
372946
|
+
var log118, templatesRoutes, instanceAccess3, idParamSchema6, templateIdParamSchema, templateNameParamSchema, listQuerySchema19, createBodySchema, sendTestBodySchema, sendByNameBodySchema;
|
|
372150
372947
|
var init_templates3 = __esm(() => {
|
|
372151
372948
|
init_dist6();
|
|
372152
372949
|
init_src6();
|
|
@@ -372171,7 +372968,7 @@ var init_templates3 = __esm(() => {
|
|
|
372171
372968
|
id: exports_external.string().uuid(),
|
|
372172
372969
|
templateName: exports_external.string().min(1)
|
|
372173
372970
|
});
|
|
372174
|
-
|
|
372971
|
+
listQuerySchema19 = exports_external.object({
|
|
372175
372972
|
status: MetaTemplateStatusSchema.optional(),
|
|
372176
372973
|
category: MetaTemplateCategorySchema.optional(),
|
|
372177
372974
|
language: exports_external.string().min(2).optional(),
|
|
@@ -372199,7 +372996,7 @@ var init_templates3 = __esm(() => {
|
|
|
372199
372996
|
filename: exports_external.string().optional()
|
|
372200
372997
|
}).optional()
|
|
372201
372998
|
});
|
|
372202
|
-
templatesRoutes.get("/instances/:id/whatsapp-templates", instanceAccess3, zValidator("param", idParamSchema6), zValidator("query",
|
|
372999
|
+
templatesRoutes.get("/instances/:id/whatsapp-templates", instanceAccess3, zValidator("param", idParamSchema6), zValidator("query", listQuerySchema19), async (c) => {
|
|
372203
373000
|
const { id: instanceId } = c.req.valid("param");
|
|
372204
373001
|
const { status, category, language, sync } = c.req.valid("query");
|
|
372205
373002
|
const services = c.get("services");
|
|
@@ -372489,7 +373286,7 @@ async function resolveOpenTurn(services, keyId, turnId, headerInstanceId, header
|
|
|
372489
373286
|
}
|
|
372490
373287
|
return null;
|
|
372491
373288
|
}
|
|
372492
|
-
var turnsRoutes, closeTurnSchema,
|
|
373289
|
+
var turnsRoutes, closeTurnSchema, listQuerySchema20, adminForceCloseSchema, bulkCloseSchema;
|
|
372493
373290
|
var init_turns2 = __esm(() => {
|
|
372494
373291
|
init_dist6();
|
|
372495
373292
|
init_dist2();
|
|
@@ -372552,7 +373349,7 @@ var init_turns2 = __esm(() => {
|
|
|
372552
373349
|
}
|
|
372553
373350
|
});
|
|
372554
373351
|
});
|
|
372555
|
-
|
|
373352
|
+
listQuerySchema20 = exports_external.object({
|
|
372556
373353
|
status: exports_external.enum(["open", "done", "timeout"]).optional(),
|
|
372557
373354
|
instanceId: exports_external.string().uuid().optional(),
|
|
372558
373355
|
chatId: exports_external.string().optional(),
|
|
@@ -372567,7 +373364,7 @@ var init_turns2 = __esm(() => {
|
|
|
372567
373364
|
confirm: exports_external.boolean(),
|
|
372568
373365
|
reason: exports_external.string().optional()
|
|
372569
373366
|
});
|
|
372570
|
-
turnsRoutes.get("/", zValidator("query",
|
|
373367
|
+
turnsRoutes.get("/", zValidator("query", listQuerySchema20), async (c) => {
|
|
372571
373368
|
const denied = requireAdmin(c);
|
|
372572
373369
|
if (denied)
|
|
372573
373370
|
return denied;
|
|
@@ -372798,7 +373595,7 @@ var init_voice2 = __esm(() => {
|
|
|
372798
373595
|
});
|
|
372799
373596
|
|
|
372800
373597
|
// ../api/src/routes/v2/webhooks.ts
|
|
372801
|
-
var webhooksRoutes, createWebhookSourceSchema, updateWebhookSourceSchema,
|
|
373598
|
+
var webhooksRoutes, createWebhookSourceSchema, updateWebhookSourceSchema, listQuerySchema21, triggerEventSchema;
|
|
372802
373599
|
var init_webhooks3 = __esm(() => {
|
|
372803
373600
|
init_dist6();
|
|
372804
373601
|
init_dist2();
|
|
@@ -372812,10 +373609,10 @@ var init_webhooks3 = __esm(() => {
|
|
|
372812
373609
|
enabled: exports_external.boolean().default(true).describe("Whether source is enabled")
|
|
372813
373610
|
});
|
|
372814
373611
|
updateWebhookSourceSchema = createWebhookSourceSchema.partial();
|
|
372815
|
-
|
|
373612
|
+
listQuerySchema21 = exports_external.object({
|
|
372816
373613
|
enabled: exports_external.coerce.boolean().optional()
|
|
372817
373614
|
});
|
|
372818
|
-
webhooksRoutes.get("/webhook-sources", zValidator("query",
|
|
373615
|
+
webhooksRoutes.get("/webhook-sources", zValidator("query", listQuerySchema21), async (c) => {
|
|
372819
373616
|
const { enabled } = c.req.valid("query");
|
|
372820
373617
|
const services = c.get("services");
|
|
372821
373618
|
const sources = await services.webhooks.list({ enabled });
|
|
@@ -373680,7 +374477,9 @@ var init_v2 = __esm(() => {
|
|
|
373680
374477
|
init_persons3();
|
|
373681
374478
|
init_processed_events();
|
|
373682
374479
|
init_providers4();
|
|
374480
|
+
init_scheduled_messages2();
|
|
373683
374481
|
init_settings3();
|
|
374482
|
+
init_slack();
|
|
373684
374483
|
init_templates3();
|
|
373685
374484
|
init_trust();
|
|
373686
374485
|
init_turns2();
|
|
@@ -373697,6 +374496,8 @@ var init_v2 = __esm(() => {
|
|
|
373697
374496
|
v2Routes.route("/instances", instancesRoutes);
|
|
373698
374497
|
v2Routes.route("/logs", logsRoutes);
|
|
373699
374498
|
v2Routes.route("/messages", messagesRoutes);
|
|
374499
|
+
v2Routes.route("/scheduled-messages", scheduledMessagesRoutes);
|
|
374500
|
+
v2Routes.route("/slack", slackRoutes);
|
|
373700
374501
|
v2Routes.route("/events", eventsRoutes);
|
|
373701
374502
|
v2Routes.route("/journeys", journeysRoutes);
|
|
373702
374503
|
v2Routes.route("/persons", personsRoutes);
|
|
@@ -374813,6 +375614,27 @@ async function downloadMediaFromUrl(ctx, instanceId, messageId, mediaUrl, mimeTy
|
|
|
374813
375614
|
return null;
|
|
374814
375615
|
}
|
|
374815
375616
|
}
|
|
375617
|
+
async function downloadMediaViaPlugin(ctx, instanceId, messageId, channelType, mediaRef, fallbackMimeType, platformTimestamp, trustedTenantId) {
|
|
375618
|
+
const plugin10 = await (ctx.resolveChannelPlugin ?? getPlugin)(channelType);
|
|
375619
|
+
if (!plugin10?.downloadInboundMedia) {
|
|
375620
|
+
log122.warn("Channel plugin cannot materialize deferred media", { channelType, messageId });
|
|
375621
|
+
return null;
|
|
375622
|
+
}
|
|
375623
|
+
try {
|
|
375624
|
+
const { buffer: buffer3, mimeType } = pluginMediaSchema.parse(await plugin10.downloadInboundMedia(instanceId, mediaRef));
|
|
375625
|
+
const result = await ctx.mediaStorage.storeFromBuffer(instanceId, messageId, buffer3, mimeType || fallbackMimeType, platformTimestamp, trustedTenantId);
|
|
375626
|
+
await runMediaDb(ctx, trustedTenantId, () => ctx.mediaStorage.updateMessageLocalPath(messageId, result.localPath));
|
|
375627
|
+
log122.debug("Downloaded inbound media via plugin", { messageId, channelType, filePath: result.localPath });
|
|
375628
|
+
return result.localPath;
|
|
375629
|
+
} catch (error3) {
|
|
375630
|
+
log122.error("Failed to download inbound media via plugin", {
|
|
375631
|
+
error: String(error3),
|
|
375632
|
+
channelType,
|
|
375633
|
+
messageId
|
|
375634
|
+
});
|
|
375635
|
+
return null;
|
|
375636
|
+
}
|
|
375637
|
+
}
|
|
374816
375638
|
async function resolveMediaPath2(ctx, instanceId, chatId, externalId, content, mimeType, channelType, trustedTenantId) {
|
|
374817
375639
|
const maxWaitMs = 5000;
|
|
374818
375640
|
const pollMs = 250;
|
|
@@ -374842,6 +375664,11 @@ async function resolveMediaPath2(ctx, instanceId, chatId, externalId, content, m
|
|
|
374842
375664
|
if (!filePath)
|
|
374843
375665
|
return null;
|
|
374844
375666
|
}
|
|
375667
|
+
if (!filePath && content.mediaId && channelType) {
|
|
375668
|
+
filePath = await downloadMediaViaPlugin(ctx, instanceId, message2.id, channelType, content.mediaId, mimeType, message2.platformTimestamp ?? undefined, trustedTenantId);
|
|
375669
|
+
if (!filePath)
|
|
375670
|
+
return null;
|
|
375671
|
+
}
|
|
374845
375672
|
if (!filePath) {
|
|
374846
375673
|
log122.debug("No media file path available", { externalId });
|
|
374847
375674
|
return null;
|
|
@@ -375139,17 +375966,23 @@ async function setupMediaProcessor(eventBus, db2, services) {
|
|
|
375139
375966
|
});
|
|
375140
375967
|
log122.info("Media processor initialized");
|
|
375141
375968
|
}
|
|
375142
|
-
var log122, PROCESSABLE_MEDIA_TYPES;
|
|
375969
|
+
var log122, PROCESSABLE_MEDIA_TYPES, pluginMediaSchema;
|
|
375143
375970
|
var init_media_processor = __esm(() => {
|
|
375144
375971
|
init_src();
|
|
375145
375972
|
init_src5();
|
|
375146
375973
|
init_src8();
|
|
375147
375974
|
init_drizzle_orm();
|
|
375975
|
+
init_zod();
|
|
375148
375976
|
init_media_storage();
|
|
375149
375977
|
init_tenant_scope();
|
|
375150
375978
|
init_worker_tenant_context();
|
|
375979
|
+
init_loader2();
|
|
375151
375980
|
log122 = createLogger("media-processor");
|
|
375152
375981
|
PROCESSABLE_MEDIA_TYPES = new Set(["audio", "image", "document", "video"]);
|
|
375982
|
+
pluginMediaSchema = exports_external.object({
|
|
375983
|
+
buffer: exports_external.instanceof(Buffer),
|
|
375984
|
+
mimeType: exports_external.string().min(1).optional()
|
|
375985
|
+
});
|
|
375153
375986
|
});
|
|
375154
375987
|
|
|
375155
375988
|
// ../api/src/tenancy/inflight-revocation.ts
|
|
@@ -375202,29 +376035,6 @@ var init_inflight_revocation = __esm(() => {
|
|
|
375202
376035
|
};
|
|
375203
376036
|
});
|
|
375204
376037
|
|
|
375205
|
-
// ../api/src/utils/phone.ts
|
|
375206
|
-
function isValidE164Phone(phone) {
|
|
375207
|
-
const bare = phone.replace(/^\+/, "");
|
|
375208
|
-
if (!/^\d+$/.test(bare))
|
|
375209
|
-
return false;
|
|
375210
|
-
return bare.length >= 7 && bare.length <= 15;
|
|
375211
|
-
}
|
|
375212
|
-
function isLidFormat(platformUserId) {
|
|
375213
|
-
const bare = platformUserId.split("@")[0] || platformUserId;
|
|
375214
|
-
return /^\d{14,}$/.test(bare);
|
|
375215
|
-
}
|
|
375216
|
-
function validateContactPhone(phone, platformUserId) {
|
|
375217
|
-
if (!phone)
|
|
375218
|
-
return;
|
|
375219
|
-
if (!isValidE164Phone(phone))
|
|
375220
|
-
return;
|
|
375221
|
-
const barePhone = phone.replace(/^\+/, "");
|
|
375222
|
-
const barePuid = platformUserId.split("@")[0] || platformUserId;
|
|
375223
|
-
if (isLidFormat(platformUserId) && barePhone === barePuid)
|
|
375224
|
-
return;
|
|
375225
|
-
return phone;
|
|
375226
|
-
}
|
|
375227
|
-
|
|
375228
376038
|
// ../api/src/plugins/sync-worker.ts
|
|
375229
376039
|
class RateLimiter {
|
|
375230
376040
|
lastRequest = 0;
|
|
@@ -376796,6 +377606,11 @@ async function withCronMonitor(slug, cron2, checkinMargin, maxRuntime, handler)
|
|
|
376796
377606
|
await handler();
|
|
376797
377607
|
}
|
|
376798
377608
|
}
|
|
377609
|
+
function createScheduledMessageSweeper(services, channelRegistry2) {
|
|
377610
|
+
const sweeper2 = new ScheduledMessageService(services.db, createPluginResolver(services.db, (channel5) => channelRegistry2.get(channel5) ?? undefined));
|
|
377611
|
+
sweeper2.setAuthPlane(services.authPlane.db);
|
|
377612
|
+
return sweeper2;
|
|
377613
|
+
}
|
|
376799
377614
|
function setupScheduler(services, channelRegistry2) {
|
|
376800
377615
|
const scheduler = getScheduler();
|
|
376801
377616
|
scheduler.register({
|
|
@@ -376924,6 +377739,29 @@ function setupScheduler(services, channelRegistry2) {
|
|
|
376924
377739
|
});
|
|
376925
377740
|
}
|
|
376926
377741
|
});
|
|
377742
|
+
if (channelRegistry2) {
|
|
377743
|
+
const scheduledMessages2 = createScheduledMessageSweeper(services, channelRegistry2);
|
|
377744
|
+
scheduler.register({
|
|
377745
|
+
name: "scheduled-message-sweeper",
|
|
377746
|
+
cron: "*/15 * * * * *",
|
|
377747
|
+
runOnStart: false,
|
|
377748
|
+
handler: async () => {
|
|
377749
|
+
await withCronMonitor("scheduled-message-sweeper", "*/15 * * * * *", 1, 1, async () => {
|
|
377750
|
+
const startTime3 = Date.now();
|
|
377751
|
+
try {
|
|
377752
|
+
const stats = await scheduledMessages2.sweep();
|
|
377753
|
+
recordScheduledJob("scheduled-message-sweeper", "success", (Date.now() - startTime3) / 1000);
|
|
377754
|
+
if (stats.scanned > 0) {
|
|
377755
|
+
log127.debug("Scheduled-message sweep tick", { ...stats });
|
|
377756
|
+
}
|
|
377757
|
+
} catch (err2) {
|
|
377758
|
+
recordScheduledJob("scheduled-message-sweeper", "failure", (Date.now() - startTime3) / 1000);
|
|
377759
|
+
throw err2;
|
|
377760
|
+
}
|
|
377761
|
+
});
|
|
377762
|
+
}
|
|
377763
|
+
});
|
|
377764
|
+
}
|
|
376927
377765
|
scheduler.register({
|
|
376928
377766
|
name: "unread-count-refresh",
|
|
376929
377767
|
cron: CronExpressions.EVERY_HOUR,
|
|
@@ -376975,6 +377813,7 @@ var init_scheduler2 = __esm(() => {
|
|
|
376975
377813
|
init_src();
|
|
376976
377814
|
init_esm5();
|
|
376977
377815
|
init_sentry_scrub();
|
|
377816
|
+
init_scheduled_messages();
|
|
376978
377817
|
init_periodic_tenant_work();
|
|
376979
377818
|
log127 = createLogger("scheduler:setup");
|
|
376980
377819
|
});
|
|
@@ -382667,6 +383506,7 @@ var src_default2 = plugin3;
|
|
|
382667
383506
|
|
|
382668
383507
|
// ../channel-hermes/src/plugin.ts
|
|
382669
383508
|
init_src2();
|
|
383509
|
+
init_src();
|
|
382670
383510
|
|
|
382671
383511
|
// ../channel-hermes/src/capabilities.ts
|
|
382672
383512
|
init_src2();
|
|
@@ -383121,6 +383961,33 @@ async function sendTemplate(client, to, opts, replyTo) {
|
|
|
383121
383961
|
payload.context = { message_id: replyTo };
|
|
383122
383962
|
return client.sendMessage(payload);
|
|
383123
383963
|
}
|
|
383964
|
+
// ../channel-hermes/src/senders/interactive.ts
|
|
383965
|
+
async function sendPlannedInteractive(client, to, interactive, replyTo) {
|
|
383966
|
+
const payload = {
|
|
383967
|
+
to: toHermesPhone(to),
|
|
383968
|
+
recipient_type: "individual",
|
|
383969
|
+
type: "interactive",
|
|
383970
|
+
interactive
|
|
383971
|
+
};
|
|
383972
|
+
if (replyTo)
|
|
383973
|
+
payload.context = { message_id: replyTo };
|
|
383974
|
+
return client.sendMessage(payload);
|
|
383975
|
+
}
|
|
383976
|
+
async function sendLocationRequest(client, to, bodyText, replyTo) {
|
|
383977
|
+
const payload = {
|
|
383978
|
+
to: toHermesPhone(to),
|
|
383979
|
+
recipient_type: "individual",
|
|
383980
|
+
type: "interactive",
|
|
383981
|
+
interactive: {
|
|
383982
|
+
type: "location_request_message",
|
|
383983
|
+
body: { text: bodyText },
|
|
383984
|
+
action: { name: "send_location" }
|
|
383985
|
+
}
|
|
383986
|
+
};
|
|
383987
|
+
if (replyTo)
|
|
383988
|
+
payload.context = { message_id: replyTo };
|
|
383989
|
+
return client.sendMessage(payload);
|
|
383990
|
+
}
|
|
383124
383991
|
// ../channel-hermes/src/plugin.ts
|
|
383125
383992
|
var HERMES_MEDIA_TYPES = new Set(["image", "audio", "video", "document", "sticker"]);
|
|
383126
383993
|
var downloadGuard2 = createDownloadGuard();
|
|
@@ -383200,7 +384067,7 @@ class HermesPlugin extends BaseChannelPlugin {
|
|
|
383200
384067
|
if (correlationId)
|
|
383201
384068
|
this.captureT10(correlationId);
|
|
383202
384069
|
try {
|
|
383203
|
-
const dispatched = await dispatchOutbound(state, message2);
|
|
384070
|
+
const dispatched = await dispatchOutbound(state, message2, this.logger);
|
|
383204
384071
|
if (!dispatched.ok) {
|
|
383205
384072
|
return { success: false, error: dispatched.error, retryable: false, timestamp: Date.now() };
|
|
383206
384073
|
}
|
|
@@ -383445,11 +384312,14 @@ class HermesPlugin extends BaseChannelPlugin {
|
|
|
383445
384312
|
}
|
|
383446
384313
|
}
|
|
383447
384314
|
}
|
|
383448
|
-
async function dispatchOutbound(state, message2) {
|
|
384315
|
+
async function dispatchOutbound(state, message2, logger5) {
|
|
383449
384316
|
const { client } = state;
|
|
383450
384317
|
const { content, to, replyTo } = message2;
|
|
383451
384318
|
if (content.type === "text") {
|
|
383452
|
-
return
|
|
384319
|
+
return dispatchOutboundText(client, message2, logger5);
|
|
384320
|
+
}
|
|
384321
|
+
if (content.type === "location_request") {
|
|
384322
|
+
return { ok: true, response: await sendLocationRequest(client, to, resolveOutboundText(message2), replyTo) };
|
|
383453
384323
|
}
|
|
383454
384324
|
if (HERMES_MEDIA_TYPES.has(content.type)) {
|
|
383455
384325
|
return dispatchOutboundMedia(client, message2);
|
|
@@ -383476,6 +384346,30 @@ async function dispatchOutbound(state, message2) {
|
|
|
383476
384346
|
}
|
|
383477
384347
|
return { ok: false, error: `Unsupported content.type=${content.type} for hermes` };
|
|
383478
384348
|
}
|
|
384349
|
+
function resolveOutboundText(message2) {
|
|
384350
|
+
const formatMode = message2.metadata?.messageFormatMode ?? "convert";
|
|
384351
|
+
const text = message2.content.text ?? "";
|
|
384352
|
+
return formatMode === "passthrough" ? text : markdownToWhatsApp(text);
|
|
384353
|
+
}
|
|
384354
|
+
async function dispatchOutboundText(client, message2, logger5) {
|
|
384355
|
+
const { content, to, replyTo } = message2;
|
|
384356
|
+
const formatted = resolveOutboundText(message2);
|
|
384357
|
+
if (!content.buttons?.length) {
|
|
384358
|
+
return { ok: true, response: await sendText2(client, to, formatted, replyTo) };
|
|
384359
|
+
}
|
|
384360
|
+
const plan = planInteractive(formatted, content.buttons, content.list?.buttonLabel ?? "Options", {
|
|
384361
|
+
sectionTitle: content.list?.sectionTitle,
|
|
384362
|
+
forceList: content.list?.forceList
|
|
384363
|
+
});
|
|
384364
|
+
if (plan.droppedRows > 0) {
|
|
384365
|
+
logger5?.warn("[hermes] interactive list capped at 10 rows \u2014 extra buttons dropped", {
|
|
384366
|
+
to,
|
|
384367
|
+
droppedRows: plan.droppedRows
|
|
384368
|
+
});
|
|
384369
|
+
}
|
|
384370
|
+
const response = plan.interactive ? await sendPlannedInteractive(client, to, plan.interactive, replyTo) : await sendText2(client, to, plan.body, replyTo);
|
|
384371
|
+
return { ok: true, response };
|
|
384372
|
+
}
|
|
383479
384373
|
async function dispatchOutboundMedia(client, message2) {
|
|
383480
384374
|
const { content, to, replyTo } = message2;
|
|
383481
384375
|
const caption = content.caption ?? content.text;
|
|
@@ -383641,6 +384535,11 @@ var SLACK_CAPABILITIES = {
|
|
|
383641
384535
|
canDeleteMessage: true,
|
|
383642
384536
|
canReplyToMessage: true,
|
|
383643
384537
|
canForwardMessage: false,
|
|
384538
|
+
canScheduleMessage: true,
|
|
384539
|
+
maxScheduleAheadMs: 120 * 24 * 60 * 60 * 1000,
|
|
384540
|
+
canGetPermalink: true,
|
|
384541
|
+
canPinMessage: true,
|
|
384542
|
+
canSearchMessages: false,
|
|
383644
384543
|
canSendContact: false,
|
|
383645
384544
|
canSendLocation: false,
|
|
383646
384545
|
canSendSticker: false,
|
|
@@ -383694,7 +384593,17 @@ function resolveStreamThrottle(throttleMs) {
|
|
|
383694
384593
|
// ../channel-slack/src/connection/bolt-client.ts
|
|
383695
384594
|
init_types10();
|
|
383696
384595
|
var import_bolt = __toESM(require_dist16(), 1);
|
|
384596
|
+
var import_web_api = __toESM(require_dist13(), 1);
|
|
383697
384597
|
var HTTP_MAX_BODY_BYTES = 1024 * 1024;
|
|
384598
|
+
function buildActingClients(options, botClient) {
|
|
384599
|
+
if (options.authMode !== "user")
|
|
384600
|
+
return { actingClient: botClient };
|
|
384601
|
+
if (!options.userToken) {
|
|
384602
|
+
throw new SlackError(SlackErrorCode.CONNECTION_FAILED, "userToken is required when authMode is 'user'");
|
|
384603
|
+
}
|
|
384604
|
+
const userClient = new import_web_api.WebClient(options.userToken);
|
|
384605
|
+
return { actingClient: userClient, userClient };
|
|
384606
|
+
}
|
|
383698
384607
|
function createBoltApp(options, logger5) {
|
|
383699
384608
|
const mode = options.mode ?? "socket";
|
|
383700
384609
|
if (mode === "http") {
|
|
@@ -383728,6 +384637,7 @@ function createSocketBoltApp(options, logger5) {
|
|
|
383728
384637
|
return {
|
|
383729
384638
|
app,
|
|
383730
384639
|
client: app.client,
|
|
384640
|
+
...buildActingClients(options, app.client),
|
|
383731
384641
|
botToken: options.botToken,
|
|
383732
384642
|
mode: "socket"
|
|
383733
384643
|
};
|
|
@@ -383760,6 +384670,7 @@ function createHttpBoltApp(options, logger5) {
|
|
|
383760
384670
|
return {
|
|
383761
384671
|
app,
|
|
383762
384672
|
client: app.client,
|
|
384673
|
+
...buildActingClients(options, app.client),
|
|
383763
384674
|
botToken: options.botToken,
|
|
383764
384675
|
mode: "http",
|
|
383765
384676
|
httpPort: options.httpPort,
|
|
@@ -383835,11 +384746,22 @@ async function startBoltConnection(connection, logger5) {
|
|
|
383835
384746
|
teamId: connection.teamId,
|
|
383836
384747
|
teamName: connection.teamName
|
|
383837
384748
|
});
|
|
384749
|
+
if (connection.userClient) {
|
|
384750
|
+
const userAuth = await connection.userClient.auth.test();
|
|
384751
|
+
connection.actingUserId = userAuth.user_id ?? undefined;
|
|
384752
|
+
logger5.info("Acting user identity resolved", {
|
|
384753
|
+
actingUserId: connection.actingUserId,
|
|
384754
|
+
actingUser: userAuth.user
|
|
384755
|
+
});
|
|
384756
|
+
}
|
|
383838
384757
|
} catch (error) {
|
|
383839
384758
|
logger5.warn("Failed to resolve bot identity before start \u2014 self-message filtering may be unreliable", {
|
|
383840
384759
|
error: String(error)
|
|
383841
384760
|
});
|
|
383842
384761
|
}
|
|
384762
|
+
if (connection.userClient && !connection.actingUserId) {
|
|
384763
|
+
throw new SlackError(SlackErrorCode.CONNECTION_FAILED, "User mode requires a resolved acting user id, but it could not be determined from the user token. Refusing to start.");
|
|
384764
|
+
}
|
|
383843
384765
|
if (connection.mode === "http") {
|
|
383844
384766
|
const port = connection.httpPort ?? 3001;
|
|
383845
384767
|
try {
|
|
@@ -384168,12 +385090,13 @@ function extractMessageMeta(event) {
|
|
|
384168
385090
|
ts,
|
|
384169
385091
|
userId,
|
|
384170
385092
|
teamId,
|
|
384171
|
-
isDm: channelType === "im",
|
|
385093
|
+
isDm: channelType === "im" || channelType === "mpim",
|
|
385094
|
+
isMpim: channelType === "mpim",
|
|
384172
385095
|
isThreadReply: threadTs !== undefined && threadTs !== ts,
|
|
384173
385096
|
channelType
|
|
384174
385097
|
};
|
|
384175
385098
|
}
|
|
384176
|
-
function shouldSkipMessage(msg,
|
|
385099
|
+
function shouldSkipMessage(msg, selfUserIds) {
|
|
384177
385100
|
if (msg.subtype === "bot_message" || msg.bot_id)
|
|
384178
385101
|
return true;
|
|
384179
385102
|
if (msg.subtype === "message_changed" || msg.subtype === "message_deleted")
|
|
@@ -384181,7 +385104,7 @@ function shouldSkipMessage(msg, botUserId) {
|
|
|
384181
385104
|
const userId = msg.user;
|
|
384182
385105
|
if (!userId)
|
|
384183
385106
|
return true;
|
|
384184
|
-
if (
|
|
385107
|
+
if (selfUserIds.some((id) => id && id === userId))
|
|
384185
385108
|
return true;
|
|
384186
385109
|
return false;
|
|
384187
385110
|
}
|
|
@@ -384205,6 +385128,7 @@ function buildRawPayload(meta, msg, extra) {
|
|
|
384205
385128
|
channelType: meta.channelType,
|
|
384206
385129
|
teamId: meta.teamId,
|
|
384207
385130
|
isDm: meta.isDm,
|
|
385131
|
+
isMpim: meta.isMpim === true,
|
|
384208
385132
|
isThreadReply: meta.isThreadReply,
|
|
384209
385133
|
files: msg.files,
|
|
384210
385134
|
...extra
|
|
@@ -384298,11 +385222,12 @@ async function processMessage2(instanceId, msg, currentBotUserId, callbacks, log
|
|
|
384298
385222
|
}
|
|
384299
385223
|
await callbacks.onMessage(instanceId, meta.ts, meta.channelId, userId, content, replyToId, rawPayload, platformTimestamp, meta);
|
|
384300
385224
|
}
|
|
384301
|
-
function setupMessageHandlers2(app, instanceId, botUserId, callbacks, dmPolicyConfig, logger5, filterConfig, reliability) {
|
|
385225
|
+
function setupMessageHandlers2(app, instanceId, botUserId, callbacks, dmPolicyConfig, logger5, filterConfig, reliability, actingUserId) {
|
|
384302
385226
|
const resolveBotUserId = () => typeof botUserId === "function" ? botUserId() : botUserId;
|
|
385227
|
+
const resolveActingUserId = () => typeof actingUserId === "function" ? actingUserId() : actingUserId;
|
|
384303
385228
|
app.message(async ({ message: message2 }) => {
|
|
384304
385229
|
const msg = message2;
|
|
384305
|
-
if (shouldSkipMessage(msg, resolveBotUserId()))
|
|
385230
|
+
if (shouldSkipMessage(msg, [resolveBotUserId(), resolveActingUserId()]))
|
|
384306
385231
|
return;
|
|
384307
385232
|
const userId = msg.user;
|
|
384308
385233
|
const meta = extractMessageMeta(msg);
|
|
@@ -384454,16 +385379,52 @@ async function uploadFileFromUrl(client, options, logger5) {
|
|
|
384454
385379
|
|
|
384455
385380
|
// ../channel-slack/src/markdown.ts
|
|
384456
385381
|
var MAX_SLACK_MESSAGE_LENGTH = 4000;
|
|
385382
|
+
function escapeMrkdwn(text) {
|
|
385383
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
385384
|
+
}
|
|
385385
|
+
function segment(text) {
|
|
385386
|
+
const segments = [];
|
|
385387
|
+
const pattern = /(```[\s\S]*?```|`[^`\n]*`)/g;
|
|
385388
|
+
let lastIndex = 0;
|
|
385389
|
+
for (const match of text.matchAll(pattern)) {
|
|
385390
|
+
const start = match.index ?? 0;
|
|
385391
|
+
if (start > lastIndex) {
|
|
385392
|
+
segments.push({ text: text.slice(lastIndex, start), isCode: false });
|
|
385393
|
+
}
|
|
385394
|
+
segments.push({ text: match[0], isCode: true });
|
|
385395
|
+
lastIndex = start + match[0].length;
|
|
385396
|
+
}
|
|
385397
|
+
if (lastIndex < text.length) {
|
|
385398
|
+
segments.push({ text: text.slice(lastIndex), isCode: false });
|
|
385399
|
+
}
|
|
385400
|
+
return segments;
|
|
385401
|
+
}
|
|
385402
|
+
function unescapeUrl(url) {
|
|
385403
|
+
return url.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
385404
|
+
}
|
|
385405
|
+
function convertProse(text) {
|
|
385406
|
+
const BOLD = "\x00B\x00";
|
|
385407
|
+
let out = escapeMrkdwn(text);
|
|
385408
|
+
out = out.replace(/^>\s?/gm, "> ");
|
|
385409
|
+
out = out.replace(/^#{1,6}\s+(.+)$/gm, `${BOLD}$1${BOLD}`);
|
|
385410
|
+
out = out.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_m, alt, url) => `<${unescapeUrl(url)}|${alt}>`);
|
|
385411
|
+
out = out.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, label, url) => `<${unescapeUrl(url)}|${label}>`);
|
|
385412
|
+
out = out.replace(/^(-{3,}|\*{3,}|_{3,})$/gm, "\u2014\u2014\u2014");
|
|
385413
|
+
out = out.replace(/^(\s*)[-*+]\s+/gm, "$1\u2022 ");
|
|
385414
|
+
out = out.replace(/\*\*(.+?)\*\*/g, `${BOLD}$1${BOLD}`);
|
|
385415
|
+
out = out.replace(/(^|[\s(])\*(?!\s)([^*\n]+?)\*(?=[\s).,;:!?]|$)/g, "$1_$2_");
|
|
385416
|
+
out = out.split(BOLD).join("*");
|
|
385417
|
+
out = out.replace(/~~(.+?)~~/g, "~$1~");
|
|
385418
|
+
return out;
|
|
385419
|
+
}
|
|
384457
385420
|
function markdownToMrkdwn(markdown) {
|
|
384458
|
-
|
|
384459
|
-
|
|
384460
|
-
|
|
384461
|
-
|
|
384462
|
-
|
|
384463
|
-
|
|
384464
|
-
|
|
384465
|
-
text = text.replace(/^(-{3,}|\*{3,}|_{3,})$/gm, "\u2014\u2014\u2014");
|
|
384466
|
-
return text;
|
|
385421
|
+
return segment(markdown).map((s) => s.isCode ? s.text : convertProse(s.text)).join("");
|
|
385422
|
+
}
|
|
385423
|
+
function findOpenFence(text) {
|
|
385424
|
+
const fences = text.match(/```[^\n]*/g);
|
|
385425
|
+
if (!fences || fences.length % 2 === 0)
|
|
385426
|
+
return null;
|
|
385427
|
+
return fences[fences.length - 1]?.slice(3).trim() ?? "";
|
|
384467
385428
|
}
|
|
384468
385429
|
function chunkMessage2(text, maxLength = MAX_SLACK_MESSAGE_LENGTH) {
|
|
384469
385430
|
if (text.length <= maxLength) {
|
|
@@ -384471,21 +385432,37 @@ function chunkMessage2(text, maxLength = MAX_SLACK_MESSAGE_LENGTH) {
|
|
|
384471
385432
|
}
|
|
384472
385433
|
const chunks = [];
|
|
384473
385434
|
let remaining = text;
|
|
385435
|
+
let carryFence = null;
|
|
384474
385436
|
while (remaining.length > 0) {
|
|
384475
|
-
|
|
384476
|
-
|
|
385437
|
+
const prefix = carryFence === null ? "" : `\`\`\`${carryFence}
|
|
385438
|
+
`;
|
|
385439
|
+
if (prefix.length + remaining.length <= maxLength) {
|
|
385440
|
+
chunks.push(prefix + remaining);
|
|
384477
385441
|
break;
|
|
384478
385442
|
}
|
|
384479
|
-
|
|
384480
|
-
|
|
384481
|
-
|
|
384482
|
-
|
|
384483
|
-
|
|
384484
|
-
|
|
384485
|
-
|
|
384486
|
-
|
|
384487
|
-
|
|
384488
|
-
|
|
385443
|
+
const split = (budget) => {
|
|
385444
|
+
let at = remaining.lastIndexOf(`
|
|
385445
|
+
`, budget);
|
|
385446
|
+
if (at <= 0 || at < budget * 0.5)
|
|
385447
|
+
at = remaining.lastIndexOf(" ", budget);
|
|
385448
|
+
if (at <= 0 || at < budget * 0.5)
|
|
385449
|
+
at = budget;
|
|
385450
|
+
return at;
|
|
385451
|
+
};
|
|
385452
|
+
const plainBudget = Math.max(1, maxLength - prefix.length);
|
|
385453
|
+
let splitIndex = split(plainBudget);
|
|
385454
|
+
let head = remaining.slice(0, splitIndex);
|
|
385455
|
+
let openFence = findOpenFence(prefix + head);
|
|
385456
|
+
if (openFence !== null) {
|
|
385457
|
+
const fencedBudget = Math.max(1, maxLength - prefix.length - 4);
|
|
385458
|
+
splitIndex = split(fencedBudget);
|
|
385459
|
+
head = remaining.slice(0, splitIndex);
|
|
385460
|
+
openFence = findOpenFence(prefix + head);
|
|
385461
|
+
}
|
|
385462
|
+
chunks.push(openFence === null ? prefix + head : `${prefix + head}
|
|
385463
|
+
\`\`\``);
|
|
385464
|
+
carryFence = openFence;
|
|
385465
|
+
remaining = remaining.slice(splitIndex).trimStart();
|
|
384489
385466
|
}
|
|
384490
385467
|
return chunks;
|
|
384491
385468
|
}
|
|
@@ -384827,6 +385804,55 @@ async function sendTextMessage2(client, options, logger5) {
|
|
|
384827
385804
|
}
|
|
384828
385805
|
return lastTs;
|
|
384829
385806
|
}
|
|
385807
|
+
var MAX_SCHEDULE_AHEAD_MS = 120 * 24 * 60 * 60 * 1000;
|
|
385808
|
+
async function scheduleTextMessage(client, options, logger5) {
|
|
385809
|
+
const formattedText = options.formatMode === "passthrough" ? options.text : markdownToMrkdwn(options.text);
|
|
385810
|
+
if (formattedText.length > MAX_SLACK_MESSAGE_LENGTH) {
|
|
385811
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, `Scheduled message is ${formattedText.length} chars, over Slack's ${MAX_SLACK_MESSAGE_LENGTH} limit. Chunking is not applied when scheduling \u2014 each chunk would get its own handle and a later cancel could half-fire.`);
|
|
385812
|
+
}
|
|
385813
|
+
const leadMs = options.postAt.getTime() - Date.now();
|
|
385814
|
+
if (leadMs <= 0) {
|
|
385815
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, `postAt is in the past (${options.postAt.toISOString()})`);
|
|
385816
|
+
}
|
|
385817
|
+
if (leadMs > MAX_SCHEDULE_AHEAD_MS) {
|
|
385818
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, `postAt is ${Math.round(leadMs / 86400000)} days out; Slack accepts at most 120.`);
|
|
385819
|
+
}
|
|
385820
|
+
try {
|
|
385821
|
+
const result = await client.chat.scheduleMessage({
|
|
385822
|
+
channel: options.channelId,
|
|
385823
|
+
text: formattedText,
|
|
385824
|
+
post_at: Math.floor(options.postAt.getTime() / 1000),
|
|
385825
|
+
thread_ts: options.threadTs,
|
|
385826
|
+
reply_broadcast: options.replyBroadcast,
|
|
385827
|
+
username: options.username,
|
|
385828
|
+
icon_url: options.iconUrl,
|
|
385829
|
+
icon_emoji: options.iconEmoji
|
|
385830
|
+
});
|
|
385831
|
+
const scheduledId = result.scheduled_message_id;
|
|
385832
|
+
if (!scheduledId) {
|
|
385833
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, "chat.scheduleMessage returned no scheduled_message_id \u2014 cannot cancel later");
|
|
385834
|
+
}
|
|
385835
|
+
return scheduledId;
|
|
385836
|
+
} catch (error) {
|
|
385837
|
+
if (error instanceof SlackError)
|
|
385838
|
+
throw error;
|
|
385839
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
385840
|
+
logger5.error("Failed to schedule message", { error: message2, channelId: options.channelId });
|
|
385841
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, `Failed to schedule message: ${message2}`);
|
|
385842
|
+
}
|
|
385843
|
+
}
|
|
385844
|
+
async function cancelScheduledSlackMessage(client, channelId, scheduledMessageId, logger5) {
|
|
385845
|
+
try {
|
|
385846
|
+
await client.chat.deleteScheduledMessage({
|
|
385847
|
+
channel: channelId,
|
|
385848
|
+
scheduled_message_id: scheduledMessageId
|
|
385849
|
+
});
|
|
385850
|
+
} catch (error) {
|
|
385851
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
385852
|
+
logger5.error("Failed to cancel scheduled message", { error: message2, channelId, scheduledMessageId });
|
|
385853
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, `Failed to cancel scheduled message: ${message2}`);
|
|
385854
|
+
}
|
|
385855
|
+
}
|
|
384830
385856
|
async function editSlackMessage(client, channelId, ts, newText, formatMode, logger5) {
|
|
384831
385857
|
const formattedText = formatMode === "passthrough" ? newText : markdownToMrkdwn(newText);
|
|
384832
385858
|
try {
|
|
@@ -384859,19 +385885,27 @@ init_types10();
|
|
|
384859
385885
|
var downloadGuard4 = createDownloadGuard();
|
|
384860
385886
|
function resolveSlackTokens(slackConfig, rawOptions, rawCredentials) {
|
|
384861
385887
|
const botToken = slackConfig.botToken ?? rawOptions.token ?? rawCredentials.botToken ?? rawCredentials.token;
|
|
385888
|
+
const userToken = slackConfig.userToken ?? rawCredentials.userToken;
|
|
385889
|
+
const authMode = slackConfig.authMode ?? "bot";
|
|
384862
385890
|
const appToken = slackConfig.appToken ?? rawCredentials.appToken;
|
|
384863
385891
|
const signingSecret = slackConfig.signingSecret ?? rawCredentials.signingSecret;
|
|
384864
385892
|
const mode = slackConfig.mode ?? "socket";
|
|
384865
385893
|
if (!botToken) {
|
|
384866
385894
|
throw new SlackError(SlackErrorCode.INVALID_TOKEN, "botToken (xoxb-...) is required");
|
|
384867
385895
|
}
|
|
385896
|
+
if (authMode === "user" && !userToken) {
|
|
385897
|
+
throw new SlackError(SlackErrorCode.INVALID_TOKEN, "userToken (xoxp-...) is required when authMode is 'user' \u2014 without it every action would silently go out as the bot");
|
|
385898
|
+
}
|
|
385899
|
+
if (userToken && !userToken.startsWith("xoxp-")) {
|
|
385900
|
+
throw new SlackError(SlackErrorCode.INVALID_TOKEN, "userToken must be a user token (xoxp-...); got a token with a different prefix");
|
|
385901
|
+
}
|
|
384868
385902
|
if (mode === "socket" && !appToken) {
|
|
384869
385903
|
throw new SlackError(SlackErrorCode.INVALID_TOKEN, "appToken (xapp-...) is required for Socket Mode");
|
|
384870
385904
|
}
|
|
384871
385905
|
if (mode === "http" && !signingSecret) {
|
|
384872
385906
|
throw new SlackError(SlackErrorCode.INVALID_TOKEN, "signingSecret is required for HTTP mode");
|
|
384873
385907
|
}
|
|
384874
|
-
return { botToken, appToken, signingSecret, mode };
|
|
385908
|
+
return { botToken, userToken, authMode, appToken, signingSecret, mode };
|
|
384875
385909
|
}
|
|
384876
385910
|
|
|
384877
385911
|
class SlackPlugin extends BaseChannelPlugin {
|
|
@@ -384950,6 +385984,8 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
384950
385984
|
}
|
|
384951
385985
|
connection = createBoltApp({
|
|
384952
385986
|
botToken: resolved.botToken,
|
|
385987
|
+
userToken: resolved.userToken,
|
|
385988
|
+
authMode: resolved.authMode,
|
|
384953
385989
|
appToken: resolved.appToken,
|
|
384954
385990
|
signingSecret: resolved.signingSecret,
|
|
384955
385991
|
retryConfig: slackConfig.retryConfig,
|
|
@@ -385078,7 +386114,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385078
386114
|
const streamMode = resolveStreamMode(slackConfig.streamMode);
|
|
385079
386115
|
const throttleMs = resolveStreamThrottle(slackConfig.streamThrottleMs);
|
|
385080
386116
|
const base2 = streamMode === "native" ? createNativeStreamSender({
|
|
385081
|
-
client: connection.
|
|
386117
|
+
client: connection.actingClient,
|
|
385082
386118
|
channelId: chatId,
|
|
385083
386119
|
threadTs,
|
|
385084
386120
|
throttleMs,
|
|
@@ -385088,7 +386124,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385088
386124
|
formatMode: options?.formatMode ?? "convert",
|
|
385089
386125
|
logger: this.logger
|
|
385090
386126
|
}) : createSlackStreamSender({
|
|
385091
|
-
client: connection.
|
|
386127
|
+
client: connection.actingClient,
|
|
385092
386128
|
channelId: chatId,
|
|
385093
386129
|
threadTs,
|
|
385094
386130
|
streamMode,
|
|
@@ -385135,12 +386171,12 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385135
386171
|
const status = shouldClear ? "" : options?.status ?? (type === "recording" ? "is recording..." : "is typing...");
|
|
385136
386172
|
const timerKey = this.presenceStatusTimerKey(instanceId, chatId, threadTs);
|
|
385137
386173
|
const delivered = status === "" ? await clearTypingStatus({
|
|
385138
|
-
client: connection.
|
|
386174
|
+
client: connection.actingClient,
|
|
385139
386175
|
channelId: chatId,
|
|
385140
386176
|
threadTs,
|
|
385141
386177
|
logger: this.logger
|
|
385142
386178
|
}) : await setSlackThreadStatus({
|
|
385143
|
-
client: connection.
|
|
386179
|
+
client: connection.actingClient,
|
|
385144
386180
|
channelId: chatId,
|
|
385145
386181
|
threadTs,
|
|
385146
386182
|
status,
|
|
@@ -385156,7 +386192,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385156
386192
|
return;
|
|
385157
386193
|
this.presenceStatusTimers.delete(timerKey);
|
|
385158
386194
|
clearTypingStatus({
|
|
385159
|
-
client: connection.
|
|
386195
|
+
client: connection.actingClient,
|
|
385160
386196
|
channelId: chatId,
|
|
385161
386197
|
threadTs,
|
|
385162
386198
|
logger: this.logger
|
|
@@ -385193,21 +386229,105 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385193
386229
|
}
|
|
385194
386230
|
async editMessage(instanceId, channelId, messageTs, newText) {
|
|
385195
386231
|
const connection = this.getConnection(instanceId);
|
|
385196
|
-
await editSlackMessage(connection.
|
|
386232
|
+
await editSlackMessage(connection.actingClient, channelId, messageTs, newText, "convert", this.logger);
|
|
385197
386233
|
}
|
|
385198
386234
|
async deleteMessage(instanceId, channelId, messageTs) {
|
|
385199
386235
|
const connection = this.getConnection(instanceId);
|
|
385200
|
-
await deleteSlackMessage(connection.
|
|
386236
|
+
await deleteSlackMessage(connection.actingClient, channelId, messageTs, this.logger);
|
|
386237
|
+
}
|
|
386238
|
+
async scheduleMessage(instanceId, message2, sendAt) {
|
|
386239
|
+
const connection = this.getConnection(instanceId);
|
|
386240
|
+
const config2 = this.slackConfigs.get(instanceId);
|
|
386241
|
+
if (message2.content.type !== "text" || !message2.content.text) {
|
|
386242
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, `Only text messages can be scheduled (got '${message2.content.type}') \u2014 chat.scheduleMessage carries no attachment.`);
|
|
386243
|
+
}
|
|
386244
|
+
const threadTs = this.resolveThreadTs(config2?.replyToMode ?? "all", message2.replyTo, message2.threadId);
|
|
386245
|
+
return scheduleTextMessage(connection.actingClient, {
|
|
386246
|
+
channelId: message2.to,
|
|
386247
|
+
text: message2.content.text,
|
|
386248
|
+
threadTs,
|
|
386249
|
+
replyBroadcast: message2.metadata?.isThreadBroadcast === true,
|
|
386250
|
+
username: config2?.defaultUsername,
|
|
386251
|
+
iconUrl: config2?.defaultIconUrl,
|
|
386252
|
+
iconEmoji: config2?.defaultIconEmoji,
|
|
386253
|
+
formatMode: message2.metadata?.messageFormatMode,
|
|
386254
|
+
postAt: sendAt
|
|
386255
|
+
}, this.logger);
|
|
386256
|
+
}
|
|
386257
|
+
async openDirectMessage(instanceId, userId) {
|
|
386258
|
+
const connection = this.getConnection(instanceId);
|
|
386259
|
+
try {
|
|
386260
|
+
const result = await connection.actingClient.conversations.open({ users: userId });
|
|
386261
|
+
const channelId = result.channel?.id;
|
|
386262
|
+
if (!channelId) {
|
|
386263
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, `conversations.open returned no channel for user ${userId}`);
|
|
386264
|
+
}
|
|
386265
|
+
return channelId;
|
|
386266
|
+
} catch (error) {
|
|
386267
|
+
if (error instanceof SlackError)
|
|
386268
|
+
throw error;
|
|
386269
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
386270
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, `Failed to open DM with ${userId}: ${message2}`);
|
|
386271
|
+
}
|
|
386272
|
+
}
|
|
386273
|
+
async searchMessages(instanceId, query, options = {}) {
|
|
386274
|
+
const connection = this.getConnection(instanceId);
|
|
386275
|
+
const config2 = this.slackConfigs.get(instanceId);
|
|
386276
|
+
if (config2?.authMode !== "user" || !connection.userClient) {
|
|
386277
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, "search.messages needs a user token (search:read); this instance runs in 'bot' auth mode");
|
|
386278
|
+
}
|
|
386279
|
+
try {
|
|
386280
|
+
const result = await connection.userClient.search.messages({
|
|
386281
|
+
query,
|
|
386282
|
+
count: options.count ?? 20,
|
|
386283
|
+
page: options.page ?? 1
|
|
386284
|
+
});
|
|
386285
|
+
const matches = result.messages?.matches ?? [];
|
|
386286
|
+
return matches.map((raw) => {
|
|
386287
|
+
const m2 = raw;
|
|
386288
|
+
return {
|
|
386289
|
+
channelId: m2.channel?.id,
|
|
386290
|
+
ts: m2.ts,
|
|
386291
|
+
text: m2.text,
|
|
386292
|
+
permalink: m2.permalink,
|
|
386293
|
+
username: m2.username
|
|
386294
|
+
};
|
|
386295
|
+
});
|
|
386296
|
+
} catch (error) {
|
|
386297
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
386298
|
+
throw new SlackError(SlackErrorCode.SEND_FAILED, `Search failed: ${message2}`);
|
|
386299
|
+
}
|
|
386300
|
+
}
|
|
386301
|
+
async cancelScheduledMessage(instanceId, channelId, scheduledId) {
|
|
386302
|
+
const connection = this.getConnection(instanceId);
|
|
386303
|
+
await cancelScheduledSlackMessage(connection.actingClient, channelId, scheduledId, this.logger);
|
|
386304
|
+
}
|
|
386305
|
+
async getPermalink(instanceId, channelId, messageTs) {
|
|
386306
|
+
const connection = this.getConnection(instanceId);
|
|
386307
|
+
try {
|
|
386308
|
+
const result = await connection.actingClient.chat.getPermalink({
|
|
386309
|
+
channel: channelId,
|
|
386310
|
+
message_ts: messageTs
|
|
386311
|
+
});
|
|
386312
|
+
return result.permalink ?? null;
|
|
386313
|
+
} catch (error) {
|
|
386314
|
+
this.logger.warn("Failed to resolve permalink", {
|
|
386315
|
+
error: error instanceof Error ? error.message : String(error),
|
|
386316
|
+
channelId,
|
|
386317
|
+
messageTs
|
|
386318
|
+
});
|
|
386319
|
+
return null;
|
|
386320
|
+
}
|
|
385201
386321
|
}
|
|
385202
386322
|
async addReaction(instanceId, channelId, messageTs, emoji) {
|
|
385203
386323
|
const connection = this.getConnection(instanceId);
|
|
385204
386324
|
const { addReaction: addReaction3 } = await Promise.resolve().then(() => (init_tools(), exports_tools));
|
|
385205
|
-
await addReaction3(connection.
|
|
386325
|
+
await addReaction3(connection.actingClient, channelId, messageTs, emoji, this.logger);
|
|
385206
386326
|
}
|
|
385207
386327
|
async removeReaction(instanceId, channelId, messageTs, emoji) {
|
|
385208
386328
|
const connection = this.getConnection(instanceId);
|
|
385209
386329
|
const { removeReaction: removeReaction3 } = await Promise.resolve().then(() => (init_tools(), exports_tools));
|
|
385210
|
-
await removeReaction3(connection.
|
|
386330
|
+
await removeReaction3(connection.actingClient, channelId, messageTs, emoji, this.logger);
|
|
385211
386331
|
}
|
|
385212
386332
|
async getProfile(instanceId) {
|
|
385213
386333
|
const connection = this.getConnection(instanceId);
|
|
@@ -385226,7 +386346,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385226
386346
|
async fetchUserProfile(instanceId, userId) {
|
|
385227
386347
|
const connection = this.getConnection(instanceId);
|
|
385228
386348
|
try {
|
|
385229
|
-
const result = await connection.
|
|
386349
|
+
const result = await connection.actingClient.users.info({ user: userId });
|
|
385230
386350
|
const user = result.user;
|
|
385231
386351
|
if (!user)
|
|
385232
386352
|
return {};
|
|
@@ -385286,11 +386406,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385286
386406
|
if (!channelId || !threadTs)
|
|
385287
386407
|
return { totalFetched: 0, messages: [] };
|
|
385288
386408
|
const botUserId = connection.botUserId;
|
|
385289
|
-
const botToken =
|
|
385290
|
-
if (!botToken) {
|
|
385291
|
-
this.logger.warn("fetchHistory: no botToken for instance", { instanceId });
|
|
385292
|
-
return { totalFetched: 0, messages: [] };
|
|
385293
|
-
}
|
|
386409
|
+
const botToken = connection.botToken;
|
|
385294
386410
|
const limit = options.limit ?? 200;
|
|
385295
386411
|
const messages = await this.paginateThreadHistory(connection, channelId, threadTs, botUserId, botToken, limit);
|
|
385296
386412
|
return { totalFetched: messages.length, messages };
|
|
@@ -385299,7 +386415,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385299
386415
|
const messages = [];
|
|
385300
386416
|
let cursor;
|
|
385301
386417
|
do {
|
|
385302
|
-
const response = await connection.
|
|
386418
|
+
const response = await connection.actingClient.conversations.replies({
|
|
385303
386419
|
channel: channelId,
|
|
385304
386420
|
ts: threadTs,
|
|
385305
386421
|
limit: Math.min(200, maxMessages - messages.length),
|
|
@@ -385372,7 +386488,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385372
386488
|
const connection = this.getConnection(instanceId);
|
|
385373
386489
|
const slackName = SlackPlugin.EMOJI_TO_SLACK[emoji] ?? emoji.replace(/^:|:$/g, "");
|
|
385374
386490
|
try {
|
|
385375
|
-
await connection.
|
|
386491
|
+
await connection.actingClient.reactions.add({ channel: chatId, timestamp: messageId, name: slackName });
|
|
385376
386492
|
} catch (err2) {
|
|
385377
386493
|
this.logger.warn("react: failed to add reaction", { chatId, messageId, emoji, error: String(err2) });
|
|
385378
386494
|
}
|
|
@@ -385381,7 +386497,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385381
386497
|
const connection = this.getConnection(instanceId);
|
|
385382
386498
|
const slackName = SlackPlugin.EMOJI_TO_SLACK[emoji] ?? emoji.replace(/^:|:$/g, "");
|
|
385383
386499
|
try {
|
|
385384
|
-
await connection.
|
|
386500
|
+
await connection.actingClient.reactions.remove({ channel: chatId, timestamp: messageId, name: slackName });
|
|
385385
386501
|
} catch (err2) {
|
|
385386
386502
|
this.logger.warn("unreact: failed to remove reaction", { chatId, messageId, emoji, error: String(err2) });
|
|
385387
386503
|
}
|
|
@@ -385393,7 +386509,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385393
386509
|
const emojiName = typeof ackEmoji === "string" ? ackEmoji.replace(/^:|:$/g, "") : null;
|
|
385394
386510
|
if (!emojiName)
|
|
385395
386511
|
return;
|
|
385396
|
-
connection.
|
|
386512
|
+
connection.actingClient.reactions.add({ channel: channelId, timestamp: messageTs, name: emojiName }).catch((err2) => {
|
|
385397
386513
|
this.logger.warn("ack reaction: failed to add", { channelId, messageTs, emoji: emojiName, error: String(err2) });
|
|
385398
386514
|
});
|
|
385399
386515
|
if (config2.removeAckAfterReply !== false) {
|
|
@@ -385412,7 +386528,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385412
386528
|
if (!emojiName)
|
|
385413
386529
|
continue;
|
|
385414
386530
|
this.pendingAckReactions.delete(key);
|
|
385415
|
-
connection.
|
|
386531
|
+
connection.actingClient.reactions.remove({ channel: channelId, timestamp: ts, name: emojiName }).catch((err2) => {
|
|
385416
386532
|
this.logger.warn("ack reaction: failed to remove", { channelId, ts, emoji: emojiName, error: String(err2) });
|
|
385417
386533
|
});
|
|
385418
386534
|
break;
|
|
@@ -385426,7 +386542,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385426
386542
|
if (!resolvedThread)
|
|
385427
386543
|
return;
|
|
385428
386544
|
await clearTypingStatus({
|
|
385429
|
-
client: connection.
|
|
386545
|
+
client: connection.actingClient,
|
|
385430
386546
|
channelId,
|
|
385431
386547
|
threadTs: resolvedThread,
|
|
385432
386548
|
logger: this.logger
|
|
@@ -385472,14 +386588,16 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385472
386588
|
async buildEnrichedPayload(instanceId, from, rawPayload) {
|
|
385473
386589
|
const displayName = await this.resolveUserDisplayName(instanceId, from);
|
|
385474
386590
|
const isDm = rawPayload.isDm;
|
|
385475
|
-
const
|
|
386591
|
+
const isMpim = rawPayload.isMpim === true;
|
|
386592
|
+
const isOneToOne = isDm && !isMpim;
|
|
386593
|
+
const chatName = isOneToOne ? displayName : undefined;
|
|
385476
386594
|
return {
|
|
385477
386595
|
...rawPayload,
|
|
385478
386596
|
displayName,
|
|
385479
386597
|
senderName: displayName,
|
|
385480
386598
|
pushName: displayName,
|
|
385481
386599
|
chatName,
|
|
385482
|
-
isGroup: !
|
|
386600
|
+
isGroup: !isOneToOne
|
|
385483
386601
|
};
|
|
385484
386602
|
}
|
|
385485
386603
|
async dispatchMessageFromDebounce(instanceId, args) {
|
|
@@ -385510,7 +386628,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385510
386628
|
},
|
|
385511
386629
|
onDmRejected: async (_instId, channelId, _userId, message2) => {
|
|
385512
386630
|
try {
|
|
385513
|
-
await sendTextMessage2(connection.
|
|
386631
|
+
await sendTextMessage2(connection.actingClient, {
|
|
385514
386632
|
channelId,
|
|
385515
386633
|
text: message2,
|
|
385516
386634
|
formatMode: "passthrough"
|
|
@@ -385527,7 +386645,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385527
386645
|
channelAllowlist: config2.channelAllowlist,
|
|
385528
386646
|
channelBlocklist: config2.channelBlocklist,
|
|
385529
386647
|
channels: config2.channels
|
|
385530
|
-
}, reliability);
|
|
386648
|
+
}, reliability, () => connection.actingUserId);
|
|
385531
386649
|
setupReactionHandlers2(connection.app, instanceId, () => connection.botUserId, {
|
|
385532
386650
|
onReaction: async (instId, messageId, chatId, userId, emoji, action) => {
|
|
385533
386651
|
await this.handleReactionReceived(instId, messageId, chatId, userId, emoji, action);
|
|
@@ -385567,7 +386685,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385567
386685
|
const formatMode = message2.metadata?.messageFormatMode ?? "convert";
|
|
385568
386686
|
const replyToMode = config2.replyToMode ?? "all";
|
|
385569
386687
|
const threadTs = this.resolveThreadTs(replyToMode, message2.replyTo, message2.threadId);
|
|
385570
|
-
return sendTextMessage2(connection.
|
|
386688
|
+
return sendTextMessage2(connection.actingClient, {
|
|
385571
386689
|
channelId,
|
|
385572
386690
|
text: message2.content.text ?? "",
|
|
385573
386691
|
threadTs,
|
|
@@ -385585,7 +386703,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385585
386703
|
if (message2.metadata?.base64) {
|
|
385586
386704
|
const buffer2 = Buffer.from(message2.metadata.base64, "base64");
|
|
385587
386705
|
const filename = message2.content.filename || `file-${Date.now()}`;
|
|
385588
|
-
return uploadFile(connection.
|
|
386706
|
+
return uploadFile(connection.actingClient, {
|
|
385589
386707
|
channelId,
|
|
385590
386708
|
content: buffer2,
|
|
385591
386709
|
filename,
|
|
@@ -385596,7 +386714,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385596
386714
|
if (!message2.content.mediaUrl) {
|
|
385597
386715
|
throw new SlackError(SlackErrorCode.SEND_FAILED, "Media URL or base64 required");
|
|
385598
386716
|
}
|
|
385599
|
-
return uploadFileFromUrl(connection.
|
|
386717
|
+
return uploadFileFromUrl(connection.actingClient, {
|
|
385600
386718
|
channelId,
|
|
385601
386719
|
url: message2.content.mediaUrl,
|
|
385602
386720
|
filename: message2.content.filename || `file-${Date.now()}`,
|
|
@@ -385611,7 +386729,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385611
386729
|
throw new SlackError(SlackErrorCode.SEND_FAILED, "Reaction requires emoji and target message");
|
|
385612
386730
|
}
|
|
385613
386731
|
const { addReaction: addReaction3 } = await Promise.resolve().then(() => (init_tools(), exports_tools));
|
|
385614
|
-
await addReaction3(connection.
|
|
386732
|
+
await addReaction3(connection.actingClient, channelId, targetTs, emoji, this.logger);
|
|
385615
386733
|
return targetTs;
|
|
385616
386734
|
}
|
|
385617
386735
|
async handleInboundFiles(instanceId, externalId, chatId, from, content, replyToId, rawPayload, platformTimestamp) {
|
|
@@ -385637,6 +386755,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385637
386755
|
const timings = platformTimestamp ? this.captureInboundTimings(platformTimestamp) : undefined;
|
|
385638
386756
|
const senderName = typeof rawPayload.senderName === "string" ? rawPayload.senderName : typeof rawPayload.displayName === "string" ? rawPayload.displayName : undefined;
|
|
385639
386757
|
const chatName = typeof rawPayload.chatName === "string" ? rawPayload.chatName : undefined;
|
|
386758
|
+
const threadTs = typeof rawPayload.threadTs === "string" ? rawPayload.threadTs : undefined;
|
|
385640
386759
|
const correlationId = await this.emitMessageReceived({
|
|
385641
386760
|
instanceId,
|
|
385642
386761
|
externalId,
|
|
@@ -385645,7 +386764,7 @@ class SlackPlugin extends BaseChannelPlugin {
|
|
|
385645
386764
|
senderName,
|
|
385646
386765
|
chatName,
|
|
385647
386766
|
content,
|
|
385648
|
-
|
|
386767
|
+
threadId: threadTs,
|
|
385649
386768
|
rawPayload,
|
|
385650
386769
|
timings
|
|
385651
386770
|
});
|
|
@@ -386995,14 +388114,14 @@ var protectedSplitters = {
|
|
|
386995
388114
|
expandable_blockquote: trySplitBlockquote,
|
|
386996
388115
|
plain: () => null
|
|
386997
388116
|
};
|
|
386998
|
-
function splitLongProtectedSegment(
|
|
386999
|
-
if (
|
|
387000
|
-
return [
|
|
387001
|
-
const splitter = protectedSplitters[
|
|
387002
|
-
const result = splitter(
|
|
388117
|
+
function splitLongProtectedSegment(segment2, maxLength) {
|
|
388118
|
+
if (segment2.value.length <= maxLength)
|
|
388119
|
+
return [segment2.value];
|
|
388120
|
+
const splitter = protectedSplitters[segment2.type];
|
|
388121
|
+
const result = splitter(segment2.value, maxLength);
|
|
387003
388122
|
if (result)
|
|
387004
388123
|
return result;
|
|
387005
|
-
return splitPlainByBoundaries(
|
|
388124
|
+
return splitPlainByBoundaries(segment2.value, maxLength);
|
|
387006
388125
|
}
|
|
387007
388126
|
function findNextProtected(html, from) {
|
|
387008
388127
|
const patterns = [
|
|
@@ -387086,12 +388205,12 @@ class ChunkAccumulator {
|
|
|
387086
388205
|
return this.chunks.length > 0 ? this.chunks : [""];
|
|
387087
388206
|
}
|
|
387088
388207
|
}
|
|
387089
|
-
function processPlainSegment(acc,
|
|
387090
|
-
const plainParts = splitPlainHtmlPreservingTags(
|
|
388208
|
+
function processPlainSegment(acc, segment2, maxLength) {
|
|
388209
|
+
const plainParts = splitPlainHtmlPreservingTags(segment2.value, maxLength);
|
|
387091
388210
|
acc.appendParts(plainParts);
|
|
387092
388211
|
}
|
|
387093
|
-
function processProtectedSegment(acc,
|
|
387094
|
-
const protectedParts = splitLongProtectedSegment(
|
|
388212
|
+
function processProtectedSegment(acc, segment2, maxLength) {
|
|
388213
|
+
const protectedParts = splitLongProtectedSegment(segment2, maxLength);
|
|
387095
388214
|
for (const part of protectedParts) {
|
|
387096
388215
|
if (part.length > maxLength) {
|
|
387097
388216
|
const hardParts = splitPlainByBoundaries(part, maxLength);
|
|
@@ -387106,11 +388225,11 @@ function splitHtmlMessage(html, maxLength = 4096) {
|
|
|
387106
388225
|
return [html];
|
|
387107
388226
|
const segments = segmentHtml(html);
|
|
387108
388227
|
const acc = new ChunkAccumulator(maxLength);
|
|
387109
|
-
for (const
|
|
387110
|
-
if (
|
|
387111
|
-
processPlainSegment(acc,
|
|
388228
|
+
for (const segment2 of segments) {
|
|
388229
|
+
if (segment2.type === "plain") {
|
|
388230
|
+
processPlainSegment(acc, segment2, maxLength);
|
|
387112
388231
|
} else {
|
|
387113
|
-
processProtectedSegment(acc,
|
|
388232
|
+
processProtectedSegment(acc, segment2, maxLength);
|
|
387114
388233
|
}
|
|
387115
388234
|
}
|
|
387116
388235
|
return acc.result();
|
|
@@ -477531,6 +478650,7 @@ for (const [i, DOUBLE_BYTE_TOKEN] of DOUBLE_BYTE_TOKENS.entries()) {
|
|
|
477531
478650
|
|
|
477532
478651
|
// ../../node_modules/.bun/baileys@vendor+baileys-v7.0.0-rc10.tgz+89588f7e3fe8b2e6/node_modules/baileys/lib/WABinary/jid-utils.js
|
|
477533
478652
|
var S_WHATSAPP_NET = "@s.whatsapp.net";
|
|
478653
|
+
var SERVER_JID = "server@c.us";
|
|
477534
478654
|
var PSA_WID = "0@c.us";
|
|
477535
478655
|
var WAJIDDomains;
|
|
477536
478656
|
(function(WAJIDDomains2) {
|
|
@@ -490763,6 +491883,181 @@ function buildAckStanza(node, errorCode, meId) {
|
|
|
490763
491883
|
}
|
|
490764
491884
|
return stanza;
|
|
490765
491885
|
}
|
|
491886
|
+
// ../../node_modules/.bun/baileys@vendor+baileys-v7.0.0-rc10.tgz+89588f7e3fe8b2e6/node_modules/baileys/lib/Utils/passkey.js
|
|
491887
|
+
var BASE64URL_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
491888
|
+
var PASSKEY_HANDOFF_INFO = "shortcake-passkey-handoff-v1";
|
|
491889
|
+
var PAIRING_ENCRYPTION_INFO = "Pairing Information Encryption Key";
|
|
491890
|
+
var assertBase64Url = (value, field, nullable = false) => {
|
|
491891
|
+
if (nullable && value === null) {
|
|
491892
|
+
return null;
|
|
491893
|
+
}
|
|
491894
|
+
if (typeof value !== "string" || !value || !BASE64URL_PATTERN.test(value)) {
|
|
491895
|
+
throw new Error(`Invalid ${field} in passkey payload`);
|
|
491896
|
+
}
|
|
491897
|
+
return value;
|
|
491898
|
+
};
|
|
491899
|
+
var parseAllowedCredentials = (value) => {
|
|
491900
|
+
if (value === undefined) {
|
|
491901
|
+
return;
|
|
491902
|
+
}
|
|
491903
|
+
if (!Array.isArray(value)) {
|
|
491904
|
+
throw new Error("Invalid allowCredentials in passkey request");
|
|
491905
|
+
}
|
|
491906
|
+
return value.map((credential, index) => {
|
|
491907
|
+
if (!credential || typeof credential !== "object") {
|
|
491908
|
+
throw new Error(`Invalid allowCredentials[${index}] in passkey request`);
|
|
491909
|
+
}
|
|
491910
|
+
const candidate = credential;
|
|
491911
|
+
if (typeof candidate.type !== "string" || !candidate.type) {
|
|
491912
|
+
throw new Error(`Invalid allowCredentials[${index}].type in passkey request`);
|
|
491913
|
+
}
|
|
491914
|
+
if (candidate.transports !== undefined && (!Array.isArray(candidate.transports) || candidate.transports.some((item) => typeof item !== "string"))) {
|
|
491915
|
+
throw new Error(`Invalid allowCredentials[${index}].transports in passkey request`);
|
|
491916
|
+
}
|
|
491917
|
+
return {
|
|
491918
|
+
id: assertBase64Url(candidate.id, `allowCredentials[${index}].id`),
|
|
491919
|
+
type: candidate.type,
|
|
491920
|
+
...candidate.transports ? { transports: candidate.transports } : {}
|
|
491921
|
+
};
|
|
491922
|
+
});
|
|
491923
|
+
};
|
|
491924
|
+
var parsePasskeyRequestOptions = (content) => {
|
|
491925
|
+
let parsed;
|
|
491926
|
+
try {
|
|
491927
|
+
parsed = JSON.parse(content.toString("utf8"));
|
|
491928
|
+
} catch {
|
|
491929
|
+
throw new Error("WhatsApp sent malformed passkey request JSON");
|
|
491930
|
+
}
|
|
491931
|
+
if (!parsed || typeof parsed !== "object") {
|
|
491932
|
+
throw new Error("WhatsApp sent an invalid passkey request");
|
|
491933
|
+
}
|
|
491934
|
+
const value = parsed;
|
|
491935
|
+
if (typeof value.rpId !== "string" || value.rpId !== "whatsapp.com") {
|
|
491936
|
+
throw new Error("WhatsApp sent an unexpected passkey relying party");
|
|
491937
|
+
}
|
|
491938
|
+
if (value.timeout !== undefined && (typeof value.timeout !== "number" || value.timeout <= 0)) {
|
|
491939
|
+
throw new Error("WhatsApp sent an invalid passkey timeout");
|
|
491940
|
+
}
|
|
491941
|
+
if (value.userVerification !== undefined && typeof value.userVerification !== "string") {
|
|
491942
|
+
throw new Error("WhatsApp sent an invalid passkey user verification mode");
|
|
491943
|
+
}
|
|
491944
|
+
if (value.extensions !== undefined && (!value.extensions || typeof value.extensions !== "object")) {
|
|
491945
|
+
throw new Error("WhatsApp sent invalid passkey extensions");
|
|
491946
|
+
}
|
|
491947
|
+
return {
|
|
491948
|
+
challenge: assertBase64Url(value.challenge, "challenge"),
|
|
491949
|
+
rpId: value.rpId,
|
|
491950
|
+
...value.timeout === undefined ? {} : { timeout: value.timeout },
|
|
491951
|
+
...value.allowCredentials === undefined ? {} : { allowCredentials: parseAllowedCredentials(value.allowCredentials) },
|
|
491952
|
+
...value.userVerification === undefined ? {} : { userVerification: value.userVerification },
|
|
491953
|
+
...value.extensions === undefined ? {} : { extensions: value.extensions }
|
|
491954
|
+
};
|
|
491955
|
+
};
|
|
491956
|
+
var parsePasskeyCredentialResponse = (input) => {
|
|
491957
|
+
if (!input || typeof input !== "object") {
|
|
491958
|
+
throw new Error("Invalid passkey credential response");
|
|
491959
|
+
}
|
|
491960
|
+
const value = input;
|
|
491961
|
+
if (value.type !== "public-key") {
|
|
491962
|
+
throw new Error("Invalid passkey credential type");
|
|
491963
|
+
}
|
|
491964
|
+
if (!value.response || typeof value.response !== "object") {
|
|
491965
|
+
throw new Error("Invalid passkey authenticator response");
|
|
491966
|
+
}
|
|
491967
|
+
const response = value.response;
|
|
491968
|
+
return {
|
|
491969
|
+
id: assertBase64Url(value.id, "credential id"),
|
|
491970
|
+
rawId: assertBase64Url(value.rawId, "raw credential id"),
|
|
491971
|
+
type: value.type,
|
|
491972
|
+
response: {
|
|
491973
|
+
clientDataJSON: assertBase64Url(response.clientDataJSON, "clientDataJSON"),
|
|
491974
|
+
authenticatorData: assertBase64Url(response.authenticatorData, "authenticatorData"),
|
|
491975
|
+
signature: assertBase64Url(response.signature, "signature"),
|
|
491976
|
+
userHandle: assertBase64Url(response.userHandle, "userHandle", true)
|
|
491977
|
+
}
|
|
491978
|
+
};
|
|
491979
|
+
};
|
|
491980
|
+
var getPasskeyDeviceType = (browser) => {
|
|
491981
|
+
const browserName = browser[1].toLowerCase();
|
|
491982
|
+
if (browserName.includes("firefox"))
|
|
491983
|
+
return proto.DeviceProps.PlatformType.FIREFOX;
|
|
491984
|
+
if (browserName.includes("edge"))
|
|
491985
|
+
return proto.DeviceProps.PlatformType.EDGE;
|
|
491986
|
+
if (browserName.includes("opera"))
|
|
491987
|
+
return proto.DeviceProps.PlatformType.OPERA;
|
|
491988
|
+
if (browserName.includes("safari"))
|
|
491989
|
+
return proto.DeviceProps.PlatformType.SAFARI;
|
|
491990
|
+
return proto.DeviceProps.PlatformType.CHROME;
|
|
491991
|
+
};
|
|
491992
|
+
var derivePasskeyHandoffKey = (advSecretKey) => Buffer.from(hkdf(Buffer.from(advSecretKey, "base64"), 32, { info: PASSKEY_HANDOFF_INFO }));
|
|
491993
|
+
var buildPasskeyPrologue = ({ credential, pairingRef, browser, handoffKey, keyPair = Curve.generateKeyPair(), companionNonce }) => {
|
|
491994
|
+
if (companionNonce.length !== 32) {
|
|
491995
|
+
throw new Error("Passkey companion nonce must contain 32 bytes");
|
|
491996
|
+
}
|
|
491997
|
+
const deviceType = getPasskeyDeviceType(browser);
|
|
491998
|
+
const identity = Buffer.from(proto.CompanionEphemeralIdentity.encode({
|
|
491999
|
+
publicKey: keyPair.public,
|
|
492000
|
+
deviceType,
|
|
492001
|
+
ref: pairingRef
|
|
492002
|
+
}).finish());
|
|
492003
|
+
const commitment = sha256(Buffer.concat([identity, companionNonce]));
|
|
492004
|
+
const payload = Buffer.from(proto.ProloguePayload.encode({
|
|
492005
|
+
companionEphemeralIdentity: identity,
|
|
492006
|
+
commitment: { hash: commitment }
|
|
492007
|
+
}).finish());
|
|
492008
|
+
const content = [
|
|
492009
|
+
{ tag: "credential_id", attrs: {}, content: Buffer.from(credential.rawId, "base64url") },
|
|
492010
|
+
{ tag: "webauthn_assertion", attrs: {}, content: Buffer.from(JSON.stringify(credential), "utf8") },
|
|
492011
|
+
{ tag: "prologue_payload", attrs: {}, content: payload }
|
|
492012
|
+
];
|
|
492013
|
+
if (handoffKey) {
|
|
492014
|
+
content.push({ tag: "pairing_handoff_proof", attrs: {}, content: hmacSign(payload, handoffKey) });
|
|
492015
|
+
}
|
|
492016
|
+
return {
|
|
492017
|
+
content,
|
|
492018
|
+
payload,
|
|
492019
|
+
cache: { keyPair, companionNonce, pairingRef, deviceType },
|
|
492020
|
+
skipHandoffUX: Boolean(handoffKey)
|
|
492021
|
+
};
|
|
492022
|
+
};
|
|
492023
|
+
var continuePasskeyPairing = ({ cache: cache2, primaryIdentity }) => {
|
|
492024
|
+
const publicKey = primaryIdentity.publicKey ? Buffer.from(primaryIdentity.publicKey) : undefined;
|
|
492025
|
+
const nonce = primaryIdentity.nonce ? Buffer.from(primaryIdentity.nonce) : undefined;
|
|
492026
|
+
if (!publicKey || publicKey.length !== 32) {
|
|
492027
|
+
throw new Error("Invalid primary passkey public key");
|
|
492028
|
+
}
|
|
492029
|
+
if (!nonce || nonce.length !== 32) {
|
|
492030
|
+
throw new Error("Invalid primary passkey nonce");
|
|
492031
|
+
}
|
|
492032
|
+
const sharedSecret = Curve.sharedKey(cache2.keyPair.private, publicKey);
|
|
492033
|
+
const salt = `Companion Pairing ${cache2.deviceType} with ref ${cache2.pairingRef}`;
|
|
492034
|
+
const encryptionKey = Buffer.from(hkdf(sharedSecret, 32, { salt: Buffer.from(salt, "utf8"), info: PAIRING_ENCRYPTION_INFO }));
|
|
492035
|
+
const digest = sha256(Buffer.concat([cache2.companionNonce, publicKey]));
|
|
492036
|
+
const codeBytes = Buffer.alloc(5);
|
|
492037
|
+
for (let index = 0;index < codeBytes.length; index += 1) {
|
|
492038
|
+
codeBytes[index] = nonce[index] ^ digest[index];
|
|
492039
|
+
}
|
|
492040
|
+
const encodedCode = bytesToCrockford(codeBytes);
|
|
492041
|
+
return {
|
|
492042
|
+
cache: { ...cache2, encryptionKey },
|
|
492043
|
+
code: `${encodedCode.slice(0, 4)}-${encodedCode.slice(4)}`
|
|
492044
|
+
};
|
|
492045
|
+
};
|
|
492046
|
+
var buildEncryptedPasskeyPairingRequest = ({ cache: cache2, noisePublicKey, identityPublicKey, advSecretKey, iv }) => {
|
|
492047
|
+
if (!cache2.encryptionKey) {
|
|
492048
|
+
throw new Error("Passkey confirmation is not ready");
|
|
492049
|
+
}
|
|
492050
|
+
if (iv.length !== 12) {
|
|
492051
|
+
throw new Error("Passkey encryption IV must contain 12 bytes");
|
|
492052
|
+
}
|
|
492053
|
+
const request = Buffer.from(proto.PairingRequest.encode({
|
|
492054
|
+
companionPublicKey: noisePublicKey,
|
|
492055
|
+
companionIdentityKey: identityPublicKey,
|
|
492056
|
+
advSecret: Buffer.from(advSecretKey, "base64")
|
|
492057
|
+
}).finish());
|
|
492058
|
+
const encryptedPayload = aesEncryptGCM(request, cache2.encryptionKey, iv, Buffer.alloc(0));
|
|
492059
|
+
return Buffer.from(proto.EncryptedPairingRequest.encode({ encryptedPayload, iv }).finish());
|
|
492060
|
+
};
|
|
490766
492061
|
// ../../node_modules/.bun/baileys@vendor+baileys-v7.0.0-rc10.tgz+89588f7e3fe8b2e6/node_modules/baileys/lib/Signal/Group/sender-key-name.js
|
|
490767
492062
|
function isNull(str) {
|
|
490768
492063
|
return str === null || str === "";
|
|
@@ -490814,14 +492109,14 @@ class SenderKeyName2 {
|
|
|
490814
492109
|
}
|
|
490815
492110
|
|
|
490816
492111
|
// ../../node_modules/.bun/baileys@vendor+baileys-v7.0.0-rc10.tgz+89588f7e3fe8b2e6/node_modules/baileys/lib/Signal/Group/sender-chain-key.js
|
|
490817
|
-
var
|
|
492112
|
+
var import_crypto19 = __toESM(require_crypto(), 1);
|
|
490818
492113
|
|
|
490819
492114
|
// ../../node_modules/.bun/baileys@vendor+baileys-v7.0.0-rc10.tgz+89588f7e3fe8b2e6/node_modules/baileys/lib/Signal/Group/sender-message-key.js
|
|
490820
|
-
var
|
|
492115
|
+
var import_crypto18 = __toESM(require_crypto(), 1);
|
|
490821
492116
|
|
|
490822
492117
|
class SenderMessageKey {
|
|
490823
492118
|
constructor(iteration, seed) {
|
|
490824
|
-
const derivative =
|
|
492119
|
+
const derivative = import_crypto18.deriveSecrets(seed, Buffer.alloc(32), Buffer.from("WhisperGroup"));
|
|
490825
492120
|
const keys = new Uint8Array(32);
|
|
490826
492121
|
keys.set(new Uint8Array(derivative[0].slice(16)));
|
|
490827
492122
|
keys.set(new Uint8Array(derivative[1].slice(0, 16)), 16);
|
|
@@ -490865,7 +492160,7 @@ class SenderChainKey {
|
|
|
490865
492160
|
return this.chainKey;
|
|
490866
492161
|
}
|
|
490867
492162
|
getDerivative(seed, key) {
|
|
490868
|
-
return
|
|
492163
|
+
return import_crypto19.calculateMAC(key, seed);
|
|
490869
492164
|
}
|
|
490870
492165
|
}
|
|
490871
492166
|
|
|
@@ -491102,7 +492397,7 @@ class GroupSessionBuilder2 {
|
|
|
491102
492397
|
}
|
|
491103
492398
|
}
|
|
491104
492399
|
// ../../node_modules/.bun/baileys@vendor+baileys-v7.0.0-rc10.tgz+89588f7e3fe8b2e6/node_modules/baileys/lib/Signal/Group/group_cipher.js
|
|
491105
|
-
var
|
|
492400
|
+
var import_crypto20 = __toESM(require_crypto(), 1);
|
|
491106
492401
|
|
|
491107
492402
|
// ../../node_modules/.bun/baileys@vendor+baileys-v7.0.0-rc10.tgz+89588f7e3fe8b2e6/node_modules/baileys/lib/Signal/Group/sender-key-message.js
|
|
491108
492403
|
var import_curve2 = __toESM(require_curve2(), 1);
|
|
@@ -491227,14 +492522,14 @@ class GroupCipher2 {
|
|
|
491227
492522
|
}
|
|
491228
492523
|
async getPlainText(iv, key, ciphertext) {
|
|
491229
492524
|
try {
|
|
491230
|
-
return
|
|
492525
|
+
return import_crypto20.decrypt(key, ciphertext, iv);
|
|
491231
492526
|
} catch (e) {
|
|
491232
492527
|
throw new Error("InvalidMessageException");
|
|
491233
492528
|
}
|
|
491234
492529
|
}
|
|
491235
492530
|
async getCipherText(iv, key, plaintext) {
|
|
491236
492531
|
try {
|
|
491237
|
-
return
|
|
492532
|
+
return import_crypto20.encrypt(key, plaintext, iv);
|
|
491238
492533
|
} catch (e) {
|
|
491239
492534
|
throw new Error("InvalidMessageException");
|
|
491240
492535
|
}
|
|
@@ -493922,6 +495217,9 @@ var makeSocket = (config2) => {
|
|
|
493922
495217
|
let epoch = 1;
|
|
493923
495218
|
let keepAliveReq;
|
|
493924
495219
|
let qrTimer;
|
|
495220
|
+
let passkeyHandoff;
|
|
495221
|
+
let passkeyLinkingCache;
|
|
495222
|
+
let passkeySkipHandoffUX = false;
|
|
493925
495223
|
let closed = false;
|
|
493926
495224
|
const socketEndHandlers = [];
|
|
493927
495225
|
const onUnexpectedError = (err2, msg) => {
|
|
@@ -494277,6 +495575,156 @@ var makeSocket = (config2) => {
|
|
|
494277
495575
|
const ciphered = aesEncryptCTR(authState.creds.pairingEphemeralKeyPair.public, key, randomIv);
|
|
494278
495576
|
return Buffer.concat([salt, randomIv, ciphered]);
|
|
494279
495577
|
}
|
|
495578
|
+
const getPasskeyRequestOptions = async (notification) => {
|
|
495579
|
+
let optionsNode = notification ? getBinaryNodeChild(notification, "passkey_request_options") : undefined;
|
|
495580
|
+
if (!optionsNode) {
|
|
495581
|
+
const response = await query({
|
|
495582
|
+
tag: "iq",
|
|
495583
|
+
attrs: {
|
|
495584
|
+
to: S_WHATSAPP_NET,
|
|
495585
|
+
type: "get",
|
|
495586
|
+
xmlns: "md"
|
|
495587
|
+
},
|
|
495588
|
+
content: [{ tag: "passkey_request_options", attrs: {} }]
|
|
495589
|
+
});
|
|
495590
|
+
optionsNode = getBinaryNodeChild(response, "passkey_request_options");
|
|
495591
|
+
}
|
|
495592
|
+
if (!optionsNode?.content || Array.isArray(optionsNode.content)) {
|
|
495593
|
+
throw new Error("Passkey request did not contain public key options");
|
|
495594
|
+
}
|
|
495595
|
+
return parsePasskeyRequestOptions(Buffer.from(optionsNode.content));
|
|
495596
|
+
};
|
|
495597
|
+
const handlePasskeyRequest = async (notification) => {
|
|
495598
|
+
if (notification.attrs.from !== S_WHATSAPP_NET && notification.attrs.from !== SERVER_JID) {
|
|
495599
|
+
logger5.warn({ from: notification.attrs.from }, "ignored passkey request from unexpected sender");
|
|
495600
|
+
return;
|
|
495601
|
+
}
|
|
495602
|
+
try {
|
|
495603
|
+
const publicKey = await getPasskeyRequestOptions(notification);
|
|
495604
|
+
clearTimeout(qrTimer);
|
|
495605
|
+
passkeyHandoff = {
|
|
495606
|
+
key: derivePasskeyHandoffKey(creds.advSecretKey),
|
|
495607
|
+
createdAt: Date.now()
|
|
495608
|
+
};
|
|
495609
|
+
creds.advSecretKey = randomBytes9(32).toString("base64");
|
|
495610
|
+
ev.emit("creds.update", { advSecretKey: creds.advSecretKey });
|
|
495611
|
+
ev.emit("connection.update", {
|
|
495612
|
+
qr: undefined,
|
|
495613
|
+
passkey: { state: "request", publicKey }
|
|
495614
|
+
});
|
|
495615
|
+
} catch (error) {
|
|
495616
|
+
const message2 = error instanceof Error ? error.message : "Unable to process passkey request";
|
|
495617
|
+
logger5.warn({ err: error }, "failed to process passkey request");
|
|
495618
|
+
ev.emit("connection.update", {
|
|
495619
|
+
passkey: { state: "error", phase: "request", message: message2 }
|
|
495620
|
+
});
|
|
495621
|
+
}
|
|
495622
|
+
};
|
|
495623
|
+
const sendPasskeyResponse = async (input) => {
|
|
495624
|
+
const credential = parsePasskeyCredentialResponse(input);
|
|
495625
|
+
const refResponse = await query({
|
|
495626
|
+
tag: "iq",
|
|
495627
|
+
attrs: {
|
|
495628
|
+
to: S_WHATSAPP_NET,
|
|
495629
|
+
type: "get",
|
|
495630
|
+
xmlns: "md"
|
|
495631
|
+
},
|
|
495632
|
+
content: [{ tag: "ref", attrs: {} }]
|
|
495633
|
+
});
|
|
495634
|
+
const refNode = getBinaryNodeChild(refResponse, "ref");
|
|
495635
|
+
if (!refNode?.content || Array.isArray(refNode.content)) {
|
|
495636
|
+
throw new Error("WhatsApp did not provide a companion reference");
|
|
495637
|
+
}
|
|
495638
|
+
const handoffKey = passkeyHandoff && Date.now() - passkeyHandoff.createdAt < 5 * 60000 ? passkeyHandoff.key : undefined;
|
|
495639
|
+
const prologue = buildPasskeyPrologue({
|
|
495640
|
+
credential,
|
|
495641
|
+
pairingRef: Buffer.from(refNode.content).toString("utf8"),
|
|
495642
|
+
browser,
|
|
495643
|
+
handoffKey,
|
|
495644
|
+
companionNonce: randomBytes9(32)
|
|
495645
|
+
});
|
|
495646
|
+
passkeyLinkingCache = prologue.cache;
|
|
495647
|
+
passkeySkipHandoffUX = prologue.skipHandoffUX;
|
|
495648
|
+
await query({
|
|
495649
|
+
tag: "iq",
|
|
495650
|
+
attrs: {
|
|
495651
|
+
to: S_WHATSAPP_NET,
|
|
495652
|
+
type: "set",
|
|
495653
|
+
xmlns: "md"
|
|
495654
|
+
},
|
|
495655
|
+
content: [{ tag: "passkey_prologue", attrs: {}, content: prologue.content }]
|
|
495656
|
+
});
|
|
495657
|
+
passkeyHandoff = undefined;
|
|
495658
|
+
};
|
|
495659
|
+
const handlePasskeyContinuation = async (notification) => {
|
|
495660
|
+
if (notification.attrs.from !== S_WHATSAPP_NET && notification.attrs.from !== SERVER_JID) {
|
|
495661
|
+
logger5.warn({ from: notification.attrs.from }, "ignored passkey continuation from unexpected sender");
|
|
495662
|
+
return;
|
|
495663
|
+
}
|
|
495664
|
+
try {
|
|
495665
|
+
if (!passkeyLinkingCache) {
|
|
495666
|
+
throw new Error("Passkey continuation arrived without an active ceremony");
|
|
495667
|
+
}
|
|
495668
|
+
const identityNode = getBinaryNodeChild(notification, "primary_ephemeral_identity");
|
|
495669
|
+
if (!identityNode?.content || Array.isArray(identityNode.content)) {
|
|
495670
|
+
throw new Error("Passkey continuation did not contain a primary identity");
|
|
495671
|
+
}
|
|
495672
|
+
const primaryIdentity = proto.PrimaryEphemeralIdentity.decode(Buffer.from(identityNode.content));
|
|
495673
|
+
const continuation = continuePasskeyPairing({ cache: passkeyLinkingCache, primaryIdentity });
|
|
495674
|
+
passkeyLinkingCache = continuation.cache;
|
|
495675
|
+
await query({
|
|
495676
|
+
tag: "iq",
|
|
495677
|
+
attrs: {
|
|
495678
|
+
to: S_WHATSAPP_NET,
|
|
495679
|
+
type: "set",
|
|
495680
|
+
xmlns: "md"
|
|
495681
|
+
},
|
|
495682
|
+
content: [
|
|
495683
|
+
{
|
|
495684
|
+
tag: "companion_nonce",
|
|
495685
|
+
attrs: {},
|
|
495686
|
+
content: passkeyLinkingCache.companionNonce
|
|
495687
|
+
}
|
|
495688
|
+
]
|
|
495689
|
+
});
|
|
495690
|
+
ev.emit("connection.update", {
|
|
495691
|
+
passkey: {
|
|
495692
|
+
state: "confirmation",
|
|
495693
|
+
code: continuation.code,
|
|
495694
|
+
skipHandoffUX: passkeySkipHandoffUX
|
|
495695
|
+
}
|
|
495696
|
+
});
|
|
495697
|
+
} catch (error) {
|
|
495698
|
+
const message2 = error instanceof Error ? error.message : "Unable to continue passkey pairing";
|
|
495699
|
+
logger5.warn({ err: error }, "failed to process passkey continuation");
|
|
495700
|
+
ev.emit("connection.update", {
|
|
495701
|
+
passkey: { state: "error", phase: "continuation", message: message2 }
|
|
495702
|
+
});
|
|
495703
|
+
}
|
|
495704
|
+
};
|
|
495705
|
+
const sendPasskeyConfirmation = async () => {
|
|
495706
|
+
if (!passkeyLinkingCache) {
|
|
495707
|
+
throw new Error("No passkey confirmation is pending");
|
|
495708
|
+
}
|
|
495709
|
+
const encryptedRequest = buildEncryptedPasskeyPairingRequest({
|
|
495710
|
+
cache: passkeyLinkingCache,
|
|
495711
|
+
noisePublicKey: creds.noiseKey.public,
|
|
495712
|
+
identityPublicKey: creds.signedIdentityKey.public,
|
|
495713
|
+
advSecretKey: creds.advSecretKey,
|
|
495714
|
+
iv: randomBytes9(12)
|
|
495715
|
+
});
|
|
495716
|
+
await query({
|
|
495717
|
+
tag: "iq",
|
|
495718
|
+
attrs: {
|
|
495719
|
+
to: S_WHATSAPP_NET,
|
|
495720
|
+
type: "set",
|
|
495721
|
+
xmlns: "md"
|
|
495722
|
+
},
|
|
495723
|
+
content: [{ tag: "encrypted_pairing_request", attrs: {}, content: encryptedRequest }]
|
|
495724
|
+
});
|
|
495725
|
+
passkeyLinkingCache = undefined;
|
|
495726
|
+
passkeySkipHandoffUX = false;
|
|
495727
|
+
};
|
|
494280
495728
|
const sendWAMBuffer = (wamBuffer) => {
|
|
494281
495729
|
return query({
|
|
494282
495730
|
tag: "iq",
|
|
@@ -494306,6 +495754,12 @@ var makeSocket = (config2) => {
|
|
|
494306
495754
|
ws.on("error", mapWebSocketError(end));
|
|
494307
495755
|
ws.on("close", () => void end(new import_boom14.Boom("Connection Terminated", { statusCode: DisconnectReason.connectionClosed })));
|
|
494308
495756
|
ws.on("CB:xmlstreamend", () => void end(new import_boom14.Boom("Connection Terminated by Server", { statusCode: DisconnectReason.connectionClosed })));
|
|
495757
|
+
ws.on("CB:notification,type:passkey_prologue_request", (notification) => {
|
|
495758
|
+
handlePasskeyRequest(notification);
|
|
495759
|
+
});
|
|
495760
|
+
ws.on("CB:notification,type:crsc_continuation", (notification) => {
|
|
495761
|
+
handlePasskeyContinuation(notification);
|
|
495762
|
+
});
|
|
494309
495763
|
ws.on("CB:iq,type:set,pair-device", async (stanza) => {
|
|
494310
495764
|
const iq = {
|
|
494311
495765
|
tag: "iq",
|
|
@@ -494533,6 +495987,8 @@ var makeSocket = (config2) => {
|
|
|
494533
495987
|
digestKeyBundle,
|
|
494534
495988
|
rotateSignedPreKey,
|
|
494535
495989
|
requestPairingCode,
|
|
495990
|
+
sendPasskeyResponse,
|
|
495991
|
+
sendPasskeyConfirmation,
|
|
494536
495992
|
updateServerTimeOffset,
|
|
494537
495993
|
sendUnifiedSession,
|
|
494538
495994
|
wamBuffer: publicWAMBuffer,
|
|
@@ -500063,6 +501519,7 @@ var MAX_QR_ATTEMPTS = 3;
|
|
|
500063
501519
|
var qrCycleAttempts = new Map;
|
|
500064
501520
|
var MAX_QR_CYCLES = 2;
|
|
500065
501521
|
var activeQrCodes = new Map;
|
|
501522
|
+
var passkeyInstances = new Set;
|
|
500066
501523
|
var connectionTimeouts = new Map;
|
|
500067
501524
|
var CONNECTION_TIMEOUT_MS = 45000;
|
|
500068
501525
|
var authenticatedInstances = new Set;
|
|
@@ -500159,6 +501616,7 @@ async function handleConnectionClose(plugin7, instanceId, lastDisconnect, config
|
|
|
500159
501616
|
qrCodeAttempts.delete(instanceId);
|
|
500160
501617
|
qrCycleAttempts.delete(instanceId);
|
|
500161
501618
|
authenticatedInstances.delete(instanceId);
|
|
501619
|
+
passkeyInstances.delete(instanceId);
|
|
500162
501620
|
cancelPendingReconnect(instanceId);
|
|
500163
501621
|
await plugin7.handleDisconnected(instanceId, "Logged out from WhatsApp", false);
|
|
500164
501622
|
return;
|
|
@@ -500206,6 +501664,7 @@ async function handleConnectionOpen(plugin7, instanceId, sock) {
|
|
|
500206
501664
|
qrCodeAttempts.delete(instanceId);
|
|
500207
501665
|
qrCycleAttempts.delete(instanceId);
|
|
500208
501666
|
activeQrCodes.delete(instanceId);
|
|
501667
|
+
passkeyInstances.delete(instanceId);
|
|
500209
501668
|
clearConnectionTimeout(instanceId);
|
|
500210
501669
|
authenticatedInstances.add(instanceId);
|
|
500211
501670
|
log51.info("Connection opened", { instanceId });
|
|
@@ -500213,8 +501672,16 @@ async function handleConnectionOpen(plugin7, instanceId, sock) {
|
|
|
500213
501672
|
}
|
|
500214
501673
|
function setupConnectionHandlers2(sock, plugin7, instanceId, onReconnect, clearAuthAndReconnect, config2 = DEFAULT_RECONNECT_CONFIG2) {
|
|
500215
501674
|
sock.ev.on("connection.update", async (update) => {
|
|
500216
|
-
const { connection, lastDisconnect, qr } = update;
|
|
500217
|
-
if (
|
|
501675
|
+
const { connection, lastDisconnect, passkey: passkey2, qr } = update;
|
|
501676
|
+
if (passkey2) {
|
|
501677
|
+
passkeyInstances.add(instanceId);
|
|
501678
|
+
activeQrCodes.delete(instanceId);
|
|
501679
|
+
qrCodeAttempts.delete(instanceId);
|
|
501680
|
+
qrCycleAttempts.delete(instanceId);
|
|
501681
|
+
clearConnectionTimeout(instanceId);
|
|
501682
|
+
await plugin7.handlePasskeyUpdate(instanceId, passkey2);
|
|
501683
|
+
}
|
|
501684
|
+
if (qr && !passkey2 && !passkeyInstances.has(instanceId)) {
|
|
500218
501685
|
const shouldContinue = await handleQrCode(plugin7, instanceId, qr, clearAuthAndReconnect);
|
|
500219
501686
|
if (!shouldContinue) {
|
|
500220
501687
|
return;
|
|
@@ -500241,6 +501708,7 @@ function resetConnectionState2(instanceId) {
|
|
|
500241
501708
|
qrCodeAttempts.delete(instanceId);
|
|
500242
501709
|
qrCycleAttempts.delete(instanceId);
|
|
500243
501710
|
activeQrCodes.delete(instanceId);
|
|
501711
|
+
passkeyInstances.delete(instanceId);
|
|
500244
501712
|
authenticatedInstances.delete(instanceId);
|
|
500245
501713
|
clearConnectionTimeout(instanceId);
|
|
500246
501714
|
cancelPendingReconnect(instanceId);
|
|
@@ -500432,6 +501900,77 @@ function getMediaSize(msg) {
|
|
|
500432
501900
|
var log52 = createLogger("whatsapp:messages");
|
|
500433
501901
|
var fallbackDedupeCache3 = createInboundDedupeCache();
|
|
500434
501902
|
var downloadGuard6 = createDownloadGuard({ maxSizeBytes: getWhatsAppMediaDownloadMaxBytes() });
|
|
501903
|
+
function joinLines(...parts) {
|
|
501904
|
+
const text = parts.filter((p2) => typeof p2 === "string" && p2.trim().length > 0).join(`
|
|
501905
|
+
`);
|
|
501906
|
+
return text.length > 0 ? text : undefined;
|
|
501907
|
+
}
|
|
501908
|
+
function bracketButtons(labels) {
|
|
501909
|
+
const clean = labels.filter((l) => typeof l === "string" && l.trim().length > 0);
|
|
501910
|
+
return clean.length > 0 ? clean.map((l) => `[${l.trim()}]`).join(" ") : undefined;
|
|
501911
|
+
}
|
|
501912
|
+
function extractListMessageText(list) {
|
|
501913
|
+
const rows = (list.sections ?? []).flatMap((s) => (s.rows ?? []).map((r) => r.title ? `\u2022 ${r.title}` : ""));
|
|
501914
|
+
return joinLines(list.title, list.description, ...rows, list.footerText);
|
|
501915
|
+
}
|
|
501916
|
+
function extractButtonsMessageText(bm) {
|
|
501917
|
+
const labels = bracketButtons((bm.buttons ?? []).map((b2) => b2.buttonText?.displayText));
|
|
501918
|
+
return joinLines(bm.contentText ?? bm.text, bm.footerText, labels);
|
|
501919
|
+
}
|
|
501920
|
+
function extractInteractiveMessageText(im) {
|
|
501921
|
+
const labels = bracketButtons((im.nativeFlowMessage?.buttons ?? []).map((b2) => b2.name));
|
|
501922
|
+
return joinLines(im.header?.title, im.header?.subtitle, im.body?.text, im.footer?.text, labels);
|
|
501923
|
+
}
|
|
501924
|
+
function extractTemplateMessageText(tpl) {
|
|
501925
|
+
const hydrated = tpl.hydratedTemplate ?? tpl.hydratedFourRowTemplate;
|
|
501926
|
+
if (hydrated) {
|
|
501927
|
+
const labels = bracketButtons((hydrated.hydratedButtons ?? []).map((b2) => b2.quickReplyButton?.displayText ?? b2.urlButton?.displayText ?? b2.callButton?.displayText));
|
|
501928
|
+
return joinLines(hydrated.hydratedTitleText, hydrated.hydratedContentText, hydrated.hydratedFooterText, labels);
|
|
501929
|
+
}
|
|
501930
|
+
return tpl.interactiveMessageTemplate ? extractInteractiveMessageText(tpl.interactiveMessageTemplate) : undefined;
|
|
501931
|
+
}
|
|
501932
|
+
function extractInteractiveMediaHeader(container, caption) {
|
|
501933
|
+
if (container.imageMessage) {
|
|
501934
|
+
return {
|
|
501935
|
+
type: "image",
|
|
501936
|
+
caption: caption ?? container.imageMessage.caption ?? undefined,
|
|
501937
|
+
mimeType: container.imageMessage.mimetype ?? "image/jpeg",
|
|
501938
|
+
mediaUrl: container.imageMessage.url ?? undefined
|
|
501939
|
+
};
|
|
501940
|
+
}
|
|
501941
|
+
if (container.videoMessage) {
|
|
501942
|
+
return {
|
|
501943
|
+
type: "video",
|
|
501944
|
+
caption: caption ?? container.videoMessage.caption ?? undefined,
|
|
501945
|
+
mimeType: container.videoMessage.mimetype ?? "video/mp4",
|
|
501946
|
+
mediaUrl: container.videoMessage.url ?? undefined
|
|
501947
|
+
};
|
|
501948
|
+
}
|
|
501949
|
+
if (container.documentMessage) {
|
|
501950
|
+
return {
|
|
501951
|
+
type: "document",
|
|
501952
|
+
filename: container.documentMessage.fileName ?? undefined,
|
|
501953
|
+
caption: caption ?? container.documentMessage.caption ?? undefined,
|
|
501954
|
+
mimeType: container.documentMessage.mimetype ?? "application/octet-stream",
|
|
501955
|
+
mediaUrl: container.documentMessage.url ?? undefined
|
|
501956
|
+
};
|
|
501957
|
+
}
|
|
501958
|
+
return null;
|
|
501959
|
+
}
|
|
501960
|
+
function extractButtonsMessage(bm) {
|
|
501961
|
+
const text = extractButtonsMessageText(bm);
|
|
501962
|
+
return extractInteractiveMediaHeader(bm, text) ?? { type: "text", text };
|
|
501963
|
+
}
|
|
501964
|
+
function extractInteractiveMessage(im) {
|
|
501965
|
+
const text = extractInteractiveMessageText(im);
|
|
501966
|
+
return extractInteractiveMediaHeader(im.header ?? {}, text) ?? { type: "text", text };
|
|
501967
|
+
}
|
|
501968
|
+
function extractTemplateMessage(tpl) {
|
|
501969
|
+
const text = extractTemplateMessageText(tpl);
|
|
501970
|
+
const hydrated = tpl.hydratedTemplate ?? tpl.hydratedFourRowTemplate;
|
|
501971
|
+
const media = hydrated ? extractInteractiveMediaHeader(hydrated, text) : null;
|
|
501972
|
+
return media ?? { type: "text", text };
|
|
501973
|
+
}
|
|
500435
501974
|
var contentExtractors = [
|
|
500436
501975
|
{
|
|
500437
501976
|
check: (m2) => !!m2.conversation,
|
|
@@ -500635,6 +502174,25 @@ var contentExtractors = [
|
|
|
500635
502174
|
text: m2.buttonsResponseMessage?.selectedDisplayText ?? m2.buttonsResponseMessage?.selectedButtonId ?? undefined
|
|
500636
502175
|
})
|
|
500637
502176
|
},
|
|
502177
|
+
{
|
|
502178
|
+
check: (m2) => !!m2.listMessage,
|
|
502179
|
+
extract: (m2) => ({
|
|
502180
|
+
type: "text",
|
|
502181
|
+
text: m2.listMessage ? extractListMessageText(m2.listMessage) : undefined
|
|
502182
|
+
})
|
|
502183
|
+
},
|
|
502184
|
+
{
|
|
502185
|
+
check: (m2) => !!m2.buttonsMessage,
|
|
502186
|
+
extract: (m2) => m2.buttonsMessage ? extractButtonsMessage(m2.buttonsMessage) : null
|
|
502187
|
+
},
|
|
502188
|
+
{
|
|
502189
|
+
check: (m2) => !!m2.interactiveMessage,
|
|
502190
|
+
extract: (m2) => m2.interactiveMessage ? extractInteractiveMessage(m2.interactiveMessage) : null
|
|
502191
|
+
},
|
|
502192
|
+
{
|
|
502193
|
+
check: (m2) => !!m2.templateMessage,
|
|
502194
|
+
extract: (m2) => m2.templateMessage ? extractTemplateMessage(m2.templateMessage) : null
|
|
502195
|
+
},
|
|
500638
502196
|
{
|
|
500639
502197
|
check: (m2) => !!m2.senderKeyDistributionMessage,
|
|
500640
502198
|
extract: () => null
|
|
@@ -501439,9 +502997,9 @@ function splitWhatsAppMessage(text, maxLength = DEFAULT_MAX_LENGTH2) {
|
|
|
501439
502997
|
flushCurrent();
|
|
501440
502998
|
current = piece;
|
|
501441
502999
|
};
|
|
501442
|
-
for (const
|
|
501443
|
-
if (
|
|
501444
|
-
const paragraphUnits = splitByDelimiter(
|
|
503000
|
+
for (const segment2 of segments) {
|
|
503001
|
+
if (segment2.type === "text") {
|
|
503002
|
+
const paragraphUnits = splitByDelimiter(segment2.value, `
|
|
501445
503003
|
|
|
501446
503004
|
`);
|
|
501447
503005
|
const textPieces = packUnits(paragraphUnits, maxLength);
|
|
@@ -501450,12 +503008,12 @@ function splitWhatsAppMessage(text, maxLength = DEFAULT_MAX_LENGTH2) {
|
|
|
501450
503008
|
}
|
|
501451
503009
|
continue;
|
|
501452
503010
|
}
|
|
501453
|
-
if (
|
|
501454
|
-
appendPiece(
|
|
503011
|
+
if (segment2.value.length <= maxLength) {
|
|
503012
|
+
appendPiece(segment2.value);
|
|
501455
503013
|
continue;
|
|
501456
503014
|
}
|
|
501457
503015
|
flushCurrent();
|
|
501458
|
-
const splitCode = splitHugeCodeBlock(
|
|
503016
|
+
const splitCode = splitHugeCodeBlock(segment2.value, maxLength);
|
|
501459
503017
|
for (const piece of splitCode) {
|
|
501460
503018
|
appendPiece(piece);
|
|
501461
503019
|
}
|
|
@@ -502071,6 +503629,7 @@ class WhatsAppPlugin extends BaseChannelPlugin {
|
|
|
502071
503629
|
version = "1.0.0";
|
|
502072
503630
|
capabilities = WHATSAPP_CAPABILITIES;
|
|
502073
503631
|
sockets = new Map;
|
|
503632
|
+
passkeyStates = new Map;
|
|
502074
503633
|
pluginConfig = {};
|
|
502075
503634
|
historySyncCallbacks = new Map;
|
|
502076
503635
|
historyPushFetchCount = new Map;
|
|
@@ -502436,6 +503995,7 @@ class WhatsAppPlugin extends BaseChannelPlugin {
|
|
|
502436
503995
|
async onInitialize(_context) {}
|
|
502437
503996
|
async connect(instanceId, config2) {
|
|
502438
503997
|
if (config2.options?.forceNewQr === true) {
|
|
503998
|
+
this.passkeyStates.delete(instanceId);
|
|
502439
503999
|
const existingSocket = this.sockets.get(instanceId);
|
|
502440
504000
|
if (existingSocket) {
|
|
502441
504001
|
existingSocket.ev.removeAllListeners("connection.update");
|
|
@@ -502529,6 +504089,7 @@ class WhatsAppPlugin extends BaseChannelPlugin {
|
|
|
502529
504089
|
await this.emitInstanceDisconnected(instanceId, "User requested disconnect");
|
|
502530
504090
|
}
|
|
502531
504091
|
clearInstanceCaches(instanceId) {
|
|
504092
|
+
this.passkeyStates.delete(instanceId);
|
|
502532
504093
|
this.groupMetadataCache.delete(instanceId);
|
|
502533
504094
|
this.groupsCache.delete(instanceId);
|
|
502534
504095
|
this.contactsCache.delete(instanceId);
|
|
@@ -502572,6 +504133,91 @@ class WhatsAppPlugin extends BaseChannelPlugin {
|
|
|
502572
504133
|
throw new WhatsAppError(ErrorCode2.PAIRING_FAILED, `Failed to request pairing code: ${message2}`);
|
|
502573
504134
|
}
|
|
502574
504135
|
}
|
|
504136
|
+
getPasskeyState(instanceId) {
|
|
504137
|
+
return this.passkeyStates.get(instanceId) ?? null;
|
|
504138
|
+
}
|
|
504139
|
+
async submitPasskeyResponse(instanceId, credential) {
|
|
504140
|
+
const sock = this.sockets.get(instanceId);
|
|
504141
|
+
if (!sock) {
|
|
504142
|
+
throw new WhatsAppError(ErrorCode2.NOT_CONNECTED, `Instance ${instanceId} is not connected.`);
|
|
504143
|
+
}
|
|
504144
|
+
const current = this.passkeyStates.get(instanceId);
|
|
504145
|
+
if (current?.state !== "request") {
|
|
504146
|
+
throw new WhatsAppError(ErrorCode2.PAIRING_FAILED, "No passkey authentication is pending.");
|
|
504147
|
+
}
|
|
504148
|
+
this.passkeyStates.set(instanceId, { state: "confirming", requestedAt: current.requestedAt });
|
|
504149
|
+
try {
|
|
504150
|
+
await sock.sendPasskeyResponse(credential);
|
|
504151
|
+
} catch (error) {
|
|
504152
|
+
this.passkeyStates.set(instanceId, current);
|
|
504153
|
+
throw error;
|
|
504154
|
+
}
|
|
504155
|
+
}
|
|
504156
|
+
async confirmPasskey(instanceId) {
|
|
504157
|
+
const sock = this.sockets.get(instanceId);
|
|
504158
|
+
if (!sock) {
|
|
504159
|
+
throw new WhatsAppError(ErrorCode2.NOT_CONNECTED, `Instance ${instanceId} is not connected.`);
|
|
504160
|
+
}
|
|
504161
|
+
const current = this.passkeyStates.get(instanceId);
|
|
504162
|
+
if (current?.state !== "confirmation") {
|
|
504163
|
+
throw new WhatsAppError(ErrorCode2.PAIRING_FAILED, "No passkey confirmation is pending.");
|
|
504164
|
+
}
|
|
504165
|
+
this.passkeyStates.set(instanceId, { state: "confirming", requestedAt: current.requestedAt });
|
|
504166
|
+
try {
|
|
504167
|
+
await sock.sendPasskeyConfirmation();
|
|
504168
|
+
} catch (error) {
|
|
504169
|
+
this.passkeyStates.set(instanceId, current);
|
|
504170
|
+
throw error;
|
|
504171
|
+
}
|
|
504172
|
+
}
|
|
504173
|
+
async handlePasskeyUpdate(instanceId, update) {
|
|
504174
|
+
const requestedAt = new Date().toISOString();
|
|
504175
|
+
if (update.state === "request") {
|
|
504176
|
+
this.passkeyStates.set(instanceId, { state: "request", publicKey: update.publicKey, requestedAt });
|
|
504177
|
+
return;
|
|
504178
|
+
}
|
|
504179
|
+
if (update.state === "error") {
|
|
504180
|
+
this.passkeyStates.set(instanceId, {
|
|
504181
|
+
state: "error",
|
|
504182
|
+
phase: update.phase,
|
|
504183
|
+
message: update.message,
|
|
504184
|
+
requestedAt
|
|
504185
|
+
});
|
|
504186
|
+
return;
|
|
504187
|
+
}
|
|
504188
|
+
if (update.skipHandoffUX) {
|
|
504189
|
+
this.passkeyStates.set(instanceId, { state: "confirming", requestedAt });
|
|
504190
|
+
const sock = this.sockets.get(instanceId);
|
|
504191
|
+
if (!sock) {
|
|
504192
|
+
this.passkeyStates.set(instanceId, {
|
|
504193
|
+
state: "error",
|
|
504194
|
+
phase: "continuation",
|
|
504195
|
+
message: "WhatsApp connection ended before passkey confirmation.",
|
|
504196
|
+
requestedAt
|
|
504197
|
+
});
|
|
504198
|
+
return;
|
|
504199
|
+
}
|
|
504200
|
+
try {
|
|
504201
|
+
await sock.sendPasskeyConfirmation();
|
|
504202
|
+
} catch (error) {
|
|
504203
|
+
const message2 = error instanceof Error ? error.message : "Unable to confirm passkey pairing.";
|
|
504204
|
+
this.passkeyStates.set(instanceId, {
|
|
504205
|
+
state: "error",
|
|
504206
|
+
phase: "continuation",
|
|
504207
|
+
message: message2,
|
|
504208
|
+
requestedAt
|
|
504209
|
+
});
|
|
504210
|
+
this.logger.warn("Failed to auto-confirm passkey pairing", { instanceId, error: message2 });
|
|
504211
|
+
}
|
|
504212
|
+
return;
|
|
504213
|
+
}
|
|
504214
|
+
this.passkeyStates.set(instanceId, {
|
|
504215
|
+
state: "confirmation",
|
|
504216
|
+
code: update.code,
|
|
504217
|
+
requiresUserConfirmation: true,
|
|
504218
|
+
requestedAt
|
|
504219
|
+
});
|
|
504220
|
+
}
|
|
502575
504221
|
buildQuotedOptions(message2, jid) {
|
|
502576
504222
|
if (!message2.replyTo)
|
|
502577
504223
|
return;
|
|
@@ -503496,6 +505142,7 @@ class WhatsAppPlugin extends BaseChannelPlugin {
|
|
|
503496
505142
|
}
|
|
503497
505143
|
}
|
|
503498
505144
|
async handleConnected(instanceId, sock) {
|
|
505145
|
+
this.passkeyStates.delete(instanceId);
|
|
503499
505146
|
let profileName;
|
|
503500
505147
|
let profilePicUrl;
|
|
503501
505148
|
let ownerIdentifier;
|