@btst/stack 5.0.0 → 5.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/index.d.cts +2 -2
- package/dist/api/index.d.mts +2 -2
- package/dist/api/index.d.ts +2 -2
- package/dist/client/index.d.cts +2 -2
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/context/index.d.cts +1 -1
- package/dist/context/index.d.mts +1 -1
- package/dist/context/index.d.ts +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/packages/stack/src/plugins/cms/api/getters.cjs +142 -6
- package/dist/packages/stack/src/plugins/cms/api/getters.mjs +139 -8
- package/dist/packages/stack/src/plugins/cms/api/operations.cjs +67 -61
- package/dist/packages/stack/src/plugins/cms/api/operations.mjs +69 -63
- package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +26 -8
- package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +27 -9
- package/dist/packages/stack/src/plugins/cms/api/query-key-defs.cjs +15 -1
- package/dist/packages/stack/src/plugins/cms/api/query-key-defs.mjs +14 -2
- package/dist/packages/stack/src/plugins/cms/client/hooks/cms-hooks.cjs +45 -24
- package/dist/packages/stack/src/plugins/cms/client/hooks/cms-hooks.mjs +45 -24
- package/dist/packages/stack/src/plugins/cms/schemas.cjs +22 -0
- package/dist/packages/stack/src/plugins/cms/schemas.mjs +20 -1
- package/dist/plugins/api/index.d.cts +2 -2
- package/dist/plugins/api/index.d.mts +2 -2
- package/dist/plugins/api/index.d.ts +2 -2
- package/dist/plugins/blog/api/index.d.cts +2 -2
- package/dist/plugins/blog/api/index.d.mts +2 -2
- package/dist/plugins/blog/api/index.d.ts +2 -2
- package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
- package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
- package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
- package/dist/plugins/blog/client/index.d.cts +2 -2
- package/dist/plugins/blog/client/index.d.mts +2 -2
- package/dist/plugins/blog/client/index.d.ts +2 -2
- package/dist/plugins/blog/query-keys.d.cts +2 -2
- package/dist/plugins/blog/query-keys.d.mts +2 -2
- package/dist/plugins/blog/query-keys.d.ts +2 -2
- package/dist/plugins/client/index.d.cts +2 -2
- package/dist/plugins/client/index.d.mts +2 -2
- package/dist/plugins/client/index.d.ts +2 -2
- package/dist/plugins/cms/api/index.cjs +1 -0
- package/dist/plugins/cms/api/index.d.cts +43 -11
- package/dist/plugins/cms/api/index.d.mts +43 -11
- package/dist/plugins/cms/api/index.d.ts +43 -11
- package/dist/plugins/cms/api/index.mjs +1 -1
- package/dist/plugins/cms/client/hooks/index.d.cts +90 -45
- package/dist/plugins/cms/client/hooks/index.d.mts +90 -45
- package/dist/plugins/cms/client/hooks/index.d.ts +90 -45
- package/dist/plugins/cms/client/index.d.cts +2 -1
- package/dist/plugins/cms/client/index.d.mts +2 -1
- package/dist/plugins/cms/client/index.d.ts +2 -1
- package/dist/plugins/cms/query-keys.cjs +69 -13
- package/dist/plugins/cms/query-keys.d.cts +89 -212
- package/dist/plugins/cms/query-keys.d.mts +89 -212
- package/dist/plugins/cms/query-keys.d.ts +89 -212
- package/dist/plugins/cms/query-keys.mjs +70 -14
- package/dist/plugins/kanban/client/index.d.cts +1 -1
- package/dist/plugins/kanban/client/index.d.mts +1 -1
- package/dist/plugins/kanban/client/index.d.ts +1 -1
- package/dist/plugins/route-docs/client/index.d.cts +1 -1
- package/dist/plugins/route-docs/client/index.d.mts +1 -1
- package/dist/plugins/route-docs/client/index.d.ts +1 -1
- package/dist/plugins/ui-builder/client/hooks/index.d.cts +3 -3
- package/dist/plugins/ui-builder/client/hooks/index.d.mts +3 -3
- package/dist/plugins/ui-builder/client/hooks/index.d.ts +3 -3
- package/dist/plugins/ui-builder/client/index.d.cts +3 -3
- package/dist/plugins/ui-builder/client/index.d.mts +3 -3
- package/dist/plugins/ui-builder/client/index.d.ts +3 -3
- package/dist/plugins/ui-builder/query-keys.d.cts +4 -3
- package/dist/plugins/ui-builder/query-keys.d.mts +4 -3
- package/dist/plugins/ui-builder/query-keys.d.ts +4 -3
- package/dist/shared/{stack.DMj68qY0.d.mts → stack.B2jlVVhD.d.mts} +5 -5
- package/dist/shared/{stack.Cvnj99cs.d.ts → stack.BB9tubJJ.d.ts} +9 -3
- package/dist/shared/{stack.Bt3WG2yb.d.cts → stack.BWduIMKG.d.cts} +35 -35
- package/dist/shared/stack.Bw09Lg2z.d.ts +1420 -0
- package/dist/shared/{stack.CkEz7vSt.d.mts → stack.C2Pvl-RS.d.mts} +9 -3
- package/dist/shared/{stack.C2l2wd_X.d.ts → stack.Ch9-ppmQ.d.ts} +35 -35
- package/dist/shared/{stack.Ht8mhDj5.d.cts → stack.D17yFglU.d.cts} +5 -5
- package/dist/shared/{stack.CiD115Ov.d.mts → stack.D6fPBfYe.d.mts} +35 -35
- package/dist/shared/stack.DFGj0gb7.d.mts +1420 -0
- package/dist/shared/{stack.pi0FxoEa.d.ts → stack.Dcfg4GNN.d.ts} +5 -5
- package/dist/shared/{stack.3rxARhgS.d.cts → stack.DrB3L7Ih.d.cts} +52 -3
- package/dist/shared/{stack.3rxARhgS.d.mts → stack.DrB3L7Ih.d.mts} +52 -3
- package/dist/shared/{stack.3rxARhgS.d.ts → stack.DrB3L7Ih.d.ts} +52 -3
- package/dist/shared/stack.NNrBKBkM.d.cts +1420 -0
- package/dist/shared/{stack.mRRyZBUg.d.cts → stack.Rb87lHqK.d.cts} +9 -3
- package/package.json +1 -1
- package/src/__tests__/cms-query-keys.test.ts +57 -0
- package/src/plugins/api/index.ts +1 -0
- package/src/plugins/api/operation.ts +16 -3
- package/src/plugins/cms/__tests__/authorization.test.ts +652 -187
- package/src/plugins/cms/__tests__/client-runtime.browser.test.tsx +655 -0
- package/src/plugins/cms/__tests__/content-read.typecheck.ts +351 -0
- package/src/plugins/cms/__tests__/getters.test.ts +286 -0
- package/src/plugins/cms/api/getters.ts +270 -12
- package/src/plugins/cms/api/index.ts +10 -0
- package/src/plugins/cms/api/operations.ts +163 -75
- package/src/plugins/cms/api/plugin.ts +50 -12
- package/src/plugins/cms/api/query-key-defs.ts +29 -2
- package/src/plugins/cms/client/hooks/cms-hooks.tsx +400 -91
- package/src/plugins/cms/client/index.ts +9 -0
- package/src/plugins/cms/query-keys.ts +171 -16
- package/src/plugins/cms/schemas.ts +30 -0
- package/src/plugins/cms/types.ts +49 -2
- package/src/plugins/media/__tests__/identity-partition.test.tsx +26 -16
- package/dist/shared/stack.CAmVUwjV.d.cts +0 -764
- package/dist/shared/stack.CQK02ujt.d.ts +0 -764
- package/dist/shared/stack.D9x1fR5a.d.mts +0 -764
- package/dist/shared/{stack.CKc_Bais.d.cts → stack.Csi-4Mgz.d.cts} +7 -7
- package/dist/shared/{stack.CKc_Bais.d.mts → stack.Csi-4Mgz.d.mts} +7 -7
- package/dist/shared/{stack.CKc_Bais.d.ts → stack.Csi-4Mgz.d.ts} +7 -7
package/dist/api/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BackendPlugin,
|
|
2
|
-
export { S as StackContext } from '../shared/stack.
|
|
1
|
+
import { B as BackendPlugin, W as PrefixedPluginRoutes, X as BackendStackConfig, Y as CompatibleStackAuth, Z as BackendStack, _ as PluginRaw, $ as PluginOperations } from '../shared/stack.Rb87lHqK.cjs';
|
|
2
|
+
export { S as StackContext } from '../shared/stack.Rb87lHqK.cjs';
|
|
3
3
|
import { AnyAuthorization } from '../authorization/index.cjs';
|
|
4
4
|
import { ServerAuth } from '../authorization/server.cjs';
|
|
5
5
|
export { toNodeHandler } from 'better-call/node';
|
package/dist/api/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BackendPlugin,
|
|
2
|
-
export { S as StackContext } from '../shared/stack.
|
|
1
|
+
import { B as BackendPlugin, W as PrefixedPluginRoutes, X as BackendStackConfig, Y as CompatibleStackAuth, Z as BackendStack, _ as PluginRaw, $ as PluginOperations } from '../shared/stack.C2Pvl-RS.mjs';
|
|
2
|
+
export { S as StackContext } from '../shared/stack.C2Pvl-RS.mjs';
|
|
3
3
|
import { AnyAuthorization } from '../authorization/index.mjs';
|
|
4
4
|
import { ServerAuth } from '../authorization/server.mjs';
|
|
5
5
|
export { toNodeHandler } from 'better-call/node';
|
package/dist/api/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BackendPlugin,
|
|
2
|
-
export { S as StackContext } from '../shared/stack.
|
|
1
|
+
import { B as BackendPlugin, W as PrefixedPluginRoutes, X as BackendStackConfig, Y as CompatibleStackAuth, Z as BackendStack, _ as PluginRaw, $ as PluginOperations } from '../shared/stack.BB9tubJJ.js';
|
|
2
|
+
export { S as StackContext } from '../shared/stack.BB9tubJJ.js';
|
|
3
3
|
import { AnyAuthorization } from '../authorization/index.js';
|
|
4
4
|
import { ServerAuth } from '../authorization/server.js';
|
|
5
5
|
export { toNodeHandler } from 'better-call/node';
|
package/dist/client/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { t as Sitemap, r as ClientPluginRegistration, u as PluginRoutes, v as ClientStackConfig, w as ResolvedClientStack } from '../shared/stack.Rb87lHqK.cjs';
|
|
2
|
+
export { x as ClientApiConfig, y as ClientApiEndpointOverride, z as ClientLocation, E as ClientLocationOverride, C as ClientPlugin, q as ClientPluginDefinition, F as ClientPluginEndpointOverride, G as ClientPluginEndpointOverrides, H as ClientProviderApi, J as ClientProviderPluginRuntime, K as ClientProviderProjection, L as ClientStack, M as ClientStackContext, N as ResolvedClientApi, s as ResolvedClientPluginRuntime, Q as ResolvedClientStackConfig } from '../shared/stack.Rb87lHqK.cjs';
|
|
3
3
|
export { I as InferListState, a as ListStateField, L as ListStateSchema, S as SetListState, b as SetListStateOptions, l as listStateParamKey, p as parseListStateFromSearchParams, r as resolveListStateHistoryMode, s as serializeListStateToSearchParams } from '../shared/stack.D26sFqSV.cjs';
|
|
4
4
|
import '@btst/yar';
|
|
5
5
|
import '@tanstack/react-query';
|
package/dist/client/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { t as Sitemap, r as ClientPluginRegistration, u as PluginRoutes, v as ClientStackConfig, w as ResolvedClientStack } from '../shared/stack.C2Pvl-RS.mjs';
|
|
2
|
+
export { x as ClientApiConfig, y as ClientApiEndpointOverride, z as ClientLocation, E as ClientLocationOverride, C as ClientPlugin, q as ClientPluginDefinition, F as ClientPluginEndpointOverride, G as ClientPluginEndpointOverrides, H as ClientProviderApi, J as ClientProviderPluginRuntime, K as ClientProviderProjection, L as ClientStack, M as ClientStackContext, N as ResolvedClientApi, s as ResolvedClientPluginRuntime, Q as ResolvedClientStackConfig } from '../shared/stack.C2Pvl-RS.mjs';
|
|
3
3
|
export { I as InferListState, a as ListStateField, L as ListStateSchema, S as SetListState, b as SetListStateOptions, l as listStateParamKey, p as parseListStateFromSearchParams, r as resolveListStateHistoryMode, s as serializeListStateToSearchParams } from '../shared/stack.D26sFqSV.mjs';
|
|
4
4
|
import '@btst/yar';
|
|
5
5
|
import '@tanstack/react-query';
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { t as Sitemap, r as ClientPluginRegistration, u as PluginRoutes, v as ClientStackConfig, w as ResolvedClientStack } from '../shared/stack.BB9tubJJ.js';
|
|
2
|
+
export { x as ClientApiConfig, y as ClientApiEndpointOverride, z as ClientLocation, E as ClientLocationOverride, C as ClientPlugin, q as ClientPluginDefinition, F as ClientPluginEndpointOverride, G as ClientPluginEndpointOverrides, H as ClientProviderApi, J as ClientProviderPluginRuntime, K as ClientProviderProjection, L as ClientStack, M as ClientStackContext, N as ResolvedClientApi, s as ResolvedClientPluginRuntime, Q as ResolvedClientStackConfig } from '../shared/stack.BB9tubJJ.js';
|
|
3
3
|
export { I as InferListState, a as ListStateField, L as ListStateSchema, S as SetListState, b as SetListStateOptions, l as listStateParamKey, p as parseListStateFromSearchParams, r as resolveListStateHistoryMode, s as serializeListStateToSearchParams } from '../shared/stack.D26sFqSV.js';
|
|
4
4
|
import '@btst/yar';
|
|
5
5
|
import '@tanstack/react-query';
|
package/dist/context/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
3
|
import { QueryClient } from '@tanstack/react-query';
|
|
4
|
-
import {
|
|
4
|
+
import { U as InferredPluginOverrides, V as RegisteredClientPlugins } from '../shared/stack.Rb87lHqK.cjs';
|
|
5
5
|
import { ResolvedClientStack, ClientLocation, ClientProviderPluginRuntime, ClientStackContext } from '../client/index.cjs';
|
|
6
6
|
import { S as StackClientAuth, a as StackIdentity } from '../shared/stack.BYMentwB.cjs';
|
|
7
7
|
import { a as StackRouterConfig, b as StackRouter, c as StackApiConfig, d as StackClientLike } from '../shared/stack.BRvqQWGt.cjs';
|
package/dist/context/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
3
|
import { QueryClient } from '@tanstack/react-query';
|
|
4
|
-
import {
|
|
4
|
+
import { U as InferredPluginOverrides, V as RegisteredClientPlugins } from '../shared/stack.C2Pvl-RS.mjs';
|
|
5
5
|
import { ResolvedClientStack, ClientLocation, ClientProviderPluginRuntime, ClientStackContext } from '../client/index.mjs';
|
|
6
6
|
import { S as StackClientAuth, a as StackIdentity } from '../shared/stack.BYMentwB.mjs';
|
|
7
7
|
import { a as StackRouterConfig, b as StackRouter, c as StackApiConfig, d as StackClientLike } from '../shared/stack.BRvqQWGt.mjs';
|
package/dist/context/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ReactElement } from 'react';
|
|
3
3
|
import { QueryClient } from '@tanstack/react-query';
|
|
4
|
-
import {
|
|
4
|
+
import { U as InferredPluginOverrides, V as RegisteredClientPlugins } from '../shared/stack.BB9tubJJ.js';
|
|
5
5
|
import { ResolvedClientStack, ClientLocation, ClientProviderPluginRuntime, ClientStackContext } from '../client/index.js';
|
|
6
6
|
import { S as StackClientAuth, a as StackIdentity } from '../shared/stack.BYMentwB.js';
|
|
7
7
|
import { a as StackRouterConfig, b as StackRouter, c as StackApiConfig, d as StackClientLike } from '../shared/stack.BRvqQWGt.js';
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createBackendStack } from './api/index.cjs';
|
|
2
|
-
export { B as BackendPlugin,
|
|
2
|
+
export { B as BackendPlugin, Z as BackendStack, X as BackendStackConfig, $ as PluginOperations, _ as PluginRaw, S as StackContext } from './shared/stack.Rb87lHqK.cjs';
|
|
3
3
|
export { a as StackIdentity } from './shared/stack.BYMentwB.cjs';
|
|
4
4
|
export { toNodeHandler } from 'better-call/node';
|
|
5
5
|
import './authorization/index.cjs';
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createBackendStack } from './api/index.mjs';
|
|
2
|
-
export { B as BackendPlugin,
|
|
2
|
+
export { B as BackendPlugin, Z as BackendStack, X as BackendStackConfig, $ as PluginOperations, _ as PluginRaw, S as StackContext } from './shared/stack.C2Pvl-RS.mjs';
|
|
3
3
|
export { a as StackIdentity } from './shared/stack.BYMentwB.mjs';
|
|
4
4
|
export { toNodeHandler } from 'better-call/node';
|
|
5
5
|
import './authorization/index.mjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createBackendStack } from './api/index.js';
|
|
2
|
-
export { B as BackendPlugin,
|
|
2
|
+
export { B as BackendPlugin, Z as BackendStack, X as BackendStackConfig, $ as PluginOperations, _ as PluginRaw, S as StackContext } from './shared/stack.BB9tubJJ.js';
|
|
3
3
|
export { a as StackIdentity } from './shared/stack.BYMentwB.js';
|
|
4
4
|
export { toNodeHandler } from 'better-call/node';
|
|
5
5
|
import './authorization/index.js';
|
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
const schemas = require('../schemas.cjs');
|
|
4
4
|
|
|
5
|
+
class CMSContentSelectionError extends Error {
|
|
6
|
+
}
|
|
7
|
+
function validateContentReadOptions(contentType, options) {
|
|
8
|
+
schemas.contentReadOptionsSchema.parse(options ?? {});
|
|
9
|
+
if (options?.fields === void 0) return;
|
|
10
|
+
if (options.view !== "content") {
|
|
11
|
+
throw new CMSContentSelectionError("fields requires view: content");
|
|
12
|
+
}
|
|
13
|
+
const properties = contentType ? JSON.parse(contentType.jsonSchema).properties : void 0;
|
|
14
|
+
for (const field of options.fields) {
|
|
15
|
+
if (!properties || !Object.hasOwn(properties, field)) {
|
|
16
|
+
throw new CMSContentSelectionError(
|
|
17
|
+
`Unknown top-level content field: ${field}`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function applyContentReadOptions(item, options) {
|
|
23
|
+
const result = options?.view === "content" ? {
|
|
24
|
+
id: item.id,
|
|
25
|
+
slug: item.slug,
|
|
26
|
+
parsedData: options.fields ? Object.fromEntries(
|
|
27
|
+
schemas.normalizeContentFields(options.fields).filter((field) => Object.hasOwn(item.parsedData, field)).map((field) => [
|
|
28
|
+
field,
|
|
29
|
+
item.parsedData[field]
|
|
30
|
+
])
|
|
31
|
+
) : item.parsedData,
|
|
32
|
+
createdAt: item.createdAt,
|
|
33
|
+
updatedAt: item.updatedAt
|
|
34
|
+
} : item;
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
5
37
|
function serializeContentType(ct) {
|
|
6
38
|
const needsMigration = !ct.autoFormVersion || ct.autoFormVersion < 2;
|
|
7
39
|
const migratedJsonSchema = needsMigration ? migrateToUnifiedSchema(ct.jsonSchema, ct.fieldConfig) : ct.jsonSchema;
|
|
@@ -86,6 +118,7 @@ async function getAllContentItems(adapter, contentTypeSlug, params) {
|
|
|
86
118
|
offset: params?.offset
|
|
87
119
|
};
|
|
88
120
|
}
|
|
121
|
+
validateContentReadOptions(contentType, params);
|
|
89
122
|
const whereConditions = [
|
|
90
123
|
{
|
|
91
124
|
field: "contentTypeId",
|
|
@@ -128,29 +161,30 @@ async function getAllContentItems(adapter, contentTypeSlug, params) {
|
|
|
128
161
|
limit !== void 0 ? offset + limit : void 0
|
|
129
162
|
);
|
|
130
163
|
return {
|
|
131
|
-
items: result,
|
|
164
|
+
items: result.map((item) => applyContentReadOptions(item, params)),
|
|
132
165
|
total,
|
|
133
166
|
limit: params?.limit,
|
|
134
167
|
offset: params?.offset
|
|
135
168
|
};
|
|
136
169
|
}
|
|
137
170
|
return {
|
|
138
|
-
items: result,
|
|
171
|
+
items: result.map((item) => applyContentReadOptions(item, params)),
|
|
139
172
|
total: dbTotal ?? result.length,
|
|
140
173
|
limit: params?.limit,
|
|
141
174
|
offset: params?.offset
|
|
142
175
|
};
|
|
143
176
|
}
|
|
144
|
-
async function getContentItemById(adapter, id) {
|
|
177
|
+
async function getContentItemById(adapter, id, options) {
|
|
145
178
|
const item = await adapter.findOne({
|
|
146
179
|
model: "contentItem",
|
|
147
180
|
where: [{ field: "id", value: id, operator: "eq" }],
|
|
148
181
|
join: { contentType: true }
|
|
149
182
|
});
|
|
150
183
|
if (!item) return null;
|
|
151
|
-
|
|
184
|
+
validateContentReadOptions(item.contentType, options);
|
|
185
|
+
return applyContentReadOptions(serializeContentItemWithType(item), options);
|
|
152
186
|
}
|
|
153
|
-
async function getContentItemBySlug(adapter, contentTypeSlug, slug) {
|
|
187
|
+
async function getContentItemBySlug(adapter, contentTypeSlug, slug, options) {
|
|
154
188
|
const contentType = await adapter.findOne({
|
|
155
189
|
model: "contentType",
|
|
156
190
|
where: [
|
|
@@ -164,6 +198,7 @@ async function getContentItemBySlug(adapter, contentTypeSlug, slug) {
|
|
|
164
198
|
if (!contentType) {
|
|
165
199
|
return null;
|
|
166
200
|
}
|
|
201
|
+
validateContentReadOptions(contentType, options);
|
|
167
202
|
const item = await adapter.findOne({
|
|
168
203
|
model: "contentItem",
|
|
169
204
|
where: [
|
|
@@ -179,14 +214,115 @@ async function getContentItemBySlug(adapter, contentTypeSlug, slug) {
|
|
|
179
214
|
if (!item) {
|
|
180
215
|
return null;
|
|
181
216
|
}
|
|
182
|
-
return serializeContentItemWithType(item);
|
|
217
|
+
return applyContentReadOptions(serializeContentItemWithType(item), options);
|
|
218
|
+
}
|
|
219
|
+
async function getContentItemsByRelation(adapter, contentTypeSlug, params) {
|
|
220
|
+
const contentType = await adapter.findOne({
|
|
221
|
+
model: "contentType",
|
|
222
|
+
where: [{ field: "slug", value: contentTypeSlug, operator: "eq" }]
|
|
223
|
+
});
|
|
224
|
+
if (!contentType) {
|
|
225
|
+
return {
|
|
226
|
+
items: [],
|
|
227
|
+
total: 0,
|
|
228
|
+
limit: params.limit ?? 20,
|
|
229
|
+
offset: params.offset ?? 0
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
validateContentReadOptions(contentType, params);
|
|
233
|
+
const result = await getContentItemsByRelationForType(
|
|
234
|
+
adapter,
|
|
235
|
+
contentType,
|
|
236
|
+
params
|
|
237
|
+
);
|
|
238
|
+
return {
|
|
239
|
+
...result,
|
|
240
|
+
items: result.items.map((item) => applyContentReadOptions(item, params))
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
async function getContentItemsByRelationForType(adapter, contentType, params) {
|
|
244
|
+
const limit = params.limit ?? 20;
|
|
245
|
+
const offset = params.offset ?? 0;
|
|
246
|
+
const batchSize = 100;
|
|
247
|
+
const sourceIds = /* @__PURE__ */ new Set();
|
|
248
|
+
for (let relationOffset = 0; ; relationOffset += batchSize) {
|
|
249
|
+
const relations = await adapter.findMany(
|
|
250
|
+
{
|
|
251
|
+
model: "contentRelation",
|
|
252
|
+
where: [
|
|
253
|
+
{ field: "targetId", value: params.targetId, operator: "eq" },
|
|
254
|
+
{ field: "fieldName", value: params.field, operator: "eq" }
|
|
255
|
+
],
|
|
256
|
+
select: ["sourceId"],
|
|
257
|
+
limit: batchSize,
|
|
258
|
+
offset: relationOffset,
|
|
259
|
+
sortBy: { field: "id", direction: "asc" }
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
for (const relation of relations) sourceIds.add(relation.sourceId);
|
|
263
|
+
if (relations.length < batchSize) break;
|
|
264
|
+
}
|
|
265
|
+
const ids = [...sourceIds];
|
|
266
|
+
const metadata = [];
|
|
267
|
+
for (let start = 0; start < ids.length; start += batchSize) {
|
|
268
|
+
metadata.push(
|
|
269
|
+
...await adapter.findMany({
|
|
270
|
+
model: "contentItem",
|
|
271
|
+
where: [
|
|
272
|
+
{
|
|
273
|
+
field: "id",
|
|
274
|
+
value: ids.slice(start, start + batchSize),
|
|
275
|
+
operator: "in"
|
|
276
|
+
},
|
|
277
|
+
{ field: "contentTypeId", value: contentType.id, operator: "eq" }
|
|
278
|
+
],
|
|
279
|
+
select: ["id", "createdAt"],
|
|
280
|
+
limit: batchSize
|
|
281
|
+
})
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
metadata.sort(
|
|
285
|
+
(left, right) => right.createdAt.getTime() - left.createdAt.getTime() || (left.id < right.id ? 1 : left.id > right.id ? -1 : 0)
|
|
286
|
+
);
|
|
287
|
+
const pageIds = metadata.slice(offset, offset + limit).map((item) => item.id);
|
|
288
|
+
const itemsById = /* @__PURE__ */ new Map();
|
|
289
|
+
for (let start = 0; start < pageIds.length; start += batchSize) {
|
|
290
|
+
const items = await adapter.findMany({
|
|
291
|
+
model: "contentItem",
|
|
292
|
+
where: [
|
|
293
|
+
{
|
|
294
|
+
field: "id",
|
|
295
|
+
value: pageIds.slice(start, start + batchSize),
|
|
296
|
+
operator: "in"
|
|
297
|
+
},
|
|
298
|
+
{ field: "contentTypeId", value: contentType.id, operator: "eq" }
|
|
299
|
+
],
|
|
300
|
+
limit: batchSize,
|
|
301
|
+
join: { contentType: true }
|
|
302
|
+
});
|
|
303
|
+
for (const item of items) itemsById.set(item.id, item);
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
items: pageIds.flatMap((id) => {
|
|
307
|
+
const item = itemsById.get(id);
|
|
308
|
+
return item ? [serializeContentItemWithType(item)] : [];
|
|
309
|
+
}),
|
|
310
|
+
total: metadata.length,
|
|
311
|
+
limit,
|
|
312
|
+
offset
|
|
313
|
+
};
|
|
183
314
|
}
|
|
184
315
|
|
|
316
|
+
exports.CMSContentSelectionError = CMSContentSelectionError;
|
|
317
|
+
exports.applyContentReadOptions = applyContentReadOptions;
|
|
185
318
|
exports.getAllContentItems = getAllContentItems;
|
|
186
319
|
exports.getAllContentTypes = getAllContentTypes;
|
|
187
320
|
exports.getContentItemById = getContentItemById;
|
|
188
321
|
exports.getContentItemBySlug = getContentItemBySlug;
|
|
322
|
+
exports.getContentItemsByRelation = getContentItemsByRelation;
|
|
323
|
+
exports.getContentItemsByRelationForType = getContentItemsByRelationForType;
|
|
189
324
|
exports.migrateToUnifiedSchema = migrateToUnifiedSchema;
|
|
190
325
|
exports.serializeContentItem = serializeContentItem;
|
|
191
326
|
exports.serializeContentItemWithType = serializeContentItemWithType;
|
|
192
327
|
exports.serializeContentType = serializeContentType;
|
|
328
|
+
exports.validateContentReadOptions = validateContentReadOptions;
|
|
@@ -1,5 +1,37 @@
|
|
|
1
|
-
import { DEFAULT_MAX_PAGE_SIZE } from '../schemas.mjs';
|
|
1
|
+
import { DEFAULT_MAX_PAGE_SIZE, contentReadOptionsSchema, normalizeContentFields } from '../schemas.mjs';
|
|
2
2
|
|
|
3
|
+
class CMSContentSelectionError extends Error {
|
|
4
|
+
}
|
|
5
|
+
function validateContentReadOptions(contentType, options) {
|
|
6
|
+
contentReadOptionsSchema.parse(options ?? {});
|
|
7
|
+
if (options?.fields === void 0) return;
|
|
8
|
+
if (options.view !== "content") {
|
|
9
|
+
throw new CMSContentSelectionError("fields requires view: content");
|
|
10
|
+
}
|
|
11
|
+
const properties = contentType ? JSON.parse(contentType.jsonSchema).properties : void 0;
|
|
12
|
+
for (const field of options.fields) {
|
|
13
|
+
if (!properties || !Object.hasOwn(properties, field)) {
|
|
14
|
+
throw new CMSContentSelectionError(
|
|
15
|
+
`Unknown top-level content field: ${field}`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function applyContentReadOptions(item, options) {
|
|
21
|
+
const result = options?.view === "content" ? {
|
|
22
|
+
id: item.id,
|
|
23
|
+
slug: item.slug,
|
|
24
|
+
parsedData: options.fields ? Object.fromEntries(
|
|
25
|
+
normalizeContentFields(options.fields).filter((field) => Object.hasOwn(item.parsedData, field)).map((field) => [
|
|
26
|
+
field,
|
|
27
|
+
item.parsedData[field]
|
|
28
|
+
])
|
|
29
|
+
) : item.parsedData,
|
|
30
|
+
createdAt: item.createdAt,
|
|
31
|
+
updatedAt: item.updatedAt
|
|
32
|
+
} : item;
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
3
35
|
function serializeContentType(ct) {
|
|
4
36
|
const needsMigration = !ct.autoFormVersion || ct.autoFormVersion < 2;
|
|
5
37
|
const migratedJsonSchema = needsMigration ? migrateToUnifiedSchema(ct.jsonSchema, ct.fieldConfig) : ct.jsonSchema;
|
|
@@ -84,6 +116,7 @@ async function getAllContentItems(adapter, contentTypeSlug, params) {
|
|
|
84
116
|
offset: params?.offset
|
|
85
117
|
};
|
|
86
118
|
}
|
|
119
|
+
validateContentReadOptions(contentType, params);
|
|
87
120
|
const whereConditions = [
|
|
88
121
|
{
|
|
89
122
|
field: "contentTypeId",
|
|
@@ -126,29 +159,30 @@ async function getAllContentItems(adapter, contentTypeSlug, params) {
|
|
|
126
159
|
limit !== void 0 ? offset + limit : void 0
|
|
127
160
|
);
|
|
128
161
|
return {
|
|
129
|
-
items: result,
|
|
162
|
+
items: result.map((item) => applyContentReadOptions(item, params)),
|
|
130
163
|
total,
|
|
131
164
|
limit: params?.limit,
|
|
132
165
|
offset: params?.offset
|
|
133
166
|
};
|
|
134
167
|
}
|
|
135
168
|
return {
|
|
136
|
-
items: result,
|
|
169
|
+
items: result.map((item) => applyContentReadOptions(item, params)),
|
|
137
170
|
total: dbTotal ?? result.length,
|
|
138
171
|
limit: params?.limit,
|
|
139
172
|
offset: params?.offset
|
|
140
173
|
};
|
|
141
174
|
}
|
|
142
|
-
async function getContentItemById(adapter, id) {
|
|
175
|
+
async function getContentItemById(adapter, id, options) {
|
|
143
176
|
const item = await adapter.findOne({
|
|
144
177
|
model: "contentItem",
|
|
145
178
|
where: [{ field: "id", value: id, operator: "eq" }],
|
|
146
179
|
join: { contentType: true }
|
|
147
180
|
});
|
|
148
181
|
if (!item) return null;
|
|
149
|
-
|
|
182
|
+
validateContentReadOptions(item.contentType, options);
|
|
183
|
+
return applyContentReadOptions(serializeContentItemWithType(item), options);
|
|
150
184
|
}
|
|
151
|
-
async function getContentItemBySlug(adapter, contentTypeSlug, slug) {
|
|
185
|
+
async function getContentItemBySlug(adapter, contentTypeSlug, slug, options) {
|
|
152
186
|
const contentType = await adapter.findOne({
|
|
153
187
|
model: "contentType",
|
|
154
188
|
where: [
|
|
@@ -162,6 +196,7 @@ async function getContentItemBySlug(adapter, contentTypeSlug, slug) {
|
|
|
162
196
|
if (!contentType) {
|
|
163
197
|
return null;
|
|
164
198
|
}
|
|
199
|
+
validateContentReadOptions(contentType, options);
|
|
165
200
|
const item = await adapter.findOne({
|
|
166
201
|
model: "contentItem",
|
|
167
202
|
where: [
|
|
@@ -177,7 +212,103 @@ async function getContentItemBySlug(adapter, contentTypeSlug, slug) {
|
|
|
177
212
|
if (!item) {
|
|
178
213
|
return null;
|
|
179
214
|
}
|
|
180
|
-
return serializeContentItemWithType(item);
|
|
215
|
+
return applyContentReadOptions(serializeContentItemWithType(item), options);
|
|
216
|
+
}
|
|
217
|
+
async function getContentItemsByRelation(adapter, contentTypeSlug, params) {
|
|
218
|
+
const contentType = await adapter.findOne({
|
|
219
|
+
model: "contentType",
|
|
220
|
+
where: [{ field: "slug", value: contentTypeSlug, operator: "eq" }]
|
|
221
|
+
});
|
|
222
|
+
if (!contentType) {
|
|
223
|
+
return {
|
|
224
|
+
items: [],
|
|
225
|
+
total: 0,
|
|
226
|
+
limit: params.limit ?? 20,
|
|
227
|
+
offset: params.offset ?? 0
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
validateContentReadOptions(contentType, params);
|
|
231
|
+
const result = await getContentItemsByRelationForType(
|
|
232
|
+
adapter,
|
|
233
|
+
contentType,
|
|
234
|
+
params
|
|
235
|
+
);
|
|
236
|
+
return {
|
|
237
|
+
...result,
|
|
238
|
+
items: result.items.map((item) => applyContentReadOptions(item, params))
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
async function getContentItemsByRelationForType(adapter, contentType, params) {
|
|
242
|
+
const limit = params.limit ?? 20;
|
|
243
|
+
const offset = params.offset ?? 0;
|
|
244
|
+
const batchSize = 100;
|
|
245
|
+
const sourceIds = /* @__PURE__ */ new Set();
|
|
246
|
+
for (let relationOffset = 0; ; relationOffset += batchSize) {
|
|
247
|
+
const relations = await adapter.findMany(
|
|
248
|
+
{
|
|
249
|
+
model: "contentRelation",
|
|
250
|
+
where: [
|
|
251
|
+
{ field: "targetId", value: params.targetId, operator: "eq" },
|
|
252
|
+
{ field: "fieldName", value: params.field, operator: "eq" }
|
|
253
|
+
],
|
|
254
|
+
select: ["sourceId"],
|
|
255
|
+
limit: batchSize,
|
|
256
|
+
offset: relationOffset,
|
|
257
|
+
sortBy: { field: "id", direction: "asc" }
|
|
258
|
+
}
|
|
259
|
+
);
|
|
260
|
+
for (const relation of relations) sourceIds.add(relation.sourceId);
|
|
261
|
+
if (relations.length < batchSize) break;
|
|
262
|
+
}
|
|
263
|
+
const ids = [...sourceIds];
|
|
264
|
+
const metadata = [];
|
|
265
|
+
for (let start = 0; start < ids.length; start += batchSize) {
|
|
266
|
+
metadata.push(
|
|
267
|
+
...await adapter.findMany({
|
|
268
|
+
model: "contentItem",
|
|
269
|
+
where: [
|
|
270
|
+
{
|
|
271
|
+
field: "id",
|
|
272
|
+
value: ids.slice(start, start + batchSize),
|
|
273
|
+
operator: "in"
|
|
274
|
+
},
|
|
275
|
+
{ field: "contentTypeId", value: contentType.id, operator: "eq" }
|
|
276
|
+
],
|
|
277
|
+
select: ["id", "createdAt"],
|
|
278
|
+
limit: batchSize
|
|
279
|
+
})
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
metadata.sort(
|
|
283
|
+
(left, right) => right.createdAt.getTime() - left.createdAt.getTime() || (left.id < right.id ? 1 : left.id > right.id ? -1 : 0)
|
|
284
|
+
);
|
|
285
|
+
const pageIds = metadata.slice(offset, offset + limit).map((item) => item.id);
|
|
286
|
+
const itemsById = /* @__PURE__ */ new Map();
|
|
287
|
+
for (let start = 0; start < pageIds.length; start += batchSize) {
|
|
288
|
+
const items = await adapter.findMany({
|
|
289
|
+
model: "contentItem",
|
|
290
|
+
where: [
|
|
291
|
+
{
|
|
292
|
+
field: "id",
|
|
293
|
+
value: pageIds.slice(start, start + batchSize),
|
|
294
|
+
operator: "in"
|
|
295
|
+
},
|
|
296
|
+
{ field: "contentTypeId", value: contentType.id, operator: "eq" }
|
|
297
|
+
],
|
|
298
|
+
limit: batchSize,
|
|
299
|
+
join: { contentType: true }
|
|
300
|
+
});
|
|
301
|
+
for (const item of items) itemsById.set(item.id, item);
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
items: pageIds.flatMap((id) => {
|
|
305
|
+
const item = itemsById.get(id);
|
|
306
|
+
return item ? [serializeContentItemWithType(item)] : [];
|
|
307
|
+
}),
|
|
308
|
+
total: metadata.length,
|
|
309
|
+
limit,
|
|
310
|
+
offset
|
|
311
|
+
};
|
|
181
312
|
}
|
|
182
313
|
|
|
183
|
-
export { getAllContentItems, getAllContentTypes, getContentItemById, getContentItemBySlug, migrateToUnifiedSchema, serializeContentItem, serializeContentItemWithType, serializeContentType };
|
|
314
|
+
export { CMSContentSelectionError, applyContentReadOptions, getAllContentItems, getAllContentTypes, getContentItemById, getContentItemBySlug, getContentItemsByRelation, getContentItemsByRelationForType, migrateToUnifiedSchema, serializeContentItem, serializeContentItemWithType, serializeContentType, validateContentReadOptions };
|