@abot-ai/socket 0.0.0-stage → 0.2.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 (85) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +21 -0
  3. package/README.md +129 -2
  4. package/bin/abot-socket.mjs +15 -0
  5. package/config.example.json +14 -0
  6. package/docs/APP-REVIEW.md +184 -0
  7. package/docs/DEPLOYMENT.md +124 -0
  8. package/docs/INSTALLATION.md +177 -0
  9. package/docs/MIGRATION.md +84 -0
  10. package/docs/PROTOCOL.md +371 -0
  11. package/docs/SECURITY.md +116 -0
  12. package/docs/SELF-HOSTING.md +161 -0
  13. package/package.json +65 -4
  14. package/src/auth/auth-database.mjs +105 -0
  15. package/src/auth/auth-limits.mjs +17 -0
  16. package/src/auth/auth-pairing.mjs +95 -0
  17. package/src/auth/auth-sessions.mjs +119 -0
  18. package/src/auth/auth-storage-path.mjs +70 -0
  19. package/src/auth/auth.mjs +45 -0
  20. package/src/auth/runtime-credentials.mjs +39 -0
  21. package/src/cli/cli-arguments.mjs +23 -0
  22. package/src/cli/cli-entry.mjs +84 -0
  23. package/src/cli/cli-environment.mjs +31 -0
  24. package/src/cli/cli-help.mjs +34 -0
  25. package/src/cli/cli-output.mjs +35 -0
  26. package/src/cli/cli.mjs +58 -0
  27. package/src/cli/client-capabilities.mjs +14 -0
  28. package/src/cli/doctor.mjs +106 -0
  29. package/src/config/config-validation.mjs +41 -0
  30. package/src/config/config.mjs +57 -0
  31. package/src/deployment/deployment-command.mjs +42 -0
  32. package/src/deployment/deployment-input.mjs +76 -0
  33. package/src/deployment/deployment-plan.mjs +62 -0
  34. package/src/deployment/deployment-templates.mjs +109 -0
  35. package/src/main.mjs +26 -0
  36. package/src/notifications/notification-delivery-credentials.mjs +48 -0
  37. package/src/notifications/notification-delivery-fcm.mjs +100 -0
  38. package/src/notifications/notification-delivery-gateway.mjs +36 -0
  39. package/src/notifications/notification-delivery-http.mjs +53 -0
  40. package/src/notifications/notification-delivery-payload.mjs +45 -0
  41. package/src/notifications/notification-delivery.mjs +43 -0
  42. package/src/notifications/notification-gateway-command.mjs +48 -0
  43. package/src/notifications/notification-gateway-store.mjs +159 -0
  44. package/src/notifications/notification-gateway.mjs +181 -0
  45. package/src/notifications/notification-http.mjs +39 -0
  46. package/src/notifications/notification-input.mjs +82 -0
  47. package/src/notifications/notification-outbox.mjs +60 -0
  48. package/src/notifications/notification-preview-crypto.mjs +42 -0
  49. package/src/notifications/notification-preview-schema.mjs +7 -0
  50. package/src/notifications/notification-preview-store.mjs +63 -0
  51. package/src/notifications/notification-preview-text.mjs +20 -0
  52. package/src/notifications/notification-projection.mjs +20 -0
  53. package/src/notifications/notification-schema.mjs +22 -0
  54. package/src/notifications/notification-service.mjs +147 -0
  55. package/src/notifications/notification-store.mjs +132 -0
  56. package/src/pairing/pairing-qr-payload.mjs +32 -0
  57. package/src/pairing/pairing-qr.mjs +42 -0
  58. package/src/protocol/approval-protocol.mjs +39 -0
  59. package/src/protocol/protocol-validation.mjs +137 -0
  60. package/src/protocol/protocol.mjs +120 -0
  61. package/src/protocol/spark-chat-protocol.mjs +51 -0
  62. package/src/relay/relay-approvals.mjs +86 -0
  63. package/src/relay/relay-client-admission.mjs +40 -0
  64. package/src/relay/relay-correlations.mjs +101 -0
  65. package/src/relay/relay-model-catalog.mjs +69 -0
  66. package/src/relay/relay-request-adoption.mjs +97 -0
  67. package/src/relay/relay-requests.mjs +211 -0
  68. package/src/relay/relay-runtime-registration.mjs +49 -0
  69. package/src/relay/relay-session-mutations.mjs +122 -0
  70. package/src/relay/relay.mjs +222 -0
  71. package/src/relay/request-ownership-schema.mjs +18 -0
  72. package/src/relay/request-ownership-store.mjs +115 -0
  73. package/src/review/review-demo-isolation.mjs +132 -0
  74. package/src/review/review-demo-setup.mjs +97 -0
  75. package/src/review/review-portal-access.mjs +64 -0
  76. package/src/review/review-portal-form.mjs +24 -0
  77. package/src/review/review-portal-page.mjs +68 -0
  78. package/src/review/review-portal-server.mjs +105 -0
  79. package/src/setup/setup-files.mjs +37 -0
  80. package/src/setup/setup-questions.mjs +62 -0
  81. package/src/setup/setup-wizard.mjs +50 -0
  82. package/src/setup/setup.mjs +42 -0
  83. package/src/transport/http-api.mjs +32 -0
  84. package/src/transport/server.mjs +175 -0
  85. package/src/transport/transport-limits.mjs +85 -0
