@infuro/cms-core 1.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/README.md +693 -0
- package/dist/admin.cjs +7119 -0
- package/dist/admin.cjs.map +1 -0
- package/dist/admin.css +75 -0
- package/dist/admin.d.cts +209 -0
- package/dist/admin.d.ts +209 -0
- package/dist/admin.js +7079 -0
- package/dist/admin.js.map +1 -0
- package/dist/api.cjs +1158 -0
- package/dist/api.cjs.map +1 -0
- package/dist/api.d.cts +2 -0
- package/dist/api.d.ts +2 -0
- package/dist/api.js +1112 -0
- package/dist/api.js.map +1 -0
- package/dist/auth.cjs +226 -0
- package/dist/auth.cjs.map +1 -0
- package/dist/auth.d.cts +99 -0
- package/dist/auth.d.ts +99 -0
- package/dist/auth.js +181 -0
- package/dist/auth.js.map +1 -0
- package/dist/config-DJ5CmQvS.d.cts +8 -0
- package/dist/config-DJ5CmQvS.d.ts +8 -0
- package/dist/hooks.cjs +94 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.d.cts +22 -0
- package/dist/hooks.d.ts +22 -0
- package/dist/hooks.js +54 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index-DP3LK1XN.d.cts +263 -0
- package/dist/index-DP3LK1XN.d.ts +263 -0
- package/dist/index.cjs +3008 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +543 -0
- package/dist/index.d.ts +543 -0
- package/dist/index.js +2928 -0
- package/dist/index.js.map +1 -0
- package/dist/theme.cjs +113 -0
- package/dist/theme.cjs.map +1 -0
- package/dist/theme.d.cts +32 -0
- package/dist/theme.d.ts +32 -0
- package/dist/theme.js +73 -0
- package/dist/theme.js.map +1 -0
- package/dist/types-D34wmivy.d.cts +78 -0
- package/dist/types-D34wmivy.d.ts +78 -0
- package/package.json +106 -0
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { NextAuthOptions } from 'next-auth';
|
|
2
|
+
|
|
3
|
+
interface SessionUser {
|
|
4
|
+
id?: string;
|
|
5
|
+
email?: string | null;
|
|
6
|
+
name?: string | null;
|
|
7
|
+
groupId?: number;
|
|
8
|
+
permissions?: string[];
|
|
9
|
+
}
|
|
10
|
+
type GetSession = () => Promise<{
|
|
11
|
+
user?: SessionUser;
|
|
12
|
+
} | null>;
|
|
13
|
+
declare const OPEN_ENDPOINTS: Array<Record<string, string[]>>;
|
|
14
|
+
declare const PERMISSION_REQUIRED_ENDPOINTS: Record<string, string[]>;
|
|
15
|
+
declare function isOpenEndpoint(pathname: string): boolean;
|
|
16
|
+
declare function getRequiredPermission(pathname: string): string[] | null;
|
|
17
|
+
declare function isPublicMethod(pathname: string, method: string): boolean;
|
|
18
|
+
interface AuthHelpers {
|
|
19
|
+
requireAuth(req: Request): Promise<Response | null>;
|
|
20
|
+
requirePermission(req: Request, permission: string): Promise<Response | null>;
|
|
21
|
+
getAuthenticatedUser(): Promise<SessionUser | null>;
|
|
22
|
+
}
|
|
23
|
+
declare function createAuthHelpers(getSession: GetSession, NextResponse: {
|
|
24
|
+
json: (body: unknown, init?: {
|
|
25
|
+
status?: number;
|
|
26
|
+
}) => Response;
|
|
27
|
+
}): AuthHelpers;
|
|
28
|
+
|
|
29
|
+
interface CmsMiddlewareConfig {
|
|
30
|
+
publicAdminPaths?: string[];
|
|
31
|
+
publicApiPaths?: string[];
|
|
32
|
+
/** path -> allowed methods */
|
|
33
|
+
publicApiMethods?: Record<string, string[]>;
|
|
34
|
+
signInPath?: string;
|
|
35
|
+
getSessionToken?: (request: {
|
|
36
|
+
cookies: {
|
|
37
|
+
get: (name: string) => {
|
|
38
|
+
value?: string;
|
|
39
|
+
} | undefined;
|
|
40
|
+
};
|
|
41
|
+
}) => string | undefined;
|
|
42
|
+
}
|
|
43
|
+
/** Default public API paths (no auth). Sites should extend this with their own routes. */
|
|
44
|
+
declare const defaultPublicApiMethods: Record<string, string[]>;
|
|
45
|
+
/**
|
|
46
|
+
* Returns middleware logic. Use from Next.js middleware:
|
|
47
|
+
* import { createCmsMiddleware } from '@infuro/cms-core';
|
|
48
|
+
* export const middleware = createCmsMiddleware({ ... });
|
|
49
|
+
* export const config = { matcher: ['/admin/:path*', '/api/:path*'] };
|
|
50
|
+
*/
|
|
51
|
+
declare function createCmsMiddleware(config?: CmsMiddlewareConfig): (request: {
|
|
52
|
+
nextUrl: {
|
|
53
|
+
pathname: string;
|
|
54
|
+
};
|
|
55
|
+
url: string;
|
|
56
|
+
method: string;
|
|
57
|
+
cookies: {
|
|
58
|
+
get: (name: string) => {
|
|
59
|
+
value?: string;
|
|
60
|
+
} | undefined;
|
|
61
|
+
};
|
|
62
|
+
}) => {
|
|
63
|
+
type: "next";
|
|
64
|
+
} | {
|
|
65
|
+
type: "redirect";
|
|
66
|
+
url: string;
|
|
67
|
+
} | {
|
|
68
|
+
type: "json";
|
|
69
|
+
status: number;
|
|
70
|
+
body: unknown;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Build NextAuth options for credentials auth. App can extend/override via extend().
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
interface NextAuthUser {
|
|
78
|
+
id: number;
|
|
79
|
+
email: string;
|
|
80
|
+
name: string | null;
|
|
81
|
+
password: string | null;
|
|
82
|
+
blocked?: boolean;
|
|
83
|
+
deleted?: boolean;
|
|
84
|
+
groupId?: number | null;
|
|
85
|
+
group?: {
|
|
86
|
+
permissions?: unknown[];
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
interface NextAuthOptionsConfig {
|
|
90
|
+
/** Resolve user by email (e.g. from TypeORM). Return null if not found. */
|
|
91
|
+
getUserByEmail: (email: string) => Promise<NextAuthUser | null>;
|
|
92
|
+
comparePassword: (plain: string, hash: string) => Promise<boolean>;
|
|
93
|
+
signInPage?: string;
|
|
94
|
+
secret?: string;
|
|
95
|
+
extend?: (options: NextAuthOptions) => NextAuthOptions;
|
|
96
|
+
}
|
|
97
|
+
declare function getNextAuthOptions(config: NextAuthOptionsConfig): NextAuthOptions;
|
|
98
|
+
|
|
99
|
+
export { type AuthHelpers, type CmsMiddlewareConfig, type GetSession, type NextAuthOptionsConfig, type NextAuthUser, OPEN_ENDPOINTS, PERMISSION_REQUIRED_ENDPOINTS, type SessionUser, createAuthHelpers, createCmsMiddleware, defaultPublicApiMethods, getNextAuthOptions, getRequiredPermission, isOpenEndpoint, isPublicMethod };
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// src/auth/helpers.ts
|
|
2
|
+
var OPEN_ENDPOINTS = [
|
|
3
|
+
{ "/api/contacts": ["POST"] },
|
|
4
|
+
{ "/api/form-submissions": ["POST"] },
|
|
5
|
+
{ "/api/blogs": ["GET"] }
|
|
6
|
+
];
|
|
7
|
+
var PERMISSION_REQUIRED_ENDPOINTS = {};
|
|
8
|
+
function isOpenEndpoint(pathname) {
|
|
9
|
+
return OPEN_ENDPOINTS.some((endpoint) => pathname.startsWith(Object.keys(endpoint)[0]));
|
|
10
|
+
}
|
|
11
|
+
function getRequiredPermission(pathname) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
function isPublicMethod(pathname, method) {
|
|
15
|
+
for (const endpoint of OPEN_ENDPOINTS) {
|
|
16
|
+
const key = Object.keys(endpoint)[0];
|
|
17
|
+
if (pathname.startsWith(key) && endpoint[key].includes(method)) return true;
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
function createAuthHelpers(getSession, NextResponse) {
|
|
22
|
+
return {
|
|
23
|
+
async requireAuth() {
|
|
24
|
+
const session = await getSession();
|
|
25
|
+
if (!session?.user?.email) {
|
|
26
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
},
|
|
30
|
+
async requirePermission() {
|
|
31
|
+
const session = await getSession();
|
|
32
|
+
if (!session?.user?.email) {
|
|
33
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
},
|
|
37
|
+
async getAuthenticatedUser() {
|
|
38
|
+
const session = await getSession();
|
|
39
|
+
return session?.user ?? null;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/auth/middleware.ts
|
|
45
|
+
var defaultPublicApiMethods = {
|
|
46
|
+
"/api/contacts": ["POST"],
|
|
47
|
+
"/api/form-submissions": ["POST"],
|
|
48
|
+
"/api/blogs": ["GET"],
|
|
49
|
+
"/api/forms": ["GET"],
|
|
50
|
+
"/api/auth": ["GET", "POST"],
|
|
51
|
+
"/api/health": ["GET"],
|
|
52
|
+
"/api/users/forgot-password": ["POST"],
|
|
53
|
+
"/api/users/set-password": ["POST"],
|
|
54
|
+
"/api/users/invite": ["POST"]
|
|
55
|
+
};
|
|
56
|
+
function defaultGetSessionToken(request) {
|
|
57
|
+
return request.cookies.get("__Secure-next-auth.session-token")?.value ?? request.cookies.get("next-auth.session-token")?.value;
|
|
58
|
+
}
|
|
59
|
+
function isPublicMethod2(pathname, method, publicApiMethods) {
|
|
60
|
+
for (const [endpoint, methods] of Object.entries(publicApiMethods)) {
|
|
61
|
+
if (pathname.startsWith(endpoint) && methods.includes(method)) return true;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
function createCmsMiddleware(config = {}) {
|
|
66
|
+
const {
|
|
67
|
+
publicAdminPaths = ["/admin/signin", "/admin/forgot-password", "/admin/reset-password", "/admin/invite"],
|
|
68
|
+
publicApiMethods = defaultPublicApiMethods,
|
|
69
|
+
signInPath = "/admin/signin",
|
|
70
|
+
getSessionToken = defaultGetSessionToken
|
|
71
|
+
} = config;
|
|
72
|
+
return function cmsMiddleware(request) {
|
|
73
|
+
const pathname = request.nextUrl.pathname;
|
|
74
|
+
const method = request.method;
|
|
75
|
+
if (publicAdminPaths.some((p) => pathname === p || pathname.startsWith(p + "/"))) {
|
|
76
|
+
return { type: "next" };
|
|
77
|
+
}
|
|
78
|
+
if (pathname.startsWith("/admin")) {
|
|
79
|
+
const token = getSessionToken(request);
|
|
80
|
+
if (!token) {
|
|
81
|
+
return { type: "redirect", url: new URL(signInPath, request.url).toString() };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (pathname.startsWith("/api")) {
|
|
85
|
+
if (isPublicMethod2(pathname, method, publicApiMethods)) {
|
|
86
|
+
return { type: "next" };
|
|
87
|
+
}
|
|
88
|
+
const token = getSessionToken(request);
|
|
89
|
+
if (!token) {
|
|
90
|
+
return { type: "json", status: 401, body: { error: "Unauthorized" } };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { type: "next" };
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/auth/nextauth-options.ts
|
|
98
|
+
import _CredentialsProvider from "next-auth/providers/credentials";
|
|
99
|
+
var CredentialsProvider = _CredentialsProvider.default ?? _CredentialsProvider;
|
|
100
|
+
function getNextAuthOptions(config) {
|
|
101
|
+
const { getUserByEmail, comparePassword, signInPage = "/admin/signin", secret, extend } = config;
|
|
102
|
+
const options = {
|
|
103
|
+
secret: secret ?? process.env.NEXTAUTH_SECRET,
|
|
104
|
+
providers: [
|
|
105
|
+
CredentialsProvider({
|
|
106
|
+
name: "credentials",
|
|
107
|
+
credentials: {
|
|
108
|
+
email: { label: "Email", type: "email" },
|
|
109
|
+
password: { label: "Password", type: "password" }
|
|
110
|
+
},
|
|
111
|
+
async authorize(credentials) {
|
|
112
|
+
if (!credentials?.email || !credentials?.password) return null;
|
|
113
|
+
try {
|
|
114
|
+
const user = await getUserByEmail(credentials.email);
|
|
115
|
+
if (!user || user.blocked || user.deleted || !user.password) return null;
|
|
116
|
+
const valid = await comparePassword(credentials.password, user.password);
|
|
117
|
+
if (!valid) return null;
|
|
118
|
+
return {
|
|
119
|
+
id: user.id.toString(),
|
|
120
|
+
email: user.email,
|
|
121
|
+
name: user.name,
|
|
122
|
+
groupId: user.groupId ?? void 0,
|
|
123
|
+
permissions: ["admin"]
|
|
124
|
+
};
|
|
125
|
+
} catch {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
],
|
|
131
|
+
session: { strategy: "jwt" },
|
|
132
|
+
pages: { signIn: signInPage },
|
|
133
|
+
cookies: process.env.NODE_ENV === "production" ? {
|
|
134
|
+
sessionToken: {
|
|
135
|
+
name: "__Secure-next-auth.session-token",
|
|
136
|
+
options: { httpOnly: true, sameSite: "lax", path: "/", secure: true }
|
|
137
|
+
}
|
|
138
|
+
} : {
|
|
139
|
+
sessionToken: {
|
|
140
|
+
name: "next-auth.session-token",
|
|
141
|
+
options: {
|
|
142
|
+
httpOnly: true,
|
|
143
|
+
sameSite: "lax",
|
|
144
|
+
path: "/",
|
|
145
|
+
secure: process.env.NEXTAUTH_URL?.startsWith("https") ?? false
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
callbacks: {
|
|
150
|
+
async jwt({ token, user }) {
|
|
151
|
+
if (user) {
|
|
152
|
+
token.id = user.id;
|
|
153
|
+
token.groupId = user.groupId;
|
|
154
|
+
token.permissions = user.permissions;
|
|
155
|
+
}
|
|
156
|
+
return token;
|
|
157
|
+
},
|
|
158
|
+
async session({ session, token }) {
|
|
159
|
+
if (session.user) {
|
|
160
|
+
session.user.id = token.id;
|
|
161
|
+
session.user.groupId = token.groupId;
|
|
162
|
+
session.user.permissions = token.permissions;
|
|
163
|
+
}
|
|
164
|
+
return session;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
return extend ? extend(options) : options;
|
|
169
|
+
}
|
|
170
|
+
export {
|
|
171
|
+
OPEN_ENDPOINTS,
|
|
172
|
+
PERMISSION_REQUIRED_ENDPOINTS,
|
|
173
|
+
createAuthHelpers,
|
|
174
|
+
createCmsMiddleware,
|
|
175
|
+
defaultPublicApiMethods,
|
|
176
|
+
getNextAuthOptions,
|
|
177
|
+
getRequiredPermission,
|
|
178
|
+
isOpenEndpoint,
|
|
179
|
+
isPublicMethod
|
|
180
|
+
};
|
|
181
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth/helpers.ts","../src/auth/middleware.ts","../src/auth/nextauth-options.ts"],"sourcesContent":["export interface SessionUser {\n id?: string;\n email?: string | null;\n name?: string | null;\n groupId?: number;\n permissions?: string[];\n}\n\nexport type GetSession = () => Promise<{ user?: SessionUser } | null>;\n\nexport const OPEN_ENDPOINTS: Array<Record<string, string[]>> = [\n { '/api/contacts': ['POST'] },\n { '/api/form-submissions': ['POST'] },\n { '/api/blogs': ['GET'] },\n];\n\nexport const PERMISSION_REQUIRED_ENDPOINTS: Record<string, string[]> = {};\n\nexport function isOpenEndpoint(pathname: string): boolean {\n return OPEN_ENDPOINTS.some((endpoint) => pathname.startsWith(Object.keys(endpoint)[0]));\n}\n\nexport function getRequiredPermission(pathname: string): string[] | null {\n return null;\n}\n\nexport function isPublicMethod(pathname: string, method: string): boolean {\n for (const endpoint of OPEN_ENDPOINTS) {\n const key = Object.keys(endpoint)[0];\n if (pathname.startsWith(key) && endpoint[key].includes(method)) return true;\n }\n return false;\n}\n\nexport interface AuthHelpers {\n requireAuth(req: Request): Promise<Response | null>;\n requirePermission(req: Request, permission: string): Promise<Response | null>;\n getAuthenticatedUser(): Promise<SessionUser | null>;\n}\n\nexport function createAuthHelpers(getSession: GetSession, NextResponse: { json: (body: unknown, init?: { status?: number }) => Response }): AuthHelpers {\n return {\n async requireAuth() {\n const session = await getSession();\n if (!session?.user?.email) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n }\n return null;\n },\n async requirePermission() {\n const session = await getSession();\n if (!session?.user?.email) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n }\n return null;\n },\n async getAuthenticatedUser() {\n const session = await getSession();\n return session?.user ?? null;\n },\n };\n}\n","export interface CmsMiddlewareConfig {\n publicAdminPaths?: string[];\n publicApiPaths?: string[];\n /** path -> allowed methods */\n publicApiMethods?: Record<string, string[]>;\n signInPath?: string;\n getSessionToken?: (request: { cookies: { get: (name: string) => { value?: string } | undefined } }) => string | undefined;\n}\n\n/** Default public API paths (no auth). Sites should extend this with their own routes. */\nexport const defaultPublicApiMethods: Record<string, string[]> = {\n '/api/contacts': ['POST'],\n '/api/form-submissions': ['POST'],\n '/api/blogs': ['GET'],\n '/api/forms': ['GET'],\n '/api/auth': ['GET', 'POST'],\n '/api/health': ['GET'],\n '/api/users/forgot-password': ['POST'],\n '/api/users/set-password': ['POST'],\n '/api/users/invite': ['POST'],\n};\n\nfunction defaultGetSessionToken(request: { cookies: { get: (name: string) => { value?: string } | undefined } }): string | undefined {\n return (\n request.cookies.get('__Secure-next-auth.session-token')?.value ??\n request.cookies.get('next-auth.session-token')?.value\n );\n}\n\nfunction isPublicMethod(pathname: string, method: string, publicApiMethods: Record<string, string[]>): boolean {\n for (const [endpoint, methods] of Object.entries(publicApiMethods)) {\n if (pathname.startsWith(endpoint) && methods.includes(method)) return true;\n }\n return false;\n}\n\n/**\n * Returns middleware logic. Use from Next.js middleware:\n * import { createCmsMiddleware } from '@infuro/cms-core';\n * export const middleware = createCmsMiddleware({ ... });\n * export const config = { matcher: ['/admin/:path*', '/api/:path*'] };\n */\nexport function createCmsMiddleware(config: CmsMiddlewareConfig = {}) {\n const {\n publicAdminPaths = ['/admin/signin', '/admin/forgot-password', '/admin/reset-password', '/admin/invite'],\n publicApiMethods = defaultPublicApiMethods,\n signInPath = '/admin/signin',\n getSessionToken = defaultGetSessionToken,\n } = config;\n\n return function cmsMiddleware(request: {\n nextUrl: { pathname: string };\n url: string;\n method: string;\n cookies: { get: (name: string) => { value?: string } | undefined };\n }): { type: 'next' } | { type: 'redirect'; url: string } | { type: 'json'; status: number; body: unknown } {\n const pathname = request.nextUrl.pathname;\n const method = request.method;\n\n if (publicAdminPaths.some((p) => pathname === p || pathname.startsWith(p + '/'))) {\n return { type: 'next' };\n }\n\n if (pathname.startsWith('/admin')) {\n const token = getSessionToken(request);\n if (!token) {\n return { type: 'redirect', url: new URL(signInPath, request.url).toString() };\n }\n }\n\n if (pathname.startsWith('/api')) {\n if (isPublicMethod(pathname, method, publicApiMethods)) {\n return { type: 'next' };\n }\n const token = getSessionToken(request);\n if (!token) {\n return { type: 'json', status: 401, body: { error: 'Unauthorized' } };\n }\n }\n\n return { type: 'next' };\n };\n}\n","/**\n * Build NextAuth options for credentials auth. App can extend/override via extend().\n */\nimport type { NextAuthOptions } from 'next-auth';\nimport _CredentialsProvider from 'next-auth/providers/credentials';\nconst CredentialsProvider = (_CredentialsProvider as unknown as { default: typeof _CredentialsProvider }).default ?? _CredentialsProvider;\n\nexport interface NextAuthUser {\n id: number;\n email: string;\n name: string | null;\n password: string | null;\n blocked?: boolean;\n deleted?: boolean;\n groupId?: number | null;\n group?: { permissions?: unknown[] };\n}\n\nexport interface NextAuthOptionsConfig {\n /** Resolve user by email (e.g. from TypeORM). Return null if not found. */\n getUserByEmail: (email: string) => Promise<NextAuthUser | null>;\n comparePassword: (plain: string, hash: string) => Promise<boolean>;\n signInPage?: string;\n secret?: string;\n extend?: (options: NextAuthOptions) => NextAuthOptions;\n}\n\nexport function getNextAuthOptions(config: NextAuthOptionsConfig): NextAuthOptions {\n const { getUserByEmail, comparePassword, signInPage = '/admin/signin', secret, extend } = config;\n\n const options: NextAuthOptions = {\n secret: secret ?? process.env.NEXTAUTH_SECRET,\n providers: [\n CredentialsProvider({\n name: 'credentials',\n credentials: {\n email: { label: 'Email', type: 'email' },\n password: { label: 'Password', type: 'password' },\n },\n async authorize(credentials) {\n if (!credentials?.email || !credentials?.password) return null;\n try {\n const user = await getUserByEmail(credentials.email);\n if (!user || user.blocked || (user as { deleted?: boolean }).deleted || !user.password) return null;\n const valid = await comparePassword(credentials.password, user.password);\n if (!valid) return null;\n return {\n id: user.id.toString(),\n email: user.email,\n name: user.name,\n groupId: user.groupId ?? undefined,\n permissions: ['admin'],\n };\n } catch {\n return null;\n }\n },\n }),\n ],\n session: { strategy: 'jwt' },\n pages: { signIn: signInPage },\n cookies:\n process.env.NODE_ENV === 'production'\n ? {\n sessionToken: {\n name: '__Secure-next-auth.session-token',\n options: { httpOnly: true, sameSite: 'lax', path: '/', secure: true },\n },\n }\n : {\n sessionToken: {\n name: 'next-auth.session-token',\n options: {\n httpOnly: true,\n sameSite: 'lax',\n path: '/',\n secure: process.env.NEXTAUTH_URL?.startsWith('https') ?? false,\n },\n },\n },\n callbacks: {\n async jwt({ token, user }) {\n if (user) {\n (token as Record<string, unknown>).id = user.id;\n (token as Record<string, unknown>).groupId = (user as { groupId?: number }).groupId;\n (token as Record<string, unknown>).permissions = (user as { permissions?: string[] }).permissions;\n }\n return token;\n },\n async session({ session, token }) {\n if (session.user) {\n (session.user as Record<string, unknown>).id = (token as Record<string, unknown>).id;\n (session.user as Record<string, unknown>).groupId = (token as Record<string, unknown>).groupId;\n (session.user as Record<string, unknown>).permissions = (token as Record<string, unknown>).permissions;\n }\n return session;\n },\n },\n };\n\n return extend ? extend(options) : options;\n}\n"],"mappings":"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","names":["isPublicMethod"]}
|
package/dist/hooks.cjs
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/hooks/index.ts
|
|
31
|
+
var hooks_exports = {};
|
|
32
|
+
__export(hooks_exports, {
|
|
33
|
+
PluginProvider: () => PluginProvider,
|
|
34
|
+
useAnalytics: () => useAnalytics,
|
|
35
|
+
useIsMobile: () => useIsMobile,
|
|
36
|
+
usePlugin: () => usePlugin
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(hooks_exports);
|
|
39
|
+
|
|
40
|
+
// src/hooks/use-mobile.ts
|
|
41
|
+
var import_react = require("react");
|
|
42
|
+
var MOBILE_BREAKPOINT = 768;
|
|
43
|
+
function useIsMobile() {
|
|
44
|
+
const [isMobile, setIsMobile] = (0, import_react.useState)(void 0);
|
|
45
|
+
(0, import_react.useEffect)(() => {
|
|
46
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
47
|
+
const onChange = () => setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
48
|
+
mql.addEventListener("change", onChange);
|
|
49
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
50
|
+
return () => mql.removeEventListener("change", onChange);
|
|
51
|
+
}, []);
|
|
52
|
+
return !!isMobile;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/hooks/use-analytics.ts
|
|
56
|
+
var import_react2 = require("react");
|
|
57
|
+
function useAnalytics(pathname) {
|
|
58
|
+
const isAdminRoute = pathname != null && pathname.startsWith("/admin");
|
|
59
|
+
(0, import_react2.useEffect)(() => {
|
|
60
|
+
if (isAdminRoute && typeof window !== "undefined") {
|
|
61
|
+
if (typeof window.gtag === "function") {
|
|
62
|
+
window.gtag = () => {
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (Array.isArray(window.dataLayer)) {
|
|
66
|
+
window.dataLayer = [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}, [isAdminRoute]);
|
|
70
|
+
return { isAdminRoute, shouldTrack: !isAdminRoute };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/hooks/use-plugin.ts
|
|
74
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
75
|
+
var PluginContext = (0, import_react3.createContext)(null);
|
|
76
|
+
function PluginProvider({
|
|
77
|
+
getPlugin,
|
|
78
|
+
children
|
|
79
|
+
}) {
|
|
80
|
+
return import_react3.default.createElement(PluginContext.Provider, { value: { getPlugin } }, children);
|
|
81
|
+
}
|
|
82
|
+
function usePlugin(name) {
|
|
83
|
+
const ctx = (0, import_react3.useContext)(PluginContext);
|
|
84
|
+
if (!ctx) return void 0;
|
|
85
|
+
return ctx.getPlugin(name);
|
|
86
|
+
}
|
|
87
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
88
|
+
0 && (module.exports = {
|
|
89
|
+
PluginProvider,
|
|
90
|
+
useAnalytics,
|
|
91
|
+
useIsMobile,
|
|
92
|
+
usePlugin
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=hooks.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/index.ts","../src/hooks/use-mobile.ts","../src/hooks/use-analytics.ts","../src/hooks/use-plugin.ts"],"sourcesContent":["export { useIsMobile } from './use-mobile';\nexport { useAnalytics } from './use-analytics';\nexport { usePlugin, PluginProvider } from './use-plugin';\n","import { useState, useEffect } from 'react';\n\nconst MOBILE_BREAKPOINT = 768;\n\nexport function useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState<boolean | undefined>(undefined);\n\n useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n const onChange = () => setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n mql.addEventListener('change', onChange);\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n return () => mql.removeEventListener('change', onChange);\n }, []);\n\n return !!isMobile;\n}\n","import { useEffect } from 'react';\n\n/**\n * Call from app with pathname from usePathname() (next/navigation).\n * Disables tracking on admin routes when pathname starts with /admin.\n */\nexport function useAnalytics(pathname: string | null): { isAdminRoute: boolean; shouldTrack: boolean } {\n const isAdminRoute = pathname != null && pathname.startsWith('/admin');\n\n useEffect(() => {\n if (isAdminRoute && typeof window !== 'undefined') {\n if (typeof (window as unknown as { gtag?: () => void }).gtag === 'function') {\n (window as unknown as { gtag: () => void }).gtag = () => {};\n }\n if (Array.isArray((window as unknown as { dataLayer?: unknown[] }).dataLayer)) {\n (window as unknown as { dataLayer: unknown[] }).dataLayer = [];\n }\n }\n }, [isAdminRoute]);\n\n return { isAdminRoute, shouldTrack: !isAdminRoute };\n}\n","import React, { createContext, useContext, type ReactNode } from 'react';\n\nconst PluginContext = createContext<{ getPlugin: <T>(name: string) => T | undefined } | null>(null);\n\nexport function PluginProvider({\n getPlugin,\n children,\n}: {\n getPlugin: <T>(name: string) => T | undefined;\n children: ReactNode;\n}) {\n return React.createElement(PluginContext.Provider, { value: { getPlugin } }, children);\n}\n\nexport function usePlugin<T = unknown>(name: string): T | undefined {\n const ctx = useContext(PluginContext);\n if (!ctx) return undefined;\n return ctx.getPlugin<T>(name);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAoC;AAEpC,IAAM,oBAAoB;AAEnB,SAAS,cAAuB;AACrC,QAAM,CAAC,UAAU,WAAW,QAAI,uBAA8B,MAAS;AAEvE,8BAAU,MAAM;AACd,UAAM,MAAM,OAAO,WAAW,eAAe,oBAAoB,CAAC,KAAK;AACvE,UAAM,WAAW,MAAM,YAAY,OAAO,aAAa,iBAAiB;AACxE,QAAI,iBAAiB,UAAU,QAAQ;AACvC,gBAAY,OAAO,aAAa,iBAAiB;AACjD,WAAO,MAAM,IAAI,oBAAoB,UAAU,QAAQ;AAAA,EACzD,GAAG,CAAC,CAAC;AAEL,SAAO,CAAC,CAAC;AACX;;;AChBA,IAAAA,gBAA0B;AAMnB,SAAS,aAAa,UAA0E;AACrG,QAAM,eAAe,YAAY,QAAQ,SAAS,WAAW,QAAQ;AAErE,+BAAU,MAAM;AACd,QAAI,gBAAgB,OAAO,WAAW,aAAa;AACjD,UAAI,OAAQ,OAA4C,SAAS,YAAY;AAC3E,QAAC,OAA2C,OAAO,MAAM;AAAA,QAAC;AAAA,MAC5D;AACA,UAAI,MAAM,QAAS,OAAgD,SAAS,GAAG;AAC7E,QAAC,OAA+C,YAAY,CAAC;AAAA,MAC/D;AAAA,IACF;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,SAAO,EAAE,cAAc,aAAa,CAAC,aAAa;AACpD;;;ACrBA,IAAAC,gBAAiE;AAEjE,IAAM,oBAAgB,6BAAwE,IAAI;AAE3F,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AACF,GAGG;AACD,SAAO,cAAAC,QAAM,cAAc,cAAc,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,QAAQ;AACvF;AAEO,SAAS,UAAuB,MAA6B;AAClE,QAAM,UAAM,0BAAW,aAAa;AACpC,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,IAAI,UAAa,IAAI;AAC9B;","names":["import_react","import_react","React"]}
|
package/dist/hooks.d.cts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
declare function useIsMobile(): boolean;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Call from app with pathname from usePathname() (next/navigation).
|
|
7
|
+
* Disables tracking on admin routes when pathname starts with /admin.
|
|
8
|
+
*/
|
|
9
|
+
declare function useAnalytics(pathname: string | null): {
|
|
10
|
+
isAdminRoute: boolean;
|
|
11
|
+
shouldTrack: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
declare function PluginProvider({ getPlugin, children, }: {
|
|
15
|
+
getPlugin: <T>(name: string) => T | undefined;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
}): React.FunctionComponentElement<React.ProviderProps<{
|
|
18
|
+
getPlugin: <T>(name: string) => T | undefined;
|
|
19
|
+
} | null>>;
|
|
20
|
+
declare function usePlugin<T = unknown>(name: string): T | undefined;
|
|
21
|
+
|
|
22
|
+
export { PluginProvider, useAnalytics, useIsMobile, usePlugin };
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
declare function useIsMobile(): boolean;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Call from app with pathname from usePathname() (next/navigation).
|
|
7
|
+
* Disables tracking on admin routes when pathname starts with /admin.
|
|
8
|
+
*/
|
|
9
|
+
declare function useAnalytics(pathname: string | null): {
|
|
10
|
+
isAdminRoute: boolean;
|
|
11
|
+
shouldTrack: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
declare function PluginProvider({ getPlugin, children, }: {
|
|
15
|
+
getPlugin: <T>(name: string) => T | undefined;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
}): React.FunctionComponentElement<React.ProviderProps<{
|
|
18
|
+
getPlugin: <T>(name: string) => T | undefined;
|
|
19
|
+
} | null>>;
|
|
20
|
+
declare function usePlugin<T = unknown>(name: string): T | undefined;
|
|
21
|
+
|
|
22
|
+
export { PluginProvider, useAnalytics, useIsMobile, usePlugin };
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/hooks/use-mobile.ts
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
var MOBILE_BREAKPOINT = 768;
|
|
4
|
+
function useIsMobile() {
|
|
5
|
+
const [isMobile, setIsMobile] = useState(void 0);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
8
|
+
const onChange = () => setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
9
|
+
mql.addEventListener("change", onChange);
|
|
10
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
11
|
+
return () => mql.removeEventListener("change", onChange);
|
|
12
|
+
}, []);
|
|
13
|
+
return !!isMobile;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/hooks/use-analytics.ts
|
|
17
|
+
import { useEffect as useEffect2 } from "react";
|
|
18
|
+
function useAnalytics(pathname) {
|
|
19
|
+
const isAdminRoute = pathname != null && pathname.startsWith("/admin");
|
|
20
|
+
useEffect2(() => {
|
|
21
|
+
if (isAdminRoute && typeof window !== "undefined") {
|
|
22
|
+
if (typeof window.gtag === "function") {
|
|
23
|
+
window.gtag = () => {
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(window.dataLayer)) {
|
|
27
|
+
window.dataLayer = [];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}, [isAdminRoute]);
|
|
31
|
+
return { isAdminRoute, shouldTrack: !isAdminRoute };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/hooks/use-plugin.ts
|
|
35
|
+
import React, { createContext, useContext } from "react";
|
|
36
|
+
var PluginContext = createContext(null);
|
|
37
|
+
function PluginProvider({
|
|
38
|
+
getPlugin,
|
|
39
|
+
children
|
|
40
|
+
}) {
|
|
41
|
+
return React.createElement(PluginContext.Provider, { value: { getPlugin } }, children);
|
|
42
|
+
}
|
|
43
|
+
function usePlugin(name) {
|
|
44
|
+
const ctx = useContext(PluginContext);
|
|
45
|
+
if (!ctx) return void 0;
|
|
46
|
+
return ctx.getPlugin(name);
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
PluginProvider,
|
|
50
|
+
useAnalytics,
|
|
51
|
+
useIsMobile,
|
|
52
|
+
usePlugin
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-mobile.ts","../src/hooks/use-analytics.ts","../src/hooks/use-plugin.ts"],"sourcesContent":["import { useState, useEffect } from 'react';\n\nconst MOBILE_BREAKPOINT = 768;\n\nexport function useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState<boolean | undefined>(undefined);\n\n useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n const onChange = () => setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n mql.addEventListener('change', onChange);\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n return () => mql.removeEventListener('change', onChange);\n }, []);\n\n return !!isMobile;\n}\n","import { useEffect } from 'react';\n\n/**\n * Call from app with pathname from usePathname() (next/navigation).\n * Disables tracking on admin routes when pathname starts with /admin.\n */\nexport function useAnalytics(pathname: string | null): { isAdminRoute: boolean; shouldTrack: boolean } {\n const isAdminRoute = pathname != null && pathname.startsWith('/admin');\n\n useEffect(() => {\n if (isAdminRoute && typeof window !== 'undefined') {\n if (typeof (window as unknown as { gtag?: () => void }).gtag === 'function') {\n (window as unknown as { gtag: () => void }).gtag = () => {};\n }\n if (Array.isArray((window as unknown as { dataLayer?: unknown[] }).dataLayer)) {\n (window as unknown as { dataLayer: unknown[] }).dataLayer = [];\n }\n }\n }, [isAdminRoute]);\n\n return { isAdminRoute, shouldTrack: !isAdminRoute };\n}\n","import React, { createContext, useContext, type ReactNode } from 'react';\n\nconst PluginContext = createContext<{ getPlugin: <T>(name: string) => T | undefined } | null>(null);\n\nexport function PluginProvider({\n getPlugin,\n children,\n}: {\n getPlugin: <T>(name: string) => T | undefined;\n children: ReactNode;\n}) {\n return React.createElement(PluginContext.Provider, { value: { getPlugin } }, children);\n}\n\nexport function usePlugin<T = unknown>(name: string): T | undefined {\n const ctx = useContext(PluginContext);\n if (!ctx) return undefined;\n return ctx.getPlugin<T>(name);\n}\n"],"mappings":";AAAA,SAAS,UAAU,iBAAiB;AAEpC,IAAM,oBAAoB;AAEnB,SAAS,cAAuB;AACrC,QAAM,CAAC,UAAU,WAAW,IAAI,SAA8B,MAAS;AAEvE,YAAU,MAAM;AACd,UAAM,MAAM,OAAO,WAAW,eAAe,oBAAoB,CAAC,KAAK;AACvE,UAAM,WAAW,MAAM,YAAY,OAAO,aAAa,iBAAiB;AACxE,QAAI,iBAAiB,UAAU,QAAQ;AACvC,gBAAY,OAAO,aAAa,iBAAiB;AACjD,WAAO,MAAM,IAAI,oBAAoB,UAAU,QAAQ;AAAA,EACzD,GAAG,CAAC,CAAC;AAEL,SAAO,CAAC,CAAC;AACX;;;AChBA,SAAS,aAAAA,kBAAiB;AAMnB,SAAS,aAAa,UAA0E;AACrG,QAAM,eAAe,YAAY,QAAQ,SAAS,WAAW,QAAQ;AAErE,EAAAA,WAAU,MAAM;AACd,QAAI,gBAAgB,OAAO,WAAW,aAAa;AACjD,UAAI,OAAQ,OAA4C,SAAS,YAAY;AAC3E,QAAC,OAA2C,OAAO,MAAM;AAAA,QAAC;AAAA,MAC5D;AACA,UAAI,MAAM,QAAS,OAAgD,SAAS,GAAG;AAC7E,QAAC,OAA+C,YAAY,CAAC;AAAA,MAC/D;AAAA,IACF;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,SAAO,EAAE,cAAc,aAAa,CAAC,aAAa;AACpD;;;ACrBA,OAAO,SAAS,eAAe,kBAAkC;AAEjE,IAAM,gBAAgB,cAAwE,IAAI;AAE3F,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AACF,GAGG;AACD,SAAO,MAAM,cAAc,cAAc,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,QAAQ;AACvF;AAEO,SAAS,UAAuB,MAA6B;AAClE,QAAM,MAAM,WAAW,aAAa;AACpC,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,IAAI,UAAa,IAAI;AAC9B;","names":["useEffect"]}
|