@causa/workspace-google 0.2.0 → 0.3.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.
@@ -21,7 +21,7 @@ const TOKEN_TTL = 3600;
21
21
  /**
22
22
  * Generates a new AppCheck token.
23
23
  */
24
- let GoogleAppCheckGenerateToken = class GoogleAppCheckGenerateToken extends WorkspaceFunction {
24
+ export let GoogleAppCheckGenerateToken = class GoogleAppCheckGenerateToken extends WorkspaceFunction {
25
25
  /**
26
26
  * The ID of the Firebase app for which the token will be generated.
27
27
  * If `undefined`, a Firebase app ID will be found in the configuration or using the API.
@@ -64,4 +64,3 @@ If the Firebase app ID is not specified, it will:
64
64
  outputFn: (token) => console.log(token),
65
65
  })
66
66
  ], GoogleAppCheckGenerateToken);
67
- export { GoogleAppCheckGenerateToken };
@@ -27,7 +27,7 @@ const DEFAULT_FIREBASE_STORAGE_SECURITY_RULE_FILE = 'storage.rules';
27
27
  * Returns a configuration with `google.firebaseStorage.securityRuleFile` set, such that the function can be used as a
28
28
  * processor.
29
29
  */
30
- let GoogleFirebaseStorageMergeRules = class GoogleFirebaseStorageMergeRules extends WorkspaceFunction {
30
+ export let GoogleFirebaseStorageMergeRules = class GoogleFirebaseStorageMergeRules extends WorkspaceFunction {
31
31
  tearDown;
32
32
  async _call(context) {
33
33
  if (this.tearDown) {
@@ -69,4 +69,3 @@ Input files are looked for in the workspace using the globs defined in google.fi
69
69
  outputFn: ({ securityRuleFile }) => console.log(securityRuleFile),
70
70
  })
71
71
  ], GoogleFirebaseStorageMergeRules);
72
- export { GoogleFirebaseStorageMergeRules };
@@ -27,7 +27,7 @@ const DEFAULT_FIRESTORE_SECURITY_RULE_FILE = 'firestore.rules';
27
27
  * Returns a configuration with `google.firestore.securityRuleFile` set, such that the function can be used as a
28
28
  * processor.
29
29
  */
30
- let GoogleFirestoreMergeRules = class GoogleFirestoreMergeRules extends WorkspaceFunction {
30
+ export let GoogleFirestoreMergeRules = class GoogleFirestoreMergeRules extends WorkspaceFunction {
31
31
  tearDown;
32
32
  async _call(context) {
33
33
  if (this.tearDown) {
@@ -69,4 +69,3 @@ Input files are looked for in the workspace using the globs defined in google.fi
69
69
  outputFn: ({ securityRuleFile }) => console.log(securityRuleFile),
70
70
  })
71
71
  ], GoogleFirestoreMergeRules);
72
- export { GoogleFirestoreMergeRules };
@@ -21,7 +21,7 @@ import { GoogleIdentityPlatformGenerateCustomToken } from './google-identity-pla
21
21
  * For this function to succeed, the `google.project` should be set, which usually means setting the environment in the
22
22
  * context. Also `google.firebase` children can be used to configure (and speed up) how tokens are generated.
23
23
  */
24
- let GoogleIdentityPlatformGenerateToken = class GoogleIdentityPlatformGenerateToken extends WorkspaceFunction {
24
+ export let GoogleIdentityPlatformGenerateToken = class GoogleIdentityPlatformGenerateToken extends WorkspaceFunction {
25
25
  /**
26
26
  * The ID of the user for which the token will be generated.
27
27
  */
@@ -71,4 +71,3 @@ Optional custom claims can be included in the signed token.`,
71
71
  outputFn: (token) => console.log(token),
72
72
  })
73
73
  ], GoogleIdentityPlatformGenerateToken);
74
- export { GoogleIdentityPlatformGenerateToken };
@@ -20,7 +20,7 @@ const MAX_SERVICE_BATCH = 20;
20
20
  /**
21
21
  * Enables GCP services defined in `google.services` for the GCP project defined in `google.project`.
22
22
  */
23
- let GoogleServicesEnable = class GoogleServicesEnable extends WorkspaceFunction {
23
+ export let GoogleServicesEnable = class GoogleServicesEnable extends WorkspaceFunction {
24
24
  tearDown;
25
25
  async _call(context) {
26
26
  if (this.tearDown) {
@@ -72,4 +72,3 @@ They will be enabled in the 'google.project' GCP project.`,
72
72
  outputFn: ({ services }) => console.log(services.join('\n')),
73
73
  })
74
74
  ], GoogleServicesEnable);
