Skip to content

Commit 29fc722

Browse files
authoredFeb 7, 2024··
Make storage bucket parameterizeable. Create const for bucket picker (#1518)
* Make storage bucket parameterizeable. Create const for bucket picker * Fix linter error * Use more specific type * Remove unused import * Export types that were part of an old spec but are not available on main package * In for a penny, in for a pound * Clarify types of select/multiSelect * Changelog
1 parent 9bda8f7 commit 29fc722

File tree

4 files changed

+121
-34
lines changed

4 files changed

+121
-34
lines changed
 

‎CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
- Fixes access on deeply nested, nonexistent property. (#1432)
22
- Add IteratedDataSnapshot interface to match with firebase admin v12 (#1517).
3+
- Make bucket parameterizeable in storage functions (#1518)
4+
- Introduce helper library for select and multi-select input (#1518)

‎src/params/index.ts

+10
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ import {
3838
InternalExpression,
3939
} from "./types";
4040

41+
export {
42+
BUCKET_PICKER,
43+
TextInput,
44+
SelectInput,
45+
SelectOptions,
46+
MultiSelectInput,
47+
select,
48+
multiSelect,
49+
} from "./types";
50+
4151
export { ParamOptions, Expression };
4252

4353
type SecretOrExpr = Param<any> | SecretParam;

‎src/params/types.ts

+73-19
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,53 @@ export class CompareExpression<
171171
/** @hidden */
172172
type ParamValueType = "string" | "list" | "boolean" | "int" | "float" | "secret";
173173

174+
/** Create a select input from a series of values. */
175+
export function select<T>(options: T[]): SelectInput<T>;
176+
177+
/** Create a select input from a map of labels to vaues. */
178+
export function select<T>(optionsWithLabels: Record<string, T>): SelectInput<T>;
179+
180+
/** Create a select input from a series of values or a map of labels to values */
181+
export function select<T>(options: T[] | Record<string, T>): SelectInput<T> {
182+
let wireOpts: SelectOptions<T>[];
183+
if (Array.isArray(options)) {
184+
wireOpts = options.map((opt) => ({ value: opt }));
185+
} else {
186+
wireOpts = Object.entries(options).map(([label, value]) => ({ label, value }));
187+
}
188+
return {
189+
select: {
190+
options: wireOpts,
191+
},
192+
};
193+
}
194+
195+
/** Create a multi-select input from a series of values. */
196+
export function multiSelect(options: string[]): MultiSelectInput;
197+
198+
/** Create a multi-select input from map of labels to values. */
199+
export function multiSelect(options: Record<string, string>): MultiSelectInput;
200+
201+
/** Create a multi-select input from a series of values or map of labels to values. */
202+
export function multiSelect(options: string[] | Record<string, string>): MultiSelectInput {
203+
let wireOpts: SelectOptions<string>[];
204+
if (Array.isArray(options)) {
205+
wireOpts = options.map((opt) => ({ value: opt }));
206+
} else {
207+
wireOpts = Object.entries(options).map(([label, value]) => ({ label, value }));
208+
}
209+
return {
210+
multiSelect: {
211+
options: wireOpts,
212+
},
213+
};
214+
}
215+
174216
type ParamInput<T> =
175-
| { text: TextInput<T> }
176-
| { select: SelectInput<T> }
177-
| { multiSelect: MultiSelectInput }
178-
| { resource: ResourceInput };
217+
| TextInput<T>
218+
| SelectInput<T>
219+
| (T extends string[] ? MultiSelectInput : never)
220+
| (T extends string ? ResourceInput : never);
179221

180222
/**
181223
* Specifies that a Param's value should be determined by prompting the user
@@ -184,18 +226,20 @@ type ParamInput<T> =
184226
*/
185227
// eslint-disable-next-line @typescript-eslint/no-unused-vars
186228
export interface TextInput<T = unknown> {
187-
example?: string;
188-
/**
189-
* A regular expression (or an escaped string to compile into a regular
190-
* expression) which the prompted text must satisfy; the prompt will retry
191-
* until input matching the regex is provided.
192-
*/
193-
validationRegex?: string | RegExp;
194-
/**
195-
* A custom error message to display when retrying the prompt based on input
196-
* failing to conform to the validationRegex,
197-
*/
198-
validationErrorMessage?: string;
229+
text: {
230+
example?: string;
231+
/**
232+
* A regular expression (or an escaped string to compile into a regular
233+
* expression) which the prompted text must satisfy; the prompt will retry
234+
* until input matching the regex is provided.
235+
*/
236+
validationRegex?: string | RegExp;
237+
/**
238+
* A custom error message to display when retrying the prompt based on input
239+
* failing to conform to the validationRegex,
240+
*/
241+
validationErrorMessage?: string;
242+
};
199243
}
200244

201245
/**
@@ -205,16 +249,24 @@ export interface TextInput<T = unknown> {
205249
*/
206250
export interface ResourceInput {
207251
resource: {
208-
type: string;
252+
type: "storage.googleapis.com/Bucket";
209253
};
210254
}
211255

256+
export const BUCKET_PICKER: ResourceInput = {
257+
resource: {
258+
type: "storage.googleapis.com/Bucket",
259+
},
260+
};
261+
212262
/**
213263
* Specifies that a Param's value should be determined by having the user select
214264
* from a list of pre-canned options interactively at deploy-time.
215265
*/
216266
export interface SelectInput<T = unknown> {
217-
options: Array<SelectOptions<T>>;
267+
select: {
268+
options: Array<SelectOptions<T>>;
269+
};
218270
}
219271

220272
/**
@@ -223,7 +275,9 @@ export interface SelectInput<T = unknown> {
223275
* Will result in errors if used on Params of type other than string[].
224276
*/
225277
export interface MultiSelectInput {
226-
options: Array<SelectOptions<string>>;
278+
multiSelect: {
279+
options: Array<SelectOptions<string>>;
280+
};
227281
}
228282

229283
/**

‎src/v2/providers/storage.ts

+36-15
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ export const metadataUpdatedEvent = "google.cloud.storage.object.v1.metadataUpda
201201
/** StorageOptions extend EventHandlerOptions with a bucket name */
202202
export interface StorageOptions extends options.EventHandlerOptions {
203203
/** The name of the bucket containing this object. */
204-
bucket?: string;
204+
bucket?: string | Expression<string>;
205205

206206
/**
207207
* If true, do not deploy or emulate this function.
@@ -324,7 +324,7 @@ export function onObjectArchived(
324324
* @param handler - Event handler which is run every time a Google Cloud Storage archival occurs.
325325
*/
326326
export function onObjectArchived(
327-
bucket: string,
327+
bucket: string | Expression<string>,
328328
handler: (event: StorageEvent) => any | Promise<any>
329329
): CloudFunction<StorageEvent>;
330330

@@ -352,7 +352,11 @@ export function onObjectArchived(
352352
* @param handler - Event handler which is run every time a Google Cloud Storage archival occurs.
353353
*/
354354
export function onObjectArchived(
355-
bucketOrOptsOrHandler: string | StorageOptions | ((event: StorageEvent) => any | Promise<any>),
355+
bucketOrOptsOrHandler:
356+
| string
357+
| Expression<string>
358+
| StorageOptions
359+
| ((event: StorageEvent) => any | Promise<any>),
356360
handler?: (event: StorageEvent) => any | Promise<any>
357361
): CloudFunction<StorageEvent> {
358362
return onOperation(archivedEvent, bucketOrOptsOrHandler, handler);
@@ -384,7 +388,7 @@ export function onObjectFinalized(
384388
* @param handler - Event handler which is run every time a Google Cloud Storage object creation occurs.
385389
*/
386390
export function onObjectFinalized(
387-
bucket: string,
391+
bucket: string | Expression<string>,
388392
handler: (event: StorageEvent) => any | Promise<any>
389393
): CloudFunction<StorageEvent>;
390394

@@ -416,7 +420,11 @@ export function onObjectFinalized(
416420
* @param handler - Event handler which is run every time a Google Cloud Storage object creation occurs.
417421
*/
418422
export function onObjectFinalized(
419-
bucketOrOptsOrHandler: string | StorageOptions | ((event: StorageEvent) => any | Promise<any>),
423+
bucketOrOptsOrHandler:
424+
| string
425+
| Expression<string>
426+
| StorageOptions
427+
| ((event: StorageEvent) => any | Promise<any>),
420428
handler?: (event: StorageEvent) => any | Promise<any>
421429
): CloudFunction<StorageEvent> {
422430
return onOperation(finalizedEvent, bucketOrOptsOrHandler, handler);
@@ -450,7 +458,7 @@ export function onObjectDeleted(
450458
* @param handler - Event handler which is run every time a Google Cloud Storage object deletion occurs.
451459
*/
452460
export function onObjectDeleted(
453-
bucket: string,
461+
bucket: string | Expression<string>,
454462
handler: (event: StorageEvent) => any | Promise<any>
455463
): CloudFunction<StorageEvent>;
456464

@@ -484,7 +492,11 @@ export function onObjectDeleted(
484492
* @param handler - Event handler which is run every time a Google Cloud Storage object deletion occurs.
485493
*/
486494
export function onObjectDeleted(
487-
bucketOrOptsOrHandler: string | StorageOptions | ((event: StorageEvent) => any | Promise<any>),
495+
bucketOrOptsOrHandler:
496+
| string
497+
| Expression<string>
498+
| StorageOptions
499+
| ((event: StorageEvent) => any | Promise<any>),
488500
handler?: (event: StorageEvent) => any | Promise<any>
489501
): CloudFunction<StorageEvent> {
490502
return onOperation(deletedEvent, bucketOrOptsOrHandler, handler);
@@ -509,7 +521,7 @@ export function onObjectMetadataUpdated(
509521
* @param handler - Event handler which is run every time a Google Cloud Storage object metadata update occurs.
510522
*/
511523
export function onObjectMetadataUpdated(
512-
bucket: string,
524+
bucket: string | Expression<string>,
513525
handler: (event: StorageEvent) => any | Promise<any>
514526
): CloudFunction<StorageEvent>;
515527

@@ -533,7 +545,11 @@ export function onObjectMetadataUpdated(
533545
* @param handler - Event handler which is run every time a Google Cloud Storage object metadata update occurs.
534546
*/
535547
export function onObjectMetadataUpdated(
536-
bucketOrOptsOrHandler: string | StorageOptions | ((event: StorageEvent) => any | Promise<any>),
548+
bucketOrOptsOrHandler:
549+
| string
550+
| Expression<string>
551+
| StorageOptions
552+
| ((event: StorageEvent) => any | Promise<any>),
537553
handler?: (event: StorageEvent) => any | Promise<any>
538554
): CloudFunction<StorageEvent> {
539555
return onOperation(metadataUpdatedEvent, bucketOrOptsOrHandler, handler);
@@ -542,7 +558,11 @@ export function onObjectMetadataUpdated(
542558
/** @internal */
543559
export function onOperation(
544560
eventType: string,
545-
bucketOrOptsOrHandler: string | StorageOptions | ((event: StorageEvent) => any | Promise<any>),
561+
bucketOrOptsOrHandler:
562+
| string
563+
| Expression<string>
564+
| StorageOptions
565+
| ((event: StorageEvent) => any | Promise<any>),
546566
handler: (event: StorageEvent) => any | Promise<any>
547567
): CloudFunction<StorageEvent> {
548568
if (typeof bucketOrOptsOrHandler === "function") {
@@ -616,11 +636,12 @@ export function onOperation(
616636

617637
/** @internal */
618638
export function getOptsAndBucket(
619-
bucketOrOpts: string | StorageOptions
620-
): [options.EventHandlerOptions, string] {
621-
let bucket: string;
639+
bucketOrOpts: string | Expression<string> | StorageOptions
640+
): [options.EventHandlerOptions, string | Expression<string>] {
641+
let bucket: string | Expression<string>;
622642
let opts: options.EventHandlerOptions;
623-
if (typeof bucketOrOpts === "string") {
643+
// If bucket is a string or Expression<string>
644+
if (typeof bucketOrOpts === "string" || "value" in bucketOrOpts) {
624645
bucket = bucketOrOpts;
625646
opts = {};
626647
} else {
@@ -635,7 +656,7 @@ export function getOptsAndBucket(
635656
" by providing bucket name directly in the event handler or by setting process.env.FIREBASE_CONFIG."
636657
);
637658
}
638-
if (!/^[a-z\d][a-z\d\\._-]{1,230}[a-z\d]$/.test(bucket)) {
659+
if (typeof bucket === "string" && !/^[a-z\d][a-z\d\\._-]{1,230}[a-z\d]$/.test(bucket)) {
639660
throw new Error(`Invalid bucket name ${bucket}`);
640661
}
641662

0 commit comments

Comments
 (0)
Please sign in to comment.