@envarai/envarpay 0.1.0-alpha.3 → 0.2.0-alpha.10

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 (72) hide show
  1. package/README.md +57 -145
  2. package/dist/commerce/alerts.d.ts +37 -0
  3. package/dist/commerce/alerts.js +127 -0
  4. package/dist/commerce/buyer-store.d.ts +101 -0
  5. package/dist/commerce/buyer-store.js +168 -0
  6. package/dist/commerce/buyer.d.ts +138 -0
  7. package/dist/commerce/buyer.js +775 -0
  8. package/dist/commerce/card.d.ts +5 -0
  9. package/dist/commerce/card.js +29 -0
  10. package/dist/commerce/chain.d.ts +24 -0
  11. package/dist/commerce/chain.js +146 -0
  12. package/dist/commerce/cli.d.ts +2 -0
  13. package/dist/commerce/cli.js +318 -0
  14. package/dist/commerce/client-runtime.d.ts +8 -0
  15. package/dist/commerce/client-runtime.js +7 -0
  16. package/dist/commerce/config.d.ts +11 -0
  17. package/dist/commerce/config.js +200 -0
  18. package/dist/commerce/envar-runtime.d.ts +47 -0
  19. package/dist/commerce/envar-runtime.js +276 -0
  20. package/dist/commerce/envar.d.ts +126 -0
  21. package/dist/commerce/envar.js +647 -0
  22. package/dist/commerce/http.d.ts +2 -0
  23. package/dist/commerce/http.js +34 -0
  24. package/dist/commerce/index.d.ts +5 -0
  25. package/dist/commerce/index.js +5 -0
  26. package/dist/commerce/management.d.ts +14 -0
  27. package/dist/commerce/management.js +140 -0
  28. package/dist/commerce/mpp-client.d.ts +70 -0
  29. package/dist/commerce/mpp-client.js +29 -0
  30. package/dist/commerce/mpp-runtime.d.ts +4 -0
  31. package/dist/commerce/mpp-runtime.js +4 -0
  32. package/dist/commerce/mpp.d.ts +53 -0
  33. package/dist/commerce/mpp.js +163 -0
  34. package/dist/commerce/native-skills.d.ts +27 -0
  35. package/dist/commerce/native-skills.js +176 -0
  36. package/dist/commerce/operations.d.ts +22 -0
  37. package/dist/commerce/operations.js +39 -0
  38. package/dist/commerce/peer-proxy.d.ts +44 -0
  39. package/dist/commerce/peer-proxy.js +673 -0
  40. package/dist/commerce/pricing.d.ts +12 -0
  41. package/dist/commerce/pricing.js +60 -0
  42. package/dist/commerce/runtime.d.ts +10 -0
  43. package/dist/commerce/runtime.js +10 -0
  44. package/dist/commerce/server.d.ts +61 -0
  45. package/dist/commerce/server.js +516 -0
  46. package/dist/commerce/setup.d.ts +18 -0
  47. package/dist/commerce/setup.js +344 -0
  48. package/dist/commerce/skill-gate.d.ts +54 -0
  49. package/dist/commerce/skill-gate.js +153 -0
  50. package/dist/commerce/store.d.ts +88 -0
  51. package/dist/commerce/store.js +473 -0
  52. package/dist/commerce/stripe-issuer.d.ts +41 -0
  53. package/dist/commerce/stripe-issuer.js +351 -0
  54. package/dist/commerce/stripe-provider.d.ts +11 -0
  55. package/dist/commerce/stripe-provider.js +132 -0
  56. package/dist/commerce/types.d.ts +138 -0
  57. package/dist/commerce/types.js +8 -0
  58. package/dist/commerce/upstream.d.ts +6 -0
  59. package/dist/commerce/upstream.js +103 -0
  60. package/dist/commerce/vault.d.ts +8 -0
  61. package/dist/commerce/vault.js +55 -0
  62. package/dist/commerce/x402.d.ts +38 -0
  63. package/dist/commerce/x402.js +181 -0
  64. package/examples/buyer-policy.json +18 -0
  65. package/examples/envar-integration-policy.json +18 -0
  66. package/examples/hermes-setup-probe.py +105 -0
  67. package/examples/native-skill-runner.py +197 -0
  68. package/examples/seller.json +52 -0
  69. package/package.json +75 -10
  70. package/schemas/buyer-policy.schema.json +253 -0
  71. package/schemas/envarpay.config.schema.json +383 -0
  72. package/schemas/quote.schema.json +91 -0
