@aphexcms/cms-core 0.1.12 → 0.1.14

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 (95) 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 +15 -12
  12. package/dist/components/AdminApp.svelte.d.ts.map +1 -1
  13. package/dist/components/admin/DocumentEditor.svelte +60 -14
  14. package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
  15. package/dist/components/admin/fields/ImageField.svelte +22 -13
  16. package/dist/components/admin/fields/ImageField.svelte.d.ts.map +1 -1
  17. package/dist/components/admin/fields/ReferenceField.svelte +2 -3
  18. package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
  19. package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts +8 -1
  20. package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts.map +1 -1
  21. package/dist/db/interfaces/asset.d.ts +22 -0
  22. package/dist/db/interfaces/asset.d.ts.map +1 -1
  23. package/dist/db/interfaces/document.d.ts +25 -0
  24. package/dist/db/interfaces/document.d.ts.map +1 -1
  25. package/dist/field-validation/utils.d.ts +19 -1
  26. package/dist/field-validation/utils.d.ts.map +1 -1
  27. package/dist/field-validation/utils.js +33 -0
  28. package/dist/hooks.d.ts +2 -0
  29. package/dist/hooks.d.ts.map +1 -1
  30. package/dist/hooks.js +80 -12
  31. package/dist/lib/auth/provider.js +1 -0
  32. package/dist/lib/db/index.js +4 -0
  33. package/dist/lib/db/interfaces/asset.js +1 -0
  34. package/dist/lib/db/interfaces/document.js +1 -0
  35. package/dist/lib/db/interfaces/index.js +1 -0
  36. package/dist/lib/db/interfaces/organization.js +1 -0
  37. package/dist/lib/db/interfaces/schema.js +1 -0
  38. package/dist/lib/db/interfaces/user.js +1 -0
  39. package/dist/lib/email/index.js +4 -0
  40. package/dist/lib/email/interfaces/email.js +1 -0
  41. package/dist/lib/field-validation/rule.js +221 -0
  42. package/dist/lib/field-validation/utils.js +99 -0
  43. package/dist/lib/storage/interfaces/index.js +2 -0
  44. package/dist/lib/storage/interfaces/storage.js +1 -0
  45. package/dist/lib/types/asset.js +2 -0
  46. package/dist/lib/types/auth.js +41 -0
  47. package/dist/lib/types/config.js +1 -0
  48. package/dist/lib/types/document.js +1 -0
  49. package/dist/lib/types/filters.js +5 -0
  50. package/dist/lib/types/index.js +9 -0
  51. package/dist/lib/types/organization.js +3 -0
  52. package/dist/lib/types/schemas.js +1 -0
  53. package/dist/lib/types/sidebar.js +1 -0
  54. package/dist/lib/types/user.js +1 -0
  55. package/dist/local-api/auth-helpers.d.ts +65 -0
  56. package/dist/local-api/auth-helpers.d.ts.map +1 -0
  57. package/dist/local-api/auth-helpers.js +102 -0
  58. package/dist/local-api/collection-api.d.ts +138 -0
  59. package/dist/local-api/collection-api.d.ts.map +1 -0
  60. package/dist/local-api/collection-api.js +276 -0
  61. package/dist/local-api/index.d.ts +108 -0
  62. package/dist/local-api/index.d.ts.map +1 -0
  63. package/dist/local-api/index.js +157 -0
  64. package/dist/local-api/permissions.d.ts +45 -0
  65. package/dist/local-api/permissions.d.ts.map +1 -0
  66. package/dist/local-api/permissions.js +117 -0
  67. package/dist/local-api/types.d.ts +65 -0
  68. package/dist/local-api/types.d.ts.map +1 -0
  69. package/dist/local-api/types.js +4 -0
  70. package/dist/routes/documents-by-id.d.ts.map +1 -1
  71. package/dist/routes/documents-by-id.js +84 -63
  72. package/dist/routes/documents-publish.d.ts.map +1 -1
  73. package/dist/routes/documents-publish.js +57 -72
  74. package/dist/routes/documents-query.d.ts +24 -0
  75. package/dist/routes/documents-query.d.ts.map +1 -0
  76. package/dist/routes/documents-query.js +95 -0
  77. package/dist/routes/documents.d.ts.map +1 -1
  78. package/dist/routes/documents.js +80 -75
  79. package/dist/routes/index.d.ts +2 -0
  80. package/dist/routes/index.d.ts.map +1 -1
  81. package/dist/routes/index.js +2 -0
  82. package/dist/server/index.d.ts +1 -0
  83. package/dist/server/index.d.ts.map +1 -1
  84. package/dist/server/index.js +2 -0
  85. package/dist/types/config.d.ts +18 -1
  86. package/dist/types/config.d.ts.map +1 -1
  87. package/dist/types/document.d.ts +1 -0
  88. package/dist/types/document.d.ts.map +1 -1
  89. package/dist/types/filters.d.ts +173 -0
  90. package/dist/types/filters.d.ts.map +1 -0
  91. package/dist/types/filters.js +5 -0
  92. package/dist/types/index.d.ts +1 -0
  93. package/dist/types/index.d.ts.map +1 -1
  94. package/dist/types/index.js +1 -0
  95. package/package.json +101 -95
@@ -131,28 +131,37 @@
131
131
  // Asset data state
132
132
  let assetData = $state<any>(null);
133
133
  let loadingAsset = $state(false);
134
+ let lastAssetId = $state<string | null>(null);
134
135
 
135
136
  // Fetch asset details when asset reference changes
136
137
  $effect(() => {
137
138
  async function loadAsset() {
138
- if (value?.asset?._ref) {
139
- loadingAsset = true;
140
- try {
141
- const result = await assets.getById(value.asset._ref);
142
- if (result.success) {
143
- assetData = result.data;
144
- } else {
145
- console.error('Failed to fetch asset details');
139
+ const assetId = value?.asset?._ref || null;
140
+
141
+ // Only fetch if asset ID has actually changed
142
+ if (assetId !== lastAssetId) {
143
+ lastAssetId = assetId;
144
+
145
+ if (assetId) {
146
+ loadingAsset = true;
147
+ try {
148
+ const result = await assets.getById(assetId);
149
+ if (result.success) {
150
+ assetData = result.data;
151
+ } else {
152
+ console.error('Failed to fetch asset details');
153
+ assetData = null;
154
+ }
155
+ } catch (error) {
156
+ console.error('Error fetching asset:', error);
146
157
  assetData = null;
158
+ } finally {
159
+ loadingAsset = false;
147
160
  }
148
- } catch (error) {
149
- console.error('Error fetching asset:', error);
161
+ } else {
150
162
  assetData = null;
151
- } finally {
152
163
  loadingAsset = false;
153
164
  }
154
- } else {
155
- assetData = null;
156
165
  }
157
166
  }
158
167
  loadAsset();
@@ -1 +1 @@
1
- {"version":3,"file":"ImageField.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/fields/ImageField.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAY1E,UAAU,KAAK;IACd,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAgQF,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ImageField.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/fields/ImageField.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAY1E,UAAU,KAAK;IACd,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAyQF,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,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 {};