@permission-protocol/sdk 0.1.0-alpha.2 → 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.
- package/LICENSE +21 -0
- package/README.md +61 -28
- package/dist/index.cjs +274 -0
- package/dist/index.d.cts +81 -0
- package/dist/index.d.ts +70 -286
- package/dist/index.js +208 -325
- package/package.json +30 -35
- package/dist/index.d.mts +0 -297
- package/dist/index.mjs +0 -325
package/dist/index.js
CHANGED
|
@@ -1,356 +1,239 @@
|
|
|
1
|
-
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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 });
|
|
1
|
+
// src/exceptions.ts
|
|
2
|
+
var PermissionProtocolError = class extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "PermissionProtocolError";
|
|
15
6
|
}
|
|
16
|
-
return to;
|
|
17
7
|
};
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
PermissionProtocolError: () => PermissionProtocolError,
|
|
24
|
-
PermissionRouter: () => PermissionRouter,
|
|
25
|
-
buildHashablePayload: () => buildHashablePayload,
|
|
26
|
-
canonicalize: () => canonicalize,
|
|
27
|
-
computeHash: () => computeHash
|
|
28
|
-
});
|
|
29
|
-
module.exports = __toCommonJS(index_exports);
|
|
30
|
-
|
|
31
|
-
// src/hash.ts
|
|
32
|
-
var import_crypto = require("crypto");
|
|
33
|
-
function canonicalize(obj) {
|
|
34
|
-
if (obj === null) {
|
|
35
|
-
return "null";
|
|
8
|
+
var PermissionDenied = class extends PermissionProtocolError {
|
|
9
|
+
constructor(message = "Permission was denied.") {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "PermissionDenied";
|
|
36
12
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
13
|
+
};
|
|
14
|
+
var ApprovalTimeout = class extends PermissionProtocolError {
|
|
15
|
+
constructor(message = "Approval request timed out.") {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "ApprovalTimeout";
|
|
42
18
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// src/config.ts
|
|
22
|
+
var DEFAULT_BASE_URL = "https://app.permissionprotocol.com";
|
|
23
|
+
var configuredApiKey;
|
|
24
|
+
var configuredBaseUrl;
|
|
25
|
+
function normalizeBaseUrl(value) {
|
|
26
|
+
return value.replace(/\/+$/, "");
|
|
51
27
|
}
|
|
52
|
-
function
|
|
28
|
+
function configure(apiKey, baseUrl) {
|
|
29
|
+
const resolvedApiKey = apiKey ?? process.env.PP_API_KEY;
|
|
30
|
+
const resolvedBaseUrl = baseUrl ?? process.env.PP_BASE_URL ?? DEFAULT_BASE_URL;
|
|
31
|
+
if (!resolvedApiKey) {
|
|
32
|
+
throw new PermissionProtocolError("Permission Protocol API key is required.");
|
|
33
|
+
}
|
|
34
|
+
configuredApiKey = resolvedApiKey;
|
|
35
|
+
configuredBaseUrl = normalizeBaseUrl(resolvedBaseUrl);
|
|
53
36
|
return {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
input: opts.input,
|
|
57
|
-
metadata: opts.metadata ?? null
|
|
37
|
+
apiKey: configuredApiKey,
|
|
38
|
+
baseUrl: configuredBaseUrl
|
|
58
39
|
};
|
|
59
40
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const receipt = {
|
|
69
|
-
receiptId: `dev_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`,
|
|
70
|
-
tenantId: opts.tenantId,
|
|
71
|
-
agentId: opts.agentId,
|
|
72
|
-
tool: opts.tool,
|
|
73
|
-
operation: opts.operation,
|
|
74
|
-
inputHash,
|
|
75
|
-
decision: "APPROVED",
|
|
76
|
-
reasonCodes: ["DEV_MODE_APPROVAL"],
|
|
77
|
-
approver: "dev_mock",
|
|
78
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
79
|
-
};
|
|
41
|
+
function getConfig() {
|
|
42
|
+
const apiKey = configuredApiKey ?? process.env.PP_API_KEY;
|
|
43
|
+
const baseUrl = configuredBaseUrl ?? process.env.PP_BASE_URL ?? DEFAULT_BASE_URL;
|
|
44
|
+
if (!apiKey) {
|
|
45
|
+
throw new PermissionProtocolError(
|
|
46
|
+
"Permission Protocol API key is not configured. Call configure(apiKey) or set PP_API_KEY."
|
|
47
|
+
);
|
|
48
|
+
}
|
|
80
49
|
return {
|
|
81
|
-
|
|
82
|
-
|
|
50
|
+
apiKey,
|
|
51
|
+
baseUrl: normalizeBaseUrl(baseUrl)
|
|
83
52
|
};
|
|
84
53
|
}
|
|
85
54
|
|
|
86
|
-
// src/
|
|
87
|
-
var
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
this.
|
|
95
|
-
this.
|
|
96
|
-
|
|
55
|
+
// src/receipt.ts
|
|
56
|
+
var Receipt = class {
|
|
57
|
+
constructor(payload) {
|
|
58
|
+
this.payload = { ...payload };
|
|
59
|
+
this.id = payload.id;
|
|
60
|
+
this.status = payload.status;
|
|
61
|
+
this.action = payload.action;
|
|
62
|
+
this.resource = payload.resource;
|
|
63
|
+
this.actor = payload.actor;
|
|
64
|
+
this.approvedBy = payload.approved_by;
|
|
65
|
+
this.policy = payload.policy;
|
|
66
|
+
this.signature = payload.signature;
|
|
67
|
+
this.issuer = payload.issuer;
|
|
68
|
+
this.timestamp = payload.timestamp;
|
|
69
|
+
this.expiresAt = payload.expires_at;
|
|
70
|
+
this.url = payload.url;
|
|
71
|
+
this.isValid = Boolean(payload.valid);
|
|
72
|
+
}
|
|
73
|
+
get valid() {
|
|
74
|
+
return this.isValid;
|
|
75
|
+
}
|
|
76
|
+
json() {
|
|
77
|
+
return { ...this.payload, valid: this.isValid };
|
|
97
78
|
}
|
|
98
79
|
};
|
|
99
80
|
|
|
100
|
-
// src/
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
81
|
+
// src/sdk.ts
|
|
82
|
+
import { hostname } from "os";
|
|
83
|
+
|
|
84
|
+
// src/client.ts
|
|
85
|
+
function createHeaders(apiKey) {
|
|
86
|
+
return {
|
|
87
|
+
"Content-Type": "application/json",
|
|
88
|
+
"X-PP-API-Key": apiKey
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function getErrorMessage(status, fallback, body) {
|
|
92
|
+
if (body && typeof body === "object") {
|
|
93
|
+
const maybeErr = body;
|
|
94
|
+
if (maybeErr.error && typeof maybeErr.error === "string") {
|
|
95
|
+
return maybeErr.error;
|
|
96
|
+
}
|
|
97
|
+
if (maybeErr.message && typeof maybeErr.message === "string") {
|
|
98
|
+
return maybeErr.message;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return `${fallback} (HTTP ${status})`;
|
|
102
|
+
}
|
|
103
|
+
async function postAuthorize(payload) {
|
|
104
|
+
const { apiKey, baseUrl } = getConfig();
|
|
105
|
+
const response = await fetch(`${baseUrl}/api/v1/receipts/verify`, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: createHeaders(apiKey),
|
|
108
|
+
body: JSON.stringify({
|
|
109
|
+
scope: payload,
|
|
110
|
+
failOnMissing: true
|
|
111
|
+
})
|
|
112
|
+
});
|
|
113
|
+
const body = await response.json().catch(() => ({}));
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
throw new PermissionProtocolError(getErrorMessage(response.status, "Authorization failed", body));
|
|
107
116
|
}
|
|
108
|
-
|
|
117
|
+
return body;
|
|
118
|
+
}
|
|
119
|
+
async function getReceipt(receiptId) {
|
|
120
|
+
const { apiKey, baseUrl } = getConfig();
|
|
121
|
+
const response = await fetch(`${baseUrl}/api/v1/receipts/${encodeURIComponent(receiptId)}`, {
|
|
122
|
+
method: "GET",
|
|
123
|
+
headers: createHeaders(apiKey)
|
|
124
|
+
});
|
|
125
|
+
const body = await response.json().catch(() => ({}));
|
|
126
|
+
if (!response.ok) {
|
|
109
127
|
throw new PermissionProtocolError(
|
|
110
|
-
|
|
111
|
-
"Hosted response receipt missing receiptId"
|
|
128
|
+
getErrorMessage(response.status, `Failed to fetch receipt ${receiptId}`, body)
|
|
112
129
|
);
|
|
113
130
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
function mapStatus(status, receipt, result) {
|
|
117
|
-
switch (status) {
|
|
118
|
-
// === APPROVED ===
|
|
119
|
-
case "APPROVED":
|
|
120
|
-
return {
|
|
121
|
-
status: "APPROVED",
|
|
122
|
-
receipt: { ...receipt, decision: "APPROVED" },
|
|
123
|
-
result
|
|
124
|
-
};
|
|
125
|
-
// === REQUIRES_APPROVAL (direct) ===
|
|
126
|
-
case "REQUIRES_APPROVAL":
|
|
127
|
-
return {
|
|
128
|
-
status: "REQUIRES_APPROVAL",
|
|
129
|
-
receipt: { ...receipt, decision: "REQUIRES_APPROVAL" }
|
|
130
|
-
};
|
|
131
|
-
// === REQUIRES_FOUNDER_VETO -> REQUIRES_APPROVAL + reason code ===
|
|
132
|
-
case "REQUIRES_FOUNDER_VETO":
|
|
133
|
-
return {
|
|
134
|
-
status: "REQUIRES_APPROVAL",
|
|
135
|
-
receipt: {
|
|
136
|
-
...receipt,
|
|
137
|
-
decision: "REQUIRES_APPROVAL",
|
|
138
|
-
reasonCodes: ensureReasonCode(receipt.reasonCodes, "REQUIRES_FOUNDER_VETO")
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
// === EXECUTING -> REQUIRES_APPROVAL + reason code ===
|
|
142
|
-
case "EXECUTING":
|
|
143
|
-
return {
|
|
144
|
-
status: "REQUIRES_APPROVAL",
|
|
145
|
-
receipt: {
|
|
146
|
-
...receipt,
|
|
147
|
-
decision: "REQUIRES_APPROVAL",
|
|
148
|
-
reasonCodes: ensureReasonCode(receipt.reasonCodes, "EXECUTING_PENDING_RESULT")
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
// === PENDING_DECISION -> REQUIRES_APPROVAL + reason code ===
|
|
152
|
-
case "PENDING_DECISION":
|
|
153
|
-
return {
|
|
154
|
-
status: "REQUIRES_APPROVAL",
|
|
155
|
-
receipt: {
|
|
156
|
-
...receipt,
|
|
157
|
-
decision: "REQUIRES_APPROVAL",
|
|
158
|
-
reasonCodes: ensureReasonCode(receipt.reasonCodes, "PENDING_DECISION")
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
// === DENIED (direct) ===
|
|
162
|
-
case "DENIED":
|
|
163
|
-
return {
|
|
164
|
-
status: "DENIED",
|
|
165
|
-
receipt: { ...receipt, decision: "DENIED" }
|
|
166
|
-
};
|
|
167
|
-
// === EXPIRED -> DENIED + reason code ===
|
|
168
|
-
case "EXPIRED":
|
|
169
|
-
return {
|
|
170
|
-
status: "DENIED",
|
|
171
|
-
receipt: {
|
|
172
|
-
...receipt,
|
|
173
|
-
decision: "DENIED",
|
|
174
|
-
reasonCodes: ensureReasonCode(receipt.reasonCodes, "APPROVAL_EXPIRED")
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
// === ERROR -> DENIED + reason code ===
|
|
178
|
-
case "ERROR":
|
|
179
|
-
return {
|
|
180
|
-
status: "DENIED",
|
|
181
|
-
receipt: {
|
|
182
|
-
...receipt,
|
|
183
|
-
decision: "DENIED",
|
|
184
|
-
reasonCodes: ensureReasonCode(receipt.reasonCodes, "EXECUTION_ERROR")
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
// === Unknown status -> fail closed ===
|
|
188
|
-
default:
|
|
189
|
-
throw new PermissionProtocolError(
|
|
190
|
-
"EXECUTION_UNAUTHORIZED",
|
|
191
|
-
`Unknown status from Permission Protocol: ${status}`
|
|
192
|
-
);
|
|
131
|
+
if (body && typeof body === "object" && "receipt" in body) {
|
|
132
|
+
return body.receipt;
|
|
193
133
|
}
|
|
134
|
+
return body;
|
|
194
135
|
}
|
|
195
|
-
function
|
|
196
|
-
|
|
197
|
-
|
|
136
|
+
async function postVerify(receiptId) {
|
|
137
|
+
const { apiKey, baseUrl } = getConfig();
|
|
138
|
+
const response = await fetch(`${baseUrl}/api/v1/receipts/verify`, {
|
|
139
|
+
method: "POST",
|
|
140
|
+
headers: createHeaders(apiKey),
|
|
141
|
+
body: JSON.stringify({
|
|
142
|
+
receiptId
|
|
143
|
+
})
|
|
144
|
+
});
|
|
145
|
+
const body = await response.json().catch(() => ({}));
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
throw new PermissionProtocolError(getErrorMessage(response.status, "Verification failed", body));
|
|
198
148
|
}
|
|
199
|
-
return
|
|
149
|
+
return body;
|
|
200
150
|
}
|
|
201
151
|
|
|
202
|
-
// src/
|
|
203
|
-
var
|
|
204
|
-
var
|
|
205
|
-
var
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
152
|
+
// src/sdk.ts
|
|
153
|
+
var DEFAULT_TIMEOUT_SECONDS = 300;
|
|
154
|
+
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
155
|
+
var MAX_POLL_INTERVAL_MS = 1e4;
|
|
156
|
+
function sleep(ms) {
|
|
157
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
158
|
+
}
|
|
159
|
+
function asReceipt(data, fallbackId) {
|
|
160
|
+
if (!data?.id && !fallbackId) {
|
|
161
|
+
throw new PermissionProtocolError("Missing receipt data in API response.");
|
|
162
|
+
}
|
|
163
|
+
return new Receipt({
|
|
164
|
+
id: data?.id ?? fallbackId ?? "",
|
|
165
|
+
status: data?.status ?? "PENDING",
|
|
166
|
+
...data
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
async function authorize(action, resource, actor, metadata, wait = true, timeout = DEFAULT_TIMEOUT_SECONDS) {
|
|
170
|
+
const params = { action, resource, actor, metadata, wait, timeout };
|
|
171
|
+
const resolvedActor = params.actor ?? hostname();
|
|
172
|
+
const response = await postAuthorize({
|
|
173
|
+
action: params.action,
|
|
174
|
+
resource: params.resource,
|
|
175
|
+
actor: resolvedActor,
|
|
176
|
+
metadata: params.metadata
|
|
177
|
+
});
|
|
178
|
+
const receipt = asReceipt(response.receipt, response.requestId);
|
|
179
|
+
if (response.approvalUrl) {
|
|
180
|
+
console.log(`Approval URL: ${response.approvalUrl}`);
|
|
181
|
+
}
|
|
182
|
+
if (!params.wait) {
|
|
183
|
+
return receipt;
|
|
184
|
+
}
|
|
185
|
+
const timeoutMs = Math.max(1, params.timeout ?? DEFAULT_TIMEOUT_SECONDS) * 1e3;
|
|
186
|
+
const deadline = Date.now() + timeoutMs;
|
|
187
|
+
let pollInterval = DEFAULT_POLL_INTERVAL_MS;
|
|
188
|
+
while (Date.now() < deadline) {
|
|
189
|
+
const current = await getReceipt(receipt.id);
|
|
190
|
+
const currentReceipt = asReceipt(current, receipt.id);
|
|
191
|
+
if (currentReceipt.status === "APPROVED") {
|
|
192
|
+
return currentReceipt;
|
|
241
193
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
clearTimeout(timeoutId);
|
|
245
|
-
if (err instanceof PermissionProtocolError) {
|
|
246
|
-
throw err;
|
|
194
|
+
if (currentReceipt.status === "DENIED" || currentReceipt.status === "EXPIRED") {
|
|
195
|
+
throw new PermissionDenied(`Approval request ${receipt.id} ended with status ${currentReceipt.status}.`);
|
|
247
196
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
throw new PermissionProtocolError("EXECUTION_UNAUTHORIZED", message);
|
|
197
|
+
await sleep(pollInterval);
|
|
198
|
+
pollInterval = Math.min(MAX_POLL_INTERVAL_MS, Math.floor(pollInterval * 1.5));
|
|
251
199
|
}
|
|
200
|
+
throw new ApprovalTimeout(
|
|
201
|
+
`Approval request ${receipt.id} was not approved within ${Math.floor(timeoutMs / 1e3)} seconds.`
|
|
202
|
+
);
|
|
252
203
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
* @returns Promise resolving to decision (APPROVED, REQUIRES_APPROVAL, or DENIED) with receipt
|
|
274
|
-
* @throws PermissionProtocolError on network failure, timeout, or invalid response
|
|
275
|
-
*/
|
|
276
|
-
async execute(opts) {
|
|
277
|
-
if (opts.mode === "dev") {
|
|
278
|
-
return devApprovalMock(opts);
|
|
279
|
-
}
|
|
280
|
-
if (!config) {
|
|
281
|
-
throw new PermissionProtocolError(
|
|
282
|
-
"MISCONFIGURED",
|
|
283
|
-
"Permission Protocol client not configured. Call PermissionRouter.configure() first."
|
|
204
|
+
async function verify(receiptId) {
|
|
205
|
+
const result = await postVerify(receiptId);
|
|
206
|
+
const payload = result.receipt ?? { id: receiptId, status: "PENDING" };
|
|
207
|
+
return new Receipt({
|
|
208
|
+
...payload,
|
|
209
|
+
id: payload.id ?? receiptId,
|
|
210
|
+
valid: Boolean(result.valid)
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
function requireApproval(options) {
|
|
214
|
+
return function withApproval(fn) {
|
|
215
|
+
return async (...args) => {
|
|
216
|
+
const action = options.action ?? fn.name ?? "action";
|
|
217
|
+
await authorize(
|
|
218
|
+
action,
|
|
219
|
+
options.resource,
|
|
220
|
+
options.actor,
|
|
221
|
+
options.metadata,
|
|
222
|
+
options.wait ?? true,
|
|
223
|
+
options.timeout ?? DEFAULT_TIMEOUT_SECONDS
|
|
284
224
|
);
|
|
285
|
-
|
|
286
|
-
const hashablePayload = buildHashablePayload(opts);
|
|
287
|
-
const inputHash = computeHash(hashablePayload);
|
|
288
|
-
const body = {
|
|
289
|
-
tenantId: opts.tenantId,
|
|
290
|
-
actor: { agentId: opts.agentId },
|
|
291
|
-
intent: {
|
|
292
|
-
name: `${opts.tool}:${opts.operation}`,
|
|
293
|
-
summary: `${opts.tool} ${opts.operation}`,
|
|
294
|
-
category: opts.tool
|
|
295
|
-
},
|
|
296
|
-
action: {
|
|
297
|
-
tool: opts.tool,
|
|
298
|
-
operation: opts.operation,
|
|
299
|
-
parameters: opts.input
|
|
300
|
-
},
|
|
301
|
-
context: {
|
|
302
|
-
environment: "production",
|
|
303
|
-
reversibility: opts.reversibility ?? "UNKNOWN",
|
|
304
|
-
metadata: opts.metadata
|
|
305
|
-
},
|
|
306
|
-
hashes: { inputHash }
|
|
225
|
+
return fn(...args);
|
|
307
226
|
};
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
sdkVersion: config.sdkVersion
|
|
315
|
-
},
|
|
316
|
-
body,
|
|
317
|
-
{
|
|
318
|
-
tenantId: opts.tenantId,
|
|
319
|
-
agentId: opts.agentId
|
|
320
|
-
}
|
|
321
|
-
);
|
|
322
|
-
const result = mapHostedResponse(hosted, opts);
|
|
323
|
-
if (config.verifyReceipt) {
|
|
324
|
-
const valid = await config.verifyReceipt(result.receipt);
|
|
325
|
-
if (!valid) {
|
|
326
|
-
throw new PermissionProtocolError(
|
|
327
|
-
"INVALID_RECEIPT",
|
|
328
|
-
"Receipt verification failed"
|
|
329
|
-
);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
return result;
|
|
333
|
-
},
|
|
334
|
-
/**
|
|
335
|
-
* Check if the client is configured.
|
|
336
|
-
* Useful for testing and debugging.
|
|
337
|
-
*/
|
|
338
|
-
isConfigured() {
|
|
339
|
-
return config !== null;
|
|
340
|
-
},
|
|
341
|
-
/**
|
|
342
|
-
* Reset configuration (for testing).
|
|
343
|
-
* @internal
|
|
344
|
-
*/
|
|
345
|
-
_reset() {
|
|
346
|
-
config = null;
|
|
347
|
-
}
|
|
348
|
-
};
|
|
349
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
350
|
-
0 && (module.exports = {
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
export {
|
|
230
|
+
ApprovalTimeout,
|
|
231
|
+
DEFAULT_BASE_URL,
|
|
232
|
+
PermissionDenied,
|
|
351
233
|
PermissionProtocolError,
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
234
|
+
Receipt,
|
|
235
|
+
authorize,
|
|
236
|
+
configure,
|
|
237
|
+
requireApproval,
|
|
238
|
+
verify
|
|
239
|
+
};
|
package/package.json
CHANGED
|
@@ -1,52 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@permission-protocol/sdk",
|
|
3
|
-
"version": "0.1.0
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official JavaScript/TypeScript SDK for Permission Protocol",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Permission Protocol",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"main": "./dist/index.cjs",
|
|
12
|
+
"module": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
8
14
|
"exports": {
|
|
9
15
|
".": {
|
|
10
16
|
"types": "./dist/index.d.ts",
|
|
11
|
-
"import": "./dist/index.
|
|
12
|
-
"require": "./dist/index.
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"require": "./dist/index.cjs"
|
|
13
19
|
}
|
|
14
20
|
},
|
|
15
21
|
"files": [
|
|
16
22
|
"dist",
|
|
17
|
-
"README.md"
|
|
18
|
-
|
|
19
|
-
"license": "Apache-2.0",
|
|
20
|
-
"homepage": "https://github.com/permission-protocol/permission-protocol",
|
|
21
|
-
"repository": {
|
|
22
|
-
"type": "git",
|
|
23
|
-
"url": "https://github.com/permission-protocol/permission-protocol"
|
|
24
|
-
},
|
|
25
|
-
"keywords": [
|
|
26
|
-
"ai",
|
|
27
|
-
"agents",
|
|
28
|
-
"authorization",
|
|
29
|
-
"receipts",
|
|
30
|
-
"audit",
|
|
31
|
-
"human-in-the-loop",
|
|
32
|
-
"ci",
|
|
33
|
-
"governance"
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
34
25
|
],
|
|
26
|
+
"sideEffects": false,
|
|
35
27
|
"engines": {
|
|
36
28
|
"node": ">=18"
|
|
37
29
|
},
|
|
38
30
|
"scripts": {
|
|
39
|
-
"build": "tsup src/index.ts --format cjs,esm --
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"test:golden": "vitest run -t 'HashablePayload v1 conformance'",
|
|
43
|
-
"lint": "eslint src --ext .ts",
|
|
44
|
-
"prepublishOnly": "npm run build"
|
|
31
|
+
"build": "tsup src/index.ts --dts --format cjs,esm --clean",
|
|
32
|
+
"typecheck": "tsc --noEmit",
|
|
33
|
+
"prepublishOnly": "npm run typecheck && npm run build"
|
|
45
34
|
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"permission",
|
|
37
|
+
"authorization",
|
|
38
|
+
"approval",
|
|
39
|
+
"sdk",
|
|
40
|
+
"typescript"
|
|
41
|
+
],
|
|
46
42
|
"devDependencies": {
|
|
47
|
-
"@types/node": "^
|
|
48
|
-
"tsup": "^8.
|
|
49
|
-
"typescript": "^5.
|
|
50
|
-
"vitest": "^1.0.0"
|
|
43
|
+
"@types/node": "^25.3.3",
|
|
44
|
+
"tsup": "^8.2.4",
|
|
45
|
+
"typescript": "^5.6.3"
|
|
51
46
|
}
|
|
52
|
-
}
|
|
47
|
+
}
|