honertia 0.1.44 → 0.1.45

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/README.md CHANGED
@@ -2,6 +2,142 @@
2
2
 
3
3
  Inertia.js adapter for Hono with Effect.ts. Server-driven app with SPA behavior.
4
4
 
5
+ ## Why Honertia
6
+
7
+ Honertia brings the Laravel/Inertia productivity loop to Hono and Cloudflare Workers, with Effect powering the backend control flow instead of ad-hoc promises and unchecked exceptions.
8
+
9
+ - **Server-driven SPA pages on Hono**: Render Inertia-style pages from Hono routes while keeping React/Vite on the client and Worker-friendly request handling on the server.
10
+ - **Effect-native route handlers**: Write actions as typed Effect programs with explicit services, structured failures, redirects, validation errors, and testable dependency layers.
11
+ - **One setup path for real apps**: `setupHonertia()` wires the Inertia middleware, database, auth, shared page props, user loading, and per-request Effect runtime in the right order.
12
+ - **Laravel-style route model binding**: Use paths like `/projects/{project}` or `/users/{user}/posts/{post}` and access resolved models with `yield* bound('project')`, backed by your Drizzle schema.
13
+ - **Safe mutation boundaries**: `validateRequest`, scoped `dbMutation`, and `dbTransaction` make writes explicit and keep unvalidated request data out of database mutations.
14
+ - **Auth built in, not bolted on**: Better Auth helpers cover authenticated routes, guest-only routes, form actions, typed `authorize()`, session loading, and shared auth props.
15
+ - **Effect-aware cache wrapper**: Cache expensive reads with schema-checked serialization, TTLs, stale-while-revalidate, and Worker `waitUntil` background refreshes.
16
+ - **Agent-friendly CLI**: Generate actions, CRUD routes, features, OpenAPI specs, route listings, project checks, and migration previews from a single `honertia` binary.
17
+ - **Production observability hooks**: Structured errors and `EffectErrorObserverService` provide a single integration point for Sentry, PostHog, or any Effect-aware reporting pipeline.
18
+
19
+ Demo Worker: [PatrickOgilvie/honertia-worker-demo](https://github.com/PatrickOgilvie/honertia-worker-demo)
20
+
21
+ One-click demo deploy:
22
+
23
+ [![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/PatrickOgilvie/honertia-worker-demo)
24
+
25
+ ## Laravel-Style Helpers
26
+
27
+ Honertia keeps common app code small and expressive. The helpers are Effect-native, but the shape should feel familiar if you like Laravel controllers, form requests, redirects, cache wrappers, and route model binding.
28
+
29
+ ```typescript
30
+ import { effectRoutes } from 'honertia/effect'
31
+ import { indexProjects, showProject, updateProject } from './actions/projects'
32
+
33
+ effectRoutes(app)
34
+ .get('/projects', indexProjects, { name: 'projects.index' })
35
+ .get('/projects/{project}', showProject, { name: 'projects.show' })
36
+ .put('/projects/{project}', updateProject, { name: 'projects.update' })
37
+ ```
38
+
39
+ ```typescript
40
+ import { Effect } from 'effect'
41
+ import { action, authorize, bound, render } from 'honertia/effect'
42
+
43
+ export const showProject = action(
44
+ Effect.gen(function* () {
45
+ const project = yield* bound('project')
46
+ yield* authorize((auth) => auth.user.id === project.userId)
47
+
48
+ return yield* render('Projects/Show', { project })
49
+ })
50
+ )
51
+ ```
52
+
53
+ ```typescript
54
+ import { Effect, Schema as S, Duration } from 'effect'
55
+ import { action, authorize, DatabaseService, render } from 'honertia/effect'
56
+ import { cache } from 'honertia/cache'
57
+ import { eq } from 'drizzle-orm'
58
+ import { projects } from '~/db/schema'
59
+
60
+ const ProjectSummary = S.Struct({
61
+ id: S.String,
62
+ name: S.String,
63
+ updatedAt: S.Date,
64
+ })
65
+
66
+ export const indexProjects = action(
67
+ Effect.gen(function* () {
68
+ const auth = yield* authorize()
69
+ const db = yield* DatabaseService
70
+
71
+ const userProjects = yield* cache(
72
+ `users:${auth.user.id}:projects`,
73
+ Effect.tryPromise(() =>
74
+ db.query.projects.findMany({
75
+ columns: { id: true, name: true, updatedAt: true },
76
+ where: eq(projects.userId, auth.user.id),
77
+ orderBy: (project, { desc }) => [desc(project.updatedAt)],
78
+ })
79
+ ),
80
+ S.Array(ProjectSummary),
81
+ { ttl: Duration.minutes(5), swr: Duration.minutes(1), version: true }
82
+ )
83
+
84
+ return yield* render('Projects/Index', { projects: userProjects })
85
+ })
86
+ )
87
+ ```
88
+
89
+ ```typescript
90
+ import { Effect, Schema as S } from 'effect'
91
+ import {
92
+ action,
93
+ authorize,
94
+ bound,
95
+ validateRequest,
96
+ DatabaseService,
97
+ dbMutation,
98
+ redirect,
99
+ requiredString,
100
+ } from 'honertia/effect'
101
+ import { eq } from 'drizzle-orm'
102
+ import { projects } from '~/db/schema'
103
+
104
+ const UpdateProject = S.Struct({
105
+ name: requiredString,
106
+ description: S.optional(S.String),
107
+ })
108
+
109
+ export const updateProject = action(
110
+ Effect.gen(function* () {
111
+ const project = yield* bound('project')
112
+ yield* authorize((auth) => auth.user.id === project.userId)
113
+
114
+ const input = yield* validateRequest(UpdateProject, {
115
+ errorComponent: 'Projects/Edit',
116
+ })
117
+ const db = yield* DatabaseService
118
+
119
+ yield* dbMutation(db, input, async (tx, input) => {
120
+ await tx
121
+ .update(projects)
122
+ .set(input)
123
+ .where(eq(projects.id, project.id))
124
+ })
125
+
126
+ return yield* redirect(`/projects/${project.id}`)
127
+ })
128
+ )
129
+ ```
130
+
131
+ ```typescript
132
+ import { render, redirect, notFound, forbidden, jsonOrRender } from 'honertia/effect'
133
+
134
+ return yield* render('Dashboard', { stats })
135
+ return yield* redirect('/login')
136
+ return yield* notFound('Project', projectId)
137
+ return yield* forbidden('You cannot edit this project')
138
+ return yield* jsonOrRender('Projects/Index', { projects })
139
+ ```
140
+
5
141
  ## CLI Commands
6
142
 
7
143
  `honertia` is shipped as a package binary. You can run commands with:
@@ -372,6 +508,15 @@ registerErrorHandlers(app)
372
508
  export default app
373
509
  ```
374
510
 
511
+ `createTemplate()` emits Inertia's script-element initial page payload:
512
+
513
+ ```html
514
+ <script data-page="app" type="application/json">...</script>
515
+ <div id="app"></div>
516
+ ```
517
+
518
+ If you provide a custom template renderer, use `serializePage(page)` from `honertia` for the JSON script body so `</script>` sequences inside props cannot close the element early.
519
+
375
520
  ### 6. src/routes.ts (REQUIRED)
376
521
 
377
522
  Route definitions.
package/dist/helpers.d.ts CHANGED
@@ -19,6 +19,15 @@ export interface TemplateOptions {
19
19
  head?: string;
20
20
  rootId?: string;
21
21
  }
22
+ /**
23
+ * Serialize an Inertia page object for embedding in a
24
+ * `<script type="application/json">` initial page payload.
25
+ *
26
+ * Escaping `/` prevents a `</script>` sequence inside JSON data from closing
27
+ * the script element early. This mirrors the approach used by @hono/inertia
28
+ * and Inertia's script-element initial page transport.
29
+ */
30
+ export declare function serializePage(page: PageObject): string;
22
31
  /**
23
32
  * Creates a template renderer function.
24
33
  *
@@ -1 +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;AAG5C,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,EAAE,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAAC,CAAA;AAEvE,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;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;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,CAgD7C;AAWD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,CA8B7D;AAED;;GAEG;AACH,eAAO,MAAM,IAAI;IACf;;;;;;;;OAQG;4BACmB,MAAM;IAa5B;;;;;;;;;OASG;2CAC2C,MAAM;CAGrD,CAAA"}
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;AAG5C,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,EAAE,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAAC,CAAA;AAEvE,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;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAEtD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;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,aAAa,GAAG,MAAM,CA8B7D;AAED;;GAEG;AACH,eAAO,MAAM,IAAI;IACf;;;;;;;;OAQG;4BACmB,MAAM;IAa5B;;;;;;;;;OASG;2CAC2C,MAAM;CAGrD,CAAA"}
package/dist/helpers.js CHANGED
@@ -2,6 +2,17 @@
2
2
  * Honertia Helpers
3
3
  */
4
4
  import { HonertiaConfigurationError } from './effect/errors.js';
5
+ /**
6
+ * Serialize an Inertia page object for embedding in a
7
+ * `<script type="application/json">` initial page payload.
8
+ *
9
+ * Escaping `/` prevents a `</script>` sequence inside JSON data from closing
10
+ * the script element early. This mirrors the approach used by @hono/inertia
11
+ * and Inertia's script-element initial page transport.
12
+ */
13
+ export function serializePage(page) {
14
+ return JSON.stringify(page).replace(/\//g, '\\/');
15
+ }
5
16
  /**
6
17
  * Creates a template renderer function.
7
18
  *
@@ -47,11 +58,7 @@ export function createTemplate(options) {
47
58
  const styleTags = styles
48
59
  .map(href => `<link rel="stylesheet" href="${escapeHtml(href)}">`)
49
60
  .join('\n ');
50
- const pageJson = JSON.stringify(page)
51
- .replace(/</g, '\\u003c')
52
- .replace(/>/g, '\\u003e')
53
- .replace(/&/g, '\\u0026')
54
- .replace(/'/g, '\\u0027');
61
+ const pageJson = serializePage(page);
55
62
  return `<!DOCTYPE html>
56
63
  <html lang="en">
57
64
  <head>
@@ -62,7 +69,8 @@ export function createTemplate(options) {
62
69
  ${head}
63
70
  </head>
64
71
  <body>
65
- <div id="${escapeHtml(rootId)}" data-page='${pageJson}'></div>
72
+ <script data-page="${escapeHtml(rootId)}" type="application/json">${pageJson}</script>
73
+ <div id="${escapeHtml(rootId)}"></div>
66
74
  ${scriptTags}
67
75
  </body>
68
76
  </html>`;
package/dist/index.d.ts CHANGED
@@ -9,6 +9,6 @@
9
9
  export { setupHonertia, createErrorHandlers, registerErrorHandlers, type HonertiaSetupConfig, type HonertiaFullConfig, type ErrorHandlerConfig, } from './setup.js';
10
10
  export { honertia, HEADERS } from './middleware.js';
11
11
  export type { PageObject, HonertiaConfig, HonertiaInstance, RenderOptions, } from './types.js';
12
- export { createTemplate, createVersion, vite, type PageProps, } from './helpers.js';
12
+ export { createTemplate, createVersion, serializePage, vite, type PageProps, } from './helpers.js';
13
13
  export * from './effect/index.js';
14
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +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,EACvB,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"}
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,EACvB,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,aAAa,EACb,IAAI,EACJ,KAAK,SAAS,GACf,MAAM,cAAc,CAAA;AAOrB,cAAc,mBAAmB,CAAA"}
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ export { setupHonertia, createErrorHandlers, registerErrorHandlers, } from './se
14
14
  // Core middleware (for manual setup)
15
15
  export { honertia, HEADERS } from './middleware.js';
16
16
  // Helpers
17
- export { createTemplate, createVersion, vite, } from './helpers.js';
17
+ export { createTemplate, createVersion, serializePage, vite, } from './helpers.js';
18
18
  // =============================================================================
19
19
  // Re-exports for convenience (deprecated - use subpath imports instead)
20
20
  // =============================================================================
@@ -1 +1 @@
1
- {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,YAAY,CAAA;AAM5D,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;IACjC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACxD;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;CACvB;AAED,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAMD;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,cAAmB,8EAkBzD;AAMD;;GAEG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,kBAAuB,gCASjC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,qBAA0B,gCAsCpC;AAMD;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAG7E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CASjF;AAMD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,QAAQ,QAalD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,QAAQ,QAS/C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,QAAQ,EAAE,gBAAgB,CAAC,EAAE,MAAM,QAa7E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,QAY/E;AAMD,eAAO,MAAM,SAAS;;;;GAIrB,CAAA;AAED,eAAO,MAAM,YAAY;;;;GAGxB,CAAA;AAED,eAAO,MAAM,UAAU;;;CAGtB,CAAA;AAMD,eAAO,MAAM,eAAe;;;;;;;;;;;CAW3B,CAAA;AAMD;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,SAAI,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,CAOnE;AAMD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACpE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,KAAK,EAAE,MAAM,MAAM,CAAA;CACpB;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CAerD"}
1
+ {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAG3B,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,YAAY,CAAA;AAM5D,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;IACjC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACxD;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;CACvB;AAED,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAMD;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,cAAmB,8EAkBzD;AAMD;;GAEG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,kBAAuB,gCASjC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,qBAA0B,gCAsCpC;AAMD;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAG7E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAWjF;AAMD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,QAAQ,QAalD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,QAAQ,QAS/C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,QAAQ,EAAE,gBAAgB,CAAC,EAAE,MAAM,QAa7E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,QAY/E;AAMD,eAAO,MAAM,SAAS;;;;GAIrB,CAAA;AAED,eAAO,MAAM,YAAY;;;;GAGxB,CAAA;AAED,eAAO,MAAM,UAAU;;;CAGtB,CAAA;AAMD,eAAO,MAAM,eAAe;;;;;;;;;;;CAW3B,CAAA;AAMD;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,SAAI,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,CAOnE;AAMD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACpE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,KAAK,EAAE,MAAM,MAAM,CAAA;CACpB;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CAerD"}
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { Hono } from 'hono';
8
8
  import { honertia, HEADERS } from './middleware.js';
9
+ import { serializePage } from './helpers.js';
9
10
  // =============================================================================
10
11
  // App Factory
11
12
  // =============================================================================
@@ -13,7 +14,7 @@ import { honertia, HEADERS } from './middleware.js';
13
14
  * Creates a test Hono app with honertia middleware configured
14
15
  */
15
16
  export function createTestApp(options = {}) {
16
- const { version = '1.0.0', render = (page) => `<!DOCTYPE html><html><body><div id="app" data-page='${JSON.stringify(page)}'></div></body></html>`, } = options;
17
+ const { version = '1.0.0', render = (page) => `<!DOCTYPE html><html><body><script data-page="app" type="application/json">${serializePage(page)}</script><div id="app"></div></body></html>`, } = options;
17
18
  const app = new Hono();
18
19
  app.use('*', honertia({
19
20
  version,
@@ -77,9 +78,9 @@ export async function parseInertiaResponse(res) {
77
78
  */
78
79
  export async function parseHtmlResponse(res) {
79
80
  const html = await res.text();
80
- const match = html.match(/data-page='([^']+)'/);
81
- if (match) {
82
- return JSON.parse(match[1]);
81
+ const scriptMatch = html.match(/<script\s+data-page="[^"]+"\s+type="application\/json">([\s\S]*?)<\/script>/);
82
+ if (scriptMatch) {
83
+ return JSON.parse(scriptMatch[1]);
83
84
  }
84
85
  return null;
85
86
  }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "honertia",
3
- "version": "0.1.44",
3
+ "version": "0.1.45",
4
4
  "description": "Inertia.js-style server-driven SPA adapter for Hono",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
9
9
  "bin": {
10
- "honertia": "./dist/cli/bin.js"
10
+ "honertia": "dist/cli/bin.js"
11
11
  },
12
12
  "exports": {
13
13
  ".": {
@@ -64,7 +64,7 @@
64
64
  "license": "MIT",
65
65
  "repository": {
66
66
  "type": "git",
67
- "url": "https://github.com/patrickogilvie/honertia"
67
+ "url": "git+https://github.com/patrickogilvie/honertia.git"
68
68
  },
69
69
  "dependencies": {
70
70
  "effect": "^3.12.0"