@agent-native/core 0.114.0 → 0.114.2
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 +2 -2
- package/corpus/core/CHANGELOG.md +15 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/create.ts +23 -0
- package/corpus/core/src/cli/skills.ts +24 -0
- package/corpus/core/src/client/build-compatibility.ts +77 -0
- package/corpus/core/src/client/route-chunk-recovery/index.ts +1 -0
- package/corpus/core/src/client/use-action.ts +32 -1
- package/corpus/core/src/deploy/build.ts +4 -1
- package/corpus/core/src/org/context.ts +56 -30
- package/corpus/core/src/server/action-routes.ts +52 -2
- package/corpus/core/src/server/auth-plugin.ts +9 -4
- package/corpus/core/src/server/better-auth-instance.ts +5 -1
- package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
- package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/core/src/templates/default/AGENTS.md +4 -1
- package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/core/src/templates/headless/AGENTS.md +5 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
- package/corpus/core/src/templates/workspace-core/AGENTS.md +3 -1
- package/corpus/core/src/templates/workspace-root/AGENTS.md +3 -1
- package/corpus/core/src/vite/client.ts +17 -0
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/analytics/AGENTS.md +5 -0
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/assets/AGENTS.md +5 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/brain/AGENTS.md +5 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/calendar/AGENTS.md +5 -0
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/chat/AGENTS.md +4 -1
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/clips/AGENTS.md +5 -0
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/content/AGENTS.md +7 -0
- package/corpus/templates/content/actions/_content-database-personal-view.ts +49 -5
- package/corpus/templates/content/actions/_content-document-access.ts +21 -0
- package/corpus/templates/content/actions/_content-favorites.ts +91 -0
- package/corpus/templates/content/actions/_content-files.ts +79 -23
- package/corpus/templates/content/actions/_content-sidebar-state.ts +24 -0
- package/corpus/templates/content/actions/_content-space-access.ts +15 -17
- package/corpus/templates/content/actions/_content-space-catalog-guards.ts +20 -0
- package/corpus/templates/content/actions/_content-spaces.ts +364 -167
- package/corpus/templates/content/actions/_database-source-utils.ts +8 -0
- package/corpus/templates/content/actions/_database-utils.ts +249 -15
- package/corpus/templates/content/actions/_delete-content-space.ts +84 -0
- package/corpus/templates/content/actions/_files-system-properties.ts +499 -0
- package/corpus/templates/content/actions/_local-file-documents.ts +0 -1
- package/corpus/templates/content/actions/_property-utils.ts +18 -9
- package/corpus/templates/content/actions/bind-content-database-source-field.ts +3 -0
- package/corpus/templates/content/actions/configure-document-property.ts +3 -0
- package/corpus/templates/content/actions/create-content-database.ts +2 -2
- package/corpus/templates/content/actions/create-content-space.ts +34 -0
- package/corpus/templates/content/actions/create-document.ts +4 -1
- package/corpus/templates/content/actions/delete-content-space.ts +19 -0
- package/corpus/templates/content/actions/delete-database-items.ts +28 -1
- package/corpus/templates/content/actions/delete-document-property.ts +3 -0
- package/corpus/templates/content/actions/delete-document.ts +39 -2
- package/corpus/templates/content/actions/duplicate-database-item.ts +6 -0
- package/corpus/templates/content/actions/duplicate-database-items.ts +6 -0
- package/corpus/templates/content/actions/duplicate-document-property.ts +3 -0
- package/corpus/templates/content/actions/get-content-database.ts +11 -2
- package/corpus/templates/content/actions/get-content-sidebar-state.ts +23 -0
- package/corpus/templates/content/actions/get-document.ts +32 -7
- package/corpus/templates/content/actions/import-content-source.ts +33 -1
- package/corpus/templates/content/actions/list-content-spaces.ts +34 -2
- package/corpus/templates/content/actions/list-documents.ts +39 -7
- package/corpus/templates/content/actions/reorder-document-property.ts +9 -0
- package/corpus/templates/content/actions/set-document-property.ts +41 -23
- package/corpus/templates/content/actions/share-local-file-document.ts +15 -0
- package/corpus/templates/content/actions/submit-content-database-form.ts +7 -0
- package/corpus/templates/content/actions/sync-local-folder-source.ts +14 -0
- package/corpus/templates/content/actions/update-content-database-view.ts +1 -0
- package/corpus/templates/content/actions/update-content-sidebar-state.ts +27 -0
- package/corpus/templates/content/actions/update-document.ts +158 -66
- package/corpus/templates/content/app/components/EmptyState.tsx +4 -57
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +8 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +519 -178
- package/corpus/templates/content/app/components/editor/DocumentInfoPanel.tsx +39 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +1 -1
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +266 -7
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +430 -152
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +467 -66
- package/corpus/templates/content/app/components/editor/database/view-config.ts +9 -3
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +720 -196
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +173 -1
- package/corpus/templates/content/app/components/sidebar/document-sidebar-sections.ts +1 -1
- package/corpus/templates/content/app/components/sidebar/select-content-space.ts +91 -16
- package/corpus/templates/content/app/entry.client.tsx +5 -1
- package/corpus/templates/content/app/hooks/use-content-database.ts +84 -3
- package/corpus/templates/content/app/hooks/use-content-spaces.ts +60 -2
- package/corpus/templates/content/app/hooks/use-create-page.ts +30 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +270 -19
- package/corpus/templates/content/app/i18n-data.ts +243 -20
- package/corpus/templates/content/app/lib/local-folder-picker-safety.ts +54 -0
- package/corpus/templates/content/app/lib/local-folder-picker-support.ts +18 -0
- package/corpus/templates/content/app/routes/_app.favorites.tsx +30 -0
- package/corpus/templates/content/app/routes/_app.local-files.tsx +18 -6
- package/corpus/templates/content/changelog/2026-07-17-workspace-files-now-stay-in-a-loading-state-until-automatic-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-17-workspace-switching-now-opens-the-selected-files-database-pr.md +6 -0
- package/corpus/templates/content/changelog/2026-07-17-workspaces-now-expand-above-their-own-files-list-without-dup.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-create-named-workspaces-each-with-its-own-private-files-data.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-favorites-align-with-workspace-and-file-rows-in-the-sidebar.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-local-folder-selection-no-longer-invokes-the-unsafe-native-p.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-made-content-workspaces-independently-expandable-restored-or.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-page-details-now-live-in-a-shared-info-and-comments-rail-dat.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-workspace-database-views-now-control-sidebar-workspace-navig.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-workspace-navigation-now-aligns-favorites-with-workspace-pag.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-favorites-now-open-as-a-table-and-compact-breadcrumbs-make-w.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-files-databases-now-start-unfiltered-sidebar-rows-exactly-fo.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-sidebar-page-trees-now-open-only-when-expanded-remember-thei.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspace-file-databases-now-use-the-workspace-name-open-as-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspace-navigation-now-stays-stable-on-hover-uses-folder-i.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspace-rows-now-use-folder-icons-and-deleting-a-user-crea.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspaces-can-be-created-without-leaving-the-workspaces-dat.md +6 -0
- package/corpus/templates/content/e2e/global-setup.ts +3 -2
- package/corpus/templates/content/parity/matrix.md +28 -28
- package/corpus/templates/content/parity/matrix.ts +8 -2
- package/corpus/templates/content/server/db/index.ts +1 -0
- package/corpus/templates/content/server/db/schema.ts +10 -0
- package/corpus/templates/content/server/lib/documents.ts +12 -7
- package/corpus/templates/content/server/plugins/db.ts +17 -0
- package/corpus/templates/content/shared/api.ts +9 -0
- package/corpus/templates/content/shared/database-form.ts +11 -2
- package/corpus/templates/content/vite.config.ts +1 -0
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/design/AGENTS.md +5 -0
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/dispatch/AGENTS.md +5 -0
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/forms/AGENTS.md +5 -0
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/macros/AGENTS.md +5 -0
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/mail/AGENTS.md +5 -0
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/plan/AGENTS.md +5 -0
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/slides/AGENTS.md +5 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/tasks/AGENTS.md +5 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +21 -0
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +19 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/build-compatibility.d.ts +11 -0
- package/dist/client/build-compatibility.d.ts.map +1 -0
- package/dist/client/build-compatibility.js +56 -0
- package/dist/client/build-compatibility.js.map +1 -0
- package/dist/client/route-chunk-recovery/index.d.ts +1 -0
- package/dist/client/route-chunk-recovery/index.d.ts.map +1 -1
- package/dist/client/route-chunk-recovery/index.js +1 -0
- package/dist/client/route-chunk-recovery/index.js.map +1 -1
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +19 -1
- package/dist/client/use-action.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/deploy/build.js +2 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/org/context.d.ts +4 -2
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +44 -22
- package/dist/org/context.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +10 -10
- package/dist/provider-api/actions/provider-api.d.ts +12 -12
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +32 -2
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth-plugin.d.ts.map +1 -1
- package/dist/server/auth-plugin.js +9 -5
- package/dist/server/auth-plugin.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +4 -1
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/mcp-embed-headers.d.ts +1 -1
- package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
- package/dist/shared/mcp-embed-headers.js +1 -1
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/dist/templates/chat/AGENTS.md +4 -1
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/dist/templates/default/AGENTS.md +4 -1
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/dist/templates/headless/AGENTS.md +5 -1
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
- package/dist/templates/workspace-core/AGENTS.md +3 -1
- package/dist/templates/workspace-root/AGENTS.md +3 -1
- package/dist/vite/client.d.ts +6 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +8 -0
- package/dist/vite/client.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/create.ts +23 -0
- package/src/cli/skills.ts +24 -0
- package/src/client/build-compatibility.ts +77 -0
- package/src/client/route-chunk-recovery/index.ts +1 -0
- package/src/client/use-action.ts +32 -1
- package/src/deploy/build.ts +4 -1
- package/src/org/context.ts +56 -30
- package/src/server/action-routes.ts +52 -2
- package/src/server/auth-plugin.ts +9 -4
- package/src/server/better-auth-instance.ts +5 -1
- package/src/shared/mcp-embed-headers.ts +1 -1
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/src/templates/chat/AGENTS.md +4 -1
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/src/templates/default/AGENTS.md +4 -1
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/src/templates/headless/AGENTS.md +5 -1
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
- package/src/templates/workspace-core/AGENTS.md +3 -1
- package/src/templates/workspace-root/AGENTS.md +3 -1
- package/src/vite/client.ts +17 -0
|
@@ -86,6 +86,7 @@ import {
|
|
|
86
86
|
organizationContentSpaceId,
|
|
87
87
|
provisionContentSpaces,
|
|
88
88
|
} from "./_content-spaces.js";
|
|
89
|
+
import { ensureFilesSystemPropertyDefinitions } from "./_files-system-properties.js";
|
|
89
90
|
import {
|
|
90
91
|
databaseItemsPositionScope,
|
|
91
92
|
documentsPositionScope,
|
|
@@ -6258,6 +6259,13 @@ export async function ensureDatabaseSourceProperty(args: {
|
|
|
6258
6259
|
database: ContentDatabaseRow;
|
|
6259
6260
|
now: string;
|
|
6260
6261
|
}) {
|
|
6262
|
+
if (args.database.systemRole === "files") {
|
|
6263
|
+
await ensureFilesSystemPropertyDefinitions({
|
|
6264
|
+
database: args.database,
|
|
6265
|
+
now: args.now,
|
|
6266
|
+
});
|
|
6267
|
+
return;
|
|
6268
|
+
}
|
|
6261
6269
|
const db = getDb();
|
|
6262
6270
|
const sources = await db
|
|
6263
6271
|
.select({
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getRequestOrgId,
|
|
3
|
+
getRequestUserEmail,
|
|
4
|
+
} from "@agent-native/core/server/request-context";
|
|
5
|
+
import {
|
|
6
|
+
accessFilter,
|
|
7
|
+
ROLE_RANK,
|
|
8
|
+
type ShareRole,
|
|
9
|
+
} from "@agent-native/core/sharing";
|
|
10
|
+
import { and, asc, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
|
2
11
|
|
|
3
12
|
import { getDb, schema } from "../server/db/index.js";
|
|
4
13
|
import { getDocumentContextPath } from "../server/lib/document-context.js";
|
|
5
14
|
import {
|
|
15
|
+
documentDiscoveryFilter,
|
|
6
16
|
parseDocumentFavorite,
|
|
7
17
|
parseDocumentHideFromSearch,
|
|
8
18
|
} from "../server/lib/documents.js";
|
|
@@ -11,11 +21,17 @@ import type {
|
|
|
11
21
|
ContentDatabaseMembership,
|
|
12
22
|
ContentDatabaseResponse,
|
|
13
23
|
} from "../shared/api.js";
|
|
24
|
+
import { favoriteDocumentIds } from "./_content-favorites.js";
|
|
25
|
+
import { listContentOrganizationMemberships } from "./_content-space-access.js";
|
|
14
26
|
import { getAllContentDatabaseSourceSnapshots } from "./_database-source-utils.js";
|
|
15
27
|
import {
|
|
16
28
|
applyFederatedOverlayValues,
|
|
17
29
|
federateSources,
|
|
18
30
|
} from "./_federation-join.js";
|
|
31
|
+
import {
|
|
32
|
+
applyFilesSystemPropertyProjection,
|
|
33
|
+
filesSystemPropertyProjection,
|
|
34
|
+
} from "./_files-system-properties.js";
|
|
19
35
|
import {
|
|
20
36
|
listPropertiesForDatabaseDocuments,
|
|
21
37
|
listPropertiesForDatabase,
|
|
@@ -29,6 +45,15 @@ function canManageRole(role: string) {
|
|
|
29
45
|
return role === "owner" || role === "admin";
|
|
30
46
|
}
|
|
31
47
|
|
|
48
|
+
function canEditRole(role: string) {
|
|
49
|
+
return role === "owner" || role === "admin" || role === "editor";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function strongerRole(current: ShareRole | null, next: ShareRole): ShareRole {
|
|
53
|
+
if (!current || ROLE_RANK[next] > ROLE_RANK[current]) return next;
|
|
54
|
+
return current;
|
|
55
|
+
}
|
|
56
|
+
|
|
32
57
|
type DatabaseMembershipRow = {
|
|
33
58
|
item: typeof schema.contentDatabaseItems.$inferSelect;
|
|
34
59
|
database: typeof schema.contentDatabases.$inferSelect;
|
|
@@ -195,10 +220,34 @@ export function filterContentDatabaseSourceRowsForPage<
|
|
|
195
220
|
);
|
|
196
221
|
}
|
|
197
222
|
|
|
223
|
+
export function filterContentDatabaseSourceForVisibleDocuments<
|
|
224
|
+
TSource extends {
|
|
225
|
+
rows: Array<{ documentId: string }>;
|
|
226
|
+
changeSets: Array<{ documentId: string | null }>;
|
|
227
|
+
},
|
|
228
|
+
>(source: TSource, visibleDocumentIds: ReadonlySet<string>): TSource {
|
|
229
|
+
return {
|
|
230
|
+
...source,
|
|
231
|
+
rows: source.rows.filter(
|
|
232
|
+
(row) => !row.documentId || visibleDocumentIds.has(row.documentId),
|
|
233
|
+
),
|
|
234
|
+
changeSets: source.changeSets.filter(
|
|
235
|
+
(changeSet) =>
|
|
236
|
+
!changeSet.documentId || visibleDocumentIds.has(changeSet.documentId),
|
|
237
|
+
),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
198
241
|
function serializeDocument(
|
|
199
242
|
doc: DocumentListRow,
|
|
200
243
|
membership?: DatabaseMembershipRow,
|
|
244
|
+
shareRole?: ShareRole,
|
|
245
|
+
isFavorite?: boolean,
|
|
201
246
|
) {
|
|
247
|
+
const isOwner =
|
|
248
|
+
doc.ownerEmail.trim().toLowerCase() ===
|
|
249
|
+
getRequestUserEmail()?.trim().toLowerCase();
|
|
250
|
+
const accessRole = isOwner ? ("owner" as const) : (shareRole ?? "viewer");
|
|
202
251
|
return {
|
|
203
252
|
id: doc.id,
|
|
204
253
|
parentId: doc.parentId,
|
|
@@ -209,12 +258,12 @@ function serializeDocument(
|
|
|
209
258
|
description: doc.description,
|
|
210
259
|
icon: doc.icon,
|
|
211
260
|
position: doc.position,
|
|
212
|
-
isFavorite: parseDocumentFavorite(doc.isFavorite),
|
|
261
|
+
isFavorite: isFavorite ?? parseDocumentFavorite(doc.isFavorite),
|
|
213
262
|
hideFromSearch: parseDocumentHideFromSearch(doc.hideFromSearch),
|
|
214
263
|
visibility: doc.visibility,
|
|
215
|
-
accessRole
|
|
216
|
-
canEdit:
|
|
217
|
-
canManage: canManageRole(
|
|
264
|
+
accessRole,
|
|
265
|
+
canEdit: canEditRole(accessRole),
|
|
266
|
+
canManage: canManageRole(accessRole),
|
|
218
267
|
databaseMembership: membership
|
|
219
268
|
? serializeDatabaseMembership(membership)
|
|
220
269
|
: undefined,
|
|
@@ -250,15 +299,77 @@ export async function getContentDatabaseResponse(
|
|
|
250
299
|
// shared one a viewer is opening) must not mutate schema.
|
|
251
300
|
|
|
252
301
|
const { limit, offset } = normalizeContentDatabasePageOptions(options);
|
|
302
|
+
const userEmail = getRequestUserEmail();
|
|
303
|
+
const activeOrgId = getRequestOrgId();
|
|
304
|
+
const authorizedOrgIds =
|
|
305
|
+
database.systemRole === "favorites" && userEmail
|
|
306
|
+
? [
|
|
307
|
+
...new Set([
|
|
308
|
+
...(await listContentOrganizationMemberships(userEmail)).map(
|
|
309
|
+
(membership) => membership.orgId,
|
|
310
|
+
),
|
|
311
|
+
...(activeOrgId ? [activeOrgId] : []),
|
|
312
|
+
]),
|
|
313
|
+
]
|
|
314
|
+
: [];
|
|
315
|
+
const favoritesVisibleDocumentIds =
|
|
316
|
+
database.systemRole === "favorites" && userEmail
|
|
317
|
+
? (
|
|
318
|
+
await db
|
|
319
|
+
.select({ id: schema.documents.id })
|
|
320
|
+
.from(schema.documents)
|
|
321
|
+
.where(
|
|
322
|
+
and(
|
|
323
|
+
or(
|
|
324
|
+
accessFilter(schema.documents, schema.documentShares, {
|
|
325
|
+
userEmail,
|
|
326
|
+
}),
|
|
327
|
+
...authorizedOrgIds.map((orgId) =>
|
|
328
|
+
accessFilter(schema.documents, schema.documentShares, {
|
|
329
|
+
userEmail,
|
|
330
|
+
orgId,
|
|
331
|
+
}),
|
|
332
|
+
),
|
|
333
|
+
),
|
|
334
|
+
documentDiscoveryFilter({
|
|
335
|
+
userEmail,
|
|
336
|
+
orgIds: authorizedOrgIds,
|
|
337
|
+
}),
|
|
338
|
+
),
|
|
339
|
+
)
|
|
340
|
+
).map((document) => document.id)
|
|
341
|
+
: null;
|
|
342
|
+
const organizationFilesItemFilter =
|
|
343
|
+
database.systemRole === "files" && database.orgId
|
|
344
|
+
? sql`exists (
|
|
345
|
+
select 1 from ${schema.documents}
|
|
346
|
+
where ${schema.documents.id} = ${schema.contentDatabaseItems.documentId}
|
|
347
|
+
and ${schema.documents.orgId} = ${database.orgId}
|
|
348
|
+
and ${schema.documents.visibility} in ('org', 'public')
|
|
349
|
+
and (${schema.documents.hideFromSearch} = 0 or ${schema.documents.hideFromSearch} is null)
|
|
350
|
+
)`
|
|
351
|
+
: undefined;
|
|
352
|
+
const visibleItemFilter = and(
|
|
353
|
+
eq(schema.contentDatabaseItems.databaseId, databaseId),
|
|
354
|
+
organizationFilesItemFilter,
|
|
355
|
+
favoritesVisibleDocumentIds
|
|
356
|
+
? favoritesVisibleDocumentIds.length > 0
|
|
357
|
+
? inArray(
|
|
358
|
+
schema.contentDatabaseItems.documentId,
|
|
359
|
+
favoritesVisibleDocumentIds,
|
|
360
|
+
)
|
|
361
|
+
: sql`1 = 0`
|
|
362
|
+
: undefined,
|
|
363
|
+
);
|
|
253
364
|
const [itemCount] = await db
|
|
254
365
|
.select({ count: sql<number>`COUNT(*)` })
|
|
255
366
|
.from(schema.contentDatabaseItems)
|
|
256
|
-
.where(
|
|
367
|
+
.where(visibleItemFilter);
|
|
257
368
|
|
|
258
369
|
let itemsQuery = db
|
|
259
370
|
.select()
|
|
260
371
|
.from(schema.contentDatabaseItems)
|
|
261
|
-
.where(
|
|
372
|
+
.where(visibleItemFilter)
|
|
262
373
|
.orderBy(asc(schema.contentDatabaseItems.position))
|
|
263
374
|
.$dynamic();
|
|
264
375
|
if (limit !== null) {
|
|
@@ -277,17 +388,116 @@ export async function getContentDatabaseResponse(
|
|
|
277
388
|
schema.documents.id,
|
|
278
389
|
items.map((item) => item.documentId),
|
|
279
390
|
),
|
|
280
|
-
|
|
391
|
+
database.systemRole === "favorites"
|
|
392
|
+
? favoritesVisibleDocumentIds?.length
|
|
393
|
+
? inArray(schema.documents.id, favoritesVisibleDocumentIds)
|
|
394
|
+
: sql`1 = 0`
|
|
395
|
+
: database.systemRole === "files" && database.orgId
|
|
396
|
+
? and(
|
|
397
|
+
eq(schema.documents.orgId, database.orgId),
|
|
398
|
+
or(
|
|
399
|
+
eq(schema.documents.visibility, "org"),
|
|
400
|
+
eq(schema.documents.visibility, "public"),
|
|
401
|
+
),
|
|
402
|
+
or(
|
|
403
|
+
eq(schema.documents.hideFromSearch, 0),
|
|
404
|
+
isNull(schema.documents.hideFromSearch),
|
|
405
|
+
),
|
|
406
|
+
)
|
|
407
|
+
: eq(schema.documents.ownerEmail, database.ownerEmail),
|
|
281
408
|
),
|
|
282
409
|
)
|
|
283
410
|
: [];
|
|
284
411
|
const documentById = new Map(documents.map((doc) => [doc.id, doc]));
|
|
412
|
+
const favorites =
|
|
413
|
+
database.systemRole === "favorites"
|
|
414
|
+
? new Set(documents.map((document) => document.id))
|
|
415
|
+
: userEmail
|
|
416
|
+
? await favoriteDocumentIds(
|
|
417
|
+
db,
|
|
418
|
+
userEmail,
|
|
419
|
+
documents.map((document) => document.id),
|
|
420
|
+
)
|
|
421
|
+
: new Set<string>();
|
|
422
|
+
const shareRoleByDocumentId = new Map<string, ShareRole>();
|
|
423
|
+
if (documents.length > 0) {
|
|
424
|
+
const principalClauses: NonNullable<ReturnType<typeof and>>[] = [];
|
|
425
|
+
const userEmail = getRequestUserEmail();
|
|
426
|
+
const orgId = getRequestOrgId();
|
|
427
|
+
if (userEmail) {
|
|
428
|
+
principalClauses.push(
|
|
429
|
+
and(
|
|
430
|
+
eq(schema.documentShares.principalType, "user"),
|
|
431
|
+
eq(schema.documentShares.principalId, userEmail),
|
|
432
|
+
)!,
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
if (orgId) {
|
|
436
|
+
principalClauses.push(
|
|
437
|
+
and(
|
|
438
|
+
eq(schema.documentShares.principalType, "org"),
|
|
439
|
+
eq(schema.documentShares.principalId, orgId),
|
|
440
|
+
)!,
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
const shareRows =
|
|
444
|
+
principalClauses.length > 0
|
|
445
|
+
? await db
|
|
446
|
+
.select({
|
|
447
|
+
resourceId: schema.documentShares.resourceId,
|
|
448
|
+
role: schema.documentShares.role,
|
|
449
|
+
})
|
|
450
|
+
.from(schema.documentShares)
|
|
451
|
+
.where(
|
|
452
|
+
and(
|
|
453
|
+
inArray(
|
|
454
|
+
schema.documentShares.resourceId,
|
|
455
|
+
documents.map((document) => document.id),
|
|
456
|
+
),
|
|
457
|
+
or(...principalClauses),
|
|
458
|
+
),
|
|
459
|
+
)
|
|
460
|
+
: [];
|
|
461
|
+
for (const row of shareRows) {
|
|
462
|
+
shareRoleByDocumentId.set(
|
|
463
|
+
row.resourceId,
|
|
464
|
+
strongerRole(
|
|
465
|
+
shareRoleByDocumentId.get(row.resourceId) ?? null,
|
|
466
|
+
row.role,
|
|
467
|
+
),
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
285
471
|
const propertiesByDocumentId = await listPropertiesForDatabaseDocuments(
|
|
286
472
|
databaseId,
|
|
287
473
|
// Property serialization uses metadata only; this list projection carries
|
|
288
474
|
// every document field it consumes except the deliberately omitted body.
|
|
289
475
|
documents as Array<typeof schema.documents.$inferSelect>,
|
|
290
476
|
);
|
|
477
|
+
const databaseProperties = await listPropertiesForDatabase(databaseId);
|
|
478
|
+
const filesProjection = await filesSystemPropertyProjection({
|
|
479
|
+
database,
|
|
480
|
+
documents,
|
|
481
|
+
properties: databaseProperties,
|
|
482
|
+
});
|
|
483
|
+
const responseProperties = filesProjection
|
|
484
|
+
? applyFilesSystemPropertyProjection({
|
|
485
|
+
properties: databaseProperties,
|
|
486
|
+
projection: filesProjection,
|
|
487
|
+
})
|
|
488
|
+
: databaseProperties;
|
|
489
|
+
if (filesProjection) {
|
|
490
|
+
for (const document of documents) {
|
|
491
|
+
propertiesByDocumentId.set(
|
|
492
|
+
document.id,
|
|
493
|
+
applyFilesSystemPropertyProjection({
|
|
494
|
+
properties: propertiesByDocumentId.get(document.id) ?? [],
|
|
495
|
+
projection: filesProjection,
|
|
496
|
+
documentId: document.id,
|
|
497
|
+
}),
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
291
501
|
const queuedBodyHydrationItemIds =
|
|
292
502
|
items.length > 0
|
|
293
503
|
? new Set(
|
|
@@ -316,11 +526,16 @@ export async function getContentDatabaseResponse(
|
|
|
316
526
|
serializedItems.push({
|
|
317
527
|
id: item.id,
|
|
318
528
|
databaseId: item.databaseId,
|
|
319
|
-
document: serializeDocument(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
529
|
+
document: serializeDocument(
|
|
530
|
+
document,
|
|
531
|
+
{
|
|
532
|
+
item,
|
|
533
|
+
database,
|
|
534
|
+
bodyHydrationQueueId: bodyHydrationQueued ? item.id : null,
|
|
535
|
+
},
|
|
536
|
+
shareRoleByDocumentId.get(document.id),
|
|
537
|
+
favorites.has(document.id),
|
|
538
|
+
),
|
|
324
539
|
position: item.position,
|
|
325
540
|
bodyHydration: serializeBodyHydration(item, {
|
|
326
541
|
queued: bodyHydrationQueued,
|
|
@@ -329,7 +544,25 @@ export async function getContentDatabaseResponse(
|
|
|
329
544
|
});
|
|
330
545
|
}
|
|
331
546
|
|
|
332
|
-
const
|
|
547
|
+
const sourceSnapshots = await getAllContentDatabaseSourceSnapshots(database);
|
|
548
|
+
const organizationVisibleDocumentIds = organizationFilesItemFilter
|
|
549
|
+
? new Set(
|
|
550
|
+
(
|
|
551
|
+
await db
|
|
552
|
+
.select({ documentId: schema.contentDatabaseItems.documentId })
|
|
553
|
+
.from(schema.contentDatabaseItems)
|
|
554
|
+
.where(visibleItemFilter)
|
|
555
|
+
).map((item) => item.documentId),
|
|
556
|
+
)
|
|
557
|
+
: null;
|
|
558
|
+
const sources = organizationVisibleDocumentIds
|
|
559
|
+
? sourceSnapshots.map((source) =>
|
|
560
|
+
filterContentDatabaseSourceForVisibleDocuments(
|
|
561
|
+
source,
|
|
562
|
+
organizationVisibleDocumentIds,
|
|
563
|
+
),
|
|
564
|
+
)
|
|
565
|
+
: sourceSnapshots;
|
|
333
566
|
const serializedDocumentIds = new Set(
|
|
334
567
|
serializedItems.map((item) => item.document.id),
|
|
335
568
|
);
|
|
@@ -365,7 +598,7 @@ export async function getContentDatabaseResponse(
|
|
|
365
598
|
contextPath: databaseDocument
|
|
366
599
|
? await getDocumentContextPath(databaseDocument)
|
|
367
600
|
: [],
|
|
368
|
-
properties:
|
|
601
|
+
properties: responseProperties,
|
|
369
602
|
items: itemsWithOverlay,
|
|
370
603
|
source: pagedPrimary,
|
|
371
604
|
sources: pagedSources,
|
|
@@ -467,6 +700,7 @@ export async function getDatabaseItemByDocumentId(
|
|
|
467
700
|
.orderBy(
|
|
468
701
|
sql`CASE WHEN ${schema.contentDatabaseSourceRows.sourceId} IS NOT NULL THEN 0 ELSE 1 END`,
|
|
469
702
|
sql`CASE WHEN ${schema.contentDatabases.systemRole} IS NULL THEN 0 ELSE 1 END`,
|
|
703
|
+
sql`CASE WHEN ${schema.contentDatabases.systemRole} = 'files' THEN 0 ELSE 1 END`,
|
|
470
704
|
asc(schema.contentDatabases.id),
|
|
471
705
|
);
|
|
472
706
|
return row ?? null;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { and, eq } from "drizzle-orm";
|
|
2
|
+
|
|
3
|
+
import { getDb, schema } from "../server/db/index.js";
|
|
4
|
+
import { resolveContentSpaceAccess } from "./_content-space-access.js";
|
|
5
|
+
import { deleteDocumentRecursive } from "./delete-document.js";
|
|
6
|
+
|
|
7
|
+
type Db = ReturnType<typeof getDb>;
|
|
8
|
+
|
|
9
|
+
export async function deleteUserContentSpace(db: Db, spaceId: string) {
|
|
10
|
+
return db.transaction(async (tx) => {
|
|
11
|
+
const scopedDb = tx as unknown as Db;
|
|
12
|
+
const access = await resolveContentSpaceAccess(spaceId, "editor", {
|
|
13
|
+
db: scopedDb,
|
|
14
|
+
});
|
|
15
|
+
if (access.role !== "owner" || access.space.kind !== "user") {
|
|
16
|
+
throw new Error("Only user-created workspaces can be deleted");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const [mapping] = await scopedDb
|
|
20
|
+
.select()
|
|
21
|
+
.from(schema.contentSpaceCatalogItems)
|
|
22
|
+
.where(
|
|
23
|
+
and(
|
|
24
|
+
eq(schema.contentSpaceCatalogItems.spaceId, spaceId),
|
|
25
|
+
eq(
|
|
26
|
+
schema.contentSpaceCatalogItems.ownerEmail,
|
|
27
|
+
access.authority.userEmail,
|
|
28
|
+
),
|
|
29
|
+
),
|
|
30
|
+
);
|
|
31
|
+
if (!mapping) throw new Error("Workspace catalog entry not found");
|
|
32
|
+
|
|
33
|
+
const [filesDatabase] = await scopedDb
|
|
34
|
+
.select({ documentId: schema.contentDatabases.documentId })
|
|
35
|
+
.from(schema.contentDatabases)
|
|
36
|
+
.where(
|
|
37
|
+
and(
|
|
38
|
+
eq(schema.contentDatabases.id, access.space.filesDatabaseId),
|
|
39
|
+
eq(schema.contentDatabases.spaceId, spaceId),
|
|
40
|
+
eq(schema.contentDatabases.systemRole, "files"),
|
|
41
|
+
),
|
|
42
|
+
);
|
|
43
|
+
if (!filesDatabase) throw new Error("Workspace Files database not found");
|
|
44
|
+
|
|
45
|
+
await scopedDb
|
|
46
|
+
.delete(schema.contentSpaceCatalogItems)
|
|
47
|
+
.where(eq(schema.contentSpaceCatalogItems.id, mapping.id));
|
|
48
|
+
const deletedCatalogDocuments = await deleteDocumentRecursive(
|
|
49
|
+
scopedDb,
|
|
50
|
+
mapping.documentId,
|
|
51
|
+
access.space.ownerEmail,
|
|
52
|
+
);
|
|
53
|
+
const deletedWorkspaceDocuments = await deleteDocumentRecursive(
|
|
54
|
+
scopedDb,
|
|
55
|
+
filesDatabase.documentId,
|
|
56
|
+
access.space.ownerEmail,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const remainingDocuments = await scopedDb
|
|
60
|
+
.select({ id: schema.documents.id })
|
|
61
|
+
.from(schema.documents)
|
|
62
|
+
.where(
|
|
63
|
+
and(
|
|
64
|
+
eq(schema.documents.spaceId, spaceId),
|
|
65
|
+
eq(schema.documents.ownerEmail, access.space.ownerEmail),
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
if (remainingDocuments.length > 0) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
"Workspace contains content outside its canonical Files database",
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
await scopedDb
|
|
75
|
+
.delete(schema.contentSpaces)
|
|
76
|
+
.where(eq(schema.contentSpaces.id, spaceId));
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
spaceId,
|
|
80
|
+
deletedDocuments:
|
|
81
|
+
deletedCatalogDocuments.length + deletedWorkspaceDocuments.length,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|