@causa/workspace-google 0.12.2 → 0.13.0-rc.2

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.
Files changed (92) hide show
  1. package/dist/backfilling/bigquery.d.ts +1 -1
  2. package/dist/backfilling/pubsub.d.ts +1 -1
  3. package/dist/backfilling/pubsub.js +1 -1
  4. package/dist/code-generation/google-firestore-renderer.d.ts +1 -1
  5. package/dist/code-generation/google-firestore-renderer.js +7 -8
  6. package/dist/code-generation/google-spanner-renderer.d.ts +1 -1
  7. package/dist/code-generation/google-spanner-renderer.js +5 -6
  8. package/dist/code-generation/utils.d.ts +2 -2
  9. package/dist/code-generation/utils.js +1 -1
  10. package/dist/configurations/generated.d.ts +741 -0
  11. package/dist/configurations/generated.js +1347 -0
  12. package/dist/configurations/index.d.ts +1 -1
  13. package/dist/configurations/index.js +1 -0
  14. package/dist/configurations/schemas/google.yaml +466 -0
  15. package/dist/configurations/schemas/service-container-cloud-run.yaml +212 -0
  16. package/dist/functions/causa/index.d.ts +1 -0
  17. package/dist/functions/causa/index.js +1 -0
  18. package/dist/functions/causa/list-schemas.d.ts +9 -0
  19. package/dist/functions/causa/list-schemas.js +23 -0
  20. package/dist/functions/emulator/start-firebase-storage.js +1 -1
  21. package/dist/functions/emulator/start-firestore.js +1 -1
  22. package/dist/functions/emulator/start-identity-platform.js +1 -1
  23. package/dist/functions/emulator/start-pubsub.call.d.ts +4 -0
  24. package/dist/functions/emulator/start-pubsub.call.js +57 -0
  25. package/dist/functions/emulator/start-pubsub.d.ts +0 -22
  26. package/dist/functions/emulator/start-pubsub.js +4 -75
  27. package/dist/functions/emulator/start-spanner.call.d.ts +4 -0
  28. package/dist/functions/emulator/start-spanner.call.js +92 -0
  29. package/dist/functions/emulator/start-spanner.d.ts +0 -38
  30. package/dist/functions/emulator/start-spanner.js +4 -124
  31. package/dist/functions/emulator/stop-firebase-storage.js +2 -1
  32. package/dist/functions/emulator/stop-firestore.js +2 -1
  33. package/dist/functions/emulator/stop-identity-platform.js +2 -1
  34. package/dist/functions/emulator/stop-pubsub.js +2 -1
  35. package/dist/functions/emulator/stop-spanner.js +2 -1
  36. package/dist/functions/event-topic/broker-create-topic-pubsub.call.d.ts +3 -0
  37. package/dist/functions/event-topic/broker-create-topic-pubsub.call.js +15 -0
  38. package/dist/functions/event-topic/broker-create-topic-pubsub.js +2 -14
  39. package/dist/functions/event-topic/broker-create-trigger-cloud-run.call.d.ts +3 -0
  40. package/dist/functions/event-topic/broker-create-trigger-cloud-run.call.js +24 -0
  41. package/dist/functions/event-topic/broker-create-trigger-cloud-run.js +2 -19
  42. package/dist/functions/event-topic/broker-delete-topic-pubsub.call.d.ts +3 -0
  43. package/dist/functions/event-topic/broker-delete-topic-pubsub.call.js +15 -0
  44. package/dist/functions/event-topic/broker-delete-topic-pubsub.js +2 -14
  45. package/dist/functions/event-topic/broker-delete-trigger-resource-cloud-run-invoker-role.call.d.ts +3 -0
  46. package/dist/functions/event-topic/broker-delete-trigger-resource-cloud-run-invoker-role.call.js +16 -0
  47. package/dist/functions/event-topic/broker-delete-trigger-resource-cloud-run-invoker-role.js +2 -11
  48. package/dist/functions/event-topic/broker-delete-trigger-resource-pubsub-subscription.call.d.ts +3 -0
  49. package/dist/functions/event-topic/broker-delete-trigger-resource-pubsub-subscription.call.js +16 -0
  50. package/dist/functions/event-topic/broker-delete-trigger-resource-pubsub-subscription.js +2 -18
  51. package/dist/functions/event-topic/broker-delete-trigger-resource-service-account.call.d.ts +3 -0
  52. package/dist/functions/event-topic/broker-delete-trigger-resource-service-account.call.js +15 -0
  53. package/dist/functions/event-topic/broker-delete-trigger-resource-service-account.js +2 -14
  54. package/dist/functions/event-topic/broker-publish-events-google.call.d.ts +3 -0
  55. package/dist/functions/event-topic/broker-publish-events-google.call.js +29 -0
  56. package/dist/functions/event-topic/broker-publish-events-google.d.ts +0 -7
  57. package/dist/functions/event-topic/broker-publish-events-google.js +3 -34
  58. package/dist/functions/google-app-check/generate-token.call.d.ts +3 -0
  59. package/dist/functions/google-app-check/generate-token.call.js +17 -0
  60. package/dist/functions/google-app-check/generate-token.js +2 -16
  61. package/dist/functions/google-identity-platform/generate-custom-token.call.d.ts +3 -0
  62. package/dist/functions/google-identity-platform/generate-custom-token.call.js +8 -0
  63. package/dist/functions/google-identity-platform/generate-custom-token.js +2 -7
  64. package/dist/functions/google-identity-platform/generate-token.call.d.ts +3 -0
  65. package/dist/functions/google-identity-platform/generate-token.call.js +13 -0
  66. package/dist/functions/google-identity-platform/generate-token.js +2 -12
  67. package/dist/functions/google-services/enable.call.d.ts +7 -0
  68. package/dist/functions/google-services/enable.call.js +35 -0
  69. package/dist/functions/google-services/enable.js +2 -34
  70. package/dist/functions/index.js +2 -1
  71. package/dist/functions/project/push-artefact-cloud-functions.call.d.ts +3 -0
  72. package/dist/functions/project/push-artefact-cloud-functions.call.js +19 -0
  73. package/dist/functions/project/push-artefact-cloud-functions.js +3 -18
  74. package/dist/functions/secret/fetch-access-token.call.d.ts +3 -0
  75. package/dist/functions/secret/fetch-access-token.call.js +10 -0
  76. package/dist/functions/secret/fetch-access-token.js +2 -8
  77. package/dist/functions/secret/fetch-secret-manager.call.d.ts +3 -0
  78. package/dist/functions/secret/fetch-secret-manager.call.js +32 -0
  79. package/dist/functions/secret/fetch-secret-manager.js +2 -29
  80. package/dist/functions/typescript/get-decorator-renderer-google-firestore.d.ts +3 -3
  81. package/dist/functions/typescript/get-decorator-renderer-google-firestore.js +4 -4
  82. package/dist/functions/typescript/get-decorator-renderer-google-spanner.d.ts +3 -3
  83. package/dist/functions/typescript/get-decorator-renderer-google-spanner.js +4 -4
  84. package/dist/index.d.ts +1 -2
  85. package/dist/index.js +1 -2
  86. package/dist/services/firebase-emulator.d.ts +1 -1
  87. package/dist/services/firebase-emulator.js +1 -1
  88. package/dist/services/gcloud-emulator.d.ts +1 -1
  89. package/dist/services/gcloud-emulator.js +1 -1
  90. package/package.json +14 -11
  91. package/dist/configurations/google.d.ts +0 -305
  92. package/dist/configurations/google.js +0 -1
