Google Cloud Platform

  • npm i @pi-r/gcp

Tip

The alias gcloud can be used in place of “gcp” for the service property.

Storage

Note

npm i firebase && npm i firebase-admin (optional)

Interface

import type { StorageOptions } from "@google-cloud/storage";
import type { FirebaseOptions } from "@firebase/app";

interface GCPStorage extends CloudStorage {
    service: "gcp" | "gcloud";
    credential: string | GCPStorageCredential;
    bucket: string;
}

interface GCPStorageCredential extends StorageOptions, FirebaseOptions {
    product?: "firebase";
}

API

type Document = Record<string, any>;
type Metadata = Record<string, any>;

Authentication

using process.env
GOOGLE_APPLICATION_CREDENTIALS = "";
{
  "dataSource": {
    "credential": "main", // squared.cloud.json
    /* OR */
    "credential": {
      "keyFilename": "./gcp.json", // Path to JSON credentials
      "projectId": "nodejs"
    },
    /* OR */
    "credential": {
      "projectId": "nodejs",
      "credentials": {
        "client_email": "**********",
        "private_key": "**********",
        "type": "service_account", // Optional
        "project_id": "nodejs"
      }
    },
    /* OR */
    "credential": {
      "projectId": "nodejs", // When using GOOGLE_APPLICATION_CREDENTIALS
      "scopes": "https://www.googleapis.com/auth/cloud-platform" // Optional
    },
    /* OR */
    "credential": {
      "projectId": "nodejs",
      "apiKey": "**********",
      "authDomain": "<project-id>.firebaseapp.com",
      /* OR */
      "product": "firebase" // When using GOOGLE_APPLICATION_CREDENTIALS
    }
  }
}

Example usage

{
  "selector": "html", // Any resource
  "cloudStorage": [{
    "service": "gcp",
    "bucket": "nodejs-001",
    "credential": {/* Authentication */},
    "admin": {
      "publicRead": true, // New buckets only
      /* OR */
      "acl": "private", // See "policy"

      "configBucket": {
        "policy": { // MakeBucketPrivateOptions
          "acl": "private", // makePrivate + includeFiles + projectPrivate
          "acl": "projectPrivate", // makePrivate + allUsers (delete) + allAuthenticatedUsers (delete)
          "acl": "authenticatedRead", // projectPrivate + allAuthenticatedUsers:READER
          "acl": "publicRead", // makePublic + includeFiles
          "acl": "publicReadWrite", // publicRead + allUsers:WRITER
          "acl": [{ "entity": "allUsers", "role": "READER" } /* add */, { "entity": "allAuthenticatedUsers" } /* delete */], // Custom

          /* Unofficial aliases - gcp.setMetadata{iamConfiguration} */
          "acl": "bucketAccessUniform", // Enable uniform bucket-level access
          "acl": "bucketAccessACL" // Revert uniform bucket-level access (within 90 days)
        },
        "tags": { // gcp.setMetadata{labels}
          "key_1": "value",
          "key_2": "value"
        },
        "tags": {}, // gcp.setMetadata{labels=null}
        "website": { // gcp.setMetadata{website}
          "indexPage": "index.html", // mainPageSuffix
          "errorPage": "404.html" // notFoundPage
        },
        /* During call to "upload" */
        "create": { // gcp.createBucket{CreateBucketRequest}
          "location": "ASIA",
          "storageClass": "STANDARD" // "NEARLINE" | "COLDLINE" | "ARCHIVE"
        },
        "lifecycle": [/* LifecycleRule */], // gcp.addLifecycleRule
        "lifecycle": [/* LifecycleRule */, false], // options.append = false
        "lifecycle": [], // Delete all rules
        "cors": [/* Cors */], // gcp.setCorsConfiguration
        "cors": [], // Delete all rules
        "retentionPolicy": 86400 // gcp.setRetentionPeriod (seconds)
      }
    },
    "upload": {
      "publicRead": true, // Will not clobber existing ACLs
      "publicRead": 0, // Remove ACL without affecting other ACLs
      /* OR */
      "acl": "authenticatedRead", // "bucketOwnerFullControl" | "bucketOwnerRead" | "private" | "projectPrivate" | "publicRead"

      /* gcp.save */
      "options": { // UploadOptions
        "contentType": "text/html",
        "predefinedAcl": "publicRead", // Supplementary are public
        "metadata": {/* Metadata */} // All objects except when "metadata" is defined
      },

      /* gcp.uploadFileInChunks{chunkSizeBytes} */
      "chunkSize": "8mb", // Aligned to 1mb
      "chunkLimit": 5, // Same as "concurrencyLimit"
      "options": {
        "contentType": "image/png",
        "metadata": {/* Metadata */},
        /* UploadFileInChunksOptions - shared */
        "headers": {
          "Authorization": "",
          "x-goog-user-project": ""
        },
        "maxQueueSize": 5,
        "concurrencyLimit": 5
      },

      /* firebase.uploadBytes */
      "options": { // UploadMetadata
        "contentType": "text/html",
        "customMetadata": {/* Metadata */} // All objects except when "metadata" is defined
      },

      /* Primary object only */
      "metadata": {
        "key": "value",
        "key_delete": null
      }
    },
    "download": {
      /* gcp.createReadStream */
      "chunkSize": "", // Empty
      "chunkLimit": 1, // Will only stream when value is 1

      /* gcp.downloadFileInChunks{chunkSizeBytes} */
      "chunkSize": "32mb", // Aligned to 1mb
      "chunkLimit": 5, // Same as "concurrencyLimit"
      "options": {
        "concurrencyLimit": 5
      }
      /* Same as interface - gcp.download + firebase.getDownloadURL */
    }
  }]
}

