@aphexcms/cms-core 7.0.0 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/dist/api/documents.d.ts +19 -0
  2. package/dist/api/documents.d.ts.map +1 -1
  3. package/dist/api/documents.js +21 -0
  4. package/dist/api/schemas/documents.d.ts +3 -0
  5. package/dist/api/schemas/documents.d.ts.map +1 -1
  6. package/dist/api/schemas/documents.js +12 -0
  7. package/dist/cli/generate-types.d.ts.map +1 -1
  8. package/dist/cli/generate-types.js +133 -19
  9. package/dist/cli/generate-types.js.map +1 -1
  10. package/dist/components/AdminApp.svelte +106 -52
  11. package/dist/components/AdminApp.svelte.d.ts.map +1 -1
  12. package/dist/components/admin/DocumentEditor.svelte +65 -2
  13. package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
  14. package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte +8 -6
  15. package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte.d.ts.map +1 -1
  16. package/dist/components/admin/fields/ArrayField.svelte +149 -2
  17. package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -1
  18. package/dist/components/admin/fields/ReferenceField.svelte +198 -125
  19. package/dist/components/admin/fields/ReferenceField.svelte.d.ts +9 -2
  20. package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
  21. package/dist/components/layout/Sidebar.svelte +1 -1
  22. package/dist/components/layout/sidebar/AppSidebar.svelte +2 -1
  23. package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts.map +1 -1
  24. package/dist/components/layout/sidebar/NavMain.svelte +9 -2
  25. package/dist/components/layout/sidebar/NavMain.svelte.d.ts +2 -0
  26. package/dist/components/layout/sidebar/NavMain.svelte.d.ts.map +1 -1
  27. package/dist/db/interfaces/index.d.ts +3 -1
  28. package/dist/db/interfaces/index.d.ts.map +1 -1
  29. package/dist/db/interfaces/reference.d.ts +43 -0
  30. package/dist/db/interfaces/reference.d.ts.map +1 -0
  31. package/dist/db/interfaces/reference.js +4 -0
  32. package/dist/db/utils/reference-resolver.d.ts +4 -6
  33. package/dist/db/utils/reference-resolver.d.ts.map +1 -1
  34. package/dist/db/utils/reference-resolver.js +33 -31
  35. package/dist/document-refresh.svelte.d.ts +3 -0
  36. package/dist/document-refresh.svelte.d.ts.map +1 -0
  37. package/dist/document-refresh.svelte.js +21 -0
  38. package/dist/graphql/resolvers.d.ts.map +1 -1
  39. package/dist/graphql/resolvers.js +61 -1
  40. package/dist/graphql/schema.d.ts.map +1 -1
  41. package/dist/graphql/schema.js +10 -0
  42. package/dist/lib/api/documents.d.ts +19 -0
  43. package/dist/lib/api/documents.d.ts.map +1 -1
  44. package/dist/lib/api/documents.js +21 -0
  45. package/dist/lib/api/documents.js.map +1 -1
  46. package/dist/lib/api/schemas/documents.d.ts +3 -0
  47. package/dist/lib/api/schemas/documents.d.ts.map +1 -1
  48. package/dist/lib/api/schemas/documents.js +12 -0
  49. package/dist/lib/api/schemas/documents.js.map +1 -1
  50. package/dist/lib/db/interfaces/index.d.ts +3 -1
  51. package/dist/lib/db/interfaces/index.d.ts.map +1 -1
  52. package/dist/lib/db/interfaces/reference.d.ts +43 -0
  53. package/dist/lib/db/interfaces/reference.d.ts.map +1 -0
  54. package/dist/lib/db/interfaces/reference.js +5 -0
  55. package/dist/lib/db/interfaces/reference.js.map +1 -0
  56. package/dist/lib/db/utils/reference-resolver.d.ts +4 -6
  57. package/dist/lib/db/utils/reference-resolver.d.ts.map +1 -1
  58. package/dist/lib/db/utils/reference-resolver.js +33 -31
  59. package/dist/lib/db/utils/reference-resolver.js.map +1 -1
  60. package/dist/lib/document-refresh.svelte.d.ts +3 -0
  61. package/dist/lib/document-refresh.svelte.d.ts.map +1 -0
  62. package/dist/lib/document-refresh.svelte.js +22 -0
  63. package/dist/lib/document-refresh.svelte.js.map +1 -0
  64. package/dist/lib/graphql/resolvers.d.ts.map +1 -1
  65. package/dist/lib/graphql/resolvers.js +61 -1
  66. package/dist/lib/graphql/resolvers.js.map +1 -1
  67. package/dist/lib/graphql/schema.d.ts.map +1 -1
  68. package/dist/lib/graphql/schema.js +10 -0
  69. package/dist/lib/graphql/schema.js.map +1 -1
  70. package/dist/lib/local-api/collection-api.d.ts +10 -1
  71. package/dist/lib/local-api/collection-api.d.ts.map +1 -1
  72. package/dist/lib/local-api/collection-api.js +39 -1
  73. package/dist/lib/local-api/collection-api.js.map +1 -1
  74. package/dist/lib/local-api/index.d.ts +29 -0
  75. package/dist/lib/local-api/index.d.ts.map +1 -1
  76. package/dist/lib/local-api/index.js +66 -2
  77. package/dist/lib/local-api/index.js.map +1 -1
  78. package/dist/lib/schema-utils/validator.js +21 -11
  79. package/dist/lib/schema-utils/validator.js.map +1 -1
  80. package/dist/lib/server/api/index.d.ts.map +1 -1
  81. package/dist/lib/server/api/index.js +3 -1
  82. package/dist/lib/server/api/index.js.map +1 -1
  83. package/dist/lib/server/api/routes/documents-by-id.d.ts.map +1 -1
  84. package/dist/lib/server/api/routes/documents-by-id.js +23 -0
  85. package/dist/lib/server/api/routes/documents-by-id.js.map +1 -1
  86. package/dist/lib/server/api/routes/documents.d.ts.map +1 -1
  87. package/dist/lib/server/api/routes/documents.js +29 -1
  88. package/dist/lib/server/api/routes/documents.js.map +1 -1
  89. package/dist/lib/services/references-service.d.ts +35 -0
  90. package/dist/lib/services/references-service.d.ts.map +1 -0
  91. package/dist/lib/services/references-service.js +60 -0
  92. package/dist/lib/services/references-service.js.map +1 -0
  93. package/dist/lib/types/schemas.d.ts +8 -0
  94. package/dist/lib/types/schemas.d.ts.map +1 -1
  95. package/dist/lib/utils/preview.d.ts +2 -3
  96. package/dist/lib/utils/preview.d.ts.map +1 -1
  97. package/dist/lib/utils/preview.js +35 -8
  98. package/dist/lib/utils/preview.js.map +1 -1
  99. package/dist/lib/utils/reference-walk.d.ts +8 -0
  100. package/dist/lib/utils/reference-walk.d.ts.map +1 -0
  101. package/dist/lib/utils/reference-walk.js +43 -0
  102. package/dist/lib/utils/reference-walk.js.map +1 -0
  103. package/dist/local-api/collection-api.d.ts +10 -1
  104. package/dist/local-api/collection-api.d.ts.map +1 -1
  105. package/dist/local-api/collection-api.js +39 -1
  106. package/dist/local-api/index.d.ts +29 -0
  107. package/dist/local-api/index.d.ts.map +1 -1
  108. package/dist/local-api/index.js +66 -2
  109. package/dist/schema-utils/validator.js +21 -11
  110. package/dist/server/api/index.d.ts.map +1 -1
  111. package/dist/server/api/index.js +3 -1
  112. package/dist/server/api/routes/documents-by-id.d.ts.map +1 -1
  113. package/dist/server/api/routes/documents-by-id.js +23 -0
  114. package/dist/server/api/routes/documents.d.ts.map +1 -1
  115. package/dist/server/api/routes/documents.js +29 -1
  116. package/dist/services/references-service.d.ts +35 -0
  117. package/dist/services/references-service.d.ts.map +1 -0
  118. package/dist/services/references-service.js +59 -0
  119. package/dist/types/schemas.d.ts +8 -0
  120. package/dist/types/schemas.d.ts.map +1 -1
  121. package/dist/utils/preview.d.ts +2 -3
  122. package/dist/utils/preview.d.ts.map +1 -1
  123. package/dist/utils/preview.js +35 -8
  124. package/dist/utils/reference-walk.d.ts +8 -0
  125. package/dist/utils/reference-walk.d.ts.map +1 -0
  126. package/dist/utils/reference-walk.js +42 -0
  127. package/package.json +3 -3
