@causa/workspace-google 1.3.0 → 1.4.0-beta.1

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 (57) hide show
  1. package/README.md +9 -0
  2. package/dist/configurations/generated.d.ts +3 -3
  3. package/dist/configurations/generated.js +8 -4
  4. package/dist/configurations/schemas/google.yaml +3 -3
  5. package/dist/functions/event-topic/create-backfill-source-bigquery.call.js +2 -2
  6. package/dist/functions/event-topic/query-events-bigquery.call.js +2 -2
  7. package/dist/functions/google-firestore/generate-typescript-decorators.js +2 -1
  8. package/dist/functions/google-pubsub/index.d.ts +1 -1
  9. package/dist/functions/google-pubsub/index.js +1 -1
  10. package/dist/functions/google-pubsub/write-topics.d.ts +7 -0
  11. package/dist/functions/google-pubsub/write-topics.js +10 -1
  12. package/dist/functions/google-spanner/generate-typescript-decorators.js +2 -1
  13. package/dist/functions/google-spanner/list-databases.d.ts +1 -1
  14. package/dist/functions/graph/index.d.ts +1 -0
  15. package/dist/functions/graph/index.js +1 -0
  16. package/dist/functions/graph/list-rules.d.ts +11 -0
  17. package/dist/functions/graph/list-rules.js +16 -0
  18. package/dist/functions/index.js +2 -1
  19. package/dist/graph/cloud-run.d.ts +98 -0
  20. package/dist/graph/cloud-run.js +102 -0
  21. package/dist/graph/ids.d.ts +35 -0
  22. package/dist/graph/ids.js +44 -0
  23. package/dist/graph/index.d.ts +6 -0
  24. package/dist/graph/index.js +6 -0
  25. package/dist/graph/rules/configuration/enqueues-assumed-from-google-task-trigger.d.ts +6 -0
  26. package/dist/graph/rules/configuration/enqueues-assumed-from-google-task-trigger.js +39 -0
  27. package/dist/graph/rules/configuration/firestore.d.ts +11 -0
  28. package/dist/graph/rules/configuration/firestore.js +93 -0
  29. package/dist/graph/rules/configuration/index.d.ts +5 -0
  30. package/dist/graph/rules/configuration/index.js +11 -0
  31. package/dist/graph/rules/configuration/service-container.d.ts +13 -0
  32. package/dist/graph/rules/configuration/service-container.js +123 -0
  33. package/dist/graph/rules/terraform/api-router.d.ts +15 -0
  34. package/dist/graph/rules/terraform/api-router.js +117 -0
  35. package/dist/graph/rules/terraform/cloud-run-cron-triggers.d.ts +11 -0
  36. package/dist/graph/rules/terraform/cloud-run-cron-triggers.js +67 -0
  37. package/dist/graph/rules/terraform/cloud-run-grants.d.ts +16 -0
  38. package/dist/graph/rules/terraform/cloud-run-grants.js +118 -0
  39. package/dist/graph/rules/terraform/cloud-run-module.d.ts +6 -0
  40. package/dist/graph/rules/terraform/cloud-run-module.js +29 -0
  41. package/dist/graph/rules/terraform/cloud-run-pubsub-triggers.d.ts +14 -0
  42. package/dist/graph/rules/terraform/cloud-run-pubsub-triggers.js +103 -0
  43. package/dist/graph/rules/terraform/cloud-run-services.d.ts +12 -0
  44. package/dist/graph/rules/terraform/cloud-run-services.js +61 -0
  45. package/dist/graph/rules/terraform/cloud-run-tasks-triggers.d.ts +14 -0
  46. package/dist/graph/rules/terraform/cloud-run-tasks-triggers.js +97 -0
  47. package/dist/graph/rules/terraform/event-topics.d.ts +18 -0
  48. package/dist/graph/rules/terraform/event-topics.js +193 -0
  49. package/dist/graph/rules/terraform/index.d.ts +5 -0
  50. package/dist/graph/rules/terraform/index.js +13 -0
  51. package/dist/graph/rules/terraform/spanner-databases.d.ts +17 -0
  52. package/dist/graph/rules/terraform/spanner-databases.js +180 -0
  53. package/dist/graph/spanner.d.ts +106 -0
  54. package/dist/graph/spanner.js +118 -0
  55. package/dist/graph/terraform-modules.d.ts +87 -0
  56. package/dist/graph/terraform-modules.js +107 -0
  57. package/package.json +27 -26
package/README.md CHANGED
@@ -74,6 +74,15 @@ This module implements the `DatabaseQueryRecords`, `ServiceContainerQueryLogs`,
74
74
  - `ServiceContainerQueryLogs` is supported when `serviceContainer.platform` is `google.cloudRun`. It queries Cloud Logging for log entries emitted by the service's Cloud Run revisions. By default, only the last hour of logs and up to 1 000 entries are returned.
75
75
  - `EventTopicQueryEvents` is supported when `events.broker` is `google.pubSub`, `events.format` is `json`, and `google.pubSub.bigQueryStorage.rawEventsDatasetId` is set. It reads events from the topic's BigQuery raw events table. Same defaults as for log queries: last hour and up to 1 000 events.
76
76
 
