Skip to content

Commit df0fd5f

Browse files
committed
wip change schema version to tuple
1 parent 5b0f7a8 commit df0fd5f

File tree

11 files changed

+52
-45
lines changed

11 files changed

+52
-45
lines changed

src/handlers/platforms/aws-lambda/saleor-webhooks/saleor-sync-webhook.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ describe("AWS Lambda SaleorSyncWebhook", () => {
7474
baseUrl: "example.com",
7575
event: "CHECKOUT_CALCULATE_TAXES",
7676
payload: { data: "test_payload" },
77-
schemaVersion: 3.19,
77+
schemaVersion: [3, 19],
7878
authData: {
7979
token: webhookConfig.apl.mockToken,
8080
jwks: webhookConfig.apl.mockJwks,

src/handlers/platforms/fetch-api/saleor-webhooks/saleor-async-webhook.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe("Web API SaleorAsyncWebhook", () => {
3333
baseUrl: "example.com",
3434
event: "product_updated",
3535
payload: { data: "test_payload" },
36-
schemaVersion: 3.2,
36+
schemaVersion: [3, 20],
3737
authData: {
3838
saleorApiUrl: mockAPL.workingSaleorApiUrl,
3939
token: mockAPL.mockToken,
@@ -62,7 +62,7 @@ describe("Web API SaleorAsyncWebhook", () => {
6262
authData: expect.objectContaining({
6363
saleorApiUrl: mockAPL.workingSaleorApiUrl,
6464
}),
65-
})
65+
}),
6666
);
6767
});
6868

src/handlers/platforms/fetch-api/saleor-webhooks/saleor-sync-webhook.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe("Web API SaleorSyncWebhook", () => {
3131
baseUrl: "example.com",
3232
event: "checkout_calculate_taxes",
3333
payload: { data: "test_payload" },
34-
schemaVersion: 3.19,
34+
schemaVersion: [3, 19],
3535
authData: {
3636
token: webhookConfiguration.apl.mockToken,
3737
jwks: webhookConfiguration.apl.mockJwks,

src/handlers/platforms/fetch-api/saleor-webhooks/saleor-webhook.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ export type WebhookConfig<Event = AsyncWebhookEventType | SyncWebhookEventType>
1414
GenericWebhookConfig<WebApiHandlerInput, Event>;
1515

1616
/** Function type provided by consumer in `SaleorWebApiWebhook.createHandler` */
17-
export type WebApiWebhookHandler<TPayload = unknown, TExtras = {}> = (
17+
export type WebApiWebhookHandler<TPayload = unknown> = (
1818
req: Request,
19-
ctx: WebhookContext<TPayload> & TExtras
19+
ctx: WebhookContext<TPayload>,
2020
) => Response | Promise<Response>;
2121

22-
export abstract class SaleorWebApiWebhook<
23-
TPayload = unknown,
24-
TExtras extends Record<string, unknown> = {}
25-
> extends GenericSaleorWebhook<WebApiHandlerInput, TPayload, TExtras> {
26-
createHandler(handlerFn: WebApiWebhookHandler<TPayload, TExtras>): WebApiHandler {
22+
export abstract class SaleorWebApiWebhook<TPayload = unknown> extends GenericSaleorWebhook<
23+
WebApiHandlerInput,
24+
TPayload
25+
> {
26+
createHandler(handlerFn: WebApiWebhookHandler<TPayload>): WebApiHandler {
2727
return async (req) => {
2828
const adapter = new WebApiAdapter(req);
2929
const prepareRequestResult = await super.prepareRequest<WebApiAdapter>(adapter);
@@ -34,7 +34,6 @@ export abstract class SaleorWebApiWebhook<
3434

3535
debug("Incoming request validated. Call handlerFn");
3636
return handlerFn(req, {
37-
...(this.extraContext ?? ({} as TExtras)),
3837
...prepareRequestResult.context,
3938
});
4039
};

src/handlers/platforms/next/saleor-webhooks/saleor-async-webhook.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe("Next.js SaleorAsyncWebhook", () => {
3333
expect(saleorAsyncWebhook.getWebhookManifest(baseUrl)).toEqual(
3434
expect.objectContaining({
3535
targetUrl: `${baseUrl}/${webhookPath}`,
36-
})
36+
}),
3737
);
3838
});
3939

@@ -56,7 +56,7 @@ describe("Next.js SaleorAsyncWebhook", () => {
5656
baseUrl: "example.com",
5757
event: "product_updated",
5858
payload: { data: "test_payload" },
59-
schemaVersion: 3.2,
59+
schemaVersion: [3, 20],
6060
authData: {
6161
saleorApiUrl: mockAPL.workingSaleorApiUrl,
6262
token: mockAPL.mockToken,

src/handlers/platforms/next/saleor-webhooks/saleor-sync-webhook.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ describe("Next.js SaleorSyncWebhook", () => {
5555
baseUrl: "example.com",
5656
event: "checkout_calculate_taxes",
5757
payload: { data: "test_payload" },
58-
schemaVersion: 3.19,
58+
schemaVersion: [3, 19],
5959
authData: {
6060
token: validSyncWebhookConfiguration.apl.mockToken,
6161
jwks: validSyncWebhookConfiguration.apl.mockJwks,

src/handlers/shared/saleor-webhook-validator.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,7 @@ describe("SaleorWebhookValidator", () => {
237237
});
238238
});
239239

240-
// TODO: This should be required
241-
it("Fallbacks to null if version is missing in payload", async () => {
240+
it("Throws if version header is missing", async () => {
242241
vi.spyOn(adapter, "getRawBody").mockResolvedValue(JSON.stringify({}));
243242
vi.spyOn(requestProcessor, "getSaleorHeaders").mockReturnValue(validHeaders);
244243

src/handlers/shared/saleor-webhook-validator.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { APL } from "@/APL";
44
import { createDebug } from "@/debug";
55
import { fetchRemoteJwks } from "@/fetch-remote-jwks";
66
import { getOtelTracer } from "@/open-telemetry";
7+
import { SaleorSchemaVersion } from "@/types";
78
import { parseSchemaVersion } from "@/util";
89
import { verifySignatureWithJwks } from "@/verify-signature";
910

@@ -69,7 +70,8 @@ export class SaleorWebhookValidator {
6970
throw new WebhookError("Wrong request method, only POST allowed", "WRONG_METHOD");
7071
}
7172

72-
const { event, signature, saleorApiUrl } = requestProcessor.getSaleorHeaders();
73+
const { event, signature, saleorApiUrl, schemaVersion } =
74+
requestProcessor.getSaleorHeaders();
7375
const baseUrl = adapter.getBaseUrl();
7476

7577
if (!baseUrl) {
@@ -94,7 +96,7 @@ export class SaleorWebhookValidator {
9496

9597
throw new WebhookError(
9698
`Wrong incoming request event: ${event}. Expected: ${expected}`,
97-
"WRONG_EVENT"
99+
"WRONG_EVENT",
98100
);
99101
}
100102

@@ -111,7 +113,7 @@ export class SaleorWebhookValidator {
111113
throw new WebhookError("Missing request body", "MISSING_REQUEST_BODY");
112114
}
113115

114-
let parsedBody: unknown & { version?: string | null };
116+
let parsedBody: unknown;
115117

116118
try {
117119
parsedBody = JSON.parse(rawBody);
@@ -121,13 +123,7 @@ export class SaleorWebhookValidator {
121123
throw new WebhookError("Request body can't be parsed", "CANT_BE_PARSED");
122124
}
123125

124-
let parsedSchemaVersion: number | null = null;
125-
126-
try {
127-
parsedSchemaVersion = parseSchemaVersion(parsedBody.version);
128-
} catch {
129-
this.debug("Schema version cannot be parsed");
130-
}
126+
const parsedSchemaVersion = parseSchemaVersion(schemaVersion);
131127

132128
/**
133129
* Verify if the app is properly installed for given Saleor API URL
@@ -139,7 +135,7 @@ export class SaleorWebhookValidator {
139135

140136
throw new WebhookError(
141137
`Can't find auth data for ${saleorApiUrl}. Please register the application`,
142-
"NOT_REGISTERED"
138+
"NOT_REGISTERED",
143139
);
144140
}
145141

@@ -162,15 +158,15 @@ export class SaleorWebhookValidator {
162158

163159
throw new WebhookError(
164160
"Fetching remote JWKS failed",
165-
"SIGNATURE_VERIFICATION_FAILED"
161+
"SIGNATURE_VERIFICATION_FAILED",
166162
);
167163
});
168164

169165
this.debug("Fetched refreshed JWKS");
170166

171167
try {
172168
this.debug(
173-
"Second attempt to validate the signature JWKS, using fresh tokens from the API"
169+
"Second attempt to validate the signature JWKS, using fresh tokens from the API",
174170
);
175171

176172
await verifySignatureWithJwks(newJwks, signature, rawBody);
@@ -183,7 +179,7 @@ export class SaleorWebhookValidator {
183179

184180
throw new WebhookError(
185181
"Request signature check failed",
186-
"SIGNATURE_VERIFICATION_FAILED"
182+
"SIGNATURE_VERIFICATION_FAILED",
187183
);
188184
}
189185
}
@@ -211,7 +207,7 @@ export class SaleorWebhookValidator {
211207
} finally {
212208
span.end();
213209
}
214-
}
210+
},
215211
);
216212
}
217213
}

src/handlers/shared/saleor-webhook.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { SaleorSchemaVersion } from "@/types";
2+
13
import { AuthData } from "../../APL";
24

35
export const WebhookErrorCodeMap: Record<SaleorWebhookError, number> = {
@@ -50,9 +52,7 @@ export type WebhookContext<TPayload> = {
5052
event: string;
5153
payload: TPayload;
5254
authData: AuthData;
53-
// TODO: Make this required
54-
/** Added in Saleor 3.15 */
55-
schemaVersion: number | null;
55+
schemaVersion: SaleorSchemaVersion;
5656
};
5757

5858
export type FormatWebhookErrorResult = {

src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,3 +320,8 @@ export interface AppManifest {
320320
};
321321
};
322322
}
323+
324+
/**
325+
* Tuple representing public schema version. Patch is omitted - it doesn't change the schema.
326+
*/
327+
export type SaleorSchemaVersion = [major: number, minor: number];

0 commit comments

Comments
 (0)