@@ -0,0 +1,85 @@
1
+ export class WindowLimiter {
2
+ constructor({ limit, windowMs, capacity = 1024, now = Date.now }) {
3
+ this.limit = limit;
4
+ this.windowMs = windowMs;
5
+ this.capacity = capacity;
6
+ this.now = now;
7
+ this.entries = new Map();
8
+ }
9
+ allow(key) {
10
+ this.prune();
11
+ const entry = this.entries.get(key);
12
+ if (entry) {
13
+ if (entry.count >= this.limit) return false;
14
+ entry.count += 1;
15
+ return true;
16
+ }
17
+ if (this.entries.size >= this.capacity) return false;
18
+ this.entries.set(key, { count: 1, until: this.now() + this.windowMs });
19
+ return true;
20
+ }
21
+ prune() {
22
+ const now = this.now();
23
+ for (const [key, value] of this.entries) if (value.until <= now) this.entries.delete(key);
24
+ }
25
+ }
26
+
27
+ export function bearerToken(req) {
28
+ const value = req.headers.authorization;
29
+ return typeof value === 'string' && /^Bearer [A-Za-z0-9_-]{43,128}$/.test(value)
30
+ ? value.slice(7) : '';
31
+ }
32
+
33
+ export function sameAuthority(req, origin) {
34
+ if (req.headers.host !== origin.host) return false;
35
+ return req.headers.origin === undefined || req.headers.origin === origin.origin;
36
+ }
37
+
38
+ // Listener is loopback-only. The local reverse proxy MUST strip/overwrite this
39
+ // header using its verified client address, never copy arbitrary forwarded input.
40
+ export function trustedClientAddress(req) {
41
+ if (!['127.0.0.1', '::1', '::ffff:127.0.0.1'].includes(req.socket.remoteAddress)) return null;
42
+ const address = req.headers['x-socket-client-ip'];
43
+ return typeof address === 'string' && isIP(address) ? address : null;
44
+ }
45
+
46
+ export function jsonResponse(res, status, body) {
47
+ const encoded = JSON.stringify(body);
48
+ res.writeHead(status, {
49
+ 'content-type': 'application/json; charset=utf-8',
50
+ 'cache-control': 'no-store',
51
+ 'pragma': 'no-cache',
52
+ 'x-content-type-options': 'nosniff',
53
+ 'content-security-policy': "default-src 'none'; frame-ancestors 'none'",
54
+ 'referrer-policy': 'no-referrer',
55
+ 'content-length': Buffer.byteLength(encoded),
56
+ });
57
+ res.end(encoded);
58
+ }
59
+
60
+ export async function readJson(req, maxBytes = 4096) {
61
+ if ((req.headers['content-type'] ?? '').split(';')[0].trim() !== 'application/json') {
62
+ throw Object.assign(new Error('invalid_content_type'), { code: 'invalid_content_type', status: 415 });
63
+ }
64
+ const declared = req.headers['content-length'];
65
+ if (declared !== undefined && (!/^\d+$/.test(declared) || Number(declared) > maxBytes)) {
66
+ throw Object.assign(new Error('payload_too_large'), { code: 'payload_too_large', status: 413 });
67
+ }
68
+ const chunks = [];
69
+ let size = 0;
70
+ for await (const chunk of req) {
71
+ size += chunk.length;
72
+ if (size > maxBytes) {
73
+ throw Object.assign(new Error('payload_too_large'), { code: 'payload_too_large', status: 413 });
74
+ }
75
+ chunks.push(chunk);
76
+ }
77
+ try {
78
+ const value = JSON.parse(Buffer.concat(chunks).toString('utf8'));
79
+ if (!value || Array.isArray(value) || typeof value !== 'object') throw new Error();
80
+ return value;
81
+ } catch {
82
+ throw Object.assign(new Error('invalid_json'), { code: 'invalid_json', status: 400 });
83
+ }
84
+ }
85
+ import { isIP } from 'node:net';