Files
simstudioai--sim/apps/sim/tools/google_drive/utils.ts
T
wehub-resource-sync d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

273 lines
7.0 KiB
TypeScript

// All available file metadata fields from Google Drive API v3
export const ALL_FILE_FIELDS = [
// Basic Info
'id',
'name',
'mimeType',
'kind',
'description',
'originalFilename',
'fullFileExtension',
'fileExtension',
// Ownership & Sharing
'owners',
'permissions',
'permissionIds',
'shared',
'ownedByMe',
'writersCanShare',
'viewersCanCopyContent',
'copyRequiresWriterPermission',
'sharingUser',
// Labels/Tags
'starred',
'trashed',
'explicitlyTrashed',
'properties',
'appProperties',
'folderColorRgb',
// Timestamps
'createdTime',
'modifiedTime',
'modifiedByMeTime',
'viewedByMeTime',
'sharedWithMeTime',
'trashedTime',
// User Info
'lastModifyingUser',
'trashingUser',
'viewedByMe',
'modifiedByMe',
// Links
'webViewLink',
'webContentLink',
'iconLink',
'thumbnailLink',
'exportLinks',
// Size & Storage
'size',
'quotaBytesUsed',
// Checksums
'md5Checksum',
'sha1Checksum',
'sha256Checksum',
// Hierarchy & Location
'parents',
'spaces',
'driveId',
'teamDriveId',
// Capabilities
'capabilities',
// Versions
'version',
'headRevisionId',
// Media Metadata
'hasThumbnail',
'thumbnailVersion',
'imageMediaMetadata',
'videoMediaMetadata',
'contentHints',
// Other
'isAppAuthorized',
'contentRestrictions',
'resourceKey',
'shortcutDetails',
'linkShareMetadata',
'labelInfo',
'hasAugmentedPermissions',
'inheritedPermissionsDisabled',
'downloadRestrictions',
].join(',')
// All revision fields from Google Drive API v3
export const ALL_REVISION_FIELDS = [
'id',
'mimeType',
'modifiedTime',
'keepForever',
'published',
'publishAuto',
'publishedLink',
'publishedOutsideDomain',
'lastModifyingUser',
'originalFilename',
'md5Checksum',
'size',
'exportLinks',
'kind',
].join(',')
/** All reply fields requested from the Google Drive API v3. */
const ALL_REPLY_FIELDS = [
'id',
'kind',
'createdTime',
'modifiedTime',
'author',
'htmlContent',
'content',
'deleted',
'action',
].join(',')
/** All comment fields requested from the Google Drive API v3. */
export const ALL_COMMENT_FIELDS = [
'id',
'kind',
'createdTime',
'modifiedTime',
'author',
'htmlContent',
'content',
'deleted',
'resolved',
'anchor',
'quotedFileContent',
`replies(${ALL_REPLY_FIELDS})`,
].join(',')
/**
* Maximum bytes accepted when exporting a Google Workspace file.
* Mirrors Google's own 10 MB export ceiling and keeps memory bounded.
*/
export const MAX_EXPORT_BYTES = 10 * 1024 * 1024
export const GOOGLE_WORKSPACE_MIME_TYPES = [
'application/vnd.google-apps.document', // Google Docs
'application/vnd.google-apps.spreadsheet', // Google Sheets
'application/vnd.google-apps.presentation', // Google Slides
'application/vnd.google-apps.drawing', // Google Drawings
'application/vnd.google-apps.form', // Google Forms
'application/vnd.google-apps.script', // Google Apps Scripts
]
export const DEFAULT_EXPORT_FORMATS: Record<string, string> = {
'application/vnd.google-apps.document': 'text/plain',
'application/vnd.google-apps.spreadsheet': 'text/csv',
'application/vnd.google-apps.presentation': 'text/plain',
'application/vnd.google-apps.drawing': 'image/png',
'application/vnd.google-apps.form': 'application/zip',
'application/vnd.google-apps.script': 'application/vnd.google-apps.script+json',
}
/**
* Valid export formats per Google Workspace file type.
* See: https://developers.google.com/drive/api/guides/ref-export-formats
*/
export const VALID_EXPORT_FORMATS: Record<string, string[]> = {
'application/vnd.google-apps.document': [
'text/plain',
'text/html',
'application/pdf',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.oasis.opendocument.text',
'application/rtf',
'application/epub+zip',
'text/markdown',
],
'application/vnd.google-apps.spreadsheet': [
'text/csv',
'text/tab-separated-values',
'application/pdf',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.oasis.opendocument.spreadsheet',
'application/zip',
],
'application/vnd.google-apps.presentation': [
'text/plain',
'application/pdf',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/vnd.oasis.opendocument.presentation',
'image/jpeg',
'image/png',
'image/svg+xml',
],
'application/vnd.google-apps.drawing': [
'application/pdf',
'image/jpeg',
'image/png',
'image/svg+xml',
],
'application/vnd.google-apps.form': ['application/zip'],
'application/vnd.google-apps.script': ['application/vnd.google-apps.script+json'],
}
export const SOURCE_MIME_TYPES: Record<string, string> = {
'application/vnd.google-apps.document': 'text/plain',
'application/vnd.google-apps.spreadsheet': 'text/csv',
'application/vnd.google-apps.presentation': 'application/vnd.ms-powerpoint',
}
export function handleSheetsFormat(input: unknown): {
csv?: string
rowCount: number
columnCount: number
} {
let workingValue: unknown = input
if (typeof workingValue === 'string') {
try {
workingValue = JSON.parse(workingValue)
} catch (_error) {
const csvString = workingValue as string
return { csv: csvString, rowCount: 0, columnCount: 0 }
}
}
if (!Array.isArray(workingValue)) {
return { rowCount: 0, columnCount: 0 }
}
let table: unknown[] = workingValue
if (
table.length > 0 &&
typeof (table as any)[0] === 'object' &&
(table as any)[0] !== null &&
!Array.isArray((table as any)[0])
) {
const allKeys = new Set<string>()
;(table as any[]).forEach((obj) => {
if (obj && typeof obj === 'object') {
Object.keys(obj).forEach((key) => allKeys.add(key))
}
})
const headers = Array.from(allKeys)
const rows = (table as any[]).map((obj) => {
if (!obj || typeof obj !== 'object') {
return Array(headers.length).fill('')
}
return headers.map((key) => {
const value = (obj as Record<string, unknown>)[key]
if (value !== null && typeof value === 'object') {
return JSON.stringify(value)
}
return value === undefined ? '' : (value as any)
})
})
table = [headers, ...rows]
}
const escapeCell = (cell: unknown): string => {
if (cell === null || cell === undefined) return ''
const stringValue = String(cell)
const mustQuote = /[",\n\r]/.test(stringValue)
const doubledQuotes = stringValue.replace(/"/g, '""')
return mustQuote ? `"${doubledQuotes}"` : doubledQuotes
}
const rowsAsStrings = (table as unknown[]).map((row) => {
if (!Array.isArray(row)) {
return escapeCell(row)
}
return row.map((cell) => escapeCell(cell)).join(',')
})
const csv = rowsAsStrings.join('\r\n')
const rowCount = Array.isArray(table) ? (table as any[]).length : 0
const columnCount =
Array.isArray(table) && Array.isArray((table as any[])[0]) ? (table as any[])[0].length : 0
return { csv, rowCount, columnCount }
}