@agent-native/core-corpus 0.201.0-nightly-20261005153421 → 0.201.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 (235) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/security/SKILL.md +9 -2
  3. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +14 -4
  4. package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +12 -7
  5. package/corpus/templates/analytics/CHANGELOG.md +6 -0
  6. package/corpus/templates/analytics/README.md +2 -2
  7. package/corpus/templates/analytics/changelog/2026-10-02-events-with-a-very-long-name-app-or-page-path-no-longer-caus.md +6 -0
  8. package/corpus/templates/analytics/package.json +1 -0
  9. package/corpus/templates/analytics/server/handlers/first-party-analytics.ts +9 -19
  10. package/corpus/templates/analytics/server/handlers/session-replay.ts +34 -47
  11. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +9 -6
  12. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +57 -36
  13. package/corpus/templates/analytics/server/lib/indexed-text.ts +53 -0
  14. package/corpus/templates/analytics/server/lib/request-errors.ts +73 -0
  15. package/corpus/templates/analytics/server/lib/session-event-index.ts +6 -16
  16. package/corpus/templates/analytics/server/lib/session-replay.ts +12 -2
  17. package/corpus/templates/analytics/server/plugins/auth.ts +2 -1
  18. package/corpus/templates/analytics/server/plugins/otel.ts +6 -0
  19. package/corpus/templates/assets/.agents/skills/security/SKILL.md +9 -2
  20. package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +12 -7
  21. package/corpus/templates/assets/CHANGELOG.md +7 -0
  22. package/corpus/templates/assets/README.md +2 -2
  23. package/corpus/templates/assets/package.json +1 -0
  24. package/corpus/templates/assets/server/plugins/auth.ts +2 -1
  25. package/corpus/templates/assets/server/plugins/otel.ts +6 -0
  26. package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +2 -1
  27. package/corpus/templates/brain/.agents/skills/brain/SKILL.md +5 -4
  28. package/corpus/templates/brain/.agents/skills/security/SKILL.md +9 -2
  29. package/corpus/templates/brain/.agents/skills/storing-data/SKILL.md +12 -7
  30. package/corpus/templates/brain/CHANGELOG.md +6 -0
  31. package/corpus/templates/brain/README.md +12 -8
  32. package/corpus/templates/brain/changelog/2026-10-05-private-slack-channels-are-searchable-org-wide.md +6 -0
  33. package/corpus/templates/brain/package.json +1 -0
  34. package/corpus/templates/brain/server/lib/audiences.ts +1 -98
  35. package/corpus/templates/brain/server/lib/connectors.ts +2 -166
  36. package/corpus/templates/brain/server/plugins/otel.ts +6 -0
  37. package/corpus/templates/calendar/.agents/skills/security/SKILL.md +9 -2
  38. package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +12 -7
  39. package/corpus/templates/calendar/CHANGELOG.md +7 -0
  40. package/corpus/templates/calendar/README.md +2 -2
  41. package/corpus/templates/calendar/package.json +1 -0
  42. package/corpus/templates/calendar/server/plugins/auth.ts +2 -1
  43. package/corpus/templates/calendar/server/plugins/otel.ts +6 -0
  44. package/corpus/templates/chat/.agents/skills/security/SKILL.md +9 -2
  45. package/corpus/templates/chat/.agents/skills/storing-data/SKILL.md +12 -7
  46. package/corpus/templates/chat/README.md +2 -2
  47. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +9 -0
  48. package/corpus/templates/clips/.agents/skills/security/SKILL.md +9 -2
  49. package/corpus/templates/clips/CHANGELOG.md +24 -0
  50. package/corpus/templates/clips/README.md +2 -2
  51. package/corpus/templates/clips/actions/lib/audio-chunk-list.ts +23 -0
  52. package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +187 -292
  53. package/corpus/templates/clips/actions/lib/chunked-transcription.ts +151 -0
  54. package/corpus/templates/clips/actions/lib/recording-audio-source.ts +191 -0
  55. package/corpus/templates/clips/actions/request-transcript.ts +81 -135
  56. package/corpus/templates/clips/actions/search-recordings.ts +19 -5
  57. package/corpus/templates/clips/app/components/clips-command-menu.tsx +5 -0
  58. package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -1
  59. package/corpus/templates/clips/app/components/library/search-bar.tsx +5 -0
  60. package/corpus/templates/clips/app/hooks/use-library.ts +1 -0
  61. package/corpus/templates/clips/app/lib/local-recording-upload.ts +13 -6
  62. package/corpus/templates/clips/app/lib/recording-section.ts +1 -1
  63. package/corpus/templates/clips/app/routes/_app.r.$recordingId.tsx +7 -5
  64. package/corpus/templates/clips/app/routes/record.tsx +16 -6
  65. package/corpus/templates/clips/changelog/2026-10-02-long-uploads-an-hour-or-more-now-transcribe-reliably-instead.md +6 -0
  66. package/corpus/templates/clips/changelog/2026-10-05-confirming-discard-recording-now-returns-you-to-your-library.md +6 -0
  67. package/corpus/templates/clips/changelog/2026-10-05-discarding-a-recording-now-removes-its-failed-upload-card-fr.md +6 -0
  68. package/corpus/templates/clips/changelog/2026-10-05-discarding-a-recovered-recording-no-longer-warns-that-it-s-o.md +6 -0
  69. package/corpus/templates/clips/changelog/2026-10-05-search-results-identify-recordings-in-trash-and-open-them-wi.md +6 -0
  70. package/corpus/templates/clips/package.json +1 -0
  71. package/corpus/templates/clips/server/lib/builder-cdn.ts +5 -0
  72. package/corpus/templates/clips/server/lib/builder-media-compression.ts +2 -2
  73. package/corpus/templates/clips/server/plugins/auth.ts +2 -1
  74. package/corpus/templates/clips/server/plugins/otel.ts +6 -0
  75. package/corpus/templates/clips/shared/transcript-failure.ts +5 -0
  76. package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +8 -2
  77. package/corpus/templates/content/.agents/skills/security/SKILL.md +9 -2
  78. package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +12 -7
  79. package/corpus/templates/content/CHANGELOG.md +41 -0
  80. package/corpus/templates/content/README.md +2 -2
  81. package/corpus/templates/content/actions/_database-navigation.ts +523 -344
  82. package/corpus/templates/content/actions/_database-row-mutation.ts +44 -10
  83. package/corpus/templates/content/actions/_database-setup-discovery.ts +9 -3
  84. package/corpus/templates/content/actions/_database-utils.ts +299 -271
  85. package/corpus/templates/content/actions/_property-utils.ts +293 -190
  86. package/corpus/templates/content/actions/_relation-values.ts +3 -1
  87. package/corpus/templates/content/actions/get-content-database.ts +1 -0
  88. package/corpus/templates/content/actions/query-content-database-items.ts +32 -5
  89. package/corpus/templates/content/actions/set-document-property.ts +17 -11
  90. package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +21 -6
  91. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +127 -43
  92. package/corpus/templates/content/app/components/editor/DocumentEditorSkeleton.tsx +159 -50
  93. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +12 -28
  94. package/corpus/templates/content/app/components/editor/PageDraftRecovery.tsx +6 -1
  95. package/corpus/templates/content/app/components/editor/TableHoverControls.tsx +139 -70
  96. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +16 -1
  97. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +180 -75
  98. package/corpus/templates/content/app/components/editor/database/DatabaseViewSkeleton.tsx +76 -0
  99. package/corpus/templates/content/app/components/editor/database/navigation-state.ts +60 -2
  100. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +41 -42
  101. package/corpus/templates/content/app/components/editor/document-editor-layout.ts +18 -0
  102. package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +11 -3
  103. package/corpus/templates/content/app/components/editor/suggestions/draft-session.ts +15 -7
  104. package/corpus/templates/content/app/components/editor/suggestions/model.ts +13 -0
  105. package/corpus/templates/content/app/components/editor/suggestions/read-only-blocks.ts +136 -0
  106. package/corpus/templates/content/app/components/editor/table-view.ts +73 -0
  107. package/corpus/templates/content/app/components/layout/ContentStartupShell.tsx +1 -1
  108. package/corpus/templates/content/app/components/layout/Layout.tsx +5 -1
  109. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +57 -16
  110. package/corpus/templates/content/app/components/sidebar/MovePageDialog.tsx +4 -4
  111. package/corpus/templates/content/app/components/sidebar/SidebarNavigationRow.tsx +34 -10
  112. package/corpus/templates/content/app/global.css +16 -8
  113. package/corpus/templates/content/app/hooks/content-action-refresh.ts +14 -13
  114. package/corpus/templates/content/app/hooks/use-content-database.ts +72 -9
  115. package/corpus/templates/content/app/hooks/use-content-personal-navigation.ts +7 -3
  116. package/corpus/templates/content/app/hooks/use-documents.ts +27 -0
  117. package/corpus/templates/content/app/i18n-data.ts +3 -2
  118. package/corpus/templates/content/app/lib/content-landing.ts +3 -31
  119. package/corpus/templates/content/app/lib/files-navigation.ts +182 -10
  120. package/corpus/templates/content/app/lib/files-root-hint.ts +20 -32
  121. package/corpus/templates/content/app/lib/page-startup-hints.ts +108 -0
  122. package/corpus/templates/content/app/lib/private-link-redirect.ts +25 -0
  123. package/corpus/templates/content/app/lib/sidebar-layout-hint.ts +34 -1
  124. package/corpus/templates/content/app/lib/startup-timing.ts +2 -0
  125. package/corpus/templates/content/app/root.tsx +3 -1
  126. package/corpus/templates/content/app/routes/_app.home.tsx +10 -19
  127. package/corpus/templates/content/app/routes/p.$id.tsx +23 -5
  128. package/corpus/templates/content/changelog/2026-10-02-a-page-link-you-cant-open-now-says-so-instead-of-opening-an.md +6 -0
  129. package/corpus/templates/content/changelog/2026-10-02-after-a-refresh-the-files-sidebar-shows-the-open-page-s-fold.md +6 -0
  130. package/corpus/templates/content/changelog/2026-10-02-large-collections-open-faster.md +6 -0
  131. package/corpus/templates/content/changelog/2026-10-02-pages-stay-inside-the-window-at-every-width-long-inline-code.md +6 -0
  132. package/corpus/templates/content/changelog/2026-10-02-pages-with-open-comments-and-collections-with-sorted-or-filt.md +6 -0
  133. package/corpus/templates/content/changelog/2026-10-02-suggest-edits-works-on-pages-written-by-agents-including-pag.md +6 -0
  134. package/corpus/templates/content/changelog/2026-10-02-while-you-suggest-edits-tables-and-other-blocks-that-suggest.md +6 -0
  135. package/corpus/templates/content/changelog/2026-10-05-collection-view-context-now-survives-quick-page-changes-when.md +6 -0
  136. package/corpus/templates/content/changelog/2026-10-05-collection-views-keep-their-saved-rows-accurate-during-refre.md +6 -0
  137. package/corpus/templates/content/changelog/2026-10-05-exact-saved-view-links-keep-collection-retry-available.md +6 -0
  138. package/corpus/templates/content/changelog/2026-10-05-expanding-a-files-folder-now-shares-one-navigation-read-acro.md +6 -0
  139. package/corpus/templates/content/changelog/2026-10-05-files-navigation-retries-temporary-failures-consistently.md +6 -0
  140. package/corpus/templates/content/changelog/2026-10-05-shared-page-owners-keep-edit-and-manage-controls-in-files-an.md +6 -0
  141. package/corpus/templates/content/changelog/2026-10-05-tagging-an-ai-in-a-comment-works-again-instead-of-failing-ri.md +6 -0
  142. package/corpus/templates/content/changelog/2026-10-05-the-home-loading-shell-keeps-the-layout-of-your-last-opened-.md +6 -0
  143. package/corpus/templates/content/changelog/2026-10-05-typing-and-a-space-or-inserting-a-toggle-or-callout-no-longe.md +6 -0
  144. package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md +4 -1
  145. package/corpus/templates/content/e2e/playwright.config.ts +1 -1
  146. package/corpus/templates/content/package.json +2 -1
  147. package/corpus/templates/content/scripts/seed-perf-database.mjs +600 -0
  148. package/corpus/templates/content/scripts/trace-startup.mjs +25 -3
  149. package/corpus/templates/content/server/db/index.ts +1 -1
  150. package/corpus/templates/content/server/lib/suggested-edits.ts +23 -26
  151. package/corpus/templates/content/server/plugins/auth.ts +2 -1
  152. package/corpus/templates/content/server/plugins/otel.ts +6 -0
  153. package/corpus/templates/content/shared/api.ts +17 -0
  154. package/corpus/templates/content/shared/suggestion-diff.ts +124 -38
  155. package/corpus/templates/content/shared/suggestion-formatting.ts +134 -3
  156. package/corpus/templates/crm/.agents/skills/security/SKILL.md +9 -2
  157. package/corpus/templates/crm/.agents/skills/storing-data/SKILL.md +12 -7
  158. package/corpus/templates/crm/package.json +1 -0
  159. package/corpus/templates/crm/server/plugins/otel.ts +6 -0
  160. package/corpus/templates/design/.agents/skills/security/SKILL.md +9 -2
  161. package/corpus/templates/design/.agents/skills/storing-data/SKILL.md +12 -7
  162. package/corpus/templates/design/CHANGELOG.md +41 -0
  163. package/corpus/templates/design/README.md +2 -2
  164. package/corpus/templates/design/actions/list-designs.ts +11 -4
  165. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +110 -32
  166. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +28 -0
  167. package/corpus/templates/design/app/components/design/multi-screen/types.ts +1 -0
  168. package/corpus/templates/design/app/components/home/DesignHomeLibrary.tsx +79 -0
  169. package/corpus/templates/design/app/components/layout/Header.tsx +2 -4
  170. package/corpus/templates/design/app/components/ui/tabs.tsx +59 -1
  171. package/corpus/templates/design/app/global.css +1 -34
  172. package/corpus/templates/design/app/i18n/en-US.ts +4 -0
  173. package/corpus/templates/design/app/lib/design-filter.ts +4 -2
  174. package/corpus/templates/design/app/pages/Index.tsx +91 -59
  175. package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +58 -17
  176. package/corpus/templates/design/changelog/2026-10-01-filter-designs-by-owner.md +6 -0
  177. package/corpus/templates/design/changelog/2026-10-03-layers-dropped-into-visible-canvas-space-beyond-a-screen-now.md +6 -0
  178. package/corpus/templates/design/changelog/2026-10-03-visible-screen-overflow-no-longer-routes-drops-to-the-canvas.md +6 -0
  179. package/corpus/templates/design/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-designs.md +6 -0
  180. package/corpus/templates/design/package.json +1 -0
  181. package/corpus/templates/design/server/plugins/auth.ts +2 -1
  182. package/corpus/templates/design/server/plugins/otel.ts +6 -0
  183. package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +9 -2
  184. package/corpus/templates/dispatch/.agents/skills/storing-data/SKILL.md +12 -7
  185. package/corpus/templates/dispatch/README.md +2 -2
  186. package/corpus/templates/dispatch/package.json +1 -0
  187. package/corpus/templates/dispatch/server/plugins/otel.ts +6 -0
  188. package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +2 -1
  189. package/corpus/templates/factory/.agents/skills/security/SKILL.md +9 -2
  190. package/corpus/templates/factory/.agents/skills/storing-data/SKILL.md +12 -7
  191. package/corpus/templates/factory/package.json +1 -0
  192. package/corpus/templates/factory/server/plugins/otel.ts +6 -0
  193. package/corpus/templates/forms/.agents/skills/security/SKILL.md +9 -2
  194. package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +12 -7
  195. package/corpus/templates/forms/README.md +2 -2
  196. package/corpus/templates/forms/package.json +1 -0
  197. package/corpus/templates/forms/server/plugins/auth.ts +2 -1
  198. package/corpus/templates/forms/server/plugins/otel.ts +6 -0
  199. package/corpus/templates/mail/.agents/skills/security/SKILL.md +9 -2
  200. package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +12 -7
  201. package/corpus/templates/mail/CHANGELOG.md +6 -0
  202. package/corpus/templates/mail/README.md +2 -2
  203. package/corpus/templates/mail/package.json +1 -0
  204. package/corpus/templates/mail/server/plugins/auth.ts +2 -1
  205. package/corpus/templates/mail/server/plugins/otel.ts +6 -0
  206. package/corpus/templates/plan/.agents/skills/security/SKILL.md +9 -2
  207. package/corpus/templates/plan/.agents/skills/storing-data/SKILL.md +12 -7
  208. package/corpus/templates/plan/CHANGELOG.md +1 -0
  209. package/corpus/templates/plan/README.md +2 -2
  210. package/corpus/templates/plan/package.json +1 -0
  211. package/corpus/templates/plan/server/plugins/auth.ts +2 -1
  212. package/corpus/templates/plan/server/plugins/otel.ts +6 -0
  213. package/corpus/templates/slides/.agents/skills/security/SKILL.md +9 -2
  214. package/corpus/templates/slides/.agents/skills/storing-data/SKILL.md +12 -7
  215. package/corpus/templates/slides/CHANGELOG.md +23 -0
  216. package/corpus/templates/slides/README.md +2 -2
  217. package/corpus/templates/slides/actions/list-decks.ts +11 -4
  218. package/corpus/templates/slides/app/components/deck/DeckFilterMenu.tsx +44 -36
  219. package/corpus/templates/slides/app/components/home/SlidesHomeLibrary.tsx +79 -0
  220. package/corpus/templates/slides/app/components/layout/Header.tsx +2 -15
  221. package/corpus/templates/slides/app/components/ui/tabs.tsx +59 -0
  222. package/corpus/templates/slides/app/global.css +3 -54
  223. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  224. package/corpus/templates/slides/app/lib/deck-filter.ts +5 -2
  225. package/corpus/templates/slides/app/pages/Index.tsx +102 -88
  226. package/corpus/templates/slides/changelog/2026-10-01-filter-decks-by-owner.md +6 -0
  227. package/corpus/templates/slides/changelog/2026-10-02-hide-recent-until-decks-available.md +6 -0
  228. package/corpus/templates/slides/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-decks-a.md +6 -0
  229. package/corpus/templates/slides/package.json +1 -0
  230. package/corpus/templates/slides/server/handlers/request-auth-context.ts +8 -0
  231. package/corpus/templates/slides/server/plugins/auth.ts +2 -1
  232. package/corpus/templates/slides/server/plugins/otel.ts +6 -0
  233. package/corpus/templates/tasks/.agents/skills/security/SKILL.md +9 -2
  234. package/corpus/templates/tasks/.agents/skills/storing-data/SKILL.md +12 -7
  235. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
