@scalar/mock-server 0.3.24 → 0.3.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/createMockServer.d.ts +1 -1
- package/dist/createMockServer.d.ts.map +1 -1
- package/dist/createMockServer.js +36 -48
- package/dist/createMockServer.js.map +7 -0
- package/dist/createMockServer.test.js +598 -0
- package/dist/createMockServer.test.js.map +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +7 -0
- package/dist/routes/mockAnyResponse.d.ts +1 -1
- package/dist/routes/mockAnyResponse.d.ts.map +1 -1
- package/dist/routes/mockAnyResponse.js +56 -64
- package/dist/routes/mockAnyResponse.js.map +7 -0
- package/dist/routes/respondWithAuthorizePage.js +39 -31
- package/dist/routes/respondWithAuthorizePage.js.map +7 -0
- package/dist/routes/respondWithOpenApiDocument.js +35 -35
- package/dist/routes/respondWithOpenApiDocument.js.map +7 -0
- package/dist/routes/respondWithToken.js +44 -41
- package/dist/routes/respondWithToken.js.map +7 -0
- package/dist/types.js +5 -4
- package/dist/types.js.map +7 -0
- package/dist/utils/createOpenApiDefinition.js +11 -0
- package/dist/utils/createOpenApiDefinition.js.map +7 -0
- package/dist/utils/findPreferredResponseKey.js +8 -10
- package/dist/utils/findPreferredResponseKey.js.map +7 -0
- package/dist/utils/findPreferredResponseKey.test.js +20 -0
- package/dist/utils/findPreferredResponseKey.test.js.map +7 -0
- package/dist/utils/getOpenAuthTokenUrls.js +33 -45
- package/dist/utils/getOpenAuthTokenUrls.js.map +7 -0
- package/dist/utils/getOpenAuthTokenUrls.test.js +127 -0
- package/dist/utils/getOpenAuthTokenUrls.test.js.map +7 -0
- package/dist/utils/getOperations.d.ts +1 -1
- package/dist/utils/getOperations.d.ts.map +1 -1
- package/dist/utils/getOperations.js +11 -14
- package/dist/utils/getOperations.js.map +7 -0
- package/dist/utils/handleAuthentication.js +95 -101
- package/dist/utils/handleAuthentication.js.map +7 -0
- package/dist/utils/honoRouteFromPath.js +5 -7
- package/dist/utils/honoRouteFromPath.js.map +7 -0
- package/dist/utils/honoRouteFromPath.test.js +32 -0
- package/dist/utils/honoRouteFromPath.test.js.map +7 -0
- package/dist/utils/isAuthenticationRequired.js +14 -18
- package/dist/utils/isAuthenticationRequired.js.map +7 -0
- package/dist/utils/isAuthenticationRequired.test.js +23 -0
- package/dist/utils/isAuthenticationRequired.test.js.map +7 -0
- package/dist/utils/logAuthenticationInstructions.js +109 -107
- package/dist/utils/logAuthenticationInstructions.js.map +7 -0
- package/dist/utils/setupAuthenticationRoutes.js +76 -82
- package/dist/utils/setupAuthenticationRoutes.js.map +7 -0
- package/package.json +7 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockAnyResponse.d.ts","sourceRoot":"","sources":["../../src/routes/mockAnyResponse.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAMnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"mockAnyResponse.d.ts","sourceRoot":"","sources":["../../src/routes/mockAnyResponse.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAMnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAGhD;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,iBAAiB,YAyEnG"}
|
|
@@ -1,67 +1,59 @@
|
|
|
1
|
-
import { getExampleFromSchema } from
|
|
2
|
-
import { accepts } from
|
|
3
|
-
import objectToXML from
|
|
4
|
-
import { findPreferredResponseKey } from
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Mock any response
|
|
8
|
-
*/
|
|
1
|
+
import { getExampleFromSchema } from "@scalar/oas-utils/spec-getters";
|
|
2
|
+
import { accepts } from "hono/accepts";
|
|
3
|
+
import objectToXML from "object-to-xml";
|
|
4
|
+
import { findPreferredResponseKey } from "../utils/findPreferredResponseKey.js";
|
|
9
5
|
function mockAnyResponse(c, operation, options) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
operation,
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
// Response
|
|
18
|
-
// default, 200, 201 …
|
|
19
|
-
const preferredResponseKey = findPreferredResponseKey(Object.keys(operation.responses ?? {}));
|
|
20
|
-
const preferredResponse = preferredResponseKey ? operation.responses?.[preferredResponseKey] : null;
|
|
21
|
-
if (!preferredResponse) {
|
|
22
|
-
c.status(500);
|
|
23
|
-
return c.json({ error: 'No response defined for this operation.' });
|
|
24
|
-
}
|
|
25
|
-
const supportedContentTypes = Object.keys(preferredResponse?.content ?? {});
|
|
26
|
-
// Headers
|
|
27
|
-
const headers = preferredResponse?.headers ?? {};
|
|
28
|
-
Object.keys(headers).forEach((header) => {
|
|
29
|
-
const value = headers[header].schema ? getExampleFromSchema(headers[header].schema) : null;
|
|
30
|
-
if (value !== null) {
|
|
31
|
-
c.header(header, value);
|
|
32
|
-
}
|
|
6
|
+
if (options?.onRequest) {
|
|
7
|
+
options.onRequest({
|
|
8
|
+
context: c,
|
|
9
|
+
operation
|
|
33
10
|
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
11
|
+
}
|
|
12
|
+
const preferredResponseKey = findPreferredResponseKey(Object.keys(operation.responses ?? {}));
|
|
13
|
+
const preferredResponse = preferredResponseKey ? operation.responses?.[preferredResponseKey] : null;
|
|
14
|
+
if (!preferredResponse) {
|
|
15
|
+
c.status(500);
|
|
16
|
+
return c.json({ error: "No response defined for this operation." });
|
|
17
|
+
}
|
|
18
|
+
const supportedContentTypes = Object.keys(preferredResponse?.content ?? {});
|
|
19
|
+
const headers = preferredResponse?.headers ?? {};
|
|
20
|
+
Object.keys(headers).forEach((header) => {
|
|
21
|
+
const value = headers[header].schema ? getExampleFromSchema(headers[header].schema) : null;
|
|
22
|
+
if (value !== null) {
|
|
23
|
+
c.header(header, value);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
const acceptedContentType = accepts(c, {
|
|
27
|
+
header: "Accept",
|
|
28
|
+
supports: supportedContentTypes,
|
|
29
|
+
default: supportedContentTypes.includes("application/json") ? "application/json" : supportedContentTypes[0] ?? "text/plain;charset=UTF-8"
|
|
30
|
+
});
|
|
31
|
+
c.header("Content-Type", acceptedContentType);
|
|
32
|
+
const acceptedResponse = preferredResponse?.content?.[acceptedContentType];
|
|
33
|
+
const body = acceptedResponse?.example ? acceptedResponse.example : acceptedResponse?.schema ? getExampleFromSchema(acceptedResponse.schema, {
|
|
34
|
+
emptyString: "string",
|
|
35
|
+
variables: c.req.param(),
|
|
36
|
+
mode: "read"
|
|
37
|
+
}) : null;
|
|
38
|
+
const statusCode = Number.parseInt(
|
|
39
|
+
preferredResponseKey === "default" ? "200" : preferredResponseKey ?? "200",
|
|
40
|
+
10
|
|
41
|
+
);
|
|
42
|
+
c.status(statusCode);
|
|
43
|
+
return c.body(
|
|
44
|
+
typeof body === "object" ? (
|
|
45
|
+
// XML
|
|
46
|
+
acceptedContentType?.includes("xml") ? `<?xml version="1.0" encoding="UTF-8"?>${objectToXML(body)}` : (
|
|
47
|
+
// JSON
|
|
48
|
+
JSON.stringify(body, null, 2)
|
|
49
|
+
)
|
|
50
|
+
) : (
|
|
51
|
+
// String
|
|
52
|
+
body
|
|
53
|
+
)
|
|
54
|
+
);
|
|
65
55
|
}
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
export {
|
|
57
|
+
mockAnyResponse
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=mockAnyResponse.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/routes/mockAnyResponse.ts"],
|
|
4
|
+
"sourcesContent": ["import { getExampleFromSchema } from '@scalar/oas-utils/spec-getters'\nimport type { OpenAPI } from '@scalar/openapi-types'\nimport type { Context } from 'hono'\nimport { accepts } from 'hono/accepts'\nimport type { StatusCode } from 'hono/utils/http-status'\n// @ts-expect-error Doesn\u2019t come with types\nimport objectToXML from 'object-to-xml'\n\nimport type { MockServerOptions } from '@/types'\nimport { findPreferredResponseKey } from '@/utils/findPreferredResponseKey'\n\n/**\n * Mock any response\n */\nexport function mockAnyResponse(c: Context, operation: OpenAPI.Operation, options: MockServerOptions) {\n // Call onRequest callback\n if (options?.onRequest) {\n options.onRequest({\n context: c,\n operation,\n })\n }\n\n // Response\n // default, 200, 201 \u2026\n const preferredResponseKey = findPreferredResponseKey(Object.keys(operation.responses ?? {}))\n const preferredResponse = preferredResponseKey ? operation.responses?.[preferredResponseKey] : null\n\n if (!preferredResponse) {\n c.status(500)\n\n return c.json({ error: 'No response defined for this operation.' })\n }\n\n const supportedContentTypes = Object.keys(preferredResponse?.content ?? {})\n\n // Headers\n const headers = preferredResponse?.headers ?? {}\n Object.keys(headers).forEach((header) => {\n const value = headers[header].schema ? getExampleFromSchema(headers[header].schema) : null\n if (value !== null) {\n c.header(header, value)\n }\n })\n\n // Content-Type\n const acceptedContentType = accepts(c, {\n header: 'Accept',\n supports: supportedContentTypes,\n default: supportedContentTypes.includes('application/json')\n ? 'application/json'\n : (supportedContentTypes[0] ?? 'text/plain;charset=UTF-8'),\n })\n\n c.header('Content-Type', acceptedContentType)\n\n const acceptedResponse = preferredResponse?.content?.[acceptedContentType]\n\n // Body\n const body = acceptedResponse?.example\n ? acceptedResponse.example\n : acceptedResponse?.schema\n ? getExampleFromSchema(acceptedResponse.schema, {\n emptyString: 'string',\n variables: c.req.param(),\n mode: 'read',\n })\n : null\n\n // Status code\n const statusCode = Number.parseInt(\n preferredResponseKey === 'default' ? '200' : (preferredResponseKey ?? '200'),\n 10,\n ) as StatusCode\n\n c.status(statusCode)\n\n return c.body(\n typeof body === 'object'\n ? // XML\n acceptedContentType?.includes('xml')\n ? `<?xml version=\"1.0\" encoding=\"UTF-8\"?>${objectToXML(body)}`\n : // JSON\n JSON.stringify(body, null, 2)\n : // String\n body,\n )\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,4BAA4B;AAGrC,SAAS,eAAe;AAGxB,OAAO,iBAAiB;AAGxB,SAAS,gCAAgC;AAKlC,SAAS,gBAAgB,GAAY,WAA8B,SAA4B;AAEpG,MAAI,SAAS,WAAW;AACtB,YAAQ,UAAU;AAAA,MAChB,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AAIA,QAAM,uBAAuB,yBAAyB,OAAO,KAAK,UAAU,aAAa,CAAC,CAAC,CAAC;AAC5F,QAAM,oBAAoB,uBAAuB,UAAU,YAAY,oBAAoB,IAAI;AAE/F,MAAI,CAAC,mBAAmB;AACtB,MAAE,OAAO,GAAG;AAEZ,WAAO,EAAE,KAAK,EAAE,OAAO,0CAA0C,CAAC;AAAA,EACpE;AAEA,QAAM,wBAAwB,OAAO,KAAK,mBAAmB,WAAW,CAAC,CAAC;AAG1E,QAAM,UAAU,mBAAmB,WAAW,CAAC;AAC/C,SAAO,KAAK,OAAO,EAAE,QAAQ,CAAC,WAAW;AACvC,UAAM,QAAQ,QAAQ,MAAM,EAAE,SAAS,qBAAqB,QAAQ,MAAM,EAAE,MAAM,IAAI;AACtF,QAAI,UAAU,MAAM;AAClB,QAAE,OAAO,QAAQ,KAAK;AAAA,IACxB;AAAA,EACF,CAAC;AAGD,QAAM,sBAAsB,QAAQ,GAAG;AAAA,IACrC,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS,sBAAsB,SAAS,kBAAkB,IACtD,qBACC,sBAAsB,CAAC,KAAK;AAAA,EACnC,CAAC;AAED,IAAE,OAAO,gBAAgB,mBAAmB;AAE5C,QAAM,mBAAmB,mBAAmB,UAAU,mBAAmB;AAGzE,QAAM,OAAO,kBAAkB,UAC3B,iBAAiB,UACjB,kBAAkB,SAChB,qBAAqB,iBAAiB,QAAQ;AAAA,IAC5C,aAAa;AAAA,IACb,WAAW,EAAE,IAAI,MAAM;AAAA,IACvB,MAAM;AAAA,EACR,CAAC,IACD;AAGN,QAAM,aAAa,OAAO;AAAA,IACxB,yBAAyB,YAAY,QAAS,wBAAwB;AAAA,IACtE;AAAA,EACF;AAEA,IAAE,OAAO,UAAU;AAEnB,SAAO,EAAE;AAAA,IACP,OAAO,SAAS;AAAA;AAAA,MAEZ,qBAAqB,SAAS,KAAK,IACjC,yCAAyC,YAAY,IAAI,CAAC;AAAA;AAAA,QAE1D,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA,MAE9B;AAAA;AAAA,EACN;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,37 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const htmlContent = generateAuthorizationHtml(redirectUrl.toString(), title);
|
|
20
|
-
return c.html(htmlContent);
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
return c.html(generateErrorHtml('Invalid redirect_uri format', 'Please provide a valid URL. The redirect_uri parameter must be a properly formatted URL that includes the protocol (e.g., https://) and a valid domain. This is essential for the OAuth 2.0 flow to securely redirect after authorization.'), 400);
|
|
1
|
+
const EXAMPLE_AUTHORIZATION_CODE = "super-secret-token";
|
|
2
|
+
function respondWithAuthorizePage(c, title = "") {
|
|
3
|
+
const redirectUri = c.req.query("redirect_uri");
|
|
4
|
+
const state = c.req.query("state");
|
|
5
|
+
if (!redirectUri) {
|
|
6
|
+
return c.html(
|
|
7
|
+
generateErrorHtml(
|
|
8
|
+
"Missing redirect_uri parameter",
|
|
9
|
+
"This parameter is required for the OAuth 2.0 authorization flow to function correctly. Please provide a valid redirect URI in your request."
|
|
10
|
+
),
|
|
11
|
+
400
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const redirectUrl = new URL(redirectUri);
|
|
16
|
+
redirectUrl.searchParams.set("code", EXAMPLE_AUTHORIZATION_CODE);
|
|
17
|
+
if (state) {
|
|
18
|
+
redirectUrl.searchParams.set("state", state);
|
|
24
19
|
}
|
|
20
|
+
const htmlContent = generateAuthorizationHtml(redirectUrl.toString(), title);
|
|
21
|
+
return c.html(htmlContent);
|
|
22
|
+
} catch {
|
|
23
|
+
return c.html(
|
|
24
|
+
generateErrorHtml(
|
|
25
|
+
"Invalid redirect_uri format",
|
|
26
|
+
"Please provide a valid URL. The redirect_uri parameter must be a properly formatted URL that includes the protocol (e.g., https://) and a valid domain. This is essential for the OAuth 2.0 flow to securely redirect after authorization."
|
|
27
|
+
),
|
|
28
|
+
400
|
|
29
|
+
);
|
|
30
|
+
}
|
|
25
31
|
}
|
|
26
|
-
function generateAuthorizationHtml(redirectUrl, title =
|
|
27
|
-
|
|
32
|
+
function generateAuthorizationHtml(redirectUrl, title = "") {
|
|
33
|
+
return `
|
|
28
34
|
<!DOCTYPE html>
|
|
29
35
|
<html lang="en">
|
|
30
36
|
<head>
|
|
31
37
|
<meta charset="UTF-8">
|
|
32
38
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
33
39
|
<title>OAuth 2.0 Authorization</title>
|
|
34
|
-
<script src="https://cdn.tailwindcss.com"
|
|
40
|
+
<script src="https://cdn.tailwindcss.com"><\/script>
|
|
35
41
|
</head>
|
|
36
42
|
<body class="flex justify-center items-center h-screen bg-gray-100">
|
|
37
43
|
|
|
@@ -53,7 +59,7 @@ function generateAuthorizationHtml(redirectUrl, title = '') {
|
|
|
53
59
|
This application is requesting access to your account. By granting authorization, you allow the application to perform certain actions on your behalf.
|
|
54
60
|
</p>
|
|
55
61
|
<p>
|
|
56
|
-
If you
|
|
62
|
+
If you\u2019re comfortable with the access being requested, click the button below to grant authorization:
|
|
57
63
|
</p>
|
|
58
64
|
</div>
|
|
59
65
|
<div class="px-6 py-4 pt-0 flex justify-between">
|
|
@@ -78,13 +84,13 @@ function generateAuthorizationHtml(redirectUrl, title = '') {
|
|
|
78
84
|
`;
|
|
79
85
|
}
|
|
80
86
|
function generateErrorHtml(title, message) {
|
|
81
|
-
|
|
87
|
+
return `<html>
|
|
82
88
|
<html lang="en">
|
|
83
89
|
<head>
|
|
84
90
|
<meta charset="UTF-8">
|
|
85
91
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
86
92
|
<title>OAuth 2.0 Authorization</title>
|
|
87
|
-
<script src="https://cdn.tailwindcss.com"
|
|
93
|
+
<script src="https://cdn.tailwindcss.com"><\/script>
|
|
88
94
|
</head>
|
|
89
95
|
<body>
|
|
90
96
|
<div class="p-4 m-8 flex flex-col gap-4 text-lg">
|
|
@@ -101,5 +107,7 @@ function generateErrorHtml(title, message) {
|
|
|
101
107
|
</body>
|
|
102
108
|
</html>`;
|
|
103
109
|
}
|
|
104
|
-
|
|
105
|
-
|
|
110
|
+
export {
|
|
111
|
+
respondWithAuthorizePage
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=respondWithAuthorizePage.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/routes/respondWithAuthorizePage.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Context } from 'hono'\n\n/** Always responds with this code */\nconst EXAMPLE_AUTHORIZATION_CODE = 'super-secret-token'\n\n/**\n * Responds with an HTML page that simulates an OAuth 2.0 authorization page.\n */\nexport function respondWithAuthorizePage(c: Context, title = '') {\n const redirectUri = c.req.query('redirect_uri')\n const state = c.req.query('state')\n\n if (!redirectUri) {\n return c.html(\n generateErrorHtml(\n 'Missing redirect_uri parameter',\n 'This parameter is required for the OAuth 2.0 authorization flow to function correctly. Please provide a valid redirect URI in your request.',\n ),\n 400,\n )\n }\n\n try {\n // Validate redirect URI against allowed domains\n const redirectUrl = new URL(redirectUri)\n\n redirectUrl.searchParams.set('code', EXAMPLE_AUTHORIZATION_CODE)\n\n if (state) {\n redirectUrl.searchParams.set('state', state)\n }\n\n const htmlContent = generateAuthorizationHtml(redirectUrl.toString(), title)\n\n return c.html(htmlContent)\n } catch {\n return c.html(\n generateErrorHtml(\n 'Invalid redirect_uri format',\n 'Please provide a valid URL. The redirect_uri parameter must be a properly formatted URL that includes the protocol (e.g., https://) and a valid domain. This is essential for the OAuth 2.0 flow to securely redirect after authorization.',\n ),\n 400,\n )\n }\n}\n\nfunction generateAuthorizationHtml(redirectUrl: string, title = '') {\n return `\n<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>OAuth 2.0 Authorization</title>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n </head>\n <body class=\"flex justify-center items-center h-screen bg-gray-100\">\n\n <div class=\"flex flex-col\">\n <div class=\"mb-5 flex justify-center items-center gap-2\">\n <img src=\"https://scalar.com/logo-dark.svg\" class=\"w-6 inline-block\" />\n <div class=\"font-medium truncate max-w-[26ch] text-lg\">\n ${title}\n </div>\n </div>\n <div class=\"bg-gray-50 rounded-lg p-1 rounded-lg w-[28rem] shadow\">\n <div class=\"\">\n <h1 class=\"text font-medium text-gray-800 px-6 pt-2 pb-3 flex gap-3 rounded-t-lg\">\n OAuth 2.0 Authorization\n </h1>\n <div class=\"bg-white rounded\">\n <div class=\"text-gray-600 text-base px-6 py-5 flex flex-col gap-3\">\n <p>\n This application is requesting access to your account. By granting authorization, you allow the application to perform certain actions on your behalf.\n </p>\n <p>\n If you\u2019re comfortable with the access being requested, click the button below to grant authorization:\n </p>\n </div>\n <div class=\"px-6 py-4 pt-0 flex justify-between\">\n <a href=\"javascript:history.back()\" class=\"inline-block px-6 py-2 text-gray-600 rounded border\" aria-label=\"Cancel authorization\">\n Cancel\n </a>\n <a href=\"${redirectUrl}\" class=\"inline-block px-6 py-2 bg-black text-white rounded transition-colors duration-300 hover:bg-gray-800\" aria-label=\"Authorize application\">\n Authorize\n </a>\n </div>\n </div>\n </div>\n </div>\n\n <p class=\"text-xs text-gray-400 mt-5 text-center\">\n This authorization page is provided by @scalar/mock-server\n </p>\n\n </div>\n </body>\n</html>\n `\n}\n\nfunction generateErrorHtml(title: string, message: string) {\n return `<html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>OAuth 2.0 Authorization</title>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n </head>\n <body>\n <div class=\"p-4 m-8 flex flex-col gap-4 text-lg\">\n <h1 class=\"font-bold\">\n Error: ${title}\n </h1>\n <p>\n ${message}\n </p>\n <p>\n Example: <code class=\"bg-gray-100 py-1 px-2 rounded text-base\"><a href=\"?redirect_uri=https://example.com/callback\">?redirect_uri=https://example.com/callback</a></code>\n </p>\n </div>\n </body>\n</html>`\n}\n"],
|
|
5
|
+
"mappings": "AAGA,MAAM,6BAA6B;AAK5B,SAAS,yBAAyB,GAAY,QAAQ,IAAI;AAC/D,QAAM,cAAc,EAAE,IAAI,MAAM,cAAc;AAC9C,QAAM,QAAQ,EAAE,IAAI,MAAM,OAAO;AAEjC,MAAI,CAAC,aAAa;AAChB,WAAO,EAAE;AAAA,MACP;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AAEF,UAAM,cAAc,IAAI,IAAI,WAAW;AAEvC,gBAAY,aAAa,IAAI,QAAQ,0BAA0B;AAE/D,QAAI,OAAO;AACT,kBAAY,aAAa,IAAI,SAAS,KAAK;AAAA,IAC7C;AAEA,UAAM,cAAc,0BAA0B,YAAY,SAAS,GAAG,KAAK;AAE3E,WAAO,EAAE,KAAK,WAAW;AAAA,EAC3B,QAAQ;AACN,WAAO,EAAE;AAAA,MACP;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,0BAA0B,aAAqB,QAAQ,IAAI;AAClE,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAeG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAqBQ,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBpC;AAEA,SAAS,kBAAkB,OAAe,SAAiB;AACzD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAWQ,KAAK;AAAA;AAAA;AAAA,UAGZ,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQjB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import { openapi } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { openapi } from "@scalar/openapi-parser";
|
|
2
|
+
async function respondWithOpenApiDocument(c, input, format = "json") {
|
|
3
|
+
if (!input) {
|
|
4
|
+
return c.text("Not found", 404);
|
|
5
|
+
}
|
|
6
|
+
try {
|
|
7
|
+
const { specification } = await openapi().load(input).get();
|
|
8
|
+
if (format === "json") {
|
|
9
|
+
return c.json(specification);
|
|
9
10
|
}
|
|
10
11
|
try {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
catch (error) {
|
|
25
|
-
return c.json({
|
|
26
|
-
error: 'Failed to convert specification to YAML',
|
|
27
|
-
message: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
28
|
-
}, 500);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
return c.json({
|
|
33
|
-
error: 'Failed to parse OpenAPI specification',
|
|
34
|
-
message: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
35
|
-
}, 400);
|
|
12
|
+
const yamlSpecification = await openapi().load(input).toYaml();
|
|
13
|
+
c.header("Content-Type", "text/yaml");
|
|
14
|
+
return c.text(yamlSpecification, 200, {
|
|
15
|
+
"Content-Type": "application/yaml; charset=UTF-8"
|
|
16
|
+
});
|
|
17
|
+
} catch (error) {
|
|
18
|
+
return c.json(
|
|
19
|
+
{
|
|
20
|
+
error: "Failed to convert specification to YAML",
|
|
21
|
+
message: error instanceof Error ? error.message : "Unknown error occurred"
|
|
22
|
+
},
|
|
23
|
+
500
|
|
24
|
+
);
|
|
36
25
|
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
return c.json(
|
|
28
|
+
{
|
|
29
|
+
error: "Failed to parse OpenAPI specification",
|
|
30
|
+
message: error instanceof Error ? error.message : "Unknown error occurred"
|
|
31
|
+
},
|
|
32
|
+
400
|
|
33
|
+
);
|
|
34
|
+
}
|
|
37
35
|
}
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
export {
|
|
37
|
+
respondWithOpenApiDocument
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=respondWithOpenApiDocument.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/routes/respondWithOpenApiDocument.ts"],
|
|
4
|
+
"sourcesContent": ["import { openapi } from '@scalar/openapi-parser'\nimport type { Context } from 'hono'\n\n/**\n * OpenAPI endpoints\n */\nexport async function respondWithOpenApiDocument(\n c: Context,\n input?: string | Record<string, any>,\n format: 'json' | 'yaml' = 'json',\n) {\n if (!input) {\n return c.text('Not found', 404)\n }\n\n try {\n const { specification } = await openapi().load(input).get()\n\n // JSON\n if (format === 'json') {\n return c.json(specification)\n }\n\n // YAML\n try {\n const yamlSpecification = await openapi().load(input).toYaml()\n c.header('Content-Type', 'text/yaml')\n return c.text(yamlSpecification, 200, {\n 'Content-Type': 'application/yaml; charset=UTF-8',\n })\n } catch (error) {\n return c.json(\n {\n error: 'Failed to convert specification to YAML',\n message: error instanceof Error ? error.message : 'Unknown error occurred',\n },\n 500,\n )\n }\n } catch (error) {\n return c.json(\n {\n error: 'Failed to parse OpenAPI specification',\n message: error instanceof Error ? error.message : 'Unknown error occurred',\n },\n 400,\n )\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,eAAe;AAMxB,eAAsB,2BACpB,GACA,OACA,SAA0B,QAC1B;AACA,MAAI,CAAC,OAAO;AACV,WAAO,EAAE,KAAK,aAAa,GAAG;AAAA,EAChC;AAEA,MAAI;AACF,UAAM,EAAE,cAAc,IAAI,MAAM,QAAQ,EAAE,KAAK,KAAK,EAAE,IAAI;AAG1D,QAAI,WAAW,QAAQ;AACrB,aAAO,EAAE,KAAK,aAAa;AAAA,IAC7B;AAGA,QAAI;AACF,YAAM,oBAAoB,MAAM,QAAQ,EAAE,KAAK,KAAK,EAAE,OAAO;AAC7D,QAAE,OAAO,gBAAgB,WAAW;AACpC,aAAO,EAAE,KAAK,mBAAmB,KAAK;AAAA,QACpC,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH,SAAS,OAAO;AACd,aAAO,EAAE;AAAA,QACP;AAAA,UACE,OAAO;AAAA,UACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QACpD;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,WAAO,EAAE;AAAA,MACP;AAAA,QACE,OAAO;AAAA,QACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MACpD;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,43 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
const EXAMPLE_ACCESS_TOKEN = 'super-secret-access-token';
|
|
3
|
-
/**
|
|
4
|
-
* Responds with a JSON object simulating an OAuth 2.0 token response.
|
|
5
|
-
*/
|
|
1
|
+
const EXAMPLE_ACCESS_TOKEN = "super-secret-access-token";
|
|
6
2
|
function respondWithToken(c) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
3
|
+
const grantType = c.req.query("grant_type");
|
|
4
|
+
if (!grantType) {
|
|
5
|
+
return c.json(
|
|
6
|
+
{
|
|
7
|
+
error: "invalid_request",
|
|
8
|
+
error_description: "Missing grant_type parameter"
|
|
9
|
+
},
|
|
10
|
+
400
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
const supportedGrantTypes = ["authorization_code", "client_credentials", "refresh_token"];
|
|
14
|
+
if (!supportedGrantTypes.includes(grantType)) {
|
|
15
|
+
return c.json(
|
|
16
|
+
{
|
|
17
|
+
error: "unsupported_grant_type",
|
|
18
|
+
error_description: `Grant type must be one of: ${supportedGrantTypes.join(", ")}`
|
|
19
|
+
},
|
|
20
|
+
400
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
if (grantType === "authorization_code" && !c.req.query("code")) {
|
|
24
|
+
return c.json(
|
|
25
|
+
{
|
|
26
|
+
error: "invalid_request",
|
|
27
|
+
error_description: "Missing code parameter"
|
|
28
|
+
},
|
|
29
|
+
400
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
const tokenResponse = {
|
|
33
|
+
access_token: EXAMPLE_ACCESS_TOKEN,
|
|
34
|
+
token_type: "Bearer",
|
|
35
|
+
expires_in: 3600,
|
|
36
|
+
refresh_token: "example-refresh-token",
|
|
37
|
+
scope: c.req.query("scope") ?? "read write"
|
|
38
|
+
};
|
|
39
|
+
c.header("Cache-Control", "no-store");
|
|
40
|
+
c.header("Pragma", "no-cache");
|
|
41
|
+
return c.json(tokenResponse);
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
export {
|
|
44
|
+
respondWithToken
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=respondWithToken.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/routes/respondWithToken.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Context } from 'hono'\n\n/** Always responds with this token */\nconst EXAMPLE_ACCESS_TOKEN = 'super-secret-access-token'\n\n/**\n * Responds with a JSON object simulating an OAuth 2.0 token response.\n */\nexport function respondWithToken(c: Context) {\n const grantType = c.req.query('grant_type')\n\n if (!grantType) {\n return c.json(\n {\n error: 'invalid_request',\n error_description: 'Missing grant_type parameter',\n },\n 400,\n )\n }\n\n // Validate supported grant types\n const supportedGrantTypes = ['authorization_code', 'client_credentials', 'refresh_token']\n\n if (!supportedGrantTypes.includes(grantType)) {\n return c.json(\n {\n error: 'unsupported_grant_type',\n error_description: `Grant type must be one of: ${supportedGrantTypes.join(', ')}`,\n },\n 400,\n )\n }\n\n // Validate required parameters for each grant type\n if (grantType === 'authorization_code' && !c.req.query('code')) {\n return c.json(\n {\n error: 'invalid_request',\n error_description: 'Missing code parameter',\n },\n 400,\n )\n }\n\n // Simulate token generation\n const tokenResponse = {\n access_token: EXAMPLE_ACCESS_TOKEN,\n token_type: 'Bearer',\n expires_in: 3600,\n refresh_token: 'example-refresh-token',\n scope: c.req.query('scope') ?? 'read write',\n }\n\n // Security headers\n c.header('Cache-Control', 'no-store')\n c.header('Pragma', 'no-cache')\n\n return c.json(tokenResponse)\n}\n"],
|
|
5
|
+
"mappings": "AAGA,MAAM,uBAAuB;AAKtB,SAAS,iBAAiB,GAAY;AAC3C,QAAM,YAAY,EAAE,IAAI,MAAM,YAAY;AAE1C,MAAI,CAAC,WAAW;AACd,WAAO,EAAE;AAAA,MACP;AAAA,QACE,OAAO;AAAA,QACP,mBAAmB;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,sBAAsB,CAAC,sBAAsB,sBAAsB,eAAe;AAExF,MAAI,CAAC,oBAAoB,SAAS,SAAS,GAAG;AAC5C,WAAO,EAAE;AAAA,MACP;AAAA,QACE,OAAO;AAAA,QACP,mBAAmB,8BAA8B,oBAAoB,KAAK,IAAI,CAAC;AAAA,MACjF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,MAAI,cAAc,wBAAwB,CAAC,EAAE,IAAI,MAAM,MAAM,GAAG;AAC9D,WAAO,EAAE;AAAA,MACP;AAAA,QACE,OAAO;AAAA,QACP,mBAAmB;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,gBAAgB;AAAA,IACpB,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,OAAO,EAAE,IAAI,MAAM,OAAO,KAAK;AAAA,EACjC;AAGA,IAAE,OAAO,iBAAiB,UAAU;AACpC,IAAE,OAAO,UAAU,UAAU;AAE7B,SAAO,EAAE,KAAK,aAAa;AAC7B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/types.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const httpMethods = ["get", "put", "post", "delete", "options", "patch"];
|
|
2
|
+
export {
|
|
3
|
+
httpMethods
|
|
4
|
+
};
|
|
5
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/types.ts"],
|
|
4
|
+
"sourcesContent": ["import type { OpenAPI } from '@scalar/openapi-types'\nimport type { Context } from 'hono'\n\n/** Available HTTP methods for Hono routes */\nexport const httpMethods = ['get', 'put', 'post', 'delete', 'options', 'patch'] as const\n\n/** Valid HTTP method */\nexport type HttpMethod = (typeof httpMethods)[number]\n\nexport type MockServerOptions = {\n /**\n * The OpenAPI specification to use for mocking.\n * Can be a string (URL or file path) or an object.\n */\n specification: string | Record<string, any>\n\n /**\n * Callback function to be called before each request is processed.\n */\n onRequest?: (data: { context: Context; operation: OpenAPI.Operation }) => void\n}\n"],
|
|
5
|
+
"mappings": "AAIO,MAAM,cAAc,CAAC,OAAO,OAAO,QAAQ,UAAU,WAAW,OAAO;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
function createOpenApiDefinition(securitySchemes) {
|
|
2
|
+
return {
|
|
3
|
+
openapi: "3.1.1",
|
|
4
|
+
info: { title: "Test API", version: "1.0.0" },
|
|
5
|
+
components: { securitySchemes }
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
createOpenApiDefinition
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=createOpenApiDefinition.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/createOpenApiDefinition.ts"],
|
|
4
|
+
"sourcesContent": ["import type { OpenAPIV3, OpenAPIV3_1 } from '@scalar/openapi-types'\n\n/** Helper function create an OpenAPI document with security schemss */\nexport function createOpenApiDefinition(\n securitySchemes: Record<string, OpenAPIV3.SecuritySchemeObject | OpenAPIV3_1.SecuritySchemeObject>,\n): OpenAPIV3_1.Document {\n return {\n openapi: '3.1.1',\n info: { title: 'Test API', version: '1.0.0' },\n components: { securitySchemes },\n }\n}\n"],
|
|
5
|
+
"mappings": "AAGO,SAAS,wBACd,iBACsB;AACtB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM,EAAE,OAAO,YAAY,SAAS,QAAQ;AAAA,IAC5C,YAAY,EAAE,gBAAgB;AAAA,EAChC;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Find the preferred response key: default, 200, 201 …
|
|
3
|
-
*/
|
|
4
1
|
function findPreferredResponseKey(responses) {
|
|
5
|
-
|
|
2
|
+
return (
|
|
6
3
|
// Regular status codes
|
|
7
|
-
[
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
undefined);
|
|
4
|
+
["default", "200", "201", "204", "404", "500"].find((key) => responses?.includes(key) ?? false) ?? // Lowest status code
|
|
5
|
+
responses?.sort()[0] ?? void 0
|
|
6
|
+
);
|
|
11
7
|
}
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
export {
|
|
9
|
+
findPreferredResponseKey
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=findPreferredResponseKey.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/findPreferredResponseKey.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Find the preferred response key: default, 200, 201 \u2026\n */\nexport function findPreferredResponseKey(responses?: string[]) {\n return (\n // Regular status codes\n ['default', '200', '201', '204', '404', '500'].find((key) => responses?.includes(key) ?? false) ??\n // Lowest status code\n responses?.sort()[0] ??\n undefined\n )\n}\n"],
|
|
5
|
+
"mappings": "AAGO,SAAS,yBAAyB,WAAsB;AAC7D;AAAA;AAAA,IAEE,CAAC,WAAW,OAAO,OAAO,OAAO,OAAO,KAAK,EAAE,KAAK,CAAC,QAAQ,WAAW,SAAS,GAAG,KAAK,KAAK;AAAA,IAE9F,WAAW,KAAK,EAAE,CAAC,KACnB;AAAA;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { findPreferredResponseKey } from "./findPreferredResponseKey.js";
|
|
3
|
+
describe("findPreferredResponseKey", () => {
|
|
4
|
+
it("returns default over 200", () => {
|
|
5
|
+
expect(findPreferredResponseKey(["default", "200"])).toBe("default");
|
|
6
|
+
});
|
|
7
|
+
it("returns 201 if it\u2019s the only one", () => {
|
|
8
|
+
expect(findPreferredResponseKey(["201"])).toBe("201");
|
|
9
|
+
});
|
|
10
|
+
it("returns 200 over 201", () => {
|
|
11
|
+
expect(findPreferredResponseKey(["200", "201"])).toBe("200");
|
|
12
|
+
});
|
|
13
|
+
it("uses what\u2019s there", () => {
|
|
14
|
+
expect(findPreferredResponseKey(["301"])).toBe("301");
|
|
15
|
+
});
|
|
16
|
+
it("doesn\u2019t return anything if there\u2019s no key at all", () => {
|
|
17
|
+
expect(findPreferredResponseKey([])).toBe(void 0);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=findPreferredResponseKey.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/findPreferredResponseKey.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { describe, expect, it } from 'vitest'\n\nimport { findPreferredResponseKey } from './findPreferredResponseKey'\n\ndescribe('findPreferredResponseKey', () => {\n it('returns default over 200', () => {\n expect(findPreferredResponseKey(['default', '200'])).toBe('default')\n })\n\n it('returns 201 if it\u2019s the only one', () => {\n expect(findPreferredResponseKey(['201'])).toBe('201')\n })\n\n it('returns 200 over 201', () => {\n expect(findPreferredResponseKey(['200', '201'])).toBe('200')\n })\n\n it('uses what\u2019s there', () => {\n expect(findPreferredResponseKey(['301'])).toBe('301')\n })\n\n it('doesn\u2019t return anything if there\u2019s no key at all', () => {\n expect(findPreferredResponseKey([])).toBe(undefined)\n })\n})\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,UAAU,QAAQ,UAAU;AAErC,SAAS,gCAAgC;AAEzC,SAAS,4BAA4B,MAAM;AACzC,KAAG,4BAA4B,MAAM;AACnC,WAAO,yBAAyB,CAAC,WAAW,KAAK,CAAC,CAAC,EAAE,KAAK,SAAS;AAAA,EACrE,CAAC;AAED,KAAG,yCAAoC,MAAM;AAC3C,WAAO,yBAAyB,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,EACtD,CAAC;AAED,KAAG,wBAAwB,MAAM;AAC/B,WAAO,yBAAyB,CAAC,OAAO,KAAK,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,EAC7D,CAAC;AAED,KAAG,0BAAqB,MAAM;AAC5B,WAAO,yBAAyB,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,EACtD,CAAC;AAED,KAAG,8DAAoD,MAAM;AAC3D,WAAO,yBAAyB,CAAC,CAAC,CAAC,EAAE,KAAK,MAAS;AAAA,EACrD,CAAC;AACH,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|