CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-google-cloud--storage

Cloud Storage Client Library for Node.js that provides comprehensive API for managing buckets, files, and metadata with authentication, streaming, and access control.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

file-operations.mddocs/

File Operations

The File class represents a Cloud Storage object/file with comprehensive methods for upload, download, management, encryption, and access control.

Class Definition

class File extends ServiceObject {
  constructor(bucket: Bucket, name: string, options?: FileOptions);
  
  // Properties
  name: string;
  bucket: Bucket;
  storage: Storage;
  acl: Acl;
  generation?: number;
  kmsKeyName?: string;
  userProject?: string;
  
  // Upload/Download methods
  save(data: SaveData, options?: SaveOptions): Promise<void>;
  createWriteStream(options?: CreateWriteStreamOptions): Writable;
  createResumableUpload(options?: CreateResumableUploadOptions): Promise<CreateResumableUploadResponse>;
  download(options?: DownloadOptions): Promise<DownloadResponse>;
  createReadStream(options?: CreateReadStreamOptions): Readable;
  
  // File management methods
  exists(options?: FileExistsOptions): Promise<FileExistsResponse>;
  get(options?: GetFileOptions): Promise<GetFileResponse>;
  getMetadata(options?: GetFileMetadataOptions): Promise<GetFileMetadataResponse>;
  setMetadata(metadata: FileMetadata, options?: SetFileMetadataOptions): Promise<SetFileMetadataResponse>;
  copy(destination: string | Bucket | File, options?: CopyOptions): Promise<CopyResponse>;
  move(destination: string | Bucket | File, options?: MoveOptions): Promise<MoveResponse>;
  delete(options?: DeleteFileOptions): Promise<DeleteFileResponse>;
}

interface FileOptions {
  encryptionKey?: string | Buffer;
  generation?: number | string;
  kmsKeyName?: string;
  userProject?: string;
}

Upload Operations

Save Data to File

save(data: SaveData, options?: SaveOptions): Promise<void>

type SaveData = string | Buffer | Uint8Array;

interface SaveOptions {
  encryptionKey?: string | Buffer;
  gzip?: boolean;
  metadata?: FileMetadata;
  offset?: number;
  predefinedAcl?: PredefinedAcl;
  private?: boolean;
  public?: boolean;
  resumable?: boolean;
  timeout?: number;
  uri?: string;
  userProject?: string;
  validation?: string | boolean;
  preconditionOpts?: PreconditionOptions;
}

// Save string data
await file.save('Hello, World!');

// Save buffer data
const buffer = Buffer.from('Binary data', 'utf8');
await file.save(buffer);

// Save with metadata
await file.save('File content', {
  metadata: {
    contentType: 'text/plain',
    cacheControl: 'no-cache',
    metadata: {
      author: 'user-123',
      version: '1.0'
    }
  }
});

// Save with compression
await file.save('Large text content...', {
  gzip: true,
  metadata: {
    contentEncoding: 'gzip'
  }
});

// Save with encryption
await file.save('Secret data', {
  encryptionKey: crypto.randomBytes(32).toString('base64')
});

// Save with access control
await file.save('Public content', {
  public: true
});

Create Write Stream

createWriteStream(options?: CreateWriteStreamOptions): Writable

interface CreateWriteStreamOptions {
  chunkSize?: number;
  encryptionKey?: string | Buffer;
  gzip?: boolean;
  metadata?: FileMetadata;
  offset?: number;
  predefinedAcl?: PredefinedAcl;
  private?: boolean;
  public?: boolean;
  resumable?: boolean;
  timeout?: number;
  uri?: string;
  userProject?: string;
  validation?: string | boolean;
  preconditionOpts?: PreconditionOptions;
}

// Basic write stream
const writeStream = file.createWriteStream();
writeStream.write('First chunk\n');
writeStream.write('Second chunk\n');
writeStream.end();

// Stream from file with metadata
const writeStream = file.createWriteStream({
  metadata: {
    contentType: 'application/json'
  }
});

fs.createReadStream('/local/file.json').pipe(writeStream);

// Resumable upload for large files
const writeStream = file.createWriteStream({
  resumable: true,
  chunkSize: 256 * 1024, // 256KB chunks
  metadata: {
    contentType: 'video/mp4'
  }
});

writeStream.on('error', (err) => {
  console.error('Upload failed:', err);
});

