@scalar/mock-server 0.9.8 → 0.9.10

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/create-mock-server.js +79 -68
  3. package/dist/index.js +1 -5
  4. package/dist/libs/store.js +66 -65
  5. package/dist/routes/mock-any-response.js +70 -63
  6. package/dist/routes/mock-handler-response.js +140 -100
  7. package/dist/routes/respond-with-authorize-page.js +89 -80
  8. package/dist/routes/respond-with-openapi-document.js +32 -35
  9. package/dist/routes/respond-with-token.js +40 -45
  10. package/dist/types.js +2 -5
  11. package/dist/utils/build-handler-context.js +83 -70
  12. package/dist/utils/build-seed-context.js +59 -52
  13. package/dist/utils/create-openapi-definition.js +7 -10
  14. package/dist/utils/execute-handler.js +16 -18
  15. package/dist/utils/execute-seed.js +22 -21
  16. package/dist/utils/find-preferred-response-key.js +9 -9
  17. package/dist/utils/get-open-auth-token-urls.js +45 -35
  18. package/dist/utils/get-operation.js +12 -12
  19. package/dist/utils/handle-authentication.js +106 -101
  20. package/dist/utils/hono-route-from-path.js +6 -6
  21. package/dist/utils/is-authentication-required.js +17 -15
  22. package/dist/utils/log-authentication-instructions.js +105 -110
  23. package/dist/utils/process-openapi-document.js +71 -58
  24. package/dist/utils/set-up-authentication-routes.js +80 -77
  25. package/dist/utils/store-wrapper.js +40 -39
  26. package/package.json +10 -14
  27. package/dist/create-mock-server.js.map +0 -7
  28. package/dist/index.js.map +0 -7
  29. package/dist/libs/store.js.map +0 -7
  30. package/dist/routes/mock-any-response.js.map +0 -7
  31. package/dist/routes/mock-handler-response.js.map +0 -7
  32. package/dist/routes/respond-with-authorize-page.js.map +0 -7
  33. package/dist/routes/respond-with-openapi-document.js.map +0 -7
  34. package/dist/routes/respond-with-token.js.map +0 -7
  35. package/dist/types.js.map +0 -7
  36. package/dist/utils/build-handler-context.js.map +0 -7
  37. package/dist/utils/build-seed-context.js.map +0 -7
  38. package/dist/utils/create-openapi-definition.js.map +0 -7
  39. package/dist/utils/execute-handler.js.map +0 -7
  40. package/dist/utils/execute-seed.js.map +0 -7
  41. package/dist/utils/find-preferred-response-key.js.map +0 -7
  42. package/dist/utils/get-open-auth-token-urls.js.map +0 -7
  43. package/dist/utils/get-operation.js.map +0 -7
  44. package/dist/utils/handle-authentication.js.map +0 -7
  45. package/dist/utils/hono-route-from-path.js.map +0 -7
  46. package/dist/utils/is-authentication-required.js.map +0 -7
  47. package/dist/utils/log-authentication-instructions.js.map +0 -7
  48. package/dist/utils/process-openapi-document.js.map +0 -7
  49. package/dist/utils/set-up-authentication-routes.js.map +0 -7
  50. package/dist/utils/store-wrapper.js.map +0 -7
