@nixxie-cms/core 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES-1.1.md +134 -0
- package/context/dist/nixxie-cms-core-context.cjs.js +4 -3
- package/context/dist/nixxie-cms-core-context.esm.js +3 -2
- package/dist/declarations/src/access.d.ts +2 -2
- package/dist/declarations/src/access.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/components/Navigation.d.ts +2 -2
- package/dist/declarations/src/admin-ui/components/Navigation.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/context.d.ts +6 -6
- package/dist/declarations/src/admin-ui/context.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/utils/Fields.d.ts +3 -3
- package/dist/declarations/src/admin-ui/utils/Fields.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/utils/filters.d.ts +5 -5
- package/dist/declarations/src/admin-ui/utils/filters.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/utils/useCreateItem.d.ts +3 -3
- package/dist/declarations/src/admin-ui/utils/useCreateItem.d.ts.map +1 -1
- package/dist/declarations/src/admin-ui/utils/utils.d.ts +2 -2
- package/dist/declarations/src/admin-ui/utils/utils.d.ts.map +1 -1
- package/dist/declarations/src/context.d.ts +1 -1
- package/dist/declarations/src/context.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/bigInt/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/bigInt/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/bytes/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/bytes/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/calendarDay/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/calendarDay/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/checkbox/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/checkbox/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/decimal/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/decimal/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/file/index.d.ts +4 -4
- package/dist/declarations/src/fields/types/file/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/float/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/float/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/image/index.d.ts +4 -4
- package/dist/declarations/src/fields/types/image/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/integer/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/integer/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/json/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/json/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/multiselect/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/multiselect/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/multiselect/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/password/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/password/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/index.d.ts +8 -8
- package/dist/declarations/src/fields/types/relationship/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/views/ComboboxMany.d.ts +3 -3
- package/dist/declarations/src/fields/types/relationship/views/ComboboxMany.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/views/ComboboxSingle.d.ts +3 -3
- package/dist/declarations/src/fields/types/relationship/views/ComboboxSingle.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/views/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/relationship/views/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/relationship/views/types.d.ts +3 -3
- package/dist/declarations/src/fields/types/relationship/views/types.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/select/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/select/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/text/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/text/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/timestamp/index.d.ts +3 -3
- package/dist/declarations/src/fields/types/timestamp/index.d.ts.map +1 -1
- package/dist/declarations/src/fields/types/virtual/index.d.ts +7 -7
- package/dist/declarations/src/fields/types/virtual/index.d.ts.map +1 -1
- package/dist/declarations/src/helpers.d.ts +249 -13
- package/dist/declarations/src/helpers.d.ts.map +1 -1
- package/dist/declarations/src/index.d.ts +9 -4
- package/dist/declarations/src/index.d.ts.map +1 -1
- package/dist/declarations/src/internal-unstable/admin-ui/pages/ListPage/index.d.ts.map +1 -1
- package/dist/declarations/src/lib/admin-meta.d.ts +11 -11
- package/dist/declarations/src/lib/admin-meta.d.ts.map +1 -1
- package/dist/declarations/src/lib/core/access-control.d.ts +18 -18
- package/dist/declarations/src/lib/core/access-control.d.ts.map +1 -1
- package/dist/declarations/src/lib/core/cascade.d.ts +47 -0
- package/dist/declarations/src/lib/core/cascade.d.ts.map +1 -0
- package/dist/declarations/src/lib/core/initialise-lists.d.ts +27 -24
- package/dist/declarations/src/lib/core/initialise-lists.d.ts.map +1 -1
- package/dist/declarations/src/lib/env.d.ts +9 -0
- package/dist/declarations/src/lib/env.d.ts.map +1 -0
- package/dist/declarations/src/lib/system.d.ts +1 -1
- package/dist/declarations/src/lib/system.d.ts.map +1 -1
- package/dist/declarations/src/list-features.d.ts +162 -0
- package/dist/declarations/src/list-features.d.ts.map +1 -0
- package/dist/declarations/src/schema.d.ts +24 -23
- package/dist/declarations/src/schema.d.ts.map +1 -1
- package/dist/declarations/src/session.d.ts +75 -0
- package/dist/declarations/src/session.d.ts.map +1 -1
- package/dist/declarations/src/types/admin-meta.d.ts +11 -11
- package/dist/declarations/src/types/admin-meta.d.ts.map +1 -1
- package/dist/declarations/src/types/config/access-control.d.ts +42 -42
- package/dist/declarations/src/types/config/access-control.d.ts.map +1 -1
- package/dist/declarations/src/types/config/fields.d.ts +19 -19
- package/dist/declarations/src/types/config/fields.d.ts.map +1 -1
- package/dist/declarations/src/types/config/hooks.d.ts +131 -131
- package/dist/declarations/src/types/config/hooks.d.ts.map +1 -1
- package/dist/declarations/src/types/config/index.d.ts +171 -8
- package/dist/declarations/src/types/config/index.d.ts.map +1 -1
- package/dist/declarations/src/types/config/lists.d.ts +146 -108
- package/dist/declarations/src/types/config/lists.d.ts.map +1 -1
- package/dist/declarations/src/types/context.d.ts +349 -47
- package/dist/declarations/src/types/context.d.ts.map +1 -1
- package/dist/declarations/src/types/next-fields.d.ts +28 -28
- package/dist/declarations/src/types/next-fields.d.ts.map +1 -1
- package/dist/declarations/src/types/type-info.d.ts +3 -3
- package/dist/declarations/src/types/type-info.d.ts.map +1 -1
- package/dist/{express-7559ca2d.esm.js → express-0abbce07.esm.js} +6 -6
- package/dist/{express-455ae20c.cjs.js → express-7ca6f76a.cjs.js} +6 -6
- package/dist/{index-15c8f81e.esm.js → index-5d8b0b4e.esm.js} +363 -183
- package/dist/index-6055753b.cjs.js +393 -0
- package/dist/{index-42045902.cjs.js → index-ac29f382.cjs.js} +363 -185
- package/dist/index-f1703b7b.esm.js +386 -0
- package/dist/nixxie-cms-core.cjs.js +1387 -30
- package/dist/nixxie-cms-core.esm.js +1361 -24
- package/dist/{non-null-graphql-add6bb3d.cjs.js → non-null-graphql-4a44c122.cjs.js} +1 -1
- package/dist/{non-null-graphql-a84ed64d.esm.js → non-null-graphql-8c5feaae.esm.js} +1 -1
- package/dist/{resolve-hooks-165a9ce2.cjs.js → resolve-hooks-10a5f84c.cjs.js} +240 -6
- package/dist/{resolve-hooks-6813a045.esm.js → resolve-hooks-9e676794.esm.js} +238 -7
- package/dist/{system-03e49e4f.esm.js → system-4d2a2648.esm.js} +32 -7
- package/dist/{system-a321642d.cjs.js → system-69e1a285.cjs.js} +32 -7
- package/fields/dist/nixxie-cms-core-fields.cjs.js +29 -576
- package/fields/dist/nixxie-cms-core-fields.esm.js +18 -565
- package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.cjs.js +4 -2
- package/fields/types/bytes/dist/nixxie-cms-core-fields-types-bytes.esm.js +4 -2
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.cjs.js +1 -6
- package/fields/types/multiselect/views/dist/nixxie-cms-core-fields-types-multiselect-views.esm.js +1 -6
- package/fields/types/password/dist/nixxie-cms-core-fields-types-password.cjs.js +4 -2
- package/fields/types/password/dist/nixxie-cms-core-fields-types-password.esm.js +4 -2
- package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.cjs.js +4 -3
- package/internal-unstable/artifacts/dist/nixxie-cms-core-internal-unstable-artifacts.esm.js +4 -3
- package/package.json +4 -4
- package/scripts/cli/dist/nixxie-cms-core-scripts-cli.cjs.js +4 -3
- package/scripts/cli/dist/nixxie-cms-core-scripts-cli.esm.js +4 -3
- package/scripts/dist/nixxie-cms-core-scripts.cjs.js +4 -3
- package/scripts/dist/nixxie-cms-core-scripts.esm.js +4 -3
- package/session/dist/nixxie-cms-core-session.cjs.js +286 -0
- package/session/dist/nixxie-cms-core-session.esm.js +279 -1
- package/src/access.ts +25 -25
- package/src/admin-ui/admin-meta-graphql.ts +5 -5
- package/src/admin-ui/components/CreateButtonLink.tsx +46 -46
- package/src/admin-ui/components/Navigation.tsx +3 -3
- package/src/admin-ui/context.tsx +6 -6
- package/src/admin-ui/utils/Fields.tsx +241 -241
- package/src/admin-ui/utils/actionData.ts +36 -36
- package/src/admin-ui/utils/filters.ts +148 -148
- package/src/admin-ui/utils/useCreateItem.ts +171 -171
- package/src/admin-ui/utils/utils.tsx +127 -127
- package/src/context.ts +1 -1
- package/src/fields/non-null-graphql.ts +115 -115
- package/src/fields/types/bigInt/index.ts +6 -6
- package/src/fields/types/bytes/index.ts +6 -6
- package/src/fields/types/calendarDay/index.ts +18 -19
- package/src/fields/types/checkbox/index.ts +6 -6
- package/src/fields/types/decimal/index.ts +6 -6
- package/src/fields/types/file/index.ts +8 -8
- package/src/fields/types/float/index.ts +6 -6
- package/src/fields/types/image/index.ts +8 -8
- package/src/fields/types/integer/index.ts +6 -6
- package/src/fields/types/json/index.ts +5 -5
- package/src/fields/types/multiselect/index.ts +7 -7
- package/src/fields/types/multiselect/views/index.tsx +149 -151
- package/src/fields/types/password/index.ts +6 -6
- package/src/fields/types/relationship/index.ts +13 -13
- package/src/fields/types/relationship/views/ComboboxMany.tsx +110 -110
- package/src/fields/types/relationship/views/ComboboxSingle.tsx +115 -115
- package/src/fields/types/relationship/views/ContextualActions.tsx +139 -139
- package/src/fields/types/relationship/views/index.tsx +492 -492
- package/src/fields/types/relationship/views/types.ts +46 -46
- package/src/fields/types/relationship/views/useApolloQuery.ts +185 -185
- package/src/fields/types/relationship/views/useFilter.tsx +109 -109
- package/src/fields/types/select/index.ts +6 -6
- package/src/fields/types/text/index.ts +6 -6
- package/src/fields/types/timestamp/index.ts +23 -21
- package/src/fields/types/virtual/index.ts +11 -11
- package/src/helpers.ts +773 -42
- package/src/index.ts +66 -24
- package/src/internal-unstable/admin-ui/pages/ItemPage/common.tsx +4 -4
- package/src/internal-unstable/admin-ui/pages/ItemPage/index.tsx +5 -5
- package/src/internal-unstable/admin-ui/pages/ListPage/index.tsx +8 -8
- package/src/lib/admin-meta.ts +369 -369
- package/src/lib/context/createContext.ts +5 -0
- package/src/lib/core/access-control.ts +434 -434
- package/src/lib/core/cascade.ts +236 -0
- package/src/lib/core/initialise-lists.ts +49 -33
- package/src/lib/core/mutations/index.ts +7 -0
- package/src/lib/core/mutations/nested-mutation-many-input-resolvers.ts +145 -145
- package/src/lib/core/mutations/nested-mutation-one-input-resolvers.ts +71 -71
- package/src/lib/core/queries/output-field.ts +178 -178
- package/src/lib/env.ts +50 -0
- package/src/lib/id-field.ts +2 -2
- package/src/lib/system.ts +221 -207
- package/src/lib/typescript-schema-printer.ts +227 -227
- package/src/list-features.ts +476 -0
- package/src/schema.ts +91 -22
- package/src/session.ts +225 -0
- package/src/types/admin-meta.ts +218 -218
- package/src/types/config/access-control.ts +186 -186
- package/src/types/config/fields.ts +96 -96
- package/src/types/config/hooks.ts +529 -529
- package/src/types/config/index.ts +185 -7
- package/src/types/config/lists.ts +606 -565
- package/src/types/context.ts +426 -55
- package/src/types/next-fields.ts +31 -31
- package/src/types/type-info.ts +38 -38
- package/src/types/type-tests.ts +21 -21
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var resolveHooks = require('./resolve-hooks-
|
|
3
|
+
var resolveHooks = require('./resolve-hooks-10a5f84c.cjs.js');
|
|
4
4
|
|
|
5
5
|
function resolveDbNullable(validation, db) {
|
|
6
6
|
if ((db === null || db === void 0 ? void 0 : db.isNullable) === false) return false;
|
|
@@ -5,6 +5,7 @@ var nextFields = require('./next-fields-49c025ef.cjs.js');
|
|
|
5
5
|
require('@graphql-ts/schema');
|
|
6
6
|
require('@graphql-ts/extend');
|
|
7
7
|
var graphql = require('graphql');
|
|
8
|
+
var node_async_hooks = require('node:async_hooks');
|
|
8
9
|
|
|
9
10
|
const userInputError = msg => new graphql.GraphQLError(`Input error: ${msg}`, {
|
|
10
11
|
extensions: {
|
|
@@ -316,6 +317,236 @@ function idFieldType(config) {
|
|
|
316
317
|
};
|
|
317
318
|
}
|
|
318
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Cascade deletion: enacts a collection's `cascade` rules inside the delete pipeline.
|
|
322
|
+
*
|
|
323
|
+
* Cascaded operations go through the normal mutation APIs (`context.sudo().db`), so the
|
|
324
|
+
* target collections' hooks, access events and their OWN cascade rules all run — deletes
|
|
325
|
+
* recurse naturally. A visited-set carried through AsyncLocalStorage guards against
|
|
326
|
+
* cycles (A → B → A) across the recursive mutation calls, which derive fresh context
|
|
327
|
+
* objects and therefore can't carry the state themselves.
|
|
328
|
+
*
|
|
329
|
+
* Note on atomicity: each cascaded operation commits independently (the hook pipeline
|
|
330
|
+
* is not transactional). `restrict` rules are checked up front, before anything is
|
|
331
|
+
* deleted, so refusals are always clean; a mid-cascade failure aborts the remaining
|
|
332
|
+
* cascade and the root delete, but already-cascaded operations stay committed.
|
|
333
|
+
*/
|
|
334
|
+
const cascadeStack = new node_async_hooks.AsyncLocalStorage();
|
|
335
|
+
|
|
336
|
+
/** Page size for fetching related records. */
|
|
337
|
+
const PAGE = 100;
|
|
338
|
+
/** Safety cap on preview tree size. */
|
|
339
|
+
const PREVIEW_LIMIT = 1000;
|
|
340
|
+
const visitKey = (listKey, id) => `${listKey}:${id}`;
|
|
341
|
+
|
|
342
|
+
/** Where-filter matching the target collection's records that point at `itemId`. */
|
|
343
|
+
function matchWhere(rule, itemId) {
|
|
344
|
+
return rule.many ? {
|
|
345
|
+
[rule.field]: {
|
|
346
|
+
some: {
|
|
347
|
+
id: {
|
|
348
|
+
equals: itemId
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
} : {
|
|
353
|
+
[rule.field]: {
|
|
354
|
+
id: {
|
|
355
|
+
equals: itemId
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function ruleAction(rule) {
|
|
361
|
+
var _rule$action;
|
|
362
|
+
return (_rule$action = rule.action) !== null && _rule$action !== void 0 ? _rule$action : 'delete';
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Check `restrict` rules for an item about to be deleted. Runs before any cascade work,
|
|
367
|
+
* so a refused delete leaves the database untouched. Records that are already part of
|
|
368
|
+
* the in-flight cascade (visited) don't count — they are being deleted too.
|
|
369
|
+
*/
|
|
370
|
+
async function enforceCascadeRestrictions(list, context, item) {
|
|
371
|
+
var _list$cascade;
|
|
372
|
+
const rules = ((_list$cascade = list.cascade) !== null && _list$cascade !== void 0 ? _list$cascade : []).filter(rule => ruleAction(rule) === 'restrict');
|
|
373
|
+
if (!rules.length) return;
|
|
374
|
+
const visited = cascadeStack.getStore();
|
|
375
|
+
const sudo = context.sudo();
|
|
376
|
+
for (const rule of rules) {
|
|
377
|
+
const matches = await sudo.db[rule.collection].findMany({
|
|
378
|
+
where: matchWhere(rule, String(item.id)),
|
|
379
|
+
take: PAGE
|
|
380
|
+
});
|
|
381
|
+
const blocking = visited ? matches.filter(match => !visited.has(visitKey(rule.collection, match.id))) : matches;
|
|
382
|
+
if (blocking.length) {
|
|
383
|
+
throw new Error(`Cannot delete this ${list.listKey} item: ${blocking.length}${matches.length === PAGE ? '+' : ''} related ` + `${rule.collection} record(s) reference it through "${rule.field}" (cascade rule: restrict). ` + `Delete or reassign them first.`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Enact the non-restrict cascade rules for an item that is about to be deleted.
|
|
390
|
+
* Called from the delete pipeline after hooks, immediately before the database delete.
|
|
391
|
+
*/
|
|
392
|
+
async function runCascade(list, context, item) {
|
|
393
|
+
var _list$cascade2, _cascadeStack$getStor;
|
|
394
|
+
const rules = ((_list$cascade2 = list.cascade) !== null && _list$cascade2 !== void 0 ? _list$cascade2 : []).filter(rule => ruleAction(rule) !== 'restrict');
|
|
395
|
+
// Mark the root as visited even when it has no rules itself — an ancestor cascade may
|
|
396
|
+
// be in flight, and other branches must know this item is already being handled.
|
|
397
|
+
const visited = (_cascadeStack$getStor = cascadeStack.getStore()) !== null && _cascadeStack$getStor !== void 0 ? _cascadeStack$getStor : new Set();
|
|
398
|
+
visited.add(visitKey(list.listKey, item.id));
|
|
399
|
+
if (!rules.length) return;
|
|
400
|
+
await cascadeStack.run(visited, async () => {
|
|
401
|
+
const sudo = context.sudo();
|
|
402
|
+
const itemId = String(item.id);
|
|
403
|
+
for (const rule of rules) {
|
|
404
|
+
var _rule$softDeleteField;
|
|
405
|
+
const action = ruleAction(rule);
|
|
406
|
+
if (!sudo.db[rule.collection]) {
|
|
407
|
+
throw new Error(`Cascade rule on ${list.listKey} points at unknown collection "${rule.collection}"`);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// softDelete'd records still reference the deleted item, so the match query must
|
|
411
|
+
// exclude already-stamped rows or this loop would never drain.
|
|
412
|
+
const softDeleteField = (_rule$softDeleteField = rule.softDeleteField) !== null && _rule$softDeleteField !== void 0 ? _rule$softDeleteField : 'deletedAt';
|
|
413
|
+
const where = action === 'softDelete' ? {
|
|
414
|
+
...matchWhere(rule, itemId),
|
|
415
|
+
[softDeleteField]: null
|
|
416
|
+
} : matchWhere(rule, itemId);
|
|
417
|
+
for (;;) {
|
|
418
|
+
const matches = await sudo.db[rule.collection].findMany({
|
|
419
|
+
where: where,
|
|
420
|
+
take: PAGE
|
|
421
|
+
});
|
|
422
|
+
const pending = matches.filter(match => !visited.has(visitKey(rule.collection, match.id)));
|
|
423
|
+
if (!pending.length) break;
|
|
424
|
+
for (const match of pending) {
|
|
425
|
+
const matchId = String(match.id);
|
|
426
|
+
if (action === 'delete') {
|
|
427
|
+
// Recurses into the target's own pipeline (hooks + its cascade rules).
|
|
428
|
+
await sudo.db[rule.collection].deleteOne({
|
|
429
|
+
where: {
|
|
430
|
+
id: matchId
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
} else if (action === 'setNull') {
|
|
434
|
+
visited.add(visitKey(rule.collection, match.id));
|
|
435
|
+
await sudo.db[rule.collection].updateOne({
|
|
436
|
+
where: {
|
|
437
|
+
id: matchId
|
|
438
|
+
},
|
|
439
|
+
data: {
|
|
440
|
+
[rule.field]: rule.many ? {
|
|
441
|
+
disconnect: [{
|
|
442
|
+
id: itemId
|
|
443
|
+
}]
|
|
444
|
+
} : {
|
|
445
|
+
disconnect: true
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
} else if (action === 'softDelete') {
|
|
450
|
+
visited.add(visitKey(rule.collection, match.id));
|
|
451
|
+
await sudo.db[rule.collection].updateOne({
|
|
452
|
+
where: {
|
|
453
|
+
id: matchId
|
|
454
|
+
},
|
|
455
|
+
data: {
|
|
456
|
+
[softDeleteField]: new Date().toISOString()
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (matches.length < PAGE) break;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// ── Dry-run preview ──
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Compute — without changing anything — the full tree of records a delete would touch,
|
|
471
|
+
* following cascade rules recursively. Surface this in delete confirmations:
|
|
472
|
+
* "This will delete 1 Post, 47 Comments and disconnect 3 Drafts."
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* const preview = await previewDelete(context, 'Post', postId)
|
|
476
|
+
* console.log(preview.totals) // { Comment: { delete: 47 }, Draft: { setNull: 3 } }
|
|
477
|
+
*/
|
|
478
|
+
async function previewDelete(context, listKey, itemId) {
|
|
479
|
+
const lists = context.__internal.lists;
|
|
480
|
+
if (!lists[listKey]) throw new Error(`previewDelete: unknown collection "${listKey}"`);
|
|
481
|
+
const sudo = context.sudo();
|
|
482
|
+
const totals = {};
|
|
483
|
+
const visited = new Set();
|
|
484
|
+
let nodes = 0;
|
|
485
|
+
let truncated = false;
|
|
486
|
+
const count = (collection, action) => {
|
|
487
|
+
var _totals$collection, _slot$action;
|
|
488
|
+
const slot = (_totals$collection = totals[collection]) !== null && _totals$collection !== void 0 ? _totals$collection : totals[collection] = {};
|
|
489
|
+
slot[action] = ((_slot$action = slot[action]) !== null && _slot$action !== void 0 ? _slot$action : 0) + 1;
|
|
490
|
+
};
|
|
491
|
+
async function walk(currentKey, id, action) {
|
|
492
|
+
visited.add(visitKey(currentKey, id));
|
|
493
|
+
const list = lists[currentKey];
|
|
494
|
+
const node = {
|
|
495
|
+
collection: currentKey,
|
|
496
|
+
id,
|
|
497
|
+
action,
|
|
498
|
+
children: []
|
|
499
|
+
};
|
|
500
|
+
const labelField = list.ui.labelField;
|
|
501
|
+
try {
|
|
502
|
+
const item = await sudo.db[currentKey].findOne({
|
|
503
|
+
where: {
|
|
504
|
+
id
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
const label = item === null || item === void 0 ? void 0 : item[labelField];
|
|
508
|
+
if (label != null && labelField !== 'id') node.label = String(label);
|
|
509
|
+
} catch {
|
|
510
|
+
// label is cosmetic — never fail the preview over it
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Only deletes propagate further cascades.
|
|
514
|
+
if (action !== 'delete') return node;
|
|
515
|
+
for (const rule of (_list$cascade3 = list.cascade) !== null && _list$cascade3 !== void 0 ? _list$cascade3 : []) {
|
|
516
|
+
var _list$cascade3;
|
|
517
|
+
const childAction = ruleAction(rule);
|
|
518
|
+
if (!lists[rule.collection]) continue;
|
|
519
|
+
let skip = 0;
|
|
520
|
+
for (;;) {
|
|
521
|
+
const matches = await sudo.db[rule.collection].findMany({
|
|
522
|
+
where: matchWhere(rule, id),
|
|
523
|
+
take: PAGE,
|
|
524
|
+
skip
|
|
525
|
+
});
|
|
526
|
+
for (const match of matches) {
|
|
527
|
+
if (visited.has(visitKey(rule.collection, match.id))) continue;
|
|
528
|
+
if (nodes >= PREVIEW_LIMIT) {
|
|
529
|
+
truncated = true;
|
|
530
|
+
return node;
|
|
531
|
+
}
|
|
532
|
+
nodes++;
|
|
533
|
+
count(rule.collection, childAction);
|
|
534
|
+
node.children.push(await walk(rule.collection, String(match.id), childAction));
|
|
535
|
+
}
|
|
536
|
+
if (matches.length < PAGE) break;
|
|
537
|
+
skip += PAGE;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return node;
|
|
541
|
+
}
|
|
542
|
+
const root = await walk(listKey, itemId, 'delete');
|
|
543
|
+
return {
|
|
544
|
+
root,
|
|
545
|
+
totals,
|
|
546
|
+
truncated
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
|
|
319
550
|
// yes, these two types have the fields but they're semantically different types
|
|
320
551
|
// (even though, yes, having EnumFilter by defined as EnumNullableFilter<Enum>, would be the same type but names would show up differently in editors for example)
|
|
321
552
|
|
|
@@ -876,7 +1107,7 @@ const BigIntFilter$2 = nextFields.g.inputObject({
|
|
|
876
1107
|
})
|
|
877
1108
|
})
|
|
878
1109
|
});
|
|
879
|
-
const String$
|
|
1110
|
+
const String$3 = {
|
|
880
1111
|
optional: StringNullableFilter$2,
|
|
881
1112
|
required: StringFilter$2
|
|
882
1113
|
};
|
|
@@ -907,7 +1138,7 @@ const BigInt$3 = {
|
|
|
907
1138
|
|
|
908
1139
|
var postgresql = /*#__PURE__*/Object.freeze({
|
|
909
1140
|
__proto__: null,
|
|
910
|
-
String: String$
|
|
1141
|
+
String: String$3,
|
|
911
1142
|
Boolean: Boolean$2,
|
|
912
1143
|
Int: Int$2,
|
|
913
1144
|
Float: Float$2,
|
|
@@ -1404,7 +1635,7 @@ const BigIntFilter$1 = nextFields.g.inputObject({
|
|
|
1404
1635
|
})
|
|
1405
1636
|
})
|
|
1406
1637
|
});
|
|
1407
|
-
const String$
|
|
1638
|
+
const String$2 = {
|
|
1408
1639
|
optional: StringNullableFilter$1,
|
|
1409
1640
|
required: StringFilter$1
|
|
1410
1641
|
};
|
|
@@ -1435,7 +1666,7 @@ const BigInt$2 = {
|
|
|
1435
1666
|
|
|
1436
1667
|
var sqlite = /*#__PURE__*/Object.freeze({
|
|
1437
1668
|
__proto__: null,
|
|
1438
|
-
String: String$
|
|
1669
|
+
String: String$2,
|
|
1439
1670
|
Boolean: Boolean$1,
|
|
1440
1671
|
Int: Int$1,
|
|
1441
1672
|
Float: Float$1,
|
|
@@ -1944,7 +2175,7 @@ const BigIntFilter = nextFields.g.inputObject({
|
|
|
1944
2175
|
})
|
|
1945
2176
|
})
|
|
1946
2177
|
});
|
|
1947
|
-
const String = {
|
|
2178
|
+
const String$1 = {
|
|
1948
2179
|
optional: StringNullableFilter,
|
|
1949
2180
|
required: StringFilter
|
|
1950
2181
|
};
|
|
@@ -1975,7 +2206,7 @@ const BigInt$1 = {
|
|
|
1975
2206
|
|
|
1976
2207
|
var mysql = /*#__PURE__*/Object.freeze({
|
|
1977
2208
|
__proto__: null,
|
|
1978
|
-
String: String,
|
|
2209
|
+
String: String$1,
|
|
1979
2210
|
Boolean: Boolean,
|
|
1980
2211
|
Int: Int,
|
|
1981
2212
|
Float: Float,
|
|
@@ -2027,6 +2258,7 @@ function expandVoidHooks(hooks) {
|
|
|
2027
2258
|
|
|
2028
2259
|
exports.accessDeniedError = accessDeniedError;
|
|
2029
2260
|
exports.accessReturnError = accessReturnError;
|
|
2261
|
+
exports.enforceCascadeRestrictions = enforceCascadeRestrictions;
|
|
2030
2262
|
exports.expandVoidHooks = expandVoidHooks;
|
|
2031
2263
|
exports.extensionError = extensionError;
|
|
2032
2264
|
exports.filterAccessError = filterAccessError;
|
|
@@ -2036,8 +2268,10 @@ exports.limitsExceededError = limitsExceededError;
|
|
|
2036
2268
|
exports.merge = merge;
|
|
2037
2269
|
exports.mysql = mysql;
|
|
2038
2270
|
exports.postgresql = postgresql;
|
|
2271
|
+
exports.previewDelete = previewDelete;
|
|
2039
2272
|
exports.relationshipError = relationshipError;
|
|
2040
2273
|
exports.resolverError = resolverError;
|
|
2274
|
+
exports.runCascade = runCascade;
|
|
2041
2275
|
exports.sqlite = sqlite;
|
|
2042
2276
|
exports.userInputError = userInputError;
|
|
2043
2277
|
exports.validationFailureError = validationFailureError;
|
|
@@ -3,6 +3,7 @@ import { g, f as fieldType, o as orderDirectionEnum, Q as QueryMode } from './ne
|
|
|
3
3
|
import '@graphql-ts/schema';
|
|
4
4
|
import '@graphql-ts/extend';
|
|
5
5
|
import { GraphQLError } from 'graphql';
|
|
6
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
6
7
|
|
|
7
8
|
const userInputError = msg => new GraphQLError(`Input error: ${msg}`, {
|
|
8
9
|
extensions: {
|
|
@@ -314,6 +315,236 @@ function idFieldType(config) {
|
|
|
314
315
|
};
|
|
315
316
|
}
|
|
316
317
|
|
|
318
|
+
/**
|
|
319
|
+
* Cascade deletion: enacts a collection's `cascade` rules inside the delete pipeline.
|
|
320
|
+
*
|
|
321
|
+
* Cascaded operations go through the normal mutation APIs (`context.sudo().db`), so the
|
|
322
|
+
* target collections' hooks, access events and their OWN cascade rules all run — deletes
|
|
323
|
+
* recurse naturally. A visited-set carried through AsyncLocalStorage guards against
|
|
324
|
+
* cycles (A → B → A) across the recursive mutation calls, which derive fresh context
|
|
325
|
+
* objects and therefore can't carry the state themselves.
|
|
326
|
+
*
|
|
327
|
+
* Note on atomicity: each cascaded operation commits independently (the hook pipeline
|
|
328
|
+
* is not transactional). `restrict` rules are checked up front, before anything is
|
|
329
|
+
* deleted, so refusals are always clean; a mid-cascade failure aborts the remaining
|
|
330
|
+
* cascade and the root delete, but already-cascaded operations stay committed.
|
|
331
|
+
*/
|
|
332
|
+
const cascadeStack = new AsyncLocalStorage();
|
|
333
|
+
|
|
334
|
+
/** Page size for fetching related records. */
|
|
335
|
+
const PAGE = 100;
|
|
336
|
+
/** Safety cap on preview tree size. */
|
|
337
|
+
const PREVIEW_LIMIT = 1000;
|
|
338
|
+
const visitKey = (listKey, id) => `${listKey}:${id}`;
|
|
339
|
+
|
|
340
|
+
/** Where-filter matching the target collection's records that point at `itemId`. */
|
|
341
|
+
function matchWhere(rule, itemId) {
|
|
342
|
+
return rule.many ? {
|
|
343
|
+
[rule.field]: {
|
|
344
|
+
some: {
|
|
345
|
+
id: {
|
|
346
|
+
equals: itemId
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
} : {
|
|
351
|
+
[rule.field]: {
|
|
352
|
+
id: {
|
|
353
|
+
equals: itemId
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function ruleAction(rule) {
|
|
359
|
+
var _rule$action;
|
|
360
|
+
return (_rule$action = rule.action) !== null && _rule$action !== void 0 ? _rule$action : 'delete';
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Check `restrict` rules for an item about to be deleted. Runs before any cascade work,
|
|
365
|
+
* so a refused delete leaves the database untouched. Records that are already part of
|
|
366
|
+
* the in-flight cascade (visited) don't count — they are being deleted too.
|
|
367
|
+
*/
|
|
368
|
+
async function enforceCascadeRestrictions(list, context, item) {
|
|
369
|
+
var _list$cascade;
|
|
370
|
+
const rules = ((_list$cascade = list.cascade) !== null && _list$cascade !== void 0 ? _list$cascade : []).filter(rule => ruleAction(rule) === 'restrict');
|
|
371
|
+
if (!rules.length) return;
|
|
372
|
+
const visited = cascadeStack.getStore();
|
|
373
|
+
const sudo = context.sudo();
|
|
374
|
+
for (const rule of rules) {
|
|
375
|
+
const matches = await sudo.db[rule.collection].findMany({
|
|
376
|
+
where: matchWhere(rule, String(item.id)),
|
|
377
|
+
take: PAGE
|
|
378
|
+
});
|
|
379
|
+
const blocking = visited ? matches.filter(match => !visited.has(visitKey(rule.collection, match.id))) : matches;
|
|
380
|
+
if (blocking.length) {
|
|
381
|
+
throw new Error(`Cannot delete this ${list.listKey} item: ${blocking.length}${matches.length === PAGE ? '+' : ''} related ` + `${rule.collection} record(s) reference it through "${rule.field}" (cascade rule: restrict). ` + `Delete or reassign them first.`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Enact the non-restrict cascade rules for an item that is about to be deleted.
|
|
388
|
+
* Called from the delete pipeline after hooks, immediately before the database delete.
|
|
389
|
+
*/
|
|
390
|
+
async function runCascade(list, context, item) {
|
|
391
|
+
var _list$cascade2, _cascadeStack$getStor;
|
|
392
|
+
const rules = ((_list$cascade2 = list.cascade) !== null && _list$cascade2 !== void 0 ? _list$cascade2 : []).filter(rule => ruleAction(rule) !== 'restrict');
|
|
393
|
+
// Mark the root as visited even when it has no rules itself — an ancestor cascade may
|
|
394
|
+
// be in flight, and other branches must know this item is already being handled.
|
|
395
|
+
const visited = (_cascadeStack$getStor = cascadeStack.getStore()) !== null && _cascadeStack$getStor !== void 0 ? _cascadeStack$getStor : new Set();
|
|
396
|
+
visited.add(visitKey(list.listKey, item.id));
|
|
397
|
+
if (!rules.length) return;
|
|
398
|
+
await cascadeStack.run(visited, async () => {
|
|
399
|
+
const sudo = context.sudo();
|
|
400
|
+
const itemId = String(item.id);
|
|
401
|
+
for (const rule of rules) {
|
|
402
|
+
var _rule$softDeleteField;
|
|
403
|
+
const action = ruleAction(rule);
|
|
404
|
+
if (!sudo.db[rule.collection]) {
|
|
405
|
+
throw new Error(`Cascade rule on ${list.listKey} points at unknown collection "${rule.collection}"`);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// softDelete'd records still reference the deleted item, so the match query must
|
|
409
|
+
// exclude already-stamped rows or this loop would never drain.
|
|
410
|
+
const softDeleteField = (_rule$softDeleteField = rule.softDeleteField) !== null && _rule$softDeleteField !== void 0 ? _rule$softDeleteField : 'deletedAt';
|
|
411
|
+
const where = action === 'softDelete' ? {
|
|
412
|
+
...matchWhere(rule, itemId),
|
|
413
|
+
[softDeleteField]: null
|
|
414
|
+
} : matchWhere(rule, itemId);
|
|
415
|
+
for (;;) {
|
|
416
|
+
const matches = await sudo.db[rule.collection].findMany({
|
|
417
|
+
where: where,
|
|
418
|
+
take: PAGE
|
|
419
|
+
});
|
|
420
|
+
const pending = matches.filter(match => !visited.has(visitKey(rule.collection, match.id)));
|
|
421
|
+
if (!pending.length) break;
|
|
422
|
+
for (const match of pending) {
|
|
423
|
+
const matchId = String(match.id);
|
|
424
|
+
if (action === 'delete') {
|
|
425
|
+
// Recurses into the target's own pipeline (hooks + its cascade rules).
|
|
426
|
+
await sudo.db[rule.collection].deleteOne({
|
|
427
|
+
where: {
|
|
428
|
+
id: matchId
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
} else if (action === 'setNull') {
|
|
432
|
+
visited.add(visitKey(rule.collection, match.id));
|
|
433
|
+
await sudo.db[rule.collection].updateOne({
|
|
434
|
+
where: {
|
|
435
|
+
id: matchId
|
|
436
|
+
},
|
|
437
|
+
data: {
|
|
438
|
+
[rule.field]: rule.many ? {
|
|
439
|
+
disconnect: [{
|
|
440
|
+
id: itemId
|
|
441
|
+
}]
|
|
442
|
+
} : {
|
|
443
|
+
disconnect: true
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
} else if (action === 'softDelete') {
|
|
448
|
+
visited.add(visitKey(rule.collection, match.id));
|
|
449
|
+
await sudo.db[rule.collection].updateOne({
|
|
450
|
+
where: {
|
|
451
|
+
id: matchId
|
|
452
|
+
},
|
|
453
|
+
data: {
|
|
454
|
+
[softDeleteField]: new Date().toISOString()
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
if (matches.length < PAGE) break;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// ── Dry-run preview ──
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Compute — without changing anything — the full tree of records a delete would touch,
|
|
469
|
+
* following cascade rules recursively. Surface this in delete confirmations:
|
|
470
|
+
* "This will delete 1 Post, 47 Comments and disconnect 3 Drafts."
|
|
471
|
+
*
|
|
472
|
+
* @example
|
|
473
|
+
* const preview = await previewDelete(context, 'Post', postId)
|
|
474
|
+
* console.log(preview.totals) // { Comment: { delete: 47 }, Draft: { setNull: 3 } }
|
|
475
|
+
*/
|
|
476
|
+
async function previewDelete(context, listKey, itemId) {
|
|
477
|
+
const lists = context.__internal.lists;
|
|
478
|
+
if (!lists[listKey]) throw new Error(`previewDelete: unknown collection "${listKey}"`);
|
|
479
|
+
const sudo = context.sudo();
|
|
480
|
+
const totals = {};
|
|
481
|
+
const visited = new Set();
|
|
482
|
+
let nodes = 0;
|
|
483
|
+
let truncated = false;
|
|
484
|
+
const count = (collection, action) => {
|
|
485
|
+
var _totals$collection, _slot$action;
|
|
486
|
+
const slot = (_totals$collection = totals[collection]) !== null && _totals$collection !== void 0 ? _totals$collection : totals[collection] = {};
|
|
487
|
+
slot[action] = ((_slot$action = slot[action]) !== null && _slot$action !== void 0 ? _slot$action : 0) + 1;
|
|
488
|
+
};
|
|
489
|
+
async function walk(currentKey, id, action) {
|
|
490
|
+
visited.add(visitKey(currentKey, id));
|
|
491
|
+
const list = lists[currentKey];
|
|
492
|
+
const node = {
|
|
493
|
+
collection: currentKey,
|
|
494
|
+
id,
|
|
495
|
+
action,
|
|
496
|
+
children: []
|
|
497
|
+
};
|
|
498
|
+
const labelField = list.ui.labelField;
|
|
499
|
+
try {
|
|
500
|
+
const item = await sudo.db[currentKey].findOne({
|
|
501
|
+
where: {
|
|
502
|
+
id
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
const label = item === null || item === void 0 ? void 0 : item[labelField];
|
|
506
|
+
if (label != null && labelField !== 'id') node.label = String(label);
|
|
507
|
+
} catch {
|
|
508
|
+
// label is cosmetic — never fail the preview over it
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Only deletes propagate further cascades.
|
|
512
|
+
if (action !== 'delete') return node;
|
|
513
|
+
for (const rule of (_list$cascade3 = list.cascade) !== null && _list$cascade3 !== void 0 ? _list$cascade3 : []) {
|
|
514
|
+
var _list$cascade3;
|
|
515
|
+
const childAction = ruleAction(rule);
|
|
516
|
+
if (!lists[rule.collection]) continue;
|
|
517
|
+
let skip = 0;
|
|
518
|
+
for (;;) {
|
|
519
|
+
const matches = await sudo.db[rule.collection].findMany({
|
|
520
|
+
where: matchWhere(rule, id),
|
|
521
|
+
take: PAGE,
|
|
522
|
+
skip
|
|
523
|
+
});
|
|
524
|
+
for (const match of matches) {
|
|
525
|
+
if (visited.has(visitKey(rule.collection, match.id))) continue;
|
|
526
|
+
if (nodes >= PREVIEW_LIMIT) {
|
|
527
|
+
truncated = true;
|
|
528
|
+
return node;
|
|
529
|
+
}
|
|
530
|
+
nodes++;
|
|
531
|
+
count(rule.collection, childAction);
|
|
532
|
+
node.children.push(await walk(rule.collection, String(match.id), childAction));
|
|
533
|
+
}
|
|
534
|
+
if (matches.length < PAGE) break;
|
|
535
|
+
skip += PAGE;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return node;
|
|
539
|
+
}
|
|
540
|
+
const root = await walk(listKey, itemId, 'delete');
|
|
541
|
+
return {
|
|
542
|
+
root,
|
|
543
|
+
totals,
|
|
544
|
+
truncated
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
317
548
|
// yes, these two types have the fields but they're semantically different types
|
|
318
549
|
// (even though, yes, having EnumFilter by defined as EnumNullableFilter<Enum>, would be the same type but names would show up differently in editors for example)
|
|
319
550
|
|
|
@@ -874,7 +1105,7 @@ const BigIntFilter$2 = g.inputObject({
|
|
|
874
1105
|
})
|
|
875
1106
|
})
|
|
876
1107
|
});
|
|
877
|
-
const String$
|
|
1108
|
+
const String$3 = {
|
|
878
1109
|
optional: StringNullableFilter$2,
|
|
879
1110
|
required: StringFilter$2
|
|
880
1111
|
};
|
|
@@ -905,7 +1136,7 @@ const BigInt$3 = {
|
|
|
905
1136
|
|
|
906
1137
|
var postgresql = /*#__PURE__*/Object.freeze({
|
|
907
1138
|
__proto__: null,
|
|
908
|
-
String: String$
|
|
1139
|
+
String: String$3,
|
|
909
1140
|
Boolean: Boolean$2,
|
|
910
1141
|
Int: Int$2,
|
|
911
1142
|
Float: Float$2,
|
|
@@ -1402,7 +1633,7 @@ const BigIntFilter$1 = g.inputObject({
|
|
|
1402
1633
|
})
|
|
1403
1634
|
})
|
|
1404
1635
|
});
|
|
1405
|
-
const String$
|
|
1636
|
+
const String$2 = {
|
|
1406
1637
|
optional: StringNullableFilter$1,
|
|
1407
1638
|
required: StringFilter$1
|
|
1408
1639
|
};
|
|
@@ -1433,7 +1664,7 @@ const BigInt$2 = {
|
|
|
1433
1664
|
|
|
1434
1665
|
var sqlite = /*#__PURE__*/Object.freeze({
|
|
1435
1666
|
__proto__: null,
|
|
1436
|
-
String: String$
|
|
1667
|
+
String: String$2,
|
|
1437
1668
|
Boolean: Boolean$1,
|
|
1438
1669
|
Int: Int$1,
|
|
1439
1670
|
Float: Float$1,
|
|
@@ -1942,7 +2173,7 @@ const BigIntFilter = g.inputObject({
|
|
|
1942
2173
|
})
|
|
1943
2174
|
})
|
|
1944
2175
|
});
|
|
1945
|
-
const String = {
|
|
2176
|
+
const String$1 = {
|
|
1946
2177
|
optional: StringNullableFilter,
|
|
1947
2178
|
required: StringFilter
|
|
1948
2179
|
};
|
|
@@ -1973,7 +2204,7 @@ const BigInt$1 = {
|
|
|
1973
2204
|
|
|
1974
2205
|
var mysql = /*#__PURE__*/Object.freeze({
|
|
1975
2206
|
__proto__: null,
|
|
1976
|
-
String: String,
|
|
2207
|
+
String: String$1,
|
|
1977
2208
|
Boolean: Boolean,
|
|
1978
2209
|
Int: Int,
|
|
1979
2210
|
Float: Float,
|
|
@@ -2023,4 +2254,4 @@ function expandVoidHooks(hooks) {
|
|
|
2023
2254
|
};
|
|
2024
2255
|
}
|
|
2025
2256
|
|
|
2026
|
-
export {
|
|
2257
|
+
export { postgresql as a, mysql as b, accessReturnError as c, accessDeniedError as d, extensionError as e, formatKeys as f, filterAccessError as g, expandVoidHooks as h, idFieldType as i, enforceCascadeRestrictions as j, resolverError as k, limitsExceededError as l, merge as m, relationshipError as n, previewDelete as p, runCascade as r, sqlite as s, userInputError as u, validationFailureError as v };
|