@@ -0,0 +1,9 @@
1
+ import { CausaListConfigurationSchemas } from '@causa/workspace-core';
2
+ /**
3
+ * Implements {@link CausaListConfigurationSchemas} for the Google module.
4
+ * Returns the paths to the configuration schemas bundled with this package.
5
+ */
6
+ export declare class CausaListConfigurationSchemasForGoogle extends CausaListConfigurationSchemas {
7
+ _call(): Promise<string[]>;
8
+ _supports(): boolean;
9
+ }
@@ -0,0 +1,23 @@
1
+ import { CausaListConfigurationSchemas } from '@causa/workspace-core';
2
+ import { globby } from 'globby';
3
+ import { dirname, resolve } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ /**
6
+ * The directory containing the configuration schemas provided by this module.
7
+ */
8
+ const SCHEMAS_DIRECTORY = resolve(dirname(fileURLToPath(import.meta.url)), '../../configurations/schemas');
9
+ /**
10
+ * Implements {@link CausaListConfigurationSchemas} for the Google module.
11
+ * Returns the paths to the configuration schemas bundled with this package.
12
+ */
13
+ export class CausaListConfigurationSchemasForGoogle extends CausaListConfigurationSchemas {
14
+ async _call() {
15
+ return await globby('*.yaml', {
16
+ cwd: SCHEMAS_DIRECTORY,
17
+ absolute: true,
18
+ });
19
+ }
20
+ _supports() {
21
+ return true;
22
+ }
23
+ }
@@ -2,7 +2,7 @@ import { WorkspaceContext } from '@causa/workspace';
2
2
  import { EmulatorStart } from '@causa/workspace-core';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { FIREBASE_CONTAINER_STORAGE_RULES_FILE, FIREBASE_STORAGE_EMULATOR_NAME, FIREBASE_STORAGE_PORT, getFirebaseStorageContainerName, } from '../../emulators/index.js';
5
- import { FirebaseEmulatorService } from '../../services/index.js';
5
+ import { FirebaseEmulatorService } from '../../services/firebase-emulator.js';
6
6
  import { GoogleFirebaseStorageMergeRules } from '../google-firebase-storage/index.js';