@@ -4,6 +4,7 @@
4
4
  import { DocumentCache } from '../cache/index.js';
5
5
  import { HierarchyService } from '../services/hierarchy-service.js';
6
6
  import { VersionService } from '../services/version-service.js';
7
+ import { ReferencesService } from '../services/references-service.js';
7
8
  import { CollectionAPI } from './collection-api.js';
8
9
  /**
9
10
  * CollectionAPI methods that compute synchronously and don't touch the DB.
@@ -53,6 +54,7 @@ export class LocalAPI {
53
54
  documentCache;
54
55
  hierarchyService;
55
56
  versionService;
57
+ referencesService;
56
58
  permissions;
57
59
  schemas;
58
60
  constructor(config, userAdapter, systemAdapter) {
@@ -64,6 +66,7 @@ export class LocalAPI {
64
66
  this.versionService = new VersionService({
65
67
  maxVersions: config.versioning?.maxVersions ?? 25
66
68
  });
69
+ this.referencesService = new ReferencesService(userAdapter);
67
70
  // Build schema map for quick lookups
68
71
  this.schemas = new Map(config.schemaTypes
69
72
  .filter((schema) => schema.type === 'document')
@@ -80,7 +83,7 @@ export class LocalAPI {
80
83
  const documentSchemas = this.config.schemaTypes.filter((s) => s.type === 'document');
81
84
  for (const schema of documentSchemas) {
82
85
  // Create a proxy that selects the correct adapter based on context
83
- const collectionAPI = new Proxy(new CollectionAPI(schema.name, this.userAdapter, schema, this.permissions, this.documentCache, this.hierarchyService, this.versionService), {
86
+ const collectionAPI = new Proxy(new CollectionAPI(schema.name, this.userAdapter, schema, this.permissions, this.documentCache, this.hierarchyService, this.versionService, this.referencesService, this.config.schemaTypes), {
84
87
  get: (target, prop) => {
85
88
  const method = target[prop];
86
89
  // Sync, pure-computation methods bypass the adapter-swap
@@ -97,7 +100,7 @@ export class LocalAPI {
97
100
  const context = args[0];
98
101
  const adapter = this.getAdapter(context);
99
102
  // Create new CollectionAPI with the correct adapter
100
- const api = new CollectionAPI(schema.name, adapter, schema, this.permissions, this.documentCache, this.hierarchyService, this.versionService);
103
+ const api = new CollectionAPI(schema.name, adapter, schema, this.permissions, this.documentCache, this.hierarchyService, this.versionService, new ReferencesService(adapter), this.config.schemaTypes);
101
104
  // Call the method on the new instance
102
105
  return api[prop].apply(api, args);
103
106
  };
@@ -154,6 +157,67 @@ export class LocalAPI {
154
157
  return null;
155
158
  return { type: rawDoc.type, document: rawDoc };
156
159
  }
160
+ /**
161
+ * Find all documents that reference the given target — the back-reference
162
+ * lookup that powers the unpublish guard. Returns lightweight rows
163
+ * (id/type/status); callers fetch full docs separately if they need data.
164
+ */
165
+ async getBackReferences(context, refId) {
166
+ const adapter = this.getAdapter(context);
167
+ return adapter.findBackReferences(context.organizationId, refId);
168
+ }
169
+ /**
170
+ * Batch lookup — fetch many documents by ID in one call. Routes through
171
+ * each doc's collection so the returned shape matches `collection.findByID`
172
+ * (perms applied, transformed, hidden fields stripped). Org hierarchy is
173
+ * resolved once for the whole batch and threaded into each per-collection
174
+ * call.
175
+ *
176
+ * Heterogeneous batches (mixed types) leave T as the default `unknown`;
177
+ * homogeneous callers (e.g. an array-of-references-to-one-type) can
178
+ * narrow it: `findDocumentsByIds<MenuItem>(ctx, ids)`.
179
+ *
180
+ * Missing/forbidden IDs are dropped from the result rather than thrown —
181
+ * callers compare result length to input length to detect gaps. If/when
182
+ * an adapter exposes a true `WHERE id IN (...)` batch we can short-circuit
183
+ * the per-id collection round-trips here without changing call sites.
184
+ */
185
+ async findDocumentsByIds(context, ids, options) {
186
+ if (ids.length === 0)
187
+ return [];
188
+ const adapter = this.getAdapter(context);
189
+ // Resolve org hierarchy once for the whole batch; thread into each
190
+ // per-id call so collection.findByID skips its own hierarchy lookup.
191
+ let filterOrganizationIds = options?.filterOrganizationIds;
192
+ if (!filterOrganizationIds && this.hierarchyService) {
193
+ filterOrganizationIds = await this.hierarchyService.getOrgIdsWithChildren(context.organizationId);
194
+ }
195
+ // First: cheap type lookups so we know which collection to route through.
196
+ const typeLookups = await Promise.all(ids.map((id) => adapter
197
+ .findByDocIdAdvanced(context.organizationId, id, { filterOrganizationIds })
198
+ .then((row) => (row ? { id, type: row.type } : null))));
199
+ // Second: per-collection findByID for each resolved doc. Fan out in
200
+ // parallel; collection.findByID enforces perms and applies the
201
+ // standard processing pipeline.
202
+ const docs = await Promise.all(typeLookups.map(async (lookup) => {
203
+ if (!lookup)
204
+ return null;
205
+ const collection = this.collections[lookup.type];
206
+ if (!collection)
207
+ return null;
208
+ try {
209
+ return (await collection.findByID(context, lookup.id, {
210
+ ...options,
211
+ filterOrganizationIds
212
+ }));
213
+ }
214
+ catch {
215
+ // Permission denied or similar — drop silently per the contract.
216
+ return null;
217
+ }
218
+ }));
219
+ return docs.filter((d) => d != null);
220
+ }
157
221
  }
