@arponascension/express-inertia 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 +478 -0
- package/dist/base.ejs +14 -0
- package/dist/engine.d.mts +24 -0
- package/dist/engine.d.ts +24 -0
- package/dist/engine.js +480 -0
- package/dist/engine.js.map +1 -0
- package/dist/engine.mjs +470 -0
- package/dist/engine.mjs.map +1 -0
- package/dist/index.d.mts +175 -0
- package/dist/index.d.ts +175 -0
- package/dist/index.js +1268 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1218 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types-Co2XESgs.d.mts +423 -0
- package/dist/types-Co2XESgs.d.ts +423 -0
- package/dist/vite.d.mts +116 -0
- package/dist/vite.d.ts +116 -0
- package/dist/vite.js +336 -0
- package/dist/vite.js.map +1 -0
- package/dist/vite.mjs +326 -0
- package/dist/vite.mjs.map +1 -0
- package/package.json +71 -0
- package/templates/base.ejs +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arpon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
# express-inertia ๐
|
|
2
|
+
|
|
3
|
+
[](https://npmjs.com/package/@arponascension/express-inertia)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](https://github.com/Arpon/express-inertia)
|
|
7
|
+
|
|
8
|
+
**Next-generation Inertia.js adapter and middleware for Express.js** with Blade-style EJS directives, Vite integration, SSR resilience, security hardening, and first-class TypeScript support.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## โจ Why express-inertia?
|
|
13
|
+
|
|
14
|
+
| Feature | Benefit |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Blade-style EJS | Write Laravel Blade syntax (`@inertia`, `@vite`, `@csrf`) directly in `.ejs` templates |
|
|
17
|
+
| Zero-config Vite | Auto HMR in dev, hashed `manifest.json` in production |
|
|
18
|
+
| SSR Resilience | Circuit breaker, retries with backoff, graceful client-side fallback |
|
|
19
|
+
| Security Hardened | Component name validation, viewData sanitization, SRI hash generation |
|
|
20
|
+
| Form Helpers | Semantic `postForm`, `putForm`, `patchForm`, `deleteForm` with flash messages |
|
|
21
|
+
| Prefetch Ready | Generate `<link rel="prefetch">` / `<link rel="preload">` from Vite manifest |
|
|
22
|
+
| Edge Compatible | Works on Cloudflare Workers, Vercel Edge, Netlify Edge via injected manifest/config |
|
|
23
|
+
| Structured Logging | Pluggable logger abstraction with request correlation IDs |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## ๐ฆ Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @arponascension/express-inertia ejs
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Peer dependencies:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install express
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## ๐ Quick Start
|
|
42
|
+
|
|
43
|
+
### 1. Configure Express Server
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import express from 'express';
|
|
47
|
+
import path from 'path';
|
|
48
|
+
import { inertia, createInertiaEngine } from 'express-inertia';
|
|
49
|
+
|
|
50
|
+
const app = express();
|
|
51
|
+
|
|
52
|
+
// Blade-compatible EJS View Engine
|
|
53
|
+
app.engine('ejs', createInertiaEngine());
|
|
54
|
+
app.set('view engine', 'ejs');
|
|
55
|
+
app.set('views', path.join(__dirname, 'views'));
|
|
56
|
+
|
|
57
|
+
// Parse request bodies & serve static files
|
|
58
|
+
app.use(express.json());
|
|
59
|
+
app.use(express.urlencoded({ extended: true }));
|
|
60
|
+
app.use(express.static(path.join(__dirname, 'public')));
|
|
61
|
+
|
|
62
|
+
// Inertia Middleware
|
|
63
|
+
app.use(
|
|
64
|
+
inertia({
|
|
65
|
+
rootView: 'base.ejs',
|
|
66
|
+
version: '0.1.0',
|
|
67
|
+
shared: (req) => ({
|
|
68
|
+
appName: 'My Express App',
|
|
69
|
+
auth: { user: (req as any).user || null },
|
|
70
|
+
}),
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Routes
|
|
75
|
+
app.get('/', (req, res) => {
|
|
76
|
+
res.inertia('Home', { title: 'Welcome Home' });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
app.listen(3000, () => console.log('Server running on http://localhost:3000'));
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. Create Root View (`views/base.ejs`)
|
|
83
|
+
|
|
84
|
+
```html
|
|
85
|
+
<!DOCTYPE html>
|
|
86
|
+
<html lang="en">
|
|
87
|
+
<head>
|
|
88
|
+
<meta charset="utf-8" />
|
|
89
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
90
|
+
<title><%= page?.props?.title || 'App' %></title>
|
|
91
|
+
|
|
92
|
+
@inertiaHead
|
|
93
|
+
@viteReactRefresh
|
|
94
|
+
@vite('src/main.tsx')
|
|
95
|
+
</head>
|
|
96
|
+
<body>
|
|
97
|
+
@inertia
|
|
98
|
+
@csrf
|
|
99
|
+
</body>
|
|
100
|
+
</html>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## ๐ท๏ธ Blade Directives & Components
|
|
106
|
+
|
|
107
|
+
Write Laravel Blade-style syntax inside EJS templates:
|
|
108
|
+
|
|
109
|
+
| Directive | Component Tag | Output |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| `@inertia` | `<x-inertia />` | Renders `<div id="app"></div><script data-page="app" type="application/json">` |
|
|
112
|
+
| `@inertia('root')` | `<x-inertia id="root" />` | Custom root ID |
|
|
113
|
+
| `@inertiaScript` | `<x-inertia-script />` | JSON script only (manual root container) |
|
|
114
|
+
| `@inertiaHead` | `<x-inertia-head />` | Injects SSR `<head>` tags |
|
|
115
|
+
| `@vite('src/main.ts')` | `<x-vite src="src/main.ts" />` | Dev HMR or production manifest |
|
|
116
|
+
| `@viteReactRefresh` | `<x-vite-react-refresh />` | React Fast Refresh preamble |
|
|
117
|
+
| `@csrf` | `<x-csrf />` | CSRF hidden input |
|
|
118
|
+
| `@routes` | `<x-routes />` | Ziggy / route definitions |
|
|
119
|
+
| `@json(myVar)` | โ | Safely stringifies a JS object |
|
|
120
|
+
|
|
121
|
+
### Custom Directives
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { registerDirective } from 'express-inertia';
|
|
125
|
+
|
|
126
|
+
registerDirective('uppercase', (args) => `<%= (${args}).toUpperCase() %>`);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## โก Response API
|
|
132
|
+
|
|
133
|
+
### `res.inertia(component, props?, viewData?)`
|
|
134
|
+
|
|
135
|
+
Renders an Inertia response. In AJAX requests it returns JSON; on full page loads it renders the root template.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
app.get('/users', (req, res) => {
|
|
139
|
+
res.inertia('Users/Index', {
|
|
140
|
+
users: await getUsers(),
|
|
141
|
+
}, {
|
|
142
|
+
metaTitle: 'User Directory', // viewData: passed to base.ejs only
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Form Helpers
|
|
148
|
+
|
|
149
|
+
Semantic form submission helpers with automatic method semantics:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
app.post('/login', (req, res) => {
|
|
153
|
+
res.inertia.postForm('Dashboard', { user: req.body.user });
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
app.put('/profile', (req, res) => {
|
|
157
|
+
res.inertia.putForm('Profile', { name: req.body.name });
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
app.patch('/settings', (req, res) => {
|
|
161
|
+
res.inertia.patchForm('Settings', { theme: req.body.theme });
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
app.delete('/account', (req, res) => {
|
|
165
|
+
res.inertia.deleteForm('Goodbye');
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Flash Messages
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
res.inertia
|
|
173
|
+
.withFlash('success', 'Profile updated!')
|
|
174
|
+
.inertia('Dashboard');
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Redirect Helpers
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
// External redirect / full reload
|
|
181
|
+
res.inertia.location('https://stripe.com/checkout');
|
|
182
|
+
|
|
183
|
+
// Back to referrer (303 See Other)
|
|
184
|
+
res.inertia.back('/dashboard');
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### History Encryption (Inertia v2)
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
res.inertia.encryptHistory(true);
|
|
191
|
+
res.inertia.clearHistory(true);
|
|
192
|
+
res.inertia('SecretReport');
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## ๐ Prop Helpers
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { lazy, always, defer, merge, optional } from 'express-inertia';
|
|
201
|
+
|
|
202
|
+
app.get('/dashboard', (req, res) => {
|
|
203
|
+
res.inertia('Dashboard', {
|
|
204
|
+
summary: await getSummary(),
|
|
205
|
+
|
|
206
|
+
// Omitted on initial load; fetched only when explicitly reloaded
|
|
207
|
+
heavyReport: lazy(async () => calculateComplexMetrics()),
|
|
208
|
+
|
|
209
|
+
// Always included, even on partial reloads of other keys
|
|
210
|
+
announcements: always(async () => getLatestAnnouncements()),
|
|
211
|
+
|
|
212
|
+
// Inertia v2: appends to existing client-side list
|
|
213
|
+
feed: merge(async () => getFeedItems()),
|
|
214
|
+
|
|
215
|
+
// Inertia v2: fetched in background after initial render
|
|
216
|
+
chartData: defer(async () => getChartData(), { group: 'analytics' }),
|
|
217
|
+
|
|
218
|
+
// Inertia v2: included on initial load, then treated as optional on updates
|
|
219
|
+
extraSetting: optional(() => getExtraSetting()),
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## โก Vite Integration
|
|
227
|
+
|
|
228
|
+
Auto-detects Vite dev server via hot file. Reads `manifest.json` in production.
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
app.use(
|
|
232
|
+
inertia({
|
|
233
|
+
vite: {
|
|
234
|
+
publicDir: 'public',
|
|
235
|
+
buildDir: 'build',
|
|
236
|
+
devServerUrl: 'http://localhost:5173',
|
|
237
|
+
hotFile: 'public/hot',
|
|
238
|
+
base: '/build/',
|
|
239
|
+
},
|
|
240
|
+
})
|
|
241
|
+
);
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Prefetch Helpers
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import { createPrefetchHelper } from 'express-inertia';
|
|
248
|
+
|
|
249
|
+
const prefetch = createPrefetchHelper(viteHelper);
|
|
250
|
+
|
|
251
|
+
// In your base template:
|
|
252
|
+
<%= prefetch.prefetch('src/Pages/Dashboard.tsx') %>
|
|
253
|
+
// <link rel="prefetch" href="/build/assets/Dashboard.abc1234.js">
|
|
254
|
+
|
|
255
|
+
<%= prefetch.preload('src/main.ts') %>
|
|
256
|
+
// <link rel="preload" href="/build/assets/main.abc1234.js">
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## ๐ Server-Side Rendering (SSR)
|
|
262
|
+
|
|
263
|
+
With built-in resilience:
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
app.use(
|
|
267
|
+
inertia({
|
|
268
|
+
ssr: {
|
|
269
|
+
enabled: true,
|
|
270
|
+
url: 'http://127.0.0.1:13714/render',
|
|
271
|
+
timeout: 2000,
|
|
272
|
+
fallback: true,
|
|
273
|
+
retry: { maxRetries: 2, baseDelayMs: 200, maxDelayMs: 2000 },
|
|
274
|
+
circuitBreaker: { failureThreshold: 5, cooldownMs: 30000 },
|
|
275
|
+
},
|
|
276
|
+
})
|
|
277
|
+
);
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Or custom render function:
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
app.use(
|
|
284
|
+
inertia({
|
|
285
|
+
ssr: {
|
|
286
|
+
enabled: true,
|
|
287
|
+
render: async (page) => {
|
|
288
|
+
return {
|
|
289
|
+
head: [`<title>${page.props.title}</title>`],
|
|
290
|
+
body: '<div id="app">...</div>',
|
|
291
|
+
};
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
})
|
|
295
|
+
);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## ๐ Security
|
|
301
|
+
|
|
302
|
+
### Component Name Validation
|
|
303
|
+
|
|
304
|
+
Prevents path traversal and injection attacks:
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
app.use(
|
|
308
|
+
inertia({
|
|
309
|
+
security: {
|
|
310
|
+
validateComponentNames: true,
|
|
311
|
+
componentNamePattern: /^[\w\/-]+$/,
|
|
312
|
+
},
|
|
313
|
+
})
|
|
314
|
+
);
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### ViewData Sanitization
|
|
318
|
+
|
|
319
|
+
Automatically strips functions and undefined values from template data.
|
|
320
|
+
|
|
321
|
+
### SRI Hash Generation
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
import { generateSriHash } from 'express-inertia';
|
|
325
|
+
|
|
326
|
+
const hash = await generateSriHash(assetContent);
|
|
327
|
+
// sha384-abc123...
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## ๐งช Structured Logging
|
|
333
|
+
|
|
334
|
+
Replace `console.warn` with a pluggable logger:
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
import { createLogger, setGlobalLogger } from 'express-inertia';
|
|
338
|
+
import pino from 'pino';
|
|
339
|
+
|
|
340
|
+
setGlobalLogger(createLogger({ prefix: 'my-app', logger: pino() }));
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Request Correlation IDs
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
import { requestIdMiddleware } from 'express-inertia';
|
|
347
|
+
|
|
348
|
+
app.use(requestIdMiddleware());
|
|
349
|
+
app.use(inertia());
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Correlates logs across the request lifecycle using `X-Request-ID` or auto-generated IDs.
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## ๐ Edge Runtime Compatibility
|
|
357
|
+
|
|
358
|
+
Works on Cloudflare Workers, Vercel Edge, and Netlify Edge by bypassing Node.js `fs`/`path`:
|
|
359
|
+
|
|
360
|
+
```ts
|
|
361
|
+
const viteHelper = createViteHelper({
|
|
362
|
+
manifest: await fetch('/build/.vite/manifest.json').then(r => r.json()),
|
|
363
|
+
base: '/build/',
|
|
364
|
+
isDev: false,
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
app.engine('ejs', createInertiaEngine({
|
|
368
|
+
templateSource: await fetch('/templates/base.ejs').then(r => r.text()),
|
|
369
|
+
vite: { manifest: await getManifest() },
|
|
370
|
+
}));
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## ๐ก๏ธ Resilience
|
|
376
|
+
|
|
377
|
+
### Circuit Breaker (SSR)
|
|
378
|
+
|
|
379
|
+
Prevents cascade failures when the SSR endpoint is down:
|
|
380
|
+
|
|
381
|
+
```ts
|
|
382
|
+
import { CircuitBreaker, resetAllCircuitBreakers } from 'express-inertia';
|
|
383
|
+
|
|
384
|
+
const breaker = new CircuitBreaker({
|
|
385
|
+
failureThreshold: 5,
|
|
386
|
+
cooldownMs: 30000,
|
|
387
|
+
probeDelayMs: 1000,
|
|
388
|
+
});
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Retry with Exponential Backoff
|
|
392
|
+
|
|
393
|
+
```ts
|
|
394
|
+
import { calculateBackoff } from 'express-inertia';
|
|
395
|
+
|
|
396
|
+
const delay = calculateBackoff(attempt, 200, 2000);
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## ๐ฏ Performance
|
|
402
|
+
|
|
403
|
+
- **Tree-shakeable**: Import only what you need
|
|
404
|
+
- **Template caching**: Compiled EJS templates cached in development
|
|
405
|
+
- **Lazy props**: Defer expensive computations until needed
|
|
406
|
+
- **Prefetching**: Preload likely navigation targets
|
|
407
|
+
- **Minified bundle**: ~40KB gzipped main entry
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## ๐ API Reference
|
|
412
|
+
|
|
413
|
+
### Middleware
|
|
414
|
+
|
|
415
|
+
| Export | Description |
|
|
416
|
+
|---|---|
|
|
417
|
+
| `inertia(options?)` | Express middleware factory |
|
|
418
|
+
| `createInertia(options?)` | Same as `inertia`, explicit name |
|
|
419
|
+
| `requestIdMiddleware()` | Assigns `req.id` for log correlation |
|
|
420
|
+
| `createInertiaEngine(options?)` | EJS view engine with Blade support |
|
|
421
|
+
| `inertiaEngine` | Default engine instance |
|
|
422
|
+
|
|
423
|
+
### Prop Helpers
|
|
424
|
+
|
|
425
|
+
| Export | Description |
|
|
426
|
+
|---|---|
|
|
427
|
+
| `lazy(fn)` | Omit on initial load |
|
|
428
|
+
| `always(fn)` | Always include |
|
|
429
|
+
| `defer(fn, opts?)` | Inertia v2 deferred prop |
|
|
430
|
+
| `merge(fn)` | Inertia v2 merge prop |
|
|
431
|
+
| `optional(fn)` | Inertia v2 optional prop |
|
|
432
|
+
| `resolveProps(props, req, isInertia)` | Resolve all prop wrappers |
|
|
433
|
+
|
|
434
|
+
### Utilities
|
|
435
|
+
|
|
436
|
+
| Export | Description |
|
|
437
|
+
|---|---|
|
|
438
|
+
| `validateComponentName(name, pattern?)` | Prevent path traversal |
|
|
439
|
+
| `sanitizeViewData(data)` | Strip functions from template data |
|
|
440
|
+
| `serializePage(page)` | Safe JSON serialization for HTML attributes |
|
|
441
|
+
| `safeStringify(obj)` | Circular-reference-safe JSON.stringify |
|
|
442
|
+
| `generateSriHash(content)` | SHA-384 SRI hash |
|
|
443
|
+
| `createLogger(opts?)` | Pluggable structured logger |
|
|
444
|
+
| `setGlobalLogger(logger)` | Replace global logger |
|
|
445
|
+
| `getGlobalLogger()` | Get current global logger |
|
|
446
|
+
|
|
447
|
+
### Resilience
|
|
448
|
+
|
|
449
|
+
| Export | Description |
|
|
450
|
+
|---|---|
|
|
451
|
+
| `CircuitBreaker` | CLOSED/OPEN/HALF_OPEN state machine |
|
|
452
|
+
| `shouldRetry(error, status, codes)` | Retry decision helper |
|
|
453
|
+
| `calculateBackoff(attempt, base, max)` | Exponential backoff with jitter |
|
|
454
|
+
| `resetAllCircuitBreakers()` | Bulk reset for testing |
|
|
455
|
+
|
|
456
|
+
### Vite
|
|
457
|
+
|
|
458
|
+
| Export | Description |
|
|
459
|
+
|---|---|
|
|
460
|
+
| `createViteHelper(config?)` | Vite asset resolver |
|
|
461
|
+
| `inertiaVitePlugin(opts?)` | Auto write/remove hot file |
|
|
462
|
+
| `createPrefetchHelper(viteHelper)` | Prefetch/preload generator |
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## ๐งช Testing
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
npm test
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Run the full test suite with Vitest (89 tests across 14 suites).
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## ๐ License
|
|
477
|
+
|
|
478
|
+
MIT ยฉ [Arpon](https://github.com/Arpon)
|
package/dist/base.ejs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
|
|
6
|
+
<title><%= typeof title !== 'undefined' ? title : (page && page.props && page.props.title ? page.props.title : 'App') %></title>
|
|
7
|
+
@inertiaHead
|
|
8
|
+
@viteReactRefresh
|
|
9
|
+
@vite('src/main.js')
|
|
10
|
+
</head>
|
|
11
|
+
<body class="font-sans antialiased bg-gray-50 text-gray-900">
|
|
12
|
+
@inertia
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { c as Page, d as SSRResult, B as BladeEngineOptions } from './types-Co2XESgs.mjs';
|
|
2
|
+
import 'express';
|
|
3
|
+
|
|
4
|
+
interface TemplateLocals extends Record<string, any> {
|
|
5
|
+
page?: Page;
|
|
6
|
+
ssr?: SSRResult | null;
|
|
7
|
+
_csrf?: string;
|
|
8
|
+
csrfToken?: string;
|
|
9
|
+
routes?: any;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates an Express view engine with Blade directive support and built-in Inertia/Vite helpers.
|
|
13
|
+
*/
|
|
14
|
+
declare function createInertiaEngine(options?: BladeEngineOptions): (filePath: string, rawOptions: Record<string, any>, callback: (err: Error | null, html?: string) => void) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Default Inertia Blade EJS engine instance.
|
|
17
|
+
*/
|
|
18
|
+
declare const inertiaEngine: (filePath: string, rawOptions: Record<string, any>, callback: (err: Error | null, html?: string) => void) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Clear all template engine caches (useful during testing or hot reloading).
|
|
21
|
+
*/
|
|
22
|
+
declare function clearEngineCache(): void;
|
|
23
|
+
|
|
24
|
+
export { type TemplateLocals, clearEngineCache, createInertiaEngine, inertiaEngine };
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { c as Page, d as SSRResult, B as BladeEngineOptions } from './types-Co2XESgs.js';
|
|
2
|
+
import 'express';
|
|
3
|
+
|
|
4
|
+
interface TemplateLocals extends Record<string, any> {
|
|
5
|
+
page?: Page;
|
|
6
|
+
ssr?: SSRResult | null;
|
|
7
|
+
_csrf?: string;
|
|
8
|
+
csrfToken?: string;
|
|
9
|
+
routes?: any;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates an Express view engine with Blade directive support and built-in Inertia/Vite helpers.
|
|
13
|
+
*/
|
|
14
|
+
declare function createInertiaEngine(options?: BladeEngineOptions): (filePath: string, rawOptions: Record<string, any>, callback: (err: Error | null, html?: string) => void) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Default Inertia Blade EJS engine instance.
|
|
17
|
+
*/
|
|
18
|
+
declare const inertiaEngine: (filePath: string, rawOptions: Record<string, any>, callback: (err: Error | null, html?: string) => void) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Clear all template engine caches (useful during testing or hot reloading).
|
|
21
|
+
*/
|
|
22
|
+
declare function clearEngineCache(): void;
|
|
23
|
+
|
|
24
|
+
export { type TemplateLocals, clearEngineCache, createInertiaEngine, inertiaEngine };
|