Skip to content

Commit 28f6bc0

Browse files
committed
Format
1 parent 0c3a8b0 commit 28f6bc0

File tree

3 files changed

+102
-52
lines changed

3 files changed

+102
-52
lines changed

spec/v2/providers/https.spec.ts

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,13 @@ import { FULL_ENDPOINT, MINIMAL_V2_ENDPOINT, FULL_OPTIONS, FULL_TRIGGER } from "
3232
import { onInit } from "../../../src/v2/core";
3333
import { Handler } from "express";
3434

35-
function request(args: { data?: any, auth?: Record<string, string>, headers?: Record<string, string>, method?: MockRequest["method"] }): any {
36-
let headers: Record<string, string> = {}
35+
function request(args: {
36+
data?: any;
37+
auth?: Record<string, string>;
38+
headers?: Record<string, string>;
39+
method?: MockRequest["method"];
40+
}): any {
41+
let headers: Record<string, string> = {};
3742
if (args.method !== "POST") {
3843
headers["content-type"] = "application/json";
3944
}
@@ -191,7 +196,7 @@ describe("onRequest", () => {
191196
res.send("Works");
192197
});
193198

194-
const req = request({ headers: { origin: "example.com" }});
199+
const req = request({ headers: { origin: "example.com" } });
195200
const resp = await runHandler(func, req);
196201
expect(resp.body).to.equal("Works");
197202
});
@@ -208,9 +213,9 @@ describe("onRequest", () => {
208213
origin: "example.com",
209214
},
210215
method: "OPTIONS",
211-
})
216+
});
212217

