@claxedo/workspace-relay-protocol 0.7.0 → 0.8.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/README.md +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.mjs +87 -76
- package/dist/token-verifier.d.ts +23 -9
- package/package.json +9 -8
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ const claims = await verifier.verify("test-token")
|
|
|
60
60
|
| `makeTunnelPing`, `makeTunnelPong` | Stable | Helpers for heartbeat requests and replies. |
|
|
61
61
|
| `TokenVerifier` and claim types | Stable | Narrow verifier interface shared by relay/runtime boundaries. |
|
|
62
62
|
| `RelayHostVerifierClaims` (incl. `role`) | Stable | Claims shape for host-side verification: org, `role` (`viewer` \| `editor` \| `admin` \| `owner`), and cloud/user-hosted backing discriminant. |
|
|
63
|
-
| `
|
|
63
|
+
| `createOidcTokenVerifier` | Public beta | Verifies session JWTs with issuer, audience, JWKS, and algorithm constraints. |
|
|
64
64
|
| `createHttpTokenVerifier` | Public beta | Calls an operator-controlled verifier endpoint over HTTP. |
|
|
65
65
|
| `createStaticTokenVerifier` | Test/single-tenant only | Fixed token table for tests and isolated self-hosted deployments. |
|
|
66
66
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export declare const TUNNEL_PROTOCOL_VERSION = 1;
|
|
2
|
-
export
|
|
2
|
+
export declare const SESSION_STREAM_LEASE_TTL_MS = 15000;
|
|
3
|
+
export declare const SESSION_TURN_LEASE_TTL_MS = 60000;
|
|
4
|
+
export { type TokenClaims, type TokenVerifierBaseClaims, type RuntimeAccessVerifierClaims, type RelayHostVerifierClaims, type TokenVerifier, type OidcTokenVerifierClaims, TokenVerifierError, type OidcTokenVerifierOptions, createOidcTokenVerifier, type HttpTokenVerifierOptions, createHttpTokenVerifier, type StaticTokenVerifierOptions, createStaticTokenVerifier, } from "./token-verifier";
|
|
3
5
|
export type TunnelHeaderMap = Record<string, string>;
|
|
4
6
|
export type TunnelPing = {
|
|
5
7
|
type: "ping";
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
|
+
// ../claxedo-helpers/dist/guards.mjs
|
|
2
|
+
function isRecord(value) {
|
|
3
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4
|
+
}
|
|
5
|
+
function isString(value) {
|
|
6
|
+
return typeof value === "string";
|
|
7
|
+
}
|
|
8
|
+
function isFiniteNumber(value) {
|
|
9
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
10
|
+
}
|
|
11
|
+
function asFiniteNumber(value) {
|
|
12
|
+
return isFiniteNumber(value) ? value : void 0;
|
|
13
|
+
}
|
|
14
|
+
function stringClaim(payload, key) {
|
|
15
|
+
const value = payload[key];
|
|
16
|
+
return isString(value) && value.trim().length > 0 ? value : void 0;
|
|
17
|
+
}
|
|
18
|
+
function numberClaim(payload, key) {
|
|
19
|
+
return asFiniteNumber(payload[key]);
|
|
20
|
+
}
|
|
21
|
+
|
|
1
22
|
// src/token-verifier.ts
|
|
2
|
-
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
23
|
+
import { createRemoteJWKSet, errors as joseErrors, jwtVerify } from "jose";
|
|
3
24
|
var TokenVerifierError = class extends Error {
|
|
4
25
|
code;
|
|
5
26
|
status;
|
|
@@ -30,34 +51,41 @@ function createHttpTokenVerifier(options) {
|
|
|
30
51
|
method: "POST",
|
|
31
52
|
headers: {
|
|
32
53
|
"content-type": "application/json",
|
|
33
|
-
...options.headers
|
|
54
|
+
...options.headers
|
|
34
55
|
},
|
|
35
56
|
body: JSON.stringify({ token }),
|
|
36
57
|
signal: controller.signal
|
|
37
58
|
});
|
|
38
59
|
if (!res.ok) {
|
|
39
60
|
throw new TokenVerifierError({
|
|
40
|
-
code: "verifier_rejected",
|
|
61
|
+
code: res.status === 401 || res.status === 403 ? "verifier_rejected" : "verifier_unavailable",
|
|
41
62
|
message: `Verifier endpoint returned ${res.status}`,
|
|
42
|
-
status: res.status === 401 || res.status === 403 ? res.status :
|
|
63
|
+
status: res.status === 401 || res.status === 403 ? res.status : 503
|
|
43
64
|
});
|
|
44
65
|
}
|
|
45
66
|
const body = await res.json().catch(() => null);
|
|
46
|
-
if (!body
|
|
67
|
+
if (!isRecord(body)) {
|
|
68
|
+
throw new TokenVerifierError({
|
|
69
|
+
code: "verifier_response_invalid",
|
|
70
|
+
message: "Verifier response is missing a subject"
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const subject = stringClaim(body, "subject");
|
|
74
|
+
if (!subject) {
|
|
47
75
|
throw new TokenVerifierError({
|
|
48
76
|
code: "verifier_response_invalid",
|
|
49
77
|
message: "Verifier response is missing a subject"
|
|
50
78
|
});
|
|
51
79
|
}
|
|
52
80
|
const claims = tokenVerifierBaseClaims(body.claims);
|
|
53
|
-
if (!claims || claims.sub !==
|
|
81
|
+
if (!claims || claims.sub !== subject) {
|
|
54
82
|
throw new TokenVerifierError({
|
|
55
83
|
code: "verifier_response_invalid",
|
|
56
84
|
message: "Verifier response is missing required token claims"
|
|
57
85
|
});
|
|
58
86
|
}
|
|
59
87
|
return {
|
|
60
|
-
subject
|
|
88
|
+
subject,
|
|
61
89
|
scopes: Array.isArray(body.scopes) ? body.scopes.filter((s) => typeof s === "string") : [],
|
|
62
90
|
claims
|
|
63
91
|
};
|
|
@@ -66,6 +94,7 @@ function createHttpTokenVerifier(options) {
|
|
|
66
94
|
throw new TokenVerifierError({
|
|
67
95
|
code: "verifier_unreachable",
|
|
68
96
|
message: err instanceof Error ? err.message : String(err),
|
|
97
|
+
status: 503,
|
|
69
98
|
cause: err
|
|
70
99
|
});
|
|
71
100
|
} finally {
|
|
@@ -74,11 +103,11 @@ function createHttpTokenVerifier(options) {
|
|
|
74
103
|
}
|
|
75
104
|
};
|
|
76
105
|
}
|
|
77
|
-
var
|
|
78
|
-
function
|
|
106
|
+
var oidcJwks = /* @__PURE__ */ new Map();
|
|
107
|
+
function createOidcTokenVerifier(options) {
|
|
79
108
|
const algorithms = options.algorithms ?? ["ES256", "EdDSA", "RS256"];
|
|
80
|
-
const remote =
|
|
81
|
-
|
|
109
|
+
const remote = oidcJwks.get(options.jwksUrl) ?? createRemoteJWKSet(new URL(options.jwksUrl));
|
|
110
|
+
oidcJwks.set(options.jwksUrl, remote);
|
|
82
111
|
return {
|
|
83
112
|
async verify(token) {
|
|
84
113
|
try {
|
|
@@ -87,11 +116,11 @@ function createClerkTokenVerifier(options) {
|
|
|
87
116
|
audience: options.audience,
|
|
88
117
|
algorithms
|
|
89
118
|
});
|
|
90
|
-
const claims =
|
|
119
|
+
const claims = oidcClaims(result.payload);
|
|
91
120
|
if (!claims) {
|
|
92
121
|
throw new TokenVerifierError({
|
|
93
|
-
code: "
|
|
94
|
-
message: "
|
|
122
|
+
code: "oidc_claims_invalid",
|
|
123
|
+
message: "Session token is missing required claims"
|
|
95
124
|
});
|
|
96
125
|
}
|
|
97
126
|
return {
|
|
@@ -101,9 +130,11 @@ function createClerkTokenVerifier(options) {
|
|
|
101
130
|
};
|
|
102
131
|
} catch (err) {
|
|
103
132
|
if (err instanceof TokenVerifierError) throw err;
|
|
133
|
+
const unavailable = err instanceof joseErrors.JWKSTimeout || !(err instanceof joseErrors.JOSEError);
|
|
104
134
|
throw new TokenVerifierError({
|
|
105
|
-
code: "
|
|
106
|
-
message: "
|
|
135
|
+
code: unavailable ? "oidc_verifier_unavailable" : "oidc_token_invalid",
|
|
136
|
+
message: unavailable ? "Session verifier is unavailable" : "Session token is invalid",
|
|
137
|
+
status: unavailable ? 503 : 401,
|
|
107
138
|
cause: err
|
|
108
139
|
});
|
|
109
140
|
}
|
|
@@ -111,10 +142,10 @@ function createClerkTokenVerifier(options) {
|
|
|
111
142
|
};
|
|
112
143
|
}
|
|
113
144
|
function createStaticTokenVerifier(options) {
|
|
114
|
-
const tokens =
|
|
145
|
+
const tokens = new Map(Object.entries(options.tokens));
|
|
115
146
|
return {
|
|
116
147
|
async verify(token) {
|
|
117
|
-
const claims = tokens
|
|
148
|
+
const claims = tokens.get(token);
|
|
118
149
|
if (!claims) {
|
|
119
150
|
throw new TokenVerifierError({
|
|
120
151
|
code: "token_not_in_static_table",
|
|
@@ -125,16 +156,8 @@ function createStaticTokenVerifier(options) {
|
|
|
125
156
|
}
|
|
126
157
|
};
|
|
127
158
|
}
|
|
128
|
-
function stringClaim(input, key) {
|
|
129
|
-
const value = input[key];
|
|
130
|
-
return typeof value === "string" && value.trim() ? value : void 0;
|
|
131
|
-
}
|
|
132
|
-
function numberClaim(input, key) {
|
|
133
|
-
const value = input[key];
|
|
134
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
135
|
-
}
|
|
136
159
|
function tokenVerifierBaseClaims(input) {
|
|
137
|
-
if (!input
|
|
160
|
+
if (!isRecord(input)) return void 0;
|
|
138
161
|
const iss = stringClaim(input, "iss");
|
|
139
162
|
const aud = stringClaim(input, "aud");
|
|
140
163
|
const sub = stringClaim(input, "sub");
|
|
@@ -143,7 +166,7 @@ function tokenVerifierBaseClaims(input) {
|
|
|
143
166
|
const exp = numberClaim(input, "exp");
|
|
144
167
|
const iat = numberClaim(input, "iat");
|
|
145
168
|
const jti = stringClaim(input, "jti");
|
|
146
|
-
if (!iss || !aud || !sub || !workspace_id || !host_id || !exp || !iat || !jti) return;
|
|
169
|
+
if (!iss || !aud || !sub || !workspace_id || !host_id || !exp || !iat || !jti) return void 0;
|
|
147
170
|
return {
|
|
148
171
|
...input,
|
|
149
172
|
iss,
|
|
@@ -156,8 +179,11 @@ function tokenVerifierBaseClaims(input) {
|
|
|
156
179
|
jti
|
|
157
180
|
};
|
|
158
181
|
}
|
|
159
|
-
function
|
|
160
|
-
if (!input.iss || !input.sub || !input.exp) return;
|
|
182
|
+
function oidcClaims(input) {
|
|
183
|
+
if (!input.iss || !input.sub || !input.exp) return void 0;
|
|
184
|
+
const sid = stringClaim(input, "sid");
|
|
185
|
+
const org_id = stringClaim(input, "org_id");
|
|
186
|
+
const orgId = stringClaim(input, "orgId");
|
|
161
187
|
return {
|
|
162
188
|
...input,
|
|
163
189
|
iss: input.iss,
|
|
@@ -165,9 +191,9 @@ function clerkClaims(input) {
|
|
|
165
191
|
exp: input.exp,
|
|
166
192
|
...input.iat ? { iat: input.iat } : {},
|
|
167
193
|
...typeof input.jti === "string" ? { jti: input.jti } : {},
|
|
168
|
-
...
|
|
169
|
-
...
|
|
170
|
-
...
|
|
194
|
+
...sid ? { sid } : {},
|
|
195
|
+
...org_id ? { org_id } : {},
|
|
196
|
+
...orgId ? { orgId } : {}
|
|
171
197
|
};
|
|
172
198
|
}
|
|
173
199
|
function scopeClaims(input) {
|
|
@@ -178,39 +204,24 @@ function scopeClaims(input) {
|
|
|
178
204
|
|
|
179
205
|
// src/index.ts
|
|
180
206
|
var TUNNEL_PROTOCOL_VERSION = 1;
|
|
181
|
-
var
|
|
182
|
-
|
|
183
|
-
"pong",
|
|
184
|
-
"host.registration.update",
|
|
185
|
-
"http.request",
|
|
186
|
-
"http.response.start",
|
|
187
|
-
"http.response.chunk",
|
|
188
|
-
"http.response.end",
|
|
189
|
-
"http.response.flow",
|
|
190
|
-
"ws.open",
|
|
191
|
-
"ws.frame",
|
|
192
|
-
"ws.close",
|
|
193
|
-
"error"
|
|
194
|
-
]);
|
|
207
|
+
var SESSION_STREAM_LEASE_TTL_MS = 15e3;
|
|
208
|
+
var SESSION_TURN_LEASE_TTL_MS = 6e4;
|
|
195
209
|
function validateTunnelMessage(input) {
|
|
196
|
-
if (!input
|
|
197
|
-
|
|
198
|
-
if (row.protocol !== TUNNEL_PROTOCOL_VERSION) {
|
|
210
|
+
if (!isRecord(input)) return { ok: false, reason: "invalid" };
|
|
211
|
+
if (input.protocol !== TUNNEL_PROTOCOL_VERSION) {
|
|
199
212
|
return {
|
|
200
213
|
ok: false,
|
|
201
214
|
reason: "protocol_mismatch",
|
|
202
215
|
expected_protocol: TUNNEL_PROTOCOL_VERSION,
|
|
203
|
-
actual_protocol:
|
|
204
|
-
...typeof
|
|
216
|
+
actual_protocol: input.protocol,
|
|
217
|
+
...typeof input.type === "string" ? { type: input.type } : {}
|
|
205
218
|
};
|
|
206
219
|
}
|
|
207
|
-
if (
|
|
208
|
-
|
|
209
|
-
if (!validateTunnelMessageShape(row)) return { ok: false, reason: "invalid" };
|
|
210
|
-
return { ok: true, message: row };
|
|
220
|
+
if (!isTunnelMessageRecord(input)) return { ok: false, reason: "invalid" };
|
|
221
|
+
return { ok: true, message: input };
|
|
211
222
|
}
|
|
212
223
|
function isTunnelMessage(input) {
|
|
213
|
-
return
|
|
224
|
+
return isRecord(input) && isTunnelMessageRecord(input);
|
|
214
225
|
}
|
|
215
226
|
function makeTunnelPong(input, receivedAt = Date.now()) {
|
|
216
227
|
return {
|
|
@@ -229,44 +240,42 @@ function makeTunnelPing(sentAt = Date.now(), id = crypto.randomUUID()) {
|
|
|
229
240
|
sent_at: sentAt
|
|
230
241
|
};
|
|
231
242
|
}
|
|
232
|
-
function
|
|
243
|
+
function isTunnelMessageRecord(row) {
|
|
244
|
+
if (row.protocol !== TUNNEL_PROTOCOL_VERSION) return false;
|
|
233
245
|
switch (row.type) {
|
|
234
246
|
case "ping":
|
|
235
|
-
return
|
|
247
|
+
return isNonEmptyString(row.id) && isFiniteNumber(row.sent_at);
|
|
236
248
|
case "pong":
|
|
237
|
-
return
|
|
249
|
+
return isNonEmptyString(row.id) && isFiniteNumber(row.sent_at) && isFiniteNumber(row.received_at);
|
|
238
250
|
case "host.registration.update":
|
|
239
|
-
return isStringArray(row.workspace_ids) &&
|
|
251
|
+
return isStringArray(row.workspace_ids) && isNonEmptyString(row.token);
|
|
240
252
|
case "http.request":
|
|
241
|
-
return
|
|
253
|
+
return isNonEmptyString(row.request_id) && isNonEmptyString(row.workspace_id) && isNonEmptyString(row.method) && isNonEmptyString(row.path) && isTunnelHeaderMap(row.headers) && isOptionalBase64(row.body_base64) && typeof row.end === "boolean";
|
|
242
254
|
case "http.response.start":
|
|
243
|
-
return
|
|
255
|
+
return isNonEmptyString(row.request_id) && isHttpStatus(row.status) && isTunnelHeaderMap(row.headers);
|
|
244
256
|
case "http.response.chunk":
|
|
245
|
-
return
|
|
257
|
+
return isNonEmptyString(row.request_id) && isBase64(row.body_base64);
|
|
246
258
|
case "http.response.end":
|
|
247
|
-
return
|
|
259
|
+
return isNonEmptyString(row.request_id);
|
|
248
260
|
case "http.response.flow":
|
|
249
|
-
return
|
|
261
|
+
return isNonEmptyString(row.request_id) && typeof row.paused === "boolean" && (row.reason === void 0 || row.reason === "slow_consumer" || row.reason === "drained" || row.reason === "closed");
|
|
250
262
|
case "ws.open":
|
|
251
|
-
return
|
|
263
|
+
return isNonEmptyString(row.channel_id) && isNonEmptyString(row.workspace_id) && isNonEmptyString(row.path) && isTunnelHeaderMap(row.headers);
|
|
252
264
|
case "ws.frame":
|
|
253
|
-
return
|
|
265
|
+
return isNonEmptyString(row.channel_id) && isBase64(row.data_base64) && typeof row.binary === "boolean";
|
|
254
266
|
case "ws.close":
|
|
255
|
-
return
|
|
267
|
+
return isNonEmptyString(row.channel_id) && (row.code === void 0 || isCloseCode(row.code)) && (row.reason === void 0 || isNonEmptyString(row.reason));
|
|
256
268
|
case "error":
|
|
257
|
-
return (row.request_id === void 0 ||
|
|
269
|
+
return (row.request_id === void 0 || isNonEmptyString(row.request_id)) && (row.channel_id === void 0 || isNonEmptyString(row.channel_id)) && isNonEmptyString(row.code) && isNonEmptyString(row.message);
|
|
258
270
|
default:
|
|
259
271
|
return false;
|
|
260
272
|
}
|
|
261
273
|
}
|
|
262
|
-
function
|
|
274
|
+
function isNonEmptyString(input) {
|
|
263
275
|
return typeof input === "string" && input.length > 0;
|
|
264
276
|
}
|
|
265
277
|
function isStringArray(input) {
|
|
266
|
-
return Array.isArray(input) && input.length > 0 && input.every(
|
|
267
|
-
}
|
|
268
|
-
function isFiniteNumber(input) {
|
|
269
|
-
return typeof input === "number" && Number.isFinite(input);
|
|
278
|
+
return Array.isArray(input) && input.length > 0 && input.every(isNonEmptyString);
|
|
270
279
|
}
|
|
271
280
|
function isHttpStatus(input) {
|
|
272
281
|
return typeof input === "number" && Number.isInteger(input) && input >= 100 && input <= 599;
|
|
@@ -288,10 +297,12 @@ function isBase64(input) {
|
|
|
288
297
|
return typeof input === "string" && /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(input);
|
|
289
298
|
}
|
|
290
299
|
export {
|
|
300
|
+
SESSION_STREAM_LEASE_TTL_MS,
|
|
301
|
+
SESSION_TURN_LEASE_TTL_MS,
|
|
291
302
|
TUNNEL_PROTOCOL_VERSION,
|
|
292
303
|
TokenVerifierError,
|
|
293
|
-
createClerkTokenVerifier,
|
|
294
304
|
createHttpTokenVerifier,
|
|
305
|
+
createOidcTokenVerifier,
|
|
295
306
|
createStaticTokenVerifier,
|
|
296
307
|
isTunnelMessage,
|
|
297
308
|
makeTunnelPing,
|
package/dist/token-verifier.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Unified token-verifier interface (P-shared).
|
|
3
3
|
*
|
|
4
|
-
* Each of the four Claxedo boundaries (relay/tunnel,
|
|
4
|
+
* Each of the four Claxedo boundaries (relay/tunnel, optional modules,
|
|
5
5
|
* SDK runner, workspace host) historically defined its own ad-hoc
|
|
6
6
|
* verifier shape. This module is the single seam every downstream user
|
|
7
7
|
* can swap a custom implementation through.
|
|
@@ -23,13 +23,27 @@ export type TokenVerifierBaseClaims = {
|
|
|
23
23
|
iat: number;
|
|
24
24
|
jti: string;
|
|
25
25
|
} & Record<string, unknown>;
|
|
26
|
-
export type RuntimeAccessVerifierClaims = TokenVerifierBaseClaims & {
|
|
26
|
+
export type RuntimeAccessVerifierClaims = Omit<TokenVerifierBaseClaims, "sub"> & {
|
|
27
27
|
org_id: string;
|
|
28
28
|
role: "viewer" | "editor" | "admin" | "owner";
|
|
29
|
+
principal_kind: "user" | "service";
|
|
30
|
+
actor_id: string;
|
|
31
|
+
actor_kind: "human" | "agent";
|
|
32
|
+
actor_public_id?: string;
|
|
33
|
+
actor_name?: string;
|
|
34
|
+
actor_avatar_url?: string;
|
|
29
35
|
};
|
|
30
|
-
export type RelayHostVerifierClaims = TokenVerifierBaseClaims & {
|
|
36
|
+
export type RelayHostVerifierClaims = Omit<TokenVerifierBaseClaims, "sub"> & {
|
|
31
37
|
org_id: string;
|
|
32
38
|
role: "viewer" | "editor" | "admin" | "owner";
|
|
39
|
+
principal_kind: "user" | "service";
|
|
40
|
+
actor_id: string;
|
|
41
|
+
actor_kind: "human" | "agent";
|
|
42
|
+
actor_public_id?: string;
|
|
43
|
+
actor_name?: string;
|
|
44
|
+
actor_avatar_url?: string;
|
|
45
|
+
/** Durable Runtime Access Token id; distinct from this short-lived RHT jti. */
|
|
46
|
+
parent_jti: string;
|
|
33
47
|
} & ({
|
|
34
48
|
access: "cloud";
|
|
35
49
|
backing: "cloud-vm";
|
|
@@ -38,9 +52,9 @@ export type RelayHostVerifierClaims = TokenVerifierBaseClaims & {
|
|
|
38
52
|
backing: "local-worktree";
|
|
39
53
|
});
|
|
40
54
|
export type TokenClaims<TClaims extends Record<string, unknown> = Record<string, unknown>> = {
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
43
|
-
subject
|
|
55
|
+
/** Provider subject for provider-backed identity verifiers. Runtime and
|
|
56
|
+
* relay-host tokens instead carry canonical actor/principal claims. */
|
|
57
|
+
subject?: string;
|
|
44
58
|
/** Scopes / capabilities asserted by the issuer. May be empty. */
|
|
45
59
|
scopes: string[];
|
|
46
60
|
/** Full claim payload. Carries the common verifier token contract plus
|
|
@@ -50,7 +64,7 @@ export type TokenClaims<TClaims extends Record<string, unknown> = Record<string,
|
|
|
50
64
|
export type TokenVerifier<TClaims extends Record<string, unknown> = Record<string, unknown>> = {
|
|
51
65
|
verify(token: string): Promise<TokenClaims<TClaims>>;
|
|
52
66
|
};
|
|
53
|
-
export type
|
|
67
|
+
export type OidcTokenVerifierClaims = JWTPayload & {
|
|
54
68
|
iss: string;
|
|
55
69
|
sub: string;
|
|
56
70
|
exp: number;
|
|
@@ -83,14 +97,14 @@ export type HttpTokenVerifierOptions = {
|
|
|
83
97
|
timeoutMs?: number;
|
|
84
98
|
};
|
|
85
99
|
export declare function createHttpTokenVerifier(options: HttpTokenVerifierOptions): TokenVerifier<TokenVerifierBaseClaims>;
|
|
86
|
-
export type
|
|
100
|
+
export type OidcTokenVerifierOptions = {
|
|
87
101
|
issuer: string;
|
|
88
102
|
jwksUrl: string;
|
|
89
103
|
audience?: string;
|
|
90
104
|
scopes?: string[];
|
|
91
105
|
algorithms?: Array<"ES256" | "EdDSA" | "RS256">;
|
|
92
106
|
};
|
|
93
|
-
export declare function
|
|
107
|
+
export declare function createOidcTokenVerifier(options: OidcTokenVerifierOptions): TokenVerifier<OidcTokenVerifierClaims>;
|
|
94
108
|
export type StaticTokenVerifierOptions<TClaims extends Record<string, unknown> = Record<string, unknown>> = {
|
|
95
109
|
/** Map of token string → claims to return. */
|
|
96
110
|
tokens: Record<string, TokenClaims<TClaims>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "@claxedo/workspace-relay-protocol",
|
|
3
|
-
"version": "0.7.0",
|
|
4
2
|
"type": "module",
|
|
5
3
|
"description": "Wire types, message validation, and token verifier interfaces for the Claxedo workspace relay tunnel protocol",
|
|
6
4
|
"license": "MIT",
|
|
@@ -19,9 +17,9 @@
|
|
|
19
17
|
"types": "./dist/index.d.ts",
|
|
20
18
|
"exports": {
|
|
21
19
|
".": {
|
|
20
|
+
"development": "./src/index.ts",
|
|
21
|
+
"bun": "./src/index.ts",
|
|
22
22
|
"types": "./dist/index.d.ts",
|
|
23
|
-
"bun": "./dist/index.mjs",
|
|
24
|
-
"development": "./dist/index.mjs",
|
|
25
23
|
"import": "./dist/index.mjs",
|
|
26
24
|
"default": "./dist/index.mjs"
|
|
27
25
|
}
|
|
@@ -34,14 +32,17 @@
|
|
|
34
32
|
"publishConfig": {
|
|
35
33
|
"access": "public"
|
|
36
34
|
},
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
},
|
|
35
|
+
"name": "@claxedo/workspace-relay-protocol",
|
|
36
|
+
"version": "0.8.0",
|
|
40
37
|
"scripts": {
|
|
41
38
|
"build": "tsx scripts/build.ts",
|
|
42
39
|
"prepublishOnly": "npm run build",
|
|
43
40
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
44
|
-
"test": "mkdir -p .artifacts/unit && bun test src --reporter=junit --reporter-outfile=.artifacts/unit/junit.xml"
|
|
41
|
+
"test": "mkdir -p .artifacts/unit && node ../../scripts/test-deadline.mjs bun test src --reporter=junit --reporter-outfile=.artifacts/unit/junit.xml"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@claxedo/helpers": "0.1.0",
|
|
45
|
+
"jose": "6.0.11"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@tsconfig/node-lts": "22.0.4",
|