@opengeni/documents 0.2.64 → 0.2.69

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/google-drive.ts"],"sourcesContent":["import type { ScopedKnowledgeScope } from \"@opengeni/contracts\";\nimport type {\n GoogleDriveSelectedSource,\n GoogleDriveTargetScope,\n} from \"@opengeni/contracts/google-drive\";\n\nexport const GOOGLE_DRIVE_PROVIDER_KEY = \"google-drive\" as const;\nexport const GOOGLE_DRIVE_FOLDER_MIME_TYPE = \"application/vnd.google-apps.folder\" as const;\nexport const GOOGLE_DRIVE_SHORTCUT_MIME_TYPE = \"application/vnd.google-apps.shortcut\" as const;\n\nconst GOOGLE_DRIVE_NATIVE_MIME_PREFIX = \"application/vnd.google-apps.\";\nconst GOOGLE_DRIVE_MAX_ID_CHARS = 256;\nconst GOOGLE_DRIVE_MAX_NAME_CHARS = 1024;\nconst GOOGLE_DRIVE_MAX_MIME_CHARS = 256;\nconst GOOGLE_DRIVE_MAX_PAGE_TOKEN_CHARS = 4096;\nconst GOOGLE_DRIVE_MAX_PAGE_ITEMS = 100;\nconst GOOGLE_DRIVE_MAX_CHECKPOINT_FOLDERS = 2_000;\nconst GOOGLE_DRIVE_MAX_CHECKPOINT_BYTES = 2 * 1024 * 1024;\n\nconst GOOGLE_DRIVE_NATIVE_EXPORTS = new Map<string, { contentType: string; extension: string }>([\n [\n \"application/vnd.google-apps.document\",\n {\n contentType: \"application/pdf\",\n extension: \".pdf\",\n },\n ],\n [\n \"application/vnd.google-apps.spreadsheet\",\n {\n contentType: \"application/pdf\",\n extension: \".pdf\",\n },\n ],\n [\n \"application/vnd.google-apps.presentation\",\n {\n contentType: \"application/pdf\",\n extension: \".pdf\",\n },\n ],\n [\"application/vnd.google-apps.drawing\", { contentType: \"application/pdf\", extension: \".pdf\" }],\n]);\n\nconst DEPENDENCY_FREE_ORDINARY_CONTENT_TYPES = new Set([\n \"application/json\",\n \"application/pdf\",\n \"application/xml\",\n \"application/x-yaml\",\n \"application/yaml\",\n]);\n\nconst GENERIC_BINARY_CONTENT_TYPES = new Set([\"application/octet-stream\", \"binary/octet-stream\"]);\n\nconst DEPENDENCY_FREE_EXTENSION_CONTENT_TYPES = new Map([\n [\".csv\", \"text/csv\"],\n [\".htm\", \"text/html\"],\n [\".html\", \"text/html\"],\n [\".json\", \"application/json\"],\n [\".markdown\", \"text/markdown\"],\n [\".md\", \"text/markdown\"],\n [\".pdf\", \"application/pdf\"],\n [\".text\", \"text/plain\"],\n [\".tsv\", \"text/tab-separated-values\"],\n [\".txt\", \"text/plain\"],\n [\".xml\", \"application/xml\"],\n [\".yaml\", \"application/x-yaml\"],\n [\".yml\", \"application/x-yaml\"],\n]);\n\nexport type GoogleDriveKnowledgeSourceIdentity = {\n providerKey: typeof GOOGLE_DRIVE_PROVIDER_KEY;\n externalTenantId: string;\n externalSourceId: string;\n sourceKind: \"google-drive-my-drive\" | \"google-drive-shared-drive\" | \"google-drive-folder\";\n sourceUri: string;\n scope: ScopedKnowledgeScope;\n};\n\n/**\n * Normalized item metadata expected from a bounded Drive files.list adapter.\n * The adapter owns provider JSON validation; this planner owns traversal,\n * checkpointing, resource limits, stable identity, and transfer classification.\n */\nexport type GoogleDriveInventoryProviderItem = {\n id: string;\n name: string;\n mimeType: string;\n driveId: string | null;\n parents: string[];\n modifiedTime: string | null;\n createdTime: string | null;\n version: string | null;\n md5Checksum: string | null;\n size: string | null;\n webViewLink: string | null;\n trashed: boolean;\n};\n\nexport type GoogleDriveInventoryPage = {\n items: GoogleDriveInventoryProviderItem[];\n nextPageToken: string | null;\n incompleteSearch: boolean;\n};\n\nexport type GoogleDriveInventoryLimits = {\n /** Hard cumulative provider-item discovery limit for this checkpoint. */\n maxItems: number;\n /** Hard cumulative known-byte limit for ordinary file downloads. */\n maxKnownBytes: number;\n /** Hard cumulative Drive list request/cost limit for this checkpoint. */\n maxApiRequests: number;\n /** Wall-clock budget for one invocation; checkpoint counters remain cumulative. */\n maxElapsedMs: number;\n /** Per-file byte ceiling. Unknown/export sizes must be enforced again while streaming. */\n maxFileBytes: number;\n /** Cycle/graph explosion guard for traversed folders. */\n maxFolders: number;\n /** Requested Drive page size. */\n pageSize: number;\n};\n\nexport type GoogleDriveTransferSkipReason =\n | \"file_too_large\"\n | \"folder_limit\"\n | \"folder_loop\"\n | \"shortcut_unsupported\"\n | \"trashed\"\n | \"unsupported_file_type\"\n | \"unsupported_native_type\";\n\nexport type GoogleDriveTransferPlan =\n | { action: \"traverse\" }\n | {\n action: \"export\";\n contentType: string;\n filename: string;\n declaredBytes: null;\n }\n | {\n action: \"download\";\n contentType: string;\n filename: string;\n declaredBytes: string | null;\n }\n | { action: \"skip\"; reason: GoogleDriveTransferSkipReason };\n\nexport type GoogleDriveInventoryEntry = {\n externalObjectId: string;\n externalVersionId: string | null;\n sourceId: string;\n parentFolderId: string;\n driveId: string | null;\n title: string;\n mimeType: string;\n modifiedTime: string | null;\n createdTime: string | null;\n sourceUri: string;\n transfer: GoogleDriveTransferPlan;\n};\n\nexport type GoogleDriveInventoryIssue = {\n code: \"incomplete_search\" | \"invalid_page\" | \"provider_error\";\n folderId: string;\n providerCode: string | null;\n};\n\nexport type GoogleDriveInventoryStopReason =\n | \"api_request_limit\"\n | \"elapsed_time_limit\"\n | \"incomplete_search\"\n | \"item_limit\"\n | \"known_byte_limit\"\n | \"provider_error\";\n\nexport type GoogleDriveInventoryTotals = {\n itemCount: number;\n folderCount: number;\n plannedFileCount: number;\n skippedItemCount: number;\n exportFileCount: number;\n downloadFileCount: number;\n unknownSizeFileCount: number;\n apiRequestCount: number;\n knownBytes: string;\n};\n\ntype GoogleDriveInventoryFrame = {\n folderId: string;\n driveId: string | null;\n pageToken: string | null;\n loaded: boolean;\n bufferedItems: GoogleDriveInventoryProviderItem[];\n nextPageToken: string | null;\n};\n\nexport type GoogleDriveInventoryCheckpoint = {\n version: 2;\n googlePermissionId: string;\n externalTenantId: string;\n sourceId: string;\n sourceDriveId: string | null;\n scope: ScopedKnowledgeScope;\n pendingFolders: GoogleDriveInventoryFrame[];\n seenFolderIds: string[];\n totals: GoogleDriveInventoryTotals;\n};\n\nexport type GoogleDriveInventoryResult = {\n status: \"complete\" | \"paused\";\n stopReason: GoogleDriveInventoryStopReason | null;\n source: GoogleDriveKnowledgeSourceIdentity;\n entries: GoogleDriveInventoryEntry[];\n issues: GoogleDriveInventoryIssue[];\n totals: GoogleDriveInventoryTotals;\n run: GoogleDriveInventoryTotals & { elapsedMs: number };\n checkpoint: GoogleDriveInventoryCheckpoint | null;\n};\n\nexport type GoogleDriveListChildren = (input: {\n folderId: string;\n driveId: string | null;\n pageToken: string | null;\n pageSize: number;\n}) => Promise<GoogleDriveInventoryPage>;\n\nexport class GoogleDriveInventoryProviderError extends Error {\n constructor(readonly providerCode: string) {\n super(providerCode);\n this.name = \"GoogleDriveInventoryProviderError\";\n }\n}\n\nexport function googleDriveKnowledgeScope(\n targetScope: GoogleDriveTargetScope,\n workspaceId: string,\n initiatingSubjectId: string,\n): ScopedKnowledgeScope {\n const boundedWorkspaceId = boundedText(workspaceId, \"workspaceId\", 256);\n const boundedSubjectId = boundedText(initiatingSubjectId, \"initiatingSubjectId\", 1024);\n if (targetScope === \"organization\") {\n return { kind: \"organization\", workspaceId: null, subjectId: null };\n }\n if (targetScope === \"workspace\") {\n return { kind: \"workspace\", workspaceId: boundedWorkspaceId, subjectId: null };\n }\n // Google Drive connections are workspace-bound today. Preserve that boundary\n // for personal knowledge rather than silently widening it across workspaces.\n return {\n kind: \"personal\",\n workspaceId: boundedWorkspaceId,\n subjectId: boundedSubjectId,\n };\n}\n\nexport function googleDriveKnowledgeSourceIdentity(input: {\n googlePermissionId: string;\n source: Pick<GoogleDriveSelectedSource, \"id\" | \"driveId\" | \"targetScope\">;\n workspaceId: string;\n initiatingSubjectId: string;\n}): GoogleDriveKnowledgeSourceIdentity {\n const sourceId = driveId(input.source.id, \"source.id\");\n const externalTenantId = normalizedGooglePermissionId(input.googlePermissionId);\n const sourceDriveId = nullableDriveId(input.source.driveId, \"source.driveId\");\n return {\n providerKey: GOOGLE_DRIVE_PROVIDER_KEY,\n externalTenantId,\n externalSourceId: sourceId,\n sourceKind:\n sourceId === \"root\"\n ? \"google-drive-my-drive\"\n : sourceDriveId === sourceId\n ? \"google-drive-shared-drive\"\n : \"google-drive-folder\",\n sourceUri: googleDriveSourceUri(sourceId),\n scope: googleDriveKnowledgeScope(\n input.source.targetScope,\n input.workspaceId,\n input.initiatingSubjectId,\n ),\n };\n}\n\nexport function planGoogleDriveTransfer(\n item: GoogleDriveInventoryProviderItem,\n maxFileBytes: number,\n): GoogleDriveTransferPlan {\n const normalized = validatedProviderItem(item);\n const byteLimit = safePositiveInteger(maxFileBytes, \"maxFileBytes\");\n if (normalized.trashed) {\n return { action: \"skip\", reason: \"trashed\" };\n }\n if (normalized.mimeType === GOOGLE_DRIVE_FOLDER_MIME_TYPE) {\n return { action: \"traverse\" };\n }\n if (normalized.mimeType === GOOGLE_DRIVE_SHORTCUT_MIME_TYPE) {\n return { action: \"skip\", reason: \"shortcut_unsupported\" };\n }\n const nativeExport = GOOGLE_DRIVE_NATIVE_EXPORTS.get(normalized.mimeType);\n if (nativeExport) {\n return {\n action: \"export\",\n contentType: nativeExport.contentType,\n filename: exportedFilename(normalized.name, nativeExport.extension),\n declaredBytes: null,\n };\n }\n if (normalized.mimeType.startsWith(GOOGLE_DRIVE_NATIVE_MIME_PREFIX)) {\n return { action: \"skip\", reason: \"unsupported_native_type\" };\n }\n const declaredBytes = fileSize(normalized.size);\n if (declaredBytes !== null && declaredBytes > BigInt(byteLimit)) {\n return { action: \"skip\", reason: \"file_too_large\" };\n }\n const contentType = dependencyFreeOrdinaryContentType(normalized.name, normalized.mimeType);\n if (!contentType) {\n return { action: \"skip\", reason: \"unsupported_file_type\" };\n }\n return {\n action: \"download\",\n contentType,\n filename: safeFilename(normalized.name),\n declaredBytes: declaredBytes?.toString() ?? null,\n };\n}\n\nexport async function inventoryGoogleDriveSource(input: {\n googlePermissionId: string;\n source: GoogleDriveSelectedSource;\n workspaceId: string;\n initiatingSubjectId: string;\n limits: GoogleDriveInventoryLimits;\n listChildren: GoogleDriveListChildren;\n checkpoint?: GoogleDriveInventoryCheckpoint | null;\n now?: (() => number) | undefined;\n}): Promise<GoogleDriveInventoryResult> {\n const limits = validatedLimits(input.limits);\n const googlePermissionId = normalizedGooglePermissionId(input.googlePermissionId);\n const source = googleDriveKnowledgeSourceIdentity({\n googlePermissionId,\n source: input.source,\n workspaceId: input.workspaceId,\n initiatingSubjectId: input.initiatingSubjectId,\n });\n const checkpointIdentity: GoogleDriveInventoryCheckpointIdentity = {\n googlePermissionId,\n externalTenantId: source.externalTenantId,\n sourceId: source.externalSourceId,\n sourceDriveId: nullableDriveId(input.source.driveId, \"source.driveId\"),\n scope: source.scope,\n };\n const now = input.now ?? Date.now;\n const startedAt = now();\n const checkpoint = input.checkpoint\n ? validatedCheckpoint(input.checkpoint, checkpointIdentity, limits)\n : initialCheckpoint(checkpointIdentity);\n const initialTotals = cloneTotals(checkpoint.totals);\n const entries: GoogleDriveInventoryEntry[] = [];\n const issues: GoogleDriveInventoryIssue[] = [];\n let stopReason: GoogleDriveInventoryStopReason | null = null;\n\n while (checkpoint.pendingFolders.length > 0) {\n if (now() - startedAt >= limits.maxElapsedMs) {\n stopReason = \"elapsed_time_limit\";\n break;\n }\n const frame = checkpoint.pendingFolders[0]!;\n if (frame.loaded && frame.bufferedItems.length === 0) {\n if (frame.nextPageToken) {\n frame.pageToken = frame.nextPageToken;\n frame.nextPageToken = null;\n frame.loaded = false;\n } else {\n checkpoint.pendingFolders.shift();\n }\n continue;\n }\n if (checkpoint.totals.itemCount >= limits.maxItems) {\n stopReason = \"item_limit\";\n break;\n }\n\n if (!frame.loaded) {\n if (checkpoint.totals.apiRequestCount >= limits.maxApiRequests) {\n stopReason = \"api_request_limit\";\n break;\n }\n const remainingItems = limits.maxItems - checkpoint.totals.itemCount;\n const requestedPageSize = Math.min(limits.pageSize, remainingItems);\n let page: GoogleDriveInventoryPage;\n try {\n page = await input.listChildren({\n folderId: frame.folderId,\n driveId: frame.driveId,\n pageToken: frame.pageToken,\n pageSize: requestedPageSize,\n });\n } catch (error) {\n checkpoint.totals.apiRequestCount += 1;\n issues.push({\n code: \"provider_error\",\n folderId: frame.folderId,\n providerCode: providerErrorCode(error),\n });\n stopReason = \"provider_error\";\n break;\n }\n checkpoint.totals.apiRequestCount += 1;\n if (!validPage(page, requestedPageSize)) {\n issues.push({ code: \"invalid_page\", folderId: frame.folderId, providerCode: null });\n stopReason = \"provider_error\";\n break;\n }\n if (page.incompleteSearch) {\n issues.push({ code: \"incomplete_search\", folderId: frame.folderId, providerCode: null });\n stopReason = \"incomplete_search\";\n break;\n }\n frame.loaded = true;\n frame.bufferedItems = page.items.map(validatedProviderItem);\n frame.nextPageToken = page.nextPageToken;\n if (now() - startedAt >= limits.maxElapsedMs) {\n stopReason = \"elapsed_time_limit\";\n break;\n }\n }\n\n if (frame.bufferedItems.length === 0) {\n if (frame.nextPageToken) {\n frame.pageToken = frame.nextPageToken;\n frame.nextPageToken = null;\n frame.loaded = false;\n } else {\n checkpoint.pendingFolders.shift();\n }\n continue;\n }\n\n const item = validatedProviderItem(frame.bufferedItems[0]!);\n let transfer = planGoogleDriveTransfer(item, limits.maxFileBytes);\n if (transfer.action === \"download\" && transfer.declaredBytes !== null) {\n const nextKnownBytes = BigInt(checkpoint.totals.knownBytes) + BigInt(transfer.declaredBytes);\n if (nextKnownBytes > BigInt(limits.maxKnownBytes)) {\n stopReason = \"known_byte_limit\";\n break;\n }\n }\n\n frame.bufferedItems.shift();\n checkpoint.totals.itemCount += 1;\n const effectiveDriveId = item.driveId ?? frame.driveId;\n if (transfer.action === \"traverse\") {\n if (checkpoint.seenFolderIds.includes(item.id)) {\n transfer = { action: \"skip\", reason: \"folder_loop\" };\n } else if (checkpoint.seenFolderIds.length >= limits.maxFolders) {\n transfer = { action: \"skip\", reason: \"folder_limit\" };\n } else {\n checkpoint.seenFolderIds.push(item.id);\n checkpoint.totals.folderCount += 1;\n checkpoint.pendingFolders.push({\n folderId: item.id,\n driveId: effectiveDriveId,\n pageToken: null,\n loaded: false,\n bufferedItems: [],\n nextPageToken: null,\n });\n }\n }\n\n if (transfer.action === \"skip\") {\n checkpoint.totals.skippedItemCount += 1;\n } else if (transfer.action === \"download\") {\n checkpoint.totals.plannedFileCount += 1;\n checkpoint.totals.downloadFileCount += 1;\n if (transfer.declaredBytes === null) {\n checkpoint.totals.unknownSizeFileCount += 1;\n } else {\n checkpoint.totals.knownBytes = (\n BigInt(checkpoint.totals.knownBytes) + BigInt(transfer.declaredBytes)\n ).toString();\n }\n } else if (transfer.action === \"export\") {\n checkpoint.totals.plannedFileCount += 1;\n checkpoint.totals.exportFileCount += 1;\n checkpoint.totals.unknownSizeFileCount += 1;\n }\n\n entries.push({\n externalObjectId: item.id,\n externalVersionId: item.version ?? item.md5Checksum ?? item.modifiedTime,\n sourceId: source.externalSourceId,\n parentFolderId: frame.folderId,\n driveId: effectiveDriveId,\n title: item.name,\n mimeType: item.mimeType,\n modifiedTime: item.modifiedTime,\n createdTime: item.createdTime,\n sourceUri: item.webViewLink ?? googleDriveFileUri(item.id),\n transfer,\n });\n }\n\n const elapsedMs = Math.max(0, now() - startedAt);\n const complete = checkpoint.pendingFolders.length === 0;\n const outputCheckpoint = complete ? null : cloneCheckpoint(checkpoint);\n if (outputCheckpoint) assertCheckpointBytes(outputCheckpoint);\n return {\n status: complete ? \"complete\" : \"paused\",\n stopReason: complete ? null : stopReason,\n source,\n entries,\n issues,\n totals: cloneTotals(checkpoint.totals),\n run: {\n ...subtractTotals(checkpoint.totals, initialTotals),\n elapsedMs,\n },\n checkpoint: outputCheckpoint,\n };\n}\n\ntype GoogleDriveInventoryCheckpointIdentity = Pick<\n GoogleDriveInventoryCheckpoint,\n \"googlePermissionId\" | \"externalTenantId\" | \"sourceId\" | \"sourceDriveId\" | \"scope\"\n>;\n\nfunction initialCheckpoint(\n identity: GoogleDriveInventoryCheckpointIdentity,\n): GoogleDriveInventoryCheckpoint {\n return {\n version: 2,\n googlePermissionId: identity.googlePermissionId,\n externalTenantId: identity.externalTenantId,\n sourceId: identity.sourceId,\n sourceDriveId: identity.sourceDriveId,\n scope: cloneScope(identity.scope),\n pendingFolders: [\n {\n folderId: identity.sourceId,\n driveId: identity.sourceDriveId,\n pageToken: null,\n loaded: false,\n bufferedItems: [],\n nextPageToken: null,\n },\n ],\n seenFolderIds: [identity.sourceId],\n totals: emptyTotals(),\n };\n}\n\nfunction validatedCheckpoint(\n value: GoogleDriveInventoryCheckpoint,\n identity: GoogleDriveInventoryCheckpointIdentity,\n limits: GoogleDriveInventoryLimits,\n): GoogleDriveInventoryCheckpoint {\n if (!value || typeof value !== \"object\" || value.version !== 2) {\n throw new Error(\"unsupported Google Drive inventory checkpoint\");\n }\n if (\n value.googlePermissionId !== identity.googlePermissionId ||\n value.externalTenantId !== identity.externalTenantId ||\n value.sourceId !== identity.sourceId ||\n value.sourceDriveId !== identity.sourceDriveId ||\n !sameScope(value.scope, identity.scope)\n ) {\n throw new Error(\"Google Drive inventory checkpoint does not match the selected source\");\n }\n const checkpoint = cloneCheckpoint(value);\n if (checkpoint.pendingFolders.length === 0) {\n throw new Error(\"Google Drive inventory checkpoint is already complete\");\n }\n if (\n checkpoint.pendingFolders.length > GOOGLE_DRIVE_MAX_CHECKPOINT_FOLDERS ||\n checkpoint.seenFolderIds.length > GOOGLE_DRIVE_MAX_CHECKPOINT_FOLDERS ||\n checkpoint.seenFolderIds.length > limits.maxFolders\n ) {\n throw new Error(\"Google Drive inventory checkpoint exceeds the folder limit\");\n }\n if (!checkpoint.seenFolderIds.includes(identity.sourceId)) {\n throw new Error(\"Google Drive inventory checkpoint lost its source boundary\");\n }\n if (new Set(checkpoint.seenFolderIds).size !== checkpoint.seenFolderIds.length) {\n throw new Error(\"Google Drive inventory checkpoint contains duplicate folder identity\");\n }\n for (const folderId of checkpoint.seenFolderIds) driveId(folderId, \"checkpoint.folderId\");\n const pendingFolderIds = new Set<string>();\n for (const frame of checkpoint.pendingFolders) {\n driveId(frame.folderId, \"checkpoint.pending.folderId\");\n if (\n !checkpoint.seenFolderIds.includes(frame.folderId) ||\n pendingFolderIds.has(frame.folderId)\n ) {\n throw new Error(\"Google Drive inventory checkpoint contains an invalid pending folder\");\n }\n pendingFolderIds.add(frame.folderId);\n nullableDriveId(frame.driveId, \"checkpoint.pending.driveId\");\n pageToken(frame.pageToken, \"checkpoint.pending.pageToken\");\n pageToken(frame.nextPageToken, \"checkpoint.pending.nextPageToken\");\n if (\n typeof frame.loaded !== \"boolean\" ||\n frame.bufferedItems.length > GOOGLE_DRIVE_MAX_PAGE_ITEMS\n ) {\n throw new Error(\"Google Drive inventory checkpoint contains an invalid page frame\");\n }\n if (!frame.loaded && (frame.bufferedItems.length > 0 || frame.nextPageToken !== null)) {\n throw new Error(\"Google Drive inventory checkpoint contains an uncommitted page frame\");\n }\n frame.bufferedItems = frame.bufferedItems.map(validatedProviderItem);\n }\n validatedTotals(checkpoint.totals);\n if (\n checkpoint.totals.folderCount !== checkpoint.seenFolderIds.length ||\n checkpoint.totals.plannedFileCount !==\n checkpoint.totals.exportFileCount + checkpoint.totals.downloadFileCount ||\n checkpoint.totals.unknownSizeFileCount > checkpoint.totals.plannedFileCount ||\n checkpoint.totals.itemCount !==\n checkpoint.totals.skippedItemCount +\n checkpoint.totals.plannedFileCount +\n checkpoint.totals.folderCount -\n 1\n ) {\n throw new Error(\"Google Drive inventory checkpoint totals are inconsistent\");\n }\n if (\n checkpoint.totals.itemCount > limits.maxItems ||\n checkpoint.totals.apiRequestCount > limits.maxApiRequests ||\n BigInt(checkpoint.totals.knownBytes) > BigInt(limits.maxKnownBytes)\n ) {\n throw new Error(\"Google Drive inventory checkpoint exceeds the supplied limits\");\n }\n assertCheckpointBytes(checkpoint);\n return checkpoint;\n}\n\nfunction validatedLimits(value: GoogleDriveInventoryLimits): GoogleDriveInventoryLimits {\n const limits = {\n maxItems: safePositiveInteger(value.maxItems, \"limits.maxItems\"),\n maxKnownBytes: safePositiveInteger(value.maxKnownBytes, \"limits.maxKnownBytes\"),\n maxApiRequests: safePositiveInteger(value.maxApiRequests, \"limits.maxApiRequests\"),\n maxElapsedMs: safePositiveInteger(value.maxElapsedMs, \"limits.maxElapsedMs\"),\n maxFileBytes: safePositiveInteger(value.maxFileBytes, \"limits.maxFileBytes\"),\n maxFolders: safePositiveInteger(value.maxFolders, \"limits.maxFolders\"),\n pageSize: safePositiveInteger(value.pageSize, \"limits.pageSize\"),\n };\n if (limits.pageSize > GOOGLE_DRIVE_MAX_PAGE_ITEMS) {\n throw new Error(`limits.pageSize must be <= ${GOOGLE_DRIVE_MAX_PAGE_ITEMS}`);\n }\n if (limits.maxFolders > GOOGLE_DRIVE_MAX_CHECKPOINT_FOLDERS) {\n throw new Error(`limits.maxFolders must be <= ${GOOGLE_DRIVE_MAX_CHECKPOINT_FOLDERS}`);\n }\n return limits;\n}\n\nfunction validPage(value: GoogleDriveInventoryPage, expectedMaxItems: number): boolean {\n if (\n !value ||\n !Array.isArray(value.items) ||\n value.items.length > expectedMaxItems ||\n value.items.length > GOOGLE_DRIVE_MAX_PAGE_ITEMS\n ) {\n return false;\n }\n try {\n pageToken(value.nextPageToken, \"page.nextPageToken\");\n value.items.forEach(validatedProviderItem);\n return typeof value.incompleteSearch === \"boolean\";\n } catch {\n return false;\n }\n}\n\nfunction validatedProviderItem(\n item: GoogleDriveInventoryProviderItem,\n): GoogleDriveInventoryProviderItem {\n const id = driveId(item.id, \"item.id\");\n const name = boundedText(item.name, \"item.name\", GOOGLE_DRIVE_MAX_NAME_CHARS);\n const mimeType = boundedText(item.mimeType, \"item.mimeType\", GOOGLE_DRIVE_MAX_MIME_CHARS);\n const parents = Array.isArray(item.parents)\n ? item.parents.map((parent) => driveId(parent, \"item.parent\"))\n : [];\n if (parents.length > 100) throw new Error(\"item.parents exceeds the supported bound\");\n return {\n id,\n name,\n mimeType,\n driveId: nullableDriveId(item.driveId, \"item.driveId\"),\n parents,\n modifiedTime: nullableBoundedText(item.modifiedTime, \"item.modifiedTime\", 128),\n createdTime: nullableBoundedText(item.createdTime, \"item.createdTime\", 128),\n version: nullableBoundedText(item.version, \"item.version\", 256),\n md5Checksum: nullableBoundedText(item.md5Checksum, \"item.md5Checksum\", 128),\n size: fileSize(item.size)?.toString() ?? null,\n webViewLink: nullableHttpsUrl(item.webViewLink, \"item.webViewLink\"),\n trashed: item.trashed === true,\n };\n}\n\nfunction dependencyFreeOrdinaryContentType(name: string, mimeType: string): string | null {\n const normalizedMime = mimeType.trim().toLowerCase();\n if (normalizedMime.startsWith(\"text/\")) return normalizedMime;\n if (DEPENDENCY_FREE_ORDINARY_CONTENT_TYPES.has(normalizedMime)) return normalizedMime;\n if (!GENERIC_BINARY_CONTENT_TYPES.has(normalizedMime)) return null;\n const lowerName = name.toLowerCase();\n for (const [extension, contentType] of DEPENDENCY_FREE_EXTENSION_CONTENT_TYPES) {\n if (lowerName.endsWith(extension)) return contentType;\n }\n return null;\n}\n\nfunction exportedFilename(name: string, extension: string): string {\n const filename = safeFilename(name);\n return filename.toLowerCase().endsWith(extension) ? filename : `${filename}${extension}`;\n}\n\nfunction safeFilename(value: string): string {\n const cleaned = value\n .normalize(\"NFKC\")\n .replace(/[\\u0000-\\u001f\\u007f/\\\\]/gu, \" \")\n .replace(/\\s+/gu, \" \")\n .trim()\n .slice(0, 512);\n return cleaned || \"untitled\";\n}\n\nfunction googleDriveSourceUri(id: string): string {\n return id === \"root\"\n ? \"https://drive.google.com/drive/my-drive\"\n : `https://drive.google.com/drive/folders/${encodeURIComponent(id)}`;\n}\n\nfunction googleDriveFileUri(id: string): string {\n return `https://drive.google.com/open?id=${encodeURIComponent(id)}`;\n}\n\nfunction fileSize(value: string | null): bigint | null {\n if (value === null) return null;\n if (!/^\\d{1,40}$/u.test(value)) throw new Error(\"item.size is invalid\");\n return BigInt(value);\n}\n\nfunction providerErrorCode(error: unknown): string | null {\n if (!(error instanceof GoogleDriveInventoryProviderError)) return null;\n const normalized = error.providerCode.trim().toLowerCase();\n return /^[a-z0-9](?:[a-z0-9._-]{0,126}[a-z0-9])?$/u.test(normalized) ? normalized : null;\n}\n\nfunction driveId(value: string, label: string): string {\n const candidate = boundedText(value, label, GOOGLE_DRIVE_MAX_ID_CHARS);\n if (candidate === \"root\" || /^[A-Za-z0-9_-]+$/u.test(candidate)) return candidate;\n throw new Error(`${label} is invalid`);\n}\n\nfunction normalizedGooglePermissionId(value: string): string {\n return boundedText(value, \"googlePermissionId\", GOOGLE_DRIVE_MAX_ID_CHARS);\n}\n\nfunction nullableDriveId(value: string | null, label: string): string | null {\n return value === null ? null : driveId(value, label);\n}\n\nfunction pageToken(value: string | null, label: string): string | null {\n if (value === null) return null;\n return boundedText(value, label, GOOGLE_DRIVE_MAX_PAGE_TOKEN_CHARS);\n}\n\nfunction boundedText(value: string, label: string, maxChars: number): string {\n if (typeof value !== \"string\") throw new Error(`${label} must be a string`);\n const trimmed = value.trim();\n if (!trimmed || trimmed.length > maxChars || /[\\u0000-\\u001f\\u007f]/u.test(trimmed)) {\n throw new Error(`${label} is invalid`);\n }\n return trimmed;\n}\n\nfunction nullableBoundedText(value: string | null, label: string, maxChars: number): string | null {\n return value === null ? null : boundedText(value, label, maxChars);\n}\n\nfunction nullableHttpsUrl(value: string | null, label: string): string | null {\n if (value === null) return null;\n const bounded = boundedText(value, label, 4096);\n const parsed = new URL(bounded);\n if (parsed.protocol !== \"https:\") throw new Error(`${label} must use https`);\n return parsed.toString();\n}\n\nfunction safePositiveInteger(value: number, label: string): number {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new Error(`${label} must be a positive safe integer`);\n }\n return value;\n}\n\nfunction validatedTotals(totals: GoogleDriveInventoryTotals): void {\n for (const [key, value] of Object.entries(totals)) {\n if (key === \"knownBytes\") continue;\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n throw new Error(`checkpoint.totals.${key} is invalid`);\n }\n }\n if (!/^\\d+$/u.test(totals.knownBytes)) {\n throw new Error(\"checkpoint.totals.knownBytes is invalid\");\n }\n}\n\nfunction emptyTotals(): GoogleDriveInventoryTotals {\n return {\n itemCount: 0,\n folderCount: 1,\n plannedFileCount: 0,\n skippedItemCount: 0,\n exportFileCount: 0,\n downloadFileCount: 0,\n unknownSizeFileCount: 0,\n apiRequestCount: 0,\n knownBytes: \"0\",\n };\n}\n\nfunction cloneTotals(value: GoogleDriveInventoryTotals): GoogleDriveInventoryTotals {\n return { ...value };\n}\n\nfunction subtractTotals(\n value: GoogleDriveInventoryTotals,\n initial: GoogleDriveInventoryTotals,\n): GoogleDriveInventoryTotals {\n return {\n itemCount: value.itemCount - initial.itemCount,\n folderCount: value.folderCount - initial.folderCount,\n plannedFileCount: value.plannedFileCount - initial.plannedFileCount,\n skippedItemCount: value.skippedItemCount - initial.skippedItemCount,\n exportFileCount: value.exportFileCount - initial.exportFileCount,\n downloadFileCount: value.downloadFileCount - initial.downloadFileCount,\n unknownSizeFileCount: value.unknownSizeFileCount - initial.unknownSizeFileCount,\n apiRequestCount: value.apiRequestCount - initial.apiRequestCount,\n knownBytes: (BigInt(value.knownBytes) - BigInt(initial.knownBytes)).toString(),\n };\n}\n\nfunction cloneProviderItem(\n value: GoogleDriveInventoryProviderItem,\n): GoogleDriveInventoryProviderItem {\n return { ...value, parents: [...value.parents] };\n}\n\nfunction cloneScope(scope: ScopedKnowledgeScope): ScopedKnowledgeScope {\n return { ...scope };\n}\n\nfunction cloneCheckpoint(value: GoogleDriveInventoryCheckpoint): GoogleDriveInventoryCheckpoint {\n return {\n version: 2,\n googlePermissionId: value.googlePermissionId,\n externalTenantId: value.externalTenantId,\n sourceId: value.sourceId,\n sourceDriveId: value.sourceDriveId,\n scope: cloneScope(value.scope),\n pendingFolders: value.pendingFolders.map((frame) => ({\n ...frame,\n bufferedItems: frame.bufferedItems.map(cloneProviderItem),\n })),\n seenFolderIds: [...value.seenFolderIds],\n totals: cloneTotals(value.totals),\n };\n}\n\nfunction sameScope(\n left: ScopedKnowledgeScope | null | undefined,\n right: ScopedKnowledgeScope,\n): boolean {\n return (\n !!left &&\n typeof left === \"object\" &&\n left.kind === right.kind &&\n left.workspaceId === right.workspaceId &&\n left.subjectId === right.subjectId\n );\n}\n\nfunction assertCheckpointBytes(checkpoint: GoogleDriveInventoryCheckpoint): void {\n if (Buffer.byteLength(JSON.stringify(checkpoint), \"utf8\") > GOOGLE_DRIVE_MAX_CHECKPOINT_BYTES) {\n throw new Error(\"Google Drive inventory checkpoint exceeds the serialized byte limit\");\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -218,15 +218,26 @@ export declare function listDocumentBases(db: Database, workspaceId: string): Pr
218
218
  export declare function getDocumentInventory(db: Database, workspaceId: string, input: DocumentInventoryInput): Promise<DocumentInventory>;
