@aphexcms/cms-core 0.1.12 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/LICENSE +21 -0
  2. package/dist/api/documents.d.ts +1 -0
  3. package/dist/api/documents.d.ts.map +1 -1
  4. package/dist/api/documents.js +9 -1
  5. package/dist/api/types.d.ts +24 -2
  6. package/dist/api/types.d.ts.map +1 -1
  7. package/dist/auth/auth-hooks.d.ts.map +1 -1
  8. package/dist/auth/auth-hooks.js +18 -4
  9. package/dist/cli/generate-types.js +218 -0
  10. package/dist/cli/index.js +86 -0
  11. package/dist/components/AdminApp.svelte +26 -55
  12. package/dist/components/AdminApp.svelte.d.ts +3 -5
  13. package/dist/components/AdminApp.svelte.d.ts.map +1 -1
  14. package/dist/components/admin/DocumentEditor.svelte +60 -14
  15. package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
  16. package/dist/components/admin/fields/ReferenceField.svelte +2 -3
  17. package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
  18. package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts +8 -1
  19. package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts.map +1 -1
  20. package/dist/db/interfaces/asset.d.ts +22 -0
  21. package/dist/db/interfaces/asset.d.ts.map +1 -1
  22. package/dist/db/interfaces/document.d.ts +25 -0
  23. package/dist/db/interfaces/document.d.ts.map +1 -1
  24. package/dist/field-validation/utils.d.ts +19 -1
  25. package/dist/field-validation/utils.d.ts.map +1 -1
  26. package/dist/field-validation/utils.js +33 -0
  27. package/dist/hooks.d.ts +2 -0
  28. package/dist/hooks.d.ts.map +1 -1
  29. package/dist/hooks.js +80 -12
  30. package/dist/lib/auth/provider.js +1 -0
  31. package/dist/lib/db/index.js +4 -0
  32. package/dist/lib/db/interfaces/asset.js +1 -0
  33. package/dist/lib/db/interfaces/document.js +1 -0
  34. package/dist/lib/db/interfaces/index.js +1 -0
  35. package/dist/lib/db/interfaces/organization.js +1 -0
  36. package/dist/lib/db/interfaces/schema.js +1 -0
  37. package/dist/lib/db/interfaces/user.js +1 -0
  38. package/dist/lib/email/index.js +4 -0
  39. package/dist/lib/email/interfaces/email.js +1 -0
  40. package/dist/lib/field-validation/rule.js +221 -0
  41. package/dist/lib/field-validation/utils.js +99 -0
  42. package/dist/lib/storage/interfaces/index.js +2 -0
  43. package/dist/lib/storage/interfaces/storage.js +1 -0
  44. package/dist/lib/types/asset.js +2 -0
  45. package/dist/lib/types/auth.js +41 -0
  46. package/dist/lib/types/config.js +1 -0
  47. package/dist/lib/types/document.js +1 -0
  48. package/dist/lib/types/filters.js +5 -0
  49. package/dist/lib/types/index.js +9 -0
  50. package/dist/lib/types/organization.js +3 -0
  51. package/dist/lib/types/schemas.js +1 -0
  52. package/dist/lib/types/sidebar.js +1 -0
  53. package/dist/lib/types/user.js +1 -0
  54. package/dist/local-api/auth-helpers.d.ts +65 -0
  55. package/dist/local-api/auth-helpers.d.ts.map +1 -0
  56. package/dist/local-api/auth-helpers.js +102 -0
  57. package/dist/local-api/collection-api.d.ts +138 -0
  58. package/dist/local-api/collection-api.d.ts.map +1 -0
  59. package/dist/local-api/collection-api.js +276 -0
  60. package/dist/local-api/index.d.ts +108 -0
  61. package/dist/local-api/index.d.ts.map +1 -0
  62. package/dist/local-api/index.js +157 -0
  63. package/dist/local-api/permissions.d.ts +45 -0
  64. package/dist/local-api/permissions.d.ts.map +1 -0
  65. package/dist/local-api/permissions.js +117 -0
  66. package/dist/local-api/types.d.ts +65 -0
  67. package/dist/local-api/types.d.ts.map +1 -0
  68. package/dist/local-api/types.js +4 -0
  69. package/dist/routes/documents-by-id.d.ts.map +1 -1
  70. package/dist/routes/documents-by-id.js +84 -63
  71. package/dist/routes/documents-publish.d.ts.map +1 -1
  72. package/dist/routes/documents-publish.js +57 -72
  73. package/dist/routes/documents-query.d.ts +24 -0
  74. package/dist/routes/documents-query.d.ts.map +1 -0
  75. package/dist/routes/documents-query.js +95 -0
  76. package/dist/routes/documents.d.ts.map +1 -1
  77. package/dist/routes/documents.js +80 -75
  78. package/dist/routes/index.d.ts +2 -0
  79. package/dist/routes/index.d.ts.map +1 -1
  80. package/dist/routes/index.js +2 -0
  81. package/dist/server/index.d.ts +1 -0
  82. package/dist/server/index.d.ts.map +1 -1
  83. package/dist/server/index.js +2 -0
  84. package/dist/types/config.d.ts +18 -1
  85. package/dist/types/config.d.ts.map +1 -1
  86. package/dist/types/document.d.ts +1 -0
  87. package/dist/types/document.d.ts.map +1 -1
  88. package/dist/types/filters.d.ts +173 -0
  89. package/dist/types/filters.d.ts.map +1 -0
  90. package/dist/types/filters.js +5 -0
  91. package/dist/types/index.d.ts +1 -0
  92. package/dist/types/index.d.ts.map +1 -1
  93. package/dist/types/index.js +1 -0
  94. package/dist/types/schemas.d.ts +0 -5
  95. package/dist/types/schemas.d.ts.map +1 -1
  96. package/package.json +101 -95
