honertia 0.1.0
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/README.md +610 -0
- package/dist/auth.d.ts +10 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +11 -0
- package/dist/effect/action.d.ts +107 -0
- package/dist/effect/action.d.ts.map +1 -0
- package/dist/effect/action.js +150 -0
- package/dist/effect/auth.d.ts +94 -0
- package/dist/effect/auth.d.ts.map +1 -0
- package/dist/effect/auth.js +204 -0
- package/dist/effect/bridge.d.ts +40 -0
- package/dist/effect/bridge.d.ts.map +1 -0
- package/dist/effect/bridge.js +103 -0
- package/dist/effect/errors.d.ts +78 -0
- package/dist/effect/errors.d.ts.map +1 -0
- package/dist/effect/errors.js +37 -0
- package/dist/effect/handler.d.ts +25 -0
- package/dist/effect/handler.d.ts.map +1 -0
- package/dist/effect/handler.js +120 -0
- package/dist/effect/index.d.ts +16 -0
- package/dist/effect/index.d.ts.map +1 -0
- package/dist/effect/index.js +25 -0
- package/dist/effect/responses.d.ts +73 -0
- package/dist/effect/responses.d.ts.map +1 -0
- package/dist/effect/responses.js +104 -0
- package/dist/effect/routing.d.ts +90 -0
- package/dist/effect/routing.d.ts.map +1 -0
- package/dist/effect/routing.js +124 -0
- package/dist/effect/schema.d.ts +263 -0
- package/dist/effect/schema.d.ts.map +1 -0
- package/dist/effect/schema.js +586 -0
- package/dist/effect/services.d.ts +85 -0
- package/dist/effect/services.d.ts.map +1 -0
- package/dist/effect/services.js +24 -0
- package/dist/effect/validation.d.ts +38 -0
- package/dist/effect/validation.d.ts.map +1 -0
- package/dist/effect/validation.js +69 -0
- package/dist/helpers.d.ts +65 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +116 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/middleware.d.ts +14 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +113 -0
- package/dist/react.d.ts +17 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +4 -0
- package/dist/schema.d.ts +9 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +34 -0
- package/dist/setup.d.ts +113 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +96 -0
- package/dist/test-utils.d.ts +105 -0
- package/dist/test-utils.d.ts.map +1 -0
- package/dist/test-utils.js +210 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/package.json +71 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effect Services for Honertia
|
|
3
|
+
*
|
|
4
|
+
* Service tags for dependency injection via Effect.
|
|
5
|
+
*/
|
|
6
|
+
import { Context } from 'effect';
|
|
7
|
+
/**
|
|
8
|
+
* Database Service - Generic database client
|
|
9
|
+
*/
|
|
10
|
+
export class DatabaseService extends Context.Tag('honertia/Database')() {
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Auth Service - Better-auth instance
|
|
14
|
+
*/
|
|
15
|
+
export class AuthService extends Context.Tag('honertia/Auth')() {
|
|
16
|
+
}
|
|
17
|
+
export class AuthUserService extends Context.Tag('honertia/AuthUser')() {
|
|
18
|
+
}
|
|
19
|
+
export class HonertiaService extends Context.Tag('honertia/Honertia')() {
|
|
20
|
+
}
|
|
21
|
+
export class RequestService extends Context.Tag('honertia/Request')() {
|
|
22
|
+
}
|
|
23
|
+
export class ResponseFactoryService extends Context.Tag('honertia/ResponseFactory')() {
|
|
24
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effect Validation Helpers
|
|
3
|
+
*
|
|
4
|
+
* Utilities for validating request data using Effect Schema.
|
|
5
|
+
*/
|
|
6
|
+
import { Effect, Schema as S, ParseResult } from 'effect';
|
|
7
|
+
import { RequestService } from './services.js';
|
|
8
|
+
import { ValidationError } from './errors.js';
|
|
9
|
+
/**
|
|
10
|
+
* Extract validation data from the request.
|
|
11
|
+
* Merges route params, query params, and body.
|
|
12
|
+
*/
|
|
13
|
+
export declare const getValidationData: Effect.Effect<{
|
|
14
|
+
[x: string]: unknown;
|
|
15
|
+
}, never, RequestService>;
|
|
16
|
+
/**
|
|
17
|
+
* Format Effect Schema parse errors into field-level validation errors.
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatSchemaErrors(error: ParseResult.ParseError, messages?: Record<string, string>, attributes?: Record<string, string>): Record<string, string>;
|
|
20
|
+
/**
|
|
21
|
+
* Validate data against a schema.
|
|
22
|
+
* Returns validated data or fails with ValidationError.
|
|
23
|
+
*/
|
|
24
|
+
export declare const validate: <A, I>(schema: S.Schema<A, I>, options?: {
|
|
25
|
+
messages?: Record<string, string>;
|
|
26
|
+
attributes?: Record<string, string>;
|
|
27
|
+
errorComponent?: string;
|
|
28
|
+
}) => (data: unknown) => Effect.Effect<A, ValidationError, never>;
|
|
29
|
+
/**
|
|
30
|
+
* Validate request data against a schema.
|
|
31
|
+
* Extracts data from request and validates in one step.
|
|
32
|
+
*/
|
|
33
|
+
export declare const validateRequest: <A, I>(schema: S.Schema<A, I>, options?: {
|
|
34
|
+
messages?: Record<string, string>;
|
|
35
|
+
attributes?: Record<string, string>;
|
|
36
|
+
errorComponent?: string;
|
|
37
|
+
}) => Effect.Effect<A, ValidationError, RequestService>;
|
|
38
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/effect/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,iBAAiB;;yBAuB5B,CAAA;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,CAAC,UAAU,EAC7B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACrC,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACtC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBxB;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,CAAC,EAC3B,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EACtB,UAAU;IACR,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,MAEA,MAAM,OAAO,KAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAYrD,CAAA;AAEL;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,CAAC,EAClC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EACtB,UAAU;IACR,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,KACA,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,eAAe,EAAE,cAAc,CAI/C,CAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effect Validation Helpers
|
|
3
|
+
*
|
|
4
|
+
* Utilities for validating request data using Effect Schema.
|
|
5
|
+
*/
|
|
6
|
+
import { Effect, Schema as S, ParseResult } from 'effect';
|
|
7
|
+
import { RequestService } from './services.js';
|
|
8
|
+
import { ValidationError } from './errors.js';
|
|
9
|
+
/**
|
|
10
|
+
* Extract validation data from the request.
|
|
11
|
+
* Merges route params, query params, and body.
|
|
12
|
+
*/
|
|
13
|
+
export const getValidationData = Effect.gen(function* () {
|
|
14
|
+
const request = yield* RequestService;
|
|
15
|
+
const routeParams = request.params();
|
|
16
|
+
const queryParams = request.query();
|
|
17
|
+
let body = {};
|
|
18
|
+
if (!['GET', 'HEAD'].includes(request.method.toUpperCase())) {
|
|
19
|
+
const contentType = request.header('Content-Type') || '';
|
|
20
|
+
const bodyResult = yield* Effect.tryPromise({
|
|
21
|
+
try: () => contentType.includes('application/json')
|
|
22
|
+
? request.json()
|
|
23
|
+
: request.parseBody(),
|
|
24
|
+
catch: () => ({}),
|
|
25
|
+
}).pipe(Effect.catchAll(() => Effect.succeed({})));
|
|
26
|
+
body = bodyResult;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
...routeParams,
|
|
30
|
+
...queryParams,
|
|
31
|
+
...body,
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Format Effect Schema parse errors into field-level validation errors.
|
|
36
|
+
*/
|
|
37
|
+
export function formatSchemaErrors(error, messages = {}, attributes = {}) {
|
|
38
|
+
const errors = {};
|
|
39
|
+
// Use ArrayFormatter to get structured errors
|
|
40
|
+
const formattedErrors = ParseResult.ArrayFormatter.formatErrorSync(error);
|
|
41
|
+
for (const issue of formattedErrors) {
|
|
42
|
+
const pathStr = issue.path.length > 0
|
|
43
|
+
? issue.path.map(p => typeof p === 'object' && p !== null && 'key' in p ? p.key : String(p)).join('.')
|
|
44
|
+
: 'form';
|
|
45
|
+
if (errors[pathStr])
|
|
46
|
+
continue; // First error wins
|
|
47
|
+
const attribute = attributes[pathStr] ?? pathStr;
|
|
48
|
+
const messageKey = messages[pathStr];
|
|
49
|
+
const message = messageKey ?? issue.message;
|
|
50
|
+
errors[pathStr] = message.replace(/:attribute/g, attribute);
|
|
51
|
+
}
|
|
52
|
+
return errors;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validate data against a schema.
|
|
56
|
+
* Returns validated data or fails with ValidationError.
|
|
57
|
+
*/
|
|
58
|
+
export const validate = (schema, options) => (data) => S.decodeUnknown(schema)(data).pipe(Effect.mapError((error) => new ValidationError({
|
|
59
|
+
errors: formatSchemaErrors(error, options?.messages ?? {}, options?.attributes ?? {}),
|
|
60
|
+
component: options?.errorComponent,
|
|
61
|
+
})));
|
|
62
|
+
/**
|
|
63
|
+
* Validate request data against a schema.
|
|
64
|
+
* Extracts data from request and validates in one step.
|
|
65
|
+
*/
|
|
66
|
+
export const validateRequest = (schema, options) => Effect.gen(function* () {
|
|
67
|
+
const data = yield* getValidationData;
|
|
68
|
+
return yield* validate(schema, options)(data);
|
|
69
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honertia Helpers
|
|
3
|
+
*/
|
|
4
|
+
import type { Context } from 'hono';
|
|
5
|
+
import type { PageObject } from './types.js';
|
|
6
|
+
export interface PageProps {
|
|
7
|
+
errors?: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
export interface TemplateOptions {
|
|
10
|
+
title?: string;
|
|
11
|
+
scripts?: string[];
|
|
12
|
+
styles?: string[];
|
|
13
|
+
head?: string;
|
|
14
|
+
rootId?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Creates a template renderer function.
|
|
18
|
+
*
|
|
19
|
+
* Can accept either static options or a function that receives context
|
|
20
|
+
* for environment-aware configuration.
|
|
21
|
+
*
|
|
22
|
+
* @example Static config
|
|
23
|
+
* ```ts
|
|
24
|
+
* createTemplate({ title: 'App', scripts: ['/main.js'] })
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example Dynamic config based on environment
|
|
28
|
+
* ```ts
|
|
29
|
+
* createTemplate((ctx) => ({
|
|
30
|
+
* title: 'App',
|
|
31
|
+
* scripts: ctx.env.ENVIRONMENT === 'production'
|
|
32
|
+
* ? ['/assets/main.js']
|
|
33
|
+
* : ['http://localhost:5173/src/main.tsx'],
|
|
34
|
+
* }))
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function createTemplate(options: TemplateOptions | ((ctx: Context) => TemplateOptions)): (page: PageObject, ctx?: Context) => string;
|
|
38
|
+
export declare function createVersion(manifest: Record<string, string>): string;
|
|
39
|
+
/**
|
|
40
|
+
* Vite development configuration helpers.
|
|
41
|
+
*/
|
|
42
|
+
export declare const vite: {
|
|
43
|
+
/**
|
|
44
|
+
* Returns the HMR (Hot Module Replacement) head scripts for Vite dev server.
|
|
45
|
+
*
|
|
46
|
+
* @param port - Vite dev server port (default: 5173)
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* head: isProd ? '' : vite.hmrHead()
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
hmrHead(port?: number): string;
|
|
53
|
+
/**
|
|
54
|
+
* Returns the main entry script URL for Vite dev server.
|
|
55
|
+
*
|
|
56
|
+
* @param entry - Entry file path (default: '/src/main.tsx')
|
|
57
|
+
* @param port - Vite dev server port (default: 5173)
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* scripts: isProd ? ['/assets/main.js'] : [vite.script()]
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
script(entry?: string, port?: number): string;
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,eAAe,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,eAAe,CAAC,GAC7D,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,OAAO,KAAK,MAAM,CA6C7C;AAWD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAStE;AAED;;GAEG;AACH,eAAO,MAAM,IAAI;IACf;;;;;;;;OAQG;4BACmB,MAAM;IAa5B;;;;;;;;;OASG;2CAC2C,MAAM;CAGrD,CAAA"}
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honertia Helpers
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Creates a template renderer function.
|
|
6
|
+
*
|
|
7
|
+
* Can accept either static options or a function that receives context
|
|
8
|
+
* for environment-aware configuration.
|
|
9
|
+
*
|
|
10
|
+
* @example Static config
|
|
11
|
+
* ```ts
|
|
12
|
+
* createTemplate({ title: 'App', scripts: ['/main.js'] })
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @example Dynamic config based on environment
|
|
16
|
+
* ```ts
|
|
17
|
+
* createTemplate((ctx) => ({
|
|
18
|
+
* title: 'App',
|
|
19
|
+
* scripts: ctx.env.ENVIRONMENT === 'production'
|
|
20
|
+
* ? ['/assets/main.js']
|
|
21
|
+
* : ['http://localhost:5173/src/main.tsx'],
|
|
22
|
+
* }))
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function createTemplate(options) {
|
|
26
|
+
return (page, ctx) => {
|
|
27
|
+
// If options is a function but no context provided, throw helpful error
|
|
28
|
+
if (typeof options === 'function' && !ctx) {
|
|
29
|
+
throw new Error('createTemplate: context required when using dynamic options function');
|
|
30
|
+
}
|
|
31
|
+
const resolvedOptions = typeof options === 'function' ? options(ctx) : options;
|
|
32
|
+
const { title = 'App', scripts = [], styles = [], head = '', rootId = 'app', } = resolvedOptions;
|
|
33
|
+
const scriptTags = scripts
|
|
34
|
+
.map(src => `<script type="module" src="${escapeHtml(src)}"></script>`)
|
|
35
|
+
.join('\n ');
|
|
36
|
+
const styleTags = styles
|
|
37
|
+
.map(href => `<link rel="stylesheet" href="${escapeHtml(href)}">`)
|
|
38
|
+
.join('\n ');
|
|
39
|
+
const pageJson = JSON.stringify(page)
|
|
40
|
+
.replace(/</g, '\\u003c')
|
|
41
|
+
.replace(/>/g, '\\u003e')
|
|
42
|
+
.replace(/&/g, '\\u0026')
|
|
43
|
+
.replace(/'/g, '\\u0027');
|
|
44
|
+
return `<!DOCTYPE html>
|
|
45
|
+
<html lang="en">
|
|
46
|
+
<head>
|
|
47
|
+
<meta charset="utf-8">
|
|
48
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
49
|
+
<title>${escapeHtml(title)}</title>
|
|
50
|
+
${styleTags}
|
|
51
|
+
${head}
|
|
52
|
+
</head>
|
|
53
|
+
<body>
|
|
54
|
+
<div id="${escapeHtml(rootId)}" data-page='${pageJson}'></div>
|
|
55
|
+
${scriptTags}
|
|
56
|
+
</body>
|
|
57
|
+
</html>`;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function escapeHtml(str) {
|
|
61
|
+
return str
|
|
62
|
+
.replace(/&/g, '&')
|
|
63
|
+
.replace(/</g, '<')
|
|
64
|
+
.replace(/>/g, '>')
|
|
65
|
+
.replace(/"/g, '"')
|
|
66
|
+
.replace(/'/g, ''');
|
|
67
|
+
}
|
|
68
|
+
export function createVersion(manifest) {
|
|
69
|
+
const combined = Object.values(manifest).sort().join('');
|
|
70
|
+
let hash = 0;
|
|
71
|
+
for (let i = 0; i < combined.length; i++) {
|
|
72
|
+
const char = combined.charCodeAt(i);
|
|
73
|
+
hash = ((hash << 5) - hash) + char;
|
|
74
|
+
hash = hash & hash;
|
|
75
|
+
}
|
|
76
|
+
return Math.abs(hash).toString(36);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Vite development configuration helpers.
|
|
80
|
+
*/
|
|
81
|
+
export const vite = {
|
|
82
|
+
/**
|
|
83
|
+
* Returns the HMR (Hot Module Replacement) head scripts for Vite dev server.
|
|
84
|
+
*
|
|
85
|
+
* @param port - Vite dev server port (default: 5173)
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* head: isProd ? '' : vite.hmrHead()
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
hmrHead(port = 5173) {
|
|
92
|
+
return `
|
|
93
|
+
<script type="module">
|
|
94
|
+
import RefreshRuntime from 'http://localhost:${port}/@react-refresh'
|
|
95
|
+
RefreshRuntime.injectIntoGlobalHook(window)
|
|
96
|
+
window.$RefreshReg$ = () => {}
|
|
97
|
+
window.$RefreshSig$ = () => (type) => type
|
|
98
|
+
window.__vite_plugin_react_preamble_installed__ = true
|
|
99
|
+
</script>
|
|
100
|
+
<script type="module" src="http://localhost:${port}/@vite/client"></script>
|
|
101
|
+
`;
|
|
102
|
+
},
|
|
103
|
+
/**
|
|
104
|
+
* Returns the main entry script URL for Vite dev server.
|
|
105
|
+
*
|
|
106
|
+
* @param entry - Entry file path (default: '/src/main.tsx')
|
|
107
|
+
* @param port - Vite dev server port (default: 5173)
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* scripts: isProd ? ['/assets/main.js'] : [vite.script()]
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
script(entry = '/src/main.tsx', port = 5173) {
|
|
114
|
+
return `http://localhost:${port}${entry}`;
|
|
115
|
+
},
|
|
116
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honertia - Inertia.js-style adapter for Hono with Effect.js
|
|
3
|
+
*
|
|
4
|
+
* This is the main entry point for core functionality.
|
|
5
|
+
* For Effect integration, import from 'honertia/effect'.
|
|
6
|
+
* For schema validators, import from 'honertia/schema'.
|
|
7
|
+
* For auth helpers, import from 'honertia/auth'.
|
|
8
|
+
*/
|
|
9
|
+
export { setupHonertia, createErrorHandlers, registerErrorHandlers, type HonertiaSetupConfig, type ErrorHandlerConfig, } from './setup.js';
|
|
10
|
+
export { honertia, HEADERS } from './middleware.js';
|
|
11
|
+
export type { PageObject, HonertiaConfig, HonertiaInstance, RenderOptions, } from './types.js';
|
|
12
|
+
export { createTemplate, createVersion, vite, type PageProps, } from './helpers.js';
|
|
13
|
+
export * from './effect/index.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAEnD,YAAY,EACV,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAA;AAGnB,OAAO,EACL,cAAc,EACd,aAAa,EACb,IAAI,EACJ,KAAK,SAAS,GACf,MAAM,cAAc,CAAA;AAOrB,cAAc,mBAAmB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honertia - Inertia.js-style adapter for Hono with Effect.js
|
|
3
|
+
*
|
|
4
|
+
* This is the main entry point for core functionality.
|
|
5
|
+
* For Effect integration, import from 'honertia/effect'.
|
|
6
|
+
* For schema validators, import from 'honertia/schema'.
|
|
7
|
+
* For auth helpers, import from 'honertia/auth'.
|
|
8
|
+
*/
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Core (Setup, Middleware, Types, Helpers)
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Setup (recommended one-liner for most apps)
|
|
13
|
+
export { setupHonertia, createErrorHandlers, registerErrorHandlers, } from './setup.js';
|
|
14
|
+
// Core middleware (for manual setup)
|
|
15
|
+
export { honertia, HEADERS } from './middleware.js';
|
|
16
|
+
// Helpers
|
|
17
|
+
export { createTemplate, createVersion, vite, } from './helpers.js';
|
|
18
|
+
// =============================================================================
|
|
19
|
+
// Re-exports for convenience (deprecated - use subpath imports instead)
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// Effect Integration - prefer: import { ... } from 'honertia/effect'
|
|
22
|
+
export * from './effect/index.js';
|
|
23
|
+
// Schema Validators - prefer: import { ... } from 'honertia/schema'
|
|
24
|
+
// (already included via effect/index.js)
|
|
25
|
+
// Auth - prefer: import { ... } from 'honertia/auth'
|
|
26
|
+
// (already included via effect/index.js)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honertia Middleware
|
|
3
|
+
*/
|
|
4
|
+
import type { MiddlewareHandler } from 'hono';
|
|
5
|
+
import type { HonertiaConfig, HonertiaInstance } from './types.js';
|
|
6
|
+
import { HEADERS } from './types.js';
|
|
7
|
+
declare module 'hono' {
|
|
8
|
+
interface ContextVariableMap {
|
|
9
|
+
honertia: HonertiaInstance;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export declare function honertia(config: HonertiaConfig): MiddlewareHandler;
|
|
13
|
+
export { HEADERS };
|
|
14
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAA;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAA6B,MAAM,YAAY,CAAA;AAC7F,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC,OAAO,QAAQ,MAAM,CAAC;IACpB,UAAU,kBAAkB;QAC1B,QAAQ,EAAE,gBAAgB,CAAA;KAC3B;CACF;AAqCD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,iBAAiB,CAgHlE;AAED,OAAO,EAAE,OAAO,EAAE,CAAA"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honertia Middleware
|
|
3
|
+
*/
|
|
4
|
+
import { HEADERS } from './types.js';
|
|
5
|
+
async function resolveValue(value) {
|
|
6
|
+
if (typeof value === 'function') {
|
|
7
|
+
return await value();
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
function filterPartialProps(props, include, exclude) {
|
|
12
|
+
let filteredProps = { ...props };
|
|
13
|
+
if (include) {
|
|
14
|
+
const includeKeys = include.split(',').map(k => k.trim());
|
|
15
|
+
filteredProps = Object.fromEntries(Object.entries(props).filter(([key]) => includeKeys.includes(key) || key === 'errors'));
|
|
16
|
+
}
|
|
17
|
+
if (exclude) {
|
|
18
|
+
const excludeKeys = exclude.split(',').map(k => k.trim());
|
|
19
|
+
filteredProps = Object.fromEntries(Object.entries(filteredProps).filter(([key]) => !excludeKeys.includes(key) || key === 'errors'));
|
|
20
|
+
}
|
|
21
|
+
return filteredProps;
|
|
22
|
+
}
|
|
23
|
+
export function honertia(config) {
|
|
24
|
+
return async (c, next) => {
|
|
25
|
+
const sharedProps = {};
|
|
26
|
+
let errors = {};
|
|
27
|
+
const getVersion = () => typeof config.version === 'function' ? config.version() : config.version;
|
|
28
|
+
const isHonertia = c.req.header(HEADERS.HONERTIA) === 'true';
|
|
29
|
+
const clientVersion = c.req.header(HEADERS.VERSION);
|
|
30
|
+
const version = getVersion();
|
|
31
|
+
// Version mismatch - force full reload
|
|
32
|
+
if (isHonertia && clientVersion && clientVersion !== version && c.req.method === 'GET') {
|
|
33
|
+
return new Response(null, {
|
|
34
|
+
status: 409,
|
|
35
|
+
headers: { [HEADERS.LOCATION]: c.req.url },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
const instance = {
|
|
39
|
+
share(key, value) {
|
|
40
|
+
sharedProps[key] = value;
|
|
41
|
+
},
|
|
42
|
+
getShared() {
|
|
43
|
+
return { ...sharedProps };
|
|
44
|
+
},
|
|
45
|
+
setErrors(newErrors) {
|
|
46
|
+
errors = { ...errors, ...newErrors };
|
|
47
|
+
},
|
|
48
|
+
async render(component, props = {}, options = {}) {
|
|
49
|
+
// Resolve lazy shared props
|
|
50
|
+
const resolvedShared = {};
|
|
51
|
+
for (const [key, value] of Object.entries(sharedProps)) {
|
|
52
|
+
resolvedShared[key] = await resolveValue(value);
|
|
53
|
+
}
|
|
54
|
+
let mergedProps = {
|
|
55
|
+
...resolvedShared,
|
|
56
|
+
...props,
|
|
57
|
+
};
|
|
58
|
+
// Add errors
|
|
59
|
+
if (Object.keys(errors).length > 0) {
|
|
60
|
+
mergedProps.errors = {
|
|
61
|
+
...(mergedProps.errors || {}),
|
|
62
|
+
...errors
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (!mergedProps.errors) {
|
|
66
|
+
mergedProps.errors = {};
|
|
67
|
+
}
|
|
68
|
+
// Handle partial reloads
|
|
69
|
+
if (isHonertia) {
|
|
70
|
+
const partialComponent = c.req.header(HEADERS.PARTIAL_COMPONENT);
|
|
71
|
+
const partialData = c.req.header(HEADERS.PARTIAL_DATA);
|
|
72
|
+
const partialExcept = c.req.header(HEADERS.PARTIAL_EXCEPT);
|
|
73
|
+
if (partialComponent === component && (partialData || partialExcept)) {
|
|
74
|
+
mergedProps = filterPartialProps(mergedProps, partialData, partialExcept);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const page = {
|
|
78
|
+
component,
|
|
79
|
+
props: mergedProps,
|
|
80
|
+
url: new URL(c.req.url).pathname + new URL(c.req.url).search,
|
|
81
|
+
version,
|
|
82
|
+
...(options.clearHistory !== undefined && { clearHistory: options.clearHistory }),
|
|
83
|
+
...(options.encryptHistory !== undefined && { encryptHistory: options.encryptHistory }),
|
|
84
|
+
};
|
|
85
|
+
if (isHonertia) {
|
|
86
|
+
return c.json(page, 200, {
|
|
87
|
+
[HEADERS.HONERTIA]: 'true',
|
|
88
|
+
'Vary': HEADERS.HONERTIA,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const html = await config.render(page, c);
|
|
92
|
+
return c.html(html, 200, {
|
|
93
|
+
'Vary': HEADERS.HONERTIA,
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
c.set('honertia', instance);
|
|
98
|
+
await next();
|
|
99
|
+
// Convert 302 to 303 for non-GET requests
|
|
100
|
+
if (isHonertia &&
|
|
101
|
+
c.res.status === 302 &&
|
|
102
|
+
['POST', 'PUT', 'PATCH', 'DELETE'].includes(c.req.method)) {
|
|
103
|
+
const location = c.res.headers.get('Location');
|
|
104
|
+
if (location) {
|
|
105
|
+
return new Response(null, {
|
|
106
|
+
status: 303,
|
|
107
|
+
headers: { 'Location': location, 'Vary': HEADERS.HONERTIA },
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export { HEADERS };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honertia React Utilities
|
|
3
|
+
*/
|
|
4
|
+
import type { PageProps } from './helpers.js';
|
|
5
|
+
type ComponentType<P = unknown> = (props: P) => unknown;
|
|
6
|
+
export type HonertiaPage<TProps = Record<string, never>> = ComponentType<TProps & PageProps>;
|
|
7
|
+
export type PageResolver = (name: string) => Promise<{
|
|
8
|
+
default: ComponentType<unknown>;
|
|
9
|
+
}> | {
|
|
10
|
+
default: ComponentType<unknown>;
|
|
11
|
+
};
|
|
12
|
+
export interface SharedProps {
|
|
13
|
+
errors?: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
export type WithSharedProps<TProps = Record<string, never>> = TProps & SharedProps;
|
|
16
|
+
export type { PageProps } from './helpers.js';
|
|
17
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,KAAK,aAAa,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAA;AAEvD,MAAM,MAAM,YAAY,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;AAE5F,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KACpC,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC,GAC5C;IAAE,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;CAAE,CAAA;AAEvC,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC;AAED,MAAM,MAAM,eAAe,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,GAAG,WAAW,CAAA;AAElF,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA"}
|
package/dist/react.js
ADDED
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honertia Schema Validators
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all Effect Schema validators and validation helpers.
|
|
5
|
+
* Import from 'honertia/schema' for validation functionality.
|
|
6
|
+
*/
|
|
7
|
+
export { S, trimmed, nullableString, optionalString, requiredString, required, alpha, alphaDash, alphaNum, startsWith, endsWith, lowercase, uppercase, coercedNumber, positiveInt, nonNegativeInt, parsePositiveInt, between, digits, digitsBetween, gt, gte, lt, lte, multipleOf, coercedBoolean, checkbox, accepted, declined, coercedDate, nullableDate, after, afterOrEqual, before, beforeOrEqual, ensureArray, distinct, minItems, maxItems, inArray, notIn, email, nullableEmail, url, nullableUrl, uuid, nullableUuid, ip, ipv4, ipv6, macAddress, jsonString, confirmed, size, min, max, password, nullable, filled, excludeIf, } from './effect/schema.js';
|
|
8
|
+
export { getValidationData, formatSchemaErrors, validate, validateRequest, } from './effect/validation.js';
|
|
9
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAEL,CAAC,EAED,OAAO,EACP,cAAc,EACd,cAAc,EACd,cAAc,EACd,QAAQ,EACR,KAAK,EACL,SAAS,EACT,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,SAAS,EAET,aAAa,EACb,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,OAAO,EACP,MAAM,EACN,aAAa,EACb,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,UAAU,EAEV,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,QAAQ,EAER,WAAW,EACX,YAAY,EACZ,KAAK,EACL,YAAY,EACZ,MAAM,EACN,aAAa,EAEb,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,QAAQ,EAER,OAAO,EACP,KAAK,EAEL,KAAK,EACL,aAAa,EACb,GAAG,EACH,WAAW,EACX,IAAI,EACJ,YAAY,EACZ,EAAE,EACF,IAAI,EACJ,IAAI,EACJ,UAAU,EACV,UAAU,EAEV,SAAS,EAET,IAAI,EACJ,GAAG,EACH,GAAG,EAEH,QAAQ,EAER,QAAQ,EACR,MAAM,EACN,SAAS,GACV,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,eAAe,GAChB,MAAM,wBAAwB,CAAA"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honertia Schema Validators
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all Effect Schema validators and validation helpers.
|
|
5
|
+
* Import from 'honertia/schema' for validation functionality.
|
|
6
|
+
*/
|
|
7
|
+
// Schema Validators (Effect Schema based)
|
|
8
|
+
export {
|
|
9
|
+
// Re-export Schema namespace
|
|
10
|
+
S,
|
|
11
|
+
// String types
|
|
12
|
+
trimmed, nullableString, optionalString, requiredString, required, alpha, alphaDash, alphaNum, startsWith, endsWith, lowercase, uppercase,
|
|
13
|
+
// Numeric types
|
|
14
|
+
coercedNumber, positiveInt, nonNegativeInt, parsePositiveInt, between, digits, digitsBetween, gt, gte, lt, lte, multipleOf,
|
|
15
|
+
// Boolean types
|
|
16
|
+
coercedBoolean, checkbox, accepted, declined,
|
|
17
|
+
// Date types
|
|
18
|
+
coercedDate, nullableDate, after, afterOrEqual, before, beforeOrEqual,
|
|
19
|
+
// Array types
|
|
20
|
+
ensureArray, distinct, minItems, maxItems,
|
|
21
|
+
// Enum/In rules
|
|
22
|
+
inArray, notIn,
|
|
23
|
+
// Format types
|
|
24
|
+
email, nullableEmail, url, nullableUrl, uuid, nullableUuid, ip, ipv4, ipv6, macAddress, jsonString,
|
|
25
|
+
// Confirmation
|
|
26
|
+
confirmed,
|
|
27
|
+
// Size rules
|
|
28
|
+
size, min, max,
|
|
29
|
+
// Password
|
|
30
|
+
password,
|
|
31
|
+
// Utility
|
|
32
|
+
nullable, filled, excludeIf, } from './effect/schema.js';
|
|
33
|
+
// Validation Helpers
|
|
34
|
+
export { getValidationData, formatSchemaErrors, validate, validateRequest, } from './effect/validation.js';
|