Add slide renderer source for one-click deployment
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +3 -0
- services/slides/Dockerfile +10 -0
- services/slides/dist/charts.js +7 -0
- services/slides/dist/layouts.js +1 -0
- services/slides/dist/render.js +55 -0
- services/slides/dist/server.js +28 -0
- services/slides/dist/themes.js +15 -0
- services/slides/node_modules/.bin/esbuild +3 -0
- services/slides/node_modules/.bin/image-size +53 -0
- services/slides/node_modules/.bin/pino +6 -0
- services/slides/node_modules/.bin/safe-regex2 +58 -0
- services/slides/node_modules/.bin/semver +195 -0
- services/slides/node_modules/.bin/tsc +2 -0
- services/slides/node_modules/.bin/tsserver +2 -0
- services/slides/node_modules/.bin/tsx +0 -0
- services/slides/node_modules/.package-lock.json +959 -0
- services/slides/node_modules/@esbuild/darwin-arm64/README.md +3 -0
- services/slides/node_modules/@esbuild/darwin-arm64/bin/esbuild +3 -0
- services/slides/node_modules/@esbuild/darwin-arm64/package.json +20 -0
- services/slides/node_modules/@fastify/ajv-compiler/.gitattributes +2 -0
- services/slides/node_modules/@fastify/ajv-compiler/.github/.stale.yml +21 -0
- services/slides/node_modules/@fastify/ajv-compiler/.github/dependabot.yml +13 -0
- services/slides/node_modules/@fastify/ajv-compiler/.github/tests_checker.yml +8 -0
- services/slides/node_modules/@fastify/ajv-compiler/.github/workflows/ci.yml +33 -0
- services/slides/node_modules/@fastify/ajv-compiler/LICENSE +23 -0
- services/slides/node_modules/@fastify/ajv-compiler/README.md +237 -0
- services/slides/node_modules/@fastify/ajv-compiler/benchmark/small-object.mjs +37 -0
- services/slides/node_modules/@fastify/ajv-compiler/eslint.config.js +6 -0
- services/slides/node_modules/@fastify/ajv-compiler/index.js +53 -0
- services/slides/node_modules/@fastify/ajv-compiler/lib/default-ajv-options.js +14 -0
- services/slides/node_modules/@fastify/ajv-compiler/lib/serializer-compiler.js +27 -0
- services/slides/node_modules/@fastify/ajv-compiler/lib/validator-compiler.js +58 -0
- services/slides/node_modules/@fastify/ajv-compiler/package.json +84 -0
- services/slides/node_modules/@fastify/ajv-compiler/standalone.js +44 -0
- services/slides/node_modules/@fastify/ajv-compiler/test/.gitkeep +0 -0
- services/slides/node_modules/@fastify/ajv-compiler/test/duplicated-id-compile.test.js +55 -0
- services/slides/node_modules/@fastify/ajv-compiler/test/index.test.js +307 -0
- services/slides/node_modules/@fastify/ajv-compiler/test/plugins.test.js +246 -0
- services/slides/node_modules/@fastify/ajv-compiler/test/serialization.test.js +279 -0
- services/slides/node_modules/@fastify/ajv-compiler/test/standalone.test.js +203 -0
- services/slides/node_modules/@fastify/ajv-compiler/types/index.d.ts +87 -0
- services/slides/node_modules/@fastify/ajv-compiler/types/index.test-d.ts +302 -0
- services/slides/node_modules/@fastify/busboy/LICENSE +24 -0
- services/slides/node_modules/@fastify/busboy/README.md +270 -0
- services/slides/node_modules/@fastify/busboy/deps/dicer/LICENSE +19 -0
- services/slides/node_modules/@fastify/busboy/deps/dicer/lib/Dicer.js +213 -0
- services/slides/node_modules/@fastify/busboy/deps/dicer/lib/HeaderParser.js +100 -0
- services/slides/node_modules/@fastify/busboy/deps/dicer/lib/PartStream.js +13 -0
- services/slides/node_modules/@fastify/busboy/deps/dicer/lib/dicer.d.ts +164 -0
- services/slides/node_modules/@fastify/busboy/deps/streamsearch/sbmh.js +230 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
services/slides/node_modules/.bin/esbuild filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
services/slides/node_modules/@esbuild/darwin-arm64/bin/esbuild filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
services/slides/node_modules/esbuild/bin/esbuild filter=lfs diff=lfs merge=lfs -text
|
services/slides/Dockerfile
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM node:22-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
COPY package.json tsconfig.json ./
|
| 5 |
+
RUN npm install
|
| 6 |
+
COPY src ./src
|
| 7 |
+
RUN npm run build
|
| 8 |
+
|
| 9 |
+
EXPOSE 8787
|
| 10 |
+
CMD ["npm", "start"]
|
services/slides/dist/charts.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export function chartTable(chart) {
|
| 2 |
+
const series = chart.series[0];
|
| 3 |
+
return {
|
| 4 |
+
labels: series?.points.map((point) => point[0]) ?? [],
|
| 5 |
+
values: series?.points.map((point) => point[1]) ?? []
|
| 6 |
+
};
|
| 7 |
+
}
|
services/slides/dist/layouts.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
export const layouts = ["title", "section", "bullets", "chart_and_insight", "image_reference"];
|
services/slides/dist/render.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as PptxModule from "pptxgenjs";
|
| 2 |
+
import { cleanHex, normalizeTheme } from "./themes.js";
|
| 3 |
+
export async function renderPresentation(spec) {
|
| 4 |
+
const PptxGenJS = (PptxModule.default ?? PptxModule);
|
| 5 |
+
const pptx = new PptxGenJS();
|
| 6 |
+
pptx.layout = "LAYOUT_WIDE";
|
| 7 |
+
pptx.author = "GLM Visual Variable Runtime";
|
| 8 |
+
pptx.subject = "Generated from visual evidence";
|
| 9 |
+
pptx.title = spec.title;
|
| 10 |
+
const theme = normalizeTheme(spec.theme);
|
| 11 |
+
pptx.defineSlideMaster({
|
| 12 |
+
title: "VVR_MASTER",
|
| 13 |
+
background: { color: cleanHex(theme.background) },
|
| 14 |
+
objects: [
|
| 15 |
+
{ rect: { x: 0, y: 0, w: 13.333, h: 0.12, fill: { color: cleanHex(theme.accent) }, line: { color: cleanHex(theme.accent) } } }
|
| 16 |
+
],
|
| 17 |
+
slideNumber: { x: 12.3, y: 7.15, color: cleanHex(theme.secondary) }
|
| 18 |
+
});
|
| 19 |
+
const slides = spec.slides.length ? spec.slides : [{ layout: "title", title: spec.title }];
|
| 20 |
+
for (const item of slides) {
|
| 21 |
+
const slide = pptx.addSlide("VVR_MASTER");
|
| 22 |
+
slide.addText(item.title, {
|
| 23 |
+
x: 0.7,
|
| 24 |
+
y: 0.65,
|
| 25 |
+
w: 11.9,
|
| 26 |
+
h: 0.6,
|
| 27 |
+
fontFace: "Aptos Display",
|
| 28 |
+
fontSize: item.layout === "title" ? 34 : 26,
|
| 29 |
+
bold: true,
|
| 30 |
+
color: cleanHex(theme.primary),
|
| 31 |
+
margin: 0
|
| 32 |
+
});
|
| 33 |
+
if (item.subtitle) {
|
| 34 |
+
slide.addText(item.subtitle, { x: 0.75, y: 1.35, w: 11.7, h: 0.4, fontSize: 16, color: cleanHex(theme.secondary) });
|
| 35 |
+
}
|
| 36 |
+
const bullets = [...(item.bullets ?? []), ...(item.insights ?? [])];
|
| 37 |
+
if (bullets.length) {
|
| 38 |
+
slide.addText(bullets.map((text) => ({ text, options: { bullet: { indent: 14 }, hanging: 4 } })), {
|
| 39 |
+
x: 0.9,
|
| 40 |
+
y: 2.0,
|
| 41 |
+
w: 11.4,
|
| 42 |
+
h: 4.6,
|
| 43 |
+
fontSize: 18,
|
| 44 |
+
color: cleanHex(theme.text_dark),
|
| 45 |
+
breakLine: false,
|
| 46 |
+
fit: "shrink"
|
| 47 |
+
});
|
| 48 |
+
}
|
| 49 |
+
if (item.notes || spec.provenance?.length) {
|
| 50 |
+
slide.addNotes(`Provenance: ${JSON.stringify(spec.provenance ?? [])}\n${item.notes ?? ""}`);
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
const data = await pptx.write({ outputType: "nodebuffer" });
|
| 54 |
+
return Buffer.from(data);
|
| 55 |
+
}
|
services/slides/dist/server.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import Fastify from "fastify";
|
| 2 |
+
import { z } from "zod";
|
| 3 |
+
import { renderPresentation } from "./render.js";
|
| 4 |
+
const app = Fastify({ logger: true });
|
| 5 |
+
const Slide = z.object({
|
| 6 |
+
layout: z.enum(["title", "section", "bullets", "chart_and_insight", "image_reference"]).default("bullets"),
|
| 7 |
+
title: z.string(),
|
| 8 |
+
subtitle: z.string().optional(),
|
| 9 |
+
bullets: z.array(z.string()).default([]),
|
| 10 |
+
insights: z.array(z.string()).default([]),
|
| 11 |
+
notes: z.string().optional()
|
| 12 |
+
});
|
| 13 |
+
const Presentation = z.object({
|
| 14 |
+
title: z.string(),
|
| 15 |
+
theme: z.record(z.unknown()).default({}),
|
| 16 |
+
slides: z.array(Slide).default([]),
|
| 17 |
+
provenance: z.array(z.record(z.unknown())).default([])
|
| 18 |
+
});
|
| 19 |
+
app.get("/health", async () => ({ status: "ok" }));
|
| 20 |
+
app.post("/render", async (request, reply) => {
|
| 21 |
+
const spec = Presentation.parse(request.body);
|
| 22 |
+
const pptx = await renderPresentation(spec);
|
| 23 |
+
reply.header("content-type", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
|
| 24 |
+
reply.header("content-disposition", "attachment; filename=\"visual-runtime-deck.pptx\"");
|
| 25 |
+
return reply.send(pptx);
|
| 26 |
+
});
|
| 27 |
+
const port = Number(process.env.PORT ?? 8787);
|
| 28 |
+
await app.listen({ host: "0.0.0.0", port });
|
services/slides/dist/themes.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export function normalizeTheme(theme) {
|
| 2 |
+
return {
|
| 3 |
+
background: theme.background ?? "F5F1E8",
|
| 4 |
+
surface: theme.surface ?? "FFFFFF",
|
| 5 |
+
primary: theme.primary ?? "16324F",
|
| 6 |
+
secondary: theme.secondary ?? "587B7F",
|
| 7 |
+
accent: theme.accent ?? "E07A5F",
|
| 8 |
+
text_dark: theme.text_dark ?? "182026",
|
| 9 |
+
text_light: theme.text_light ?? "FFFFFF",
|
| 10 |
+
data_series: theme.data_series ?? ["16324F", "E07A5F", "81B29A", "F2CC8F"]
|
| 11 |
+
};
|
| 12 |
+
}
|
| 13 |
+
export function cleanHex(value) {
|
| 14 |
+
return value.replace("#", "").toUpperCase();
|
| 15 |
+
}
|
services/slides/node_modules/.bin/esbuild
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e2dc9a52440a2a34f09434a2f4843cb1e30f84e40dcf238976ec61ef8cd7f36a
|
| 3 |
+
size 10573778
|
services/slides/node_modules/.bin/image-size
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
| 3 |
+
'use strict'
|
| 4 |
+
|
| 5 |
+
const fs = require('fs')
|
| 6 |
+
const path = require('path')
|
| 7 |
+
const { imageSize } = require('..')
|
| 8 |
+
|
| 9 |
+
const files = process.argv.slice(2)
|
| 10 |
+
|
| 11 |
+
if (!files.length) {
|
| 12 |
+
console.error('Usage: image-size image1 [image2] [image3] ...')
|
| 13 |
+
process.exit(-1)
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
const red = ['\x1B[31m', '\x1B[39m']
|
| 17 |
+
// const bold = ['\x1B[1m', '\x1B[22m']
|
| 18 |
+
const grey = ['\x1B[90m', '\x1B[39m']
|
| 19 |
+
const green = ['\x1B[32m', '\x1B[39m']
|
| 20 |
+
|
| 21 |
+
function colorize(text, color) {
|
| 22 |
+
return color[0] + text + color[1]
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
files.forEach(function (image) {
|
| 26 |
+
try {
|
| 27 |
+
if (fs.existsSync(path.resolve(image))) {
|
| 28 |
+
const greyX = colorize('x', grey)
|
| 29 |
+
const greyImage = colorize(image, grey)
|
| 30 |
+
const size = imageSize(image)
|
| 31 |
+
const sizes = size.images || [size]
|
| 32 |
+
sizes.forEach((size) => {
|
| 33 |
+
let greyType = ''
|
| 34 |
+
if (size.type) {
|
| 35 |
+
greyType = colorize(' (' + size.type + ')', grey)
|
| 36 |
+
}
|
| 37 |
+
console.info(
|
| 38 |
+
colorize(size.width, green) +
|
| 39 |
+
greyX +
|
| 40 |
+
colorize(size.height, green) +
|
| 41 |
+
' - ' +
|
| 42 |
+
greyImage +
|
| 43 |
+
greyType,
|
| 44 |
+
)
|
| 45 |
+
})
|
| 46 |
+
} else {
|
| 47 |
+
console.error("file doesn't exist - ", image)
|
| 48 |
+
}
|
| 49 |
+
} catch (e) {
|
| 50 |
+
// console.error(e.stack)
|
| 51 |
+
console.error(colorize(e.message, red), '-', image)
|
| 52 |
+
}
|
| 53 |
+
})
|
services/slides/node_modules/.bin/pino
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
console.error(
|
| 3 |
+
'`pino` cli has been removed. Use `pino-pretty` cli instead.\n' +
|
| 4 |
+
'\nSee: https://github.com/pinojs/pino-pretty'
|
| 5 |
+
)
|
| 6 |
+
process.exit(1)
|
services/slides/node_modules/.bin/safe-regex2
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
'use strict'
|
| 3 |
+
|
| 4 |
+
const { parseArgs } = require('node:util')
|
| 5 |
+
const { safeRegex } = require('../index.js')
|
| 6 |
+
|
| 7 |
+
const { version } = require('../package.json')
|
| 8 |
+
|
| 9 |
+
const { values: options, positionals } = parseArgs({
|
| 10 |
+
allowPositionals: true,
|
| 11 |
+
options: {
|
| 12 |
+
version: {
|
| 13 |
+
type: 'boolean',
|
| 14 |
+
short: 'v',
|
| 15 |
+
default: false,
|
| 16 |
+
},
|
| 17 |
+
help: {
|
| 18 |
+
type: 'boolean',
|
| 19 |
+
short: 'h',
|
| 20 |
+
default: false,
|
| 21 |
+
}
|
| 22 |
+
},
|
| 23 |
+
})
|
| 24 |
+
|
| 25 |
+
function help () {
|
| 26 |
+
console.log(`Usage: safe-regex2 [options] <regex>
|
| 27 |
+
|
| 28 |
+
Check if a regular expression is safe to use in a production environment.
|
| 29 |
+
|
| 30 |
+
Options:
|
| 31 |
+
-v, --version Display the version number
|
| 32 |
+
-h, --help Display this help message
|
| 33 |
+
<regex> The regular expression to check`
|
| 34 |
+
)
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
if (options.help) {
|
| 38 |
+
help()
|
| 39 |
+
} else if (options.version) {
|
| 40 |
+
console.log(version)
|
| 41 |
+
} else {
|
| 42 |
+
if (positionals.length === 0) {
|
| 43 |
+
help()
|
| 44 |
+
} else if (positionals.length > 1) {
|
| 45 |
+
console.error('Error: Too many positional arguments.')
|
| 46 |
+
help()
|
| 47 |
+
} else {
|
| 48 |
+
const regex = positionals[0]
|
| 49 |
+
const isSafe = safeRegex(regex)
|
| 50 |
+
if (isSafe === false) {
|
| 51 |
+
console.error('Provided regex is invalid or unsafe.')
|
| 52 |
+
process.exit(1)
|
| 53 |
+
} else {
|
| 54 |
+
console.log('Provided regex is safe.')
|
| 55 |
+
process.exit(0)
|
| 56 |
+
}
|
| 57 |
+
}
|
| 58 |
+
}
|
services/slides/node_modules/.bin/semver
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
// Standalone semver comparison program.
|
| 3 |
+
// Exits successfully and prints matching version(s) if
|
| 4 |
+
// any supplied version is valid and passes all tests.
|
| 5 |
+
|
| 6 |
+
'use strict'
|
| 7 |
+
|
| 8 |
+
const argv = process.argv.slice(2)
|
| 9 |
+
|
| 10 |
+
let versions = []
|
| 11 |
+
|
| 12 |
+
const range = []
|
| 13 |
+
|
| 14 |
+
let inc = null
|
| 15 |
+
|
| 16 |
+
const version = require('../package.json').version
|
| 17 |
+
|
| 18 |
+
let loose = false
|
| 19 |
+
|
| 20 |
+
let includePrerelease = false
|
| 21 |
+
|
| 22 |
+
let coerce = false
|
| 23 |
+
|
| 24 |
+
let rtl = false
|
| 25 |
+
|
| 26 |
+
let identifier
|
| 27 |
+
|
| 28 |
+
let identifierBase
|
| 29 |
+
|
| 30 |
+
const semver = require('../')
|
| 31 |
+
const parseOptions = require('../internal/parse-options')
|
| 32 |
+
|
| 33 |
+
let reverse = false
|
| 34 |
+
|
| 35 |
+
let options = {}
|
| 36 |
+
|
| 37 |
+
const main = () => {
|
| 38 |
+
if (!argv.length) {
|
| 39 |
+
return help()
|
| 40 |
+
}
|
| 41 |
+
while (argv.length) {
|
| 42 |
+
let a = argv.shift()
|
| 43 |
+
const indexOfEqualSign = a.indexOf('=')
|
| 44 |
+
if (indexOfEqualSign !== -1) {
|
| 45 |
+
const value = a.slice(indexOfEqualSign + 1)
|
| 46 |
+
a = a.slice(0, indexOfEqualSign)
|
| 47 |
+
argv.unshift(value)
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
switch (a) {
|
| 51 |
+
case '-rv': case '-rev': case '--rev': case '--reverse':
|
| 52 |
+
reverse = true
|
| 53 |
+
break
|
| 54 |
+
case '-l': case '--loose':
|
| 55 |
+
loose = true
|
| 56 |
+
break
|
| 57 |
+
case '-p': case '--include-prerelease':
|
| 58 |
+
includePrerelease = true
|
| 59 |
+
break
|
| 60 |
+
case '-v': case '--version':
|
| 61 |
+
versions.push(argv.shift())
|
| 62 |
+
break
|
| 63 |
+
case '-i': case '--inc': case '--increment':
|
| 64 |
+
if (semver.RELEASE_TYPES.includes(argv[0]) || (argv[0] === 'release')) {
|
| 65 |
+
inc = { value: argv.shift(), maybeErrantValue: null, option: a }
|
| 66 |
+
} else {
|
| 67 |
+
inc = { value: 'patch', maybeErrantValue: argv[0], option: a }
|
| 68 |
+
}
|
| 69 |
+
break
|
| 70 |
+
case '--preid':
|
| 71 |
+
identifier = argv.shift()
|
| 72 |
+
break
|
| 73 |
+
case '-r': case '--range':
|
| 74 |
+
range.push(argv.shift())
|
| 75 |
+
break
|
| 76 |
+
case '-n':
|
| 77 |
+
identifierBase = argv.shift()
|
| 78 |
+
if (identifierBase === 'false') {
|
| 79 |
+
identifierBase = false
|
| 80 |
+
}
|
| 81 |
+
break
|
| 82 |
+
case '-c': case '--coerce':
|
| 83 |
+
coerce = true
|
| 84 |
+
break
|
| 85 |
+
case '--rtl':
|
| 86 |
+
rtl = true
|
| 87 |
+
break
|
| 88 |
+
case '--ltr':
|
| 89 |
+
rtl = false
|
| 90 |
+
break
|
| 91 |
+
case '-h': case '--help': case '-?':
|
| 92 |
+
return help()
|
| 93 |
+
default:
|
| 94 |
+
versions.push(a)
|
| 95 |
+
break
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
options = parseOptions({ loose, includePrerelease, rtl })
|
| 100 |
+
|
| 101 |
+
if (
|
| 102 |
+
inc &&
|
| 103 |
+
versions.includes(inc.maybeErrantValue) &&
|
| 104 |
+
!semver.valid(inc.maybeErrantValue, options)
|
| 105 |
+
) {
|
| 106 |
+
console.warn(`Invalid value for ${inc.option}; defaulting to 'patch'. This may become a failure in future major versions.`)
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
versions = versions.map((v) => {
|
| 110 |
+
return coerce ? (semver.coerce(v, options) || { version: v }).version : v
|
| 111 |
+
}).filter((v) => {
|
| 112 |
+
return semver.valid(v, options)
|
| 113 |
+
})
|
| 114 |
+
if (!versions.length) {
|
| 115 |
+
return fail()
|
| 116 |
+
}
|
| 117 |
+
if (inc && (versions.length !== 1 || range.length)) {
|
| 118 |
+
return failInc()
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
for (let i = 0, l = range.length; i < l; i++) {
|
| 122 |
+
versions = versions.filter((v) => {
|
| 123 |
+
return semver.satisfies(v, range[i], options)
|
| 124 |
+
})
|
| 125 |
+
if (!versions.length) {
|
| 126 |
+
return fail()
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
versions
|
| 130 |
+
.sort((a, b) => semver[reverse ? 'rcompare' : 'compare'](a, b, options))
|
| 131 |
+
.map(v => semver.clean(v, options))
|
| 132 |
+
.map(v => inc ? semver.inc(v, inc.value, options, identifier, identifierBase) : v)
|
| 133 |
+
.forEach(v => console.log(v))
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
const failInc = () => {
|
| 137 |
+
console.error('--inc can only be used on a single version with no range')
|
| 138 |
+
fail()
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
const fail = () => process.exit(1)
|
| 142 |
+
|
| 143 |
+
const help = () => console.log(
|
| 144 |
+
`SemVer ${version}
|
| 145 |
+
|
| 146 |
+
A JavaScript implementation of the https://semver.org/ specification
|
| 147 |
+
Copyright Isaac Z. Schlueter
|
| 148 |
+
|
| 149 |
+
Usage: semver [options] <version> [<version> [...]]
|
| 150 |
+
Prints valid versions sorted by SemVer precedence
|
| 151 |
+
|
| 152 |
+
Options:
|
| 153 |
+
-r --range <range>
|
| 154 |
+
Print versions that match the specified range.
|
| 155 |
+
|
| 156 |
+
-i --increment [<level>]
|
| 157 |
+
Increment a version by the specified level. Level can
|
| 158 |
+
be one of: major, minor, patch, premajor, preminor,
|
| 159 |
+
prepatch, prerelease, or release. Default level is 'patch'.
|
| 160 |
+
Only one version may be specified.
|
| 161 |
+
|
| 162 |
+
--preid <identifier>
|
| 163 |
+
Identifier to be used to prefix premajor, preminor,
|
| 164 |
+
prepatch or prerelease version increments.
|
| 165 |
+
|
| 166 |
+
-l --loose
|
| 167 |
+
Interpret versions and ranges loosely
|
| 168 |
+
|
| 169 |
+
-p --include-prerelease
|
| 170 |
+
Always include prerelease versions in range matching
|
| 171 |
+
|
| 172 |
+
-c --coerce
|
| 173 |
+
Coerce a string into SemVer if possible
|
| 174 |
+
(does not imply --loose)
|
| 175 |
+
|
| 176 |
+
--rtl
|
| 177 |
+
Coerce version strings right to left
|
| 178 |
+
|
| 179 |
+
--ltr
|
| 180 |
+
Coerce version strings left to right (default)
|
| 181 |
+
|
| 182 |
+
-n <base>
|
| 183 |
+
Base number to be used for the prerelease identifier.
|
| 184 |
+
Can be either 0 or 1, or false to omit the number altogether.
|
| 185 |
+
Defaults to 0.
|
| 186 |
+
|
| 187 |
+
Program exits successfully if any valid version satisfies
|
| 188 |
+
all supplied ranges, and prints all satisfying versions.
|
| 189 |
+
|
| 190 |
+
If no satisfying versions are found, then exits failure.
|
| 191 |
+
|
| 192 |
+
Versions are printed in ascending order, so supplying
|
| 193 |
+
multiple versions to the utility will just sort them.`)
|
| 194 |
+
|
| 195 |
+
main()
|
services/slides/node_modules/.bin/tsc
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
require('../lib/tsc.js')
|
services/slides/node_modules/.bin/tsserver
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
require('../lib/tsserver.js')
|
services/slides/node_modules/.bin/tsx
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
services/slides/node_modules/.package-lock.json
ADDED
|
@@ -0,0 +1,959 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "glm-vvr-slides",
|
| 3 |
+
"version": "0.1.0",
|
| 4 |
+
"lockfileVersion": 3,
|
| 5 |
+
"requires": true,
|
| 6 |
+
"packages": {
|
| 7 |
+
"node_modules/@esbuild/darwin-arm64": {
|
| 8 |
+
"version": "0.28.1",
|
| 9 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
|
| 10 |
+
"integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
|
| 11 |
+
"cpu": [
|
| 12 |
+
"arm64"
|
| 13 |
+
],
|
| 14 |
+
"dev": true,
|
| 15 |
+
"license": "MIT",
|
| 16 |
+
"optional": true,
|
| 17 |
+
"os": [
|
| 18 |
+
"darwin"
|
| 19 |
+
],
|
| 20 |
+
"engines": {
|
| 21 |
+
"node": ">=18"
|
| 22 |
+
}
|
| 23 |
+
},
|
| 24 |
+
"node_modules/@fastify/ajv-compiler": {
|
| 25 |
+
"version": "4.0.5",
|
| 26 |
+
"resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-4.0.5.tgz",
|
| 27 |
+
"integrity": "sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A==",
|
| 28 |
+
"funding": [
|
| 29 |
+
{
|
| 30 |
+
"type": "github",
|
| 31 |
+
"url": "https://github.com/sponsors/fastify"
|
| 32 |
+
},
|
| 33 |
+
{
|
| 34 |
+
"type": "opencollective",
|
| 35 |
+
"url": "https://opencollective.com/fastify"
|
| 36 |
+
}
|
| 37 |
+
],
|
| 38 |
+
"license": "MIT",
|
| 39 |
+
"dependencies": {
|
| 40 |
+
"ajv": "^8.12.0",
|
| 41 |
+
"ajv-formats": "^3.0.1",
|
| 42 |
+
"fast-uri": "^3.0.0"
|
| 43 |
+
}
|
| 44 |
+
},
|
| 45 |
+
"node_modules/@fastify/busboy": {
|
| 46 |
+
"version": "3.2.0",
|
| 47 |
+
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.2.0.tgz",
|
| 48 |
+
"integrity": "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==",
|
| 49 |
+
"license": "MIT"
|
| 50 |
+
},
|
| 51 |
+
"node_modules/@fastify/deepmerge": {
|
| 52 |
+
"version": "3.2.1",
|
| 53 |
+
"resolved": "https://registry.npmjs.org/@fastify/deepmerge/-/deepmerge-3.2.1.tgz",
|
| 54 |
+
"integrity": "sha512-N5Oqvltoa2r9z1tbx4xjky0oRR60v+T47Ic4J1ukoVQcptLOrIdRnCSdTGmOmajZuHVKlTnfcmrjyqsGEW1ztA==",
|
| 55 |
+
"funding": [
|
| 56 |
+
{
|
| 57 |
+
"type": "github",
|
| 58 |
+
"url": "https://github.com/sponsors/fastify"
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"type": "opencollective",
|
| 62 |
+
"url": "https://opencollective.com/fastify"
|
| 63 |
+
}
|
| 64 |
+
],
|
| 65 |
+
"license": "MIT"
|
| 66 |
+
},
|
| 67 |
+
"node_modules/@fastify/error": {
|
| 68 |
+
"version": "4.2.0",
|
| 69 |
+
"resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.2.0.tgz",
|
| 70 |
+
"integrity": "sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==",
|
| 71 |
+
"funding": [
|
| 72 |
+
{
|
| 73 |
+
"type": "github",
|
| 74 |
+
"url": "https://github.com/sponsors/fastify"
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"type": "opencollective",
|
| 78 |
+
"url": "https://opencollective.com/fastify"
|
| 79 |
+
}
|
| 80 |
+
],
|
| 81 |
+
"license": "MIT"
|
| 82 |
+
},
|
| 83 |
+
"node_modules/@fastify/fast-json-stringify-compiler": {
|
| 84 |
+
"version": "5.0.3",
|
| 85 |
+
"resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.0.3.tgz",
|
| 86 |
+
"integrity": "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==",
|
| 87 |
+
"funding": [
|
| 88 |
+
{
|
| 89 |
+
"type": "github",
|
| 90 |
+
"url": "https://github.com/sponsors/fastify"
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
"type": "opencollective",
|
| 94 |
+
"url": "https://opencollective.com/fastify"
|
| 95 |
+
}
|
| 96 |
+
],
|
| 97 |
+
"license": "MIT",
|
| 98 |
+
"dependencies": {
|
| 99 |
+
"fast-json-stringify": "^6.0.0"
|
| 100 |
+
}
|
| 101 |
+
},
|
| 102 |
+
"node_modules/@fastify/forwarded": {
|
| 103 |
+
"version": "3.0.1",
|
| 104 |
+
"resolved": "https://registry.npmjs.org/@fastify/forwarded/-/forwarded-3.0.1.tgz",
|
| 105 |
+
"integrity": "sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==",
|
| 106 |
+
"funding": [
|
| 107 |
+
{
|
| 108 |
+
"type": "github",
|
| 109 |
+
"url": "https://github.com/sponsors/fastify"
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"type": "opencollective",
|
| 113 |
+
"url": "https://opencollective.com/fastify"
|
| 114 |
+
}
|
| 115 |
+
],
|
| 116 |
+
"license": "MIT"
|
| 117 |
+
},
|
| 118 |
+
"node_modules/@fastify/merge-json-schemas": {
|
| 119 |
+
"version": "0.2.1",
|
| 120 |
+
"resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.2.1.tgz",
|
| 121 |
+
"integrity": "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==",
|
| 122 |
+
"funding": [
|
| 123 |
+
{
|
| 124 |
+
"type": "github",
|
| 125 |
+
"url": "https://github.com/sponsors/fastify"
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"type": "opencollective",
|
| 129 |
+
"url": "https://opencollective.com/fastify"
|
| 130 |
+
}
|
| 131 |
+
],
|
| 132 |
+
"license": "MIT",
|
| 133 |
+
"dependencies": {
|
| 134 |
+
"dequal": "^2.0.3"
|
| 135 |
+
}
|
| 136 |
+
},
|
| 137 |
+
"node_modules/@fastify/multipart": {
|
| 138 |
+
"version": "9.4.0",
|
| 139 |
+
"resolved": "https://registry.npmjs.org/@fastify/multipart/-/multipart-9.4.0.tgz",
|
| 140 |
+
"integrity": "sha512-Z404bzZeLSXTBmp/trCBuoVFX28pM7rhv849Q5TsbTFZHuk1lc4QjQITTPK92DKVpXmNtJXeHSSc7GYvqFpxAQ==",
|
| 141 |
+
"funding": [
|
| 142 |
+
{
|
| 143 |
+
"type": "github",
|
| 144 |
+
"url": "https://github.com/sponsors/fastify"
|
| 145 |
+
},
|
| 146 |
+
{
|
| 147 |
+
"type": "opencollective",
|
| 148 |
+
"url": "https://opencollective.com/fastify"
|
| 149 |
+
}
|
| 150 |
+
],
|
| 151 |
+
"license": "MIT",
|
| 152 |
+
"dependencies": {
|
| 153 |
+
"@fastify/busboy": "^3.0.0",
|
| 154 |
+
"@fastify/deepmerge": "^3.0.0",
|
| 155 |
+
"@fastify/error": "^4.0.0",
|
| 156 |
+
"fastify-plugin": "^5.0.0",
|
| 157 |
+
"secure-json-parse": "^4.0.0"
|
| 158 |
+
}
|
| 159 |
+
},
|
| 160 |
+
"node_modules/@fastify/proxy-addr": {
|
| 161 |
+
"version": "5.1.0",
|
| 162 |
+
"resolved": "https://registry.npmjs.org/@fastify/proxy-addr/-/proxy-addr-5.1.0.tgz",
|
| 163 |
+
"integrity": "sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==",
|
| 164 |
+
"funding": [
|
| 165 |
+
{
|
| 166 |
+
"type": "github",
|
| 167 |
+
"url": "https://github.com/sponsors/fastify"
|
| 168 |
+
},
|
| 169 |
+
{
|
| 170 |
+
"type": "opencollective",
|
| 171 |
+
"url": "https://opencollective.com/fastify"
|
| 172 |
+
}
|
| 173 |
+
],
|
| 174 |
+
"license": "MIT",
|
| 175 |
+
"dependencies": {
|
| 176 |
+
"@fastify/forwarded": "^3.0.0",
|
| 177 |
+
"ipaddr.js": "^2.1.0"
|
| 178 |
+
}
|
| 179 |
+
},
|
| 180 |
+
"node_modules/@pinojs/redact": {
|
| 181 |
+
"version": "0.4.0",
|
| 182 |
+
"resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz",
|
| 183 |
+
"integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==",
|
| 184 |
+
"license": "MIT"
|
| 185 |
+
},
|
| 186 |
+
"node_modules/@types/node": {
|
| 187 |
+
"version": "22.20.0",
|
| 188 |
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.0.tgz",
|
| 189 |
+
"integrity": "sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==",
|
| 190 |
+
"dev": true,
|
| 191 |
+
"license": "MIT",
|
| 192 |
+
"dependencies": {
|
| 193 |
+
"undici-types": "~6.21.0"
|
| 194 |
+
}
|
| 195 |
+
},
|
| 196 |
+
"node_modules/abstract-logging": {
|
| 197 |
+
"version": "2.0.1",
|
| 198 |
+
"resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
|
| 199 |
+
"integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==",
|
| 200 |
+
"license": "MIT"
|
| 201 |
+
},
|
| 202 |
+
"node_modules/ajv": {
|
| 203 |
+
"version": "8.20.0",
|
| 204 |
+
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
|
| 205 |
+
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
|
| 206 |
+
"license": "MIT",
|
| 207 |
+
"dependencies": {
|
| 208 |
+
"fast-deep-equal": "^3.1.3",
|
| 209 |
+
"fast-uri": "^3.0.1",
|
| 210 |
+
"json-schema-traverse": "^1.0.0",
|
| 211 |
+
"require-from-string": "^2.0.2"
|
| 212 |
+
},
|
| 213 |
+
"funding": {
|
| 214 |
+
"type": "github",
|
| 215 |
+
"url": "https://github.com/sponsors/epoberezkin"
|
| 216 |
+
}
|
| 217 |
+
},
|
| 218 |
+
"node_modules/ajv-formats": {
|
| 219 |
+
"version": "3.0.1",
|
| 220 |
+
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
|
| 221 |
+
"integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
|
| 222 |
+
"license": "MIT",
|
| 223 |
+
"dependencies": {
|
| 224 |
+
"ajv": "^8.0.0"
|
| 225 |
+
},
|
| 226 |
+
"peerDependencies": {
|
| 227 |
+
"ajv": "^8.0.0"
|
| 228 |
+
},
|
| 229 |
+
"peerDependenciesMeta": {
|
| 230 |
+
"ajv": {
|
| 231 |
+
"optional": true
|
| 232 |
+
}
|
| 233 |
+
}
|
| 234 |
+
},
|
| 235 |
+
"node_modules/atomic-sleep": {
|
| 236 |
+
"version": "1.0.0",
|
| 237 |
+
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
|
| 238 |
+
"integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
|
| 239 |
+
"license": "MIT",
|
| 240 |
+
"engines": {
|
| 241 |
+
"node": ">=8.0.0"
|
| 242 |
+
}
|
| 243 |
+
},
|
| 244 |
+
"node_modules/avvio": {
|
| 245 |
+
"version": "9.2.0",
|
| 246 |
+
"resolved": "https://registry.npmjs.org/avvio/-/avvio-9.2.0.tgz",
|
| 247 |
+
"integrity": "sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==",
|
| 248 |
+
"funding": [
|
| 249 |
+
{
|
| 250 |
+
"type": "github",
|
| 251 |
+
"url": "https://github.com/sponsors/fastify"
|
| 252 |
+
},
|
| 253 |
+
{
|
| 254 |
+
"type": "opencollective",
|
| 255 |
+
"url": "https://opencollective.com/fastify"
|
| 256 |
+
}
|
| 257 |
+
],
|
| 258 |
+
"license": "MIT",
|
| 259 |
+
"dependencies": {
|
| 260 |
+
"@fastify/error": "^4.0.0",
|
| 261 |
+
"fastq": "^1.17.1"
|
| 262 |
+
}
|
| 263 |
+
},
|
| 264 |
+
"node_modules/cookie": {
|
| 265 |
+
"version": "1.1.1",
|
| 266 |
+
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
|
| 267 |
+
"integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
|
| 268 |
+
"license": "MIT",
|
| 269 |
+
"engines": {
|
| 270 |
+
"node": ">=18"
|
| 271 |
+
},
|
| 272 |
+
"funding": {
|
| 273 |
+
"type": "opencollective",
|
| 274 |
+
"url": "https://opencollective.com/express"
|
| 275 |
+
}
|
| 276 |
+
},
|
| 277 |
+
"node_modules/core-util-is": {
|
| 278 |
+
"version": "1.0.3",
|
| 279 |
+
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
| 280 |
+
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
| 281 |
+
"license": "MIT"
|
| 282 |
+
},
|
| 283 |
+
"node_modules/dequal": {
|
| 284 |
+
"version": "2.0.3",
|
| 285 |
+
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
| 286 |
+
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
| 287 |
+
"license": "MIT",
|
| 288 |
+
"engines": {
|
| 289 |
+
"node": ">=6"
|
| 290 |
+
}
|
| 291 |
+
},
|
| 292 |
+
"node_modules/esbuild": {
|
| 293 |
+
"version": "0.28.1",
|
| 294 |
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
|
| 295 |
+
"integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
|
| 296 |
+
"dev": true,
|
| 297 |
+
"hasInstallScript": true,
|
| 298 |
+
"license": "MIT",
|
| 299 |
+
"bin": {
|
| 300 |
+
"esbuild": "bin/esbuild"
|
| 301 |
+
},
|
| 302 |
+
"engines": {
|
| 303 |
+
"node": ">=18"
|
| 304 |
+
},
|
| 305 |
+
"optionalDependencies": {
|
| 306 |
+
"@esbuild/aix-ppc64": "0.28.1",
|
| 307 |
+
"@esbuild/android-arm": "0.28.1",
|
| 308 |
+
"@esbuild/android-arm64": "0.28.1",
|
| 309 |
+
"@esbuild/android-x64": "0.28.1",
|
| 310 |
+
"@esbuild/darwin-arm64": "0.28.1",
|
| 311 |
+
"@esbuild/darwin-x64": "0.28.1",
|
| 312 |
+
"@esbuild/freebsd-arm64": "0.28.1",
|
| 313 |
+
"@esbuild/freebsd-x64": "0.28.1",
|
| 314 |
+
"@esbuild/linux-arm": "0.28.1",
|
| 315 |
+
"@esbuild/linux-arm64": "0.28.1",
|
| 316 |
+
"@esbuild/linux-ia32": "0.28.1",
|
| 317 |
+
"@esbuild/linux-loong64": "0.28.1",
|
| 318 |
+
"@esbuild/linux-mips64el": "0.28.1",
|
| 319 |
+
"@esbuild/linux-ppc64": "0.28.1",
|
| 320 |
+
"@esbuild/linux-riscv64": "0.28.1",
|
| 321 |
+
"@esbuild/linux-s390x": "0.28.1",
|
| 322 |
+
"@esbuild/linux-x64": "0.28.1",
|
| 323 |
+
"@esbuild/netbsd-arm64": "0.28.1",
|
| 324 |
+
"@esbuild/netbsd-x64": "0.28.1",
|
| 325 |
+
"@esbuild/openbsd-arm64": "0.28.1",
|
| 326 |
+
"@esbuild/openbsd-x64": "0.28.1",
|
| 327 |
+
"@esbuild/openharmony-arm64": "0.28.1",
|
| 328 |
+
"@esbuild/sunos-x64": "0.28.1",
|
| 329 |
+
"@esbuild/win32-arm64": "0.28.1",
|
| 330 |
+
"@esbuild/win32-ia32": "0.28.1",
|
| 331 |
+
"@esbuild/win32-x64": "0.28.1"
|
| 332 |
+
}
|
| 333 |
+
},
|
| 334 |
+
"node_modules/fast-decode-uri-component": {
|
| 335 |
+
"version": "1.0.1",
|
| 336 |
+
"resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
|
| 337 |
+
"integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==",
|
| 338 |
+
"license": "MIT"
|
| 339 |
+
},
|
| 340 |
+
"node_modules/fast-deep-equal": {
|
| 341 |
+
"version": "3.1.3",
|
| 342 |
+
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
| 343 |
+
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
| 344 |
+
"license": "MIT"
|
| 345 |
+
},
|
| 346 |
+
"node_modules/fast-json-stringify": {
|
| 347 |
+
"version": "6.4.0",
|
| 348 |
+
"resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-6.4.0.tgz",
|
| 349 |
+
"integrity": "sha512-ibRCQ0GZKJIQ+P3Et1h0LhPgp3PMTYk0MH8O+kW3lNYsvmaQww5Nn3f1jf73Q0jR1Yz3a1CDP4/NZD3vOajWJQ==",
|
| 350 |
+
"funding": [
|
| 351 |
+
{
|
| 352 |
+
"type": "github",
|
| 353 |
+
"url": "https://github.com/sponsors/fastify"
|
| 354 |
+
},
|
| 355 |
+
{
|
| 356 |
+
"type": "opencollective",
|
| 357 |
+
"url": "https://opencollective.com/fastify"
|
| 358 |
+
}
|
| 359 |
+
],
|
| 360 |
+
"license": "MIT",
|
| 361 |
+
"dependencies": {
|
| 362 |
+
"@fastify/merge-json-schemas": "^0.2.0",
|
| 363 |
+
"ajv": "^8.12.0",
|
| 364 |
+
"ajv-formats": "^3.0.1",
|
| 365 |
+
"fast-uri": "^3.0.0",
|
| 366 |
+
"json-schema-ref-resolver": "^3.0.0",
|
| 367 |
+
"rfdc": "^1.2.0"
|
| 368 |
+
}
|
| 369 |
+
},
|
| 370 |
+
"node_modules/fast-querystring": {
|
| 371 |
+
"version": "1.1.2",
|
| 372 |
+
"resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz",
|
| 373 |
+
"integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==",
|
| 374 |
+
"license": "MIT",
|
| 375 |
+
"dependencies": {
|
| 376 |
+
"fast-decode-uri-component": "^1.0.1"
|
| 377 |
+
}
|
| 378 |
+
},
|
| 379 |
+
"node_modules/fast-uri": {
|
| 380 |
+
"version": "3.1.2",
|
| 381 |
+
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
|
| 382 |
+
"integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==",
|
| 383 |
+
"funding": [
|
| 384 |
+
{
|
| 385 |
+
"type": "github",
|
| 386 |
+
"url": "https://github.com/sponsors/fastify"
|
| 387 |
+
},
|
| 388 |
+
{
|
| 389 |
+
"type": "opencollective",
|
| 390 |
+
"url": "https://opencollective.com/fastify"
|
| 391 |
+
}
|
| 392 |
+
],
|
| 393 |
+
"license": "BSD-3-Clause"
|
| 394 |
+
},
|
| 395 |
+
"node_modules/fastify": {
|
| 396 |
+
"version": "5.8.5",
|
| 397 |
+
"resolved": "https://registry.npmjs.org/fastify/-/fastify-5.8.5.tgz",
|
| 398 |
+
"integrity": "sha512-Yqptv59pQzPgQUSIm87hMqHJmdkb1+GPxdE6vW6FRyVE9G86mt7rOghitiU4JHRaTyDUk9pfeKmDeu70lAwM4Q==",
|
| 399 |
+
"funding": [
|
| 400 |
+
{
|
| 401 |
+
"type": "github",
|
| 402 |
+
"url": "https://github.com/sponsors/fastify"
|
| 403 |
+
},
|
| 404 |
+
{
|
| 405 |
+
"type": "opencollective",
|
| 406 |
+
"url": "https://opencollective.com/fastify"
|
| 407 |
+
}
|
| 408 |
+
],
|
| 409 |
+
"license": "MIT",
|
| 410 |
+
"dependencies": {
|
| 411 |
+
"@fastify/ajv-compiler": "^4.0.5",
|
| 412 |
+
"@fastify/error": "^4.0.0",
|
| 413 |
+
"@fastify/fast-json-stringify-compiler": "^5.0.0",
|
| 414 |
+
"@fastify/proxy-addr": "^5.0.0",
|
| 415 |
+
"abstract-logging": "^2.0.1",
|
| 416 |
+
"avvio": "^9.0.0",
|
| 417 |
+
"fast-json-stringify": "^6.0.0",
|
| 418 |
+
"find-my-way": "^9.0.0",
|
| 419 |
+
"light-my-request": "^6.0.0",
|
| 420 |
+
"pino": "^9.14.0 || ^10.1.0",
|
| 421 |
+
"process-warning": "^5.0.0",
|
| 422 |
+
"rfdc": "^1.3.1",
|
| 423 |
+
"secure-json-parse": "^4.0.0",
|
| 424 |
+
"semver": "^7.6.0",
|
| 425 |
+
"toad-cache": "^3.7.0"
|
| 426 |
+
}
|
| 427 |
+
},
|
| 428 |
+
"node_modules/fastify-plugin": {
|
| 429 |
+
"version": "5.1.0",
|
| 430 |
+
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.1.0.tgz",
|
| 431 |
+
"integrity": "sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw==",
|
| 432 |
+
"funding": [
|
| 433 |
+
{
|
| 434 |
+
"type": "github",
|
| 435 |
+
"url": "https://github.com/sponsors/fastify"
|
| 436 |
+
},
|
| 437 |
+
{
|
| 438 |
+
"type": "opencollective",
|
| 439 |
+
"url": "https://opencollective.com/fastify"
|
| 440 |
+
}
|
| 441 |
+
],
|
| 442 |
+
"license": "MIT"
|
| 443 |
+
},
|
| 444 |
+
"node_modules/fastq": {
|
| 445 |
+
"version": "1.20.1",
|
| 446 |
+
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
|
| 447 |
+
"integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
|
| 448 |
+
"license": "ISC",
|
| 449 |
+
"dependencies": {
|
| 450 |
+
"reusify": "^1.0.4"
|
| 451 |
+
}
|
| 452 |
+
},
|
| 453 |
+
"node_modules/find-my-way": {
|
| 454 |
+
"version": "9.6.0",
|
| 455 |
+
"resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.6.0.tgz",
|
| 456 |
+
"integrity": "sha512-Zf4Xve4RymLl7NgaavNebZ01joJ8MfVerOG43wy7SHLO+r+K0C6d/SE0BiR7AV5V1VOCFlOP7ecdo+I4qmiHrQ==",
|
| 457 |
+
"license": "MIT",
|
| 458 |
+
"dependencies": {
|
| 459 |
+
"fast-deep-equal": "^3.1.3",
|
| 460 |
+
"fast-querystring": "^1.0.0",
|
| 461 |
+
"safe-regex2": "^5.0.0"
|
| 462 |
+
},
|
| 463 |
+
"engines": {
|
| 464 |
+
"node": ">=20"
|
| 465 |
+
}
|
| 466 |
+
},
|
| 467 |
+
"node_modules/https": {
|
| 468 |
+
"version": "1.0.0",
|
| 469 |
+
"resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz",
|
| 470 |
+
"integrity": "sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==",
|
| 471 |
+
"license": "ISC"
|
| 472 |
+
},
|
| 473 |
+
"node_modules/image-size": {
|
| 474 |
+
"version": "1.2.1",
|
| 475 |
+
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz",
|
| 476 |
+
"integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==",
|
| 477 |
+
"license": "MIT",
|
| 478 |
+
"dependencies": {
|
| 479 |
+
"queue": "6.0.2"
|
| 480 |
+
},
|
| 481 |
+
"bin": {
|
| 482 |
+
"image-size": "bin/image-size.js"
|
| 483 |
+
},
|
| 484 |
+
"engines": {
|
| 485 |
+
"node": ">=16.x"
|
| 486 |
+
}
|
| 487 |
+
},
|
| 488 |
+
"node_modules/immediate": {
|
| 489 |
+
"version": "3.0.6",
|
| 490 |
+
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
| 491 |
+
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
|
| 492 |
+
"license": "MIT"
|
| 493 |
+
},
|
| 494 |
+
"node_modules/inherits": {
|
| 495 |
+
"version": "2.0.4",
|
| 496 |
+
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
| 497 |
+
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
| 498 |
+
"license": "ISC"
|
| 499 |
+
},
|
| 500 |
+
"node_modules/ipaddr.js": {
|
| 501 |
+
"version": "2.4.0",
|
| 502 |
+
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz",
|
| 503 |
+
"integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==",
|
| 504 |
+
"license": "MIT",
|
| 505 |
+
"engines": {
|
| 506 |
+
"node": ">= 10"
|
| 507 |
+
}
|
| 508 |
+
},
|
| 509 |
+
"node_modules/isarray": {
|
| 510 |
+
"version": "1.0.0",
|
| 511 |
+
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
| 512 |
+
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
| 513 |
+
"license": "MIT"
|
| 514 |
+
},
|
| 515 |
+
"node_modules/json-schema-ref-resolver": {
|
| 516 |
+
"version": "3.0.0",
|
| 517 |
+
"resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-3.0.0.tgz",
|
| 518 |
+
"integrity": "sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==",
|
| 519 |
+
"funding": [
|
| 520 |
+
{
|
| 521 |
+
"type": "github",
|
| 522 |
+
"url": "https://github.com/sponsors/fastify"
|
| 523 |
+
},
|
| 524 |
+
{
|
| 525 |
+
"type": "opencollective",
|
| 526 |
+
"url": "https://opencollective.com/fastify"
|
| 527 |
+
}
|
| 528 |
+
],
|
| 529 |
+
"license": "MIT",
|
| 530 |
+
"dependencies": {
|
| 531 |
+
"dequal": "^2.0.3"
|
| 532 |
+
}
|
| 533 |
+
},
|
| 534 |
+
"node_modules/json-schema-traverse": {
|
| 535 |
+
"version": "1.0.0",
|
| 536 |
+
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
| 537 |
+
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
| 538 |
+
"license": "MIT"
|
| 539 |
+
},
|
| 540 |
+
"node_modules/jszip": {
|
| 541 |
+
"version": "3.10.1",
|
| 542 |
+
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
| 543 |
+
"integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
|
| 544 |
+
"license": "(MIT OR GPL-3.0-or-later)",
|
| 545 |
+
"dependencies": {
|
| 546 |
+
"lie": "~3.3.0",
|
| 547 |
+
"pako": "~1.0.2",
|
| 548 |
+
"readable-stream": "~2.3.6",
|
| 549 |
+
"setimmediate": "^1.0.5"
|
| 550 |
+
}
|
| 551 |
+
},
|
| 552 |
+
"node_modules/lie": {
|
| 553 |
+
"version": "3.3.0",
|
| 554 |
+
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
| 555 |
+
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
| 556 |
+
"license": "MIT",
|
| 557 |
+
"dependencies": {
|
| 558 |
+
"immediate": "~3.0.5"
|
| 559 |
+
}
|
| 560 |
+
},
|
| 561 |
+
"node_modules/light-my-request": {
|
| 562 |
+
"version": "6.6.0",
|
| 563 |
+
"resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-6.6.0.tgz",
|
| 564 |
+
"integrity": "sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==",
|
| 565 |
+
"funding": [
|
| 566 |
+
{
|
| 567 |
+
"type": "github",
|
| 568 |
+
"url": "https://github.com/sponsors/fastify"
|
| 569 |
+
},
|
| 570 |
+
{
|
| 571 |
+
"type": "opencollective",
|
| 572 |
+
"url": "https://opencollective.com/fastify"
|
| 573 |
+
}
|
| 574 |
+
],
|
| 575 |
+
"license": "BSD-3-Clause",
|
| 576 |
+
"dependencies": {
|
| 577 |
+
"cookie": "^1.0.1",
|
| 578 |
+
"process-warning": "^4.0.0",
|
| 579 |
+
"set-cookie-parser": "^2.6.0"
|
| 580 |
+
}
|
| 581 |
+
},
|
| 582 |
+
"node_modules/light-my-request/node_modules/process-warning": {
|
| 583 |
+
"version": "4.0.1",
|
| 584 |
+
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz",
|
| 585 |
+
"integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==",
|
| 586 |
+
"funding": [
|
| 587 |
+
{
|
| 588 |
+
"type": "github",
|
| 589 |
+
"url": "https://github.com/sponsors/fastify"
|
| 590 |
+
},
|
| 591 |
+
{
|
| 592 |
+
"type": "opencollective",
|
| 593 |
+
"url": "https://opencollective.com/fastify"
|
| 594 |
+
}
|
| 595 |
+
],
|
| 596 |
+
"license": "MIT"
|
| 597 |
+
},
|
| 598 |
+
"node_modules/on-exit-leak-free": {
|
| 599 |
+
"version": "2.1.2",
|
| 600 |
+
"resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
|
| 601 |
+
"integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==",
|
| 602 |
+
"license": "MIT",
|
| 603 |
+
"engines": {
|
| 604 |
+
"node": ">=14.0.0"
|
| 605 |
+
}
|
| 606 |
+
},
|
| 607 |
+
"node_modules/pako": {
|
| 608 |
+
"version": "1.0.11",
|
| 609 |
+
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
| 610 |
+
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
| 611 |
+
"license": "(MIT AND Zlib)"
|
| 612 |
+
},
|
| 613 |
+
"node_modules/pino": {
|
| 614 |
+
"version": "10.3.1",
|
| 615 |
+
"resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz",
|
| 616 |
+
"integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==",
|
| 617 |
+
"license": "MIT",
|
| 618 |
+
"dependencies": {
|
| 619 |
+
"@pinojs/redact": "^0.4.0",
|
| 620 |
+
"atomic-sleep": "^1.0.0",
|
| 621 |
+
"on-exit-leak-free": "^2.1.0",
|
| 622 |
+
"pino-abstract-transport": "^3.0.0",
|
| 623 |
+
"pino-std-serializers": "^7.0.0",
|
| 624 |
+
"process-warning": "^5.0.0",
|
| 625 |
+
"quick-format-unescaped": "^4.0.3",
|
| 626 |
+
"real-require": "^0.2.0",
|
| 627 |
+
"safe-stable-stringify": "^2.3.1",
|
| 628 |
+
"sonic-boom": "^4.0.1",
|
| 629 |
+
"thread-stream": "^4.0.0"
|
| 630 |
+
},
|
| 631 |
+
"bin": {
|
| 632 |
+
"pino": "bin.js"
|
| 633 |
+
}
|
| 634 |
+
},
|
| 635 |
+
"node_modules/pino-abstract-transport": {
|
| 636 |
+
"version": "3.0.0",
|
| 637 |
+
"resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz",
|
| 638 |
+
"integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==",
|
| 639 |
+
"license": "MIT",
|
| 640 |
+
"dependencies": {
|
| 641 |
+
"split2": "^4.0.0"
|
| 642 |
+
}
|
| 643 |
+
},
|
| 644 |
+
"node_modules/pino-std-serializers": {
|
| 645 |
+
"version": "7.1.0",
|
| 646 |
+
"resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz",
|
| 647 |
+
"integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==",
|
| 648 |
+
"license": "MIT"
|
| 649 |
+
},
|
| 650 |
+
"node_modules/pptxgenjs": {
|
| 651 |
+
"version": "3.12.0",
|
| 652 |
+
"resolved": "https://registry.npmjs.org/pptxgenjs/-/pptxgenjs-3.12.0.tgz",
|
| 653 |
+
"integrity": "sha512-ZozkYKWb1MoPR4ucw3/aFYlHkVIJxo9czikEclcUVnS4Iw/M+r+TEwdlB3fyAWO9JY1USxJDt0Y0/r15IR/RUA==",
|
| 654 |
+
"license": "MIT",
|
| 655 |
+
"dependencies": {
|
| 656 |
+
"@types/node": "^18.7.3",
|
| 657 |
+
"https": "^1.0.0",
|
| 658 |
+
"image-size": "^1.0.0",
|
| 659 |
+
"jszip": "^3.7.1"
|
| 660 |
+
}
|
| 661 |
+
},
|
| 662 |
+
"node_modules/pptxgenjs/node_modules/@types/node": {
|
| 663 |
+
"version": "18.19.130",
|
| 664 |
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
|
| 665 |
+
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
|
| 666 |
+
"license": "MIT",
|
| 667 |
+
"dependencies": {
|
| 668 |
+
"undici-types": "~5.26.4"
|
| 669 |
+
}
|
| 670 |
+
},
|
| 671 |
+
"node_modules/pptxgenjs/node_modules/undici-types": {
|
| 672 |
+
"version": "5.26.5",
|
| 673 |
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
| 674 |
+
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
| 675 |
+
"license": "MIT"
|
| 676 |
+
},
|
| 677 |
+
"node_modules/process-nextick-args": {
|
| 678 |
+
"version": "2.0.1",
|
| 679 |
+
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
| 680 |
+
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
| 681 |
+
"license": "MIT"
|
| 682 |
+
},
|
| 683 |
+
"node_modules/process-warning": {
|
| 684 |
+
"version": "5.0.0",
|
| 685 |
+
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz",
|
| 686 |
+
"integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==",
|
| 687 |
+
"funding": [
|
| 688 |
+
{
|
| 689 |
+
"type": "github",
|
| 690 |
+
"url": "https://github.com/sponsors/fastify"
|
| 691 |
+
},
|
| 692 |
+
{
|
| 693 |
+
"type": "opencollective",
|
| 694 |
+
"url": "https://opencollective.com/fastify"
|
| 695 |
+
}
|
| 696 |
+
],
|
| 697 |
+
"license": "MIT"
|
| 698 |
+
},
|
| 699 |
+
"node_modules/queue": {
|
| 700 |
+
"version": "6.0.2",
|
| 701 |
+
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
|
| 702 |
+
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
|
| 703 |
+
"license": "MIT",
|
| 704 |
+
"dependencies": {
|
| 705 |
+
"inherits": "~2.0.3"
|
| 706 |
+
}
|
| 707 |
+
},
|
| 708 |
+
"node_modules/quick-format-unescaped": {
|
| 709 |
+
"version": "4.0.4",
|
| 710 |
+
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
|
| 711 |
+
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
|
| 712 |
+
"license": "MIT"
|
| 713 |
+
},
|
| 714 |
+
"node_modules/readable-stream": {
|
| 715 |
+
"version": "2.3.8",
|
| 716 |
+
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
| 717 |
+
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
| 718 |
+
"license": "MIT",
|
| 719 |
+
"dependencies": {
|
| 720 |
+
"core-util-is": "~1.0.0",
|
| 721 |
+
"inherits": "~2.0.3",
|
| 722 |
+
"isarray": "~1.0.0",
|
| 723 |
+
"process-nextick-args": "~2.0.0",
|
| 724 |
+
"safe-buffer": "~5.1.1",
|
| 725 |
+
"string_decoder": "~1.1.1",
|
| 726 |
+
"util-deprecate": "~1.0.1"
|
| 727 |
+
}
|
| 728 |
+
},
|
| 729 |
+
"node_modules/real-require": {
|
| 730 |
+
"version": "0.2.0",
|
| 731 |
+
"resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
|
| 732 |
+
"integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==",
|
| 733 |
+
"license": "MIT",
|
| 734 |
+
"engines": {
|
| 735 |
+
"node": ">= 12.13.0"
|
| 736 |
+
}
|
| 737 |
+
},
|
| 738 |
+
"node_modules/require-from-string": {
|
| 739 |
+
"version": "2.0.2",
|
| 740 |
+
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
| 741 |
+
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
| 742 |
+
"license": "MIT",
|
| 743 |
+
"engines": {
|
| 744 |
+
"node": ">=0.10.0"
|
| 745 |
+
}
|
| 746 |
+
},
|
| 747 |
+
"node_modules/ret": {
|
| 748 |
+
"version": "0.5.0",
|
| 749 |
+
"resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz",
|
| 750 |
+
"integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==",
|
| 751 |
+
"license": "MIT",
|
| 752 |
+
"engines": {
|
| 753 |
+
"node": ">=10"
|
| 754 |
+
}
|
| 755 |
+
},
|
| 756 |
+
"node_modules/reusify": {
|
| 757 |
+
"version": "1.1.0",
|
| 758 |
+
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
|
| 759 |
+
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
|
| 760 |
+
"license": "MIT",
|
| 761 |
+
"engines": {
|
| 762 |
+
"iojs": ">=1.0.0",
|
| 763 |
+
"node": ">=0.10.0"
|
| 764 |
+
}
|
| 765 |
+
},
|
| 766 |
+
"node_modules/rfdc": {
|
| 767 |
+
"version": "1.4.1",
|
| 768 |
+
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
| 769 |
+
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
| 770 |
+
"license": "MIT"
|
| 771 |
+
},
|
| 772 |
+
"node_modules/safe-buffer": {
|
| 773 |
+
"version": "5.1.2",
|
| 774 |
+
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
| 775 |
+
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
| 776 |
+
"license": "MIT"
|
| 777 |
+
},
|
| 778 |
+
"node_modules/safe-regex2": {
|
| 779 |
+
"version": "5.1.1",
|
| 780 |
+
"resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.1.1.tgz",
|
| 781 |
+
"integrity": "sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==",
|
| 782 |
+
"funding": [
|
| 783 |
+
{
|
| 784 |
+
"type": "github",
|
| 785 |
+
"url": "https://github.com/sponsors/fastify"
|
| 786 |
+
},
|
| 787 |
+
{
|
| 788 |
+
"type": "opencollective",
|
| 789 |
+
"url": "https://opencollective.com/fastify"
|
| 790 |
+
}
|
| 791 |
+
],
|
| 792 |
+
"license": "MIT",
|
| 793 |
+
"dependencies": {
|
| 794 |
+
"ret": "~0.5.0"
|
| 795 |
+
},
|
| 796 |
+
"bin": {
|
| 797 |
+
"safe-regex2": "bin/safe-regex2.js"
|
| 798 |
+
}
|
| 799 |
+
},
|
| 800 |
+
"node_modules/safe-stable-stringify": {
|
| 801 |
+
"version": "2.5.0",
|
| 802 |
+
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
|
| 803 |
+
"integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
|
| 804 |
+
"license": "MIT",
|
| 805 |
+
"engines": {
|
| 806 |
+
"node": ">=10"
|
| 807 |
+
}
|
| 808 |
+
},
|
| 809 |
+
"node_modules/secure-json-parse": {
|
| 810 |
+
"version": "4.1.0",
|
| 811 |
+
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz",
|
| 812 |
+
"integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==",
|
| 813 |
+
"funding": [
|
| 814 |
+
{
|
| 815 |
+
"type": "github",
|
| 816 |
+
"url": "https://github.com/sponsors/fastify"
|
| 817 |
+
},
|
| 818 |
+
{
|
| 819 |
+
"type": "opencollective",
|
| 820 |
+
"url": "https://opencollective.com/fastify"
|
| 821 |
+
}
|
| 822 |
+
],
|
| 823 |
+
"license": "BSD-3-Clause"
|
| 824 |
+
},
|
| 825 |
+
"node_modules/semver": {
|
| 826 |
+
"version": "7.8.5",
|
| 827 |
+
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
|
| 828 |
+
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
|
| 829 |
+
"license": "ISC",
|
| 830 |
+
"bin": {
|
| 831 |
+
"semver": "bin/semver.js"
|
| 832 |
+
},
|
| 833 |
+
"engines": {
|
| 834 |
+
"node": ">=10"
|
| 835 |
+
}
|
| 836 |
+
},
|
| 837 |
+
"node_modules/set-cookie-parser": {
|
| 838 |
+
"version": "2.7.2",
|
| 839 |
+
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
|
| 840 |
+
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
|
| 841 |
+
"license": "MIT"
|
| 842 |
+
},
|
| 843 |
+
"node_modules/setimmediate": {
|
| 844 |
+
"version": "1.0.5",
|
| 845 |
+
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
| 846 |
+
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
|
| 847 |
+
"license": "MIT"
|
| 848 |
+
},
|
| 849 |
+
"node_modules/sonic-boom": {
|
| 850 |
+
"version": "4.2.1",
|
| 851 |
+
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz",
|
| 852 |
+
"integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==",
|
| 853 |
+
"license": "MIT",
|
| 854 |
+
"dependencies": {
|
| 855 |
+
"atomic-sleep": "^1.0.0"
|
| 856 |
+
}
|
| 857 |
+
},
|
| 858 |
+
"node_modules/split2": {
|
| 859 |
+
"version": "4.2.0",
|
| 860 |
+
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
|
| 861 |
+
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
|
| 862 |
+
"license": "ISC",
|
| 863 |
+
"engines": {
|
| 864 |
+
"node": ">= 10.x"
|
| 865 |
+
}
|
| 866 |
+
},
|
| 867 |
+
"node_modules/string_decoder": {
|
| 868 |
+
"version": "1.1.1",
|
| 869 |
+
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
| 870 |
+
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
| 871 |
+
"license": "MIT",
|
| 872 |
+
"dependencies": {
|
| 873 |
+
"safe-buffer": "~5.1.0"
|
| 874 |
+
}
|
| 875 |
+
},
|
| 876 |
+
"node_modules/thread-stream": {
|
| 877 |
+
"version": "4.2.0",
|
| 878 |
+
"resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.2.0.tgz",
|
| 879 |
+
"integrity": "sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==",
|
| 880 |
+
"license": "MIT",
|
| 881 |
+
"dependencies": {
|
| 882 |
+
"real-require": "^1.0.0"
|
| 883 |
+
},
|
| 884 |
+
"engines": {
|
| 885 |
+
"node": ">=20"
|
| 886 |
+
}
|
| 887 |
+
},
|
| 888 |
+
"node_modules/thread-stream/node_modules/real-require": {
|
| 889 |
+
"version": "1.0.0",
|
| 890 |
+
"resolved": "https://registry.npmjs.org/real-require/-/real-require-1.0.0.tgz",
|
| 891 |
+
"integrity": "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==",
|
| 892 |
+
"license": "MIT"
|
| 893 |
+
},
|
| 894 |
+
"node_modules/toad-cache": {
|
| 895 |
+
"version": "3.7.1",
|
| 896 |
+
"resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.1.tgz",
|
| 897 |
+
"integrity": "sha512-5DXWzE4Vz7xNHsv+xQ+MGfJYyC78Aok3tEr0MNwHoRf7vZnga1mQXZ4/Nsodld4VR6Wd+VhfmqnNrsRJyYPfrQ==",
|
| 898 |
+
"license": "MIT",
|
| 899 |
+
"engines": {
|
| 900 |
+
"node": ">=20"
|
| 901 |
+
}
|
| 902 |
+
},
|
| 903 |
+
"node_modules/tsx": {
|
| 904 |
+
"version": "4.22.4",
|
| 905 |
+
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz",
|
| 906 |
+
"integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==",
|
| 907 |
+
"dev": true,
|
| 908 |
+
"license": "MIT",
|
| 909 |
+
"dependencies": {
|
| 910 |
+
"esbuild": "~0.28.0"
|
| 911 |
+
},
|
| 912 |
+
"bin": {
|
| 913 |
+
"tsx": "dist/cli.mjs"
|
| 914 |
+
},
|
| 915 |
+
"engines": {
|
| 916 |
+
"node": ">=18.0.0"
|
| 917 |
+
},
|
| 918 |
+
"optionalDependencies": {
|
| 919 |
+
"fsevents": "~2.3.3"
|
| 920 |
+
}
|
| 921 |
+
},
|
| 922 |
+
"node_modules/typescript": {
|
| 923 |
+
"version": "5.9.3",
|
| 924 |
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
| 925 |
+
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
| 926 |
+
"dev": true,
|
| 927 |
+
"license": "Apache-2.0",
|
| 928 |
+
"bin": {
|
| 929 |
+
"tsc": "bin/tsc",
|
| 930 |
+
"tsserver": "bin/tsserver"
|
| 931 |
+
},
|
| 932 |
+
"engines": {
|
| 933 |
+
"node": ">=14.17"
|
| 934 |
+
}
|
| 935 |
+
},
|
| 936 |
+
"node_modules/undici-types": {
|
| 937 |
+
"version": "6.21.0",
|
| 938 |
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
| 939 |
+
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
| 940 |
+
"dev": true,
|
| 941 |
+
"license": "MIT"
|
| 942 |
+
},
|
| 943 |
+
"node_modules/util-deprecate": {
|
| 944 |
+
"version": "1.0.2",
|
| 945 |
+
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
| 946 |
+
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
| 947 |
+
"license": "MIT"
|
| 948 |
+
},
|
| 949 |
+
"node_modules/zod": {
|
| 950 |
+
"version": "3.25.76",
|
| 951 |
+
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
| 952 |
+
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
| 953 |
+
"license": "MIT",
|
| 954 |
+
"funding": {
|
| 955 |
+
"url": "https://github.com/sponsors/colinhacks"
|
| 956 |
+
}
|
| 957 |
+
}
|
| 958 |
+
}
|
| 959 |
+
}
|
services/slides/node_modules/@esbuild/darwin-arm64/README.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# esbuild
|
| 2 |
+
|
| 3 |
+
This is the macOS ARM 64-bit binary for esbuild, a JavaScript bundler and minifier. See https://github.com/evanw/esbuild for details.
|
services/slides/node_modules/@esbuild/darwin-arm64/bin/esbuild
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e2dc9a52440a2a34f09434a2f4843cb1e30f84e40dcf238976ec61ef8cd7f36a
|
| 3 |
+
size 10573778
|
services/slides/node_modules/@esbuild/darwin-arm64/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "@esbuild/darwin-arm64",
|
| 3 |
+
"version": "0.28.1",
|
| 4 |
+
"description": "The macOS ARM 64-bit binary for esbuild, a JavaScript bundler.",
|
| 5 |
+
"repository": {
|
| 6 |
+
"type": "git",
|
| 7 |
+
"url": "git+https://github.com/evanw/esbuild.git"
|
| 8 |
+
},
|
| 9 |
+
"license": "MIT",
|
| 10 |
+
"preferUnplugged": true,
|
| 11 |
+
"engines": {
|
| 12 |
+
"node": ">=18"
|
| 13 |
+
},
|
| 14 |
+
"os": [
|
| 15 |
+
"darwin"
|
| 16 |
+
],
|
| 17 |
+
"cpu": [
|
| 18 |
+
"arm64"
|
| 19 |
+
]
|
| 20 |
+
}
|
services/slides/node_modules/@fastify/ajv-compiler/.gitattributes
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Set default behavior to automatically convert line endings
|
| 2 |
+
* text=auto eol=lf
|
services/slides/node_modules/@fastify/ajv-compiler/.github/.stale.yml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Number of days of inactivity before an issue becomes stale
|
| 2 |
+
daysUntilStale: 15
|
| 3 |
+
# Number of days of inactivity before a stale issue is closed
|
| 4 |
+
daysUntilClose: 7
|
| 5 |
+
# Issues with these labels will never be considered stale
|
| 6 |
+
exemptLabels:
|
| 7 |
+
- "discussion"
|
| 8 |
+
- "feature request"
|
| 9 |
+
- "bug"
|
| 10 |
+
- "help wanted"
|
| 11 |
+
- "plugin suggestion"
|
| 12 |
+
- "good first issue"
|
| 13 |
+
# Label to use when marking an issue as stale
|
| 14 |
+
staleLabel: stale
|
| 15 |
+
# Comment to post when marking an issue as stale. Set to `false` to disable
|
| 16 |
+
markComment: >
|
| 17 |
+
This issue has been automatically marked as stale because it has not had
|
| 18 |
+
recent activity. It will be closed if no further activity occurs. Thank you
|
| 19 |
+
for your contributions.
|
| 20 |
+
# Comment to post when closing a stale issue. Set to `false` to disable
|
| 21 |
+
closeComment: false
|
services/slides/node_modules/@fastify/ajv-compiler/.github/dependabot.yml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: 2
|
| 2 |
+
updates:
|
| 3 |
+
- package-ecosystem: "github-actions"
|
| 4 |
+
directory: "/"
|
| 5 |
+
schedule:
|
| 6 |
+
interval: "monthly"
|
| 7 |
+
open-pull-requests-limit: 10
|
| 8 |
+
|
| 9 |
+
- package-ecosystem: "npm"
|
| 10 |
+
directory: "/"
|
| 11 |
+
schedule:
|
| 12 |
+
interval: "weekly"
|
| 13 |
+
open-pull-requests-limit: 10
|
services/slides/node_modules/@fastify/ajv-compiler/.github/tests_checker.yml
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
comment: |
|
| 2 |
+
Hello! Thank you for contributing!
|
| 3 |
+
It appears that you have changed the code, but the tests that verify your change are missing. Could you please add them?
|
| 4 |
+
fileExtensions:
|
| 5 |
+
- '.ts'
|
| 6 |
+
- '.js'
|
| 7 |
+
|
| 8 |
+
testDir: 'test'
|
services/slides/node_modules/@fastify/ajv-compiler/.github/workflows/ci.yml
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: CI
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches:
|
| 6 |
+
- main
|
| 7 |
+
- next
|
| 8 |
+
- 'v*'
|
| 9 |
+
paths-ignore:
|
| 10 |
+
- 'docs/**'
|
| 11 |
+
- '*.md'
|
| 12 |
+
pull_request:
|
| 13 |
+
paths-ignore:
|
| 14 |
+
- 'docs/**'
|
| 15 |
+
- '*.md'
|
| 16 |
+
|
| 17 |
+
# This allows a subsequently queued workflow run to interrupt previous runs
|
| 18 |
+
concurrency:
|
| 19 |
+
group: "${{ github.workflow }}-${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
|
| 20 |
+
cancel-in-progress: true
|
| 21 |
+
|
| 22 |
+
permissions:
|
| 23 |
+
contents: read
|
| 24 |
+
|
| 25 |
+
jobs:
|
| 26 |
+
test:
|
| 27 |
+
permissions:
|
| 28 |
+
contents: write
|
| 29 |
+
pull-requests: write
|
| 30 |
+
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5
|
| 31 |
+
with:
|
| 32 |
+
license-check: true
|
| 33 |
+
lint: true
|
services/slides/node_modules/@fastify/ajv-compiler/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2022-present The Fastify team
|
| 4 |
+
|
| 5 |
+
The Fastify team members are listed at https://github.com/fastify/fastify#team.
|
| 6 |
+
|
| 7 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 8 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 9 |
+
in the Software without restriction, including without limitation the rights
|
| 10 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 11 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 12 |
+
furnished to do so, subject to the following conditions:
|
| 13 |
+
|
| 14 |
+
The above copyright notice and this permission notice shall be included in all
|
| 15 |
+
copies or substantial portions of the Software.
|
| 16 |
+
|
| 17 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 18 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 19 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 20 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 21 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 22 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 23 |
+
SOFTWARE.
|
services/slides/node_modules/@fastify/ajv-compiler/README.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# @fastify/ajv-compiler
|
| 2 |
+
|
| 3 |
+
[](https://github.com/fastify/ajv-compiler/actions/workflows/ci.yml)
|
| 4 |
+
[](https://www.npmjs.com/package/@fastify/ajv-compiler)
|
| 5 |
+
[](https://github.com/neostandard/neostandard)
|
| 6 |
+
|
| 7 |
+
This module manages the [`ajv`](https://www.npmjs.com/package/ajv) instances for the Fastify framework.
|
| 8 |
+
It isolates the `ajv` dependency so that the AJV version is not tightly coupled to the Fastify version.
|
| 9 |
+
This allows the user to decide which version of AJV to use in their Fastify-based application.
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
## Versions
|
| 13 |
+
|
| 14 |
+
| `@fastify/ajv-compiler` | `ajv` | Default in `fastify` |
|
| 15 |
+
|------------------------:|------:|---------------------:|
|
| 16 |
+
| v4.x | v8.x | ^5.x |
|
| 17 |
+
| v3.x | v8.x | ^4.x |
|
| 18 |
+
| v2.x | v8.x | - |
|
| 19 |
+
| v1.x | v6.x | ^3.14 |
|
| 20 |
+
|
| 21 |
+
### AJV Configuration
|
| 22 |
+
|
| 23 |
+
The Fastify's default [`ajv` options](https://github.com/ajv-validator/ajv/tree/v6#options) are:
|
| 24 |
+
|
| 25 |
+
```js
|
| 26 |
+
{
|
| 27 |
+
coerceTypes: 'array',
|
| 28 |
+
useDefaults: true,
|
| 29 |
+
removeAdditional: true,
|
| 30 |
+
uriResolver: require('fast-uri'),
|
| 31 |
+
addUsedSchema: false,
|
| 32 |
+
// Explicitly set allErrors to `false`.
|
| 33 |
+
// When set to `true`, a DoS attack is possible.
|
| 34 |
+
allErrors: false
|
| 35 |
+
}
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
Moreover, the [`ajv-formats`](https://www.npmjs.com/package/ajv-formats) module is included by default.
|
| 39 |
+
If you need to customize it, check the _usage_ section below.
|
| 40 |
+
|
| 41 |
+
To customize the `ajv` options, see how in the [Fastify documentation](https://fastify.dev/docs/latest/Reference/Server/#ajv).
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
## Usage
|
| 45 |
+
|
| 46 |
+
This module is already used as default by Fastify.
|
| 47 |
+
If you need to provide your server instance with a different version, refer to [the Fastify docs](https://fastify.dev/docs/latest/Reference/Server/#schemacontroller).
|
| 48 |
+
|
| 49 |
+
### Customize the `ajv-formats` plugin
|
| 50 |
+
|
| 51 |
+
The `format` keyword is not part of the official `ajv` module since v7. To use it, you need to install the `ajv-formats` module and this module
|
| 52 |
+
does it for you with the default configuration.
|
| 53 |
+
|
| 54 |
+
If you need to configure the `ajv-formats` plugin you can do it using the standard Fastify configuration:
|
| 55 |
+
|
| 56 |
+
```js
|
| 57 |
+
const app = fastify({
|
| 58 |
+
ajv: {
|
| 59 |
+
plugins: [[require('ajv-formats'), { mode: 'fast' }]]
|
| 60 |
+
}
|
| 61 |
+
})
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
In this way, your setup will have precedence over the `@fastify/ajv-compiler` default configuration.
|
| 65 |
+
|
| 66 |
+
### Customize the `ajv` instance
|
| 67 |
+
|
| 68 |
+
If you need to customize the `ajv` instance and take full control of its configuration, you can do it by
|
| 69 |
+
using the `onCreate` option in the Fastify configuration that accepts a synchronous function that receives the `ajv` instance:
|
| 70 |
+
|
| 71 |
+
```js
|
| 72 |
+
const app = fastify({
|
| 73 |
+
ajv: {
|
| 74 |
+
onCreate: (ajv) => {
|
| 75 |
+
// Modify the ajv instance as you need.
|
| 76 |
+
ajv.addFormat('myFormat', (data) => typeof data === 'string')
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
+
})
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
### Fastify with JTD
|
| 83 |
+
|
| 84 |
+
The [JSON Type Definition](https://jsontypedef.com/) feature is supported by AJV v8.x and you can benefit from it in your Fastify application.
|
| 85 |
+
|
| 86 |
+
With Fastify v3.20.x and higher, you can use the `@fastify/ajv-compiler` module to load JSON Type Definitions like so:
|
| 87 |
+
|
| 88 |
+
```js
|
| 89 |
+
const factory = require('@fastify/ajv-compiler')()
|
| 90 |
+
|
| 91 |
+
const app = fastify({
|
| 92 |
+
jsonShorthand: false,
|
| 93 |
+
ajv: {
|
| 94 |
+
customOptions: { }, // additional JTD options
|
| 95 |
+
mode: 'JTD'
|
| 96 |
+
},
|
| 97 |
+
schemaController: {
|
| 98 |
+
compilersFactory: {
|
| 99 |
+
buildValidator: factory
|
| 100 |
+
}
|
| 101 |
+
}
|
| 102 |
+
})
|
| 103 |
+
```
|
| 104 |
+
|
| 105 |
+
The default AJV JTD options are the same as [Fastify's default options](#AJV-Configuration).
|
| 106 |
+
|
| 107 |
+
#### Fastify with JTD and serialization
|
| 108 |
+
|
| 109 |
+
You can use JTD Schemas to serialize your response object too:
|
| 110 |
+
|
| 111 |
+
```js
|
| 112 |
+
const factoryValidator = require('@fastify/ajv-compiler')()
|
| 113 |
+
const factorySerializer = require('@fastify/ajv-compiler')({ jtdSerializer: true })
|
| 114 |
+
|
| 115 |
+
const app = fastify({
|
| 116 |
+
jsonShorthand: false,
|
| 117 |
+
ajv: {
|
| 118 |
+
customOptions: { }, // additional JTD options
|
| 119 |
+
mode: 'JTD'
|
| 120 |
+
},
|
| 121 |
+
schemaController: {
|
| 122 |
+
compilersFactory: {
|
| 123 |
+
buildValidator: factoryValidator,
|
| 124 |
+
buildSerializer: factorySerializer
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
})
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
### AJV Standalone
|
| 132 |
+
|
| 133 |
+
AJV v8 introduced a [standalone feature](https://ajv.js.org/standalone.html) that lets you pre-compile your schemas and use them in your application for a faster startup.
|
| 134 |
+
|
| 135 |
+
To use this feature, you must be aware of the following:
|
| 136 |
+
|
| 137 |
+
1. You must generate and save the application's compiled schemas.
|
| 138 |
+
2. Read the compiled schemas from the file and provide them back to your Fastify application.
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
#### Generate and save the compiled schemas
|
| 142 |
+
|
| 143 |
+
Fastify helps you to generate the validation schemas functions and it is your choice to save them where you want.
|
| 144 |
+
To accomplish this, you must use a new compiler: `StandaloneValidator`.
|
| 145 |
+
|
| 146 |
+
You must provide 2 parameters to this compiler:
|
| 147 |
+
|
| 148 |
+
- `readMode: false`: a boolean to indicate that you want to generate the schemas functions string.
|
| 149 |
+
- `storeFunction`" a sync function that must store the source code of the schemas functions. You may provide an async function too, but you must manage errors.
|
| 150 |
+
|
| 151 |
+
When `readMode: false`, **the compiler is meant to be used in development ONLY**.
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
```js
|
| 155 |
+
const { StandaloneValidator } = require('@fastify/ajv-compiler')
|
| 156 |
+
const factory = StandaloneValidator({
|
| 157 |
+
readMode: false,
|
| 158 |
+
storeFunction (routeOpts, schemaValidationCode) {
|
| 159 |
+
// routeOpts is like: { schema, method, url, httpPart }
|
| 160 |
+
// schemaValidationCode is a string source code that is the compiled schema function
|
| 161 |
+
const fileName = generateFileName(routeOpts)
|
| 162 |
+
fs.writeFileSync(path.join(__dirname, fileName), schemaValidationCode)
|
| 163 |
+
}
|
| 164 |
+
})
|
| 165 |
+
|
| 166 |
+
const app = fastify({
|
| 167 |
+
jsonShorthand: false,
|
| 168 |
+
schemaController: {
|
| 169 |
+
compilersFactory: {
|
| 170 |
+
buildValidator: factory
|
| 171 |
+
}
|
| 172 |
+
}
|
| 173 |
+
})
|
| 174 |
+
|
| 175 |
+
// ... add all your routes with schemas ...
|
| 176 |
+
|
| 177 |
+
app.ready().then(() => {
|
| 178 |
+
// at this stage all your schemas are compiled and stored in the file system
|
| 179 |
+
// now it is important to turn off the readMode
|
| 180 |
+
})
|
| 181 |
+
```
|
| 182 |
+
|
| 183 |
+
#### Read the compiled schemas functions
|
| 184 |
+
|
| 185 |
+
At this stage, you should have a file for every route's schema.
|
| 186 |
+
To use them, you must use the `StandaloneValidator` with the parameters:
|
| 187 |
+
|
| 188 |
+
- `readMode: true`: a boolean to indicate that you want to read and use the schemas functions string.
|
| 189 |
+
- `restoreFunction`" a sync function that must return a function to validate the route.
|
| 190 |
+
|
| 191 |
+
Important keep away before you continue reading the documentation:
|
| 192 |
+
|
| 193 |
+
- when you use the `readMode: true`, the application schemas are not compiled (they are ignored). So, if you change your schemas, you must recompile them!
|
| 194 |
+
- as you can see, you must relate the route's schema to the file name using the `routeOpts` object. You may use the `routeOpts.schema.$id` field to do so, it is up to you to define a unique schema identifier.
|
| 195 |
+
|
| 196 |
+
```js
|
| 197 |
+
const { StandaloneValidator } = require('@fastify/ajv-compiler')
|
| 198 |
+
const factory = StandaloneValidator({
|
| 199 |
+
readMode: true,
|
| 200 |
+
restoreFunction (routeOpts) {
|
| 201 |
+
// routeOpts is like: { schema, method, url, httpPart }
|
| 202 |
+
const fileName = generateFileName(routeOpts)
|
| 203 |
+
return require(path.join(__dirname, fileName))
|
| 204 |
+
}
|
| 205 |
+
})
|
| 206 |
+
|
| 207 |
+
const app = fastify({
|
| 208 |
+
jsonShorthand: false,
|
| 209 |
+
schemaController: {
|
| 210 |
+
compilersFactory: {
|
| 211 |
+
buildValidator: factory
|
| 212 |
+
}
|
| 213 |
+
}
|
| 214 |
+
})
|
| 215 |
+
|
| 216 |
+
// ... add all your routes with schemas as before...
|
| 217 |
+
|
| 218 |
+
app.listen({ port: 3000 })
|
| 219 |
+
```
|
| 220 |
+
|
| 221 |
+
### How it works
|
| 222 |
+
|
| 223 |
+
This module provides a factory function to produce [Validator Compilers](https://fastify.dev/docs/latest/Reference/Server/#validatorcompiler) functions.
|
| 224 |
+
|
| 225 |
+
The Fastify factory function is just one per server instance and it is called for every encapsulated context created by the application through the `fastify.register()` call.
|
| 226 |
+
|
| 227 |
+
Every Validator Compiler produced has a dedicated AJV instance, so this factory will try to produce as less as possible AJV instances to reduce the memory footprint and the startup time.
|
| 228 |
+
|
| 229 |
+
The variables involved to choose if a Validator Compiler can be reused are:
|
| 230 |
+
|
| 231 |
+
- the AJV configuration: it is [one per server](https://fastify.dev/docs/latest/Reference/Server/#ajv)
|
| 232 |
+
- the external JSON schemas: once a new schema is added to a fastify's context, calling `fastify.addSchema()`, it will cause a new AJV initialization
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
## License
|
| 236 |
+
|
| 237 |
+
Licensed under [MIT](./LICENSE).
|
services/slides/node_modules/@fastify/ajv-compiler/benchmark/small-object.mjs
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import cronometro from 'cronometro'
|
| 2 |
+
|
| 3 |
+
import fjs from 'fast-json-stringify'
|
| 4 |
+
import AjvCompiler from '../index.js'
|
| 5 |
+
|
| 6 |
+
const fjsSerialize = buildFJSSerializerFunction({
|
| 7 |
+
type: 'object',
|
| 8 |
+
properties: {
|
| 9 |
+
hello: { type: 'string' },
|
| 10 |
+
name: { type: 'string' }
|
| 11 |
+
}
|
| 12 |
+
})
|
| 13 |
+
const ajvSerialize = buildAJVSerializerFunction({
|
| 14 |
+
properties: {
|
| 15 |
+
hello: { type: 'string' },
|
| 16 |
+
name: { type: 'string' }
|
| 17 |
+
}
|
| 18 |
+
})
|
| 19 |
+
|
| 20 |
+
await cronometro({
|
| 21 |
+
'fast-json-stringify': function () {
|
| 22 |
+
fjsSerialize({ hello: 'Ciao', name: 'Manuel' })
|
| 23 |
+
},
|
| 24 |
+
'ajv serializer': function () {
|
| 25 |
+
ajvSerialize({ hello: 'Ciao', name: 'Manuel' })
|
| 26 |
+
}
|
| 27 |
+
})
|
| 28 |
+
|
| 29 |
+
function buildFJSSerializerFunction (schema) {
|
| 30 |
+
return fjs(schema)
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
function buildAJVSerializerFunction (schema) {
|
| 34 |
+
const factory = AjvCompiler({ jtdSerializer: true })
|
| 35 |
+
const compiler = factory({}, { customOptions: {} })
|
| 36 |
+
return compiler({ schema })
|
| 37 |
+
}
|
services/slides/node_modules/@fastify/ajv-compiler/eslint.config.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
module.exports = require('neostandard')({
|
| 4 |
+
ignores: require('neostandard').resolveIgnoresFromGitignore(),
|
| 5 |
+
ts: true
|
| 6 |
+
})
|
services/slides/node_modules/@fastify/ajv-compiler/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const AjvReference = Symbol.for('fastify.ajv-compiler.reference')
|
| 4 |
+
const ValidatorCompiler = require('./lib/validator-compiler')
|
| 5 |
+
const SerializerCompiler = require('./lib/serializer-compiler')
|
| 6 |
+
|
| 7 |
+
function AjvCompiler (opts) {
|
| 8 |
+
const validatorPool = new Map()
|
| 9 |
+
const serializerPool = new Map()
|
| 10 |
+
|
| 11 |
+
if (opts && opts.jtdSerializer === true) {
|
| 12 |
+
return function buildSerializerFromPool (externalSchemas, serializerOpts) {
|
| 13 |
+
const uniqueAjvKey = getPoolKey({}, serializerOpts)
|
| 14 |
+
if (serializerPool.has(uniqueAjvKey)) {
|
| 15 |
+
return serializerPool.get(uniqueAjvKey)
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
const compiler = new SerializerCompiler(externalSchemas, serializerOpts)
|
| 19 |
+
const ret = compiler.buildSerializerFunction.bind(compiler)
|
| 20 |
+
serializerPool.set(uniqueAjvKey, ret)
|
| 21 |
+
|
| 22 |
+
return ret
|
| 23 |
+
}
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
return function buildCompilerFromPool (externalSchemas, options) {
|
| 27 |
+
const uniqueAjvKey = getPoolKey(externalSchemas, options.customOptions)
|
| 28 |
+
if (validatorPool.has(uniqueAjvKey)) {
|
| 29 |
+
return validatorPool.get(uniqueAjvKey)
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
const compiler = new ValidatorCompiler(externalSchemas, options)
|
| 33 |
+
const ret = compiler.buildValidatorFunction.bind(compiler)
|
| 34 |
+
validatorPool.set(uniqueAjvKey, ret)
|
| 35 |
+
|
| 36 |
+
if (options.customOptions.code !== undefined) {
|
| 37 |
+
ret[AjvReference] = compiler
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
return ret
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
function getPoolKey (externalSchemas, options) {
|
| 45 |
+
const externals = JSON.stringify(externalSchemas)
|
| 46 |
+
const ajvConfig = JSON.stringify(options)
|
| 47 |
+
return `${externals}${ajvConfig}`
|
| 48 |
+
}
|
| 49 |
+
module.exports = AjvCompiler
|
| 50 |
+
module.exports.default = AjvCompiler
|
| 51 |
+
module.exports.AjvCompiler = AjvCompiler
|
| 52 |
+
module.exports.AjvReference = AjvReference
|
| 53 |
+
module.exports.StandaloneValidator = require('./standalone')
|
services/slides/node_modules/@fastify/ajv-compiler/lib/default-ajv-options.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const fastUri = require('fast-uri')
|
| 4 |
+
|
| 5 |
+
module.exports = Object.freeze({
|
| 6 |
+
coerceTypes: 'array',
|
| 7 |
+
useDefaults: true,
|
| 8 |
+
removeAdditional: true,
|
| 9 |
+
uriResolver: fastUri,
|
| 10 |
+
addUsedSchema: false,
|
| 11 |
+
// Explicitly set allErrors to `false`.
|
| 12 |
+
// When set to `true`, a DoS attack is possible.
|
| 13 |
+
allErrors: false
|
| 14 |
+
})
|
services/slides/node_modules/@fastify/ajv-compiler/lib/serializer-compiler.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const AjvJTD = require('ajv/dist/jtd')
|
| 4 |
+
|
| 5 |
+
const defaultAjvOptions = require('./default-ajv-options')
|
| 6 |
+
|
| 7 |
+
class SerializerCompiler {
|
| 8 |
+
constructor (_externalSchemas, options) {
|
| 9 |
+
this.ajv = new AjvJTD(Object.assign({}, defaultAjvOptions, options))
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* https://ajv.js.org/json-type-definition.html#ref-form
|
| 13 |
+
* Unlike JSON Schema, JTD does not allow to reference:
|
| 14 |
+
* - any schema fragment other than root level definitions member
|
| 15 |
+
* - root of the schema - there is another way to define a self-recursive schema (see Example 2)
|
| 16 |
+
* - another schema file (but you can still combine schemas from multiple files using JavaScript).
|
| 17 |
+
*
|
| 18 |
+
* So we ignore the externalSchemas parameter.
|
| 19 |
+
*/
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
buildSerializerFunction ({ schema/*, method, url, httpStatus */ }) {
|
| 23 |
+
return this.ajv.compileSerializer(schema)
|
| 24 |
+
}
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
module.exports = SerializerCompiler
|
services/slides/node_modules/@fastify/ajv-compiler/lib/validator-compiler.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const Ajv = require('ajv').default
|
| 4 |
+
const AjvJTD = require('ajv/dist/jtd')
|
| 5 |
+
|
| 6 |
+
const defaultAjvOptions = require('./default-ajv-options')
|
| 7 |
+
|
| 8 |
+
class ValidatorCompiler {
|
| 9 |
+
constructor (externalSchemas, options) {
|
| 10 |
+
// This instance of Ajv is private
|
| 11 |
+
// it should not be customized or used
|
| 12 |
+
if (options.mode === 'JTD') {
|
| 13 |
+
this.ajv = new AjvJTD(Object.assign({}, defaultAjvOptions, options.customOptions))
|
| 14 |
+
} else {
|
| 15 |
+
this.ajv = new Ajv(Object.assign({}, defaultAjvOptions, options.customOptions))
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
let addFormatPlugin = true
|
| 19 |
+
if (options.plugins && options.plugins.length > 0) {
|
| 20 |
+
for (const plugin of options.plugins) {
|
| 21 |
+
if (Array.isArray(plugin)) {
|
| 22 |
+
addFormatPlugin = addFormatPlugin && plugin[0].name !== 'formatsPlugin'
|
| 23 |
+
plugin[0](this.ajv, plugin[1])
|
| 24 |
+
} else {
|
| 25 |
+
addFormatPlugin = addFormatPlugin && plugin.name !== 'formatsPlugin'
|
| 26 |
+
plugin(this.ajv)
|
| 27 |
+
}
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
if (addFormatPlugin) {
|
| 32 |
+
require('ajv-formats')(this.ajv)
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
options.onCreate?.(this.ajv)
|
| 36 |
+
|
| 37 |
+
const sourceSchemas = Object.values(externalSchemas)
|
| 38 |
+
for (const extSchema of sourceSchemas) {
|
| 39 |
+
this.ajv.addSchema(extSchema)
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
buildValidatorFunction ({ schema/*, method, url, httpPart */ }) {
|
| 44 |
+
// Ajv does not support compiling two schemas with the same
|
| 45 |
+
// id inside the same instance. Therefore if we have already
|
| 46 |
+
// compiled the schema with the given id, we just return it.
|
| 47 |
+
if (schema.$id) {
|
| 48 |
+
const stored = this.ajv.getSchema(schema.$id)
|
| 49 |
+
if (stored) {
|
| 50 |
+
return stored
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
return this.ajv.compile(schema)
|
| 55 |
+
}
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
module.exports = ValidatorCompiler
|
services/slides/node_modules/@fastify/ajv-compiler/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "@fastify/ajv-compiler",
|
| 3 |
+
"version": "4.0.5",
|
| 4 |
+
"description": "Build and manage the AJV instances for the fastify framework",
|
| 5 |
+
"main": "index.js",
|
| 6 |
+
"type": "commonjs",
|
| 7 |
+
"types": "types/index.d.ts",
|
| 8 |
+
"directories": {
|
| 9 |
+
"test": "test"
|
| 10 |
+
},
|
| 11 |
+
"scripts": {
|
| 12 |
+
"lint": "eslint",
|
| 13 |
+
"lint:fix": "eslint --fix",
|
| 14 |
+
"unit": "c8 --100 node --test",
|
| 15 |
+
"test": "npm run unit && npm run test:typescript",
|
| 16 |
+
"test:typescript": "tsd",
|
| 17 |
+
"ajv:compile": "ajv compile -s test/source.json -o test/validate_schema.js"
|
| 18 |
+
},
|
| 19 |
+
"repository": {
|
| 20 |
+
"type": "git",
|
| 21 |
+
"url": "git+https://github.com/fastify/ajv-compiler.git"
|
| 22 |
+
},
|
| 23 |
+
"keywords": [
|
| 24 |
+
"ajv",
|
| 25 |
+
"validator",
|
| 26 |
+
"schema",
|
| 27 |
+
"compiler",
|
| 28 |
+
"fastify"
|
| 29 |
+
],
|
| 30 |
+
"author": "Manuel Spigolon <behemoth89@gmail.com> (https://github.com/Eomm)",
|
| 31 |
+
"contributors": [
|
| 32 |
+
{
|
| 33 |
+
"name": "Matteo Collina",
|
| 34 |
+
"email": "hello@matteocollina.com"
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"name": "Aras Abbasi",
|
| 38 |
+
"email": "aras.abbasi@gmail.com"
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"name": "James Sumners",
|
| 42 |
+
"url": "https://james.sumners.info"
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
"name": "Frazer Smith",
|
| 46 |
+
"email": "frazer.dev@icloud.com",
|
| 47 |
+
"url": "https://github.com/fdawgs"
|
| 48 |
+
}
|
| 49 |
+
],
|
| 50 |
+
"license": "MIT",
|
| 51 |
+
"bugs": {
|
| 52 |
+
"url": "https://github.com/fastify/ajv-compiler/issues"
|
| 53 |
+
},
|
| 54 |
+
"homepage": "https://github.com/fastify/ajv-compiler#readme",
|
| 55 |
+
"funding": [
|
| 56 |
+
{
|
| 57 |
+
"type": "github",
|
| 58 |
+
"url": "https://github.com/sponsors/fastify"
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"type": "opencollective",
|
| 62 |
+
"url": "https://opencollective.com/fastify"
|
| 63 |
+
}
|
| 64 |
+
],
|
| 65 |
+
"devDependencies": {
|
| 66 |
+
"ajv-cli": "^5.0.0",
|
| 67 |
+
"ajv-errors": "^3.0.0",
|
| 68 |
+
"ajv-i18n": "^4.2.0",
|
| 69 |
+
"ajv-merge-patch": "^5.0.1",
|
| 70 |
+
"c8": "^10.1.3",
|
| 71 |
+
"cronometro": "^5.3.0",
|
| 72 |
+
"eslint": "^9.17.0",
|
| 73 |
+
"fastify": "^5.0.0",
|
| 74 |
+
"neostandard": "^0.12.0",
|
| 75 |
+
"require-from-string": "^2.0.2",
|
| 76 |
+
"sanitize-filename": "^1.6.3",
|
| 77 |
+
"tsd": "^0.33.0"
|
| 78 |
+
},
|
| 79 |
+
"dependencies": {
|
| 80 |
+
"ajv": "^8.12.0",
|
| 81 |
+
"ajv-formats": "^3.0.1",
|
| 82 |
+
"fast-uri": "^3.0.0"
|
| 83 |
+
}
|
| 84 |
+
}
|
services/slides/node_modules/@fastify/ajv-compiler/standalone.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const ValidatorSelector = require('./index')
|
| 4 |
+
const standaloneCode = require('ajv/dist/standalone').default
|
| 5 |
+
|
| 6 |
+
function StandaloneValidator (options = { readMode: true }) {
|
| 7 |
+
if (options.readMode === true && !options.restoreFunction) {
|
| 8 |
+
throw new Error('You must provide a restoreFunction options when readMode ON')
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
if (options.readMode !== true && !options.storeFunction) {
|
| 12 |
+
throw new Error('You must provide a storeFunction options when readMode OFF')
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
if (options.readMode === true) {
|
| 16 |
+
// READ MODE: it behalf only in the restore function provided by the user
|
| 17 |
+
return function wrapper () {
|
| 18 |
+
return function (opts) {
|
| 19 |
+
return options.restoreFunction(opts)
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
// WRITE MODE: it behalf on the default ValidatorSelector, wrapping the API to run the Ajv Standalone code generation
|
| 25 |
+
const factory = ValidatorSelector()
|
| 26 |
+
return function wrapper (externalSchemas, ajvOptions = {}) {
|
| 27 |
+
if (!ajvOptions.customOptions || !ajvOptions.customOptions.code) {
|
| 28 |
+
// to generate the validation source code, these options are mandatory
|
| 29 |
+
ajvOptions.customOptions = Object.assign({}, ajvOptions.customOptions, { code: { source: true } })
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
const compiler = factory(externalSchemas, ajvOptions)
|
| 33 |
+
return function (opts) { // { schema/*, method, url, httpPart */ }
|
| 34 |
+
const validationFunc = compiler(opts)
|
| 35 |
+
|
| 36 |
+
const schemaValidationCode = standaloneCode(compiler[ValidatorSelector.AjvReference].ajv, validationFunc)
|
| 37 |
+
options.storeFunction(opts, schemaValidationCode)
|
| 38 |
+
|
| 39 |
+
return validationFunc
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
module.exports = StandaloneValidator
|
services/slides/node_modules/@fastify/ajv-compiler/test/.gitkeep
ADDED
|
File without changes
|
services/slides/node_modules/@fastify/ajv-compiler/test/duplicated-id-compile.test.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const { test } = require('node:test')
|
| 4 |
+
const AjvCompiler = require('../index')
|
| 5 |
+
|
| 6 |
+
const postSchema = Object.freeze({
|
| 7 |
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
| 8 |
+
type: 'object',
|
| 9 |
+
$id: 'http://mydomain.com/user',
|
| 10 |
+
title: 'User schema',
|
| 11 |
+
description: 'Contains all user fields',
|
| 12 |
+
properties: {
|
| 13 |
+
username: { type: 'string', minLength: 4 },
|
| 14 |
+
firstName: { type: 'string', minLength: 1 },
|
| 15 |
+
lastName: { type: 'string', minLength: 1 },
|
| 16 |
+
email: { type: 'string' },
|
| 17 |
+
password: { type: 'string', minLength: 6 },
|
| 18 |
+
bio: { type: 'string' }
|
| 19 |
+
},
|
| 20 |
+
required: ['username', 'firstName', 'lastName', 'email', 'bio', 'password']
|
| 21 |
+
})
|
| 22 |
+
|
| 23 |
+
const patchSchema = Object.freeze({
|
| 24 |
+
$schema: 'http://json-schema.org/draft-07/schema#',
|
| 25 |
+
type: 'object',
|
| 26 |
+
$id: 'http://mydomain.com/user',
|
| 27 |
+
title: 'User schema',
|
| 28 |
+
description: 'Contains all user fields',
|
| 29 |
+
properties: {
|
| 30 |
+
firstName: { type: 'string', minLength: 1 },
|
| 31 |
+
lastName: { type: 'string', minLength: 1 },
|
| 32 |
+
bio: { type: 'string' }
|
| 33 |
+
}
|
| 34 |
+
})
|
| 35 |
+
|
| 36 |
+
const fastifyAjvOptionsDefault = Object.freeze({
|
| 37 |
+
customOptions: {}
|
| 38 |
+
})
|
| 39 |
+
|
| 40 |
+
test('must not store schema on compile', t => {
|
| 41 |
+
t.plan(5)
|
| 42 |
+
const factory = AjvCompiler()
|
| 43 |
+
const compiler = factory({}, fastifyAjvOptionsDefault)
|
| 44 |
+
const postFn = compiler({ schema: postSchema })
|
| 45 |
+
const patchFn = compiler({ schema: patchSchema })
|
| 46 |
+
|
| 47 |
+
const resultForPost = postFn({})
|
| 48 |
+
t.assert.deepStrictEqual(resultForPost, false)
|
| 49 |
+
t.assert.deepStrictEqual(postFn.errors[0].keyword, 'required')
|
| 50 |
+
t.assert.deepStrictEqual(postFn.errors[0].message, "must have required property 'username'")
|
| 51 |
+
|
| 52 |
+
const resultForPatch = patchFn({})
|
| 53 |
+
t.assert.ok(resultForPatch)
|
| 54 |
+
t.assert.ok(!patchFn.errors)
|
| 55 |
+
})
|
services/slides/node_modules/@fastify/ajv-compiler/test/index.test.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const { test } = require('node:test')
|
| 4 |
+
const fastify = require('fastify')
|
| 5 |
+
const AjvCompiler = require('../index')
|
| 6 |
+
|
| 7 |
+
const sym = Symbol.for('fastify.ajv-compiler.reference')
|
| 8 |
+
|
| 9 |
+
const sampleSchema = Object.freeze({
|
| 10 |
+
$id: 'example1',
|
| 11 |
+
type: 'object',
|
| 12 |
+
properties: {
|
| 13 |
+
name: { type: 'string' }
|
| 14 |
+
}
|
| 15 |
+
})
|
| 16 |
+
|
| 17 |
+
const externalSchemas1 = Object.freeze({})
|
| 18 |
+
const externalSchemas2 = Object.freeze({
|
| 19 |
+
foo: {
|
| 20 |
+
$id: 'foo',
|
| 21 |
+
type: 'object',
|
| 22 |
+
properties: {
|
| 23 |
+
name: { type: 'string' }
|
| 24 |
+
}
|
| 25 |
+
}
|
| 26 |
+
})
|
| 27 |
+
|
| 28 |
+
const fastifyAjvOptionsDefault = Object.freeze({
|
| 29 |
+
customOptions: {}
|
| 30 |
+
})
|
| 31 |
+
|
| 32 |
+
const fastifyJtdDefault = Object.freeze({
|
| 33 |
+
customOptions: { },
|
| 34 |
+
mode: 'JTD'
|
| 35 |
+
})
|
| 36 |
+
|
| 37 |
+
const fastifyAjvOptionsCustom = Object.freeze({
|
| 38 |
+
customOptions: {
|
| 39 |
+
allErrors: true,
|
| 40 |
+
removeAdditional: false
|
| 41 |
+
},
|
| 42 |
+
plugins: [
|
| 43 |
+
require('ajv-formats'),
|
| 44 |
+
[require('ajv-errors'), { singleError: false }]
|
| 45 |
+
]
|
| 46 |
+
})
|
| 47 |
+
|
| 48 |
+
test('basic usage', t => {
|
| 49 |
+
t.plan(1)
|
| 50 |
+
const factory = AjvCompiler()
|
| 51 |
+
const compiler = factory(externalSchemas1, fastifyAjvOptionsDefault)
|
| 52 |
+
const validatorFunc = compiler({ schema: sampleSchema })
|
| 53 |
+
const result = validatorFunc({ name: 'hello' })
|
| 54 |
+
t.assert.deepStrictEqual(result, true)
|
| 55 |
+
})
|
| 56 |
+
|
| 57 |
+
test('array coercion', t => {
|
| 58 |
+
t.plan(2)
|
| 59 |
+
const factory = AjvCompiler()
|
| 60 |
+
const compiler = factory(externalSchemas1, fastifyAjvOptionsDefault)
|
| 61 |
+
|
| 62 |
+
const arraySchema = {
|
| 63 |
+
$id: 'example1',
|
| 64 |
+
type: 'object',
|
| 65 |
+
properties: {
|
| 66 |
+
name: { type: 'array', items: { type: 'string' } }
|
| 67 |
+
}
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
const validatorFunc = compiler({ schema: arraySchema })
|
| 71 |
+
|
| 72 |
+
const inputObj = { name: 'hello' }
|
| 73 |
+
t.assert.deepStrictEqual(validatorFunc(inputObj), true)
|
| 74 |
+
t.assert.deepStrictEqual(inputObj, { name: ['hello'] }, 'the name property should be coerced to an array')
|
| 75 |
+
})
|
| 76 |
+
|
| 77 |
+
test('nullable default', t => {
|
| 78 |
+
t.plan(2)
|
| 79 |
+
const factory = AjvCompiler()
|
| 80 |
+
const compiler = factory({}, fastifyAjvOptionsDefault)
|
| 81 |
+
const validatorFunc = compiler({
|
| 82 |
+
schema: {
|
| 83 |
+
type: 'object',
|
| 84 |
+
properties: {
|
| 85 |
+
nullable: { type: 'string', nullable: true },
|
| 86 |
+
notNullable: { type: 'string' }
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
+
})
|
| 90 |
+
const input = { nullable: null, notNullable: null }
|
| 91 |
+
const result = validatorFunc(input)
|
| 92 |
+
t.assert.deepStrictEqual(result, true)
|
| 93 |
+
t.assert.deepStrictEqual(input, { nullable: null, notNullable: '' }, 'the notNullable field has been coerced')
|
| 94 |
+
})
|
| 95 |
+
|
| 96 |
+
test('plugin loading', t => {
|
| 97 |
+
t.plan(3)
|
| 98 |
+
const factory = AjvCompiler()
|
| 99 |
+
const compiler = factory(externalSchemas1, fastifyAjvOptionsCustom)
|
| 100 |
+
const validatorFunc = compiler({
|
| 101 |
+
schema: {
|
| 102 |
+
type: 'object',
|
| 103 |
+
properties: {
|
| 104 |
+
q: {
|
| 105 |
+
type: 'string',
|
| 106 |
+
format: 'date',
|
| 107 |
+
formatMinimum: '2016-02-06',
|
| 108 |
+
formatExclusiveMaximum: '2016-12-27'
|
| 109 |
+
}
|
| 110 |
+
},
|
| 111 |
+
required: ['q'],
|
| 112 |
+
errorMessage: 'hello world'
|
| 113 |
+
}
|
| 114 |
+
})
|
| 115 |
+
const result = validatorFunc({ q: '2016-10-02' })
|
| 116 |
+
t.assert.deepStrictEqual(result, true)
|
| 117 |
+
|
| 118 |
+
const resultFail = validatorFunc({})
|
| 119 |
+
t.assert.deepStrictEqual(resultFail, false)
|
| 120 |
+
t.assert.deepStrictEqual(validatorFunc.errors[0].message, 'hello world')
|
| 121 |
+
})
|
| 122 |
+
|
| 123 |
+
test('optimization - cache ajv instance', t => {
|
| 124 |
+
t.plan(5)
|
| 125 |
+
const factory = AjvCompiler()
|
| 126 |
+
const compiler1 = factory(externalSchemas1, fastifyAjvOptionsDefault)
|
| 127 |
+
const compiler2 = factory(externalSchemas1, fastifyAjvOptionsDefault)
|
| 128 |
+
t.assert.deepStrictEqual(compiler1, compiler2, 'same instance')
|
| 129 |
+
t.assert.deepStrictEqual(compiler1, compiler2, 'same instance')
|
| 130 |
+
|
| 131 |
+
const compiler3 = factory(externalSchemas2, fastifyAjvOptionsDefault)
|
| 132 |
+
t.assert.notEqual(compiler3, compiler1, 'new ajv instance when externa schema change')
|
| 133 |
+
|
| 134 |
+
const compiler4 = factory(externalSchemas1, fastifyAjvOptionsCustom)
|
| 135 |
+
t.assert.notEqual(compiler4, compiler1, 'new ajv instance when externa schema change')
|
| 136 |
+
t.assert.notEqual(compiler4, compiler3, 'new ajv instance when externa schema change')
|
| 137 |
+
})
|
| 138 |
+
|
| 139 |
+
test('the onCreate callback can enhance the ajv instance', t => {
|
| 140 |
+
t.plan(2)
|
| 141 |
+
const factory = AjvCompiler()
|
| 142 |
+
|
| 143 |
+
const fastifyAjvCustomOptionsFormats = Object.freeze({
|
| 144 |
+
onCreate (ajv) {
|
| 145 |
+
for (const [formatName, format] of Object.entries(this.customOptions.formats)) {
|
| 146 |
+
ajv.addFormat(formatName, format)
|
| 147 |
+
}
|
| 148 |
+
},
|
| 149 |
+
customOptions: {
|
| 150 |
+
formats: {
|
| 151 |
+
date: /foo/
|
| 152 |
+
}
|
| 153 |
+
}
|
| 154 |
+
})
|
| 155 |
+
|
| 156 |
+
const compiler1 = factory(externalSchemas1, fastifyAjvCustomOptionsFormats)
|
| 157 |
+
const validatorFunc = compiler1({
|
| 158 |
+
schema: {
|
| 159 |
+
type: 'string',
|
| 160 |
+
format: 'date'
|
| 161 |
+
}
|
| 162 |
+
})
|
| 163 |
+
const result = validatorFunc('foo')
|
| 164 |
+
t.assert.deepStrictEqual(result, true)
|
| 165 |
+
|
| 166 |
+
const resultFail = validatorFunc('2016-10-02')
|
| 167 |
+
t.assert.deepStrictEqual(resultFail, false)
|
| 168 |
+
})
|
| 169 |
+
|
| 170 |
+
// https://github.com/fastify/fastify/pull/2969
|
| 171 |
+
test('compile same $id when in external schema', t => {
|
| 172 |
+
t.plan(3)
|
| 173 |
+
const factory = AjvCompiler()
|
| 174 |
+
|
| 175 |
+
const base = {
|
| 176 |
+
$id: 'urn:schema:base',
|
| 177 |
+
definitions: {
|
| 178 |
+
hello: { type: 'string' }
|
| 179 |
+
},
|
| 180 |
+
type: 'object',
|
| 181 |
+
properties: {
|
| 182 |
+
hello: { $ref: '#/definitions/hello' }
|
| 183 |
+
}
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
const refSchema = {
|
| 187 |
+
$id: 'urn:schema:ref',
|
| 188 |
+
type: 'object',
|
| 189 |
+
properties: {
|
| 190 |
+
hello: { $ref: 'urn:schema:base#/definitions/hello' }
|
| 191 |
+
}
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
const compiler = factory({
|
| 195 |
+
[base.$id]: base,
|
| 196 |
+
[refSchema.$id]: refSchema
|
| 197 |
+
|
| 198 |
+
}, fastifyAjvOptionsDefault)
|
| 199 |
+
|
| 200 |
+
t.assert.ok(!compiler[sym], 'the ajv reference do not exists if code is not activated')
|
| 201 |
+
|
| 202 |
+
const validatorFunc1 = compiler({
|
| 203 |
+
schema: {
|
| 204 |
+
$id: 'urn:schema:ref'
|
| 205 |
+
}
|
| 206 |
+
})
|
| 207 |
+
|
| 208 |
+
const validatorFunc2 = compiler({
|
| 209 |
+
schema: {
|
| 210 |
+
$id: 'urn:schema:ref'
|
| 211 |
+
}
|
| 212 |
+
})
|
| 213 |
+
|
| 214 |
+
t.assert.ok('the compile does not fail if the schema compiled is already in the external schemas')
|
| 215 |
+
t.assert.deepStrictEqual(validatorFunc1, validatorFunc2, 'the returned function is the same')
|
| 216 |
+
})
|
| 217 |
+
|
| 218 |
+
test('JTD MODE', async t => {
|
| 219 |
+
t.plan(2)
|
| 220 |
+
|
| 221 |
+
t.test('compile jtd schema', t => {
|
| 222 |
+
t.plan(4)
|
| 223 |
+
const factory = AjvCompiler()
|
| 224 |
+
|
| 225 |
+
const jtdSchema = {
|
| 226 |
+
discriminator: 'version',
|
| 227 |
+
mapping: {
|
| 228 |
+
1: {
|
| 229 |
+
properties: {
|
| 230 |
+
foo: { type: 'uint8' }
|
| 231 |
+
}
|
| 232 |
+
},
|
| 233 |
+
2: {
|
| 234 |
+
properties: {
|
| 235 |
+
foo: { type: 'string' }
|
| 236 |
+
}
|
| 237 |
+
}
|
| 238 |
+
}
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
const compiler = factory({}, fastifyJtdDefault)
|
| 242 |
+
const validatorFunc = compiler({ schema: jtdSchema })
|
| 243 |
+
t.assert.ok('generated validation function for JTD SCHEMA')
|
| 244 |
+
|
| 245 |
+
const result = validatorFunc({
|
| 246 |
+
version: '2',
|
| 247 |
+
foo: []
|
| 248 |
+
})
|
| 249 |
+
t.assert.ok(!result, 'failed validation')
|
| 250 |
+
t.assert.ok(validatorFunc.errors instanceof Array)
|
| 251 |
+
|
| 252 |
+
const success = validatorFunc({
|
| 253 |
+
version: '1',
|
| 254 |
+
foo: 42
|
| 255 |
+
})
|
| 256 |
+
t.assert.ok(success)
|
| 257 |
+
})
|
| 258 |
+
|
| 259 |
+
await t.test('fastify integration', async t => {
|
| 260 |
+
const factory = AjvCompiler()
|
| 261 |
+
|
| 262 |
+
const app = fastify({
|
| 263 |
+
jsonShorthand: false,
|
| 264 |
+
ajv: {
|
| 265 |
+
customOptions: { },
|
| 266 |
+
mode: 'JTD'
|
| 267 |
+
},
|
| 268 |
+
schemaController: {
|
| 269 |
+
compilersFactory: {
|
| 270 |
+
buildValidator: factory
|
| 271 |
+
}
|
| 272 |
+
}
|
| 273 |
+
})
|
| 274 |
+
|
| 275 |
+
app.post('/', {
|
| 276 |
+
schema: {
|
| 277 |
+
body: {
|
| 278 |
+
discriminator: 'version',
|
| 279 |
+
mapping: {
|
| 280 |
+
1: {
|
| 281 |
+
properties: {
|
| 282 |
+
foo: { type: 'uint8' }
|
| 283 |
+
}
|
| 284 |
+
},
|
| 285 |
+
2: {
|
| 286 |
+
properties: {
|
| 287 |
+
foo: { type: 'string' }
|
| 288 |
+
}
|
| 289 |
+
}
|
| 290 |
+
}
|
| 291 |
+
}
|
| 292 |
+
}
|
| 293 |
+
}, () => {})
|
| 294 |
+
|
| 295 |
+
const res = await app.inject({
|
| 296 |
+
url: '/',
|
| 297 |
+
method: 'POST',
|
| 298 |
+
payload: {
|
| 299 |
+
version: '1',
|
| 300 |
+
foo: 'this is not a number'
|
| 301 |
+
}
|
| 302 |
+
})
|
| 303 |
+
|
| 304 |
+
t.assert.deepStrictEqual(res.statusCode, 400)
|
| 305 |
+
t.assert.deepStrictEqual(res.json().message, 'body/foo must be uint8')
|
| 306 |
+
})
|
| 307 |
+
})
|
services/slides/node_modules/@fastify/ajv-compiler/test/plugins.test.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const { test } = require('node:test')
|
| 4 |
+
const fastify = require('fastify')
|
| 5 |
+
const AjvCompiler = require('../index')
|
| 6 |
+
|
| 7 |
+
const ajvFormats = require('ajv-formats')
|
| 8 |
+
const ajvErrors = require('ajv-errors')
|
| 9 |
+
const localize = require('ajv-i18n')
|
| 10 |
+
|
| 11 |
+
test('Format Baseline test', async (t) => {
|
| 12 |
+
const app = buildApplication({
|
| 13 |
+
customOptions: {
|
| 14 |
+
validateFormats: false
|
| 15 |
+
}
|
| 16 |
+
})
|
| 17 |
+
|
| 18 |
+
const res = await app.inject({
|
| 19 |
+
url: '/hello',
|
| 20 |
+
headers: {
|
| 21 |
+
'x-foo': 'hello',
|
| 22 |
+
'x-date': 'not a date',
|
| 23 |
+
'x-email': 'not an email'
|
| 24 |
+
},
|
| 25 |
+
query: {
|
| 26 |
+
foo: 'hello',
|
| 27 |
+
date: 'not a date',
|
| 28 |
+
email: 'not an email'
|
| 29 |
+
}
|
| 30 |
+
})
|
| 31 |
+
t.assert.deepStrictEqual(res.statusCode, 200, 'format validation does not apply as configured')
|
| 32 |
+
t.assert.deepStrictEqual(res.payload, 'hello')
|
| 33 |
+
})
|
| 34 |
+
|
| 35 |
+
test('Custom Format plugin loading test', async (t) => {
|
| 36 |
+
t.plan(3)
|
| 37 |
+
const app = buildApplication({
|
| 38 |
+
customOptions: {
|
| 39 |
+
validateFormats: true
|
| 40 |
+
},
|
| 41 |
+
plugins: [[ajvFormats, { mode: 'fast' }]]
|
| 42 |
+
})
|
| 43 |
+
|
| 44 |
+
const res = await app.inject('/hello')
|
| 45 |
+
t.assert.deepStrictEqual(res.statusCode, 400, 'format validation applies')
|
| 46 |
+
|
| 47 |
+
const res1 = await app.inject('/2ad0612c-7578-4b18-9a6f-579863f40e0b')
|
| 48 |
+
t.assert.deepStrictEqual(res1.statusCode, 400, 'format validation applies')
|
| 49 |
+
|
| 50 |
+
const res2 = await app.inject({
|
| 51 |
+
url: '/2ad0612c-7578-4b18-9a6f-579863f40e0b',
|
| 52 |
+
headers: {
|
| 53 |
+
'x-foo': 'hello',
|
| 54 |
+
'x-date': new Date().toISOString(),
|
| 55 |
+
'x-email': 'foo@bar.baz'
|
| 56 |
+
},
|
| 57 |
+
query: {
|
| 58 |
+
foo: 'hello',
|
| 59 |
+
date: new Date().toISOString(),
|
| 60 |
+
email: 'foo@bar.baz'
|
| 61 |
+
}
|
| 62 |
+
})
|
| 63 |
+
t.assert.deepStrictEqual(res2.statusCode, 200)
|
| 64 |
+
})
|
| 65 |
+
|
| 66 |
+
test('Format plugin set by default test', async (t) => {
|
| 67 |
+
t.plan(3)
|
| 68 |
+
const app = buildApplication({})
|
| 69 |
+
|
| 70 |
+
const res = await app.inject('/hello')
|
| 71 |
+
t.assert.deepStrictEqual(res.statusCode, 400, 'format validation applies')
|
| 72 |
+
|
| 73 |
+
const res1 = await app.inject('/2ad0612c-7578-4b18-9a6f-579863f40e0b')
|
| 74 |
+
t.assert.deepStrictEqual(res1.statusCode, 400, 'format validation applies')
|
| 75 |
+
|
| 76 |
+
const res2 = await app.inject({
|
| 77 |
+
url: '/2ad0612c-7578-4b18-9a6f-579863f40e0b',
|
| 78 |
+
headers: {
|
| 79 |
+
'x-foo': 'hello',
|
| 80 |
+
'x-date': new Date().toISOString(),
|
| 81 |
+
'x-email': 'foo@bar.baz'
|
| 82 |
+
},
|
| 83 |
+
query: {
|
| 84 |
+
foo: 'hello',
|
| 85 |
+
date: new Date().toISOString(),
|
| 86 |
+
email: 'foo@bar.baz'
|
| 87 |
+
}
|
| 88 |
+
})
|
| 89 |
+
t.assert.deepStrictEqual(res2.statusCode, 200)
|
| 90 |
+
})
|
| 91 |
+
|
| 92 |
+
test('Custom error messages', async (t) => {
|
| 93 |
+
t.plan(6)
|
| 94 |
+
|
| 95 |
+
const app = buildApplication({
|
| 96 |
+
customOptions: {
|
| 97 |
+
removeAdditional: false,
|
| 98 |
+
allErrors: true
|
| 99 |
+
},
|
| 100 |
+
plugins: [ajvFormats, ajvErrors]
|
| 101 |
+
})
|
| 102 |
+
|
| 103 |
+
const errorMessage = {
|
| 104 |
+
required: 'custom miss',
|
| 105 |
+
type: 'custom type', // will not replace internal "type" error for the property "foo"
|
| 106 |
+
_: 'custom type', // this prop will do it
|
| 107 |
+
additionalProperties: 'custom too many params'
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
app.post('/', {
|
| 111 |
+
handler: () => { t.assert.fail('dont call me') },
|
| 112 |
+
schema: {
|
| 113 |
+
body: {
|
| 114 |
+
type: 'object',
|
| 115 |
+
required: ['foo'],
|
| 116 |
+
properties: {
|
| 117 |
+
foo: { type: 'integer' }
|
| 118 |
+
},
|
| 119 |
+
additionalProperties: false,
|
| 120 |
+
errorMessage
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
+
})
|
| 124 |
+
|
| 125 |
+
const res = await app.inject({
|
| 126 |
+
url: '/',
|
| 127 |
+
method: 'post',
|
| 128 |
+
payload: {}
|
| 129 |
+
})
|
| 130 |
+
t.assert.deepStrictEqual(res.statusCode, 400)
|
| 131 |
+
t.assert.ok(res.json().message.includes(errorMessage.required))
|
| 132 |
+
|
| 133 |
+
const res1 = await app.inject({
|
| 134 |
+
url: '/',
|
| 135 |
+
method: 'post',
|
| 136 |
+
payload: { foo: 'not a number' }
|
| 137 |
+
})
|
| 138 |
+
t.assert.deepStrictEqual(res1.statusCode, 400)
|
| 139 |
+
t.assert.ok(res1.json().message.includes(errorMessage.type))
|
| 140 |
+
|
| 141 |
+
const res2 = await app.inject({
|
| 142 |
+
url: '/',
|
| 143 |
+
method: 'post',
|
| 144 |
+
payload: { foo: 3, bar: 'ops' }
|
| 145 |
+
})
|
| 146 |
+
|
| 147 |
+
t.assert.deepStrictEqual(res2.statusCode, 400)
|
| 148 |
+
t.assert.ok(res2.json().message.includes(errorMessage.additionalProperties))
|
| 149 |
+
})
|
| 150 |
+
|
| 151 |
+
test('Custom i18n error messages', async (t) => {
|
| 152 |
+
t.plan(2)
|
| 153 |
+
|
| 154 |
+
const app = buildApplication({
|
| 155 |
+
customOptions: {
|
| 156 |
+
allErrors: true,
|
| 157 |
+
messages: false
|
| 158 |
+
},
|
| 159 |
+
plugins: [ajvFormats]
|
| 160 |
+
})
|
| 161 |
+
|
| 162 |
+
app.post('/', {
|
| 163 |
+
handler: () => { t.assert.fail('dont call me') },
|
| 164 |
+
schema: {
|
| 165 |
+
body: {
|
| 166 |
+
type: 'object',
|
| 167 |
+
required: ['foo'],
|
| 168 |
+
properties: {
|
| 169 |
+
foo: { type: 'integer' }
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
+
}
|
| 173 |
+
})
|
| 174 |
+
|
| 175 |
+
app.setErrorHandler((error, request, reply) => {
|
| 176 |
+
t.assert.ok('Error handler executed')
|
| 177 |
+
if (error.validation) {
|
| 178 |
+
localize.ru(error.validation)
|
| 179 |
+
reply.status(400).send(error.validation)
|
| 180 |
+
return
|
| 181 |
+
}
|
| 182 |
+
t.assert.fail('not other errors')
|
| 183 |
+
})
|
| 184 |
+
|
| 185 |
+
const res = await app.inject({
|
| 186 |
+
method: 'POST',
|
| 187 |
+
url: '/',
|
| 188 |
+
payload: {
|
| 189 |
+
foo: 'string'
|
| 190 |
+
}
|
| 191 |
+
})
|
| 192 |
+
|
| 193 |
+
t.assert.deepStrictEqual(res.json()[0].message, 'должно быть integer')
|
| 194 |
+
})
|
| 195 |
+
|
| 196 |
+
function buildApplication (ajvOptions) {
|
| 197 |
+
const factory = AjvCompiler()
|
| 198 |
+
|
| 199 |
+
const app = fastify({
|
| 200 |
+
ajv: ajvOptions,
|
| 201 |
+
schemaController: {
|
| 202 |
+
compilersFactory: {
|
| 203 |
+
buildValidator: factory
|
| 204 |
+
}
|
| 205 |
+
}
|
| 206 |
+
})
|
| 207 |
+
|
| 208 |
+
app.get('/:id', {
|
| 209 |
+
schema: {
|
| 210 |
+
headers: {
|
| 211 |
+
type: 'object',
|
| 212 |
+
required: [
|
| 213 |
+
'x-foo',
|
| 214 |
+
'x-date',
|
| 215 |
+
'x-email'
|
| 216 |
+
],
|
| 217 |
+
properties: {
|
| 218 |
+
'x-foo': { type: 'string' },
|
| 219 |
+
'x-date': { type: 'string', format: 'date-time' },
|
| 220 |
+
'x-email': { type: 'string', format: 'email' }
|
| 221 |
+
}
|
| 222 |
+
},
|
| 223 |
+
query: {
|
| 224 |
+
type: 'object',
|
| 225 |
+
required: [
|
| 226 |
+
'foo',
|
| 227 |
+
'date',
|
| 228 |
+
'email'
|
| 229 |
+
],
|
| 230 |
+
properties: {
|
| 231 |
+
foo: { type: 'string' },
|
| 232 |
+
date: { type: 'string', format: 'date-time' },
|
| 233 |
+
email: { type: 'string', format: 'email' }
|
| 234 |
+
}
|
| 235 |
+
},
|
| 236 |
+
params: {
|
| 237 |
+
type: 'object',
|
| 238 |
+
properties: {
|
| 239 |
+
id: { type: 'string', format: 'uuid' }
|
| 240 |
+
}
|
| 241 |
+
}
|
| 242 |
+
}
|
| 243 |
+
}, async () => 'hello')
|
| 244 |
+
|
| 245 |
+
return app
|
| 246 |
+
}
|
services/slides/node_modules/@fastify/ajv-compiler/test/serialization.test.js
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const { test } = require('node:test')
|
| 4 |
+
const fastify = require('fastify')
|
| 5 |
+
const AjvCompiler = require('../index')
|
| 6 |
+
|
| 7 |
+
const jtdSchema = {
|
| 8 |
+
discriminator: 'version',
|
| 9 |
+
mapping: {
|
| 10 |
+
1: {
|
| 11 |
+
properties: {
|
| 12 |
+
foo: { type: 'uint8' }
|
| 13 |
+
}
|
| 14 |
+
},
|
| 15 |
+
2: {
|
| 16 |
+
properties: {
|
| 17 |
+
foo: { type: 'string' }
|
| 18 |
+
}
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
const externalSchemas1 = Object.freeze({})
|
| 24 |
+
const externalSchemas2 = Object.freeze({
|
| 25 |
+
foo: {
|
| 26 |
+
definitions: {
|
| 27 |
+
coordinates: {
|
| 28 |
+
properties: {
|
| 29 |
+
lat: { type: 'float32' },
|
| 30 |
+
lng: { type: 'float32' }
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
}
|
| 34 |
+
}
|
| 35 |
+
})
|
| 36 |
+
|
| 37 |
+
const fastifyAjvOptionsDefault = Object.freeze({
|
| 38 |
+
customOptions: {}
|
| 39 |
+
})
|
| 40 |
+
|
| 41 |
+
test('basic serializer usage', t => {
|
| 42 |
+
t.plan(4)
|
| 43 |
+
const factory = AjvCompiler({ jtdSerializer: true })
|
| 44 |
+
const compiler = factory(externalSchemas1, fastifyAjvOptionsDefault)
|
| 45 |
+
const serializeFunc = compiler({ schema: jtdSchema })
|
| 46 |
+
t.assert.deepStrictEqual(serializeFunc({ version: '1', foo: 42 }), '{"version":"1","foo":42}')
|
| 47 |
+
t.assert.deepStrictEqual(serializeFunc({ version: '2', foo: 'hello' }), '{"version":"2","foo":"hello"}')
|
| 48 |
+
t.assert.deepStrictEqual(serializeFunc({ version: '3', foo: 'hello' }), '{"version":"3"}')
|
| 49 |
+
t.assert.deepStrictEqual(serializeFunc({ version: '2', foo: ['not', 1, { string: 'string' }] }), '{"version":"2","foo":"not,1,[object Object]"}')
|
| 50 |
+
})
|
| 51 |
+
|
| 52 |
+
test('external schemas are ignored', t => {
|
| 53 |
+
t.plan(1)
|
| 54 |
+
const factory = AjvCompiler({ jtdSerializer: true })
|
| 55 |
+
const compiler = factory(externalSchemas2, fastifyAjvOptionsDefault)
|
| 56 |
+
const serializeFunc = compiler({
|
| 57 |
+
schema: {
|
| 58 |
+
definitions: {
|
| 59 |
+
coordinates: {
|
| 60 |
+
properties: {
|
| 61 |
+
lat: { type: 'float32' },
|
| 62 |
+
lng: { type: 'float32' }
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
},
|
| 66 |
+
properties: {
|
| 67 |
+
userLoc: { ref: 'coordinates' },
|
| 68 |
+
serverLoc: { ref: 'coordinates' }
|
| 69 |
+
}
|
| 70 |
+
}
|
| 71 |
+
})
|
| 72 |
+
t.assert.deepStrictEqual(serializeFunc(
|
| 73 |
+
{ userLoc: { lat: 50, lng: -90 }, serverLoc: { lat: -15, lng: 50 } }),
|
| 74 |
+
'{"userLoc":{"lat":50,"lng":-90},"serverLoc":{"lat":-15,"lng":50}}'
|
| 75 |
+
)
|
| 76 |
+
})
|
| 77 |
+
|
| 78 |
+
test('fastify integration within JTD serializer', async t => {
|
| 79 |
+
const factoryValidator = AjvCompiler()
|
| 80 |
+
const factorySerializer = AjvCompiler({ jtdSerializer: true })
|
| 81 |
+
|
| 82 |
+
const app = fastify({
|
| 83 |
+
jsonShorthand: false,
|
| 84 |
+
ajv: {
|
| 85 |
+
customOptions: { },
|
| 86 |
+
mode: 'JTD'
|
| 87 |
+
},
|
| 88 |
+
schemaController: {
|
| 89 |
+
compilersFactory: {
|
| 90 |
+
buildValidator: factoryValidator,
|
| 91 |
+
buildSerializer: factorySerializer
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
})
|
| 95 |
+
|
| 96 |
+
app.post('/', {
|
| 97 |
+
schema: {
|
| 98 |
+
body: jtdSchema,
|
| 99 |
+
response: {
|
| 100 |
+
200: {
|
| 101 |
+
properties: {
|
| 102 |
+
id: { type: 'string' },
|
| 103 |
+
createdAt: { type: 'timestamp' },
|
| 104 |
+
karma: { type: 'int32' },
|
| 105 |
+
isAdmin: { type: 'boolean' }
|
| 106 |
+
}
|
| 107 |
+
},
|
| 108 |
+
400: jtdSchema
|
| 109 |
+
}
|
| 110 |
+
}
|
| 111 |
+
}, async () => {
|
| 112 |
+
return {
|
| 113 |
+
id: '123',
|
| 114 |
+
createdAt: new Date('1999-01-31T23:00:00.000Z'),
|
| 115 |
+
karma: 42,
|
| 116 |
+
isAdmin: true,
|
| 117 |
+
remove: 'me'
|
| 118 |
+
}
|
| 119 |
+
})
|
| 120 |
+
|
| 121 |
+
{
|
| 122 |
+
const res = await app.inject({
|
| 123 |
+
url: '/',
|
| 124 |
+
method: 'POST',
|
| 125 |
+
payload: {
|
| 126 |
+
version: '1',
|
| 127 |
+
foo: 'not a number'
|
| 128 |
+
}
|
| 129 |
+
})
|
| 130 |
+
|
| 131 |
+
t.assert.deepStrictEqual(res.statusCode, 400)
|
| 132 |
+
t.assert.deepStrictEqual(res.json(), { version: 'undefined' })
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
{
|
| 136 |
+
const res = await app.inject({
|
| 137 |
+
url: '/',
|
| 138 |
+
method: 'POST',
|
| 139 |
+
payload: {
|
| 140 |
+
version: '1',
|
| 141 |
+
foo: 32
|
| 142 |
+
}
|
| 143 |
+
})
|
| 144 |
+
|
| 145 |
+
t.assert.deepStrictEqual(res.statusCode, 200)
|
| 146 |
+
t.assert.deepStrictEqual(res.json(), {
|
| 147 |
+
id: '123',
|
| 148 |
+
createdAt: '1999-01-31T23:00:00.000Z',
|
| 149 |
+
karma: 42,
|
| 150 |
+
isAdmin: true
|
| 151 |
+
})
|
| 152 |
+
}
|
| 153 |
+
})
|
| 154 |
+
|
| 155 |
+
test('fastify integration and cached serializer', async t => {
|
| 156 |
+
const factoryValidator = AjvCompiler()
|
| 157 |
+
const factorySerializer = AjvCompiler({ jtdSerializer: true })
|
| 158 |
+
|
| 159 |
+
const app = fastify({
|
| 160 |
+
jsonShorthand: false,
|
| 161 |
+
ajv: {
|
| 162 |
+
customOptions: { },
|
| 163 |
+
mode: 'JTD'
|
| 164 |
+
},
|
| 165 |
+
schemaController: {
|
| 166 |
+
compilersFactory: {
|
| 167 |
+
buildValidator: factoryValidator,
|
| 168 |
+
buildSerializer: factorySerializer
|
| 169 |
+
}
|
| 170 |
+
}
|
| 171 |
+
})
|
| 172 |
+
|
| 173 |
+
app.register(async function plugin (app, opts) {
|
| 174 |
+
app.post('/', {
|
| 175 |
+
schema: {
|
| 176 |
+
body: jtdSchema,
|
| 177 |
+
response: {
|
| 178 |
+
200: {
|
| 179 |
+
properties: {
|
| 180 |
+
id: { type: 'string' },
|
| 181 |
+
createdAt: { type: 'timestamp' },
|
| 182 |
+
karma: { type: 'int32' },
|
| 183 |
+
isAdmin: { type: 'boolean' }
|
| 184 |
+
}
|
| 185 |
+
},
|
| 186 |
+
400: jtdSchema
|
| 187 |
+
}
|
| 188 |
+
}
|
| 189 |
+
}, async () => {
|
| 190 |
+
return {
|
| 191 |
+
id: '123',
|
| 192 |
+
createdAt: new Date('1999-01-31T23:00:00.000Z'),
|
| 193 |
+
karma: 42,
|
| 194 |
+
isAdmin: true,
|
| 195 |
+
remove: 'me'
|
| 196 |
+
}
|
| 197 |
+
})
|
| 198 |
+
})
|
| 199 |
+
|
| 200 |
+
app.register(async function plugin (app, opts) {
|
| 201 |
+
app.post('/two', {
|
| 202 |
+
schema: {
|
| 203 |
+
body: jtdSchema,
|
| 204 |
+
response: {
|
| 205 |
+
400: jtdSchema
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
}, () => {})
|
| 209 |
+
})
|
| 210 |
+
|
| 211 |
+
{
|
| 212 |
+
const res = await app.inject({
|
| 213 |
+
url: '/',
|
| 214 |
+
method: 'POST',
|
| 215 |
+
payload: {
|
| 216 |
+
version: '1',
|
| 217 |
+
foo: 'not a number'
|
| 218 |
+
}
|
| 219 |
+
})
|
| 220 |
+
|
| 221 |
+
t.assert.deepStrictEqual(res.statusCode, 400)
|
| 222 |
+
t.assert.deepStrictEqual(res.json(), { version: 'undefined' })
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
{
|
| 226 |
+
const res = await app.inject({
|
| 227 |
+
url: '/',
|
| 228 |
+
method: 'POST',
|
| 229 |
+
payload: {
|
| 230 |
+
version: '1',
|
| 231 |
+
foo: 32
|
| 232 |
+
}
|
| 233 |
+
})
|
| 234 |
+
|
| 235 |
+
t.assert.deepStrictEqual(res.statusCode, 200)
|
| 236 |
+
t.assert.deepStrictEqual(res.json(), {
|
| 237 |
+
id: '123',
|
| 238 |
+
createdAt: '1999-01-31T23:00:00.000Z',
|
| 239 |
+
karma: 42,
|
| 240 |
+
isAdmin: true
|
| 241 |
+
})
|
| 242 |
+
}
|
| 243 |
+
})
|
| 244 |
+
|
| 245 |
+
test('fastify integration within JTD serializer and custom options', async t => {
|
| 246 |
+
const factorySerializer = AjvCompiler({ jtdSerializer: true })
|
| 247 |
+
|
| 248 |
+
const app = fastify({
|
| 249 |
+
jsonShorthand: false,
|
| 250 |
+
serializerOpts: {
|
| 251 |
+
allErrors: true,
|
| 252 |
+
logger: 'wrong-value'
|
| 253 |
+
},
|
| 254 |
+
schemaController: {
|
| 255 |
+
compilersFactory: {
|
| 256 |
+
buildSerializer: factorySerializer
|
| 257 |
+
}
|
| 258 |
+
}
|
| 259 |
+
})
|
| 260 |
+
|
| 261 |
+
app.post('/', {
|
| 262 |
+
schema: {
|
| 263 |
+
response: {
|
| 264 |
+
200: {
|
| 265 |
+
properties: {
|
| 266 |
+
test: { type: 'boolean' }
|
| 267 |
+
}
|
| 268 |
+
}
|
| 269 |
+
}
|
| 270 |
+
}
|
| 271 |
+
}, async () => { })
|
| 272 |
+
|
| 273 |
+
try {
|
| 274 |
+
await app.ready()
|
| 275 |
+
t.assert.fail('should throw')
|
| 276 |
+
} catch (error) {
|
| 277 |
+
t.assert.deepStrictEqual(error.message, 'logger must implement log, warn and error methods', 'the wrong setting is forwarded to ajv/jtd')
|
| 278 |
+
}
|
| 279 |
+
})
|
services/slides/node_modules/@fastify/ajv-compiler/test/standalone.test.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const fs = require('node:fs')
|
| 4 |
+
const path = require('node:path')
|
| 5 |
+
const { test } = require('node:test')
|
| 6 |
+
const fastify = require('fastify')
|
| 7 |
+
const sanitize = require('sanitize-filename')
|
| 8 |
+
|
| 9 |
+
const { StandaloneValidator: AjvStandaloneValidator } = require('../')
|
| 10 |
+
|
| 11 |
+
function generateFileName (routeOpts) {
|
| 12 |
+
return `/ajv-generated-${sanitize(routeOpts.schema.$id)}-${routeOpts.method}-${routeOpts.httpPart}-${sanitize(routeOpts.url)}.js`
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
const generatedFileNames = []
|
| 16 |
+
|
| 17 |
+
test('standalone', async t => {
|
| 18 |
+
t.plan(4)
|
| 19 |
+
|
| 20 |
+
t.after(async () => {
|
| 21 |
+
for (const fileName of generatedFileNames) {
|
| 22 |
+
await fs.promises.unlink(path.join(__dirname, fileName))
|
| 23 |
+
}
|
| 24 |
+
})
|
| 25 |
+
|
| 26 |
+
t.test('errors', t => {
|
| 27 |
+
t.plan(2)
|
| 28 |
+
t.assert.throws(() => {
|
| 29 |
+
AjvStandaloneValidator()
|
| 30 |
+
}, 'missing restoreFunction')
|
| 31 |
+
t.assert.throws(() => {
|
| 32 |
+
AjvStandaloneValidator({ readMode: false })
|
| 33 |
+
}, 'missing storeFunction')
|
| 34 |
+
})
|
| 35 |
+
|
| 36 |
+
t.test('generate standalone code', t => {
|
| 37 |
+
t.plan(5)
|
| 38 |
+
|
| 39 |
+
const base = {
|
| 40 |
+
$id: 'urn:schema:base',
|
| 41 |
+
definitions: {
|
| 42 |
+
hello: { type: 'string' }
|
| 43 |
+
},
|
| 44 |
+
type: 'object',
|
| 45 |
+
properties: {
|
| 46 |
+
hello: { $ref: '#/definitions/hello' }
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
const refSchema = {
|
| 51 |
+
$id: 'urn:schema:ref',
|
| 52 |
+
type: 'object',
|
| 53 |
+
properties: {
|
| 54 |
+
hello: { $ref: 'urn:schema:base#/definitions/hello' }
|
| 55 |
+
}
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
const endpointSchema = {
|
| 59 |
+
schema: {
|
| 60 |
+
$id: 'urn:schema:endpoint',
|
| 61 |
+
$ref: 'urn:schema:ref'
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
const schemaMap = {
|
| 66 |
+
[base.$id]: base,
|
| 67 |
+
[refSchema.$id]: refSchema
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
const factory = AjvStandaloneValidator({
|
| 71 |
+
readMode: false,
|
| 72 |
+
storeFunction (routeOpts, schemaValidationCode) {
|
| 73 |
+
t.assert.deepStrictEqual(routeOpts, endpointSchema)
|
| 74 |
+
t.assert.ok(typeof schemaValidationCode === 'string')
|
| 75 |
+
fs.writeFileSync(path.join(__dirname, '/ajv-generated.js'), schemaValidationCode)
|
| 76 |
+
generatedFileNames.push('/ajv-generated.js')
|
| 77 |
+
t.assert.ok('stored the validation function')
|
| 78 |
+
}
|
| 79 |
+
})
|
| 80 |
+
|
| 81 |
+
const compiler = factory(schemaMap)
|
| 82 |
+
compiler(endpointSchema)
|
| 83 |
+
t.assert.ok('compiled the endpoint schema')
|
| 84 |
+
|
| 85 |
+
t.test('usage standalone code', t => {
|
| 86 |
+
t.plan(3)
|
| 87 |
+
const standaloneValidate = require('./ajv-generated')
|
| 88 |
+
|
| 89 |
+
const valid = standaloneValidate({ hello: 'world' })
|
| 90 |
+
t.assert.ok(valid)
|
| 91 |
+
|
| 92 |
+
const invalid = standaloneValidate({ hello: [] })
|
| 93 |
+
t.assert.ok(!invalid)
|
| 94 |
+
|
| 95 |
+
t.assert.ok(standaloneValidate)
|
| 96 |
+
})
|
| 97 |
+
})
|
| 98 |
+
|
| 99 |
+
t.test('fastify integration - writeMode', async t => {
|
| 100 |
+
t.plan(6)
|
| 101 |
+
|
| 102 |
+
const factory = AjvStandaloneValidator({
|
| 103 |
+
readMode: false,
|
| 104 |
+
storeFunction (routeOpts, schemaValidationCode) {
|
| 105 |
+
const fileName = generateFileName(routeOpts)
|
| 106 |
+
t.assert.ok(routeOpts)
|
| 107 |
+
fs.writeFileSync(path.join(__dirname, fileName), schemaValidationCode)
|
| 108 |
+
t.assert.ok('stored the validation function')
|
| 109 |
+
generatedFileNames.push(fileName)
|
| 110 |
+
},
|
| 111 |
+
restoreFunction () {
|
| 112 |
+
t.assert.fail('write mode ON')
|
| 113 |
+
}
|
| 114 |
+
})
|
| 115 |
+
|
| 116 |
+
const app = buildApp(factory)
|
| 117 |
+
await app.ready()
|
| 118 |
+
})
|
| 119 |
+
|
| 120 |
+
await t.test('fastify integration - readMode', async t => {
|
| 121 |
+
t.plan(6)
|
| 122 |
+
|
| 123 |
+
const factory = AjvStandaloneValidator({
|
| 124 |
+
readMode: true,
|
| 125 |
+
storeFunction () {
|
| 126 |
+
t.assert.fail('read mode ON')
|
| 127 |
+
},
|
| 128 |
+
restoreFunction (routeOpts) {
|
| 129 |
+
t.assert.ok('restore the validation function')
|
| 130 |
+
const fileName = generateFileName(routeOpts)
|
| 131 |
+
return require(path.join(__dirname, fileName))
|
| 132 |
+
}
|
| 133 |
+
})
|
| 134 |
+
|
| 135 |
+
const app = buildApp(factory)
|
| 136 |
+
await app.ready()
|
| 137 |
+
|
| 138 |
+
let res = await app.inject({
|
| 139 |
+
url: '/foo',
|
| 140 |
+
method: 'POST',
|
| 141 |
+
payload: { hello: [] }
|
| 142 |
+
})
|
| 143 |
+
t.assert.deepStrictEqual(res.statusCode, 400)
|
| 144 |
+
|
| 145 |
+
res = await app.inject({
|
| 146 |
+
url: '/bar?lang=invalid',
|
| 147 |
+
method: 'GET'
|
| 148 |
+
})
|
| 149 |
+
t.assert.deepStrictEqual(res.statusCode, 400)
|
| 150 |
+
|
| 151 |
+
res = await app.inject({
|
| 152 |
+
url: '/bar?lang=it',
|
| 153 |
+
method: 'GET'
|
| 154 |
+
})
|
| 155 |
+
t.assert.deepStrictEqual(res.statusCode, 200)
|
| 156 |
+
})
|
| 157 |
+
|
| 158 |
+
function buildApp (factory) {
|
| 159 |
+
const app = fastify({
|
| 160 |
+
jsonShorthand: false,
|
| 161 |
+
schemaController: {
|
| 162 |
+
compilersFactory: {
|
| 163 |
+
buildValidator: factory
|
| 164 |
+
}
|
| 165 |
+
}
|
| 166 |
+
})
|
| 167 |
+
|
| 168 |
+
app.addSchema({
|
| 169 |
+
$id: 'urn:schema:foo',
|
| 170 |
+
type: 'object',
|
| 171 |
+
properties: {
|
| 172 |
+
name: { type: 'string' },
|
| 173 |
+
id: { type: 'integer' }
|
| 174 |
+
}
|
| 175 |
+
})
|
| 176 |
+
|
| 177 |
+
app.post('/foo', {
|
| 178 |
+
schema: {
|
| 179 |
+
body: {
|
| 180 |
+
$id: 'urn:schema:body',
|
| 181 |
+
type: 'object',
|
| 182 |
+
properties: {
|
| 183 |
+
hello: { $ref: 'urn:schema:foo#/properties/name' }
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
}, () => { return 'ok' })
|
| 188 |
+
|
| 189 |
+
app.get('/bar', {
|
| 190 |
+
schema: {
|
| 191 |
+
query: {
|
| 192 |
+
$id: 'urn:schema:query',
|
| 193 |
+
type: 'object',
|
| 194 |
+
properties: {
|
| 195 |
+
lang: { type: 'string', enum: ['it', 'en'] }
|
| 196 |
+
}
|
| 197 |
+
}
|
| 198 |
+
}
|
| 199 |
+
}, () => { return 'ok' })
|
| 200 |
+
|
| 201 |
+
return app
|
| 202 |
+
}
|
| 203 |
+
})
|
services/slides/node_modules/@fastify/ajv-compiler/types/index.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import _ajv, { AnySchema, Options as AjvOptions, ValidateFunction, Plugin } from 'ajv'
|
| 2 |
+
import AjvJTD, { JTDOptions } from 'ajv/dist/jtd'
|
| 3 |
+
import type { Options, ErrorObject } from 'ajv'
|
| 4 |
+
import { AnyValidateFunction } from 'ajv/dist/core'
|
| 5 |
+
|
| 6 |
+
type Ajv = _ajv
|
| 7 |
+
type AjvSerializerGenerator = typeof AjvCompiler
|
| 8 |
+
|
| 9 |
+
type AjvJTDCompile = AjvJTD['compileSerializer']
|
| 10 |
+
type AjvCompile = (schema: AnySchema, _meta?: boolean) => AnyValidateFunction
|
| 11 |
+
|
| 12 |
+
type SharedCompilerOptions = {
|
| 13 |
+
onCreate?: (ajvInstance: Ajv) => void;
|
| 14 |
+
plugins?: (Plugin<unknown> | [Plugin<unknown>, unknown])[];
|
| 15 |
+
}
|
| 16 |
+
type JdtCompilerOptions = SharedCompilerOptions & {
|
| 17 |
+
mode: 'JTD';
|
| 18 |
+
customOptions?: JTDOptions
|
| 19 |
+
}
|
| 20 |
+
type AjvCompilerOptions = SharedCompilerOptions & {
|
| 21 |
+
mode?: never;
|
| 22 |
+
customOptions?: AjvOptions
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
type BuildAjvOrJdtCompilerFromPool = (
|
| 26 |
+
externalSchemas: { [key: string]: AnySchema | AnySchema[] },
|
| 27 |
+
options?: JdtCompilerOptions | AjvCompilerOptions
|
| 28 |
+
) => AjvCompile
|
| 29 |
+
|
| 30 |
+
type BuildJtdSerializerFromPool = (externalSchemas: any, serializerOpts?: { mode?: never; } & JTDOptions) => AjvJTDCompile
|
| 31 |
+
|
| 32 |
+
declare function AjvCompiler (opts: { jtdSerializer: true }): AjvCompiler.BuildSerializerFromPool
|
| 33 |
+
declare function AjvCompiler (opts?: { jtdSerializer?: false }): AjvCompiler.BuildCompilerFromPool
|
| 34 |
+
|
| 35 |
+
declare function StandaloneValidator (options: AjvCompiler.StandaloneOptions): AjvCompiler.BuildCompilerFromPool
|
| 36 |
+
|
| 37 |
+
declare namespace AjvCompiler {
|
| 38 |
+
export type { Options, ErrorObject }
|
| 39 |
+
export { Ajv }
|
| 40 |
+
|
| 41 |
+
export type BuildSerializerFromPool = BuildJtdSerializerFromPool
|
| 42 |
+
|
| 43 |
+
export type BuildCompilerFromPool = BuildAjvOrJdtCompilerFromPool
|
| 44 |
+
|
| 45 |
+
export const AjvReference: Symbol
|
| 46 |
+
|
| 47 |
+
export enum HttpParts {
|
| 48 |
+
Body = 'body',
|
| 49 |
+
Headers = 'headers',
|
| 50 |
+
Params = 'params',
|
| 51 |
+
Query = 'querystring',
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
export type RouteDefinition = {
|
| 55 |
+
method: string,
|
| 56 |
+
url: string,
|
| 57 |
+
httpPart: HttpParts,
|
| 58 |
+
schema?: unknown,
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
export type StandaloneRestoreFunction = (opts: RouteDefinition) => ValidateFunction
|
| 62 |
+
|
| 63 |
+
export type StandaloneStoreFunction = (opts: RouteDefinition, schemaValidationCode: string) => void
|
| 64 |
+
|
| 65 |
+
export type StandaloneOptionsReadModeOn = {
|
| 66 |
+
readMode: true;
|
| 67 |
+
restoreFunction?: StandaloneRestoreFunction
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
export type StandaloneOptionsReadModeOff = {
|
| 71 |
+
readMode?: false | undefined;
|
| 72 |
+
storeFunction?: StandaloneStoreFunction;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
export type StandaloneOptions = StandaloneOptionsReadModeOn | StandaloneOptionsReadModeOff
|
| 76 |
+
|
| 77 |
+
export type ValidatorFactory = BuildCompilerFromPool | BuildSerializerFromPool
|
| 78 |
+
|
| 79 |
+
export type ValidatorCompiler = ReturnType<ValidatorFactory>
|
| 80 |
+
|
| 81 |
+
export { StandaloneValidator }
|
| 82 |
+
|
| 83 |
+
export const AjvCompiler: AjvSerializerGenerator
|
| 84 |
+
export { AjvCompiler as default }
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
export = AjvCompiler
|
services/slides/node_modules/@fastify/ajv-compiler/types/index.test-d.ts
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { AnySchemaObject, ValidateFunction } from 'ajv'
|
| 2 |
+
import { AnyValidateFunction } from 'ajv/dist/core'
|
| 3 |
+
import { expectAssignable, expectType } from 'tsd'
|
| 4 |
+
import AjvCompiler, { AjvReference, ValidatorFactory, StandaloneValidator, RouteDefinition, ErrorObject, BuildCompilerFromPool, BuildSerializerFromPool, ValidatorCompiler } from '..'
|
| 5 |
+
import type Ajv from 'ajv'
|
| 6 |
+
|
| 7 |
+
{
|
| 8 |
+
const compiler = AjvCompiler({})
|
| 9 |
+
expectType<BuildCompilerFromPool>(compiler)
|
| 10 |
+
}
|
| 11 |
+
{
|
| 12 |
+
const compiler = AjvCompiler()
|
| 13 |
+
expectType<BuildCompilerFromPool>(compiler)
|
| 14 |
+
}
|
| 15 |
+
{
|
| 16 |
+
const compiler = AjvCompiler({ jtdSerializer: false })
|
| 17 |
+
expectType<BuildCompilerFromPool>(compiler)
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
{
|
| 21 |
+
const factory = AjvCompiler({ jtdSerializer: false })
|
| 22 |
+
expectType<BuildCompilerFromPool>(factory)
|
| 23 |
+
factory({}, {
|
| 24 |
+
onCreate (ajv) {
|
| 25 |
+
expectType<import('ajv').default>(ajv)
|
| 26 |
+
}
|
| 27 |
+
})
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
{
|
| 31 |
+
const compiler = AjvCompiler({ jtdSerializer: true })
|
| 32 |
+
expectType<BuildSerializerFromPool>(compiler)
|
| 33 |
+
}
|
| 34 |
+
const reader = StandaloneValidator({
|
| 35 |
+
readMode: true,
|
| 36 |
+
restoreFunction: (route: RouteDefinition) => {
|
| 37 |
+
expectAssignable<RouteDefinition>(route)
|
| 38 |
+
return {} as ValidateFunction
|
| 39 |
+
},
|
| 40 |
+
})
|
| 41 |
+
expectAssignable<ValidatorFactory>(reader)
|
| 42 |
+
|
| 43 |
+
const writer = StandaloneValidator({
|
| 44 |
+
readMode: false,
|
| 45 |
+
storeFunction: (route: RouteDefinition, code: string) => {
|
| 46 |
+
expectAssignable<RouteDefinition>(route)
|
| 47 |
+
expectAssignable<string>(code)
|
| 48 |
+
},
|
| 49 |
+
})
|
| 50 |
+
expectAssignable<ValidatorFactory>(writer)
|
| 51 |
+
|
| 52 |
+
expectType<unknown>(({} as ErrorObject).data)
|
| 53 |
+
expectType<string>(({} as ErrorObject).instancePath)
|
| 54 |
+
expectType<string>(({} as ErrorObject).keyword)
|
| 55 |
+
expectType<string | undefined>(({} as ErrorObject).message)
|
| 56 |
+
expectType<Record<string, any>>(({} as ErrorObject).params)
|
| 57 |
+
expectType<AnySchemaObject | undefined>(({} as ErrorObject).parentSchema)
|
| 58 |
+
expectType<string | undefined>(({} as ErrorObject).propertyName)
|
| 59 |
+
expectType<unknown>(({} as ErrorObject).schema)
|
| 60 |
+
expectType<string>(({} as ErrorObject).schemaPath)
|
| 61 |
+
|
| 62 |
+
expectType<Symbol>(AjvReference)
|
| 63 |
+
|
| 64 |
+
{
|
| 65 |
+
const jtdSchema = {
|
| 66 |
+
discriminator: 'version',
|
| 67 |
+
mapping: {
|
| 68 |
+
1: {
|
| 69 |
+
properties: {
|
| 70 |
+
foo: { type: 'uint8' }
|
| 71 |
+
}
|
| 72 |
+
},
|
| 73 |
+
2: {
|
| 74 |
+
properties: {
|
| 75 |
+
foo: { type: 'string' }
|
| 76 |
+
}
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
const externalSchemas1 = {
|
| 82 |
+
foo: {
|
| 83 |
+
definitions: {
|
| 84 |
+
coordinates: {
|
| 85 |
+
properties: {
|
| 86 |
+
lat: { type: 'float32' },
|
| 87 |
+
lng: { type: 'float32' }
|
| 88 |
+
}
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
const factory = AjvCompiler({ jtdSerializer: true })
|
| 95 |
+
expectType<BuildSerializerFromPool>(factory)
|
| 96 |
+
const compiler = factory(externalSchemas1, {})
|
| 97 |
+
expectAssignable<Function>(compiler)
|
| 98 |
+
const serializeFunc = compiler({ schema: jtdSchema })
|
| 99 |
+
expectType<(data: unknown) => string>(serializeFunc)
|
| 100 |
+
expectType<string>(serializeFunc({ version: '1', foo: 42 }))
|
| 101 |
+
}
|
| 102 |
+
// JTD
|
| 103 |
+
{
|
| 104 |
+
const factory = AjvCompiler()
|
| 105 |
+
expectType<BuildCompilerFromPool>(factory)
|
| 106 |
+
|
| 107 |
+
const jtdSchema = {
|
| 108 |
+
discriminator: 'version',
|
| 109 |
+
mapping: {
|
| 110 |
+
1: {
|
| 111 |
+
properties: {
|
| 112 |
+
foo: { type: 'uint8' }
|
| 113 |
+
}
|
| 114 |
+
},
|
| 115 |
+
2: {
|
| 116 |
+
properties: {
|
| 117 |
+
foo: { type: 'string' }
|
| 118 |
+
}
|
| 119 |
+
}
|
| 120 |
+
}
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
const compiler = factory({}, {
|
| 124 |
+
customOptions: {},
|
| 125 |
+
mode: 'JTD'
|
| 126 |
+
})
|
| 127 |
+
expectAssignable<ValidatorCompiler>(compiler)
|
| 128 |
+
const validatorFunc = compiler({ schema: jtdSchema })
|
| 129 |
+
expectAssignable<ValidateFunction>(validatorFunc)
|
| 130 |
+
|
| 131 |
+
expectType<boolean | Promise<any>>(validatorFunc({
|
| 132 |
+
version: '2',
|
| 133 |
+
foo: []
|
| 134 |
+
}))
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
// generate standalone code
|
| 138 |
+
{
|
| 139 |
+
const base = {
|
| 140 |
+
$id: 'urn:schema:base',
|
| 141 |
+
definitions: {
|
| 142 |
+
hello: { type: 'string' }
|
| 143 |
+
},
|
| 144 |
+
type: 'object',
|
| 145 |
+
properties: {
|
| 146 |
+
hello: { $ref: '#/definitions/hello' }
|
| 147 |
+
}
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
const refSchema = {
|
| 151 |
+
$id: 'urn:schema:ref',
|
| 152 |
+
type: 'object',
|
| 153 |
+
properties: {
|
| 154 |
+
hello: { $ref: 'urn:schema:base#/definitions/hello' }
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
const endpointSchema = {
|
| 159 |
+
schema: {
|
| 160 |
+
$id: 'urn:schema:endpoint',
|
| 161 |
+
$ref: 'urn:schema:ref'
|
| 162 |
+
}
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
const schemaMap = {
|
| 166 |
+
[base.$id]: base,
|
| 167 |
+
[refSchema.$id]: refSchema
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
const factory = StandaloneValidator({
|
| 171 |
+
readMode: false,
|
| 172 |
+
storeFunction (routeOpts, schemaValidationCode) {
|
| 173 |
+
expectType<RouteDefinition>(routeOpts)
|
| 174 |
+
expectType<string>(schemaValidationCode)
|
| 175 |
+
}
|
| 176 |
+
})
|
| 177 |
+
expectAssignable<ValidatorFactory>(factory)
|
| 178 |
+
|
| 179 |
+
const compiler = factory(schemaMap)
|
| 180 |
+
expectAssignable<ValidatorCompiler>(compiler)
|
| 181 |
+
expectAssignable<Function>(compiler(endpointSchema))
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
{
|
| 185 |
+
const base = {
|
| 186 |
+
$id: 'urn:schema:base',
|
| 187 |
+
definitions: {
|
| 188 |
+
hello: { type: 'string' }
|
| 189 |
+
},
|
| 190 |
+
type: 'object',
|
| 191 |
+
properties: {
|
| 192 |
+
hello: { $ref: '#/definitions/hello' }
|
| 193 |
+
}
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
const refSchema = {
|
| 197 |
+
$id: 'urn:schema:ref',
|
| 198 |
+
type: 'object',
|
| 199 |
+
properties: {
|
| 200 |
+
hello: { $ref: 'urn:schema:base#/definitions/hello' }
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
const endpointSchema = {
|
| 205 |
+
schema: {
|
| 206 |
+
$id: 'urn:schema:endpoint',
|
| 207 |
+
$ref: 'urn:schema:ref'
|
| 208 |
+
}
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
const schemaMap = {
|
| 212 |
+
[base.$id]: base,
|
| 213 |
+
[refSchema.$id]: refSchema
|
| 214 |
+
}
|
| 215 |
+
const factory = StandaloneValidator({
|
| 216 |
+
readMode: true,
|
| 217 |
+
restoreFunction (routeOpts) {
|
| 218 |
+
expectType<RouteDefinition>(routeOpts)
|
| 219 |
+
return {} as ValidateFunction
|
| 220 |
+
}
|
| 221 |
+
})
|
| 222 |
+
expectAssignable<ValidatorFactory>(factory)
|
| 223 |
+
|
| 224 |
+
const compiler = factory(schemaMap)
|
| 225 |
+
expectAssignable<ValidatorCompiler>(compiler)
|
| 226 |
+
expectType<AnyValidateFunction<any>>(compiler(endpointSchema))
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
// Plugins
|
| 230 |
+
{
|
| 231 |
+
const factory = AjvCompiler()
|
| 232 |
+
const compilerFactoryParams = {
|
| 233 |
+
customOptions: {},
|
| 234 |
+
plugins: [
|
| 235 |
+
(ajv: Ajv) => {
|
| 236 |
+
expectType<Ajv>(ajv)
|
| 237 |
+
return ajv
|
| 238 |
+
},
|
| 239 |
+
(ajv: Ajv, options: unknown) => {
|
| 240 |
+
expectType<Ajv>(ajv)
|
| 241 |
+
expectType<unknown>(options)
|
| 242 |
+
return ajv
|
| 243 |
+
}
|
| 244 |
+
]
|
| 245 |
+
}
|
| 246 |
+
expectAssignable<Parameters<BuildCompilerFromPool>>([{}, compilerFactoryParams])
|
| 247 |
+
|
| 248 |
+
const compiler = factory({}, {
|
| 249 |
+
customOptions: {},
|
| 250 |
+
plugins: [
|
| 251 |
+
(ajv) => {
|
| 252 |
+
expectType<Ajv>(ajv)
|
| 253 |
+
return ajv
|
| 254 |
+
},
|
| 255 |
+
(ajv, options) => {
|
| 256 |
+
expectType<Ajv>(ajv)
|
| 257 |
+
expectType<unknown>(options)
|
| 258 |
+
return ajv
|
| 259 |
+
}
|
| 260 |
+
]
|
| 261 |
+
})
|
| 262 |
+
expectAssignable<ValidatorCompiler>(compiler)
|
| 263 |
+
}
|
| 264 |
+
// Compiler factory should allow both signatures (mode: JTD and mode omitted)
|
| 265 |
+
{
|
| 266 |
+
expectAssignable<Parameters<BuildCompilerFromPool>>([{}, {}])
|
| 267 |
+
|
| 268 |
+
const ajvPlugin = (ajv: Ajv): Ajv => {
|
| 269 |
+
expectType<Ajv>(ajv)
|
| 270 |
+
return ajv
|
| 271 |
+
}
|
| 272 |
+
expectAssignable<Parameters<BuildCompilerFromPool>>([{}, { plugins: [ajvPlugin] }])
|
| 273 |
+
|
| 274 |
+
expectAssignable<Parameters<BuildCompilerFromPool>>([{}, {
|
| 275 |
+
mode: 'JTD',
|
| 276 |
+
customOptions: {
|
| 277 |
+
removeAdditional: 'all'
|
| 278 |
+
},
|
| 279 |
+
plugins: [ajvPlugin]
|
| 280 |
+
}])
|
| 281 |
+
|
| 282 |
+
expectAssignable<Parameters<BuildCompilerFromPool>>([{}, {
|
| 283 |
+
mode: 'JTD',
|
| 284 |
+
customOptions: {
|
| 285 |
+
removeAdditional: 'all'
|
| 286 |
+
},
|
| 287 |
+
plugins: [[ajvPlugin, ['string1', 'string2']]]
|
| 288 |
+
}])
|
| 289 |
+
|
| 290 |
+
expectAssignable<Parameters<BuildCompilerFromPool>>([{}, {
|
| 291 |
+
plugins: [
|
| 292 |
+
ajvPlugin,
|
| 293 |
+
(ajv: Ajv, options: unknown): Ajv => {
|
| 294 |
+
expectType<Ajv>(ajv)
|
| 295 |
+
expectType<unknown>(options)
|
| 296 |
+
return ajv
|
| 297 |
+
},
|
| 298 |
+
[ajvPlugin, ['keyword1', 'keyword2']],
|
| 299 |
+
[ajvPlugin, [{ key: 'value' }]],
|
| 300 |
+
]
|
| 301 |
+
}])
|
| 302 |
+
}
|
services/slides/node_modules/@fastify/busboy/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright Brian White. All rights reserved.
|
| 4 |
+
Copyright (c) 2021-present The Fastify team
|
| 5 |
+
|
| 6 |
+
The Fastify team members are listed at https://github.com/fastify/fastify#team.
|
| 7 |
+
|
| 8 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 9 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 10 |
+
in the Software without restriction, including without limitation the rights
|
| 11 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 12 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 13 |
+
furnished to do so, subject to the following conditions:
|
| 14 |
+
|
| 15 |
+
The above copyright notice and this permission notice shall be included in all
|
| 16 |
+
copies or substantial portions of the Software.
|
| 17 |
+
|
| 18 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 19 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 20 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 21 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 22 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 23 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 24 |
+
SOFTWARE.
|
services/slides/node_modules/@fastify/busboy/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# busboy
|
| 2 |
+
|
| 3 |
+
<div align="center">
|
| 4 |
+
|
| 5 |
+
[](https://github.com/fastify/busboy/actions)
|
| 6 |
+
[](https://standardjs.com/)
|
| 7 |
+
[](https://github.com/fastify/.github/blob/main/SECURITY.md)
|
| 8 |
+
|
| 9 |
+
</div>
|
| 10 |
+
|
| 11 |
+
<div align="center">
|
| 12 |
+
|
| 13 |
+
[](https://www.npmjs.com/package/@fastify/busboy)
|
| 14 |
+
[](https://www.npmjs.com/package/@fastify/busboy)
|
| 15 |
+
|
| 16 |
+
</div>
|
| 17 |
+
|
| 18 |
+
Description
|
| 19 |
+
===========
|
| 20 |
+
|
| 21 |
+
A Node.js module for parsing incoming HTML form data.
|
| 22 |
+
|
| 23 |
+
This is an officially supported fork by [fastify](https://github.com/fastify/) organization of the amazing library [originally created](https://github.com/mscdex/busboy) by Brian White,
|
| 24 |
+
aimed at addressing long-standing issues with it.
|
| 25 |
+
|
| 26 |
+
Benchmark (Mean time for 500 Kb payload, 2000 cycles, 1000 cycle warmup):
|
| 27 |
+
|
| 28 |
+
| Library | Version | Mean time in nanoseconds (less is better) |
|
| 29 |
+
|-----------------------|---------|-------------------------------------------|
|
| 30 |
+
| busboy | 0.3.1 | `340114` |
|
| 31 |
+
| @fastify/busboy | 1.0.0 | `270984` |
|
| 32 |
+
|
| 33 |
+
[Changelog](https://github.com/fastify/busboy/blob/main/CHANGELOG.md) since busboy 0.31.
|
| 34 |
+
|
| 35 |
+
Requirements
|
| 36 |
+
============
|
| 37 |
+
|
| 38 |
+
* [Node.js](http://nodejs.org/) 10+
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
Install
|
| 42 |
+
=======
|
| 43 |
+
|
| 44 |
+
npm i @fastify/busboy
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
Examples
|
| 48 |
+
========
|
| 49 |
+
|
| 50 |
+
* Parsing (multipart) with default options:
|
| 51 |
+
|
| 52 |
+
```javascript
|
| 53 |
+
const http = require('node:http');
|
| 54 |
+
const { inspect } = require('node:util');
|
| 55 |
+
const Busboy = require('@fastify/busboy');
|
| 56 |
+
|
| 57 |
+
http.createServer((req, res) => {
|
| 58 |
+
if (req.method === 'POST') {
|
| 59 |
+
const busboy = new Busboy({ headers: req.headers });
|
| 60 |
+
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
|
| 61 |
+
console.log(`File [${fieldname}]: filename: ${filename}, encoding: ${encoding}, mimetype: ${mimetype}`);
|
| 62 |
+
file.on('data', data => {
|
| 63 |
+
console.log(`File [${fieldname}] got ${data.length} bytes`);
|
| 64 |
+
});
|
| 65 |
+
file.on('end', () => {
|
| 66 |
+
console.log(`File [${fieldname}] Finished`);
|
| 67 |
+
});
|
| 68 |
+
});
|
| 69 |
+
busboy.on('field', (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) => {
|
| 70 |
+
console.log(`Field [${fieldname}]: value: ${inspect(val)}`);
|
| 71 |
+
});
|
| 72 |
+
busboy.on('finish', () => {
|
| 73 |
+
console.log('Done parsing form!');
|
| 74 |
+
res.writeHead(303, { Connection: 'close', Location: '/' });
|
| 75 |
+
res.end();
|
| 76 |
+
});
|
| 77 |
+
req.pipe(busboy);
|
| 78 |
+
} else if (req.method === 'GET') {
|
| 79 |
+
res.writeHead(200, { Connection: 'close' });
|
| 80 |
+
res.end(`<html><head></head><body>
|
| 81 |
+
<form method="POST" enctype="multipart/form-data">
|
| 82 |
+
<input type="text" name="textfield"><br>
|
| 83 |
+
<input type="file" name="filefield"><br>
|
| 84 |
+
<input type="submit">
|
| 85 |
+
</form>
|
| 86 |
+
</body></html>`);
|
| 87 |
+
}
|
| 88 |
+
}).listen(8000, () => {
|
| 89 |
+
console.log('Listening for requests');
|
| 90 |
+
});
|
| 91 |
+
|
| 92 |
+
// Example output, using http://nodejs.org/images/ryan-speaker.jpg as the file:
|
| 93 |
+
//
|
| 94 |
+
// Listening for requests
|
| 95 |
+
// File [filefield]: filename: ryan-speaker.jpg, encoding: binary
|
| 96 |
+
// File [filefield] got 11971 bytes
|
| 97 |
+
// Field [textfield]: value: 'testing! :-)'
|
| 98 |
+
// File [filefield] Finished
|
| 99 |
+
// Done parsing form!
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
* Save all incoming files to disk:
|
| 103 |
+
|
| 104 |
+
```javascript
|
| 105 |
+
const http = require('node:http');
|
| 106 |
+
const path = require('node:path');
|
| 107 |
+
const os = require('node:os');
|
| 108 |
+
const fs = require('node:fs');
|
| 109 |
+
|
| 110 |
+
const Busboy = require('@fastify/busboy');
|
| 111 |
+
|
| 112 |
+
http.createServer(function(req, res) {
|
| 113 |
+
if (req.method === 'POST') {
|
| 114 |
+
const busboy = new Busboy({ headers: req.headers });
|
| 115 |
+
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
|
| 116 |
+
var saveTo = path.join(os.tmpdir(), path.basename(fieldname));
|
| 117 |
+
file.pipe(fs.createWriteStream(saveTo));
|
| 118 |
+
});
|
| 119 |
+
busboy.on('finish', function() {
|
| 120 |
+
res.writeHead(200, { 'Connection': 'close' });
|
| 121 |
+
res.end("That's all folks!");
|
| 122 |
+
});
|
| 123 |
+
return req.pipe(busboy);
|
| 124 |
+
}
|
| 125 |
+
res.writeHead(404);
|
| 126 |
+
res.end();
|
| 127 |
+
}).listen(8000, function() {
|
| 128 |
+
console.log('Listening for requests');
|
| 129 |
+
});
|
| 130 |
+
```
|
| 131 |
+
|
| 132 |
+
* Parsing (urlencoded) with default options:
|
| 133 |
+
|
| 134 |
+
```javascript
|
| 135 |
+
const http = require('node:http');
|
| 136 |
+
const { inspect } = require('node:util');
|
| 137 |
+
|
| 138 |
+
const Busboy = require('@fastify/busboy');
|
| 139 |
+
|
| 140 |
+
http.createServer(function(req, res) {
|
| 141 |
+
if (req.method === 'POST') {
|
| 142 |
+
const busboy = new Busboy({ headers: req.headers });
|
| 143 |
+
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
|
| 144 |
+
console.log('File [' + fieldname + ']: filename: ' + filename);
|
| 145 |
+
file.on('data', function(data) {
|
| 146 |
+
console.log('File [' + fieldname + '] got ' + data.length + ' bytes');
|
| 147 |
+
});
|
| 148 |
+
file.on('end', function() {
|
| 149 |
+
console.log('File [' + fieldname + '] Finished');
|
| 150 |
+
});
|
| 151 |
+
});
|
| 152 |
+
busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated) {
|
| 153 |
+
console.log('Field [' + fieldname + ']: value: ' + inspect(val));
|
| 154 |
+
});
|
| 155 |
+
busboy.on('finish', function() {
|
| 156 |
+
console.log('Done parsing form!');
|
| 157 |
+
res.writeHead(303, { Connection: 'close', Location: '/' });
|
| 158 |
+
res.end();
|
| 159 |
+
});
|
| 160 |
+
req.pipe(busboy);
|
| 161 |
+
} else if (req.method === 'GET') {
|
| 162 |
+
res.writeHead(200, { Connection: 'close' });
|
| 163 |
+
res.end('<html><head></head><body>\
|
| 164 |
+
<form method="POST">\
|
| 165 |
+
<input type="text" name="textfield"><br />\
|
| 166 |
+
<select name="selectfield">\
|
| 167 |
+
<option value="1">1</option>\
|
| 168 |
+
<option value="10">10</option>\
|
| 169 |
+
<option value="100">100</option>\
|
| 170 |
+
<option value="9001">9001</option>\
|
| 171 |
+
</select><br />\
|
| 172 |
+
<input type="checkbox" name="checkfield">Node.js rules!<br />\
|
| 173 |
+
<input type="submit">\
|
| 174 |
+
</form>\
|
| 175 |
+
</body></html>');
|
| 176 |
+
}
|
| 177 |
+
}).listen(8000, function() {
|
| 178 |
+
console.log('Listening for requests');
|
| 179 |
+
});
|
| 180 |
+
|
| 181 |
+
// Example output:
|
| 182 |
+
//
|
| 183 |
+
// Listening for requests
|
| 184 |
+
// Field [textfield]: value: 'testing! :-)'
|
| 185 |
+
// Field [selectfield]: value: '9001'
|
| 186 |
+
// Field [checkfield]: value: 'on'
|
| 187 |
+
// Done parsing form!
|
| 188 |
+
```
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
API
|
| 192 |
+
===
|
| 193 |
+
|
| 194 |
+
_Busboy_ is a _Writable_ stream
|
| 195 |
+
|
| 196 |
+
Busboy (special) events
|
| 197 |
+
-----------------------
|
| 198 |
+
|
| 199 |
+
* **file**(< _string_ >fieldname, < _ReadableStream_ >stream, < _string_ >filename, < _string_ >transferEncoding, < _string_ >mimeType) - Emitted for each new file form field found. `transferEncoding` contains the 'Content-Transfer-Encoding' value for the file stream. `mimeType` contains the 'Content-Type' value for the file stream.
|
| 200 |
+
* Note: if you listen for this event, you should always handle the `stream` no matter if you care about the file contents or not (e.g. you can simply just do `stream.resume();` if you want to discard the contents), otherwise the 'finish' event will never fire on the Busboy instance. However, if you don't care about **any** incoming files, you can simply not listen for the 'file' event at all and any/all files will be automatically and safely discarded (these discarded files do still count towards `files` and `parts` limits).
|
| 201 |
+
* If a configured file size limit was reached, `stream` will both have a boolean property `truncated` (best checked at the end of the stream) and emit a 'limit' event to notify you when this happens.
|
| 202 |
+
* The property `bytesRead` informs about the number of bytes that have been read so far.
|
| 203 |
+
|
| 204 |
+
* **field**(< _string_ >fieldname, < _string_ >value, < _boolean_ >fieldnameTruncated, < _boolean_ >valueTruncated, < _string_ >transferEncoding, < _string_ >mimeType) - Emitted for each new non-file field found.
|
| 205 |
+
|
| 206 |
+
* **partsLimit**() - Emitted when specified `parts` limit has been reached. No more 'file' or 'field' events will be emitted.
|
| 207 |
+
|
| 208 |
+
* **filesLimit**() - Emitted when specified `files` limit has been reached. No more 'file' events will be emitted.
|
| 209 |
+
|
| 210 |
+
* **fieldsLimit**() - Emitted when specified `fields` limit has been reached. No more 'field' events will be emitted.
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
Busboy methods
|
| 214 |
+
--------------
|
| 215 |
+
|
| 216 |
+
* **(constructor)**(< _object_ >config) - Creates and returns a new Busboy instance.
|
| 217 |
+
|
| 218 |
+
* The constructor takes the following valid `config` settings:
|
| 219 |
+
|
| 220 |
+
* **headers** - _object_ - These are the HTTP headers of the incoming request, which are used by individual parsers.
|
| 221 |
+
|
| 222 |
+
* **autoDestroy** - _boolean_ - Whether this stream should automatically call .destroy() on itself after ending. (Default: false).
|
| 223 |
+
|
| 224 |
+
* **highWaterMark** - _integer_ - highWaterMark to use for this Busboy instance (Default: WritableStream default).
|
| 225 |
+
|
| 226 |
+
* **fileHwm** - _integer_ - highWaterMark to use for file streams (Default: ReadableStream default).
|
| 227 |
+
|
| 228 |
+
* **defCharset** - _string_ - Default character set to use when one isn't defined (Default: 'utf8').
|
| 229 |
+
|
| 230 |
+
* **preservePath** - _boolean_ - If paths in the multipart 'filename' field shall be preserved. (Default: false).
|
| 231 |
+
|
| 232 |
+
* **isPartAFile** - __function__ - Use this function to override the default file detection functionality. It has following parameters:
|
| 233 |
+
|
| 234 |
+
* fieldName - __string__ The name of the field.
|
| 235 |
+
|
| 236 |
+
* contentType - __string__ The content-type of the part, e.g. `text/plain`, `image/jpeg`, `application/octet-stream`
|
| 237 |
+
|
| 238 |
+
* fileName - __string__ The name of a file supplied by the part.
|
| 239 |
+
|
| 240 |
+
(Default: `(fieldName, contentType, fileName) => (contentType === 'application/octet-stream' || fileName !== undefined)`)
|
| 241 |
+
|
| 242 |
+
* **limits** - _object_ - Various limits on incoming data. Valid properties are:
|
| 243 |
+
|
| 244 |
+
* **fieldNameSize** - _integer_ - Max field name size (in bytes) (Default: 100 bytes).
|
| 245 |
+
|
| 246 |
+
* **fieldSize** - _integer_ - Max field value size (in bytes) (Default: 1 MiB, which is 1024 x 1024 bytes).
|
| 247 |
+
|
| 248 |
+
* **fields** - _integer_ - Max number of non-file fields (Default: Infinity).
|
| 249 |
+
|
| 250 |
+
* **fileSize** - _integer_ - For multipart forms, the max file size (in bytes) (Default: Infinity).
|
| 251 |
+
|
| 252 |
+
* **files** - _integer_ - For multipart forms, the max number of file fields (Default: Infinity).
|
| 253 |
+
|
| 254 |
+
* **parts** - _integer_ - For multipart forms, the max number of parts (fields + files) (Default: Infinity).
|
| 255 |
+
|
| 256 |
+
* **headerPairs** - _integer_ - For multipart forms, the max number of header key=>value pairs to parse **Default:** 2000
|
| 257 |
+
|
| 258 |
+
* **headerSize** - _integer_ - For multipart forms, the max size of a multipart header **Default:** 81920.
|
| 259 |
+
|
| 260 |
+
* The constructor can throw errors:
|
| 261 |
+
|
| 262 |
+
* **Busboy expected an options-Object.** - Busboy expected an Object as first parameters.
|
| 263 |
+
|
| 264 |
+
* **Busboy expected an options-Object with headers-attribute.** - The first parameter is lacking of a headers-attribute.
|
| 265 |
+
|
| 266 |
+
* **Limit $limit is not a valid number** - Busboy expected the desired limit to be of type number. Busboy throws this Error to prevent a potential security issue by falling silently back to the Busboy-defaults. Potential source for this Error can be the direct use of environment variables without transforming them to the type number.
|
| 267 |
+
|
| 268 |
+
* **Unsupported Content-Type.** - The `Content-Type` isn't one Busboy can parse.
|
| 269 |
+
|
| 270 |
+
* **Missing Content-Type-header.** - The provided headers don't include `Content-Type` at all.
|
services/slides/node_modules/@fastify/busboy/deps/dicer/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright Brian White. All rights reserved.
|
| 2 |
+
|
| 3 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 4 |
+
of this software and associated documentation files (the "Software"), to
|
| 5 |
+
deal in the Software without restriction, including without limitation the
|
| 6 |
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
| 7 |
+
sell copies of the Software, and to permit persons to whom the Software is
|
| 8 |
+
furnished to do so, subject to the following conditions:
|
| 9 |
+
|
| 10 |
+
The above copyright notice and this permission notice shall be included in
|
| 11 |
+
all copies or substantial portions of the Software.
|
| 12 |
+
|
| 13 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 14 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 15 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 16 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 17 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
| 18 |
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
| 19 |
+
IN THE SOFTWARE.
|
services/slides/node_modules/@fastify/busboy/deps/dicer/lib/Dicer.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const WritableStream = require('node:stream').Writable
|
| 4 |
+
const inherits = require('node:util').inherits
|
| 5 |
+
|
| 6 |
+
const StreamSearch = require('../../streamsearch/sbmh')
|
| 7 |
+
|
| 8 |
+
const PartStream = require('./PartStream')
|
| 9 |
+
const HeaderParser = require('./HeaderParser')
|
| 10 |
+
|
| 11 |
+
const DASH = 45
|
| 12 |
+
const B_ONEDASH = Buffer.from('-')
|
| 13 |
+
const B_CRLF = Buffer.from('\r\n')
|
| 14 |
+
const EMPTY_FN = function () {}
|
| 15 |
+
|
| 16 |
+
function Dicer (cfg) {
|
| 17 |
+
if (!(this instanceof Dicer)) { return new Dicer(cfg) }
|
| 18 |
+
WritableStream.call(this, cfg)
|
| 19 |
+
|
| 20 |
+
if (!cfg || (!cfg.headerFirst && typeof cfg.boundary !== 'string')) { throw new TypeError('Boundary required') }
|
| 21 |
+
|
| 22 |
+
if (typeof cfg.boundary === 'string') { this.setBoundary(cfg.boundary) } else { this._bparser = undefined }
|
| 23 |
+
|
| 24 |
+
this._headerFirst = cfg.headerFirst
|
| 25 |
+
|
| 26 |
+
this._dashes = 0
|
| 27 |
+
this._parts = 0
|
| 28 |
+
this._finished = false
|
| 29 |
+
this._realFinish = false
|
| 30 |
+
this._isPreamble = true
|
| 31 |
+
this._justMatched = false
|
| 32 |
+
this._firstWrite = true
|
| 33 |
+
this._inHeader = true
|
| 34 |
+
this._part = undefined
|
| 35 |
+
this._cb = undefined
|
| 36 |
+
this._ignoreData = false
|
| 37 |
+
this._partOpts = { highWaterMark: cfg.partHwm }
|
| 38 |
+
this._pause = false
|
| 39 |
+
|
| 40 |
+
const self = this
|
| 41 |
+
this._hparser = new HeaderParser(cfg)
|
| 42 |
+
this._hparser.on('header', function (header) {
|
| 43 |
+
self._inHeader = false
|
| 44 |
+
self._part.emit('header', header)
|
| 45 |
+
})
|
| 46 |
+
}
|
| 47 |
+
inherits(Dicer, WritableStream)
|
| 48 |
+
|
| 49 |
+
Dicer.prototype.emit = function (ev) {
|
| 50 |
+
if (ev === 'finish' && !this._realFinish) {
|
| 51 |
+
if (!this._finished) {
|
| 52 |
+
const self = this
|
| 53 |
+
process.nextTick(function () {
|
| 54 |
+
self.emit('error', new Error('Unexpected end of multipart data'))
|
| 55 |
+
if (self._part && !self._ignoreData) {
|
| 56 |
+
const type = (self._isPreamble ? 'Preamble' : 'Part')
|
| 57 |
+
self._part.emit('error', new Error(type + ' terminated early due to unexpected end of multipart data'))
|
| 58 |
+
self._part.push(null)
|
| 59 |
+
process.nextTick(function () {
|
| 60 |
+
self._realFinish = true
|
| 61 |
+
self.emit('finish')
|
| 62 |
+
self._realFinish = false
|
| 63 |
+
})
|
| 64 |
+
return
|
| 65 |
+
}
|
| 66 |
+
self._realFinish = true
|
| 67 |
+
self.emit('finish')
|
| 68 |
+
self._realFinish = false
|
| 69 |
+
})
|
| 70 |
+
}
|
| 71 |
+
} else { WritableStream.prototype.emit.apply(this, arguments) }
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
Dicer.prototype._write = function (data, encoding, cb) {
|
| 75 |
+
// ignore unexpected data (e.g. extra trailer data after finished)
|
| 76 |
+
if (!this._hparser && !this._bparser) { return cb() }
|
| 77 |
+
|
| 78 |
+
if (this._headerFirst && this._isPreamble) {
|
| 79 |
+
if (!this._part) {
|
| 80 |
+
this._part = new PartStream(this._partOpts)
|
| 81 |
+
if (this.listenerCount('preamble') !== 0) { this.emit('preamble', this._part) } else { this._ignore() }
|
| 82 |
+
}
|
| 83 |
+
const r = this._hparser.push(data)
|
| 84 |
+
if (!this._inHeader && r !== undefined && r < data.length) { data = data.slice(r) } else { return cb() }
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
// allows for "easier" testing
|
| 88 |
+
if (this._firstWrite) {
|
| 89 |
+
this._bparser.push(B_CRLF)
|
| 90 |
+
this._firstWrite = false
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
this._bparser.push(data)
|
| 94 |
+
|
| 95 |
+
if (this._pause) { this._cb = cb } else { cb() }
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
Dicer.prototype.reset = function () {
|
| 99 |
+
this._part = undefined
|
| 100 |
+
this._bparser = undefined
|
| 101 |
+
this._hparser = undefined
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
Dicer.prototype.setBoundary = function (boundary) {
|
| 105 |
+
const self = this
|
| 106 |
+
this._bparser = new StreamSearch('\r\n--' + boundary)
|
| 107 |
+
this._bparser.on('info', function (isMatch, data, start, end) {
|
| 108 |
+
self._oninfo(isMatch, data, start, end)
|
| 109 |
+
})
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
Dicer.prototype._ignore = function () {
|
| 113 |
+
if (this._part && !this._ignoreData) {
|
| 114 |
+
this._ignoreData = true
|
| 115 |
+
this._part.on('error', EMPTY_FN)
|
| 116 |
+
// we must perform some kind of read on the stream even though we are
|
| 117 |
+
// ignoring the data, otherwise node's Readable stream will not emit 'end'
|
| 118 |
+
// after pushing null to the stream
|
| 119 |
+
this._part.resume()
|
| 120 |
+
}
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
Dicer.prototype._oninfo = function (isMatch, data, start, end) {
|
| 124 |
+
let buf; const self = this; let i = 0; let r; let shouldWriteMore = true
|
| 125 |
+
|
| 126 |
+
if (!this._part && this._justMatched && data) {
|
| 127 |
+
while (this._dashes < 2 && (start + i) < end) {
|
| 128 |
+
if (data[start + i] === DASH) {
|
| 129 |
+
++i
|
| 130 |
+
++this._dashes
|
| 131 |
+
} else {
|
| 132 |
+
if (this._dashes) { buf = B_ONEDASH }
|
| 133 |
+
this._dashes = 0
|
| 134 |
+
break
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
if (this._dashes === 2) {
|
| 138 |
+
if ((start + i) < end && this.listenerCount('trailer') !== 0) { this.emit('trailer', data.slice(start + i, end)) }
|
| 139 |
+
this.reset()
|
| 140 |
+
this._finished = true
|
| 141 |
+
// no more parts will be added
|
| 142 |
+
if (self._parts === 0) {
|
| 143 |
+
self._realFinish = true
|
| 144 |
+
self.emit('finish')
|
| 145 |
+
self._realFinish = false
|
| 146 |
+
}
|
| 147 |
+
}
|
| 148 |
+
if (this._dashes) { return }
|
| 149 |
+
}
|
| 150 |
+
if (this._justMatched) { this._justMatched = false }
|
| 151 |
+
if (!this._part) {
|
| 152 |
+
this._part = new PartStream(this._partOpts)
|
| 153 |
+
this._part._read = function (n) {
|
| 154 |
+
self._unpause()
|
| 155 |
+
}
|
| 156 |
+
if (this._isPreamble && this.listenerCount('preamble') !== 0) {
|
| 157 |
+
this.emit('preamble', this._part)
|
| 158 |
+
} else if (this._isPreamble !== true && this.listenerCount('part') !== 0) {
|
| 159 |
+
this.emit('part', this._part)
|
| 160 |
+
} else {
|
| 161 |
+
this._ignore()
|
| 162 |
+
}
|
| 163 |
+
if (!this._isPreamble) { this._inHeader = true }
|
| 164 |
+
}
|
| 165 |
+
if (data && start < end && !this._ignoreData) {
|
| 166 |
+
if (this._isPreamble || !this._inHeader) {
|
| 167 |
+
if (buf) { shouldWriteMore = this._part.push(buf) }
|
| 168 |
+
shouldWriteMore = this._part.push(data.slice(start, end))
|
| 169 |
+
if (!shouldWriteMore) { this._pause = true }
|
| 170 |
+
} else if (!this._isPreamble && this._inHeader) {
|
| 171 |
+
if (buf) { this._hparser.push(buf) }
|
| 172 |
+
r = this._hparser.push(data.slice(start, end))
|
| 173 |
+
if (!this._inHeader && r !== undefined && r < end) { this._oninfo(false, data, start + r, end) }
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
if (isMatch) {
|
| 177 |
+
this._hparser.reset()
|
| 178 |
+
if (this._isPreamble) { this._isPreamble = false } else {
|
| 179 |
+
if (start !== end) {
|
| 180 |
+
++this._parts
|
| 181 |
+
this._part.on('end', function () {
|
| 182 |
+
if (--self._parts === 0) {
|
| 183 |
+
if (self._finished) {
|
| 184 |
+
self._realFinish = true
|
| 185 |
+
self.emit('finish')
|
| 186 |
+
self._realFinish = false
|
| 187 |
+
} else {
|
| 188 |
+
self._unpause()
|
| 189 |
+
}
|
| 190 |
+
}
|
| 191 |
+
})
|
| 192 |
+
}
|
| 193 |
+
}
|
| 194 |
+
this._part.push(null)
|
| 195 |
+
this._part = undefined
|
| 196 |
+
this._ignoreData = false
|
| 197 |
+
this._justMatched = true
|
| 198 |
+
this._dashes = 0
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
Dicer.prototype._unpause = function () {
|
| 203 |
+
if (!this._pause) { return }
|
| 204 |
+
|
| 205 |
+
this._pause = false
|
| 206 |
+
if (this._cb) {
|
| 207 |
+
const cb = this._cb
|
| 208 |
+
this._cb = undefined
|
| 209 |
+
cb()
|
| 210 |
+
}
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
module.exports = Dicer
|
services/slides/node_modules/@fastify/busboy/deps/dicer/lib/HeaderParser.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const EventEmitter = require('node:events').EventEmitter
|
| 4 |
+
const inherits = require('node:util').inherits
|
| 5 |
+
const getLimit = require('../../../lib/utils/getLimit')
|
| 6 |
+
|
| 7 |
+
const StreamSearch = require('../../streamsearch/sbmh')
|
| 8 |
+
|
| 9 |
+
const B_DCRLF = Buffer.from('\r\n\r\n')
|
| 10 |
+
const RE_CRLF = /\r\n/g
|
| 11 |
+
const RE_HDR = /^([^:]+):[ \t]?([\x00-\xFF]+)?$/ // eslint-disable-line no-control-regex
|
| 12 |
+
|
| 13 |
+
function HeaderParser (cfg) {
|
| 14 |
+
EventEmitter.call(this)
|
| 15 |
+
|
| 16 |
+
cfg = cfg || {}
|
| 17 |
+
const self = this
|
| 18 |
+
this.nread = 0
|
| 19 |
+
this.maxed = false
|
| 20 |
+
this.npairs = 0
|
| 21 |
+
this.maxHeaderPairs = getLimit(cfg, 'maxHeaderPairs', 2000)
|
| 22 |
+
this.maxHeaderSize = getLimit(cfg, 'maxHeaderSize', 80 * 1024)
|
| 23 |
+
this.buffer = ''
|
| 24 |
+
this.header = {}
|
| 25 |
+
this.finished = false
|
| 26 |
+
this.ss = new StreamSearch(B_DCRLF)
|
| 27 |
+
this.ss.on('info', function (isMatch, data, start, end) {
|
| 28 |
+
if (data && !self.maxed) {
|
| 29 |
+
if (self.nread + end - start >= self.maxHeaderSize) {
|
| 30 |
+
end = self.maxHeaderSize - self.nread + start
|
| 31 |
+
self.nread = self.maxHeaderSize
|
| 32 |
+
self.maxed = true
|
| 33 |
+
} else { self.nread += (end - start) }
|
| 34 |
+
|
| 35 |
+
self.buffer += data.toString('binary', start, end)
|
| 36 |
+
}
|
| 37 |
+
if (isMatch) { self._finish() }
|
| 38 |
+
})
|
| 39 |
+
}
|
| 40 |
+
inherits(HeaderParser, EventEmitter)
|
| 41 |
+
|
| 42 |
+
HeaderParser.prototype.push = function (data) {
|
| 43 |
+
const r = this.ss.push(data)
|
| 44 |
+
if (this.finished) { return r }
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
HeaderParser.prototype.reset = function () {
|
| 48 |
+
this.finished = false
|
| 49 |
+
this.buffer = ''
|
| 50 |
+
this.header = {}
|
| 51 |
+
this.ss.reset()
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
HeaderParser.prototype._finish = function () {
|
| 55 |
+
if (this.buffer) { this._parseHeader() }
|
| 56 |
+
this.ss.matches = this.ss.maxMatches
|
| 57 |
+
const header = this.header
|
| 58 |
+
this.header = {}
|
| 59 |
+
this.buffer = ''
|
| 60 |
+
this.finished = true
|
| 61 |
+
this.nread = this.npairs = 0
|
| 62 |
+
this.maxed = false
|
| 63 |
+
this.emit('header', header)
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
HeaderParser.prototype._parseHeader = function () {
|
| 67 |
+
if (this.npairs === this.maxHeaderPairs) { return }
|
| 68 |
+
|
| 69 |
+
const lines = this.buffer.split(RE_CRLF)
|
| 70 |
+
const len = lines.length
|
| 71 |
+
let m, h
|
| 72 |
+
|
| 73 |
+
for (var i = 0; i < len; ++i) { // eslint-disable-line no-var
|
| 74 |
+
if (lines[i].length === 0) { continue }
|
| 75 |
+
if (lines[i][0] === '\t' || lines[i][0] === ' ') {
|
| 76 |
+
// folded header content
|
| 77 |
+
// RFC2822 says to just remove the CRLF and not the whitespace following
|
| 78 |
+
// it, so we follow the RFC and include the leading whitespace ...
|
| 79 |
+
if (h) {
|
| 80 |
+
this.header[h][this.header[h].length - 1] += lines[i]
|
| 81 |
+
continue
|
| 82 |
+
}
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
const posColon = lines[i].indexOf(':')
|
| 86 |
+
if (
|
| 87 |
+
posColon === -1 ||
|
| 88 |
+
posColon === 0
|
| 89 |
+
) {
|
| 90 |
+
return
|
| 91 |
+
}
|
| 92 |
+
m = RE_HDR.exec(lines[i])
|
| 93 |
+
h = m[1].toLowerCase()
|
| 94 |
+
this.header[h] = this.header[h] || []
|
| 95 |
+
this.header[h].push((m[2] || ''))
|
| 96 |
+
if (++this.npairs === this.maxHeaderPairs) { break }
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
module.exports = HeaderParser
|
services/slides/node_modules/@fastify/busboy/deps/dicer/lib/PartStream.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
const inherits = require('node:util').inherits
|
| 4 |
+
const ReadableStream = require('node:stream').Readable
|
| 5 |
+
|
| 6 |
+
function PartStream (opts) {
|
| 7 |
+
ReadableStream.call(this, opts)
|
| 8 |
+
}
|
| 9 |
+
inherits(PartStream, ReadableStream)
|
| 10 |
+
|
| 11 |
+
PartStream.prototype._read = function (n) {}
|
| 12 |
+
|
| 13 |
+
module.exports = PartStream
|
services/slides/node_modules/@fastify/busboy/deps/dicer/lib/dicer.d.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Type definitions for dicer 0.2
|
| 2 |
+
// Project: https://github.com/mscdex/dicer
|
| 3 |
+
// Definitions by: BendingBender <https://github.com/BendingBender>
|
| 4 |
+
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
| 5 |
+
// TypeScript Version: 2.2
|
| 6 |
+
/// <reference types="node" />
|
| 7 |
+
|
| 8 |
+
import stream = require("stream");
|
| 9 |
+
|
| 10 |
+
// tslint:disable:unified-signatures
|
| 11 |
+
|
| 12 |
+
/**
|
| 13 |
+
* A very fast streaming multipart parser for node.js.
|
| 14 |
+
* Dicer is a WritableStream
|
| 15 |
+
*
|
| 16 |
+
* Dicer (special) events:
|
| 17 |
+
* - on('finish', ()) - Emitted when all parts have been parsed and the Dicer instance has been ended.
|
| 18 |
+
* - on('part', (stream: PartStream)) - Emitted when a new part has been found.
|
| 19 |
+
* - on('preamble', (stream: PartStream)) - Emitted for preamble if you should happen to need it (can usually be ignored).
|
| 20 |
+
* - on('trailer', (data: Buffer)) - Emitted when trailing data was found after the terminating boundary (as with the preamble, this can usually be ignored too).
|
| 21 |
+
*/
|
| 22 |
+
export class Dicer extends stream.Writable {
|
| 23 |
+
/**
|
| 24 |
+
* Creates and returns a new Dicer instance with the following valid config settings:
|
| 25 |
+
*
|
| 26 |
+
* @param config The configuration to use
|
| 27 |
+
*/
|
| 28 |
+
constructor(config: Dicer.Config);
|
| 29 |
+
/**
|
| 30 |
+
* Sets the boundary to use for parsing and performs some initialization needed for parsing.
|
| 31 |
+
* You should only need to use this if you set headerFirst to true in the constructor and are parsing the boundary from the preamble header.
|
| 32 |
+
*
|
| 33 |
+
* @param boundary The boundary to use
|
| 34 |
+
*/
|
| 35 |
+
setBoundary(boundary: string): void;
|
| 36 |
+
addListener(event: "finish", listener: () => void): this;
|
| 37 |
+
addListener(event: "part", listener: (stream: Dicer.PartStream) => void): this;
|
| 38 |
+
addListener(event: "preamble", listener: (stream: Dicer.PartStream) => void): this;
|
| 39 |
+
addListener(event: "trailer", listener: (data: Buffer) => void): this;
|
| 40 |
+
addListener(event: "close", listener: () => void): this;
|
| 41 |
+
addListener(event: "drain", listener: () => void): this;
|
| 42 |
+
addListener(event: "error", listener: (err: Error) => void): this;
|
| 43 |
+
addListener(event: "pipe", listener: (src: stream.Readable) => void): this;
|
| 44 |
+
addListener(event: "unpipe", listener: (src: stream.Readable) => void): this;
|
| 45 |
+
addListener(event: string, listener: (...args: any[]) => void): this;
|
| 46 |
+
on(event: "finish", listener: () => void): this;
|
| 47 |
+
on(event: "part", listener: (stream: Dicer.PartStream) => void): this;
|
| 48 |
+
on(event: "preamble", listener: (stream: Dicer.PartStream) => void): this;
|
| 49 |
+
on(event: "trailer", listener: (data: Buffer) => void): this;
|
| 50 |
+
on(event: "close", listener: () => void): this;
|
| 51 |
+
on(event: "drain", listener: () => void): this;
|
| 52 |
+
on(event: "error", listener: (err: Error) => void): this;
|
| 53 |
+
on(event: "pipe", listener: (src: stream.Readable) => void): this;
|
| 54 |
+
on(event: "unpipe", listener: (src: stream.Readable) => void): this;
|
| 55 |
+
on(event: string, listener: (...args: any[]) => void): this;
|
| 56 |
+
once(event: "finish", listener: () => void): this;
|
| 57 |
+
once(event: "part", listener: (stream: Dicer.PartStream) => void): this;
|
| 58 |
+
once(event: "preamble", listener: (stream: Dicer.PartStream) => void): this;
|
| 59 |
+
once(event: "trailer", listener: (data: Buffer) => void): this;
|
| 60 |
+
once(event: "close", listener: () => void): this;
|
| 61 |
+
once(event: "drain", listener: () => void): this;
|
| 62 |
+
once(event: "error", listener: (err: Error) => void): this;
|
| 63 |
+
once(event: "pipe", listener: (src: stream.Readable) => void): this;
|
| 64 |
+
once(event: "unpipe", listener: (src: stream.Readable) => void): this;
|
| 65 |
+
once(event: string, listener: (...args: any[]) => void): this;
|
| 66 |
+
prependListener(event: "finish", listener: () => void): this;
|
| 67 |
+
prependListener(event: "part", listener: (stream: Dicer.PartStream) => void): this;
|
| 68 |
+
prependListener(event: "preamble", listener: (stream: Dicer.PartStream) => void): this;
|
| 69 |
+
prependListener(event: "trailer", listener: (data: Buffer) => void): this;
|
| 70 |
+
prependListener(event: "close", listener: () => void): this;
|
| 71 |
+
prependListener(event: "drain", listener: () => void): this;
|
| 72 |
+
prependListener(event: "error", listener: (err: Error) => void): this;
|
| 73 |
+
prependListener(event: "pipe", listener: (src: stream.Readable) => void): this;
|
| 74 |
+
prependListener(event: "unpipe", listener: (src: stream.Readable) => void): this;
|
| 75 |
+
prependListener(event: string, listener: (...args: any[]) => void): this;
|
| 76 |
+
prependOnceListener(event: "finish", listener: () => void): this;
|
| 77 |
+
prependOnceListener(event: "part", listener: (stream: Dicer.PartStream) => void): this;
|
| 78 |
+
prependOnceListener(event: "preamble", listener: (stream: Dicer.PartStream) => void): this;
|
| 79 |
+
prependOnceListener(event: "trailer", listener: (data: Buffer) => void): this;
|
| 80 |
+
prependOnceListener(event: "close", listener: () => void): this;
|
| 81 |
+
prependOnceListener(event: "drain", listener: () => void): this;
|
| 82 |
+
prependOnceListener(event: "error", listener: (err: Error) => void): this;
|
| 83 |
+
prependOnceListener(event: "pipe", listener: (src: stream.Readable) => void): this;
|
| 84 |
+
prependOnceListener(event: "unpipe", listener: (src: stream.Readable) => void): this;
|
| 85 |
+
prependOnceListener(event: string, listener: (...args: any[]) => void): this;
|
| 86 |
+
removeListener(event: "finish", listener: () => void): this;
|
| 87 |
+
removeListener(event: "part", listener: (stream: Dicer.PartStream) => void): this;
|
| 88 |
+
removeListener(event: "preamble", listener: (stream: Dicer.PartStream) => void): this;
|
| 89 |
+
removeListener(event: "trailer", listener: (data: Buffer) => void): this;
|
| 90 |
+
removeListener(event: "close", listener: () => void): this;
|
| 91 |
+
removeListener(event: "drain", listener: () => void): this;
|
| 92 |
+
removeListener(event: "error", listener: (err: Error) => void): this;
|
| 93 |
+
removeListener(event: "pipe", listener: (src: stream.Readable) => void): this;
|
| 94 |
+
removeListener(event: "unpipe", listener: (src: stream.Readable) => void): this;
|
| 95 |
+
removeListener(event: string, listener: (...args: any[]) => void): this;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
declare namespace Dicer {
|
| 99 |
+
interface Config {
|
| 100 |
+
/**
|
| 101 |
+
* This is the boundary used to detect the beginning of a new part.
|
| 102 |
+
*/
|
| 103 |
+
boundary?: string | undefined;
|
| 104 |
+
/**
|
| 105 |
+
* If true, preamble header parsing will be performed first.
|
| 106 |
+
*/
|
| 107 |
+
headerFirst?: boolean | undefined;
|
| 108 |
+
/**
|
| 109 |
+
* The maximum number of header key=>value pairs to parse Default: 2000 (same as node's http).
|
| 110 |
+
*/
|
| 111 |
+
maxHeaderPairs?: number | undefined;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
/**
|
| 115 |
+
* PartStream is a _ReadableStream_
|
| 116 |
+
*
|
| 117 |
+
* PartStream (special) events:
|
| 118 |
+
* - on('header', (header: object)) - An object containing the header for this particular part. Each property value is an array of one or more string values.
|
| 119 |
+
*/
|
| 120 |
+
interface PartStream extends stream.Readable {
|
| 121 |
+
addListener(event: "header", listener: (header: object) => void): this;
|
| 122 |
+
addListener(event: "close", listener: () => void): this;
|
| 123 |
+
addListener(event: "data", listener: (chunk: Buffer | string) => void): this;
|
| 124 |
+
addListener(event: "end", listener: () => void): this;
|
| 125 |
+
addListener(event: "readable", listener: () => void): this;
|
| 126 |
+
addListener(event: "error", listener: (err: Error) => void): this;
|
| 127 |
+
addListener(event: string, listener: (...args: any[]) => void): this;
|
| 128 |
+
on(event: "header", listener: (header: object) => void): this;
|
| 129 |
+
on(event: "close", listener: () => void): this;
|
| 130 |
+
on(event: "data", listener: (chunk: Buffer | string) => void): this;
|
| 131 |
+
on(event: "end", listener: () => void): this;
|
| 132 |
+
on(event: "readable", listener: () => void): this;
|
| 133 |
+
on(event: "error", listener: (err: Error) => void): this;
|
| 134 |
+
on(event: string, listener: (...args: any[]) => void): this;
|
| 135 |
+
once(event: "header", listener: (header: object) => void): this;
|
| 136 |
+
once(event: "close", listener: () => void): this;
|
| 137 |
+
once(event: "data", listener: (chunk: Buffer | string) => void): this;
|
| 138 |
+
once(event: "end", listener: () => void): this;
|
| 139 |
+
once(event: "readable", listener: () => void): this;
|
| 140 |
+
once(event: "error", listener: (err: Error) => void): this;
|
| 141 |
+
once(event: string, listener: (...args: any[]) => void): this;
|
| 142 |
+
prependListener(event: "header", listener: (header: object) => void): this;
|
| 143 |
+
prependListener(event: "close", listener: () => void): this;
|
| 144 |
+
prependListener(event: "data", listener: (chunk: Buffer | string) => void): this;
|
| 145 |
+
prependListener(event: "end", listener: () => void): this;
|
| 146 |
+
prependListener(event: "readable", listener: () => void): this;
|
| 147 |
+
prependListener(event: "error", listener: (err: Error) => void): this;
|
| 148 |
+
prependListener(event: string, listener: (...args: any[]) => void): this;
|
| 149 |
+
prependOnceListener(event: "header", listener: (header: object) => void): this;
|
| 150 |
+
prependOnceListener(event: "close", listener: () => void): this;
|
| 151 |
+
prependOnceListener(event: "data", listener: (chunk: Buffer | string) => void): this;
|
| 152 |
+
prependOnceListener(event: "end", listener: () => void): this;
|
| 153 |
+
prependOnceListener(event: "readable", listener: () => void): this;
|
| 154 |
+
prependOnceListener(event: "error", listener: (err: Error) => void): this;
|
| 155 |
+
prependOnceListener(event: string, listener: (...args: any[]) => void): this;
|
| 156 |
+
removeListener(event: "header", listener: (header: object) => void): this;
|
| 157 |
+
removeListener(event: "close", listener: () => void): this;
|
| 158 |
+
removeListener(event: "data", listener: (chunk: Buffer | string) => void): this;
|
| 159 |
+
removeListener(event: "end", listener: () => void): this;
|
| 160 |
+
removeListener(event: "readable", listener: () => void): this;
|
| 161 |
+
removeListener(event: "error", listener: (err: Error) => void): this;
|
| 162 |
+
removeListener(event: string, listener: (...args: any[]) => void): this;
|
| 163 |
+
}
|
| 164 |
+
}
|
services/slides/node_modules/@fastify/busboy/deps/streamsearch/sbmh.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use strict'
|
| 2 |
+
|
| 3 |
+
/**
|
| 4 |
+
* Copyright Brian White. All rights reserved.
|
| 5 |
+
*
|
| 6 |
+
* @see https://github.com/mscdex/streamsearch
|
| 7 |
+
*
|
| 8 |
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 9 |
+
* of this software and associated documentation files (the "Software"), to
|
| 10 |
+
* deal in the Software without restriction, including without limitation the
|
| 11 |
+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
| 12 |
+
* sell copies of the Software, and to permit persons to whom the Software is
|
| 13 |
+
* furnished to do so, subject to the following conditions:
|
| 14 |
+
*
|
| 15 |
+
* The above copyright notice and this permission notice shall be included in
|
| 16 |
+
* all copies or substantial portions of the Software.
|
| 17 |
+
*
|
| 18 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 19 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 20 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 21 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 22 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
| 23 |
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
| 24 |
+
* IN THE SOFTWARE.
|
| 25 |
+
*
|
| 26 |
+
* Based heavily on the Streaming Boyer-Moore-Horspool C++ implementation
|
| 27 |
+
* by Hongli Lai at: https://github.com/FooBarWidget/boyer-moore-horspool
|
| 28 |
+
*/
|
| 29 |
+
|
| 30 |
+
const { EventEmitter } = require('node:events')
|
| 31 |
+
const { inherits } = require('node:util')
|
| 32 |
+
|
| 33 |
+
function SBMH (needle) {
|
| 34 |
+
if (typeof needle === 'string') {
|
| 35 |
+
needle = Buffer.from(needle)
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
if (!Buffer.isBuffer(needle)) {
|
| 39 |
+
throw new TypeError('The needle has to be a String or a Buffer.')
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
const needleLength = needle.length
|
| 43 |
+
const needleLastCharIndex = needleLength - 1
|
| 44 |
+
|
| 45 |
+
if (needleLength === 0) {
|
| 46 |
+
throw new Error('The needle cannot be an empty String/Buffer.')
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
if (needleLength > 256) {
|
| 50 |
+
throw new Error('The needle cannot have a length bigger than 256.')
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
this.maxMatches = Infinity
|
| 54 |
+
this.matches = 0
|
| 55 |
+
|
| 56 |
+
this._occ = new Uint8Array(256)
|
| 57 |
+
.fill(needleLength) // Initialize occurrence table.
|
| 58 |
+
this._lookbehind_size = 0
|
| 59 |
+
this._needle = needle
|
| 60 |
+
this._bufpos = 0
|
| 61 |
+
|
| 62 |
+
this._lookbehind = Buffer.alloc(needleLastCharIndex)
|
| 63 |
+
|
| 64 |
+
// Populate occurrence table with analysis of the needle,
|
| 65 |
+
// ignoring last letter.
|
| 66 |
+
for (var i = 0; i < needleLastCharIndex; ++i) { // eslint-disable-line no-var
|
| 67 |
+
this._occ[needle[i]] = needleLastCharIndex - i
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
inherits(SBMH, EventEmitter)
|
| 71 |
+
|
| 72 |
+
SBMH.prototype.reset = function () {
|
| 73 |
+
this._lookbehind_size = 0
|
| 74 |
+
this.matches = 0
|
| 75 |
+
this._bufpos = 0
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
SBMH.prototype.push = function (chunk, pos) {
|
| 79 |
+
if (!Buffer.isBuffer(chunk)) {
|
| 80 |
+
chunk = Buffer.from(chunk, 'binary')
|
| 81 |
+
}
|
| 82 |
+
const chlen = chunk.length
|
| 83 |
+
this._bufpos = pos || 0
|
| 84 |
+
let r
|
| 85 |
+
while (r !== chlen && this.matches < this.maxMatches) { r = this._sbmh_feed(chunk) }
|
| 86 |
+
return r
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
SBMH.prototype._sbmh_feed = function (data) {
|
| 90 |
+
const len = data.length
|
| 91 |
+
const needle = this._needle
|
| 92 |
+
const needleLength = needle.length
|
| 93 |
+
const needleLastCharIndex = needleLength - 1
|
| 94 |
+
const needleLastChar = needle[needleLastCharIndex]
|
| 95 |
+
|
| 96 |
+
// Positive: points to a position in `data`
|
| 97 |
+
// pos == 3 points to data[3]
|
| 98 |
+
// Negative: points to a position in the lookbehind buffer
|
| 99 |
+
// pos == -2 points to lookbehind[lookbehind_size - 2]
|
| 100 |
+
let pos = -this._lookbehind_size
|
| 101 |
+
let ch
|
| 102 |
+
|
| 103 |
+
if (pos < 0) {
|
| 104 |
+
// Lookbehind buffer is not empty. Perform Boyer-Moore-Horspool
|
| 105 |
+
// search with character lookup code that considers both the
|
| 106 |
+
// lookbehind buffer and the current round's haystack data.
|
| 107 |
+
//
|
| 108 |
+
// Loop until
|
| 109 |
+
// there is a match.
|
| 110 |
+
// or until
|
| 111 |
+
// we've moved past the position that requires the
|
| 112 |
+
// lookbehind buffer. In this case we switch to the
|
| 113 |
+
// optimized loop.
|
| 114 |
+
// or until
|
| 115 |
+
// the character to look at lies outside the haystack.
|
| 116 |
+
while (pos < 0 && pos <= len - needleLength) {
|
| 117 |
+
ch = data[pos + needleLastCharIndex]
|
| 118 |
+
|
| 119 |
+
if (
|
| 120 |
+
ch === needleLastChar &&
|
| 121 |
+
this._sbmh_memcmp(data, pos, needleLastCharIndex)
|
| 122 |
+
) {
|
| 123 |
+
this._lookbehind_size = 0
|
| 124 |
+
++this.matches
|
| 125 |
+
this.emit('info', true)
|
| 126 |
+
return (this._bufpos = pos + needleLength)
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
pos += this._occ[ch]
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
// No match.
|
| 133 |
+
|
| 134 |
+
while (pos < 0 && !this._sbmh_memcmp(data, pos, len - pos)) {
|
| 135 |
+
// There's too few data for Boyer-Moore-Horspool to run,
|
| 136 |
+
// so let's use a different algorithm to skip as much as
|
| 137 |
+
// we can.
|
| 138 |
+
// Forward pos until
|
| 139 |
+
// the trailing part of lookbehind + data
|
| 140 |
+
// looks like the beginning of the needle
|
| 141 |
+
// or until
|
| 142 |
+
// pos == 0
|
| 143 |
+
++pos
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
if (pos >= 0) {
|
| 147 |
+
// Discard lookbehind buffer.
|
| 148 |
+
this.emit('info', false, this._lookbehind, 0, this._lookbehind_size)
|
| 149 |
+
this._lookbehind_size = 0
|
| 150 |
+
} else {
|
| 151 |
+
// Cut off part of the lookbehind buffer that has
|
| 152 |
+
// been processed and append the entire haystack
|
| 153 |
+
// into it.
|
| 154 |
+
const bytesToCutOff = this._lookbehind_size + pos
|
| 155 |
+
if (bytesToCutOff > 0) {
|
| 156 |
+
// The cut off data is guaranteed not to contain the needle.
|
| 157 |
+
this.emit('info', false, this._lookbehind, 0, bytesToCutOff)
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
this._lookbehind_size -= bytesToCutOff
|
| 161 |
+
this._lookbehind.copy(this._lookbehind, 0, bytesToCutOff, this._lookbehind_size)
|
| 162 |
+
|
| 163 |
+
data.copy(this._lookbehind, this._lookbehind_size)
|
| 164 |
+
this._lookbehind_size += len
|
| 165 |
+
|
| 166 |
+
this._bufpos = len
|
| 167 |
+
return len
|
| 168 |
+
}
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
// Lookbehind buffer is now empty. We only need to check if the
|
| 172 |
+
// needle is in the haystack.
|
| 173 |
+
pos = data.indexOf(needle, pos + this._bufpos)
|
| 174 |
+
|
| 175 |
+
if (pos !== -1) {
|
| 176 |
+
++this.matches
|
| 177 |
+
if (pos === 0) { this.emit('info', true) } else { this.emit('info', true, data, this._bufpos, pos) }
|
| 178 |
+
return (this._bufpos = pos + needleLength)
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
pos = len - needleLastCharIndex
|
| 182 |
+
if (pos < 0) {
|
| 183 |
+
pos = 0
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
// There was no match. If there's trailing haystack data that we cannot
|
| 187 |
+
// match yet using the Boyer-Moore-Horspool algorithm (because the trailing
|
| 188 |
+
// data is less than the needle size) then match using a modified
|
| 189 |
+
// algorithm that starts matching from the beginning instead of the end.
|
| 190 |
+
// Whatever trailing data is left after running this algorithm is added to
|
| 191 |
+
// the lookbehind buffer.
|
| 192 |
+
while (
|
| 193 |
+
pos !== len &&
|
| 194 |
+
(
|
| 195 |
+
data[pos] !== needle[0] ||
|
| 196 |
+
Buffer.compare(
|
| 197 |
+
data.subarray(pos + 1, len),
|
| 198 |
+
needle.subarray(1, len - pos)
|
| 199 |
+
) !== 0
|
| 200 |
+
)
|
| 201 |
+
) {
|
| 202 |
+
++pos
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
if (pos !== len) {
|
| 206 |
+
data.copy(this._lookbehind, 0, pos, len)
|
| 207 |
+
this._lookbehind_size = len - pos
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
// Everything until pos is guaranteed not to contain needle data.
|
| 211 |
+
if (pos !== 0) { this.emit('info', false, data, this._bufpos, pos) }
|
| 212 |
+
|
| 213 |
+
this._bufpos = len
|
| 214 |
+
return len
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
SBMH.prototype._sbmh_lookup_char = function (data, pos) {
|
| 218 |
+
return pos < 0
|
| 219 |
+
? this._lookbehind[this._lookbehind_size + pos]
|
| 220 |
+
: data[pos]
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
SBMH.prototype._sbmh_memcmp = function (data, pos, len) {
|
| 224 |
+
for (var i = 0; i < len; ++i) { // eslint-disable-line no-var
|
| 225 |
+
if (this._sbmh_lookup_char(data, pos + i) !== this._needle[i]) { return false }
|
| 226 |
+
}
|
| 227 |
+
return true
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
module.exports = SBMH
|