@kyro-cms/core 0.3.4 → 0.4.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 +3 -3
- package/dist/api-handler.cjs +6 -6
- package/dist/api-handler.js +5 -5
- package/dist/{chunk-X3CU27OO.cjs → chunk-3FW6WVVP.cjs} +2 -17
- package/dist/chunk-3FW6WVVP.cjs.map +1 -0
- package/dist/{chunk-CZ3HWX2X.cjs → chunk-3ZZPZYCM.cjs} +42 -67
- package/dist/chunk-3ZZPZYCM.cjs.map +1 -0
- package/dist/{chunk-6LPNEC6D.js → chunk-C4JJEE42.js} +43 -68
- package/dist/chunk-C4JJEE42.js.map +1 -0
- package/dist/{chunk-VEI5KQVC.cjs → chunk-FWGHXRRI.cjs} +45 -15
- package/dist/chunk-FWGHXRRI.cjs.map +1 -0
- package/dist/{chunk-MMYAIYHJ.cjs → chunk-M4GFA2UQ.cjs} +336 -32
- package/dist/chunk-M4GFA2UQ.cjs.map +1 -0
- package/dist/{chunk-2SJATAN4.js → chunk-OJBK3JYF.js} +336 -32
- package/dist/chunk-OJBK3JYF.js.map +1 -0
- package/dist/{chunk-XIXGJGQW.js → chunk-SAMZQVC2.js} +44 -14
- package/dist/chunk-SAMZQVC2.js.map +1 -0
- package/dist/{chunk-B76I67F3.js → chunk-WSCJQI2B.js} +61 -13
- package/dist/chunk-WSCJQI2B.js.map +1 -0
- package/dist/{chunk-RGIQKTZ7.js → chunk-YMG55RSX.js} +4 -18
- package/dist/chunk-YMG55RSX.js.map +1 -0
- package/dist/{chunk-DAIBBBOL.cjs → chunk-Z2OVHWHB.cjs} +61 -13
- package/dist/chunk-Z2OVHWHB.cjs.map +1 -0
- package/dist/drizzle/index.cjs +10 -10
- package/dist/drizzle/index.js +2 -2
- package/dist/index.cjs +138 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +77 -44
- package/dist/index.js.map +1 -1
- package/dist/rest/index.cjs +5 -4
- package/dist/rest/index.js +3 -2
- package/dist/templates/index.cjs +24 -24
- package/dist/templates/index.js +1 -1
- package/package.json +2 -14
- package/dist/WebhookService-BCpW2dyL.d.ts +0 -112
- package/dist/WebhookService-DxYSFvNg.d.cts +0 -112
- package/dist/api-handler.d.cts +0 -9
- package/dist/api-handler.d.ts +0 -9
- package/dist/base-DvvNqnM-.d.cts +0 -73
- package/dist/base-eVegJ_Pr.d.ts +0 -73
- package/dist/chunk-2SJATAN4.js.map +0 -1
- package/dist/chunk-6LPNEC6D.js.map +0 -1
- package/dist/chunk-B76I67F3.js.map +0 -1
- package/dist/chunk-CZ3HWX2X.cjs.map +0 -1
- package/dist/chunk-DAIBBBOL.cjs.map +0 -1
- package/dist/chunk-MMYAIYHJ.cjs.map +0 -1
- package/dist/chunk-RGIQKTZ7.js.map +0 -1
- package/dist/chunk-VEI5KQVC.cjs.map +0 -1
- package/dist/chunk-X3CU27OO.cjs.map +0 -1
- package/dist/chunk-XIXGJGQW.js.map +0 -1
- package/dist/cli/index.d.cts +0 -1
- package/dist/cli/index.d.ts +0 -1
- package/dist/client.d.cts +0 -12
- package/dist/client.d.ts +0 -12
- package/dist/drizzle/index.d.cts +0 -135
- package/dist/drizzle/index.d.ts +0 -135
- package/dist/fields/index.d.cts +0 -27
- package/dist/fields/index.d.ts +0 -27
- package/dist/graphql/index.d.cts +0 -22
- package/dist/graphql/index.d.ts +0 -22
- package/dist/index-Bz9JqRGI.d.cts +0 -86
- package/dist/index-Bz9JqRGI.d.ts +0 -86
- package/dist/index-CLp-DRKA.d.ts +0 -64
- package/dist/index-DfO7G4kN.d.cts +0 -64
- package/dist/index.d.cts +0 -1361
- package/dist/index.d.ts +0 -1361
- package/dist/integration.d.cts +0 -27
- package/dist/integration.d.ts +0 -27
- package/dist/mongodb/index.d.cts +0 -63
- package/dist/mongodb/index.d.ts +0 -63
- package/dist/mysql-media-AI6YK767.cjs +0 -48
- package/dist/mysql-media-AI6YK767.cjs.map +0 -1
- package/dist/mysql-media-CDZUS7YX.js +0 -45
- package/dist/mysql-media-CDZUS7YX.js.map +0 -1
- package/dist/rest/index.d.cts +0 -57
- package/dist/rest/index.d.ts +0 -57
- package/dist/templates/index.d.cts +0 -59
- package/dist/templates/index.d.ts +0 -59
- package/dist/trpc/index.d.cts +0 -136
- package/dist/trpc/index.d.ts +0 -136
- package/dist/types-Bs1up4yP.d.ts +0 -461
- package/dist/types-Da83JLDk.d.cts +0 -130
- package/dist/types-Da83JLDk.d.ts +0 -130
- package/dist/types-J3R9nVsZ.d.cts +0 -461
- package/dist/types-VtjUxIMp.d.cts +0 -246
- package/dist/types-VtjUxIMp.d.ts +0 -246
- package/dist/ws/index.d.cts +0 -88
- package/dist/ws/index.d.ts +0 -88
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
var chunkDLHUQO25_cjs = require('./chunk-DLHUQO25.cjs');
|
|
4
4
|
var chunkADLJSJSN_cjs = require('./chunk-ADLJSJSN.cjs');
|
|
5
5
|
var chunkIBG6V56E_cjs = require('./chunk-IBG6V56E.cjs');
|
|
6
|
+
var chunkVJT6P4N6_cjs = require('./chunk-VJT6P4N6.cjs');
|
|
6
7
|
var chunkR3XIBBAW_cjs = require('./chunk-R3XIBBAW.cjs');
|
|
7
|
-
var
|
|
8
|
+
var chunk3FW6WVVP_cjs = require('./chunk-3FW6WVVP.cjs');
|
|
8
9
|
var chunkG7VZBCD6_cjs = require('./chunk-G7VZBCD6.cjs');
|
|
9
10
|
var crypto = require('crypto');
|
|
10
11
|
var unstorage = require('unstorage');
|
|
@@ -13,6 +14,7 @@ var hono = require('hono');
|
|
|
13
14
|
var path = require('path');
|
|
14
15
|
var fs = require('fs');
|
|
15
16
|
var sharp = require('sharp');
|
|
17
|
+
var graphql = require('graphql');
|
|
16
18
|
var promises = require('fs/promises');
|
|
17
19
|
var clientS3 = require('@aws-sdk/client-s3');
|
|
18
20
|
var stream = require('stream');
|
|
@@ -1360,7 +1362,7 @@ var AuthRoutes = class {
|
|
|
1360
1362
|
}
|
|
1361
1363
|
try {
|
|
1362
1364
|
const sessions = await getUserSessions(session.userId, getSessionIdFromRequest(req) ?? void 0);
|
|
1363
|
-
return this.jsonResponse({
|
|
1365
|
+
return this.jsonResponse({ sessions });
|
|
1364
1366
|
} catch (error) {
|
|
1365
1367
|
console.error("[AuthRoutes.listSessions] Error:", error);
|
|
1366
1368
|
return this.errorResponse("Failed to list sessions", 500);
|
|
@@ -2677,7 +2679,7 @@ var MediaService = class _MediaService {
|
|
|
2677
2679
|
this.db = db;
|
|
2678
2680
|
this.storage = storage2;
|
|
2679
2681
|
this.dialect = options?.dialect || "sqlite";
|
|
2680
|
-
this.genId = options?.genId ||
|
|
2682
|
+
this.genId = options?.genId || chunk3FW6WVVP_cjs.genId;
|
|
2681
2683
|
}
|
|
2682
2684
|
static async init(db, options) {
|
|
2683
2685
|
let storage2;
|
|
@@ -2851,7 +2853,7 @@ var MediaService = class _MediaService {
|
|
|
2851
2853
|
]
|
|
2852
2854
|
);
|
|
2853
2855
|
} else {
|
|
2854
|
-
const { media: mediaSchema } = await
|
|
2856
|
+
const { media: mediaSchema } = await import('./media-WKP5AOX2.cjs');
|
|
2855
2857
|
await this.db.insert(mediaSchema).values({
|
|
2856
2858
|
id,
|
|
2857
2859
|
filename: storageResult.filename,
|
|
@@ -2907,7 +2909,7 @@ var MediaService = class _MediaService {
|
|
|
2907
2909
|
id
|
|
2908
2910
|
]);
|
|
2909
2911
|
} else {
|
|
2910
|
-
const { media: mediaSchema } = await
|
|
2912
|
+
const { media: mediaSchema } = await import('./media-WKP5AOX2.cjs');
|
|
2911
2913
|
const [row] = await this.db.select().from(mediaSchema).where(mediaSchema.id.equals(id));
|
|
2912
2914
|
if (row) item = this.rowToMedia(row);
|
|
2913
2915
|
}
|
|
@@ -2922,7 +2924,7 @@ var MediaService = class _MediaService {
|
|
|
2922
2924
|
if (this.dialect === "sqlite") {
|
|
2923
2925
|
await this.sqliteRun(`DELETE FROM ${this.mediaTable} WHERE id = ?`, [id]);
|
|
2924
2926
|
} else {
|
|
2925
|
-
const { media: mediaSchema } = await
|
|
2927
|
+
const { media: mediaSchema } = await import('./media-WKP5AOX2.cjs');
|
|
2926
2928
|
await this.db.delete(mediaSchema).where(mediaSchema.id.equals(id));
|
|
2927
2929
|
}
|
|
2928
2930
|
}
|
|
@@ -2936,7 +2938,7 @@ var MediaService = class _MediaService {
|
|
|
2936
2938
|
id
|
|
2937
2939
|
]);
|
|
2938
2940
|
} else {
|
|
2939
|
-
const { media: mediaSchema } = await
|
|
2941
|
+
const { media: mediaSchema } = await import('./media-WKP5AOX2.cjs');
|
|
2940
2942
|
const [row] = await this.db.select().from(mediaSchema).where(mediaSchema.id.equals(id));
|
|
2941
2943
|
if (row) item = this.rowToMedia(row);
|
|
2942
2944
|
}
|
|
@@ -2970,7 +2972,7 @@ var MediaService = class _MediaService {
|
|
|
2970
2972
|
[...vals, this.now(), id]
|
|
2971
2973
|
);
|
|
2972
2974
|
} else {
|
|
2973
|
-
const { media: mediaSchema } = await
|
|
2975
|
+
const { media: mediaSchema } = await import('./media-WKP5AOX2.cjs');
|
|
2974
2976
|
await this.db.update(mediaSchema).set({ ...updateData, updatedAt: this.now() }).where(mediaSchema.id.equals(id));
|
|
2975
2977
|
}
|
|
2976
2978
|
return {
|
|
@@ -2988,7 +2990,7 @@ var MediaService = class _MediaService {
|
|
|
2988
2990
|
);
|
|
2989
2991
|
return row2 ? this.rowToMedia(row2) : null;
|
|
2990
2992
|
}
|
|
2991
|
-
const { media: mediaSchema } = await
|
|
2993
|
+
const { media: mediaSchema } = await import('./media-WKP5AOX2.cjs');
|
|
2992
2994
|
const [row] = await this.db.select().from(mediaSchema).where(mediaSchema.id.equals(id));
|
|
2993
2995
|
return row ? this.rowToMedia(row) : null;
|
|
2994
2996
|
}
|
|
@@ -3035,8 +3037,8 @@ var MediaService = class _MediaService {
|
|
|
3035
3037
|
totalPages: Math.ceil(totalDocs2 / limit)
|
|
3036
3038
|
};
|
|
3037
3039
|
}
|
|
3038
|
-
const { media: mediaSchema } = await
|
|
3039
|
-
const { like, or, and, asc, desc, eq, sql } = await
|
|
3040
|
+
const { media: mediaSchema } = await import('./media-WKP5AOX2.cjs');
|
|
3041
|
+
const { like, or, and, asc, desc, eq, sql } = await import('drizzle-orm/pg-core');
|
|
3040
3042
|
const conditions = [];
|
|
3041
3043
|
if (search) {
|
|
3042
3044
|
conditions.push(
|
|
@@ -3104,7 +3106,7 @@ var MediaService = class _MediaService {
|
|
|
3104
3106
|
);
|
|
3105
3107
|
return row ? this.rowToMedia(row) : null;
|
|
3106
3108
|
}
|
|
3107
|
-
const { media: mediaSchema } = await
|
|
3109
|
+
const { media: mediaSchema } = await import('./media-WKP5AOX2.cjs');
|
|
3108
3110
|
const [updated] = await this.db.update(mediaSchema).set({ ...data, updatedAt: /* @__PURE__ */ new Date() }).where(mediaSchema.id.equals(id)).returning();
|
|
3109
3111
|
return updated ? this.rowToMedia(updated) : null;
|
|
3110
3112
|
}
|
|
@@ -3125,7 +3127,7 @@ var MediaService = class _MediaService {
|
|
|
3125
3127
|
);
|
|
3126
3128
|
}
|
|
3127
3129
|
} else {
|
|
3128
|
-
const { media: mediaSchema } = await
|
|
3130
|
+
const { media: mediaSchema } = await import('./media-WKP5AOX2.cjs');
|
|
3129
3131
|
for (const id of ids) {
|
|
3130
3132
|
await this.db.update(mediaSchema).set({ ...data, updatedAt: /* @__PURE__ */ new Date() }).where(mediaSchema.id.equals(id));
|
|
3131
3133
|
}
|
|
@@ -3139,8 +3141,8 @@ var MediaService = class _MediaService {
|
|
|
3139
3141
|
);
|
|
3140
3142
|
return rows.map((r) => r.path).filter((f) => f && f !== "").sort();
|
|
3141
3143
|
}
|
|
3142
|
-
const { media: mediaSchema, mediaFolders: folderSchema } = await
|
|
3143
|
-
const { eq, sql } = await
|
|
3144
|
+
const { media: mediaSchema, mediaFolders: folderSchema } = await import('./media-WKP5AOX2.cjs');
|
|
3145
|
+
const { eq, sql } = await import('drizzle-orm/pg-core');
|
|
3144
3146
|
const fromMedia = await this.db.select({ folder: mediaSchema.folder }).from(mediaSchema).groupBy(mediaSchema.folder);
|
|
3145
3147
|
const fromFolders = await this.db.select({ path: folderSchema.path }).from(folderSchema);
|
|
3146
3148
|
const allPaths = /* @__PURE__ */ new Set([
|
|
@@ -3159,7 +3161,7 @@ var MediaService = class _MediaService {
|
|
|
3159
3161
|
[fullPath, name, parentPath || null, now]
|
|
3160
3162
|
);
|
|
3161
3163
|
} else {
|
|
3162
|
-
const { mediaFolders: folderSchema } = await
|
|
3164
|
+
const { mediaFolders: folderSchema } = await import('./media-WKP5AOX2.cjs');
|
|
3163
3165
|
await this.db.insert(folderSchema).values({
|
|
3164
3166
|
path: fullPath,
|
|
3165
3167
|
name,
|
|
@@ -3180,8 +3182,8 @@ var MediaService = class _MediaService {
|
|
|
3180
3182
|
[folder, `${folder}/%`]
|
|
3181
3183
|
);
|
|
3182
3184
|
} else {
|
|
3183
|
-
const { mediaFolders: folderSchema } = await
|
|
3184
|
-
const { like, or, eq } = await
|
|
3185
|
+
const { mediaFolders: folderSchema } = await import('./media-WKP5AOX2.cjs');
|
|
3186
|
+
const { like, or, eq } = await import('./media-WKP5AOX2.cjs');
|
|
3185
3187
|
await this.db.delete(folderSchema).where(
|
|
3186
3188
|
or(
|
|
3187
3189
|
eq(folderSchema.path, folder),
|
|
@@ -3382,6 +3384,27 @@ function getWebhookEvent(collection, operation) {
|
|
|
3382
3384
|
if (mapped) return mapped[operation];
|
|
3383
3385
|
return `collection.${operation}`;
|
|
3384
3386
|
}
|
|
3387
|
+
function extractIp(req) {
|
|
3388
|
+
const forwarded = req.headers.get("x-forwarded-for");
|
|
3389
|
+
if (forwarded) return forwarded.split(",")[0].trim();
|
|
3390
|
+
return req.headers.get("x-real-ip") || "unknown";
|
|
3391
|
+
}
|
|
3392
|
+
function auditApiKeyUsage(sessionAuthAdapter, apiKeyContext, endpoint, method, req) {
|
|
3393
|
+
if (apiKeyContext?.apiKeyId && sessionAuthAdapter) {
|
|
3394
|
+
sessionAuthAdapter.createAuditLog({
|
|
3395
|
+
action: "api_request",
|
|
3396
|
+
userId: apiKeyContext.userId || "",
|
|
3397
|
+
resource: "api_key",
|
|
3398
|
+
resourceId: apiKeyContext.apiKeyId,
|
|
3399
|
+
success: true,
|
|
3400
|
+
metadata: {
|
|
3401
|
+
endpoint,
|
|
3402
|
+
method,
|
|
3403
|
+
ip: extractIp(req)
|
|
3404
|
+
}
|
|
3405
|
+
});
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3385
3408
|
function readBaseUpdatedAt(body) {
|
|
3386
3409
|
return body.baseUpdatedAt ?? body._baseUpdatedAt;
|
|
3387
3410
|
}
|
|
@@ -3524,7 +3547,8 @@ async function resolveAuthContext(req, authMw, staticUser, staticTenantID) {
|
|
|
3524
3547
|
return {
|
|
3525
3548
|
user: result.user || staticUser,
|
|
3526
3549
|
tenantID: result.tenantContext?.tenantId || staticTenantID,
|
|
3527
|
-
apiKeyContext: result.apiKeyContext
|
|
3550
|
+
apiKeyContext: result.apiKeyContext,
|
|
3551
|
+
authType: result.authType
|
|
3528
3552
|
};
|
|
3529
3553
|
}
|
|
3530
3554
|
function createHonoApp(options) {
|
|
@@ -3639,6 +3663,69 @@ function createHonoApp(options) {
|
|
|
3639
3663
|
app.delete("/api/auth/sessions", async (c) => authRoutes.revokeOtherSessions(c.req.raw));
|
|
3640
3664
|
app.delete("/api/auth/sessions/:id", async (c) => authRoutes.revokeSession(c.req.raw, c.req.param("id")));
|
|
3641
3665
|
app.put("/api/auth/sessions/:id/name", async (c) => authRoutes.renameSession(c.req.raw, c.req.param("id")));
|
|
3666
|
+
app.post("/api/graphql", async (c) => {
|
|
3667
|
+
try {
|
|
3668
|
+
const req = c.req.raw;
|
|
3669
|
+
const apiKeyRaw = chunkIBG6V56E_cjs.extractApiKeyFromRequest(req);
|
|
3670
|
+
if (apiKeyRaw && db) {
|
|
3671
|
+
const apiKeyResult = await chunkIBG6V56E_cjs.validateApiKey(apiKeyRaw, db);
|
|
3672
|
+
if (!apiKeyResult.valid) {
|
|
3673
|
+
return c.json({ errors: [{ message: apiKeyResult.error || "Invalid API key" }] }, 401);
|
|
3674
|
+
}
|
|
3675
|
+
const apiKeyId = apiKeyResult.apiKeyId || "";
|
|
3676
|
+
await sessionAuthAdapter?.createAuditLog({
|
|
3677
|
+
action: "api_key_request",
|
|
3678
|
+
userId: apiKeyResult.userId || "",
|
|
3679
|
+
resource: "api_key",
|
|
3680
|
+
resourceId: apiKeyId,
|
|
3681
|
+
success: true,
|
|
3682
|
+
metadata: {
|
|
3683
|
+
endpoint: "/api/graphql",
|
|
3684
|
+
method: "POST",
|
|
3685
|
+
ip: extractIp(req)
|
|
3686
|
+
}
|
|
3687
|
+
});
|
|
3688
|
+
}
|
|
3689
|
+
const body = await req.json().catch(() => ({}));
|
|
3690
|
+
const { query, variables } = body;
|
|
3691
|
+
if (!query) {
|
|
3692
|
+
return c.json({ errors: [{ message: "No query provided" }] }, 400);
|
|
3693
|
+
}
|
|
3694
|
+
let gqlUser;
|
|
3695
|
+
let apiKeyCtx;
|
|
3696
|
+
if (apiKeyRaw && db) {
|
|
3697
|
+
const apiKeyResult = await chunkIBG6V56E_cjs.validateApiKey(apiKeyRaw, db);
|
|
3698
|
+
if (apiKeyResult.valid && apiKeyResult.user) {
|
|
3699
|
+
gqlUser = apiKeyResult.user;
|
|
3700
|
+
apiKeyCtx = chunkIBG6V56E_cjs.createApiKeyContext(apiKeyResult);
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3703
|
+
const schema = chunkVJT6P4N6_cjs.buildGraphQLSchema({
|
|
3704
|
+
registry,
|
|
3705
|
+
db,
|
|
3706
|
+
user: gqlUser,
|
|
3707
|
+
req,
|
|
3708
|
+
settings
|
|
3709
|
+
});
|
|
3710
|
+
const document = graphql.parse(query);
|
|
3711
|
+
const result = await graphql.execute({
|
|
3712
|
+
schema,
|
|
3713
|
+
document,
|
|
3714
|
+
variableValues: variables,
|
|
3715
|
+
contextValue: { user: gqlUser, apiKeyContext: apiKeyCtx, req, db }
|
|
3716
|
+
});
|
|
3717
|
+
return c.json(result);
|
|
3718
|
+
} catch (error) {
|
|
3719
|
+
if (error.message?.includes("GraphQL is disabled")) {
|
|
3720
|
+
return c.json({ errors: [{ message: "GraphQL API is disabled" }] }, 403);
|
|
3721
|
+
}
|
|
3722
|
+
if (error instanceof SyntaxError) {
|
|
3723
|
+
return c.json({ errors: [{ message: "Invalid request body" }] }, 400);
|
|
3724
|
+
}
|
|
3725
|
+
console.error("[GraphQL] execution error:", error);
|
|
3726
|
+
return c.json({ errors: [{ message: error.message || "GraphQL execution failed" }] }, 500);
|
|
3727
|
+
}
|
|
3728
|
+
});
|
|
3642
3729
|
app.get("/api/auth/access", async (c) => {
|
|
3643
3730
|
try {
|
|
3644
3731
|
const { user: ctxUser, tenantID: ctxTenantID } = await resolveAuthContext(
|
|
@@ -4353,6 +4440,7 @@ function createHonoApp(options) {
|
|
|
4353
4440
|
key: rawKey,
|
|
4354
4441
|
keyPrefix: chunkIBG6V56E_cjs.generateApiKeyPrefix(rawKey),
|
|
4355
4442
|
permissions: Array.isArray(body.permissions) ? body.permissions : ["*"],
|
|
4443
|
+
expiresAt: body.expiresAt || null,
|
|
4356
4444
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4357
4445
|
}
|
|
4358
4446
|
});
|
|
@@ -4398,6 +4486,201 @@ function createHonoApp(options) {
|
|
|
4398
4486
|
return c.json({ error: error.message }, 500);
|
|
4399
4487
|
}
|
|
4400
4488
|
});
|
|
4489
|
+
app.patch("/api/keys/:id", async (c) => {
|
|
4490
|
+
try {
|
|
4491
|
+
const { user: ctxUser } = await resolveAuthContext(c.req.raw, authMw, user, tenantID);
|
|
4492
|
+
if (!ctxUser || !hasPermission(ctxUser, "users:admin")) {
|
|
4493
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
4494
|
+
}
|
|
4495
|
+
const id = c.req.param("id");
|
|
4496
|
+
const body = await c.req.json();
|
|
4497
|
+
const existing = await db.findByID({ collection: chunkIBG6V56E_cjs.API_KEY_COLLECTION, id });
|
|
4498
|
+
if (!existing) return c.json({ error: "API key not found" }, 404);
|
|
4499
|
+
const updateData = {};
|
|
4500
|
+
if (typeof body.name === "string" && body.name.trim()) updateData.name = body.name.trim();
|
|
4501
|
+
if (Array.isArray(body.permissions)) updateData.permissions = body.permissions;
|
|
4502
|
+
if (body.expiresAt !== void 0) updateData.expiresAt = body.expiresAt || null;
|
|
4503
|
+
if (Object.keys(updateData).length === 0) return c.json({ error: "Nothing to update" }, 400);
|
|
4504
|
+
const updated = await db.update({ collection: chunkIBG6V56E_cjs.API_KEY_COLLECTION, id, data: updateData });
|
|
4505
|
+
return c.json({ ...updated, keyPrefix: existing.keyPrefix });
|
|
4506
|
+
} catch (error) {
|
|
4507
|
+
console.error("[ApiKeys] PATCH error:", error);
|
|
4508
|
+
return c.json({ error: error.message }, 500);
|
|
4509
|
+
}
|
|
4510
|
+
});
|
|
4511
|
+
app.post("/api/keys/:id/rotate", async (c) => {
|
|
4512
|
+
try {
|
|
4513
|
+
const { user: ctxUser } = await resolveAuthContext(c.req.raw, authMw, user, tenantID);
|
|
4514
|
+
if (!ctxUser || !hasPermission(ctxUser, "users:admin")) {
|
|
4515
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
4516
|
+
}
|
|
4517
|
+
const id = c.req.param("id");
|
|
4518
|
+
const existing = await db.findByID({ collection: chunkIBG6V56E_cjs.API_KEY_COLLECTION, id });
|
|
4519
|
+
if (!existing) return c.json({ error: "API key not found" }, 404);
|
|
4520
|
+
const rawKey = chunkIBG6V56E_cjs.generateApiKey();
|
|
4521
|
+
const updated = await db.update({
|
|
4522
|
+
collection: chunkIBG6V56E_cjs.API_KEY_COLLECTION,
|
|
4523
|
+
id,
|
|
4524
|
+
data: {
|
|
4525
|
+
key: rawKey,
|
|
4526
|
+
keyPrefix: chunkIBG6V56E_cjs.generateApiKeyPrefix(rawKey),
|
|
4527
|
+
lastUsedAt: null
|
|
4528
|
+
}
|
|
4529
|
+
});
|
|
4530
|
+
await sessionAuthAdapter?.createAuditLog({
|
|
4531
|
+
action: "api_key_rotate",
|
|
4532
|
+
userId: ctxUser.id,
|
|
4533
|
+
resource: "api_key",
|
|
4534
|
+
resourceId: id,
|
|
4535
|
+
success: true,
|
|
4536
|
+
metadata: { keyName: existing.name }
|
|
4537
|
+
});
|
|
4538
|
+
return c.json({
|
|
4539
|
+
...updated,
|
|
4540
|
+
key: rawKey,
|
|
4541
|
+
permissions: existing.permissions,
|
|
4542
|
+
expiresAt: existing.expiresAt
|
|
4543
|
+
});
|
|
4544
|
+
} catch (error) {
|
|
4545
|
+
console.error("[ApiKeys] rotate error:", error);
|
|
4546
|
+
return c.json({ error: error.message }, 500);
|
|
4547
|
+
}
|
|
4548
|
+
});
|
|
4549
|
+
app.get("/api/webhooks", async (c) => {
|
|
4550
|
+
try {
|
|
4551
|
+
const { user: ctxUser } = await resolveAuthContext(c.req.raw, authMw, user, tenantID);
|
|
4552
|
+
if (!ctxUser || !hasPermission(ctxUser, "users:read")) {
|
|
4553
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
4554
|
+
}
|
|
4555
|
+
if (!webhookService) return c.json({ error: "Webhook service not available" }, 503);
|
|
4556
|
+
const webhooks = await webhookService.getWebhooks();
|
|
4557
|
+
return c.json({ docs: webhooks });
|
|
4558
|
+
} catch (error) {
|
|
4559
|
+
console.error("[Webhooks] GET error:", error);
|
|
4560
|
+
return c.json({ error: error.message }, 500);
|
|
4561
|
+
}
|
|
4562
|
+
});
|
|
4563
|
+
app.post("/api/webhooks", async (c) => {
|
|
4564
|
+
try {
|
|
4565
|
+
const { user: ctxUser } = await resolveAuthContext(c.req.raw, authMw, user, tenantID);
|
|
4566
|
+
if (!ctxUser || !hasPermission(ctxUser, "users:admin")) {
|
|
4567
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
4568
|
+
}
|
|
4569
|
+
if (!webhookService) return c.json({ error: "Webhook service not available" }, 503);
|
|
4570
|
+
const body = await c.req.json();
|
|
4571
|
+
const webhook = await webhookService.createWebhook(body);
|
|
4572
|
+
await sessionAuthAdapter?.createAuditLog({
|
|
4573
|
+
action: "webhook_create",
|
|
4574
|
+
userId: ctxUser.id,
|
|
4575
|
+
resource: "webhook",
|
|
4576
|
+
resourceId: webhook.id,
|
|
4577
|
+
success: true,
|
|
4578
|
+
metadata: { name: webhook.name, url: webhook.url }
|
|
4579
|
+
});
|
|
4580
|
+
return c.json(webhook, 201);
|
|
4581
|
+
} catch (error) {
|
|
4582
|
+
console.error("[Webhooks] POST error:", error);
|
|
4583
|
+
return c.json({ error: error.message }, 500);
|
|
4584
|
+
}
|
|
4585
|
+
});
|
|
4586
|
+
app.get("/api/webhooks/:id", async (c) => {
|
|
4587
|
+
try {
|
|
4588
|
+
const { user: ctxUser } = await resolveAuthContext(c.req.raw, authMw, user, tenantID);
|
|
4589
|
+
if (!ctxUser || !hasPermission(ctxUser, "users:read")) {
|
|
4590
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
4591
|
+
}
|
|
4592
|
+
if (!webhookService) return c.json({ error: "Webhook service not available" }, 503);
|
|
4593
|
+
const id = c.req.param("id");
|
|
4594
|
+
const webhook = await webhookService.getWebhookById(id);
|
|
4595
|
+
if (!webhook) return c.json({ error: "Webhook not found" }, 404);
|
|
4596
|
+
return c.json(webhook);
|
|
4597
|
+
} catch (error) {
|
|
4598
|
+
console.error("[Webhooks] GET :id error:", error);
|
|
4599
|
+
return c.json({ error: error.message }, 500);
|
|
4600
|
+
}
|
|
4601
|
+
});
|
|
4602
|
+
app.patch("/api/webhooks/:id", async (c) => {
|
|
4603
|
+
try {
|
|
4604
|
+
const { user: ctxUser } = await resolveAuthContext(c.req.raw, authMw, user, tenantID);
|
|
4605
|
+
if (!ctxUser || !hasPermission(ctxUser, "users:admin")) {
|
|
4606
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
4607
|
+
}
|
|
4608
|
+
if (!webhookService) return c.json({ error: "Webhook service not available" }, 503);
|
|
4609
|
+
const id = c.req.param("id");
|
|
4610
|
+
const body = await c.req.json();
|
|
4611
|
+
const updated = await webhookService.updateWebhook(id, body);
|
|
4612
|
+
if (!updated) return c.json({ error: "Webhook not found" }, 404);
|
|
4613
|
+
await sessionAuthAdapter?.createAuditLog({
|
|
4614
|
+
action: "webhook_update",
|
|
4615
|
+
userId: ctxUser.id,
|
|
4616
|
+
resource: "webhook",
|
|
4617
|
+
resourceId: id,
|
|
4618
|
+
success: true,
|
|
4619
|
+
metadata: { name: updated.name }
|
|
4620
|
+
});
|
|
4621
|
+
return c.json(updated);
|
|
4622
|
+
} catch (error) {
|
|
4623
|
+
console.error("[Webhooks] PATCH error:", error);
|
|
4624
|
+
return c.json({ error: error.message }, 500);
|
|
4625
|
+
}
|
|
4626
|
+
});
|
|
4627
|
+
app.delete("/api/webhooks/:id", async (c) => {
|
|
4628
|
+
try {
|
|
4629
|
+
const { user: ctxUser } = await resolveAuthContext(c.req.raw, authMw, user, tenantID);
|
|
4630
|
+
if (!ctxUser || !hasPermission(ctxUser, "users:admin")) {
|
|
4631
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
4632
|
+
}
|
|
4633
|
+
if (!webhookService) return c.json({ error: "Webhook service not available" }, 503);
|
|
4634
|
+
const id = c.req.param("id");
|
|
4635
|
+
const existing = await webhookService.getWebhookById(id);
|
|
4636
|
+
if (!existing) return c.json({ error: "Webhook not found" }, 404);
|
|
4637
|
+
await webhookService.deleteWebhook(id);
|
|
4638
|
+
await sessionAuthAdapter?.createAuditLog({
|
|
4639
|
+
action: "webhook_delete",
|
|
4640
|
+
userId: ctxUser.id,
|
|
4641
|
+
resource: "webhook",
|
|
4642
|
+
resourceId: id,
|
|
4643
|
+
success: true,
|
|
4644
|
+
metadata: { name: existing.name }
|
|
4645
|
+
});
|
|
4646
|
+
return c.json({ message: "Webhook deleted" });
|
|
4647
|
+
} catch (error) {
|
|
4648
|
+
console.error("[Webhooks] DELETE error:", error);
|
|
4649
|
+
return c.json({ error: error.message }, 500);
|
|
4650
|
+
}
|
|
4651
|
+
});
|
|
4652
|
+
app.post("/api/webhooks/:id/test", async (c) => {
|
|
4653
|
+
try {
|
|
4654
|
+
const { user: ctxUser } = await resolveAuthContext(c.req.raw, authMw, user, tenantID);
|
|
4655
|
+
if (!ctxUser || !hasPermission(ctxUser, "users:admin")) {
|
|
4656
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
4657
|
+
}
|
|
4658
|
+
if (!webhookService) return c.json({ error: "Webhook service not available" }, 503);
|
|
4659
|
+
const id = c.req.param("id");
|
|
4660
|
+
const result = await webhookService.testWebhook(id);
|
|
4661
|
+
if (!result) return c.json({ error: "Webhook not found" }, 404);
|
|
4662
|
+
return c.json(result);
|
|
4663
|
+
} catch (error) {
|
|
4664
|
+
console.error("[Webhooks] test error:", error);
|
|
4665
|
+
return c.json({ error: error.message }, 500);
|
|
4666
|
+
}
|
|
4667
|
+
});
|
|
4668
|
+
app.get("/api/webhooks/:id/history", async (c) => {
|
|
4669
|
+
try {
|
|
4670
|
+
const { user: ctxUser } = await resolveAuthContext(c.req.raw, authMw, user, tenantID);
|
|
4671
|
+
if (!ctxUser || !hasPermission(ctxUser, "users:read")) {
|
|
4672
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
4673
|
+
}
|
|
4674
|
+
if (!webhookService) return c.json({ error: "Webhook service not available" }, 503);
|
|
4675
|
+
const id = c.req.param("id");
|
|
4676
|
+
const limit = Math.min(parseInt(c.req.query("limit") || "50"), 100);
|
|
4677
|
+
const history = await webhookService.getDeliveryHistory(id, limit);
|
|
4678
|
+
return c.json({ docs: history });
|
|
4679
|
+
} catch (error) {
|
|
4680
|
+
console.error("[Webhooks] history error:", error);
|
|
4681
|
+
return c.json({ error: error.message }, 500);
|
|
4682
|
+
}
|
|
4683
|
+
});
|
|
4401
4684
|
const collections = registry.getCollections();
|
|
4402
4685
|
for (const collection of collections) {
|
|
4403
4686
|
let computeDiff2 = function(a, b) {
|
|
@@ -4434,6 +4717,7 @@ function createHonoApp(options) {
|
|
|
4434
4717
|
if (!access.allowed) {
|
|
4435
4718
|
return c.json({ error: access.error }, access.status || 403);
|
|
4436
4719
|
}
|
|
4720
|
+
auditApiKeyUsage(sessionAuthAdapter, apiKeyContext, basePath, "GET", c.req.raw);
|
|
4437
4721
|
const url = new URL(c.req.url);
|
|
4438
4722
|
const page = parseInt(url.searchParams.get("page") || "1");
|
|
4439
4723
|
const limit = Math.min(
|
|
@@ -4491,6 +4775,7 @@ function createHonoApp(options) {
|
|
|
4491
4775
|
const url = new URL(c.req.url);
|
|
4492
4776
|
const compareA = url.searchParams.get("compareA");
|
|
4493
4777
|
const compareB = url.searchParams.get("compareB");
|
|
4778
|
+
auditApiKeyUsage(sessionAuthAdapter, apiKeyContext, `${basePath}/${id}/versions`, "GET", c.req.raw);
|
|
4494
4779
|
if (compareA && compareB) {
|
|
4495
4780
|
const [versionA, versionB] = await Promise.all([
|
|
4496
4781
|
db.findVersionByID({ collection: slug, versionId: compareA, tenantID: ctxTenantID }),
|
|
@@ -4503,7 +4788,7 @@ function createHonoApp(options) {
|
|
|
4503
4788
|
return c.json({ diffs });
|
|
4504
4789
|
}
|
|
4505
4790
|
const page = parseInt(url.searchParams.get("page") || "1");
|
|
4506
|
-
const limit = parseInt(url.searchParams.get("limit") || "10");
|
|
4791
|
+
const limit = Math.min(parseInt(url.searchParams.get("limit") || "10"), 100);
|
|
4507
4792
|
const result = await db.findVersions({
|
|
4508
4793
|
collection: slug,
|
|
4509
4794
|
documentId: id,
|
|
@@ -4690,6 +4975,7 @@ function createHonoApp(options) {
|
|
|
4690
4975
|
if (!access.allowed) {
|
|
4691
4976
|
return c.json({ error: access.error }, access.status || 403);
|
|
4692
4977
|
}
|
|
4978
|
+
auditApiKeyUsage(sessionAuthAdapter, apiKeyContext, basePath, "POST", c.req.raw);
|
|
4693
4979
|
const body = await c.req.json();
|
|
4694
4980
|
const schema = registry.getCreateZodSchema(slug);
|
|
4695
4981
|
let validated;
|
|
@@ -4749,13 +5035,19 @@ function createHonoApp(options) {
|
|
|
4749
5035
|
const id = c.req.param("id");
|
|
4750
5036
|
const body = await c.req.json();
|
|
4751
5037
|
const baseUpdatedAt = readBaseUpdatedAt(body);
|
|
5038
|
+
console.log(`[PATCH] ${slug}/${id}`, {
|
|
5039
|
+
baseUpdatedAt,
|
|
5040
|
+
bodyKeys: Object.keys(body),
|
|
5041
|
+
tenantID: ctxTenantID
|
|
5042
|
+
});
|
|
4752
5043
|
const cleaned = Object.fromEntries(
|
|
4753
5044
|
Object.entries(omitRevisionFields(body)).filter(
|
|
4754
|
-
([_, v]) => v !==
|
|
5045
|
+
([_, v]) => v !== "null" && v !== void 0
|
|
4755
5046
|
)
|
|
4756
5047
|
);
|
|
4757
5048
|
const schema = registry.getUpdateZodSchema(slug);
|
|
4758
5049
|
const validated = schema.parse(cleaned);
|
|
5050
|
+
console.log(`[PATCH] Validated data:`, Object.keys(validated));
|
|
4759
5051
|
const originalDoc = await db.findByID({
|
|
4760
5052
|
collection: slug,
|
|
4761
5053
|
id,
|
|
@@ -4763,6 +5055,9 @@ function createHonoApp(options) {
|
|
|
4763
5055
|
draft: true
|
|
4764
5056
|
// Always fetch current doc regardless of status
|
|
4765
5057
|
});
|
|
5058
|
+
if (originalDoc) {
|
|
5059
|
+
console.log(`[PATCH] Original doc updatedAt:`, originalDoc.updatedAt);
|
|
5060
|
+
}
|
|
4766
5061
|
if (!originalDoc) {
|
|
4767
5062
|
return c.json({ error: "Document not found" }, 404);
|
|
4768
5063
|
}
|
|
@@ -4782,7 +5077,7 @@ function createHonoApp(options) {
|
|
|
4782
5077
|
changeDescription: "Manual save (Draft)",
|
|
4783
5078
|
tenantID: ctxTenantID
|
|
4784
5079
|
});
|
|
4785
|
-
|
|
5080
|
+
await db.update({
|
|
4786
5081
|
collection: slug,
|
|
4787
5082
|
id,
|
|
4788
5083
|
data: { _has_draft: true },
|
|
@@ -4791,13 +5086,21 @@ function createHonoApp(options) {
|
|
|
4791
5086
|
});
|
|
4792
5087
|
} else {
|
|
4793
5088
|
const saveData = isDraftEnabled ? { ...validated, _status: "draft", _has_draft: false } : validated;
|
|
4794
|
-
|
|
5089
|
+
await db.update({
|
|
4795
5090
|
collection: slug,
|
|
4796
5091
|
id,
|
|
4797
5092
|
data: saveData,
|
|
4798
5093
|
tenantID: ctxTenantID
|
|
4799
5094
|
});
|
|
4800
|
-
|
|
5095
|
+
}
|
|
5096
|
+
doc = await db.findByID({
|
|
5097
|
+
collection: slug,
|
|
5098
|
+
id,
|
|
5099
|
+
tenantID: ctxTenantID,
|
|
5100
|
+
draft: true
|
|
5101
|
+
});
|
|
5102
|
+
if (isDraftEnabled) {
|
|
5103
|
+
if (!isAlreadyPublished) {
|
|
4801
5104
|
await db.createVersion({
|
|
4802
5105
|
collection: slug,
|
|
4803
5106
|
documentId: id,
|
|
@@ -4807,13 +5110,13 @@ function createHonoApp(options) {
|
|
|
4807
5110
|
changeDescription: "Manual save",
|
|
4808
5111
|
tenantID: ctxTenantID
|
|
4809
5112
|
});
|
|
4810
|
-
} else {
|
|
4811
|
-
await db.deleteDraft({
|
|
4812
|
-
collection: slug,
|
|
4813
|
-
documentId: id,
|
|
4814
|
-
tenantID: ctxTenantID
|
|
4815
|
-
});
|
|
4816
5113
|
}
|
|
5114
|
+
} else {
|
|
5115
|
+
await db.deleteDraft({
|
|
5116
|
+
collection: slug,
|
|
5117
|
+
documentId: id,
|
|
5118
|
+
tenantID: ctxTenantID
|
|
5119
|
+
});
|
|
4817
5120
|
}
|
|
4818
5121
|
if (webhookService) {
|
|
4819
5122
|
webhookService.trigger(getWebhookEvent(slug, "update"), {
|
|
@@ -4825,6 +5128,7 @@ function createHonoApp(options) {
|
|
|
4825
5128
|
tenantId: ctxTenantID
|
|
4826
5129
|
}).catch((err) => console.error(`[Webhook] Failed to trigger:`, err));
|
|
4827
5130
|
}
|
|
5131
|
+
console.log(`[PATCH] Result doc updatedAt:`, doc?.updatedAt);
|
|
4828
5132
|
return c.json({ data: doc, message: isDraftEnabled ? "Draft saved" : "Updated successfully" });
|
|
4829
5133
|
} catch (error) {
|
|
4830
5134
|
if (error.name === "ZodError") {
|
|
@@ -5534,5 +5838,5 @@ exports.init_secret = init_secret;
|
|
|
5534
5838
|
exports.loadSecrets = loadSecrets;
|
|
5535
5839
|
exports.resolveProvider = resolveProvider;
|
|
5536
5840
|
exports.setDbAdapter = setDbAdapter;
|
|
5537
|
-
//# sourceMappingURL=chunk-
|
|
5538
|
-
//# sourceMappingURL=chunk-
|
|
5841
|
+
//# sourceMappingURL=chunk-M4GFA2UQ.cjs.map
|
|
5842
|
+
//# sourceMappingURL=chunk-M4GFA2UQ.cjs.map
|