158
222
  // Global Local API instance
159
223
  let localAPIInstance = null;
@@ -57,6 +57,21 @@ export function validateSchemaReferences(schemas) {
57
57
  // Check array field references
58
58
  if (field.type === 'array' && field.of) {
59
59
  for (const arrayType of field.of) {
60
+ // Reference items inside an array must declare `to` and target known schemas
61
+ if (arrayType.type === 'reference') {
62
+ const to = arrayType.to;
63
+ if (!Array.isArray(to) || to.length === 0) {
64
+ errors.push(`Schema "${parentSchema}" field "${field.name}" has a reference array item missing "to" — declare allowed target document types`);
65
+ }
66
+ else {
67
+ for (const target of to) {
68
+ if (!schemaNames.has(target.type)) {
69
+ errors.push(`Schema "${parentSchema}" field "${field.name}" reference array item targets unknown document type "${target.type}"`);
70
+ }
71
+ }
72
+ }
73
+ continue;
74
+ }
60
75
  // Skip validation for primitive types and inline objects
61
76
  if (primitiveTypes.includes(arrayType.type)) {
62
77
  continue;
@@ -123,17 +138,12 @@ export function validateSchemaReferences(schemas) {
123
138
  if (schema.preview?.select) {
124
139
  const fieldNames = new Set(schema.fields?.map((f) => f.name) || []);
125
140
  const rootOf = (path) => path.split('.', 1)[0] ?? path;
126
- if (schema.preview.select.title &&
127
- !fieldNames.has(rootOf(schema.preview.select.title))) {
128
- errors.push(`Schema "${schema.name}" preview.select.title references unknown field "${schema.preview.select.title}"`);
129
- }
130
- if (schema.preview.select.subtitle &&
131
- !fieldNames.has(rootOf(schema.preview.select.subtitle))) {
132
- errors.push(`Schema "${schema.name}" preview.select.subtitle references unknown field "${schema.preview.select.subtitle}"`);
133
- }
134
- if (schema.preview.select.media &&
135
- !fieldNames.has(rootOf(schema.preview.select.media))) {
136
- errors.push(`Schema "${schema.name}" preview.select.media references unknown field "${schema.preview.select.media}"`);
141
+ for (const [key, path] of Object.entries(schema.preview.select)) {
142
+ if (typeof path !== 'string' || !path)
143
+ continue;
144
+ if (!fieldNames.has(rootOf(path))) {
145
+ errors.push(`Schema "${schema.name}" preview.select.${key} references unknown field "${path}"`);
146
+ }
137
147
  }
138
148
  }
139
149
  // Validate orderings
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/server/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAoB7C;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAAG;IACtB,SAAS,EAAE;QACV,QAAQ,EAAE,YAAY,CAAC;QACvB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;KAClB,CAAC;IACF,QAAQ,EAAE;QACT,QAAQ,EAAE,YAAY,CAAC;QACvB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;KAClB,CAAC;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,cAAc,kGAY7B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,QAoCrD;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC5B,SAAS,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,IAEzC,GAAG,OAAO,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,uBAejD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/server/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAoB7C;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAAG;IACtB,SAAS,EAAE;QACV,QAAQ,EAAE,YAAY,CAAC;QACvB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;KAClB,CAAC;IACF,QAAQ,EAAE;QACT,QAAQ,EAAE,YAAY,CAAC;QACvB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;KAClB,CAAC;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,cAAc,kGAY7B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,QAsCrD;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC5B,SAAS,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,IAEzC,GAAG,OAAO,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,uBAejD"}
@@ -52,8 +52,10 @@ export function mountAphexBuiltins(app) {
52
52
  app.route('/documents', documentsQueryRouter);
53
53
  app.route('/documents', documentsPublishRouter);
54
54
  app.route('/documents', documentVersionsRouter);
55
- app.route('/documents', documentsByIdRouter);
55
+ // documentsRouter has the literal `/by-ids` batch endpoint, which must
56
+ // mount before documentsByIdRouter or `:id` will swallow it.
56
57
  app.route('/documents', documentsRouter);
58
+ app.route('/documents', documentsByIdRouter);
57
59
  // Assets — same precedence rule: specific paths before parametric.
58
60
  // `/assets/bulk` and `/assets/references/counts` must register before
59
61
  // `/assets/:id` or Hono will capture them as `:id = "bulk"` etc.
@@ -1 +1 @@
1
- {"version":3,"file":"documents-by-id.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/api/routes/documents-by-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAO5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,eAAO,MAAM,mBAAmB,EAAE,IAAI,CAAC,QAAQ,CAkM5C,CAAC"}
1
+ {"version":3,"file":"documents-by-id.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/api/routes/documents-by-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAO5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,eAAO,MAAM,mBAAmB,EAAE,IAAI,CAAC,QAAQ,CA6N5C,CAAC"}
@@ -148,4 +148,27 @@ export const documentsByIdRouter = new Hono()
148
148
  message: error instanceof Error ? error.message : 'Unknown error'
149
149
  }, 500);
150
150
  }
151
+ })
152
+ .get('/:id/back-references', async (c) => {
153
+ try {
154
+ const { localAPI } = c.var.aphexCMS;
155
+ const context = authToContext(c.var.auth);
156
+ const id = c.req.param('id');
157
+ if (!id) {
158
+ return c.json({ success: false, error: 'Document ID is required' }, 400);
159
+ }
160
+ const refs = await localAPI.getBackReferences(context, id);
161
+ return c.json({ success: true, data: refs });
162
+ }
163
+ catch (error) {
164
+ cmsLogger.error('Failed to fetch back-references:', error);
165
+ if (error instanceof PermissionError) {
166
+ return c.json({ success: false, error: 'Forbidden', message: error.message }, 403);
167
+ }
168
+ return c.json({
169
+ success: false,
170
+ error: 'Failed to fetch back-references',
171
+ message: error instanceof Error ? error.message : 'Unknown error'
172
+ }, 500);
173
+ }
151
174
  });
@@ -1 +1 @@
1
- {"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/api/routes/documents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAM5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKzC,eAAO,MAAM,eAAe,EAAE,IAAI,CAAC,QAAQ,CAuKxC,CAAC"}
1
+ {"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/api/routes/documents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAU5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKzC,eAAO,MAAM,eAAe,EAAE,IAAI,CAAC,QAAQ,CAyMxC,CAAC"}
@@ -3,7 +3,7 @@ import { zValidator } from '@hono/zod-validator';
3
3
  import { authToContext } from '../../../local-api/auth-helpers.js';
4
4
  import { PermissionError } from '../../../local-api/permissions.js';
5
5
  import { cmsLogger } from '../../../utils/logger.js';
6
- import { createDocumentRequest, listDocumentsQuery } from '../../../api/schemas/documents.js';
6
+ import { createDocumentRequest, getDocumentsByIdsQuery, listDocumentsQuery } from '../../../api/schemas/documents.js';
7
7
  const DEFAULT_PAGE_SIZE = 20;
8
8
  const DEFAULT_PAGE = 1;
9
9
  export const documentsRouter = new Hono()
@@ -83,6 +83,34 @@ export const documentsRouter = new Hono()
83
83
  message: error instanceof Error ? error.message : 'Unknown error'
84
84
  }, 500);
