within-sdk 1.0.0 → 1.0.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.
package/dist/validate.js DELETED
@@ -1,139 +0,0 @@
1
- /**
2
- * With.in MCP Auth SDK — Token Validation
3
- *
4
- * Validates tokens against With.in's JWKS endpoint.
5
- * Caches the JWKS keys in memory with a 5-minute refresh interval.
6
- *
7
- * SYNC NOTE: vendor/lib/validate.ts intentionally diverges here — it adds
8
- * `ngrok-skip-browser-warning` headers for local-dev only. Keep the
9
- * published SDK clean of those.
10
- */
11
- import { createRemoteJWKSet, jwtVerify } from 'jose';
12
- // Cache JWKS key set per URL
13
- const jwksCache = new Map();
14
- function getJwks(jwksUrl) {
15
- let jwks = jwksCache.get(jwksUrl);
16
- if (!jwks) {
17
- jwks = createRemoteJWKSet(new URL(jwksUrl));
18
- jwksCache.set(jwksUrl, jwks);
19
- }
20
- return jwks;
21
- }
22
- export async function validateWithinToken(token, jwksUrl) {
23
- try {
24
- const jwks = getJwks(jwksUrl);
25
- const { payload } = await jwtVerify(token, jwks);
26
- // Verify it's a With.in token
27
- if (payload.token_type !== 'access' && payload.token_type !== 'identity') {
28
- return null;
29
- }
30
- return payload;
31
- }
32
- catch {
33
- return null;
34
- }
35
- }
36
- export function extractBearerToken(authHeader) {
37
- if (!authHeader)
38
- return null;
39
- const match = authHeader.match(/^Bearer\s+(.+)$/i);
40
- return match?.[1] ?? null;
41
- }
42
- /** Report to With.in that the vendor recognises this user as an existing customer.
43
- * Call this when a With.in token arrives and you find the user in your own DB.
44
- * With.in will mark the user as a subscriber (no conversion fee).
45
- *
46
- * Pass `withinAccessToken` whenever it's available — the backend authenticates
47
- * the request by checking that token's claims match (email + vendor_slug).
48
- * Without it the call is rejected, so the vendorTokenValidator path (where
49
- * no With.in token exists) cannot drive conversions. That path is intentionally
50
- * niche today; broader auth (vendor shared secret) is planned. */
51
- export async function reportConversion(authServerUrl, vendorSlug, email, withinAccessToken) {
52
- if (!withinAccessToken)
53
- return; // No token, no auth → skip silently.
54
- try {
55
- await fetch(`${authServerUrl}/oauth/conversion`, {
56
- method: 'POST',
57
- headers: {
58
- 'Content-Type': 'application/json',
59
- Authorization: `Bearer ${withinAccessToken}`,
60
- },
61
- body: JSON.stringify({ email, vendor_slug: vendorSlug }),
62
- });
63
- }
64
- catch {
65
- // Don't block auth if reporting fails
66
- }
67
- }
68
- /** Check whether the token holder is now a subscriber for this vendor.
69
- * Used to unstick users who paid seconds ago but whose cached access
70
- * token still says the trial is exhausted. Returns false on any error —
71
- * falling back to the normal trial-exhausted message is the safe default. */
72
- export async function checkSubscriptionStatus(authServerUrl, token) {
73
- // Hard-cap the live check so a slow or dead auth server doesn't stall the
74
- // tool response. Claude will time out the tool call around ~30s; we fail
75
- // fast at 3s and let the normal trial-ended message render.
76
- const controller = new AbortController();
77
- const timer = setTimeout(() => controller.abort(), 3000);
78
- try {
79
- const res = await fetch(`${authServerUrl}/oauth/subscription-status`, {
80
- headers: { Authorization: `Bearer ${token}` },
81
- signal: controller.signal,
82
- });
83
- if (!res.ok)
84
- return false;
85
- const data = await res.json();
86
- return data.subscriber === true;
87
- }
88
- catch {
89
- return false;
90
- }
91
- finally {
92
- clearTimeout(timer);
93
- }
94
- }
95
- /** Report a tool call back to With.in for lead tracking and revocation
96
- * enforcement. `aiClient` — the MCP client name captured from the session's
97
- * `initialize` request (`clientInfo.name`). Lets the vendor and the user
98
- * see which agent (Claude Desktop, Cursor, ChatGPT, …) actually made
99
- * the call.
100
- *
101
- * Returns `{ revoked: true }` when the backend reports the token has been
102
- * revoked since issuance. Network/server errors return `{ revoked: false }`
103
- * so reporting outages never block a tool call. */
104
- export async function reportToolCall(authServerUrl, token, vendorSlug, toolName, aiClient, toolArguments) {
105
- try {
106
- const res = await fetch(`${authServerUrl}/oauth/report`, {
107
- method: 'POST',
108
- headers: { 'Content-Type': 'application/json' },
109
- body: JSON.stringify({
110
- token,
111
- tool_name: toolName,
112
- vendor_slug: vendorSlug,
113
- ai_client: aiClient,
114
- tool_arguments: toolArguments ?? undefined,
115
- }),
116
- });
117
- if (res.status === 401) {
118
- try {
119
- const body = (await res.json());
120
- if (body?.error === 'token_revoked')
121
- return { revoked: true };
122
- }
123
- catch { }
124
- }
125
- if (res.status === 429) {
126
- try {
127
- const body = (await res.json());
128
- if (body?.error === 'tool_budget_exhausted' && typeof body.tool === 'string' && typeof body.limit === 'number') {
129
- return { revoked: false, budgetExhausted: { tool: body.tool, limit: body.limit } };
130
- }
131
- }
132
- catch { }
133
- }
134
- }
135
- catch {
136
- // Don't block tool calls if reporting fails
137
- }
138
- return { revoked: false };
139
- }