@ucdjs-internal/worker-utils 0.0.1-beta.1
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/LICENSE +21 -0
- package/dist/index.d.mts +200 -0
- package/dist/index.mjs +297 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-PRESENT Lucas Nørgård
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { ApiError } from "@ucdjs/schemas";
|
|
2
|
+
import { Context } from "hono";
|
|
3
|
+
import { TypedResponse } from "hono/types";
|
|
4
|
+
import { ContentfulStatusCode } from "hono/utils/http-status";
|
|
5
|
+
import { ZodType, z } from "zod";
|
|
6
|
+
|
|
7
|
+
//#region src/cache.d.ts
|
|
8
|
+
type ClearCacheFn = (requestOrPath: Request | string) => Promise<void>;
|
|
9
|
+
declare function clearCacheEntry(name: string): Promise<ClearCacheFn>;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/environment.d.ts
|
|
12
|
+
type WorkerEnvironmentName = "production" | "preview" | "local" | "testing" | (string & {});
|
|
13
|
+
declare function getApiOriginForEnvironment(environment: WorkerEnvironmentName | undefined): string;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/errors.d.ts
|
|
16
|
+
interface ResponseOptions {
|
|
17
|
+
/**
|
|
18
|
+
* The message to include in the response.
|
|
19
|
+
*/
|
|
20
|
+
message?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Additional headers to include in the response.
|
|
23
|
+
* This can be used to set custom headers like `Content-Type`, `Cache-Control`,
|
|
24
|
+
* or any other headers that might be relevant to the response.
|
|
25
|
+
*/
|
|
26
|
+
headers?: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Creates a standardized 400 Bad Request HTTP response with JSON error details.
|
|
30
|
+
*
|
|
31
|
+
* @param {Context | ResponseOptions} contextOrOptions - Hono context or configuration options
|
|
32
|
+
* @param {ResponseOptions?} options - Configuration options when context is provided
|
|
33
|
+
* @returns {Response} A Response object with 400 status and JSON error body
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { badRequest } from "../../lib";
|
|
38
|
+
*
|
|
39
|
+
* // Basic usage (legacy)
|
|
40
|
+
* return badRequest();
|
|
41
|
+
*
|
|
42
|
+
* // With custom message
|
|
43
|
+
* return badRequest({
|
|
44
|
+
* message: "Invalid request parameters",
|
|
45
|
+
* });
|
|
46
|
+
*
|
|
47
|
+
* // With Hono context (new)
|
|
48
|
+
* return badRequest(c, { message: "Invalid request parameters" });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare function badRequest(contextOrOptions?: Context | ResponseOptions, options?: ResponseOptions): Response & TypedResponse<ApiError, 400, "json">;
|
|
52
|
+
/**
|
|
53
|
+
* Creates a standardized 403 Forbidden HTTP response with JSON error details.
|
|
54
|
+
*
|
|
55
|
+
* @param {Context | ResponseOptions} contextOrOptions - Hono context or configuration options
|
|
56
|
+
* @param {ResponseOptions?} options - Configuration options when context is provided
|
|
57
|
+
* @returns {Response} A Response object with 403 status and JSON error body
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* import { forbidden } from "../../lib";
|
|
62
|
+
*
|
|
63
|
+
* // Basic usage (legacy)
|
|
64
|
+
* return forbidden();
|
|
65
|
+
*
|
|
66
|
+
* // With custom message (legacy)
|
|
67
|
+
* return forbidden({
|
|
68
|
+
* message: "Access denied to this resource"
|
|
69
|
+
* });
|
|
70
|
+
*
|
|
71
|
+
* // With Hono context (new)
|
|
72
|
+
* return forbidden(c, { message: "Access denied to this resource" });
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare function forbidden(contextOrOptions?: Context | ResponseOptions, options?: ResponseOptions): Response & TypedResponse<ApiError, 403, "json">;
|
|
76
|
+
/**
|
|
77
|
+
* Creates a standardized 404 Not Found HTTP response with JSON error details.
|
|
78
|
+
*
|
|
79
|
+
* @param {Context | ResponseOptions} contextOrOptions - Hono context or configuration options
|
|
80
|
+
* @param {ResponseOptions?} options - Configuration options when context is provided
|
|
81
|
+
* @returns {Response} A Response object with 404 status and JSON error body
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* import { notFound } from "../../lib";
|
|
86
|
+
*
|
|
87
|
+
* // Basic usage (legacy)
|
|
88
|
+
* return notFound();
|
|
89
|
+
*
|
|
90
|
+
* // With custom message (legacy)
|
|
91
|
+
* return notFound({
|
|
92
|
+
* message: "User not found"
|
|
93
|
+
* });
|
|
94
|
+
*
|
|
95
|
+
* // With Hono context (new)
|
|
96
|
+
* return notFound(c, { message: "User not found" });
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
declare function notFound(contextOrOptions?: Context | ResponseOptions, options?: ResponseOptions): Response & TypedResponse<ApiError, 404, "json">;
|
|
100
|
+
/**
|
|
101
|
+
* Creates a standardized 500 Internal Server Error HTTP response with JSON error details.
|
|
102
|
+
*
|
|
103
|
+
* @param {Context | ResponseOptions} contextOrOptions - Hono context or configuration options
|
|
104
|
+
* @param {ResponseOptions?} options - Configuration options when context is provided
|
|
105
|
+
* @returns {Response} A Response object with 500 status and JSON error body
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* import { internalServerError } from "../../lib";
|
|
110
|
+
*
|
|
111
|
+
* // Basic usage (legacy)
|
|
112
|
+
* return internalServerError();
|
|
113
|
+
*
|
|
114
|
+
* // With custom message (legacy)
|
|
115
|
+
* return internalServerError({
|
|
116
|
+
* message: "Database connection failed"
|
|
117
|
+
* });
|
|
118
|
+
*
|
|
119
|
+
* // With Hono context (new)
|
|
120
|
+
* return internalServerError(c, { message: "Database connection failed" });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
declare function internalServerError(contextOrOptions?: Context | ResponseOptions, options?: ResponseOptions): Response & TypedResponse<ApiError, 500, "json">;
|
|
124
|
+
declare function badGateway(contextOrOptions?: Context | ResponseOptions, options?: ResponseOptions): Response & TypedResponse<ApiError, 502, "json">;
|
|
125
|
+
declare function unauthorized(contextOrOptions?: Context | ResponseOptions, options?: ResponseOptions): Response & TypedResponse<ApiError, 401, "json">;
|
|
126
|
+
type CustomResponseOptions = Omit<Required<ResponseOptions>, "headers"> & {
|
|
127
|
+
/**
|
|
128
|
+
* Custom headers to include in the response.
|
|
129
|
+
* This can be used to set headers like `Content-Type`, `Cache-Control`, etc.
|
|
130
|
+
*/
|
|
131
|
+
headers?: Record<string, string>;
|
|
132
|
+
/**
|
|
133
|
+
* The HTTP status code to use for the response.
|
|
134
|
+
* This should be a valid @see {ContentfulStatusCode}.
|
|
135
|
+
*/
|
|
136
|
+
status: number;
|
|
137
|
+
};
|
|
138
|
+
type CustomResponseOptionsWithContext = CustomResponseOptions & {
|
|
139
|
+
/**
|
|
140
|
+
* Custom headers to include in the response.
|
|
141
|
+
* This can be used to set headers like `Content-Type`, `Cache-Control`, etc.
|
|
142
|
+
*/
|
|
143
|
+
headers?: Record<string, string>;
|
|
144
|
+
/**
|
|
145
|
+
* The HTTP status code to use for the response.
|
|
146
|
+
* This should be a valid @see {ContentfulStatusCode}.
|
|
147
|
+
*/
|
|
148
|
+
status: number;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Creates a custom HTTP error response with specified status code and JSON error details.
|
|
152
|
+
* This function allows for flexible error responses with any valid HTTP status code.
|
|
153
|
+
*
|
|
154
|
+
* @param {Context | CustomResponseOptions} contextOrOptions - Hono context or configuration options
|
|
155
|
+
* @param {CustomResponseOptionsWithContext?} options - Configuration options when context is provided
|
|
156
|
+
* @returns {Response} A Response object with the specified status and JSON error body
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* import { customError } from "../../lib";
|
|
161
|
+
*
|
|
162
|
+
* // Custom 422 Unprocessable Entity error (legacy)
|
|
163
|
+
* return customError({
|
|
164
|
+
* status: 422,
|
|
165
|
+
* message: "Validation failed",
|
|
166
|
+
* });
|
|
167
|
+
*
|
|
168
|
+
* // Custom 429 Too Many Requests error with headers (legacy)
|
|
169
|
+
* return customError({
|
|
170
|
+
* status: 429,
|
|
171
|
+
* message: "Rate limit exceeded",
|
|
172
|
+
* headers: {
|
|
173
|
+
* "Retry-After": "3600"
|
|
174
|
+
* }
|
|
175
|
+
* });
|
|
176
|
+
*
|
|
177
|
+
* // With Hono context (new)
|
|
178
|
+
* return customError(c, {
|
|
179
|
+
* status: 422,
|
|
180
|
+
* message: "Validation failed"
|
|
181
|
+
* });
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
declare function customError(contextOrOptions: Context | CustomResponseOptions, options?: CustomResponseOptionsWithContext): Response;
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/hostnames.d.ts
|
|
187
|
+
declare function isStoreSubdomainHostname(hostname: string): boolean;
|
|
188
|
+
//#endregion
|
|
189
|
+
//#region src/strict.d.ts
|
|
190
|
+
declare function strictJSONResponse<C extends Context, S extends ZodType, D extends Parameters<Context["json"]>[0] & z.infer<S>, U extends ContentfulStatusCode>(c: C, schema: S, data: D, statusCode?: U): Response;
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region src/tasks.d.ts
|
|
193
|
+
declare const MAX_TAR_SIZE_BYTES: number;
|
|
194
|
+
declare const MAX_WORKFLOW_INSTANCE_ID_LENGTH = 100;
|
|
195
|
+
declare const ALLOWED_STRING_ID_PATTERN = "^\\w[\\w-]*$";
|
|
196
|
+
declare function makeManifestUploadId(version: string, now?: () => number): string;
|
|
197
|
+
declare function isValidWorkflowInstanceId(id: string): boolean;
|
|
198
|
+
declare function buildR2Key(version: string, workflowId: string): string;
|
|
199
|
+
//#endregion
|
|
200
|
+
export { ALLOWED_STRING_ID_PATTERN, ClearCacheFn, CustomResponseOptions, CustomResponseOptionsWithContext, MAX_TAR_SIZE_BYTES, MAX_WORKFLOW_INSTANCE_ID_LENGTH, ResponseOptions, WorkerEnvironmentName, badGateway, badRequest, buildR2Key, clearCacheEntry, customError, forbidden, getApiOriginForEnvironment, internalServerError, isStoreSubdomainHostname, isValidWorkflowInstanceId, makeManifestUploadId, notFound, strictJSONResponse, unauthorized };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
//#region src/cache.ts
|
|
2
|
+
async function clearCacheEntry(name) {
|
|
3
|
+
let cachePromise = null;
|
|
4
|
+
return async (requestOrPath) => {
|
|
5
|
+
if (!cachePromise) cachePromise = caches.open(name);
|
|
6
|
+
const cache = await cachePromise;
|
|
7
|
+
const request = typeof requestOrPath === "string" ? new Request(requestOrPath) : requestOrPath;
|
|
8
|
+
await cache.delete(request);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/environment.ts
|
|
14
|
+
function getApiOriginForEnvironment(environment) {
|
|
15
|
+
if (environment === "production") return "https://api.ucdjs.dev";
|
|
16
|
+
if (environment === "preview") return "https://preview.api.ucdjs.dev";
|
|
17
|
+
return "http://localhost:8787";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/errors.ts
|
|
22
|
+
/**
|
|
23
|
+
* Creates a standardized 400 Bad Request HTTP response with JSON error details.
|
|
24
|
+
*
|
|
25
|
+
* @param {Context | ResponseOptions} contextOrOptions - Hono context or configuration options
|
|
26
|
+
* @param {ResponseOptions?} options - Configuration options when context is provided
|
|
27
|
+
* @returns {Response} A Response object with 400 status and JSON error body
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { badRequest } from "../../lib";
|
|
32
|
+
*
|
|
33
|
+
* // Basic usage (legacy)
|
|
34
|
+
* return badRequest();
|
|
35
|
+
*
|
|
36
|
+
* // With custom message
|
|
37
|
+
* return badRequest({
|
|
38
|
+
* message: "Invalid request parameters",
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* // With Hono context (new)
|
|
42
|
+
* return badRequest(c, { message: "Invalid request parameters" });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
function badRequest(contextOrOptions = {}, options = {}) {
|
|
46
|
+
let finalOptions;
|
|
47
|
+
if ("req" in contextOrOptions) finalOptions = options;
|
|
48
|
+
else finalOptions = contextOrOptions;
|
|
49
|
+
return Response.json({
|
|
50
|
+
message: finalOptions.message || "Bad Request",
|
|
51
|
+
status: 400,
|
|
52
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
53
|
+
}, {
|
|
54
|
+
status: 400,
|
|
55
|
+
headers: {
|
|
56
|
+
"Content-Type": "application/json",
|
|
57
|
+
...finalOptions.headers
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Creates a standardized 403 Forbidden HTTP response with JSON error details.
|
|
63
|
+
*
|
|
64
|
+
* @param {Context | ResponseOptions} contextOrOptions - Hono context or configuration options
|
|
65
|
+
* @param {ResponseOptions?} options - Configuration options when context is provided
|
|
66
|
+
* @returns {Response} A Response object with 403 status and JSON error body
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* import { forbidden } from "../../lib";
|
|
71
|
+
*
|
|
72
|
+
* // Basic usage (legacy)
|
|
73
|
+
* return forbidden();
|
|
74
|
+
*
|
|
75
|
+
* // With custom message (legacy)
|
|
76
|
+
* return forbidden({
|
|
77
|
+
* message: "Access denied to this resource"
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* // With Hono context (new)
|
|
81
|
+
* return forbidden(c, { message: "Access denied to this resource" });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
function forbidden(contextOrOptions = {}, options = {}) {
|
|
85
|
+
let finalOptions;
|
|
86
|
+
if ("req" in contextOrOptions) finalOptions = options;
|
|
87
|
+
else finalOptions = contextOrOptions;
|
|
88
|
+
return Response.json({
|
|
89
|
+
message: finalOptions.message || "Forbidden",
|
|
90
|
+
status: 403,
|
|
91
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
92
|
+
}, {
|
|
93
|
+
status: 403,
|
|
94
|
+
headers: {
|
|
95
|
+
"Content-Type": "application/json",
|
|
96
|
+
...finalOptions.headers
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Creates a standardized 404 Not Found HTTP response with JSON error details.
|
|
102
|
+
*
|
|
103
|
+
* @param {Context | ResponseOptions} contextOrOptions - Hono context or configuration options
|
|
104
|
+
* @param {ResponseOptions?} options - Configuration options when context is provided
|
|
105
|
+
* @returns {Response} A Response object with 404 status and JSON error body
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* import { notFound } from "../../lib";
|
|
110
|
+
*
|
|
111
|
+
* // Basic usage (legacy)
|
|
112
|
+
* return notFound();
|
|
113
|
+
*
|
|
114
|
+
* // With custom message (legacy)
|
|
115
|
+
* return notFound({
|
|
116
|
+
* message: "User not found"
|
|
117
|
+
* });
|
|
118
|
+
*
|
|
119
|
+
* // With Hono context (new)
|
|
120
|
+
* return notFound(c, { message: "User not found" });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
function notFound(contextOrOptions = {}, options = {}) {
|
|
124
|
+
let finalOptions;
|
|
125
|
+
if ("req" in contextOrOptions) finalOptions = options;
|
|
126
|
+
else finalOptions = contextOrOptions;
|
|
127
|
+
return Response.json({
|
|
128
|
+
message: finalOptions.message || "Not Found",
|
|
129
|
+
status: 404,
|
|
130
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
131
|
+
}, {
|
|
132
|
+
status: 404,
|
|
133
|
+
headers: {
|
|
134
|
+
"Content-Type": "application/json",
|
|
135
|
+
...finalOptions.headers
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Creates a standardized 500 Internal Server Error HTTP response with JSON error details.
|
|
141
|
+
*
|
|
142
|
+
* @param {Context | ResponseOptions} contextOrOptions - Hono context or configuration options
|
|
143
|
+
* @param {ResponseOptions?} options - Configuration options when context is provided
|
|
144
|
+
* @returns {Response} A Response object with 500 status and JSON error body
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* import { internalServerError } from "../../lib";
|
|
149
|
+
*
|
|
150
|
+
* // Basic usage (legacy)
|
|
151
|
+
* return internalServerError();
|
|
152
|
+
*
|
|
153
|
+
* // With custom message (legacy)
|
|
154
|
+
* return internalServerError({
|
|
155
|
+
* message: "Database connection failed"
|
|
156
|
+
* });
|
|
157
|
+
*
|
|
158
|
+
* // With Hono context (new)
|
|
159
|
+
* return internalServerError(c, { message: "Database connection failed" });
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
function internalServerError(contextOrOptions = {}, options = {}) {
|
|
163
|
+
let finalOptions;
|
|
164
|
+
if ("req" in contextOrOptions) finalOptions = options;
|
|
165
|
+
else finalOptions = contextOrOptions;
|
|
166
|
+
return Response.json({
|
|
167
|
+
message: finalOptions.message || "Internal Server Error",
|
|
168
|
+
status: 500,
|
|
169
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
170
|
+
}, {
|
|
171
|
+
status: 500,
|
|
172
|
+
headers: {
|
|
173
|
+
"Content-Type": "application/json",
|
|
174
|
+
...finalOptions.headers
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function badGateway(contextOrOptions = {}, options = {}) {
|
|
179
|
+
let finalOptions;
|
|
180
|
+
if ("req" in contextOrOptions) finalOptions = options;
|
|
181
|
+
else finalOptions = contextOrOptions;
|
|
182
|
+
return Response.json({
|
|
183
|
+
message: finalOptions.message || "Bad Gateway",
|
|
184
|
+
status: 502,
|
|
185
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
186
|
+
}, {
|
|
187
|
+
status: 502,
|
|
188
|
+
headers: {
|
|
189
|
+
"Content-Type": "application/json",
|
|
190
|
+
...finalOptions.headers
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function unauthorized(contextOrOptions = {}, options = {}) {
|
|
195
|
+
let finalOptions;
|
|
196
|
+
if ("req" in contextOrOptions) finalOptions = options;
|
|
197
|
+
else finalOptions = contextOrOptions;
|
|
198
|
+
return Response.json({
|
|
199
|
+
message: finalOptions.message || "Unauthorized",
|
|
200
|
+
status: 401,
|
|
201
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
202
|
+
}, {
|
|
203
|
+
status: 401,
|
|
204
|
+
headers: {
|
|
205
|
+
"Content-Type": "application/json",
|
|
206
|
+
...finalOptions.headers
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Creates a custom HTTP error response with specified status code and JSON error details.
|
|
212
|
+
* This function allows for flexible error responses with any valid HTTP status code.
|
|
213
|
+
*
|
|
214
|
+
* @param {Context | CustomResponseOptions} contextOrOptions - Hono context or configuration options
|
|
215
|
+
* @param {CustomResponseOptionsWithContext?} options - Configuration options when context is provided
|
|
216
|
+
* @returns {Response} A Response object with the specified status and JSON error body
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* import { customError } from "../../lib";
|
|
221
|
+
*
|
|
222
|
+
* // Custom 422 Unprocessable Entity error (legacy)
|
|
223
|
+
* return customError({
|
|
224
|
+
* status: 422,
|
|
225
|
+
* message: "Validation failed",
|
|
226
|
+
* });
|
|
227
|
+
*
|
|
228
|
+
* // Custom 429 Too Many Requests error with headers (legacy)
|
|
229
|
+
* return customError({
|
|
230
|
+
* status: 429,
|
|
231
|
+
* message: "Rate limit exceeded",
|
|
232
|
+
* headers: {
|
|
233
|
+
* "Retry-After": "3600"
|
|
234
|
+
* }
|
|
235
|
+
* });
|
|
236
|
+
*
|
|
237
|
+
* // With Hono context (new)
|
|
238
|
+
* return customError(c, {
|
|
239
|
+
* status: 422,
|
|
240
|
+
* message: "Validation failed"
|
|
241
|
+
* });
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
function customError(contextOrOptions, options) {
|
|
245
|
+
let finalOptions;
|
|
246
|
+
if ("req" in contextOrOptions) {
|
|
247
|
+
if (!options) throw new Error("Options parameter is required when using Hono context");
|
|
248
|
+
finalOptions = options;
|
|
249
|
+
} else finalOptions = contextOrOptions;
|
|
250
|
+
return Response.json({
|
|
251
|
+
message: finalOptions.message,
|
|
252
|
+
status: finalOptions.status,
|
|
253
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
254
|
+
}, {
|
|
255
|
+
status: finalOptions.status,
|
|
256
|
+
headers: {
|
|
257
|
+
"Content-Type": "application/json",
|
|
258
|
+
...finalOptions.headers
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region src/hostnames.ts
|
|
265
|
+
function isStoreSubdomainHostname(hostname) {
|
|
266
|
+
return hostname === "ucd-store.ucdjs.dev" || hostname === "preview.ucd-store.ucdjs.dev" || hostname === "ucd-store.localhost";
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
//#endregion
|
|
270
|
+
//#region src/strict.ts
|
|
271
|
+
function strictJSONResponse(c, schema, data, statusCode) {
|
|
272
|
+
const validatedResponse = schema.safeParse(data);
|
|
273
|
+
if (!validatedResponse.success) return customError({
|
|
274
|
+
status: 400,
|
|
275
|
+
message: `Invalid response data: ${validatedResponse.error.message}`
|
|
276
|
+
});
|
|
277
|
+
return c.json(validatedResponse.data, statusCode);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/tasks.ts
|
|
282
|
+
const MAX_TAR_SIZE_BYTES = 10 * 1024 * 1024;
|
|
283
|
+
const MAX_WORKFLOW_INSTANCE_ID_LENGTH = 100;
|
|
284
|
+
const ALLOWED_STRING_ID_PATTERN = "^\\w[\\w-]*$";
|
|
285
|
+
const ALLOWED_WORKFLOW_INSTANCE_ID_REGEX = new RegExp(ALLOWED_STRING_ID_PATTERN);
|
|
286
|
+
function makeManifestUploadId(version, now = Date.now) {
|
|
287
|
+
return `manifest-upload-${version.replace(/\./g, "-")}-${now()}`;
|
|
288
|
+
}
|
|
289
|
+
function isValidWorkflowInstanceId(id) {
|
|
290
|
+
return id.length <= MAX_WORKFLOW_INSTANCE_ID_LENGTH && ALLOWED_WORKFLOW_INSTANCE_ID_REGEX.test(id);
|
|
291
|
+
}
|
|
292
|
+
function buildR2Key(version, workflowId) {
|
|
293
|
+
return `manifest-tars/${version}/${workflowId}.tar`;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
//#endregion
|
|
297
|
+
export { ALLOWED_STRING_ID_PATTERN, MAX_TAR_SIZE_BYTES, MAX_WORKFLOW_INSTANCE_ID_LENGTH, badGateway, badRequest, buildR2Key, clearCacheEntry, customError, forbidden, getApiOriginForEnvironment, internalServerError, isStoreSubdomainHostname, isValidWorkflowInstanceId, makeManifestUploadId, notFound, strictJSONResponse, unauthorized };
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ucdjs-internal/worker-utils",
|
|
3
|
+
"version": "0.0.1-beta.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Lucas Nørgård",
|
|
7
|
+
"email": "lucasnrgaard@gmail.com",
|
|
8
|
+
"url": "https://luxass.dev"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"homepage": "https://github.com/ucdjs/ucd",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/ucdjs/ucd.git",
|
|
15
|
+
"directory": "packages/worker-utils"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/ucdjs/ucd/issues"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": "./dist/index.mjs",
|
|
22
|
+
"./package.json": "./package.json"
|
|
23
|
+
},
|
|
24
|
+
"types": "./dist/index.d.mts",
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=22.18"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"hono": "4.11.9",
|
|
33
|
+
"zod": "4.3.6"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@ucdjs-internal/shared": "0.1.1-beta.1",
|
|
37
|
+
"@ucdjs/schemas": "0.1.1-beta.1"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@luxass/eslint-config": "7.2.0",
|
|
41
|
+
"eslint": "10.0.0",
|
|
42
|
+
"hono": "4.11.9",
|
|
43
|
+
"publint": "0.3.17",
|
|
44
|
+
"tsdown": "0.20.3",
|
|
45
|
+
"typescript": "5.9.3",
|
|
46
|
+
"vitest-testdirs": "4.4.2",
|
|
47
|
+
"zod": "4.3.6",
|
|
48
|
+
"@ucdjs-tooling/tsdown-config": "1.0.0",
|
|
49
|
+
"@ucdjs-tooling/tsconfig": "1.0.0"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsdown --tsconfig=./tsconfig.build.json",
|
|
56
|
+
"dev": "tsdown --watch",
|
|
57
|
+
"clean": "git clean -xdf dist node_modules",
|
|
58
|
+
"lint": "eslint .",
|
|
59
|
+
"typecheck": "tsc --noEmit -p tsconfig.build.json"
|
|
60
|
+
}
|
|
61
|
+
}
|