219
219
  export declare function getDocumentBase(db: Database, workspaceId: string, baseId: string): Promise<DocumentBase | null>;
220
220
  /**
221
- * Find-or-create the workspace's Default base — where knowledge drops land
222
- * before configured curation files them elsewhere. Matched by name
223
- * (case-insensitive) so a user-created "Default" is adopted rather than
224
- * duplicated.
221
+ * Find-or-create the workspace's internal Default collection — where ordinary
222
+ * uploads can start and knowledge drops land before configured curation files
223
+ * them elsewhere. Matched by name (case-insensitive) so a user-created
224
+ * "Default" is adopted rather than duplicated.
225
225
  */
226
226
  export declare function ensureDefaultBase(db: Database, input: {
227
227
  accountId: string;
228
228
  workspaceId: string;
229
229
  }): Promise<DocumentBase>;
230
+ /**
231
+ * List a workspace's optional document collections after restoring the
232
+ * internal Default collection when it is missing. Keeping the ensure and list
233
+ * in the service layer gives every caller the same migration-free recovery
234
+ * behavior after an old writer, manual repair, or future collection-management
235
+ * path renames or removes Default.
236
+ */
237
+ export declare function listDocumentBasesEnsuringDefault(db: Database, input: {
238
+ accountId: string;
239
+ workspaceId: string;
240
+ }): Promise<DocumentBase[]>;
230
241
  export declare function addDocumentToBase(db: Database, input: AddDocumentRequest & {
231
242
  accountId: string;
232
243
  workspaceId: string;
package/dist/index.js CHANGED
@@ -492,6 +492,10 @@ async function ensureDefaultBase(db, input) {
492
492
  })
493
493
  );
494
494
  }
495
+ async function listDocumentBasesEnsuringDefault(db, input) {
496
+ await ensureDefaultBase(db, input);
497
+ return await listDocumentBases(db, input.workspaceId);
498
+ }
495
499
  async function addDocumentToBase(db, input) {
496
500
  return await withRlsContext(
497
501
  db,
@@ -1366,6 +1370,7 @@ export {
1366
1370
  heuristicCuration,
1367
1371
  indexDocumentNow,
1368
1372
  listDocumentBases,
1373
+ listDocumentBasesEnsuringDefault,
1369
1374
  listDocuments,
1370
1375
  moveDocumentToBase,
1371
1376
  parseCurationOutcome,