@kyro-cms/core 0.9.6 → 0.9.8

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 (91) hide show
  1. package/dist/{WebhookService-BKszZlG0.d.cts → WebhookService-Dj8pJ3sp.d.cts} +1 -1
  2. package/dist/{WebhookService-Ccf1j-IN.d.ts → WebhookService-DpRB940h.d.ts} +1 -1
  3. package/dist/api-handler-graphql.cjs +11 -11
  4. package/dist/api-handler-graphql.js +7 -7
  5. package/dist/api-handler-trpc.cjs +9 -9
  6. package/dist/api-handler-trpc.js +7 -7
  7. package/dist/api-handler.cjs +10 -10
  8. package/dist/api-handler.js +7 -7
  9. package/dist/{base-CIuXkrH4.d.cts → base-BjyoF6da.d.cts} +2 -2
  10. package/dist/{base-fFo4lqER.d.ts → base-C2YR8lWt.d.ts} +2 -2
  11. package/dist/{chunk-QVJNSAQL.cjs → chunk-2CBCU5ML.cjs} +47 -41
  12. package/dist/chunk-2CBCU5ML.cjs.map +1 -0
  13. package/dist/{chunk-NZEUU7QB.js → chunk-2GXALYKV.js} +2 -2
  14. package/dist/chunk-2GXALYKV.js.map +1 -0
  15. package/dist/{chunk-3UK5XBVJ.js → chunk-2Z7YAJBS.js} +10 -9
  16. package/dist/chunk-2Z7YAJBS.js.map +1 -0
  17. package/dist/{chunk-QX3WNQ7V.js → chunk-65DSXNQL.js} +4 -4
  18. package/dist/{chunk-QX3WNQ7V.js.map → chunk-65DSXNQL.js.map} +1 -1
  19. package/dist/{chunk-PONTBXR5.js → chunk-6DURKQ6W.js} +370 -140
  20. package/dist/chunk-6DURKQ6W.js.map +1 -0
  21. package/dist/{chunk-AX2TZRQJ.js → chunk-EQTMBMDR.js} +3 -3
  22. package/dist/{chunk-AX2TZRQJ.js.map → chunk-EQTMBMDR.js.map} +1 -1
  23. package/dist/{chunk-E5UJBLQ7.js → chunk-FIAMXNTH.js} +2 -2
  24. package/dist/chunk-FIAMXNTH.js.map +1 -0
  25. package/dist/{chunk-VLK5SJRI.js → chunk-HA4MGAZJ.js} +28 -22
  26. package/dist/chunk-HA4MGAZJ.js.map +1 -0
  27. package/dist/{chunk-FKKQUMXR.cjs → chunk-KGJRJ7CU.cjs} +2 -2
  28. package/dist/chunk-KGJRJ7CU.cjs.map +1 -0
  29. package/dist/{chunk-FSKONGCX.cjs → chunk-OJ2AM75W.cjs} +2 -2
  30. package/dist/chunk-OJ2AM75W.cjs.map +1 -0
  31. package/dist/{chunk-DRVOUQMT.cjs → chunk-OVZO4KB6.cjs} +45 -79
  32. package/dist/chunk-OVZO4KB6.cjs.map +1 -0
  33. package/dist/{chunk-RRKCIAPU.cjs → chunk-PF642V5O.cjs} +372 -140
  34. package/dist/chunk-PF642V5O.cjs.map +1 -0
  35. package/dist/{chunk-OZ3CCTTA.cjs → chunk-PJ7F4TCC.cjs} +5 -5
  36. package/dist/{chunk-OZ3CCTTA.cjs.map → chunk-PJ7F4TCC.cjs.map} +1 -1
  37. package/dist/{chunk-HVCUIII2.cjs → chunk-W3GT55TY.cjs} +13 -13
  38. package/dist/{chunk-HVCUIII2.cjs.map → chunk-W3GT55TY.cjs.map} +1 -1
  39. package/dist/{chunk-QFLB4EIJ.cjs → chunk-Z7OH3MWT.cjs} +10 -9
  40. package/dist/chunk-Z7OH3MWT.cjs.map +1 -0
  41. package/dist/{chunk-CMXVTUYV.js → chunk-ZFHTJ2YX.js} +29 -63
  42. package/dist/chunk-ZFHTJ2YX.js.map +1 -0
  43. package/dist/client.cjs +3 -3
  44. package/dist/client.d.cts +2 -2
  45. package/dist/client.d.ts +2 -2
  46. package/dist/client.js +1 -1
  47. package/dist/drizzle/index.d.cts +3 -3
  48. package/dist/drizzle/index.d.ts +3 -3
  49. package/dist/fields/index.cjs +21 -21
  50. package/dist/fields/index.d.cts +1 -1
  51. package/dist/fields/index.d.ts +1 -1
  52. package/dist/fields/index.js +1 -1
  53. package/dist/graphql/index.cjs +13 -5
  54. package/dist/graphql/index.d.cts +34 -12
  55. package/dist/graphql/index.d.ts +34 -12
  56. package/dist/graphql/index.js +2 -2
  57. package/dist/{index-BKta3cBH.d.cts → index-DHbywDs-.d.cts} +2 -2
  58. package/dist/{index-ClOqnkTO.d.ts → index-jLs0zlft.d.ts} +2 -2
  59. package/dist/index.cjs +90 -90
  60. package/dist/index.d.cts +9 -9
  61. package/dist/index.d.ts +9 -9
  62. package/dist/index.js +8 -8
  63. package/dist/mongodb/index.d.cts +3 -3
  64. package/dist/mongodb/index.d.ts +3 -3
  65. package/dist/rest/index.cjs +5 -5
  66. package/dist/rest/index.d.cts +4 -4
  67. package/dist/rest/index.d.ts +4 -4
  68. package/dist/rest/index.js +3 -3
  69. package/dist/templates/index.d.cts +2 -2
  70. package/dist/templates/index.d.ts +2 -2
  71. package/dist/trpc/index.cjs +12 -12
  72. package/dist/trpc/index.d.cts +3 -3
  73. package/dist/trpc/index.d.ts +3 -3
  74. package/dist/trpc/index.js +3 -3
  75. package/dist/{types-Dgzlftb7.d.ts → types-BzH3_rtP.d.ts} +7 -7
  76. package/dist/{types-Ds0tCA3L.d.cts → types-CY_iNunL.d.cts} +7 -7
  77. package/dist/{types-DeSApf9T.d.ts → types-C_rVxU2T.d.cts} +4 -4
  78. package/dist/{types-DeSApf9T.d.cts → types-C_rVxU2T.d.ts} +4 -4
  79. package/package.json +2 -1
  80. package/dist/chunk-3UK5XBVJ.js.map +0 -1
  81. package/dist/chunk-CMXVTUYV.js.map +0 -1
  82. package/dist/chunk-DRVOUQMT.cjs.map +0 -1
  83. package/dist/chunk-E5UJBLQ7.js.map +0 -1
  84. package/dist/chunk-FKKQUMXR.cjs.map +0 -1
  85. package/dist/chunk-FSKONGCX.cjs.map +0 -1
  86. package/dist/chunk-NZEUU7QB.js.map +0 -1
  87. package/dist/chunk-PONTBXR5.js.map +0 -1
  88. package/dist/chunk-QFLB4EIJ.cjs.map +0 -1
  89. package/dist/chunk-QVJNSAQL.cjs.map +0 -1
  90. package/dist/chunk-RRKCIAPU.cjs.map +0 -1
  91. package/dist/chunk-VLK5SJRI.js.map +0 -1
