@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.
Files changed (113) hide show
  1. package/dist/api/index.d.cts +2 -2
  2. package/dist/api/index.d.mts +2 -2
  3. package/dist/api/index.d.ts +2 -2
  4. package/dist/client/index.d.cts +2 -2
  5. package/dist/client/index.d.mts +2 -2
  6. package/dist/client/index.d.ts +2 -2
  7. package/dist/context/index.d.cts +1 -1
  8. package/dist/context/index.d.mts +1 -1
  9. package/dist/context/index.d.ts +1 -1
  10. package/dist/index.d.cts +1 -1
  11. package/dist/index.d.mts +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/packages/stack/src/plugins/cms/api/getters.cjs +142 -6
  14. package/dist/packages/stack/src/plugins/cms/api/getters.mjs +139 -8
  15. package/dist/packages/stack/src/plugins/cms/api/operations.cjs +67 -61
  16. package/dist/packages/stack/src/plugins/cms/api/operations.mjs +69 -63
  17. package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +26 -8
  18. package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +27 -9
  19. package/dist/packages/stack/src/plugins/cms/api/query-key-defs.cjs +15 -1
  20. package/dist/packages/stack/src/plugins/cms/api/query-key-defs.mjs +14 -2
  21. package/dist/packages/stack/src/plugins/cms/client/hooks/cms-hooks.cjs +45 -24
  22. package/dist/packages/stack/src/plugins/cms/client/hooks/cms-hooks.mjs +45 -24
  23. package/dist/packages/stack/src/plugins/cms/schemas.cjs +22 -0
  24. package/dist/packages/stack/src/plugins/cms/schemas.mjs +20 -1
  25. package/dist/plugins/api/index.d.cts +2 -2
  26. package/dist/plugins/api/index.d.mts +2 -2
  27. package/dist/plugins/api/index.d.ts +2 -2
  28. package/dist/plugins/blog/api/index.d.cts +2 -2
  29. package/dist/plugins/blog/api/index.d.mts +2 -2
  30. package/dist/plugins/blog/api/index.d.ts +2 -2
  31. package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
  32. package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
  33. package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
  34. package/dist/plugins/blog/client/index.d.cts +2 -2
  35. package/dist/plugins/blog/client/index.d.mts +2 -2
  36. package/dist/plugins/blog/client/index.d.ts +2 -2
  37. package/dist/plugins/blog/query-keys.d.cts +2 -2
  38. package/dist/plugins/blog/query-keys.d.mts +2 -2
  39. package/dist/plugins/blog/query-keys.d.ts +2 -2
  40. package/dist/plugins/client/index.d.cts +2 -2
  41. package/dist/plugins/client/index.d.mts +2 -2
  42. package/dist/plugins/client/index.d.ts +2 -2
  43. package/dist/plugins/cms/api/index.cjs +1 -0
  44. package/dist/plugins/cms/api/index.d.cts +43 -11
  45. package/dist/plugins/cms/api/index.d.mts +43 -11
  46. package/dist/plugins/cms/api/index.d.ts +43 -11
  47. package/dist/plugins/cms/api/index.mjs +1 -1
  48. package/dist/plugins/cms/client/hooks/index.d.cts +90 -45
  49. package/dist/plugins/cms/client/hooks/index.d.mts +90 -45
  50. package/dist/plugins/cms/client/hooks/index.d.ts +90 -45
  51. package/dist/plugins/cms/client/index.d.cts +2 -1
  52. package/dist/plugins/cms/client/index.d.mts +2 -1
  53. package/dist/plugins/cms/client/index.d.ts +2 -1
  54. package/dist/plugins/cms/query-keys.cjs +69 -13
  55. package/dist/plugins/cms/query-keys.d.cts +89 -212
  56. package/dist/plugins/cms/query-keys.d.mts +89 -212
  57. package/dist/plugins/cms/query-keys.d.ts +89 -212
  58. package/dist/plugins/cms/query-keys.mjs +70 -14
  59. package/dist/plugins/kanban/client/index.d.cts +1 -1
  60. package/dist/plugins/kanban/client/index.d.mts +1 -1
  61. package/dist/plugins/kanban/client/index.d.ts +1 -1
  62. package/dist/plugins/route-docs/client/index.d.cts +1 -1
  63. package/dist/plugins/route-docs/client/index.d.mts +1 -1
  64. package/dist/plugins/route-docs/client/index.d.ts +1 -1
  65. package/dist/plugins/ui-builder/client/hooks/index.d.cts +3 -3
  66. package/dist/plugins/ui-builder/client/hooks/index.d.mts +3 -3
  67. package/dist/plugins/ui-builder/client/hooks/index.d.ts +3 -3
  68. package/dist/plugins/ui-builder/client/index.d.cts +3 -3
  69. package/dist/plugins/ui-builder/client/index.d.mts +3 -3
  70. package/dist/plugins/ui-builder/client/index.d.ts +3 -3
  71. package/dist/plugins/ui-builder/query-keys.d.cts +4 -3
  72. package/dist/plugins/ui-builder/query-keys.d.mts +4 -3
  73. package/dist/plugins/ui-builder/query-keys.d.ts +4 -3
  74. package/dist/shared/{stack.DMj68qY0.d.mts → stack.B2jlVVhD.d.mts} +5 -5
  75. package/dist/shared/{stack.Cvnj99cs.d.ts → stack.BB9tubJJ.d.ts} +9 -3
  76. package/dist/shared/{stack.Bt3WG2yb.d.cts → stack.BWduIMKG.d.cts} +35 -35
  77. package/dist/shared/stack.Bw09Lg2z.d.ts +1420 -0
  78. package/dist/shared/{stack.CkEz7vSt.d.mts → stack.C2Pvl-RS.d.mts} +9 -3
  79. package/dist/shared/{stack.C2l2wd_X.d.ts → stack.Ch9-ppmQ.d.ts} +35 -35
  80. package/dist/shared/{stack.Ht8mhDj5.d.cts → stack.D17yFglU.d.cts} +5 -5
  81. package/dist/shared/{stack.CiD115Ov.d.mts → stack.D6fPBfYe.d.mts} +35 -35
  82. package/dist/shared/stack.DFGj0gb7.d.mts +1420 -0
  83. package/dist/shared/{stack.pi0FxoEa.d.ts → stack.Dcfg4GNN.d.ts} +5 -5
  84. package/dist/shared/{stack.3rxARhgS.d.cts → stack.DrB3L7Ih.d.cts} +52 -3
  85. package/dist/shared/{stack.3rxARhgS.d.mts → stack.DrB3L7Ih.d.mts} +52 -3
  86. package/dist/shared/{stack.3rxARhgS.d.ts → stack.DrB3L7Ih.d.ts} +52 -3
  87. package/dist/shared/stack.NNrBKBkM.d.cts +1420 -0
  88. package/dist/shared/{stack.mRRyZBUg.d.cts → stack.Rb87lHqK.d.cts} +9 -3
  89. package/package.json +1 -1
  90. package/src/__tests__/cms-query-keys.test.ts +57 -0
  91. package/src/plugins/api/index.ts +1 -0
  92. package/src/plugins/api/operation.ts +16 -3
  93. package/src/plugins/cms/__tests__/authorization.test.ts +652 -187
  94. package/src/plugins/cms/__tests__/client-runtime.browser.test.tsx +655 -0
  95. package/src/plugins/cms/__tests__/content-read.typecheck.ts +351 -0
  96. package/src/plugins/cms/__tests__/getters.test.ts +286 -0
  97. package/src/plugins/cms/api/getters.ts +270 -12
  98. package/src/plugins/cms/api/index.ts +10 -0
  99. package/src/plugins/cms/api/operations.ts +163 -75
  100. package/src/plugins/cms/api/plugin.ts +50 -12
  101. package/src/plugins/cms/api/query-key-defs.ts +29 -2
  102. package/src/plugins/cms/client/hooks/cms-hooks.tsx +400 -91
  103. package/src/plugins/cms/client/index.ts +9 -0
  104. package/src/plugins/cms/query-keys.ts +171 -16
  105. package/src/plugins/cms/schemas.ts +30 -0
  106. package/src/plugins/cms/types.ts +49 -2
  107. package/src/plugins/media/__tests__/identity-partition.test.tsx +26 -16
  108. package/dist/shared/stack.CAmVUwjV.d.cts +0 -764
  109. package/dist/shared/stack.CQK02ujt.d.ts +0 -764
  110. package/dist/shared/stack.D9x1fR5a.d.mts +0 -764
  111. package/dist/shared/{stack.CKc_Bais.d.cts → stack.Csi-4Mgz.d.cts} +7 -7
  112. package/dist/shared/{stack.CKc_Bais.d.mts → stack.Csi-4Mgz.d.mts} +7 -7
  113. package/dist/shared/{stack.CKc_Bais.d.ts → stack.Csi-4Mgz.d.ts} +7 -7
