@karbonjs/auth 0.1.0 → 0.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karbonjs/auth",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Authentication helpers for Karbon — token management, user cache, hooks",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,7 +15,7 @@
15
15
  "dist"
16
16
  ],
17
17
  "dependencies": {
18
- "@karbonjs/types": "0.1.0"
18
+ "@karbonjs/types": "0.2.1"
19
19
  },
20
20
  "publishConfig": {
21
21
  "access": "public"
package/dist/roles.d.ts DELETED
@@ -1,33 +0,0 @@
1
- /**
2
- * Role hierarchy definition.
3
- * Higher roles inherit permissions from lower roles.
4
- *
5
- * ```ts
6
- * const hierarchy: RoleHierarchy = {
7
- * 'ROLE_SUPER_ADMIN': ['ROLE_ADMIN'],
8
- * 'ROLE_ADMIN': ['ROLE_EDITOR'],
9
- * 'ROLE_EDITOR': ['ROLE_USER'],
10
- * 'ROLE_USER': [],
11
- * }
12
- * ```
13
- */
14
- export type RoleHierarchy = Record<string, string[]>;
15
- /**
16
- * Check if a user's roles satisfy a required role, considering hierarchy.
17
- *
18
- * ```ts
19
- * hasRole(['ROLE_ADMIN'], 'ROLE_USER', hierarchy) // true (admin inherits user)
20
- * hasRole(['ROLE_USER'], 'ROLE_ADMIN', hierarchy) // false
21
- * ```
22
- */
23
- export declare function hasRole(userRoles: string[], requiredRole: string, hierarchy?: RoleHierarchy): boolean;
24
- /**
25
- * Get the highest priority role from a list.
26
- * Priority is determined by hierarchy depth (deeper = higher).
27
- */
28
- export declare function highestRole(userRoles: string[], hierarchy: RoleHierarchy): string | null;
29
- /**
30
- * Shorthand: check if user has admin-level access.
31
- */
32
- export declare function isAdmin(userRoles: string[], hierarchy?: RoleHierarchy): boolean;
33
- //# sourceMappingURL=roles.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"roles.d.ts","sourceRoot":"","sources":["../src/roles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;AAEpD;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,GAAE,aAAkB,GAAG,OAAO,CAQzG;AAiBD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAexF;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,GAAE,aAAkB,GAAG,OAAO,CAEnF"}
package/dist/roles.js DELETED
@@ -1,57 +0,0 @@
1
- /**
2
- * Check if a user's roles satisfy a required role, considering hierarchy.
3
- *
4
- * ```ts
5
- * hasRole(['ROLE_ADMIN'], 'ROLE_USER', hierarchy) // true (admin inherits user)
6
- * hasRole(['ROLE_USER'], 'ROLE_ADMIN', hierarchy) // false
7
- * ```
8
- */
9
- export function hasRole(userRoles, requiredRole, hierarchy = {}) {
10
- if (userRoles.includes(requiredRole))
11
- return true;
12
- // Check hierarchy: does any user role inherit the required role?
13
- for (const role of userRoles) {
14
- if (resolveRoles(role, hierarchy).includes(requiredRole))
15
- return true;
16
- }
17
- return false;
18
- }
19
- /**
20
- * Resolve all inherited roles for a given role.
21
- */
22
- function resolveRoles(role, hierarchy, visited = new Set()) {
23
- if (visited.has(role))
24
- return [];
25
- visited.add(role);
26
- const children = hierarchy[role] ?? [];
27
- const all = [role];
28
- for (const child of children) {
29
- all.push(...resolveRoles(child, hierarchy, visited));
30
- }
31
- return all;
32
- }
33
- /**
34
- * Get the highest priority role from a list.
35
- * Priority is determined by hierarchy depth (deeper = higher).
36
- */
37
- export function highestRole(userRoles, hierarchy) {
38
- if (userRoles.length === 0)
39
- return null;
40
- let best = userRoles[0];
41
- let bestDepth = 0;
42
- for (const role of userRoles) {
43
- const depth = resolveRoles(role, hierarchy).length;
44
- if (depth > bestDepth) {
45
- bestDepth = depth;
46
- best = role;
47
- }
48
- }
49
- return best;
50
- }
51
- /**
52
- * Shorthand: check if user has admin-level access.
53
- */
54
- export function isAdmin(userRoles, hierarchy = {}) {
55
- return hasRole(userRoles, 'ROLE_ADMIN', hierarchy);
56
- }
57
- //# sourceMappingURL=roles.js.map
package/dist/roles.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"roles.js","sourceRoot":"","sources":["../src/roles.ts"],"names":[],"mappings":"AAeA;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CAAC,SAAmB,EAAE,YAAoB,EAAE,YAA2B,EAAE;IAC9F,IAAI,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAA;IAEjD,iEAAiE;IACjE,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,OAAO,IAAI,CAAA;IACvE,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,IAAY,EAAE,SAAwB,EAAE,UAAU,IAAI,GAAG,EAAU;IACvF,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAA;IAChC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAEjB,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IACtC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;IAClB,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,GAAG,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;IACtD,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,SAAmB,EAAE,SAAwB;IACvE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAEvC,IAAI,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;IACvB,IAAI,SAAS,GAAG,CAAC,CAAA;IAEjB,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,MAAM,CAAA;QAClD,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;YACtB,SAAS,GAAG,KAAK,CAAA;YACjB,IAAI,GAAG,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,SAAmB,EAAE,YAA2B,EAAE;IACxE,OAAO,OAAO,CAAC,SAAS,EAAE,YAAY,EAAE,SAAS,CAAC,CAAA;AACpD,CAAC"}
@@ -1,35 +0,0 @@
1
- export interface TokenPair {
2
- token: string;
3
- refreshToken: string;
4
- sessionId?: number;
5
- }
6
- export interface TokenManagerConfig {
7
- /** API endpoint for token refresh (e.g. "/auth/refresh") */
8
- refreshEndpoint: string;
9
- /** Base API URL */
10
- apiUrl: string;
11
- /** Called with new tokens after successful refresh */
12
- onRefresh?: (tokens: TokenPair) => void;
13
- /** Called when refresh fails */
14
- onExpired?: () => void;
15
- }
16
- /**
17
- * Server-side token refresh manager.
18
- * Handles refresh token exchange and deduplication.
19
- *
20
- * ```ts
21
- * const tokenManager = createTokenManager({
22
- * refreshEndpoint: '/auth/refresh',
23
- * apiUrl: 'http://localhost:3005/api/v1',
24
- * onRefresh: (tokens) => setCookies(tokens),
25
- * onExpired: () => clearSession(),
26
- * })
27
- *
28
- * const newTokens = await tokenManager.refresh(refreshToken, sessionId)
29
- * ```
30
- */
31
- export declare function createTokenManager(config: TokenManagerConfig): {
32
- /** Refresh tokens. Deduplicates concurrent calls. */
33
- refresh(refreshToken: string, sessionId?: number): Promise<TokenPair | null>;
34
- };
35
- //# sourceMappingURL=token-manager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../src/token-manager.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,sDAAsD;IACtD,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAA;IACvC,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB;IAmCzD,qDAAqD;0BACzB,MAAM,cAAc,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;EAOrF"}
@@ -1,56 +0,0 @@
1
- /**
2
- * Server-side token refresh manager.
3
- * Handles refresh token exchange and deduplication.
4
- *
5
- * ```ts
6
- * const tokenManager = createTokenManager({
7
- * refreshEndpoint: '/auth/refresh',
8
- * apiUrl: 'http://localhost:3005/api/v1',
9
- * onRefresh: (tokens) => setCookies(tokens),
10
- * onExpired: () => clearSession(),
11
- * })
12
- *
13
- * const newTokens = await tokenManager.refresh(refreshToken, sessionId)
14
- * ```
15
- */
16
- export function createTokenManager(config) {
17
- let pending = null;
18
- async function doRefresh(refreshToken, sessionId) {
19
- try {
20
- const res = await fetch(`${config.apiUrl}${config.refreshEndpoint}`, {
21
- method: 'POST',
22
- headers: { 'Content-Type': 'application/json' },
23
- body: JSON.stringify({
24
- refresh_token: refreshToken,
25
- session_id: sessionId,
26
- }),
27
- });
28
- if (!res.ok) {
29
- config.onExpired?.();
30
- return null;
31
- }
32
- const data = await res.json();
33
- const tokens = {
34
- token: data.token,
35
- refreshToken: data.refresh_token,
36
- sessionId: data.session_id,
37
- };
38
- config.onRefresh?.(tokens);
39
- return tokens;
40
- }
41
- catch {
42
- config.onExpired?.();
43
- return null;
44
- }
45
- }
46
- return {
47
- /** Refresh tokens. Deduplicates concurrent calls. */
48
- async refresh(refreshToken, sessionId) {
49
- if (!pending) {
50
- pending = doRefresh(refreshToken, sessionId).finally(() => { pending = null; });
51
- }
52
- return pending;
53
- },
54
- };
55
- }
56
- //# sourceMappingURL=token-manager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../src/token-manager.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAA0B;IAC3D,IAAI,OAAO,GAAqC,IAAI,CAAA;IAEpD,KAAK,UAAU,SAAS,CAAC,YAAoB,EAAE,SAAkB;QAC/D,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,EAAE;gBACnE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,aAAa,EAAE,YAAY;oBAC3B,UAAU,EAAE,SAAS;iBACtB,CAAC;aACH,CAAC,CAAA;YAEF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,CAAC,SAAS,EAAE,EAAE,CAAA;gBACpB,OAAO,IAAI,CAAA;YACb,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;YAC7B,MAAM,MAAM,GAAc;gBACxB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,YAAY,EAAE,IAAI,CAAC,aAAa;gBAChC,SAAS,EAAE,IAAI,CAAC,UAAU;aAC3B,CAAA;YAED,MAAM,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,CAAA;YAC1B,OAAO,MAAM,CAAA;QACf,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,SAAS,EAAE,EAAE,CAAA;YACpB,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED,OAAO;QACL,qDAAqD;QACrD,KAAK,CAAC,OAAO,CAAC,YAAoB,EAAE,SAAkB;YACpD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,SAAS,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,IAAI,CAAA,CAAC,CAAC,CAAC,CAAA;YAChF,CAAC;YACD,OAAO,OAAO,CAAA;QAChB,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -1,30 +0,0 @@
1
- import type { AuthUser } from '@karbonjs/types';
2
- export interface UserCacheOptions {
3
- /** Max entries in cache (default: 500) */
4
- maxSize?: number;
5
- /** TTL in milliseconds (default: 2 minutes) */
6
- ttl?: number;
7
- }
8
- /**
9
- * In-memory user cache for SSR hooks.
10
- * Prevents hammering the /profile endpoint on every request.
11
- *
12
- * ```ts
13
- * const cache = createUserCache({ ttl: 120_000, maxSize: 500 })
14
- *
15
- * // In your SSR hook:
16
- * let user = cache.get(token)
17
- * if (!user) {
18
- * user = await fetchProfile(token)
19
- * if (user) cache.set(token, user)
20
- * }
21
- * ```
22
- */
23
- export declare function createUserCache(opts?: UserCacheOptions): {
24
- get(token: string): AuthUser | null;
25
- set(token: string, user: AuthUser): void;
26
- invalidate(token: string): void;
27
- clear(): void;
28
- readonly size: number;
29
- };
30
- //# sourceMappingURL=user-cache.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"user-cache.d.ts","sourceRoot":"","sources":["../src/user-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE/C,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAOD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,gBAAqB;eAM5C,MAAM,GAAG,QAAQ,GAAG,IAAI;eAUxB,MAAM,QAAQ,QAAQ,GAAG,IAAI;sBAStB,MAAM,GAAG,IAAI;aAItB,IAAI;mBAID,MAAM;EAIrB"}
@@ -1,51 +0,0 @@
1
- /**
2
- * In-memory user cache for SSR hooks.
3
- * Prevents hammering the /profile endpoint on every request.
4
- *
5
- * ```ts
6
- * const cache = createUserCache({ ttl: 120_000, maxSize: 500 })
7
- *
8
- * // In your SSR hook:
9
- * let user = cache.get(token)
10
- * if (!user) {
11
- * user = await fetchProfile(token)
12
- * if (user) cache.set(token, user)
13
- * }
14
- * ```
15
- */
16
- export function createUserCache(opts = {}) {
17
- const maxSize = opts.maxSize ?? 500;
18
- const ttl = opts.ttl ?? 120_000;
19
- const store = new Map();
20
- return {
21
- get(token) {
22
- const entry = store.get(token);
23
- if (!entry)
24
- return null;
25
- if (Date.now() - entry.timestamp > ttl) {
26
- store.delete(token);
27
- return null;
28
- }
29
- return entry.user;
30
- },
31
- set(token, user) {
32
- // Evict oldest if full
33
- if (store.size >= maxSize) {
34
- const oldest = store.keys().next().value;
35
- if (oldest)
36
- store.delete(oldest);
37
- }
38
- store.set(token, { user, timestamp: Date.now() });
39
- },
40
- invalidate(token) {
41
- store.delete(token);
42
- },
43
- clear() {
44
- store.clear();
45
- },
46
- get size() {
47
- return store.size;
48
- },
49
- };
50
- }
51
- //# sourceMappingURL=user-cache.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"user-cache.js","sourceRoot":"","sources":["../src/user-cache.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAAC,OAAyB,EAAE;IACzD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,GAAG,CAAA;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAA;IAC/B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAA;IAE3C,OAAO;QACL,GAAG,CAAC,KAAa;YACf,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC9B,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAA;YACvB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC;gBACvC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBACnB,OAAO,IAAI,CAAA;YACb,CAAC;YACD,OAAO,KAAK,CAAC,IAAI,CAAA;QACnB,CAAC;QAED,GAAG,CAAC,KAAa,EAAE,IAAc;YAC/B,uBAAuB;YACvB,IAAI,KAAK,CAAC,IAAI,IAAI,OAAO,EAAE,CAAC;gBAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAA;gBACxC,IAAI,MAAM;oBAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAClC,CAAC;YACD,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;QACnD,CAAC;QAED,UAAU,CAAC,KAAa;YACtB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACrB,CAAC;QAED,KAAK;YACH,KAAK,CAAC,KAAK,EAAE,CAAA;QACf,CAAC;QAED,IAAI,IAAI;YACN,OAAO,KAAK,CAAC,IAAI,CAAA;QACnB,CAAC;KACF,CAAA;AACH,CAAC"}