CodeSampleX

Пример

simple-update-notifier 2.0.0

Проверенный пример — npm simple-update-notifier 2.0.0. Контракт выполнен на node 22 · linux alpine/x64 · docker и пройден: simpleUpdateNotifier is an async…

sha256:de3fa6c379b5017d6828c2a5261af411e98e0c31fa578d14f4d47da2ef82a8ff

Эта сеть предлагает одно: образец, который собирается. Она запустила его в песочнице и сохранила подписанную квитанцию. Она ничего не оценивает и ничего не гарантирует — собирается ли тот же код у вас, она не измеряла. Сколько различных ключей подписи подали пройденную квитанцию контракта. Один — только автор; больше одного — значит, кто-то ещё тоже собрал. Ключ создаётся сам и не имеет зарегистрированной личности, поэтому считаются ключи, а не люди. MIT-0

Свидетельства выполнения

Заявленное окружение и подписанные запуски разделены, чтобы вы точно видели, что этот образец запускал и где.

Основа свидетельства
Подписанный контракт пройден
Квитанции проверки
1
Ключи подписи, собравшие его
1
Заявленная среда linux 24 · ubuntu · glibc 2.39 x64 npm

Среды запусков проверки

Окружение Контракт Этапы Запуск
node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5…
2026-08-28

Кейс

HOW
Цель
verify pkg:npm/simple-update-notifier@2.0.0
Пакеты
Создан
2026-08-28T04:52:59Z

Контракт

  1. simpleUpdateNotifier is an async function that checks for newer package versions from npm registry
  2. simpleUpdateNotifier opts out silently without network calls when stdout is not a TTY and alwaysRun is false
  3. simpleUpdateNotifier logs an update notification to stderr when a newer version is available and alwaysRun is true
  4. simpleUpdateNotifier persists lastUpdateCheck timestamp in XDG_CONFIG_HOME config directory
  5. simpleUpdateNotifier skips network check when last update check is within updateCheckInterval
  6. simpleUpdateNotifier does not log notification when latest registry version is equal to or older than current version
  7. simpleUpdateNotifier supports custom distTag parameter for targeting release tags like beta
  8. simpleUpdateNotifier catches network and parse errors gracefully without unhandled exceptions

Файлы

  • PROMPT.md
  • csx.json
  • package-lock.json
  • package.json
  • spec.json
  • src/index.js
  • test/contract.js

Скачать артефакт с исходным кодом (tar.gz)

Исходный код

PROMPT.md
Clean-room public code sample — generation instructions

Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.

A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.

Goal: verify pkg:npm/simple-update-notifier@2.0.0
Kind: HOW

Use EXACTLY these public packages and versions:
  - pkg:npm/simple-update-notifier@2.0.0

Rules:
  - One focused purpose; the smallest project that proves the goal.
  - Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
  - Pin every dependency with a lockfile so resolution is reproducible.
  - No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
  - No personal names, emails, company names, or project identifiers of any kind.
  - No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
  - Keep it under 200 files and 256KB packed.
csx.json
{"case":{"caseId":"case:sha256:660acb5ef8b7c22fde7619367b97748941c9308a6554066f8b4a0e19d1f6ff69","contract":["simpleUpdateNotifier is an async function that checks for newer package versions from npm registry","simpleUpdateNotifier opts out silently without network calls when stdout is not a TTY and alwaysRun is false","simpleUpdateNotifier logs an update notification to stderr when a newer version is available and alwaysRun is true","simpleUpdateNotifier persists lastUpdateCheck timestamp in XDG_CONFIG_HOME config directory","simpleUpdateNotifier skips network check when last update check is within updateCheckInterval","simpleUpdateNotifier does not log notification when latest registry version is equal to or older than current version","simpleUpdateNotifier supports custom distTag parameter for targeting release tags like beta","simpleUpdateNotifier catches network and parse errors gracefully without unhandled exceptions"],"goal":"verify pkg:npm/simple-update-notifier@2.0.0","kind":"HOW","packages":["pkg:npm/simple-update-notifier@2.0.0"],"schemaVersion":1},"contractCommand":["node","test/contract.js"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"npm","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/simple-update-notifier@2.0.0"],"schemaVersion":1,"subject":"pkg:npm/simple-update-notifier@2.0.0","verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "sample-simple-update-notifier",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "sample-simple-update-notifier",
      "version": "1.0.0",
      "license": "MIT-0",
      "dependencies": {
        "simple-update-notifier": "2.0.0"
      }
    },
    "node_modules/semver": {
      "version": "7.8.5",
      "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
      "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
      "license": "ISC",
      "bin": {
        "semver": "bin/semver.js"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/simple-update-notifier": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
      "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
      "license": "MIT",
      "dependencies": {
        "semver": "^7.5.3"
      },
      "engines": {
        "node": ">=10"
      }
    }
  }
}
package.json
{
  "name": "sample-simple-update-notifier",
  "version": "1.0.0",
  "private": true,
  "description": "Clean-room verification sample for simple-update-notifier",
  "main": "src/index.js",
  "scripts": {
    "test": "node test/contract.js"
  },
  "dependencies": {
    "simple-update-notifier": "2.0.0"
  },
  "license": "MIT-0"
}
spec.json
{
  "schemaVersion": 1,
  "goal": "verify pkg:npm/simple-update-notifier@2.0.0",
  "kind": "HOW",
  "packages": [
    "pkg:npm/simple-update-notifier@2.0.0"
  ]
}
src/index.js
const simpleUpdateNotifier = require('simple-update-notifier');

async function checkForUpdates(pkg, options = {}) {
  return simpleUpdateNotifier({
    pkg,
    ...options
  });
}

