scopeblind-agent 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.
@@ -0,0 +1,116 @@
1
+ /**
2
+ * ScopeBlind Agent SDK — Cryptographic device identity for AI agents, CLIs, and SDKs.
3
+ *
4
+ * Uses DPoP (RFC 9449) to create proof-of-possession for each request.
5
+ * The agent generates an ES256 key pair on first use and stores it locally.
6
+ * Each request includes a self-signed JWT proof that binds it to the agent's key.
7
+ *
8
+ * Quick start:
9
+ * npm install scopeblind-agent
10
+ *
11
+ * import { createAgent } from 'scopeblind-agent';
12
+ *
13
+ * const agent = await createAgent({ keyPath: '.scopeblind/agent-key.json' });
14
+ *
15
+ * // Option 1: Get headers to attach to your own fetch
16
+ * const headers = agent.headers('POST', 'https://api.example.com/endpoint');
17
+ * await fetch(url, { method: 'POST', headers, body: '...' });
18
+ *
19
+ * // Option 2: Use the built-in fetch wrapper
20
+ * const res = await agent.fetch('https://api.example.com/endpoint', {
21
+ * method: 'POST',
22
+ * body: JSON.stringify({ data: '...' }),
23
+ * });
24
+ *
25
+ * The server running `scopeblind` middleware will automatically verify the DPoP
26
+ * proof and identify this agent by its key hash (req.scopeblind.dpopDeviceId).
27
+ *
28
+ * Full docs: https://www.scopeblind.com/llms.txt
29
+ */
30
+ interface AgentOptions {
31
+ /**
32
+ * Path to store the agent's key pair (JSON file).
33
+ * If the file doesn't exist, a new key pair will be generated.
34
+ * Default: '.scopeblind/agent-key.json'
35
+ */
36
+ keyPath?: string;
37
+ /**
38
+ * Existing JWK key pair to use instead of generating/loading from file.
39
+ * Useful for serverless environments or in-memory key management.
40
+ */
41
+ jwk?: {
42
+ publicKey: {
43
+ kty: string;
44
+ crv: string;
45
+ x: string;
46
+ y: string;
47
+ };
48
+ privateKey: {
49
+ kty: string;
50
+ crv: string;
51
+ x: string;
52
+ y: string;
53
+ d: string;
54
+ };
55
+ };
56
+ }
57
+ interface ScopeBlindAgent {
58
+ /** The agent's device ID (SHA-256 hash of the public key, 16 hex chars) */
59
+ deviceId: string;
60
+ /** The agent's public key as JWK */
61
+ publicKey: {
62
+ kty: string;
63
+ crv: string;
64
+ x: string;
65
+ y: string;
66
+ };
67
+ /**
68
+ * Create a DPoP proof JWT for a specific request.
69
+ * Returns the proof string to use as the DPoP header value.
70
+ */
71
+ createProof: (method: string, url: string) => string;
72
+ /**
73
+ * Get headers object with DPoP proof for a request.
74
+ * Use this to attach proof to your own fetch/axios calls.
75
+ */
76
+ headers: (method: string, url: string, extraHeaders?: Record<string, string>) => Record<string, string>;
77
+ /**
78
+ * Fetch wrapper that automatically attaches DPoP proof.
79
+ * Drop-in replacement for global fetch with automatic proof-of-possession.
80
+ */
81
+ fetch: (url: string, init?: RequestInit) => Promise<Response>;
82
+ }
83
+ declare function hashJWK(jwk: {
84
+ kty: string;
85
+ crv: string;
86
+ x: string;
87
+ y: string;
88
+ }): string;
89
+ /**
90
+ * Create a ScopeBlind agent with DPoP proof-of-possession capability.
91
+ *
92
+ * The agent generates (or loads) an ES256 key pair and creates self-signed
93
+ * JWT proofs per RFC 9449 for each request. The server-side `scopeblind`
94
+ * middleware verifies these proofs and identifies the agent by its key hash.
95
+ *
96
+ * @param options - Agent configuration
97
+ * @returns A ScopeBlindAgent instance with proof creation and fetch methods
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * import { createAgent } from 'scopeblind-agent';
102
+ *
103
+ * const agent = await createAgent();
104
+ * console.log('Agent device ID:', agent.deviceId);
105
+ *
106
+ * // Automatic DPoP proof with fetch wrapper
107
+ * const res = await agent.fetch('https://api.example.com/endpoint', {
108
+ * method: 'POST',
109
+ * headers: { 'Content-Type': 'application/json' },
110
+ * body: JSON.stringify({ prompt: 'Hello' }),
111
+ * });
112
+ * ```
113
+ */
114
+ declare function createAgent(options?: AgentOptions): Promise<ScopeBlindAgent>;
115
+
116
+ export { type AgentOptions, type ScopeBlindAgent, createAgent, hashJWK };
@@ -0,0 +1,116 @@
1
+ /**
2
+ * ScopeBlind Agent SDK — Cryptographic device identity for AI agents, CLIs, and SDKs.
3
+ *
4
+ * Uses DPoP (RFC 9449) to create proof-of-possession for each request.
5
+ * The agent generates an ES256 key pair on first use and stores it locally.
6
+ * Each request includes a self-signed JWT proof that binds it to the agent's key.
7
+ *
8
+ * Quick start:
9
+ * npm install scopeblind-agent
10
+ *
11
+ * import { createAgent } from 'scopeblind-agent';
12
+ *
13
+ * const agent = await createAgent({ keyPath: '.scopeblind/agent-key.json' });
14
+ *
15
+ * // Option 1: Get headers to attach to your own fetch
16
+ * const headers = agent.headers('POST', 'https://api.example.com/endpoint');
17
+ * await fetch(url, { method: 'POST', headers, body: '...' });
18
+ *
19
+ * // Option 2: Use the built-in fetch wrapper
20
+ * const res = await agent.fetch('https://api.example.com/endpoint', {
21
+ * method: 'POST',
22
+ * body: JSON.stringify({ data: '...' }),
23
+ * });
24
+ *
25
+ * The server running `scopeblind` middleware will automatically verify the DPoP
26
+ * proof and identify this agent by its key hash (req.scopeblind.dpopDeviceId).
27
+ *
28
+ * Full docs: https://www.scopeblind.com/llms.txt
29
+ */
30
+ interface AgentOptions {
31
+ /**
32
+ * Path to store the agent's key pair (JSON file).
33
+ * If the file doesn't exist, a new key pair will be generated.
34
+ * Default: '.scopeblind/agent-key.json'
35
+ */
36
+ keyPath?: string;
37
+ /**
38
+ * Existing JWK key pair to use instead of generating/loading from file.
39
+ * Useful for serverless environments or in-memory key management.
40
+ */
41
+ jwk?: {
42
+ publicKey: {
43
+ kty: string;
44
+ crv: string;
45
+ x: string;
46
+ y: string;
47
+ };
48
+ privateKey: {
49
+ kty: string;
50
+ crv: string;
51
+ x: string;
52
+ y: string;
53
+ d: string;
54
+ };
55
+ };
56
+ }
57
+ interface ScopeBlindAgent {
58
+ /** The agent's device ID (SHA-256 hash of the public key, 16 hex chars) */
59
+ deviceId: string;
60
+ /** The agent's public key as JWK */
61
+ publicKey: {
62
+ kty: string;
63
+ crv: string;
64
+ x: string;
65
+ y: string;
66
+ };
67
+ /**
68
+ * Create a DPoP proof JWT for a specific request.
69
+ * Returns the proof string to use as the DPoP header value.
70
+ */
71
+ createProof: (method: string, url: string) => string;
72
+ /**
73
+ * Get headers object with DPoP proof for a request.
74
+ * Use this to attach proof to your own fetch/axios calls.
75
+ */
76
+ headers: (method: string, url: string, extraHeaders?: Record<string, string>) => Record<string, string>;
77
+ /**
78
+ * Fetch wrapper that automatically attaches DPoP proof.
79
+ * Drop-in replacement for global fetch with automatic proof-of-possession.
80
+ */
81
+ fetch: (url: string, init?: RequestInit) => Promise<Response>;
82
+ }
83
+ declare function hashJWK(jwk: {
84
+ kty: string;
85
+ crv: string;
86
+ x: string;
87
+ y: string;
88
+ }): string;
89
+ /**
90
+ * Create a ScopeBlind agent with DPoP proof-of-possession capability.
91
+ *
92
+ * The agent generates (or loads) an ES256 key pair and creates self-signed
93
+ * JWT proofs per RFC 9449 for each request. The server-side `scopeblind`
94
+ * middleware verifies these proofs and identifies the agent by its key hash.
95
+ *
96
+ * @param options - Agent configuration
97
+ * @returns A ScopeBlindAgent instance with proof creation and fetch methods
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * import { createAgent } from 'scopeblind-agent';
102
+ *
103
+ * const agent = await createAgent();
104
+ * console.log('Agent device ID:', agent.deviceId);
105
+ *
106
+ * // Automatic DPoP proof with fetch wrapper
107
+ * const res = await agent.fetch('https://api.example.com/endpoint', {
108
+ * method: 'POST',
109
+ * headers: { 'Content-Type': 'application/json' },
110
+ * body: JSON.stringify({ prompt: 'Hello' }),
111
+ * });
112
+ * ```
113
+ */
114
+ declare function createAgent(options?: AgentOptions): Promise<ScopeBlindAgent>;
115
+
116
+ export { type AgentOptions, type ScopeBlindAgent, createAgent, hashJWK };
package/dist/index.js ADDED
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ createAgent: () => createAgent,
24
+ hashJWK: () => hashJWK
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+ var import_node_crypto = require("crypto");
28
+ var import_node_fs = require("fs");
29
+ var import_node_path = require("path");
30
+ function generateKeyPair() {
31
+ const { publicKey, privateKey } = (0, import_node_crypto.generateKeyPairSync)("ec", {
32
+ namedCurve: "P-256"
33
+ });
34
+ const pubJwk = publicKey.export({ format: "jwk" });
35
+ const privJwk = privateKey.export({ format: "jwk" });
36
+ return {
37
+ publicKey: { kty: pubJwk.kty, crv: pubJwk.crv, x: pubJwk.x, y: pubJwk.y },
38
+ privateKey: { kty: privJwk.kty, crv: privJwk.crv, x: privJwk.x, y: privJwk.y, d: privJwk.d },
39
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
40
+ };
41
+ }
42
+ function loadOrGenerateKey(keyPath) {
43
+ if ((0, import_node_fs.existsSync)(keyPath)) {
44
+ try {
45
+ const data = (0, import_node_fs.readFileSync)(keyPath, "utf8");
46
+ const stored = JSON.parse(data);
47
+ if (stored.publicKey?.kty === "EC" && stored.publicKey?.crv === "P-256" && stored.privateKey?.d) {
48
+ return stored;
49
+ }
50
+ } catch {
51
+ }
52
+ }
53
+ const key = generateKeyPair();
54
+ const dir = (0, import_node_path.dirname)(keyPath);
55
+ if (!(0, import_node_fs.existsSync)(dir)) {
56
+ (0, import_node_fs.mkdirSync)(dir, { recursive: true });
57
+ }
58
+ (0, import_node_fs.writeFileSync)(keyPath, JSON.stringify(key, null, 2), { mode: 384 });
59
+ return key;
60
+ }
61
+ function hashJWK(jwk) {
62
+ const canonical = JSON.stringify({
63
+ crv: jwk.crv,
64
+ kty: jwk.kty,
65
+ x: jwk.x,
66
+ y: jwk.y
67
+ });
68
+ return (0, import_node_crypto.createHash)("sha256").update(canonical).digest("hex").slice(0, 16);
69
+ }
70
+ function base64url(data) {
71
+ return data.toString("base64url");
72
+ }
73
+ function createDPoPProof(method, url, publicKey, privateKeyJwk) {
74
+ const header = {
75
+ typ: "dpop+jwt",
76
+ alg: "ES256",
77
+ jwk: publicKey
78
+ };
79
+ const now = Math.floor(Date.now() / 1e3);
80
+ const payload = {
81
+ jti: (0, import_node_crypto.randomUUID)().replace(/-/g, ""),
82
+ htm: method.toUpperCase(),
83
+ htu: url,
84
+ iat: now
85
+ };
86
+ const headerB64 = base64url(Buffer.from(JSON.stringify(header)));
87
+ const payloadB64 = base64url(Buffer.from(JSON.stringify(payload)));
88
+ const signingInput = `${headerB64}.${payloadB64}`;
89
+ const { createPrivateKey } = require("crypto");
90
+ const privKey = createPrivateKey({
91
+ key: {
92
+ ...privateKeyJwk,
93
+ key_ops: ["sign"]
94
+ },
95
+ format: "jwk"
96
+ });
97
+ const sign = (0, import_node_crypto.createSign)("SHA256");
98
+ sign.update(signingInput);
99
+ const derSig = sign.sign(privKey);
100
+ const r = extractIntegerFromDER(derSig, 0);
101
+ const s = extractIntegerFromDER(derSig, r.offset);
102
+ const rawSig = Buffer.concat([padTo32(r.value), padTo32(s.value)]);
103
+ const signatureB64 = base64url(rawSig);
104
+ return `${signingInput}.${signatureB64}`;
105
+ }
106
+ function extractIntegerFromDER(buf, startOffset) {
107
+ let offset = startOffset;
108
+ if (offset === 0 && buf[offset] === 48) {
109
+ offset++;
110
+ if (buf[offset] & 128) {
111
+ offset += (buf[offset] & 127) + 1;
112
+ } else {
113
+ offset++;
114
+ }
115
+ }
116
+ if (buf[offset] !== 2) throw new Error("Expected INTEGER tag");
117
+ offset++;
118
+ const len = buf[offset];
119
+ offset++;
120
+ let value = buf.subarray(offset, offset + len);
121
+ if (value[0] === 0 && value.length > 1) {
122
+ value = value.subarray(1);
123
+ }
124
+ return { value, offset: offset + len };
125
+ }
126
+ function padTo32(buf) {
127
+ if (buf.length === 32) return buf;
128
+ if (buf.length > 32) return buf.subarray(buf.length - 32);
129
+ const padded = Buffer.alloc(32);
130
+ buf.copy(padded, 32 - buf.length);
131
+ return padded;
132
+ }
133
+ async function createAgent(options = {}) {
134
+ const keyPath = options.keyPath || ".scopeblind/agent-key.json";
135
+ let key;
136
+ if (options.jwk) {
137
+ key = {
138
+ publicKey: options.jwk.publicKey,
139
+ privateKey: options.jwk.privateKey,
140
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
141
+ };
142
+ } else {
143
+ key = loadOrGenerateKey(keyPath);
144
+ }
145
+ const deviceId = hashJWK(key.publicKey);
146
+ const createProof = (method, url) => {
147
+ return createDPoPProof(method, url, key.publicKey, key.privateKey);
148
+ };
149
+ const getHeaders = (method, url, extraHeaders) => {
150
+ return {
151
+ ...extraHeaders,
152
+ DPoP: createProof(method, url)
153
+ };
154
+ };
155
+ const agentFetch = async (url, init) => {
156
+ const method = init?.method || "GET";
157
+ const dpop = createProof(method, url);
158
+ const headers = new Headers(init?.headers);
159
+ headers.set("DPoP", dpop);
160
+ return globalThis.fetch(url, {
161
+ ...init,
162
+ headers
163
+ });
164
+ };
165
+ return {
166
+ deviceId,
167
+ publicKey: key.publicKey,
168
+ createProof,
169
+ headers: getHeaders,
170
+ fetch: agentFetch
171
+ };
172
+ }
173
+ // Annotate the CommonJS export names for ESM import in node:
174
+ 0 && (module.exports = {
175
+ createAgent,
176
+ hashJWK
177
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,158 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/index.ts
9
+ import { createHash, generateKeyPairSync, createSign, randomUUID } from "crypto";
10
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
11
+ import { dirname } from "path";
12
+ function generateKeyPair() {
13
+ const { publicKey, privateKey } = generateKeyPairSync("ec", {
14
+ namedCurve: "P-256"
15
+ });
16
+ const pubJwk = publicKey.export({ format: "jwk" });
17
+ const privJwk = privateKey.export({ format: "jwk" });
18
+ return {
19
+ publicKey: { kty: pubJwk.kty, crv: pubJwk.crv, x: pubJwk.x, y: pubJwk.y },
20
+ privateKey: { kty: privJwk.kty, crv: privJwk.crv, x: privJwk.x, y: privJwk.y, d: privJwk.d },
21
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
22
+ };
23
+ }
24
+ function loadOrGenerateKey(keyPath) {
25
+ if (existsSync(keyPath)) {
26
+ try {
27
+ const data = readFileSync(keyPath, "utf8");
28
+ const stored = JSON.parse(data);
29
+ if (stored.publicKey?.kty === "EC" && stored.publicKey?.crv === "P-256" && stored.privateKey?.d) {
30
+ return stored;
31
+ }
32
+ } catch {
33
+ }
34
+ }
35
+ const key = generateKeyPair();
36
+ const dir = dirname(keyPath);
37
+ if (!existsSync(dir)) {
38
+ mkdirSync(dir, { recursive: true });
39
+ }
40
+ writeFileSync(keyPath, JSON.stringify(key, null, 2), { mode: 384 });
41
+ return key;
42
+ }
43
+ function hashJWK(jwk) {
44
+ const canonical = JSON.stringify({
45
+ crv: jwk.crv,
46
+ kty: jwk.kty,
47
+ x: jwk.x,
48
+ y: jwk.y
49
+ });
50
+ return createHash("sha256").update(canonical).digest("hex").slice(0, 16);
51
+ }
52
+ function base64url(data) {
53
+ return data.toString("base64url");
54
+ }
55
+ function createDPoPProof(method, url, publicKey, privateKeyJwk) {
56
+ const header = {
57
+ typ: "dpop+jwt",
58
+ alg: "ES256",
59
+ jwk: publicKey
60
+ };
61
+ const now = Math.floor(Date.now() / 1e3);
62
+ const payload = {
63
+ jti: randomUUID().replace(/-/g, ""),
64
+ htm: method.toUpperCase(),
65
+ htu: url,
66
+ iat: now
67
+ };
68
+ const headerB64 = base64url(Buffer.from(JSON.stringify(header)));
69
+ const payloadB64 = base64url(Buffer.from(JSON.stringify(payload)));
70
+ const signingInput = `${headerB64}.${payloadB64}`;
71
+ const { createPrivateKey } = __require("crypto");
72
+ const privKey = createPrivateKey({
73
+ key: {
74
+ ...privateKeyJwk,
75
+ key_ops: ["sign"]
76
+ },
77
+ format: "jwk"
78
+ });
79
+ const sign = createSign("SHA256");
80
+ sign.update(signingInput);
81
+ const derSig = sign.sign(privKey);
82
+ const r = extractIntegerFromDER(derSig, 0);
83
+ const s = extractIntegerFromDER(derSig, r.offset);
84
+ const rawSig = Buffer.concat([padTo32(r.value), padTo32(s.value)]);
85
+ const signatureB64 = base64url(rawSig);
86
+ return `${signingInput}.${signatureB64}`;
87
+ }
88
+ function extractIntegerFromDER(buf, startOffset) {
89
+ let offset = startOffset;
90
+ if (offset === 0 && buf[offset] === 48) {
91
+ offset++;
92
+ if (buf[offset] & 128) {
93
+ offset += (buf[offset] & 127) + 1;
94
+ } else {
95
+ offset++;
96
+ }
97
+ }
98
+ if (buf[offset] !== 2) throw new Error("Expected INTEGER tag");
99
+ offset++;
100
+ const len = buf[offset];
101
+ offset++;
102
+ let value = buf.subarray(offset, offset + len);
103
+ if (value[0] === 0 && value.length > 1) {
104
+ value = value.subarray(1);
105
+ }
106
+ return { value, offset: offset + len };
107
+ }
108
+ function padTo32(buf) {
109
+ if (buf.length === 32) return buf;
110
+ if (buf.length > 32) return buf.subarray(buf.length - 32);
111
+ const padded = Buffer.alloc(32);
112
+ buf.copy(padded, 32 - buf.length);
113
+ return padded;
114
+ }
115
+ async function createAgent(options = {}) {
116
+ const keyPath = options.keyPath || ".scopeblind/agent-key.json";
117
+ let key;
118
+ if (options.jwk) {
119
+ key = {
120
+ publicKey: options.jwk.publicKey,
121
+ privateKey: options.jwk.privateKey,
122
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
123
+ };
124
+ } else {
125
+ key = loadOrGenerateKey(keyPath);
126
+ }
127
+ const deviceId = hashJWK(key.publicKey);
128
+ const createProof = (method, url) => {
129
+ return createDPoPProof(method, url, key.publicKey, key.privateKey);
130
+ };
131
+ const getHeaders = (method, url, extraHeaders) => {
132
+ return {
133
+ ...extraHeaders,
134
+ DPoP: createProof(method, url)
135
+ };
136
+ };
137
+ const agentFetch = async (url, init) => {
138
+ const method = init?.method || "GET";
139
+ const dpop = createProof(method, url);
140
+ const headers = new Headers(init?.headers);
141
+ headers.set("DPoP", dpop);
142
+ return globalThis.fetch(url, {
143
+ ...init,
144
+ headers
145
+ });
146
+ };
147
+ return {
148
+ deviceId,
149
+ publicKey: key.publicKey,
150
+ createProof,
151
+ headers: getHeaders,
152
+ fetch: agentFetch
153
+ };
154
+ }
155
+ export {
156
+ createAgent,
157
+ hashJWK
158
+ };
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "scopeblind-agent",
3
+ "version": "1.0.0",
4
+ "description": "Cryptographic device identity for AI agents and CLIs. DPoP proof-of-possession for ScopeBlind-protected APIs.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "module": "dist/index.mjs",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "README.md"
22
+ ],
23
+ "keywords": [
24
+ "scopeblind",
25
+ "dpop",
26
+ "proof-of-possession",
27
+ "ai-agent",
28
+ "device-identity",
29
+ "api-security",
30
+ "rate-limiting",
31
+ "mcp",
32
+ "llm-gateway",
33
+ "bot-protection",
34
+ "rfc-9449",
35
+ "cryptographic-identity"
36
+ ],
37
+ "author": "Tom Farley <tommy@scopeblind.com>",
38
+ "license": "MIT",
39
+ "homepage": "https://www.scopeblind.com",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/nicosxt/scopeblind-gateway"
43
+ },
44
+ "bugs": {
45
+ "url": "https://github.com/nicosxt/scopeblind-gateway/issues"
46
+ },
47
+ "dependencies": {},
48
+ "devDependencies": {
49
+ "tsup": "^8.0.0",
50
+ "typescript": "^5.0.0",
51
+ "@types/node": "^20.0.0"
52
+ },
53
+ "engines": {
54
+ "node": ">=18.0.0"
55
+ }
56
+ }