@lastshotlabs/bunshot 0.0.21 → 0.0.27

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 (185) hide show
  1. package/README.md +3035 -1249
  2. package/dist/adapters/localStorage.d.ts +6 -0
  3. package/dist/adapters/localStorage.js +59 -0
  4. package/dist/adapters/memoryAuth.d.ts +13 -0
  5. package/dist/adapters/memoryAuth.js +261 -2
  6. package/dist/adapters/memoryStorage.d.ts +3 -0
  7. package/dist/adapters/memoryStorage.js +44 -0
  8. package/dist/adapters/mongoAuth.js +217 -1
  9. package/dist/adapters/s3Storage.d.ts +14 -0
  10. package/dist/adapters/s3Storage.js +126 -0
  11. package/dist/adapters/sqliteAuth.d.ts +30 -0
  12. package/dist/adapters/sqliteAuth.js +352 -2
  13. package/dist/app.d.ts +203 -3
  14. package/dist/app.js +352 -48
  15. package/dist/cli.js +118 -38
  16. package/dist/index.d.ts +69 -8
  17. package/dist/index.js +46 -5
  18. package/dist/lib/HttpError.d.ts +7 -1
  19. package/dist/lib/HttpError.js +10 -1
  20. package/dist/lib/appConfig.d.ts +157 -0
  21. package/dist/lib/appConfig.js +54 -0
  22. package/dist/lib/auditLog.d.ts +58 -0
  23. package/dist/lib/auditLog.js +218 -0
  24. package/dist/lib/authAdapter.d.ts +140 -1
  25. package/dist/lib/authRateLimit.js +36 -0
  26. package/dist/lib/breachedPassword.d.ts +13 -0
  27. package/dist/lib/breachedPassword.js +48 -0
  28. package/dist/lib/captcha.d.ts +25 -0
  29. package/dist/lib/captcha.js +37 -0
  30. package/dist/lib/constants.d.ts +4 -0
  31. package/dist/lib/constants.js +4 -0
  32. package/dist/lib/context.d.ts +24 -1
  33. package/dist/lib/context.js +17 -3
  34. package/dist/lib/createRoute.d.ts +28 -2
  35. package/dist/lib/createRoute.js +54 -3
  36. package/dist/lib/credentialStuffing.d.ts +31 -0
  37. package/dist/lib/credentialStuffing.js +77 -0
  38. package/dist/lib/deletionCancelToken.d.ts +12 -0
  39. package/dist/lib/deletionCancelToken.js +88 -0
  40. package/dist/lib/emailVerification.d.ts +6 -0
  41. package/dist/lib/emailVerification.js +46 -3
  42. package/dist/lib/groups.d.ts +113 -0
  43. package/dist/lib/groups.js +133 -0
  44. package/dist/lib/idempotency.d.ts +22 -0
  45. package/dist/lib/idempotency.js +182 -0
  46. package/dist/lib/jwks.d.ts +25 -0
  47. package/dist/lib/jwks.js +51 -0
  48. package/dist/lib/jwt.d.ts +15 -2
  49. package/dist/lib/jwt.js +92 -5
  50. package/dist/lib/logger.d.ts +2 -0
  51. package/dist/lib/logger.js +6 -0
  52. package/dist/lib/m2m.d.ts +29 -0
  53. package/dist/lib/m2m.js +48 -0
  54. package/dist/lib/metrics.d.ts +14 -0
  55. package/dist/lib/metrics.js +158 -0
  56. package/dist/lib/mfaChallenge.d.ts +14 -1
  57. package/dist/lib/mfaChallenge.js +111 -6
  58. package/dist/lib/mongo.js +1 -1
  59. package/dist/lib/oauthCode.js +23 -18
  60. package/dist/lib/pagination.d.ts +119 -0
  61. package/dist/lib/pagination.js +166 -0
  62. package/dist/lib/resetPassword.js +3 -1
  63. package/dist/lib/saml.d.ts +25 -0
  64. package/dist/lib/saml.js +64 -0
  65. package/dist/lib/scim.d.ts +44 -0
  66. package/dist/lib/scim.js +54 -0
  67. package/dist/lib/securityEvents.d.ts +28 -0
  68. package/dist/lib/securityEvents.js +26 -0
  69. package/dist/lib/session.d.ts +14 -0
  70. package/dist/lib/session.js +121 -5
  71. package/dist/lib/signing.d.ts +52 -0
  72. package/dist/lib/signing.js +183 -0
  73. package/dist/lib/storageAdapter.d.ts +30 -0
  74. package/dist/lib/storageAdapter.js +1 -0
  75. package/dist/lib/stripUnreferencedSchemas.d.ts +11 -0
  76. package/dist/lib/stripUnreferencedSchemas.js +79 -0
  77. package/dist/lib/suspension.d.ts +13 -0
  78. package/dist/lib/suspension.js +23 -0
  79. package/dist/lib/tenant.js +2 -2
  80. package/dist/lib/upload.d.ts +39 -0
  81. package/dist/lib/upload.js +112 -0
  82. package/dist/lib/uploadRegistry.d.ts +18 -0
  83. package/dist/lib/uploadRegistry.js +83 -0
  84. package/dist/lib/validate.js +2 -2
  85. package/dist/lib/ws.d.ts +1 -0
  86. package/dist/lib/ws.js +28 -0
  87. package/dist/lib/wsHeartbeat.d.ts +12 -0
  88. package/dist/lib/wsHeartbeat.js +57 -0
  89. package/dist/lib/wsMessages.d.ts +40 -0
  90. package/dist/lib/wsMessages.js +330 -0
  91. package/dist/lib/wsPresence.d.ts +25 -0
  92. package/dist/lib/wsPresence.js +99 -0
  93. package/dist/middleware/auditLog.d.ts +22 -0
  94. package/dist/middleware/auditLog.js +39 -0
  95. package/dist/middleware/bearerAuth.js +1 -1
  96. package/dist/middleware/cacheResponse.js +5 -1
  97. package/dist/middleware/captcha.d.ts +10 -0
  98. package/dist/middleware/captcha.js +36 -0
  99. package/dist/middleware/csrf.js +18 -4
  100. package/dist/middleware/errorHandler.js +4 -1
  101. package/dist/middleware/identify.js +89 -14
  102. package/dist/middleware/metrics.d.ts +9 -0
  103. package/dist/middleware/metrics.js +26 -0
  104. package/dist/middleware/requestId.d.ts +3 -0
  105. package/dist/middleware/requestId.js +7 -0
  106. package/dist/middleware/requestLogger.d.ts +38 -0
  107. package/dist/middleware/requestLogger.js +68 -0
  108. package/dist/middleware/requestSigning.d.ts +20 -0
  109. package/dist/middleware/requestSigning.js +100 -0
  110. package/dist/middleware/requireMfaSetup.d.ts +16 -0
  111. package/dist/middleware/requireMfaSetup.js +37 -0
  112. package/dist/middleware/requireRole.d.ts +9 -3
  113. package/dist/middleware/requireRole.js +23 -36
  114. package/dist/middleware/requireScope.d.ts +10 -0
  115. package/dist/middleware/requireScope.js +25 -0
  116. package/dist/middleware/requireStepUp.d.ts +18 -0
  117. package/dist/middleware/requireStepUp.js +29 -0
  118. package/dist/middleware/scimAuth.d.ts +8 -0
  119. package/dist/middleware/scimAuth.js +29 -0
  120. package/dist/middleware/upload.d.ts +5 -0
  121. package/dist/middleware/upload.js +27 -0
  122. package/dist/middleware/webhookAuth.d.ts +30 -0
  123. package/dist/middleware/webhookAuth.js +58 -0
  124. package/dist/models/AuditLog.d.ts +30 -0
  125. package/dist/models/AuditLog.js +39 -0
  126. package/dist/models/AuthUser.d.ts +7 -0
  127. package/dist/models/AuthUser.js +7 -0
  128. package/dist/models/Group.d.ts +21 -0
  129. package/dist/models/Group.js +28 -0
  130. package/dist/models/GroupMembership.d.ts +21 -0
  131. package/dist/models/GroupMembership.js +25 -0
  132. package/dist/models/M2MClient.d.ts +18 -0
  133. package/dist/models/M2MClient.js +18 -0
  134. package/dist/routes/auth.d.ts +3 -2
  135. package/dist/routes/auth.js +238 -21
  136. package/dist/routes/groups.d.ts +21 -0
  137. package/dist/routes/groups.js +346 -0
  138. package/dist/routes/jobs.js +66 -46
  139. package/dist/routes/m2m.d.ts +2 -0
  140. package/dist/routes/m2m.js +72 -0
  141. package/dist/routes/metrics.d.ts +8 -0
  142. package/dist/routes/metrics.js +55 -0
  143. package/dist/routes/mfa.js +13 -1
  144. package/dist/routes/oauth.js +6 -0
  145. package/dist/routes/oidc.d.ts +2 -0
  146. package/dist/routes/oidc.js +29 -0
  147. package/dist/routes/passkey.d.ts +1 -0
  148. package/dist/routes/passkey.js +157 -0
  149. package/dist/routes/saml.d.ts +2 -0
  150. package/dist/routes/saml.js +86 -0
  151. package/dist/routes/scim.d.ts +2 -0
  152. package/dist/routes/scim.js +255 -0
  153. package/dist/routes/uploads.d.ts +14 -0
  154. package/dist/routes/uploads.js +227 -0
  155. package/dist/server.d.ts +26 -0
  156. package/dist/server.js +46 -3
  157. package/dist/services/auth.d.ts +2 -0
  158. package/dist/services/auth.js +101 -22
  159. package/dist/services/mfa.js +2 -2
  160. package/dist/ws/index.js +5 -1
  161. package/docs/sections/auth-flow/full.md +203 -47
  162. package/docs/sections/auth-flow/overview.md +2 -2
  163. package/docs/sections/auth-security-examples/full.md +388 -0
  164. package/docs/sections/authentication/full.md +130 -0
  165. package/docs/sections/authentication/overview.md +5 -0
  166. package/docs/sections/cli/full.md +13 -1
  167. package/docs/sections/configuration/full.md +17 -0
  168. package/docs/sections/configuration/overview.md +1 -0
  169. package/docs/sections/exports/full.md +34 -3
  170. package/docs/sections/logging/full.md +83 -0
  171. package/docs/sections/metrics/full.md +131 -0
  172. package/docs/sections/oauth/full.md +189 -189
  173. package/docs/sections/oauth/overview.md +1 -1
  174. package/docs/sections/pagination/full.md +93 -0
  175. package/docs/sections/passkey-login/full.md +90 -0
  176. package/docs/sections/passkey-login/overview.md +1 -0
  177. package/docs/sections/roles/full.md +224 -135
  178. package/docs/sections/roles/overview.md +3 -1
  179. package/docs/sections/signing/full.md +203 -0
  180. package/docs/sections/uploads/full.md +208 -0
  181. package/docs/sections/versioning/full.md +85 -0
  182. package/docs/sections/webhook-auth/full.md +100 -0
  183. package/docs/sections/websocket/full.md +95 -0
  184. package/docs/sections/websocket-rooms/full.md +6 -1
  185. package/package.json +18 -5