7
7
  /**
8
8
  * The Firebase configuration file enabling only the Storage emulator.
@@ -1,7 +1,7 @@
1
1
  import { WorkspaceContext } from '@causa/workspace';
2
2
  import { EmulatorStart } from '@causa/workspace-core';
3
3
  import { FIRESTORE_CONTAINER_RULES_FILE, FIRESTORE_EMULATOR_NAME, FIRESTORE_PORT, getFirestoreContainerName, } from '../../emulators/index.js';
4
- import { GcloudEmulatorService } from '../../services/index.js';
4
+ import { GcloudEmulatorService } from '../../services/gcloud-emulator.js';
5
5
  import { GoogleFirestoreMergeRules } from '../google-firestore/index.js';
6
6
  /**
7
7
  * Implements {@link EmulatorStart} for the Firestore emulator.
@@ -2,7 +2,7 @@ import { WorkspaceContext } from '@causa/workspace';
2
2
  import { EmulatorStart } from '@causa/workspace-core';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { FIREBASE_AUTH_PORT, IDENTITY_PLATFORM_EMULATOR_NAME, getIdentityPlatformContainerName, } from '../../emulators/index.js';
5
- import { FirebaseEmulatorService } from '../../services/index.js';
5
+ import { FirebaseEmulatorService } from '../../services/firebase-emulator.js';
6
6
  /**
7
7
  * The Firebase configuration file enabling only the Auth emulator.
8
8
  */
@@ -0,0 +1,4 @@
1
+ import type { WorkspaceContext } from '@causa/workspace';
2
+ import { type EmulatorStartResult } from '@causa/workspace-core';
3
+ import type { EmulatorStartForPubSub } from './start-pubsub.js';
4
+ export default function call(this: EmulatorStartForPubSub, context: WorkspaceContext): Promise<EmulatorStartResult>;
@@ -0,0 +1,57 @@
1
+ import { EventTopicList, } from '@causa/workspace-core';
2
+ import { PubSub } from '@google-cloud/pubsub';
3
+ import { getLocalGcpProject } from '../../configurations/utils.js';
4
+ import { PUBSUB_EMULATOR_NAME, PUBSUB_PORT, formatPubSubTopicAsEnvironmentVariable, getPubSubContainerName, } from '../../emulators/index.js';
5
+ import { GcloudEmulatorService } from '../../services/gcloud-emulator.js';
6
+ export default async function call(context) {
7
+ const configuration = await startPubSub(this, context);
8
+ return { name: PUBSUB_EMULATOR_NAME, configuration };
9
+ }
10
+ async function startPubSub(self, context) {
11
+ if (self.dryRun) {
12
+ return {};
13
+ }
14
+ const emulatorConf = await startPubSubEmulator(context);
15
+ const topicsConf = await createTopicsIfNeeded(context);
16
+ context.logger.info('📫 Successfully initialized Pub/Sub emulator.');
17
+ return { ...emulatorConf, ...topicsConf };
18
+ }
19
+ async function startPubSubEmulator(context) {
20
+ context.logger.info('📫 Starting Pub/Sub emulator.');
21
+ const gcpProject = getLocalGcpProject(context);
22
+ const containerName = getPubSubContainerName(context);
23
+ const gcloudEmulatorService = context.service(GcloudEmulatorService);
24
+ await gcloudEmulatorService.start('pubsub', containerName, [{ host: '127.0.0.1', local: PUBSUB_PORT, container: PUBSUB_PORT }], {
25
+ availabilityEndpoint: `http://127.0.0.1:${PUBSUB_PORT}/v1/projects/${gcpProject}/topics`,
26
+ });
27
+ return {
28
+ PUBSUB_EMULATOR_HOST: `127.0.0.1:${PUBSUB_PORT}`,
29
+ GOOGLE_CLOUD_PROJECT: gcloudEmulatorService.localGcpProject,
30
+ GCP_PROJECT: gcloudEmulatorService.localGcpProject,
31
+ GCLOUD_PROJECT: gcloudEmulatorService.localGcpProject,
32
+ };
33
+ }
34
+ async function createTopicsIfNeeded(context) {
35
+ if (context.get('events.broker') !== 'google.pubSub') {
36
+ context.logger.warn('📫️ Pub/Sub is not set as the event broker. Skipping event topics setup.');
37
+ return {};
38
+ }
39
+ const topics = await context.call(EventTopicList, {});
40
+ const gcpProject = getLocalGcpProject(context);
41
+ const pubSub = new PubSub({
42
+ projectId: gcpProject,
43
+ apiEndpoint: `127.0.0.1:${PUBSUB_PORT}`,
44
+ });
45
+ const envVars = await Promise.all(topics.map(async ({ id }) => {
46
+ context.logger.info(`📫 Creating Pub/Sub emulator topic '${id}'.`);
47
+ const [topic] = await pubSub.topic(id).create();
48
+ return {
49
+ envVar: formatPubSubTopicAsEnvironmentVariable(id),
50
+ pubSubTopic: topic.name,
51
+ };
52
+ }));
53
+ return envVars.reduce((vars, { envVar, pubSubTopic }) => {
54
+ vars[envVar] = pubSubTopic;
55
+ return vars;
56
+ }, {});
57
+ }
@@ -8,26 +8,4 @@ import { EmulatorStart, type EmulatorStartResult } from '@causa/workspace-core';
8
8
  export declare class EmulatorStartForPubSub extends EmulatorStart {
9
9
  _call(context: WorkspaceContext): Promise<EmulatorStartResult>;
10
10
  _supports(): boolean;
11
- /**
12
- * Starts the Pub/Sub emulator and creates the topics defined in the workspace.
13
- *
14
- * @param context The {@link WorkspaceContext}.
15
- * @returns The configuration for the emulator and the local Pub/Sub topics.
16
- */
17
- private startPubSub;
18
- /**
19
- * Starts the Pub/Sub emulator.
20
- *
21
- * @param context The {@link WorkspaceContext}.
22
- * @returns The configuration for the Pub/Sub emulator.
23
- */
24
- private startPubSubEmulator;
25
- /**
26
- * Creates the Pub/Sub topics corresponding to the event topics defined in the workspace.
27
- * This is only performed if Pub/Sub is defined as the broker for the workspace.
28
- *
29
- * @param context The {@link WorkspaceContext}.
30
- * @returns The configuration listing the local Pub/Sub topics.
31
- */
32
- private createTopicsIfNeeded;
33
11
  }
