@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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { fail } from "@agent-native/core/action";
|
|
1
2
|
import { alias } from "@agent-native/core/db/schema";
|
|
2
3
|
import {
|
|
3
4
|
getRequestOrgId,
|
|
@@ -7,6 +8,7 @@ import {
|
|
|
7
8
|
accessFilter,
|
|
8
9
|
ROLE_RANK,
|
|
9
10
|
resolveAccess,
|
|
11
|
+
type ResolvedAccess,
|
|
10
12
|
type ShareRole,
|
|
11
13
|
} from "@agent-native/core/sharing";
|
|
12
14
|
import {
|
|
@@ -77,7 +79,9 @@ import {
|
|
|
77
79
|
import {
|
|
78
80
|
listPropertiesForDatabaseDocuments,
|
|
79
81
|
listPropertiesForDatabase,
|
|
82
|
+
readDatabasePropertySchema,
|
|
80
83
|
serializeDatabase,
|
|
84
|
+
type DatabasePropertySchema,
|
|
81
85
|
} from "./_property-utils.js";
|
|
82
86
|
export { getDocumentContextPath };
|
|
83
87
|
|
|
@@ -174,30 +178,16 @@ export const contentDatabaseTableQuerySchema = z
|
|
|
174
178
|
})
|
|
175
179
|
.optional();
|
|
176
180
|
|
|
177
|
-
|
|
178
|
-
databaseId: string,
|
|
181
|
+
function contentDatabaseTableQueryMode(
|
|
179
182
|
query: ContentDatabaseTableQuery | undefined,
|
|
183
|
+
sourceFields: DatabasePropertySchema["sourceFields"],
|
|
180
184
|
) {
|
|
181
185
|
if (!query) return undefined;
|
|
182
|
-
const sourceFields = await getDb()
|
|
183
|
-
.select({
|
|
184
|
-
metadataJson: schema.contentDatabaseSources.metadataJson,
|
|
185
|
-
propertyId: schema.contentDatabaseSourceFields.propertyId,
|
|
186
|
-
})
|
|
187
|
-
.from(schema.contentDatabaseSourceFields)
|
|
188
|
-
.innerJoin(
|
|
189
|
-
schema.contentDatabaseSources,
|
|
190
|
-
eq(
|
|
191
|
-
schema.contentDatabaseSources.id,
|
|
192
|
-
schema.contentDatabaseSourceFields.sourceId,
|
|
193
|
-
),
|
|
194
|
-
)
|
|
195
|
-
.where(eq(schema.contentDatabaseSources.databaseId, databaseId));
|
|
196
186
|
const secondaryPropertyIds = new Set<string>();
|
|
197
187
|
for (const field of sourceFields) {
|
|
198
188
|
let role: unknown = null;
|
|
199
189
|
try {
|
|
200
|
-
role = JSON.parse(field.
|
|
190
|
+
role = JSON.parse(field.sourceMetadataJson || "{}").federation?.role;
|
|
201
191
|
} catch {
|
|
202
192
|
role = null;
|
|
203
193
|
}
|
|
@@ -497,6 +487,8 @@ export type ContentDatabaseReadResolution =
|
|
|
497
487
|
| {
|
|
498
488
|
available: true;
|
|
499
489
|
database: typeof schema.contentDatabases.$inferSelect;
|
|
490
|
+
/** Null when read access comes from the Files space, not the page. */
|
|
491
|
+
accessRole: ResolvedAccess["role"] | null;
|
|
500
492
|
}
|
|
501
493
|
| {
|
|
502
494
|
available: false;
|
|
@@ -512,22 +504,21 @@ export async function resolveContentDatabaseRead(args: {
|
|
|
512
504
|
documentId?: string;
|
|
513
505
|
}): Promise<ContentDatabaseReadResolution> {
|
|
514
506
|
const db = getDb();
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
507
|
+
const [database] =
|
|
508
|
+
args.databaseId || args.documentId
|
|
509
|
+
? await db
|
|
510
|
+
.select()
|
|
511
|
+
.from(schema.contentDatabases)
|
|
512
|
+
.where(
|
|
513
|
+
args.databaseId
|
|
514
|
+
? eq(schema.contentDatabases.id, args.databaseId)
|
|
515
|
+
: eq(schema.contentDatabases.documentId, args.documentId!),
|
|
516
|
+
)
|
|
517
|
+
: [];
|
|
518
|
+
const databaseId = args.databaseId || database?.id;
|
|
523
519
|
if (!databaseId) {
|
|
524
520
|
throw new Error("Either databaseId or documentId is required.");
|
|
525
521
|
}
|
|
526
|
-
|
|
527
|
-
const [database] = await db
|
|
528
|
-
.select()
|
|
529
|
-
.from(schema.contentDatabases)
|
|
530
|
-
.where(eq(schema.contentDatabases.id, databaseId));
|
|
531
522
|
if (!database) {
|
|
532
523
|
return {
|
|
533
524
|
available: false,
|
|
@@ -538,7 +529,13 @@ export async function resolveContentDatabaseRead(args: {
|
|
|
538
529
|
};
|
|
539
530
|
}
|
|
540
531
|
|
|
541
|
-
|
|
532
|
+
const access = await resolveAccess(
|
|
533
|
+
"document",
|
|
534
|
+
database.documentId,
|
|
535
|
+
undefined,
|
|
536
|
+
{ skipResourceBody: true },
|
|
537
|
+
);
|
|
538
|
+
let canRead = Boolean(access);
|
|
542
539
|
if (!canRead && database.systemRole === "files" && database.spaceId) {
|
|
543
540
|
try {
|
|
544
541
|
await resolveContentSpaceAccess(database.spaceId);
|
|
@@ -560,7 +557,7 @@ export async function resolveContentDatabaseRead(args: {
|
|
|
560
557
|
};
|
|
561
558
|
}
|
|
562
559
|
|
|
563
|
-
return { available: true, database };
|
|
560
|
+
return { available: true, database, accessRole: access?.role ?? null };
|
|
564
561
|
}
|
|
565
562
|
|
|
566
563
|
type ContentDatabasePageBuild = ContentDatabasePageResponse & {
|
|
@@ -608,6 +605,7 @@ export async function getContentDatabasePageResponse(
|
|
|
608
605
|
filesMembershipDatabaseId?: string;
|
|
609
606
|
sidebarOrder?: ContentSidebarViewOrder;
|
|
610
607
|
database?: typeof schema.contentDatabases.$inferSelect;
|
|
608
|
+
propertySchema?: DatabasePropertySchema;
|
|
611
609
|
} = {},
|
|
612
610
|
): Promise<ContentDatabasePageBuild> {
|
|
613
611
|
const db = getDb();
|
|
@@ -626,11 +624,6 @@ export async function getContentDatabasePageResponse(
|
|
|
626
624
|
|
|
627
625
|
const { limit, offset } = normalizeContentDatabasePageOptions(options);
|
|
628
626
|
const tableQuery = options.tableQuery;
|
|
629
|
-
const tableQueryMode = await contentDatabaseTableQueryMode(
|
|
630
|
-
databaseId,
|
|
631
|
-
tableQuery,
|
|
632
|
-
);
|
|
633
|
-
const serverTableQuery = tableQueryMode === "server" ? tableQuery : undefined;
|
|
634
627
|
const userEmail = getRequestUserEmail();
|
|
635
628
|
const normalizedUserEmail = userEmail
|
|
636
629
|
? normalizeContentSpaceEmail(userEmail)
|
|
@@ -759,18 +752,30 @@ export async function getContentDatabasePageResponse(
|
|
|
759
752
|
: sql`1 = 0`
|
|
760
753
|
: undefined,
|
|
761
754
|
);
|
|
762
|
-
const [itemCount] = await
|
|
763
|
-
.
|
|
764
|
-
|
|
765
|
-
|
|
755
|
+
const [propertySchema, [itemCount]] = await Promise.all([
|
|
756
|
+
options.propertySchema ?? readDatabasePropertySchema(db, databaseId),
|
|
757
|
+
db
|
|
758
|
+
.select({ count: sql<number>`COUNT(*)` })
|
|
759
|
+
.from(schema.contentDatabaseItems)
|
|
760
|
+
.where(visibleItemFilter),
|
|
761
|
+
]);
|
|
766
762
|
const totalVisibleItems = Number(itemCount?.count ?? 0);
|
|
767
763
|
if (tableQuery && totalVisibleItems > CONTENT_DATABASE_MAX_READ_LIMIT) {
|
|
768
764
|
throw new Error(
|
|
769
765
|
`Table constraints support up to ${CONTENT_DATABASE_MAX_READ_LIMIT} rows; this database has ${totalVisibleItems}.`,
|
|
770
766
|
);
|
|
771
767
|
}
|
|
768
|
+
const tableQueryMode = contentDatabaseTableQueryMode(
|
|
769
|
+
tableQuery,
|
|
770
|
+
propertySchema.sourceFields,
|
|
771
|
+
);
|
|
772
|
+
const serverTableQuery = tableQueryMode === "server" ? tableQuery : undefined;
|
|
772
773
|
|
|
773
|
-
const databaseProperties = await listPropertiesForDatabase(
|
|
774
|
+
const databaseProperties = await listPropertiesForDatabase(
|
|
775
|
+
databaseId,
|
|
776
|
+
undefined,
|
|
777
|
+
{ propertySchema },
|
|
778
|
+
);
|
|
774
779
|
const boundedProjectionPropertyIds =
|
|
775
780
|
serverTableQuery && !database.systemRole
|
|
776
781
|
? boundedTableQueryProjectionPropertyIds(
|
|
@@ -779,7 +784,9 @@ export async function getContentDatabasePageResponse(
|
|
|
779
784
|
)
|
|
780
785
|
: null;
|
|
781
786
|
|
|
782
|
-
let
|
|
787
|
+
let itemsRead: Promise<
|
|
788
|
+
Array<typeof schema.contentDatabaseItems.$inferSelect>
|
|
789
|
+
>;
|
|
783
790
|
if (options.sidebarOrder && !serverTableQuery) {
|
|
784
791
|
const customItemIds = options.sidebarOrder.itemIds;
|
|
785
792
|
const customRank = contentDatabaseCustomOrderRank(customItemIds);
|
|
@@ -814,7 +821,7 @@ export async function getContentDatabasePageResponse(
|
|
|
814
821
|
if (limit !== null) {
|
|
815
822
|
orderedItemsQuery = orderedItemsQuery.limit(limit).offset(offset);
|
|
816
823
|
}
|
|
817
|
-
|
|
824
|
+
itemsRead = orderedItemsQuery.then((rows) => rows.map((row) => row.item));
|
|
818
825
|
} else {
|
|
819
826
|
let itemsQuery = db
|
|
820
827
|
.select()
|
|
@@ -831,98 +838,108 @@ export async function getContentDatabasePageResponse(
|
|
|
831
838
|
} else if (limit !== null) {
|
|
832
839
|
itemsQuery = itemsQuery.limit(limit).offset(offset);
|
|
833
840
|
}
|
|
834
|
-
|
|
841
|
+
itemsRead = itemsQuery.then((rows) => rows);
|
|
835
842
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
.select({
|
|
840
|
-
id: schema.documents.id,
|
|
841
|
-
title: schema.documents.title,
|
|
842
|
-
ownerEmail: schema.documents.ownerEmail,
|
|
843
|
-
createdAt: schema.documents.createdAt,
|
|
844
|
-
updatedAt: schema.documents.updatedAt,
|
|
845
|
-
})
|
|
846
|
-
.from(schema.documents)
|
|
847
|
-
.innerJoin(
|
|
848
|
-
schema.contentDatabaseItems,
|
|
849
|
-
eq(schema.contentDatabaseItems.documentId, schema.documents.id),
|
|
843
|
+
const queryProperties = boundedProjectionPropertyIds
|
|
844
|
+
? databaseProperties.filter((property) =>
|
|
845
|
+
boundedProjectionPropertyIds.has(property.definition.id),
|
|
850
846
|
)
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
847
|
+
: [];
|
|
848
|
+
const additionalBlocksPropertyIds = queryProperties.flatMap((property) =>
|
|
849
|
+
isBlocksPropertyType(property.definition.type) &&
|
|
850
|
+
!isPrimaryBlocksField(property.definition.options)
|
|
851
|
+
? [property.definition.id]
|
|
852
|
+
: [],
|
|
853
|
+
);
|
|
854
|
+
const [itemRows, boundedCandidates] = await Promise.all([
|
|
855
|
+
itemsRead,
|
|
856
|
+
serverTableQuery && boundedProjectionPropertyIds
|
|
857
|
+
? Promise.all([
|
|
858
|
+
db
|
|
863
859
|
.select({
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
860
|
+
id: schema.documents.id,
|
|
861
|
+
title: schema.documents.title,
|
|
862
|
+
ownerEmail: schema.documents.ownerEmail,
|
|
863
|
+
createdAt: schema.documents.createdAt,
|
|
864
|
+
updatedAt: schema.documents.updatedAt,
|
|
867
865
|
})
|
|
868
|
-
.from(schema.
|
|
866
|
+
.from(schema.documents)
|
|
869
867
|
.innerJoin(
|
|
870
868
|
schema.contentDatabaseItems,
|
|
871
|
-
eq(
|
|
872
|
-
schema.contentDatabaseItems.documentId,
|
|
873
|
-
schema.documentPropertyValues.documentId,
|
|
874
|
-
),
|
|
869
|
+
eq(schema.contentDatabaseItems.documentId, schema.documents.id),
|
|
875
870
|
)
|
|
876
871
|
.where(
|
|
877
872
|
and(
|
|
878
873
|
visibleItemFilter,
|
|
879
|
-
|
|
880
|
-
...boundedProjectionPropertyIds,
|
|
881
|
-
]),
|
|
874
|
+
eq(schema.documents.ownerEmail, database.ownerEmail),
|
|
882
875
|
),
|
|
883
|
-
)
|
|
884
|
-
|
|
876
|
+
),
|
|
877
|
+
boundedProjectionPropertyIds.size > 0
|
|
878
|
+
? db
|
|
879
|
+
.select({
|
|
880
|
+
documentId: schema.documentPropertyValues.documentId,
|
|
881
|
+
propertyId: schema.documentPropertyValues.propertyId,
|
|
882
|
+
valueJson: schema.documentPropertyValues.valueJson,
|
|
883
|
+
})
|
|
884
|
+
.from(schema.documentPropertyValues)
|
|
885
|
+
.innerJoin(
|
|
886
|
+
schema.contentDatabaseItems,
|
|
887
|
+
eq(
|
|
888
|
+
schema.contentDatabaseItems.documentId,
|
|
889
|
+
schema.documentPropertyValues.documentId,
|
|
890
|
+
),
|
|
891
|
+
)
|
|
892
|
+
.where(
|
|
893
|
+
and(
|
|
894
|
+
visibleItemFilter,
|
|
895
|
+
inArray(schema.documentPropertyValues.propertyId, [
|
|
896
|
+
...boundedProjectionPropertyIds,
|
|
897
|
+
]),
|
|
898
|
+
),
|
|
899
|
+
)
|
|
900
|
+
: [],
|
|
901
|
+
additionalBlocksPropertyIds.length > 0
|
|
902
|
+
? db
|
|
903
|
+
.select({
|
|
904
|
+
documentId: schema.documentBlockFieldContents.documentId,
|
|
905
|
+
propertyId: schema.documentBlockFieldContents.propertyId,
|
|
906
|
+
content: schema.documentBlockFieldContents.content,
|
|
907
|
+
})
|
|
908
|
+
.from(schema.documentBlockFieldContents)
|
|
909
|
+
.innerJoin(
|
|
910
|
+
schema.contentDatabaseItems,
|
|
911
|
+
eq(
|
|
912
|
+
schema.contentDatabaseItems.documentId,
|
|
913
|
+
schema.documentBlockFieldContents.documentId,
|
|
914
|
+
),
|
|
915
|
+
)
|
|
916
|
+
.where(
|
|
917
|
+
and(
|
|
918
|
+
visibleItemFilter,
|
|
919
|
+
inArray(
|
|
920
|
+
schema.documentBlockFieldContents.propertyId,
|
|
921
|
+
additionalBlocksPropertyIds,
|
|
922
|
+
),
|
|
923
|
+
),
|
|
924
|
+
)
|
|
925
|
+
: [],
|
|
926
|
+
])
|
|
927
|
+
: null,
|
|
928
|
+
]);
|
|
929
|
+
let items = itemRows;
|
|
930
|
+
let boundedTableQueryTotal: number | null = null;
|
|
931
|
+
if (serverTableQuery && boundedCandidates) {
|
|
932
|
+
const [candidateDocuments, candidateValues, candidateBlockContents] =
|
|
933
|
+
boundedCandidates;
|
|
934
|
+
const candidateDocumentById = new Map(
|
|
935
|
+
candidateDocuments.map((document) => [document.id, document]),
|
|
936
|
+
);
|
|
885
937
|
const candidateValueByDocumentAndProperty = new Map(
|
|
886
938
|
candidateValues.map((value) => [
|
|
887
939
|
`${value.documentId}\0${value.propertyId}`,
|
|
888
940
|
parsePropertyValue(value.valueJson),
|
|
889
941
|
]),
|
|
890
942
|
);
|
|
891
|
-
const queryProperties = databaseProperties.filter((property) =>
|
|
892
|
-
boundedProjectionPropertyIds.has(property.definition.id),
|
|
893
|
-
);
|
|
894
|
-
const additionalBlocksPropertyIds = queryProperties.flatMap((property) =>
|
|
895
|
-
isBlocksPropertyType(property.definition.type) &&
|
|
896
|
-
!isPrimaryBlocksField(property.definition.options)
|
|
897
|
-
? [property.definition.id]
|
|
898
|
-
: [],
|
|
899
|
-
);
|
|
900
|
-
const candidateBlockContents =
|
|
901
|
-
additionalBlocksPropertyIds.length > 0
|
|
902
|
-
? await db
|
|
903
|
-
.select({
|
|
904
|
-
documentId: schema.documentBlockFieldContents.documentId,
|
|
905
|
-
propertyId: schema.documentBlockFieldContents.propertyId,
|
|
906
|
-
content: schema.documentBlockFieldContents.content,
|
|
907
|
-
})
|
|
908
|
-
.from(schema.documentBlockFieldContents)
|
|
909
|
-
.innerJoin(
|
|
910
|
-
schema.contentDatabaseItems,
|
|
911
|
-
eq(
|
|
912
|
-
schema.contentDatabaseItems.documentId,
|
|
913
|
-
schema.documentBlockFieldContents.documentId,
|
|
914
|
-
),
|
|
915
|
-
)
|
|
916
|
-
.where(
|
|
917
|
-
and(
|
|
918
|
-
visibleItemFilter,
|
|
919
|
-
inArray(
|
|
920
|
-
schema.documentBlockFieldContents.propertyId,
|
|
921
|
-
additionalBlocksPropertyIds,
|
|
922
|
-
),
|
|
923
|
-
),
|
|
924
|
-
)
|
|
925
|
-
: [];
|
|
926
943
|
const candidateBlockContentByDocumentAndProperty = new Map(
|
|
927
944
|
candidateBlockContents.map((row) => [
|
|
928
945
|
`${row.documentId}\0${row.propertyId}`,
|
|
@@ -1027,114 +1044,78 @@ export async function getContentDatabasePageResponse(
|
|
|
1027
1044
|
)
|
|
1028
1045
|
: [];
|
|
1029
1046
|
const documentById = new Map(documents.map((doc) => [doc.id, doc]));
|
|
1030
|
-
const
|
|
1047
|
+
const documentIds = documents.map((document) => document.id);
|
|
1048
|
+
const sharePrincipalClauses: NonNullable<ReturnType<typeof and>>[] = [];
|
|
1049
|
+
if (userEmail) {
|
|
1050
|
+
sharePrincipalClauses.push(
|
|
1051
|
+
and(
|
|
1052
|
+
eq(schema.documentShares.principalType, "user"),
|
|
1053
|
+
eq(schema.documentShares.principalId, userEmail),
|
|
1054
|
+
)!,
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
if (activeOrgId) {
|
|
1058
|
+
sharePrincipalClauses.push(
|
|
1059
|
+
and(
|
|
1060
|
+
eq(schema.documentShares.principalType, "org"),
|
|
1061
|
+
eq(schema.documentShares.principalId, activeOrgId),
|
|
1062
|
+
)!,
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
const [
|
|
1066
|
+
favorites,
|
|
1067
|
+
shareRows,
|
|
1068
|
+
propertiesByDocumentId,
|
|
1069
|
+
filesProjection,
|
|
1070
|
+
queuedBodyHydrationItemIds,
|
|
1071
|
+
workspaceMemberships,
|
|
1072
|
+
] = await Promise.all([
|
|
1031
1073
|
database.systemRole === "favorites"
|
|
1032
|
-
? new Set(
|
|
1074
|
+
? new Set(documentIds)
|
|
1033
1075
|
: userEmail
|
|
1034
|
-
?
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1076
|
+
? favoriteDocumentIds(db, userEmail, documentIds)
|
|
1077
|
+
: new Set<string>(),
|
|
1078
|
+
documents.length > 0 && sharePrincipalClauses.length > 0
|
|
1079
|
+
? db
|
|
1080
|
+
.select({
|
|
1081
|
+
resourceId: schema.documentShares.resourceId,
|
|
1082
|
+
role: schema.documentShares.role,
|
|
1083
|
+
})
|
|
1084
|
+
.from(schema.documentShares)
|
|
1085
|
+
.where(
|
|
1086
|
+
and(
|
|
1087
|
+
inArray(schema.documentShares.resourceId, documentIds),
|
|
1088
|
+
or(...sharePrincipalClauses),
|
|
1089
|
+
),
|
|
1038
1090
|
)
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
)!,
|
|
1051
|
-
);
|
|
1052
|
-
}
|
|
1053
|
-
if (orgId) {
|
|
1054
|
-
principalClauses.push(
|
|
1055
|
-
and(
|
|
1056
|
-
eq(schema.documentShares.principalType, "org"),
|
|
1057
|
-
eq(schema.documentShares.principalId, orgId),
|
|
1058
|
-
)!,
|
|
1059
|
-
);
|
|
1060
|
-
}
|
|
1061
|
-
const shareRows =
|
|
1062
|
-
principalClauses.length > 0
|
|
1063
|
-
? await db
|
|
1064
|
-
.select({
|
|
1065
|
-
resourceId: schema.documentShares.resourceId,
|
|
1066
|
-
role: schema.documentShares.role,
|
|
1067
|
-
})
|
|
1068
|
-
.from(schema.documentShares)
|
|
1069
|
-
.where(
|
|
1070
|
-
and(
|
|
1071
|
-
inArray(
|
|
1072
|
-
schema.documentShares.resourceId,
|
|
1073
|
-
documents.map((document) => document.id),
|
|
1074
|
-
),
|
|
1075
|
-
or(...principalClauses),
|
|
1076
|
-
),
|
|
1077
|
-
)
|
|
1078
|
-
: [];
|
|
1079
|
-
for (const row of shareRows) {
|
|
1080
|
-
shareRoleByDocumentId.set(
|
|
1081
|
-
row.resourceId,
|
|
1082
|
-
strongerRole(
|
|
1083
|
-
shareRoleByDocumentId.get(row.resourceId) ?? null,
|
|
1084
|
-
row.role,
|
|
1085
|
-
),
|
|
1086
|
-
);
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
const propertiesByDocumentId = await listPropertiesForDatabaseDocuments(
|
|
1090
|
-
databaseId,
|
|
1091
|
-
documents as Array<typeof schema.documents.$inferSelect>,
|
|
1092
|
-
);
|
|
1093
|
-
const filesProjection = await filesSystemPropertyProjection({
|
|
1094
|
-
database,
|
|
1095
|
-
documents,
|
|
1096
|
-
properties: databaseProperties,
|
|
1097
|
-
});
|
|
1098
|
-
const responseProperties = filesProjection
|
|
1099
|
-
? applyFilesSystemPropertyProjection({
|
|
1100
|
-
properties: databaseProperties,
|
|
1101
|
-
projection: filesProjection,
|
|
1102
|
-
})
|
|
1103
|
-
: databaseProperties;
|
|
1104
|
-
if (filesProjection) {
|
|
1105
|
-
for (const document of documents) {
|
|
1106
|
-
propertiesByDocumentId.set(
|
|
1107
|
-
document.id,
|
|
1108
|
-
applyFilesSystemPropertyProjection({
|
|
1109
|
-
properties: propertiesByDocumentId.get(document.id) ?? [],
|
|
1110
|
-
projection: filesProjection,
|
|
1111
|
-
documentId: document.id,
|
|
1112
|
-
}),
|
|
1113
|
-
);
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
const queuedBodyHydrationItemIds =
|
|
1091
|
+
: [],
|
|
1092
|
+
listPropertiesForDatabaseDocuments(
|
|
1093
|
+
databaseId,
|
|
1094
|
+
documents as Array<typeof schema.documents.$inferSelect>,
|
|
1095
|
+
{ includeBlocksFieldIdentity: false, propertySchema },
|
|
1096
|
+
),
|
|
1097
|
+
filesSystemPropertyProjection({
|
|
1098
|
+
database,
|
|
1099
|
+
documents,
|
|
1100
|
+
properties: databaseProperties,
|
|
1101
|
+
}),
|
|
1117
1102
|
items.length > 0
|
|
1118
|
-
?
|
|
1119
|
-
(
|
|
1120
|
-
|
|
1121
|
-
.
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
.
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
).map((row) => row.databaseItemId),
|
|
1133
|
-
)
|
|
1134
|
-
: new Set<string>();
|
|
1135
|
-
const workspaceMemberships =
|
|
1103
|
+
? db
|
|
1104
|
+
.select({
|
|
1105
|
+
databaseItemId:
|
|
1106
|
+
schema.contentDatabaseBodyHydrationQueue.databaseItemId,
|
|
1107
|
+
})
|
|
1108
|
+
.from(schema.contentDatabaseBodyHydrationQueue)
|
|
1109
|
+
.where(
|
|
1110
|
+
inArray(
|
|
1111
|
+
schema.contentDatabaseBodyHydrationQueue.databaseItemId,
|
|
1112
|
+
items.map((item) => item.id),
|
|
1113
|
+
),
|
|
1114
|
+
)
|
|
1115
|
+
.then((rows) => new Set(rows.map((row) => row.databaseItemId)))
|
|
1116
|
+
: new Set<string>(),
|
|
1136
1117
|
database.systemRole === "favorites" && documents.length > 0
|
|
1137
|
-
?
|
|
1118
|
+
? db
|
|
1138
1119
|
.select({
|
|
1139
1120
|
documentId: schema.contentDatabaseItems.documentId,
|
|
1140
1121
|
databaseId: schema.contentDatabaseItems.databaseId,
|
|
@@ -1149,15 +1130,38 @@ export async function getContentDatabasePageResponse(
|
|
|
1149
1130
|
)
|
|
1150
1131
|
.where(
|
|
1151
1132
|
and(
|
|
1152
|
-
inArray(
|
|
1153
|
-
schema.contentDatabaseItems.documentId,
|
|
1154
|
-
documents.map((document) => document.id),
|
|
1155
|
-
),
|
|
1133
|
+
inArray(schema.contentDatabaseItems.documentId, documentIds),
|
|
1156
1134
|
eq(schema.contentDatabases.systemRole, "files"),
|
|
1157
1135
|
isNull(schema.contentDatabases.deletedAt),
|
|
1158
1136
|
),
|
|
1159
1137
|
)
|
|
1160
|
-
: []
|
|
1138
|
+
: [],
|
|
1139
|
+
]);
|
|
1140
|
+
const shareRoleByDocumentId = new Map<string, ShareRole>();
|
|
1141
|
+
for (const row of shareRows) {
|
|
1142
|
+
shareRoleByDocumentId.set(
|
|
1143
|
+
row.resourceId,
|
|
1144
|
+
strongerRole(shareRoleByDocumentId.get(row.resourceId) ?? null, row.role),
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
const responseProperties = filesProjection
|
|
1148
|
+
? applyFilesSystemPropertyProjection({
|
|
1149
|
+
properties: databaseProperties,
|
|
1150
|
+
projection: filesProjection,
|
|
1151
|
+
})
|
|
1152
|
+
: databaseProperties;
|
|
1153
|
+
if (filesProjection) {
|
|
1154
|
+
for (const document of documents) {
|
|
1155
|
+
propertiesByDocumentId.set(
|
|
1156
|
+
document.id,
|
|
1157
|
+
applyFilesSystemPropertyProjection({
|
|
1158
|
+
properties: propertiesByDocumentId.get(document.id) ?? [],
|
|
1159
|
+
projection: filesProjection,
|
|
1160
|
+
documentId: document.id,
|
|
1161
|
+
}),
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1161
1165
|
const workspaceDatabaseIdByDocumentId = new Map(
|
|
1162
1166
|
workspaceMemberships.map((membership) => [
|
|
1163
1167
|
membership.documentId,
|
|
@@ -1318,52 +1322,78 @@ export async function getContentDatabaseResponse(
|
|
|
1318
1322
|
filesMembershipDatabaseId?: string;
|
|
1319
1323
|
sidebarOrder?: ContentSidebarViewOrder;
|
|
1320
1324
|
database?: typeof schema.contentDatabases.$inferSelect;
|
|
1325
|
+
/** The caller's role on the database page, when it already resolved it. */
|
|
1326
|
+
accessRole?: ResolvedAccess["role"] | null;
|
|
1321
1327
|
} = {},
|
|
1322
1328
|
): Promise<ContentDatabaseResponse> {
|
|
1323
|
-
const page = await getContentDatabasePageResponse(databaseId, options);
|
|
1324
1329
|
const db = getDb();
|
|
1325
|
-
const
|
|
1326
|
-
.
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1330
|
+
const database =
|
|
1331
|
+
options.database ??
|
|
1332
|
+
(
|
|
1333
|
+
await db
|
|
1334
|
+
.select()
|
|
1335
|
+
.from(schema.contentDatabases)
|
|
1336
|
+
.where(eq(schema.contentDatabases.id, databaseId))
|
|
1337
|
+
)[0];
|
|
1338
|
+
if (!database || database.deletedAt) {
|
|
1339
|
+
fail(`Database "${databaseId}" not found`, {
|
|
1340
|
+
errorCode: "DATABASE_NOT_FOUND",
|
|
1341
|
+
statusCode: 404,
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1344
|
+
const [propertySchema, [databaseDocument]] = await Promise.all([
|
|
1345
|
+
readDatabasePropertySchema(db, database.id),
|
|
1346
|
+
db
|
|
1347
|
+
.select({
|
|
1348
|
+
id: schema.documents.id,
|
|
1349
|
+
parentId: schema.documents.parentId,
|
|
1350
|
+
description: schema.documents.description,
|
|
1351
|
+
})
|
|
1352
|
+
.from(schema.documents)
|
|
1353
|
+
.where(
|
|
1354
|
+
and(
|
|
1355
|
+
eq(schema.documents.id, database.documentId),
|
|
1356
|
+
accessFilter(schema.documents, schema.documentShares),
|
|
1357
|
+
),
|
|
1336
1358
|
),
|
|
1337
|
-
|
|
1338
|
-
const contextPath =
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1359
|
+
]);
|
|
1360
|
+
const [page, contextPath, contracts] = await Promise.all([
|
|
1361
|
+
getContentDatabasePageResponse(database.id, {
|
|
1362
|
+
...options,
|
|
1363
|
+
database,
|
|
1364
|
+
propertySchema,
|
|
1365
|
+
}),
|
|
1366
|
+
databaseDocument ? getDocumentContextPath(databaseDocument) : [],
|
|
1367
|
+
database.spaceId && !database.systemRole
|
|
1368
|
+
? getDatabaseMutationContract(
|
|
1345
1369
|
{
|
|
1346
|
-
authorityScope:
|
|
1347
|
-
? {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
kind: "personal",
|
|
1353
|
-
id: page.databaseRecord.ownerEmail,
|
|
1354
|
-
},
|
|
1355
|
-
spaceId: page.databaseRecord.spaceId,
|
|
1356
|
-
databaseId: page.databaseRecord.id,
|
|
1357
|
-
databaseDocumentId: page.databaseRecord.documentId,
|
|
1370
|
+
authorityScope: database.orgId
|
|
1371
|
+
? { kind: "organization", id: database.orgId }
|
|
1372
|
+
: { kind: "personal", id: database.ownerEmail },
|
|
1373
|
+
spaceId: database.spaceId,
|
|
1374
|
+
databaseId: database.id,
|
|
1375
|
+
databaseDocumentId: database.documentId,
|
|
1358
1376
|
},
|
|
1359
|
-
{
|
|
1360
|
-
|
|
1361
|
-
|
|
1377
|
+
{
|
|
1378
|
+
accessAlreadyResolved: true,
|
|
1379
|
+
loaded: {
|
|
1380
|
+
database,
|
|
1381
|
+
definitions: propertySchema.definitions,
|
|
1382
|
+
sourceManagedPropertyIds: propertySchema.sourceManagedPropertyIds,
|
|
1383
|
+
},
|
|
1384
|
+
},
|
|
1385
|
+
).then(async (mutationContract) => ({
|
|
1386
|
+
mutationContract,
|
|
1387
|
+
setupContract: await getDatabaseSetupContract(
|
|
1388
|
+
database,
|
|
1389
|
+
mutationContract,
|
|
1390
|
+
{ accessRole: options.accessRole },
|
|
1391
|
+
),
|
|
1392
|
+
}))
|
|
1393
|
+
: undefined,
|
|
1394
|
+
]);
|
|
1362
1395
|
return {
|
|
1363
|
-
database: serializeDatabase(
|
|
1364
|
-
page.databaseRecord,
|
|
1365
|
-
databaseDocument?.description ?? "",
|
|
1366
|
-
),
|
|
1396
|
+
database: serializeDatabase(database, databaseDocument?.description ?? ""),
|
|
1367
1397
|
contextPath,
|
|
1368
1398
|
properties: page.properties,
|
|
1369
1399
|
items: page.items,
|
|
@@ -1371,11 +1401,9 @@ export async function getContentDatabaseResponse(
|
|
|
1371
1401
|
sources: page.sources,
|
|
1372
1402
|
pagination: page.pagination,
|
|
1373
1403
|
tableQueryMode: page.tableQueryMode,
|
|
1374
|
-
mutationContract,
|
|
1375
|
-
configurationRevision: configurationRevision(
|
|
1376
|
-
setupContract:
|
|
1377
|
-
? await getDatabaseSetupContract(page.databaseRecord, mutationContract)
|
|
1378
|
-
: undefined,
|
|
1404
|
+
mutationContract: contracts?.mutationContract,
|
|
1405
|
+
configurationRevision: configurationRevision(database),
|
|
1406
|
+
setupContract: contracts?.setupContract,
|
|
1379
1407
|
};
|
|
1380
1408
|
}
|
|
1381
1409
|
|