@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.
Files changed (51) hide show
  1. package/dist/{WebhookService-BCpW2dyL.d.ts → WebhookService-118ZTFis.d.ts} +1 -1
  2. package/dist/{WebhookService-DxYSFvNg.d.cts → WebhookService-AefJfqX0.d.cts} +1 -1
  3. package/dist/api-handler.cjs +5 -5
  4. package/dist/api-handler.js +4 -4
  5. package/dist/{chunk-VEI5KQVC.cjs → chunk-2UOI5MUC.cjs} +45 -15
  6. package/dist/chunk-2UOI5MUC.cjs.map +1 -0
  7. package/dist/{chunk-2SJATAN4.js → chunk-4UD44U4Z.js} +320 -16
  8. package/dist/chunk-4UD44U4Z.js.map +1 -0
  9. package/dist/{chunk-XIXGJGQW.js → chunk-5FTY2DLG.js} +44 -14
  10. package/dist/chunk-5FTY2DLG.js.map +1 -0
  11. package/dist/{chunk-MMYAIYHJ.cjs → chunk-DE7OQOMD.cjs} +319 -15
  12. package/dist/chunk-DE7OQOMD.cjs.map +1 -0
  13. package/dist/{chunk-CZ3HWX2X.cjs → chunk-R4C4O4SE.cjs} +8 -8
  14. package/dist/chunk-R4C4O4SE.cjs.map +1 -0
  15. package/dist/{chunk-B76I67F3.js → chunk-WSCJQI2B.js} +61 -13
  16. package/dist/chunk-WSCJQI2B.js.map +1 -0
  17. package/dist/{chunk-6LPNEC6D.js → chunk-Y3TM7WH7.js} +9 -9
  18. package/dist/chunk-Y3TM7WH7.js.map +1 -0
  19. package/dist/{chunk-DAIBBBOL.cjs → chunk-Z2OVHWHB.cjs} +61 -13
  20. package/dist/chunk-Z2OVHWHB.cjs.map +1 -0
  21. package/dist/client.d.cts +1 -1
  22. package/dist/client.d.ts +1 -1
  23. package/dist/drizzle/index.cjs +5 -5
  24. package/dist/drizzle/index.d.cts +1 -1
  25. package/dist/drizzle/index.d.ts +1 -1
  26. package/dist/drizzle/index.js +1 -1
  27. package/dist/index.cjs +133 -93
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +7 -5
  30. package/dist/index.d.ts +7 -5
  31. package/dist/index.js +75 -35
  32. package/dist/index.js.map +1 -1
  33. package/dist/rest/index.cjs +4 -3
  34. package/dist/rest/index.d.cts +1 -1
  35. package/dist/rest/index.d.ts +1 -1
  36. package/dist/rest/index.js +2 -1
  37. package/dist/templates/index.cjs +24 -24
  38. package/dist/templates/index.js +1 -1
  39. package/dist/trpc/index.d.cts +1 -1
  40. package/dist/trpc/index.d.ts +1 -1
  41. package/dist/{types-Da83JLDk.d.cts → types-BnTm7oJG.d.cts} +1 -1
  42. package/dist/{types-Da83JLDk.d.ts → types-BnTm7oJG.d.ts} +1 -1
  43. package/package.json +1 -1
  44. package/dist/chunk-2SJATAN4.js.map +0 -1
  45. package/dist/chunk-6LPNEC6D.js.map +0 -1
  46. package/dist/chunk-B76I67F3.js.map +0 -1
  47. package/dist/chunk-CZ3HWX2X.cjs.map +0 -1
  48. package/dist/chunk-DAIBBBOL.cjs.map +0 -1
  49. package/dist/chunk-MMYAIYHJ.cjs.map +0 -1
  50. package/dist/chunk-VEI5KQVC.cjs.map +0 -1
  51. 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({ success: true, sessions });
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 !== null && v !== "null" && v !== void 0
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
- doc = await db.update({
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
- doc = await db.update({
5089
+ await db.update({
4795
5090
  collection: slug,
4796
5091
  id,
4797
5092
  data: saveData,
4798
5093
  tenantID: ctxTenantID
4799
5094
  });
4800
- if (isDraftEnabled) {
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-MMYAIYHJ.cjs.map
5538
- //# sourceMappingURL=chunk-MMYAIYHJ.cjs.map
5841
+ //# sourceMappingURL=chunk-DE7OQOMD.cjs.map
5842
+ //# sourceMappingURL=chunk-DE7OQOMD.cjs.map