@agent-native/core 0.133.1 → 0.133.3

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 (76) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +12 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/a2a/client.ts +22 -5
  5. package/corpus/core/src/client/use-action.ts +6 -0
  6. package/corpus/core/src/integrations/webhook-handler.ts +7 -0
  7. package/corpus/core/src/scripts/call-agent.ts +29 -2
  8. package/corpus/templates/content/actions/_batch-utils.ts +33 -0
  9. package/corpus/templates/content/actions/_builder-cms-read-client.ts +173 -81
  10. package/corpus/templates/content/actions/_content-files.ts +31 -21
  11. package/corpus/templates/content/actions/_database-source-utils.ts +653 -155
  12. package/corpus/templates/content/actions/_database-utils.ts +535 -41
  13. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +291 -240
  14. package/corpus/templates/content/actions/add-database-item.ts +15 -1
  15. package/corpus/templates/content/actions/attach-content-database-source.ts +156 -58
  16. package/corpus/templates/content/actions/bind-content-database-source-field.ts +2 -2
  17. package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +4 -1
  18. package/corpus/templates/content/actions/delete-database-items.ts +8 -2
  19. package/corpus/templates/content/actions/disconnect-content-database-source.ts +2 -2
  20. package/corpus/templates/content/actions/duplicate-database-item.ts +15 -1
  21. package/corpus/templates/content/actions/duplicate-database-items.ts +19 -1
  22. package/corpus/templates/content/actions/execute-builder-source-execution.ts +2 -1
  23. package/corpus/templates/content/actions/get-content-database.ts +12 -64
  24. package/corpus/templates/content/actions/move-database-item.ts +4 -1
  25. package/corpus/templates/content/actions/prepare-builder-source-execution.ts +1 -1
  26. package/corpus/templates/content/actions/prepare-builder-source-review.ts +4 -8
  27. package/corpus/templates/content/actions/preview-content-database-source-attach.ts +92 -0
  28. package/corpus/templates/content/actions/process-builder-body-hydration.ts +2 -1
  29. package/corpus/templates/content/actions/query-content-database-items.ts +64 -0
  30. package/corpus/templates/content/actions/refresh-content-database-source.ts +7 -0
  31. package/corpus/templates/content/actions/review-content-database-source-change-set.ts +1 -1
  32. package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +1 -1
  33. package/corpus/templates/content/actions/stage-builder-revision.ts +1 -1
  34. package/corpus/templates/content/actions/update-content-database-personal-view.ts +29 -3
  35. package/corpus/templates/content/actions/update-content-database-view.ts +1 -1
  36. package/corpus/templates/content/actions/validate-builder-source-execution.ts +1 -1
  37. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +3 -22
  38. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +267 -105
  39. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +1 -34
  40. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +159 -4
  41. package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +4 -211
  42. package/corpus/templates/content/app/hooks/use-content-database.ts +285 -24
  43. package/corpus/templates/content/app/hooks/use-document-properties.ts +7 -6
  44. package/corpus/templates/content/app/i18n-data.ts +10 -0
  45. package/corpus/templates/content/changelog/2026-07-29-large-databases-keep-useful-rows-visible.md +6 -0
  46. package/corpus/templates/content/changelog/2026-07-30-builder-source-columns-now-appear-immediately-when-connected.md +6 -0
  47. package/corpus/templates/content/changelog/2026-07-30-deleting-a-page-no-longer-leaves-the-content-sidebar-unrespo.md +6 -0
  48. package/corpus/templates/content/changelog/2026-07-30-large-builder-backed-tables-show-useful-rows-sooner-and-fini.md +6 -0
  49. package/corpus/templates/content/changelog/2026-08-01-large-builder-databases-now-show-rows-immediately-and-finish.md +6 -0
  50. package/corpus/templates/content/e2e/playwright.config.ts +2 -1
  51. package/corpus/templates/content/parity/matrix.md +2 -1
  52. package/corpus/templates/content/parity/matrix.ts +25 -0
  53. package/corpus/templates/content/shared/api.ts +54 -4
  54. package/corpus/templates/content/shared/database-query.ts +359 -0
  55. package/dist/a2a/client.d.ts +9 -1
  56. package/dist/a2a/client.d.ts.map +1 -1
  57. package/dist/a2a/client.js +12 -4
  58. package/dist/a2a/client.js.map +1 -1
  59. package/dist/client/use-action.d.ts.map +1 -1
  60. package/dist/client/use-action.js +6 -0
  61. package/dist/client/use-action.js.map +1 -1
  62. package/dist/collab/routes.d.ts +1 -1
  63. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  64. package/dist/integrations/webhook-handler.js +3 -0
  65. package/dist/integrations/webhook-handler.js.map +1 -1
  66. package/dist/observability/routes.d.ts +3 -3
  67. package/dist/progress/routes.d.ts +1 -1
  68. package/dist/scripts/call-agent.d.ts.map +1 -1
  69. package/dist/scripts/call-agent.js +24 -2
  70. package/dist/scripts/call-agent.js.map +1 -1
  71. package/dist/server/transcribe-voice.d.ts +1 -1
  72. package/package.json +1 -1
  73. package/src/a2a/client.ts +22 -5
  74. package/src/client/use-action.ts +6 -0
  75. package/src/integrations/webhook-handler.ts +7 -0
  76. package/src/scripts/call-agent.ts +29 -2
