@lastshotlabs/bunshot 0.0.21 → 0.0.25

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 (122) hide show
  1. package/README.md +3035 -1249
  2. package/dist/adapters/localStorage.d.ts +6 -0
  3. package/dist/adapters/localStorage.js +44 -0
  4. package/dist/adapters/memoryAuth.d.ts +7 -0
  5. package/dist/adapters/memoryAuth.js +144 -0
  6. package/dist/adapters/memoryStorage.d.ts +3 -0
  7. package/dist/adapters/memoryStorage.js +44 -0
  8. package/dist/adapters/mongoAuth.js +120 -0
  9. package/dist/adapters/s3Storage.d.ts +14 -0
  10. package/dist/adapters/s3Storage.js +126 -0
  11. package/dist/adapters/sqliteAuth.d.ts +7 -0
  12. package/dist/adapters/sqliteAuth.js +199 -0
  13. package/dist/app.d.ts +100 -3
  14. package/dist/app.js +247 -46
  15. package/dist/cli.js +118 -38
  16. package/dist/index.d.ts +49 -7
  17. package/dist/index.js +35 -5
  18. package/dist/lib/HttpError.d.ts +5 -0
  19. package/dist/lib/HttpError.js +7 -0
  20. package/dist/lib/appConfig.d.ts +44 -0
  21. package/dist/lib/appConfig.js +16 -0
  22. package/dist/lib/auditLog.d.ts +52 -0
  23. package/dist/lib/auditLog.js +201 -0
  24. package/dist/lib/authAdapter.d.ts +69 -0
  25. package/dist/lib/constants.d.ts +4 -0
  26. package/dist/lib/constants.js +4 -0
  27. package/dist/lib/context.d.ts +19 -1
  28. package/dist/lib/context.js +17 -3
  29. package/dist/lib/createRoute.d.ts +28 -2
  30. package/dist/lib/createRoute.js +54 -3
  31. package/dist/lib/deletionCancelToken.d.ts +12 -0
  32. package/dist/lib/deletionCancelToken.js +88 -0
  33. package/dist/lib/groups.d.ts +113 -0
  34. package/dist/lib/groups.js +133 -0
  35. package/dist/lib/idempotency.d.ts +22 -0
  36. package/dist/lib/idempotency.js +182 -0
  37. package/dist/lib/metrics.d.ts +14 -0
  38. package/dist/lib/metrics.js +158 -0
  39. package/dist/lib/pagination.d.ts +119 -0
  40. package/dist/lib/pagination.js +166 -0
  41. package/dist/lib/session.d.ts +4 -0
  42. package/dist/lib/session.js +56 -2
  43. package/dist/lib/signing.d.ts +52 -0
  44. package/dist/lib/signing.js +180 -0
  45. package/dist/lib/storageAdapter.d.ts +30 -0
  46. package/dist/lib/storageAdapter.js +1 -0
  47. package/dist/lib/stripUnreferencedSchemas.d.ts +11 -0
  48. package/dist/lib/stripUnreferencedSchemas.js +79 -0
  49. package/dist/lib/tenant.js +2 -2
  50. package/dist/lib/upload.d.ts +35 -0
  51. package/dist/lib/upload.js +87 -0
  52. package/dist/lib/validate.js +2 -2
  53. package/dist/lib/ws.d.ts +1 -0
  54. package/dist/lib/ws.js +21 -0
  55. package/dist/lib/wsHeartbeat.d.ts +12 -0
  56. package/dist/lib/wsHeartbeat.js +57 -0
  57. package/dist/lib/wsMessages.d.ts +40 -0
  58. package/dist/lib/wsMessages.js +330 -0
  59. package/dist/lib/wsPresence.d.ts +25 -0
  60. package/dist/lib/wsPresence.js +99 -0
  61. package/dist/middleware/auditLog.d.ts +22 -0
  62. package/dist/middleware/auditLog.js +39 -0
  63. package/dist/middleware/cacheResponse.js +5 -1
  64. package/dist/middleware/csrf.js +10 -0
  65. package/dist/middleware/identify.js +57 -9
  66. package/dist/middleware/metrics.d.ts +9 -0
  67. package/dist/middleware/metrics.js +26 -0
  68. package/dist/middleware/requestId.d.ts +3 -0
  69. package/dist/middleware/requestId.js +7 -0
  70. package/dist/middleware/requestLogger.d.ts +38 -0
  71. package/dist/middleware/requestLogger.js +68 -0
  72. package/dist/middleware/requestSigning.d.ts +20 -0
  73. package/dist/middleware/requestSigning.js +99 -0
  74. package/dist/middleware/requireMfaSetup.d.ts +16 -0
  75. package/dist/middleware/requireMfaSetup.js +36 -0
  76. package/dist/middleware/requireRole.d.ts +9 -3
  77. package/dist/middleware/requireRole.js +23 -36
  78. package/dist/middleware/upload.d.ts +5 -0
  79. package/dist/middleware/upload.js +27 -0
  80. package/dist/middleware/webhookAuth.d.ts +30 -0
  81. package/dist/middleware/webhookAuth.js +57 -0
  82. package/dist/models/AuditLog.d.ts +30 -0
  83. package/dist/models/AuditLog.js +39 -0
  84. package/dist/models/Group.d.ts +21 -0
  85. package/dist/models/Group.js +28 -0
  86. package/dist/models/GroupMembership.d.ts +21 -0
  87. package/dist/models/GroupMembership.js +25 -0
  88. package/dist/routes/auth.js +84 -6
  89. package/dist/routes/groups.d.ts +21 -0
  90. package/dist/routes/groups.js +346 -0
  91. package/dist/routes/jobs.js +47 -45
  92. package/dist/routes/metrics.d.ts +7 -0
  93. package/dist/routes/metrics.js +52 -0
  94. package/dist/routes/mfa.js +4 -0
  95. package/dist/routes/uploads.d.ts +2 -0
  96. package/dist/routes/uploads.js +135 -0
  97. package/dist/server.d.ts +26 -0
  98. package/dist/server.js +46 -3
  99. package/dist/ws/index.js +3 -0
  100. package/docs/sections/auth-flow/full.md +779 -634
  101. package/docs/sections/auth-flow/overview.md +2 -2
  102. package/docs/sections/auth-security-examples/full.md +365 -0
  103. package/docs/sections/authentication/full.md +130 -0
  104. package/docs/sections/authentication/overview.md +5 -0
  105. package/docs/sections/cli/full.md +13 -1
  106. package/docs/sections/configuration/full.md +17 -0
  107. package/docs/sections/configuration/overview.md +1 -0
  108. package/docs/sections/exports/full.md +34 -3
  109. package/docs/sections/logging/full.md +83 -0
  110. package/docs/sections/metrics/full.md +127 -0
  111. package/docs/sections/oauth/full.md +189 -189
  112. package/docs/sections/oauth/overview.md +1 -1
  113. package/docs/sections/pagination/full.md +93 -0
  114. package/docs/sections/roles/full.md +224 -135
  115. package/docs/sections/roles/overview.md +3 -1
  116. package/docs/sections/signing/full.md +203 -0
  117. package/docs/sections/uploads/full.md +199 -0
  118. package/docs/sections/versioning/full.md +85 -0
  119. package/docs/sections/webhook-auth/full.md +100 -0
  120. package/docs/sections/websocket/full.md +83 -0
  121. package/docs/sections/websocket-rooms/full.md +6 -1
  122. package/package.json +16 -4