75
- export { GoogleServicesEnable };
@@ -15,8 +15,10 @@ import { GoogleIdentityPlatformGenerateCustomToken } from './google-identity-pla
15
15
  import { GoogleIdentityPlatformGenerateToken } from './google-identity-platform-generate-token.js';
16
16
  import { GoogleServicesEnable } from './google-services-enable.js';
17
17
  import { GoogleSpannerListDatabases } from './google-spanner-list-databases.js';
18
- import { ProjectGetArtefactDestinationForServiceContainer } from './project-get-artefact-destination-service-container.js';
18
+ import { ProjectGetArtefactDestinationForCloudFunctions } from './project-get-artefact-destination-cloud-functions.js';
19
+ import { ProjectGetArtefactDestinationForCloudRun } from './project-get-artefact-destination-cloud-run.js';
20
+ import { ProjectPushArtefactForCloudFunctions } from './project-push-artefact-cloud-functions.js';
19
21
  import { SecretFetchForGoogleSecretManager } from './secret-fetch-secret-manager.js';
20
22
  export function registerFunctions(context) {
21
- context.registerFunctionImplementations(EmulatorStartForFirebaseStorage, EmulatorStartForFirestore, EmulatorStartForIdentityPlatform, EmulatorStartForPubSub, EmulatorStartForSpanner, EmulatorStopForFirebaseStorage, EmulatorStopForFirestore, EmulatorStopForIdentityPlatform, EmulatorStopForPubSub, EmulatorStopForSpanner, GoogleAppCheckGenerateToken, GoogleFirebaseStorageMergeRules, GoogleFirestoreMergeRules, GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenerateToken, GoogleServicesEnable, GoogleSpannerListDatabases, ProjectGetArtefactDestinationForServiceContainer, SecretFetchForGoogleSecretManager);
23
+ context.registerFunctionImplementations(EmulatorStartForFirebaseStorage, EmulatorStartForFirestore, EmulatorStartForIdentityPlatform, EmulatorStartForPubSub, EmulatorStartForSpanner, EmulatorStopForFirebaseStorage, EmulatorStopForFirestore, EmulatorStopForIdentityPlatform, EmulatorStopForPubSub, EmulatorStopForSpanner, GoogleAppCheckGenerateToken, GoogleFirebaseStorageMergeRules, GoogleFirestoreMergeRules, GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenerateToken, GoogleServicesEnable, GoogleSpannerListDatabases, ProjectGetArtefactDestinationForCloudFunctions, ProjectGetArtefactDestinationForCloudRun, ProjectPushArtefactForCloudFunctions, SecretFetchForGoogleSecretManager);
22
24
  }
