@stellar-agent-services/protocol 0.0.0-stage → 0.1.1

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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +14 -2
  3. package/dist/canonical-json.d.ts +18 -0
  4. package/dist/canonical-json.d.ts.map +1 -0
  5. package/dist/canonical-json.js +86 -0
  6. package/dist/canonical-json.js.map +1 -0
  7. package/dist/errors.d.ts +85 -0
  8. package/dist/errors.d.ts.map +1 -0
  9. package/dist/errors.js +46 -0
  10. package/dist/errors.js.map +1 -0
  11. package/dist/headers.d.ts +15 -0
  12. package/dist/headers.d.ts.map +1 -0
  13. package/dist/headers.js +29 -0
  14. package/dist/headers.js.map +1 -0
  15. package/dist/index.d.ts +11 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +18 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/jobs.d.ts +62 -0
  20. package/dist/jobs.d.ts.map +1 -0
  21. package/dist/jobs.js +66 -0
  22. package/dist/jobs.js.map +1 -0
  23. package/dist/manifest.d.ts +95 -0
  24. package/dist/manifest.d.ts.map +1 -0
  25. package/dist/manifest.js +144 -0
  26. package/dist/manifest.js.map +1 -0
  27. package/dist/networks.d.ts +19 -0
  28. package/dist/networks.d.ts.map +1 -0
  29. package/dist/networks.js +33 -0
  30. package/dist/networks.js.map +1 -0
  31. package/dist/receipts.d.ts +112 -0
  32. package/dist/receipts.d.ts.map +1 -0
  33. package/dist/receipts.js +35 -0
  34. package/dist/receipts.js.map +1 -0
  35. package/dist/standard.d.ts +25 -0
  36. package/dist/standard.d.ts.map +1 -0
  37. package/dist/standard.js +29 -0
  38. package/dist/standard.js.map +1 -0
  39. package/dist/strkey.d.ts +7 -0
  40. package/dist/strkey.d.ts.map +1 -0
  41. package/dist/strkey.js +56 -0
  42. package/dist/strkey.js.map +1 -0
  43. package/dist/validation-request.d.ts +32 -0
  44. package/dist/validation-request.d.ts.map +1 -0
  45. package/dist/validation-request.js +29 -0
  46. package/dist/validation-request.js.map +1 -0
  47. package/package.json +37 -4
  48. package/schemas/manifest.schema.json +272 -0
  49. package/schemas/validation-request.schema.json +43 -0
  50. package/schemas/verification-receipt.schema.json +149 -0
  51. package/test-vectors/README.md +45 -0
  52. package/test-vectors/binding-hash.json +64 -0
  53. package/test-vectors/canonical-json.json +94 -0
  54. package/test-vectors/challenges.json +245 -0
  55. package/test-vectors/headers.json +37 -0
  56. package/test-vectors/job-states.json +39 -0
  57. package/test-vectors/manifests.json +1322 -0
  58. package/test-vectors/problems.json +15 -0
  59. package/test-vectors/validation-requests.json +98 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stellar Agent Services contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,15 @@