@@ -1,110 +1,150 @@
1
- import { getExampleFromSchema } from "@scalar/oas-utils/spec-getters";
2
- import { accepts } from "hono/accepts";
3
- import { buildHandlerContext } from "../utils/build-handler-context.js";
4
- import { executeHandler } from "../utils/execute-handler.js";
1
+ import { getExampleFromSchema } from '@scalar/oas-utils/spec-getters';
2
+ import { accepts } from 'hono/accepts';
3
+ import { buildHandlerContext } from '../utils/build-handler-context.js';
4
+ import { executeHandler } from '../utils/execute-handler.js';
5
+ /**
6
+ * Get example response from OpenAPI spec for a given status code.
7
+ * Returns the example value if found, or null if not available.
8
+ */
5
9
  function getExampleFromResponse(c, statusCode, responses) {
6
- if (!responses) {
7
- return null;
8
- }
9
- const statusCodeStr = statusCode.toString();
10
- const response = responses[statusCodeStr] || responses.default;
11
- if (!response) {
12
- return null;
13
- }
14
- const supportedContentTypes = Object.keys(response.content ?? {});
15
- if (supportedContentTypes.length === 0) {
16
- return null;
17
- }
18
- const acceptedContentType = accepts(c, {
19
- header: "Accept",
20
- supports: supportedContentTypes,
21
- default: supportedContentTypes.includes("application/json") ? "application/json" : supportedContentTypes[0] ?? "text/plain;charset=UTF-8"
22
- });
23
- const acceptedResponse = response.content?.[acceptedContentType];
24
- if (!acceptedResponse) {
25
- return null;
26
- }
27
- return acceptedResponse.example !== void 0 ? acceptedResponse.example : acceptedResponse.schema ? getExampleFromSchema(acceptedResponse.schema, {
28
- emptyString: "string",
29
- variables: c.req.param(),
30
- mode: "read"
31
- }) : null;
10
+ if (!responses) {
11
+ return null;
12
+ }
13
+ const statusCodeStr = statusCode.toString();
14
+ const response = responses[statusCodeStr] || responses.default;
15
+ if (!response) {
16
+ return null;
17
+ }
18
+ const supportedContentTypes = Object.keys(response.content ?? {});
19
+ // If no content types are defined, return null
20
+ if (supportedContentTypes.length === 0) {
21
+ return null;
22
+ }
23
+ // Content-Type negotiation
24
+ const acceptedContentType = accepts(c, {
25
+ header: 'Accept',
26
+ supports: supportedContentTypes,
27
+ default: supportedContentTypes.includes('application/json')
28
+ ? 'application/json'
29
+ : (supportedContentTypes[0] ?? 'text/plain;charset=UTF-8'),
30
+ });
31
+ const acceptedResponse = response.content?.[acceptedContentType];
32
+ if (!acceptedResponse) {
33
+ return null;
34
+ }
35
+ // Extract example from example property or generate from schema
36
+ return acceptedResponse.example !== undefined
37
+ ? acceptedResponse.example
38
+ : acceptedResponse.schema
39
+ ? getExampleFromSchema(acceptedResponse.schema, {
40
+ emptyString: 'string',
41
+ variables: c.req.param(),
42
+ mode: 'read',
43
+ })
44
+ : null;
32
45
  }
