@agent-native/core 0.80.5 → 0.80.6

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 (58) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +7 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/cli/create.ts +1 -0
  5. package/corpus/core/src/sharing/registry.ts +17 -0
  6. package/corpus/core/src/templates/default/pnpm-workspace.yaml +1 -0
  7. package/corpus/core/src/templates/workspace-root/pnpm-workspace.yaml +1 -0
  8. package/corpus/templates/content/AGENTS.md +45 -44
  9. package/corpus/templates/content/README.md +16 -0
  10. package/corpus/templates/content/actions/_builder-cms-read-client.ts +125 -0
  11. package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +28 -6
  12. package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +238 -69
  13. package/corpus/templates/content/actions/_builder-cms-write-settings.ts +125 -43
  14. package/corpus/templates/content/actions/_database-source-utils.ts +746 -97
  15. package/corpus/templates/content/actions/_database-utils.ts +17 -14
  16. package/corpus/templates/content/actions/_federation-join.ts +14 -2
  17. package/corpus/templates/content/actions/_join-suggestion.ts +89 -14
  18. package/corpus/templates/content/actions/_local-file-documents.ts +2 -1
  19. package/corpus/templates/content/actions/attach-content-database-source.ts +124 -5
  20. package/corpus/templates/content/actions/bind-content-database-source-field.ts +256 -0
  21. package/corpus/templates/content/actions/change-content-database-source-role.ts +420 -0
  22. package/corpus/templates/content/actions/create-document.ts +8 -0
  23. package/corpus/templates/content/actions/execute-builder-source-batch.ts +282 -0
  24. package/corpus/templates/content/actions/execute-builder-source-execution.ts +220 -8
  25. package/corpus/templates/content/actions/get-content-database.ts +10 -2
  26. package/corpus/templates/content/actions/prepare-builder-source-execution.ts +19 -2
  27. package/corpus/templates/content/actions/prepare-builder-source-review.ts +47 -15
  28. package/corpus/templates/content/actions/refresh-content-database-source.ts +11 -4
  29. package/corpus/templates/content/actions/review-content-database-source-change-set.ts +6 -2
  30. package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +32 -12
  31. package/corpus/templates/content/actions/stage-builder-revision.ts +14 -10
  32. package/corpus/templates/content/actions/validate-builder-source-execution.ts +25 -3
  33. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +1520 -553
  34. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +150 -1
  35. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +647 -66
  36. package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +543 -204
  37. package/corpus/templates/content/app/hooks/use-content-database.ts +62 -0
  38. package/corpus/templates/content/app/i18n/zh-TW.ts +64 -0
  39. package/corpus/templates/content/app/i18n-data.ts +784 -0
  40. package/corpus/templates/content/changelog/2026-06-29-builder-review-checks-now-preserve-publish-and-unpublish-cho.md +6 -0
  41. package/corpus/templates/content/changelog/2026-06-29-database-sources-can-now-be-added-as-more-rows-or-matched.md +6 -0
  42. package/corpus/templates/content/changelog/2026-06-29-fixed-loading-the-final-rows-in-larger-databases-without-bre.md +6 -0
  43. package/corpus/templates/content/shared/api.ts +91 -1
  44. package/corpus/templates/content/vite.config.ts +14 -7
  45. package/dist/cli/create.d.ts.map +1 -1
  46. package/dist/cli/create.js +1 -0
  47. package/dist/cli/create.js.map +1 -1
  48. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  49. package/dist/notifications/routes.d.ts +1 -1
  50. package/dist/observability/routes.d.ts +5 -5
  51. package/dist/sharing/registry.d.ts.map +1 -1
  52. package/dist/sharing/registry.js +11 -0
  53. package/dist/sharing/registry.js.map +1 -1
  54. package/dist/templates/default/pnpm-workspace.yaml +1 -0
  55. package/dist/templates/workspace-root/pnpm-workspace.yaml +1 -0
  56. package/package.json +1 -1
  57. package/src/templates/default/pnpm-workspace.yaml +1 -0
  58. package/src/templates/workspace-root/pnpm-workspace.yaml +1 -0
@@ -6,6 +6,7 @@ import {
6
6
  } from "@agent-native/core/client";
