@agent-native/core 0.114.0 → 0.114.1
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 +9 -0
- package/corpus/core/package.json +1 -1
- 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/vite/client.ts +17 -0
- package/corpus/templates/content/AGENTS.md +2 -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/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/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.js +2 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- 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/secrets/routes.d.ts +9 -9
- 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/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/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/vite/client.ts +17 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import { and, eq, inArray, sql } from "drizzle-orm";
|
|
4
|
+
|
|
5
|
+
import { schema } from "../server/db/index.js";
|
|
6
|
+
import { normalizeContentSpaceEmail } from "./_content-space-access.js";
|
|
7
|
+
import {
|
|
8
|
+
personalContentSpaceId,
|
|
9
|
+
systemIdsForContentSpace,
|
|
10
|
+
} from "./_content-spaces.js";
|
|
11
|
+
|
|
12
|
+
type Db = any;
|
|
13
|
+
|
|
14
|
+
export function favoritesSystemIds(userEmail: string) {
|
|
15
|
+
return systemIdsForContentSpace(
|
|
16
|
+
personalContentSpaceId(normalizeContentSpaceEmail(userEmail)),
|
|
17
|
+
"favorites",
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function favoriteDocumentIds(
|
|
22
|
+
db: Db,
|
|
23
|
+
userEmail: string,
|
|
24
|
+
documentIds: string[],
|
|
25
|
+
) {
|
|
26
|
+
if (documentIds.length === 0) return new Set<string>();
|
|
27
|
+
const favoritesDatabaseId = favoritesSystemIds(userEmail).databaseId;
|
|
28
|
+
const rows = await db
|
|
29
|
+
.select({ documentId: schema.contentDatabaseItems.documentId })
|
|
30
|
+
.from(schema.contentDatabaseItems)
|
|
31
|
+
.where(
|
|
32
|
+
and(
|
|
33
|
+
eq(schema.contentDatabaseItems.databaseId, favoritesDatabaseId),
|
|
34
|
+
inArray(schema.contentDatabaseItems.documentId, documentIds),
|
|
35
|
+
),
|
|
36
|
+
);
|
|
37
|
+
return new Set(rows.map((row: { documentId: string }) => row.documentId));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function setFavoriteMembership(args: {
|
|
41
|
+
db: Db;
|
|
42
|
+
userEmail: string;
|
|
43
|
+
documentId: string;
|
|
44
|
+
favorite: boolean;
|
|
45
|
+
now: string;
|
|
46
|
+
}) {
|
|
47
|
+
const email = normalizeContentSpaceEmail(args.userEmail);
|
|
48
|
+
const favoritesDatabaseId = favoritesSystemIds(email).databaseId;
|
|
49
|
+
const [existing] = await args.db
|
|
50
|
+
.select({ id: schema.contentDatabaseItems.id })
|
|
51
|
+
.from(schema.contentDatabaseItems)
|
|
52
|
+
.where(
|
|
53
|
+
and(
|
|
54
|
+
eq(schema.contentDatabaseItems.databaseId, favoritesDatabaseId),
|
|
55
|
+
eq(schema.contentDatabaseItems.documentId, args.documentId),
|
|
56
|
+
),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
if (!args.favorite) {
|
|
60
|
+
if (existing) {
|
|
61
|
+
await args.db
|
|
62
|
+
.delete(schema.contentDatabaseItems)
|
|
63
|
+
.where(eq(schema.contentDatabaseItems.id, existing.id));
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (existing) return true;
|
|
68
|
+
|
|
69
|
+
const [position] = await args.db
|
|
70
|
+
.select({ max: sql<number>`COALESCE(MAX(position), -1)` })
|
|
71
|
+
.from(schema.contentDatabaseItems)
|
|
72
|
+
.where(eq(schema.contentDatabaseItems.databaseId, favoritesDatabaseId));
|
|
73
|
+
const id = `content_database_item_${createHash("sha256")
|
|
74
|
+
.update(`${favoritesDatabaseId}:${args.documentId}`)
|
|
75
|
+
.digest("hex")
|
|
76
|
+
.slice(0, 32)}`;
|
|
77
|
+
await args.db
|
|
78
|
+
.insert(schema.contentDatabaseItems)
|
|
79
|
+
.values({
|
|
80
|
+
id,
|
|
81
|
+
ownerEmail: email,
|
|
82
|
+
orgId: null,
|
|
83
|
+
databaseId: favoritesDatabaseId,
|
|
84
|
+
documentId: args.documentId,
|
|
85
|
+
position: Number(position?.max ?? -1) + 1,
|
|
86
|
+
createdAt: args.now,
|
|
87
|
+
updatedAt: args.now,
|
|
88
|
+
})
|
|
89
|
+
.onConflictDoNothing();
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
|
|
3
3
|
import { accessFilter } from "@agent-native/core/sharing";
|
|
4
|
-
import { and, eq, inArray, isNull, or, sql } from "drizzle-orm";
|
|
4
|
+
import { and, eq, inArray, isNotNull, isNull, or, sql } from "drizzle-orm";
|
|
5
5
|
|
|
6
6
|
import { schema } from "../server/db/index.js";
|
|
7
7
|
import {
|
|
@@ -62,9 +62,44 @@ async function reconcileDocuments(args: {
|
|
|
62
62
|
args.filesDatabases.map((database) => [database.spaceId, database]),
|
|
63
63
|
);
|
|
64
64
|
const filesDatabaseIds = args.filesDatabases.map((database) => database.id);
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
const documentIds = args.documents.map((document) => document.id);
|
|
66
|
+
const [systemDatabaseDocuments, workspaceReferenceDocuments] =
|
|
67
|
+
documentIds.length > 0
|
|
68
|
+
? await Promise.all([
|
|
69
|
+
args.db
|
|
70
|
+
.select({ id: schema.contentDatabases.documentId })
|
|
71
|
+
.from(schema.contentDatabases)
|
|
72
|
+
.where(
|
|
73
|
+
and(
|
|
74
|
+
inArray(schema.contentDatabases.documentId, documentIds),
|
|
75
|
+
isNotNull(schema.contentDatabases.systemRole),
|
|
76
|
+
),
|
|
77
|
+
),
|
|
78
|
+
args.db
|
|
79
|
+
.select({ id: schema.contentSpaceCatalogItems.documentId })
|
|
80
|
+
.from(schema.contentSpaceCatalogItems)
|
|
81
|
+
.innerJoin(
|
|
82
|
+
schema.contentDatabases,
|
|
83
|
+
eq(
|
|
84
|
+
schema.contentDatabases.id,
|
|
85
|
+
schema.contentSpaceCatalogItems.catalogDatabaseId,
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
.where(
|
|
89
|
+
and(
|
|
90
|
+
inArray(
|
|
91
|
+
schema.contentSpaceCatalogItems.documentId,
|
|
92
|
+
documentIds,
|
|
93
|
+
),
|
|
94
|
+
eq(schema.contentDatabases.systemRole, "workspaces"),
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
])
|
|
98
|
+
: [[], []];
|
|
99
|
+
const excludedDocumentIds = new Set([
|
|
100
|
+
...systemDatabaseDocuments.map((document: any) => document.id),
|
|
101
|
+
...workspaceReferenceDocuments.map((document: any) => document.id),
|
|
102
|
+
]);
|
|
68
103
|
const existingItems = filesDatabaseIds.length
|
|
69
104
|
? await args.db
|
|
70
105
|
.select()
|
|
@@ -93,7 +128,7 @@ async function reconcileDocuments(args: {
|
|
|
93
128
|
const inserts: Array<typeof schema.contentDatabaseItems.$inferInsert> = [];
|
|
94
129
|
for (const document of args.documents) {
|
|
95
130
|
const existing = itemsByDocument.get(document.id) ?? [];
|
|
96
|
-
if (
|
|
131
|
+
if (excludedDocumentIds.has(document.id)) {
|
|
97
132
|
for (const item of existing) deleteIds.add(item.id);
|
|
98
133
|
continue;
|
|
99
134
|
}
|
|
@@ -239,24 +274,23 @@ export async function reconcileContentFilesMemberships(
|
|
|
239
274
|
const email = normalizeContentSpaceEmail(userEmail);
|
|
240
275
|
const memberships = await listContentOrganizationMemberships(email);
|
|
241
276
|
const personalSpaceId = personalContentSpaceId(email);
|
|
242
|
-
const
|
|
277
|
+
const orgSpaces = new Map<
|
|
278
|
+
string,
|
|
279
|
+
{ spaceId: string; canReconcilePrivateDocuments: boolean }
|
|
280
|
+
>();
|
|
243
281
|
for (const membership of memberships) {
|
|
244
282
|
const spaceId = organizationContentSpaceId(membership.orgId);
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
error.message ===
|
|
252
|
-
`Editor access is required for Content space "${spaceId}"`
|
|
253
|
-
) {
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
throw error;
|
|
257
|
-
}
|
|
283
|
+
await resolveContentSpaceAccess(spaceId);
|
|
284
|
+
orgSpaces.set(membership.orgId, {
|
|
285
|
+
spaceId,
|
|
286
|
+
canReconcilePrivateDocuments:
|
|
287
|
+
membership.role === "owner" || membership.role === "admin",
|
|
288
|
+
});
|
|
258
289
|
}
|
|
259
|
-
const accessibleSpaceIds = [
|
|
290
|
+
const accessibleSpaceIds = [
|
|
291
|
+
personalSpaceId,
|
|
292
|
+
...[...orgSpaces.values()].map(({ spaceId }) => spaceId),
|
|
293
|
+
];
|
|
260
294
|
const now = new Date().toISOString();
|
|
261
295
|
const result: ContentFilesReconciliation = {
|
|
262
296
|
assignedSpaces: 0,
|
|
@@ -288,7 +322,7 @@ export async function reconcileContentFilesMemberships(
|
|
|
288
322
|
);
|
|
289
323
|
result.assignedSpaces += personalLegacyDocuments.length;
|
|
290
324
|
}
|
|
291
|
-
for (const [orgId,
|
|
325
|
+
for (const [orgId, orgSpace] of orgSpaces) {
|
|
292
326
|
const legacyDocuments = await tx
|
|
293
327
|
.select({ id: schema.documents.id })
|
|
294
328
|
.from(schema.documents)
|
|
@@ -296,12 +330,19 @@ export async function reconcileContentFilesMemberships(
|
|
|
296
330
|
and(
|
|
297
331
|
eq(schema.documents.orgId, orgId),
|
|
298
332
|
isNull(schema.documents.spaceId),
|
|
333
|
+
orgSpace.canReconcilePrivateDocuments
|
|
334
|
+
? undefined
|
|
335
|
+
: or(
|
|
336
|
+
eq(schema.documents.ownerEmail, email),
|
|
337
|
+
eq(schema.documents.visibility, "org"),
|
|
338
|
+
eq(schema.documents.visibility, "public"),
|
|
339
|
+
),
|
|
299
340
|
),
|
|
300
341
|
);
|
|
301
342
|
if (!legacyDocuments.length) continue;
|
|
302
343
|
await tx
|
|
303
344
|
.update(schema.documents)
|
|
304
|
-
.set({ spaceId, updatedAt: now })
|
|
345
|
+
.set({ spaceId: orgSpace.spaceId, updatedAt: now })
|
|
305
346
|
.where(
|
|
306
347
|
inArray(
|
|
307
348
|
schema.documents.id,
|
|
@@ -311,10 +352,25 @@ export async function reconcileContentFilesMemberships(
|
|
|
311
352
|
result.assignedSpaces += legacyDocuments.length;
|
|
312
353
|
}
|
|
313
354
|
|
|
314
|
-
const
|
|
355
|
+
const accessibleDocuments = await tx
|
|
315
356
|
.select()
|
|
316
357
|
.from(schema.documents)
|
|
317
358
|
.where(inArray(schema.documents.spaceId, accessibleSpaceIds));
|
|
359
|
+
const orgSpaceById = new Map(
|
|
360
|
+
[...orgSpaces.values()].map((space) => [space.spaceId, space]),
|
|
361
|
+
);
|
|
362
|
+
const documents = accessibleDocuments.filter((document: any) => {
|
|
363
|
+
if (document.spaceId === personalSpaceId) {
|
|
364
|
+
return normalizeContentSpaceEmail(document.ownerEmail) === email;
|
|
365
|
+
}
|
|
366
|
+
const orgSpace = orgSpaceById.get(document.spaceId);
|
|
367
|
+
return (
|
|
368
|
+
orgSpace?.canReconcilePrivateDocuments === true ||
|
|
369
|
+
normalizeContentSpaceEmail(document.ownerEmail) === email ||
|
|
370
|
+
document.visibility === "org" ||
|
|
371
|
+
document.visibility === "public"
|
|
372
|
+
);
|
|
373
|
+
});
|
|
318
374
|
const filesDatabases = await tx
|
|
319
375
|
.select()
|
|
320
376
|
.from(schema.contentDatabases)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const CONTENT_SIDEBAR_STATE_VERSION = 1;
|
|
4
|
+
export const CONTENT_SIDEBAR_STATE_SETTING_KEY = "content-sidebar-state";
|
|
5
|
+
|
|
6
|
+
const expandedIdSchema = z.string().min(1).max(256);
|
|
7
|
+
|
|
8
|
+
export const contentSidebarStateSchema = z.object({
|
|
9
|
+
version: z.literal(CONTENT_SIDEBAR_STATE_VERSION),
|
|
10
|
+
expandedWorkspaceIds: z.array(expandedIdSchema).max(1_000),
|
|
11
|
+
expandedDocumentIds: z.array(expandedIdSchema).max(5_000),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type ContentSidebarState = z.infer<typeof contentSidebarStateSchema>;
|
|
15
|
+
|
|
16
|
+
export function normalizeContentSidebarState(value: unknown) {
|
|
17
|
+
const parsed = contentSidebarStateSchema.safeParse(value);
|
|
18
|
+
if (!parsed.success) return null;
|
|
19
|
+
return {
|
|
20
|
+
...parsed.data,
|
|
21
|
+
expandedWorkspaceIds: [...new Set(parsed.data.expandedWorkspaceIds)],
|
|
22
|
+
expandedDocumentIds: [...new Set(parsed.data.expandedDocumentIds)],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -1,25 +1,9 @@
|
|
|
1
1
|
import { getDbExec } from "@agent-native/core/db";
|
|
2
|
-
import { table, text } from "@agent-native/core/db/schema";
|
|
3
2
|
import { getRequestUserEmail } from "@agent-native/core/server/request-context";
|
|
4
3
|
import { and, eq, sql } from "drizzle-orm";
|
|
5
4
|
|
|
6
5
|
import { getDb, schema } from "../server/db/index.js";
|
|
7
6
|
|
|
8
|
-
// Keep these lightweight table references local. Importing the public org
|
|
9
|
-
// barrel also initializes auth's long-lived cleanup timer, which breaks test
|
|
10
|
-
// suites that intentionally drain fake timers.
|
|
11
|
-
const organizations = table("organizations", {
|
|
12
|
-
id: text("id").primaryKey(),
|
|
13
|
-
name: text("name").notNull(),
|
|
14
|
-
createdBy: text("created_by").notNull(),
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const orgMembers = table("org_members", {
|
|
18
|
-
orgId: text("org_id").notNull(),
|
|
19
|
-
email: text("email").notNull(),
|
|
20
|
-
role: text("role").notNull(),
|
|
21
|
-
});
|
|
22
|
-
|
|
23
7
|
export type ContentSpaceRole = "viewer" | "editor" | "owner";
|
|
24
8
|
|
|
25
9
|
export type ContentSpaceAccess = {
|
|
@@ -40,6 +24,10 @@ export async function getContentOrganizationMembership(
|
|
|
40
24
|
options: { db?: any } = {},
|
|
41
25
|
): Promise<{ role: string; name: string; createdBy: string } | null> {
|
|
42
26
|
if (options.db) {
|
|
27
|
+
// The canonical tables carry the active database dialect. Loading them only
|
|
28
|
+
// for transaction-scoped checks avoids initializing auth timers elsewhere.
|
|
29
|
+
const { organizations, orgMembers } =
|
|
30
|
+
await import("@agent-native/core/org");
|
|
43
31
|
const [row] = await options.db
|
|
44
32
|
.select({
|
|
45
33
|
role: orgMembers.role,
|
|
@@ -130,7 +118,7 @@ export async function listContentOrganizationMemberships(userEmail: string) {
|
|
|
130
118
|
|
|
131
119
|
export async function resolveContentSpaceAccess(
|
|
132
120
|
spaceId: string,
|
|
133
|
-
requiredRole: "viewer" | "editor" = "viewer",
|
|
121
|
+
requiredRole: "viewer" | "contributor" | "editor" = "viewer",
|
|
134
122
|
options: { db?: any } = {},
|
|
135
123
|
): Promise<ContentSpaceAccess> {
|
|
136
124
|
const userEmail = getRequestUserEmail();
|
|
@@ -167,6 +155,16 @@ export async function resolveContentSpaceAccess(
|
|
|
167
155
|
: membership.role === "admin"
|
|
168
156
|
? "editor"
|
|
169
157
|
: "viewer";
|
|
158
|
+
if (
|
|
159
|
+
requiredRole === "contributor" &&
|
|
160
|
+
membership.role !== "owner" &&
|
|
161
|
+
membership.role !== "admin" &&
|
|
162
|
+
membership.role !== "member"
|
|
163
|
+
) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`Contributor access is required for Content space "${spaceId}"`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
170
168
|
if (requiredRole === "editor" && role === "viewer") {
|
|
171
169
|
throw new Error(`Editor access is required for Content space "${spaceId}"`);
|
|
172
170
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { inArray } from "drizzle-orm";
|
|
2
|
+
|
|
3
|
+
import { schema } from "../server/db/index.js";
|
|
4
|
+
|
|
5
|
+
type Db = any;
|
|
6
|
+
|
|
7
|
+
export async function assertNotWorkspaceCatalogDocuments(
|
|
8
|
+
db: Db,
|
|
9
|
+
documentIds: string[],
|
|
10
|
+
operation: string,
|
|
11
|
+
) {
|
|
12
|
+
if (documentIds.length === 0) return;
|
|
13
|
+
const [workspaceReference] = await db
|
|
14
|
+
.select({ id: schema.contentSpaceCatalogItems.id })
|
|
15
|
+
.from(schema.contentSpaceCatalogItems)
|
|
16
|
+
.where(inArray(schema.contentSpaceCatalogItems.documentId, documentIds));
|
|
17
|
+
if (workspaceReference) {
|
|
18
|
+
throw new Error(`Workspace references cannot be ${operation} as pages`);
|
|
19
|
+
}
|
|
20
|
+
}
|