@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
package/dist/app.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { Hono } from 'hono';
2
+ import type { Platform, AppConfig } from './types/platform.js';
3
+ import { type Provisioner } from './slack/provisioner.js';
4
+ export interface CreateAppResult {
5
+ app: Hono;
6
+ provisioner: Provisioner;
7
+ }
8
+ export declare function createApp(platform: Platform, config: AppConfig): CreateAppResult;
9
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAI9D,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAM5E,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,IAAI,CAAA;IACT,WAAW,EAAE,WAAW,CAAA;CACzB;AAgFD,wBAAgB,SAAS,CACvB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,SAAS,GAChB,eAAe,CA0HjB"}
package/dist/app.js ADDED
@@ -0,0 +1,147 @@
1
+ import { Hono } from 'hono';
2
+ import { logger } from 'hono/logger';
3
+ import { createApiProxy } from './relay/api-proxy.js';
4
+ import { createSlackEventsHandler } from './slack/events.js';
5
+ import { createOAuthHandler } from './slack/oauth.js';
6
+ import { createProvisioner } from './slack/provisioner.js';
7
+ import { createAuthHandler, createAuthMiddleware } from './auth/handler.js';
8
+ import { createWebApi } from './web/api.js';
9
+ import { createPages } from './web/pages.js';
10
+ import { createSetupPage } from './web/setup.js';
11
+ /**
12
+ * Create the main Hono application with all routes wired up.
13
+ * Works in both Node.js and CF Workers environments.
14
+ */
15
+ function generateInstallScript() {
16
+ return `#!/bin/sh
17
+ set -e
18
+
19
+ # sena-ai bot bootstrap script
20
+ # Usage: curl -fsSL <platform-url>/install.sh | sh -s -- --name "봇이름" --bot-username "lily-bot" --connect-key "cpk_..." --platform-url "https://..."
21
+
22
+ BOT_NAME=""
23
+ BOT_USERNAME=""
24
+ CONNECT_KEY=""
25
+ PLATFORM_URL=""
26
+
27
+ while [ \$# -gt 0 ]; do
28
+ case "\$1" in
29
+ --name) BOT_NAME="\$2"; shift 2;;
30
+ --bot-username) BOT_USERNAME="\$2"; shift 2;;
31
+ --connect-key) CONNECT_KEY="\$2"; shift 2;;
32
+ --platform-url) PLATFORM_URL="\$2"; shift 2;;
33
+ *) echo "Unknown option: \$1"; exit 1;;
34
+ esac
35
+ done
36
+
37
+ if [ -z "\$BOT_NAME" ] || [ -z "\$BOT_USERNAME" ] || [ -z "\$CONNECT_KEY" ] || [ -z "\$PLATFORM_URL" ]; then
38
+ echo "Error: --name, --bot-username, --connect-key, --platform-url are all required."
39
+ exit 1
40
+ fi
41
+
42
+ DIR_NAME="\$BOT_USERNAME"
43
+
44
+ echo "🤖 Setting up bot: \$BOT_NAME"
45
+ echo " Directory: ./\$DIR_NAME"
46
+ echo ""
47
+
48
+ # Download template from GitHub
49
+ echo "📦 Downloading bot template..."
50
+ TMPDIR_DL=\$(mktemp -d)
51
+ curl -fsSL https://github.com/unlimiting-studio/sena-ai/archive/refs/heads/main.tar.gz -o "\$TMPDIR_DL/repo.tar.gz"
52
+ tar xzf "\$TMPDIR_DL/repo.tar.gz" -C "\$TMPDIR_DL"
53
+
54
+ # Copy template directory
55
+ cp -r "\$TMPDIR_DL/sena-ai-main/templates/bot-starter" "\$DIR_NAME"
56
+ rm -rf "\$TMPDIR_DL"
57
+
58
+ cd "\$DIR_NAME"
59
+
60
+ # Escape special characters for sed replacement
61
+ escape_sed() {
62
+ printf '%s' "\$1" | sed 's/[&/\\]/\\&/g'
63
+ }
64
+
65
+ # Customize package.json name
66
+ ESCAPED_DIR=\$(escape_sed "\$DIR_NAME")
67
+ sed -i.bak "s/\\"sena-bot\\"/\\"\$ESCAPED_DIR\\"/" package.json && rm -f package.json.bak
68
+
69
+ # Replace bot name placeholder in sena.config.ts
70
+ ESCAPED_NAME=\$(escape_sed "\$BOT_NAME")
71
+ sed -i.bak "s/%%BOT_NAME%%/\$ESCAPED_NAME/" sena.config.ts && rm -f sena.config.ts.bak
72
+
73
+ # Create .env from template
74
+ ESCAPED_KEY=\$(escape_sed "\$CONNECT_KEY")
75
+ sed -e "s/%%CONNECT_KEY%%/\$ESCAPED_KEY/" -e "s|%%PLATFORM_URL%%|\$PLATFORM_URL|" .env.template > .env
76
+ rm -f .env.template
77
+
78
+ echo ""
79
+ echo "✅ Bot scaffolding complete!"
80
+ echo ""
81
+ echo "Next steps:"
82
+ echo " cd \$DIR_NAME"
83
+ echo " pnpm install"
84
+ echo " npx sena start"
85
+ echo ""
86
+ `;
87
+ }
88
+ export function createApp(platform, config) {
89
+ const app = new Hono();
90
+ app.use('*', logger());
91
+ const provisioner = createProvisioner(platform.bots, platform.configTokens, platform.vault, config.platformBaseUrl);
92
+ const authMiddleware = createAuthMiddleware(platform.workspaceAdminConfig, platform.vault);
93
+ // Serve bootstrap script at /install.sh
94
+ app.get('/install.sh', (c) => {
95
+ c.header('Content-Type', 'text/plain; charset=utf-8');
96
+ return c.body(generateInstallScript());
97
+ });
98
+ // Health check
99
+ app.get('/health', (c) => c.json({
100
+ ok: true,
101
+ connectedBots: platform.relay.connectedBots().length,
102
+ ts: new Date().toISOString(),
103
+ }));
104
+ // SSE/WebSocket relay stream endpoint
105
+ app.get('/relay/stream', async (c) => {
106
+ const connectKey = c.req.header('x-connect-key') || c.req.query('connect_key');
107
+ if (!connectKey) {
108
+ return c.json({ error: 'missing connect_key' }, 401);
109
+ }
110
+ const bot = await platform.bots.findByConnectKeyAndStatus(connectKey, 'active');
111
+ if (!bot) {
112
+ return c.json({ error: 'invalid connect_key or bot not active' }, 401);
113
+ }
114
+ return platform.relay.handleStream(c, bot.id, connectKey);
115
+ });
116
+ // Slack API proxy
117
+ app.route('/', createApiProxy(platform.bots, platform.vault));
118
+ // Slack events
119
+ app.route('/', createSlackEventsHandler(platform.bots, platform.vault, platform.relay, platform.crypto));
120
+ // Bot installation OAuth
121
+ app.route('/', createOAuthHandler(platform.bots, platform.vault, platform.crypto, platform.oauthStates));
122
+ // Slack login setup + auth
123
+ app.route('/', createSetupPage(platform.workspaceAdminConfig, platform.vault));
124
+ app.route('/', createAuthHandler(platform.workspaceAdminConfig, platform.oauthStates, platform.crypto, platform.vault, { platformBaseUrl: config.platformBaseUrl }));
125
+ // Protect all subsequent web/API/admin routes.
126
+ app.use('/', authMiddleware.requireAuth);
127
+ app.use('/bots/*', authMiddleware.requireAuth);
128
+ app.use('/api/*', authMiddleware.requireAuth);
129
+ app.use('/admin/*', authMiddleware.requireAuth);
130
+ // Web API
131
+ app.route('/', createWebApi(platform.bots, provisioner, platform.crypto, config.workspaceId));
132
+ // Web UI pages
133
+ app.route('/', createPages(platform.bots, config.platformBaseUrl));
134
+ // Admin endpoints
135
+ app.get('/admin/bots', async (c) => {
136
+ const allBots = await platform.bots.findAllSummary();
137
+ return c.json({ bots: allBots });
138
+ });
139
+ app.get('/admin/connections', (c) => {
140
+ return c.json({
141
+ connected: platform.relay.connectedBots(),
142
+ count: platform.relay.connectedBots().length,
143
+ });
144
+ });
145
+ return { app, provisioner };
146
+ }
147
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { Hono } from 'hono';
2
+ import type { Context, Next } from 'hono';
3
+ import type { OAuthStateRepository, WorkspaceAdminConfigRepository } from '../types/repository.js';
4
+ import type { CryptoProvider } from '../types/crypto.js';
5
+ import type { Vault } from '../types/vault.js';
6
+ import { type AuthSession, type AuthSessionUser } from './session.js';
7
+ export interface AuthEnv {
8
+ Variables: {
9
+ user: AuthSessionUser;
10
+ session: AuthSession;
11
+ };
12
+ }
13
+ export declare function createAuthHandler(workspaceAdminConfig: WorkspaceAdminConfigRepository, oauthStates: OAuthStateRepository, crypto: CryptoProvider, vault: Vault, config: {
14
+ platformBaseUrl: string;
15
+ }): Hono<AuthEnv, import("hono/types").BlankSchema, "/">;
16
+ export declare function createAuthMiddleware(workspaceAdminConfig: WorkspaceAdminConfigRepository, vault: Vault): {
17
+ requireAuth: (c: Context, next: Next) => Promise<Response | undefined>;
18
+ };
19
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/auth/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAGzC,OAAO,KAAK,EAAE,oBAAoB,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAA;AAClG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,cAAc,CAAA;AAqBrB,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE;QACT,IAAI,EAAE,eAAe,CAAA;QACrB,OAAO,EAAE,WAAW,CAAA;KACrB,CAAA;CACF;AAED,wBAAgB,iBAAiB,CAC/B,oBAAoB,EAAE,8BAA8B,EACpD,WAAW,EAAE,oBAAoB,EACjC,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE;IACN,eAAe,EAAE,MAAM,CAAA;CACxB,wDA+JF;AAED,wBAAgB,oBAAoB,CAClC,oBAAoB,EAAE,8BAA8B,EACpD,KAAK,EAAE,KAAK;qBAEkB,OAAO,QAAQ,IAAI;EAgClD"}
@@ -0,0 +1,213 @@
1
+ import { Hono } from 'hono';
2
+ import { deleteCookie, getCookie, setCookie } from 'hono/cookie';
3
+ import { AUTH_SESSION_MAX_AGE_SECONDS, createSessionCookieValue, parseSessionCookieValue, } from './session.js';
4
+ const DEFAULT_WORKSPACE_ADMIN_CONFIG_ID = 'default';
5
+ const LOGIN_STATE_PREFIX = 'login:';
6
+ export function createAuthHandler(workspaceAdminConfig, oauthStates, crypto, vault, config) {
7
+ const app = new Hono();
8
+ app.get('/auth/login', async (c) => {
9
+ const creds = await getSlackLoginCredentials(workspaceAdminConfig, vault);
10
+ if (!creds) {
11
+ return c.redirect('/setup');
12
+ }
13
+ const state = await crypto.randomHex(16);
14
+ const nonce = await crypto.randomHex(8);
15
+ await oauthStates.deleteExpired();
16
+ await oauthStates.create({
17
+ state,
18
+ botId: `${LOGIN_STATE_PREFIX}${nonce}`,
19
+ expiresAt: new Date(Date.now() + 10 * 60 * 1000),
20
+ });
21
+ const params = new URLSearchParams({
22
+ response_type: 'code',
23
+ client_id: creds.clientId,
24
+ scope: 'openid profile email',
25
+ redirect_uri: `${config.platformBaseUrl}/auth/callback`,
26
+ state,
27
+ nonce,
28
+ });
29
+ return c.redirect(`https://slack.com/openid/connect/authorize?${params.toString()}`);
30
+ });
31
+ app.get('/auth/callback', async (c) => {
32
+ const error = c.req.query('error');
33
+ if (error) {
34
+ return renderErrorPage(c, 'Slack 로그인 오류', error, 400);
35
+ }
36
+ const code = c.req.query('code');
37
+ const state = c.req.query('state');
38
+ if (!code || !state) {
39
+ return renderErrorPage(c, '잘못된 요청', 'code/state가 누락됐어요.', 400);
40
+ }
41
+ await oauthStates.deleteExpired();
42
+ const storedState = await oauthStates.consume(state);
43
+ if (!storedState || !storedState.botId.startsWith(LOGIN_STATE_PREFIX)) {
44
+ return renderErrorPage(c, '잘못된 상태', '로그인 상태가 만료됐거나 유효하지 않아요.', 400);
45
+ }
46
+ const creds = await getSlackLoginCredentials(workspaceAdminConfig, vault);
47
+ if (!creds) {
48
+ return c.redirect('/setup');
49
+ }
50
+ const redirectUri = `${config.platformBaseUrl}/auth/callback`;
51
+ const tokenRes = await fetch('https://slack.com/api/openid.connect.token', {
52
+ method: 'POST',
53
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
54
+ body: new URLSearchParams({
55
+ client_id: creds.clientId,
56
+ client_secret: creds.clientSecret,
57
+ code,
58
+ redirect_uri: redirectUri,
59
+ grant_type: 'authorization_code',
60
+ }),
61
+ });
62
+ const tokenData = (await tokenRes.json());
63
+ if (!tokenData.ok || !tokenData.access_token) {
64
+ return renderErrorPage(c, 'Slack 토큰 교환 실패', tokenData.error ?? 'unknown_error', 400);
65
+ }
66
+ const userInfoRes = await fetch('https://slack.com/api/openid.connect.userInfo', {
67
+ headers: { Authorization: `Bearer ${tokenData.access_token}` },
68
+ });
69
+ const userInfo = (await userInfoRes.json());
70
+ if (!userInfo.ok || !userInfo.sub) {
71
+ return renderErrorPage(c, 'Slack 사용자 정보 조회 실패', userInfo.error ?? 'unknown_error', 400);
72
+ }
73
+ const slackTeamId = userInfo['https://slack.com/team_id'] ?? '';
74
+ if (!slackTeamId) {
75
+ return renderErrorPage(c, 'Slack 팀 정보 누락', 'team_id를 확인할 수 없어요.', 400);
76
+ }
77
+ const configs = await listConfiguredSlackLoginConfigs(workspaceAdminConfig);
78
+ const configuredTeamIds = getConfiguredTeamIds(configs);
79
+ if (configuredTeamIds.length > 0 &&
80
+ !configuredTeamIds.includes(slackTeamId)) {
81
+ return renderErrorPage(c, '허용되지 않은 워크스페이스', `${slackTeamId} 워크스페이스는 이 플랫폼에 접근할 수 없어요.`, 403);
82
+ }
83
+ const defaultConfig = configs.find((cfg) => cfg.workspaceId === DEFAULT_WORKSPACE_ADMIN_CONFIG_ID);
84
+ const teamConfig = configs.find((cfg) => cfg.workspaceId === slackTeamId);
85
+ if (!teamConfig && defaultConfig) {
86
+ await workspaceAdminConfig.upsert({
87
+ workspaceId: slackTeamId,
88
+ slackClientId: defaultConfig.slackClientId,
89
+ slackClientSecretEnc: defaultConfig.slackClientSecretEnc,
90
+ dCookieEnc: defaultConfig.dCookieEnc,
91
+ xoxcTokenEnc: defaultConfig.xoxcTokenEnc,
92
+ workspaceDomain: defaultConfig.workspaceDomain,
93
+ updatedByUserId: defaultConfig.updatedByUserId,
94
+ });
95
+ }
96
+ const user = {
97
+ slackUserId: userInfo.sub,
98
+ slackTeamId,
99
+ name: userInfo.name ?? 'Slack User',
100
+ email: userInfo.email ?? null,
101
+ avatarUrl: userInfo.picture ?? null,
102
+ };
103
+ const expiresAt = new Date(Date.now() + AUTH_SESSION_MAX_AGE_SECONDS * 1000);
104
+ const sessionCookie = await createSessionCookieValue(vault, user, expiresAt);
105
+ setCookie(c, 'sena_session', sessionCookie, {
106
+ httpOnly: true,
107
+ secure: true,
108
+ sameSite: 'Lax',
109
+ path: '/',
110
+ maxAge: AUTH_SESSION_MAX_AGE_SECONDS,
111
+ });
112
+ return c.redirect('/');
113
+ });
114
+ app.post('/auth/logout', (c) => {
115
+ deleteCookie(c, 'sena_session', { path: '/' });
116
+ return c.redirect('/auth/login');
117
+ });
118
+ return app;
119
+ }
120
+ export function createAuthMiddleware(workspaceAdminConfig, vault) {
121
+ const requireAuth = async (c, next) => {
122
+ const configs = await listConfiguredSlackLoginConfigs(workspaceAdminConfig);
123
+ if (configs.length === 0) {
124
+ return unauthenticated(c, '/setup', 'slack_login_not_configured', 503);
125
+ }
126
+ const rawSession = getCookie(c, 'sena_session');
127
+ if (!rawSession) {
128
+ return unauthenticated(c, '/auth/login', 'unauthorized', 401);
129
+ }
130
+ const session = await parseSessionCookieValue(vault, rawSession);
131
+ if (!session) {
132
+ deleteCookie(c, 'sena_session', { path: '/' });
133
+ return unauthenticated(c, '/auth/login', 'unauthorized', 401);
134
+ }
135
+ const configuredTeamIds = getConfiguredTeamIds(configs);
136
+ if (configuredTeamIds.length > 0 &&
137
+ !configuredTeamIds.includes(session.user.slackTeamId)) {
138
+ deleteCookie(c, 'sena_session', { path: '/' });
139
+ return unauthenticated(c, '/auth/login', 'workspace_forbidden', 403);
140
+ }
141
+ c.set('user', session.user);
142
+ c.set('session', session);
143
+ await next();
144
+ };
145
+ return { requireAuth };
146
+ }
147
+ async function getSlackLoginCredentials(workspaceAdminConfig, vault) {
148
+ const configs = await listConfiguredSlackLoginConfigs(workspaceAdminConfig);
149
+ const preferredConfig = configs.find((cfg) => cfg.workspaceId !== DEFAULT_WORKSPACE_ADMIN_CONFIG_ID) ??
150
+ configs[0];
151
+ if (!preferredConfig?.slackClientId || !preferredConfig.slackClientSecretEnc) {
152
+ return null;
153
+ }
154
+ return {
155
+ clientId: preferredConfig.slackClientId,
156
+ clientSecret: await vault.decrypt(preferredConfig.slackClientSecretEnc),
157
+ };
158
+ }
159
+ async function listConfiguredSlackLoginConfigs(workspaceAdminConfig) {
160
+ const configs = await workspaceAdminConfig.findAll();
161
+ return configs.filter((config) => typeof config.slackClientId === 'string' &&
162
+ config.slackClientId.trim().length > 0 &&
163
+ typeof config.slackClientSecretEnc === 'string' &&
164
+ config.slackClientSecretEnc.length > 0);
165
+ }
166
+ function getConfiguredTeamIds(configs) {
167
+ return configs
168
+ .map((config) => config.workspaceId)
169
+ .filter((workspaceId) => workspaceId !== DEFAULT_WORKSPACE_ADMIN_CONFIG_ID);
170
+ }
171
+ function unauthenticated(c, redirectPath, error, status) {
172
+ if (c.req.path.startsWith('/api/')) {
173
+ return c.json({ error, redirectTo: redirectPath }, { status });
174
+ }
175
+ return c.redirect(redirectPath);
176
+ }
177
+ function renderErrorPage(c, title, message, status) {
178
+ return c.html(`<!DOCTYPE html>
179
+ <html lang="ko">
180
+ <head>
181
+ <meta charset="UTF-8">
182
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
183
+ <title>${escapeHtml(title)} - Sena Platform</title>
184
+ <script src="https://cdn.tailwindcss.com"></script>
185
+ </head>
186
+ <body class="bg-gray-50 min-h-screen flex items-center justify-center px-4">
187
+ <main class="w-full max-w-md bg-white rounded-xl shadow-sm border border-gray-200 p-8 text-center">
188
+ <h1 class="text-xl font-bold text-gray-900 mb-2">${escapeHtml(title)}</h1>
189
+ <p class="text-sm text-gray-600 mb-6">${escapeHtml(message)}</p>
190
+ <a href="/auth/login" class="inline-flex items-center px-4 py-2 bg-indigo-600 text-white font-medium rounded-lg hover:bg-indigo-700 transition-colors">다시 로그인</a>
191
+ </main>
192
+ </body>
193
+ </html>`, { status });
194
+ }
195
+ function escapeHtml(value) {
196
+ return value.replace(/[&<>"']/g, (char) => {
197
+ switch (char) {
198
+ case '&':
199
+ return '&amp;';
200
+ case '<':
201
+ return '&lt;';
202
+ case '>':
203
+ return '&gt;';
204
+ case '"':
205
+ return '&quot;';
206
+ case "'":
207
+ return '&#39;';
208
+ default:
209
+ return char;
210
+ }
211
+ });
212
+ }
213
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/auth/handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Vault } from '../types/vault.js';
2
+ export interface AuthSessionUser {
3
+ slackUserId: string;
4
+ slackTeamId: string;
5
+ name: string;
6
+ email: string | null;
7
+ avatarUrl: string | null;
8
+ }
9
+ export interface AuthSession {
10
+ user: AuthSessionUser;
11
+ expiresAt: string;
12
+ }
13
+ export declare const AUTH_SESSION_MAX_AGE_SECONDS: number;
14
+ export declare function createSessionCookieValue(vault: Vault, user: AuthSessionUser, expiresAt: Date): Promise<string>;
15
+ export declare function parseSessionCookieValue(vault: Vault, rawCookieValue: string): Promise<AuthSession | null>;
16
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,eAAO,MAAM,4BAA4B,QAAoB,CAAA;AAE7D,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,IAAI,GACd,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,KAAK,EACZ,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAqB7B"}
@@ -0,0 +1,54 @@
1
+ export const AUTH_SESSION_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;
2
+ export async function createSessionCookieValue(vault, user, expiresAt) {
3
+ const encrypted = await vault.encrypt(JSON.stringify({
4
+ user,
5
+ expiresAt: expiresAt.toISOString(),
6
+ }));
7
+ return toBase64Url(encrypted);
8
+ }
9
+ export async function parseSessionCookieValue(vault, rawCookieValue) {
10
+ try {
11
+ const decrypted = await vault.decrypt(fromBase64Url(rawCookieValue));
12
+ const parsed = JSON.parse(decrypted);
13
+ if (!isAuthSession(parsed)) {
14
+ return null;
15
+ }
16
+ const expiresAt = new Date(parsed.expiresAt);
17
+ if (Number.isNaN(expiresAt.getTime()) || expiresAt <= new Date()) {
18
+ return null;
19
+ }
20
+ return {
21
+ user: parsed.user,
22
+ expiresAt: expiresAt.toISOString(),
23
+ };
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ }
29
+ function isRecord(value) {
30
+ return typeof value === 'object' && value !== null;
31
+ }
32
+ function isAuthSessionUser(value) {
33
+ if (!isRecord(value))
34
+ return false;
35
+ return (typeof value.slackUserId === 'string' &&
36
+ typeof value.slackTeamId === 'string' &&
37
+ typeof value.name === 'string' &&
38
+ (value.email === null || typeof value.email === 'string') &&
39
+ (value.avatarUrl === null || typeof value.avatarUrl === 'string'));
40
+ }
41
+ function isAuthSession(value) {
42
+ if (!isRecord(value))
43
+ return false;
44
+ return typeof value.expiresAt === 'string' && isAuthSessionUser(value.user);
45
+ }
46
+ function toBase64Url(base64) {
47
+ return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/u, '');
48
+ }
49
+ function fromBase64Url(base64Url) {
50
+ const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
51
+ const paddingLength = (4 - (base64.length % 4 || 4)) % 4;
52
+ return base64 + '='.repeat(paddingLength);
53
+ }
54
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type DrizzleD1Database } from 'drizzle-orm/d1';
2
+ import type { BotRepository, ConfigTokenRepository, OAuthStateRepository, WorkspaceAdminConfigRepository } from '../../types/repository.js';
3
+ import * as schema from './schema.js';
4
+ export type D1Db = DrizzleD1Database<typeof schema>;
5
+ export declare function initD1(d1: D1Database): D1Db;
6
+ export interface D1Repositories {
7
+ bots: BotRepository;
8
+ configTokens: ConfigTokenRepository;
9
+ oauthStates: OAuthStateRepository;
10
+ workspaceAdminConfig: WorkspaceAdminConfigRepository;
11
+ }
12
+ export declare function createD1Repositories(db: D1Db): D1Repositories;
13
+ export { bots, configTokens, oauthStates, workspaceAdminConfig } from './schema.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/db/d1/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAEhE,OAAO,KAAK,EAIV,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,8BAA8B,EAC/B,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC,MAAM,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,MAAM,CAAC,CAAA;AAEnD,wBAAgB,MAAM,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI,CAE3C;AAqCD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAA;IACnB,YAAY,EAAE,qBAAqB,CAAA;IACnC,WAAW,EAAE,oBAAoB,CAAA;IACjC,oBAAoB,EAAE,8BAA8B,CAAA;CACrD;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,IAAI,GAAG,cAAc,CAO7D;AA2OD,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA"}