完整代码加修复数据库连接字符串!!!
This commit is contained in:
2
.env
2
.env
@@ -1,5 +1,5 @@
|
|||||||
# 替换成你自己的 MongoDB Atlas 或本地数据库的连接字符串
|
# 替换成你自己的 MongoDB Atlas 或本地数据库的连接字符串
|
||||||
MONGO_URI="mongodb+srv://<username>:<password>@<cluster-url>/<database-name>?retryWrites=true&w=majority"
|
MONGO_URI="mongodb://mongo_c6bNmG:mongo_tyNkXh@83.229.121.44:27017/?authSource=admin"
|
||||||
|
|
||||||
# 指定你要操作的数据库名称
|
# 指定你要操作的数据库名称
|
||||||
DATABASE_NAME="todo_app_fastify"
|
DATABASE_NAME="todo_app_fastify"
|
||||||
38
db-connector.js
Normal file
38
db-connector.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
const fastifyPlugin = require('fastify-plugin');
|
||||||
|
const { MongoClient } = require('mongodb');
|
||||||
|
|
||||||
|
async function dbConnector(fastify, options) {
|
||||||
|
const url = process.env.MONGO_URI;
|
||||||
|
const dbName = process.env.DATABASE_NAME;
|
||||||
|
|
||||||
|
if (!url) {
|
||||||
|
throw new Error('MONGO_URI must be defined in your .env file');
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = new MongoClient(url);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
fastify.log.info('成功连接到 MongoDB 数据库!');
|
||||||
|
|
||||||
|
const db = client.db(dbName);
|
||||||
|
|
||||||
|
// 使用 fastify.decorate 将数据库实例和 ObjectId 挂载到 Fastify 实例上
|
||||||
|
// 这样在所有路由中都可以通过 fastify.mongo.db 访问
|
||||||
|
fastify.decorate('mongo', { db });
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
// 如果连接失败,可以选择关闭 fastify 实例或抛出错误
|
||||||
|
throw new Error('数据库连接失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保在服务器关闭时断开数据库连接
|
||||||
|
fastify.addHook('onClose', async (instance) => {
|
||||||
|
await client.close();
|
||||||
|
instance.log.info('MongoDB 数据库连接已断开。');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 fastify-plugin 包装,防止 Fastify 对插件进行不必要的封装
|
||||||
|
module.exports = fastifyPlugin(dbConnector);
|
||||||
6
node_modules/.package-lock.json
generated
vendored
6
node_modules/.package-lock.json
generated
vendored
@@ -319,6 +319,12 @@
|
|||||||
"toad-cache": "^3.7.0"
|
"toad-cache": "^3.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fastify-plugin": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fastq": {
|
"node_modules/fastq": {
|
||||||
"version": "1.19.1",
|
"version": "1.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
|
||||||
|
|||||||
2
node_modules/fastify-plugin/.gitattributes
generated
vendored
Normal file
2
node_modules/fastify-plugin/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Set default behavior to automatically convert line endings
|
||||||
|
* text=auto eol=lf
|
||||||
13
node_modules/fastify-plugin/.github/dependabot.yml
generated
vendored
Normal file
13
node_modules/fastify-plugin/.github/dependabot.yml
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "monthly"
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
|
||||||
|
- package-ecosystem: "npm"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
open-pull-requests-limit: 10
|
||||||
21
node_modules/fastify-plugin/.github/stale.yml
generated
vendored
Normal file
21
node_modules/fastify-plugin/.github/stale.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Number of days of inactivity before an issue becomes stale
|
||||||
|
daysUntilStale: 15
|
||||||
|
# Number of days of inactivity before a stale issue is closed
|
||||||
|
daysUntilClose: 7
|
||||||
|
# Issues with these labels will never be considered stale
|
||||||
|
exemptLabels:
|
||||||
|
- "discussion"
|
||||||
|
- "feature request"
|
||||||
|
- "bug"
|
||||||
|
- "help wanted"
|
||||||
|
- "plugin suggestion"
|
||||||
|
- "good first issue"
|
||||||
|
# Label to use when marking an issue as stale
|
||||||
|
staleLabel: stale
|
||||||
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
|
closeComment: false
|
||||||
23
node_modules/fastify-plugin/.github/workflows/ci.yml
generated
vendored
Normal file
23
node_modules/fastify-plugin/.github/workflows/ci.yml
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- next
|
||||||
|
- 'v*'
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- '*.md'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- '*.md'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5.0.0
|
||||||
|
with:
|
||||||
|
lint: true
|
||||||
|
license-check: true
|
||||||
21
node_modules/fastify-plugin/LICENSE
generated
vendored
Normal file
21
node_modules/fastify-plugin/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Fastify
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
188
node_modules/fastify-plugin/README.md
generated
vendored
Normal file
188
node_modules/fastify-plugin/README.md
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
# fastify-plugin
|
||||||
|
|
||||||
|

|
||||||
|
[](https://www.npmjs.com/package/fastify-plugin)
|
||||||
|
[](https://standardjs.com/)
|
||||||
|
|
||||||
|
`fastify-plugin` is a plugin helper for [Fastify](https://github.com/fastify/fastify).
|
||||||
|
|
||||||
|
When you build plugins for Fastify and you want them to be accessible in the same context where you require them, you have two ways:
|
||||||
|
1. Use the `skip-override` hidden property
|
||||||
|
2. Use this module
|
||||||
|
|
||||||
|
__Note: the v4.x series of this module covers Fastify v4__
|
||||||
|
__Note: the v2.x & v3.x series of this module covers Fastify v3. For Fastify v2 support, refer to the v1.x series.__
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i fastify-plugin
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
`fastify-plugin` can do three things for you:
|
||||||
|
- Add the `skip-override` hidden property
|
||||||
|
- Check the bare-minimum version of Fastify
|
||||||
|
- Pass some custom metadata of the plugin to Fastify
|
||||||
|
|
||||||
|
Example using a callback:
|
||||||
|
```js
|
||||||
|
const fp = require('fastify-plugin')
|
||||||
|
|
||||||
|
module.exports = fp(function (fastify, opts, done) {
|
||||||
|
// your plugin code
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
Example using an [async](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) function:
|
||||||
|
```js
|
||||||
|
const fp = require('fastify-plugin')
|
||||||
|
|
||||||
|
// A callback function param is not required for async functions
|
||||||
|
module.exports = fp(async function (fastify, opts) {
|
||||||
|
// Wait for an async function to fulfill promise before proceeding
|
||||||
|
await exampleAsyncFunction()
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
In addition, if you use this module when creating new plugins, you can declare the dependencies, the name, and the expected Fastify version that your plugin needs.
|
||||||
|
|
||||||
|
#### Fastify version
|
||||||
|
If you need to set a bare-minimum version of Fastify for your plugin, just add the [semver](https://semver.org/) range that you need:
|
||||||
|
```js
|
||||||
|
const fp = require('fastify-plugin')
|
||||||
|
|
||||||
|
module.exports = fp(function (fastify, opts, done) {
|
||||||
|
// your plugin code
|
||||||
|
done()
|
||||||
|
}, { fastify: '5.x' })
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to check the Fastify version only, you can pass just the version string.
|
||||||
|
|
||||||
|
You can check [here](https://github.com/npm/node-semver#ranges) how to define a `semver` range.
|
||||||
|
|
||||||
|
#### Name
|
||||||
|
Fastify uses this option to validate the dependency graph, allowing it to ensure that no name collisions occur and making it possible to perform [dependency checks](https://github.com/fastify/fastify-plugin#dependencies).
|
||||||
|
|
||||||
|
```js
|
||||||
|
const fp = require('fastify-plugin')
|
||||||
|
|
||||||
|
function plugin (fastify, opts, done) {
|
||||||
|
// your plugin code
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = fp(plugin, {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'your-plugin-name'
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Dependencies
|
||||||
|
You can also check if the `plugins` and `decorators` that your plugin intend to use are present in the dependency graph.
|
||||||
|
> *Note:* This is the point where registering `name` of the plugins become important, because you can reference `plugin` dependencies by their [name](https://github.com/fastify/fastify-plugin#name).
|
||||||
|
```js
|
||||||
|
const fp = require('fastify-plugin')
|
||||||
|
|
||||||
|
function plugin (fastify, opts, done) {
|
||||||
|
// your plugin code
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = fp(plugin, {
|
||||||
|
fastify: '5.x',
|
||||||
|
decorators: {
|
||||||
|
fastify: ['plugin1', 'plugin2'],
|
||||||
|
reply: ['compress']
|
||||||
|
},
|
||||||
|
dependencies: ['plugin1-name', 'plugin2-name']
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Encapsulate
|
||||||
|
|
||||||
|
By default, `fastify-plugin` breaks the [encapsulation](https://github.com/fastify/fastify/blob/HEAD/docs/Reference/Encapsulation.md) but you can optionally keep the plugin encapsulated.
|
||||||
|
This allows you to set the plugin's name and validate its dependencies without making the plugin accessible.
|
||||||
|
```js
|
||||||
|
const fp = require('fastify-plugin')
|
||||||
|
|
||||||
|
function plugin (fastify, opts, done) {
|
||||||
|
// the decorator is not accessible outside this plugin
|
||||||
|
fastify.decorate('util', function() {})
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = fp(plugin, {
|
||||||
|
name: 'my-encapsulated-plugin',
|
||||||
|
fastify: '5.x',
|
||||||
|
decorators: {
|
||||||
|
fastify: ['plugin1', 'plugin2'],
|
||||||
|
reply: ['compress']
|
||||||
|
},
|
||||||
|
dependencies: ['plugin1-name', 'plugin2-name'],
|
||||||
|
encapsulate: true
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Bundlers and Typescript
|
||||||
|
`fastify-plugin` adds a `.default` and `[name]` property to the passed in function.
|
||||||
|
The type definition would have to be updated to leverage this.
|
||||||
|
|
||||||
|
## Known Issue: TypeScript Contextual Inference
|
||||||
|
|
||||||
|
[Documentation Reference](https://www.typescriptlang.org/docs/handbook/functions.html#inferring-the-types)
|
||||||
|
|
||||||
|
It is common for developers to inline their plugin with fastify-plugin such as:
|
||||||
|
|
||||||
|
```js
|
||||||
|
fp((fastify, opts, done) => { done() })
|
||||||
|
fp(async (fastify, opts) => { return })
|
||||||
|
```
|
||||||
|
|
||||||
|
TypeScript can sometimes infer the types of the arguments for these functions. Plugins in Fastify are recommended to be typed using either `FastifyPluginCallback` or `FastifyPluginAsync`. These two definitions only differ in two ways:
|
||||||
|
|
||||||
|
1. The third argument `done` (the callback part)
|
||||||
|
2. The return type `FastifyPluginCallback` or `FastifyPluginAsync`
|
||||||
|
|
||||||
|
At this time, TypeScript inference is not smart enough to differentiate by definition argument length alone.
|
||||||
|
|
||||||
|
Thus, if you are a TypeScript developer please use on the following patterns instead:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// Callback
|
||||||
|
|
||||||
|
// Assign type directly
|
||||||
|
const pluginCallback: FastifyPluginCallback = (fastify, options, done) => { }
|
||||||
|
fp(pluginCallback)
|
||||||
|
|
||||||
|
// or define your own function declaration that satisfies the existing definitions
|
||||||
|
const pluginCallbackWithTypes = (fastify: FastifyInstance, options: FastifyPluginOptions, done: (error?: FastifyError) => void): void => { }
|
||||||
|
fp(pluginCallbackWithTypes)
|
||||||
|
// or inline
|
||||||
|
fp((fastify: FastifyInstance, options: FastifyPluginOptions, done: (error?: FastifyError) => void): void => { })
|
||||||
|
|
||||||
|
// Async
|
||||||
|
|
||||||
|
// Assign type directly
|
||||||
|
const pluginAsync: FastifyPluginAsync = async (fastify, options) => { }
|
||||||
|
fp(pluginAsync)
|
||||||
|
|
||||||
|
// or define your own function declaration that satisfies the existing definitions
|
||||||
|
const pluginAsyncWithTypes = async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { }
|
||||||
|
fp(pluginAsyncWithTypes)
|
||||||
|
// or inline
|
||||||
|
fp(async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { })
|
||||||
|
```
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
This project is kindly sponsored by:
|
||||||
|
- [nearForm](https://nearform.com)
|
||||||
|
- [LetzDoIt](https://www.letzdoitapp.com/)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under [MIT](./LICENSE).
|
||||||
25
node_modules/fastify-plugin/lib/getPluginName.js
generated
vendored
Normal file
25
node_modules/fastify-plugin/lib/getPluginName.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const fpStackTracePattern = /at\s{1}(?:.*\.)?plugin\s{1}.*\n\s*(.*)/
|
||||||
|
const fileNamePattern = /(\w*(\.\w*)*)\..*/
|
||||||
|
|
||||||
|
module.exports = function getPluginName (fn) {
|
||||||
|
if (fn.name.length > 0) return fn.name
|
||||||
|
|
||||||
|
const stackTraceLimit = Error.stackTraceLimit
|
||||||
|
Error.stackTraceLimit = 10
|
||||||
|
try {
|
||||||
|
throw new Error('anonymous function')
|
||||||
|
} catch (e) {
|
||||||
|
Error.stackTraceLimit = stackTraceLimit
|
||||||
|
return extractPluginName(e.stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractPluginName (stack) {
|
||||||
|
const m = stack.match(fpStackTracePattern)
|
||||||
|
|
||||||
|
// get last section of path and match for filename
|
||||||
|
return m ? m[1].split(/[/\\]/).slice(-1)[0].match(fileNamePattern)[1] : 'anonymous'
|
||||||
|
}
|
||||||
|
module.exports.extractPluginName = extractPluginName
|
||||||
10
node_modules/fastify-plugin/lib/toCamelCase.js
generated
vendored
Normal file
10
node_modules/fastify-plugin/lib/toCamelCase.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
module.exports = function toCamelCase (name) {
|
||||||
|
if (name[0] === '@') {
|
||||||
|
name = name.slice(1).replace('/', '-')
|
||||||
|
}
|
||||||
|
return name.replace(/-(.)/g, function (match, g1) {
|
||||||
|
return g1.toUpperCase()
|
||||||
|
})
|
||||||
|
}
|
||||||
40
node_modules/fastify-plugin/package.json
generated
vendored
Normal file
40
node_modules/fastify-plugin/package.json
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "fastify-plugin",
|
||||||
|
"version": "5.0.1",
|
||||||
|
"description": "Plugin helper for Fastify",
|
||||||
|
"main": "plugin.js",
|
||||||
|
"type": "commonjs",
|
||||||
|
"types": "types/plugin.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"lint": "standard",
|
||||||
|
"test": "npm run test:unit && npm run test:typescript",
|
||||||
|
"test:unit": "c8 --100 node --test",
|
||||||
|
"test:coverage": "c8 node --test && c8 report --reporter=html",
|
||||||
|
"test:typescript": "tsd"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/fastify/fastify-plugin.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"plugin",
|
||||||
|
"helper",
|
||||||
|
"fastify"
|
||||||
|
],
|
||||||
|
"author": "Tomas Della Vedova - @delvedor (http://delved.org)",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/fastify/fastify-plugin/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/fastify/fastify-plugin#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"@fastify/pre-commit": "^2.1.0",
|
||||||
|
"@fastify/type-provider-typebox": "^5.0.0-pre.fv5.1",
|
||||||
|
"@types/node": "^22.0.0",
|
||||||
|
"c8": "^10.1.2",
|
||||||
|
"fastify": "^5.0.0",
|
||||||
|
"proxyquire": "^2.1.3",
|
||||||
|
"standard": "^17.1.0",
|
||||||
|
"tsd": "^0.31.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
67
node_modules/fastify-plugin/plugin.js
generated
vendored
Normal file
67
node_modules/fastify-plugin/plugin.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const getPluginName = require('./lib/getPluginName')
|
||||||
|
const toCamelCase = require('./lib/toCamelCase')
|
||||||
|
|
||||||
|
let count = 0
|
||||||
|
|
||||||
|
function plugin (fn, options = {}) {
|
||||||
|
let autoName = false
|
||||||
|
|
||||||
|
if (fn.default !== undefined) {
|
||||||
|
// Support for 'export default' behaviour in transpiled ECMAScript module
|
||||||
|
fn = fn.default
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof fn !== 'function') {
|
||||||
|
throw new TypeError(
|
||||||
|
`fastify-plugin expects a function, instead got a '${typeof fn}'`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string') {
|
||||||
|
options = {
|
||||||
|
fastify: options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof options !== 'object' ||
|
||||||
|
Array.isArray(options) ||
|
||||||
|
options === null
|
||||||
|
) {
|
||||||
|
throw new TypeError('The options object should be an object')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.fastify !== undefined && typeof options.fastify !== 'string') {
|
||||||
|
throw new TypeError(`fastify-plugin expects a version string, instead got '${typeof options.fastify}'`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.name) {
|
||||||
|
autoName = true
|
||||||
|
options.name = getPluginName(fn) + '-auto-' + count++
|
||||||
|
}
|
||||||
|
|
||||||
|
fn[Symbol.for('skip-override')] = options.encapsulate !== true
|
||||||
|
fn[Symbol.for('fastify.display-name')] = options.name
|
||||||
|
fn[Symbol.for('plugin-meta')] = options
|
||||||
|
|
||||||
|
// Faux modules support
|
||||||
|
if (!fn.default) {
|
||||||
|
fn.default = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeScript support for named imports
|
||||||
|
// See https://github.com/fastify/fastify/issues/2404 for more details
|
||||||
|
// The type definitions would have to be update to match this.
|
||||||
|
const camelCase = toCamelCase(options.name)
|
||||||
|
if (!autoName && !fn[camelCase]) {
|
||||||
|
fn[camelCase] = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
return fn
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = plugin
|
||||||
|
module.exports.default = plugin
|
||||||
|
module.exports.fastifyPlugin = plugin
|
||||||
110
node_modules/fastify-plugin/test/bundlers.test.js
generated
vendored
Normal file
110
node_modules/fastify-plugin/test/bundlers.test.js
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { test } = require('node:test')
|
||||||
|
const fp = require('../plugin')
|
||||||
|
|
||||||
|
test('webpack removes require.main.filename', t => {
|
||||||
|
const filename = require.main.filename
|
||||||
|
const info = console.info
|
||||||
|
t.after(() => {
|
||||||
|
require.main.filename = filename
|
||||||
|
console.info = info
|
||||||
|
})
|
||||||
|
|
||||||
|
require.main.filename = null
|
||||||
|
|
||||||
|
console.info = function (msg) {
|
||||||
|
t.assert.fail('logged: ' + msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
fastify: '^5.0.0'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('support faux modules', (t) => {
|
||||||
|
const plugin = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(plugin.default, plugin)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('support faux modules does not override existing default field in babel module', (t) => {
|
||||||
|
const module = {
|
||||||
|
default: (fastify, opts, next) => next()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.default.default = 'Existing default field'
|
||||||
|
|
||||||
|
const plugin = fp(module)
|
||||||
|
|
||||||
|
t.assert.strictEqual(plugin.default, 'Existing default field')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('support ts named imports', (t) => {
|
||||||
|
const plugin = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
name: 'hello'
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(plugin.hello, plugin)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('from kebab-case to camelCase', (t) => {
|
||||||
|
const plugin = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
name: 'hello-world'
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(plugin.helloWorld, plugin)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('from @-prefixed named imports', (t) => {
|
||||||
|
const plugin = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
name: '@hello/world'
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(plugin.helloWorld, plugin)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('from @-prefixed named kebab-case to camelCase', (t) => {
|
||||||
|
const plugin = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
name: '@hello/my-world'
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(plugin.helloMyWorld, plugin)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('from kebab-case to camelCase multiple words', (t) => {
|
||||||
|
const plugin = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
name: 'hello-long-world'
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(plugin.helloLongWorld, plugin)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('from kebab-case to camelCase multiple words does not override', (t) => {
|
||||||
|
const fn = (fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
const foobar = {}
|
||||||
|
fn.helloLongWorld = foobar
|
||||||
|
|
||||||
|
const plugin = fp(fn, {
|
||||||
|
name: 'hello-long-world'
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(plugin.helloLongWorld, foobar)
|
||||||
|
})
|
||||||
67
node_modules/fastify-plugin/test/checkVersion.test.js
generated
vendored
Normal file
67
node_modules/fastify-plugin/test/checkVersion.test.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { test } = require('node:test')
|
||||||
|
const fp = require('../plugin')
|
||||||
|
|
||||||
|
test('checkVersion having require.main.filename', (t) => {
|
||||||
|
const info = console.info
|
||||||
|
t.assert.ok(require.main.filename)
|
||||||
|
t.after(() => {
|
||||||
|
console.info = info
|
||||||
|
})
|
||||||
|
|
||||||
|
console.info = function (msg) {
|
||||||
|
t.assert.fail('logged: ' + msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
fastify: '^5.0.0'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('checkVersion having no require.main.filename but process.argv[1]', (t) => {
|
||||||
|
const filename = require.main.filename
|
||||||
|
const info = console.info
|
||||||
|
t.after(() => {
|
||||||
|
require.main.filename = filename
|
||||||
|
console.info = info
|
||||||
|
})
|
||||||
|
|
||||||
|
require.main.filename = null
|
||||||
|
|
||||||
|
console.info = function (msg) {
|
||||||
|
t.assert.fail('logged: ' + msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
fastify: '^5.0.0'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('checkVersion having no require.main.filename and no process.argv[1]', (t) => {
|
||||||
|
const filename = require.main.filename
|
||||||
|
const argv = process.argv
|
||||||
|
const info = console.info
|
||||||
|
t.after(() => {
|
||||||
|
require.main.filename = filename
|
||||||
|
process.argv = argv
|
||||||
|
console.info = info
|
||||||
|
})
|
||||||
|
|
||||||
|
require.main.filename = null
|
||||||
|
process.argv[1] = null
|
||||||
|
|
||||||
|
console.info = function (msg) {
|
||||||
|
t.assert.fail('logged: ' + msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
fastify: '^5.0.0'
|
||||||
|
})
|
||||||
|
})
|
||||||
14
node_modules/fastify-plugin/test/composite.test.js
generated
vendored
Normal file
14
node_modules/fastify-plugin/test/composite.test.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { test } = require('node:test')
|
||||||
|
const fp = require('../plugin')
|
||||||
|
|
||||||
|
test('anonymous function should be named composite.test0', (t) => {
|
||||||
|
t.plan(2)
|
||||||
|
const fn = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, 'composite.test-auto-0')
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], 'composite.test-auto-0')
|
||||||
|
})
|
||||||
11
node_modules/fastify-plugin/test/esm/esm.mjs
generated
vendored
Normal file
11
node_modules/fastify-plugin/test/esm/esm.mjs
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { test } from 'node:test'
|
||||||
|
import fp from '../../plugin.js'
|
||||||
|
|
||||||
|
test('esm base support', (t) => {
|
||||||
|
fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
fastify: '^5.0.0'
|
||||||
|
})
|
||||||
|
t.assert.ok(true, 'fp function called without throwing an error')
|
||||||
|
})
|
||||||
11
node_modules/fastify-plugin/test/esm/index.test.js
generated
vendored
Normal file
11
node_modules/fastify-plugin/test/esm/index.test.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
// Node v8 throw a `SyntaxError: Unexpected token import`
|
||||||
|
// even if this branch is never touch in the code,
|
||||||
|
// by using `eval` we can avoid this issue.
|
||||||
|
// eslint-disable-next-line
|
||||||
|
new Function('module', 'return import(module)')('./esm.mjs').catch((err) => {
|
||||||
|
process.nextTick(() => {
|
||||||
|
throw err
|
||||||
|
})
|
||||||
|
})
|
||||||
49
node_modules/fastify-plugin/test/extractPluginName.test.js
generated
vendored
Normal file
49
node_modules/fastify-plugin/test/extractPluginName.test.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { test } = require('node:test')
|
||||||
|
const extractPluginName = require('../lib/getPluginName').extractPluginName
|
||||||
|
|
||||||
|
const winStack = `Error: anonymous function
|
||||||
|
at checkName (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\index.js:43:11)
|
||||||
|
at plugin (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\index.js:24:20)
|
||||||
|
at Test.test (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\test\\hello.test.js:9:14)
|
||||||
|
at bound (domain.js:396:14)
|
||||||
|
at Test.runBound (domain.js:409:12)
|
||||||
|
at ret (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:278:21)
|
||||||
|
at Test.main (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:282:7)
|
||||||
|
at writeSubComment (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:371:13)
|
||||||
|
at TAP.writeSubComment (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:403:5)
|
||||||
|
at Test.runBeforeEach (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:370:14)
|
||||||
|
at loop (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\function-loop\\index.js:35:15)
|
||||||
|
at TAP.runBeforeEach (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:683:7)
|
||||||
|
at TAP.processSubtest (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:369:12)
|
||||||
|
at TAP.process (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:306:14)
|
||||||
|
at TAP.sub (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:185:10)
|
||||||
|
at TAP.test (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:209:17)`
|
||||||
|
|
||||||
|
const nixStack = `Error: anonymous function
|
||||||
|
at checkName (/home/leonardo/desktop/fastify-plugin/index.js:43:11)
|
||||||
|
at plugin (/home/leonardo/desktop/fastify-plugin/index.js:24:20)
|
||||||
|
at Test.test (/home/leonardo/desktop/fastify-plugin/test/this.is.a.test.js:9:14)
|
||||||
|
at bound (domain.js:396:14)
|
||||||
|
at Test.runBound (domain.js:409:12)
|
||||||
|
at ret (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:278:21)
|
||||||
|
at Test.main (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:282:7)
|
||||||
|
at writeSubComment (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:371:13)
|
||||||
|
at TAP.writeSubComment (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:403:5)
|
||||||
|
at Test.runBeforeEach (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:370:14)
|
||||||
|
at loop (/home/leonardo/desktop/fastify-plugin/node_modules/function-loop/index.js:35:15)
|
||||||
|
at TAP.runBeforeEach (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:683:7)
|
||||||
|
at TAP.processSubtest (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:369:12)
|
||||||
|
at TAP.process (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:306:14)
|
||||||
|
at TAP.sub (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:185:10)
|
||||||
|
at TAP.test (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:209:17)`
|
||||||
|
|
||||||
|
const anonymousStack = 'Unable to parse this'
|
||||||
|
|
||||||
|
test('extractPluginName tests', (t) => {
|
||||||
|
t.plan(3)
|
||||||
|
t.assert.strictEqual(extractPluginName(winStack), 'hello.test')
|
||||||
|
t.assert.strictEqual(extractPluginName(nixStack), 'this.is.a.test')
|
||||||
|
t.assert.strictEqual(extractPluginName(anonymousStack), 'anonymous')
|
||||||
|
})
|
||||||
15
node_modules/fastify-plugin/test/mu1tip1e.composite.test.js
generated
vendored
Normal file
15
node_modules/fastify-plugin/test/mu1tip1e.composite.test.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { test } = require('node:test')
|
||||||
|
const fp = require('../plugin')
|
||||||
|
|
||||||
|
test('anonymous function should be named mu1tip1e.composite.test', (t) => {
|
||||||
|
t.plan(2)
|
||||||
|
|
||||||
|
const fn = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, 'mu1tip1e.composite.test-auto-0')
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], 'mu1tip1e.composite.test-auto-0')
|
||||||
|
})
|
||||||
396
node_modules/fastify-plugin/test/test.js
generated
vendored
Normal file
396
node_modules/fastify-plugin/test/test.js
generated
vendored
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { test } = require('node:test')
|
||||||
|
const proxyquire = require('proxyquire')
|
||||||
|
const fp = require('../plugin')
|
||||||
|
const Fastify = require('fastify')
|
||||||
|
|
||||||
|
const pkg = require('../package.json')
|
||||||
|
|
||||||
|
test('fastify-plugin is a function', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
t.assert.ok(typeof fp === 'function')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should return the function with the skip-override Symbol', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
|
||||||
|
function plugin (fastify, opts, next) {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fp(plugin)
|
||||||
|
t.assert.ok(plugin[Symbol.for('skip-override')])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should support "default" function from babel module', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
|
||||||
|
const plugin = {
|
||||||
|
default: () => { }
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
fp(plugin)
|
||||||
|
t.assert.ok(true)
|
||||||
|
} catch (e) {
|
||||||
|
t.assert.strictEqual(e.message, 'fastify-plugin expects a function, instead got a \'object\'')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should throw if the plugin is not a function', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
|
||||||
|
try {
|
||||||
|
fp('plugin')
|
||||||
|
t.assert.fail()
|
||||||
|
} catch (e) {
|
||||||
|
t.assert.strictEqual(e.message, 'fastify-plugin expects a function, instead got a \'string\'')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should check the fastify version', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
|
||||||
|
function plugin (fastify, opts, next) {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
fp(plugin, { fastify: '>=0.10.0' })
|
||||||
|
t.assert.ok(true)
|
||||||
|
} catch (e) {
|
||||||
|
t.assert.fail()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should check the fastify version', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
|
||||||
|
function plugin (fastify, opts, next) {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
fp(plugin, '>=0.10.0')
|
||||||
|
t.assert.ok(true)
|
||||||
|
} catch (e) {
|
||||||
|
t.assert.fail()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('the options object should be an object', (t) => {
|
||||||
|
t.plan(2)
|
||||||
|
|
||||||
|
try {
|
||||||
|
fp(() => { }, null)
|
||||||
|
t.assert.fail()
|
||||||
|
} catch (e) {
|
||||||
|
t.assert.strictEqual(e.message, 'The options object should be an object')
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
fp(() => { }, [])
|
||||||
|
t.assert.fail()
|
||||||
|
} catch (e) {
|
||||||
|
t.assert.strictEqual(e.message, 'The options object should be an object')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should throw if the version number is not a string', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
|
||||||
|
try {
|
||||||
|
fp(() => { }, { fastify: 12 })
|
||||||
|
t.assert.fail()
|
||||||
|
} catch (e) {
|
||||||
|
t.assert.strictEqual(e.message, 'fastify-plugin expects a version string, instead got \'number\'')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Should accept an option object', (t) => {
|
||||||
|
t.plan(2)
|
||||||
|
|
||||||
|
const opts = { hello: 'world' }
|
||||||
|
|
||||||
|
function plugin (fastify, opts, next) {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fp(plugin, opts)
|
||||||
|
|
||||||
|
t.assert.ok(plugin[Symbol.for('skip-override')], 'skip-override symbol should be present')
|
||||||
|
t.assert.deepStrictEqual(plugin[Symbol.for('plugin-meta')], opts, 'plugin-meta should match opts')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Should accept an option object and checks the version', (t) => {
|
||||||
|
t.plan(2)
|
||||||
|
|
||||||
|
const opts = { hello: 'world', fastify: '>=0.10.0' }
|
||||||
|
|
||||||
|
function plugin (fastify, opts, next) {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fp(plugin, opts)
|
||||||
|
t.assert.ok(plugin[Symbol.for('skip-override')])
|
||||||
|
t.assert.deepStrictEqual(plugin[Symbol.for('plugin-meta')], opts)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should set anonymous function name to file it was called from with a counter', (t) => {
|
||||||
|
const fp = proxyquire('../plugin.js', { stubs: {} })
|
||||||
|
|
||||||
|
const fn = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, 'test-auto-0')
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], 'test-auto-0')
|
||||||
|
|
||||||
|
const fn2 = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(fn2[Symbol.for('plugin-meta')].name, 'test-auto-1')
|
||||||
|
t.assert.strictEqual(fn2[Symbol.for('fastify.display-name')], 'test-auto-1')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should set function name if Error.stackTraceLimit is set to 0', (t) => {
|
||||||
|
const stackTraceLimit = Error.stackTraceLimit = 0
|
||||||
|
|
||||||
|
const fp = proxyquire('../plugin.js', { stubs: {} })
|
||||||
|
|
||||||
|
const fn = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, 'test-auto-0')
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], 'test-auto-0')
|
||||||
|
|
||||||
|
const fn2 = fp((fastify, opts, next) => {
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(fn2[Symbol.for('plugin-meta')].name, 'test-auto-1')
|
||||||
|
t.assert.strictEqual(fn2[Symbol.for('fastify.display-name')], 'test-auto-1')
|
||||||
|
|
||||||
|
Error.stackTraceLimit = stackTraceLimit
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should set display-name to meta name', (t) => {
|
||||||
|
t.plan(2)
|
||||||
|
|
||||||
|
const functionName = 'superDuperSpecialFunction'
|
||||||
|
|
||||||
|
const fn = fp((fastify, opts, next) => next(), {
|
||||||
|
name: functionName
|
||||||
|
})
|
||||||
|
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, functionName)
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], functionName)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should preserve fastify version in meta', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
|
||||||
|
const opts = { hello: 'world', fastify: '>=0.10.0' }
|
||||||
|
|
||||||
|
const fn = fp((fastify, opts, next) => next(), opts)
|
||||||
|
|
||||||
|
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].fastify, '>=0.10.0')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should check fastify dependency graph - plugin', async (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
const fastify = Fastify()
|
||||||
|
|
||||||
|
fastify.register(fp((fastify, opts, next) => next(), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'plugin1-name'
|
||||||
|
}))
|
||||||
|
|
||||||
|
fastify.register(fp((fastify, opts, next) => next(), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'test',
|
||||||
|
dependencies: ['plugin1-name', 'plugin2-name']
|
||||||
|
}))
|
||||||
|
|
||||||
|
await t.assert.rejects(fastify.ready(), { message: "The dependency 'plugin2-name' of plugin 'test' is not registered" })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should check fastify dependency graph - decorate', async (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
const fastify = Fastify()
|
||||||
|
|
||||||
|
fastify.decorate('plugin1', fp((fastify, opts, next) => next(), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'plugin1-name'
|
||||||
|
}))
|
||||||
|
|
||||||
|
fastify.register(fp((fastify, opts, next) => next(), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'test',
|
||||||
|
decorators: { fastify: ['plugin1', 'plugin2'] }
|
||||||
|
}))
|
||||||
|
|
||||||
|
await t.assert.rejects(fastify.ready(), { message: "The decorator 'plugin2' required by 'test' is not present in Fastify" })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should check fastify dependency graph - decorateReply', async (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
const fastify = Fastify()
|
||||||
|
|
||||||
|
fastify.decorateReply('plugin1', fp((fastify, opts, next) => next(), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'plugin1-name'
|
||||||
|
}))
|
||||||
|
|
||||||
|
fastify.register(fp((fastify, opts, next) => next(), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'test',
|
||||||
|
decorators: { reply: ['plugin1', 'plugin2'] }
|
||||||
|
}))
|
||||||
|
|
||||||
|
await t.assert.rejects(fastify.ready(), { message: "The decorator 'plugin2' required by 'test' is not present in Reply" })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should accept an option to encapsulate', async (t) => {
|
||||||
|
t.plan(3)
|
||||||
|
|
||||||
|
const fastify = Fastify()
|
||||||
|
|
||||||
|
fastify.register(fp((fastify, opts, next) => {
|
||||||
|
fastify.decorate('accessible', true)
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
name: 'accessible-plugin'
|
||||||
|
}))
|
||||||
|
|
||||||
|
fastify.register(fp((fastify, opts, next) => {
|
||||||
|
fastify.decorate('alsoAccessible', true)
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
name: 'accessible-plugin2',
|
||||||
|
encapsulate: false
|
||||||
|
}))
|
||||||
|
|
||||||
|
fastify.register(fp((fastify, opts, next) => {
|
||||||
|
fastify.decorate('encapsulated', true)
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
name: 'encapsulated-plugin',
|
||||||
|
encapsulate: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
await fastify.ready()
|
||||||
|
|
||||||
|
t.assert.ok(fastify.hasDecorator('accessible'))
|
||||||
|
t.assert.ok(fastify.hasDecorator('alsoAccessible'))
|
||||||
|
t.assert.ok(!fastify.hasDecorator('encapsulated'))
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should check dependencies when encapsulated', async (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
const fastify = Fastify()
|
||||||
|
|
||||||
|
fastify.register(fp((fastify, opts, next) => next(), {
|
||||||
|
name: 'test',
|
||||||
|
dependencies: ['missing-dependency-name'],
|
||||||
|
encapsulate: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
await t.assert.rejects(fastify.ready(), { message: "The dependency 'missing-dependency-name' of plugin 'test' is not registered" })
|
||||||
|
})
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should check version when encapsulated',
|
||||||
|
{ skip: /\d-.+/.test(pkg.devDependencies.fastify) },
|
||||||
|
async (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
const fastify = Fastify()
|
||||||
|
|
||||||
|
fastify.register(fp((fastify, opts, next) => next(), {
|
||||||
|
name: 'test',
|
||||||
|
fastify: '<=2.10.0',
|
||||||
|
encapsulate: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
await t.assert.rejects(fastify.ready(), { message: /fastify-plugin: test - expected '<=2.10.0' fastify version, '\d.\d+.\d+' is installed/ })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
test('should check decorators when encapsulated', async (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
const fastify = Fastify()
|
||||||
|
|
||||||
|
fastify.decorate('plugin1', 'foo')
|
||||||
|
|
||||||
|
fastify.register(fp((fastify, opts, next) => next(), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'test',
|
||||||
|
encapsulate: true,
|
||||||
|
decorators: { fastify: ['plugin1', 'plugin2'] }
|
||||||
|
}))
|
||||||
|
|
||||||
|
await t.assert.rejects(fastify.ready(), { message: "The decorator 'plugin2' required by 'test' is not present in Fastify" })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('plugin name when encapsulated', async (t) => {
|
||||||
|
t.plan(6)
|
||||||
|
const fastify = Fastify()
|
||||||
|
|
||||||
|
fastify.register(function plugin (instance, opts, next) {
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
fastify.register(fp(getFn('hello'), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'hello',
|
||||||
|
encapsulate: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
fastify.register(function plugin (fastify, opts, next) {
|
||||||
|
fastify.register(fp(getFn('deep'), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'deep',
|
||||||
|
encapsulate: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
fastify.register(fp(function genericPlugin (fastify, opts, next) {
|
||||||
|
t.assert.strictEqual(fastify.pluginName, 'deep-deep', 'should be deep-deep')
|
||||||
|
|
||||||
|
fastify.register(fp(getFn('deep-deep-deep'), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'deep-deep-deep',
|
||||||
|
encapsulate: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
fastify.register(fp(getFn('deep-deep -> not-encapsulated-2'), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'not-encapsulated-2'
|
||||||
|
}))
|
||||||
|
|
||||||
|
next()
|
||||||
|
}, {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'deep-deep',
|
||||||
|
encapsulate: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
fastify.register(fp(getFn('plugin -> not-encapsulated'), {
|
||||||
|
fastify: '5.x',
|
||||||
|
name: 'not-encapsulated'
|
||||||
|
}))
|
||||||
|
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
await fastify.ready()
|
||||||
|
|
||||||
|
function getFn (expectedName) {
|
||||||
|
return function genericPlugin (fastify, opts, next) {
|
||||||
|
t.assert.strictEqual(fastify.pluginName, expectedName, `should be ${expectedName}`)
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
24
node_modules/fastify-plugin/test/toCamelCase.test.js
generated
vendored
Normal file
24
node_modules/fastify-plugin/test/toCamelCase.test.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { test } = require('node:test')
|
||||||
|
const toCamelCase = require('../lib/toCamelCase')
|
||||||
|
|
||||||
|
test('from kebab-case to camelCase', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
t.assert.strictEqual(toCamelCase('hello-world'), 'helloWorld')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('from @-prefixed named imports', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
t.assert.strictEqual(toCamelCase('@hello/world'), 'helloWorld')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('from @-prefixed named kebab-case to camelCase', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
t.assert.strictEqual(toCamelCase('@hello/my-world'), 'helloMyWorld')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('from kebab-case to camelCase multiple words', (t) => {
|
||||||
|
t.plan(1)
|
||||||
|
t.assert.strictEqual(toCamelCase('hello-long-world'), 'helloLongWorld')
|
||||||
|
})
|
||||||
19
node_modules/fastify-plugin/types/example-async.test-d.ts
generated
vendored
Normal file
19
node_modules/fastify-plugin/types/example-async.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { FastifyPluginAsync } from "fastify";
|
||||||
|
|
||||||
|
type FastifyExampleAsync = FastifyPluginAsync<fastifyExampleAsync.FastifyExampleAsyncOptions>;
|
||||||
|
|
||||||
|
declare namespace fastifyExampleAsync {
|
||||||
|
|
||||||
|
export interface FastifyExampleAsyncOptions {
|
||||||
|
foo?: 'bar'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FastifyExampleAsyncPluginOptions extends FastifyExampleAsyncOptions {
|
||||||
|
}
|
||||||
|
export const fastifyExampleAsync: FastifyExampleAsync
|
||||||
|
export { fastifyExampleAsync as default }
|
||||||
|
}
|
||||||
|
|
||||||
|
declare function fastifyExampleAsync(...params: Parameters<FastifyExampleAsync>): ReturnType<FastifyExampleAsync>
|
||||||
|
|
||||||
|
export default fastifyExampleAsync
|
||||||
19
node_modules/fastify-plugin/types/example-callback.test-d.ts
generated
vendored
Normal file
19
node_modules/fastify-plugin/types/example-callback.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { FastifyPluginCallback } from "fastify";
|
||||||
|
|
||||||
|
type FastifyExampleCallback = FastifyPluginCallback<fastifyExampleCallback.FastifyExampleCallbackOptions>;
|
||||||
|
|
||||||
|
declare namespace fastifyExampleCallback {
|
||||||
|
|
||||||
|
export interface FastifyExampleCallbackOptions {
|
||||||
|
foo?: 'bar'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FastifyExampleCallbackPluginOptions extends FastifyExampleCallbackOptions {
|
||||||
|
}
|
||||||
|
export const fastifyExampleCallback: FastifyExampleCallback
|
||||||
|
export { fastifyExampleCallback as default }
|
||||||
|
}
|
||||||
|
|
||||||
|
declare function fastifyExampleCallback(...params: Parameters<FastifyExampleCallback>): ReturnType<FastifyExampleCallback>
|
||||||
|
|
||||||
|
export default fastifyExampleCallback
|
||||||
61
node_modules/fastify-plugin/types/plugin.d.ts
generated
vendored
Normal file
61
node_modules/fastify-plugin/types/plugin.d.ts
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/// <reference types="fastify" />
|
||||||
|
|
||||||
|
import {
|
||||||
|
FastifyPluginCallback,
|
||||||
|
FastifyPluginAsync,
|
||||||
|
FastifyPluginOptions,
|
||||||
|
RawServerBase,
|
||||||
|
RawServerDefault,
|
||||||
|
FastifyTypeProvider,
|
||||||
|
FastifyTypeProviderDefault,
|
||||||
|
FastifyBaseLogger,
|
||||||
|
} from 'fastify'
|
||||||
|
|
||||||
|
type FastifyPlugin = typeof fastifyPlugin
|
||||||
|
|
||||||
|
declare namespace fastifyPlugin {
|
||||||
|
export interface PluginMetadata {
|
||||||
|
/** Bare-minimum version of Fastify for your plugin, just add the semver range that you need. */
|
||||||
|
fastify?: string,
|
||||||
|
name?: string,
|
||||||
|
/** Decorator dependencies for this plugin */
|
||||||
|
decorators?: {
|
||||||
|
fastify?: (string | symbol)[],
|
||||||
|
reply?: (string | symbol)[],
|
||||||
|
request?: (string | symbol)[]
|
||||||
|
},
|
||||||
|
/** The plugin dependencies */
|
||||||
|
dependencies?: string[],
|
||||||
|
encapsulate?: boolean
|
||||||
|
}
|
||||||
|
// Exporting PluginOptions for backward compatibility after renaming it to PluginMetadata
|
||||||
|
/**
|
||||||
|
* @deprecated Use PluginMetadata instead
|
||||||
|
*/
|
||||||
|
export interface PluginOptions extends PluginMetadata {}
|
||||||
|
|
||||||
|
export const fastifyPlugin: FastifyPlugin
|
||||||
|
export { fastifyPlugin as default }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function does three things for you:
|
||||||
|
* 1. Add the `skip-override` hidden property
|
||||||
|
* 2. Check bare-minimum version of Fastify
|
||||||
|
* 3. Pass some custom metadata of the plugin to Fastify
|
||||||
|
* @param fn Fastify plugin function
|
||||||
|
* @param options Optional plugin options
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare function fastifyPlugin<
|
||||||
|
Options extends FastifyPluginOptions = Record<never, never>,
|
||||||
|
RawServer extends RawServerBase = RawServerDefault,
|
||||||
|
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
|
||||||
|
Logger extends FastifyBaseLogger = FastifyBaseLogger,
|
||||||
|
Fn extends FastifyPluginCallback<Options, RawServer, TypeProvider, Logger> | FastifyPluginAsync<Options, RawServer, TypeProvider, Logger> = FastifyPluginCallback<Options, RawServer, TypeProvider, Logger>
|
||||||
|
>(
|
||||||
|
fn: Fn extends unknown ? Fn extends (...args: any) => Promise<any> ? FastifyPluginAsync<Options, RawServer, TypeProvider, Logger> : FastifyPluginCallback<Options, RawServer, TypeProvider, Logger> : Fn,
|
||||||
|
options?: fastifyPlugin.PluginMetadata | string
|
||||||
|
): Fn;
|
||||||
|
|
||||||
|
export = fastifyPlugin
|
||||||
166
node_modules/fastify-plugin/types/plugin.test-d.ts
generated
vendored
Normal file
166
node_modules/fastify-plugin/types/plugin.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
import fastifyPlugin from '..';
|
||||||
|
import fastify, { FastifyPluginCallback, FastifyPluginAsync, FastifyError, FastifyInstance, FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault, FastifyBaseLogger } from 'fastify';
|
||||||
|
import { expectAssignable, expectError, expectNotType, expectType } from 'tsd'
|
||||||
|
import { Server } from "node:https"
|
||||||
|
import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox"
|
||||||
|
import fastifyExampleCallback from './example-callback.test-d';
|
||||||
|
import fastifyExampleAsync from './example-async.test-d';
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
foo: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const testSymbol = Symbol('foobar')
|
||||||
|
|
||||||
|
// Callback
|
||||||
|
|
||||||
|
const pluginCallback: FastifyPluginCallback = (fastify, options, next) => { }
|
||||||
|
expectType<FastifyPluginCallback>(fastifyPlugin(pluginCallback))
|
||||||
|
|
||||||
|
const pluginCallbackWithTypes = (fastify: FastifyInstance, options: FastifyPluginOptions, next: (error?: FastifyError) => void): void => { }
|
||||||
|
expectAssignable<FastifyPluginCallback>(fastifyPlugin(pluginCallbackWithTypes))
|
||||||
|
expectNotType<any>(fastifyPlugin(pluginCallbackWithTypes))
|
||||||
|
|
||||||
|
expectAssignable<FastifyPluginCallback>(fastifyPlugin((fastify: FastifyInstance, options: FastifyPluginOptions, next: (error?: FastifyError) => void): void => { }))
|
||||||
|
expectNotType<any>(fastifyPlugin((fastify: FastifyInstance, options: FastifyPluginOptions, next: (error?: FastifyError) => void): void => { }))
|
||||||
|
|
||||||
|
expectType<FastifyPluginCallback>(fastifyPlugin(pluginCallback, ''))
|
||||||
|
expectType<FastifyPluginCallback>(fastifyPlugin(pluginCallback, {
|
||||||
|
fastify: '',
|
||||||
|
name: '',
|
||||||
|
decorators: {
|
||||||
|
fastify: ['', testSymbol],
|
||||||
|
reply: ['', testSymbol],
|
||||||
|
request: ['', testSymbol]
|
||||||
|
},
|
||||||
|
dependencies: [''],
|
||||||
|
encapsulate: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
const pluginCallbackWithOptions: FastifyPluginCallback<Options> = (fastify, options, next) => {
|
||||||
|
expectType<string>(options.foo)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectType<FastifyPluginCallback<Options>>(fastifyPlugin(pluginCallbackWithOptions))
|
||||||
|
|
||||||
|
const pluginCallbackWithServer: FastifyPluginCallback<Options, Server> = (fastify, options, next) => {
|
||||||
|
expectType<Server>(fastify.server)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectType<FastifyPluginCallback<Options, Server>>(fastifyPlugin(pluginCallbackWithServer))
|
||||||
|
|
||||||
|
const pluginCallbackWithTypeProvider: FastifyPluginCallback<Options, Server, TypeBoxTypeProvider> = (fastify, options, next) => { }
|
||||||
|
|
||||||
|
expectType<FastifyPluginCallback<Options, Server, TypeBoxTypeProvider>>(fastifyPlugin(pluginCallbackWithTypeProvider))
|
||||||
|
|
||||||
|
// Async
|
||||||
|
|
||||||
|
const pluginAsync: FastifyPluginAsync = async (fastify, options) => { }
|
||||||
|
expectType<FastifyPluginAsync>(fastifyPlugin(pluginAsync))
|
||||||
|
|
||||||
|
const pluginAsyncWithTypes = async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { }
|
||||||
|
expectType<FastifyPluginAsync<FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault>>(fastifyPlugin(pluginAsyncWithTypes))
|
||||||
|
|
||||||
|
expectType<FastifyPluginAsync<FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault>>(fastifyPlugin(async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { }))
|
||||||
|
expectType<FastifyPluginAsync>(fastifyPlugin(pluginAsync, ''))
|
||||||
|
expectType<FastifyPluginAsync>(fastifyPlugin(pluginAsync, {
|
||||||
|
fastify: '',
|
||||||
|
name: '',
|
||||||
|
decorators: {
|
||||||
|
fastify: ['', testSymbol],
|
||||||
|
reply: ['', testSymbol],
|
||||||
|
request: ['', testSymbol]
|
||||||
|
},
|
||||||
|
dependencies: [''],
|
||||||
|
encapsulate: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
const pluginAsyncWithOptions: FastifyPluginAsync<Options> = async (fastify, options) => {
|
||||||
|
expectType<string>(options.foo)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectType<FastifyPluginAsync<Options>>(fastifyPlugin(pluginAsyncWithOptions))
|
||||||
|
|
||||||
|
const pluginAsyncWithServer: FastifyPluginAsync<Options, Server> = async (fastify, options) => {
|
||||||
|
expectType<Server>(fastify.server)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectType<FastifyPluginAsync<Options, Server>>(fastifyPlugin(pluginAsyncWithServer))
|
||||||
|
|
||||||
|
const pluginAsyncWithTypeProvider: FastifyPluginAsync<Options, Server, TypeBoxTypeProvider> = async (fastify, options) => { }
|
||||||
|
|
||||||
|
expectType<FastifyPluginAsync<Options, Server, TypeBoxTypeProvider>>(fastifyPlugin(pluginAsyncWithTypeProvider))
|
||||||
|
|
||||||
|
// Fastify register
|
||||||
|
|
||||||
|
const server = fastify()
|
||||||
|
server.register(fastifyPlugin(pluginCallback))
|
||||||
|
server.register(fastifyPlugin(pluginCallbackWithTypes))
|
||||||
|
server.register(fastifyPlugin(pluginCallbackWithOptions))
|
||||||
|
server.register(fastifyPlugin(pluginCallbackWithServer))
|
||||||
|
server.register(fastifyPlugin(pluginCallbackWithTypeProvider))
|
||||||
|
server.register(fastifyPlugin(pluginAsync))
|
||||||
|
server.register(fastifyPlugin(pluginAsyncWithTypes))
|
||||||
|
server.register(fastifyPlugin(pluginAsyncWithOptions))
|
||||||
|
server.register(fastifyPlugin(pluginAsyncWithServer))
|
||||||
|
server.register(fastifyPlugin(pluginAsyncWithTypeProvider))
|
||||||
|
|
||||||
|
// properly handling callback and async
|
||||||
|
fastifyPlugin(function (fastify, options, next) {
|
||||||
|
expectType<FastifyInstance>(fastify)
|
||||||
|
expectType<Record<never, never>>(options)
|
||||||
|
expectType<(err?: Error) => void>(next)
|
||||||
|
})
|
||||||
|
|
||||||
|
fastifyPlugin<Options>(function (fastify, options, next) {
|
||||||
|
expectType<FastifyInstance>(fastify)
|
||||||
|
expectType<Options>(options)
|
||||||
|
expectType<(err?: Error) => void>(next)
|
||||||
|
})
|
||||||
|
|
||||||
|
fastifyPlugin<Options>(async function (fastify, options) {
|
||||||
|
expectType<FastifyInstance>(fastify)
|
||||||
|
expectType<Options>(options)
|
||||||
|
})
|
||||||
|
|
||||||
|
expectAssignable<FastifyPluginAsync<Options, RawServerDefault, FastifyTypeProviderDefault, FastifyBaseLogger>>(fastifyPlugin(async function (fastify: FastifyInstance, options: Options) { }))
|
||||||
|
expectNotType<any>(fastifyPlugin(async function (fastify: FastifyInstance, options: Options) { }))
|
||||||
|
|
||||||
|
fastifyPlugin(async function (fastify, options: Options) {
|
||||||
|
expectType<FastifyInstance>(fastify)
|
||||||
|
expectType<Options>(options)
|
||||||
|
})
|
||||||
|
|
||||||
|
fastifyPlugin(async function (fastify, options) {
|
||||||
|
expectType<FastifyInstance>(fastify)
|
||||||
|
expectType<Record<never, never>>(options)
|
||||||
|
})
|
||||||
|
|
||||||
|
expectError(
|
||||||
|
fastifyPlugin(async function (fastify, options: Options, next) {
|
||||||
|
expectType<FastifyInstance>(fastify)
|
||||||
|
expectType<Options>(options)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
expectAssignable<FastifyPluginCallback<Options>>(fastifyPlugin(function (fastify, options, next) { }))
|
||||||
|
expectNotType<any>(fastifyPlugin(function (fastify, options, next) { }))
|
||||||
|
|
||||||
|
fastifyPlugin(function (fastify, options: Options, next) {
|
||||||
|
expectType<FastifyInstance>(fastify)
|
||||||
|
expectType<Options>(options)
|
||||||
|
expectType<(err?: Error) => void>(next)
|
||||||
|
})
|
||||||
|
|
||||||
|
expectError(
|
||||||
|
fastifyPlugin(function (fastify, options: Options, next) {
|
||||||
|
expectType<FastifyInstance>(fastify)
|
||||||
|
expectType<Options>(options)
|
||||||
|
return Promise.resolve()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
server.register(fastifyExampleCallback, { foo: 'bar' })
|
||||||
|
expectError(server.register(fastifyExampleCallback, { foo: 'baz' }))
|
||||||
|
|
||||||
|
server.register(fastifyExampleAsync, { foo: 'bar' })
|
||||||
|
expectError(server.register(fastifyExampleAsync, { foo: 'baz' }))
|
||||||
7
package-lock.json
generated
7
package-lock.json
generated
@@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^17.2.2",
|
"dotenv": "^17.2.2",
|
||||||
"fastify": "^5.6.0",
|
"fastify": "^5.6.0",
|
||||||
|
"fastify-plugin": "^5.0.1",
|
||||||
"mongodb": "^6.20.0"
|
"mongodb": "^6.20.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -329,6 +330,12 @@
|
|||||||
"toad-cache": "^3.7.0"
|
"toad-cache": "^3.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fastify-plugin": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fastq": {
|
"node_modules/fastq": {
|
||||||
"version": "1.19.1",
|
"version": "1.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^17.2.2",
|
"dotenv": "^17.2.2",
|
||||||
"fastify": "^5.6.0",
|
"fastify": "^5.6.0",
|
||||||
|
"fastify-plugin": "^5.0.1",
|
||||||
"mongodb": "^6.20.0"
|
"mongodb": "^6.20.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
131
server.js
Normal file
131
server.js
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
// 1. 导入依赖
|
||||||
|
require('dotenv').config(); // 尽早加载环境变量
|
||||||
|
const fastify = require('fastify')({ logger: true }); // 开启日志,方便调试
|
||||||
|
const { ObjectId } = require('mongodb'); // 导入 ObjectId 用于ID操作
|
||||||
|
|
||||||
|
// 2. 注册 MongoDB 插件
|
||||||
|
// Fastify 的插件系统能确保在路由处理前,数据库连接已经准备就绪
|
||||||
|
fastify.register(require('./db-connector'));
|
||||||
|
|
||||||
|
// ------------------- API 路由定义 -------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {post} /todos 创建一个新的 Todo
|
||||||
|
*/
|
||||||
|
fastify.post('/todos', async (request, reply) => {
|
||||||
|
// fastify.mongo.db 是由我们的插件注入的
|
||||||
|
const todosCollection = fastify.mongo.db.collection('todos');
|
||||||
|
|
||||||
|
// 从请求体中获取数据
|
||||||
|
const { text, completed = false } = request.body;
|
||||||
|
|
||||||
|
if (!text) {
|
||||||
|
return reply.code(400).send({ message: '`text` 字段是必需的。' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTodo = {
|
||||||
|
text,
|
||||||
|
completed,
|
||||||
|
createdAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await todosCollection.insertOne(newTodo);
|
||||||
|
reply.code(201).send(result); // 201 Created
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {get} /todos 获取所有 Todos
|
||||||
|
*/
|
||||||
|
fastify.get('/todos', async (request, reply) => {
|
||||||
|
const todosCollection = fastify.mongo.db.collection('todos');
|
||||||
|
const todos = await todosCollection.find({}).toArray();
|
||||||
|
reply.send(todos);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {get} /todos/:id 获取单个 Todo
|
||||||
|
*/
|
||||||
|
fastify.get('/todos/:id', async (request, reply) => {
|
||||||
|
const { id } = request.params;
|
||||||
|
|
||||||
|
// 校验 ID 格式是否正确
|
||||||
|
if (!ObjectId.isValid(id)) {
|
||||||
|
return reply.code(400).send({ message: '无效的ID格式。' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectId = new ObjectId(id);
|
||||||
|
const todosCollection = fastify.mongo.db.collection('todos');
|
||||||
|
const todo = await todosCollection.findOne({ _id: objectId });
|
||||||
|
|
||||||
|
if (!todo) {
|
||||||
|
return reply.code(404).send({ message: '未找到指定的 Todo。' });
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.send(todo);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {put} /todos/:id 更新一个 Todo
|
||||||
|
*/
|
||||||
|
fastify.put('/todos/:id', async (request, reply) => {
|
||||||
|
const { id } = request.params;
|
||||||
|
const { text, completed } = request.body;
|
||||||
|
|
||||||
|
if (!ObjectId.isValid(id)) {
|
||||||
|
return reply.code(400).send({ message: '无效的ID格式。' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectId = new ObjectId(id);
|
||||||
|
const todosCollection = fastify.mongo.db.collection('todos');
|
||||||
|
|
||||||
|
const updateDoc = { $set: {} };
|
||||||
|
if (text !== undefined) updateDoc.$set.text = text;
|
||||||
|
if (completed !== undefined) updateDoc.$set.completed = completed;
|
||||||
|
|
||||||
|
// 如果没有提供任何更新字段,则返回错误
|
||||||
|
if (Object.keys(updateDoc.$set).length === 0) {
|
||||||
|
return reply.code(400).send({ message: '请提供需要更新的字段 (text 或 completed)。' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await todosCollection.updateOne({ _id: objectId }, updateDoc);
|
||||||
|
|
||||||
|
if (result.matchedCount === 0) {
|
||||||
|
return reply.code(404).send({ message: '未找到指定的 Todo 进行更新。' });
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.send({ message: 'Todo 更新成功。' });
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {delete} /todos/:id 删除一个 Todo
|
||||||
|
*/
|
||||||
|
fastify.delete('/todos/:id', async (request, reply) => {
|
||||||
|
const { id } = request.params;
|
||||||
|
|
||||||
|
if (!ObjectId.isValid(id)) {
|
||||||
|
return reply.code(400).send({ message: '无效的ID格式。' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectId = new ObjectId(id);
|
||||||
|
const todosCollection = fastify.mongo.db.collection('todos');
|
||||||
|
const result = await todosCollection.deleteOne({ _id: objectId });
|
||||||
|
|
||||||
|
if (result.deletedCount === 0) {
|
||||||
|
return reply.code(404).send({ message: '未找到指定的 Todo 进行删除。' });
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.code(200).send({ message: 'Todo 删除成功。' });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. 启动服务器
|
||||||
|
const start = async () => {
|
||||||
|
try {
|
||||||
|
await fastify.listen({ port: 3000 });
|
||||||
|
fastify.log.info(`服务器运行在 ${fastify.server.address().port}`);
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
start();
|
||||||
Reference in New Issue
Block a user