UNPKG

8.72 kBJavaScriptView Raw
1"use strict";
2// The MIT License (MIT)
3//
4// Copyright (c) 2022 Firebase
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in all
14// copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22// SOFTWARE.
23Object.defineProperty(exports, "__esModule", { value: true });
24exports.getOptsAndBucket = exports.onOperation = exports.onObjectMetadataUpdated = exports.onObjectDeleted = exports.onObjectFinalized = exports.onObjectArchived = exports.metadataUpdatedEvent = exports.deletedEvent = exports.finalizedEvent = exports.archivedEvent = void 0;
25/**
26 * Cloud functions to handle events from Google Cloud Storage.
27 * @packageDocumentation
28 */
29const config_1 = require("../../common/config");
30const encoding_1 = require("../../common/encoding");
31const manifest_1 = require("../../runtime/manifest");
32const trace_1 = require("../trace");
33const options = require("../options");
34const onInit_1 = require("../../common/onInit");
35/** @internal */
36exports.archivedEvent = "google.cloud.storage.object.v1.archived";
37/** @internal */
38exports.finalizedEvent = "google.cloud.storage.object.v1.finalized";
39/** @internal */
40exports.deletedEvent = "google.cloud.storage.object.v1.deleted";
41/** @internal */
42exports.metadataUpdatedEvent = "google.cloud.storage.object.v1.metadataUpdated";
43/**
44 * Event handler sent only when a bucket has enabled object versioning.
45 * This event indicates that the live version of an object has become an
46 * archived version, either because it was archived or because it was
47 * overwritten by the upload of an object of the same name.
48 *
49 * @param bucketOrOptsOrHandler - Options or string that may (or may not) define the bucket to be used.
50 * @param handler - Event handler which is run every time a Google Cloud Storage archival occurs.
51 */
52function onObjectArchived(bucketOrOptsOrHandler, handler) {
53 return onOperation(exports.archivedEvent, bucketOrOptsOrHandler, handler);
54}
55exports.onObjectArchived = onObjectArchived;
56/**
57 * Event handler which fires every time a Google Cloud Storage object
58 * creation occurs.
59 *
60 * Sent when a new object (or a new generation of an existing object)
61 * is successfully created in the bucket. This includes copying or rewriting
62 * an existing object. A failed upload does not trigger this event.
63 *
64 * @param bucketOrOptsOrHandler - Options or string that may (or may not) define the bucket to be used.
65 * @param handler - Event handler which is run every time a Google Cloud Storage object creation occurs.
66 */
67function onObjectFinalized(bucketOrOptsOrHandler, handler) {
68 return onOperation(exports.finalizedEvent, bucketOrOptsOrHandler, handler);
69}
70exports.onObjectFinalized = onObjectFinalized;
71/**
72 * Event handler which fires every time a Google Cloud Storage deletion occurs.
73 *
74 * Sent when an object has been permanently deleted. This includes objects
75 * that are overwritten or are deleted as part of the bucket's lifecycle
76 * configuration. For buckets with object versioning enabled, this is not
77 * sent when an object is archived, even if archival occurs
78 * via the `storage.objects.delete` method.
79 *
80 * @param bucketOrOptsOrHandler - Options or string that may (or may not) define the bucket to be used.
81 * @param handler - Event handler which is run every time a Google Cloud Storage object deletion occurs.
82 */
83function onObjectDeleted(bucketOrOptsOrHandler, handler) {
84 return onOperation(exports.deletedEvent, bucketOrOptsOrHandler, handler);
85}
86exports.onObjectDeleted = onObjectDeleted;
87/**
88 * Event handler which fires every time the metadata of an existing object
89 * changes.
90 *
91 * @param bucketOrOptsOrHandler - Options or string that may (or may not) define the bucket to be used.
92 * @param handler - Event handler which is run every time a Google Cloud Storage object metadata update occurs.
93 */
94function onObjectMetadataUpdated(bucketOrOptsOrHandler, handler) {
95 return onOperation(exports.metadataUpdatedEvent, bucketOrOptsOrHandler, handler);
96}
97exports.onObjectMetadataUpdated = onObjectMetadataUpdated;
98/** @internal */
99function onOperation(eventType, bucketOrOptsOrHandler, handler) {
100 if (typeof bucketOrOptsOrHandler === "function") {
101 handler = bucketOrOptsOrHandler;
102 bucketOrOptsOrHandler = {};
103 }
104 const [opts, bucket] = getOptsAndBucket(bucketOrOptsOrHandler);
105 const func = (raw) => {
106 return (0, trace_1.wrapTraceContext)((0, onInit_1.withInit)(handler))(raw);
107 };
108 func.run = handler;
109 Object.defineProperty(func, "__trigger", {
110 get: () => {
111 const baseOpts = options.optionsToTriggerAnnotations(options.getGlobalOptions());
112 const specificOpts = options.optionsToTriggerAnnotations(opts);
113 return {
114 platform: "gcfv2",
115 ...baseOpts,
116 ...specificOpts,
117 labels: {
118 ...baseOpts === null || baseOpts === void 0 ? void 0 : baseOpts.labels,
119 ...specificOpts === null || specificOpts === void 0 ? void 0 : specificOpts.labels,
120 },
121 eventTrigger: {
122 eventType,
123 resource: bucket, // TODO(colerogers): replace with 'bucket,' eventually
124 },
125 };
126 },
127 });
128 // TypeScript doesn't recognize defineProperty as adding a property and complains
129 // that __endpoint doesn't exist. We can either cast to any and lose all type safety
130 // or we can just assign a meaningless value before calling defineProperty.
131 func.__endpoint = {};
132 // SDK may attempt to read FIREBASE_CONFIG env var to fetch the default bucket name.
133 // To prevent runtime errors when FIREBASE_CONFIG env var is missing, we use getters.
134 Object.defineProperty(func, "__endpoint", {
135 get: () => {
136 var _a;
137 const baseOpts = options.optionsToEndpoint(options.getGlobalOptions());
138 const specificOpts = options.optionsToEndpoint(opts);
139 const endpoint = {
140 platform: "gcfv2",
141 ...(0, manifest_1.initV2Endpoint)(options.getGlobalOptions(), opts),
142 ...baseOpts,
143 ...specificOpts,
144 labels: {
145 ...baseOpts === null || baseOpts === void 0 ? void 0 : baseOpts.labels,
146 ...specificOpts === null || specificOpts === void 0 ? void 0 : specificOpts.labels,
147 },
148 eventTrigger: {
149 eventType,
150 eventFilters: { bucket },
151 retry: (_a = opts.retry) !== null && _a !== void 0 ? _a : false,
152 },
153 };
154 (0, encoding_1.copyIfPresent)(endpoint.eventTrigger, opts, "retry", "retry");
155 return endpoint;
156 },
157 });
158 return func;
159}
160exports.onOperation = onOperation;
161/** @internal */
162function getOptsAndBucket(bucketOrOpts) {
163 var _a;
164 let bucket;
165 let opts;
166 // If bucket is a string or Expression<string>
167 if (typeof bucketOrOpts === "string" || "value" in bucketOrOpts) {
168 bucket = bucketOrOpts;
169 opts = {};
170 }
171 else {
172 bucket = bucketOrOpts.bucket || ((_a = (0, config_1.firebaseConfig)()) === null || _a === void 0 ? void 0 : _a.storageBucket);
173 opts = { ...bucketOrOpts };
174 delete opts.bucket;
175 }
176 if (!bucket) {
177 throw new Error("Missing bucket name. If you are unit testing, please provide a bucket name" +
178 " by providing bucket name directly in the event handler or by setting process.env.FIREBASE_CONFIG.");
179 }
180 if (typeof bucket === "string" && !/^[a-z\d][a-z\d\\._-]{1,230}[a-z\d]$/.test(bucket)) {
181 throw new Error(`Invalid bucket name ${bucket}`);
182 }
183 return [opts, bucket];
184}
185exports.getOptsAndBucket = getOptsAndBucket;