7
7
  import type {
8
8
  AddContentDatabaseSourceFieldPropertyRequest,
9
+ BindContentDatabaseSourceFieldRequest,
9
10
  ContentDatabaseResponse,
10
11
  ContentDatabaseSourceFieldPropertyResponse,
11
12
  ContentDatabaseSource,
@@ -848,6 +849,22 @@ function PropertyRow({
848
849
  );
849
850
  }
850
851
 
852
+ // Mirror of the server's propertyTypeForSourceField — keep in sync. Used to
853
+ // gate which source fields can bind into a column (type compatibility).
854
+ function propertyTypeForSourceFieldType(
855
+ sourceFieldType: string,
856
+ ): DocumentPropertyType {
857
+ if (sourceFieldType === "number") return "number";
858
+ if (sourceFieldType === "datetime" || sourceFieldType === "date") {
859
+ return "date";
860
+ }
861
+ if (sourceFieldType === "url") return "url";
862
+ if (sourceFieldType === "boolean" || sourceFieldType === "checkbox") {
863
+ return "checkbox";
864
+ }
865
+ return "text";
866
+ }
867
+
851
868
  export function PropertyManagementPopover({
852
869
  property,
853
870
  documentId,
@@ -857,6 +874,7 @@ export function PropertyManagementPopover({
857
874
  triggerTrailing,
858
875
  sourceField,
859
876
  sourceAttached = false,
877
+ sources,
860
878
  }: {
861
879
  property: DocumentProperty;
862
880
  documentId: string;
@@ -866,12 +884,65 @@ export function PropertyManagementPopover({
866
884
  triggerTrailing?: ReactNode;
867
885
  sourceField?: ContentDatabaseSource["fields"][number] | null;
868
886
  sourceAttached?: boolean;
887
+ sources?: ContentDatabaseSource[];
869
888
  }) {
870
889
  const t = useT();
871
890
  const configure = useConfigureDocumentProperty(documentId);
872
891
  const duplicate = useDuplicateDocumentProperty(documentId);
873
892
  const remove = useDeleteDocumentProperty(documentId);
874
893
  const { data: propertiesData } = useDocumentProperties(documentId);
894
+ const bindQueryClient = useQueryClient();
895
+ const bindSourceField = useActionMutation<
896
+ ContentDatabaseResponse,
897
+ BindContentDatabaseSourceFieldRequest
898
+ >("bind-content-database-source-field", {
899
+ onSuccess: () => {
900
+ bindQueryClient.invalidateQueries({
901
+ queryKey: ["action", "get-content-database"],
902
+ });
903
+ bindQueryClient.invalidateQueries({
904
+ queryKey: ["action", "list-document-properties", { documentId }],
905
+ });
906
+ },
907
+ });
908
+ // Per-source field bindings for THIS column (row-union): which source fields
909
+ // feed it, and which unmapped, type-compatible fields could be bound into it
910
+ // (at most one field per source per column).
911
+ const allSourceFieldEntries = (sources ?? []).flatMap((src) =>
912
+ src.fields.map((field) => ({ source: src, field })),
913
+ );
914
+ const boundSourceFields = allSourceFieldEntries.filter(
915
+ (entry) => entry.field.propertyId === property.definition.id,
916
+ );
917
+ const boundSourceIds = new Set(boundSourceFields.map((b) => b.source.id));
918
+ const columnType = property.definition.type;
919
+ const bindableSourceFields = allSourceFieldEntries.filter((entry) => {
920
+ if (
921
+ entry.field.propertyId ||
922
+ entry.field.mappingType === "title" ||
923
+ entry.field.mappingType === "system" ||
924
+ entry.field.writeOwner === "derived" ||
925
+ boundSourceIds.has(entry.source.id)
926
+ ) {
927
+ return false;
928
+ }
929
+ const fieldIsMultiValue = [
930
+ "list",
931
+ "array",
932
+ "tags",
933
+ "multi_select",
934
+ ].includes(entry.field.sourceFieldType.trim().toLowerCase());
935
+ // text columns accept any SCALAR field but not multi-value ones (lossy);
936
+ // otherwise the derived type must match the column type.
937
+ return columnType === "text"
938
+ ? !fieldIsMultiValue
939
+ : columnType ===
940
+ propertyTypeForSourceFieldType(entry.field.sourceFieldType);
941
+ });
942
+ const showBindingEditor =
943
+ !isComputedPropertyType(columnType) &&
944
+ columnType !== "blocks" &&
945
+ (boundSourceFields.length > 0 || bindableSourceFields.length > 0);
875
946
  // Whether deleting THIS property removes the last Blocks field of the type —
876
947
  // i.e. the body. Drives the yellow warning in the delete dialog.
877
948
  const blocksFieldCount = (propertiesData?.properties ?? []).filter(
@@ -1169,7 +1240,85 @@ export function PropertyManagementPopover({
1169
1240
  </div>
1170
1241
  ) : null}
1171
1242
 
1172
- {sourceAttached ? (
1243
+ {showBindingEditor ? (
1244
+ <>
1245
+ <DropdownMenuSeparator />
1246
+ <div className="grid gap-1.5 px-2 py-1.5 text-xs">
1247
+ <div className="font-medium text-foreground">
1248
+ {t("database.sourcesFeedingThisColumn")}
1249
+ </div>
1250
+ {boundSourceFields.length > 0 ? (
1251
+ <div className="grid gap-1">
1252
+ {boundSourceFields.map(({ source: src, field }) => (
1253
+ <div
1254
+ key={field.id}
1255
+ className="flex min-w-0 items-center gap-1.5"
1256
+ >
1257
+ <IconLink className="size-3.5 shrink-0 text-muted-foreground" />
1258
+ <span className="min-w-0 flex-1 truncate text-muted-foreground">
1259
+ <span className="text-foreground">
1260
+ {src.sourceName}
1261
+ </span>{" "}
1262
+ · {field.sourceFieldLabel}
1263
+ </span>
1264
+ <button
1265
+ type="button"
1266
+ aria-label={`Unbind ${field.sourceFieldLabel} from ${src.sourceName}`}
1267
+ disabled={bindSourceField.isPending}
1268
+ className="shrink-0 rounded p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50"
1269
+ onClick={() =>
1270
+ void bindSourceField.mutateAsync({
1271
+ documentId,
1272
+ sourceFieldId: field.id,
1273
+ propertyId: null,
1274
+ })
1275
+ }
1276
+ >
1277
+ <IconX className="size-3.5" />
1278
+ </button>
1279
+ </div>
1280
+ ))}
1281
+ </div>
1282
+ ) : (
1283
+ <div className="text-muted-foreground">
1284
+ {t("database.noSourceFieldsBoundYet")}
1285
+ </div>
1286
+ )}
1287
+ {bindableSourceFields.length > 0 ? (
1288
+ <DropdownMenuSub>
1289
+ <DropdownMenuSubTrigger className="mt-0.5 rounded px-1.5 py-1 text-xs">
1290
+ <IconPlus className="mr-1.5 size-3.5 text-muted-foreground" />
1291
+ {t("database.bindAFieldFromASource")}
1292
+ </DropdownMenuSubTrigger>
1293
+ <DropdownMenuSubContent className="max-h-80 w-64 overflow-auto">
1294
+ {bindableSourceFields.map(({ source: src, field }) => (
1295
+ <DropdownMenuItem
1296
+ key={field.id}
1297
+ disabled={bindSourceField.isPending}
1298
+ onSelect={(event) => {
1299
+ event.preventDefault();
1300
+ void bindSourceField.mutateAsync({
1301
+ documentId,
1302
+ sourceFieldId: field.id,
1303
+ propertyId: property.definition.id,
1304
+ });
1305
+ }}
1306
+ >
1307
+ <IconLink className="mr-2 size-3.5 shrink-0 text-muted-foreground" />
1308
+ <span className="min-w-0 flex-1 truncate">
1309
+ {field.sourceFieldLabel}
1310
+ </span>
1311
+ <span className="ml-2 shrink-0 truncate text-[11px] text-muted-foreground">
1312
+ {src.sourceName}
1313
+ </span>
1314
+ </DropdownMenuItem>
1315
+ ))}
1316
+ </DropdownMenuSubContent>
1317
+ </DropdownMenuSub>
1318
+ ) : null}
1319
+ </div>
1320
+ </>
1321
+ ) : sourceAttached ? (
1173
1322
  <>
1174
1323
  <DropdownMenuSeparator />
1175
1324
  <div className="grid gap-1 px-2 py-1.5 text-xs">