← Back to results

Plugin Quality Guide

Practical tips to improve your Signal K plugin's registry score. Most fixes take less than 5 minutes.

Scoring Breakdown

TierPointsHow to pass
Install20npm install --ignore-scripts succeeds
Load15Module exports a function that returns {id, name, start, stop}
Activate15start(config) completes without error — config is populated from your schema defaults
Schema5plugin.schema returns a JSON Schema object
Tests25npm test passes (biggest single tier — see below)
Security20npm audit finds no high or critical vulnerabilities

Quick Wins

1. Fix npm audit issues

npm audit
npm audit fix

Most issues come from transitive dependencies. Update your direct dependencies first. If a vulnerability is in a deep transitive dep you don't control, consider whether you really need that dependency.

2. Add schema defaults

Every property in your schema should have a default value. The registry extracts these and passes them to start(). If your plugin crashes without them, it loses 15 points.

schema: {
  type: 'object',
  properties: {
    interval: {
      type: 'number',
      title: 'Update interval (seconds)',
      default: 60
    }
  }
}

See Plugin Configuration & Schemas for full details.

3. Guard start() against missing config

Even with schema defaults, defensive coding helps:

start(config) {
  const interval = config.interval ?? 60
  const items = config.items || []
}

Adding Tests (25 points)

The registry clones your source repo and runs npm test. The easiest approach uses Node's built-in test runner — zero dependencies needed.

TypeScript (recommended)

Create test/plugin.test.ts:

import { describe, it } from 'node:test'
import assert from 'node:assert/strict'
import pluginFactory from '../src/index'

describe('plugin', () => {
  const app = { debug: () => {}, error: () => {} } as any
  const plugin = pluginFactory(app)

  it('has required interface', () => {
    assert.equal(typeof plugin.start, 'function')
    assert.equal(typeof plugin.stop, 'function')
    assert.ok(plugin.id)
  })

  it('starts and stops without error', () => {
    plugin.start({}, () => {})
    plugin.stop()
  })
})

Add to package.json:

"scripts": {
  "build": "tsc",
  "test": "tsc && node --test dist/test/plugin.test.js"
}

The registry clones your source repo, runs npm install and npm run build, then npm test — so typescript from your devDependencies is available.

JavaScript

Create test/plugin.test.js:

const { describe, it } = require('node:test')
const assert = require('node:assert/strict')
const pluginFactory = require('../plugin/index.js')

describe('plugin', () => {
  const app = { debug: () => {}, error: () => {} }
  const plugin = pluginFactory(app)

  it('has required interface', () => {
    assert.equal(typeof plugin.start, 'function')
    assert.equal(typeof plugin.stop, 'function')
    assert.ok(plugin.id)
  })

  it('starts and stops without error', () => {
    plugin.start({}, () => {})
    plugin.stop()
  })
})

Add to package.json:

"scripts": {
  "test": "node --test test/plugin.test.js"
}
~15 lines, no devDependencies, worth 25 points. Extend with tests for your actual plugin logic from here.

Why node:test? Published npm packages don't include devDependencies, so jest/mocha won't be available when the registry installs your plugin. The registry clones your source repo to run tests, but node:test is built into Node and always available.

Common Issues

activation error: Cannot read properties of undefined

Your start() assumes config has nested objects that don't exist yet. Add default values to nested properties in your schema, or use optional chaining (config.options?.speed ?? 5).

tests: not-runnable

Your test runner (jest, mocha, vitest) isn't installed because devDependencies aren't available. Switch to node:test (built-in) or ensure the test command works after a fresh npm install.

audit-high or audit-critical

Run npm audit locally. Usually it's a transitive dependency. Try npm audit fix or update the parent dependency that pulls it in.

Score didn't improve after a fix?

The registry retests when a new version is published to npm. Bump your version and publish. Alternatively, results older than 7 days are automatically retested on the nightly run.

Further Reading

← Back to results