@kyro-cms/core 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -589
- package/dist/{WebhookService-118ZTFis.d.ts → WebhookService-CUTb9XOy.d.ts} +1 -1
- package/dist/{WebhookService-AefJfqX0.d.cts → WebhookService-Yg2UEOB4.d.cts} +1 -1
- package/dist/api-handler-graphql.cjs +44 -0
- package/dist/api-handler-graphql.cjs.map +1 -0
- package/dist/api-handler-graphql.d.cts +6 -0
- package/dist/api-handler-graphql.d.ts +6 -0
- package/dist/api-handler-graphql.js +41 -0
- package/dist/api-handler-graphql.js.map +1 -0
- package/dist/api-handler-trpc.cjs +38 -0
- package/dist/api-handler-trpc.cjs.map +1 -0
- package/dist/api-handler-trpc.d.cts +5 -0
- package/dist/api-handler-trpc.d.ts +5 -0
- package/dist/api-handler-trpc.js +36 -0
- package/dist/api-handler-trpc.js.map +1 -0
- package/dist/api-handler.cjs +31 -97
- package/dist/api-handler.cjs.map +1 -1
- package/dist/api-handler.d.cts +2 -1
- package/dist/api-handler.d.ts +2 -1
- package/dist/api-handler.js +19 -95
- package/dist/api-handler.js.map +1 -1
- package/dist/{tenant-B1YB0Jy8.d.ts → base-B71y_EAF.d.cts} +6 -12
- package/dist/{tenant-Cpeveji6.d.cts → base-DaqY2GhA.d.ts} +6 -12
- package/dist/bootstrap-5NLASFOG.cjs +32 -0
- package/dist/{bootstrap-AKAUP6F6.cjs.map → bootstrap-5NLASFOG.cjs.map} +1 -1
- package/dist/bootstrap-T5BK77LD.js +7 -0
- package/dist/{bootstrap-JCML6NFO.js.map → bootstrap-T5BK77LD.js.map} +1 -1
- package/dist/{chunk-35U3FROB.js → chunk-22M4O4ZJ.js} +607 -63
- package/dist/chunk-22M4O4ZJ.js.map +1 -0
- package/dist/chunk-2HZRBATX.cjs +253 -0
- package/dist/chunk-2HZRBATX.cjs.map +1 -0
- package/dist/{chunk-VJT6P4N6.cjs → chunk-3HR772HI.cjs} +199 -32
- package/dist/chunk-3HR772HI.cjs.map +1 -0
- package/dist/chunk-3KTWGODI.cjs +178 -0
- package/dist/chunk-3KTWGODI.cjs.map +1 -0
- package/dist/{chunk-QXIQWPAP.js → chunk-3UK5XBVJ.js} +4 -134
- package/dist/chunk-3UK5XBVJ.js.map +1 -0
- package/dist/{chunk-FXYP2HA6.js → chunk-4AO3A3JM.js} +48 -4
- package/dist/chunk-4AO3A3JM.js.map +1 -0
- package/dist/chunk-4M7X5HAB.cjs +173 -0
- package/dist/chunk-4M7X5HAB.cjs.map +1 -0
- package/dist/chunk-5EPFQUQD.js +3243 -0
- package/dist/chunk-5EPFQUQD.js.map +1 -0
- package/dist/{chunk-Y3N7UUDO.js → chunk-7OGPN7MP.js} +5 -2
- package/dist/chunk-7OGPN7MP.js.map +1 -0
- package/dist/{chunk-WOWUL7ZY.js → chunk-AL5KX63J.js} +4 -3
- package/dist/chunk-AL5KX63J.js.map +1 -0
- package/dist/{chunk-2OL4O2TH.cjs → chunk-C36TMDTY.cjs} +66 -61
- package/dist/chunk-C36TMDTY.cjs.map +1 -0
- package/dist/{chunk-ES5HNFFT.js → chunk-CF7OL6HR.js} +4 -2
- package/dist/chunk-CF7OL6HR.js.map +1 -0
- package/dist/chunk-CJONKRHJ.js +162 -0
- package/dist/chunk-CJONKRHJ.js.map +1 -0
- package/dist/{chunk-2KVHZE6O.cjs → chunk-COIASRDK.cjs} +202 -46
- package/dist/chunk-COIASRDK.cjs.map +1 -0
- package/dist/chunk-DEVFAKCQ.cjs +3291 -0
- package/dist/chunk-DEVFAKCQ.cjs.map +1 -0
- package/dist/{chunk-3ZFYL34R.js → chunk-DYTZ6FQ7.js} +12 -185
- package/dist/chunk-DYTZ6FQ7.js.map +1 -0
- package/dist/{chunk-QPPDLRNR.js → chunk-EJN2PAOE.js} +197 -41
- package/dist/chunk-EJN2PAOE.js.map +1 -0
- package/dist/chunk-FAXU7BMP.js +220 -0
- package/dist/chunk-FAXU7BMP.js.map +1 -0
- package/dist/{chunk-OHVB4AJ7.js → chunk-FOPGUM27.js} +22 -17
- package/dist/chunk-FOPGUM27.js.map +1 -0
- package/dist/chunk-GAOXD3XT.js +175 -0
- package/dist/chunk-GAOXD3XT.js.map +1 -0
- package/dist/{chunk-4DA7QPLA.cjs → chunk-GXFOGU7N.cjs} +5 -2
- package/dist/chunk-GXFOGU7N.cjs.map +1 -0
- package/dist/{chunk-I7HHI6QV.cjs → chunk-IDVRRRAK.cjs} +17 -9
- package/dist/chunk-IDVRRRAK.cjs.map +1 -0
- package/dist/{chunk-WQBRWOQT.cjs → chunk-JOPVMWTM.cjs} +3 -2
- package/dist/chunk-JOPVMWTM.cjs.map +1 -0
- package/dist/chunk-KC2GDBLS.cjs +84 -0
- package/dist/chunk-KC2GDBLS.cjs.map +1 -0
- package/dist/{chunk-K7JPTH3G.cjs → chunk-KNRSROWB.cjs} +132 -74
- package/dist/chunk-KNRSROWB.cjs.map +1 -0
- package/dist/{chunk-3AJE4SEG.js → chunk-KPA4AN4R.js} +125 -67
- package/dist/chunk-KPA4AN4R.js.map +1 -0
- package/dist/{chunk-QUW2RZTM.cjs → chunk-L46ROHUS.cjs} +51 -7
- package/dist/chunk-L46ROHUS.cjs.map +1 -0
- package/dist/chunk-L4EZKIEX.js +185 -0
- package/dist/chunk-L4EZKIEX.js.map +1 -0
- package/dist/{chunk-REK7AYOC.js → chunk-L5UKKZQN.js} +199 -32
- package/dist/chunk-L5UKKZQN.js.map +1 -0
- package/dist/chunk-NKPKR5BW.cjs +188 -0
- package/dist/chunk-NKPKR5BW.cjs.map +1 -0
- package/dist/{chunk-Y3QQN7PN.js → chunk-P2HKJ7P5.js} +13 -4
- package/dist/chunk-P2HKJ7P5.js.map +1 -0
- package/dist/{chunk-SA7NSSIQ.cjs → chunk-PI73NNOK.cjs} +13 -187
- package/dist/chunk-PI73NNOK.cjs.map +1 -0
- package/dist/{chunk-HXRD4B37.js → chunk-PU2Z5VWF.js} +1279 -556
- package/dist/chunk-PU2Z5VWF.js.map +1 -0
- package/dist/{chunk-H727JIG7.js → chunk-Q72BOAPK.js} +16 -8
- package/dist/chunk-Q72BOAPK.js.map +1 -0
- package/dist/{chunk-IBG6V56E.cjs → chunk-QFLB4EIJ.cjs} +2 -139
- package/dist/chunk-QFLB4EIJ.cjs.map +1 -0
- package/dist/{chunk-YVUJBEXE.cjs → chunk-RAMGUDJN.cjs} +16 -7
- package/dist/chunk-RAMGUDJN.cjs.map +1 -0
- package/dist/{chunk-LINKCEG4.cjs → chunk-ROJHKAQ4.cjs} +617 -73
- package/dist/chunk-ROJHKAQ4.cjs.map +1 -0
- package/dist/{chunk-5KVM3WEY.cjs → chunk-RSF3UU7H.cjs} +1330 -602
- package/dist/chunk-RSF3UU7H.cjs.map +1 -0
- package/dist/{chunk-V3LKPM3O.cjs → chunk-SHTTJMLT.cjs} +4 -2
- package/dist/chunk-SHTTJMLT.cjs.map +1 -0
- package/dist/chunk-SPBTLUN6.js +92 -0
- package/dist/chunk-SPBTLUN6.js.map +1 -0
- package/dist/{chunk-57P6MJKC.js → chunk-TXSZFA4G.js} +3 -3
- package/dist/chunk-TXSZFA4G.js.map +1 -0
- package/dist/chunk-UERVXYVK.cjs +99 -0
- package/dist/chunk-UERVXYVK.cjs.map +1 -0
- package/dist/{chunk-PDYFVNUX.cjs → chunk-V2TVSCV5.cjs} +16 -23
- package/dist/chunk-V2TVSCV5.cjs.map +1 -0
- package/dist/{chunk-DXHRBMGB.js → chunk-VO35MNPH.js} +12 -19
- package/dist/chunk-VO35MNPH.js.map +1 -0
- package/dist/{chunk-IA6AU5PI.cjs → chunk-WNCYAKF3.cjs} +3 -3
- package/dist/chunk-WNCYAKF3.cjs.map +1 -0
- package/dist/chunk-XEB7PH2E.js +81 -0
- package/dist/chunk-XEB7PH2E.js.map +1 -0
- package/dist/cli/index.cjs +5 -5
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +5 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/client.cjs +3 -3
- package/dist/client.d.cts +3 -3
- package/dist/client.d.ts +3 -3
- package/dist/client.js +1 -1
- package/dist/drizzle/index.cjs +14 -13
- package/dist/drizzle/index.d.cts +9 -7
- package/dist/drizzle/index.d.ts +9 -7
- package/dist/drizzle/index.js +5 -4
- package/dist/fields/index.cjs +21 -37
- package/dist/fields/index.d.cts +2 -22
- package/dist/fields/index.d.ts +2 -22
- package/dist/fields/index.js +1 -1
- package/dist/graphql/index.cjs +5 -4
- package/dist/graphql/index.d.cts +5 -3
- package/dist/graphql/index.d.ts +5 -3
- package/dist/graphql/index.js +3 -2
- package/dist/index-CJXPB_ot.d.ts +276 -0
- package/dist/index-CaTNnLGd.d.cts +276 -0
- package/dist/index.cjs +304 -162
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +129 -205
- package/dist/index.d.ts +129 -205
- package/dist/index.js +172 -33
- package/dist/index.js.map +1 -1
- package/dist/integration.cjs +2 -2
- package/dist/integration.js +1 -1
- package/dist/mongo-auth-adapter-ISOM7FSS.cjs +17 -0
- package/dist/{mongo-auth-adapter-NHHUJHVH.cjs.map → mongo-auth-adapter-ISOM7FSS.cjs.map} +1 -1
- package/dist/mongo-auth-adapter-MO6STCV3.js +4 -0
- package/dist/{mongo-auth-adapter-NJQUUCTP.js.map → mongo-auth-adapter-MO6STCV3.js.map} +1 -1
- package/dist/mongodb/index.cjs +8 -7
- package/dist/mongodb/index.d.cts +5 -7
- package/dist/mongodb/index.d.ts +5 -7
- package/dist/mongodb/index.js +4 -3
- package/dist/postgres-auth-adapter-DWDR7P5G.js +5 -0
- package/dist/{postgres-auth-adapter-3T2NKTSE.js.map → postgres-auth-adapter-DWDR7P5G.js.map} +1 -1
- package/dist/postgres-auth-adapter-WRWSJD4E.cjs +14 -0
- package/dist/{postgres-auth-adapter-7IEENCKQ.cjs.map → postgres-auth-adapter-WRWSJD4E.cjs.map} +1 -1
- package/dist/redis-adapter-HGTPWIGV.js +4 -0
- package/dist/{redis-adapter-VQXD7ESY.js.map → redis-adapter-HGTPWIGV.js.map} +1 -1
- package/dist/redis-adapter-KJ3YOOT6.cjs +13 -0
- package/dist/{redis-adapter-D2E2S3GB.cjs.map → redis-adapter-KJ3YOOT6.cjs.map} +1 -1
- package/dist/rest/index.cjs +15 -14
- package/dist/rest/index.d.cts +4 -4
- package/dist/rest/index.d.ts +4 -4
- package/dist/rest/index.js +13 -12
- package/dist/{schema-5PHL5IVB.js → schema-6I5OFR4Z.js} +3 -3
- package/dist/{schema-5PHL5IVB.js.map → schema-6I5OFR4Z.js.map} +1 -1
- package/dist/{schema-37SE2F4B.cjs → schema-TTFE4467.cjs} +14 -14
- package/dist/{schema-37SE2F4B.cjs.map → schema-TTFE4467.cjs.map} +1 -1
- package/dist/sqlite-adapter-6GEUSVXQ.js +4 -0
- package/dist/{sqlite-adapter-TR3U3W6Q.js.map → sqlite-adapter-6GEUSVXQ.js.map} +1 -1
- package/dist/sqlite-adapter-CSIZE5SX.cjs +13 -0
- package/dist/{sqlite-adapter-LVK5PS4T.cjs.map → sqlite-adapter-CSIZE5SX.cjs.map} +1 -1
- package/dist/templates/index.cjs +133 -31
- package/dist/templates/index.d.cts +52 -9
- package/dist/templates/index.d.ts +52 -9
- package/dist/templates/index.js +3 -1
- package/dist/trpc/index.cjs +13 -12
- package/dist/trpc/index.d.cts +55 -49
- package/dist/trpc/index.d.ts +55 -49
- package/dist/trpc/index.js +4 -3
- package/dist/{types-D6ZLRGbH.d.cts → types-CpjuXbe7.d.cts} +2 -0
- package/dist/{types-D6ZLRGbH.d.ts → types-CpjuXbe7.d.ts} +2 -0
- package/dist/{types-Bs1up4yP.d.ts → types-CyCQ6SAI.d.ts} +28 -2
- package/dist/{types-J3R9nVsZ.d.cts → types-DJxD9394.d.cts} +28 -2
- package/dist/{types-VtjUxIMp.d.cts → types-Z6FBiqa2.d.cts} +35 -14
- package/dist/{types-VtjUxIMp.d.ts → types-Z6FBiqa2.d.ts} +35 -14
- package/package.json +22 -4
- package/dist/bootstrap-AKAUP6F6.cjs +0 -32
- package/dist/bootstrap-JCML6NFO.js +0 -7
- package/dist/chunk-2KVHZE6O.cjs.map +0 -1
- package/dist/chunk-2OL4O2TH.cjs.map +0 -1
- package/dist/chunk-35U3FROB.js.map +0 -1
- package/dist/chunk-3AJE4SEG.js.map +0 -1
- package/dist/chunk-3J4MFTI3.js +0 -3872
- package/dist/chunk-3J4MFTI3.js.map +0 -1
- package/dist/chunk-3ZFYL34R.js.map +0 -1
- package/dist/chunk-4DA7QPLA.cjs.map +0 -1
- package/dist/chunk-57P6MJKC.js.map +0 -1
- package/dist/chunk-5KVM3WEY.cjs.map +0 -1
- package/dist/chunk-6IMPH6WV.cjs +0 -3897
- package/dist/chunk-6IMPH6WV.cjs.map +0 -1
- package/dist/chunk-ATBOUGQP.cjs +0 -513
- package/dist/chunk-ATBOUGQP.cjs.map +0 -1
- package/dist/chunk-DXHRBMGB.js.map +0 -1
- package/dist/chunk-ES5HNFFT.js.map +0 -1
- package/dist/chunk-FXYP2HA6.js.map +0 -1
- package/dist/chunk-H727JIG7.js.map +0 -1
- package/dist/chunk-HXRD4B37.js.map +0 -1
- package/dist/chunk-I7HHI6QV.cjs.map +0 -1
- package/dist/chunk-IA6AU5PI.cjs.map +0 -1
- package/dist/chunk-IBG6V56E.cjs.map +0 -1
- package/dist/chunk-K7JPTH3G.cjs.map +0 -1
- package/dist/chunk-LINKCEG4.cjs.map +0 -1
- package/dist/chunk-OHVB4AJ7.js.map +0 -1
- package/dist/chunk-PDYFVNUX.cjs.map +0 -1
- package/dist/chunk-Q23JB3KL.js +0 -488
- package/dist/chunk-Q23JB3KL.js.map +0 -1
- package/dist/chunk-QPPDLRNR.js.map +0 -1
- package/dist/chunk-QUW2RZTM.cjs.map +0 -1
- package/dist/chunk-QXIQWPAP.js.map +0 -1
- package/dist/chunk-R3XIBBAW.cjs +0 -34
- package/dist/chunk-R3XIBBAW.cjs.map +0 -1
- package/dist/chunk-REK7AYOC.js.map +0 -1
- package/dist/chunk-SA7NSSIQ.cjs.map +0 -1
- package/dist/chunk-SDMNUYVU.js +0 -30
- package/dist/chunk-SDMNUYVU.js.map +0 -1
- package/dist/chunk-V3LKPM3O.cjs.map +0 -1
- package/dist/chunk-VJT6P4N6.cjs.map +0 -1
- package/dist/chunk-WOWUL7ZY.js.map +0 -1
- package/dist/chunk-WQBRWOQT.cjs.map +0 -1
- package/dist/chunk-Y3N7UUDO.js.map +0 -1
- package/dist/chunk-Y3QQN7PN.js.map +0 -1
- package/dist/chunk-YVUJBEXE.cjs.map +0 -1
- package/dist/index-CLp-DRKA.d.ts +0 -64
- package/dist/index-DfO7G4kN.d.cts +0 -64
- package/dist/mongo-auth-adapter-NHHUJHVH.cjs +0 -17
- package/dist/mongo-auth-adapter-NJQUUCTP.js +0 -4
- package/dist/postgres-auth-adapter-3T2NKTSE.js +0 -5
- package/dist/postgres-auth-adapter-7IEENCKQ.cjs +0 -14
- package/dist/redis-adapter-D2E2S3GB.cjs +0 -13
- package/dist/redis-adapter-VQXD7ESY.js +0 -4
- package/dist/sqlite-adapter-LVK5PS4T.cjs +0 -13
- package/dist/sqlite-adapter-TR3U3W6Q.js +0 -4
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { createStorageSettingsGlobal } from './chunk-GAOXD3XT.js';
|
|
2
|
+
import { createContext, createKyroServer } from './chunk-KPA4AN4R.js';
|
|
3
|
+
import { buildGraphQLSchema } from './chunk-L5UKKZQN.js';
|
|
4
|
+
import { getDefaultRegistry, createHonoApp, createS3Storage, createCloudinaryStorage, createFtpStorage } from './chunk-PU2Z5VWF.js';
|
|
5
|
+
import { createWebhookService, WEBHOOK_COLLECTION, WEBHOOK_DELIVERY_COLLECTION } from './chunk-3UK5XBVJ.js';
|
|
6
|
+
import { API_KEY_COLLECTION, extractApiKeyFromRequest, validateApiKey, createApiKeyContext } from './chunk-CJONKRHJ.js';
|
|
5
7
|
import { KyroPubSub, createWSServer } from './chunk-3TPQ2BU6.js';
|
|
6
|
-
import { AbstractBaseAdapter, applyRLS, DEFAULT_RLS_CONFIG, canAccessDocument } from './chunk-
|
|
8
|
+
import { AbstractBaseAdapter, applyRLS, DEFAULT_RLS_CONFIG, canAccessDocument } from './chunk-DYTZ6FQ7.js';
|
|
7
9
|
import { z } from 'zod';
|
|
10
|
+
import { parse, execute } from 'graphql';
|
|
8
11
|
import { createRequire } from 'module';
|
|
9
12
|
import { randomBytes } from 'crypto';
|
|
10
13
|
|
|
@@ -174,9 +177,9 @@ function validateFields(fields, context) {
|
|
|
174
177
|
break;
|
|
175
178
|
case "select":
|
|
176
179
|
case "radio":
|
|
177
|
-
if (!field.options || field.options.length === 0) {
|
|
180
|
+
if ((!field.options || field.options.length === 0) && !field.dynamicOptions) {
|
|
178
181
|
errors.push(`${context}: ${field.type} field "${fieldName}" has no options defined`);
|
|
179
|
-
} else {
|
|
182
|
+
} else if (field.options) {
|
|
180
183
|
const values = field.options.map((o) => o.value);
|
|
181
184
|
const uniqueValues = new Set(values);
|
|
182
185
|
if (values.length !== uniqueValues.size) {
|
|
@@ -265,7 +268,7 @@ function validateRelationships(fields, collections) {
|
|
|
265
268
|
const targets = Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo];
|
|
266
269
|
for (const target of targets) {
|
|
267
270
|
if (!collectionSlugs.has(target)) {
|
|
268
|
-
|
|
271
|
+
console.warn(`[Kyro Config Warning]: Relationship field "${field.name}" references unknown collection "${target}". Select options will not be available until this collection is registered.`);
|
|
269
272
|
}
|
|
270
273
|
}
|
|
271
274
|
}
|
|
@@ -365,7 +368,7 @@ function textToZod(field) {
|
|
|
365
368
|
return schema;
|
|
366
369
|
}
|
|
367
370
|
function numberToZod(field) {
|
|
368
|
-
let schema = field.integer ? z.number().int() : z.number();
|
|
371
|
+
let schema = field.integer ? z.coerce.number().int() : z.coerce.number();
|
|
369
372
|
if (field.min !== void 0) schema = schema.min(field.min);
|
|
370
373
|
if (field.max !== void 0) schema = schema.max(field.max);
|
|
371
374
|
if (field.step) {
|
|
@@ -424,12 +427,16 @@ function textareaToZod(field) {
|
|
|
424
427
|
return schema;
|
|
425
428
|
}
|
|
426
429
|
function selectToZod(field) {
|
|
427
|
-
const values = field.options.map((opt) => opt.value);
|
|
428
430
|
let schema;
|
|
429
|
-
if (field.
|
|
430
|
-
|
|
431
|
+
if (field.options && field.options.length > 0) {
|
|
432
|
+
const values = field.options.map((opt) => opt.value);
|
|
433
|
+
if (field.hasMany) {
|
|
434
|
+
schema = z.array(z.enum(values));
|
|
435
|
+
} else {
|
|
436
|
+
schema = z.enum(values);
|
|
437
|
+
}
|
|
431
438
|
} else {
|
|
432
|
-
schema = z.
|
|
439
|
+
schema = field.hasMany ? z.array(z.string()) : z.string();
|
|
433
440
|
}
|
|
434
441
|
if (!field.required) schema = schema.optional().nullable();
|
|
435
442
|
if (field.validate) schema = addCustomValidation(schema, field.validate);
|
|
@@ -459,10 +466,7 @@ function colorToZod(field) {
|
|
|
459
466
|
return schema;
|
|
460
467
|
}
|
|
461
468
|
function richTextToZod(field) {
|
|
462
|
-
let schema = z.
|
|
463
|
-
z.array(z.record(z.any())),
|
|
464
|
-
z.string()
|
|
465
|
-
]);
|
|
469
|
+
let schema = z.array(z.record(z.any()));
|
|
466
470
|
if (!field.required) schema = schema.optional().nullable();
|
|
467
471
|
if (field.validate) schema = addCustomValidation(schema, field.validate);
|
|
468
472
|
return schema;
|
|
@@ -573,9 +577,9 @@ function blocksToZod(field) {
|
|
|
573
577
|
const unknownSchema = z.object({
|
|
574
578
|
blockType: z.string()
|
|
575
579
|
}).catchall(z.any());
|
|
576
|
-
schema = z.array(z.union([knownSchema, unknownSchema]));
|
|
580
|
+
schema = z.array(z.union([knownSchema, unknownSchema, z.record(z.any())]));
|
|
577
581
|
} else {
|
|
578
|
-
schema = z.array(z.object({ blockType: z.string() }).catchall(z.any()));
|
|
582
|
+
schema = z.array(z.union([z.object({ blockType: z.string() }).catchall(z.any()), z.record(z.any())]));
|
|
579
583
|
}
|
|
580
584
|
if (field.minRows) schema = schema.min(field.minRows);
|
|
581
585
|
if (field.maxRows) schema = schema.max(field.maxRows);
|
|
@@ -721,6 +725,7 @@ function globalToZod(global) {
|
|
|
721
725
|
|
|
722
726
|
// src/registry/index.ts
|
|
723
727
|
var Registry = class {
|
|
728
|
+
storageProviders = getDefaultRegistry();
|
|
724
729
|
collections = /* @__PURE__ */ new Map();
|
|
725
730
|
globals = /* @__PURE__ */ new Map();
|
|
726
731
|
plugins = [];
|
|
@@ -788,6 +793,19 @@ var Registry = class {
|
|
|
788
793
|
if (this.initialized) {
|
|
789
794
|
throw new Error("Cannot add globals after Registry has been initialized");
|
|
790
795
|
}
|
|
796
|
+
this._addGlobalUnsafe(config);
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Add a global after the registry is already initialized.
|
|
800
|
+
* Only for internal use (e.g. storage settings form built at startup).
|
|
801
|
+
*/
|
|
802
|
+
addGlobalPostInit(config) {
|
|
803
|
+
if (this.globals.has(config.slug)) {
|
|
804
|
+
this.globals.delete(config.slug);
|
|
805
|
+
}
|
|
806
|
+
this._addGlobalUnsafe(config);
|
|
807
|
+
}
|
|
808
|
+
_addGlobalUnsafe(config) {
|
|
791
809
|
if (this.globals.has(config.slug)) {
|
|
792
810
|
console.warn(
|
|
793
811
|
`[Registry] Duplicate global slug "${config.slug}" \u2014 skipping`
|
|
@@ -942,6 +960,17 @@ var Registry = class {
|
|
|
942
960
|
admin: { readOnly: true, hidden: true }
|
|
943
961
|
});
|
|
944
962
|
}
|
|
963
|
+
if (config.versions?.drafts && !fields.some((f) => f.name === "publishStatus")) {
|
|
964
|
+
fields.push({
|
|
965
|
+
name: "publishStatus",
|
|
966
|
+
type: "select",
|
|
967
|
+
options: [
|
|
968
|
+
{ value: "draft", label: "Draft" },
|
|
969
|
+
{ value: "published", label: "Published" }
|
|
970
|
+
],
|
|
971
|
+
admin: { readOnly: true, hidden: true }
|
|
972
|
+
});
|
|
973
|
+
}
|
|
945
974
|
if (config.auth && !fields.some((f) => f.name === "password")) {
|
|
946
975
|
fields.push({
|
|
947
976
|
name: "password",
|
|
@@ -1086,6 +1115,296 @@ function createRegistry() {
|
|
|
1086
1115
|
instance = new Registry();
|
|
1087
1116
|
return instance;
|
|
1088
1117
|
}
|
|
1118
|
+
|
|
1119
|
+
// src/plugins/storage-s3.ts
|
|
1120
|
+
var s3Variants = {
|
|
1121
|
+
aws: {
|
|
1122
|
+
type: "aws",
|
|
1123
|
+
configKey: "s3",
|
|
1124
|
+
displayName: "S3 Compatible (AWS, Backblaze, Wasabi, etc.)",
|
|
1125
|
+
configFields: [
|
|
1126
|
+
{ name: "bucket", type: "text", label: "Bucket Name", required: true },
|
|
1127
|
+
{ name: "region", type: "text", label: "Region", defaultValue: "us-east-1", admin: { placeholder: "us-east-1" } },
|
|
1128
|
+
{ name: "accessKeyId", type: "text", label: "Access Key ID", required: true },
|
|
1129
|
+
{ name: "secretAccessKey", type: "password", label: "Secret Access Key", required: true },
|
|
1130
|
+
{ name: "endpoint", type: "text", label: "Endpoint URL", admin: { placeholder: "https://s3.custom.com" } },
|
|
1131
|
+
{ name: "cdnUrl", type: "text", label: "CDN URL", admin: { placeholder: "https://cdn.example.com" } },
|
|
1132
|
+
{ name: "prefix", type: "text", label: "Path Prefix", admin: { placeholder: "uploads" } }
|
|
1133
|
+
]
|
|
1134
|
+
},
|
|
1135
|
+
r2: {
|
|
1136
|
+
type: "r2",
|
|
1137
|
+
configKey: "r2",
|
|
1138
|
+
displayName: "Cloudflare R2",
|
|
1139
|
+
configFields: [
|
|
1140
|
+
{ name: "accountId", type: "text", label: "Account ID", required: true, admin: { placeholder: "Your Cloudflare Account ID" } },
|
|
1141
|
+
{ name: "accessKeyId", type: "text", label: "Access Key ID", required: true },
|
|
1142
|
+
{ name: "secretAccessKey", type: "password", label: "Secret Access Key", required: true },
|
|
1143
|
+
{ name: "bucket", type: "text", label: "Bucket Name", required: true },
|
|
1144
|
+
{
|
|
1145
|
+
name: "publicDevUrl",
|
|
1146
|
+
type: "text",
|
|
1147
|
+
label: "Public Dev URL ID",
|
|
1148
|
+
admin: {
|
|
1149
|
+
placeholder: "pub-xxxxxxxxxxxxxxxx",
|
|
1150
|
+
description: "Enter ONLY the ID (e.g., pub-b8d8c4cc8bcf4d868ddd95efc1b305aa). Do NOT include https:// or the full URL. Found in R2 Dashboard \u2192 Public Dev URL."
|
|
1151
|
+
}
|
|
1152
|
+
},
|
|
1153
|
+
{ name: "cdnUrl", type: "text", label: "Custom CDN URL", admin: { placeholder: "https://assets.example.com (optional)" } },
|
|
1154
|
+
{ name: "prefix", type: "text", label: "Path Prefix", admin: { placeholder: "uploads (optional)", description: "Optional prefix for all object keys. Do not use '/' as prefix." } }
|
|
1155
|
+
]
|
|
1156
|
+
},
|
|
1157
|
+
gcs: {
|
|
1158
|
+
type: "gcs",
|
|
1159
|
+
configKey: "gcs",
|
|
1160
|
+
displayName: "Google Cloud Storage",
|
|
1161
|
+
configFields: [
|
|
1162
|
+
{ name: "bucket", type: "text", label: "Bucket Name", required: true },
|
|
1163
|
+
{ name: "projectId", type: "text", label: "Project ID" },
|
|
1164
|
+
{ name: "clientEmail", type: "text", label: "Client Email" },
|
|
1165
|
+
{ name: "privateKey", type: "password", label: "Private Key" },
|
|
1166
|
+
{ name: "cdnUrl", type: "text", label: "CDN URL" },
|
|
1167
|
+
{ name: "prefix", type: "text", label: "Path Prefix" }
|
|
1168
|
+
]
|
|
1169
|
+
},
|
|
1170
|
+
digitalocean: {
|
|
1171
|
+
type: "digitalocean",
|
|
1172
|
+
configKey: "digitalocean",
|
|
1173
|
+
displayName: "DigitalOcean Spaces",
|
|
1174
|
+
configFields: [
|
|
1175
|
+
{ name: "bucket", type: "text", label: "Bucket Name", required: true },
|
|
1176
|
+
{ name: "region", type: "text", label: "Region", defaultValue: "nyc3" },
|
|
1177
|
+
{ name: "accessKeyId", type: "text", label: "Access Key ID", required: true },
|
|
1178
|
+
{ name: "secretAccessKey", type: "password", label: "Secret Access Key", required: true },
|
|
1179
|
+
{ name: "cdnUrl", type: "text", label: "CDN URL" },
|
|
1180
|
+
{ name: "prefix", type: "text", label: "Path Prefix" }
|
|
1181
|
+
]
|
|
1182
|
+
},
|
|
1183
|
+
backblaze: {
|
|
1184
|
+
type: "backblaze",
|
|
1185
|
+
configKey: "backblaze",
|
|
1186
|
+
displayName: "Backblaze B2",
|
|
1187
|
+
configFields: [
|
|
1188
|
+
{ name: "bucket", type: "text", label: "Bucket Name", required: true },
|
|
1189
|
+
{ name: "accountId", type: "text", label: "Account ID" },
|
|
1190
|
+
{ name: "applicationKeyId", type: "text", label: "Application Key ID", required: true },
|
|
1191
|
+
{ name: "applicationKey", type: "password", label: "Application Key", required: true },
|
|
1192
|
+
{ name: "cdnUrl", type: "text", label: "CDN URL" },
|
|
1193
|
+
{ name: "prefix", type: "text", label: "Path Prefix" }
|
|
1194
|
+
]
|
|
1195
|
+
},
|
|
1196
|
+
wasabi: {
|
|
1197
|
+
type: "wasabi",
|
|
1198
|
+
configKey: "wasabi",
|
|
1199
|
+
displayName: "Wasabi",
|
|
1200
|
+
configFields: [
|
|
1201
|
+
{ name: "bucket", type: "text", label: "Bucket Name", required: true },
|
|
1202
|
+
{ name: "region", type: "text", label: "Region", defaultValue: "us-east-1" },
|
|
1203
|
+
{ name: "accessKeyId", type: "text", label: "Access Key ID", required: true },
|
|
1204
|
+
{ name: "secretAccessKey", type: "password", label: "Secret Access Key", required: true },
|
|
1205
|
+
{ name: "cdnUrl", type: "text", label: "CDN URL" },
|
|
1206
|
+
{ name: "prefix", type: "text", label: "Path Prefix" }
|
|
1207
|
+
]
|
|
1208
|
+
}
|
|
1209
|
+
};
|
|
1210
|
+
function getEndpoint(type, config) {
|
|
1211
|
+
switch (type) {
|
|
1212
|
+
case "r2":
|
|
1213
|
+
return config?.endpoint || `https://${config?.accountId || ""}.r2.cloudflarestorage.com`;
|
|
1214
|
+
case "digitalocean":
|
|
1215
|
+
return config?.endpoint || `https://${config?.region || "nyc3"}.digitaloceanspaces.com`;
|
|
1216
|
+
case "backblaze":
|
|
1217
|
+
return config?.endpoint || `https://s3.backblazeb2.com`;
|
|
1218
|
+
case "wasabi":
|
|
1219
|
+
return config?.endpoint || `https://s3.${config?.region || "us-east-1"}.wasabisys.com`;
|
|
1220
|
+
default:
|
|
1221
|
+
return config?.endpoint;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
function buildS3Config(type, c) {
|
|
1225
|
+
return {
|
|
1226
|
+
provider: type,
|
|
1227
|
+
bucket: c?.bucket || "",
|
|
1228
|
+
region: c?.region || "us-east-1",
|
|
1229
|
+
accessKeyId: c?.accessKeyId || c?.clientEmail || c?.applicationKeyId || "",
|
|
1230
|
+
secretAccessKey: c?.secretAccessKey || c?.privateKey || c?.applicationKey || "",
|
|
1231
|
+
endpoint: getEndpoint(type, c),
|
|
1232
|
+
cdnUrl: c?.cdnUrl,
|
|
1233
|
+
prefix: c?.prefix,
|
|
1234
|
+
accountId: c?.accountId,
|
|
1235
|
+
publicDevUrl: c?.publicDevUrl
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
function buildS3ConfigFromStorageConfig(type, def, sc) {
|
|
1239
|
+
const c = sc[def.configKey] || {};
|
|
1240
|
+
return buildS3Config(type, c);
|
|
1241
|
+
}
|
|
1242
|
+
function buildS3ConfigFromRaw(type, def, raw) {
|
|
1243
|
+
const c = raw?.[def.configKey] || raw;
|
|
1244
|
+
return buildS3Config(type, c);
|
|
1245
|
+
}
|
|
1246
|
+
var s3StoragePlugin = {
|
|
1247
|
+
name: "@kyro-cms/storage-s3",
|
|
1248
|
+
version: "1.0.0",
|
|
1249
|
+
description: "S3-compatible storage (AWS R2 GCS DigitalOcean Backblaze Wasabi)",
|
|
1250
|
+
init: (kyro) => {
|
|
1251
|
+
const registry = kyro.storageProviders;
|
|
1252
|
+
if (!registry) return;
|
|
1253
|
+
const pluginName = "@kyro-cms/storage-s3";
|
|
1254
|
+
for (const v of Object.values(s3Variants)) {
|
|
1255
|
+
registry.register({
|
|
1256
|
+
type: v.type,
|
|
1257
|
+
displayName: v.displayName,
|
|
1258
|
+
pluginName,
|
|
1259
|
+
configKey: v.configKey,
|
|
1260
|
+
configFields: v.configFields,
|
|
1261
|
+
extractConfig: (sc) => buildS3ConfigFromStorageConfig(v.type, v, sc),
|
|
1262
|
+
extractRawConfig: (raw) => buildS3ConfigFromRaw(v.type, v, raw),
|
|
1263
|
+
factory: (c) => createS3Storage(c)
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
|
|
1269
|
+
// src/plugins/storage-cloudinary.ts
|
|
1270
|
+
var cloudinaryStoragePlugin = {
|
|
1271
|
+
name: "@kyro-cms/storage-cloudinary",
|
|
1272
|
+
version: "1.0.0",
|
|
1273
|
+
description: "Cloudinary image and video storage",
|
|
1274
|
+
init: (kyro) => {
|
|
1275
|
+
const registry = kyro.storageProviders;
|
|
1276
|
+
if (!registry) return;
|
|
1277
|
+
registry.register({
|
|
1278
|
+
type: "cloudinary",
|
|
1279
|
+
displayName: "Cloudinary",
|
|
1280
|
+
pluginName: "@kyro-cms/storage-cloudinary",
|
|
1281
|
+
configKey: "cloudinary",
|
|
1282
|
+
configFields: [
|
|
1283
|
+
{ name: "cloudName", type: "text", label: "Cloud Name", required: true },
|
|
1284
|
+
{ name: "apiKey", type: "text", label: "API Key", required: true },
|
|
1285
|
+
{ name: "apiSecret", type: "password", label: "API Secret", required: true },
|
|
1286
|
+
{ name: "folder", type: "text", label: "Folder", admin: { placeholder: "Optional folder path" } },
|
|
1287
|
+
{
|
|
1288
|
+
name: "uploadPreset",
|
|
1289
|
+
type: "text",
|
|
1290
|
+
label: "Upload Preset (optional)",
|
|
1291
|
+
admin: { placeholder: "Leave empty for signed uploads", description: "If not set, uploads will be signed with API Secret" }
|
|
1292
|
+
}
|
|
1293
|
+
],
|
|
1294
|
+
extractConfig: (sc) => ({
|
|
1295
|
+
cloudName: sc.cloudinary?.cloudName || "",
|
|
1296
|
+
apiKey: sc.cloudinary?.apiKey || "",
|
|
1297
|
+
apiSecret: sc.cloudinary?.apiSecret || "",
|
|
1298
|
+
folder: sc.cloudinary?.folder,
|
|
1299
|
+
uploadPreset: sc.cloudinary?.uploadPreset
|
|
1300
|
+
}),
|
|
1301
|
+
extractRawConfig: (c) => {
|
|
1302
|
+
const cl = c?.cloudinary || c;
|
|
1303
|
+
return {
|
|
1304
|
+
cloudName: cl?.cloudName || "",
|
|
1305
|
+
apiKey: cl?.apiKey || "",
|
|
1306
|
+
apiSecret: cl?.apiSecret || "",
|
|
1307
|
+
folder: cl?.folder,
|
|
1308
|
+
uploadPreset: cl?.uploadPreset
|
|
1309
|
+
};
|
|
1310
|
+
},
|
|
1311
|
+
factory: (c) => createCloudinaryStorage(c)
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
|
|
1316
|
+
// src/plugins/storage-ftp.ts
|
|
1317
|
+
var ftpStoragePlugin = {
|
|
1318
|
+
name: "@kyro-cms/storage-ftp",
|
|
1319
|
+
version: "1.0.0",
|
|
1320
|
+
description: "FTP/SFTP storage provider",
|
|
1321
|
+
init: (kyro) => {
|
|
1322
|
+
const registry = kyro.storageProviders;
|
|
1323
|
+
if (!registry) return;
|
|
1324
|
+
registry.register({
|
|
1325
|
+
type: "ftp",
|
|
1326
|
+
displayName: "FTP",
|
|
1327
|
+
pluginName: "@kyro-cms/storage-ftp",
|
|
1328
|
+
configKey: "ftp",
|
|
1329
|
+
configFields: [
|
|
1330
|
+
{ name: "host", type: "text", label: "Host", required: true, admin: { placeholder: "ftp.example.com" } },
|
|
1331
|
+
{ name: "port", type: "number", label: "Port", defaultValue: 21, admin: { placeholder: "21 for FTP" } },
|
|
1332
|
+
{ name: "user", type: "text", label: "Username", required: true },
|
|
1333
|
+
{ name: "password", type: "password", label: "Password", required: true },
|
|
1334
|
+
{ name: "secure", type: "checkbox", label: "Use TLS/SSL", defaultValue: false, admin: { description: "Enable TLS/SSL for secure connections (FTP only)" } },
|
|
1335
|
+
{ name: "baseUrl", type: "text", label: "Base URL", required: true, admin: { placeholder: "https://files.example.com" } },
|
|
1336
|
+
{ name: "prefix", type: "text", label: "Path Prefix", admin: { placeholder: "uploads" } }
|
|
1337
|
+
],
|
|
1338
|
+
extractConfig: (sc) => ({
|
|
1339
|
+
host: sc.ftp?.host || "",
|
|
1340
|
+
port: sc.ftp?.port || 21,
|
|
1341
|
+
user: sc.ftp?.user || "",
|
|
1342
|
+
password: sc.ftp?.password || "",
|
|
1343
|
+
secure: sc.ftp?.secure || false,
|
|
1344
|
+
baseUrl: sc.ftp?.baseUrl || "",
|
|
1345
|
+
prefix: sc.ftp?.prefix,
|
|
1346
|
+
type: "ftp"
|
|
1347
|
+
}),
|
|
1348
|
+
extractRawConfig: (c) => {
|
|
1349
|
+
const ftp = c?.ftp || c;
|
|
1350
|
+
return {
|
|
1351
|
+
host: ftp?.host || "",
|
|
1352
|
+
port: ftp?.port || 21,
|
|
1353
|
+
user: ftp?.user || "",
|
|
1354
|
+
password: ftp?.password || "",
|
|
1355
|
+
secure: ftp?.secure || false,
|
|
1356
|
+
baseUrl: ftp?.baseUrl || "",
|
|
1357
|
+
prefix: ftp?.prefix,
|
|
1358
|
+
type: "ftp"
|
|
1359
|
+
};
|
|
1360
|
+
},
|
|
1361
|
+
factory: (c) => createFtpStorage(c)
|
|
1362
|
+
});
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
var builtinStoragePlugins = [
|
|
1366
|
+
s3StoragePlugin,
|
|
1367
|
+
cloudinaryStoragePlugin,
|
|
1368
|
+
ftpStoragePlugin
|
|
1369
|
+
];
|
|
1370
|
+
function updateFieldByPath(fields, path, updates) {
|
|
1371
|
+
const parts = path.split(".");
|
|
1372
|
+
if (parts.length === 0) return false;
|
|
1373
|
+
const currentPart = parts[0];
|
|
1374
|
+
const remainingPath = parts.slice(1).join(".");
|
|
1375
|
+
for (const field of fields) {
|
|
1376
|
+
if (field.name === currentPart) {
|
|
1377
|
+
if (remainingPath) {
|
|
1378
|
+
if (field.fields && Array.isArray(field.fields)) {
|
|
1379
|
+
return updateFieldByPath(field.fields, remainingPath, updates);
|
|
1380
|
+
}
|
|
1381
|
+
if (field.type === "array" && field.fields && Array.isArray(field.fields)) {
|
|
1382
|
+
return updateFieldByPath(field.fields, remainingPath, updates);
|
|
1383
|
+
}
|
|
1384
|
+
return false;
|
|
1385
|
+
} else {
|
|
1386
|
+
Object.assign(field, updates);
|
|
1387
|
+
return true;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
return false;
|
|
1392
|
+
}
|
|
1393
|
+
function applyCollectionOverrides(collections, overrides) {
|
|
1394
|
+
if (!overrides) return;
|
|
1395
|
+
for (const col of collections) {
|
|
1396
|
+
const override = overrides[col.slug];
|
|
1397
|
+
if (override) {
|
|
1398
|
+
const { fields: fieldOverrides, ...adminOverrides } = override;
|
|
1399
|
+
col.admin = { ...col.admin, ...adminOverrides };
|
|
1400
|
+
if (fieldOverrides && col.fields && Array.isArray(col.fields)) {
|
|
1401
|
+
for (const [fieldPath, fieldUpdates] of Object.entries(fieldOverrides)) {
|
|
1402
|
+
updateFieldByPath(col.fields, fieldPath, fieldUpdates);
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1089
1408
|
var Kyro = class {
|
|
1090
1409
|
registry;
|
|
1091
1410
|
db;
|
|
@@ -1100,12 +1419,18 @@ var Kyro = class {
|
|
|
1100
1419
|
this.db = config.adapter;
|
|
1101
1420
|
this.pubsub = new KyroPubSub(this.registry);
|
|
1102
1421
|
this.webhookService = createWebhookService(this.db);
|
|
1422
|
+
if (config.collections && config.admin?.collectionOverrides) {
|
|
1423
|
+
applyCollectionOverrides(config.collections, config.admin.collectionOverrides);
|
|
1424
|
+
}
|
|
1103
1425
|
if (config.collections) {
|
|
1104
1426
|
this.registry.addCollections(config.collections);
|
|
1105
1427
|
}
|
|
1106
1428
|
if (config.globals) {
|
|
1107
1429
|
this.registry.addGlobals(config.globals);
|
|
1108
1430
|
}
|
|
1431
|
+
for (const plugin of builtinStoragePlugins) {
|
|
1432
|
+
this.registry.addPlugin(plugin);
|
|
1433
|
+
}
|
|
1109
1434
|
if (config.plugins) {
|
|
1110
1435
|
for (const plugin of config.plugins) {
|
|
1111
1436
|
this.registry.addPlugin(plugin);
|
|
@@ -1114,6 +1439,17 @@ var Kyro = class {
|
|
|
1114
1439
|
}
|
|
1115
1440
|
async init() {
|
|
1116
1441
|
await this.registry.init();
|
|
1442
|
+
const storageGlobal = createStorageSettingsGlobal(
|
|
1443
|
+
this.registry.storageProviders,
|
|
1444
|
+
(name) => this.registry.storageProviders.isPluginEnabled(name)
|
|
1445
|
+
);
|
|
1446
|
+
this.registry.addGlobalPostInit(storageGlobal);
|
|
1447
|
+
const pluginSettingsGlobal = {
|
|
1448
|
+
slug: "plugin-settings",
|
|
1449
|
+
admin: { hidden: true },
|
|
1450
|
+
fields: [{ name: "states", type: "json" }]
|
|
1451
|
+
};
|
|
1452
|
+
this.registry.addGlobalPostInit(pluginSettingsGlobal);
|
|
1117
1453
|
if (!this.db) {
|
|
1118
1454
|
throw new Error(
|
|
1119
1455
|
`Database adapter is null \u2014 failed to load at startup. Check the server console for the exact error.`
|
|
@@ -1160,6 +1496,7 @@ var Kyro = class {
|
|
|
1160
1496
|
{ name: "nextRetryAt", type: "date" }
|
|
1161
1497
|
]
|
|
1162
1498
|
};
|
|
1499
|
+
const allGlobals = this.registry.getGlobals();
|
|
1163
1500
|
await this.db.init(
|
|
1164
1501
|
[
|
|
1165
1502
|
...this.registry.getCollections(),
|
|
@@ -1167,12 +1504,13 @@ var Kyro = class {
|
|
|
1167
1504
|
webhookCollection,
|
|
1168
1505
|
webhookDeliveryCollection
|
|
1169
1506
|
],
|
|
1170
|
-
|
|
1507
|
+
allGlobals
|
|
1171
1508
|
);
|
|
1509
|
+
await this.loadPluginState();
|
|
1172
1510
|
this.pubsub.autoRegisterHooks();
|
|
1173
1511
|
console.log("\u2705 Kyro CMS initialized");
|
|
1174
1512
|
console.log(` Collections: ${this.registry.getCollections().length}`);
|
|
1175
|
-
console.log(` Globals: ${
|
|
1513
|
+
console.log(` Globals: ${allGlobals.length}`);
|
|
1176
1514
|
}
|
|
1177
1515
|
// ============================================================================
|
|
1178
1516
|
// API Methods
|
|
@@ -1181,18 +1519,38 @@ var Kyro = class {
|
|
|
1181
1519
|
async loadSettings() {
|
|
1182
1520
|
if (this.settings) return this.settings;
|
|
1183
1521
|
try {
|
|
1184
|
-
const
|
|
1185
|
-
collection: "
|
|
1186
|
-
where: {
|
|
1522
|
+
const doc = await this.db.findOne({
|
|
1523
|
+
collection: "_globals_access-settings",
|
|
1524
|
+
where: {}
|
|
1187
1525
|
});
|
|
1188
|
-
if (
|
|
1189
|
-
this.settings =
|
|
1526
|
+
if (doc) {
|
|
1527
|
+
this.settings = { access: doc };
|
|
1190
1528
|
}
|
|
1191
1529
|
} catch (e) {
|
|
1192
1530
|
console.log("\u26A0\uFE0F No access-settings found, using defaults");
|
|
1193
1531
|
}
|
|
1194
1532
|
return this.settings || {};
|
|
1195
1533
|
}
|
|
1534
|
+
async loadPluginState() {
|
|
1535
|
+
const storageRegistry = this.registry.storageProviders;
|
|
1536
|
+
const pluginNames = storageRegistry.getAllPluginNames();
|
|
1537
|
+
let pluginStates = {};
|
|
1538
|
+
try {
|
|
1539
|
+
const doc = await this.db.findOne({
|
|
1540
|
+
collection: "_globals_plugin-settings",
|
|
1541
|
+
where: {}
|
|
1542
|
+
});
|
|
1543
|
+
if (doc && doc.states) {
|
|
1544
|
+
pluginStates = doc.states;
|
|
1545
|
+
}
|
|
1546
|
+
} catch (e) {
|
|
1547
|
+
}
|
|
1548
|
+
for (const name of pluginNames) {
|
|
1549
|
+
if (pluginStates[name] !== void 0) {
|
|
1550
|
+
storageRegistry.setPluginEnabled(name, pluginStates[name]);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1196
1554
|
getREST(options) {
|
|
1197
1555
|
const authObj = typeof this.config.auth === "object" ? this.config.auth : null;
|
|
1198
1556
|
const authSecret = authObj?.secret;
|
|
@@ -1210,33 +1568,196 @@ var Kyro = class {
|
|
|
1210
1568
|
});
|
|
1211
1569
|
}
|
|
1212
1570
|
getGraphQL(options) {
|
|
1213
|
-
|
|
1571
|
+
const defaultSchema = buildGraphQLSchema({
|
|
1214
1572
|
registry: this.registry,
|
|
1215
1573
|
db: this.db,
|
|
1216
|
-
|
|
1217
|
-
|
|
1574
|
+
settings: this.settings,
|
|
1575
|
+
user: options?.user,
|
|
1576
|
+
req: options?.req,
|
|
1577
|
+
tenantID: options?.tenantID
|
|
1218
1578
|
});
|
|
1579
|
+
return {
|
|
1580
|
+
fetch: async (request, _locals) => {
|
|
1581
|
+
const apiKeyRaw = extractApiKeyFromRequest(request);
|
|
1582
|
+
let gqlUser;
|
|
1583
|
+
let apiKeyCtx;
|
|
1584
|
+
if (apiKeyRaw && this.db) {
|
|
1585
|
+
const apiKeyResult = await validateApiKey(apiKeyRaw, this.db);
|
|
1586
|
+
if (!apiKeyResult.valid) {
|
|
1587
|
+
return new Response(
|
|
1588
|
+
JSON.stringify({ errors: [{ message: apiKeyResult.error || "Invalid API key" }] }),
|
|
1589
|
+
{ status: 401, headers: { "Content-Type": "application/json" } }
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1592
|
+
if (apiKeyResult.user) {
|
|
1593
|
+
gqlUser = apiKeyResult.user;
|
|
1594
|
+
apiKeyCtx = createApiKeyContext(apiKeyResult);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
const mustRebuild = gqlUser !== options?.user || apiKeyCtx !== void 0;
|
|
1598
|
+
const schema = mustRebuild ? buildGraphQLSchema({
|
|
1599
|
+
registry: this.registry,
|
|
1600
|
+
db: this.db,
|
|
1601
|
+
settings: this.settings,
|
|
1602
|
+
user: gqlUser,
|
|
1603
|
+
req: request,
|
|
1604
|
+
tenantID: options?.tenantID,
|
|
1605
|
+
apiKey: apiKeyCtx
|
|
1606
|
+
}) : defaultSchema;
|
|
1607
|
+
const body = request.method === "POST" ? await request.json().catch(() => ({})) : {};
|
|
1608
|
+
const query = body.query || "";
|
|
1609
|
+
const variables = body.variables || {};
|
|
1610
|
+
if (!query) {
|
|
1611
|
+
return new Response(
|
|
1612
|
+
JSON.stringify({ error: "No GraphQL query provided" }),
|
|
1613
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
1614
|
+
);
|
|
1615
|
+
}
|
|
1616
|
+
try {
|
|
1617
|
+
const document = parse(query);
|
|
1618
|
+
const result = await execute({
|
|
1619
|
+
schema,
|
|
1620
|
+
document,
|
|
1621
|
+
variableValues: variables,
|
|
1622
|
+
contextValue: {
|
|
1623
|
+
db: this.db,
|
|
1624
|
+
registry: this.registry,
|
|
1625
|
+
settings: this.settings,
|
|
1626
|
+
user: gqlUser,
|
|
1627
|
+
req: request,
|
|
1628
|
+
tenantID: options?.tenantID
|
|
1629
|
+
}
|
|
1630
|
+
});
|
|
1631
|
+
return new Response(JSON.stringify(result), {
|
|
1632
|
+
status: 200,
|
|
1633
|
+
headers: { "Content-Type": "application/json" }
|
|
1634
|
+
});
|
|
1635
|
+
} catch (err) {
|
|
1636
|
+
return new Response(
|
|
1637
|
+
JSON.stringify({ errors: [{ message: err.message }] }),
|
|
1638
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
},
|
|
1642
|
+
schema: defaultSchema
|
|
1643
|
+
};
|
|
1219
1644
|
}
|
|
1220
1645
|
getTRPC(options) {
|
|
1221
|
-
return
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1646
|
+
return {
|
|
1647
|
+
fetch: async (request, locals) => {
|
|
1648
|
+
const url = new URL(request.url);
|
|
1649
|
+
const path = url.pathname.replace(/^\/api\/trpc\//, "");
|
|
1650
|
+
const [slug, ...rest] = path.split(".");
|
|
1651
|
+
let procedureName = rest.join(".");
|
|
1652
|
+
procedureName = procedureName.replace(/\.(query|mutate|subscribe)$/, "");
|
|
1653
|
+
if (!slug || !procedureName) {
|
|
1654
|
+
return new Response(
|
|
1655
|
+
JSON.stringify({
|
|
1656
|
+
error: {
|
|
1657
|
+
message: "Invalid tRPC path",
|
|
1658
|
+
code: -32600,
|
|
1659
|
+
data: { code: "BAD_REQUEST", httpStatus: 400 }
|
|
1660
|
+
}
|
|
1661
|
+
}),
|
|
1662
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
const ctx = await createContext({
|
|
1666
|
+
db: this.db,
|
|
1667
|
+
registry: this.registry,
|
|
1668
|
+
req: request,
|
|
1669
|
+
user: options?.user,
|
|
1670
|
+
tenantID: options?.tenantID,
|
|
1671
|
+
settings: this.settings
|
|
1672
|
+
});
|
|
1673
|
+
const kyroRouter = createKyroServer(ctx);
|
|
1674
|
+
const collectionRouter = kyroRouter[slug];
|
|
1675
|
+
if (!collectionRouter) {
|
|
1676
|
+
return new Response(
|
|
1677
|
+
JSON.stringify({
|
|
1678
|
+
error: {
|
|
1679
|
+
message: `Collection '${slug}' not found`,
|
|
1680
|
+
code: -32601,
|
|
1681
|
+
data: { code: "NOT_FOUND", httpStatus: 404 }
|
|
1682
|
+
}
|
|
1683
|
+
}),
|
|
1684
|
+
{ status: 404, headers: { "Content-Type": "application/json" } }
|
|
1685
|
+
);
|
|
1686
|
+
}
|
|
1687
|
+
const procedure = collectionRouter[procedureName];
|
|
1688
|
+
if (typeof procedure !== "function") {
|
|
1689
|
+
return new Response(
|
|
1690
|
+
JSON.stringify({
|
|
1691
|
+
error: {
|
|
1692
|
+
message: `Procedure '${procedureName}' not found`,
|
|
1693
|
+
code: -32601,
|
|
1694
|
+
data: { code: "NOT_FOUND", httpStatus: 404 }
|
|
1695
|
+
}
|
|
1696
|
+
}),
|
|
1697
|
+
{ status: 404, headers: { "Content-Type": "application/json" } }
|
|
1698
|
+
);
|
|
1699
|
+
}
|
|
1700
|
+
try {
|
|
1701
|
+
let raw = {};
|
|
1702
|
+
if (request.method === "POST" || request.method === "PATCH") {
|
|
1703
|
+
raw = await request.json().catch(() => ({}));
|
|
1704
|
+
} else {
|
|
1705
|
+
const qs = new URL(request.url).searchParams.get("input");
|
|
1706
|
+
if (qs) {
|
|
1707
|
+
try {
|
|
1708
|
+
raw = JSON.parse(decodeURIComponent(qs));
|
|
1709
|
+
} catch {
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
const input = raw?.["0"] ?? raw;
|
|
1714
|
+
const result = await procedure({ ...input, collection: slug });
|
|
1715
|
+
return new Response(JSON.stringify({ result: { data: result } }), {
|
|
1716
|
+
status: 200,
|
|
1717
|
+
headers: { "Content-Type": "application/json" }
|
|
1718
|
+
});
|
|
1719
|
+
} catch (err) {
|
|
1720
|
+
const msg = err.message || "Internal error";
|
|
1721
|
+
const httpStatus = msg.includes("not found") ? 404 : msg.includes("denied") || msg.includes("authentication required") ? 403 : msg.includes("conflict") ? 409 : 500;
|
|
1722
|
+
const code = httpStatus === 404 ? -32601 : httpStatus === 403 ? -32001 : httpStatus === 409 ? -32002 : -32603;
|
|
1723
|
+
return new Response(
|
|
1724
|
+
JSON.stringify({
|
|
1725
|
+
error: {
|
|
1726
|
+
message: msg,
|
|
1727
|
+
code,
|
|
1728
|
+
data: {
|
|
1729
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
1730
|
+
httpStatus
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
}),
|
|
1734
|
+
{ status: httpStatus, headers: { "Content-Type": "application/json" } }
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1737
|
+
},
|
|
1738
|
+
router: null
|
|
1739
|
+
};
|
|
1740
|
+
}
|
|
1741
|
+
getWS() {
|
|
1742
|
+
return this.wsServer;
|
|
1228
1743
|
}
|
|
1229
1744
|
async startWebSocket(options) {
|
|
1230
1745
|
const apiAccess = this.settings?.access?.apiAccess;
|
|
1231
|
-
if (apiAccess?.
|
|
1746
|
+
if (apiAccess?.wsEnabled === false) {
|
|
1232
1747
|
console.log("\u26A0\uFE0F WebSocket is disabled in settings");
|
|
1233
1748
|
return null;
|
|
1234
1749
|
}
|
|
1750
|
+
const defaultVerifyToken = async (token) => {
|
|
1751
|
+
const result = await validateApiKey(token, this.db);
|
|
1752
|
+
if (!result.valid) throw new Error(result.error || "Invalid API key");
|
|
1753
|
+
if (!result.user) throw new Error("API key has no associated user");
|
|
1754
|
+
return result.user;
|
|
1755
|
+
};
|
|
1235
1756
|
this.wsServer = createWSServer({
|
|
1236
1757
|
pubsub: this.pubsub,
|
|
1237
1758
|
port: options?.port || 8080,
|
|
1238
1759
|
requireAuth: options?.requireAuth ?? apiAccess?.requireAuth,
|
|
1239
|
-
verifyToken: options?.verifyToken
|
|
1760
|
+
verifyToken: options?.verifyToken || defaultVerifyToken
|
|
1240
1761
|
});
|
|
1241
1762
|
console.log(`\u{1F50C} WebSocket server started on port ${options?.port || 8080}`);
|
|
1242
1763
|
return this.wsServer;
|
|
@@ -1361,13 +1882,6 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1361
1882
|
migrations = /* @__PURE__ */ new Map();
|
|
1362
1883
|
draftsTableName = "kyro_drafts";
|
|
1363
1884
|
versionsTableName = "kyro_versions";
|
|
1364
|
-
tenantContext;
|
|
1365
|
-
setTenantContext(context) {
|
|
1366
|
-
this.tenantContext = context;
|
|
1367
|
-
}
|
|
1368
|
-
getTenantContext() {
|
|
1369
|
-
return this.tenantContext;
|
|
1370
|
-
}
|
|
1371
1885
|
constructor(options) {
|
|
1372
1886
|
super();
|
|
1373
1887
|
this.path = options.path;
|
|
@@ -1381,6 +1895,34 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1381
1895
|
if (!this.db) {
|
|
1382
1896
|
this.db = new DatabaseSync(this.path || ":memory:");
|
|
1383
1897
|
}
|
|
1898
|
+
if (this.db && typeof this.db.prepare === "function" && !this.db.prepare.__wrapped) {
|
|
1899
|
+
const originalPrepare = this.db.prepare.bind(this.db);
|
|
1900
|
+
const wrappedPrepare = (sql) => {
|
|
1901
|
+
const stmt = originalPrepare(sql);
|
|
1902
|
+
const serialize = (val) => {
|
|
1903
|
+
if (typeof val === "boolean") return val ? 1 : 0;
|
|
1904
|
+
if (val === void 0) return null;
|
|
1905
|
+
return val;
|
|
1906
|
+
};
|
|
1907
|
+
return new Proxy(stmt, {
|
|
1908
|
+
get(target, prop, receiver) {
|
|
1909
|
+
if (prop === "all") {
|
|
1910
|
+
return (...params) => target.all(...params.map(serialize));
|
|
1911
|
+
}
|
|
1912
|
+
if (prop === "get") {
|
|
1913
|
+
return (...params) => target.get(...params.map(serialize));
|
|
1914
|
+
}
|
|
1915
|
+
if (prop === "run") {
|
|
1916
|
+
return (...params) => target.run(...params.map(serialize));
|
|
1917
|
+
}
|
|
1918
|
+
const val = Reflect.get(target, prop, receiver);
|
|
1919
|
+
return typeof val === "function" ? val.bind(target) : val;
|
|
1920
|
+
}
|
|
1921
|
+
});
|
|
1922
|
+
};
|
|
1923
|
+
wrappedPrepare.__wrapped = true;
|
|
1924
|
+
this.db.prepare = wrappedPrepare;
|
|
1925
|
+
}
|
|
1384
1926
|
this.db.exec("PRAGMA journal_mode = WAL");
|
|
1385
1927
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
1386
1928
|
this.connected = true;
|
|
@@ -1408,8 +1950,8 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1408
1950
|
}
|
|
1409
1951
|
columns.push(`${this.col("createdAt")} TEXT DEFAULT (datetime('now'))`);
|
|
1410
1952
|
columns.push(`${this.col("updatedAt")} TEXT DEFAULT (datetime('now'))`);
|
|
1411
|
-
columns.push(`
|
|
1412
|
-
columns.push(`
|
|
1953
|
+
columns.push(`publishStatus TEXT DEFAULT 'draft'`);
|
|
1954
|
+
columns.push(`hasDraft INTEGER DEFAULT 0`);
|
|
1413
1955
|
if (config.tenantScoped) {
|
|
1414
1956
|
columns.push(`tenant_id TEXT NOT NULL`);
|
|
1415
1957
|
}
|
|
@@ -1417,7 +1959,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1417
1959
|
if (existingColumns.length === 0) {
|
|
1418
1960
|
const createSQL = `CREATE TABLE IF NOT EXISTS ${name} (${columns.join(", ")})`;
|
|
1419
1961
|
this.db.exec(createSQL);
|
|
1420
|
-
this.db.exec(`CREATE INDEX IF NOT EXISTS idx_${name}
|
|
1962
|
+
this.db.exec(`CREATE INDEX IF NOT EXISTS idx_${name}_publishStatus ON ${name}(publishStatus)`);
|
|
1421
1963
|
for (const field of flattenFields(config.fields)) {
|
|
1422
1964
|
if (field.name && field.indexed) {
|
|
1423
1965
|
this.db.exec(
|
|
@@ -1436,9 +1978,9 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1436
1978
|
const colName = colDef.split(" ")[0].replace(/^"/, "").replace(/"$/, "");
|
|
1437
1979
|
if (!existingSet.has(colName) && colName !== "id") {
|
|
1438
1980
|
try {
|
|
1439
|
-
if (colName === "
|
|
1981
|
+
if (colName === "publishStatus") {
|
|
1440
1982
|
this.db.exec(`ALTER TABLE ${name} ADD COLUMN ${this.col(colName)} TEXT DEFAULT 'published'`);
|
|
1441
|
-
} else if (colName === "
|
|
1983
|
+
} else if (colName === "hasDraft") {
|
|
1442
1984
|
this.db.exec(`ALTER TABLE ${name} ADD COLUMN ${this.col(colName)} INTEGER DEFAULT 0`);
|
|
1443
1985
|
} else {
|
|
1444
1986
|
this.db.exec(`ALTER TABLE ${name} ADD COLUMN ${this.col(colName)} TEXT`);
|
|
@@ -1471,7 +2013,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1471
2013
|
`CREATE INDEX IF NOT EXISTS idx_${this.versionsTableName}_doc ON ${this.versionsTableName}(collection_slug, document_id)`
|
|
1472
2014
|
);
|
|
1473
2015
|
this.db.exec(
|
|
1474
|
-
`CREATE INDEX IF NOT EXISTS idx_${this.versionsTableName}
|
|
2016
|
+
`CREATE INDEX IF NOT EXISTS idx_${this.versionsTableName}publishStatus ON ${this.versionsTableName}(status)`
|
|
1475
2017
|
);
|
|
1476
2018
|
}
|
|
1477
2019
|
ensureDraftsTable() {
|
|
@@ -1572,7 +2114,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1572
2114
|
effectiveWhere = rlsQuery.where || {};
|
|
1573
2115
|
}
|
|
1574
2116
|
if (!draft && config.versions?.drafts) {
|
|
1575
|
-
conditions.push(`
|
|
2117
|
+
conditions.push(`publishStatus = ?`);
|
|
1576
2118
|
params.push("published");
|
|
1577
2119
|
}
|
|
1578
2120
|
if (tenantID && config.tenantScoped) {
|
|
@@ -1617,7 +2159,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1617
2159
|
}
|
|
1618
2160
|
if (draft) {
|
|
1619
2161
|
docs = await Promise.all(docs.map(async (doc) => {
|
|
1620
|
-
if (doc.
|
|
2162
|
+
if (doc.hasDraft) {
|
|
1621
2163
|
const versions = await this.findVersions({
|
|
1622
2164
|
collection: slug,
|
|
1623
2165
|
documentId: doc.id,
|
|
@@ -1625,7 +2167,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1625
2167
|
sort: "-createdAt"
|
|
1626
2168
|
});
|
|
1627
2169
|
if (versions.docs.length > 0 && versions.docs[0].status === "draft") {
|
|
1628
|
-
return { ...doc, ...versions.docs[0].data,
|
|
2170
|
+
return { ...doc, ...versions.docs[0].data, hasDraft: true, publishStatus: doc.publishStatus };
|
|
1629
2171
|
}
|
|
1630
2172
|
}
|
|
1631
2173
|
return doc;
|
|
@@ -1659,7 +2201,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1659
2201
|
}
|
|
1660
2202
|
}
|
|
1661
2203
|
if (!draft && config.versions?.drafts) {
|
|
1662
|
-
sql += ` AND
|
|
2204
|
+
sql += ` AND publishStatus = ?`;
|
|
1663
2205
|
params.push("published");
|
|
1664
2206
|
}
|
|
1665
2207
|
if (tenantID && config.tenantScoped) {
|
|
@@ -1669,7 +2211,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1669
2211
|
const row = this.db.prepare(sql).get(...params);
|
|
1670
2212
|
if (!row) return null;
|
|
1671
2213
|
let doc = this.rowToDoc(row, config);
|
|
1672
|
-
if (draft && doc.
|
|
2214
|
+
if (draft && doc.hasDraft) {
|
|
1673
2215
|
const versions = await this.findVersions({
|
|
1674
2216
|
collection: slug,
|
|
1675
2217
|
documentId: doc.id,
|
|
@@ -1677,7 +2219,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1677
2219
|
sort: "-createdAt"
|
|
1678
2220
|
});
|
|
1679
2221
|
if (versions.docs.length > 0 && versions.docs[0].status === "draft") {
|
|
1680
|
-
doc = { ...doc, ...versions.docs[0].data,
|
|
2222
|
+
doc = { ...doc, ...versions.docs[0].data, hasDraft: true, publishStatus: doc.publishStatus };
|
|
1681
2223
|
}
|
|
1682
2224
|
}
|
|
1683
2225
|
return doc;
|
|
@@ -1708,7 +2250,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1708
2250
|
const quotedColumns = filteredColumns.map((c) => this.col(c));
|
|
1709
2251
|
const placeholders = filteredColumns.map(() => "?").join(", ");
|
|
1710
2252
|
const values = Object.values(filteredData).map(
|
|
1711
|
-
(v) => typeof v === "object" ? JSON.stringify(v) : v
|
|
2253
|
+
(v) => v !== null && typeof v === "object" ? JSON.stringify(v) : v
|
|
1712
2254
|
);
|
|
1713
2255
|
this.db.prepare(
|
|
1714
2256
|
`INSERT OR REPLACE INTO ${tableName} (${quotedColumns.join(", ")}) VALUES (${placeholders})`
|
|
@@ -1788,7 +2330,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1788
2330
|
const conditions = [];
|
|
1789
2331
|
const params = [];
|
|
1790
2332
|
if (!args.draft && globalConfig.versions) {
|
|
1791
|
-
conditions.push("
|
|
2333
|
+
conditions.push("publishStatus = 'published'");
|
|
1792
2334
|
}
|
|
1793
2335
|
if (conditions.length > 0) {
|
|
1794
2336
|
sql += ` WHERE ${conditions.join(" AND ")}`;
|
|
@@ -1797,7 +2339,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1797
2339
|
const result2 = this.db.prepare(sql).get(...params);
|
|
1798
2340
|
if (result2) {
|
|
1799
2341
|
let doc = this.rowToDoc(result2, globalConfig);
|
|
1800
|
-
if (args.draft && doc.
|
|
2342
|
+
if (args.draft && doc.hasDraft) {
|
|
1801
2343
|
const versions = await this.findVersions({
|
|
1802
2344
|
collection: args.collection,
|
|
1803
2345
|
documentId: parsed.globalSlug,
|
|
@@ -1805,7 +2347,7 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
1805
2347
|
sort: "-createdAt"
|
|
1806
2348
|
});
|
|
1807
2349
|
if (versions.docs.length > 0 && versions.docs[0].status === "draft") {
|
|
1808
|
-
doc = { ...doc, ...versions.docs[0].data,
|
|
2350
|
+
doc = { ...doc, ...versions.docs[0].data, hasDraft: true, publishStatus: doc.publishStatus };
|
|
1809
2351
|
}
|
|
1810
2352
|
}
|
|
1811
2353
|
return doc;
|
|
@@ -2147,6 +2689,8 @@ var LocalAdapter = class extends AbstractBaseAdapter {
|
|
|
2147
2689
|
if (config.tenantScoped) {
|
|
2148
2690
|
doc.tenantID = row.tenant_id;
|
|
2149
2691
|
}
|
|
2692
|
+
doc.publishStatus = row.publishStatus ?? "published";
|
|
2693
|
+
doc.hasDraft = row.hasDraft ? Boolean(row.hasDraft) : false;
|
|
2150
2694
|
return doc;
|
|
2151
2695
|
}
|
|
2152
2696
|
generateId() {
|
|
@@ -2232,5 +2776,5 @@ function createLocalAdapter(options) {
|
|
|
2232
2776
|
}
|
|
2233
2777
|
|
|
2234
2778
|
export { ConfigValidationError, Kyro, LocalAdapter, Registry, collectionToCreateZod, collectionToUpdateZod, collectionToWhereZod, collectionToZod, createKyro, createLocalAdapter, createRegistry, fieldToZod, getRegistry, globalToZod, resetRegistry, validateCollection, validateConfig, validateFields, validateGlobal };
|
|
2235
|
-
//# sourceMappingURL=chunk-
|
|
2236
|
-
//# sourceMappingURL=chunk-
|
|
2779
|
+
//# sourceMappingURL=chunk-22M4O4ZJ.js.map
|
|
2780
|
+
//# sourceMappingURL=chunk-22M4O4ZJ.js.map
|