@lastshotlabs/bunshot 0.0.20 → 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.
- package/README.md +3035 -1249
- package/dist/adapters/localStorage.d.ts +6 -0
- package/dist/adapters/localStorage.js +44 -0
- package/dist/adapters/memoryAuth.d.ts +7 -0
- package/dist/adapters/memoryAuth.js +144 -0
- package/dist/adapters/memoryStorage.d.ts +3 -0
- package/dist/adapters/memoryStorage.js +44 -0
- package/dist/adapters/mongoAuth.js +120 -0
- package/dist/adapters/s3Storage.d.ts +14 -0
- package/dist/adapters/s3Storage.js +126 -0
- package/dist/adapters/sqliteAuth.d.ts +7 -0
- package/dist/adapters/sqliteAuth.js +199 -0
- package/dist/app.d.ts +100 -3
- package/dist/app.js +248 -47
- package/dist/cli.js +118 -38
- package/dist/index.d.ts +49 -7
- package/dist/index.js +35 -5
- package/dist/lib/HttpError.d.ts +5 -0
- package/dist/lib/HttpError.js +7 -0
- package/dist/lib/appConfig.d.ts +44 -0
- package/dist/lib/appConfig.js +16 -0
- package/dist/lib/auditLog.d.ts +52 -0
- package/dist/lib/auditLog.js +201 -0
- package/dist/lib/authAdapter.d.ts +69 -0
- package/dist/lib/constants.d.ts +4 -0
- package/dist/lib/constants.js +4 -0
- package/dist/lib/context.d.ts +19 -1
- package/dist/lib/context.js +17 -3
- package/dist/lib/createRoute.d.ts +28 -2
- package/dist/lib/createRoute.js +54 -3
- package/dist/lib/deletionCancelToken.d.ts +12 -0
- package/dist/lib/deletionCancelToken.js +88 -0
- package/dist/lib/groups.d.ts +113 -0
- package/dist/lib/groups.js +133 -0
- package/dist/lib/idempotency.d.ts +22 -0
- package/dist/lib/idempotency.js +182 -0
- package/dist/lib/metrics.d.ts +14 -0
- package/dist/lib/metrics.js +158 -0
- package/dist/lib/pagination.d.ts +119 -0
- package/dist/lib/pagination.js +166 -0
- package/dist/lib/session.d.ts +4 -0
- package/dist/lib/session.js +56 -2
- package/dist/lib/signing.d.ts +52 -0
- package/dist/lib/signing.js +180 -0
- package/dist/lib/storageAdapter.d.ts +30 -0
- package/dist/lib/storageAdapter.js +1 -0
- package/dist/lib/stripUnreferencedSchemas.d.ts +11 -0
- package/dist/lib/stripUnreferencedSchemas.js +79 -0
- package/dist/lib/tenant.js +2 -2
- package/dist/lib/upload.d.ts +35 -0
- package/dist/lib/upload.js +87 -0
- package/dist/lib/validate.js +2 -2
- package/dist/lib/ws.d.ts +1 -0
- package/dist/lib/ws.js +21 -0
- package/dist/lib/wsHeartbeat.d.ts +12 -0
- package/dist/lib/wsHeartbeat.js +57 -0
- package/dist/lib/wsMessages.d.ts +40 -0
- package/dist/lib/wsMessages.js +330 -0
- package/dist/lib/wsPresence.d.ts +25 -0
- package/dist/lib/wsPresence.js +99 -0
- package/dist/middleware/auditLog.d.ts +22 -0
- package/dist/middleware/auditLog.js +39 -0
- package/dist/middleware/cacheResponse.js +5 -1
- package/dist/middleware/csrf.js +10 -0
- package/dist/middleware/identify.js +57 -9
- package/dist/middleware/metrics.d.ts +9 -0
- package/dist/middleware/metrics.js +26 -0
- package/dist/middleware/requestId.d.ts +3 -0
- package/dist/middleware/requestId.js +7 -0
- package/dist/middleware/requestLogger.d.ts +38 -0
- package/dist/middleware/requestLogger.js +68 -0
- package/dist/middleware/requestSigning.d.ts +20 -0
- package/dist/middleware/requestSigning.js +99 -0
- package/dist/middleware/requireMfaSetup.d.ts +16 -0
- package/dist/middleware/requireMfaSetup.js +36 -0
- package/dist/middleware/requireRole.d.ts +9 -3
- package/dist/middleware/requireRole.js +23 -36
- package/dist/middleware/upload.d.ts +5 -0
- package/dist/middleware/upload.js +27 -0
- package/dist/middleware/webhookAuth.d.ts +30 -0
- package/dist/middleware/webhookAuth.js +57 -0
- package/dist/models/AuditLog.d.ts +30 -0
- package/dist/models/AuditLog.js +39 -0
- package/dist/models/Group.d.ts +21 -0
- package/dist/models/Group.js +28 -0
- package/dist/models/GroupMembership.d.ts +21 -0
- package/dist/models/GroupMembership.js +25 -0
- package/dist/routes/auth.js +84 -6
- package/dist/routes/groups.d.ts +21 -0
- package/dist/routes/groups.js +346 -0
- package/dist/routes/jobs.js +47 -45
- package/dist/routes/metrics.d.ts +7 -0
- package/dist/routes/metrics.js +52 -0
- package/dist/routes/mfa.js +4 -0
- package/dist/routes/uploads.d.ts +2 -0
- package/dist/routes/uploads.js +135 -0
- package/dist/server.d.ts +26 -0
- package/dist/server.js +46 -3
- package/dist/ws/index.js +3 -0
- package/docs/sections/auth-flow/full.md +779 -634
- package/docs/sections/auth-flow/overview.md +2 -2
- package/docs/sections/auth-security-examples/full.md +365 -0
- package/docs/sections/authentication/full.md +130 -0
- package/docs/sections/authentication/overview.md +5 -0
- package/docs/sections/cli/full.md +13 -1
- package/docs/sections/configuration/full.md +17 -0
- package/docs/sections/configuration/overview.md +1 -0
- package/docs/sections/exports/full.md +34 -3
- package/docs/sections/logging/full.md +83 -0
- package/docs/sections/metrics/full.md +127 -0
- package/docs/sections/oauth/full.md +189 -189
- package/docs/sections/oauth/overview.md +1 -1
- package/docs/sections/pagination/full.md +93 -0
- package/docs/sections/roles/full.md +224 -135
- package/docs/sections/roles/overview.md +3 -1
- package/docs/sections/signing/full.md +203 -0
- package/docs/sections/uploads/full.md +199 -0
- package/docs/sections/versioning/full.md +85 -0
- package/docs/sections/webhook-auth/full.md +100 -0
- package/docs/sections/websocket/full.md +83 -0
- package/docs/sections/websocket-rooms/full.md +6 -1
- package/package.json +16 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,28 +1,34 @@
|
|
|
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 { 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 } from "./app";
|
|
4
4
|
export type { PasswordPolicyConfig } from "./lib/appConfig";
|
|
5
5
|
export type { CreateServerConfig, WsConfig } from "./server";
|
|
6
6
|
export { appConnection, authConnection, mongoose, connectMongo, connectAuthMongo, connectAppMongo, disconnectMongo } from "./lib/mongo";
|
|
7
7
|
export { connectRedis, disconnectRedis, getRedis } from "./lib/redis";
|
|
8
8
|
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";
|
|
9
|
+
export { HttpError, ValidationError } from "./lib/HttpError";
|
|
10
|
+
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
11
|
export { createRouter } from "./lib/context";
|
|
12
|
-
export { createRoute, withSecurity, registerSchema, registerSchemas } from "./lib/createRoute";
|
|
12
|
+
export { createRoute, withSecurity, registerSchema, registerSchemas, setVersionPrefix, clearVersionPrefix } from "./lib/createRoute";
|
|
13
|
+
export { stripUnreferencedSchemas } from "./lib/stripUnreferencedSchemas";
|
|
13
14
|
export { zodToMongoose } from "./lib/zodToMongoose";
|
|
14
15
|
export type { ZodToMongooseConfig, ZodToMongooseRefConfig } from "./lib/zodToMongoose";
|
|
15
16
|
export { createDtoMapper } from "./lib/createDtoMapper";
|
|
16
17
|
export type { DtoMapperConfig } from "./lib/createDtoMapper";
|
|
17
|
-
export type { AppEnv, AppVariables } from "./lib/context";
|
|
18
|
+
export type { AppEnv, AppVariables, ValidationErrorFormatter, DefaultValidationErrorBody, ValidationErrorDetail } from "./lib/context";
|
|
19
|
+
export { defaultValidationErrorFormatter } from "./lib/context";
|
|
18
20
|
export { signToken, verifyToken } from "./lib/jwt";
|
|
19
21
|
export { log } from "./lib/logger";
|
|
20
22
|
export { createResetToken, consumeResetToken, setPasswordResetStore } from "./lib/resetPassword";
|
|
23
|
+
export { createDeletionCancelToken, consumeDeletionCancelToken, setDeletionCancelTokenStore } from "./lib/deletionCancelToken";
|
|
21
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";
|
|
27
|
+
export type { IdempotencyOptions } from "./lib/idempotency";
|
|
22
28
|
export { getClientIp, setTrustProxy } from "./lib/clientIp";
|
|
23
29
|
export { storeOAuthCode, consumeOAuthCode, setOAuthCodeStore } from "./lib/oauthCode";
|
|
24
30
|
export type { OAuthCodePayload } from "./lib/oauthCode";
|
|
25
|
-
export { createSession, getSession, deleteSession, getUserSessions, getActiveSessionCount, evictOldestSession, updateSessionLastActive, setSessionStore, deleteUserSessions, setRefreshToken, getSessionByRefreshToken, rotateRefreshToken } from "./lib/session";
|
|
31
|
+
export { createSession, getSession, deleteSession, getUserSessions, getActiveSessionCount, evictOldestSession, updateSessionLastActive, setSessionStore, deleteUserSessions, setRefreshToken, getSessionByRefreshToken, rotateRefreshToken, getSessionFingerprint, setSessionFingerprint } from "./lib/session";
|
|
26
32
|
export type { SessionMetadata, SessionInfo, RefreshResult } from "./lib/session";
|
|
27
33
|
export { createVerificationToken, getVerificationToken, deleteVerificationToken } from "./lib/emailVerification";
|
|
28
34
|
export { createMfaChallenge, consumeMfaChallenge, replaceMfaChallengeOtp, setMfaChallengeStore, createWebAuthnRegistrationChallenge, consumeWebAuthnRegistrationChallenge, clearMemoryMfaChallenges } from "./lib/mfaChallenge";
|
|
@@ -39,10 +45,25 @@ export type { RateLimitOptions } from "./middleware/rateLimit";
|
|
|
39
45
|
export { userAuth } from "./middleware/userAuth";
|
|
40
46
|
export { requireRole } from "./middleware/requireRole";
|
|
41
47
|
export { requireVerifiedEmail } from "./middleware/requireVerifiedEmail";
|
|
48
|
+
export { requireMfaSetup } from "./middleware/requireMfaSetup";
|
|
42
49
|
export { csrfProtection, refreshCsrfToken, clearCsrfToken } from "./middleware/csrf";
|
|
43
50
|
export type { CsrfMiddlewareOptions } from "./middleware/csrf";
|
|
44
51
|
export { cacheResponse, bustCache, bustCachePattern, setCacheStore, getCacheModel } from "./middleware/cacheResponse";
|
|
52
|
+
export { webhookAuth } from "./middleware/webhookAuth";
|
|
53
|
+
export type { WebhookAuthOptions, WebhookTimestampOptions } from "./middleware/webhookAuth";
|
|
54
|
+
export { requireSignedRequest } from "./middleware/requestSigning";
|
|
55
|
+
export type { RequestSigningOptions } from "./middleware/requestSigning";
|
|
56
|
+
export { auditLog } from "./middleware/auditLog";
|
|
57
|
+
export type { AuditLogMiddlewareOptions } from "./middleware/auditLog";
|
|
58
|
+
export { requestId } from "./middleware/requestId";
|
|
59
|
+
export { requestLogger } from "./middleware/requestLogger";
|
|
60
|
+
export type { RequestLogEntry, RequestLoggerOptions, LogLevel } from "./middleware/requestLogger";
|
|
61
|
+
export { metricsCollector } from "./middleware/metrics";
|
|
62
|
+
export type { MetricsMiddlewareOptions } from "./middleware/metrics";
|
|
45
63
|
export { buildFingerprint } from "./lib/fingerprint";
|
|
64
|
+
export { logAuditEntry, getAuditLogs, clearAuditLogMemoryStore } from "./lib/auditLog";
|
|
65
|
+
export { resetMetrics, incrementCounter, observeHistogram, registerGaugeCallback, serializeMetrics, closeMetricsQueues } from "./lib/metrics";
|
|
66
|
+
export type { AuditLogEntry, AuditLogOptions, AuditLogQuery } from "./lib/auditLog";
|
|
46
67
|
export { sqliteAuthAdapter, setSqliteDb, startSqliteCleanup } from "./adapters/sqliteAuth";
|
|
47
68
|
export { memoryAuthAdapter, clearMemoryStore } from "./adapters/memoryAuth";
|
|
48
69
|
export { setUserRoles, addUserRole, removeUserRole, getTenantRoles, setTenantRoles, addTenantRole, removeTenantRole } from "./lib/roles";
|
|
@@ -50,7 +71,28 @@ export type { AuthAdapter, OAuthProfile, WebAuthnCredential } from "./lib/authAd
|
|
|
50
71
|
export type { OAuthProviderConfig } from "./lib/oauth";
|
|
51
72
|
export { websocket, createWsUpgradeHandler } from "./ws/index";
|
|
52
73
|
export type { SocketData } from "./ws/index";
|
|
53
|
-
export { publish, subscribe, unsubscribe, getSubscriptions, handleRoomActions, getRooms, getRoomSubscribers } from "./lib/ws";
|
|
74
|
+
export { publish, subscribe, unsubscribe, getSubscriptions, handleRoomActions, getRooms, getRoomSubscribers, setPresenceEnabled } from "./lib/ws";
|
|
75
|
+
export { registerSocket, deregisterSocket, handlePong, startHeartbeat, stopHeartbeat, clearHeartbeatState } from "./lib/wsHeartbeat";
|
|
76
|
+
export type { HeartbeatConfig } from "./lib/wsHeartbeat";
|
|
77
|
+
export { trackSocket, untrackSocket, addPresence, removePresence, cleanupPresence, getRoomPresence, getUserPresence, clearPresenceStore } from "./lib/wsPresence";
|
|
78
|
+
export { persistMessage, getMessageHistory, configureRoom, setWsMessageStore, setWsMessageDefaults, clearWsMessageMemoryStore } from "./lib/wsMessages";
|
|
79
|
+
export type { StoredMessage, WsMessageStore, WsMessageDefaults, RoomPersistenceConfig } from "./lib/wsMessages";
|
|
54
80
|
export { createTenant, deleteTenant, getTenant, listTenants } from "./lib/tenant";
|
|
55
81
|
export type { TenantInfo, CreateTenantOptions } from "./lib/tenant";
|
|
56
82
|
export { invalidateTenantCache } from "./middleware/tenant";
|
|
83
|
+
export { createGroup, deleteGroup, getGroup, listGroups, updateGroup, addGroupMember, updateGroupMembership, removeGroupMember, getGroupMembers, getUserGroups, getEffectiveRoles, } from "./lib/groups";
|
|
84
|
+
export type { GroupRecord, GroupMembershipRecord, PaginationOpts, PaginatedResult } from "./lib/groups";
|
|
85
|
+
export type { GroupsConfig, GroupsManagementConfig } from "./routes/groups";
|
|
86
|
+
export { offsetParams, parseOffsetParams, paginatedResponse, cursorParams, parseCursorParams, cursorResponse, maybeSignCursor, } from "./lib/pagination";
|
|
87
|
+
export type { OffsetParamDefaults, ParsedOffsetParams, CursorParamDefaults, ParsedCursorParams, CursorResult, } from "./lib/pagination";
|
|
88
|
+
export { handleUpload } from "./middleware/upload";
|
|
89
|
+
export type { UploadMiddlewareOptions } from "./middleware/upload";
|
|
90
|
+
export { parseUpload, setStorageAdapter, getStorageAdapter, setUploadConfig, getUploadConfig } from "./lib/upload";
|
|
91
|
+
export type { UploadOpts } from "./lib/upload";
|
|
92
|
+
export type { StorageAdapter, UploadResult } from "./lib/storageAdapter";
|
|
93
|
+
export type { UploadConfig, PresignedUrlConfig } from "./app";
|
|
94
|
+
export { memoryStorage, clearMemoryUploadStore } from "./adapters/memoryStorage";
|
|
95
|
+
export { localStorage } from "./adapters/localStorage";
|
|
96
|
+
export type { LocalStorageConfig } from "./adapters/localStorage";
|
|
97
|
+
export { s3Storage } from "./adapters/s3Storage";
|
|
98
|
+
export type { S3StorageConfig } from "./adapters/s3Storage";
|
package/dist/index.js
CHANGED
|
@@ -6,19 +6,24 @@ export { appConnection, authConnection, mongoose, connectMongo, connectAuthMongo
|
|
|
6
6
|
export { connectRedis, disconnectRedis, getRedis } from "./lib/redis";
|
|
7
7
|
// Lib utilities
|
|
8
8
|
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";
|
|
9
|
+
export { HttpError, ValidationError } from "./lib/HttpError";
|
|
10
|
+
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
11
|
export { createRouter } from "./lib/context";
|
|
12
|
-
export { createRoute, withSecurity, registerSchema, registerSchemas } from "./lib/createRoute";
|
|
12
|
+
export { createRoute, withSecurity, registerSchema, registerSchemas, setVersionPrefix, clearVersionPrefix } from "./lib/createRoute";
|
|
13
|
+
export { stripUnreferencedSchemas } from "./lib/stripUnreferencedSchemas";
|
|
13
14
|
export { zodToMongoose } from "./lib/zodToMongoose";
|
|
14
15
|
export { createDtoMapper } from "./lib/createDtoMapper";
|
|
16
|
+
export { defaultValidationErrorFormatter } from "./lib/context";
|
|
15
17
|
export { signToken, verifyToken } from "./lib/jwt";
|
|
16
18
|
export { log } from "./lib/logger";
|
|
17
19
|
export { createResetToken, consumeResetToken, setPasswordResetStore } from "./lib/resetPassword";
|
|
20
|
+
export { createDeletionCancelToken, consumeDeletionCancelToken, setDeletionCancelTokenStore } from "./lib/deletionCancelToken";
|
|
18
21
|
export { timingSafeEqual, sha256 } from "./lib/crypto";
|
|
22
|
+
export { hmacSign, hmacVerify, signCookieValue, verifyCookieValue, signCursor, verifyCursor, createPresignedUrl, verifyPresignedUrl } from "./lib/signing";
|
|
23
|
+
export { idempotent, setIdempotencyStore, clearIdempotencyMemoryStore } from "./lib/idempotency";
|
|
19
24
|
export { getClientIp, setTrustProxy } from "./lib/clientIp";
|
|
20
25
|
export { storeOAuthCode, consumeOAuthCode, setOAuthCodeStore } from "./lib/oauthCode";
|
|
21
|
-
export { createSession, getSession, deleteSession, getUserSessions, getActiveSessionCount, evictOldestSession, updateSessionLastActive, setSessionStore, deleteUserSessions, setRefreshToken, getSessionByRefreshToken, rotateRefreshToken } from "./lib/session";
|
|
26
|
+
export { createSession, getSession, deleteSession, getUserSessions, getActiveSessionCount, evictOldestSession, updateSessionLastActive, setSessionStore, deleteUserSessions, setRefreshToken, getSessionByRefreshToken, rotateRefreshToken, getSessionFingerprint, setSessionFingerprint } from "./lib/session";
|
|
22
27
|
export { createVerificationToken, getVerificationToken, deleteVerificationToken } from "./lib/emailVerification";
|
|
23
28
|
export { createMfaChallenge, consumeMfaChallenge, replaceMfaChallengeOtp, setMfaChallengeStore, createWebAuthnRegistrationChallenge, consumeWebAuthnRegistrationChallenge, clearMemoryMfaChallenges } from "./lib/mfaChallenge";
|
|
24
29
|
export { bustAuthLimit, trackAttempt, isLimited, clearMemoryRateLimitStore } from "./lib/authRateLimit";
|
|
@@ -31,17 +36,42 @@ export { rateLimit } from "./middleware/rateLimit";
|
|
|
31
36
|
export { userAuth } from "./middleware/userAuth";
|
|
32
37
|
export { requireRole } from "./middleware/requireRole";
|
|
33
38
|
export { requireVerifiedEmail } from "./middleware/requireVerifiedEmail";
|
|
39
|
+
export { requireMfaSetup } from "./middleware/requireMfaSetup";
|
|
34
40
|
export { csrfProtection, refreshCsrfToken, clearCsrfToken } from "./middleware/csrf";
|
|
35
41
|
export { cacheResponse, bustCache, bustCachePattern, setCacheStore, getCacheModel } from "./middleware/cacheResponse";
|
|
42
|
+
export { webhookAuth } from "./middleware/webhookAuth";
|
|
43
|
+
export { requireSignedRequest } from "./middleware/requestSigning";
|
|
44
|
+
export { auditLog } from "./middleware/auditLog";
|
|
45
|
+
export { requestId } from "./middleware/requestId";
|
|
46
|
+
export { requestLogger } from "./middleware/requestLogger";
|
|
47
|
+
export { metricsCollector } from "./middleware/metrics";
|
|
36
48
|
// Lib utilities (bot protection)
|
|
37
49
|
export { buildFingerprint } from "./lib/fingerprint";
|
|
50
|
+
export { logAuditEntry, getAuditLogs, clearAuditLogMemoryStore } from "./lib/auditLog";
|
|
51
|
+
export { resetMetrics, incrementCounter, observeHistogram, registerGaugeCallback, serializeMetrics, closeMetricsQueues } from "./lib/metrics";
|
|
38
52
|
// Models
|
|
39
53
|
export { sqliteAuthAdapter, setSqliteDb, startSqliteCleanup } from "./adapters/sqliteAuth";
|
|
40
54
|
export { memoryAuthAdapter, clearMemoryStore } from "./adapters/memoryAuth";
|
|
41
55
|
export { setUserRoles, addUserRole, removeUserRole, getTenantRoles, setTenantRoles, addTenantRole, removeTenantRole } from "./lib/roles";
|
|
42
56
|
// WebSocket
|
|
43
57
|
export { websocket, createWsUpgradeHandler } from "./ws/index";
|
|
44
|
-
export { publish, subscribe, unsubscribe, getSubscriptions, handleRoomActions, getRooms, getRoomSubscribers } from "./lib/ws";
|
|
58
|
+
export { publish, subscribe, unsubscribe, getSubscriptions, handleRoomActions, getRooms, getRoomSubscribers, setPresenceEnabled } from "./lib/ws";
|
|
59
|
+
// WebSocket — Heartbeat
|
|
60
|
+
export { registerSocket, deregisterSocket, handlePong, startHeartbeat, stopHeartbeat, clearHeartbeatState } from "./lib/wsHeartbeat";
|
|
61
|
+
// WebSocket — Presence
|
|
62
|
+
export { trackSocket, untrackSocket, addPresence, removePresence, cleanupPresence, getRoomPresence, getUserPresence, clearPresenceStore } from "./lib/wsPresence";
|
|
63
|
+
// WebSocket — Message Persistence
|
|
64
|
+
export { persistMessage, getMessageHistory, configureRoom, setWsMessageStore, setWsMessageDefaults, clearWsMessageMemoryStore } from "./lib/wsMessages";
|
|
45
65
|
// Tenancy
|
|
46
66
|
export { createTenant, deleteTenant, getTenant, listTenants } from "./lib/tenant";
|
|
47
67
|
export { invalidateTenantCache } from "./middleware/tenant";
|
|
68
|
+
// Groups
|
|
69
|
+
export { createGroup, deleteGroup, getGroup, listGroups, updateGroup, addGroupMember, updateGroupMembership, removeGroupMember, getGroupMembers, getUserGroups, getEffectiveRoles, } from "./lib/groups";
|
|
70
|
+
// Pagination helpers
|
|
71
|
+
export { offsetParams, parseOffsetParams, paginatedResponse, cursorParams, parseCursorParams, cursorResponse, maybeSignCursor, } from "./lib/pagination";
|
|
72
|
+
// Upload
|
|
73
|
+
export { handleUpload } from "./middleware/upload";
|
|
74
|
+
export { parseUpload, setStorageAdapter, getStorageAdapter, setUploadConfig, getUploadConfig } from "./lib/upload";
|
|
75
|
+
export { memoryStorage, clearMemoryUploadStore } from "./adapters/memoryStorage";
|
|
76
|
+
export { localStorage } from "./adapters/localStorage";
|
|
77
|
+
export { s3Storage } from "./adapters/s3Storage";
|
package/dist/lib/HttpError.d.ts
CHANGED
|
@@ -2,3 +2,8 @@ export declare class HttpError extends Error {
|
|
|
2
2
|
status: number;
|
|
3
3
|
constructor(status: number, message: string);
|
|
4
4
|
}
|
|
5
|
+
import type { ZodIssue } from "zod";
|
|
6
|
+
export declare class ValidationError extends HttpError {
|
|
7
|
+
readonly issues: ZodIssue[];
|
|
8
|
+
constructor(issues: ZodIssue[]);
|
|
9
|
+
}
|
package/dist/lib/HttpError.js
CHANGED
package/dist/lib/appConfig.d.ts
CHANGED
|
@@ -102,6 +102,8 @@ export interface MfaConfig {
|
|
|
102
102
|
emailOtp?: MfaEmailOtpConfig;
|
|
103
103
|
/** WebAuthn/FIDO2 configuration. When set, enables security key MFA routes. */
|
|
104
104
|
webauthn?: MfaWebAuthnConfig;
|
|
105
|
+
/** When true, authenticated users must complete MFA setup before accessing non-auth endpoints. Default: false. */
|
|
106
|
+
required?: boolean;
|
|
105
107
|
}
|
|
106
108
|
export declare const setMfaConfig: (config: MfaConfig | null) => void;
|
|
107
109
|
export declare const getMfaConfig: () => MfaConfig | null;
|
|
@@ -114,5 +116,47 @@ export declare const getMfaChallengeTtl: () => number;
|
|
|
114
116
|
export declare const getMfaEmailOtpConfig: () => MfaEmailOtpConfig | null;
|
|
115
117
|
export declare const getMfaEmailOtpCodeLength: () => number;
|
|
116
118
|
export declare const getMfaWebAuthnConfig: () => MfaWebAuthnConfig | null;
|
|
119
|
+
export declare const getMfaRequired: () => boolean;
|
|
117
120
|
export declare const setCsrfEnabled: (v: boolean) => void;
|
|
118
121
|
export declare const getCsrfEnabled: () => boolean;
|
|
122
|
+
export interface SigningConfig {
|
|
123
|
+
/**
|
|
124
|
+
* HMAC secret. Defaults to JWT_SECRET_DEV/JWT_SECRET_PROD env var if omitted.
|
|
125
|
+
* Pass string[] to support key rotation — first element signs, all elements verify.
|
|
126
|
+
*/
|
|
127
|
+
secret?: string | string[];
|
|
128
|
+
/** Sign/verify cookie values set via exported helpers. Default: false. */
|
|
129
|
+
cookies?: boolean;
|
|
130
|
+
/** Sign pagination cursor tokens to prevent client tampering. Default: false. */
|
|
131
|
+
cursors?: boolean;
|
|
132
|
+
/** HMAC-based stateless presigned URLs (no DB lookup). Default: false. */
|
|
133
|
+
presignedUrls?: boolean | {
|
|
134
|
+
defaultExpiry?: number;
|
|
135
|
+
};
|
|
136
|
+
/** Require clients to HMAC-sign requests (method+path+timestamp+body). Default: false. */
|
|
137
|
+
requestSigning?: boolean | {
|
|
138
|
+
tolerance?: number;
|
|
139
|
+
header?: string;
|
|
140
|
+
timestampHeader?: string;
|
|
141
|
+
};
|
|
142
|
+
/** Hash idempotency keys before storage. Default: false. */
|
|
143
|
+
idempotencyKeys?: boolean;
|
|
144
|
+
/** Bind sessions to client IP+UA fingerprint. Default: false. */
|
|
145
|
+
sessionBinding?: boolean | {
|
|
146
|
+
fields?: Array<"ip" | "ua" | "accept-language">;
|
|
147
|
+
/**
|
|
148
|
+
* What to do when fingerprint doesn't match.
|
|
149
|
+
* - "unauthenticate": treat as logged-out (default — graceful but masks attacks)
|
|
150
|
+
* - "reject": return 401 (strict — recommended for security-conscious apps)
|
|
151
|
+
* - "log-only": allow through but log the mismatch (useful during rollout)
|
|
152
|
+
*/
|
|
153
|
+
onMismatch?: "unauthenticate" | "reject" | "log-only";
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
export declare const setSigningConfig: (config: SigningConfig | null) => void;
|
|
157
|
+
export declare const getSigningConfig: () => SigningConfig | null;
|
|
158
|
+
/**
|
|
159
|
+
* Returns the active signing secret: signing.secret → JWT_SECRET_PROD/DEV env var.
|
|
160
|
+
* Returns null when neither is configured — callers must handle this gracefully.
|
|
161
|
+
*/
|
|
162
|
+
export declare const getSigningSecret: () => string | string[] | null;
|
package/dist/lib/appConfig.js
CHANGED
|
@@ -59,9 +59,25 @@ export const getMfaChallengeTtl = () => _mfaConfig?.challengeTtlSeconds ?? 300;
|
|
|
59
59
|
export const getMfaEmailOtpConfig = () => _mfaConfig?.emailOtp ?? null;
|
|
60
60
|
export const getMfaEmailOtpCodeLength = () => _mfaConfig?.emailOtp?.codeLength ?? 6;
|
|
61
61
|
export const getMfaWebAuthnConfig = () => _mfaConfig?.webauthn ?? null;
|
|
62
|
+
export const getMfaRequired = () => _mfaConfig?.required ?? false;
|
|
62
63
|
// ---------------------------------------------------------------------------
|
|
63
64
|
// CSRF config
|
|
64
65
|
// ---------------------------------------------------------------------------
|
|
65
66
|
let _csrfEnabled = false;
|
|
66
67
|
export const setCsrfEnabled = (v) => { _csrfEnabled = v; };
|
|
67
68
|
export const getCsrfEnabled = () => _csrfEnabled;
|
|
69
|
+
let _signingConfig = null;
|
|
70
|
+
export const setSigningConfig = (config) => { _signingConfig = config; };
|
|
71
|
+
export const getSigningConfig = () => _signingConfig;
|
|
72
|
+
/**
|
|
73
|
+
* Returns the active signing secret: signing.secret → JWT_SECRET_PROD/DEV env var.
|
|
74
|
+
* Returns null when neither is configured — callers must handle this gracefully.
|
|
75
|
+
*/
|
|
76
|
+
export const getSigningSecret = () => {
|
|
77
|
+
if (_signingConfig?.secret)
|
|
78
|
+
return _signingConfig.secret;
|
|
79
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
80
|
+
const envKey = isProd ? "JWT_SECRET_PROD" : "JWT_SECRET_DEV";
|
|
81
|
+
const rawSecret = process.env[envKey];
|
|
82
|
+
return rawSecret ?? null;
|
|
83
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
export interface AuditLogEntry {
|
|
3
|
+
id: string;
|
|
4
|
+
userId: string | null;
|
|
5
|
+
sessionId: string | null;
|
|
6
|
+
tenantId: string | null;
|
|
7
|
+
method: string;
|
|
8
|
+
path: string;
|
|
9
|
+
status: number;
|
|
10
|
+
ip: string | null;
|
|
11
|
+
userAgent: string | null;
|
|
12
|
+
action?: string;
|
|
13
|
+
resource?: string;
|
|
14
|
+
resourceId?: string;
|
|
15
|
+
meta?: Record<string, unknown>;
|
|
16
|
+
requestId?: string;
|
|
17
|
+
/** ISO 8601 string across all backends. */
|
|
18
|
+
createdAt: string;
|
|
19
|
+
/** MongoDB TTL only — silently ignored by SQLite and memory stores. */
|
|
20
|
+
expiresAt?: Date;
|
|
21
|
+
}
|
|
22
|
+
export type AuditLogStore = "mongo" | "sqlite" | "memory";
|
|
23
|
+
export interface AuditLogOptions {
|
|
24
|
+
store: AuditLogStore;
|
|
25
|
+
/** Required when `store === "sqlite"`. */
|
|
26
|
+
db?: Database;
|
|
27
|
+
}
|
|
28
|
+
export interface AuditLogQuery {
|
|
29
|
+
userId?: string;
|
|
30
|
+
tenantId?: string;
|
|
31
|
+
after?: Date | string;
|
|
32
|
+
before?: Date | string;
|
|
33
|
+
/** Default 50, max 200. */
|
|
34
|
+
limit?: number;
|
|
35
|
+
/** Default 0. */
|
|
36
|
+
offset?: number;
|
|
37
|
+
}
|
|
38
|
+
export declare function clearAuditLogMemoryStore(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Persist an audit log entry to the configured store.
|
|
41
|
+
* Errors are caught internally — this function never throws, to ensure
|
|
42
|
+
* storage failures never fail the HTTP request.
|
|
43
|
+
*/
|
|
44
|
+
export declare function logAuditEntry(entry: AuditLogEntry, options: AuditLogOptions): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Query audit log entries from the configured store.
|
|
47
|
+
* Returns `{ items, total }` where `total` is the filtered count before pagination.
|
|
48
|
+
*/
|
|
49
|
+
export declare function getAuditLogs(query: AuditLogQuery, options: AuditLogOptions): Promise<{
|
|
50
|
+
items: AuditLogEntry[];
|
|
51
|
+
total: number;
|
|
52
|
+
}>;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory store
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
let _auditLogs = [];
|
|
5
|
+
export function clearAuditLogMemoryStore() {
|
|
6
|
+
_auditLogs = [];
|
|
7
|
+
}
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// SQLite helpers
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
function ensureSqliteTable(db) {
|
|
12
|
+
// No module-level flag — CREATE IF NOT EXISTS is idempotent and cheap.
|
|
13
|
+
// A flag would break when multiple Database instances are used (e.g. in tests).
|
|
14
|
+
db.run(`
|
|
15
|
+
CREATE TABLE IF NOT EXISTS audit_logs (
|
|
16
|
+
id TEXT PRIMARY KEY,
|
|
17
|
+
userId TEXT,
|
|
18
|
+
sessionId TEXT,
|
|
19
|
+
tenantId TEXT,
|
|
20
|
+
method TEXT NOT NULL,
|
|
21
|
+
path TEXT NOT NULL,
|
|
22
|
+
status INTEGER NOT NULL,
|
|
23
|
+
ip TEXT,
|
|
24
|
+
userAgent TEXT,
|
|
25
|
+
action TEXT,
|
|
26
|
+
resource TEXT,
|
|
27
|
+
resourceId TEXT,
|
|
28
|
+
meta TEXT,
|
|
29
|
+
createdAt TEXT NOT NULL
|
|
30
|
+
)
|
|
31
|
+
`);
|
|
32
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_al_user ON audit_logs(userId, createdAt)");
|
|
33
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_al_tenant ON audit_logs(tenantId, createdAt)");
|
|
34
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_al_path ON audit_logs(path)");
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// logAuditEntry
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
/**
|
|
40
|
+
* Persist an audit log entry to the configured store.
|
|
41
|
+
* Errors are caught internally — this function never throws, to ensure
|
|
42
|
+
* storage failures never fail the HTTP request.
|
|
43
|
+
*/
|
|
44
|
+
export async function logAuditEntry(entry, options) {
|
|
45
|
+
try {
|
|
46
|
+
if (options.store === "memory") {
|
|
47
|
+
_auditLogs.push(entry);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (options.store === "sqlite") {
|
|
51
|
+
const db = options.db;
|
|
52
|
+
if (!db)
|
|
53
|
+
throw new Error("AuditLog: store is 'sqlite' but no db instance was provided");
|
|
54
|
+
ensureSqliteTable(db);
|
|
55
|
+
db.run(`INSERT INTO audit_logs
|
|
56
|
+
(id, userId, sessionId, tenantId, method, path, status,
|
|
57
|
+
ip, userAgent, action, resource, resourceId, meta, createdAt)
|
|
58
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
59
|
+
entry.id,
|
|
60
|
+
entry.userId ?? null,
|
|
61
|
+
entry.sessionId ?? null,
|
|
62
|
+
entry.tenantId ?? null,
|
|
63
|
+
entry.method,
|
|
64
|
+
entry.path,
|
|
65
|
+
entry.status,
|
|
66
|
+
entry.ip ?? null,
|
|
67
|
+
entry.userAgent ?? null,
|
|
68
|
+
entry.action ?? null,
|
|
69
|
+
entry.resource ?? null,
|
|
70
|
+
entry.resourceId ?? null,
|
|
71
|
+
entry.meta !== undefined ? JSON.stringify(entry.meta) : null,
|
|
72
|
+
entry.createdAt,
|
|
73
|
+
]);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (options.store === "mongo") {
|
|
77
|
+
// Lazy import to avoid bundling mongoose when not used
|
|
78
|
+
const { AuditLog } = await import("../models/AuditLog");
|
|
79
|
+
await AuditLog.create({
|
|
80
|
+
...entry,
|
|
81
|
+
createdAt: new Date(entry.createdAt),
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
console.error("[auditLog] failed to write entry:", err);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// getAuditLogs
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
/**
|
|
94
|
+
* Query audit log entries from the configured store.
|
|
95
|
+
* Returns `{ items, total }` where `total` is the filtered count before pagination.
|
|
96
|
+
*/
|
|
97
|
+
export async function getAuditLogs(query, options) {
|
|
98
|
+
const limit = Math.min(query.limit ?? 50, 200);
|
|
99
|
+
const offset = query.offset ?? 0;
|
|
100
|
+
const after = query.after ? new Date(query.after).toISOString() : undefined;
|
|
101
|
+
const before = query.before ? new Date(query.before).toISOString() : undefined;
|
|
102
|
+
// --- Memory ---
|
|
103
|
+
if (options.store === "memory") {
|
|
104
|
+
let filtered = _auditLogs.slice();
|
|
105
|
+
if (query.userId !== undefined)
|
|
106
|
+
filtered = filtered.filter(e => e.userId === query.userId);
|
|
107
|
+
if (query.tenantId !== undefined)
|
|
108
|
+
filtered = filtered.filter(e => e.tenantId === query.tenantId);
|
|
109
|
+
if (after)
|
|
110
|
+
filtered = filtered.filter(e => e.createdAt >= after);
|
|
111
|
+
if (before)
|
|
112
|
+
filtered = filtered.filter(e => e.createdAt < before);
|
|
113
|
+
return { items: filtered.slice(offset, offset + limit), total: filtered.length };
|
|
114
|
+
}
|
|
115
|
+
// --- SQLite ---
|
|
116
|
+
if (options.store === "sqlite") {
|
|
117
|
+
const db = options.db;
|
|
118
|
+
if (!db)
|
|
119
|
+
throw new Error("AuditLog: store is 'sqlite' but no db instance was provided");
|
|
120
|
+
ensureSqliteTable(db);
|
|
121
|
+
const conditions = [];
|
|
122
|
+
const params = [];
|
|
123
|
+
if (query.userId !== undefined) {
|
|
124
|
+
conditions.push("userId = ?");
|
|
125
|
+
params.push(query.userId);
|
|
126
|
+
}
|
|
127
|
+
if (query.tenantId !== undefined) {
|
|
128
|
+
conditions.push("tenantId = ?");
|
|
129
|
+
params.push(query.tenantId);
|
|
130
|
+
}
|
|
131
|
+
if (after) {
|
|
132
|
+
conditions.push("createdAt >= ?");
|
|
133
|
+
params.push(after);
|
|
134
|
+
}
|
|
135
|
+
if (before) {
|
|
136
|
+
conditions.push("createdAt < ?");
|
|
137
|
+
params.push(before);
|
|
138
|
+
}
|
|
139
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
140
|
+
const { count } = db.query(`SELECT COUNT(*) as count FROM audit_logs ${where}`).get(...params) ?? { count: 0 };
|
|
141
|
+
const rows = db.query(`SELECT * FROM audit_logs ${where} ORDER BY createdAt DESC LIMIT ? OFFSET ?`).all(...params, limit, offset);
|
|
142
|
+
const items = rows.map(row => ({
|
|
143
|
+
id: row.id,
|
|
144
|
+
userId: row.userId ?? null,
|
|
145
|
+
sessionId: row.sessionId ?? null,
|
|
146
|
+
tenantId: row.tenantId ?? null,
|
|
147
|
+
method: row.method,
|
|
148
|
+
path: row.path,
|
|
149
|
+
status: row.status,
|
|
150
|
+
ip: row.ip ?? null,
|
|
151
|
+
userAgent: row.userAgent ?? null,
|
|
152
|
+
action: row.action ?? undefined,
|
|
153
|
+
resource: row.resource ?? undefined,
|
|
154
|
+
resourceId: row.resourceId ?? undefined,
|
|
155
|
+
meta: row.meta ? JSON.parse(row.meta) : undefined,
|
|
156
|
+
createdAt: row.createdAt,
|
|
157
|
+
}));
|
|
158
|
+
return { items, total: count };
|
|
159
|
+
}
|
|
160
|
+
// --- MongoDB ---
|
|
161
|
+
if (options.store === "mongo") {
|
|
162
|
+
const { AuditLog } = await import("../models/AuditLog");
|
|
163
|
+
const filter = {};
|
|
164
|
+
if (query.userId !== undefined)
|
|
165
|
+
filter.userId = query.userId;
|
|
166
|
+
if (query.tenantId !== undefined)
|
|
167
|
+
filter.tenantId = query.tenantId;
|
|
168
|
+
if (after || before) {
|
|
169
|
+
filter.createdAt = {
|
|
170
|
+
...(after ? { $gte: new Date(after) } : {}),
|
|
171
|
+
...(before ? { $lt: new Date(before) } : {}),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const [total, docs] = await Promise.all([
|
|
175
|
+
AuditLog.countDocuments(filter),
|
|
176
|
+
AuditLog.find(filter)
|
|
177
|
+
.sort({ createdAt: -1 })
|
|
178
|
+
.skip(offset)
|
|
179
|
+
.limit(limit)
|
|
180
|
+
.lean(),
|
|
181
|
+
]);
|
|
182
|
+
const items = docs.map(doc => ({
|
|
183
|
+
id: doc.id,
|
|
184
|
+
userId: doc.userId ?? null,
|
|
185
|
+
sessionId: doc.sessionId ?? null,
|
|
186
|
+
tenantId: doc.tenantId ?? null,
|
|
187
|
+
method: doc.method,
|
|
188
|
+
path: doc.path,
|
|
189
|
+
status: doc.status,
|
|
190
|
+
ip: doc.ip ?? null,
|
|
191
|
+
userAgent: doc.userAgent ?? null,
|
|
192
|
+
action: doc.action,
|
|
193
|
+
resource: doc.resource,
|
|
194
|
+
resourceId: doc.resourceId,
|
|
195
|
+
meta: doc.meta,
|
|
196
|
+
createdAt: doc.createdAt.toISOString(),
|
|
197
|
+
}));
|
|
198
|
+
return { items, total };
|
|
199
|
+
}
|
|
200
|
+
return { items: [], total: 0 };
|
|
201
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { GroupRecord, GroupMembershipRecord, PaginationOpts, PaginatedResult } from "./groups";
|
|
2
|
+
export type { GroupRecord, GroupMembershipRecord, PaginationOpts, PaginatedResult };
|
|
1
3
|
export interface OAuthProfile {
|
|
2
4
|
email?: string;
|
|
3
5
|
name?: string;
|
|
@@ -102,6 +104,73 @@ export interface AuthAdapter {
|
|
|
102
104
|
updateWebAuthnCredentialSignCount?(userId: string, credentialId: string, signCount: number): Promise<void>;
|
|
103
105
|
/** Optional. Find the user who owns a WebAuthn credential. Returns userId or null. Used for cross-user uniqueness checks. */
|
|
104
106
|
findUserByWebAuthnCredentialId?(credentialId: string): Promise<string | null>;
|
|
107
|
+
/**
|
|
108
|
+
* Create a new group. Returns the new group's id.
|
|
109
|
+
* The name must be a slug (/^[a-z0-9_-]+$/) and unique within its scope.
|
|
110
|
+
* tenantId: null = app-wide group, string = tenant-scoped group.
|
|
111
|
+
*/
|
|
112
|
+
createGroup?(group: Omit<GroupRecord, "id" | "createdAt" | "updatedAt">): Promise<{
|
|
113
|
+
id: string;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Delete a group and cascade-delete all its memberships.
|
|
117
|
+
* Cascade behavior is adapter-specific (MongoDB: manual deleteMany, SQLite: ON DELETE CASCADE).
|
|
118
|
+
*/
|
|
119
|
+
deleteGroup?(groupId: string): Promise<void>;
|
|
120
|
+
/** Get a group by ID. Returns null if not found. */
|
|
121
|
+
getGroup?(groupId: string): Promise<GroupRecord | null>;
|
|
122
|
+
/**
|
|
123
|
+
* List groups scoped to a tenant (tenantId string) or app-wide (tenantId null).
|
|
124
|
+
* Results are paginated (default limit 50, max 200).
|
|
125
|
+
*/
|
|
126
|
+
listGroups?(tenantId: string | null, opts?: PaginationOpts): Promise<PaginatedResult<GroupRecord>>;
|
|
127
|
+
/**
|
|
128
|
+
* Update mutable group fields: name, displayName, description, roles.
|
|
129
|
+
* tenantId is intentionally excluded — it is immutable after creation.
|
|
130
|
+
*/
|
|
131
|
+
updateGroup?(groupId: string, updates: Partial<Pick<GroupRecord, "roles" | "name" | "displayName" | "description">>): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Add a user to a group with optional per-membership roles.
|
|
134
|
+
*
|
|
135
|
+
* CONTRACT: throws if the user is already a member (unique constraint violation).
|
|
136
|
+
* All adapters must surface this as a thrown error, not a silent no-op.
|
|
137
|
+
* Use updateGroupMembership to change roles on an existing membership.
|
|
138
|
+
*/
|
|
139
|
+
addGroupMember?(groupId: string, userId: string, roles?: string[]): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Update the per-membership roles for an existing group member.
|
|
142
|
+
* Replaces the member's roles[] in place (not additive).
|
|
143
|
+
* No updatedAt is tracked — intentional, see GroupMembershipRecord.
|
|
144
|
+
*/
|
|
145
|
+
updateGroupMembership?(groupId: string, userId: string, roles: string[]): Promise<void>;
|
|
146
|
+
/** Remove a user from a group. No-op if the user is not a member. */
|
|
147
|
+
removeGroupMember?(groupId: string, userId: string): Promise<void>;
|
|
148
|
+
/** List members of a group with their per-membership roles. Paginated. */
|
|
149
|
+
getGroupMembers?(groupId: string, opts?: PaginationOpts): Promise<PaginatedResult<{
|
|
150
|
+
userId: string;
|
|
151
|
+
roles: string[];
|
|
152
|
+
}>>;
|
|
153
|
+
/**
|
|
154
|
+
* List all groups a user belongs to in the given scope, with their per-membership roles.
|
|
155
|
+
* tenantId = null → app-wide groups; tenantId = string → tenant-scoped groups.
|
|
156
|
+
*/
|
|
157
|
+
getUserGroups?(userId: string, tenantId: string | null): Promise<Array<{
|
|
158
|
+
group: GroupRecord;
|
|
159
|
+
membershipRoles: string[];
|
|
160
|
+
}>>;
|
|
161
|
+
/**
|
|
162
|
+
* Return all roles a user effectively has in the given scope, combining:
|
|
163
|
+
* 1. Direct roles (app-wide or tenant-scoped)
|
|
164
|
+
* 2. Group baseline roles (from all groups the user belongs to in that scope)
|
|
165
|
+
* 3. Per-membership roles (user-specific extras within each group)
|
|
166
|
+
*
|
|
167
|
+
* SCOPE CONTRACT (matches requireRole behavior):
|
|
168
|
+
* - tenantId = null → app-wide direct roles + app-wide group roles only
|
|
169
|
+
* - tenantId = string → tenant-scoped direct roles + tenant-scoped group roles only
|
|
170
|
+
*
|
|
171
|
+
* Tenant-scoped group roles NEVER satisfy app-wide role checks and vice versa.
|
|
172
|
+
*/
|
|
173
|
+
getEffectiveRoles?(userId: string, tenantId: string | null): Promise<string[]>;
|
|
105
174
|
}
|
|
106
175
|
export declare const setAuthAdapter: (adapter: AuthAdapter) => void;
|
|
107
176
|
export declare const getAuthAdapter: () => AuthAdapter;
|
package/dist/lib/constants.d.ts
CHANGED
|
@@ -4,3 +4,7 @@ export declare const COOKIE_REFRESH_TOKEN = "refresh_token";
|
|
|
4
4
|
export declare const HEADER_REFRESH_TOKEN = "x-refresh-token";
|
|
5
5
|
export declare const COOKIE_CSRF_TOKEN = "csrf_token";
|
|
6
6
|
export declare const HEADER_CSRF_TOKEN = "x-csrf-token";
|
|
7
|
+
export declare const HEADER_REQUEST_ID = "x-request-id";
|
|
8
|
+
export declare const HEADER_IDEMPOTENCY_KEY = "idempotency-key";
|
|
9
|
+
export declare const HEADER_SIGNATURE = "x-signature";
|
|
10
|
+
export declare const HEADER_TIMESTAMP = "x-timestamp";
|
package/dist/lib/constants.js
CHANGED
|
@@ -4,3 +4,7 @@ export const COOKIE_REFRESH_TOKEN = "refresh_token";
|
|
|
4
4
|
export const HEADER_REFRESH_TOKEN = "x-refresh-token";
|
|
5
5
|
export const COOKIE_CSRF_TOKEN = "csrf_token";
|
|
6
6
|
export const HEADER_CSRF_TOKEN = "x-csrf-token";
|
|
7
|
+
export const HEADER_REQUEST_ID = "x-request-id";
|
|
8
|
+
export const HEADER_IDEMPOTENCY_KEY = "idempotency-key";
|
|
9
|
+
export const HEADER_SIGNATURE = "x-signature";
|
|
10
|
+
export const HEADER_TIMESTAMP = "x-timestamp";
|