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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +610 -0
  3. package/dist/auth.d.ts +10 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +11 -0
  6. package/dist/effect/action.d.ts +107 -0
  7. package/dist/effect/action.d.ts.map +1 -0
  8. package/dist/effect/action.js +150 -0
  9. package/dist/effect/auth.d.ts +94 -0
  10. package/dist/effect/auth.d.ts.map +1 -0
  11. package/dist/effect/auth.js +204 -0
  12. package/dist/effect/bridge.d.ts +40 -0
  13. package/dist/effect/bridge.d.ts.map +1 -0
  14. package/dist/effect/bridge.js +103 -0
  15. package/dist/effect/errors.d.ts +78 -0
  16. package/dist/effect/errors.d.ts.map +1 -0
  17. package/dist/effect/errors.js +37 -0
  18. package/dist/effect/handler.d.ts +25 -0
  19. package/dist/effect/handler.d.ts.map +1 -0
  20. package/dist/effect/handler.js +120 -0
  21. package/dist/effect/index.d.ts +16 -0
  22. package/dist/effect/index.d.ts.map +1 -0
  23. package/dist/effect/index.js +25 -0
  24. package/dist/effect/responses.d.ts +73 -0
  25. package/dist/effect/responses.d.ts.map +1 -0
  26. package/dist/effect/responses.js +104 -0
  27. package/dist/effect/routing.d.ts +90 -0
  28. package/dist/effect/routing.d.ts.map +1 -0
  29. package/dist/effect/routing.js +124 -0
  30. package/dist/effect/schema.d.ts +263 -0
  31. package/dist/effect/schema.d.ts.map +1 -0
  32. package/dist/effect/schema.js +586 -0
  33. package/dist/effect/services.d.ts +85 -0
  34. package/dist/effect/services.d.ts.map +1 -0
  35. package/dist/effect/services.js +24 -0
  36. package/dist/effect/validation.d.ts +38 -0
  37. package/dist/effect/validation.d.ts.map +1 -0
  38. package/dist/effect/validation.js +69 -0
  39. package/dist/helpers.d.ts +65 -0
  40. package/dist/helpers.d.ts.map +1 -0
  41. package/dist/helpers.js +116 -0
  42. package/dist/index.d.ts +14 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +26 -0
  45. package/dist/middleware.d.ts +14 -0
  46. package/dist/middleware.d.ts.map +1 -0
  47. package/dist/middleware.js +113 -0
  48. package/dist/react.d.ts +17 -0
  49. package/dist/react.d.ts.map +1 -0
  50. package/dist/react.js +4 -0
  51. package/dist/schema.d.ts +9 -0
  52. package/dist/schema.d.ts.map +1 -0
  53. package/dist/schema.js +34 -0
  54. package/dist/setup.d.ts +113 -0
  55. package/dist/setup.d.ts.map +1 -0
  56. package/dist/setup.js +96 -0
  57. package/dist/test-utils.d.ts +105 -0
  58. package/dist/test-utils.d.ts.map +1 -0
  59. package/dist/test-utils.js +210 -0
  60. package/dist/types.d.ts +37 -0
  61. package/dist/types.d.ts.map +1 -0
  62. package/dist/types.js +11 -0
  63. 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"}
@@ -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, '&amp;')
63
+ .replace(/</g, '&lt;')
64
+ .replace(/>/g, '&gt;')
65
+ .replace(/"/g, '&quot;')
66
+ .replace(/'/g, '&#39;');
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
+ };
@@ -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 };
@@ -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
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Honertia React Utilities
3
+ */
4
+ export {};
@@ -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';