1
- # Temporary Holding Version
1
+ # @stellar-agent-services/protocol
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Provider Standard v1 as code. It holds the manifest, job, receipt and header definitions that every other
4
+ package shares. Specification: [docs/provider-standard.md](../../docs/provider-standard.md).
5
+
6
+ | Path | Contents |
7
+ | --- | --- |
8
+ | [`schemas/manifest.schema.json`](schemas/manifest.schema.json) | The manifest JSON Schema (2020-12) |
9
+ | [`schemas/verification-receipt.schema.json`](schemas/verification-receipt.schema.json), [`schemas/validation-request.schema.json`](schemas/validation-request.schema.json) | The two Validation Registry documents: the verifier's receipt and the owner's request |
10
+ | [`test-vectors/`](test-vectors) | Known-answer tests that implementations in any language can use |
11
+ | `src/` | Types (manifest, `JobView`, `Problem`, `PaymentReceipt`, `VerificationReceipt`, `ValidationRequest`), constants and the reference checks: `canonicalJson`, `bindingHash`, `checkManifestRules`, `checkChallenge`, `stellarAddressKind`, `canTransition`, `chargedFor`, `conformanceLevel`, `validationRequestHash`, `validationRequestDataUri` |
12
+
13
+ - No runtime dependencies and no signing code, so the read-only discovery server can import it safely.
14
+ - It ships the schema rather than a validator. To validate a manifest, run any JSON Schema 2020-12 validator,
15
+ then `checkManifestRules()` (spec §2.4).
@@ -0,0 +1,18 @@
1
+ /** A JSON value as JSON.parse produces it. */
2
+ export type JsonValue = null | boolean | number | string | JsonValue[] | JsonObject;
3
+ export interface JsonObject {
4
+ [key: string]: JsonValue;
5
+ }
6
+ /**
7
+ * Serializes a JSON value the RFC 8785 way: no whitespace, object keys sorted by UTF-16 code units,
8
+ * ECMAScript number and string formatting.
9
+ *
10
+ * Throws on anything that is not I-JSON (RFC 7493): NaN, Infinity, lone surrogates, undefined,
11
+ * functions, cycles, sparse arrays and non-plain objects.
12
+ */
13
+ export declare function canonicalJson(value: unknown): string;
14
+ /** Lowercase hex SHA-256 of a string (as UTF-8) or of bytes. Uses Web Crypto: Node, Workers, Deno, Bun. */
15
+ export declare function sha256Hex(data: string | Uint8Array): Promise<string>;
16
+ /** sha256Hex(canonicalJson(value)): the hash used for binding hashes and shared documents. */
17
+ export declare function canonicalSha256(value: unknown): Promise<string>;
18
+ //# sourceMappingURL=canonical-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical-json.d.ts","sourceRoot":"","sources":["../src/canonical-json.ts"],"names":[],"mappings":"AAOA,8CAA8C;AAC9C,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,GAAG,UAAU,CAAC;AACpF,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAKD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpD;AAED,2GAA2G;AAC3G,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1E;AAED,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAE/D"}
@@ -0,0 +1,86 @@
1
+ // Canonical JSON (RFC 8785, JCS) and SHA-256.
2
+ //
3
+ // Used for the job binding hash (service + input), manifest hashes and verification receipt
4
+ // hashes, so that key order or whitespace can never change a hash. Other projects (e.g. ERC-8126 on
5
+ // Stellar) must produce the same bytes for shared Validation Registry documents, so this follows
6
+ // RFC 8785 exactly and is pinned by test-vectors/canonical-json.json.
7
+ // With the `u` flag a valid surrogate pair is one code point, so this matches only lone surrogates.
8
+ const LONE_SURROGATE = /[\uD800-\uDFFF]/u;
9
+ /**
10
+ * Serializes a JSON value the RFC 8785 way: no whitespace, object keys sorted by UTF-16 code units,
11
+ * ECMAScript number and string formatting.
12
+ *
13
+ * Throws on anything that is not I-JSON (RFC 7493): NaN, Infinity, lone surrogates, undefined,
14
+ * functions, cycles, sparse arrays and non-plain objects.
15
+ */
16
+ export function canonicalJson(value) {
17
+ return serialize(value, new Set());
18
+ }
19
+ /** Lowercase hex SHA-256 of a string (as UTF-8) or of bytes. Uses Web Crypto: Node, Workers, Deno, Bun. */
20
+ export async function sha256Hex(data) {
21
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : new Uint8Array(data);
22
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
23
+ return Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join("");
24
+ }
25
+ /** sha256Hex(canonicalJson(value)): the hash used for binding hashes and shared documents. */
26
+ export function canonicalSha256(value) {
27
+ return sha256Hex(canonicalJson(value));
28
+ }
29
+ function serialize(value, ancestors) {
30
+ if (value === null)
31
+ return "null";
32
+ switch (typeof value) {
33
+ case "boolean":
34
+ return value ? "true" : "false";
35
+ case "number":
36
+ if (!Number.isFinite(value))
37
+ throw new TypeError("canonicalJson: NaN and Infinity are not JSON");
38
+ // ECMAScript Number-to-String, as RFC 8785 §3.2.2.3 requires. -0 becomes "0".
39
+ return JSON.stringify(value);
40
+ case "string":
41
+ return serializeString(value);
42
+ case "object":
43
+ break;
44
+ default:
45
+ throw new TypeError(`canonicalJson: a ${typeof value} is not JSON`);
46
+ }
47
+ if (ancestors.has(value))
48
+ throw new TypeError("canonicalJson: circular structure");
49
+ ancestors.add(value);
50
+ try {
51
+ if (Array.isArray(value)) {
52
+ const items = [];
53
+ for (let i = 0; i < value.length; i++) {
54
+ if (!(i in value))
55
+ throw new TypeError("canonicalJson: sparse arrays are not JSON");
56
+ items.push(serialize(value[i], ancestors));
57
+ }
58
+ return `[${items.join(",")}]`;
59
+ }
60
+ const prototype = Object.getPrototypeOf(value);
61
+ if (prototype !== Object.prototype && prototype !== null) {
62
+ throw new TypeError("canonicalJson: only plain objects and arrays are JSON");
63
+ }
64
+ const record = value;
65
+ // The default sort compares UTF-16 code units, which is the order RFC 8785 §3.2.3 requires.
66
+ const members = Object.keys(record)
67
+ .sort()
68
+ .map((key) => {
69
+ const member = record[key];
70
+ if (member === undefined)
71
+ throw new TypeError(`canonicalJson: "${key}" is undefined`);
72
+ return `${serializeString(key)}:${serialize(member, ancestors)}`;
73
+ });
74
+ return `{${members.join(",")}}`;
75
+ }
76
+ finally {
77
+ ancestors.delete(value);
78
+ }
79
+ }
80
+ function serializeString(value) {
81
+ if (LONE_SURROGATE.test(value))
82
+ throw new TypeError("canonicalJson: string contains a lone surrogate");
83
+ // JSON.stringify escapes exactly what RFC 8785 §3.2.2.2 requires and nothing more.
84
+ return JSON.stringify(value);
85
+ }
86
+ //# sourceMappingURL=canonical-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical-json.js","sourceRoot":"","sources":["../src/canonical-json.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ export declare const PROBLEM_CONTENT_TYPE = "application/problem+json";
2
+ /** Codes for HTTP error responses, with their status and default title (§6). */
3
+ export declare const PROBLEMS: {
4
+ readonly invalid_request: {
5
+ readonly status: 400;
6
+ readonly title: "The request is malformed";
7
+ };
8
+ readonly invalid_input: {
9
+ readonly status: 400;
10
+ readonly title: "Input does not match the service's inputSchema";
11
+ };
12
+ readonly service_not_found: {
13
+ readonly status: 404;
14
+ readonly title: "No service with that name";
15
+ };
16
+ readonly job_not_found: {
17
+ readonly status: 404;
18
+ readonly title: "Job not found";
19
+ };
20
+ readonly request_in_progress: {
21
+ readonly status: 409;
22
+ readonly title: "The job is still being claimed or settled";
23
+ readonly retryAfter: true;
24
+ };
25
+ readonly payload_too_large: {
26
+ readonly status: 413;
27
+ readonly title: "The input is larger than maxInputBytes";
28
+ };
29
+ readonly idempotency_key_reused: {
30
+ readonly status: 422;
31
+ readonly title: "The job id is bound to a different request";
32
+ };
33
+ readonly rate_limited: {
34
+ readonly status: 429;
35
+ readonly title: "Too many requests";
36
+ readonly retryAfter: true;
37
+ };
38
+ readonly unavailable: {
39
+ readonly status: 503;
40
+ readonly title: "The service is unavailable";
41
+ readonly retryAfter: true;
42
+ };
43
+ };
44
+ export type ProblemCode = keyof typeof PROBLEMS;
45
+ /** Codes for a failed job, in the job view's `error.code` (§6). */
46
+ export declare const JOB_FAILURES: {
47
+ readonly service_failed: {
48
+ readonly title: "The work failed";
49
+ };
50
+ readonly output_invalid: {
51
+ readonly title: "The output did not match outputSchema";
52
+ };
53
+ readonly timeout: {
54
+ readonly title: "The work did not finish in time";
55
+ };
56
+ readonly payment_failed: {
57
+ readonly title: "Settlement did not happen";
58
+ };
59
+ };
60
+ export type JobFailureCode = keyof typeof JOB_FAILURES;
61
+ /** An RFC 9457 problem. `status` is present on HTTP errors and absent on a failed job's `error`. */
62
+ export interface Problem<Code extends string = ProblemCode> {
63
+ type: string;
64
+ title: string;
65
+ status?: number;
66
+ detail?: string;
67
+ code: Code;
68
+ /** invalid_input only: where the input fails its schema. */
69
+ errors?: InputError[];
70
+ }
71
+ export interface InputError {
72
+ /** JSON Pointer (RFC 6901) into the input. */
73
+ pointer: string;
74
+ message: string;
75
+ }
76
+ /** The problem `type` URI for a problem or job failure code. */
77
+ export declare function problemType(code: ProblemCode | JobFailureCode): string;
78
+ /** Builds the body of an HTTP error response. Send it as PROBLEM_CONTENT_TYPE with PROBLEMS[code].status. */
79
+ export declare function problem(code: ProblemCode, options?: {
80
+ detail?: string;
81
+ errors?: InputError[];
82
+ }): Problem;
83
+ /** Builds a failed job's `error`. */
84
+ export declare function jobError(code: JobFailureCode, detail?: string): Problem<JobFailureCode>;
85
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,oBAAoB,6BAA6B,CAAC;AAE/D,gFAAgF;AAChF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAUoE,CAAC;AAE1F,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,QAAQ,CAAC;AAEhD,mEAAmE;AACnE,eAAO,MAAM,YAAY;;;;;;;;;;;;;CAK6B,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,YAAY,CAAC;AAEvD,oGAAoG;AACpG,MAAM,WAAW,OAAO,CAAC,IAAI,SAAS,MAAM,GAAG,WAAW;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC;IACX,4DAA4D;IAC5D,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,cAAc,GAAG,MAAM,CAEtE;AAED,6GAA6G;AAC7G,wBAAgB,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAA;CAAO,GAAG,OAAO,CAG5G;AAED,qCAAqC;AACrC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAIvF"}
package/dist/errors.js ADDED
@@ -0,0 +1,46 @@
1
+ // Error responses (docs/provider-standard.md §6).
2
+ //
3
+ // Every error other than 402 is an RFC 9457 problem with a stable `code`, which is what clients act
4
+ // on [E1]. A failed job carries the same shape in its job view, with a job failure code. 402
5
+ // responses use x402's own format, not this one.
6
+ //
7
+ // Problems never contain request headers, payment payloads or job tokens [E2]: `detail` and
8
+ // `errors[].message` are written by the provider, never copied from the request.
9
+ import { SPEC_URL } from "./standard.js";
10
+ export const PROBLEM_CONTENT_TYPE = "application/problem+json";
11
+ /** Codes for HTTP error responses, with their status and default title (§6). */
12
+ export const PROBLEMS = {
13
+ invalid_request: { status: 400, title: "The request is malformed" },
14
+ invalid_input: { status: 400, title: "Input does not match the service's inputSchema" },
15
+ service_not_found: { status: 404, title: "No service with that name" },
16
+ job_not_found: { status: 404, title: "Job not found" },
17
+ request_in_progress: { status: 409, title: "The job is still being claimed or settled", retryAfter: true },
18
+ payload_too_large: { status: 413, title: "The input is larger than maxInputBytes" },
19
+ idempotency_key_reused: { status: 422, title: "The job id is bound to a different request" },
20
+ rate_limited: { status: 429, title: "Too many requests", retryAfter: true },
21
+ unavailable: { status: 503, title: "The service is unavailable", retryAfter: true },
22
+ };
23
+ /** Codes for a failed job, in the job view's `error.code` (§6). */
24
+ export const JOB_FAILURES = {
25
+ service_failed: { title: "The work failed" },
26
+ output_invalid: { title: "The output did not match outputSchema" },
27
+ timeout: { title: "The work did not finish in time" },
28
+ payment_failed: { title: "Settlement did not happen" },
29
+ };
30
+ /** The problem `type` URI for a problem or job failure code. */
31
+ export function problemType(code) {
32
+ return `${SPEC_URL}#error-${code}`;
33
+ }
34
+ /** Builds the body of an HTTP error response. Send it as PROBLEM_CONTENT_TYPE with PROBLEMS[code].status. */
35
+ export function problem(code, options = {}) {
36
+ const { status, title } = PROBLEMS[code];
37
+ return { type: problemType(code), title, status, code, ...options };
38
+ }
39
+ /** Builds a failed job's `error`. */
40
+ export function jobError(code, detail) {
41
+ const error = { type: problemType(code), title: JOB_FAILURES[code].title, code };
42
+ if (detail !== undefined)
43
+ error.detail = detail;
44
+ return error;
45
+ }
46
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,EAAE;AACF,oGAAoG;AACpG,6FAA6F;AAC7F,iDAAiD;AACjD,EAAE;AACF,4FAA4F;AAC5F,iFAAiF;AAEjF,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,CAAC,MAAM,oBAAoB,GAAG,0BAA0B,CAAC;AAE/D,gFAAgF;AAChF,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,eAAe,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,0BAA0B,EAAE;IACnE,aAAa,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,gDAAgD,EAAE;IACvF,iBAAiB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,2BAA2B,EAAE;IACtE,aAAa,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,eAAe,EAAE;IACtD,mBAAmB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,2CAA2C,EAAE,UAAU,EAAE,IAAI,EAAE;IAC1G,iBAAiB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,wCAAwC,EAAE;IACnF,sBAAsB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,4CAA4C,EAAE;IAC5F,YAAY,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,IAAI,EAAE;IAC3E,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,4BAA4B,EAAE,UAAU,EAAE,IAAI,EAAE;CACI,CAAC;AAI1F,mEAAmE;AACnE,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,cAAc,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE;IAC5C,cAAc,EAAE,EAAE,KAAK,EAAE,uCAAuC,EAAE;IAClE,OAAO,EAAE,EAAE,KAAK,EAAE,iCAAiC,EAAE;IACrD,cAAc,EAAE,EAAE,KAAK,EAAE,2BAA2B,EAAE;CACF,CAAC;AAqBvD,gEAAgE;AAChE,MAAM,UAAU,WAAW,CAAC,IAAkC;IAC5D,OAAO,GAAG,QAAQ,UAAU,IAAI,EAAE,CAAC;AACrC,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,OAAO,CAAC,IAAiB,EAAE,UAAsD,EAAE;IACjG,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC;AACtE,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,QAAQ,CAAC,IAAoB,EAAE,MAAe;IAC5D,MAAM,KAAK,GAA4B,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IAC1G,IAAI,MAAM,KAAK,SAAS;QAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;IAChD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,15 @@
1
+ /** IETF Idempotency-Key (draft-07). Its value becomes the job id. */
2
+ export declare const IDEMPOTENCY_KEY = "Idempotency-Key";
3
+ /** The job's bearer secret. No "X-" prefix (RFC 6648). */
4
+ export declare const JOB_TOKEN = "Job-Token";
5
+ /** A lowercase RFC 9562 UUID of any version. Clients SHOULD use v4 or v7. */
6
+ export declare const IDEMPOTENCY_KEY_PATTERN: RegExp;
7
+ /** 32 random bytes, base64url without padding. The provider stores only its SHA-256 [J3]. */
8
+ export declare const JOB_TOKEN_PATTERN: RegExp;
9
+ /**
10
+ * Reads Retry-After (RFC 9110 §10.2.3) as whole seconds from `now`: delay-seconds, or an HTTP-date
11
+ * (0 once it has passed). Returns undefined for a missing or malformed value. Providers send
12
+ * delay-seconds (§5.8); the date form is read for HTTP proxies in front of them.
13
+ */
14
+ export declare function parseRetryAfter(value: string | null | undefined, now?: number): number | undefined;
15
+ //# sourceMappingURL=headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAKA,qEAAqE;AACrE,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,0DAA0D;AAC1D,eAAO,MAAM,SAAS,cAAc,CAAC;AAErC,6EAA6E;AAC7E,eAAO,MAAM,uBAAuB,QAAmE,CAAC;AAExG,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB,QAAwB,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,GAAG,SAAS,CAO9G"}
@@ -0,0 +1,29 @@
1
+ // HTTP header names used by the standard (docs/provider-standard.md §5.2), and reading Retry-After (§5.8).
2
+ //
3
+ // The x402 v2 headers (PAYMENT-REQUIRED, PAYMENT-SIGNATURE, PAYMENT-RESPONSE) come from @x402/core
4
+ // and are not redefined here. Location and Retry-After are used as HTTP defines them.
5
+ /** IETF Idempotency-Key (draft-07). Its value becomes the job id. */
6
+ export const IDEMPOTENCY_KEY = "Idempotency-Key";
7
+ /** The job's bearer secret. No "X-" prefix (RFC 6648). */
8
+ export const JOB_TOKEN = "Job-Token";
9
+ /** A lowercase RFC 9562 UUID of any version. Clients SHOULD use v4 or v7. */
10
+ export const IDEMPOTENCY_KEY_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
11
+ /** 32 random bytes, base64url without padding. The provider stores only its SHA-256 [J3]. */
12
+ export const JOB_TOKEN_PATTERN = /^[A-Za-z0-9_-]{43}$/;
13
+ /**
14
+ * Reads Retry-After (RFC 9110 §10.2.3) as whole seconds from `now`: delay-seconds, or an HTTP-date
15
+ * (0 once it has passed). Returns undefined for a missing or malformed value. Providers send
16
+ * delay-seconds (§5.8); the date form is read for HTTP proxies in front of them.
17
+ */
18
+ export function parseRetryAfter(value, now = Date.now()) {
19
+ if (value === null || value === undefined)
20
+ return undefined;
21
+ const trimmed = value.trim();
22
+ if (/^\d+$/.test(trimmed))
23
+ return Number(trimmed);
24
+ if (!/^[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} GMT$/.test(trimmed))
25
+ return undefined;
26
+ const date = Date.parse(trimmed);
27
+ return Number.isNaN(date) ? undefined : Math.max(0, Math.ceil((date - now) / 1000));
28
+ }
29
+ //# sourceMappingURL=headers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.js","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,EAAE;AACF,mGAAmG;AACnG,sFAAsF;AAEtF,qEAAqE;AACrE,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAEjD,0DAA0D;AAC1D,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC;AAErC,6EAA6E;AAC7E,MAAM,CAAC,MAAM,uBAAuB,GAAG,gEAAgE,CAAC;AAExG,6FAA6F;AAC7F,MAAM,CAAC,MAAM,iBAAiB,GAAG,qBAAqB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAgC,EAAE,MAAc,IAAI,CAAC,GAAG,EAAE;IACxF,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5D,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,CAAC,kEAAkE,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IACxG,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AACtF,CAAC"}
@@ -0,0 +1,11 @@
1
+ export * from "./standard.js";
2
+ export * from "./manifest.js";
3
+ export * from "./jobs.js";
4
+ export * from "./headers.js";
5
+ export * from "./receipts.js";
6
+ export * from "./validation-request.js";
7
+ export * from "./networks.js";
8
+ export * from "./canonical-json.js";
9
+ export * from "./errors.js";
10
+ export * from "./strkey.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ // @stellar-agent-services/protocol
2
+ //
3
+ // Provider Standard v1 as code. Every other package (provider-kit, payment-client, verifier) and,
4
+ // read-only, stellar-agent-search import their shared definitions from here.
5
+ //
6
+ // Rule: this package has NO runtime dependencies and never imports signing code, so the read-only
7
+ // discovery server can depend on it without breaking its "no signer imports" invariant.
8
+ export * from "./standard.js";
9
+ export * from "./manifest.js";
10
+ export * from "./jobs.js";
11
+ export * from "./headers.js";
12
+ export * from "./receipts.js";
13
+ export * from "./validation-request.js";
14
+ export * from "./networks.js";
15
+ export * from "./canonical-json.js";
16
+ export * from "./errors.js";
17
+ export * from "./strkey.js";
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,EAAE;AACF,kGAAkG;AAClG,6EAA6E;AAC7E,EAAE;AACF,kGAAkG;AAClG,wFAAwF;AAExF,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC"}
package/dist/jobs.d.ts ADDED
@@ -0,0 +1,62 @@
1
+ import { type JsonObject } from "./canonical-json.js";
2
+ import type { JobFailureCode, Problem } from "./errors.js";
3
+ import type { PaymentReceipt } from "./receipts.js";
4
+ /** When the user is charged (§3.2). The manifest default is "upfront". */
5
+ export type Charge = "on-success" | "upfront";
6
+ /** POST {baseUrl}/services/{name}/jobs (§5.1). */
7
+ export declare function createJobUrl(baseUrl: string, service: string): string;
8
+ /** GET {baseUrl}/jobs/{jobId} (§5.1). */
9
+ export declare function jobStatusUrl(baseUrl: string, jobId: string): string;
10
+ /** GET {baseUrl}/jobs/{jobId}/result (§5.1). */
11
+ export declare function jobResultUrl(baseUrl: string, jobId: string): string;
12
+ /** hex(sha256(JCS({ service, input }))): binds a job id to one request (§5.3). */
13
+ export declare function bindingHash(service: string, input: unknown): Promise<string>;
14
+ export type JobStatus = "queued" | "running" | "succeeded" | "failed" | "payment_uncertain";
15
+ export declare const JOB_STATUSES: readonly JobStatus[];
16
+ /** `succeeded` and `failed` never change again [J12]. */
17
+ export declare const FINAL_JOB_STATUSES: readonly JobStatus[];
18
+ /** Whether the user paid: "unknown" exactly while the job is payment_uncertain (§5.6). */
19
+ export type Charged = boolean | "unknown";
20
+ /** The one response body of create-job, check-status and get-result (§5.5). */
21
+ export interface JobView {
22
+ jobId: string;
23
+ service: string;
24
+ status: JobStatus;
25
+ charge: Charge;
26
+ charged: Charged;
27
+ /** RFC 3339 timestamps. */
28
+ createdAt: string;
29
+ updatedAt: string;
30
+ expiresAt: string;
31
+ /** create-job and get-result, when succeeded. Withheld while payment_uncertain [J14]. */
32
+ output?: JsonObject;
33
+ /** When failed. */
34
+ error?: Problem<JobFailureCode>;
35
+ /** When charged is true. */
36
+ payment?: PaymentReceipt;
37
+ /** While queued [Q5]. */
38
+ queue?: QueuePosition;
39
+ /** Only in the create-job response, and only when the provider created the token [J2]. */
40
+ jobToken?: string;
41
+ }
42
+ /** Where a queued job stands (§5.8). A hint, not a promise. */
43
+ export interface QueuePosition {
44
+ /** 1 for the next job to start. */
45
+ position: number;
46
+ /** RFC 3339. */
47
+ estimatedStartAt: string;
48
+ }
49
+ /** The states a job may start in: (new) → queued | running | payment_uncertain | failed (§5.6). */
50
+ export declare const INITIAL_JOB_STATUSES: readonly JobStatus[];
51
+ /** Allowed transitions between states (§5.6). Final states have none [J12]. */
52
+ export declare const JOB_TRANSITIONS: Readonly<Record<JobStatus, readonly JobStatus[]>>;
53
+ /**
54
+ * Whether a job may move from `from` (undefined for a new job) to `to`. running → payment_uncertain
55
+ * happens only with charge "on-success", where settlement follows the work (§5.6).
56
+ */
57
+ export declare function canTransition(from: JobStatus | undefined, to: JobStatus, charge: Charge): boolean;
58
+ /** The `charged` value the §5.6 table requires for a job's status, charge and failure code. */
59
+ export declare function chargedFor(status: JobStatus, charge: Charge, failureCode?: JobFailureCode): Charged;
60
+ /** 200 once the job has finished, otherwise 202 with Retry-After [J8]. */
61
+ export declare function jobViewHttpStatus(status: JobStatus): 200 | 202;
62
+ //# sourceMappingURL=jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,0EAA0E;AAC1E,MAAM,MAAM,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;AAE9C,kDAAkD;AAClD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGrE;AAED,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnE;AAED,gDAAgD;AAChD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAE5E;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,mBAAmB,CAAC;AAC5F,eAAO,MAAM,YAAY,EAAE,SAAS,SAAS,EAAsE,CAAC;AAEpH,yDAAyD;AACzD,eAAO,MAAM,kBAAkB,EAAE,SAAS,SAAS,EAA4B,CAAC;AAEhF,0FAA0F;AAC1F,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AAE1C,+EAA+E;AAC/E,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,yFAAyF;IACzF,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,mBAAmB;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAChC,4BAA4B;IAC5B,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,yBAAyB;IACzB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB;IAChB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,mGAAmG;AACnG,eAAO,MAAM,oBAAoB,EAAE,SAAS,SAAS,EAAyD,CAAC;AAE/G,+EAA+E;AAC/E,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC,CAM7E,CAAC;AAEF;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAIjG;AAED,+FAA+F;AAC/F,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,cAAc,GAAG,OAAO,CAWnG;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,GAAG,GAAG,GAAG,CAE9D"}
package/dist/jobs.js ADDED
@@ -0,0 +1,66 @@
1
+ // Job model: create-job, check-status, get-result (docs/provider-standard.md §5).
2
+ import { canonicalSha256 } from "./canonical-json.js";
3
+ import { IDEMPOTENCY_KEY_PATTERN } from "./headers.js";
4
+ import { SERVICE_NAME_PATTERN } from "./standard.js";
5
+ /** POST {baseUrl}/services/{name}/jobs (§5.1). */
6
+ export function createJobUrl(baseUrl, service) {
7
+ if (!SERVICE_NAME_PATTERN.test(service))
8
+ throw new TypeError(`invalid service name: ${service}`);
9
+ return `${baseUrl}/services/${service}/jobs`;
10
+ }
11
+ /** GET {baseUrl}/jobs/{jobId} (§5.1). */
12
+ export function jobStatusUrl(baseUrl, jobId) {
13
+ if (!IDEMPOTENCY_KEY_PATTERN.test(jobId))
14
+ throw new TypeError(`invalid job id: ${jobId}`);
15
+ return `${baseUrl}/jobs/${jobId}`;
16
+ }
17
+ /** GET {baseUrl}/jobs/{jobId}/result (§5.1). */
18
+ export function jobResultUrl(baseUrl, jobId) {
19
+ return `${jobStatusUrl(baseUrl, jobId)}/result`;
20
+ }
21
+ /** hex(sha256(JCS({ service, input }))): binds a job id to one request (§5.3). */
22
+ export function bindingHash(service, input) {
23
+ return canonicalSha256({ service, input });
24
+ }
25
+ export const JOB_STATUSES = ["queued", "running", "succeeded", "failed", "payment_uncertain"];
26
+ /** `succeeded` and `failed` never change again [J12]. */
27
+ export const FINAL_JOB_STATUSES = ["succeeded", "failed"];
28
+ /** The states a job may start in: (new) → queued | running | payment_uncertain | failed (§5.6). */
29
+ export const INITIAL_JOB_STATUSES = ["queued", "running", "payment_uncertain", "failed"];
30
+ /** Allowed transitions between states (§5.6). Final states have none [J12]. */
31
+ export const JOB_TRANSITIONS = {
32
+ queued: ["running"],
33
+ running: ["succeeded", "failed", "payment_uncertain"],
34
+ payment_uncertain: ["queued", "succeeded", "failed"],
35
+ succeeded: [],
36
+ failed: [],
37
+ };
38
+ /**
39
+ * Whether a job may move from `from` (undefined for a new job) to `to`. running → payment_uncertain
40
+ * happens only with charge "on-success", where settlement follows the work (§5.6).
41
+ */
42
+ export function canTransition(from, to, charge) {
43
+ if (from === undefined)
44
+ return INITIAL_JOB_STATUSES.includes(to);
45
+ if (from === "running" && to === "payment_uncertain" && charge !== "on-success")
46
+ return false;
47
+ return JOB_TRANSITIONS[from].includes(to);
48
+ }
49
+ /** The `charged` value the §5.6 table requires for a job's status, charge and failure code. */
50
+ export function chargedFor(status, charge, failureCode) {
51
+ switch (status) {
52
+ case "payment_uncertain":
53
+ return "unknown";
54
+ case "succeeded":
55
+ return true;
56
+ case "failed":
57
+ return charge === "upfront" && failureCode !== "payment_failed";
58
+ default:
59
+ return charge === "upfront";
60
+ }
61
+ }
62
+ /** 200 once the job has finished, otherwise 202 with Retry-After [J8]. */
63
+ export function jobViewHttpStatus(status) {
64
+ return FINAL_JOB_STATUSES.includes(status) ? 200 : 202;
65
+ }
66
+ //# sourceMappingURL=jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.js","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ import { type JsonObject, type JsonValue } from "./canonical-json.js";
2
+ import { type Charge } from "./jobs.js";
3
+ import type { StellarNetwork } from "./networks.js";
4
+ export interface ProviderManifest {
5
+ standard: "stellar-agent-services/provider@1";
6
+ provider: ProviderInfo;
7
+ baseUrl: string;
8
+ payment: PaymentInfo;
9
+ jobs?: {
10
+ retentionSeconds?: number;
11
+ };
12
+ services: ServiceDescriptor[];
13
+ extensions?: JsonObject;
14
+ }
15
+ export interface ProviderInfo {
16
+ name: string;
17
+ description?: string;
18
+ homepage?: string;
19
+ agentId?: number;
20
+ termsUrl?: string;
21
+ dataUse?: {
22
+ storesInputs?: boolean;
23
+ trainsOnInputs?: boolean;
24
+ };
25
+ }
26
+ export interface PaymentInfo {
27
+ protocol: "x402";
28
+ x402Version: 2;
29
+ /** Exactly one option in v1 [P1]. */
30
+ accepts: [PaymentOption];
31
+ }
32
+ /** x402 v2 PaymentRequirements field names, without `amount` (§4.1). */
33
+ export interface PaymentOption {
34
+ scheme: "exact";
35
+ network: StellarNetwork;
36
+ asset: string;
37
+ payTo: string;
38
+ maxTimeoutSeconds: number;
39
+ extra: {
40
+ areFeesSponsored: true;
41
+ [key: string]: JsonValue;
42
+ };
43
+ }
44
+ /** One service. Field names follow MCP tools, so a service maps 1:1 to an MCP tool (Appendix B). */
45
+ export interface ServiceDescriptor {
46
+ name: string;
47
+ title?: string;
48
+ description: string;
49
+ price: {
50
+ amount: string;
51
+ };
52
+ charge?: Charge;
53
+ expectedDurationSeconds?: number;
54
+ inputSchema: JsonObject;
55
+ outputSchema: JsonObject;
56
+ examples?: {
57
+ input: JsonObject;
58
+ output: JsonObject;
59
+ }[];
60
+ maxInputBytes?: number;
61
+ tags?: string[];
62
+ capacity?: ServiceCapacity;
63
+ extensions?: JsonObject;
64
+ }
65
+ /** How much load a service takes (§5.8). Hints only: the provider's 429, 503 and queue answers are what count. */
66
+ export interface ServiceCapacity {
67
+ /** Jobs the service runs at the same time. */
68
+ concurrency?: number;
69
+ /** Longest a new job may expect to wait in the queue; beyond it, create-job answers 503. 0: no queue. */
70
+ maxQueueWaitSeconds?: number;
71
+ }
72
+ /** A broken rule: its id in provider-standard.md and a JSON Pointer to the offending value. */
73
+ export interface RuleViolation {
74
+ rule: string;
75
+ pointer: string;
76
+ message: string;
77
+ }
78
+ export interface ManifestRuleOptions {
79
+ /** The URL the manifest was fetched from. */
80
+ manifestUrl: string;
81
+ /** Validates a value against a JSON Schema. Without it, examples are not checked [S9]. */
82
+ validateExample?: (schema: JsonObject, value: JsonValue) => boolean;
83
+ }
84
+ /**
85
+ * Checks the manifest rules that JSON Schema can't express: M1 (HTTPS manifest URL), M3 (I-JSON),
86
+ * M5 (same origin), M7 (unique service names), S6 (schema size), S9 (examples) and P11 (address
87
+ * checksum). Call it only on a manifest that passed the JSON Schema.
88
+ */
89
+ export declare function checkManifestRules(manifest: ProviderManifest, options: ManifestRuleOptions): RuleViolation[];
90
+ /**
91
+ * Checks a decoded x402 PAYMENT-REQUIRED challenge for one service against the manifest the user
92
+ * approved ([P3], [P4], [P5]). A client refuses to sign if this returns any violation [P7].
93
+ */
94
+ export declare function checkChallenge(manifest: ProviderManifest, serviceName: string, challenge: unknown): RuleViolation[];
95
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}