emulate 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +198 -27
- package/dist/api.d.ts +2 -1
- package/dist/api.js +675 -103
- package/dist/api.js.map +1 -1
- package/dist/chunk-WVQMFHQM.js +83 -0
- package/dist/chunk-WVQMFHQM.js.map +1 -0
- package/dist/{dist-B674PYKV.js → dist-2ZZGNPJI.js} +22 -43
- package/dist/dist-2ZZGNPJI.js.map +1 -0
- package/dist/{dist-RDFBZ5O6.js → dist-CXRPM6BK.js} +211 -48
- package/dist/dist-CXRPM6BK.js.map +1 -0
- package/dist/{dist-VVXVP5EZ.js → dist-DSJSF3GY.js} +551 -91
- package/dist/dist-DSJSF3GY.js.map +1 -0
- package/dist/{dist-RMK3BS5M.js → dist-IFULY5LE.js} +196 -33
- package/dist/dist-IFULY5LE.js.map +1 -0
- package/dist/dist-IRUBHCZU.js +1898 -0
- package/dist/dist-IRUBHCZU.js.map +1 -0
- package/dist/{dist-YOVM5HEY.js → dist-NJJLJT2N.js} +520 -61
- package/dist/dist-NJJLJT2N.js.map +1 -0
- package/dist/dist-OGSAVJ25.js +4874 -0
- package/dist/dist-OGSAVJ25.js.map +1 -0
- package/dist/{dist-H6JYGQM4.js → dist-PO4CL5SJ.js} +271 -158
- package/dist/dist-PO4CL5SJ.js.map +1 -0
- package/dist/{dist-QMOJM6DV.js → dist-R3TNKUIE.js} +238 -55
- package/dist/dist-R3TNKUIE.js.map +1 -0
- package/dist/{dist-6JFNJPUU.js → dist-WACHAAVU.js} +171 -22
- package/dist/dist-WACHAAVU.js.map +1 -0
- package/dist/{dist-OTJZRQ3Q.js → dist-XWWZVLQQ.js} +216 -75
- package/dist/dist-XWWZVLQQ.js.map +1 -0
- package/dist/{dist-6EW7SSOZ.js → dist-ZY5SZSJ2.js} +397 -223
- package/dist/dist-ZY5SZSJ2.js.map +1 -0
- package/dist/fonts/favicon.ico +0 -0
- package/dist/helpers-LXLP3DFE-LBOTATT5.js +17 -0
- package/dist/helpers-LXLP3DFE-LBOTATT5.js.map +1 -0
- package/dist/index.js +812 -117
- package/dist/index.js.map +1 -1
- package/package.json +17 -15
- package/dist/chunk-TEPNEZ63.js +0 -2143
- package/dist/chunk-TEPNEZ63.js.map +0 -1
- package/dist/dist-6EW7SSOZ.js.map +0 -1
- package/dist/dist-6JFNJPUU.js.map +0 -1
- package/dist/dist-B674PYKV.js.map +0 -1
- package/dist/dist-G7WQPZ3Y.js +0 -1287
- package/dist/dist-G7WQPZ3Y.js.map +0 -1
- package/dist/dist-H6JYGQM4.js.map +0 -1
- package/dist/dist-OTJZRQ3Q.js.map +0 -1
- package/dist/dist-QMOJM6DV.js.map +0 -1
- package/dist/dist-RDFBZ5O6.js.map +0 -1
- package/dist/dist-RMK3BS5M.js.map +0 -1
- package/dist/dist-VVXVP5EZ.js.map +0 -1
- package/dist/dist-YOVM5HEY.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../@emulators/slack/src/store.ts","../../@emulators/slack/src/helpers.ts","../../@emulators/slack/src/routes/auth.ts","../../@emulators/slack/src/routes/chat.ts","../../@emulators/slack/src/routes/conversations.ts","../../@emulators/slack/src/routes/users.ts","../../@emulators/slack/src/routes/reactions.ts","../../@emulators/slack/src/routes/team.ts","../../@emulators/slack/src/routes/oauth.ts","../../@emulators/core/src/store.ts","../../@emulators/core/src/http.ts","../../@emulators/core/src/webhooks.ts","../../@emulators/core/src/middleware/error-handler.ts","../../@emulators/core/src/middleware/auth.ts","../../@emulators/core/src/debug.ts","../../@emulators/core/src/fonts.ts","../../@emulators/core/src/server.ts","../../@emulators/core/src/middleware/pagination.ts","../../@emulators/core/src/ui.ts","../../@emulators/core/src/oauth-helpers.ts","../../@emulators/core/src/persistence.ts","../../@emulators/slack/src/routes/webhooks.ts","../../@emulators/slack/src/routes/files.ts","../../@emulators/slack/src/routes/pins.ts","../../@emulators/slack/src/routes/bookmarks.ts","../../@emulators/slack/src/routes/views.ts","../../@emulators/slack/src/routes/inspector.ts","../../@emulators/slack/src/index.ts"],"sourcesContent":["import { Store, type Collection } from \"@emulators/core\";\nimport type {\n SlackTeam,\n SlackUser,\n SlackChannel,\n SlackEphemeralMessage,\n SlackMessage,\n SlackScheduledMessage,\n SlackBot,\n SlackOAuthApp,\n SlackInstallation,\n SlackToken,\n SlackIncomingWebhook,\n SlackFile,\n SlackFileUploadSession,\n SlackPin,\n SlackBookmark,\n SlackView,\n SlackViewTrigger,\n} from \"./entities.js\";\n\nexport interface SlackStore {\n teams: Collection<SlackTeam>;\n users: Collection<SlackUser>;\n channels: Collection<SlackChannel>;\n messages: Collection<SlackMessage>;\n ephemeralMessages: Collection<SlackEphemeralMessage>;\n scheduledMessages: Collection<SlackScheduledMessage>;\n bots: Collection<SlackBot>;\n oauthApps: Collection<SlackOAuthApp>;\n installations: Collection<SlackInstallation>;\n tokens: Collection<SlackToken>;\n incomingWebhooks: Collection<SlackIncomingWebhook>;\n files: Collection<SlackFile>;\n fileUploadSessions: Collection<SlackFileUploadSession>;\n pins: Collection<SlackPin>;\n bookmarks: Collection<SlackBookmark>;\n views: Collection<SlackView>;\n viewTriggers: Collection<SlackViewTrigger>;\n}\n\nexport function getSlackStore(store: Store): SlackStore {\n return {\n teams: store.collection<SlackTeam>(\"slack.teams\", [\"team_id\"]),\n users: store.collection<SlackUser>(\"slack.users\", [\"user_id\", \"email\"]),\n channels: store.collection<SlackChannel>(\"slack.channels\", [\"channel_id\", \"name\"]),\n messages: store.collection<SlackMessage>(\"slack.messages\", [\"ts\", \"channel_id\"]),\n ephemeralMessages: store.collection<SlackEphemeralMessage>(\"slack.ephemeral_messages\", [\n \"ts\",\n \"channel_id\",\n \"target_user\",\n ]),\n scheduledMessages: store.collection<SlackScheduledMessage>(\"slack.scheduled_messages\", [\n \"scheduled_message_id\",\n \"channel_id\",\n ]),\n bots: store.collection<SlackBot>(\"slack.bots\", [\"bot_id\"]),\n oauthApps: store.collection<SlackOAuthApp>(\"slack.oauth_apps\", [\"client_id\"]),\n installations: store.collection<SlackInstallation>(\"slack.installations\", [\n \"installation_id\",\n \"app_id\",\n \"client_id\",\n \"team_id\",\n ]),\n tokens: store.collection<SlackToken>(\"slack.tokens\", [\"token\", \"user_id\", \"app_id\", \"team_id\"]),\n incomingWebhooks: store.collection<SlackIncomingWebhook>(\"slack.incoming_webhooks\", [\"token\"]),\n files: store.collection<SlackFile>(\"slack.files\", [\"file_id\", \"user\"]),\n fileUploadSessions: store.collection<SlackFileUploadSession>(\"slack.file_upload_sessions\", [\"file_id\"]),\n pins: store.collection<SlackPin>(\"slack.pins\", [\"pin_id\", \"channel_id\", \"message_ts\"]),\n bookmarks: store.collection<SlackBookmark>(\"slack.bookmarks\", [\"bookmark_id\", \"channel_id\"]),\n views: store.collection<SlackView>(\"slack.views\", [\"view_id\", \"user_id\", \"external_id\", \"root_view_id\"]),\n viewTriggers: store.collection<SlackViewTrigger>(\"slack.view_triggers\", [\"trigger_id\", \"user_id\", \"view_id\"]),\n };\n}\n","import { randomBytes } from \"crypto\";\nimport type { Context } from \"@emulators/core\";\nimport type { ContentfulStatusCode } from \"@emulators/core\";\nimport type { Store } from \"@emulators/core\";\nimport type {\n SlackChannel,\n SlackFile,\n SlackJsonObject,\n SlackMessage,\n SlackScheduledMessage,\n SlackView,\n} from \"./entities.js\";\n\nexport type SlackScopeRequirement = string | string[];\n\nlet tsCounter = 0;\n\nexport type SlackRichMessageFieldName =\n | \"blocks\"\n | \"attachments\"\n | \"metadata\"\n | \"mrkdwn\"\n | \"parse\"\n | \"link_names\"\n | \"unfurl_links\"\n | \"unfurl_media\"\n | \"username\"\n | \"icon_url\"\n | \"icon_emoji\"\n | \"bot_id\"\n | \"app_id\"\n | \"client_msg_id\"\n | \"reply_broadcast\";\n\nexport type SlackRichMessageFields = Partial<Pick<SlackMessage, SlackRichMessageFieldName>>;\n\nexport interface SlackRichMessageParseResult {\n fields: SlackRichMessageFields;\n providedFields: SlackRichMessageFieldName[];\n error?: string;\n}\n\ninterface ParsedField<T> {\n value?: T;\n error?: string;\n}\n\nexport function generateSlackId(prefix: string): string {\n return prefix + randomBytes(5).toString(\"hex\").toUpperCase().slice(0, 9);\n}\n\nexport function generateTs(): string {\n const now = Math.floor(Date.now() / 1000);\n tsCounter++;\n return `${now}.${String(tsCounter).padStart(6, \"0\")}`;\n}\n\nexport function slackOk<T extends Record<string, unknown>>(c: Context, data: T) {\n return c.json({ ok: true, ...data });\n}\n\nexport function slackError(c: Context, error: string, status: ContentfulStatusCode = 200) {\n return c.json({ ok: false, error }, status);\n}\n\nexport function isSlackStrictScopes(store: Store): boolean {\n return store.getData<boolean>(\"slack.strict_scopes\") === true;\n}\n\nexport function requireSlackScopes(c: Context, store: Store, requirements: SlackScopeRequirement[]) {\n if (!isSlackStrictScopes(store)) return undefined;\n\n const provided = slackProvidedScopes(c);\n const providedSet = new Set(provided);\n const missing = requirements.filter((requirement) => {\n if (Array.isArray(requirement)) {\n return !requirement.some((scope) => providedSet.has(scope));\n }\n return !providedSet.has(requirement);\n });\n\n if (missing.length === 0) return undefined;\n\n return c.json({\n ok: false,\n error: \"missing_scope\",\n needed: missing.map((requirement) => (Array.isArray(requirement) ? requirement.join(\"|\") : requirement)).join(\",\"),\n provided: provided.join(\",\"),\n });\n}\n\nexport function hasSlackScope(c: Context, scope: string): boolean {\n return slackProvidedScopes(c).includes(scope);\n}\n\nfunction slackProvidedScopes(c: Context): string[] {\n return c.get(\"authScopes\") ?? c.get(\"authUser\")?.scopes ?? [];\n}\n\nexport function slackConversationReadScope(ch: SlackChannel): string {\n if (ch.is_im) return \"im:read\";\n if (ch.is_mpim) return \"mpim:read\";\n if (ch.is_private) return \"groups:read\";\n return \"channels:read\";\n}\n\nexport function slackConversationHistoryScope(ch: SlackChannel): string {\n if (ch.is_im) return \"im:history\";\n if (ch.is_mpim) return \"mpim:history\";\n if (ch.is_private) return \"groups:history\";\n return \"channels:history\";\n}\n\nexport function slackConversationWriteScope(ch: SlackChannel): SlackScopeRequirement {\n if (ch.is_im) return \"im:write\";\n if (ch.is_mpim) return \"mpim:write\";\n if (ch.is_private) return \"groups:write\";\n return [\"channels:manage\", \"channels:write\"];\n}\n\nexport function slackConversationJoinScope(ch: SlackChannel): SlackScopeRequirement {\n if (ch.is_private) return \"groups:write\";\n return [\"channels:join\", \"channels:write\"];\n}\n\nexport async function parseSlackBody(c: Context): Promise<Record<string, unknown>> {\n const contentType = c.req.header(\"Content-Type\") ?? \"\";\n const rawText = await c.req.text();\n\n if (contentType.includes(\"application/json\")) {\n try {\n const parsed = JSON.parse(rawText) as unknown;\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n // Slack SDKs send application/x-www-form-urlencoded by default\n const params = new URLSearchParams(rawText);\n const result: Record<string, unknown> = {};\n for (const [key, value] of params) {\n result[key] = value;\n }\n return result;\n}\n\nexport function formatSlackMessage(msg: SlackMessage) {\n return {\n type: msg.type,\n user: msg.user,\n text: msg.text,\n ts: msg.ts,\n ...(msg.subtype ? { subtype: msg.subtype } : {}),\n ...(msg.bot_id ? { bot_id: msg.bot_id } : {}),\n ...(msg.app_id ? { app_id: msg.app_id } : {}),\n ...(msg.username ? { username: msg.username } : {}),\n ...(msg.icon_url ? { icon_url: msg.icon_url } : {}),\n ...(msg.icon_emoji ? { icon_emoji: msg.icon_emoji } : {}),\n ...(msg.client_msg_id ? { client_msg_id: msg.client_msg_id } : {}),\n ...(msg.topic !== undefined ? { topic: msg.topic } : {}),\n ...(msg.purpose !== undefined ? { purpose: msg.purpose } : {}),\n ...(msg.old_name !== undefined ? { old_name: msg.old_name } : {}),\n ...(msg.name !== undefined ? { name: msg.name } : {}),\n ...(msg.files !== undefined ? { files: msg.files.map(formatSlackFile) } : {}),\n ...(msg.upload !== undefined ? { upload: msg.upload } : {}),\n ...(msg.blocks !== undefined ? { blocks: msg.blocks } : {}),\n ...(msg.attachments !== undefined ? { attachments: msg.attachments } : {}),\n ...(msg.metadata !== undefined ? { metadata: msg.metadata } : {}),\n ...(msg.mrkdwn !== undefined ? { mrkdwn: msg.mrkdwn } : {}),\n ...(msg.parse !== undefined ? { parse: msg.parse } : {}),\n ...(msg.link_names !== undefined ? { link_names: msg.link_names } : {}),\n ...(msg.unfurl_links !== undefined ? { unfurl_links: msg.unfurl_links } : {}),\n ...(msg.unfurl_media !== undefined ? { unfurl_media: msg.unfurl_media } : {}),\n ...(msg.reply_broadcast !== undefined ? { reply_broadcast: msg.reply_broadcast } : {}),\n ...(msg.edited ? { edited: msg.edited } : {}),\n ...(msg.thread_ts ? { thread_ts: msg.thread_ts } : {}),\n ...(msg.reply_count > 0 ? { reply_count: msg.reply_count, reply_users: msg.reply_users } : {}),\n ...(msg.reactions.length > 0 ? { reactions: msg.reactions } : {}),\n };\n}\n\nexport function formatSlackFile(file: SlackFile) {\n return {\n id: file.file_id,\n created: file.created,\n timestamp: file.timestamp,\n name: file.name,\n title: file.title,\n mimetype: file.mimetype,\n filetype: file.filetype,\n pretty_type: file.pretty_type,\n user: file.user,\n user_team: file.team_id,\n editable: file.editable,\n size: file.size,\n mode: file.mode,\n is_external: file.is_external,\n external_type: file.external_type,\n is_public: file.is_public,\n public_url_shared: file.public_url_shared,\n display_as_bot: file.display_as_bot,\n url_private: file.url_private,\n url_private_download: file.url_private_download,\n permalink: file.permalink,\n channels: file.channels,\n groups: file.groups,\n ims: file.ims,\n shares: file.shares,\n comments_count: 0,\n is_starred: false,\n has_rich_preview: false,\n ...(file.alt_txt ? { alt_txt: file.alt_txt } : {}),\n ...(file.initial_comment ? { initial_comment: file.initial_comment } : {}),\n ...(file.thread_ts ? { thread_ts: file.thread_ts } : {}),\n };\n}\n\nexport function formatSlackPermalink(baseUrl: string, channel: string, msg: SlackMessage): string {\n const permalink = `${baseUrl.replace(/\\/$/, \"\")}/archives/${channel}/p${msg.ts.replace(\".\", \"\")}`;\n if (!msg.thread_ts || msg.thread_ts === msg.ts) return permalink;\n\n const params = new URLSearchParams({ thread_ts: msg.thread_ts, cid: channel });\n return `${permalink}?${params.toString()}`;\n}\n\nexport function formatSlackScheduledMessage(msg: SlackScheduledMessage) {\n return {\n text: msg.text,\n type: msg.type,\n subtype: msg.subtype,\n ...(msg.username ? { username: msg.username } : {}),\n ...(msg.bot_id ? { bot_id: msg.bot_id } : {}),\n ...(msg.app_id ? { app_id: msg.app_id } : {}),\n ...(msg.icon_url ? { icon_url: msg.icon_url } : {}),\n ...(msg.icon_emoji ? { icon_emoji: msg.icon_emoji } : {}),\n ...(msg.client_msg_id ? { client_msg_id: msg.client_msg_id } : {}),\n ...(msg.blocks !== undefined ? { blocks: msg.blocks } : {}),\n ...(msg.attachments !== undefined ? { attachments: msg.attachments } : {}),\n ...(msg.metadata !== undefined ? { metadata: msg.metadata } : {}),\n ...(msg.mrkdwn !== undefined ? { mrkdwn: msg.mrkdwn } : {}),\n ...(msg.parse !== undefined ? { parse: msg.parse } : {}),\n ...(msg.link_names !== undefined ? { link_names: msg.link_names } : {}),\n ...(msg.unfurl_links !== undefined ? { unfurl_links: msg.unfurl_links } : {}),\n ...(msg.unfurl_media !== undefined ? { unfurl_media: msg.unfurl_media } : {}),\n ...(msg.reply_broadcast !== undefined ? { reply_broadcast: msg.reply_broadcast } : {}),\n ...(msg.thread_ts ? { thread_ts: msg.thread_ts } : {}),\n };\n}\n\nexport function formatSlackScheduledMessageListItem(msg: SlackScheduledMessage) {\n return {\n id: msg.scheduled_message_id,\n channel_id: msg.channel_id,\n post_at: msg.post_at,\n date_created: msg.date_created,\n text: msg.text,\n };\n}\n\nexport function formatSlackView(view: SlackView) {\n return {\n id: view.view_id,\n team_id: view.team_id,\n type: view.type,\n title: view.title,\n close: view.close,\n submit: view.submit,\n blocks: view.blocks,\n private_metadata: view.private_metadata,\n callback_id: view.callback_id,\n external_id: view.external_id,\n state: view.state,\n hash: view.hash,\n clear_on_close: view.clear_on_close,\n notify_on_close: view.notify_on_close,\n root_view_id: view.root_view_id,\n previous_view_id: view.previous_view_id ?? null,\n app_id: view.app_id,\n bot_id: view.bot_id,\n };\n}\n\nexport function getSlackConversationOpenState(ch: SlackChannel, userId?: string): boolean {\n if ((ch.is_im || ch.is_mpim) && userId && ch.is_open_by_user) {\n return ch.is_open_by_user[userId] === true;\n }\n return ch.is_open ?? false;\n}\n\nexport function setSlackConversationOpenState(\n ch: SlackChannel,\n userId: string,\n isOpen: boolean,\n): Partial<SlackChannel> {\n if (!ch.is_im && !ch.is_mpim) return { is_open: isOpen };\n return { is_open_by_user: { ...(ch.is_open_by_user ?? {}), [userId]: isOpen } };\n}\n\nexport function parseSlackRichMessageFields(body: Record<string, unknown>): SlackRichMessageParseResult {\n const fields: SlackRichMessageFields = {};\n const providedFields: SlackRichMessageFieldName[] = [];\n\n const blocks = parseSlackObjectArray(body.blocks, \"invalid_blocks\");\n if (blocks.error) return { fields, providedFields, error: blocks.error };\n if (hasBodyField(body, \"blocks\")) {\n providedFields.push(\"blocks\");\n if (blocks.value !== undefined) fields.blocks = blocks.value;\n }\n\n const attachments = parseSlackObjectArray(body.attachments, \"invalid_attachments\");\n if (attachments.error) return { fields, providedFields, error: attachments.error };\n if (hasBodyField(body, \"attachments\")) {\n providedFields.push(\"attachments\");\n if (attachments.value !== undefined) fields.attachments = attachments.value;\n }\n\n const metadata = parseSlackObject(body.metadata, \"invalid_metadata_format\");\n if (metadata.error) return { fields, providedFields, error: metadata.error };\n if (hasBodyField(body, \"metadata\")) {\n providedFields.push(\"metadata\");\n if (metadata.value !== undefined) fields.metadata = metadata.value;\n }\n\n setOptionalStringField(body, fields, providedFields, \"parse\");\n setOptionalStringField(body, fields, providedFields, \"username\");\n setOptionalStringField(body, fields, providedFields, \"icon_url\");\n setOptionalStringField(body, fields, providedFields, \"icon_emoji\");\n setOptionalStringField(body, fields, providedFields, \"bot_id\");\n setOptionalStringField(body, fields, providedFields, \"app_id\");\n setOptionalStringField(body, fields, providedFields, \"client_msg_id\");\n\n setOptionalBooleanField(body, fields, providedFields, \"mrkdwn\");\n setOptionalBooleanField(body, fields, providedFields, \"link_names\");\n setOptionalBooleanField(body, fields, providedFields, \"unfurl_links\");\n setOptionalBooleanField(body, fields, providedFields, \"unfurl_media\");\n setOptionalBooleanField(body, fields, providedFields, \"reply_broadcast\");\n\n return { fields, providedFields };\n}\n\nexport function hasSlackMessageContent(text: string, fields: SlackRichMessageFields): boolean {\n return text.length > 0 || (fields.blocks?.length ?? 0) > 0 || (fields.attachments?.length ?? 0) > 0;\n}\n\nexport function resetTsCounter(): void {\n tsCounter = 0;\n}\n\nfunction hasBodyField(body: Record<string, unknown>, field: string): boolean {\n return Object.prototype.hasOwnProperty.call(body, field);\n}\n\nfunction isSlackJsonObject(value: unknown): value is SlackJsonObject {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction parseSlackJsonString(value: string): ParsedField<unknown> {\n if (value.length === 0) return {};\n try {\n return { value: JSON.parse(value) as unknown };\n } catch {\n return { error: \"invalid_json\" };\n }\n}\n\nfunction parseSlackObjectArray(value: unknown, error: string): ParsedField<SlackJsonObject[]> {\n let parsed = value;\n if (parsed === undefined || parsed === null || parsed === \"\") return {};\n if (typeof parsed === \"string\") {\n const result = parseSlackJsonString(parsed);\n if (result.error) return { error };\n parsed = result.value;\n }\n\n if (!Array.isArray(parsed) || !parsed.every(isSlackJsonObject)) {\n return { error };\n }\n return { value: parsed };\n}\n\nfunction parseSlackObject(value: unknown, error: string): ParsedField<SlackJsonObject> {\n let parsed = value;\n if (parsed === undefined || parsed === null || parsed === \"\") return {};\n if (typeof parsed === \"string\") {\n const result = parseSlackJsonString(parsed);\n if (result.error) return { error };\n parsed = result.value;\n }\n\n if (!isSlackJsonObject(parsed)) {\n return { error };\n }\n return { value: parsed };\n}\n\nfunction parseSlackBoolean(value: unknown): boolean | undefined {\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"number\") {\n if (value === 1) return true;\n if (value === 0) return false;\n }\n if (typeof value === \"string\") {\n const normalized = value.toLowerCase();\n if (normalized === \"true\" || normalized === \"1\") return true;\n if (normalized === \"false\" || normalized === \"0\") return false;\n }\n return undefined;\n}\n\nfunction setOptionalStringField<K extends Extract<SlackRichMessageFieldName, keyof SlackRichMessageFields>>(\n body: Record<string, unknown>,\n fields: SlackRichMessageFields,\n providedFields: SlackRichMessageFieldName[],\n field: K,\n): void {\n if (!hasBodyField(body, field)) return;\n providedFields.push(field);\n const value = body[field];\n if (typeof value === \"string\" && value.length > 0) {\n fields[field] = value as SlackRichMessageFields[K];\n }\n}\n\nfunction setOptionalBooleanField<K extends Extract<SlackRichMessageFieldName, keyof SlackRichMessageFields>>(\n body: Record<string, unknown>,\n fields: SlackRichMessageFields,\n providedFields: SlackRichMessageFieldName[],\n field: K,\n): void {\n if (!hasBodyField(body, field)) return;\n providedFields.push(field);\n const value = parseSlackBoolean(body[field]);\n if (value !== undefined) {\n fields[field] = value as SlackRichMessageFields[K];\n }\n}\n","import type { RouteContext } from \"@emulators/core\";\nimport { getSlackStore } from \"../store.js\";\nimport { slackOk, slackError } from \"../helpers.js\";\n\nexport function authRoutes(ctx: RouteContext): void {\n const { app, store } = ctx;\n const ss = () => getSlackStore(store);\n\n // auth.test - verify token, return user/team info\n app.post(\"/api/auth.test\", (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) {\n return slackError(c, \"not_authed\");\n }\n\n // Look up by user_id first, then fall back to name (for token-based auth\n // where the token login may be the username rather than the user_id)\n const user =\n ss().users.findOneBy(\"user_id\", authUser.login) ??\n ss()\n .users.all()\n .find((u) => u.name === authUser.login);\n if (!user) {\n return slackError(c, \"invalid_auth\");\n }\n\n const team = ss().teams.all()[0];\n const token = c.get(\"authToken\");\n const tokenRecord = token ? ss().tokens.findOneBy(\"token\", token) : undefined;\n const bot =\n (tokenRecord?.bot_id ? ss().bots.findOneBy(\"bot_id\", tokenRecord.bot_id) : undefined) ??\n (user.is_bot\n ? ss()\n .bots.all()\n .find((item) => item.user_id === user.user_id)\n : undefined);\n const installation = tokenRecord?.installation_id\n ? ss().installations.findOneBy(\"installation_id\", tokenRecord.installation_id)\n : undefined;\n\n return slackOk(c, {\n url: `https://${team?.domain ?? \"emulate\"}.slack.com/`,\n team: team?.name ?? \"Emulate\",\n user: user.name,\n team_id: team?.team_id ?? \"T000000001\",\n user_id: user.user_id,\n bot_id: bot?.bot_id,\n app_id: tokenRecord?.app_id,\n app_name: installation?.app_name,\n });\n });\n}\n","import type { Context, RouteContext } from \"@emulators/core\";\nimport type { SlackChannel, SlackMessage, SlackUser } from \"../entities.js\";\nimport { getSlackStore } from \"../store.js\";\nimport {\n formatSlackMessage,\n formatSlackPermalink,\n formatSlackScheduledMessage,\n formatSlackScheduledMessageListItem,\n generateSlackId,\n generateTs,\n getSlackConversationOpenState,\n hasSlackMessageContent,\n parseSlackBody,\n parseSlackRichMessageFields,\n requireSlackScopes,\n setSlackConversationOpenState,\n slackError,\n slackOk,\n} from \"../helpers.js\";\n\nexport function chatRoutes(ctx: RouteContext): void {\n const { app, store, webhooks, baseUrl } = ctx;\n const ss = () => getSlackStore(store);\n const findChannel = (channel: string) =>\n ss().channels.findOneBy(\"channel_id\", channel) ??\n ss()\n .channels.all()\n .find((ch) => !ch.is_im && !ch.is_mpim && ch.name === channel);\n const getAuthSlackUser = (authUser: { login: string }) =>\n ss().users.findOneBy(\"user_id\", authUser.login) ?? ss().users.findOneBy(\"name\", authUser.login);\n const getAuthUserId = (authUser: { login: string }) => getAuthSlackUser(authUser)?.user_id ?? authUser.login;\n const isAuthChannelMember = (channel: SlackChannel, authUser: { login: string }) => {\n const user = getAuthSlackUser(authUser);\n const userId = user?.user_id ?? authUser.login;\n return channel.members.includes(userId) || (user ? channel.members.includes(user.name) : false);\n };\n const canAccessConversation = (channel: SlackChannel, authUser: { login: string }) =>\n !channel.is_private || isAuthChannelMember(channel, authUser);\n const isAuthoredByUser = (msg: { user: string }, authUser: { login: string }) => {\n const user = getAuthSlackUser(authUser);\n return msg.user === authUser.login || msg.user === user?.user_id || msg.user === user?.name;\n };\n const isChannelMember = (channel: SlackChannel, user: SlackUser) =>\n channel.members.includes(user.user_id) || channel.members.includes(user.name);\n const deletePinsForMessage = (channel: string, ts: string) => {\n for (const pin of ss()\n .pins.findBy(\"message_ts\", ts)\n .filter((pin) => pin.channel_id === channel)) {\n ss().pins.delete(pin.id);\n }\n };\n const dispatchConversationEvent = async (type: string, event: Record<string, unknown>) => {\n await webhooks.dispatch(\n type,\n undefined,\n {\n type: \"event_callback\",\n event: { type, ...event },\n },\n \"slack\",\n );\n };\n const findOrCreateDirectMessage = async (authUser: { login: string }, userId: string) => {\n const targetUser = ss().users.findOneBy(\"user_id\", userId);\n if (!targetUser || targetUser.deleted) return undefined;\n\n const authUserId = getAuthUserId(authUser);\n if (targetUser.user_id === authUserId) return undefined;\n\n const members = [authUserId, targetUser.user_id].sort();\n const existing = ss()\n .channels.all()\n .find(\n (ch) =>\n ch.is_im && ch.members.length === members.length && [...ch.members].sort().join(\",\") === members.join(\",\"),\n );\n if (existing) {\n if (!getSlackConversationOpenState(existing, authUserId)) {\n const updated = ss().channels.update(existing.id, setSlackConversationOpenState(existing, authUserId, true));\n if (updated) await dispatchConversationEvent(\"im_open\", { channel: updated.channel_id });\n return updated;\n }\n return existing;\n }\n\n const team = ss().teams.all()[0];\n const now = Math.floor(Date.now() / 1000);\n const created = ss().channels.insert({\n channel_id: generateSlackId(\"D\"),\n team_id: team?.team_id ?? \"T000000001\",\n name: targetUser.name,\n is_channel: false,\n is_private: true,\n is_im: true,\n is_mpim: false,\n is_open_by_user: { [authUserId]: true },\n user: targetUser.user_id,\n is_archived: false,\n topic: { value: \"\", creator: authUserId, last_set: now },\n purpose: { value: \"\", creator: authUserId, last_set: now },\n members,\n creator: authUserId,\n num_members: members.length,\n last_read: {},\n });\n await dispatchConversationEvent(\"im_created\", {\n channel: formatDirectMessageChannel(created, authUserId, targetUser.user_id),\n });\n await dispatchConversationEvent(\"im_open\", { channel: created.channel_id });\n return created;\n };\n const findWritableConversation = async (authUser: { login: string }, channel: string) =>\n findChannel(channel) ?? (await findOrCreateDirectMessage(authUser, channel));\n\n // chat.postMessage\n app.post(\"/api/chat.postMessage\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"chat:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const text = typeof body.text === \"string\" ? body.text : \"\";\n const thread_ts = typeof body.thread_ts === \"string\" ? body.thread_ts : undefined;\n const richMessage = parseSlackRichMessageFields(body);\n if (richMessage.error) return slackError(c, richMessage.error);\n\n if (!channel) return slackError(c, \"channel_not_found\");\n if (!hasSlackMessageContent(text, richMessage.fields)) return slackError(c, \"no_text\");\n\n const ch = await findWritableConversation(authUser, channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n if (ch.is_archived) return slackError(c, \"is_archived\");\n if (!canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n const authUserId = getAuthUserId(authUser);\n\n const ts = generateTs();\n const msg = ss().messages.insert({\n ts,\n channel_id: ch.channel_id,\n user: authUserId,\n text,\n type: \"message\" as const,\n thread_ts,\n ...richMessage.fields,\n reply_count: 0,\n reply_users: [],\n reactions: [],\n });\n\n // Update parent thread reply count\n if (thread_ts) {\n const parent = ss()\n .messages.all()\n .find((m) => m.ts === thread_ts && m.channel_id === ch.channel_id);\n if (parent) {\n const replyUsers = parent.reply_users.includes(authUserId)\n ? parent.reply_users\n : [...parent.reply_users, authUserId];\n ss().messages.update(parent.id, {\n reply_count: parent.reply_count + 1,\n reply_users: replyUsers,\n });\n }\n }\n\n await webhooks.dispatch(\n \"message\",\n undefined,\n {\n type: \"event_callback\",\n event: {\n ...formatSlackMessage(msg),\n type: \"message\",\n channel: ch.channel_id,\n },\n },\n \"slack\",\n );\n\n return slackOk(c, {\n channel: ch.channel_id,\n ts,\n message: formatSlackMessage(msg),\n });\n });\n\n // chat.postEphemeral\n app.post(\"/api/chat.postEphemeral\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"chat:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const user = typeof body.user === \"string\" ? body.user : \"\";\n const text = typeof body.text === \"string\" ? body.text : \"\";\n const thread_ts = typeof body.thread_ts === \"string\" ? body.thread_ts : undefined;\n const richMessage = parseSlackRichMessageFields(body);\n if (richMessage.error) return slackError(c, richMessage.error);\n\n if (!channel) return slackError(c, \"channel_not_found\");\n if (!user) return slackError(c, \"user_not_found\");\n if (!hasSlackMessageContent(text, richMessage.fields)) return slackError(c, \"no_text\");\n\n const ch = findChannel(channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n if (ch.is_archived) return slackError(c, \"is_archived\");\n if (!canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n\n const targetUser = ss().users.findOneBy(\"user_id\", user);\n if (!targetUser) return slackError(c, \"user_not_found\");\n if (!isChannelMember(ch, targetUser)) return slackError(c, \"user_not_in_channel\");\n const authUserId = getAuthUserId(authUser);\n\n const ts = generateTs();\n ss().ephemeralMessages.insert({\n ts,\n channel_id: ch.channel_id,\n user: authUserId,\n target_user: targetUser.user_id,\n text,\n type: \"message\" as const,\n thread_ts,\n ...richMessage.fields,\n reply_count: 0,\n reply_users: [],\n reactions: [],\n });\n\n return slackOk(c, { message_ts: ts });\n });\n\n // chat.update\n app.post(\"/api/chat.update\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"chat:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const ts = typeof body.ts === \"string\" ? body.ts : \"\";\n const hasText = typeof body.text === \"string\";\n const text = hasText ? (body.text as string) : \"\";\n const richMessage = parseSlackRichMessageFields(body);\n if (richMessage.error) return slackError(c, richMessage.error);\n\n if (!channel || !ts) return slackError(c, \"message_not_found\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (ch && !canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n\n const msg = ss()\n .messages.all()\n .find((m) => m.ts === ts && m.channel_id === channel);\n if (!msg) return slackError(c, \"message_not_found\");\n if (!isAuthoredByUser(msg, authUser)) return slackError(c, \"cant_update_message\");\n\n const updates: Partial<SlackMessage> = { ...richMessage.fields };\n if (hasText) {\n updates.text = text;\n if (!richMessage.providedFields.includes(\"blocks\")) updates.blocks = undefined;\n if (!richMessage.providedFields.includes(\"attachments\")) updates.attachments = undefined;\n }\n\n if (!hasText && Object.keys(updates).length === 0) {\n return slackError(c, \"no_text\");\n }\n\n const authUserId = getAuthUserId(authUser);\n const eventTs = generateTs();\n const updated = ss().messages.update(msg.id, {\n ...updates,\n edited: { user: authUserId, ts: eventTs },\n })!;\n\n await webhooks.dispatch(\n \"message\",\n undefined,\n {\n type: \"event_callback\",\n event: {\n type: \"message\",\n subtype: \"message_changed\",\n hidden: true,\n channel,\n ts: eventTs,\n event_ts: eventTs,\n message: formatSlackMessage(updated),\n previous_message: formatSlackMessage(msg),\n },\n },\n \"slack\",\n );\n\n return slackOk(c, {\n channel,\n ts,\n text: updated.text,\n message: formatSlackMessage(updated),\n });\n });\n\n // chat.delete\n app.post(\"/api/chat.delete\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"chat:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const ts = typeof body.ts === \"string\" ? body.ts : \"\";\n\n if (!channel || !ts) return slackError(c, \"message_not_found\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (ch && !canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n\n const msg = ss()\n .messages.all()\n .find((m) => m.ts === ts && m.channel_id === channel);\n if (!msg) return slackError(c, \"message_not_found\");\n if (!isAuthoredByUser(msg, authUser)) return slackError(c, \"cant_delete_message\");\n\n ss().messages.delete(msg.id);\n deletePinsForMessage(channel, ts);\n\n const eventTs = generateTs();\n await webhooks.dispatch(\n \"message\",\n undefined,\n {\n type: \"event_callback\",\n event: {\n type: \"message\",\n subtype: \"message_deleted\",\n hidden: true,\n channel,\n ts: eventTs,\n event_ts: eventTs,\n deleted_ts: ts,\n previous_message: formatSlackMessage(msg),\n },\n },\n \"slack\",\n );\n\n return slackOk(c, { channel, ts });\n });\n\n async function getPermalink(c: Context) {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = c.req.method === \"GET\" ? {} : await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : (c.req.query(\"channel\") ?? \"\");\n const messageTs = typeof body.message_ts === \"string\" ? body.message_ts : (c.req.query(\"message_ts\") ?? \"\");\n\n if (!channel) return slackError(c, \"channel_not_found\");\n if (!messageTs) return slackError(c, \"message_not_found\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n if (!canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n\n const msg = ss()\n .messages.all()\n .find((m) => m.ts === messageTs && m.channel_id === channel);\n if (!msg) return slackError(c, \"message_not_found\");\n\n return slackOk(c, {\n channel,\n permalink: formatSlackPermalink(baseUrl, ch.channel_id, msg),\n });\n }\n\n // chat.getPermalink\n app.get(\"/api/chat.getPermalink\", getPermalink);\n app.post(\"/api/chat.getPermalink\", getPermalink);\n\n // chat.scheduleMessage\n app.post(\"/api/chat.scheduleMessage\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"chat:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const text = typeof body.text === \"string\" ? body.text : \"\";\n const postAt = Number(body.post_at);\n const thread_ts = typeof body.thread_ts === \"string\" ? body.thread_ts : undefined;\n const richMessage = parseSlackRichMessageFields(body);\n if (richMessage.error) return slackError(c, richMessage.error);\n\n if (!channel) return slackError(c, \"channel_not_found\");\n if (!hasSlackMessageContent(text, richMessage.fields)) return slackError(c, \"no_text\");\n if (!Number.isFinite(postAt) || postAt <= 0) return slackError(c, \"invalid_time\");\n\n const now = Math.floor(Date.now() / 1000);\n const postAtSeconds = Math.floor(postAt);\n if (postAtSeconds <= now) return slackError(c, \"time_in_past\");\n if (postAtSeconds > now + 120 * 24 * 60 * 60) return slackError(c, \"time_too_far\");\n\n const ch = findChannel(channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n if (ch.is_archived) return slackError(c, \"is_archived\");\n if (!canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n const authUserId = getAuthUserId(authUser);\n\n const scheduled = ss().scheduledMessages.insert({\n scheduled_message_id: generateSlackId(\"Q\"),\n channel_id: ch.channel_id,\n user: authUserId,\n text,\n type: \"delayed_message\" as const,\n subtype: \"bot_message\" as const,\n thread_ts,\n ...richMessage.fields,\n post_at: postAtSeconds,\n date_created: now,\n });\n\n return slackOk(c, {\n channel: ch.channel_id,\n scheduled_message_id: scheduled.scheduled_message_id,\n post_at: scheduled.post_at,\n message: formatSlackScheduledMessage(scheduled),\n });\n });\n\n // chat.deleteScheduledMessage\n app.post(\"/api/chat.deleteScheduledMessage\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"chat:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const scheduledMessageId = typeof body.scheduled_message_id === \"string\" ? body.scheduled_message_id : \"\";\n\n if (!channel) return slackError(c, \"channel_not_found\");\n if (!scheduledMessageId) return slackError(c, \"invalid_scheduled_message_id\");\n\n const ch = findChannel(channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n if (!canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n\n const scheduled = ss()\n .scheduledMessages.all()\n .find((m) => m.channel_id === ch.channel_id && m.scheduled_message_id === scheduledMessageId);\n if (!scheduled) return slackError(c, \"invalid_scheduled_message_id\");\n if (!isAuthoredByUser(scheduled, authUser)) return slackError(c, \"cant_delete_message\");\n\n ss().scheduledMessages.delete(scheduled.id);\n return slackOk(c, {});\n });\n\n // chat.scheduledMessages.list\n app.post(\"/api/chat.scheduledMessages.list\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"chat:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const cursor = typeof body.cursor === \"string\" ? body.cursor : \"\";\n const requestedLimit = body.limit === undefined ? 100 : Number(body.limit);\n const oldest = body.oldest === undefined ? undefined : Number(body.oldest);\n const latest = body.latest === undefined ? undefined : Number(body.latest);\n\n if (!Number.isFinite(requestedLimit) || requestedLimit < 1) {\n return slackError(c, \"invalid_arguments\");\n }\n if ((oldest !== undefined && !Number.isFinite(oldest)) || (latest !== undefined && !Number.isFinite(latest))) {\n return slackError(c, \"invalid_arguments\");\n }\n if (oldest !== undefined && latest !== undefined && oldest > latest) {\n return slackError(c, \"invalid_arguments\");\n }\n const limit = Math.min(Math.floor(requestedLimit), 1000);\n\n const ch = channel ? findChannel(channel) : undefined;\n if (channel && !ch) return slackError(c, \"channel_not_found\");\n if (ch && !canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n\n const allScheduled = ss()\n .scheduledMessages.all()\n .filter((msg) => isAuthoredByUser(msg, authUser))\n .filter((msg) => !ch || msg.channel_id === ch.channel_id)\n .filter((msg) => {\n const messageChannel = ss().channels.findOneBy(\"channel_id\", msg.channel_id);\n return messageChannel ? canAccessConversation(messageChannel, authUser) : false;\n })\n .filter((msg) => oldest === undefined || msg.post_at >= oldest)\n .filter((msg) => latest === undefined || msg.post_at <= latest)\n .sort((a, b) => a.post_at - b.post_at || a.scheduled_message_id.localeCompare(b.scheduled_message_id));\n\n let startIndex = 0;\n if (cursor) {\n const idx = allScheduled.findIndex((msg) => msg.scheduled_message_id === cursor);\n if (idx < 0) return slackError(c, \"invalid_cursor\");\n if (idx >= 0) startIndex = idx;\n }\n\n const page = allScheduled.slice(startIndex, startIndex + limit);\n const nextCursor =\n startIndex + limit < allScheduled.length ? allScheduled[startIndex + limit].scheduled_message_id : \"\";\n\n return slackOk(c, {\n scheduled_messages: page.map(formatSlackScheduledMessageListItem),\n response_metadata: { next_cursor: nextCursor },\n });\n });\n\n // chat.meMessage\n app.post(\"/api/chat.meMessage\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"chat:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const text = typeof body.text === \"string\" ? body.text : \"\";\n\n if (!channel) return slackError(c, \"channel_not_found\");\n\n const ch = findChannel(channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n if (ch.is_archived) return slackError(c, \"is_archived\");\n if (!canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n const authUserId = getAuthUserId(authUser);\n\n const ts = generateTs();\n ss().messages.insert({\n ts,\n channel_id: ch.channel_id,\n user: authUserId,\n text,\n type: \"message\" as const,\n subtype: \"me_message\",\n reply_count: 0,\n reply_users: [],\n reactions: [],\n });\n\n return slackOk(c, { channel: ch.channel_id, ts });\n });\n}\n\nfunction formatDirectMessageChannel(ch: SlackChannel, viewer: string, user: string) {\n return {\n id: ch.channel_id,\n name: ch.name,\n name_normalized: ch.name,\n is_channel: ch.is_channel,\n is_group: false,\n is_im: true,\n is_mpim: false,\n is_private: ch.is_private,\n is_archived: ch.is_archived,\n is_open: getSlackConversationOpenState(ch, viewer),\n user,\n is_member: true,\n last_read: ch.last_read?.[viewer] ?? \"0000000000.000000\",\n topic: ch.topic,\n purpose: ch.purpose,\n creator: ch.creator,\n num_members: ch.num_members,\n created: Math.floor(new Date(ch.created_at).getTime() / 1000),\n };\n}\n","import type { RouteContext } from \"@emulators/core\";\nimport type { SlackChannel, SlackFile, SlackFileShare, SlackMessage, SlackUser } from \"../entities.js\";\nimport { getSlackStore } from \"../store.js\";\nimport {\n formatSlackMessage,\n generateSlackId,\n generateTs,\n getSlackConversationOpenState,\n parseSlackBody,\n requireSlackScopes,\n setSlackConversationOpenState,\n slackConversationHistoryScope,\n slackConversationJoinScope,\n slackConversationReadScope,\n slackConversationWriteScope,\n slackError,\n slackOk,\n} from \"../helpers.js\";\n\nexport function conversationsRoutes(ctx: RouteContext): void {\n const { app, store, webhooks } = ctx;\n const ss = () => getSlackStore(store);\n const getAuthSlackUser = (authUser: { login: string }) =>\n ss().users.findOneBy(\"user_id\", authUser.login) ?? ss().users.findOneBy(\"name\", authUser.login);\n const getAuthUserId = (authUser: { login: string }) => getAuthSlackUser(authUser)?.user_id ?? authUser.login;\n const memberAliases = (user: SlackUser | undefined, userId: string) =>\n new Set([userId, user?.name].filter((value): value is string => Boolean(value)));\n const getChannelMemberKey = (channel: SlackChannel, user: SlackUser | undefined, userId: string) => {\n const aliases = memberAliases(user, userId);\n return channel.members.find((member) => aliases.has(member));\n };\n const isChannelMember = (channel: SlackChannel, user: SlackUser | undefined, userId: string) =>\n getChannelMemberKey(channel, user, userId) !== undefined;\n const canReadConversation = (channel: SlackChannel, user: SlackUser | undefined, userId: string) =>\n !channel.is_private || isChannelMember(channel, user, userId);\n const visibleFileChannelIds = (file: SlackFile, authUser: { login: string }) => {\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = authSlackUser?.user_id ?? authUser.login;\n return fileChannels(file).filter((channelId) => {\n const channel = ss().channels.findOneBy(\"channel_id\", channelId);\n return channel ? canReadConversation(channel, authSlackUser, authUserId) : false;\n });\n };\n const visibleFileForAuth = (file: SlackFile, authUser: { login: string }): SlackFile => {\n const visibleIds = new Set(visibleFileChannelIds(file, authUser));\n const publicShares = filterVisibleShares(file.shares.public, visibleIds);\n const privateShares = filterVisibleShares(file.shares.private, visibleIds);\n const shares: SlackFile[\"shares\"] = {};\n if (publicShares) shares.public = publicShares;\n if (privateShares) shares.private = privateShares;\n\n return {\n ...file,\n channels: file.channels.filter((channelId) => visibleIds.has(channelId)),\n groups: file.groups.filter((channelId) => visibleIds.has(channelId)),\n ims: file.ims.filter((channelId) => visibleIds.has(channelId)),\n shares,\n };\n };\n const formatSlackMessageForAuth = (msg: SlackMessage, authUser: { login: string }) =>\n formatSlackMessage({\n ...msg,\n ...(msg.files\n ? {\n files: msg.files\n .map((file) => ss().files.findOneBy(\"file_id\", file.file_id) ?? file)\n .filter((file) => !file.deleted)\n .map((file) => visibleFileForAuth(file, authUser)),\n }\n : {}),\n });\n const dispatchConversationEvent = async (type: string, event: Record<string, unknown>) => {\n await webhooks.dispatch(\n type,\n undefined,\n {\n type: \"event_callback\",\n event: { type, ...event },\n },\n \"slack\",\n );\n };\n const insertAndDispatchMessageEvent = async (\n channel: SlackChannel,\n user: string,\n message: Pick<SlackMessage, \"subtype\" | \"text\"> &\n Partial<Pick<SlackMessage, \"topic\" | \"purpose\" | \"old_name\" | \"name\">>,\n ) => {\n const msg = ss().messages.insert({\n ts: generateTs(),\n channel_id: channel.channel_id,\n user,\n type: \"message\" as const,\n ...message,\n reply_count: 0,\n reply_users: [],\n reactions: [],\n });\n\n await webhooks.dispatch(\n \"message\",\n undefined,\n {\n type: \"event_callback\",\n event: {\n ...formatSlackMessage(msg),\n channel: channel.channel_id,\n event_ts: msg.ts,\n },\n },\n \"slack\",\n );\n return msg;\n };\n const dispatchMemberJoined = async (channel: SlackChannel, user: string, inviter?: string) => {\n await dispatchConversationEvent(\"member_joined_channel\", {\n user,\n channel: channel.channel_id,\n channel_type: channelTypeLetter(channel),\n team: channel.team_id,\n ...(inviter ? { inviter } : {}),\n });\n };\n const dispatchMemberLeft = async (channel: SlackChannel, user: string) => {\n await dispatchConversationEvent(\"member_left_channel\", {\n user,\n channel: channel.channel_id,\n channel_type: channelTypeLetter(channel),\n team: channel.team_id,\n });\n };\n\n // conversations.list\n app.post(\"/api/conversations.list\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const limit = Math.min(Number(body.limit) || 100, 1000);\n const cursor = typeof body.cursor === \"string\" ? body.cursor : \"\";\n const excludeArchived = isTruthySlackBoolean(body.exclude_archived);\n const types = parseConversationTypes(body.types);\n const scopeError = requireSlackScopes(c, store, readScopesForConversationTypes(types));\n if (scopeError) return scopeError;\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n\n const allChannels = ss()\n .channels.all()\n .filter((ch) => matchesConversationTypes(ch, types))\n .filter((ch) => canReadConversation(ch, authSlackUser, authUserId))\n .filter((ch) => !excludeArchived || !ch.is_archived);\n\n // Simple cursor pagination using channel id\n let startIndex = 0;\n if (cursor) {\n const idx = allChannels.findIndex((ch) => ch.channel_id === cursor);\n if (idx >= 0) startIndex = idx;\n }\n\n const page = allChannels.slice(startIndex, startIndex + limit);\n const nextCursor = startIndex + limit < allChannels.length ? allChannels[startIndex + limit].channel_id : \"\";\n\n return slackOk(c, {\n channels: page.map((ch) => formatChannel(ch, authUserId, authSlackUser?.name)),\n response_metadata: { next_cursor: nextCursor },\n });\n });\n\n // conversations.info\n app.post(\"/api/conversations.info\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationReadScope(ch)]);\n if (scopeError) return scopeError;\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!canReadConversation(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n return slackOk(c, { channel: formatChannel(ch, authUserId, authSlackUser?.name) });\n });\n\n // conversations.create\n app.post(\"/api/conversations.create\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const name = normalizeChannelName(typeof body.name === \"string\" ? body.name : \"\");\n const isPrivate = body.is_private === true || body.is_private === \"true\";\n const scopeError = requireSlackScopes(c, store, [\n isPrivate ? \"groups:write\" : [\"channels:manage\", \"channels:write\"],\n ]);\n if (scopeError) return scopeError;\n\n if (!name) return slackError(c, \"invalid_name_specials\");\n const nameError = validateChannelName(name);\n if (nameError) return slackError(c, nameError);\n\n const existing = findNamedChannel(ss().channels.all(), name);\n if (existing) return slackError(c, \"name_taken\");\n\n const team = ss().teams.all()[0];\n const channelId = generateSlackId(\"C\");\n const now = Math.floor(Date.now() / 1000);\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n\n const ch = ss().channels.insert({\n channel_id: channelId,\n team_id: team?.team_id ?? \"T000000001\",\n name,\n is_channel: !isPrivate,\n is_private: isPrivate,\n is_archived: false,\n topic: { value: \"\", creator: \"\", last_set: 0 },\n purpose: { value: \"\", creator: authUserId, last_set: now },\n members: [authUserId],\n creator: authUserId,\n num_members: 1,\n });\n\n return slackOk(c, { channel: formatChannel(ch, authUserId, authSlackUser?.name) });\n });\n\n // conversations.archive\n app.post(\"/api/conversations.archive\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n if (!channel) return slackError(c, \"channel_not_found\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(ch)]);\n if (scopeError) return scopeError;\n if (isDirectConversation(ch)) return slackError(c, \"method_not_supported_for_channel_type\");\n if (isGeneralChannel(ch)) return slackError(c, \"cant_archive_general\");\n if (ch.is_archived) return slackError(c, \"already_archived\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!isChannelMember(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const updated = ss().channels.update(ch.id, { is_archived: true })!;\n await dispatchConversationEvent(lifecycleEventType(updated, \"archive\"), {\n channel: updated.channel_id,\n user: authUserId,\n });\n await insertAndDispatchMessageEvent(updated, authUserId, {\n subtype: lifecycleEventType(updated, \"archive\"),\n text: `<@${authUserId}> archived the ${conversationNoun(updated)}`,\n });\n\n return slackOk(c, {});\n });\n\n // conversations.unarchive\n app.post(\"/api/conversations.unarchive\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n if (!channel) return slackError(c, \"channel_not_found\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(ch)]);\n if (scopeError) return scopeError;\n if (isDirectConversation(ch)) return slackError(c, \"method_not_supported_for_channel_type\");\n if (!ch.is_archived) return slackError(c, \"not_archived\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n const isMember = isChannelMember(ch, authSlackUser, authUserId);\n if (ch.is_private && !isMember) return slackError(c, \"not_in_channel\");\n\n const members = isMember ? ch.members : [...ch.members, authUserId];\n const updated = ss().channels.update(ch.id, {\n is_archived: false,\n members,\n num_members: members.length,\n })!;\n\n await dispatchConversationEvent(lifecycleEventType(updated, \"unarchive\"), {\n channel: updated.channel_id,\n user: authUserId,\n });\n await insertAndDispatchMessageEvent(updated, authUserId, {\n subtype: lifecycleEventType(updated, \"unarchive\"),\n text: `<@${authUserId}> unarchived the ${conversationNoun(updated)}`,\n });\n\n return slackOk(c, {});\n });\n\n // conversations.rename\n app.post(\"/api/conversations.rename\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const name = normalizeChannelName(typeof body.name === \"string\" ? body.name : \"\");\n if (!channel) return slackError(c, \"channel_not_found\");\n\n const nameError = validateChannelName(name);\n if (nameError) return slackError(c, nameError);\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(ch)]);\n if (scopeError) return scopeError;\n if (isDirectConversation(ch)) return slackError(c, \"method_not_supported_for_channel_type\");\n if (ch.is_archived) return slackError(c, \"is_archived\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!isChannelMember(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n if (ch.creator !== authUserId && ch.creator !== authUser.login && !authSlackUser?.is_admin) {\n return slackError(c, \"not_authorized\");\n }\n\n const existing = findNamedChannel(ss().channels.all(), name);\n if (existing && existing.id !== ch.id) return slackError(c, \"name_taken\");\n if (name === ch.name) return slackOk(c, { channel: formatChannel(ch, authUserId, authSlackUser?.name) });\n\n const oldName = ch.name;\n const updated = ss().channels.update(ch.id, { name })!;\n await dispatchConversationEvent(lifecycleEventType(updated, \"rename\"), {\n channel: {\n id: updated.channel_id,\n name: updated.name,\n created: createdSeconds(updated),\n },\n });\n await insertAndDispatchMessageEvent(updated, authUserId, {\n subtype: lifecycleMessageSubtype(updated, \"name\"),\n text: `<@${authUserId}> renamed the ${conversationNoun(updated)} from \"${oldName}\" to \"${updated.name}\"`,\n old_name: oldName,\n name: updated.name,\n });\n\n return slackOk(c, { channel: formatChannel(updated, authUserId, authSlackUser?.name) });\n });\n\n // conversations.setTopic\n app.post(\"/api/conversations.setTopic\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const topic = typeof body.topic === \"string\" ? body.topic : undefined;\n if (!channel) return slackError(c, \"channel_not_found\");\n if (topic === undefined) return slackError(c, \"invalid_arguments\");\n if (topic.length > 250) return slackError(c, \"too_long\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(ch)]);\n if (scopeError) return scopeError;\n if (isDirectConversation(ch)) return slackError(c, \"method_not_supported_for_channel_type\");\n if (ch.is_archived) return slackError(c, \"is_archived\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!isChannelMember(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const now = Math.floor(Date.now() / 1000);\n const updated = ss().channels.update(ch.id, {\n topic: { value: topic, creator: authUserId, last_set: now },\n })!;\n\n await insertAndDispatchMessageEvent(updated, authUserId, {\n subtype: lifecycleMessageSubtype(updated, \"topic\"),\n text: `<@${authUserId}> set the ${conversationNoun(updated)} topic: ${topic}`,\n topic,\n });\n\n return slackOk(c, { channel: formatChannel(updated, authUserId, authSlackUser?.name) });\n });\n\n // conversations.setPurpose\n app.post(\"/api/conversations.setPurpose\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const purpose = typeof body.purpose === \"string\" ? body.purpose : undefined;\n if (!channel) return slackError(c, \"channel_not_found\");\n if (purpose === undefined) return slackError(c, \"invalid_arguments\");\n if (purpose.length > 250) return slackError(c, \"too_long\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(ch)]);\n if (scopeError) return scopeError;\n if (isDirectConversation(ch)) return slackError(c, \"method_not_supported_for_channel_type\");\n if (ch.is_archived) return slackError(c, \"is_archived\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!isChannelMember(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const now = Math.floor(Date.now() / 1000);\n const updated = ss().channels.update(ch.id, {\n purpose: { value: purpose, creator: authUserId, last_set: now },\n })!;\n\n await insertAndDispatchMessageEvent(updated, authUserId, {\n subtype: lifecycleMessageSubtype(updated, \"purpose\"),\n text: `<@${authUserId}> set the ${conversationNoun(updated)} purpose: ${purpose}`,\n purpose,\n });\n\n return slackOk(c, { purpose, channel: formatChannel(updated, authUserId, authSlackUser?.name) });\n });\n\n // conversations.history\n app.post(\"/api/conversations.history\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const limit = Math.min(Number(body.limit) || 100, 1000);\n const cursor = typeof body.cursor === \"string\" ? body.cursor : \"\";\n\n if (!channel) return slackError(c, \"channel_not_found\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationHistoryScope(ch)]);\n if (scopeError) return scopeError;\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!canReadConversation(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n // Get top-level messages (no thread_ts or thread_ts === ts)\n const allMessages = ss()\n .messages.findBy(\"channel_id\", channel)\n .filter((m) => !m.thread_ts || m.thread_ts === m.ts)\n .sort((a, b) => (b.ts > a.ts ? 1 : -1));\n\n let startIndex = 0;\n if (cursor) {\n const idx = allMessages.findIndex((m) => m.ts === cursor);\n if (idx >= 0) startIndex = idx;\n }\n\n const page = allMessages.slice(startIndex, startIndex + limit);\n const hasMore = startIndex + limit < allMessages.length;\n const nextCursor = hasMore ? allMessages[startIndex + limit].ts : \"\";\n\n return slackOk(c, {\n messages: page.map((message) => formatSlackMessageForAuth(message, authUser)),\n has_more: hasMore,\n response_metadata: { next_cursor: nextCursor },\n });\n });\n\n // conversations.replies\n app.post(\"/api/conversations.replies\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const ts = typeof body.ts === \"string\" ? body.ts : \"\";\n\n if (!channel || !ts) return slackError(c, \"channel_not_found\");\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationHistoryScope(ch)]);\n if (scopeError) return scopeError;\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!canReadConversation(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const allMessages = ss()\n .messages.findBy(\"channel_id\", channel)\n .filter((m) => m.ts === ts || m.thread_ts === ts)\n .sort((a, b) => (a.ts > b.ts ? 1 : -1));\n\n return slackOk(c, {\n messages: allMessages.map((message) => formatSlackMessageForAuth(message, authUser)),\n has_more: false,\n });\n });\n\n // conversations.join\n app.post(\"/api/conversations.join\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationJoinScope(ch)]);\n if (scopeError) return scopeError;\n if (ch.is_archived) return slackError(c, \"is_archived\");\n if (ch.is_im || ch.is_mpim) return slackError(c, \"method_not_supported_for_channel_type\");\n\n const authUserId = getAuthUserId(authUser);\n const authSlackUser = getAuthSlackUser(authUser);\n if (ch.is_private && !isChannelMember(ch, authSlackUser, authUserId)) {\n return slackError(c, \"not_in_channel\");\n }\n\n const memberKey = getChannelMemberKey(ch, authSlackUser, authUserId);\n if (!memberKey) {\n const updated = ss().channels.update(ch.id, {\n members: [...ch.members, authUserId],\n num_members: ch.num_members + 1,\n })!;\n await dispatchMemberJoined(updated, authUserId);\n }\n\n const updated = ss().channels.findOneBy(\"channel_id\", channel)!;\n return slackOk(c, { channel: formatChannel(updated, authUserId, authSlackUser?.name) });\n });\n\n // conversations.leave\n app.post(\"/api/conversations.leave\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(ch)]);\n if (scopeError) return scopeError;\n if (ch.is_im) return slackError(c, \"method_not_supported_for_channel_type\");\n if (isGeneralChannel(ch)) return slackError(c, \"cant_leave_general\");\n\n const authUserId = getAuthUserId(authUser);\n const authSlackUser = getAuthSlackUser(authUser);\n const memberKey = getChannelMemberKey(ch, authSlackUser, authUserId);\n if (!memberKey) return c.json({ ok: false, not_in_channel: true });\n\n const aliases = memberAliases(authSlackUser, authUserId);\n const updatedMembers = ch.members.filter((m) => !aliases.has(m));\n if (updatedMembers.length === 0) return slackError(c, \"last_member\");\n\n const updated = ss().channels.update(ch.id, {\n members: updatedMembers,\n num_members: updatedMembers.length,\n })!;\n await dispatchMemberLeft(updated, authUserId);\n\n return slackOk(c, {});\n });\n\n // conversations.invite\n app.post(\"/api/conversations.invite\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const users = parseUserList(body.users);\n if (!channel) return slackError(c, \"channel_not_found\");\n if (users.length === 0) return slackError(c, \"user_not_found\");\n if (users.length > 100) return slackError(c, \"too_many_users\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(ch)]);\n if (scopeError) return scopeError;\n if (ch.is_archived) return slackError(c, \"is_archived\");\n if (ch.is_im) return slackError(c, \"method_not_supported_for_channel_type\");\n\n const authUserId = getAuthUserId(authUser);\n const authSlackUser = getAuthSlackUser(authUser);\n if (!isChannelMember(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const errors: Array<{ user: string; ok: false; error: string }> = [];\n const validUsers: string[] = [];\n for (const userId of users) {\n const user = ss().users.findOneBy(\"user_id\", userId);\n if (!user || user.deleted) {\n errors.push({ user: userId, ok: false, error: \"user_not_found\" });\n } else if (userId === authUserId) {\n errors.push({ user: userId, ok: false, error: \"cant_invite_self\" });\n } else if (isChannelMember(ch, user, userId)) {\n errors.push({ user: userId, ok: false, error: \"already_in_channel\" });\n } else {\n validUsers.push(userId);\n }\n }\n\n if (errors.length > 0) {\n return c.json({ ok: false, error: errors[0].error, errors });\n }\n\n const updatedMembers = [...ch.members, ...validUsers];\n const updated = ss().channels.update(ch.id, {\n members: updatedMembers,\n num_members: updatedMembers.length,\n })!;\n\n for (const user of validUsers) {\n await dispatchMemberJoined(updated, user, authUserId);\n }\n\n return slackOk(c, { channel: formatChannel(updated, authUserId, authSlackUser?.name) });\n });\n\n // conversations.kick\n app.post(\"/api/conversations.kick\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const user = typeof body.user === \"string\" ? body.user : \"\";\n if (!channel) return slackError(c, \"channel_not_found\");\n if (!user) return slackError(c, \"user_not_found\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(ch)]);\n if (scopeError) return scopeError;\n if (ch.is_archived) return slackError(c, \"is_archived\");\n if (isGeneralChannel(ch)) return slackError(c, \"cant_kick_from_general\");\n if (ch.is_im) return slackError(c, \"method_not_supported_for_channel_type\");\n\n const authUserId = getAuthUserId(authUser);\n const authSlackUser = getAuthSlackUser(authUser);\n if (!isChannelMember(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n if (user === authUserId) return slackError(c, \"cant_kick_self\");\n const targetUser = ss().users.findOneBy(\"user_id\", user);\n if (!targetUser) return slackError(c, \"user_not_found\");\n const targetMemberKey = getChannelMemberKey(ch, targetUser, user);\n if (!targetMemberKey) return slackError(c, \"user_not_in_channel\");\n\n const targetAliases = memberAliases(targetUser, user);\n const updatedMembers = ch.members.filter((member) => !targetAliases.has(member));\n const updated = ss().channels.update(ch.id, {\n members: updatedMembers,\n num_members: updatedMembers.length,\n })!;\n await dispatchMemberLeft(updated, user);\n\n return slackOk(c, { errors: {} });\n });\n\n // conversations.open\n app.post(\"/api/conversations.open\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const users = parseUserList(body.users);\n const returnIm = isTruthySlackBoolean(body.return_im);\n const preventCreation = isTruthySlackBoolean(body.prevent_creation);\n const authUserId = getAuthUserId(authUser);\n const authSlackUser = getAuthSlackUser(authUser);\n\n if (channel) {\n const existing = ss().channels.findOneBy(\"channel_id\", channel);\n if (!existing || (!existing.is_im && !existing.is_mpim)) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(existing)]);\n if (scopeError) return scopeError;\n if (!isChannelMember(existing, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n const alreadyOpen = getSlackConversationOpenState(existing, authUserId);\n const updated = alreadyOpen\n ? existing\n : ss().channels.update(existing.id, setSlackConversationOpenState(existing, authUserId, true))!;\n if (!alreadyOpen) await dispatchConversationEvent(openEventType(updated), { channel: updated.channel_id });\n return slackOk(c, {\n ...(alreadyOpen ? { no_op: true, already_open: true } : {}),\n channel: returnIm ? formatChannel(updated, authUserId, authSlackUser?.name) : { id: updated.channel_id },\n });\n }\n\n if (users.length === 0) return slackError(c, \"users_list_not_supplied\");\n if (users.length > 8) return slackError(c, \"too_many_users\");\n\n const targetUsers: SlackUser[] = [];\n for (const userId of users) {\n if (userId === authUserId) continue;\n const user = ss().users.findOneBy(\"user_id\", userId);\n if (!user || user.deleted) return slackError(c, \"user_not_found\");\n targetUsers.push(user);\n }\n if (targetUsers.length === 0) return slackError(c, \"users_list_not_supplied\");\n\n const memberIds = [...new Set([authUserId, ...targetUsers.map((user) => user.user_id)])];\n const isMpim = memberIds.length > 2;\n const scopeError = requireSlackScopes(c, store, [isMpim ? \"mpim:write\" : \"im:write\"]);\n if (scopeError) return scopeError;\n const existing = findConversationByMembers(ss().channels.all(), memberIds, isMpim);\n if (existing) {\n const alreadyOpen = getSlackConversationOpenState(existing, authUserId);\n const updated = alreadyOpen\n ? existing\n : ss().channels.update(existing.id, setSlackConversationOpenState(existing, authUserId, true))!;\n if (!alreadyOpen) await dispatchConversationEvent(openEventType(updated), { channel: updated.channel_id });\n return slackOk(c, {\n ...(alreadyOpen ? { no_op: true, already_open: true } : {}),\n channel: returnIm ? formatChannel(updated, authUserId, authSlackUser?.name) : { id: updated.channel_id },\n });\n }\n if (preventCreation) return slackError(c, \"channel_not_found\");\n\n const team = ss().teams.all()[0];\n const now = Math.floor(Date.now() / 1000);\n const created = ss().channels.insert({\n channel_id: generateSlackId(isMpim ? \"G\" : \"D\"),\n team_id: team?.team_id ?? \"T000000001\",\n name: isMpim\n ? `mpdm-${targetUsers.map((user) => user.name).join(\"-\")}`\n : (targetUsers[0]?.name ?? \"direct-message\"),\n is_channel: false,\n is_private: true,\n is_im: !isMpim,\n is_mpim: isMpim,\n is_open_by_user: { [authUserId]: true },\n user: isMpim ? undefined : targetUsers[0]?.user_id,\n is_archived: false,\n topic: { value: \"\", creator: authUserId, last_set: now },\n purpose: { value: \"\", creator: authUserId, last_set: now },\n members: memberIds,\n creator: authUserId,\n num_members: memberIds.length,\n last_read: {},\n });\n\n await dispatchConversationEvent(created.is_im ? \"im_created\" : \"group_joined\", {\n channel: formatChannel(created, authUserId, authSlackUser?.name),\n });\n await dispatchConversationEvent(openEventType(created), { channel: created.channel_id });\n\n return slackOk(c, {\n channel: returnIm ? formatChannel(created, authUserId, authSlackUser?.name) : { id: created.channel_id },\n });\n });\n\n // conversations.close\n app.post(\"/api/conversations.close\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n if (!channel) return slackError(c, \"channel_not_found\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch || (!ch.is_im && !ch.is_mpim)) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(ch)]);\n if (scopeError) return scopeError;\n const authUserId = getAuthUserId(authUser);\n const authSlackUser = getAuthSlackUser(authUser);\n if (!isChannelMember(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n if (!getSlackConversationOpenState(ch, authUserId)) {\n return slackOk(c, { no_op: true, already_closed: true });\n }\n\n const updated = ss().channels.update(ch.id, setSlackConversationOpenState(ch, authUserId, false))!;\n await dispatchConversationEvent(closeEventType(updated), { channel: updated.channel_id });\n return slackOk(c, {});\n });\n\n // conversations.mark\n app.post(\"/api/conversations.mark\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const ts = typeof body.ts === \"string\" ? body.ts : \"\";\n if (!channel) return slackError(c, \"channel_not_found\");\n if (!ts) return slackError(c, \"invalid_ts\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationWriteScope(ch)]);\n if (scopeError) return scopeError;\n\n const authUserId = getAuthUserId(authUser);\n const authSlackUser = getAuthSlackUser(authUser);\n if (!isChannelMember(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n ss().channels.update(ch.id, {\n last_read: { ...(ch.last_read ?? {}), [authUserId]: ts },\n });\n await dispatchConversationEvent(markEventType(ch), { channel: ch.channel_id, ts });\n\n return slackOk(c, {});\n });\n\n // conversations.members\n app.post(\"/api/conversations.members\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (!ch) return slackError(c, \"channel_not_found\");\n const scopeError = requireSlackScopes(c, store, [slackConversationReadScope(ch)]);\n if (scopeError) return scopeError;\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!canReadConversation(ch, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n return slackOk(c, {\n members: ch.members,\n response_metadata: { next_cursor: \"\" },\n });\n });\n}\n\nfunction formatChannel(ch: SlackChannel, viewer?: string, viewerName?: string) {\n const imUser = ch.is_im && viewer ? ch.members.find((member) => member !== viewer) : ch.user;\n const isMember = viewer\n ? ch.members.includes(viewer) || (viewerName !== undefined && ch.members.includes(viewerName))\n : undefined;\n return {\n id: ch.channel_id,\n name: ch.name,\n name_normalized: ch.name,\n is_channel: ch.is_channel,\n is_group: ch.is_private && !ch.is_im && !ch.is_mpim,\n is_im: ch.is_im ?? false,\n is_mpim: ch.is_mpim ?? false,\n is_private: ch.is_private,\n is_archived: ch.is_archived,\n is_open: getSlackConversationOpenState(ch, viewer),\n ...(imUser ? { user: imUser } : {}),\n is_member: viewer ? isMember : undefined,\n last_read: viewer ? (ch.last_read?.[viewer] ?? \"0000000000.000000\") : undefined,\n topic: ch.topic,\n purpose: ch.purpose,\n creator: ch.creator,\n num_members: ch.num_members,\n created: createdSeconds(ch),\n };\n}\n\nfunction createdSeconds(ch: SlackChannel): number {\n return Math.floor(new Date(ch.created_at).getTime() / 1000);\n}\n\nfunction normalizeChannelName(name: string): string {\n return name.trim().toLowerCase().replace(/\\s+/g, \"-\");\n}\n\nfunction validateChannelName(name: string): string | undefined {\n if (!name) return \"invalid_name_required\";\n if (name.length > 80) return \"invalid_name_maxlength\";\n if (!/[a-z0-9]/.test(name)) return \"invalid_name_punctuation\";\n if (!/^[a-z0-9_-]+$/.test(name)) return \"invalid_name_specials\";\n return undefined;\n}\n\nfunction isTruthySlackBoolean(value: unknown): boolean {\n if (value === true || value === 1) return true;\n if (typeof value !== \"string\") return false;\n const normalized = value.toLowerCase();\n return normalized === \"true\" || normalized === \"1\";\n}\n\nfunction isGeneralChannel(ch: SlackChannel): boolean {\n return ch.channel_id === \"C000000001\" || ch.name === \"general\";\n}\n\nfunction isDirectConversation(ch: SlackChannel): boolean {\n return Boolean(ch.is_im || ch.is_mpim);\n}\n\nfunction lifecycleEventType(ch: SlackChannel, action: \"archive\" | \"rename\" | \"unarchive\"): string {\n return `${conversationEventPrefix(ch)}_${action}`;\n}\n\nfunction lifecycleMessageSubtype(ch: SlackChannel, action: \"name\" | \"purpose\" | \"topic\"): string {\n return `${conversationEventPrefix(ch)}_${action}`;\n}\n\nfunction conversationEventPrefix(ch: SlackChannel): \"channel\" | \"group\" {\n return ch.is_private ? \"group\" : \"channel\";\n}\n\nfunction conversationNoun(ch: SlackChannel): \"channel\" | \"group\" {\n return ch.is_private ? \"group\" : \"channel\";\n}\n\nfunction parseConversationTypes(value: unknown): Set<string> {\n const raw = typeof value === \"string\" && value.length > 0 ? value : \"public_channel\";\n return new Set(\n raw\n .split(\",\")\n .map((type) => type.trim())\n .filter(Boolean),\n );\n}\n\nfunction readScopesForConversationTypes(types: Set<string>): string[] {\n const scopes: string[] = [];\n if (types.has(\"public_channel\")) scopes.push(\"channels:read\");\n if (types.has(\"private_channel\")) scopes.push(\"groups:read\");\n if (types.has(\"im\")) scopes.push(\"im:read\");\n if (types.has(\"mpim\")) scopes.push(\"mpim:read\");\n return scopes.length > 0 ? scopes : [\"channels:read\"];\n}\n\nfunction matchesConversationTypes(ch: SlackChannel, types: Set<string>): boolean {\n if (types.has(\"public_channel\") && !ch.is_private && !ch.is_im && !ch.is_mpim) return true;\n if (types.has(\"private_channel\") && ch.is_private && !ch.is_im && !ch.is_mpim) return true;\n if (types.has(\"im\") && ch.is_im) return true;\n if (types.has(\"mpim\") && ch.is_mpim) return true;\n return false;\n}\n\nfunction parseUserList(value: unknown): string[] {\n const users = Array.isArray(value) ? value : typeof value === \"string\" ? value.split(\",\") : [];\n return [...new Set(users.map((user) => String(user).trim()).filter(Boolean))];\n}\n\nfunction sameMembers(left: string[], right: string[]): boolean {\n if (left.length !== right.length) return false;\n const leftKey = [...left].sort().join(\",\");\n const rightKey = [...right].sort().join(\",\");\n return leftKey === rightKey;\n}\n\nfunction findConversationByMembers(\n channels: SlackChannel[],\n members: string[],\n isMpim: boolean,\n): SlackChannel | undefined {\n return channels.find(\n (ch) => Boolean(ch.is_mpim) === isMpim && Boolean(ch.is_im) === !isMpim && sameMembers(ch.members, members),\n );\n}\n\nfunction findNamedChannel(channels: SlackChannel[], name: string): SlackChannel | undefined {\n return channels.find((ch) => !ch.is_im && !ch.is_mpim && ch.name === name);\n}\n\nfunction fileChannels(file: SlackFile): string[] {\n return [...file.channels, ...file.groups, ...file.ims];\n}\n\nfunction filterVisibleShares(shares: Record<string, SlackFileShare[]> | undefined, visibleIds: Set<string>) {\n const entries = Object.entries(shares ?? {}).filter(([channelId]) => visibleIds.has(channelId));\n return entries.length > 0 ? Object.fromEntries(entries) : undefined;\n}\n\nfunction channelTypeLetter(ch: SlackChannel): \"C\" | \"D\" | \"G\" {\n if (ch.is_im) return \"D\";\n if (ch.is_private || ch.is_mpim) return \"G\";\n return \"C\";\n}\n\nfunction openEventType(ch: SlackChannel): \"group_open\" | \"im_open\" {\n return ch.is_im ? \"im_open\" : \"group_open\";\n}\n\nfunction closeEventType(ch: SlackChannel): \"group_close\" | \"im_close\" {\n return ch.is_im ? \"im_close\" : \"group_close\";\n}\n\nfunction markEventType(ch: SlackChannel): \"channel_marked\" | \"group_marked\" | \"im_marked\" {\n if (ch.is_im) return \"im_marked\";\n if (ch.is_private || ch.is_mpim) return \"group_marked\";\n return \"channel_marked\";\n}\n","import type { Context, RouteContext } from \"@emulators/core\";\nimport { getSlackStore } from \"../store.js\";\nimport {\n generateTs,\n slackOk,\n slackError,\n parseSlackBody,\n requireSlackScopes,\n isSlackStrictScopes,\n hasSlackScope,\n} from \"../helpers.js\";\nimport type { SlackManualPresence, SlackPresence, SlackUser, SlackUserProfile } from \"../entities.js\";\n\nexport function usersRoutes(ctx: RouteContext): void {\n const { app, store, webhooks } = ctx;\n const ss = () => getSlackStore(store);\n const getAuthSlackUser = (authUser: { login: string }) =>\n ss().users.findOneBy(\"user_id\", authUser.login) ?? ss().users.findOneBy(\"name\", authUser.login);\n const getAuthUserId = (authUser: { login: string }) => getAuthSlackUser(authUser)?.user_id ?? authUser.login;\n\n // users.list\n app.post(\"/api/users.list\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"users:read\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const limit = Math.min(Number(body.limit) || 100, 1000);\n const cursor = typeof body.cursor === \"string\" ? body.cursor : \"\";\n\n const allUsers = ss()\n .users.all()\n .filter((u) => !u.deleted);\n\n let startIndex = 0;\n if (cursor) {\n const idx = allUsers.findIndex((u) => u.user_id === cursor);\n if (idx >= 0) startIndex = idx;\n }\n\n const page = allUsers.slice(startIndex, startIndex + limit);\n const nextCursor = startIndex + limit < allUsers.length ? allUsers[startIndex + limit].user_id : \"\";\n\n return slackOk(c, {\n members: page.map((user) => formatUser(user, canExposeEmail(c))),\n response_metadata: { next_cursor: nextCursor },\n });\n });\n\n // users.info\n app.post(\"/api/users.info\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"users:read\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const userId = typeof body.user === \"string\" ? body.user : \"\";\n\n const user = ss().users.findOneBy(\"user_id\", userId);\n if (!user) return slackError(c, \"user_not_found\");\n\n return slackOk(c, { user: formatUser(user, canExposeEmail(c)) });\n });\n\n // users.lookupByEmail\n app.post(\"/api/users.lookupByEmail\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"users:read.email\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const email = typeof body.email === \"string\" ? body.email : \"\";\n\n if (!email) return slackError(c, \"users_not_found\");\n\n const user = ss().users.findOneBy(\"email\", email);\n if (!user) return slackError(c, \"users_not_found\");\n\n return slackOk(c, { user: formatUser(user, true) });\n });\n\n async function profileGet(c: Context) {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"users.profile:read\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackRequest(c);\n const requestedUserId = typeof body.user === \"string\" && body.user ? body.user : getAuthUserId(authUser);\n const user = ss().users.findOneBy(\"user_id\", requestedUserId);\n if (!user || user.deleted) return slackError(c, \"user_not_found\");\n\n return slackOk(c, { profile: formatProfile(user.profile, canExposeEmail(c)) });\n }\n\n async function profileSet(c: Context) {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"users.profile:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const requestedUserId = typeof body.user === \"string\" && body.user ? body.user : getAuthUserId(authUser);\n const user = ss().users.findOneBy(\"user_id\", requestedUserId);\n if (!user || user.deleted) return slackError(c, \"user_not_found\");\n\n const updates = parseProfileUpdates(body);\n if (!updates) return slackError(c, \"invalid_arguments\");\n\n const nextProfile = mergeProfile(user.profile, updates);\n const userUpdates: Partial<SlackUser> = { profile: nextProfile };\n if (updates.real_name !== undefined) userUpdates.real_name = nextProfile.real_name;\n if (updates.email !== undefined) userUpdates.email = nextProfile.email;\n\n const updated = ss().users.update(user.id, userUpdates)!;\n await webhooks.dispatch(\n \"user_change\",\n undefined,\n {\n type: \"event_callback\",\n event: {\n type: \"user_change\",\n user: formatUser(updated),\n cache_ts: Number(generateTs().replace(\".\", \"\")),\n },\n },\n \"slack\",\n );\n\n return slackOk(c, { profile: formatProfile(updated.profile, canExposeEmail(c)) });\n }\n\n async function getPresence(c: Context) {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"users:read\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackRequest(c);\n const authUserId = getAuthUserId(authUser);\n const requestedUserId = typeof body.user === \"string\" && body.user ? body.user : authUserId;\n const user = ss().users.findOneBy(\"user_id\", requestedUserId);\n if (!user || user.deleted) return slackError(c, \"user_not_found\");\n\n const presence = user.presence ?? \"active\";\n if (requestedUserId !== authUserId) {\n return slackOk(c, { presence });\n }\n\n const manualPresence = user.manual_presence ?? (presence === \"away\" ? \"away\" : \"auto\");\n return slackOk(c, {\n presence,\n online: presence === \"active\",\n auto_away: false,\n manual_away: manualPresence === \"away\",\n connection_count: user.connection_count ?? (presence === \"active\" ? 1 : 0),\n ...(user.last_activity ? { last_activity: user.last_activity } : {}),\n });\n }\n\n async function setPresence(c: Context) {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"users:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const presence = typeof body.presence === \"string\" ? body.presence : \"\";\n if (presence !== \"auto\" && presence !== \"away\") return slackError(c, \"invalid_presence\");\n\n const authUserId = getAuthUserId(authUser);\n const user = ss().users.findOneBy(\"user_id\", authUserId);\n if (!user || user.deleted) return slackError(c, \"user_not_found\");\n\n const now = Math.floor(Date.now() / 1000);\n const nextPresence: SlackPresence = presence === \"away\" ? \"away\" : \"active\";\n const manualPresence: SlackManualPresence = presence === \"away\" ? \"away\" : \"auto\";\n const updated = ss().users.update(user.id, {\n presence: nextPresence,\n manual_presence: manualPresence,\n connection_count: nextPresence === \"active\" ? 1 : 0,\n last_activity: nextPresence === \"active\" ? now : user.last_activity,\n })!;\n\n await webhooks.dispatch(\n \"presence_change\",\n undefined,\n {\n type: \"event_callback\",\n event: {\n type: \"presence_change\",\n user: updated.user_id,\n presence: nextPresence,\n },\n },\n \"slack\",\n );\n\n return slackOk(c, {});\n }\n\n function canExposeEmail(c: Context): boolean {\n return !isSlackStrictScopes(store) || hasSlackScope(c, \"users:read.email\");\n }\n\n app.get(\"/api/users.profile.get\", profileGet);\n app.post(\"/api/users.profile.get\", profileGet);\n app.post(\"/api/users.profile.set\", profileSet);\n app.get(\"/api/users.getPresence\", getPresence);\n app.post(\"/api/users.getPresence\", getPresence);\n app.post(\"/api/users.setPresence\", setPresence);\n}\n\nfunction formatUser(u: SlackUser, includeEmail = true) {\n const profile = formatProfile(u.profile, includeEmail);\n return {\n id: u.user_id,\n team_id: u.team_id,\n name: u.name,\n real_name: u.real_name,\n is_admin: u.is_admin,\n is_bot: u.is_bot,\n deleted: u.deleted,\n profile,\n };\n}\n\nfunction formatProfile(profile: SlackUserProfile, includeEmail = true) {\n const formatted = normalizeProfile(profile);\n return includeEmail ? formatted : omitEmail(formatted);\n}\n\nfunction normalizeProfile(profile: SlackUserProfile): SlackUserProfile {\n return {\n title: \"\",\n phone: \"\",\n skype: \"\",\n ...profile,\n real_name_normalized: profile.real_name_normalized ?? profile.real_name,\n display_name_normalized: profile.display_name_normalized ?? profile.display_name,\n status_text: profile.status_text ?? \"\",\n status_emoji: profile.status_emoji ?? \"\",\n status_emoji_display_info: profile.status_emoji_display_info ?? [],\n status_expiration: profile.status_expiration ?? 0,\n huddle_state: profile.huddle_state ?? \"default_unset\",\n huddle_state_expiration_ts: profile.huddle_state_expiration_ts ?? 0,\n };\n}\n\nfunction omitEmail(profile: SlackUserProfile): Omit<SlackUserProfile, \"email\"> {\n const { email: _email, ...rest } = profile;\n return rest;\n}\n\nasync function parseSlackRequest(c: Context): Promise<Record<string, unknown>> {\n if (c.req.method === \"GET\") {\n return Object.fromEntries(new URL(c.req.url).searchParams.entries());\n }\n return parseSlackBody(c);\n}\n\nfunction parseProfileUpdates(body: Record<string, unknown>): Partial<SlackUserProfile> | undefined {\n const profile = parseProfileObject(body.profile);\n if (profile) return profile;\n\n const name = typeof body.name === \"string\" ? body.name : \"\";\n if (!name) return undefined;\n if (!Object.prototype.hasOwnProperty.call(body, \"value\")) return undefined;\n return { [name]: String(body.value ?? \"\") } as Partial<SlackUserProfile>;\n}\n\nfunction parseProfileObject(value: unknown): Partial<SlackUserProfile> | undefined {\n if (value === undefined || value === null || value === \"\") return undefined;\n if (typeof value === \"string\") {\n try {\n const parsed = JSON.parse(value) as unknown;\n return isProfileObject(parsed) ? (parsed as Partial<SlackUserProfile>) : undefined;\n } catch {\n return undefined;\n }\n }\n return isProfileObject(value) ? (value as Partial<SlackUserProfile>) : undefined;\n}\n\nfunction isProfileObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction mergeProfile(profile: SlackUserProfile, updates: Partial<SlackUserProfile>): SlackUserProfile {\n const next: SlackUserProfile = normalizeProfile({ ...profile, ...updates });\n\n if (updates.real_name !== undefined) {\n next.real_name = String(updates.real_name);\n next.real_name_normalized = next.real_name;\n const [firstName = \"\", ...rest] = next.real_name.trim().split(/\\s+/);\n next.first_name = firstName;\n next.last_name = rest.join(\" \");\n }\n if (updates.display_name !== undefined) {\n next.display_name = String(updates.display_name);\n next.display_name_normalized = next.display_name;\n }\n if (updates.email !== undefined) {\n next.email = String(updates.email);\n }\n if (updates.fields !== undefined) {\n next.fields = updates.fields;\n }\n\n return next;\n}\n","import type { RouteContext } from \"@emulators/core\";\nimport type { SlackChannel } from \"../entities.js\";\nimport { getSlackStore } from \"../store.js\";\nimport { formatSlackMessage, slackOk, slackError, parseSlackBody, requireSlackScopes } from \"../helpers.js\";\n\nexport function reactionsRoutes(ctx: RouteContext): void {\n const { app, store, webhooks } = ctx;\n const ss = () => getSlackStore(store);\n const getAuthSlackUser = (authUser: { login: string }) =>\n ss().users.findOneBy(\"user_id\", authUser.login) ?? ss().users.findOneBy(\"name\", authUser.login);\n const getAuthUserId = (authUser: { login: string }) => getAuthSlackUser(authUser)?.user_id ?? authUser.login;\n const getAuthUserAliases = (authUser: { login: string }) => {\n const user = getAuthSlackUser(authUser);\n return new Set([authUser.login, user?.user_id, user?.name].filter((value): value is string => Boolean(value)));\n };\n const isAuthChannelMember = (channel: SlackChannel, authUser: { login: string }) => {\n const user = getAuthSlackUser(authUser);\n const userId = user?.user_id ?? authUser.login;\n return channel.members.includes(userId) || (user ? channel.members.includes(user.name) : false);\n };\n const canAccessConversation = (channel: SlackChannel, authUser: { login: string }) =>\n !channel.is_private || isAuthChannelMember(channel, authUser);\n\n // reactions.add\n app.post(\"/api/reactions.add\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"reactions:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const timestamp = typeof body.timestamp === \"string\" ? body.timestamp : \"\";\n const name = typeof body.name === \"string\" ? body.name : \"\";\n\n if (!name) return slackError(c, \"invalid_name\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (ch && !canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n\n const msg = ss()\n .messages.all()\n .find((m) => m.ts === timestamp && m.channel_id === channel);\n if (!msg) return slackError(c, \"message_not_found\");\n\n const reactions = [...msg.reactions];\n const existing = reactions.find((r) => r.name === name);\n const authUserId = getAuthUserId(authUser);\n const aliases = getAuthUserAliases(authUser);\n if (existing) {\n if (existing.users.some((user) => aliases.has(user))) {\n return slackError(c, \"already_reacted\");\n }\n existing.users.push(authUserId);\n existing.count++;\n } else {\n reactions.push({ name, users: [authUserId], count: 1 });\n }\n\n ss().messages.update(msg.id, { reactions });\n\n await webhooks.dispatch(\n \"reaction_added\",\n undefined,\n {\n type: \"event_callback\",\n event: {\n type: \"reaction_added\",\n user: authUserId,\n reaction: name,\n item: { type: \"message\", channel, ts: timestamp },\n },\n },\n \"slack\",\n );\n\n return slackOk(c, {});\n });\n\n // reactions.remove\n app.post(\"/api/reactions.remove\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"reactions:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const timestamp = typeof body.timestamp === \"string\" ? body.timestamp : \"\";\n const name = typeof body.name === \"string\" ? body.name : \"\";\n\n if (!name) return slackError(c, \"invalid_name\");\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (ch && !canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n\n const msg = ss()\n .messages.all()\n .find((m) => m.ts === timestamp && m.channel_id === channel);\n if (!msg) return slackError(c, \"message_not_found\");\n\n const reactions = [...msg.reactions];\n const existing = reactions.find((r) => r.name === name);\n const authUserId = getAuthUserId(authUser);\n const aliases = getAuthUserAliases(authUser);\n if (!existing || !existing.users.some((user) => aliases.has(user))) {\n return slackError(c, \"no_reaction\");\n }\n\n existing.users = existing.users.filter((u) => !aliases.has(u));\n existing.count = existing.users.length;\n\n const filtered = reactions.filter((r) => r.count > 0);\n ss().messages.update(msg.id, { reactions: filtered });\n\n await webhooks.dispatch(\n \"reaction_removed\",\n undefined,\n {\n type: \"event_callback\",\n event: {\n type: \"reaction_removed\",\n user: authUserId,\n reaction: name,\n item: { type: \"message\", channel, ts: timestamp },\n },\n },\n \"slack\",\n );\n\n return slackOk(c, {});\n });\n\n // reactions.get\n app.post(\"/api/reactions.get\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"reactions:read\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const timestamp = typeof body.timestamp === \"string\" ? body.timestamp : \"\";\n\n const ch = ss().channels.findOneBy(\"channel_id\", channel);\n if (ch && !canAccessConversation(ch, authUser)) return slackError(c, \"not_in_channel\");\n\n const msg = ss()\n .messages.all()\n .find((m) => m.ts === timestamp && m.channel_id === channel);\n if (!msg) return slackError(c, \"message_not_found\");\n\n return slackOk(c, {\n type: \"message\",\n message: { ...formatSlackMessage(msg), reactions: msg.reactions },\n });\n });\n}\n","import type { RouteContext } from \"@emulators/core\";\nimport { getSlackStore } from \"../store.js\";\nimport { slackOk, slackError, parseSlackBody, requireSlackScopes } from \"../helpers.js\";\n\nexport function teamRoutes(ctx: RouteContext): void {\n const { app, store } = ctx;\n const ss = () => getSlackStore(store);\n\n // team.info\n app.post(\"/api/team.info\", (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"team:read\"]);\n if (scopeError) return scopeError;\n\n const team = ss().teams.all()[0];\n if (!team) return slackError(c, \"team_not_found\");\n\n return slackOk(c, {\n team: {\n id: team.team_id,\n name: team.name,\n domain: team.domain,\n },\n });\n });\n\n // bots.info\n app.post(\"/api/bots.info\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"users:read\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const botId = typeof body.bot === \"string\" ? body.bot : \"\";\n\n const bot = ss().bots.findOneBy(\"bot_id\", botId);\n if (!bot) return slackError(c, \"bot_not_found\");\n\n return slackOk(c, {\n bot: {\n id: bot.bot_id,\n name: bot.name,\n deleted: bot.deleted,\n icons: bot.icons,\n },\n });\n });\n}\n","import { randomBytes } from \"crypto\";\nimport type { RouteContext } from \"@emulators/core\";\nimport {\n escapeHtml,\n renderCardPage,\n renderErrorPage,\n renderUserButton,\n matchesRedirectUri,\n constantTimeSecretEqual,\n bodyStr,\n debug,\n} from \"@emulators/core\";\nimport { getSlackStore } from \"../store.js\";\nimport { generateSlackId } from \"../helpers.js\";\nimport type { SlackBot, SlackInstallation, SlackOAuthApp, SlackUser } from \"../entities.js\";\nimport type { SlackStore } from \"../store.js\";\n\ntype PendingCode = {\n userId: string;\n scope: string;\n userScope: string;\n redirectUri: string;\n clientId: string;\n created_at: number;\n};\n\nconst PENDING_CODE_TTL_MS = 10 * 60 * 1000;\nconst SERVICE_LABEL = \"Slack\";\n\nfunction getPendingCodes(store: import(\"@emulators/core\").Store): Map<string, PendingCode> {\n let map = store.getData<Map<string, PendingCode>>(\"slack.oauth.pendingCodes\");\n if (!map) {\n map = new Map();\n store.setData(\"slack.oauth.pendingCodes\", map);\n }\n return map;\n}\n\nfunction isPendingCodeExpired(p: PendingCode): boolean {\n return Date.now() - p.created_at > PENDING_CODE_TTL_MS;\n}\n\nexport function oauthRoutes({ app, store, tokenMap }: RouteContext): void {\n const ss = () => getSlackStore(store);\n\n // Authorization page - renders the consent UI\n app.get(\"/oauth/v2/authorize\", (c) => {\n const client_id = c.req.query(\"client_id\") ?? \"\";\n const redirect_uri = c.req.query(\"redirect_uri\") ?? \"\";\n const scope = c.req.query(\"scope\") ?? \"\";\n const user_scope = c.req.query(\"user_scope\") ?? \"\";\n const state = c.req.query(\"state\") ?? \"\";\n\n const appsConfigured = ss().oauthApps.all().length > 0;\n let appName = \"\";\n if (appsConfigured) {\n const oauthApp = ss().oauthApps.findOneBy(\"client_id\", client_id);\n if (!oauthApp) {\n return c.html(\n renderErrorPage(\"Application not found\", `The client_id '${client_id}' is not registered.`, SERVICE_LABEL),\n 400,\n );\n }\n if (redirect_uri && !matchesRedirectUri(redirect_uri, oauthApp.redirect_uris)) {\n return c.html(\n renderErrorPage(\n \"Redirect URI mismatch\",\n \"The redirect_uri is not registered for this application.\",\n SERVICE_LABEL,\n ),\n 400,\n );\n }\n appName = oauthApp.name;\n }\n\n const subtitleText = appName\n ? `Authorize <strong>${escapeHtml(appName)}</strong> to access your Slack workspace.`\n : \"Choose a user to authorize.\";\n\n const users = ss()\n .users.all()\n .filter((u) => !u.deleted && !u.is_bot);\n const userButtons = users\n .map((user) => {\n return renderUserButton({\n letter: (user.name[0] ?? \"?\").toUpperCase(),\n login: user.name,\n name: user.real_name,\n email: user.email,\n formAction: \"/oauth/v2/authorize/callback\",\n hiddenFields: {\n user_id: user.user_id,\n redirect_uri,\n scope,\n user_scope,\n state,\n client_id,\n },\n });\n })\n .join(\"\\n\");\n\n const body = users.length === 0 ? '<p class=\"empty\">No users in the emulator store.</p>' : userButtons;\n\n return c.html(renderCardPage(\"Sign in to Slack\", subtitleText, body, SERVICE_LABEL));\n });\n\n // Authorization callback\n app.post(\"/oauth/v2/authorize/callback\", async (c) => {\n const body = await c.req.parseBody();\n const userId = bodyStr(body.user_id);\n const redirect_uri = bodyStr(body.redirect_uri);\n const scope = bodyStr(body.scope);\n const userScope = bodyStr(body.user_scope);\n const state = bodyStr(body.state);\n const client_id = bodyStr(body.client_id);\n\n const code = randomBytes(20).toString(\"hex\");\n\n getPendingCodes(store).set(code, {\n userId,\n scope,\n userScope,\n redirectUri: redirect_uri,\n clientId: client_id,\n created_at: Date.now(),\n });\n\n debug(\"slack.oauth\", `[Slack callback] code=${code.slice(0, 8)}... user=${userId}`);\n\n const url = new URL(redirect_uri);\n url.searchParams.set(\"code\", code);\n if (state) url.searchParams.set(\"state\", state);\n\n return c.redirect(url.toString(), 302);\n });\n\n // oauth.v2.access - token exchange\n app.post(\"/api/oauth.v2.access\", async (c) => {\n const contentType = c.req.header(\"Content-Type\") ?? \"\";\n const rawText = await c.req.text();\n\n let body: Record<string, unknown>;\n if (contentType.includes(\"application/json\")) {\n try {\n body = JSON.parse(rawText);\n } catch {\n body = {};\n }\n } else {\n body = Object.fromEntries(new URLSearchParams(rawText));\n }\n\n const code = typeof body.code === \"string\" ? body.code : \"\";\n const basicAuth = parseBasicAuth(c.req.header(\"Authorization\"));\n const client_id = typeof body.client_id === \"string\" ? body.client_id : (basicAuth?.clientId ?? \"\");\n const client_secret = typeof body.client_secret === \"string\" ? body.client_secret : (basicAuth?.clientSecret ?? \"\");\n const redirect_uri = typeof body.redirect_uri === \"string\" ? body.redirect_uri : \"\";\n\n const appsConfigured = ss().oauthApps.all().length > 0;\n let oauthApp: SlackOAuthApp | undefined;\n if (appsConfigured) {\n oauthApp = ss().oauthApps.findOneBy(\"client_id\", client_id);\n if (!oauthApp) {\n return c.json({ ok: false, error: \"invalid_client_id\" });\n }\n if (!constantTimeSecretEqual(client_secret, oauthApp.client_secret)) {\n return c.json({ ok: false, error: \"invalid_client_id\" });\n }\n }\n\n const pendingMap = getPendingCodes(store);\n const pending = pendingMap.get(code);\n if (!pending) {\n return c.json({ ok: false, error: \"invalid_code\" });\n }\n if (isPendingCodeExpired(pending)) {\n pendingMap.delete(code);\n return c.json({ ok: false, error: \"invalid_code\" });\n }\n\n pendingMap.delete(code);\n\n if (client_id && pending.clientId && client_id !== pending.clientId) {\n return c.json({ ok: false, error: \"invalid_client_id\" });\n }\n if (redirect_uri && pending.redirectUri && redirect_uri !== pending.redirectUri) {\n return c.json({ ok: false, error: \"bad_redirect_uri\" });\n }\n\n const user = ss().users.findOneBy(\"user_id\", pending.userId);\n if (!user) {\n return c.json({ ok: false, error: \"invalid_code\" });\n }\n\n const accessToken = \"xoxb-\" + randomBytes(20).toString(\"base64url\");\n const userAccessToken = \"xoxp-\" + randomBytes(20).toString(\"base64url\");\n const team = ss().teams.all()[0];\n const teamId = team?.team_id ?? \"T000000001\";\n const appId = ensureOAuthAppId(ss(), oauthApp, client_id || pending.clientId);\n const requestedScopes = normalizeScopes(pending.scope, oauthApp?.scopes ?? [\"chat:write\", \"channels:read\"]);\n const userScopes = pending.userScope ? normalizeScopes(pending.userScope, []) : [];\n const bot = ensureBotForApp(ss(), oauthApp, appId, teamId);\n const installation = upsertInstallation(ss(), {\n appId,\n clientId: client_id || pending.clientId,\n teamId,\n appName: oauthApp?.name ?? \"Slack App\",\n installerUserId: user.user_id,\n bot,\n scopes: requestedScopes,\n userScopes,\n });\n\n ss().tokens.insert({\n token: accessToken,\n token_type: \"bot\",\n team_id: teamId,\n user_id: bot.user.user_id,\n scopes: requestedScopes,\n app_id: appId,\n client_id: client_id || pending.clientId,\n installation_id: installation.installation_id,\n bot_id: bot.bot.bot_id,\n bot_user_id: bot.user.user_id,\n authed_user_id: user.user_id,\n });\n\n if (tokenMap) {\n tokenMap.set(accessToken, { login: bot.user.user_id, id: bot.user.id, scopes: requestedScopes });\n }\n\n if (userScopes.length > 0) {\n ss().tokens.insert({\n token: userAccessToken,\n token_type: \"user\",\n team_id: teamId,\n user_id: user.user_id,\n scopes: userScopes,\n app_id: appId,\n client_id: client_id || pending.clientId,\n installation_id: installation.installation_id,\n bot_id: bot.bot.bot_id,\n bot_user_id: bot.user.user_id,\n authed_user_id: user.user_id,\n });\n tokenMap?.set(userAccessToken, { login: user.user_id, id: user.id, scopes: userScopes });\n }\n\n debug(\"slack.oauth\", `[Slack token] issued token for ${oauthApp?.name ?? \"Slack App\"} as ${bot.user.name}`);\n\n return c.json({\n ok: true,\n access_token: accessToken,\n token_type: \"bot\",\n scope: requestedScopes.join(\",\"),\n bot_user_id: bot.user.user_id,\n app_id: appId,\n team: {\n id: teamId,\n name: team?.name ?? \"Emulate\",\n },\n enterprise: null,\n is_enterprise_install: false,\n authed_user: {\n id: user.user_id,\n ...(userScopes.length > 0\n ? { scope: userScopes.join(\",\"), access_token: userAccessToken, token_type: \"user\" }\n : {}),\n },\n });\n });\n}\n\nfunction parseBasicAuth(value: string | undefined): { clientId: string; clientSecret: string } | undefined {\n if (!value?.startsWith(\"Basic \")) return undefined;\n try {\n const decoded = Buffer.from(value.slice(\"Basic \".length), \"base64\").toString(\"utf8\");\n const separator = decoded.indexOf(\":\");\n if (separator < 0) return undefined;\n return {\n clientId: decoded.slice(0, separator),\n clientSecret: decoded.slice(separator + 1),\n };\n } catch {\n return undefined;\n }\n}\n\nfunction ensureOAuthAppId(ss: SlackStore, oauthApp: SlackOAuthApp | undefined, fallback: string): string {\n if (!oauthApp) return fallback || generateSlackId(\"A\");\n if (oauthApp.app_id) return oauthApp.app_id;\n\n const appId = generateSlackId(\"A\");\n ss.oauthApps.update(oauthApp.id, { app_id: appId });\n return appId;\n}\n\nfunction ensureBotForApp(\n ss: SlackStore,\n oauthApp: SlackOAuthApp | undefined,\n appId: string,\n teamId: string,\n): { bot: SlackBot; user: SlackUser } {\n const botId = oauthApp?.bot_id ?? generateSlackId(\"B\");\n const botUserId = oauthApp?.bot_user_id ?? generateSlackId(\"U\");\n const botName = oauthApp?.bot_name ?? slugifyBotName(oauthApp?.name ?? \"Slack App\");\n\n if (oauthApp && (!oauthApp.bot_id || !oauthApp.bot_user_id || !oauthApp.bot_name)) {\n ss.oauthApps.update(oauthApp.id, {\n bot_id: botId,\n bot_user_id: botUserId,\n bot_name: botName,\n });\n }\n\n const existingBot = ss.bots.findOneBy(\"bot_id\", botId);\n const bot =\n existingBot ??\n ss.bots.insert({\n bot_id: botId,\n app_id: appId,\n user_id: botUserId,\n name: botName,\n deleted: false,\n icons: { image_48: \"\" },\n });\n\n if (existingBot && (existingBot.app_id !== appId || existingBot.user_id !== botUserId)) {\n ss.bots.update(existingBot.id, { app_id: appId, user_id: botUserId });\n }\n\n const existingUser = ss.users.findOneBy(\"user_id\", botUserId);\n const user =\n existingUser ??\n ss.users.insert({\n user_id: botUserId,\n team_id: teamId,\n name: botName,\n real_name: oauthApp?.name ?? botName,\n email: `${botName}@bots.emulate.dev`,\n is_admin: false,\n is_bot: true,\n deleted: false,\n profile: {\n display_name: botName,\n real_name: oauthApp?.name ?? botName,\n email: `${botName}@bots.emulate.dev`,\n image_48: \"\",\n image_192: \"\",\n real_name_normalized: oauthApp?.name ?? botName,\n display_name_normalized: botName,\n status_text: \"\",\n status_emoji: \"\",\n status_emoji_display_info: [],\n status_expiration: 0,\n },\n presence: \"active\",\n manual_presence: \"auto\",\n connection_count: 1,\n last_activity: Math.floor(Date.now() / 1000),\n });\n\n return {\n bot: ss.bots.findOneBy(\"bot_id\", bot.bot_id) ?? bot,\n user,\n };\n}\n\nfunction upsertInstallation(\n ss: SlackStore,\n input: {\n appId: string;\n clientId: string;\n teamId: string;\n appName: string;\n installerUserId: string;\n bot: { bot: SlackBot; user: SlackUser };\n scopes: string[];\n userScopes: string[];\n },\n): SlackInstallation {\n const existing = ss.installations.all().find((item) => item.app_id === input.appId && item.team_id === input.teamId);\n const data = {\n app_id: input.appId,\n client_id: input.clientId,\n team_id: input.teamId,\n app_name: input.appName,\n installer_user_id: input.installerUserId,\n bot_id: input.bot.bot.bot_id,\n bot_user_id: input.bot.user.user_id,\n scopes: input.scopes,\n user_scopes: input.userScopes,\n };\n\n if (existing) {\n return ss.installations.update(existing.id, data)!;\n }\n\n return ss.installations.insert({\n installation_id: generateSlackId(\"I\"),\n ...data,\n });\n}\n\nfunction normalizeScopes(value: string | undefined, fallback: string[]): string[] {\n if (!value) return [...fallback];\n return value\n .split(/[,\\s]+/)\n .map((scope) => scope.trim())\n .filter(Boolean);\n}\n\nfunction slugifyBotName(value: string): string {\n const slug = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return slug || \"slack-app\";\n}\n","export interface Entity {\n id: number;\n created_at: string;\n updated_at: string;\n}\n\nexport type InsertInput<T extends Entity> = Omit<T, \"id\" | \"created_at\" | \"updated_at\"> & { id?: number };\n\nexport type FilterFn<T> = (item: T) => boolean;\nexport type SortFn<T> = (a: T, b: T) => number;\n\nexport interface QueryOptions<T> {\n filter?: FilterFn<T>;\n sort?: SortFn<T>;\n page?: number;\n per_page?: number;\n}\n\nexport interface PaginatedResult<T> {\n items: T[];\n total_count: number;\n page: number;\n per_page: number;\n has_next: boolean;\n has_prev: boolean;\n}\n\nexport interface CollectionSnapshot<T extends Entity = Entity> {\n items: T[];\n autoId: number;\n indexFields: string[];\n}\n\nexport interface StoreSnapshot {\n collections: Record<string, CollectionSnapshot>;\n data: Record<string, unknown>;\n}\n\nexport function serializeValue(value: unknown): unknown {\n if (value instanceof Map) {\n return { __type: \"Map\" as const, entries: [...value.entries()].map(([k, v]) => [k, serializeValue(v)]) };\n }\n if (value instanceof Set) {\n return { __type: \"Set\" as const, values: [...value.values()] };\n }\n return value;\n}\n\nexport function deserializeValue(value: unknown): unknown {\n if (value !== null && typeof value === \"object\" && \"__type\" in value) {\n const tagged = value as Record<string, unknown>;\n if (tagged.__type === \"Map\") {\n const entries = tagged.entries as [unknown, unknown][];\n return new Map(entries.map(([k, v]) => [k, deserializeValue(v)]));\n }\n if (tagged.__type === \"Set\") {\n return new Set(tagged.values as unknown[]);\n }\n }\n return value;\n}\n\nexport class Collection<T extends Entity> {\n private items = new Map<number, T>();\n private indexes = new Map<string, Map<string | number, Set<number>>>();\n private autoId = 1;\n readonly fieldNames: string[];\n\n constructor(private indexFields: (keyof T)[] = []) {\n this.fieldNames = indexFields.map(String).sort();\n for (const field of indexFields) {\n this.indexes.set(String(field), new Map());\n }\n }\n\n private addToIndex(item: T): void {\n for (const field of this.indexFields) {\n const value = item[field];\n if (value === undefined || value === null) continue;\n const indexMap = this.indexes.get(String(field))!;\n const key = String(value);\n if (!indexMap.has(key)) {\n indexMap.set(key, new Set());\n }\n indexMap.get(key)!.add(item.id);\n }\n }\n\n private removeFromIndex(item: T): void {\n for (const field of this.indexFields) {\n const value = item[field];\n if (value === undefined || value === null) continue;\n const indexMap = this.indexes.get(String(field))!;\n const key = String(value);\n indexMap.get(key)?.delete(item.id);\n }\n }\n\n insert(data: InsertInput<T>): T {\n const now = new Date().toISOString();\n const explicitId = data.id != null && data.id > 0 ? data.id : undefined;\n const id = explicitId ?? this.autoId++;\n if (id >= this.autoId) {\n this.autoId = id + 1;\n }\n const item = {\n ...data,\n id,\n created_at: now,\n updated_at: now,\n } as unknown as T;\n this.items.set(id, item);\n this.addToIndex(item);\n return item;\n }\n\n get(id: number): T | undefined {\n return this.items.get(id);\n }\n\n findBy(field: keyof T, value: T[keyof T] | string | number): T[] {\n if (this.indexes.has(String(field))) {\n const ids = this.indexes.get(String(field))!.get(String(value));\n if (!ids) return [];\n return Array.from(ids)\n .map((id) => this.items.get(id)!)\n .filter(Boolean);\n }\n return this.all().filter((item) => item[field] === value);\n }\n\n findOneBy(field: keyof T, value: T[keyof T] | string | number): T | undefined {\n return this.findBy(field, value)[0];\n }\n\n update(id: number, data: Partial<T>): T | undefined {\n const existing = this.items.get(id);\n if (!existing) return undefined;\n this.removeFromIndex(existing);\n const updated = {\n ...existing,\n ...data,\n id,\n updated_at: new Date().toISOString(),\n } as T;\n this.items.set(id, updated);\n this.addToIndex(updated);\n return updated;\n }\n\n delete(id: number): boolean {\n const existing = this.items.get(id);\n if (!existing) return false;\n this.removeFromIndex(existing);\n return this.items.delete(id);\n }\n\n all(): T[] {\n return Array.from(this.items.values());\n }\n\n query(options: QueryOptions<T> = {}): PaginatedResult<T> {\n let results = this.all();\n\n if (options.filter) {\n results = results.filter(options.filter);\n }\n\n const total_count = results.length;\n\n if (options.sort) {\n results.sort(options.sort);\n }\n\n const page = options.page ?? 1;\n const per_page = Math.min(options.per_page ?? 30, 100);\n const start = (page - 1) * per_page;\n const paged = results.slice(start, start + per_page);\n\n return {\n items: paged,\n total_count,\n page,\n per_page,\n has_next: start + per_page < total_count,\n has_prev: page > 1,\n };\n }\n\n count(filter?: FilterFn<T>): number {\n if (!filter) return this.items.size;\n return this.all().filter(filter).length;\n }\n\n clear(): void {\n this.items.clear();\n for (const indexMap of this.indexes.values()) {\n indexMap.clear();\n }\n this.autoId = 1;\n }\n\n snapshot(): CollectionSnapshot<T> {\n return {\n items: this.all(),\n autoId: this.autoId,\n indexFields: this.fieldNames,\n };\n }\n\n restore(snap: CollectionSnapshot<T>): void {\n this.clear();\n this.autoId = snap.autoId;\n for (const item of snap.items) {\n this.items.set(item.id, item);\n this.addToIndex(item);\n }\n }\n}\n\nexport class Store {\n private collections = new Map<string, Collection<any>>();\n private _data = new Map<string, unknown>();\n\n collection<T extends Entity>(name: string, indexFields: (keyof T)[] = []): Collection<T> {\n const existing = this.collections.get(name);\n if (existing) {\n if (indexFields.length > 0) {\n const requested = indexFields.map(String).sort();\n if (existing.fieldNames.length !== requested.length || existing.fieldNames.some((f, i) => f !== requested[i])) {\n throw new Error(\n `Collection \"${name}\" already exists with indexes [${existing.fieldNames}] but was requested with [${requested}]`,\n );\n }\n }\n return existing as Collection<T>;\n }\n const col = new Collection<T>(indexFields);\n this.collections.set(name, col);\n return col;\n }\n\n getData<V>(key: string): V | undefined {\n return this._data.get(key) as V | undefined;\n }\n\n setData<V>(key: string, value: V): void {\n this._data.set(key, value);\n }\n\n reset(): void {\n for (const collection of this.collections.values()) {\n collection.clear();\n }\n this._data.clear();\n }\n\n snapshot(): StoreSnapshot {\n const collections: Record<string, CollectionSnapshot> = {};\n for (const [name, col] of this.collections) {\n collections[name] = col.snapshot();\n }\n const data: Record<string, unknown> = {};\n for (const [key, value] of this._data) {\n data[key] = serializeValue(value);\n }\n return { collections, data };\n }\n\n restore(snap: StoreSnapshot): void {\n const snapshotNames = new Set(Object.keys(snap.collections));\n for (const name of this.collections.keys()) {\n if (!snapshotNames.has(name)) {\n this.collections.delete(name);\n }\n }\n for (const [name, colSnap] of Object.entries(snap.collections)) {\n const indexFields = colSnap.indexFields as (keyof Entity)[];\n const col = this.collection(name, indexFields);\n col.restore(colSnap as CollectionSnapshot<any>);\n }\n this._data.clear();\n for (const [key, value] of Object.entries(snap.data)) {\n this._data.set(key, deserializeValue(value));\n }\n }\n}\n","import { createServer as createNodeServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\n\ntype BodyInit = ConstructorParameters<typeof Response>[0];\ntype HeadersInit = ConstructorParameters<typeof Headers>[0];\ntype FormDataEntryValue = string | File;\n\nexport type ContentfulStatusCode = number;\nexport type Next = () => Promise<void>;\n\ntype VariablesOf<E> = unknown extends E\n ? Record<string, any>\n : E extends { Variables: infer V }\n ? V\n : Record<string, any>;\ntype HandlerResult = Response | void | Promise<Response | void>;\n\nexport type Handler<E = unknown, P extends string = string> = (c: Context<E, P>, next: Next) => HandlerResult;\nexport type MiddlewareHandler<E = unknown> = Handler<E>;\nexport type ErrorHandler<E = unknown> = (err: unknown, c: Context<E>) => Response | Promise<Response>;\nexport type FetchHandler = (request: Request) => Response | Promise<Response>;\n\ninterface CompiledPath {\n pattern: string;\n regex: RegExp;\n paramNames: string[];\n}\n\ninterface Route<E> {\n method: string;\n compiled: CompiledPath;\n handlers: Handler<E>[];\n}\n\ninterface MatchedHandler<E> {\n handler: Handler<E>;\n params: Record<string, string>;\n}\n\nexport interface ServeOptions {\n fetch: FetchHandler;\n port?: number;\n hostname?: string;\n}\n\nexport interface CorsOptions {\n origin?: string;\n allowMethods?: string[];\n allowHeaders?: string[];\n credentials?: boolean;\n maxAge?: number;\n}\n\nexport class HonoRequest<P extends string = string> {\n readonly raw: Request;\n readonly url: string;\n readonly method: string;\n readonly path: string;\n\n constructor(\n request: Request,\n private readonly params: Record<string, string>,\n ) {\n this.raw = request;\n this.url = request.url;\n this.method = request.method;\n this.path = new URL(request.url).pathname;\n }\n\n header(): Record<string, string>;\n header(name: string): string | undefined;\n header(name?: string): Record<string, string> | string | undefined {\n if (name) return this.raw.headers.get(name) ?? undefined;\n const headers: Record<string, string> = {};\n this.raw.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return headers;\n }\n\n query(name: string): string | undefined {\n return new URL(this.url).searchParams.get(name) ?? undefined;\n }\n\n queries(name: string): string[] | undefined {\n const values = new URL(this.url).searchParams.getAll(name);\n return values.length > 0 ? values : undefined;\n }\n\n param(): Record<string, string>;\n param(name: string): string;\n param(name?: string): Record<string, string> | string {\n if (!name) return { ...this.params };\n return this.params[name] ?? \"\";\n }\n\n json<T = any>(): Promise<T> {\n return this.raw.json() as Promise<T>;\n }\n\n text(): Promise<string> {\n return this.raw.text();\n }\n\n arrayBuffer(): Promise<ArrayBuffer> {\n return this.raw.arrayBuffer();\n }\n\n async parseBody(): Promise<Record<string, FormDataEntryValue | FormDataEntryValue[]>> {\n const contentType = this.header(\"Content-Type\") ?? \"\";\n if (contentType.includes(\"multipart/form-data\")) {\n return formDataToObject(await this.raw.formData());\n }\n if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n const params = new URLSearchParams(await this.raw.text());\n const out: Record<string, string | string[]> = {};\n for (const [key, value] of params) {\n appendBodyValue(out, key, value);\n }\n return out;\n }\n if (contentType.includes(\"application/json\")) {\n const body = await this.raw.json().catch(() => ({}));\n return body && typeof body === \"object\" && !Array.isArray(body)\n ? (body as Record<string, FormDataEntryValue | FormDataEntryValue[]>)\n : {};\n }\n return {};\n }\n}\n\nexport class Context<E = unknown, P extends string = string> {\n readonly req: HonoRequest<P>;\n private readonly vars = new Map<string, unknown>();\n private readonly responseHeaders = new Headers();\n private responseStatus = 200;\n\n constructor(\n request: Request,\n params: Record<string, string>,\n private readonly notFoundHandler: (c: Context<E>) => Response | Promise<Response>,\n ) {\n this.req = new HonoRequest<P>(request, params);\n }\n\n get<K extends keyof VariablesOf<E> & string>(key: K): VariablesOf<E>[K] | undefined {\n return this.vars.get(key) as VariablesOf<E>[K] | undefined;\n }\n\n set<K extends keyof VariablesOf<E> & string>(key: K, value: VariablesOf<E>[K]): void {\n this.vars.set(key, value);\n }\n\n header(name: string, value: string): void {\n this.responseHeaders.set(name, value);\n }\n\n status(status: number): void {\n this.responseStatus = status;\n }\n\n json(data: unknown, status?: ContentfulStatusCode, headers?: HeadersInit): Response {\n return this.response(JSON.stringify(data), status, defaultContentType(headers, \"application/json; charset=UTF-8\"));\n }\n\n text(text: string, status?: ContentfulStatusCode, headers?: HeadersInit): Response {\n return this.response(text, status, defaultContentType(headers, \"text/plain; charset=UTF-8\"));\n }\n\n html(html: string, status?: ContentfulStatusCode, headers?: HeadersInit): Response {\n return this.response(html, status, defaultContentType(headers, \"text/html; charset=UTF-8\"));\n }\n\n body(body: BodyInit | null, status?: ContentfulStatusCode, headers?: HeadersInit): Response {\n return this.response(body, status, headers);\n }\n\n redirect(location: string, status: ContentfulStatusCode = 302): Response {\n return this.response(null, status, { Location: location });\n }\n\n notFound(): Response | Promise<Response> {\n return this.notFoundHandler(this);\n }\n\n finalize(response: Response): Response {\n if (!hasHeaders(this.responseHeaders)) return response;\n const headers = new Headers(response.headers);\n this.responseHeaders.forEach((value, key) => {\n headers.set(key, value);\n });\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n private response(body: BodyInit | null, status?: ContentfulStatusCode, headers?: HeadersInit): Response {\n const merged = new Headers(headers);\n this.responseHeaders.forEach((value, key) => {\n merged.set(key, value);\n });\n return new Response(body, {\n status: status ?? this.responseStatus,\n headers: merged,\n });\n }\n}\n\nexport class Hono<E = unknown> {\n private readonly middleware: Route<E>[] = [];\n private readonly routes: Route<E>[] = [];\n private errorHandler: ErrorHandler<E> = (err) => {\n const message = err instanceof Error ? err.message : \"Internal Server Error\";\n return new Response(message, { status: 500 });\n };\n private notFoundHandler: (c: Context<E>) => Response | Promise<Response> = () =>\n new Response(\"404 Not Found\", { status: 404 });\n\n use<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this;\n use(...handlers: Handler<E>[]): this;\n use<P extends string = string>(pathOrHandler: string | Handler<E>, ...handlers: Handler<E, P>[]): this {\n if (typeof pathOrHandler === \"string\") {\n this.middleware.push({ method: \"ALL\", compiled: compilePath(pathOrHandler), handlers: handlers as Handler<E>[] });\n } else {\n this.middleware.push({ method: \"ALL\", compiled: compilePath(\"*\"), handlers: [pathOrHandler, ...handlers] });\n }\n return this;\n }\n\n on<P extends string = string>(method: string, path: string, ...handlers: Handler<E, P>[]): this {\n this.routes.push({ method: method.toUpperCase(), compiled: compilePath(path), handlers: handlers as Handler<E>[] });\n return this;\n }\n\n get<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this {\n return this.on(\"GET\", path, ...handlers);\n }\n\n post<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this {\n return this.on(\"POST\", path, ...handlers);\n }\n\n put<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this {\n return this.on(\"PUT\", path, ...handlers);\n }\n\n patch<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this {\n return this.on(\"PATCH\", path, ...handlers);\n }\n\n delete<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this {\n return this.on(\"DELETE\", path, ...handlers);\n }\n\n onError(handler: ErrorHandler<E>): this {\n this.errorHandler = handler;\n return this;\n }\n\n notFound(handler: (c: Context<E>) => Response | Promise<Response>): this {\n this.notFoundHandler = handler;\n return this;\n }\n\n async request(input: string | Request, init?: RequestInit): Promise<Response> {\n if (input instanceof Request) return this.fetch(input);\n const url = input.startsWith(\"/\") ? `http://localhost${input}` : input;\n return this.fetch(new Request(url, init));\n }\n\n fetch = async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const path = url.pathname;\n const method = request.method.toUpperCase();\n const matched = this.match(method, path);\n const context = new Context<E>(request, matched.params, this.notFoundHandler);\n\n try {\n const response = await this.dispatch(context, matched.handlers);\n return context.finalize(response ?? (await this.notFoundHandler(context)));\n } catch (err) {\n return context.finalize(await this.errorHandler(err, context));\n }\n };\n\n private match(method: string, path: string): { handlers: MatchedHandler<E>[]; params: Record<string, string> } {\n const handlers: MatchedHandler<E>[] = [];\n const params: Record<string, string> = {};\n\n for (const route of this.middleware) {\n const match = matchPath(route.compiled, path);\n if (!match) continue;\n Object.assign(params, match);\n for (const handler of route.handlers) {\n handlers.push({ handler, params: match });\n }\n }\n\n const route =\n this.routes.find((candidate) => candidate.method === method && matchPath(candidate.compiled, path) != null) ??\n (method === \"HEAD\"\n ? this.routes.find((candidate) => candidate.method === \"GET\" && matchPath(candidate.compiled, path) != null)\n : undefined);\n\n if (route) {\n const match = matchPath(route.compiled, path) ?? {};\n Object.assign(params, match);\n for (const handler of route.handlers) {\n handlers.push({ handler, params: match });\n }\n }\n\n return { handlers, params };\n }\n\n private async dispatch(context: Context<E>, handlers: MatchedHandler<E>[]): Promise<Response | void> {\n let index = -1;\n const run = async (nextIndex: number): Promise<Response | void> => {\n if (nextIndex <= index) throw new Error(\"next() called multiple times\");\n index = nextIndex;\n const matched = handlers[nextIndex];\n if (!matched) return undefined;\n\n const originalParams = context.req.param();\n Object.assign(originalParams, matched.params);\n\n let nextResponse: Response | void = undefined;\n let nextCalled = false;\n const next: Next = async () => {\n nextCalled = true;\n nextResponse = await run(nextIndex + 1);\n };\n\n const response = await matched.handler(context, next);\n if (response instanceof Response) return response;\n if (nextCalled) return nextResponse;\n return response;\n };\n\n return run(0);\n }\n}\n\nexport function cors(options: CorsOptions = {}): MiddlewareHandler {\n const origin = options.origin ?? \"*\";\n const allowMethods = options.allowMethods ?? [\"GET\", \"HEAD\", \"PUT\", \"POST\", \"DELETE\", \"PATCH\", \"OPTIONS\"];\n\n return async (c, next) => {\n c.header(\"Access-Control-Allow-Origin\", origin);\n if (options.credentials) c.header(\"Access-Control-Allow-Credentials\", \"true\");\n\n if (c.req.method.toUpperCase() === \"OPTIONS\") {\n c.header(\"Access-Control-Allow-Methods\", allowMethods.join(\",\"));\n const allowHeaders = options.allowHeaders?.join(\",\") ?? c.req.header(\"Access-Control-Request-Headers\");\n if (allowHeaders) c.header(\"Access-Control-Allow-Headers\", allowHeaders);\n if (options.maxAge != null) c.header(\"Access-Control-Max-Age\", String(options.maxAge));\n return c.body(null, 204);\n }\n\n await next();\n };\n}\n\nexport function serve(options: ServeOptions): Server {\n const port = options.port ?? 3000;\n const server = createNodeServer(async (req, res) => {\n try {\n const request = nodeRequestToFetchRequest(req);\n const response = await options.fetch(request);\n await writeFetchResponse(res, response, req.method?.toUpperCase() === \"HEAD\");\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Internal Server Error\";\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"text/plain; charset=UTF-8\");\n res.end(message);\n }\n });\n server.listen(port, options.hostname);\n return server;\n}\n\nfunction compilePath(pattern: string): CompiledPath {\n if (pattern === \"*\" || pattern === \"/*\") {\n return { pattern, regex: /^.*$/, paramNames: [] };\n }\n\n const paramNames: string[] = [];\n let source = \"^\";\n for (let i = 0; i < pattern.length; i++) {\n const char = pattern[i];\n if (char !== \":\") {\n source += escapeRegex(char);\n continue;\n }\n\n let name = \"\";\n i++;\n while (i < pattern.length && /[A-Za-z0-9_]/.test(pattern[i])) {\n name += pattern[i];\n i++;\n }\n i--;\n paramNames.push(name);\n\n if (pattern[i + 1] === \"{\") {\n const close = pattern.indexOf(\"}\", i + 2);\n if (close < 0) throw new Error(`Invalid route pattern: ${pattern}`);\n const expr = pattern.slice(i + 2, close);\n source += `(${expr})`;\n i = close;\n } else {\n source += \"([^/]+)\";\n }\n }\n source += \"$\";\n return { pattern, regex: new RegExp(source), paramNames };\n}\n\nfunction matchPath(compiled: CompiledPath, path: string): Record<string, string> | null {\n const match = compiled.regex.exec(path);\n if (!match) return null;\n const params: Record<string, string> = {};\n for (let i = 0; i < compiled.paramNames.length; i++) {\n params[compiled.paramNames[i]] = decodePathParam(match[i + 1] ?? \"\");\n }\n return params;\n}\n\nfunction decodePathParam(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nfunction escapeRegex(value: string): string {\n return value.replace(/[|\\\\{}()[\\]^$+*?.]/g, \"\\\\$&\");\n}\n\nfunction hasHeaders(headers: Headers): boolean {\n for (const _ of headers) return true;\n return false;\n}\n\nfunction defaultContentType(headers: HeadersInit | undefined, contentType: string): Headers {\n const out = new Headers(headers);\n if (!out.has(\"Content-Type\")) {\n out.set(\"Content-Type\", contentType);\n }\n return out;\n}\n\nfunction formDataToObject(formData: FormData): Record<string, FormDataEntryValue | FormDataEntryValue[]> {\n const out: Record<string, FormDataEntryValue | FormDataEntryValue[]> = {};\n for (const [key, value] of formData) {\n appendBodyValue(out, key, value);\n }\n return out;\n}\n\nfunction appendBodyValue<T>(target: Record<string, T | T[]>, key: string, value: T): void {\n const existing = target[key];\n if (existing === undefined) {\n target[key] = value;\n } else if (Array.isArray(existing)) {\n existing.push(value);\n } else {\n target[key] = [existing, value];\n }\n}\n\nfunction nodeRequestToFetchRequest(req: IncomingMessage): Request {\n const host = req.headers.host ?? \"localhost\";\n const url = new URL(req.url ?? \"/\", `http://${host}`);\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value == null) continue;\n if (Array.isArray(value)) {\n for (const item of value) headers.append(key, item);\n } else {\n headers.set(key, value);\n }\n }\n\n const method = req.method ?? \"GET\";\n const hasBody = method !== \"GET\" && method !== \"HEAD\";\n return new Request(url.toString(), {\n method,\n headers,\n body: hasBody ? (req as unknown as BodyInit) : undefined,\n duplex: \"half\",\n } as RequestInit & { duplex: string });\n}\n\nasync function writeFetchResponse(res: ServerResponse, response: Response, headOnly: boolean): Promise<void> {\n res.statusCode = response.status;\n res.statusMessage = response.statusText;\n\n const headersWithCookies = response.headers as Headers & { getSetCookie?: () => string[] };\n const cookies = headersWithCookies.getSetCookie?.();\n response.headers.forEach((value, key) => {\n if (key.toLowerCase() === \"set-cookie\" && cookies && cookies.length > 0) return;\n res.setHeader(key, value);\n });\n if (cookies && cookies.length > 0) {\n res.setHeader(\"Set-Cookie\", cookies);\n }\n\n if (headOnly || !response.body) {\n res.end();\n return;\n }\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!res.write(value)) {\n await new Promise<void>((resolve) => res.once(\"drain\", resolve));\n }\n }\n res.end();\n } catch (err) {\n res.destroy(err instanceof Error ? err : undefined);\n }\n}\n","import { createHmac } from \"crypto\";\n\nexport interface WebhookSubscription {\n id: number;\n url: string;\n events: string[];\n active: boolean;\n secret?: string;\n owner: string;\n repo?: string;\n}\n\nexport interface WebhookDelivery {\n id: number;\n hook_id: number;\n event: string;\n action?: string;\n payload: unknown;\n status_code: number | null;\n delivered_at: string;\n duration: number | null;\n success: boolean;\n}\n\nconst MAX_DELIVERIES = 1000;\n\nexport class WebhookDispatcher {\n private subscriptions: WebhookSubscription[] = [];\n private deliveries: WebhookDelivery[] = [];\n private subscriptionIdCounter = 1;\n private deliveryIdCounter = 1;\n\n register(sub: Omit<WebhookSubscription, \"id\"> & { id?: number }): WebhookSubscription {\n const { id: explicitId, ...rest } = sub;\n const id = explicitId !== undefined ? explicitId : this.subscriptionIdCounter++;\n if (id >= this.subscriptionIdCounter) {\n this.subscriptionIdCounter = id + 1;\n }\n const subscription: WebhookSubscription = { ...rest, id };\n this.subscriptions.push(subscription);\n return subscription;\n }\n\n unregister(id: number): boolean {\n const idx = this.subscriptions.findIndex((s) => s.id === id);\n if (idx === -1) return false;\n this.subscriptions.splice(idx, 1);\n return true;\n }\n\n getSubscription(id: number): WebhookSubscription | undefined {\n return this.subscriptions.find((s) => s.id === id);\n }\n\n getSubscriptions(owner?: string, repo?: string): WebhookSubscription[] {\n return this.subscriptions.filter((s) => {\n if (owner && s.owner !== owner) return false;\n if (repo !== undefined && s.repo !== repo) return false;\n return true;\n });\n }\n\n updateSubscription(\n id: number,\n data: Partial<Pick<WebhookSubscription, \"url\" | \"events\" | \"active\" | \"secret\">>,\n ): WebhookSubscription | undefined {\n const sub = this.subscriptions.find((s) => s.id === id);\n if (!sub) return undefined;\n Object.assign(sub, data);\n return sub;\n }\n\n async dispatch(\n event: string,\n action: string | undefined,\n payload: unknown,\n owner: string,\n repo?: string,\n ): Promise<void> {\n const matchingSubs = this.subscriptions.filter((s) => {\n if (!s.active) return false;\n if (s.owner !== owner) return false;\n if (repo !== undefined) {\n if (s.repo !== repo) return false;\n } else if (s.repo !== undefined) {\n return false;\n }\n return event === \"ping\" || s.events.includes(\"*\") || s.events.includes(event);\n });\n\n for (const sub of matchingSubs) {\n const delivery: WebhookDelivery = {\n id: this.deliveryIdCounter++,\n hook_id: sub.id,\n event,\n action,\n payload,\n status_code: null,\n delivered_at: new Date().toISOString(),\n duration: null,\n success: false,\n };\n\n const body = JSON.stringify(payload);\n\n const signatureHeaders: Record<string, string> = {};\n if (sub.secret) {\n const hmac = createHmac(\"sha256\", sub.secret).update(body).digest(\"hex\");\n signatureHeaders[\"X-Hub-Signature-256\"] = `sha256=${hmac}`;\n }\n\n try {\n const start = Date.now();\n const response = await fetch(sub.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-GitHub-Event\": event,\n \"X-GitHub-Delivery\": String(delivery.id),\n ...signatureHeaders,\n },\n body,\n signal: AbortSignal.timeout(10000),\n });\n delivery.duration = Date.now() - start;\n delivery.status_code = response.status;\n delivery.success = response.ok;\n } catch {\n delivery.duration = 0;\n delivery.success = false;\n }\n\n this.deliveries.push(delivery);\n if (this.deliveries.length > MAX_DELIVERIES) {\n this.deliveries.splice(0, this.deliveries.length - MAX_DELIVERIES);\n }\n }\n }\n\n getDeliveries(hookId?: number): WebhookDelivery[] {\n if (hookId !== undefined) {\n return this.deliveries.filter((d) => d.hook_id === hookId);\n }\n return [...this.deliveries];\n }\n\n clear(): void {\n this.subscriptions.length = 0;\n this.deliveries.length = 0;\n this.subscriptionIdCounter = 1;\n this.deliveryIdCounter = 1;\n }\n}\n","import type { Context, ContentfulStatusCode, ErrorHandler, MiddlewareHandler } from \"../http.js\";\n\nconst DEFAULT_DOCS_URL = \"https://emulate.dev\";\n\nfunction getDocsUrl(c: Context): string {\n return (c.get(\"docsUrl\") as string | undefined) ?? DEFAULT_DOCS_URL;\n}\n\nfunction errorStatus(err: unknown): number {\n if (err && typeof err === \"object\" && \"status\" in err) {\n const s = (err as { status: unknown }).status;\n if (typeof s === \"number\" && Number.isFinite(s)) return s;\n }\n return 500;\n}\n\n/**\n * Use with `app.onError(...)`. Route handlers throw to the app error handler.\n */\nexport function createApiErrorHandler(documentationUrl?: string): ErrorHandler {\n return (err, c) => {\n if (documentationUrl) {\n c.set(\"docsUrl\", documentationUrl);\n }\n const status = errorStatus(err);\n const message = err instanceof Error ? err.message : \"Internal Server Error\";\n return c.json(\n {\n message,\n documentation_url: getDocsUrl(c),\n },\n status as ContentfulStatusCode,\n );\n };\n}\n\n/** Sets `docsUrl` on the context for successful responses; register `createApiErrorHandler` for thrown `ApiError`s. */\nexport function createErrorHandler(documentationUrl?: string): MiddlewareHandler {\n return async (c, next) => {\n if (documentationUrl) {\n c.set(\"docsUrl\", documentationUrl);\n }\n await next();\n };\n}\n\nexport const errorHandler: MiddlewareHandler = createErrorHandler();\n\nexport class ApiError extends Error {\n constructor(\n public status: number,\n message: string,\n public errors?: Array<{ resource: string; field: string; code: string }>,\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nexport function notFound(resource?: string): ApiError {\n return new ApiError(404, resource ? `${resource} not found` : \"Not Found\");\n}\n\nexport function validationError(message: string, errors?: ApiError[\"errors\"]): ApiError {\n return new ApiError(422, message, errors);\n}\n\nexport function unauthorized(): ApiError {\n return new ApiError(401, \"Requires authentication\");\n}\n\nexport function forbidden(): ApiError {\n return new ApiError(403, \"Forbidden\");\n}\n\nexport async function parseJsonBody(c: Context): Promise<Record<string, unknown>> {\n try {\n const body = await c.req.json();\n if (body && typeof body === \"object\" && !Array.isArray(body)) {\n return body as Record<string, unknown>;\n }\n return {};\n } catch {\n throw new ApiError(400, \"Problems parsing JSON\");\n }\n}\n","import type { Context, Next } from \"../http.js\";\nimport { jwtVerify, importPKCS8 } from \"jose\";\nimport { debug } from \"../debug.js\";\n\nexport interface AuthUser {\n login: string;\n id: number;\n scopes: string[];\n}\n\nexport interface AuthApp {\n appId: number;\n slug: string;\n name: string;\n}\n\nexport interface AuthInstallation {\n installationId: number;\n appId: number;\n permissions: Record<string, string>;\n repositoryIds: number[];\n repositorySelection: \"all\" | \"selected\";\n}\n\nexport type TokenMap = Map<string, AuthUser>;\n\nexport interface TokenEntry {\n token: string;\n login: string;\n id: number;\n scopes: string[];\n}\n\nexport function serializeTokenMap(tokenMap: TokenMap): TokenEntry[] {\n return [...tokenMap.entries()].map(([token, user]) => ({\n token,\n login: user.login,\n id: user.id,\n scopes: user.scopes,\n }));\n}\n\nexport function restoreTokenMap(tokenMap: TokenMap, tokens: TokenEntry[]): void {\n tokenMap.clear();\n for (const t of tokens) {\n tokenMap.set(t.token, { login: t.login, id: t.id, scopes: t.scopes });\n }\n}\n\nexport type AppEnv = {\n Variables: {\n authUser?: AuthUser;\n authApp?: AuthApp;\n authToken?: string;\n authScopes?: string[];\n docsUrl?: string;\n };\n};\n\nexport interface AppKeyResolver {\n (appId: number): { privateKey: string; slug: string; name: string } | null;\n}\n\nexport interface AuthFallback {\n login: string;\n id: number;\n scopes: string[];\n}\n\nexport function authMiddleware(tokens: TokenMap, appKeyResolver?: AppKeyResolver, fallbackUser?: AuthFallback) {\n return async (c: Context, next: Next) => {\n const authHeader = c.req.header(\"Authorization\");\n if (authHeader) {\n const token = authHeader.replace(/^(Bearer|token)\\s+/i, \"\").trim();\n\n if (token.startsWith(\"eyJ\") && appKeyResolver) {\n try {\n const [, payloadB64] = token.split(\".\");\n const payload = JSON.parse(Buffer.from(payloadB64, \"base64url\").toString());\n const appId = typeof payload.iss === \"string\" ? parseInt(payload.iss, 10) : payload.iss;\n\n if (typeof appId === \"number\" && !isNaN(appId)) {\n const appInfo = appKeyResolver(appId);\n if (appInfo) {\n const key = await importPKCS8(appInfo.privateKey, \"RS256\");\n await jwtVerify(token, key, { algorithms: [\"RS256\"] });\n c.set(\"authApp\", {\n appId,\n slug: appInfo.slug,\n name: appInfo.name,\n } satisfies AuthApp);\n }\n }\n } catch {\n // JWT verification failed\n }\n } else {\n let user = tokens.get(token);\n if (!user && fallbackUser && token.length > 0) {\n debug(\"auth\", \"fallback user for unknown token\", { login: fallbackUser.login, id: fallbackUser.id });\n user = { login: fallbackUser.login, id: fallbackUser.id, scopes: fallbackUser.scopes };\n }\n if (user) {\n c.set(\"authUser\", user);\n c.set(\"authToken\", token);\n c.set(\"authScopes\", user.scopes);\n }\n }\n }\n await next();\n };\n}\n\nexport function requireAuth() {\n return async (c: Context, next: Next) => {\n if (!c.get(\"authUser\")) {\n const docsUrl = (c.get(\"docsUrl\") as string | undefined) ?? \"https://emulate.dev\";\n return c.json(\n {\n message: \"Requires authentication\",\n documentation_url: docsUrl,\n },\n 401,\n );\n }\n await next();\n };\n}\n\nexport function requireAppAuth() {\n return async (c: Context, next: Next) => {\n if (!c.get(\"authApp\")) {\n const docsUrl = (c.get(\"docsUrl\") as string | undefined) ?? \"https://emulate.dev\";\n return c.json(\n {\n message: \"A JSON web token could not be decoded\",\n documentation_url: docsUrl,\n },\n 401,\n );\n }\n await next();\n };\n}\n","const isDebug =\n typeof process !== \"undefined\" &&\n (process.env.DEBUG === \"1\" || process.env.DEBUG === \"true\" || process.env.EMULATE_DEBUG === \"1\");\n\nexport function debug(label: string, ...args: unknown[]): void {\n if (isDebug) {\n console.log(`[${label}]`, ...args);\n }\n}\n","import { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport type { Hono } from \"./http.js\";\nimport type { AppEnv } from \"./middleware/auth.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nconst FONTS: Record<string, Buffer> = {\n \"geist-sans.woff2\": readFileSync(join(__dirname, \"fonts\", \"geist-sans.woff2\")),\n \"GeistPixel-Square.woff2\": readFileSync(join(__dirname, \"fonts\", \"GeistPixel-Square.woff2\")),\n};\n\nconst FAVICON = readFileSync(join(__dirname, \"fonts\", \"favicon.ico\"));\n\nexport function registerFontRoutes(app: Hono<AppEnv>): void {\n app.get(\"/_emulate/fonts/:name\", (c) => {\n const name = c.req.param(\"name\");\n const buf = FONTS[name];\n if (!buf) return c.notFound();\n return new Response(buf, {\n headers: {\n \"Content-Type\": \"font/woff2\",\n \"Cache-Control\": \"public, max-age=31536000, immutable\",\n \"Access-Control-Allow-Origin\": \"*\",\n },\n });\n });\n\n app.get(\"/_emulate/favicon.ico\", (c) => {\n return new Response(FAVICON, {\n headers: {\n \"Content-Type\": \"image/x-icon\",\n \"Cache-Control\": \"public, max-age=31536000, immutable\",\n },\n });\n });\n}\n","import { Hono, cors } from \"./http.js\";\nimport { Store } from \"./store.js\";\nimport { WebhookDispatcher } from \"./webhooks.js\";\nimport { createApiErrorHandler, createErrorHandler } from \"./middleware/error-handler.js\";\nimport {\n authMiddleware,\n type AuthFallback,\n type TokenMap,\n type AppKeyResolver,\n type AppEnv,\n} from \"./middleware/auth.js\";\nimport type { ServicePlugin } from \"./plugin.js\";\nimport { registerFontRoutes } from \"./fonts.js\";\n\nexport interface ServerOptions {\n port?: number;\n baseUrl?: string;\n docsUrl?: string;\n tokens?: Record<string, { login: string; id: number; scopes?: string[] }>;\n appKeyResolver?: AppKeyResolver;\n fallbackUser?: AuthFallback;\n}\n\nexport function createServer(plugin: ServicePlugin, options: ServerOptions = {}) {\n const port = options.port ?? 4000;\n const baseUrl = options.baseUrl ?? `http://localhost:${port}`;\n\n const app = new Hono<AppEnv>();\n const store = new Store();\n const webhooks = new WebhookDispatcher();\n\n const tokenMap: TokenMap = new Map();\n if (options.tokens) {\n for (const [token, user] of Object.entries(options.tokens)) {\n tokenMap.set(token, {\n login: user.login,\n id: user.id,\n scopes: user.scopes ?? [\"repo\", \"user\", \"admin:org\", \"admin:repo_hook\"],\n });\n }\n }\n\n const docsUrl = options.docsUrl ?? `https://emulate.dev/${plugin.name}`;\n\n registerFontRoutes(app);\n\n app.onError(createApiErrorHandler(docsUrl));\n app.use(\"*\", cors());\n app.use(\"*\", createErrorHandler(docsUrl));\n app.use(\"*\", authMiddleware(tokenMap, options.appKeyResolver, options.fallbackUser));\n\n const rateLimitCounters = new Map<string, { remaining: number; resetAt: number }>();\n let lastPruneAt = Math.floor(Date.now() / 1000);\n\n app.use(\"*\", async (c, next) => {\n const token = c.get(\"authToken\") ?? \"__anonymous__\";\n const now = Math.floor(Date.now() / 1000);\n\n if (now - lastPruneAt > 3600) {\n for (const [key, val] of rateLimitCounters) {\n if (val.resetAt <= now) rateLimitCounters.delete(key);\n }\n lastPruneAt = now;\n }\n\n let counter = rateLimitCounters.get(token);\n if (!counter || counter.resetAt <= now) {\n counter = { remaining: 5000, resetAt: now + 3600 };\n rateLimitCounters.set(token, counter);\n }\n\n counter.remaining = Math.max(0, counter.remaining - 1);\n\n c.header(\"X-RateLimit-Limit\", \"5000\");\n c.header(\"X-RateLimit-Remaining\", String(counter.remaining));\n c.header(\"X-RateLimit-Reset\", String(counter.resetAt));\n c.header(\"X-RateLimit-Resource\", \"core\");\n\n if (counter.remaining === 0) {\n return c.json(\n {\n message: \"API rate limit exceeded\",\n documentation_url: docsUrl,\n },\n 403,\n );\n }\n\n await next();\n });\n\n plugin.register(app, store, webhooks, baseUrl, tokenMap);\n\n app.notFound((c) =>\n c.json(\n {\n message: \"Not Found\",\n documentation_url: docsUrl,\n },\n 404,\n ),\n );\n\n return { app, store, webhooks, port, baseUrl, tokenMap };\n}\n","import type { Context } from \"../http.js\";\n\nexport interface PaginationParams {\n page: number;\n per_page: number;\n}\n\nexport function parsePagination(c: Context): PaginationParams {\n const page = Math.max(1, parseInt(c.req.query(\"page\") ?? \"1\", 10) || 1);\n const per_page = Math.min(100, Math.max(1, parseInt(c.req.query(\"per_page\") ?? \"30\", 10) || 30));\n return { page, per_page };\n}\n\nexport function setLinkHeader(c: Context, totalCount: number, page: number, perPage: number): void {\n const lastPage = Math.max(1, Math.ceil(totalCount / perPage));\n const baseUrl = new URL(c.req.url);\n const links: string[] = [];\n\n const makeLink = (p: number, rel: string) => {\n baseUrl.searchParams.set(\"page\", String(p));\n baseUrl.searchParams.set(\"per_page\", String(perPage));\n return `<${baseUrl.toString()}>; rel=\"${rel}\"`;\n };\n\n if (page < lastPage) {\n links.push(makeLink(page + 1, \"next\"));\n links.push(makeLink(lastPage, \"last\"));\n }\n if (page > 1) {\n links.push(makeLink(1, \"first\"));\n links.push(makeLink(page - 1, \"prev\"));\n }\n\n if (links.length > 0) {\n c.header(\"Link\", links.join(\", \"));\n }\n}\n","export function escapeHtml(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n}\n\nexport function escapeAttr(s: string): string {\n return escapeHtml(s).replace(/'/g, \"'\");\n}\n\nconst CSS = `\n@font-face{\n font-family:'Geist';font-style:normal;font-weight:100 900;font-display:swap;\n src:url('/_emulate/fonts/geist-sans.woff2') format('woff2');\n}\n@font-face{\n font-family:'Geist Pixel';font-style:normal;font-weight:400;font-display:swap;\n src:url('/_emulate/fonts/GeistPixel-Square.woff2') format('woff2');\n}\n*{box-sizing:border-box;margin:0;padding:0}\nbody{\n font-family:'Geist',-apple-system,BlinkMacSystemFont,sans-serif;\n background:#000;color:#33ff00;min-height:100vh;\n -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;\n}\n.emu-bar{\n border-bottom:1px solid #0a3300;padding:10px 20px;\n display:flex;align-items:center;gap:10px;font-size:.8125rem;color:#1a8c00;\n}\n.emu-bar-title{font-weight:600;color:#33ff00;font-family:'Geist Pixel',monospace;}\n.emu-bar-links{margin-left:auto;display:flex;gap:16px;}\n.emu-bar-links a{\n color:#1a8c00;font-size:.75rem;text-decoration:none;transition:color .15s;\n}\n.emu-bar-links a:hover{color:#33ff00;}\n.emu-bar-links a .full{display:inline;}\n.emu-bar-links a .short{display:none;}\n@media(max-width:600px){\n .emu-bar-links a .full{display:none;}\n .emu-bar-links a .short{display:inline;}\n}\n\n.content{\n display:flex;align-items:center;justify-content:center;\n min-height:calc(100vh - 42px);padding:24px 16px;\n}\n.content-inner{width:100%;max-width:420px;}\n.card-title{\n font-family:'Geist Pixel',monospace;\n font-size:1.125rem;font-weight:600;margin-bottom:4px;color:#33ff00;\n}\n.card-subtitle{color:#1a8c00;font-size:.8125rem;margin-bottom:18px;line-height:1.45;}\n.powered-by{\n position:fixed;bottom:0;left:0;right:0;\n text-align:center;padding:12px;font-size:.6875rem;color:#0a3300;\n font-family:'Geist Pixel',monospace;\n}\n.powered-by a{color:#1a8c00;text-decoration:none;transition:color .15s;}\n.powered-by a:hover{color:#33ff00;}\n\n.error-title{\n font-family:'Geist Pixel',monospace;\n color:#ff4444;font-size:1.125rem;font-weight:600;margin-bottom:8px;\n}\n.error-msg{color:#1a8c00;font-size:.875rem;line-height:1.5;}\n.error-card{text-align:center;}\n\n.user-form{margin-bottom:8px;}\n.user-form:last-of-type{margin-bottom:0;}\n.user-btn{\n width:100%;display:flex;align-items:center;gap:12px;\n padding:10px 12px;border:1px solid #0a3300;border-radius:8px;\n background:#000;color:inherit;cursor:pointer;text-align:left;\n font:inherit;transition:border-color .15s;\n}\n.user-btn:hover{border-color:#33ff00;}\n.avatar{\n width:36px;height:36px;border-radius:50%;\n background:#0a3300;color:#33ff00;font-weight:600;font-size:.875rem;\n display:flex;align-items:center;justify-content:center;flex-shrink:0;\n font-family:'Geist Pixel',monospace;\n}\n.user-text{min-width:0;}\n.user-login{font-weight:600;font-size:.875rem;display:block;color:#33ff00;}\n.user-meta{color:#1a8c00;font-size:.75rem;margin-top:1px;}\n.user-email{font-size:.6875rem;color:#116600;word-break:break-all;margin-top:1px;}\n\n.settings-layout{\n max-width:920px;margin:0 auto;padding:28px 20px;\n display:flex;gap:28px;\n}\n.settings-sidebar{width:200px;flex-shrink:0;}\n.settings-sidebar a{\n display:block;padding:6px 10px;border-radius:6px;color:#1a8c00;\n text-decoration:none;font-size:.8125rem;transition:color .15s;\n}\n.settings-sidebar a:hover{color:#33ff00;}\n.settings-sidebar a.active{color:#33ff00;font-weight:600;}\n.settings-main{flex:1;min-width:0;}\n\n.s-card{\n padding:18px 0;margin-bottom:14px;border-bottom:1px solid #0a3300;\n}\n.s-card:last-child{border-bottom:none;}\n.s-card-header{display:flex;align-items:center;gap:14px;margin-bottom:14px;}\n.s-icon{\n width:42px;height:42px;border-radius:8px;\n background:#0a3300;display:flex;align-items:center;justify-content:center;\n font-size:1.125rem;font-weight:700;color:#116600;flex-shrink:0;\n font-family:'Geist Pixel',monospace;\n}\n.s-title{\n font-family:'Geist Pixel',monospace;\n font-size:1.25rem;font-weight:600;color:#33ff00;\n}\n.s-subtitle{font-size:.75rem;color:#1a8c00;margin-top:2px;}\n.section-heading{\n font-size:.9375rem;font-weight:600;margin-bottom:10px;color:#33ff00;\n display:flex;align-items:center;justify-content:space-between;\n}\n.perm-list{list-style:none;}\n.perm-list li{padding:5px 0;font-size:.8125rem;display:flex;align-items:center;gap:6px;color:#1a8c00;}\n.check{color:#33ff00;}\n.org-row{\n display:flex;align-items:center;gap:8px;padding:7px 0;\n border-bottom:1px solid #0a3300;font-size:.8125rem;\n}\n.org-row:last-child{border-bottom:none;}\n.org-icon{\n width:22px;height:22px;border-radius:4px;background:#0a3300;\n display:flex;align-items:center;justify-content:center;\n font-size:.625rem;font-weight:700;color:#116600;flex-shrink:0;\n font-family:'Geist Pixel',monospace;\n}\n.org-name{font-weight:600;color:#33ff00;}\n.badge{font-size:.6875rem;padding:1px 7px;border-radius:999px;font-weight:500;}\n.badge-granted{background:#0a3300;color:#33ff00;}\n.badge-denied{background:#1a0a0a;color:#ff4444;}\n.badge-requested{background:#0a3300;color:#1a8c00;}\n.btn-revoke{\n display:inline-block;padding:5px 14px;border-radius:6px;\n border:1px solid #0a3300;background:transparent;color:#ff4444;\n font-size:.75rem;font-weight:600;cursor:pointer;transition:border-color .15s;\n}\n.btn-revoke:hover{border-color:#ff4444;}\n.info-text{color:#1a8c00;font-size:.75rem;line-height:1.5;margin-top:10px;}\n.app-link{\n display:flex;align-items:center;gap:12px;padding:12px;\n border:1px solid #0a3300;border-radius:8px;background:#000;\n text-decoration:none;color:inherit;margin-bottom:8px;transition:border-color .15s;\n}\n.app-link:hover{border-color:#33ff00;}\n.app-link-name{font-weight:600;font-size:.875rem;color:#33ff00;}\n.app-link-scopes{font-size:.6875rem;color:#1a8c00;margin-top:1px;}\n.empty{color:#1a8c00;text-align:center;padding:28px 0;font-size:.875rem;}\n\n.inspector-layout{max-width:960px;margin:0 auto;padding:28px 20px;}\n.inspector-tabs{display:flex;gap:4px;margin-bottom:20px;}\n.inspector-tabs a{\n padding:7px 16px;border-radius:6px;text-decoration:none;\n font-size:.8125rem;color:#1a8c00;border:1px solid transparent;\n transition:color .15s,border-color .15s;\n}\n.inspector-tabs a:hover{color:#33ff00;}\n.inspector-tabs a.active{color:#33ff00;font-weight:600;border-color:#0a3300;background:#0a3300;}\n.inspector-section{margin-bottom:24px;}\n.inspector-section h2{\n font-family:'Geist Pixel',monospace;\n font-size:1rem;font-weight:600;color:#33ff00;margin-bottom:10px;\n}\n.inspector-section h3{\n font-family:'Geist Pixel',monospace;\n font-size:.875rem;font-weight:600;color:#1a8c00;margin:16px 0 8px;\n}\n.inspector-table{width:100%;border-collapse:collapse;margin-bottom:12px;}\n.inspector-table th,.inspector-table td{\n text-align:left;padding:8px 12px;border-bottom:1px solid #0a3300;\n font-size:.8125rem;\n}\n.inspector-table th{color:#1a8c00;font-weight:600;font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;}\n.inspector-table td{color:#33ff00;}\n.inspector-table tbody tr{transition:background .1s;}\n.inspector-table tbody tr:hover{background:#0a3300;}\n.inspector-empty{color:#1a8c00;text-align:center;padding:20px 0;font-size:.8125rem;}\n\n.checkout-layout{\n display:flex;min-height:calc(100vh - 42px);\n}\n.checkout-summary{\n flex:1;background:#020;padding:48px 40px 48px 10%;\n display:flex;flex-direction:column;justify-content:center;\n border-right:1px solid #0a3300;\n}\n.checkout-form-side{\n flex:1;background:#000;padding:48px 10% 48px 40px;\n display:flex;flex-direction:column;justify-content:center;\n}\n.checkout-merchant{\n display:flex;align-items:center;gap:10px;margin-bottom:6px;\n}\n.checkout-merchant-name{\n font-family:'Geist Pixel',monospace;\n font-size:.9375rem;font-weight:600;color:#33ff00;\n}\n.checkout-test-badge{\n font-size:.625rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;\n background:#0a3300;color:#1a8c00;padding:2px 8px;border-radius:4px;\n}\n.checkout-total{\n font-family:'Geist Pixel',monospace;\n font-size:2rem;font-weight:700;color:#33ff00;margin:8px 0 28px;\n}\n.checkout-line-item{\n display:flex;align-items:center;gap:14px;padding:14px 0;\n border-bottom:1px solid #0a3300;\n}\n.checkout-line-item:first-child{border-top:1px solid #0a3300;}\n.checkout-item-icon{\n width:42px;height:42px;border-radius:6px;background:#0a3300;\n display:flex;align-items:center;justify-content:center;flex-shrink:0;\n font-family:'Geist Pixel',monospace;font-size:.875rem;font-weight:700;color:#116600;\n}\n.checkout-item-details{flex:1;min-width:0;}\n.checkout-item-name{font-size:.875rem;font-weight:600;color:#33ff00;}\n.checkout-item-qty{font-size:.75rem;color:#1a8c00;margin-top:2px;}\n.checkout-item-price{\n font-size:.875rem;font-weight:600;color:#33ff00;text-align:right;white-space:nowrap;\n}\n.checkout-item-unit{font-size:.6875rem;color:#1a8c00;text-align:right;margin-top:2px;}\n.checkout-totals{margin-top:20px;}\n.checkout-totals-row{\n display:flex;justify-content:space-between;padding:6px 0;\n font-size:.8125rem;color:#1a8c00;\n}\n.checkout-totals-row.total{\n border-top:1px solid #0a3300;margin-top:8px;padding-top:14px;\n font-size:.9375rem;font-weight:600;color:#33ff00;\n}\n.checkout-form-section{margin-bottom:24px;}\n.checkout-form-label{\n font-size:.8125rem;font-weight:600;color:#33ff00;margin-bottom:8px;display:block;\n}\n.checkout-input{\n width:100%;padding:10px 12px;border:1px solid #0a3300;border-radius:6px;\n background:#020;color:#33ff00;font:inherit;font-size:.875rem;\n transition:border-color .15s;outline:none;\n}\n.checkout-input:focus{border-color:#33ff00;}\n.checkout-input::placeholder{color:#116600;}\n.checkout-card-box{\n border:1px solid #0a3300;border-radius:6px;padding:14px;\n background:#020;\n}\n.checkout-card-row{\n display:flex;gap:12px;margin-top:10px;\n}\n.checkout-card-row .checkout-input{flex:1;}\n.checkout-sim-note{\n font-size:.6875rem;color:#1a8c00;margin-top:10px;text-align:center;\n font-style:italic;\n}\n.checkout-pay-btn{\n width:100%;padding:14px;border:none;border-radius:8px;\n background:#33ff00;color:#000;font:inherit;font-size:.9375rem;font-weight:700;\n cursor:pointer;transition:background .15s;\n font-family:'Geist Pixel',monospace;\n}\n.checkout-pay-btn:hover{background:#44ff22;}\n.checkout-cancel{\n text-align:center;margin-top:14px;\n}\n.checkout-cancel a{\n color:#1a8c00;text-decoration:none;font-size:.8125rem;\n transition:color .15s;\n}\n.checkout-cancel a:hover{color:#33ff00;}\n@media(max-width:768px){\n .checkout-layout{flex-direction:column;}\n .checkout-summary{padding:32px 20px;border-right:none;border-bottom:1px solid #0a3300;}\n .checkout-form-side{padding:32px 20px;}\n}\n`;\n\nconst POWERED_BY = `<div class=\"powered-by\">Powered by <a href=\"https://emulate.dev\" target=\"_blank\" rel=\"noopener\">emulate</a></div>`;\n\nfunction emuBar(service?: string): string {\n const title = service ? `${escapeHtml(service)} Emulator` : \"Emulator\";\n return `<div class=\"emu-bar\">\n <span class=\"emu-bar-title\">${title}</span>\n <nav class=\"emu-bar-links\">\n <a href=\"https://github.com/vercel-labs/emulate/issues\" target=\"_blank\" rel=\"noopener\"><span class=\"full\">Report Issue</span><span class=\"short\">Report</span></a>\n <a href=\"https://github.com/vercel-labs/emulate\" target=\"_blank\" rel=\"noopener\"><span class=\"full\">Source Code</span><span class=\"short\">Source</span></a>\n <a href=\"https://emulate.dev\" target=\"_blank\" rel=\"noopener\"><span class=\"full\">Learn More</span><span class=\"short\">Learn</span></a>\n </nav>\n</div>`;\n}\n\nfunction head(title: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\"/>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/>\n<link rel=\"icon\" href=\"/_emulate/favicon.ico\"/>\n<title>${escapeHtml(title)} | emulate</title>\n<style>${CSS}</style>\n</head>`;\n}\n\nexport function renderCardPage(title: string, subtitle: string, body: string, service?: string): string {\n return `${head(title)}\n<body>\n${emuBar(service)}\n<div class=\"content\">\n <div class=\"content-inner\">\n <div class=\"card-title\">${escapeHtml(title)}</div>\n <div class=\"card-subtitle\">${subtitle}</div>\n ${body}\n </div>\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport function renderErrorPage(title: string, message: string, service?: string): string {\n return `${head(title)}\n<body>\n${emuBar(service)}\n<div class=\"content\">\n <div class=\"content-inner error-card\">\n <div class=\"error-title\">${escapeHtml(title)}</div>\n <div class=\"error-msg\">${escapeHtml(message)}</div>\n </div>\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport function renderSettingsPage(title: string, sidebarHtml: string, bodyHtml: string, service?: string): string {\n return `${head(title)}\n<body>\n${emuBar(service)}\n<div class=\"settings-layout\">\n <nav class=\"settings-sidebar\">${sidebarHtml}</nav>\n <div class=\"settings-main\">${bodyHtml}</div>\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport interface InspectorTab {\n id: string;\n label: string;\n href: string;\n}\n\nexport function renderInspectorPage(\n title: string,\n tabs: InspectorTab[],\n activeTab: string,\n body: string,\n service?: string,\n): string {\n const tabLinks = tabs\n .map(\n (t) => `<a href=\"${escapeAttr(t.href)}\" class=\"${t.id === activeTab ? \"active\" : \"\"}\">${escapeHtml(t.label)}</a>`,\n )\n .join(\"\");\n\n return `${head(title)}\n<body>\n${emuBar(service)}\n<div class=\"inspector-layout\">\n <nav class=\"inspector-tabs\">${tabLinks}</nav>\n ${body}\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport function renderFormPostPage(action: string, fields: Record<string, string>, service?: string): string {\n const hiddens = Object.entries(fields)\n .filter(([, v]) => v != null)\n .map(([k, v]) => `<input type=\"hidden\" name=\"${escapeAttr(k)}\" value=\"${escapeAttr(v)}\"/>`)\n .join(\"\\n\");\n\n return `${head(\"Redirecting\")}\n<body onload=\"document.forms[0].submit()\">\n${emuBar(service)}\n<div class=\"content\">\n <div class=\"content-inner\" style=\"text-align:center\">\n <div class=\"card-subtitle\">Redirecting…</div>\n <form method=\"POST\" action=\"${escapeAttr(action)}\">\n${hiddens}\n <noscript><button type=\"submit\" class=\"user-btn\" style=\"margin-top:12px;justify-content:center\">\n <span class=\"user-login\">Continue</span>\n </button></noscript>\n </form>\n </div>\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport interface CheckoutLineItem {\n name: string;\n quantity: number;\n unitPrice: number;\n totalPrice: number;\n currency: string;\n}\n\nexport interface CheckoutPageOptions {\n merchantName?: string;\n lineItems: CheckoutLineItem[];\n subtotal: number;\n total: number;\n currency: string;\n sessionId: string;\n cancelUrl?: string | null;\n}\n\nexport function renderCheckoutPage(opts: CheckoutPageOptions, service?: string): string {\n const fmt = (cents: number, cur: string) => `$${(cents / 100).toFixed(2)} ${cur.toUpperCase()}`;\n const fmtShort = (cents: number) => `$${(cents / 100).toFixed(2)}`;\n\n const itemsHtml =\n opts.lineItems.length > 0\n ? opts.lineItems\n .map((li) => {\n const initial = li.name.charAt(0).toUpperCase();\n const unitNote =\n li.quantity > 1 ? `<div class=\"checkout-item-unit\">${fmtShort(li.unitPrice)} each</div>` : \"\";\n return `<div class=\"checkout-line-item\">\n <div class=\"checkout-item-icon\">${escapeHtml(initial)}</div>\n <div class=\"checkout-item-details\">\n <div class=\"checkout-item-name\">${escapeHtml(li.name)}</div>\n <div class=\"checkout-item-qty\">Qty ${li.quantity}</div>\n </div>\n <div>\n <div class=\"checkout-item-price\">${fmtShort(li.totalPrice)}</div>\n ${unitNote}\n </div>\n</div>`;\n })\n .join(\"\")\n : '<p class=\"empty\">No line items</p>';\n\n const totalsHtml = `<div class=\"checkout-totals\">\n <div class=\"checkout-totals-row\">\n <span>Subtotal</span><span>${fmtShort(opts.subtotal)}</span>\n </div>\n <div class=\"checkout-totals-row total\">\n <span>Total due</span><span>${fmt(opts.total, opts.currency)}</span>\n </div>\n</div>`;\n\n const cancelHtml = opts.cancelUrl\n ? `<div class=\"checkout-cancel\"><a href=\"${escapeAttr(opts.cancelUrl)}\">Cancel</a></div>`\n : \"\";\n\n const merchant = opts.merchantName ? escapeHtml(opts.merchantName) : \"Checkout\";\n\n return `${head(\"Checkout\")}\n<body>\n${emuBar(service)}\n<div class=\"checkout-layout\">\n <div class=\"checkout-summary\">\n <div class=\"checkout-merchant\">\n <span class=\"checkout-merchant-name\">${merchant}</span>\n <span class=\"checkout-test-badge\">Test Mode</span>\n </div>\n <div class=\"checkout-total\">${fmtShort(opts.total)}</div>\n ${itemsHtml}\n ${totalsHtml}\n </div>\n <div class=\"checkout-form-side\">\n <form method=\"post\" action=\"/checkout/${escapeAttr(opts.sessionId)}/complete\">\n <div class=\"checkout-form-section\">\n <label class=\"checkout-form-label\">Email</label>\n <input type=\"email\" name=\"email\" class=\"checkout-input\" placeholder=\"you@example.com\"/>\n </div>\n <div class=\"checkout-form-section\">\n <label class=\"checkout-form-label\">Card information</label>\n <div class=\"checkout-card-box\">\n <input type=\"text\" class=\"checkout-input\" placeholder=\"1234 1234 1234 1234\" disabled/>\n <div class=\"checkout-card-row\">\n <input type=\"text\" class=\"checkout-input\" placeholder=\"MM / YY\" disabled/>\n <input type=\"text\" class=\"checkout-input\" placeholder=\"CVC\" disabled/>\n </div>\n </div>\n <div class=\"checkout-sim-note\">Card fields are simulated. Payment will be auto-approved.</div>\n </div>\n <button type=\"submit\" class=\"checkout-pay-btn\">Pay ${fmtShort(opts.total)}</button>\n </form>\n ${cancelHtml}\n </div>\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport interface UserButtonOptions {\n letter: string;\n login: string;\n name?: string;\n email?: string;\n formAction: string;\n hiddenFields: Record<string, string>;\n}\n\nexport function renderUserButton(opts: UserButtonOptions): string {\n const hiddens = Object.entries(opts.hiddenFields)\n .map(([k, v]) => `<input type=\"hidden\" name=\"${escapeAttr(k)}\" value=\"${escapeAttr(v)}\"/>`)\n .join(\"\");\n\n const nameLine = opts.name ? `<div class=\"user-meta\">${escapeHtml(opts.name)}</div>` : \"\";\n const emailLine = opts.email ? `<div class=\"user-email\">${escapeHtml(opts.email)}</div>` : \"\";\n\n return `<form class=\"user-form\" method=\"post\" action=\"${escapeAttr(opts.formAction)}\">\n${hiddens}\n<button type=\"submit\" class=\"user-btn\">\n <span class=\"avatar\">${escapeHtml(opts.letter)}</span>\n <span class=\"user-text\">\n <span class=\"user-login\">${escapeHtml(opts.login)}</span>\n ${nameLine}${emailLine}\n </span>\n</button>\n</form>`;\n}\n","import { timingSafeEqual } from \"crypto\";\n\nexport function normalizeUri(uri: string): string {\n try {\n const u = new URL(uri);\n return `${u.origin}${u.pathname.replace(/\\/+$/, \"\")}`;\n } catch {\n return uri.replace(/\\/+$/, \"\").split(\"?\")[0];\n }\n}\n\nexport function matchesRedirectUri(incoming: string, registered: string[]): boolean {\n const normalized = normalizeUri(incoming);\n return registered.some((r) => normalizeUri(r) === normalized);\n}\n\nexport function constantTimeSecretEqual(a: string, b: string): boolean {\n const bufA = Buffer.from(a, \"utf-8\");\n const bufB = Buffer.from(b, \"utf-8\");\n if (bufA.length !== bufB.length) return false;\n return timingSafeEqual(bufA, bufB);\n}\n\nexport function bodyStr(v: unknown): string {\n if (typeof v === \"string\") return v;\n if (Array.isArray(v) && typeof v[0] === \"string\") return v[0];\n return \"\";\n}\n\nexport function parseCookies(header: string): Record<string, string> {\n const cookies: Record<string, string> = {};\n for (const part of header.split(\";\")) {\n const [k, ...v] = part.split(\"=\");\n if (k) cookies[k.trim()] = v.join(\"=\").trim();\n }\n return cookies;\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nexport interface PersistenceAdapter {\n load(): Promise<string | null>;\n save(data: string): Promise<void>;\n}\n\nexport function filePersistence(path: string): PersistenceAdapter {\n return {\n async load() {\n try {\n return await readFile(path, \"utf-8\");\n } catch {\n return null;\n }\n },\n async save(data: string) {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, data, \"utf-8\");\n },\n };\n}\n","import type { RouteContext } from \"@emulators/core\";\nimport { getSlackStore } from \"../store.js\";\nimport { formatSlackMessage, generateTs, hasSlackMessageContent, parseSlackRichMessageFields } from \"../helpers.js\";\n\nexport function webhookRoutes(ctx: RouteContext): void {\n const { app, store, webhooks } = ctx;\n const ss = () => getSlackStore(store);\n const findChannel = (channel: string) =>\n ss().channels.findOneBy(\"channel_id\", channel) ??\n ss()\n .channels.all()\n .find((ch) => !ch.is_im && !ch.is_mpim && ch.name === channel);\n\n // Incoming Webhooks - POST /services/:teamId/:botId/:token\n // The simplest Slack integration: apps POST JSON to send a message to a channel.\n app.post(\"/services/:teamId/:botId/:token\", async (c) => {\n const contentType = c.req.header(\"Content-Type\") ?? \"\";\n const rawText = await c.req.text();\n\n let body: Record<string, unknown>;\n if (contentType.includes(\"application/json\")) {\n try {\n body = JSON.parse(rawText);\n } catch {\n return c.text(\"invalid_payload\", 400);\n }\n } else {\n // Slack also accepts form-urlencoded with a \"payload\" field\n const params = new URLSearchParams(rawText);\n const payload = params.get(\"payload\");\n if (payload) {\n try {\n body = JSON.parse(payload);\n } catch {\n return c.text(\"invalid_payload\", 400);\n }\n } else {\n body = {};\n }\n }\n\n const text = typeof body.text === \"string\" ? body.text : \"\";\n const channelName = typeof body.channel === \"string\" ? body.channel : \"\";\n const threadTs = typeof body.thread_ts === \"string\" ? body.thread_ts : undefined;\n const richMessage = parseSlackRichMessageFields(body);\n if (richMessage.error) {\n return c.text(richMessage.error, 400);\n }\n\n if (!hasSlackMessageContent(text, richMessage.fields)) {\n return c.text(\"no_text\", 400);\n }\n\n // Find target channel: explicit channel, webhook default, or #general\n const webhook = ss()\n .incomingWebhooks.all()\n .find((w) => w.token === c.req.param(\"token\"));\n\n let targetChannel = channelName ? findChannel(channelName) : null;\n\n if (!targetChannel && webhook) {\n targetChannel = findChannel(webhook.default_channel);\n }\n\n if (!targetChannel) {\n targetChannel = findChannel(\"general\");\n }\n\n if (!targetChannel) {\n return c.text(\"channel_not_found\", 404);\n }\n\n const ts = generateTs();\n const botId = c.req.param(\"botId\");\n\n const msg = ss().messages.insert({\n ts,\n channel_id: targetChannel.channel_id,\n user: botId,\n text,\n type: \"message\" as const,\n subtype: \"bot_message\",\n thread_ts: threadTs,\n ...richMessage.fields,\n bot_id: botId,\n reply_count: 0,\n reply_users: [],\n reactions: [],\n });\n\n const { user: _user, ...eventMessage } = formatSlackMessage(msg);\n\n await webhooks.dispatch(\n \"message\",\n undefined,\n {\n type: \"event_callback\",\n event: {\n ...eventMessage,\n type: \"message\",\n subtype: \"bot_message\",\n channel: targetChannel.channel_id,\n bot_id: botId,\n },\n },\n \"slack\",\n );\n\n return c.text(\"ok\");\n });\n}\n","import type { Context, RouteContext } from \"@emulators/core\";\nimport type {\n SlackChannel,\n SlackFile,\n SlackFileShare,\n SlackFileUploadSession,\n SlackJsonObject,\n SlackMessage,\n SlackUser,\n} from \"../entities.js\";\nimport { getSlackStore } from \"../store.js\";\nimport {\n formatSlackFile,\n formatSlackMessage,\n generateSlackId,\n generateTs,\n parseSlackBody,\n requireSlackScopes,\n slackError,\n slackOk,\n} from \"../helpers.js\";\n\nexport function filesRoutes(ctx: RouteContext): void {\n const { app, store, webhooks, baseUrl } = ctx;\n const ss = () => getSlackStore(store);\n const serviceBaseUrl = baseUrl.replace(/\\/$/, \"\");\n const getAuthSlackUser = (authUser: { login: string }) =>\n ss().users.findOneBy(\"user_id\", authUser.login) ?? ss().users.findOneBy(\"name\", authUser.login);\n const getAuthUserId = (authUser: { login: string }) => getAuthSlackUser(authUser)?.user_id ?? authUser.login;\n const isChannelMember = (channel: SlackChannel, user: SlackUser | undefined, userId: string) =>\n channel.members.includes(userId) || (user ? channel.members.includes(user.name) : false);\n const canReadConversation = (channel: SlackChannel, user: SlackUser | undefined, userId: string) =>\n !channel.is_private || isChannelMember(channel, user, userId);\n const visibleFileChannelIds = (file: SlackFile, authUser: { login: string }) => {\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = authSlackUser?.user_id ?? authUser.login;\n return fileChannels(file).filter((channelId) => {\n const channel = ss().channels.findOneBy(\"channel_id\", channelId);\n return channel ? canReadConversation(channel, authSlackUser, authUserId) : false;\n });\n };\n const canAccessFile = (file: SlackFile, authUser: { login: string }) => {\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = authSlackUser?.user_id ?? authUser.login;\n if (file.user === authUserId || (authSlackUser && file.user === authSlackUser.name)) return true;\n return visibleFileChannelIds(file, authUser).length > 0;\n };\n const canAccessFileInChannel = (file: SlackFile, authUser: { login: string }, channelId: string) => {\n return visibleFileChannelIds(file, authUser).includes(channelId);\n };\n const formatSlackFileForAuth = (file: SlackFile, authUser: { login: string }) => {\n const visibleIds = new Set(visibleFileChannelIds(file, authUser));\n const publicShares = filterVisibleShares(file.shares.public, visibleIds);\n const privateShares = filterVisibleShares(file.shares.private, visibleIds);\n const shares: SlackFile[\"shares\"] = {};\n if (publicShares) shares.public = publicShares;\n if (privateShares) shares.private = privateShares;\n\n return formatSlackFile({\n ...file,\n channels: file.channels.filter((channelId) => visibleIds.has(channelId)),\n groups: file.groups.filter((channelId) => visibleIds.has(channelId)),\n ims: file.ims.filter((channelId) => visibleIds.has(channelId)),\n shares,\n });\n };\n const canDeleteFile = (file: SlackFile, authUser: { login: string }) => {\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = authSlackUser?.user_id ?? authUser.login;\n return file.user === authUserId || authSlackUser?.is_admin === true;\n };\n const findChannel = (channel: string) =>\n ss().channels.findOneBy(\"channel_id\", channel) ??\n ss()\n .channels.all()\n .find((ch) => !ch.is_im && !ch.is_mpim && ch.name === channel);\n\n type ShareTargetRef = { key: string; channel?: SlackChannel; directUserId?: string };\n\n const findDirectMessage = (authUserId: string, userId: string) => {\n const members = [authUserId, userId].sort();\n return ss()\n .channels.all()\n .find(\n (ch) =>\n ch.is_im && ch.members.length === members.length && [...ch.members].sort().join(\",\") === members.join(\",\"),\n );\n };\n\n const findOrCreateDirectMessage = (authUser: { login: string }, userId: string) => {\n const targetUser = ss().users.findOneBy(\"user_id\", userId);\n if (!targetUser || targetUser.deleted) return undefined;\n\n const authUserId = getAuthUserId(authUser);\n if (targetUser.user_id === authUserId) return undefined;\n\n const members = [authUserId, targetUser.user_id].sort();\n const existing = findDirectMessage(authUserId, targetUser.user_id);\n if (existing) return existing;\n\n const team = ss().teams.all()[0];\n const now = Math.floor(Date.now() / 1000);\n return ss().channels.insert({\n channel_id: generateSlackId(\"D\"),\n team_id: team?.team_id ?? \"T000000001\",\n name: targetUser.name,\n is_channel: false,\n is_private: true,\n is_im: true,\n is_mpim: false,\n is_open_by_user: { [authUserId]: true },\n user: targetUser.user_id,\n is_archived: false,\n topic: { value: \"\", creator: authUserId, last_set: now },\n purpose: { value: \"\", creator: authUserId, last_set: now },\n members,\n creator: authUserId,\n num_members: members.length,\n last_read: {},\n });\n };\n\n const resolveShareTarget = (authUser: { login: string }, channel: string): ShareTargetRef | undefined => {\n const existingChannel = findChannel(channel);\n if (existingChannel) return { key: existingChannel.channel_id, channel: existingChannel };\n if (!channel.startsWith(\"U\")) return undefined;\n\n const targetUser = ss().users.findOneBy(\"user_id\", channel);\n if (!targetUser || targetUser.deleted) return undefined;\n\n const authUserId = getAuthUserId(authUser);\n if (targetUser.user_id === authUserId) return undefined;\n\n const existingDirectMessage = findDirectMessage(authUserId, targetUser.user_id);\n if (existingDirectMessage) return { key: existingDirectMessage.channel_id, channel: existingDirectMessage };\n return { key: `user:${targetUser.user_id}`, directUserId: targetUser.user_id };\n };\n\n app.post(\"/api/files.getUploadURLExternal\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"files:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const filename = typeof body.filename === \"string\" ? body.filename.trim() : \"\";\n const length = Number(body.length);\n const altTxt = typeof body.alt_text === \"string\" ? body.alt_text : undefined;\n const snippetType = typeof body.snippet_type === \"string\" ? body.snippet_type : undefined;\n\n if (!filename || !Number.isFinite(length) || length < 0) return slackError(c, \"invalid_arguments\");\n\n const team = ss().teams.all()[0];\n const fileId = generateSlackId(\"F\");\n const uploadUrl = `${serviceBaseUrl}/upload/v1/${fileId}`;\n ss().fileUploadSessions.insert({\n file_id: fileId,\n team_id: team?.team_id ?? \"T000000001\",\n user: getAuthUserId(authUser),\n filename,\n title: filename,\n length: Math.floor(length),\n upload_url: uploadUrl,\n alt_txt: altTxt,\n snippet_type: snippetType,\n uploaded: false,\n completed: false,\n });\n\n return slackOk(c, { upload_url: uploadUrl, file_id: fileId });\n });\n\n app.post(\"/upload/v1/:fileId\", async (c) => {\n const session = ss().fileUploadSessions.findOneBy(\"file_id\", c.req.param(\"fileId\"));\n if (!session || session.completed) return c.text(\"file_not_found\", 404);\n\n const data = await readUploadBytes(c);\n if (!data) return c.text(\"invalid_upload\", 400);\n\n ss().fileUploadSessions.update(session.id, {\n uploaded: true,\n uploaded_size: data.byteLength,\n content_base64: data.toString(\"base64\"),\n });\n return c.text(\"OK\");\n });\n\n app.post(\"/api/files.completeUploadExternal\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"files:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const requestedFiles = parseCompleteFiles(body.files);\n if (!requestedFiles || requestedFiles.length === 0) return slackError(c, \"invalid_arguments\");\n if (new Set(requestedFiles.map((file) => file.id)).size !== requestedFiles.length) {\n return slackError(c, \"invalid_arguments\");\n }\n\n const authUserId = getAuthUserId(authUser);\n const initialComment = typeof body.initial_comment === \"string\" ? body.initial_comment : \"\";\n const threadTs = typeof body.thread_ts === \"string\" ? body.thread_ts : undefined;\n const blocks = initialComment ? undefined : parseBlocks(body.blocks);\n if (!initialComment && body.blocks !== undefined && blocks === undefined) return slackError(c, \"invalid_blocks\");\n\n const requestedSessions: SlackFileUploadSession[] = [];\n for (const requestedFile of requestedFiles) {\n const session = ss().fileUploadSessions.findOneBy(\"file_id\", requestedFile.id);\n if (!session || !session.uploaded || session.completed || session.user !== authUserId) {\n return slackError(c, \"file_not_found\");\n }\n requestedSessions.push(session);\n }\n\n const rawChannelIds = parseDestinationChannels(body.channel_id, body.channels);\n const targetRefs: ShareTargetRef[] = [];\n const targetKeys = new Set<string>();\n for (const channelId of rawChannelIds) {\n const target = resolveShareTarget(authUser, channelId);\n if (!target) return slackError(c, \"channel_not_found\");\n if (target.channel?.is_archived) return slackError(c, \"is_archived\");\n if (target.channel && !canReadConversation(target.channel, getAuthSlackUser(authUser), authUserId)) {\n return slackError(c, \"not_in_channel\");\n }\n if (!targetKeys.has(target.key)) {\n targetKeys.add(target.key);\n targetRefs.push(target);\n }\n }\n\n const targets: SlackChannel[] = [];\n for (const target of targetRefs) {\n const channel = target.channel ?? findOrCreateDirectMessage(authUser, target.directUserId ?? \"\");\n if (!channel) return slackError(c, \"channel_not_found\");\n targets.push(channel);\n }\n\n const completedFiles: SlackFile[] = [];\n for (let index = 0; index < requestedFiles.length; index++) {\n const requestedFile = requestedFiles[index];\n const session = requestedSessions[index];\n const file = ss().files.insert(\n buildSlackFile(session, {\n title: requestedFile.title ?? session.title,\n user: authUserId,\n baseUrl: serviceBaseUrl,\n initialComment,\n threadTs,\n }),\n );\n ss().fileUploadSessions.update(session.id, { completed: true });\n await dispatchFileEvent(webhooks, \"file_created\", file);\n completedFiles.push(file);\n }\n\n const sharedFiles = targets.length > 0 ? await shareFiles(targets, completedFiles) : completedFiles;\n return slackOk(c, { files: sharedFiles.map((file) => formatSlackFileForAuth(file, authUser)) });\n\n async function shareFiles(channels: SlackChannel[], files: SlackFile[]) {\n const updatedFiles = [...files];\n for (const channel of channels) {\n const msg = ss().messages.insert({\n ts: generateTs(),\n channel_id: channel.channel_id,\n user: authUserId,\n text: initialComment,\n type: \"message\" as const,\n subtype: \"file_share\",\n thread_ts: threadTs,\n blocks,\n files: updatedFiles,\n upload: true,\n reply_count: 0,\n reply_users: [],\n reactions: [],\n });\n\n updateParentThread(channel.channel_id, threadTs, authUserId);\n\n const messageFiles: SlackFile[] = [];\n for (const file of updatedFiles) {\n const shared = updateFileShare(file, channel, msg, authUserId);\n messageFiles.push(shared);\n await dispatchFileEvent(webhooks, \"file_shared\", shared, { channel_id: channel.channel_id });\n }\n\n const updatedMessage = ss().messages.update(msg.id, { files: messageFiles })!;\n await webhooks.dispatch(\n \"message\",\n undefined,\n {\n type: \"event_callback\",\n event: {\n ...formatSlackMessage(updatedMessage),\n type: \"message\",\n subtype: \"file_share\",\n channel: channel.channel_id,\n },\n },\n \"slack\",\n );\n\n for (const shared of messageFiles) {\n const index = updatedFiles.findIndex((file) => file.file_id === shared.file_id);\n if (index >= 0) updatedFiles[index] = shared;\n }\n }\n return updatedFiles;\n }\n });\n\n async function fileInfo(c: Context) {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"files:read\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackRequest(c);\n const fileId = typeof body.file === \"string\" ? body.file : \"\";\n const file = fileId ? ss().files.findOneBy(\"file_id\", fileId) : undefined;\n if (!file || file.deleted || !canAccessFile(file, authUser)) return slackError(c, \"file_not_found\");\n\n return slackOk(c, {\n file: formatSlackFileForAuth(file, authUser),\n comments: [],\n paging: { count: 0, total: 0, page: 1, pages: 0 },\n });\n }\n\n async function fileList(c: Context) {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"files:read\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackRequest(c);\n const channel = typeof body.channel === \"string\" ? body.channel : \"\";\n const user = typeof body.user === \"string\" ? body.user : \"\";\n const types = typeof body.types === \"string\" ? body.types : \"all\";\n const tsFrom = body.ts_from === undefined ? undefined : Number(body.ts_from);\n const tsTo = body.ts_to === undefined ? undefined : Number(body.ts_to);\n const page = Math.max(1, Math.floor(Number(body.page) || 1));\n const count = Math.min(Math.max(1, Math.floor(Number(body.count) || 100)), 1000);\n\n const files = ss()\n .files.all()\n .filter((file) => !file.deleted)\n .filter((file) => canAccessFile(file, authUser))\n .filter((file) => !channel || canAccessFileInChannel(file, authUser, channel))\n .filter((file) => !user || file.user === user)\n .filter((file) => tsFrom === undefined || file.created >= tsFrom)\n .filter((file) => tsTo === undefined || file.created <= tsTo)\n .filter((file) => matchesFileTypes(file, types))\n .sort((a, b) => b.created - a.created || b.file_id.localeCompare(a.file_id));\n\n const start = (page - 1) * count;\n const paged = files.slice(start, start + count);\n return slackOk(c, {\n files: paged.map((file) => formatSlackFileForAuth(file, authUser)),\n paging: {\n count,\n total: files.length,\n page,\n pages: Math.ceil(files.length / count),\n },\n });\n }\n\n app.get(\"/api/files.info\", fileInfo);\n app.post(\"/api/files.info\", fileInfo);\n app.get(\"/api/files.list\", fileList);\n app.post(\"/api/files.list\", fileList);\n\n app.get(\"/files-pri/:fileId/:filename\", (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return c.text(\"not_authed\", 401);\n const scopeError = requireSlackScopes(c, store, [\"files:read\"]);\n if (scopeError) return scopeError;\n\n const file = ss().files.findOneBy(\"file_id\", c.req.param(\"fileId\"));\n if (!file || file.deleted) return c.text(\"file_not_found\", 404);\n if (!canAccessFile(file, authUser)) return c.text(\"file_not_found\", 404);\n\n const data = Buffer.from(file.content_base64 ?? \"\", \"base64\");\n return new Response(data, {\n status: 200,\n headers: {\n \"Content-Type\": file.mimetype,\n ...(c.req.query(\"download\") ? { \"Content-Disposition\": `attachment; filename=\"${file.name}\"` } : {}),\n },\n });\n });\n\n app.post(\"/api/files.delete\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"files:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const fileId = typeof body.file === \"string\" ? body.file : \"\";\n const file = fileId ? ss().files.findOneBy(\"file_id\", fileId) : undefined;\n if (!file || file.deleted || !canAccessFile(file, authUser)) return slackError(c, \"file_not_found\");\n if (!canDeleteFile(file, authUser)) return slackError(c, \"cant_delete_file\");\n\n const deleted = ss().files.update(file.id, { deleted: true })!;\n removeFileFromMessages(deleted.file_id);\n await dispatchFileEvent(webhooks, \"file_deleted\", deleted);\n return slackOk(c, {});\n });\n\n function removeFileFromMessages(fileId: string) {\n for (const message of ss().messages.all()) {\n if (!message.files?.some((file) => file.file_id === fileId)) continue;\n ss().messages.update(message.id, {\n files: message.files.filter((file) => file.file_id !== fileId),\n });\n }\n }\n\n function updateParentThread(channelId: string, threadTs: string | undefined, userId: string) {\n if (!threadTs) return;\n const parent = ss()\n .messages.all()\n .find((message) => message.channel_id === channelId && message.ts === threadTs);\n if (!parent) return;\n\n const replyUsers = parent.reply_users.includes(userId) ? parent.reply_users : [...parent.reply_users, userId];\n ss().messages.update(parent.id, {\n reply_count: parent.reply_count + 1,\n reply_users: replyUsers,\n });\n }\n\n function updateFileShare(file: SlackFile, channel: SlackChannel, msg: SlackMessage, userId: string): SlackFile {\n const share: SlackFileShare = {\n ts: msg.ts,\n channel_name: channel.name,\n team_id: channel.team_id,\n share_user_id: userId,\n source: \"UPLOAD\",\n thread_ts: msg.thread_ts,\n reply_count: 0,\n reply_users: [],\n reply_users_count: 0,\n is_silent_share: false,\n };\n const shareBucket = channel.is_private ? \"private\" : \"public\";\n const shares = {\n ...file.shares,\n [shareBucket]: {\n ...(file.shares[shareBucket] ?? {}),\n [channel.channel_id]: [...(file.shares[shareBucket]?.[channel.channel_id] ?? []), share],\n },\n };\n const channelFields = nextFileChannelFields(file, channel);\n return ss().files.update(file.id, {\n ...channelFields,\n shares,\n is_public: channelFields.channels.length > 0,\n })!;\n }\n}\n\nasync function parseSlackRequest(c: Context): Promise<Record<string, unknown>> {\n if (c.req.method === \"GET\") {\n return Object.fromEntries(new URL(c.req.url).searchParams.entries());\n }\n return parseSlackBody(c);\n}\n\nasync function readUploadBytes(c: Context): Promise<Buffer | undefined> {\n const contentType = c.req.header(\"Content-Type\") ?? \"\";\n if (!contentType.includes(\"multipart/form-data\")) {\n return Buffer.from(await c.req.arrayBuffer());\n }\n\n const body = await c.req.parseBody();\n const values = orderedUploadFormValues(body);\n for (const value of values) {\n const data = await formValueToBuffer(value, \"file\");\n if (data) return data;\n }\n for (const value of values) {\n const data = await formValueToBuffer(value, \"string\");\n if (data) return data;\n }\n return undefined;\n}\n\nfunction orderedUploadFormValues(body: Record<string, unknown>): unknown[] {\n const preferredFields = new Set([\"filename\", \"file\", \"body\"]);\n const values = [...preferredFields].flatMap((field) => formValues(body[field]));\n const fallbackValues = Object.entries(body)\n .filter(([field]) => !preferredFields.has(field))\n .flatMap(([, value]) => formValues(value));\n return [...values, ...fallbackValues];\n}\n\nfunction formValues(value: unknown): unknown[] {\n if (value === undefined) return [];\n return Array.isArray(value) ? value : [value];\n}\n\nasync function formValueToBuffer(value: unknown, kind: \"file\" | \"string\"): Promise<Buffer | undefined> {\n if (kind === \"string\" && typeof value === \"string\") return Buffer.from(value);\n if (kind === \"file\" && value && typeof value === \"object\" && \"arrayBuffer\" in value) {\n const arrayBuffer = (value as { arrayBuffer: () => Promise<ArrayBuffer> }).arrayBuffer;\n if (typeof arrayBuffer === \"function\") return Buffer.from(await arrayBuffer.call(value));\n }\n return undefined;\n}\n\nfunction parseCompleteFiles(\n value: unknown,\n): Array<{ id: string; title?: string; highlight_type?: string }> | undefined {\n const parsed = parseJsonMaybe(value);\n if (!Array.isArray(parsed)) return undefined;\n\n const files: Array<{ id: string; title?: string; highlight_type?: string }> = [];\n for (const entry of parsed) {\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) return undefined;\n const record = entry as Record<string, unknown>;\n if (typeof record.id !== \"string\" || !record.id) return undefined;\n if (record.title !== undefined && typeof record.title !== \"string\") return undefined;\n if (record.highlight_type !== undefined && typeof record.highlight_type !== \"string\") return undefined;\n files.push({\n id: record.id,\n title: record.title,\n highlight_type: record.highlight_type,\n });\n }\n return files;\n}\n\nfunction parseDestinationChannels(channelId: unknown, channels: unknown): string[] {\n const values: string[] = [];\n if (typeof channelId === \"string\" && channelId.trim()) values.push(channelId.trim());\n if (typeof channels === \"string\" && channels.trim()) {\n values.push(...channels.split(\",\").map((channel) => channel.trim()));\n }\n return [...new Set(values.filter(Boolean))];\n}\n\nfunction parseBlocks(value: unknown): SlackJsonObject[] | undefined {\n const parsed = parseJsonMaybe(value);\n if (parsed === undefined || parsed === \"\") return undefined;\n if (!Array.isArray(parsed)) return undefined;\n if (!parsed.every((item) => item !== null && typeof item === \"object\" && !Array.isArray(item))) return undefined;\n return parsed as SlackJsonObject[];\n}\n\nfunction parseJsonMaybe(value: unknown): unknown {\n if (typeof value !== \"string\") return value;\n if (!value.trim()) return undefined;\n try {\n return JSON.parse(value) as unknown;\n } catch {\n return undefined;\n }\n}\n\nfunction buildSlackFile(\n session: {\n file_id: string;\n team_id: string;\n filename: string;\n length: number;\n alt_txt?: string;\n snippet_type?: string;\n content_base64?: string;\n uploaded_size?: number;\n },\n options: {\n title: string;\n user: string;\n baseUrl: string;\n initialComment?: string;\n threadTs?: string;\n },\n): Omit<SlackFile, \"id\" | \"created_at\" | \"updated_at\"> {\n const created = Math.floor(Date.now() / 1000);\n const fileType = fileTypeFor(session.filename, session.snippet_type);\n const root = options.baseUrl.replace(/\\/$/, \"\");\n return {\n file_id: session.file_id,\n team_id: session.team_id,\n user: options.user,\n name: session.filename,\n title: options.title || session.filename,\n mimetype: mimeTypeFor(session.filename, session.snippet_type),\n filetype: fileType,\n pretty_type: prettyTypeFor(fileType),\n mode: session.snippet_type ? \"snippet\" : \"hosted\",\n size: session.uploaded_size ?? session.length,\n created,\n timestamp: created,\n url_private: `${root}/files-pri/${session.file_id}/${encodeURIComponent(session.filename)}`,\n url_private_download: `${root}/files-pri/${session.file_id}/${encodeURIComponent(session.filename)}?download=1`,\n permalink: `${root}/files/${session.file_id}`,\n is_external: false,\n external_type: \"\",\n is_public: false,\n public_url_shared: false,\n display_as_bot: false,\n editable: session.snippet_type !== undefined,\n deleted: false,\n channels: [],\n groups: [],\n ims: [],\n shares: {},\n initial_comment: options.initialComment || undefined,\n thread_ts: options.threadTs,\n alt_txt: session.alt_txt,\n snippet_type: session.snippet_type,\n content_base64: session.content_base64,\n };\n}\n\nfunction nextFileChannelFields(file: SlackFile, channel: SlackChannel) {\n const channels = new Set(file.channels);\n const groups = new Set(file.groups);\n const ims = new Set(file.ims);\n\n if (channel.is_im || channel.is_mpim) ims.add(channel.channel_id);\n else if (channel.is_private) groups.add(channel.channel_id);\n else channels.add(channel.channel_id);\n\n return { channels: [...channels], groups: [...groups], ims: [...ims] };\n}\n\nfunction fileChannels(file: SlackFile): string[] {\n return [...file.channels, ...file.groups, ...file.ims];\n}\n\nfunction filterVisibleShares(shares: Record<string, SlackFileShare[]> | undefined, visibleIds: Set<string>) {\n const entries = Object.entries(shares ?? {}).filter(([channelId]) => visibleIds.has(channelId));\n return entries.length > 0 ? Object.fromEntries(entries) : undefined;\n}\n\nfunction matchesFileTypes(file: SlackFile, types: string): boolean {\n const requested = types\n .split(\",\")\n .map((type) => type.trim())\n .filter(Boolean);\n if (requested.length === 0 || requested.includes(\"all\")) return true;\n if (requested.includes(file.filetype)) return true;\n if (requested.includes(\"snippets\") && file.mode === \"snippet\") return true;\n if (requested.includes(\"images\") && file.mimetype.startsWith(\"image/\")) return true;\n if (requested.includes(\"zips\") && file.filetype === \"zip\") return true;\n if (requested.includes(\"pdfs\") && file.filetype === \"pdf\") return true;\n return false;\n}\n\nfunction fileTypeFor(filename: string, snippetType?: string): string {\n if (snippetType) return snippetType;\n const ext = filename.split(\".\").pop()?.toLowerCase() ?? \"\";\n if (!ext || ext === filename) return \"auto\";\n if (ext === \"jpg\" || ext === \"jpeg\") return \"jpg\";\n if (ext === \"md\" || ext === \"markdown\") return \"markdown\";\n return ext;\n}\n\nfunction mimeTypeFor(filename: string, snippetType?: string): string {\n if (snippetType) return \"text/plain\";\n const ext = filename.split(\".\").pop()?.toLowerCase() ?? \"\";\n const byExt: Record<string, string> = {\n gif: \"image/gif\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n md: \"text/markdown\",\n pdf: \"application/pdf\",\n png: \"image/png\",\n txt: \"text/plain\",\n zip: \"application/zip\",\n };\n return byExt[ext] ?? \"application/octet-stream\";\n}\n\nfunction prettyTypeFor(filetype: string): string {\n const byType: Record<string, string> = {\n auto: \"File\",\n gif: \"GIF\",\n jpg: \"JPEG\",\n markdown: \"Markdown\",\n pdf: \"PDF\",\n png: \"PNG\",\n txt: \"Plain Text\",\n zip: \"Zip\",\n };\n return byType[filetype] ?? filetype.toUpperCase();\n}\n\nasync function dispatchFileEvent(\n webhooks: RouteContext[\"webhooks\"],\n type: \"file_created\" | \"file_shared\" | \"file_deleted\",\n file: SlackFile,\n extra: Record<string, unknown> = {},\n) {\n await webhooks.dispatch(\n type,\n undefined,\n {\n type: \"event_callback\",\n event: {\n type,\n file_id: file.file_id,\n file: formatSlackFile(file),\n ...extra,\n },\n },\n \"slack\",\n );\n}\n","import type { Context, RouteContext } from \"@emulators/core\";\nimport type { SlackChannel, SlackMessage, SlackPin, SlackUser } from \"../entities.js\";\nimport { getSlackStore } from \"../store.js\";\nimport {\n formatSlackMessage,\n formatSlackPermalink,\n generateSlackId,\n generateTs,\n parseSlackBody,\n requireSlackScopes,\n slackError,\n slackOk,\n} from \"../helpers.js\";\n\nexport function pinsRoutes(ctx: RouteContext): void {\n const { app, store, webhooks, baseUrl } = ctx;\n const ss = () => getSlackStore(store);\n const getAuthSlackUser = (authUser: { login: string }) =>\n ss().users.findOneBy(\"user_id\", authUser.login) ?? ss().users.findOneBy(\"name\", authUser.login);\n const getAuthUserId = (authUser: { login: string }) => getAuthSlackUser(authUser)?.user_id ?? authUser.login;\n const isChannelMember = (channel: SlackChannel, user: SlackUser | undefined, userId: string) =>\n channel.members.includes(userId) || (user ? channel.members.includes(user.name) : false);\n const canReadConversation = (channel: SlackChannel, user: SlackUser | undefined, userId: string) =>\n !channel.is_private || isChannelMember(channel, user, userId);\n const findPinnedMessage = (channelId: string, timestamp: string) =>\n ss()\n .messages.all()\n .find((message) => message.channel_id === channelId && message.ts === timestamp);\n const findPin = (channelId: string, timestamp: string) =>\n ss()\n .pins.all()\n .find((pin) => pin.channel_id === channelId && pin.message_ts === timestamp);\n\n app.post(\"/api/pins.add\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"pins:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channelId = typeof body.channel === \"string\" ? body.channel : \"\";\n const timestamp = typeof body.timestamp === \"string\" ? body.timestamp : \"\";\n if (!channelId) return slackError(c, \"channel_not_found\");\n if (!timestamp) return slackError(c, \"no_item_specified\");\n if (!isSlackTimestamp(timestamp)) return slackError(c, \"bad_timestamp\");\n\n const channel = ss().channels.findOneBy(\"channel_id\", channelId);\n if (!channel) return slackError(c, \"channel_not_found\");\n if (channel.is_archived) return slackError(c, \"is_archived\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!isChannelMember(channel, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const message = findPinnedMessage(channel.channel_id, timestamp);\n if (!message) return slackError(c, \"message_not_found\");\n if (findPin(channel.channel_id, timestamp)) return slackError(c, \"already_pinned\");\n\n const pin = ss().pins.insert({\n pin_id: generateSlackId(\"P\"),\n team_id: channel.team_id,\n channel_id: channel.channel_id,\n message_ts: timestamp,\n created: Math.floor(Date.now() / 1000),\n created_by: authUserId,\n });\n\n await dispatchPinEvent(\"pin_added\", {\n user: authUserId,\n channel_id: channel.channel_id,\n item: formatPinItem(pin, message),\n event_ts: generateTs(),\n });\n\n return slackOk(c, {});\n });\n\n async function pinList(c: Context) {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"pins:read\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackRequest(c);\n const channelId = typeof body.channel === \"string\" ? body.channel : \"\";\n if (!channelId) return slackError(c, \"channel_not_found\");\n\n const channel = ss().channels.findOneBy(\"channel_id\", channelId);\n if (!channel) return slackError(c, \"channel_not_found\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!canReadConversation(channel, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const items = ss()\n .pins.findBy(\"channel_id\", channel.channel_id)\n .sort((a, b) => b.created - a.created)\n .flatMap((pin) => {\n const message = findPinnedMessage(pin.channel_id, pin.message_ts);\n return message ? [formatPinItem(pin, message)] : [];\n });\n\n return slackOk(c, { items });\n }\n\n app.get(\"/api/pins.list\", pinList);\n app.post(\"/api/pins.list\", pinList);\n\n app.post(\"/api/pins.remove\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"pins:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channelId = typeof body.channel === \"string\" ? body.channel : \"\";\n const timestamp = typeof body.timestamp === \"string\" ? body.timestamp : \"\";\n if (!channelId) return slackError(c, \"channel_not_found\");\n if (!timestamp) return slackError(c, \"no_item_specified\");\n if (!isSlackTimestamp(timestamp)) return slackError(c, \"bad_timestamp\");\n\n const channel = ss().channels.findOneBy(\"channel_id\", channelId);\n if (!channel) return slackError(c, \"channel_not_found\");\n if (channel.is_archived) return slackError(c, \"is_archived\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!isChannelMember(channel, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const pin = findPin(channel.channel_id, timestamp);\n const message = findPinnedMessage(channel.channel_id, timestamp);\n if (!pin) return slackError(c, \"no_pin\");\n\n ss().pins.delete(pin.id);\n if (!message) return slackOk(c, {});\n\n const hasPins = ss().pins.findBy(\"channel_id\", channel.channel_id).length > 0;\n await dispatchPinEvent(\"pin_removed\", {\n user: authUserId,\n channel_id: channel.channel_id,\n item: formatPinItem(pin, message),\n has_pins: hasPins,\n event_ts: generateTs(),\n });\n\n return slackOk(c, {});\n });\n\n function formatPinItem(pin: SlackPin, message: SlackMessage) {\n return {\n type: \"message\",\n channel: pin.channel_id,\n created: pin.created,\n created_by: pin.created_by,\n message: {\n ...formatSlackMessage(message),\n pinned_to: [pin.channel_id],\n permalink: formatSlackPermalink(baseUrl, pin.channel_id, message),\n },\n };\n }\n\n async function dispatchPinEvent(type: \"pin_added\" | \"pin_removed\", event: Record<string, unknown>) {\n await webhooks.dispatch(\n type,\n undefined,\n {\n type: \"event_callback\",\n event: { type, ...event },\n },\n \"slack\",\n );\n }\n}\n\nasync function parseSlackRequest(c: Context): Promise<Record<string, unknown>> {\n if (c.req.method === \"GET\") {\n return Object.fromEntries(new URL(c.req.url).searchParams.entries());\n }\n return parseSlackBody(c);\n}\n\nfunction isSlackTimestamp(value: string): boolean {\n return /^\\d{1,16}\\.\\d{1,16}$/.test(value);\n}\n","import type { RouteContext } from \"@emulators/core\";\nimport type { SlackBookmark, SlackChannel, SlackUser } from \"../entities.js\";\nimport { getSlackStore } from \"../store.js\";\nimport { generateSlackId, parseSlackBody, requireSlackScopes, slackError, slackOk } from \"../helpers.js\";\n\nexport function bookmarksRoutes(ctx: RouteContext): void {\n const { app, store } = ctx;\n const ss = () => getSlackStore(store);\n const getAuthSlackUser = (authUser: { login: string }) =>\n ss().users.findOneBy(\"user_id\", authUser.login) ?? ss().users.findOneBy(\"name\", authUser.login);\n const getAuthUserId = (authUser: { login: string }) => getAuthSlackUser(authUser)?.user_id ?? authUser.login;\n const isChannelMember = (channel: SlackChannel, user: SlackUser | undefined, userId: string) =>\n channel.members.includes(userId) || (user ? channel.members.includes(user.name) : false);\n const canReadConversation = (channel: SlackChannel, user: SlackUser | undefined, userId: string) =>\n !channel.is_private || isChannelMember(channel, user, userId);\n\n app.post(\"/api/bookmarks.add\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"bookmarks:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channelId = stringField(body.channel_id) || stringField(body.channel);\n const channel = findBookmarkChannel(channelId);\n if (!channel) return slackError(c, \"channel_not_found\");\n if (channel.is_archived) return slackError(c, \"is_archived\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!isChannelMember(channel, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const title = stringField(body.title).trim();\n const type = stringField(body.type);\n const link = stringField(body.link) || stringField(body.url);\n if (type !== \"link\") return slackError(c, \"invalid_bookmark_type\");\n if (!title || !link) return slackError(c, \"invalid_arguments\");\n if (!isValidBookmarkLink(link)) return slackError(c, \"invalid_link\");\n if (ss().bookmarks.findBy(\"channel_id\", channel.channel_id).length >= 100) {\n return slackError(c, \"too_many_bookmarks\");\n }\n\n const now = Math.floor(Date.now() / 1000);\n const team = ss().teams.all()[0];\n const bookmark = ss().bookmarks.insert({\n bookmark_id: generateSlackId(\"Bk\"),\n team_id: team?.team_id ?? channel.team_id,\n channel_id: channel.channel_id,\n title,\n type: \"link\",\n link,\n emoji: stringField(body.emoji),\n icon_url: bookmarkIconUrl(link),\n entity_id: null,\n date_created: now,\n date_updated: 0,\n rank: bookmarkRank(channel.channel_id),\n last_updated_by_user_id: authUserId,\n last_updated_by_team_id: team?.team_id ?? channel.team_id,\n shortcut_id: null,\n app_id: null,\n ...(accessLevel(body.access_level) ? { access_level: accessLevel(body.access_level) } : {}),\n ...(stringField(body.parent_id) ? { parent_id: stringField(body.parent_id) } : {}),\n });\n\n return slackOk(c, { bookmark: formatBookmark(bookmark) });\n });\n\n app.post(\"/api/bookmarks.edit\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"bookmarks:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channelId = stringField(body.channel_id) || stringField(body.channel);\n const bookmarkId = stringField(body.bookmark_id);\n const channel = findBookmarkChannel(channelId);\n if (!channel) return slackError(c, \"channel_not_found\");\n if (channel.is_archived) return slackError(c, \"is_archived\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!isChannelMember(channel, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const bookmark = findBookmark(channel.channel_id, bookmarkId);\n if (!bookmark) return slackError(c, \"not_found\");\n\n const updates: Partial<SlackBookmark> = {\n date_updated: Math.floor(Date.now() / 1000),\n last_updated_by_user_id: authUserId,\n };\n const title = stringField(body.title).trim();\n const link = stringField(body.link) || stringField(body.url);\n const emoji = stringField(body.emoji);\n if (title) updates.title = title;\n if (link) {\n if (!isValidBookmarkLink(link)) return slackError(c, \"invalid_link\");\n updates.link = link;\n updates.icon_url = bookmarkIconUrl(link);\n }\n if (Object.prototype.hasOwnProperty.call(body, \"emoji\")) updates.emoji = emoji;\n\n const updated = ss().bookmarks.update(bookmark.id, updates)!;\n return slackOk(c, { bookmark: formatBookmark(updated) });\n });\n\n app.post(\"/api/bookmarks.list\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"bookmarks:read\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channelId = stringField(body.channel_id) || stringField(body.channel);\n const channel = findBookmarkChannel(channelId);\n if (!channel) return slackError(c, \"channel_not_found\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!canReadConversation(channel, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const bookmarks = ss()\n .bookmarks.findBy(\"channel_id\", channel.channel_id)\n .sort(compareSlackBookmarks)\n .map(formatBookmark);\n\n return slackOk(c, { bookmarks });\n });\n\n app.post(\"/api/bookmarks.remove\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n const scopeError = requireSlackScopes(c, store, [\"bookmarks:write\"]);\n if (scopeError) return scopeError;\n\n const body = await parseSlackBody(c);\n const channelId = stringField(body.channel_id) || stringField(body.channel);\n const bookmarkId = stringField(body.bookmark_id);\n const channel = findBookmarkChannel(channelId);\n if (!channel) return slackError(c, \"channel_not_found\");\n if (channel.is_archived) return slackError(c, \"is_archived\");\n\n const authSlackUser = getAuthSlackUser(authUser);\n const authUserId = getAuthUserId(authUser);\n if (!isChannelMember(channel, authSlackUser, authUserId)) return slackError(c, \"not_in_channel\");\n\n const bookmark = findBookmark(channel.channel_id, bookmarkId);\n if (!bookmark) return slackError(c, \"not_found\");\n\n ss().bookmarks.delete(bookmark.id);\n return slackOk(c, {});\n });\n\n function findBookmarkChannel(channelId: string): SlackChannel | undefined {\n if (!channelId) return undefined;\n return ss().channels.findOneBy(\"channel_id\", channelId);\n }\n\n function findBookmark(channelId: string, bookmarkId: string): SlackBookmark | undefined {\n if (!bookmarkId) return undefined;\n return ss()\n .bookmarks.all()\n .find((bookmark) => bookmark.channel_id === channelId && bookmark.bookmark_id === bookmarkId);\n }\n\n function bookmarkRank(channelId: string): string {\n const maxRank = ss()\n .bookmarks.findBy(\"channel_id\", channelId)\n .reduce((max, bookmark) => Math.max(max, validBookmarkRankNumber(bookmark) ?? 0), 0);\n return (maxRank + 1).toString(36);\n }\n}\n\nexport function compareSlackBookmarks(a: SlackBookmark, b: SlackBookmark): number {\n return (\n bookmarkRankNumber(a) - bookmarkRankNumber(b) ||\n a.date_created - b.date_created ||\n a.id - b.id ||\n a.bookmark_id.localeCompare(b.bookmark_id)\n );\n}\n\nfunction formatBookmark(bookmark: SlackBookmark) {\n return {\n id: bookmark.bookmark_id,\n channel_id: bookmark.channel_id,\n title: bookmark.title,\n link: bookmark.link,\n emoji: bookmark.emoji,\n icon_url: bookmark.icon_url,\n type: bookmark.type,\n entity_id: bookmark.entity_id,\n date_created: bookmark.date_created,\n date_updated: bookmark.date_updated,\n rank: bookmark.rank,\n last_updated_by_user_id: bookmark.last_updated_by_user_id,\n last_updated_by_team_id: bookmark.last_updated_by_team_id,\n shortcut_id: bookmark.shortcut_id,\n app_id: bookmark.app_id,\n };\n}\n\nfunction stringField(value: unknown): string {\n return typeof value === \"string\" ? value : \"\";\n}\n\nfunction accessLevel(value: unknown): \"read\" | \"write\" | undefined {\n if (value === \"read\" || value === \"write\") return value;\n return undefined;\n}\n\nfunction bookmarkRankNumber(bookmark: SlackBookmark): number {\n return validBookmarkRankNumber(bookmark) ?? Number.MAX_SAFE_INTEGER;\n}\n\nfunction validBookmarkRankNumber(bookmark: SlackBookmark): number | undefined {\n if (!/^[0-9a-z]+$/i.test(bookmark.rank)) return undefined;\n const rank = parseInt(bookmark.rank, 36);\n return Number.isSafeInteger(rank) ? rank : undefined;\n}\n\nfunction bookmarkIconUrl(link: string): string {\n try {\n const url = new URL(link);\n return `${url.origin}/favicon.ico`;\n } catch {\n return \"\";\n }\n}\n\nfunction isValidBookmarkLink(link: string): boolean {\n try {\n const url = new URL(link);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n","import type { Context, RouteContext } from \"@emulators/core\";\nimport type { SlackJsonObject, SlackToken, SlackView, SlackViewType } from \"../entities.js\";\nimport { getSlackStore } from \"../store.js\";\nimport { formatSlackView, generateSlackId, generateTs, parseSlackBody, slackError, slackOk } from \"../helpers.js\";\n\ninterface ParsedViewPayload {\n type: SlackViewType;\n blocks: SlackJsonObject[];\n private_metadata: string;\n callback_id: string;\n external_id: string;\n title: SlackJsonObject | null;\n submit: SlackJsonObject | null;\n close: SlackJsonObject | null;\n state: SlackJsonObject;\n clear_on_close: boolean;\n notify_on_close: boolean;\n}\n\ninterface ConsumedTrigger {\n user_id?: string;\n app_id?: string;\n view_id?: string;\n}\n\nconst VIEW_TRIGGER_TTL_SECONDS = 3;\nconst MAX_MODAL_STACK_DEPTH = 3;\n\nexport function viewsRoutes(ctx: RouteContext): void {\n const { app, store } = ctx;\n const ss = () => getSlackStore(store);\n const teamId = () => ss().teams.all()[0]?.team_id ?? \"T000000001\";\n\n app.post(\"/api/views.publish\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const userId = resolveUserId(stringField(body.user_id));\n if (!userId) return slackError(c, \"user_not_found\");\n\n const parsed = parseViewPayload(body.view, \"home\");\n if (parsed.error || !parsed.view) return slackError(c, parsed.error ?? \"invalid_view\");\n const viewPayload = parsed.view;\n\n const actor = viewActor(c);\n const existing = ss()\n .views.all()\n .find((view) => view.type === \"home\" && view.user_id === userId && view.app_id === actor.app_id);\n const hash = stringField(body.hash);\n if (existing && hash && hash !== existing.hash) return slackError(c, \"hash_conflict\");\n if (findDuplicateExternalId(viewPayload.external_id, existing?.view_id)) {\n return slackError(c, \"duplicate_external_id\");\n }\n\n const now = nowSeconds();\n const view =\n existing ??\n ss().views.insert({\n ...viewPayload,\n view_id: generateSlackId(\"V\"),\n team_id: teamId(),\n user_id: userId,\n hash: generateTs(),\n root_view_id: \"\",\n app_id: actor.app_id,\n bot_id: actor.bot_id,\n created: now,\n updated: now,\n });\n\n const updated = ss().views.update(view.id, {\n ...viewPayload,\n root_view_id: view.root_view_id || view.view_id,\n hash: generateTs(),\n updated: now,\n })!;\n return slackOk(c, { view: formatSlackView(updated) });\n });\n\n app.post(\"/api/views.open\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const parsed = parseViewPayload(body.view, \"modal\");\n if (parsed.error || !parsed.view) return slackError(c, parsed.error ?? \"invalid_view\");\n const viewPayload = parsed.view;\n\n const actor = viewActor(c);\n const trigger = consumeTrigger(viewExchangeId(body), actor.app_id);\n if (trigger.error) return slackError(c, trigger.error);\n const userId = trigger.value!.user_id!;\n if (!resolveUserId(userId)) return slackError(c, \"user_not_found\");\n if (findDuplicateExternalId(viewPayload.external_id)) return slackError(c, \"duplicate_external_id\");\n\n const view = createView(viewPayload, {\n user_id: userId,\n app_id: actor.app_id,\n bot_id: actor.bot_id,\n });\n return slackOk(c, { view: formatSlackView(view) });\n });\n\n app.post(\"/api/views.update\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const view = findView(stringField(body.view_id), stringField(body.external_id));\n if (!view) return slackError(c, \"not_found\");\n const actor = viewActor(c);\n if (view.app_id !== actor.app_id) return slackError(c, \"not_found\");\n\n const hash = stringField(body.hash);\n if (hash && hash !== view.hash) return slackError(c, \"hash_conflict\");\n\n const parsed = parseViewPayload(body.view, view.type, view.type);\n if (parsed.error || !parsed.view) return slackError(c, parsed.error ?? \"invalid_view\");\n const viewPayload = parsed.view;\n if (findDuplicateExternalId(viewPayload.external_id, view.view_id)) {\n return slackError(c, \"duplicate_external_id\");\n }\n\n const updated = ss().views.update(view.id, {\n ...viewPayload,\n hash: generateTs(),\n updated: nowSeconds(),\n })!;\n return slackOk(c, { view: formatSlackView(updated) });\n });\n\n app.post(\"/api/views.push\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const parsed = parseViewPayload(body.view, \"modal\");\n if (parsed.error || !parsed.view) return slackError(c, parsed.error ?? \"invalid_view\");\n const viewPayload = parsed.view;\n\n const actor = viewActor(c);\n const trigger = consumeTrigger(viewExchangeId(body), actor.app_id);\n if (trigger.error) return slackError(c, trigger.error);\n const userId = trigger.value!.user_id!;\n if (!resolveUserId(userId)) return slackError(c, \"user_not_found\");\n if (findDuplicateExternalId(viewPayload.external_id)) return slackError(c, \"duplicate_external_id\");\n\n const parent = trigger.value?.view_id ? ss().views.findOneBy(\"view_id\", trigger.value.view_id) : undefined;\n if (!parent || parent.type !== \"modal\" || parent.user_id !== userId) return slackError(c, \"view_not_found\");\n if (modalStackDepth(parent) >= MAX_MODAL_STACK_DEPTH) return slackError(c, \"push_limit_reached\");\n\n const view = createView(viewPayload, {\n user_id: userId,\n app_id: actor.app_id,\n bot_id: actor.bot_id,\n previous_view_id: parent?.view_id,\n root_view_id: parent?.root_view_id ?? parent?.view_id,\n });\n return slackOk(c, { view: formatSlackView(view) });\n });\n\n app.post(\"/api/views.generateTriggerId\", async (c) => {\n const authUser = c.get(\"authUser\");\n if (!authUser) return slackError(c, \"not_authed\");\n\n const body = await parseSlackBody(c);\n const referencedView = stringField(body.view_id)\n ? ss().views.findOneBy(\"view_id\", stringField(body.view_id))\n : undefined;\n if (stringField(body.view_id) && !referencedView) return slackError(c, \"view_not_found\");\n const actor = viewActor(c);\n if (referencedView && referencedView.app_id !== actor.app_id) return slackError(c, \"view_not_found\");\n\n const userId = resolveUserId(stringField(body.user_id)) ?? referencedView?.user_id ?? resolveUserId(authUser.login);\n if (!userId || !resolveUserId(userId)) return slackError(c, \"user_not_found\");\n\n const triggerId = generateTriggerId();\n const expiresAt = nowSeconds() + VIEW_TRIGGER_TTL_SECONDS;\n ss().viewTriggers.insert({\n trigger_id: triggerId,\n team_id: teamId(),\n user_id: userId,\n app_id: actor.app_id,\n expires_at: expiresAt,\n used: false,\n ...(referencedView ? { view_id: referencedView.view_id } : {}),\n });\n return slackOk(c, { trigger_id: triggerId, expires_at: expiresAt });\n });\n\n function createView(\n parsed: ParsedViewPayload,\n options: {\n user_id: string;\n app_id: string;\n bot_id: string;\n root_view_id?: string;\n previous_view_id?: string;\n },\n ): SlackView {\n const now = nowSeconds();\n const viewId = generateSlackId(\"V\");\n return ss().views.insert({\n ...parsed,\n view_id: viewId,\n team_id: teamId(),\n user_id: options.user_id,\n hash: generateTs(),\n root_view_id: options.root_view_id ?? viewId,\n ...(options.previous_view_id ? { previous_view_id: options.previous_view_id } : {}),\n app_id: options.app_id,\n bot_id: options.bot_id,\n created: now,\n updated: now,\n });\n }\n\n function findView(viewId: string, externalId: string): SlackView | undefined {\n if (viewId) return ss().views.findOneBy(\"view_id\", viewId);\n if (externalId) return ss().views.findOneBy(\"external_id\", externalId);\n return undefined;\n }\n\n function findDuplicateExternalId(externalId: string, currentViewId?: string): SlackView | undefined {\n if (!externalId) return undefined;\n return ss()\n .views.all()\n .find((view) => view.team_id === teamId() && view.external_id === externalId && view.view_id !== currentViewId);\n }\n\n function resolveUserId(value: string): string | undefined {\n if (!value) return undefined;\n return ss().users.findOneBy(\"user_id\", value)?.user_id ?? ss().users.findOneBy(\"name\", value)?.user_id;\n }\n\n function modalStackDepth(view: SlackView): number {\n const rootViewId = view.root_view_id || view.view_id;\n return ss()\n .views.all()\n .filter((candidate) => candidate.type === \"modal\" && candidate.root_view_id === rootViewId).length;\n }\n\n function viewActor(c: Context): { app_id: string; bot_id: string } {\n const token = authTokenRecord(c);\n const appId = token?.app_id ?? ss().oauthApps.all()[0]?.app_id ?? \"A000000001\";\n const botId = token?.bot_id ?? ss().bots.all()[0]?.bot_id ?? \"B000000001\";\n return { app_id: appId, bot_id: botId };\n }\n\n function authTokenRecord(c: Context): SlackToken | undefined {\n const token = c.get(\"authToken\") as string | undefined;\n return token ? ss().tokens.findOneBy(\"token\", token) : undefined;\n }\n\n function consumeTrigger(triggerId: string, appId: string): { value?: ConsumedTrigger; error?: string } {\n if (!triggerId) return { error: \"invalid_trigger_id\" };\n const trigger = ss().viewTriggers.findOneBy(\"trigger_id\", triggerId);\n if (!trigger) return { error: \"invalid_trigger_id\" };\n if (trigger.app_id !== appId) return { error: \"invalid_trigger_id\" };\n if (trigger.used) return { error: \"exchanged_trigger_id\" };\n if (trigger.expires_at <= nowSeconds()) return { error: \"expired_trigger_id\" };\n const updated = ss().viewTriggers.update(trigger.id, { used: true }) ?? trigger;\n return { value: { user_id: updated.user_id, app_id: updated.app_id, view_id: updated.view_id } };\n }\n\n function parseViewPayload(\n value: unknown,\n expectedType: SlackViewType,\n fallbackType?: SlackViewType,\n ): { view?: ParsedViewPayload; error?: string } {\n const view = parseViewObject(value);\n if (!view) return { error: \"invalid_view\" };\n\n const type = typeof view.type === \"string\" ? view.type : fallbackType;\n if (type !== expectedType) return { error: \"invalid_view\" };\n\n const blocks = view.blocks;\n if (!Array.isArray(blocks) || !blocks.every(isSlackJsonObject)) return { error: \"invalid_view\" };\n\n const title = optionalObject(view.title);\n const submit = optionalObject(view.submit);\n const close = optionalObject(view.close);\n const state = optionalObject(view.state) ?? { values: {} };\n if (title === false || submit === false || close === false || state === false) return { error: \"invalid_view\" };\n if (expectedType === \"modal\" && title === null) return { error: \"invalid_view\" };\n\n return {\n view: {\n type: expectedType,\n blocks,\n private_metadata: stringField(view.private_metadata),\n callback_id: stringField(view.callback_id),\n external_id: stringField(view.external_id),\n title,\n submit,\n close,\n state,\n clear_on_close: booleanField(view.clear_on_close, false),\n notify_on_close: booleanField(view.notify_on_close, false),\n },\n };\n }\n}\n\nfunction parseViewObject(value: unknown): Record<string, unknown> | undefined {\n let parsed = value;\n if (typeof parsed === \"string\") {\n if (!parsed) return undefined;\n try {\n parsed = JSON.parse(parsed) as unknown;\n } catch {\n return undefined;\n }\n }\n if (!isSlackJsonObject(parsed)) return undefined;\n return parsed;\n}\n\nfunction optionalObject(value: unknown): SlackJsonObject | null | false {\n if (value === undefined || value === null || value === \"\") return null;\n return isSlackJsonObject(value) ? value : false;\n}\n\nfunction isSlackJsonObject(value: unknown): value is SlackJsonObject {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction stringField(value: unknown): string {\n return typeof value === \"string\" ? value : \"\";\n}\n\nfunction viewExchangeId(body: Record<string, unknown>): string {\n return stringField(body.trigger_id) || stringField(body.interactivity_pointer);\n}\n\nfunction booleanField(value: unknown, fallback: boolean): boolean {\n if (typeof value === \"boolean\") return value;\n if (value === 1 || value === \"1\" || value === \"true\") return true;\n if (value === 0 || value === \"0\" || value === \"false\") return false;\n return fallback;\n}\n\nfunction nowSeconds(): number {\n return Math.floor(Date.now() / 1000);\n}\n\nfunction generateTriggerId(): string {\n const first = Math.floor(Date.now() / 1000);\n const second = Math.floor(Math.random() * 1_000_000)\n .toString()\n .padStart(6, \"0\");\n return `${first}.${second}.${generateSlackId(\"trg\").toLowerCase()}`;\n}\n","import type { InspectorTab, RouteContext, WebhookDelivery, WebhookSubscription } from \"@emulators/core\";\nimport { escapeAttr, escapeHtml, renderInspectorPage } from \"@emulators/core\";\nimport { getSlackStore } from \"../store.js\";\nimport type {\n SlackBookmark,\n SlackChannel,\n SlackEphemeralMessage,\n SlackIncomingWebhook,\n SlackInstallation,\n SlackMessage,\n SlackOAuthApp,\n SlackPin,\n SlackScheduledMessage,\n SlackToken,\n SlackView,\n SlackViewTrigger,\n} from \"../entities.js\";\nimport { compareSlackBookmarks } from \"./bookmarks.js\";\n\nconst SERVICE_LABEL = \"Slack\";\n\nconst INSPECTOR_TABS: InspectorTab[] = [\n { id: \"messages\", label: \"Messages\", href: \"/?tab=messages\" },\n { id: \"channels\", label: \"Channels\", href: \"/?tab=channels\" },\n { id: \"files\", label: \"Files\", href: \"/?tab=files\" },\n { id: \"views\", label: \"Views\", href: \"/?tab=views\" },\n { id: \"auth\", label: \"Auth\", href: \"/?tab=auth\" },\n { id: \"events\", label: \"Events\", href: \"/?tab=events\" },\n];\n\ntype InspectorTabId = (typeof INSPECTOR_TABS)[number][\"id\"];\n\nfunction timeAgo(isoDate: string): string {\n const seconds = Math.floor((Date.now() - new Date(isoDate).getTime()) / 1000);\n if (seconds < 60) return \"just now\";\n if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;\n if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;\n return `${Math.floor(seconds / 86400)}d ago`;\n}\n\nfunction collectTextValues(value: unknown, output: string[]): void {\n if (Array.isArray(value)) {\n for (const item of value) collectTextValues(item, output);\n return;\n }\n if (value === null || typeof value !== \"object\") return;\n\n const record = value as Record<string, unknown>;\n const text = record.text;\n if (typeof text === \"string\" && text.trim().length > 0) {\n output.push(text);\n } else {\n collectTextValues(text, output);\n }\n collectTextValues(record.fields, output);\n collectTextValues(record.elements, output);\n collectTextValues(record.accessory, output);\n}\n\nfunction richMessagePreview(\n msg: Pick<SlackMessage, \"text\" | \"blocks\" | \"attachments\" | \"files\"> | SlackScheduledMessage,\n): string {\n if (msg.text.trim().length > 0) return msg.text;\n\n const blockText: string[] = [];\n collectTextValues(msg.blocks, blockText);\n if (blockText.length > 0) return blockText.join(\" \");\n\n const attachmentText =\n msg.attachments\n ?.flatMap((attachment) => [attachment.text, attachment.title])\n .filter((value): value is string => typeof value === \"string\" && value.trim().length > 0) ?? [];\n if (attachmentText.length > 0) return attachmentText.join(\" \");\n\n const files = \"files\" in msg ? msg.files : undefined;\n const fileText = files?.map((file) => file.title || file.name).filter((value) => value.trim().length > 0) ?? [];\n if (fileText.length > 0) return fileText.join(\" \");\n\n if (msg.blocks?.length) return `${msg.blocks.length} ${msg.blocks.length === 1 ? \"block\" : \"blocks\"}`;\n if (msg.attachments?.length) {\n return `${msg.attachments.length} ${msg.attachments.length === 1 ? \"attachment\" : \"attachments\"}`;\n }\n if (files?.length) return `${files.length} ${files.length === 1 ? \"file\" : \"files\"}`;\n return msg.text;\n}\n\nfunction viewPreview(view: SlackView): string {\n const blockText: string[] = [];\n collectTextValues(view.blocks, blockText);\n if (blockText.length > 0) return blockText.join(\" \");\n\n const title = view.title?.text;\n if (typeof title === \"string\" && title.trim().length > 0) return title;\n\n if (view.callback_id) return view.callback_id;\n if (view.external_id) return view.external_id;\n return `${view.blocks.length} ${view.blocks.length === 1 ? \"block\" : \"blocks\"}`;\n}\n\nfunction renderSection(title: string, body: string): string {\n return `<section class=\"inspector-section\">\n <h2>${escapeHtml(title)}</h2>\n ${body}\n</section>`;\n}\n\nfunction renderTable(headers: string[], rows: string[][], empty: string): string {\n if (rows.length === 0) return `<p class=\"inspector-empty\">${escapeHtml(empty)}</p>`;\n\n const headerHtml = headers.map((header) => `<th>${escapeHtml(header)}</th>`).join(\"\");\n const rowsHtml = rows.map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join(\"\")}</tr>`).join(\"\\n\");\n return `<table class=\"inspector-table\">\n <thead><tr>${headerHtml}</tr></thead>\n <tbody>\n${rowsHtml}\n </tbody>\n</table>`;\n}\n\nfunction badge(label: string, tone: \"granted\" | \"requested\" | \"denied\" = \"requested\"): string {\n return `<span class=\"badge badge-${tone}\">${escapeHtml(label)}</span>`;\n}\n\nfunction renderReactionBadges(reactions: Array<{ name: string; count: number }>): string {\n if (reactions.length === 0) return \"\";\n return reactions.map((reaction) => badge(`:${reaction.name}: ${reaction.count}`, \"granted\")).join(\" \");\n}\n\nfunction linkCell(href: string, label: string): string {\n return `<a href=\"${escapeAttr(href)}\">${escapeHtml(label)}</a>`;\n}\n\nfunction scopePreview(scopes: string[] | undefined): string {\n if (!scopes || scopes.length === 0) return \"\";\n return scopes.join(\", \");\n}\n\nfunction userLabel(users: Map<string, string>, id: string): string {\n return users.get(id) ?? id;\n}\n\nfunction channelLabel(ch: SlackChannel): string {\n if (ch.is_im) return `DM ${ch.name}`;\n if (ch.is_mpim) return `MPIM ${ch.name}`;\n if (ch.is_private) return `private ${ch.name}`;\n return `# ${ch.name}`;\n}\n\nfunction channelKind(ch: SlackChannel): string {\n if (ch.is_im) return \"DM\";\n if (ch.is_mpim) return \"MPIM\";\n if (ch.is_private) return \"Private\";\n return \"Public\";\n}\n\nfunction openStateLabel(ch: SlackChannel, users: Map<string, string>): string {\n if (ch.is_open_by_user) {\n const openUsers = Object.entries(ch.is_open_by_user)\n .filter(([, isOpen]) => isOpen === true)\n .map(([userId]) => userLabel(users, userId));\n return openUsers.length > 0 ? openUsers.join(\", \") : \"closed\";\n }\n return ch.is_open ? \"open\" : \"closed\";\n}\n\nfunction maskToken(value: string): string {\n if (value.length <= 10) return value;\n return `${value.slice(0, 8)}...${value.slice(-4)}`;\n}\n\nfunction sortedChannels(channels: SlackChannel[]): SlackChannel[] {\n return [...channels].sort(\n (a, b) =>\n Number(a.is_archived) - Number(b.is_archived) ||\n channelKind(a).localeCompare(channelKind(b)) ||\n a.name.localeCompare(b.name),\n );\n}\n\nexport function inspectorRoutes(ctx: RouteContext): void {\n const { app, store, webhooks } = ctx;\n const ss = () => getSlackStore(store);\n\n app.get(\"/\", (c) => {\n const team = ss().teams.all()[0];\n const requestedTab = c.req.query(\"tab\") ?? \"messages\";\n const activeTab = INSPECTOR_TABS.some((tab) => tab.id === requestedTab)\n ? (requestedTab as InspectorTabId)\n : \"messages\";\n const users = buildUserMap();\n\n const body =\n activeTab === \"channels\"\n ? renderChannelsView(users)\n : activeTab === \"files\"\n ? renderFilesView(users)\n : activeTab === \"views\"\n ? renderViewsView(users)\n : activeTab === \"auth\"\n ? renderAuthView()\n : activeTab === \"events\"\n ? renderEventsView()\n : renderMessagesView(c.req.query(\"channel\") ?? \"\", users);\n\n return c.html(\n renderInspectorPage(\n `${team?.name ?? \"Slack\"} - Message Inspector`,\n INSPECTOR_TABS,\n activeTab,\n body,\n SERVICE_LABEL,\n ),\n );\n });\n\n function buildUserMap(): Map<string, string> {\n const userMap = new Map<string, string>();\n for (const u of ss().users.all()) {\n userMap.set(u.user_id, u.name);\n userMap.set(u.name, u.name);\n }\n for (const b of ss().bots.all()) {\n userMap.set(b.bot_id, b.name);\n if (b.user_id) userMap.set(b.user_id, b.name);\n }\n return userMap;\n }\n\n function renderMessagesView(requestedChannel: string, users: Map<string, string>): string {\n const channels = sortedChannels(ss().channels.all());\n const visibleChannels = channels.filter((ch) => !ch.is_archived);\n const activeChannel =\n channels.find((ch) => ch.channel_id === requestedChannel) ?? visibleChannels[0] ?? channels[0];\n if (!activeChannel) {\n return renderSection(\"Messages\", '<p class=\"inspector-empty\">No conversations in the emulator store.</p>');\n }\n\n const channelMessages = ss()\n .messages.findBy(\"channel_id\", activeChannel.channel_id)\n .sort((a, b) => (b.ts > a.ts ? 1 : -1));\n const messages = channelMessages.slice(0, 50);\n const threads = channelMessages\n .filter((message) => message.thread_ts && message.thread_ts !== message.ts)\n .slice(0, 20);\n const ephemeralMessages = ss()\n .ephemeralMessages.findBy(\"channel_id\", activeChannel.channel_id)\n .sort((a, b) => (b.ts > a.ts ? 1 : -1))\n .slice(0, 20);\n const scheduledMessages = ss()\n .scheduledMessages.findBy(\"channel_id\", activeChannel.channel_id)\n .sort((a, b) => a.post_at - b.post_at)\n .slice(0, 20);\n const pins = ss()\n .pins.findBy(\"channel_id\", activeChannel.channel_id)\n .filter((pin) => channelMessages.some((message) => message.ts === pin.message_ts))\n .sort((a, b) => b.created - a.created)\n .slice(0, 20);\n const bookmarks = ss()\n .bookmarks.findBy(\"channel_id\", activeChannel.channel_id)\n .sort(compareSlackBookmarks)\n .slice(0, 20);\n const views = ss()\n .views.all()\n .sort((a, b) => b.updated - a.updated || b.id - a.id);\n const homeViews = views.filter((view) => view.type === \"home\").slice(0, 20);\n const modalViews = views.filter((view) => view.type === \"modal\").slice(0, 20);\n\n const stats = `${ss().users.all().length} users, ${channels.length} conversations, ${ss().messages.all().length} messages, ${ss().views.all().length} views`;\n const body = [\n renderConversationSelector(channels, activeChannel.channel_id),\n renderSection(\n `Messages In ${channelLabel(activeChannel)}`,\n `<p class=\"info-text\">${escapeHtml(activeChannel.topic.value || \"No topic set\")} - ${escapeHtml(stats)}</p>` +\n renderMessagesTable(\n messages,\n users,\n \"No messages yet. Post one with chat.postMessage or an incoming webhook.\",\n ),\n ),\n renderSection(\"Threads\", renderMessagesTable(threads, users, \"No thread replies for this conversation.\")),\n renderSection(\n \"Ephemeral\",\n renderEphemeralTable(ephemeralMessages, users, \"No ephemeral messages for this conversation.\"),\n ),\n renderSection(\n \"Scheduled\",\n renderScheduledTable(scheduledMessages, users, \"No scheduled messages for this conversation.\"),\n ),\n renderSection(\"Pins\", renderPinsTable(pins, channelMessages, users, \"No pins for this conversation.\")),\n renderSection(\"Bookmarks\", renderBookmarksTable(bookmarks, \"No bookmarks for this conversation.\")),\n renderSection(\"App Home\", renderViewsTable(homeViews, users, \"No App Home views have been published.\")),\n renderSection(\"Modals\", renderViewsTable(modalViews, users, \"No modal views have been opened.\")),\n ];\n return body.join(\"\\n\");\n }\n\n function renderConversationSelector(channels: SlackChannel[], activeChannelId: string): string {\n const rows = channels.map((ch) => [\n ch.channel_id === activeChannelId ? badge(\"active\", \"granted\") : \"\",\n linkCell(`/?tab=messages&channel=${encodeURIComponent(ch.channel_id)}`, channelLabel(ch)),\n escapeHtml(channelKind(ch)),\n escapeHtml(String(ch.num_members)),\n ch.is_archived ? badge(\"archived\", \"denied\") : badge(\"open\", \"granted\"),\n ]);\n return renderSection(\n \"Conversations\",\n renderTable([\"\", \"Name\", \"Type\", \"Members\", \"State\"], rows, \"No conversations in the emulator store.\"),\n );\n }\n\n function renderChannelsView(users: Map<string, string>): string {\n const channels = sortedChannels(ss().channels.all());\n const conversations = channels.filter((channel) => !channel.is_im && !channel.is_mpim);\n const dms = channels.filter((channel) => channel.is_im || channel.is_mpim);\n\n return [\n renderSection(\n \"Channels\",\n renderTable(\n [\"ID\", \"Name\", \"Type\", \"Members\", \"Topic\", \"Purpose\", \"State\"],\n conversations.map((ch) => [\n escapeHtml(ch.channel_id),\n linkCell(`/?tab=messages&channel=${encodeURIComponent(ch.channel_id)}`, channelLabel(ch)),\n escapeHtml(channelKind(ch)),\n escapeHtml(ch.members.map((member) => userLabel(users, member)).join(\", \")),\n escapeHtml(ch.topic.value),\n escapeHtml(ch.purpose.value),\n ch.is_archived ? badge(\"archived\", \"denied\") : badge(\"open\", \"granted\"),\n ]),\n \"No channels in the emulator store.\",\n ),\n ),\n renderSection(\n \"Direct Messages\",\n renderTable(\n [\"ID\", \"Name\", \"Type\", \"Members\", \"Open State\"],\n dms.map((ch) => [\n escapeHtml(ch.channel_id),\n linkCell(`/?tab=messages&channel=${encodeURIComponent(ch.channel_id)}`, channelLabel(ch)),\n escapeHtml(channelKind(ch)),\n escapeHtml(ch.members.map((member) => userLabel(users, member)).join(\", \")),\n escapeHtml(openStateLabel(ch, users)),\n ]),\n \"No DMs or MPIMs in the emulator store.\",\n ),\n ),\n ].join(\"\\n\");\n }\n\n function renderFilesView(users: Map<string, string>): string {\n const files = ss()\n .files.all()\n .sort((a, b) => b.created - a.created || b.id - a.id);\n const sessions = ss()\n .fileUploadSessions.all()\n .filter((session) => !session.completed)\n .sort((a, b) => b.id - a.id);\n\n return [\n renderSection(\n \"Files\",\n renderTable(\n [\"ID\", \"Title\", \"User\", \"Channels\", \"Size\", \"State\", \"Created\"],\n files.map((file) => [\n escapeHtml(file.file_id),\n escapeHtml(file.title || file.name),\n escapeHtml(userLabel(users, file.user)),\n escapeHtml([...file.channels, ...file.groups, ...file.ims].join(\", \")),\n escapeHtml(String(file.size)),\n file.deleted ? badge(\"deleted\", \"denied\") : badge(\"available\", \"granted\"),\n escapeHtml(new Date(file.created * 1000).toISOString()),\n ]),\n \"No completed files in the emulator store.\",\n ),\n ),\n renderSection(\n \"Pending Uploads\",\n renderTable(\n [\"File ID\", \"Filename\", \"Title\", \"Length\", \"Uploaded\", \"Completed\"],\n sessions.map((session) => [\n escapeHtml(session.file_id),\n escapeHtml(session.filename),\n escapeHtml(session.title),\n escapeHtml(String(session.length)),\n session.uploaded ? badge(\"uploaded\", \"granted\") : badge(\"pending\"),\n session.completed ? badge(\"complete\", \"granted\") : badge(\"pending\"),\n ]),\n \"No pending external upload sessions.\",\n ),\n ),\n ].join(\"\\n\");\n }\n\n function renderViewsView(users: Map<string, string>): string {\n const views = ss()\n .views.all()\n .sort((a, b) => b.updated - a.updated || b.id - a.id);\n const homeViews = views.filter((view) => view.type === \"home\");\n const modalViews = views.filter((view) => view.type === \"modal\");\n const triggers = ss()\n .viewTriggers.all()\n .sort((a, b) => b.expires_at - a.expires_at || b.id - a.id);\n\n return [\n renderSection(\"App Home\", renderViewsTable(homeViews, users, \"No App Home views have been published.\")),\n renderSection(\"Modals\", renderViewsTable(modalViews, users, \"No modal views have been opened.\")),\n renderSection(\"Trigger IDs\", renderTriggerTable(triggers, users)),\n ].join(\"\\n\");\n }\n\n function renderAuthView(): string {\n const subscriptions = webhooks.getSubscriptions(\"slack\");\n return [\n renderSection(\"OAuth Apps\", renderOAuthAppsTable(ss().oauthApps.all())),\n renderSection(\"Installations\", renderInstallationsTable(ss().installations.all())),\n renderSection(\"Tokens\", renderTokensTable(ss().tokens.all())),\n renderSection(\"Incoming Webhooks\", renderIncomingWebhooksTable(ss().incomingWebhooks.all())),\n renderSection(\"Event Subscriptions\", renderSubscriptionsTable(subscriptions)),\n ].join(\"\\n\");\n }\n\n function renderEventsView(): string {\n const subscriptions = webhooks.getSubscriptions(\"slack\");\n const slackHookIds = new Set(subscriptions.map((subscription) => subscription.id));\n const allDeliveries = webhooks\n .getDeliveries()\n .filter((delivery) => slackHookIds.has(delivery.hook_id))\n .sort((a, b) => b.id - a.id);\n const deliveries = allDeliveries.slice(0, 100);\n const failed = allDeliveries.filter((delivery) => !delivery.success).slice(0, 100);\n\n return [\n renderSection(\"Event Subscriptions\", renderSubscriptionsTable(subscriptions)),\n renderSection(\n \"Event Deliveries\",\n renderDeliveriesTable(deliveries, subscriptions, \"No Slack event deliveries yet.\"),\n ),\n renderSection(\"Last Errors\", renderDeliveriesTable(failed, subscriptions, \"No failed Slack event deliveries.\")),\n ].join(\"\\n\");\n }\n}\n\nfunction renderMessagesTable(messages: SlackMessage[], users: Map<string, string>, empty: string): string {\n return renderTable(\n [\"Time\", \"User\", \"Message\", \"Reactions\", \"TS\"],\n messages.map((msg) => {\n const isBot = msg.subtype === \"bot_message\";\n const richBadge =\n msg.text.length === 0 && ((msg.blocks?.length ?? 0) > 0 || (msg.attachments?.length ?? 0) > 0)\n ? ` ${badge(\"rich\", \"granted\")}`\n : \"\";\n const threadBadge =\n msg.reply_count > 0\n ? ` ${badge(`${msg.reply_count} ${msg.reply_count === 1 ? \"reply\" : \"replies\"}`, \"requested\")}`\n : \"\";\n const fileBadge = msg.files?.length\n ? ` ${badge(`${msg.files.length} ${msg.files.length === 1 ? \"file\" : \"files\"}`, \"granted\")}`\n : \"\";\n const threadIndicator = msg.thread_ts && msg.thread_ts !== msg.ts ? `${badge(\"thread\", \"denied\")} ` : \"\";\n return [\n escapeHtml(timeAgo(msg.created_at)),\n `${escapeHtml(userLabel(users, msg.user))}${isBot ? ` ${badge(\"bot\", \"granted\")}` : \"\"}`,\n `${threadIndicator}${escapeHtml(richMessagePreview(msg))}${richBadge}${fileBadge}${threadBadge}`,\n renderReactionBadges(msg.reactions),\n escapeHtml(msg.ts),\n ];\n }),\n empty,\n );\n}\n\nfunction renderEphemeralTable(messages: SlackEphemeralMessage[], users: Map<string, string>, empty: string): string {\n return renderTable(\n [\"Time\", \"Target\", \"Message\", \"TS\"],\n messages.map((msg) => [\n escapeHtml(timeAgo(msg.created_at)),\n `${escapeHtml(userLabel(users, msg.target_user))} ${badge(\"ephemeral\", \"requested\")}`,\n escapeHtml(richMessagePreview(msg)),\n escapeHtml(msg.ts),\n ]),\n empty,\n );\n}\n\nfunction renderScheduledTable(messages: SlackScheduledMessage[], users: Map<string, string>, empty: string): string {\n return renderTable(\n [\"Post At\", \"User\", \"Message\", \"ID\"],\n messages.map((msg) => [\n escapeHtml(new Date(msg.post_at * 1000).toISOString()),\n escapeHtml(userLabel(users, msg.user)),\n escapeHtml(richMessagePreview(msg)),\n escapeHtml(msg.scheduled_message_id),\n ]),\n empty,\n );\n}\n\nfunction renderPinsTable(\n pins: SlackPin[],\n channelMessages: SlackMessage[],\n users: Map<string, string>,\n empty: string,\n): string {\n return renderTable(\n [\"Created\", \"Creator\", \"Message\", \"TS\"],\n pins.map((pin) => {\n const message = channelMessages.find((candidate) => candidate.ts === pin.message_ts);\n return [\n escapeHtml(new Date(pin.created * 1000).toISOString()),\n escapeHtml(userLabel(users, pin.created_by)),\n escapeHtml(message ? richMessagePreview(message) : pin.message_ts),\n escapeHtml(pin.message_ts),\n ];\n }),\n empty,\n );\n}\n\nfunction renderBookmarksTable(bookmarks: SlackBookmark[], empty: string): string {\n return renderTable(\n [\"Title\", \"Type\", \"Link\", \"Rank\"],\n bookmarks.map((bookmark) => [\n escapeHtml(bookmark.title),\n escapeHtml(bookmark.type),\n escapeHtml(bookmark.link),\n escapeHtml(bookmark.rank),\n ]),\n empty,\n );\n}\n\nfunction renderViewsTable(views: SlackView[], users: Map<string, string>, empty: string): string {\n return renderTable(\n [\"ID\", \"Type\", \"User\", \"App\", \"Preview\", \"Hash\", \"Root\", \"Previous\"],\n views.map((view) => [\n escapeHtml(view.view_id),\n view.type === \"home\" ? badge(\"app home\", \"granted\") : badge(\"modal\", \"requested\"),\n escapeHtml(userLabel(users, view.user_id)),\n escapeHtml(view.app_id),\n escapeHtml(viewPreview(view)),\n escapeHtml(view.hash),\n escapeHtml(view.root_view_id),\n escapeHtml(view.previous_view_id ?? \"\"),\n ]),\n empty,\n );\n}\n\nfunction renderTriggerTable(triggers: SlackViewTrigger[], users: Map<string, string>): string {\n const now = Math.floor(Date.now() / 1000);\n return renderTable(\n [\"Trigger ID\", \"User\", \"App\", \"View\", \"Expires\", \"State\"],\n triggers.map((trigger) => [\n escapeHtml(trigger.trigger_id),\n escapeHtml(userLabel(users, trigger.user_id)),\n escapeHtml(trigger.app_id),\n escapeHtml(trigger.view_id ?? \"\"),\n escapeHtml(new Date(trigger.expires_at * 1000).toISOString()),\n trigger.used\n ? badge(\"used\", \"denied\")\n : trigger.expires_at <= now\n ? badge(\"expired\", \"denied\")\n : badge(\"active\", \"granted\"),\n ]),\n \"No local trigger ids have been generated.\",\n );\n}\n\nfunction renderOAuthAppsTable(apps: SlackOAuthApp[]): string {\n return renderTable(\n [\"App ID\", \"Client ID\", \"Name\", \"Bot\", \"Scopes\", \"User Scopes\"],\n apps.map((app) => [\n escapeHtml(app.app_id ?? \"\"),\n escapeHtml(app.client_id),\n escapeHtml(app.name),\n escapeHtml(app.bot_id ?? app.bot_name ?? \"\"),\n escapeHtml(scopePreview(app.scopes)),\n escapeHtml(scopePreview(app.user_scopes)),\n ]),\n \"No OAuth apps are configured.\",\n );\n}\n\nfunction renderInstallationsTable(installations: SlackInstallation[]): string {\n return renderTable(\n [\"Installation\", \"App\", \"Team\", \"Bot User\", \"Installer\", \"Scopes\"],\n installations.map((installation) => [\n escapeHtml(installation.installation_id),\n escapeHtml(installation.app_id),\n escapeHtml(installation.team_id),\n escapeHtml(installation.bot_user_id),\n escapeHtml(installation.installer_user_id),\n escapeHtml(scopePreview(installation.scopes)),\n ]),\n \"No OAuth installations have been recorded.\",\n );\n}\n\nfunction renderTokensTable(tokens: SlackToken[]): string {\n return renderTable(\n [\"Token\", \"Type\", \"Team\", \"User\", \"App\", \"Bot\", \"Scopes\"],\n tokens.map((token) => [\n escapeHtml(maskToken(token.token)),\n escapeHtml(token.token_type),\n escapeHtml(token.team_id),\n escapeHtml(token.user_id),\n escapeHtml(token.app_id ?? \"\"),\n escapeHtml(token.bot_id ?? token.bot_user_id ?? \"\"),\n escapeHtml(scopePreview(token.scopes)),\n ]),\n \"No Slack token records have been seeded or exchanged.\",\n );\n}\n\nfunction renderIncomingWebhooksTable(webhooks: SlackIncomingWebhook[]): string {\n return renderTable(\n [\"Token\", \"Team\", \"Bot\", \"Default Channel\", \"Label\", \"URL\"],\n webhooks.map((webhook) => [\n escapeHtml(maskToken(webhook.token)),\n escapeHtml(webhook.team_id),\n escapeHtml(webhook.bot_id),\n escapeHtml(webhook.default_channel),\n escapeHtml(webhook.label),\n escapeHtml(webhook.url),\n ]),\n \"No incoming webhooks are configured.\",\n );\n}\n\nfunction renderSubscriptionsTable(subscriptions: WebhookSubscription[]): string {\n return renderTable(\n [\"ID\", \"URL\", \"Events\", \"State\"],\n subscriptions.map((subscription) => [\n escapeHtml(String(subscription.id)),\n escapeHtml(subscription.url),\n escapeHtml(subscription.events.join(\", \")),\n subscription.active ? badge(\"active\", \"granted\") : badge(\"inactive\", \"denied\"),\n ]),\n \"No Slack event subscriptions are registered.\",\n );\n}\n\nfunction renderDeliveriesTable(\n deliveries: WebhookDelivery[],\n subscriptions: WebhookSubscription[],\n empty: string,\n): string {\n const subscriptionsById = new Map(subscriptions.map((subscription) => [subscription.id, subscription]));\n return renderTable(\n [\"ID\", \"Event\", \"Hook\", \"URL\", \"Status\", \"Duration\", \"Delivered\"],\n deliveries.map((delivery) => {\n const subscription = subscriptionsById.get(delivery.hook_id);\n return [\n escapeHtml(String(delivery.id)),\n escapeHtml(delivery.event),\n escapeHtml(String(delivery.hook_id)),\n escapeHtml(subscription?.url ?? \"\"),\n delivery.success\n ? badge(String(delivery.status_code ?? \"ok\"), \"granted\")\n : badge(String(delivery.status_code ?? \"failed\"), \"denied\"),\n escapeHtml(delivery.duration === null ? \"\" : `${delivery.duration}ms`),\n escapeHtml(delivery.delivered_at),\n ];\n }),\n empty,\n );\n}\n","import type { Context, Hono } from \"@emulators/core\";\nimport type { ServicePlugin, Store, WebhookDispatcher, TokenMap, AppEnv, RouteContext } from \"@emulators/core\";\nimport { getSlackStore } from \"./store.js\";\nimport { generateSlackId } from \"./helpers.js\";\nimport type { SlackOAuthApp, SlackPresence, SlackTokenType, SlackUserProfile } from \"./entities.js\";\nimport { authRoutes } from \"./routes/auth.js\";\nimport { chatRoutes } from \"./routes/chat.js\";\nimport { conversationsRoutes } from \"./routes/conversations.js\";\nimport { usersRoutes } from \"./routes/users.js\";\nimport { reactionsRoutes } from \"./routes/reactions.js\";\nimport { teamRoutes } from \"./routes/team.js\";\nimport { oauthRoutes } from \"./routes/oauth.js\";\nimport { webhookRoutes } from \"./routes/webhooks.js\";\nimport { filesRoutes } from \"./routes/files.js\";\nimport { pinsRoutes } from \"./routes/pins.js\";\nimport { bookmarksRoutes } from \"./routes/bookmarks.js\";\nimport { viewsRoutes } from \"./routes/views.js\";\nimport { inspectorRoutes } from \"./routes/inspector.js\";\n\nexport { getSlackStore, type SlackStore } from \"./store.js\";\nexport * from \"./entities.js\";\n\nexport interface SlackSeedConfig {\n port?: number;\n team?: {\n name?: string;\n domain?: string;\n };\n users?: Array<{\n name: string;\n real_name?: string;\n email?: string;\n is_admin?: boolean;\n profile?: Partial<SlackUserProfile>;\n presence?: SlackPresence;\n }>;\n channels?: Array<{\n name: string;\n topic?: string;\n purpose?: string;\n is_private?: boolean;\n }>;\n bots?: Array<{\n name: string;\n }>;\n oauth_apps?: Array<{\n app_id?: string;\n client_id: string;\n client_secret: string;\n name: string;\n redirect_uris: string[];\n scopes?: string[] | string;\n user_scopes?: string[] | string;\n bot_id?: string;\n bot_user_id?: string;\n bot_name?: string;\n }>;\n tokens?: Array<{\n token: string;\n type?: SlackTokenType;\n user?: string;\n user_id?: string;\n scopes?: string[] | string;\n app_id?: string;\n client_id?: string;\n team_id?: string;\n bot_id?: string;\n bot_user_id?: string;\n authed_user_id?: string;\n }>;\n incoming_webhooks?: Array<{\n channel: string;\n label?: string;\n }>;\n strict_scopes?: boolean;\n signing_secret?: string;\n}\n\nconst DEFAULT_SLACK_SCOPES = [\n \"chat:write\",\n \"channels:read\",\n \"channels:history\",\n \"channels:join\",\n \"channels:manage\",\n \"channels:write\",\n \"groups:read\",\n \"groups:history\",\n \"groups:write\",\n \"im:read\",\n \"im:history\",\n \"im:write\",\n \"mpim:read\",\n \"mpim:history\",\n \"mpim:write\",\n \"users:read\",\n \"users:read.email\",\n \"users.profile:read\",\n \"users.profile:write\",\n \"users:write\",\n \"files:read\",\n \"files:write\",\n \"pins:read\",\n \"pins:write\",\n \"bookmarks:read\",\n \"bookmarks:write\",\n \"reactions:read\",\n \"reactions:write\",\n \"team:read\",\n];\n\nfunction seedDefaults(store: Store, _baseUrl: string): void {\n const ss = getSlackStore(store);\n\n const teamId = \"T000000001\";\n\n ss.teams.insert({\n team_id: teamId,\n name: \"Emulate\",\n domain: \"emulate\",\n });\n\n const userId = \"U000000001\";\n ss.users.insert({\n user_id: userId,\n team_id: teamId,\n name: \"admin\",\n real_name: \"Admin User\",\n email: \"admin@emulate.dev\",\n is_admin: true,\n is_bot: false,\n deleted: false,\n profile: {\n display_name: \"admin\",\n real_name: \"Admin User\",\n email: \"admin@emulate.dev\",\n image_48: \"\",\n image_192: \"\",\n real_name_normalized: \"Admin User\",\n display_name_normalized: \"admin\",\n status_text: \"\",\n status_emoji: \"\",\n status_emoji_display_info: [],\n status_expiration: 0,\n },\n presence: \"active\",\n manual_presence: \"auto\",\n connection_count: 1,\n last_activity: Math.floor(Date.now() / 1000),\n });\n\n ss.channels.insert({\n channel_id: \"C000000001\",\n team_id: teamId,\n name: \"general\",\n is_channel: true,\n is_private: false,\n is_archived: false,\n topic: { value: \"General discussion\", creator: userId, last_set: Math.floor(Date.now() / 1000) },\n purpose: { value: \"A place for general discussion\", creator: userId, last_set: Math.floor(Date.now() / 1000) },\n members: [userId],\n creator: userId,\n num_members: 1,\n });\n\n ss.channels.insert({\n channel_id: \"C000000002\",\n team_id: teamId,\n name: \"random\",\n is_channel: true,\n is_private: false,\n is_archived: false,\n topic: { value: \"Random stuff\", creator: userId, last_set: Math.floor(Date.now() / 1000) },\n purpose: {\n value: \"A place for non-work-related chatter\",\n creator: userId,\n last_set: Math.floor(Date.now() / 1000),\n },\n members: [userId],\n creator: userId,\n num_members: 1,\n });\n\n // Default incoming webhook for #general\n ss.incomingWebhooks.insert({\n token: \"X000000001\",\n team_id: teamId,\n bot_id: \"B000000001\",\n default_channel: \"general\",\n label: \"Default Webhook\",\n url: `/services/${teamId}/B000000001/X000000001`,\n });\n}\n\nexport function seedFromConfig(store: Store, _baseUrl: string, config: SlackSeedConfig): void {\n const ss = getSlackStore(store);\n\n if (config.team) {\n const existing = ss.teams.all()[0];\n if (existing) {\n ss.teams.update(existing.id, {\n name: config.team.name ?? existing.name,\n domain: config.team.domain ?? existing.domain,\n });\n }\n }\n\n const team = ss.teams.all()[0];\n const teamId = team?.team_id ?? \"T000000001\";\n\n if (config.users) {\n for (const u of config.users) {\n const existing = ss.users.all().find((eu) => eu.name === u.name);\n if (existing) continue;\n\n const userId = generateSlackId(\"U\");\n const email = u.profile?.email ?? u.email ?? `${u.name}@emulate.dev`;\n const realName = u.real_name ?? u.name;\n const profile = normalizeSeedProfile({\n display_name: u.name,\n real_name: realName,\n email,\n image_48: \"\",\n image_192: \"\",\n ...u.profile,\n });\n ss.users.insert({\n user_id: userId,\n team_id: teamId,\n name: u.name,\n real_name: profile.real_name,\n email: profile.email,\n is_admin: u.is_admin ?? false,\n is_bot: false,\n deleted: false,\n profile,\n presence: u.presence ?? \"active\",\n manual_presence: u.presence === \"away\" ? \"away\" : \"auto\",\n connection_count: u.presence === \"away\" ? 0 : 1,\n last_activity: u.presence === \"away\" ? undefined : Math.floor(Date.now() / 1000),\n });\n }\n }\n\n if (config.channels) {\n for (const ch of config.channels) {\n const existing = ss.channels.findOneBy(\"name\", ch.name);\n if (existing) continue;\n\n const creator = ss.users.all()[0]?.user_id ?? \"U000000001\";\n const now = Math.floor(Date.now() / 1000);\n const isPrivate = ch.is_private ?? false;\n\n ss.channels.insert({\n channel_id: generateSlackId(\"C\"),\n team_id: teamId,\n name: ch.name,\n is_channel: !isPrivate,\n is_private: isPrivate,\n is_archived: false,\n topic: { value: ch.topic ?? \"\", creator, last_set: now },\n purpose: { value: ch.purpose ?? \"\", creator, last_set: now },\n members: ss.users.all().map((u) => u.user_id),\n creator,\n num_members: ss.users.all().length,\n });\n }\n }\n\n if (config.bots) {\n for (const b of config.bots) {\n const existing = ss.bots.all().find((eb) => eb.name === b.name);\n if (existing) continue;\n\n ss.bots.insert({\n bot_id: generateSlackId(\"B\"),\n name: b.name,\n deleted: false,\n icons: { image_48: \"\" },\n });\n }\n }\n\n if (config.oauth_apps) {\n for (const oa of config.oauth_apps) {\n const existing = ss.oauthApps.findOneBy(\"client_id\", oa.client_id);\n if (existing) {\n if (!existing.app_id) {\n ss.oauthApps.update(existing.id, { app_id: oa.app_id ?? generateSlackId(\"A\") });\n }\n continue;\n }\n\n ss.oauthApps.insert({\n app_id: oa.app_id ?? generateSlackId(\"A\"),\n client_id: oa.client_id,\n client_secret: oa.client_secret,\n name: oa.name,\n redirect_uris: oa.redirect_uris,\n scopes: normalizeScopes(oa.scopes),\n user_scopes: normalizeScopes(oa.user_scopes),\n bot_id: oa.bot_id,\n bot_user_id: oa.bot_user_id,\n bot_name: oa.bot_name,\n });\n }\n\n const installer = ss.users.all().find((user) => !user.deleted && !user.is_bot) ?? ss.users.all()[0];\n for (const appRecord of ss.oauthApps.all()) {\n seedOAuthInstallation(ss, teamId, installer?.user_id ?? \"U000000001\", appRecord);\n }\n }\n\n if (config.tokens) {\n for (const token of config.tokens) {\n const value = token.token.trim();\n if (!value || ss.tokens.findOneBy(\"token\", value)) continue;\n\n const userId =\n resolveSeedTokenUserId(ss, token.user_id ?? token.user) ?? ss.users.all()[0]?.user_id ?? \"U000000001\";\n ss.tokens.insert({\n token: value,\n token_type: token.type ?? \"test\",\n team_id: token.team_id ?? teamId,\n user_id: userId,\n scopes: normalizeScopes(token.scopes, DEFAULT_SLACK_SCOPES),\n app_id: token.app_id,\n client_id: token.client_id,\n bot_id: token.bot_id,\n bot_user_id: token.bot_user_id,\n authed_user_id: token.authed_user_id,\n });\n }\n }\n\n if (config.incoming_webhooks) {\n const firstBot = ss.bots.all()[0];\n const botId = firstBot?.bot_id ?? \"B000000001\";\n\n for (const wh of config.incoming_webhooks) {\n const token = generateSlackId(\"X\");\n ss.incomingWebhooks.insert({\n token,\n team_id: teamId,\n bot_id: botId,\n default_channel: wh.channel,\n label: wh.label ?? wh.channel,\n url: `/services/${teamId}/${botId}/${token}`,\n });\n }\n }\n\n if (config.signing_secret) {\n store.setData(\"slack.signing_secret\", config.signing_secret);\n }\n\n if (config.strict_scopes !== undefined) {\n store.setData(\"slack.strict_scopes\", config.strict_scopes);\n }\n}\n\nexport const slackPlugin: ServicePlugin = {\n name: \"slack\",\n register(app: Hono<AppEnv>, store: Store, webhooks: WebhookDispatcher, baseUrl: string, tokenMap?: TokenMap): void {\n app.use(\"*\", async (c, next) => {\n applySlackTokenAuth(c, store);\n await next();\n });\n\n const ctx: RouteContext = { app, store, webhooks, baseUrl, tokenMap };\n authRoutes(ctx);\n chatRoutes(ctx);\n conversationsRoutes(ctx);\n usersRoutes(ctx);\n reactionsRoutes(ctx);\n teamRoutes(ctx);\n oauthRoutes(ctx);\n webhookRoutes(ctx);\n filesRoutes(ctx);\n pinsRoutes(ctx);\n bookmarksRoutes(ctx);\n viewsRoutes(ctx);\n inspectorRoutes(ctx);\n },\n seed(store: Store, baseUrl: string): void {\n seedDefaults(store, baseUrl);\n },\n};\n\nexport default slackPlugin;\n\nexport function normalizeScopes(value: string[] | string | undefined, fallback: string[] = []): string[] {\n if (Array.isArray(value)) return value.map((scope) => scope.trim()).filter(Boolean);\n if (typeof value === \"string\") {\n return value\n .split(/[,\\s]+/)\n .map((scope) => scope.trim())\n .filter(Boolean);\n }\n return [...fallback];\n}\n\nfunction applySlackTokenAuth(c: Context, store: Store): void {\n const token = slackRequestToken(c);\n if (!token) return;\n\n const record = getSlackStore(store).tokens.findOneBy(\"token\", token);\n if (!record) return;\n\n c.set(\"authToken\", record.token);\n c.set(\"authScopes\", record.scopes);\n c.set(\"authUser\", {\n login: record.user_id,\n id: record.id,\n scopes: record.scopes,\n });\n}\n\nfunction slackRequestToken(c: Context): string | undefined {\n const authHeader = c.req.header(\"Authorization\");\n if (!authHeader) return undefined;\n const token = authHeader.replace(/^(Bearer|token)\\s+/i, \"\").trim();\n return token || undefined;\n}\n\nfunction seedOAuthInstallation(\n ss: ReturnType<typeof getSlackStore>,\n teamId: string,\n installerUserId: string,\n app: SlackOAuthApp,\n): void {\n const appId = app.app_id ?? generateSlackId(\"A\");\n if (!app.app_id) ss.oauthApps.update(app.id, { app_id: appId });\n\n const botName = app.bot_name ?? slugifySlackBotName(app.name);\n const existingBot =\n (app.bot_id ? ss.bots.findOneBy(\"bot_id\", app.bot_id) : undefined) ??\n ss.bots.all().find((bot) => bot.name === botName);\n const botId = app.bot_id ?? existingBot?.bot_id ?? generateSlackId(\"B\");\n const botUserId = app.bot_user_id ?? existingBot?.user_id ?? generateSlackId(\"U\");\n const bot =\n existingBot ??\n ss.bots.insert({\n bot_id: botId,\n app_id: appId,\n user_id: botUserId,\n name: botName,\n deleted: false,\n icons: { image_48: \"\" },\n });\n\n if (bot.app_id !== appId || bot.user_id !== botUserId) {\n ss.bots.update(bot.id, { app_id: appId, user_id: botUserId });\n }\n if (!app.bot_id || !app.bot_user_id || !app.bot_name) {\n ss.oauthApps.update(app.id, {\n bot_id: botId,\n bot_user_id: botUserId,\n bot_name: botName,\n });\n }\n\n if (!ss.users.findOneBy(\"user_id\", botUserId)) {\n ss.users.insert({\n user_id: botUserId,\n team_id: teamId,\n name: botName,\n real_name: app.name,\n email: `${botName}@bots.emulate.dev`,\n is_admin: false,\n is_bot: true,\n deleted: false,\n profile: {\n display_name: botName,\n real_name: app.name,\n email: `${botName}@bots.emulate.dev`,\n image_48: \"\",\n image_192: \"\",\n real_name_normalized: app.name,\n display_name_normalized: botName,\n status_text: \"\",\n status_emoji: \"\",\n status_emoji_display_info: [],\n status_expiration: 0,\n },\n presence: \"active\",\n manual_presence: \"auto\",\n connection_count: 1,\n last_activity: Math.floor(Date.now() / 1000),\n });\n }\n\n const existingInstallation = ss.installations\n .all()\n .find((installation) => installation.app_id === appId && installation.team_id === teamId);\n const data = {\n app_id: appId,\n client_id: app.client_id,\n team_id: teamId,\n app_name: app.name,\n installer_user_id: installerUserId,\n bot_id: botId,\n bot_user_id: botUserId,\n scopes: app.scopes ?? [],\n user_scopes: app.user_scopes ?? [],\n };\n\n if (existingInstallation) {\n ss.installations.update(existingInstallation.id, data);\n } else {\n ss.installations.insert({\n installation_id: generateSlackId(\"I\"),\n ...data,\n });\n }\n}\n\nfunction resolveSeedTokenUserId(ss: ReturnType<typeof getSlackStore>, userRef: string | undefined): string | undefined {\n if (!userRef) return undefined;\n return ss.users.findOneBy(\"user_id\", userRef)?.user_id ?? ss.users.findOneBy(\"name\", userRef)?.user_id ?? userRef;\n}\n\nfunction slugifySlackBotName(value: string): string {\n const slug = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return slug || \"slack-app\";\n}\n\nfunction normalizeSeedProfile(profile: SlackUserProfile): SlackUserProfile {\n return {\n ...profile,\n real_name_normalized: profile.real_name_normalized ?? profile.real_name,\n display_name_normalized: profile.display_name_normalized ?? profile.display_name,\n status_text: profile.status_text ?? \"\",\n status_emoji: profile.status_emoji ?? \"\",\n status_emoji_display_info: profile.status_emoji_display_info ?? [],\n status_expiration: profile.status_expiration ?? 0,\n };\n}\n"],"mappings":"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","names":["randomBytes","pin","updated","existing","scopeError","fileChannels","filterVisibleShares","parseSlackRequest","stringField","view","isSlackJsonObject","SERVICE_LABEL","normalizeScopes","bot"]}
|