+ import { fail } from "@agent-native/core/action";
1
2
  import { alias } from "@agent-native/core/db/schema";
2
3
  import {
3
4
  getRequestOrgId,
@@ -7,6 +8,7 @@ import {
7
8
  accessFilter,
8
9
  ROLE_RANK,
9
10
  resolveAccess,
11
+ type ResolvedAccess,
10
12
  type ShareRole,
11
13
  } from "@agent-native/core/sharing";
12
14
  import {
@@ -77,7 +79,9 @@ import {
77
79
  import {
78
80
  listPropertiesForDatabaseDocuments,
79
81
  listPropertiesForDatabase,
82
+ readDatabasePropertySchema,
80
83
  serializeDatabase,
84
+ type DatabasePropertySchema,
81
85
  } from "./_property-utils.js";
82
86
  export { getDocumentContextPath };
83
87
 
@@ -174,30 +178,16 @@ export const contentDatabaseTableQuerySchema = z
174
178
  })
175
179
  .optional();
176
180
 
177
- async function contentDatabaseTableQueryMode(
178
- databaseId: string,
181
+ function contentDatabaseTableQueryMode(
179
182
  query: ContentDatabaseTableQuery | undefined,
183
+ sourceFields: DatabasePropertySchema["sourceFields"],
180
184
  ) {
181
185
  if (!query) return undefined;
182
- const sourceFields = await getDb()
183
- .select({
184
- metadataJson: schema.contentDatabaseSources.metadataJson,
185
- propertyId: schema.contentDatabaseSourceFields.propertyId,
186
- })
187
- .from(schema.contentDatabaseSourceFields)
188
- .innerJoin(
189
- schema.contentDatabaseSources,
190
- eq(
191
- schema.contentDatabaseSources.id,
192
- schema.contentDatabaseSourceFields.sourceId,
193
- ),
194
- )
195
- .where(eq(schema.contentDatabaseSources.databaseId, databaseId));
196
186
  const secondaryPropertyIds = new Set<string>();
197
187
  for (const field of sourceFields) {
198
188
  let role: unknown = null;
199
189
  try {
200
- role = JSON.parse(field.metadataJson || "{}").federation?.role;
190
+ role = JSON.parse(field.sourceMetadataJson || "{}").federation?.role;
201
191
  } catch {
202
192
  role = null;
203
193
  }
@@ -497,6 +487,8 @@ export type ContentDatabaseReadResolution =
497
487
  | {
498
488
  available: true;
499
489
  database: typeof schema.contentDatabases.$inferSelect;
490
+ /** Null when read access comes from the Files space, not the page. */
491
+ accessRole: ResolvedAccess["role"] | null;
500
492
  }
501
493
  | {
502
494
  available: false;
@@ -512,22 +504,21 @@ export async function resolveContentDatabaseRead(args: {
512
504
  documentId?: string;
513
505
  }): Promise<ContentDatabaseReadResolution> {
514
506
  const db = getDb();
515
- let databaseId = args.databaseId;
516
- if (!databaseId && args.documentId) {
517
- const [database] = await db
518
- .select({ id: schema.contentDatabases.id })
519
- .from(schema.contentDatabases)
520
- .where(eq(schema.contentDatabases.documentId, args.documentId));
521
- databaseId = database?.id;
522
- }
507
+ const [database] =
508
+ args.databaseId || args.documentId
509
+ ? await db
510
+ .select()
511
+ .from(schema.contentDatabases)
512
+ .where(
513
+ args.databaseId
514
+ ? eq(schema.contentDatabases.id, args.databaseId)
515
+ : eq(schema.contentDatabases.documentId, args.documentId!),
516
+ )
517
+ : [];
518
+ const databaseId = args.databaseId || database?.id;
523
519
  if (!databaseId) {
524
520
  throw new Error("Either databaseId or documentId is required.");
525
521
  }
526
-
527
- const [database] = await db
528
- .select()
529
- .from(schema.contentDatabases)
530
- .where(eq(schema.contentDatabases.id, databaseId));
531
522
  if (!database) {
532
523
  return {
533
524
  available: false,
@@ -538,7 +529,13 @@ export async function resolveContentDatabaseRead(args: {
538
529
  };
539
530
  }
540
531
 
541
- let canRead = Boolean(await resolveAccess("document", database.documentId));
532
+ const access = await resolveAccess(
533
+ "document",
534
+ database.documentId,
535
+ undefined,
536
+ { skipResourceBody: true },
537
+ );
538
+ let canRead = Boolean(access);
542
539
  if (!canRead && database.systemRole === "files" && database.spaceId) {
543
540
  try {
544
541
  await resolveContentSpaceAccess(database.spaceId);
@@ -560,7 +557,7 @@ export async function resolveContentDatabaseRead(args: {
560
557
  };
561
558
  }
562
559
 
563
- return { available: true, database };
560
+ return { available: true, database, accessRole: access?.role ?? null };
564
561
  }
565
562
 
566
563
  type ContentDatabasePageBuild = ContentDatabasePageResponse & {
@@ -608,6 +605,7 @@ export async function getContentDatabasePageResponse(
608
605
  filesMembershipDatabaseId?: string;
609
606
  sidebarOrder?: ContentSidebarViewOrder;
610
607
  database?: typeof schema.contentDatabases.$inferSelect;
608
+ propertySchema?: DatabasePropertySchema;
611
609
  } = {},
612
610
  ): Promise<ContentDatabasePageBuild> {
613
611
  const db = getDb();
@@ -626,11 +624,6 @@ export async function getContentDatabasePageResponse(
626
624
 
627
625
  const { limit, offset } = normalizeContentDatabasePageOptions(options);
628
626
  const tableQuery = options.tableQuery;
629
- const tableQueryMode = await contentDatabaseTableQueryMode(
630
- databaseId,
631
- tableQuery,
632
- );
633
- const serverTableQuery = tableQueryMode === "server" ? tableQuery : undefined;
634
627
  const userEmail = getRequestUserEmail();
635
628
  const normalizedUserEmail = userEmail
636
629
  ? normalizeContentSpaceEmail(userEmail)
@@ -759,18 +752,30 @@ export async function getContentDatabasePageResponse(
759
752
  : sql`1 = 0`
760
753
  : undefined,
761
754
  );
762
- const [itemCount] = await db
763
- .select({ count: sql<number>`COUNT(*)` })
764
- .from(schema.contentDatabaseItems)
765
- .where(visibleItemFilter);
755
+ const [propertySchema, [itemCount]] = await Promise.all([
756
+ options.propertySchema ?? readDatabasePropertySchema(db, databaseId),
757
+ db
758
+ .select({ count: sql<number>`COUNT(*)` })
759
+ .from(schema.contentDatabaseItems)
760
+ .where(visibleItemFilter),
761
+ ]);
766
762
  const totalVisibleItems = Number(itemCount?.count ?? 0);
767
763
  if (tableQuery && totalVisibleItems > CONTENT_DATABASE_MAX_READ_LIMIT) {
768
764
  throw new Error(
769
765
  `Table constraints support up to ${CONTENT_DATABASE_MAX_READ_LIMIT} rows; this database has ${totalVisibleItems}.`,
770
766
  );
771
767
  }
768
+ const tableQueryMode = contentDatabaseTableQueryMode(
769
+ tableQuery,
770
+ propertySchema.sourceFields,
771
+ );
772
+ const serverTableQuery = tableQueryMode === "server" ? tableQuery : undefined;
772
773
 
773
- const databaseProperties = await listPropertiesForDatabase(databaseId);
774
+ const databaseProperties = await listPropertiesForDatabase(
775
+ databaseId,
776
+ undefined,
777
+ { propertySchema },
778
+ );
774
779
  const boundedProjectionPropertyIds =
775
780
  serverTableQuery && !database.systemRole
776
781
  ? boundedTableQueryProjectionPropertyIds(
@@ -779,7 +784,9 @@ export async function getContentDatabasePageResponse(
779
784
  )
780
785
  : null;
781
786
 
782
- let items;
787
+ let itemsRead: Promise<
788
+ Array<typeof schema.contentDatabaseItems.$inferSelect>
789
+ >;
783
790
  if (options.sidebarOrder && !serverTableQuery) {
784
791
  const customItemIds = options.sidebarOrder.itemIds;
785
792
  const customRank = contentDatabaseCustomOrderRank(customItemIds);
@@ -814,7 +821,7 @@ export async function getContentDatabasePageResponse(
814
821
  if (limit !== null) {
815
822
  orderedItemsQuery = orderedItemsQuery.limit(limit).offset(offset);
816
823
  }
817
- items = (await orderedItemsQuery).map((row) => row.item);
824
+ itemsRead = orderedItemsQuery.then((rows) => rows.map((row) => row.item));
818
825
  } else {
819
826
  let itemsQuery = db
820
827
  .select()
@@ -831,98 +838,108 @@ export async function getContentDatabasePageResponse(
831
838
  } else if (limit !== null) {
832
839
  itemsQuery = itemsQuery.limit(limit).offset(offset);
833
840
  }
834
- items = await itemsQuery;
841
+ itemsRead = itemsQuery.then((rows) => rows);
835
842
  }
836
- let boundedTableQueryTotal: number | null = null;
837
- if (serverTableQuery && boundedProjectionPropertyIds) {
838
- const candidateDocuments = await db
839
- .select({
840
- id: schema.documents.id,
841
- title: schema.documents.title,
842
- ownerEmail: schema.documents.ownerEmail,
843
- createdAt: schema.documents.createdAt,
844
- updatedAt: schema.documents.updatedAt,
845
- })
846
- .from(schema.documents)
847
- .innerJoin(
848
- schema.contentDatabaseItems,
849
- eq(schema.contentDatabaseItems.documentId, schema.documents.id),
843
+ const queryProperties = boundedProjectionPropertyIds
844
+ ? databaseProperties.filter((property) =>
845
+ boundedProjectionPropertyIds.has(property.definition.id),
850
846
  )
851
- .where(
852
- and(
853
- visibleItemFilter,
854
- eq(schema.documents.ownerEmail, database.ownerEmail),
855
- ),
856
- );
857
- const candidateDocumentById = new Map(
858
- candidateDocuments.map((document) => [document.id, document]),
859
- );
860
- const candidateValues =
861
- boundedProjectionPropertyIds.size > 0
862
- ? await db
847
+ : [];
848
+ const additionalBlocksPropertyIds = queryProperties.flatMap((property) =>
849
+ isBlocksPropertyType(property.definition.type) &&
850
+ !isPrimaryBlocksField(property.definition.options)
851
+ ? [property.definition.id]
852
+ : [],
853
+ );
854
+ const [itemRows, boundedCandidates] = await Promise.all([
855
+ itemsRead,
856
+ serverTableQuery && boundedProjectionPropertyIds
857
+ ? Promise.all([
858
+ db
863
859
  .select({
864
- documentId: schema.documentPropertyValues.documentId,
865
- propertyId: schema.documentPropertyValues.propertyId,
866
- valueJson: schema.documentPropertyValues.valueJson,
860
+ id: schema.documents.id,
861
+ title: schema.documents.title,
862
+ ownerEmail: schema.documents.ownerEmail,
863
+ createdAt: schema.documents.createdAt,
864
+ updatedAt: schema.documents.updatedAt,
867
865
  })
868
- .from(schema.documentPropertyValues)
866
+ .from(schema.documents)
869
867
  .innerJoin(
870
868
  schema.contentDatabaseItems,
871
- eq(
872
- schema.contentDatabaseItems.documentId,
873
- schema.documentPropertyValues.documentId,
874
- ),
869
+ eq(schema.contentDatabaseItems.documentId, schema.documents.id),
875
870
  )
876
871
  .where(
877
872
  and(
878
873
  visibleItemFilter,
879
- inArray(schema.documentPropertyValues.propertyId, [
880
- ...boundedProjectionPropertyIds,
881
- ]),
874
+ eq(schema.documents.ownerEmail, database.ownerEmail),
882
875
  ),
883
- )
884
- : [];
876
+ ),
877
+ boundedProjectionPropertyIds.size > 0
878
+ ? db
879
+ .select({
880
+ documentId: schema.documentPropertyValues.documentId,
881
+ propertyId: schema.documentPropertyValues.propertyId,
882
+ valueJson: schema.documentPropertyValues.valueJson,
883
+ })
884
+ .from(schema.documentPropertyValues)
885
+ .innerJoin(
886
+ schema.contentDatabaseItems,
887
+ eq(
888
+ schema.contentDatabaseItems.documentId,
889
+ schema.documentPropertyValues.documentId,
890
+ ),
891
+ )
892
+ .where(
893
+ and(
894
+ visibleItemFilter,
895
+ inArray(schema.documentPropertyValues.propertyId, [
896
+ ...boundedProjectionPropertyIds,
897
+ ]),
898
+ ),
899
+ )
900
+ : [],
901
+ additionalBlocksPropertyIds.length > 0
902
+ ? db
903
+ .select({
904
+ documentId: schema.documentBlockFieldContents.documentId,
905
+ propertyId: schema.documentBlockFieldContents.propertyId,
906
+ content: schema.documentBlockFieldContents.content,
907
+ })
908
+ .from(schema.documentBlockFieldContents)
909
+ .innerJoin(
910
+ schema.contentDatabaseItems,
911
+ eq(
912
+ schema.contentDatabaseItems.documentId,
913
+ schema.documentBlockFieldContents.documentId,
914
+ ),
915
+ )
916
+ .where(
917
+ and(
918
+ visibleItemFilter,
919
+ inArray(
920
+ schema.documentBlockFieldContents.propertyId,
921
+ additionalBlocksPropertyIds,
922
+ ),
923
+ ),
924
+ )
925
+ : [],
926
+ ])
927
+ : null,
928
+ ]);
929
+ let items = itemRows;
930
+ let boundedTableQueryTotal: number | null = null;
931
+ if (serverTableQuery && boundedCandidates) {
932
+ const [candidateDocuments, candidateValues, candidateBlockContents] =
933
+ boundedCandidates;
934
+ const candidateDocumentById = new Map(
935
+ candidateDocuments.map((document) => [document.id, document]),
936
+ );
885
937
  const candidateValueByDocumentAndProperty = new Map(
886
938
  candidateValues.map((value) => [
887
939
  `${value.documentId}\0${value.propertyId}`,
888
940
  parsePropertyValue(value.valueJson),
889
941
  ]),
890
942
  );
891
- const queryProperties = databaseProperties.filter((property) =>
892
- boundedProjectionPropertyIds.has(property.definition.id),
893
- );
894
- const additionalBlocksPropertyIds = queryProperties.flatMap((property) =>
895
- isBlocksPropertyType(property.definition.type) &&
896
- !isPrimaryBlocksField(property.definition.options)
897
- ? [property.definition.id]
898
- : [],
899
- );
900
- const candidateBlockContents =
901
- additionalBlocksPropertyIds.length > 0
902
- ? await db
903
- .select({
904
- documentId: schema.documentBlockFieldContents.documentId,
905
- propertyId: schema.documentBlockFieldContents.propertyId,
906
- content: schema.documentBlockFieldContents.content,
907
- })
908
- .from(schema.documentBlockFieldContents)
909
- .innerJoin(
910
- schema.contentDatabaseItems,
911
- eq(
912
- schema.contentDatabaseItems.documentId,
913
- schema.documentBlockFieldContents.documentId,
914
- ),
915
- )
916
- .where(
917
- and(
918
- visibleItemFilter,
919
- inArray(
920
- schema.documentBlockFieldContents.propertyId,
921
- additionalBlocksPropertyIds,
922
- ),
923
- ),
924
- )
925
- : [];
926
943
  const candidateBlockContentByDocumentAndProperty = new Map(
927
944
  candidateBlockContents.map((row) => [
928
945
  `${row.documentId}\0${row.propertyId}`,
@@ -1027,114 +1044,78 @@ export async function getContentDatabasePageResponse(
1027
1044
  )
1028
1045
  : [];
1029
1046
  const documentById = new Map(documents.map((doc) => [doc.id, doc]));
1030
- const favorites =
1047
+ const documentIds = documents.map((document) => document.id);
1048
+ const sharePrincipalClauses: NonNullable<ReturnType<typeof and>>[] = [];
1049
+ if (userEmail) {
1050
+ sharePrincipalClauses.push(
1051
+ and(
1052
+ eq(schema.documentShares.principalType, "user"),
1053
+ eq(schema.documentShares.principalId, userEmail),
1054
+ )!,
1055
+ );
1056
+ }
1057
+ if (activeOrgId) {
1058
+ sharePrincipalClauses.push(
1059
+ and(
1060
+ eq(schema.documentShares.principalType, "org"),
1061
+ eq(schema.documentShares.principalId, activeOrgId),
1062
+ )!,
1063
+ );
1064
+ }
1065
+ const [
1066
+ favorites,
1067
+ shareRows,
1068
+ propertiesByDocumentId,
1069
+ filesProjection,
1070
+ queuedBodyHydrationItemIds,
1071
+ workspaceMemberships,
1072
+ ] = await Promise.all([
1031
1073
  database.systemRole === "favorites"
1032
- ? new Set(documents.map((document) => document.id))
1074
+ ? new Set(documentIds)
1033
1075
  : userEmail
1034
- ? await favoriteDocumentIds(
1035
- db,
1036
- userEmail,
1037
- documents.map((document) => document.id),
1076
+ ? favoriteDocumentIds(db, userEmail, documentIds)
1077
+ : new Set<string>(),
1078
+ documents.length > 0 && sharePrincipalClauses.length > 0
1079
+ ? db
1080
+ .select({
1081
+ resourceId: schema.documentShares.resourceId,
1082
+ role: schema.documentShares.role,
1083
+ })
1084
+ .from(schema.documentShares)
1085
+ .where(
1086
+ and(
1087
+ inArray(schema.documentShares.resourceId, documentIds),
1088
+ or(...sharePrincipalClauses),
1089
+ ),
1038
1090
  )
1039
- : new Set<string>();
1040
- const shareRoleByDocumentId = new Map<string, ShareRole>();
1041
- if (documents.length > 0) {
1042
- const principalClauses: NonNullable<ReturnType<typeof and>>[] = [];
1043
- const userEmail = getRequestUserEmail();
1044
- const orgId = getRequestOrgId();
1045
- if (userEmail) {
1046
- principalClauses.push(
1047
- and(
1048
- eq(schema.documentShares.principalType, "user"),
1049
- eq(schema.documentShares.principalId, userEmail),
1050
- )!,
1051
- );
1052
- }
1053
- if (orgId) {
1054
- principalClauses.push(
1055
- and(
1056
- eq(schema.documentShares.principalType, "org"),
1057
- eq(schema.documentShares.principalId, orgId),
1058
- )!,
1059
- );
1060
- }
1061
- const shareRows =
1062
- principalClauses.length > 0
1063
- ? await db
1064
- .select({
1065
- resourceId: schema.documentShares.resourceId,
1066
- role: schema.documentShares.role,
1067
- })
1068
- .from(schema.documentShares)
1069
- .where(
1070
- and(
1071
- inArray(
1072
- schema.documentShares.resourceId,
1073
- documents.map((document) => document.id),
1074
- ),
1075
- or(...principalClauses),
1076
- ),
1077
- )
1078
- : [];
1079
- for (const row of shareRows) {
1080
- shareRoleByDocumentId.set(
1081
- row.resourceId,
1082
- strongerRole(
1083
- shareRoleByDocumentId.get(row.resourceId) ?? null,
1084
- row.role,
1085
- ),
1086
- );
1087
- }
1088
- }
1089
- const propertiesByDocumentId = await listPropertiesForDatabaseDocuments(
1090
- databaseId,
1091
- documents as Array<typeof schema.documents.$inferSelect>,
1092
- );
1093
- const filesProjection = await filesSystemPropertyProjection({
1094
- database,
1095
- documents,
1096
- properties: databaseProperties,
1097
- });
1098
- const responseProperties = filesProjection
1099
- ? applyFilesSystemPropertyProjection({
1100
- properties: databaseProperties,
1101
- projection: filesProjection,
1102
- })
1103
- : databaseProperties;
1104
- if (filesProjection) {
1105
- for (const document of documents) {
1106
- propertiesByDocumentId.set(
1107
- document.id,
1108
- applyFilesSystemPropertyProjection({
1109
- properties: propertiesByDocumentId.get(document.id) ?? [],
1110
- projection: filesProjection,
1111
- documentId: document.id,
1112
- }),
1113
- );
1114
- }
1115
- }
1116
- const queuedBodyHydrationItemIds =
1091
+ : [],
1092
+ listPropertiesForDatabaseDocuments(
1093
+ databaseId,
1094
+ documents as Array<typeof schema.documents.$inferSelect>,
1095
+ { includeBlocksFieldIdentity: false, propertySchema },
1096
+ ),
1097
+ filesSystemPropertyProjection({
1098
+ database,
1099
+ documents,
1100
+ properties: databaseProperties,
1101
+ }),
1117
1102
  items.length > 0
1118
- ? new Set(
1119
- (
1120
- await db
1121
- .select({
1122
- databaseItemId:
1123
- schema.contentDatabaseBodyHydrationQueue.databaseItemId,
1124
- })
1125
- .from(schema.contentDatabaseBodyHydrationQueue)
1126
- .where(
1127
- inArray(
1128
- schema.contentDatabaseBodyHydrationQueue.databaseItemId,
1129
- items.map((item) => item.id),
1130
- ),
1131
- )
1132
- ).map((row) => row.databaseItemId),
1133
- )
1134
- : new Set<string>();
1135
- const workspaceMemberships =
1103
+ ? db
1104
+ .select({
1105
+ databaseItemId:
1106
+ schema.contentDatabaseBodyHydrationQueue.databaseItemId,
1107
+ })
1108
+ .from(schema.contentDatabaseBodyHydrationQueue)
1109
+ .where(
1110
+ inArray(
1111
+ schema.contentDatabaseBodyHydrationQueue.databaseItemId,
1112
+ items.map((item) => item.id),
1113
+ ),
1114
+ )
1115
+ .then((rows) => new Set(rows.map((row) => row.databaseItemId)))
1116
+ : new Set<string>(),
1136
1117
  database.systemRole === "favorites" && documents.length > 0
1137
- ? await db
1118
+ ? db
1138
1119
  .select({
1139
1120
  documentId: schema.contentDatabaseItems.documentId,
1140
1121
  databaseId: schema.contentDatabaseItems.databaseId,
@@ -1149,15 +1130,38 @@ export async function getContentDatabasePageResponse(
1149
1130
  )
1150
1131
  .where(
1151
1132
  and(
1152
- inArray(
1153
- schema.contentDatabaseItems.documentId,
1154
- documents.map((document) => document.id),
1155
- ),
1133
+ inArray(schema.contentDatabaseItems.documentId, documentIds),
1156
1134
  eq(schema.contentDatabases.systemRole, "files"),
1157
1135
  isNull(schema.contentDatabases.deletedAt),
1158
1136
  ),
1159
1137
  )
1160
- : [];
1138
+ : [],
1139
+ ]);
1140
+ const shareRoleByDocumentId = new Map<string, ShareRole>();
1141
+ for (const row of shareRows) {
1142
+ shareRoleByDocumentId.set(
1143
+ row.resourceId,
1144
+ strongerRole(shareRoleByDocumentId.get(row.resourceId) ?? null, row.role),
1145
+ );
1146
+ }
1147
+ const responseProperties = filesProjection
1148
+ ? applyFilesSystemPropertyProjection({
1149
+ properties: databaseProperties,
1150
+ projection: filesProjection,
1151
+ })
1152
+ : databaseProperties;
1153
+ if (filesProjection) {
1154
+ for (const document of documents) {
1155
+ propertiesByDocumentId.set(
1156
+ document.id,
1157
+ applyFilesSystemPropertyProjection({
1158
+ properties: propertiesByDocumentId.get(document.id) ?? [],
1159
+ projection: filesProjection,
1160
+ documentId: document.id,
1161
+ }),
1162
+ );
1163
+ }
1164
+ }
1161
1165
  const workspaceDatabaseIdByDocumentId = new Map(
1162
1166
  workspaceMemberships.map((membership) => [
1163
1167
  membership.documentId,
@@ -1318,52 +1322,78 @@ export async function getContentDatabaseResponse(
1318
1322
  filesMembershipDatabaseId?: string;
1319
1323
  sidebarOrder?: ContentSidebarViewOrder;
1320
1324
  database?: typeof schema.contentDatabases.$inferSelect;
1325
+ /** The caller's role on the database page, when it already resolved it. */
1326
+ accessRole?: ResolvedAccess["role"] | null;
1321
1327
  } = {},
1322
1328
  ): Promise<ContentDatabaseResponse> {
1323
- const page = await getContentDatabasePageResponse(databaseId, options);
1324
1329
  const db = getDb();
1325
- const [databaseDocument] = await db
1326
- .select({
1327
- id: schema.documents.id,
1328
- parentId: schema.documents.parentId,
1329
- description: schema.documents.description,
1330
- })
1331
- .from(schema.documents)
1332
- .where(
1333
- and(
1334
- eq(schema.documents.id, page.databaseRecord.documentId),
1335
- accessFilter(schema.documents, schema.documentShares),
1330
+ const database =
1331
+ options.database ??
1332
+ (
1333
+ await db
1334
+ .select()
1335
+ .from(schema.contentDatabases)
1336
+ .where(eq(schema.contentDatabases.id, databaseId))
1337
+ )[0];
1338
+ if (!database || database.deletedAt) {
1339
+ fail(`Database "${databaseId}" not found`, {
1340
+ errorCode: "DATABASE_NOT_FOUND",
1341
+ statusCode: 404,
1342
+ });
1343
+ }
1344
+ const [propertySchema, [databaseDocument]] = await Promise.all([
1345
+ readDatabasePropertySchema(db, database.id),
1346
+ db
1347
+ .select({
1348
+ id: schema.documents.id,
1349
+ parentId: schema.documents.parentId,
1350
+ description: schema.documents.description,
1351
+ })
1352
+ .from(schema.documents)
1353
+ .where(
1354
+ and(
1355
+ eq(schema.documents.id, database.documentId),
1356
+ accessFilter(schema.documents, schema.documentShares),
1357
+ ),
1336
1358
  ),
1337
- );
1338
- const contextPath = databaseDocument
1339
- ? await getDocumentContextPath(databaseDocument)
1340
- : [];
1341
-
1342
- const mutationContract =
1343
- page.databaseRecord.spaceId && !page.databaseRecord.systemRole
1344
- ? await getDatabaseMutationContract(
1359
+ ]);
1360
+ const [page, contextPath, contracts] = await Promise.all([
1361
+ getContentDatabasePageResponse(database.id, {
1362
+ ...options,
1363
+ database,
1364
+ propertySchema,
1365
+ }),
1366
+ databaseDocument ? getDocumentContextPath(databaseDocument) : [],
1367
+ database.spaceId && !database.systemRole
1368
+ ? getDatabaseMutationContract(
1345
1369
  {
1346
- authorityScope: page.databaseRecord.orgId
1347
- ? {
1348
- kind: "organization",
1349
- id: page.databaseRecord.orgId,
1350
- }
1351
- : {
1352
- kind: "personal",
1353
- id: page.databaseRecord.ownerEmail,
1354
- },
1355
- spaceId: page.databaseRecord.spaceId,
1356
- databaseId: page.databaseRecord.id,
1357
- databaseDocumentId: page.databaseRecord.documentId,
1370
+ authorityScope: database.orgId
1371
+ ? { kind: "organization", id: database.orgId }
1372
+ : { kind: "personal", id: database.ownerEmail },
1373
+ spaceId: database.spaceId,
1374
+ databaseId: database.id,
1375
+ databaseDocumentId: database.documentId,
1358
1376
  },
1359
- { accessAlreadyResolved: true },
1360
- )
1361
- : undefined;
1377
+ {
1378
+ accessAlreadyResolved: true,
1379
+ loaded: {
1380
+ database,
1381
+ definitions: propertySchema.definitions,
1382
+ sourceManagedPropertyIds: propertySchema.sourceManagedPropertyIds,
1383
+ },
1384
+ },
1385
+ ).then(async (mutationContract) => ({
1386
+ mutationContract,
1387
+ setupContract: await getDatabaseSetupContract(
1388
+ database,
1389
+ mutationContract,
1390
+ { accessRole: options.accessRole },
1391
+ ),
1392
+ }))
1393
+ : undefined,
1394
+ ]);
1362
1395
  return {
1363
- database: serializeDatabase(
1364
- page.databaseRecord,
1365
- databaseDocument?.description ?? "",
1366
- ),
1396
+ database: serializeDatabase(database, databaseDocument?.description ?? ""),
1367
1397
  contextPath,
1368
1398
  properties: page.properties,
1369
1399
  items: page.items,
@@ -1371,11 +1401,9 @@ export async function getContentDatabaseResponse(
1371
1401
  sources: page.sources,
1372
1402
  pagination: page.pagination,
1373
1403
  tableQueryMode: page.tableQueryMode,
1374
- mutationContract,
1375
- configurationRevision: configurationRevision(page.databaseRecord),
1376
- setupContract: mutationContract
1377
- ? await getDatabaseSetupContract(page.databaseRecord, mutationContract)
1378
- : undefined,
1404
+ mutationContract: contracts?.mutationContract,
1405
+ configurationRevision: configurationRevision(database),
1406
+ setupContract: contracts?.setupContract,
1379
1407
  };
1380
1408
  }
1381
1409