@adminforge/core 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +56 -0
- package/CHANGELOG.md +32 -0
- package/LICENSE +21 -0
- package/bin/adminforge.js +317 -0
- package/dist/auth-client.cjs +45 -0
- package/dist/auth-client.cjs.map +1 -0
- package/dist/auth-client.d.cts +17 -0
- package/dist/auth-client.d.ts +17 -0
- package/dist/auth-client.js +20 -0
- package/dist/auth-client.js.map +1 -0
- package/dist/auth.cjs +65 -0
- package/dist/auth.cjs.map +1 -0
- package/dist/auth.d.cts +21 -0
- package/dist/auth.d.ts +21 -0
- package/dist/auth.js +36 -0
- package/dist/auth.js.map +1 -0
- package/dist/client-D0cjJVsn.d.ts +20 -0
- package/dist/client-sRnmZ-Y9.d.cts +20 -0
- package/dist/index-CyzxaE7n.d.cts +124 -0
- package/dist/index-CyzxaE7n.d.ts +124 -0
- package/dist/index.cjs +453 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +410 -0
- package/dist/index.js.map +1 -0
- package/dist/next.cjs +839 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +84 -0
- package/dist/next.d.ts +84 -0
- package/dist/next.js +800 -0
- package/dist/next.js.map +1 -0
- package/dist/styles.css +763 -0
- package/dist/styles.css.map +1 -0
- package/dist/styles.d.cts +2 -0
- package/dist/styles.d.ts +2 -0
- package/dist/ui.cjs +2500 -0
- package/dist/ui.cjs.map +1 -0
- package/dist/ui.d.cts +119 -0
- package/dist/ui.d.ts +119 -0
- package/dist/ui.js +2448 -0
- package/dist/ui.js.map +1 -0
- package/eslint.config.js +35 -0
- package/package.json +99 -0
- package/src/api/controller.ts +234 -0
- package/src/api/index.ts +4 -0
- package/src/api/next.ts +281 -0
- package/src/api/security/agent-auth.ts +134 -0
- package/src/auth/config.ts +20 -0
- package/src/auth/index.ts +3 -0
- package/src/auth/middleware.ts +15 -0
- package/src/auth/provider.tsx +28 -0
- package/src/core/fields/index.ts +119 -0
- package/src/core/hooks/index.ts +60 -0
- package/src/core/index.ts +43 -0
- package/src/core/registry/index.ts +22 -0
- package/src/core/schema/collection.ts +12 -0
- package/src/core/schema/config.ts +11 -0
- package/src/core/schema/normalize.ts +32 -0
- package/src/core/types/index.ts +114 -0
- package/src/db/client.ts +146 -0
- package/src/db/index.ts +3 -0
- package/src/db/schema-generator.ts +104 -0
- package/src/fields/index.ts +1 -0
- package/src/index.ts +4 -0
- package/src/next.ts +3 -0
- package/src/styles/adminforge.css +840 -0
- package/src/ui/AdminDashboard.tsx +176 -0
- package/src/ui/AdminForgeContext.tsx +64 -0
- package/src/ui/components/AdminLayout.tsx +107 -0
- package/src/ui/form-engine/FormEngine.tsx +250 -0
- package/src/ui/form-engine/ImageUpload.tsx +68 -0
- package/src/ui/form-engine/RelationInput.tsx +215 -0
- package/src/ui/form-engine/RichTextEditor.tsx +708 -0
- package/src/ui/index.ts +18 -0
- package/src/ui/screens/AdminPage.tsx +162 -0
- package/src/ui/screens/AgentTokenPage.tsx +232 -0
- package/src/ui/screens/CollectionFormPage.tsx +135 -0
- package/src/ui/screens/CollectionListPage.tsx +170 -0
- package/src/ui/screens/CollectionSchemaPage.tsx +180 -0
- package/src/ui/screens/RoleDetailPage.tsx +147 -0
- package/src/ui/screens/RolesListPage.tsx +57 -0
- package/src/ui/table-engine/TableEngine.tsx +157 -0
- package/src/ui.ts +3 -0
- package/tsconfig.json +10 -0
- package/tsup.config.ts +54 -0
package/dist/next.cjs
ADDED
|
@@ -0,0 +1,839 @@
|
|
|
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 __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// src/api/security/agent-auth.ts
|
|
34
|
+
var agent_auth_exports = {};
|
|
35
|
+
__export(agent_auth_exports, {
|
|
36
|
+
assertScope: () => assertScope,
|
|
37
|
+
generateAgentToken: () => generateAgentToken,
|
|
38
|
+
verifyAgentToken: () => verifyAgentToken
|
|
39
|
+
});
|
|
40
|
+
function getSecret() {
|
|
41
|
+
const secret = process.env.ADMINFORGE_SECRET;
|
|
42
|
+
if (!secret) {
|
|
43
|
+
throw new Error("ADMINFORGE_SECRET env var is required. Generate one with: openssl rand -hex 32");
|
|
44
|
+
}
|
|
45
|
+
return secret;
|
|
46
|
+
}
|
|
47
|
+
function normalizeScope(scope) {
|
|
48
|
+
const normalized = scope.trim().toLowerCase();
|
|
49
|
+
if (!/^[a-z0-9_-]+:[a-z]+$/.test(normalized)) {
|
|
50
|
+
throw new Error(`Malformed scope format: ${scope}`);
|
|
51
|
+
}
|
|
52
|
+
return normalized;
|
|
53
|
+
}
|
|
54
|
+
function assertValidAction(action) {
|
|
55
|
+
const validActions = ["create", "read", "update", "delete"];
|
|
56
|
+
if (!validActions.includes(action)) {
|
|
57
|
+
throw new Error(`Invalid action: ${action}`);
|
|
58
|
+
}
|
|
59
|
+
return action;
|
|
60
|
+
}
|
|
61
|
+
function assertValidCollection(collection2) {
|
|
62
|
+
if (!/^[a-z0-9_-]+$/.test(collection2)) {
|
|
63
|
+
throw new Error(`Invalid collection name: ${collection2}`);
|
|
64
|
+
}
|
|
65
|
+
return collection2;
|
|
66
|
+
}
|
|
67
|
+
function generateAgentToken(userId, role, scopes, expiresInSeconds = 600) {
|
|
68
|
+
const normalizedScopes = scopes.map(normalizeScope);
|
|
69
|
+
return import_jsonwebtoken.default.sign(
|
|
70
|
+
{
|
|
71
|
+
sub: userId,
|
|
72
|
+
role,
|
|
73
|
+
scope: normalizedScopes,
|
|
74
|
+
sessionId: import_crypto.default.randomUUID()
|
|
75
|
+
},
|
|
76
|
+
getSecret(),
|
|
77
|
+
{
|
|
78
|
+
expiresIn: expiresInSeconds,
|
|
79
|
+
issuer: "adminforge",
|
|
80
|
+
audience: "agent"
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
function isRevoked(sessionId) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
function verifyAgentToken(token) {
|
|
88
|
+
try {
|
|
89
|
+
const payload = import_jsonwebtoken.default.verify(token, getSecret(), {
|
|
90
|
+
issuer: "adminforge",
|
|
91
|
+
audience: "agent"
|
|
92
|
+
});
|
|
93
|
+
if (!payload.sub) throw new Error("Missing userId (sub)");
|
|
94
|
+
if (!payload.role) throw new Error("Missing role");
|
|
95
|
+
if (!Array.isArray(payload.scope)) throw new Error("Invalid scope format");
|
|
96
|
+
if (isRevoked(payload.sessionId)) {
|
|
97
|
+
throw new Error("Session revoked");
|
|
98
|
+
}
|
|
99
|
+
payload.scope = payload.scope.map(normalizeScope);
|
|
100
|
+
return payload;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
throw new Error(`Unauthorized: ${error.message}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function assertScope(agent, collection2, action) {
|
|
106
|
+
const validColl = assertValidCollection(collection2);
|
|
107
|
+
const validAction = assertValidAction(action);
|
|
108
|
+
const key = `${validColl}:${validAction}`.toLowerCase();
|
|
109
|
+
if (!agent.scope.includes(key)) {
|
|
110
|
+
throw new Error(`Forbidden: Missing scope ${key}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
var import_jsonwebtoken, import_crypto;
|
|
114
|
+
var init_agent_auth = __esm({
|
|
115
|
+
"src/api/security/agent-auth.ts"() {
|
|
116
|
+
"use strict";
|
|
117
|
+
import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
|
|
118
|
+
import_crypto = __toESM(require("crypto"), 1);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// src/core/schema/config.ts
|
|
123
|
+
function defineConfig(config) {
|
|
124
|
+
return {
|
|
125
|
+
collections: config.collections,
|
|
126
|
+
auth: config.auth ?? { enabled: false }
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
var init_config = __esm({
|
|
130
|
+
"src/core/schema/config.ts"() {
|
|
131
|
+
"use strict";
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// src/core/schema/collection.ts
|
|
136
|
+
function collection(input) {
|
|
137
|
+
return {
|
|
138
|
+
name: input.name,
|
|
139
|
+
label: input.label ?? input.name.charAt(0).toUpperCase() + input.name.slice(1),
|
|
140
|
+
icon: input.icon,
|
|
141
|
+
fields: input.fields,
|
|
142
|
+
hooks: input.hooks,
|
|
143
|
+
access: input.access
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
var init_collection = __esm({
|
|
147
|
+
"src/core/schema/collection.ts"() {
|
|
148
|
+
"use strict";
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// src/core/schema/normalize.ts
|
|
153
|
+
function normalize(config) {
|
|
154
|
+
return {
|
|
155
|
+
collections: config.collections.map((c) => ({
|
|
156
|
+
...c,
|
|
157
|
+
label: c.label ?? c.name.charAt(0).toUpperCase() + c.name.slice(1)
|
|
158
|
+
})),
|
|
159
|
+
auth: config.auth ?? { enabled: false }
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function serializeConfig(config) {
|
|
163
|
+
return {
|
|
164
|
+
...config,
|
|
165
|
+
collections: config.collections.map((c) => ({
|
|
166
|
+
...c,
|
|
167
|
+
fields: Object.fromEntries(
|
|
168
|
+
Object.entries(c.fields).map(([name, field]) => {
|
|
169
|
+
const { validation, ...rest } = field;
|
|
170
|
+
return [name, rest];
|
|
171
|
+
})
|
|
172
|
+
)
|
|
173
|
+
}))
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
var init_normalize = __esm({
|
|
177
|
+
"src/core/schema/normalize.ts"() {
|
|
178
|
+
"use strict";
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// src/core/fields/index.ts
|
|
183
|
+
function fieldMeta(options = {}) {
|
|
184
|
+
return {
|
|
185
|
+
required: Boolean(options.required),
|
|
186
|
+
unique: Boolean(options.unique),
|
|
187
|
+
default: options.default,
|
|
188
|
+
label: options.label,
|
|
189
|
+
hidden: options.hidden,
|
|
190
|
+
readOnly: options.readOnly,
|
|
191
|
+
description: options.description
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function text(options = {}) {
|
|
195
|
+
return {
|
|
196
|
+
type: "text",
|
|
197
|
+
db: { type: "String", nullable: !options.required, unique: options.unique, default: options.default },
|
|
198
|
+
access: options.access,
|
|
199
|
+
ui: { component: "text", props: { label: options.label, hidden: options.hidden, readOnly: options.readOnly } },
|
|
200
|
+
validation: options.required ? import_zod2.z.string().min(1) : import_zod2.z.string().optional(),
|
|
201
|
+
meta: fieldMeta(options)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function boolean(options = {}) {
|
|
205
|
+
return {
|
|
206
|
+
type: "boolean",
|
|
207
|
+
db: { type: "Boolean", nullable: !options.required, default: options.default ?? false },
|
|
208
|
+
access: options.access,
|
|
209
|
+
ui: { component: "boolean", props: { label: options.label, hidden: options.hidden, readOnly: options.readOnly } },
|
|
210
|
+
validation: options.required ? import_zod2.z.boolean() : import_zod2.z.boolean().optional(),
|
|
211
|
+
meta: fieldMeta(options)
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function richText(options = {}) {
|
|
215
|
+
return {
|
|
216
|
+
type: "richText",
|
|
217
|
+
db: { type: "String", nullable: !options.required },
|
|
218
|
+
access: options.access,
|
|
219
|
+
ui: { component: "richText", props: { label: options.label, hidden: options.hidden, readOnly: options.readOnly } },
|
|
220
|
+
validation: options.required ? import_zod2.z.string().min(1) : import_zod2.z.string().optional(),
|
|
221
|
+
meta: fieldMeta(options)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function slug(options) {
|
|
225
|
+
return {
|
|
226
|
+
type: "slug",
|
|
227
|
+
db: { type: "String", nullable: !options.required, unique: options.unique ?? true },
|
|
228
|
+
access: options.access,
|
|
229
|
+
ui: { component: "slug", props: { from: options.from, label: options.label, hidden: options.hidden, readOnly: options.readOnly } },
|
|
230
|
+
validation: options.required ? import_zod2.z.string().regex(/^[a-z0-9-]+$/) : import_zod2.z.string().regex(/^[a-z0-9-]+$/).optional(),
|
|
231
|
+
hooks: { beforeSave: (value) => {
|
|
232
|
+
if (typeof value === "string") return value.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
233
|
+
return value;
|
|
234
|
+
} },
|
|
235
|
+
meta: { ...fieldMeta(options), unique: options.unique ?? true }
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function relation(options) {
|
|
239
|
+
const isMulti = options.type === "many-to-many" || options.type === "one-to-many";
|
|
240
|
+
return {
|
|
241
|
+
type: "relation",
|
|
242
|
+
db: { type: "String", nullable: !options.required, references: { model: options.to, field: "id" }, relationType: options.type },
|
|
243
|
+
access: options.access,
|
|
244
|
+
ui: { component: "relation", props: { to: options.to, relationType: options.type, label: options.label, hidden: options.hidden, readOnly: options.readOnly } },
|
|
245
|
+
validation: isMulti ? options.required ? import_zod2.z.array(import_zod2.z.string()).min(1) : import_zod2.z.array(import_zod2.z.string()).optional() : options.required ? import_zod2.z.string().min(1) : import_zod2.z.string().optional(),
|
|
246
|
+
meta: fieldMeta(options)
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function date(options = {}) {
|
|
250
|
+
return {
|
|
251
|
+
type: "date",
|
|
252
|
+
db: { type: "DateTime", nullable: !options.required },
|
|
253
|
+
access: options.access,
|
|
254
|
+
ui: { component: "date", props: { label: options.label, hidden: options.hidden, readOnly: options.readOnly } },
|
|
255
|
+
validation: options.required ? import_zod2.z.string().datetime() : import_zod2.z.string().datetime().optional(),
|
|
256
|
+
hooks: { beforeSave: (value) => {
|
|
257
|
+
if (options.autoCreate && !value) return (/* @__PURE__ */ new Date()).toISOString();
|
|
258
|
+
return value;
|
|
259
|
+
} },
|
|
260
|
+
meta: fieldMeta(options)
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function image(options = {}) {
|
|
264
|
+
return {
|
|
265
|
+
type: "image",
|
|
266
|
+
db: { type: "String", nullable: true },
|
|
267
|
+
access: options.access,
|
|
268
|
+
ui: { component: "image", props: { label: options.label, hidden: options.hidden, readOnly: options.readOnly } },
|
|
269
|
+
validation: import_zod2.z.string().optional(),
|
|
270
|
+
meta: fieldMeta(options)
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
var import_zod2, fields;
|
|
274
|
+
var init_fields = __esm({
|
|
275
|
+
"src/core/fields/index.ts"() {
|
|
276
|
+
"use strict";
|
|
277
|
+
import_zod2 = require("zod");
|
|
278
|
+
fields = {
|
|
279
|
+
text,
|
|
280
|
+
boolean,
|
|
281
|
+
richText,
|
|
282
|
+
slug,
|
|
283
|
+
relation,
|
|
284
|
+
date,
|
|
285
|
+
image
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// src/core/registry/index.ts
|
|
291
|
+
function registerField(name, definition) {
|
|
292
|
+
if (fieldRegistry.has(name)) {
|
|
293
|
+
throw new Error(`Field "${name}" is already registered`);
|
|
294
|
+
}
|
|
295
|
+
fieldRegistry.set(name, definition);
|
|
296
|
+
}
|
|
297
|
+
function getField(name) {
|
|
298
|
+
return fieldRegistry.get(name);
|
|
299
|
+
}
|
|
300
|
+
function getRegisteredFields() {
|
|
301
|
+
return new Map(fieldRegistry);
|
|
302
|
+
}
|
|
303
|
+
function clearRegistry() {
|
|
304
|
+
fieldRegistry.clear();
|
|
305
|
+
}
|
|
306
|
+
var fieldRegistry;
|
|
307
|
+
var init_registry = __esm({
|
|
308
|
+
"src/core/registry/index.ts"() {
|
|
309
|
+
"use strict";
|
|
310
|
+
fieldRegistry = /* @__PURE__ */ new Map();
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// src/core/hooks/index.ts
|
|
315
|
+
async function executeBeforeCreate(hooks, data) {
|
|
316
|
+
if (hooks?.beforeCreate) {
|
|
317
|
+
return await hooks.beforeCreate({ data });
|
|
318
|
+
}
|
|
319
|
+
return data;
|
|
320
|
+
}
|
|
321
|
+
async function executeAfterCreate(hooks, data, id) {
|
|
322
|
+
if (hooks?.afterCreate) {
|
|
323
|
+
await hooks.afterCreate({ data, id });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
async function executeBeforeUpdate(hooks, data, id) {
|
|
327
|
+
if (hooks?.beforeUpdate) {
|
|
328
|
+
return await hooks.beforeUpdate({ data, id });
|
|
329
|
+
}
|
|
330
|
+
return data;
|
|
331
|
+
}
|
|
332
|
+
async function executeAfterUpdate(hooks, data, id) {
|
|
333
|
+
if (hooks?.afterUpdate) {
|
|
334
|
+
await hooks.afterUpdate({ data, id });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async function executeBeforeDelete(hooks, id) {
|
|
338
|
+
if (hooks?.beforeDelete) {
|
|
339
|
+
await hooks.beforeDelete({ id });
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async function executeAfterDelete(hooks, id) {
|
|
343
|
+
if (hooks?.afterDelete) {
|
|
344
|
+
await hooks.afterDelete({ id });
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
var init_hooks = __esm({
|
|
348
|
+
"src/core/hooks/index.ts"() {
|
|
349
|
+
"use strict";
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// src/core/index.ts
|
|
354
|
+
var core_exports = {};
|
|
355
|
+
__export(core_exports, {
|
|
356
|
+
clearRegistry: () => clearRegistry,
|
|
357
|
+
collection: () => collection,
|
|
358
|
+
defineConfig: () => defineConfig,
|
|
359
|
+
executeAfterCreate: () => executeAfterCreate,
|
|
360
|
+
executeAfterDelete: () => executeAfterDelete,
|
|
361
|
+
executeAfterUpdate: () => executeAfterUpdate,
|
|
362
|
+
executeBeforeCreate: () => executeBeforeCreate,
|
|
363
|
+
executeBeforeDelete: () => executeBeforeDelete,
|
|
364
|
+
executeBeforeUpdate: () => executeBeforeUpdate,
|
|
365
|
+
fields: () => fields,
|
|
366
|
+
getField: () => getField,
|
|
367
|
+
getRegisteredFields: () => getRegisteredFields,
|
|
368
|
+
normalize: () => normalize,
|
|
369
|
+
registerField: () => registerField,
|
|
370
|
+
serializeConfig: () => serializeConfig
|
|
371
|
+
});
|
|
372
|
+
var init_core = __esm({
|
|
373
|
+
"src/core/index.ts"() {
|
|
374
|
+
"use strict";
|
|
375
|
+
init_config();
|
|
376
|
+
init_collection();
|
|
377
|
+
init_normalize();
|
|
378
|
+
init_fields();
|
|
379
|
+
init_registry();
|
|
380
|
+
init_hooks();
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// src/next.ts
|
|
385
|
+
var next_exports = {};
|
|
386
|
+
__export(next_exports, {
|
|
387
|
+
adminMiddleware: () => adminMiddleware,
|
|
388
|
+
assertScope: () => assertScope,
|
|
389
|
+
auth: () => auth,
|
|
390
|
+
createAdminForgeApi: () => createAdminForgeApi,
|
|
391
|
+
createAuthConfig: () => createAuthConfig,
|
|
392
|
+
createController: () => createController,
|
|
393
|
+
createRouteHandlers: () => createRouteHandlers,
|
|
394
|
+
generateAgentToken: () => generateAgentToken,
|
|
395
|
+
verifyAgentToken: () => verifyAgentToken
|
|
396
|
+
});
|
|
397
|
+
module.exports = __toCommonJS(next_exports);
|
|
398
|
+
|
|
399
|
+
// src/api/controller.ts
|
|
400
|
+
var import_zod = require("zod");
|
|
401
|
+
init_agent_auth();
|
|
402
|
+
function buildValidationSchema(collection2) {
|
|
403
|
+
const shape = {};
|
|
404
|
+
for (const [name, field] of Object.entries(collection2.fields)) {
|
|
405
|
+
shape[name] = field.validation;
|
|
406
|
+
}
|
|
407
|
+
return import_zod.z.object(shape);
|
|
408
|
+
}
|
|
409
|
+
function hasAccess(access, operation, role) {
|
|
410
|
+
if (!access) return true;
|
|
411
|
+
const allowed = access[operation];
|
|
412
|
+
if (!allowed || !Array.isArray(allowed)) return true;
|
|
413
|
+
if (!role) return false;
|
|
414
|
+
return allowed.includes(role);
|
|
415
|
+
}
|
|
416
|
+
function createController(collection2, db, session) {
|
|
417
|
+
const validationSchema = buildValidationSchema(collection2);
|
|
418
|
+
const role = session?.user?.role || session?.agent?.role;
|
|
419
|
+
const actorId = session?.user?.id || session?.agent?.sub;
|
|
420
|
+
function requireAccess(operation) {
|
|
421
|
+
console.error(`[ACL] Operation: ${operation}, Collection: ${collection2.name}, Role: ${role}, Source: ${session?.source}`);
|
|
422
|
+
if (session?.agent) {
|
|
423
|
+
assertScope(session.agent, collection2.name, operation);
|
|
424
|
+
}
|
|
425
|
+
if (!hasAccess(collection2.access, operation, role)) {
|
|
426
|
+
console.warn(`[ACL] DENIED: ${role} not allowed to ${operation} on ${collection2.name}. Allowed:`, collection2.access?.[operation]);
|
|
427
|
+
throw new Error(`Access denied: ${operation} on ${collection2.name}`);
|
|
428
|
+
}
|
|
429
|
+
console.error(JSON.stringify({
|
|
430
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
431
|
+
type: "mutation_attempt",
|
|
432
|
+
source: session?.source || "unknown",
|
|
433
|
+
userId: actorId || "anonymous",
|
|
434
|
+
role: role || "none",
|
|
435
|
+
collection: collection2.name,
|
|
436
|
+
action: operation,
|
|
437
|
+
sessionId: session?.agent?.sessionId
|
|
438
|
+
}));
|
|
439
|
+
}
|
|
440
|
+
function buildSearchWhere(search) {
|
|
441
|
+
if (!search) return void 0;
|
|
442
|
+
const searchFields = Object.entries(collection2.fields).filter(([_, field]) => field.type === "text" || field.type === "slug" || field.type === "richText").map(([name]) => name);
|
|
443
|
+
if (searchFields.length === 0) return void 0;
|
|
444
|
+
return {
|
|
445
|
+
OR: searchFields.map((field) => ({
|
|
446
|
+
[field]: { contains: search, mode: "insensitive" }
|
|
447
|
+
}))
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function filterFields(fields2) {
|
|
451
|
+
const filtered = {};
|
|
452
|
+
for (const [key, value] of Object.entries(fields2)) {
|
|
453
|
+
const field = collection2.fields[key];
|
|
454
|
+
if (hasAccess(field?.access, "read", role)) {
|
|
455
|
+
filtered[key] = value;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return filtered;
|
|
459
|
+
}
|
|
460
|
+
function filterWritableFields(fields2, operation) {
|
|
461
|
+
const filtered = {};
|
|
462
|
+
for (const [key, value] of Object.entries(fields2)) {
|
|
463
|
+
const field = collection2.fields[key];
|
|
464
|
+
if (field && hasAccess(field.access, operation, role)) {
|
|
465
|
+
filtered[key] = value;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return filtered;
|
|
469
|
+
}
|
|
470
|
+
function applyFieldHooks(fields2, hookName) {
|
|
471
|
+
const next = { ...fields2 };
|
|
472
|
+
for (const [key, value] of Object.entries(next)) {
|
|
473
|
+
const hook = collection2.fields[key]?.hooks?.[hookName];
|
|
474
|
+
if (hook) {
|
|
475
|
+
next[key] = hook(value);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return next;
|
|
479
|
+
}
|
|
480
|
+
function applyDerivedFields(fields2) {
|
|
481
|
+
const next = { ...fields2 };
|
|
482
|
+
for (const [name, field] of Object.entries(collection2.fields)) {
|
|
483
|
+
if (field.type !== "slug") continue;
|
|
484
|
+
const current = next[name];
|
|
485
|
+
if (typeof current === "string" && current.trim().length > 0) continue;
|
|
486
|
+
const from = field.ui.props?.from;
|
|
487
|
+
if (typeof from !== "string") continue;
|
|
488
|
+
const source = next[from];
|
|
489
|
+
if (typeof source !== "string" || source.trim().length === 0) continue;
|
|
490
|
+
const slugified = source.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
491
|
+
next[name] = slugified;
|
|
492
|
+
}
|
|
493
|
+
return next;
|
|
494
|
+
}
|
|
495
|
+
return {
|
|
496
|
+
async list(args = {}) {
|
|
497
|
+
requireAccess("read");
|
|
498
|
+
const { where, orderBy, page = 1, pageSize = 50, search } = args;
|
|
499
|
+
const searchWhere = buildSearchWhere(search);
|
|
500
|
+
const combinedWhere = searchWhere ? { ...where, ...searchWhere } : where;
|
|
501
|
+
const skip = (page - 1) * pageSize;
|
|
502
|
+
const effectiveOrderBy = orderBy || (collection2.fields.createdAt ? { createdAt: "desc" } : { id: "desc" });
|
|
503
|
+
const [raw, total] = await Promise.all([
|
|
504
|
+
db.findMany(collection2.name, { where: combinedWhere, orderBy: effectiveOrderBy, skip, take: pageSize }),
|
|
505
|
+
db.count(collection2.name, { where: combinedWhere })
|
|
506
|
+
]);
|
|
507
|
+
const data = raw.map(filterFields);
|
|
508
|
+
return { data, total, page, pageSize };
|
|
509
|
+
},
|
|
510
|
+
async get(id) {
|
|
511
|
+
requireAccess("read");
|
|
512
|
+
const raw = await db.findUnique(collection2.name, id);
|
|
513
|
+
if (!raw) return null;
|
|
514
|
+
return filterFields(raw);
|
|
515
|
+
},
|
|
516
|
+
async create(data) {
|
|
517
|
+
requireAccess("create");
|
|
518
|
+
const allowed = filterWritableFields(data, "create");
|
|
519
|
+
const withDerived = applyDerivedFields(allowed);
|
|
520
|
+
const beforeValidate = applyFieldHooks(withDerived, "beforeValidate");
|
|
521
|
+
const parsed = validationSchema.parse(beforeValidate);
|
|
522
|
+
const beforeSave = applyFieldHooks(parsed, "beforeSave");
|
|
523
|
+
const transformed = transformRelations(beforeSave, false);
|
|
524
|
+
return db.create(collection2.name, transformed);
|
|
525
|
+
},
|
|
526
|
+
async update(id, data) {
|
|
527
|
+
requireAccess("update");
|
|
528
|
+
const allowed = filterWritableFields(data, "update");
|
|
529
|
+
const beforeValidate = applyFieldHooks(allowed, "beforeValidate");
|
|
530
|
+
const parsed = validationSchema.partial().parse(beforeValidate);
|
|
531
|
+
const beforeSave = applyFieldHooks(parsed, "beforeSave");
|
|
532
|
+
const transformed = transformRelations(beforeSave, true);
|
|
533
|
+
return db.update(collection2.name, id, transformed);
|
|
534
|
+
},
|
|
535
|
+
async delete(id) {
|
|
536
|
+
requireAccess("delete");
|
|
537
|
+
return db.delete(collection2.name, id);
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
function transformRelations(data, isUpdate) {
|
|
541
|
+
const transformed = { ...data };
|
|
542
|
+
for (const [key, value] of Object.entries(transformed)) {
|
|
543
|
+
const field = collection2.fields[key];
|
|
544
|
+
if (field?.type === "relation") {
|
|
545
|
+
const relationType = field.db.relationType ?? "many-to-one";
|
|
546
|
+
const isMulti = relationType === "many-to-many" || relationType === "one-to-many";
|
|
547
|
+
if (Array.isArray(value)) {
|
|
548
|
+
const ids = value.filter((id) => typeof id === "string" && id.length > 0);
|
|
549
|
+
transformed[key] = isUpdate ? { set: ids.map((id) => ({ id })) } : { connect: ids.map((id) => ({ id })) };
|
|
550
|
+
} else if (!isMulti && typeof value === "string" && value.length > 0) {
|
|
551
|
+
transformed[key] = { connect: { id: value } };
|
|
552
|
+
} else if ((value === null || value === "") && isUpdate) {
|
|
553
|
+
transformed[key] = { disconnect: true };
|
|
554
|
+
} else if (value === null || value === "") {
|
|
555
|
+
delete transformed[key];
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return transformed;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/api/index.ts
|
|
564
|
+
init_agent_auth();
|
|
565
|
+
|
|
566
|
+
// src/api/next.ts
|
|
567
|
+
init_agent_auth();
|
|
568
|
+
function jsonResponse(data, status = 200) {
|
|
569
|
+
return new Response(JSON.stringify(data), {
|
|
570
|
+
status,
|
|
571
|
+
headers: { "Content-Type": "application/json" }
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
function getBody(request) {
|
|
575
|
+
return request.json().catch(() => ({}));
|
|
576
|
+
}
|
|
577
|
+
function createRouteHandlers({ config, db, auth: auth2 }) {
|
|
578
|
+
const getSecurity = async (request) => {
|
|
579
|
+
const authHeader = request.headers.get("authorization");
|
|
580
|
+
if (authHeader?.startsWith("Bearer ")) {
|
|
581
|
+
const token = authHeader.split(" ")[1];
|
|
582
|
+
try {
|
|
583
|
+
const agent = verifyAgentToken(token);
|
|
584
|
+
return {
|
|
585
|
+
source: "agent",
|
|
586
|
+
agent,
|
|
587
|
+
user: { id: agent.sub, role: agent.role }
|
|
588
|
+
};
|
|
589
|
+
} catch (e) {
|
|
590
|
+
console.error(`[Auth] Agent Verification Failed: ${e.message}`);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
if (auth2) {
|
|
594
|
+
try {
|
|
595
|
+
const session = await auth2();
|
|
596
|
+
if (session?.user) {
|
|
597
|
+
return {
|
|
598
|
+
source: "user",
|
|
599
|
+
user: {
|
|
600
|
+
id: session.user.id || session.user.email,
|
|
601
|
+
role: session.role || "user"
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
} catch (e) {
|
|
606
|
+
console.error(`[Auth] Session Retrieval Failed: ${e.message}`);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return { source: "user" };
|
|
610
|
+
};
|
|
611
|
+
function generateHandlers(collectionName) {
|
|
612
|
+
const collection2 = config.collections.find((c) => c.name === collectionName);
|
|
613
|
+
if (!collection2) {
|
|
614
|
+
throw new Error(`Collection "${collectionName}" not found in config`);
|
|
615
|
+
}
|
|
616
|
+
return {
|
|
617
|
+
GET: async (request, context) => {
|
|
618
|
+
const security = await getSecurity(request);
|
|
619
|
+
const controller = createController(collection2, db, security);
|
|
620
|
+
const params = await context.params;
|
|
621
|
+
if (params.id) {
|
|
622
|
+
const result2 = await controller.get(params.id);
|
|
623
|
+
if (!result2) return jsonResponse({ error: "Not found" }, 404);
|
|
624
|
+
return jsonResponse(result2);
|
|
625
|
+
}
|
|
626
|
+
const url = new URL(request.url);
|
|
627
|
+
const page = parseInt(url.searchParams.get("page") ?? "1");
|
|
628
|
+
const pageSize = parseInt(url.searchParams.get("pageSize") ?? "10");
|
|
629
|
+
const search = url.searchParams.get("search") ?? void 0;
|
|
630
|
+
const result = await controller.list({ page, pageSize, search });
|
|
631
|
+
return jsonResponse(result);
|
|
632
|
+
},
|
|
633
|
+
POST: async (request) => {
|
|
634
|
+
const security = await getSecurity(request);
|
|
635
|
+
const controller = createController(collection2, db, security);
|
|
636
|
+
const body = await getBody(request);
|
|
637
|
+
try {
|
|
638
|
+
const result = await controller.create(body);
|
|
639
|
+
return jsonResponse(result, 201);
|
|
640
|
+
} catch (err) {
|
|
641
|
+
const error = err;
|
|
642
|
+
if (error.name === "ZodError") {
|
|
643
|
+
const issues = error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ");
|
|
644
|
+
return jsonResponse({ error: `Validation failed: ${issues}` }, 400);
|
|
645
|
+
}
|
|
646
|
+
return jsonResponse({ error: error.message }, 400);
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
PATCH: async (request, context) => {
|
|
650
|
+
const security = await getSecurity(request);
|
|
651
|
+
const controller = createController(collection2, db, security);
|
|
652
|
+
const params = await context.params;
|
|
653
|
+
if (!params.id) return jsonResponse({ error: "ID required" }, 400);
|
|
654
|
+
const body = await getBody(request);
|
|
655
|
+
try {
|
|
656
|
+
const result = await controller.update(params.id, body);
|
|
657
|
+
return jsonResponse(result);
|
|
658
|
+
} catch (err) {
|
|
659
|
+
const error = err;
|
|
660
|
+
if (error.name === "ZodError") {
|
|
661
|
+
const issues = error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ");
|
|
662
|
+
return jsonResponse({ error: `Validation failed: ${issues}` }, 400);
|
|
663
|
+
}
|
|
664
|
+
return jsonResponse({ error: error.message }, 400);
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
DELETE: async (request, context) => {
|
|
668
|
+
const security = await getSecurity(request);
|
|
669
|
+
const controller = createController(collection2, db, security);
|
|
670
|
+
const params = await context.params;
|
|
671
|
+
if (!params.id) return jsonResponse({ error: "ID required" }, 400);
|
|
672
|
+
try {
|
|
673
|
+
const result = await controller.delete(params.id);
|
|
674
|
+
return jsonResponse(result);
|
|
675
|
+
} catch (err) {
|
|
676
|
+
const error = err;
|
|
677
|
+
return jsonResponse({ error: error.message }, 400);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
return { generateHandlers };
|
|
683
|
+
}
|
|
684
|
+
function createAdminForgeApi({ config, db, auth: auth2 }) {
|
|
685
|
+
const { generateHandlers } = createRouteHandlers({ config, db, auth: auth2 });
|
|
686
|
+
const getCollectionAndId = (slug2) => {
|
|
687
|
+
const [collectionName, id] = slug2;
|
|
688
|
+
const handlers = generateHandlers(collectionName);
|
|
689
|
+
return { handlers, id };
|
|
690
|
+
};
|
|
691
|
+
return {
|
|
692
|
+
async GET(request, { params }) {
|
|
693
|
+
try {
|
|
694
|
+
const resolvedParams = await params;
|
|
695
|
+
const slug2 = resolvedParams.slug || resolvedParams.admin || Object.values(resolvedParams)[0];
|
|
696
|
+
if (slug2.includes("_config")) {
|
|
697
|
+
if (config.auth?.enabled && auth2) {
|
|
698
|
+
try {
|
|
699
|
+
const session = await auth2();
|
|
700
|
+
if (!session?.user) {
|
|
701
|
+
return jsonResponse({ error: "Unauthorized" }, 401);
|
|
702
|
+
}
|
|
703
|
+
} catch {
|
|
704
|
+
return jsonResponse({ error: "Unauthorized" }, 401);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
const { serializeConfig: serializeConfig2 } = await Promise.resolve().then(() => (init_core(), core_exports));
|
|
708
|
+
return jsonResponse(serializeConfig2(config));
|
|
709
|
+
}
|
|
710
|
+
const { handlers, id } = getCollectionAndId(slug2);
|
|
711
|
+
return handlers.GET(request, { params: Promise.resolve({ id: id || "" }) });
|
|
712
|
+
} catch (err) {
|
|
713
|
+
return jsonResponse({ error: err.message }, 404);
|
|
714
|
+
}
|
|
715
|
+
},
|
|
716
|
+
async POST(request, { params }) {
|
|
717
|
+
try {
|
|
718
|
+
const resolvedParams = await params;
|
|
719
|
+
const slug2 = resolvedParams.slug || resolvedParams.admin || Object.values(resolvedParams)[0];
|
|
720
|
+
if (slug2[0] === "_media") {
|
|
721
|
+
const formData = await request.formData();
|
|
722
|
+
const file = formData.get("file");
|
|
723
|
+
if (!file) return jsonResponse({ error: "No file uploaded" }, 400);
|
|
724
|
+
const bytes = await file.arrayBuffer();
|
|
725
|
+
const buffer = Buffer.from(bytes);
|
|
726
|
+
const path = await import("path");
|
|
727
|
+
const fs = await import("fs/promises");
|
|
728
|
+
const uploadDir = path.join(process.cwd(), "public", "uploads");
|
|
729
|
+
try {
|
|
730
|
+
await fs.mkdir(uploadDir, { recursive: true });
|
|
731
|
+
} catch {
|
|
732
|
+
}
|
|
733
|
+
const filename = `${Date.now()}-${file.name.replace(/\s+/g, "-")}`;
|
|
734
|
+
const filePath = path.join(uploadDir, filename);
|
|
735
|
+
await fs.writeFile(filePath, buffer);
|
|
736
|
+
return jsonResponse({
|
|
737
|
+
url: `/uploads/${filename}`,
|
|
738
|
+
filename
|
|
739
|
+
}, 201);
|
|
740
|
+
}
|
|
741
|
+
if (slug2[0] === "_tokens") {
|
|
742
|
+
const { generateAgentToken: generateAgentToken2 } = await Promise.resolve().then(() => (init_agent_auth(), agent_auth_exports));
|
|
743
|
+
const body = await request.json();
|
|
744
|
+
const { scope, expiresIn = 600 } = body;
|
|
745
|
+
if (!Array.isArray(scope)) {
|
|
746
|
+
return jsonResponse({ error: "Scope must be an array" }, 400);
|
|
747
|
+
}
|
|
748
|
+
for (const s of scope) {
|
|
749
|
+
const [collection2, action] = s.split(":");
|
|
750
|
+
const exists = config.collections.find((c) => c.name === collection2);
|
|
751
|
+
if (!exists) return jsonResponse({ error: `Invalid collection: ${collection2}` }, 400);
|
|
752
|
+
if (!["create", "read", "update", "delete"].includes(action)) {
|
|
753
|
+
return jsonResponse({ error: `Invalid action: ${action}` }, 400);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
let userId = "admin";
|
|
757
|
+
let role = "admin";
|
|
758
|
+
if (auth2) {
|
|
759
|
+
const session = await auth2();
|
|
760
|
+
if (session?.user) {
|
|
761
|
+
userId = session.user.id || session.user.email;
|
|
762
|
+
role = session.role || "admin";
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
const token = generateAgentToken2(userId, role, scope, expiresIn);
|
|
766
|
+
return jsonResponse({ token });
|
|
767
|
+
}
|
|
768
|
+
const { handlers } = getCollectionAndId(slug2);
|
|
769
|
+
return handlers.POST(request);
|
|
770
|
+
} catch (err) {
|
|
771
|
+
return jsonResponse({ error: err.message }, 404);
|
|
772
|
+
}
|
|
773
|
+
},
|
|
774
|
+
async PATCH(request, { params }) {
|
|
775
|
+
try {
|
|
776
|
+
const resolvedParams = await params;
|
|
777
|
+
const slug2 = resolvedParams.slug || resolvedParams.admin || Object.values(resolvedParams)[0];
|
|
778
|
+
const { handlers, id } = getCollectionAndId(slug2);
|
|
779
|
+
return handlers.PATCH(request, { params: Promise.resolve({ id: id || "" }) });
|
|
780
|
+
} catch (err) {
|
|
781
|
+
return jsonResponse({ error: err.message }, 404);
|
|
782
|
+
}
|
|
783
|
+
},
|
|
784
|
+
async DELETE(request, { params }) {
|
|
785
|
+
try {
|
|
786
|
+
const resolvedParams = await params;
|
|
787
|
+
const slug2 = resolvedParams.slug || resolvedParams.admin || Object.values(resolvedParams)[0];
|
|
788
|
+
const { handlers, id } = getCollectionAndId(slug2);
|
|
789
|
+
return handlers.DELETE(request, { params: Promise.resolve({ id: id || "" }) });
|
|
790
|
+
} catch (err) {
|
|
791
|
+
return jsonResponse({ error: err.message }, 404);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// src/auth/config.ts
|
|
798
|
+
function createAuthConfig(options) {
|
|
799
|
+
return {
|
|
800
|
+
...options,
|
|
801
|
+
providers: ["credentials"]
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
var auth = {
|
|
805
|
+
providers: {
|
|
806
|
+
credentials: {
|
|
807
|
+
id: "credentials",
|
|
808
|
+
name: "Credentials"
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
// src/auth/middleware.ts
|
|
814
|
+
function adminMiddleware(handler) {
|
|
815
|
+
return async (request) => {
|
|
816
|
+
const sessionCookie = request.headers.get("cookie") ?? "";
|
|
817
|
+
const hasSession = sessionCookie.includes("next-auth.session-token");
|
|
818
|
+
if (!hasSession) {
|
|
819
|
+
return new Response(JSON.stringify({ error: "Unauthorized" }), {
|
|
820
|
+
status: 401,
|
|
821
|
+
headers: { "Content-Type": "application/json" }
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
return handler(request);
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
828
|
+
0 && (module.exports = {
|
|
829
|
+
adminMiddleware,
|
|
830
|
+
assertScope,
|
|
831
|
+
auth,
|
|
832
|
+
createAdminForgeApi,
|
|
833
|
+
createAuthConfig,
|
|
834
|
+
createController,
|
|
835
|
+
createRouteHandlers,
|
|
836
|
+
generateAgentToken,
|
|
837
|
+
verifyAgentToken
|
|
838
|
+
});
|
|
839
|
+
//# sourceMappingURL=next.cjs.map
|