writeStream.on('finish', () => {
  console.log('Upload completed');
});

// Compressed upload
const writeStream = file.createWriteStream({
  gzip: true,
  metadata: {
    contentEncoding: 'gzip'
  }
});

// Pipeline with transformation
const zlib = require('zlib');
fs.createReadStream('/large/file.txt')
  .pipe(zlib.createGzip())
  .pipe(writeStream);

Create Resumable Upload

createResumableUpload(options?: CreateResumableUploadOptions): Promise<CreateResumableUploadResponse>

interface CreateResumableUploadOptions {
  chunkSize?: number;
  configPath?: string;
  encryptionKey?: string | Buffer;
  generation?: number;
  kmsKeyName?: string;
  metadata?: FileMetadata;
  offset?: number;
  origin?: string;
  predefinedAcl?: PredefinedAcl;
  private?: boolean;
  public?: boolean;
  uri?: string;
  userProject?: string;
  preconditionOpts?: PreconditionOptions;
}

type CreateResumableUploadResponse = [string]; // [resumeUri]

// Create resumable upload session
const [resumeUri] = await file.createResumableUpload({
  chunkSize: 1024 * 1024, // 1MB chunks
  metadata: {
    contentType: 'application/octet-stream'
  }
});

console.log('Resume URI:', resumeUri);

// Resume upload later
const writeStream = file.createWriteStream({
  uri: resumeUri
});

Download Operations

Download to Memory

download(options?: DownloadOptions): Promise<DownloadResponse>

interface DownloadOptions {
  destination?: string;
  start?: number;
  end?: number;
  validation?: string | boolean;
  userProject?: string;
  decompress?: boolean;
}

type DownloadResponse = [Buffer]; // [fileContents]

// Download entire file
const [contents] = await file.download();
console.log('File contents:', contents.toString());

// Download to local file
await file.download({
  destination: '/local/path/downloaded-file.txt'
});

// Download byte range
const [partialContents] = await file.download({
  start: 0,
  end: 1023 // First 1KB
});

// Download with decompression
const [contents] = await file.download({
  decompress: true // Auto-decompress gzipped files
});

// Download without validation (faster)
const [contents] = await file.download({
  validation: false
});

Create Read Stream

createReadStream(options?: CreateReadStreamOptions): Readable

interface CreateReadStreamOptions {
  start?: number;
  end?: number;
  validation?: string | boolean;
  userProject?: string;
  decompress?: boolean;
}

// Basic read stream
const readStream = file.createReadStream();
readStream.pipe(fs.createWriteStream('/local/output.txt'));

// Stream byte range
const readStream = file.createReadStream({
  start: 1024,
  end: 2047 // Bytes 1024-2047
});

// Stream with decompression
const readStream = file.createReadStream({
  decompress: true
});

// Stream processing
file.createReadStream()
  .on('data', (chunk) => {
    console.log(`Received ${chunk.length} bytes`);
  })
  .on('end', () => {
    console.log('Download completed');
  })
  .on('error', (err) => {
    console.error('Download failed:', err);
  });

// Transform stream
const zlib = require('zlib');
file.createReadStream()
  .pipe(zlib.createGunzip())
  .pipe(fs.createWriteStream('/local/uncompressed.txt'));

File Management

Check File Existence

exists(options?: FileExistsOptions): Promise<FileExistsResponse>

interface FileExistsOptions {
  userProject?: string;
}

type FileExistsResponse = [boolean]; // [exists]

// Check if file exists
const [exists] = await file.exists();
if (exists) {
  console.log('File exists');
} else {
  console.log('File does not exist');
}

Get File (Create if Needed)

get(options?: GetFileOptions): Promise<GetFileResponse>

interface GetFileOptions extends GetFileMetadataOptions {
  autoCreate?: boolean;
  generation?: number;
}

type GetFileResponse = [File, unknown]; // [file, apiResponse]

// Get file (create empty file if doesn't exist)
const [file] = await file.get({
  autoCreate: true
});

File Metadata

getMetadata(options?: GetFileMetadataOptions): Promise<GetFileMetadataResponse>
setMetadata(metadata: FileMetadata, options?: SetFileMetadataOptions): Promise<SetFileMetadataResponse>

interface GetFileMetadataOptions {
  userProject?: string;
  generation?: number;
  ifGenerationMatch?: number;
  ifGenerationNotMatch?: number;
  ifMetagenerationMatch?: number;
  ifMetagenerationNotMatch?: number;
}

