@forge-cms/runtime 0.3.0 → 0.5.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/globals.d.ts.map +1 -1
- package/dist/globals.js +25 -4
- package/dist/globals.js.map +1 -1
- package/dist/handlers.d.ts +13 -7
- package/dist/handlers.d.ts.map +1 -1
- package/dist/handlers.js +27 -52
- package/dist/handlers.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/operations.d.ts +50 -0
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +162 -57
- package/dist/operations.js.map +1 -1
- package/dist/populate.d.ts +23 -3
- package/dist/populate.d.ts.map +1 -1
- package/dist/populate.js +40 -8
- package/dist/populate.js.map +1 -1
- package/dist/read-policy.d.ts +35 -0
- package/dist/read-policy.d.ts.map +1 -0
- package/dist/read-policy.js +59 -0
- package/dist/read-policy.js.map +1 -0
- package/dist/relation-integrity.d.ts +70 -9
- package/dist/relation-integrity.d.ts.map +1 -1
- package/dist/relation-integrity.js +88 -59
- package/dist/relation-integrity.js.map +1 -1
- package/dist/runtime.d.ts +5 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +8 -29
- package/dist/runtime.js.map +1 -1
- package/dist/typed-api.d.ts +2 -2
- package/dist/typed-api.d.ts.map +1 -1
- package/dist/versions.d.ts +4 -6
- package/dist/versions.d.ts.map +1 -1
- package/dist/versions.js +56 -29
- package/dist/versions.js.map +1 -1
- package/package.json +7 -7
package/dist/versions.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { NotFoundError } from './errors.js';
|
|
2
|
+
import { documentMatches } from './access.js';
|
|
3
|
+
import { checkAccess, statusConstraint } from './read-policy.js';
|
|
4
|
+
import { filterReadableFields } from './field-access.js';
|
|
2
5
|
function getCollectionOrThrow(ctx, slug) {
|
|
3
6
|
const collection = ctx.getCollection(slug);
|
|
4
7
|
if (!collection)
|
|
@@ -15,6 +18,36 @@ function autosaveEnabled(collection) {
|
|
|
15
18
|
}
|
|
16
19
|
return false;
|
|
17
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* A version's history must not tell an untrusted caller anything about its owning document that the
|
|
23
|
+
* document's own read policy wouldn't already tell them (spec 058 §2 / maintainer brief §2). This
|
|
24
|
+
* mirrors `findByID`'s own owner-lookup: collection-level denial surfaces as `403` (matching a normal
|
|
25
|
+
* denied read), a missing owner or a row/draft mismatch surfaces as `404` (never confirms whether a
|
|
26
|
+
* hidden document exists), exactly like `findByID` already behaves for a single document by id.
|
|
27
|
+
*
|
|
28
|
+
* Only called when `overrideAccess === false` — a trusted Local API call skips this entirely, same as
|
|
29
|
+
* every other operation's `overrideAccess: true` default.
|
|
30
|
+
*/
|
|
31
|
+
async function assertOwnerReadable(ctx, collection, documentId, user) {
|
|
32
|
+
const owner = await ctx.adapters.database.findById(collection.slug, documentId);
|
|
33
|
+
if (!owner)
|
|
34
|
+
throw new NotFoundError(`Document '${documentId}' not found`);
|
|
35
|
+
const decision = await checkAccess(collection, 'read', {
|
|
36
|
+
user,
|
|
37
|
+
overrideAccess: false,
|
|
38
|
+
id: documentId,
|
|
39
|
+
doc: owner
|
|
40
|
+
});
|
|
41
|
+
if (decision.where && !documentMatches(owner, decision.where)) {
|
|
42
|
+
throw new NotFoundError(`Document '${documentId}' not found`);
|
|
43
|
+
}
|
|
44
|
+
// Matches `findByID`'s own default: a single document known by id is visible to any authenticated
|
|
45
|
+
// caller regardless of draft status; anonymous callers only ever see published documents.
|
|
46
|
+
const status = statusConstraint(collection, undefined, user, false, 'all');
|
|
47
|
+
if (status && !documentMatches(owner, status)) {
|
|
48
|
+
throw new NotFoundError(`Document '${documentId}' not found`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
18
51
|
/**
|
|
19
52
|
* Lists all versions of a document, newest first.
|
|
20
53
|
*/
|
|
@@ -23,6 +56,11 @@ export async function listVersions(ctx, args) {
|
|
|
23
56
|
if (!versionsEnabled(collection)) {
|
|
24
57
|
throw new Error(`Collection '${args.collection}' does not have versions enabled`);
|
|
25
58
|
}
|
|
59
|
+
const user = args.user ?? null;
|
|
60
|
+
const overrideAccess = args.overrideAccess !== false;
|
|
61
|
+
if (!overrideAccess) {
|
|
62
|
+
await assertOwnerReadable(ctx, collection, args.documentId, user);
|
|
63
|
+
}
|
|
26
64
|
const versionsCollection = `_versions_${args.collection}`;
|
|
27
65
|
const records = await ctx.adapters.database.findMany({
|
|
28
66
|
collection: versionsCollection,
|
|
@@ -32,10 +70,19 @@ export async function listVersions(ctx, args) {
|
|
|
32
70
|
...(args.limit !== undefined && { limit: args.limit }),
|
|
33
71
|
...(args.offset !== undefined && { offset: args.offset })
|
|
34
72
|
});
|
|
35
|
-
|
|
73
|
+
const versions = records.map(toVersion);
|
|
74
|
+
if (overrideAccess)
|
|
75
|
+
return versions;
|
|
76
|
+
return Promise.all(versions.map(async (version) => ({
|
|
77
|
+
...version,
|
|
78
|
+
data: await filterReadableFields(version.data, collection, user)
|
|
79
|
+
})));
|
|
36
80
|
}
|
|
37
81
|
/**
|
|
38
|
-
* Gets a specific version by id.
|
|
82
|
+
* Gets a specific version by id. `overrideAccess: true` (the default, matching every other Local API
|
|
83
|
+
* method) returns the raw, unfiltered snapshot with no owner-visibility check — used internally by
|
|
84
|
+
* {@link import('./operations.js').restoreVersion}, where the authoritative access gate is the
|
|
85
|
+
* subsequent `update()` call, not this read.
|
|
39
86
|
*/
|
|
40
87
|
export async function getVersion(ctx, args) {
|
|
41
88
|
const collection = getCollectionOrThrow(ctx, args.collection);
|
|
@@ -46,33 +93,13 @@ export async function getVersion(ctx, args) {
|
|
|
46
93
|
const record = await ctx.adapters.database.findById(versionsCollection, args.versionId);
|
|
47
94
|
if (!record)
|
|
48
95
|
throw new NotFoundError(`Version '${args.versionId}' not found`);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (!versionsEnabled(collection)) {
|
|
57
|
-
throw new Error(`Collection '${args.collection}' does not have versions enabled`);
|
|
58
|
-
}
|
|
59
|
-
const version = await getVersion(ctx, {
|
|
60
|
-
collection: args.collection,
|
|
61
|
-
versionId: args.versionId,
|
|
62
|
-
...(args.user !== undefined && { user: args.user }),
|
|
63
|
-
...(args.overrideAccess !== undefined && { overrideAccess: args.overrideAccess })
|
|
64
|
-
});
|
|
65
|
-
// Update the document with the version data
|
|
66
|
-
const record = await ctx.adapters.database.update(args.collection, version.documentId, version.data);
|
|
67
|
-
// Create a new version for the restore
|
|
68
|
-
await createVersion(ctx, {
|
|
69
|
-
collection: args.collection,
|
|
70
|
-
documentId: version.documentId,
|
|
71
|
-
data: version.data,
|
|
72
|
-
...(args.user !== undefined && { user: args.user }),
|
|
73
|
-
label: `Restored from version ${version.versionNumber}`
|
|
74
|
-
});
|
|
75
|
-
return record;
|
|
96
|
+
const version = toVersion(record);
|
|
97
|
+
const user = args.user ?? null;
|
|
98
|
+
const overrideAccess = args.overrideAccess !== false;
|
|
99
|
+
if (overrideAccess)
|
|
100
|
+
return version;
|
|
101
|
+
await assertOwnerReadable(ctx, collection, version.documentId, user);
|
|
102
|
+
return { ...version, data: await filterReadableFields(version.data, collection, user) };
|
|
76
103
|
}
|
|
77
104
|
/**
|
|
78
105
|
* Creates a new version of a document. Called automatically on updates when versions are enabled.
|
package/dist/versions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../src/versions.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../src/versions.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forge-cms/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Runtime orchestrator for ForgeCMS — binds schema, adapters, and handlers.",
|
|
5
5
|
"author": "ForgeCMS contributors",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@forge-cms/api": "0.
|
|
39
|
-
"@forge-cms/
|
|
40
|
-
"@forge-cms/
|
|
41
|
-
"@forge-cms/
|
|
42
|
-
"@forge-cms/
|
|
38
|
+
"@forge-cms/api": "0.5.0",
|
|
39
|
+
"@forge-cms/db": "0.5.0",
|
|
40
|
+
"@forge-cms/storage": "0.5.0",
|
|
41
|
+
"@forge-cms/core": "0.5.0",
|
|
42
|
+
"@forge-cms/auth": "0.5.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"typescript": "5.9.2",
|
|
46
|
-
"vitest": "
|
|
46
|
+
"vitest": "4.1.6"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "tsc -p tsconfig.build.json",
|