@revealui/core 0.2.0 → 0.3.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/README.md +137 -30
- package/dist/api/compression.d.ts.map +1 -1
- package/dist/api/payload-optimization.d.ts.map +1 -1
- package/dist/api/rate-limit.d.ts +30 -29
- package/dist/api/rate-limit.d.ts.map +1 -1
- package/dist/api/rate-limit.js +79 -4
- package/dist/api/response-cache.d.ts.map +1 -1
- package/dist/api/response-cache.js +1 -1
- package/dist/api/rest.d.ts.map +1 -1
- package/dist/api/rest.js +5 -4
- package/dist/auth/access.d.ts.map +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/cache/query-cache.d.ts +12 -10
- package/dist/cache/query-cache.d.ts.map +1 -1
- package/dist/cache/query-cache.js +38 -42
- package/dist/caching/app-cache.d.ts +5 -0
- package/dist/caching/app-cache.d.ts.map +1 -1
- package/dist/caching/app-cache.js +9 -1
- package/dist/caching/cdn-config.d.ts +2 -2
- package/dist/caching/cdn-config.d.ts.map +1 -1
- package/dist/caching/cdn-config.js +5 -15
- package/dist/caching/edge-cache.d.ts +1 -1
- package/dist/caching/edge-cache.d.ts.map +1 -1
- package/dist/caching/edge-cache.js +44 -11
- package/dist/caching/index.d.ts +6 -0
- package/dist/caching/index.d.ts.map +1 -0
- package/dist/caching/index.js +5 -0
- package/dist/caching/service-worker.d.ts +10 -18
- package/dist/caching/service-worker.d.ts.map +1 -1
- package/dist/caching/service-worker.js +5 -4
- package/dist/client/admin/RichText.d.ts +1 -1
- package/dist/client/admin/RichText.d.ts.map +1 -1
- package/dist/client/admin/components/AdminDashboard.d.ts.map +1 -1
- package/dist/client/admin/components/AdminDashboard.js +178 -205
- package/dist/client/admin/components/CollectionList.d.ts.map +1 -1
- package/dist/client/admin/components/DocumentForm.d.ts.map +1 -1
- package/dist/client/admin/components/DocumentForm.js +130 -6
- package/dist/client/admin/components/GlobalForm.d.ts.map +1 -1
- package/dist/client/admin/context/ServerFunctionContext.d.ts +8 -0
- package/dist/client/admin/context/ServerFunctionContext.d.ts.map +1 -0
- package/dist/client/admin/context/ServerFunctionContext.js +15 -0
- package/dist/client/admin/i18n/en.d.ts.map +1 -1
- package/dist/client/admin/index.d.ts +1 -0
- package/dist/client/admin/index.d.ts.map +1 -1
- package/dist/client/admin/index.js +1 -0
- package/dist/client/admin/layout.d.ts +1 -1
- package/dist/client/admin/layout.d.ts.map +1 -1
- package/dist/client/admin/layout.js +3 -2
- package/dist/client/admin/page.d.ts.map +1 -1
- package/dist/client/admin/utils/apiClient.d.ts.map +1 -1
- package/dist/client/admin/utils/apiClient.js +0 -4
- package/dist/client/admin/utils/auth.d.ts +0 -4
- package/dist/client/admin/utils/auth.d.ts.map +1 -1
- package/dist/client/admin/utils/auth.js +0 -6
- package/dist/client/admin/utils/index.d.ts +0 -1
- package/dist/client/admin/utils/index.d.ts.map +1 -1
- package/dist/client/admin/utils/index.js +0 -1
- package/dist/client/admin/utils/serializeConfig.d.ts.map +1 -1
- package/dist/client/hooks.d.ts.map +1 -1
- package/dist/client/index.d.ts +0 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +0 -2
- package/dist/client/richtext/RichTextEditor.d.ts.map +1 -1
- package/dist/client/richtext/components/ImageNodeComponent.d.ts.map +1 -1
- package/dist/client/richtext/components/ImageNodeComponent.js +0 -1
- package/dist/client/richtext/components/ImageUploadButton.d.ts +2 -0
- package/dist/client/richtext/components/ImageUploadButton.d.ts.map +1 -1
- package/dist/client/richtext/components/ImageUploadButton.js +30 -15
- package/dist/client/richtext/index.d.ts.map +1 -1
- package/dist/client/richtext/nodes/DecoratorBlockNode.d.ts.map +1 -1
- package/dist/client/richtext/nodes/ImageNode.d.ts.map +1 -1
- package/dist/client/richtext/plugins/CollaborationPlugin.d.ts.map +1 -1
- package/dist/client/richtext/plugins/CursorsOverlayPlugin.d.ts.map +1 -1
- package/dist/client/richtext/plugins/FloatingToolbarPlugin.d.ts.map +1 -1
- package/dist/client/richtext/plugins/ImagePlugin.d.ts.map +1 -1
- package/dist/client/richtext/plugins/ToolbarPlugin.d.ts.map +1 -1
- package/dist/client/ui/index.d.ts.map +1 -1
- package/dist/client/ui/index.js +1 -1
- package/dist/collections/CollectionOperations.d.ts +7 -7
- package/dist/collections/CollectionOperations.d.ts.map +1 -1
- package/dist/collections/CollectionOperations.js +15 -1
- package/dist/collections/hooks.d.ts.map +1 -1
- package/dist/collections/index.d.ts.map +1 -1
- package/dist/collections/operations/create.d.ts +2 -4
- package/dist/collections/operations/create.d.ts.map +1 -1
- package/dist/collections/operations/create.js +9 -7
- package/dist/collections/operations/createMany.d.ts +12 -0
- package/dist/collections/operations/createMany.d.ts.map +1 -0
- package/dist/collections/operations/createMany.js +43 -0
- package/dist/collections/operations/delete.d.ts +1 -1
- package/dist/collections/operations/delete.d.ts.map +1 -1
- package/dist/collections/operations/delete.js +31 -2
- package/dist/collections/operations/deleteMany.d.ts +11 -0
- package/dist/collections/operations/deleteMany.d.ts.map +1 -0
- package/dist/collections/operations/deleteMany.js +50 -0
- package/dist/collections/operations/fieldHooks.d.ts +2 -2
- package/dist/collections/operations/fieldHooks.d.ts.map +1 -1
- package/dist/collections/operations/fieldHooks.js +4 -4
- package/dist/collections/operations/find.d.ts +2 -4
- package/dist/collections/operations/find.d.ts.map +1 -1
- package/dist/collections/operations/find.js +115 -8
- package/dist/collections/operations/findById.d.ts +3 -4
- package/dist/collections/operations/findById.d.ts.map +1 -1
- package/dist/collections/operations/findById.js +53 -1
- package/dist/collections/operations/sqlAdapter.d.ts +23 -0
- package/dist/collections/operations/sqlAdapter.d.ts.map +1 -0
- package/dist/collections/operations/sqlAdapter.js +76 -0
- package/dist/collections/operations/update.d.ts +3 -5
- package/dist/collections/operations/update.d.ts.map +1 -1
- package/dist/collections/operations/update.js +103 -11
- package/dist/collections/operations/updateMany.d.ts +11 -0
- package/dist/collections/operations/updateMany.d.ts.map +1 -0
- package/dist/collections/operations/updateMany.js +52 -0
- package/dist/collections/registry.d.ts +12 -0
- package/dist/collections/registry.d.ts.map +1 -0
- package/dist/collections/registry.js +38 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/runtime.d.ts.map +1 -1
- package/dist/config/utils.d.ts +0 -10
- package/dist/config/utils.d.ts.map +1 -1
- package/dist/config/utils.js +18 -17
- package/dist/database/index.d.ts +3 -0
- package/dist/database/index.d.ts.map +1 -1
- package/dist/database/index.js +1 -5
- package/dist/database/safe-parse.d.ts +26 -0
- package/dist/database/safe-parse.d.ts.map +1 -0
- package/dist/database/safe-parse.js +42 -0
- package/dist/database/ssl-config.d.ts.map +1 -1
- package/dist/database/type-adapter.d.ts.map +1 -1
- package/dist/database/universal-postgres.d.ts.map +1 -1
- package/dist/database/universal-postgres.js +18 -13
- package/dist/dataloader.d.ts.map +1 -1
- package/dist/dataloader.js +16 -2
- package/dist/error-handling/circuit-breaker.d.ts +1 -1
- package/dist/error-handling/circuit-breaker.d.ts.map +1 -1
- package/dist/error-handling/circuit-breaker.js +11 -3
- package/dist/error-handling/error-boundary.d.ts.map +1 -1
- package/dist/error-handling/error-reporter.d.ts +6 -5
- package/dist/error-handling/error-reporter.d.ts.map +1 -1
- package/dist/error-handling/error-reporter.js +26 -41
- package/dist/error-handling/fallback-components.d.ts.map +1 -1
- package/dist/error-handling/fallback-components.js +1 -1
- package/dist/error-handling/index.d.ts +3 -5
- package/dist/error-handling/index.d.ts.map +1 -1
- package/dist/error-handling/index.js +2 -5
- package/dist/error-handling/retry.d.ts.map +1 -1
- package/dist/error-handling/retry.js +13 -8
- package/dist/factories/builders.d.ts.map +1 -1
- package/dist/factories/index.d.ts.map +1 -1
- package/dist/features.d.ts +5 -5
- package/dist/features.d.ts.map +1 -1
- package/dist/features.js +6 -5
- package/dist/fieldTraversal.d.ts.map +1 -1
- package/dist/fields/config/types.d.ts.map +1 -1
- package/dist/fields/getDefaultValue.d.ts.map +1 -1
- package/dist/fields/getFieldPaths.d.ts.map +1 -1
- package/dist/fields/hooks/afterRead/index.d.ts.map +1 -1
- package/dist/fields/hooks/afterRead/promise.d.ts.map +1 -1
- package/dist/fields/hooks/afterRead/traverseFields.d.ts.map +1 -1
- package/dist/generated/types/cms.d.ts.map +1 -1
- package/dist/generated/types/cms.js +0 -1
- package/dist/generated/types/index.d.ts +0 -3
- package/dist/generated/types/index.d.ts.map +1 -1
- package/dist/generated/types/index.js +0 -7
- package/dist/generated/types/neon.d.ts.map +1 -1
- package/dist/generated/types/neon.js +4 -2
- package/dist/globals/GlobalOperations.d.ts.map +1 -1
- package/dist/globals/GlobalOperations.js +4 -2
- package/dist/globals/index.d.ts.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -6
- package/dist/instance/RevealUIInstance.d.ts.map +1 -1
- package/dist/instance/RevealUIInstance.js +50 -69
- package/dist/instance/index.d.ts.map +1 -1
- package/dist/instance/logger.d.ts.map +1 -1
- package/dist/instance/methods/create.d.ts.map +1 -1
- package/dist/instance/methods/create.js +4 -4
- package/dist/instance/methods/delete.d.ts.map +1 -1
- package/dist/instance/methods/delete.js +5 -5
- package/dist/instance/methods/find.d.ts.map +1 -1
- package/dist/instance/methods/find.js +0 -3
- package/dist/instance/methods/findById.d.ts.map +1 -1
- package/dist/instance/methods/findById.js +0 -3
- package/dist/instance/methods/hooks.d.ts.map +1 -1
- package/dist/instance/methods/hooks.js +3 -1
- package/dist/instance/methods/update.d.ts.map +1 -1
- package/dist/instance/methods/update.js +4 -4
- package/dist/jobs/index.d.ts +16 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +14 -0
- package/dist/jobs/queue.d.ts +57 -0
- package/dist/jobs/queue.d.ts.map +1 -0
- package/dist/jobs/queue.js +134 -0
- package/dist/license-encryption.d.ts +21 -0
- package/dist/license-encryption.d.ts.map +1 -0
- package/dist/license-encryption.js +74 -0
- package/dist/license.d.ts +33 -7
- package/dist/license.d.ts.map +1 -1
- package/dist/license.js +119 -16
- package/dist/monitoring/alerts.d.ts.map +1 -1
- package/dist/monitoring/cleanup-manager.d.ts.map +1 -1
- package/dist/monitoring/health-monitor.d.ts.map +1 -1
- package/dist/monitoring/index.d.ts.map +1 -1
- package/dist/monitoring/process-registry.d.ts.map +1 -1
- package/dist/monitoring/query-monitor.d.ts.map +1 -1
- package/dist/monitoring/types.d.ts.map +1 -1
- package/dist/monitoring/zombie-detector.d.ts.map +1 -1
- package/dist/monitoring/zombie-detector.js +5 -0
- package/dist/nextjs/index.d.ts.map +1 -1
- package/dist/nextjs/utilities.d.ts.map +1 -1
- package/dist/nextjs/withRevealUI.d.ts.map +1 -1
- package/dist/observability/alerts.d.ts.map +1 -1
- package/dist/observability/alerts.js +1 -2
- package/dist/observability/health-check.d.ts +1 -5
- package/dist/observability/health-check.d.ts.map +1 -1
- package/dist/observability/health-check.js +37 -43
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/logger.d.ts.map +1 -1
- package/dist/observability/logger.js +1 -1
- package/dist/observability/metrics.d.ts.map +1 -1
- package/dist/observability/tracing.d.ts.map +1 -1
- package/dist/observability/tracing.js +0 -1
- package/dist/optimization/asset-optimizer.d.ts +6 -2
- package/dist/optimization/asset-optimizer.d.ts.map +1 -1
- package/dist/optimization/asset-optimizer.js +31 -7
- package/dist/optimization/bundle-analyzer.d.ts +1 -1
- package/dist/optimization/bundle-analyzer.d.ts.map +1 -1
- package/dist/optimization/bundle-analyzer.js +29 -5
- package/dist/optimization/code-splitting.d.ts +0 -23
- package/dist/optimization/code-splitting.d.ts.map +1 -1
- package/dist/optimization/code-splitting.js +0 -29
- package/dist/plugins/form-builder.d.ts.map +1 -1
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/nested-docs.d.ts +4 -0
- package/dist/plugins/nested-docs.d.ts.map +1 -1
- package/dist/plugins/nested-docs.js +50 -5
- package/dist/plugins/redirects.d.ts.map +1 -1
- package/dist/queries/index.d.ts.map +1 -1
- package/dist/queries/queryBuilder.d.ts.map +1 -1
- package/dist/queries/queryBuilder.js +15 -5
- package/dist/relationships/analyzer.d.ts.map +1 -1
- package/dist/relationships/analyzer.js +8 -0
- package/dist/relationships/index.d.ts.map +1 -1
- package/dist/relationships/populate-core.d.ts +57 -0
- package/dist/relationships/populate-core.d.ts.map +1 -0
- package/dist/relationships/populate-core.js +116 -0
- package/dist/relationships/populate-helpers.d.ts +5 -51
- package/dist/relationships/populate-helpers.d.ts.map +1 -1
- package/dist/relationships/populate-helpers.js +4 -109
- package/dist/relationships/population.d.ts +1 -9
- package/dist/relationships/population.d.ts.map +1 -1
- package/dist/relationships/population.js +8 -3
- package/dist/revealui.d.ts.map +1 -1
- package/dist/richtext/exports/client/rcc.d.ts.map +1 -1
- package/dist/richtext/exports/client/rcc.js +1 -1
- package/dist/richtext/exports/server/rsc.d.ts +17 -0
- package/dist/richtext/exports/server/rsc.d.ts.map +1 -1
- package/dist/richtext/exports/server/rsc.js +61 -5
- package/dist/richtext/index.d.ts.map +1 -1
- package/dist/richtext/lexical.d.ts.map +1 -1
- package/dist/security/audit.d.ts +1 -1
- package/dist/security/audit.d.ts.map +1 -1
- package/dist/security/audit.js +4 -2
- package/dist/security/auth.d.ts +29 -160
- package/dist/security/auth.d.ts.map +1 -1
- package/dist/security/auth.js +150 -367
- package/dist/security/authorization.d.ts +7 -31
- package/dist/security/authorization.d.ts.map +1 -1
- package/dist/security/authorization.js +72 -14
- package/dist/security/encryption.d.ts +56 -44
- package/dist/security/encryption.d.ts.map +1 -1
- package/dist/security/encryption.js +128 -100
- package/dist/security/gdpr-storage.d.ts +102 -0
- package/dist/security/gdpr-storage.d.ts.map +1 -0
- package/dist/security/gdpr-storage.js +65 -0
- package/dist/security/gdpr.d.ts +57 -37
- package/dist/security/gdpr.d.ts.map +1 -1
- package/dist/security/gdpr.js +155 -94
- package/dist/security/headers.d.ts +4 -2
- package/dist/security/headers.d.ts.map +1 -1
- package/dist/security/headers.js +35 -17
- package/dist/security/index.d.ts +3 -16
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +3 -16
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/renderPage.d.ts.map +1 -1
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +2 -4
- package/dist/storage/vercel-blob.d.ts.map +1 -1
- package/dist/translations/index.d.ts.map +1 -1
- package/dist/types/access.d.ts.map +1 -1
- package/dist/types/api.d.ts.map +1 -1
- package/dist/types/cms.d.ts.map +1 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/extensions.d.ts.map +1 -1
- package/dist/types/frontend.d.ts.map +1 -1
- package/dist/types/generated.d.ts +0 -2
- package/dist/types/generated.d.ts.map +1 -1
- package/dist/types/generated.js +0 -1
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/interfaces/app.d.ts.map +1 -1
- package/dist/types/jobs.d.ts.map +1 -1
- package/dist/types/legacy.d.ts.map +1 -1
- package/dist/types/plugins.d.ts.map +1 -1
- package/dist/types/query.d.ts.map +1 -1
- package/dist/types/request.d.ts.map +1 -1
- package/dist/types/richtext.d.ts.map +1 -1
- package/dist/types/runtime.d.ts +59 -1
- package/dist/types/runtime.d.ts.map +1 -1
- package/dist/types/schema.d.ts.map +1 -1
- package/dist/types/user.d.ts.map +1 -1
- package/dist/utils/access-conversion.d.ts.map +1 -1
- package/dist/utils/api-wrapper.d.ts.map +1 -1
- package/dist/utils/api-wrapper.js +1 -1
- package/dist/utils/block-conversion.d.ts.map +1 -1
- package/dist/utils/cache.d.ts.map +1 -1
- package/dist/utils/deep-clone.js +0 -1
- package/dist/utils/error-responses.d.ts.map +1 -1
- package/dist/utils/errors.d.ts +36 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +103 -0
- package/dist/utils/field-conversion.d.ts +1 -1
- package/dist/utils/field-conversion.d.ts.map +1 -1
- package/dist/utils/flattenResult.d.ts.map +1 -1
- package/dist/utils/flattenResult.js +0 -1
- package/dist/utils/getBlockSelect.d.ts.map +1 -1
- package/dist/utils/getSelectMode.d.ts.map +1 -1
- package/dist/utils/isValidID.d.ts.map +1 -1
- package/dist/utils/json-parsing.d.ts.map +1 -1
- package/dist/utils/logger-client.d.ts.map +1 -1
- package/dist/utils/logger-server.d.ts.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/request-context.d.ts.map +1 -1
- package/dist/utils/stripUnselectedFields.d.ts.map +1 -1
- package/dist/utils/type-guards.d.ts.map +1 -1
- package/package.json +39 -16
|
@@ -3,6 +3,10 @@ export interface NestedDocsPluginConfig {
|
|
|
3
3
|
collections?: string[];
|
|
4
4
|
parentFieldSlug?: string;
|
|
5
5
|
breadcrumbsFieldSlug?: string;
|
|
6
|
+
/** Drizzle DB client getter — if not provided, breadcrumbs will be empty */
|
|
7
|
+
getDb?: () => unknown;
|
|
8
|
+
/** Label field to use for breadcrumb labels (defaults to 'title') */
|
|
9
|
+
labelField?: string;
|
|
6
10
|
}
|
|
7
11
|
export declare function nestedDocsPlugin(config?: NestedDocsPluginConfig): Plugin;
|
|
8
12
|
//# sourceMappingURL=nested-docs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nested-docs.d.ts","sourceRoot":"","sources":["../../src/plugins/nested-docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"nested-docs.d.ts","sourceRoot":"","sources":["../../src/plugins/nested-docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC;IACtB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAgED,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,sBAA2B,GAAG,MAAM,CA4F5E"}
|
|
@@ -1,5 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walk up the parent chain to build breadcrumbs.
|
|
3
|
+
* Uses raw SQL via the Drizzle client to query the same collection table.
|
|
4
|
+
*/
|
|
5
|
+
async function buildBreadcrumbs(db, collectionSlug, parentId, parentFieldSlug, labelField, maxDepth = 10) {
|
|
6
|
+
const crumbs = [];
|
|
7
|
+
let currentId = parentId;
|
|
8
|
+
let depth = 0;
|
|
9
|
+
// Validate identifiers to prevent SQL injection (table/column names are from config, not user input)
|
|
10
|
+
const identifierPattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
11
|
+
const identifiersValid = identifierPattern.test(collectionSlug) &&
|
|
12
|
+
identifierPattern.test(labelField) &&
|
|
13
|
+
identifierPattern.test(parentFieldSlug);
|
|
14
|
+
if (!identifiersValid) {
|
|
15
|
+
return crumbs;
|
|
16
|
+
}
|
|
17
|
+
while (currentId && depth < maxDepth) {
|
|
18
|
+
try {
|
|
19
|
+
// Use parameterized query — $1 is the only user-controlled value
|
|
20
|
+
const result = await db.execute({
|
|
21
|
+
sql: `SELECT id, "${labelField}", "${parentFieldSlug}" FROM "${collectionSlug}" WHERE id = $1 LIMIT 1`,
|
|
22
|
+
params: [currentId],
|
|
23
|
+
// biome-ignore lint/suspicious/noExplicitAny: Drizzle sql template requires any for raw parameterized queries
|
|
24
|
+
});
|
|
25
|
+
const row = result?.rows?.[0];
|
|
26
|
+
if (!row)
|
|
27
|
+
break;
|
|
28
|
+
crumbs.unshift({
|
|
29
|
+
doc: String(row.id),
|
|
30
|
+
url: `/${collectionSlug}/${String(row.id)}`,
|
|
31
|
+
label: String(row[labelField] ?? row.id),
|
|
32
|
+
});
|
|
33
|
+
currentId = row[parentFieldSlug] ? String(row[parentFieldSlug]) : null;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
depth++;
|
|
39
|
+
}
|
|
40
|
+
return crumbs;
|
|
41
|
+
}
|
|
1
42
|
export function nestedDocsPlugin(config = {}) {
|
|
2
|
-
const { collections = [], parentFieldSlug = 'parent', breadcrumbsFieldSlug = 'breadcrumbs', } = config;
|
|
43
|
+
const { collections = [], parentFieldSlug = 'parent', breadcrumbsFieldSlug = 'breadcrumbs', getDb, labelField = 'title', } = config;
|
|
3
44
|
return (incomingConfig) => {
|
|
4
45
|
if (incomingConfig.collections) {
|
|
5
46
|
for (const collection of incomingConfig.collections) {
|
|
@@ -42,11 +83,15 @@ export function nestedDocsPlugin(config = {}) {
|
|
|
42
83
|
},
|
|
43
84
|
],
|
|
44
85
|
};
|
|
86
|
+
const collectionSlug = collection.slug;
|
|
45
87
|
// Add hooks for breadcrumbs
|
|
46
|
-
const beforeChangeHook = ({ data }) => {
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
|
|
88
|
+
const beforeChangeHook = async ({ data }) => {
|
|
89
|
+
const parentId = data[parentFieldSlug];
|
|
90
|
+
if (parentId && getDb) {
|
|
91
|
+
const db = getDb();
|
|
92
|
+
data[breadcrumbsFieldSlug] = await buildBreadcrumbs(db, collectionSlug, String(parentId), parentFieldSlug, labelField);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
50
95
|
data[breadcrumbsFieldSlug] = [];
|
|
51
96
|
}
|
|
52
97
|
return data;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirects.d.ts","sourceRoot":"","sources":["../../src/plugins/redirects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"redirects.d.ts","sourceRoot":"","sources":["../../src/plugins/redirects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAExF,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE;YAAE,aAAa,EAAE,KAAK,EAAE,CAAA;SAAE,KAAK,KAAK,EAAE,CAAC;QACvD,KAAK,CAAC,EAAE;YACN,WAAW,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE;gBACpB,GAAG,EAAE,QAAQ,CAAC;gBACd,GAAG,EAAE,aAAa,CAAC;aACpB,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;SACvC,CAAC;KACH,CAAC;CACH;AAED,wBAAgB,eAAe,CAAC,MAAM,GAAE,qBAA0B,GAAG,MAAM,CAsE1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/queries/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,cAAc,GACpB,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/queries/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,cAAc,GACpB,MAAM,mBAAmB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queryBuilder.d.ts","sourceRoot":"","sources":["../../src/queries/queryBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"queryBuilder.d.ts","sourceRoot":"","sources":["../../src/queries/queryBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAExE;;;;;GAKG;AAEH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,YAAY,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,GAAG,SAAS,EAC3D,MAAM,EAAE,OAAO,EAAE,EACjB,OAAO,GAAE,iBAAsB,GAC9B,MAAM,CAyNR;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,EAAE,CAoEjE"}
|
|
@@ -24,10 +24,17 @@ export function buildWhereClause(where, params, options = {}) {
|
|
|
24
24
|
return '?';
|
|
25
25
|
};
|
|
26
26
|
const quoteField = (field) => {
|
|
27
|
-
|
|
27
|
+
if (!quoteFields)
|
|
28
|
+
return field;
|
|
29
|
+
// Escape embedded double quotes to prevent SQL injection via identifier breakout
|
|
30
|
+
const escaped = field.replace(/"/g, '""');
|
|
31
|
+
return `"${escaped}"`;
|
|
28
32
|
};
|
|
29
33
|
const whereWithGroups = where;
|
|
30
|
-
const isOperatorObject = (value) => typeof value === 'object' &&
|
|
34
|
+
const isOperatorObject = (value) => typeof value === 'object' &&
|
|
35
|
+
value !== null &&
|
|
36
|
+
!Array.isArray(value) &&
|
|
37
|
+
!(value instanceof Date);
|
|
31
38
|
// Handle and/or groups
|
|
32
39
|
if (Array.isArray(whereWithGroups.and)) {
|
|
33
40
|
const conditions = whereWithGroups.and
|
|
@@ -141,8 +148,10 @@ export function buildWhereClause(where, params, options = {}) {
|
|
|
141
148
|
// contains (LIKE with wildcards)
|
|
142
149
|
if ('contains' in condition && typeof condition.contains === 'string') {
|
|
143
150
|
const placeholder = getPlaceholder();
|
|
144
|
-
|
|
145
|
-
|
|
151
|
+
// Escape LIKE wildcards (% and _) in user input to prevent wildcard injection
|
|
152
|
+
const escaped = condition.contains.replace(/[%_\\]/g, '\\$&');
|
|
153
|
+
params.push(`%${escaped}%`);
|
|
154
|
+
conditions.push(`${quotedField} LIKE ${placeholder} ESCAPE '\\'`);
|
|
146
155
|
}
|
|
147
156
|
// greater_than
|
|
148
157
|
if ('greater_than' in condition && condition.greater_than !== undefined) {
|
|
@@ -209,7 +218,8 @@ export function extractWhereValues(where) {
|
|
|
209
218
|
break;
|
|
210
219
|
case 'contains':
|
|
211
220
|
if (typeof value === 'string') {
|
|
212
|
-
|
|
221
|
+
const escaped = value.replace(/[%_\\]/g, '\\$&');
|
|
222
|
+
values.push(`%${escaped}%`);
|
|
213
223
|
}
|
|
214
224
|
break;
|
|
215
225
|
case 'in':
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/relationships/analyzer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/relationships/analyzer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D;;;;;;;;;;GAUG;AAEH;;GAEG;AACH,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,sBAAsB,GAAG,kBAAkB,GAAG,gBAAgB,EACtE,cAAc,CAAC,EAAE,MAAM,GACtB,oBAAoB,EAAE,CA6DxB;AA6DD;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG;IAC9E,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CA+BA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defaultLogger } from '../instance/logger.js';
|
|
1
2
|
/**
|
|
2
3
|
* Analyzes a collection or global configuration and extracts all relationship fields
|
|
3
4
|
* with their storage metadata for proper query building.
|
|
@@ -46,6 +47,13 @@ export function getRelationshipFields(config, collectionSlug) {
|
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
traverseFields(config.fields);
|
|
50
|
+
// Validate extracted metadata to catch configuration errors early
|
|
51
|
+
const validation = validateRelationshipMetadata(relationships);
|
|
52
|
+
if (!validation.valid) {
|
|
53
|
+
for (const error of validation.errors) {
|
|
54
|
+
defaultLogger.warn(`[RelationshipAnalyzer] ${error}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
49
57
|
return relationships;
|
|
50
58
|
}
|
|
51
59
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relationships/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relationships/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Population Core — Pure Types & Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module contains types and pure utility functions for relationship
|
|
5
|
+
* population that have NO imports from the afterRead chain, breaking the
|
|
6
|
+
* circular dependency: population → populate-helpers → afterRead → population.
|
|
7
|
+
*/
|
|
8
|
+
/** Relationship field types supported by population */
|
|
9
|
+
export interface PopulateRelationshipField {
|
|
10
|
+
type: 'relationship' | 'upload' | 'join';
|
|
11
|
+
name: string;
|
|
12
|
+
relationTo?: string | string[];
|
|
13
|
+
collection?: string | string[];
|
|
14
|
+
hasMany?: boolean;
|
|
15
|
+
maxDepth?: number;
|
|
16
|
+
localized?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** Information extracted about a relationship */
|
|
19
|
+
export interface RelationInfo {
|
|
20
|
+
/** The collection slug this relationship points to */
|
|
21
|
+
relationName: string | undefined;
|
|
22
|
+
/** The ID(s) to populate */
|
|
23
|
+
id: unknown;
|
|
24
|
+
/** The related collection config if available */
|
|
25
|
+
relatedCollection: unknown;
|
|
26
|
+
}
|
|
27
|
+
/** Location information for updating a document with populated values */
|
|
28
|
+
export interface UpdateLocation {
|
|
29
|
+
index?: number;
|
|
30
|
+
key?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Extract relationship information from field and data
|
|
34
|
+
*
|
|
35
|
+
* Handles polymorphic relationships, join tables, and direct FK relationships.
|
|
36
|
+
*/
|
|
37
|
+
export declare function extractRelationInfo(field: PopulateRelationshipField, data: unknown, req: {
|
|
38
|
+
revealui?: {
|
|
39
|
+
collections?: Record<string, unknown>;
|
|
40
|
+
};
|
|
41
|
+
}): RelationInfo;
|
|
42
|
+
/**
|
|
43
|
+
* Check if a relationship should be populated based on depth
|
|
44
|
+
*/
|
|
45
|
+
export declare function shouldPopulateRelationship(currentDepth: number, depth: number): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Update document with populated relationship value
|
|
48
|
+
*
|
|
49
|
+
* Handles various field configurations: arrays, localized fields, join tables, etc.
|
|
50
|
+
*/
|
|
51
|
+
export declare function updateDocumentWithPopulatedValue(args: {
|
|
52
|
+
dataReference: Record<string, unknown>;
|
|
53
|
+
field: PopulateRelationshipField;
|
|
54
|
+
relationshipValue: unknown;
|
|
55
|
+
location: UpdateLocation;
|
|
56
|
+
}): void;
|
|
57
|
+
//# sourceMappingURL=populate-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"populate-core.d.ts","sourceRoot":"","sources":["../../src/relationships/populate-core.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,uDAAuD;AACvD,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,4BAA4B;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,iDAAiD;IACjD,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,yBAAyB,EAChC,IAAI,EAAE,OAAO,EACb,GAAG,EAAE;IACH,QAAQ,CAAC,EAAE;QACT,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACvC,CAAC;CACH,GACA,YAAY,CAwCd;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEvF;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,IAAI,EAAE;IACrD,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,KAAK,EAAE,yBAAyB,CAAC;IACjC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,cAAc,CAAC;CAC1B,GAAG,IAAI,CAsDP"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Population Core — Pure Types & Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module contains types and pure utility functions for relationship
|
|
5
|
+
* population that have NO imports from the afterRead chain, breaking the
|
|
6
|
+
* circular dependency: population → populate-helpers → afterRead → population.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Extract relationship information from field and data
|
|
10
|
+
*
|
|
11
|
+
* Handles polymorphic relationships, join tables, and direct FK relationships.
|
|
12
|
+
*/
|
|
13
|
+
export function extractRelationInfo(field, data, req) {
|
|
14
|
+
const dataRecord = data;
|
|
15
|
+
// Determine relation name based on field type
|
|
16
|
+
let relationName;
|
|
17
|
+
if (field.type === 'join') {
|
|
18
|
+
relationName = Array.isArray(field.collection)
|
|
19
|
+
? dataRecord.relationTo
|
|
20
|
+
: field.collection;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
relationName = Array.isArray(field.relationTo)
|
|
24
|
+
? dataRecord.relationTo
|
|
25
|
+
: field.relationTo;
|
|
26
|
+
}
|
|
27
|
+
// Get related collection config
|
|
28
|
+
const relatedCollection = relationName && req.revealui?.collections ? req.revealui.collections[relationName] : undefined;
|
|
29
|
+
// Extract ID based on field configuration
|
|
30
|
+
let id;
|
|
31
|
+
if (field.type === 'join' && Array.isArray(field.collection)) {
|
|
32
|
+
id = dataRecord.value;
|
|
33
|
+
}
|
|
34
|
+
else if (field.type !== 'join' && Array.isArray(field.relationTo)) {
|
|
35
|
+
id = dataRecord.value;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
id = data;
|
|
39
|
+
}
|
|
40
|
+
// Normalize ID to string or number
|
|
41
|
+
if (typeof id !== 'string' &&
|
|
42
|
+
typeof id !== 'number' &&
|
|
43
|
+
typeof id?.toString === 'function' &&
|
|
44
|
+
typeof id !== 'object') {
|
|
45
|
+
id = id.toString();
|
|
46
|
+
}
|
|
47
|
+
return { relationName, id, relatedCollection };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Check if a relationship should be populated based on depth
|
|
51
|
+
*/
|
|
52
|
+
export function shouldPopulateRelationship(currentDepth, depth) {
|
|
53
|
+
return depth > 0 && currentDepth <= depth;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Update document with populated relationship value
|
|
57
|
+
*
|
|
58
|
+
* Handles various field configurations: arrays, localized fields, join tables, etc.
|
|
59
|
+
*/
|
|
60
|
+
export function updateDocumentWithPopulatedValue(args) {
|
|
61
|
+
const { dataReference, field, relationshipValue, location } = args;
|
|
62
|
+
const { index, key } = location;
|
|
63
|
+
// Case 1: Localized array field (has both index and key)
|
|
64
|
+
if (typeof index === 'number' && typeof key === 'string') {
|
|
65
|
+
const fieldRecord = dataReference[field.name];
|
|
66
|
+
const localeRecords = fieldRecord[key];
|
|
67
|
+
const localeEntry = localeRecords[index];
|
|
68
|
+
if (field.type !== 'join' && Array.isArray(field.relationTo)) {
|
|
69
|
+
localeEntry.value = relationshipValue;
|
|
70
|
+
}
|
|
71
|
+
else if (field.type === 'join' && Array.isArray(field.collection)) {
|
|
72
|
+
localeEntry.value = relationshipValue;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
localeRecords[index] = relationshipValue;
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Case 2: Array field or localized field (has index or key, but not both)
|
|
80
|
+
if (typeof index === 'number' || typeof key === 'string') {
|
|
81
|
+
const fieldRecord = dataReference[field.name];
|
|
82
|
+
const target = (index ?? key);
|
|
83
|
+
if (field.type === 'join') {
|
|
84
|
+
if (!Array.isArray(field.collection)) {
|
|
85
|
+
const docs = fieldRecord.docs;
|
|
86
|
+
docs[target] = relationshipValue;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const docs = fieldRecord.docs;
|
|
90
|
+
const docEntry = docs[target];
|
|
91
|
+
docEntry.value = relationshipValue;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else if (Array.isArray(field.relationTo)) {
|
|
95
|
+
const entries = fieldRecord;
|
|
96
|
+
const entry = entries[target];
|
|
97
|
+
entry.value = relationshipValue;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
fieldRecord[target] = relationshipValue;
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// Case 3: Single value (no index or key)
|
|
105
|
+
if (field.type !== 'join' && Array.isArray(field.relationTo)) {
|
|
106
|
+
const fieldRecord = dataReference[field.name];
|
|
107
|
+
fieldRecord.value = relationshipValue;
|
|
108
|
+
}
|
|
109
|
+
else if (field.type === 'join' && Array.isArray(field.collection)) {
|
|
110
|
+
const fieldRecord = dataReference[field.name];
|
|
111
|
+
fieldRecord.value = relationshipValue;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
dataReference[field.name] = relationshipValue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -3,41 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Extracted from the monolithic populate() function to improve
|
|
5
5
|
* maintainability, testability, and clarity.
|
|
6
|
-
*/
|
|
7
|
-
import type { RevealRequest, TypedFallbackLocale } from '../types/index.js';
|
|
8
|
-
/** Relationship field types supported by population */
|
|
9
|
-
export interface PopulateRelationshipField {
|
|
10
|
-
type: 'relationship' | 'upload' | 'join';
|
|
11
|
-
name: string;
|
|
12
|
-
relationTo?: string | string[];
|
|
13
|
-
collection?: string | string[];
|
|
14
|
-
hasMany?: boolean;
|
|
15
|
-
maxDepth?: number;
|
|
16
|
-
localized?: boolean;
|
|
17
|
-
}
|
|
18
|
-
/** Information extracted about a relationship */
|
|
19
|
-
export interface RelationInfo {
|
|
20
|
-
/** The collection slug this relationship points to */
|
|
21
|
-
relationName: string | undefined;
|
|
22
|
-
/** The ID(s) to populate */
|
|
23
|
-
id: unknown;
|
|
24
|
-
/** The related collection config if available */
|
|
25
|
-
relatedCollection: unknown;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Extract relationship information from field and data
|
|
29
6
|
*
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
export declare function extractRelationInfo(field: PopulateRelationshipField, data: unknown, req: {
|
|
33
|
-
revealui?: {
|
|
34
|
-
collections?: Record<string, unknown>;
|
|
35
|
-
};
|
|
36
|
-
}): RelationInfo;
|
|
37
|
-
/**
|
|
38
|
-
* Check if a relationship should be populated based on depth
|
|
7
|
+
* Pure types and utilities live in populate-core.ts (no afterRead imports).
|
|
8
|
+
* This module re-exports them and adds helpers that depend on afterRead.
|
|
39
9
|
*/
|
|
40
|
-
|
|
10
|
+
import type { RevealRequest, TypedFallbackLocale } from '../types/index.js';
|
|
11
|
+
export type { PopulateRelationshipField, RelationInfo, UpdateLocation } from './populate-core.js';
|
|
12
|
+
export { extractRelationInfo, shouldPopulateRelationship, updateDocumentWithPopulatedValue, } from './populate-core.js';
|
|
41
13
|
/**
|
|
42
14
|
* Load a related document using the dataLoader
|
|
43
15
|
*
|
|
@@ -83,22 +55,4 @@ export declare function applyNestedPopulation(args: {
|
|
|
83
55
|
showHiddenFields: boolean;
|
|
84
56
|
req: RevealRequest;
|
|
85
57
|
}): Promise<unknown>;
|
|
86
|
-
/**
|
|
87
|
-
* Location information for updating a document with populated values
|
|
88
|
-
*/
|
|
89
|
-
export interface UpdateLocation {
|
|
90
|
-
index?: number;
|
|
91
|
-
key?: string;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Update document with populated relationship value
|
|
95
|
-
*
|
|
96
|
-
* Handles various field configurations: arrays, localized fields, join tables, etc.
|
|
97
|
-
*/
|
|
98
|
-
export declare function updateDocumentWithPopulatedValue(args: {
|
|
99
|
-
dataReference: Record<string, unknown>;
|
|
100
|
-
field: PopulateRelationshipField;
|
|
101
|
-
relationshipValue: unknown;
|
|
102
|
-
location: UpdateLocation;
|
|
103
|
-
}): void;
|
|
104
58
|
//# sourceMappingURL=populate-helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"populate-helpers.d.ts","sourceRoot":"","sources":["../../src/relationships/populate-helpers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"populate-helpers.d.ts","sourceRoot":"","sources":["../../src/relationships/populate-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAIV,aAAa,EAGb,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EAAE,yBAAyB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAClG,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,gCAAgC,GACjC,MAAM,oBAAoB,CAAC;AAE5B;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,EAAE,EAAE,OAAO,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,mBAAmB,CAAC;IACpC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,GAAG,EAAE;QACH,UAAU,CAAC,EAAE;YACX,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;SAC1C,CAAC;KACH,CAAC;CACH,GAAG,OAAO,CAAC,OAAO,CAAC,CA8DnB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,OAAO,CAAC;IACb,gBAAgB,EAAE;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;QACnB,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,mBAAmB,CAAC;IACpC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,GAAG,EAAE,aAAa,CAAC;CACpB,GAAG,OAAO,CAAC,OAAO,CAAC,CA+CnB"}
|
|
@@ -3,56 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Extracted from the monolithic populate() function to improve
|
|
5
5
|
* maintainability, testability, and clarity.
|
|
6
|
+
*
|
|
7
|
+
* Pure types and utilities live in populate-core.ts (no afterRead imports).
|
|
8
|
+
* This module re-exports them and adds helpers that depend on afterRead.
|
|
6
9
|
*/
|
|
7
10
|
import { createDataloaderCacheKey } from '../dataloader.js';
|
|
8
11
|
import { afterRead } from '../fields/hooks/afterRead/index.js';
|
|
9
|
-
|
|
10
|
-
* Extract relationship information from field and data
|
|
11
|
-
*
|
|
12
|
-
* Handles polymorphic relationships, join tables, and direct FK relationships.
|
|
13
|
-
*/
|
|
14
|
-
export function extractRelationInfo(field, data, req) {
|
|
15
|
-
const dataRecord = data;
|
|
16
|
-
// Determine relation name based on field type
|
|
17
|
-
let relationName;
|
|
18
|
-
if (field.type === 'join') {
|
|
19
|
-
relationName = Array.isArray(field.collection)
|
|
20
|
-
? dataRecord.relationTo
|
|
21
|
-
: field.collection;
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
relationName = Array.isArray(field.relationTo)
|
|
25
|
-
? dataRecord.relationTo
|
|
26
|
-
: field.relationTo;
|
|
27
|
-
}
|
|
28
|
-
// Get related collection config
|
|
29
|
-
const relatedCollection = relationName && req.revealui?.collections ? req.revealui.collections[relationName] : undefined;
|
|
30
|
-
// Extract ID based on field configuration
|
|
31
|
-
let id;
|
|
32
|
-
if (field.type === 'join' && Array.isArray(field.collection)) {
|
|
33
|
-
id = dataRecord.value;
|
|
34
|
-
}
|
|
35
|
-
else if (field.type !== 'join' && Array.isArray(field.relationTo)) {
|
|
36
|
-
id = dataRecord.value;
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
id = data;
|
|
40
|
-
}
|
|
41
|
-
// Normalize ID to string or number
|
|
42
|
-
if (typeof id !== 'string' &&
|
|
43
|
-
typeof id !== 'number' &&
|
|
44
|
-
typeof id?.toString === 'function' &&
|
|
45
|
-
typeof id !== 'object') {
|
|
46
|
-
id = id.toString();
|
|
47
|
-
}
|
|
48
|
-
return { relationName, id, relatedCollection };
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Check if a relationship should be populated based on depth
|
|
52
|
-
*/
|
|
53
|
-
export function shouldPopulateRelationship(currentDepth, depth) {
|
|
54
|
-
return depth > 0 && currentDepth <= depth;
|
|
55
|
-
}
|
|
12
|
+
export { extractRelationInfo, shouldPopulateRelationship, updateDocumentWithPopulatedValue, } from './populate-core.js';
|
|
56
13
|
/**
|
|
57
14
|
* Load a related document using the dataLoader
|
|
58
15
|
*
|
|
@@ -123,65 +80,3 @@ export async function applyNestedPopulation(args) {
|
|
|
123
80
|
showHiddenFields,
|
|
124
81
|
});
|
|
125
82
|
}
|
|
126
|
-
/**
|
|
127
|
-
* Update document with populated relationship value
|
|
128
|
-
*
|
|
129
|
-
* Handles various field configurations: arrays, localized fields, join tables, etc.
|
|
130
|
-
*/
|
|
131
|
-
export function updateDocumentWithPopulatedValue(args) {
|
|
132
|
-
const { dataReference, field, relationshipValue, location } = args;
|
|
133
|
-
const { index, key } = location;
|
|
134
|
-
// Case 1: Localized array field (has both index and key)
|
|
135
|
-
if (typeof index === 'number' && typeof key === 'string') {
|
|
136
|
-
const fieldRecord = dataReference[field.name];
|
|
137
|
-
const localeRecords = fieldRecord[key];
|
|
138
|
-
const localeEntry = localeRecords[index];
|
|
139
|
-
if (field.type !== 'join' && Array.isArray(field.relationTo)) {
|
|
140
|
-
localeEntry.value = relationshipValue;
|
|
141
|
-
}
|
|
142
|
-
else if (field.type === 'join' && Array.isArray(field.collection)) {
|
|
143
|
-
localeEntry.value = relationshipValue;
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
localeRecords[index] = relationshipValue;
|
|
147
|
-
}
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
// Case 2: Array field or localized field (has index or key, but not both)
|
|
151
|
-
if (typeof index === 'number' || typeof key === 'string') {
|
|
152
|
-
const fieldRecord = dataReference[field.name];
|
|
153
|
-
const target = (index ?? key);
|
|
154
|
-
if (field.type === 'join') {
|
|
155
|
-
if (!Array.isArray(field.collection)) {
|
|
156
|
-
const docs = fieldRecord.docs;
|
|
157
|
-
docs[target] = relationshipValue;
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
const docs = fieldRecord.docs;
|
|
161
|
-
const docEntry = docs[target];
|
|
162
|
-
docEntry.value = relationshipValue;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
else if (Array.isArray(field.relationTo)) {
|
|
166
|
-
const entries = fieldRecord;
|
|
167
|
-
const entry = entries[target];
|
|
168
|
-
entry.value = relationshipValue;
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
fieldRecord[target] = relationshipValue;
|
|
172
|
-
}
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
// Case 3: Single value (no index or key)
|
|
176
|
-
if (field.type !== 'join' && Array.isArray(field.relationTo)) {
|
|
177
|
-
const fieldRecord = dataReference[field.name];
|
|
178
|
-
fieldRecord.value = relationshipValue;
|
|
179
|
-
}
|
|
180
|
-
else if (field.type === 'join' && Array.isArray(field.collection)) {
|
|
181
|
-
const fieldRecord = dataReference[field.name];
|
|
182
|
-
fieldRecord.value = relationshipValue;
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
dataReference[field.name] = relationshipValue;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PopulateType, TypedFallbackLocale } from '../types/index.js';
|
|
2
|
+
import type { PopulateRelationshipField } from './populate-core.js';
|
|
2
3
|
interface PopulateRequest {
|
|
3
4
|
revealui?: {
|
|
4
5
|
collections?: Record<string, {
|
|
@@ -15,15 +16,6 @@ interface PopulateRequest {
|
|
|
15
16
|
find?: (options: unknown) => Promise<unknown>;
|
|
16
17
|
};
|
|
17
18
|
}
|
|
18
|
-
interface PopulateRelationshipField {
|
|
19
|
-
type: 'relationship' | 'upload' | 'join';
|
|
20
|
-
name: string;
|
|
21
|
-
relationTo?: string | string[];
|
|
22
|
-
collection?: string | string[];
|
|
23
|
-
hasMany?: boolean;
|
|
24
|
-
maxDepth?: number;
|
|
25
|
-
localized?: boolean;
|
|
26
|
-
}
|
|
27
19
|
type PromiseArgs = {
|
|
28
20
|
currentDepth: number;
|
|
29
21
|
depth: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"population.d.ts","sourceRoot":"","sources":["../../src/relationships/population.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"population.d.ts","sourceRoot":"","sources":["../../src/relationships/population.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAiB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC1F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAapE,UAAU,eAAe;IACvB,QAAQ,CAAC,EAAE;QACT,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,MAAM,CAAC,EAAE;gBAAE,eAAe,CAAC,EAAE,OAAO,CAAA;aAAE,CAAA;SAAE,CAAC,CAAC;QACzE,MAAM,CAAC,EAAE;YAAE,WAAW,CAAC,EAAE,OAAO,EAAE,CAAA;SAAE,CAAC;KACtC,CAAC;IACF,UAAU,CAAC,EAAE;QACX,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KAC/C,CAAC;CACH;AAkHD,KAAK,WAAW,GAAG;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,mBAAmB,CAAC;IACpC,KAAK,EAAE,yBAAyB,CAAC;IACjC,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,GAAG,EAAE,eAAe,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,6BAA6B,GAAU,0IAYjD,WAAW,KAAG,OAAO,CAAC,IAAI,CAoI5B,CAAC"}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
+
// External type imports
|
|
1
2
|
import { fieldHasMaxDepth, fieldShouldBeLocalized, fieldSupportsMany, } from '../fields/config/types.js';
|
|
3
|
+
// Pure utilities from populate-core (no circular dependency)
|
|
4
|
+
import { extractRelationInfo, shouldPopulateRelationship, updateDocumentWithPopulatedValue, } from './populate-core.js';
|
|
5
|
+
// Helpers that depend on afterRead (static import — safe because populate-core
|
|
6
|
+
// broke the cycle: population no longer imports from populate-helpers for the
|
|
7
|
+
// functions that afterRead/promise.ts needs)
|
|
8
|
+
import { applyNestedPopulation, loadRelatedDocument } from './populate-helpers.js';
|
|
2
9
|
/**
|
|
3
10
|
* Populate a single relationship field
|
|
4
11
|
*
|
|
5
12
|
* Refactored from the original monolithic function for better maintainability.
|
|
6
|
-
* Uses helper functions from populate-
|
|
13
|
+
* Uses helper functions from populate-core.ts and populate-helpers.ts.
|
|
7
14
|
*/
|
|
8
15
|
const populate = async ({ currentDepth, data, dataReference, depth, draft, fallbackLocale, field, index, key, locale, overrideAccess, populateArg, req, showHiddenFields, }) => {
|
|
9
|
-
// Import helpers (dynamic to avoid circular dependencies)
|
|
10
|
-
const { extractRelationInfo, shouldPopulateRelationship, loadRelatedDocument, applyNestedPopulation, updateDocumentWithPopulatedValue, } = await import('./populate-helpers.js');
|
|
11
16
|
// Step 1: Extract relationship information
|
|
12
17
|
const { relationName, id, relatedCollection } = extractRelationInfo(field, data, req);
|
|
13
18
|
if (!relatedCollection) {
|
package/dist/revealui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"revealui.d.ts","sourceRoot":"","sources":["../src/revealui.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,
|
|
1
|
+
{"version":3,"file":"revealui.d.ts","sourceRoot":"","sources":["../src/revealui.ts"],"names":[],"mappings":"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"}
|