tru-402 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.
Files changed (45) hide show
  1. package/dist/bin/trux.d.ts +3 -0
  2. package/dist/bin/trux.d.ts.map +1 -0
  3. package/dist/bin/trux.js +39 -0
  4. package/dist/bin/trux.js.map +1 -0
  5. package/dist/src/challenge.d.ts +18 -0
  6. package/dist/src/challenge.d.ts.map +1 -0
  7. package/dist/src/challenge.js +86 -0
  8. package/dist/src/challenge.js.map +1 -0
  9. package/dist/src/identity.d.ts +51 -0
  10. package/dist/src/identity.d.ts.map +1 -0
  11. package/dist/src/identity.js +2 -0
  12. package/dist/src/identity.js.map +1 -0
  13. package/dist/src/index.d.ts +6 -0
  14. package/dist/src/index.d.ts.map +1 -0
  15. package/dist/src/index.js +5 -0
  16. package/dist/src/index.js.map +1 -0
  17. package/dist/src/init/discovery.d.ts +10 -0
  18. package/dist/src/init/discovery.d.ts.map +1 -0
  19. package/dist/src/init/discovery.js +77 -0
  20. package/dist/src/init/discovery.js.map +1 -0
  21. package/dist/src/init/env.d.ts +10 -0
  22. package/dist/src/init/env.d.ts.map +1 -0
  23. package/dist/src/init/env.js +64 -0
  24. package/dist/src/init/env.js.map +1 -0
  25. package/dist/src/init/index.d.ts +5 -0
  26. package/dist/src/init/index.d.ts.map +1 -0
  27. package/dist/src/init/index.js +163 -0
  28. package/dist/src/init/index.js.map +1 -0
  29. package/dist/src/init/scan.d.ts +21 -0
  30. package/dist/src/init/scan.d.ts.map +1 -0
  31. package/dist/src/init/scan.js +128 -0
  32. package/dist/src/init/scan.js.map +1 -0
  33. package/dist/src/middleware.d.ts +12 -0
  34. package/dist/src/middleware.d.ts.map +1 -0
  35. package/dist/src/middleware.js +117 -0
  36. package/dist/src/middleware.js.map +1 -0
  37. package/dist/src/session.d.ts +20 -0
  38. package/dist/src/session.d.ts.map +1 -0
  39. package/dist/src/session.js +57 -0
  40. package/dist/src/session.js.map +1 -0
  41. package/dist/src/verify.d.ts +12 -0
  42. package/dist/src/verify.d.ts.map +1 -0
  43. package/dist/src/verify.js +38 -0
  44. package/dist/src/verify.js.map +1 -0
  45. package/package.json +47 -0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=trux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trux.d.ts","sourceRoot":"","sources":["../../bin/trux.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import { runInit } from '../src/init/index.js';
