teppi-check 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # teppi-check
2
+
3
+ Send one unpaid request to any paid endpoint and see what it actually advertises.
4
+
5
+ ```bash
6
+ npx teppi-check https://some-seller.example/v1/extract
7
+ ```
8
+
9
+ No install and no dependencies: the published package is a single bundled file, so the validator
10
+ that reads a schema here is the same build that read it when the record was written.
11
+
12
+ It sends the request the scheduled prober sends. Both call one `handshake` function, and a test
13
+ runs the two side by side and fails if the bytes on the wire differ. That is what makes an entry
14
+ in the record something you can check rather than something you are asked to accept.
15
+
16
+ ```
17
+ POST https://some-seller.example/v1/extract
18
+ 2026-08-30T10:22:14.263Z
19
+
20
+ 402 in 118ms
21
+ endpoint answered ok
22
+ asks for payment ok
23
+ payment terms parse ok
24
+ read from the body
25
+ offers at least one way to pay ok
26
+ 1 option(s)
27
+ price is stated ok
28
+ network is stated ok
29
+ scheme is stated ok
30
+ payout address is stated ok
31
+ asset is stated ok
32
+ input schema is usable ok
33
+ output schema is usable fail
34
+ not declared, so no response can ever be checked against it
35
+ payment terms are not cached fail
36
+ no cache-control, so a proxy may serve stale terms
37
+
38
+ advertised
39
+ 10000 0x2222...2222 on eip155:8453 via exact
40
+
41
+ request sha256:ba6f7ff0...0878
42
+ response sha256:0a83a213...2496
43
+
44
+ 2 checks failed
45
+ ```
46
+
47
+ ## Why this exists
48
+
49
+ Teppi keeps the Machine Delivery Record: what happened when someone paid a machine service and
50
+ waited for something back. A record is only worth reading if a stranger can check it, so the
51
+ probe that produces it ships as a command anyone can run. Point it at an endpoint, compare the
52
+ output to the published entry, and decide for yourself.
53
+
54
+ This is the unpaid half of the probe. It reports what an endpoint promises. Whether it delivers
55
+ takes a purchase, which the full prober does on a schedule.
56
+
57
+ ## What it checks
58
+
59
+ | Check | Fails when |
60
+ |---|---|
61
+ | endpoint answered | connection refused, DNS failure, or timeout |
62
+ | asks for payment | anything other than a 402 |
63
+ | payment terms parse | no readable terms in the `payment-required` header or the body |
64
+ | offers at least one way to pay | `accepts` is missing or empty |
65
+ | price, network, scheme, payout address, asset | any entry in `accepts` leaves one unstated |
66
+ | input schema is usable | absent, or present but not a compilable JSON Schema |
67
+ | output schema is usable | same. Without one, no response can ever be validated |
68
+ | payment terms are not cached | no `no-store` or `no-cache`, so a proxy may serve stale terms and stale nonces |
69
+
70
+ Terms are read from the `payment-required` header (base64 or plain JSON) or from the response
71
+ body, because deployed servers use both.
72
+
73
+ ## Options
74
+
75
+ ```
76
+ --method <verb> default POST
77
+ --body <json|@file> default {}
78
+ --json machine readable output
79
+ --timeout <ms> default 15000
80
+ --user-agent <ua> default node
81
+ ```
82
+
83
+ Exit codes: `0` every check passed, `1` a check failed, `2` the endpoint could not be reached.
84
+
85
+ Requests go over HTTPS only, apart from localhost.
86
+
87
+ ## Use it in CI
88
+
89
+ ```yaml
90
+ - run: npx teppi-check https://your-api.example/v1/thing
91
+ ```
92
+
93
+ The command fails the build when your own endpoint stops advertising what it should, which is
94
+ the failure mode nobody notices until buyers quietly stop calling.
95
+
96
+ ## Library
97
+
98
+ ```ts
99
+ import { probe } from 'teppi-check';
100
+
101
+ const result = await probe({ url: 'https://some-seller.example/v1/extract' });
102
+ console.log(result.verdict, result.checks);
103
+ ```
104
+
105
+ MIT.
@@ -0,0 +1,20 @@
1
+ import { type PaymentTerms } from './terms.js';
2
+ export type CheckStatus = 'pass' | 'fail' | 'skip';
3
+ export type Check = {
4
+ readonly id: string;
5
+ readonly label: string;
6
+ readonly status: CheckStatus;
7
+ readonly detail?: string;
8
+ };
9
+ export declare function schemaCheck(id: string, label: string, schema: unknown): Check;
10
+ export type HandshakeInput = {
11
+ readonly status: number;
12
+ readonly headers: Headers;
13
+ readonly terms: PaymentTerms | null;
14
+ readonly parseError: string | null;
15
+ readonly source: string;
16
+ };
17
+ export declare function runHandshakeChecks(input: HandshakeInput): Check[];
18
+ export declare function unreachable(reason: string): Check[];
19
+ export declare function verdictOf(checks: readonly Check[]): 'pass' | 'fail';
20
+ //# sourceMappingURL=checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2B,KAAK,YAAY,EAAsB,MAAM,mBAAmB,CAAC;AAGnG,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEnD,MAAM,MAAM,KAAK,GAAG;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAqBF,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,KAAK,CAa7E;AAED,MAAM,MAAM,cAAc,GAAG;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB,CAAC;AA+BF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,EAAE,CA4CjE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,CAEnD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,MAAM,GAAG,MAAM,CAEnE"}
package/npm/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}