@@ -1,5 +1,5 @@
1
- import { B as BackendPlugin, V as PrefixedPluginRoutes, W as BackendStackConfig, X as CompatibleStackAuth, Y as BackendStack, Z as PluginRaw, _ as PluginOperations } from '../shared/stack.mRRyZBUg.cjs';
2
- export { S as StackContext } from '../shared/stack.mRRyZBUg.cjs';
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';
@@ -1,5 +1,5 @@
1
- import { B as BackendPlugin, V as PrefixedPluginRoutes, W as BackendStackConfig, X as CompatibleStackAuth, Y as BackendStack, Z as PluginRaw, _ as PluginOperations } from '../shared/stack.CkEz7vSt.mjs';
2
- export { S as StackContext } from '../shared/stack.CkEz7vSt.mjs';
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';
@@ -1,5 +1,5 @@
1
- import { B as BackendPlugin, V as PrefixedPluginRoutes, W as BackendStackConfig, X as CompatibleStackAuth, Y as BackendStack, Z as PluginRaw, _ as PluginOperations } from '../shared/stack.Cvnj99cs.js';
2
- export { S as StackContext } from '../shared/stack.Cvnj99cs.js';
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';
@@ -1,5 +1,5 @@
1
- import { s as Sitemap, q as ClientPluginRegistration, t as PluginRoutes, u as ClientStackConfig, v as ResolvedClientStack } from '../shared/stack.mRRyZBUg.cjs';
2
- export { w as ClientApiConfig, x as ClientApiEndpointOverride, y as ClientLocation, z as ClientLocationOverride, C as ClientPlugin, p as ClientPluginDefinition, E as ClientPluginEndpointOverride, F as ClientPluginEndpointOverrides, G as ClientProviderApi, H as ClientProviderPluginRuntime, J as ClientProviderProjection, K as ClientStack, L as ClientStackContext, M as ResolvedClientApi, r as ResolvedClientPluginRuntime, N as ResolvedClientStackConfig } from '../shared/stack.mRRyZBUg.cjs';
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';
@@ -1,5 +1,5 @@
1
- import { s as Sitemap, q as ClientPluginRegistration, t as PluginRoutes, u as ClientStackConfig, v as ResolvedClientStack } from '../shared/stack.CkEz7vSt.mjs';
2
- export { w as ClientApiConfig, x as ClientApiEndpointOverride, y as ClientLocation, z as ClientLocationOverride, C as ClientPlugin, p as ClientPluginDefinition, E as ClientPluginEndpointOverride, F as ClientPluginEndpointOverrides, G as ClientProviderApi, H as ClientProviderPluginRuntime, J as ClientProviderProjection, K as ClientStack, L as ClientStackContext, M as ResolvedClientApi, r as ResolvedClientPluginRuntime, N as ResolvedClientStackConfig } from '../shared/stack.CkEz7vSt.mjs';
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';
@@ -1,5 +1,5 @@
1
- import { s as Sitemap, q as ClientPluginRegistration, t as PluginRoutes, u as ClientStackConfig, v as ResolvedClientStack } from '../shared/stack.Cvnj99cs.js';
2
- export { w as ClientApiConfig, x as ClientApiEndpointOverride, y as ClientLocation, z as ClientLocationOverride, C as ClientPlugin, p as ClientPluginDefinition, E as ClientPluginEndpointOverride, F as ClientPluginEndpointOverrides, G as ClientProviderApi, H as ClientProviderPluginRuntime, J as ClientProviderProjection, K as ClientStack, L as ClientStackContext, M as ResolvedClientApi, r as ResolvedClientPluginRuntime, N as ResolvedClientStackConfig } from '../shared/stack.Cvnj99cs.js';
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';
@@ -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 { T as InferredPluginOverrides, U as RegisteredClientPlugins } from '../shared/stack.mRRyZBUg.cjs';
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';
@@ -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 { T as InferredPluginOverrides, U as RegisteredClientPlugins } from '../shared/stack.CkEz7vSt.mjs';
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';
@@ -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 { T as InferredPluginOverrides, U as RegisteredClientPlugins } from '../shared/stack.Cvnj99cs.js';
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, Y as BackendStack, W as BackendStackConfig, _ as PluginOperations, Z as PluginRaw, S as StackContext } from './shared/stack.mRRyZBUg.cjs';
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, Y as BackendStack, W as BackendStackConfig, _ as PluginOperations, Z as PluginRaw, S as StackContext } from './shared/stack.CkEz7vSt.mjs';
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, Y as BackendStack, W as BackendStackConfig, _ as PluginOperations, Z as PluginRaw, S as StackContext } from './shared/stack.Cvnj99cs.js';
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
- return serializeContentItemWithType(item);
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
- return serializeContentItemWithType(item);
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 };