@@ -1,9 +1,6 @@
1
- import { WorkspaceContext } from '@causa/workspace';
2
- import { EmulatorStart, EventTopicList, } from '@causa/workspace-core';
3
- import { PubSub } from '@google-cloud/pubsub';
4
- import { getLocalGcpProject } from '../../configurations/utils.js';
5
- import { PUBSUB_EMULATOR_NAME, PUBSUB_PORT, formatPubSubTopicAsEnvironmentVariable, getPubSubContainerName, } from '../../emulators/index.js';
6
- import { GcloudEmulatorService } from '../../services/index.js';
1
+ import { callDeferred, WorkspaceContext } from '@causa/workspace';
2
+ import { EmulatorStart } from '@causa/workspace-core';
3
+ import { PUBSUB_EMULATOR_NAME } from '../../emulators/index.js';
7
4
  /**
8
5
  * Implements {@link EmulatorStart} for the Pub/Sub emulator.
9
6
  * This first starts the Pub/Sub emulator, and then creates the topics defined in the workspace (if the workspace is
@@ -11,77 +8,9 @@ import { GcloudEmulatorService } from '../../services/index.js';
11
8
  */
12
9
  export class EmulatorStartForPubSub extends EmulatorStart {
13
10
  async _call(context) {
14
- const configuration = await this.startPubSub(context);
15
- return { name: PUBSUB_EMULATOR_NAME, configuration };
11
+ return await callDeferred(this, context, import.meta.url);
16
12
  }
17
13
  _supports() {
18
14
  return this.name === undefined || this.name === PUBSUB_EMULATOR_NAME;
19
15
  }
20
- /**
21
- * Starts the Pub/Sub emulator and creates the topics defined in the workspace.
22
- *
23
- * @param context The {@link WorkspaceContext}.
24
- * @returns The configuration for the emulator and the local Pub/Sub topics.
25
- */
26
- async startPubSub(context) {
27
- if (this.dryRun) {
28
- return {};
29
- }
30
- const emulatorConf = await this.startPubSubEmulator(context);
31
- const topicsConf = await this.createTopicsIfNeeded(context);
32
- context.logger.info('📫 Successfully initialized Pub/Sub emulator.');
33
- return { ...emulatorConf, ...topicsConf };
34
- }
35
- /**
36
- * Starts the Pub/Sub emulator.
37
- *
38
- * @param context The {@link WorkspaceContext}.
39
- * @returns The configuration for the Pub/Sub emulator.
40
- */
41
- async startPubSubEmulator(context) {
42
- context.logger.info('📫 Starting Pub/Sub emulator.');
43
- const gcpProject = getLocalGcpProject(context);
44
- const containerName = getPubSubContainerName(context);
45
- const gcloudEmulatorService = context.service(GcloudEmulatorService);
46
- await gcloudEmulatorService.start('pubsub', containerName, [{ host: '127.0.0.1', local: PUBSUB_PORT, container: PUBSUB_PORT }], {
47
- availabilityEndpoint: `http://127.0.0.1:${PUBSUB_PORT}/v1/projects/${gcpProject}/topics`,
48
- });
49
- return {
50
- PUBSUB_EMULATOR_HOST: `127.0.0.1:${PUBSUB_PORT}`,
51
- GOOGLE_CLOUD_PROJECT: gcloudEmulatorService.localGcpProject,
52
- GCP_PROJECT: gcloudEmulatorService.localGcpProject,
53
- GCLOUD_PROJECT: gcloudEmulatorService.localGcpProject,
54
- };
55
- }
56
- /**
57
- * Creates the Pub/Sub topics corresponding to the event topics defined in the workspace.
58
- * This is only performed if Pub/Sub is defined as the broker for the workspace.
59
- *
60
- * @param context The {@link WorkspaceContext}.
61
- * @returns The configuration listing the local Pub/Sub topics.
62
- */
63
- async createTopicsIfNeeded(context) {
64
- if (context.get('events.broker') !== 'google.pubSub') {
65
- context.logger.warn('📫️ Pub/Sub is not set as the event broker. Skipping event topics setup.');
66
- return {};
67
- }
68
- const topics = await context.call(EventTopicList, {});
69
- const gcpProject = getLocalGcpProject(context);
70
- const pubSub = new PubSub({
71
- projectId: gcpProject,
72
- apiEndpoint: `127.0.0.1:${PUBSUB_PORT}`,
73
- });
74
- const envVars = await Promise.all(topics.map(async ({ id }) => {
75
- context.logger.info(`📫 Creating Pub/Sub emulator topic '${id}'.`);
76
- const [topic] = await pubSub.topic(id).create();
77
- return {
78
- envVar: formatPubSubTopicAsEnvironmentVariable(id),
79
- pubSubTopic: topic.name,
80
- };
81
- }));
82
- return envVars.reduce((vars, { envVar, pubSubTopic }) => {
83
- vars[envVar] = pubSubTopic;
84
- return vars;
85
- }, {});
86
- }
87
16
  }