package/dist/server.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { Server, ServerWebSocket, WebSocketHandler } from "bun";
2
2
  import { type CreateAppConfig } from "./app";
3
3
  import { type SocketData } from "./ws/index";
4
+ import { type HeartbeatConfig } from "./lib/wsHeartbeat";
5
+ import { type WsMessageStore, type WsMessageDefaults } from "./lib/wsMessages";
4
6
  export interface WsConfig<T extends object = object> {
5
7
  /** Override or extend the default WebSocket handler */
6
8
  handler?: WebSocketHandler<SocketData<T>>;
@@ -18,6 +20,25 @@ export interface WsConfig<T extends object = object> {
18
20
  * Defaults to 65536 (64 KB).
19
21
  */
20
22
  maxMessageSize?: number;
23
+ /**
24
+ * Heartbeat / ping-pong keepalive. Set `true` for defaults (30s interval, 10s timeout)
25
+ * or provide an object to customize intervals.
26
+ */
27
+ heartbeat?: boolean | HeartbeatConfig;
28
+ /**
29
+ * Presence tracking. Set `true` for defaults or provide config.
30
+ * When enabled, `presence_join`/`presence_leave` events are broadcast to rooms.
31
+ */
32
+ presence?: boolean | {
33
+ broadcastEvents?: boolean;
34
+ };
35
+ /**
36
+ * Message persistence. Opt rooms in via `configureRoom()`.
37
+ */
38
+ persistence?: {
39
+ store?: WsMessageStore;
40
+ defaults?: WsMessageDefaults;
41
+ };
21
42
  }
22
43
  export interface CreateServerConfig<T extends object = object> extends CreateAppConfig {
23
44
  port?: number;
@@ -27,5 +48,10 @@ export interface CreateServerConfig<T extends object = object> extends CreateApp
27
48
  enableWorkers?: boolean;
28
49
  /** WebSocket configuration */
29
50
  ws?: WsConfig<T>;
51
+ /**
52
+ * Maximum request body size in bytes. Defaults to the upload config limit when present
53
+ * (maxFileSize * maxFiles), otherwise Bun's default (128 MB).
54
+ */
55
+ maxRequestBodySize?: number;
30
56
  }
31
57
  export declare const createServer: <T extends object = object>(config: CreateServerConfig<T>) => Promise<Server<SocketData<T>>>;
package/dist/server.js CHANGED
@@ -1,17 +1,44 @@
1
1
  import { createApp } from "./app";
2
2
  import { websocket as defaultWebsocket, createWsUpgradeHandler } from "./ws/index";
3
- import { setWsServer, handleRoomActions, cleanupSocket } from "./lib/ws";
3
+ import { setWsServer, handleRoomActions, cleanupSocket, setPresenceEnabled } from "./lib/ws";
4
+ import { registerSocket, deregisterSocket, handlePong, startHeartbeat, stopHeartbeat } from "./lib/wsHeartbeat";
5
+ import { trackSocket, untrackSocket } from "./lib/wsPresence";
6
+ import { setWsMessageStore, setWsMessageDefaults } from "./lib/wsMessages";
4
7
  import { log } from "./lib/logger";
5
8
  export const createServer = async (config) => {
6
9
  const app = await createApp(config);
7
10
  const port = Number(process.env.PORT ?? config.port ?? 3000);
8
11
  const { workersDir, enableWorkers = true, ws: wsConfig = {} } = config;
9
- const { handler: userWs, upgradeHandler: wsUpgradeHandler, onRoomSubscribe, maxMessageSize = 65_536 } = wsConfig;
12
+ // Compute maxRequestBodySize: explicit config wins, else derive from upload config
13
+ let maxRequestBodySize = config.maxRequestBodySize;
14
+ if (maxRequestBodySize === undefined && config.upload) {
15
+ const maxFileSize = config.upload.maxFileSize ?? 10 * 1024 * 1024;
16
+ const maxFiles = config.upload.maxFiles ?? 10;
17
+ maxRequestBodySize = maxFileSize * maxFiles;
18
+ }
19
+ const { handler: userWs, upgradeHandler: wsUpgradeHandler, onRoomSubscribe, maxMessageSize = 65_536, heartbeat: heartbeatConfig, presence: presenceConfig, persistence: persistenceConfig, } = wsConfig;
20
+ // Configure presence
21
+ if (presenceConfig)
22
+ setPresenceEnabled(true);
23
+ // Configure message persistence
24
+ if (persistenceConfig) {
25
+ if (persistenceConfig.store)
26
+ setWsMessageStore(persistenceConfig.store);
27
+ if (persistenceConfig.defaults)
28
+ setWsMessageDefaults(persistenceConfig.defaults);
29
+ }
10
30
  const defaultOpen = defaultWebsocket.open;
11
31
  const defaultClose = defaultWebsocket.close;
12
32
  const defaultDrain = defaultWebsocket.drain;
33
+ const heartbeatEnabled = !!heartbeatConfig;
13
34
  const ws = {
14
- open: userWs?.open ?? defaultOpen,
35
+ open(socket) {
36
+ if (heartbeatEnabled)
37
+ registerSocket(socket, socket.data.id);
38
+ if (presenceConfig)
39
+ trackSocket(socket.data.id, socket.data.userId);
40
+ (userWs?.open ?? defaultOpen)(socket);
41
+ },
15
42
  async message(socket, message) {
16
43
  const size = typeof message === "string" ? message.length : message.byteLength;
17
44
  if (size > maxMessageSize) {
@@ -26,10 +53,18 @@ export const createServer = async (config) => {
26
53
  }
27
54
  },
28
55
  close(socket, code, reason) {
56
+ if (heartbeatEnabled)
57
+ deregisterSocket(socket.data.id);
58
+ if (presenceConfig)
59
+ untrackSocket(socket.data.id);
29
60
  cleanupSocket(socket.data.id, socket.data.rooms);
30
61
  socket.data.rooms.clear();
31
62
  (userWs?.close ?? defaultClose)(socket, code, reason);
32
63
  },
64
+ pong(socket) {
65
+ if (heartbeatEnabled)
66
+ handlePong(socket.data.id);
67
+ },
33
68
  drain: userWs?.drain ?? defaultDrain,
34
69
  };
35
70
  let server;
@@ -42,12 +77,20 @@ export const createServer = async (config) => {
42
77
  },
43
78
  fetch: app.fetch,
44
79
  websocket: ws,
80
+ ...(maxRequestBodySize !== undefined ? { maxRequestBodySize } : {}),
45
81
  error(err) {
46
82
  console.error(err);
47
83
  return Response.json({ error: "Internal Server Error" }, { status: 500 });
48
84
  },
49
85
  });
50
86
  setWsServer(server);
87
+ // Start heartbeat after server is ready
88
+ if (heartbeatEnabled)
89
+ startHeartbeat(heartbeatConfig);
90
+ // Graceful shutdown — stop heartbeat alongside existing cleanup
91
+ const gracefulShutdown = () => { stopHeartbeat(); };
92
+ process.on("SIGTERM", gracefulShutdown);
93
+ process.on("SIGINT", gracefulShutdown);
51
94
  if (enableWorkers && workersDir) {
52
95
  const glob = new Bun.Glob("**/*.ts");
53
96
  for await (const file of glob.scan({ cwd: workersDir })) {
package/dist/ws/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { verifyToken } from "../lib/jwt";
2
2
  import { getSession } from "../lib/session";
3
3
  import { COOKIE_TOKEN } from "../lib/constants";
4
+ import { trackSocket, untrackSocket } from "../lib/wsPresence";
4
5
  export const createWsUpgradeHandler = (server) => async (req) => {
5
6
  let userId = null;
6
7
  try {
@@ -22,6 +23,7 @@ export const createWsUpgradeHandler = (server) => async (req) => {
22
23
  };
23
24
  export const websocket = {
24
25
  open(ws) {
26
+ trackSocket(ws.data.id, ws.data.userId);
25
27
  console.log(`[ws] connected: ${ws.data.id}`);
26
28
  ws.send(JSON.stringify({ event: "connected", id: ws.data.id }));
27
29
  },
@@ -30,6 +32,7 @@ export const websocket = {
30
32
  // Override ws.handler.message in WsConfig for custom message handling.
31
33
  },
32
34
  close(ws) {
35
+ untrackSocket(ws.data.id);
33
36
  console.log(`[ws] disconnected: ${ws.data.id}`);
34
37
  },
35
38
  };