Attention

Firebase does not support any bucket operations except emptyBucket and metadata.

Database

Interface

import type { GoogleAuthOptions } from "google-auth-library";
import type { PathType } from "@google-cloud/datastore";
import type { entity } from "@google-cloud/datastore/build/src/entity";

interface GCPDatabaseQuery extends CloudDatabase {
    source: "cloud";
    service: "gcp" | "gcloud";
    credential: string | GCPDatabaseCredential;
    product?: "firestore" | "bigquery" | "bigtable" | "datastore" | "spanner" | "firebase";
    id?: string | string[];
    params?: string | unknown[] | Document;
    database?: string;
    updateType?: 0 | 1 | 2 | 3;
    columns?: string[];
    keys?: DatastoreKey | DatastoreKey[];
    kind?: string | string[];
    orderBy?: unknown[][];
}

interface GCPDatabaseCredential extends GoogleAuthOptions {/* Empty */}

type DatastoreKey = string | PathType[] | entity.KeyOptions;

Authentication

{
  "dataSource": {
    "credential": "main", // squared.cloud.json
    /* OR */
    "credential": {/* Same as Storage */},
    /* OR */
    "credential": {
      "projectId": "nodejs",
      "apiKey": "**********",
      "authDomain": "<project-id>.firebaseapp.com",
      "databaseURL": "https://<database-name>.firebaseio.com" // Required
    }
  }
}

Example usage

Firestore