@@ -0,0 +1,4 @@
1
+ import type { WorkspaceContext } from '@causa/workspace';
2
+ import type { EmulatorStartResult } from '@causa/workspace-core';
3
+ import type { EmulatorStartForSpanner } from './start-spanner.js';
4
+ export default function call(this: EmulatorStartForSpanner, context: WorkspaceContext): Promise<EmulatorStartResult>;
@@ -0,0 +1,92 @@
1
+ import { DockerEmulatorService } from '@causa/workspace-core/services';
2
+ import { Instance, Spanner } from '@google-cloud/spanner';
3
+ // The Spanner client depends on `google-gax` rather than `@grpc/grpc-js` directly. By ensuring `google-gax` is kept in
4
+ // sync with the version required by Spanner, and importing `grpc` from `google-gax`, the correct `grpc.credentials`
5
+ // version can be loaded.
6
+ import { grpc } from 'google-gax';
7
+ import { getLocalGcpProject, } from '../../configurations/index.js';
8
+ import { SPANNER_EMULATOR_NAME, SPANNER_GRPC_PORT, SPANNER_HTTP_PORT, SPANNER_IMAGE, getSpannerContainerName, } from '../../emulators/index.js';
9
+ import { GoogleSpannerListDatabases } from '../google-spanner/index.js';
10
+ export default async function call(context) {
11
+ const configuration = await startSpanner(this, context);
12
+ return { name: SPANNER_EMULATOR_NAME, configuration };
13
+ }
14
+ async function startSpanner(self, context) {
15
+ if (self.dryRun) {
16
+ return {};
17
+ }
18
+ const emulatorConf = await startSpannerEmulator(context);
19
+ const instanceAndDatabaseConf = await initializeEmulator(context);
20
+ context.logger.info('🗃️ Successfully initialized Spanner emulator.');
21
+ return { ...emulatorConf, ...instanceAndDatabaseConf };
22
+ }
23
+ async function startSpannerEmulator(context) {
24
+ context.logger.info('🗃️ Starting Spanner emulator.');
25
+ const gcpProject = getLocalGcpProject(context);
26
+ const containerName = getSpannerContainerName(context);
27
+ const imageVersion = context
28
+ .asConfiguration()
29
+ .get('google.spanner.emulator.version') ?? 'latest';
30
+ const dockerEmulatorService = context.service(DockerEmulatorService);
31
+ await dockerEmulatorService.start(`${SPANNER_IMAGE}:${imageVersion}`, containerName, [SPANNER_GRPC_PORT, SPANNER_HTTP_PORT].map((p) => ({
32
+ host: '127.0.0.1',
33
+ local: p,
34
+ container: p,
35
+ })));
36
+ await dockerEmulatorService.waitForAvailability(containerName, `http://127.0.0.1:${SPANNER_HTTP_PORT}/v1/projects/${gcpProject}/instances`);
37
+ return {
38
+ SPANNER_EMULATOR_HOST: `127.0.0.1:${SPANNER_GRPC_PORT}`,
39
+ GOOGLE_CLOUD_PROJECT: gcpProject,
40
+ GCP_PROJECT: gcpProject,
41
+ GCLOUD_PROJECT: gcpProject,
42
+ };
43
+ }
44
+ async function initializeEmulator(context) {
45
+ const spanner = new Spanner({
46
+ servicePath: '127.0.0.1',
47
+ port: SPANNER_GRPC_PORT,
48
+ projectId: getLocalGcpProject(context),
49
+ sslCreds: grpc.credentials.createInsecure(),
50
+ });
51
+ const { instance, instanceConf } = await createInstance(spanner, context);
52
+ const databaseConf = await createDatabases(instance, context);
53
+ spanner.close();
54
+ return { ...instanceConf, ...databaseConf };
55
+ }
56
+ async function createInstance(spanner, context) {
57
+ const instanceName = context
58
+ .asConfiguration()
59
+ .get('google.spanner.emulator.instanceName') ?? 'local';
60
+ context.logger.info(`🗃️ Creating Spanner emulator instance '${instanceName}'.`);
61
+ const [instance, operation] = await spanner.createInstance(instanceName, {
62
+ config: 'emulator-config',
63
+ displayName: instanceName,
64
+ processingUnits: 100,
65
+ });
66
+ await operation.promise();
67
+ return { instance, instanceConf: { SPANNER_INSTANCE: instanceName } };
68
+ }
69
+ async function createDatabases(instance, context) {
70
+ const databases = await context.call(GoogleSpannerListDatabases, {});
71
+ await Promise.all(databases.map(async (database) => {
72
+ context.logger.info(`🗃️ Creating Spanner emulator database '${database.id}'.`);
73
+ // Discarding `DROP TABLE` statements as the emulator does not seem to handle them properly.
74
+ const ddls = database.ddls.filter((statement) => !statement.toUpperCase().startsWith('DROP TABLE'));
75
+ const [db, operation] = await instance.createDatabase(database.id, {
76
+ schema: ddls,
77
+ });
78
+ // While unlikely, the database object might emit errors, e.g "The client has already been closed.".
79
+ // These errors could simply be ignored, as awaiting on the operation should be enough to ensure the database is
80
+ // created. However they are logged as warnings for completeness.
81
+ db.on('error', (error) => {
82
+ context.logger.warn(`⚠️ Uncaught Spanner database error: '${error.message}'.`);
83
+ });
84
+ await operation.promise();
85
+ await db.close();
86
+ }));
87
+ return databases.length === 0
88
+ ? {}
89
+ : {
90
+ SPANNER_DATABASE: databases.map((database) => database.id).join('|'),
91
+ };
92
+ }
@@ -7,42 +7,4 @@ import { EmulatorStart, type EmulatorStartResult } from '@causa/workspace-core';
7
7
  export declare class EmulatorStartForSpanner extends EmulatorStart {
8
8
  _call(context: WorkspaceContext): Promise<EmulatorStartResult>;
9
9
  _supports(): boolean;
10
- /**
11
- * Starts the Spanner emulator, and creates the instance and databases within it.
12
- *
13
- * @param context The {@link WorkspaceContext}.
14
- * @returns The configuration for the emulator, instance and databases.
15
- */
16
- private startSpanner;
17
- /**
18
- * Starts the Spanner emulator.
19
- * The emulator is defined in a separate Docker image, not part of the `gcloud` CLI emulators.
20
- *
21
- * @param context The {@link WorkspaceContext}.
22
- * @returns The configuration for the Spanner emulator.
23
- */
24
- private startSpannerEmulator;
25
- /**
26
- * Creates the Spanner instance and databases within the emulator.
27
- *
28
- * @param context The {@link WorkspaceContext}.
29
- * @returns The configuration for the created instance and databases.
30
- */
31
- private initializeEmulator;
32
- /**
33
- * Creates a local instance within the Spanner emulator.
34
- *
35
- * @param spanner The {@link Spanner} client.
36
- * @param context The {@link WorkspaceContext}.
37
- * @returns The created Spanner {@link Instance} and the corresponding client configuration.
38
- */
39
- private createInstance;
40
- /**
41
- * Creates the Spanner databases within the given instance, along with their DDL statements found in the workspace.
42
- *
43
- * @param instance The Spanner {@link Instance} in which the databases should be created.
44
- * @param context The {@link WorkspaceContext}.
45
- * @returns The configuration for the created databases.
46
- */
47
- private createDatabases;
48
10
  }
