Skip to content

Commit 3902b80

Browse files
Ugly type safety (#1548)
* Ugly typesafety * Formatter * consolidate make firestore event fns and simplify typings --------- Co-authored-by: Brian Li <[email protected]>
1 parent 8c83dd8 commit 3902b80

File tree

2 files changed

+135
-52
lines changed

2 files changed

+135
-52
lines changed

spec/v2/providers/firestore.spec.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ const eventBase = {
4040
datacontenttype: "application/protobuf",
4141
dataschema:
4242
"https://github.com/googleapis/google-cloudevents/blob/main/proto/google/events/cloud/firestore/v1/data.proto",
43-
authtype: "unknown",
44-
authid: "1234",
4543
id: "379ad868-5ef9-4c84-a8ba-f75f1b056663",
4644
source: "projects/my-project/databases/my-db/documents/d",
4745
subject: "documents/foo/fGRodw71mHutZ4wGDuT8",
@@ -86,6 +84,15 @@ function makeEvent(data?: any): firestore.RawFirestoreEvent {
8684
} as firestore.RawFirestoreEvent;
8785
}
8886

87+
function makeAuthEvent(data?: any): firestore.RawFirestoreAuthEvent {
88+
return {
89+
...eventBase,
90+
data,
91+
authid: "userId",
92+
authtype: "unknown",
93+
} as firestore.RawFirestoreAuthEvent;
94+
}
95+
8996
const createdData = {
9097
value: {
9198
fields: {
@@ -910,6 +917,26 @@ describe("firestore", () => {
910917

911918
expect(event.data.data()).to.deep.eq({ hello: "delete world" });
912919
});
920+
921+
it("should make event from a created event with auth context", () => {
922+
const event = firestore.makeFirestoreEvent(
923+
firestore.createdEventWithAuthContextType,
924+
makeAuthEvent(makeEncodedProtobuf(createdProto)),
925+
firestore.makeParams("foo/fGRodw71mHutZ4wGDuT8", new PathPattern("foo/{bar}"))
926+
);
927+
928+
expect(event.data.data()).to.deep.eq({ hello: "create world" });
929+
});
930+
931+
it("should include auth fields if provided in raw event", () => {
932+
const event = firestore.makeFirestoreEvent(
933+
firestore.createdEventWithAuthContextType,
934+
makeAuthEvent(makeEncodedProtobuf(createdProto)),
935+
firestore.makeParams("foo/fGRodw71mHutZ4wGDuT8", new PathPattern("foo/{bar}"))
936+
);
937+
938+
expect(event).to.include({ authId: "userId", authType: "unknown" });
939+
});
913940
});
914941

915942
describe("makeChangedFirestoreEvent", () => {
@@ -943,6 +970,15 @@ describe("firestore", () => {
943970
});
944971
});
945972

973+
it("should include auth fields if provided in raw event", () => {
974+
const event = firestore.makeChangedFirestoreEvent(
975+
makeAuthEvent(makeEncodedProtobuf(writtenProto)),
976+
firestore.makeParams("foo/fGRodw71mHutZ4wGDuT8", new PathPattern("foo/{bar}"))
977+
);
978+
979+
expect(event).to.include({ authId: "userId", authType: "unknown" });
980+
});
981+
946982
describe("makeEndpoint", () => {
947983
it("should make an endpoint with a document path pattern", () => {
948984
const expectedEp = makeExpectedEp(

src/v2/providers/firestore.ts

Lines changed: 97 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ export interface RawFirestoreEvent extends CloudEvent<Uint8Array | RawFirestoreD
9393
document: string;
9494
datacontenttype?: string;
9595
dataschema: string;
96-
authtype?: string;
96+
}
97+
98+
/** @internal */
99+
export interface RawFirestoreAuthEvent extends RawFirestoreEvent {
100+
authtype?: AuthType;
97101
authid?: string;
98102
}
99103

@@ -125,17 +129,21 @@ export interface FirestoreEvent<T, Params = Record<string, string>> extends Clou
125129
namespace: string;
126130
/** The document path */
127131
document: string;
128-
/** The type of principal that triggered the event */
129-
authType?: AuthType;
130-
/** The unique identifier for the principal */
131-
authId?: string;
132132
/**
133133
* An object containing the values of the path patterns.
134134
* Only named capture groups will be populated - {key}, {key=*}, {key=**}
135135
*/
136136
params: Params;
137137
}
138138

139+
export interface FirestoreAuthEvent<T, Params = Record<string, string>>
140+
extends FirestoreEvent<T, Params> {
141+
/** The type of principal that triggered the event */
142+
authType: AuthType;
143+
/** The unique identifier for the principal */
144+
authId?: string;
145+
}
146+
139147
/** DocumentOptions extend EventHandlerOptions with provided document and optional database and namespace. */
140148
export interface DocumentOptions<Document extends string = string> extends EventHandlerOptions {
141149
/** The document path */
@@ -197,9 +205,9 @@ export function onDocumentWritten<Document extends string>(
197205
export function onDocumentWrittenWithAuthContext<Document extends string>(
198206
document: Document,
199207
handler: (
200-
event: FirestoreEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>
208+
event: FirestoreAuthEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>
201209
) => any | Promise<any>
202-
): CloudFunction<FirestoreEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>>;
210+
): CloudFunction<FirestoreAuthEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>>;
203211

204212
/**
205213
* Event handler that triggers when a document is created, updated, or deleted in Firestore.
@@ -211,9 +219,9 @@ export function onDocumentWrittenWithAuthContext<Document extends string>(
211219
export function onDocumentWrittenWithAuthContext<Document extends string>(
212220
opts: DocumentOptions<Document>,
213221
handler: (
214-
event: FirestoreEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>
222+
event: FirestoreAuthEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>
215223
) => any | Promise<any>
216-
): CloudFunction<FirestoreEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>>;
224+
): CloudFunction<FirestoreAuthEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>>;
217225

218226
/**
219227
* Event handler that triggers when a document is created, updated, or deleted in Firestore.
@@ -223,12 +231,19 @@ export function onDocumentWrittenWithAuthContext<Document extends string>(
223231
* @param handler - Event handler which is run every time a Firestore create, update, or delete occurs.
224232
*/
225233
export function onDocumentWrittenWithAuthContext<Document extends string>(
226-
documentorOpts: Document | DocumentOptions<Document>,
234+
documentOrOpts: Document | DocumentOptions<Document>,
227235
handler: (
228-
event: FirestoreEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>
236+
event: FirestoreAuthEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>
229237
) => any | Promise<any>
230-
): CloudFunction<FirestoreEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>> {
231-
return onChangedOperation(writtenEventWithAuthContextType, documentorOpts, handler);
238+
): CloudFunction<FirestoreAuthEvent<Change<DocumentSnapshot> | undefined, ParamsOf<Document>>> {
239+
// const fn = (
240+
// event: FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>> & {
241+
// foo: string;
242+
// }
243+
// ): any => {
244+
// return event;
245+
// };
246+
return onChangedOperation(writtenEventWithAuthContextType, documentOrOpts, handler);
232247
}
233248

234249
/**
@@ -282,9 +297,9 @@ export function onDocumentCreated<Document extends string>(
282297
export function onDocumentCreatedWithAuthContext<Document extends string>(
283298
document: Document,
284299
handler: (
285-
event: FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
300+
event: FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
286301
) => any | Promise<any>
287-
): CloudFunction<FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>>;
302+
): CloudFunction<FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>>;
288303

289304
/**
290305
* Event handler that triggers when a document is created in Firestore.
@@ -296,9 +311,9 @@ export function onDocumentCreatedWithAuthContext<Document extends string>(
296311
export function onDocumentCreatedWithAuthContext<Document extends string>(
297312
opts: DocumentOptions<Document>,
298313
handler: (
299-
event: FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
314+
event: FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
300315
) => any | Promise<any>
301-
): CloudFunction<FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>>;
316+
): CloudFunction<FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>>;
302317

303318
/**
304319
* Event handler that triggers when a document is created in Firestore.
@@ -309,9 +324,9 @@ export function onDocumentCreatedWithAuthContext<Document extends string>(
309324
export function onDocumentCreatedWithAuthContext<Document extends string>(
310325
documentOrOpts: Document | DocumentOptions<Document>,
311326
handler: (
312-
event: FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
327+
event: FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
313328
) => any | Promise<any>
314-
): CloudFunction<FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>> {
329+
): CloudFunction<FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>> {
315330
return onOperation(createdEventWithAuthContextType, documentOrOpts, handler);
316331
}
317332

@@ -365,9 +380,10 @@ export function onDocumentUpdated<Document extends string>(
365380
export function onDocumentUpdatedWithAuthContext<Document extends string>(
366381
document: Document,
367382
handler: (
368-
event: FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>
383+
event: FirestoreAuthEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>
369384
) => any | Promise<any>
370-
): CloudFunction<FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>>;
385+
): CloudFunction<FirestoreAuthEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>>;
386+
371387
/**
372388
* Event handler that triggers when a document is updated in Firestore.
373389
* This trigger also provides the authentication context of the principal who triggered the event.
@@ -378,9 +394,9 @@ export function onDocumentUpdatedWithAuthContext<Document extends string>(
378394
export function onDocumentUpdatedWithAuthContext<Document extends string>(
379395
opts: DocumentOptions<Document>,
380396
handler: (
381-
event: FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>
397+
event: FirestoreAuthEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>
382398
) => any | Promise<any>
383-
): CloudFunction<FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>>;
399+
): CloudFunction<FirestoreAuthEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>>;
384400

385401
/**
386402
* Event handler that triggers when a document is updated in Firestore.
@@ -391,9 +407,11 @@ export function onDocumentUpdatedWithAuthContext<Document extends string>(
391407
export function onDocumentUpdatedWithAuthContext<Document extends string>(
392408
documentOrOpts: Document | DocumentOptions<Document>,
393409
handler: (
394-
event: FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>
410+
event: FirestoreAuthEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>
395411
) => any | Promise<any>
396-
): CloudFunction<FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>> {
412+
): CloudFunction<
413+
FirestoreAuthEvent<Change<QueryDocumentSnapshot> | undefined, ParamsOf<Document>>
414+
> {
397415
return onChangedOperation(updatedEventWithAuthContextType, documentOrOpts, handler);
398416
}
399417

@@ -448,9 +466,9 @@ export function onDocumentDeleted<Document extends string>(
448466
export function onDocumentDeletedWithAuthContext<Document extends string>(
449467
document: Document,
450468
handler: (
451-
event: FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
469+
event: FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
452470
) => any | Promise<any>
453-
): CloudFunction<FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>>;
471+
): CloudFunction<FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>>;
454472

455473
/**
456474
* Event handler that triggers when a document is deleted in Firestore.
@@ -462,9 +480,9 @@ export function onDocumentDeletedWithAuthContext<Document extends string>(
462480
export function onDocumentDeletedWithAuthContext<Document extends string>(
463481
opts: DocumentOptions<Document>,
464482
handler: (
465-
event: FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
483+
event: FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
466484
) => any | Promise<any>
467-
): CloudFunction<FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>>;
485+
): CloudFunction<FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>>;
468486

469487
/**
470488
* Event handler that triggers when a document is deleted in Firestore.
@@ -475,9 +493,9 @@ export function onDocumentDeletedWithAuthContext<Document extends string>(
475493
export function onDocumentDeletedWithAuthContext<Document extends string>(
476494
documentOrOpts: Document | DocumentOptions<Document>,
477495
handler: (
478-
event: FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
496+
event: FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>
479497
) => any | Promise<any>
480-
): CloudFunction<FirestoreEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>> {
498+
): CloudFunction<FirestoreAuthEvent<QueryDocumentSnapshot | undefined, ParamsOf<Document>>> {
481499
return onOperation(deletedEventWithAuthContextType, documentOrOpts, handler);
482500
}
483501

@@ -566,43 +584,68 @@ export function makeParams(document: string, documentPattern: PathPattern) {
566584
/** @internal */
567585
export function makeFirestoreEvent<Params>(
568586
eventType: string,
569-
event: RawFirestoreEvent,
587+
event: RawFirestoreEvent | RawFirestoreAuthEvent,
570588
params: Params
571-
): FirestoreEvent<QueryDocumentSnapshot | undefined, Params> {
589+
):
590+
| FirestoreEvent<QueryDocumentSnapshot | undefined, Params>
591+
| FirestoreAuthEvent<QueryDocumentSnapshot | undefined, Params> {
572592
const data = event.data
573-
? eventType === createdEventType
593+
? eventType === createdEventType || eventType === createdEventWithAuthContextType
574594
? createSnapshot(event)
575595
: createBeforeSnapshot(event)
576596
: undefined;
577597
const firestoreEvent: FirestoreEvent<QueryDocumentSnapshot | undefined, Params> = {
578598
...event,
579599
params,
580600
data,
581-
authType: event.authtype as AuthType,
582-
authId: event.authid,
583601
};
602+
584603
delete (firestoreEvent as any).datacontenttype;
585604
delete (firestoreEvent as any).dataschema;
605+
606+
if ("authtype" in event) {
607+
const eventWithAuth = {
608+
...firestoreEvent,
609+
authType: event.authtype,
610+
authId: event.authid,
611+
};
612+
delete (eventWithAuth as any).authtype;
613+
delete (eventWithAuth as any).authid;
614+
return eventWithAuth;
615+
}
616+
586617
return firestoreEvent;
587618
}
588619

589620
/** @internal */
590621
export function makeChangedFirestoreEvent<Params>(
591-
event: RawFirestoreEvent,
622+
event: RawFirestoreEvent | RawFirestoreAuthEvent,
592623
params: Params
593-
): FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, Params> {
624+
):
625+
| FirestoreEvent<Change<DocumentSnapshot> | undefined, Params>
626+
| FirestoreAuthEvent<Change<DocumentSnapshot> | undefined, Params> {
594627
const data = event.data
595628
? Change.fromObjects(createBeforeSnapshot(event), createSnapshot(event))
596629
: undefined;
597630
const firestoreEvent: FirestoreEvent<Change<QueryDocumentSnapshot> | undefined, Params> = {
598631
...event,
599632
params,
600633
data,
601-
authType: event.authtype as AuthType,
602-
authId: event.authid,
603634
};
604635
delete (firestoreEvent as any).datacontenttype;
605636
delete (firestoreEvent as any).dataschema;
637+
638+
if ("authtype" in event) {
639+
const eventWithAuth = {
640+
...firestoreEvent,
641+
authType: event.authtype,
642+
authId: event.authid,
643+
};
644+
delete (eventWithAuth as any).authtype;
645+
delete (eventWithAuth as any).authid;
646+
return eventWithAuth;
647+
}
648+
606649
return firestoreEvent;
607650
}
608651

@@ -649,16 +692,19 @@ export function makeEndpoint(
649692
}
650693

651694
/** @internal */
652-
export function onOperation<Document extends string>(
695+
export function onOperation<
696+
Document extends string,
697+
Event extends FirestoreEvent<QueryDocumentSnapshot, ParamsOf<Document>>
698+
>(
653699
eventType: string,
654700
documentOrOpts: Document | DocumentOptions<Document>,
655-
handler: (event: FirestoreEvent<QueryDocumentSnapshot, ParamsOf<Document>>) => any | Promise<any>
656-
): CloudFunction<FirestoreEvent<QueryDocumentSnapshot, ParamsOf<Document>>> {
701+
handler: (event: Event) => any | Promise<any>
702+
): CloudFunction<Event> {
657703
const { document, database, namespace, opts } = getOpts(documentOrOpts);
658704

659705
// wrap the handler
660706
const func = (raw: CloudEvent<unknown>) => {
661-
const event = raw as RawFirestoreEvent;
707+
const event = raw as RawFirestoreEvent | RawFirestoreAuthEvent;
662708
const documentPattern = new PathPattern(
663709
typeof document === "string" ? document : document.value()
664710
);
@@ -675,18 +721,19 @@ export function onOperation<Document extends string>(
675721
}
676722

677723
/** @internal */
678-
export function onChangedOperation<Document extends string>(
724+
export function onChangedOperation<
725+
Document extends string,
726+
Event extends FirestoreEvent<Change<DocumentSnapshot>, ParamsOf<Document>>
727+
>(
679728
eventType: string,
680729
documentOrOpts: Document | DocumentOptions<Document>,
681-
handler: (
682-
event: FirestoreEvent<Change<QueryDocumentSnapshot>, ParamsOf<Document>>
683-
) => any | Promise<any>
684-
): CloudFunction<FirestoreEvent<Change<QueryDocumentSnapshot>, ParamsOf<Document>>> {
730+
handler: (event: Event) => any | Promise<any>
731+
): CloudFunction<Event> {
685732
const { document, database, namespace, opts } = getOpts(documentOrOpts);
686733

687734
// wrap the handler
688735
const func = (raw: CloudEvent<unknown>) => {
689-
const event = raw as RawFirestoreEvent;
736+
const event = raw as RawFirestoreEvent | RawFirestoreAuthEvent;
690737
const documentPattern = new PathPattern(
691738
typeof document === "string" ? document : document.value()
692739
);

0 commit comments

Comments
 (0)