@agent-native/core 0.134.0 → 0.134.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 +1 -1
- package/corpus/core/CHANGELOG.md +6 -0
- package/corpus/core/docs/content/template-content-developers.mdx +1 -1
- package/corpus/core/package.json +1 -1
- package/corpus/templates/clips/changelog/2026-07-29-meeting-notes-no-longer-transcribe-the-other-side-twice-when.md +6 -0
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +37 -48
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +7 -5
- package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +182 -106
- package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +43 -14
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +3 -3
- package/corpus/templates/clips/desktop/src-tauri/src/echo_guard.rs +443 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -0
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +125 -16
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +6 -4
- package/corpus/templates/content/actions/_database-membership-lock.ts +25 -0
- package/corpus/templates/content/actions/_database-row-batch.ts +6 -2
- package/corpus/templates/content/actions/_database-source-utils.ts +289 -129
- package/corpus/templates/content/actions/_database-utils.ts +12 -3
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +39 -21
- package/corpus/templates/content/actions/attach-content-database-source.ts +4 -1
- package/corpus/templates/content/actions/change-content-database-source-role.ts +3 -5
- package/corpus/templates/content/actions/duplicate-document-property.ts +59 -46
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +77 -71
- package/corpus/templates/content/actions/materialize-builder-required-fields.ts +7 -0
- package/corpus/templates/content/actions/remove-database-items.ts +183 -0
- package/corpus/templates/content/actions/set-document-property.ts +57 -39
- package/corpus/templates/content/actions/sync-local-folder-source.ts +7 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +471 -329
- package/corpus/templates/content/app/components/editor/database/row-access.ts +45 -0
- package/corpus/templates/content/app/components/editor/database/shared.tsx +141 -38
- package/corpus/templates/content/app/hooks/use-content-database.ts +2 -2
- package/corpus/templates/content/app/i18n-data.ts +130 -0
- package/corpus/templates/content/changelog/2026-07-30-database-rows-can-now-be-removed-without-deleting-their-page.md +6 -0
- package/corpus/templates/content/parity/eval-scenarios.ts +2 -2
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +4 -5
- package/corpus/templates/content/shared/api.ts +4 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +26 -11
- package/corpus/templates/design/actions/take-design-screenshot.ts +7 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +11 -3
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +4 -1
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +54 -17
- package/corpus/templates/design/app/components/design/design-canvas/local-runtime.ts +126 -0
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +2 -0
- package/corpus/templates/design/app/pages/Index.tsx +3 -1
- package/corpus/templates/design/app/pages/Present.tsx +2 -1
- package/corpus/templates/design/changelog/2026-07-30-a-broken-inline-script-in-a-generated-screen-is-now-caught-o.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-design-html-is-now-validated-with-a-spec-grade-html-parser-i.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-designs-now-load-their-tailwind-and-alpine-runtimes-from-the.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-designs-with-a-broken-alpine-expression-are-now-caught-on-sa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-30-editing-a-design-no-longer-strips-its-styling-the-canvas-kep.md +6 -0
- package/corpus/templates/design/package.json +4 -0
- package/corpus/templates/design/shared/html-integrity.ts +802 -556
- package/dist/notifications/routes.d.ts +3 -3
- package/docs/content/template-content-developers.mdx +1 -1
- package/package.json +1 -1
- package/corpus/templates/content/actions/delete-database-items.ts +0 -89
|
@@ -91,6 +91,7 @@ import {
|
|
|
91
91
|
organizationContentSpaceId,
|
|
92
92
|
provisionContentSpaces,
|
|
93
93
|
} from "./_content-spaces.js";
|
|
94
|
+
import { lockDatabaseMemberships } from "./_database-membership-lock.js";
|
|
94
95
|
import { ensureFilesSystemPropertyDefinitions } from "./_files-system-properties.js";
|
|
95
96
|
import {
|
|
96
97
|
databaseItemsPositionScope,
|
|
@@ -1448,89 +1449,92 @@ async function enqueueBuilderBodyHydrations(
|
|
|
1448
1449
|
const databaseItemIds = Array.from(
|
|
1449
1450
|
new Set(uniqueRequests.map((request) => request.databaseItemId)),
|
|
1450
1451
|
);
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
existingRows
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1452
|
+
return db.transaction(async (tx) => {
|
|
1453
|
+
await lockDatabaseMemberships(tx, databaseItemIds);
|
|
1454
|
+
const existingRows: ContentDatabaseBodyHydrationQueueRowDb[] = [];
|
|
1455
|
+
for (const idChunk of chunks(databaseItemIds, idChunkSize())) {
|
|
1456
|
+
existingRows.push(
|
|
1457
|
+
...(await tx
|
|
1458
|
+
.select()
|
|
1459
|
+
.from(schema.contentDatabaseBodyHydrationQueue)
|
|
1460
|
+
.where(
|
|
1461
|
+
inArray(
|
|
1462
|
+
schema.contentDatabaseBodyHydrationQueue.databaseItemId,
|
|
1463
|
+
idChunk,
|
|
1464
|
+
),
|
|
1465
|
+
)),
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1468
|
+
const existingByItemId = new Map(
|
|
1469
|
+
existingRows.map((row) => [row.databaseItemId, row]),
|
|
1463
1470
|
);
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
:
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1471
|
+
const queueRows: (typeof schema.contentDatabaseBodyHydrationQueue.$inferInsert)[] =
|
|
1472
|
+
[];
|
|
1473
|
+
for (const request of uniqueRequests) {
|
|
1474
|
+
const existing = existingByItemId.get(request.databaseItemId);
|
|
1475
|
+
const existingEntry = existing ? parseHydrationEntry(existing) : null;
|
|
1476
|
+
const shouldPreserveExistingEntry =
|
|
1477
|
+
builderEntryHasBodyContent(existingEntry) &&
|
|
1478
|
+
!builderEntryHasBodyContent(request.entry);
|
|
1479
|
+
const priority =
|
|
1480
|
+
request.priority ??
|
|
1481
|
+
builderBodyHydrationPriorityForRequest({ documentId: null });
|
|
1482
|
+
queueRows.push({
|
|
1483
|
+
id: existing?.id ?? crypto.randomUUID(),
|
|
1484
|
+
ownerEmail: request.ownerEmail,
|
|
1485
|
+
orgId: request.orgId,
|
|
1486
|
+
sourceId: request.sourceId,
|
|
1487
|
+
databaseItemId: request.databaseItemId,
|
|
1488
|
+
documentId: request.documentId,
|
|
1489
|
+
sourceRowId: request.entry.id,
|
|
1490
|
+
sourceTable: request.sourceTable,
|
|
1491
|
+
sourceEntryJson: shouldPreserveExistingEntry
|
|
1492
|
+
? existing!.sourceEntryJson
|
|
1493
|
+
: JSON.stringify(request.entry),
|
|
1494
|
+
priority: Math.min(existing?.priority ?? priority, priority),
|
|
1495
|
+
attempts: existing?.attempts ?? 0,
|
|
1496
|
+
lastAttemptedAt: existing?.lastAttemptedAt ?? null,
|
|
1497
|
+
lastError: null,
|
|
1498
|
+
createdAt: existing?.createdAt ?? request.now,
|
|
1499
|
+
updatedAt: request.now,
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
const upsertedRows: ContentDatabaseBodyHydrationQueueRowDb[] = [];
|
|
1503
|
+
for (const chunk of chunks(queueRows, bulkChunkSizeForColumnCount(15))) {
|
|
1504
|
+
upsertedRows.push(
|
|
1505
|
+
...(await tx
|
|
1506
|
+
.insert(schema.contentDatabaseBodyHydrationQueue)
|
|
1507
|
+
.values(chunk)
|
|
1508
|
+
.onConflictDoUpdate({
|
|
1509
|
+
target: schema.contentDatabaseBodyHydrationQueue.databaseItemId,
|
|
1510
|
+
set: {
|
|
1511
|
+
ownerEmail: sql`excluded.owner_email`,
|
|
1512
|
+
orgId: sql`excluded.org_id`,
|
|
1513
|
+
sourceId: sql`excluded.source_id`,
|
|
1514
|
+
documentId: sql`excluded.document_id`,
|
|
1515
|
+
sourceRowId: sql`excluded.source_row_id`,
|
|
1516
|
+
sourceTable: sql`excluded.source_table`,
|
|
1517
|
+
sourceEntryJson: sql`excluded.source_entry_json`,
|
|
1518
|
+
priority: sql`excluded.priority`,
|
|
1519
|
+
lastError: null,
|
|
1520
|
+
updatedAt: sql`excluded.updated_at`,
|
|
1521
|
+
},
|
|
1522
|
+
})
|
|
1523
|
+
.returning()),
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
for (const idChunk of chunks(databaseItemIds, idChunkSize())) {
|
|
1527
|
+
await tx
|
|
1528
|
+
.update(schema.contentDatabaseItems)
|
|
1529
|
+
.set({
|
|
1530
|
+
bodyHydrationStatus: "pending",
|
|
1531
|
+
bodyHydrationError: null,
|
|
1532
|
+
updatedAt: uniqueRequests[0]!.now,
|
|
1519
1533
|
})
|
|
1520
|
-
.
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
await db
|
|
1525
|
-
.update(schema.contentDatabaseItems)
|
|
1526
|
-
.set({
|
|
1527
|
-
bodyHydrationStatus: "pending",
|
|
1528
|
-
bodyHydrationError: null,
|
|
1529
|
-
updatedAt: uniqueRequests[0]!.now,
|
|
1530
|
-
})
|
|
1531
|
-
.where(inArray(schema.contentDatabaseItems.id, idChunk));
|
|
1532
|
-
}
|
|
1533
|
-
return upsertedRows;
|
|
1534
|
+
.where(inArray(schema.contentDatabaseItems.id, idChunk));
|
|
1535
|
+
}
|
|
1536
|
+
return upsertedRows;
|
|
1537
|
+
});
|
|
1534
1538
|
}
|
|
1535
1539
|
|
|
1536
1540
|
export async function enqueueBuilderBodyHydrationForItems(args: {
|
|
@@ -5308,7 +5312,27 @@ export async function seedMockSourceRows(args: {
|
|
|
5308
5312
|
}) {
|
|
5309
5313
|
if (args.items.length === 0) return;
|
|
5310
5314
|
const db = getDb();
|
|
5311
|
-
const rows = args
|
|
5315
|
+
const rows = mockSourceRowsForSeed(args);
|
|
5316
|
+
await db.transaction(async (tx) => {
|
|
5317
|
+
await lockDatabaseMemberships(
|
|
5318
|
+
tx,
|
|
5319
|
+
rows.map((row) => row.databaseItemId),
|
|
5320
|
+
);
|
|
5321
|
+
await insertMockSourceRows(tx, rows, args.now);
|
|
5322
|
+
});
|
|
5323
|
+
}
|
|
5324
|
+
|
|
5325
|
+
function mockSourceRowsForSeed(args: {
|
|
5326
|
+
sourceId: string;
|
|
5327
|
+
ownerEmail: string;
|
|
5328
|
+
sourceType: ContentDatabaseSourceType;
|
|
5329
|
+
sourceTable: string;
|
|
5330
|
+
items: ContentDatabaseItem[];
|
|
5331
|
+
now: string;
|
|
5332
|
+
existingBuilderRows?: Map<string, ExistingBuilderSourceRowIdentity>;
|
|
5333
|
+
builderEntriesByDocumentId?: Map<string, BuilderCmsSourceEntry>;
|
|
5334
|
+
}) {
|
|
5335
|
+
return args.items.map((item, index) => {
|
|
5312
5336
|
const builderEntry = args.builderEntriesByDocumentId?.get(item.document.id);
|
|
5313
5337
|
const existingBuilderRow = args.existingBuilderRows?.get(item.document.id);
|
|
5314
5338
|
const builderIdentity =
|
|
@@ -5370,6 +5394,17 @@ export async function seedMockSourceRows(args: {
|
|
|
5370
5394
|
updatedAt: args.now,
|
|
5371
5395
|
};
|
|
5372
5396
|
});
|
|
5397
|
+
}
|
|
5398
|
+
|
|
5399
|
+
async function insertMockSourceRows(
|
|
5400
|
+
db: any,
|
|
5401
|
+
rows: ReturnType<typeof mockSourceRowsForSeed>,
|
|
5402
|
+
now: string,
|
|
5403
|
+
) {
|
|
5404
|
+
if (rows.length === 0) return;
|
|
5405
|
+
if (rows.some((row) => !row.sourceId)) {
|
|
5406
|
+
throw new Error("Source row writes require a source ID.");
|
|
5407
|
+
}
|
|
5373
5408
|
await db
|
|
5374
5409
|
.insert(schema.contentDatabaseSourceRows)
|
|
5375
5410
|
.values(rows)
|
|
@@ -5383,15 +5418,53 @@ export async function seedMockSourceRows(args: {
|
|
|
5383
5418
|
.update(schema.contentDatabaseItems)
|
|
5384
5419
|
.set({
|
|
5385
5420
|
bodyHydrationStatus: "unavailable",
|
|
5386
|
-
bodyHydrationAttemptedAt:
|
|
5421
|
+
bodyHydrationAttemptedAt: now,
|
|
5387
5422
|
bodyHydrationError: null,
|
|
5388
5423
|
bodyHydrationVersion: null,
|
|
5389
|
-
updatedAt:
|
|
5424
|
+
updatedAt: now,
|
|
5390
5425
|
})
|
|
5391
5426
|
.where(inArray(schema.contentDatabaseItems.id, idChunk));
|
|
5392
5427
|
}
|
|
5393
5428
|
}
|
|
5394
5429
|
|
|
5430
|
+
export async function replaceMockSourceRows(args: {
|
|
5431
|
+
sourceId: string;
|
|
5432
|
+
ownerEmail: string;
|
|
5433
|
+
sourceType: ContentDatabaseSourceType;
|
|
5434
|
+
sourceTable: string;
|
|
5435
|
+
items: ContentDatabaseItem[];
|
|
5436
|
+
now: string;
|
|
5437
|
+
existingBuilderRows?: Map<string, ExistingBuilderSourceRowIdentity>;
|
|
5438
|
+
builderEntriesByDocumentId?: Map<string, BuilderCmsSourceEntry>;
|
|
5439
|
+
documentIds?: string[];
|
|
5440
|
+
}) {
|
|
5441
|
+
const db = getDb();
|
|
5442
|
+
const rows = mockSourceRowsForSeed(args);
|
|
5443
|
+
await db.transaction(async (tx) => {
|
|
5444
|
+
const scope = args.documentIds?.length
|
|
5445
|
+
? and(
|
|
5446
|
+
eq(schema.contentDatabaseSourceRows.sourceId, args.sourceId),
|
|
5447
|
+
inArray(
|
|
5448
|
+
schema.contentDatabaseSourceRows.documentId,
|
|
5449
|
+
args.documentIds,
|
|
5450
|
+
),
|
|
5451
|
+
)
|
|
5452
|
+
: eq(schema.contentDatabaseSourceRows.sourceId, args.sourceId);
|
|
5453
|
+
const oldRows = await tx
|
|
5454
|
+
.select({
|
|
5455
|
+
databaseItemId: schema.contentDatabaseSourceRows.databaseItemId,
|
|
5456
|
+
})
|
|
5457
|
+
.from(schema.contentDatabaseSourceRows)
|
|
5458
|
+
.where(scope);
|
|
5459
|
+
await lockDatabaseMemberships(tx, [
|
|
5460
|
+
...oldRows.map((row) => row.databaseItemId).filter(Boolean),
|
|
5461
|
+
...rows.map((row) => row.databaseItemId),
|
|
5462
|
+
]);
|
|
5463
|
+
await tx.delete(schema.contentDatabaseSourceRows).where(scope);
|
|
5464
|
+
await insertMockSourceRows(tx, rows, args.now);
|
|
5465
|
+
});
|
|
5466
|
+
}
|
|
5467
|
+
|
|
5395
5468
|
export function sourceValuesForSeededSourceRow(args: {
|
|
5396
5469
|
sourceType: ContentDatabaseSourceType;
|
|
5397
5470
|
item: ContentDatabaseItem;
|
|
@@ -5862,10 +5935,6 @@ export async function resyncMockSourceSnapshot(args: {
|
|
|
5862
5935
|
.where(
|
|
5863
5936
|
eq(schema.contentDatabaseBodyHydrationQueue.sourceId, args.source.id),
|
|
5864
5937
|
);
|
|
5865
|
-
await db
|
|
5866
|
-
.delete(schema.contentDatabaseSourceRows)
|
|
5867
|
-
.where(eq(schema.contentDatabaseSourceRows.sourceId, args.source.id));
|
|
5868
|
-
|
|
5869
5938
|
await seedMockSourceFields({
|
|
5870
5939
|
sourceId: args.source.id,
|
|
5871
5940
|
ownerEmail: args.database.ownerEmail,
|
|
@@ -5873,7 +5942,7 @@ export async function resyncMockSourceSnapshot(args: {
|
|
|
5873
5942
|
properties,
|
|
5874
5943
|
now: args.now,
|
|
5875
5944
|
});
|
|
5876
|
-
await
|
|
5945
|
+
await replaceMockSourceRows({
|
|
5877
5946
|
sourceId: args.source.id,
|
|
5878
5947
|
ownerEmail: args.database.ownerEmail,
|
|
5879
5948
|
sourceType: normalizeSourceType(args.source.sourceType),
|
|
@@ -6054,6 +6123,7 @@ export function builderCmsEntryAlreadyRepresented(args: {
|
|
|
6054
6123
|
|
|
6055
6124
|
export async function importBuilderCmsEntriesAsDatabaseItems(args: {
|
|
6056
6125
|
database: ContentDatabaseRow;
|
|
6126
|
+
sourceId: string;
|
|
6057
6127
|
entries: BuilderCmsSourceEntry[];
|
|
6058
6128
|
now: string;
|
|
6059
6129
|
sourceTable: string;
|
|
@@ -6159,8 +6229,8 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
|
|
|
6159
6229
|
.filter((row) => !representedDocumentIds.has(row.document.id))
|
|
6160
6230
|
.map((row) => row.document.title.trim().toLowerCase()),
|
|
6161
6231
|
);
|
|
6162
|
-
const
|
|
6163
|
-
currentItems.map((row) => [row.document.id, row
|
|
6232
|
+
const currentRowByDocumentId = new Map(
|
|
6233
|
+
currentItems.map((row) => [row.document.id, row]),
|
|
6164
6234
|
);
|
|
6165
6235
|
|
|
6166
6236
|
// Reads MAX(position) for both `documents` and `content_database_items`
|
|
@@ -6195,7 +6265,6 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
|
|
|
6195
6265
|
const documentRows: (typeof schema.documents.$inferInsert)[] = [];
|
|
6196
6266
|
const itemRows: (typeof schema.contentDatabaseItems.$inferInsert)[] =
|
|
6197
6267
|
[];
|
|
6198
|
-
|
|
6199
6268
|
for (const entry of args.entries) {
|
|
6200
6269
|
if (
|
|
6201
6270
|
builderCmsEntryAlreadyRepresented({
|
|
@@ -6213,9 +6282,9 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
|
|
|
6213
6282
|
sourceTable: args.sourceTable,
|
|
6214
6283
|
entryId: entry.id,
|
|
6215
6284
|
});
|
|
6216
|
-
const
|
|
6217
|
-
|
|
6218
|
-
if (
|
|
6285
|
+
const existingDeterministicRow =
|
|
6286
|
+
currentRowByDocumentId.get(documentId);
|
|
6287
|
+
if (existingDeterministicRow?.item.id === itemId) {
|
|
6219
6288
|
// A prior attach can commit the deterministic document/item and
|
|
6220
6289
|
// fail before linking its source row. Treat that pair as the
|
|
6221
6290
|
// same Builder identity so refresh repairs the missing link
|
|
@@ -6230,7 +6299,8 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
|
|
|
6230
6299
|
continue;
|
|
6231
6300
|
}
|
|
6232
6301
|
|
|
6233
|
-
|
|
6302
|
+
const documentPosition = nextDocPosition++;
|
|
6303
|
+
const documentRow = {
|
|
6234
6304
|
id: documentId,
|
|
6235
6305
|
spaceId: databaseSpaceId,
|
|
6236
6306
|
ownerEmail: args.database.ownerEmail,
|
|
@@ -6239,20 +6309,22 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
|
|
|
6239
6309
|
title,
|
|
6240
6310
|
content: "",
|
|
6241
6311
|
icon: null,
|
|
6242
|
-
position:
|
|
6312
|
+
position: documentPosition,
|
|
6243
6313
|
isFavorite: 0,
|
|
6244
6314
|
hideFromSearch: databaseDocument?.hideFromSearch ?? 0,
|
|
6245
6315
|
visibility: databaseDocument?.visibility ?? "private",
|
|
6246
6316
|
createdAt: args.now,
|
|
6247
6317
|
updatedAt: args.now,
|
|
6248
|
-
}
|
|
6318
|
+
};
|
|
6319
|
+
const itemPosition = nextItemPosition++;
|
|
6320
|
+
documentRows.push(documentRow);
|
|
6249
6321
|
itemRows.push({
|
|
6250
6322
|
id: itemId,
|
|
6251
6323
|
ownerEmail: args.database.ownerEmail,
|
|
6252
6324
|
orgId: args.database.orgId,
|
|
6253
6325
|
databaseId: args.database.id,
|
|
6254
6326
|
documentId,
|
|
6255
|
-
position:
|
|
6327
|
+
position: itemPosition,
|
|
6256
6328
|
bodyHydrationStatus: "pending",
|
|
6257
6329
|
bodyHydrationError: null,
|
|
6258
6330
|
createdAt: args.now,
|
|
@@ -6260,6 +6332,100 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
|
|
|
6260
6332
|
});
|
|
6261
6333
|
importedEntriesByDocumentId.set(documentId, entry);
|
|
6262
6334
|
}
|
|
6335
|
+
const candidateDocumentById = new Map(
|
|
6336
|
+
documentRows.map((document) => [document.id!, document]),
|
|
6337
|
+
);
|
|
6338
|
+
const sourceSeedItems: ContentDatabaseItem[] = [
|
|
6339
|
+
...itemRows.map((item): ContentDatabaseItem => {
|
|
6340
|
+
const document = candidateDocumentById.get(item.documentId)!;
|
|
6341
|
+
return {
|
|
6342
|
+
id: item.id!,
|
|
6343
|
+
databaseId: args.database.id,
|
|
6344
|
+
document: {
|
|
6345
|
+
id: document.id!,
|
|
6346
|
+
parentId: document.parentId ?? null,
|
|
6347
|
+
title: document.title ?? "Untitled",
|
|
6348
|
+
content: "",
|
|
6349
|
+
icon: document.icon ?? null,
|
|
6350
|
+
position: document.position ?? 0,
|
|
6351
|
+
isFavorite: false,
|
|
6352
|
+
hideFromSearch: Boolean(document.hideFromSearch),
|
|
6353
|
+
visibility: document.visibility ?? "private",
|
|
6354
|
+
accessRole: "owner" as const,
|
|
6355
|
+
canView: true,
|
|
6356
|
+
canEdit: true,
|
|
6357
|
+
canManage: true,
|
|
6358
|
+
createdAt: document.createdAt!,
|
|
6359
|
+
updatedAt: document.updatedAt!,
|
|
6360
|
+
},
|
|
6361
|
+
position: item.position ?? 0,
|
|
6362
|
+
properties: [],
|
|
6363
|
+
bodyHydration: {
|
|
6364
|
+
status: "pending" as const,
|
|
6365
|
+
attemptedAt: null,
|
|
6366
|
+
error: null,
|
|
6367
|
+
version: null,
|
|
6368
|
+
},
|
|
6369
|
+
};
|
|
6370
|
+
}),
|
|
6371
|
+
...[...importedEntriesByDocumentId.keys()].flatMap(
|
|
6372
|
+
(documentId): ContentDatabaseItem[] => {
|
|
6373
|
+
if (candidateDocumentById.has(documentId)) return [];
|
|
6374
|
+
const row = currentRowByDocumentId.get(documentId);
|
|
6375
|
+
if (!row) return [];
|
|
6376
|
+
return [
|
|
6377
|
+
{
|
|
6378
|
+
id: row.item.id,
|
|
6379
|
+
databaseId: args.database.id,
|
|
6380
|
+
document: {
|
|
6381
|
+
id: row.document.id,
|
|
6382
|
+
parentId: row.document.parentId,
|
|
6383
|
+
title: row.document.title,
|
|
6384
|
+
content: "",
|
|
6385
|
+
icon: row.document.icon,
|
|
6386
|
+
position: row.document.position,
|
|
6387
|
+
isFavorite: Boolean(row.document.isFavorite),
|
|
6388
|
+
hideFromSearch: Boolean(row.document.hideFromSearch),
|
|
6389
|
+
visibility: row.document.visibility,
|
|
6390
|
+
accessRole: "owner" as const,
|
|
6391
|
+
canView: true,
|
|
6392
|
+
canEdit: true,
|
|
6393
|
+
canManage: true,
|
|
6394
|
+
createdAt: row.document.createdAt,
|
|
6395
|
+
updatedAt: row.document.updatedAt,
|
|
6396
|
+
},
|
|
6397
|
+
position: row.item.position,
|
|
6398
|
+
properties: [],
|
|
6399
|
+
bodyHydration: {
|
|
6400
|
+
status:
|
|
6401
|
+
row.item.bodyHydrationStatus === "pending" ||
|
|
6402
|
+
row.item.bodyHydrationStatus === "hydrating" ||
|
|
6403
|
+
row.item.bodyHydrationStatus === "hydrated" ||
|
|
6404
|
+
row.item.bodyHydrationStatus === "unavailable" ||
|
|
6405
|
+
row.item.bodyHydrationStatus === "error"
|
|
6406
|
+
? row.item.bodyHydrationStatus
|
|
6407
|
+
: "hydrated",
|
|
6408
|
+
attemptedAt: row.item.bodyHydrationAttemptedAt,
|
|
6409
|
+
error: row.item.bodyHydrationError,
|
|
6410
|
+
version: row.item.bodyHydrationVersion,
|
|
6411
|
+
},
|
|
6412
|
+
},
|
|
6413
|
+
];
|
|
6414
|
+
},
|
|
6415
|
+
),
|
|
6416
|
+
];
|
|
6417
|
+
if (!args.sourceId) {
|
|
6418
|
+
throw new Error("Builder imports require a source ID.");
|
|
6419
|
+
}
|
|
6420
|
+
const importedSourceRows = mockSourceRowsForSeed({
|
|
6421
|
+
sourceId: args.sourceId,
|
|
6422
|
+
ownerEmail: args.database.ownerEmail,
|
|
6423
|
+
sourceType: "builder-cms",
|
|
6424
|
+
sourceTable: args.sourceTable,
|
|
6425
|
+
items: sourceSeedItems,
|
|
6426
|
+
now: args.now,
|
|
6427
|
+
builderEntriesByDocumentId: importedEntriesByDocumentId,
|
|
6428
|
+
});
|
|
6263
6429
|
const insertedItemIds = new Set<string>();
|
|
6264
6430
|
await db.transaction(async (tx) => {
|
|
6265
6431
|
for (const chunk of chunks(
|
|
@@ -6284,6 +6450,11 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
|
|
|
6284
6450
|
insertedItemIds.add(item.id);
|
|
6285
6451
|
}
|
|
6286
6452
|
}
|
|
6453
|
+
await lockDatabaseMemberships(
|
|
6454
|
+
tx,
|
|
6455
|
+
importedSourceRows.map((row) => row.databaseItemId),
|
|
6456
|
+
);
|
|
6457
|
+
await insertMockSourceRows(tx, importedSourceRows, args.now);
|
|
6287
6458
|
await ensureDocumentsFilesMembership(
|
|
6288
6459
|
tx,
|
|
6289
6460
|
documentRows.map((row) => row.id),
|
|
@@ -6292,9 +6463,6 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
|
|
|
6292
6463
|
);
|
|
6293
6464
|
});
|
|
6294
6465
|
|
|
6295
|
-
const candidateDocumentById = new Map(
|
|
6296
|
-
documentRows.map((document) => [document.id!, document]),
|
|
6297
|
-
);
|
|
6298
6466
|
const importedItems: ContentDatabaseItem[] = itemRows
|
|
6299
6467
|
.filter((item) => insertedItemIds.has(item.id!))
|
|
6300
6468
|
.map((item) => {
|
|
@@ -6474,6 +6642,7 @@ export async function resyncBuilderCmsSourceSnapshot(args: {
|
|
|
6474
6642
|
if (builderRead.state === "live") {
|
|
6475
6643
|
const importResult = await importBuilderCmsEntriesAsDatabaseItems({
|
|
6476
6644
|
database: args.database,
|
|
6645
|
+
sourceId: args.source.id,
|
|
6477
6646
|
entries: builderEntries,
|
|
6478
6647
|
now: args.now,
|
|
6479
6648
|
sourceTable: args.source.sourceTable,
|
|
@@ -6553,17 +6722,7 @@ export async function resyncBuilderCmsSourceSnapshot(args: {
|
|
|
6553
6722
|
);
|
|
6554
6723
|
const fetchedDocumentIds = itemsToLink.map((item) => item.document.id);
|
|
6555
6724
|
if (fetchedDocumentIds.length > 0) {
|
|
6556
|
-
|
|
6557
|
-
await db
|
|
6558
|
-
.delete(schema.contentDatabaseSourceRows)
|
|
6559
|
-
.where(
|
|
6560
|
-
and(
|
|
6561
|
-
eq(schema.contentDatabaseSourceRows.sourceId, args.source.id),
|
|
6562
|
-
inArray(schema.contentDatabaseSourceRows.documentId, idChunk),
|
|
6563
|
-
),
|
|
6564
|
-
);
|
|
6565
|
-
}
|
|
6566
|
-
await seedMockSourceRows({
|
|
6725
|
+
await replaceMockSourceRows({
|
|
6567
6726
|
sourceId: args.source.id,
|
|
6568
6727
|
ownerEmail: args.database.ownerEmail,
|
|
6569
6728
|
sourceType: "builder-cms",
|
|
@@ -6572,6 +6731,7 @@ export async function resyncBuilderCmsSourceSnapshot(args: {
|
|
|
6572
6731
|
now: args.now,
|
|
6573
6732
|
existingBuilderRows,
|
|
6574
6733
|
builderEntriesByDocumentId,
|
|
6734
|
+
documentIds: fetchedDocumentIds,
|
|
6575
6735
|
});
|
|
6576
6736
|
const refreshedFields = await db
|
|
6577
6737
|
.select()
|
|
@@ -6601,18 +6761,25 @@ export async function resyncBuilderCmsSourceSnapshot(args: {
|
|
|
6601
6761
|
.select({
|
|
6602
6762
|
id: schema.contentDatabaseSourceRows.id,
|
|
6603
6763
|
sourceRowId: schema.contentDatabaseSourceRows.sourceRowId,
|
|
6764
|
+
databaseItemId: schema.contentDatabaseSourceRows.databaseItemId,
|
|
6604
6765
|
})
|
|
6605
6766
|
.from(schema.contentDatabaseSourceRows)
|
|
6606
6767
|
.where(eq(schema.contentDatabaseSourceRows.sourceId, args.source.id))
|
|
6607
6768
|
).filter((row) => !activeSourceRowIds.has(row.sourceRowId));
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
.
|
|
6615
|
-
|
|
6769
|
+
await db.transaction(async (tx) => {
|
|
6770
|
+
await lockDatabaseMemberships(
|
|
6771
|
+
tx,
|
|
6772
|
+
staleRows.map((row) => row.databaseItemId).filter(Boolean),
|
|
6773
|
+
);
|
|
6774
|
+
for (const idChunk of chunks(
|
|
6775
|
+
staleRows.map((row) => row.id),
|
|
6776
|
+
idChunkSize(),
|
|
6777
|
+
)) {
|
|
6778
|
+
await tx
|
|
6779
|
+
.delete(schema.contentDatabaseSourceRows)
|
|
6780
|
+
.where(inArray(schema.contentDatabaseSourceRows.id, idChunk));
|
|
6781
|
+
}
|
|
6782
|
+
});
|
|
6616
6783
|
}
|
|
6617
6784
|
|
|
6618
6785
|
await updateBuilderCmsSourceReadMetadata({
|
|
@@ -6644,10 +6811,6 @@ export async function resyncBuilderCmsSourceSnapshot(args: {
|
|
|
6644
6811
|
.delete(schema.contentDatabaseSourceFields)
|
|
6645
6812
|
.where(eq(schema.contentDatabaseSourceFields.sourceId, args.source.id));
|
|
6646
6813
|
}
|
|
6647
|
-
await db
|
|
6648
|
-
.delete(schema.contentDatabaseSourceRows)
|
|
6649
|
-
.where(eq(schema.contentDatabaseSourceRows.sourceId, args.source.id));
|
|
6650
|
-
|
|
6651
6814
|
if (shouldReseedSourceFields) {
|
|
6652
6815
|
await seedMockSourceFields({
|
|
6653
6816
|
sourceId: args.source.id,
|
|
@@ -6682,7 +6845,7 @@ export async function resyncBuilderCmsSourceSnapshot(args: {
|
|
|
6682
6845
|
: existingBuilderRows.has(item.document.id),
|
|
6683
6846
|
)
|
|
6684
6847
|
: response.items;
|
|
6685
|
-
await
|
|
6848
|
+
await replaceMockSourceRows({
|
|
6686
6849
|
sourceId: args.source.id,
|
|
6687
6850
|
ownerEmail: args.database.ownerEmail,
|
|
6688
6851
|
sourceType: "builder-cms",
|
|
@@ -6827,9 +6990,6 @@ export async function replaceSourceMetadata(args: {
|
|
|
6827
6990
|
await db
|
|
6828
6991
|
.delete(schema.contentDatabaseSourceFields)
|
|
6829
6992
|
.where(eq(schema.contentDatabaseSourceFields.sourceId, args.source.id));
|
|
6830
|
-
await db
|
|
6831
|
-
.delete(schema.contentDatabaseSourceRows)
|
|
6832
|
-
.where(eq(schema.contentDatabaseSourceRows.sourceId, args.source.id));
|
|
6833
6993
|
}
|
|
6834
6994
|
|
|
6835
6995
|
if (args.source) {
|
|
@@ -191,11 +191,11 @@ async function contentDatabaseTableQueryMode(
|
|
|
191
191
|
return usesSecondaryField ? "client-required" : "server";
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
function canManageRole(role: string) {
|
|
194
|
+
function canManageRole(role: string | undefined) {
|
|
195
195
|
return role === "owner" || role === "admin";
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
function canEditRole(role: string) {
|
|
198
|
+
function canEditRole(role: string | undefined) {
|
|
199
199
|
return role === "owner" || role === "admin" || role === "editor";
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -399,7 +399,15 @@ function serializeDocument(
|
|
|
399
399
|
const isOwner =
|
|
400
400
|
doc.ownerEmail.trim().toLowerCase() ===
|
|
401
401
|
getRequestUserEmail()?.trim().toLowerCase();
|
|
402
|
-
const
|
|
402
|
+
const hasVisibilityAccess =
|
|
403
|
+
doc.visibility === "public" ||
|
|
404
|
+
(doc.visibility === "org" &&
|
|
405
|
+
!!doc.orgId &&
|
|
406
|
+
doc.orgId === getRequestOrgId());
|
|
407
|
+
const canView = isOwner || hasVisibilityAccess || shareRole !== undefined;
|
|
408
|
+
const accessRole = isOwner
|
|
409
|
+
? ("owner" as const)
|
|
410
|
+
: (shareRole ?? (hasVisibilityAccess ? ("viewer" as const) : undefined));
|
|
403
411
|
return {
|
|
404
412
|
id: doc.id,
|
|
405
413
|
parentId: doc.parentId,
|
|
@@ -414,6 +422,7 @@ function serializeDocument(
|
|
|
414
422
|
hideFromSearch: parseDocumentHideFromSearch(doc.hideFromSearch),
|
|
415
423
|
visibility: doc.visibility,
|
|
416
424
|
accessRole,
|
|
425
|
+
canView,
|
|
417
426
|
canEdit: canEditRole(accessRole),
|
|
418
427
|
canManage: canManageRole(accessRole),
|
|
419
428
|
databaseMembership: membership
|