@@ -1,3 +1,11 @@
|
||||
module.exports = {
|
||||
extends: ['@payloadcms'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.spec.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
26
packages/plugin-sentry/.github/workflows/main.yml
vendored
Normal file
26
packages/plugin-sentry/.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: build_and_test
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org
|
||||
|
||||
- name: yarn cache
|
||||
uses: c-hive/gha-yarn-cache@v2
|
||||
- run: yarn
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
- run: yarn build
|
||||
- run: yarn test
|
||||
249
packages/plugin-sentry/.gitignore
vendored
249
packages/plugin-sentry/.gitignore
vendored
@@ -1,6 +1,247 @@
|
||||
node_modules
|
||||
dev/yarn.lock
|
||||
|
||||
# Created by https://www.gitignore.io/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||
|
||||
### macOS ###
|
||||
*.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# Yarn Berry
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
.pnp.*
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
dist
|
||||
|
||||
|
||||
### SublimeText ###
|
||||
# cache files for sublime text
|
||||
*.tmlanguage.cache
|
||||
*.tmPreferences.cache
|
||||
*.stTheme.cache
|
||||
|
||||
# workspace files are user-specific
|
||||
*.sublime-workspace
|
||||
|
||||
# project files should be checked into the repository, unless a significant
|
||||
# proportion of contributors will probably not be using SublimeText
|
||||
# *.sublime-project
|
||||
|
||||
# sftp configuration file
|
||||
sftp-config.json
|
||||
|
||||
# Package control specific files
|
||||
Package Control.last-run
|
||||
Package Control.ca-list
|
||||
Package Control.ca-bundle
|
||||
Package Control.system-ca-bundle
|
||||
Package Control.cache/
|
||||
Package Control.ca-certs/
|
||||
Package Control.merged-ca-bundle
|
||||
Package Control.user-ca-bundle
|
||||
oscrypto-ca-bundle.crt
|
||||
bh_unicode_properties.cache
|
||||
|
||||
# Sublime-github package stores a github token in this file
|
||||
# https://packagecontrol.io/packages/sublime-github
|
||||
GitHub.sublime-settings
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history
|
||||
|
||||
### WebStorm ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
.idea/*
|
||||
# User-specific stuff:
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.xml
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# CMake
|
||||
cmake-build-debug/
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Ruby plugin and RubyMine
|
||||
/.rakeTasks
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
### WebStorm Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
.idea/sonarlint
|
||||
|
||||
### Windows ###
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# End of https://www.gitignore.io/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||
|
||||
# Ignore all uploads
|
||||
demo/upload
|
||||
demo/media
|
||||
demo/files
|
||||
|
||||
# Ignore build folder
|
||||
build
|
||||
.DS_Store
|
||||
package-lock.json
|
||||
|
||||
# Ignore built components
|
||||
components/index.js
|
||||
components/styles.css
|
||||
|
||||
# Ignore generated
|
||||
demo/generated-types.ts
|
||||
demo/generated-schema.graphql
|
||||
|
||||
# Ignore dist, no need for git
|
||||
dist
|
||||
|
||||
# Ignore emulator volumes
|
||||
src/adapters/s3/emulator/.localstack/
|
||||
|
||||
2
packages/plugin-sentry/dev/.env.example
Normal file
2
packages/plugin-sentry/dev/.env.example
Normal file
@@ -0,0 +1,2 @@
|
||||
MONGODB_URI=mongodb://localhost/plugin-sentry
|
||||
PAYLOAD_SECRET=mwfkfksosksseanllcosjshdncm
|
||||
14
packages/plugin-sentry/jest.config.js
Normal file
14
packages/plugin-sentry/jest.config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
verbose: true,
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/src/**/*.spec.ts'],
|
||||
transform: {
|
||||
'^.+\\.(ts|tsx)?$': 'ts-jest',
|
||||
},
|
||||
testTimeout: 60000,
|
||||
moduleNameMapper: {
|
||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
|
||||
'<rootDir>/src/webpack/mocks/fileMock.js',
|
||||
'\\.(css|scss)$': '<rootDir>/src/webpack/mocks/emptyModule.js',
|
||||
},
|
||||
}
|
||||
@@ -8,9 +8,11 @@
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"test": "jest",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint --fix --ext .ts,.tsx src"
|
||||
"lint:fix": "eslint --fix --ext .ts,.tsx src",
|
||||
"clean": "rimraf dist && rimraf dev/yarn.lock",
|
||||
"prepublishOnly": "yarn clean && yarn build && yarn test"
|
||||
},
|
||||
"keywords": [
|
||||
"payload",
|
||||
@@ -26,7 +28,7 @@
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"payload": "^1.9.2",
|
||||
"payload": "^1.10.1",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -37,6 +39,7 @@
|
||||
"devDependencies": {
|
||||
"@payloadcms/eslint-config": "^0.0.1",
|
||||
"@types/express": "^4.17.9",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "18.11.3",
|
||||
"@types/react": "18.0.21",
|
||||
"@typescript-eslint/eslint-plugin": "^5.51.0",
|
||||
@@ -51,10 +54,12 @@
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"nodemon": "^2.0.6",
|
||||
"payload": "^1.9.2",
|
||||
"payload": "^1.10.1",
|
||||
"prettier": "^2.7.1",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,2 @@
|
||||
/* eslint-disable no-console */
|
||||
import type { Config } from 'payload/config'
|
||||
|
||||
import { captureException } from './captureException'
|
||||
import { startSentry } from './startSentry'
|
||||
import type { PluginOptions } from './types'
|
||||
import { extendWebpackConfig } from './webpack'
|
||||
|
||||
export const sentry =
|
||||
(pluginOptions: PluginOptions) =>
|
||||
(incomingConfig: Config): Config => {
|
||||
if (!pluginOptions.dsn) {
|
||||
console.log('Sentry plugin is disabled because no DSN was provided')
|
||||
return incomingConfig
|
||||
}
|
||||
|
||||
let config = { ...incomingConfig }
|
||||
const webpack = extendWebpackConfig(incomingConfig)
|
||||
|
||||
config.admin = {
|
||||
...(config.admin || {}),
|
||||
webpack,
|
||||
}
|
||||
|
||||
config.hooks = {
|
||||
...(incomingConfig.hooks || {}),
|
||||
afterError: (err: any) => {
|
||||
captureException(err)
|
||||
},
|
||||
}
|
||||
|
||||
startSentry({
|
||||
dsn: pluginOptions.dsn,
|
||||
options: pluginOptions.options || {},
|
||||
})
|
||||
|
||||
return config
|
||||
}
|
||||
export { sentry } from './plugin'
|
||||
export type { PluginOptions } from './types'
|
||||
|
||||
57
packages/plugin-sentry/src/plugin.spec.ts
Normal file
57
packages/plugin-sentry/src/plugin.spec.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import type { Config } from 'payload/config'
|
||||
import { defaults } from 'payload/dist/config/defaults'
|
||||
|
||||
import { sentry } from './plugin'
|
||||
import * as startSentryFuncs from './startSentry'
|
||||
|
||||
let startSentrySpy: jest.SpyInstance
|
||||
|
||||
describe('plugin', () => {
|
||||
beforeEach(() => {
|
||||
startSentrySpy = jest.spyOn(startSentryFuncs, 'startSentry').mockImplementation(() => {})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
startSentrySpy.mockRestore()
|
||||
})
|
||||
|
||||
it('should run the plugin', () => {
|
||||
const plugin = sentry({ enabled: true, dsn: 'asdf' })
|
||||
const config = plugin(createConfig())
|
||||
|
||||
assertPluginRan(config)
|
||||
})
|
||||
|
||||
it('should not run if dsn is not provided', () => {
|
||||
const plugin = sentry({ enabled: true, dsn: undefined })
|
||||
const config = plugin(createConfig())
|
||||
|
||||
assertPluginDidNotRun(config)
|
||||
})
|
||||
|
||||
it('should respect enabled: false', () => {
|
||||
const plugin = sentry({ enabled: false })
|
||||
const config = plugin(createConfig())
|
||||
|
||||
assertPluginDidNotRun(config)
|
||||
})
|
||||
})
|
||||
|
||||
function assertPluginRan(config: Config) {
|
||||
expect(config.admin?.webpack).toBeDefined()
|
||||
expect(config.hooks?.afterError).toBeDefined()
|
||||
expect(startSentrySpy).toHaveBeenCalled()
|
||||
}
|
||||
|
||||
function assertPluginDidNotRun(config: Config) {
|
||||
expect(config.admin?.webpack).toBeDefined()
|
||||
expect(config.hooks?.afterError).toBeUndefined()
|
||||
expect(startSentrySpy).not.toHaveBeenCalled()
|
||||
}
|
||||
|
||||
function createConfig(overrides?: Partial<Config>): Config {
|
||||
return {
|
||||
...defaults,
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
38
packages/plugin-sentry/src/plugin.ts
Normal file
38
packages/plugin-sentry/src/plugin.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/* eslint-disable no-console */
|
||||
import type { Config } from 'payload/config'
|
||||
|
||||
import { captureException } from './captureException'
|
||||
import { startSentry } from './startSentry'
|
||||
import type { PluginOptions } from './types'
|
||||
import { extendWebpackConfig } from './webpack'
|
||||
|
||||
export const sentry =
|
||||
(pluginOptions: PluginOptions) =>
|
||||
(incomingConfig: Config): Config => {
|
||||
let config = { ...incomingConfig }
|
||||
const webpack = extendWebpackConfig(incomingConfig)
|
||||
|
||||
config.admin = {
|
||||
...(config.admin || {}),
|
||||
webpack,
|
||||
}
|
||||
|
||||
if (pluginOptions.enabled === false || !pluginOptions.dsn) {
|
||||
return config
|
||||
}
|
||||
|
||||
config.hooks = {
|
||||
...(incomingConfig.hooks || {}),
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
afterError: (err: any) => {
|
||||
captureException(err)
|
||||
},
|
||||
}
|
||||
|
||||
startSentry({
|
||||
dsn: pluginOptions.dsn,
|
||||
options: pluginOptions.options || {},
|
||||
})
|
||||
|
||||
return config
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable no-console */
|
||||
import * as Sentry from '@sentry/node'
|
||||
import type { NextFunction, Request, Response } from 'express'
|
||||
import express from 'express'
|
||||
|
||||
import type { PluginOptions } from './types'
|
||||
|
||||
export const startSentry = (pluginOptions: PluginOptions): any => {
|
||||
export const startSentry = (pluginOptions: PluginOptions): void => {
|
||||
const { dsn, options } = pluginOptions
|
||||
|
||||
try {
|
||||
@@ -42,7 +44,12 @@ export const startSentry = (pluginOptions: PluginOptions): any => {
|
||||
}) as express.ErrorRequestHandler,
|
||||
)
|
||||
|
||||
app.use(function onError(err, req, res, next) {
|
||||
app.use(function onError(
|
||||
_err: unknown,
|
||||
_req: Request,
|
||||
res: Response & { sentry?: string },
|
||||
_next: NextFunction,
|
||||
) {
|
||||
res.statusCode = 500
|
||||
res.end(res.sentry + '\n')
|
||||
})
|
||||
|
||||
@@ -2,7 +2,8 @@ import type { RequestHandlerOptions } from '@sentry/node/types/handlers'
|
||||
import type { ClientOptions } from '@sentry/types'
|
||||
|
||||
export interface PluginOptions {
|
||||
dsn: string
|
||||
dsn?: string
|
||||
enabled?: boolean
|
||||
options?: {
|
||||
init?: Partial<ClientOptions>
|
||||
requestHandler?: RequestHandlerOptions
|
||||
|
||||
8464
packages/plugin-sentry/yarn.lock
Normal file
8464
packages/plugin-sentry/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user