@sena-ai/platform-core 1.4.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.
Files changed (158) hide show
  1. package/dist/app.d.ts +9 -0
  2. package/dist/app.d.ts.map +1 -0
  3. package/dist/app.js +147 -0
  4. package/dist/app.js.map +1 -0
  5. package/dist/auth/handler.d.ts +19 -0
  6. package/dist/auth/handler.d.ts.map +1 -0
  7. package/dist/auth/handler.js +213 -0
  8. package/dist/auth/handler.js.map +1 -0
  9. package/dist/auth/session.d.ts +16 -0
  10. package/dist/auth/session.d.ts.map +1 -0
  11. package/dist/auth/session.js +54 -0
  12. package/dist/auth/session.js.map +1 -0
  13. package/dist/db/d1/index.d.ts +14 -0
  14. package/dist/db/d1/index.d.ts.map +1 -0
  15. package/dist/db/d1/index.js +252 -0
  16. package/dist/db/d1/index.js.map +1 -0
  17. package/dist/db/d1/schema.d.ts +610 -0
  18. package/dist/db/d1/schema.d.ts.map +1 -0
  19. package/dist/db/d1/schema.js +58 -0
  20. package/dist/db/d1/schema.js.map +1 -0
  21. package/dist/db/mysql/index.d.ts +14 -0
  22. package/dist/db/mysql/index.d.ts.map +1 -0
  23. package/dist/db/mysql/index.js +248 -0
  24. package/dist/db/mysql/index.js.map +1 -0
  25. package/dist/db/mysql/schema.d.ts +562 -0
  26. package/dist/db/mysql/schema.d.ts.map +1 -0
  27. package/dist/db/mysql/schema.js +61 -0
  28. package/dist/db/mysql/schema.js.map +1 -0
  29. package/dist/db/postgresql/index.d.ts +14 -0
  30. package/dist/db/postgresql/index.d.ts.map +1 -0
  31. package/dist/db/postgresql/index.js +246 -0
  32. package/dist/db/postgresql/index.js.map +1 -0
  33. package/dist/db/postgresql/schema.d.ts +591 -0
  34. package/dist/db/postgresql/schema.d.ts.map +1 -0
  35. package/dist/db/postgresql/schema.js +64 -0
  36. package/dist/db/postgresql/schema.js.map +1 -0
  37. package/dist/index.d.ts +6 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +3 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/relay/api-proxy.d.ts +10 -0
  42. package/dist/relay/api-proxy.d.ts.map +1 -0
  43. package/dist/relay/api-proxy.js +40 -0
  44. package/dist/relay/api-proxy.js.map +1 -0
  45. package/dist/runtime/cf/crypto.d.ts +7 -0
  46. package/dist/runtime/cf/crypto.d.ts.map +1 -0
  47. package/dist/runtime/cf/crypto.js +48 -0
  48. package/dist/runtime/cf/crypto.js.map +1 -0
  49. package/dist/runtime/cf/index.d.ts +20 -0
  50. package/dist/runtime/cf/index.d.ts.map +1 -0
  51. package/dist/runtime/cf/index.js +14 -0
  52. package/dist/runtime/cf/index.js.map +1 -0
  53. package/dist/runtime/cf/relay.d.ts +11 -0
  54. package/dist/runtime/cf/relay.d.ts.map +1 -0
  55. package/dist/runtime/cf/relay.js +57 -0
  56. package/dist/runtime/cf/relay.js.map +1 -0
  57. package/dist/runtime/cf/vault.d.ts +7 -0
  58. package/dist/runtime/cf/vault.d.ts.map +1 -0
  59. package/dist/runtime/cf/vault.js +68 -0
  60. package/dist/runtime/cf/vault.js.map +1 -0
  61. package/dist/runtime/node/crypto.d.ts +6 -0
  62. package/dist/runtime/node/crypto.d.ts.map +1 -0
  63. package/dist/runtime/node/crypto.js +26 -0
  64. package/dist/runtime/node/crypto.js.map +1 -0
  65. package/dist/runtime/node/index.d.ts +17 -0
  66. package/dist/runtime/node/index.d.ts.map +1 -0
  67. package/dist/runtime/node/index.js +14 -0
  68. package/dist/runtime/node/index.js.map +1 -0
  69. package/dist/runtime/node/relay.d.ts +6 -0
  70. package/dist/runtime/node/relay.d.ts.map +1 -0
  71. package/dist/runtime/node/relay.js +73 -0
  72. package/dist/runtime/node/relay.js.map +1 -0
  73. package/dist/runtime/node/vault.d.ts +7 -0
  74. package/dist/runtime/node/vault.d.ts.map +1 -0
  75. package/dist/runtime/node/vault.js +41 -0
  76. package/dist/runtime/node/vault.js.map +1 -0
  77. package/dist/slack/events.d.ts +15 -0
  78. package/dist/slack/events.d.ts.map +1 -0
  79. package/dist/slack/events.js +63 -0
  80. package/dist/slack/events.js.map +1 -0
  81. package/dist/slack/oauth.d.ts +13 -0
  82. package/dist/slack/oauth.d.ts.map +1 -0
  83. package/dist/slack/oauth.js +90 -0
  84. package/dist/slack/oauth.js.map +1 -0
  85. package/dist/slack/provisioner.d.ts +60 -0
  86. package/dist/slack/provisioner.d.ts.map +1 -0
  87. package/dist/slack/provisioner.js +156 -0
  88. package/dist/slack/provisioner.js.map +1 -0
  89. package/dist/types/crypto.d.ts +15 -0
  90. package/dist/types/crypto.d.ts.map +1 -0
  91. package/dist/types/crypto.js +2 -0
  92. package/dist/types/crypto.js.map +1 -0
  93. package/dist/types/index.d.ts +6 -0
  94. package/dist/types/index.d.ts.map +1 -0
  95. package/dist/types/index.js +2 -0
  96. package/dist/types/index.js.map +1 -0
  97. package/dist/types/platform.d.ts +25 -0
  98. package/dist/types/platform.d.ts.map +1 -0
  99. package/dist/types/platform.js +2 -0
  100. package/dist/types/platform.js.map +1 -0
  101. package/dist/types/relay.d.ts +16 -0
  102. package/dist/types/relay.d.ts.map +1 -0
  103. package/dist/types/relay.js +2 -0
  104. package/dist/types/relay.js.map +1 -0
  105. package/dist/types/repository.d.ts +78 -0
  106. package/dist/types/repository.d.ts.map +1 -0
  107. package/dist/types/repository.js +6 -0
  108. package/dist/types/repository.js.map +1 -0
  109. package/dist/types/vault.d.ts +9 -0
  110. package/dist/types/vault.d.ts.map +1 -0
  111. package/dist/types/vault.js +2 -0
  112. package/dist/types/vault.js.map +1 -0
  113. package/dist/web/api.d.ts +9 -0
  114. package/dist/web/api.d.ts.map +1 -0
  115. package/dist/web/api.js +144 -0
  116. package/dist/web/api.js.map +1 -0
  117. package/dist/web/pages.d.ts +4 -0
  118. package/dist/web/pages.d.ts.map +1 -0
  119. package/dist/web/pages.js +401 -0
  120. package/dist/web/pages.js.map +1 -0
  121. package/dist/web/setup.d.ts +5 -0
  122. package/dist/web/setup.d.ts.map +1 -0
  123. package/dist/web/setup.js +208 -0
  124. package/dist/web/setup.js.map +1 -0
  125. package/package.json +46 -0
  126. package/src/app.ts +221 -0
  127. package/src/auth/handler.ts +343 -0
  128. package/src/auth/session.ts +89 -0
  129. package/src/db/d1/index.ts +304 -0
  130. package/src/db/d1/schema.ts +62 -0
  131. package/src/db/mysql/index.ts +301 -0
  132. package/src/db/mysql/schema.ts +78 -0
  133. package/src/db/postgresql/index.ts +311 -0
  134. package/src/db/postgresql/schema.ts +82 -0
  135. package/src/index.ts +21 -0
  136. package/src/relay/api-proxy.ts +61 -0
  137. package/src/runtime/cf/crypto.ts +74 -0
  138. package/src/runtime/cf/index.ts +31 -0
  139. package/src/runtime/cf/relay.ts +74 -0
  140. package/src/runtime/cf/vault.ts +99 -0
  141. package/src/runtime/node/crypto.ts +33 -0
  142. package/src/runtime/node/index.ts +28 -0
  143. package/src/runtime/node/relay.ts +98 -0
  144. package/src/runtime/node/vault.ts +50 -0
  145. package/src/slack/events.ts +92 -0
  146. package/src/slack/oauth.ts +127 -0
  147. package/src/slack/provisioner.ts +256 -0
  148. package/src/types/crypto.ts +14 -0
  149. package/src/types/index.ts +14 -0
  150. package/src/types/platform.ts +31 -0
  151. package/src/types/relay.ts +16 -0
  152. package/src/types/repository.ts +93 -0
  153. package/src/types/vault.ts +8 -0
  154. package/src/web/api.ts +204 -0
  155. package/src/web/pages.ts +458 -0
  156. package/src/web/setup.ts +270 -0
  157. package/tsconfig.json +19 -0
  158. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,63 @@