77
+ ### Architecture graph
78
+
79
+ This module contributes to the architecture graph extracted by `cs graph extract` (see the core module):
80
+
81
+ - Some rules read the workspace configuration and model: the Firestore database and the collections schemas bind to (`firestoreFromConfiguration`), the triggers of type `google.pubSub` and the entities projects access through the databases and collections listed in `serviceContainer.outputs` (`googleServiceContainerFromConfiguration`), and the triggers of type `google.task(s)`.
82
+ - Other rules mirror the resources created by the Causa Terraform modules for Google Cloud, one rule per module (Cloud Run services, event topics, Spanner databases, and API router), by joining the arguments of their blocks with the configuration the modules read. Each resource is linked by a `deploys` edge from the projects applying the block.
83
+
84
+ Infrastructure nodes carry the Google Cloud resource they stand for in `data.resource`: its `type` (e.g. `pubsub.googleapis.com/Topic`), its `id`, i.e. its full resource name (or `idPrefix` when the full name is not known), and the `scope`, i.e. the project whose configuration should be used to render the identifier.
85
+
77
86
  ### Secrets backend
78
87
 
79
88
  This module implements the `google.secretManager` secret backend, allowing fetching secrets from the Google Secret Manager service. Here are some example of how secrets with the `google.secretManager` backend should be defined:
