within-enforcement-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/enforcement.d.ts +25 -0
- package/dist/enforcement.d.ts.map +1 -0
- package/dist/enforcement.js +95 -0
- package/dist/enforcement.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +34 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { EnforcementConfig, Enforcement } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create an enforcement instance for gating MCP tool calls.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* ```typescript
|
|
7
|
+
* const within = createEnforcement({
|
|
8
|
+
* vendorId: 'my-vendor',
|
|
9
|
+
* apiUrl: 'https://within-actions.onrender.com',
|
|
10
|
+
* apiKey: process.env.WITHIN_API_KEY,
|
|
11
|
+
* toolScopeMap: {
|
|
12
|
+
* search: 'data:read',
|
|
13
|
+
* write_record: 'data:write',
|
|
14
|
+
* },
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // In your tool handler:
|
|
18
|
+
* const decision = await within.authorize('search', claims);
|
|
19
|
+
* if (!decision.allowed) return `Access denied: ${decision.reason}`;
|
|
20
|
+
* // ... run tool ...
|
|
21
|
+
* await within.complete('search', claims, 'success');
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function createEnforcement(config: EnforcementConfig): Enforcement;
|
|
25
|
+
//# sourceMappingURL=enforcement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enforcement.d.ts","sourceRoot":"","sources":["../src/enforcement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EAKjB,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,WAAW,CAgGxE"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create an enforcement instance for gating MCP tool calls.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* ```typescript
|
|
6
|
+
* const within = createEnforcement({
|
|
7
|
+
* vendorId: 'my-vendor',
|
|
8
|
+
* apiUrl: 'https://within-actions.onrender.com',
|
|
9
|
+
* apiKey: process.env.WITHIN_API_KEY,
|
|
10
|
+
* toolScopeMap: {
|
|
11
|
+
* search: 'data:read',
|
|
12
|
+
* write_record: 'data:write',
|
|
13
|
+
* },
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* // In your tool handler:
|
|
17
|
+
* const decision = await within.authorize('search', claims);
|
|
18
|
+
* if (!decision.allowed) return `Access denied: ${decision.reason}`;
|
|
19
|
+
* // ... run tool ...
|
|
20
|
+
* await within.complete('search', claims, 'success');
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function createEnforcement(config) {
|
|
24
|
+
const { vendorId, apiUrl, apiKey, toolScopeMap } = config;
|
|
25
|
+
async function authorize(toolName, claims) {
|
|
26
|
+
const userType = claims['https://within.com/user_type'];
|
|
27
|
+
// Customers pass straight through — Within is not involved
|
|
28
|
+
if (userType === 'customer') {
|
|
29
|
+
return { allowed: true, bypassed: true };
|
|
30
|
+
}
|
|
31
|
+
// Scope check (from token, no network call)
|
|
32
|
+
const requiredScope = toolScopeMap[toolName];
|
|
33
|
+
if (requiredScope) {
|
|
34
|
+
const userScopes = claims['https://within.com/scopes'] ?? [];
|
|
35
|
+
if (!userScopes.includes(requiredScope)) {
|
|
36
|
+
return { allowed: false, reason: 'scope_denied' };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Quota check (live, hits the ledger)
|
|
40
|
+
const email = claims.email;
|
|
41
|
+
if (!email) {
|
|
42
|
+
return { allowed: false, reason: 'no_entitlement' };
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const res = await fetch(`${apiUrl}/api/ledger/${encodeURIComponent(email)}?vendor_id=${vendorId}`, { headers: { Authorization: `Bearer ${apiKey}` } });
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
return { allowed: false, reason: 'no_entitlement' };
|
|
48
|
+
}
|
|
49
|
+
const ledger = (await res.json());
|
|
50
|
+
if (!ledger.isActive) {
|
|
51
|
+
return { allowed: false, reason: 'inactive' };
|
|
52
|
+
}
|
|
53
|
+
if (ledger.quotaRemaining <= 0) {
|
|
54
|
+
return { allowed: false, reason: 'quota_exceeded' };
|
|
55
|
+
}
|
|
56
|
+
return { allowed: true };
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Network error — fail closed
|
|
60
|
+
return { allowed: false, reason: 'no_entitlement' };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function complete(toolName, claims, outcome, opts) {
|
|
64
|
+
const userType = claims['https://within.com/user_type'];
|
|
65
|
+
// No-op for customers
|
|
66
|
+
if (userType === 'customer')
|
|
67
|
+
return;
|
|
68
|
+
const email = claims.email;
|
|
69
|
+
if (!email)
|
|
70
|
+
return;
|
|
71
|
+
try {
|
|
72
|
+
await fetch(`${apiUrl}/api/usage`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: {
|
|
75
|
+
'Content-Type': 'application/json',
|
|
76
|
+
Authorization: `Bearer ${apiKey}`,
|
|
77
|
+
},
|
|
78
|
+
body: JSON.stringify({
|
|
79
|
+
vendor_id: vendorId,
|
|
80
|
+
email,
|
|
81
|
+
domain: claims['https://within.com/domain'],
|
|
82
|
+
tool_name: toolName,
|
|
83
|
+
outcome,
|
|
84
|
+
agent_session_id: opts?.agentSessionId,
|
|
85
|
+
latency_ms: opts?.latencyMs,
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Fire-and-forget — don't break the tool call if metering fails
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { authorize, complete };
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=enforcement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enforcement.js","sourceRoot":"","sources":["../src/enforcement.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,OAAO,EACP,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** Configuration for the enforcement SDK. */
|
|
2
|
+
export interface EnforcementConfig {
|
|
3
|
+
/** Vendor identifier — must match the vendor_id used in Within's backend. */
|
|
4
|
+
vendorId: string;
|
|
5
|
+
/** Within API base URL (e.g. https://within-actions.onrender.com). */
|
|
6
|
+
apiUrl: string;
|
|
7
|
+
/** API key for authenticating with Within's ledger/usage endpoints. */
|
|
8
|
+
apiKey: string;
|
|
9
|
+
/**
|
|
10
|
+
* Maps each MCP tool name to the scope it requires.
|
|
11
|
+
* Tools not listed here are unrestricted.
|
|
12
|
+
*
|
|
13
|
+
* Available scopes (cumulative by tier):
|
|
14
|
+
* Tier 0: tools:suggest
|
|
15
|
+
* Tier 1: tools:run, data:read
|
|
16
|
+
* Tier 2: data:write_limited
|
|
17
|
+
* Tier 3: data:write, crm:read
|
|
18
|
+
* Tier 4: crm:write_limited, analytics:read
|
|
19
|
+
*/
|
|
20
|
+
toolScopeMap: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
/** Within claims stamped into the Auth0 access token by the Auth0 Action. */
|
|
23
|
+
export interface WithinClaims {
|
|
24
|
+
sub?: string;
|
|
25
|
+
email?: string;
|
|
26
|
+
'https://within.com/user_type'?: 'customer' | 'prospect' | 'personal';
|
|
27
|
+
'https://within.com/domain'?: string;
|
|
28
|
+
'https://within.com/tier'?: number;
|
|
29
|
+
'https://within.com/scopes'?: string[];
|
|
30
|
+
'https://within.com/icp_score'?: number;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
}
|
|
33
|
+
/** Result of an authorization check. */
|
|
34
|
+
export interface AuthorizeResult {
|
|
35
|
+
/** Whether the tool call is allowed. */
|
|
36
|
+
allowed: boolean;
|
|
37
|
+
/** True when the user is a customer — enforcement was skipped entirely. */
|
|
38
|
+
bypassed?: boolean;
|
|
39
|
+
/** Reason for denial, if not allowed. */
|
|
40
|
+
reason?: DenialReason;
|
|
41
|
+
}
|
|
42
|
+
export type DenialReason = 'scope_denied' | 'quota_exceeded' | 'inactive' | 'no_entitlement';
|
|
43
|
+
/** Options for the complete() call. */
|
|
44
|
+
export interface CompleteOptions {
|
|
45
|
+
agentSessionId?: string;
|
|
46
|
+
latencyMs?: number;
|
|
47
|
+
}
|
|
48
|
+
export type Outcome = 'success' | 'failure' | 'quota_exceeded' | 'scope_denied';
|
|
49
|
+
/** The enforcement instance returned by createEnforcement(). */
|
|
50
|
+
export interface Enforcement {
|
|
51
|
+
/**
|
|
52
|
+
* Check if a tool call is allowed for the given user.
|
|
53
|
+
*
|
|
54
|
+
* - Customers: always allowed, no network calls.
|
|
55
|
+
* - Prospects: scope check (from token) + quota check (live, hits Within API).
|
|
56
|
+
*/
|
|
57
|
+
authorize(toolName: string, claims: WithinClaims): Promise<AuthorizeResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Report the outcome of a tool call.
|
|
60
|
+
*
|
|
61
|
+
* - Customers: no-op.
|
|
62
|
+
* - Prospects: records usage. Only 'success' increments quota.
|
|
63
|
+
* Fire-and-forget — never throws.
|
|
64
|
+
*/
|
|
65
|
+
complete(toolName: string, claims: WithinClaims, outcome: Outcome, opts?: CompleteOptions): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IAEjB,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IAEf,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;IAEf;;;;;;;;;;OAUG;IACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IACtE,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,2BAA2B,CAAC,EAAE,MAAM,EAAE,CAAC;IACvC,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wCAAwC;AACxC,MAAM,WAAW,eAAe;IAC9B,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yCAAyC;IACzC,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,MAAM,YAAY,GACpB,cAAc,GACd,gBAAgB,GAChB,UAAU,GACV,gBAAgB,CAAC;AAErB,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAEhF,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAE5E;;;;;;OAMG;IACH,QAAQ,CACN,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "within-enforcement-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Within GrowthAuth Enforcement SDK — scope checking, quota gating, and usage metering for MCP tool calls.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"within",
|
|
19
|
+
"mcp",
|
|
20
|
+
"enforcement",
|
|
21
|
+
"quota",
|
|
22
|
+
"scoping",
|
|
23
|
+
"trial",
|
|
24
|
+
"growthaauth"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"typescript": "^5.0.0"
|
|
33
|
+
}
|
|
34
|
+
}
|