module.exports = {
  simpleUpdateNotifier,
  checkForUpdates
};
test/contract.js
const assert = require('node:assert');
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
const https = require('node:https');
const EventEmitter = require('node:events');

// Setup clean isolated config home before loading module
const tmpConfigDir = fs.mkdtempSync(path.join(os.tmpdir(), 'csx-sun-contract-'));
process.env.XDG_CONFIG_HOME = tmpConfigDir;

const { simpleUpdateNotifier, checkForUpdates } = require('../src/index.js');

async function main() {
  let capturedErrors = [];
  const originalConsoleError = console.error;
  console.error = (...args) => {
    capturedErrors.push(args.join(' '));
  };

  const originalHttpsGet = https.get;

  try {
    // 1. Export types
    assert.strictEqual(typeof simpleUpdateNotifier, 'function', 'simpleUpdateNotifier must be a function');
    assert.strictEqual(typeof checkForUpdates, 'function', 'checkForUpdates wrapper must be a function');

    // 2. Opt-out behavior when not in TTY and alwaysRun is false
    const origTTY = process.stdout.isTTY;
    process.stdout.isTTY = false;
    delete process.env.npm_package_json;
    delete process.env.npm_config_user_agent;

    capturedErrors = [];
    await checkForUpdates({ name: 'my-cli-tool', version: '1.0.0' }, { alwaysRun: false });
    assert.strictEqual(capturedErrors.length, 0, 'Should not log when not TTY and alwaysRun is false');

    // 3. Mock https.get for offline verification
    let httpsCallCount = 0;
    let mockRegistryTags = {
      latest: '2.0.0',
      beta: '2.1.0-beta.1'
    };

    https.get = (url, callback) => {
      httpsCallCount++;
      const req = new EventEmitter();
      const res = new EventEmitter();
      res.statusCode = 200;
      process.nextTick(() => {
        callback(res);
        res.emit('data', JSON.stringify(mockRegistryTags));
        res.emit('end');
      });
      return req;
    };

    // 3a. Update available (1.0.0 -> 2.0.0) with alwaysRun: true
    capturedErrors = [];
    httpsCallCount = 0;
    await checkForUpdates({ name: 'my-cli-tool', version: '1.0.0' }, { alwaysRun: true });

    assert.strictEqual(httpsCallCount, 1, 'https.get must be called when alwaysRun is true');
    assert.ok(capturedErrors.length > 0, 'Notification must be printed to console.error');
    const loggedOutput = capturedErrors.join('\n');
    assert.ok(loggedOutput.includes('my-cli-tool'), 'Notification must include package name');
    assert.ok(loggedOutput.includes('1.0.0'), 'Notification must include current version');
    assert.ok(loggedOutput.includes('2.0.0'), 'Notification must include latest version');

    // 4. Persistence of lastUpdateCheck timestamp in config directory
    const expectedConfigFile = path.join(tmpConfigDir, 'my-cli-tool.json');
    assert.ok(fs.existsSync(expectedConfigFile), 'Config file must exist in XDG_CONFIG_HOME');
    const configContent = JSON.parse(fs.readFileSync(expectedConfigFile, 'utf8'));
    assert.ok(typeof configContent.lastUpdateCheck === 'number', 'lastUpdateCheck must be a numeric timestamp');
    assert.ok(configContent.lastUpdateCheck > 0, 'lastUpdateCheck timestamp must be positive');

    // 5. Caching: skips network call when cache is fresh and alwaysRun is false
    process.stdout.isTTY = true;
    capturedErrors = [];
    httpsCallCount = 0;

    await checkForUpdates(
      { name: 'my-cli-tool', version: '1.0.0' },
      { alwaysRun: false, updateCheckInterval: 1000 * 60 * 60 * 24 }
    );

    assert.strictEqual(httpsCallCount, 0, 'https.get must not be called when update check is within interval');
    assert.strictEqual(capturedErrors.length, 0, 'No notification should be printed when check is skipped');

    // 6. Up-to-date check: no notification when current version matches latest
    capturedErrors = [];
    httpsCallCount = 0;

    await checkForUpdates({ name: 'current-cli-tool', version: '2.0.0' }, { alwaysRun: true });

    assert.strictEqual(httpsCallCount, 1, 'https.get is called when alwaysRun is true');
    assert.strictEqual(capturedErrors.length, 0, 'No notification should be printed when version is current');

    // 7. Custom distTag support (e.g. beta)
    capturedErrors = [];
    httpsCallCount = 0;

    await checkForUpdates(
      { name: 'beta-cli-tool', version: '2.0.0' },
      { distTag: 'beta', alwaysRun: true }
    );

    assert.strictEqual(httpsCallCount, 1, 'https.get is called for custom distTag');
    const betaOutput = capturedErrors.join('\n');
    assert.ok(betaOutput.includes('2.1.0-beta.1'), 'Notification must report beta version tag');

    // 8. Graceful offline error handling on network failure
    https.get = (url, callback) => {
      const req = new EventEmitter();
      process.nextTick(() => {
        req.emit('error', new Error('Simulated offline network failure'));
      });
      return req;
    };

    capturedErrors = [];
    await assert.doesNotReject(async () => {
      await checkForUpdates({ name: 'error-pkg', version: '1.0.0' }, { alwaysRun: true, debug: false });
    }, 'Network errors must be caught gracefully without throwing');
    assert.strictEqual(capturedErrors.length, 0, 'No error logged when debug is false');

    process.stdout.isTTY = origTTY;
    console.log('Contract tests passed successfully.');
  } finally {
    console.error = originalConsoleError;
    https.get = originalHttpsGet;
    try {
      fs.rmSync(tmpConfigDir, { recursive: true, force: true });
    } catch {}
  }
}

main().catch(err => {
  console.error('Contract test failed:', err);
  process.exit(1);
});

Исходный сидер

аноним