@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,10 @@
1
+ import { Hono } from 'hono';
2
+ import type { Vault } from '../types/vault.js';
3
+ import type { BotRepository } from '../types/repository.js';
4
+ /**
5
+ * Slack API proxy.
6
+ * Local runtimes send POST /relay/api with Slack API calls.
7
+ * The proxy decrypts the bot_token from Vault and forwards the request.
8
+ */
9
+ export declare function createApiProxy(botRepo: BotRepository, vault: Vault): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
10
+ //# sourceMappingURL=api-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-proxy.d.ts","sourceRoot":"","sources":["../../src/relay/api-proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAE3D;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,8EAmDlE"}
@@ -0,0 +1,40 @@
1
+ import { Hono } from 'hono';
2
+ /**
3
+ * Slack API proxy.
4
+ * Local runtimes send POST /relay/api with Slack API calls.
5
+ * The proxy decrypts the bot_token from Vault and forwards the request.
6
+ */
7
+ export function createApiProxy(botRepo, vault) {
8
+ const app = new Hono();
9
+ app.post('/relay/api', async (c) => {
10
+ const connectKey = c.req.header('x-connect-key');
11
+ if (!connectKey) {
12
+ return c.json({ ok: false, error: 'missing x-connect-key header' }, 401);
13
+ }
14
+ const bot = await botRepo.findByConnectKeyAndStatus(connectKey, 'active');
15
+ if (!bot) {
16
+ return c.json({ ok: false, error: 'invalid connect_key or bot not active' }, 401);
17
+ }
18
+ if (!bot.botTokenEnc) {
19
+ return c.json({ ok: false, error: 'bot has no token configured' }, 500);
20
+ }
21
+ const botToken = await vault.decrypt(bot.botTokenEnc);
22
+ const body = await c.req.json();
23
+ if (!body.method) {
24
+ return c.json({ ok: false, error: 'missing method field' }, 400);
25
+ }
26
+ const slackUrl = `https://slack.com/api/${body.method}`;
27
+ const slackRes = await fetch(slackUrl, {
28
+ method: 'POST',
29
+ headers: {
30
+ Authorization: `Bearer ${botToken}`,
31
+ 'Content-Type': 'application/json; charset=utf-8',
32
+ },
33
+ body: JSON.stringify(body.params || {}),
34
+ });
35
+ const slackData = await slackRes.json();
36
+ return c.json(slackData);
37
+ });
38
+ return app;
39
+ }
40
+ //# sourceMappingURL=api-proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-proxy.js","sourceRoot":"","sources":["../../src/relay/api-proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAI3B;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAAsB,EAAE,KAAY;IACjE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;IAEtB,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAA;QAChD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,8BAA8B,EAAE,EACpD,GAAG,CACJ,CAAA;QACH,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,yBAAyB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QACzE,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,uCAAuC,EAAE,EAC7D,GAAG,CACJ,CAAA;QACH,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,EAAE,GAAG,CAAC,CAAA;QACzE,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QAErD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAGzB,CAAA;QAEJ,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,EAAE,GAAG,CAAC,CAAA;QAClE,CAAC;QAED,MAAM,QAAQ,GAAG,yBAAyB,IAAI,CAAC,MAAM,EAAE,CAAA;QAEvD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;YACrC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,QAAQ,EAAE;gBACnC,cAAc,EAAE,iCAAiC;aAClD;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;SACxC,CAAC,CAAA;QAEF,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QACvC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAoC,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,OAAO,GAAG,CAAA;AACZ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { CryptoProvider } from '../../types/crypto.js';
2
+ /**
3
+ * CryptoProvider implementation using Web Crypto API.
4
+ * Compatible with CF Workers runtime.
5
+ */
6
+ export declare function createCfCrypto(): CryptoProvider;
7
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../../src/runtime/cf/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE3D;;;GAGG;AACH,wBAAgB,cAAc,IAAI,cAAc,CAmE/C"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * CryptoProvider implementation using Web Crypto API.
3
+ * Compatible with CF Workers runtime.
4
+ */
5
+ export function createCfCrypto() {
6
+ return {
7
+ async randomHex(byteLength) {
8
+ const bytes = crypto.getRandomValues(new Uint8Array(byteLength));
9
+ return Array.from(bytes)
10
+ .map((b) => b.toString(16).padStart(2, '0'))
11
+ .join('');
12
+ },
13
+ uuid() {
14
+ return crypto.randomUUID();
15
+ },
16
+ async hmacSha256(key, data) {
17
+ const encoder = new TextEncoder();
18
+ const cryptoKey = await crypto.subtle.importKey('raw', encoder.encode(key), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
19
+ const signature = await crypto.subtle.sign('HMAC', cryptoKey, encoder.encode(data));
20
+ return Array.from(new Uint8Array(signature))
21
+ .map((b) => b.toString(16).padStart(2, '0'))
22
+ .join('');
23
+ },
24
+ async timingSafeEqual(a, b) {
25
+ const encoder = new TextEncoder();
26
+ const bufA = encoder.encode(a);
27
+ const bufB = encoder.encode(b);
28
+ if (bufA.length !== bufB.length)
29
+ return false;
30
+ // Import both as HMAC keys and compare by signing
31
+ // This provides constant-time comparison without node:crypto
32
+ const key = crypto.getRandomValues(new Uint8Array(32));
33
+ const cryptoKey = await crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
34
+ const [sigA, sigB] = await Promise.all([
35
+ crypto.subtle.sign('HMAC', cryptoKey, bufA),
36
+ crypto.subtle.sign('HMAC', cryptoKey, bufB),
37
+ ]);
38
+ const arrA = new Uint8Array(sigA);
39
+ const arrB = new Uint8Array(sigB);
40
+ let result = 0;
41
+ for (let i = 0; i < arrA.length; i++) {
42
+ result |= arrA[i] ^ arrB[i];
43
+ }
44
+ return result === 0;
45
+ },
46
+ };
47
+ }
48
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../../src/runtime/cf/crypto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Vault } from '../../types/vault.js';
2
+ import type { RelayHub } from '../../types/relay.js';
3
+ import type { CryptoProvider } from '../../types/crypto.js';
4
+ export interface CfEnv {
5
+ RELAY_DO: DurableObjectNamespace;
6
+ VAULT_MASTER_KEY: string;
7
+ PLATFORM_BASE_URL: string;
8
+ SLACK_WORKSPACE_ID: string;
9
+ }
10
+ export interface CfRuntime {
11
+ vault: Vault;
12
+ relay: RelayHub;
13
+ crypto: CryptoProvider;
14
+ }
15
+ /**
16
+ * Create runtime services for Cloudflare Workers (vault, relay, crypto).
17
+ * Does NOT include DB repositories -- those are created separately via the DB subpath.
18
+ */
19
+ export declare function createCfRuntime(env: CfEnv): Promise<CfRuntime>;
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/runtime/cf/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAK3D,MAAM,WAAW,KAAK;IACpB,QAAQ,EAAE,sBAAsB,CAAA;IAChC,gBAAgB,EAAE,MAAM,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;IACzB,kBAAkB,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,KAAK,EAAE,QAAQ,CAAA;IACf,MAAM,EAAE,cAAc,CAAA;CACvB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,CAMpE"}
@@ -0,0 +1,14 @@
1
+ import { createCfVault } from './vault.js';
2
+ import { createCfCrypto } from './crypto.js';
3
+ import { createCfRelay } from './relay.js';
4
+ /**
5
+ * Create runtime services for Cloudflare Workers (vault, relay, crypto).
6
+ * Does NOT include DB repositories -- those are created separately via the DB subpath.
7
+ */
8
+ export async function createCfRuntime(env) {
9
+ const vault = await createCfVault(env.VAULT_MASTER_KEY);
10
+ const crypto = createCfCrypto();
11
+ const relay = createCfRelay(env.RELAY_DO);
12
+ return { vault, relay, crypto };
13
+ }
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/cf/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAe1C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAU;IAC9C,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;IACvD,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;IAC/B,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAEzC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AACjC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { RelayHub } from '../../types/relay.js';
2
+ /**
3
+ * Durable Objects-based RelayHub for CF Workers.
4
+ *
5
+ * This stub communicates with a Durable Object namespace.
6
+ * Each bot gets its own Durable Object instance that manages WebSocket connections.
7
+ *
8
+ * The actual Durable Object class (RelayDurableObject) is exported from apps/worker.
9
+ */
10
+ export declare function createCfRelay(doNamespace: DurableObjectNamespace): RelayHub;
11
+ //# sourceMappingURL=relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../../src/runtime/cf/relay.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAEpD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,sBAAsB,GAAG,QAAQ,CA8D3E"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Durable Objects-based RelayHub for CF Workers.
3
+ *
4
+ * This stub communicates with a Durable Object namespace.
5
+ * Each bot gets its own Durable Object instance that manages WebSocket connections.
6
+ *
7
+ * The actual Durable Object class (RelayDurableObject) is exported from apps/worker.
8
+ */
9
+ export function createCfRelay(doNamespace) {
10
+ function getStub(botId) {
11
+ const id = doNamespace.idFromName(botId);
12
+ return doNamespace.get(id);
13
+ }
14
+ return {
15
+ async handleStream(c, botId, _connectKey) {
16
+ const upgradeHeader = c.req.header('Upgrade');
17
+ if (upgradeHeader !== 'websocket') {
18
+ return c.json({ error: 'expected websocket upgrade' }, { status: 426 });
19
+ }
20
+ // Forward the WebSocket upgrade request to the Durable Object
21
+ const stub = getStub(botId);
22
+ const url = new URL(c.req.url);
23
+ url.pathname = '/ws';
24
+ url.searchParams.set('botId', botId);
25
+ return stub.fetch(url.toString(), {
26
+ headers: c.req.raw.headers,
27
+ });
28
+ },
29
+ dispatch(botId, event) {
30
+ // Fire and forget -- send event to the DO
31
+ const stub = getStub(botId);
32
+ const url = new URL('https://internal/dispatch');
33
+ url.searchParams.set('botId', botId);
34
+ stub
35
+ .fetch(url.toString(), {
36
+ method: 'POST',
37
+ headers: { 'Content-Type': 'application/json' },
38
+ body: JSON.stringify(event),
39
+ })
40
+ .catch((err) => {
41
+ console.error(`[cf-relay] dispatch error for bot ${botId}:`, err);
42
+ });
43
+ // We return true optimistically; the DO handles delivery
44
+ return true;
45
+ },
46
+ isConnected(_botId) {
47
+ // In CF Workers, we cannot synchronously check DO state
48
+ // This is best-effort
49
+ return true;
50
+ },
51
+ connectedBots() {
52
+ // Cannot enumerate Durable Objects synchronously
53
+ return [];
54
+ },
55
+ };
56
+ }
57
+ //# sourceMappingURL=relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.js","sourceRoot":"","sources":["../../../src/runtime/cf/relay.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,WAAmC;IAC/D,SAAS,OAAO,CAAC,KAAa;QAC5B,MAAM,EAAE,GAAG,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QACxC,OAAO,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC5B,CAAC;IAED,OAAO;QACL,KAAK,CAAC,YAAY,CAChB,CAAU,EACV,KAAa,EACb,WAAmB;YAEnB,MAAM,aAAa,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAC7C,IAAI,aAAa,KAAK,WAAW,EAAE,CAAC;gBAClC,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,KAAK,EAAE,4BAA4B,EAAE,EACvC,EAAE,MAAM,EAAE,GAAG,EAAE,CAChB,CAAA;YACH,CAAC;YAED,8DAA8D;YAC9D,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;YAC3B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC9B,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAA;YACpB,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YAEpC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;gBAChC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO;aAC3B,CAAwB,CAAA;QAC3B,CAAC;QAED,QAAQ,CAAC,KAAa,EAAE,KAAc;YACpC,0CAA0C;YAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;YAC3B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,2BAA2B,CAAC,CAAA;YAChD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YAEpC,IAAI;iBACD,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;gBACrB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;aAC5B,CAAC;iBACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;gBACtB,OAAO,CAAC,KAAK,CAAC,qCAAqC,KAAK,GAAG,EAAE,GAAG,CAAC,CAAA;YACnE,CAAC,CAAC,CAAA;YAEJ,yDAAyD;YACzD,OAAO,IAAI,CAAA;QACb,CAAC;QAED,WAAW,CAAC,MAAc;YACxB,wDAAwD;YACxD,sBAAsB;YACtB,OAAO,IAAI,CAAA;QACb,CAAC;QAED,aAAa;YACX,iDAAiD;YACjD,OAAO,EAAE,CAAA;QACX,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Vault } from '../../types/vault.js';
2
+ /**
3
+ * AES-256-GCM Vault implementation using Web Crypto API.
4
+ * Compatible with CF Workers runtime.
5
+ */
6
+ export declare function createCfVault(masterKeyHex: string): Promise<Vault>;
7
+ //# sourceMappingURL=vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../../src/runtime/cf/vault.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAKjD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAgExE"}
@@ -0,0 +1,68 @@
1
+ const ALGORITHM = 'AES-GCM';
2
+ const IV_LENGTH = 12;
3
+ /**
4
+ * AES-256-GCM Vault implementation using Web Crypto API.
5
+ * Compatible with CF Workers runtime.
6
+ */
7
+ export async function createCfVault(masterKeyHex) {
8
+ const rawKey = hexToArrayBuffer(masterKeyHex);
9
+ if (rawKey.byteLength !== 32) {
10
+ throw new Error('VAULT_MASTER_KEY must be 32 bytes (64 hex chars)');
11
+ }
12
+ const cryptoKey = await crypto.subtle.importKey('raw', rawKey, { name: ALGORITHM }, false, ['encrypt', 'decrypt']);
13
+ return {
14
+ async encrypt(plaintext) {
15
+ const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
16
+ const encoded = new TextEncoder().encode(plaintext);
17
+ const ciphertext = await crypto.subtle.encrypt({ name: ALGORITHM, iv }, cryptoKey, encoded);
18
+ // Web Crypto appends authTag to ciphertext
19
+ // Format: base64(iv + ciphertext_with_tag) -- matches Node.js layout
20
+ // Node layout: iv(12) + authTag(16) + ciphertext
21
+ // WebCrypto layout: ciphertext + authTag(16)
22
+ // We need to rearrange to match Node.js format
23
+ const ctBytes = new Uint8Array(ciphertext);
24
+ const actualCiphertext = ctBytes.slice(0, ctBytes.length - 16);
25
+ const authTag = ctBytes.slice(ctBytes.length - 16);
26
+ const result = new Uint8Array(iv.length + authTag.length + actualCiphertext.length);
27
+ result.set(iv, 0);
28
+ result.set(authTag, iv.length);
29
+ result.set(actualCiphertext, iv.length + authTag.length);
30
+ return uint8ArrayToBase64(result);
31
+ },
32
+ async decrypt(encoded) {
33
+ const data = base64ToUint8Array(encoded);
34
+ const iv = data.slice(0, IV_LENGTH);
35
+ const authTag = data.slice(IV_LENGTH, IV_LENGTH + 16);
36
+ const ciphertext = data.slice(IV_LENGTH + 16);
37
+ // Reconstruct WebCrypto format: ciphertext + authTag
38
+ const combined = new Uint8Array(ciphertext.length + authTag.length);
39
+ combined.set(ciphertext, 0);
40
+ combined.set(authTag, ciphertext.length);
41
+ const decrypted = await crypto.subtle.decrypt({ name: ALGORITHM, iv }, cryptoKey, combined);
42
+ return new TextDecoder().decode(decrypted);
43
+ },
44
+ };
45
+ }
46
+ function hexToArrayBuffer(hex) {
47
+ const bytes = new Uint8Array(hex.length / 2);
48
+ for (let i = 0; i < hex.length; i += 2) {
49
+ bytes[i / 2] = Number.parseInt(hex.substring(i, i + 2), 16);
50
+ }
51
+ return bytes.buffer;
52
+ }
53
+ function uint8ArrayToBase64(bytes) {
54
+ let binary = '';
55
+ for (let i = 0; i < bytes.length; i++) {
56
+ binary += String.fromCharCode(bytes[i]);
57
+ }
58
+ return btoa(binary);
59
+ }
60
+ function base64ToUint8Array(base64) {
61
+ const binary = atob(base64);
62
+ const bytes = new Uint8Array(binary.length);
63
+ for (let i = 0; i < binary.length; i++) {
64
+ bytes[i] = binary.charCodeAt(i);
65
+ }
66
+ return bytes;
67
+ }
68
+ //# sourceMappingURL=vault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.js","sourceRoot":"","sources":["../../../src/runtime/cf/vault.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG,SAAS,CAAA;AAC3B,MAAM,SAAS,GAAG,EAAE,CAAA;AAEpB;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,YAAoB;IACtD,MAAM,MAAM,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAA;IAC7C,IAAI,MAAM,CAAC,UAAU,KAAK,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;IACrE,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAC7C,KAAK,EACL,MAAM,EACN,EAAE,IAAI,EAAE,SAAS,EAAE,EACnB,KAAK,EACL,CAAC,SAAS,EAAE,SAAS,CAAC,CACvB,CAAA;IAED,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,SAAiB;YAC7B,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC,CAAA;YAC5D,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAEnD,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAC5C,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EACvB,SAAS,EACT,OAAO,CACR,CAAA;YAED,2CAA2C;YAC3C,qEAAqE;YACrE,iDAAiD;YACjD,6CAA6C;YAC7C,+CAA+C;YAC/C,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,CAAA;YAC1C,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;YAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;YAElD,MAAM,MAAM,GAAG,IAAI,UAAU,CAC3B,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,gBAAgB,CAAC,MAAM,CACrD,CAAA;YACD,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;YACjB,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,CAAA;YAC9B,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;YAExD,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAA;QACnC,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,OAAe;YAC3B,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAA;YACxC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,SAAS,GAAG,EAAE,CAAC,CAAA;YACrD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC,CAAA;YAE7C,qDAAqD;YACrD,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;YACnE,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;YAC3B,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;YAExC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAC3C,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EACvB,SAAS,EACT,QAAQ,CACT,CAAA;YAED,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAC5C,CAAC;KACF,CAAA;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAW;IACnC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAC7D,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAA;AACrB,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAiB;IAC3C,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IACzC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAA;AACrB,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAc;IACxC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;IAC3B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;IACjC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { CryptoProvider } from '../../types/crypto.js';
2
+ /**
3
+ * CryptoProvider implementation using Node.js crypto module.
4
+ */
5
+ export declare function createNodeCrypto(): CryptoProvider;
6
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../../src/runtime/node/crypto.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE3D;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,cAAc,CAqBjD"}
@@ -0,0 +1,26 @@
1
+ import { createHmac, randomBytes, timingSafeEqual as nodeTimingSafeEqual, } from 'node:crypto';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ /**
4
+ * CryptoProvider implementation using Node.js crypto module.
5
+ */
6
+ export function createNodeCrypto() {
7
+ return {
8
+ async randomHex(byteLength) {
9
+ return randomBytes(byteLength).toString('hex');
10
+ },
11
+ uuid() {
12
+ return uuidv4();
13
+ },
14
+ async hmacSha256(key, data) {
15
+ return createHmac('sha256', key).update(data).digest('hex');
16
+ },
17
+ async timingSafeEqual(a, b) {
18
+ const bufA = Buffer.from(a, 'utf8');
19
+ const bufB = Buffer.from(b, 'utf8');
20
+ if (bufA.length !== bufB.length)
21
+ return false;
22
+ return nodeTimingSafeEqual(bufA, bufB);
23
+ },
24
+ };
25
+ }
26
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../../src/runtime/node/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,WAAW,EACX,eAAe,IAAI,mBAAmB,GACvC,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAA;AAGnC;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,KAAK,CAAC,SAAS,CAAC,UAAkB;YAChC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAChD,CAAC;QAED,IAAI;YACF,OAAO,MAAM,EAAE,CAAA;QACjB,CAAC;QAED,KAAK,CAAC,UAAU,CAAC,GAAW,EAAE,IAAY;YACxC,OAAO,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC7D,CAAC;QAED,KAAK,CAAC,eAAe,CAAC,CAAS,EAAE,CAAS;YACxC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;YACnC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;YACnC,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAA;YAC7C,OAAO,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACxC,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Vault } from '../../types/vault.js';
2
+ import type { RelayHub } from '../../types/relay.js';
3
+ import type { CryptoProvider } from '../../types/crypto.js';
4
+ export interface NodeRuntimeConfig {
5
+ vaultMasterKey: string;
6
+ }
7
+ export interface NodeRuntime {
8
+ vault: Vault;
9
+ relay: RelayHub;
10
+ crypto: CryptoProvider;
11
+ }
12
+ /**
13
+ * Create runtime services for Node.js (vault, relay, crypto).
14
+ * Does NOT include DB repositories -- those are created separately via the DB subpath.
15
+ */
16
+ export declare function createNodeRuntime(config: NodeRuntimeConfig): NodeRuntime;
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/runtime/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAK3D,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,KAAK,CAAA;IACZ,KAAK,EAAE,QAAQ,CAAA;IACf,MAAM,EAAE,cAAc,CAAA;CACvB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,WAAW,CAMxE"}
@@ -0,0 +1,14 @@
1
+ import { createNodeVault } from './vault.js';
2
+ import { createNodeCrypto } from './crypto.js';
3
+ import { createNodeRelay } from './relay.js';
4
+ /**
5
+ * Create runtime services for Node.js (vault, relay, crypto).
6
+ * Does NOT include DB repositories -- those are created separately via the DB subpath.
7
+ */
8
+ export function createNodeRuntime(config) {
9
+ const vault = createNodeVault(config.vaultMasterKey);
10
+ const crypto = createNodeCrypto();
11
+ const relay = createNodeRelay();
12
+ return { vault, relay, crypto };
13
+ }
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/node/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAY5C;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAyB;IACzD,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;IACpD,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAA;IACjC,MAAM,KAAK,GAAG,eAAe,EAAE,CAAA;IAE/B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AACjC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { RelayHub } from '../../types/relay.js';
2
+ /**
3
+ * SSE-based RelayHub implementation for Node.js.
4
+ */
5
+ export declare function createNodeRelay(): RelayHub;
6
+ //# sourceMappingURL=relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../../src/runtime/node/relay.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AASpD;;GAEG;AACH,wBAAgB,eAAe,IAAI,QAAQ,CAmF1C"}
@@ -0,0 +1,73 @@
1
+ import { streamSSE } from 'hono/streaming';
2
+ /**
3
+ * SSE-based RelayHub implementation for Node.js.
4
+ */
5
+ export function createNodeRelay() {
6
+ // botId -> SSEClient (1 bot = 1 active connection)
7
+ const clients = new Map();
8
+ let eventCounter = 0;
9
+ return {
10
+ async handleStream(c, botId, connectKey) {
11
+ return streamSSE(c, async (stream) => {
12
+ // Replace existing connection (reconnect scenario)
13
+ const existing = clients.get(botId);
14
+ if (existing) {
15
+ existing.close();
16
+ }
17
+ let closed = false;
18
+ const client = {
19
+ botId,
20
+ connectKey,
21
+ send(event, data, id) {
22
+ if (closed)
23
+ return;
24
+ stream.writeSSE({ event, data, id }).catch(() => {
25
+ closed = true;
26
+ });
27
+ },
28
+ close() {
29
+ closed = true;
30
+ },
31
+ };
32
+ clients.set(botId, client);
33
+ // Connection confirmation event
34
+ client.send('connected', JSON.stringify({ botId, ts: Date.now() }));
35
+ // Heartbeat (every 30 seconds)
36
+ const heartbeatInterval = setInterval(() => {
37
+ if (closed) {
38
+ clearInterval(heartbeatInterval);
39
+ return;
40
+ }
41
+ client.send('ping', JSON.stringify({ ts: Date.now() }));
42
+ }, 30_000);
43
+ // Wait for connection close
44
+ stream.onAbort(() => {
45
+ closed = true;
46
+ clearInterval(heartbeatInterval);
47
+ clients.delete(botId);
48
+ });
49
+ // Keep connection alive until aborted
50
+ while (!closed) {
51
+ await new Promise((r) => setTimeout(r, 1000));
52
+ }
53
+ clearInterval(heartbeatInterval);
54
+ clients.delete(botId);
55
+ });
56
+ },
57
+ dispatch(botId, event) {
58
+ const client = clients.get(botId);
59
+ if (!client)
60
+ return false;
61
+ const id = String(++eventCounter);
62
+ client.send('slack_event', JSON.stringify(event), id);
63
+ return true;
64
+ },
65
+ isConnected(botId) {
66
+ return clients.has(botId);
67
+ },
68
+ connectedBots() {
69
+ return Array.from(clients.keys());
70
+ },
71
+ };
72
+ }
73
+ //# sourceMappingURL=relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.js","sourceRoot":"","sources":["../../../src/runtime/node/relay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Vault } from '../../types/vault.js';
2
+ /**
3
+ * AES-256-GCM Vault implementation using Node.js crypto.
4
+ * Returns Promises to match the Vault interface (Web Crypto compatibility).
5
+ */
6
+ export declare function createNodeVault(masterKeyHex: string): Vault;
7
+ //# sourceMappingURL=vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../../src/runtime/node/vault.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAMjD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,KAAK,CAkC3D"}
@@ -0,0 +1,41 @@
1
+ import { createCipheriv, createDecipheriv, randomBytes, } from 'node:crypto';
2
+ const ALGORITHM = 'aes-256-gcm';
3
+ const IV_LENGTH = 12;
4
+ const AUTH_TAG_LENGTH = 16;
5
+ /**
6
+ * AES-256-GCM Vault implementation using Node.js crypto.
7
+ * Returns Promises to match the Vault interface (Web Crypto compatibility).
8
+ */
9
+ export function createNodeVault(masterKeyHex) {
10
+ const masterKey = Buffer.from(masterKeyHex, 'hex');
11
+ if (masterKey.length !== 32) {
12
+ throw new Error('VAULT_MASTER_KEY must be 32 bytes (64 hex chars)');
13
+ }
14
+ return {
15
+ async encrypt(plaintext) {
16
+ const iv = randomBytes(IV_LENGTH);
17
+ const cipher = createCipheriv(ALGORITHM, masterKey, iv, {
18
+ authTagLength: AUTH_TAG_LENGTH,
19
+ });
20
+ const encrypted = Buffer.concat([
21
+ cipher.update(plaintext, 'utf8'),
22
+ cipher.final(),
23
+ ]);
24
+ const authTag = cipher.getAuthTag();
25
+ // Format: base64(iv + authTag + ciphertext)
26
+ return Buffer.concat([iv, authTag, encrypted]).toString('base64');
27
+ },
28
+ async decrypt(encoded) {
29
+ const data = Buffer.from(encoded, 'base64');
30
+ const iv = data.subarray(0, IV_LENGTH);
31
+ const authTag = data.subarray(IV_LENGTH, IV_LENGTH + AUTH_TAG_LENGTH);
32
+ const ciphertext = data.subarray(IV_LENGTH + AUTH_TAG_LENGTH);
33
+ const decipher = createDecipheriv(ALGORITHM, masterKey, iv, {
34
+ authTagLength: AUTH_TAG_LENGTH,
35
+ });
36
+ decipher.setAuthTag(authTag);
37
+ return decipher.update(ciphertext) + decipher.final('utf8');
38
+ },
39
+ };
40
+ }
41
+ //# sourceMappingURL=vault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.js","sourceRoot":"","sources":["../../../src/runtime/node/vault.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,WAAW,GACZ,MAAM,aAAa,CAAA;AAGpB,MAAM,SAAS,GAAG,aAAa,CAAA;AAC/B,MAAM,SAAS,GAAG,EAAE,CAAA;AACpB,MAAM,eAAe,GAAG,EAAE,CAAA;AAE1B;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;IAClD,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;IACrE,CAAC;IAED,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,SAAiB;YAC7B,MAAM,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;YACjC,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE;gBACtD,aAAa,EAAE,eAAe;aAC/B,CAAC,CAAA;YACF,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;gBAC9B,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC;gBAChC,MAAM,CAAC,KAAK,EAAE;aACf,CAAC,CAAA;YACF,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAA;YACnC,4CAA4C;YAC5C,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QACnE,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,OAAe;YAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;YAC3C,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;YACtC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,eAAe,CAAC,CAAA;YACrE,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,eAAe,CAAC,CAAA;YAE7D,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE;gBAC1D,aAAa,EAAE,eAAe;aAC/B,CAAC,CAAA;YACF,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;YAC5B,OAAO,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QAC7D,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { Hono } from 'hono';
2
+ import type { Vault } from '../types/vault.js';
3
+ import type { RelayHub } from '../types/relay.js';
4
+ import type { CryptoProvider } from '../types/crypto.js';
5
+ import type { BotRepository } from '../types/repository.js';
6
+ /**
7
+ * Slack HTTP Events API receiver + relay to SSE/WebSocket Hub.
8
+ *
9
+ * Route: POST /slack/events/:botId
10
+ * - url_verification challenge auto-response
11
+ * - signing_secret signature verification
12
+ * - Relay to local runtime via RelayHub
13
+ */
14
+ export declare function createSlackEventsHandler(botRepo: BotRepository, vault: Vault, relay: RelayHub, crypto: CryptoProvider): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
15
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/slack/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAE3D;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,cAAc,8EAyEvB"}