@kyro-cms/core 0.1.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 +241 -0
- package/dist/base-CQkFzqQl.d.ts +62 -0
- package/dist/base-DlhVlwnN.d.cts +62 -0
- package/dist/chunk-3Q3FS5J4.cjs +273 -0
- package/dist/chunk-3Q3FS5J4.cjs.map +1 -0
- package/dist/chunk-3TPQ2BU6.js +423 -0
- package/dist/chunk-3TPQ2BU6.js.map +1 -0
- package/dist/chunk-3VZCX4DF.cjs +384 -0
- package/dist/chunk-3VZCX4DF.cjs.map +1 -0
- package/dist/chunk-BXMWDUED.js +115 -0
- package/dist/chunk-BXMWDUED.js.map +1 -0
- package/dist/chunk-DIC236EW.js +290 -0
- package/dist/chunk-DIC236EW.js.map +1 -0
- package/dist/chunk-DKSMFC3L.js +268 -0
- package/dist/chunk-DKSMFC3L.js.map +1 -0
- package/dist/chunk-DVD5P72E.cjs +428 -0
- package/dist/chunk-DVD5P72E.cjs.map +1 -0
- package/dist/chunk-HT6VE4NW.cjs +293 -0
- package/dist/chunk-HT6VE4NW.cjs.map +1 -0
- package/dist/chunk-K7QF2QCM.cjs +311 -0
- package/dist/chunk-K7QF2QCM.cjs.map +1 -0
- package/dist/chunk-OG3KX56O.js +308 -0
- package/dist/chunk-OG3KX56O.js.map +1 -0
- package/dist/chunk-R3XIBBAW.cjs +34 -0
- package/dist/chunk-R3XIBBAW.cjs.map +1 -0
- package/dist/chunk-RLTG4YZM.cjs +117 -0
- package/dist/chunk-RLTG4YZM.cjs.map +1 -0
- package/dist/chunk-SDMNUYVU.js +30 -0
- package/dist/chunk-SDMNUYVU.js.map +1 -0
- package/dist/chunk-UEG7KMKC.cjs +228 -0
- package/dist/chunk-UEG7KMKC.cjs.map +1 -0
- package/dist/chunk-UEYC46RL.js +374 -0
- package/dist/chunk-UEYC46RL.js.map +1 -0
- package/dist/chunk-YPAFJ7EV.js +225 -0
- package/dist/chunk-YPAFJ7EV.js.map +1 -0
- package/dist/cli/index.cjs +306 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +303 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/drizzle/index.cjs +25 -0
- package/dist/drizzle/index.cjs.map +1 -0
- package/dist/drizzle/index.d.cts +49 -0
- package/dist/drizzle/index.d.ts +49 -0
- package/dist/drizzle/index.js +4 -0
- package/dist/drizzle/index.js.map +1 -0
- package/dist/graphql/index.cjs +16 -0
- package/dist/graphql/index.cjs.map +1 -0
- package/dist/graphql/index.d.cts +20 -0
- package/dist/graphql/index.d.ts +20 -0
- package/dist/graphql/index.js +3 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/index-4fJKLFK2.d.ts +63 -0
- package/dist/index-DI0DRPNv.d.cts +63 -0
- package/dist/index.cjs +2506 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +525 -0
- package/dist/index.d.ts +525 -0
- package/dist/index.js +2334 -0
- package/dist/index.js.map +1 -0
- package/dist/mongodb/index.cjs +17 -0
- package/dist/mongodb/index.cjs.map +1 -0
- package/dist/mongodb/index.d.cts +49 -0
- package/dist/mongodb/index.d.ts +49 -0
- package/dist/mongodb/index.js +4 -0
- package/dist/mongodb/index.js.map +1 -0
- package/dist/rest/index.cjs +17 -0
- package/dist/rest/index.cjs.map +1 -0
- package/dist/rest/index.d.cts +28 -0
- package/dist/rest/index.d.ts +28 -0
- package/dist/rest/index.js +4 -0
- package/dist/rest/index.js.map +1 -0
- package/dist/trpc/index.cjs +45 -0
- package/dist/trpc/index.cjs.map +1 -0
- package/dist/trpc/index.d.cts +130 -0
- package/dist/trpc/index.d.ts +130 -0
- package/dist/trpc/index.js +4 -0
- package/dist/trpc/index.js.map +1 -0
- package/dist/types-BGM5MV_K.d.cts +589 -0
- package/dist/types-BGM5MV_K.d.ts +589 -0
- package/dist/ws/index.cjs +24 -0
- package/dist/ws/index.cjs.map +1 -0
- package/dist/ws/index.d.cts +88 -0
- package/dist/ws/index.d.ts +88 -0
- package/dist/ws/index.js +3 -0
- package/dist/ws/index.js.map +1 -0
- package/package.json +120 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkR3XIBBAW_cjs = require('./chunk-R3XIBBAW.cjs');
|
|
4
|
+
var hono = require('hono');
|
|
5
|
+
|
|
6
|
+
function createHonoApp(options) {
|
|
7
|
+
const { registry, db, user, tenantID, cors } = options;
|
|
8
|
+
const app = new hono.Hono();
|
|
9
|
+
if (cors) {
|
|
10
|
+
app.use("*", async (c, next) => {
|
|
11
|
+
const origin = c.req.header("Origin") || "*";
|
|
12
|
+
if (cors.origins && !cors.origins.includes(origin) && !cors.origins.includes("*")) ;
|
|
13
|
+
c.header("Access-Control-Allow-Origin", origin);
|
|
14
|
+
c.header("Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE, OPTIONS");
|
|
15
|
+
c.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
16
|
+
if (cors.credentials) {
|
|
17
|
+
c.header("Access-Control-Allow-Credentials", "true");
|
|
18
|
+
}
|
|
19
|
+
if (c.req.method === "OPTIONS") {
|
|
20
|
+
return c.text("");
|
|
21
|
+
}
|
|
22
|
+
await next();
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
app.get("/api/health", (c) => {
|
|
26
|
+
return c.json({
|
|
27
|
+
status: "ok",
|
|
28
|
+
version: "0.1.0",
|
|
29
|
+
collections: registry.getCollectionSlugs(),
|
|
30
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
app.get("/api/collections", (c) => {
|
|
34
|
+
const collections2 = registry.getCollections().map((col) => ({
|
|
35
|
+
slug: col.slug,
|
|
36
|
+
label: col.label || col.slug,
|
|
37
|
+
fields: col.fields.filter((f) => f.name).map((f) => ({
|
|
38
|
+
name: f.name,
|
|
39
|
+
type: f.type,
|
|
40
|
+
required: f.required,
|
|
41
|
+
label: f.label
|
|
42
|
+
}))
|
|
43
|
+
}));
|
|
44
|
+
return c.json(collections2);
|
|
45
|
+
});
|
|
46
|
+
const collections = registry.getCollections();
|
|
47
|
+
for (const collection of collections) {
|
|
48
|
+
const slug = collection.slug;
|
|
49
|
+
const basePath = `/api/${slug}`;
|
|
50
|
+
app.get(basePath, async (c) => {
|
|
51
|
+
try {
|
|
52
|
+
if (collection.access?.read) {
|
|
53
|
+
const allowed = await chunkR3XIBBAW_cjs.evaluateAccess(collection.access.read, {
|
|
54
|
+
req: c.req,
|
|
55
|
+
user,
|
|
56
|
+
tenantID
|
|
57
|
+
});
|
|
58
|
+
if (allowed === false) {
|
|
59
|
+
return c.json({ error: "Access denied" }, 403);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const url = new URL(c.req.url);
|
|
63
|
+
const page = parseInt(url.searchParams.get("page") || "1");
|
|
64
|
+
const limit = Math.min(parseInt(url.searchParams.get("limit") || "10"), 100);
|
|
65
|
+
const sort = url.searchParams.get("sort") || void 0;
|
|
66
|
+
const depth = parseInt(url.searchParams.get("depth") || "0");
|
|
67
|
+
const select = url.searchParams.get("select")?.split(",") || void 0;
|
|
68
|
+
let where = {};
|
|
69
|
+
const whereParam = url.searchParams.get("where");
|
|
70
|
+
if (whereParam) {
|
|
71
|
+
try {
|
|
72
|
+
where = JSON.parse(whereParam);
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const result = await db.find({
|
|
77
|
+
collection: slug,
|
|
78
|
+
where,
|
|
79
|
+
sort,
|
|
80
|
+
limit,
|
|
81
|
+
page,
|
|
82
|
+
depth,
|
|
83
|
+
tenantID,
|
|
84
|
+
select
|
|
85
|
+
});
|
|
86
|
+
return c.json(result);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
return c.json({ error: error.message }, 500);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
app.get(`${basePath}/:id`, async (c) => {
|
|
92
|
+
try {
|
|
93
|
+
const id = c.req.param("id");
|
|
94
|
+
const url = new URL(c.req.url);
|
|
95
|
+
const depth = parseInt(url.searchParams.get("depth") || "0");
|
|
96
|
+
const select = url.searchParams.get("select")?.split(",") || void 0;
|
|
97
|
+
if (collection.access?.read) {
|
|
98
|
+
const allowed = await chunkR3XIBBAW_cjs.evaluateAccess(collection.access.read, {
|
|
99
|
+
req: c.req,
|
|
100
|
+
user,
|
|
101
|
+
tenantID,
|
|
102
|
+
id
|
|
103
|
+
});
|
|
104
|
+
if (allowed === false) {
|
|
105
|
+
return c.json({ error: "Access denied" }, 403);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const doc = await db.findByID({
|
|
109
|
+
collection: slug,
|
|
110
|
+
id,
|
|
111
|
+
depth,
|
|
112
|
+
tenantID,
|
|
113
|
+
select
|
|
114
|
+
});
|
|
115
|
+
if (!doc) {
|
|
116
|
+
return c.json({ error: "Document not found" }, 404);
|
|
117
|
+
}
|
|
118
|
+
return c.json(doc);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
return c.json({ error: error.message }, 500);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
app.post(basePath, async (c) => {
|
|
124
|
+
try {
|
|
125
|
+
const body = await c.req.json();
|
|
126
|
+
if (collection.access?.create) {
|
|
127
|
+
const allowed = await chunkR3XIBBAW_cjs.evaluateAccess(collection.access.create, {
|
|
128
|
+
req: c.req,
|
|
129
|
+
user,
|
|
130
|
+
tenantID,
|
|
131
|
+
data: body
|
|
132
|
+
});
|
|
133
|
+
if (allowed === false) {
|
|
134
|
+
return c.json({ error: "Access denied" }, 403);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const schema = registry.getCreateZodSchema(slug);
|
|
138
|
+
const validated = schema.parse(body);
|
|
139
|
+
if (collection.tenantScoped && tenantID) {
|
|
140
|
+
validated.tenantID = tenantID;
|
|
141
|
+
}
|
|
142
|
+
const doc = await db.create({
|
|
143
|
+
collection: slug,
|
|
144
|
+
data: validated,
|
|
145
|
+
tenantID
|
|
146
|
+
});
|
|
147
|
+
return c.json({ doc, message: "Created successfully" }, 201);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if (error.name === "ZodError") {
|
|
150
|
+
return c.json({ error: "Validation failed", details: error.errors }, 400);
|
|
151
|
+
}
|
|
152
|
+
return c.json({ error: error.message }, 500);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
app.patch(`${basePath}/:id`, async (c) => {
|
|
156
|
+
try {
|
|
157
|
+
const id = c.req.param("id");
|
|
158
|
+
const body = await c.req.json();
|
|
159
|
+
if (collection.access?.update) {
|
|
160
|
+
const allowed = await chunkR3XIBBAW_cjs.evaluateAccess(collection.access.update, {
|
|
161
|
+
req: c.req,
|
|
162
|
+
user,
|
|
163
|
+
tenantID,
|
|
164
|
+
id,
|
|
165
|
+
data: body
|
|
166
|
+
});
|
|
167
|
+
if (allowed === false) {
|
|
168
|
+
return c.json({ error: "Access denied" }, 403);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const schema = registry.getUpdateZodSchema(slug);
|
|
172
|
+
const validated = schema.parse(body);
|
|
173
|
+
const doc = await db.update({
|
|
174
|
+
collection: slug,
|
|
175
|
+
id,
|
|
176
|
+
data: validated,
|
|
177
|
+
tenantID
|
|
178
|
+
});
|
|
179
|
+
return c.json({ doc, message: "Updated successfully" });
|
|
180
|
+
} catch (error) {
|
|
181
|
+
if (error.name === "ZodError") {
|
|
182
|
+
return c.json({ error: "Validation failed", details: error.errors }, 400);
|
|
183
|
+
}
|
|
184
|
+
return c.json({ error: error.message }, 500);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
app.delete(`${basePath}/:id`, async (c) => {
|
|
188
|
+
try {
|
|
189
|
+
const id = c.req.param("id");
|
|
190
|
+
if (collection.access?.delete) {
|
|
191
|
+
const allowed = await chunkR3XIBBAW_cjs.evaluateAccess(collection.access.delete, {
|
|
192
|
+
req: c.req,
|
|
193
|
+
user,
|
|
194
|
+
tenantID,
|
|
195
|
+
id
|
|
196
|
+
});
|
|
197
|
+
if (allowed === false) {
|
|
198
|
+
return c.json({ error: "Access denied" }, 403);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const doc = await db.delete({
|
|
202
|
+
collection: slug,
|
|
203
|
+
id,
|
|
204
|
+
tenantID
|
|
205
|
+
});
|
|
206
|
+
return c.json({ doc, message: "Deleted successfully" });
|
|
207
|
+
} catch (error) {
|
|
208
|
+
return c.json({ error: error.message }, 500);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return app;
|
|
213
|
+
}
|
|
214
|
+
function createRESTAPI(registry, db, options) {
|
|
215
|
+
return createHonoApp({
|
|
216
|
+
registry,
|
|
217
|
+
db,
|
|
218
|
+
user: options?.user,
|
|
219
|
+
req: options?.req,
|
|
220
|
+
tenantID: options?.tenantID,
|
|
221
|
+
cors: options?.cors
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
exports.createHonoApp = createHonoApp;
|
|
226
|
+
exports.createRESTAPI = createRESTAPI;
|
|
227
|
+
//# sourceMappingURL=chunk-UEG7KMKC.cjs.map
|
|
228
|
+
//# sourceMappingURL=chunk-UEG7KMKC.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api/rest/hono-app.ts"],"names":["Hono","collections","evaluateAccess"],"mappings":"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","file":"chunk-UEG7KMKC.cjs","sourcesContent":["import { Hono } from 'hono';\nimport type { BaseAdapter } from '../../registry/types.js';\nimport { Registry } from '../../registry/index.js';\nimport { evaluateAccess } from '../../access/types.js';\nimport type { User, Request } from '../../hooks/types.js';\n\n// ============================================================================\n// REST API Factory\n// ============================================================================\n\nexport interface HonoAppOptions {\n registry: Registry;\n db: BaseAdapter;\n user?: User;\n req?: Request;\n tenantID?: string;\n cors?: {\n origins?: string[];\n credentials?: boolean;\n };\n}\n\nexport function createHonoApp(options: HonoAppOptions): Hono {\n const { registry, db, user, tenantID, cors } = options;\n const app = new Hono();\n\n // CORS middleware\n if (cors) {\n app.use('*', async (c, next) => {\n const origin = c.req.header('Origin') || '*';\n if (cors.origins && !cors.origins.includes(origin) && !cors.origins.includes('*')) {\n // Blocked origin\n }\n \n c.header('Access-Control-Allow-Origin', origin);\n c.header('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE, OPTIONS');\n c.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');\n if (cors.credentials) {\n c.header('Access-Control-Allow-Credentials', 'true');\n }\n \n if (c.req.method === 'OPTIONS') {\n return c.text('');\n }\n \n await next();\n });\n }\n\n // Health check\n app.get('/api/health', (c) => {\n return c.json({\n status: 'ok',\n version: '0.1.0',\n collections: registry.getCollectionSlugs(),\n timestamp: new Date().toISOString(),\n });\n });\n\n // List collections\n app.get('/api/collections', (c) => {\n const collections = registry.getCollections().map(col => ({\n slug: col.slug,\n label: col.label || col.slug,\n fields: col.fields.filter(f => f.name).map(f => ({\n name: f.name,\n type: f.type,\n required: f.required,\n label: f.label,\n })),\n }));\n return c.json(collections);\n });\n\n // Dynamic collection routes\n const collections = registry.getCollections();\n\n for (const collection of collections) {\n const slug = collection.slug;\n const basePath = `/api/${slug}`;\n\n // GET /api/:collection - List\n app.get(basePath, async (c) => {\n try {\n // Check access\n if (collection.access?.read) {\n const allowed = await evaluateAccess(collection.access.read, {\n req: c.req as any,\n user,\n tenantID,\n });\n if (allowed === false) {\n return c.json({ error: 'Access denied' }, 403);\n }\n }\n\n // Parse query params\n const url = new URL(c.req.url);\n const page = parseInt(url.searchParams.get('page') || '1');\n const limit = Math.min(parseInt(url.searchParams.get('limit') || '10'), 100);\n const sort = url.searchParams.get('sort') || undefined;\n const depth = parseInt(url.searchParams.get('depth') || '0');\n const select = url.searchParams.get('select')?.split(',') || undefined;\n \n let where = {};\n const whereParam = url.searchParams.get('where');\n if (whereParam) {\n try {\n where = JSON.parse(whereParam);\n } catch {}\n }\n\n const result = await db.find({\n collection: slug,\n where,\n sort,\n limit,\n page,\n depth,\n tenantID,\n select,\n });\n\n return c.json(result);\n } catch (error: any) {\n return c.json({ error: error.message }, 500);\n }\n });\n\n // GET /api/:collection/:id - Find by ID\n app.get(`${basePath}/:id`, async (c) => {\n try {\n const id = c.req.param('id');\n const url = new URL(c.req.url);\n const depth = parseInt(url.searchParams.get('depth') || '0');\n const select = url.searchParams.get('select')?.split(',') || undefined;\n\n // Check access\n if (collection.access?.read) {\n const allowed = await evaluateAccess(collection.access.read, {\n req: c.req as any,\n user,\n tenantID,\n id,\n });\n if (allowed === false) {\n return c.json({ error: 'Access denied' }, 403);\n }\n }\n\n const doc = await db.findByID({\n collection: slug,\n id,\n depth,\n tenantID,\n select,\n });\n\n if (!doc) {\n return c.json({ error: 'Document not found' }, 404);\n }\n\n return c.json(doc);\n } catch (error: any) {\n return c.json({ error: error.message }, 500);\n }\n });\n\n // POST /api/:collection - Create\n app.post(basePath, async (c) => {\n try {\n const body = await c.req.json();\n\n // Check access\n if (collection.access?.create) {\n const allowed = await evaluateAccess(collection.access.create, {\n req: c.req as any,\n user,\n tenantID,\n data: body,\n });\n if (allowed === false) {\n return c.json({ error: 'Access denied' }, 403);\n }\n }\n\n // Validate with Zod\n const schema = registry.getCreateZodSchema(slug);\n const validated = schema.parse(body);\n\n // Add tenantID if scoped\n if (collection.tenantScoped && tenantID) {\n validated.tenantID = tenantID;\n }\n\n const doc = await db.create({\n collection: slug,\n data: validated,\n tenantID,\n });\n\n return c.json({ doc, message: 'Created successfully' }, 201);\n } catch (error: any) {\n if (error.name === 'ZodError') {\n return c.json({ error: 'Validation failed', details: error.errors }, 400);\n }\n return c.json({ error: error.message }, 500);\n }\n });\n\n // PATCH /api/:collection/:id - Update\n app.patch(`${basePath}/:id`, async (c) => {\n try {\n const id = c.req.param('id');\n const body = await c.req.json();\n\n // Check access\n if (collection.access?.update) {\n const allowed = await evaluateAccess(collection.access.update, {\n req: c.req as any,\n user,\n tenantID,\n id,\n data: body,\n });\n if (allowed === false) {\n return c.json({ error: 'Access denied' }, 403);\n }\n }\n\n // Validate with Zod\n const schema = registry.getUpdateZodSchema(slug);\n const validated = schema.parse(body);\n\n const doc = await db.update({\n collection: slug,\n id,\n data: validated,\n tenantID,\n });\n\n return c.json({ doc, message: 'Updated successfully' });\n } catch (error: any) {\n if (error.name === 'ZodError') {\n return c.json({ error: 'Validation failed', details: error.errors }, 400);\n }\n return c.json({ error: error.message }, 500);\n }\n });\n\n // DELETE /api/:collection/:id - Delete\n app.delete(`${basePath}/:id`, async (c) => {\n try {\n const id = c.req.param('id');\n\n // Check access\n if (collection.access?.delete) {\n const allowed = await evaluateAccess(collection.access.delete, {\n req: c.req as any,\n user,\n tenantID,\n id,\n });\n if (allowed === false) {\n return c.json({ error: 'Access denied' }, 403);\n }\n }\n\n const doc = await db.delete({\n collection: slug,\n id,\n tenantID,\n });\n\n return c.json({ doc, message: 'Deleted successfully' });\n } catch (error: any) {\n return c.json({ error: error.message }, 500);\n }\n });\n }\n\n return app;\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\nexport function createRESTAPI(registry: Registry, db: BaseAdapter, options?: {\n user?: User;\n req?: Request;\n tenantID?: string;\n cors?: {\n origins?: string[];\n credentials?: boolean;\n };\n}): Hono {\n return createHonoApp({\n registry,\n db,\n user: options?.user,\n req: options?.req,\n tenantID: options?.tenantID,\n cors: options?.cors,\n });\n}\n"]}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { evaluateAccess } from './chunk-SDMNUYVU.js';
|
|
2
|
+
|
|
3
|
+
// src/api/trpc/context.ts
|
|
4
|
+
function createContext(options) {
|
|
5
|
+
return {
|
|
6
|
+
db: options.db,
|
|
7
|
+
registry: options.registry,
|
|
8
|
+
req: options.req,
|
|
9
|
+
user: options.user,
|
|
10
|
+
tenantID: options.tenantID
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/api/trpc/procedures.ts
|
|
15
|
+
function createFindProcedure(ctx) {
|
|
16
|
+
return async (input) => {
|
|
17
|
+
const { collection, where, sort, limit, page, depth, select } = input;
|
|
18
|
+
const config = ctx.registry.getCollection(collection);
|
|
19
|
+
if (config.access?.read) {
|
|
20
|
+
const allowed = await evaluateAccess(config.access.read, {
|
|
21
|
+
req: ctx.req,
|
|
22
|
+
user: ctx.user,
|
|
23
|
+
tenantID: ctx.tenantID
|
|
24
|
+
});
|
|
25
|
+
if (allowed === false) throw new Error("Access denied");
|
|
26
|
+
}
|
|
27
|
+
if (config.hooks?.beforeRead) {
|
|
28
|
+
for (const hook of config.hooks.beforeRead) {
|
|
29
|
+
await hook({
|
|
30
|
+
collection,
|
|
31
|
+
req: ctx.req,
|
|
32
|
+
user: ctx.user,
|
|
33
|
+
tenantID: ctx.tenantID,
|
|
34
|
+
operation: "read",
|
|
35
|
+
where
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const result = await ctx.db.find({
|
|
40
|
+
collection,
|
|
41
|
+
where: where || {},
|
|
42
|
+
sort,
|
|
43
|
+
limit: limit || 10,
|
|
44
|
+
page: page || 1,
|
|
45
|
+
depth: depth || 0,
|
|
46
|
+
tenantID: ctx.tenantID,
|
|
47
|
+
select
|
|
48
|
+
});
|
|
49
|
+
if (config.hooks?.afterRead) {
|
|
50
|
+
for (const doc of result.docs) {
|
|
51
|
+
for (const hook of config.hooks.afterRead) {
|
|
52
|
+
await hook({
|
|
53
|
+
collection,
|
|
54
|
+
doc,
|
|
55
|
+
req: ctx.req,
|
|
56
|
+
user: ctx.user,
|
|
57
|
+
tenantID: ctx.tenantID,
|
|
58
|
+
operation: "read"
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function createFindByIDProcedure(ctx) {
|
|
67
|
+
return async (input) => {
|
|
68
|
+
const { collection, id, depth, select } = input;
|
|
69
|
+
const config = ctx.registry.getCollection(collection);
|
|
70
|
+
if (config.access?.read) {
|
|
71
|
+
const allowed = await evaluateAccess(config.access.read, {
|
|
72
|
+
req: ctx.req,
|
|
73
|
+
user: ctx.user,
|
|
74
|
+
tenantID: ctx.tenantID,
|
|
75
|
+
id
|
|
76
|
+
});
|
|
77
|
+
if (allowed === false) throw new Error("Access denied");
|
|
78
|
+
}
|
|
79
|
+
const doc = await ctx.db.findByID({
|
|
80
|
+
collection,
|
|
81
|
+
id,
|
|
82
|
+
depth: depth || 0,
|
|
83
|
+
tenantID: ctx.tenantID,
|
|
84
|
+
select
|
|
85
|
+
});
|
|
86
|
+
if (!doc) throw new Error(`Document not found: ${collection}/${id}`);
|
|
87
|
+
if (config.hooks?.afterRead) {
|
|
88
|
+
for (const hook of config.hooks.afterRead) {
|
|
89
|
+
await hook({
|
|
90
|
+
collection,
|
|
91
|
+
doc,
|
|
92
|
+
req: ctx.req,
|
|
93
|
+
user: ctx.user,
|
|
94
|
+
tenantID: ctx.tenantID,
|
|
95
|
+
operation: "read",
|
|
96
|
+
id
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return doc;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function createCreateProcedure(ctx) {
|
|
104
|
+
return async (input) => {
|
|
105
|
+
const { collection, data, depth, select } = input;
|
|
106
|
+
const config = ctx.registry.getCollection(collection);
|
|
107
|
+
if (config.access?.create) {
|
|
108
|
+
const allowed = await evaluateAccess(config.access.create, {
|
|
109
|
+
req: ctx.req,
|
|
110
|
+
user: ctx.user,
|
|
111
|
+
tenantID: ctx.tenantID,
|
|
112
|
+
data
|
|
113
|
+
});
|
|
114
|
+
if (allowed === false) throw new Error("Access denied");
|
|
115
|
+
}
|
|
116
|
+
const schema = ctx.registry.getCreateZodSchema(collection);
|
|
117
|
+
const validated = schema.parse(data);
|
|
118
|
+
if (config.tenantScoped && ctx.tenantID) {
|
|
119
|
+
validated.tenantID = ctx.tenantID;
|
|
120
|
+
}
|
|
121
|
+
if (config.hooks?.beforeValidate) {
|
|
122
|
+
for (const hook of config.hooks.beforeValidate) {
|
|
123
|
+
const hookResult = await hook({
|
|
124
|
+
collection,
|
|
125
|
+
data: validated,
|
|
126
|
+
req: ctx.req,
|
|
127
|
+
user: ctx.user,
|
|
128
|
+
tenantID: ctx.tenantID,
|
|
129
|
+
operation: "create"
|
|
130
|
+
});
|
|
131
|
+
if (hookResult) Object.assign(validated, hookResult);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (config.hooks?.beforeChange) {
|
|
135
|
+
for (const hook of config.hooks.beforeChange) {
|
|
136
|
+
const hookResult = await hook({
|
|
137
|
+
collection,
|
|
138
|
+
data: validated,
|
|
139
|
+
req: ctx.req,
|
|
140
|
+
user: ctx.user,
|
|
141
|
+
tenantID: ctx.tenantID,
|
|
142
|
+
operation: "create"
|
|
143
|
+
});
|
|
144
|
+
if (hookResult) Object.assign(validated, hookResult);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const doc = await ctx.db.create({
|
|
148
|
+
collection,
|
|
149
|
+
data: validated,
|
|
150
|
+
depth: depth || 0,
|
|
151
|
+
tenantID: ctx.tenantID,
|
|
152
|
+
select
|
|
153
|
+
});
|
|
154
|
+
if (config.hooks?.afterChange) {
|
|
155
|
+
for (const hook of config.hooks.afterChange) {
|
|
156
|
+
await hook({
|
|
157
|
+
collection,
|
|
158
|
+
doc,
|
|
159
|
+
data: validated,
|
|
160
|
+
req: ctx.req,
|
|
161
|
+
user: ctx.user,
|
|
162
|
+
tenantID: ctx.tenantID,
|
|
163
|
+
operation: "create"
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return { doc };
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function createUpdateProcedure(ctx) {
|
|
171
|
+
return async (input) => {
|
|
172
|
+
const { collection, id, data, depth, select } = input;
|
|
173
|
+
const config = ctx.registry.getCollection(collection);
|
|
174
|
+
const originalDoc = await ctx.db.findByID({
|
|
175
|
+
collection,
|
|
176
|
+
id,
|
|
177
|
+
tenantID: ctx.tenantID
|
|
178
|
+
});
|
|
179
|
+
if (!originalDoc) throw new Error(`Document not found: ${collection}/${id}`);
|
|
180
|
+
if (config.access?.update) {
|
|
181
|
+
const allowed = await evaluateAccess(config.access.update, {
|
|
182
|
+
req: ctx.req,
|
|
183
|
+
user: ctx.user,
|
|
184
|
+
tenantID: ctx.tenantID,
|
|
185
|
+
id,
|
|
186
|
+
doc: originalDoc,
|
|
187
|
+
data
|
|
188
|
+
});
|
|
189
|
+
if (allowed === false) throw new Error("Access denied");
|
|
190
|
+
}
|
|
191
|
+
const schema = ctx.registry.getUpdateZodSchema(collection);
|
|
192
|
+
const validated = schema.parse(data);
|
|
193
|
+
if (config.tenantScoped && ctx.tenantID) {
|
|
194
|
+
validated.tenantID = ctx.tenantID;
|
|
195
|
+
}
|
|
196
|
+
if (config.hooks?.beforeValidate) {
|
|
197
|
+
for (const hook of config.hooks.beforeValidate) {
|
|
198
|
+
const hookResult = await hook({
|
|
199
|
+
collection,
|
|
200
|
+
data: validated,
|
|
201
|
+
originalDoc,
|
|
202
|
+
req: ctx.req,
|
|
203
|
+
user: ctx.user,
|
|
204
|
+
tenantID: ctx.tenantID,
|
|
205
|
+
operation: "update",
|
|
206
|
+
id
|
|
207
|
+
});
|
|
208
|
+
if (hookResult) Object.assign(validated, hookResult);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (config.hooks?.beforeChange) {
|
|
212
|
+
for (const hook of config.hooks.beforeChange) {
|
|
213
|
+
const hookResult = await hook({
|
|
214
|
+
collection,
|
|
215
|
+
data: validated,
|
|
216
|
+
originalDoc,
|
|
217
|
+
req: ctx.req,
|
|
218
|
+
user: ctx.user,
|
|
219
|
+
tenantID: ctx.tenantID,
|
|
220
|
+
operation: "update",
|
|
221
|
+
id
|
|
222
|
+
});
|
|
223
|
+
if (hookResult) Object.assign(validated, hookResult);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const doc = await ctx.db.update({
|
|
227
|
+
collection,
|
|
228
|
+
id,
|
|
229
|
+
data: validated,
|
|
230
|
+
depth: depth || 0,
|
|
231
|
+
tenantID: ctx.tenantID,
|
|
232
|
+
select
|
|
233
|
+
});
|
|
234
|
+
if (config.hooks?.afterChange) {
|
|
235
|
+
for (const hook of config.hooks.afterChange) {
|
|
236
|
+
await hook({
|
|
237
|
+
collection,
|
|
238
|
+
doc,
|
|
239
|
+
data: validated,
|
|
240
|
+
originalDoc,
|
|
241
|
+
req: ctx.req,
|
|
242
|
+
user: ctx.user,
|
|
243
|
+
tenantID: ctx.tenantID,
|
|
244
|
+
operation: "update",
|
|
245
|
+
id
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return { doc };
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function createDeleteProcedure(ctx) {
|
|
253
|
+
return async (input) => {
|
|
254
|
+
const { collection, id } = input;
|
|
255
|
+
const config = ctx.registry.getCollection(collection);
|
|
256
|
+
const originalDoc = await ctx.db.findByID({
|
|
257
|
+
collection,
|
|
258
|
+
id,
|
|
259
|
+
tenantID: ctx.tenantID
|
|
260
|
+
});
|
|
261
|
+
if (!originalDoc) throw new Error(`Document not found: ${collection}/${id}`);
|
|
262
|
+
if (config.access?.delete) {
|
|
263
|
+
const allowed = await evaluateAccess(config.access.delete, {
|
|
264
|
+
req: ctx.req,
|
|
265
|
+
user: ctx.user,
|
|
266
|
+
tenantID: ctx.tenantID,
|
|
267
|
+
id,
|
|
268
|
+
doc: originalDoc
|
|
269
|
+
});
|
|
270
|
+
if (allowed === false) throw new Error("Access denied");
|
|
271
|
+
}
|
|
272
|
+
if (config.hooks?.beforeDelete) {
|
|
273
|
+
for (const hook of config.hooks.beforeDelete) {
|
|
274
|
+
await hook({
|
|
275
|
+
collection,
|
|
276
|
+
doc: originalDoc,
|
|
277
|
+
req: ctx.req,
|
|
278
|
+
user: ctx.user,
|
|
279
|
+
tenantID: ctx.tenantID,
|
|
280
|
+
operation: "delete",
|
|
281
|
+
id
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const doc = await ctx.db.delete({
|
|
286
|
+
collection,
|
|
287
|
+
id,
|
|
288
|
+
tenantID: ctx.tenantID
|
|
289
|
+
});
|
|
290
|
+
if (config.hooks?.afterDelete) {
|
|
291
|
+
for (const hook of config.hooks.afterDelete) {
|
|
292
|
+
await hook({
|
|
293
|
+
collection,
|
|
294
|
+
doc,
|
|
295
|
+
req: ctx.req,
|
|
296
|
+
user: ctx.user,
|
|
297
|
+
tenantID: ctx.tenantID,
|
|
298
|
+
operation: "delete",
|
|
299
|
+
id
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return { doc, message: "Deleted successfully" };
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function createCountProcedure(ctx) {
|
|
307
|
+
return async (input) => {
|
|
308
|
+
const { collection, where } = input;
|
|
309
|
+
const config = ctx.registry.getCollection(collection);
|
|
310
|
+
if (config.access?.read) {
|
|
311
|
+
const allowed = await evaluateAccess(config.access.read, {
|
|
312
|
+
req: ctx.req,
|
|
313
|
+
user: ctx.user,
|
|
314
|
+
tenantID: ctx.tenantID
|
|
315
|
+
});
|
|
316
|
+
if (allowed === false) throw new Error("Access denied");
|
|
317
|
+
}
|
|
318
|
+
const totalDocs = await ctx.db.count({
|
|
319
|
+
collection,
|
|
320
|
+
where: where || {},
|
|
321
|
+
tenantID: ctx.tenantID
|
|
322
|
+
});
|
|
323
|
+
return { totalDocs };
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// src/api/trpc/router.ts
|
|
328
|
+
function createDynamicRouter(ctx) {
|
|
329
|
+
const router = {};
|
|
330
|
+
const collections = ctx.registry.getCollections();
|
|
331
|
+
for (const collection of collections) {
|
|
332
|
+
const slug = collection.slug;
|
|
333
|
+
router[slug] = {
|
|
334
|
+
find: createFindProcedure(ctx),
|
|
335
|
+
findByID: createFindByIDProcedure(ctx),
|
|
336
|
+
create: createCreateProcedure(ctx),
|
|
337
|
+
update: createUpdateProcedure(ctx),
|
|
338
|
+
delete: createDeleteProcedure(ctx),
|
|
339
|
+
count: createCountProcedure(ctx)
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
const globals = ctx.registry.getGlobals();
|
|
343
|
+
for (const global of globals) {
|
|
344
|
+
const slug = global.slug;
|
|
345
|
+
router[`_globals_${slug}`] = {
|
|
346
|
+
get: async () => {
|
|
347
|
+
const doc = await ctx.db.findOne({
|
|
348
|
+
collection: `_globals_${slug}`,
|
|
349
|
+
where: {},
|
|
350
|
+
tenantID: ctx.tenantID
|
|
351
|
+
});
|
|
352
|
+
return doc;
|
|
353
|
+
},
|
|
354
|
+
update: async (input) => {
|
|
355
|
+
const schema = ctx.registry.getZodSchema(slug);
|
|
356
|
+
const validated = schema.parse(input.data);
|
|
357
|
+
const doc = await ctx.db.create({
|
|
358
|
+
collection: `_globals_${slug}`,
|
|
359
|
+
data: { ...validated, id: slug },
|
|
360
|
+
tenantID: ctx.tenantID
|
|
361
|
+
});
|
|
362
|
+
return doc;
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
return router;
|
|
367
|
+
}
|
|
368
|
+
function createKyroServer(ctx) {
|
|
369
|
+
return createDynamicRouter(ctx);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export { createContext, createCountProcedure, createCreateProcedure, createDeleteProcedure, createDynamicRouter, createFindByIDProcedure, createFindProcedure, createKyroServer, createUpdateProcedure };
|
|
373
|
+
//# sourceMappingURL=chunk-UEYC46RL.js.map
|
|
374
|
+
//# sourceMappingURL=chunk-UEYC46RL.js.map
|