@@ -0,0 +1,11 @@
1
+ import { WorkspaceContext } from '@causa/workspace';
2
+ import { ProjectGetArtefactDestination } from '@causa/workspace-core';
3
+ /**
4
+ * Implements the {@link ProjectGetArtefactDestination} function for Cloud Functions projects.
5
+ * Cloud Functions archives are stored in a Google Cloud Storage bucket, the destination of which must be
6
+ * defined in the `google.cloudFunctions.archivesStorageLocation` configuration.
7
+ */
8
+ export declare class ProjectGetArtefactDestinationForCloudFunctions extends ProjectGetArtefactDestination {
9
+ _call(context: WorkspaceContext): Promise<string>;
10
+ _supports(context: WorkspaceContext): boolean;
11
+ }
@@ -0,0 +1,18 @@
1
+ import { ProjectGetArtefactDestination, } from '@causa/workspace-core';
2
+ /**
3
+ * Implements the {@link ProjectGetArtefactDestination} function for Cloud Functions projects.
4
+ * Cloud Functions archives are stored in a Google Cloud Storage bucket, the destination of which must be
5
+ * defined in the `google.cloudFunctions.archivesStorageLocation` configuration.
6
+ */
7
+ export class ProjectGetArtefactDestinationForCloudFunctions extends ProjectGetArtefactDestination {
8
+ async _call(context) {
9
+ const projectName = context.getOrThrow('project.name');
10
+ const archivesStorageLocation = context.getOrThrow('google.cloudFunctions.archivesStorageLocation');
11
+ return `${archivesStorageLocation}/${projectName}/${this.tag}.zip`;
12
+ }
13
+ _supports(context) {
14
+ const conf = context.asConfiguration();
15
+ return (conf.get('project.type') === 'serverlessFunctions' &&
16
+ conf.get('serverlessFunctions.platform') === 'google.cloudFunctions');
17
+ }
18
+ }
@@ -4,7 +4,7 @@ import { ProjectGetArtefactDestination } from '@causa/workspace-core';
4
4
  * Implements the {@link ProjectGetArtefactDestination} function for Cloud Run services.
5
5
  * The destination Docker repository is expected to be defined in `google.cloudRun.dockerRepository`.
6
6
  */
