@xylex-group/athena 2.12.0 → 2.13.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/LICENSE +21 -21
- package/README.md +1190 -1184
- package/bin/athena-js.js +104 -76
- package/dist/admin.cjs +45 -0
- package/dist/admin.cjs.map +1 -0
- package/dist/admin.d.cts +64 -0
- package/dist/admin.d.ts +64 -0
- package/dist/admin.js +41 -0
- package/dist/admin.js.map +1 -0
- package/dist/athena-auth-url-oLux_57a.d.cts +377 -0
- package/dist/athena-auth-url-oLux_57a.d.ts +377 -0
- package/dist/browser.cjs +33 -46
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +12 -10
- package/dist/browser.d.ts +12 -10
- package/dist/browser.js +33 -46
- package/dist/browser.js.map +1 -1
- package/dist/cli/index.cjs +150 -48
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +14 -5
- package/dist/cli/index.d.ts +14 -5
- package/dist/cli/index.js +150 -49
- package/dist/cli/index.js.map +1 -1
- package/dist/{client-QUbAs7E8.d.ts → client-BJjUwDSg.d.cts} +109 -1448
- package/dist/{client-C3x75Zgn.d.cts → client-DVOKSYDI.d.ts} +109 -1448
- package/dist/cookies.cjs +18 -0
- package/dist/cookies.cjs.map +1 -1
- package/dist/cookies.d.cts +2 -1
- package/dist/cookies.d.ts +2 -1
- package/dist/cookies.js +17 -1
- package/dist/cookies.js.map +1 -1
- package/dist/{index-CVcQCGyG.d.ts → index-CFL9xbFR.d.cts} +2 -0
- package/dist/{index-CVcQCGyG.d.cts → index-UKJpunc6.d.ts} +2 -0
- package/dist/index.cjs +101 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -10
- package/dist/index.d.ts +13 -10
- package/dist/index.js +101 -47
- package/dist/index.js.map +1 -1
- package/dist/{model-form-CD1uhWSh.d.cts → model-form-Dw4zEL5a.d.cts} +2 -2
- package/dist/{model-form-Dm69I-oO.d.ts → model-form-yRg71q3H.d.ts} +2 -2
- package/dist/{module-CW3tWJ10.d.ts → module-DBteUIob.d.ts} +12 -9
- package/dist/{module-Cxcurfes.d.cts → module-yoX49uQC.d.cts} +12 -9
- package/dist/next/client.cjs +452 -46
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.d.cts +7 -4
- package/dist/next/client.d.ts +7 -4
- package/dist/next/client.js +430 -47
- package/dist/next/client.js.map +1 -1
- package/dist/next/server.cjs +292 -46
- package/dist/next/server.cjs.map +1 -1
- package/dist/next/server.d.cts +81 -5
- package/dist/next/server.d.ts +81 -5
- package/dist/next/server.js +280 -47
- package/dist/next/server.js.map +1 -1
- package/dist/organization.cjs +72 -0
- package/dist/organization.cjs.map +1 -0
- package/dist/organization.d.cts +43 -0
- package/dist/organization.d.ts +43 -0
- package/dist/organization.js +70 -0
- package/dist/organization.js.map +1 -0
- package/dist/payload-BzVbUgY_.d.cts +219 -0
- package/dist/payload-DEOWN_oo.d.ts +219 -0
- package/dist/{pipeline-BAwb6Vzm.d.ts → pipeline-Bj6RWt1A.d.ts} +1 -1
- package/dist/{pipeline-B14jVK7J.d.cts → pipeline-Dwck-wZO.d.cts} +1 -1
- package/dist/react.cjs +2 -10
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +26 -7
- package/dist/react.d.ts +26 -7
- package/dist/react.js +2 -10
- package/dist/react.js.map +1 -1
- package/dist/session-cookie-detection-BqOp9mO6.d.cts +46 -0
- package/dist/session-cookie-detection-BqOp9mO6.d.ts +46 -0
- package/dist/social-providers.cjs +4189 -0
- package/dist/social-providers.cjs.map +1 -0
- package/dist/social-providers.d.cts +4948 -0
- package/dist/social-providers.d.ts +4948 -0
- package/dist/social-providers.js +4117 -0
- package/dist/social-providers.js.map +1 -0
- package/dist/{types-Cq4-NoB4.d.ts → types-BRP7sfSF.d.ts} +50 -2
- package/dist/{types-Dr849HD6.d.cts → types-BU8uJH_b.d.cts} +50 -2
- package/dist/{types-CwJCPpLD.d.ts → types-CH78O90i.d.cts} +2 -2
- package/dist/{types-CwJCPpLD.d.cts → types-CH78O90i.d.ts} +2 -2
- package/dist/{types-DMOoYnPS.d.cts → types-CjC9_5ZQ.d.cts} +3 -3
- package/dist/{types-BcVmPBP-.d.ts → types-DPgejxYC.d.ts} +3 -3
- package/dist/types-eAKAh71s.d.cts +1476 -0
- package/dist/types-eAKAh71s.d.ts +1476 -0
- package/dist/utils.cjs +438 -12
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +76 -11
- package/dist/utils.d.ts +76 -11
- package/dist/utils.js +390 -13
- package/dist/utils.js.map +1 -1
- package/package.json +49 -22
- package/dist/shared-0Kdc74lu.d.ts +0 -35
- package/dist/shared-C0wVICRv.d.cts +0 -35
package/bin/athena-js.js
CHANGED
|
@@ -1,76 +1,104 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
4
|
-
import path from 'node:path'
|
|
5
|
-
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
6
|
-
|
|
7
|
-
const binPath = fileURLToPath(import.meta.url)
|
|
8
|
-
const packageRoot = path.resolve(path.dirname(binPath), '..')
|
|
9
|
-
const cliEntrypointPath = path.resolve(packageRoot, 'dist', 'cli', 'index.js')
|
|
10
|
-
const packageJsonPath = path.resolve(packageRoot, 'package.json')
|
|
11
|
-
|
|
12
|
-
function getInstalledVersion() {
|
|
13
|
-
try {
|
|
14
|
-
const packageJsonRaw = readFileSync(packageJsonPath, 'utf8')
|
|
15
|
-
const packageJson = JSON.parse(packageJsonRaw)
|
|
16
|
-
return typeof packageJson.version === 'string' ? packageJson.version : 'unknown'
|
|
17
|
-
} catch {
|
|
18
|
-
return 'unknown'
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
'
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
6
|
+
|
|
7
|
+
const binPath = fileURLToPath(import.meta.url)
|
|
8
|
+
const packageRoot = path.resolve(path.dirname(binPath), '..')
|
|
9
|
+
const cliEntrypointPath = path.resolve(packageRoot, 'dist', 'cli', 'index.js')
|
|
10
|
+
const packageJsonPath = path.resolve(packageRoot, 'package.json')
|
|
11
|
+
|
|
12
|
+
function getInstalledVersion() {
|
|
13
|
+
try {
|
|
14
|
+
const packageJsonRaw = readFileSync(packageJsonPath, 'utf8')
|
|
15
|
+
const packageJson = JSON.parse(packageJsonRaw)
|
|
16
|
+
return typeof packageJson.version === 'string' ? packageJson.version : 'unknown'
|
|
17
|
+
} catch {
|
|
18
|
+
return 'unknown'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isDebugEnabled() {
|
|
23
|
+
return process.env.ATHENA_JS_DEBUG === '1' || process.env.ATHENA_JS_DEBUG === 'true'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function printMissingEntrypointError() {
|
|
27
|
+
const installedVersion = getInstalledVersion()
|
|
28
|
+
console.error(
|
|
29
|
+
[
|
|
30
|
+
'Failed to start athena-js CLI: package install is missing the generated CLI entrypoint.',
|
|
31
|
+
`Expected file: ${cliEntrypointPath}`,
|
|
32
|
+
`Installed package version: ${installedVersion}`,
|
|
33
|
+
'',
|
|
34
|
+
'Fix by reinstalling the latest package:',
|
|
35
|
+
' pnpm add -g @xylex-group/athena@latest',
|
|
36
|
+
' # or in the project:',
|
|
37
|
+
' pnpm add @xylex-group/athena@latest',
|
|
38
|
+
].join('\n'),
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function formatRuntimeError(error) {
|
|
43
|
+
if (error instanceof Error) {
|
|
44
|
+
if (isDebugEnabled()) {
|
|
45
|
+
return error.stack ?? error.message
|
|
46
|
+
}
|
|
47
|
+
return error.message
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (typeof error === 'string') {
|
|
51
|
+
return error
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return 'Unknown error.'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isAlreadyFormattedCliError(detail) {
|
|
58
|
+
if (typeof detail !== 'string') {
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
61
|
+
return (
|
|
62
|
+
detail.includes('Schema introspection failed') ||
|
|
63
|
+
detail.includes('does not exist (code 3D000)') ||
|
|
64
|
+
detail.includes('Unknown option') ||
|
|
65
|
+
detail.includes('Diagnostics:') ||
|
|
66
|
+
detail.includes('Generated ') ||
|
|
67
|
+
detail.startsWith('[athena-js]')
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function main() {
|
|
72
|
+
if (!existsSync(cliEntrypointPath)) {
|
|
73
|
+
printMissingEntrypointError()
|
|
74
|
+
process.exit(1)
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const cliEntrypointUrl = pathToFileURL(cliEntrypointPath).href
|
|
80
|
+
const cliModule = await import(cliEntrypointUrl)
|
|
81
|
+
if (typeof cliModule.runCLI !== 'function') {
|
|
82
|
+
throw new Error('CLI module does not export runCLI.')
|
|
83
|
+
}
|
|
84
|
+
await cliModule.runCLI(process.argv.slice(2))
|
|
85
|
+
if (typeof process.exitCode === 'number' && process.exitCode !== 0) {
|
|
86
|
+
process.exit(process.exitCode)
|
|
87
|
+
}
|
|
88
|
+
} catch (err) {
|
|
89
|
+
const errorDetail = formatRuntimeError(err)
|
|
90
|
+
if (isAlreadyFormattedCliError(errorDetail)) {
|
|
91
|
+
console.error(errorDetail)
|
|
92
|
+
} else if (errorDetail.includes('\n')) {
|
|
93
|
+
console.error(`Failed to start athena-js CLI:\n${errorDetail}`)
|
|
94
|
+
} else {
|
|
95
|
+
console.error(`Failed to start athena-js CLI: ${errorDetail}`)
|
|
96
|
+
}
|
|
97
|
+
if (isDebugEnabled() && err instanceof Error && err.stack && !String(errorDetail).includes(err.stack)) {
|
|
98
|
+
console.error(err.stack)
|
|
99
|
+
}
|
|
100
|
+
process.exit(1)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
void main()
|
package/dist/admin.cjs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/admin/index.ts
|
|
4
|
+
function hasAdminRole(session) {
|
|
5
|
+
const role = session?.user?.role;
|
|
6
|
+
if (!role) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
return role.split(",").map((item) => item.trim().toLowerCase()).includes("admin");
|
|
10
|
+
}
|
|
11
|
+
async function hasAdminPermission(client, input) {
|
|
12
|
+
if (!input.session?.user?.id) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (input.allowRoleBypass !== false && hasAdminRole(input.session)) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
const result = await client.auth.admin.hasPermission(
|
|
19
|
+
{
|
|
20
|
+
permission: input.permission,
|
|
21
|
+
permissions: input.permissions,
|
|
22
|
+
...input.fetchOptions ? { fetchOptions: input.fetchOptions } : {}
|
|
23
|
+
},
|
|
24
|
+
input.requestOptions
|
|
25
|
+
);
|
|
26
|
+
return Boolean(result.ok && result.data?.success);
|
|
27
|
+
}
|
|
28
|
+
async function resolveAdminPermission(client, input) {
|
|
29
|
+
if (!input.session) {
|
|
30
|
+
return { ok: false, status: 401, error: "Unauthorized" };
|
|
31
|
+
}
|
|
32
|
+
if (!await hasAdminPermission(client, input)) {
|
|
33
|
+
return { ok: false, status: 403, error: "Forbidden" };
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
ok: true,
|
|
37
|
+
session: input.session
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
exports.hasAdminPermission = hasAdminPermission;
|
|
42
|
+
exports.hasAdminRole = hasAdminRole;
|
|
43
|
+
exports.resolveAdminPermission = resolveAdminPermission;
|
|
44
|
+
//# sourceMappingURL=admin.cjs.map
|
|
45
|
+
//# sourceMappingURL=admin.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/admin/index.ts"],"names":[],"mappings":";;;AA4DO,SAAS,aACd,OAAA,EACS;AACT,EAAA,MAAM,IAAA,GAAO,SAAS,IAAA,EAAM,IAAA;AAC5B,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA,CACJ,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAA,IAAA,KAAQ,IAAA,CAAK,IAAA,EAAK,CAAE,WAAA,EAAa,CAAA,CACrC,SAAS,OAAO,CAAA;AACrB;AAQA,eAAsB,kBAAA,CACpB,QACA,KAAA,EACkB;AAClB,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,EAAS,IAAA,EAAM,EAAA,EAAI;AAC5B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,MAAM,eAAA,KAAoB,KAAA,IAAS,YAAA,CAAa,KAAA,CAAM,OAAO,CAAA,EAAG;AAClE,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,aAAA;AAAA,IACrC;AAAA,MACE,YAAY,KAAA,CAAM,UAAA;AAAA,MAClB,aAAa,KAAA,CAAM,WAAA;AAAA,MACnB,GAAI,MAAM,YAAA,GAAe,EAAE,cAAc,KAAA,CAAM,YAAA,KAAiB;AAAC,KACnE;AAAA,IACA,KAAA,CAAM;AAAA,GACR;AAEA,EAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,EAAA,IAAM,MAAA,CAAO,MAAM,OAAO,CAAA;AAClD;AAQA,eAAsB,sBAAA,CAGpB,QACA,KAAA,EAGgD;AAChD,EAAA,IAAI,CAAC,MAAM,OAAA,EAAS;AAClB,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,OAAO,cAAA,EAAe;AAAA,EACzD;AAEA,EAAA,IAAI,CAAE,MAAM,kBAAA,CAAmB,MAAA,EAAQ,KAAK,CAAA,EAAI;AAC9C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,OAAO,WAAA,EAAY;AAAA,EACtD;AAEA,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,IAAA;AAAA,IACJ,SAAS,KAAA,CAAM;AAAA,GACjB;AACF","file":"admin.cjs","sourcesContent":["import type {\n AthenaAdminHasPermissionRequest,\n AthenaAuthBindings,\n AthenaAuthCallOptions,\n AthenaAuthFetchCompatibleInput,\n} from '../auth/types.ts'\n\n/**\n * Minimal session shape used by the admin convenience helpers.\n *\n * This stays framework-agnostic so callers can pass Athena auth sessions,\n * app-local session wrappers, or request-derived session snapshots.\n */\nexport interface AthenaAdminSessionLike {\n user?: {\n id?: string | null | undefined\n role?: string | null | undefined\n } | null | undefined\n session?: {\n token?: string | null | undefined\n activeOrganizationId?: string | null | undefined\n } | null | undefined\n}\n\nexport interface AthenaAdminPermissionClient {\n auth: Pick<AthenaAuthBindings, 'admin'>\n}\n\nexport interface AthenaAdminPermissionCheckInput {\n session: AthenaAdminSessionLike | null | undefined\n permissions: AthenaAdminHasPermissionRequest['permissions']\n permission?: AthenaAdminHasPermissionRequest['permission']\n fetchOptions?: AthenaAuthFetchCompatibleInput['fetchOptions']\n requestOptions?: AthenaAuthCallOptions\n allowRoleBypass?: boolean\n}\n\nexport interface AthenaAdminPermissionSuccess<\n TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike,\n> {\n ok: true\n session: NonNullable<TSession>\n}\n\nexport interface AthenaAdminPermissionFailure {\n ok: false\n status: 401 | 403\n error: 'Unauthorized' | 'Forbidden'\n}\n\nexport type AthenaAdminPermissionResult<\n TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike,\n> = AthenaAdminPermissionSuccess<TSession> | AthenaAdminPermissionFailure\n\n/**\n * Returns true when the session user already carries the `admin` role locally.\n *\n * Role strings are treated as a comma-separated list and normalized\n * case-insensitively so `\"admin\"`, `\"ADMIN\"`, and `\"member, admin\"` all pass.\n */\nexport function hasAdminRole(\n session: AthenaAdminSessionLike | null | undefined,\n): boolean {\n const role = session?.user?.role\n if (!role) {\n return false\n }\n\n return role\n .split(',')\n .map(item => item.trim().toLowerCase())\n .includes('admin')\n}\n\n/**\n * Checks admin permission against the configured Athena auth client.\n *\n * This helper short-circuits when no session user is present and, by default,\n * trusts a local `admin` role before calling `client.auth.admin.hasPermission(...)`.\n */\nexport async function hasAdminPermission(\n client: AthenaAdminPermissionClient,\n input: AthenaAdminPermissionCheckInput,\n): Promise<boolean> {\n if (!input.session?.user?.id) {\n return false\n }\n\n if (input.allowRoleBypass !== false && hasAdminRole(input.session)) {\n return true\n }\n\n const result = await client.auth.admin.hasPermission(\n {\n permission: input.permission,\n permissions: input.permissions,\n ...(input.fetchOptions ? { fetchOptions: input.fetchOptions } : {}),\n },\n input.requestOptions,\n )\n\n return Boolean(result.ok && result.data?.success)\n}\n\n/**\n * Resolves an admin permission check into a small framework-agnostic guard result.\n *\n * Consumers can map the returned `{ ok, status, error }` shape into Next.js,\n * Hono, Express, or any other response layer without importing framework types here.\n */\nexport async function resolveAdminPermission<\n TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike,\n>(\n client: AthenaAdminPermissionClient,\n input: Omit<AthenaAdminPermissionCheckInput, 'session'> & {\n session: TSession | null | undefined\n },\n): Promise<AthenaAdminPermissionResult<TSession>> {\n if (!input.session) {\n return { ok: false, status: 401, error: 'Unauthorized' }\n }\n\n if (!(await hasAdminPermission(client, input))) {\n return { ok: false, status: 403, error: 'Forbidden' }\n }\n\n return {\n ok: true,\n session: input.session as NonNullable<TSession>,\n }\n}\n"]}
|
package/dist/admin.d.cts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { aF as AthenaAdminHasPermissionRequest, aG as AthenaAuthFetchCompatibleInput, E as AthenaAuthCallOptions, D as AthenaAuthBindings } from './types-eAKAh71s.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal session shape used by the admin convenience helpers.
|
|
5
|
+
*
|
|
6
|
+
* This stays framework-agnostic so callers can pass Athena auth sessions,
|
|
7
|
+
* app-local session wrappers, or request-derived session snapshots.
|
|
8
|
+
*/
|
|
9
|
+
interface AthenaAdminSessionLike {
|
|
10
|
+
user?: {
|
|
11
|
+
id?: string | null | undefined;
|
|
12
|
+
role?: string | null | undefined;
|
|
13
|
+
} | null | undefined;
|
|
14
|
+
session?: {
|
|
15
|
+
token?: string | null | undefined;
|
|
16
|
+
activeOrganizationId?: string | null | undefined;
|
|
17
|
+
} | null | undefined;
|
|
18
|
+
}
|
|
19
|
+
interface AthenaAdminPermissionClient {
|
|
20
|
+
auth: Pick<AthenaAuthBindings, 'admin'>;
|
|
21
|
+
}
|
|
22
|
+
interface AthenaAdminPermissionCheckInput {
|
|
23
|
+
session: AthenaAdminSessionLike | null | undefined;
|
|
24
|
+
permissions: AthenaAdminHasPermissionRequest['permissions'];
|
|
25
|
+
permission?: AthenaAdminHasPermissionRequest['permission'];
|
|
26
|
+
fetchOptions?: AthenaAuthFetchCompatibleInput['fetchOptions'];
|
|
27
|
+
requestOptions?: AthenaAuthCallOptions;
|
|
28
|
+
allowRoleBypass?: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface AthenaAdminPermissionSuccess<TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike> {
|
|
31
|
+
ok: true;
|
|
32
|
+
session: NonNullable<TSession>;
|
|
33
|
+
}
|
|
34
|
+
interface AthenaAdminPermissionFailure {
|
|
35
|
+
ok: false;
|
|
36
|
+
status: 401 | 403;
|
|
37
|
+
error: 'Unauthorized' | 'Forbidden';
|
|
38
|
+
}
|
|
39
|
+
type AthenaAdminPermissionResult<TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike> = AthenaAdminPermissionSuccess<TSession> | AthenaAdminPermissionFailure;
|
|
40
|
+
/**
|
|
41
|
+
* Returns true when the session user already carries the `admin` role locally.
|
|
42
|
+
*
|
|
43
|
+
* Role strings are treated as a comma-separated list and normalized
|
|
44
|
+
* case-insensitively so `"admin"`, `"ADMIN"`, and `"member, admin"` all pass.
|
|
45
|
+
*/
|
|
46
|
+
declare function hasAdminRole(session: AthenaAdminSessionLike | null | undefined): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Checks admin permission against the configured Athena auth client.
|
|
49
|
+
*
|
|
50
|
+
* This helper short-circuits when no session user is present and, by default,
|
|
51
|
+
* trusts a local `admin` role before calling `client.auth.admin.hasPermission(...)`.
|
|
52
|
+
*/
|
|
53
|
+
declare function hasAdminPermission(client: AthenaAdminPermissionClient, input: AthenaAdminPermissionCheckInput): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* Resolves an admin permission check into a small framework-agnostic guard result.
|
|
56
|
+
*
|
|
57
|
+
* Consumers can map the returned `{ ok, status, error }` shape into Next.js,
|
|
58
|
+
* Hono, Express, or any other response layer without importing framework types here.
|
|
59
|
+
*/
|
|
60
|
+
declare function resolveAdminPermission<TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike>(client: AthenaAdminPermissionClient, input: Omit<AthenaAdminPermissionCheckInput, 'session'> & {
|
|
61
|
+
session: TSession | null | undefined;
|
|
62
|
+
}): Promise<AthenaAdminPermissionResult<TSession>>;
|
|
63
|
+
|
|
64
|
+
export { type AthenaAdminPermissionCheckInput, type AthenaAdminPermissionClient, type AthenaAdminPermissionFailure, type AthenaAdminPermissionResult, type AthenaAdminPermissionSuccess, type AthenaAdminSessionLike, hasAdminPermission, hasAdminRole, resolveAdminPermission };
|
package/dist/admin.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { aF as AthenaAdminHasPermissionRequest, aG as AthenaAuthFetchCompatibleInput, E as AthenaAuthCallOptions, D as AthenaAuthBindings } from './types-eAKAh71s.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal session shape used by the admin convenience helpers.
|
|
5
|
+
*
|
|
6
|
+
* This stays framework-agnostic so callers can pass Athena auth sessions,
|
|
7
|
+
* app-local session wrappers, or request-derived session snapshots.
|
|
8
|
+
*/
|
|
9
|
+
interface AthenaAdminSessionLike {
|
|
10
|
+
user?: {
|
|
11
|
+
id?: string | null | undefined;
|
|
12
|
+
role?: string | null | undefined;
|
|
13
|
+
} | null | undefined;
|
|
14
|
+
session?: {
|
|
15
|
+
token?: string | null | undefined;
|
|
16
|
+
activeOrganizationId?: string | null | undefined;
|
|
17
|
+
} | null | undefined;
|
|
18
|
+
}
|
|
19
|
+
interface AthenaAdminPermissionClient {
|
|
20
|
+
auth: Pick<AthenaAuthBindings, 'admin'>;
|
|
21
|
+
}
|
|
22
|
+
interface AthenaAdminPermissionCheckInput {
|
|
23
|
+
session: AthenaAdminSessionLike | null | undefined;
|
|
24
|
+
permissions: AthenaAdminHasPermissionRequest['permissions'];
|
|
25
|
+
permission?: AthenaAdminHasPermissionRequest['permission'];
|
|
26
|
+
fetchOptions?: AthenaAuthFetchCompatibleInput['fetchOptions'];
|
|
27
|
+
requestOptions?: AthenaAuthCallOptions;
|
|
28
|
+
allowRoleBypass?: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface AthenaAdminPermissionSuccess<TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike> {
|
|
31
|
+
ok: true;
|
|
32
|
+
session: NonNullable<TSession>;
|
|
33
|
+
}
|
|
34
|
+
interface AthenaAdminPermissionFailure {
|
|
35
|
+
ok: false;
|
|
36
|
+
status: 401 | 403;
|
|
37
|
+
error: 'Unauthorized' | 'Forbidden';
|
|
38
|
+
}
|
|
39
|
+
type AthenaAdminPermissionResult<TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike> = AthenaAdminPermissionSuccess<TSession> | AthenaAdminPermissionFailure;
|
|
40
|
+
/**
|
|
41
|
+
* Returns true when the session user already carries the `admin` role locally.
|
|
42
|
+
*
|
|
43
|
+
* Role strings are treated as a comma-separated list and normalized
|
|
44
|
+
* case-insensitively so `"admin"`, `"ADMIN"`, and `"member, admin"` all pass.
|
|
45
|
+
*/
|
|
46
|
+
declare function hasAdminRole(session: AthenaAdminSessionLike | null | undefined): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Checks admin permission against the configured Athena auth client.
|
|
49
|
+
*
|
|
50
|
+
* This helper short-circuits when no session user is present and, by default,
|
|
51
|
+
* trusts a local `admin` role before calling `client.auth.admin.hasPermission(...)`.
|
|
52
|
+
*/
|
|
53
|
+
declare function hasAdminPermission(client: AthenaAdminPermissionClient, input: AthenaAdminPermissionCheckInput): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* Resolves an admin permission check into a small framework-agnostic guard result.
|
|
56
|
+
*
|
|
57
|
+
* Consumers can map the returned `{ ok, status, error }` shape into Next.js,
|
|
58
|
+
* Hono, Express, or any other response layer without importing framework types here.
|
|
59
|
+
*/
|
|
60
|
+
declare function resolveAdminPermission<TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike>(client: AthenaAdminPermissionClient, input: Omit<AthenaAdminPermissionCheckInput, 'session'> & {
|
|
61
|
+
session: TSession | null | undefined;
|
|
62
|
+
}): Promise<AthenaAdminPermissionResult<TSession>>;
|
|
63
|
+
|
|
64
|
+
export { type AthenaAdminPermissionCheckInput, type AthenaAdminPermissionClient, type AthenaAdminPermissionFailure, type AthenaAdminPermissionResult, type AthenaAdminPermissionSuccess, type AthenaAdminSessionLike, hasAdminPermission, hasAdminRole, resolveAdminPermission };
|
package/dist/admin.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/admin/index.ts
|
|
2
|
+
function hasAdminRole(session) {
|
|
3
|
+
const role = session?.user?.role;
|
|
4
|
+
if (!role) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
return role.split(",").map((item) => item.trim().toLowerCase()).includes("admin");
|
|
8
|
+
}
|
|
9
|
+
async function hasAdminPermission(client, input) {
|
|
10
|
+
if (!input.session?.user?.id) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
if (input.allowRoleBypass !== false && hasAdminRole(input.session)) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
const result = await client.auth.admin.hasPermission(
|
|
17
|
+
{
|
|
18
|
+
permission: input.permission,
|
|
19
|
+
permissions: input.permissions,
|
|
20
|
+
...input.fetchOptions ? { fetchOptions: input.fetchOptions } : {}
|
|
21
|
+
},
|
|
22
|
+
input.requestOptions
|
|
23
|
+
);
|
|
24
|
+
return Boolean(result.ok && result.data?.success);
|
|
25
|
+
}
|
|
26
|
+
async function resolveAdminPermission(client, input) {
|
|
27
|
+
if (!input.session) {
|
|
28
|
+
return { ok: false, status: 401, error: "Unauthorized" };
|
|
29
|
+
}
|
|
30
|
+
if (!await hasAdminPermission(client, input)) {
|
|
31
|
+
return { ok: false, status: 403, error: "Forbidden" };
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
ok: true,
|
|
35
|
+
session: input.session
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { hasAdminPermission, hasAdminRole, resolveAdminPermission };
|
|
40
|
+
//# sourceMappingURL=admin.js.map
|
|
41
|
+
//# sourceMappingURL=admin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/admin/index.ts"],"names":[],"mappings":";AA4DO,SAAS,aACd,OAAA,EACS;AACT,EAAA,MAAM,IAAA,GAAO,SAAS,IAAA,EAAM,IAAA;AAC5B,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA,CACJ,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAA,IAAA,KAAQ,IAAA,CAAK,IAAA,EAAK,CAAE,WAAA,EAAa,CAAA,CACrC,SAAS,OAAO,CAAA;AACrB;AAQA,eAAsB,kBAAA,CACpB,QACA,KAAA,EACkB;AAClB,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,EAAS,IAAA,EAAM,EAAA,EAAI;AAC5B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,MAAM,eAAA,KAAoB,KAAA,IAAS,YAAA,CAAa,KAAA,CAAM,OAAO,CAAA,EAAG;AAClE,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,aAAA;AAAA,IACrC;AAAA,MACE,YAAY,KAAA,CAAM,UAAA;AAAA,MAClB,aAAa,KAAA,CAAM,WAAA;AAAA,MACnB,GAAI,MAAM,YAAA,GAAe,EAAE,cAAc,KAAA,CAAM,YAAA,KAAiB;AAAC,KACnE;AAAA,IACA,KAAA,CAAM;AAAA,GACR;AAEA,EAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,EAAA,IAAM,MAAA,CAAO,MAAM,OAAO,CAAA;AAClD;AAQA,eAAsB,sBAAA,CAGpB,QACA,KAAA,EAGgD;AAChD,EAAA,IAAI,CAAC,MAAM,OAAA,EAAS;AAClB,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,OAAO,cAAA,EAAe;AAAA,EACzD;AAEA,EAAA,IAAI,CAAE,MAAM,kBAAA,CAAmB,MAAA,EAAQ,KAAK,CAAA,EAAI;AAC9C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,OAAO,WAAA,EAAY;AAAA,EACtD;AAEA,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,IAAA;AAAA,IACJ,SAAS,KAAA,CAAM;AAAA,GACjB;AACF","file":"admin.js","sourcesContent":["import type {\n AthenaAdminHasPermissionRequest,\n AthenaAuthBindings,\n AthenaAuthCallOptions,\n AthenaAuthFetchCompatibleInput,\n} from '../auth/types.ts'\n\n/**\n * Minimal session shape used by the admin convenience helpers.\n *\n * This stays framework-agnostic so callers can pass Athena auth sessions,\n * app-local session wrappers, or request-derived session snapshots.\n */\nexport interface AthenaAdminSessionLike {\n user?: {\n id?: string | null | undefined\n role?: string | null | undefined\n } | null | undefined\n session?: {\n token?: string | null | undefined\n activeOrganizationId?: string | null | undefined\n } | null | undefined\n}\n\nexport interface AthenaAdminPermissionClient {\n auth: Pick<AthenaAuthBindings, 'admin'>\n}\n\nexport interface AthenaAdminPermissionCheckInput {\n session: AthenaAdminSessionLike | null | undefined\n permissions: AthenaAdminHasPermissionRequest['permissions']\n permission?: AthenaAdminHasPermissionRequest['permission']\n fetchOptions?: AthenaAuthFetchCompatibleInput['fetchOptions']\n requestOptions?: AthenaAuthCallOptions\n allowRoleBypass?: boolean\n}\n\nexport interface AthenaAdminPermissionSuccess<\n TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike,\n> {\n ok: true\n session: NonNullable<TSession>\n}\n\nexport interface AthenaAdminPermissionFailure {\n ok: false\n status: 401 | 403\n error: 'Unauthorized' | 'Forbidden'\n}\n\nexport type AthenaAdminPermissionResult<\n TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike,\n> = AthenaAdminPermissionSuccess<TSession> | AthenaAdminPermissionFailure\n\n/**\n * Returns true when the session user already carries the `admin` role locally.\n *\n * Role strings are treated as a comma-separated list and normalized\n * case-insensitively so `\"admin\"`, `\"ADMIN\"`, and `\"member, admin\"` all pass.\n */\nexport function hasAdminRole(\n session: AthenaAdminSessionLike | null | undefined,\n): boolean {\n const role = session?.user?.role\n if (!role) {\n return false\n }\n\n return role\n .split(',')\n .map(item => item.trim().toLowerCase())\n .includes('admin')\n}\n\n/**\n * Checks admin permission against the configured Athena auth client.\n *\n * This helper short-circuits when no session user is present and, by default,\n * trusts a local `admin` role before calling `client.auth.admin.hasPermission(...)`.\n */\nexport async function hasAdminPermission(\n client: AthenaAdminPermissionClient,\n input: AthenaAdminPermissionCheckInput,\n): Promise<boolean> {\n if (!input.session?.user?.id) {\n return false\n }\n\n if (input.allowRoleBypass !== false && hasAdminRole(input.session)) {\n return true\n }\n\n const result = await client.auth.admin.hasPermission(\n {\n permission: input.permission,\n permissions: input.permissions,\n ...(input.fetchOptions ? { fetchOptions: input.fetchOptions } : {}),\n },\n input.requestOptions,\n )\n\n return Boolean(result.ok && result.data?.success)\n}\n\n/**\n * Resolves an admin permission check into a small framework-agnostic guard result.\n *\n * Consumers can map the returned `{ ok, status, error }` shape into Next.js,\n * Hono, Express, or any other response layer without importing framework types here.\n */\nexport async function resolveAdminPermission<\n TSession extends AthenaAdminSessionLike = AthenaAdminSessionLike,\n>(\n client: AthenaAdminPermissionClient,\n input: Omit<AthenaAdminPermissionCheckInput, 'session'> & {\n session: TSession | null | undefined\n },\n): Promise<AthenaAdminPermissionResult<TSession>> {\n if (!input.session) {\n return { ok: false, status: 401, error: 'Unauthorized' }\n }\n\n if (!(await hasAdminPermission(client, input))) {\n return { ok: false, status: 403, error: 'Forbidden' }\n }\n\n return {\n ok: true,\n session: input.session as NonNullable<TSession>,\n }\n}\n"]}
|