wassemgtk commited on
Commit
0eaa85f
·
verified ·
1 Parent(s): 092fd7d

Add slide renderer source for one-click deployment

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +3 -0
  2. services/slides/Dockerfile +10 -0
  3. services/slides/dist/charts.js +7 -0
  4. services/slides/dist/layouts.js +1 -0
  5. services/slides/dist/render.js +55 -0
  6. services/slides/dist/server.js +28 -0
  7. services/slides/dist/themes.js +15 -0
  8. services/slides/node_modules/.bin/esbuild +3 -0
  9. services/slides/node_modules/.bin/image-size +53 -0
  10. services/slides/node_modules/.bin/pino +6 -0
  11. services/slides/node_modules/.bin/safe-regex2 +58 -0
  12. services/slides/node_modules/.bin/semver +195 -0
  13. services/slides/node_modules/.bin/tsc +2 -0
  14. services/slides/node_modules/.bin/tsserver +2 -0
  15. services/slides/node_modules/.bin/tsx +0 -0
  16. services/slides/node_modules/.package-lock.json +959 -0
  17. services/slides/node_modules/@esbuild/darwin-arm64/README.md +3 -0
  18. services/slides/node_modules/@esbuild/darwin-arm64/bin/esbuild +3 -0
  19. services/slides/node_modules/@esbuild/darwin-arm64/package.json +20 -0
  20. services/slides/node_modules/@fastify/ajv-compiler/.gitattributes +2 -0
  21. services/slides/node_modules/@fastify/ajv-compiler/.github/.stale.yml +21 -0
  22. services/slides/node_modules/@fastify/ajv-compiler/.github/dependabot.yml +13 -0
  23. services/slides/node_modules/@fastify/ajv-compiler/.github/tests_checker.yml +8 -0
  24. services/slides/node_modules/@fastify/ajv-compiler/.github/workflows/ci.yml +33 -0
  25. services/slides/node_modules/@fastify/ajv-compiler/LICENSE +23 -0
  26. services/slides/node_modules/@fastify/ajv-compiler/README.md +237 -0
  27. services/slides/node_modules/@fastify/ajv-compiler/benchmark/small-object.mjs +37 -0
  28. services/slides/node_modules/@fastify/ajv-compiler/eslint.config.js +6 -0
  29. services/slides/node_modules/@fastify/ajv-compiler/index.js +53 -0
  30. services/slides/node_modules/@fastify/ajv-compiler/lib/default-ajv-options.js +14 -0
  31. services/slides/node_modules/@fastify/ajv-compiler/lib/serializer-compiler.js +27 -0
  32. services/slides/node_modules/@fastify/ajv-compiler/lib/validator-compiler.js +58 -0
  33. services/slides/node_modules/@fastify/ajv-compiler/package.json +84 -0
  34. services/slides/node_modules/@fastify/ajv-compiler/standalone.js +44 -0
  35. services/slides/node_modules/@fastify/ajv-compiler/test/.gitkeep +0 -0
  36. services/slides/node_modules/@fastify/ajv-compiler/test/duplicated-id-compile.test.js +55 -0
  37. services/slides/node_modules/@fastify/ajv-compiler/test/index.test.js +307 -0
  38. services/slides/node_modules/@fastify/ajv-compiler/test/plugins.test.js +246 -0
  39. services/slides/node_modules/@fastify/ajv-compiler/test/serialization.test.js +279 -0
  40. services/slides/node_modules/@fastify/ajv-compiler/test/standalone.test.js +203 -0
  41. services/slides/node_modules/@fastify/ajv-compiler/types/index.d.ts +87 -0
  42. services/slides/node_modules/@fastify/ajv-compiler/types/index.test-d.ts +302 -0
  43. services/slides/node_modules/@fastify/busboy/LICENSE +24 -0
  44. services/slides/node_modules/@fastify/busboy/README.md +270 -0
  45. services/slides/node_modules/@fastify/busboy/deps/dicer/LICENSE +19 -0
  46. services/slides/node_modules/@fastify/busboy/deps/dicer/lib/Dicer.js +213 -0
  47. services/slides/node_modules/@fastify/busboy/deps/dicer/lib/HeaderParser.js +100 -0
  48. services/slides/node_modules/@fastify/busboy/deps/dicer/lib/PartStream.js +13 -0
  49. services/slides/node_modules/@fastify/busboy/deps/dicer/lib/dicer.d.ts +164 -0
  50. 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
+ [![CI](https://github.com/fastify/ajv-compiler/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/ajv-compiler/actions/workflows/ci.yml)
4
+ [![NPM version](https://img.shields.io/npm/v/@fastify/ajv-compiler.svg?style=flat)](https://www.npmjs.com/package/@fastify/ajv-compiler)
5
+ [![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](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
+ [![Build Status](https://github.com/fastify/busboy/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/busboy/actions)
6
+ [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)
7
+ [![Security Responsible Disclosure](https://img.shields.io/badge/Security-Responsible%20Disclosure-yellow.svg)](https://github.com/fastify/.github/blob/main/SECURITY.md)
8
+
9
+ </div>
10
+
11
+ <div align="center">
12
+
13
+ [![NPM version](https://img.shields.io/npm/v/@fastify/busboy.svg?style=flat)](https://www.npmjs.com/package/@fastify/busboy)
14
+ [![NPM downloads](https://img.shields.io/npm/dm/@fastify/busboy.svg?style=flat)](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