@@ -0,0 +1,60 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { Ajv2020 } from 'ajv/dist/2020.js';
3
+ import addFormatsImport from 'ajv-formats';
4
+ import { atomic, currencyOf, digest, serviceTermsDigest } from './config.js';
5
+ import { CommerceError } from './types.js';
6
+ const addFormats = addFormatsImport;
7
+ export function buildQuote(config, args) {
8
+ if (!args.caller || !args.messageId || args.messageId.length > 128)
9
+ throw new CommerceError('invalid_identity', 'Authenticated caller and stable message ID are required');
10
+ const service = config.services.find(s => s.id === args.serviceId);
11
+ const offer = service?.offers.find(o => o.id === args.offerId);
12
+ if (!service || !offer)
13
+ throw new CommerceError('offer_not_found', 'Service offer not found');
14
+ const ajv = new Ajv2020({ strict: true });
15
+ addFormats(ajv);
16
+ const validate = ajv.compile(service.contract.inputSchema);
17
+ if (!validate(args.input))
18
+ throw new CommerceError('invalid_input', ajv.errorsText(validate.errors));
19
+ let amount = 0n;
20
+ if (offer.pricing.kind === 'fixed')
21
+ amount = atomic(offer.pricing.amount);
22
+ if (offer.pricing.kind === 'quantity') {
23
+ let current = args.input;
24
+ for (const part of offer.pricing.quantity.pointer.slice(1).split('/')) {
25
+ const key = part.replace(/~1/g, '/').replace(/~0/g, '~');
26
+ current = current && typeof current === 'object' && Object.hasOwn(current, key) ? current[key] : undefined;
27
+ }
28
+ const q = offer.pricing.quantity;
29
+ if (!Array.isArray(current) || current.length < q.min || current.length > q.max)
30
+ throw new CommerceError('invalid_quantity', 'Input quantity outside the purchased range');
31
+ amount = atomic(offer.pricing.unitAmount) * BigInt(current.length);
32
+ }
33
+ if (amount >= 2n ** 256n)
34
+ throw new CommerceError('invalid_amount', 'Quoted amount is too large');
35
+ const profile = offer.paymentProfile ? config.paymentProfiles[offer.paymentProfile] : null;
36
+ const recipient = profile?.adapter === 'x402' ? profile.payTo : profile ? args.stripeRecipient : null;
37
+ if (profile?.adapter === 'mpp' && !recipient)
38
+ throw new CommerceError('merchant_not_ready', 'Resolve and verify the Stripe merchant before quoting');
39
+ const now = args.now ?? new Date();
40
+ const ttl = args.ttlSeconds ?? 600;
41
+ if (!Number.isInteger(ttl) || ttl < 1 || ttl > 3600 || !Number.isFinite(now.getTime()))
42
+ throw new CommerceError('invalid_expiry', 'Quote lifetime must be 1–3600 seconds');
43
+ const quote = {
44
+ quoteVersion: 1, quoteId: randomUUID(), caller: args.caller, serviceId: service.id,
45
+ serviceRevision: service.revision, offerId: offer.id, messageId: args.messageId,
46
+ inputDigest: digest(args.input), termsDigest: serviceTermsDigest(config.configVersion, service, offer, profile),
47
+ issuedAt: now.toISOString(), expiresAt: new Date(now.getTime() + ttl * 1000).toISOString(),
48
+ amount: amount.toString(), currency: profile ? currencyOf(profile) : null,
49
+ recipient: recipient ?? null, paymentProfile: profile ? structuredClone(profile) : null,
50
+ };
51
+ if (quote.paymentProfile)
52
+ Object.freeze(quote.paymentProfile);
53
+ return Object.freeze(quote);
54
+ }
55
+ export function assertQuoteRequest(quote, caller, messageId, input, now = new Date()) {
56
+ if (quote.caller !== caller || quote.messageId !== messageId || quote.inputDigest !== digest(input))
57
+ throw new CommerceError('quote_mismatch', 'Request differs from the frozen quote');
58
+ if (!Number.isFinite(now.getTime()) || !Number.isFinite(Date.parse(quote.expiresAt)) || now.getTime() >= Date.parse(quote.expiresAt))
59
+ throw new CommerceError('quote_expired', 'Review a new quote before payment');
60
+ }
@@ -0,0 +1,10 @@
1
+ /** Node.js service APIs. Keep node:sqlite out of the portable contracts entry. */
2
+ export * from './store.js';
3
+ export * from './server.js';
4
+ export * from './upstream.js';
5
+ export * from './skill-gate.js';
6
+ export * from './native-skills.js';
7
+ export * from './http.js';
8
+ export * from './x402.js';
9
+ export * from './vault.js';
10
+ export * from './chain.js';
@@ -0,0 +1,10 @@
1
+ /** Node.js service APIs. Keep node:sqlite out of the portable contracts entry. */
2
+ export * from './store.js';
3
+ export * from './server.js';
4
+ export * from './upstream.js';
5
+ export * from './skill-gate.js';
6
+ export * from './native-skills.js';
7
+ export * from './http.js';
8
+ export * from './x402.js';
9
+ export * from './vault.js';
10
+ export * from './chain.js';
@@ -0,0 +1,61 @@
1
+ import { AgentCard, Task, SendMessageRequest } from '@a2a-js/sdk';
2
+ import { ServerCallContext } from '@a2a-js/sdk/server';
3
+ import { CommerceStore, type OrderRecord, type ContinuationRecord, type RemoteTaskReference } from './store.js';
4
+ import { type CommerceConfig, type Input, type Service } from './types.js';
5
+ export interface ExecuteOrder {
6
+ (order: OrderRecord, service: Service): AsyncIterable<Task>;
7
+ assertSkill?: (service: Service) => unknown;
8
+ skillCard?: () => AgentCard;
9
+ continue?: (order: OrderRecord, service: Service, continuation: ContinuationRecord, remote: RemoteTaskReference) => AsyncIterable<Task>;
10
+ recover?: (order: OrderRecord, service: Service, remote: RemoteTaskReference) => Promise<Task>;
11
+ remoteInterface?: (task: Task) => string | undefined;
12
+ }
13
+ export interface CommerceServerOptions {
14
+ config: CommerceConfig;
15
+ origin: string;
16
+ store: CommerceStore;
17
+ authenticate: (request: Request) => Promise<string | null>;
18
+ execute: ExecuteOrder;
19
+ paymentGate?: {
20
+ handle(request: Request, order: OrderRecord): Promise<{
21
+ response: Response;
22
+ } | {
23
+ headers: Record<string, string>;
24
+ }>;
25
+ };
26
+ stripeRecipientFor?: (accountRef: string) => string | undefined;
27
+ ownershipChallenges?: Readonly<Record<string, string>>;
28
+ onError?: (code: string, orderId?: string) => void;
29
+ }
30
+ export declare function bearerAuthenticator(tokens: Readonly<Record<string, string>>): (request: Request) => Promise<string | null>;
31
+ /** HTTP handler + one durable worker. Recovery only reads the original upstream Task. */
32
+ export declare class CommerceServer {
33
+ private options;
34
+ private currentConfig;
35
+ get config(): CommerceConfig;
36
+ readonly store: CommerceStore;
37
+ private routes;
38
+ private running;
39
+ private kickPending;
40
+ private stopped;
41
+ private workerFailed;
42
+ private waiters;
43
+ private activeOrders;
44
+ private recoveries;
45
+ constructor(options: CommerceServerOptions);
46
+ /** Atomically replace active routes while retaining immutable history and original Tasks. */
47
+ applyConfig(value: CommerceConfig): void;
48
+ private activeRevision;
49
+ private context;
50
+ quote(service: Service, offerId: string, caller: string, messageId: string, input: Input): Readonly<import("./types.js").PriceQuote>;
51
+ handle(request: Request): Promise<Response>;
52
+ continueTask(params: SendMessageRequest, input: Input, service: Service, offerId: string, context: ServerCallContext): Promise<Task>;
53
+ recoverTask(taskId: string, context: ServerCallContext): Promise<Task>;
54
+ private project;
55
+ schedule(): void;
56
+ private drain;
57
+ waitForTask(taskId: string, context: ServerCallContext): Promise<Task>;
58
+ private wake;
59
+ stop(): void;
60
+ get isRunning(): boolean;
61
+ }