@wrelik/auth 0.2.2 → 3.0.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/.turbo/turbo-build.log +25 -29
- package/.turbo/turbo-lint.log +11 -0
- package/.turbo/turbo-test.log +16 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +28 -0
- package/dist/client/index.d.mts +5 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/{next.js → client/index.js} +19 -25
- package/dist/client/index.mjs +22 -0
- package/dist/server/index.d.mts +15 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/{index.js → server/index.js} +36 -29
- package/dist/server/index.mjs +58 -0
- package/dist/shared/index.d.mts +21 -0
- package/dist/shared/index.d.ts +21 -0
- package/dist/shared/index.js +18 -0
- package/dist/shared/index.mjs +0 -0
- package/package.json +38 -14
- package/src/client/index.contract.test.ts +24 -0
- package/src/client/index.test.ts +18 -0
- package/src/client/index.ts +23 -0
- package/src/server/index.test.ts +61 -0
- package/src/server/index.ts +71 -0
- package/src/shared/index.ts +1 -0
- package/src/shared/types.ts +21 -0
- package/tsconfig.json +3 -1
- package/dist/chunk-HWIZ2Q5U.mjs +0 -17
- package/dist/chunk-TF32HGN2.mjs +0 -32
- package/dist/index.d.mts +0 -7
- package/dist/index.d.ts +0 -7
- package/dist/index.mjs +0 -16
- package/dist/next.d.mts +0 -5
- package/dist/next.d.ts +0 -5
- package/dist/next.mjs +0 -14
- package/dist/react-native.d.mts +0 -14
- package/dist/react-native.d.ts +0 -14
- package/dist/react-native.js +0 -77
- package/dist/react-native.mjs +0 -27
- package/dist/shared-Z5LN5APr.d.mts +0 -11
- package/dist/shared-Z5LN5APr.d.ts +0 -11
- package/src/index.test.ts +0 -29
- package/src/index.ts +0 -21
- package/src/next.ts +0 -8
- package/src/react-native.ts +0 -28
- package/src/shared.test.ts +0 -40
- package/src/shared.ts +0 -34
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,31 +1,27 @@
|
|
|
1
1
|
|
|
2
|
-
> @wrelik/auth@0.
|
|
3
|
-
> tsup src/index.ts src/
|
|
2
|
+
> @wrelik/auth@3.0.0 build /Users/lee/Projects/wrelik-kit/packages/auth
|
|
3
|
+
> tsup src/server/index.ts src/client/index.ts src/shared/index.ts --format cjs,esm --dts --clean
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m395.00 B[39m
|
|
29
|
-
[32mDTS[39m [1mdist/next.d.mts [22m[32m135.00 B[39m
|
|
30
|
-
[32mDTS[39m [1mdist/react-native.d.mts [22m[32m432.00 B[39m
|
|
31
|
-
[32mDTS[39m [1mdist/shared-Z5LN5APr.d.mts [22m[32m525.00 B[39m
|
|
5
|
+
CLI Building entry: src/server/index.ts, src/client/index.ts, src/shared/index.ts
|
|
6
|
+
CLI Using tsconfig: tsconfig.json
|
|
7
|
+
CLI tsup v8.5.1
|
|
8
|
+
CLI Target: es2019
|
|
9
|
+
CLI Cleaning output folder
|
|
10
|
+
CJS Build start
|
|
11
|
+
ESM Build start
|
|
12
|
+
ESM dist/shared/index.mjs 0 B
|
|
13
|
+
ESM dist/server/index.mjs 1.55 KB
|
|
14
|
+
ESM dist/client/index.mjs 631.00 B
|
|
15
|
+
ESM ⚡️ Build success in 287ms
|
|
16
|
+
CJS dist/server/index.js 2.72 KB
|
|
17
|
+
CJS dist/client/index.js 1.62 KB
|
|
18
|
+
CJS dist/shared/index.js 767.00 B
|
|
19
|
+
CJS ⚡️ Build success in 288ms
|
|
20
|
+
DTS Build start
|
|
21
|
+
DTS ⚡️ Build success in 3552ms
|
|
22
|
+
DTS dist/server/index.d.ts 701.00 B
|
|
23
|
+
DTS dist/client/index.d.ts 155.00 B
|
|
24
|
+
DTS dist/shared/index.d.ts 479.00 B
|
|
25
|
+
DTS dist/server/index.d.mts 702.00 B
|
|
26
|
+
DTS dist/client/index.d.mts 156.00 B
|
|
27
|
+
DTS dist/shared/index.d.mts 479.00 B
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
> @wrelik/auth@0.2.2 lint /Users/lee/Projects/wrelik-kit/packages/auth
|
|
3
|
+
> eslint src/
|
|
4
|
+
|
|
5
|
+
Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming latest React version for linting.
|
|
6
|
+
|
|
7
|
+
/Users/lee/Projects/wrelik-kit/packages/auth/src/server.ts
|
|
8
|
+
5:1 warning '@clerk/backend' import is restricted from being used. Please use @wrelik/auth/server instead no-restricted-imports
|
|
9
|
+
|
|
10
|
+
✖ 1 problem (0 errors, 1 warning)
|
|
11
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
> @wrelik/auth@3.0.0 test /Users/lee/Projects/wrelik-kit/packages/auth
|
|
3
|
+
> vitest run --passWithNoTests
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[1m[46m RUN [49m[22m [36mv4.1.2 [39m[90m/Users/lee/Projects/wrelik-kit/packages/auth[39m
|
|
7
|
+
|
|
8
|
+
[32m✓[39m src/client/index.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
9
|
+
[32m✓[39m src/client/index.contract.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
10
|
+
[32m✓[39m src/server/index.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
11
|
+
|
|
12
|
+
[2m Test Files [22m [1m[32m3 passed[39m[22m[90m (3)[39m
|
|
13
|
+
[2m Tests [22m [1m[32m9 passed[39m[22m[90m (9)[39m
|
|
14
|
+
[2m Start at [22m 20:04:59
|
|
15
|
+
[2m Duration [22m 877ms[2m (transform 865ms, setup 0ms, import 1.09s, tests 20ms, environment 0ms)[22m
|
|
16
|
+
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @wrelik/auth
|
|
2
2
|
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 3262454: Upgrade runtime SDK and workspace tooling dependencies to latest compatible versions, including Clerk, Sentry, AWS SDK, Inngest, Resend, Upstash, Zod, TypeScript, Turbo, Vitest, TSUP, and ESLint.
|
|
8
|
+
|
|
9
|
+
Adopt root ESLint flat config and align wrapper peer ranges for updated SDK majors while preserving package export paths. Also apply a patched transitive Next.js resolution to close audit findings and keep production audit clean.
|
|
10
|
+
|
|
11
|
+
Note: Vite is pinned to the latest 7.x line for runtime compatibility in this environment; this avoids current rolldown native-binding failures seen with Vite 8 under Node 20.18.0.
|
|
12
|
+
|
|
13
|
+
Breaking change: `@wrelik/auth` and `@wrelik/clerk-next` now require `@clerk/nextjs@7.x` via updated peer ranges (`>=7 <8`). Consumers on Clerk v4-v6 must upgrade to Clerk v7 before adopting these versions.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies [3262454]
|
|
18
|
+
- @wrelik/errors@2.0.1
|
|
19
|
+
|
|
20
|
+
## 2.0.0
|
|
21
|
+
|
|
22
|
+
### Major Changes
|
|
23
|
+
|
|
24
|
+
- 818ed58: Refactor runtime packages to strict subpath exports (`/server`, `/client`, `/shared`) with side-effect free entrypoints and hard CI/runtime boundary enforcement.
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Updated dependencies [818ed58]
|
|
29
|
+
- @wrelik/errors@2.0.0
|
|
30
|
+
|
|
3
31
|
## 0.2.2
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
|
@@ -17,37 +17,31 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
|
|
20
|
-
// src/
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
23
|
-
|
|
20
|
+
// src/client/index.ts
|
|
21
|
+
var client_exports = {};
|
|
22
|
+
__export(client_exports, {
|
|
23
|
+
mapClerkToSession: () => mapClerkToSession
|
|
24
24
|
});
|
|
25
|
-
module.exports = __toCommonJS(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
function
|
|
33
|
-
var _a, _b;
|
|
34
|
-
|
|
25
|
+
module.exports = __toCommonJS(client_exports);
|
|
26
|
+
function normalizeRoles(value) {
|
|
27
|
+
if (!Array.isArray(value)) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
return value.filter((role) => typeof role === "string");
|
|
31
|
+
}
|
|
32
|
+
function mapClerkToSession(input) {
|
|
33
|
+
var _a, _b, _c, _d;
|
|
34
|
+
const auth = input != null ? input : {};
|
|
35
|
+
if (!auth.userId) {
|
|
35
36
|
return { userId: null, tenantId: null, roles: [] };
|
|
36
37
|
}
|
|
37
|
-
const roles = ((_b = (_a = auth2.sessionClaims) == null ? void 0 : _a.publicMetadata) == null ? void 0 : _b.roles) || [];
|
|
38
38
|
return {
|
|
39
|
-
userId:
|
|
40
|
-
tenantId:
|
|
41
|
-
roles
|
|
39
|
+
userId: auth.userId,
|
|
40
|
+
tenantId: (_a = auth.orgId) != null ? _a : null,
|
|
41
|
+
roles: normalizeRoles((_d = (_c = (_b = auth.session) == null ? void 0 : _b.user) == null ? void 0 : _c.publicMetadata) == null ? void 0 : _d.roles)
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
// src/next.ts
|
|
46
|
-
function getSession() {
|
|
47
|
-
const clerkAuth = (0, import_nextjs.auth)();
|
|
48
|
-
return fromClerkAuth(clerkAuth);
|
|
49
|
-
}
|
|
50
44
|
// Annotate the CommonJS export names for ESM import in node:
|
|
51
45
|
0 && (module.exports = {
|
|
52
|
-
|
|
46
|
+
mapClerkToSession
|
|
53
47
|
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// src/client/index.ts
|
|
2
|
+
function normalizeRoles(value) {
|
|
3
|
+
if (!Array.isArray(value)) {
|
|
4
|
+
return [];
|
|
5
|
+
}
|
|
6
|
+
return value.filter((role) => typeof role === "string");
|
|
7
|
+
}
|
|
8
|
+
function mapClerkToSession(input) {
|
|
9
|
+
var _a, _b, _c, _d;
|
|
10
|
+
const auth = input != null ? input : {};
|
|
11
|
+
if (!auth.userId) {
|
|
12
|
+
return { userId: null, tenantId: null, roles: [] };
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
userId: auth.userId,
|
|
16
|
+
tenantId: (_a = auth.orgId) != null ? _a : null,
|
|
17
|
+
roles: normalizeRoles((_d = (_c = (_b = auth.session) == null ? void 0 : _b.user) == null ? void 0 : _c.publicMetadata) == null ? void 0 : _d.roles)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
mapClerkToSession
|
|
22
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { WorkflowSession } from '../shared/index.mjs';
|
|
2
|
+
|
|
3
|
+
type ClerkAuthLike = {
|
|
4
|
+
userId: string | null;
|
|
5
|
+
orgId?: string | null;
|
|
6
|
+
sessionClaims?: unknown;
|
|
7
|
+
};
|
|
8
|
+
declare function fromClerkAuth(clerkAuth: ClerkAuthLike | null): WorkflowSession;
|
|
9
|
+
declare function getSession(): Promise<WorkflowSession>;
|
|
10
|
+
declare function requireUser(session: WorkflowSession | null): string;
|
|
11
|
+
declare function requireTenant(session: WorkflowSession | null): string;
|
|
12
|
+
declare function hasRole(session: WorkflowSession | null, role: string): boolean;
|
|
13
|
+
declare function requireRole(session: WorkflowSession | null, role: string): void;
|
|
14
|
+
|
|
15
|
+
export { fromClerkAuth, getSession, hasRole, requireRole, requireTenant, requireUser };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { WorkflowSession } from '../shared/index.js';
|
|
2
|
+
|
|
3
|
+
type ClerkAuthLike = {
|
|
4
|
+
userId: string | null;
|
|
5
|
+
orgId?: string | null;
|
|
6
|
+
sessionClaims?: unknown;
|
|
7
|
+
};
|
|
8
|
+
declare function fromClerkAuth(clerkAuth: ClerkAuthLike | null): WorkflowSession;
|
|
9
|
+
declare function getSession(): Promise<WorkflowSession>;
|
|
10
|
+
declare function requireUser(session: WorkflowSession | null): string;
|
|
11
|
+
declare function requireTenant(session: WorkflowSession | null): string;
|
|
12
|
+
declare function hasRole(session: WorkflowSession | null, role: string): boolean;
|
|
13
|
+
declare function requireRole(session: WorkflowSession | null, role: string): void;
|
|
14
|
+
|
|
15
|
+
export { fromClerkAuth, getSession, hasRole, requireRole, requireTenant, requireUser };
|
|
@@ -17,59 +17,66 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
20
|
+
// src/server/index.ts
|
|
21
|
+
var server_exports = {};
|
|
22
|
+
__export(server_exports, {
|
|
23
23
|
fromClerkAuth: () => fromClerkAuth,
|
|
24
|
+
getSession: () => getSession,
|
|
24
25
|
hasRole: () => hasRole,
|
|
25
26
|
requireRole: () => requireRole,
|
|
26
27
|
requireTenant: () => requireTenant,
|
|
27
28
|
requireUser: () => requireUser
|
|
28
29
|
});
|
|
29
|
-
module.exports = __toCommonJS(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
module.exports = __toCommonJS(server_exports);
|
|
31
|
+
var import_server = require("@clerk/nextjs/server");
|
|
32
|
+
var import_shared = require("@wrelik/errors/shared");
|
|
33
|
+
function normalizeRoles(value) {
|
|
34
|
+
if (!Array.isArray(value)) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
return value.filter((role) => typeof role === "string");
|
|
38
|
+
}
|
|
39
|
+
function fromClerkAuth(clerkAuth) {
|
|
40
|
+
var _a, _b, _c;
|
|
41
|
+
if (!(clerkAuth == null ? void 0 : clerkAuth.userId)) {
|
|
42
|
+
return { userId: null, tenantId: null, roles: [] };
|
|
43
|
+
}
|
|
44
|
+
const authLike = clerkAuth;
|
|
45
|
+
const claims = (_a = authLike.sessionClaims) != null ? _a : {};
|
|
46
|
+
return {
|
|
47
|
+
userId: clerkAuth.userId,
|
|
48
|
+
tenantId: (_b = clerkAuth.orgId) != null ? _b : null,
|
|
49
|
+
roles: normalizeRoles((_c = claims.publicMetadata) == null ? void 0 : _c.roles)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async function getSession() {
|
|
53
|
+
return fromClerkAuth(await (0, import_server.auth)());
|
|
54
|
+
}
|
|
33
55
|
function requireUser(session) {
|
|
34
|
-
if (!session
|
|
35
|
-
throw new
|
|
56
|
+
if (!(session == null ? void 0 : session.userId)) {
|
|
57
|
+
throw new import_shared.AuthRequiredError();
|
|
36
58
|
}
|
|
37
59
|
return session.userId;
|
|
38
60
|
}
|
|
39
61
|
function requireTenant(session) {
|
|
40
62
|
requireUser(session);
|
|
41
|
-
if (!session
|
|
42
|
-
throw new
|
|
63
|
+
if (!(session == null ? void 0 : session.tenantId)) {
|
|
64
|
+
throw new import_shared.TenantRequiredError();
|
|
43
65
|
}
|
|
44
66
|
return session.tenantId;
|
|
45
67
|
}
|
|
46
68
|
function hasRole(session, role) {
|
|
47
|
-
|
|
48
|
-
if (!Array.isArray(session.roles)) return false;
|
|
49
|
-
return session.roles.includes(role);
|
|
69
|
+
return Boolean((session == null ? void 0 : session.userId) && Array.isArray(session.roles) && session.roles.includes(role));
|
|
50
70
|
}
|
|
51
71
|
function requireRole(session, role) {
|
|
52
72
|
if (!hasRole(session, role)) {
|
|
53
|
-
throw new
|
|
73
|
+
throw new import_shared.PermissionDeniedError(`Role ${role} required`);
|
|
54
74
|
}
|
|
55
75
|
}
|
|
56
|
-
|
|
57
|
-
// src/index.ts
|
|
58
|
-
function fromClerkAuth(auth) {
|
|
59
|
-
var _a, _b;
|
|
60
|
-
if (!auth || !auth.userId) {
|
|
61
|
-
return { userId: null, tenantId: null, roles: [] };
|
|
62
|
-
}
|
|
63
|
-
const roles = ((_b = (_a = auth.sessionClaims) == null ? void 0 : _a.publicMetadata) == null ? void 0 : _b.roles) || [];
|
|
64
|
-
return {
|
|
65
|
-
userId: auth.userId,
|
|
66
|
-
tenantId: auth.orgId || null,
|
|
67
|
-
roles
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
76
|
// Annotate the CommonJS export names for ESM import in node:
|
|
71
77
|
0 && (module.exports = {
|
|
72
78
|
fromClerkAuth,
|
|
79
|
+
getSession,
|
|
73
80
|
hasRole,
|
|
74
81
|
requireRole,
|
|
75
82
|
requireTenant,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// src/server/index.ts
|
|
2
|
+
import { auth } from "@clerk/nextjs/server";
|
|
3
|
+
import {
|
|
4
|
+
AuthRequiredError,
|
|
5
|
+
PermissionDeniedError,
|
|
6
|
+
TenantRequiredError
|
|
7
|
+
} from "@wrelik/errors/shared";
|
|
8
|
+
function normalizeRoles(value) {
|
|
9
|
+
if (!Array.isArray(value)) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
return value.filter((role) => typeof role === "string");
|
|
13
|
+
}
|
|
14
|
+
function fromClerkAuth(clerkAuth) {
|
|
15
|
+
var _a, _b, _c;
|
|
16
|
+
if (!(clerkAuth == null ? void 0 : clerkAuth.userId)) {
|
|
17
|
+
return { userId: null, tenantId: null, roles: [] };
|
|
18
|
+
}
|
|
19
|
+
const authLike = clerkAuth;
|
|
20
|
+
const claims = (_a = authLike.sessionClaims) != null ? _a : {};
|
|
21
|
+
return {
|
|
22
|
+
userId: clerkAuth.userId,
|
|
23
|
+
tenantId: (_b = clerkAuth.orgId) != null ? _b : null,
|
|
24
|
+
roles: normalizeRoles((_c = claims.publicMetadata) == null ? void 0 : _c.roles)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
async function getSession() {
|
|
28
|
+
return fromClerkAuth(await auth());
|
|
29
|
+
}
|
|
30
|
+
function requireUser(session) {
|
|
31
|
+
if (!(session == null ? void 0 : session.userId)) {
|
|
32
|
+
throw new AuthRequiredError();
|
|
33
|
+
}
|
|
34
|
+
return session.userId;
|
|
35
|
+
}
|
|
36
|
+
function requireTenant(session) {
|
|
37
|
+
requireUser(session);
|
|
38
|
+
if (!(session == null ? void 0 : session.tenantId)) {
|
|
39
|
+
throw new TenantRequiredError();
|
|
40
|
+
}
|
|
41
|
+
return session.tenantId;
|
|
42
|
+
}
|
|
43
|
+
function hasRole(session, role) {
|
|
44
|
+
return Boolean((session == null ? void 0 : session.userId) && Array.isArray(session.roles) && session.roles.includes(role));
|
|
45
|
+
}
|
|
46
|
+
function requireRole(session, role) {
|
|
47
|
+
if (!hasRole(session, role)) {
|
|
48
|
+
throw new PermissionDeniedError(`Role ${role} required`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
fromClerkAuth,
|
|
53
|
+
getSession,
|
|
54
|
+
hasRole,
|
|
55
|
+
requireRole,
|
|
56
|
+
requireTenant,
|
|
57
|
+
requireUser
|
|
58
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface WorkflowSession {
|
|
2
|
+
userId: string | null;
|
|
3
|
+
tenantId: string | null;
|
|
4
|
+
roles: string[];
|
|
5
|
+
}
|
|
6
|
+
interface ClerkSessionLike {
|
|
7
|
+
userId?: string | null;
|
|
8
|
+
orgId?: string | null;
|
|
9
|
+
sessionClaims?: unknown;
|
|
10
|
+
}
|
|
11
|
+
interface ClerkClientSessionLike {
|
|
12
|
+
userId?: string | null;
|
|
13
|
+
orgId?: string | null;
|
|
14
|
+
session?: {
|
|
15
|
+
user?: {
|
|
16
|
+
publicMetadata?: unknown;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type { ClerkClientSessionLike, ClerkSessionLike, WorkflowSession };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface WorkflowSession {
|
|
2
|
+
userId: string | null;
|
|
3
|
+
tenantId: string | null;
|
|
4
|
+
roles: string[];
|
|
5
|
+
}
|
|
6
|
+
interface ClerkSessionLike {
|
|
7
|
+
userId?: string | null;
|
|
8
|
+
orgId?: string | null;
|
|
9
|
+
sessionClaims?: unknown;
|
|
10
|
+
}
|
|
11
|
+
interface ClerkClientSessionLike {
|
|
12
|
+
userId?: string | null;
|
|
13
|
+
orgId?: string | null;
|
|
14
|
+
session?: {
|
|
15
|
+
user?: {
|
|
16
|
+
publicMetadata?: unknown;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type { ClerkClientSessionLike, ClerkSessionLike, WorkflowSession };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
|
|
16
|
+
// src/shared/index.ts
|
|
17
|
+
var shared_exports = {};
|
|
18
|
+
module.exports = __toCommonJS(shared_exports);
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrelik/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -9,29 +9,53 @@
|
|
|
9
9
|
"url": "https://github.com/lwhite702/wrelik-kit.git",
|
|
10
10
|
"directory": "packages/auth"
|
|
11
11
|
},
|
|
12
|
-
"
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
12
|
+
"sideEffects": false,
|
|
14
13
|
"exports": {
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
"./server": {
|
|
15
|
+
"types": "./dist/server/index.d.ts",
|
|
16
|
+
"import": "./dist/server/index.mjs",
|
|
17
|
+
"require": "./dist/server/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./client": {
|
|
20
|
+
"types": "./dist/client/index.d.ts",
|
|
21
|
+
"import": "./dist/client/index.mjs",
|
|
22
|
+
"require": "./dist/client/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./shared": {
|
|
25
|
+
"types": "./dist/shared/index.d.ts",
|
|
26
|
+
"import": "./dist/shared/index.mjs",
|
|
27
|
+
"require": "./dist/shared/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./package.json": "./package.json"
|
|
18
30
|
},
|
|
19
31
|
"dependencies": {
|
|
20
|
-
"@clerk/backend": "^
|
|
21
|
-
"@wrelik/errors": "0.
|
|
32
|
+
"@clerk/backend": "^3.2.4",
|
|
33
|
+
"@wrelik/errors": "2.0.1"
|
|
22
34
|
},
|
|
23
35
|
"peerDependencies": {
|
|
24
|
-
"@clerk/nextjs": "
|
|
36
|
+
"@clerk/nextjs": ">=7 <8"
|
|
25
37
|
},
|
|
26
38
|
"devDependencies": {
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
39
|
+
"@clerk/nextjs": "^7.0.8",
|
|
40
|
+
"@types/node": "^25.5.2",
|
|
41
|
+
"next": "15.5.14",
|
|
42
|
+
"tsup": "^8.5.1",
|
|
43
|
+
"vite": "^7.3.1",
|
|
44
|
+
"vitest": "^4.1.2",
|
|
45
|
+
"@wrelik/eslint-config": "0.1.2",
|
|
46
|
+
"@wrelik/tsconfig": "0.1.2"
|
|
47
|
+
},
|
|
48
|
+
"wrelik": {
|
|
49
|
+
"runtimes": [
|
|
50
|
+
"server",
|
|
51
|
+
"client",
|
|
52
|
+
"shared"
|
|
53
|
+
]
|
|
31
54
|
},
|
|
32
55
|
"scripts": {
|
|
33
|
-
"build": "tsup src/index.ts src/
|
|
56
|
+
"build": "tsup src/server/index.ts src/client/index.ts src/shared/index.ts --format cjs,esm --dts --clean",
|
|
34
57
|
"lint": "eslint src/",
|
|
58
|
+
"typecheck": "tsc --noEmit",
|
|
35
59
|
"test": "vitest run --passWithNoTests"
|
|
36
60
|
}
|
|
37
61
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { mapClerkToSession } from './index';
|
|
3
|
+
|
|
4
|
+
describe('@wrelik/auth/client contract', () => {
|
|
5
|
+
it('normalizes mixed roles from Clerk client payload', () => {
|
|
6
|
+
const session = mapClerkToSession({
|
|
7
|
+
userId: 'u1',
|
|
8
|
+
orgId: 't1',
|
|
9
|
+
session: {
|
|
10
|
+
user: {
|
|
11
|
+
publicMetadata: {
|
|
12
|
+
roles: ['admin', 42, 'owner'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
expect(session).toEqual({
|
|
19
|
+
userId: 'u1',
|
|
20
|
+
tenantId: 't1',
|
|
21
|
+
roles: ['admin', 'owner'],
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { mapClerkToSession } from './index';
|
|
3
|
+
|
|
4
|
+
describe('@wrelik/auth/client', () => {
|
|
5
|
+
it('maps unknown auth input to a safe empty session', () => {
|
|
6
|
+
expect(mapClerkToSession(null)).toEqual({ userId: null, tenantId: null, roles: [] });
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('maps role metadata without permission checks', () => {
|
|
10
|
+
const session = mapClerkToSession({
|
|
11
|
+
userId: 'u1',
|
|
12
|
+
orgId: 'o1',
|
|
13
|
+
session: { user: { publicMetadata: { roles: ['admin', 1] } } },
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
expect(session).toEqual({ userId: 'u1', tenantId: 'o1', roles: ['admin'] });
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ClerkClientSessionLike, WorkflowSession } from '../shared';
|
|
2
|
+
|
|
3
|
+
function normalizeRoles(value: unknown): string[] {
|
|
4
|
+
if (!Array.isArray(value)) {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return value.filter((role): role is string => typeof role === 'string');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function mapClerkToSession(input: unknown): WorkflowSession {
|
|
12
|
+
const auth = (input ?? {}) as ClerkClientSessionLike;
|
|
13
|
+
|
|
14
|
+
if (!auth.userId) {
|
|
15
|
+
return { userId: null, tenantId: null, roles: [] };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
userId: auth.userId,
|
|
20
|
+
tenantId: auth.orgId ?? null,
|
|
21
|
+
roles: normalizeRoles((auth.session?.user?.publicMetadata as { roles?: unknown } | undefined)?.roles),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { AuthRequiredError, PermissionDeniedError, TenantRequiredError } from '@wrelik/errors/shared';
|
|
3
|
+
import { fromClerkAuth, hasRole, requireRole, requireTenant, requireUser } from './index';
|
|
4
|
+
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
vi.resetModules();
|
|
7
|
+
vi.clearAllMocks();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
describe('@wrelik/auth/server', () => {
|
|
11
|
+
it('requires authenticated users and tenant contexts', () => {
|
|
12
|
+
expect(() => requireUser(null)).toThrow(AuthRequiredError);
|
|
13
|
+
expect(() => requireTenant({ userId: 'u1', tenantId: null, roles: [] })).toThrow(TenantRequiredError);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('checks role membership with runtime-shape safety', () => {
|
|
17
|
+
expect(hasRole({ userId: 'u1', tenantId: 't1', roles: ['admin'] }, 'admin')).toBe(true);
|
|
18
|
+
expect(() => requireRole({ userId: 'u1', tenantId: 't1', roles: [] }, 'admin')).toThrow(
|
|
19
|
+
PermissionDeniedError,
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('maps Clerk auth payloads defensively', () => {
|
|
24
|
+
const session = fromClerkAuth({
|
|
25
|
+
userId: 'u1',
|
|
26
|
+
orgId: 'o1',
|
|
27
|
+
sessionClaims: { publicMetadata: { roles: ['admin', 1] } },
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
} as any);
|
|
30
|
+
|
|
31
|
+
expect(session).toEqual({ userId: 'u1', tenantId: 'o1', roles: ['admin'] });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('retrieves and normalizes sessions from Clerk auth()', async () => {
|
|
35
|
+
vi.resetModules();
|
|
36
|
+
vi.doMock('@clerk/nextjs/server', () => ({
|
|
37
|
+
auth: () => ({
|
|
38
|
+
userId: 'u1',
|
|
39
|
+
orgId: 'o1',
|
|
40
|
+
sessionClaims: { publicMetadata: { roles: ['admin', 123] } },
|
|
41
|
+
}),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
const mod = await import('./index');
|
|
45
|
+
await expect(mod.getSession()).resolves.toEqual({ userId: 'u1', tenantId: 'o1', roles: ['admin'] });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('returns anonymous session when Clerk auth() is signed out', async () => {
|
|
49
|
+
vi.resetModules();
|
|
50
|
+
vi.doMock('@clerk/nextjs/server', () => ({
|
|
51
|
+
auth: () => ({ userId: null, orgId: null, sessionClaims: {} }),
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
const mod = await import('./index');
|
|
55
|
+
await expect(mod.getSession()).resolves.toEqual({ userId: null, tenantId: null, roles: [] });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('does not expose a root package import', () => {
|
|
59
|
+
expect(() => require.resolve('@wrelik/auth')).toThrow();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { auth } from '@clerk/nextjs/server';
|
|
2
|
+
import {
|
|
3
|
+
AuthRequiredError,
|
|
4
|
+
PermissionDeniedError,
|
|
5
|
+
TenantRequiredError,
|
|
6
|
+
} from '@wrelik/errors/shared';
|
|
7
|
+
import type { ClerkSessionLike, WorkflowSession } from '../shared';
|
|
8
|
+
|
|
9
|
+
function normalizeRoles(value: unknown): string[] {
|
|
10
|
+
if (!Array.isArray(value)) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return value.filter((role): role is string => typeof role === 'string');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type ClerkAuthLike = {
|
|
18
|
+
userId: string | null;
|
|
19
|
+
orgId?: string | null;
|
|
20
|
+
sessionClaims?: unknown;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function fromClerkAuth(
|
|
24
|
+
clerkAuth: ClerkAuthLike | null,
|
|
25
|
+
): WorkflowSession {
|
|
26
|
+
if (!clerkAuth?.userId) {
|
|
27
|
+
return { userId: null, tenantId: null, roles: [] };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const authLike: ClerkSessionLike = clerkAuth;
|
|
31
|
+
const claims =
|
|
32
|
+
(authLike.sessionClaims as { publicMetadata?: { roles?: unknown } } | undefined) ?? {};
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
userId: clerkAuth.userId,
|
|
36
|
+
tenantId: clerkAuth.orgId ?? null,
|
|
37
|
+
roles: normalizeRoles(claims.publicMetadata?.roles),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function getSession(): Promise<WorkflowSession> {
|
|
42
|
+
return fromClerkAuth(await auth());
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function requireUser(session: WorkflowSession | null): string {
|
|
46
|
+
if (!session?.userId) {
|
|
47
|
+
throw new AuthRequiredError();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return session.userId;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function requireTenant(session: WorkflowSession | null): string {
|
|
54
|
+
requireUser(session);
|
|
55
|
+
|
|
56
|
+
if (!session?.tenantId) {
|
|
57
|
+
throw new TenantRequiredError();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return session.tenantId;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function hasRole(session: WorkflowSession | null, role: string): boolean {
|
|
64
|
+
return Boolean(session?.userId && Array.isArray(session.roles) && session.roles.includes(role));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function requireRole(session: WorkflowSession | null, role: string): void {
|
|
68
|
+
if (!hasRole(session, role)) {
|
|
69
|
+
throw new PermissionDeniedError(`Role ${role} required`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { WorkflowSession, ClerkSessionLike, ClerkClientSessionLike } from './types';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface WorkflowSession {
|
|
2
|
+
userId: string | null;
|
|
3
|
+
tenantId: string | null;
|
|
4
|
+
roles: string[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface ClerkSessionLike {
|
|
8
|
+
userId?: string | null;
|
|
9
|
+
orgId?: string | null;
|
|
10
|
+
sessionClaims?: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ClerkClientSessionLike {
|
|
14
|
+
userId?: string | null;
|
|
15
|
+
orgId?: string | null;
|
|
16
|
+
session?: {
|
|
17
|
+
user?: {
|
|
18
|
+
publicMetadata?: unknown;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
}
|
package/tsconfig.json
CHANGED
package/dist/chunk-HWIZ2Q5U.mjs
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
function fromClerkAuth(auth) {
|
|
3
|
-
var _a, _b;
|
|
4
|
-
if (!auth || !auth.userId) {
|
|
5
|
-
return { userId: null, tenantId: null, roles: [] };
|
|
6
|
-
}
|
|
7
|
-
const roles = ((_b = (_a = auth.sessionClaims) == null ? void 0 : _a.publicMetadata) == null ? void 0 : _b.roles) || [];
|
|
8
|
-
return {
|
|
9
|
-
userId: auth.userId,
|
|
10
|
-
tenantId: auth.orgId || null,
|
|
11
|
-
roles
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export {
|
|
16
|
-
fromClerkAuth
|
|
17
|
-
};
|
package/dist/chunk-TF32HGN2.mjs
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// src/shared.ts
|
|
2
|
-
import { AuthRequiredError, PermissionDeniedError, TenantRequiredError } from "@wrelik/errors";
|
|
3
|
-
function requireUser(session) {
|
|
4
|
-
if (!session || !session.userId) {
|
|
5
|
-
throw new AuthRequiredError();
|
|
6
|
-
}
|
|
7
|
-
return session.userId;
|
|
8
|
-
}
|
|
9
|
-
function requireTenant(session) {
|
|
10
|
-
requireUser(session);
|
|
11
|
-
if (!session || !session.tenantId) {
|
|
12
|
-
throw new TenantRequiredError();
|
|
13
|
-
}
|
|
14
|
-
return session.tenantId;
|
|
15
|
-
}
|
|
16
|
-
function hasRole(session, role) {
|
|
17
|
-
if (!session || !session.userId) return false;
|
|
18
|
-
if (!Array.isArray(session.roles)) return false;
|
|
19
|
-
return session.roles.includes(role);
|
|
20
|
-
}
|
|
21
|
-
function requireRole(session, role) {
|
|
22
|
-
if (!hasRole(session, role)) {
|
|
23
|
-
throw new PermissionDeniedError(`Role ${role} required`);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export {
|
|
28
|
-
requireUser,
|
|
29
|
-
requireTenant,
|
|
30
|
-
hasRole,
|
|
31
|
-
requireRole
|
|
32
|
-
};
|
package/dist/index.d.mts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { SignedInAuthObject, SignedOutAuthObject } from '@clerk/backend';
|
|
2
|
-
import { W as WorkflowSession } from './shared-Z5LN5APr.mjs';
|
|
3
|
-
export { h as hasRole, r as requireRole, a as requireTenant, b as requireUser } from './shared-Z5LN5APr.mjs';
|
|
4
|
-
|
|
5
|
-
declare function fromClerkAuth(auth: SignedInAuthObject | SignedOutAuthObject | null): WorkflowSession;
|
|
6
|
-
|
|
7
|
-
export { WorkflowSession, fromClerkAuth };
|
package/dist/index.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { SignedInAuthObject, SignedOutAuthObject } from '@clerk/backend';
|
|
2
|
-
import { W as WorkflowSession } from './shared-Z5LN5APr.js';
|
|
3
|
-
export { h as hasRole, r as requireRole, a as requireTenant, b as requireUser } from './shared-Z5LN5APr.js';
|
|
4
|
-
|
|
5
|
-
declare function fromClerkAuth(auth: SignedInAuthObject | SignedOutAuthObject | null): WorkflowSession;
|
|
6
|
-
|
|
7
|
-
export { WorkflowSession, fromClerkAuth };
|
package/dist/index.mjs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
fromClerkAuth
|
|
3
|
-
} from "./chunk-HWIZ2Q5U.mjs";
|
|
4
|
-
import {
|
|
5
|
-
hasRole,
|
|
6
|
-
requireRole,
|
|
7
|
-
requireTenant,
|
|
8
|
-
requireUser
|
|
9
|
-
} from "./chunk-TF32HGN2.mjs";
|
|
10
|
-
export {
|
|
11
|
-
fromClerkAuth,
|
|
12
|
-
hasRole,
|
|
13
|
-
requireRole,
|
|
14
|
-
requireTenant,
|
|
15
|
-
requireUser
|
|
16
|
-
};
|
package/dist/next.d.mts
DELETED
package/dist/next.d.ts
DELETED
package/dist/next.mjs
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
fromClerkAuth
|
|
3
|
-
} from "./chunk-HWIZ2Q5U.mjs";
|
|
4
|
-
import "./chunk-TF32HGN2.mjs";
|
|
5
|
-
|
|
6
|
-
// src/next.ts
|
|
7
|
-
import { auth } from "@clerk/nextjs";
|
|
8
|
-
function getSession() {
|
|
9
|
-
const clerkAuth = auth();
|
|
10
|
-
return fromClerkAuth(clerkAuth);
|
|
11
|
-
}
|
|
12
|
-
export {
|
|
13
|
-
getSession
|
|
14
|
-
};
|
package/dist/react-native.d.mts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { W as WorkflowSession } from './shared-Z5LN5APr.mjs';
|
|
2
|
-
export { h as hasRole, r as requireRole, a as requireTenant, b as requireUser } from './shared-Z5LN5APr.mjs';
|
|
3
|
-
|
|
4
|
-
declare function mapClerkToSession(auth: {
|
|
5
|
-
userId?: string | null;
|
|
6
|
-
orgId?: string | null;
|
|
7
|
-
session?: {
|
|
8
|
-
user?: {
|
|
9
|
-
publicMetadata?: any;
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
} | null): WorkflowSession;
|
|
13
|
-
|
|
14
|
-
export { WorkflowSession, mapClerkToSession };
|
package/dist/react-native.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { W as WorkflowSession } from './shared-Z5LN5APr.js';
|
|
2
|
-
export { h as hasRole, r as requireRole, a as requireTenant, b as requireUser } from './shared-Z5LN5APr.js';
|
|
3
|
-
|
|
4
|
-
declare function mapClerkToSession(auth: {
|
|
5
|
-
userId?: string | null;
|
|
6
|
-
orgId?: string | null;
|
|
7
|
-
session?: {
|
|
8
|
-
user?: {
|
|
9
|
-
publicMetadata?: any;
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
} | null): WorkflowSession;
|
|
13
|
-
|
|
14
|
-
export { WorkflowSession, mapClerkToSession };
|
package/dist/react-native.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/react-native.ts
|
|
21
|
-
var react_native_exports = {};
|
|
22
|
-
__export(react_native_exports, {
|
|
23
|
-
hasRole: () => hasRole,
|
|
24
|
-
mapClerkToSession: () => mapClerkToSession,
|
|
25
|
-
requireRole: () => requireRole,
|
|
26
|
-
requireTenant: () => requireTenant,
|
|
27
|
-
requireUser: () => requireUser
|
|
28
|
-
});
|
|
29
|
-
module.exports = __toCommonJS(react_native_exports);
|
|
30
|
-
|
|
31
|
-
// src/shared.ts
|
|
32
|
-
var import_errors = require("@wrelik/errors");
|
|
33
|
-
function requireUser(session) {
|
|
34
|
-
if (!session || !session.userId) {
|
|
35
|
-
throw new import_errors.AuthRequiredError();
|
|
36
|
-
}
|
|
37
|
-
return session.userId;
|
|
38
|
-
}
|
|
39
|
-
function requireTenant(session) {
|
|
40
|
-
requireUser(session);
|
|
41
|
-
if (!session || !session.tenantId) {
|
|
42
|
-
throw new import_errors.TenantRequiredError();
|
|
43
|
-
}
|
|
44
|
-
return session.tenantId;
|
|
45
|
-
}
|
|
46
|
-
function hasRole(session, role) {
|
|
47
|
-
if (!session || !session.userId) return false;
|
|
48
|
-
if (!Array.isArray(session.roles)) return false;
|
|
49
|
-
return session.roles.includes(role);
|
|
50
|
-
}
|
|
51
|
-
function requireRole(session, role) {
|
|
52
|
-
if (!hasRole(session, role)) {
|
|
53
|
-
throw new import_errors.PermissionDeniedError(`Role ${role} required`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// src/react-native.ts
|
|
58
|
-
function mapClerkToSession(auth) {
|
|
59
|
-
var _a, _b, _c;
|
|
60
|
-
if (!auth || !auth.userId) {
|
|
61
|
-
return { userId: null, tenantId: null, roles: [] };
|
|
62
|
-
}
|
|
63
|
-
const roles = ((_c = (_b = (_a = auth.session) == null ? void 0 : _a.user) == null ? void 0 : _b.publicMetadata) == null ? void 0 : _c.roles) || [];
|
|
64
|
-
return {
|
|
65
|
-
userId: auth.userId,
|
|
66
|
-
tenantId: auth.orgId || null,
|
|
67
|
-
roles
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
71
|
-
0 && (module.exports = {
|
|
72
|
-
hasRole,
|
|
73
|
-
mapClerkToSession,
|
|
74
|
-
requireRole,
|
|
75
|
-
requireTenant,
|
|
76
|
-
requireUser
|
|
77
|
-
});
|
package/dist/react-native.mjs
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
hasRole,
|
|
3
|
-
requireRole,
|
|
4
|
-
requireTenant,
|
|
5
|
-
requireUser
|
|
6
|
-
} from "./chunk-TF32HGN2.mjs";
|
|
7
|
-
|
|
8
|
-
// src/react-native.ts
|
|
9
|
-
function mapClerkToSession(auth) {
|
|
10
|
-
var _a, _b, _c;
|
|
11
|
-
if (!auth || !auth.userId) {
|
|
12
|
-
return { userId: null, tenantId: null, roles: [] };
|
|
13
|
-
}
|
|
14
|
-
const roles = ((_c = (_b = (_a = auth.session) == null ? void 0 : _a.user) == null ? void 0 : _b.publicMetadata) == null ? void 0 : _c.roles) || [];
|
|
15
|
-
return {
|
|
16
|
-
userId: auth.userId,
|
|
17
|
-
tenantId: auth.orgId || null,
|
|
18
|
-
roles
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
export {
|
|
22
|
-
hasRole,
|
|
23
|
-
mapClerkToSession,
|
|
24
|
-
requireRole,
|
|
25
|
-
requireTenant,
|
|
26
|
-
requireUser
|
|
27
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
interface WorkflowSession {
|
|
2
|
-
userId: string | null;
|
|
3
|
-
tenantId: string | null;
|
|
4
|
-
roles: string[];
|
|
5
|
-
}
|
|
6
|
-
declare function requireUser(session: WorkflowSession | null): string;
|
|
7
|
-
declare function requireTenant(session: WorkflowSession | null): string;
|
|
8
|
-
declare function hasRole(session: WorkflowSession | null, role: string): boolean;
|
|
9
|
-
declare function requireRole(session: WorkflowSession | null, role: string): void;
|
|
10
|
-
|
|
11
|
-
export { type WorkflowSession as W, requireTenant as a, requireUser as b, hasRole as h, requireRole as r };
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
interface WorkflowSession {
|
|
2
|
-
userId: string | null;
|
|
3
|
-
tenantId: string | null;
|
|
4
|
-
roles: string[];
|
|
5
|
-
}
|
|
6
|
-
declare function requireUser(session: WorkflowSession | null): string;
|
|
7
|
-
declare function requireTenant(session: WorkflowSession | null): string;
|
|
8
|
-
declare function hasRole(session: WorkflowSession | null, role: string): boolean;
|
|
9
|
-
declare function requireRole(session: WorkflowSession | null, role: string): void;
|
|
10
|
-
|
|
11
|
-
export { type WorkflowSession as W, requireTenant as a, requireUser as b, hasRole as h, requireRole as r };
|
package/src/index.test.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { requireUser, fromClerkAuth } from './index';
|
|
3
|
-
import { AuthRequiredError } from '@wrelik/errors';
|
|
4
|
-
|
|
5
|
-
describe('@wrelik/auth', () => {
|
|
6
|
-
it('should throw AuthRequiredError if user is null', () => {
|
|
7
|
-
const session = { userId: null, tenantId: null, roles: [] };
|
|
8
|
-
expect(() => requireUser(session)).toThrow(AuthRequiredError);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('should return userId if session is valid', () => {
|
|
12
|
-
const session = { userId: 'user_123', tenantId: null, roles: [] };
|
|
13
|
-
expect(requireUser(session)).toBe('user_123');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should correctly parse Clerk auth object', () => {
|
|
17
|
-
const clerkAuth = {
|
|
18
|
-
userId: 'user_123',
|
|
19
|
-
orgId: 'org_456',
|
|
20
|
-
sessionClaims: { publicMetadata: { roles: ['admin'] } },
|
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
-
} as any;
|
|
23
|
-
|
|
24
|
-
const session = fromClerkAuth(clerkAuth);
|
|
25
|
-
expect(session.userId).toBe('user_123');
|
|
26
|
-
expect(session.tenantId).toBe('org_456');
|
|
27
|
-
expect(session.roles).toContain('admin');
|
|
28
|
-
});
|
|
29
|
-
});
|
package/src/index.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { SignedInAuthObject, SignedOutAuthObject } from '@clerk/backend';
|
|
2
|
-
import { type WorkflowSession } from './shared';
|
|
3
|
-
|
|
4
|
-
export * from './shared';
|
|
5
|
-
|
|
6
|
-
export function fromClerkAuth(
|
|
7
|
-
auth: SignedInAuthObject | SignedOutAuthObject | null,
|
|
8
|
-
): WorkflowSession {
|
|
9
|
-
if (!auth || !auth.userId) {
|
|
10
|
-
return { userId: null, tenantId: null, roles: [] };
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
-
const roles = ((auth.sessionClaims?.publicMetadata as any)?.roles as string[]) || [];
|
|
15
|
-
|
|
16
|
-
return {
|
|
17
|
-
userId: auth.userId,
|
|
18
|
-
tenantId: auth.orgId || null,
|
|
19
|
-
roles,
|
|
20
|
-
};
|
|
21
|
-
}
|
package/src/next.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-restricted-imports */
|
|
2
|
-
import { auth } from '@clerk/nextjs';
|
|
3
|
-
import { fromClerkAuth, type WorkflowSession } from './index';
|
|
4
|
-
|
|
5
|
-
export function getSession(): WorkflowSession {
|
|
6
|
-
const clerkAuth = auth();
|
|
7
|
-
return fromClerkAuth(clerkAuth);
|
|
8
|
-
}
|
package/src/react-native.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { type WorkflowSession } from './shared';
|
|
2
|
-
|
|
3
|
-
export * from './shared';
|
|
4
|
-
|
|
5
|
-
// We accept the `useAuth` or `useUser` return value or similar from Clerk Expo
|
|
6
|
-
// but to be loose coupling, we defined it as any with some shape checks if needed.
|
|
7
|
-
// However, the requirement says "converts the Clerk Expo session/user representation".
|
|
8
|
-
export function mapClerkToSession(
|
|
9
|
-
auth: {
|
|
10
|
-
userId?: string | null;
|
|
11
|
-
orgId?: string | null;
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
-
session?: { user?: { publicMetadata?: any } };
|
|
14
|
-
} | null,
|
|
15
|
-
): WorkflowSession {
|
|
16
|
-
if (!auth || !auth.userId) {
|
|
17
|
-
return { userId: null, tenantId: null, roles: [] };
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// The roles might be in publicMetadata of the user object in session
|
|
21
|
-
const roles = (auth.session?.user?.publicMetadata?.roles as string[]) || [];
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
userId: auth.userId,
|
|
25
|
-
tenantId: auth.orgId || null,
|
|
26
|
-
roles,
|
|
27
|
-
};
|
|
28
|
-
}
|
package/src/shared.test.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { requireUser, requireTenant, hasRole } from './shared';
|
|
3
|
-
|
|
4
|
-
describe('Auth Shared', () => {
|
|
5
|
-
it('requireUser throws if no user', () => {
|
|
6
|
-
expect(() => requireUser(null)).toThrow('Authentication required');
|
|
7
|
-
expect(() => requireUser({ userId: null, tenantId: null, roles: [] })).toThrow(
|
|
8
|
-
'Authentication required',
|
|
9
|
-
);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('requireUser returns userId', () => {
|
|
13
|
-
expect(requireUser({ userId: 'u1', tenantId: null, roles: [] })).toBe('u1');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('requireTenant throws if no tenant', () => {
|
|
17
|
-
expect(() => requireTenant({ userId: 'u1', tenantId: null, roles: [] })).toThrow(
|
|
18
|
-
'Tenant context required',
|
|
19
|
-
);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('hasRole checks roles', () => {
|
|
23
|
-
const session = { userId: 'u1', tenantId: 't1', roles: ['admin'] };
|
|
24
|
-
expect(hasRole(session, 'admin')).toBe(true);
|
|
25
|
-
expect(hasRole(session, 'user')).toBe(false);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('does not grant role access when roles has invalid runtime shape', () => {
|
|
29
|
-
const malformedSession = {
|
|
30
|
-
userId: 'u1',
|
|
31
|
-
tenantId: 't1',
|
|
32
|
-
// Simulates untrusted runtime payload, despite the TypeScript type.
|
|
33
|
-
roles: 'admin',
|
|
34
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
|
-
} as any;
|
|
36
|
-
|
|
37
|
-
expect(hasRole(malformedSession, 'admin')).toBe(false);
|
|
38
|
-
expect(hasRole(malformedSession, 'min')).toBe(false);
|
|
39
|
-
});
|
|
40
|
-
});
|
package/src/shared.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { AuthRequiredError, PermissionDeniedError, TenantRequiredError } from '@wrelik/errors';
|
|
2
|
-
|
|
3
|
-
export interface WorkflowSession {
|
|
4
|
-
userId: string | null;
|
|
5
|
-
tenantId: string | null;
|
|
6
|
-
roles: string[];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function requireUser(session: WorkflowSession | null): string {
|
|
10
|
-
if (!session || !session.userId) {
|
|
11
|
-
throw new AuthRequiredError();
|
|
12
|
-
}
|
|
13
|
-
return session.userId;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function requireTenant(session: WorkflowSession | null): string {
|
|
17
|
-
requireUser(session);
|
|
18
|
-
if (!session || !session.tenantId) {
|
|
19
|
-
throw new TenantRequiredError();
|
|
20
|
-
}
|
|
21
|
-
return session.tenantId;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function hasRole(session: WorkflowSession | null, role: string): boolean {
|
|
25
|
-
if (!session || !session.userId) return false;
|
|
26
|
-
if (!Array.isArray(session.roles)) return false;
|
|
27
|
-
return session.roles.includes(role);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function requireRole(session: WorkflowSession | null, role: string) {
|
|
31
|
-
if (!hasRole(session, role)) {
|
|
32
|
-
throw new PermissionDeniedError(`Role ${role} required`);
|
|
33
|
-
}
|
|
34
|
-
}
|