@gravito/ion 1.0.0-beta.5 → 1.0.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/README.md +2 -2
- package/README.zh-TW.md +1 -1
- package/dist/index.cjs +108 -46
- package/dist/{InertiaService.d.ts → index.d.cts} +46 -4
- package/dist/index.d.ts +120 -11
- package/dist/index.js +153 -0
- package/package.json +13 -10
- package/dist/InertiaService.d.ts.map +0 -1
- package/dist/index.cjs.map +0 -11
- package/dist/index.d.ts.map +0 -1
- package/dist/index.mjs +0 -89
- package/dist/index.mjs.map +0 -11
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Inertia.js adapter for Gravito. Build modern monoliths with React/Vue.
|
|
4
4
|
|
|
5
|
-
**Orbit Inertia** allows you to build single-page apps using classic server-side routing and controllers. It acts as the glue between Gravito (
|
|
5
|
+
**Orbit Inertia** allows you to build single-page apps using classic server-side routing and controllers. It acts as the glue between Gravito (Photon) and your frontend framework.
|
|
6
6
|
|
|
7
7
|
## ✨ Features
|
|
8
8
|
|
|
@@ -58,7 +58,7 @@ By default, Inertia looks for `src/views/app.html`. This is the "shell" of your
|
|
|
58
58
|
In your controllers, simply use `inertia.render()`:
|
|
59
59
|
|
|
60
60
|
```typescript
|
|
61
|
-
import { Context } from '
|
|
61
|
+
import { Context } from '@gravito/photon';
|
|
62
62
|
import { InertiaService } from '@gravito/ion';
|
|
63
63
|
|
|
64
64
|
export class HomeController {
|
package/README.zh-TW.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1,53 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
-
var __toCommonJS = (from) => {
|
|
7
|
-
var entry = __moduleCache.get(from), desc;
|
|
8
|
-
if (entry)
|
|
9
|
-
return entry;
|
|
10
|
-
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
-
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
-
get: () => from[key],
|
|
14
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
-
}));
|
|
16
|
-
__moduleCache.set(from, entry);
|
|
17
|
-
return entry;
|
|
18
|
-
};
|
|
19
6
|
var __export = (target, all) => {
|
|
20
7
|
for (var name in all)
|
|
21
|
-
__defProp(target, name, {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
27
17
|
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
19
|
|
|
29
20
|
// src/index.ts
|
|
30
|
-
var
|
|
31
|
-
__export(
|
|
32
|
-
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
InertiaService: () => InertiaService,
|
|
33
24
|
OrbitIon: () => OrbitIon,
|
|
34
|
-
|
|
25
|
+
default: () => index_default
|
|
35
26
|
});
|
|
36
|
-
module.exports = __toCommonJS(
|
|
37
|
-
var import_gravito_core = require("gravito-core");
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
38
28
|
|
|
39
29
|
// src/InertiaService.ts
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
var InertiaService = class {
|
|
31
|
+
/**
|
|
32
|
+
* Create a new InertiaService instance
|
|
33
|
+
*
|
|
34
|
+
* @param context - The Gravito request context
|
|
35
|
+
* @param config - Optional configuration
|
|
36
|
+
*/
|
|
44
37
|
constructor(context, config = {}) {
|
|
45
38
|
this.context = context;
|
|
46
39
|
this.config = config;
|
|
47
40
|
}
|
|
41
|
+
sharedProps = {};
|
|
42
|
+
/**
|
|
43
|
+
* Escape a string for safe use in HTML attributes
|
|
44
|
+
*
|
|
45
|
+
* Strategy: JSON.stringify already escapes special characters including
|
|
46
|
+
* quotes as \". We need to escape these for HTML attributes, but we must
|
|
47
|
+
* be careful not to break JSON escape sequences.
|
|
48
|
+
*
|
|
49
|
+
* The solution: Escape backslash-quote sequences (\" from JSON.stringify)
|
|
50
|
+
* as \\" so they become \\" in HTML, which the browser decodes
|
|
51
|
+
* to \\" (valid JSON), not \" (invalid JSON).
|
|
52
|
+
*
|
|
53
|
+
* @param value - The string to escape.
|
|
54
|
+
* @returns The escaped string.
|
|
55
|
+
*/
|
|
48
56
|
escapeForSingleQuotedHtmlAttribute(value) {
|
|
49
57
|
return value.replace(/&/g, "&").replace(/\\"/g, "\\"").replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'");
|
|
50
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Render an Inertia component
|
|
61
|
+
*
|
|
62
|
+
* @param component - The component name to render
|
|
63
|
+
* @param props - Props to pass to the component
|
|
64
|
+
* @param rootVars - Additional variables for the root template
|
|
65
|
+
* @returns HTTP Response
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* return inertia.render('Users/Index', {
|
|
70
|
+
* users: await User.all(),
|
|
71
|
+
* filters: { search: ctx.req.query('search') }
|
|
72
|
+
* })
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
51
75
|
render(component, props = {}, rootVars = {}) {
|
|
52
76
|
let pageUrl;
|
|
53
77
|
try {
|
|
@@ -79,41 +103,79 @@ class InertiaService {
|
|
|
79
103
|
if (!view) {
|
|
80
104
|
throw new Error("OrbitPrism is required for the initial page load in OrbitIon");
|
|
81
105
|
}
|
|
82
|
-
const isDev =
|
|
83
|
-
return this.context.html(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
106
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
107
|
+
return this.context.html(
|
|
108
|
+
view.render(
|
|
109
|
+
rootView,
|
|
110
|
+
{
|
|
111
|
+
...rootVars,
|
|
112
|
+
page: this.escapeForSingleQuotedHtmlAttribute(JSON.stringify(page)),
|
|
113
|
+
isDev
|
|
114
|
+
},
|
|
115
|
+
{ layout: "" }
|
|
116
|
+
)
|
|
117
|
+
);
|
|
88
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Share data with all Inertia responses
|
|
121
|
+
*
|
|
122
|
+
* Shared props are merged with component-specific props on every render.
|
|
123
|
+
*
|
|
124
|
+
* @param key - The prop key
|
|
125
|
+
* @param value - The prop value
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* // In middleware
|
|
130
|
+
* inertia.share('auth', { user: ctx.get('auth')?.user() })
|
|
131
|
+
* inertia.share('flash', ctx.get('session')?.getFlash('message'))
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
89
134
|
share(key, value) {
|
|
90
135
|
this.sharedProps[key] = value;
|
|
91
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Share multiple props at once
|
|
139
|
+
*
|
|
140
|
+
* @param props - Object of props to share
|
|
141
|
+
*/
|
|
92
142
|
shareAll(props) {
|
|
93
143
|
Object.assign(this.sharedProps, props);
|
|
94
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Get all shared props
|
|
147
|
+
*
|
|
148
|
+
* @returns A shallow copy of the shared props object.
|
|
149
|
+
*/
|
|
95
150
|
getSharedProps() {
|
|
96
151
|
return { ...this.sharedProps };
|
|
97
152
|
}
|
|
98
|
-
}
|
|
153
|
+
};
|
|
99
154
|
|
|
100
155
|
// src/index.ts
|
|
101
|
-
|
|
156
|
+
var OrbitIon = class {
|
|
157
|
+
/**
|
|
158
|
+
* Install the Inertia orbit into PlanetCore
|
|
159
|
+
*/
|
|
102
160
|
install(core) {
|
|
103
|
-
core.logger.info("\
|
|
161
|
+
core.logger.info("\u{1F6F0}\uFE0F Orbit Inertia installed");
|
|
104
162
|
const appVersion = core.config.get("APP_VERSION", "1.0.0");
|
|
105
163
|
core.adapter.use("*", async (c, next) => {
|
|
106
|
-
const gravitoCtx =
|
|
164
|
+
const gravitoCtx = c;
|
|
107
165
|
const inertia = new InertiaService(gravitoCtx, {
|
|
108
166
|
version: String(appVersion),
|
|
109
167
|
rootView: "app"
|
|
168
|
+
// Default to src/views/app.html
|
|
110
169
|
});
|
|
111
170
|
c.set("inertia", inertia);
|
|
112
171
|
await next();
|
|
113
|
-
return;
|
|
172
|
+
return void 0;
|
|
114
173
|
});
|
|
115
174
|
}
|
|
116
|
-
}
|
|
117
|
-
var
|
|
118
|
-
|
|
119
|
-
|
|
175
|
+
};
|
|
176
|
+
var index_default = OrbitIon;
|
|
177
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
178
|
+
0 && (module.exports = {
|
|
179
|
+
InertiaService,
|
|
180
|
+
OrbitIon
|
|
181
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { GravitoContext, GravitoVariables, GravitoOrbit, PlanetCore } from '@gravito/core';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @fileoverview Inertia.js Service for Gravito
|
|
3
5
|
*
|
|
@@ -7,11 +9,11 @@
|
|
|
7
9
|
* @module @gravito/ion
|
|
8
10
|
* @since 1.0.0
|
|
9
11
|
*/
|
|
10
|
-
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* Configuration options for InertiaService
|
|
13
15
|
*/
|
|
14
|
-
|
|
16
|
+
interface InertiaConfig {
|
|
15
17
|
/**
|
|
16
18
|
* The root view template name
|
|
17
19
|
* @default 'app'
|
|
@@ -37,7 +39,7 @@ export interface InertiaConfig {
|
|
|
37
39
|
* }
|
|
38
40
|
* ```
|
|
39
41
|
*/
|
|
40
|
-
|
|
42
|
+
declare class InertiaService {
|
|
41
43
|
private context;
|
|
42
44
|
private config;
|
|
43
45
|
private sharedProps;
|
|
@@ -109,4 +111,44 @@ export declare class InertiaService {
|
|
|
109
111
|
*/
|
|
110
112
|
getSharedProps(): Record<string, unknown>;
|
|
111
113
|
}
|
|
112
|
-
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @fileoverview Orbit Inertia - Inertia.js integration for Gravito
|
|
117
|
+
*
|
|
118
|
+
* Provides server-side Inertia.js integration for building modern
|
|
119
|
+
* single-page applications with server-side routing.
|
|
120
|
+
*
|
|
121
|
+
* @module @gravito/ion
|
|
122
|
+
* @since 1.0.0
|
|
123
|
+
*/
|
|
124
|
+
|
|
125
|
+
declare module '@gravito/core' {
|
|
126
|
+
interface GravitoVariables {
|
|
127
|
+
/** Inertia.js service for SPA rendering */
|
|
128
|
+
inertia?: InertiaService;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* OrbitIon - Inertia.js integration orbit
|
|
133
|
+
*
|
|
134
|
+
* This orbit provides seamless Inertia.js integration, enabling
|
|
135
|
+
* SPA-like navigation with server-side routing.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* import { PlanetCore, defineConfig } from '@gravito/core'
|
|
140
|
+
* import { OrbitIon } from '@gravito/ion'
|
|
141
|
+
*
|
|
142
|
+
* const core = await PlanetCore.boot(defineConfig({
|
|
143
|
+
* orbits: [OrbitIon]
|
|
144
|
+
* }))
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
declare class OrbitIon implements GravitoOrbit {
|
|
148
|
+
/**
|
|
149
|
+
* Install the Inertia orbit into PlanetCore
|
|
150
|
+
*/
|
|
151
|
+
install(core: PlanetCore): void;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export { type InertiaConfig, InertiaService, OrbitIon, OrbitIon as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,117 @@
|
|
|
1
|
+
import { GravitoContext, GravitoVariables, GravitoOrbit, PlanetCore } from '@gravito/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Inertia.js Service for Gravito
|
|
5
|
+
*
|
|
6
|
+
* Provides server-side Inertia.js integration for building modern
|
|
7
|
+
* single-page applications with server-side routing.
|
|
8
|
+
*
|
|
9
|
+
* @module @gravito/ion
|
|
10
|
+
* @since 1.0.0
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration options for InertiaService
|
|
15
|
+
*/
|
|
16
|
+
interface InertiaConfig {
|
|
17
|
+
/**
|
|
18
|
+
* The root view template name
|
|
19
|
+
* @default 'app'
|
|
20
|
+
*/
|
|
21
|
+
rootView?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Asset version for cache busting
|
|
24
|
+
*/
|
|
25
|
+
version?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* InertiaService - Server-side Inertia.js adapter
|
|
29
|
+
*
|
|
30
|
+
* This service handles the Inertia.js protocol for seamless
|
|
31
|
+
* SPA-like navigation with server-side routing.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* // In a controller
|
|
36
|
+
* async index(ctx: GravitoContext) {
|
|
37
|
+
* const inertia = ctx.get('inertia') as InertiaService
|
|
38
|
+
* return inertia.render('Home', { users: await User.all() })
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare class InertiaService {
|
|
43
|
+
private context;
|
|
44
|
+
private config;
|
|
45
|
+
private sharedProps;
|
|
46
|
+
/**
|
|
47
|
+
* Create a new InertiaService instance
|
|
48
|
+
*
|
|
49
|
+
* @param context - The Gravito request context
|
|
50
|
+
* @param config - Optional configuration
|
|
51
|
+
*/
|
|
52
|
+
constructor(context: GravitoContext<GravitoVariables>, config?: InertiaConfig);
|
|
53
|
+
/**
|
|
54
|
+
* Escape a string for safe use in HTML attributes
|
|
55
|
+
*
|
|
56
|
+
* Strategy: JSON.stringify already escapes special characters including
|
|
57
|
+
* quotes as \". We need to escape these for HTML attributes, but we must
|
|
58
|
+
* be careful not to break JSON escape sequences.
|
|
59
|
+
*
|
|
60
|
+
* The solution: Escape backslash-quote sequences (\" from JSON.stringify)
|
|
61
|
+
* as \\" so they become \\" in HTML, which the browser decodes
|
|
62
|
+
* to \\" (valid JSON), not \" (invalid JSON).
|
|
63
|
+
*
|
|
64
|
+
* @param value - The string to escape.
|
|
65
|
+
* @returns The escaped string.
|
|
66
|
+
*/
|
|
67
|
+
private escapeForSingleQuotedHtmlAttribute;
|
|
68
|
+
/**
|
|
69
|
+
* Render an Inertia component
|
|
70
|
+
*
|
|
71
|
+
* @param component - The component name to render
|
|
72
|
+
* @param props - Props to pass to the component
|
|
73
|
+
* @param rootVars - Additional variables for the root template
|
|
74
|
+
* @returns HTTP Response
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* return inertia.render('Users/Index', {
|
|
79
|
+
* users: await User.all(),
|
|
80
|
+
* filters: { search: ctx.req.query('search') }
|
|
81
|
+
* })
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
render(component: string, props?: Record<string, unknown>, rootVars?: Record<string, unknown>): Response;
|
|
85
|
+
/**
|
|
86
|
+
* Share data with all Inertia responses
|
|
87
|
+
*
|
|
88
|
+
* Shared props are merged with component-specific props on every render.
|
|
89
|
+
*
|
|
90
|
+
* @param key - The prop key
|
|
91
|
+
* @param value - The prop value
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* // In middleware
|
|
96
|
+
* inertia.share('auth', { user: ctx.get('auth')?.user() })
|
|
97
|
+
* inertia.share('flash', ctx.get('session')?.getFlash('message'))
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
share(key: string, value: unknown): void;
|
|
101
|
+
/**
|
|
102
|
+
* Share multiple props at once
|
|
103
|
+
*
|
|
104
|
+
* @param props - Object of props to share
|
|
105
|
+
*/
|
|
106
|
+
shareAll(props: Record<string, unknown>): void;
|
|
107
|
+
/**
|
|
108
|
+
* Get all shared props
|
|
109
|
+
*
|
|
110
|
+
* @returns A shallow copy of the shared props object.
|
|
111
|
+
*/
|
|
112
|
+
getSharedProps(): Record<string, unknown>;
|
|
113
|
+
}
|
|
114
|
+
|
|
1
115
|
/**
|
|
2
116
|
* @fileoverview Orbit Inertia - Inertia.js integration for Gravito
|
|
3
117
|
*
|
|
@@ -7,10 +121,8 @@
|
|
|
7
121
|
* @module @gravito/ion
|
|
8
122
|
* @since 1.0.0
|
|
9
123
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export * from './InertiaService';
|
|
13
|
-
declare module 'gravito-core' {
|
|
124
|
+
|
|
125
|
+
declare module '@gravito/core' {
|
|
14
126
|
interface GravitoVariables {
|
|
15
127
|
/** Inertia.js service for SPA rendering */
|
|
16
128
|
inertia?: InertiaService;
|
|
@@ -24,7 +136,7 @@ declare module 'gravito-core' {
|
|
|
24
136
|
*
|
|
25
137
|
* @example
|
|
26
138
|
* ```typescript
|
|
27
|
-
* import { PlanetCore, defineConfig } from 'gravito
|
|
139
|
+
* import { PlanetCore, defineConfig } from '@gravito/core'
|
|
28
140
|
* import { OrbitIon } from '@gravito/ion'
|
|
29
141
|
*
|
|
30
142
|
* const core = await PlanetCore.boot(defineConfig({
|
|
@@ -32,14 +144,11 @@ declare module 'gravito-core' {
|
|
|
32
144
|
* }))
|
|
33
145
|
* ```
|
|
34
146
|
*/
|
|
35
|
-
|
|
147
|
+
declare class OrbitIon implements GravitoOrbit {
|
|
36
148
|
/**
|
|
37
149
|
* Install the Inertia orbit into PlanetCore
|
|
38
150
|
*/
|
|
39
151
|
install(core: PlanetCore): void;
|
|
40
152
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
*/
|
|
44
|
-
export default OrbitIon;
|
|
45
|
-
//# sourceMappingURL=index.d.ts.map
|
|
153
|
+
|
|
154
|
+
export { type InertiaConfig, InertiaService, OrbitIon, OrbitIon as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// src/InertiaService.ts
|
|
2
|
+
var InertiaService = class {
|
|
3
|
+
/**
|
|
4
|
+
* Create a new InertiaService instance
|
|
5
|
+
*
|
|
6
|
+
* @param context - The Gravito request context
|
|
7
|
+
* @param config - Optional configuration
|
|
8
|
+
*/
|
|
9
|
+
constructor(context, config = {}) {
|
|
10
|
+
this.context = context;
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
sharedProps = {};
|
|
14
|
+
/**
|
|
15
|
+
* Escape a string for safe use in HTML attributes
|
|
16
|
+
*
|
|
17
|
+
* Strategy: JSON.stringify already escapes special characters including
|
|
18
|
+
* quotes as \". We need to escape these for HTML attributes, but we must
|
|
19
|
+
* be careful not to break JSON escape sequences.
|
|
20
|
+
*
|
|
21
|
+
* The solution: Escape backslash-quote sequences (\" from JSON.stringify)
|
|
22
|
+
* as \\" so they become \\" in HTML, which the browser decodes
|
|
23
|
+
* to \\" (valid JSON), not \" (invalid JSON).
|
|
24
|
+
*
|
|
25
|
+
* @param value - The string to escape.
|
|
26
|
+
* @returns The escaped string.
|
|
27
|
+
*/
|
|
28
|
+
escapeForSingleQuotedHtmlAttribute(value) {
|
|
29
|
+
return value.replace(/&/g, "&").replace(/\\"/g, "\\"").replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'");
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Render an Inertia component
|
|
33
|
+
*
|
|
34
|
+
* @param component - The component name to render
|
|
35
|
+
* @param props - Props to pass to the component
|
|
36
|
+
* @param rootVars - Additional variables for the root template
|
|
37
|
+
* @returns HTTP Response
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* return inertia.render('Users/Index', {
|
|
42
|
+
* users: await User.all(),
|
|
43
|
+
* filters: { search: ctx.req.query('search') }
|
|
44
|
+
* })
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
render(component, props = {}, rootVars = {}) {
|
|
48
|
+
let pageUrl;
|
|
49
|
+
try {
|
|
50
|
+
const reqUrl = new URL(this.context.req.url, "http://localhost");
|
|
51
|
+
pageUrl = reqUrl.pathname + reqUrl.search;
|
|
52
|
+
} catch {
|
|
53
|
+
pageUrl = this.context.req.url;
|
|
54
|
+
}
|
|
55
|
+
const resolveProps = (p) => {
|
|
56
|
+
const resolved = {};
|
|
57
|
+
for (const [key, value] of Object.entries(p)) {
|
|
58
|
+
resolved[key] = typeof value === "function" ? value() : value;
|
|
59
|
+
}
|
|
60
|
+
return resolved;
|
|
61
|
+
};
|
|
62
|
+
const page = {
|
|
63
|
+
component,
|
|
64
|
+
props: resolveProps({ ...this.sharedProps, ...props }),
|
|
65
|
+
url: pageUrl,
|
|
66
|
+
version: this.config.version
|
|
67
|
+
};
|
|
68
|
+
if (this.context.req.header("X-Inertia")) {
|
|
69
|
+
this.context.header("X-Inertia", "true");
|
|
70
|
+
this.context.header("Vary", "Accept");
|
|
71
|
+
return this.context.json(page);
|
|
72
|
+
}
|
|
73
|
+
const view = this.context.get("view");
|
|
74
|
+
const rootView = this.config.rootView ?? "app";
|
|
75
|
+
if (!view) {
|
|
76
|
+
throw new Error("OrbitPrism is required for the initial page load in OrbitIon");
|
|
77
|
+
}
|
|
78
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
79
|
+
return this.context.html(
|
|
80
|
+
view.render(
|
|
81
|
+
rootView,
|
|
82
|
+
{
|
|
83
|
+
...rootVars,
|
|
84
|
+
page: this.escapeForSingleQuotedHtmlAttribute(JSON.stringify(page)),
|
|
85
|
+
isDev
|
|
86
|
+
},
|
|
87
|
+
{ layout: "" }
|
|
88
|
+
)
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Share data with all Inertia responses
|
|
93
|
+
*
|
|
94
|
+
* Shared props are merged with component-specific props on every render.
|
|
95
|
+
*
|
|
96
|
+
* @param key - The prop key
|
|
97
|
+
* @param value - The prop value
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* // In middleware
|
|
102
|
+
* inertia.share('auth', { user: ctx.get('auth')?.user() })
|
|
103
|
+
* inertia.share('flash', ctx.get('session')?.getFlash('message'))
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
share(key, value) {
|
|
107
|
+
this.sharedProps[key] = value;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Share multiple props at once
|
|
111
|
+
*
|
|
112
|
+
* @param props - Object of props to share
|
|
113
|
+
*/
|
|
114
|
+
shareAll(props) {
|
|
115
|
+
Object.assign(this.sharedProps, props);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get all shared props
|
|
119
|
+
*
|
|
120
|
+
* @returns A shallow copy of the shared props object.
|
|
121
|
+
*/
|
|
122
|
+
getSharedProps() {
|
|
123
|
+
return { ...this.sharedProps };
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// src/index.ts
|
|
128
|
+
var OrbitIon = class {
|
|
129
|
+
/**
|
|
130
|
+
* Install the Inertia orbit into PlanetCore
|
|
131
|
+
*/
|
|
132
|
+
install(core) {
|
|
133
|
+
core.logger.info("\u{1F6F0}\uFE0F Orbit Inertia installed");
|
|
134
|
+
const appVersion = core.config.get("APP_VERSION", "1.0.0");
|
|
135
|
+
core.adapter.use("*", async (c, next) => {
|
|
136
|
+
const gravitoCtx = c;
|
|
137
|
+
const inertia = new InertiaService(gravitoCtx, {
|
|
138
|
+
version: String(appVersion),
|
|
139
|
+
rootView: "app"
|
|
140
|
+
// Default to src/views/app.html
|
|
141
|
+
});
|
|
142
|
+
c.set("inertia", inertia);
|
|
143
|
+
await next();
|
|
144
|
+
return void 0;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
var index_default = OrbitIon;
|
|
149
|
+
export {
|
|
150
|
+
InertiaService,
|
|
151
|
+
OrbitIon,
|
|
152
|
+
index_default as default
|
|
153
|
+
};
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravito/ion",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Inertia.js adapter for Gravito",
|
|
5
|
-
"module": "./dist/index.mjs",
|
|
6
5
|
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
|
-
"import": "./dist/index.
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
13
|
"require": "./dist/index.cjs"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
@@ -21,17 +21,20 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "bun run build.ts",
|
|
23
23
|
"test": "bun test",
|
|
24
|
-
"typecheck": "tsc --noEmit"
|
|
24
|
+
"typecheck": "bun tsc -p tsconfig.json --noEmit --skipLibCheck",
|
|
25
|
+
"test:coverage": "bun test --coverage --coverage-threshold=80",
|
|
26
|
+
"test:ci": "bun test --coverage --coverage-threshold=80"
|
|
25
27
|
},
|
|
26
28
|
"peerDependencies": {
|
|
27
|
-
"gravito
|
|
28
|
-
"
|
|
29
|
+
"@gravito/core": "workspace:*",
|
|
30
|
+
"@gravito/photon": "workspace:*"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
31
|
-
"gravito-core": "1.0.0-beta.5",
|
|
32
|
-
"hono": "^4.0.0",
|
|
33
33
|
"bun-types": "latest",
|
|
34
|
-
"
|
|
34
|
+
"@gravito/core": "workspace:*",
|
|
35
|
+
"@gravito/photon": "workspace:*",
|
|
36
|
+
"tsup": "^8.5.1",
|
|
37
|
+
"typescript": "^5.9.3"
|
|
35
38
|
},
|
|
36
39
|
"keywords": [
|
|
37
40
|
"gravito",
|
|
@@ -52,4 +55,4 @@
|
|
|
52
55
|
"url": "git+https://github.com/gravito-framework/gravito.git",
|
|
53
56
|
"directory": "packages/ion"
|
|
54
57
|
}
|
|
55
|
-
}
|
|
58
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"InertiaService.d.ts","sourceRoot":"","sources":["../src/InertiaService.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAe,MAAM,cAAc,CAAA;AAEjF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,cAAc;IAUvB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;IAVhB,OAAO,CAAC,WAAW,CAA8B;IAEjD;;;;;OAKG;gBAEO,OAAO,EAAE,cAAc,CAAC,gBAAgB,CAAC,EACzC,MAAM,GAAE,aAAkB;IAGpC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,kCAAkC;IAc1C;;;;;;;;;;;;;;;OAeG;IACI,MAAM,CACX,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACrC,QAAQ;IA4DX;;;;;;;;;;;;;;OAcG;IACI,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAI/C;;;;OAIG;IACI,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIrD;;;;OAIG;IACI,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAGjD"}
|
package/dist/index.cjs.map
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/InertiaService.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"/**\n * @fileoverview Orbit Inertia - Inertia.js integration for Gravito\n *\n * Provides server-side Inertia.js integration for building modern\n * single-page applications with server-side routing.\n *\n * @module @gravito/ion\n * @since 1.0.0\n */\n\nimport type { GravitoContext, GravitoOrbit, GravitoVariables, PlanetCore } from 'gravito-core'\nimport { HonoContextWrapper } from 'gravito-core'\nimport { InertiaService } from './InertiaService'\n\nexport * from './InertiaService'\n\n// Module augmentation for type-safe context injection\ndeclare module 'gravito-core' {\n interface GravitoVariables {\n /** Inertia.js service for SPA rendering */\n inertia?: InertiaService\n }\n}\n\n/**\n * OrbitIon - Inertia.js integration orbit\n *\n * This orbit provides seamless Inertia.js integration, enabling\n * SPA-like navigation with server-side routing.\n *\n * @example\n * ```typescript\n * import { PlanetCore, defineConfig } from 'gravito-core'\n * import { OrbitIon } from '@gravito/ion'\n *\n * const core = await PlanetCore.boot(defineConfig({\n * orbits: [OrbitIon]\n * }))\n * ```\n */\nexport class OrbitIon implements GravitoOrbit {\n /**\n * Install the Inertia orbit into PlanetCore\n */\n install(core: PlanetCore): void {\n core.logger.info('🛰️ Orbit Inertia installed')\n\n const appVersion = core.config.get('APP_VERSION', '1.0.0')\n\n // Register middleware to inject Inertia helper\n core.adapter.use('*', async (c: any, next: any) => {\n // Create GravitoContext wrapper for InertiaService\n // This allows InertiaService to use the abstraction layer\n const gravitoCtx = new HonoContextWrapper(c) as GravitoContext<GravitoVariables>\n\n // Initialize with config\n const inertia = new InertiaService(gravitoCtx, {\n version: String(appVersion),\n rootView: 'app', // Default to src/views/app.html\n })\n\n c.set('inertia', inertia)\n await next()\n return undefined\n })\n }\n}\n\n/**\n * Default export for convenience\n */\nexport default OrbitIon\n",
|
|
6
|
-
"/**\n * @fileoverview Inertia.js Service for Gravito\n *\n * Provides server-side Inertia.js integration for building modern\n * single-page applications with server-side routing.\n *\n * @module @gravito/ion\n * @since 1.0.0\n */\n\nimport type { GravitoContext, GravitoVariables, ViewService } from 'gravito-core'\n\n/**\n * Configuration options for InertiaService\n */\nexport interface InertiaConfig {\n /**\n * The root view template name\n * @default 'app'\n */\n rootView?: string\n\n /**\n * Asset version for cache busting\n */\n version?: string\n}\n\n/**\n * InertiaService - Server-side Inertia.js adapter\n *\n * This service handles the Inertia.js protocol for seamless\n * SPA-like navigation with server-side routing.\n *\n * @example\n * ```typescript\n * // In a controller\n * async index(ctx: GravitoContext) {\n * const inertia = ctx.get('inertia') as InertiaService\n * return inertia.render('Home', { users: await User.all() })\n * }\n * ```\n */\nexport class InertiaService {\n private sharedProps: Record<string, unknown> = {}\n\n /**\n * Create a new InertiaService instance\n *\n * @param context - The Gravito request context\n * @param config - Optional configuration\n */\n constructor(\n private context: GravitoContext<GravitoVariables>,\n private config: InertiaConfig = {}\n ) {}\n\n /**\n * Escape a string for safe use in HTML attributes\n *\n * Strategy: JSON.stringify already escapes special characters including\n * quotes as \\\". We need to escape these for HTML attributes, but we must\n * be careful not to break JSON escape sequences.\n *\n * The solution: Escape backslash-quote sequences (\\\" from JSON.stringify)\n * as \\\\" so they become \\\\" in HTML, which the browser decodes\n * to \\\\\" (valid JSON), not \\" (invalid JSON).\n *\n * @param value - The string to escape.\n * @returns The escaped string.\n */\n private escapeForSingleQuotedHtmlAttribute(value: string): string {\n // First escape ampersands to prevent breaking existing HTML entities\n // Then escape backslash-quote sequences (from JSON.stringify) as \\\\"\n // This ensures \\\" becomes \\\\" which decodes to \\\\\" (valid JSON)\n return value\n .replace(/&/g, '&')\n .replace(/\\\\\"/g, '\\\\"') // Escape \\\" as \\\\" (becomes \\\\\" after decode)\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/'/g, ''')\n // Note: We don't escape standalone \" because JSON.stringify already\n // escaped all quotes as \\\", so any remaining \" would be invalid JSON anyway\n }\n\n /**\n * Render an Inertia component\n *\n * @param component - The component name to render\n * @param props - Props to pass to the component\n * @param rootVars - Additional variables for the root template\n * @returns HTTP Response\n *\n * @example\n * ```typescript\n * return inertia.render('Users/Index', {\n * users: await User.all(),\n * filters: { search: ctx.req.query('search') }\n * })\n * ```\n */\n public render(\n component: string,\n props: Record<string, unknown> = {},\n rootVars: Record<string, unknown> = {}\n ): Response {\n // For SSG, use relative URL (pathname only) to avoid cross-origin issues\n let pageUrl: string\n try {\n const reqUrl = new URL(this.context.req.url, 'http://localhost')\n pageUrl = reqUrl.pathname + reqUrl.search\n } catch {\n // Fallback if URL parsing fails\n pageUrl = this.context.req.url\n }\n\n // Resolve lazy props (functions)\n const resolveProps = (p: Record<string, unknown>) => {\n const resolved: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(p)) {\n resolved[key] = typeof value === 'function' ? value() : value\n }\n return resolved\n }\n\n const page = {\n component,\n props: resolveProps({ ...this.sharedProps, ...props }),\n url: pageUrl,\n version: this.config.version,\n }\n\n // 1. If it's an Inertia request, return JSON\n if (this.context.req.header('X-Inertia')) {\n this.context.header('X-Inertia', 'true')\n this.context.header('Vary', 'Accept')\n return this.context.json(page)\n }\n\n // 2. Otherwise return the root HTML with data-page attribute\n // We assume there is a ViewService that handles the root template\n // The rootView should contain: <div id=\"app\" data-page='{{{ page }}}'></div>\n const view = this.context.get('view') as ViewService | undefined\n const rootView = this.config.rootView ?? 'app'\n\n if (!view) {\n throw new Error('OrbitPrism is required for the initial page load in OrbitIon')\n }\n\n // Detect development mode\n const isDev = process.env.NODE_ENV !== 'production'\n\n return this.context.html(\n view.render(\n rootView,\n {\n ...rootVars,\n page: this.escapeForSingleQuotedHtmlAttribute(JSON.stringify(page)),\n isDev,\n },\n { layout: '' }\n )\n )\n }\n\n /**\n * Share data with all Inertia responses\n *\n * Shared props are merged with component-specific props on every render.\n *\n * @param key - The prop key\n * @param value - The prop value\n *\n * @example\n * ```typescript\n * // In middleware\n * inertia.share('auth', { user: ctx.get('auth')?.user() })\n * inertia.share('flash', ctx.get('session')?.getFlash('message'))\n * ```\n */\n public share(key: string, value: unknown): void {\n this.sharedProps[key] = value\n }\n\n /**\n * Share multiple props at once\n *\n * @param props - Object of props to share\n */\n public shareAll(props: Record<string, unknown>): void {\n Object.assign(this.sharedProps, props)\n }\n\n /**\n * Get all shared props\n *\n * @returns A shallow copy of the shared props object.\n */\n public getSharedProps(): Record<string, unknown> {\n return { ...this.sharedProps }\n }\n}\n"
|
|
7
|
-
],
|
|
8
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWmC,IAAnC;;;ACgCO,MAAM,eAAe;AAAA,EAUhB;AAAA,EACA;AAAA,EAVF,cAAuC,CAAC;AAAA,EAQhD,WAAW,CACD,SACA,SAAwB,CAAC,GACjC;AAAA,IAFQ;AAAA,IACA;AAAA;AAAA,EAiBF,kCAAkC,CAAC,OAAuB;AAAA,IAIhE,OAAO,MACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,QAAQ,UAAU,EAC1B,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ;AAAA;AAAA,EAqBpB,MAAM,CACX,WACA,QAAiC,CAAC,GAClC,WAAoC,CAAC,GAC3B;AAAA,IAEV,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,MAAM,SAAS,IAAI,IAAI,KAAK,QAAQ,IAAI,KAAK,kBAAkB;AAAA,MAC/D,UAAU,OAAO,WAAW,OAAO;AAAA,MACnC,MAAM;AAAA,MAEN,UAAU,KAAK,QAAQ,IAAI;AAAA;AAAA,IAI7B,MAAM,eAAe,CAAC,MAA+B;AAAA,MACnD,MAAM,WAAoC,CAAC;AAAA,MAC3C,YAAY,KAAK,UAAU,OAAO,QAAQ,CAAC,GAAG;AAAA,QAC5C,SAAS,OAAO,OAAO,UAAU,aAAa,MAAM,IAAI;AAAA,MAC1D;AAAA,MACA,OAAO;AAAA;AAAA,IAGT,MAAM,OAAO;AAAA,MACX;AAAA,MACA,OAAO,aAAa,KAAK,KAAK,gBAAgB,MAAM,CAAC;AAAA,MACrD,KAAK;AAAA,MACL,SAAS,KAAK,OAAO;AAAA,IACvB;AAAA,IAGA,IAAI,KAAK,QAAQ,IAAI,OAAO,WAAW,GAAG;AAAA,MACxC,KAAK,QAAQ,OAAO,aAAa,MAAM;AAAA,MACvC,KAAK,QAAQ,OAAO,QAAQ,QAAQ;AAAA,MACpC,OAAO,KAAK,QAAQ,KAAK,IAAI;AAAA,IAC/B;AAAA,IAKA,MAAM,OAAO,KAAK,QAAQ,IAAI,MAAM;AAAA,IACpC,MAAM,WAAW,KAAK,OAAO,YAAY;AAAA,IAEzC,IAAI,CAAC,MAAM;AAAA,MACT,MAAM,IAAI,MAAM,8DAA8D;AAAA,IAChF;AAAA,IAGA,MAAM,QAAQ;AAAA,IAEd,OAAO,KAAK,QAAQ,KAClB,KAAK,OACH,UACA;AAAA,SACK;AAAA,MACH,MAAM,KAAK,mCAAmC,KAAK,UAAU,IAAI,CAAC;AAAA,MAClE;AAAA,IACF,GACA,EAAE,QAAQ,GAAG,CACf,CACF;AAAA;AAAA,EAkBK,KAAK,CAAC,KAAa,OAAsB;AAAA,IAC9C,KAAK,YAAY,OAAO;AAAA;AAAA,EAQnB,QAAQ,CAAC,OAAsC;AAAA,IACpD,OAAO,OAAO,KAAK,aAAa,KAAK;AAAA;AAAA,EAQhC,cAAc,GAA4B;AAAA,IAC/C,OAAO,KAAK,KAAK,YAAY;AAAA;AAEjC;;;ADjKO,MAAM,SAAiC;AAAA,EAI5C,OAAO,CAAC,MAAwB;AAAA,IAC9B,KAAK,OAAO,KAAK,uCAA4B;AAAA,IAE7C,MAAM,aAAa,KAAK,OAAO,IAAI,eAAe,OAAO;AAAA,IAGzD,KAAK,QAAQ,IAAI,KAAK,OAAO,GAAQ,SAAc;AAAA,MAGjD,MAAM,aAAa,IAAI,uCAAmB,CAAC;AAAA,MAG3C,MAAM,UAAU,IAAI,eAAe,YAAY;AAAA,QAC7C,SAAS,OAAO,UAAU;AAAA,QAC1B,UAAU;AAAA,MACZ,CAAC;AAAA,MAED,EAAE,IAAI,WAAW,OAAO;AAAA,MACxB,MAAM,KAAK;AAAA,MACX;AAAA,KACD;AAAA;AAEL;AAKA,IAAe;",
|
|
9
|
-
"debugId": "28569892347C834C64756E2164756E21",
|
|
10
|
-
"names": []
|
|
11
|
-
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAkB,YAAY,EAAoB,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9F,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjD,cAAc,kBAAkB,CAAA;AAGhC,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,gBAAgB;QACxB,2CAA2C;QAC3C,OAAO,CAAC,EAAE,cAAc,CAAA;KACzB;CACF;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,QAAS,YAAW,YAAY;IAC3C;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;CAsBhC;AAED;;GAEG;AACH,eAAe,QAAQ,CAAA"}
|
package/dist/index.mjs
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
import { HonoContextWrapper } from "gravito-core";
|
|
3
|
-
|
|
4
|
-
// src/InertiaService.ts
|
|
5
|
-
class InertiaService {
|
|
6
|
-
context;
|
|
7
|
-
config;
|
|
8
|
-
sharedProps = {};
|
|
9
|
-
constructor(context, config = {}) {
|
|
10
|
-
this.context = context;
|
|
11
|
-
this.config = config;
|
|
12
|
-
}
|
|
13
|
-
escapeForSingleQuotedHtmlAttribute(value) {
|
|
14
|
-
return value.replace(/&/g, "&").replace(/\\"/g, "\\"").replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'");
|
|
15
|
-
}
|
|
16
|
-
render(component, props = {}, rootVars = {}) {
|
|
17
|
-
let pageUrl;
|
|
18
|
-
try {
|
|
19
|
-
const reqUrl = new URL(this.context.req.url, "http://localhost");
|
|
20
|
-
pageUrl = reqUrl.pathname + reqUrl.search;
|
|
21
|
-
} catch {
|
|
22
|
-
pageUrl = this.context.req.url;
|
|
23
|
-
}
|
|
24
|
-
const resolveProps = (p) => {
|
|
25
|
-
const resolved = {};
|
|
26
|
-
for (const [key, value] of Object.entries(p)) {
|
|
27
|
-
resolved[key] = typeof value === "function" ? value() : value;
|
|
28
|
-
}
|
|
29
|
-
return resolved;
|
|
30
|
-
};
|
|
31
|
-
const page = {
|
|
32
|
-
component,
|
|
33
|
-
props: resolveProps({ ...this.sharedProps, ...props }),
|
|
34
|
-
url: pageUrl,
|
|
35
|
-
version: this.config.version
|
|
36
|
-
};
|
|
37
|
-
if (this.context.req.header("X-Inertia")) {
|
|
38
|
-
this.context.header("X-Inertia", "true");
|
|
39
|
-
this.context.header("Vary", "Accept");
|
|
40
|
-
return this.context.json(page);
|
|
41
|
-
}
|
|
42
|
-
const view = this.context.get("view");
|
|
43
|
-
const rootView = this.config.rootView ?? "app";
|
|
44
|
-
if (!view) {
|
|
45
|
-
throw new Error("OrbitPrism is required for the initial page load in OrbitIon");
|
|
46
|
-
}
|
|
47
|
-
const isDev = true;
|
|
48
|
-
return this.context.html(view.render(rootView, {
|
|
49
|
-
...rootVars,
|
|
50
|
-
page: this.escapeForSingleQuotedHtmlAttribute(JSON.stringify(page)),
|
|
51
|
-
isDev
|
|
52
|
-
}, { layout: "" }));
|
|
53
|
-
}
|
|
54
|
-
share(key, value) {
|
|
55
|
-
this.sharedProps[key] = value;
|
|
56
|
-
}
|
|
57
|
-
shareAll(props) {
|
|
58
|
-
Object.assign(this.sharedProps, props);
|
|
59
|
-
}
|
|
60
|
-
getSharedProps() {
|
|
61
|
-
return { ...this.sharedProps };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// src/index.ts
|
|
66
|
-
class OrbitIon {
|
|
67
|
-
install(core) {
|
|
68
|
-
core.logger.info("\uD83D\uDEF0️ Orbit Inertia installed");
|
|
69
|
-
const appVersion = core.config.get("APP_VERSION", "1.0.0");
|
|
70
|
-
core.adapter.use("*", async (c, next) => {
|
|
71
|
-
const gravitoCtx = new HonoContextWrapper(c);
|
|
72
|
-
const inertia = new InertiaService(gravitoCtx, {
|
|
73
|
-
version: String(appVersion),
|
|
74
|
-
rootView: "app"
|
|
75
|
-
});
|
|
76
|
-
c.set("inertia", inertia);
|
|
77
|
-
await next();
|
|
78
|
-
return;
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
var src_default = OrbitIon;
|
|
83
|
-
export {
|
|
84
|
-
src_default as default,
|
|
85
|
-
OrbitIon,
|
|
86
|
-
InertiaService
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
//# debugId=7A0FC6E9ACB58F0F64756E2164756E21
|
package/dist/index.mjs.map
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/InertiaService.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"/**\n * @fileoverview Orbit Inertia - Inertia.js integration for Gravito\n *\n * Provides server-side Inertia.js integration for building modern\n * single-page applications with server-side routing.\n *\n * @module @gravito/ion\n * @since 1.0.0\n */\n\nimport type { GravitoContext, GravitoOrbit, GravitoVariables, PlanetCore } from 'gravito-core'\nimport { HonoContextWrapper } from 'gravito-core'\nimport { InertiaService } from './InertiaService'\n\nexport * from './InertiaService'\n\n// Module augmentation for type-safe context injection\ndeclare module 'gravito-core' {\n interface GravitoVariables {\n /** Inertia.js service for SPA rendering */\n inertia?: InertiaService\n }\n}\n\n/**\n * OrbitIon - Inertia.js integration orbit\n *\n * This orbit provides seamless Inertia.js integration, enabling\n * SPA-like navigation with server-side routing.\n *\n * @example\n * ```typescript\n * import { PlanetCore, defineConfig } from 'gravito-core'\n * import { OrbitIon } from '@gravito/ion'\n *\n * const core = await PlanetCore.boot(defineConfig({\n * orbits: [OrbitIon]\n * }))\n * ```\n */\nexport class OrbitIon implements GravitoOrbit {\n /**\n * Install the Inertia orbit into PlanetCore\n */\n install(core: PlanetCore): void {\n core.logger.info('🛰️ Orbit Inertia installed')\n\n const appVersion = core.config.get('APP_VERSION', '1.0.0')\n\n // Register middleware to inject Inertia helper\n core.adapter.use('*', async (c: any, next: any) => {\n // Create GravitoContext wrapper for InertiaService\n // This allows InertiaService to use the abstraction layer\n const gravitoCtx = new HonoContextWrapper(c) as GravitoContext<GravitoVariables>\n\n // Initialize with config\n const inertia = new InertiaService(gravitoCtx, {\n version: String(appVersion),\n rootView: 'app', // Default to src/views/app.html\n })\n\n c.set('inertia', inertia)\n await next()\n return undefined\n })\n }\n}\n\n/**\n * Default export for convenience\n */\nexport default OrbitIon\n",
|
|
6
|
-
"/**\n * @fileoverview Inertia.js Service for Gravito\n *\n * Provides server-side Inertia.js integration for building modern\n * single-page applications with server-side routing.\n *\n * @module @gravito/ion\n * @since 1.0.0\n */\n\nimport type { GravitoContext, GravitoVariables, ViewService } from 'gravito-core'\n\n/**\n * Configuration options for InertiaService\n */\nexport interface InertiaConfig {\n /**\n * The root view template name\n * @default 'app'\n */\n rootView?: string\n\n /**\n * Asset version for cache busting\n */\n version?: string\n}\n\n/**\n * InertiaService - Server-side Inertia.js adapter\n *\n * This service handles the Inertia.js protocol for seamless\n * SPA-like navigation with server-side routing.\n *\n * @example\n * ```typescript\n * // In a controller\n * async index(ctx: GravitoContext) {\n * const inertia = ctx.get('inertia') as InertiaService\n * return inertia.render('Home', { users: await User.all() })\n * }\n * ```\n */\nexport class InertiaService {\n private sharedProps: Record<string, unknown> = {}\n\n /**\n * Create a new InertiaService instance\n *\n * @param context - The Gravito request context\n * @param config - Optional configuration\n */\n constructor(\n private context: GravitoContext<GravitoVariables>,\n private config: InertiaConfig = {}\n ) {}\n\n /**\n * Escape a string for safe use in HTML attributes\n *\n * Strategy: JSON.stringify already escapes special characters including\n * quotes as \\\". We need to escape these for HTML attributes, but we must\n * be careful not to break JSON escape sequences.\n *\n * The solution: Escape backslash-quote sequences (\\\" from JSON.stringify)\n * as \\\\" so they become \\\\" in HTML, which the browser decodes\n * to \\\\\" (valid JSON), not \\" (invalid JSON).\n *\n * @param value - The string to escape.\n * @returns The escaped string.\n */\n private escapeForSingleQuotedHtmlAttribute(value: string): string {\n // First escape ampersands to prevent breaking existing HTML entities\n // Then escape backslash-quote sequences (from JSON.stringify) as \\\\"\n // This ensures \\\" becomes \\\\" which decodes to \\\\\" (valid JSON)\n return value\n .replace(/&/g, '&')\n .replace(/\\\\\"/g, '\\\\"') // Escape \\\" as \\\\" (becomes \\\\\" after decode)\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/'/g, ''')\n // Note: We don't escape standalone \" because JSON.stringify already\n // escaped all quotes as \\\", so any remaining \" would be invalid JSON anyway\n }\n\n /**\n * Render an Inertia component\n *\n * @param component - The component name to render\n * @param props - Props to pass to the component\n * @param rootVars - Additional variables for the root template\n * @returns HTTP Response\n *\n * @example\n * ```typescript\n * return inertia.render('Users/Index', {\n * users: await User.all(),\n * filters: { search: ctx.req.query('search') }\n * })\n * ```\n */\n public render(\n component: string,\n props: Record<string, unknown> = {},\n rootVars: Record<string, unknown> = {}\n ): Response {\n // For SSG, use relative URL (pathname only) to avoid cross-origin issues\n let pageUrl: string\n try {\n const reqUrl = new URL(this.context.req.url, 'http://localhost')\n pageUrl = reqUrl.pathname + reqUrl.search\n } catch {\n // Fallback if URL parsing fails\n pageUrl = this.context.req.url\n }\n\n // Resolve lazy props (functions)\n const resolveProps = (p: Record<string, unknown>) => {\n const resolved: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(p)) {\n resolved[key] = typeof value === 'function' ? value() : value\n }\n return resolved\n }\n\n const page = {\n component,\n props: resolveProps({ ...this.sharedProps, ...props }),\n url: pageUrl,\n version: this.config.version,\n }\n\n // 1. If it's an Inertia request, return JSON\n if (this.context.req.header('X-Inertia')) {\n this.context.header('X-Inertia', 'true')\n this.context.header('Vary', 'Accept')\n return this.context.json(page)\n }\n\n // 2. Otherwise return the root HTML with data-page attribute\n // We assume there is a ViewService that handles the root template\n // The rootView should contain: <div id=\"app\" data-page='{{{ page }}}'></div>\n const view = this.context.get('view') as ViewService | undefined\n const rootView = this.config.rootView ?? 'app'\n\n if (!view) {\n throw new Error('OrbitPrism is required for the initial page load in OrbitIon')\n }\n\n // Detect development mode\n const isDev = process.env.NODE_ENV !== 'production'\n\n return this.context.html(\n view.render(\n rootView,\n {\n ...rootVars,\n page: this.escapeForSingleQuotedHtmlAttribute(JSON.stringify(page)),\n isDev,\n },\n { layout: '' }\n )\n )\n }\n\n /**\n * Share data with all Inertia responses\n *\n * Shared props are merged with component-specific props on every render.\n *\n * @param key - The prop key\n * @param value - The prop value\n *\n * @example\n * ```typescript\n * // In middleware\n * inertia.share('auth', { user: ctx.get('auth')?.user() })\n * inertia.share('flash', ctx.get('session')?.getFlash('message'))\n * ```\n */\n public share(key: string, value: unknown): void {\n this.sharedProps[key] = value\n }\n\n /**\n * Share multiple props at once\n *\n * @param props - Object of props to share\n */\n public shareAll(props: Record<string, unknown>): void {\n Object.assign(this.sharedProps, props)\n }\n\n /**\n * Get all shared props\n *\n * @returns A shallow copy of the shared props object.\n */\n public getSharedProps(): Record<string, unknown> {\n return { ...this.sharedProps }\n }\n}\n"
|
|
7
|
-
],
|
|
8
|
-
"mappings": ";AAWA;;;ACgCO,MAAM,eAAe;AAAA,EAUhB;AAAA,EACA;AAAA,EAVF,cAAuC,CAAC;AAAA,EAQhD,WAAW,CACD,SACA,SAAwB,CAAC,GACjC;AAAA,IAFQ;AAAA,IACA;AAAA;AAAA,EAiBF,kCAAkC,CAAC,OAAuB;AAAA,IAIhE,OAAO,MACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,QAAQ,UAAU,EAC1B,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ;AAAA;AAAA,EAqBpB,MAAM,CACX,WACA,QAAiC,CAAC,GAClC,WAAoC,CAAC,GAC3B;AAAA,IAEV,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,MAAM,SAAS,IAAI,IAAI,KAAK,QAAQ,IAAI,KAAK,kBAAkB;AAAA,MAC/D,UAAU,OAAO,WAAW,OAAO;AAAA,MACnC,MAAM;AAAA,MAEN,UAAU,KAAK,QAAQ,IAAI;AAAA;AAAA,IAI7B,MAAM,eAAe,CAAC,MAA+B;AAAA,MACnD,MAAM,WAAoC,CAAC;AAAA,MAC3C,YAAY,KAAK,UAAU,OAAO,QAAQ,CAAC,GAAG;AAAA,QAC5C,SAAS,OAAO,OAAO,UAAU,aAAa,MAAM,IAAI;AAAA,MAC1D;AAAA,MACA,OAAO;AAAA;AAAA,IAGT,MAAM,OAAO;AAAA,MACX;AAAA,MACA,OAAO,aAAa,KAAK,KAAK,gBAAgB,MAAM,CAAC;AAAA,MACrD,KAAK;AAAA,MACL,SAAS,KAAK,OAAO;AAAA,IACvB;AAAA,IAGA,IAAI,KAAK,QAAQ,IAAI,OAAO,WAAW,GAAG;AAAA,MACxC,KAAK,QAAQ,OAAO,aAAa,MAAM;AAAA,MACvC,KAAK,QAAQ,OAAO,QAAQ,QAAQ;AAAA,MACpC,OAAO,KAAK,QAAQ,KAAK,IAAI;AAAA,IAC/B;AAAA,IAKA,MAAM,OAAO,KAAK,QAAQ,IAAI,MAAM;AAAA,IACpC,MAAM,WAAW,KAAK,OAAO,YAAY;AAAA,IAEzC,IAAI,CAAC,MAAM;AAAA,MACT,MAAM,IAAI,MAAM,8DAA8D;AAAA,IAChF;AAAA,IAGA,MAAM,QAAQ;AAAA,IAEd,OAAO,KAAK,QAAQ,KAClB,KAAK,OACH,UACA;AAAA,SACK;AAAA,MACH,MAAM,KAAK,mCAAmC,KAAK,UAAU,IAAI,CAAC;AAAA,MAClE;AAAA,IACF,GACA,EAAE,QAAQ,GAAG,CACf,CACF;AAAA;AAAA,EAkBK,KAAK,CAAC,KAAa,OAAsB;AAAA,IAC9C,KAAK,YAAY,OAAO;AAAA;AAAA,EAQnB,QAAQ,CAAC,OAAsC;AAAA,IACpD,OAAO,OAAO,KAAK,aAAa,KAAK;AAAA;AAAA,EAQhC,cAAc,GAA4B;AAAA,IAC/C,OAAO,KAAK,KAAK,YAAY;AAAA;AAEjC;;;ADjKO,MAAM,SAAiC;AAAA,EAI5C,OAAO,CAAC,MAAwB;AAAA,IAC9B,KAAK,OAAO,KAAK,uCAA4B;AAAA,IAE7C,MAAM,aAAa,KAAK,OAAO,IAAI,eAAe,OAAO;AAAA,IAGzD,KAAK,QAAQ,IAAI,KAAK,OAAO,GAAQ,SAAc;AAAA,MAGjD,MAAM,aAAa,IAAI,mBAAmB,CAAC;AAAA,MAG3C,MAAM,UAAU,IAAI,eAAe,YAAY;AAAA,QAC7C,SAAS,OAAO,UAAU;AAAA,QAC1B,UAAU;AAAA,MACZ,CAAC;AAAA,MAED,EAAE,IAAI,WAAW,OAAO;AAAA,MACxB,MAAM,KAAK;AAAA,MACX;AAAA,KACD;AAAA;AAEL;AAKA,IAAe;",
|
|
9
|
-
"debugId": "7A0FC6E9ACB58F0F64756E2164756E21",
|
|
10
|
-
"names": []
|
|
11
|
-
}
|