@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.
- package/dist/api/documents.d.ts +19 -0
- package/dist/api/documents.d.ts.map +1 -1
- package/dist/api/documents.js +21 -0
- package/dist/api/schemas/documents.d.ts +3 -0
- package/dist/api/schemas/documents.d.ts.map +1 -1
- package/dist/api/schemas/documents.js +12 -0
- package/dist/cli/generate-types.d.ts.map +1 -1
- package/dist/cli/generate-types.js +133 -19
- package/dist/cli/generate-types.js.map +1 -1
- package/dist/components/AdminApp.svelte +106 -52
- package/dist/components/AdminApp.svelte.d.ts.map +1 -1
- package/dist/components/admin/DocumentEditor.svelte +65 -2
- package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
- package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte +8 -6
- package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ArrayField.svelte +149 -2
- package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ReferenceField.svelte +198 -125
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts +9 -2
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
- package/dist/components/layout/Sidebar.svelte +1 -1
- package/dist/components/layout/sidebar/AppSidebar.svelte +2 -1
- package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts.map +1 -1
- package/dist/components/layout/sidebar/NavMain.svelte +9 -2
- package/dist/components/layout/sidebar/NavMain.svelte.d.ts +2 -0
- package/dist/components/layout/sidebar/NavMain.svelte.d.ts.map +1 -1
- package/dist/db/interfaces/index.d.ts +3 -1
- package/dist/db/interfaces/index.d.ts.map +1 -1
- package/dist/db/interfaces/reference.d.ts +43 -0
- package/dist/db/interfaces/reference.d.ts.map +1 -0
- package/dist/db/interfaces/reference.js +4 -0
- package/dist/db/utils/reference-resolver.d.ts +4 -6
- package/dist/db/utils/reference-resolver.d.ts.map +1 -1
- package/dist/db/utils/reference-resolver.js +33 -31
- package/dist/document-refresh.svelte.d.ts +3 -0
- package/dist/document-refresh.svelte.d.ts.map +1 -0
- package/dist/document-refresh.svelte.js +21 -0
- package/dist/graphql/resolvers.d.ts.map +1 -1
- package/dist/graphql/resolvers.js +61 -1
- package/dist/graphql/schema.d.ts.map +1 -1
- package/dist/graphql/schema.js +10 -0
- package/dist/lib/api/documents.d.ts +19 -0
- package/dist/lib/api/documents.d.ts.map +1 -1
- package/dist/lib/api/documents.js +21 -0
- package/dist/lib/api/documents.js.map +1 -1
- package/dist/lib/api/schemas/documents.d.ts +3 -0
- package/dist/lib/api/schemas/documents.d.ts.map +1 -1
- package/dist/lib/api/schemas/documents.js +12 -0
- package/dist/lib/api/schemas/documents.js.map +1 -1
- package/dist/lib/db/interfaces/index.d.ts +3 -1
- package/dist/lib/db/interfaces/index.d.ts.map +1 -1
- package/dist/lib/db/interfaces/reference.d.ts +43 -0
- package/dist/lib/db/interfaces/reference.d.ts.map +1 -0
- package/dist/lib/db/interfaces/reference.js +5 -0
- package/dist/lib/db/interfaces/reference.js.map +1 -0
- package/dist/lib/db/utils/reference-resolver.d.ts +4 -6
- package/dist/lib/db/utils/reference-resolver.d.ts.map +1 -1
- package/dist/lib/db/utils/reference-resolver.js +33 -31
- package/dist/lib/db/utils/reference-resolver.js.map +1 -1
- package/dist/lib/document-refresh.svelte.d.ts +3 -0
- package/dist/lib/document-refresh.svelte.d.ts.map +1 -0
- package/dist/lib/document-refresh.svelte.js +22 -0
- package/dist/lib/document-refresh.svelte.js.map +1 -0
- package/dist/lib/graphql/resolvers.d.ts.map +1 -1
- package/dist/lib/graphql/resolvers.js +61 -1
- package/dist/lib/graphql/resolvers.js.map +1 -1
- package/dist/lib/graphql/schema.d.ts.map +1 -1
- package/dist/lib/graphql/schema.js +10 -0
- package/dist/lib/graphql/schema.js.map +1 -1
- package/dist/lib/local-api/collection-api.d.ts +10 -1
- package/dist/lib/local-api/collection-api.d.ts.map +1 -1
- package/dist/lib/local-api/collection-api.js +39 -1
- package/dist/lib/local-api/collection-api.js.map +1 -1
- package/dist/lib/local-api/index.d.ts +29 -0
- package/dist/lib/local-api/index.d.ts.map +1 -1
- package/dist/lib/local-api/index.js +66 -2
- package/dist/lib/local-api/index.js.map +1 -1
- package/dist/lib/schema-utils/validator.js +21 -11
- package/dist/lib/schema-utils/validator.js.map +1 -1
- package/dist/lib/server/api/index.d.ts.map +1 -1
- package/dist/lib/server/api/index.js +3 -1
- package/dist/lib/server/api/index.js.map +1 -1
- package/dist/lib/server/api/routes/documents-by-id.d.ts.map +1 -1
- package/dist/lib/server/api/routes/documents-by-id.js +23 -0
- package/dist/lib/server/api/routes/documents-by-id.js.map +1 -1
- package/dist/lib/server/api/routes/documents.d.ts.map +1 -1
- package/dist/lib/server/api/routes/documents.js +29 -1
- package/dist/lib/server/api/routes/documents.js.map +1 -1
- package/dist/lib/services/references-service.d.ts +35 -0
- package/dist/lib/services/references-service.d.ts.map +1 -0
- package/dist/lib/services/references-service.js +60 -0
- package/dist/lib/services/references-service.js.map +1 -0
- package/dist/lib/types/schemas.d.ts +8 -0
- package/dist/lib/types/schemas.d.ts.map +1 -1
- package/dist/lib/utils/preview.d.ts +2 -3
- package/dist/lib/utils/preview.d.ts.map +1 -1
- package/dist/lib/utils/preview.js +35 -8
- package/dist/lib/utils/preview.js.map +1 -1
- package/dist/lib/utils/reference-walk.d.ts +8 -0
- package/dist/lib/utils/reference-walk.d.ts.map +1 -0
- package/dist/lib/utils/reference-walk.js +43 -0
- package/dist/lib/utils/reference-walk.js.map +1 -0
- package/dist/local-api/collection-api.d.ts +10 -1
- package/dist/local-api/collection-api.d.ts.map +1 -1
- package/dist/local-api/collection-api.js +39 -1
- package/dist/local-api/index.d.ts +29 -0
- package/dist/local-api/index.d.ts.map +1 -1
- package/dist/local-api/index.js +66 -2
- package/dist/schema-utils/validator.js +21 -11
- package/dist/server/api/index.d.ts.map +1 -1
- package/dist/server/api/index.js +3 -1
- package/dist/server/api/routes/documents-by-id.d.ts.map +1 -1
- package/dist/server/api/routes/documents-by-id.js +23 -0
- package/dist/server/api/routes/documents.d.ts.map +1 -1
- package/dist/server/api/routes/documents.js +29 -1
- package/dist/services/references-service.d.ts +35 -0
- package/dist/services/references-service.d.ts.map +1 -0
- package/dist/services/references-service.js +59 -0
- package/dist/types/schemas.d.ts +8 -0
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/utils/preview.d.ts +2 -3
- package/dist/utils/preview.d.ts.map +1 -1
- package/dist/utils/preview.js +35 -8
- package/dist/utils/reference-walk.d.ts +8 -0
- package/dist/utils/reference-walk.d.ts.map +1 -0
- package/dist/utils/reference-walk.js +42 -0
- package/package.json +3 -3
package/dist/local-api/index.js
CHANGED
|
@@ -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
|
-
|
|
127
|
-
!
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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,
|
|
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"}
|
package/dist/server/api/index.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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;
|
|
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
|
+
}
|
package/dist/types/schemas.d.ts
CHANGED
|
@@ -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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"}
|
package/dist/utils/preview.d.ts
CHANGED
|
@@ -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).
|
|
10
|
-
*
|
|
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;
|
|
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"}
|
package/dist/utils/preview.js
CHANGED
|
@@ -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).
|
|
38
|
-
*
|
|
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
|
|
43
|
-
if (
|
|
44
|
-
const resolved = toPreviewString(
|
|
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
|
-
|
|
50
|
-
|
|
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": "
|
|
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.
|
|
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.
|
|
133
|
+
"svelte": "^5.55.5",
|
|
134
134
|
"svelte-check": "^4.3.4",
|
|
135
135
|
"tailwindcss": "^4.1.17",
|
|
136
136
|
"typescript": "^5.9.3",
|