@@ -6,11 +6,16 @@ import type {
6
6
  AddContentDatabaseSourceFieldPropertyRequest,
7
7
  AddDatabaseItemRequest,
8
8
  AttachContentDatabaseSourceRequest,
9
+ BuilderCmsAttachPreviewResponse,
9
10
  BuilderCmsModelsResponse,
10
11
  CancelPreparedBuilderSourceUpdateRequest,
11
12
  CancelPreparedBuilderSourceUpdateResponse,
12
13
  ChangeContentDatabaseSourceRoleRequest,
13
14
  ContentDatabaseResponse,
15
+ ContentDatabaseSourceAttachmentAck,
16
+ ContentDatabaseSourceAttachmentResult,
17
+ ContentDatabaseItemsPageResponse,
18
+ ContentDatabaseTableQuery,
14
19
  ContentDatabaseItem,
15
20
  ContentDatabasePersonalViewResponse,
16
21
  ContentDatabaseSourceFieldMapping,
@@ -60,6 +65,11 @@ export function contentDatabaseByIdQueryKey(databaseId: string) {
60
65
  return ["action", "get-content-database", { databaseId }] as const;
61
66
  }
62
67
 
68
+ export const contentDatabaseItemsPageQueryKey = [
69
+ "action",
70
+ "query-content-database-items",
71
+ ] as const;
72
+
63
73
  export function applyOptimisticItemToContentDatabase(
64
74
  current: ContentDatabaseResponse | undefined,
65
75
  item: ContentDatabaseItem,
@@ -174,21 +184,59 @@ export function contentDatabaseQueryFilter(documentId: string) {
174
184
  };
175
185
  }
176
186
 
187
+ export function contentDatabaseConstrainedQueryFilter(documentId: string) {
188
+ return {
189
+ queryKey: ["action", "get-content-database"],
190
+ predicate: (query: Query) => {
191
+ if (!isContentDatabaseQueryForDocument(query.queryKey, documentId)) {
192
+ return false;
193
+ }
194
+ const params = query.queryKey[2] as { tableQuery?: unknown };
195
+ return params.tableQuery !== undefined;
196
+ },
197
+ };
198
+ }
199
+
177
200
  export function writeContentDatabaseResponseToCache(
178
201
  queryClient: Pick<QueryClient, "setQueryData" | "setQueriesData">,
179
202
  documentId: string,
180
203
  data: ContentDatabaseResponse,
181
204
  ) {
182
- queryClient.setQueryData<ContentDatabaseResponse>(
183
- contentDatabaseQueryKey(documentId),
184
- data,
185
- );
205
+ if (!data.pagination) {
206
+ queryClient.setQueryData<ContentDatabaseResponse>(
207
+ contentDatabaseQueryKey(documentId),
208
+ data,
209
+ );
210
+ }
186
211
  queryClient.setQueriesData<ContentDatabaseResponse>(
187
- contentDatabaseQueryFilter(documentId),
212
+ {
213
+ queryKey: ["action", "get-content-database"],
214
+ predicate: (query) =>
215
+ contentDatabaseResponseCanSeedQuery(query.queryKey, documentId, data),
216
+ },
188
217
  data,
189
218
  );
190
219
  }
191
220
 
221
+ export function contentDatabaseResponseCanSeedQuery(
222
+ queryKey: readonly unknown[],
223
+ documentId: string,
224
+ data: ContentDatabaseResponse,
225
+ ) {
226
+ if (!isContentDatabaseQueryForDocument(queryKey, documentId)) return false;
227
+ const params = queryKey[2] as {
228
+ limit?: unknown;
229
+ offset?: unknown;
230
+ tableQuery?: unknown;
231
+ };
232
+ if (params.tableQuery !== undefined) return false;
233
+ if (!data.pagination) return params.limit === undefined;
234
+ return (
235
+ params.limit === data.pagination.limit &&
236
+ (params.offset ?? 0) === data.pagination.offset
237
+ );
238
+ }
239
+
192
240
  export function applyOptimisticBuilderWriteMode(
193
241
  current: ContentDatabaseResponse | undefined,
194
242
  request: SetContentDatabaseSourceWriteModeRequest,
@@ -583,9 +631,13 @@ function removeOptimisticSourceFieldProperty(
583
631
  };
584
632
  }
585
633
 
586
- export function useContentDatabase(documentId: string | null, limit?: number) {
634
+ export function useContentDatabase(
635
+ documentId: string | null,
636
+ limit?: number,
637
+ tableQuery?: ContentDatabaseTableQuery,
638
+ ) {
587
639
  const queryClient = useQueryClient();
588
- return useActionQuery<ContentDatabaseResponse>(
640
+ const baseQuery = useActionQuery<ContentDatabaseResponse>(
589
641
  "get-content-database",
590
642
  documentId ? { documentId, limit } : undefined,
591
643
  {
@@ -604,6 +656,39 @@ export function useContentDatabase(documentId: string | null, limit?: number) {
604
656
  initialDataUpdatedAt: 0,
605
657
  },
606
658
  );
659
+ const pageQuery = useActionQuery<ContentDatabaseItemsPageResponse>(
660
+ "query-content-database-items",
661
+ documentId && tableQuery ? { documentId, limit, tableQuery } : undefined,
662
+ {
663
+ enabled: Boolean(documentId && tableQuery),
664
+ retry: false,
665
+ placeholderData: (previous) => previous,
666
+ },
667
+ );
668
+ const page = tableQuery ? pageQuery.data : undefined;
669
+ const data =
670
+ page &&
671
+ baseQuery.data &&
672
+ !baseQuery.data.attachPreview &&
673
+ !isContentDatabaseUnavailable(baseQuery.data)
674
+ ? {
675
+ ...baseQuery.data,
676
+ items: page.items,
677
+ source: page.source,
678
+ sources: page.sources,
679
+ pagination: page.pagination,
680
+ tableQueryMode: page.tableQueryMode,
681
+ }
682
+ : baseQuery.data;
683
+ return {
684
+ ...baseQuery,
685
+ data,
686
+ isLoading: tableQuery ? pageQuery.isLoading && !data : baseQuery.isLoading,
687
+ isFetching: tableQuery ? pageQuery.isFetching : baseQuery.isFetching,
688
+ isError: tableQuery ? pageQuery.isError : baseQuery.isError,
689
+ error: tableQuery ? pageQuery.error : baseQuery.error,
690
+ refetch: tableQuery ? pageQuery.refetch : baseQuery.refetch,
691
+ };
607
692
  }
608
693
 
609
694
  export function useContentDatabaseById(databaseId: string | null) {
@@ -749,12 +834,28 @@ export function useAddDatabaseItem(documentId: string) {
749
834
  return useActionMutation<ContentDatabaseResponse, AddDatabaseItemRequest>(
750
835
  "add-database-item",
751
836
  {
837
+ skipActionQueryInvalidation: true,
752
838
  onSuccess: (data) => {
753
- // The action returns the committed row and full database snapshot.
754
- // Seed every active pagination key before invalidating so navigating
755
- // away from the creation side-peek cannot briefly lose an appended row
756
- // behind an older 100/200-row response.
757
- writeContentDatabaseResponseToCache(queryClient, documentId, data);
839
+ if (data.createdItem) {
840
+ queryClient.setQueriesData<ContentDatabaseResponse>(
841
+ {
842
+ queryKey: ["action", "get-content-database"],
843
+ predicate: (query) => {
844
+ if (
845
+ !isContentDatabaseQueryForDocument(query.queryKey, documentId)
846
+ ) {
847
+ return false;
848
+ }
849
+ const params = query.queryKey[2] as {
850
+ tableQuery?: unknown;
851
+ };
852
+ return params.tableQuery === undefined;
853
+ },
854
+ },
855
+ (current) =>
856
+ applyOptimisticItemToContentDatabase(current, data.createdItem!),
857
+ );
858
+ }
758
859
  queryClient.invalidateQueries({
759
860
  queryKey: contentDatabaseQueryKey(documentId),
760
861
  });
@@ -779,6 +880,9 @@ export function useSubmitContentDatabaseForm(documentId: string) {
779
880
  queryClient.invalidateQueries({
780
881
  queryKey: contentDatabaseQueryKey(documentId),
781
882
  });
883
+ queryClient.invalidateQueries({
884
+ queryKey: contentDatabaseItemsPageQueryKey,
885
+ });
782
886
  queryClient.invalidateQueries({
783
887
  queryKey: ["action", "list-documents"],
784
888
  });
@@ -796,6 +900,9 @@ export function useDuplicateDatabaseItem(documentId: string) {
796
900
  queryClient.invalidateQueries({
797
901
  queryKey: contentDatabaseQueryKey(documentId),
798
902
  });
903
+ queryClient.invalidateQueries({
904
+ queryKey: contentDatabaseItemsPageQueryKey,
905
+ });
799
906
  queryClient.invalidateQueries({
800
907
  queryKey: ["action", "list-documents"],
801
908
  });
@@ -912,13 +1019,18 @@ export function useUpdateContentDatabaseView(documentId: string) {
912
1019
  ContentDatabaseResponse,
913
1020
  UpdateContentDatabaseViewRequest
914
1021
  >("update-content-database-view", {
915
- onSuccess: () => {
916
- queryClient.invalidateQueries({
917
- queryKey: contentDatabaseQueryKey(documentId),
918
- });
919
- queryClient.invalidateQueries({
920
- queryKey: ["action", "get-content-database-source", { documentId }],
921
- });
1022
+ skipActionQueryInvalidation: true,
1023
+ onSuccess: (data) => {
1024
+ queryClient.setQueriesData<ContentDatabaseResponse>(
1025
+ contentDatabaseQueryFilter(documentId),
1026
+ (current) =>
1027
+ current
1028
+ ? {
1029
+ ...current,
1030
+ database: data.database,
1031
+ }
1032
+ : current,
1033
+ );
922
1034
  },
923
1035
  });
924
1036
  }
@@ -991,17 +1103,76 @@ export function useUpdateContentDatabasePersonalView(
991
1103
  });
992
1104
  }
993
1105
 
994
- export function useAttachContentDatabaseSource(documentId: string) {
1106
+ export function useAttachContentDatabaseSource(
1107
+ documentId: string,
1108
+ fallbackData?: ContentDatabaseResponse,
1109
+ ) {
995
1110
  const queryClient = useQueryClient();
996
1111
  return useActionMutation<
997
- ContentDatabaseResponse,
1112
+ ContentDatabaseSourceAttachmentResult,
998
1113
  AttachContentDatabaseSourceRequest
999
1114
  >("attach-content-database-source", {
1115
+ skipActionQueryInvalidation: true,
1116
+ onMutate: async (variables) => {
1117
+ const previous = queryClient.getQueriesData<ContentDatabaseResponse>(
1118
+ contentDatabaseQueryFilter(documentId),
1119
+ );
1120
+ const cancelPending = queryClient.cancelQueries(
1121
+ contentDatabaseQueryFilter(documentId),
1122
+ { revert: false },
1123
+ );
1124
+ if (variables.sourceType === "builder-cms" && variables.sourceTable) {
1125
+ const preview =
1126
+ queryClient.getQueryData<BuilderCmsAttachPreviewResponse>([
1127
+ "action",
1128
+ "preview-content-database-source-attach",
1129
+ {
1130
+ documentId,
1131
+ sourceTable: variables.sourceTable,
1132
+ fieldPaths: variables.builderFieldPaths,
1133
+ },
1134
+ ]);
1135
+ if (preview) {
1136
+ writeBuilderAttachPreviewToCache(
1137
+ queryClient,
1138
+ documentId,
1139
+ preview,
1140
+ fallbackData,
1141
+ );
1142
+ }
1143
+ }
1144
+ await cancelPending;
1145
+ return { previous };
1146
+ },
1147
+ onError: (_error, _variables, context) => {
1148
+ const previous = (
1149
+ context as
1150
+ | {
1151
+ previous?: Array<
1152
+ [readonly unknown[], ContentDatabaseResponse | undefined]
1153
+ >;
1154
+ }
1155
+ | undefined
1156
+ )?.previous;
1157
+ for (const [queryKey, data] of previous ?? []) {
1158
+ queryClient.setQueryData(queryKey, data);
1159
+ }
1160
+ },
1000
1161
  onSuccess: (data) => {
1001
- writeContentDatabaseResponseToCache(queryClient, documentId, data);
1162
+ if (!("responseProjection" in data)) {
1163
+ writeContentDatabaseResponseToCache(queryClient, documentId, data);
1164
+ } else {
1165
+ queryClient.setQueriesData<ContentDatabaseResponse>(
1166
+ contentDatabaseQueryFilter(documentId),
1167
+ (current) => applyBuilderAttachCompletion(current, data),
1168
+ );
1169
+ }
1002
1170
  queryClient.invalidateQueries({
1003
1171
  queryKey: contentDatabaseQueryKey(documentId),
1004
1172
  });
1173
+ queryClient.invalidateQueries({
1174
+ queryKey: contentDatabaseItemsPageQueryKey,
1175
+ });
1005
1176
  queryClient.invalidateQueries({
1006
1177
  queryKey: ["action", "get-content-database-source", { documentId }],
1007
1178
  });
@@ -1009,6 +1180,84 @@ export function useAttachContentDatabaseSource(documentId: string) {
1009
1180
  });
1010
1181
  }
1011
1182
 
1183
+ export function applyBuilderAttachCompletion(
1184
+ current: ContentDatabaseResponse | undefined,
1185
+ completion: ContentDatabaseSourceAttachmentAck,
1186
+ ) {
1187
+ if (!current) return current;
1188
+ return {
1189
+ ...current,
1190
+ pagination: current.pagination
1191
+ ? {
1192
+ ...current.pagination,
1193
+ totalItems: completion.importedItemCount,
1194
+ hasMore:
1195
+ current.pagination.returnedItems < completion.importedItemCount,
1196
+ }
1197
+ : current.pagination,
1198
+ attachPreview: {
1199
+ sourceTable: completion.sourceTable,
1200
+ fetchedAt: completion.fetchedAt,
1201
+ importedItemCount: completion.importedItemCount,
1202
+ complete: true,
1203
+ },
1204
+ };
1205
+ }
1206
+
1207
+ export function useBuilderCmsAttachPreview(args: {
1208
+ documentId: string;
1209
+ sourceTable: string | null;
1210
+ fieldPaths?: string[];
1211
+ enabled?: boolean;
1212
+ }) {
1213
+ return useActionQuery<BuilderCmsAttachPreviewResponse>(
1214
+ "preview-content-database-source-attach",
1215
+ args.sourceTable
1216
+ ? {
1217
+ documentId: args.documentId,
1218
+ sourceTable: args.sourceTable,
1219
+ fieldPaths: args.fieldPaths,
1220
+ }
1221
+ : undefined,
1222
+ {
1223
+ enabled: args.enabled !== false && Boolean(args.sourceTable),
1224
+ retry: false,
1225
+ staleTime: 30_000,
1226
+ },
1227
+ );
1228
+ }
1229
+
1230
+ export function writeBuilderAttachPreviewToCache(
1231
+ queryClient: Pick<QueryClient, "setQueriesData">,
1232
+ documentId: string,
1233
+ preview: BuilderCmsAttachPreviewResponse,
1234
+ fallbackData?: ContentDatabaseResponse,
1235
+ ) {
1236
+ queryClient.setQueriesData<ContentDatabaseResponse>(
1237
+ contentDatabaseQueryFilter(documentId),
1238
+ (current) => {
1239
+ const base = current ?? fallbackData ?? preview.base;
1240
+ return base
1241
+ ? {
1242
+ ...base,
1243
+ items: preview.items,
1244
+ pagination: {
1245
+ offset: 0,
1246
+ limit: preview.items.length || 1,
1247
+ totalItems: preview.items.length,
1248
+ returnedItems: preview.items.length,
1249
+ hasMore: preview.hasMore,
1250
+ },
1251
+ attachPreview: {
1252
+ sourceTable: preview.sourceTable,
1253
+ fetchedAt: preview.fetchedAt,
1254
+ },
1255
+ }
1256
+ : current;
1257
+ },
1258
+ );
1259
+ }
1260
+
1012
1261
  export function useChangeContentDatabaseSourceRole(documentId: string) {
1013
1262
  const queryClient = useQueryClient();
1014
1263
  return useActionMutation<
@@ -1032,6 +1281,7 @@ export function useAddContentDatabaseSourceFieldProperty(documentId: string) {
1032
1281
  ContentDatabaseSourceFieldPropertyResponse,
1033
1282
  AddContentDatabaseSourceFieldPropertyRequest
1034
1283
  >("add-content-database-source-field-property", {
1284
+ skipActionQueryInvalidation: true,
1035
1285
  onMutate: async (variables) => {
1036
1286
  await queryClient.cancelQueries({
1037
1287
  queryKey: contentDatabaseQueryKey(documentId),
@@ -1076,6 +1326,9 @@ export function useAddContentDatabaseSourceFieldProperty(documentId: string) {
1076
1326
  queryClient.invalidateQueries({
1077
1327
  queryKey: contentDatabaseQueryKey(documentId),
1078
1328
  });
1329
+ queryClient.invalidateQueries({
1330
+ queryKey: contentDatabaseItemsPageQueryKey,
1331
+ });
1079
1332
  queryClient.invalidateQueries({
1080
1333
  queryKey: ["action", "get-content-database-source", { documentId }],
1081
1334
  });
@@ -1208,6 +1461,7 @@ export function invalidateContentDatabaseSourceRefreshQueries(
1208
1461
  queryClient.invalidateQueries({
1209
1462
  queryKey: contentDatabaseQueryKey(documentId),
1210
1463
  });
1464
+ queryClient.invalidateQueries({ queryKey: contentDatabaseItemsPageQueryKey });
1211
1465
  queryClient.invalidateQueries({
1212
1466
  queryKey: ["action", "get-content-database-source", { documentId }],
1213
1467
  });
@@ -1220,8 +1474,14 @@ export function useProcessBuilderBodyHydration(documentId: string) {
1220
1474
  ProcessBuilderBodyHydrationRequest
1221
1475
  >("process-builder-body-hydration", {
1222
1476
  skipActionQueryInvalidation: true,
1223
- onSuccess: (_data, variables) => {
1224
- invalidateBuilderBodyHydrationQueries(queryClient, documentId, variables);
1477
+ onSuccess: (data, variables) => {
1478
+ if (data.remaining === 0 || variables.documentId) {
1479
+ invalidateBuilderBodyHydrationQueries(
1480
+ queryClient,
1481
+ documentId,
1482
+ variables,
1483
+ );
1484
+ }
1225
1485
  },
1226
1486
  });
1227
1487
  }
@@ -1236,6 +1496,7 @@ export function invalidateBuilderBodyHydrationQueries(
1236
1496
  queryClient.invalidateQueries({
1237
1497
  queryKey: contentDatabaseQueryKey(documentId),
1238
1498
  });
1499
+ queryClient.invalidateQueries({ queryKey: contentDatabaseItemsPageQueryKey });
1239
1500
  queryClient.invalidateQueries({
1240
1501
  queryKey: ["action", "get-content-database-source", { documentId }],
1241
1502
  });
@@ -18,6 +18,7 @@ import {
18
18
  applyDocumentPropertiesToDatabaseResponse,
19
19
  applyDocumentPropertyValueToDatabaseResponse,
20
20
  contentDatabaseQueryFilter,
21
+ contentDatabaseConstrainedQueryFilter,
21
22
  contentDatabaseQueryKey,
22
23
  removeDocumentPropertyFromDatabaseResponse,
23
24
  } from "./use-content-database";
@@ -93,9 +94,9 @@ export function useConfigureDocumentProperty(
93
94
  queryClient.invalidateQueries({
94
95
  queryKey: ["action", "get-document", { id: documentId }],
95
96
  });
96
- queryClient.invalidateQueries({
97
- ...contentDatabaseQueryFilter(databaseDocumentId),
98
- });
97
+ queryClient.invalidateQueries(
98
+ contentDatabaseConstrainedQueryFilter(databaseDocumentId),
99
+ );
99
100
  },
100
101
  });
101
102
  return withDatabaseScope(mutation, databaseId);
@@ -160,9 +161,9 @@ export function useSetDocumentProperty(
160
161
  queryClient.invalidateQueries({
161
162
  queryKey: ["action", "get-document", { id: variables.documentId }],
162
163
  });
163
- queryClient.invalidateQueries({
164
- ...contentDatabaseQueryFilter(databaseDocumentId),
165
- });
164
+ queryClient.invalidateQueries(
165
+ contentDatabaseConstrainedQueryFilter(databaseDocumentId),
166
+ );
166
167
  queryClient.invalidateQueries({
167
168
  queryKey: [
168
169
  "action",
@@ -26,6 +26,7 @@ const databaseMessages = {
26
26
  addingDetailsMatchedOn: "Adding details matched on {{field}}.",
27
27
  addingItems: "Adding items",
28
28
  addingItemsAsRows: "Adding items as their own rows in this database.",
29
+ attachingReadOnly: "Attaching · read-only",
29
30
  addMoreItemsToThisList: "Add more items to this list",
30
31
  addProperty: "Add property",
31
32
  allAvailableDetailFieldsAlreadyVisible:
@@ -8962,6 +8963,7 @@ export const messagesByLocale = {
8962
8963
  builderRowsFetchedSoFar: "目前已获取 {{count}} 行。",
8963
8964
  builderRowsFinishingUp: "Builder 行即将完成加载。",
8964
8965
  builderRowsLoadingBackground: "Builder 仍在后台加载行。",
8966
+ attachingReadOnly: "正在附加 · 只读",
8965
8967
  builderRowsLoadingHitSnag: "Builder 行加载遇到问题。",
8966
8968
  opening: "正在打开...",
8967
8969
  },
@@ -9147,6 +9149,7 @@ export const messagesByLocale = {
9147
9149
  "Las filas de Builder están terminando de cargarse.",
9148
9150
  builderRowsLoadingBackground:
9149
9151
  "Builder sigue cargando filas en segundo plano.",
9152
+ attachingReadOnly: "Adjuntando · solo lectura",
9150
9153
  builderRowsLoadingHitSnag:
9151
9154
  "La carga de filas de Builder tuvo un problema.",
9152
9155
  opening: "Abriendo...",
@@ -9344,6 +9347,7 @@ export const messagesByLocale = {
9344
9347
  builderRowsFinishingUp: "Les lignes Builder terminent leur chargement.",
9345
9348
  builderRowsLoadingBackground:
9346
9349
  "Builder charge encore des lignes en arrière-plan.",
9350
+ attachingReadOnly: "Ajout en cours · lecture seule",
9347
9351
  builderRowsLoadingHitSnag:
9348
9352
  "Le chargement des lignes Builder a rencontré un problème.",
9349
9353
  opening: "Ouverture...",
@@ -9540,6 +9544,7 @@ export const messagesByLocale = {
9540
9544
  builderRowsFinishingUp: "Builder-Zeilen werden fertig geladen.",
9541
9545
  builderRowsLoadingBackground:
9542
9546
  "Builder lädt weiterhin Zeilen im Hintergrund.",
9547
+ attachingReadOnly: "Wird angehängt · schreibgeschützt",
9543
9548
  builderRowsLoadingHitSnag:
9544
9549
  "Beim Laden der Builder-Zeilen ist ein Problem aufgetreten.",
9545
9550
  opening: "Wird geöffnet...",
@@ -9736,6 +9741,7 @@ export const messagesByLocale = {
9736
9741
  builderRowsFinishingUp: "Builder 行の読み込みを完了しています。",
9737
9742
  builderRowsLoadingBackground:
9738
9743
  "Builder はバックグラウンドで行を読み込み続けています。",
9744
+ attachingReadOnly: "接続中 · 読み取り専用",
9739
9745
  builderRowsLoadingHitSnag: "Builder 行の読み込みで問題が発生しました。",
9740
9746
  opening: "開いています...",
9741
9747
  },
@@ -9928,6 +9934,7 @@ export const messagesByLocale = {
9928
9934
  builderRowsFinishingUp: "Builder 행 로드를 마무리하는 중입니다.",
9929
9935
  builderRowsLoadingBackground:
9930
9936
  "Builder가 백그라운드에서 행을 계속 로드하고 있습니다.",
9937
+ attachingReadOnly: "연결 중 · 읽기 전용",
9931
9938
  builderRowsLoadingHitSnag: "Builder 행 로드 중 문제가 발생했습니다.",
9932
9939
  opening: "여는 중...",
9933
9940
  },
@@ -10115,6 +10122,7 @@ export const messagesByLocale = {
10115
10122
  "As linhas do Builder estão terminando de carregar.",
10116
10123
  builderRowsLoadingBackground:
10117
10124
  "O Builder ainda está carregando linhas em segundo plano.",
10125
+ attachingReadOnly: "Anexando · somente leitura",
10118
10126
  builderRowsLoadingHitSnag:
10119
10127
  "O carregamento de linhas do Builder encontrou um problema.",
10120
10128
  opening: "Abrindo...",
@@ -10307,6 +10315,7 @@ export const messagesByLocale = {
10307
10315
  builderRowsFinishingUp: "Builder पंक्तियां लोड होना पूरा कर रही हैं।",
10308
10316
  builderRowsLoadingBackground:
10309
10317
  "Builder अभी भी पृष्ठभूमि में पंक्तियां लोड कर रहा है।",
10318
+ attachingReadOnly: "संलग्न किया जा रहा है · केवल पढ़ने के लिए",
10310
10319
  builderRowsLoadingHitSnag: "Builder पंक्तियां लोड करने में समस्या आई।",
10311
10320
  opening: "खोला जा रहा है...",
10312
10321
  },
@@ -10488,6 +10497,7 @@ export const messagesByLocale = {
10488
10497
  builderRowsFetchedSoFar: "تم جلب {{count}} صفًا حتى الآن.",
10489
10498
  builderRowsFinishingUp: "صفوف Builder توشك على إكمال التحميل.",
10490
10499
  builderRowsLoadingBackground: "لا يزال Builder يحمّل الصفوف في الخلفية.",
10500
+ attachingReadOnly: "جارٍ الإرفاق · للقراءة فقط",
10491
10501
  builderRowsLoadingHitSnag: "واجه تحميل صفوف Builder مشكلة.",
10492
10502
  opening: "جارٍ الفتح...",
10493
10503
  },
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-29
4
+ ---
5
+
6
+ Large databases keep useful rows visible while table sorting and Builder review details load.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-30
4
+ ---
5
+
6
+ Builder source columns now appear immediately when connected entries already contain the selected field, including empty values.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-30
4
+ ---
5
+
6
+ Deleting a page no longer leaves the Content sidebar unresponsive.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-30
4
+ ---
5
+
6
+ Large Builder-backed tables show useful rows sooner and finish loading in the background.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-01
4
+ ---
5
+
6
+ Large Builder databases now show rows immediately and finish syncing much faster.
@@ -14,7 +14,8 @@ import { defineConfig, devices } from "@playwright/test";
14
14
  */
15
15
  export default defineConfig({
16
16
  testDir: ".",
17
- testMatch: /(registry-blocks|local-files|database-preview-menu)\.spec\.ts/,
17
+ testMatch:
18
+ /(registry-blocks|local-files|database-preview-menu|sidebar-delete)\.spec\.ts/,
18
19
  fullyParallel: true,
19
20
  workers: process.env.CI ? 2 : 3,
20
21
  retries: 2,
@@ -10,6 +10,7 @@ This generated matrix tracks whether high-value Content UI operations use the sa
10
10
  | database.private-preview-drafts | database | Persist and reconcile a user's private database-page preview draft | action-backed | `get-preview-document-draft`, `update-preview-document-draft` | `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-documents.ts` | A user's private preview draft is read, saved, conflict-checked, or deleted without changing the shared database page until the normal save flow applies it. | These per-user editor-state actions are intentionally hidden from agent tools because preview drafts are a private UI recovery mechanism. | - | P1 | covered | `actions/preview-document-draft.db.test.ts` | - | - |
11
11
  | database.properties-and-view-config | database | Configure properties, values, ordering, and saved views | action-backed | `configure-document-property`, `delete-document-property`, `duplicate-document-property`, `get-content-database-personal-view`, `list-document-properties`, `reorder-document-property`, `set-document-property`, `update-content-database-personal-view`, `update-content-database-view` | `app/components/editor/DocumentProperties.tsx`, `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-document-properties.ts` | Property schemas, property values, property order, filters, sorts, grouping, hidden columns, view type, and view settings are stored. | - | - | P0 | covered | `actions/bind-content-database-source-field.db.test.ts`, `actions/content-database-source-actions.test.ts`, `actions/resync-content-database-source.db.test.ts` | `database-source-scope` | - |
12
12
  | database.rows | database | Add, duplicate, move, open, and delete database rows | action-backed | `add-database-item`, `delete-database-items`, `delete-document`, `duplicate-database-items`, `duplicate-database-item`, `move-database-item`, `set-document-property` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/database/DatabaseView.tsx` | Database row backing documents and row ordering are created, duplicated, moved, edited, and deleted. | - | - | P0 | covered | `actions/database-row-batch-actions.db.test.ts`, `parity/__tests__/database-row-batch-reliability.test.ts` | `database-bulk-row-reliability` | - |
13
+ | database.table-query-page | database | Query one constrained page while retaining database metadata | action-backed | `query-content-database-items` | `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-content-database.ts` | - | This UI-only bounded projection is intentionally hidden with agentTool: false; agents use get-content-database for the complete database contract. | - | P0 | covered | `actions/content-database-lifecycle.db.test.ts`, `app/hooks/use-content-database.test.ts` | - | - |
13
14
  | editor.agent-assist-prompts | editor | Ask AI from slash generation or comment context | client-assist | - | `app/components/editor/SlashCommandMenu.tsx`, `app/components/editor/CommentsSidebar.tsx` | No direct durable mutation; the prompt asks the agent to use document actions when it decides to write. | - | - | P1 | none | - | - | - |
14
15
  | editor.client-formatting-and-insertions | editor | Rich text formatting, selection state, slash block insertion, and copy actions | client-only-ephemeral | - | `app/components/editor/BubbleToolbar.tsx`, `app/components/editor/SlashCommandMenu.tsx`, `app/components/editor/DocumentToolbar.tsx` | - | - | - | P1 | none | - | - | - |
15
16
  | editor.document-body-and-title | editor | Edit document title, body, icon, image alt text, and precise text | action-backed | `edit-document`, `pull-document`, `set-image-alt-text`, `transcribe-media`, `update-document` | `app/components/editor/DocumentEditor.tsx`, `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/extensions/ImageBlock.tsx`, `app/components/editor/SlashCommandMenu.tsx` | Document content, title, icon, image metadata, and text replacements are saved to the same document source. | - | - | P0 | covered | `actions/content-database-lifecycle.db.test.ts`, `actions/_local-file-documents.test.ts` | `document-search-edit` | - |
@@ -26,7 +27,7 @@ This generated matrix tracks whether high-value Content UI operations use the sa
26
27
  | source-sync.builder-cms-review-and-write-gates | source-sync | Review, stage, validate, cancel, and execute Builder CMS source writes | action-backed | `cancel-prepared-builder-source-update`, `execute-builder-source-batch`, `execute-builder-source-execution`, `prepare-builder-source-execution`, `prepare-builder-source-review`, `preview-builder-source-review`, `review-content-database-source-change-set`, `set-content-database-source-write-mode`, `stage-builder-source-bulk-update`, `stage-builder-revision`, `validate-builder-source-execution` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/components/editor/database-sources/BuilderSourceReviewDialog.tsx` | Builder source write mode, staged reviews, pre-dispatch cancellations, validation records, and bounded execution records are created through guarded actions. | - | - | P0 | covered | `actions/builder-source-review-gates.db.test.ts`, `actions/cancel-prepared-builder-source-update.db.test.ts`, `actions/execute-builder-source-execution.test.ts`, `actions/stage-builder-source-bulk-update.db.test.ts` | `builder-source-review-readonly` | - |
27
28
  | source-sync.builder-documents | source-sync | List, pull, check, and push Builder docs/blog MDX documents | action-backed | `check-builder-doc`, `list-builder-docs`, `pull-builder-doc`, `push-builder-doc` | `actions/list-builder-docs.ts`, `actions/pull-builder-doc.ts`, `actions/check-builder-doc.ts`, `actions/push-builder-doc.ts` | Builder docs/blog entries can be read into Content, checked locally, and pushed through guarded Builder document actions. | - | - | P1 | seeded | - | - | - |
28
29
  | source-sync.builder-required-field-materialization | source-sync | Add required Builder publishing fields to a connected collection | action-backed | `materialize-builder-required-fields` | `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-content-database.ts` | Required Builder fields are materialized as editable Content properties in one local mutation. | This bounded safe-model setup action is intentionally hidden from the agent tool list; the visible source settings surface invokes it. | - | P1 | covered | `actions/materialize-builder-required-fields.test.ts` | - | - |
29
- | source-sync.database-source-bindings | source-sync | Attach, inspect, refresh, disconnect, join, and bind database sources | action-backed | `add-content-database-source-field-property`, `attach-content-database-source`, `bind-content-database-source-field`, `change-content-database-source-role`, `disconnect-content-database-source`, `get-content-database-source`, `list-builder-cms-models`, `list-notion-database-sources`, `refresh-content-database-source`, `suggest-source-join-key` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/DocumentProperties.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-content-database.ts` | Mounted database source metadata, fields, source role, join keys, and source-field/property bindings are stored and refreshed. | - | - | P0 | covered | `actions/bind-content-database-source-field.db.test.ts`, `actions/content-database-source-actions.test.ts`, `actions/resync-content-database-source.db.test.ts` | `database-source-scope` | - |
30
+ | source-sync.database-source-bindings | source-sync | Attach, inspect, refresh, disconnect, join, and bind database sources | action-backed | `add-content-database-source-field-property`, `attach-content-database-source`, `bind-content-database-source-field`, `change-content-database-source-role`, `disconnect-content-database-source`, `get-content-database-source`, `list-builder-cms-models`, `list-notion-database-sources`, `preview-content-database-source-attach`, `refresh-content-database-source`, `suggest-source-join-key` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/DocumentProperties.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-content-database.ts` | Mounted database source metadata, fields, source role, join keys, and source-field/property bindings are stored and refreshed. | - | - | P0 | covered | `actions/bind-content-database-source-field.db.test.ts`, `actions/content-database-source-actions.test.ts`, `actions/resync-content-database-source.db.test.ts` | `database-source-scope` | - |
30
31
  | source-sync.provider-api-and-staged-datasets | source-sync | Inspect provider APIs and stage/query/delete large provider datasets | action-backed | `delete-staged-dataset`, `list-staged-datasets`, `provider-api-catalog`, `provider-api-docs`, `provider-api-request`, `query-staged-dataset` | `actions/provider-api-catalog.ts`, `actions/provider-api-docs.ts`, `actions/provider-api-request.ts`, `actions/query-staged-dataset.ts` | Provider API metadata and staged dataset scratch storage support scoped agent/source analysis. | - | - | P1 | seeded | - | - | - |
31
32
  | versions.history-and-restore | versions | Open version history and restore a previous document version | action-backed | `list-document-versions`, `restore-document-version` | `app/components/editor/VersionHistoryPanel.tsx`, `app/hooks/use-document-versions.ts` | Document versions are listed and selected versions can restore the document while snapshotting current state. | - | - | P0 | seeded | - | - | - |
32
33
  | workspace.spaces-and-files-catalog | workspace | Provision, navigate, and delete Content spaces through Files and Workspaces with personal expansion state | action-backed | `backfill-content-files`, `create-content-space`, `delete-content-space`, `ensure-content-spaces`, `get-content-sidebar-state`, `list-content-spaces`, `update-content-sidebar-state` | `app/components/sidebar/DocumentSidebar.tsx`, `app/hooks/use-content-spaces.ts` | Personal and organization spaces, user-created workspaces, their canonical Files databases, the personal Workspaces catalog, and each user's sidebar expansion state are stored and reconciled in SQL; deleting a user-created workspace atomically removes its catalog row and contents. | - | - | P0 | covered | `actions/content-spaces.db.test.ts`, `actions/content-files.db.test.ts`, `actions/content-sidebar-state.test.ts` | - | - |