package/dist/cli.js CHANGED
@@ -1,21 +1,96 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- var D=import.meta.require;import{existsSync as N,mkdirSync as X,writeFileSync as q,readSync as b,rmSync as h}from"fs";import{join as B}from"path";import{spawnSync as M}from"child_process";function w(z){process.stdout.write(z);let H=Buffer.alloc(1024),Q=b(0,H,0,H.length,null);return H.subarray(0,Q).toString().trim().replace(/\r/g,"")}function E(z,H,Q=0){let J=Q;function Z($=!1){if(!$)process.stdout.write(`\x1B[${H.length}A`);for(let A=0;A<H.length;A++){let V=A===J,R=V?"\x1B[36m>\x1B[0m":" ",g=V?`\x1B[1m${H[A]}\x1B[0m`:`\x1B[2m${H[A]}\x1B[0m`;process.stdout.write(`\x1B[2K ${R} ${g}
4
- `)}}if(!process.stdin.isTTY){console.log(z),H.forEach((V,R)=>console.log(` ${R+1}) ${V}`));let $=w(` Choose [${Q+1}]: `);if(!$)return Q;let A=parseInt($);if(A>=1&&A<=H.length)return A-1;return Q}console.log(z),process.stdout.write("\x1B[?25l"),Z(!0),process.stdin.setRawMode(!0);let _=Buffer.alloc(16);try{while(!0){let $=b(0,_,0,_.length,null),A=_.subarray(0,$).toString();if(A==="\r"||A===`
5
- `)break;else if(A==="\x1B[A"||A==="\x1BOA")J=(J-1+H.length)%H.length,Z();else if(A==="\x1B[B"||A==="\x1BOB")J=(J+1)%H.length,Z();else if(A==="\x03")process.stdout.write(`\x1B[?25h
6
- `),process.stdin.setRawMode(!1),process.exit(0);else{let V=parseInt(A);if(V>=1&&V<=H.length){J=V-1,Z();break}}}}finally{process.stdin.setRawMode(!1),process.stdout.write("\x1B[?25h")}return J}var f=process.argv[2],m=process.argv[3],O=f||w("App name: ");if(!O)console.error("App name is required."),process.exit(1);var I=O.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,""),G=m||(f?I:w(`Directory (${I}): `))||I,K=!1,W=!1,P="mongo",v="redis",T="redis",F="redis";console.log("");var x=E("Database setup:",["Full stack (MongoDB + Redis \u2014 production ready)","SQLite (single file, no external services)","Memory (ephemeral, great for prototyping/tests)","Custom (choose each store individually)"]);if(x===0)K=E("MongoDB connection mode:",["Single (auth + app data share one connection)","Separate (auth on its own cluster)"])===0?"single":"separate",W=!0,P="mongo",v="redis",T="redis",F="redis";else if(x===1)K=!1,W=!1,P="sqlite",v="sqlite",T="sqlite",F="sqlite";else if(x===2)K=!1,W=!1,P="memory",v="memory",T="memory",F="memory";else{console.log(`
3
+ var a=import.meta.require;import{existsSync as D,mkdirSync as E,writeFileSync as I,readSync as g,rmSync as r}from"fs";import{join as K}from"path";import{spawnSync as w}from"child_process";function b(z){process.stdout.write(z);let G=Buffer.alloc(1024),U=g(0,G,0,G.length,null);return G.subarray(0,U).toString().trim().replace(/\r/g,"")}function Q(z,G,U=0){let J=U;function $(_=!1){if(!_)process.stdout.write(`\x1B[${G.length}A`);for(let H=0;H<G.length;H++){let Z=H===J,F=Z?"\x1B[36m>\x1B[0m":" ",L=Z?`\x1B[1m${G[H]}\x1B[0m`:`\x1B[2m${G[H]}\x1B[0m`;process.stdout.write(`\x1B[2K ${F} ${L}
4
+ `)}}if(!process.stdin.isTTY){console.log(z),G.forEach((Z,F)=>console.log(` ${F+1}) ${Z}`));let _=b(` Choose [${U+1}]: `);if(!_)return U;let H=parseInt(_);if(H>=1&&H<=G.length)return H-1;return U}console.log(z),process.stdout.write("\x1B[?25l"),$(!0),process.stdin.setRawMode(!0);let W=Buffer.alloc(16);try{while(!0){let _=g(0,W,0,W.length,null),H=W.subarray(0,_).toString();if(H==="\r"||H===`
5
+ `)break;else if(H==="\x1B[A"||H==="\x1BOA")J=(J-1+G.length)%G.length,$();else if(H==="\x1B[B"||H==="\x1BOB")J=(J+1)%G.length,$();else if(H==="\x03")process.stdout.write(`\x1B[?25h
6
+ `),process.stdin.setRawMode(!1),process.exit(0);else{let Z=parseInt(H);if(Z>=1&&Z<=G.length){J=Z-1,$();break}}}}finally{process.stdin.setRawMode(!1),process.stdout.write("\x1B[?25h")}return J}var y=process.argv[2],n=process.argv[3],N=y||b("App name: ");if(!N)console.error("App name is required."),process.exit(1);var x=N.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,""),X=n||(y?x:b(`Directory (${x}): `))||x,Y=!1,B=!1,T="mongo",q="redis",v="redis",O="redis";console.log("");var C=Q("Database setup:",["Full stack (MongoDB + Redis \u2014 production ready)","SQLite (single file, no external services)","Memory (ephemeral, great for prototyping/tests)","Custom (choose each store individually)"]);if(C===0)Y=Q("MongoDB connection mode:",["Single (auth + app data share one connection)","Separate (auth on its own cluster)"])===0?"single":"separate",B=!0,T="mongo",q="redis",v="redis",O="redis";else if(C===1)Y=!1,B=!1,T="sqlite",q="sqlite",v="sqlite",O="sqlite";else if(C===2)Y=!1,B=!1,T="memory",q="memory",v="memory",O="memory";else{console.log(`
7
7
  Configure each store:
8
- `);let z=E("MongoDB:",["Single (one connection for auth + app data)","Separate (auth on its own cluster)","None (no MongoDB)"]);if(z===0)K="single";else if(z===1)K="separate";else K=!1;W=E("Redis:",["Yes","No"])===0;let Q=[],J=[];if(W)Q.push("redis"),J.push("Redis");if(K)Q.push("mongo"),J.push("MongoDB");Q.push("sqlite","memory"),J.push("SQLite","Memory");let Z=[],_=[];if(K)Z.push("mongo"),_.push("MongoDB");Z.push("sqlite","memory"),_.push("SQLite","Memory");let $=E("Auth store:",_);P=Z[$];let A=E("Sessions store:",J);v=Q[A];let V=E("Cache store:",J);T=Q[V];let R=E("OAuth state store:",J);F=Q[R]}var S=P==="sqlite"||v==="sqlite"||T==="sqlite"||F==="sqlite",U=B(process.cwd(),G),Y=B(U,"src"),k=B(Y,"config"),j=B(Y,"lib"),p=B(Y,"routes"),l=B(Y,"workers"),u=B(Y,"queues"),d=B(Y,"ws"),c=B(Y,"services"),a=B(Y,"middleware"),r=B(Y,"models");if(N(U))console.error(`Directory "${G}" already exists.`),process.exit(1);function n(){let z=[];if(K)z.push(` mongo: "${K}",`);else z.push(" mongo: false,");if(z.push(` redis: ${W},`),z.push(` auth: "${P}",`),z.push(` sessions: "${v}",`),z.push(` oauthState: "${F}",`),z.push(` cache: "${T}",`),S)z.push(' sqlite: path.join(import.meta.dir, "../../data.db"),');return`{
8
+ `);let z=Q("MongoDB:",["Single (one connection for auth + app data)","Separate (auth on its own cluster)","None (no MongoDB)"]);if(z===0)Y="single";else if(z===1)Y="separate";else Y=!1;B=Q("Redis:",["Yes","No"])===0;let U=[],J=[];if(B)U.push("redis"),J.push("Redis");if(Y)U.push("mongo"),J.push("MongoDB");U.push("sqlite","memory"),J.push("SQLite","Memory");let $=[],W=[];if(Y)$.push("mongo"),W.push("MongoDB");$.push("sqlite","memory"),W.push("SQLite","Memory");let _=Q("Auth store:",W);T=$[_];let H=Q("Sessions store:",J);q=U[H];let Z=Q("Cache store:",J);v=U[Z];let F=Q("OAuth state store:",J);O=U[F]}var s=T==="sqlite"||q==="sqlite"||v==="sqlite"||O==="sqlite";console.log("");var R="web-saas",m=null,t=Q("How would you like to configure auth?",["Use a preset (pick a security posture, get sensible defaults)","Step by step (choose features individually)"]);if(t===0){let z=Q("Which best describes your app?",["Web app / SaaS (CSRF, refresh tokens, botProtection)","Internal / admin (MFA required, no refresh tokens, tight limits)",'Mobile / API only (no CSRF, cors: "*", header auth)',"Dev / prototype (permissive \u2014 iterate fast, no rate limits)"]);R=["web-saas","internal","mobile-api","dev"][z]}else{R="custom";let z=Q("Password policy:",["Relaxed (8 chars)","Strong (12+ chars, special required)","Minimal (dev only)"]),G=["relaxed","strong","minimal"][z],J=Q("Email verification:",["Yes","No"])===0,W=Q("Password reset:",["Yes","No"])===0,H=Q("Refresh tokens:",["Yes","No"])===0,Z=Q("MFA:",["None","Optional (users opt in)","Required (all users)"]),F=["none","optional","required"][Z],h=Q("CSRF protection:",["Yes","No"])===0,P=[],d=["Google","GitHub","Apple","Microsoft"];while(!0){let j=[...d.filter((c)=>!P.includes(c)),"None (done)"],u=Q("OAuth providers (select all that apply):",j),f=j[u];if(f==="None (done)")break;P.push(f)}m={passwordPolicy:G,emailVerification:J,passwordReset:W,refreshTokens:H,mfa:F,csrf:h,oauthProviders:P}}var A=K(process.cwd(),X),V=K(A,"src"),S=K(V,"config"),l=K(V,"lib"),i=K(V,"routes"),o=K(V,"workers"),e=K(V,"queues"),zz=K(V,"ws"),Gz=K(V,"services"),Hz=K(V,"middleware"),Jz=K(V,"models");if(D(A))console.error(`Directory "${X}" already exists.`),process.exit(1);function Kz(){let z=[];if(Y)z.push(` mongo: "${Y}",`);else z.push(" mongo: false,");if(z.push(` redis: ${B},`),z.push(` auth: "${T}",`),z.push(` sessions: "${q}",`),z.push(` oauthState: "${O}",`),z.push(` cache: "${v}",`),s)z.push(' sqlite: path.join(import.meta.dir, "../../data.db"),');return`{
9
9
  ${z.join(`
10
10
  `)}
11
- }`}var s=`export const APP_NAME = "${O}";
11
+ }`}function Qz(){if(R==="web-saas")return`export const auth: AuthConfig = {
12
+ roles: Object.values(USER_ROLES),
13
+ defaultRole: USER_ROLES.USER,
14
+ passwordPolicy: { minLength: 8, requireLetter: true, requireDigit: true },
15
+ // Uncomment to require email verification before login:
16
+ // emailVerification: {
17
+ // required: true,
18
+ // onSend: async (email, token) => { /* send via Resend, SendGrid, etc. */ },
19
+ // },
20
+ // Uncomment to enable password reset:
21
+ // passwordReset: {
22
+ // onSend: async (email, token) => { /* send via Resend, SendGrid, etc. */ },
23
+ // },
24
+ refreshTokens: { accessTokenExpiry: 900, refreshTokenExpiry: 2_592_000 },
25
+ sessionPolicy: { trackLastActive: true },
26
+ // Uncomment to enable opt-in MFA (TOTP + email OTP):
27
+ // mfa: { issuer: APP_NAME },
28
+ };
29
+
30
+ export const security: SecurityConfig = {
31
+ cors: ["https://myapp.com"], // TODO: replace with your domain
32
+ trustProxy: 1,
33
+ csrf: { enabled: true },
34
+ botProtection: { fingerprintRateLimit: true },
35
+ };`;if(R==="internal")return`export const auth: AuthConfig = {
36
+ roles: ["superadmin", "admin", "viewer"],
37
+ defaultRole: "viewer",
38
+ passwordPolicy: { minLength: 14, requireLetter: true, requireDigit: true, requireSpecial: true },
39
+ mfa: { issuer: APP_NAME, required: true },
40
+ sessionPolicy: {
41
+ maxSessions: 2,
42
+ trackLastActive: true,
43
+ persistSessionMetadata: true,
44
+ includeInactiveSessions: true,
45
+ },
46
+ rateLimit: { login: { windowMs: 15 * 60 * 1000, max: 5 } },
47
+ };
48
+
49
+ export const security: SecurityConfig = {
50
+ cors: ["https://admin.myapp.com"], // TODO: replace with your domain
51
+ trustProxy: 1,
52
+ csrf: { enabled: true },
53
+ rateLimit: { windowMs: 60_000, max: 30 },
54
+ };`;if(R==="mobile-api")return`export const auth: AuthConfig = {
55
+ roles: Object.values(USER_ROLES),
56
+ defaultRole: USER_ROLES.USER,
57
+ refreshTokens: { accessTokenExpiry: 900, refreshTokenExpiry: 2_592_000, rotationGraceSeconds: 60 },
58
+ sessionPolicy: { maxSessions: 5 },
59
+ };
60
+
61
+ export const security: SecurityConfig = {
62
+ cors: "*",
63
+ trustProxy: 1,
64
+ botProtection: { fingerprintRateLimit: true },
65
+ };`;if(R==="dev")return`export const auth: AuthConfig = {
66
+ roles: Object.values(USER_ROLES),
67
+ defaultRole: USER_ROLES.USER,
68
+ passwordPolicy: { minLength: 1, requireLetter: false, requireDigit: false, requireSpecial: false },
69
+ rateLimit: {
70
+ login: { windowMs: 60_000, max: 10_000 },
71
+ register: { windowMs: 60_000, max: 10_000 },
72
+ },
73
+ };
74
+
75
+ export const security: SecurityConfig = {
76
+ cors: "*",
77
+ bearerAuth: false,
78
+ };`;let z=m,G=[" roles: Object.values(USER_ROLES),"," defaultRole: USER_ROLES.USER,"];if(z.passwordPolicy==="relaxed")G.push(" passwordPolicy: { minLength: 8, requireLetter: true, requireDigit: true },");else if(z.passwordPolicy==="strong")G.push(" passwordPolicy: { minLength: 12, requireLetter: true, requireDigit: true, requireSpecial: true },");else G.push(" passwordPolicy: { minLength: 1, requireLetter: false, requireDigit: false, requireSpecial: false },");if(z.emailVerification)G.push(" emailVerification: {"),G.push(" required: true,"),G.push(" onSend: async (email, token) => { /* send via Resend, SendGrid, etc. */ },"),G.push(" },");if(z.passwordReset)G.push(" passwordReset: {"),G.push(" onSend: async (email, token) => { /* send via Resend, SendGrid, etc. */ },"),G.push(" },");if(z.refreshTokens)G.push(" refreshTokens: { accessTokenExpiry: 900, refreshTokenExpiry: 2_592_000 },");if(z.mfa==="optional")G.push(" mfa: { issuer: APP_NAME },");else if(z.mfa==="required")G.push(" mfa: { issuer: APP_NAME, required: true },");G.push(" sessionPolicy: { trackLastActive: true },");let U=`export const auth: AuthConfig = {
79
+ ${G.join(`
80
+ `)}
81
+ };`,J=[' cors: "*",'];if(z.csrf)J.push(" csrf: { enabled: true },");let $=`export const security: SecurityConfig = {
82
+ ${J.join(`
83
+ `)}
84
+ };`;return`${U}
85
+
86
+ ${$}`}var Uz=`export const APP_NAME = "${N}";
12
87
  export const APP_VERSION = "1.0.0";
13
88
 
14
89
  export const USER_ROLES = {
15
90
  ADMIN: "admin",
16
91
  USER: "user",
17
92
  };
18
- `,t=`import path from "path";
93
+ `,Xz=`import path from "path";
19
94
  import {
20
95
  type AppMeta,
21
96
  type AuthConfig,
@@ -36,16 +111,9 @@ export const workersDir = path.join(import.meta.dir, "../workers");
36
111
 
37
112
  export const port = process.env.PORT ? parseInt(process.env.PORT) : 3000;
38
113
 
39
- export const db: DbConfig = ${n()};
40
-
41
- export const auth: AuthConfig = {
42
- roles: Object.values(USER_ROLES),
43
- defaultRole: USER_ROLES.USER,
44
- };
114
+ export const db: DbConfig = ${Kz()};
45
115
 
46
- export const security: SecurityConfig = {
47
- cors: ["*"],
48
- };
116
+ ${Qz()}
49
117
 
50
118
  export const appConfig: CreateServerConfig = {
51
119
  app,
@@ -56,11 +124,11 @@ export const appConfig: CreateServerConfig = {
56
124
  auth,
57
125
  security,
58
126
  };
59
- `,i=`import { createServer } from "@lastshotlabs/bunshot";
127
+ `,Yz=`import { createServer } from "@lastshotlabs/bunshot";
60
128
  import { appConfig } from "@config/index";
61
129
 
62
130
  await createServer(appConfig);
63
- `,o=`# ${O}
131
+ `,Zz=`# ${N}
64
132
 
65
133
  Built with [@lastshotlabs/bunshot](https://github.com/Last-Shot-Labs/bunshot).
66
134
 
@@ -105,7 +173,7 @@ export const router = createRouter();
105
173
 
106
174
  router.get("/products", (c) => c.json({ products: [] }));
107
175
  \`\`\`
108
- ${K?`
176
+ ${Y?`
109
177
  ## Adding models
110
178
 
111
179
  \`\`\`ts
@@ -123,7 +191,7 @@ export const Product = appConnection.model("Product", ProductSchema);
123
191
  ## Environment variables
124
192
 
125
193
  See \`.env\` \u2014 fill in the values before running.
126
- `;function e(){let z=["NODE_ENV=development","PORT=3000"];if(K==="single")z.push(`
194
+ `;function $z(){let z=["NODE_ENV=development","PORT=3000"];if(Y==="single")z.push(`
127
195
  # MongoDB
128
196
  MONGO_USER_DEV=
129
197
  MONGO_PW_DEV=
@@ -132,7 +200,7 @@ MONGO_DB_DEV=
132
200
  MONGO_USER_PROD=
133
201
  MONGO_PW_PROD=
134
202
  MONGO_HOST_PROD=
135
- MONGO_DB_PROD=`);else if(K==="separate")z.push(`
203
+ MONGO_DB_PROD=`);else if(Y==="separate")z.push(`
136
204
  # MongoDB (app data)
137
205
  MONGO_USER_DEV=
138
206
  MONGO_PW_DEV=
@@ -151,7 +219,7 @@ MONGO_AUTH_DB_DEV=
151
219
  MONGO_AUTH_USER_PROD=
152
220
  MONGO_AUTH_PW_PROD=
153
221
  MONGO_AUTH_HOST_PROD=
154
- MONGO_AUTH_DB_PROD=`);if(W)z.push(`
222
+ MONGO_AUTH_DB_PROD=`);if(B)z.push(`
155
223
  # Redis
156
224
  REDIS_HOST_DEV=
157
225
  REDIS_USER_DEV=
@@ -168,26 +236,38 @@ BEARER_TOKEN_DEV=
168
236
  BEARER_TOKEN_PROD=
169
237
 
170
238
  # OAuth \u2014 Google (optional)
171
- GOOGLE_CLIENT_ID=
172
- GOOGLE_CLIENT_SECRET=
173
- GOOGLE_REDIRECT_URI=
239
+ # GOOGLE_CLIENT_ID=
240
+ # GOOGLE_CLIENT_SECRET=
241
+ # GOOGLE_REDIRECT_URI=
174
242
 
175
243
  # OAuth \u2014 Apple (optional)
176
- APPLE_CLIENT_ID=
177
- APPLE_TEAM_ID=
178
- APPLE_KEY_ID=
179
- APPLE_PRIVATE_KEY=
180
- APPLE_REDIRECT_URI=`),z.join(`
244
+ # APPLE_CLIENT_ID=
245
+ # APPLE_TEAM_ID=
246
+ # APPLE_KEY_ID=
247
+ # APPLE_PRIVATE_KEY=
248
+ # APPLE_REDIRECT_URI=
249
+
250
+ # OAuth \u2014 GitHub (optional)
251
+ # GITHUB_CLIENT_ID=
252
+ # GITHUB_CLIENT_SECRET=
253
+ # GITHUB_REDIRECT_URI=
254
+
255
+ # OAuth \u2014 Microsoft (optional)
256
+ # MICROSOFT_TENANT_ID=
257
+ # MICROSOFT_CLIENT_ID=
258
+ # MICROSOFT_CLIENT_SECRET=
259
+ # MICROSOFT_REDIRECT_URI=`),z.join(`
181
260
  `)+`
182
261
  `}console.log(`
183
- @lastshotlabs/bunshot \u2014 creating ${G}
184
- `);X(U,{recursive:!0});console.log(" Running bun init...");M("bun",["init","-y"],{cwd:U,stdio:"inherit"});var C=B(U,"index.ts");if(N(C))h(C);var y=B(U,"package.json"),L=JSON.parse(D("fs").readFileSync(y,"utf-8"));L.module="src/index.ts";L.scripts={dev:"bun --watch src/index.ts",start:"bun src/index.ts"};L.dependencies={...L.dependencies,"@lastshotlabs/bunshot":"*"};q(y,JSON.stringify(L,null,2)+`
185
- `,"utf-8");var zz=B(U,"tsconfig.json"),Az={compilerOptions:{lib:["ESNext"],target:"ESNext",module:"Preserve",moduleDetection:"force",jsx:"react-jsx",allowJs:!0,moduleResolution:"bundler",allowImportingTsExtensions:!0,verbatimModuleSyntax:!0,noEmit:!0,strict:!0,skipLibCheck:!0,noFallthroughCasesInSwitch:!0,noUncheckedIndexedAccess:!0,noImplicitOverride:!0,noUnusedLocals:!1,noUnusedParameters:!1,noPropertyAccessFromIndexSignature:!1,paths:{"@lib/*":["./src/lib/*"],"@middleware/*":["./src/middleware/*"],"@models/*":["./src/models/*"],"@queues/*":["./src/queues/*"],"@routes/*":["./src/routes/*"],"@scripts/*":["./src/scripts/*"],"@services/*":["./src/services/*"],"@workers/*":["./src/workers/*"],"@service-facades/*":["./src/service-facades/*"],"@config/*":["./src/config/*"],"@constants/*":["./src/lib/constants/*"]}}};q(zz,JSON.stringify(Az,null,2)+`
186
- `,"utf-8");X(k,{recursive:!0});X(j,{recursive:!0});X(p,{recursive:!0});X(l,{recursive:!0});X(u,{recursive:!0});X(d,{recursive:!0});X(c,{recursive:!0});X(a,{recursive:!0});X(r,{recursive:!0});q(B(j,"constants.ts"),s,"utf-8");q(B(k,"index.ts"),t,"utf-8");q(B(Y,"index.ts"),i,"utf-8");q(B(U,".env"),e(),"utf-8");q(B(U,"README.md"),o,"utf-8");console.log(" Created:");console.log(` + ${G}/src/index.ts`);console.log(` + ${G}/src/config/index.ts`);console.log(` + ${G}/src/lib/constants.ts`);console.log(` + ${G}/src/routes/`);console.log(` + ${G}/src/workers/`);console.log(` + ${G}/src/queues/`);console.log(` + ${G}/src/ws/`);console.log(` + ${G}/src/services/`);console.log(` + ${G}/src/middleware/`);console.log(` + ${G}/src/models/`);console.log(` + ${G}/.env`);console.log(` + ${G}/README.md`);console.log(`
187
- DB config:`);console.log(` mongo: ${K||"none"} | redis: ${W}`);console.log(` auth: ${P} | sessions: ${v} | cache: ${T} | oauthState: ${F}`);console.log(`
188
- Initializing git...`);var Bz=M("git",["init"],{cwd:U,stdio:"inherit"});if(Bz.status!==0)console.error(" git init failed \u2014 skipping.");console.log(`
189
- Installing dependencies...`);var Gz=M("bun",["install"],{cwd:U,stdio:"inherit"});if(Gz.status!==0)console.error(`
262
+ @lastshotlabs/bunshot \u2014 creating ${X}
263
+ `);E(A,{recursive:!0});console.log(" Running bun init...");w("bun",["init","-y"],{cwd:A,stdio:"inherit"});var k=K(A,"index.ts");if(D(k))r(k);var p=K(A,"package.json"),M=JSON.parse(a("fs").readFileSync(p,"utf-8"));M.module="src/index.ts";M.scripts={dev:"bun --watch src/index.ts",start:"bun src/index.ts"};M.dependencies={...M.dependencies,"@lastshotlabs/bunshot":"*"};I(p,JSON.stringify(M,null,2)+`
264
+ `,"utf-8");var Az=K(A,"tsconfig.json"),Ez={compilerOptions:{lib:["ESNext"],target:"ESNext",module:"Preserve",moduleDetection:"force",jsx:"react-jsx",allowJs:!0,moduleResolution:"bundler",allowImportingTsExtensions:!0,verbatimModuleSyntax:!0,noEmit:!0,strict:!0,skipLibCheck:!0,noFallthroughCasesInSwitch:!0,noUncheckedIndexedAccess:!0,noImplicitOverride:!0,noUnusedLocals:!1,noUnusedParameters:!1,noPropertyAccessFromIndexSignature:!1,paths:{"@lib/*":["./src/lib/*"],"@middleware/*":["./src/middleware/*"],"@models/*":["./src/models/*"],"@queues/*":["./src/queues/*"],"@routes/*":["./src/routes/*"],"@scripts/*":["./src/scripts/*"],"@services/*":["./src/services/*"],"@workers/*":["./src/workers/*"],"@service-facades/*":["./src/service-facades/*"],"@config/*":["./src/config/*"],"@constants/*":["./src/lib/constants/*"]}}};I(Az,JSON.stringify(Ez,null,2)+`
265
+ `,"utf-8");E(S,{recursive:!0});E(l,{recursive:!0});E(i,{recursive:!0});E(o,{recursive:!0});E(e,{recursive:!0});E(zz,{recursive:!0});E(Gz,{recursive:!0});E(Hz,{recursive:!0});E(Jz,{recursive:!0});I(K(l,"constants.ts"),Uz,"utf-8");I(K(S,"index.ts"),Xz,"utf-8");I(K(V,"index.ts"),Yz,"utf-8");I(K(A,".env"),$z(),"utf-8");I(K(A,"README.md"),Zz,"utf-8");console.log(" Created:");console.log(` + ${X}/src/index.ts`);console.log(` + ${X}/src/config/index.ts`);console.log(` + ${X}/src/lib/constants.ts`);console.log(` + ${X}/src/routes/`);console.log(` + ${X}/src/workers/`);console.log(` + ${X}/src/queues/`);console.log(` + ${X}/src/ws/`);console.log(` + ${X}/src/services/`);console.log(` + ${X}/src/middleware/`);console.log(` + ${X}/src/models/`);console.log(` + ${X}/.env`);console.log(` + ${X}/README.md`);console.log(`
266
+ DB config:`);console.log(` mongo: ${Y||"none"} | redis: ${B}`);console.log(` auth: ${T} | sessions: ${q} | cache: ${v} | oauthState: ${O}`);console.log(`
267
+ Auth config:`);console.log(` posture: ${R}`);console.log(`
268
+ Initializing git...`);var Vz=w("git",["init"],{cwd:A,stdio:"inherit"});if(Vz.status!==0)console.error(" git init failed \u2014 skipping.");console.log(`
269
+ Installing dependencies...`);var Wz=w("bun",["install"],{cwd:A,stdio:"inherit"});if(Wz.status!==0)console.error(`
190
270
  bun install failed. Run it manually inside the directory.`),process.exit(1);console.log(`
191
271
  Done! Next steps:
192
- `);console.log(` cd ${G}`);console.log(" # fill in .env");console.log(` bun dev
272
+ `);console.log(` cd ${X}`);console.log(" # fill in .env");console.log(` bun dev
193
273
  `);
package/dist/index.d.ts CHANGED
@@ -1,34 +1,47 @@
1
1
  export { createApp } from "./app";
2
2
  export { createServer } from "./server";
3
- export type { CreateAppConfig, ModelSchemasConfig, DbConfig, AppMeta, AuthConfig, AuthRateLimitConfig, AccountDeletionConfig, OAuthConfig, SecurityConfig, CsrfConfig, BotProtectionConfig, PrimaryField, EmailVerificationConfig, PasswordResetConfig, RefreshTokenConfig, MfaConfig, MfaEmailOtpConfig, MfaWebAuthnConfig, JobsConfig, TenancyConfig, TenantConfig } from "./app";
3
+ export type { SecurityEvent, SecurityEventType, SecurityEventConfig } from "./lib/securityEvents";
4
+ export { emitSecurityEvent, setSecurityEventConfig, getSecurityEventConfig } from "./lib/securityEvents";
5
+ export type { CreateAppConfig, ModelSchemasConfig, DbConfig, AppMeta, AuthConfig, AuthRateLimitConfig, AccountDeletionConfig, OAuthConfig, SecurityConfig, CsrfConfig, BotProtectionConfig, PrimaryField, EmailVerificationConfig, PasswordResetConfig, RefreshTokenConfig, MfaConfig, MfaEmailOtpConfig, MfaWebAuthnConfig, JobsConfig, TenancyConfig, TenantConfig, LoggingConfig, MetricsConfig, ValidationConfig, VersioningConfig, SigningConfig, JwtConfig, BreachedPasswordConfig, StepUpConfig, OidcConfig, SamlConfig, ScimConfig } from "./app";
6
+ export { setScimTokens } from "./middleware/scimAuth";
4
7
  export type { PasswordPolicyConfig } from "./lib/appConfig";
8
+ export type { SamlProfile } from "./lib/saml";
5
9
  export type { CreateServerConfig, WsConfig } from "./server";
6
10
  export { appConnection, authConnection, mongoose, connectMongo, connectAuthMongo, connectAppMongo, disconnectMongo } from "./lib/mongo";
7
11
  export { connectRedis, disconnectRedis, getRedis } from "./lib/redis";
8
12
  export { getAppRoles } from "./lib/appConfig";
9
- export { HttpError } from "./lib/HttpError";
10
- export { COOKIE_TOKEN, HEADER_USER_TOKEN, COOKIE_REFRESH_TOKEN, HEADER_REFRESH_TOKEN, COOKIE_CSRF_TOKEN, HEADER_CSRF_TOKEN } from "./lib/constants";
13
+ export { HttpError, ValidationError } from "./lib/HttpError";
14
+ export { COOKIE_TOKEN, HEADER_USER_TOKEN, COOKIE_REFRESH_TOKEN, HEADER_REFRESH_TOKEN, COOKIE_CSRF_TOKEN, HEADER_CSRF_TOKEN, HEADER_REQUEST_ID, HEADER_IDEMPOTENCY_KEY, HEADER_SIGNATURE, HEADER_TIMESTAMP } from "./lib/constants";
11
15
  export { createRouter } from "./lib/context";
12
- export { createRoute, withSecurity, registerSchema, registerSchemas } from "./lib/createRoute";
16
+ export { createRoute, withSecurity, registerSchema, registerSchemas, setVersionPrefix, clearVersionPrefix } from "./lib/createRoute";
17
+ export { stripUnreferencedSchemas } from "./lib/stripUnreferencedSchemas";
13
18
  export { zodToMongoose } from "./lib/zodToMongoose";
14
19
  export type { ZodToMongooseConfig, ZodToMongooseRefConfig } from "./lib/zodToMongoose";
15
20
  export { createDtoMapper } from "./lib/createDtoMapper";
16
21
  export type { DtoMapperConfig } from "./lib/createDtoMapper";
17
- export type { AppEnv, AppVariables } from "./lib/context";
22
+ export type { AppEnv, AppVariables, ValidationErrorFormatter, DefaultValidationErrorBody, ValidationErrorDetail } from "./lib/context";
23
+ export { defaultValidationErrorFormatter } from "./lib/context";
18
24
  export { signToken, verifyToken } from "./lib/jwt";
25
+ export { getJwks, loadJwksKey, generateAndLoadKeyPair, isJwksLoaded } from "./lib/jwks";
19
26
  export { log } from "./lib/logger";
20
27
  export { createResetToken, consumeResetToken, setPasswordResetStore } from "./lib/resetPassword";
28
+ export { createDeletionCancelToken, consumeDeletionCancelToken, setDeletionCancelTokenStore } from "./lib/deletionCancelToken";
21
29
  export { timingSafeEqual, sha256 } from "./lib/crypto";
30
+ export { hmacSign, hmacVerify, signCookieValue, verifyCookieValue, signCursor, verifyCursor, createPresignedUrl, verifyPresignedUrl } from "./lib/signing";
31
+ export { idempotent, setIdempotencyStore, clearIdempotencyMemoryStore } from "./lib/idempotency";
32
+ export type { IdempotencyOptions } from "./lib/idempotency";
22
33
  export { getClientIp, setTrustProxy } from "./lib/clientIp";
23
34
  export { storeOAuthCode, consumeOAuthCode, setOAuthCodeStore } from "./lib/oauthCode";
24
35
  export type { OAuthCodePayload } from "./lib/oauthCode";
25
- export { createSession, getSession, deleteSession, getUserSessions, getActiveSessionCount, evictOldestSession, updateSessionLastActive, setSessionStore, deleteUserSessions, setRefreshToken, getSessionByRefreshToken, rotateRefreshToken } from "./lib/session";
36
+ export { createSession, getSession, deleteSession, getUserSessions, getActiveSessionCount, evictOldestSession, updateSessionLastActive, setSessionStore, deleteUserSessions, setRefreshToken, getSessionByRefreshToken, rotateRefreshToken, getSessionFingerprint, setSessionFingerprint, setMfaVerifiedAt, getMfaVerifiedAt } from "./lib/session";
26
37
  export type { SessionMetadata, SessionInfo, RefreshResult } from "./lib/session";
27
38
  export { createVerificationToken, getVerificationToken, deleteVerificationToken } from "./lib/emailVerification";
28
39
  export { createMfaChallenge, consumeMfaChallenge, replaceMfaChallengeOtp, setMfaChallengeStore, createWebAuthnRegistrationChallenge, consumeWebAuthnRegistrationChallenge, clearMemoryMfaChallenges } from "./lib/mfaChallenge";
29
40
  export type { MfaChallengeData, MfaChallengeOptions, MfaChallengePurpose } from "./lib/mfaChallenge";
30
41
  export { bustAuthLimit, trackAttempt, isLimited, clearMemoryRateLimitStore } from "./lib/authRateLimit";
31
42
  export type { LimitOpts } from "./lib/authRateLimit";
43
+ export { trackFailedLogin, isStuffingBlocked, setCredentialStuffingConfig, clearCredentialStuffingStore } from "./lib/credentialStuffing";
44
+ export type { CredentialStuffingConfig } from "./lib/credentialStuffing";
32
45
  export { validate } from "./lib/validate";
33
46
  export { bearerAuth } from "./middleware/bearerAuth";
34
47
  export { botProtection } from "./middleware/botProtection";
@@ -39,18 +52,66 @@ export type { RateLimitOptions } from "./middleware/rateLimit";
39
52
  export { userAuth } from "./middleware/userAuth";
40
53
  export { requireRole } from "./middleware/requireRole";
41
54
  export { requireVerifiedEmail } from "./middleware/requireVerifiedEmail";
55
+ export { requireMfaSetup } from "./middleware/requireMfaSetup";
56
+ export { requireStepUp } from "./middleware/requireStepUp";
57
+ export type { StepUpOptions } from "./middleware/requireStepUp";
42
58
  export { csrfProtection, refreshCsrfToken, clearCsrfToken } from "./middleware/csrf";
43
59
  export type { CsrfMiddlewareOptions } from "./middleware/csrf";
44
60
  export { cacheResponse, bustCache, bustCachePattern, setCacheStore, getCacheModel } from "./middleware/cacheResponse";
61
+ export { webhookAuth } from "./middleware/webhookAuth";
62
+ export type { WebhookAuthOptions, WebhookTimestampOptions } from "./middleware/webhookAuth";
63
+ export { requireSignedRequest } from "./middleware/requestSigning";
64
+ export type { RequestSigningOptions } from "./middleware/requestSigning";
65
+ export { auditLog } from "./middleware/auditLog";
66
+ export type { AuditLogMiddlewareOptions } from "./middleware/auditLog";
67
+ export { requestId } from "./middleware/requestId";
68
+ export { requestLogger } from "./middleware/requestLogger";
69
+ export type { RequestLogEntry, RequestLoggerOptions, LogLevel } from "./middleware/requestLogger";
70
+ export { metricsCollector } from "./middleware/metrics";
71
+ export type { MetricsMiddlewareOptions } from "./middleware/metrics";
72
+ export { requireCaptcha } from "./middleware/captcha";
73
+ export type { CaptchaConfig, CaptchaProvider } from "./lib/captcha";
74
+ export { verifyCaptcha } from "./lib/captcha";
75
+ export { requireScope } from "./middleware/requireScope";
76
+ export { createM2MClient, deleteM2MClient, listM2MClients, getM2MClient } from "./lib/m2m";
77
+ export type { M2MClientRecord } from "./lib/authAdapter";
78
+ export type { M2MConfig } from "./lib/appConfig";
45
79
  export { buildFingerprint } from "./lib/fingerprint";
80
+ export { logAuditEntry, getAuditLogs, clearAuditLogMemoryStore } from "./lib/auditLog";
81
+ export { resetMetrics, incrementCounter, observeHistogram, registerGaugeCallback, serializeMetrics, closeMetricsQueues } from "./lib/metrics";
82
+ export type { AuditLogEntry, AuditLogOptions, AuditLogQuery } from "./lib/auditLog";
46
83
  export { sqliteAuthAdapter, setSqliteDb, startSqliteCleanup } from "./adapters/sqliteAuth";
47
84
  export { memoryAuthAdapter, clearMemoryStore } from "./adapters/memoryAuth";
48
85
  export { setUserRoles, addUserRole, removeUserRole, getTenantRoles, setTenantRoles, addTenantRole, removeTenantRole } from "./lib/roles";
49
- export type { AuthAdapter, OAuthProfile, WebAuthnCredential } from "./lib/authAdapter";
86
+ export { setSuspended, getSuspended } from "./lib/suspension";
87
+ export type { AuthAdapter, OAuthProfile, IdentityProfile, UserRecord, UserQuery, WebAuthnCredential } from "./lib/authAdapter";
50
88
  export type { OAuthProviderConfig } from "./lib/oauth";
51
89
  export { websocket, createWsUpgradeHandler } from "./ws/index";
52
90
  export type { SocketData } from "./ws/index";
53
- export { publish, subscribe, unsubscribe, getSubscriptions, handleRoomActions, getRooms, getRoomSubscribers } from "./lib/ws";
91
+ export { publish, subscribe, unsubscribe, getSubscriptions, handleRoomActions, getRooms, getRoomSubscribers, setPresenceEnabled } from "./lib/ws";
92
+ export { registerSocket, deregisterSocket, handlePong, startHeartbeat, stopHeartbeat, clearHeartbeatState } from "./lib/wsHeartbeat";
93
+ export type { HeartbeatConfig } from "./lib/wsHeartbeat";
94
+ export { trackSocket, untrackSocket, addPresence, removePresence, cleanupPresence, getRoomPresence, getUserPresence, clearPresenceStore } from "./lib/wsPresence";
95
+ export { persistMessage, getMessageHistory, configureRoom, setWsMessageStore, setWsMessageDefaults, clearWsMessageMemoryStore } from "./lib/wsMessages";
96
+ export type { StoredMessage, WsMessageStore, WsMessageDefaults, RoomPersistenceConfig } from "./lib/wsMessages";
54
97
  export { createTenant, deleteTenant, getTenant, listTenants } from "./lib/tenant";
55
98
  export type { TenantInfo, CreateTenantOptions } from "./lib/tenant";
56
99
  export { invalidateTenantCache } from "./middleware/tenant";
100
+ export { createGroup, deleteGroup, getGroup, listGroups, updateGroup, addGroupMember, updateGroupMembership, removeGroupMember, getGroupMembers, getUserGroups, getEffectiveRoles, } from "./lib/groups";
101
+ export type { GroupRecord, GroupMembershipRecord, PaginationOpts, PaginatedResult } from "./lib/groups";
102
+ export type { GroupsConfig, GroupsManagementConfig } from "./routes/groups";
103
+ export { offsetParams, parseOffsetParams, paginatedResponse, cursorParams, parseCursorParams, cursorResponse, maybeSignCursor, } from "./lib/pagination";
104
+ export type { OffsetParamDefaults, ParsedOffsetParams, CursorParamDefaults, ParsedCursorParams, CursorResult, } from "./lib/pagination";
105
+ export { handleUpload } from "./middleware/upload";
106
+ export type { UploadMiddlewareOptions } from "./middleware/upload";
107
+ export { parseUpload, setStorageAdapter, getStorageAdapter, setUploadConfig, getUploadConfig, generateUploadKeyFromFilename } from "./lib/upload";
108
+ export type { UploadOpts } from "./lib/upload";
109
+ export { setUploadRegistryStore, clearUploadRegistry, registerUpload, getUploadRecord, deleteUploadRecord } from "./lib/uploadRegistry";
110
+ export type { UploadRecord } from "./lib/uploadRegistry";
111
+ export type { StorageAdapter, UploadResult } from "./lib/storageAdapter";
112
+ export type { UploadConfig, PresignedUrlConfig } from "./app";
113
+ export { memoryStorage, clearMemoryUploadStore } from "./adapters/memoryStorage";
114
+ export { localStorage } from "./adapters/localStorage";
115
+ export type { LocalStorageConfig } from "./adapters/localStorage";
116
+ export { s3Storage } from "./adapters/s3Storage";
117
+ export type { S3StorageConfig } from "./adapters/s3Storage";
package/dist/index.js CHANGED
@@ -1,27 +1,36 @@
1
1
  // App factory
2
2
  export { createApp } from "./app";
3
3
  export { createServer } from "./server";
4
+ export { emitSecurityEvent, setSecurityEventConfig, getSecurityEventConfig } from "./lib/securityEvents";
5
+ export { setScimTokens } from "./middleware/scimAuth";
4
6
  // Database
5
7
  export { appConnection, authConnection, mongoose, connectMongo, connectAuthMongo, connectAppMongo, disconnectMongo } from "./lib/mongo";
6
8
  export { connectRedis, disconnectRedis, getRedis } from "./lib/redis";
7
9
  // Lib utilities
8
10
  export { getAppRoles } from "./lib/appConfig";
9
- export { HttpError } from "./lib/HttpError";
10
- export { COOKIE_TOKEN, HEADER_USER_TOKEN, COOKIE_REFRESH_TOKEN, HEADER_REFRESH_TOKEN, COOKIE_CSRF_TOKEN, HEADER_CSRF_TOKEN } from "./lib/constants";
11
+ export { HttpError, ValidationError } from "./lib/HttpError";
12
+ export { COOKIE_TOKEN, HEADER_USER_TOKEN, COOKIE_REFRESH_TOKEN, HEADER_REFRESH_TOKEN, COOKIE_CSRF_TOKEN, HEADER_CSRF_TOKEN, HEADER_REQUEST_ID, HEADER_IDEMPOTENCY_KEY, HEADER_SIGNATURE, HEADER_TIMESTAMP } from "./lib/constants";
11
13
  export { createRouter } from "./lib/context";
12
- export { createRoute, withSecurity, registerSchema, registerSchemas } from "./lib/createRoute";
14
+ export { createRoute, withSecurity, registerSchema, registerSchemas, setVersionPrefix, clearVersionPrefix } from "./lib/createRoute";
15
+ export { stripUnreferencedSchemas } from "./lib/stripUnreferencedSchemas";
13
16
  export { zodToMongoose } from "./lib/zodToMongoose";
14
17
  export { createDtoMapper } from "./lib/createDtoMapper";
18
+ export { defaultValidationErrorFormatter } from "./lib/context";
15
19
  export { signToken, verifyToken } from "./lib/jwt";
20
+ export { getJwks, loadJwksKey, generateAndLoadKeyPair, isJwksLoaded } from "./lib/jwks";
16
21
  export { log } from "./lib/logger";
17
22
  export { createResetToken, consumeResetToken, setPasswordResetStore } from "./lib/resetPassword";
23
+ export { createDeletionCancelToken, consumeDeletionCancelToken, setDeletionCancelTokenStore } from "./lib/deletionCancelToken";
18
24
  export { timingSafeEqual, sha256 } from "./lib/crypto";
25
+ export { hmacSign, hmacVerify, signCookieValue, verifyCookieValue, signCursor, verifyCursor, createPresignedUrl, verifyPresignedUrl } from "./lib/signing";
26
+ export { idempotent, setIdempotencyStore, clearIdempotencyMemoryStore } from "./lib/idempotency";
19
27
  export { getClientIp, setTrustProxy } from "./lib/clientIp";
20
28
  export { storeOAuthCode, consumeOAuthCode, setOAuthCodeStore } from "./lib/oauthCode";
21
- export { createSession, getSession, deleteSession, getUserSessions, getActiveSessionCount, evictOldestSession, updateSessionLastActive, setSessionStore, deleteUserSessions, setRefreshToken, getSessionByRefreshToken, rotateRefreshToken } from "./lib/session";
29
+ export { createSession, getSession, deleteSession, getUserSessions, getActiveSessionCount, evictOldestSession, updateSessionLastActive, setSessionStore, deleteUserSessions, setRefreshToken, getSessionByRefreshToken, rotateRefreshToken, getSessionFingerprint, setSessionFingerprint, setMfaVerifiedAt, getMfaVerifiedAt } from "./lib/session";
22
30
  export { createVerificationToken, getVerificationToken, deleteVerificationToken } from "./lib/emailVerification";
23
31
  export { createMfaChallenge, consumeMfaChallenge, replaceMfaChallengeOtp, setMfaChallengeStore, createWebAuthnRegistrationChallenge, consumeWebAuthnRegistrationChallenge, clearMemoryMfaChallenges } from "./lib/mfaChallenge";
24
32
  export { bustAuthLimit, trackAttempt, isLimited, clearMemoryRateLimitStore } from "./lib/authRateLimit";
33
+ export { trackFailedLogin, isStuffingBlocked, setCredentialStuffingConfig, clearCredentialStuffingStore } from "./lib/credentialStuffing";
25
34
  export { validate } from "./lib/validate";
26
35
  // Middleware
27
36
  export { bearerAuth } from "./middleware/bearerAuth";
@@ -31,17 +40,49 @@ export { rateLimit } from "./middleware/rateLimit";
31
40
  export { userAuth } from "./middleware/userAuth";
32
41
  export { requireRole } from "./middleware/requireRole";
33
42
  export { requireVerifiedEmail } from "./middleware/requireVerifiedEmail";
43
+ export { requireMfaSetup } from "./middleware/requireMfaSetup";
44
+ export { requireStepUp } from "./middleware/requireStepUp";
34
45
  export { csrfProtection, refreshCsrfToken, clearCsrfToken } from "./middleware/csrf";
35
46
  export { cacheResponse, bustCache, bustCachePattern, setCacheStore, getCacheModel } from "./middleware/cacheResponse";
47
+ export { webhookAuth } from "./middleware/webhookAuth";
48
+ export { requireSignedRequest } from "./middleware/requestSigning";
49
+ export { auditLog } from "./middleware/auditLog";
50
+ export { requestId } from "./middleware/requestId";
51
+ export { requestLogger } from "./middleware/requestLogger";
52
+ export { metricsCollector } from "./middleware/metrics";
53
+ export { requireCaptcha } from "./middleware/captcha";
54
+ export { verifyCaptcha } from "./lib/captcha";
55
+ export { requireScope } from "./middleware/requireScope";
56
+ export { createM2MClient, deleteM2MClient, listM2MClients, getM2MClient } from "./lib/m2m";
36
57
  // Lib utilities (bot protection)
37
58
  export { buildFingerprint } from "./lib/fingerprint";
59
+ export { logAuditEntry, getAuditLogs, clearAuditLogMemoryStore } from "./lib/auditLog";
60
+ export { resetMetrics, incrementCounter, observeHistogram, registerGaugeCallback, serializeMetrics, closeMetricsQueues } from "./lib/metrics";
38
61
  // Models
39
62
  export { sqliteAuthAdapter, setSqliteDb, startSqliteCleanup } from "./adapters/sqliteAuth";
40
63
  export { memoryAuthAdapter, clearMemoryStore } from "./adapters/memoryAuth";
41
64
  export { setUserRoles, addUserRole, removeUserRole, getTenantRoles, setTenantRoles, addTenantRole, removeTenantRole } from "./lib/roles";
65
+ export { setSuspended, getSuspended } from "./lib/suspension";
42
66
  // WebSocket
43
67
  export { websocket, createWsUpgradeHandler } from "./ws/index";
44
- export { publish, subscribe, unsubscribe, getSubscriptions, handleRoomActions, getRooms, getRoomSubscribers } from "./lib/ws";
68
+ export { publish, subscribe, unsubscribe, getSubscriptions, handleRoomActions, getRooms, getRoomSubscribers, setPresenceEnabled } from "./lib/ws";
69
+ // WebSocket — Heartbeat
70
+ export { registerSocket, deregisterSocket, handlePong, startHeartbeat, stopHeartbeat, clearHeartbeatState } from "./lib/wsHeartbeat";
71
+ // WebSocket — Presence
72
+ export { trackSocket, untrackSocket, addPresence, removePresence, cleanupPresence, getRoomPresence, getUserPresence, clearPresenceStore } from "./lib/wsPresence";
73
+ // WebSocket — Message Persistence
74
+ export { persistMessage, getMessageHistory, configureRoom, setWsMessageStore, setWsMessageDefaults, clearWsMessageMemoryStore } from "./lib/wsMessages";
45
75
  // Tenancy
46
76
  export { createTenant, deleteTenant, getTenant, listTenants } from "./lib/tenant";
47
77
  export { invalidateTenantCache } from "./middleware/tenant";
78
+ // Groups
79
+ export { createGroup, deleteGroup, getGroup, listGroups, updateGroup, addGroupMember, updateGroupMembership, removeGroupMember, getGroupMembers, getUserGroups, getEffectiveRoles, } from "./lib/groups";
80
+ // Pagination helpers
81
+ export { offsetParams, parseOffsetParams, paginatedResponse, cursorParams, parseCursorParams, cursorResponse, maybeSignCursor, } from "./lib/pagination";
82
+ // Upload
83
+ export { handleUpload } from "./middleware/upload";
84
+ export { parseUpload, setStorageAdapter, getStorageAdapter, setUploadConfig, getUploadConfig, generateUploadKeyFromFilename } from "./lib/upload";
85
+ export { setUploadRegistryStore, clearUploadRegistry, registerUpload, getUploadRecord, deleteUploadRecord } from "./lib/uploadRegistry";
86
+ export { memoryStorage, clearMemoryUploadStore } from "./adapters/memoryStorage";
87
+ export { localStorage } from "./adapters/localStorage";
88
+ export { s3Storage } from "./adapters/s3Storage";
@@ -1,4 +1,10 @@
1
1
  export declare class HttpError extends Error {
2
2
  status: number;
3
- constructor(status: number, message: string);
3
+ code?: string | undefined;
4
+ constructor(status: number, message: string, code?: string | undefined);
5
+ }
6
+ import type { ZodIssue } from "zod";
7
+ export declare class ValidationError extends HttpError {
8
+ readonly issues: ZodIssue[];
9
+ constructor(issues: ZodIssue[]);
4
10
  }
@@ -1,7 +1,16 @@
1
1
  export class HttpError extends Error {
2
2
  status;
3
- constructor(status, message) {
3
+ code;
4
+ constructor(status, message, code) {
4
5
  super(message);
5
6
  this.status = status;
7
+ this.code = code;
8
+ }
9
+ }
10
+ export class ValidationError extends HttpError {
11
+ issues;
12
+ constructor(issues) {
13
+ super(400, "Validation failed");
14
+ this.issues = issues;
6
15
  }
7
16
  }