@claxedo/workspace-relay-protocol 0.6.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 -75
- 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,9 +142,10 @@ function createClerkTokenVerifier(options) {
|
|
|
111
142
|
};
|
|
112
143
|
}
|
|
113
144
|
function createStaticTokenVerifier(options) {
|
|
145
|
+
const tokens = new Map(Object.entries(options.tokens));
|
|
114
146
|
return {
|
|
115
147
|
async verify(token) {
|
|
116
|
-
const claims =
|
|
148
|
+
const claims = tokens.get(token);
|
|
117
149
|
if (!claims) {
|
|
118
150
|
throw new TokenVerifierError({
|
|
119
151
|
code: "token_not_in_static_table",
|
|
@@ -124,16 +156,8 @@ function createStaticTokenVerifier(options) {
|
|
|
124
156
|
}
|
|
125
157
|
};
|
|
126
158
|
}
|
|
127
|
-
function stringClaim(input, key) {
|
|
128
|
-
const value = input[key];
|
|
129
|
-
return typeof value === "string" && value.trim() ? value : void 0;
|
|
130
|
-
}
|
|
131
|
-
function numberClaim(input, key) {
|
|
132
|
-
const value = input[key];
|
|
133
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
134
|
-
}
|
|
135
159
|
function tokenVerifierBaseClaims(input) {
|
|
136
|
-
if (!input
|
|
160
|
+
if (!isRecord(input)) return void 0;
|
|
137
161
|
const iss = stringClaim(input, "iss");
|
|
138
162
|
const aud = stringClaim(input, "aud");
|
|
139
163
|
const sub = stringClaim(input, "sub");
|
|
@@ -142,7 +166,7 @@ function tokenVerifierBaseClaims(input) {
|
|
|
142
166
|
const exp = numberClaim(input, "exp");
|
|
143
167
|
const iat = numberClaim(input, "iat");
|
|
144
168
|
const jti = stringClaim(input, "jti");
|
|
145
|
-
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;
|
|
146
170
|
return {
|
|
147
171
|
...input,
|
|
148
172
|
iss,
|
|
@@ -155,8 +179,11 @@ function tokenVerifierBaseClaims(input) {
|
|
|
155
179
|
jti
|
|
156
180
|
};
|
|
157
181
|
}
|
|
158
|
-
function
|
|
159
|
-
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");
|
|
160
187
|
return {
|
|
161
188
|
...input,
|
|
162
189
|
iss: input.iss,
|
|
@@ -164,9 +191,9 @@ function clerkClaims(input) {
|
|
|
164
191
|
exp: input.exp,
|
|
165
192
|
...input.iat ? { iat: input.iat } : {},
|
|
166
193
|
...typeof input.jti === "string" ? { jti: input.jti } : {},
|
|
167
|
-
...
|
|
168
|
-
...
|
|
169
|
-
...
|
|
194
|
+
...sid ? { sid } : {},
|
|
195
|
+
...org_id ? { org_id } : {},
|
|
196
|
+
...orgId ? { orgId } : {}
|
|
170
197
|
};
|
|
171
198
|
}
|
|
172
199
|
function scopeClaims(input) {
|
|
@@ -177,39 +204,24 @@ function scopeClaims(input) {
|
|
|
177
204
|
|
|
178
205
|
// src/index.ts
|
|
179
206
|
var TUNNEL_PROTOCOL_VERSION = 1;
|
|
180
|
-
var
|
|
181
|
-
|
|
182
|
-
"pong",
|
|
183
|
-
"host.registration.update",
|
|
184
|
-
"http.request",
|
|
185
|
-
"http.response.start",
|
|
186
|
-
"http.response.chunk",
|
|
187
|
-
"http.response.end",
|
|
188
|
-
"http.response.flow",
|
|
189
|
-
"ws.open",
|
|
190
|
-
"ws.frame",
|
|
191
|
-
"ws.close",
|
|
192
|
-
"error"
|
|
193
|
-
]);
|
|
207
|
+
var SESSION_STREAM_LEASE_TTL_MS = 15e3;
|
|
208
|
+
var SESSION_TURN_LEASE_TTL_MS = 6e4;
|
|
194
209
|
function validateTunnelMessage(input) {
|
|
195
|
-
if (!input
|
|
196
|
-
|
|
197
|
-
if (row.protocol !== TUNNEL_PROTOCOL_VERSION) {
|
|
210
|
+
if (!isRecord(input)) return { ok: false, reason: "invalid" };
|
|
211
|
+
if (input.protocol !== TUNNEL_PROTOCOL_VERSION) {
|
|
198
212
|
return {
|
|
199
213
|
ok: false,
|
|
200
214
|
reason: "protocol_mismatch",
|
|
201
215
|
expected_protocol: TUNNEL_PROTOCOL_VERSION,
|
|
202
|
-
actual_protocol:
|
|
203
|
-
...typeof
|
|
216
|
+
actual_protocol: input.protocol,
|
|
217
|
+
...typeof input.type === "string" ? { type: input.type } : {}
|
|
204
218
|
};
|
|
205
219
|
}
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
if (!validateTunnelMessageShape(row)) return { ok: false, reason: "invalid" };
|
|
209
|
-
return { ok: true, message: row };
|
|
220
|
+
if (!isTunnelMessageRecord(input)) return { ok: false, reason: "invalid" };
|
|
221
|
+
return { ok: true, message: input };
|
|
210
222
|
}
|
|
211
223
|
function isTunnelMessage(input) {
|
|
212
|
-
return
|
|
224
|
+
return isRecord(input) && isTunnelMessageRecord(input);
|
|
213
225
|
}
|
|
214
226
|
function makeTunnelPong(input, receivedAt = Date.now()) {
|
|
215
227
|
return {
|
|
@@ -228,44 +240,42 @@ function makeTunnelPing(sentAt = Date.now(), id = crypto.randomUUID()) {
|
|
|
228
240
|
sent_at: sentAt
|
|
229
241
|
};
|
|
230
242
|
}
|
|
231
|
-
function
|
|
243
|
+
function isTunnelMessageRecord(row) {
|
|
244
|
+
if (row.protocol !== TUNNEL_PROTOCOL_VERSION) return false;
|
|
232
245
|
switch (row.type) {
|
|
233
246
|
case "ping":
|
|
234
|
-
return
|
|
247
|
+
return isNonEmptyString(row.id) && isFiniteNumber(row.sent_at);
|
|
235
248
|
case "pong":
|
|
236
|
-
return
|
|
249
|
+
return isNonEmptyString(row.id) && isFiniteNumber(row.sent_at) && isFiniteNumber(row.received_at);
|
|
237
250
|
case "host.registration.update":
|
|
238
|
-
return isStringArray(row.workspace_ids) &&
|
|
251
|
+
return isStringArray(row.workspace_ids) && isNonEmptyString(row.token);
|
|
239
252
|
case "http.request":
|
|
240
|
-
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";
|
|
241
254
|
case "http.response.start":
|
|
242
|
-
return
|
|
255
|
+
return isNonEmptyString(row.request_id) && isHttpStatus(row.status) && isTunnelHeaderMap(row.headers);
|
|
243
256
|
case "http.response.chunk":
|
|
244
|
-
return
|
|
257
|
+
return isNonEmptyString(row.request_id) && isBase64(row.body_base64);
|
|
245
258
|
case "http.response.end":
|
|
246
|
-
return
|
|
259
|
+
return isNonEmptyString(row.request_id);
|
|
247
260
|
case "http.response.flow":
|
|
248
|
-
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");
|
|
249
262
|
case "ws.open":
|
|
250
|
-
return
|
|
263
|
+
return isNonEmptyString(row.channel_id) && isNonEmptyString(row.workspace_id) && isNonEmptyString(row.path) && isTunnelHeaderMap(row.headers);
|
|
251
264
|
case "ws.frame":
|
|
252
|
-
return
|
|
265
|
+
return isNonEmptyString(row.channel_id) && isBase64(row.data_base64) && typeof row.binary === "boolean";
|
|
253
266
|
case "ws.close":
|
|
254
|
-
return
|
|
267
|
+
return isNonEmptyString(row.channel_id) && (row.code === void 0 || isCloseCode(row.code)) && (row.reason === void 0 || isNonEmptyString(row.reason));
|
|
255
268
|
case "error":
|
|
256
|
-
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);
|
|
257
270
|
default:
|
|
258
271
|
return false;
|
|
259
272
|
}
|
|
260
273
|
}
|
|
261
|
-
function
|
|
274
|
+
function isNonEmptyString(input) {
|
|
262
275
|
return typeof input === "string" && input.length > 0;
|
|
263
276
|
}
|
|
264
277
|
function isStringArray(input) {
|
|
265
|
-
return Array.isArray(input) && input.length > 0 && input.every(
|
|
266
|
-
}
|
|
267
|
-
function isFiniteNumber(input) {
|
|
268
|
-
return typeof input === "number" && Number.isFinite(input);
|
|
278
|
+
return Array.isArray(input) && input.length > 0 && input.every(isNonEmptyString);
|
|
269
279
|
}
|
|
270
280
|
function isHttpStatus(input) {
|
|
271
281
|
return typeof input === "number" && Number.isInteger(input) && input >= 100 && input <= 599;
|
|
@@ -287,10 +297,12 @@ function isBase64(input) {
|
|
|
287
297
|
return typeof input === "string" && /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(input);
|
|
288
298
|
}
|
|
289
299
|
export {
|
|
300
|
+
SESSION_STREAM_LEASE_TTL_MS,
|
|
301
|
+
SESSION_TURN_LEASE_TTL_MS,
|
|
290
302
|
TUNNEL_PROTOCOL_VERSION,
|
|
291
303
|
TokenVerifierError,
|
|
292
|
-
createClerkTokenVerifier,
|
|
293
304
|
createHttpTokenVerifier,
|
|
305
|
+
createOidcTokenVerifier,
|
|
294
306
|
createStaticTokenVerifier,
|
|
295
307
|
isTunnelMessage,
|
|
296
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.6.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": "bun test src"
|
|
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",
|