@aphexcms/cms-core 0.1.6 → 0.1.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.
- package/package.json +8 -4
- package/src/lib/api/assets.ts +75 -0
- package/src/lib/api/client.ts +150 -0
- package/src/lib/api/documents.ts +102 -0
- package/src/lib/api/index.ts +7 -0
- package/src/lib/api/organizations.ts +154 -0
- package/src/lib/api/types.ts +34 -0
- package/src/lib/auth/auth-errors.ts +23 -0
- package/src/lib/auth/auth-hooks.ts +132 -0
- package/src/lib/auth/provider.ts +25 -0
- package/{dist/client/index.js → src/lib/client/index.ts} +19 -8
- package/{dist → src/lib}/components/AdminApp.svelte +4 -5
- package/{dist → src/lib}/components/admin/DocumentEditor.svelte +7 -7
- package/{dist → src/lib}/components/admin/SchemaField.svelte +1 -1
- package/{dist → src/lib}/components/admin/fields/ArrayField.svelte +3 -3
- package/{dist → src/lib}/components/admin/fields/BooleanField.svelte +1 -1
- package/{dist → src/lib}/components/admin/fields/ImageField.svelte +40 -13
- package/{dist → src/lib}/components/admin/fields/NumberField.svelte +1 -1
- package/{dist → src/lib}/components/admin/fields/ReferenceField.svelte +2 -2
- package/{dist → src/lib}/components/admin/fields/SlugField.svelte +2 -2
- package/{dist → src/lib}/components/admin/fields/StringField.svelte +1 -1
- package/{dist → src/lib}/components/admin/fields/TextareaField.svelte +1 -1
- package/{dist/components/index.js → src/lib/components/index.ts} +5 -1
- package/{dist → src/lib}/components/layout/OrganizationSwitcher.svelte +2 -2
- package/{dist → src/lib}/components/layout/Sidebar.svelte +1 -1
- package/{dist → src/lib}/components/layout/sidebar/AppSidebar.svelte +1 -1
- package/{dist → src/lib}/components/layout/sidebar/NavUser.svelte +1 -1
- package/src/lib/config.ts +18 -0
- package/{dist/db/adapters/index.js → src/lib/db/adapters/index.ts} +0 -1
- package/{dist/db/index.js → src/lib/db/index.ts} +2 -1
- package/src/lib/db/interfaces/asset.ts +61 -0
- package/src/lib/db/interfaces/document.ts +53 -0
- package/src/lib/db/interfaces/index.ts +98 -0
- package/src/lib/db/interfaces/organization.ts +51 -0
- package/src/lib/db/interfaces/schema.ts +13 -0
- package/src/lib/db/interfaces/user.ts +16 -0
- package/src/lib/db/utils/reference-resolver.ts +119 -0
- package/src/lib/define.ts +7 -0
- package/{dist/email/index.js → src/lib/email/index.ts} +2 -1
- package/src/lib/email/interfaces/email.ts +45 -0
- package/src/lib/engine.ts +85 -0
- package/src/lib/field-validation/rule.ts +287 -0
- package/src/lib/field-validation/utils.ts +91 -0
- package/src/lib/hooks.ts +142 -0
- package/{dist/index.js → src/lib/index.ts} +2 -1
- package/{dist/is-mobile.svelte.js → src/lib/is-mobile.svelte.ts} +5 -3
- package/src/lib/routes/assets-by-id.ts +161 -0
- package/src/lib/routes/assets-cdn.ts +185 -0
- package/src/lib/routes/assets.ts +116 -0
- package/src/lib/routes/documents-by-id.ts +188 -0
- package/src/lib/routes/documents-publish.ts +211 -0
- package/src/lib/routes/documents.ts +172 -0
- package/src/lib/routes/index.ts +13 -0
- package/src/lib/routes/organizations-by-id.ts +258 -0
- package/src/lib/routes/organizations-invitations.ts +183 -0
- package/src/lib/routes/organizations-members.ts +301 -0
- package/src/lib/routes/organizations-switch.ts +74 -0
- package/src/lib/routes/organizations.ts +147 -0
- package/src/lib/routes/schemas-by-type.ts +35 -0
- package/src/lib/routes/schemas.ts +19 -0
- package/{dist/routes-exports.js → src/lib/routes-exports.ts} +28 -5
- package/src/lib/schema-context.svelte.ts +24 -0
- package/src/lib/schema-utils/cleanup.ts +116 -0
- package/src/lib/schema-utils/index.ts +4 -0
- package/src/lib/schema-utils/utils.ts +47 -0
- package/src/lib/schema-utils/validator.ts +58 -0
- package/src/lib/server/index.ts +40 -0
- package/src/lib/services/asset-service.ts +256 -0
- package/src/lib/services/index.ts +6 -0
- package/src/lib/storage/adapters/index.ts +2 -0
- package/src/lib/storage/adapters/local-storage-adapter.ts +215 -0
- package/{dist/storage/index.js → src/lib/storage/index.ts} +4 -2
- package/src/lib/storage/interfaces/index.ts +2 -0
- package/src/lib/storage/interfaces/storage.ts +114 -0
- package/src/lib/storage/providers/storage.ts +83 -0
- package/src/lib/types/asset.ts +81 -0
- package/src/lib/types/auth.ts +80 -0
- package/src/lib/types/config.ts +45 -0
- package/src/lib/types/document.ts +38 -0
- package/src/lib/types/index.ts +8 -0
- package/src/lib/types/organization.ts +119 -0
- package/src/lib/types/schemas.ts +151 -0
- package/src/lib/types/sidebar.ts +37 -0
- package/src/lib/types/user.ts +17 -0
- package/src/lib/utils/content-hash.ts +75 -0
- package/src/lib/utils/image-url.ts +204 -0
- package/src/lib/utils/index.ts +12 -0
- package/src/lib/utils/slug.ts +33 -0
- package/src/lib/utils.ts +13 -0
- package/dist/api/assets.d.ts +0 -48
- package/dist/api/assets.d.ts.map +0 -1
- package/dist/api/assets.js +0 -52
- package/dist/api/client.d.ts +0 -37
- package/dist/api/client.d.ts.map +0 -1
- package/dist/api/client.js +0 -125
- package/dist/api/documents.d.ts +0 -56
- package/dist/api/documents.d.ts.map +0 -1
- package/dist/api/documents.js +0 -77
- package/dist/api/index.d.ts +0 -7
- package/dist/api/index.d.ts.map +0 -1
- package/dist/api/index.js +0 -5
- package/dist/api/organizations.d.ts +0 -101
- package/dist/api/organizations.d.ts.map +0 -1
- package/dist/api/organizations.js +0 -92
- package/dist/api/types.d.ts +0 -23
- package/dist/api/types.d.ts.map +0 -1
- package/dist/api/types.js +0 -1
- package/dist/auth/auth-errors.d.ts +0 -7
- package/dist/auth/auth-errors.d.ts.map +0 -1
- package/dist/auth/auth-errors.js +0 -13
- package/dist/auth/auth-hooks.d.ts +0 -6
- package/dist/auth/auth-hooks.d.ts.map +0 -1
- package/dist/auth/auth-hooks.js +0 -108
- package/dist/auth/provider.d.ts +0 -17
- package/dist/auth/provider.d.ts.map +0 -1
- package/dist/auth/provider.js +0 -1
- package/dist/client/index.d.ts +0 -24
- package/dist/client/index.d.ts.map +0 -1
- package/dist/components/AdminApp.svelte.d.ts +0 -24
- package/dist/components/AdminApp.svelte.d.ts.map +0 -1
- package/dist/components/admin/AdminLayout.svelte.d.ts +0 -15
- package/dist/components/admin/AdminLayout.svelte.d.ts.map +0 -1
- package/dist/components/admin/DocumentEditor.svelte.d.ts +0 -18
- package/dist/components/admin/DocumentEditor.svelte.d.ts.map +0 -1
- package/dist/components/admin/DocumentTypesList.svelte.d.ts +0 -14
- package/dist/components/admin/DocumentTypesList.svelte.d.ts.map +0 -1
- package/dist/components/admin/ObjectModal.svelte.d.ts +0 -15
- package/dist/components/admin/ObjectModal.svelte.d.ts.map +0 -1
- package/dist/components/admin/SchemaField.svelte.d.ts +0 -19
- package/dist/components/admin/SchemaField.svelte.d.ts.map +0 -1
- package/dist/components/admin/fields/ArrayField.svelte.d.ts +0 -12
- package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +0 -1
- package/dist/components/admin/fields/BooleanField.svelte.d.ts +0 -13
- package/dist/components/admin/fields/BooleanField.svelte.d.ts.map +0 -1
- package/dist/components/admin/fields/ImageField.svelte.d.ts +0 -15
- package/dist/components/admin/fields/ImageField.svelte.d.ts.map +0 -1
- package/dist/components/admin/fields/NumberField.svelte.d.ts +0 -14
- package/dist/components/admin/fields/NumberField.svelte.d.ts.map +0 -1
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts +0 -12
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +0 -1
- package/dist/components/admin/fields/SlugField.svelte.d.ts +0 -15
- package/dist/components/admin/fields/SlugField.svelte.d.ts.map +0 -1
- package/dist/components/admin/fields/StringField.svelte.d.ts +0 -14
- package/dist/components/admin/fields/StringField.svelte.d.ts.map +0 -1
- package/dist/components/admin/fields/TextareaField.svelte.d.ts +0 -14
- package/dist/components/admin/fields/TextareaField.svelte.d.ts.map +0 -1
- package/dist/components/fields/index.d.ts +0 -9
- package/dist/components/fields/index.d.ts.map +0 -1
- package/dist/components/index.d.ts +0 -7
- package/dist/components/index.d.ts.map +0 -1
- package/dist/components/layout/OrganizationSwitcher.svelte.d.ts +0 -11
- package/dist/components/layout/OrganizationSwitcher.svelte.d.ts.map +0 -1
- package/dist/components/layout/Sidebar.svelte.d.ts +0 -14
- package/dist/components/layout/Sidebar.svelte.d.ts.map +0 -1
- package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts +0 -11
- package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts.map +0 -1
- package/dist/components/layout/sidebar/NavMain.svelte.d.ts +0 -19
- package/dist/components/layout/sidebar/NavMain.svelte.d.ts.map +0 -1
- package/dist/components/layout/sidebar/NavSecondary.svelte.d.ts +0 -9
- package/dist/components/layout/sidebar/NavSecondary.svelte.d.ts.map +0 -1
- package/dist/components/layout/sidebar/NavUser.svelte.d.ts +0 -9
- package/dist/components/layout/sidebar/NavUser.svelte.d.ts.map +0 -1
- package/dist/config.d.ts +0 -3
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -15
- package/dist/db/adapters/index.d.ts +0 -1
- package/dist/db/adapters/index.d.ts.map +0 -1
- package/dist/db/index.d.ts +0 -2
- package/dist/db/index.d.ts.map +0 -1
- package/dist/db/interfaces/asset.d.ts +0 -51
- package/dist/db/interfaces/asset.d.ts.map +0 -1
- package/dist/db/interfaces/asset.js +0 -1
- package/dist/db/interfaces/document.d.ts +0 -36
- package/dist/db/interfaces/document.d.ts.map +0 -1
- package/dist/db/interfaces/document.js +0 -1
- package/dist/db/interfaces/index.d.ts +0 -73
- package/dist/db/interfaces/index.d.ts.map +0 -1
- package/dist/db/interfaces/index.js +0 -1
- package/dist/db/interfaces/organization.d.ts +0 -27
- package/dist/db/interfaces/organization.d.ts.map +0 -1
- package/dist/db/interfaces/organization.js +0 -1
- package/dist/db/interfaces/schema.d.ts +0 -21
- package/dist/db/interfaces/schema.d.ts.map +0 -1
- package/dist/db/interfaces/schema.js +0 -1
- package/dist/db/interfaces/user.d.ts +0 -15
- package/dist/db/interfaces/user.d.ts.map +0 -1
- package/dist/db/interfaces/user.js +0 -1
- package/dist/db/utils/reference-resolver.d.ts +0 -18
- package/dist/db/utils/reference-resolver.d.ts.map +0 -1
- package/dist/db/utils/reference-resolver.js +0 -80
- package/dist/define.d.ts +0 -3
- package/dist/define.d.ts.map +0 -1
- package/dist/define.js +0 -4
- package/dist/email/index.d.ts +0 -2
- package/dist/email/index.d.ts.map +0 -1
- package/dist/email/interfaces/email.d.ts +0 -42
- package/dist/email/interfaces/email.d.ts.map +0 -1
- package/dist/email/interfaces/email.js +0 -1
- package/dist/engine.d.ts +0 -26
- package/dist/engine.d.ts.map +0 -1
- package/dist/engine.js +0 -66
- package/dist/field-validation/rule.d.ts +0 -51
- package/dist/field-validation/rule.d.ts.map +0 -1
- package/dist/field-validation/rule.js +0 -221
- package/dist/field-validation/utils.d.ts +0 -21
- package/dist/field-validation/utils.d.ts.map +0 -1
- package/dist/field-validation/utils.js +0 -66
- package/dist/hooks.d.ts +0 -23
- package/dist/hooks.d.ts.map +0 -1
- package/dist/hooks.js +0 -96
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/is-mobile.svelte.d.ts +0 -5
- package/dist/is-mobile.svelte.d.ts.map +0 -1
- package/dist/routes/assets-by-id.d.ts +0 -5
- package/dist/routes/assets-by-id.d.ts.map +0 -1
- package/dist/routes/assets-by-id.js +0 -138
- package/dist/routes/assets-cdn.d.ts +0 -3
- package/dist/routes/assets-cdn.d.ts.map +0 -1
- package/dist/routes/assets-cdn.js +0 -155
- package/dist/routes/assets.d.ts +0 -4
- package/dist/routes/assets.d.ts.map +0 -1
- package/dist/routes/assets.js +0 -94
- package/dist/routes/documents-by-id.d.ts +0 -5
- package/dist/routes/documents-by-id.d.ts.map +0 -1
- package/dist/routes/documents-by-id.js +0 -142
- package/dist/routes/documents-publish.d.ts +0 -4
- package/dist/routes/documents-publish.d.ts.map +0 -1
- package/dist/routes/documents-publish.js +0 -151
- package/dist/routes/documents.d.ts +0 -4
- package/dist/routes/documents.d.ts.map +0 -1
- package/dist/routes/documents.js +0 -131
- package/dist/routes/index.d.ts +0 -6
- package/dist/routes/index.d.ts.map +0 -1
- package/dist/routes/index.js +0 -10
- package/dist/routes/organizations-by-id.d.ts +0 -5
- package/dist/routes/organizations-by-id.d.ts.map +0 -1
- package/dist/routes/organizations-by-id.js +0 -187
- package/dist/routes/organizations-invitations.d.ts +0 -4
- package/dist/routes/organizations-invitations.d.ts.map +0 -1
- package/dist/routes/organizations-invitations.js +0 -125
- package/dist/routes/organizations-members.d.ts +0 -5
- package/dist/routes/organizations-members.d.ts.map +0 -1
- package/dist/routes/organizations-members.js +0 -206
- package/dist/routes/organizations-switch.d.ts +0 -3
- package/dist/routes/organizations-switch.d.ts.map +0 -1
- package/dist/routes/organizations-switch.js +0 -53
- package/dist/routes/organizations.d.ts +0 -4
- package/dist/routes/organizations.d.ts.map +0 -1
- package/dist/routes/organizations.js +0 -108
- package/dist/routes/schemas-by-type.d.ts +0 -3
- package/dist/routes/schemas-by-type.d.ts.map +0 -1
- package/dist/routes/schemas-by-type.js +0 -25
- package/dist/routes/schemas.d.ts +0 -3
- package/dist/routes/schemas.d.ts.map +0 -1
- package/dist/routes/schemas.js +0 -11
- package/dist/routes-exports.d.ts +0 -14
- package/dist/routes-exports.d.ts.map +0 -1
- package/dist/schema-context.svelte.d.ts +0 -10
- package/dist/schema-context.svelte.d.ts.map +0 -1
- package/dist/schema-context.svelte.js +0 -18
- package/dist/schema-utils/cleanup.d.ts +0 -21
- package/dist/schema-utils/cleanup.d.ts.map +0 -1
- package/dist/schema-utils/cleanup.js +0 -80
- package/dist/schema-utils/index.d.ts +0 -4
- package/dist/schema-utils/index.d.ts.map +0 -1
- package/dist/schema-utils/index.js +0 -4
- package/dist/schema-utils/utils.d.ts +0 -30
- package/dist/schema-utils/utils.d.ts.map +0 -1
- package/dist/schema-utils/utils.js +0 -37
- package/dist/schema-utils/validator.d.ts +0 -6
- package/dist/schema-utils/validator.d.ts.map +0 -1
- package/dist/schema-utils/validator.js +0 -45
- package/dist/server/index.d.ts +0 -16
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/index.js +0 -28
- package/dist/services/asset-service.d.ts +0 -86
- package/dist/services/asset-service.d.ts.map +0 -1
- package/dist/services/asset-service.js +0 -187
- package/dist/services/index.d.ts +0 -3
- package/dist/services/index.d.ts.map +0 -1
- package/dist/services/index.js +0 -4
- package/dist/storage/adapters/index.d.ts +0 -2
- package/dist/storage/adapters/index.d.ts.map +0 -1
- package/dist/storage/adapters/index.js +0 -2
- package/dist/storage/adapters/local-storage-adapter.d.ts +0 -54
- package/dist/storage/adapters/local-storage-adapter.d.ts.map +0 -1
- package/dist/storage/adapters/local-storage-adapter.js +0 -187
- package/dist/storage/index.d.ts +0 -3
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/interfaces/index.d.ts +0 -2
- package/dist/storage/interfaces/index.d.ts.map +0 -1
- package/dist/storage/interfaces/index.js +0 -2
- package/dist/storage/interfaces/storage.d.ts +0 -91
- package/dist/storage/interfaces/storage.d.ts.map +0 -1
- package/dist/storage/interfaces/storage.js +0 -1
- package/dist/storage/providers/storage.d.ts +0 -43
- package/dist/storage/providers/storage.d.ts.map +0 -1
- package/dist/storage/providers/storage.js +0 -64
- package/dist/types/asset.d.ts +0 -73
- package/dist/types/asset.d.ts.map +0 -1
- package/dist/types/asset.js +0 -2
- package/dist/types/auth.d.ts +0 -50
- package/dist/types/auth.d.ts.map +0 -1
- package/dist/types/auth.js +0 -41
- package/dist/types/config.d.ts +0 -47
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/config.js +0 -1
- package/dist/types/document.d.ts +0 -34
- package/dist/types/document.d.ts.map +0 -1
- package/dist/types/document.js +0 -1
- package/dist/types/index.d.ts +0 -9
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -8
- package/dist/types/organization.d.ts +0 -105
- package/dist/types/organization.d.ts.map +0 -1
- package/dist/types/organization.js +0 -3
- package/dist/types/schemas.d.ts +0 -114
- package/dist/types/schemas.d.ts.map +0 -1
- package/dist/types/schemas.js +0 -1
- package/dist/types/sidebar.d.ts +0 -33
- package/dist/types/sidebar.d.ts.map +0 -1
- package/dist/types/sidebar.js +0 -1
- package/dist/types/user.d.ts +0 -14
- package/dist/types/user.d.ts.map +0 -1
- package/dist/types/user.js +0 -1
- package/dist/utils/content-hash.d.ts +0 -22
- package/dist/utils/content-hash.d.ts.map +0 -1
- package/dist/utils/content-hash.js +0 -67
- package/dist/utils/image-url.d.ts +0 -88
- package/dist/utils/image-url.d.ts.map +0 -1
- package/dist/utils/image-url.js +0 -165
- package/dist/utils/index.d.ts +0 -6
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -9
- package/dist/utils/slug.d.ts +0 -13
- package/dist/utils/slug.d.ts.map +0 -1
- package/dist/utils/slug.js +0 -30
- package/dist/utils.d.ts +0 -13
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -5
- /package/{dist → src/lib}/app.d.ts +0 -0
- /package/{dist → src/lib}/auth/MULTI_TENANCY_PLAN.md +0 -0
- /package/{dist → src/lib}/components/admin/AdminLayout.svelte +0 -0
- /package/{dist → src/lib}/components/admin/DocumentTypesList.svelte +0 -0
- /package/{dist → src/lib}/components/admin/ObjectModal.svelte +0 -0
- /package/{dist/components/fields/index.js → src/lib/components/fields/index.ts} +0 -0
- /package/{dist → src/lib}/components/layout/sidebar/NavMain.svelte +0 -0
- /package/{dist → src/lib}/components/layout/sidebar/NavSecondary.svelte +0 -0
- /package/{dist → src/lib}/plugins/README.md +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { SchemaType, Field, ArrayField } from '../types/schemas';
|
|
2
|
+
|
|
3
|
+
export interface OrphanedField {
|
|
4
|
+
path: string;
|
|
5
|
+
key: string;
|
|
6
|
+
value: any;
|
|
7
|
+
level: 'document' | 'nested';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface SchemaCleanupResult {
|
|
11
|
+
hasOrphanedFields: boolean;
|
|
12
|
+
orphanedFields: OrphanedField[];
|
|
13
|
+
cleanedData: Record<string, any>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Find orphaned fields in document data that no longer exist in the schema
|
|
18
|
+
*/
|
|
19
|
+
export function findOrphanedFields(
|
|
20
|
+
documentData: Record<string, any>,
|
|
21
|
+
schema: SchemaType
|
|
22
|
+
): SchemaCleanupResult {
|
|
23
|
+
const orphanedFields: OrphanedField[] = [];
|
|
24
|
+
|
|
25
|
+
function checkObject(
|
|
26
|
+
obj: Record<string, any>,
|
|
27
|
+
fields: Field[],
|
|
28
|
+
pathPrefix = ''
|
|
29
|
+
): Record<string, any> {
|
|
30
|
+
const cleaned: Record<string, any> = {};
|
|
31
|
+
const fieldMap = new Map(fields.map((field) => [field.name, field]));
|
|
32
|
+
|
|
33
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
34
|
+
const currentPath = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
35
|
+
const field = fieldMap.get(key);
|
|
36
|
+
|
|
37
|
+
if (!field) {
|
|
38
|
+
// Orphaned field found
|
|
39
|
+
orphanedFields.push({
|
|
40
|
+
path: currentPath,
|
|
41
|
+
key,
|
|
42
|
+
value,
|
|
43
|
+
level: pathPrefix ? 'nested' : 'document'
|
|
44
|
+
});
|
|
45
|
+
continue; // Skip this field in cleaned data
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Recursively check nested objects and arrays
|
|
49
|
+
if (field.type === 'object' && field.fields && value && typeof value === 'object') {
|
|
50
|
+
cleaned[key] = checkObject(value, field.fields, currentPath);
|
|
51
|
+
} else if (field.type === 'array' && Array.isArray(value)) {
|
|
52
|
+
cleaned[key] = checkArray(value, field, currentPath);
|
|
53
|
+
} else {
|
|
54
|
+
cleaned[key] = value;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return cleaned;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function checkArray(array: any[], arrayField: Field, pathPrefix: string): any[] {
|
|
62
|
+
if (arrayField.type !== 'array' || !arrayField.of) {
|
|
63
|
+
return array;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return array.map((item, index) => {
|
|
67
|
+
const itemPath = `${pathPrefix}[${index}]`;
|
|
68
|
+
|
|
69
|
+
if (item && typeof item === 'object' && item._type) {
|
|
70
|
+
// Find the schema for this array item type
|
|
71
|
+
const itemTypeSchema = getSchemaForArrayItem(item._type, arrayField);
|
|
72
|
+
if (itemTypeSchema && itemTypeSchema.fields) {
|
|
73
|
+
return checkObject(item, itemTypeSchema.fields, itemPath);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return item;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const cleanedData = checkObject(documentData, schema.fields);
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
hasOrphanedFields: orphanedFields.length > 0,
|
|
85
|
+
orphanedFields,
|
|
86
|
+
cleanedData
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get the schema for an array item type (helper function)
|
|
92
|
+
* This would need to be integrated with your schema registry
|
|
93
|
+
*/
|
|
94
|
+
function getSchemaForArrayItem(typeName: string, arrayField: ArrayField): SchemaType | null {
|
|
95
|
+
// This is a placeholder - you'd need to integrate with your actual schema registry
|
|
96
|
+
// For now, we'll assume inline object schemas
|
|
97
|
+
if (arrayField.of) {
|
|
98
|
+
const typeRef = arrayField.of.find((ref) => ref.type === typeName);
|
|
99
|
+
if (typeRef && typeof typeRef !== 'string') {
|
|
100
|
+
// Handle inline schema definitions if needed
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Apply cleanup by removing orphaned fields from document data
|
|
109
|
+
*/
|
|
110
|
+
export function applySchemaCleanup(
|
|
111
|
+
documentData: Record<string, any>,
|
|
112
|
+
schema: SchemaType
|
|
113
|
+
): Record<string, any> {
|
|
114
|
+
const result = findOrphanedFields(documentData, schema);
|
|
115
|
+
return result.cleanedData;
|
|
116
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { SchemaType } from '../types/schemas';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Schema utility functions that work with a schema registry
|
|
5
|
+
* These functions accept schemas as parameters to avoid package-level dependencies
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get a schema type by name from a collection of schemas
|
|
10
|
+
*/
|
|
11
|
+
export function getSchemaByName(schemas: SchemaType[], name: string): SchemaType | null {
|
|
12
|
+
return schemas.find((schema) => schema.name === name) || null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get all available object types (for array field dropdowns)
|
|
17
|
+
*/
|
|
18
|
+
export function getObjectTypes(schemas: SchemaType[]): SchemaType[] {
|
|
19
|
+
return schemas.filter((schema) => schema.type === 'object');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get all available document types
|
|
24
|
+
*/
|
|
25
|
+
export function getDocumentTypes(schemas: SchemaType[]): SchemaType[] {
|
|
26
|
+
return schemas.filter((schema) => schema.type === 'document');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check if a schema type exists
|
|
31
|
+
*/
|
|
32
|
+
export function schemaExists(schemas: SchemaType[], name: string): boolean {
|
|
33
|
+
return schemas.some((schema) => schema.name === name);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the available types for an array field
|
|
38
|
+
*/
|
|
39
|
+
export function getArrayTypes(
|
|
40
|
+
schemas: SchemaType[],
|
|
41
|
+
arrayField: { of?: Array<{ type: string }> }
|
|
42
|
+
): SchemaType[] {
|
|
43
|
+
if (!arrayField.of) return [];
|
|
44
|
+
|
|
45
|
+
const typeNames = arrayField.of.map((item) => item.type);
|
|
46
|
+
return schemas.filter((schema) => typeNames.includes(schema.name));
|
|
47
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { SchemaType, Field } from '../types/schemas';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validate all schema references to ensure they exist
|
|
5
|
+
*/
|
|
6
|
+
export function validateSchemaReferences(schemas: SchemaType[]): void {
|
|
7
|
+
const schemaNames = new Set(schemas.map((schema) => schema.name));
|
|
8
|
+
const errors: string[] = [];
|
|
9
|
+
|
|
10
|
+
function validateField(field: Field, parentSchema: string): void {
|
|
11
|
+
// Check array field references
|
|
12
|
+
if (field.type === 'array' && field.of) {
|
|
13
|
+
for (const arrayType of field.of) {
|
|
14
|
+
if (!schemaNames.has(arrayType.type)) {
|
|
15
|
+
errors.push(
|
|
16
|
+
`Schema "${parentSchema}" field "${field.name}" references unknown type "${arrayType.type}"`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Check object field references (if they reference external types)
|
|
23
|
+
if (field.type === 'object' && typeof field.fields === 'string') {
|
|
24
|
+
if (!schemaNames.has(field.fields)) {
|
|
25
|
+
errors.push(
|
|
26
|
+
`Schema "${parentSchema}" field "${field.name}" references unknown object type "${field.fields}"`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Recursively check nested fields -- cast type later or something. cba
|
|
32
|
+
if ('fields' in field && Array.isArray(field.fields)) {
|
|
33
|
+
for (const nestedField of field.fields) {
|
|
34
|
+
validateField(nestedField, parentSchema);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Validate each schema
|
|
40
|
+
for (const schema of schemas) {
|
|
41
|
+
if (schema.fields) {
|
|
42
|
+
for (const field of schema.fields) {
|
|
43
|
+
validateField(field, schema.name);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Throw error if any validation issues found
|
|
49
|
+
if (errors.length > 0) {
|
|
50
|
+
console.error('\nSchema Validation Errors:');
|
|
51
|
+
errors.forEach((error) => console.error(error));
|
|
52
|
+
|
|
53
|
+
// Just throw the errors directly
|
|
54
|
+
throw new Error(errors.join('\n'));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log('✅ Schema validation passed - all references are valid');
|
|
58
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Aphex CMS Core - Server-side exports
|
|
2
|
+
// These require Node.js and should NOT be imported client-side
|
|
3
|
+
|
|
4
|
+
// Export all core types from the new central location
|
|
5
|
+
export * from '../types/index';
|
|
6
|
+
|
|
7
|
+
export * from '../auth/provider';
|
|
8
|
+
|
|
9
|
+
export * from '../email/index';
|
|
10
|
+
|
|
11
|
+
// Authentication errors
|
|
12
|
+
export { AuthError, type AuthErrorCode } from '../auth/auth-errors';
|
|
13
|
+
|
|
14
|
+
// Configuration system
|
|
15
|
+
export { createCMSConfig } from '../config';
|
|
16
|
+
|
|
17
|
+
// Hooks integration (SvelteKit server hooks)
|
|
18
|
+
export { createCMSHook, type CMSInstances } from '../hooks';
|
|
19
|
+
|
|
20
|
+
// Database interfaces (no longer export registry or adapters - use adapter packages)
|
|
21
|
+
export * from '../db/interfaces/index';
|
|
22
|
+
|
|
23
|
+
// Storage adapters and interfaces
|
|
24
|
+
export * from '../storage/index';
|
|
25
|
+
export * from '../storage/interfaces/index';
|
|
26
|
+
export * from '../storage/providers/storage';
|
|
27
|
+
|
|
28
|
+
// Services (includes sharp for image processing)
|
|
29
|
+
export * from '../services/index';
|
|
30
|
+
export { AssetService } from '../services/asset-service';
|
|
31
|
+
|
|
32
|
+
// API Route handlers (for re-exporting in your app's API routes)
|
|
33
|
+
// Re-export from routes-exports to avoid .js extension issues in workspace
|
|
34
|
+
export * from '../routes-exports';
|
|
35
|
+
|
|
36
|
+
// Schema utilities
|
|
37
|
+
export * from '../schema-utils/index';
|
|
38
|
+
|
|
39
|
+
// Content hash utilities (server-side)
|
|
40
|
+
export { createHashForPublishing } from '../utils/content-hash';
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// Asset service - orchestrates storage and database operations
|
|
2
|
+
import sharp from 'sharp';
|
|
3
|
+
import type { StorageAdapter } from '../storage/interfaces/storage';
|
|
4
|
+
import type { DatabaseAdapter } from '../db/interfaces/index';
|
|
5
|
+
import type { Asset } from '../types/index';
|
|
6
|
+
|
|
7
|
+
export interface AssetUploadData {
|
|
8
|
+
buffer: Buffer;
|
|
9
|
+
originalFilename: string;
|
|
10
|
+
mimeType: string;
|
|
11
|
+
size: number;
|
|
12
|
+
title?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
alt?: string;
|
|
15
|
+
creditLine?: string;
|
|
16
|
+
createdBy?: string; // User ID who uploaded this asset
|
|
17
|
+
metadata?: {
|
|
18
|
+
schemaType?: string; // e.g., 'newsletterLanding'
|
|
19
|
+
fieldPath?: string; // e.g., 'logo' or 'seo.metaImage'
|
|
20
|
+
[key: string]: any; // Allow additional metadata
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface AssetFilters {
|
|
25
|
+
assetType?: 'image' | 'file';
|
|
26
|
+
mimeType?: string;
|
|
27
|
+
search?: string;
|
|
28
|
+
limit?: number;
|
|
29
|
+
offset?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Asset service - coordinates storage and database operations
|
|
34
|
+
* Maintains separation of concerns while providing unified asset management
|
|
35
|
+
*/
|
|
36
|
+
export class AssetService {
|
|
37
|
+
constructor(
|
|
38
|
+
private storage: StorageAdapter,
|
|
39
|
+
private database: DatabaseAdapter
|
|
40
|
+
) {}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Upload and store an asset
|
|
44
|
+
*/
|
|
45
|
+
async uploadAsset(organizationId: string, data: AssetUploadData): Promise<Asset> {
|
|
46
|
+
// Determine asset type
|
|
47
|
+
const assetType = data.mimeType.startsWith('image/') ? 'image' : 'file';
|
|
48
|
+
|
|
49
|
+
// Extract image metadata if it's an image
|
|
50
|
+
let width: number | undefined;
|
|
51
|
+
let height: number | undefined;
|
|
52
|
+
let metadata: any = {
|
|
53
|
+
// Include field metadata for privacy checking
|
|
54
|
+
...data.metadata
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
if (assetType === 'image') {
|
|
58
|
+
try {
|
|
59
|
+
const imageMetadata = await sharp(data.buffer).metadata();
|
|
60
|
+
width = imageMetadata.width;
|
|
61
|
+
height = imageMetadata.height;
|
|
62
|
+
|
|
63
|
+
// Merge image metadata with field metadata
|
|
64
|
+
metadata = {
|
|
65
|
+
...metadata, // Keep schemaType and fieldPath
|
|
66
|
+
format: imageMetadata.format,
|
|
67
|
+
space: imageMetadata.space,
|
|
68
|
+
channels: imageMetadata.channels,
|
|
69
|
+
density: imageMetadata.density,
|
|
70
|
+
hasProfile: imageMetadata.hasProfile,
|
|
71
|
+
hasAlpha: imageMetadata.hasAlpha
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Add dominant color
|
|
75
|
+
const stats = await sharp(data.buffer).stats();
|
|
76
|
+
metadata.dominantColor = stats.dominant;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.warn('Could not extract image metadata:', error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 1. Store file using storage adapter
|
|
83
|
+
const storageFile = await this.storage.store({
|
|
84
|
+
buffer: data.buffer,
|
|
85
|
+
filename: data.originalFilename,
|
|
86
|
+
mimeType: data.mimeType,
|
|
87
|
+
size: data.size
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// 2. Save asset metadata using database adapter
|
|
91
|
+
try {
|
|
92
|
+
const asset = await this.database.createAsset({
|
|
93
|
+
assetType,
|
|
94
|
+
filename: storageFile.path.split('/').pop() || data.originalFilename,
|
|
95
|
+
originalFilename: data.originalFilename,
|
|
96
|
+
mimeType: data.mimeType,
|
|
97
|
+
size: data.size,
|
|
98
|
+
url: storageFile.url || '', // Empty for local storage initially
|
|
99
|
+
path: storageFile.path,
|
|
100
|
+
storageAdapter: this.storage.name,
|
|
101
|
+
organizationId,
|
|
102
|
+
width,
|
|
103
|
+
height,
|
|
104
|
+
metadata,
|
|
105
|
+
title: data.title || undefined,
|
|
106
|
+
description: data.description || undefined,
|
|
107
|
+
alt: data.alt || undefined,
|
|
108
|
+
creditLine: data.creditLine || undefined,
|
|
109
|
+
createdBy: data.createdBy
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// If using local storage, generate and store the CDN URL with the real asset ID
|
|
113
|
+
if (!storageFile.url) {
|
|
114
|
+
const cdnUrl = `/media/${asset.id}/${encodeURIComponent(asset.originalFilename)}`;
|
|
115
|
+
|
|
116
|
+
// Update both the object and the database
|
|
117
|
+
asset.url = cdnUrl;
|
|
118
|
+
await this.database.updateAsset(organizationId, asset.id, { url: cdnUrl });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return asset;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
// If database save fails, clean up the stored file
|
|
124
|
+
await this.storage.delete(storageFile.path);
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Find asset by ID
|
|
131
|
+
*/
|
|
132
|
+
async findAssetById(organizationId: string, id: string): Promise<Asset | null> {
|
|
133
|
+
return await this.database.findAssetById(organizationId, id);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Find asset by ID globally (bypasses organization filter for public asset access)
|
|
138
|
+
* Only available on PostgreSQL adapter with RLS bypass
|
|
139
|
+
*/
|
|
140
|
+
async findAssetByIdGlobal(id: string): Promise<Asset | null> {
|
|
141
|
+
// Check if the adapter has the global method
|
|
142
|
+
if (
|
|
143
|
+
'findAssetByIdGlobal' in this.database &&
|
|
144
|
+
typeof this.database.findAssetByIdGlobal === 'function'
|
|
145
|
+
) {
|
|
146
|
+
console.log('[AssetService] Using findAssetByIdGlobal from adapter');
|
|
147
|
+
return await this.database.findAssetByIdGlobal(id);
|
|
148
|
+
}
|
|
149
|
+
// Fallback: not supported
|
|
150
|
+
console.warn('[AssetService] findAssetByIdGlobal not supported by this database adapter');
|
|
151
|
+
console.warn('[AssetService] Database adapter type:', this.database.constructor.name);
|
|
152
|
+
console.warn(
|
|
153
|
+
'[AssetService] Available methods:',
|
|
154
|
+
Object.getOwnPropertyNames(Object.getPrototypeOf(this.database))
|
|
155
|
+
);
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Find multiple assets with filtering
|
|
161
|
+
*/
|
|
162
|
+
async findAssets(organizationId: string, filters: AssetFilters = {}): Promise<Asset[]> {
|
|
163
|
+
return await this.database.findAssets(organizationId, filters);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Delete asset (both file and database record)
|
|
168
|
+
*
|
|
169
|
+
* Note: If the asset was stored by a different adapter (e.g., switching from R2 to local),
|
|
170
|
+
* file deletion may fail. The database record will still be removed for a clean state.
|
|
171
|
+
*/
|
|
172
|
+
async deleteAsset(organizationId: string, id: string): Promise<boolean> {
|
|
173
|
+
const asset = await this.database.findAssetById(organizationId, id);
|
|
174
|
+
if (!asset) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Try to delete file from storage
|
|
179
|
+
// If the asset was stored by a different adapter, this may fail
|
|
180
|
+
if (asset.storageAdapter === this.storage.name) {
|
|
181
|
+
// Same adapter - delete should work
|
|
182
|
+
try {
|
|
183
|
+
await this.storage.delete(asset.path);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.warn(`Failed to delete file from storage: ${asset.path}`, error);
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
// Different adapter - log warning but continue with database cleanup
|
|
189
|
+
console.warn(
|
|
190
|
+
`Asset ${id} was stored by '${asset.storageAdapter}' but current adapter is '${this.storage.name}'. ` +
|
|
191
|
+
`File at ${asset.path} may need manual cleanup.`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Always delete database record for clean state
|
|
196
|
+
return await this.database.deleteAsset(organizationId, id);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Update asset metadata
|
|
201
|
+
*/
|
|
202
|
+
async updateAssetMetadata(
|
|
203
|
+
organizationId: string,
|
|
204
|
+
id: string,
|
|
205
|
+
metadata: {
|
|
206
|
+
title?: string;
|
|
207
|
+
description?: string;
|
|
208
|
+
alt?: string;
|
|
209
|
+
creditLine?: string;
|
|
210
|
+
updatedBy?: string; // User ID who updated this asset
|
|
211
|
+
}
|
|
212
|
+
): Promise<Asset | null> {
|
|
213
|
+
return await this.database.updateAsset(organizationId, id, metadata);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get asset statistics
|
|
218
|
+
*/
|
|
219
|
+
async getAssetStats(organizationId: string): Promise<{
|
|
220
|
+
totalAssets: number;
|
|
221
|
+
totalImages: number;
|
|
222
|
+
totalFiles: number;
|
|
223
|
+
totalSize: number;
|
|
224
|
+
}> {
|
|
225
|
+
const [totalAssets, assetsByType, totalSize] = await Promise.all([
|
|
226
|
+
this.database.countAssets(organizationId),
|
|
227
|
+
this.database.countAssetsByType(organizationId),
|
|
228
|
+
this.database.getTotalAssetsSize(organizationId)
|
|
229
|
+
]);
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
totalAssets,
|
|
233
|
+
totalImages: assetsByType.image || 0,
|
|
234
|
+
totalFiles: assetsByType.file || 0,
|
|
235
|
+
totalSize
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Get health status of both storage and database
|
|
241
|
+
*/
|
|
242
|
+
async getHealthStatus(): Promise<{
|
|
243
|
+
storage: boolean;
|
|
244
|
+
database: boolean;
|
|
245
|
+
}> {
|
|
246
|
+
const [storageHealthy, databaseHealthy] = await Promise.all([
|
|
247
|
+
this.storage.isHealthy(),
|
|
248
|
+
this.database.isHealthy()
|
|
249
|
+
]);
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
storage: storageHealthy,
|
|
253
|
+
database: databaseHealthy
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|