Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"typescript": "4.9.5",
"vi-fetch": "^0.8.0",
"vite": "6.0.11 ",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "3.0.4"
},
"peerDependenciesMeta": {
Expand Down Expand Up @@ -144,6 +145,11 @@
"import": "./handlers/next/index.mjs",
"require": "./handlers/next/index.js"
},
"./handlers/shared": {
"types": "./handlers/shared/index.d.ts",
"import": "./handlers/shared/index.mjs",
"require": "./handlers/shared/index.js"
},
"./saleor-app": {
"types": "./saleor-app.d.ts",
"import": "./saleor-app.mjs",
Expand Down
36 changes: 36 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 0 additions & 48 deletions src/handlers/next/create-manifest-handler.ts

This file was deleted.

64 changes: 0 additions & 64 deletions src/handlers/next/create-protected-handler.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { createMocks } from "node-mocks-http";
import { beforeEach, describe, expect, it, Mock, vi } from "vitest";

import { APL, AuthData } from "../../APL";
import { MockAPL } from "../../test-utils/mock-apl";
import { APL, AuthData } from "@/APL";
import * as fetchRemoteJwksModule from "@/fetch-remote-jwks";
import * as getAppIdModule from "@/get-app-id";
import { MockAPL } from "@/test-utils/mock-apl";

import { createAppRegisterHandler } from "./create-app-register-handler";

const mockJwksValue = "{}";
const mockAppId = "42";

vi.mock("../../get-app-id", () => ({
getAppId: vi.fn().mockResolvedValue("42"), // can't use var reference, due to hoisting
}));

vi.mock("../../fetch-remote-jwks", () => ({
fetchRemoteJwks: vi.fn().mockResolvedValue("{}"), // can't use var reference, due to hoisting
}));
// Cannot use vi.mock on module, due to issues with alias resolution
// in vitest vs TypeScript: https://github.com/vitest-dev/vitest/issues/3105
vi.spyOn(fetchRemoteJwksModule, "fetchRemoteJwks").mockResolvedValue("{}");
vi.spyOn(getAppIdModule, "getAppId").mockResolvedValue("42");

describe("create-app-register-handler", () => {
let mockApl: APL;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@ import { toNextHandler } from "retes/adapter";
import { withMethod } from "retes/middleware";
import { Response } from "retes/response";

import { AuthData } from "../../APL";
import { SALEOR_API_URL_HEADER } from "../../const";
import { createDebug } from "../../debug";
import { fetchRemoteJwks } from "../../fetch-remote-jwks";
import { getAppId } from "../../get-app-id";
import { withAuthTokenRequired } from "../../middleware";
import { HasAPL } from "../../saleor-app";
import { validateAllowSaleorUrls } from "./validate-allow-saleor-urls";
import { AuthData } from "@/APL";
import { SALEOR_API_URL_HEADER } from "@/const";
import { createDebug } from "@/debug";
import { fetchRemoteJwks } from "@/fetch-remote-jwks";
import { getAppId } from "@/get-app-id";
import { HookCallbackErrorParams } from "@/handlers/shared/create-app-register-handler-types";
import { validateAllowSaleorUrls } from "@/handlers/shared/validate-allow-saleor-urls";
import { withAuthTokenRequired } from "@/middleware";
import { HasAPL } from "@/saleor-app";

const debug = createDebug("createAppRegisterHandler");

type HookCallbackErrorParams = {
status?: number;
message?: string;
};

class RegisterCallbackError extends Error {
public status = 500;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createMocks } from "node-mocks-http";
import { describe, expect, it } from "vitest";

import { AppManifest } from "../../types";
import { AppManifest } from "@/types";

import { createManifestHandler } from "./create-manifest-handler";

describe("createManifestHandler", () => {
Expand Down
48 changes: 48 additions & 0 deletions src/handlers/platforms/next/create-manifest-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { NextApiHandler, NextApiRequest } from "next";

import { createDebug } from "@/debug";
import { getBaseUrl, getSaleorHeaders } from "@/headers";
import { AppManifest } from "@/types";

export type CreateManifestHandlerOptions = {
manifestFactory(context: {
appBaseUrl: string;
request: NextApiRequest;
/** For Saleor < 3.15 it will be null. */
schemaVersion: number | null;
}): AppManifest | Promise<AppManifest>;
};

const debug = createDebug("create-manifest-handler");

/**
* Creates API handler for Next.js. Helps with Manifest creation, hides
* implementation details if possible
* In the future this will be extracted to separate sdk/next package
*/
export const createManifestHandler =
(options: CreateManifestHandlerOptions): NextApiHandler =>
async (request, response) => {
const { schemaVersion } = getSaleorHeaders(request.headers);
const baseURL = getBaseUrl(request.headers);

debug("Received request with schema version \"%s\" and base URL \"%s\"", schemaVersion, baseURL);

try {
const manifest = await options.manifestFactory({
appBaseUrl: baseURL,
request,
schemaVersion,
});

debug("Executed manifest file");

return response.status(200).json(manifest);
} catch (e) {
debug("Error while resolving manifest: %O", e);

Check warning on line 42 in src/handlers/platforms/next/create-manifest-handler.ts

View check run for this annotation

Codecov / codecov/patch

src/handlers/platforms/next/create-manifest-handler.ts#L42

Added line #L42 was not covered by tests

return response.status(500).json({
message: "Error resolving manifest file",
});
}

Check warning on line 47 in src/handlers/platforms/next/create-manifest-handler.ts

View check run for this annotation

Codecov / codecov/patch

src/handlers/platforms/next/create-manifest-handler.ts#L44-L47

Added lines #L44 - L47 were not covered by tests
};
54 changes: 54 additions & 0 deletions src/handlers/platforms/next/create-protected-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next";

import { APL } from "@/APL";
import { createDebug } from "@/debug";
import { ProtectedHandlerErrorCodeMap } from "@/handlers/shared/protected-handler";

Check warning on line 5 in src/handlers/platforms/next/create-protected-handler.ts

View check run for this annotation

Codecov / codecov/patch

src/handlers/platforms/next/create-protected-handler.ts#L4-L5

Added lines #L4 - L5 were not covered by tests
import { Permission } from "@/types";

import {

Check warning on line 8 in src/handlers/platforms/next/create-protected-handler.ts

View check run for this annotation

Codecov / codecov/patch

src/handlers/platforms/next/create-protected-handler.ts#L8

Added line #L8 was not covered by tests
processSaleorProtectedHandler,
ProtectedHandlerError,
} from "./process-protected-handler";
import { ProtectedHandlerContext } from "./protected-handler-context";

const debug = createDebug("ProtectedHandler");

Check warning on line 14 in src/handlers/platforms/next/create-protected-handler.ts

View check run for this annotation

Codecov / codecov/patch

src/handlers/platforms/next/create-protected-handler.ts#L14

Added line #L14 was not covered by tests

export type NextProtectedApiHandler<TResp = unknown> = (
req: NextApiRequest,
res: NextApiResponse<TResp>,
ctx: ProtectedHandlerContext
) => unknown | Promise<unknown>;

/**
* Wraps provided function, to ensure incoming request comes from Saleor Dashboard.
* Also provides additional `context` object containing request properties.
*/
export const createProtectedHandler =
(
handlerFn: NextProtectedApiHandler,
apl: APL,
requiredPermissions?: Permission[]

Check warning on line 30 in src/handlers/platforms/next/create-protected-handler.ts

View check run for this annotation

Codecov / codecov/patch

src/handlers/platforms/next/create-protected-handler.ts#L26-L30

Added lines #L26 - L30 were not covered by tests
): NextApiHandler =>
(req, res) => {
debug("Protected handler called");
processSaleorProtectedHandler({
req,
apl,
requiredPermissions,
})
.then(async (context) => {
debug("Incoming request validated. Call handlerFn");
return handlerFn(req, res, context);
})
.catch((e) => {
debug("Unexpected error during processing the request");

Check warning on line 44 in src/handlers/platforms/next/create-protected-handler.ts

View check run for this annotation

Codecov / codecov/patch

src/handlers/platforms/next/create-protected-handler.ts#L32-L44

Added lines #L32 - L44 were not covered by tests

if (e instanceof ProtectedHandlerError) {
debug(`Validation error: ${e.message}`);
res.status(ProtectedHandlerErrorCodeMap[e.errorType] || 400).end();
return;
}
debug("Unexpected error: %O", e);
res.status(500).end();
});
};

Check warning on line 54 in src/handlers/platforms/next/create-protected-handler.ts

View check run for this annotation

Codecov / codecov/patch

src/handlers/platforms/next/create-protected-handler.ts#L46-L54

Added lines #L46 - L54 were not covered by tests
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
export * from "./saleor-webhooks/saleor-async-webhook";
export * from "./saleor-webhooks/saleor-sync-webhook";
export { NextWebhookApiHandler } from "./saleor-webhooks/saleor-webhook";
export * from "./saleor-webhooks/sync-webhook-response-builder";

// Left for compatibility
export { buildSyncWebhookResponsePayload } from "@/handlers/shared/sync-webhook-response-builder";

Check warning on line 11 in src/handlers/platforms/next/index.ts

View check run for this annotation

Codecov / codecov/patch

src/handlers/platforms/next/index.ts#L11

Added line #L11 was not covered by tests
Loading