@onreza/adapter-nitro 0.2.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 +144 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -0
- package/dist/manifest.d.ts +2 -0
- package/dist/preset/entry.d.ts +5 -0
- package/dist/preset/entry.js +1 -0
- package/dist/preset/preset.d.ts +17 -0
- package/dist/preset/preset.js +1 -0
- package/dist/routes.d.ts +11 -0
- package/dist/types.d.ts +26 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# @onreza/adapter-nitro
|
|
2
|
+
|
|
3
|
+
Nitro preset ONREZA для развёртывания [Nuxt](https://nuxt.com), [Analog](https://analogjs.org), [Vinxi](https://vinxi.vercel.app) и standalone [Nitro](https://nitro.build) приложений на платформе ONREZA с поддержкой SSR, hybrid mode, prerendering и ISR.
|
|
4
|
+
|
|
5
|
+
## Установка
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm add @onreza/adapter-nitro
|
|
9
|
+
bun add @onreza/adapter-nitro
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Использование
|
|
13
|
+
|
|
14
|
+
### Nuxt
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
// nuxt.config.ts
|
|
18
|
+
export default defineNuxtConfig({
|
|
19
|
+
nitro: {
|
|
20
|
+
preset: "@onreza/adapter-nitro",
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Standalone Nitro
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
// nitro.config.ts
|
|
29
|
+
export default defineNitroConfig({
|
|
30
|
+
preset: "@onreza/adapter-nitro",
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Analog
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// vite.config.ts
|
|
38
|
+
import { defineConfig } from "vite";
|
|
39
|
+
import analog from "@analogjs/platform";
|
|
40
|
+
|
|
41
|
+
export default defineConfig({
|
|
42
|
+
plugins: [
|
|
43
|
+
analog({
|
|
44
|
+
nitro: { preset: "@onreza/adapter-nitro" },
|
|
45
|
+
}),
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Конфигурация
|
|
51
|
+
|
|
52
|
+
Конфигурация выполняется через стандартные механизмы Nitro — `routeRules`:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
// nuxt.config.ts или nitro.config.ts
|
|
56
|
+
export default defineNuxtConfig({
|
|
57
|
+
routeRules: {
|
|
58
|
+
"/blog/**": { isr: 60 }, // ISR с 60 сек ревалидацией
|
|
59
|
+
"/about": { prerender: true }, // Static prerender
|
|
60
|
+
"/api/**": { cors: true }, // CORS для API
|
|
61
|
+
},
|
|
62
|
+
nitro: {
|
|
63
|
+
preset: "@onreza/adapter-nitro",
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `routeRules.isr`
|
|
69
|
+
|
|
70
|
+
Включает Incremental Static Regeneration для указанных маршрутов.
|
|
71
|
+
|
|
72
|
+
| Значение | Описание |
|
|
73
|
+
|----------|----------|
|
|
74
|
+
| `number` | Время ревалидации в секундах |
|
|
75
|
+
| `true` | ISR с дефолтным временем (60 сек) |
|
|
76
|
+
| `{ expiration: number }` | Vercel-совместимый формат |
|
|
77
|
+
|
|
78
|
+
### `routeRules.swr`
|
|
79
|
+
|
|
80
|
+
Альтернатива `isr` — Stale-While-Revalidate с аналогичным синтаксисом.
|
|
81
|
+
|
|
82
|
+
### `routeRules.prerender`
|
|
83
|
+
|
|
84
|
+
`true` — страница будет отрендерена при сборке и раздаваться как static.
|
|
85
|
+
|
|
86
|
+
## Поддерживаемые возможности
|
|
87
|
+
|
|
88
|
+
| Возможность | Статус |
|
|
89
|
+
|-------------|--------|
|
|
90
|
+
| SSR | Поддерживается |
|
|
91
|
+
| Hybrid output | Поддерживается |
|
|
92
|
+
| Static prerender | Поддерживается |
|
|
93
|
+
| API Routes | Поддерживается |
|
|
94
|
+
| ISR / SWR | Поддерживается |
|
|
95
|
+
| Environment Variables | Поддерживается |
|
|
96
|
+
| routeRules | Поддерживается |
|
|
97
|
+
| Nuxt 3 | Поддерживается |
|
|
98
|
+
| Analog | Поддерживается |
|
|
99
|
+
| Standalone Nitro | Поддерживается |
|
|
100
|
+
| Nuxt Server Components | В планах |
|
|
101
|
+
| Image Optimization | В планах |
|
|
102
|
+
|
|
103
|
+
## Build output
|
|
104
|
+
|
|
105
|
+
После сборки адаптер генерирует:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
.output/
|
|
109
|
+
├── .onreza/
|
|
110
|
+
│ └── manifest.json # Метаданные билда
|
|
111
|
+
├── server/
|
|
112
|
+
│ └── entry.mjs # Server handler (fetch контракт)
|
|
113
|
+
├── client/ # Static assets (Nuxt: public/)
|
|
114
|
+
│ └── _nuxt/
|
|
115
|
+
└── prerender/ # Prerendered HTML (опционально)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Ограничения
|
|
119
|
+
|
|
120
|
+
ONREZA использует edge runtime (V8 isolate) без доступа к `node_modules`. Это означает:
|
|
121
|
+
|
|
122
|
+
| Ограничение | Причина | Альтернатива |
|
|
123
|
+
|-------------|---------|--------------|
|
|
124
|
+
| Native модули (Prisma, Sharp, bcrypt) | Нет бинарников в edge | HTTP-based драйверы, внешние API |
|
|
125
|
+
| `fs`, `child_process` | Нет файловой системы | Fetch к API, S3 |
|
|
126
|
+
| Long-running процессы | Таймаут 30 сек | Webhook-based архитектура |
|
|
127
|
+
|
|
128
|
+
Для работы с базой данных используйте HTTP-драйверы:
|
|
129
|
+
- `@neondatabase/serverless` (Neon)
|
|
130
|
+
- `@planetscale/database` (PlanetScale)
|
|
131
|
+
- Drizzle/Kysely с HTTP адаптерами
|
|
132
|
+
|
|
133
|
+
## Совместимость
|
|
134
|
+
|
|
135
|
+
- Nitro >= 2.0.0
|
|
136
|
+
- Nuxt >= 3.0.0
|
|
137
|
+
|
|
138
|
+
## Документация
|
|
139
|
+
|
|
140
|
+
[docs.onreza.ru/adapters/nitro](https://docs.onreza.ru/adapters/nitro)
|
|
141
|
+
|
|
142
|
+
## Лицензия
|
|
143
|
+
|
|
144
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { ApiRoute, IsrRoute, OnrezaManifest, Route, RoutePriority, RouteType, SsrRoute, StaticRoute, } from "@onreza/shared";
|
|
2
|
+
export { default } from "./preset/preset.ts";
|
|
3
|
+
export { collectRoutes, routeToRegex } from "./routes.ts";
|
|
4
|
+
export type { NitroPrerenderedRoute, NitroRouteRules, NitroScannedHandler, OnrezaRoute, } from "./types.ts";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{fileURLToPath as V}from"node:url";import{readFile as _}from"node:fs/promises";import{createRequire as L}from"node:module";import{fileURLToPath as O}from"node:url";import{generateManifest as b,writeManifest as w}from"@onreza/shared";var q={pattern:"^/_nuxt/.*$",priority:100,type:"static"},M={pattern:"^/.*$",priority:0,type:"ssr"};function H(B){return B.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function F(B){let D=B;return D=D.replace(/\*\*/g,"\x00DOUBLE_STAR\x00"),D=D.replace(/\*/g,"\x00SINGLE_STAR\x00"),D=D.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,"\x00PARAM_$1\x00"),D=H(D),D=D.replace(new RegExp(H("\x00DOUBLE_STAR\x00"),"g"),".*"),D=D.replace(new RegExp(H("\x00SINGLE_STAR\x00"),"g"),"[^/]*"),D=D.replace(new RegExp(`${H("\x00PARAM_")}([a-zA-Z_][a-zA-Z0-9_]*)${H("\x00")}`,"g"),"([^/]+)"),`^${D}/?$`}function N(B){return B.startsWith("/api/")||B==="/api"}function Z(B){if(B===void 0||B===null||B===!1)return null;if(typeof B==="number")return B;if(B===!0)return 60;if(typeof B==="object"&&"expiration"in B&&typeof B.expiration==="number")return B.expiration;return null}function z(B,K){if(K[B]){let Q=K[B],X=Z(Q.isr);if(X!==null)return{revalidate:X};let Y=Z(Q.swr);if(Y!==null)return{revalidate:Y}}for(let[Q,X]of Object.entries(K))if(Q.includes("*")||Q.includes(":")){if(new RegExp(F(Q)).test(B)){let D=Z(X.isr);if(D!==null)return{revalidate:D};let j=Z(X.swr);if(j!==null)return{revalidate:j}}}return null}function U(B,K){if(K[B]?.prerender===!0)return!0;for(let[Q,X]of Object.entries(K))if(X.prerender===!0&&(Q.includes("*")||Q.includes(":"))){if(new RegExp(F(Q)).test(B))return!0}return!1}function y(B){let{handlers:K,prerenderedRoutes:Q=[],routeRules:X}=B,Y=[{...q}],D=new Set,j=!1;for(let $ of Q){if($.skip||$.error)continue;let W=$.route;D.add(W);let G=z(W,X);if(G)Y.push({pattern:F(W),priority:30,revalidate:G.revalidate,src:W,type:"isr"});else Y.push({pattern:F(W),priority:50,src:W,type:"static"})}for(let $ of K){if($.middleware)continue;if(D.has($.route))continue;let W=$.route;if(U(W,X)){let G=z(W,X);if(G)Y.push({pattern:F(W),priority:30,revalidate:G.revalidate,src:W,type:"isr"});else Y.push({pattern:F(W),priority:50,src:W,type:"static"});D.add(W);continue}if(N(W)){j=!0,Y.push({pattern:F(W),priority:20,src:W,type:"api"}),D.add(W);continue}j=!0,D.add(W)}if(j)Y.push({...M});return Y.sort(($,W)=>W.priority-$.priority)}function I(B,K){try{return JSON.parse(B)}catch(Q){throw Error(`Failed to parse ${K}`,{cause:Q})}}async function E(){let B=O(new URL("../../package.json",import.meta.url)),K=await _(B,"utf-8");return I(K,B).version}function k(){let B=L(import.meta.url),K=B.resolve("nitropack/package.json"),X=B("node:fs").readFileSync(K,"utf-8");return I(X,K).version}function A(B){let K=[];for(let Q of B){if(Q.skip||Q.error)continue;if(Q.fileName?.endsWith(".html"))K.push(Q.fileName)}return K}async function J(B){let K=B.scannedHandlers,Q=B._prerenderedRoutes??[],X=B.options.routeRules??{},Y=y({handlers:K,prerenderedRoutes:Q,routeRules:X}),D=A(Q),j=await E(),$=k(),W=b({adapterName:"@onreza/adapter-nitro",adapterVersion:j,frameworkName:"nitro",frameworkVersion:$,prerenderPages:D.length>0?D:void 0,routes:Y});await w(B.options.output.dir,W)}function C(B,K){if(K?.url&&typeof B!=="function"&&B.entry&&typeof B.entry==="string"&&B.entry.startsWith("."))B.entry=V(new URL(B.entry,K.url));return{...B,_meta:K}}var S=C({entry:"./entry",exportConditions:["worker"],hooks:{async compiled(B){await J(B),console.log("[onreza] Generated .onreza/manifest.json")}},output:{publicDir:"{{ output.dir }}/client",serverDir:"{{ output.dir }}/server"},rollupConfig:{output:{entryFileNames:"entry.mjs",format:"esm"}}},{name:"@onreza/adapter-nitro",url:import.meta.url});export{F as routeToRegex,S as default,y as collectRoutes};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"#nitro-internal-pollyfills";import{toWebHandler as C}from"h3";import{useNitroApp as F}from"nitropack/runtime";var G=F(),I=C(G.h3App),B=globalThis.ONREZA?.env;if(B)for(let[j,w]of B.entries())process.env[j]=w;var M={async fetch(j){try{return await I(j)}catch(w){return console.error("[onreza] nitro error:",w),new Response("Internal Server Error",{status:500})}}};export{M as default};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { NitroPreset } from "nitropack";
|
|
2
|
+
/**
|
|
3
|
+
* Preset metadata type (from nitropack/kit)
|
|
4
|
+
*/
|
|
5
|
+
interface NitroPresetMeta {
|
|
6
|
+
name?: string;
|
|
7
|
+
stdName?: string;
|
|
8
|
+
url?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Extended preset type with internal _meta field
|
|
12
|
+
*/
|
|
13
|
+
type NitroPresetWithMeta = NitroPreset & {
|
|
14
|
+
_meta?: NitroPresetMeta;
|
|
15
|
+
};
|
|
16
|
+
declare const _default: NitroPresetWithMeta;
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{fileURLToPath as V}from"node:url";import{readFile as U}from"node:fs/promises";import{createRequire as _}from"node:module";import{fileURLToPath as L}from"node:url";import{generateManifest as O,writeManifest as b}from"@onreza/shared";var q={pattern:"^/_nuxt/.*$",priority:100,type:"static"},E={pattern:"^/.*$",priority:0,type:"ssr"};function G(B){return B.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function y(B){let D=B;return D=D.replace(/\*\*/g,"\x00DOUBLE_STAR\x00"),D=D.replace(/\*/g,"\x00SINGLE_STAR\x00"),D=D.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g,"\x00PARAM_$1\x00"),D=G(D),D=D.replace(new RegExp(G("\x00DOUBLE_STAR\x00"),"g"),".*"),D=D.replace(new RegExp(G("\x00SINGLE_STAR\x00"),"g"),"[^/]*"),D=D.replace(new RegExp(`${G("\x00PARAM_")}([a-zA-Z_][a-zA-Z0-9_]*)${G("\x00")}`,"g"),"([^/]+)"),`^${D}/?$`}function M(B){return B.startsWith("/api/")||B==="/api"}function H(B){if(B===void 0||B===null||B===!1)return null;if(typeof B==="number")return B;if(B===!0)return 60;if(typeof B==="object"&&"expiration"in B&&typeof B.expiration==="number")return B.expiration;return null}function Z(B,K){if(K[B]){let Q=K[B],X=H(Q.isr);if(X!==null)return{revalidate:X};let Y=H(Q.swr);if(Y!==null)return{revalidate:Y}}for(let[Q,X]of Object.entries(K))if(Q.includes("*")||Q.includes(":")){if(new RegExp(y(Q)).test(B)){let D=H(X.isr);if(D!==null)return{revalidate:D};let j=H(X.swr);if(j!==null)return{revalidate:j}}}return null}function N(B,K){if(K[B]?.prerender===!0)return!0;for(let[Q,X]of Object.entries(K))if(X.prerender===!0&&(Q.includes("*")||Q.includes(":"))){if(new RegExp(y(Q)).test(B))return!0}return!1}function z(B){let{handlers:K,prerenderedRoutes:Q=[],routeRules:X}=B,Y=[{...q}],D=new Set,j=!1;for(let $ of Q){if($.skip||$.error)continue;let W=$.route;D.add(W);let F=Z(W,X);if(F)Y.push({pattern:y(W),priority:30,revalidate:F.revalidate,src:W,type:"isr"});else Y.push({pattern:y(W),priority:50,src:W,type:"static"})}for(let $ of K){if($.middleware)continue;if(D.has($.route))continue;let W=$.route;if(N(W,X)){let F=Z(W,X);if(F)Y.push({pattern:y(W),priority:30,revalidate:F.revalidate,src:W,type:"isr"});else Y.push({pattern:y(W),priority:50,src:W,type:"static"});D.add(W);continue}if(M(W)){j=!0,Y.push({pattern:y(W),priority:20,src:W,type:"api"}),D.add(W);continue}j=!0,D.add(W)}if(j)Y.push({...E});return Y.sort(($,W)=>W.priority-$.priority)}function I(B,K){try{return JSON.parse(B)}catch(Q){throw Error(`Failed to parse ${K}`,{cause:Q})}}async function w(){let B=L(new URL("../../package.json",import.meta.url)),K=await U(B,"utf-8");return I(K,B).version}function k(){let B=_(import.meta.url),K=B.resolve("nitropack/package.json"),X=B("node:fs").readFileSync(K,"utf-8");return I(X,K).version}function A(B){let K=[];for(let Q of B){if(Q.skip||Q.error)continue;if(Q.fileName?.endsWith(".html"))K.push(Q.fileName)}return K}async function J(B){let K=B.scannedHandlers,Q=B._prerenderedRoutes??[],X=B.options.routeRules??{},Y=z({handlers:K,prerenderedRoutes:Q,routeRules:X}),D=A(Q),j=await w(),$=k(),W=O({adapterName:"@onreza/adapter-nitro",adapterVersion:j,frameworkName:"nitro",frameworkVersion:$,prerenderPages:D.length>0?D:void 0,routes:Y});await b(B.options.output.dir,W)}function C(B,K){if(K?.url&&typeof B!=="function"&&B.entry&&typeof B.entry==="string"&&B.entry.startsWith("."))B.entry=V(new URL(B.entry,K.url));return{...B,_meta:K}}var g=C({entry:"./entry",exportConditions:["worker"],hooks:{async compiled(B){await J(B),console.log("[onreza] Generated .onreza/manifest.json")}},output:{publicDir:"{{ output.dir }}/client",serverDir:"{{ output.dir }}/server"},rollupConfig:{output:{entryFileNames:"entry.mjs",format:"esm"}}},{name:"@onreza/adapter-nitro",url:import.meta.url});export{g as default};
|
package/dist/routes.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Route } from "@onreza/shared";
|
|
2
|
+
import type { NitroRouteConfig } from "nitropack";
|
|
3
|
+
import type { NitroPrerenderedRoute, NitroScannedHandler } from "./types.ts";
|
|
4
|
+
declare function routeToRegex(route: string): string;
|
|
5
|
+
export interface CollectRoutesParams {
|
|
6
|
+
handlers: NitroScannedHandler[];
|
|
7
|
+
prerenderedRoutes?: NitroPrerenderedRoute[];
|
|
8
|
+
routeRules: Record<string, NitroRouteConfig>;
|
|
9
|
+
}
|
|
10
|
+
export declare function collectRoutes(params: CollectRoutesParams): Route[];
|
|
11
|
+
export { routeToRegex };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { NitroRouteConfig } from "nitropack";
|
|
2
|
+
export interface NitroScannedHandler {
|
|
3
|
+
handler: string;
|
|
4
|
+
lazy?: boolean;
|
|
5
|
+
method?: string;
|
|
6
|
+
middleware?: boolean;
|
|
7
|
+
route: string;
|
|
8
|
+
}
|
|
9
|
+
export interface NitroPrerenderedRoute {
|
|
10
|
+
contentType?: string;
|
|
11
|
+
contents?: string;
|
|
12
|
+
data?: unknown;
|
|
13
|
+
error?: Error;
|
|
14
|
+
fileName?: string;
|
|
15
|
+
generateTimeMS?: number;
|
|
16
|
+
route: string;
|
|
17
|
+
skip?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export type NitroRouteRules = Record<string, NitroRouteConfig>;
|
|
20
|
+
export interface OnrezaRoute {
|
|
21
|
+
pattern: string;
|
|
22
|
+
priority: number;
|
|
23
|
+
revalidate?: number;
|
|
24
|
+
src?: string;
|
|
25
|
+
type: "static" | "ssr" | "api" | "isr";
|
|
26
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@onreza/adapter-nitro",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "ONREZA Nitro adapter for Nuxt, Analog, Vinxi and standalone Nitro",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "ONREZA OSS <opensource@onreza.ru>",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/preset/preset.js",
|
|
11
|
+
"types": "./dist/preset/preset.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./types": {
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"files": ["dist"],
|
|
21
|
+
"keywords": ["nitro-preset", "nuxt", "analog", "vinxi", "onreza"],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "bun build.ts",
|
|
24
|
+
"test": "bun test",
|
|
25
|
+
"typecheck": "tsc --noEmit"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"nitropack": "^2"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@onreza/shared": "0.0.0",
|
|
32
|
+
"h3": "^1.15.3",
|
|
33
|
+
"nitropack": "^2.11.12"
|
|
34
|
+
}
|
|
35
|
+
}
|