@@ -1,7 +1,22 @@
1
- import { checkCollectionAccess, checkGlobalAccess } from './chunk-NZEUU7QB.js';
2
- import { GraphQLObjectType, GraphQLString, GraphQLInputObjectType, GraphQLBoolean, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLSchema, printSchema, GraphQLUnionType, GraphQLFloat, GraphQLEnumType } from 'graphql';
1
+ import { checkCollectionAccess, checkGlobalAccess } from './chunk-2GXALYKV.js';
2
+ import { GraphQLError, GraphQLObjectType, GraphQLString, GraphQLNonNull, GraphQLInputObjectType, GraphQLBoolean, GraphQLInt, GraphQLList, GraphQLDirective, DirectiveLocation, printSchema, GraphQLSchema, GraphQLUnionType, GraphQLFloat, GraphQLEnumType } from 'graphql';
3
3
  export { printSchema } from 'graphql';
4
4
 
5
+ function toPascalCase(slug) {
6
+ return slug.split(/[-_]/).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
7
+ }
8
+ function toCamelCase(slug) {
9
+ const p = toPascalCase(slug);
10
+ return p.charAt(0).toLowerCase() + p.slice(1);
11
+ }
12
+ function toPascalSingular(slug) {
13
+ const p = toPascalCase(slug);
14
+ if (p.endsWith("s") && p.length > 1) return p.slice(0, -1);
15
+ return p;
16
+ }
17
+ function toCamelSingular(slug) {
18
+ return toCamelCase(slug).endsWith("s") && slug.length > 1 ? toCamelCase(slug).slice(0, -1) : toCamelCase(slug);
19
+ }
5
20
  var RelationLoader = class {
6
21
  db;
7
22
  tenantID;
@@ -68,6 +83,24 @@ function gqlError(message, code) {
68
83
  err.extensions = { code };
69
84
  return err;
70
85
  }
86
+ function depthLimit(maxDepth) {
87
+ return (validationContext) => {
88
+ let depth = 0;
89
+ return {
90
+ Field() {
91
+ depth++;
92
+ if (depth > maxDepth) {
93
+ validationContext.reportError(
94
+ new GraphQLError(`Query exceeds max depth of ${maxDepth}`)
95
+ );
96
+ }
97
+ },
98
+ leaveField() {
99
+ depth--;
100
+ }
101
+ };
102
+ };
103
+ }
71
104
  async function checkAccess(config, operation, context) {
72
105
  const result = await checkCollectionAccess(config, operation, context);
73
106
  if (!result.allowed) {
@@ -81,7 +114,7 @@ async function checkGqlGlobalAccess(config, operation, context) {
81
114
  throw gqlError(result.error || "Access denied", "FORBIDDEN");
82
115
  }
83
116
  }
84
- function fieldToGraphQLType(field, registry, collectionTypes, isInputType = false, loader) {
117
+ function fieldToGraphQLType(field, registry, collectionTypes, isInputType = false) {
85
118
  switch (field.type) {
86
119
  case "text":
87
120
  case "email":
@@ -119,9 +152,8 @@ function fieldToGraphQLType(field, registry, collectionTypes, isInputType = fals
119
152
  }
120
153
  const relatedCollection = registry.getCollection(field.relationTo);
121
154
  if (relatedCollection) {
122
- const refName = `${field.relationTo.replace(/-/g, "_")}_ref`;
123
155
  const refType = new GraphQLObjectType({
124
- name: refName,
156
+ name: toPascalSingular(field.relationTo),
125
157
  fields: () => ({
126
158
  id: { type: GraphQLString },
127
159
  ...buildFieldsFromCollection(relatedCollection, registry, collectionTypes)
@@ -138,21 +170,35 @@ function fieldToGraphQLType(field, registry, collectionTypes, isInputType = fals
138
170
  }
139
171
  return field.hasMany ? new GraphQLList(GraphQLString) : GraphQLString;
140
172
  case "array": {
141
- if (isInputType) return GraphQLString;
173
+ if (isInputType) {
174
+ const arrFields2 = field.fields;
175
+ if (arrFields2 && arrFields2.length > 0) {
176
+ const arrTypeName = `${field.name?.replace(/-/g, "_") || "array"}_input_item`;
177
+ return new GraphQLList(fieldsToGraphQLInputObjectType(arrTypeName, arrFields2, registry));
178
+ }
179
+ return new GraphQLList(GraphQLString);
180
+ }
142
181
  const arrFields = field.fields;
143
182
  if (arrFields && arrFields.length > 0) {
144
183
  const arrTypeName = `${field.name?.replace(/-/g, "_") || "array"}_item`;
145
- const itemType = fieldsToGraphQLObjectType(arrTypeName, arrFields, registry, collectionTypes, loader);
184
+ const itemType = fieldsToGraphQLObjectType(arrTypeName, arrFields, registry, collectionTypes);
146
185
  return new GraphQLList(itemType);
147
186
  }
148
187
  return new GraphQLList(GraphQLString);
149
188
  }
150
189
  case "group": {
151
- if (isInputType) return GraphQLString;
190
+ if (isInputType) {
191
+ const groupFields2 = field.fields;
192
+ if (groupFields2 && groupFields2.length > 0) {
193
+ const groupTypeName = `${field.name?.replace(/-/g, "_") || "group"}_input_group`;
194
+ return fieldsToGraphQLInputObjectType(groupTypeName, groupFields2, registry);
195
+ }
196
+ return GraphQLString;
197
+ }
152
198
  const groupFields = field.fields;
153
199
  if (groupFields && groupFields.length > 0) {
154
200
  const groupTypeName = `${field.name?.replace(/-/g, "_") || "group"}_group`;
155
- return fieldsToGraphQLObjectType(groupTypeName, groupFields, registry, collectionTypes, loader);
201
+ return fieldsToGraphQLObjectType(groupTypeName, groupFields, registry, collectionTypes);
156
202
  }
157
203
  return GraphQLString;
158
204
  }
@@ -162,7 +208,7 @@ function fieldToGraphQLType(field, registry, collectionTypes, isInputType = fals
162
208
  if (blocks && blocks.length > 0) {
163
209
  const blockTypes = [];
164
210
  for (const block of blocks) {
165
- const blockTypeName = `Block_${block.slug.replace(/-/g, "_")}`;
211
+ const blockTypeName = `Block${toPascalCase(block.slug)}`;
166
212
  const bType = new GraphQLObjectType({
167
213
  name: blockTypeName,
168
214
  fields: () => {
@@ -173,7 +219,7 @@ function fieldToGraphQLType(field, registry, collectionTypes, isInputType = fals
173
219
  if (block.fields) {
174
220
  for (const bf of block.fields) {
175
221
  if (!bf.name) continue;
176
- const bfConfig = buildFieldConfig(bf, registry, collectionTypes, loader);
222
+ const bfConfig = buildFieldConfig(bf, registry, collectionTypes);
177
223
  if (bfConfig) out[bf.name] = bfConfig;
178
224
  }
179
225
  }
@@ -188,7 +234,7 @@ function fieldToGraphQLType(field, registry, collectionTypes, isInputType = fals
188
234
  name: unionName,
189
235
  types: blockTypes,
190
236
  resolveType(value) {
191
- const blockName = `Block_${(value?.blockType || "").replace(/-/g, "_")}`;
237
+ const blockName = `Block${value?.blockType ? toPascalCase(value.blockType) : ""}`;
192
238
  const blockType = blockTypes.find(
193
239
  (bt) => bt.name === blockName
194
240
  );
@@ -207,11 +253,11 @@ function fieldToGraphQLType(field, registry, collectionTypes, isInputType = fals
207
253
  return GraphQLString;
208
254
  }
209
255
  }
210
- function buildFieldsFromCollection(config, registry, collectionTypes, loader) {
256
+ function buildFieldsFromCollection(config, registry, collectionTypes) {
211
257
  const fields = {};
212
258
  for (const field of config.fields) {
213
259
  if (field.name && field.admin?.hidden !== true) {
214
- const fc = buildFieldConfig(field, registry, collectionTypes, loader);
260
+ const fc = buildFieldConfig(field, registry, collectionTypes);
215
261
  if (fc) fields[field.name] = fc;
216
262
  }
217
263
  }
@@ -231,7 +277,7 @@ function buildSortEnum(config) {
231
277
  }
232
278
  }
233
279
  return new GraphQLEnumType({
234
- name: `${config.slug.replace(/-/g, "_")}_sort`,
280
+ name: `${toPascalSingular(config.slug)}Sort`,
235
281
  values: sortFields
236
282
  });
237
283
  }
@@ -329,7 +375,7 @@ function buildCollectionFilterType(config, namePrefix) {
329
375
  }
330
376
  }
331
377
  return new GraphQLInputObjectType({
332
- name: `${namePrefix}_filter`,
378
+ name: `${namePrefix}Filter`,
333
379
  fields
334
380
  });
335
381
  }
@@ -342,7 +388,42 @@ function translateFilter(filter) {
342
388
  }
343
389
  return result;
344
390
  }
345
- function fieldsToGraphQLObjectType(name, fields, registry, collectionTypes, loader) {
391
+ function fieldsToGraphQLInputObjectType(name, fields, registry) {
392
+ return new GraphQLInputObjectType({
393
+ name,
394
+ fields: () => {
395
+ const out = {};
396
+ for (const field of fields) {
397
+ if (!field.name) continue;
398
+ if (field.type === "row" || field.type === "collapsible") {
399
+ const subFields = field.fields;
400
+ if (subFields) {
401
+ for (const sf of subFields) {
402
+ if (!sf.name) continue;
403
+ out[sf.name] = { type: fieldToGraphQLType(sf, registry, void 0, true) };
404
+ }
405
+ }
406
+ } else if (field.type === "tabs") {
407
+ const tabs = field.tabs;
408
+ if (tabs) {
409
+ for (const tab of tabs) {
410
+ if (tab.fields) {
411
+ for (const sf of tab.fields) {
412
+ if (!sf.name) continue;
413
+ out[sf.name] = { type: fieldToGraphQLType(sf, registry, void 0, true) };
414
+ }
415
+ }
416
+ }
417
+ }
418
+ } else {
419
+ out[field.name] = { type: fieldToGraphQLType(field, registry, void 0, true) };
420
+ }
421
+ }
422
+ return out;
423
+ }
424
+ });
425
+ }
426
+ function fieldsToGraphQLObjectType(name, fields, registry, collectionTypes) {
346
427
  return new GraphQLObjectType({
347
428
  name,
348
429
  fields: () => {
@@ -354,7 +435,7 @@ function fieldsToGraphQLObjectType(name, fields, registry, collectionTypes, load
354
435
  if (subFields) {
355
436
  for (const sf of subFields) {
356
437
  if (!sf.name) continue;
357
- const fc = buildFieldConfig(sf, registry, collectionTypes, loader);
438
+ const fc = buildFieldConfig(sf, registry, collectionTypes);
358
439
  if (fc) out[sf.name] = fc;
359
440
  }
360
441
  }
@@ -365,14 +446,14 @@ function fieldsToGraphQLObjectType(name, fields, registry, collectionTypes, load
365
446
  if (tab.fields) {
366
447
  for (const sf of tab.fields) {
367
448
  if (!sf.name) continue;
368
- const fc = buildFieldConfig(sf, registry, collectionTypes, loader);
449
+ const fc = buildFieldConfig(sf, registry, collectionTypes);
369
450
  if (fc) out[sf.name] = fc;
370
451
  }
371
452
  }
372
453
  }
373
454
  }
374
455
  } else {
375
- const fc = buildFieldConfig(field, registry, collectionTypes, loader);
456
+ const fc = buildFieldConfig(field, registry, collectionTypes);
376
457
  if (fc) out[field.name] = fc;
377
458
  }
378
459
  }
@@ -380,14 +461,17 @@ function fieldsToGraphQLObjectType(name, fields, registry, collectionTypes, load
380
461
  }
381
462
  });
382
463
  }
383
- function buildFieldConfig(field, registry, collectionTypes, loader) {
464
+ function buildFieldConfig(field, registry, collectionTypes) {
384
465
  if (!field.name) return null;
466
+ const deprecationReason = field.deprecated || void 0;
385
467
  if (field.type === "relationship" && !field.hasMany) {
386
- const gqlType = fieldToGraphQLType(field, registry, collectionTypes, false, loader);
468
+ const gqlType = fieldToGraphQLType(field, registry, collectionTypes, false);
387
469
  return {
388
470
  type: field.required ? new GraphQLNonNull(gqlType) : gqlType,
389
471
  description: field.admin?.description || field.label,
390
- resolve: (source) => {
472
+ deprecationReason,
473
+ resolve: (source, args, ctx) => {
474
+ const loader = ctx?.relationLoader;
391
475
  const relField = field;
392
476
  const id = source?.[relField.name];
393
477
  if (!id) return null;
@@ -401,11 +485,13 @@ function buildFieldConfig(field, registry, collectionTypes, loader) {
401
485
  };
402
486
  }
403
487
  if (field.type === "relationship" && field.hasMany) {
404
- const gqlType = fieldToGraphQLType(field, registry, collectionTypes, false, loader);
488
+ const gqlType = fieldToGraphQLType(field, registry, collectionTypes, false);
405
489
  return {
406
490
  type: gqlType,
407
491
  description: field.admin?.description || field.label,
408
- resolve: (source) => {
492
+ deprecationReason,
493
+ resolve: (source, args, ctx) => {
494
+ const loader = ctx?.relationLoader;
409
495
  const relField = field;
410
496
  const ids = source?.[relField.name] || [];
411
497
  if (!ids.length) return [];
@@ -426,27 +512,27 @@ function buildFieldConfig(field, registry, collectionTypes, loader) {
426
512
  };
427
513
  }
428
514
  return {
429
- type: field.required ? new GraphQLNonNull(fieldToGraphQLType(field, registry, collectionTypes, false, loader)) : fieldToGraphQLType(field, registry, collectionTypes, false, loader),
430
- description: field.admin?.description || field.label
515
+ type: field.required ? new GraphQLNonNull(fieldToGraphQLType(field, registry, collectionTypes, false)) : fieldToGraphQLType(field, registry, collectionTypes, false),
516
+ description: field.admin?.description || field.label,
517
+ deprecationReason
431
518
  };
432
519
  }
433
520
  function buildGraphQLSchema(options) {
434
- const { registry, db, user, req, tenantID, apiKey, settings } = options;
521
+ const { registry, db, settings } = options;
435
522
  const apiAccess = settings?.access?.apiAccess;
436
523
  if (apiAccess?.graphqlEnabled === false) {
437
524
  throw new Error("GraphQL API is disabled");
438
525
  }
439
526
  const collections = registry.getCollections();
440
527
  const globals = registry.getGlobals();
441
- const relationLoader = new RelationLoader({ db, tenantID, user });
442
528
  const collectionTypes = {};
443
529
  const collectionInputTypes = {};
444
530
  for (const collection of collections) {
445
531
  collectionTypes[collection.slug] = new GraphQLObjectType({
446
- name: `${collection.slug.replace(/-/g, "_")}_type`,
532
+ name: toPascalSingular(collection.slug),
447
533
  fields: () => ({
448
- id: { type: GraphQLString },
449
- ...buildFieldsFromCollection(collection, registry, collectionTypes, relationLoader),
534
+ id: { type: new GraphQLNonNull(GraphQLString) },
535
+ ...buildFieldsFromCollection(collection, registry, collectionTypes),
450
536
  ...collection.timestamps ? {
451
537
  createdAt: { type: GraphQLString },
452
538
  updatedAt: { type: GraphQLString }
@@ -465,7 +551,7 @@ function buildGraphQLSchema(options) {
465
551
  }
466
552
  }
467
553
  collectionInputTypes[collection.slug] = new GraphQLInputObjectType({
468
- name: `${collection.slug.replace(/-/g, "_")}_input`,
554
+ name: `${toPascalSingular(collection.slug)}Input`,
469
555
  fields: () => inputFields
470
556
  });
471
557
  }
@@ -473,19 +559,18 @@ function buildGraphQLSchema(options) {
473
559
  const globalInputTypes = {};
474
560
  for (const global of globals) {
475
561
  globalTypes[global.slug] = new GraphQLObjectType({
476
- name: `${global.slug.replace(/-/g, "_")}_global_type`,
562
+ name: toPascalCase(global.slug),
477
563
  fields: () => ({
478
564
  id: { type: GraphQLString },
479
565
  ...buildFieldsFromCollection(
480
566
  { slug: global.slug, fields: global.fields },
481
567
  registry,
482
- collectionTypes,
483
- relationLoader
568
+ collectionTypes
484
569
  )
485
570
  })
486
571
  });
487
572
  globalInputTypes[global.slug] = new GraphQLInputObjectType({
488
- name: `${global.slug.replace(/-/g, "_")}_global_input`,
573
+ name: `${toPascalCase(global.slug)}Input`,
489
574
  fields: () => {
490
575
  const inputFields = {};
491
576
  for (const field of global.fields) {
@@ -499,15 +584,24 @@ function buildGraphQLSchema(options) {
499
584
  }
500
585
  });
501
586
  }
587
+ const pageInfoType = new GraphQLObjectType({
588
+ name: "PageInfo",
589
+ fields: {
590
+ hasNextPage: { type: new GraphQLNonNull(GraphQLBoolean) },
591
+ hasPreviousPage: { type: new GraphQLNonNull(GraphQLBoolean) },
592
+ startCursor: { type: GraphQLString },
593
+ endCursor: { type: GraphQLString }
594
+ }
595
+ });
502
596
  const queryFields = {};
503
597
  for (const collection of collections) {
504
598
  const type = collectionTypes[collection.slug];
505
599
  if (!type) continue;
506
- const filterType = buildCollectionFilterType(collection, collection.slug.replace(/-/g, "_"));
600
+ const filterType = buildCollectionFilterType(collection, toPascalSingular(collection.slug));
507
601
  const sortEnum = buildSortEnum(collection);
508
- queryFields[`${collection.slug.replace(/-/g, "_")}Find`] = {
602
+ queryFields[toCamelCase(collection.slug)] = {
509
603
  type: new GraphQLObjectType({
510
- name: `${collection.slug.replace(/-/g, "_")}_find_result`,
604
+ name: `${toPascalSingular(collection.slug)}FindResult`,
511
605
  fields: {
512
606
  docs: { type: new GraphQLList(type) },
513
607
  totalDocs: { type: GraphQLInt },
@@ -525,14 +619,15 @@ function buildGraphQLSchema(options) {
525
619
  draft: { type: GraphQLBoolean }
526
620
  },
527
621
  resolve: async (_, args, ctx) => {
622
+ const { user: ctxUser, req: ctxReq, tenantID: ctxTenant, apiKey: ctxApiKey, db: ctxDb, relationLoader: ctxLoader } = ctx;
528
623
  const extraWhere = await checkAccess(collection, "read", {
529
- user,
530
- req,
531
- tenantID,
532
- apiKey
624
+ user: ctxUser,
625
+ req: ctxReq,
626
+ tenantID: ctxTenant,
627
+ apiKey: ctxApiKey
533
628
  });
534
- if (tenantID) {
535
- db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
629
+ if (ctxTenant) {
630
+ ctxDb.setTenantContext({ tenantId: ctxTenant, userId: ctxUser?.id ?? "", role: ctxUser?.role, isSuperAdmin: ctxUser?.role === "super_admin" });
536
631
  }
537
632
  let where = {};
538
633
  if (args.where) {
@@ -548,51 +643,52 @@ function buildGraphQLSchema(options) {
548
643
  if (extraWhere) {
549
644
  where = { ...where, ...extraWhere };
550
645
  }
551
- const isDraft = args.draft ?? !!user;
552
- return RelationLoader.withBatch(relationLoader, async () => {
553
- return db.find({
646
+ const isDraft = args.draft ?? !!ctxUser;
647
+ return RelationLoader.withBatch(ctxLoader, async () => {
648
+ return ctxDb.find({
554
649
  collection: collection.slug,
555
650
  where,
556
651
  sort: args.sort,
557
652
  limit: args.limit || 10,
558
653
  page: args.page || 1,
559
- tenantID,
654
+ tenantID: ctxTenant,
560
655
  draft: isDraft
561
656
  });
562
657
  });
563
658
  }
564
659
  };
565
- queryFields[`${collection.slug.replace(/-/g, "_")}FindByID`] = {
660
+ queryFields[toCamelSingular(collection.slug)] = {
566
661
  type,
567
662
  args: {
568
663
  id: { type: new GraphQLNonNull(GraphQLString) },
569
664
  draft: { type: GraphQLBoolean }
570
665
  },
571
666
  resolve: async (_, args, ctx) => {
667
+ const { user: ctxUser, req: ctxReq, tenantID: ctxTenant, apiKey: ctxApiKey, db: ctxDb, relationLoader: ctxLoader } = ctx;
572
668
  await checkAccess(collection, "read", {
573
- user,
574
- req,
575
- tenantID,
576
- apiKey
669
+ user: ctxUser,
670
+ req: ctxReq,
671
+ tenantID: ctxTenant,
672
+ apiKey: ctxApiKey
577
673
  });
578
- if (tenantID) {
579
- db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
674
+ if (ctxTenant) {
675
+ ctxDb.setTenantContext({ tenantId: ctxTenant, userId: ctxUser?.id ?? "", role: ctxUser?.role, isSuperAdmin: ctxUser?.role === "super_admin" });
580
676
  }
581
- const isDraft = args.draft ?? !!user;
582
- return RelationLoader.withBatch(relationLoader, async () => {
583
- const doc = await db.findByID({
677
+ const isDraft = args.draft ?? !!ctxUser;
678
+ return RelationLoader.withBatch(ctxLoader, async () => {
679
+ const doc = await ctxDb.findByID({
584
680
  collection: collection.slug,
585
681
  id: args.id,
586
- tenantID,
682
+ tenantID: ctxTenant,
587
683
  draft: isDraft
588
684
  });
589
685
  return doc;
590
686
  });
591
687
  }
592
688
  };
593
- queryFields[`${collection.slug.replace(/-/g, "_")}Count`] = {
689
+ queryFields[`count${toPascalSingular(collection.slug)}s`] = {
594
690
  type: new GraphQLObjectType({
595
- name: `${collection.slug.replace(/-/g, "_")}_count`,
691
+ name: `${toPascalSingular(collection.slug)}Count`,
596
692
  fields: {
597
693
  totalDocs: { type: GraphQLInt }
598
694
  }
@@ -601,11 +697,12 @@ function buildGraphQLSchema(options) {
601
697
  where: { type: GraphQLString }
602
698
  },
603
699
  resolve: async (_, args, ctx) => {
700
+ const { user: ctxUser, req: ctxReq, tenantID: ctxTenant, apiKey: ctxApiKey, db: ctxDb } = ctx;
604
701
  await checkAccess(collection, "read", {
605
- user,
606
- req,
607
- tenantID,
608
- apiKey
702
+ user: ctxUser,
703
+ req: ctxReq,
704
+ tenantID: ctxTenant,
705
+ apiKey: ctxApiKey
609
706
  });
610
707
  let where = {};
611
708
  if (args.where) {
@@ -618,33 +715,129 @@ function buildGraphQLSchema(options) {
618
715
  where = translateFilter(args.where);
619
716
  }
620
717
  }
621
- const count = await db.count({
718
+ const count = await ctxDb.count({
622
719
  collection: collection.slug,
623
720
  where,
624
- tenantID
721
+ tenantID: ctxTenant
625
722
  });
626
723
  return { totalDocs: count };
627
724
  }
628
725
  };
726
+ const edgeType = new GraphQLObjectType({
727
+ name: `${toPascalSingular(collection.slug)}Edge`,
728
+ fields: {
729
+ node: { type },
730
+ cursor: { type: new GraphQLNonNull(GraphQLString) }
731
+ }
732
+ });
733
+ const connectionType = new GraphQLObjectType({
734
+ name: `${toPascalSingular(collection.slug)}Connection`,
735
+ fields: {
736
+ edges: { type: new GraphQLList(edgeType) },
737
+ pageInfo: { type: new GraphQLNonNull(pageInfoType) },
738
+ totalCount: { type: GraphQLInt }
739
+ }
740
+ });
741
+ queryFields[`${toCamelCase(collection.slug)}Connection`] = {
742
+ type: connectionType,
743
+ args: {
744
+ first: { type: GraphQLInt },
745
+ after: { type: GraphQLString },
746
+ last: { type: GraphQLInt },
747
+ before: { type: GraphQLString },
748
+ where: { type: filterType },
749
+ sort: { type: sortEnum || GraphQLString },
750
+ draft: { type: GraphQLBoolean }
751
+ },
752
+ resolve: async (_, args, ctx) => {
753
+ const { user: ctxUser, req: ctxReq, tenantID: ctxTenant, apiKey: ctxApiKey, db: ctxDb, relationLoader: ctxLoader } = ctx;
754
+ const extraWhere = await checkAccess(collection, "read", {
755
+ user: ctxUser,
756
+ req: ctxReq,
757
+ tenantID: ctxTenant,
758
+ apiKey: ctxApiKey
759
+ });
760
+ if (ctxTenant) {
761
+ ctxDb.setTenantContext({ tenantId: ctxTenant, userId: ctxUser?.id ?? "", role: ctxUser?.role, isSuperAdmin: ctxUser?.role === "super_admin" });
762
+ }
763
+ let where = {};
764
+ if (args.where) {
765
+ if (typeof args.where === "string") {
766
+ try {
767
+ where = JSON.parse(args.where);
768
+ } catch {
769
+ }
770
+ } else {
771
+ where = translateFilter(args.where);
772
+ }
773
+ }
774
+ if (extraWhere) where = { ...where, ...extraWhere };
775
+ const isDraft = args.draft ?? !!ctxUser;
776
+ return RelationLoader.withBatch(ctxLoader, async () => {
777
+ let page = 1;
778
+ let limit = args.first || args.last || 10;
779
+ if (args.after) {
780
+ try {
781
+ const afterIdx = parseInt(Buffer.from(args.after, "base64").toString("utf-8"), 10);
782
+ if (!isNaN(afterIdx)) page = Math.floor(afterIdx / limit) + 1;
783
+ } catch {
784
+ }
785
+ } else if (args.before) {
786
+ try {
787
+ const beforeIdx = parseInt(Buffer.from(args.before, "base64").toString("utf-8"), 10);
788
+ if (!isNaN(beforeIdx)) page = Math.max(1, Math.floor(beforeIdx / limit));
789
+ } catch {
790
+ }
791
+ }
792
+ const result = await ctxDb.find({
793
+ collection: collection.slug,
794
+ where,
795
+ sort: args.sort,
796
+ limit,
797
+ page,
798
+ tenantID: ctxTenant,
799
+ draft: isDraft
800
+ });
801
+ const edges = (result.docs || []).map((doc, idx) => {
802
+ const cursorIdx = (page - 1) * limit + idx;
803
+ return {
804
+ node: doc,
805
+ cursor: Buffer.from(String(cursorIdx)).toString("base64")
806
+ };
807
+ });
808
+ return {
809
+ edges,
810
+ pageInfo: {
811
+ hasNextPage: result.hasNextPage || false,
812
+ hasPreviousPage: result.hasPrevPage || false,
813
+ startCursor: edges.length > 0 ? edges[0].cursor : null,
814
+ endCursor: edges.length > 0 ? edges[edges.length - 1].cursor : null
815
+ },
816
+ totalCount: result.totalDocs
817
+ };
818
+ });
819
+ }
820
+ };
629
821
  }
630
822
  for (const global of globals) {
631
823
  const type = globalTypes[global.slug];
632
824
  if (!type) continue;
633
- queryFields[`${global.slug.replace(/-/g, "_")}Get`] = {
825
+ queryFields[toCamelCase(global.slug)] = {
634
826
  type,
635
- resolve: async () => {
827
+ resolve: async (_, args, ctx) => {
828
+ const { user: ctxUser, req: ctxReq, tenantID: ctxTenant, db: ctxDb } = ctx;
636
829
  await checkGqlGlobalAccess(global, "read", {
637
- user,
638
- req,
639
- tenantID
830
+ user: ctxUser,
831
+ req: ctxReq,
832
+ tenantID: ctxTenant
640
833
  });
641
- if (tenantID) {
642
- db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
834
+ if (ctxTenant) {
835
+ ctxDb.setTenantContext({ tenantId: ctxTenant, userId: ctxUser?.id ?? "", role: ctxUser?.role, isSuperAdmin: ctxUser?.role === "super_admin" });
643
836
  }
644
- return db.findOne({
837
+ return ctxDb.findOne({
645
838
  collection: `_globals_${global.slug}`,
646
839
  where: {},
647
- tenantID
840
+ tenantID: ctxTenant
648
841
  });
649
842
  }
650
843
  };
@@ -658,9 +851,9 @@ function buildGraphQLSchema(options) {
658
851
  const type = collectionTypes[collection.slug];
659
852
  const inputType = collectionInputTypes[collection.slug];
660
853
  if (!type || !inputType) continue;
661
- mutationFields[`${collection.slug.replace(/-/g, "_")}Create`] = {
854
+ mutationFields[`create${toPascalSingular(collection.slug)}`] = {
662
855
  type: new GraphQLObjectType({
663
- name: `${collection.slug.replace(/-/g, "_")}_create_result`,
856
+ name: `${toPascalSingular(collection.slug)}CreateResult`,
664
857
  fields: {
665
858
  doc: { type },
666
859
  message: { type: GraphQLString }
@@ -671,28 +864,38 @@ function buildGraphQLSchema(options) {
671
864
  draft: { type: GraphQLBoolean }
672
865
  },
673
866
  resolve: async (_, args, ctx) => {
867
+ const { user: ctxUser, req: ctxReq, tenantID: ctxTenant, apiKey: ctxApiKey, db: ctxDb, registry: ctxRegistry } = ctx;
674
868
  await checkAccess(collection, "create", {
675
- user,
676
- req,
677
- tenantID,
678
- apiKey
869
+ user: ctxUser,
870
+ req: ctxReq,
871
+ tenantID: ctxTenant,
872
+ apiKey: ctxApiKey
679
873
  });
680
- if (tenantID) {
681
- db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
874
+ if (ctxTenant) {
875
+ ctxDb.setTenantContext({ tenantId: ctxTenant, userId: ctxUser?.id ?? "", role: ctxUser?.role, isSuperAdmin: ctxUser?.role === "super_admin" });
682
876
  }
683
- const schema = registry.getCreateZodSchema(collection.slug);
684
- const validated = schema.parse(args.data);
685
- const doc = await db.create({
877
+ const createSchema = ctxRegistry.getCreateZodSchema(collection.slug);
878
+ let validated;
879
+ try {
880
+ validated = createSchema.parse(args.data);
881
+ } catch (err) {
882
+ if (err?.issues) {
883
+ const msg = err.issues.map((i) => `${i.path?.join(".")}: ${i.message}`).join("; ");
884
+ throw gqlError(msg, "BAD_USER_INPUT");
885
+ }
886
+ throw err;
887
+ }
888
+ const doc = await ctxDb.create({
686
889
  collection: collection.slug,
687
890
  data: validated,
688
- tenantID
891
+ tenantID: ctxTenant
689
892
  });
690
893
  return { doc, message: "Created successfully" };
691
894
  }
692
895
  };
693
- mutationFields[`${collection.slug.replace(/-/g, "_")}Update`] = {
896
+ mutationFields[`update${toPascalSingular(collection.slug)}`] = {
694
897
  type: new GraphQLObjectType({
695
- name: `${collection.slug.replace(/-/g, "_")}_update_result`,
898
+ name: `${toPascalSingular(collection.slug)}UpdateResult`,
696
899
  fields: {
697
900
  doc: { type },
698
901
  message: { type: GraphQLString }
@@ -705,20 +908,21 @@ function buildGraphQLSchema(options) {
705
908
  draft: { type: GraphQLBoolean }
706
909
  },
707
910
  resolve: async (_, args, ctx) => {
911
+ const { user: ctxUser, req: ctxReq, tenantID: ctxTenant, apiKey: ctxApiKey, db: ctxDb, registry: ctxRegistry } = ctx;
708
912
  await checkAccess(collection, "update", {
709
- user,
710
- req,
711
- tenantID,
712
- apiKey
913
+ user: ctxUser,
914
+ req: ctxReq,
915
+ tenantID: ctxTenant,
916
+ apiKey: ctxApiKey
713
917
  });
714
- if (tenantID) {
715
- db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
918
+ if (ctxTenant) {
919
+ ctxDb.setTenantContext({ tenantId: ctxTenant, userId: ctxUser?.id ?? "", role: ctxUser?.role, isSuperAdmin: ctxUser?.role === "super_admin" });
716
920
  }
717
921
  if (args.baseUpdatedAt) {
718
- const originalDoc = await db.findByID({
922
+ const originalDoc = await ctxDb.findByID({
719
923
  collection: collection.slug,
720
924
  id: args.id,
721
- tenantID,
925
+ tenantID: ctxTenant,
722
926
  draft: true
723
927
  });
724
928
  if (originalDoc && originalDoc.updatedAt && args.baseUpdatedAt !== originalDoc.updatedAt) {
@@ -728,20 +932,29 @@ function buildGraphQLSchema(options) {
728
932
  );
729
933
  }
730
934
  }
731
- const schema = registry.getUpdateZodSchema(collection.slug);
732
- const validated = schema.parse(args.data);
733
- const doc = await db.update({
935
+ const updateSchema = ctxRegistry.getUpdateZodSchema(collection.slug);
936
+ let validated;
937
+ try {
938
+ validated = updateSchema.parse(args.data);
939
+ } catch (err) {
940
+ if (err?.issues) {
941
+ const msg = err.issues.map((i) => `${i.path?.join(".")}: ${i.message}`).join("; ");
942
+ throw gqlError(msg, "BAD_USER_INPUT");
943
+ }
944
+ throw err;
945
+ }
946
+ const doc = await ctxDb.update({
734
947
  collection: collection.slug,
735
948
  id: args.id,
736
949
  data: validated,
737
- tenantID
950
+ tenantID: ctxTenant
738
951
  });
739
952
  return { doc, message: "Updated successfully" };
740
953
  }
741
954
  };
742
- mutationFields[`${collection.slug.replace(/-/g, "_")}Delete`] = {
955
+ mutationFields[`delete${toPascalSingular(collection.slug)}`] = {
743
956
  type: new GraphQLObjectType({
744
- name: `${collection.slug.replace(/-/g, "_")}_delete_result`,
957
+ name: `${toPascalSingular(collection.slug)}DeleteResult`,
745
958
  fields: {
746
959
  doc: { type },
747
960
  message: { type: GraphQLString }
@@ -751,19 +964,20 @@ function buildGraphQLSchema(options) {
751
964
  id: { type: new GraphQLNonNull(GraphQLString) }
752
965
  },
753
966
  resolve: async (_, args, ctx) => {
967
+ const { user: ctxUser, req: ctxReq, tenantID: ctxTenant, apiKey: ctxApiKey, db: ctxDb } = ctx;
754
968
  await checkAccess(collection, "delete", {
755
- user,
756
- req,
757
- tenantID,
758
- apiKey
969
+ user: ctxUser,
970
+ req: ctxReq,
971
+ tenantID: ctxTenant,
972
+ apiKey: ctxApiKey
759
973
  });
760
- if (tenantID) {
761
- db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
974
+ if (ctxTenant) {
975
+ ctxDb.setTenantContext({ tenantId: ctxTenant, userId: ctxUser?.id ?? "", role: ctxUser?.role, isSuperAdmin: ctxUser?.role === "super_admin" });
762
976
  }
763
- const doc = await db.delete({
977
+ const doc = await ctxDb.delete({
764
978
  collection: collection.slug,
765
979
  id: args.id,
766
- tenantID
980
+ tenantID: ctxTenant
767
981
  });
768
982
  return { doc, message: "Deleted successfully" };
769
983
  }
@@ -772,9 +986,9 @@ function buildGraphQLSchema(options) {
772
986
  for (const global of globals) {
773
987
  const inputType = globalInputTypes[global.slug];
774
988
  if (!inputType) continue;
775
- mutationFields[`${global.slug.replace(/-/g, "_")}Update`] = {
989
+ mutationFields[`update${toPascalCase(global.slug)}`] = {
776
990
  type: new GraphQLObjectType({
777
- name: `${global.slug.replace(/-/g, "_")}_update_result`,
991
+ name: `${toPascalCase(global.slug)}UpdateResult`,
778
992
  fields: {
779
993
  doc: { type: globalTypes[global.slug] || GraphQLString },
780
994
  message: { type: GraphQLString }
@@ -784,32 +998,33 @@ function buildGraphQLSchema(options) {
784
998
  data: { type: new GraphQLNonNull(inputType) }
785
999
  },
786
1000
  resolve: async (_, args, ctx) => {
1001
+ const { user: ctxUser, req: ctxReq, tenantID: ctxTenant, db: ctxDb } = ctx;
787
1002
  await checkGqlGlobalAccess(global, "update", {
788
- user,
789
- req,
790
- tenantID
1003
+ user: ctxUser,
1004
+ req: ctxReq,
1005
+ tenantID: ctxTenant
791
1006
  });
792
- if (tenantID) {
793
- db.setTenantContext({ tenantId: tenantID, userId: user?.id ?? "", role: user?.role, isSuperAdmin: user?.role === "super_admin" });
1007
+ if (ctxTenant) {
1008
+ ctxDb.setTenantContext({ tenantId: ctxTenant, userId: ctxUser?.id ?? "", role: ctxUser?.role, isSuperAdmin: ctxUser?.role === "super_admin" });
794
1009
  }
795
- const doc = await db.findOne({
1010
+ const doc = await ctxDb.findOne({
796
1011
  collection: `_globals_${global.slug}`,
797
1012
  where: {},
798
- tenantID
1013
+ tenantID: ctxTenant
799
1014
  });
800
1015
  let result;
801
1016
  if (doc) {
802
- result = await db.update({
1017
+ result = await ctxDb.update({
803
1018
  collection: `_globals_${global.slug}`,
804
1019
  id: doc.id,
805
1020
  data: args.data,
806
- tenantID
1021
+ tenantID: ctxTenant
807
1022
  });
808
1023
  } else {
809
- result = await db.create({
1024
+ result = await ctxDb.create({
810
1025
  collection: `_globals_${global.slug}`,
811
1026
  data: args.data,
812
- tenantID
1027
+ tenantID: ctxTenant
813
1028
  });
814
1029
  }
815
1030
  return { doc: result, message: "Updated successfully" };
@@ -820,23 +1035,38 @@ function buildGraphQLSchema(options) {
820
1035
  name: "Mutation",
821
1036
  fields: mutationFields
822
1037
  });
1038
+ const keyDirective = new GraphQLDirective({
1039
+ name: "key",
1040
+ locations: [DirectiveLocation.OBJECT, DirectiveLocation.INTERFACE],
1041
+ args: {
1042
+ fields: { type: new GraphQLNonNull(GraphQLString) }
1043
+ }
1044
+ });
1045
+ const serviceSdl = printSchema(new GraphQLSchema({
1046
+ query: new GraphQLObjectType({ name: "Query", fields: { ...queryFields } }),
1047
+ mutation: Mutation,
1048
+ directives: [keyDirective]
1049
+ }));
1050
+ queryFields._service = {
1051
+ type: new GraphQLObjectType({
1052
+ name: "_Service",
1053
+ fields: {
1054
+ sdl: { type: GraphQLString }
1055
+ }
1056
+ }),
1057
+ resolve: () => ({ sdl: serviceSdl })
1058
+ };
823
1059
  return new GraphQLSchema({
824
1060
  query: Query,
825
- mutation: Mutation
1061
+ mutation: Mutation,
1062
+ directives: [keyDirective]
826
1063
  });
827
1064
  }
828
- function createGraphQLSchema(registry, db, options) {
829
- const schema = buildGraphQLSchema({
830
- registry,
831
- db,
832
- user: options?.user,
833
- req: options?.req,
834
- tenantID: options?.tenantID,
835
- apiKey: options?.apiKey
836
- });
1065
+ function createGraphQLSchema(registry, db) {
1066
+ const schema = buildGraphQLSchema({ registry, db });
837
1067
  return Object.assign(schema, { sdl: printSchema(schema) });
838
1068
  }
839
1069
 
840
- export { buildGraphQLSchema, createGraphQLSchema };
841
- //# sourceMappingURL=chunk-PONTBXR5.js.map
842
- //# sourceMappingURL=chunk-PONTBXR5.js.map
1070
+ export { RelationLoader, buildGraphQLSchema, createGraphQLSchema, depthLimit };
1071
+ //# sourceMappingURL=chunk-6DURKQ6W.js.map
1072
+ //# sourceMappingURL=chunk-6DURKQ6W.js.map