1
+ import { Hono } from 'hono';
2
+ /**
3
+ * Slack HTTP Events API receiver + relay to SSE/WebSocket Hub.
4
+ *
5
+ * Route: POST /slack/events/:botId
6
+ * - url_verification challenge auto-response
7
+ * - signing_secret signature verification
8
+ * - Relay to local runtime via RelayHub
9
+ */
10
+ export function createSlackEventsHandler(botRepo, vault, relay, crypto) {
11
+ const app = new Hono();
12
+ app.post('/slack/events/:botId', async (c) => {
13
+ const botId = c.req.param('botId');
14
+ const rawBody = await c.req.text();
15
+ const bot = await botRepo.findByIdAndStatus(botId, 'active');
16
+ if (!bot) {
17
+ return c.json({ error: 'unknown bot' }, 404);
18
+ }
19
+ // Signing secret verification
20
+ if (bot.signingSecretEnc) {
21
+ const signingSecret = await vault.decrypt(bot.signingSecretEnc);
22
+ const timestamp = c.req.header('x-slack-request-timestamp');
23
+ const slackSignature = c.req.header('x-slack-signature');
24
+ if (!timestamp || !slackSignature) {
25
+ return c.json({ error: 'missing slack signature headers' }, 401);
26
+ }
27
+ // Only allow requests within 5 minutes (replay attack prevention)
28
+ const now = Math.floor(Date.now() / 1000);
29
+ if (Math.abs(now - Number(timestamp)) > 300) {
30
+ return c.json({ error: 'request too old' }, 401);
31
+ }
32
+ const basestring = `v0:${timestamp}:${rawBody}`;
33
+ const hmac = await crypto.hmacSha256(signingSecret, basestring);
34
+ const computed = `v0=${hmac}`;
35
+ const isValid = await crypto.timingSafeEqual(computed, slackSignature);
36
+ if (!isValid) {
37
+ return c.json({ error: 'invalid signature' }, 401);
38
+ }
39
+ }
40
+ const payload = JSON.parse(rawBody);
41
+ // URL verification challenge
42
+ if (payload.type === 'url_verification') {
43
+ return c.json({ challenge: payload.challenge });
44
+ }
45
+ // event_callback -> relay to local runtime
46
+ if (payload.type === 'event_callback') {
47
+ const dispatched = relay.dispatch(botId, {
48
+ type: payload.type,
49
+ event: payload.event,
50
+ event_id: payload.event_id,
51
+ event_time: payload.event_time,
52
+ team_id: payload.team_id,
53
+ });
54
+ if (!dispatched) {
55
+ console.warn(`[events] bot ${botId} not connected, event dropped`);
56
+ }
57
+ }
58
+ // Slack expects 200 within 3 seconds
59
+ return c.json({ ok: true });
60
+ });
61
+ return app;
62
+ }
63
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/slack/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { Hono } from 'hono';
2
+ import type { Vault } from '../types/vault.js';
3
+ import type { CryptoProvider } from '../types/crypto.js';
4
+ import type { BotRepository, OAuthStateRepository } from '../types/repository.js';
5
+ /**
6
+ * Slack OAuth 2.0 handler.
7
+ *
8
+ * Flow:
9
+ * 1. GET /oauth/start/:botId -> Redirect to Slack auth page
10
+ * 2. Slack approves -> GET /oauth/callback -> acquire bot_token -> save to Vault
11
+ */
12
+ export declare function createOAuthHandler(botRepo: BotRepository, vault: Vault, crypto: CryptoProvider, oauthStates: OAuthStateRepository): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
13
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/slack/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACrB,MAAM,wBAAwB,CAAA;AAU/B;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,cAAc,EACtB,WAAW,EAAE,oBAAoB,8EAmGlC"}
@@ -0,0 +1,90 @@
1
+ import { Hono } from 'hono';
2
+ /**
3
+ * Slack OAuth 2.0 handler.
4
+ *
5
+ * Flow:
6
+ * 1. GET /oauth/start/:botId -> Redirect to Slack auth page
7
+ * 2. Slack approves -> GET /oauth/callback -> acquire bot_token -> save to Vault
8
+ */
9
+ export function createOAuthHandler(botRepo, vault, crypto, oauthStates) {
10
+ const app = new Hono();
11
+ app.get('/oauth/start/:botId', async (c) => {
12
+ const botId = c.req.param('botId');
13
+ const bot = await botRepo.findById(botId);
14
+ if (!bot || !bot.clientId) {
15
+ return c.json({ error: 'bot not found or not provisioned' }, 404);
16
+ }
17
+ // Clean up expired states
18
+ await oauthStates.deleteExpired();
19
+ const state = await crypto.randomHex(16);
20
+ await oauthStates.create({
21
+ state,
22
+ botId,
23
+ expiresAt: new Date(Date.now() + 5 * 60 * 1000),
24
+ });
25
+ const scopes = [
26
+ 'app_mentions:read',
27
+ 'chat:write',
28
+ 'chat:write.public',
29
+ 'channels:history',
30
+ 'channels:read',
31
+ 'channels:join',
32
+ 'groups:history',
33
+ 'groups:read',
34
+ 'im:history',
35
+ 'im:read',
36
+ 'im:write',
37
+ 'reactions:read',
38
+ 'reactions:write',
39
+ 'files:read',
40
+ 'files:write',
41
+ 'users:read',
42
+ ].join(',');
43
+ const slackUrl = new URL('https://slack.com/oauth/v2/authorize');
44
+ slackUrl.searchParams.set('client_id', bot.clientId);
45
+ slackUrl.searchParams.set('scope', scopes);
46
+ slackUrl.searchParams.set('state', state);
47
+ return c.redirect(slackUrl.toString());
48
+ });
49
+ app.get('/oauth/callback', async (c) => {
50
+ const code = c.req.query('code');
51
+ const state = c.req.query('state');
52
+ if (!code || !state) {
53
+ return c.json({ error: 'missing code or state' }, 400);
54
+ }
55
+ await oauthStates.deleteExpired();
56
+ const entry = await oauthStates.consume(state);
57
+ if (!entry) {
58
+ return c.json({ error: 'invalid or expired state' }, 400);
59
+ }
60
+ const bot = await botRepo.findById(entry.botId);
61
+ if (!bot || !bot.clientId || !bot.clientSecretEnc) {
62
+ return c.json({ error: 'bot configuration incomplete' }, 500);
63
+ }
64
+ const clientSecret = await vault.decrypt(bot.clientSecretEnc);
65
+ // Exchange code for token
66
+ const res = await fetch('https://slack.com/api/oauth.v2.access', {
67
+ method: 'POST',
68
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
69
+ body: new URLSearchParams({
70
+ client_id: bot.clientId,
71
+ client_secret: clientSecret,
72
+ code,
73
+ }),
74
+ });
75
+ const data = (await res.json());
76
+ if (!data.ok || !data.access_token) {
77
+ return c.json({ error: `Slack OAuth failed: ${data.error}` }, 400);
78
+ }
79
+ // Save bot token to Vault and activate
80
+ await botRepo.update(entry.botId, {
81
+ botTokenEnc: await vault.encrypt(data.access_token),
82
+ slackTeamId: data.team?.id ?? null,
83
+ status: 'active',
84
+ });
85
+ // Redirect to completion page
86
+ return c.redirect(`/bots/${entry.botId}/complete`);
87
+ });
88
+ return app;
89
+ }
90
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/slack/oauth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import type { Vault } from '../types/vault.js';
2
+ import type { BotRepository, ConfigTokenRepository } from '../types/repository.js';
3
+ declare const SLACK_MANIFEST_TEMPLATE: (opts: {
4
+ botName: string;
5
+ botUsername: string;
6
+ eventUrl: string;
7
+ redirectUrl: string;
8
+ }) => {
9
+ display_information: {
10
+ name: string;
11
+ description: string;
12
+ background_color: string;
13
+ };
14
+ features: {
15
+ bot_user: {
16
+ display_name: string;
17
+ always_online: boolean;
18
+ };
19
+ };
20
+ oauth_config: {
21
+ redirect_urls: string[];
22
+ scopes: {
23
+ bot: string[];
24
+ };
25
+ };
26
+ settings: {
27
+ event_subscriptions: {
28
+ request_url: string;
29
+ bot_events: string[];
30
+ };
31
+ interactivity: {
32
+ is_enabled: boolean;
33
+ };
34
+ org_deploy_enabled: boolean;
35
+ socket_mode_enabled: boolean;
36
+ };
37
+ };
38
+ export interface Provisioner {
39
+ rotateConfigToken(workspaceId: string): Promise<boolean>;
40
+ createApp(workspaceId: string, botId: string, botName: string, botUsername: string): Promise<{
41
+ ok: boolean;
42
+ appId?: string;
43
+ clientId?: string;
44
+ clientSecret?: string;
45
+ signingSecret?: string;
46
+ error?: string;
47
+ }>;
48
+ deleteApp(workspaceId: string, appId: string): Promise<{
49
+ ok: boolean;
50
+ error?: string;
51
+ }>;
52
+ SLACK_MANIFEST_TEMPLATE: typeof SLACK_MANIFEST_TEMPLATE;
53
+ }
54
+ /**
55
+ * Slack App Configuration Token management.
56
+ * One Config Token per workspace manages multiple apps.
57
+ */
58
+ export declare function createProvisioner(botRepo: BotRepository, configTokenRepo: ConfigTokenRepository, vault: Vault, platformBaseUrl: string): Provisioner;
59
+ export {};
60
+ //# sourceMappingURL=provisioner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisioner.d.ts","sourceRoot":"","sources":["../../src/slack/provisioner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACtB,MAAM,wBAAwB,CAAA;AAE/B,QAAA,MAAM,uBAAuB,GAAI,MAAM;IACrC,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDC,CAAA;AAqBF,MAAM,WAAW,WAAW;IAC1B,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACxD,SAAS,CACP,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QACT,EAAE,EAAE,OAAO,CAAA;QACX,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAC,CAAA;IACF,SAAS,CACP,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3C,uBAAuB,EAAE,OAAO,uBAAuB,CAAA;CACxD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,aAAa,EACtB,eAAe,EAAE,qBAAqB,EACtC,KAAK,EAAE,KAAK,EACZ,eAAe,EAAE,MAAM,GACtB,WAAW,CA4Ib"}
@@ -0,0 +1,156 @@
1
+ const SLACK_MANIFEST_TEMPLATE = (opts) => ({
2
+ display_information: {
3
+ name: opts.botName,
4
+ description: `${opts.botName} -- powered by sena-ai`,
5
+ background_color: '#1a1a2e',
6
+ },
7
+ features: {
8
+ bot_user: {
9
+ display_name: opts.botUsername,
10
+ always_online: true,
11
+ },
12
+ },
13
+ oauth_config: {
14
+ redirect_urls: [opts.redirectUrl],
15
+ scopes: {
16
+ bot: [
17
+ 'app_mentions:read',
18
+ 'chat:write',
19
+ 'chat:write.public',
20
+ 'channels:history',
21
+ 'channels:read',
22
+ 'channels:join',
23
+ 'groups:history',
24
+ 'groups:read',
25
+ 'im:history',
26
+ 'im:read',
27
+ 'im:write',
28
+ 'reactions:read',
29
+ 'reactions:write',
30
+ 'files:read',
31
+ 'files:write',
32
+ 'users:read',
33
+ ],
34
+ },
35
+ },
36
+ settings: {
37
+ event_subscriptions: {
38
+ request_url: opts.eventUrl,
39
+ bot_events: [
40
+ 'app_mention',
41
+ 'message.channels',
42
+ 'message.groups',
43
+ 'message.im',
44
+ 'reaction_added',
45
+ ],
46
+ },
47
+ interactivity: {
48
+ is_enabled: false,
49
+ },
50
+ org_deploy_enabled: false,
51
+ socket_mode_enabled: false,
52
+ },
53
+ });
54
+ /**
55
+ * Slack App Configuration Token management.
56
+ * One Config Token per workspace manages multiple apps.
57
+ */
58
+ export function createProvisioner(botRepo, configTokenRepo, vault, platformBaseUrl) {
59
+ async function rotateConfigToken(workspaceId) {
60
+ const row = await configTokenRepo.findByWorkspaceId(workspaceId);
61
+ if (!row)
62
+ return false;
63
+ const refreshToken = await vault.decrypt(row.refreshTokenEnc);
64
+ const res = await fetch('https://slack.com/api/tooling.tokens.rotate', {
65
+ method: 'POST',
66
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
67
+ body: new URLSearchParams({ refresh_token: refreshToken }),
68
+ });
69
+ const data = (await res.json());
70
+ if (!data.ok || !data.token || !data.refresh_token) {
71
+ console.error(`[provisioner] rotate failed for ${workspaceId}:`, data.error);
72
+ return false;
73
+ }
74
+ await configTokenRepo.upsert({
75
+ workspaceId,
76
+ accessTokenEnc: await vault.encrypt(data.token),
77
+ refreshTokenEnc: await vault.encrypt(data.refresh_token),
78
+ expiresAt: new Date((data.exp ?? 0) * 1000),
79
+ });
80
+ return true;
81
+ }
82
+ async function createApp(workspaceId, botId, botName, botUsername) {
83
+ const tokenRow = await configTokenRepo.findByWorkspaceId(workspaceId);
84
+ if (!tokenRow) {
85
+ return { ok: false, error: 'no config token for workspace' };
86
+ }
87
+ const configToken = await vault.decrypt(tokenRow.accessTokenEnc);
88
+ const eventUrl = `${platformBaseUrl}/slack/events/${botId}`;
89
+ const redirectUrl = `${platformBaseUrl}/oauth/callback`;
90
+ const manifest = SLACK_MANIFEST_TEMPLATE({
91
+ botName,
92
+ botUsername,
93
+ eventUrl,
94
+ redirectUrl,
95
+ });
96
+ const res = await fetch('https://slack.com/api/apps.manifest.create', {
97
+ method: 'POST',
98
+ headers: {
99
+ Authorization: `Bearer ${configToken}`,
100
+ 'Content-Type': 'application/json',
101
+ },
102
+ body: JSON.stringify({ manifest }),
103
+ });
104
+ const data = (await res.json());
105
+ if (!data.ok) {
106
+ console.error(`[provisioner] Slack API error detail:`, JSON.stringify(data));
107
+ return { ok: false, error: data.error };
108
+ }
109
+ await botRepo.update(botId, {
110
+ slackAppId: data.app_id ?? null,
111
+ clientId: data.credentials?.client_id ?? null,
112
+ clientSecretEnc: data.credentials?.client_secret
113
+ ? await vault.encrypt(data.credentials.client_secret)
114
+ : null,
115
+ signingSecretEnc: data.credentials?.signing_secret
116
+ ? await vault.encrypt(data.credentials.signing_secret)
117
+ : null,
118
+ manifestJson: JSON.stringify(manifest),
119
+ });
120
+ return {
121
+ ok: true,
122
+ appId: data.app_id,
123
+ clientId: data.credentials?.client_id,
124
+ clientSecret: data.credentials?.client_secret,
125
+ signingSecret: data.credentials?.signing_secret,
126
+ };
127
+ }
128
+ async function deleteApp(workspaceId, appId) {
129
+ const tokenRow = await configTokenRepo.findByWorkspaceId(workspaceId);
130
+ if (!tokenRow) {
131
+ return { ok: false, error: 'no config token for workspace' };
132
+ }
133
+ const configToken = await vault.decrypt(tokenRow.accessTokenEnc);
134
+ const res = await fetch('https://slack.com/api/apps.manifest.delete', {
135
+ method: 'POST',
136
+ headers: {
137
+ Authorization: `Bearer ${configToken}`,
138
+ 'Content-Type': 'application/json',
139
+ },
140
+ body: JSON.stringify({ app_id: appId }),
141
+ });
142
+ const data = (await res.json());
143
+ if (!data.ok) {
144
+ console.error(`[provisioner] Slack app delete failed for ${appId}:`, JSON.stringify(data));
145
+ return { ok: false, error: data.error };
146
+ }
147
+ return { ok: true };
148
+ }
149
+ return {
150
+ rotateConfigToken,
151
+ createApp,
152
+ deleteApp,
153
+ SLACK_MANIFEST_TEMPLATE,
154
+ };
155
+ }
156
+ //# sourceMappingURL=provisioner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisioner.js","sourceRoot":"","sources":["../../src/slack/provisioner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * CryptoProvider interface: platform-agnostic crypto operations.
3
+ * Node.js uses node:crypto, CF Workers uses Web Crypto API.
4
+ */
5
+ export interface CryptoProvider {
6
+ /** Generate a random hex string of the given byte length. */
7
+ randomHex(byteLength: number): Promise<string>;
8
+ /** Generate a UUID v4. */
9
+ uuid(): string;
10
+ /** Compute HMAC-SHA256 and return hex digest. */
11
+ hmacSha256(key: string, data: string): Promise<string>;
12
+ /** Constant-time string comparison. */
13
+ timingSafeEqual(a: string, b: string): Promise<boolean>;
14
+ }
15
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/types/crypto.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9C,0BAA0B;IAC1B,IAAI,IAAI,MAAM,CAAA;IACd,iDAAiD;IACjD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACtD,uCAAuC;IACvC,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACxD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/types/crypto.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ export type { Vault } from './vault.js';
2
+ export type { RelayHub } from './relay.js';
3
+ export type { CryptoProvider } from './crypto.js';
4
+ export type { BotRow, ConfigTokenRow, OAuthStateRow, WorkspaceAdminConfigRow, BotRepository, ConfigTokenRepository, OAuthStateRepository, WorkspaceAdminConfigRepository, } from './repository.js';
5
+ export type { Platform, AppConfig } from './platform.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AACvC,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,YAAY,EACV,MAAM,EACN,cAAc,EACd,aAAa,EACb,uBAAuB,EACvB,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,8BAA8B,GAC/B,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ import type { Vault } from './vault.js';
2
+ import type { RelayHub } from './relay.js';
3
+ import type { CryptoProvider } from './crypto.js';
4
+ import type { BotRepository, ConfigTokenRepository, OAuthStateRepository, WorkspaceAdminConfigRepository } from './repository.js';
5
+ /**
6
+ * Main Platform interface composing all platform-specific services.
7
+ * Implemented by platform-node and platform-cf.
8
+ */
9
+ export interface Platform {
10
+ vault: Vault;
11
+ relay: RelayHub;
12
+ crypto: CryptoProvider;
13
+ bots: BotRepository;
14
+ configTokens: ConfigTokenRepository;
15
+ oauthStates: OAuthStateRepository;
16
+ workspaceAdminConfig: WorkspaceAdminConfigRepository;
17
+ }
18
+ /**
19
+ * Application configuration shared across runtimes.
20
+ */
21
+ export interface AppConfig {
22
+ platformBaseUrl: string;
23
+ workspaceId: string;
24
+ }
25
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/types/platform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,8BAA8B,EAC/B,MAAM,iBAAiB,CAAA;AAExB;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,KAAK,CAAA;IACZ,KAAK,EAAE,QAAQ,CAAA;IACf,MAAM,EAAE,cAAc,CAAA;IACtB,IAAI,EAAE,aAAa,CAAA;IACnB,YAAY,EAAE,qBAAqB,CAAA;IACnC,WAAW,EAAE,oBAAoB,CAAA;IACjC,oBAAoB,EAAE,8BAA8B,CAAA;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;CACpB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/types/platform.ts"],"names":[],"mappings":""}
@@ -0,0 +1,16 @@
1
+ import type { Context } from 'hono';
2
+ /**
3
+ * RelayHub interface: manages connections between the platform and local bot runtimes.
4
+ * Node.js uses SSE, CF Workers uses WebSocket via Durable Objects.
5
+ */
6
+ export interface RelayHub {
7
+ /** Handle a new streaming connection from a bot runtime. */
8
+ handleStream(c: Context, botId: string, connectKey: string): Promise<Response>;
9
+ /** Dispatch a Slack event to the connected bot runtime. */
10
+ dispatch(botId: string, event: unknown): boolean;
11
+ /** Check if a specific bot is connected. */
12
+ isConnected(botId: string): boolean;
13
+ /** List all connected bot IDs. */
14
+ connectedBots(): string[];
15
+ }
16
+ //# sourceMappingURL=relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../src/types/relay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,4DAA4D;IAC5D,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC9E,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAA;IAChD,4CAA4C;IAC5C,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;IACnC,kCAAkC;IAClC,aAAa,IAAI,MAAM,EAAE,CAAA;CAC1B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.js","sourceRoot":"","sources":["../../src/types/relay.ts"],"names":[],"mappings":""}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Database row types and repository interfaces.
3
+ * These abstract away the underlying DB (MySQL, PostgreSQL, D1/SQLite) and ORM (Drizzle).
4
+ */
5
+ export interface BotRow {
6
+ id: string;
7
+ name: string;
8
+ botUsername: string;
9
+ profileImageUrl: string | null;
10
+ connectKey: string;
11
+ slackAppId: string | null;
12
+ slackTeamId: string | null;
13
+ botTokenEnc: string | null;
14
+ signingSecretEnc: string | null;
15
+ clientId: string | null;
16
+ clientSecretEnc: string | null;
17
+ manifestJson: string | null;
18
+ status: 'pending' | 'active' | 'disabled';
19
+ createdAt: Date;
20
+ updatedAt: Date;
21
+ }
22
+ export interface ConfigTokenRow {
23
+ workspaceId: string;
24
+ accessTokenEnc: string;
25
+ refreshTokenEnc: string;
26
+ expiresAt: Date;
27
+ updatedAt: Date;
28
+ }
29
+ export interface OAuthStateRow {
30
+ state: string;
31
+ botId: string;
32
+ expiresAt: Date;
33
+ }
34
+ export interface WorkspaceAdminConfigRow {
35
+ workspaceId: string;
36
+ slackClientId: string | null;
37
+ slackClientSecretEnc: string | null;
38
+ dCookieEnc: string | null;
39
+ xoxcTokenEnc: string | null;
40
+ workspaceDomain: string | null;
41
+ updatedAt: Date;
42
+ updatedByUserId: string | null;
43
+ }
44
+ export interface BotRepository {
45
+ findById(id: string): Promise<BotRow | null>;
46
+ findByConnectKey(connectKey: string): Promise<BotRow | null>;
47
+ findByConnectKeyAndStatus(connectKey: string, status: BotRow['status']): Promise<BotRow | null>;
48
+ findByIdAndStatus(id: string, status: BotRow['status']): Promise<BotRow | null>;
49
+ findAll(): Promise<BotRow[]>;
50
+ findAllSummary(): Promise<Array<{
51
+ id: string;
52
+ name: string;
53
+ profileImageUrl: string | null;
54
+ slackAppId: string | null;
55
+ slackTeamId: string | null;
56
+ status: BotRow['status'];
57
+ createdAt: Date;
58
+ }>>;
59
+ create(bot: Omit<BotRow, 'createdAt' | 'updatedAt'>): Promise<void>;
60
+ update(id: string, data: Partial<Omit<BotRow, 'id'>>): Promise<void>;
61
+ delete(id: string): Promise<void>;
62
+ }
63
+ export interface ConfigTokenRepository {
64
+ findByWorkspaceId(id: string): Promise<ConfigTokenRow | null>;
65
+ findAll(): Promise<ConfigTokenRow[]>;
66
+ upsert(row: Omit<ConfigTokenRow, 'updatedAt'>): Promise<void>;
67
+ }
68
+ export interface OAuthStateRepository {
69
+ create(row: OAuthStateRow): Promise<void>;
70
+ consume(state: string): Promise<OAuthStateRow | null>;
71
+ deleteExpired(): Promise<void>;
72
+ }
73
+ export interface WorkspaceAdminConfigRepository {
74
+ findByWorkspaceId(workspaceId: string): Promise<WorkspaceAdminConfigRow | null>;
75
+ findAll(): Promise<WorkspaceAdminConfigRow[]>;
76
+ upsert(config: Omit<WorkspaceAdminConfigRow, 'updatedAt'>): Promise<void>;
77
+ }
78
+ //# sourceMappingURL=repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/types/repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Database row types and repository interfaces.
3
+ * These abstract away the underlying DB (MySQL, PostgreSQL, D1/SQLite) and ORM (Drizzle).
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/types/repository.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Vault interface for encrypting/decrypting secrets.
3
+ * All methods return Promises to support Web Crypto (async) implementations.
4
+ */
5
+ export interface Vault {
6
+ encrypt(plaintext: string): Promise<string>;
7
+ decrypt(encoded: string): Promise<string>;
8
+ }
9
+ //# sourceMappingURL=vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../src/types/vault.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,KAAK;IACpB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3C,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CAC1C"}