3
+ const args = process.argv.slice(2);
4
+ const command = args[0];
5
+ if (!command || command === 'init') {
6
+ runInit().catch((err) => {
7
+ console.error('Error:', err.message);
8
+ process.exit(1);
9
+ });
10
+ }
11
+ else if (command === '--help' || command === '-h') {
12
+ console.log(`
13
+ tru-402 — One-line middleware for agent commerce
14
+
15
+ Usage:
16
+ npx tru-402 init Set up tru-402 in your project (register app, connect Stripe, write .env)
17
+
18
+ Options:
19
+ --help, -h Show this help message
20
+ --version, -v Show version
21
+
22
+ Learn more: https://tru.so/docs
23
+ `);
24
+ }
25
+ else if (command === '--version' || command === '-v') {
26
+ // Read version from package.json at runtime
27
+ const { readFileSync } = await import('fs');
28
+ const { resolve, dirname } = await import('path');
29
+ const { fileURLToPath } = await import('url');
30
+ const __dirname = dirname(fileURLToPath(import.meta.url));
31
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, '../../package.json'), 'utf-8'));
32
+ console.log(pkg.version);
33
+ }
34
+ else {
35
+ console.error(`Unknown command: ${command}`);
36
+ console.error('Run `npx tru-402 --help` for usage.');
37
+ process.exit(1);
38
+ }
39
+ //# sourceMappingURL=trux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trux.js","sourceRoot":"","sources":["../../bin/trux.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAExB,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;IACnC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACtB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;CAWb,CAAC,CAAC;AACH,CAAC;KAAM,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;IACvD,4CAA4C;IAC5C,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACxF,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { TruxOptions, TruxConfig } from './identity.js';
2
+ export interface ChallengeParams {
3
+ options: TruxOptions;
4
+ config: TruxConfig;
5
+ requestUrl: string;
6
+ }
7
+ export interface ChallengeResponse {
8
+ /** WWW-Authenticate header value */
9
+ header: string;
10
+ /** JSON body for the 402 response */
11
+ body: Record<string, unknown>;
12
+ }
13
+ /**
14
+ * Generate a 402 Payment Required challenge.
15
+ * Produces both the WWW-Authenticate header and self-documenting JSON body.
16
+ */
17
+ export declare function generateChallenge(params: ChallengeParams): ChallengeResponse;
18
+ //# sourceMappingURL=challenge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"challenge.d.ts","sourceRoot":"","sources":["../../src/challenge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAa7D,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,iBAAiB,CA+E5E"}
@@ -0,0 +1,86 @@
1
+ import crypto from 'crypto';
2
+ /**
3
+ * Encode a JSON object to base64url (MPP-compatible request encoding).
4
+ */
5
+ function toBase64Url(obj) {
6
+ return Buffer.from(JSON.stringify(obj))
7
+ .toString('base64')
8
+ .replace(/\+/g, '-')
9
+ .replace(/\//g, '_')
10
+ .replace(/=+$/, '');
11
+ }
12
+ /**
13
+ * Generate a 402 Payment Required challenge.
14
+ * Produces both the WWW-Authenticate header and self-documenting JSON body.
15
+ */
16
+ export function generateChallenge(params) {
17
+ const { options, config, requestUrl } = params;
18
+ const challengeId = crypto.randomUUID();
19
+ const amountDollars = options.amount;
20
+ const currency = options.currency || 'usd';
21
+ const expires = new Date(Date.now() + 5 * 60 * 1000).toISOString(); // 5 min
22
+ // MPP-compatible request encoding
23
+ const request = toBase64Url({
24
+ amount: String(amountDollars),
25
+ currency,
26
+ url: requestUrl,
27
+ });
28
+ const realm = config.serviceName || config.appId;
29
+ // WWW-Authenticate header
30
+ const header = `Payment id="${challengeId}", realm="${realm}", method="tru", intent="charge", request="${request}", expires="${expires}"`;
31
+ // Self-documenting body
32
+ const body = {
33
+ error: 'payment_required',
34
+ message: `This API costs $${amountDollars.toFixed(2)} per request. No account or API key needed — pay and get the response.`,
35
+ amount: amountDollars,
36
+ currency,
37
+ description: options.description || undefined,
38
+ how_to_pay: {
39
+ step_1: `POST ${config.apiUrl}/api/mpp/resolve-challenge`,
40
+ step_1_body: {
41
+ challenge: {
42
+ id: challengeId,
43
+ realm,
44
+ method: 'tru',
45
+ intent: 'charge',
46
+ request,
47
+ expires,
48
+ },
49
+ email: '<your_email>',
50
+ },
51
+ step_1_note: "If you don't have a tru account, open the auth_url below in the user's browser first.",
52
+ step_2: 'The response includes an authorization_header value',
53
+ step_3: 'Retry this same request with that Authorization header',
54
+ },
55
+ auth_url: `${config.apiUrl}/connect`,
56
+ auth_url_note: 'First-time users: open this URL to link a payment method via Stripe Link (10 seconds)',
57
+ challenge: {
58
+ id: challengeId,
59
+ realm,
60
+ method: 'tru',
61
+ intent: 'charge',
62
+ request,
63
+ expires,
64
+ },
65
+ };
66
+ // Include session info for micropayments
67
+ if (amountDollars < 0.50) {
68
+ const sessionBudget = options.sessionBudget || 5.00;
69
+ body.session_available = {
70
+ message: `For repeated requests, the first payment creates a $${sessionBudget.toFixed(2)} session. Subsequent requests use X-Tru-Session header — no re-auth needed.`,
71
+ budget: sessionBudget,
72
+ duration_minutes: 60,
73
+ };
74
+ }
75
+ // Include plan upsell if configured
76
+ if (options.plan) {
77
+ body.plan_available = {
78
+ name: options.plan.name,
79
+ price: options.plan.price,
80
+ interval: options.plan.interval,
81
+ message: `The ${options.plan.name} plan ($${options.plan.price}/${options.plan.interval}) gives unlimited access.`,
82
+ };
83
+ }
84
+ return { header, body };
85
+ }
86
+ //# sourceMappingURL=challenge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"challenge.js","sourceRoot":"","sources":["../../src/challenge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * TruIdentity — populated on req.tru for every paid or authenticated request.
3
+ */
4
+ export interface TruIdentity {
5
+ email: string;
6
+ name: string;
7
+ userId: string;
8
+ cardBrand: string;
9
+ cardLast4: string;
10
+ agentName: string;
11
+ chargeId: string;
12
+ sessionId?: string;
13
+ }
14
+ /**
15
+ * Plan configuration for subscription upsell.
16
+ */
17
+ export interface TruxPlan {
18
+ name: string;
19
+ price: number;
20
+ interval: 'month' | 'year';
21
+ suggestAfter?: number;
22
+ }
23
+ /**
24
+ * Options passed to the trux() middleware factory.
25
+ */
26
+ export interface TruxOptions {
27
+ amount: number;
28
+ currency?: string;
29
+ description?: string;
30
+ plan?: TruxPlan;
31
+ sessionBudget?: number;
32
+ passthrough?: (req: any) => boolean;
33
+ }
34
+ /**
35
+ * Internal config resolved from env vars.
36
+ */
37
+ export interface TruxConfig {
38
+ appId: string;
39
+ apiKey: string;
40
+ apiUrl: string;
41
+ appSecret?: string;
42
+ serviceName?: string;
43
+ }
44
+ declare global {
45
+ namespace Express {
46
+ interface Request {
47
+ tru?: TruIdentity;
48
+ }
49
+ }
50
+ }
51
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,GAAG,CAAC,EAAE,WAAW,CAAC;SACnB;KACF;CACF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ export { createMiddleware as trux } from './middleware.js';
2
+ export type { TruIdentity, TruxOptions, TruxPlan, TruxConfig } from './identity.js';
3
+ export { generateChallenge } from './challenge.js';
4
+ export { verifyCredential } from './verify.js';
5
+ export { debitSession, createSession } from './session.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,IAAI,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { createMiddleware as trux } from './middleware.js';
2
+ export { generateChallenge } from './challenge.js';
3
+ export { verifyCredential } from './verify.js';
4
+ export { debitSession, createSession } from './session.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,IAAI,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ProjectInfo } from './scan.js';
2
+ /**
3
+ * Generate an agent.md file from discovered routes.
4
+ */
5
+ export declare function generateAgentMd(project: ProjectInfo, serviceName: string, apiUrl: string): string;
6
+ /**
7
+ * Generate an llms.txt file for LLM discovery.
8
+ */
9
+ export declare function generateLlmsTxt(project: ProjectInfo, serviceName: string, apiUrl: string): string;
10
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/init/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EACpB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb,MAAM,CA6CR;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EACpB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb,MAAM,CAkCR"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Generate an agent.md file from discovered routes.
3
+ */
4
+ export function generateAgentMd(project, serviceName, apiUrl) {
5
+ const lines = [];
6
+ lines.push(`# ${project.displayName || project.name}`);
7
+ lines.push('');
8
+ if (project.description) {
9
+ lines.push(`> ${project.description}`);
10
+ lines.push('');
11
+ }
12
+ lines.push('## Authentication');
13
+ lines.push('');
14
+ lines.push('This API uses [tru](https://tru.so) for payment-based authentication.');
15
+ lines.push('No API key or account needed. Unauthenticated requests return HTTP 402 with payment instructions.');
16
+ lines.push('');
17
+ lines.push('### How to pay');
18
+ lines.push('');
19
+ lines.push('1. Make a request to any endpoint below');
20
+ lines.push('2. If you get a 402, read the JSON body — it contains `how_to_pay` instructions');
21
+ lines.push(`3. POST the challenge to \`${apiUrl}/api/mpp/resolve-challenge\` with your email`);
22
+ lines.push('4. Use the returned `authorization_header` to retry your request');
23
+ lines.push('');
24
+ lines.push('First-time users: the 402 response includes an `auth_url` to link a payment method (10 seconds via Stripe Link).');
25
+ lines.push('');
26
+ if (project.routes.length > 0) {
27
+ lines.push('## Endpoints');
28
+ lines.push('');
29
+ for (const route of project.routes) {
30
+ lines.push(`### ${route.method} ${route.path}`);
31
+ if (route.description) {
32
+ lines.push(`${route.description}`);
33
+ }
34
+ lines.push(`- **Cost:** $${route.amount.toFixed(2)} per request`);
35
+ lines.push('');
36
+ }
37
+ }
38
+ lines.push('## Pricing');
39
+ lines.push('');
40
+ lines.push('All endpoints use per-request pricing. Amounts under $0.50 are batched into sessions (one charge per session, not per request).');
41
+ lines.push('');
42
+ return lines.join('\n');
43
+ }
44
+ /**
45
+ * Generate an llms.txt file for LLM discovery.
46
+ */
47
+ export function generateLlmsTxt(project, serviceName, apiUrl) {
48
+ const lines = [];
49
+ lines.push(`# ${project.displayName || project.name}`);
50
+ lines.push('');
51
+ if (project.description) {
52
+ lines.push(`> ${project.description}`);
53
+ lines.push('');
54
+ }
55
+ lines.push('## Docs');
56
+ lines.push('');
57
+ lines.push(`- [Agent Guide](./agent.md): How to authenticate and use this API`);
58
+ lines.push(`- [tru Platform](${apiUrl}): Payment and identity provider`);
59
+ lines.push('');
60
+ if (project.routes.length > 0) {
61
+ lines.push('## API Endpoints');
62
+ lines.push('');
63
+ for (const route of project.routes) {
64
+ const desc = route.description || route.path;
65
+ lines.push(`- ${route.method} ${route.path}: ${desc} ($${route.amount.toFixed(2)}/request)`);
66
+ }
67
+ lines.push('');
68
+ }
69
+ lines.push('## Payment');
70
+ lines.push('');
71
+ lines.push('All endpoints return HTTP 402 for unauthenticated requests.');
72
+ lines.push('The 402 response body contains self-documenting payment instructions.');
73
+ lines.push(`No API key or tru account needed — resolve the payment challenge at ${apiUrl}/api/mpp/resolve-challenge.`);
74
+ lines.push('');
75
+ return lines.join('\n');
76
+ }
77
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/init/discovery.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAoB,EACpB,WAAmB,EACnB,MAAc;IAEd,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAChC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;IACpF,KAAK,CAAC,IAAI,CAAC,mGAAmG,CAAC,CAAC;IAChH,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACtD,KAAK,CAAC,IAAI,CAAC,iFAAiF,CAAC,CAAC;IAC9F,KAAK,CAAC,IAAI,CAAC,8BAA8B,MAAM,8CAA8C,CAAC,CAAC;IAC/F,KAAK,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;IAC/E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kHAAkH,CAAC,CAAC;IAC/H,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEf,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAChD,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;gBACtB,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;YACrC,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,gBAAgB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;YAClE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,iIAAiI,CAAC,CAAC;IAC9I,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAoB,EACpB,WAAmB,EACnB,MAAc;IAEd,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;IAChF,KAAK,CAAC,IAAI,CAAC,oBAAoB,MAAM,kCAAkC,CAAC,CAAC;IACzE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,IAAI,CAAC;YAC7C,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,MAAM,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QAC/F,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;IAC1E,KAAK,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;IACpF,KAAK,CAAC,IAAI,CAAC,uEAAuE,MAAM,6BAA6B,CAAC,CAAC;IACvH,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Read existing .env file into a key-value map.
3
+ */
4
+ export declare function readEnvFile(cwd: string): Record<string, string>;
5
+ /**
6
+ * Write/merge values into .env file.
7
+ * Preserves existing values and comments.
8
+ */
9
+ export declare function writeEnvFile(cwd: string, values: Record<string, string>): void;
10
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/init/env.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAyB/D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QA4BvE"}
@@ -0,0 +1,64 @@
1
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
2
+ import { resolve } from 'path';
3
+ /**
4
+ * Read existing .env file into a key-value map.
5
+ */
6
+ export function readEnvFile(cwd) {
7
+ const envPath = resolve(cwd, '.env');
8
+ const result = {};
9
+ if (!existsSync(envPath))
10
+ return result;
11
+ try {
12
+ const content = readFileSync(envPath, 'utf-8');
13
+ for (const line of content.split('\n')) {
14
+ const trimmed = line.trim();
15
+ if (!trimmed || trimmed.startsWith('#'))
16
+ continue;
17
+ const eqIdx = trimmed.indexOf('=');
18
+ if (eqIdx === -1)
19
+ continue;
20
+ const key = trimmed.slice(0, eqIdx).trim();
21
+ let value = trimmed.slice(eqIdx + 1).trim();
22
+ // Remove surrounding quotes
23
+ if ((value.startsWith('"') && value.endsWith('"')) ||
24
+ (value.startsWith("'") && value.endsWith("'"))) {
25
+ value = value.slice(1, -1);
26
+ }
27
+ result[key] = value;
28
+ }
29
+ }
30
+ catch { /* ignore */ }
31
+ return result;
32
+ }
33
+ /**
34
+ * Write/merge values into .env file.
35
+ * Preserves existing values and comments.
36
+ */
37
+ export function writeEnvFile(cwd, values) {
38
+ const envPath = resolve(cwd, '.env');
39
+ let content = '';
40
+ if (existsSync(envPath)) {
41
+ content = readFileSync(envPath, 'utf-8');
42
+ }
43
+ // Add a trux section header if we're adding new keys
44
+ const existingKeys = new Set(Object.keys(readEnvFile(cwd)));
45
+ const newKeys = Object.keys(values).filter(k => !existingKeys.has(k));
46
+ if (newKeys.length > 0) {
47
+ if (content && !content.endsWith('\n'))
48
+ content += '\n';
49
+ if (content)
50
+ content += '\n# trux\n';
51
+ }
52
+ for (const [key, value] of Object.entries(values)) {
53
+ if (existingKeys.has(key)) {
54
+ // Update existing key
55
+ const regex = new RegExp(`^${key}\\s*=.*$`, 'm');
56
+ content = content.replace(regex, `${key}=${value}`);
57
+ }
58
+ else {
59
+ content += `${key}=${value}\n`;
60
+ }
61
+ }
62
+ writeFileSync(envPath, content);
63
+ }
64
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../../src/init/env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Main init orchestrator for `npx tru-402 init`.
3
+ */
4
+ export declare function runInit(): Promise<void>;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/init/index.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,wBAAsB,OAAO,kBAwJ5B"}
@@ -0,0 +1,163 @@
1
+ import { scanProject } from './scan.js';
2
+ import { writeEnvFile, readEnvFile } from './env.js';
3
+ import { generateAgentMd, generateLlmsTxt } from './discovery.js';
4
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
5
+ import { resolve } from 'path';
6
+ const TRU_API_URL = process.env.TRU_API_URL || 'https://tru.so';
7
+ /**
8
+ * Main init orchestrator for `npx tru-402 init`.
9
+ */
10
+ export async function runInit() {
11
+ console.log('\n tru-402 — One-line middleware for agent commerce\n');
12
+ // 1. Scan project
13
+ console.log(' Scanning project...');
14
+ const project = scanProject(process.cwd());
15
+ console.log(` Found: ${project.name} (${project.framework})`);
16
+ if (project.routes.length > 0) {
17
+ console.log(` Detected ${project.routes.length} route(s) with trux() middleware`);
18
+ }
19
+ // 2. Check if already initialized
20
+ const existingEnv = readEnvFile(process.cwd());
21
+ if (existingEnv.TRU_APP_ID && existingEnv.TRU_API_KEY) {
22
+ console.log('\n Already initialized! Found TRU_APP_ID and TRU_API_KEY in .env');
23
+ console.log(' To re-initialize, remove those values from .env first.\n');
24
+ return;
25
+ }
26
+ // 3. Register app via browser flow
27
+ console.log('\n Step 1: Register your app with tru');
28
+ console.log(' Opening browser for authentication...\n');
29
+ let registerResult;
30
+ try {
31
+ // Dynamic import of tru-cli auth module
32
+ const { registerViaBrowser } = await import('tru-cli/auth');
33
+ const serviceName = project.name
34
+ .toLowerCase()
35
+ .replace(/[^a-z0-9-]/g, '-')
36
+ .replace(/-+/g, '-')
37
+ .replace(/^-|-$/g, '');
38
+ registerResult = await registerViaBrowser({
39
+ service_name: serviceName,
40
+ display_name: project.displayName || project.name,
41
+ description: project.description || `${project.name} API`,
42
+ });
43
+ console.log(` App registered: ${registerResult.app.display_name} (${registerResult.app.service_name})`);
44
+ }
45
+ catch (err) {
46
+ if (err.code === 'MODULE_NOT_FOUND') {
47
+ console.log(' tru-cli not found. Installing...');
48
+ const { execSync } = await import('child_process');
49
+ execSync('npm install -g tru-cli', { stdio: 'inherit' });
50
+ console.log('\n Please run `npx tru-402 init` again.');
51
+ return;
52
+ }
53
+ throw err;
54
+ }
55
+ // 4. Connect Stripe
56
+ console.log('\n Step 2: Connect your Stripe account');
57
+ console.log(' Opening Stripe Connect...\n');
58
+ try {
59
+ const { getConnectOAuthUrl } = await import('tru-cli/api-client');
60
+ const connectResult = await getConnectOAuthUrl(registerResult.app.service_name);
61
+ if (connectResult.url) {
62
+ const { exec } = await import('child_process');
63
+ const platform = process.platform;
64
+ const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'start' : 'xdg-open';
65
+ exec(`${cmd} "${connectResult.url}"`);
66
+ console.log(' Stripe Connect OAuth opened in browser.');
67
+ console.log(` If it didn't open: ${connectResult.url}`);
68
+ console.log('\n Complete the Stripe connection, then come back here.');
69
+ // Poll for connection (check every 3s for up to 5 min)
70
+ const { lookupAppByServiceName } = await import('tru-cli/api-client');
71
+ let connected = false;
72
+ for (let i = 0; i < 100; i++) {
73
+ await new Promise(r => setTimeout(r, 3000));
74
+ try {
75
+ const app = await lookupAppByServiceName(registerResult.app.service_name);
76
+ if (app.app?.stripe_connected) {
77
+ connected = true;
78
+ console.log(' Stripe connected!');
79
+ break;
80
+ }
81
+ }
82
+ catch { /* keep polling */ }
83
+ }
84
+ if (!connected) {
85
+ console.log('\n Stripe connection timed out. You can connect later via the tru dashboard.');
86
+ }
87
+ }
88
+ else if (connectResult.already_connected) {
89
+ console.log(' Stripe already connected!');
90
+ }
91
+ }
92
+ catch (err) {
93
+ console.log(` Stripe Connect skipped: ${err.message}`);
94
+ console.log(' You can connect later via the tru dashboard.');
95
+ }
96
+ // 5. Write .env
97
+ console.log('\n Step 3: Writing configuration...');
98
+ writeEnvFile(process.cwd(), {
99
+ TRU_APP_ID: registerResult.app.id,
100
+ TRU_API_KEY: registerResult.api_key,
101
+ TRU_APP_SECRET: registerResult.app_secret,
102
+ TRU_SERVICE_NAME: registerResult.app.service_name,
103
+ TRU_API_URL,
104
+ });
105
+ console.log(' Written to .env');
106
+ // 6. Add .env to .gitignore
107
+ ensureGitignore(process.cwd());
108
+ // 7. Generate agent.md from detected routes
109
+ if (project.routes.length > 0) {
110
+ console.log('\n Step 4: Generating discovery files...');
111
+ const agentMd = generateAgentMd(project, registerResult.app.service_name, TRU_API_URL);
112
+ const agentMdPath = resolve(process.cwd(), 'agent.md');
113
+ writeFileSync(agentMdPath, agentMd);
114
+ console.log(' Generated agent.md');
115
+ const llmsTxt = generateLlmsTxt(project, registerResult.app.service_name, TRU_API_URL);
116
+ const publicDir = resolve(process.cwd(), 'public');
117
+ if (existsSync(publicDir)) {
118
+ writeFileSync(resolve(publicDir, 'llms.txt'), llmsTxt);
119
+ console.log(' Generated public/llms.txt');
120
+ }
121
+ else {
122
+ writeFileSync(resolve(process.cwd(), 'llms.txt'), llmsTxt);
123
+ console.log(' Generated llms.txt');
124
+ }
125
+ }
126
+ // 8. Done!
127
+ console.log(`
128
+ Done! Your endpoints now accept agent payments.
129
+
130
+ Usage:
131
+ const { trux } = require('tru-402');
132
+ // or: import { trux } from 'tru-402';
133
+
134
+ app.post('/api/generate', trux({ amount: 0.05 }), (req, res) => {
135
+ console.log(req.tru); // { email, name, userId, cardBrand, cardLast4, agentName, chargeId }
136
+ res.json({ result: '...' });
137
+ });
138
+
139
+ What happens:
140
+ - Unauthenticated requests get a 402 with payment instructions
141
+ - Agents pay via tru and retry with an Authorization header
142
+ - req.tru contains verified identity on every paid request
143
+ - Existing auth (API keys, sessions) passes through unchanged
144
+
145
+ Dashboard: ${TRU_API_URL}/admin
146
+ Docs: https://tru.so/docs
147
+ `);
148
+ }
149
+ function ensureGitignore(cwd) {
150
+ const gitignorePath = resolve(cwd, '.gitignore');
151
+ if (existsSync(gitignorePath)) {
152
+ const content = readFileSync(gitignorePath, 'utf-8');
153
+ if (!content.includes('.env')) {
154
+ writeFileSync(gitignorePath, content + '\n.env\n');
155
+ console.log(' Added .env to .gitignore');
156
+ }
157
+ }
158
+ else {
159
+ writeFileSync(gitignorePath, '.env\nnode_modules/\n');
160
+ console.log(' Created .gitignore with .env');
161
+ }
162
+ }
163
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/init/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface RouteInfo {
2
+ method: string;
3
+ path: string;
4
+ amount: number;
5
+ description?: string;
6
+ file: string;
7
+ line: number;
8
+ }
9
+ export interface ProjectInfo {
10
+ name: string;
11
+ displayName?: string;
12
+ description?: string;
13
+ framework: string;
14
+ routes: RouteInfo[];
15
+ productionUrl?: string;
16
+ }
17
+ /**
18
+ * Scan a project directory for package.json info and trux() middleware usage.
19
+ */
20
+ export declare function scanProject(cwd: string): ProjectInfo;
21
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/init/scan.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAiCpD"}
@@ -0,0 +1,128 @@
1
+ import { readFileSync, existsSync, readdirSync, statSync } from 'fs';
2
+ import { resolve, join, extname } from 'path';
3
+ /**
4
+ * Scan a project directory for package.json info and trux() middleware usage.
5
+ */
6
+ export function scanProject(cwd) {
7
+ const info = {
8
+ name: 'my-app',
9
+ framework: 'unknown',
10
+ routes: [],
11
+ };
12
+ // Read package.json
13
+ const pkgPath = resolve(cwd, 'package.json');
14
+ if (existsSync(pkgPath)) {
15
+ try {
16
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
17
+ info.name = pkg.name || 'my-app';
18
+ info.displayName = pkg.name?.replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
19
+ info.description = pkg.description;
20
+ // Detect framework from dependencies
21
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
22
+ if (deps.express)
23
+ info.framework = 'express';
24
+ else if (deps.fastify)
25
+ info.framework = 'fastify';
26
+ else if (deps.koa)
27
+ info.framework = 'koa';
28
+ else if (deps.hono)
29
+ info.framework = 'hono';
30
+ }
31
+ catch { /* ignore parse errors */ }
32
+ }
33
+ // Scan source files for trux() middleware usage
34
+ const sourceFiles = findSourceFiles(cwd);
35
+ for (const file of sourceFiles) {
36
+ const routes = scanFileForTrux(file);
37
+ info.routes.push(...routes);
38
+ }
39
+ return info;
40
+ }
41
+ /**
42
+ * Find TypeScript/JavaScript source files in common locations.
43
+ */
44
+ function findSourceFiles(cwd) {
45
+ const files = [];
46
+ const dirs = ['src', 'routes', 'api', 'lib', 'server', 'app'];
47
+ // Also scan root-level .ts/.js files
48
+ try {
49
+ for (const entry of readdirSync(cwd)) {
50
+ const ext = extname(entry);
51
+ if (['.ts', '.js', '.mjs'].includes(ext) && !entry.startsWith('.')) {
52
+ files.push(resolve(cwd, entry));
53
+ }
54
+ }
55
+ }
56
+ catch { /* ignore */ }
57
+ for (const dir of dirs) {
58
+ const dirPath = resolve(cwd, dir);
59
+ if (existsSync(dirPath)) {
60
+ walkDir(dirPath, files, 3); // max depth 3
61
+ }
62
+ }
63
+ return files;
64
+ }
65
+ function walkDir(dir, files, depth) {
66
+ if (depth <= 0)
67
+ return;
68
+ try {
69
+ for (const entry of readdirSync(dir)) {
70
+ if (entry.startsWith('.') || entry === 'node_modules' || entry === 'dist')
71
+ continue;
72
+ const full = join(dir, entry);
73
+ const stat = statSync(full);
74
+ if (stat.isDirectory()) {
75
+ walkDir(full, files, depth - 1);
76
+ }
77
+ else {
78
+ const ext = extname(entry);
79
+ if (['.ts', '.js', '.mjs'].includes(ext)) {
80
+ files.push(full);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ catch { /* ignore permission errors */ }
86
+ }
87
+ /**
88
+ * Scan a single file for trux() middleware calls.
89
+ * Matches patterns like: app.post('/path', trux({ amount: 0.05 }), handler)
90
+ */
91
+ function scanFileForTrux(filePath) {
92
+ const routes = [];
93
+ try {
94
+ const content = readFileSync(filePath, 'utf-8');
95
+ const lines = content.split('\n');
96
+ // Match: app.METHOD('path', trux({ amount: N.NN ... }), ...)
97
+ // or: router.METHOD('path', trux({ amount: N.NN ... }), ...)
98
+ const pattern = /\.(get|post|put|patch|delete)\s*\(\s*['"`]([^'"`]+)['"`]\s*,\s*trux\s*\(\s*\{([^}]+)\}/g;
99
+ for (let i = 0; i < lines.length; i++) {
100
+ // Check multi-line by joining with next few lines
101
+ const chunk = lines.slice(i, i + 5).join(' ');
102
+ let match;
103
+ pattern.lastIndex = 0;
104
+ while ((match = pattern.exec(chunk)) !== null) {
105
+ const method = match[1];
106
+ const path = match[2];
107
+ const optionsStr = match[3];
108
+ // Extract amount
109
+ const amountMatch = optionsStr.match(/amount\s*:\s*([\d.]+)/);
110
+ const amount = amountMatch ? parseFloat(amountMatch[1]) : 0;
111
+ // Extract description
112
+ const descMatch = optionsStr.match(/description\s*:\s*['"`]([^'"`]+)['"`]/);
113
+ const description = descMatch ? descMatch[1] : undefined;
114
+ routes.push({
115
+ method: method.toUpperCase(),
116
+ path,
117
+ amount,
118
+ description,
119
+ file: filePath,
120
+ line: i + 1,
121
+ });
122
+ }
123
+ }
124
+ }
125
+ catch { /* ignore read errors */ }
126
+ return routes;
127
+ }
128
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/init/scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ import type { TruxOptions } from './identity.js';
3
+ /**
4
+ * Create the trux Express middleware.
5
+ *
6
+ * Usage:
7
+ * ```
8
+ * app.post('/api/generate', trux({ amount: 0.05 }), handler);
9
+ * ```
10
+ */
11
+ export declare function createMiddleware(options: TruxOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
12
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,eAAe,CAAC;AA0E7D;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,IAGrC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,mBA8C9D"}
@@ -0,0 +1,117 @@
1
+ import { generateChallenge } from './challenge.js';
2
+ import { verifyCredential } from './verify.js';
3
+ import { debitSession } from './session.js';
4
+ /**
5
+ * Resolve trux config from environment variables.
6
+ */
7
+ function resolveConfig() {
8
+ const appId = process.env.TRU_APP_ID;
9
+ const apiKey = process.env.TRU_API_KEY;
10
+ if (!appId || !apiKey) {
11
+ throw new Error('tru-402: TRU_APP_ID and TRU_API_KEY environment variables are required. Run `npx tru-402 init` to set them up.');
12
+ }
13
+ return {
14
+ appId,
15
+ apiKey,
16
+ apiUrl: process.env.TRU_API_URL || 'https://tru.so',
17
+ appSecret: process.env.TRU_APP_SECRET,
18
+ serviceName: process.env.TRU_SERVICE_NAME,
19
+ };
20
+ }
21
+ // Lazy-loaded config singleton
22
+ let _config = null;
23
+ function getConfig() {
24
+ if (!_config)
25
+ _config = resolveConfig();
26
+ return _config;
27
+ }
28
+ /**
29
+ * Extract credential from Authorization header.
30
+ * Supports: "Payment <credential>" and "Bearer <credential>" (where credential starts with spt_)
31
+ */
32
+ function extractCredential(authHeader) {
33
+ if (!authHeader)
34
+ return null;
35
+ if (authHeader.startsWith('Payment ')) {
36
+ return authHeader.slice(8).trim();
37
+ }
38
+ if (authHeader.startsWith('Bearer spt_')) {
39
+ return authHeader.slice(7).trim();
40
+ }
41
+ return null;
42
+ }
43
+ /**
44
+ * Check if request has existing auth that should bypass payment.
45
+ * Looks for API keys, session cookies, or other standard auth mechanisms.
46
+ */
47
+ function hasExistingAuth(req, options) {
48
+ // Custom passthrough check
49
+ if (options.passthrough?.(req))
50
+ return true;
51
+ // Standard auth headers (non-SPT bearer tokens, basic auth, API keys)
52
+ const auth = req.headers.authorization;
53
+ if (auth && !auth.startsWith('Payment ') && !auth.startsWith('Bearer spt_')) {
54
+ return true;
55
+ }
56
+ // Common API key headers
57
+ if (req.headers['x-api-key'] || req.headers['api-key'])
58
+ return true;
59
+ // Session cookies
60
+ if (req.cookies?.session || req.cookies?.token)
61
+ return true;
62
+ return false;
63
+ }
64
+ /**
65
+ * Create the trux Express middleware.
66
+ *
67
+ * Usage:
68
+ * ```
69
+ * app.post('/api/generate', trux({ amount: 0.05 }), handler);
70
+ * ```
71
+ */
72
+ export function createMiddleware(options) {
73
+ const amountCents = Math.round(options.amount * 100);
74
+ return async (req, res, next) => {
75
+ try {
76
+ const config = getConfig();
77
+ // 1. Passthrough for existing auth (existing customers unaffected)
78
+ if (hasExistingAuth(req, options)) {
79
+ return next();
80
+ }
81
+ // 2. Check for SPT credential (Authorization: Payment <spt_xxx>)
82
+ const credential = extractCredential(req.headers.authorization);
83
+ if (credential) {
84
+ const result = await verifyCredential(credential, amountCents, config);
85
+ if (result.valid && result.identity) {
86
+ req.tru = result.identity;
87
+ return next();
88
+ }
89
+ // Invalid credential — fall through to 402
90
+ }
91
+ // 3. Check for session header (X-Tru-Session)
92
+ const sessionId = req.headers['x-tru-session'];
93
+ if (sessionId) {
94
+ const result = await debitSession(sessionId, amountCents, config);
95
+ if (result.ok && result.identity) {
96
+ req.tru = result.identity;
97
+ return next();
98
+ }
99
+ // Session exhausted or invalid — fall through to 402
100
+ }
101
+ // 4. No valid auth — return 402 with self-documenting challenge
102
+ const requestUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
103
+ const challenge = generateChallenge({
104
+ options,
105
+ config,
106
+ requestUrl,
107
+ });
108
+ res.status(402)
109
+ .set('WWW-Authenticate', challenge.header)
110
+ .json(challenge.body);
111
+ }
112
+ catch (err) {
113
+ next(err);
114
+ }
115
+ };
116
+ }
117
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { TruIdentity, TruxConfig } from './identity.js';
2
+ interface SessionDebitResult {
3
+ ok: boolean;
4
+ remaining_cents?: number;
5
+ identity?: TruIdentity;
6
+ error?: string;
7
+ }
8
+ /**
9
+ * Debit from an existing trux session.
10
+ */
11
+ export declare function debitSession(sessionId: string, amountCents: number, config: TruxConfig): Promise<SessionDebitResult>;
12
+ /**
13
+ * Create a new trux session after initial 402 resolution.
14
+ */
15
+ export declare function createSession(userEmail: string, budgetCents: number, chargeRequestId: string, stripeSptId: string, agentName: string | undefined, config: TruxConfig): Promise<{
16
+ sessionId: string;
17
+ expiresAt: string;
18
+ } | null>;
19
+ export {};
20
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE7D,UAAU,kBAAkB;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,kBAAkB,CAAC,CAiC7B;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAkB1D"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Debit from an existing trux session.
3
+ */
4
+ export async function debitSession(sessionId, amountCents, config) {
5
+ const res = await fetch(`${config.apiUrl}/api/mpp/session-debit`, {
6
+ method: 'POST',
7
+ headers: {
8
+ 'Content-Type': 'application/json',
9
+ 'X-API-Key': config.apiKey,
10
+ },
11
+ body: JSON.stringify({
12
+ session_id: sessionId,
13
+ amount_cents: amountCents,
14
+ }),
15
+ });
16
+ const data = await res.json();
17
+ if (!res.ok || !data.ok) {
18
+ return { ok: false, error: data.error || `HTTP ${res.status}` };
19
+ }
20
+ return {
21
+ ok: true,
22
+ remaining_cents: data.remaining_cents,
23
+ identity: data.identity ? {
24
+ email: data.identity.email,
25
+ name: data.identity.name,
26
+ userId: data.identity.userId,
27
+ cardBrand: data.identity.cardBrand,
28
+ cardLast4: data.identity.cardLast4,
29
+ agentName: data.identity.agentName,
30
+ chargeId: data.identity.chargeId,
31
+ sessionId,
32
+ } : undefined,
33
+ };
34
+ }
35
+ /**
36
+ * Create a new trux session after initial 402 resolution.
37
+ */
38
+ export async function createSession(userEmail, budgetCents, chargeRequestId, stripeSptId, agentName, config) {
39
+ const res = await fetch(`${config.apiUrl}/api/mpp/sessions`, {
40
+ method: 'POST',
41
+ headers: {
42
+ 'Content-Type': 'application/json',
43
+ 'X-API-Key': config.apiKey,
44
+ },
45
+ body: JSON.stringify({
46
+ user_email: userEmail,
47
+ budget_cents: budgetCents,
48
+ charge_request_id: chargeRequestId,
49
+ stripe_spt_id: stripeSptId,
50
+ agent_name: agentName,
51
+ }),
52
+ });
53
+ if (!res.ok)
54
+ return null;
55
+ return res.json();
56
+ }
57
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"AASA;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,SAAiB,EACjB,WAAmB,EACnB,MAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,wBAAwB,EAAE;QAChE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,WAAW,EAAE,MAAM,CAAC,MAAM;SAC3B;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,UAAU,EAAE,SAAS;YACrB,YAAY,EAAE,WAAW;SAC1B,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAE9B,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACxB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;IAClE,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YACxB,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK;YAC1B,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;YACxB,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM;YAC5B,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS;YAClC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS;YAClC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS;YAClC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ;YAChC,SAAS;SACV,CAAC,CAAC,CAAC,SAAS;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,SAAiB,EACjB,WAAmB,EACnB,eAAuB,EACvB,WAAmB,EACnB,SAA6B,EAC7B,MAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,mBAAmB,EAAE;QAC3D,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,WAAW,EAAE,MAAM,CAAC,MAAM;SAC3B;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,UAAU,EAAE,SAAS;YACrB,YAAY,EAAE,WAAW;YACzB,iBAAiB,EAAE,eAAe;YAClC,aAAa,EAAE,WAAW;YAC1B,UAAU,EAAE,SAAS;SACtB,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACzB,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { TruIdentity, TruxConfig } from './identity.js';
2
+ interface VerifyResult {
3
+ valid: boolean;
4
+ identity?: TruIdentity;
5
+ error?: string;
6
+ }
7
+ /**
8
+ * Verify an SPT credential with the tru API and return user identity.
9
+ */
10
+ export declare function verifyCredential(credential: string, amountCents: number, config: TruxConfig): Promise<VerifyResult>;
11
+ export {};
12
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE7D,UAAU,YAAY;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,CAoCvB"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Verify an SPT credential with the tru API and return user identity.
3
+ */
4
+ export async function verifyCredential(credential, amountCents, config) {
5
+ const res = await fetch(`${config.apiUrl}/api/mpp/verify-credential`, {
6
+ method: 'POST',
7
+ headers: {
8
+ 'Content-Type': 'application/json',
9
+ 'X-API-Key': config.apiKey,
10
+ },
11
+ body: JSON.stringify({
12
+ credential,
13
+ amount_cents: amountCents,
14
+ app_id: config.appId,
15
+ }),
16
+ });
17
+ if (!res.ok) {
18
+ const err = await res.json().catch(() => ({ error: 'Verification failed' }));
19
+ return { valid: false, error: err.error || `HTTP ${res.status}` };
20
+ }
21
+ const data = await res.json();
22
+ if (!data.valid) {
23
+ return { valid: false, error: data.error };
24
+ }
25
+ return {
26
+ valid: true,
27
+ identity: {
28
+ email: data.identity.email,
29
+ name: data.identity.name,
30
+ userId: data.identity.userId,
31
+ cardBrand: data.identity.cardBrand,
32
+ cardLast4: data.identity.cardLast4,
33
+ agentName: data.identity.agentName,
34
+ chargeId: data.identity.chargeId,
35
+ },
36
+ };
37
+ }
38
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,UAAkB,EAClB,WAAmB,EACnB,MAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,4BAA4B,EAAE;QACpE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,WAAW,EAAE,MAAM,CAAC,MAAM;SAC3B;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,UAAU;YACV,YAAY,EAAE,WAAW;YACzB,MAAM,EAAE,MAAM,CAAC,KAAK;SACrB,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC;QAC7E,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;IACpE,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IAC7C,CAAC;IAED,OAAO;QACL,KAAK,EAAE,IAAI;QACX,QAAQ,EAAE;YACR,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK;YAC1B,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;YACxB,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM;YAC5B,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS;YAClC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS;YAClC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS;YAClC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ;SACjC;KACF,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "tru-402",
3
+ "version": "0.1.0",
4
+ "description": "One-line middleware for agent commerce. Add paid endpoints with identity — no setup flow, no API keys for buyers.",
5
+ "type": "module",
6
+ "bin": {
7
+ "tru-402": "dist/bin/trux.js"
8
+ },
9
+ "exports": {
10
+ ".": "./dist/src/index.js"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "tsc --watch"
18
+ },
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "dependencies": {
23
+ "@types/express": "^5.0.0",
24
+ "@types/node": "^22.10.7",
25
+ "typescript": "^5.7.3"
26
+ },
27
+ "peerDependencies": {
28
+ "express": ">=4.0.0"
29
+ },
30
+ "keywords": [
31
+ "agent",
32
+ "commerce",
33
+ "middleware",
34
+ "402",
35
+ "payment",
36
+ "tru",
37
+ "mpp",
38
+ "stripe",
39
+ "express"
40
+ ],
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/dwurtz/tru"
44
+ },
45
+ "author": "Very Tru, LLC",
46
+ "license": "MIT"
47
+ }