{
  "selector": "h1",
  "type": "text",
  "dataSource": {
    "source": "cloud",
    "service": "gcp",
    "product": "firestore",
    "credential": {/* Authentication */},
    "table": "demo",

    "id": "8Qnt83DSNW0eNykpuzcQ", // fs.collection(table).doc
    /* OR */
    "id": ["8Qnt83DSNW0eNykpuzcQ", "aahiEBE4qHM73JE7jom3"], // fs.getAll (table/id)
    "options": {/* ReadOptions */},
    /* OR */
    "params": ["column", "column.sub"], // fs.collection(table).findNearest
    "query": [1, 2],
    "options": {
      "limit": 1000, // Optional
      "distanceMeasure": "EUCLIDEAN"
    },
    /* OR */
    "query": [ // fs.collection(table)
      ["where", "group", "==", "Firestore"],
      ["where", "id", "==", "8Qnt83DSNW0eNykpuzcQ"],
      ["findNearest", "column", [1, 2], { "limit": 1000, "distanceMeasure": "EUCLIDEAN" }],
      ["limitToLast", 2],
      ["orderBy", "title", "asc"]
    ],
    "query": [
      ["whereAnd", // Unofficial
        ["group", "==", "Firestore"],
        ["id", "==", "8Qnt83DSNW0eNykpuzcQ"]
      ],
      ["limitToLast", 2]
    ],
    "query": [
      ["whereOr", // Unofficial
        ["id", "==", "8Qnt83DSNW0eNykpuzcQ"],
        ["id", "==", "aahiEBE4qHM73JE7jom3"]
      ],
      ["orderBy", "title", "asc"]
    ],
    "orderBy": [
      ["title", "asc"]
    ],

    "value": "<b>${title}</b>: ${description}",

    "updateType": 0, // 0 - update{exists} | 1 - create | 2 - set | 3 - set{merge}
    "update": {/* Document */}, // fs.update
    "update": {
      "key1": "__delete__", // FieldValue.delete()
      "key2": "__increment__", // FieldValue.increment(1)
      "key2": "__increment<number>__", // FieldValue.increment(number)
      "key3": "__serverTimestamp__" // FieldValue.serverTimestamp()
    },
    "id": "8Qnt83DSNW0eNykpuzcQ" // Same as item being retrieved
  }
}
  • endAt

  • endBefore

  • limit

  • limitToLast

  • offset

  • orderBy

  • select

  • startAfter

  • startAt

  • where

  • whereAnd

  • whereOr

  • withConverter

BigQuery

Note

npm i @google-cloud/bigquery

{
  "selector": "h1",
  "type": "text",
  "dataSource": {
    "source": "cloud",
    "service": "gcp",
    "product": "bigquery",
    "credential": {/* Authentication */},

    "database": "nodejs", // Dataset (optional)
    "table": "demo", // Destination table (optional)

    "query": "SELECT name, count FROM `demo.names_2014` WHERE gender = 'M' ORDER BY count DESC LIMIT 10", // bq.getQueryResults

    "params": { "name": "value" },
    "params": ["arg0" /* ? */, "arg1" /* ? */],
    "options": {/* IQuery */},

    /* Result: { "item_src": "bigquery.png", "item_alt": "BigQuery" } */
    "value": {
      "src": "item_src",
      "alt": "item_alt"
    },

    "update": "SELECT name, state FROM `bigquery-public-data.usa_names.usa_1910_current` LIMIT 10" // "database" | "database" + "table" (bq.setMetadata)
  }
}

Datastore

Note

npm i @google-cloud/datastore

{
  "selector": "h1",
  "type": "text",
  "dataSource": {
    "source": "cloud",
    "service": "gcp",
    "product": "datastore",
    "credential": {/* Authentication */},

    "keys": "task", // ds.get
    "keys": ["task", "sampletask1"], // PathType[]
    "keys": { // KeyOptions
      "namespace": "nodejs",
      "path": ["task", "sampletask3"]
    },
    "keys": ["task", ["task", "sampletask2"]],
    /* OR */
    "name": "<namespace>", // With "kind" (optional)
    "kind": "Task", // ds.runQuery (at least one parameter)
    "kind": ["Task1", "Task2"],
    "query": [
      ["filter", "done", "=", false],
      ["filter", "priority", ">=", 4],
      ["order", "priority", { "descending": true }]
    ],
    "options": {/* RunQueryOptions */},

    "value": "`<b>${this.title}</b>: ${this.description} (${this.total * 2})`", // Function template literal

    "update": {/* Document */}, // ds.save
    "keys": "task", // Same as item being retrieved
    /* OR */
    "kind": "Task",
    "query": [/* Same */]
  }
}
  • end

  • filter

  • groupBy

  • hasAncestor

  • limit

  • offset

  • order

  • select

  • start

Bigtable

Note

npm i @google-cloud/bigtable

{
  "selector": "h1",
  "type": "text",
  "dataSource": {
    "source": "cloud",
    "service": "gcp",
    "product": "bigtable",
    "credential": {/* Authentication */},
    "name": "nodejs", // Instance
    "table": "demo",

    "id": "rowKey1", // bt.get
    "columns": ["column1", "column2"],
    /* OR */
    "id": "<empty>", // bt.createReadStream

    "query": {/* Filter */}, // Overrides "filter" in GetRowOptions
    "options": {/* GetRowOptions */},

    "value": "{{if not expired}}<b>${title}</b>: ${description}{{else}}Expired{{end}}",

    "update": {/* Document */}, // bt.save
    "id": "rowKey1" // Same as item being retrieved
  }
}

