// Environment bindings export interface Env { DB: D1Database; NOTIFICATIONS_HUB: DurableObjectNamespace; ASSETS?: { fetch(input: RequestInfo | URL, init?: RequestInit): Promise; }; // Prefer R2 when available. Optional to support KV-only deployments. ATTACHMENTS?: R2Bucket; // Optional fallback for attachment/send file storage (no credit card required). ATTACHMENTS_KV?: KVNamespace; JWT_SECRET: string; TOTP_SECRET?: string; } export type UserRole = 'admin' | 'user'; export type UserStatus = 'active' | 'banned'; // Sample JWT secret used by `.dev.vars.example`. // If runtime JWT_SECRET equals this value, treat it as unsafe. export const DEFAULT_DEV_SECRET = 'Enter-your-JWT-key-here-at-least-32-characters'; // Attachment model export interface Attachment { id: string; cipherId: string; fileName: string; // encrypted size: number; sizeName: string; key: string | null; // encrypted attachment key } // User model export interface User { id: string; email: string; name: string | null; masterPasswordHint: string | null; masterPasswordHash: string; key: string; privateKey: string | null; publicKey: string | null; kdfType: number; kdfIterations: number; kdfMemory?: number; kdfParallelism?: number; securityStamp: string; role: UserRole; status: UserStatus; verifyDevices?: boolean; totpSecret: string | null; totpRecoveryCode: string | null; createdAt: string; updatedAt: string; } export interface Invite { code: string; createdBy: string; usedBy: string | null; expiresAt: string; status: 'active' | 'used' | 'revoked' | 'expired'; createdAt: string; updatedAt: string; } export interface AuditLog { id: string; actorUserId: string | null; action: string; targetType: string | null; targetId: string | null; metadata: string | null; createdAt: string; } // Cipher types export enum CipherType { Login = 1, SecureNote = 2, Card = 3, Identity = 4, } export interface CipherLoginUri { uri: string | null; uriChecksum: string | null; match: number | null; } export interface CipherLogin { username: string | null; password: string | null; uris: CipherLoginUri[] | null; totp: string | null; autofillOnPageLoad: boolean | null; fido2Credentials: any[] | null; uri: string | null; passwordRevisionDate: string | null; } export interface CipherCard { cardholderName: string | null; brand: string | null; number: string | null; expMonth: string | null; expYear: string | null; code: string | null; } export interface CipherSshKey { publicKey: string; privateKey: string; keyFingerprint: string; } export interface CipherIdentity { title: string | null; firstName: string | null; middleName: string | null; lastName: string | null; address1: string | null; address2: string | null; address3: string | null; city: string | null; state: string | null; postalCode: string | null; country: string | null; company: string | null; email: string | null; phone: string | null; ssn: string | null; username: string | null; passportNumber: string | null; licenseNumber: string | null; } export interface CipherSecureNote { type: number; } export interface CipherField { name: string | null; value: string | null; type: number; linkedId: number | null; } export interface PasswordHistory { password: string; lastUsedDate: string; } export interface Cipher { id: string; userId: string; type: CipherType; folderId: string | null; name: string | null; notes: string | null; favorite: boolean; login: CipherLogin | null; card: CipherCard | null; identity: CipherIdentity | null; secureNote: CipherSecureNote | null; sshKey: CipherSshKey | null; fields: CipherField[] | null; passwordHistory: PasswordHistory[] | null; reprompt: number; key: string | null; createdAt: string; updatedAt: string; archivedAt: string | null; deletedAt: string | null; /** Allow unknown fields from Bitwarden clients to be stored and passed through transparently. */ [key: string]: any; } // Folder model export interface Folder { id: string; userId: string; name: string; createdAt: string; updatedAt: string; } export interface Device { userId: string; deviceIdentifier: string; name: string; type: number; sessionStamp: string; encryptedUserKey: string | null; encryptedPublicKey: string | null; encryptedPrivateKey: string | null; devicePendingAuthRequest?: DevicePendingAuthRequest | null; createdAt: string; updatedAt: string; } export interface DevicePendingAuthRequest { id: string; creationDate: string; } export interface DeviceResponse { id: string; userId?: string | null; name: string; identifier: string; type: number; creationDate: string; revisionDate: string; isTrusted: boolean; encryptedUserKey: string | null; encryptedPublicKey: string | null; devicePendingAuthRequest: DevicePendingAuthRequest | null; object: string; [key: string]: any; } export interface ProtectedDeviceResponse { id: string; name: string; identifier: string; type: number; creationDate: string; encryptedUserKey: string | null; encryptedPublicKey: string | null; object: string; [key: string]: any; } export interface RefreshTokenRecord { userId: string; expiresAt: number; deviceIdentifier: string | null; deviceSessionStamp: string | null; } export interface TrustedDeviceTokenSummary { deviceIdentifier: string; expiresAt: number; tokenCount: number; } export enum SendType { Text = 0, File = 1, } export enum SendAuthType { Email = 0, Password = 1, None = 2, } export interface Send { id: string; userId: string; type: SendType; name: string; notes: string | null; data: string; key: string; passwordHash: string | null; passwordSalt: string | null; passwordIterations: number | null; authType: SendAuthType; emails: string | null; maxAccessCount: number | null; accessCount: number; disabled: boolean; hideEmail: boolean | null; createdAt: string; updatedAt: string; expirationDate: string | null; deletionDate: string; } export interface SendResponse { id: string; accessId: string; type: number; name: string; notes: string | null; text: any | null; file: any | null; key: string; maxAccessCount: number | null; accessCount: number; password: string | null; emails: string | null; authType: SendAuthType; disabled: boolean; hideEmail: boolean | null; revisionDate: string; expirationDate: string | null; deletionDate: string; object: string; } // JWT Payload export interface JWTPayload { sub: string; // user id email: string; name: string | null; email_verified: boolean; // required by mobile client amr: string[]; // authentication methods reference - required by mobile client sstamp: string; // security stamp - invalidates token when user changes password did?: string; // device identifier - invalidates per-device sessions dstamp?: string; // device session stamp iat: number; exp: number; iss: string; premium: boolean; } // UserDecryptionOptions types for mobile client compatibility export interface MasterPasswordUnlockKdf { KdfType: number; Iterations: number; Memory: number | null; Parallelism: number | null; } export interface MasterPasswordUnlock { Kdf: MasterPasswordUnlockKdf; MasterKeyEncryptedUserKey: string; MasterKeyWrappedUserKey: string; Salt: string; Object: string; } export interface UserDecryptionOptions { HasMasterPassword: boolean; Object: string; // Bitwarden Android 2026.1.x expects this to exist; missing it breaks unlock when the vault is empty. MasterPasswordUnlock: MasterPasswordUnlock; TrustedDeviceOption: null; KeyConnectorOption: null; } // API Response types export interface TokenResponse { access_token: string; expires_in: number; token_type: string; refresh_token?: string; web_session?: boolean; TwoFactorToken?: string; Key: string; PrivateKey: string | null; Kdf: number; KdfIterations: number; KdfMemory?: number; KdfParallelism?: number; ForcePasswordReset: boolean; ResetMasterPassword: boolean; scope: string; unofficialServer: boolean; MasterPasswordPolicy?: { Object: string; } | null; ApiUseKeyConnector?: boolean; AccountKeys?: any | null; accountKeys?: any | null; UserDecryptionOptions: UserDecryptionOptions; userDecryptionOptions?: UserDecryptionOptions; VaultKeys?: { symEncKey: string; symMacKey: string; }; } export interface ProfileResponse { id: string; name: string | null; email: string; emailVerified: boolean; premium: boolean; premiumFromOrganization: boolean; usesKeyConnector: boolean; masterPasswordHint: string | null; culture: string; twoFactorEnabled: boolean; key: string; privateKey: string | null; accountKeys: any | null; securityStamp: string; organizations: any[]; providers: any[]; providerOrganizations: any[]; forcePasswordReset: boolean; avatarColor: string | null; creationDate: string; verifyDevices?: boolean; role?: UserRole; status?: UserStatus; object: string; } export interface CipherResponse { id: string; organizationId: string | null; folderId: string | null; type: number; name: string | null; notes: string | null; favorite: boolean; login: CipherLogin | null; card: CipherCard | null; identity: CipherIdentity | null; secureNote: CipherSecureNote | null; sshKey: CipherSshKey | null; fields: CipherField[] | null; passwordHistory: PasswordHistory[] | null; reprompt: number; organizationUseTotp: boolean; creationDate: string; revisionDate: string; deletedDate: string | null; archivedDate: string | null; edit: boolean; viewPassword: boolean; permissions: CipherPermissions | null; object: string; collectionIds: string[]; attachments: any[] | null; key: string | null; encryptedFor: string | null; /** Allow unknown fields to pass through to clients transparently. */ [key: string]: any; } export interface CipherPermissions { delete: boolean; restore: boolean; } export interface FolderResponse { id: string; name: string; revisionDate: string; object: string; } export interface SyncResponse { profile: ProfileResponse; folders: FolderResponse[]; collections: any[]; ciphers: CipherResponse[]; domains: any; policies: any[]; sends: SendResponse[]; UserDecryption?: { MasterPasswordUnlock: MasterPasswordUnlock | null; TrustedDeviceOption?: null; KeyConnectorOption?: null; WebAuthnPrfOption?: null; Object?: string; } | null; // PascalCase for desktop/browser clients UserDecryptionOptions: UserDecryptionOptions | null; // camelCase for Android client (SyncResponseJson uses @SerialName("userDecryption")) userDecryption: { masterPasswordUnlock: { kdf: { kdfType: number; iterations: number; memory: number | null; parallelism: number | null; }; masterKeyWrappedUserKey: string; masterKeyEncryptedUserKey: string; salt: string; } | null; } | null; object: string; }