85
85
  }
86
+ })
87
+ .get('/by-ids', zValidator('query', getDocumentsByIdsQuery, (result, c) => {
88
+ if (!result.success) {
89
+ return c.json({
90
+ success: false,
91
+ error: 'Invalid query parameters',
92
+ issues: result.error.issues
93
+ }, 400);
94
+ }
95
+ }), async (c) => {
96
+ try {
97
+ const { localAPI } = c.var.aphexCMS;
98
+ const context = authToContext(c.var.auth);
99
+ const { ids } = c.req.valid('query');
100
+ const docs = await localAPI.findDocumentsByIds(context, ids);
101
+ return c.json({ success: true, data: docs });
102
+ }
103
+ catch (error) {
104
+ cmsLogger.error('Failed to batch-fetch documents:', error);
105
+ if (error instanceof PermissionError) {
106
+ return c.json({ success: false, error: 'Forbidden', message: error.message }, 403);
107
+ }
108
+ return c.json({
109
+ success: false,
110
+ error: 'Failed to fetch documents',
111
+ message: error instanceof Error ? error.message : 'Unknown error'
112
+ }, 500);
113
+ }
86
114
  })
87
115
  .post('/', zValidator('json', createDocumentRequest, (result, c) => {
88
116
  if (!result.success) {
@@ -0,0 +1,35 @@
1
+ import type { DatabaseAdapter } from '../db/interfaces.js';
2
+ import type { SchemaType } from '../types/schemas.js';
3
+ /**
4
+ * Maintains the back-reference index. After every doc save the collection-API
5
+ * calls into here with the doc's draftData (the freshly-saved version) and
6
+ * its schema; we walk the data via the schema-aware walker, dedupe the
7
+ * resulting ref IDs, and atomically replace the rows for that referencer.
8
+ *
9
+ * Failures are logged but never thrown — a stale ref index is bad UX (the
10
+ * publish/unpublish guards may be wrong), but it shouldn't block the user's
11
+ * save. The boot-time backfill catches up gaps when the studio restarts.
12
+ */
13
+ export declare class ReferencesService {
14
+ private databaseAdapter;
15
+ constructor(databaseAdapter: DatabaseAdapter);
16
+ /**
17
+ * Sync the back-reference rows for a single document. Idempotent —
18
+ * safe to call repeatedly with the same data.
19
+ */
20
+ syncReferencesFor(organizationId: string, documentId: string, data: unknown, schema: SchemaType | null, registry: SchemaType[]): Promise<void>;
21
+ /**
22
+ * Boot-time backfill — if the references table is empty for an org,
23
+ * scan every document and rebuild the index. Idempotent and cheap when
24
+ * the index already has rows (the empty check short-circuits).
25
+ *
26
+ * Skipped silently in error paths — boot must keep going even if the
27
+ * scan can't run (missing perms, connection issues, etc).
28
+ */
29
+ backfillIfEmpty(organizationId: string, schemas: SchemaType[], listAllDocuments: () => Promise<Array<{
30
+ id: string;
31
+ type: string;
32
+ data: unknown;
33
+ }>>): Promise<void>;
34
+ }
35
+ //# sourceMappingURL=references-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"references-service.d.ts","sourceRoot":"","sources":["../../src/lib/services/references-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD;;;;;;;;;GASG;AACH,qBAAa,iBAAiB;IACjB,OAAO,CAAC,eAAe;gBAAf,eAAe,EAAE,eAAe;IAEpD;;;OAGG;IACG,iBAAiB,CACtB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,QAAQ,EAAE,UAAU,EAAE,GACpB,OAAO,CAAC,IAAI,CAAC;IAShB;;;;;;;OAOG;IACG,eAAe,CACpB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,UAAU,EAAE,EACrB,gBAAgB,EAAE,MAAM,OAAO,CAC9B,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAClD,GACC,OAAO,CAAC,IAAI,CAAC;CAwBhB"}
@@ -0,0 +1,59 @@
1
+ import { collectReferenceIds } from '../utils/reference-walk.js';
2
+ import { cmsLogger } from '../utils/logger.js';
3
+ /**
4
+ * Maintains the back-reference index. After every doc save the collection-API
5
+ * calls into here with the doc's draftData (the freshly-saved version) and
6
+ * its schema; we walk the data via the schema-aware walker, dedupe the
7
+ * resulting ref IDs, and atomically replace the rows for that referencer.
8
+ *
9
+ * Failures are logged but never thrown — a stale ref index is bad UX (the
10
+ * publish/unpublish guards may be wrong), but it shouldn't block the user's
11
+ * save. The boot-time backfill catches up gaps when the studio restarts.
12
+ */
13
+ export class ReferencesService {
14
+ databaseAdapter;
15
+ constructor(databaseAdapter) {
16
+ this.databaseAdapter = databaseAdapter;
17
+ }
18
+ /**
19
+ * Sync the back-reference rows for a single document. Idempotent —
20
+ * safe to call repeatedly with the same data.
21
+ */
22
+ async syncReferencesFor(organizationId, documentId, data, schema, registry) {
23
+ try {
24
+ const refIds = collectReferenceIds(data, schema, registry);
25
+ await this.databaseAdapter.replaceReferencesFor(organizationId, documentId, refIds);
26
+ }
27
+ catch (err) {
28
+ cmsLogger.error('[References]', 'Failed to sync references for', documentId, err);
29
+ }
30
+ }
31
+ /**
32
+ * Boot-time backfill — if the references table is empty for an org,
33
+ * scan every document and rebuild the index. Idempotent and cheap when
34
+ * the index already has rows (the empty check short-circuits).
35
+ *
36
+ * Skipped silently in error paths — boot must keep going even if the
37
+ * scan can't run (missing perms, connection issues, etc).
38
+ */
39
+ async backfillIfEmpty(organizationId, schemas, listAllDocuments) {
40
+ try {
41
+ const populated = await this.databaseAdapter.hasAnyReferences(organizationId);
42
+ if (populated)
43
+ return;
44
+ const docs = await listAllDocuments();
45
+ if (docs.length === 0)
46
+ return;
47
+ cmsLogger.info('[References]', `Backfilling reference index for ${docs.length} document(s) in org ${organizationId}`);
48
+ for (const doc of docs) {
49
+ const schema = schemas.find((s) => s.name === doc.type) ?? null;
50
+ const refIds = collectReferenceIds(doc.data, schema, schemas);
51
+ await this.databaseAdapter.replaceReferencesFor(organizationId, doc.id, refIds);
52
+ }
53
+ cmsLogger.info('[References]', 'Backfill complete');
54
+ }
55
+ catch (err) {
56
+ cmsLogger.error('[References]', 'Backfill failed (continuing without index)', err);
57
+ }
58
+ }
59
+ }
@@ -143,6 +143,9 @@ export interface TypeReference {
143
143
  fields?: Field[];
144
144
  icon?: typeof LucideIcon;
145
145
  preview?: PreviewConfig;
146
+ to?: Array<{
147
+ type: string;
148
+ }>;
146
149
  }
147
150
  export interface ArrayField extends BaseField {
148
151
  type: 'array';
@@ -189,6 +192,11 @@ export interface PreviewConfig {
189
192
  title?: string;
190
193
  subtitle?: string;
191
194
  media?: string;
195
+ } & Record<string, string>;
196
+ prepare?: (selection: Record<string, unknown>) => {
197
+ title?: string;
198
+ subtitle?: string;
199
+ media?: string;
192
200
  };
193
201
  }
194
202
  export interface OrderingItem {
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/lib/types/schemas.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/lib/types/schemas.ts"],"names":[],"mappings":"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"}
@@ -6,9 +6,8 @@ import type { SchemaType } from '../types/schemas.js';
6
6
  export declare function readPath(item: any, path: string): unknown;
7
7
  /**
8
8
  * Resolve the title to display for an item (array row, document list row,
9
- * reference picker row). Honors `schema.preview.select.title` first
10
- * (with dot-path support), then falls back to the conventional field
11
- * names, then the schema's own title, then the type name.
9
+ * reference picker row). Precedence: `preview.prepare()` → `select.title`
10
+ * dot-path conventional field names schema title → type name.
12
11
  */
13
12
  export declare function resolvePreviewTitle(item: any, schema: SchemaType | null | undefined, defaultTypeLabel?: string): string;
14
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/lib/utils/preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAOzD;AAuBD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACrC,gBAAgB,CAAC,EAAE,MAAM,GACvB,MAAM,CAYR;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACrC,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,GACnC,MAAM,GAAG,IAAI,CAIf"}
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/lib/utils/preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAOzD;AA2CD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACrC,gBAAgB,CAAC,EAAE,MAAM,GACvB,MAAM,CAkBR;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACrC,IAAI,EAAE,GAAG,EACT,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,GACnC,MAAM,GAAG,IAAI,CAMf"}
@@ -32,25 +32,49 @@ function toPreviewString(value) {
32
32
  * — the first non-empty string wins.
33
33
  */
34
34
  const DEFAULT_TITLE_FIELDS = ['title', 'heading', 'name', 'label'];
35
+ /**
36
+ * Run `preview.prepare` if defined: resolve every dot-path in `select`,
37
+ * pass the resolved selection map to `prepare`, and return the result.
38
+ * Returns `null` when no `prepare` is configured — callers should fall
39
+ * back to direct `select.title` / `select.subtitle` reads in that case.
40
+ */
41
+ function runPrepare(item, schema) {
42
+ const prepare = schema?.preview?.prepare;
43
+ if (!prepare)
44
+ return null;
45
+ const select = schema?.preview?.select ?? {};
46
+ const selection = {};
47
+ for (const [key, path] of Object.entries(select)) {
48
+ selection[key] = readPath(item, path);
49
+ }
50
+ return prepare(selection);
51
+ }
35
52
  /**
36
53
  * Resolve the title to display for an item (array row, document list row,
37
- * reference picker row). Honors `schema.preview.select.title` first
38
- * (with dot-path support), then falls back to the conventional field
39
- * names, then the schema's own title, then the type name.
54
+ * reference picker row). Precedence: `preview.prepare()` → `select.title`
55
+ * dot-path conventional field names schema title → type name.
40
56
  */
41
57
  export function resolvePreviewTitle(item, schema, defaultTypeLabel) {
42
- const configured = schema?.preview?.select?.title;
43
- if (configured) {
44
- const resolved = toPreviewString(readPath(item, configured));
58
+ const prepared = runPrepare(item, schema);
59
+ if (prepared) {
60
+ const resolved = toPreviewString(prepared.title);
45
61
  if (resolved)
46
62
  return resolved;
47
63
  }
48
64
  else {
49
- for (const name of DEFAULT_TITLE_FIELDS) {
50
- const resolved = toPreviewString(item?.[name]);
65
+ const configured = schema?.preview?.select?.title;
66
+ if (configured) {
67
+ const resolved = toPreviewString(readPath(item, configured));
51
68
  if (resolved)
52
69
  return resolved;
53
70
  }
71
+ else {
72
+ for (const name of DEFAULT_TITLE_FIELDS) {
73
+ const resolved = toPreviewString(item?.[name]);
74
+ if (resolved)
75
+ return resolved;
76
+ }
77
+ }
54
78
  }
55
79
  return schema?.title ?? defaultTypeLabel ?? 'Untitled';
56
80
  }
@@ -60,6 +84,9 @@ export function resolvePreviewTitle(item, schema, defaultTypeLabel) {
60
84
  * should branch on the null and skip rendering the subtitle line.
61
85
  */
62
86
  export function resolvePreviewSubtitle(item, schema) {
87
+ const prepared = runPrepare(item, schema);
88
+ if (prepared)
89
+ return toPreviewString(prepared.subtitle);
63
90
  const configured = schema?.preview?.select?.subtitle;
64
91
  if (!configured)
65
92
  return null;
@@ -0,0 +1,8 @@
1
+ import type { SchemaType } from '../types/schemas.js';
2
+ /**
3
+ * Collect all referenced document IDs from a doc's data. The `schema` and
4
+ * `registry` params are accepted for API compatibility but no longer used —
5
+ * the unified ref shape makes them unnecessary.
6
+ */
7
+ export declare function collectReferenceIds(data: unknown, _schema?: SchemaType | null, _registry?: SchemaType[]): string[];
8
+ //# sourceMappingURL=reference-walk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference-walk.d.ts","sourceRoot":"","sources":["../../src/lib/utils/reference-walk.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,EAC3B,SAAS,CAAC,EAAE,UAAU,EAAE,GACtB,MAAM,EAAE,CAIV"}
@@ -0,0 +1,42 @@
1
+ // Walks a document's data and collects every reference's target ID. Both
2
+ // singular and array refs share the same on-disk shape now —
3
+ // `{ _type: 'reference', _ref }` — so this can be schema-less.
4
+ //
5
+ // Asset references (image/file) wrap an Asset, not a document, and aren't
6
+ // subject to the publish workflow — so they're skipped (we only collect
7
+ // ids whose marker is exactly 'reference').
8
+ /**
9
+ * Collect all referenced document IDs from a doc's data. The `schema` and
10
+ * `registry` params are accepted for API compatibility but no longer used —
11
+ * the unified ref shape makes them unnecessary.
12
+ */
13
+ export function collectReferenceIds(data, _schema, _registry) {
14
+ const ids = new Set();
15
+ walk(data, ids);
16
+ return Array.from(ids);
17
+ }
18
+ function walk(value, ids) {
19
+ if (value == null)
20
+ return;
21
+ if (Array.isArray(value)) {
22
+ for (const item of value)
23
+ walk(item, ids);
24
+ return;
25
+ }
26
+ if (typeof value !== 'object')
27
+ return;
28
+ const obj = value;
29
+ if (obj._type === 'reference' && typeof obj._ref === 'string' && obj._ref) {
30
+ ids.add(obj._ref);
31
+ return;
32
+ }
33
+ // Image/file fields store asset refs ({ _type:'image', asset:{_type:'reference', _ref} })
34
+ // that point to the assets table, not documents — skip them.
35
+ if (obj._type === 'image' || obj._type === 'file')
36
+ return;
37
+ for (const key of Object.keys(obj)) {
38
+ if (key.startsWith('_'))
39
+ continue;
40
+ walk(obj[key], ids);
41
+ }
42
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aphexcms/cms-core",
3
- "version": "7.0.0",
3
+ "version": "8.1.0",
4
4
  "description": "Aphex CMS Core - A Sanity-style CMS with ports and adapters architecture",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -81,7 +81,7 @@
81
81
  "svelte": "^5.44.0",
82
82
  "tailwind-merge": "^3.4.0",
83
83
  "tailwind-variants": "^3.2.2",
84
- "@aphexcms/ui": "0.6.0"
84
+ "@aphexcms/ui": "0.7.0"
85
85
  },
86
86
  "peerDependenciesMeta": {
87
87
  "graphql": {
@@ -130,7 +130,7 @@
130
130
  "prettier": "^3.6.2",
131
131
  "prettier-plugin-svelte": "^3.4.0",
132
132
  "prettier-plugin-tailwindcss": "^0.7.1",
133
- "svelte": "^5.44.0",
133
+ "svelte": "^5.55.5",
134
134
  "svelte-check": "^4.3.4",
135
135
  "tailwindcss": "^4.1.17",
136
136
  "typescript": "^5.9.3",