@kjerneverk/riotplan-cloud 1.0.0-dev.0
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/dist/index.d.ts +179 -0
- package/dist/index.js +1113 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/gcs-sync.ts","../src/runtime.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { readFile, mkdir, readdir, rm, stat, writeFile, rename } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\n\nexport interface GcsAuthConfig {\n projectId?: string;\n keyFilename?: string;\n credentialsJson?: string;\n}\n\nexport interface GcsBucketLocation {\n bucket: string;\n prefix?: string;\n}\n\nexport interface GcsSyncDownStats {\n bucket: string;\n prefix: string;\n localDirectory: string;\n remoteListedCount: number;\n remoteIncludedCount: number;\n changedCount: number;\n skippedUnchangedCount: number;\n downloadedCount: number;\n downloadedBytes: number;\n localScannedCount: number;\n removedCount: number;\n elapsedMs: number;\n phases: {\n mkdirMs: number;\n createClientMs: number;\n listRemoteMs: number;\n downloadMs: number;\n listLocalMs: number;\n cleanupMs: number;\n };\n}\n\nexport interface GcsSyncUpStats {\n bucket: string;\n prefix: string;\n localDirectory: string;\n localScannedCount: number;\n localIncludedCount: number;\n uploadedCount: number;\n remoteListedCount: number;\n removedRemoteCount: number;\n elapsedMs: number;\n phases: {\n mkdirMs: number;\n createClientMs: number;\n listLocalMs: number;\n uploadMs: number;\n listRemoteMs: number;\n cleanupMs: number;\n };\n}\n\ntype MirrorDebugEvent = (\n event: string,\n details: Record<string, unknown>\n) => void;\n\ntype StorageFile = {\n name: string;\n download: (options: { destination: string }) => Promise<void>;\n save?: (data: string | Buffer, options?: Record<string, unknown>) => Promise<void>;\n delete: (options?: { ignoreNotFound?: boolean }) => Promise<void>;\n getMetadata?: () => Promise<Array<Record<string, unknown>>>;\n metadata?: {\n md5Hash?: string;\n generation?: string;\n etag?: string;\n size?: number | string;\n updated?: string;\n };\n};\n\nexport interface SyncManifestObject {\n path: string;\n generation?: string;\n etag?: string;\n md5Hash?: string;\n size?: number;\n updatedAt?: string;\n localPath: string;\n lastSyncedAt: string;\n}\n\nexport interface SyncManifest {\n version: number;\n createdAt: string;\n updatedAt: string;\n objects: Record<string, SyncManifestObject>;\n}\n\nconst SYNC_MANIFEST_VERSION = 1;\nconst SYNC_MANIFEST_FILE = '.riotplan-sync-manifest.json';\nconst REMOTE_INDEX_SCHEMA_VERSION = 1;\nconst REMOTE_INDEX_FILE = '.riotplan-sync-index-v1.json';\nconst REMOTE_INDEX_CACHE_FILE = '.riotplan-remote-index-cache-v1.json';\nconst REMOTE_INDEX_DOWNLOAD_TMP = '.riotplan-remote-index-download.tmp.json';\n\nexport interface RemoteObjectState {\n path: string;\n generation?: string;\n etag?: string;\n md5Hash?: string;\n size?: number;\n updatedAt?: string;\n}\n\nexport function buildSyncDiff(\n remoteObjects: Record<string, RemoteObjectState>,\n manifestObjects: Record<string, SyncManifestObject> | undefined,\n localFiles: Set<string>\n): {\n added: string[];\n changed: string[];\n unchanged: string[];\n deletedLocal: string[];\n} {\n const added: string[] = [];\n const changed: string[] = [];\n const unchanged: string[] = [];\n const remotePaths = new Set(Object.keys(remoteObjects));\n\n for (const relativePath of remotePaths) {\n const remote = remoteObjects[relativePath];\n const localExists = localFiles.has(relativePath);\n const manifest = manifestObjects?.[relativePath];\n\n if (!localExists) {\n added.push(relativePath);\n continue;\n }\n if (!manifest) {\n changed.push(relativePath);\n continue;\n }\n\n const byGeneration =\n manifest.generation &&\n remote.generation &&\n manifest.generation === remote.generation;\n const byEtag = manifest.etag && remote.etag && manifest.etag === remote.etag;\n const byMd5 = manifest.md5Hash && remote.md5Hash && manifest.md5Hash === remote.md5Hash;\n\n if (byGeneration || byEtag || byMd5) {\n unchanged.push(relativePath);\n } else {\n changed.push(relativePath);\n }\n }\n\n const deletedLocal: string[] = [];\n for (const localRelative of localFiles) {\n if (!remotePaths.has(localRelative)) {\n deletedLocal.push(localRelative);\n }\n }\n\n return { added, changed, unchanged, deletedLocal };\n}\n\ntype BucketLike = {\n getFiles: (options?: { prefix?: string }) => Promise<[StorageFile[]]>;\n upload: (path: string, options: { destination: string }) => Promise<unknown>;\n file: (name: string) => StorageFile;\n};\n\ntype StorageLike = {\n bucket: (name: string) => BucketLike;\n};\n\nfunction isRetryableError(error: unknown): boolean {\n if (!error || typeof error !== 'object') return false;\n const code = (error as any).code;\n const message = String((error as any).message || '').toLowerCase();\n if (typeof code === 'number' && [408, 429, 500, 502, 503, 504].includes(code)) return true;\n if (typeof code === 'string' && ['ETIMEDOUT', 'ECONNRESET', 'EAI_AGAIN'].includes(code)) return true;\n return message.includes('timeout') || message.includes('temporar') || message.includes('rate');\n}\n\nasync function withRetry<T>(fn: () => Promise<T>, retries = 2): Promise<T> {\n let attempt = 0;\n let lastError: unknown;\n while (attempt <= retries) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n if (attempt >= retries || !isRetryableError(error)) {\n throw error;\n }\n const backoffMs = 100 * Math.pow(2, attempt);\n await new Promise((resolve) => setTimeout(resolve, backoffMs));\n }\n attempt += 1;\n }\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n}\n\nfunction normalizePrefix(prefix?: string): string {\n if (!prefix) {\n return '';\n }\n return prefix.replace(/^\\/+/, '').replace(/\\/+$/, '');\n}\n\nfunction toObjectName(prefix: string, relativePath: string): string {\n const normalizedRelative = relativePath.split('\\\\').join('/');\n return prefix ? `${prefix}/${normalizedRelative}` : normalizedRelative;\n}\n\nfunction toRelativePath(prefix: string, objectName: string): string {\n if (!prefix) {\n return objectName;\n }\n if (objectName.startsWith(`${prefix}/`)) {\n return objectName.slice(prefix.length + 1);\n }\n return objectName;\n}\n\nfunction isInternalSyncControlFile(relativePath: string): boolean {\n const normalized = relativePath.split('\\\\').join('/');\n const base = normalized.split('/').pop() || normalized;\n return (\n base === SYNC_MANIFEST_FILE\n || base === REMOTE_INDEX_FILE\n || base === REMOTE_INDEX_CACHE_FILE\n || base === REMOTE_INDEX_DOWNLOAD_TMP\n );\n}\n\ninterface RemoteSyncIndex {\n version: number;\n generatedAt: string;\n objects: Record<string, RemoteObjectState>;\n}\n\ninterface RemoteSyncIndexCache {\n version: number;\n indexObject: string;\n etag?: string;\n generation?: string;\n updatedAt?: string;\n objects: Record<string, RemoteObjectState>;\n}\n\nasync function loadRemoteSyncIndexCache(localDirectory: string): Promise<RemoteSyncIndexCache | null> {\n const cachePath = join(localDirectory, REMOTE_INDEX_CACHE_FILE);\n try {\n const raw = await readFile(cachePath, 'utf8');\n const parsed = JSON.parse(raw) as RemoteSyncIndexCache;\n if (\n !parsed\n || typeof parsed !== 'object'\n || parsed.version !== REMOTE_INDEX_SCHEMA_VERSION\n || typeof parsed.indexObject !== 'string'\n || !parsed.objects\n || typeof parsed.objects !== 'object'\n ) {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nasync function saveRemoteSyncIndexCache(localDirectory: string, cache: RemoteSyncIndexCache): Promise<void> {\n const path = join(localDirectory, REMOTE_INDEX_CACHE_FILE);\n const tempPath = `${path}.tmp`;\n await writeFile(tempPath, `${JSON.stringify(cache, null, 2)}\\n`, 'utf8');\n await rename(tempPath, path);\n}\n\nfunction metadataStringValue(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value : undefined;\n}\n\nfunction metadataNumberValue(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number.parseInt(value, 10);\n if (Number.isFinite(parsed)) {\n return parsed;\n }\n }\n return undefined;\n}\n\nfunction parseRemoteMetadata(metadata: Record<string, unknown> | undefined): {\n md5Hash?: string;\n generation?: string;\n etag?: string;\n size?: number;\n updatedAt?: string;\n} {\n return {\n md5Hash: metadataStringValue(metadata?.md5Hash),\n generation: metadataStringValue(metadata?.generation),\n etag: metadataStringValue(metadata?.etag),\n size: metadataNumberValue(metadata?.size),\n updatedAt: metadataStringValue(metadata?.updated),\n };\n}\n\nfunction normalizeRemoteIndexObjects(objects: unknown): Record<string, RemoteObjectState> {\n if (!objects || typeof objects !== 'object') {\n return {};\n }\n const normalized: Record<string, RemoteObjectState> = {};\n for (const [rawPath, rawState] of Object.entries(objects as Record<string, unknown>)) {\n const path = typeof rawPath === 'string' ? rawPath : '';\n if (!path || isInternalSyncControlFile(path)) {\n continue;\n }\n const state = rawState as Record<string, unknown>;\n normalized[path] = {\n path,\n generation: metadataStringValue(state?.generation),\n etag: metadataStringValue(state?.etag),\n md5Hash: metadataStringValue(state?.md5Hash),\n size: metadataNumberValue(state?.size),\n updatedAt: metadataStringValue(state?.updatedAt),\n };\n }\n return normalized;\n}\n\nasync function collectLocalFiles(rootDir: string): Promise<string[]> {\n const entries = await readdir(rootDir, { withFileTypes: true }).catch(() => []);\n const files: string[] = [];\n for (const entry of entries) {\n const fullPath = join(rootDir, entry.name);\n if (entry.isDirectory()) {\n const nested = await collectLocalFiles(fullPath);\n for (const child of nested) {\n files.push(join(entry.name, child));\n }\n continue;\n }\n files.push(entry.name);\n }\n return files;\n}\n\nasync function fileMd5Base64(path: string): Promise<string> {\n const buffer = await readFile(path);\n return createHash('md5').update(buffer).digest('base64');\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function resolveRemoteMd5(file: StorageFile): Promise<string | undefined> {\n if (file.metadata?.md5Hash) {\n return file.metadata.md5Hash;\n }\n if (typeof file.getMetadata === 'function') {\n try {\n const [metadata] = await file.getMetadata();\n const md5Hash = typeof metadata?.md5Hash === 'string' ? metadata.md5Hash : undefined;\n if (md5Hash) {\n file.metadata = { ...(file.metadata || {}), md5Hash };\n }\n return md5Hash;\n } catch {\n return undefined;\n }\n }\n return undefined;\n}\n\nasync function resolveRemoteMetadata(file: StorageFile): Promise<{\n md5Hash?: string;\n generation?: string;\n etag?: string;\n size?: number;\n updatedAt?: string;\n}> {\n const fromInline = parseRemoteMetadata(file.metadata as Record<string, unknown> | undefined);\n if (fromInline.md5Hash || fromInline.generation || fromInline.etag || fromInline.size !== undefined || fromInline.updatedAt) {\n return fromInline;\n }\n if (typeof file.getMetadata !== 'function') {\n return fromInline;\n }\n try {\n const [metadata] = await file.getMetadata();\n const parsed = parseRemoteMetadata(metadata);\n const md5Hash = parsed.md5Hash || file.metadata?.md5Hash;\n const generation = parsed.generation;\n const etag = parsed.etag;\n const size = parsed.size;\n const updatedAt = parsed.updatedAt;\n if (md5Hash) {\n file.metadata = { ...(file.metadata || {}), md5Hash };\n }\n return { md5Hash, generation, etag, size, updatedAt };\n } catch {\n return {\n md5Hash: file.metadata?.md5Hash,\n };\n }\n}\n\nasync function loadRemoteSyncIndex(\n bucket: BucketLike,\n prefix: string,\n localDirectory: string,\n onDebugEvent?: MirrorDebugEvent\n): Promise<{\n objects: Record<string, RemoteObjectState> | null;\n indexEtag?: string;\n indexGeneration?: string;\n usedCachedIndex: boolean;\n}> {\n const indexObject = toObjectName(prefix, REMOTE_INDEX_FILE);\n const remoteIndexFile = bucket.file(indexObject);\n if (!remoteIndexFile || typeof remoteIndexFile.getMetadata !== 'function') {\n return { objects: null, usedCachedIndex: false };\n }\n\n let metadata: Record<string, unknown> | undefined;\n try {\n const [resolved] = await withRetry(() => remoteIndexFile.getMetadata!());\n metadata = resolved;\n } catch (error: any) {\n if (error?.code === 404) {\n return { objects: null, usedCachedIndex: false };\n }\n onDebugEvent?.('sync_down.index.metadata_failed', {\n indexObject,\n error: error instanceof Error ? error.message : String(error),\n });\n return { objects: null, usedCachedIndex: false };\n }\n\n const indexEtag = metadataStringValue(metadata?.etag);\n const indexGeneration = metadataStringValue(metadata?.generation);\n const cache = await loadRemoteSyncIndexCache(localDirectory);\n if (\n cache\n && cache.indexObject === indexObject\n && (\n (indexEtag && cache.etag === indexEtag)\n || (indexGeneration && cache.generation === indexGeneration)\n )\n ) {\n onDebugEvent?.('sync_down.index.cache_hit', {\n indexObject,\n objectCount: Object.keys(cache.objects || {}).length,\n });\n return {\n objects: normalizeRemoteIndexObjects(cache.objects),\n indexEtag,\n indexGeneration,\n usedCachedIndex: true,\n };\n }\n\n const downloadPath = join(localDirectory, REMOTE_INDEX_DOWNLOAD_TMP);\n try {\n await withRetry(() => remoteIndexFile.download({ destination: downloadPath }));\n const raw = await readFile(downloadPath, 'utf8');\n const parsed = JSON.parse(raw) as Partial<RemoteSyncIndex>;\n if (parsed.version !== REMOTE_INDEX_SCHEMA_VERSION || !parsed.objects || typeof parsed.objects !== 'object') {\n onDebugEvent?.('sync_down.index.invalid_schema', {\n indexObject,\n version: parsed.version ?? null,\n });\n return { objects: null, indexEtag, indexGeneration, usedCachedIndex: false };\n }\n const normalizedObjects = normalizeRemoteIndexObjects(parsed.objects);\n await saveRemoteSyncIndexCache(localDirectory, {\n version: REMOTE_INDEX_SCHEMA_VERSION,\n indexObject,\n etag: indexEtag,\n generation: indexGeneration,\n updatedAt: metadataStringValue(metadata?.updated),\n objects: normalizedObjects,\n });\n onDebugEvent?.('sync_down.index.downloaded', {\n indexObject,\n objectCount: Object.keys(normalizedObjects).length,\n });\n return {\n objects: normalizedObjects,\n indexEtag,\n indexGeneration,\n usedCachedIndex: false,\n };\n } catch (error) {\n onDebugEvent?.('sync_down.index.download_failed', {\n indexObject,\n error: error instanceof Error ? error.message : String(error),\n });\n return { objects: null, indexEtag, indexGeneration, usedCachedIndex: false };\n } finally {\n await rm(downloadPath, { force: true }).catch(() => undefined);\n }\n}\n\nasync function writeRemoteSyncIndex(\n bucket: BucketLike,\n prefix: string,\n localDirectory: string,\n objects: Record<string, RemoteObjectState>,\n onDebugEvent?: MirrorDebugEvent\n): Promise<void> {\n const indexObject = toObjectName(prefix, REMOTE_INDEX_FILE);\n const tempPath = join(localDirectory, `${REMOTE_INDEX_FILE}.tmp`);\n const payload: RemoteSyncIndex = {\n version: REMOTE_INDEX_SCHEMA_VERSION,\n generatedAt: new Date().toISOString(),\n objects,\n };\n try {\n await writeFile(tempPath, `${JSON.stringify(payload, null, 2)}\\n`, 'utf8');\n await withRetry(() => bucket.upload(tempPath, { destination: indexObject }));\n onDebugEvent?.('sync_up.index.written', {\n indexObject,\n objectCount: Object.keys(objects).length,\n });\n } finally {\n await rm(tempPath, { force: true }).catch(() => undefined);\n }\n}\n\nexport async function loadSyncManifest(localDirectory: string): Promise<{\n manifest: SyncManifest | null;\n invalidated: boolean;\n}> {\n const manifestPath = join(localDirectory, SYNC_MANIFEST_FILE);\n try {\n const raw = await readFile(manifestPath, 'utf8');\n const parsed = JSON.parse(raw) as SyncManifest;\n if (!parsed || typeof parsed !== 'object' || parsed.version !== SYNC_MANIFEST_VERSION || !parsed.objects) {\n return { manifest: null, invalidated: true };\n }\n return { manifest: parsed, invalidated: false };\n } catch (error: any) {\n if (error?.code === 'ENOENT') {\n return { manifest: null, invalidated: false };\n }\n return { manifest: null, invalidated: true };\n }\n}\n\nexport async function writeSyncManifest(localDirectory: string, objects: Record<string, SyncManifestObject>): Promise<void> {\n const manifestPath = join(localDirectory, SYNC_MANIFEST_FILE);\n const tempManifestPath = `${manifestPath}.tmp`;\n const now = new Date().toISOString();\n const payload: SyncManifest = {\n version: SYNC_MANIFEST_VERSION,\n createdAt: now,\n updatedAt: now,\n objects,\n };\n await writeFile(tempManifestPath, `${JSON.stringify(payload, null, 2)}\\n`, 'utf8');\n await rename(tempManifestPath, manifestPath);\n}\n\nasync function createStorageClient(auth: GcsAuthConfig): Promise<StorageLike> {\n let credentials: Record<string, unknown> | undefined;\n if (auth.credentialsJson) {\n try {\n credentials = JSON.parse(auth.credentialsJson) as Record<string, unknown>;\n } catch (error) {\n throw new Error(`Invalid cloud.credentialsJson JSON: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // Dynamic import avoids pulling GCS SDK into browser-oriented bundle passes.\n const moduleName = '@google-cloud/storage';\n const storageModule = (await import(moduleName)) as {\n Storage: new (options: Record<string, unknown>) => StorageLike;\n };\n\n return new storageModule.Storage({\n projectId: auth.projectId,\n keyFilename: auth.keyFilename,\n credentials: credentials as any,\n });\n}\n\nexport class GcsMirror {\n private readonly auth: GcsAuthConfig;\n private readonly bucketName: string;\n private readonly prefix: string;\n private readonly localDirectory: string;\n private readonly includeFile: (relativePath: string) => boolean;\n private readonly incrementalSyncEnabled: boolean;\n private readonly onDebugEvent?: MirrorDebugEvent;\n\n constructor(options: {\n auth: GcsAuthConfig;\n location: GcsBucketLocation;\n localDirectory: string;\n includeFile?: (relativePath: string) => boolean;\n incrementalSyncEnabled?: boolean;\n onDebugEvent?: MirrorDebugEvent;\n }) {\n this.auth = options.auth;\n this.bucketName = options.location.bucket;\n this.prefix = normalizePrefix(options.location.prefix);\n this.localDirectory = resolve(options.localDirectory);\n this.includeFile = options.includeFile || (() => true);\n this.incrementalSyncEnabled = options.incrementalSyncEnabled !== false;\n this.onDebugEvent = options.onDebugEvent;\n }\n\n async syncDown(): Promise<GcsSyncDownStats> {\n const startedAt = Date.now();\n this.onDebugEvent?.('sync_down.start', {\n bucket: this.bucketName,\n prefix: this.prefix,\n localDirectory: this.localDirectory,\n });\n const mkdirStartedAt = Date.now();\n await mkdir(this.localDirectory, { recursive: true });\n const mkdirMs = Date.now() - mkdirStartedAt;\n this.onDebugEvent?.('sync_down.phase.mkdir', { elapsedMs: mkdirMs });\n\n const clientStartedAt = Date.now();\n const storage = await createStorageClient(this.auth);\n const createClientMs = Date.now() - clientStartedAt;\n this.onDebugEvent?.('sync_down.phase.create_client', { elapsedMs: createClientMs });\n const bucket = storage.bucket(this.bucketName);\n\n const listRemoteStartedAt = Date.now();\n const remoteIndex = await loadRemoteSyncIndex(bucket, this.prefix, this.localDirectory, this.onDebugEvent);\n let files: StorageFile[] = [];\n let usedRemoteIndex = false;\n if (remoteIndex.objects) {\n usedRemoteIndex = true;\n } else {\n [files] = await withRetry(() => bucket.getFiles({ prefix: this.prefix || undefined }));\n }\n const listRemoteMs = Date.now() - listRemoteStartedAt;\n this.onDebugEvent?.('sync_down.phase.list_remote', {\n elapsedMs: listRemoteMs,\n listedCount: usedRemoteIndex ? Object.keys(remoteIndex.objects || {}).length : files.length,\n source: usedRemoteIndex ? 'gcs-index' : 'bucket-list',\n usedCachedIndex: remoteIndex.usedCachedIndex,\n });\n\n const { manifest, invalidated } = this.incrementalSyncEnabled\n ? await loadSyncManifest(this.localDirectory)\n : { manifest: null, invalidated: false };\n if (invalidated) {\n this.onDebugEvent?.('sync_down.manifest.invalidated', {\n localDirectory: this.localDirectory,\n reason: 'unsupported_or_corrupt_manifest',\n });\n }\n\n const localFilesAtStart = await collectLocalFiles(this.localDirectory);\n const localTrackedAtStart = new Set(\n localFilesAtStart.filter((relativePath) => this.includeFile(relativePath))\n );\n const remoteStateByPath: Record<string, RemoteObjectState> = {};\n const remoteFileByPath = new Map<string, StorageFile>();\n if (usedRemoteIndex && remoteIndex.objects) {\n for (const [relativePath, objectState] of Object.entries(remoteIndex.objects)) {\n if (!relativePath || isInternalSyncControlFile(relativePath) || !this.includeFile(relativePath)) {\n continue;\n }\n remoteStateByPath[relativePath] = objectState;\n remoteFileByPath.set(relativePath, bucket.file(toObjectName(this.prefix, relativePath)));\n }\n } else {\n for (const file of files) {\n const objectName = file.name;\n if (objectName.endsWith('/')) {\n continue;\n }\n const relativePath = toRelativePath(this.prefix, objectName);\n if (!relativePath || isInternalSyncControlFile(relativePath) || !this.includeFile(relativePath)) {\n continue;\n }\n remoteFileByPath.set(relativePath, file);\n const remoteMeta = await resolveRemoteMetadata(file);\n remoteStateByPath[relativePath] = {\n path: relativePath,\n generation: remoteMeta.generation,\n etag: remoteMeta.etag,\n md5Hash: remoteMeta.md5Hash,\n size: remoteMeta.size,\n updatedAt: remoteMeta.updatedAt,\n };\n }\n }\n\n const remoteSet = new Set(Object.keys(remoteStateByPath));\n const remoteIncludedCount = remoteSet.size;\n let diff: ReturnType<typeof buildSyncDiff>;\n if (!this.incrementalSyncEnabled) {\n diff = {\n added: [...remoteSet],\n changed: [],\n unchanged: [],\n deletedLocal: [...localTrackedAtStart].filter((path) => !remoteSet.has(path)),\n };\n } else {\n try {\n diff = buildSyncDiff(remoteStateByPath, manifest?.objects, localTrackedAtStart);\n } catch (error) {\n this.onDebugEvent?.('sync_down.diff_recovery', {\n reason: error instanceof Error ? error.message : String(error),\n strategy: 'full_resync',\n });\n diff = {\n added: [],\n changed: [...remoteSet],\n unchanged: [],\n deletedLocal: [...localTrackedAtStart].filter((path) => !remoteSet.has(path)),\n };\n }\n }\n let changedCount = diff.added.length + diff.changed.length;\n let skippedUnchangedCount = diff.unchanged.length;\n let downloadedCount = 0;\n let downloadedBytes = 0;\n const manifestObjects: Record<string, SyncManifestObject> = {};\n const downloadStartedAt = Date.now();\n const downloadTargets = [...diff.added, ...diff.changed];\n for (const relativePath of downloadTargets) {\n const file = remoteFileByPath.get(relativePath);\n if (!file) {\n continue;\n }\n const localPath = join(this.localDirectory, relativePath);\n let shouldDownload = true;\n const remoteMeta = remoteStateByPath[relativePath];\n const existingManifestEntry = manifest?.objects?.[relativePath];\n const existsLocally = await fileExists(localPath);\n if (this.incrementalSyncEnabled && existsLocally && existingManifestEntry) {\n const unchangedByManifest =\n existingManifestEntry.generation &&\n remoteMeta?.generation &&\n existingManifestEntry.generation === remoteMeta.generation;\n if (unchangedByManifest) {\n shouldDownload = false;\n }\n }\n if (this.incrementalSyncEnabled && existsLocally && shouldDownload) {\n const remoteMd5 = remoteMeta?.md5Hash || (await resolveRemoteMd5(file));\n if (remoteMd5) {\n const localMd5 = await fileMd5Base64(localPath);\n shouldDownload = localMd5 !== remoteMd5;\n }\n }\n if (!shouldDownload) {\n skippedUnchangedCount += 1;\n changedCount -= 1;\n continue;\n }\n await mkdir(dirname(localPath), { recursive: true });\n const downloadFileStartedAt = Date.now();\n await withRetry(() => file.download({ destination: localPath }));\n const fileElapsedMs = Date.now() - downloadFileStartedAt;\n downloadedCount += 1;\n try {\n downloadedBytes += (await stat(localPath)).size;\n } catch {\n // best-effort metric, ignore stat failures\n }\n if (fileElapsedMs >= 250) {\n this.onDebugEvent?.('sync_down.file_download', {\n path: relativePath,\n elapsedMs: fileElapsedMs,\n });\n }\n manifestObjects[relativePath] = {\n path: relativePath,\n generation: remoteMeta?.generation,\n etag: remoteMeta?.etag,\n md5Hash: remoteMeta?.md5Hash,\n size: remoteMeta?.size,\n updatedAt: remoteMeta?.updatedAt,\n localPath: relativePath,\n lastSyncedAt: new Date().toISOString(),\n };\n }\n for (const relativePath of remoteSet) {\n if (!manifestObjects[relativePath] && manifest?.objects?.[relativePath]) {\n manifestObjects[relativePath] = {\n ...manifest.objects[relativePath],\n lastSyncedAt: new Date().toISOString(),\n };\n }\n }\n const downloadMs = Date.now() - downloadStartedAt;\n this.onDebugEvent?.('sync_down.phase.download', {\n elapsedMs: downloadMs,\n downloadedCount,\n includedCount: remoteIncludedCount,\n changedCount,\n skippedUnchangedCount,\n downloadedBytes,\n });\n\n const listLocalStartedAt = Date.now();\n const localFiles = await collectLocalFiles(this.localDirectory);\n const listLocalMs = Date.now() - listLocalStartedAt;\n this.onDebugEvent?.('sync_down.phase.list_local', { elapsedMs: listLocalMs, scannedCount: localFiles.length });\n\n const cleanupStartedAt = Date.now();\n let removedCount = 0;\n this.onDebugEvent?.('sync_down.gc.start', {\n localDirectory: this.localDirectory,\n deletedLocalCandidates: diff.deletedLocal.length,\n });\n for (const localRelative of diff.deletedLocal) {\n if (!remoteSet.has(localRelative)) {\n await rm(join(this.localDirectory, localRelative), { force: true });\n removedCount += 1;\n this.onDebugEvent?.('sync_down.gc.remove_local', {\n path: localRelative,\n });\n }\n }\n const cleanupMs = Date.now() - cleanupStartedAt;\n this.onDebugEvent?.('sync_down.gc.complete', {\n removedCount,\n elapsedMs: cleanupMs,\n });\n if (this.incrementalSyncEnabled) {\n const manifestWriteStartedAt = Date.now();\n await writeSyncManifest(this.localDirectory, manifestObjects);\n this.onDebugEvent?.('sync_down.manifest.write_complete', {\n objectCount: Object.keys(manifestObjects).length,\n elapsedMs: Date.now() - manifestWriteStartedAt,\n });\n }\n const elapsedMs = Date.now() - startedAt;\n const stats: GcsSyncDownStats = {\n bucket: this.bucketName,\n prefix: this.prefix,\n localDirectory: this.localDirectory,\n remoteListedCount: usedRemoteIndex ? remoteIncludedCount : files.length,\n remoteIncludedCount,\n changedCount,\n skippedUnchangedCount,\n downloadedCount,\n downloadedBytes,\n localScannedCount: localFiles.length,\n removedCount,\n elapsedMs,\n phases: {\n mkdirMs,\n createClientMs,\n listRemoteMs,\n downloadMs,\n listLocalMs,\n cleanupMs,\n },\n };\n this.onDebugEvent?.('sync_down.complete', stats as unknown as Record<string, unknown>);\n return stats;\n }\n\n async syncUp(): Promise<GcsSyncUpStats> {\n const startedAt = Date.now();\n this.onDebugEvent?.('sync_up.start', {\n bucket: this.bucketName,\n prefix: this.prefix,\n localDirectory: this.localDirectory,\n });\n const mkdirStartedAt = Date.now();\n await mkdir(this.localDirectory, { recursive: true });\n const mkdirMs = Date.now() - mkdirStartedAt;\n const clientStartedAt = Date.now();\n const storage = await createStorageClient(this.auth);\n const createClientMs = Date.now() - clientStartedAt;\n const bucket = storage.bucket(this.bucketName);\n const listRemoteStartedAt = Date.now();\n const [remoteFiles] = await withRetry(() => bucket.getFiles({ prefix: this.prefix || undefined }));\n const listRemoteMs = Date.now() - listRemoteStartedAt;\n const remoteByRelative = new Map<string, StorageFile>();\n for (const remote of remoteFiles) {\n if (remote.name.endsWith('/')) {\n continue;\n }\n const relativePath = toRelativePath(this.prefix, remote.name);\n if (!relativePath || isInternalSyncControlFile(relativePath) || !this.includeFile(relativePath)) {\n continue;\n }\n remoteByRelative.set(relativePath, remote);\n }\n\n const listLocalStartedAt = Date.now();\n const localFiles = await collectLocalFiles(this.localDirectory);\n const listLocalMs = Date.now() - listLocalStartedAt;\n const localSet = new Set<string>();\n let localIncludedCount = 0;\n let uploadedCount = 0;\n const uploadStartedAt = Date.now();\n\n for (const localRelative of localFiles) {\n if (isInternalSyncControlFile(localRelative) || !this.includeFile(localRelative)) {\n continue;\n }\n localIncludedCount += 1;\n localSet.add(localRelative);\n const localPath = join(this.localDirectory, localRelative);\n const remoteFile = remoteByRelative.get(localRelative);\n let shouldUpload = true;\n if (remoteFile) {\n const remoteMd5 = await resolveRemoteMd5(remoteFile);\n if (remoteMd5) {\n const localMd5 = await fileMd5Base64(localPath);\n shouldUpload = localMd5 !== remoteMd5;\n }\n }\n if (!shouldUpload) {\n continue;\n }\n const objectName = toObjectName(this.prefix, localRelative);\n const uploadFileStartedAt = Date.now();\n await withRetry(() =>\n bucket.upload(localPath, {\n destination: objectName,\n })\n );\n const fileElapsedMs = Date.now() - uploadFileStartedAt;\n uploadedCount += 1;\n if (fileElapsedMs >= 250) {\n this.onDebugEvent?.('sync_up.file_upload', {\n path: localRelative,\n elapsedMs: fileElapsedMs,\n });\n }\n }\n const uploadMs = Date.now() - uploadStartedAt;\n\n let removedRemoteCount = 0;\n const cleanupStartedAt = Date.now();\n this.onDebugEvent?.('sync_up.gc.start', {\n bucket: this.bucketName,\n prefix: this.prefix,\n remoteCandidates: remoteFiles.length,\n });\n for (const remote of remoteFiles) {\n if (remote.name.endsWith('/')) {\n continue;\n }\n const relativePath = toRelativePath(this.prefix, remote.name);\n if (!relativePath || isInternalSyncControlFile(relativePath) || !this.includeFile(relativePath)) {\n continue;\n }\n if (!localSet.has(relativePath)) {\n await withRetry(() => remote.delete({ ignoreNotFound: true }));\n removedRemoteCount += 1;\n this.onDebugEvent?.('sync_up.gc.remove_remote', {\n path: relativePath,\n });\n }\n }\n const cleanupMs = Date.now() - cleanupStartedAt;\n this.onDebugEvent?.('sync_up.gc.complete', {\n removedRemoteCount,\n elapsedMs: cleanupMs,\n });\n\n const indexStartedAt = Date.now();\n const indexObjects: Record<string, RemoteObjectState> = {};\n for (const localRelative of localSet) {\n const localPath = join(this.localDirectory, localRelative);\n const localStats = await stat(localPath).catch(() => null);\n const md5Hash = await fileMd5Base64(localPath).catch(() => undefined);\n indexObjects[localRelative] = {\n path: localRelative,\n md5Hash,\n size: localStats?.size,\n updatedAt: localStats?.mtime ? localStats.mtime.toISOString() : undefined,\n };\n }\n await writeRemoteSyncIndex(bucket, this.prefix, this.localDirectory, indexObjects, this.onDebugEvent);\n this.onDebugEvent?.('sync_up.phase.write_index', {\n elapsedMs: Date.now() - indexStartedAt,\n objectCount: Object.keys(indexObjects).length,\n });\n\n const elapsedMs = Date.now() - startedAt;\n const stats: GcsSyncUpStats = {\n bucket: this.bucketName,\n prefix: this.prefix,\n localDirectory: this.localDirectory,\n localScannedCount: localFiles.length,\n localIncludedCount,\n uploadedCount,\n remoteListedCount: remoteFiles.length,\n removedRemoteCount,\n elapsedMs,\n phases: {\n mkdirMs,\n createClientMs,\n listLocalMs,\n uploadMs,\n listRemoteMs,\n cleanupMs,\n },\n };\n this.onDebugEvent?.('sync_up.complete', stats as unknown as Record<string, unknown>);\n return stats;\n }\n}\n","import { mkdir } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { GcsMirror } from './gcs-sync.js';\nimport type { GcsSyncDownStats, GcsSyncUpStats } from './gcs-sync.js';\n\nexport interface CloudStorageConfig {\n enabled?: boolean;\n incrementalSyncEnabled?: boolean;\n syncFreshnessTtlMs?: number;\n syncTimeoutMs?: number;\n planBucket?: string;\n planPrefix?: string;\n contextBucket?: string;\n contextPrefix?: string;\n projectId?: string;\n keyFilename?: string;\n credentialsJson?: string;\n cacheDirectory?: string;\n}\n\nexport interface CloudRuntimeConfig {\n cloud?: CloudStorageConfig;\n}\n\nfunction isTruthy(value: unknown): boolean {\n if (typeof value === 'boolean') {\n return value;\n }\n if (typeof value === 'string') {\n return /^(1|true|yes|on)$/i.test(value);\n }\n return false;\n}\n\nfunction firstNonEmpty(...values: Array<string | undefined>): string | undefined {\n for (const value of values) {\n if (typeof value === 'string' && value.trim()) {\n return value.trim();\n }\n }\n return undefined;\n}\n\nexport interface CloudRuntimeDirectories {\n workingDirectory: string;\n contextDirectory: string;\n}\n\nexport interface CloudRuntime extends CloudRuntimeDirectories {\n enabled: boolean;\n syncDown: (options?: { forceRefresh?: boolean }) => Promise<{\n plan: GcsSyncDownStats | null;\n context: GcsSyncDownStats | null;\n syncFreshHit: boolean;\n coalescedWaiterCount: number;\n }>;\n syncUpPlans: () => Promise<GcsSyncUpStats | null>;\n syncUpContext: () => Promise<GcsSyncUpStats | null>;\n}\n\nexport interface CloudRuntimeDiagnostics {\n debug?: (event: string, details?: Record<string, unknown>) => void;\n}\n\ntype InFlightOperation<T> = {\n promise: Promise<T>;\n waiterCount: number;\n};\n\ntype DebouncedOperationState<T> = {\n promise: Promise<T>;\n waiterCount: number;\n};\n\nconst inFlightOperations = new Map<string, InFlightOperation<unknown>>();\nconst debouncedOperations = new Map<string, DebouncedOperationState<unknown>>();\nconst lastSuccessfulSyncAtByScope = new Map<string, number>();\n\nfunction toInt(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) && parsed >= 0 ? parsed : undefined;\n}\n\nfunction resolveFreshnessTtlMs(config: CloudRuntimeConfig | null | undefined): number {\n const fromConfig = (config?.cloud as Record<string, unknown> | undefined)?.syncFreshnessTtlMs;\n if (typeof fromConfig === 'number' && Number.isFinite(fromConfig) && fromConfig >= 0) {\n return fromConfig;\n }\n return toInt(process.env.RIOTPLAN_CLOUD_SYNC_FRESHNESS_TTL_MS) || 5_000;\n}\n\nfunction resolveSyncTimeoutMs(config: CloudRuntimeConfig | null | undefined): number {\n const fromConfig = (config?.cloud as Record<string, unknown> | undefined)?.syncTimeoutMs;\n if (typeof fromConfig === 'number' && Number.isFinite(fromConfig) && fromConfig > 0) {\n return fromConfig;\n }\n return toInt(process.env.RIOTPLAN_CLOUD_SYNC_TIMEOUT_MS) || 120_000;\n}\n\nfunction resolveSyncUpDebounceMs(_config: CloudRuntimeConfig | null | undefined): number {\n const fromEnv = toInt(process.env.RIOTPLAN_CLOUD_SYNC_UP_DEBOUNCE_MS);\n if (typeof fromEnv === 'number') {\n return fromEnv;\n }\n // Internal server-side default; not exposed through MCP schemas.\n return 400;\n}\n\nexport async function runCoalescedOperation<T>(\n key: string,\n operation: () => Promise<T>,\n options?: { timeoutMs?: number }\n): Promise<{ result: T; coalesced: boolean; waiterCount: number }> {\n const existing = inFlightOperations.get(key) as InFlightOperation<T> | undefined;\n if (existing) {\n existing.waiterCount += 1;\n const result = await existing.promise;\n return {\n result,\n coalesced: true,\n waiterCount: existing.waiterCount,\n };\n }\n\n const timeoutMs = options?.timeoutMs && options.timeoutMs > 0 ? options.timeoutMs : 0;\n const entry: InFlightOperation<T> = {\n waiterCount: 0,\n promise: (async () => {\n try {\n if (!timeoutMs) {\n return await operation();\n }\n return await Promise.race([\n operation(),\n new Promise<T>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Coalesced operation timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n }),\n ]);\n } finally {\n inFlightOperations.delete(key);\n }\n })(),\n };\n inFlightOperations.set(key, entry);\n const result = await entry.promise;\n return {\n result,\n coalesced: false,\n waiterCount: entry.waiterCount,\n };\n}\n\nexport async function runDebouncedCoalescedOperation<T>(\n key: string,\n operation: () => Promise<T>,\n options?: { debounceMs?: number; timeoutMs?: number }\n): Promise<{ result: T; coalesced: boolean; waiterCount: number }> {\n const existing = debouncedOperations.get(key) as DebouncedOperationState<T> | undefined;\n if (existing) {\n existing.waiterCount += 1;\n const result = await existing.promise;\n return {\n result,\n coalesced: true,\n waiterCount: existing.waiterCount,\n };\n }\n\n const debounceMs = options?.debounceMs && options.debounceMs > 0 ? options.debounceMs : 0;\n const timeoutMs = options?.timeoutMs && options.timeoutMs > 0 ? options.timeoutMs : 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const promise = new Promise<T>((resolve, reject) => {\n const execute = async () => {\n const run = async () => operation();\n const task = timeoutMs\n ? Promise.race([\n run(),\n new Promise<T>((_, timeoutReject) => {\n setTimeout(() => {\n timeoutReject(new Error(`Debounced operation timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n }),\n ])\n : run();\n try {\n resolve(await task);\n } catch (error) {\n reject(error);\n } finally {\n debouncedOperations.delete(key);\n }\n };\n\n if (debounceMs > 0) {\n timer = setTimeout(() => {\n void execute();\n }, debounceMs);\n return;\n }\n\n void execute();\n });\n\n const state: DebouncedOperationState<T> = {\n promise,\n waiterCount: 0,\n };\n debouncedOperations.set(key, state);\n\n try {\n const result = await promise;\n return {\n result,\n coalesced: false,\n waiterCount: state.waiterCount,\n };\n } catch (error) {\n if (timer) {\n clearTimeout(timer);\n }\n throw error;\n }\n}\n\nexport async function createCloudRuntime(\n config: CloudRuntimeConfig | null | undefined,\n localPlanDirectory: string,\n diagnostics?: CloudRuntimeDiagnostics\n): Promise<CloudRuntime> {\n const cloudConfig = config?.cloud;\n const incrementalSyncEnabled = (cloudConfig as Record<string, unknown> | undefined)?.incrementalSyncEnabled !== false;\n const freshnessTtlMs = incrementalSyncEnabled ? resolveFreshnessTtlMs(config) : 0;\n const syncTimeoutMs = resolveSyncTimeoutMs(config);\n const syncUpDebounceMs = resolveSyncUpDebounceMs(config);\n const enabled =\n isTruthy(cloudConfig?.enabled) ||\n isTruthy(process.env.RIOTPLAN_CLOUD_ENABLED) ||\n isTruthy(process.env.RIOTPLAN_GCS_ENABLED);\n\n if (!enabled) {\n return {\n enabled: false,\n workingDirectory: localPlanDirectory,\n contextDirectory: localPlanDirectory,\n syncDown: async () => ({\n plan: null,\n context: null,\n syncFreshHit: false,\n coalescedWaiterCount: 0,\n }),\n syncUpPlans: async () => null,\n syncUpContext: async () => null,\n };\n }\n\n const planBucket = firstNonEmpty(\n cloudConfig?.planBucket,\n process.env.RIOTPLAN_PLAN_BUCKET,\n process.env.RIOTPLAN_GCS_PLAN_BUCKET\n );\n const contextBucket = firstNonEmpty(\n cloudConfig?.contextBucket,\n process.env.RIOTPLAN_CONTEXT_BUCKET,\n process.env.RIOTPLAN_GCS_CONTEXT_BUCKET\n );\n\n if (!planBucket || !contextBucket) {\n throw new Error(\n 'Cloud mode enabled but missing bucket config. Set cloud.planBucket + cloud.contextBucket or RIOTPLAN_PLAN_BUCKET + RIOTPLAN_CONTEXT_BUCKET.'\n );\n }\n\n const cacheRoot = resolve(\n firstNonEmpty(cloudConfig?.cacheDirectory, process.env.RIOTPLAN_CLOUD_CACHE_DIR) ||\n join(localPlanDirectory, '.cloud-cache')\n );\n const planMirrorDir = join(cacheRoot, 'plans');\n const contextMirrorDir = join(cacheRoot, 'context');\n\n await mkdir(planMirrorDir, { recursive: true });\n await mkdir(contextMirrorDir, { recursive: true });\n\n const auth = {\n projectId: firstNonEmpty(cloudConfig?.projectId, process.env.GOOGLE_CLOUD_PROJECT),\n keyFilename: firstNonEmpty(cloudConfig?.keyFilename, process.env.GOOGLE_APPLICATION_CREDENTIALS),\n credentialsJson: firstNonEmpty(cloudConfig?.credentialsJson, process.env.GOOGLE_CREDENTIALS_JSON),\n };\n\n const planMirror = new GcsMirror({\n auth,\n location: {\n bucket: planBucket,\n prefix: cloudConfig?.planPrefix,\n },\n localDirectory: planMirrorDir,\n includeFile: (relativePath) => relativePath.endsWith('.plan'),\n incrementalSyncEnabled,\n onDebugEvent: (event, details) => {\n diagnostics?.debug?.(`plan.${event}`, details);\n },\n });\n\n const contextMirror = new GcsMirror({\n auth,\n location: {\n bucket: contextBucket,\n prefix: cloudConfig?.contextPrefix,\n },\n localDirectory: contextMirrorDir,\n incrementalSyncEnabled,\n onDebugEvent: (event, details) => {\n diagnostics?.debug?.(`context.${event}`, details);\n },\n });\n\n return {\n enabled: true,\n workingDirectory: planMirrorDir,\n contextDirectory: contextMirrorDir,\n syncDown: async (options) => {\n const startedAt = Date.now();\n const planScope = `sync_down:${planMirrorDir}:plan`;\n const contextScope = `sync_down:${contextMirrorDir}:context`;\n const now = Date.now();\n const planFresh = freshnessTtlMs > 0 && now - (lastSuccessfulSyncAtByScope.get(planScope) || 0) <= freshnessTtlMs;\n const contextFresh = freshnessTtlMs > 0 && now - (lastSuccessfulSyncAtByScope.get(contextScope) || 0) <= freshnessTtlMs;\n if (!options?.forceRefresh && planFresh && contextFresh) {\n diagnostics?.debug?.('sync_down.fresh_hit', {\n freshnessTtlMs,\n planScope,\n contextScope,\n });\n return {\n plan: null,\n context: null,\n syncFreshHit: true,\n coalescedWaiterCount: 0,\n };\n }\n diagnostics?.debug?.('sync_down.start', {\n planBucket,\n contextBucket,\n planMirrorDir,\n contextMirrorDir,\n incrementalSyncEnabled,\n freshnessTtlMs,\n syncTimeoutMs,\n });\n const [planSync, contextSync] = await Promise.all([\n runCoalescedOperation(planScope, () => planMirror.syncDown(), { timeoutMs: syncTimeoutMs }),\n runCoalescedOperation(contextScope, () => contextMirror.syncDown(), { timeoutMs: syncTimeoutMs }),\n ]);\n const planStats = planSync.result;\n const contextStats = contextSync.result;\n lastSuccessfulSyncAtByScope.set(planScope, Date.now());\n lastSuccessfulSyncAtByScope.set(contextScope, Date.now());\n const coalescedWaiterCount = planSync.waiterCount + contextSync.waiterCount;\n const syncFreshHit = planStats.downloadedCount === 0 && contextStats.downloadedCount === 0;\n diagnostics?.debug?.('sync_down.complete', {\n elapsedMs: Date.now() - startedAt,\n syncFreshHit,\n coalescedWaiterCount,\n syncOutcome: syncFreshHit ? 'fresh-hit' : 'full-or-incremental',\n plan: planStats,\n context: contextStats,\n });\n return {\n plan: planStats,\n context: contextStats,\n syncFreshHit,\n coalescedWaiterCount,\n };\n },\n syncUpPlans: async () => {\n const startedAt = Date.now();\n diagnostics?.debug?.('sync_up_plans.start', { planBucket, planMirrorDir });\n const syncUpScope = `sync_up:${planMirrorDir}:plan`;\n const syncResult = await runDebouncedCoalescedOperation(\n syncUpScope,\n () => planMirror.syncUp(),\n { debounceMs: syncUpDebounceMs, timeoutMs: syncTimeoutMs }\n );\n const stats = syncResult.result;\n if (syncResult.coalesced || syncResult.waiterCount > 0) {\n diagnostics?.debug?.('sync_up_plans.coalesced', {\n scope: syncUpScope,\n coalesced: syncResult.coalesced,\n coalescedWaiterCount: syncResult.waiterCount,\n debounceMs: syncUpDebounceMs,\n });\n }\n diagnostics?.debug?.('sync_up_plans.complete', {\n elapsedMs: Date.now() - startedAt,\n plan: stats,\n coalesced: syncResult.coalesced,\n coalescedWaiterCount: syncResult.waiterCount,\n debounceMs: syncUpDebounceMs,\n });\n return stats;\n },\n syncUpContext: async () => {\n const startedAt = Date.now();\n diagnostics?.debug?.('sync_up_context.start', { contextBucket, contextMirrorDir });\n const syncUpScope = `sync_up:${contextMirrorDir}:context`;\n const syncResult = await runDebouncedCoalescedOperation(\n syncUpScope,\n () => contextMirror.syncUp(),\n { debounceMs: syncUpDebounceMs, timeoutMs: syncTimeoutMs }\n );\n const stats = syncResult.result;\n if (syncResult.coalesced || syncResult.waiterCount > 0) {\n diagnostics?.debug?.('sync_up_context.coalesced', {\n scope: syncUpScope,\n coalesced: syncResult.coalesced,\n coalescedWaiterCount: syncResult.waiterCount,\n debounceMs: syncUpDebounceMs,\n });\n }\n diagnostics?.debug?.('sync_up_context.complete', {\n elapsedMs: Date.now() - startedAt,\n context: stats,\n coalesced: syncResult.coalesced,\n coalescedWaiterCount: syncResult.waiterCount,\n debounceMs: syncUpDebounceMs,\n });\n return stats;\n },\n };\n}\n"],"names":["resolve","result"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kjerneverk/riotplan-cloud",
|
|
3
|
+
"version": "1.0.0-dev.0",
|
|
4
|
+
"description": "Cloud runtime and GCS sync for RiotPlan",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=24.0.0"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"clean": "rm -rf dist",
|
|
19
|
+
"build": "npm run lint && vite build",
|
|
20
|
+
"test": "npm run test:coverage",
|
|
21
|
+
"test:coverage": "vitest run --coverage",
|
|
22
|
+
"test:debug": "vitest --run --coverage --reporter verbose",
|
|
23
|
+
"lint": "eslint src",
|
|
24
|
+
"lint:fix": "eslint src --fix",
|
|
25
|
+
"precommit": "npm run build && npm run lint && npm run test",
|
|
26
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
27
|
+
},
|
|
28
|
+
"keywords": ["riotplan", "cloud", "gcs", "sync", "storage"],
|
|
29
|
+
"author": "Tim O'Brien <tobrien@discursive.com>",
|
|
30
|
+
"license": "Apache-2.0",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/kjerneverk/riotplan-cloud"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@google-cloud/storage": "^7.19.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@eslint/eslintrc": "^3.3.1",
|
|
40
|
+
"@eslint/js": "^9.28.0",
|
|
41
|
+
"@types/node": "^24.10.9",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^8.34.0",
|
|
43
|
+
"@typescript-eslint/parser": "^8.34.0",
|
|
44
|
+
"@vitest/coverage-v8": "^4.0.17",
|
|
45
|
+
"eslint": "^9.28.0",
|
|
46
|
+
"eslint-plugin-import": "^2.31.0",
|
|
47
|
+
"globals": "^17.0.0",
|
|
48
|
+
"typescript": "^5.8.3",
|
|
49
|
+
"vite": "^7.0.4",
|
|
50
|
+
"vite-plugin-dts": "^4.5.4",
|
|
51
|
+
"vitest": "^4.0.17"
|
|
52
|
+
}
|
|
53
|
+
}
|