7
- export declare class ProjectGetArtefactDestinationForServiceContainer extends ProjectGetArtefactDestination {
7
+ export declare class ProjectGetArtefactDestinationForCloudRun extends ProjectGetArtefactDestination {
8
8
  _call(context: WorkspaceContext): Promise<string>;
9
9
  _supports(context: WorkspaceContext): boolean;
10
10
  }
@@ -3,7 +3,7 @@ import { ProjectGetArtefactDestination, } from '@causa/workspace-core';
3
3
  * Implements the {@link ProjectGetArtefactDestination} function for Cloud Run services.
4
4
  * The destination Docker repository is expected to be defined in `google.cloudRun.dockerRepository`.
5
5
  */
6
- export class ProjectGetArtefactDestinationForServiceContainer extends ProjectGetArtefactDestination {
6
+ export class ProjectGetArtefactDestinationForCloudRun extends ProjectGetArtefactDestination {
7
7
  async _call(context) {
8
8
  const projectName = context.getOrThrow('project.name');
9
9
  const dockerRepository = context.getOrThrow('google.cloudRun.dockerRepository');
@@ -0,0 +1,11 @@
1
+ import { WorkspaceContext } from '@causa/workspace';
2
+ import { ProjectPushArtefact } from '@causa/workspace-core';
3
+ /**
4
+ * Implements the {@link ProjectPushArtefact} function for Cloud Functions projects.
5
+ * This copies the local archive of the Cloud Functions project to the Google Cloud Storage URI set in
6
+ * {@link ProjectPushArtefact.destination}.
7
+ */
8
+ export declare class ProjectPushArtefactForCloudFunctions extends ProjectPushArtefact {
9
+ _call(context: WorkspaceContext): Promise<string>;
10
+ _supports(context: WorkspaceContext): boolean;
11
+ }
@@ -0,0 +1,31 @@
1
+ import { ArtefactAlreadyExistsError, ProjectPushArtefact, } from '@causa/workspace-core';
2
+ import { rm } from 'fs/promises';
3
+ import { CloudStorageService } from '../services/index.js';
4
+ /**
5
+ * Implements the {@link ProjectPushArtefact} function for Cloud Functions projects.
6
+ * This copies the local archive of the Cloud Functions project to the Google Cloud Storage URI set in
7
+ * {@link ProjectPushArtefact.destination}.
8
+ */
9
+ export class ProjectPushArtefactForCloudFunctions extends ProjectPushArtefact {
10
+ async _call(context) {
11
+ context.logger.info(`🚚 Pushing Cloud Functions archive to Cloud Storage.`);
12
+ const storageService = context.service(CloudStorageService);
13
+ const destination = storageService.getFileFromGsUri(this.destination);
14
+ if (!this.overwrite) {
15
+ const [exists] = await destination.exists();
16
+ if (exists) {
17
+ throw new ArtefactAlreadyExistsError(this.destination);
18
+ }
19
+ }
20
+ await destination.bucket.upload(this.artefact, { destination });
21
+ context.logger.info(`🚚 Successfully pushed archive to '${this.destination}'.`);
22
+ context.logger.debug(`🔥 Removing local artefact '${this.artefact}'.`);
23
+ await rm(this.artefact);
24
+ return this.destination;
25
+ }
26
+ _supports(context) {
27
+ const conf = context.asConfiguration();
28
+ return (conf.get('project.type') === 'serverlessFunctions' &&
29
+ conf.get('serverlessFunctions.platform') === 'google.cloudFunctions');
30
+ }
31
+ }
@@ -4,3 +4,5 @@ export { FirebaseEmulatorService } from './firebase-emulator.js';
4
4
  export { GcloudEmulatorService } from './gcloud-emulator.js';
5
5
  export { GoogleApisService } from './google-apis.js';
6
6
  export { GoogleSecretManagerService } from './secret-manager.js';
7
+ export * from './storage.errors.js';
8
+ export { CloudStorageService } from './storage.js';
@@ -4,3 +4,5 @@ export { FirebaseEmulatorService } from './firebase-emulator.js';
4
4
  export { GcloudEmulatorService } from './gcloud-emulator.js';
5
5
  export { GoogleApisService } from './google-apis.js';
6
6
  export { GoogleSecretManagerService } from './secret-manager.js';
7
+ export * from './storage.errors.js';
8
+ export { CloudStorageService } from './storage.js';
@@ -0,0 +1,33 @@
1
+ import { File, Storage } from '@google-cloud/storage';
2
+ /**
3
+ * A service for interacting with Google Cloud Storage.
4
+ * It exposes a singleton instance of the Google Cloud Storage client.
5
+ */
6
+ export declare class CloudStorageService {
7
+ readonly storage: Storage;
8
+ constructor();
9
+ /**
10
+ * Parses a Google Cloud Storage URI into a bucket and path.
11
+ * Cloud Storage URIs are of the form `gs://<bucket>/<path>`.
12
+ *
13
+ * @param uri The Google Cloud Storage URI.
14
+ * @returns The name of the Google Cloud Storage bucket and the path within the bucket.
15
+ */
16
+ parseGsUri(uri: string): {
17
+ /**
18
+ * The name of the Google Cloud Storage bucket.
19
+ */
20
+ readonly bucket: string;
21
+ /**
22
+ * The path within the bucket.
23
+ */
24
+ readonly path: string;
25
+ };
26
+ /**
27
+ * Parses a Google Cloud Storage URI into a {@link File}.
28
+ *
29
+ * @param uri The Google Cloud Storage URI.
30
+ * @returns The {@link File} at the given URI.
31
+ */
32
+ getFileFromGsUri(uri: string): File;
33
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * An error thrown when the Cloud Storage URI is invalid.
3
+ * Cloud Storage URIs are of the form `gs://<bucket>/<path>`.
4
+ */
5
+ export declare class InvalidCloudStorageUriError extends Error {
6
+ readonly uri: string;
7
+ constructor(uri: string);
8
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * An error thrown when the Cloud Storage URI is invalid.
3
+ * Cloud Storage URIs are of the form `gs://<bucket>/<path>`.
4
+ */
5
+ export class InvalidCloudStorageUriError extends Error {
6
+ uri;
7
+ constructor(uri) {
8
+ super(`Invalid Google Cloud Storage URI: '${uri}'.`);
9
+ this.uri = uri;
10
+ }
11
+ }
@@ -0,0 +1,36 @@
1
+ import { Storage } from '@google-cloud/storage';
2
+ import { InvalidCloudStorageUriError } from './storage.errors.js';
3
+ /**
4
+ * A service for interacting with Google Cloud Storage.
5
+ * It exposes a singleton instance of the Google Cloud Storage client.
6
+ */
7
+ export class CloudStorageService {
8
+ storage;
9
+ constructor() {
10
+ this.storage = new Storage();
11
+ }
12
+ /**
13
+ * Parses a Google Cloud Storage URI into a bucket and path.
14
+ * Cloud Storage URIs are of the form `gs://<bucket>/<path>`.
15
+ *
16
+ * @param uri The Google Cloud Storage URI.
17
+ * @returns The name of the Google Cloud Storage bucket and the path within the bucket.
18
+ */
19
+ parseGsUri(uri) {
20
+ const match = uri.match(/^gs:\/\/([^/]+)\/(.*)$/);
21
+ if (!match) {
22
+ throw new InvalidCloudStorageUriError(uri);
23
+ }
24
+ return { bucket: match[1], path: match[2] };
25
+ }
26
+ /**
27
+ * Parses a Google Cloud Storage URI into a {@link File}.
28
+ *
29
+ * @param uri The Google Cloud Storage URI.
30
+ * @returns The {@link File} at the given URI.
31
+ */
32
+ getFileFromGsUri(uri) {
33
+ const { bucket, path } = this.parseGsUri(uri);
34
+ return this.storage.bucket(bucket).file(path);
35
+ }
36
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@causa/workspace-google",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "The Causa workspace module providing many functionalities related to GCP and its services.",
5
5
  "repository": "github:causa-io/workspace-module-google",
6
6
  "license": "ISC",
@@ -31,16 +31,17 @@
31
31
  "dependencies": {
32
32
  "@causa/cli": ">= 0.3.3 < 1.0.0",
33
33
  "@causa/workspace": ">= 0.7.0 < 1.0.0",
34
- "@causa/workspace-core": ">= 0.4.0 < 1.0.0",
34
+ "@causa/workspace-core": ">= 0.6.0 < 1.0.0",
35
35
  "@google-cloud/apikeys": "^0.2.2",
36
36
  "@google-cloud/iam-credentials": "^2.0.4",
37
- "@google-cloud/pubsub": "^3.6.0",
37
+ "@google-cloud/pubsub": "^3.7.0",
38
38
  "@google-cloud/secret-manager": "^4.2.2",
39
39
  "@google-cloud/service-usage": "^2.2.2",
40
- "@google-cloud/spanner": "^6.10.0",
40
+ "@google-cloud/spanner": "^6.10.1",
41
+ "@google-cloud/storage": "^6.10.1",
41
42
  "class-validator": "^0.14.0",
42
- "firebase": "^9.22.0",
43
- "firebase-admin": "^11.8.0",
43
+ "firebase": "^9.22.1",
44
+ "firebase-admin": "^11.9.0",
44
45
  "globby": "^13.1.4",
45
46
  "google-gax": "^3.6.0",
46
47
  "googleapis": "^118.0.0",
@@ -48,8 +49,8 @@
48
49
  },
49
50
  "devDependencies": {
50
51
  "@tsconfig/node18": "^2.0.1",
51
- "@types/jest": "^29.5.1",
52
- "@types/node": "^18.16.14",
52
+ "@types/jest": "^29.5.2",
53
+ "@types/node": "^18.16.16",
53
54
  "@types/uuid": "^9.0.1",
54
55
  "copyfiles": "^2.4.1",
55
56
  "eslint": "^8.41.0",
@@ -60,6 +61,6 @@
60
61
  "rimraf": "^5.0.1",
61
62
  "ts-jest": "^29.1.0",
62
63
  "ts-node": "^10.9.1",
63
- "typescript": "^5.0.4"
64
+ "typescript": "^5.1.3"
64
65
  }
65
66
  }