213-
const resp = await runHandler(func, req as any);
218+
const resp = await runHandler(func, req);
214219
expect(resp.status).to.equal(204);
215220
expect(resp.body).to.be.undefined;
216221
expect(resp.headers).to.deep.equal({
@@ -237,7 +242,7 @@ describe("onRequest", () => {
237242
method: "OPTIONS",
238243
});
239244

240-
const resp = await runHandler(func, req as any);
245+
const resp = await runHandler(func, req);
241246
expect(resp.status).to.equal(204);
242247
expect(resp.body).to.be.undefined;
243248
expect(resp.headers).to.deep.equal({
@@ -266,7 +271,7 @@ describe("onRequest", () => {
266271
method: "OPTIONS",
267272
});
268273

269-
const resp = await runHandler(func, req as any);
274+
const resp = await runHandler(func, req);
270275
expect(resp.status).to.equal(200);
271276
expect(resp.body).to.be.equal("Good");
272277
expect(resp.headers).to.deep.equal({});
@@ -289,7 +294,7 @@ describe("onRequest", () => {
289294
let hello;
290295
onInit(() => (hello = "world"));
291296
expect(hello).to.be.undefined;
292-
await runHandler(func, req as any);
297+
await runHandler(func, req);
293298
expect(hello).to.equal("world");
294299
});
295300
});
@@ -404,9 +409,9 @@ describe("onCall", () => {
404409
it("should be an express handler", async () => {
405410
const func = https.onCall(() => 42);
406411

407-
const req = request({ headers: { origin: "example.com" }});
412+
const req = request({ headers: { origin: "example.com" } });
408413

409-
const resp = await runHandler(func, req as any);
414+
const resp = await runHandler(func, req);
410415
expect(resp.body).to.deep.equal(JSON.stringify({ result: 42 }));
411416
});
412417

@@ -424,7 +429,7 @@ describe("onCall", () => {
424429
method: "OPTIONS",
425430
});
426431

427-
const resp = await runHandler(func, req as any);
432+
const resp = await runHandler(func, req);
428433
expect(resp.status).to.equal(204);
429434
expect(resp.body).to.be.undefined;
430435
expect(resp.headers).to.deep.equal({
@@ -450,7 +455,7 @@ describe("onCall", () => {
450455
method: "OPTIONS",
451456
});
452457

453-
const response = await runHandler(func, req as any);
458+
const response = await runHandler(func, req);
454459

455460
expect(response.status).to.equal(204);
456461
expect(response.body).to.be.undefined;
@@ -466,7 +471,7 @@ describe("onCall", () => {
466471

467472
it("adds CORS headers", async () => {
468473
const func = https.onCall(() => 42);
469-
const req = request({ headers: { origin: "example.com" }})
474+
const req = request({ headers: { origin: "example.com" } });
470475
const response = await runHandler(func, req);
471476

472477
expect(response.status).to.equal(200);
@@ -488,16 +493,15 @@ describe("onCall", () => {
488493
it("calls init function", async () => {
489494
const func = https.onCall(() => 42);
490495

491-
const req = request({ headers: { origin: "example.com" }});
496+
const req = request({ headers: { origin: "example.com" } });
492497
let hello;
493498
onInit(() => (hello = "world"));
494499
expect(hello).to.be.undefined;
495-
await runHandler(func, req as any);
500+
await runHandler(func, req);
496501
expect(hello).to.equal("world");
497502
});
498503

499504
describe("authPolicy", () => {
500-
501505
before(() => {
502506
sinon.stub(debug, "isDebugFeatureEnabled").withArgs("skipTokenVerification").returns(true);
503507
});
@@ -514,7 +518,7 @@ describe("onCall", () => {
514518
() => 42
515519
);
516520

517-
const authResp = await runHandler(func, request({ auth: { sub: "inlined" }}));
521+
const authResp = await runHandler(func, request({ auth: { sub: "inlined" } }));
518522
expect(authResp.status).to.equal(200);
519523

520524
const anonResp = await runHandler(func, request({}));
@@ -543,7 +547,7 @@ describe("onCall", () => {
543547
{ fn: specificValue, auth: { meaning: "42" }, status: 200 },
544548
{ fn: specificValue, auth: { meaning: "43" }, status: 403 },
545549
{ fn: specificValue, auth: { order: "66" }, status: 403 },
546-
{ fn: specificValue, status: 403 },
550+
{ fn: specificValue, status: 403 },
547551
];
548552
for (const test of cases) {
549553
const resp = await runHandler(test.fn, request({ auth: test.auth }));
@@ -579,14 +583,13 @@ describe("onCallGenkit", () => {
579583
flow.run.withArgs("answer").returns(42);
580584
flow.stream.onCall(0).throws("Unexpected stream");
581585

582-
const f = https.onCallGenkit(flow);
586+
const f = https.onCallGenkit(flow);
583587

584588
const req = request({ data: "answer" });
585589
const res = await runHandler(f, req);
586-
expect(JSON.parse(res.body)).to.deep.equal({"result":42});
590+
expect(JSON.parse(res.body)).to.deep.equal({ result: 42 });
587591
});
588592

589-
590593
it("Streams with SSE requests", async () => {
591594
const flow = {
592595
__action: {
@@ -597,8 +600,10 @@ describe("onCallGenkit", () => {
597600
};
598601
flow.run.onFirstCall().throws();
599602
flow.stream.withArgs("answer").returns({
600-
stream: (async function*() {
603+
stream: (async function* () {
604+
await Promise.resolve();
601605
yield 1;
606+
await Promise.resolve();
602607
yield 2;
603608
})(),
604609
output: Promise.resolve(42),
@@ -607,12 +612,13 @@ describe("onCallGenkit", () => {
607612

608613
const f = https.onCallGenkit(flow);
609614

610-
const req = request({ data: "answer", headers: { accept: "text/event-stream" }});
615+
const req = request({ data: "answer", headers: { accept: "text/event-stream" } });
611616
const res = await runHandler(f, req);
612-
expect(res.body).to.equal(['data: {"message":1}', 'data: {"message":2}', 'data: {"result":42}',''].join("\n"));
617+
expect(res.body).to.equal(
618+
['data: {"message":1}', 'data: {"message":2}', 'data: {"result":42}', ""].join("\n")
619+
);
613620
});
614621

615-
616622
// TODO: Once genkit 1.0.0-rc.4 is released, add a type checking test that succeeds by compiling correctly.
617623
// It should create a genkit resource and then call onCallGenkit with it. If the compiler fails, our typing
618624
// needs to be updated.

src/runtime/manifest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export interface ManifestEndpoint {
6969

7070
callableTrigger?: {
7171
genkitAction?: string;
72-
}
72+
};
7373

7474
eventTrigger?: {
7575
eventFilters: Record<string, string | Expression<string>>;

src/v2/providers/https.ts

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -506,22 +506,60 @@ interface GenkitRunOptions {
506506
context?: any;
507507
}
508508

509-
type GenkitAction<I extends ZodType = ZodType<any>, O extends ZodType = ZodType<any>, S extends ZodType = ZodType<any>> = {
510-
run(input: I["__output"], options: GenkitRunOptions): Promise<O["__output"]>;
511-
stream(input: I["__output"], options: GenkitRunOptions): { stream: AsyncIterable<S["__output"]>, output: O["__output"] };
509+
type GenkitAction<
510+
I extends ZodType = ZodType<any>,
511+
O extends ZodType = ZodType<any>,
512+
S extends ZodType = ZodType<any>
513+
> = {
514+
// NOTE: The return type from run includes trace data that we may one day like to use.
515+
run(input: I["__output"], options: GenkitRunOptions): Promise<{ result: O["__output"] }>;
516+
stream(
517+
input: I["__output"],
518+
options: GenkitRunOptions
519+
): { stream: AsyncIterable<S["__output"]>; output: O["__output"] };
512520

513521
__action: {
514522
name: string;
515523
};
516-
}
517-
518-
type ActionInput<F extends GenkitAction> = F extends GenkitAction<infer I extends ZodType<infer T>, any, any> ? T : never;
519-
type ActionOutput<F extends GenkitAction> = F extends GenkitAction<any, infer O extends ZodType<infer T>, any> ? T : never;
520-
type ActionStream<F extends GenkitAction> = F extends GenkitAction<any, any, infer S extends ZodType<infer T>> ? T : never;
524+
};
521525

522-
export function onCallGenkit<A extends GenkitAction>(action: A): CallableFunction<ActionInput<A>, Promise<ActionOutput<A>>, ActionStream<A>>;
523-
export function onCallGenkit<A extends GenkitAction>(opts: CallableOptions<ActionInput<A>>, flow: A): CallableFunction<ActionInput<A>, Promise<ActionOutput<A>>, ActionStream<A>>;
524-
export function onCallGenkit<A extends GenkitAction>(optsOrAction: A | CallableOptions<ActionInput<A>>, action?: A): CallableFunction<ActionInput<A>, Promise<ActionOutput<A>>, ActionStream<A>> {
526+
// Note: A double infer is required to extract the ZodType's native type from the GenkitAction, but triggers an
527+
// unused variable linter error for the ZodType wrapper.
528+
/* eslint-disable @typescript-eslint/no-unused-vars */
529+
type ActionInput<F extends GenkitAction> = F extends GenkitAction<
530+
infer I extends ZodType<infer T>,
531+
any,
532+
any
533+
>
534+
? T
535+
: never;
536+
type ActionOutput<F extends GenkitAction> = F extends GenkitAction<
537+
any,
538+
infer O extends ZodType<infer T>,
539+
any
540+
>
541+
? T
542+
: never;
543+
type ActionStream<F extends GenkitAction> = F extends GenkitAction<
544+
any,
545+
any,
546+
infer S extends ZodType<infer T>
547+
>
548+
? T
549+
: never;
550+
/* eslint-enable @typescript-eslint/no-unused-vars */
551+
552+
export function onCallGenkit<A extends GenkitAction>(
553+
action: A
554+
): CallableFunction<ActionInput<A>, Promise<ActionOutput<A>>, ActionStream<A>>;
555+
export function onCallGenkit<A extends GenkitAction>(
556+
opts: CallableOptions<ActionInput<A>>,
557+
flow: A
558+
): CallableFunction<ActionInput<A>, Promise<ActionOutput<A>>, ActionStream<A>>;
559+
export function onCallGenkit<A extends GenkitAction>(
560+
optsOrAction: A | CallableOptions<ActionInput<A>>,
561+
action?: A
562+
): CallableFunction<ActionInput<A>, Promise<ActionOutput<A>>, ActionStream<A>> {
525563
let opts: CallableOptions<ActionInput<A>>;
526564
if (arguments.length === 2) {
527565
opts = optsOrAction as CallableOptions<ActionInput<A>>;
@@ -530,23 +568,29 @@ export function onCallGenkit<A extends GenkitAction>(optsOrAction: A | CallableO
530568
action = optsOrAction as A;
531569
}
532570
if (opts.secrets?.length === 0) {
533-
logger.debug(`Genkit function for ${action.__action.name} is not bound to any secret. This may mean that you are not storing API keys as a secret or that you are not binding your secret to this function. See https://firebase.google.com/docs/functions/config-env?gen=2nd#secret_parameters for more information.`);
571+
logger.debug(
572+
`Genkit function for ${action.__action.name} is not bound to any secret. This may mean that you are not storing API keys as a secret or that you are not binding your secret to this function. See https://firebase.google.com/docs/functions/config-env?gen=2nd#secret_parameters for more information.`
573+
);
534574
}
535-
const cloudFunction = onCall<ActionInput<A>, Promise<ActionOutput<A>>, ActionStream<A>>(opts, async (req, res) => {
536-
let context: Omit<CallableRequest, "data" | "rawRequest" | "acceptsStreaming"> = {};
537-
copyIfPresent(context, req, "auth", "app", "instanceIdToken");
538-
539-
if (!req.acceptsStreaming) {
540-
return action.run(req.data, { context });
575+
const cloudFunction = onCall<ActionInput<A>, Promise<ActionOutput<A>>, ActionStream<A>>(
576+
opts,
577+
async (req, res) => {
578+
const context: Omit<CallableRequest, "data" | "rawRequest" | "acceptsStreaming"> = {};
579+
copyIfPresent(context, req, "auth", "app", "instanceIdToken");
580+
581+
if (!req.acceptsStreaming) {
582+
const { result } = await action.run(req.data, { context });
583+
return result;
584+
}
585+
586+
const { stream, output } = action.stream(req.data, { context });
587+
for await (const chunk of stream) {
588+
await res.sendChunk(chunk);
589+
}
590+
return output;
541591
}
542-
543-
const { stream, output } = action.stream(req.data, { context });
544-
for await (const chunk of stream) {
545-
await res.sendChunk(chunk);
546-
}
547-
return output;
548-
});
592+
);
549593

550594
cloudFunction.__endpoint.callableTrigger.genkitAction = action.__action.name;
551-
return cloudFunction;
595+
return cloudFunction;
552596
}

0 commit comments

Comments
 (0)