@hadoku/worker-utils 0.0.0-stage → 1.6.19
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 +15 -0
- package/README.md +334 -2
- package/dist/auth.d.ts +153 -0
- package/dist/auth.js +39 -0
- package/dist/authPage.d.ts +113 -0
- package/dist/authPage.js +833 -0
- package/dist/cloudflareWorkerLogger.d.ts +71 -0
- package/dist/cloudflareWorkerLogger.js +94 -0
- package/dist/content-level.d.ts +52 -0
- package/dist/content-level.js +28 -0
- package/dist/context.d.ts +110 -0
- package/dist/context.js +75 -0
- package/dist/cors.d.ts +123 -0
- package/dist/cors.js +113 -0
- package/dist/edge-routes.d.ts +47 -0
- package/dist/edge-routes.js +34 -0
- package/dist/identity.d.ts +477 -0
- package/dist/identity.js +239 -0
- package/dist/index.d.ts +108 -0
- package/dist/index.js +976 -0
- package/dist/masking.d.ts +108 -0
- package/dist/masking.js +90 -0
- package/dist/openapi-config.d.ts +252 -0
- package/dist/openapi-config.js +131 -0
- package/dist/openapi-schemas.d.ts +157 -0
- package/dist/openapi-schemas.js +79 -0
- package/dist/rate-limit.d.ts +39 -0
- package/dist/rate-limit.js +59 -0
- package/dist/responses.d.ts +159 -0
- package/dist/responses.js +80 -0
- package/dist/types.d.ts +166 -0
- package/dist/types.js +0 -0
- package/dist/validation.d.ts +88 -0
- package/dist/validation.js +172 -0
- package/package.json +34 -4
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Context } from 'hono';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared types for worker utilities
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
type UserType = string;
|
|
8
|
+
interface AuthContext {
|
|
9
|
+
userType: UserType;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
interface AuthConfig<TEnv = any> {
|
|
13
|
+
/**
|
|
14
|
+
* Sources to check for authentication credentials (in order of priority)
|
|
15
|
+
* @example ['header:X-User-Key', 'query:key', 'cookie:auth_token']
|
|
16
|
+
*/
|
|
17
|
+
sources: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Function to resolve userType from the extracted credential
|
|
20
|
+
* @param credential - The extracted auth credential
|
|
21
|
+
* @param env - The worker environment bindings
|
|
22
|
+
* @returns UserType or AuthContext object
|
|
23
|
+
*/
|
|
24
|
+
resolver: (credential: string | undefined, env: TEnv) => UserType | AuthContext;
|
|
25
|
+
/**
|
|
26
|
+
* Variable name to store auth context in Hono context
|
|
27
|
+
* @default 'authContext'
|
|
28
|
+
*/
|
|
29
|
+
contextKey?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Additional fields to add to auth context
|
|
32
|
+
*/
|
|
33
|
+
additionalFields?: (c: Context, env: TEnv) => Record<string, any>;
|
|
34
|
+
}
|
|
35
|
+
interface ContextExtractionConfig {
|
|
36
|
+
/**
|
|
37
|
+
* Mappings of context field name to sources
|
|
38
|
+
* @example { userId: ['header:X-User-Id', 'query:userId'], sessionId: ['header:X-Session-Id'] }
|
|
39
|
+
*/
|
|
40
|
+
fields: Record<string, string[]>;
|
|
41
|
+
/**
|
|
42
|
+
* Default values for fields if not found
|
|
43
|
+
* @example { userId: 'anonymous', boardId: 'main' }
|
|
44
|
+
*/
|
|
45
|
+
defaults?: Record<string, any>;
|
|
46
|
+
/**
|
|
47
|
+
* Transform functions for extracted values
|
|
48
|
+
* @example { userId: (val) => val?.toLowerCase() }
|
|
49
|
+
*/
|
|
50
|
+
transforms?: Record<string, (value: string) => any>;
|
|
51
|
+
}
|
|
52
|
+
interface ValidationRule {
|
|
53
|
+
field: string;
|
|
54
|
+
required?: boolean;
|
|
55
|
+
type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
56
|
+
minLength?: number;
|
|
57
|
+
maxLength?: number;
|
|
58
|
+
pattern?: RegExp;
|
|
59
|
+
custom?: (value: unknown) => boolean | string;
|
|
60
|
+
}
|
|
61
|
+
interface ValidationResult {
|
|
62
|
+
valid: boolean;
|
|
63
|
+
errors: {
|
|
64
|
+
field: string;
|
|
65
|
+
message: string;
|
|
66
|
+
}[];
|
|
67
|
+
}
|
|
68
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
69
|
+
interface LogEntry {
|
|
70
|
+
timestamp: string;
|
|
71
|
+
level: LogLevel;
|
|
72
|
+
message: string;
|
|
73
|
+
context?: Record<string, any>;
|
|
74
|
+
}
|
|
75
|
+
interface LoggerConfig {
|
|
76
|
+
/**
|
|
77
|
+
* Minimum log level to output
|
|
78
|
+
* @default 'info'
|
|
79
|
+
*/
|
|
80
|
+
minLevel?: LogLevel;
|
|
81
|
+
/**
|
|
82
|
+
* Include timestamp in logs
|
|
83
|
+
* @default true
|
|
84
|
+
*/
|
|
85
|
+
includeTimestamp?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Prefix for all log messages
|
|
88
|
+
* @example '[task-api]'
|
|
89
|
+
*/
|
|
90
|
+
prefix?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Custom formatter for log output
|
|
93
|
+
*/
|
|
94
|
+
formatter?: (entry: LogEntry) => string;
|
|
95
|
+
}
|
|
96
|
+
interface ErrorResponse {
|
|
97
|
+
error: string;
|
|
98
|
+
details?: unknown;
|
|
99
|
+
timestamp?: string;
|
|
100
|
+
}
|
|
101
|
+
interface SuccessResponse<T = any> {
|
|
102
|
+
data: T;
|
|
103
|
+
message?: string;
|
|
104
|
+
timestamp?: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The canonical health status — the SINGLE source of truth for the health
|
|
108
|
+
* contract. Both the runtime helper `healthCheck()` (responses.ts) and the
|
|
109
|
+
* OpenAPI schema `createHealthResponseSchema()` (openapi-schemas.ts) reference
|
|
110
|
+
* this type, so the two can no longer drift apart (they used to: the schema
|
|
111
|
+
* declared `status: 'healthy'` + a numeric timestamp that healthCheck never
|
|
112
|
+
* emitted). openapi-schemas.ts guards its `z.enum([...])` against this type
|
|
113
|
+
* with `satisfies`, so a rename/removal here fails that build.
|
|
114
|
+
*/
|
|
115
|
+
type HealthStatus = 'ok' | 'degraded' | 'error';
|
|
116
|
+
interface HealthCheckResponse {
|
|
117
|
+
status: HealthStatus;
|
|
118
|
+
service: string;
|
|
119
|
+
timestamp: string;
|
|
120
|
+
version?: string;
|
|
121
|
+
checks?: Record<string, boolean | string>;
|
|
122
|
+
/**
|
|
123
|
+
* What an operator should DO about a non-ok status, ideally the literal
|
|
124
|
+
* command to run. Surfaced verbatim into the Discord alert by
|
|
125
|
+
* monitoring-api's worker-health alerter, so "edge_auth: missing" at 2am
|
|
126
|
+
* does not mean rediscovering the fix.
|
|
127
|
+
*/
|
|
128
|
+
remediation?: string;
|
|
129
|
+
/**
|
|
130
|
+
* Slow-moving numbers worth watching but not worth alerting on — storage
|
|
131
|
+
* consumed, row counts, percentage of a quota. Reported, never used to
|
|
132
|
+
* derive `status`.
|
|
133
|
+
*/
|
|
134
|
+
gauges?: Record<string, number | null>;
|
|
135
|
+
}
|
|
136
|
+
interface CORSConfig {
|
|
137
|
+
/**
|
|
138
|
+
* Allowed origins (supports wildcards like 'http://localhost:*')
|
|
139
|
+
*/
|
|
140
|
+
origins: string[];
|
|
141
|
+
/**
|
|
142
|
+
* Allowed HTTP methods
|
|
143
|
+
* @default ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']
|
|
144
|
+
*/
|
|
145
|
+
methods?: string[];
|
|
146
|
+
/**
|
|
147
|
+
* Allowed headers
|
|
148
|
+
*/
|
|
149
|
+
allowedHeaders?: string[];
|
|
150
|
+
/**
|
|
151
|
+
* Exposed headers
|
|
152
|
+
*/
|
|
153
|
+
exposedHeaders?: string[];
|
|
154
|
+
/**
|
|
155
|
+
* Allow credentials
|
|
156
|
+
* @default true
|
|
157
|
+
*/
|
|
158
|
+
credentials?: boolean;
|
|
159
|
+
/**
|
|
160
|
+
* Max age for preflight cache
|
|
161
|
+
* @default 86400 (24 hours)
|
|
162
|
+
*/
|
|
163
|
+
maxAge?: number;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export type { AuthConfig, AuthContext, CORSConfig, ContextExtractionConfig, ErrorResponse, HealthCheckResponse, HealthStatus, LogEntry, LogLevel, LoggerConfig, SuccessResponse, UserType, ValidationResult, ValidationRule };
|
package/dist/types.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ValidationRule, ValidationResult } from './types.js';
|
|
2
|
+
import 'hono';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Validate multiple fields against rules
|
|
6
|
+
*
|
|
7
|
+
* @param data - Data object to validate
|
|
8
|
+
* @param rules - Array of validation rules
|
|
9
|
+
* @returns Validation result with errors
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const result = validateFields(requestBody, [
|
|
14
|
+
* { field: 'id', required: true },
|
|
15
|
+
* { field: 'title', required: true, minLength: 1 },
|
|
16
|
+
* { field: 'tags', type: 'array' }
|
|
17
|
+
* ]);
|
|
18
|
+
*
|
|
19
|
+
* if (!result.valid) {
|
|
20
|
+
* console.log(result.errors);
|
|
21
|
+
* // [{ field: 'title', message: 'title must be at least 1 characters' }]
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare function validateFields(data: Record<string, any>, rules: ValidationRule[]): ValidationResult;
|
|
26
|
+
/**
|
|
27
|
+
* Returns the name of the first missing or empty-string field, or null.
|
|
28
|
+
*
|
|
29
|
+
* Re-added to worker-utils 1.2.1 (matches the original 1.0.0 signature).
|
|
30
|
+
* Removed in 15c3376 cleanup but @wolffm/task still imports it.
|
|
31
|
+
*/
|
|
32
|
+
declare function requireFields(data: Record<string, any>, fields: string[]): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Re-added in 1.2.1. Same surface @wolffm/task imports for ID validation.
|
|
35
|
+
*/
|
|
36
|
+
declare function isNonEmptyString(value: unknown): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Common validation rules
|
|
39
|
+
*/
|
|
40
|
+
declare const CommonRules: {
|
|
41
|
+
/**
|
|
42
|
+
* ID field (required, non-empty string)
|
|
43
|
+
*/
|
|
44
|
+
id: () => ValidationRule;
|
|
45
|
+
/**
|
|
46
|
+
* Title field (required, 1-500 characters)
|
|
47
|
+
*/
|
|
48
|
+
title: (options?: {
|
|
49
|
+
minLength?: number;
|
|
50
|
+
maxLength?: number;
|
|
51
|
+
}) => ValidationRule;
|
|
52
|
+
/**
|
|
53
|
+
* Email field
|
|
54
|
+
*/
|
|
55
|
+
email: (required?: boolean) => ValidationRule;
|
|
56
|
+
/**
|
|
57
|
+
* URL field
|
|
58
|
+
*/
|
|
59
|
+
url: (required?: boolean) => ValidationRule;
|
|
60
|
+
/**
|
|
61
|
+
* Enum field (value must be in allowed list)
|
|
62
|
+
*/
|
|
63
|
+
enum: (field: string, allowedValues: unknown[], required?: boolean) => ValidationRule;
|
|
64
|
+
/**
|
|
65
|
+
* Array field with optional element validation
|
|
66
|
+
*/
|
|
67
|
+
array: (field: string, options?: {
|
|
68
|
+
required?: boolean;
|
|
69
|
+
minLength?: number;
|
|
70
|
+
maxLength?: number;
|
|
71
|
+
elementType?: "string" | "number" | "boolean" | "object";
|
|
72
|
+
}) => ValidationRule;
|
|
73
|
+
/**
|
|
74
|
+
* Number field with optional range validation
|
|
75
|
+
*/
|
|
76
|
+
number: (field: string, options?: {
|
|
77
|
+
required?: boolean;
|
|
78
|
+
min?: number;
|
|
79
|
+
max?: number;
|
|
80
|
+
integer?: boolean;
|
|
81
|
+
}) => ValidationRule;
|
|
82
|
+
/**
|
|
83
|
+
* Boolean field
|
|
84
|
+
*/
|
|
85
|
+
boolean: (field: string, required?: boolean) => ValidationRule;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export { CommonRules, isNonEmptyString, requireFields, validateFields };
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// validation.ts
|
|
2
|
+
function validateField(value, rule) {
|
|
3
|
+
if (rule.required && (value === void 0 || value === null || value === "")) {
|
|
4
|
+
return `${rule.field} is required`;
|
|
5
|
+
}
|
|
6
|
+
if (value === void 0 || value === null) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
if (rule.type) {
|
|
10
|
+
const actualType = Array.isArray(value) ? "array" : typeof value;
|
|
11
|
+
if (actualType !== rule.type) {
|
|
12
|
+
return `${rule.field} must be of type ${rule.type}`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (typeof value === "string") {
|
|
16
|
+
if (rule.minLength !== void 0 && value.length < rule.minLength) {
|
|
17
|
+
return `${rule.field} must be at least ${rule.minLength} characters`;
|
|
18
|
+
}
|
|
19
|
+
if (rule.maxLength !== void 0 && value.length > rule.maxLength) {
|
|
20
|
+
return `${rule.field} must be at most ${rule.maxLength} characters`;
|
|
21
|
+
}
|
|
22
|
+
if (rule.pattern && !rule.pattern.test(value)) {
|
|
23
|
+
return `${rule.field} format is invalid`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (rule.custom) {
|
|
27
|
+
const result = rule.custom(value);
|
|
28
|
+
if (result !== true && typeof result === "string") {
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
if (result === false) {
|
|
32
|
+
return `${rule.field} is invalid`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
function validateFields(data, rules) {
|
|
38
|
+
const errors = [];
|
|
39
|
+
for (const rule of rules) {
|
|
40
|
+
const value = data[rule.field];
|
|
41
|
+
const error = validateField(value, rule);
|
|
42
|
+
if (error) {
|
|
43
|
+
errors.push({ field: rule.field, message: error });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
valid: errors.length === 0,
|
|
48
|
+
errors
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function requireFields(data, fields) {
|
|
52
|
+
for (const field of fields) {
|
|
53
|
+
const value = data[field];
|
|
54
|
+
if (value === void 0 || value === null || typeof value === "string" && value.trim() === "") {
|
|
55
|
+
return `Missing required field: ${field}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
function isNonEmptyString(value) {
|
|
61
|
+
return typeof value === "string" && value.trim() !== "";
|
|
62
|
+
}
|
|
63
|
+
var CommonRules = {
|
|
64
|
+
/**
|
|
65
|
+
* ID field (required, non-empty string)
|
|
66
|
+
*/
|
|
67
|
+
id: () => ({
|
|
68
|
+
field: "id",
|
|
69
|
+
required: true,
|
|
70
|
+
type: "string",
|
|
71
|
+
custom: (val) => typeof val === "string" && val.trim() !== "" || "ID cannot be empty"
|
|
72
|
+
}),
|
|
73
|
+
/**
|
|
74
|
+
* Title field (required, 1-500 characters)
|
|
75
|
+
*/
|
|
76
|
+
title: (options = {}) => ({
|
|
77
|
+
field: "title",
|
|
78
|
+
required: true,
|
|
79
|
+
type: "string",
|
|
80
|
+
minLength: options.minLength ?? 1,
|
|
81
|
+
maxLength: options.maxLength ?? 500,
|
|
82
|
+
custom: (val) => typeof val === "string" && val.trim() !== "" || "Title cannot be empty"
|
|
83
|
+
}),
|
|
84
|
+
/**
|
|
85
|
+
* Email field
|
|
86
|
+
*/
|
|
87
|
+
email: (required = false) => ({
|
|
88
|
+
field: "email",
|
|
89
|
+
required,
|
|
90
|
+
type: "string",
|
|
91
|
+
pattern: /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/
|
|
92
|
+
}),
|
|
93
|
+
/**
|
|
94
|
+
* URL field
|
|
95
|
+
*/
|
|
96
|
+
url: (required = false) => ({
|
|
97
|
+
field: "url",
|
|
98
|
+
required,
|
|
99
|
+
type: "string",
|
|
100
|
+
pattern: /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)$/
|
|
101
|
+
}),
|
|
102
|
+
/**
|
|
103
|
+
* Enum field (value must be in allowed list)
|
|
104
|
+
*/
|
|
105
|
+
enum: (field, allowedValues, required = false) => ({
|
|
106
|
+
field,
|
|
107
|
+
required,
|
|
108
|
+
custom: (val) => allowedValues.includes(val) || `${field} must be one of: ${allowedValues.join(", ")}`
|
|
109
|
+
}),
|
|
110
|
+
/**
|
|
111
|
+
* Array field with optional element validation
|
|
112
|
+
*/
|
|
113
|
+
array: (field, options = {}) => ({
|
|
114
|
+
field,
|
|
115
|
+
required: options.required,
|
|
116
|
+
type: "array",
|
|
117
|
+
custom: (val) => {
|
|
118
|
+
if (!Array.isArray(val)) return false;
|
|
119
|
+
if (options.minLength !== void 0 && val.length < options.minLength) {
|
|
120
|
+
return `${field} must have at least ${options.minLength} items`;
|
|
121
|
+
}
|
|
122
|
+
if (options.maxLength !== void 0 && val.length > options.maxLength) {
|
|
123
|
+
return `${field} must have at most ${options.maxLength} items`;
|
|
124
|
+
}
|
|
125
|
+
if (options.elementType) {
|
|
126
|
+
const invalidItem = val.find((item) => {
|
|
127
|
+
const actualType = Array.isArray(item) ? "array" : typeof item;
|
|
128
|
+
return actualType !== options.elementType;
|
|
129
|
+
});
|
|
130
|
+
if (invalidItem !== void 0) {
|
|
131
|
+
return `All ${field} items must be of type ${options.elementType}`;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
}),
|
|
137
|
+
/**
|
|
138
|
+
* Number field with optional range validation
|
|
139
|
+
*/
|
|
140
|
+
number: (field, options = {}) => ({
|
|
141
|
+
field,
|
|
142
|
+
required: options.required,
|
|
143
|
+
type: "number",
|
|
144
|
+
custom: (val) => {
|
|
145
|
+
if (typeof val !== "number") return false;
|
|
146
|
+
if (options.integer && !Number.isInteger(val)) {
|
|
147
|
+
return `${field} must be an integer`;
|
|
148
|
+
}
|
|
149
|
+
if (options.min !== void 0 && val < options.min) {
|
|
150
|
+
return `${field} must be at least ${options.min}`;
|
|
151
|
+
}
|
|
152
|
+
if (options.max !== void 0 && val > options.max) {
|
|
153
|
+
return `${field} must be at most ${options.max}`;
|
|
154
|
+
}
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
}),
|
|
158
|
+
/**
|
|
159
|
+
* Boolean field
|
|
160
|
+
*/
|
|
161
|
+
boolean: (field, required = false) => ({
|
|
162
|
+
field,
|
|
163
|
+
required,
|
|
164
|
+
type: "boolean"
|
|
165
|
+
})
|
|
166
|
+
};
|
|
167
|
+
export {
|
|
168
|
+
CommonRules,
|
|
169
|
+
isNonEmptyString,
|
|
170
|
+
requireFields,
|
|
171
|
+
validateFields
|
|
172
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hadoku/worker-utils",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "1.6.19",
|
|
4
|
+
"license": "ISC",
|
|
5
|
+
"description": "Shared utilities for Cloudflare Workers",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/WolffM/hadoku_site.git"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/index.js",
|
|
14
|
+
"./auth": "./dist/auth.js",
|
|
15
|
+
"./authPage": "./dist/authPage.js",
|
|
16
|
+
"./context": "./dist/context.js",
|
|
17
|
+
"./validation": "./dist/validation.js",
|
|
18
|
+
"./cors": "./dist/cors.js",
|
|
19
|
+
"./logging": "./dist/cloudflareWorkerLogger.js",
|
|
20
|
+
"./responses": "./dist/responses.js",
|
|
21
|
+
"./types": "./dist/types.js",
|
|
22
|
+
"./edge-routes": "./dist/edge-routes.js",
|
|
23
|
+
"./content-level": "./dist/content-level.js",
|
|
24
|
+
"./identity": "./dist/identity.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@hono/zod-openapi": "^1.1.5",
|
|
31
|
+
"@wolffm/logger": "npm:@hadoku/logger@^1.4.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"hono": "^4.11.4"
|
|
35
|
+
}
|
|
36
|
+
}
|