vike-lite 1.4.0 → 1.6.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 +1 -7
- package/dist/__internal/server.d.mts +3 -3
- package/dist/__internal/shared.d.mts +1 -1
- package/dist/__internal/shared.mjs +1 -1
- package/dist/{index-kftPCG4J.d.mts → index-Dt5n1zWh.d.mts} +2 -2
- package/dist/{matchRoute-BNUQpQu-.mjs → matchRoute-nTNPxoMq.mjs} +12 -6
- package/dist/server.mjs +17 -8
- package/dist/vite.d.mts +18 -3
- package/dist/vite.mjs +64 -38
- package/package.json +1 -1
- package/LICENSE +0 -9
package/README.md
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
# vike-lite
|
|
2
2
|
|
|
3
|
-
Light version of [Vike](https://vike.dev)
|
|
4
|
-
|
|
5
|
-
### ✨ Features
|
|
6
|
-
❯ **Zero dependencies:**<br> _light_ with less dependencies and essential checks
|
|
7
|
-
❯ **Functionalities:**<br> [See documentation](doc/FUNCTIONALITIES.md)
|
|
8
|
-
|
|
9
3
|
### ⚙️ Install
|
|
10
4
|
| Package Manager | Command
|
|
11
5
|
| - | -
|
|
@@ -79,4 +73,4 @@ git clone https://github.com/node-ecosystem/vike-lite.git
|
|
|
79
73
|
|
|
80
74
|
---
|
|
81
75
|
|
|
82
|
-
This project is licensed under the [MIT License](LICENSE).
|
|
76
|
+
This project is licensed under the [MIT License](../../LICENSE).
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as Config } from "../index-
|
|
1
|
+
import { t as Config } from "../index-Dt5n1zWh.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/server/store.d.ts
|
|
4
4
|
interface VikeState {
|
|
5
|
-
routes:
|
|
6
|
-
errorRoute:
|
|
5
|
+
routes: typeof import('virtual:routes')['routes'];
|
|
6
|
+
errorRoute: typeof import('virtual:routes')['errorRoute'] | null;
|
|
7
7
|
config: Config | null;
|
|
8
8
|
manifest: Manifest | undefined;
|
|
9
9
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as RenderContext, r as matchRoute, t as Config } from "../index-
|
|
1
|
+
import { n as RenderContext, r as matchRoute, t as Config } from "../index-Dt5n1zWh.mjs";
|
|
2
2
|
export { Config, RenderContext, matchRoute };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as matchRoute } from "../matchRoute-
|
|
1
|
+
import { t as matchRoute } from "../matchRoute-nTNPxoMq.mjs";
|
|
2
2
|
export { matchRoute };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
//#region src/shared/matchRoute.d.ts
|
|
1
|
+
//#region src/__internal/shared/matchRoute.d.ts
|
|
2
2
|
declare function matchRoute(urlPathname: string, routes: typeof import('virtual:routes').routes): {
|
|
3
3
|
route: any;
|
|
4
4
|
routeParams: Record<string, string>;
|
|
5
5
|
} | null;
|
|
6
6
|
//#endregion
|
|
7
|
-
//#region src/shared/index.d.ts
|
|
7
|
+
//#region src/__internal/shared/index.d.ts
|
|
8
8
|
interface RenderContext {
|
|
9
9
|
pageContext: any;
|
|
10
10
|
Page: unknown;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
//#region src/shared/matchRoute.ts
|
|
1
|
+
//#region src/__internal/shared/matchRoute.ts
|
|
2
2
|
const regexCache = /* @__PURE__ */ new Map();
|
|
3
|
+
function escapeRegex(str) {
|
|
4
|
+
return str.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
5
|
+
}
|
|
3
6
|
function matchRoute(urlPathname, routes) {
|
|
4
7
|
for (const route of routes) {
|
|
5
8
|
if (!route.path.includes(":")) {
|
|
@@ -12,10 +15,13 @@ function matchRoute(urlPathname, routes) {
|
|
|
12
15
|
let compiled = regexCache.get(route.path);
|
|
13
16
|
if (!compiled) {
|
|
14
17
|
const paramNames = [];
|
|
15
|
-
const regexPath = route.path.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
const regexPath = route.path.split("/").map((segment) => {
|
|
19
|
+
if (segment.startsWith(":")) {
|
|
20
|
+
paramNames.push(segment.slice(1));
|
|
21
|
+
return "([^/]+)";
|
|
22
|
+
}
|
|
23
|
+
return escapeRegex(segment);
|
|
24
|
+
}).join("/");
|
|
19
25
|
compiled = {
|
|
20
26
|
regex: new RegExp(`^${regexPath}/?$`),
|
|
21
27
|
paramNames
|
|
@@ -25,7 +31,7 @@ function matchRoute(urlPathname, routes) {
|
|
|
25
31
|
const match = urlPathname.match(compiled.regex);
|
|
26
32
|
if (match) {
|
|
27
33
|
const routeParams = {};
|
|
28
|
-
for (let i = 0; i < compiled.paramNames.length; i++) routeParams[compiled.paramNames[i]] = match[i + 1];
|
|
34
|
+
for (let i = 0; i < compiled.paramNames.length; i++) routeParams[compiled.paramNames[i]] = decodeURIComponent(match[i + 1]);
|
|
29
35
|
return {
|
|
30
36
|
route,
|
|
31
37
|
routeParams
|
package/dist/server.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as matchRoute } from "./matchRoute-
|
|
1
|
+
import { t as matchRoute } from "./matchRoute-nTNPxoMq.mjs";
|
|
2
2
|
import { n as store } from "./store-CfUB1COP.mjs";
|
|
3
3
|
//#region src/utils/serializeContext.ts
|
|
4
4
|
const ESCAPE_LOOKUP = {
|
|
@@ -26,11 +26,15 @@ var AbortRender = class extends Error {
|
|
|
26
26
|
//#endregion
|
|
27
27
|
//#region src/server/renderPage.ts
|
|
28
28
|
const isProd = process.env.NODE_ENV === "production";
|
|
29
|
+
const { BASE_URL } = import.meta.env;
|
|
30
|
+
function withBase(file) {
|
|
31
|
+
return `${BASE_URL.replace(/\/$/, "")}/${file.replace(/^\//, "")}`;
|
|
32
|
+
}
|
|
29
33
|
function getAssets(route) {
|
|
30
34
|
if (!isProd) return {
|
|
31
35
|
cssLinks: "",
|
|
32
36
|
jsPreloads: "",
|
|
33
|
-
entryClient: "
|
|
37
|
+
entryClient: withBase("@id/virtual:entry-client")
|
|
34
38
|
};
|
|
35
39
|
const cssFiles = /* @__PURE__ */ new Set();
|
|
36
40
|
const jsFiles = /* @__PURE__ */ new Set();
|
|
@@ -55,9 +59,9 @@ function getAssets(route) {
|
|
|
55
59
|
if (head) collectAssets(head);
|
|
56
60
|
if (layout) collectAssets(layout);
|
|
57
61
|
return {
|
|
58
|
-
cssLinks: [...cssFiles].map((href) => `<link rel="stylesheet" href="
|
|
59
|
-
jsPreloads: [...jsFiles].map((href) => `<link rel="modulepreload" href="
|
|
60
|
-
entryClient:
|
|
62
|
+
cssLinks: [...cssFiles].map((href) => `<link rel="stylesheet" href="${withBase(href)}">`).join(""),
|
|
63
|
+
jsPreloads: [...jsFiles].map((href) => `<link rel="modulepreload" href="${withBase(href)}">`).join(""),
|
|
64
|
+
entryClient: withBase(manifest[virtualEntryClientKey].file)
|
|
61
65
|
};
|
|
62
66
|
}
|
|
63
67
|
async function buildPageContext(urlPathname, urlOriginal, isJsonRequest) {
|
|
@@ -70,8 +74,8 @@ async function buildPageContext(urlPathname, urlOriginal, isJsonRequest) {
|
|
|
70
74
|
urlPathname
|
|
71
75
|
};
|
|
72
76
|
const [dataMod, titleMod, PageModule, HeadModule, LayoutModule] = await Promise.all([
|
|
73
|
-
route.
|
|
74
|
-
route.
|
|
77
|
+
route.Data?.() ?? null,
|
|
78
|
+
route.Title?.() ?? null,
|
|
75
79
|
isJsonRequest ? null : route.Page(),
|
|
76
80
|
isJsonRequest ? null : route.Head?.() ?? null,
|
|
77
81
|
isJsonRequest ? null : route.Layout?.() ?? null
|
|
@@ -133,7 +137,12 @@ async function renderErrorPage(req, status, urlPathname, error) {
|
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
139
|
async function renderPage(req) {
|
|
136
|
-
|
|
140
|
+
let pathname = new URL(req.url).pathname;
|
|
141
|
+
if (BASE_URL !== "/") {
|
|
142
|
+
const baseSlashed = BASE_URL.endsWith("/") ? BASE_URL : BASE_URL + "/";
|
|
143
|
+
const baseNoSlash = baseSlashed.slice(0, -1);
|
|
144
|
+
pathname = pathname === baseNoSlash ? "/" : pathname.slice(baseSlashed.length - 1);
|
|
145
|
+
}
|
|
137
146
|
const isJsonRequest = pathname.endsWith(".pageContext.json");
|
|
138
147
|
let targetPathname = pathname;
|
|
139
148
|
if (isJsonRequest) {
|
package/dist/vite.d.mts
CHANGED
|
@@ -6,9 +6,24 @@ declare function routerPlugin({
|
|
|
6
6
|
serverEntry,
|
|
7
7
|
apiPrefix
|
|
8
8
|
}?: {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The directory where your page components are located.
|
|
11
|
+
* This is where the plugin will look for your page files to generate routes.
|
|
12
|
+
* @default 'pages'
|
|
13
|
+
*/
|
|
14
|
+
pagesDir?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The entry point for your server application code.
|
|
17
|
+
* This is where you can define custom server logic, such as API routes or middleware.
|
|
18
|
+
* The build will produce dist/server/index.mjs, which is the entry point for your server application.
|
|
19
|
+
* @default 'server/index'
|
|
20
|
+
*/
|
|
21
|
+
serverEntry?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The prefix for your API routes.
|
|
24
|
+
* @default '/api'
|
|
25
|
+
*/
|
|
26
|
+
apiPrefix?: string;
|
|
12
27
|
}): Plugin;
|
|
13
28
|
//#endregion
|
|
14
29
|
export { routerPlugin as default };
|
package/dist/vite.mjs
CHANGED
|
@@ -4,6 +4,11 @@ import { Readable } from "node:stream";
|
|
|
4
4
|
import { pipeline } from "node:stream/promises";
|
|
5
5
|
import { loadEnv } from "vite";
|
|
6
6
|
//#region src/utils/generateRoutes.ts
|
|
7
|
+
const pageExtensions = [".ts", ".js"];
|
|
8
|
+
const pageExtensionsX = [".tsx", ".jsx"];
|
|
9
|
+
function findFile(files, basename, extensions) {
|
|
10
|
+
return files.find((file) => extensions.some((ext) => file === `${basename}${ext}`));
|
|
11
|
+
}
|
|
7
12
|
function generateRoutes(viteRoot, pagesDir) {
|
|
8
13
|
const pagesAbsPath = path.resolve(viteRoot, pagesDir);
|
|
9
14
|
if (!fs.existsSync(pagesAbsPath)) return { routes: [] };
|
|
@@ -12,15 +17,20 @@ function generateRoutes(viteRoot, pagesDir) {
|
|
|
12
17
|
function walk(dir, routePath, parentLayout, parentHead) {
|
|
13
18
|
const files = fs.readdirSync(dir);
|
|
14
19
|
const importPath = path.relative(viteRoot, dir).replaceAll("\\", "/");
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
20
|
+
const layoutFile = findFile(files, "+Layout", pageExtensionsX);
|
|
21
|
+
const currentLayout = layoutFile ? `${importPath}/${layoutFile}` : parentLayout;
|
|
22
|
+
const headFile = findFile(files, "+Head", pageExtensionsX);
|
|
23
|
+
const currentHead = headFile ? `${importPath}/${headFile}` : parentHead;
|
|
24
|
+
const pageFile = findFile(files, "+Page", pageExtensionsX);
|
|
25
|
+
if (pageFile) {
|
|
18
26
|
const route = {
|
|
19
27
|
path: routePath || "/",
|
|
20
|
-
page: `${importPath}
|
|
21
|
-
hasData: files.includes("+data.ts"),
|
|
22
|
-
hasTitle: files.includes("+title.ts")
|
|
28
|
+
page: `${importPath}/${pageFile}`
|
|
23
29
|
};
|
|
30
|
+
const dataFile = findFile(files, "+data", pageExtensions);
|
|
31
|
+
if (dataFile) route.data = `${importPath}/${dataFile}`;
|
|
32
|
+
const titleFile = findFile(files, "+title", pageExtensions);
|
|
33
|
+
if (titleFile) route.title = `${importPath}/${titleFile}`;
|
|
24
34
|
if (currentLayout) route.layout = currentLayout;
|
|
25
35
|
if (currentHead) route.head = currentHead;
|
|
26
36
|
routes.push(route);
|
|
@@ -29,9 +39,10 @@ function generateRoutes(viteRoot, pagesDir) {
|
|
|
29
39
|
const fullPath = path.join(dir, file);
|
|
30
40
|
if (!fs.statSync(fullPath).isDirectory()) continue;
|
|
31
41
|
if (file === "_error") {
|
|
32
|
-
|
|
42
|
+
const errorPageFile = findFile(fs.readdirSync(fullPath), "+Page", pageExtensionsX);
|
|
43
|
+
if (errorPageFile) errorRoute = {
|
|
33
44
|
path: "_error",
|
|
34
|
-
page: `${importPath}/_error
|
|
45
|
+
page: `${importPath}/_error/${errorPageFile}`,
|
|
35
46
|
layout: currentLayout,
|
|
36
47
|
head: currentHead
|
|
37
48
|
};
|
|
@@ -172,10 +183,11 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
|
|
|
172
183
|
code += `{path:'${r.path}',page:'${r.page}',Page:()=>import('/${r.page}'),`;
|
|
173
184
|
if (r.head) code += `head:'${r.head}',Head:()=>import('/${r.head}'),`;
|
|
174
185
|
if (r.layout) code += `layout:'${r.layout}',Layout:()=>import('/${r.layout}'),`;
|
|
175
|
-
code += `
|
|
186
|
+
if (r.data) code += `data:'${r.data}',`;
|
|
187
|
+
if (r.title) code += `title:'${r.title}',`;
|
|
176
188
|
if (isSSR) {
|
|
177
|
-
if (r.
|
|
178
|
-
if (r.
|
|
189
|
+
if (r.data) code += `Data:()=>import('/${r.data}'),`;
|
|
190
|
+
if (r.title) code += `Title:()=>import('/${r.title}'),`;
|
|
179
191
|
}
|
|
180
192
|
code += "},";
|
|
181
193
|
}
|
|
@@ -198,26 +210,23 @@ function routerPlugin({ pagesDir = "pages", serverEntry = "server/index", apiPre
|
|
|
198
210
|
import { onRenderClient } from '${virtualRendererId}';
|
|
199
211
|
const { default: render } = await onRenderClient();
|
|
200
212
|
await render({ routes, errorRoute });`;
|
|
201
|
-
if (id === resolvedVirtualSetupId) return `
|
|
202
|
-
import { routes, errorRoute, config } from '${virtualModuleId}';
|
|
213
|
+
if (id === resolvedVirtualSetupId) return `import { routes, errorRoute, config } from '${virtualModuleId}';
|
|
203
214
|
import { setVikeState } from 'vike-lite/__internal/server';
|
|
204
215
|
let manifest;
|
|
205
216
|
if (process.env.NODE_ENV === 'production') {
|
|
206
217
|
manifest = (await import('${virtualManifestId}')).default;
|
|
207
218
|
}
|
|
208
|
-
setVikeState({ routes, errorRoute, config, manifest })
|
|
209
|
-
`;
|
|
219
|
+
setVikeState({ routes, errorRoute, config, manifest });`;
|
|
210
220
|
if (id === resolvedVirtualEntryServerId) {
|
|
211
|
-
const extensions = [
|
|
212
|
-
".ts",
|
|
213
|
-
".js",
|
|
214
|
-
".mjs"
|
|
215
|
-
];
|
|
216
221
|
let hasCustomServer = false;
|
|
217
222
|
let customServerPath = "";
|
|
218
223
|
if (serverEntry) {
|
|
219
224
|
const basePath = path.resolve(viteConfigRoot, serverEntry);
|
|
220
|
-
for (const ext of [
|
|
225
|
+
for (const ext of [
|
|
226
|
+
".ts",
|
|
227
|
+
".js",
|
|
228
|
+
".mjs"
|
|
229
|
+
]) if (fs.existsSync(basePath + ext)) {
|
|
221
230
|
hasCustomServer = true;
|
|
222
231
|
customServerPath = (basePath + ext).replaceAll("\\", "/");
|
|
223
232
|
break;
|
|
@@ -243,11 +252,11 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
243
252
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
244
253
|
const clientDir = path.resolve(__dirname, '../client');
|
|
245
254
|
const MIME_TYPES = {
|
|
246
|
-
'.html': 'text/html',
|
|
247
|
-
'.js': 'text/javascript',
|
|
248
|
-
'.mjs': 'text/javascript',
|
|
249
|
-
'.css': 'text/css',
|
|
250
|
-
'.json': 'application/json',
|
|
255
|
+
'.html': 'text/html; charset=utf-8',
|
|
256
|
+
'.js': 'text/javascript; charset=utf-8',
|
|
257
|
+
'.mjs': 'text/javascript; charset=utf-8',
|
|
258
|
+
'.css': 'text/css; charset=utf-8',
|
|
259
|
+
'.json': 'application/json; charset=utf-8',
|
|
251
260
|
'.png': 'image/png',
|
|
252
261
|
'.jpg': 'image/jpeg',
|
|
253
262
|
'.jpeg': 'image/jpeg',
|
|
@@ -256,23 +265,30 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
256
265
|
'.ico': 'image/x-icon',
|
|
257
266
|
'.webmanifest': 'application/manifest+json',
|
|
258
267
|
'.xml': 'application/xml',
|
|
259
|
-
'.txt': 'text/plain',
|
|
268
|
+
'.txt': 'text/plain; charset=utf-8',
|
|
260
269
|
'.woff': 'font/woff',
|
|
261
|
-
'.woff2': 'font/woff2'
|
|
270
|
+
'.woff2': 'font/woff2',
|
|
271
|
+
'.wasm': 'application/wasm'
|
|
262
272
|
};
|
|
273
|
+
const base = import.meta.env.BASE_URL;
|
|
263
274
|
const server = createServer(async (req, res) => {
|
|
264
275
|
try {
|
|
265
276
|
const urlObj = new URL(req.url || '/', 'http://' + (req.headers.host || 'localhost'));
|
|
266
277
|
const pathname = urlObj.pathname;
|
|
267
|
-
|
|
268
|
-
|
|
278
|
+
let fileUrl = pathname;
|
|
279
|
+
if (base !== '/' && pathname.startsWith(base)) fileUrl = '/' + pathname.slice(base.length);
|
|
280
|
+
if (fileUrl !== '/') {
|
|
281
|
+
const filePath = path.resolve(clientDir, '.' + fileUrl)
|
|
282
|
+
if (!filePath.startsWith(clientDir + path.sep)) {
|
|
283
|
+
res.statusCode = 403
|
|
284
|
+
res.end('Forbidden')
|
|
285
|
+
return
|
|
286
|
+
}
|
|
269
287
|
if (filePath.startsWith(clientDir) && fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
|
|
270
288
|
const ext = path.extname(filePath).toLowerCase();
|
|
271
289
|
const mimeType = MIME_TYPES[ext] || 'application/octet-stream';
|
|
272
290
|
res.setHeader('Content-Type', mimeType);
|
|
273
|
-
|
|
274
|
-
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
|
275
|
-
}
|
|
291
|
+
res.setHeader('Cache-Control', fileUrl.startsWith('/assets/') ? 'public, max-age=31536000, immutable' : 'public, max-age=0, must-revalidate')
|
|
276
292
|
fs.createReadStream(filePath).pipe(res);
|
|
277
293
|
return;
|
|
278
294
|
}
|
|
@@ -284,6 +300,10 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
284
300
|
}
|
|
285
301
|
const { method } = req;
|
|
286
302
|
const init = { method, headers };
|
|
303
|
+
if (req.method === 'HEAD') {
|
|
304
|
+
res.end()
|
|
305
|
+
return
|
|
306
|
+
}
|
|
287
307
|
if (method !== 'GET' && method !== 'HEAD') {
|
|
288
308
|
init.body = Readable.toWeb(req);
|
|
289
309
|
init.duplex = 'half';
|
|
@@ -294,11 +314,8 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
294
314
|
for (const [key, val] of response.headers) {
|
|
295
315
|
res.setHeader(key, val);
|
|
296
316
|
}
|
|
297
|
-
if (response.body)
|
|
298
|
-
|
|
299
|
-
} else {
|
|
300
|
-
res.end();
|
|
301
|
-
}
|
|
317
|
+
if (response.body) await pipeline(Readable.fromWeb(response.body), res);
|
|
318
|
+
else res.end();
|
|
302
319
|
} catch (e) {
|
|
303
320
|
console.error(e);
|
|
304
321
|
res.statusCode = 500;
|
|
@@ -315,6 +332,15 @@ if (process.env.NODE_ENV === 'production') {
|
|
|
315
332
|
},
|
|
316
333
|
configureServer(server) {
|
|
317
334
|
return () => {
|
|
335
|
+
const pagesPath = path.resolve(viteConfigRoot, pagesDir);
|
|
336
|
+
server.watcher.on("all", (event, file) => {
|
|
337
|
+
if (!((event === "add" || event === "unlink") && file.startsWith(pagesPath))) return;
|
|
338
|
+
for (const env of Object.values(server.environments)) {
|
|
339
|
+
const mod = env.moduleGraph.getModuleById(resolvedVirtualModuleId);
|
|
340
|
+
if (mod) env.moduleGraph.invalidateModule(mod);
|
|
341
|
+
}
|
|
342
|
+
server.ws.send({ type: "full-reload" });
|
|
343
|
+
});
|
|
318
344
|
server.middlewares.use(async (req, res, next) => {
|
|
319
345
|
try {
|
|
320
346
|
const { default: app } = await server.environments.ssr.runner.import(resolvedVirtualEntryServerId);
|
package/package.json
CHANGED
package/LICENSE
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024-present node-ecosystem
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
-
|
|
7
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
-
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|