@kyro-cms/core 0.3.4 → 0.3.5
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/dist/{WebhookService-BCpW2dyL.d.ts → WebhookService-118ZTFis.d.ts} +1 -1
- package/dist/{WebhookService-DxYSFvNg.d.cts → WebhookService-AefJfqX0.d.cts} +1 -1
- package/dist/api-handler.cjs +5 -5
- package/dist/api-handler.js +4 -4
- package/dist/{chunk-VEI5KQVC.cjs → chunk-2UOI5MUC.cjs} +45 -15
- package/dist/chunk-2UOI5MUC.cjs.map +1 -0
- package/dist/{chunk-2SJATAN4.js → chunk-4UD44U4Z.js} +320 -16
- package/dist/chunk-4UD44U4Z.js.map +1 -0
- package/dist/{chunk-XIXGJGQW.js → chunk-5FTY2DLG.js} +44 -14
- package/dist/chunk-5FTY2DLG.js.map +1 -0
- package/dist/{chunk-MMYAIYHJ.cjs → chunk-DE7OQOMD.cjs} +319 -15
- package/dist/chunk-DE7OQOMD.cjs.map +1 -0
- package/dist/{chunk-CZ3HWX2X.cjs → chunk-R4C4O4SE.cjs} +8 -8
- package/dist/chunk-R4C4O4SE.cjs.map +1 -0
- package/dist/{chunk-B76I67F3.js → chunk-WSCJQI2B.js} +61 -13
- package/dist/chunk-WSCJQI2B.js.map +1 -0
- package/dist/{chunk-6LPNEC6D.js → chunk-Y3TM7WH7.js} +9 -9
- package/dist/chunk-Y3TM7WH7.js.map +1 -0
- package/dist/{chunk-DAIBBBOL.cjs → chunk-Z2OVHWHB.cjs} +61 -13
- package/dist/chunk-Z2OVHWHB.cjs.map +1 -0
- package/dist/client.d.cts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/drizzle/index.cjs +5 -5
- package/dist/drizzle/index.d.cts +1 -1
- package/dist/drizzle/index.d.ts +1 -1
- package/dist/drizzle/index.js +1 -1
- package/dist/index.cjs +133 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +75 -35
- package/dist/index.js.map +1 -1
- package/dist/rest/index.cjs +4 -3
- package/dist/rest/index.d.cts +1 -1
- package/dist/rest/index.d.ts +1 -1
- package/dist/rest/index.js +2 -1
- package/dist/templates/index.cjs +24 -24
- package/dist/templates/index.js +1 -1
- package/dist/trpc/index.d.cts +1 -1
- package/dist/trpc/index.d.ts +1 -1
- package/dist/{types-Da83JLDk.d.cts → types-BnTm7oJG.d.cts} +1 -1
- package/dist/{types-Da83JLDk.d.ts → types-BnTm7oJG.d.ts} +1 -1
- package/package.json +1 -1
- 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-VEI5KQVC.cjs.map +0 -1
- package/dist/chunk-XIXGJGQW.js.map +0 -1
|
@@ -3,6 +3,7 @@
|
|
|
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
8
|
var chunkX3CU27OO_cjs = require('./chunk-X3CU27OO.cjs');
|
|
8
9
|
var chunkG7VZBCD6_cjs = require('./chunk-G7VZBCD6.cjs');
|
|
@@ -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);
|
|
@@ -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-DE7OQOMD.cjs.map
|
|
5842
|
+
//# sourceMappingURL=chunk-DE7OQOMD.cjs.map
|