interface FileMetadata {
  acl?: AclMetadata[];
  bucket?: string;
  cacheControl?: string;
  componentCount?: number;
  contentDisposition?: string;
  contentEncoding?: string;
  contentLanguage?: string;
  contentType?: string;
  crc32c?: string;
  customTime?: string;
  customerEncryption?: {
    encryptionAlgorithm?: string;
    keySha256?: string;
  };
  etag?: string;
  eventBasedHold?: boolean;
  generation?: string;
  id?: string;
  kmsKeyName?: string;
  md5Hash?: string;
  mediaLink?: string;
  metadata?: { [key: string]: string };
  metageneration?: string;
  name?: string;
  owner?: {
    entity?: string;
    entityId?: string;
  };
  retentionExpirationTime?: string;
  selfLink?: string;
  size?: string;
  storageClass?: string;
  temporaryHold?: boolean;
  timeCreated?: string;
  timeDeleted?: string;
  updated?: string;
}

type GetFileMetadataResponse = [FileMetadata, unknown]; // [metadata, apiResponse]
type SetFileMetadataResponse = [FileMetadata, unknown]; // [metadata, apiResponse]

// Get file metadata
const [metadata] = await file.getMetadata();
console.log('File size:', metadata.size);
console.log('Content type:', metadata.contentType);
console.log('Created:', metadata.timeCreated);
console.log('MD5 hash:', metadata.md5Hash);

// Set custom metadata
await file.setMetadata({
  metadata: {
    author: 'john-doe',
    version: '2.1',
    category: 'document'
  }
});

// Update content headers
await file.setMetadata({
  contentType: 'application/pdf',
  contentDisposition: 'attachment; filename="report.pdf"',
  cacheControl: 'public, max-age=3600'
});

// Set custom time (for lifecycle rules)
await file.setMetadata({
  customTime: '2023-12-31T23:59:59Z'
});

// Set holds (for retention)
await file.setMetadata({
  temporaryHold: true,
  eventBasedHold: false
});

File Operations

Copy File

copy(destination: string | Bucket | File, options?: CopyOptions): Promise<CopyResponse>

interface CopyOptions {
  destinationKmsKeyName?: string;
  predefinedAcl?: PredefinedAcl;
  token?: string;
  userProject?: string;
  preconditionOpts?: PreconditionOptions;
}

type CopyResponse = [File, unknown]; // [destinationFile, apiResponse]

// Copy within same bucket
const [copiedFile] = await file.copy('backup/copy-of-file.txt');

// Copy to different bucket
const destinationBucket = storage.bucket('other-bucket');
const [copiedFile] = await file.copy(destinationBucket.file('copied-file.txt'));

// Copy with different encryption
const [copiedFile] = await file.copy('encrypted-copy.txt', {
  destinationKmsKeyName: 'projects/PROJECT_ID/locations/us/keyRings/ring/cryptoKeys/key'
});

// Copy with ACL
const [copiedFile] = await file.copy('public-copy.txt', {
  predefinedAcl: 'publicRead'
});

Move File

move(destination: string | Bucket | File, options?: MoveOptions): Promise<MoveResponse>

interface MoveOptions {
  destinationKmsKeyName?: string;
  predefinedAcl?: PredefinedAcl;
  userProject?: string;
  preconditionOpts?: PreconditionOptions;
}

type MoveResponse = [File, unknown]; // [destinationFile, apiResponse]

// Move within same bucket
const [movedFile] = await file.move('new-location/file.txt');

// Move to different bucket
const destinationBucket = storage.bucket('archive-bucket');
const [movedFile] = await file.move(destinationBucket.file('archived-file.txt'));

// Move with encryption change
const [movedFile] = await file.move('encrypted/file.txt', {
  destinationKmsKeyName: 'projects/PROJECT_ID/locations/us/keyRings/ring/cryptoKeys/key'
});

Delete File

delete(options?: DeleteFileOptions): Promise<DeleteFileResponse>

interface DeleteFileOptions {
  ignoreNotFound?: boolean;
  userProject?: string;
  ifGenerationMatch?: number;
  ifGenerationNotMatch?: number;
  ifMetagenerationMatch?: number;
  ifMetagenerationNotMatch?: number;
}

