Files
NetMesh/infrastructure/services/adapters/index.ts
zhaolei 3c72efcb7f
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
[Init] Initial commit - NetMesh terminal manager
2026-09-13 18:24:01 +08:00

133 lines
4.9 KiB
TypeScript

/**
* Cloud Sync Adapters - Unified Export
*/
import type {
CloudProvider,
SyncedFile,
OAuthTokens,
ProviderAccount,
WebDAVConfig,
S3Config,
} from '../../../domain/sync';
import { isBuiltinCloudProvider } from '../../../domain/sync';
import type { EncryptedObjectStorage } from '../../../domain/encryptedObjectStorage';
import {
cloudAdapterAsEncryptedObjectStorage,
encryptedObjectStorageAsCloudAdapter,
webdavEncryptedObjectCapabilities,
} from './encryptedObjectStorageBridge';
/**
* Unified adapter interface
*/
export interface CloudAdapter {
readonly isAuthenticated: boolean;
readonly accountInfo: ProviderAccount | null;
readonly resourceId: string | null;
signOut(): void;
initializeSync(): Promise<string | null>;
upload(syncedFile: SyncedFile, options?: { signal?: AbortSignal }): Promise<string>;
download(options?: { signal?: AbortSignal }): Promise<SyncedFile | null>;
deleteSync(options?: { signal?: AbortSignal }): Promise<void>;
getTokens(): OAuthTokens | null;
}
export type { EncryptedObjectStorage };
/**
* Create adapter for a specific provider.
* Built-in providers keep their dedicated adapters. Namespaced plugin provider
* IDs require an EncryptedObjectStorage factory (plugin host bridge).
*/
export const createAdapter = async (
provider: CloudProvider,
tokens?: OAuthTokens,
resourceId?: string,
config?: WebDAVConfig | S3Config,
options?: {
/** Plugin sync storage factory for namespaced provider IDs. */
createPluginStorage?: (providerId: string) => EncryptedObjectStorage | Promise<EncryptedObjectStorage>;
},
): Promise<CloudAdapter> => {
switch (provider) {
case 'github': {
const { GitHubAdapter } = await import('./GitHubAdapter');
return new GitHubAdapter(tokens, resourceId);
}
case 'google': {
const { GoogleDriveAdapter } = await import('./GoogleDriveAdapter');
return new GoogleDriveAdapter(tokens, resourceId);
}
case 'onedrive': {
const { OneDriveAdapter } = await import('./OneDriveAdapter');
return new OneDriveAdapter(tokens, resourceId);
}
case 'webdav': {
const { WebDAVAdapter } = await import('./WebDAVAdapter');
// Production WebDAV path runs through EncryptedObjectStorage so plugin
// providers and WebDAV share one encrypt→write / read→decrypt surface.
const raw = new WebDAVAdapter(config as WebDAVConfig | undefined, resourceId);
const storage = cloudAdapterAsEncryptedObjectStorage(raw, 'webdav', {
capabilities: webdavEncryptedObjectCapabilities(),
});
return encryptedObjectStorageAsCloudAdapter(storage, {
account: raw.accountInfo,
// Match raw WebDAVAdapter: config present ⇒ authenticated for cache reuse.
initiallyAuthenticated: raw.isAuthenticated,
// Preserve constructor/persisted resourceId; refresh from raw after connect.
resourceId: raw.resourceId ?? resourceId ?? null,
resolveResourceId: () => raw.resourceId,
// WebDAVAdapter.upload already performs pad + strict body verify; skip the
// shared bridge's second full re-read to avoid write amplification.
assumeVerifiedWrites: true,
});
}
case 's3': {
const { S3Adapter } = await import('./S3Adapter');
return new S3Adapter(config as S3Config | undefined, resourceId);
}
default: {
if (isBuiltinCloudProvider(provider)) {
throw new Error(`Unknown provider: ${provider}`);
}
if (!options?.createPluginStorage) {
throw new Error(
`Plugin sync provider ${provider} is unavailable (missing or not registered)`,
);
}
const storage = await options.createPluginStorage(provider);
// Credentials/config already validated by getConnectedAdapter; report
// authenticated so the manager reuses this instance across sync calls.
// rebindSession: plugin runtimes can restart while availability membership
// stays unchanged, so ensureConnected must re-issue connect() with the
// saved configuration/credential instead of skipping after the first call.
return encryptedObjectStorageAsCloudAdapter(storage, {
initiallyAuthenticated: true,
resourceId: resourceId ?? null,
rebindSession: true,
});
}
}
};
/**
* View a CloudAdapter as EncryptedObjectStorage. WebDAV is the first built-in
* adapted through this shared surface for configuration, secrets, upload,
* download, verification, and recovery exercises.
*/
export const asEncryptedObjectStorage = (
provider: CloudProvider,
adapter: CloudAdapter,
): EncryptedObjectStorage =>
cloudAdapterAsEncryptedObjectStorage(adapter, provider, {
capabilities: provider === 'webdav'
? webdavEncryptedObjectCapabilities()
: {
revisions: provider === 'github',
conditionalWrites: false,
atomicReplacement: provider === 'webdav' || provider === 's3',
},
});