@@ -1,135 +1,15 @@
1
- import { WorkspaceContext } from '@causa/workspace';
2
- import { DockerEmulatorService, EmulatorStart, } from '@causa/workspace-core';
3
- import { Instance, Spanner } from '@google-cloud/spanner';
4
- // The Spanner client depends on `google-gax` rather than `@grpc/grpc-js` directly. By ensuring `google-gax` is kept in
5
- // sync with the version required by Spanner, and importing `grpc` from `google-gax`, the correct `grpc.credentials`
6
- // version can be loaded.
7
- import { grpc } from 'google-gax';
8
- import { getLocalGcpProject, } from '../../configurations/index.js';
9
- import { SPANNER_EMULATOR_NAME, SPANNER_GRPC_PORT, SPANNER_HTTP_PORT, SPANNER_IMAGE, getSpannerContainerName, } from '../../emulators/index.js';
10
- import { GoogleSpannerListDatabases } from '../google-spanner/index.js';
1
+ import { callDeferred, WorkspaceContext } from '@causa/workspace';
2
+ import { EmulatorStart } from '@causa/workspace-core';
3
+ import { SPANNER_EMULATOR_NAME } from '../../emulators/index.js';
11
4
  /**
12
5
  * Implements {@link EmulatorStart} for the Spanner emulator.
13
6
  * This starts the emulator, creates a local instance, and creates the databases using the DDLs found in the workspace.
14
7
  */