@@ -73,7 +73,7 @@
73
73
 
74
74
  // Hash-based state tracking
75
75
  const hasUnpublishedContent = $derived(
76
- hasUnpublishedChanges(documentData, fullDocument?.publishedHash || null)
76
+ hasUnpublishedChanges(documentData, fullDocument?._meta?.publishedHash || null)
77
77
  );
78
78
  const canPublish = $derived(
79
79
  hasUnpublishedContent && !saving && documentId && !hasValidationErrors
@@ -198,15 +198,20 @@
198
198
  // Store full document for hash comparison
199
199
  fullDocument = response.data;
200
200
 
201
- // Load the draft data if available, otherwise published data
202
- const data = response.data.draftData || response.data.publishedData || {};
203
- console.log('📄 Loaded document data:', data);
204
- console.log('📄 Published hash:', response.data.publishedHash);
201
+ // With LocalAPI, data is flattened at top level (not in draftData)
202
+ // Extract all fields except id and _meta
203
+ const { id, _meta, ...data } = response.data;
204
+ console.log('📄 Full response.data:', response.data);
205
+ console.log('📄 Extracted data (after destructuring):', data);
206
+ console.log('📄 Keys in extracted data:', Object.keys(data));
207
+ console.log('📄 Published hash:', _meta?.publishedHash);
205
208
 
206
209
  documentData = { ...data };
210
+ console.log('📄 documentData after assignment:', documentData);
211
+ console.log('📄 Keys in documentData:', Object.keys(documentData));
207
212
  hasUnsavedChanges = false; // Just loaded, so no unsaved changes
208
213
  } else {
209
- console.error('❌ Failed to load document data:', response.error);
214
+ console.log('❌ Failed to load document data:', response.error);
210
215
  saveError = response.error || 'Failed to load document';
211
216
  }
212
217
  } catch (err) {
@@ -249,13 +254,47 @@
249
254
  });
250
255
  }
251
256
 
257
+ // Check if current data differs from last saved draft
258
+ function hasChangesFromSaved(): boolean {
259
+ if (!fullDocument) return true; // No saved version = has changes
260
+
261
+ // Extract saved draft data from fullDocument (same as we do in loadDocumentData)
262
+ const { id, _meta, ...savedData } = fullDocument;
263
+
264
+ // Compare current documentData with saved data using stable JSON
265
+ const currentJson = JSON.stringify(sortObjectForComparison(documentData));
266
+ const savedJson = JSON.stringify(sortObjectForComparison(savedData));
267
+
268
+ return currentJson !== savedJson;
269
+ }
270
+
271
+ // Helper to recursively sort object keys for stable comparison
272
+ function sortObjectForComparison(item: any): any {
273
+ if (item === null || typeof item !== 'object') return item;
274
+
275
+ if (Array.isArray(item)) {
276
+ return item.map(sortObjectForComparison);
277
+ }
278
+
279
+ const sortedKeys = Object.keys(item).sort();
280
+ const sortedObj: any = {};
281
+ for (const key of sortedKeys) {
282
+ sortedObj[key] = sortObjectForComparison(item[key]);
283
+ }
284
+ return sortedObj;
285
+ }
286
+
252
287
  // Watch for changes to trigger auto-save (debounced)
