Skip to content

Commit 51caa77

Browse files
authored
Add new Adapter and Action interfaces, add new Next.js handler implementation, remove middlewares (#401)
* Add actions * Add adapter, new shared classes * Add next.js platform adapter * Add new implementation for next.js handlers * Replace domain validation with saleorApiUrl * Remove deprecated exports * Remove deprecated exports, add missing export, fix imports * Fix broken imports * Remove middlewares * Remove usage of Saleor-Domain header * Make saleorSchemaVersion required, dropping support for Saleor < 3.15 Add tests * Make action types more strict, allow passing generic * Add register error codes type * Add register handler tests * Add more tests, fix broken jwks handling * Preffer http over other protocols when https is not present * Add tests for platform adapter * Add missing export * Adapter middleware headers - always return undefined for missing values * Add tests for adapter middleware * Add tests for protected action validator * Add tests for create-protected-handler * Remove unused code * Fix tests * Add method validation to manifest action * Fix TS error * Remove assertion to fix tsup build * Remove assertion to fix prettier * Remove retes * Remove deprecated webhook fields * Rewrite saleor-async-webhook tests * Add changesets * Remove duplicated changeset * Add missing coverage * Add tests for re-fetching jwks * Fix TS error * Add missing test case * Make fields required on SaleorAsyncWebhook * Add more tests for sync webhook * Improve changeset description * Rename adapter middleware -> saleor request processor * Remove debug backwards compatibility * CR * Update changeset * Remove actions from export * Remove externals export
1 parent d339a69 commit 51caa77

File tree

57 files changed

+3517
-2121
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+3517
-2121
lines changed

.changeset/hip-queens-roll.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@saleor/app-sdk": patch
3+
---
4+
5+
Removed `/middlewares`, you should use `/handlers` instead.

.changeset/kind-zoos-raise.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@saleor/app-sdk": major
3+
---
4+
5+
Removed deprecated fields fields and methods in `/handlers`:
6+
7+
- `SaleorAsyncWebhook` and `SaleorSyncWebhook` - removed `asyncEvent` and `subscriptionQueryAst`
8+
- Removed `processSaleorWebhook` and `processProtectedHandler` methods
9+
- Some types were moved from `/next` to `/shared`

.changeset/sixty-taxis-glow.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@saleor/app-sdk": patch
3+
---
4+
5+
Added abstract `PlatformAdapterInterface` and `ActionHandlerInterface` to enable cross-framework handler implementations.
6+
7+
Next.js handlers were rewritten to use the new interface.

.changeset/tough-socks-tease.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"@saleor/app-sdk": major
33
---
44

5-
Breaking change: Remove checking "domain" header from Saleor requests. It should be replaced with the "saleor-api-url" header.
5+
Breaking change: SDK will no longer check `saleor-domain` header when validating Saleor requests, instead it will check `saleor-api-url` header.

package.json

-6
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
"debug": "4.3.4",
4242
"jose": "4.14.4",
4343
"raw-body": "2.5.2",
44-
"retes": "0.33.0",
4544
"uuid": "9.0.0"
4645
},
4746
"devDependencies": {
@@ -126,11 +125,6 @@
126125
"import": "./settings-manager/index.mjs",
127126
"require": "./settings-manager/index.js"
128127
},
129-
"./middleware": {
130-
"types": "./middleware/index.d.ts",
131-
"import": "./middleware/index.mjs",
132-
"require": "./middleware/index.js"
133-
},
134128
"./urls": {
135129
"types": "./urls.d.ts",
136130
"import": "./urls.mjs",

pnpm-lock.yaml

-30
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
3+
import { SALEOR_SCHEMA_VERSION } from "@/const";
4+
import { MockAdapter } from "@/test-utils/mock-adapter";
5+
import { AppManifest } from "@/types";
6+
7+
import { ManifestActionHandler } from "./manifest-action-handler";
8+
9+
describe("ManifestActionHandler", () => {
10+
const mockManifest: AppManifest = {
11+
id: "test-app",
12+
name: "Test Application",
13+
version: "1.0.0",
14+
appUrl: "http://example.com",
15+
permissions: [],
16+
tokenTargetUrl: "http://example.com/token",
17+
};
18+
19+
let adapter: MockAdapter;
20+
21+
beforeEach(() => {
22+
adapter = new MockAdapter({
23+
mockHeaders: {
24+
[SALEOR_SCHEMA_VERSION]: "3.20",
25+
},
26+
baseUrl: "http://example.com",
27+
});
28+
adapter.method = "GET";
29+
});
30+
31+
it("should call manifest factory and return 200 status when it resolves", async () => {
32+
const handler = new ManifestActionHandler(adapter);
33+
const manifestFactory = vi.fn().mockResolvedValue(mockManifest);
34+
35+
const result = await handler.handleAction({ manifestFactory });
36+
37+
expect(result.status).toBe(200);
38+
expect(result.body).toEqual(mockManifest);
39+
expect(manifestFactory).toHaveBeenCalledWith({
40+
appBaseUrl: "http://example.com",
41+
request: {},
42+
schemaVersion: 3.20,
43+
});
44+
});
45+
46+
it("should call manifest factory and return 500 when it throws an error", async () => {
47+
const handler = new ManifestActionHandler(adapter);
48+
const manifestFactory = vi.fn().mockRejectedValue(new Error("Test error"));
49+
50+
const result = await handler.handleAction({ manifestFactory });
51+
52+
expect(result.status).toBe(500);
53+
expect(result.body).toBe("Error resolving manifest file.");
54+
});
55+
56+
it("should return 405 when not called using HTTP GET method", async () => {
57+
adapter.method = "POST";
58+
const handler = new ManifestActionHandler(adapter);
59+
60+
const manifestFactory = vi.fn().mockResolvedValue(mockManifest);
61+
62+
const result = await handler.handleAction({ manifestFactory });
63+
64+
expect(result.status).toBe(405);
65+
expect(result.body).toBe("Method not allowed");
66+
expect(manifestFactory).not.toHaveBeenCalled();
67+
})
68+
69+
it("should return 400 when receives null schema version header from unsupported legacy Saleor version", async () => {
70+
adapter.getHeader = vi.fn().mockReturnValue(null);
71+
const handler = new ManifestActionHandler(adapter);
72+
73+
const manifestFactory = vi.fn().mockResolvedValue(mockManifest);
74+
75+
const result = await handler.handleAction({ manifestFactory });
76+
77+
expect(result.status).toBe(400);
78+
expect(result.body).toBe("Missing schema version header");
79+
expect(manifestFactory).not.toHaveBeenCalled();
80+
});
81+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { createDebug } from "@/debug";
2+
import { AppManifest } from "@/types";
3+
4+
import {
5+
ActionHandlerInterface,
6+
ActionHandlerResult,
7+
PlatformAdapterInterface,
8+
} from "../shared/generic-adapter-use-case-types";
9+
import { SaleorRequestProcessor } from "../shared/saleor-request-processor";
10+
11+
const debug = createDebug("create-manifest-handler");
12+
13+
export type CreateManifestHandlerOptions<T> = {
14+
manifestFactory(context: {
15+
appBaseUrl: string;
16+
request: T;
17+
/** Added in Saleor 3.15 */
18+
schemaVersion: number;
19+
}): AppManifest | Promise<AppManifest>;
20+
};
21+
22+
export class ManifestActionHandler<I> implements ActionHandlerInterface {
23+
constructor(private adapter: PlatformAdapterInterface<I>) {}
24+
25+
private requestProcessor = new SaleorRequestProcessor(this.adapter);
26+
27+
async handleAction(options: CreateManifestHandlerOptions<I>): Promise<ActionHandlerResult> {
28+
const { schemaVersion } = this.requestProcessor.getSaleorHeaders();
29+
const baseURL = this.adapter.getBaseUrl();
30+
31+
debug("Received request with schema version \"%s\" and base URL \"%s\"", schemaVersion, baseURL);
32+
33+
const invalidMethodResponse = this.requestProcessor.withMethod(["GET"]);
34+
35+
if (invalidMethodResponse) {
36+
return invalidMethodResponse;
37+
}
38+
39+
if (!schemaVersion) {
40+
return {
41+
status: 400,
42+
bodyType: "string",
43+
body: "Missing schema version header",
44+
};
45+
}
46+
47+
try {
48+
const manifest = await options.manifestFactory({
49+
appBaseUrl: baseURL,
50+
request: this.adapter.request,
51+
schemaVersion,
52+
});
53+
54+
debug("Executed manifest file");
55+
56+
return {
57+
status: 200,
58+
bodyType: "json",
59+
body: manifest,
60+
};
61+
} catch (e) {
62+
debug("Error while resolving manifest: %O", e);
63+
64+
return {
65+
status: 500,
66+
bodyType: "string",
67+
body: "Error resolving manifest file.",
68+
};
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)