15
8
  export class EmulatorStartForSpanner extends EmulatorStart {
16
9
  async _call(context) {
17
- const configuration = await this.startSpanner(context);
18
- return { name: SPANNER_EMULATOR_NAME, configuration };
10
+ return await callDeferred(this, context, import.meta.url);
19
11
  }
20
12
  _supports() {
21
13
  return this.name === undefined || this.name === SPANNER_EMULATOR_NAME;
22
14
  }
23
- /**
24
- * Starts the Spanner emulator, and creates the instance and databases within it.
25
- *
26
- * @param context The {@link WorkspaceContext}.
27
- * @returns The configuration for the emulator, instance and databases.
28
- */
29
- async startSpanner(context) {
30
- if (this.dryRun) {
31
- return {};
32
- }
33
- const emulatorConf = await this.startSpannerEmulator(context);
34
- const instanceAndDatabaseConf = await this.initializeEmulator(context);
35
- context.logger.info('🗃️ Successfully initialized Spanner emulator.');
36
- return { ...emulatorConf, ...instanceAndDatabaseConf };
37
- }
38
- /**
39
- * Starts the Spanner emulator.
40
- * The emulator is defined in a separate Docker image, not part of the `gcloud` CLI emulators.
41
- *
42
- * @param context The {@link WorkspaceContext}.
43
- * @returns The configuration for the Spanner emulator.
44
- */
45
- async startSpannerEmulator(context) {
46
- context.logger.info('🗃️ Starting Spanner emulator.');
47
- const gcpProject = getLocalGcpProject(context);
48
- const containerName = getSpannerContainerName(context);
49
- const imageVersion = context
50
- .asConfiguration()
51
- .get('google.spanner.emulator.version') ?? 'latest';
52
- const dockerEmulatorService = context.service(DockerEmulatorService);
53
- await dockerEmulatorService.start(`${SPANNER_IMAGE}:${imageVersion}`, containerName, [SPANNER_GRPC_PORT, SPANNER_HTTP_PORT].map((p) => ({
54
- host: '127.0.0.1',
55
- local: p,
56
- container: p,
57
- })));
58
- await dockerEmulatorService.waitForAvailability(containerName, `http://127.0.0.1:${SPANNER_HTTP_PORT}/v1/projects/${gcpProject}/instances`);
59
- return {
60
- SPANNER_EMULATOR_HOST: `127.0.0.1:${SPANNER_GRPC_PORT}`,
61
- GOOGLE_CLOUD_PROJECT: gcpProject,
62
- GCP_PROJECT: gcpProject,
63
- GCLOUD_PROJECT: gcpProject,
64
- };
65
- }
66
- /**
67
- * Creates the Spanner instance and databases within the emulator.
68
- *
69
- * @param context The {@link WorkspaceContext}.
70
- * @returns The configuration for the created instance and databases.
71
- */
72
- async initializeEmulator(context) {
73
- const spanner = new Spanner({
74
- servicePath: '127.0.0.1',
75
- port: SPANNER_GRPC_PORT,
76
- projectId: getLocalGcpProject(context),
77
- sslCreds: grpc.credentials.createInsecure(),
78
- });
79
- const { instance, instanceConf } = await this.createInstance(spanner, context);
80
- const databaseConf = await this.createDatabases(instance, context);
81
- spanner.close();
82
- return { ...instanceConf, ...databaseConf };
83
- }
84
- /**
85
- * Creates a local instance within the Spanner emulator.
86
- *
87
- * @param spanner The {@link Spanner} client.
88
- * @param context The {@link WorkspaceContext}.
89
- * @returns The created Spanner {@link Instance} and the corresponding client configuration.
90
- */
91
- async createInstance(spanner, context) {
92
- const instanceName = context
93
- .asConfiguration()
94
- .get('google.spanner.emulator.instanceName') ?? 'local';
95
- context.logger.info(`🗃️ Creating Spanner emulator instance '${instanceName}'.`);
96
- const [instance, operation] = await spanner.createInstance(instanceName, {
97
- config: 'emulator-config',
98
- displayName: instanceName,
99
- processingUnits: 100,
100
- });
101
- await operation.promise();
102
- return { instance, instanceConf: { SPANNER_INSTANCE: instanceName } };
103
- }
104
- /**
105
- * Creates the Spanner databases within the given instance, along with their DDL statements found in the workspace.
106
- *
107
- * @param instance The Spanner {@link Instance} in which the databases should be created.
108
- * @param context The {@link WorkspaceContext}.
109
- * @returns The configuration for the created databases.
110
- */
111
- async createDatabases(instance, context) {
112
- const databases = await context.call(GoogleSpannerListDatabases, {});
113
- await Promise.all(databases.map(async (database) => {
114
- context.logger.info(`🗃️ Creating Spanner emulator database '${database.id}'.`);
115
- // Discarding `DROP TABLE` statements as the emulator does not seem to handle them properly.
116
- const ddls = database.ddls.filter((statement) => !statement.toUpperCase().startsWith('DROP TABLE'));
117
- const [db, operation] = await instance.createDatabase(database.id, {
118
- schema: ddls,
119
- });
120
- // While unlikely, the database object might emit errors, e.g "The client has already been closed.".
121
- // These errors could simply be ignored, as awaiting on the operation should be enough to ensure the database is
122
- // created. However they are logged as warnings for completeness.
123
- db.on('error', (error) => {
124
- context.logger.warn(`⚠️ Uncaught Spanner database error: '${error.message}'.`);
125
- });
126
- await operation.promise();
127
- await db.close();
128
- }));
129
- return databases.length === 0
130
- ? {}
131
- : {
132
- SPANNER_DATABASE: databases.map((database) => database.id).join('|'),
133
- };
134
- }
135
15
  }
@@ -1,5 +1,6 @@
1
1
  import { WorkspaceContext } from '@causa/workspace';
2
- import { DockerEmulatorService, EmulatorStop } from '@causa/workspace-core';
2
+ import { EmulatorStop } from '@causa/workspace-core';
3
+ import { DockerEmulatorService } from '@causa/workspace-core/services';
3
4
  import { FIREBASE_STORAGE_EMULATOR_NAME, getFirebaseStorageContainerName, } from '../../emulators/index.js';
