@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.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +14 -4
- package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/analytics/CHANGELOG.md +6 -0
- package/corpus/templates/analytics/README.md +2 -2
- package/corpus/templates/analytics/changelog/2026-10-02-events-with-a-very-long-name-app-or-page-path-no-longer-caus.md +6 -0
- package/corpus/templates/analytics/package.json +1 -0
- package/corpus/templates/analytics/server/handlers/first-party-analytics.ts +9 -19
- package/corpus/templates/analytics/server/handlers/session-replay.ts +34 -47
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +9 -6
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +57 -36
- package/corpus/templates/analytics/server/lib/indexed-text.ts +53 -0
- package/corpus/templates/analytics/server/lib/request-errors.ts +73 -0
- package/corpus/templates/analytics/server/lib/session-event-index.ts +6 -16
- package/corpus/templates/analytics/server/lib/session-replay.ts +12 -2
- package/corpus/templates/analytics/server/plugins/auth.ts +2 -1
- package/corpus/templates/analytics/server/plugins/otel.ts +6 -0
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/assets/CHANGELOG.md +7 -0
- package/corpus/templates/assets/README.md +2 -2
- package/corpus/templates/assets/package.json +1 -0
- package/corpus/templates/assets/server/plugins/auth.ts +2 -1
- package/corpus/templates/assets/server/plugins/otel.ts +6 -0
- package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +2 -1
- package/corpus/templates/brain/.agents/skills/brain/SKILL.md +5 -4
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/brain/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/brain/CHANGELOG.md +6 -0
- package/corpus/templates/brain/README.md +12 -8
- package/corpus/templates/brain/changelog/2026-10-05-private-slack-channels-are-searchable-org-wide.md +6 -0
- package/corpus/templates/brain/package.json +1 -0
- package/corpus/templates/brain/server/lib/audiences.ts +1 -98
- package/corpus/templates/brain/server/lib/connectors.ts +2 -166
- package/corpus/templates/brain/server/plugins/otel.ts +6 -0
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/calendar/CHANGELOG.md +7 -0
- package/corpus/templates/calendar/README.md +2 -2
- package/corpus/templates/calendar/package.json +1 -0
- package/corpus/templates/calendar/server/plugins/auth.ts +2 -1
- package/corpus/templates/calendar/server/plugins/otel.ts +6 -0
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/chat/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/chat/README.md +2 -2
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +9 -0
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/clips/CHANGELOG.md +24 -0
- package/corpus/templates/clips/README.md +2 -2
- package/corpus/templates/clips/actions/lib/audio-chunk-list.ts +23 -0
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +187 -292
- package/corpus/templates/clips/actions/lib/chunked-transcription.ts +151 -0
- package/corpus/templates/clips/actions/lib/recording-audio-source.ts +191 -0
- package/corpus/templates/clips/actions/request-transcript.ts +81 -135
- package/corpus/templates/clips/actions/search-recordings.ts +19 -5
- package/corpus/templates/clips/app/components/clips-command-menu.tsx +5 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -1
- package/corpus/templates/clips/app/components/library/search-bar.tsx +5 -0
- package/corpus/templates/clips/app/hooks/use-library.ts +1 -0
- package/corpus/templates/clips/app/lib/local-recording-upload.ts +13 -6
- package/corpus/templates/clips/app/lib/recording-section.ts +1 -1
- package/corpus/templates/clips/app/routes/_app.r.$recordingId.tsx +7 -5
- package/corpus/templates/clips/app/routes/record.tsx +16 -6
- package/corpus/templates/clips/changelog/2026-10-02-long-uploads-an-hour-or-more-now-transcribe-reliably-instead.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-confirming-discard-recording-now-returns-you-to-your-library.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-discarding-a-recording-now-removes-its-failed-upload-card-fr.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-discarding-a-recovered-recording-no-longer-warns-that-it-s-o.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-search-results-identify-recordings-in-trash-and-open-them-wi.md +6 -0
- package/corpus/templates/clips/package.json +1 -0
- package/corpus/templates/clips/server/lib/builder-cdn.ts +5 -0
- package/corpus/templates/clips/server/lib/builder-media-compression.ts +2 -2
- package/corpus/templates/clips/server/plugins/auth.ts +2 -1
- package/corpus/templates/clips/server/plugins/otel.ts +6 -0
- package/corpus/templates/clips/shared/transcript-failure.ts +5 -0
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +8 -2
- package/corpus/templates/content/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/content/CHANGELOG.md +41 -0
- package/corpus/templates/content/README.md +2 -2
- package/corpus/templates/content/actions/_database-navigation.ts +523 -344
- package/corpus/templates/content/actions/_database-row-mutation.ts +44 -10
- package/corpus/templates/content/actions/_database-setup-discovery.ts +9 -3
- package/corpus/templates/content/actions/_database-utils.ts +299 -271
- package/corpus/templates/content/actions/_property-utils.ts +293 -190
- package/corpus/templates/content/actions/_relation-values.ts +3 -1
- package/corpus/templates/content/actions/get-content-database.ts +1 -0
- package/corpus/templates/content/actions/query-content-database-items.ts +32 -5
- package/corpus/templates/content/actions/set-document-property.ts +17 -11
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +21 -6
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +127 -43
- package/corpus/templates/content/app/components/editor/DocumentEditorSkeleton.tsx +159 -50
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +12 -28
- package/corpus/templates/content/app/components/editor/PageDraftRecovery.tsx +6 -1
- package/corpus/templates/content/app/components/editor/TableHoverControls.tsx +139 -70
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +16 -1
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +180 -75
- package/corpus/templates/content/app/components/editor/database/DatabaseViewSkeleton.tsx +76 -0
- package/corpus/templates/content/app/components/editor/database/navigation-state.ts +60 -2
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +41 -42
- package/corpus/templates/content/app/components/editor/document-editor-layout.ts +18 -0
- package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +11 -3
- package/corpus/templates/content/app/components/editor/suggestions/draft-session.ts +15 -7
- package/corpus/templates/content/app/components/editor/suggestions/model.ts +13 -0
- package/corpus/templates/content/app/components/editor/suggestions/read-only-blocks.ts +136 -0
- package/corpus/templates/content/app/components/editor/table-view.ts +73 -0
- package/corpus/templates/content/app/components/layout/ContentStartupShell.tsx +1 -1
- package/corpus/templates/content/app/components/layout/Layout.tsx +5 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +57 -16
- package/corpus/templates/content/app/components/sidebar/MovePageDialog.tsx +4 -4
- package/corpus/templates/content/app/components/sidebar/SidebarNavigationRow.tsx +34 -10
- package/corpus/templates/content/app/global.css +16 -8
- package/corpus/templates/content/app/hooks/content-action-refresh.ts +14 -13
- package/corpus/templates/content/app/hooks/use-content-database.ts +72 -9
- package/corpus/templates/content/app/hooks/use-content-personal-navigation.ts +7 -3
- package/corpus/templates/content/app/hooks/use-documents.ts +27 -0
- package/corpus/templates/content/app/i18n-data.ts +3 -2
- package/corpus/templates/content/app/lib/content-landing.ts +3 -31
- package/corpus/templates/content/app/lib/files-navigation.ts +182 -10
- package/corpus/templates/content/app/lib/files-root-hint.ts +20 -32
- package/corpus/templates/content/app/lib/page-startup-hints.ts +108 -0
- package/corpus/templates/content/app/lib/private-link-redirect.ts +25 -0
- package/corpus/templates/content/app/lib/sidebar-layout-hint.ts +34 -1
- package/corpus/templates/content/app/lib/startup-timing.ts +2 -0
- package/corpus/templates/content/app/root.tsx +3 -1
- package/corpus/templates/content/app/routes/_app.home.tsx +10 -19
- package/corpus/templates/content/app/routes/p.$id.tsx +23 -5
- package/corpus/templates/content/changelog/2026-10-02-a-page-link-you-cant-open-now-says-so-instead-of-opening-an.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-after-a-refresh-the-files-sidebar-shows-the-open-page-s-fold.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-large-collections-open-faster.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-pages-stay-inside-the-window-at-every-width-long-inline-code.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-pages-with-open-comments-and-collections-with-sorted-or-filt.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-suggest-edits-works-on-pages-written-by-agents-including-pag.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-while-you-suggest-edits-tables-and-other-blocks-that-suggest.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-collection-view-context-now-survives-quick-page-changes-when.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-collection-views-keep-their-saved-rows-accurate-during-refre.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-exact-saved-view-links-keep-collection-retry-available.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-expanding-a-files-folder-now-shares-one-navigation-read-acro.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-files-navigation-retries-temporary-failures-consistently.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-shared-page-owners-keep-edit-and-manage-controls-in-files-an.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-tagging-an-ai-in-a-comment-works-again-instead-of-failing-ri.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-the-home-loading-shell-keeps-the-layout-of-your-last-opened-.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-typing-and-a-space-or-inserting-a-toggle-or-callout-no-longe.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md +4 -1
- package/corpus/templates/content/e2e/playwright.config.ts +1 -1
- package/corpus/templates/content/package.json +2 -1
- package/corpus/templates/content/scripts/seed-perf-database.mjs +600 -0
- package/corpus/templates/content/scripts/trace-startup.mjs +25 -3
- package/corpus/templates/content/server/db/index.ts +1 -1
- package/corpus/templates/content/server/lib/suggested-edits.ts +23 -26
- package/corpus/templates/content/server/plugins/auth.ts +2 -1
- package/corpus/templates/content/server/plugins/otel.ts +6 -0
- package/corpus/templates/content/shared/api.ts +17 -0
- package/corpus/templates/content/shared/suggestion-diff.ts +124 -38
- package/corpus/templates/content/shared/suggestion-formatting.ts +134 -3
- package/corpus/templates/crm/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/crm/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/crm/package.json +1 -0
- package/corpus/templates/crm/server/plugins/otel.ts +6 -0
- package/corpus/templates/design/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/design/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/design/CHANGELOG.md +41 -0
- package/corpus/templates/design/README.md +2 -2
- package/corpus/templates/design/actions/list-designs.ts +11 -4
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +110 -32
- package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +28 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +1 -0
- package/corpus/templates/design/app/components/home/DesignHomeLibrary.tsx +79 -0
- package/corpus/templates/design/app/components/layout/Header.tsx +2 -4
- package/corpus/templates/design/app/components/ui/tabs.tsx +59 -1
- package/corpus/templates/design/app/global.css +1 -34
- package/corpus/templates/design/app/i18n/en-US.ts +4 -0
- package/corpus/templates/design/app/lib/design-filter.ts +4 -2
- package/corpus/templates/design/app/pages/Index.tsx +91 -59
- package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +58 -17
- package/corpus/templates/design/changelog/2026-10-01-filter-designs-by-owner.md +6 -0
- package/corpus/templates/design/changelog/2026-10-03-layers-dropped-into-visible-canvas-space-beyond-a-screen-now.md +6 -0
- package/corpus/templates/design/changelog/2026-10-03-visible-screen-overflow-no-longer-routes-drops-to-the-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-designs.md +6 -0
- package/corpus/templates/design/package.json +1 -0
- package/corpus/templates/design/server/plugins/auth.ts +2 -1
- package/corpus/templates/design/server/plugins/otel.ts +6 -0
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/dispatch/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/dispatch/README.md +2 -2
- package/corpus/templates/dispatch/package.json +1 -0
- package/corpus/templates/dispatch/server/plugins/otel.ts +6 -0
- package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +2 -1
- package/corpus/templates/factory/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/factory/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/factory/package.json +1 -0
- package/corpus/templates/factory/server/plugins/otel.ts +6 -0
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/forms/README.md +2 -2
- package/corpus/templates/forms/package.json +1 -0
- package/corpus/templates/forms/server/plugins/auth.ts +2 -1
- package/corpus/templates/forms/server/plugins/otel.ts +6 -0
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/mail/CHANGELOG.md +6 -0
- package/corpus/templates/mail/README.md +2 -2
- package/corpus/templates/mail/package.json +1 -0
- package/corpus/templates/mail/server/plugins/auth.ts +2 -1
- package/corpus/templates/mail/server/plugins/otel.ts +6 -0
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/plan/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/plan/CHANGELOG.md +1 -0
- package/corpus/templates/plan/README.md +2 -2
- package/corpus/templates/plan/package.json +1 -0
- package/corpus/templates/plan/server/plugins/auth.ts +2 -1
- package/corpus/templates/plan/server/plugins/otel.ts +6 -0
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/slides/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/slides/CHANGELOG.md +23 -0
- package/corpus/templates/slides/README.md +2 -2
- package/corpus/templates/slides/actions/list-decks.ts +11 -4
- package/corpus/templates/slides/app/components/deck/DeckFilterMenu.tsx +44 -36
- package/corpus/templates/slides/app/components/home/SlidesHomeLibrary.tsx +79 -0
- package/corpus/templates/slides/app/components/layout/Header.tsx +2 -15
- package/corpus/templates/slides/app/components/ui/tabs.tsx +59 -0
- package/corpus/templates/slides/app/global.css +3 -54
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/lib/deck-filter.ts +5 -2
- package/corpus/templates/slides/app/pages/Index.tsx +102 -88
- package/corpus/templates/slides/changelog/2026-10-01-filter-decks-by-owner.md +6 -0
- package/corpus/templates/slides/changelog/2026-10-02-hide-recent-until-decks-available.md +6 -0
- package/corpus/templates/slides/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-decks-a.md +6 -0
- package/corpus/templates/slides/package.json +1 -0
- package/corpus/templates/slides/server/handlers/request-auth-context.ts +8 -0
- package/corpus/templates/slides/server/plugins/auth.ts +2 -1
- package/corpus/templates/slides/server/plugins/otel.ts +6 -0
- package/corpus/templates/tasks/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/tasks/.agents/skills/storing-data/SKILL.md +12 -7
- package/package.json +1 -1
|
@@ -77,27 +77,59 @@ type ContentDatabaseItemRow = InferSelectModel<
|
|
|
77
77
|
typeof schema.contentDatabaseItems
|
|
78
78
|
>;
|
|
79
79
|
type DbClient = ReturnType<typeof getDb>;
|
|
80
|
+
type PropertyDefinitionRow = InferSelectModel<
|
|
81
|
+
typeof schema.documentPropertyDefinitions
|
|
82
|
+
>;
|
|
80
83
|
|
|
81
|
-
|
|
84
|
+
/**
|
|
85
|
+
* A database's property definitions (in display order) and its source field
|
|
86
|
+
* bindings. Read once per request and pass it down; every list helper below
|
|
87
|
+
* would otherwise re-read both.
|
|
88
|
+
*/
|
|
89
|
+
export type DatabasePropertySchema = {
|
|
90
|
+
definitions: PropertyDefinitionRow[];
|
|
91
|
+
sourceFields: Array<{
|
|
92
|
+
propertyId: string | null;
|
|
93
|
+
writeOwner: string;
|
|
94
|
+
readOnly: number;
|
|
95
|
+
sourceMetadataJson: string;
|
|
96
|
+
}>;
|
|
97
|
+
sourceManagedPropertyIds: Set<string>;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export async function readDatabasePropertySchema(
|
|
82
101
|
db: DbClient,
|
|
83
102
|
databaseId: string,
|
|
84
|
-
) {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
schema.
|
|
96
|
-
schema.
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
103
|
+
): Promise<DatabasePropertySchema> {
|
|
104
|
+
const [definitions, sourceFields] = await Promise.all([
|
|
105
|
+
db
|
|
106
|
+
.select()
|
|
107
|
+
.from(schema.documentPropertyDefinitions)
|
|
108
|
+
.where(eq(schema.documentPropertyDefinitions.databaseId, databaseId))
|
|
109
|
+
.orderBy(asc(schema.documentPropertyDefinitions.position)),
|
|
110
|
+
db
|
|
111
|
+
.select({
|
|
112
|
+
propertyId: schema.contentDatabaseSourceFields.propertyId,
|
|
113
|
+
writeOwner: schema.contentDatabaseSourceFields.writeOwner,
|
|
114
|
+
readOnly: schema.contentDatabaseSourceFields.readOnly,
|
|
115
|
+
sourceMetadataJson: schema.contentDatabaseSources.metadataJson,
|
|
116
|
+
})
|
|
117
|
+
.from(schema.contentDatabaseSourceFields)
|
|
118
|
+
.innerJoin(
|
|
119
|
+
schema.contentDatabaseSources,
|
|
120
|
+
eq(
|
|
121
|
+
schema.contentDatabaseSources.id,
|
|
122
|
+
schema.contentDatabaseSourceFields.sourceId,
|
|
123
|
+
),
|
|
124
|
+
)
|
|
125
|
+
.where(eq(schema.contentDatabaseSources.databaseId, databaseId)),
|
|
126
|
+
]);
|
|
127
|
+
return {
|
|
128
|
+
definitions,
|
|
129
|
+
sourceFields,
|
|
130
|
+
sourceManagedPropertyIds:
|
|
131
|
+
contentDatabaseSourceManagedPropertyIds(sourceFields),
|
|
132
|
+
};
|
|
101
133
|
}
|
|
102
134
|
|
|
103
135
|
export function nanoid(size = 12): string {
|
|
@@ -650,40 +682,38 @@ export async function listPropertiesForAllDocumentDatabases(
|
|
|
650
682
|
export async function listPropertiesForDatabase(
|
|
651
683
|
databaseId: string,
|
|
652
684
|
valueDocument?: DocumentRow,
|
|
653
|
-
options: {
|
|
685
|
+
options: {
|
|
686
|
+
includeContainerDerivedValues?: boolean;
|
|
687
|
+
propertySchema?: DatabasePropertySchema;
|
|
688
|
+
} = {},
|
|
654
689
|
) {
|
|
655
690
|
const db = getDb();
|
|
656
|
-
const definitions
|
|
657
|
-
.
|
|
658
|
-
|
|
659
|
-
.where(eq(schema.documentPropertyDefinitions.databaseId, databaseId))
|
|
660
|
-
.orderBy(asc(schema.documentPropertyDefinitions.position));
|
|
691
|
+
const { definitions, sourceManagedPropertyIds } =
|
|
692
|
+
options.propertySchema ??
|
|
693
|
+
(await readDatabasePropertySchema(db, databaseId));
|
|
661
694
|
|
|
662
695
|
if (definitions.length === 0) return [];
|
|
663
696
|
const includeContainerDerivedValues =
|
|
664
697
|
options.includeContainerDerivedValues !== false;
|
|
665
|
-
const [
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
? blockFieldContentsForDocument(valueDocument.id)
|
|
685
|
-
: new Map<string, string>(),
|
|
686
|
-
]);
|
|
698
|
+
const [values, databaseRowNumber, blockContentByPropertyId] =
|
|
699
|
+
await Promise.all([
|
|
700
|
+
valueDocument
|
|
701
|
+
? db
|
|
702
|
+
.select()
|
|
703
|
+
.from(schema.documentPropertyValues)
|
|
704
|
+
.where(
|
|
705
|
+
eq(schema.documentPropertyValues.documentId, valueDocument.id),
|
|
706
|
+
)
|
|
707
|
+
: [],
|
|
708
|
+
valueDocument &&
|
|
709
|
+
includeContainerDerivedValues &&
|
|
710
|
+
definitions.some((definition) => definition.type === "id")
|
|
711
|
+
? databaseRowNumberForDocument(databaseId, valueDocument.id)
|
|
712
|
+
: undefined,
|
|
713
|
+
valueDocument
|
|
714
|
+
? blockFieldContentsForDocument(valueDocument.id)
|
|
715
|
+
: new Map<string, string>(),
|
|
716
|
+
]);
|
|
687
717
|
|
|
688
718
|
const valueByPropertyId = new Map(
|
|
689
719
|
values.map((value) => [value.propertyId, value]),
|
|
@@ -794,25 +824,15 @@ export async function listPropertiesForDatabase(
|
|
|
794
824
|
: property,
|
|
795
825
|
);
|
|
796
826
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
)
|
|
803
|
-
nextProperties.push({
|
|
804
|
-
...property,
|
|
805
|
-
value: await evaluatePropertyRollup(property, evaluatedProperties),
|
|
806
|
-
});
|
|
807
|
-
} else if (property.definition.type === "rollup") {
|
|
808
|
-
nextProperties.push({ ...property, value: null });
|
|
809
|
-
} else {
|
|
810
|
-
nextProperties.push(property);
|
|
811
|
-
}
|
|
827
|
+
if (!includeContainerDerivedValues) {
|
|
828
|
+
return evaluatedProperties.map((property) =>
|
|
829
|
+
property.definition.type === "rollup"
|
|
830
|
+
? { ...property, value: null }
|
|
831
|
+
: property,
|
|
832
|
+
);
|
|
812
833
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
const [withTargets] = await withRelationTargets(db, [nextProperties]);
|
|
834
|
+
const [withRollups] = await withRollupValues([evaluatedProperties]);
|
|
835
|
+
const [withTargets] = await withRelationTargets(db, [withRollups]);
|
|
816
836
|
return withTargets;
|
|
817
837
|
}
|
|
818
838
|
|
|
@@ -844,62 +864,30 @@ function propertyValueKey(documentId: string, propertyId: string) {
|
|
|
844
864
|
export async function listPropertiesForDatabaseDocuments(
|
|
845
865
|
databaseId: string,
|
|
846
866
|
valueDocuments: DocumentRow[],
|
|
867
|
+
options: {
|
|
868
|
+
/**
|
|
869
|
+
* Blocks field identities need each document's full body: the primary
|
|
870
|
+
* field is the body itself. List reads project documents without
|
|
871
|
+
* `content`, so asking for identities there would report every field as
|
|
872
|
+
* stale against an empty body (and reconcile one diff per row).
|
|
873
|
+
*/
|
|
874
|
+
includeBlocksFieldIdentity: boolean;
|
|
875
|
+
propertySchema?: DatabasePropertySchema;
|
|
876
|
+
},
|
|
847
877
|
): Promise<Map<string, DocumentProperty[]>> {
|
|
848
878
|
const db = getDb();
|
|
849
|
-
const definitions = await db
|
|
850
|
-
.select()
|
|
851
|
-
.from(schema.documentPropertyDefinitions)
|
|
852
|
-
.where(eq(schema.documentPropertyDefinitions.databaseId, databaseId))
|
|
853
|
-
.orderBy(asc(schema.documentPropertyDefinitions.position));
|
|
854
879
|
const result = new Map<string, DocumentProperty[]>();
|
|
855
880
|
if (valueDocuments.length === 0) return result;
|
|
881
|
+
const { definitions, sourceManagedPropertyIds } =
|
|
882
|
+
options.propertySchema ??
|
|
883
|
+
(await readDatabasePropertySchema(db, databaseId));
|
|
856
884
|
if (definitions.length === 0) {
|
|
857
885
|
for (const document of valueDocuments) result.set(document.id, []);
|
|
858
886
|
return result;
|
|
859
887
|
}
|
|
860
|
-
const sourceManagedPropertyIds = await sourceManagedPropertyIdsForDatabase(
|
|
861
|
-
db,
|
|
862
|
-
databaseId,
|
|
863
|
-
);
|
|
864
888
|
|
|
865
889
|
const documentIds = valueDocuments.map((document) => document.id);
|
|
866
890
|
const propertyIds = definitions.map((definition) => definition.id);
|
|
867
|
-
const values: Array<typeof schema.documentPropertyValues.$inferSelect> = [];
|
|
868
|
-
for (const documentIdChunk of chunks(documentIds, 200)) {
|
|
869
|
-
for (const propertyIdChunk of chunks(propertyIds, 200)) {
|
|
870
|
-
values.push(
|
|
871
|
-
...(await db
|
|
872
|
-
.select()
|
|
873
|
-
.from(schema.documentPropertyValues)
|
|
874
|
-
.where(
|
|
875
|
-
and(
|
|
876
|
-
inArray(
|
|
877
|
-
schema.documentPropertyValues.documentId,
|
|
878
|
-
documentIdChunk,
|
|
879
|
-
),
|
|
880
|
-
inArray(
|
|
881
|
-
schema.documentPropertyValues.propertyId,
|
|
882
|
-
propertyIdChunk,
|
|
883
|
-
),
|
|
884
|
-
),
|
|
885
|
-
)),
|
|
886
|
-
);
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
const valueByDocumentAndProperty = new Map(
|
|
890
|
-
values.map((value) => [
|
|
891
|
-
propertyValueKey(value.documentId, value.propertyId),
|
|
892
|
-
value,
|
|
893
|
-
]),
|
|
894
|
-
);
|
|
895
|
-
|
|
896
|
-
const rowNumberByDocumentId = definitions.some(
|
|
897
|
-
(definition) => definition.type === "id",
|
|
898
|
-
)
|
|
899
|
-
? await databaseRowNumbersByDocumentId(databaseId)
|
|
900
|
-
: new Map<string, number>();
|
|
901
|
-
|
|
902
|
-
const blockContentByDocumentAndProperty = new Map<string, string>();
|
|
903
891
|
const hasAdditionalBlocksFields = definitions.some((definition) => {
|
|
904
892
|
const type = definition.type as DocumentPropertyType;
|
|
905
893
|
return (
|
|
@@ -907,55 +895,91 @@ export async function listPropertiesForDatabaseDocuments(
|
|
|
907
895
|
!isPrimaryBlocksField(parsePropertyOptions(definition.optionsJson))
|
|
908
896
|
);
|
|
909
897
|
});
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
.
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
898
|
+
const [values, rowNumberByDocumentId, blockContentRows] = await Promise.all([
|
|
899
|
+
Promise.all(
|
|
900
|
+
chunks(documentIds, 200).flatMap((documentIdChunk) =>
|
|
901
|
+
chunks(propertyIds, 200).map((propertyIdChunk) =>
|
|
902
|
+
db
|
|
903
|
+
.select()
|
|
904
|
+
.from(schema.documentPropertyValues)
|
|
905
|
+
.where(
|
|
906
|
+
and(
|
|
907
|
+
inArray(
|
|
908
|
+
schema.documentPropertyValues.documentId,
|
|
909
|
+
documentIdChunk,
|
|
910
|
+
),
|
|
911
|
+
inArray(
|
|
912
|
+
schema.documentPropertyValues.propertyId,
|
|
913
|
+
propertyIdChunk,
|
|
914
|
+
),
|
|
915
|
+
),
|
|
916
|
+
),
|
|
917
|
+
),
|
|
918
|
+
),
|
|
919
|
+
).then((groups) => groups.flat()),
|
|
920
|
+
definitions.some((definition) => definition.type === "id")
|
|
921
|
+
? databaseRowNumbersByDocumentId(databaseId)
|
|
922
|
+
: new Map<string, number>(),
|
|
923
|
+
hasAdditionalBlocksFields
|
|
924
|
+
? Promise.all(
|
|
925
|
+
chunks(documentIds, 200).map((documentIdChunk) =>
|
|
926
|
+
db
|
|
927
|
+
.select({
|
|
928
|
+
documentId: schema.documentBlockFieldContents.documentId,
|
|
929
|
+
propertyId: schema.documentBlockFieldContents.propertyId,
|
|
930
|
+
content: schema.documentBlockFieldContents.content,
|
|
931
|
+
})
|
|
932
|
+
.from(schema.documentBlockFieldContents)
|
|
933
|
+
.where(
|
|
934
|
+
inArray(
|
|
935
|
+
schema.documentBlockFieldContents.documentId,
|
|
936
|
+
documentIdChunk,
|
|
937
|
+
),
|
|
938
|
+
),
|
|
923
939
|
),
|
|
924
|
-
)
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
940
|
+
).then((groups) => groups.flat())
|
|
941
|
+
: [],
|
|
942
|
+
]);
|
|
943
|
+
const valueByDocumentAndProperty = new Map(
|
|
944
|
+
values.map((value) => [
|
|
945
|
+
propertyValueKey(value.documentId, value.propertyId),
|
|
946
|
+
value,
|
|
947
|
+
]),
|
|
948
|
+
);
|
|
949
|
+
const blockContentByDocumentAndProperty = new Map(
|
|
950
|
+
blockContentRows.map((row) => [
|
|
951
|
+
propertyValueKey(row.documentId, row.propertyId),
|
|
952
|
+
row.content ?? "",
|
|
953
|
+
]),
|
|
954
|
+
);
|
|
933
955
|
|
|
934
|
-
const blocksFieldIdentityById =
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
956
|
+
const blocksFieldIdentityById = options.includeBlocksFieldIdentity
|
|
957
|
+
? await readBlocksFieldIdentities({
|
|
958
|
+
db,
|
|
959
|
+
fields: valueDocuments.flatMap((document) =>
|
|
960
|
+
definitions.flatMap((definition) => {
|
|
961
|
+
const type = definition.type as DocumentPropertyType;
|
|
962
|
+
if (!isBlocksPropertyType(type)) return [];
|
|
963
|
+
const options = parsePropertyOptions(definition.optionsJson);
|
|
964
|
+
return [
|
|
965
|
+
{
|
|
966
|
+
documentId: document.id,
|
|
967
|
+
propertyId: definition.id,
|
|
968
|
+
markdown: resolveBlocksFieldValue({
|
|
969
|
+
options,
|
|
970
|
+
documentBody: document.content,
|
|
971
|
+
blockFieldContent: blockContentByDocumentAndProperty.get(
|
|
972
|
+
propertyValueKey(document.id, definition.id),
|
|
973
|
+
),
|
|
974
|
+
}),
|
|
975
|
+
},
|
|
976
|
+
];
|
|
977
|
+
}),
|
|
978
|
+
),
|
|
979
|
+
})
|
|
980
|
+
: null;
|
|
957
981
|
|
|
958
|
-
|
|
982
|
+
const propertyLists = valueDocuments.map((document) => {
|
|
959
983
|
const properties = definitions.map((definition) => {
|
|
960
984
|
const propertyDefinition = serializePropertyDefinition(definition);
|
|
961
985
|
const storedValue = valueByDocumentAndProperty.get(
|
|
@@ -983,7 +1007,8 @@ export async function listPropertiesForDatabaseDocuments(
|
|
|
983
1007
|
!definition.systemRole &&
|
|
984
1008
|
!isComputedPropertyType(propertyDefinition.type) &&
|
|
985
1009
|
!sourceManagedPropertyIds.has(definition.id),
|
|
986
|
-
...(
|
|
1010
|
+
...(blocksFieldIdentityById &&
|
|
1011
|
+
isBlocksPropertyType(propertyDefinition.type)
|
|
987
1012
|
? {
|
|
988
1013
|
blocksField: blocksFieldIdentityById.get(
|
|
989
1014
|
blocksFieldId(document.id, definition.id),
|
|
@@ -998,7 +1023,7 @@ export async function listPropertiesForDatabaseDocuments(
|
|
|
998
1023
|
.filter((property) => property.definition.type !== "formula")
|
|
999
1024
|
.map((property) => [property.definition.name, property.value]),
|
|
1000
1025
|
);
|
|
1001
|
-
|
|
1026
|
+
return properties.map((property) =>
|
|
1002
1027
|
property.definition.type === "formula"
|
|
1003
1028
|
? {
|
|
1004
1029
|
...property,
|
|
@@ -1009,58 +1034,136 @@ export async function listPropertiesForDatabaseDocuments(
|
|
|
1009
1034
|
}
|
|
1010
1035
|
: property,
|
|
1011
1036
|
);
|
|
1012
|
-
|
|
1013
|
-
for (const property of evaluatedProperties) {
|
|
1014
|
-
if (property.definition.type === "rollup") {
|
|
1015
|
-
nextProperties.push({
|
|
1016
|
-
...property,
|
|
1017
|
-
value: await evaluatePropertyRollup(property, evaluatedProperties),
|
|
1018
|
-
});
|
|
1019
|
-
} else {
|
|
1020
|
-
nextProperties.push(property);
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
result.set(document.id, nextProperties);
|
|
1024
|
-
}
|
|
1037
|
+
});
|
|
1025
1038
|
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1039
|
+
const withTargets = await withRelationTargets(
|
|
1040
|
+
db,
|
|
1041
|
+
await withRollupValues(propertyLists),
|
|
1042
|
+
);
|
|
1043
|
+
valueDocuments.forEach((document, index) => {
|
|
1044
|
+
result.set(document.id, withTargets[index]!);
|
|
1030
1045
|
});
|
|
1031
1046
|
return result;
|
|
1032
1047
|
}
|
|
1033
1048
|
|
|
1034
|
-
|
|
1049
|
+
type RollupPlan = {
|
|
1050
|
+
aggregation: string;
|
|
1051
|
+
linkedDocumentIds: string[];
|
|
1052
|
+
targetProperty: DocumentProperty | null;
|
|
1053
|
+
};
|
|
1054
|
+
|
|
1055
|
+
function rollupPlan(
|
|
1035
1056
|
property: DocumentProperty,
|
|
1036
1057
|
properties: DocumentProperty[],
|
|
1037
|
-
):
|
|
1058
|
+
): RollupPlan {
|
|
1038
1059
|
const config = property.definition.options.rollup;
|
|
1039
1060
|
const relationPropertyId = config?.relationPropertyId ?? null;
|
|
1040
1061
|
const targetPropertyId = config?.targetPropertyId ?? null;
|
|
1041
|
-
const aggregation = config?.aggregation ?? "count";
|
|
1042
1062
|
const relationProperty = relationPropertyId
|
|
1043
1063
|
? properties.find(
|
|
1044
1064
|
(candidate) => candidate.definition.id === relationPropertyId,
|
|
1045
1065
|
)
|
|
1046
1066
|
: null;
|
|
1047
|
-
|
|
1067
|
+
return {
|
|
1068
|
+
aggregation: config?.aggregation ?? "count",
|
|
1069
|
+
linkedDocumentIds: relationValueIds(relationProperty?.value),
|
|
1070
|
+
targetProperty: targetPropertyId
|
|
1071
|
+
? (properties.find(
|
|
1072
|
+
(candidate) => candidate.definition.id === targetPropertyId,
|
|
1073
|
+
) ?? null)
|
|
1074
|
+
: null,
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1048
1077
|
|
|
1049
|
-
|
|
1050
|
-
|
|
1078
|
+
function rollupReadsLinkedValues(plan: RollupPlan) {
|
|
1079
|
+
return (
|
|
1080
|
+
plan.aggregation !== "count" &&
|
|
1081
|
+
plan.linkedDocumentIds.length > 0 &&
|
|
1082
|
+
plan.targetProperty !== null
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1051
1085
|
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1086
|
+
/**
|
|
1087
|
+
* Evaluate every rollup in `propertyLists` (one list per row) with one
|
|
1088
|
+
* linked-value read per rollup property across all rows, not one per row.
|
|
1089
|
+
*/
|
|
1090
|
+
async function withRollupValues(
|
|
1091
|
+
propertyLists: DocumentProperty[][],
|
|
1092
|
+
): Promise<DocumentProperty[][]> {
|
|
1093
|
+
if (
|
|
1094
|
+
!propertyLists.some((properties) =>
|
|
1095
|
+
properties.some((property) => property.definition.type === "rollup"),
|
|
1096
|
+
)
|
|
1097
|
+
) {
|
|
1098
|
+
return propertyLists;
|
|
1099
|
+
}
|
|
1100
|
+
const requests = new Map<
|
|
1101
|
+
string,
|
|
1102
|
+
{ targetProperty: DocumentProperty; documentIds: Set<string> }
|
|
1103
|
+
>();
|
|
1104
|
+
for (const properties of propertyLists) {
|
|
1105
|
+
for (const property of properties) {
|
|
1106
|
+
if (property.definition.type !== "rollup") continue;
|
|
1107
|
+
const plan = rollupPlan(property, properties);
|
|
1108
|
+
if (!rollupReadsLinkedValues(plan)) continue;
|
|
1109
|
+
let request = requests.get(property.definition.id);
|
|
1110
|
+
if (!request) {
|
|
1111
|
+
request = {
|
|
1112
|
+
targetProperty: plan.targetProperty!,
|
|
1113
|
+
documentIds: new Set(),
|
|
1114
|
+
};
|
|
1115
|
+
requests.set(property.definition.id, request);
|
|
1116
|
+
}
|
|
1117
|
+
for (const id of plan.linkedDocumentIds) request.documentIds.add(id);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
const linkedValuesByRollupId = new Map(
|
|
1121
|
+
await Promise.all(
|
|
1122
|
+
[...requests].map(async ([rollupId, request]) => {
|
|
1123
|
+
const valueByDocumentId = new Map<string, DocumentPropertyValue>();
|
|
1124
|
+
for (const ids of chunks([...request.documentIds], 500)) {
|
|
1125
|
+
const values = await propertyValuesForLinkedDocuments(
|
|
1126
|
+
ids,
|
|
1127
|
+
request.targetProperty,
|
|
1128
|
+
);
|
|
1129
|
+
ids.forEach((id, index) => {
|
|
1130
|
+
valueByDocumentId.set(id, values[index] ?? null);
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
return [rollupId, valueByDocumentId] as const;
|
|
1134
|
+
}),
|
|
1135
|
+
),
|
|
1136
|
+
);
|
|
1137
|
+
return propertyLists.map((properties) =>
|
|
1138
|
+
properties.map((property) => {
|
|
1139
|
+
if (property.definition.type !== "rollup") return property;
|
|
1140
|
+
const plan = rollupPlan(property, properties);
|
|
1141
|
+
const valueByDocumentId = linkedValuesByRollupId.get(
|
|
1142
|
+
property.definition.id,
|
|
1143
|
+
);
|
|
1144
|
+
return {
|
|
1145
|
+
...property,
|
|
1146
|
+
value: aggregateRollup(
|
|
1147
|
+
plan,
|
|
1148
|
+
plan.linkedDocumentIds.map(
|
|
1149
|
+
(id) => valueByDocumentId?.get(id) ?? null,
|
|
1150
|
+
),
|
|
1151
|
+
),
|
|
1152
|
+
};
|
|
1153
|
+
}),
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1058
1156
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1157
|
+
function aggregateRollup(
|
|
1158
|
+
plan: RollupPlan,
|
|
1159
|
+
linkedValues: DocumentPropertyValue[],
|
|
1160
|
+
): DocumentPropertyValue {
|
|
1161
|
+
const { aggregation } = plan;
|
|
1162
|
+
if (aggregation === "count") return plan.linkedDocumentIds.length;
|
|
1163
|
+
if (!rollupReadsLinkedValues(plan)) return null;
|
|
1164
|
+
const filledValues = linkedValues.filter(
|
|
1165
|
+
(value) => !isEmptyPropertyValue(value),
|
|
1062
1166
|
);
|
|
1063
|
-
const filledValues = values.filter((value) => !isEmptyPropertyValue(value));
|
|
1064
1167
|
|
|
1065
1168
|
if (aggregation === "count_values") return filledValues.length;
|
|
1066
1169
|
if (aggregation === "count_unique") {
|
|
@@ -52,7 +52,9 @@ async function liveDatabase(
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
async function canReadDatabase(database: ContentDatabaseRow) {
|
|
55
|
-
return !!(await resolveAccess("document", database.documentId
|
|
55
|
+
return !!(await resolveAccess("document", database.documentId, undefined, {
|
|
56
|
+
skipResourceBody: true,
|
|
57
|
+
}));
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
/**
|
|
@@ -6,7 +6,11 @@ import type {
|
|
|
6
6
|
ContentDatabaseNavigationPageResponse,
|
|
7
7
|
ContentDatabaseUnavailableResponse,
|
|
8
8
|
} from "../shared/api.js";
|
|
9
|
-
import {
|
|
9
|
+
import { readPersonalDatabaseViewOverrides } from "./_content-database-personal-view.js";
|
|
10
|
+
import {
|
|
11
|
+
getContentDatabaseNavigationPage,
|
|
12
|
+
MAX_NAVIGATION_EXPAND_IDS,
|
|
13
|
+
} from "./_database-navigation.js";
|
|
10
14
|
import {
|
|
11
15
|
CONTENT_DATABASE_MAX_READ_LIMIT,
|
|
12
16
|
contentDatabaseTableQuerySchema,
|
|
@@ -49,6 +53,13 @@ export default defineAction({
|
|
|
49
53
|
.min(1)
|
|
50
54
|
.optional()
|
|
51
55
|
.describe("Opaque cursor returned by the previous matching page"),
|
|
56
|
+
expand: z
|
|
57
|
+
.array(z.string().min(1))
|
|
58
|
+
.max(MAX_NAVIGATION_EXPAND_IDS)
|
|
59
|
+
.optional()
|
|
60
|
+
.describe(
|
|
61
|
+
"Expanded document IDs, most important first; each one this read returns comes back with its first child page in branches, and branchesTruncated is true when the cap left any out",
|
|
62
|
+
),
|
|
52
63
|
})
|
|
53
64
|
.optional()
|
|
54
65
|
.describe(
|
|
@@ -84,22 +95,38 @@ export default defineAction({
|
|
|
84
95
|
statusCode: 400,
|
|
85
96
|
});
|
|
86
97
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
// A person's saved order is theirs alone, so it is read while the
|
|
99
|
+
// database's access check runs; it is used only if that check passes.
|
|
100
|
+
// The check answers first: an unavailable database returns its typed
|
|
101
|
+
// response even when the saved order cannot be read.
|
|
102
|
+
const [resolved, [earlyOverrides]] = await Promise.all([
|
|
103
|
+
resolveContentDatabaseRead({ databaseId, documentId }),
|
|
104
|
+
Promise.allSettled(
|
|
105
|
+
navigation && userEmail && databaseId
|
|
106
|
+
? [readPersonalDatabaseViewOverrides(userEmail, databaseId)]
|
|
107
|
+
: [],
|
|
108
|
+
),
|
|
109
|
+
]);
|
|
91
110
|
if (!resolved.available) return resolved;
|
|
92
111
|
|
|
93
112
|
if (navigation) {
|
|
94
113
|
if (!userEmail) throw new Error("Not authenticated.");
|
|
114
|
+
if (earlyOverrides?.status === "rejected") throw earlyOverrides.reason;
|
|
95
115
|
return getContentDatabaseNavigationPage({
|
|
96
116
|
database: resolved.database,
|
|
97
117
|
userEmail,
|
|
118
|
+
overrides: earlyOverrides
|
|
119
|
+
? earlyOverrides.value
|
|
120
|
+
: await readPersonalDatabaseViewOverrides(
|
|
121
|
+
userEmail,
|
|
122
|
+
resolved.database.id,
|
|
123
|
+
),
|
|
98
124
|
parentId: navigation.parentId,
|
|
99
125
|
sort: navigation.sort,
|
|
100
126
|
viewId: navigation.viewId,
|
|
101
127
|
limit: limit ?? 20,
|
|
102
128
|
cursor: navigation.cursor,
|
|
129
|
+
expand: navigation.expand,
|
|
103
130
|
});
|
|
104
131
|
}
|
|
105
132
|
|