type DeleteFileResponse = [unknown]; // [apiResponse]

// Delete file
await file.delete();

// Delete specific generation
await file.delete({
  ifGenerationMatch: 1234567890
});

// Delete ignoring not found errors
await file.delete({
  ignoreNotFound: true
});

Access Control

Make Public/Private

makePublic(): Promise<MakeFilePublicResponse>
makePrivate(options?: MakeFilePrivateOptions): Promise<MakeFilePrivateResponse>

interface MakeFilePrivateOptions {
  strict?: boolean;
  userProject?: string;
}

type MakeFilePublicResponse = [unknown]; // [apiResponse]
type MakeFilePrivateResponse = [unknown]; // [apiResponse]

// Make file publicly readable
await file.makePublic();

// Make file private
await file.makePrivate();

// Strict private (remove all access)
await file.makePrivate({
  strict: true
});

// Check if file is public
const [isPublic] = await file.isPublic();
console.log('File is public:', isPublic);

Storage Class

setStorageClass(storageClass: string, options?: SetStorageClassOptions): Promise<SetStorageClassResponse>

interface SetStorageClassOptions {
  userProject?: string;
  ifGenerationMatch?: number;
  ifGenerationNotMatch?: number;
  ifMetagenerationMatch?: number;
  ifMetagenerationNotMatch?: number;
}

type SetStorageClassResponse = [unknown]; // [apiResponse]

// Available storage classes
const storageClasses = [
  'STANDARD',
  'NEARLINE',
  'COLDLINE', 
  'ARCHIVE',
  'DURABLE_REDUCED_AVAILABILITY'
];

// Change storage class
await file.setStorageClass('COLDLINE');

// Change with precondition
await file.setStorageClass('ARCHIVE', {
  ifGenerationMatch: file.generation
});

Security and Encryption

Rotate Encryption Key

rotateEncryptionKey(encryptionKey?: string | Buffer, options?: RotateEncryptionKeyOptions): Promise<RotateEncryptionKeyResponse>

interface RotateEncryptionKeyOptions {
  kmsKeyName?: string;
  userProject?: string;
}

type RotateEncryptionKeyResponse = [File, unknown]; // [file, apiResponse]

// Generate new encryption key
const newKey = crypto.randomBytes(32).toString('base64');
const [file] = await file.rotateEncryptionKey(newKey);

// Rotate to KMS key
const [file] = await file.rotateEncryptionKey(undefined, {
  kmsKeyName: 'projects/PROJECT_ID/locations/us/keyRings/ring/cryptoKeys/key'
});

// Remove encryption (make unencrypted)
const [file] = await file.rotateEncryptionKey();

Signed URLs

getSignedUrl(config: GetSignedUrlConfig): Promise<GetSignedUrlResponse>

interface GetSignedUrlConfig {
  version: 'v2' | 'v4';
  action: 'read' | 'write' | 'delete' | 'resumable';
  expires: string | number | Date;
  accessibleAt?: string | number | Date;
  contentMd5?: string;
  contentType?: string;
  extensionHeaders?: { [key: string]: string };
  promptSaveAs?: string;
  queryParams?: { [key: string]: string };
  responseDisposition?: string;
  responseType?: string;
  virtualHostedStyle?: boolean;
  cname?: string;
}

type GetSignedUrlResponse = [string]; // [signedUrl]

// Read access (download)
const [url] = await file.getSignedUrl({
  version: 'v4',
  action: 'read',
  expires: Date.now() + 15 * 60 * 1000 // 15 minutes
});

// Write access (upload)
const [url] = await file.getSignedUrl({
  version: 'v4',
  action: 'write',
  expires: Date.now() + 60 * 60 * 1000, // 1 hour
  contentType: 'image/jpeg'
});

// With custom response headers
const [url] = await file.getSignedUrl({
  version: 'v4',
  action: 'read',
  expires: Date.now() + 3600000,
  responseType: 'application/pdf',
  responseDisposition: 'attachment; filename="document.pdf"'
});

// Resumable upload
const [url] = await file.getSignedUrl({
  version: 'v4',
  action: 'resumable',
  expires: Date.now() + 24 * 60 * 60 * 1000 // 24 hours
});

// With query parameters
const [url] = await file.getSignedUrl({
  version: 'v4',
  action: 'read',
  expires: Date.now() + 3600000,
  queryParams: {
    'response-cache-control': 'no-cache'
  }
});