253
288
  $effect(() => {
254
289
  const hasContent = hasMeaningfulContent(documentData);
290
+ const hasChanges = hasChangesFromSaved();
255
291
 
256
- // Only set hasUnsavedChanges if we actually have meaningful data
257
- if (hasContent) {
292
+ // Only set hasUnsavedChanges if we actually have meaningful data AND it differs from saved
293
+ if (hasContent && hasChanges) {
258
294
  hasUnsavedChanges = true;
295
+ } else if (!hasChanges) {
296
+ // If there are no changes from saved, mark as not having unsaved changes
297
+ hasUnsavedChanges = false;
259
298
  }
260
299
 
261
300
  if (autoSaveTimer) {
@@ -263,12 +302,14 @@
263
302
  }
264
303
 
265
304
  // Debounced auto-save - waits for 800ms pause in typing (like Notion/modern apps)
266
- // Only auto-save if there's meaningful content and not in read-only mode
267
- if (hasContent && schema && !isReadOnly) {
305
+ // Only auto-save if there's meaningful content, data has changed, and not in read-only mode
306
+ if (hasContent && hasChanges && schema && !isReadOnly) {
268
307
  autoSaveTimer = setTimeout(() => {
269
- console.log('🔄 Auto-saving after typing pause...', { documentId });
308
+ console.log('🔄 Auto-saving after typing pause (data changed)...', { documentId });
270
309
  saveDocument(true); // auto-save
271
310
  }, 1200); // Shorter delay - saves faster but still waits for typing pauses
311
+ } else if (!hasChanges) {
312
+ console.log('⏭️ Skipping auto-save - no changes from saved data');
272
313
  }
273
314
 
274
315
  return () => {
@@ -292,11 +333,11 @@
292
333
  // Create new document
293
334
  console.log('🔄 Creating new document with data:', {
294
335
  type: documentType,
295
- draftData: documentData
336
+ data: documentData
296
337
  });
297
338
  response = await documents.create({
298
339
  type: documentType,
299
- draftData: documentData
340
+ data: documentData
300
341
  });
301
342
 
302
343
  console.log('📝 Document creation response:', response);
@@ -315,8 +356,13 @@
315
356
  } else if (documentId) {
316
357
  // Update existing document
317
358
  response = await documents.updateById(documentId, {
318
- draftData: documentData
359
+ data: documentData
319
360
  });
361
+
362
+ // Update fullDocument with the response to keep saved data in sync
363
+ if (response?.success && response.data) {
364
+ fullDocument = response.data;
365
+ }
320
366
  }
321
367
 
322
368
  if (response?.success) {
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentEditor.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentEditor.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAM1D,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAwsBF,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"DocumentEditor.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentEditor.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAM1D,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAsvBF,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -129,9 +129,8 @@
129
129
  }
130
130
 
131
131
  function getDocumentTitle(doc: any): string {
132
- // Try to get title from draft data first, then published data
133
- const data = doc.draftData || doc.publishedData || {};
134
- return data.title || data.name || data.heading || 'Untitled';
132
+ // With LocalAPI, data is flattened at top level
133
+ return doc.title || doc.name || doc.heading || 'Untitled';
135
134
  }
136
135
 
137
136
  const selectedLabel = $derived(selectedDocument ? getDocumentTitle(selectedDocument) : null);
@@ -1 +1 @@
1
- {"version":3,"file":"ReferenceField.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/fields/ReferenceField.svelte.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,KAAK,EAAwC,MAAM,wBAAwB,CAAC;AAIzF,UAAU,KAAK;IACd,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzC,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAoOF,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"ReferenceField.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/fields/ReferenceField.svelte.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,KAAK,EAAwC,MAAM,wBAAwB,CAAC;AAIzF,UAAU,KAAK;IACd,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACzC,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAmOF,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -1,4 +1,11 @@
1
- declare const AppSidebar: import("svelte").Component<any, {}, "">;
1
+ import { Sidebar } from '@aphexcms/ui/shadcn/sidebar';
2
+ import type { SidebarData } from '../../../types/sidebar.js';
3
+ import type { ComponentProps } from 'svelte';
4
+ type Props = ComponentProps<typeof Sidebar> & {
5
+ data: SidebarData;
6
+ onSignOut?: () => void | Promise<void>;
7
+ };
8
+ declare const AppSidebar: import("svelte").Component<Props, {}, "">;
2
9
  type AppSidebar = ReturnType<typeof AppSidebar>;
3
10
  export default AppSidebar;
4
11
  //# sourceMappingURL=AppSidebar.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppSidebar.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/layout/sidebar/AppSidebar.svelte.ts"],"names":[],"mappings":"AAyEA,QAAA,MAAM,UAAU,yCAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"AppSidebar.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/layout/sidebar/AppSidebar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,OAAO,EAKP,MAAM,6BAA6B,CAAC;AAItC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAG5C,KAAK,KAAK,GAAG,cAAc,CAAC,OAAO,OAAO,CAAC,GAAG;IAC7C,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC,CAAC;AAqDH,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import type { Asset } from '../../types/index.js';
2
+ import type { Where, FindOptions, FindResult } from '../../types/filters.js';
2
3
  export interface AssetFilters {
3
4
  organizationId: string;
4
5
  assetType?: 'image' | 'file';
@@ -47,5 +48,26 @@ export interface AssetAdapter {
47
48
  countAssets(organizationId: string): Promise<number>;
48
49
  countAssetsByType(organizationId: string): Promise<Record<string, number>>;
49
50
  getTotalAssetsSize(organizationId: string): Promise<number>;
51
+ /**
52
+ * Find multiple assets with advanced filtering and pagination
53
+ * @param organizationId - Organization ID for multi-tenancy
54
+ * @param options - Advanced filter options (where, limit, offset, sort, etc.)
55
+ * @returns Paginated result with assets and metadata
56
+ */
57
+ findManyAssetsAdvanced(organizationId: string, options?: FindOptions): Promise<FindResult<Asset>>;
58
+ /**
59
+ * Find a single asset by ID
60
+ * @param organizationId - Organization ID for multi-tenancy
61
+ * @param id - Asset ID
62
+ * @returns Asset or null if not found
63
+ */
64
+ findAssetByIdAdvanced(organizationId: string, id: string): Promise<Asset | null>;
65
+ /**
66
+ * Count assets matching a where clause
67
+ * @param organizationId - Organization ID for multi-tenancy
68
+ * @param where - Filter conditions
69
+ * @returns Count of matching assets
70
+ */
71
+ countAssetsAdvanced(organizationId: string, where?: Where): Promise<number>;
50
72
  }
51
73
  //# sourceMappingURL=asset.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/asset.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAE5B,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACnD,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzE,UAAU,CACT,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,CAAC,GAC5C,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACpB,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9F,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAGlE,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3E,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC5D"}
1
+ {"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/asset.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { Document } from '../../types/index.js';
2
+ import type { Where, FindOptions, FindResult } from '../../types/filters.js';
2
3
  export interface DocumentFilters {
3
4
  organizationId: string;
4
5
  type?: string;
@@ -32,5 +33,29 @@ export interface DocumentAdapter {
32
33
  unpublishDoc(organizationId: string, id: string): Promise<Document | null>;
33
34
  countDocsByType(organizationId: string, type: string): Promise<number>;
34
35
  getDocCountsByType(organizationId: string): Promise<Record<string, number>>;
36
+ /**
37
+ * Find multiple documents with advanced filtering and pagination
38
+ * @param organizationId - Organization ID for multi-tenancy
39
+ * @param collectionName - Collection/document type to query
40
+ * @param options - Advanced filter options (where, limit, offset, sort, etc.)
41
+ * @returns Paginated result with documents and metadata
42
+ */
43
+ findManyDocAdvanced(organizationId: string, collectionName: string, options?: FindOptions): Promise<FindResult<Document>>;
44
+ /**
45
+ * Find a single document by ID with advanced options
46
+ * @param organizationId - Organization ID for multi-tenancy
47
+ * @param id - Document ID
48
+ * @param options - Options for depth, select, perspective
49
+ * @returns Document or null if not found
50
+ */
51
+ findByDocIdAdvanced(organizationId: string, id: string, options?: Partial<FindOptions>): Promise<Document | null>;
52
+ /**
53
+ * Count documents matching a where clause
54
+ * @param organizationId - Organization ID for multi-tenancy
55
+ * @param collectionName - Collection/document type to query
56
+ * @param where - Filter conditions
57
+ * @returns Count of matching documents
58
+ */
59
+ countDocuments(organizationId: string, collectionName: string, where?: Where): Promise<number>;
35
60
  }
36
61
  //# sourceMappingURL=document.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/document.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,WAAW,eAAe;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,GAAG,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAE/B,WAAW,CACV,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,gBAAgB,CAAC,GAC/C,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACvB,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC1F,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5D,cAAc,CACb,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,GAAG,EACT,SAAS,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC5B,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAGpE,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACzE,YAAY,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAG3E,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5E"}
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../../src/lib/db/interfaces/document.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,GAAG,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAE/B,WAAW,CACV,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,gBAAgB,CAAC,GAC/C,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACvB,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC1F,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5D,cAAc,CACb,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,GAAG,EACT,SAAS,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC5B,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAGpE,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACzE,YAAY,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAG3E,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAG5E;;;;;;OAMG;IACH,mBAAmB,CAClB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEjC;;;;;;OAMG;IACH,mBAAmB,CAClB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC5B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAE5B;;;;;;OAMG;IACH,cAAc,CACb,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,KAAK,CAAC,EAAE,KAAK,GACX,OAAO,CAAC,MAAM,CAAC,CAAC;CACnB"}
@@ -1,8 +1,15 @@
1
- import type { Field } from '../types/index.js';
1
+ import type { Field, SchemaType } from '../types/index.js';
2
2
  export interface ValidationError {
3
3
  level: 'error' | 'warning' | 'info';
4
4
  message: string;
5
5
  }
6
+ export interface DocumentValidationResult {
7
+ isValid: boolean;
8
+ errors: Array<{
9
+ field: string;
10
+ errors: string[];
11
+ }>;
12
+ }
6
13
  /**
7
14
  * Check if a field is required based on its validation rules
8
15
  */
@@ -18,4 +25,15 @@ export declare function validateField(field: Field, value: any, context?: any):
18
25
  * Get validation CSS classes for input styling
19
26
  */
20
27
  export declare function getValidationClasses(hasErrors: boolean): string;
28
+ /**
29
+ * Validate an entire document's data against a schema
30
+ * This function validates all fields in a schema against the provided data
31
+ * and returns any validation errors found.
32
+ *
33
+ * @param schema - The schema type containing field definitions
34
+ * @param data - The document data to validate
35
+ * @param context - Optional context to pass to field validators
36
+ * @returns Validation result with isValid flag and array of field errors
37
+ */
38
+ export declare function validateDocumentData(schema: SchemaType, data: Record<string, any>, context?: any): Promise<DocumentValidationResult>;
21
39
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/field-validation/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAG5C,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAUrD;AAED;;GAEG;AACH,wBAAsB,aAAa,CAClC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,GAAG,EACV,OAAO,GAAE,GAAQ,GACf,OAAO,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC1B,CAAC,CA6CD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAO/D"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/field-validation/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGxD,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAUrD;AAED;;GAEG;AACH,wBAAsB,aAAa,CAClC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,GAAG,EACV,OAAO,GAAE,GAAQ,GACf,OAAO,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC1B,CAAC,CA6CD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAO/D;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACzC,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,GAAE,GAAQ,GACf,OAAO,CAAC,wBAAwB,CAAC,CA0BnC"}
@@ -64,3 +64,36 @@ export function getValidationClasses(hasErrors) {
64
64
  // No green styling for success - only show red for errors
65
65
  return '';
66
66
  }
67
+ /**
68
+ * Validate an entire document's data against a schema
69
+ * This function validates all fields in a schema against the provided data
70
+ * and returns any validation errors found.
71
+ *
72
+ * @param schema - The schema type containing field definitions
73
+ * @param data - The document data to validate
74
+ * @param context - Optional context to pass to field validators
75
+ * @returns Validation result with isValid flag and array of field errors
76
+ */
77
+ export async function validateDocumentData(schema, data, context = {}) {
78
+ const validationErrors = [];
79
+ // Validate each field in the schema
80
+ for (const field of schema.fields) {
81
+ const value = data[field.name];
82
+ const result = await validateField(field, value, { ...context, ...data });
83
+ if (!result.isValid) {
84
+ const errorMessages = result.errors
85
+ .filter((e) => e.level === 'error')
86
+ .map((e) => e.message);
87
+ if (errorMessages.length > 0) {
88
+ validationErrors.push({
89
+ field: field.name,
90
+ errors: errorMessages
91
+ });
92
+ }
93
+ }
94
+ }
95
+ return {
96
+ isValid: validationErrors.length === 0,
97
+ errors: validationErrors
98
+ };
99
+ }
package/dist/hooks.d.ts CHANGED
@@ -6,6 +6,7 @@ import type { StorageAdapter } from './storage/interfaces/storage.js';
6
6
  import type { EmailAdapter } from './email/index.js';
7
7
  import type { AuthProvider } from './auth/provider.js';
8
8
  import { CMSEngine } from './engine.js';
9
+ import { type LocalAPI } from './local-api/index.js';
9
10
  export interface CMSInstances {
10
11
  config: CMSConfig;
11
12
  assetService: AssetService;
@@ -13,6 +14,7 @@ export interface CMSInstances {
13
14
  databaseAdapter: DatabaseAdapter;
14
15
  emailAdapter?: EmailAdapter | null;
15
16
  cmsEngine: CMSEngine;
17
+ localAPI: LocalAPI;
16
18
  auth?: AuthProvider;
17
19
  pluginRoutes?: Map<string, {
18
20
  handler: (event: any) => Promise<Response> | Response;
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/lib/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAIpD,OAAO,EAAa,SAAS,EAAE,MAAM,UAAU,CAAC;AAGhD,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,cAAc,CAAC;IAC/B,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,YAAY,CAAC,EAAE,GAAG,CACjB,MAAM,EACN;QAAE,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAC7E,CAAC;CACF;AAqBD,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CA+FvD"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/lib/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAA8B,MAAM,eAAe,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAIpD,OAAO,EAAa,SAAS,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlE,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,cAAc,CAAC;IAC/B,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,YAAY,CAAC,EAAE,GAAG,CACjB,MAAM,EACN;QAAE,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAC7E,CAAC;CACF;AA4ED,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAyHvD"}
package/dist/hooks.js CHANGED
@@ -2,6 +2,7 @@ import { handleAuthHook } from './auth/auth-hooks.js';
2
2
  import { createStorageAdapter as createStorageAdapterProvider } from './storage/providers/storage.js';
3
3
  import { AssetService as AssetServiceClass } from './services/asset-service.js';
4
4
  import { createCMS } from './engine.js';
5
+ import { createLocalAPI } from './local-api/index.js';
5
6
  let cmsInstances = null;
6
7
  let lastConfigHash = null;
7
8
  // Helper to generate a simple hash of schema types for change detection
@@ -18,6 +19,51 @@ function createDefaultStorageAdapter() {
18
19
  baseUrl: '' // No direct URL - all access through /assets/{id}/{filename}
19
20
  });
20
21
  }
22
+ /**
23
+ * Resolves a plugin configuration to an actual CMSPlugin instance
24
+ * Supports three formats:
25
+ * 1. String: '@aphexcms/graphql-plugin' - dynamically imports default export
26
+ * 2. Object with name/options: { name: '@aphexcms/graphql-plugin', options: {...} }
27
+ * 3. Already instantiated plugin: CMSPlugin object
28
+ */
29
+ async function resolvePlugin(pluginConfig) {
30
+ // Format 3: Already an instantiated plugin
31
+ if (typeof pluginConfig === 'object' && 'install' in pluginConfig) {
32
+ return pluginConfig;
33
+ }
34
+ // Format 1: String reference
35
+ if (typeof pluginConfig === 'string') {
36
+ try {
37
+ const pluginModule = await import(/* @vite-ignore */ pluginConfig);
38
+ const plugin = pluginModule.default || pluginModule;
39
+ if (typeof plugin === 'function') {
40
+ // If it's a factory function, call it with no options
41
+ return plugin();
42
+ }
43
+ return plugin;
44
+ }
45
+ catch (error) {
46
+ throw new Error(`Failed to load plugin "${pluginConfig}". Make sure it's installed: npm install ${pluginConfig}\nError: ${error}`);
47
+ }
48
+ }
49
+ // Format 2: Object with name and options
50
+ if (typeof pluginConfig === 'object' && 'name' in pluginConfig) {
51
+ try {
52
+ const pluginModule = await import(/* @vite-ignore */ pluginConfig.name);
53
+ const pluginFactory = pluginModule.default || pluginModule;
54
+ if (typeof pluginFactory === 'function') {
55
+ // Call factory with options
56
+ return pluginFactory(pluginConfig.options || {});
57
+ }
58
+ // If not a factory, return as-is (assuming it's already a plugin)
59
+ return pluginFactory;
60
+ }
61
+ catch (error) {
62
+ throw new Error(`Failed to load plugin "${pluginConfig.name}". Make sure it's installed: npm install ${pluginConfig.name}\nError: ${error}`);
63
+ }
64
+ }
65
+ throw new Error(`Invalid plugin configuration: ${JSON.stringify(pluginConfig)}`);
66
+ }
21
67
  export function createCMSHook(config) {
22
68
  return async ({ event, resolve }) => {
23
69
  // Note: In dev mode, /storage/ might be accessible via Vite dev server
@@ -33,15 +79,43 @@ export function createCMSHook(config) {
33
79
  const emailAdapter = config.email ?? null;
34
80
  const assetService = new AssetServiceClass(storageAdapter, databaseAdapter);
35
81
  const cmsEngine = createCMS(config, databaseAdapter);
82
+ // Initialize Local API (unified operations layer)
83
+ const localAPI = createLocalAPI(config, databaseAdapter);
36
84
  await cmsEngine.initialize();
37
- // Build plugin route map (do this ONCE at startup)
85
+ // Build plugin route map and install plugins (do this ONCE at startup)
38
86
  const pluginRoutes = new Map();
87
+ // Resolve and install plugins
39
88
  if (config.plugins && config.plugins.length > 0) {
40
- for (const plugin of config.plugins) {
41
- if (plugin.routes) {
42
- for (const [path, handler] of Object.entries(plugin.routes)) {
43
- pluginRoutes.set(path, { handler, pluginName: plugin.name });
89
+ for (const pluginConfig of config.plugins) {
90
+ try {
91
+ // Resolve plugin config to actual CMSPlugin instance (may involve dynamic import)
92
+ const plugin = await resolvePlugin(pluginConfig);
93
+ console.log(`🔌 Loading plugin: ${plugin.name}@${plugin.version}`);
94
+ // Build route map before installation
95
+ if (plugin.routes) {
96
+ for (const [path, handler] of Object.entries(plugin.routes)) {
97
+ pluginRoutes.set(path, { handler, pluginName: plugin.name });
98
+ }
44
99
  }
100
+ // Create temporary cmsInstances for installation (will be replaced below)
101
+ const tempInstances = {
102
+ config,
103
+ databaseAdapter: databaseAdapter,
104
+ assetService: assetService,
105
+ storageAdapter: storageAdapter,
106
+ emailAdapter: emailAdapter,
107
+ cmsEngine: cmsEngine,
108
+ localAPI: localAPI,
109
+ auth: config.auth?.provider,
110
+ pluginRoutes
111
+ };
112
+ // Install the plugin
113
+ console.log(`🔌 Installing plugin: ${plugin.name}`);
114
+ await plugin.install(tempInstances);
115
+ }
116
+ catch (error) {
117
+ console.error(`❌ Failed to load/install plugin:`, error);
118
+ throw error;
45
119
  }
46
120
  }
47
121
  }
@@ -52,16 +126,10 @@ export function createCMSHook(config) {
52
126
  storageAdapter: storageAdapter,
53
127
  emailAdapter: emailAdapter,
54
128
  cmsEngine: cmsEngine,
129
+ localAPI: localAPI,
55
130
  auth: config.auth?.provider,
56
131
  pluginRoutes
57
132
  };
58
- // Install plugins
59
- if (config.plugins && config.plugins.length > 0) {
60
- for (const plugin of config.plugins) {
61
- console.log(`🔌 Installing plugin: ${plugin.name}`);
62
- await plugin.install(cmsInstances);
63
- }
64
- }
65
133
  lastConfigHash = currentConfigHash;
66
134
  }
67
135
  else if (configChanged) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ // Aphex CMS Database Layer
2
+ // Ports and adapters for database operations
3
+ // Interfaces
4
+ export * from './interfaces/index.js';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ // Aphex CMS Email Layer
2
+ // Ports and adapters for email sending operations
3
+ // Interfaces
4
+ export * from './interfaces/email.js';
@@ -0,0 +1 @@
1
+ export {};