4
5
  /**
5
6
  * Implements {@link EmulatorStop} for the Firebase Storage emulator.
@@ -1,5 +1,6 @@
1
1
  import { WorkspaceContext } from '@causa/workspace';
2
- import { DockerEmulatorService, EmulatorStop } from '@causa/workspace-core';
2
+ import { EmulatorStop } from '@causa/workspace-core';
3
+ import { DockerEmulatorService } from '@causa/workspace-core/services';
3
4
  import { FIRESTORE_EMULATOR_NAME, getFirestoreContainerName, } from '../../emulators/index.js';
4
5
  /**
5
6
  * Implements {@link EmulatorStop} for the Firestore emulator.
@@ -1,5 +1,6 @@
1
1
  import { WorkspaceContext } from '@causa/workspace';
2
- import { DockerEmulatorService, EmulatorStop } from '@causa/workspace-core';
2
+ import { EmulatorStop } from '@causa/workspace-core';
3
+ import { DockerEmulatorService } from '@causa/workspace-core/services';
3
4
  import { IDENTITY_PLATFORM_EMULATOR_NAME, getIdentityPlatformContainerName, } from '../../emulators/index.js';
4
5
  /**
5
6
  * Implements {@link EmulatorStop} for the Identity Platform emulator.
@@ -1,5 +1,6 @@
1
1
  import { WorkspaceContext } from '@causa/workspace';
2
- import { DockerEmulatorService, EmulatorStop } from '@causa/workspace-core';
2
+ import { EmulatorStop } from '@causa/workspace-core';
3
+ import { DockerEmulatorService } from '@causa/workspace-core/services';
3
4
  import { PUBSUB_EMULATOR_NAME, getPubSubContainerName, } from '../../emulators/index.js';
4
5
  /**
5
6
  * Implements {@link EmulatorStop} for the Pub/Sub emulator.
@@ -1,5 +1,6 @@
1
1
  import { WorkspaceContext } from '@causa/workspace';
2
- import { DockerEmulatorService, EmulatorStop } from '@causa/workspace-core';
2
+ import { EmulatorStop } from '@causa/workspace-core';
3
+ import { DockerEmulatorService } from '@causa/workspace-core/services';
3
4
  import { SPANNER_EMULATOR_NAME, getSpannerContainerName, } from '../../emulators/index.js';
4
5
  /**
5
6
  * Implements {@link EmulatorStop} for the Spanner emulator.
@@ -0,0 +1,3 @@
1
+ import type { WorkspaceContext } from '@causa/workspace';
2
+ import type { EventTopicBrokerCreateTopicForPubSub } from './broker-create-topic-pubsub.js';
3
+ export default function call(this: EventTopicBrokerCreateTopicForPubSub, context: WorkspaceContext): Promise<string>;
@@ -0,0 +1,15 @@
1
+ import { PubSubService } from '../../services/pubsub.js';
2
+ export default async function call(context) {
3
+ const googleConf = context.asConfiguration();
4
+ const projectId = googleConf.getOrThrow('google.project');
5
+ const region = googleConf.get('google.region');
6
+ const topicId = `projects/${projectId}/topics/${this.name}`;
7
+ context.logger.info(`📫 Creating Pub/Sub topic '${topicId}'.`);
8
+ await context.service(PubSubService).pubSub.createTopic({
9
+ name: topicId,
10
+ ...(region
11
+ ? { messageStoragePolicy: { allowedPersistenceRegions: [region] } }
12
+ : {}),
13
+ });
14
+ return topicId;
15
+ }
@@ -1,6 +1,5 @@
1
- import { WorkspaceContext } from '@causa/workspace';
1
+ import { callDeferred, WorkspaceContext } from '@causa/workspace';
2
2
  import { EventTopicBrokerCreateTopic, } from '@causa/workspace-core';
3
- import { PubSubService } from '../../services/index.js';
4
3
  /**
5
4
  * Implements {@link EventTopicBrokerCreateTopic} for Pub/Sub.
6
5
  * Topics are created in the GCP project set in the `google.project` configuration.
@@ -8,18 +7,7 @@ import { PubSubService } from '../../services/index.js';
8
7
  */
9
8
  export class EventTopicBrokerCreateTopicForPubSub extends EventTopicBrokerCreateTopic {
10
9
  async _call(context) {
11
- const googleConf = context.asConfiguration();
12
- const projectId = googleConf.getOrThrow('google.project');
13
- const region = googleConf.get('google.region');
14
- const topicId = `projects/${projectId}/topics/${this.name}`;
15
- context.logger.info(`📫 Creating Pub/Sub topic '${topicId}'.`);
16
- await context.service(PubSubService).pubSub.createTopic({
17
- name: topicId,
18
- ...(region
19
- ? { messageStoragePolicy: { allowedPersistenceRegions: [region] } }
20
- : {}),
21
- });
22
- return topicId;
10
+ return await callDeferred(this, context, import.meta.url);
23
11
  }
24
12
  _supports(context) {
25
13
  return (context.asConfiguration().get('events.broker') ===
@@ -0,0 +1,3 @@
1
+ import type { WorkspaceContext } from '@causa/workspace';
2
+ import type { EventTopicBrokerCreateTriggerForCloudRun } from './broker-create-trigger-cloud-run.js';
3
+ export default function call(this: EventTopicBrokerCreateTriggerForCloudRun, context: WorkspaceContext): Promise<string[]>;