@eminuckan/spine 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/LICENSE +21 -0
- package/README.md +425 -0
- package/dist/api-client/index.d.ts +3 -0
- package/dist/api-client/index.js +4 -0
- package/dist/api-client/server.d.ts +4 -0
- package/dist/api-client/server.js +5 -0
- package/dist/api-client-Ftxqm3Ep.js +212 -0
- package/dist/api-client-Ftxqm3Ep.js.map +1 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +0 -0
- package/dist/auth/server.d.ts +3 -0
- package/dist/auth/server.js +6 -0
- package/dist/auth.server-C979TR6W.js +724 -0
- package/dist/auth.server-C979TR6W.js.map +1 -0
- package/dist/auth.server-DU-x2LPA.js +5 -0
- package/dist/identity/index.d.ts +4 -0
- package/dist/identity/index.js +3 -0
- package/dist/identity/server.d.ts +4 -0
- package/dist/identity/server.js +4 -0
- package/dist/identity-CFa1txoj.js +235 -0
- package/dist/identity-CFa1txoj.js.map +1 -0
- package/dist/index-BIJOC8Fb.d.ts +272 -0
- package/dist/index-BIJOC8Fb.d.ts.map +1 -0
- package/dist/index-Bt9XE6gj.d.ts +104 -0
- package/dist/index-Bt9XE6gj.d.ts.map +1 -0
- package/dist/index-C2hGpzGr.d.ts +74 -0
- package/dist/index-C2hGpzGr.d.ts.map +1 -0
- package/dist/index-CfQsb3l_.d.ts +170 -0
- package/dist/index-CfQsb3l_.d.ts.map +1 -0
- package/dist/index-D6RK_5vm.d.ts +199 -0
- package/dist/index-D6RK_5vm.d.ts.map +1 -0
- package/dist/index-DrttYPAj.d.ts +30 -0
- package/dist/index-DrttYPAj.d.ts.map +1 -0
- package/dist/index-geY2ynnN.d.ts +141 -0
- package/dist/index-geY2ynnN.d.ts.map +1 -0
- package/dist/index-kr8Wk7v5.d.ts +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +10 -0
- package/dist/logging/index.d.ts +3 -0
- package/dist/logging/index.js +3 -0
- package/dist/logging-_h2mi3L9.js +118 -0
- package/dist/logging-_h2mi3L9.js.map +1 -0
- package/dist/permissions/index.d.ts +2 -0
- package/dist/permissions/index.js +3 -0
- package/dist/permissions-D5ScGGnd.js +281 -0
- package/dist/permissions-D5ScGGnd.js.map +1 -0
- package/dist/query-client/index.d.ts +2 -0
- package/dist/query-client/index.js +3 -0
- package/dist/query-client-DRPQIKHX.js +174 -0
- package/dist/query-client-DRPQIKHX.js.map +1 -0
- package/dist/react-router/index.d.ts +12 -0
- package/dist/react-router/index.js +10 -0
- package/dist/react-router/server.d.ts +18 -0
- package/dist/react-router/server.js +17 -0
- package/dist/redis-session-storage.server-DhufyPjd.js +250 -0
- package/dist/redis-session-storage.server-DhufyPjd.js.map +1 -0
- package/dist/server-BoeUiXSh.d.ts +40 -0
- package/dist/server-BoeUiXSh.d.ts.map +1 -0
- package/dist/server-C-DiVP9e.js +185 -0
- package/dist/server-C-DiVP9e.js.map +1 -0
- package/dist/server-CLbksnvg.d.ts +144 -0
- package/dist/server-CLbksnvg.d.ts.map +1 -0
- package/dist/server-CNp6gjFE.js +78 -0
- package/dist/server-CNp6gjFE.js.map +1 -0
- package/dist/server-CXGaRaiS.d.ts +256 -0
- package/dist/server-CXGaRaiS.d.ts.map +1 -0
- package/dist/server-CiSbg-9C.js +352 -0
- package/dist/server-CiSbg-9C.js.map +1 -0
- package/dist/server-DLgH3FRR.js +312 -0
- package/dist/server-DLgH3FRR.js.map +1 -0
- package/dist/server-DazqdM63.d.ts +93 -0
- package/dist/server-DazqdM63.d.ts.map +1 -0
- package/dist/server-iWm3oeCM.js +145 -0
- package/dist/server-iWm3oeCM.js.map +1 -0
- package/dist/server-zEKMDpP7.d.ts +80 -0
- package/dist/server-zEKMDpP7.d.ts.map +1 -0
- package/dist/server.d.ts +18 -0
- package/dist/server.js +17 -0
- package/dist/signalr/index.d.ts +4 -0
- package/dist/signalr/index.js +3 -0
- package/dist/signalr-BJGcXc0m.js +274 -0
- package/dist/signalr-BJGcXc0m.js.map +1 -0
- package/dist/src-D7mh9MKA.js +0 -0
- package/dist/tenant/index.d.ts +3 -0
- package/dist/tenant/index.js +3 -0
- package/dist/tenant/server.d.ts +3 -0
- package/dist/tenant/server.js +5 -0
- package/dist/tenant-C6KPaSCX.js +256 -0
- package/dist/tenant-C6KPaSCX.js.map +1 -0
- package/dist/types-BTjFzIhv.d.ts +31 -0
- package/dist/types-BTjFzIhv.d.ts.map +1 -0
- package/dist/types-DoIfDhl6.d.ts +55 -0
- package/dist/types-DoIfDhl6.d.ts.map +1 -0
- package/dist/types-DufLRY7A.d.ts +164 -0
- package/dist/types-DufLRY7A.d.ts.map +1 -0
- package/dist/types-uDrDMkCq.d.ts +93 -0
- package/dist/types-uDrDMkCq.d.ts.map +1 -0
- package/package.json +147 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { APIConfig, APILogger, CreateAPIConfigOptions, GetAccessTokenFn, GetCurrentTenantFn, RetryConfig, TokenRefreshFn } from "./index-D6RK_5vm.js";
|
|
2
|
+
import { AxiosInstance } from "axios";
|
|
3
|
+
|
|
4
|
+
//#region src/api-client/api-config.server.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* API Config Factory Options
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* API Config Factory Options
|
|
11
|
+
*/
|
|
12
|
+
interface APIConfigFactoryOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Base URL for API requests
|
|
15
|
+
*/
|
|
16
|
+
baseURL?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Default headers applied to all requests
|
|
19
|
+
*/
|
|
20
|
+
defaultHeaders?: Record<string, string>;
|
|
21
|
+
/**
|
|
22
|
+
* User agent string
|
|
23
|
+
*/
|
|
24
|
+
userAgent?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Default timeout in milliseconds
|
|
27
|
+
*/
|
|
28
|
+
timeout?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Create API Config Factory
|
|
32
|
+
*
|
|
33
|
+
* Creates a factory function that generates API configurations
|
|
34
|
+
* with the provided auth and tenant resolvers.
|
|
35
|
+
*/
|
|
36
|
+
declare function createAPIConfigFactory(getAccessToken: GetAccessTokenFn, getCurrentTenant: GetCurrentTenantFn, logger?: APILogger, factoryOptions?: APIConfigFactoryOptions): {
|
|
37
|
+
createAPIConfig: (request: Request, options?: CreateAPIConfigOptions) => Promise<APIConfig>;
|
|
38
|
+
getAPIBaseURL: () => string;
|
|
39
|
+
};
|
|
40
|
+
type APIConfigFactory = ReturnType<typeof createAPIConfigFactory>; //#endregion
|
|
41
|
+
//#region src/api-client/axios-setup.server.d.ts
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=api-config.server.d.ts.map
|
|
44
|
+
/**
|
|
45
|
+
* Axios Setup Options
|
|
46
|
+
*/
|
|
47
|
+
interface AxiosSetupOptions {
|
|
48
|
+
/**
|
|
49
|
+
* Logger instance for logging
|
|
50
|
+
*/
|
|
51
|
+
logger?: APILogger;
|
|
52
|
+
/**
|
|
53
|
+
* Token refresh function
|
|
54
|
+
*/
|
|
55
|
+
attemptTokenRefresh?: TokenRefreshFn;
|
|
56
|
+
/**
|
|
57
|
+
* Retry configuration
|
|
58
|
+
*/
|
|
59
|
+
retryConfig?: RetryConfig;
|
|
60
|
+
/**
|
|
61
|
+
* Whether to add request ID header
|
|
62
|
+
*/
|
|
63
|
+
addRequestId?: boolean;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Setup Axios interceptors for auto-generated clients
|
|
67
|
+
*
|
|
68
|
+
* Features:
|
|
69
|
+
* - Automatic token refresh on 401
|
|
70
|
+
* - Retry logic with exponential backoff
|
|
71
|
+
* - ProblemDetails error parsing
|
|
72
|
+
* - Timeout management
|
|
73
|
+
* - Comprehensive logging
|
|
74
|
+
*
|
|
75
|
+
* @param axiosInstance - The Axios instance from auto-generated client
|
|
76
|
+
* @param request - The incoming request object (for token refresh)
|
|
77
|
+
* @param options - Configuration options
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ` ypescript
|
|
81
|
+
* const config = await createAPIConfig(request);
|
|
82
|
+
* const api = new IdentityApi(config);
|
|
83
|
+
* setupAxiosInterceptors(api.axios, request, { logger, attemptTokenRefresh });
|
|
84
|
+
*
|
|
85
|
+
* // Now all API calls have automatic retry, token refresh, error handling
|
|
86
|
+
* const users = await api.getUsers(tenantId);
|
|
87
|
+
* `
|
|
88
|
+
*/
|
|
89
|
+
declare function setupAxiosInterceptors(axiosInstance: AxiosInstance, request: Request, options?: AxiosSetupOptions): void;
|
|
90
|
+
/**
|
|
91
|
+
* Create Enhanced Client Options
|
|
92
|
+
*/
|
|
93
|
+
interface CreateEnhancedClientOptions extends AxiosSetupOptions {
|
|
94
|
+
/**
|
|
95
|
+
* Whether tenant is required
|
|
96
|
+
*/
|
|
97
|
+
requireTenant?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Whether to include auth
|
|
100
|
+
*/
|
|
101
|
+
includeAuth?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Explicit tenant ID override
|
|
104
|
+
*/
|
|
105
|
+
tenantId?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Custom headers
|
|
108
|
+
*/
|
|
109
|
+
customHeaders?: Record<string, string>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Helper to create and setup an API client in one call
|
|
113
|
+
*
|
|
114
|
+
* @param request - The incoming request object
|
|
115
|
+
* @param ClientClass - The auto-generated API client class
|
|
116
|
+
* @param createAPIConfig - Function to create API configuration
|
|
117
|
+
* @param ConfigurationClass - The Configuration class from generated API
|
|
118
|
+
* @param options - Configuration options
|
|
119
|
+
* @returns Configured API client instance with interceptors
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ` ypescript
|
|
123
|
+
* import { IdentityApi, Configuration } from './generated-api';
|
|
124
|
+
*
|
|
125
|
+
* const { client: api, tenantId } = await createEnhancedClient(
|
|
126
|
+
* request,
|
|
127
|
+
* IdentityApi,
|
|
128
|
+
* createAPIConfig,
|
|
129
|
+
* Configuration,
|
|
130
|
+
* { logger, attemptTokenRefresh }
|
|
131
|
+
* );
|
|
132
|
+
* const users = await api.getUsers(tenantId);
|
|
133
|
+
* `
|
|
134
|
+
*/
|
|
135
|
+
declare function createEnhancedClient<T>(request: Request, ClientClass: new (configuration?: any, basePath?: string, axios?: AxiosInstance) => T, createAPIConfig: (request: Request, options?: any) => Promise<any>, ConfigurationClass: new (params?: any) => any, options?: CreateEnhancedClientOptions): Promise<{
|
|
136
|
+
client: T;
|
|
137
|
+
tenantId: string;
|
|
138
|
+
}>;
|
|
139
|
+
|
|
140
|
+
//#endregion
|
|
141
|
+
//# sourceMappingURL=axios-setup.server.d.ts.map
|
|
142
|
+
|
|
143
|
+
export { APIConfigFactory, APIConfigFactoryOptions, AxiosSetupOptions, CreateEnhancedClientOptions, createAPIConfigFactory as createAPIConfigFactory$1, createEnhancedClient as createEnhancedClient$1, setupAxiosInterceptors as setupAxiosInterceptors$1 };
|
|
144
|
+
//# sourceMappingURL=server-CLbksnvg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-CLbksnvg.d.ts","names":[],"sources":["../src/api-client/api-config.server.ts","../src/api-client/axios-setup.server.ts"],"sourcesContent":null,"mappings":";;;;;;;;AA2BA;;;UAAiB,uBAAA;;;;EAyBD,OAAA,CAAA,EAAA,MAAA;EAAsB;;;EAEA,cAC3B,CAAA,EApBQ,MAoBR,CAAA,MAAA,EAAA,MAAA,CAAA;EAAS;;;EAiEe,SACtB,CAAA,EAAA,MAAA;EAAS;AAAV;AA0EZ;EAA4B,OAAA,CAAA,EAAA,MAAA;;;AAAa;;;;;iBA/IzB,sBAAA,iBACE,oCACE,6BACT,4BACO;6BA+DL,mBACA,2BACR,QAAQ;EClDI,aAAA,EAAA,GAAA,GAAiB,MAAA;CAAA;AAIvB,KDwHC,gBAAA,GAAmB,UCxHpB,CAAA,ODwHsC,sBCxHtC,CAAA,CAAA;;;;;;;AD4CE,UChDI,iBAAA,CDgDJ;EAAO;;;EAER,MAAA,CAAA,EC9CD,SD8CC;EA0EA;;;EAA2D,mBAAxC,CAAA,ECpHP,cDoHO;EAAU;;;gBChHzB;;;;EAZC,YAAA,CAAA,EAAA,OAAiB;;;;;AAYP;;;;;;;;;;;;;;;;;;;;;iBA+BX,sBAAA,gBACC,wBACN,mBACA;;;;AAHK,UA8KC,2BAAA,SAAoC,iBA9Kf,CAAA;EAAA;;;EAEpB,aACP,CAAA,EAAA,OAAA;EAAsB;;;;EA2KhB;;;EAgBO,QAhB6B,CAAA,EAAA,MAAA;EAAiB;;;kBAgBpD;;;;;;;;;;;;;;;;;;;;;;AA2BlB;;;;AAEsF,iBAFhE,oBAEgE,CAAA,CAAA,CAAA,CAAA,OAAA,EAD3E,OAC2E,EAAA,WAAA,EAAA,KAAA,aAAA,CAAA,EAAA,GAAA,EAAA,QAAA,CAAA,EAAA,MAAA,EAAA,KAAA,CAAA,EAAlB,aAAkB,EAAA,GAAA,CAAA,EAAA,eAAA,EAAA,CAAA,OAAA,EACzD,OADyD,EAAA,OAAA,CAAA,EAAA,GAAA,EAAA,GAC9B,OAD8B,CAAA,GAAA,CAAA,EAAA,kBAAA,EAAA,KAAA,MAAA,CAAA,EAAA,GAAA,EAAA,GAAA,GAAA,EAAA,OAAA,CAAA,EAG3E,2BAH2E,CAAA,EAInF,OAJmF,CAAA;EAAC,MAC1D,EAGR,CAHQ;EAAO,QAAoB,EAAA,MAAA;CAAO,CAAA"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { PermissionChecker } from "./permissions-D5ScGGnd.js";
|
|
2
|
+
|
|
3
|
+
//#region src/permissions/route-protection.server.ts
|
|
4
|
+
const DEFAULT_UNAUTHORIZED_RESPONSE = () => new Response("Unauthorized", {
|
|
5
|
+
status: 401,
|
|
6
|
+
statusText: "You must be logged in to access this resource"
|
|
7
|
+
});
|
|
8
|
+
const DEFAULT_FORBIDDEN_RESPONSE = (details) => {
|
|
9
|
+
const message = process.env.NODE_ENV === "development" ? `Missing permissions: ${details.missingPermissions?.join(", ")}` : "You don't have permission to access this resource";
|
|
10
|
+
return new Response(message, {
|
|
11
|
+
status: 403,
|
|
12
|
+
statusText: "Forbidden"
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
let permissionRouteProtectionConfig = {};
|
|
16
|
+
function getPermissionRouteProtectionConfig() {
|
|
17
|
+
if (!permissionRouteProtectionConfig.getSession) throw new Error("Permission route protection session getter not configured. Call configurePermissionRouteProtection first.");
|
|
18
|
+
if (!permissionRouteProtectionConfig.resolveContext) throw new Error("Permission route protection context resolver not configured. Call configurePermissionRouteProtection first.");
|
|
19
|
+
return {
|
|
20
|
+
getSession: permissionRouteProtectionConfig.getSession,
|
|
21
|
+
resolveContext: permissionRouteProtectionConfig.resolveContext,
|
|
22
|
+
createUnauthorizedResponse: permissionRouteProtectionConfig.createUnauthorizedResponse || DEFAULT_UNAUTHORIZED_RESPONSE,
|
|
23
|
+
createForbiddenResponse: permissionRouteProtectionConfig.createForbiddenResponse || DEFAULT_FORBIDDEN_RESPONSE
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function configurePermissionRouteProtection(config) {
|
|
27
|
+
permissionRouteProtectionConfig = {
|
|
28
|
+
...permissionRouteProtectionConfig,
|
|
29
|
+
...config
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function resetPermissionRouteProtection() {
|
|
33
|
+
permissionRouteProtectionConfig = {};
|
|
34
|
+
}
|
|
35
|
+
async function getPermissionRouteState(request) {
|
|
36
|
+
const config = getPermissionRouteProtectionConfig();
|
|
37
|
+
const session = await config.getSession(request);
|
|
38
|
+
const context = await config.resolveContext(request, session);
|
|
39
|
+
return {
|
|
40
|
+
config,
|
|
41
|
+
session,
|
|
42
|
+
context
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async function requirePermission(request, permission, options = {}) {
|
|
46
|
+
const { config, session, context } = await getPermissionRouteState(request);
|
|
47
|
+
if (!session.user || !session.accessToken) throw config.createUnauthorizedResponse(request, session);
|
|
48
|
+
const checker = new PermissionChecker(context.permissions || []);
|
|
49
|
+
const permissionsToCheck = Array.isArray(permission) ? permission : [permission];
|
|
50
|
+
const result = checker.hasPermissions(permissionsToCheck, options);
|
|
51
|
+
if (!result.hasPermission) throw config.createForbiddenResponse({
|
|
52
|
+
request,
|
|
53
|
+
permission,
|
|
54
|
+
permissionsToCheck,
|
|
55
|
+
missingPermissions: result.missingPermissions,
|
|
56
|
+
options,
|
|
57
|
+
session,
|
|
58
|
+
context
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async function checkPermission(request, permission, options = {}) {
|
|
62
|
+
try {
|
|
63
|
+
await requirePermission(request, permission, options);
|
|
64
|
+
return true;
|
|
65
|
+
} catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function withPermission(permission, loader, options) {
|
|
70
|
+
return async (args) => {
|
|
71
|
+
await requirePermission(args.request, permission, options);
|
|
72
|
+
return loader(args);
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { checkPermission, configurePermissionRouteProtection, requirePermission, resetPermissionRouteProtection, withPermission };
|
|
78
|
+
//# sourceMappingURL=server-CNp6gjFE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-CNp6gjFE.js","names":["details: ForbiddenPermissionDetails","permissionRouteProtectionConfig: PermissionRouteProtectionConfig","config: PermissionRouteProtectionConfig","request: Request","permission: PermissionCode | PermissionCode[]","options: PermissionCheckOptions","loader: (args: any) => Promise<TLoaderData>","options?: PermissionCheckOptions","args: any"],"sources":["../src/permissions/route-protection.server.ts"],"sourcesContent":["import { PermissionChecker } from './permission-service';\nimport type { PermissionCheckOptions, PermissionCode } from './types';\n\nexport interface PermissionRouteSession {\n user?: {\n sub?: string;\n email?: string | null;\n } | null;\n accessToken?: string | null;\n}\n\nexport interface PermissionRouteContext {\n permissions: PermissionCode[];\n currentTenant?: string | null;\n}\n\nexport interface ForbiddenPermissionDetails {\n request: Request;\n permission: PermissionCode | PermissionCode[];\n permissionsToCheck: PermissionCode[];\n missingPermissions?: PermissionCode[];\n options: PermissionCheckOptions;\n session: PermissionRouteSession;\n context: PermissionRouteContext;\n}\n\nexport interface PermissionRouteProtectionConfig {\n getSession?: (request: Request) => Promise<PermissionRouteSession>;\n resolveContext?: (\n request: Request,\n session: PermissionRouteSession\n ) => Promise<PermissionRouteContext>;\n createUnauthorizedResponse?: (\n request: Request,\n session: PermissionRouteSession\n ) => Response;\n createForbiddenResponse?: (details: ForbiddenPermissionDetails) => Response;\n}\n\nconst DEFAULT_UNAUTHORIZED_RESPONSE = () =>\n new Response('Unauthorized', {\n status: 401,\n statusText: 'You must be logged in to access this resource',\n });\n\nconst DEFAULT_FORBIDDEN_RESPONSE = (details: ForbiddenPermissionDetails) => {\n const message =\n process.env.NODE_ENV === 'development'\n ? `Missing permissions: ${details.missingPermissions?.join(', ')}`\n : \"You don't have permission to access this resource\";\n\n return new Response(message, {\n status: 403,\n statusText: 'Forbidden',\n });\n};\n\nlet permissionRouteProtectionConfig: PermissionRouteProtectionConfig = {};\n\nfunction getPermissionRouteProtectionConfig(): Required<PermissionRouteProtectionConfig> {\n if (!permissionRouteProtectionConfig.getSession) {\n throw new Error(\n 'Permission route protection session getter not configured. Call configurePermissionRouteProtection first.'\n );\n }\n\n if (!permissionRouteProtectionConfig.resolveContext) {\n throw new Error(\n 'Permission route protection context resolver not configured. Call configurePermissionRouteProtection first.'\n );\n }\n\n return {\n getSession: permissionRouteProtectionConfig.getSession,\n resolveContext: permissionRouteProtectionConfig.resolveContext,\n createUnauthorizedResponse:\n permissionRouteProtectionConfig.createUnauthorizedResponse || DEFAULT_UNAUTHORIZED_RESPONSE,\n createForbiddenResponse:\n permissionRouteProtectionConfig.createForbiddenResponse || DEFAULT_FORBIDDEN_RESPONSE,\n };\n}\n\nexport function configurePermissionRouteProtection(\n config: PermissionRouteProtectionConfig\n): void {\n permissionRouteProtectionConfig = {\n ...permissionRouteProtectionConfig,\n ...config,\n };\n}\n\nexport function resetPermissionRouteProtection(): void {\n permissionRouteProtectionConfig = {};\n}\n\nasync function getPermissionRouteState(request: Request): Promise<{\n config: Required<PermissionRouteProtectionConfig>;\n session: PermissionRouteSession;\n context: PermissionRouteContext;\n}> {\n const config = getPermissionRouteProtectionConfig();\n const session = await config.getSession(request);\n const context = await config.resolveContext(request, session);\n\n return {\n config,\n session,\n context,\n };\n}\n\nexport async function requirePermission(\n request: Request,\n permission: PermissionCode | PermissionCode[],\n options: PermissionCheckOptions = {}\n): Promise<void> {\n const { config, session, context } = await getPermissionRouteState(request);\n\n if (!session.user || !session.accessToken) {\n throw config.createUnauthorizedResponse(request, session);\n }\n\n const checker = new PermissionChecker(context.permissions || []);\n const permissionsToCheck = Array.isArray(permission) ? permission : [permission];\n const result = checker.hasPermissions(permissionsToCheck, options);\n\n if (!result.hasPermission) {\n throw config.createForbiddenResponse({\n request,\n permission,\n permissionsToCheck,\n missingPermissions: result.missingPermissions,\n options,\n session,\n context,\n });\n }\n}\n\nexport async function checkPermission(\n request: Request,\n permission: PermissionCode | PermissionCode[],\n options: PermissionCheckOptions = {}\n): Promise<boolean> {\n try {\n await requirePermission(request, permission, options);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function withPermission<TLoaderData>(\n permission: PermissionCode | PermissionCode[],\n loader: (args: any) => Promise<TLoaderData>,\n options?: PermissionCheckOptions\n) {\n return async (args: any): Promise<TLoaderData> => {\n await requirePermission(args.request, permission, options);\n return loader(args);\n };\n}\n"],"mappings":";;;AAuCA,MAAM,gCAAgC,MACpC,IAAI,SAAS,gBAAgB;CAC3B,QAAQ;CACR,YAAY;AACb;AAEH,MAAM,6BAA6B,CAACA,YAAwC;CAC1E,MAAM,UACJ,QAAQ,IAAI,aAAa,iBACpB,uBAAuB,QAAQ,oBAAoB,KAAK,KAAK,CAAC,IAC/D;AAEN,QAAO,IAAI,SAAS,SAAS;EAC3B,QAAQ;EACR,YAAY;CACb;AACF;AAED,IAAIC,kCAAmE,CAAE;AAEzE,SAAS,qCAAgF;AACvF,MAAK,gCAAgC,WACnC,OAAM,IAAI,MACR;AAIJ,MAAK,gCAAgC,eACnC,OAAM,IAAI,MACR;AAIJ,QAAO;EACL,YAAY,gCAAgC;EAC5C,gBAAgB,gCAAgC;EAChD,4BACE,gCAAgC,8BAA8B;EAChE,yBACE,gCAAgC,2BAA2B;CAC9D;AACF;AAED,SAAgB,mCACdC,QACM;AACN,mCAAkC;EAChC,GAAG;EACH,GAAG;CACJ;AACF;AAED,SAAgB,iCAAuC;AACrD,mCAAkC,CAAE;AACrC;AAED,eAAe,wBAAwBC,SAIpC;CACD,MAAM,SAAS,oCAAoC;CACnD,MAAM,UAAU,MAAM,OAAO,WAAW,QAAQ;CAChD,MAAM,UAAU,MAAM,OAAO,eAAe,SAAS,QAAQ;AAE7D,QAAO;EACL;EACA;EACA;CACD;AACF;AAED,eAAsB,kBACpBA,SACAC,YACAC,UAAkC,CAAE,GACrB;CACf,MAAM,EAAE,QAAQ,SAAS,SAAS,GAAG,MAAM,wBAAwB,QAAQ;AAE3E,MAAK,QAAQ,SAAS,QAAQ,YAC5B,OAAM,OAAO,2BAA2B,SAAS,QAAQ;CAG3D,MAAM,UAAU,IAAI,kBAAkB,QAAQ,eAAe,CAAE;CAC/D,MAAM,qBAAqB,MAAM,QAAQ,WAAW,GAAG,aAAa,CAAC,UAAW;CAChF,MAAM,SAAS,QAAQ,eAAe,oBAAoB,QAAQ;AAElE,MAAK,OAAO,cACV,OAAM,OAAO,wBAAwB;EACnC;EACA;EACA;EACA,oBAAoB,OAAO;EAC3B;EACA;EACA;CACD,EAAC;AAEL;AAED,eAAsB,gBACpBF,SACAC,YACAC,UAAkC,CAAE,GAClB;AAClB,KAAI;AACF,QAAM,kBAAkB,SAAS,YAAY,QAAQ;AACrD,SAAO;CACR,QAAO;AACN,SAAO;CACR;AACF;AAED,SAAgB,eACdD,YACAE,QACAC,SACA;AACA,QAAO,OAAOC,SAAoC;AAChD,QAAM,kBAAkB,KAAK,SAAS,YAAY,QAAQ;AAC1D,SAAO,OAAO,KAAK;CACpB;AACF"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { AuthClaimMapping, AuthError, LoginOptions, OAuthState, ProtectionLevel, SessionData, TokenRefreshResult$1 as TokenRefreshResult, UserInfo } from "./types-DufLRY7A.js";
|
|
2
|
+
|
|
3
|
+
//#region src/auth/redis-session-storage.server.d.ts
|
|
4
|
+
|
|
5
|
+
declare const AUTH_ERROR_COOKIE_PREFIX: string;
|
|
6
|
+
declare function createAuthSession(request: Request, sessionData: Partial<SessionData>): Promise<Headers>;
|
|
7
|
+
declare function getAuthSession(request: Request): Promise<SessionData>;
|
|
8
|
+
declare function updateAuthSession(request: Request, updates: Partial<SessionData>): Promise<Headers>;
|
|
9
|
+
declare function destroyAuthSession(request: Request): Promise<Headers>;
|
|
10
|
+
declare function requireAuthSession(request: Request): Promise<SessionData>;
|
|
11
|
+
declare function isSessionValid(request: Request): Promise<boolean>;
|
|
12
|
+
declare function createOAuthState(state: OAuthState): Promise<string>;
|
|
13
|
+
declare function getOAuthState(stateId: string): Promise<OAuthState | null>;
|
|
14
|
+
declare function deleteOAuthState(stateId: string): Promise<void>;
|
|
15
|
+
declare function cleanupExpiredOAuthStates(): Promise<number>;
|
|
16
|
+
declare function closeRedisConnection(): Promise<void>;
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/auth/auth.server.d.ts
|
|
20
|
+
//# sourceMappingURL=redis-session-storage.server.d.ts.map
|
|
21
|
+
/**
|
|
22
|
+
* Configure claim mapping so different providers/backends can project their
|
|
23
|
+
* own claim names onto the shared auth/session primitives.
|
|
24
|
+
*/
|
|
25
|
+
declare function configureAuthClaimMapping(mapping: AuthClaimMapping): void;
|
|
26
|
+
/**
|
|
27
|
+
* Reset claim mapping to the built-in defaults.
|
|
28
|
+
*/
|
|
29
|
+
declare function resetAuthClaimMapping(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Extract user info from ID token claims
|
|
32
|
+
*/
|
|
33
|
+
declare function extractUserInfo(claims: Record<string, unknown>): {
|
|
34
|
+
tenants: string[];
|
|
35
|
+
currentTenant?: string;
|
|
36
|
+
isOnboarded: boolean;
|
|
37
|
+
tenantRoles: Record<string, string[]>;
|
|
38
|
+
permissions: string[];
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Check if there's an auth error in cookies
|
|
42
|
+
*
|
|
43
|
+
* This should be called by apps (especially those without landing pages like Dashboard)
|
|
44
|
+
* BEFORE starting OAuth flow to prevent redirect loops.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* // In dashboard's index route loader
|
|
49
|
+
* const authError = getAuthError(request);
|
|
50
|
+
* if (authError) {
|
|
51
|
+
* return { authError }; // Show error to user
|
|
52
|
+
* }
|
|
53
|
+
* // No error, proceed with session check
|
|
54
|
+
* const user = await getUser(request);
|
|
55
|
+
* if (!user) {
|
|
56
|
+
* return login(request);
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare function getAuthError(request: Request): AuthError | null;
|
|
61
|
+
/**
|
|
62
|
+
* Clear auth error cookies
|
|
63
|
+
*
|
|
64
|
+
* Call this after displaying the error to the user
|
|
65
|
+
*/
|
|
66
|
+
declare function clearAuthErrorHeaders(): Headers;
|
|
67
|
+
/**
|
|
68
|
+
* Check if request has auth error (quick check without parsing)
|
|
69
|
+
*/
|
|
70
|
+
declare function hasAuthError(request: Request): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Initiate OAuth login flow
|
|
73
|
+
*
|
|
74
|
+
* @param request - The incoming request
|
|
75
|
+
* @param returnUrlOrOptions - Either a return URL string or LoginOptions object
|
|
76
|
+
*/
|
|
77
|
+
declare function login(request: Request, returnUrlOrOptions?: string | LoginOptions): Promise<Response>;
|
|
78
|
+
/**
|
|
79
|
+
* Handle OAuth callback
|
|
80
|
+
*
|
|
81
|
+
* Handles OAuth authorization response including success and error cases.
|
|
82
|
+
*
|
|
83
|
+
* Error Handling:
|
|
84
|
+
* - `access_denied`: User doesn't have access to this application
|
|
85
|
+
* - For apps with landing page: Redirect home with error cookie
|
|
86
|
+
* - For apps without landing page: Redirect home with error cookie (must handle specially)
|
|
87
|
+
* - `login_required`: No active identity session
|
|
88
|
+
* - Redirect to home to start fresh login
|
|
89
|
+
*/
|
|
90
|
+
declare function handleCallback(request: Request): Promise<Response>;
|
|
91
|
+
/**
|
|
92
|
+
* Logout user
|
|
93
|
+
*
|
|
94
|
+
* Backend uses id_token_hint to identify which tokens to revoke.
|
|
95
|
+
*
|
|
96
|
+
* **Scenario 1: Full SSO Logout (Manual Sign Out)**
|
|
97
|
+
* - Query param: sso_logout=true
|
|
98
|
+
* - Result: Full logout + identity cookie cleared
|
|
99
|
+
* - User must re-authenticate everywhere
|
|
100
|
+
*
|
|
101
|
+
* **Scenario 2: Standard Logout (Automatic/Token Expired)**
|
|
102
|
+
* - No sso_logout param
|
|
103
|
+
* - Result: Tokens revoked based on id_token_hint
|
|
104
|
+
* - Backend determines which tokens to revoke
|
|
105
|
+
*
|
|
106
|
+
* Configuration:
|
|
107
|
+
* - `OIDC_SSO_LOGOUT` env var ('true' | 'false') - default behavior
|
|
108
|
+
* - Query param `sso_logout=true` - override for full logout
|
|
109
|
+
*/
|
|
110
|
+
declare function logout(request: Request): Promise<Response>;
|
|
111
|
+
/**
|
|
112
|
+
* Get current user from session
|
|
113
|
+
*/
|
|
114
|
+
declare function getUser(request: Request): Promise<UserInfo | null>;
|
|
115
|
+
/**
|
|
116
|
+
* Require authenticated user (throws redirect to login if not authenticated)
|
|
117
|
+
*/
|
|
118
|
+
declare function requireAuth(request: Request): Promise<UserInfo>;
|
|
119
|
+
/**
|
|
120
|
+
* Get access token from session
|
|
121
|
+
*/
|
|
122
|
+
declare function getAccessToken(request: Request): Promise<string | null>;
|
|
123
|
+
/**
|
|
124
|
+
* Refresh tokens
|
|
125
|
+
*/
|
|
126
|
+
declare function refreshTokens(request: Request, refreshToken?: string): Promise<TokenRefreshResult>;
|
|
127
|
+
/**
|
|
128
|
+
* Clear auth server cache (useful for testing)
|
|
129
|
+
*/
|
|
130
|
+
declare function clearAuthServerCache(): void;
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/auth/route-protection.server.d.ts
|
|
134
|
+
//# sourceMappingURL=auth.server.d.ts.map
|
|
135
|
+
/**
|
|
136
|
+
* Check if token needs refresh
|
|
137
|
+
*/
|
|
138
|
+
declare function shouldRefreshToken(request: Request): Promise<boolean>;
|
|
139
|
+
/**
|
|
140
|
+
* Identity context check configuration
|
|
141
|
+
*/
|
|
142
|
+
interface DefaultRouteIdentityContext {
|
|
143
|
+
hasAnyMembership: boolean;
|
|
144
|
+
hasSubscription: boolean;
|
|
145
|
+
isOnboarded: boolean;
|
|
146
|
+
}
|
|
147
|
+
interface IdentityContextChecker<TIdentityContext = DefaultRouteIdentityContext> {
|
|
148
|
+
getIdentityContext: (request: Request, userId: string, forceRefresh?: boolean) => Promise<DefaultRouteIdentityContext & TIdentityContext>;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Tenant checker configuration
|
|
152
|
+
*/
|
|
153
|
+
interface TenantChecker {
|
|
154
|
+
getCurrentTenant: (request: Request) => Promise<string | null>;
|
|
155
|
+
initializeTenant: (request: Request) => Promise<{
|
|
156
|
+
headers: Headers;
|
|
157
|
+
tenantId: string;
|
|
158
|
+
} | null>;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Subscription checker configuration
|
|
162
|
+
*/
|
|
163
|
+
interface SubscriptionChecker {
|
|
164
|
+
checkTenantSubscriptionStatus: (request: Request, tenantId: string) => Promise<boolean>;
|
|
165
|
+
}
|
|
166
|
+
interface RouteProtectionRedirect {
|
|
167
|
+
location: string;
|
|
168
|
+
headers?: HeadersInit;
|
|
169
|
+
status?: number;
|
|
170
|
+
}
|
|
171
|
+
interface AutomaticLogoutRequestContext {
|
|
172
|
+
request: Request;
|
|
173
|
+
reason: 'expired-no-refresh-token' | 'refresh-failed';
|
|
174
|
+
}
|
|
175
|
+
interface LoginReturnUrlContext {
|
|
176
|
+
request: Request;
|
|
177
|
+
currentPath: string;
|
|
178
|
+
protection: ProtectionLevel;
|
|
179
|
+
}
|
|
180
|
+
interface RouteProtectionResolverContext<TIdentityContext = DefaultRouteIdentityContext> {
|
|
181
|
+
request: Request;
|
|
182
|
+
user: UserInfo;
|
|
183
|
+
currentPath: string;
|
|
184
|
+
protection: ProtectionLevel;
|
|
185
|
+
getIdentityContext: (forceRefresh?: boolean) => Promise<TIdentityContext | null>;
|
|
186
|
+
getCurrentTenant: () => Promise<string | null>;
|
|
187
|
+
initializeTenant: () => Promise<{
|
|
188
|
+
headers: Headers;
|
|
189
|
+
tenantId: string;
|
|
190
|
+
} | null>;
|
|
191
|
+
}
|
|
192
|
+
interface RouteProtectionErrorHandlerContext<TIdentityContext = DefaultRouteIdentityContext> extends RouteProtectionResolverContext<TIdentityContext> {
|
|
193
|
+
error: unknown;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Route protection configuration
|
|
197
|
+
*/
|
|
198
|
+
interface RouteProtectionConfig<TIdentityContext = DefaultRouteIdentityContext> {
|
|
199
|
+
identityChecker?: IdentityContextChecker<TIdentityContext>;
|
|
200
|
+
tenantChecker?: TenantChecker;
|
|
201
|
+
subscriptionChecker?: SubscriptionChecker;
|
|
202
|
+
resolveRoute?: (context: RouteProtectionResolverContext<TIdentityContext>) => Promise<RouteProtectionRedirect | null | void> | RouteProtectionRedirect | null | void;
|
|
203
|
+
handleRouteError?: (context: RouteProtectionErrorHandlerContext<TIdentityContext>) => Promise<RouteProtectionRedirect | null | void> | RouteProtectionRedirect | null | void;
|
|
204
|
+
getLoginReturnUrl?: (context: LoginReturnUrlContext) => string;
|
|
205
|
+
createAutomaticLogoutRequest?: (context: AutomaticLogoutRequestContext) => Promise<Request> | Request;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Configure route protection with identity/tenant/subscription checkers
|
|
209
|
+
*/
|
|
210
|
+
declare function configureRouteProtection<TIdentityContext = DefaultRouteIdentityContext>(config: RouteProtectionConfig<TIdentityContext>): void;
|
|
211
|
+
/**
|
|
212
|
+
* Reset route protection to its built-in defaults.
|
|
213
|
+
*/
|
|
214
|
+
declare function resetRouteProtectionConfig(): void;
|
|
215
|
+
/**
|
|
216
|
+
* Main route protection function
|
|
217
|
+
*/
|
|
218
|
+
declare function protectRoute<T>(request: Request, protection: ProtectionLevel, loaderFn: (user?: UserInfo) => Promise<T> | T): Promise<T>;
|
|
219
|
+
/**
|
|
220
|
+
* Public route (optional auth)
|
|
221
|
+
*/
|
|
222
|
+
declare const publicRoute: <T>(request: Request, loaderFn: (user?: UserInfo) => Promise<T> | T) => Promise<T>;
|
|
223
|
+
/**
|
|
224
|
+
* Auth-protected route
|
|
225
|
+
*/
|
|
226
|
+
declare const authRoute: <T>(request: Request, loaderFn: (user: UserInfo) => Promise<T> | T) => Promise<T>;
|
|
227
|
+
/**
|
|
228
|
+
* Onboarding route
|
|
229
|
+
*/
|
|
230
|
+
declare const onboardingRoute: <T>(request: Request, loaderFn: (user: UserInfo) => Promise<T> | T) => Promise<T>;
|
|
231
|
+
/**
|
|
232
|
+
* Subscription route
|
|
233
|
+
*/
|
|
234
|
+
declare const subscriptionRoute: <T>(request: Request, loaderFn: (user: UserInfo) => Promise<T> | T) => Promise<T>;
|
|
235
|
+
|
|
236
|
+
//#endregion
|
|
237
|
+
//#region src/auth/token-refresh.server.d.ts
|
|
238
|
+
//# sourceMappingURL=route-protection.server.d.ts.map
|
|
239
|
+
/**
|
|
240
|
+
* Attempt to refresh the access token
|
|
241
|
+
*/
|
|
242
|
+
declare function attemptTokenRefresh(request: Request): Promise<TokenRefreshResult>;
|
|
243
|
+
/**
|
|
244
|
+
* Check if a response indicates token expiration
|
|
245
|
+
*/
|
|
246
|
+
declare function isTokenExpiredResponse(response: Response): boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Check if token refresh should be attempted
|
|
249
|
+
*/
|
|
250
|
+
declare function shouldAttemptTokenRefresh(response: Response, hasAuth: boolean): boolean;
|
|
251
|
+
|
|
252
|
+
//#endregion
|
|
253
|
+
//# sourceMappingURL=token-refresh.server.d.ts.map
|
|
254
|
+
|
|
255
|
+
export { AUTH_ERROR_COOKIE_PREFIX, AutomaticLogoutRequestContext, DefaultRouteIdentityContext, IdentityContextChecker, LoginReturnUrlContext, RouteProtectionConfig, RouteProtectionErrorHandlerContext, RouteProtectionRedirect, RouteProtectionResolverContext, SubscriptionChecker, TenantChecker, attemptTokenRefresh as attemptTokenRefresh$1, authRoute as authRoute$1, cleanupExpiredOAuthStates, clearAuthErrorHeaders, clearAuthServerCache, closeRedisConnection, configureAuthClaimMapping, configureRouteProtection as configureRouteProtection$1, createAuthSession, createOAuthState, deleteOAuthState, destroyAuthSession, extractUserInfo, getAccessToken, getAuthError, getAuthSession, getOAuthState, getUser, handleCallback, hasAuthError, isSessionValid, isTokenExpiredResponse as isTokenExpiredResponse$1, login, logout, onboardingRoute as onboardingRoute$1, protectRoute as protectRoute$1, publicRoute as publicRoute$1, refreshTokens, requireAuth, requireAuthSession, resetAuthClaimMapping, resetRouteProtectionConfig as resetRouteProtectionConfig$1, shouldAttemptTokenRefresh as shouldAttemptTokenRefresh$1, shouldRefreshToken as shouldRefreshToken$1, subscriptionRoute as subscriptionRoute$1, updateAuthSession };
|
|
256
|
+
//# sourceMappingURL=server-CXGaRaiS.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-CXGaRaiS.d.ts","names":[],"sources":["../src/auth/redis-session-storage.server.ts","../src/auth/auth.server.ts","../src/auth/route-protection.server.ts","../src/auth/token-refresh.server.ts"],"sourcesContent":null,"mappings":"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"}
|