@opengeni/sdk 3.1.0 → 3.1.2
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/README.md +1037 -71
- package/dist/accounts.d.ts +5 -1
- package/dist/accounts.js +13 -1
- package/dist/accounts.js.map +1 -1
- package/dist/adapters/express.d.ts +31 -0
- package/dist/adapters/express.js +87 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/hono.d.ts +16 -0
- package/dist/adapters/hono.js +8 -0
- package/dist/adapters/hono.js.map +1 -0
- package/dist/adapters/next.d.ts +29 -0
- package/dist/adapters/next.js +22 -0
- package/dist/adapters/next.js.map +1 -0
- package/dist/allowance-refusal.d.ts +2 -0
- package/dist/allowance-refusal.js +50 -0
- package/dist/allowance-refusal.js.map +1 -0
- package/dist/app-links.d.ts +42 -0
- package/dist/app-links.js +66 -0
- package/dist/app-links.js.map +1 -0
- package/dist/artifact-catalog.d.ts +40 -0
- package/dist/artifact-client.d.ts +20 -8
- package/dist/artifacts.d.ts +1 -1
- package/dist/artifacts.js +8 -6
- package/dist/automations.js +8 -2
- package/dist/automations.js.map +1 -1
- package/dist/azure-live-transport.d.ts +32 -0
- package/dist/browser.d.ts +7 -2
- package/dist/browser.js +27 -5
- package/dist/chat/fold.d.ts +75 -0
- package/dist/chat/handler.d.ts +41 -0
- package/dist/chat/http.d.ts +67 -0
- package/dist/chat/ids.d.ts +34 -0
- package/dist/chat/index.d.ts +9 -0
- package/dist/chat/index.js +1703 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/openai.d.ts +30 -0
- package/dist/chat/opengeni.d.ts +129 -0
- package/dist/chat/types.d.ts +207 -0
- package/dist/chat/vercel.d.ts +49 -0
- package/dist/chats.d.ts +8 -0
- package/dist/chunk-4AHR4KGA.js +301 -0
- package/dist/chunk-4AHR4KGA.js.map +1 -0
- package/dist/chunk-6HZGAIUE.js +1665 -0
- package/dist/chunk-6HZGAIUE.js.map +1 -0
- package/dist/chunk-7EWT3PV6.js +368 -0
- package/dist/chunk-7EWT3PV6.js.map +1 -0
- package/dist/{chunk-VYCTL62C.js → chunk-GZQSWAKD.js} +1 -1
- package/dist/chunk-GZQSWAKD.js.map +1 -0
- package/dist/chunk-JXXCTW5W.js +1392 -0
- package/dist/chunk-JXXCTW5W.js.map +1 -0
- package/dist/{chunk-YTAWBDO2.js → chunk-KADZ5PGG.js} +28 -2
- package/dist/chunk-KADZ5PGG.js.map +1 -0
- package/dist/{chunk-YKZME56C.js → chunk-KWADQ227.js} +3 -3
- package/dist/{chunk-YKZME56C.js.map → chunk-KWADQ227.js.map} +1 -1
- package/dist/{chunk-7ZXBPJZP.js → chunk-NEM5N6C6.js} +3902 -1457
- package/dist/chunk-NEM5N6C6.js.map +1 -0
- package/dist/{chunk-GW3EJ2GP.js → chunk-O7KANXC3.js} +86 -13
- package/dist/chunk-O7KANXC3.js.map +1 -0
- package/dist/{chunk-VUQZAB3O.js → chunk-OAKHWFSV.js} +28 -32
- package/dist/chunk-OAKHWFSV.js.map +1 -0
- package/dist/chunk-P7UWKORG.js +561 -0
- package/dist/chunk-P7UWKORG.js.map +1 -0
- package/dist/chunk-QGEIL4TR.js +195 -0
- package/dist/chunk-QGEIL4TR.js.map +1 -0
- package/dist/chunk-RJHCBZF7.js +270 -0
- package/dist/chunk-RJHCBZF7.js.map +1 -0
- package/dist/chunk-S3D75WSQ.js +340 -0
- package/dist/chunk-S3D75WSQ.js.map +1 -0
- package/dist/chunk-UM4ZXXJR.js +9 -0
- package/dist/chunk-UM4ZXXJR.js.map +1 -0
- package/dist/chunk-VPVMLM7Q.js +15 -0
- package/dist/chunk-VPVMLM7Q.js.map +1 -0
- package/dist/{chunk-C2H7HBNP.js → chunk-WVCJRSGJ.js} +119 -14
- package/dist/chunk-WVCJRSGJ.js.map +1 -0
- package/dist/chunk-XA7HVIHI.js +126 -0
- package/dist/chunk-XA7HVIHI.js.map +1 -0
- package/dist/{chunk-TX3EIENU.js → chunk-YDVPI7WT.js} +73 -2
- package/dist/chunk-YDVPI7WT.js.map +1 -0
- package/dist/chunk-YKIHNLWD.js +153 -0
- package/dist/chunk-YKIHNLWD.js.map +1 -0
- package/dist/chunk-ZDUBPV33.js +277 -0
- package/dist/chunk-ZDUBPV33.js.map +1 -0
- package/dist/client.d.ts +1065 -124
- package/dist/codex-realtime-controller.d.ts +13 -0
- package/dist/codex-realtime-controller.js +4 -2
- package/dist/codex-realtime-v3-wire.d.ts +3 -2
- package/dist/codex-realtime.d.ts +5 -1
- package/dist/company-brain.d.ts +1 -11
- package/dist/company-profile.d.ts +13 -0
- package/dist/core.d.ts +7 -2
- package/dist/core.js +25 -6
- package/dist/deprecation.d.ts +47 -0
- package/dist/document-authority-client.d.ts +24 -2
- package/dist/document-authority.js +7 -5
- package/dist/editable-artifacts/index.d.ts +1 -1
- package/dist/editable-artifacts/types.d.ts +12 -2
- package/dist/editable-artifacts.js +19 -3
- package/dist/editable-artifacts.js.map +1 -1
- package/dist/embedding-client.d.ts +129 -0
- package/dist/errors.d.ts +76 -1
- package/dist/feedback.d.ts +23 -0
- package/dist/gateway-realtime-transport.js +1 -1
- package/dist/github-repositories.d.ts +10 -0
- package/dist/github-repositories.js +36 -0
- package/dist/github-repositories.js.map +1 -0
- package/dist/index.d.ts +64 -11
- package/dist/index.js +566 -141
- package/dist/index.js.map +1 -1
- package/dist/insights-usage.d.ts +33 -0
- package/dist/insights-usage.js +7 -0
- package/dist/insights-usage.js.map +1 -0
- package/dist/interaction.d.ts +103 -71
- package/dist/interaction.js +4 -2
- package/dist/knowledge.d.ts +7 -0
- package/dist/knowledge.js +20 -0
- package/dist/knowledge.js.map +1 -0
- package/dist/known-tools.d.ts +4 -0
- package/dist/message-links.d.ts +68 -0
- package/dist/model-context.d.ts +68 -0
- package/dist/model-display.d.ts +2 -0
- package/dist/model-display.js +17 -0
- package/dist/model-display.js.map +1 -0
- package/dist/model-picker-order.d.ts +1 -0
- package/dist/model-picker-order.js +10 -0
- package/dist/model-picker-order.js.map +1 -0
- package/dist/organization-integration-policy.d.ts +26 -0
- package/dist/organization-integration-policy.js +26 -0
- package/dist/organization-integration-policy.js.map +1 -0
- package/dist/pr-review-client.d.ts +1 -1
- package/dist/pr-review.d.ts +1 -1
- package/dist/pr-review.js.map +1 -1
- package/dist/preference-registry.d.ts +1 -1
- package/dist/prepared-mcp-setup.d.ts +5 -0
- package/dist/proxy.d.ts +13 -11
- package/dist/realtime.d.ts +4 -2
- package/dist/realtime.js +253 -7
- package/dist/realtime.js.map +1 -1
- package/dist/session-history-import.d.ts +22 -0
- package/dist/session-history-import.js +36 -0
- package/dist/session-history-import.js.map +1 -0
- package/dist/session-list-entries.d.ts +1 -0
- package/dist/session-list-entries.js +7 -0
- package/dist/session-list-entries.js.map +1 -0
- package/dist/session-message-search.d.ts +53 -0
- package/dist/session-proxy-client.d.ts +28 -0
- package/dist/session-proxy.d.ts +334 -0
- package/dist/session-proxy.js +24 -0
- package/dist/session-proxy.js.map +1 -0
- package/dist/session-titles.d.ts +2 -0
- package/dist/session-usage-limits.d.ts +10 -0
- package/dist/session-usage-limits.js +43 -0
- package/dist/session-usage-limits.js.map +1 -0
- package/dist/shared-catalog-loader.d.ts +34 -0
- package/dist/site-bridge-host.d.ts +112 -0
- package/dist/site-bridge-host.js +285 -0
- package/dist/site-bridge-host.js.map +1 -0
- package/dist/site-browser-entry.d.ts +1 -0
- package/dist/site-browser-runtime.gen.d.ts +1 -0
- package/dist/site-data.d.ts +178 -0
- package/dist/site-document.d.ts +5 -0
- package/dist/site-document.js +20 -0
- package/dist/site-document.js.map +1 -0
- package/dist/site-document.test.d.ts +1 -0
- package/dist/site-http.d.ts +17 -0
- package/dist/site-sql.d.ts +31 -0
- package/dist/site-tool-bridge.d.ts +57 -0
- package/dist/site.d.ts +182 -0
- package/dist/site.js +62 -0
- package/dist/site.js.map +1 -0
- package/dist/skills.d.ts +75 -0
- package/dist/sse.d.ts +1 -1
- package/dist/stream.d.ts +2 -0
- package/dist/tenant-workspaces.d.ts +47 -0
- package/dist/tenant-workspaces.js +8 -0
- package/dist/tenant-workspaces.js.map +1 -0
- package/dist/tool-auth.d.ts +87 -0
- package/dist/tool-auth.js +23 -0
- package/dist/tool-auth.js.map +1 -0
- package/dist/tool-display-metadata.d.ts +3 -0
- package/dist/tools-37DCTCNZ.js +12 -0
- package/dist/tools-37DCTCNZ.js.map +1 -0
- package/dist/tools.d.ts +81 -0
- package/dist/transcription.d.ts +1 -1
- package/dist/types.d.ts +2848 -573
- package/dist/usage-allowances.d.ts +36 -0
- package/dist/usage-allowances.js +80 -0
- package/dist/usage-allowances.js.map +1 -0
- package/dist/vault-types.d.ts +236 -0
- package/dist/vaults-api.d.ts +57 -0
- package/dist/workspace-artifacts.d.ts +47 -5
- package/dist/workspace-instruction-policies.d.ts +2 -2
- package/dist/workspace-integrations.d.ts +74 -0
- package/dist/workspace-integrations.js +65 -0
- package/dist/workspace-integrations.js.map +1 -0
- package/dist/workspace-state.d.ts +8 -71
- package/package.json +99 -5
- package/src/accounts.ts +18 -0
- package/src/adapters/express.ts +136 -0
- package/src/adapters/hono.ts +18 -0
- package/src/adapters/next.ts +42 -0
- package/src/allowance-refusal.ts +5 -0
- package/src/app-links.ts +117 -0
- package/src/artifact-catalog.ts +51 -0
- package/src/artifact-client.ts +40 -49
- package/src/artifacts.ts +1 -0
- package/src/automations-client.ts +8 -2
- package/src/azure-live-transport.ts +286 -0
- package/src/browser.ts +37 -0
- package/src/chat/fold.ts +431 -0
- package/src/chat/handler.ts +240 -0
- package/src/chat/http.ts +257 -0
- package/src/chat/ids.ts +85 -0
- package/src/chat/index.ts +88 -0
- package/src/chat/openai.ts +439 -0
- package/src/chat/opengeni.ts +737 -0
- package/src/chat/types.ts +219 -0
- package/src/chat/vercel.ts +204 -0
- package/src/chats.ts +16 -0
- package/src/client.ts +5822 -1847
- package/src/codex-realtime-controller.ts +163 -8
- package/src/codex-realtime-v3-wire.ts +4 -3
- package/src/codex-realtime-v3.ts +12 -3
- package/src/codex-realtime.ts +11 -3
- package/src/company-brain.ts +0 -40
- package/src/company-profile.ts +13 -0
- package/src/core.ts +20 -0
- package/src/deprecation.ts +149 -0
- package/src/document-authority-client.ts +104 -1
- package/src/editable-artifacts/controller.ts +36 -2
- package/src/editable-artifacts/index.ts +1 -0
- package/src/editable-artifacts/types.ts +29 -16
- package/src/embedding-client.ts +519 -0
- package/src/errors.ts +303 -4
- package/src/feedback.ts +20 -0
- package/src/gateway-realtime-transport.ts +3 -3
- package/src/github-repositories.ts +60 -0
- package/src/index.ts +611 -64
- package/src/insights-usage.ts +61 -0
- package/src/interaction.ts +274 -93
- package/src/knowledge.ts +72 -0
- package/src/known-tools.ts +279 -0
- package/src/message-links.ts +178 -0
- package/src/model-context.ts +113 -0
- package/src/model-display.ts +11 -0
- package/src/model-picker-order.ts +6 -0
- package/src/organization-integration-policy.ts +54 -0
- package/src/pr-review-client.ts +1 -1
- package/src/pr-review.ts +1 -1
- package/src/preference-registry.ts +2 -0
- package/src/prepared-mcp-setup.ts +123 -0
- package/src/proxy.ts +23 -12
- package/src/realtime.ts +16 -6
- package/src/session-history-import.ts +84 -0
- package/src/session-list-entries.ts +1 -0
- package/src/session-message-search.ts +47 -0
- package/src/session-proxy-client.ts +68 -0
- package/src/session-proxy.ts +2098 -0
- package/src/session-titles.ts +10 -0
- package/src/session-usage-limits.ts +71 -0
- package/src/shared-catalog-loader.ts +169 -0
- package/src/site-bridge-host.ts +422 -0
- package/src/site-browser-entry.ts +6 -0
- package/src/site-browser-runtime.gen.ts +2 -0
- package/src/site-data.ts +372 -0
- package/src/site-document.test.ts +64 -0
- package/src/site-document.ts +18 -0
- package/src/site-http.ts +171 -0
- package/src/site-sql.ts +153 -0
- package/src/site-tool-bridge.ts +401 -0
- package/src/site.ts +867 -0
- package/src/skills.ts +69 -0
- package/src/sse.ts +9 -3
- package/src/stream.ts +33 -10
- package/src/tenant-workspaces.ts +148 -0
- package/src/tool-auth.ts +301 -0
- package/src/tool-display-metadata.ts +27 -0
- package/src/tools.ts +452 -0
- package/src/transcription.ts +3 -0
- package/src/types.ts +3216 -581
- package/src/usage-allowances.ts +189 -0
- package/src/vault-types.ts +293 -0
- package/src/vaults-api.ts +288 -0
- package/src/workspace-artifacts.ts +55 -6
- package/src/workspace-instruction-policies.ts +2 -1
- package/src/workspace-integrations.ts +402 -0
- package/src/workspace-state.ts +8 -82
- package/dist/chunk-7ZXBPJZP.js.map +0 -1
- package/dist/chunk-C2H7HBNP.js.map +0 -1
- package/dist/chunk-C4DJPZRU.js +0 -119
- package/dist/chunk-C4DJPZRU.js.map +0 -1
- package/dist/chunk-GW3EJ2GP.js.map +0 -1
- package/dist/chunk-TX3EIENU.js.map +0 -1
- package/dist/chunk-VUQZAB3O.js.map +0 -1
- package/dist/chunk-VYCTL62C.js.map +0 -1
- package/dist/chunk-YTAWBDO2.js.map +0 -1
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// src/tool-auth.ts
|
|
2
|
+
var TOOL_TOKEN_ISSUER = "opengeni-session-proxy";
|
|
3
|
+
var TOOL_TOKEN_KEY_LABEL = "opengeni-tool-token:v1";
|
|
4
|
+
var TOOL_TOKEN_DEFAULT_TTL_SECONDS = 24 * 60 * 60;
|
|
5
|
+
var MAX_TTL_SECONDS = 7 * 24 * 60 * 60;
|
|
6
|
+
var MAX_HEADER_VALUE_LENGTH = 4096;
|
|
7
|
+
var TOOL_SERVER_URL_ENV = "OPENGENI_TOOL_SERVER_URL";
|
|
8
|
+
var CLOCK_SKEW_SECONDS = 60;
|
|
9
|
+
var ToolRequestError = class extends Error {
|
|
10
|
+
constructor(code) {
|
|
11
|
+
super("Tool request is not authorized.");
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.name = "ToolRequestError";
|
|
14
|
+
}
|
|
15
|
+
status = 401;
|
|
16
|
+
/** A ready 401 response with a `WWW-Authenticate: Bearer` challenge. */
|
|
17
|
+
toResponse() {
|
|
18
|
+
return new Response(JSON.stringify({ error: { code: this.code, message: this.message } }), {
|
|
19
|
+
status: 401,
|
|
20
|
+
headers: {
|
|
21
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
22
|
+
"WWW-Authenticate": 'Bearer error="invalid_token"'
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
async function verifyToolRequest(request, options = {}) {
|
|
28
|
+
const key = await signingKey(resolveToolTokenSecret(options.secret));
|
|
29
|
+
const audience = options.audience ?? environment(TOOL_SERVER_URL_ENV);
|
|
30
|
+
if (!audience) {
|
|
31
|
+
throw new TypeError(
|
|
32
|
+
`verifyToolRequest needs the tool server URL: pass { audience } or set ${TOOL_SERVER_URL_ENV}.`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
const authorization = requestAuthorization(request);
|
|
36
|
+
const match = /^Bearer[ ]+([A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)$/i.exec(
|
|
37
|
+
authorization?.trim() ?? ""
|
|
38
|
+
);
|
|
39
|
+
if (!match) throw new ToolRequestError("token_missing");
|
|
40
|
+
const [header, payload, signature] = match[1].split(".");
|
|
41
|
+
let protectedHeader;
|
|
42
|
+
let claims;
|
|
43
|
+
let signatureBytes;
|
|
44
|
+
try {
|
|
45
|
+
signatureBytes = base64UrlDecode(signature);
|
|
46
|
+
protectedHeader = JSON.parse(utf8(base64UrlDecode(header)));
|
|
47
|
+
claims = JSON.parse(utf8(base64UrlDecode(payload)));
|
|
48
|
+
} catch {
|
|
49
|
+
throw new ToolRequestError("token_malformed");
|
|
50
|
+
}
|
|
51
|
+
if (!protectedHeader || typeof protectedHeader !== "object" || protectedHeader.alg !== "HS256" || !claims || typeof claims !== "object" || Array.isArray(claims)) {
|
|
52
|
+
throw new ToolRequestError("token_malformed");
|
|
53
|
+
}
|
|
54
|
+
const valid = await crypto.subtle.verify(
|
|
55
|
+
"HMAC",
|
|
56
|
+
key,
|
|
57
|
+
signatureBytes,
|
|
58
|
+
new TextEncoder().encode(`${header}.${payload}`)
|
|
59
|
+
);
|
|
60
|
+
if (!valid) throw new ToolRequestError("token_invalid");
|
|
61
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
62
|
+
const { iss, aud, sub, exp, iat, workspace_id, source, tenant } = claims;
|
|
63
|
+
if (iss !== TOOL_TOKEN_ISSUER) throw new ToolRequestError("token_invalid");
|
|
64
|
+
if (typeof exp !== "number" || exp <= now) throw new ToolRequestError("token_expired");
|
|
65
|
+
if (typeof iat !== "number" || iat > now + CLOCK_SKEW_SECONDS) {
|
|
66
|
+
throw new ToolRequestError("token_invalid");
|
|
67
|
+
}
|
|
68
|
+
if (aud !== audience) {
|
|
69
|
+
throw new ToolRequestError("token_audience");
|
|
70
|
+
}
|
|
71
|
+
if (typeof sub !== "string" || !sub || typeof workspace_id !== "string" || !workspace_id || typeof source !== "string" || tenant !== void 0 && typeof tenant !== "string") {
|
|
72
|
+
throw new ToolRequestError("token_invalid");
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
user: sub,
|
|
76
|
+
...tenant !== void 0 ? { tenant } : {},
|
|
77
|
+
workspaceId: workspace_id,
|
|
78
|
+
source,
|
|
79
|
+
expiresAt: new Date(exp * 1e3)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async function mintToolToken(input) {
|
|
83
|
+
const ttl = input.ttlSeconds ?? TOOL_TOKEN_DEFAULT_TTL_SECONDS;
|
|
84
|
+
if (!Number.isSafeInteger(ttl) || ttl < 1 || ttl > MAX_TTL_SECONDS) {
|
|
85
|
+
throw new TypeError(`ttlSeconds must be an integer from 1 to ${MAX_TTL_SECONDS}.`);
|
|
86
|
+
}
|
|
87
|
+
const key = await signingKey(resolveToolTokenSecret(input.secret));
|
|
88
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
89
|
+
const header = base64UrlJson({ alg: "HS256", typ: "JWT" });
|
|
90
|
+
const payload = base64UrlJson({
|
|
91
|
+
iss: TOOL_TOKEN_ISSUER,
|
|
92
|
+
aud: input.audience,
|
|
93
|
+
sub: input.user,
|
|
94
|
+
workspace_id: input.workspaceId,
|
|
95
|
+
source: input.source,
|
|
96
|
+
...input.tenant !== void 0 ? { tenant: input.tenant } : {},
|
|
97
|
+
iat: now,
|
|
98
|
+
exp: now + ttl
|
|
99
|
+
});
|
|
100
|
+
const signature = await crypto.subtle.sign(
|
|
101
|
+
"HMAC",
|
|
102
|
+
key,
|
|
103
|
+
new TextEncoder().encode(`${header}.${payload}`)
|
|
104
|
+
);
|
|
105
|
+
const token = `${header}.${payload}.${base64UrlEncode(new Uint8Array(signature))}`;
|
|
106
|
+
if (`Bearer ${token}`.length > MAX_HEADER_VALUE_LENGTH) {
|
|
107
|
+
throw new TypeError(
|
|
108
|
+
`Tool token exceeds Opengeni's ${MAX_HEADER_VALUE_LENGTH}-character header limit; shorten the user, tenant, or URL.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return token;
|
|
112
|
+
}
|
|
113
|
+
async function deriveToolTokenKey(secret) {
|
|
114
|
+
return [...await derivedKeyBytes(resolveToolTokenSecret(secret))].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
115
|
+
}
|
|
116
|
+
function resolveToolTokenSecret(secret) {
|
|
117
|
+
const resolved = secret ?? environment("OPENGENI_API_KEY");
|
|
118
|
+
if (!resolved) {
|
|
119
|
+
throw new TypeError(
|
|
120
|
+
"Tool tokens need a signing secret: set OPENGENI_API_KEY, or pass the same `secret` to the session proxy's toolServer and verifyToolRequest."
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return resolved;
|
|
124
|
+
}
|
|
125
|
+
function environment(name) {
|
|
126
|
+
return globalThis.process?.env?.[name] || void 0;
|
|
127
|
+
}
|
|
128
|
+
async function derivedKeyBytes(secret) {
|
|
129
|
+
const root = await crypto.subtle.importKey(
|
|
130
|
+
"raw",
|
|
131
|
+
new TextEncoder().encode(secret),
|
|
132
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
133
|
+
false,
|
|
134
|
+
["sign"]
|
|
135
|
+
);
|
|
136
|
+
return new Uint8Array(
|
|
137
|
+
await crypto.subtle.sign("HMAC", root, new TextEncoder().encode(TOOL_TOKEN_KEY_LABEL))
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
var keys = /* @__PURE__ */ new Map();
|
|
141
|
+
function signingKey(secret) {
|
|
142
|
+
let key = keys.get(secret);
|
|
143
|
+
if (!key) {
|
|
144
|
+
key = (async () => await crypto.subtle.importKey(
|
|
145
|
+
"raw",
|
|
146
|
+
await derivedKeyBytes(secret),
|
|
147
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
148
|
+
false,
|
|
149
|
+
["sign", "verify"]
|
|
150
|
+
))();
|
|
151
|
+
key.catch(() => keys.delete(secret));
|
|
152
|
+
if (keys.size >= 16) keys.delete(keys.keys().next().value);
|
|
153
|
+
keys.set(secret, key);
|
|
154
|
+
}
|
|
155
|
+
return key;
|
|
156
|
+
}
|
|
157
|
+
function requestAuthorization(request) {
|
|
158
|
+
if (typeof Request !== "undefined" && request instanceof Request) {
|
|
159
|
+
return request.headers.get("authorization") ?? void 0;
|
|
160
|
+
}
|
|
161
|
+
const headers = request.headers;
|
|
162
|
+
const raw = headers && typeof headers.get === "function" ? headers.get("authorization") ?? void 0 : headers?.authorization;
|
|
163
|
+
return Array.isArray(raw) ? void 0 : raw;
|
|
164
|
+
}
|
|
165
|
+
function base64UrlJson(value) {
|
|
166
|
+
return base64UrlEncode(new TextEncoder().encode(JSON.stringify(value)));
|
|
167
|
+
}
|
|
168
|
+
function base64UrlEncode(bytes) {
|
|
169
|
+
let binary = "";
|
|
170
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
171
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
172
|
+
}
|
|
173
|
+
function base64UrlDecode(value) {
|
|
174
|
+
const base64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
175
|
+
const binary = atob(base64 + "=".repeat((4 - base64.length % 4) % 4));
|
|
176
|
+
const bytes = new Uint8Array(binary.length);
|
|
177
|
+
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
178
|
+
return bytes;
|
|
179
|
+
}
|
|
180
|
+
function utf8(bytes) {
|
|
181
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export {
|
|
185
|
+
TOOL_TOKEN_ISSUER,
|
|
186
|
+
TOOL_TOKEN_KEY_LABEL,
|
|
187
|
+
TOOL_TOKEN_DEFAULT_TTL_SECONDS,
|
|
188
|
+
TOOL_SERVER_URL_ENV,
|
|
189
|
+
ToolRequestError,
|
|
190
|
+
verifyToolRequest,
|
|
191
|
+
mintToolToken,
|
|
192
|
+
deriveToolTokenKey,
|
|
193
|
+
resolveToolTokenSecret
|
|
194
|
+
};
|
|
195
|
+
//# sourceMappingURL=chunk-QGEIL4TR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tool-auth.ts"],"sourcesContent":["/**\n * Per-user credentials for a product's own MCP tool server.\n *\n * `createSessionProxyHandler({ toolServer })` mints a short-lived token for the\n * user its `resolve` hook authenticated, attaches it to each session it creates,\n * and refreshes it on every message, approval, and answer. The product's MCP\n * endpoint calls {@link verifyToolRequest} on every request and scopes all data\n * access to the returned identity, never to ids the model supplied.\n *\n * Wire format (for non-Node verifiers): an HS256 JWT in `Authorization: Bearer`,\n * signed with the hex key from {@link deriveToolTokenKey} (`HMAC-SHA256(key =\n * secret, message = \"opengeni-tool-token:v1\")`, where `secret` is\n * `OPENGENI_API_KEY` unless configured). Give a non-Node verifier that derived\n * key, never the organization key. Claims: `iss` = `\"opengeni-session-proxy\"`,\n * `aud` = the tool server URL, `sub` = the external user id, `workspace_id`,\n * `source`, optional `tenant`, `iat`, `exp`.\n */\n\n/** `iss` of every tool token. */\nexport const TOOL_TOKEN_ISSUER = \"opengeni-session-proxy\";\n/** HMAC message used to derive the signing key from the secret. */\nexport const TOOL_TOKEN_KEY_LABEL = \"opengeni-tool-token:v1\";\n/** Default token lifetime: 24 hours, refreshed on every message, approval, and answer. */\nexport const TOOL_TOKEN_DEFAULT_TTL_SECONDS = 24 * 60 * 60;\nconst MAX_TTL_SECONDS = 7 * 24 * 60 * 60;\n/** Opengeni's per-value limit for session MCP credential headers. */\nconst MAX_HEADER_VALUE_LENGTH = 4096;\n/** Default `toolServer.url` and `verifyToolRequest` audience. */\nexport const TOOL_SERVER_URL_ENV = \"OPENGENI_TOOL_SERVER_URL\";\nconst CLOCK_SKEW_SECONDS = 60;\n\n/** The user a verified tool request acts for. */\nexport type ToolRequestIdentity = {\n /** External user id the session proxy's `resolve` hook authenticated. */\n user: string;\n /** Tenant from `resolve`, when it returned one. */\n tenant?: string | undefined;\n workspaceId: string;\n /** External identity source (same as the proxy's `asUser` source). */\n source: string;\n expiresAt: Date;\n};\n\nexport type VerifyToolRequestOptions = {\n /** Signing secret. Defaults to `OPENGENI_API_KEY`; must match the proxy's. */\n secret?: string | undefined;\n /**\n * Exact tool server URL the token must be issued for (the proxy's\n * `toolServer.url`). Defaults to `OPENGENI_TOOL_SERVER_URL`.\n */\n audience?: string | undefined;\n};\n\n/** A Web `Request`, or a Node/Express request (`headers` plus `originalUrl`/`url`). */\nexport type ToolRequestLike =\n | Request\n | {\n headers: Record<string, string | string[] | undefined>;\n originalUrl?: string | undefined;\n url?: string | undefined;\n };\n\n/** Missing, expired, forged, or misdirected tool token. Respond with `status` (401). */\nexport class ToolRequestError extends Error {\n readonly status = 401;\n constructor(readonly code: string) {\n super(\"Tool request is not authorized.\");\n this.name = \"ToolRequestError\";\n }\n /** A ready 401 response with a `WWW-Authenticate: Bearer` challenge. */\n toResponse(): Response {\n return new Response(JSON.stringify({ error: { code: this.code, message: this.message } }), {\n status: 401,\n headers: {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"WWW-Authenticate\": 'Bearer error=\"invalid_token\"',\n },\n });\n }\n}\n\n/**\n * Verify the tool token on one MCP request and return who it acts for.\n * Throws {@link ToolRequestError} (401) for every invalid token. Call it on\n * every request, before any tool runs.\n *\n * ```ts\n * const user = await verifyToolRequest(request); // { user, tenant, workspaceId }\n * ```\n */\nexport async function verifyToolRequest(\n request: ToolRequestLike,\n options: VerifyToolRequestOptions = {},\n): Promise<ToolRequestIdentity> {\n const key = await signingKey(resolveToolTokenSecret(options.secret));\n const audience = options.audience ?? environment(TOOL_SERVER_URL_ENV);\n if (!audience) {\n throw new TypeError(\n `verifyToolRequest needs the tool server URL: pass { audience } or set ${TOOL_SERVER_URL_ENV}.`,\n );\n }\n const authorization = requestAuthorization(request);\n const match = /^Bearer[ ]+([A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+)$/i.exec(\n authorization?.trim() ?? \"\",\n );\n if (!match) throw new ToolRequestError(\"token_missing\");\n const [header, payload, signature] = match[1]!.split(\".\") as [string, string, string];\n let protectedHeader: unknown;\n let claims: Record<string, unknown>;\n let signatureBytes: Uint8Array<ArrayBuffer>;\n try {\n signatureBytes = base64UrlDecode(signature);\n protectedHeader = JSON.parse(utf8(base64UrlDecode(header)));\n claims = JSON.parse(utf8(base64UrlDecode(payload)));\n } catch {\n throw new ToolRequestError(\"token_malformed\");\n }\n if (\n !protectedHeader ||\n typeof protectedHeader !== \"object\" ||\n (protectedHeader as { alg?: unknown }).alg !== \"HS256\" ||\n !claims ||\n typeof claims !== \"object\" ||\n Array.isArray(claims)\n ) {\n throw new ToolRequestError(\"token_malformed\");\n }\n const valid = await crypto.subtle.verify(\n \"HMAC\",\n key,\n signatureBytes,\n new TextEncoder().encode(`${header}.${payload}`),\n );\n if (!valid) throw new ToolRequestError(\"token_invalid\");\n const now = Math.floor(Date.now() / 1000);\n const { iss, aud, sub, exp, iat, workspace_id, source, tenant } = claims;\n if (iss !== TOOL_TOKEN_ISSUER) throw new ToolRequestError(\"token_invalid\");\n if (typeof exp !== \"number\" || exp <= now) throw new ToolRequestError(\"token_expired\");\n if (typeof iat !== \"number\" || iat > now + CLOCK_SKEW_SECONDS) {\n throw new ToolRequestError(\"token_invalid\");\n }\n if (aud !== audience) {\n throw new ToolRequestError(\"token_audience\");\n }\n if (\n typeof sub !== \"string\" ||\n !sub ||\n typeof workspace_id !== \"string\" ||\n !workspace_id ||\n typeof source !== \"string\" ||\n (tenant !== undefined && typeof tenant !== \"string\")\n ) {\n throw new ToolRequestError(\"token_invalid\");\n }\n return {\n user: sub,\n ...(tenant !== undefined ? { tenant } : {}),\n workspaceId: workspace_id,\n source,\n expiresAt: new Date(exp * 1000),\n };\n}\n\n/** Mint one tool token. The session proxy calls this; products rarely need to. */\nexport async function mintToolToken(input: {\n /** Tool server URL; becomes `aud`. */\n audience: string;\n user: string;\n tenant?: string | undefined;\n workspaceId: string;\n source: string;\n secret?: string | undefined;\n ttlSeconds?: number | undefined;\n}): Promise<string> {\n const ttl = input.ttlSeconds ?? TOOL_TOKEN_DEFAULT_TTL_SECONDS;\n if (!Number.isSafeInteger(ttl) || ttl < 1 || ttl > MAX_TTL_SECONDS) {\n throw new TypeError(`ttlSeconds must be an integer from 1 to ${MAX_TTL_SECONDS}.`);\n }\n const key = await signingKey(resolveToolTokenSecret(input.secret));\n const now = Math.floor(Date.now() / 1000);\n const header = base64UrlJson({ alg: \"HS256\", typ: \"JWT\" });\n const payload = base64UrlJson({\n iss: TOOL_TOKEN_ISSUER,\n aud: input.audience,\n sub: input.user,\n workspace_id: input.workspaceId,\n source: input.source,\n ...(input.tenant !== undefined ? { tenant: input.tenant } : {}),\n iat: now,\n exp: now + ttl,\n });\n const signature = await crypto.subtle.sign(\n \"HMAC\",\n key,\n new TextEncoder().encode(`${header}.${payload}`),\n );\n const token = `${header}.${payload}.${base64UrlEncode(new Uint8Array(signature))}`;\n if (`Bearer ${token}`.length > MAX_HEADER_VALUE_LENGTH) {\n throw new TypeError(\n `Tool token exceeds Opengeni's ${MAX_HEADER_VALUE_LENGTH}-character header limit; shorten the user, tenant, or URL.`,\n );\n }\n return token;\n}\n\n/**\n * The hex HS256 key tool tokens are signed with. Give this (not the\n * organization key) to a tool server written in Python, Ruby, Go, and so on.\n */\nexport async function deriveToolTokenKey(secret?: string): Promise<string> {\n return [...(await derivedKeyBytes(resolveToolTokenSecret(secret)))]\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/** The configured secret, else `OPENGENI_API_KEY`. Throws when neither is set. */\nexport function resolveToolTokenSecret(secret: string | undefined): string {\n const resolved = secret ?? environment(\"OPENGENI_API_KEY\");\n if (!resolved) {\n throw new TypeError(\n \"Tool tokens need a signing secret: set OPENGENI_API_KEY, or pass the same `secret` to the session proxy's toolServer and verifyToolRequest.\",\n );\n }\n return resolved;\n}\n\nfunction environment(name: string): string | undefined {\n return (\n (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.[\n name\n ] || undefined\n );\n}\n\nasync function derivedKeyBytes(secret: string): Promise<Uint8Array<ArrayBuffer>> {\n const root = await crypto.subtle.importKey(\n \"raw\",\n new TextEncoder().encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n return new Uint8Array(\n await crypto.subtle.sign(\"HMAC\", root, new TextEncoder().encode(TOOL_TOKEN_KEY_LABEL)),\n );\n}\n\nconst keys = new Map<string, Promise<CryptoKey>>();\n\n/** HS256 key derived from the secret, so the raw secret never signs tokens itself. */\nfunction signingKey(secret: string): Promise<CryptoKey> {\n let key = keys.get(secret);\n if (!key) {\n key = (async () =>\n await crypto.subtle.importKey(\n \"raw\",\n await derivedKeyBytes(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\", \"verify\"],\n ))();\n key.catch(() => keys.delete(secret));\n if (keys.size >= 16) keys.delete(keys.keys().next().value!);\n keys.set(secret, key);\n }\n return key;\n}\n\nfunction requestAuthorization(request: ToolRequestLike): string | undefined {\n if (typeof Request !== \"undefined\" && request instanceof Request) {\n return request.headers.get(\"authorization\") ?? undefined;\n }\n const headers = (request as Exclude<ToolRequestLike, Request>).headers as unknown;\n const raw =\n headers && typeof (headers as Headers).get === \"function\"\n ? ((headers as Headers).get(\"authorization\") ?? undefined)\n : (headers as Record<string, string | string[] | undefined>)?.authorization;\n return Array.isArray(raw) ? undefined : raw;\n}\n\nfunction base64UrlJson(value: unknown): string {\n return base64UrlEncode(new TextEncoder().encode(JSON.stringify(value)));\n}\n\nfunction base64UrlEncode(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction base64UrlDecode(value: string): Uint8Array<ArrayBuffer> {\n const base64 = value.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(base64 + \"=\".repeat((4 - (base64.length % 4)) % 4));\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);\n return bytes;\n}\n\nfunction utf8(bytes: Uint8Array): string {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// ../contracts/src/workspace-integration-wire.ts
|
|
2
|
+
var WORKSPACE_WEBHOOK_EVENT_TYPES = [
|
|
3
|
+
"turn.completed",
|
|
4
|
+
"turn.failed",
|
|
5
|
+
"turn.cancelled",
|
|
6
|
+
"session.status.changed",
|
|
7
|
+
"session.requiresAction",
|
|
8
|
+
"session.humanInput.requested",
|
|
9
|
+
"session.notification.posted",
|
|
10
|
+
"session.notification.withdrawn",
|
|
11
|
+
"usage.threshold_reached",
|
|
12
|
+
"usage.exhausted",
|
|
13
|
+
"usage.period_reset"
|
|
14
|
+
];
|
|
15
|
+
var OPENGENI_WEBHOOK_TEST_EVENT_TYPE = "webhook.test";
|
|
16
|
+
var OPENGENI_TEST_REQUEST_NIL_ID = "00000000-0000-0000-0000-000000000000";
|
|
17
|
+
var OPENGENI_SIGNATURE_HEADER = "OpenGeni-Signature";
|
|
18
|
+
var OPENGENI_EVENT_ID_HEADER = "OpenGeni-Event-Id";
|
|
19
|
+
var OPENGENI_DELIVERY_ID_HEADER = "OpenGeni-Delivery-Id";
|
|
20
|
+
var OPENGENI_SIGNATURE_TOLERANCE_SECONDS = 300;
|
|
21
|
+
var encoder = new TextEncoder();
|
|
22
|
+
async function hmacSha256Hex(secret, message) {
|
|
23
|
+
const key = await crypto.subtle.importKey(
|
|
24
|
+
"raw",
|
|
25
|
+
encoder.encode(secret),
|
|
26
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
27
|
+
false,
|
|
28
|
+
["sign"]
|
|
29
|
+
);
|
|
30
|
+
const signature = new Uint8Array(await crypto.subtle.sign("HMAC", key, encoder.encode(message)));
|
|
31
|
+
return Array.from(signature, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
32
|
+
}
|
|
33
|
+
function constantTimeEqualHex(left, right) {
|
|
34
|
+
if (left.length !== right.length) return false;
|
|
35
|
+
let difference = 0;
|
|
36
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
37
|
+
difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
|
|
38
|
+
}
|
|
39
|
+
return difference === 0;
|
|
40
|
+
}
|
|
41
|
+
async function signOpenGeniPayload(secret, body, timestampSeconds = Math.floor(Date.now() / 1e3)) {
|
|
42
|
+
return `t=${timestampSeconds},v1=${await hmacSha256Hex(secret, `${timestampSeconds}.${body}`)}`;
|
|
43
|
+
}
|
|
44
|
+
async function verifyOpenGeniSignature(input) {
|
|
45
|
+
if (!input.signature) return false;
|
|
46
|
+
let timestamp = null;
|
|
47
|
+
const candidates = [];
|
|
48
|
+
for (const part of input.signature.split(",")) {
|
|
49
|
+
const [key, value] = part.trim().split("=", 2);
|
|
50
|
+
if (key === "t" && value && /^\d{1,12}$/.test(value)) timestamp = Number(value);
|
|
51
|
+
if (key === "v1" && value && /^[0-9a-f]{64}$/.test(value)) candidates.push(value);
|
|
52
|
+
}
|
|
53
|
+
if (timestamp === null || candidates.length === 0) return false;
|
|
54
|
+
const now = input.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
55
|
+
const tolerance = input.toleranceSeconds ?? OPENGENI_SIGNATURE_TOLERANCE_SECONDS;
|
|
56
|
+
if (Math.abs(now - timestamp) > tolerance) return false;
|
|
57
|
+
const expected = await hmacSha256Hex(input.secret, `${timestamp}.${input.body}`);
|
|
58
|
+
return candidates.some((candidate) => constantTimeEqualHex(candidate, expected));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/workspace-integrations.ts
|
|
62
|
+
var OpenGeniSignatureError = class extends Error {
|
|
63
|
+
constructor() {
|
|
64
|
+
super("Opengeni signature verification failed");
|
|
65
|
+
this.name = "OpenGeniSignatureError";
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function header(headers, name) {
|
|
69
|
+
if (headers instanceof Headers) return headers.get(name);
|
|
70
|
+
const wanted = name.toLowerCase();
|
|
71
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
72
|
+
if (key.toLowerCase() === wanted) {
|
|
73
|
+
return Array.isArray(value) ? value[0] ?? null : value ?? null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
async function verifiedObject(input) {
|
|
79
|
+
const valid = await verifyOpenGeniSignature({
|
|
80
|
+
secret: input.secret,
|
|
81
|
+
body: input.body,
|
|
82
|
+
signature: header(input.headers, OPENGENI_SIGNATURE_HEADER),
|
|
83
|
+
...input.toleranceSeconds !== void 0 ? { toleranceSeconds: input.toleranceSeconds } : {}
|
|
84
|
+
});
|
|
85
|
+
if (!valid) throw new OpenGeniSignatureError();
|
|
86
|
+
const parsed = JSON.parse(input.body);
|
|
87
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
88
|
+
throw new OpenGeniSignatureError();
|
|
89
|
+
}
|
|
90
|
+
return parsed;
|
|
91
|
+
}
|
|
92
|
+
async function verifyWebhookEvent(input) {
|
|
93
|
+
const event = await verifiedObject(input);
|
|
94
|
+
const usageEvent = typeof event.type === "string" && event.type.startsWith("usage.");
|
|
95
|
+
const lane = event.lane === void 0 ? "workspace" : event.lane;
|
|
96
|
+
if (typeof event.id !== "string" || typeof event.type !== "string" || typeof event.workspaceId !== "string" || lane !== "workspace" && lane !== "organization" || usageEvent && lane !== "workspace" || !(typeof event.sessionId === "string" || (event.sessionId === null || event.sessionId === void 0) && [
|
|
97
|
+
"usage.threshold_reached",
|
|
98
|
+
"usage.exhausted",
|
|
99
|
+
"usage.period_reset",
|
|
100
|
+
OPENGENI_WEBHOOK_TEST_EVENT_TYPE
|
|
101
|
+
].includes(event.type))) {
|
|
102
|
+
throw new OpenGeniSignatureError();
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
event: { ...event, lane },
|
|
106
|
+
deliveryId: header(input.headers, OPENGENI_DELIVERY_ID_HEADER)
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async function verifyCredentialProviderRequest(input) {
|
|
110
|
+
const parsed = await verifiedObject(input);
|
|
111
|
+
if (parsed.type !== "credentials.request" || typeof parsed.workspaceId !== "string") {
|
|
112
|
+
throw new OpenGeniSignatureError();
|
|
113
|
+
}
|
|
114
|
+
return parsed;
|
|
115
|
+
}
|
|
116
|
+
var OPENGENI_WEBHOOK_HEADERS = {
|
|
117
|
+
signature: OPENGENI_SIGNATURE_HEADER,
|
|
118
|
+
eventId: OPENGENI_EVENT_ID_HEADER,
|
|
119
|
+
deliveryId: OPENGENI_DELIVERY_ID_HEADER
|
|
120
|
+
};
|
|
121
|
+
async function getOrganizationCredentialProvider(client, organizationId) {
|
|
122
|
+
return client.requestJson(
|
|
123
|
+
"GET",
|
|
124
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/credential-provider`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
async function putOrganizationCredentialProvider(client, organizationId, request) {
|
|
128
|
+
return client.requestJson(
|
|
129
|
+
"PUT",
|
|
130
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/credential-provider`,
|
|
131
|
+
request
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
async function deleteOrganizationCredentialProvider(client, organizationId) {
|
|
135
|
+
await client.requestJson(
|
|
136
|
+
"DELETE",
|
|
137
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/credential-provider`,
|
|
138
|
+
void 0,
|
|
139
|
+
{},
|
|
140
|
+
{ responseType: "void" }
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
async function listOrganizationWebhooks(client, organizationId) {
|
|
144
|
+
return client.requestJson(
|
|
145
|
+
"GET",
|
|
146
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/webhooks`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
async function createOrganizationWebhook(client, organizationId, request) {
|
|
150
|
+
return client.requestJson(
|
|
151
|
+
"POST",
|
|
152
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/webhooks`,
|
|
153
|
+
request
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
async function getOrganizationWebhook(client, organizationId, webhookId) {
|
|
157
|
+
return client.requestJson(
|
|
158
|
+
"GET",
|
|
159
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
async function updateOrganizationWebhook(client, organizationId, webhookId, request) {
|
|
163
|
+
return client.requestJson(
|
|
164
|
+
"PATCH",
|
|
165
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}`,
|
|
166
|
+
request
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
async function deleteOrganizationWebhook(client, organizationId, webhookId) {
|
|
170
|
+
await client.requestJson(
|
|
171
|
+
"DELETE",
|
|
172
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}`,
|
|
173
|
+
void 0,
|
|
174
|
+
{},
|
|
175
|
+
{ responseType: "void" }
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
async function listOrganizationWebhookDeliveries(client, organizationId, webhookId, options = {}) {
|
|
179
|
+
return client.requestJson(
|
|
180
|
+
"GET",
|
|
181
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}/deliveries`,
|
|
182
|
+
void 0,
|
|
183
|
+
options.limit !== void 0 ? { limit: String(options.limit) } : {}
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
async function redeliverOrganizationWebhookDelivery(client, organizationId, webhookId, deliveryId) {
|
|
187
|
+
return client.requestJson(
|
|
188
|
+
"POST",
|
|
189
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}/deliveries/${encodeURIComponent(deliveryId)}/redeliver`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
async function getWorkspaceWebhook(client, workspaceId, webhookId) {
|
|
193
|
+
return client.requestJson("GET", `/v1/workspaces/${workspaceId}/webhooks/${webhookId}`);
|
|
194
|
+
}
|
|
195
|
+
async function rotateWorkspaceCredentialProviderSecret(client, workspaceId) {
|
|
196
|
+
return client.requestJson(
|
|
197
|
+
"POST",
|
|
198
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/credential-provider/rotate-secret`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
async function rotateOrganizationCredentialProviderSecret(client, organizationId) {
|
|
202
|
+
return client.requestJson(
|
|
203
|
+
"POST",
|
|
204
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/credential-provider/rotate-secret`
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
async function rotateOrganizationWebhookSecret(client, organizationId, webhookId) {
|
|
208
|
+
return client.requestJson(
|
|
209
|
+
"POST",
|
|
210
|
+
`/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}/rotate-secret`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
async function rotateWorkspaceWebhookSecret(client, workspaceId, webhookId) {
|
|
214
|
+
return client.requestJson(
|
|
215
|
+
"POST",
|
|
216
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/webhooks/${encodeURIComponent(webhookId)}/rotate-secret`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
async function testWorkspaceWebhook(client, workspaceId, webhookId) {
|
|
220
|
+
return client.requestJson(
|
|
221
|
+
"POST",
|
|
222
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/webhooks/${encodeURIComponent(webhookId)}/test`
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
async function testWorkspaceCredentialProvider(client, workspaceId) {
|
|
226
|
+
return client.requestJson(
|
|
227
|
+
"POST",
|
|
228
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/credential-provider/test`
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
async function getWorkspaceInheritedIntegrations(client, workspaceId) {
|
|
232
|
+
return client.requestJson(
|
|
233
|
+
"GET",
|
|
234
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/inherited-integrations`
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export {
|
|
239
|
+
WORKSPACE_WEBHOOK_EVENT_TYPES,
|
|
240
|
+
OPENGENI_WEBHOOK_TEST_EVENT_TYPE,
|
|
241
|
+
OPENGENI_TEST_REQUEST_NIL_ID,
|
|
242
|
+
OPENGENI_SIGNATURE_HEADER,
|
|
243
|
+
OPENGENI_EVENT_ID_HEADER,
|
|
244
|
+
OPENGENI_DELIVERY_ID_HEADER,
|
|
245
|
+
signOpenGeniPayload,
|
|
246
|
+
verifyOpenGeniSignature,
|
|
247
|
+
OpenGeniSignatureError,
|
|
248
|
+
verifyWebhookEvent,
|
|
249
|
+
verifyCredentialProviderRequest,
|
|
250
|
+
OPENGENI_WEBHOOK_HEADERS,
|
|
251
|
+
getOrganizationCredentialProvider,
|
|
252
|
+
putOrganizationCredentialProvider,
|
|
253
|
+
deleteOrganizationCredentialProvider,
|
|
254
|
+
listOrganizationWebhooks,
|
|
255
|
+
createOrganizationWebhook,
|
|
256
|
+
getOrganizationWebhook,
|
|
257
|
+
updateOrganizationWebhook,
|
|
258
|
+
deleteOrganizationWebhook,
|
|
259
|
+
listOrganizationWebhookDeliveries,
|
|
260
|
+
redeliverOrganizationWebhookDelivery,
|
|
261
|
+
getWorkspaceWebhook,
|
|
262
|
+
rotateWorkspaceCredentialProviderSecret,
|
|
263
|
+
rotateOrganizationCredentialProviderSecret,
|
|
264
|
+
rotateOrganizationWebhookSecret,
|
|
265
|
+
rotateWorkspaceWebhookSecret,
|
|
266
|
+
testWorkspaceWebhook,
|
|
267
|
+
testWorkspaceCredentialProvider,
|
|
268
|
+
getWorkspaceInheritedIntegrations
|
|
269
|
+
};
|
|
270
|
+
//# sourceMappingURL=chunk-RJHCBZF7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../contracts/src/workspace-integration-wire.ts","../src/workspace-integrations.ts"],"sourcesContent":["/**\n * Dependency-free wire constants and the OpenGeni-Signature scheme shared by\n * workspace webhooks and credential providers. Kept free of zod so browser and\n * React Native bundles can verify signatures without the schema runtime.\n */\n\nexport const WORKSPACE_WEBHOOK_EVENT_TYPES = [\n \"turn.completed\",\n \"turn.failed\",\n \"turn.cancelled\",\n \"session.status.changed\",\n \"session.requiresAction\",\n \"session.humanInput.requested\",\n \"session.notification.posted\",\n \"session.notification.withdrawn\",\n \"usage.threshold_reached\",\n \"usage.exhausted\",\n \"usage.period_reset\",\n] as const;\n\n/**\n * Sent only when an administrator presses \"Send test event\". It is never a\n * subscribable type: every endpoint can receive it, and a receiver that does\n * not care acknowledges it with any 2xx.\n */\nexport const OPENGENI_WEBHOOK_TEST_EVENT_TYPE = \"webhook.test\";\n\n/**\n * The session, turn and attempt ids of a credential-provider test request\n * (`purpose: \"test\"`). A test is not a run, so no real ids exist.\n */\nexport const OPENGENI_TEST_REQUEST_NIL_ID = \"00000000-0000-0000-0000-000000000000\";\n\nexport const OPENGENI_SIGNATURE_HEADER = \"OpenGeni-Signature\";\nexport const OPENGENI_EVENT_ID_HEADER = \"OpenGeni-Event-Id\";\nexport const OPENGENI_DELIVERY_ID_HEADER = \"OpenGeni-Delivery-Id\";\nexport const OPENGENI_SIGNATURE_TOLERANCE_SECONDS = 300;\n\nconst encoder = new TextEncoder();\n\nasync function hmacSha256Hex(secret: string, message: string): Promise<string> {\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const signature = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, encoder.encode(message)));\n return Array.from(signature, (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nfunction constantTimeEqualHex(left: string, right: string): boolean {\n if (left.length !== right.length) return false;\n let difference = 0;\n for (let index = 0; index < left.length; index += 1) {\n difference |= left.charCodeAt(index) ^ right.charCodeAt(index);\n }\n return difference === 0;\n}\n\n/**\n * `OpenGeni-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>`.\n * The timestamp is signed so a captured request cannot be replayed later.\n */\nexport async function signOpenGeniPayload(\n secret: string,\n body: string,\n timestampSeconds = Math.floor(Date.now() / 1000),\n): Promise<string> {\n return `t=${timestampSeconds},v1=${await hmacSha256Hex(secret, `${timestampSeconds}.${body}`)}`;\n}\n\nexport type VerifyOpenGeniSignatureInput = {\n secret: string;\n /** The exact raw request body, before JSON parsing. */\n body: string;\n /** The `OpenGeni-Signature` header value. */\n signature: string | null | undefined;\n toleranceSeconds?: number;\n nowSeconds?: number;\n};\n\nexport async function verifyOpenGeniSignature(\n input: VerifyOpenGeniSignatureInput,\n): Promise<boolean> {\n if (!input.signature) return false;\n let timestamp: number | null = null;\n const candidates: string[] = [];\n for (const part of input.signature.split(\",\")) {\n const [key, value] = part.trim().split(\"=\", 2);\n if (key === \"t\" && value && /^\\d{1,12}$/.test(value)) timestamp = Number(value);\n if (key === \"v1\" && value && /^[0-9a-f]{64}$/.test(value)) candidates.push(value);\n }\n if (timestamp === null || candidates.length === 0) return false;\n const now = input.nowSeconds ?? Math.floor(Date.now() / 1000);\n const tolerance = input.toleranceSeconds ?? OPENGENI_SIGNATURE_TOLERANCE_SECONDS;\n if (Math.abs(now - timestamp) > tolerance) return false;\n const expected = await hmacSha256Hex(input.secret, `${timestamp}.${input.body}`);\n return candidates.some((candidate) => constantTimeEqualHex(candidate, expected));\n}\n","import {\n OPENGENI_DELIVERY_ID_HEADER,\n OPENGENI_EVENT_ID_HEADER,\n OPENGENI_SIGNATURE_HEADER,\n OPENGENI_WEBHOOK_TEST_EVENT_TYPE,\n verifyOpenGeniSignature,\n} from \"@opengeni/contracts/workspace-integration-wire\";\nimport type { CredentialProviderRequest, WorkspaceWebhookEvent } from \"@opengeni/contracts\";\nimport type { OpenGeniClient } from \"./client\";\nimport type {\n CreateOrganizationWebhookRequest,\n CreateOrganizationWebhookResponse,\n GetOrganizationCredentialProviderResponse,\n ListOrganizationWebhookDeliveriesResponse,\n ListOrganizationWebhooksResponse,\n OrganizationWebhook,\n OrganizationWebhookDelivery,\n PutOrganizationCredentialProviderRequest,\n PutOrganizationCredentialProviderResponse,\n RotateWorkspaceCredentialProviderSecretResponse,\n RotateOrganizationCredentialProviderSecretResponse,\n RotateWorkspaceWebhookSecretResponse,\n RotateOrganizationWebhookSecretResponse,\n TestWorkspaceCredentialProviderResponse,\n TestWorkspaceWebhookResponse,\n UpdateOrganizationWebhookRequest,\n WorkspaceInheritedIntegrationsResponse,\n WorkspaceWebhook,\n} from \"@opengeni/contracts\";\n\nexport type {\n CreateOrganizationWebhookRequest,\n CreateOrganizationWebhookResponse,\n CreateWorkspaceWebhookRequest,\n CreateWorkspaceWebhookResponse,\n CredentialProviderRequest,\n CredentialProviderInitiatorContext,\n CredentialProviderResponse,\n CredentialProviderMcpHeaders,\n CredentialProviderMcpMaterial,\n GetOrganizationCredentialProviderResponse,\n GetWorkspaceCredentialProviderResponse,\n InitiatingHuman,\n IntegrationEndpointTestResult,\n IntegrationWorkspaceFilter,\n ListOrganizationWebhookDeliveriesResponse,\n ListOrganizationWebhooksResponse,\n ListWorkspaceWebhookDeliveriesResponse,\n ListWorkspaceWebhooksResponse,\n PutWorkspaceCredentialProviderRequest,\n PutWorkspaceCredentialProviderResponse,\n PutOrganizationCredentialProviderRequest,\n PutOrganizationCredentialProviderResponse,\n RotateWorkspaceCredentialProviderSecretResponse,\n RotateOrganizationCredentialProviderSecretResponse,\n RotateWorkspaceWebhookSecretResponse,\n RotateOrganizationWebhookSecretResponse,\n TestWorkspaceCredentialProviderResponse,\n TestWorkspaceWebhookResponse,\n OrganizationCredentialProvider,\n OrganizationWebhook,\n OrganizationWebhookDelivery,\n UpdateOrganizationWebhookRequest,\n UpdateWorkspaceWebhookRequest,\n WorkspaceCredentialProvider,\n WorkspaceInheritedIntegrationsResponse,\n WorkspaceTestWebhookEvent,\n WorkspaceWebhook,\n WorkspaceWebhookDelivery,\n WorkspaceWebhookEvent,\n WorkspaceWebhookEventType,\n SessionWorkspaceWebhookEvent,\n WorkspaceUsageWebhookEvent,\n} from \"@opengeni/contracts\";\nexport {\n OPENGENI_DELIVERY_ID_HEADER,\n OPENGENI_EVENT_ID_HEADER,\n OPENGENI_SIGNATURE_HEADER,\n OPENGENI_TEST_REQUEST_NIL_ID,\n OPENGENI_WEBHOOK_TEST_EVENT_TYPE,\n WORKSPACE_WEBHOOK_EVENT_TYPES,\n signOpenGeniPayload,\n verifyOpenGeniSignature,\n} from \"@opengeni/contracts/workspace-integration-wire\";\n\nexport type WorkspaceSandboxImages = { images: string[]; selected: string | null };\n\nexport class OpenGeniSignatureError extends Error {\n constructor() {\n super(\"Opengeni signature verification failed\");\n this.name = \"OpenGeniSignatureError\";\n }\n}\n\ntype SignedRequest = {\n /** The exact raw request body. Parse it only after verification. */\n body: string;\n headers: Headers | Record<string, string | string[] | undefined>;\n secret: string;\n toleranceSeconds?: number;\n};\n\nfunction header(headers: SignedRequest[\"headers\"], name: string): string | null {\n if (headers instanceof Headers) return headers.get(name);\n const wanted = name.toLowerCase();\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === wanted) {\n return Array.isArray(value) ? (value[0] ?? null) : (value ?? null);\n }\n }\n return null;\n}\n\nasync function verifiedObject(input: SignedRequest): Promise<Record<string, unknown>> {\n const valid = await verifyOpenGeniSignature({\n secret: input.secret,\n body: input.body,\n signature: header(input.headers, OPENGENI_SIGNATURE_HEADER),\n ...(input.toleranceSeconds !== undefined ? { toleranceSeconds: input.toleranceSeconds } : {}),\n });\n if (!valid) throw new OpenGeniSignatureError();\n const parsed: unknown = JSON.parse(input.body);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new OpenGeniSignatureError();\n }\n return parsed as Record<string, unknown>;\n}\n\n/**\n * Verify and parse one webhook delivery. Delivery is at least once: dedupe on\n * `event.id` (also sent as the `OpenGeni-Event-Id` header). A `webhook.test`\n * event (from \"Send test event\") names no session: acknowledge it with 2xx.\n */\nexport async function verifyWebhookEvent(input: SignedRequest): Promise<{\n event: WorkspaceWebhookEvent;\n deliveryId: string | null;\n}> {\n const event = await verifiedObject(input);\n const usageEvent = typeof event.type === \"string\" && event.type.startsWith(\"usage.\");\n const lane = event.lane === undefined ? \"workspace\" : event.lane;\n if (\n typeof event.id !== \"string\" ||\n typeof event.type !== \"string\" ||\n typeof event.workspaceId !== \"string\" ||\n (lane !== \"workspace\" && lane !== \"organization\") ||\n (usageEvent && lane !== \"workspace\") ||\n !(\n typeof event.sessionId === \"string\" ||\n ((event.sessionId === null || event.sessionId === undefined) &&\n [\n \"usage.threshold_reached\",\n \"usage.exhausted\",\n \"usage.period_reset\",\n OPENGENI_WEBHOOK_TEST_EVENT_TYPE,\n ].includes(event.type))\n )\n ) {\n throw new OpenGeniSignatureError();\n }\n return {\n event: { ...event, lane } as WorkspaceWebhookEvent,\n deliveryId: header(input.headers, OPENGENI_DELIVERY_ID_HEADER),\n };\n}\n\n/**\n * Verify the exact bytes and parse a provider request, including its frozen\n * initiatorContext when sent by an upgraded worker. Provenance grants no access.\n */\nexport async function verifyCredentialProviderRequest(\n input: SignedRequest,\n): Promise<CredentialProviderRequest> {\n const parsed = await verifiedObject(input);\n if (parsed.type !== \"credentials.request\" || typeof parsed.workspaceId !== \"string\") {\n throw new OpenGeniSignatureError();\n }\n return parsed as CredentialProviderRequest;\n}\n\n/** Identity header names, for receivers that log or dedupe. */\nexport const OPENGENI_WEBHOOK_HEADERS = {\n signature: OPENGENI_SIGNATURE_HEADER,\n eventId: OPENGENI_EVENT_ID_HEADER,\n deliveryId: OPENGENI_DELIVERY_ID_HEADER,\n} as const;\n\n/** Server-side integration administration is opt-in, outside the eager browser client. */\nexport async function getOrganizationCredentialProvider(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n): Promise<GetOrganizationCredentialProviderResponse> {\n return client.requestJson(\n \"GET\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/credential-provider`,\n );\n}\n\n/** Replace configuration; explicit filter required. Store the first returned signing secret. */\nexport async function putOrganizationCredentialProvider(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n request: PutOrganizationCredentialProviderRequest,\n): Promise<PutOrganizationCredentialProviderResponse> {\n return client.requestJson(\n \"PUT\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/credential-provider`,\n request,\n );\n}\n\nexport async function deleteOrganizationCredentialProvider(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n): Promise<void> {\n await client.requestJson<void>(\n \"DELETE\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/credential-provider`,\n undefined,\n {},\n { responseType: \"void\" },\n );\n}\n\nexport async function listOrganizationWebhooks(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n): Promise<ListOrganizationWebhooksResponse> {\n return client.requestJson(\n \"GET\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/webhooks`,\n );\n}\n\n/** Create a webhook and return its signing secret once. */\nexport async function createOrganizationWebhook(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n request: CreateOrganizationWebhookRequest,\n): Promise<CreateOrganizationWebhookResponse> {\n return client.requestJson(\n \"POST\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/webhooks`,\n request,\n );\n}\n\nexport async function getOrganizationWebhook(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n webhookId: string,\n): Promise<OrganizationWebhook> {\n return client.requestJson(\n \"GET\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}`,\n );\n}\n\nexport async function updateOrganizationWebhook(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n webhookId: string,\n request: UpdateOrganizationWebhookRequest,\n): Promise<OrganizationWebhook> {\n return client.requestJson(\n \"PATCH\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}`,\n request,\n );\n}\n\nexport async function deleteOrganizationWebhook(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n webhookId: string,\n): Promise<void> {\n await client.requestJson<void>(\n \"DELETE\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}`,\n undefined,\n {},\n { responseType: \"void\" },\n );\n}\n\nexport async function listOrganizationWebhookDeliveries(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n webhookId: string,\n options: { limit?: number } = {},\n): Promise<ListOrganizationWebhookDeliveriesResponse> {\n return client.requestJson(\n \"GET\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}/deliveries`,\n undefined,\n options.limit !== undefined ? { limit: String(options.limit) } : {},\n );\n}\n\n/** Requeue a settled delivery with a fresh attempt budget. */\nexport async function redeliverOrganizationWebhookDelivery(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n webhookId: string,\n deliveryId: string,\n): Promise<OrganizationWebhookDelivery> {\n return client.requestJson(\n \"POST\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}/deliveries/${encodeURIComponent(deliveryId)}/redeliver`,\n );\n}\n\nexport async function getWorkspaceWebhook(\n client: Pick<OpenGeniClient, \"requestJson\">,\n workspaceId: string,\n webhookId: string,\n): Promise<WorkspaceWebhook> {\n return client.requestJson(\"GET\", `/v1/workspaces/${workspaceId}/webhooks/${webhookId}`);\n}\n\n/** Rotate immediately. Store the new secret; the old signing secret stops working. */\nexport async function rotateWorkspaceCredentialProviderSecret(\n client: Pick<OpenGeniClient, \"requestJson\">,\n workspaceId: string,\n): Promise<RotateWorkspaceCredentialProviderSecretResponse> {\n return client.requestJson(\n \"POST\",\n `/v1/workspaces/${encodeURIComponent(workspaceId)}/credential-provider/rotate-secret`,\n );\n}\n\nexport async function rotateOrganizationCredentialProviderSecret(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n): Promise<RotateOrganizationCredentialProviderSecretResponse> {\n return client.requestJson(\n \"POST\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/credential-provider/rotate-secret`,\n );\n}\n\nexport async function rotateOrganizationWebhookSecret(\n client: Pick<OpenGeniClient, \"requestJson\">,\n organizationId: string,\n webhookId: string,\n): Promise<RotateOrganizationWebhookSecretResponse> {\n return client.requestJson(\n \"POST\",\n `/v1/organizations/${encodeURIComponent(organizationId)}/webhooks/${encodeURIComponent(webhookId)}/rotate-secret`,\n );\n}\n\nexport async function rotateWorkspaceWebhookSecret(\n client: Pick<OpenGeniClient, \"requestJson\">,\n workspaceId: string,\n webhookId: string,\n): Promise<RotateWorkspaceWebhookSecretResponse> {\n return client.requestJson(\n \"POST\",\n `/v1/workspaces/${encodeURIComponent(workspaceId)}/webhooks/${encodeURIComponent(webhookId)}/rotate-secret`,\n );\n}\n\n/**\n * Send one signed `webhook.test` event to a workspace webhook now and return\n * what the endpoint answered. Nothing is queued or retried.\n */\nexport async function testWorkspaceWebhook(\n client: Pick<OpenGeniClient, \"requestJson\">,\n workspaceId: string,\n webhookId: string,\n): Promise<TestWorkspaceWebhookResponse> {\n return client.requestJson(\n \"POST\",\n `/v1/workspaces/${encodeURIComponent(workspaceId)}/webhooks/${encodeURIComponent(webhookId)}/test`,\n );\n}\n\n/**\n * Send one signed `purpose: \"test\"` request to the credential provider this\n * workspace's runs use (its own, else the organization's). Only the names of\n * returned credentials come back, never their values.\n */\nexport async function testWorkspaceCredentialProvider(\n client: Pick<OpenGeniClient, \"requestJson\">,\n workspaceId: string,\n): Promise<TestWorkspaceCredentialProviderResponse> {\n return client.requestJson(\n \"POST\",\n `/v1/workspaces/${encodeURIComponent(workspaceId)}/credential-provider/test`,\n );\n}\n\n/** Organization registrations that reach this workspace. Workspace administrators only. */\nexport async function getWorkspaceInheritedIntegrations(\n client: Pick<OpenGeniClient, \"requestJson\">,\n workspaceId: string,\n): Promise<WorkspaceInheritedIntegrationsResponse> {\n return client.requestJson(\n \"GET\",\n `/v1/workspaces/${encodeURIComponent(workspaceId)}/inherited-integrations`,\n );\n}\n"],"mappings":"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","names":[]}
|