@adonisjs/inertia 1.0.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/LICENSE.md +9 -0
- package/README.md +33 -0
- package/build/configure.js +82 -0
- package/build/index.d.ts +3 -0
- package/build/index.js +11 -0
- package/build/providers/inertia_provider.d.ts +26 -0
- package/build/providers/inertia_provider.js +46 -0
- package/build/src/debug.d.ts +3 -0
- package/build/src/debug.js +10 -0
- package/build/src/define_config.d.ts +5 -0
- package/build/src/define_config.js +14 -0
- package/build/src/inertia.d.ts +39 -0
- package/build/src/inertia.js +119 -0
- package/build/src/inertia_middleware.d.ts +12 -0
- package/build/src/inertia_middleware.js +47 -0
- package/build/src/plugins/api_client.d.ts +37 -0
- package/build/src/plugins/api_client.js +62 -0
- package/build/src/plugins/edge.d.ts +5 -0
- package/build/src/plugins/edge.js +43 -0
- package/build/src/types.d.ts +32 -0
- package/build/src/types.js +9 -0
- package/build/src/version_cache.d.ts +27 -0
- package/build/src/version_cache.js +68 -0
- package/build/stubs/config.stub +18 -0
- package/build/stubs/main.d.ts +1 -0
- package/build/stubs/main.js +10 -0
- package/package.json +126 -0
- package/providers/inertia_provider.ts +66 -0
- package/src/debug.ts +12 -0
- package/src/define_config.ts +17 -0
- package/src/inertia.ts +140 -0
- package/src/inertia_middleware.ts +54 -0
- package/src/plugins/api_client.ts +127 -0
- package/src/plugins/edge.ts +50 -0
- package/src/types.ts +48 -0
- package/src/version_cache.ts +74 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @adonisjs/inertia
|
|
2
|
+
|
|
3
|
+
<br />
|
|
4
|
+
|
|
5
|
+
[![gh-workflow-image]][gh-workflow-url] [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url]
|
|
6
|
+
|
|
7
|
+
## Introduction
|
|
8
|
+
Official [Inertia.js](https://inertiajs.com/) adapter for AdonisJS.
|
|
9
|
+
|
|
10
|
+
## Official Documentation
|
|
11
|
+
The documentation is available on the [AdonisJS website](https://docs.adonisjs.com/guides/inertia/introduction).
|
|
12
|
+
|
|
13
|
+
## Contributing
|
|
14
|
+
One of the primary goals of AdonisJS is to have a vibrant community of users and contributors who believes in the principles of the framework.
|
|
15
|
+
|
|
16
|
+
We encourage you to read the [contribution guide](https://github.com/adonisjs/.github/blob/main/docs/CONTRIBUTING.md) before contributing to the framework.
|
|
17
|
+
|
|
18
|
+
## Code of Conduct
|
|
19
|
+
In order to ensure that the AdonisJS community is welcoming to all, please review and abide by the [Code of Conduct](https://github.com/adonisjs/.github/blob/main/docs/CODE_OF_CONDUCT.md).
|
|
20
|
+
|
|
21
|
+
## License
|
|
22
|
+
AdonisJS Lucid is open-sourced software licensed under the [MIT license](LICENSE.md).
|
|
23
|
+
|
|
24
|
+
[gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/adonisjs/inertia/test.yml?style=for-the-badge
|
|
25
|
+
[gh-workflow-url]: https://github.com/adonisjs/inertia/actions/workflows/test.yml "Github action"
|
|
26
|
+
|
|
27
|
+
[npm-image]: https://img.shields.io/npm/v/@adonisjs/inertia/latest.svg?style=for-the-badge&logo=npm
|
|
28
|
+
[npm-url]: https://www.npmjs.com/package/@adonisjs/inertia/v/latest "npm"
|
|
29
|
+
|
|
30
|
+
[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
|
|
31
|
+
|
|
32
|
+
[license-url]: LICENSE.md
|
|
33
|
+
[license-image]: https://img.shields.io/github/license/adonisjs/inertia?style=for-the-badge
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/inertia
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
const ADAPTERS = ['Vue 3', 'React', 'Svelte'];
|
|
10
|
+
const ADAPTERS_INFO = {
|
|
11
|
+
'Vue 3': {
|
|
12
|
+
dependencies: [
|
|
13
|
+
{ name: '@inertiajs/vue3', isDevDependency: false },
|
|
14
|
+
{ name: 'vue', isDevDependency: false },
|
|
15
|
+
{ name: '@vitejs/plugin-vue', isDevDependency: true },
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
'React': {
|
|
19
|
+
dependencies: [
|
|
20
|
+
{ name: '@inertiajs/inertia-react', isDevDependency: false },
|
|
21
|
+
{ name: 'react', isDevDependency: false },
|
|
22
|
+
{ name: 'react-dom', isDevDependency: false },
|
|
23
|
+
{ name: '@vitejs/plugin-react', isDevDependency: true },
|
|
24
|
+
{ name: '@types/react', isDevDependency: true },
|
|
25
|
+
{ name: '@types/react-dom', isDevDependency: true },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
'Svelte': {
|
|
29
|
+
dependencies: [
|
|
30
|
+
{ name: '@inertiajs/inertia-svelte', isDevDependency: false },
|
|
31
|
+
{ name: 'svelte', isDevDependency: false },
|
|
32
|
+
{ name: '@sveltejs/vite-plugin-svelte', isDevDependency: true },
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Configures the package
|
|
38
|
+
*/
|
|
39
|
+
export async function configure(command) {
|
|
40
|
+
/**
|
|
41
|
+
* Prompt for adapter
|
|
42
|
+
*/
|
|
43
|
+
const adapter = await command.prompt.choice('Select the Inertia adapter you want to use', ADAPTERS, { name: 'adapter' });
|
|
44
|
+
const pkgToInstall = ADAPTERS_INFO[adapter].dependencies;
|
|
45
|
+
/**
|
|
46
|
+
* Prompt for SSR
|
|
47
|
+
*/
|
|
48
|
+
const withSsr = await command.prompt.confirm('Do you want to enable server-side rendering?', {
|
|
49
|
+
name: 'ssr',
|
|
50
|
+
});
|
|
51
|
+
if (withSsr) {
|
|
52
|
+
pkgToInstall.push(...(ADAPTERS_INFO[adapter].ssrDependencies || []));
|
|
53
|
+
}
|
|
54
|
+
const codemods = await command.createCodemods();
|
|
55
|
+
/**
|
|
56
|
+
* Publish provider
|
|
57
|
+
*/
|
|
58
|
+
await codemods.updateRcFile((rcFile) => {
|
|
59
|
+
rcFile.addProvider('@adonisjs/inertia/inertia_provider');
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* Add Inertia middleware
|
|
63
|
+
*/
|
|
64
|
+
codemods.registerMiddleware('router', [
|
|
65
|
+
{ path: '@adonisjs/inertia/inertia_middleware', position: 'after' },
|
|
66
|
+
]);
|
|
67
|
+
/**
|
|
68
|
+
* Publish config
|
|
69
|
+
*/
|
|
70
|
+
await command.publishStub('config.stub');
|
|
71
|
+
/**
|
|
72
|
+
* Install packages
|
|
73
|
+
*/
|
|
74
|
+
const shouldInstallPackages = await command.prompt.confirm(`Do you want to install dependencies ${pkgToInstall.map((pkg) => pkg.name).join(', ')}?`, { name: 'install' });
|
|
75
|
+
if (shouldInstallPackages) {
|
|
76
|
+
command.installPackages(pkgToInstall);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
command.listPackagesToInstall(pkgToInstall);
|
|
80
|
+
}
|
|
81
|
+
command.logger.success('Inertia was configured successfully. Please note that you still need to update your vite config, setup your Edge root view and others things. Read the docs for more info.');
|
|
82
|
+
}
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/inertia
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
export { configure } from './configure.js';
|
|
10
|
+
export { stubsRoot } from './stubs/main.js';
|
|
11
|
+
export { defineConfig } from './src/define_config.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ApplicationService } from '@adonisjs/core/types';
|
|
2
|
+
import { Inertia } from '../src/inertia.js';
|
|
3
|
+
/**
|
|
4
|
+
* HttpContext augmentations
|
|
5
|
+
*/
|
|
6
|
+
declare module '@adonisjs/core/http' {
|
|
7
|
+
interface HttpContext {
|
|
8
|
+
inertia: Inertia;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Inertia provider
|
|
13
|
+
*/
|
|
14
|
+
export default class InertiaProvider {
|
|
15
|
+
protected app: ApplicationService;
|
|
16
|
+
constructor(app: ApplicationService);
|
|
17
|
+
/**
|
|
18
|
+
* Registers edge plugin when edge is installed
|
|
19
|
+
*/
|
|
20
|
+
protected registerEdgePlugin(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Register Inertia middleware, edge plugin, and add
|
|
23
|
+
* `inertia` property to the HttpContext
|
|
24
|
+
*/
|
|
25
|
+
boot(): Promise<void>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/inertia
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { HttpContext } from '@adonisjs/core/http';
|
|
10
|
+
import { Inertia } from '../src/inertia.js';
|
|
11
|
+
import { VersionCache } from '../src/version_cache.js';
|
|
12
|
+
import InertiaMiddleware from '../src/inertia_middleware.js';
|
|
13
|
+
/**
|
|
14
|
+
* Inertia provider
|
|
15
|
+
*/
|
|
16
|
+
export default class InertiaProvider {
|
|
17
|
+
app;
|
|
18
|
+
constructor(app) {
|
|
19
|
+
this.app = app;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Registers edge plugin when edge is installed
|
|
23
|
+
*/
|
|
24
|
+
async registerEdgePlugin() {
|
|
25
|
+
try {
|
|
26
|
+
const edgeExports = await import('edge.js');
|
|
27
|
+
const { edgePluginInertia } = await import('../src/plugins/edge.js');
|
|
28
|
+
edgeExports.default.use(edgePluginInertia());
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Register Inertia middleware, edge plugin, and add
|
|
34
|
+
* `inertia` property to the HttpContext
|
|
35
|
+
*/
|
|
36
|
+
async boot() {
|
|
37
|
+
const appRoot = this.app.appRoot;
|
|
38
|
+
const config = this.app.config.get('inertia', { view: 'app' });
|
|
39
|
+
const versionCache = await new VersionCache(appRoot, config.assetsVersion).computeVersion();
|
|
40
|
+
this.app.container.singleton(InertiaMiddleware, () => new InertiaMiddleware(versionCache));
|
|
41
|
+
HttpContext.getter('inertia', function inertia() {
|
|
42
|
+
return new Inertia(this, config, versionCache.getVersion());
|
|
43
|
+
}, false);
|
|
44
|
+
await this.registerEdgePlugin();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/inertia
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { debuglog } from 'node:util';
|
|
10
|
+
export default debuglog('adonisjs:inertia');
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/inertia
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Define the Inertia configuration
|
|
11
|
+
*/
|
|
12
|
+
export function defineConfig(config) {
|
|
13
|
+
return config;
|
|
14
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
2
|
+
import type { InertiaConfig, MaybePromise, PageProps, AssetsVersion } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Main class used to interact with Inertia
|
|
5
|
+
*/
|
|
6
|
+
export declare class Inertia {
|
|
7
|
+
#private;
|
|
8
|
+
protected ctx: HttpContext;
|
|
9
|
+
protected config: InertiaConfig;
|
|
10
|
+
protected version: AssetsVersion;
|
|
11
|
+
constructor(ctx: HttpContext, config: InertiaConfig, version: AssetsVersion);
|
|
12
|
+
/**
|
|
13
|
+
* Render a page using Inertia
|
|
14
|
+
*/
|
|
15
|
+
render(component: string, pageProps?: PageProps): Promise<string | {
|
|
16
|
+
component: string;
|
|
17
|
+
version: AssetsVersion;
|
|
18
|
+
props: any;
|
|
19
|
+
url: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Create a lazy prop
|
|
23
|
+
*
|
|
24
|
+
* Lazy props are never resolved on first visit, but only when the client
|
|
25
|
+
* request a partial reload explicitely with this value.
|
|
26
|
+
*
|
|
27
|
+
* See https://inertiajs.com/partial-reloads#lazy-data-evaluation
|
|
28
|
+
*/
|
|
29
|
+
lazy(callback: () => MaybePromise<any>): {
|
|
30
|
+
[x: symbol]: () => MaybePromise<any>;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* This method can be used to redirect the user to an external website
|
|
34
|
+
* or even a non-inertia route of your application.
|
|
35
|
+
*
|
|
36
|
+
* See https://inertiajs.com/redirects#external-redirects
|
|
37
|
+
*/
|
|
38
|
+
location(url: string): Promise<void>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/inertia
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Main class used to interact with Inertia
|
|
11
|
+
*/
|
|
12
|
+
export class Inertia {
|
|
13
|
+
ctx;
|
|
14
|
+
config;
|
|
15
|
+
version;
|
|
16
|
+
/**
|
|
17
|
+
* The name of the Edge view that will be used to render the page.
|
|
18
|
+
*/
|
|
19
|
+
#edgeRootView;
|
|
20
|
+
/**
|
|
21
|
+
* Symbol used to identify lazy props
|
|
22
|
+
*/
|
|
23
|
+
#kLazySymbol = Symbol('lazy');
|
|
24
|
+
constructor(ctx, config = {}, version) {
|
|
25
|
+
this.ctx = ctx;
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.version = version;
|
|
28
|
+
this.#edgeRootView = config.rootView || 'root';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Check if a value is a lazy prop
|
|
32
|
+
*/
|
|
33
|
+
#isLazyProps(value) {
|
|
34
|
+
return typeof value === 'object' && value && this.#kLazySymbol in value;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Pick props to resolve based on x-inertia-partial-data header
|
|
38
|
+
*
|
|
39
|
+
* If header is not present, resolve all props except lazy props
|
|
40
|
+
* If header is present, resolve only the props that are listed in the header
|
|
41
|
+
*/
|
|
42
|
+
#pickPropsToResolve(component, props) {
|
|
43
|
+
const partialData = this.ctx.request
|
|
44
|
+
.header('x-inertia-partial-data')
|
|
45
|
+
?.split(',')
|
|
46
|
+
.filter(Boolean);
|
|
47
|
+
const partialComponent = this.ctx.request.header('x-inertia-partial-component');
|
|
48
|
+
let entriesToResolve = Object.entries(props);
|
|
49
|
+
if (partialData && partialComponent === component) {
|
|
50
|
+
entriesToResolve = entriesToResolve.filter(([key]) => partialData.includes(key));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
entriesToResolve = entriesToResolve.filter(([key]) => !this.#isLazyProps(props[key]));
|
|
54
|
+
}
|
|
55
|
+
return entriesToResolve;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the props that will be sent to the client
|
|
59
|
+
*/
|
|
60
|
+
async #resolvePageProps(component, props) {
|
|
61
|
+
const entriesToResolve = this.#pickPropsToResolve(component, props);
|
|
62
|
+
const entries = entriesToResolve.map(async ([key, value]) => {
|
|
63
|
+
if (typeof value === 'function') {
|
|
64
|
+
return [key, await value(this.ctx)];
|
|
65
|
+
}
|
|
66
|
+
if (this.#isLazyProps(value)) {
|
|
67
|
+
const lazyValue = value[this.#kLazySymbol];
|
|
68
|
+
return [key, await lazyValue()];
|
|
69
|
+
}
|
|
70
|
+
return [key, value];
|
|
71
|
+
});
|
|
72
|
+
return Object.fromEntries(await Promise.all(entries));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Build the page object that will be returned to the client
|
|
76
|
+
*
|
|
77
|
+
* See https://inertiajs.com/the-protocol#the-page-object
|
|
78
|
+
*/
|
|
79
|
+
async #buildPageObject(component, pageProps) {
|
|
80
|
+
return {
|
|
81
|
+
component,
|
|
82
|
+
version: this.version,
|
|
83
|
+
props: await this.#resolvePageProps(component, { ...this.config.sharedData, ...pageProps }),
|
|
84
|
+
url: this.ctx.request.url(true),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Render a page using Inertia
|
|
89
|
+
*/
|
|
90
|
+
async render(component, pageProps) {
|
|
91
|
+
const pageObject = await this.#buildPageObject(component, pageProps);
|
|
92
|
+
const isInertiaRequest = !!this.ctx.request.header('x-inertia');
|
|
93
|
+
if (!isInertiaRequest) {
|
|
94
|
+
return this.ctx.view.render(this.#edgeRootView, { page: pageObject });
|
|
95
|
+
}
|
|
96
|
+
return pageObject;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create a lazy prop
|
|
100
|
+
*
|
|
101
|
+
* Lazy props are never resolved on first visit, but only when the client
|
|
102
|
+
* request a partial reload explicitely with this value.
|
|
103
|
+
*
|
|
104
|
+
* See https://inertiajs.com/partial-reloads#lazy-data-evaluation
|
|
105
|
+
*/
|
|
106
|
+
lazy(callback) {
|
|
107
|
+
return { [this.#kLazySymbol]: callback };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* This method can be used to redirect the user to an external website
|
|
111
|
+
* or even a non-inertia route of your application.
|
|
112
|
+
*
|
|
113
|
+
* See https://inertiajs.com/redirects#external-redirects
|
|
114
|
+
*/
|
|
115
|
+
async location(url) {
|
|
116
|
+
this.ctx.response.header('X-Inertia-Location', url);
|
|
117
|
+
this.ctx.response.status(409);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
2
|
+
import type { NextFn } from '@adonisjs/core/types/http';
|
|
3
|
+
import type { VersionCache } from './version_cache.js';
|
|
4
|
+
/**
|
|
5
|
+
* Inertia middleware to handle the Inertia requests and
|
|
6
|
+
* set appropriate headers/status
|
|
7
|
+
*/
|
|
8
|
+
export default class InertiaMiddleware {
|
|
9
|
+
protected version: VersionCache;
|
|
10
|
+
constructor(version: VersionCache);
|
|
11
|
+
handle({ request, response }: HttpContext, next: NextFn): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/inertia
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Inertia middleware to handle the Inertia requests and
|
|
11
|
+
* set appropriate headers/status
|
|
12
|
+
*/
|
|
13
|
+
export default class InertiaMiddleware {
|
|
14
|
+
version;
|
|
15
|
+
constructor(version) {
|
|
16
|
+
this.version = version;
|
|
17
|
+
}
|
|
18
|
+
async handle({ request, response }, next) {
|
|
19
|
+
await next();
|
|
20
|
+
const isInertiaRequest = !!request.header('x-inertia');
|
|
21
|
+
if (!isInertiaRequest)
|
|
22
|
+
return;
|
|
23
|
+
response.header('Vary', 'Accept');
|
|
24
|
+
response.header('X-Inertia', 'true');
|
|
25
|
+
/**
|
|
26
|
+
* When redirecting a PUT/PATCH/DELETE request, we need to change the
|
|
27
|
+
* we must use a 303 status code instead of a 302 to force
|
|
28
|
+
* the browser to use a GET request after redirecting.
|
|
29
|
+
*
|
|
30
|
+
* See https://inertiajs.com/redirects
|
|
31
|
+
*/
|
|
32
|
+
const method = request.method();
|
|
33
|
+
if (response.getStatus() === 302 && ['PUT', 'PATCH', 'DELETE'].includes(method)) {
|
|
34
|
+
response.status(303);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Handle version change
|
|
38
|
+
*
|
|
39
|
+
* See https://inertiajs.com/the-protocol#asset-versioning
|
|
40
|
+
*/
|
|
41
|
+
const version = this.version.getVersion();
|
|
42
|
+
if (method === 'GET' && request.header('x-inertia-version', '') !== version) {
|
|
43
|
+
response.header('x-inertia-location', request.url());
|
|
44
|
+
response.status(409);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { PluginFn } from '@japa/runner/types';
|
|
2
|
+
import type { PageProps } from '../types.js';
|
|
3
|
+
declare module '@japa/api-client' {
|
|
4
|
+
interface ApiRequest {
|
|
5
|
+
/**
|
|
6
|
+
* Set `X-Inertia` header on the request
|
|
7
|
+
*/
|
|
8
|
+
withInertia(): this;
|
|
9
|
+
/**
|
|
10
|
+
* Set `X-Inertia-Partial-Data` and `X-Inertia-Partial-Component` headers on the request
|
|
11
|
+
*/
|
|
12
|
+
withInertiaPartialReload(component: string, data: string[]): this;
|
|
13
|
+
}
|
|
14
|
+
interface ApiResponse {
|
|
15
|
+
/**
|
|
16
|
+
* The inertia component
|
|
17
|
+
*/
|
|
18
|
+
inertiaComponent?: string;
|
|
19
|
+
/**
|
|
20
|
+
* The inertia response props
|
|
21
|
+
*/
|
|
22
|
+
inertiaProps: PageProps;
|
|
23
|
+
/**
|
|
24
|
+
* Assert component name of inertia response
|
|
25
|
+
*/
|
|
26
|
+
assertInertiaComponent(component: string): this;
|
|
27
|
+
/**
|
|
28
|
+
* Assert props to be exactly the same as the given props
|
|
29
|
+
*/
|
|
30
|
+
assertInertiaProps(props: PageProps): this;
|
|
31
|
+
/**
|
|
32
|
+
* Assert inertia props contains a subset of the given props
|
|
33
|
+
*/
|
|
34
|
+
assertInertiaPropsContains(props: PageProps): this;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export declare function inertiaApiClient(): PluginFn;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/inertia
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { ApiRequest, ApiResponse } from '@japa/api-client';
|
|
10
|
+
/**
|
|
11
|
+
* Ensure the response is an inertia response, otherwise throw an error
|
|
12
|
+
*/
|
|
13
|
+
function ensureIsInertiaResponse() {
|
|
14
|
+
if (!this.header('x-inertia')) {
|
|
15
|
+
throw new Error('Response is not an Inertia response. Make sure to call `withInertia()` on the request');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function inertiaApiClient() {
|
|
19
|
+
return () => {
|
|
20
|
+
ApiRequest.macro('withInertia', function () {
|
|
21
|
+
this.header('x-inertia', 'true');
|
|
22
|
+
return this;
|
|
23
|
+
});
|
|
24
|
+
ApiRequest.macro('withInertiaPartialReload', function (component, data) {
|
|
25
|
+
this.withInertia();
|
|
26
|
+
this.header('X-Inertia-Partial-Data', data.join(','));
|
|
27
|
+
this.header('X-Inertia-Partial-Component', component);
|
|
28
|
+
return this;
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Response getters
|
|
32
|
+
*/
|
|
33
|
+
ApiResponse.getter('inertiaComponent', function () {
|
|
34
|
+
ensureIsInertiaResponse.call(this);
|
|
35
|
+
return this.body().component;
|
|
36
|
+
});
|
|
37
|
+
ApiResponse.getter('inertiaProps', function () {
|
|
38
|
+
ensureIsInertiaResponse.call(this);
|
|
39
|
+
return this.body().props;
|
|
40
|
+
});
|
|
41
|
+
/**
|
|
42
|
+
* Response assertions
|
|
43
|
+
*/
|
|
44
|
+
ApiResponse.macro('assertInertiaComponent', function (component) {
|
|
45
|
+
ensureIsInertiaResponse.call(this);
|
|
46
|
+
this.assert.deepEqual(this.body().component, component);
|
|
47
|
+
return this;
|
|
48
|
+
});
|
|
49
|
+
ApiResponse.macro('assertInertiaProps', function (props) {
|
|
50
|
+
this.ensureHasAssert();
|
|
51
|
+
ensureIsInertiaResponse.call(this);
|
|
52
|
+
this.assert.deepEqual(this.body().props, props);
|
|
53
|
+
return this;
|
|
54
|
+
});
|
|
55
|
+
ApiResponse.macro('assertInertiaPropsContains', function (props) {
|
|
56
|
+
this.ensureHasAssert();
|
|
57
|
+
ensureIsInertiaResponse.call(this);
|
|
58
|
+
this.assert.containsSubset(this.body().props, props);
|
|
59
|
+
return this;
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/inertia
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { encode } from 'html-entities';
|
|
10
|
+
import debug from '../debug.js';
|
|
11
|
+
/**
|
|
12
|
+
* Register the Inertia tags and globals within Edge
|
|
13
|
+
*/
|
|
14
|
+
export const edgePluginInertia = () => {
|
|
15
|
+
return (edge) => {
|
|
16
|
+
debug('sharing globals and inertia tags with edge');
|
|
17
|
+
edge.global('inertia', (page = {}) => {
|
|
18
|
+
if (page.ssrBody)
|
|
19
|
+
return page.ssrBody;
|
|
20
|
+
return `<div id="app" data-page="${encode(JSON.stringify(page))}"></div>`;
|
|
21
|
+
});
|
|
22
|
+
edge.global('inertiaHead', (page) => {
|
|
23
|
+
const { ssrHead = [] } = page || {};
|
|
24
|
+
return ssrHead.join('\n');
|
|
25
|
+
});
|
|
26
|
+
edge.registerTag({
|
|
27
|
+
block: false,
|
|
28
|
+
tagName: 'inertia',
|
|
29
|
+
seekable: false,
|
|
30
|
+
compile(_, buffer, { filename, loc }) {
|
|
31
|
+
buffer.writeExpression(`out += state.inertia(state.page)`, filename, loc.start.line);
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
edge.registerTag({
|
|
35
|
+
block: false,
|
|
36
|
+
tagName: 'inertiaHead',
|
|
37
|
+
seekable: false,
|
|
38
|
+
compile(_, buffer, { filename, loc }) {
|
|
39
|
+
buffer.writeExpression(`out += state.inertiaHead(state.page)`, filename, loc.start.line);
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
2
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
3
|
+
/**
|
|
4
|
+
* Props that will be passed to inertia render method
|
|
5
|
+
*/
|
|
6
|
+
export type PageProps = Record<string, unknown>;
|
|
7
|
+
/**
|
|
8
|
+
* Shared data types
|
|
9
|
+
*/
|
|
10
|
+
export type Data = string | number | object | boolean;
|
|
11
|
+
export type SharedDatumFactory = (ctx: HttpContext) => MaybePromise<Data>;
|
|
12
|
+
export type SharedData = Record<string, Data | SharedDatumFactory>;
|
|
13
|
+
/**
|
|
14
|
+
* Allowed values for the assets version
|
|
15
|
+
*/
|
|
16
|
+
export type AssetsVersion = string | number | undefined;
|
|
17
|
+
export interface InertiaConfig {
|
|
18
|
+
/**
|
|
19
|
+
* Path to the Edge view that will be used as the root view for Inertia responses.
|
|
20
|
+
* @default root (resources/views/root.edge)
|
|
21
|
+
*/
|
|
22
|
+
rootView?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The version of your assets. Every client request will be checked against this version.
|
|
25
|
+
* If the version is not the same, the client will do a full reload.
|
|
26
|
+
*/
|
|
27
|
+
assetsVersion?: AssetsVersion;
|
|
28
|
+
/**
|
|
29
|
+
* Data that should be shared with all rendered pages
|
|
30
|
+
*/
|
|
31
|
+
sharedData?: SharedData;
|
|
32
|
+
}
|