@@ -70,9 +70,9 @@ export declare class GoogleCloudRunEventBackfillServiceCloneConfig {
70
70
  * See https://cloud.google.com/run/docs/securing/ingress#settings for more details.
71
71
  */
72
72
  export declare enum GoogleCloudRunIngress {
73
- All = "all",
74
- Internal = "internal",
75
- InternalAndCloudLoadBalancing = "internal-and-cloud-load-balancing"
73
+ IngressTrafficAll = "INGRESS_TRAFFIC_ALL",
74
+ IngressTrafficInternalOnly = "INGRESS_TRAFFIC_INTERNAL_ONLY",
75
+ IngressTrafficInternalLoadBalancer = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER"
76
76
  }
77
77
  /**
78
78
  * Google Cloud Run platform.
@@ -127,9 +127,9 @@ __decorate([
127
127
  */
128
128
  export var GoogleCloudRunIngress;
129
129
  (function (GoogleCloudRunIngress) {
130
- GoogleCloudRunIngress["All"] = "all";
131
- GoogleCloudRunIngress["Internal"] = "internal";
132
- GoogleCloudRunIngress["InternalAndCloudLoadBalancing"] = "internal-and-cloud-load-balancing";
130
+ GoogleCloudRunIngress["IngressTrafficAll"] = "INGRESS_TRAFFIC_ALL";
131
+ GoogleCloudRunIngress["IngressTrafficInternalOnly"] = "INGRESS_TRAFFIC_INTERNAL_ONLY";
132
+ GoogleCloudRunIngress["IngressTrafficInternalLoadBalancer"] = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER";
133
133
  })(GoogleCloudRunIngress || (GoogleCloudRunIngress = {}));
134
134
  /**
135
135
  * Google Cloud Run platform.
@@ -1685,7 +1685,11 @@ __decorate([
1685
1685
  ], GoogleCloudRun.prototype, "requestConcurrency", void 0);
1686
1686
  __decorate([
1687
1687
  AllowMissing(),
1688
- IsIn(['all', 'internal', 'internal-and-cloud-load-balancing']),
1688
+ IsIn([
1689
+ 'INGRESS_TRAFFIC_ALL',
1690
+ 'INGRESS_TRAFFIC_INTERNAL_ONLY',
1691
+ 'INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER',
1692
+ ]),
1689
1693
  __metadata("design:type", String)
1690
1694
  ], GoogleCloudRun.prototype, "ingress", void 0);
1691
1695
  __decorate([
@@ -469,9 +469,9 @@ properties:
469
469
  title: GoogleCloudRunIngress
470
470
  type: string
471
471
  enum:
472
- - all
473
- - internal
474
- - internal-and-cloud-load-balancing
472
+ - INGRESS_TRAFFIC_ALL
473
+ - INGRESS_TRAFFIC_INTERNAL_ONLY
474
+ - INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER
475
475
  description: >-
476
476
  The type of allowed ingress that can reach the container.
477
477
 
@@ -1,4 +1,5 @@
1
1
  import { BigQueryService } from '../../services/index.js';
2
+ import { rawEventsTableName } from '../google-pubsub/index.js';
2
3
  import { BIGQUERY_SOURCE_REGEX, } from './create-backfill-source-bigquery.js';
3
4
  /**
4
5
  * Resolves the full BigQuery table ID from the function arguments and configuration.
@@ -18,8 +19,7 @@ function resolveTableId(self, context) {
18
19
  const googleConf = context.asConfiguration();
19
20
  const projectId = googleConf.getOrThrow('google.project');
20
21
  const rawEventsDatasetId = googleConf.getOrThrow('google.pubSub.bigQueryStorage.rawEventsDatasetId');
21
- const tableName = self.eventTopic.replace(/[-\.]/g, '_');
22
- return `${projectId}.${rawEventsDatasetId}.${tableName}`;
22
+ return `${projectId}.${rawEventsDatasetId}.${rawEventsTableName(self.eventTopic)}`;
23
23
  }
24
24
  export default async function call() {
25
25
  const tableId = resolveTableId(this, this._context);
@@ -1,4 +1,5 @@
1
1
  import { BigQueryService } from '../../services/index.js';
2
+ import { rawEventsTableName } from '../google-pubsub/index.js';
2
3
  /**
3
4
  * The default duration applied to `from` when it is not set, in milliseconds.
4
5
  */
@@ -13,8 +14,7 @@ export default async function call() {
13
14
  const googleConf = this._context.asConfiguration();
14
15
  const projectId = googleConf.getOrThrow('google.project');
15
16
  const rawEventsDatasetId = googleConf.getOrThrow('google.pubSub.bigQueryStorage.rawEventsDatasetId');
16
- const tableName = this.topic.replace(/[-\.]/g, '_');
17
- const tableId = `${projectId}.${rawEventsDatasetId}.${tableName}`;
17
+ const tableId = `${projectId}.${rawEventsDatasetId}.${rawEventsTableName(this.topic)}`;
18
18
  const conditions = [`publish_time >= @from`];
19
19
  const params = { from: from.toISOString() };
20
20
  if (this.to) {
@@ -1,3 +1,4 @@
1
+ import { splitSchemaPath } from '@causa/workspace-core/jsonschema';
1
2
  import { ModelGenerateTypeScriptDecorators } from '@causa/workspace-typescript';
2
3
  import { addDecoratorToList, } from '@causa/workspace-typescript/code-generation';
3
4
  import micromatch from 'micromatch';
@@ -32,7 +33,7 @@ export class ModelGenerateTypeScriptDecoratorsForGoogleFirestore extends ModelGe
32
33
  if (Array.isArray(globs)) {
33
34
  const projectPath = this._context.getProjectPathOrThrow();
34
35
  const absoluteGlobs = globs.map((g) => join(projectPath, g));
35
- const schemaPath = this.schema.path.split('#')[0];
36
+ const { file: schemaPath } = splitSchemaPath(this.schema.path);
36
37
  if (!micromatch.isMatch(schemaPath, absoluteGlobs)) {
37
38
  return [];
38
39
  }
@@ -1 +1 @@
1
- export { GooglePubSubWriteTopics } from './write-topics.js';
1
+ export { GooglePubSubWriteTopics, rawEventsTableName } from './write-topics.js';
@@ -1 +1 @@
1
- export { GooglePubSubWriteTopics } from './write-topics.js';
1
+ export { GooglePubSubWriteTopics, rawEventsTableName } from './write-topics.js';
@@ -1,5 +1,12 @@
1
1
  import { type ProcessorResult, WorkspaceFunction } from '@causa/workspace';
2
2
  import { type InfrastructureProcessor } from '@causa/workspace-core';
3
+ /**
4
+ * Returns the name of the BigQuery table storing the raw events of a topic.
5
+ *
6
+ * @param topic The ID of the topic.
7
+ * @returns The name of the BigQuery table.
8
+ */
9
+ export declare function rawEventsTableName(topic: string): string;
3
10
  /**
4
11
  * A function that uses {@link EventTopicList} to find all the topics in the workspace, and writes their configurations
5
12
  * to a directory.
@@ -18,6 +18,15 @@ import { join } from 'path';
18
18
  * The default directory where Pub/Sub topic configurations are written, relative to the workspace root.
19
19
  */
20
20
  const DEFAULT_TOPIC_CONFIGURATIONS_DIRECTORY = join(CAUSA_FOLDER, 'pubsub-topics');
21
+ /**
22
+ * Returns the name of the BigQuery table storing the raw events of a topic.
23
+ *
24
+ * @param topic The ID of the topic.
25
+ * @returns The name of the BigQuery table.
26
+ */
27
+ export function rawEventsTableName(topic) {
28
+ return topic.replace(/[-.]/g, '_');
29
+ }
21
30
  /**
22
31
  * A function that uses {@link EventTopicList} to find all the topics in the workspace, and writes their configurations
23
32
  * to a directory.
@@ -56,7 +65,7 @@ export class GooglePubSubWriteTopics extends WorkspaceFunction {
56
65
  await Promise.all(topics.map(async (topic) => {
57
66
  const topicConfiguration = {
58
67
  ...topic,
59
- bigQueryTableName: topic.id.replace(/[-\.]/g, '_'),
68
+ bigQueryTableName: rawEventsTableName(topic.id),
60
69
  };
61
70
  const topicFile = join(absoluteDir, `${topic.id}.json`);
62
71
  await writeFile(topicFile, JSON.stringify(topicConfiguration));
@@ -1,3 +1,4 @@
1
+ import { splitSchemaPath } from '@causa/workspace-core/jsonschema';
1
2
  import { ModelGenerateTypeScriptDecorators } from '@causa/workspace-typescript';
2
3
  import { addDecoratorToList, } from '@causa/workspace-typescript/code-generation';
3
4
  import micromatch from 'micromatch';
@@ -41,7 +42,7 @@ export class ModelGenerateTypeScriptDecoratorsForGoogleSpanner extends ModelGene
41
42
  if (Array.isArray(globs)) {
42
43
  const projectPath = this._context.getProjectPathOrThrow();
43
44
  const absoluteGlobs = globs.map((g) => join(projectPath, g));
44
- const schemaPath = this.schema.path.split('#')[0];
45
+ const { file: schemaPath } = splitSchemaPath(this.schema.path);
45
46
  if (!micromatch.isMatch(schemaPath, absoluteGlobs)) {
46
47
  return [];
47
48
  }
@@ -8,7 +8,7 @@ export type SpannerDatabase = {
8
8
  */
9
9
  id: string;
10
10
  /**
11
- * The paths (relative to the workspace root) containing DDL statements for this database.
11
+ * The absolute paths of the files containing DDL statements for this database.
12
12
  */
13
13
  ddlFiles: string[];
14
14
  /**
@@ -0,0 +1 @@
1
+ export { GraphListRulesForGoogle } from './list-rules.js';
@@ -0,0 +1 @@
1
+ export { GraphListRulesForGoogle } from './list-rules.js';
@@ -0,0 +1,11 @@
1
+ import { GraphListRules, type GraphRule } from '@causa/workspace-core';
2
+ /**
3
+ * Implements {@link GraphListRules} for Google Cloud.
4
+ * The rules read the Google-specific parts of the workspace configuration and model (Firestore collections, the
5
+ * entities projects access through their `google.*` outputs, triggers of Google-specific types), and mirror the
6
+ * resources created by the Causa Terraform modules for Google Cloud.
7
+ */
8
+ export declare class GraphListRulesForGoogle extends GraphListRules {
9
+ _call(): GraphRule[];
10
+ _supports(): boolean;
11
+ }
@@ -0,0 +1,16 @@
1
+ import { GraphListRules } from '@causa/workspace-core';
2
+ import { GOOGLE_GRAPH_RULES, GOOGLE_TERRAFORM_GRAPH_RULES, } from '../../graph/index.js';
3
+ /**
4
+ * Implements {@link GraphListRules} for Google Cloud.
5
+ * The rules read the Google-specific parts of the workspace configuration and model (Firestore collections, the
6
+ * entities projects access through their `google.*` outputs, triggers of Google-specific types), and mirror the
7
+ * resources created by the Causa Terraform modules for Google Cloud.
8
+ */
9
+ export class GraphListRulesForGoogle extends GraphListRules {
10
+ _call() {
11
+ return [...GOOGLE_GRAPH_RULES, ...GOOGLE_TERRAFORM_GRAPH_RULES];
12
+ }
13
+ _supports() {
14
+ return true;
15
+ }
16
+ }
@@ -8,10 +8,11 @@ import { GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenera
8
8
  import { GooglePubSubWriteTopics } from './google-pubsub/index.js';
9
9
  import { GoogleServicesEnable } from './google-services/index.js';
10
10
  import { DatabaseQueryRecordsForSpanner, GoogleSpannerListDatabases, GoogleSpannerWriteDatabases, ModelGenerateTypeScriptDecoratorsForGoogleSpanner, ModelSchemaExtractDatabaseForGoogleSpanner, } from './google-spanner/index.js';
11
+ import { GraphListRulesForGoogle } from './graph/index.js';
11
12
  import { ProjectGetArtefactDestinationForCloudFunctions, ProjectGetArtefactDestinationForCloudRun, ProjectPushArtefactForCloudFunctions, } from './project/index.js';
12
13
  import { SecretFetchForGoogleAccessToken, SecretFetchForGoogleSecretManager, } from './secret/index.js';
13
14
  import { ServiceContainerQueryLogsForCloudRun } from './service-container/index.js';
14
15
  import { ModelGenerateTypeScriptTriggerDecoratorsForGoogle } from './typescript/index.js';
15
16
  export function registerFunctions(context) {
16
- context.registerFunctionImplementations(CausaListConfigurationSchemasForGoogle, DatabaseQueryRecordsForFirestore, DatabaseQueryRecordsForSpanner, EmulatorStartForFirebaseStorage, EmulatorStartForFirestore, EmulatorStartForIdentityPlatform, EmulatorStartForPubSub, EmulatorStartForSpanner, EmulatorStopForFirebaseStorage, EmulatorStopForFirestore, EmulatorStopForIdentityPlatform, EmulatorStopForPubSub, EmulatorStopForSpanner, EventTopicBrokerCreateTopicForPubSub, EventTopicBrokerCreateTriggerForCloudRun, EventTopicBrokerDeleteTopicForPubSub, EventTopicBrokerDeleteTriggerResourceForCloudRunInvokerRole, EventTopicBrokerDeleteTriggerResourceForCloudRunService, EventTopicBrokerDeleteTriggerResourceForPubSubSubscription, EventTopicBrokerDeleteTriggerResourceForServiceAccount, EventTopicBrokerGetTopicIdForPubSub, EventTopicBrokerPublishEventsForGoogle, EventTopicBrokerWaitForProcessingForPubSub, EventTopicCreateBackfillSourceForBigQuery, EventTopicQueryEventsForBigQuery, GoogleAppCheckGenerateToken, GoogleFirebaseStorageMergeRules, GoogleFirestoreMergeRules, GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenerateToken, GooglePubSubWriteTopics, GoogleServicesEnable, GoogleSpannerListDatabases, GoogleSpannerWriteDatabases, ModelGenerateTypeScriptDecoratorsForGoogleFirestore, ModelGenerateTypeScriptDecoratorsForGoogleSpanner, ModelGenerateTypeScriptTriggerDecoratorsForGoogle, ModelSchemaExtractDatabaseForGoogleFirestore, ModelSchemaExtractDatabaseForGoogleSpanner, ProjectGetArtefactDestinationForCloudFunctions, ProjectGetArtefactDestinationForCloudRun, ProjectPushArtefactForCloudFunctions, SecretFetchForGoogleAccessToken, SecretFetchForGoogleSecretManager, ServiceContainerQueryLogsForCloudRun);
17
+ context.registerFunctionImplementations(CausaListConfigurationSchemasForGoogle, DatabaseQueryRecordsForFirestore, DatabaseQueryRecordsForSpanner, EmulatorStartForFirebaseStorage, EmulatorStartForFirestore, EmulatorStartForIdentityPlatform, EmulatorStartForPubSub, EmulatorStartForSpanner, EmulatorStopForFirebaseStorage, EmulatorStopForFirestore, EmulatorStopForIdentityPlatform, EmulatorStopForPubSub, EmulatorStopForSpanner, EventTopicBrokerCreateTopicForPubSub, EventTopicBrokerCreateTriggerForCloudRun, EventTopicBrokerDeleteTopicForPubSub, EventTopicBrokerDeleteTriggerResourceForCloudRunInvokerRole, EventTopicBrokerDeleteTriggerResourceForCloudRunService, EventTopicBrokerDeleteTriggerResourceForPubSubSubscription, EventTopicBrokerDeleteTriggerResourceForServiceAccount, EventTopicBrokerGetTopicIdForPubSub, EventTopicBrokerPublishEventsForGoogle, EventTopicBrokerWaitForProcessingForPubSub, EventTopicCreateBackfillSourceForBigQuery, EventTopicQueryEventsForBigQuery, GoogleAppCheckGenerateToken, GoogleFirebaseStorageMergeRules, GoogleFirestoreMergeRules, GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenerateToken, GooglePubSubWriteTopics, GoogleServicesEnable, GoogleSpannerListDatabases, GoogleSpannerWriteDatabases, GraphListRulesForGoogle, ModelGenerateTypeScriptDecoratorsForGoogleFirestore, ModelGenerateTypeScriptDecoratorsForGoogleSpanner, ModelGenerateTypeScriptTriggerDecoratorsForGoogle, ModelSchemaExtractDatabaseForGoogleFirestore, ModelSchemaExtractDatabaseForGoogleSpanner, ProjectGetArtefactDestinationForCloudFunctions, ProjectGetArtefactDestinationForCloudRun, ProjectPushArtefactForCloudFunctions, SecretFetchForGoogleAccessToken, SecretFetchForGoogleSecretManager, ServiceContainerQueryLogsForCloudRun);
17
18
  }
@@ -0,0 +1,98 @@
1
+ import type { ServiceContainerConfiguration } from '@causa/workspace-core';
2
+ import { GraphFact, type GraphContext, type GraphFactOutput, type GraphTemplatePart, type WorkspaceProject } from '@causa/workspace-core/graph';
3
+ import { type TerraformModuleBlock } from '@causa/workspace-terraform';
4
+ /**
5
+ * A trigger defined in the `serviceContainer.triggers` configuration.
6
+ */
7
+ type ServiceContainerTrigger = NonNullable<NonNullable<ServiceContainerConfiguration['serviceContainer']>['triggers']>[string];
8
+ /**
9
+ * The source of the Causa Terraform module deploying a service container to Cloud Run.
10
+ */
11
+ export declare const CLOUD_RUN_MODULE_SOURCE = "causa-io/service-container-cloud-run/google";
12
+ /**
13
+ * A block of the Cloud Run module, i.e. a deployed service, with the module's logic evaluated from the block's
14
+ * arguments and the project's configuration.
15
+ */
16
+ export type CloudRunService = {
17
+ /**
18
+ * The Terraform module block defining the Cloud Run service.
19
+ */
20
+ readonly block: TerraformModuleBlock;
21
+ /**
22
+ * The project whose configuration file the block reads.
23
+ */
24
+ readonly project: WorkspaceProject;
25
+ /**
26
+ * The name of the service, `coalesce(var.name, project.name)`.
27
+ */
28
+ readonly name: string;
29
+ /**
30
+ * The ID of the `service` node.
31
+ */
32
+ readonly id: string;
33
+ /**
34
+ * Whether the service's HTTP endpoints are exposed through the API router (`enable_public_http_endpoints`, `false` by
35
+ * default).
36
+ */
37
+ readonly enablePublicHttpEndpoints: boolean;
38
+ /**
39
+ * Whether the block grants the publisher role on the project's `outputs.eventTopics` (`set_pubsub_permissions`,
40
+ * defaulting to `set_iam_permissions`).
41
+ */
42
+ readonly setPubsubPermissions: boolean;
43
+ /**
44
+ * Whether the block grants access to the Spanner databases of the project's outputs (`set_spanner_permissions`,
45
+ * defaulting to `set_iam_permissions`).
46
+ */
47
+ readonly setSpannerPermissions: boolean;
48
+ /**
49
+ * Whether the block grants access to the Firestore database for the collections of the project's outputs
50
+ * (`set_firestore_permissions`, defaulting to `set_iam_permissions`).
51
+ */
52
+ readonly setFirestorePermissions: boolean;
53
+ /**
54
+ * Whether the block grants the enqueuer role on the queues of the project's task triggers (`set_tasks_permissions`,
55
+ * defaulting to `set_iam_permissions`).
56
+ */
57
+ readonly setTasksPermissions: boolean;
58
+ /**
59
+ * The triggers the module turns into Pub/Sub push subscriptions, keyed by name: `event` or `google.pubSub` triggers
60
+ * with an HTTP endpoint, not disabled.
61
+ */
62
+ readonly pubsubTriggers: ReadonlyMap<string, ServiceContainerTrigger>;
63
+ /**
64
+ * The triggers the module turns into Cloud Tasks queues, keyed by name. A disabled trigger still has its * queue,
65
+ * paused.
66
+ */
67
+ readonly tasksTriggers: ReadonlyMap<string, ServiceContainerTrigger>;
68
+ /**
69
+ * The triggers the module turns into Cloud Scheduler jobs, keyed by name. A disabled trigger still has its job,
70
+ * paused.
71
+ */
72
+ readonly cronTriggers: ReadonlyMap<string, ServiceContainerTrigger>;
73
+ /**
74
+ * The GCP project part of resource names.
75
+ */
76
+ readonly projectPart: GraphTemplatePart;
77
+ /**
78
+ * The location part of resource names, shared by the service, its queues, and its jobs.
79
+ */
80
+ readonly locationPart: GraphTemplatePart;
81
+ };
82
+ /**
83
+ * The blocks of the Cloud Run module, evaluated against the configuration of the projects they deploy.
84
+ * Blocks whose `configuration_file` does not name a project of the workspace cannot be mirrored, and are reported.
85
+ */
86
+ export declare class CloudRunFact extends GraphFact<CloudRunService[]> {
87
+ compute(graph: GraphContext): Promise<GraphFactOutput<CloudRunService[]>>;
88
+ /**
89
+ * Evaluates a Cloud Run module block, mirroring the defaults of the module.
90
+ *
91
+ * @param block The module block.
92
+ * @param project The project whose configuration file the block reads.
93
+ * @param warnings The warnings of the fact, to which the ones about the block are added.
94
+ * @returns The {@link CloudRunService}.
95
+ */
96
+ private evaluate;
97
+ }
98
+ export {};
@@ -0,0 +1,102 @@
1
+ import { GraphFact, ProjectsFact, serviceId, } from '@causa/workspace-core/graph';
2
+ import { modulesWithSource, TerraformProjectsFact, } from '@causa/workspace-terraform';
3
+ import { argumentOrConfiguration, projectOfConfigurationFile, } from './terraform-modules.js';
4
+ /**
5
+ * The source of the Causa Terraform module deploying a service container to Cloud Run.
6
+ */
7
+ export const CLOUD_RUN_MODULE_SOURCE = 'causa-io/service-container-cloud-run/google';
8
+ /**
9
+ * The major version of the Cloud Run module whose behavior is mirrored (trigger filters, IAM grants, resource names).
10
+ */
11
+ const MIRRORED_CLOUD_RUN_MAJOR = 1;
12
+ /**
13
+ * The blocks of the Cloud Run module, evaluated against the configuration of the projects they deploy.
14
+ * Blocks whose `configuration_file` does not name a project of the workspace cannot be mirrored, and are reported.
15
+ */
16
+ export class CloudRunFact extends GraphFact {
17
+ async compute(graph) {
18
+ const [terraformProjects, projects] = await Promise.all([
19
+ graph.get(TerraformProjectsFact),
20
+ graph.get(ProjectsFact),
21
+ ]);
22
+ const services = [];
23
+ const warnings = [];
24
+ for (const block of modulesWithSource(terraformProjects, CLOUD_RUN_MODULE_SOURCE)) {
25
+ const project = projectOfConfigurationFile(block.arguments['configuration_file'], projects);
26
+ if (!project) {
27
+ warnings.push({
28
+ message: "The Cloud Run module block is skipped, as its 'configuration_file' does not name a project of the workspace.",
29
+ sources: [block.declaration],
30
+ });
31
+ continue;
32
+ }
33
+ services.push(this.evaluate(block, project, warnings));
34
+ }
35
+ return { value: services, warnings };
36
+ }
37
+ /**
38
+ * Evaluates a Cloud Run module block, mirroring the defaults of the module.
39
+ *
40
+ * @param block The module block.
41
+ * @param project The project whose configuration file the block reads.
42
+ * @param warnings The warnings of the fact, to which the ones about the block are added.
43
+ * @returns The {@link CloudRunService}.
44
+ */
45
+ evaluate(block, project, warnings) {
46
+ const sources = [block.declaration];
47
+ const major = Number(block.version?.split('.')[0]);
48
+ if (major !== MIRRORED_CLOUD_RUN_MAJOR) {
49
+ warnings.push({
50
+ message: `The Cloud Run module version '${block.version ?? 'unset'}' is not the one being mirrored (${MIRRORED_CLOUD_RUN_MAJOR}.x). Resources are extracted as for that version.`,
51
+ sources,
52
+ });
53
+ }
54
+ const argument = (name, fallback) => {
55
+ const value = block.arguments[name];
56
+ if (value === undefined) {
57
+ return fallback;
58
+ }
59
+ if (!('value' in value)) {
60
+ const assumed = typeof fallback === 'string' ? fallback : JSON.stringify(fallback);
61
+ warnings.push({
62
+ message: `The argument '${name}' is computed (${value.expression}). Assuming ${assumed}.`,
63
+ sources,
64
+ });
65
+ return fallback;
66
+ }
67
+ return (value.value ?? fallback);
68
+ };
69
+ const name = argument('name', project.name) || project.name;
70
+ const enableTriggers = argument('enable_triggers', false);
71
+ const triggers = Object.entries({
72
+ ...(project.context
73
+ .asConfiguration()
74
+ .get('serviceContainer.triggers', { unsafe: true }) ?? {}),
75
+ ...argument('triggers', {}),
76
+ }).filter(([, t]) => t.endpoint?.type === 'http');
77
+ const ofTypes = (enabled, types, excludeDisabled = false) => new Map(enabled
78
+ ? triggers.filter(([, t]) => types.includes(t.type ?? '') &&
79
+ !(excludeDisabled && t.enabled === false))
80
+ : []);
81
+ const setIamPermissions = argument('set_iam_permissions', true);
82
+ return {
83
+ block,
84
+ project,
85
+ name,
86
+ id: serviceId(project.directory, name),
87
+ enablePublicHttpEndpoints: argument('enable_public_http_endpoints', false),
88
+ setPubsubPermissions: argument('set_pubsub_permissions', setIamPermissions),
89
+ setSpannerPermissions: argument('set_spanner_permissions', setIamPermissions),
90
+ setFirestorePermissions: argument('set_firestore_permissions', setIamPermissions),
91
+ setTasksPermissions: argument('set_tasks_permissions', setIamPermissions),
92
+ pubsubTriggers: ofTypes(argument('enable_pubsub_triggers', enableTriggers), ['event', 'google.pubSub'], true),
93
+ tasksTriggers: ofTypes(argument('enable_tasks_triggers', enableTriggers), ['task', 'google.task', 'google.tasks']),
94
+ cronTriggers: ofTypes(argument('enable_cron_triggers', enableTriggers), [
95
+ 'cron',
96
+ 'google.scheduler',
97
+ ]),
98
+ projectPart: argumentOrConfiguration(block, 'gcp_project_id', 'google.project', warnings),
99
+ locationPart: argumentOrConfiguration(block, 'location', 'google.cloudRun.location', warnings),
100
+ };
101
+ }
102
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The engine of Spanner databases. It is also the key of `serviceContainer.outputs` listing the databases a project
3
+ * owns, and the `engine` of Spanner database bindings.
4
+ */
5
+ export declare const SPANNER_ENGINE = "google.spanner";
6
+ /**
7
+ * The engine of Firestore databases. It is also the key of `serviceContainer.outputs` listing the collections a
8
+ * project owns, and the `engine` of Firestore database bindings.
9
+ */
10
+ export declare const FIRESTORE_ENGINE = "google.firestore";
11
+ /**
12
+ * The engine of BigQuery datasets.
13
+ */
14
+ export declare const BIGQUERY_ENGINE = "google.bigquery";
15
+ export declare const spannerInstanceId: (instance: string) => string;
16
+ /**
17
+ * The name of a Spanner database within its engine, `<instance>.<database>`, as `outputs['google.spanner']` lists it.
18
+ */
19
+ export declare const spannerDatabaseName: (instance: string, database: string) => string;
20
+ export declare const spannerDatabaseLocator: (instance: string, database: string) => string;
21
+ export declare const firestoreDatabaseLocator: (database: string) => string;
22
+ export declare const bigQueryDatasetLocator: (dataset: string) => string;
23
+ /**
24
+ * Returns the path of the collection holding the documents of a Firestore binding, independently of the properties
25
+ * used as document IDs: the last segment (the document) is dropped, and the other placeholders are replaced with `{}`.
26
+ * For example, `users/{user}/bookmarkFolders/{id}` becomes `users/{}/bookmarkFolders`.
27
+ *
28
+ * @param bindingTable The table of the binding, i.e. the path of its documents.
29
+ * @returns The collection path, or `undefined` if the root collection is not named by the binding.
30
+ */
31
+ export declare function firestoreCollectionPath(bindingTable: string): string | undefined;
32
+ /**
33
+ * The locator of the BigQuery subscription archiving a topic's raw events.
34
+ */
35
+ export declare const rawEventsSubscriptionLocator: (topic: string) => string;
@@ -0,0 +1,44 @@
1
+ import { databaseLocator, nodeId } from '@causa/workspace-core/graph';
2
+ /**
3
+ * The engine of Spanner databases. It is also the key of `serviceContainer.outputs` listing the databases a project
4
+ * owns, and the `engine` of Spanner database bindings.
5
+ */
6
+ export const SPANNER_ENGINE = 'google.spanner';
7
+ /**
8
+ * The engine of Firestore databases. It is also the key of `serviceContainer.outputs` listing the collections a
9
+ * project owns, and the `engine` of Firestore database bindings.
10
+ */
11
+ export const FIRESTORE_ENGINE = 'google.firestore';
12
+ /**
13
+ * The engine of BigQuery datasets.
14
+ */
15
+ export const BIGQUERY_ENGINE = 'google.bigquery';
16
+ export const spannerInstanceId = (instance) => nodeId('google.spanner.instance', instance);
17
+ /**
18
+ * The name of a Spanner database within its engine, `<instance>.<database>`, as `outputs['google.spanner']` lists it.
19
+ */
20
+ export const spannerDatabaseName = (instance, database) => `${instance}.${database}`;
21
+ export const spannerDatabaseLocator = (instance, database) => databaseLocator(SPANNER_ENGINE, spannerDatabaseName(instance, database));
22
+ export const firestoreDatabaseLocator = (database) => databaseLocator(FIRESTORE_ENGINE, database);
23
+ export const bigQueryDatasetLocator = (dataset) => databaseLocator(BIGQUERY_ENGINE, dataset);
24
+ /**
25
+ * Returns the path of the collection holding the documents of a Firestore binding, independently of the properties
26
+ * used as document IDs: the last segment (the document) is dropped, and the other placeholders are replaced with `{}`.
27
+ * For example, `users/{user}/bookmarkFolders/{id}` becomes `users/{}/bookmarkFolders`.
28
+ *
29
+ * @param bindingTable The table of the binding, i.e. the path of its documents.
30
+ * @returns The collection path, or `undefined` if the root collection is not named by the binding.
31
+ */
32
+ export function firestoreCollectionPath(bindingTable) {
33
+ const segments = bindingTable.split('/').slice(0, -1);
34
+ if (segments.length === 0 || /^\{.*\}$/.test(segments[0])) {
35
+ return undefined;
36
+ }
37
+ return segments
38
+ .map((segment) => (/^\{.*\}$/.test(segment) ? '{}' : segment))
39
+ .join('/');
40
+ }
41
+ /**
42
+ * The locator of the BigQuery subscription archiving a topic's raw events.
43
+ */
44
+ export const rawEventsSubscriptionLocator = (topic) => `rawEvents/${topic}`;
@@ -0,0 +1,6 @@
1
+ export * from './cloud-run.js';
2
+ export * from './ids.js';
3
+ export * from './rules/configuration/index.js';
4
+ export * from './rules/terraform/index.js';
5
+ export * from './spanner.js';
6
+ export * from './terraform-modules.js';
@@ -0,0 +1,6 @@
1
+ export * from './cloud-run.js';
2
+ export * from './ids.js';
3
+ export * from './rules/configuration/index.js';
4
+ export * from './rules/terraform/index.js';
5
+ export * from './spanner.js';
6
+ export * from './terraform-modules.js';
@@ -0,0 +1,6 @@
1
+ import { type GraphRule } from '@causa/workspace-core';
2
+ /**
3
+ * An `enqueues` edge from a service container project to each of its own `google.task` or `google.tasks` triggers,
4
+ * assuming the owning project is the producer.
5
+ */
6
+ export declare const enqueuesAssumedFromGoogleTaskTrigger: GraphRule;
@@ -0,0 +1,39 @@
1
+ import { GraphOriginKind, } from '@causa/workspace-core';
2
+ import { projectId, triggerId, ProjectsFact, } from '@causa/workspace-core/graph';
3
+ /**
4
+ * An `enqueues` edge from a service container project to each of its own `google.task` or `google.tasks` triggers,
5
+ * assuming the owning project is the producer.
6
+ */
7
+ export const enqueuesAssumedFromGoogleTaskTrigger = {
8
+ name: 'enqueuesAssumedFromGoogleTaskTrigger',
9
+ kind: GraphOriginKind.Inferred,
10
+ description: 'One `enqueues` edge from a service container project to each of its own `google.task` or `google.tasks` triggers, assuming the owning project is the producer.',
11
+ async run(graph) {
12
+ const { locator } = graph;
13
+ const projects = await graph.get(ProjectsFact);
14
+ const edges = [];
15
+ for (const project of projects.filter((p) => p.type === 'serviceContainer')) {
16
+ const triggers = project.context
17
+ .asConfiguration()
18
+ .get('serviceContainer.triggers', { unsafe: true }) ?? {};
19
+ for (const [name, trigger] of Object.entries(triggers)) {
20
+ if (!['google.task', 'google.tasks'].includes(trigger.type ?? '')) {
21
+ continue;
22
+ }
23
+ edges.push({
24
+ type: 'enqueues',
25
+ from: projectId(project.directory),
26
+ to: triggerId(project.directory, name),
27
+ sources: [
28
+ await locator.configurationSource(project.context, [
29
+ 'serviceContainer',
30
+ 'triggers',
31
+ name,
32
+ ]),
33
+ ],
34
+ });
35
+ }
36
+ }
37
+ return { edges };
38
+ },
39
+ };
@@ -0,0 +1,11 @@
1
+ import { type GraphRule } from '@causa/workspace-core';
2
+ /**
3
+ * The Firestore database of the workspace, `google.firestore.database`, and the collections schemas bind to:
4
+ *
5
+ * - A `database` node for the database.
6
+ * - A `table` node per Firestore collection a schema binds to (`causa.googleFirestoreCollection`). The locator is the
7
+ * collection path, with `{}` in place of document IDs (e.g. `users/{}/bookmarks`), under the single Firestore database
8
+ * of the workspace. A binding that does not name its root collection is reported.
9
+ * - A `realizes` edge from each collection to the entity whose binding declares it.
10
+ */
11
+ export declare const firestoreFromConfiguration: GraphRule;