initial commit

This commit is contained in:
Zoe
2023-01-03 09:29:04 -06:00
commit 7851137d88
12889 changed files with 2557443 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io> and Nitro contributors
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.
+109
View File
@@ -0,0 +1,109 @@
[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![npm-edge version][npm-edge-version-src]][npm-edge-version-href]
[![npm-edge downloads][npm-edge-downloads-src]][npm-edge-downloads-href]
<!-- [![GitHub Actions][github-actions-src]][github-actions-href] [![Codecov][codecov-src]][codecov-href] -->
<h1 align="center">⚗️ Nitro</h1>
<p align="center">Build and Deploy Universal JavaScript Servers</p>
## Why using Nitro?
Nitro provides a powerful toolchain and a runtime framework from the [UnJS](https://github.com/unjs) ecosystem to build and deploy **any JavaScript server, anywhere!**
❯ 🐇 **Rapid development** experience with hot module replacement <br>
❯ 😌 **Multi-provider** deployments with a single codebase and zero-configuration<br>
❯ 💼 **Portable and compact** deployments without `node_modules` dependency <br>
❯ 📁 **Directory structure** aware to register API routes and more with zero configuration <br>
❯ 🤏 **Minimal Design** to fit into any solution with minimum overhead <br>
❯ 🚀 **Code-splitting** and async chunk loading for fast server startup time <br>
❯ 👕 **TypeScript** fully supported <br>
❯ 💾 **Multi-driver storage** and caching layer <br>
❯ 💰 **Route caching** and static **pre-rendering** with built-in crawler <br>
❯ 🐱 **Hackable** to extend almost any part of nitro using options <br>
❯ ✨ **Auto imports** for lazy folks and a tidy minimal codebase <br>
❯ 🏛️ **Best-effort compatibility** for using legacy npm packages and mocking Node.js modules <br>
## Who is using Nitro?
[Nuxt 3](https://v3.nuxtjs.org/guide/concepts/server-engine) is using Nitro as its server engine.
<br>
<hr>
<h3><a href="https://nitro.unjs.io">📖 Documentation</a></h3>
<h3><a href="https://github.com/unjs/nitro/blob/main/CHANGELOG.md">✍️ Changelog</a></h3>
<h3><a href="https://stackblitz.com/github/unjs/nitro/tree/main/examples/hello-world">🏀 Online playground</a></h3>
<hr>
<br>
<h2 align="center">😺 Quick Start</h2>
0️⃣ Create an empty directory `nitro-app`
```bash
mkdir nitro-app
cd nitro-app
```
1️⃣ Create `routes/index.ts`:
```ts [routes/index.ts]
export default defineEventHandler(() => 'nitro is amazing!')
```
2️⃣ Start development server:
```bash
npx nitropack dev
```
🪄 Your API is ready at `http://localhost:3000/`
Check `.nitro/dev/index.mjs` if want to know what is happening
3️⃣ You can now build your production-ready server:
```bash
npx nitropack build
````
4️⃣ Output is in the `.output` directory and ready to be deployed on almost any VPS with no dependencies. You can locally try it too:
```bash
node .output/server/index.mjs
```
That's it you got it! Read the [documentation](https://nitro.unjs.io) to learn more.
<hr>
<h3 align="center">🌱 nitro is young and under development</h3>
Check [🐛 open issues](https://github.com/unjs/nitro/issues) for the known issues and roadmap and tell us [💡your ideas](https://github.com/unjs/nitro/discussions/new)!
<hr>
## License
Made with 💛 Published under [MIT](./LICENSE).
<!-- Badges -->
[npm-version-src]: https://flat.badgen.net/npm/v/nitropack?style=flat-square&label=stable
[npm-version-href]: https://npmjs.com/package/nitropack
[npm-downloads-src]: https://flat.badgen.net/npm/dm/nitropack?style=flat-square&label=stable
[npm-downloads-href]: https://npmjs.com/package/nitropack
[npm-edge-version-src]: https://flat.badgen.net/npm/v/nitropack-edge?style=flat-square&label=edge
[npm-edge-version-href]: https://npmjs.com/package/nitropack-edge
[npm-edge-downloads-src]: https://flat.badgen.net/npm/dm/nitropack-edge?style=flat-square&label=edge
[npm-edge-downloads-href]: https://npmjs.com/package/nitropack-edge
[github-actions-src]: https://flat.badgen.net/github/status/unjs/nitro?style=flat-square
[github-actions-href]: https://github.com/unjs/nitro/actions?query=workflow%3Aci
[codecov-src]: https://flat.badgen.net/codecov/c/gh/unjs/nitro/main?style=flat-square
[codecov-href]: https://codecov.io/gh/unjs/nitro
+1
View File
@@ -0,0 +1 @@
Generated Vendored Executable
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env node
import mri from 'mri';
import { resolve } from 'pathe';
import { a as createNitro, g as createDevServer, p as prepare, b as build, c as copyPublicAssets, i as prerender } from './shared/nitro.c8278d90.mjs';
import 'worker_threads';
import 'fs';
import 'perfect-debounce';
import 'h3';
import 'http-proxy';
import 'listhen';
import 'serve-placeholder';
import 'serve-static';
import 'ufo';
import 'chokidar';
import 'url';
import 'chalk';
import 'radix3';
import 'defu';
import 'hookable';
import 'unimport';
import 'consola';
import 'c12';
import 'klona/full';
import 'scule';
import 'mlly';
import 'std-env';
import 'pkg-types';
import 'module';
import 'fs-extra';
import 'jiti';
import 'dot-prop';
import 'archiver';
import 'globby';
import 'fs/promises';
import 'unstorage';
import 'pathe/utils';
import 'rollup';
import 'pretty-bytes';
import 'gzip-size';
import 'rollup-plugin-terser';
import '@rollup/plugin-commonjs';
import '@rollup/plugin-node-resolve';
import '@rollup/plugin-alias';
import '@rollup/plugin-json';
import '@rollup/plugin-wasm';
import '@rollup/plugin-inject';
import 'rollup-plugin-visualizer';
import 'unenv';
import 'unimport/unplugin';
import 'ohash';
import '@rollup/plugin-replace';
import 'knitwork';
import '@vercel/nft';
import 'semver';
import 'etag';
import 'mime';
import 'esbuild';
import '@rollup/pluginutils';
import 'node:zlib';
import 'node:fs/promises';
import 'node:fs';
async function main() {
const args = mri(process.argv.slice(2));
const command = args._[0];
const rootDir = resolve(args._[1] || ".");
if (command === "dev") {
const nitro = await createNitro({
rootDir,
dev: true,
preset: "nitro-dev"
});
const server = createDevServer(nitro);
await server.listen({});
await prepare(nitro);
await build(nitro);
return;
}
if (command === "build") {
const nitro = await createNitro({
rootDir,
dev: false
});
await prepare(nitro);
await copyPublicAssets(nitro);
await prerender(nitro);
await build(nitro);
await nitro.close();
process.exit(0);
}
console.error(`Unknown command ${command}! Usage: nitro dev|build [rootDir]`);
process.exit(1);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
+572
View File
@@ -0,0 +1,572 @@
import { FetchRequest, FetchOptions, FetchResponse } from 'ofetch';
import { Preset } from 'unenv';
import { Unimport } from 'unimport';
import { UnimportPluginOptions } from 'unimport/unplugin';
import { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
import { Hookable, NestedHooks } from 'hookable';
import { Consola, LogLevel } from 'consola';
import { WatchOptions, FSWatcher } from 'chokidar';
import { RollupCommonJSOptions } from '@rollup/plugin-commonjs';
import { RollupWasmOptions } from '@rollup/plugin-wasm';
import { Storage, BuiltinDriverName } from 'unstorage';
import { ServerOptions } from 'http-proxy';
import { NodeFileTraceOptions } from '@vercel/nft';
import { InputOptions, OutputOptions } from 'rollup';
import { Loader } from 'esbuild';
import { FilterPattern } from '@rollup/pluginutils';
import { App, Router, H3Event, EventHandler, H3Error } from 'h3';
import { Worker } from 'worker_threads';
import { ListenOptions, Listener } from 'listhen';
import { createCall, createFetch } from 'unenv/runtime/fetch/index';
type MatchResult<Key extends string, Exact extends boolean = false, Score extends any[] = [], catchAll extends boolean = false> = {
[k in Key]: {
key: k;
exact: Exact;
score: Score;
catchAll: catchAll;
};
}[Key];
type Subtract<Minuend extends any[] = [], Subtrahend extends any[] = []> = Minuend extends [...Subtrahend, ...infer Remainder] ? Remainder : never;
type TupleIfDiff<First extends string, Second extends string, Tuple extends any[] = []> = First extends `${Second}${infer Diff}` ? Diff extends '' ? [] : Tuple : [];
type MaxTuple<N extends any[] = [], T extends any[] = []> = {
current: T;
result: MaxTuple<N, ['', ...T]>;
}[[N['length']] extends [Partial<T>['length']] ? 'current' : 'result'];
type CalcMatchScore<Key extends string, Route extends string, Score extends any[] = [], Init extends boolean = false, FirstKeySegMatcher extends string = Init extends true ? ':Invalid:' : ''> = `${Key}/` extends `${infer KeySeg}/${infer KeyRest}` ? KeySeg extends FirstKeySegMatcher ? Subtract<[...Score, ...TupleIfDiff<Route, Key, ['', '']>], TupleIfDiff<Key, Route, ['', '']>> : `${Route}/` extends `${infer RouteSeg}/${infer RouteRest}` ? `${RouteSeg}?` extends `${infer RouteSegWithoutQuery}?${string}` ? RouteSegWithoutQuery extends KeySeg ? CalcMatchScore<KeyRest, RouteRest, [...Score, '', '']> : KeySeg extends `:${string}` ? RouteSegWithoutQuery extends '' ? never : CalcMatchScore<KeyRest, RouteRest, [...Score, '']> : KeySeg extends RouteSegWithoutQuery ? CalcMatchScore<KeyRest, RouteRest, [...Score, '']> : never : never : never : never;
type _MatchedRoutes<Route extends string, MatchedResultUnion extends MatchResult<string> = MatchResult<keyof InternalApi>> = MatchedResultUnion['key'] extends infer MatchedKeys ? MatchedKeys extends string ? Route extends MatchedKeys ? MatchResult<MatchedKeys, true> : MatchedKeys extends `${infer Root}/**${string}` ? MatchedKeys extends `${string}/**` ? Route extends `${Root}/${string}` ? MatchResult<MatchedKeys, false, [], true> : never : MatchResult<MatchedKeys, false, CalcMatchScore<Root, Route, [], true>> : MatchResult<MatchedKeys, false, CalcMatchScore<MatchedKeys, Route, [], true>> : never : never;
type MatchedRoutes<Route extends string, MatchedKeysResult extends MatchResult<string> = MatchResult<keyof InternalApi>, Matches extends MatchResult<string> = _MatchedRoutes<Route, MatchedKeysResult>> = Route extends '/' ? keyof InternalApi : Extract<Matches, {
exact: true;
}> extends never ? Extract<Exclude<Matches, {
score: never;
}>, {
score: MaxTuple<Matches['score']>;
}>['key'] | Extract<Matches, {
catchAll: true;
}>['key'] : Extract<Matches, {
exact: true;
}>['key'];
type KebabCase<T extends string, A extends string = ''> = T extends `${infer F}${infer R}` ? KebabCase<R, `${A}${F extends Lowercase<F> ? '' : '-'}${Lowercase<F>}`> : A;
interface InternalApi {
}
type NitroFetchRequest = Exclude<keyof InternalApi, `/_${string}` | `/api/_${string}`> | Exclude<FetchRequest, string> | string & {};
type MiddlewareOf<Route extends string> = Exclude<InternalApi[MatchedRoutes<Route>], Error | void>;
type TypedInternalResponse<Route, Default = unknown> = Default extends string | boolean | number | null | void | object ? Default : Route extends string ? MiddlewareOf<Route> extends never ? Default : MiddlewareOf<Route> : Default;
interface $Fetch<DefaultT = unknown, DefaultR extends NitroFetchRequest = NitroFetchRequest> {
<T = DefaultT, R extends NitroFetchRequest = DefaultR>(request: R, opts?: FetchOptions): Promise<TypedInternalResponse<R, T>>;
raw<T = DefaultT, R extends NitroFetchRequest = DefaultR>(request: R, opts?: FetchOptions): Promise<FetchResponse<TypedInternalResponse<R, T>>>;
create<T = DefaultT, R extends NitroFetchRequest = DefaultR>(defaults: FetchOptions): $Fetch<T, R>;
}
declare global {
var $fetch: $Fetch;
namespace NodeJS {
interface Global {
$fetch: $Fetch;
}
}
}
interface NodeExternalsOptions {
inline?: string[];
external?: string[];
outDir?: string;
trace?: boolean;
traceOptions?: NodeFileTraceOptions;
moduleDirectories?: string[];
exportConditions?: string[];
traceInclude?: string[];
}
type RollupConfig = InputOptions & {
output: OutputOptions;
};
type Options = {
include?: FilterPattern;
exclude?: FilterPattern;
sourceMap?: boolean;
minify?: boolean;
target: string | string[];
jsxFactory?: string;
jsxFragment?: string;
define?: {
[k: string]: string;
};
/**
* Use this tsconfig file instead
* Disable it by setting to `false`
*/
tsconfig?: string | false;
/**
* Map extension to esbuild loader
* Note that each entry (the extension) needs to start with a dot
*/
loaders?: {
[ext: string]: Loader | false;
};
};
interface NitroApp {
h3App: App;
router: Router;
hooks: Hookable;
localCall: ReturnType<typeof createCall>;
localFetch: ReturnType<typeof createFetch>;
}
interface CacheEntry<T = any> {
value?: T;
expires?: number;
mtime?: number;
integrity?: string;
}
interface CacheOptions<T = any> {
name?: string;
getKey?: (...args: any[]) => string;
transform?: (entry: CacheEntry<T>, ...args: any[]) => any;
validate?: (entry: CacheEntry<T>) => boolean;
group?: string;
integrity?: any;
maxAge?: number;
static?: boolean;
swr?: boolean;
staleMaxAge?: number;
base?: string;
}
interface ResponseCacheEntry<T = any> {
body: T;
code: number;
headers: Record<string, string | number | string[]>;
}
interface CachedEventHandlerOptions<T = any> extends Omit<CacheOptions<ResponseCacheEntry<T>>, 'getKey' | 'transform' | 'validate'> {
headersOnly?: boolean;
}
interface NitroAppPlugin {
(nitro: NitroApp): void;
}
interface RenderResponse {
body: string;
statusCode: number;
statusMessage: string;
headers: Record<string, string>;
}
type RenderHandler = (event: H3Event) => Partial<RenderResponse> | Promise<Partial<RenderResponse>>;
declare const awsLambda: NitroPreset;
declare const azureFunctions: NitroPreset;
declare const azure: NitroPreset;
declare const baseWorker: NitroPreset;
declare const cloudflare: NitroPreset;
declare const cloudflarePages: NitroPreset;
declare const deno: NitroPreset;
declare const digitalOcean: NitroPreset;
declare const firebase: NitroPreset;
declare const heroku: NitroPreset;
declare const layer0: NitroPreset;
declare const netlify: NitroPreset;
declare const netlifyBuilder: NitroPreset;
declare const netlifyEdge: NitroPreset;
declare const nitroDev: NitroPreset;
declare const nitroPrerender: NitroPreset;
declare const cli: NitroPreset;
declare const nodeServer: NitroPreset;
declare const nodeCluster: NitroPreset;
declare const node: NitroPreset;
declare const renderCom: NitroPreset;
declare const serviceWorker: NitroPreset;
declare const stormkit: NitroPreset;
declare const vercel: NitroPreset;
declare const vercelEdge: NitroPreset;
declare const cleavr: NitroPreset;
declare const _PRESETS_awsLambda: typeof awsLambda;
declare const _PRESETS_azureFunctions: typeof azureFunctions;
declare const _PRESETS_azure: typeof azure;
declare const _PRESETS_baseWorker: typeof baseWorker;
declare const _PRESETS_cloudflare: typeof cloudflare;
declare const _PRESETS_cloudflarePages: typeof cloudflarePages;
declare const _PRESETS_deno: typeof deno;
declare const _PRESETS_digitalOcean: typeof digitalOcean;
declare const _PRESETS_firebase: typeof firebase;
declare const _PRESETS_heroku: typeof heroku;
declare const _PRESETS_layer0: typeof layer0;
declare const _PRESETS_netlify: typeof netlify;
declare const _PRESETS_netlifyBuilder: typeof netlifyBuilder;
declare const _PRESETS_netlifyEdge: typeof netlifyEdge;
declare const _PRESETS_nitroDev: typeof nitroDev;
declare const _PRESETS_nitroPrerender: typeof nitroPrerender;
declare const _PRESETS_cli: typeof cli;
declare const _PRESETS_nodeServer: typeof nodeServer;
declare const _PRESETS_nodeCluster: typeof nodeCluster;
declare const _PRESETS_node: typeof node;
declare const _PRESETS_renderCom: typeof renderCom;
declare const _PRESETS_serviceWorker: typeof serviceWorker;
declare const _PRESETS_stormkit: typeof stormkit;
declare const _PRESETS_vercel: typeof vercel;
declare const _PRESETS_vercelEdge: typeof vercelEdge;
declare const _PRESETS_cleavr: typeof cleavr;
declare namespace _PRESETS {
export {
_PRESETS_awsLambda as awsLambda,
_PRESETS_azureFunctions as azureFunctions,
_PRESETS_azure as azure,
_PRESETS_baseWorker as baseWorker,
_PRESETS_cloudflare as cloudflare,
_PRESETS_cloudflarePages as cloudflarePages,
_PRESETS_deno as deno,
_PRESETS_digitalOcean as digitalOcean,
_PRESETS_firebase as firebase,
_PRESETS_heroku as heroku,
_PRESETS_layer0 as layer0,
_PRESETS_netlify as netlify,
_PRESETS_netlifyBuilder as netlifyBuilder,
_PRESETS_netlifyEdge as netlifyEdge,
_PRESETS_nitroDev as nitroDev,
_PRESETS_nitroPrerender as nitroPrerender,
_PRESETS_cli as cli,
_PRESETS_nodeServer as nodeServer,
_PRESETS_nodeCluster as nodeCluster,
_PRESETS_node as node,
_PRESETS_renderCom as renderCom,
_PRESETS_serviceWorker as serviceWorker,
_PRESETS_stormkit as stormkit,
_PRESETS_vercel as vercel,
_PRESETS_vercelEdge as vercelEdge,
_PRESETS_cleavr as cleavr,
};
}
interface NitroEventHandler {
/**
* Path prefix or route
*
* If an empty string used, will be used as a middleware
*/
route?: string;
/**
* Specifies this is a middleware handler.
* Middleware are called on every route and should normally return nothing to pass to the next handlers
*/
middleware?: boolean;
/**
* Use lazy loading to import handler
*/
lazy?: boolean;
/**
* Path to event handler
*
*/
handler: string;
/**
* Router method matcher
*/
method?: string;
}
interface NitroDevEventHandler {
/**
* Path prefix or route
*/
route?: string;
/**
* Event handler
*
*/
handler: EventHandler;
}
type NitroErrorHandler = (error: H3Error, event: H3Event) => void | Promise<void>;
/**
* Vercel Build Output Configuration
* @see https://vercel.com/docs/build-output-api/v3
*/
interface VercelBuildConfigV3 {
version: 3;
routes?: ({
src: string;
headers: {
'cache-control': string;
};
continue: boolean;
} | {
handle: string;
} | {
src: string;
dest: string;
})[];
images?: {
sizes: number[];
domains: string[];
minimumCacheTTL?: number;
formats?: ('image/avif' | 'image/webp')[];
dangerouslyAllowSVG?: boolean;
contentSecurityPolicy?: string;
};
wildcard?: Array<{
domain: string;
value: string;
}>;
overrides?: Record<string, {
path?: string;
contentType?: string;
}>;
cache?: string[];
}
interface PresetOptions {
vercel: {
config: VercelBuildConfigV3;
};
}
interface Nitro {
options: NitroOptions;
scannedHandlers: NitroEventHandler[];
vfs: Record<string, string>;
hooks: Hookable<NitroHooks>;
unimport?: Unimport;
logger: Consola;
storage: Storage;
close: () => Promise<void>;
_prerenderedRoutes?: PrerenderGenerateRoute[];
}
interface PrerenderRoute {
route: string;
contents?: string;
data?: ArrayBuffer;
fileName?: string;
error?: Error & {
statusCode: number;
statusMessage: string;
};
generateTimeMS?: number;
}
interface PrerenderGenerateRoute extends PrerenderRoute {
skip?: boolean;
}
type HookResult = void | Promise<void>;
interface NitroHooks {
'rollup:before': (nitro: Nitro) => HookResult;
'compiled': (nitro: Nitro) => HookResult;
'dev:reload': () => HookResult;
'close': () => HookResult;
'prerender:routes': (routes: Set<string>) => HookResult;
'prerender:route': (route: PrerenderRoute) => HookResult;
'prerender:generate': (route: PrerenderGenerateRoute, nitro: Nitro) => HookResult;
}
type CustomDriverName = string & {
_custom?: any;
};
interface StorageMounts {
[path: string]: {
driver: BuiltinDriverName | CustomDriverName;
[option: string]: any;
};
}
type DeepPartial<T> = T extends Record<string, any> ? {
[P in keyof T]?: DeepPartial<T[P]> | T[P];
} : T;
type NitroPreset = NitroConfig | (() => NitroConfig);
interface NitroConfig extends DeepPartial<Omit<NitroOptions, 'routeRules'>> {
extends?: string | string[] | NitroPreset;
routeRules?: {
[path: string]: NitroRouteConfig;
};
}
interface PublicAssetDir {
baseURL?: string;
fallthrough?: boolean;
maxAge: number;
dir: string;
}
interface ServerAssetDir {
baseName: string;
dir: string;
}
interface DevServerOptions {
watch: string[];
}
interface CompressOptions {
gzip?: boolean;
brotli?: boolean;
}
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N ? Acc[number] : Enumerate<N, [...Acc, Acc['length']]>;
type IntRange<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>;
type HTTPStatusCode = IntRange<100, 600>;
interface NitroRouteConfig {
cache?: CachedEventHandlerOptions | false;
headers?: Record<string, string>;
redirect?: string | {
to: string;
statusCode?: HTTPStatusCode;
};
prerender?: boolean;
cors?: boolean;
swr?: boolean | number;
static?: boolean | number;
}
interface NitroRouteRules extends Omit<NitroRouteConfig, 'redirect' | 'cors' | 'swr' | 'static'> {
redirect?: {
to: string;
statusCode: HTTPStatusCode;
};
}
interface NitroOptions extends PresetOptions {
_config: NitroConfig;
debug: boolean;
preset: KebabCase<keyof typeof _PRESETS> | (string & {});
logLevel: LogLevel;
runtimeConfig: {
app: {
baseURL: string;
};
[key: string]: any;
};
workspaceDir: string;
rootDir: string;
srcDir: string;
scanDirs: string[];
buildDir: string;
output: {
dir: string;
serverDir: string;
publicDir: string;
};
storage: StorageMounts;
devStorage: StorageMounts;
bundledStorage: string[];
timing: boolean;
renderer: string;
serveStatic: boolean | 'node' | 'deno';
noPublicDir: boolean;
experimental?: {
wasm?: boolean | RollupWasmOptions;
};
serverAssets: ServerAssetDir[];
publicAssets: PublicAssetDir[];
imports: UnimportPluginOptions | false;
plugins: string[];
virtual: Record<string, string | (() => string | Promise<string>)>;
compressPublicAssets: boolean | CompressOptions;
dev: boolean;
devServer: DevServerOptions;
watchOptions: WatchOptions;
devProxy: Record<string, string | ServerOptions>;
baseURL: string;
handlers: NitroEventHandler[];
routeRules: {
[path: string]: NitroRouteRules;
};
devHandlers: NitroDevEventHandler[];
errorHandler: string;
devErrorHandler: NitroErrorHandler;
prerender: {
crawlLinks: boolean;
ignore: string[];
routes: string[];
};
rollupConfig?: RollupConfig;
entry: string;
unenv: Preset;
alias: Record<string, string>;
minify: boolean;
inlineDynamicImports: boolean;
sourceMap: boolean;
node: boolean;
moduleSideEffects: string[];
esbuild?: {
options?: Partial<Options>;
};
noExternals: boolean;
externals: NodeExternalsOptions;
analyze: false | PluginVisualizerOptions;
replace: Record<string, string | ((id: string) => string)>;
commonJS?: RollupCommonJSOptions;
typescript: {
internalPaths?: boolean;
generateTsConfig?: boolean;
};
hooks: NestedHooks<NitroHooks>;
nodeModulesDirs: string[];
commands: {
preview: string;
deploy: string;
};
}
declare function prepare(nitro: Nitro): Promise<void>;
declare function copyPublicAssets(nitro: Nitro): Promise<void>;
declare function build(nitro: Nitro): Promise<void>;
declare function writeTypes(nitro: Nitro): Promise<void>;
declare function createNitro(config?: NitroConfig): Promise<Nitro>;
declare const GLOB_SCAN_PATTERN = "**/*.{ts,mjs,js,cjs}";
type FileInfo = {
dir: string;
path: string;
fullPath: string;
};
declare function scanHandlers(nitro: Nitro): Promise<{
dirs: string[];
files: FileInfo[];
handlers: NitroEventHandler[];
}[]>;
declare function scanMiddleware(nitro: Nitro): Promise<{
dirs: string[];
files: FileInfo[];
handlers: NitroEventHandler[];
}>;
declare function scanRoutes(nitro: Nitro, dir: string, prefix?: string): Promise<{
dirs: string[];
files: FileInfo[];
handlers: NitroEventHandler[];
}>;
declare function scanPlugins(nitro: Nitro): Promise<any[]>;
interface NitroWorker {
worker: Worker;
address: {
host: string;
port: number;
socketPath?: string;
};
}
interface NitroDevServer {
reload: () => void;
listen: (port: ListenOptions['port'], opts?: Partial<ListenOptions>) => Promise<Listener>;
app: App;
close: () => Promise<void>;
watcher?: FSWatcher;
}
declare function createDevServer(nitro: Nitro): NitroDevServer;
declare function loadOptions(configOverrides?: NitroConfig): Promise<NitroOptions>;
declare function defineNitroConfig(config: NitroConfig): NitroConfig;
declare function prerender(nitro: Nitro): Promise<void>;
declare function defineNitroPreset(preset: NitroPreset): NitroPreset;
export { $Fetch, CacheEntry, CacheOptions, CachedEventHandlerOptions, CompressOptions, DevServerOptions, GLOB_SCAN_PATTERN, InternalApi, KebabCase, MatchedRoutes, MiddlewareOf, Nitro, NitroApp, NitroAppPlugin, NitroConfig, NitroDevEventHandler, NitroDevServer, NitroErrorHandler, NitroEventHandler, NitroFetchRequest, NitroHooks, NitroOptions, NitroPreset, NitroRouteConfig, NitroRouteRules, NitroWorker, PrerenderGenerateRoute, PrerenderRoute, PublicAssetDir, RenderHandler, RenderResponse, ResponseCacheEntry, ServerAssetDir, StorageMounts, TypedInternalResponse, build, copyPublicAssets, createDevServer, createNitro, defineNitroConfig, defineNitroPreset, loadOptions, prepare, prerender, scanHandlers, scanMiddleware, scanPlugins, scanRoutes, writeTypes };
+59
View File
@@ -0,0 +1,59 @@
export { G as GLOB_SCAN_PATTERN, b as build, c as copyPublicAssets, g as createDevServer, a as createNitro, h as defineNitroConfig, j as defineNitroPreset, l as loadOptions, p as prepare, i as prerender, s as scanHandlers, d as scanMiddleware, f as scanPlugins, e as scanRoutes, w as writeTypes } from './shared/nitro.c8278d90.mjs';
import 'worker_threads';
import 'fs';
import 'perfect-debounce';
import 'h3';
import 'http-proxy';
import 'listhen';
import 'serve-placeholder';
import 'serve-static';
import 'pathe';
import 'ufo';
import 'chokidar';
import 'url';
import 'chalk';
import 'radix3';
import 'defu';
import 'hookable';
import 'unimport';
import 'consola';
import 'c12';
import 'klona/full';
import 'scule';
import 'mlly';
import 'std-env';
import 'pkg-types';
import 'module';
import 'fs-extra';
import 'jiti';
import 'dot-prop';
import 'archiver';
import 'globby';
import 'fs/promises';
import 'unstorage';
import 'pathe/utils';
import 'rollup';
import 'pretty-bytes';
import 'gzip-size';
import 'rollup-plugin-terser';
import '@rollup/plugin-commonjs';
import '@rollup/plugin-node-resolve';
import '@rollup/plugin-alias';
import '@rollup/plugin-json';
import '@rollup/plugin-wasm';
import '@rollup/plugin-inject';
import 'rollup-plugin-visualizer';
import 'unenv';
import 'unimport/unplugin';
import 'ohash';
import '@rollup/plugin-replace';
import 'knitwork';
import '@vercel/nft';
import 'semver';
import 'etag';
import 'mime';
import 'esbuild';
import '@rollup/pluginutils';
import 'node:zlib';
import 'node:fs/promises';
import 'node:fs';
+12
View File
@@ -0,0 +1,12 @@
import { App as H3App, Router } from 'h3';
import { createCall, createFetch as createLocalFetch } from 'unenv/runtime/fetch/index';
import { Hookable } from 'hookable';
export interface NitroApp {
h3App: H3App;
router: Router;
hooks: Hookable;
localCall: ReturnType<typeof createCall>;
localFetch: ReturnType<typeof createLocalFetch>;
}
export declare const nitroApp: NitroApp;
export declare const useNitroApp: () => NitroApp;
+57
View File
@@ -0,0 +1,57 @@
import { createApp, createRouter, lazyEventHandler, toNodeListener } from "h3";
import { createFetch, Headers } from "ofetch";
import destr from "destr";
import { createCall, createFetch as createLocalFetch } from "unenv/runtime/fetch/index";
import { createHooks } from "hookable";
import { useRuntimeConfig } from "./config.mjs";
import { timingMiddleware } from "./timing.mjs";
import { cachedEventHandler } from "./cache.mjs";
import { createRouteRulesHandler, getRouteRulesForPath } from "./route-rules.mjs";
import { plugins } from "#internal/nitro/virtual/plugins";
import errorHandler from "#internal/nitro/virtual/error-handler";
import { handlers } from "#internal/nitro/virtual/server-handlers";
function createNitroApp() {
const config = useRuntimeConfig();
const hooks = createHooks();
const h3App = createApp({
debug: destr(process.env.DEBUG),
onError: errorHandler
});
h3App.use(config.app.baseURL, timingMiddleware);
const router = createRouter();
h3App.use(createRouteRulesHandler());
for (const h of handlers) {
let handler = h.lazy ? lazyEventHandler(h.handler) : h.handler;
if (h.middleware || !h.route) {
const middlewareBase = (config.app.baseURL + (h.route || "/")).replace(/\/+/g, "/");
h3App.use(middlewareBase, handler);
} else {
const routeRules = getRouteRulesForPath(h.route.replace(/:\w+|\*\*/g, "_"));
if (routeRules.cache) {
handler = cachedEventHandler(handler, {
group: "nitro/routes",
...routeRules.cache
});
}
router.use(h.route, handler, h.method);
}
}
h3App.use(config.app.baseURL, router);
const localCall = createCall(toNodeListener(h3App));
const localFetch = createLocalFetch(localCall, globalThis.fetch);
const $fetch = createFetch({ fetch: localFetch, Headers, defaults: { baseURL: config.app.baseURL } });
globalThis.$fetch = $fetch;
const app = {
hooks,
h3App,
router,
localCall,
localFetch
};
for (const plugin of plugins) {
plugin(app);
}
return app;
}
export const nitroApp = createNitroApp();
export const useNitroApp = () => nitroApp;
+32
View File
@@ -0,0 +1,32 @@
import { EventHandler } from 'h3';
export interface CacheEntry<T = any> {
value?: T;
expires?: number;
mtime?: number;
integrity?: string;
}
export interface CacheOptions<T = any> {
name?: string;
getKey?: (...args: any[]) => string;
transform?: (entry: CacheEntry<T>, ...args: any[]) => any;
validate?: (entry: CacheEntry<T>) => boolean;
group?: string;
integrity?: any;
maxAge?: number;
static?: boolean;
swr?: boolean;
staleMaxAge?: number;
base?: string;
}
export declare function defineCachedFunction<T = any>(fn: ((...args: any[]) => T | Promise<T>), opts: CacheOptions<T>): (...args: any[]) => Promise<T | undefined>;
export declare const cachedFunction: typeof defineCachedFunction;
export interface ResponseCacheEntry<T = any> {
body: T;
code: number;
headers: Record<string, string | number | string[]>;
}
export interface CachedEventHandlerOptions<T = any> extends Omit<CacheOptions<ResponseCacheEntry<T>>, 'getKey' | 'transform' | 'validate'> {
headersOnly?: boolean;
}
export declare function defineCachedEventHandler<T = any>(handler: EventHandler<T>, opts?: CachedEventHandlerOptions<T>): EventHandler<T>;
export declare const cachedEventHandler: typeof defineCachedEventHandler;
+217
View File
@@ -0,0 +1,217 @@
import { hash } from "ohash";
import { handleCacheHeaders, defineEventHandler, createEvent } from "h3";
import { parseURL } from "ufo";
import { useStorage } from "#internal/nitro";
const defaultCacheOptions = {
name: "_",
base: "/cache",
swr: true,
maxAge: 1
};
export function defineCachedFunction(fn, opts) {
opts = { ...defaultCacheOptions, ...opts };
const pending = {};
const group = opts.group || "nitro";
const name = opts.name || fn.name || "_";
const integrity = hash([opts.integrity, fn, opts]);
const validate = opts.validate || (() => true);
async function get(key, resolver) {
const cacheKey = [opts.base, group, name, key + ".json"].filter(Boolean).join(":").replace(/:\/$/, ":index");
const entry = await useStorage().getItem(cacheKey) || {};
const ttl = (opts.maxAge ?? opts.maxAge ?? 0) * 1e3;
if (ttl) {
entry.expires = Date.now() + ttl;
}
const expired = entry.integrity !== integrity || ttl && Date.now() - (entry.mtime || 0) > ttl || !validate(entry);
const _resolve = async () => {
if (!pending[key]) {
entry.value = void 0;
entry.integrity = void 0;
entry.mtime = void 0;
entry.expires = void 0;
pending[key] = Promise.resolve(resolver());
}
entry.value = await pending[key];
entry.mtime = Date.now();
entry.integrity = integrity;
delete pending[key];
if (validate(entry)) {
useStorage().setItem(cacheKey, entry).catch((error) => console.error("[nitro] [cache]", error));
}
};
const _resolvePromise = expired ? _resolve() : Promise.resolve();
if (opts.swr && entry.value) {
_resolvePromise.catch(console.error);
return Promise.resolve(entry);
}
return _resolvePromise.then(() => entry);
}
return async (...args) => {
const key = (opts.getKey || getKey)(...args);
const entry = await get(key, () => fn(...args));
let value = entry.value;
if (opts.transform) {
value = await opts.transform(entry, ...args) || value;
}
return value;
};
}
export const cachedFunction = defineCachedFunction;
function getKey(...args) {
return args.length ? hash(args, {}) : "";
}
export function defineCachedEventHandler(handler, opts = defaultCacheOptions) {
const _opts = {
...opts,
getKey: (event) => {
const url = event.req.originalUrl || event.req.url;
const friendlyName = decodeURI(parseURL(url).pathname).replace(/[^a-zA-Z0-9]/g, "").substring(0, 16);
const urlHash = hash(url);
return `${friendlyName}.${urlHash}`;
},
validate: (entry) => {
if (entry.value.code >= 400) {
return false;
}
if (entry.value.body === void 0) {
return false;
}
return true;
},
group: opts.group || "nitro/handlers",
integrity: [
opts.integrity,
handler
]
};
const _cachedHandler = cachedFunction(async (incomingEvent) => {
const reqProxy = cloneWithProxy(incomingEvent.req, { headers: {} });
const resHeaders = {};
let _resSendBody;
const resProxy = cloneWithProxy(incomingEvent.res, {
statusCode: 200,
getHeader(name) {
return resHeaders[name];
},
setHeader(name, value) {
resHeaders[name] = value;
return this;
},
getHeaderNames() {
return Object.keys(resHeaders);
},
hasHeader(name) {
return name in resHeaders;
},
removeHeader(name) {
delete resHeaders[name];
},
getHeaders() {
return resHeaders;
},
end(chunk, arg2, arg3) {
if (typeof chunk === "string") {
_resSendBody = chunk;
}
if (typeof arg2 === "function") {
arg2();
}
if (typeof arg3 === "function") {
arg3();
}
return this;
},
write(chunk, arg2, arg3) {
if (typeof chunk === "string") {
_resSendBody = chunk;
}
if (typeof arg2 === "function") {
arg2();
}
if (typeof arg3 === "function") {
arg3();
}
return this;
},
writeHead(statusCode, headers2) {
this.statusCode = statusCode;
if (headers2) {
for (const header in headers2) {
this.setHeader(header, headers2[header]);
}
}
return this;
}
});
const event = createEvent(reqProxy, resProxy);
event.context = incomingEvent.context;
const body = await handler(event) || _resSendBody;
const headers = event.res.getHeaders();
headers.etag = headers.Etag || headers.etag || `W/"${hash(body)}"`;
headers["last-modified"] = headers["Last-Modified"] || headers["last-modified"] || new Date().toUTCString();
const cacheControl = [];
if (opts.swr) {
if (opts.maxAge) {
cacheControl.push(`s-maxage=${opts.maxAge}`);
}
if (opts.staleMaxAge) {
cacheControl.push(`stale-while-revalidate=${opts.staleMaxAge}`);
} else {
cacheControl.push("stale-while-revalidate");
}
} else if (opts.maxAge) {
cacheControl.push(`max-age=${opts.maxAge}`);
}
if (cacheControl.length) {
headers["cache-control"] = cacheControl.join(", ");
}
const cacheEntry = {
code: event.res.statusCode,
headers,
body
};
return cacheEntry;
}, _opts);
return defineEventHandler(async (event) => {
if (opts.headersOnly) {
if (handleCacheHeaders(event, { maxAge: opts.maxAge })) {
return;
}
return handler(event);
}
const response = await _cachedHandler(event);
if (event.res.headersSent || event.res.writableEnded) {
return response.body;
}
if (handleCacheHeaders(event, {
modifiedTime: new Date(response.headers["last-modified"]),
etag: response.headers.etag,
maxAge: opts.maxAge
})) {
return;
}
event.res.statusCode = response.code;
for (const name in response.headers) {
event.res.setHeader(name, response.headers[name]);
}
return response.body;
});
}
function cloneWithProxy(obj, overrides) {
return new Proxy(obj, {
get(target, property, receiver) {
if (property in overrides) {
return overrides[property];
}
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
if (property in overrides) {
overrides[property] = value;
return true;
}
return Reflect.set(target, property, value, receiver);
}
});
}
export const cachedEventHandler = defineCachedEventHandler;
+1
View File
@@ -0,0 +1 @@
export {};
+4
View File
@@ -0,0 +1,4 @@
import { $fetch } from "ofetch";
if (!globalThis.$fetch) {
globalThis.$fetch = $fetch;
}
+3
View File
@@ -0,0 +1,3 @@
declare const config: Readonly<Record<string, any>>;
export declare const useRuntimeConfig: () => Readonly<Record<string, any>>;
export default config;
+40
View File
@@ -0,0 +1,40 @@
import destr from "destr";
import { snakeCase } from "scule";
const _runtimeConfig = process.env.RUNTIME_CONFIG;
const ENV_PREFIX = "NITRO_";
const ENV_PREFIX_ALT = _runtimeConfig.nitro.envPrefix ?? process.env.NITRO_ENV_PREFIX ?? "_";
const getEnv = (key) => {
const envKey = snakeCase(key).toUpperCase();
return destr(process.env[ENV_PREFIX + envKey] ?? process.env[ENV_PREFIX_ALT + envKey]);
};
function isObject(input) {
return typeof input === "object" && !Array.isArray(input);
}
function overrideConfig(obj, parentKey = "") {
for (const key in obj) {
const subKey = parentKey ? `${parentKey}_${key}` : key;
const envValue = getEnv(subKey);
if (isObject(obj[key])) {
if (isObject(envValue)) {
obj[key] = { ...obj[key], ...envValue };
}
overrideConfig(obj[key], subKey);
} else {
obj[key] = envValue ?? obj[key];
}
}
}
overrideConfig(_runtimeConfig);
const config = deepFreeze(_runtimeConfig);
export const useRuntimeConfig = () => config;
export default config;
function deepFreeze(object) {
const propNames = Object.getOwnPropertyNames(object);
for (const name of propNames) {
const value = object[name];
if (value && typeof value === "object") {
deepFreeze(value);
}
}
return Object.freeze(object);
}
+2
View File
@@ -0,0 +1,2 @@
declare const _default: import("./plugin").NitroAppPlugin;
export default _default;
+5
View File
@@ -0,0 +1,5 @@
import { createDebugger } from "hookable";
import { defineNitroPlugin } from "./plugin.mjs";
export default defineNitroPlugin((nitro) => {
createDebugger(nitro.hooks, { tag: "nitro-runtime" });
});
+8
View File
@@ -0,0 +1,8 @@
import type { APIGatewayProxyEvent, APIGatewayProxyEventV2, APIGatewayProxyResult, APIGatewayProxyResultV2, Context } from 'aws-lambda';
import '#internal/nitro/virtual/polyfill';
type Event = Omit<APIGatewayProxyEvent, 'pathParameters' | 'stageVariables' | 'requestContext' | 'resource'> | Omit<APIGatewayProxyEventV2, 'pathParameters' | 'stageVariables' | 'requestContext' | 'resource'>;
type Result = Exclude<APIGatewayProxyResult | APIGatewayProxyResultV2, string> & {
statusCode: number;
};
export declare const handler: (event: Event, context: Context) => Promise<Result>;
export {};
+34
View File
@@ -0,0 +1,34 @@
import "#internal/nitro/virtual/polyfill";
import { withQuery } from "ufo";
import { nitroApp } from "../app.mjs";
export const handler = async function handler2(event, context) {
const query = { ...event.queryStringParameters, ...event.multiValueQueryStringParameters };
const url = withQuery(event.path || event.rawPath, query);
const method = event.httpMethod || event.requestContext?.http?.method || "get";
if ("cookies" in event && event.cookies) {
event.headers.cookie = event.cookies.join(";");
}
const r = await nitroApp.localCall({
event,
url,
context,
headers: normalizeIncomingHeaders(event.headers),
method,
query,
body: event.body
});
const outgoingCookies = r.headers["set-cookie"];
const cookies = Array.isArray(outgoingCookies) ? outgoingCookies : outgoingCookies?.split(",") || [];
return {
cookies,
statusCode: r.status,
headers: normalizeOutgoingHeaders(r.headers),
body: r.body.toString()
};
};
function normalizeIncomingHeaders(headers) {
return Object.fromEntries(Object.entries(headers || {}).map(([key, value]) => [key.toLowerCase(), value]));
}
function normalizeOutgoingHeaders(headers) {
return Object.fromEntries(Object.entries(headers).filter(([key]) => !["set-cookie"].includes(key)).map(([k, v]) => [k, Array.isArray(v) ? v.join(",") : v]));
}
+2
View File
@@ -0,0 +1,2 @@
import '#internal/nitro/virtual/polyfill';
export declare function handle(context: any, req: any): Promise<void>;
+16
View File
@@ -0,0 +1,16 @@
import "#internal/nitro/virtual/polyfill";
import { nitroApp } from "../app.mjs";
export async function handle(context, req) {
const url = "/" + (req.params.url || "");
const { body, status, statusText, headers } = await nitroApp.localCall({
url,
headers: req.headers,
method: req.method,
body: req.rawBody
});
context.res = {
status,
headers,
body: body ? body.toString() : statusText
};
}
+2
View File
@@ -0,0 +1,2 @@
import '#internal/nitro/virtual/polyfill';
export declare function handle(context: any, req: any): Promise<void>;
+23
View File
@@ -0,0 +1,23 @@
import "#internal/nitro/virtual/polyfill";
import { parseURL } from "ufo";
import { nitroApp } from "../app.mjs";
export async function handle(context, req) {
let url;
if (req.headers["x-ms-original-url"]) {
const parsedURL = parseURL(req.headers["x-ms-original-url"]);
url = parsedURL.pathname + parsedURL.search;
} else {
url = "/api/" + (req.params.url || "");
}
const { body, status, statusText, headers } = await nitroApp.localCall({
url,
headers: req.headers,
method: req.method,
body: req.rawBody
});
context.res = {
status,
headers,
body: body ? body.toString() : statusText
};
}
+1
View File
@@ -0,0 +1 @@
import '#internal/nitro/virtual/polyfill';
+20
View File
@@ -0,0 +1,20 @@
import "#internal/nitro/virtual/polyfill";
import { nitroApp } from "../app.mjs";
async function cli() {
const url = process.argv[2] || "/";
const debug = (label, ...args) => console.debug(`> ${label}:`, ...args);
const r = await nitroApp.localCall({ url });
debug("URL", url);
debug("StatusCode", r.status);
debug("StatusMessage", r.statusText);
for (const header of r.headers.entries()) {
debug(header[0], header[1]);
}
console.log("\n", r.body.toString());
}
if (require.main === module) {
cli().catch((err) => {
console.error(err);
process.exit(1);
});
}
+18
View File
@@ -0,0 +1,18 @@
import '#internal/nitro/virtual/polyfill';
/** @see https://developers.cloudflare.com/pages/platform/functions/#writing-your-first-function */
interface CFRequestContext {
/** same as existing Worker API */
request: any;
/** same as existing Worker API */
env: any;
/** if filename includes [id] or [[path]] **/
params: any;
/** Same as ctx.waitUntil in existing Worker API */
waitUntil: any;
/** Used for middleware or to fetch assets */
next: any;
/** Arbitrary space for passing data between middlewares */
data: any;
}
export declare function onRequest(ctx: CFRequestContext): Promise<any>;
export {};
+33
View File
@@ -0,0 +1,33 @@
import "#internal/nitro/virtual/polyfill";
import { requestHasBody } from "../utils.mjs";
import { nitroApp } from "../app.mjs";
export async function onRequest(ctx) {
try {
const asset = await ctx.next();
if (asset.status !== 404) {
return asset;
}
} catch (_err) {
}
const url = new URL(ctx.request.url);
let body;
if (requestHasBody(ctx.request)) {
body = Buffer.from(await ctx.request.arrayBuffer());
}
const r = await nitroApp.localCall({
url: url.pathname + url.search,
method: ctx.request.method,
headers: ctx.request.headers,
host: url.hostname,
protocol: url.protocol,
body
});
return new Response(r.body, {
headers: normalizeOutgoingHeaders(r.headers),
status: r.status,
statusText: r.statusText
});
}
function normalizeOutgoingHeaders(headers) {
return Object.entries(headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(",") : v]);
}
+1
View File
@@ -0,0 +1 @@
import '#internal/nitro/virtual/polyfill';
+45
View File
@@ -0,0 +1,45 @@
import "#internal/nitro/virtual/polyfill";
import { getAssetFromKV, mapRequestToAsset } from "@cloudflare/kv-asset-handler";
import { withoutBase } from "ufo";
import { requestHasBody } from "../utils.mjs";
import { nitroApp } from "../app.mjs";
import { useRuntimeConfig } from "#internal/nitro";
addEventListener("fetch", (event) => {
event.respondWith(handleEvent(event));
});
async function handleEvent(event) {
try {
return await getAssetFromKV(event, { cacheControl: assetsCacheControl, mapRequestToAsset: baseURLModifier });
} catch (_err) {
}
const url = new URL(event.request.url);
let body;
if (requestHasBody(event.request)) {
body = Buffer.from(await event.request.arrayBuffer());
}
const r = await nitroApp.localCall({
event,
url: url.pathname + url.search,
host: url.hostname,
protocol: url.protocol,
headers: Object.fromEntries(event.request.headers.entries()),
method: event.request.method,
redirect: event.request.redirect,
body
});
return new Response(r.body, {
headers: normalizeOutgoingHeaders(r.headers),
status: r.status,
statusText: r.statusText
});
}
function assetsCacheControl(_request) {
return {};
}
const baseURLModifier = (request) => {
const url = withoutBase(request.url, useRuntimeConfig().app.baseURL);
return mapRequestToAsset(new Request(url, request));
};
function normalizeOutgoingHeaders(headers) {
return Object.entries(headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(",") : v]);
}
+1
View File
@@ -0,0 +1 @@
import '#internal/nitro/virtual/polyfill';
+31
View File
@@ -0,0 +1,31 @@
import "#internal/nitro/virtual/polyfill";
import { serve } from "https://deno.land/std/http/server.ts";
import { requestHasBody, useRequestBody } from "../utils.mjs";
import { nitroApp } from "../app.mjs";
serve((request) => {
return handleRequest(request);
});
async function handleRequest(request) {
const url = new URL(request.url);
let body;
if (requestHasBody(request)) {
body = await useRequestBody(request);
}
const r = await nitroApp.localCall({
url: url.pathname + url.search,
host: url.hostname,
protocol: url.protocol,
headers: Object.fromEntries(request.headers.entries()),
method: request.method,
redirect: request.redirect,
body
});
return new Response(r.body || void 0, {
headers: normalizeOutgoingHeaders(r.headers),
status: r.status,
statusText: r.statusText
});
}
function normalizeOutgoingHeaders(headers) {
return Object.entries(headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(",") : v]);
}
+2
View File
@@ -0,0 +1,2 @@
import '#internal/nitro/virtual/polyfill';
export declare const server: any;
+5
View File
@@ -0,0 +1,5 @@
import "#internal/nitro/virtual/polyfill";
import functions from "firebase-functions";
import { toNodeListener } from "h3";
import { nitroApp } from "../app.mjs";
export const server = functions.https.onRequest(toNodeListener(nitroApp.h3App));
+1
View File
@@ -0,0 +1 @@
export declare const handler: import("@netlify/functions").Handler;
+3
View File
@@ -0,0 +1,3 @@
import { builder } from "@netlify/functions";
import { handler as _handler } from "#internal/nitro/entries/aws-lambda";
export const handler = builder(_handler);
+2
View File
@@ -0,0 +1,2 @@
import '#internal/nitro/virtual/polyfill';
export default function (request: Request, _context: any): Promise<Response>;
+24
View File
@@ -0,0 +1,24 @@
import "#internal/nitro/virtual/polyfill";
import { nitroApp } from "../app.mjs";
import { requestHasBody, useRequestBody } from "../utils.mjs";
export default async function(request, _context) {
const url = new URL(request.url);
let body;
if (requestHasBody(request)) {
body = await useRequestBody(request);
}
const r = await nitroApp.localCall({
url: url.pathname + url.search,
host: url.hostname,
protocol: url.protocol,
headers: request.headers,
method: request.method,
redirect: request.redirect,
body
});
return new Response(r.body, {
headers: r.headers,
status: r.status,
statusText: r.statusText
});
}
+3
View File
@@ -0,0 +1,3 @@
import '#internal/nitro/virtual/polyfill';
import type { Handler } from '@netlify/functions/dist/main';
export declare const handler: Handler;
+41
View File
@@ -0,0 +1,41 @@
import "#internal/nitro/virtual/polyfill";
import { withQuery } from "ufo";
import { nitroApp } from "../app.mjs";
import { getRouteRulesForPath } from "../route-rules.mjs";
export const handler = async function handler2(event, context) {
const query = { ...event.queryStringParameters, ...event.multiValueQueryStringParameters };
const url = withQuery(event.path, query);
const routeRules = getRouteRulesForPath(url);
if (routeRules.cache && (routeRules.cache.swr || routeRules.cache.static)) {
const builder = await import("@netlify/functions").then((r) => r.builder || r.default.builder);
const ttl = typeof routeRules.cache.swr === "number" ? routeRules.cache.swr : 60;
const swrHandler = routeRules.cache.swr ? (event2, context2) => lambda(event2, context2).then((r) => ({ ...r, ttl })) : lambda;
return builder(swrHandler)(event, context);
}
return lambda(event, context);
};
async function lambda(event, context) {
const query = { ...event.queryStringParameters, ...event.multiValueQueryStringParameters };
const url = withQuery(event.path, query);
const method = event.httpMethod || "get";
const r = await nitroApp.localCall({
event,
url,
context,
headers: normalizeIncomingHeaders(event.headers),
method,
query,
body: event.body
});
return {
statusCode: r.status,
headers: normalizeOutgoingHeaders(r.headers),
body: r.body.toString()
};
}
function normalizeIncomingHeaders(headers) {
return Object.fromEntries(Object.entries(headers || {}).map(([key, value]) => [key.toLowerCase(), value]));
}
function normalizeOutgoingHeaders(headers) {
return Object.fromEntries(Object.entries(headers).filter(([key]) => !["set-cookie"].includes(key)).map(([k, v]) => [k, Array.isArray(v) ? v.join(",") : v]));
}
+1
View File
@@ -0,0 +1 @@
import '#internal/nitro/virtual/polyfill';
+38
View File
@@ -0,0 +1,38 @@
import "#internal/nitro/virtual/polyfill";
import { Server } from "http";
import { tmpdir } from "os";
import { join } from "path";
import { mkdirSync } from "fs";
import { threadId, parentPort } from "worker_threads";
import { isWindows, provider } from "std-env";
import { toNodeListener } from "h3";
import { nitroApp } from "../app.mjs";
const server = new Server(toNodeListener(nitroApp.h3App));
function getAddress() {
if (provider === "stackblitz" || process.env.NITRO_NO_UNIX_SOCKET) {
return "0";
}
const socketName = `worker-${process.pid}-${threadId}.sock`;
if (isWindows) {
return join("\\\\.\\pipe\\nitro", socketName);
} else {
const socketDir = join(tmpdir(), "nitro");
mkdirSync(socketDir, { recursive: true });
return join(socketDir, socketName);
}
}
const listenAddress = getAddress();
server.listen(listenAddress, () => {
const _address = server.address();
parentPort.postMessage({
event: "listen",
address: typeof _address === "string" ? { socketPath: _address } : { host: "localhost", port: _address.port }
});
});
if (process.env.DEBUG) {
process.on("unhandledRejection", (err) => console.error("[nitro] [dev] [unhandledRejection]", err));
process.on("uncaughtException", (err) => console.error("[nitro] [dev] [uncaughtException]", err));
} else {
process.on("unhandledRejection", (err) => console.error("[nitro] [dev] [unhandledRejection] " + err));
process.on("uncaughtException", (err) => console.error("[nitro] [dev] [uncaughtException] " + err));
}
+2
View File
@@ -0,0 +1,2 @@
import '#internal/nitro/virtual/polyfill';
export declare const localFetch: (input: string | Request, init: import("unenv/runtime/fetch").FetchOptions) => Promise<Response>;
+10
View File
@@ -0,0 +1,10 @@
import "#internal/nitro/virtual/polyfill";
import { nitroApp } from "../app.mjs";
export const localFetch = nitroApp.localFetch;
if (process.env.DEBUG) {
process.on("unhandledRejection", (err) => console.error("[nitro] [dev] [unhandledRejection]", err));
process.on("uncaughtException", (err) => console.error("[nitro] [dev] [uncaughtException]", err));
} else {
process.on("unhandledRejection", (err) => console.error("[nitro] [dev] [unhandledRejection] " + err));
process.on("uncaughtException", (err) => console.error("[nitro] [dev] [uncaughtException] " + err));
}
+1
View File
@@ -0,0 +1 @@
export {};
+16
View File
@@ -0,0 +1,16 @@
import os from "node:os";
import cluster from "node:cluster";
if (cluster.isPrimary) {
const numberOfWorkers = parseInt(process.env.NITRO_CLUSTER_WORKERS) || os.cpus().length;
for (let i = 0; i < numberOfWorkers; i++) {
cluster.fork();
}
cluster.on("exit", () => {
cluster.fork();
});
} else {
import("./node-server").catch((error) => {
console.error(error);
process.exit(1);
});
}
+3
View File
@@ -0,0 +1,3 @@
import '#internal/nitro/virtual/polyfill';
declare const _default: {};
export default _default;
+31
View File
@@ -0,0 +1,31 @@
import "#internal/nitro/virtual/polyfill";
import { Server as HttpServer } from "http";
import { Server as HttpsServer } from "https";
import destr from "destr";
import { toNodeListener } from "h3";
import { nitroApp } from "../app.mjs";
import { useRuntimeConfig } from "#internal/nitro";
const cert = process.env.NITRO_SSL_CERT;
const key = process.env.NITRO_SSL_KEY;
const server = cert && key ? new HttpsServer({ key, cert }, toNodeListener(nitroApp.h3App)) : new HttpServer(toNodeListener(nitroApp.h3App));
const port = destr(process.env.NITRO_PORT || process.env.PORT) || 3e3;
const host = process.env.NITRO_HOST || process.env.HOST;
const s = server.listen(port, host, (err) => {
if (err) {
console.error(err);
process.exit(1);
}
const protocol = cert && key ? "https" : "http";
const i = s.address();
const baseURL = (useRuntimeConfig().app.baseURL || "").replace(/\/$/, "");
const url = `${protocol}://${i.family === "IPv6" ? `[${i.address}]` : i.address}:${i.port}${baseURL}`;
console.log(`Listening ${url}`);
});
if (process.env.DEBUG) {
process.on("unhandledRejection", (err) => console.error("[nitro] [dev] [unhandledRejection]", err));
process.on("uncaughtException", (err) => console.error("[nitro] [dev] [uncaughtException]", err));
} else {
process.on("unhandledRejection", (err) => console.error("[nitro] [dev] [unhandledRejection] " + err));
process.on("uncaughtException", (err) => console.error("[nitro] [dev] [uncaughtException] " + err));
}
export default {};
+4
View File
@@ -0,0 +1,4 @@
import '#internal/nitro/virtual/polyfill';
export declare const listener: import("h3").NodeListener;
/** @deprecated use new `listener` export instead */
export declare const handler: import("h3").NodeListener;
+12
View File
@@ -0,0 +1,12 @@
import "#internal/nitro/virtual/polyfill";
import { toNodeListener } from "h3";
import { nitroApp } from "../app.mjs";
export const listener = toNodeListener(nitroApp.h3App);
export const handler = listener;
if (process.env.DEBUG) {
process.on("unhandledRejection", (err) => console.error("[nitro] [dev] [unhandledRejection]", err));
process.on("uncaughtException", (err) => console.error("[nitro] [dev] [uncaughtException]", err));
} else {
process.on("unhandledRejection", (err) => console.error("[nitro] [dev] [unhandledRejection] " + err));
process.on("uncaughtException", (err) => console.error("[nitro] [dev] [uncaughtException] " + err));
}
+1
View File
@@ -0,0 +1 @@
import '#internal/nitro/virtual/polyfill';
+38
View File
@@ -0,0 +1,38 @@
import "#internal/nitro/virtual/polyfill";
import { requestHasBody, useRequestBody } from "../utils.mjs";
import { nitroApp } from "../app.mjs";
import { isPublicAssetURL } from "#internal/nitro/virtual/public-assets";
addEventListener("fetch", (event) => {
const url = new URL(event.request.url);
if (isPublicAssetURL(url.pathname) || url.pathname.includes("/_server/")) {
return;
}
event.respondWith(handleEvent(url, event));
});
async function handleEvent(url, event) {
let body;
if (requestHasBody(event.request)) {
body = await useRequestBody(event.request);
}
const r = await nitroApp.localCall({
event,
url: url.pathname + url.search,
host: url.hostname,
protocol: url.protocol,
headers: event.request.headers,
method: event.request.method,
redirect: event.request.redirect,
body
});
return new Response(r.body, {
headers: r.headers,
status: r.status,
statusText: r.statusText
});
}
self.addEventListener("install", () => {
self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(self.clients.claim());
});
+20
View File
@@ -0,0 +1,20 @@
import type { Handler } from 'aws-lambda';
import '#internal/nitro/virtual/polyfill';
interface StormkitEvent {
url: string;
path: string;
method: string;
body?: string;
query?: Record<string, Array<string>>;
headers?: Record<string, string>;
rawHeaders?: Array<string>;
}
export interface StormkitResult {
statusCode: number;
headers?: {
[header: string]: boolean | number | string;
} | undefined;
body?: string | undefined;
}
export declare const handler: Handler<StormkitEvent, StormkitResult>;
export {};
+22
View File
@@ -0,0 +1,22 @@
import "#internal/nitro/virtual/polyfill";
import { nitroApp } from "../app.mjs";
export const handler = async function(event, context) {
const method = event.method || "get";
const r = await nitroApp.localCall({
event,
url: event.url,
context,
headers: event.headers,
method,
query: event.query,
body: event.body
});
return {
statusCode: r.status,
headers: normalizeOutgoingHeaders(r.headers),
body: r.body.toString()
};
};
function normalizeOutgoingHeaders(headers) {
return Object.fromEntries(Object.entries(headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(",") : v]));
}
+2
View File
@@ -0,0 +1,2 @@
import '#internal/nitro/virtual/polyfill';
export default function handleEvent(request: any, event: any): Promise<Response>;
+27
View File
@@ -0,0 +1,27 @@
import "#internal/nitro/virtual/polyfill";
import { requestHasBody, useRequestBody } from "#internal/nitro/utils";
import { nitroApp } from "#internal/nitro/app";
export default async function handleEvent(request, event) {
const url = new URL(request.url);
let body;
if (requestHasBody(request)) {
body = await useRequestBody(request);
}
const r = await nitroApp.localCall({
event,
url: url.pathname + url.search,
host: url.hostname,
protocol: url.protocol,
headers: Object.fromEntries(request.headers.entries()),
method: request.method,
body
});
return new Response(r.body, {
headers: normalizeOutgoingHeaders(r.headers),
status: r.status,
statusText: r.statusText
});
}
function normalizeOutgoingHeaders(headers) {
return Object.entries(headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(",") : v]);
}
+4
View File
@@ -0,0 +1,4 @@
import '#internal/nitro/virtual/polyfill';
import { NodeListener } from 'h3';
declare const _default: NodeListener;
export default _default;
+15
View File
@@ -0,0 +1,15 @@
import "#internal/nitro/virtual/polyfill";
import { toNodeListener } from "h3";
import { parseQuery } from "ufo";
import { nitroApp } from "../app.mjs";
const handler = toNodeListener(nitroApp.h3App);
export default (function(req, res) {
const query = req.headers["x-now-route-matches"];
if (query) {
const { url } = parseQuery(query);
if (url) {
req.url = url;
}
}
return handler(req, res);
});
+3
View File
@@ -0,0 +1,3 @@
import type { NitroErrorHandler } from '../types';
declare const _default: NitroErrorHandler;
export default _default;
+65
View File
@@ -0,0 +1,65 @@
import { normalizeError, isJsonRequest } from "./utils.mjs";
const isDev = process.env.NODE_ENV === "development";
export default (function(error, event) {
const { stack, statusCode, statusMessage, message } = normalizeError(error);
const showDetails = isDev && statusCode !== 404;
const errorObject = {
url: event.req.url || "",
statusCode,
statusMessage,
message,
stack: showDetails ? stack.map((i) => i.text) : void 0
};
if (error.unhandled || error.fatal) {
const tags = [
"[nitro]",
"[request error]",
error.unhandled && "[unhandled]",
error.fatal && "[fatal]"
].filter(Boolean).join(" ");
console.error(tags, error.message + "\n" + stack.map((l) => " " + l.text).join(" \n"));
}
event.res.statusCode = statusCode;
if (statusMessage) {
event.res.statusMessage = statusMessage;
}
if (isJsonRequest(event)) {
event.res.setHeader("Content-Type", "application/json");
event.res.end(JSON.stringify(errorObject));
} else {
event.res.setHeader("Content-Type", "text/html");
event.res.end(renderHTMLError(errorObject));
}
});
function renderHTMLError(error) {
const statusCode = error.statusCode || 500;
const statusMessage = error.statusMessage || "Request Error";
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${statusCode} ${statusMessage}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico/css/pico.min.css">
</head>
<body>
<main class="container">
<dialog open>
<article>
<header>
<h2>${statusCode} ${statusMessage}</h2>
</header>
<code>
${error.message}<br><br>
${"\n" + (error.stack || []).map((i) => `&nbsp;&nbsp;${i}`).join("<br>")}
</code>
<footer>
<a href="/" onclick="event.preventDefault();history.back();">Go Back</a>
</footer>
</article>
</dialog>
</main>
</body>
</html>
`;
}
+7
View File
@@ -0,0 +1,7 @@
export { useStorage } from '#internal/nitro/virtual/storage';
export { useRuntimeConfig } from './config';
export * from './cache';
export { useNitroApp } from './app';
export * from './plugin';
export * from './renderer';
export { getRouteRules } from './route-rules';
+7
View File
@@ -0,0 +1,7 @@
export { useStorage } from "#internal/nitro/virtual/storage";
export { useRuntimeConfig } from "./config.mjs";
export * from "./cache.mjs";
export { useNitroApp } from "./app.mjs";
export * from "./plugin.mjs";
export * from "./renderer.mjs";
export { getRouteRules } from "./route-rules.mjs";
+6
View File
@@ -0,0 +1,6 @@
import type { NitroApp } from './app';
export interface NitroAppPlugin {
(nitro: NitroApp): void;
}
export declare function defineNitroPlugin(def: NitroAppPlugin): NitroAppPlugin;
export declare const nitroPlugin: typeof defineNitroPlugin;
+4
View File
@@ -0,0 +1,4 @@
export function defineNitroPlugin(def) {
return def;
}
export const nitroPlugin = defineNitroPlugin;
+9
View File
@@ -0,0 +1,9 @@
import { H3Event } from 'h3';
export interface RenderResponse {
body: string;
statusCode: number;
statusMessage: string;
headers: Record<string, string>;
}
export type RenderHandler = (event: H3Event) => Partial<RenderResponse> | Promise<Partial<RenderResponse>>;
export declare function defineRenderHandler(handler: RenderHandler): import("h3").EventHandler<string | undefined>;
+33
View File
@@ -0,0 +1,33 @@
import { eventHandler } from "h3";
import { useNitroApp } from "./app.mjs";
export function defineRenderHandler(handler) {
return eventHandler(async (event) => {
if (event.req.url.endsWith("/favicon.ico")) {
event.res.setHeader("Content-Type", "image/x-icon");
event.res.end("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
return;
}
const response = await handler(event);
if (!response) {
if (!event.res.writableEnded) {
event.res.statusCode = event.res.statusCode === 200 ? 500 : event.res.statusCode;
event.res.end("No response returned from render handler: " + event.req.url);
}
return;
}
const nitroApp = useNitroApp();
await nitroApp.hooks.callHook("render:response", response, { event });
if (!event.res.headersSent && response.headers) {
for (const header in response.headers) {
event.res.setHeader(header, response.headers[header]);
}
if (response.statusCode) {
event.res.statusCode = response.statusCode;
}
if (response.statusMessage) {
event.res.statusMessage = response.statusMessage;
}
}
return typeof response.body === "string" ? response.body : JSON.stringify(response.body);
});
}
+5
View File
@@ -0,0 +1,5 @@
import { H3Event } from 'h3';
import type { NitroRouteRules } from 'nitropack';
export declare function createRouteRulesHandler(): import("h3").EventHandler<void | undefined>;
export declare function getRouteRules(event: H3Event): NitroRouteRules;
export declare function getRouteRulesForPath(path: string): NitroRouteRules;
+28
View File
@@ -0,0 +1,28 @@
import { eventHandler, sendRedirect, setHeaders } from "h3";
import defu from "defu";
import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
import { useRuntimeConfig } from "./config.mjs";
const config = useRuntimeConfig();
const _routeRulesMatcher = toRouteMatcher(createRadixRouter({ routes: config.nitro.routeRules }));
export function createRouteRulesHandler() {
return eventHandler((event) => {
const routeRules = getRouteRules(event);
if (routeRules.headers) {
setHeaders(event, routeRules.headers);
}
if (routeRules.redirect) {
return sendRedirect(event, routeRules.redirect.to, routeRules.redirect.statusCode);
}
});
}
export function getRouteRules(event) {
event.context._nitro = event.context._nitro || {};
if (!event.context._nitro.routeRules) {
const path = new URL(event.req.url, "http://localhost").pathname;
event.context._nitro.routeRules = getRouteRulesForPath(path);
}
return event.context._nitro.routeRules;
}
export function getRouteRulesForPath(path) {
return defu({}, ..._routeRulesMatcher.matchAll(path).reverse());
}
+2
View File
@@ -0,0 +1,2 @@
declare const _default: import("h3").EventHandler<any>;
export default _default;
+66
View File
@@ -0,0 +1,66 @@
import { eventHandler, createError } from "h3";
import { joinURL, withoutTrailingSlash, withLeadingSlash, parseURL } from "ufo";
import { getAsset, readAsset, isPublicAssetURL } from "#internal/nitro/virtual/public-assets";
const METHODS = ["HEAD", "GET"];
const EncodingMap = { gzip: ".gz", br: ".br" };
export default eventHandler((event) => {
if (event.req.method && !METHODS.includes(event.req.method)) {
return;
}
let id = decodeURIComponent(withLeadingSlash(withoutTrailingSlash(parseURL(event.req.url).pathname)));
let asset;
const encodingHeader = String(event.req.headers["accept-encoding"] || "");
const encodings = encodingHeader.split(",").map((e) => EncodingMap[e.trim()]).filter(Boolean).sort().concat([""]);
if (encodings.length > 1) {
event.res.setHeader("Vary", "Accept-Encoding");
}
for (const encoding of encodings) {
for (const _id of [id + encoding, joinURL(id, "index.html" + encoding)]) {
const _asset = getAsset(_id);
if (_asset) {
asset = _asset;
id = _id;
break;
}
}
}
if (!asset) {
if (isPublicAssetURL(id)) {
throw createError({
statusMessage: "Cannot find static asset " + id,
statusCode: 404
});
}
return;
}
const ifNotMatch = event.req.headers["if-none-match"] === asset.etag;
if (ifNotMatch) {
event.res.statusCode = 304;
event.res.end();
return;
}
const ifModifiedSinceH = event.req.headers["if-modified-since"];
if (ifModifiedSinceH && asset.mtime) {
if (new Date(ifModifiedSinceH) >= new Date(asset.mtime)) {
event.res.statusCode = 304;
event.res.end();
return;
}
}
if (asset.type && !event.res.getHeader("Content-Type")) {
event.res.setHeader("Content-Type", asset.type);
}
if (asset.etag && !event.res.getHeader("ETag")) {
event.res.setHeader("ETag", asset.etag);
}
if (asset.mtime && !event.res.getHeader("Last-Modified")) {
event.res.setHeader("Last-Modified", asset.mtime);
}
if (asset.encoding && !event.res.getHeader("Content-Encoding")) {
event.res.setHeader("Content-Encoding", asset.encoding);
}
if (asset.size && !event.res.getHeader("Content-Length")) {
event.res.setHeader("Content-Length", asset.size);
}
return readAsset(id);
});
+2
View File
@@ -0,0 +1,2 @@
export declare const globalTiming: any;
export declare const timingMiddleware: import("h3").EventHandler<void>;
+19
View File
@@ -0,0 +1,19 @@
import { eventHandler } from "h3";
export const globalTiming = globalThis.__timing__ || {
start: () => 0,
end: () => 0,
metrics: []
};
export const timingMiddleware = eventHandler((event) => {
const start = globalTiming.start();
const _end = event.res.end;
event.res.end = function(chunk, encoding, cb) {
const metrics = [["Generate", globalTiming.end(start)], ...globalTiming.metrics];
const serverTiming = metrics.map((m) => `-;dur=${m[1]};desc="${encodeURIComponent(m[0])}"`).join(", ");
if (!event.res.headersSent) {
event.res.setHeader("Server-Timing", serverTiming);
}
_end.call(event.res, chunk, encoding, cb);
return this;
}.bind(event.res);
});
+4
View File
@@ -0,0 +1,4 @@
export type { NitroApp } from './app';
export type { CacheEntry, CacheOptions, ResponseCacheEntry, CachedEventHandlerOptions } from './cache';
export type { NitroAppPlugin } from './plugin';
export type { RenderResponse, RenderHandler } from './renderer';
View File
+14
View File
@@ -0,0 +1,14 @@
import type { H3Event } from 'h3';
export declare function requestHasBody(request: globalThis.Request): boolean;
export declare function useRequestBody(request: globalThis.Request): Promise<any>;
export declare function hasReqHeader(event: H3Event, name: string, includes: string): boolean | "" | undefined;
export declare function isJsonRequest(event: H3Event): boolean | undefined;
export declare function normalizeError(error: any): {
stack: {
text: string;
internal: boolean;
}[];
statusCode: any;
statusMessage: any;
message: any;
};
+51
View File
@@ -0,0 +1,51 @@
import { getRequestHeader } from "h3";
const METHOD_WITH_BODY_RE = /post|put|patch/i;
const TEXT_MIME_RE = /application\/text|text\/html/;
const JSON_MIME_RE = /application\/json/;
export function requestHasBody(request) {
return METHOD_WITH_BODY_RE.test(request.method);
}
export async function useRequestBody(request) {
const contentType = request.headers.get("content-type") || "";
if (contentType.includes("form")) {
const formData = await request.formData();
const body = /* @__PURE__ */ Object.create(null);
for (const entry of formData.entries()) {
body[entry[0]] = entry[1];
}
return body;
} else if (JSON_MIME_RE.test(contentType)) {
return request.json();
} else if (TEXT_MIME_RE.test(contentType)) {
return request.text();
} else {
const blob = await request.blob();
return URL.createObjectURL(blob);
}
}
export function hasReqHeader(event, name, includes) {
const value = getRequestHeader(event, name);
return value && typeof value === "string" && value.toLowerCase().includes(includes);
}
export function isJsonRequest(event) {
return hasReqHeader(event, "accept", "application/json") || hasReqHeader(event, "user-agent", "curl/") || hasReqHeader(event, "user-agent", "httpie/") || event.req.url?.endsWith(".json") || event.req.url?.includes("/api/");
}
export function normalizeError(error) {
const cwd = process.cwd();
const stack = (error.stack || "").split("\n").splice(1).filter((line) => line.includes("at ")).map((line) => {
const text = line.replace(cwd + "/", "./").replace("webpack:/", "").replace("file://", "").trim();
return {
text,
internal: line.includes("node_modules") && !line.includes(".cache") || line.includes("internal") || line.includes("new Promise")
};
});
const statusCode = error.statusCode || 500;
const statusMessage = error.statusMessage ?? (statusCode === 404 ? "Not Found" : "");
const message = error.message || error.toString();
return {
stack,
statusCode,
statusMessage,
message
};
}
+5
View File
@@ -0,0 +1,5 @@
import type { NitroErrorHandler } from '../../types'
const errorHandler: NitroErrorHandler
export default errorHandler
+3
View File
@@ -0,0 +1,3 @@
import type { NitroAppPlugin } from '../plugin'
export const plugins: NitroAppPlugin[] = []
+2
View File
@@ -0,0 +1,2 @@
declare const _default: {};
export default _default;
+1
View File
@@ -0,0 +1 @@
export default {};
+4
View File
@@ -0,0 +1,4 @@
export const publicAssetBases: string[]
export const isPublicAssetURL: (id: string) => boolean
export const readAsset: (id: string) => Promise<Buffer>
export const getAsset: (id: string) => any
+4
View File
@@ -0,0 +1,4 @@
export interface AssetMeta { type?: string, etag?: string, mtime?: string }
export function readAsset<T = any> (id: string): Promise<T>
export function statAsset (id: string): Promise<AssetMeta>
export function getKeys() : Promise<string[]>
+14
View File
@@ -0,0 +1,14 @@
import type { H3EventHandler, LazyEventHandler, RouterMethod } from 'h3'
type HandlerDefinition = {
route: string
lazy?: boolean
middleware?: boolean
handler: H3EventHandler
method?: RouterMethod
} & {
lazy: true
handler: LazyEventHandler
}
export const handlers: HandlerDefinition[]
+3
View File
@@ -0,0 +1,3 @@
import type { Storage } from 'unstorage'
export declare const useStorage: () => Storage
File diff suppressed because it is too large Load Diff
+141
View File
@@ -0,0 +1,141 @@
{
"name": "nitropack",
"version": "1.0.0",
"description": "Build and Deploy Universal JavaScript Servers",
"repository": "unjs/nitro",
"license": "MIT",
"type": "module",
"exports": {
".": "./dist/index.mjs",
"./cli": "./dist/cli.mjs",
"./runtime/*": "./dist/runtime/*.mjs",
"./dist/runtime/*": "./dist/runtime/*.mjs",
"./package.json": "./package.json"
},
"main": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"bin": {
"nitro": "./dist/cli.mjs",
"nitropack": "./dist/cli.mjs"
},
"files": [
"dist"
],
"scripts": {
"build": "unbuild",
"dev": "pnpm nitro dev playground",
"dev:build": "pnpm nitro build playground",
"dev:start": "node playground/.output/server/index.mjs",
"docs:build": "vitepress build docs",
"docs:dev": "vitepress dev docs",
"docs:serve": "vitepress serve docs",
"lint": "eslint --ext .ts,.mjs,.cjs .",
"nitro": "jiti ./src/cli.ts",
"prepack": "pnpm build",
"release": "pnpm test && pnpm build && changelogen --release && pnpm publish && git push --follow-tags",
"stub": "unbuild --stub",
"test": "pnpm lint && vitest run --silent",
"test:types": "tsc --noEmit && pnpm test:fixture:types",
"test:fixture:types": "pnpm stub && jiti ./test/scripts/gen-fixture-types.ts && cd test/fixture && tsc --noEmit"
},
"resolutions": {
"nitropack": "link:."
},
"dependencies": {
"@cloudflare/kv-asset-handler": "^0.2.0",
"@netlify/functions": "^1.3.0",
"@rollup/plugin-alias": "^4.0.2",
"@rollup/plugin-commonjs": "^23.0.2",
"@rollup/plugin-inject": "^5.0.2",
"@rollup/plugin-json": "^5.0.1",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-replace": "^5.0.1",
"@rollup/plugin-wasm": "^6.0.1",
"@rollup/pluginutils": "^5.0.2",
"@vercel/nft": "^0.22.1",
"archiver": "^5.3.1",
"c12": "^1.0.1",
"chalk": "^5.1.2",
"chokidar": "^3.5.3",
"consola": "^2.15.3",
"cookie-es": "^0.5.0",
"defu": "^6.1.1",
"destr": "^1.2.1",
"dot-prop": "^7.2.0",
"esbuild": "^0.15.14",
"escape-string-regexp": "^5.0.0",
"etag": "^1.8.1",
"fs-extra": "^10.1.0",
"globby": "^13.1.2",
"gzip-size": "^7.0.0",
"h3": "^1.0.1",
"hookable": "^5.4.2",
"http-proxy": "^1.18.1",
"is-primitive": "^3.0.1",
"jiti": "^1.16.0",
"klona": "^2.0.5",
"knitwork": "^1.0.0",
"listhen": "^1.0.0",
"mime": "^3.0.0",
"mlly": "^1.0.0",
"mri": "^1.2.0",
"node-fetch-native": "^1.0.1",
"ohash": "^1.0.0",
"ofetch": "^1.0.0",
"pathe": "^1.0.0",
"perfect-debounce": "^0.1.3",
"pkg-types": "^1.0.1",
"pretty-bytes": "^6.0.0",
"radix3": "^1.0.0",
"rollup": "^2.79.1",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-visualizer": "^5.8.3",
"scule": "^1.0.0",
"semver": "^7.3.8",
"serve-placeholder": "^2.0.1",
"serve-static": "^1.15.0",
"source-map-support": "^0.5.21",
"std-env": "^3.3.1",
"ufo": "^1.0.0",
"unenv": "^1.0.0",
"unimport": "^1.0.0",
"unstorage": "^1.0.1"
},
"devDependencies": {
"@nuxtjs/eslint-config-typescript": "^11.0.0",
"@types/aws-lambda": "^8.10.108",
"@types/etag": "^1.8.1",
"@types/fs-extra": "^9.0.13",
"@types/http-proxy": "^1.17.9",
"@types/node-fetch": "^2.6.2",
"@types/object-hash": "^2.2.1",
"@types/semver": "^7.3.13",
"@types/serve-static": "^1.15.0",
"@vitest/coverage-c8": "^0.25.2",
"c8": "^7.12.0",
"changelogen": "^0.4.0",
"edge-runtime": "2.0.2",
"eslint": "^8.27.0",
"eslint-config-unjs": "^0.0.2",
"execa": "^6.1.0",
"expect-type": "^0.15.0",
"miniflare": "^2.11.0",
"typescript": "^4.9.3",
"unbuild": "^1.0.1",
"vitest": "^0.25.2"
},
"packageManager": "pnpm@7.16.0",
"engines": {
"node": "^14.16.0 || ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"react",
"@types/react",
"react-dom",
"@algolia/client-search"
]
}
}
}