Signed POST Policies

generateSignedPostPolicyV2(options: GenerateSignedPostPolicyV2Options): Promise<GenerateSignedPostPolicyV2Response>
generateSignedPostPolicyV4(options: GenerateSignedPostPolicyV4Options): Promise<GenerateSignedPostPolicyV4Response>

interface GenerateSignedPostPolicyV2Options {
  expires: string | number | Date;
  equals?: string[][];
  startsWith?: string[][];
  acl?: string;
  successRedirect?: string;
  successStatus?: string;
  contentLengthRange?: {
    min?: number;
    max?: number;
  };
}

interface GenerateSignedPostPolicyV4Options {
  expires: string | number | Date;
  conditions?: (string | string[])[];
  fields?: { [key: string]: string };
  virtualHostedStyle?: boolean;
  bucketBoundHostname?: string;
}

interface PolicyDocument {
  expiration: string;
  conditions: (string | string[] | { [key: string]: string })[];
}

interface PolicyFields {
  [key: string]: string;
}

interface SignedPostPolicyV4Output {
  url: string;
  fields: PolicyFields;
}

type GenerateSignedPostPolicyV2Response = [PolicyDocument, string]; // [policy, signature]
type GenerateSignedPostPolicyV4Response = [SignedPostPolicyV4Output]; // [signedPostPolicy]

// V2 POST policy
const [policy, signature] = await file.generateSignedPostPolicyV2({
  expires: Date.now() + 60 * 60 * 1000, // 1 hour
  contentLengthRange: {
    min: 1,
    max: 10 * 1024 * 1024 // 10MB
  }
});

// V4 POST policy (recommended)
const [signedPostPolicy] = await file.generateSignedPostPolicyV4({
  expires: Date.now() + 60 * 60 * 1000,
  conditions: [
    ['content-length-range', 1, 10 * 1024 * 1024],
    ['starts-with', '$content-type', 'image/']
  ],
  fields: {
    'x-goog-meta-user': 'user-123'
  }
});

console.log('POST URL:', signedPostPolicy.url);
console.log('Form fields:', signedPostPolicy.fields);

Utility Methods

Get Expiration Date

getExpirationDate(): Promise<GetExpirationDateResponse>

type GetExpirationDateResponse = [Date]; // [expirationDate]

// Get file expiration date (from lifecycle rules)
const [expirationDate] = await file.getExpirationDate();
if (expirationDate) {
  console.log('File expires on:', expirationDate);
} else {
  console.log('File does not have an expiration date');
}

Check Public Access

isPublic(): Promise<[boolean]>

// Check if file is publicly accessible
const [isPublic] = await file.isPublic();
console.log('File is public:', isPublic);

Predefined ACLs

type PredefinedAcl = 
  | 'authenticatedRead'
  | 'bucketOwnerFullControl'
  | 'bucketOwnerRead'
  | 'private'
  | 'projectPrivate'
  | 'publicRead'
  | 'publicReadWrite';

// Usage in upload operations
await file.save('content', {
  predefinedAcl: 'publicRead'
});

// Usage in copy operations
await file.copy('new-file.txt', {
  predefinedAcl: 'bucketOwnerFullControl'
});

Error Handling

import { ApiError } from '@google-cloud/storage';

try {
  const [contents] = await file.download();
} catch (error) {
  if (error instanceof ApiError) {
    if (error.code === 404) {
      console.log('File not found');
    } else if (error.code === 403) {
      console.log('Access denied');
    } else {
      console.error(`API Error ${error.code}: ${error.message}`);
    }
  }
}

Callback Support

All async methods support both Promise and callback patterns:

// Promise pattern (recommended)
const [contents] = await file.download();

// Callback pattern
file.download((err, contents) => {
  if (err) {
    console.error('Error:', err);
    return;
  }
  console.log('Downloaded file contents');
});

// Callback types
interface DownloadCallback {
  (err: Error | null, contents?: Buffer): void;
}

interface CopyCallback {
  (err: Error | null, copiedFile?: File, apiResponse?: unknown): void;
}

interface DeleteFileCallback {
  (err: Error | null, apiResponse?: unknown): void;
}

docs

access-control.md

authentication.md

bucket-operations.md

file-operations.md

index.md

notifications.md

storage-client.md

transfer-manager.md

utilities.md

tile.json