@causa/workspace-google 0.18.0-beta.1 → 0.18.0-beta.3
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.
- package/dist/configurations/generated.d.ts +30 -0
- package/dist/configurations/generated.js +60 -0
- package/dist/configurations/schemas/google.yaml +43 -0
- package/dist/emulators/firebase-storage.d.ts +9 -1
- package/dist/emulators/firebase-storage.js +13 -1
- package/dist/emulators/firestore.d.ts +9 -1
- package/dist/emulators/firestore.js +13 -1
- package/dist/emulators/identity-platform.d.ts +9 -1
- package/dist/emulators/identity-platform.js +13 -1
- package/dist/emulators/pubsub.d.ts +9 -1
- package/dist/emulators/pubsub.js +13 -1
- package/dist/emulators/spanner.d.ts +18 -2
- package/dist/emulators/spanner.js +26 -2
- package/dist/functions/emulator/start-firebase-storage.js +4 -3
- package/dist/functions/emulator/start-firestore.js +5 -10
- package/dist/functions/emulator/start-identity-platform.js +4 -7
- package/dist/functions/emulator/start-pubsub.call.js +10 -9
- package/dist/functions/emulator/start-spanner.call.js +14 -13
- package/dist/functions/event-topic/broker-delete-trigger-resource-pubsub-subscription.js +2 -1
- package/dist/functions/event-topic/broker-wait-for-processing-pubsub.call.d.ts +2 -0
- package/dist/functions/event-topic/broker-wait-for-processing-pubsub.call.js +119 -0
- package/dist/functions/event-topic/broker-wait-for-processing-pubsub.d.ts +16 -0
- package/dist/functions/event-topic/broker-wait-for-processing-pubsub.js +23 -0
- package/dist/functions/event-topic/index.d.ts +1 -0
- package/dist/functions/event-topic/index.js +1 -0
- package/dist/functions/google-firestore/generate-typescript-decorators.d.ts +13 -0
- package/dist/functions/google-firestore/generate-typescript-decorators.js +78 -0
- package/dist/functions/google-firestore/index.d.ts +1 -0
- package/dist/functions/google-firestore/index.js +1 -0
- package/dist/functions/google-spanner/generate-typescript-decorators.d.ts +14 -0
- package/dist/functions/google-spanner/generate-typescript-decorators.js +120 -0
- package/dist/functions/google-spanner/index.d.ts +1 -0
- package/dist/functions/google-spanner/index.js +1 -0
- package/dist/functions/index.js +4 -5
- package/dist/services/cloud-monitoring.d.ts +44 -0
- package/dist/services/cloud-monitoring.js +61 -0
- package/dist/services/index.d.ts +2 -1
- package/dist/services/index.js +2 -1
- package/dist/services/pubsub.d.ts +1 -0
- package/dist/services/pubsub.js +1 -0
- package/dist/services/pubsub.utils.d.ts +9 -0
- package/dist/services/pubsub.utils.js +11 -0
- package/package.json +8 -8
- package/dist/code-generation/google-firestore-renderer.d.ts +0 -12
- package/dist/code-generation/google-firestore-renderer.js +0 -89
- package/dist/code-generation/google-spanner-renderer.d.ts +0 -11
- package/dist/code-generation/google-spanner-renderer.js +0 -100
- package/dist/code-generation/index.d.ts +0 -2
- package/dist/code-generation/index.js +0 -2
- package/dist/code-generation/utils.d.ts +0 -12
- package/dist/code-generation/utils.js +0 -21
- package/dist/functions/typescript/get-decorator-renderer-google-firestore.d.ts +0 -8
- package/dist/functions/typescript/get-decorator-renderer-google-firestore.js +0 -14
- package/dist/functions/typescript/get-decorator-renderer-google-spanner.d.ts +0 -8
- package/dist/functions/typescript/get-decorator-renderer-google-spanner.js +0 -14
- package/dist/functions/typescript/index.d.ts +0 -2
- package/dist/functions/typescript/index.js +0 -2
|
@@ -5,7 +5,7 @@ import { Instance, Spanner } from '@google-cloud/spanner';
|
|
|
5
5
|
// version can be loaded.
|
|
6
6
|
import { grpc } from 'google-gax';
|
|
7
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';
|
|
8
|
+
import { SPANNER_EMULATOR_NAME, SPANNER_GRPC_PORT, SPANNER_HTTP_PORT, SPANNER_IMAGE, getSpannerContainerName, getSpannerEmulatorGrpcPort, getSpannerEmulatorHttpPort, } from '../../emulators/index.js';
|
|
9
9
|
import { GoogleSpannerListDatabases } from '../google-spanner/index.js';
|
|
10
10
|
export default async function call() {
|
|
11
11
|
const configuration = await startSpanner(this, this._context);
|
|
@@ -15,12 +15,14 @@ async function startSpanner(self, context) {
|
|
|
15
15
|
if (self.dryRun) {
|
|
16
16
|
return {};
|
|
17
17
|
}
|
|
18
|
-
const
|
|
19
|
-
const
|
|
18
|
+
const grpcHostPort = getSpannerEmulatorGrpcPort(context);
|
|
19
|
+
const httpHostPort = getSpannerEmulatorHttpPort(context);
|
|
20
|
+
const emulatorConf = await startSpannerEmulator(context, grpcHostPort, httpHostPort);
|
|
21
|
+
const instanceAndDatabaseConf = await initializeEmulator(context, grpcHostPort);
|
|
20
22
|
context.logger.info('🗃️ Successfully initialized Spanner emulator.');
|
|
21
23
|
return { ...emulatorConf, ...instanceAndDatabaseConf };
|
|
22
24
|
}
|
|
23
|
-
async function startSpannerEmulator(context) {
|
|
25
|
+
async function startSpannerEmulator(context, grpcHostPort, httpHostPort) {
|
|
24
26
|
context.logger.info('🗃️ Starting Spanner emulator.');
|
|
25
27
|
const gcpProject = getLocalGcpProject(context);
|
|
26
28
|
const containerName = getSpannerContainerName(context);
|
|
@@ -28,23 +30,22 @@ async function startSpannerEmulator(context) {
|
|
|
28
30
|
.asConfiguration()
|
|
29
31
|
.get('google.spanner.emulator.version') ?? 'latest';
|
|
30
32
|
const dockerEmulatorService = context.service(DockerEmulatorService);
|
|
31
|
-
await dockerEmulatorService.start(`${SPANNER_IMAGE}:${imageVersion}`, containerName, [
|
|
32
|
-
host: '127.0.0.1',
|
|
33
|
-
local:
|
|
34
|
-
|
|
35
|
-
})
|
|
36
|
-
await dockerEmulatorService.waitForAvailability(containerName, `http://127.0.0.1:${SPANNER_HTTP_PORT}/v1/projects/${gcpProject}/instances`);
|
|
33
|
+
await dockerEmulatorService.start(`${SPANNER_IMAGE}:${imageVersion}`, containerName, [
|
|
34
|
+
{ host: '127.0.0.1', local: grpcHostPort, container: SPANNER_GRPC_PORT },
|
|
35
|
+
{ host: '127.0.0.1', local: httpHostPort, container: SPANNER_HTTP_PORT },
|
|
36
|
+
]);
|
|
37
|
+
await dockerEmulatorService.waitForAvailability(containerName, `http://127.0.0.1:${httpHostPort}/v1/projects/${gcpProject}/instances`);
|
|
37
38
|
return {
|
|
38
|
-
SPANNER_EMULATOR_HOST: `127.0.0.1:${
|
|
39
|
+
SPANNER_EMULATOR_HOST: `127.0.0.1:${grpcHostPort}`,
|
|
39
40
|
GOOGLE_CLOUD_PROJECT: gcpProject,
|
|
40
41
|
GCP_PROJECT: gcpProject,
|
|
41
42
|
GCLOUD_PROJECT: gcpProject,
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
|
-
async function initializeEmulator(context) {
|
|
45
|
+
async function initializeEmulator(context, port) {
|
|
45
46
|
const spanner = new Spanner({
|
|
46
47
|
servicePath: '127.0.0.1',
|
|
47
|
-
port
|
|
48
|
+
port,
|
|
48
49
|
projectId: getLocalGcpProject(context),
|
|
49
50
|
sslCreds: grpc.credentials.createInsecure(),
|
|
50
51
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { callDeferred } from '@causa/workspace';
|
|
2
2
|
import { EventTopicBrokerDeleteTriggerResource, } from '@causa/workspace-core';
|
|
3
|
+
import { PUBSUB_SUBSCRIPTION_ID_REGEX } from '../../services/pubsub.utils.js';
|
|
3
4
|
/**
|
|
4
5
|
* Implements {@link EventTopicBrokerDeleteTriggerResource} for Pub/Sub subscriptions.
|
|
5
6
|
* Pub/Sub subscriptions are for example used when creating Cloud Run triggers.
|
|
@@ -9,7 +10,7 @@ export class EventTopicBrokerDeleteTriggerResourceForPubSubSubscription extends
|
|
|
9
10
|
return await callDeferred(this, import.meta.url);
|
|
10
11
|
}
|
|
11
12
|
_supports() {
|
|
12
|
-
return (this.id
|
|
13
|
+
return (PUBSUB_SUBSCRIPTION_ID_REGEX.test(this.id) &&
|
|
13
14
|
this._context
|
|
14
15
|
.asConfiguration()
|
|
15
16
|
.get('events.broker') === 'google.pubSub');
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { setTimeout } from 'timers/promises';
|
|
2
|
+
import { CloudMonitoringService, } from '../../services/cloud-monitoring.js';
|
|
3
|
+
import { PUBSUB_SUBSCRIPTION_ID_REGEX, shortSubscriptionId, } from '../../services/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* The interval between two consecutive polls of the Cloud Monitoring API, in milliseconds.
|
|
6
|
+
*/
|
|
7
|
+
const POLL_INTERVAL = 30 * 1000;
|
|
8
|
+
/**
|
|
9
|
+
* The duration of the trailing window of points fetched on each poll, in milliseconds.
|
|
10
|
+
* It must be greater than `QUIET_WINDOW` plus a margin for the Cloud Monitoring export lag.
|
|
11
|
+
*/
|
|
12
|
+
const TRAILING_WINDOW = 10 * 60 * 1000;
|
|
13
|
+
/**
|
|
14
|
+
* The minimum duration (server-time, derived from point timestamps) over which all three monitored metrics must
|
|
15
|
+
* continuously report zero before a subscription is considered drained, in milliseconds.
|
|
16
|
+
*/
|
|
17
|
+
const QUIET_WINDOW = 3 * 60 * 1000;
|
|
18
|
+
/**
|
|
19
|
+
* The alignment period used when querying the cumulative `ack_message_count` metric so that points represent the
|
|
20
|
+
* number of acks within each bucket (delta), rather than the absolute cumulative value, in seconds.
|
|
21
|
+
*/
|
|
22
|
+
const ALIGNMENT_PERIOD = 60;
|
|
23
|
+
/**
|
|
24
|
+
* The overall timeout for waiting on a single subscription, in milliseconds.
|
|
25
|
+
* On timeout the function throws so that the backfill file is preserved for manual cleanup.
|
|
26
|
+
*/
|
|
27
|
+
const TIMEOUT = 60 * 60 * 1000;
|
|
28
|
+
/**
|
|
29
|
+
* Returns the Cloud Monitoring filter for the given metric on the given subscription.
|
|
30
|
+
*/
|
|
31
|
+
function buildFilter(metricType, subscriptionId) {
|
|
32
|
+
return [
|
|
33
|
+
`metric.type = "${metricType}"`,
|
|
34
|
+
`resource.type = "pubsub_subscription"`,
|
|
35
|
+
`resource.labels.subscription_id = "${subscriptionId}"`,
|
|
36
|
+
].join(' AND ');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Checks whether a gauge metric has been quiet (zero-valued) for at least {@link QUIET_WINDOW}.
|
|
40
|
+
*
|
|
41
|
+
* The check is purely server-side: the latest zero-valued point's timestamp must be at least `QUIET_WINDOW` after the
|
|
42
|
+
* latest non-zero point's timestamp. When no non-zero point exists in the trailing window, the metric is considered
|
|
43
|
+
* quiet (the outer liftoff gate is responsible for distinguishing "cold start" from "already drained").
|
|
44
|
+
*/
|
|
45
|
+
function isGaugeQuiet(points) {
|
|
46
|
+
const lastNonZeroTimestamp = points.filter(({ value }) => value > 0).at(-1)?.timestamp ?? -Infinity;
|
|
47
|
+
const latestZeroTimestamp = points.filter(({ value }) => value === 0).at(-1)?.timestamp ?? -Infinity;
|
|
48
|
+
return latestZeroTimestamp - lastNonZeroTimestamp >= QUIET_WINDOW;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Checks whether a cumulative metric (queried with `ALIGN_DELTA`) has had no non-zero activity in the trailing
|
|
52
|
+
* `QUIET_WINDOW` before the given reference time.
|
|
53
|
+
*
|
|
54
|
+
* Unlike a gauge, Pub/Sub stops writing samples for a cumulative metric while there is no activity. The server-side
|
|
55
|
+
* "still has zero points" anchor used by {@link isGaugeQuiet} therefore does not apply: the absence of points must be
|
|
56
|
+
* interpreted against an external time reference (the query end).
|
|
57
|
+
*/
|
|
58
|
+
function isCumulativeQuiet(points, referenceTime) {
|
|
59
|
+
const lastNonZeroTimestamp = points.filter(({ value }) => value > 0).at(-1)?.timestamp ?? -Infinity;
|
|
60
|
+
return referenceTime.getTime() - lastNonZeroTimestamp >= QUIET_WINDOW;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Observes a single subscription by fetching its three metrics over the configured trailing window and evaluating the
|
|
64
|
+
* liftoff and quiet conditions.
|
|
65
|
+
*/
|
|
66
|
+
async function observeSubscription(context, subscriptionId) {
|
|
67
|
+
const cms = context.service(CloudMonitoringService);
|
|
68
|
+
const end = new Date();
|
|
69
|
+
const start = new Date(end.getTime() - TRAILING_WINDOW);
|
|
70
|
+
const ackFilter = buildFilter('pubsub.googleapis.com/subscription/ack_message_count', subscriptionId);
|
|
71
|
+
const backlogFilter = buildFilter('pubsub.googleapis.com/subscription/num_undelivered_messages', subscriptionId);
|
|
72
|
+
const ageFilter = buildFilter('pubsub.googleapis.com/subscription/oldest_unacked_message_age', subscriptionId);
|
|
73
|
+
const [ackPoints, backlogPoints, agePoints] = await Promise.all([
|
|
74
|
+
cms.listPoints(ackFilter, start, end, {
|
|
75
|
+
aligner: 'ALIGN_DELTA',
|
|
76
|
+
alignmentPeriod: ALIGNMENT_PERIOD,
|
|
77
|
+
}),
|
|
78
|
+
cms.listPoints(backlogFilter, start, end),
|
|
79
|
+
cms.listPoints(ageFilter, start, end),
|
|
80
|
+
]);
|
|
81
|
+
const liftoff = ackPoints.some(({ value }) => value > 0);
|
|
82
|
+
const backlog = backlogPoints.at(-1)?.value ?? null;
|
|
83
|
+
const drained = liftoff &&
|
|
84
|
+
isCumulativeQuiet(ackPoints, end) &&
|
|
85
|
+
isGaugeQuiet(backlogPoints) &&
|
|
86
|
+
isGaugeQuiet(agePoints);
|
|
87
|
+
return { liftoff, backlog, drained };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Waits for a single subscription to be drained, polling Cloud Monitoring until either the drained state is reached
|
|
91
|
+
* or the overall timeout elapses.
|
|
92
|
+
*/
|
|
93
|
+
async function waitForSubscription(context, subscriptionId) {
|
|
94
|
+
const deadline = Date.now() + TIMEOUT;
|
|
95
|
+
while (true) {
|
|
96
|
+
const { drained, backlog, liftoff } = await observeSubscription(context, subscriptionId);
|
|
97
|
+
if (drained) {
|
|
98
|
+
context.logger.debug(`✅ Subscription '${subscriptionId}' drained: backlog is empty and metrics have been quiet for at least ${QUIET_WINDOW / 1000}s.`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const backlogLabel = backlog === null ? 'no data yet' : `backlog=${backlog}`;
|
|
102
|
+
context.logger.debug(`⏳ Subscription '${subscriptionId}' not drained yet (liftoff=${liftoff}, ${backlogLabel}).`);
|
|
103
|
+
if (Date.now() >= deadline) {
|
|
104
|
+
throw new Error(`Timed out after ${Math.round(TIMEOUT / 60_000)} minute(s) waiting for subscription '${subscriptionId}' to drain.`);
|
|
105
|
+
}
|
|
106
|
+
await setTimeout(POLL_INTERVAL);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export default async function call() {
|
|
110
|
+
const subscriptionIds = this.temporaryData.temporaryTriggerResourceIds
|
|
111
|
+
.filter((id) => PUBSUB_SUBSCRIPTION_ID_REGEX.test(id))
|
|
112
|
+
.map(shortSubscriptionId);
|
|
113
|
+
if (subscriptionIds.length === 0) {
|
|
114
|
+
throw new Error(`Cannot wait for processing of backfill on event topic '${this.eventTopic}': no temporary Pub/Sub subscription was created. Only backfills with temporary triggers are supported.`);
|
|
115
|
+
}
|
|
116
|
+
this._context.logger.info(`⏳ Waiting for processing of ${subscriptionIds.length} temporary Pub/Sub subscription(s) for event topic '${this.eventTopic}'.`);
|
|
117
|
+
await Promise.all(subscriptionIds.map((id) => waitForSubscription(this._context, id)));
|
|
118
|
+
this._context.logger.info(`✅ All temporary Pub/Sub subscriptions for event topic '${this.eventTopic}' have been drained.`);
|
|
119
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { EventTopicBrokerWaitForProcessing } from '@causa/workspace-core';
|
|
2
|
+
/**
|
|
3
|
+
* Implements {@link EventTopicBrokerWaitForProcessing} for Pub/Sub temporary subscriptions.
|
|
4
|
+
*
|
|
5
|
+
* Only backfills that created temporary push subscriptions are supported: at least one entry of
|
|
6
|
+
* {@link BackfillTemporaryData.temporaryTriggerResourceIds} must match a subscription ID. If none does, the function
|
|
7
|
+
* throws — there is no observable signal for backfills that publish into existing topics with existing subscriptions.
|
|
8
|
+
*
|
|
9
|
+
* Completion is decided per-subscription from Cloud Monitoring time series (`subscription/ack_message_count`,
|
|
10
|
+
* `subscription/num_undelivered_messages`, `subscription/oldest_unacked_message_age`). See the call file for the exact
|
|
11
|
+
* decision logic.
|
|
12
|
+
*/
|
|
13
|
+
export declare class EventTopicBrokerWaitForProcessingForPubSub extends EventTopicBrokerWaitForProcessing {
|
|
14
|
+
_call(): Promise<void>;
|
|
15
|
+
_supports(): boolean;
|
|
16
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { callDeferred } from '@causa/workspace';
|
|
2
|
+
import { EventTopicBrokerWaitForProcessing, } from '@causa/workspace-core';
|
|
3
|
+
/**
|
|
4
|
+
* Implements {@link EventTopicBrokerWaitForProcessing} for Pub/Sub temporary subscriptions.
|
|
5
|
+
*
|
|
6
|
+
* Only backfills that created temporary push subscriptions are supported: at least one entry of
|
|
7
|
+
* {@link BackfillTemporaryData.temporaryTriggerResourceIds} must match a subscription ID. If none does, the function
|
|
8
|
+
* throws — there is no observable signal for backfills that publish into existing topics with existing subscriptions.
|
|
9
|
+
*
|
|
10
|
+
* Completion is decided per-subscription from Cloud Monitoring time series (`subscription/ack_message_count`,
|
|
11
|
+
* `subscription/num_undelivered_messages`, `subscription/oldest_unacked_message_age`). See the call file for the exact
|
|
12
|
+
* decision logic.
|
|
13
|
+
*/
|
|
14
|
+
export class EventTopicBrokerWaitForProcessingForPubSub extends EventTopicBrokerWaitForProcessing {
|
|
15
|
+
async _call() {
|
|
16
|
+
return await callDeferred(this, import.meta.url);
|
|
17
|
+
}
|
|
18
|
+
_supports() {
|
|
19
|
+
return (this._context
|
|
20
|
+
.asConfiguration()
|
|
21
|
+
.get('events.broker') === 'google.pubSub');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -6,5 +6,6 @@ export { EventTopicBrokerDeleteTriggerResourceForPubSubSubscription } from './br
|
|
|
6
6
|
export { EventTopicBrokerDeleteTriggerResourceForServiceAccount } from './broker-delete-trigger-resource-service-account.js';
|
|
7
7
|
export { EventTopicBrokerGetTopicIdForPubSub } from './broker-get-topic-id-pubsub.js';
|
|
8
8
|
export { EventTopicBrokerPublishEventsForGoogle } from './broker-publish-events-google.js';
|
|
9
|
+
export { EventTopicBrokerWaitForProcessingForPubSub } from './broker-wait-for-processing-pubsub.js';
|
|
9
10
|
export { EventTopicCreateBackfillSourceForBigQuery } from './create-backfill-source-bigquery.js';
|
|
10
11
|
export { EventTopicQueryEventsForBigQuery } from './query-events-bigquery.js';
|
|
@@ -6,5 +6,6 @@ export { EventTopicBrokerDeleteTriggerResourceForPubSubSubscription } from './br
|
|
|
6
6
|
export { EventTopicBrokerDeleteTriggerResourceForServiceAccount } from './broker-delete-trigger-resource-service-account.js';
|
|
7
7
|
export { EventTopicBrokerGetTopicIdForPubSub } from './broker-get-topic-id-pubsub.js';
|
|
8
8
|
export { EventTopicBrokerPublishEventsForGoogle } from './broker-publish-events-google.js';
|
|
9
|
+
export { EventTopicBrokerWaitForProcessingForPubSub } from './broker-wait-for-processing-pubsub.js';
|
|
9
10
|
export { EventTopicCreateBackfillSourceForBigQuery } from './create-backfill-source-bigquery.js';
|
|
10
11
|
export { EventTopicQueryEventsForBigQuery } from './query-events-bigquery.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ModelGenerateTypeScriptDecorators } from '@causa/workspace-typescript';
|
|
2
|
+
import { type TypeScriptDecorator } from '@causa/workspace-typescript/code-generation';
|
|
3
|
+
/**
|
|
4
|
+
* Implements {@link ModelGenerateTypeScriptDecorators} to add Google Firestore decorators from the Causa Google runtime.
|
|
5
|
+
*
|
|
6
|
+
* If an object schema is marked with the `googleFirestoreCollection` extension, the `@FirestoreCollection` decorator is
|
|
7
|
+
* added to the class. If the `hasSoftDelete` property is `true`, the `@SoftDeletedFirestoreCollection` decorator is also
|
|
8
|
+
* added.
|
|
9
|
+
*/
|
|
10
|
+
export declare class ModelGenerateTypeScriptDecoratorsForGoogleFirestore extends ModelGenerateTypeScriptDecorators {
|
|
11
|
+
_call(): TypeScriptDecorator[];
|
|
12
|
+
_supports(): boolean;
|
|
13
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ModelGenerateTypeScriptDecorators } from '@causa/workspace-typescript';
|
|
2
|
+
import { addDecoratorToList, } from '@causa/workspace-typescript/code-generation';
|
|
3
|
+
import micromatch from 'micromatch';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
/**
|
|
6
|
+
* The name of the Causa extension marking an object schema as a Google Firestore collection.
|
|
7
|
+
*/
|
|
8
|
+
const GOOGLE_FIRESTORE_COLLECTION_EXTENSION = 'googleFirestoreCollection';
|
|
9
|
+
/**
|
|
10
|
+
* The name of the Causa module for the TypeScript Google runtime.
|
|
11
|
+
*/
|
|
12
|
+
const CAUSA_GOOGLE_MODULE = '@causa/runtime-google';
|
|
13
|
+
/**
|
|
14
|
+
* Implements {@link ModelGenerateTypeScriptDecorators} to add Google Firestore decorators from the Causa Google runtime.
|
|
15
|
+
*
|
|
16
|
+
* If an object schema is marked with the `googleFirestoreCollection` extension, the `@FirestoreCollection` decorator is
|
|
17
|
+
* added to the class. If the `hasSoftDelete` property is `true`, the `@SoftDeletedFirestoreCollection` decorator is also
|
|
18
|
+
* added.
|
|
19
|
+
*/
|
|
20
|
+
export class ModelGenerateTypeScriptDecoratorsForGoogleFirestore extends ModelGenerateTypeScriptDecorators {
|
|
21
|
+
_call() {
|
|
22
|
+
if (this.property) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const attribute = this.schema.extensions[GOOGLE_FIRESTORE_COLLECTION_EXTENSION];
|
|
26
|
+
if (!attribute) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
const globs = this.configuration?.google?.firestore?.globs;
|
|
30
|
+
if (Array.isArray(globs)) {
|
|
31
|
+
const projectPath = this._context.getProjectPathOrThrow();
|
|
32
|
+
const absoluteGlobs = globs.map((g) => join(projectPath, g));
|
|
33
|
+
const schemaPath = this.schema.path.split('#')[0];
|
|
34
|
+
if (!micromatch.isMatch(schemaPath, absoluteGlobs)) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const debugName = this.schema.name;
|
|
39
|
+
if (typeof attribute !== 'object') {
|
|
40
|
+
throw new Error(`Invalid '${GOOGLE_FIRESTORE_COLLECTION_EXTENSION}' attribute on '${debugName}'. Expected an object.`);
|
|
41
|
+
}
|
|
42
|
+
const { name, path, hasSoftDelete } = attribute;
|
|
43
|
+
if (typeof name !== 'string') {
|
|
44
|
+
throw new Error(`Invalid '${GOOGLE_FIRESTORE_COLLECTION_EXTENSION}' attribute on '${debugName}'. Expected an object with a 'name' string property.`);
|
|
45
|
+
}
|
|
46
|
+
if (!Array.isArray(path)) {
|
|
47
|
+
throw new Error(`Invalid '${GOOGLE_FIRESTORE_COLLECTION_EXTENSION}' attribute on '${debugName}'. Expected an object with a 'path' array property.`);
|
|
48
|
+
}
|
|
49
|
+
const propertyNames = new Set(this.schema.properties.map((p) => p.name));
|
|
50
|
+
const elements = path.map((element) => {
|
|
51
|
+
if (typeof element === 'string') {
|
|
52
|
+
return JSON.stringify(element);
|
|
53
|
+
}
|
|
54
|
+
if (typeof element === 'object' &&
|
|
55
|
+
element !== null &&
|
|
56
|
+
'property' in element &&
|
|
57
|
+
typeof element.property === 'string') {
|
|
58
|
+
const propertyName = element.property;
|
|
59
|
+
if (!propertyNames.has(propertyName)) {
|
|
60
|
+
throw new Error(`Property '${propertyName}' referenced in 'path' not found in '${debugName}'.`);
|
|
61
|
+
}
|
|
62
|
+
return `doc.${propertyName}`;
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`Invalid path element in '${GOOGLE_FIRESTORE_COLLECTION_EXTENSION}' attribute on '${debugName}'.`);
|
|
65
|
+
});
|
|
66
|
+
const pathExpression = path.length === 1 ? elements[0] : `[${elements.join(', ')}].join("/")`;
|
|
67
|
+
const decorators = [];
|
|
68
|
+
addDecoratorToList(decorators, { schema: this.schema }, 'FirestoreCollection', CAUSA_GOOGLE_MODULE, `@FirestoreCollection({ name: ${JSON.stringify(name)}, path: (doc) => ${pathExpression} })`);
|
|
69
|
+
if (hasSoftDelete === true) {
|
|
70
|
+
addDecoratorToList(decorators, { schema: this.schema }, 'SoftDeletedFirestoreCollection', CAUSA_GOOGLE_MODULE, '@SoftDeletedFirestoreCollection()');
|
|
71
|
+
}
|
|
72
|
+
return decorators;
|
|
73
|
+
}
|
|
74
|
+
_supports() {
|
|
75
|
+
return (this._context.get('project.language') === 'typescript' &&
|
|
76
|
+
this.generator === 'typescriptModelClass');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { ModelSchemaExtractDatabaseForGoogleFirestore } from './extract-database.js';
|
|
2
|
+
export { ModelGenerateTypeScriptDecoratorsForGoogleFirestore } from './generate-typescript-decorators.js';
|
|
2
3
|
export { DatabaseQueryRecordsForFirestore } from './query-records.js';
|
|
3
4
|
export { GoogleFirestoreMergeRules } from './merge-rules.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { ModelSchemaExtractDatabaseForGoogleFirestore } from './extract-database.js';
|
|
2
|
+
export { ModelGenerateTypeScriptDecoratorsForGoogleFirestore } from './generate-typescript-decorators.js';
|
|
2
3
|
export { DatabaseQueryRecordsForFirestore } from './query-records.js';
|
|
3
4
|
export { GoogleFirestoreMergeRules } from './merge-rules.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ModelGenerateTypeScriptDecorators } from '@causa/workspace-typescript';
|
|
2
|
+
import { type TypeScriptDecorator } from '@causa/workspace-typescript/code-generation';
|
|
3
|
+
/**
|
|
4
|
+
* Implements {@link ModelGenerateTypeScriptDecorators} to add Google Spanner decorators from the Causa Google runtime.
|
|
5
|
+
*
|
|
6
|
+
* If an object schema is marked with the `googleSpannerTable` extension, the `@SpannerTable` decorator is added to the
|
|
7
|
+
* class, and `@SpannerColumn` decorators are added to all its properties.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ModelGenerateTypeScriptDecoratorsForGoogleSpanner extends ModelGenerateTypeScriptDecorators {
|
|
10
|
+
_call(): TypeScriptDecorator[];
|
|
11
|
+
_supports(): boolean;
|
|
12
|
+
private decoratorsForClass;
|
|
13
|
+
private decoratorsForProperty;
|
|
14
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { ModelGenerateTypeScriptDecorators } from '@causa/workspace-typescript';
|
|
2
|
+
import { addDecoratorToList, } from '@causa/workspace-typescript/code-generation';
|
|
3
|
+
import micromatch from 'micromatch';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
/**
|
|
6
|
+
* The name of the Causa extension marking an object schema as a Google Spanner table.
|
|
7
|
+
*/
|
|
8
|
+
const GOOGLE_SPANNER_TABLE_EXTENSION = 'googleSpannerTable';
|
|
9
|
+
/**
|
|
10
|
+
* The name of the optional Causa extension that can be present on an object property schema to specify options for the
|
|
11
|
+
* `@SpannerColumn` decorator.
|
|
12
|
+
*/
|
|
13
|
+
const GOOGLE_SPANNER_COLUMN_EXTENSION = 'googleSpannerColumn';
|
|
14
|
+
/**
|
|
15
|
+
* The name of the Causa module for the TypeScript Google runtime.
|
|
16
|
+
*/
|
|
17
|
+
const CAUSA_GOOGLE_MODULE = '@causa/runtime-google';
|
|
18
|
+
/**
|
|
19
|
+
* The list of options that can be passed to the `@SpannerColumn` decorator and that indicates that the schema specifies
|
|
20
|
+
* the type of the column. In this case, the renderer should not infer any type information.
|
|
21
|
+
*/
|
|
22
|
+
const TYPE_INFO_COLUMN_ATTRIBUTE_NAMES = [
|
|
23
|
+
'isBigInt',
|
|
24
|
+
'isInt',
|
|
25
|
+
'isPreciseDate',
|
|
26
|
+
'isJson',
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Implements {@link ModelGenerateTypeScriptDecorators} to add Google Spanner decorators from the Causa Google runtime.
|
|
30
|
+
*
|
|
31
|
+
* If an object schema is marked with the `googleSpannerTable` extension, the `@SpannerTable` decorator is added to the
|
|
32
|
+
* class, and `@SpannerColumn` decorators are added to all its properties.
|
|
33
|
+
*/
|
|
34
|
+
export class ModelGenerateTypeScriptDecoratorsForGoogleSpanner extends ModelGenerateTypeScriptDecorators {
|
|
35
|
+
_call() {
|
|
36
|
+
const tableAttribute = this.schema.extensions[GOOGLE_SPANNER_TABLE_EXTENSION];
|
|
37
|
+
if (!tableAttribute) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const globs = this.configuration?.google?.spanner?.globs;
|
|
41
|
+
if (Array.isArray(globs)) {
|
|
42
|
+
const projectPath = this._context.getProjectPathOrThrow();
|
|
43
|
+
const absoluteGlobs = globs.map((g) => join(projectPath, g));
|
|
44
|
+
const schemaPath = this.schema.path.split('#')[0];
|
|
45
|
+
if (!micromatch.isMatch(schemaPath, absoluteGlobs)) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return this.property
|
|
50
|
+
? this.decoratorsForProperty()
|
|
51
|
+
: this.decoratorsForClass(tableAttribute);
|
|
52
|
+
}
|
|
53
|
+
_supports() {
|
|
54
|
+
return (this._context.get('project.language') === 'typescript' &&
|
|
55
|
+
this.generator === 'typescriptModelClass');
|
|
56
|
+
}
|
|
57
|
+
decoratorsForClass(tableAttribute) {
|
|
58
|
+
const debugName = this.schema.name;
|
|
59
|
+
if (typeof tableAttribute !== 'object' ||
|
|
60
|
+
tableAttribute === null ||
|
|
61
|
+
!('primaryKey' in tableAttribute) ||
|
|
62
|
+
!Array.isArray(tableAttribute.primaryKey) ||
|
|
63
|
+
tableAttribute.primaryKey.length === 0 ||
|
|
64
|
+
tableAttribute.primaryKey.some((k) => typeof k !== 'string')) {
|
|
65
|
+
throw new Error(`Invalid '${GOOGLE_SPANNER_TABLE_EXTENSION}' attribute on '${debugName}'. Expected an object with a 'primaryKey' array.`);
|
|
66
|
+
}
|
|
67
|
+
const { primaryKey, name } = tableAttribute;
|
|
68
|
+
if (name !== undefined && typeof name !== 'string') {
|
|
69
|
+
throw new Error(`Invalid 'name' in '${GOOGLE_SPANNER_TABLE_EXTENSION}' attribute on '${debugName}'. Expected a string.`);
|
|
70
|
+
}
|
|
71
|
+
const decorators = [];
|
|
72
|
+
addDecoratorToList(decorators, { schema: this.schema }, 'SpannerTable', CAUSA_GOOGLE_MODULE, `@SpannerTable(${JSON.stringify({ primaryKey, name })})`);
|
|
73
|
+
return decorators;
|
|
74
|
+
}
|
|
75
|
+
decoratorsForProperty() {
|
|
76
|
+
const property = this.property;
|
|
77
|
+
const rawAttributes = property.extensions[GOOGLE_SPANNER_COLUMN_EXTENSION] ?? {};
|
|
78
|
+
if (typeof rawAttributes !== 'object' || rawAttributes === null) {
|
|
79
|
+
throw new Error(`Invalid '${GOOGLE_SPANNER_COLUMN_EXTENSION}' attribute on '${this.schema.name}.${property.name}'. Expected an object.`);
|
|
80
|
+
}
|
|
81
|
+
const { name: overriddenName, tsOptions } = rawAttributes;
|
|
82
|
+
if (tsOptions !== undefined &&
|
|
83
|
+
(typeof tsOptions !== 'object' || tsOptions === null)) {
|
|
84
|
+
throw new Error(`Invalid 'tsOptions' in '${GOOGLE_SPANNER_COLUMN_EXTENSION}' attribute. Expected an object.`);
|
|
85
|
+
}
|
|
86
|
+
const columnAttributes = {
|
|
87
|
+
...(tsOptions ?? {}),
|
|
88
|
+
};
|
|
89
|
+
if (overriddenName !== undefined) {
|
|
90
|
+
if (typeof overriddenName !== 'string') {
|
|
91
|
+
throw new Error(`Invalid 'name' in '${GOOGLE_SPANNER_COLUMN_EXTENSION}' attribute. Expected a string.`);
|
|
92
|
+
}
|
|
93
|
+
columnAttributes.name = overriddenName;
|
|
94
|
+
}
|
|
95
|
+
const softDeletionColumn = this.configuration?.google?.spanner
|
|
96
|
+
?.softDeletionColumn;
|
|
97
|
+
const columnName = typeof overriddenName === 'string' ? overriddenName : property.name;
|
|
98
|
+
if (columnName === softDeletionColumn) {
|
|
99
|
+
columnAttributes.softDelete = true;
|
|
100
|
+
}
|
|
101
|
+
const schemaOverridesTypeInfo = TYPE_INFO_COLUMN_ATTRIBUTE_NAMES.some((n) => n in columnAttributes);
|
|
102
|
+
if (!schemaOverridesTypeInfo) {
|
|
103
|
+
const type = property.type.kind === 'array' ? property.type.items : property.type;
|
|
104
|
+
const resolved = type.kind === 'ref' ? this.schemas[type.ref] : undefined;
|
|
105
|
+
if (type.kind === 'primitive' && type.type === 'integer') {
|
|
106
|
+
columnAttributes.isInt = true;
|
|
107
|
+
}
|
|
108
|
+
else if (type.kind === 'map' || resolved?.kind === 'object') {
|
|
109
|
+
columnAttributes.isJson = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const hasOptions = Object.keys(columnAttributes).length > 0;
|
|
113
|
+
const source = hasOptions
|
|
114
|
+
? `@SpannerColumn(${JSON.stringify(columnAttributes)})`
|
|
115
|
+
: '@SpannerColumn()';
|
|
116
|
+
const decorators = [];
|
|
117
|
+
addDecoratorToList(decorators, { schema: this.schema, property }, 'SpannerColumn', CAUSA_GOOGLE_MODULE, source);
|
|
118
|
+
return decorators;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { ModelSchemaExtractDatabaseForGoogleSpanner } from './extract-database.js';
|
|
2
|
+
export { ModelGenerateTypeScriptDecoratorsForGoogleSpanner } from './generate-typescript-decorators.js';
|
|
2
3
|
export { GoogleSpannerListDatabases } from './list-databases.js';
|
|
3
4
|
export { DatabaseQueryRecordsForSpanner } from './query-records.js';
|
|
4
5
|
export { GoogleSpannerWriteDatabases } from './write-databases.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { ModelSchemaExtractDatabaseForGoogleSpanner } from './extract-database.js';
|
|
2
|
+
export { ModelGenerateTypeScriptDecoratorsForGoogleSpanner } from './generate-typescript-decorators.js';
|
|
2
3
|
export { GoogleSpannerListDatabases } from './list-databases.js';
|
|
3
4
|
export { DatabaseQueryRecordsForSpanner } from './query-records.js';
|
|
4
5
|
export { GoogleSpannerWriteDatabases } from './write-databases.js';
|
package/dist/functions/index.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { CausaListConfigurationSchemasForGoogle } from './causa/index.js';
|
|
2
2
|
import { EmulatorStartForFirebaseStorage, EmulatorStartForFirestore, EmulatorStartForIdentityPlatform, EmulatorStartForPubSub, EmulatorStartForSpanner, EmulatorStopForFirebaseStorage, EmulatorStopForFirestore, EmulatorStopForIdentityPlatform, EmulatorStopForPubSub, EmulatorStopForSpanner, } from './emulator/index.js';
|
|
3
|
-
import { EventTopicBrokerCreateTopicForPubSub, EventTopicBrokerCreateTriggerForCloudRun, EventTopicBrokerDeleteTopicForPubSub, EventTopicBrokerDeleteTriggerResourceForCloudRunInvokerRole, EventTopicBrokerDeleteTriggerResourceForPubSubSubscription, EventTopicBrokerDeleteTriggerResourceForServiceAccount, EventTopicBrokerGetTopicIdForPubSub, EventTopicBrokerPublishEventsForGoogle, EventTopicCreateBackfillSourceForBigQuery, EventTopicQueryEventsForBigQuery, } from './event-topic/index.js';
|
|
3
|
+
import { EventTopicBrokerCreateTopicForPubSub, EventTopicBrokerCreateTriggerForCloudRun, EventTopicBrokerDeleteTopicForPubSub, EventTopicBrokerDeleteTriggerResourceForCloudRunInvokerRole, EventTopicBrokerDeleteTriggerResourceForPubSubSubscription, EventTopicBrokerDeleteTriggerResourceForServiceAccount, EventTopicBrokerGetTopicIdForPubSub, EventTopicBrokerPublishEventsForGoogle, EventTopicBrokerWaitForProcessingForPubSub, EventTopicCreateBackfillSourceForBigQuery, EventTopicQueryEventsForBigQuery, } from './event-topic/index.js';
|
|
4
4
|
import { GoogleAppCheckGenerateToken } from './google-app-check/index.js';
|
|
5
5
|
import { GoogleFirebaseStorageMergeRules } from './google-firebase-storage/index.js';
|
|
6
|
-
import { DatabaseQueryRecordsForFirestore, GoogleFirestoreMergeRules, ModelSchemaExtractDatabaseForGoogleFirestore, } from './google-firestore/index.js';
|
|
6
|
+
import { DatabaseQueryRecordsForFirestore, GoogleFirestoreMergeRules, ModelGenerateTypeScriptDecoratorsForGoogleFirestore, ModelSchemaExtractDatabaseForGoogleFirestore, } from './google-firestore/index.js';
|
|
7
7
|
import { GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenerateToken, } from './google-identity-platform/index.js';
|
|
8
8
|
import { GooglePubSubWriteTopics } from './google-pubsub/index.js';
|
|
9
9
|
import { GoogleServicesEnable } from './google-services/index.js';
|
|
10
|
-
import { DatabaseQueryRecordsForSpanner, GoogleSpannerListDatabases, GoogleSpannerWriteDatabases, ModelSchemaExtractDatabaseForGoogleSpanner, } from './google-spanner/index.js';
|
|
10
|
+
import { DatabaseQueryRecordsForSpanner, GoogleSpannerListDatabases, GoogleSpannerWriteDatabases, ModelGenerateTypeScriptDecoratorsForGoogleSpanner, ModelSchemaExtractDatabaseForGoogleSpanner, } from './google-spanner/index.js';
|
|
11
11
|
import { ProjectGetArtefactDestinationForCloudFunctions, ProjectGetArtefactDestinationForCloudRun, ProjectPushArtefactForCloudFunctions, } from './project/index.js';
|
|
12
12
|
import { SecretFetchForGoogleAccessToken, SecretFetchForGoogleSecretManager, } from './secret/index.js';
|
|
13
13
|
import { ServiceContainerQueryLogsForCloudRun } from './service-container/index.js';
|
|
14
|
-
import { TypeScriptGetDecoratorRendererForGoogleFirestore, TypeScriptGetDecoratorRendererForGoogleSpanner, } from './typescript/index.js';
|
|
15
14
|
export function registerFunctions(context) {
|
|
16
|
-
context.registerFunctionImplementations(CausaListConfigurationSchemasForGoogle, DatabaseQueryRecordsForFirestore, DatabaseQueryRecordsForSpanner, EmulatorStartForFirebaseStorage, EmulatorStartForFirestore, EmulatorStartForIdentityPlatform, EmulatorStartForPubSub, EmulatorStartForSpanner, EmulatorStopForFirebaseStorage, EmulatorStopForFirestore, EmulatorStopForIdentityPlatform, EmulatorStopForPubSub, EmulatorStopForSpanner, EventTopicBrokerCreateTopicForPubSub, EventTopicBrokerCreateTriggerForCloudRun, EventTopicBrokerDeleteTopicForPubSub, EventTopicBrokerDeleteTriggerResourceForCloudRunInvokerRole, EventTopicBrokerDeleteTriggerResourceForPubSubSubscription, EventTopicBrokerDeleteTriggerResourceForServiceAccount, EventTopicBrokerGetTopicIdForPubSub, EventTopicBrokerPublishEventsForGoogle, EventTopicCreateBackfillSourceForBigQuery, EventTopicQueryEventsForBigQuery, GoogleAppCheckGenerateToken, GoogleFirebaseStorageMergeRules, GoogleFirestoreMergeRules, GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenerateToken, GooglePubSubWriteTopics, GoogleServicesEnable, GoogleSpannerListDatabases, GoogleSpannerWriteDatabases, ModelSchemaExtractDatabaseForGoogleFirestore, ModelSchemaExtractDatabaseForGoogleSpanner, ProjectGetArtefactDestinationForCloudFunctions, ProjectGetArtefactDestinationForCloudRun, ProjectPushArtefactForCloudFunctions, SecretFetchForGoogleAccessToken, SecretFetchForGoogleSecretManager, ServiceContainerQueryLogsForCloudRun
|
|
15
|
+
context.registerFunctionImplementations(CausaListConfigurationSchemasForGoogle, DatabaseQueryRecordsForFirestore, DatabaseQueryRecordsForSpanner, EmulatorStartForFirebaseStorage, EmulatorStartForFirestore, EmulatorStartForIdentityPlatform, EmulatorStartForPubSub, EmulatorStartForSpanner, EmulatorStopForFirebaseStorage, EmulatorStopForFirestore, EmulatorStopForIdentityPlatform, EmulatorStopForPubSub, EmulatorStopForSpanner, EventTopicBrokerCreateTopicForPubSub, EventTopicBrokerCreateTriggerForCloudRun, EventTopicBrokerDeleteTopicForPubSub, EventTopicBrokerDeleteTriggerResourceForCloudRunInvokerRole, EventTopicBrokerDeleteTriggerResourceForPubSubSubscription, EventTopicBrokerDeleteTriggerResourceForServiceAccount, EventTopicBrokerGetTopicIdForPubSub, EventTopicBrokerPublishEventsForGoogle, EventTopicBrokerWaitForProcessingForPubSub, EventTopicCreateBackfillSourceForBigQuery, EventTopicQueryEventsForBigQuery, GoogleAppCheckGenerateToken, GoogleFirebaseStorageMergeRules, GoogleFirestoreMergeRules, GoogleIdentityPlatformGenerateCustomToken, GoogleIdentityPlatformGenerateToken, GooglePubSubWriteTopics, GoogleServicesEnable, GoogleSpannerListDatabases, GoogleSpannerWriteDatabases, ModelGenerateTypeScriptDecoratorsForGoogleFirestore, ModelGenerateTypeScriptDecoratorsForGoogleSpanner, ModelSchemaExtractDatabaseForGoogleFirestore, ModelSchemaExtractDatabaseForGoogleSpanner, ProjectGetArtefactDestinationForCloudFunctions, ProjectGetArtefactDestinationForCloudRun, ProjectPushArtefactForCloudFunctions, SecretFetchForGoogleAccessToken, SecretFetchForGoogleSecretManager, ServiceContainerQueryLogsForCloudRun);
|
|
17
16
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { WorkspaceContext } from '@causa/workspace';
|
|
2
|
+
import { MetricServiceClient } from '@google-cloud/monitoring';
|
|
3
|
+
/**
|
|
4
|
+
* A single metric point with its server-side end timestamp (as milliseconds since epoch) and numeric value.
|
|
5
|
+
*/
|
|
6
|
+
export type MetricPoint = {
|
|
7
|
+
/**
|
|
8
|
+
* The end timestamp of the point's interval, as milliseconds since epoch.
|
|
9
|
+
*/
|
|
10
|
+
readonly timestamp: number;
|
|
11
|
+
/**
|
|
12
|
+
* The numeric value of the point.
|
|
13
|
+
*/
|
|
14
|
+
readonly value: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A service exposing a thin wrapper around the Cloud Monitoring API.
|
|
18
|
+
*/
|
|
19
|
+
export declare class CloudMonitoringService {
|
|
20
|
+
/**
|
|
21
|
+
* The underlying Cloud Monitoring client.
|
|
22
|
+
*/
|
|
23
|
+
readonly client: MetricServiceClient;
|
|
24
|
+
/**
|
|
25
|
+
* The ID of the GCP project from which metrics are read.
|
|
26
|
+
*/
|
|
27
|
+
readonly projectId: string;
|
|
28
|
+
constructor(context: WorkspaceContext);
|
|
29
|
+
/**
|
|
30
|
+
* Fetches the data points for a single time series over the given time interval.
|
|
31
|
+
* Returns the points sorted in ascending timestamp order. Each point's timestamp is the end of the corresponding
|
|
32
|
+
* interval, in milliseconds since epoch. An empty array is returned when no series matches the filter.
|
|
33
|
+
*
|
|
34
|
+
* @param filter The Cloud Monitoring metric filter expression (e.g. `metric.type = "..."`).
|
|
35
|
+
* @param start The inclusive lower bound of the interval to fetch.
|
|
36
|
+
* @param end The exclusive upper bound of the interval to fetch.
|
|
37
|
+
* @param options Optional aggregation options.
|
|
38
|
+
* @returns The list of points, ordered by ascending timestamp.
|
|
39
|
+
*/
|
|
40
|
+
listPoints(filter: string, start: Date, end: Date, options?: {
|
|
41
|
+
readonly alignmentPeriod?: number;
|
|
42
|
+
readonly aligner?: 'ALIGN_NONE' | 'ALIGN_DELTA' | 'ALIGN_RATE' | 'ALIGN_MEAN' | 'ALIGN_MAX';
|
|
43
|
+
}): Promise<MetricPoint[]>;
|
|
44
|
+
}
|