Spanner

Note

npm i @google-cloud/spanner

{
  "selector": "h1",
  "type": "text",
  "dataSource": {
    "source": "cloud",
    "service": "gcp",
    "product": "spanner",
    "credential": {/* Authentication */},
    "name": "nodejs", // Instance

    "database": "sample", // Required
    "options": {
      "databasePool": {/* session-pool.SessionPoolOptions */},
      "databaseQuery": {/* protos.IQueryOptions */}
    },

    "table": "demo", // sp.table.read
    "columns": ["col1", "col2"], // Overrides "columns" in ReadRequest
    "query": { // ReadRequest
      "columns": [],
      "keys": []
    },
    "options": {
      "tableRead": {/* TimestampBounds */}
    },
    /* OR */
    "table": "<empty>", // sp.run
    "query": "SELECT 1", // DML
    "query": { "sql": "SELECT 1", "params": { "p1": 0, "p2": 1 } } // ExecuteSqlRequest

    "dynamic": true, // element.innerXml (with tags)
    "dynamic": false, // element.textContent

    "table": "demo", // sp.table.update
    "update": {/* Document */},
    "updateType": 0, // 0 - update | 1 - insert | 2 - replace
    "options": {
      "tableUpdate": {/* UpdateRowsOptions */}
    },
    /* OR */
    "table": "<empty>", // sp.runUpdate
    "update": "SELECT 1",
    "update": { "sql": "SELECT 1", "params": { "p1": 0, "p2": 1 } }
  }
}

Realtime Database

Note

npm i firebase && npm i firebase-admin (optional)

{
  "selector": "h1",
  "type": "text",
  "dataSource": {
    "source": "cloud",
    "service": "gcp",
    "product": "firebase",
    "credential": {/* Authentication */},

    "query": "path/to/ref", // rd.child
    /* OR */
    "query": "path/to/ref", // rd.query
    "orderBy": [
      ["orderByChild", "path/to/child"],
      ["startAfter", 5, "name"],
      ["limitToFirst", 1]
    ],

    "viewEngine": { "name": "ejs" },
    "value": "<b><%= title %></b>: <%= description %>",

    "update": {/* Document */}, // rd.update
    "query": "path/to/ref" // Same as item being retrieved (rd.child)
  }
}
  • endBefore

  • endAt

  • equalTo

  • limitToFirst

  • limitToLast

  • orderByChild

  • orderByKey

  • orderByPriority

  • orderByValue

  • startAt

  • startAfter

@pi-r/gcp

Added in version 0.8.0:

  • Storage action download using createReadStream with chunkLimit was implemented.

  • Firestore method findNearest as a VectorQuery and Query is supported.

Added in version 0.7.1:

  • Firestore methods where | orderBy | select supports using FieldPath params.

Added in version 0.7.0:

  • CLOUD_UPLOAD_STREAM attribute in ICloudServiceClient was enabled.

  • CLOUD_UPLOAD_CHUNK attribute in ICloudServiceClient was enabled.

  • CLOUD_DOWNLOAD_CHUNK attribute in ICloudServiceClient was enabled.

  • chunkSize | chunkLimit in CloudStorageUpload were implemented.

  • chunkSize | chunkLimit in CloudStorageDownload were implemented.

  • Storage configBucket.tags using Metadata was implemented.

  • Storage configBucket.cors using Cors was implemented.

  • Storage configBucket.lifecycle using LifecycleRule was implemented.

  • Firestore property update supports using FieldValue<”delete” | “increment” | “serverTimestamp”> methods.

  • Firestore property update supports using property updateType enum values.

Removed in version 0.7.0:

  • GCPStorageCredential no longer extends CreateBucketRequest.

Added in version 0.6.3:

  • Firestore property id supports multiple document references.

  • Firestore property query supports using Filter<”and” | “or”> conditional groups for where.

Added in version 0.6.2:

  • GoogleAuthOptions properties authClient and credentials were not detected during credential validation.

  • Datastore method createQuery with “namespace” and “kind” parameter is supported.