46
+ /**
47
+ * Determine HTTP status code based on store operation tracking.
48
+ * Prioritizes operations based on semantic meaning:
49
+ * - get > update > delete > create > list
50
+ * This ensures that if a handler performs multiple operations (e.g., get followed by create for logging),
51
+ * the status code reflects the most semantically meaningful operation.
52
+ */
33
53
  function determineStatusCode(tracking) {
34
- const { operations } = tracking;
35
- if (operations.length === 0) {
36
- return 200;
37
- }
38
- const getOperation = operations.find((op) => op.operation === "get");
39
- if (getOperation) {
40
- if (getOperation.result === void 0 || getOperation.result === null) {
41
- return 404;
54
+ const { operations } = tracking;
55
+ // If no operations were performed, default to 200
56
+ if (operations.length === 0) {
57
+ return 200;
42
58
  }
43
- return 200;
44
- }
45
- const updateOperation = operations.find((op) => op.operation === "update");
46
- if (updateOperation) {
47
- if (updateOperation.result === null || updateOperation.result === void 0) {
48
- return 404;
59
+ // Priority order: get > update > delete > create > list
60
+ // Check for get operations first (highest priority)
61
+ const getOperation = operations.find((op) => op.operation === 'get');
62
+ if (getOperation) {
63
+ // Return 404 if get() returned undefined or null
64
+ if (getOperation.result === undefined || getOperation.result === null) {
65
+ return 404;
66
+ }
67
+ return 200;
49
68
  }
50
- return 200;
51
- }
52
- const deleteOperation = operations.find((op) => op.operation === "delete");
53
- if (deleteOperation) {
54
- if (deleteOperation.result === null || deleteOperation.result === void 0) {
55
- return 404;
69
+ // Check for update operations
70
+ const updateOperation = operations.find((op) => op.operation === 'update');
71
+ if (updateOperation) {
72
+ // Return 404 if update() returned null (item not found)
73
+ if (updateOperation.result === null || updateOperation.result === undefined) {
74
+ return 404;
75
+ }
76
+ return 200;
56
77
  }
57
- return 204;
58
- }
59
- const createOperation = operations.find((op) => op.operation === "create");
60
- if (createOperation) {
61
- return 201;
62
- }
63
- return 200;
78
+ // Check for delete operations
79
+ const deleteOperation = operations.find((op) => op.operation === 'delete');
80
+ if (deleteOperation) {
81
+ // Return 404 if delete() returned null (item not found)
82
+ if (deleteOperation.result === null || deleteOperation.result === undefined) {
83
+ return 404;
84
+ }
85
+ return 204;
86
+ }
87
+ // Check for create operations
88
+ const createOperation = operations.find((op) => op.operation === 'create');
89
+ if (createOperation) {
90
+ return 201;
91
+ }
92
+ // Default to 200 for list or any other operation
93
+ return 200;
64
94
  }
65
- async function mockHandlerResponse(c, operation, options) {
66
- if (options?.onRequest) {
67
- options.onRequest({
68
- context: c,
69
- operation
70
- });
71
- }
72
- const handlerCode = operation?.["x-handler"];
73
- if (!handlerCode) {
74
- c.status(500);
75
- return c.json({ error: "x-handler code not found in operation" });
76
- }
77
- try {
78
- const { context, tracking } = await buildHandlerContext(c, operation);
79
- const { result } = await executeHandler(handlerCode, context);
80
- const statusCode = determineStatusCode(tracking);
81
- c.status(statusCode);
82
- if (statusCode === 204) {
83
- return c.body(null);
95
+ /**
96
+ * Mock response using x-handler code.
97
+ * Executes the handler and returns its result as the response.
98
+ */
99
+ export async function mockHandlerResponse(c, operation, options) {
100
+ // Call onRequest callback
101
+ if (options?.onRequest) {
102
+ options.onRequest({
103
+ context: c,
104
+ operation,
105
+ });
84
106
  }
85
- c.header("Content-Type", "application/json");
86
- if (result === void 0 || result === null) {
87
- const exampleResponse = getExampleFromResponse(
88
- c,
89
- statusCode,
90
- operation.responses
91
- );
92
- if (exampleResponse !== null) {
93
- return c.json(exampleResponse);
94
- }
95
- return c.json(null);
107
+ // Get x-handler code from operation
108
+ const handlerCode = operation?.['x-handler'];
109
+ if (!handlerCode) {
110
+ c.status(500);
111
+ return c.json({ error: 'x-handler code not found in operation' });
112
+ }
113
+ try {
114
+ // Build handler context with tracking
115
+ const { context, tracking } = await buildHandlerContext(c, operation);
116
+ // Execute handler
117
+ const { result } = await executeHandler(handlerCode, context);
118
+ // Determine status code based on all store operations, prioritizing semantically meaningful ones
119
+ const statusCode = determineStatusCode(tracking);
120
+ // Set status code
121
+ c.status(statusCode);
122
+ // For 204 No Content, return null body without Content-Type header
123
+ if (statusCode === 204) {
124
+ return c.body(null);
125
+ }
126
+ // Set Content-Type header for other responses
127
+ c.header('Content-Type', 'application/json');
128
+ // Return the handler result as JSON
129
+ // Handle undefined/null results gracefully
130
+ if (result === undefined || result === null) {
131
+ // Try to pick up example response from OpenAPI spec if available
132
+ const exampleResponse = getExampleFromResponse(c, statusCode, operation.responses);
133
+ if (exampleResponse !== null) {
134
+ return c.json(exampleResponse);
135
+ }
136
+ return c.json(null);
137
+ }
138
+ return c.json(result);
139
+ }
140
+ catch (error) {
141
+ // Log error to console
142
+ console.error('x-handler execution error:', error);
143
+ // Return 500 error
144
+ c.status(500);
145
+ return c.json({
146
+ error: 'Handler execution failed',
147
+ message: error instanceof Error ? error.message : String(error),
148
+ });
96
149
  }
97
- return c.json(result);
98
- } catch (error) {
99
- console.error("x-handler execution error:", error);
100
- c.status(500);
101
- return c.json({
102
- error: "Handler execution failed",
103
- message: error instanceof Error ? error.message : String(error)
104
- });
105
- }
106
150
  }
107
- export {
108
- mockHandlerResponse
109
- };
110
- //# sourceMappingURL=mock-handler-response.js.map
@@ -1,92 +1,105 @@
1
- const EXAMPLE_AUTHORIZATION_CODE = "super-secret-token";
2
- const EXAMPLE_ACCESS_TOKEN = "super-secret-access-token";
1
+ /** Always responds with this code */
2
+ const EXAMPLE_AUTHORIZATION_CODE = 'super-secret-token';
3
+ /** Always responds with this token for implicit flow */
4
+ const EXAMPLE_ACCESS_TOKEN = 'super-secret-access-token';
5
+ /**
6
+ * Escapes HTML special characters to prevent XSS when rendering user-controlled scope values.
7
+ */
3
8
  function escapeHtml(s) {
4
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
9
+ return s
10
+ .replace(/&/g, '&amp;')
11
+ .replace(/</g, '&lt;')
12
+ .replace(/>/g, '&gt;')
13
+ .replace(/"/g, '&quot;')
14
+ .replace(/'/g, '&#39;');
5
15
  }
16
+ /**
17
+ * Parses the OAuth 2.0 scope query parameter (space- or +-separated) into an array of scope strings.
18
+ */
6
19
  function parseScopeParam(scopeQuery) {
7
- if (!scopeQuery || scopeQuery.trim() === "") {
8
- return [];
9
- }
10
- return scopeQuery.split(/[\s+]+/).map((s) => s.trim()).filter(Boolean);
20
+ if (!scopeQuery || scopeQuery.trim() === '') {
21
+ return [];
22
+ }
23
+ return scopeQuery
24
+ .split(/[\s+]+/)
25
+ .map((s) => s.trim())
26
+ .filter(Boolean);
11
27
  }
12
- function respondWithAuthorizePage(c, title = "") {
13
- const redirectUri = c.req.query("redirect_uri");
14
- const responseType = c.req.query("response_type");
15
- const scope = c.req.query("scope");
16
- const state = c.req.query("state");
17
- if (!redirectUri) {
18
- return c.html(
19
- generateErrorHtml(
20
- "Missing redirect_uri parameter",
21
- "This parameter is required for the OAuth 2.0 authorization flow to function correctly. Please provide a valid redirect URI in your request."
22
- ),
23
- 400
24
- );
25
- }
26
- try {
27
- const redirectUrl = new URL(redirectUri);
28
- const isImplicitFlow = responseType === "token";
29
- if (isImplicitFlow) {
30
- const fragmentParams = new URLSearchParams();
31
- fragmentParams.set("access_token", EXAMPLE_ACCESS_TOKEN);
32
- fragmentParams.set("token_type", "Bearer");
33
- fragmentParams.set("expires_in", "3600");
34
- if (scope) {
35
- fragmentParams.set("scope", scope);
36
- }
37
- if (state) {
38
- fragmentParams.set("state", state);
39
- }
40
- redirectUrl.hash = fragmentParams.toString();
41
- } else {
42
- redirectUrl.searchParams.set("code", EXAMPLE_AUTHORIZATION_CODE);
43
- if (state) {
44
- redirectUrl.searchParams.set("state", state);
45
- }
28
+ /**
29
+ * Responds with an HTML page that simulates an OAuth 2.0 authorization page.
30
+ */
31
+ export function respondWithAuthorizePage(c, title = '') {
32
+ const redirectUri = c.req.query('redirect_uri');
33
+ const responseType = c.req.query('response_type');
34
+ const scope = c.req.query('scope');
35
+ const state = c.req.query('state');
36
+ if (!redirectUri) {
37
+ return c.html(generateErrorHtml('Missing redirect_uri parameter', 'This parameter is required for the OAuth 2.0 authorization flow to function correctly. Please provide a valid redirect URI in your request.'), 400);
38
+ }
39
+ try {
40
+ // Validate redirect URI against allowed domains
41
+ const redirectUrl = new URL(redirectUri);
42
+ const isImplicitFlow = responseType === 'token';
43
+ if (isImplicitFlow) {
44
+ const fragmentParams = new URLSearchParams();
45
+ fragmentParams.set('access_token', EXAMPLE_ACCESS_TOKEN);
46
+ fragmentParams.set('token_type', 'Bearer');
47
+ fragmentParams.set('expires_in', '3600');
48
+ if (scope) {
49
+ fragmentParams.set('scope', scope);
50
+ }
51
+ if (state) {
52
+ fragmentParams.set('state', state);
53
+ }
54
+ redirectUrl.hash = fragmentParams.toString();
55
+ }
56
+ else {
57
+ redirectUrl.searchParams.set('code', EXAMPLE_AUTHORIZATION_CODE);
58
+ if (state) {
59
+ redirectUrl.searchParams.set('state', state);
60
+ }
61
+ }
62
+ const deniedUrl = new URL(redirectUri);
63
+ if (isImplicitFlow) {
64
+ const deniedFragmentParams = new URLSearchParams();
65
+ deniedFragmentParams.set('error', 'access_denied');
66
+ deniedFragmentParams.set('error_description', 'User has denied the authorization request');
67
+ if (state) {
68
+ deniedFragmentParams.set('state', state);
69
+ }
70
+ deniedUrl.hash = deniedFragmentParams.toString();
71
+ }
72
+ else {
73
+ if (state) {
74
+ deniedUrl.searchParams.set('state', state);
75
+ }
76
+ deniedUrl.searchParams.set('error', 'access_denied');
77
+ deniedUrl.searchParams.set('error_description', 'User has denied the authorization request');
78
+ }
79
+ const scopes = parseScopeParam(c.req.query('scope'));
80
+ const htmlContent = generateAuthorizationHtml(redirectUrl.toString(), deniedUrl.toString(), title, scopes);
81
+ return c.html(htmlContent);
46
82
  }
47
- const deniedUrl = new URL(redirectUri);
48
- if (isImplicitFlow) {
49
- const deniedFragmentParams = new URLSearchParams();
50
- deniedFragmentParams.set("error", "access_denied");
51
- deniedFragmentParams.set("error_description", "User has denied the authorization request");
52
- if (state) {
53
- deniedFragmentParams.set("state", state);
54
- }
55
- deniedUrl.hash = deniedFragmentParams.toString();
56
- } else {
57
- if (state) {
58
- deniedUrl.searchParams.set("state", state);
59
- }
60
- deniedUrl.searchParams.set("error", "access_denied");
61
- deniedUrl.searchParams.set("error_description", "User has denied the authorization request");
83
+ catch {
84
+ 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);
62
85
  }
63
- const scopes = parseScopeParam(c.req.query("scope"));
64
- const htmlContent = generateAuthorizationHtml(redirectUrl.toString(), deniedUrl.toString(), title, scopes);
65
- return c.html(htmlContent);
66
- } catch {
67
- return c.html(
68
- generateErrorHtml(
69
- "Invalid redirect_uri format",
70
- "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."
71
- ),
72
- 400
73
- );
74
- }
75
86
  }
76
- function generateAuthorizationHtml(redirectUrl, deniedUrl, title = "", scopes = []) {
77
- const scopesSection = scopes.length > 0 ? `
87
+ function generateAuthorizationHtml(redirectUrl, deniedUrl, title = '', scopes = []) {
88
+ const scopesSection = scopes.length > 0
89
+ ? `
78
90
  <p class="font-medium text-gray-700">Requested Scopes</p>
79
91
  <ul class="list-disc list-inside space-y-1">
80
- ${scopes.map((scope) => `<li><code class="bg-gray-100 py-1 px-2 rounded text-sm">${escapeHtml(scope)}</code></li>`).join("\n ")}
81
- </ul>` : "";
82
- return `
92
+ ${scopes.map((scope) => `<li><code class="bg-gray-100 py-1 px-2 rounded text-sm">${escapeHtml(scope)}</code></li>`).join('\n ')}
93
+ </ul>`
94
+ : '';
95
+ return `
83
96
  <!DOCTYPE html>
84
97
  <html lang="en">
85
98
  <head>
86
99
  <meta charset="UTF-8">
87
100
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
88
101
  <title>OAuth 2.0 Authorization</title>
89
- <script src="https://cdn.tailwindcss.com"><\/script>
102
+ <script src="https://cdn.tailwindcss.com"></script>
90
103
  </head>
91
104
  <body class="flex justify-center items-center h-screen bg-gray-100">
92
105
 
@@ -134,13 +147,13 @@ function generateAuthorizationHtml(redirectUrl, deniedUrl, title = "", scopes =
134
147
  `;
135
148
  }
136
149
  function generateErrorHtml(title, message) {
137
- return `<html>
150
+ return `<html>
138
151
  <html lang="en">
139
152
  <head>
140
153
  <meta charset="UTF-8">
141
154
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
142
155
  <title>OAuth 2.0 Authorization</title>
143
- <script src="https://cdn.tailwindcss.com"><\/script>
156
+ <script src="https://cdn.tailwindcss.com"></script>
144
157
  </head>
145
158
  <body>
146
159
  <div class="p-4 m-8 flex flex-col gap-4 text-lg">
@@ -157,7 +170,3 @@ function generateErrorHtml(title, message) {
157
170
  </body>
158
171
  </html>`;
159
172
  }
160
- export {
161
- respondWithAuthorizePage
162
- };
163
- //# sourceMappingURL=respond-with-authorize-page.js.map
@@ -1,39 +1,36 @@
1
- import { normalize, toYaml } from "@scalar/openapi-parser";
2
- function respondWithOpenApiDocument(c, input, format = "json") {
3
- if (!input) {
4
- return c.text("Not found", 404);
5
- }
6
- try {
7
- const document = normalize(input);
8
- if (format === "json") {
9
- return c.json(document);
1
+ import { normalize, toYaml } from '@scalar/openapi-parser';
2
+ /**
3
+ * OpenAPI endpoints
4
+ */
5
+ export function respondWithOpenApiDocument(c, input, format = 'json') {
6
+ if (!input) {
7
+ return c.text('Not found', 404);
10
8
  }
11
9
  try {
12
- const yamlDocument = toYaml(normalize(document));
13
- c.header("Content-Type", "text/yaml");
14
- return c.text(yamlDocument, 200, {
15
- "Content-Type": "application/yaml; charset=UTF-8"
16
- });
17
- } catch (error) {
18
- return c.json(
19
- {
20
- error: "Failed to convert document to YAML",
21
- message: error instanceof Error ? error.message : "Unknown error occurred"
22
- },
23
- 500
24
- );
10
+ const document = normalize(input);
11
+ // JSON
12
+ if (format === 'json') {
13
+ return c.json(document);
14
+ }
15
+ // YAML
16
+ try {
17
+ const yamlDocument = toYaml(normalize(document));
18
+ c.header('Content-Type', 'text/yaml');
19
+ return c.text(yamlDocument, 200, {
20
+ 'Content-Type': 'application/yaml; charset=UTF-8',
21
+ });
22
+ }
23
+ catch (error) {
24
+ return c.json({
25
+ error: 'Failed to convert document to YAML',
26
+ message: error instanceof Error ? error.message : 'Unknown error occurred',
27
+ }, 500);
28
+ }
29
+ }
30
+ catch (error) {
31
+ return c.json({
32
+ error: 'Failed to parse OpenAPI document',
33
+ message: error instanceof Error ? error.message : 'Unknown error occurred',
34
+ }, 400);
25
35
  }
26
- } catch (error) {
27
- return c.json(
28
- {
29
- error: "Failed to parse OpenAPI document",
30
- message: error instanceof Error ? error.message : "Unknown error occurred"
31
- },
32
- 400
33
- );
34
- }
35
36
  }
36
- export {
37
- respondWithOpenApiDocument
38
- };
39
- //# sourceMappingURL=respond-with-openapi-document.js.map
@@ -1,46 +1,41 @@
1
- const EXAMPLE_ACCESS_TOKEN = "super-secret-access-token";
2
- function respondWithToken(c) {
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);
1
+ /** Always responds with this token */
2
+ const EXAMPLE_ACCESS_TOKEN = 'super-secret-access-token';
3
+ /**
4
+ * Responds with a JSON object simulating an OAuth 2.0 token response.
5
+ */
6
+ export function respondWithToken(c) {
7
+ const grantType = c.req.query('grant_type');
8
+ if (!grantType) {
9
+ return c.json({
10
+ error: 'invalid_request',
11
+ error_description: 'Missing grant_type parameter',
12
+ }, 400);
13
+ }
14
+ // Validate supported grant types
15
+ const supportedGrantTypes = ['authorization_code', 'client_credentials', 'refresh_token'];
16
+ if (!supportedGrantTypes.includes(grantType)) {
17
+ return c.json({
18
+ error: 'unsupported_grant_type',
19
+ error_description: `Grant type must be one of: ${supportedGrantTypes.join(', ')}`,
20
+ }, 400);
21
+ }
22
+ // Validate required parameters for each grant type
23
+ if (grantType === 'authorization_code' && !c.req.query('code')) {
24
+ return c.json({
25
+ error: 'invalid_request',
26
+ error_description: 'Missing code parameter',
27
+ }, 400);
28
+ }
29
+ // Simulate token generation
30
+ const tokenResponse = {
31
+ access_token: EXAMPLE_ACCESS_TOKEN,
32
+ token_type: 'Bearer',
33
+ expires_in: 3600,
34
+ refresh_token: 'example-refresh-token',
35
+ scope: c.req.query('scope') ?? 'read write',
36
+ };
37
+ // Security headers
38
+ c.header('Cache-Control', 'no-store');
39
+ c.header('Pragma', 'no-cache');
40
+ return c.json(tokenResponse);
42
41
  }
43
- export {
44
- respondWithToken
45
- };
46
- //# sourceMappingURL=respond-with-token.js.map
package/dist/types.js CHANGED
@@ -1,5 +1,2 @@
1
- const httpMethods = ["get", "put", "post", "delete", "options", "patch"];
2
- export {
3
- httpMethods
4
- };
5
- //# sourceMappingURL=types.js.map
1
+ /** Available HTTP methods for Hono routes */
2
+ export const httpMethods = ['get', 'put', 'post', 'delete', 'options', 'patch'];