Пример
http2-wrapper 1.0.3: Agent, auto, request
Проверенный пример — npm http2-wrapper 1.0.3: Agent, auto, request. Контракт выполнен на node 22 · linux alpine/x64 · docker и пройден.
sha256:821ebfbe0a644a937bb52973f75043706135694314ef9a55dc17da5c04db971a
Эта сеть предлагает одно: образец, который собирается. Она запустила его в песочнице и сохранила подписанную квитанцию. Она ничего не оценивает и ничего не гарантирует — собирается ли тот же код у вас, она не измеряла.
Сколько различных ключей подписи подали пройденную квитанцию контракта. Один — только автор; больше одного — значит, кто-то ещё тоже собрал. Ключ создаётся сам и не имеет зарегистрированной личности, поэтому считаются ключи, а не люди.
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/http2-wrapper@1.0.3
- Пакеты
- Символы
-
- http2-wrapper.Agent
- http2-wrapper.auto
- http2-wrapper.request
- Создан
- 2026-08-28T05:59:46Z
Контракт
- http2-wrapper exports Agent, auto, request, get, ClientRequest, and IncomingMessage
- Agent manages HTTP/2 session options, settings, and connection lifecycle
- request initiates HTTP/2 client requests supporting custom HTTP methods, headers, and request body streams
- get executes HTTP/2 GET requests with automatic request termination
- auto performs ALPN negotiation to dispatch requests to HTTP/2 or HTTP/1
- ClientRequest validates request options and throws on invalid protocol
Файлы
- PROMPT.md
- csx.json
- package-lock.json
- package.json
- spec.json
- src/index.js
- test/contract.mjs
Исходный код
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/http2-wrapper@1.0.3
Kind: HOW
Use EXACTLY these public packages and versions:
- pkg:npm/http2-wrapper@1.0.3
Demonstrate these symbols/APIs:
- http2-wrapper.Agent
- http2-wrapper.auto
- http2-wrapper.request
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.
{"case":{"caseId":"case:sha256:f702a5319deece87905dd17d43d5a41eb9eee18145efd852bf9ee3a4a4d66207","contract":["http2-wrapper exports Agent, auto, request, get, ClientRequest, and IncomingMessage","Agent manages HTTP/2 session options, settings, and connection lifecycle","request initiates HTTP/2 client requests supporting custom HTTP methods, headers, and request body streams","get executes HTTP/2 GET requests with automatic request termination","auto performs ALPN negotiation to dispatch requests to HTTP/2 or HTTP/1","ClientRequest validates request options and throws on invalid protocol"],"goal":"verify pkg:npm/http2-wrapper@1.0.3","kind":"HOW","packages":["pkg:npm/http2-wrapper@1.0.3"],"schemaVersion":1,"symbols":["http2-wrapper.Agent","http2-wrapper.auto","http2-wrapper.request"]},"contractCommand":["node","test/contract.mjs"],"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/http2-wrapper@1.0.3"],"schemaVersion":1,"subject":"pkg:npm/http2-wrapper@1.0.3","symbols":["http2-wrapper.Agent","http2-wrapper.auto","http2-wrapper.request"],"verifierAdapter":"node-typescript@1"}
{
"name": "sample-http2-wrapper",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sample-http2-wrapper",
"version": "1.0.0",
"license": "MIT-0",
"dependencies": {
"http2-wrapper": "1.0.3"
}
},
"node_modules/http2-wrapper": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
"integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
"license": "MIT",
"dependencies": {
"quick-lru": "^5.1.1",
"resolve-alpn": "^1.0.0"
},
"engines": {
"node": ">=10.19.0"
}
},
"node_modules/quick-lru": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/resolve-alpn": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
"integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
"license": "MIT"
}
}
}
{
"name": "sample-http2-wrapper",
"version": "1.0.0",
"private": true,
"description": "Clean-room code sample for http2-wrapper@1.0.3",
"main": "src/index.js",
"license": "MIT-0",
"dependencies": {
"http2-wrapper": "1.0.3"
}
}
{
"schemaVersion": 1,
"goal": "verify pkg:npm/http2-wrapper@1.0.3",
"kind": "HOW",
"packages": [
"pkg:npm/http2-wrapper@1.0.3"
],
"symbols": [
"http2-wrapper.Agent",
"http2-wrapper.auto",
"http2-wrapper.request"
]
}
'use strict';
const http2Wrapper = require('http2-wrapper');
/**
* Creates an HTTP/2 Agent instance for managing HTTP/2 sessions and connection pooling.
*
* @param {object} [options] - Agent options such as maxFreeSessions, maxSessions, timeout.
* @returns {http2Wrapper.Agent} Configured Agent instance.
*/
function createAgent(options) {
return new http2Wrapper.Agent(options);
}
/**
* Initiates an HTTP/2 client request with the provided options and callback.
*
* @param {string | URL | object} url - Target URL or request options.
* @param {object | Function} [options] - Request options or response callback.
* @param {Function} [callback] - Response callback receiving IncomingMessage.
* @returns {http2Wrapper.ClientRequest} ClientRequest instance.
*/
function request(url, options, callback) {
return http2Wrapper.request(url, options, callback);
}
/**
* Initiates an HTTP/2 GET request and automatically ends the request stream.
*
* @param {string | URL | object} url - Target URL or request options.
* @param {object | Function} [options] - Request options or response callback.
* @param {Function} [callback] - Response callback receiving IncomingMessage.
* @returns {http2Wrapper.ClientRequest} ClientRequest instance.
*/
function get(url, options, callback) {
return http2Wrapper.get(url, options, callback);
}
/**
* Performs ALPN negotiation to automatically resolve HTTP/1 or HTTP/2 protocol.
*
* @param {string | URL | object} url - Target URL or request options.
* @param {object | Function} [options] - Request options or response callback.
* @param {Function} [callback] - Response callback receiving IncomingMessage.
* @returns {Promise<http2Wrapper.ClientRequest | import('http').ClientRequest>} Promise resolving to request instance.
*/
async function auto(url, options, callback) {
return http2Wrapper.auto(url, options, callback);
}
module.exports = {
http2Wrapper,
createAgent,
request,
get,
auto
};
import assert from 'node:assert';
import http2 from 'node:http2';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const { http2Wrapper, createAgent, request, get, auto } = require('../src/index.js');
const TEST_KEY_B64 = 'LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQzJSdGwwdDZGZUlWUGoKY2Z6K3NuK1FUeU9zNFNHNHRndkhWVUw4djFqbmZsK3plUEwvVGlyWG1BZ0k3eVVsbXZWSlh6OWk0Z21kdDFvQwo0UFNjTjB5K3RsV0UwbUk5UXltVGN4UXVadjlZdHBDNW8xdlhhZDY2ekNDdEtKdmJwaW10M2ZnMWx3YzVQd2Z5Cmx5L1pLNFF6Uy9UbENiUmZOb2kzSEo0V2JqVSt6amQ5N1JxWWJzNnAyUG1LS2c5K0RrYlNvbVFldXNiQzg3M1AKeURXd1dTYk9qMjl2L1BHcXJyMUdSNmlRVVJGMjUvWWFzRHQrZDAycVpiMEphVktpZzZhaDFvdURUSU5ZdjdlbQoyZERiTkRaalJrczlGOEZGSFA4c3I4NU9ZZnFYUkFISW14cXFWaDU4QTlsZnZCRVIrSGhOZzFNaDNjd0lVR3BTCkhjUE94WE1sQWdNQkFBRUNnZ0VBTEcxdTVjTzNUWGZ1bUQ2cGxWUGhBMFhDMG9tcUhEa2svRkFrREhKQUkyWjYKUVlhZXBjdEI1bndjSXo5VXpNcHM5RllHbjEyc1RkaUpsQytMOTRLRURtem5RY0U4cUNWMVhnYmIyYWFKb1BBWQpyT0tzQ1VCNUJRc3BnTU1uMy96clprRTIxU3NMVy9Eb3lVQi83VjB0c3dvVnRmaXNVZE83TlhTQWRNT21iempQCllBWkRKVGh0NXFIdG1iTEZpQkRiQ0ttTkkycGxuSkZKK1Bqdk1HMmtlWXdQWDE1eGgwVUlDZEwvMkRGak1Pbk0KQ0QzSm5jRlhiOTEzZXVIWVFGZ2ZaSkxjRGFWMGJJN2paaHpCb0FXMHRFNldhTkhndFE4SXhRMmNrMWJaYVo3cgpUdm1weU9hNk5xVUVLd3UxMHNzY1N6MWtKZU1WU2JCaTJhUWs5Nk55Z1FLQmdRRFpZbGJUdEVQeTBGZjFrZlRVClZycHpnQ0pFYXArQ2pxYnJ3K3VydFEvV3MvOGVkRzcwNEFBS1R4TGNBSmlXZ3Iya3BwOFVKVEJFUVdENXZJcmQKanJsVHZjVEZXM3dYcnZWSlRPTXAzdEhhOEhNZ1ZGVUUvb3dvb3NCWG54ZU9WZjdWS2tGanlRMVVWUFRHazhCMgp1UkZSSEpFTHJ5ZzJmWUdtcUtmNHI5SjFnUUtCZ1FEV3AvdXdSc1doZWhRQlExcHZ1ZnBVUE11bXBEWTgvVEQyClQwVUIveWJEQTJTbVpWbmxTU2NuNFRpNUNjNGlPQ2s2c1FHQWx5amhWVXF5TTkveERzU2llVzBxZStsMzhYU1EKR0VMZW1jVGxMN0d1WS9JNWxRMy9oVWtoOW1lVEhYMTk1OVhndjJlUStoQzlPVElwbXpObGszRG5saHVSbEZFRgplVGFMUDJFM3BRS0JnQUQ2ZjFlT25TdXZvbVc1bFhlTE9HV2lzd1RKMGhQOVhtVDdTY2xKRkZ3c0RUN3UyVDBDCjhSMGF4QVAzZ0xoVXVGUFFhRERvQmZLWXRMNExDamo3Rm54NUF6UzhONi9IbXRVTW9vMGlzcUVncWZRQVRTMnIKazZmdks1eDVXOXJKS2s5OVZEUUZ5S2lUaFZLTGdiZEhGL3ZjZkE2b2FDN3VtN0hMV280MUJHYUJBb0dCQUtLaQpSNGw1Tllkd3JQT0FDbWNZSzFmamNCRGozY3c3c1BzTmVDVlpJZzhpNVFGRlRPVHhsZDhiUHhUREh4RENLRXExCmpZUFdBejBtbUIrSU9pV3pvTHZROENyK0V4ZXpNek54amtpRmpLNXdnbGkwbFBPWHdURlYxT0VNaGREcXlRZTUKdlV3NCtNalpEaEd2NGhldjVUTVNrTHFGK29GRU5GYkhUZElXeFJ1WkFvR0JBSTFmZVlEcDRlVW9DaWRNWHpKYQpmaG5YUDhmNU05WjdzNmZ2ZGxRcDBod1V1OFVza1E1cjViMTlyRDA4RFlKU3JtYkV4M2MvUm02enF3YVJnUjZRCmVmc1JuWE1hM2xmZHZwV1lRcDRDb09jWDg5ZnRYUnMwR3I1NFl3Zm52b00yRndoM1d1MFl1cnhBTkpVVXdFTnoKL3N0bHRjaWE2TytrVG1reHpYQllXeVRBCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K';
const TEST_CERT_B64 = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURDVENDQWZHZ0F3SUJBZ0lVV3BZT1FodG1yeU0wYnhLandxQXN4bDJoUnNZd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZERVNNQkFHQTFVRUF3d0piRzlqWVd4b2IzTjBNQjRYRFRJMk1EZ3lPREExTlRneE5Wb1hEVEkzTURneQpPREExTlRneE5Wb3dGREVTTUJBR0ExVUVBd3dKYkc5allXeG9iM04wTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGCkFBT0NBUThBTUlJQkNnS0NBUUVBdGtiWmRMZWhYaUZUNDNIOC9ySi9rRThqck9FaHVMWUx4MVZDL0w5WTUzNWYKczNqeS8wNHExNWdJQ084bEpacjFTVjgvWXVJSm5iZGFBdUQwbkRkTXZyWlZoTkppUFVNcGszTVVMbWIvV0xhUQp1YU5iMTJuZXVzd2dyU2liMjZZcHJkMzROWmNIT1Q4SDhwY3YyU3VFTTB2MDVRbTBYemFJdHh5ZUZtNDFQczQzCmZlMGFtRzdPcWRqNWlpb1BmZzVHMHFKa0hyckd3dk85ejhnMXNGa216bzl2Yi96eHFxNjlSa2Vva0ZFUmR1ZjIKR3JBN2ZuZE5xbVc5Q1dsU29vT21vZGFMZzB5RFdMKzNwdG5RMnpRMlkwWkxQUmZCUlJ6L0xLL09UbUg2bDBRQgp5SnNhcWxZZWZBUFpYN3dSRWZoNFRZTlRJZDNNQ0ZCcVVoM0R6c1Z6SlFJREFRQUJvMU13VVRBZEJnTlZIUTRFCkZnUVVLZmM2Yk1mQ056aHVCTHhiZFZHNEppN3VrY3N3SHdZRFZSMGpCQmd3Rm9BVUtmYzZiTWZDTnpodUJMeGIKZFZHNEppN3VrY3N3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBVDVZYwpRcWxJYmlvRE1ab2pYSjk4THh2bCtlYklpSnRsVjRqTk00M1UwNlBhZG9jSW1CT1diWkFsVkVGUmd6SjFXbjZRCjcvQU1jR0UwNWI0d2N1VHBxZzQ3L08rUUMxazhibTdOTjdQVXVFMlFaaVZoUmd6ZXFSVnJ5VExUa2UyZU1QM0kKN3ljaXQreWJVZTF0cWNiaUlnUXRqZ05NNnZhRTRMblM5ek5QbDhWRk5vTHA3cWFMekMwdjJaMnNSMCtQd3lFUQpObWhibDJDbFRaSVhPMVpZa3hTcmJXN2hueW16aUN2MVBBYUs5WG8va3Vsa1MxRFJNelM0TXp6ZnpaRTFabmg3ClJaVlY1cGJIZHNRWnNMOEt3T1Y5NWtsREp4YTlPUGFkQnNJS0lFNHVtd1dYak1DSFpiMWpORzUxQWsrY0MxemYKdnVEYnlkVlhsR1VleWtBak1RPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=';
async function testAll() {
// 1. Export verification
assert.strictEqual(typeof http2Wrapper.Agent, 'function', 'http2Wrapper.Agent constructor should be exported');
assert.strictEqual(typeof http2Wrapper.auto, 'function', 'http2Wrapper.auto should be exported');
assert.strictEqual(typeof http2Wrapper.request, 'function', 'http2Wrapper.request should be exported');
assert.strictEqual(typeof http2Wrapper.get, 'function', 'http2Wrapper.get should be exported');
assert.strictEqual(typeof http2Wrapper.ClientRequest, 'function', 'http2Wrapper.ClientRequest should be exported');
assert.strictEqual(typeof createAgent, 'function', 'createAgent helper should be exported');
assert.strictEqual(typeof request, 'function', 'request helper should be exported');
assert.strictEqual(typeof get, 'function', 'get helper should be exported');
assert.strictEqual(typeof auto, 'function', 'auto helper should be exported');
// 2. Agent instantiation and origin normalization
const customAgent = createAgent({
maxFreeSessions: 5,
timeout: 30000
});
assert(customAgent instanceof http2Wrapper.Agent, 'customAgent should be an instance of Agent');
assert.strictEqual(customAgent.maxFreeSessions, 5, 'customAgent maxFreeSessions should match configuration');
assert.deepStrictEqual(customAgent.settings, { enablePush: false }, 'default agent settings should disable push');
const origin = http2Wrapper.Agent.normalizeOrigin('https://example.com:8443/test/path');
assert.strictEqual(origin, 'https://example.com:8443', 'normalizeOrigin should extract origin correctly');
// 3. ClientRequest validation
assert.throws(
() => request({ protocol: 'ftp:', hostname: 'localhost' }),
{ code: 'ERR_INVALID_PROTOCOL' },
'request should reject invalid protocols with ERR_INVALID_PROTOCOL'
);
// 4. Offline HTTP/2 secure server integration tests
const key = Buffer.from(TEST_KEY_B64, 'base64').toString('utf8');
const cert = Buffer.from(TEST_CERT_B64, 'base64').toString('utf8');
const server = http2.createSecureServer({
key,
cert,
allowHTTP1: true
});
server.on('request', (req, res) => {
if (req.url === '/status') {
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({ status: 'ok', httpVersion: req.httpVersion }));
} else if (req.url === '/echo' && req.method === 'POST') {
let body = '';
req.on('data', (chunk) => { body += chunk; });
req.on('end', () => {
res.writeHead(200, {
'content-type': 'text/plain',
'x-custom-response': 'received'
});
res.end(`echo:${body}`);
});
} else {
res.writeHead(404);
res.end();
}
});
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
const port = server.address().port;
const testAgent = new http2Wrapper.Agent({
rejectUnauthorized: false
});
try {
// 5. Verify request POST with streaming payload
await new Promise((resolve, reject) => {
const req = request({
hostname: '127.0.0.1',
port,
path: '/echo',
method: 'POST',
agent: testAgent,
rejectUnauthorized: false
}, (res) => {
assert.strictEqual(res.statusCode, 200, 'POST status code should be 200');
assert.strictEqual(res.headers['x-custom-response'], 'received', 'custom header should be present in response');
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
assert.strictEqual(data, 'echo:payload-data', 'POST response body should match echoed payload');
resolve();
});
});
req.on('error', reject);
req.write('payload-data');
req.end();
});
// 6. Verify get GET request
await new Promise((resolve, reject) => {
const req = get({
hostname: '127.0.0.1',
port,
path: '/status',
agent: testAgent,
rejectUnauthorized: false
}, (res) => {
assert.strictEqual(res.statusCode, 200, 'GET status code should be 200');
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
const parsed = JSON.parse(data);
assert.strictEqual(parsed.status, 'ok', 'status response should be ok');
assert.strictEqual(parsed.httpVersion, '2.0', 'httpVersion should be 2.0');
resolve();
});
});
req.on('error', reject);
});
// 7. Verify auto ALPN negotiation
await new Promise(async (resolve, reject) => {
try {
const req = await auto({
hostname: '127.0.0.1',
port,
path: '/status',
rejectUnauthorized: false
}, (res) => {
assert.strictEqual(res.statusCode, 200, 'auto request status code should be 200');
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
const parsed = JSON.parse(data);
assert.strictEqual(parsed.status, 'ok', 'auto request response status should be ok');
resolve();
});
});
req.on('error', reject);
req.end();
} catch (err) {
reject(err);
}
});
} finally {
testAgent.destroy();
await new Promise((resolve) => server.close(resolve));
}
console.log('All http2-wrapper contract tests passed successfully.');
}
testAll().catch((err) => {
console.error('Contract test failure:', err);
process.exit(1);
});
Исходный сидер
аноним