@astralbeam/sdk 0.0.1 → 0.0.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 +152 -4
- package/dist/chat-DdU0uj9s.js +65 -0
- package/dist/client-utils-DyEcBInP.js +1 -0
- package/dist/client.d.ts +127 -2
- package/dist/client.js +1 -4
- package/dist/react.d.ts +45 -2
- package/dist/react.js +91 -3
- package/dist/server.d.ts +31 -2
- package/dist/server.js +692 -2
- package/package.json +29 -5
package/dist/server.js
CHANGED
|
@@ -1,4 +1,694 @@
|
|
|
1
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
2
|
+
const encoder = new TextEncoder();
|
|
3
|
+
const decoder = new TextDecoder();
|
|
4
|
+
new TextDecoder("utf-8", { fatal: true });
|
|
5
|
+
function concat(...buffers) {
|
|
6
|
+
const size = buffers.reduce((acc, { length }) => acc + length, 0);
|
|
7
|
+
const buf = new Uint8Array(size);
|
|
8
|
+
let i = 0;
|
|
9
|
+
for (const buffer of buffers) {
|
|
10
|
+
buf.set(buffer, i);
|
|
11
|
+
i += buffer.length;
|
|
12
|
+
}
|
|
13
|
+
return buf;
|
|
14
|
+
}
|
|
15
|
+
function encode$1(string) {
|
|
16
|
+
const bytes = new Uint8Array(string.length);
|
|
17
|
+
for (let i = 0; i < string.length; i++) {
|
|
18
|
+
const code = string.charCodeAt(i);
|
|
19
|
+
if (code > 127) throw new TypeError("non-ASCII string encountered in encode()");
|
|
20
|
+
bytes[i] = code;
|
|
21
|
+
}
|
|
22
|
+
return bytes;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/crypto_key.js
|
|
26
|
+
const unusable = (name, prop = "algorithm.name") => /* @__PURE__ */ new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
27
|
+
function checkUsage(key, usage) {
|
|
28
|
+
if (usage && !key.usages.includes(usage)) throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
|
|
29
|
+
}
|
|
30
|
+
function checkModulusLength(alg, key) {
|
|
31
|
+
const { modulusLength } = key.algorithm;
|
|
32
|
+
if (typeof modulusLength !== "number" || modulusLength < 2048) throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
33
|
+
}
|
|
34
|
+
function checkCryptoKey(key, expected, usage) {
|
|
35
|
+
const algorithm = key.algorithm;
|
|
36
|
+
if (algorithm.name !== expected.name) throw unusable(expected.name);
|
|
37
|
+
if (expected.hash && algorithm.hash?.name !== expected.hash) throw unusable(expected.hash, "algorithm.hash");
|
|
38
|
+
if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve) throw unusable(expected.namedCurve, "algorithm.namedCurve");
|
|
39
|
+
if (expected.length !== void 0 && algorithm.length !== expected.length) throw unusable(expected.length, "algorithm.length");
|
|
40
|
+
checkUsage(key, usage);
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/invalid_key_input.js
|
|
44
|
+
function message(msg, actual, ...types) {
|
|
45
|
+
if (types.length > 2) {
|
|
46
|
+
const last = types.pop();
|
|
47
|
+
msg += `one of type ${types.join(", ")}, or ${last}.`;
|
|
48
|
+
} else if (types.length === 2) msg += `one of type ${types[0]} or ${types[1]}.`;
|
|
49
|
+
else msg += `of type ${types[0]}.`;
|
|
50
|
+
if (actual == null) msg += ` Received ${actual}`;
|
|
51
|
+
else if (typeof actual === "function" && actual.name) msg += ` Received function ${actual.name}`;
|
|
52
|
+
else if (typeof actual === "object" && actual != null) {
|
|
53
|
+
if (actual.constructor?.name) msg += ` Received an instance of ${actual.constructor.name}`;
|
|
54
|
+
}
|
|
55
|
+
return msg;
|
|
56
|
+
}
|
|
57
|
+
const withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/util/errors.js
|
|
60
|
+
var JOSEError = class extends Error {
|
|
61
|
+
static code = "ERR_JOSE_GENERIC";
|
|
62
|
+
code = "ERR_JOSE_GENERIC";
|
|
63
|
+
constructor(message, options) {
|
|
64
|
+
super(message, options);
|
|
65
|
+
this.name = this.constructor.name;
|
|
66
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var JOSENotSupported = class extends JOSEError {
|
|
70
|
+
static code = "ERR_JOSE_NOT_SUPPORTED";
|
|
71
|
+
code = "ERR_JOSE_NOT_SUPPORTED";
|
|
72
|
+
};
|
|
73
|
+
var JWSInvalid = class extends JOSEError {
|
|
74
|
+
static code = "ERR_JWS_INVALID";
|
|
75
|
+
code = "ERR_JWS_INVALID";
|
|
76
|
+
};
|
|
77
|
+
var JWTInvalid = class extends JOSEError {
|
|
78
|
+
static code = "ERR_JWT_INVALID";
|
|
79
|
+
code = "ERR_JWT_INVALID";
|
|
80
|
+
};
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/is_key_like.js
|
|
83
|
+
const isCryptoKey = (key) => {
|
|
84
|
+
if (key?.[Symbol.toStringTag] === "CryptoKey") return true;
|
|
85
|
+
try {
|
|
86
|
+
return key instanceof CryptoKey;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
|
|
92
|
+
const isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/base64.js
|
|
95
|
+
function encodeBase64(input) {
|
|
96
|
+
if (Uint8Array.prototype.toBase64) return input.toBase64();
|
|
97
|
+
const CHUNK_SIZE = 32768;
|
|
98
|
+
const arr = [];
|
|
99
|
+
for (let i = 0; i < input.length; i += CHUNK_SIZE) arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
|
|
100
|
+
return btoa(arr.join(""));
|
|
101
|
+
}
|
|
102
|
+
function decodeBase64(encoded) {
|
|
103
|
+
if (Uint8Array.fromBase64) return Uint8Array.fromBase64(encoded);
|
|
104
|
+
const binary = atob(encoded);
|
|
105
|
+
const bytes = new Uint8Array(binary.length);
|
|
106
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
107
|
+
return bytes;
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/util/base64url.js
|
|
111
|
+
const invalid = "The input to be decoded is not correctly encoded.";
|
|
112
|
+
function decode(input) {
|
|
113
|
+
if (Uint8Array.fromBase64) try {
|
|
114
|
+
return Uint8Array.fromBase64(typeof input === "string" ? input : decoder.decode(input), { alphabet: "base64url" });
|
|
115
|
+
} catch (cause) {
|
|
116
|
+
throw new TypeError(invalid, { cause });
|
|
117
|
+
}
|
|
118
|
+
let encoded = input;
|
|
119
|
+
if (encoded instanceof Uint8Array) encoded = decoder.decode(encoded);
|
|
120
|
+
if (encoded.includes("+") || encoded.includes("/")) throw new TypeError(invalid);
|
|
121
|
+
encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
122
|
+
try {
|
|
123
|
+
return decodeBase64(encoded);
|
|
124
|
+
} catch {
|
|
125
|
+
throw new TypeError(invalid);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function encode(input) {
|
|
129
|
+
let unencoded = input;
|
|
130
|
+
if (typeof unencoded === "string") unencoded = encoder.encode(unencoded);
|
|
131
|
+
if (Uint8Array.prototype.toBase64) return unencoded.toBase64({
|
|
132
|
+
alphabet: "base64url",
|
|
133
|
+
omitPadding: true
|
|
134
|
+
});
|
|
135
|
+
return encodeBase64(unencoded).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
136
|
+
}
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/type_checks.js
|
|
139
|
+
function isObject(input) {
|
|
140
|
+
if (typeof input !== "object" || input === null || Object.prototype.toString.call(input) !== "[object Object]") return false;
|
|
141
|
+
const prototype = Object.getPrototypeOf(input);
|
|
142
|
+
if (prototype === null) return true;
|
|
143
|
+
let proto = prototype;
|
|
144
|
+
while (Object.getPrototypeOf(proto) !== null) proto = Object.getPrototypeOf(proto);
|
|
145
|
+
return prototype === proto;
|
|
146
|
+
}
|
|
147
|
+
function isDisjoint(...headers) {
|
|
148
|
+
const parameters = /* @__PURE__ */ new Set();
|
|
149
|
+
for (const header of headers) {
|
|
150
|
+
if (!header) continue;
|
|
151
|
+
for (const parameter of Object.keys(header)) {
|
|
152
|
+
if (parameters.has(parameter)) return false;
|
|
153
|
+
parameters.add(parameter);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
const isJWK = (key) => isObject(key) && typeof key.kty === "string";
|
|
159
|
+
const isPrivateJWK = (key) => key.kty !== "oct" && (key.kty === "AKP" && typeof key.priv === "string" || typeof key.d === "string");
|
|
160
|
+
const isPublicJWK = (key) => key.kty !== "oct" && key.d === void 0 && key.priv === void 0;
|
|
161
|
+
const isSecretJWK = (key) => key.kty === "oct" && typeof key.k === "string";
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/helpers.js
|
|
164
|
+
function assertNotSet(value, name) {
|
|
165
|
+
if (value) throw new TypeError(`${name} can only be called once`);
|
|
166
|
+
}
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/jwk_to_key.js
|
|
169
|
+
async function jwkToKey(entry, jwk) {
|
|
170
|
+
if (jwk.kty === "RSA" && "oth" in jwk && jwk.oth !== void 0) throw new JOSENotSupported("RSA JWK \"oth\" (Other Primes Info) Parameter value is not supported");
|
|
171
|
+
if (!entry.kty.includes(jwk.kty)) throw new JOSENotSupported("Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value");
|
|
172
|
+
const algorithm = entry.resolve?.({
|
|
173
|
+
kty: jwk.kty,
|
|
174
|
+
crv: jwk.crv
|
|
175
|
+
}) ?? entry.subtle;
|
|
176
|
+
const isPrivate = !!(jwk.d || jwk.priv);
|
|
177
|
+
const keyData = { ...jwk };
|
|
178
|
+
if (keyData.kty !== "AKP") delete keyData.alg;
|
|
179
|
+
delete keyData.use;
|
|
180
|
+
return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/key.js
|
|
184
|
+
const tag = (key) => key[Symbol.toStringTag];
|
|
185
|
+
const jwkMatchesOp = (entry, key, usage) => {
|
|
186
|
+
const { alg } = entry;
|
|
187
|
+
if (key.use !== void 0) {
|
|
188
|
+
const expected = usage === "sign" || usage === "verify" ? "sig" : "enc";
|
|
189
|
+
if (key.use !== expected) throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
|
|
190
|
+
}
|
|
191
|
+
if (key.alg !== void 0 && key.alg !== alg) throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
|
|
192
|
+
if (Array.isArray(key.key_ops)) {
|
|
193
|
+
const expectedKeyOp = usage === "encrypt" || usage === "decrypt" ? entry.ops?.[usage === "encrypt" ? 0 : 1] : usage;
|
|
194
|
+
if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp)) throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
function checkKeyType(entry, key, usage) {
|
|
198
|
+
const { alg, secret } = entry;
|
|
199
|
+
const privateKey = usage === "decrypt" || usage === "sign";
|
|
200
|
+
if (secret && key instanceof Uint8Array) return [BYTES, key];
|
|
201
|
+
if (isJWK(key)) {
|
|
202
|
+
if (secret ? !isSecretJWK(key) : !(privateKey ? isPrivateJWK(key) : isPublicJWK(key))) throw new TypeError(secret ? `JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present` : `JSON Web Key for this operation must be a ${privateKey ? "private" : "public"} JWK`);
|
|
203
|
+
jwkMatchesOp(entry, key, usage);
|
|
204
|
+
return [JWK, key];
|
|
205
|
+
}
|
|
206
|
+
if (!isKeyLike(key)) throw new TypeError(secret ? withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array") : withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
207
|
+
if (secret) {
|
|
208
|
+
if (key.type !== "secret") throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
209
|
+
} else {
|
|
210
|
+
if (key.type === "secret") throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
|
|
211
|
+
const expectedType = privateKey ? "private" : "public";
|
|
212
|
+
if ((key.type === "public" || key.type === "private") && key.type !== expectedType) {
|
|
213
|
+
const operation = usage === "sign" ? "signing" : usage === "verify" ? "verifying" : `${usage.slice(0, -1)}tion`;
|
|
214
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm ${operation} must be of type "${expectedType}"`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return isCryptoKey(key) ? [CRYPTO, key] : [KEYOBJECT, key];
|
|
218
|
+
}
|
|
219
|
+
const BYTES = 0;
|
|
220
|
+
const CRYPTO = 1;
|
|
221
|
+
const KEYOBJECT = 2;
|
|
222
|
+
const JWK = 3;
|
|
223
|
+
let cache;
|
|
224
|
+
const nist = {
|
|
225
|
+
__proto__: null,
|
|
226
|
+
prime256v1: "P-256",
|
|
227
|
+
secp384r1: "P-384",
|
|
228
|
+
secp521r1: "P-521"
|
|
229
|
+
};
|
|
230
|
+
function cached(key, alg, value) {
|
|
231
|
+
cache ||= /* @__PURE__ */ new WeakMap();
|
|
232
|
+
const entry = cache.get(key);
|
|
233
|
+
if (value) if (entry) entry[alg] = value;
|
|
234
|
+
else cache.set(key, {
|
|
235
|
+
__proto__: null,
|
|
236
|
+
[alg]: value
|
|
237
|
+
});
|
|
238
|
+
return value ?? entry?.[alg];
|
|
239
|
+
}
|
|
240
|
+
const handleJWK = async (key, jwk, entry) => cached(key, entry.alg) ?? cached(key, entry.alg, await jwkToKey(entry, {
|
|
241
|
+
...jwk,
|
|
242
|
+
alg: entry.alg
|
|
243
|
+
}));
|
|
244
|
+
const handleKeyObject = (keyObject, entry) => {
|
|
245
|
+
const hit = cached(keyObject, entry.alg);
|
|
246
|
+
if (hit) return hit;
|
|
247
|
+
const isPublic = keyObject.type === "public";
|
|
248
|
+
const usages = entry.usages[isPublic ? 0 : 1];
|
|
249
|
+
const { asymmetricKeyType } = keyObject;
|
|
250
|
+
const crv = nist[keyObject.asymmetricKeyDetails?.namedCurve];
|
|
251
|
+
const params = entry.resolve?.({
|
|
252
|
+
crv,
|
|
253
|
+
asymmetricKeyType
|
|
254
|
+
}) ?? entry.subtle;
|
|
255
|
+
return cached(keyObject, entry.alg, keyObject.toCryptoKey(params, isPublic, usages));
|
|
256
|
+
};
|
|
257
|
+
async function prepareKey(entry, key, usage) {
|
|
258
|
+
const tagged = checkKeyType(entry, key, usage);
|
|
259
|
+
switch (tagged[0]) {
|
|
260
|
+
case BYTES:
|
|
261
|
+
case CRYPTO: return tagged[1];
|
|
262
|
+
case JWK: {
|
|
263
|
+
const key = tagged[1];
|
|
264
|
+
if (key.k) return decode(key.k);
|
|
265
|
+
if (!Object.isFrozen(key)) {
|
|
266
|
+
const { key_ops } = key;
|
|
267
|
+
if (Array.isArray(key_ops)) Object.freeze(key_ops);
|
|
268
|
+
Object.freeze(key);
|
|
269
|
+
}
|
|
270
|
+
return handleJWK(key, key, entry);
|
|
271
|
+
}
|
|
272
|
+
case KEYOBJECT: {
|
|
273
|
+
const keyObject = tagged[1];
|
|
274
|
+
if (keyObject.type === "secret") return keyObject.export();
|
|
275
|
+
if ("toCryptoKey" in keyObject && typeof keyObject.toCryptoKey === "function") return handleKeyObject(keyObject, entry);
|
|
276
|
+
return handleJWK(keyObject, keyObject.export({ format: "jwk" }), entry);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/key_descriptor.js
|
|
282
|
+
function table(entries) {
|
|
283
|
+
const out = { __proto__: null };
|
|
284
|
+
for (const alg in entries) out[alg] = {
|
|
285
|
+
...entries[alg],
|
|
286
|
+
alg
|
|
287
|
+
};
|
|
288
|
+
return out;
|
|
289
|
+
}
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/options.js
|
|
292
|
+
const JWS_RECOGNIZED = {
|
|
293
|
+
__proto__: null,
|
|
294
|
+
b64: true
|
|
295
|
+
};
|
|
296
|
+
function validateCritDuplicates(Err, protectedHeader) {
|
|
297
|
+
const { crit } = protectedHeader ?? {};
|
|
298
|
+
if (Array.isArray(crit) && new Set(crit).size !== crit.length) throw new Err("\"crit\" (Critical) Header Parameter MUST NOT contain duplicate values");
|
|
299
|
+
}
|
|
300
|
+
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
301
|
+
if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) throw new Err("\"crit\" (Critical) Header Parameter MUST be integrity protected");
|
|
302
|
+
if (!protectedHeader || protectedHeader.crit === void 0) return [];
|
|
303
|
+
if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) throw new Err("\"crit\" (Critical) Header Parameter MUST be an array of non-empty strings when present");
|
|
304
|
+
const recognized = recognizedOption === void 0 ? recognizedDefault : {
|
|
305
|
+
__proto__: null,
|
|
306
|
+
...recognizedOption,
|
|
307
|
+
...recognizedDefault
|
|
308
|
+
};
|
|
309
|
+
for (const parameter of protectedHeader.crit) {
|
|
310
|
+
if (!(parameter in recognized)) throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|
311
|
+
if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === void 0) throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|
312
|
+
if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === void 0)) throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|
313
|
+
}
|
|
314
|
+
return protectedHeader.crit;
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/signing.js
|
|
318
|
+
async function getSigKey(entry, key, usage) {
|
|
319
|
+
if (key instanceof Uint8Array) return crypto.subtle.importKey("raw", key, entry.subtle, false, [usage]);
|
|
320
|
+
checkCryptoKey(key, entry.subtle, usage);
|
|
321
|
+
if (entry.minRsaBits) checkModulusLength(entry.alg, key);
|
|
322
|
+
return key;
|
|
323
|
+
}
|
|
324
|
+
async function sign(entry, key, data) {
|
|
325
|
+
const cryptoKey = await getSigKey(entry, key, "sign");
|
|
326
|
+
const signature = await crypto.subtle.sign(entry.signing, cryptoKey, data);
|
|
327
|
+
return new Uint8Array(signature);
|
|
328
|
+
}
|
|
329
|
+
//#endregion
|
|
330
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/jws_algorithms.js
|
|
331
|
+
const sig = [["verify"], ["sign"]];
|
|
332
|
+
function hmac(bits) {
|
|
333
|
+
const subtle = {
|
|
334
|
+
name: "HMAC",
|
|
335
|
+
hash: `SHA-${bits}`
|
|
336
|
+
};
|
|
337
|
+
return {
|
|
338
|
+
kty: ["oct"],
|
|
339
|
+
secret: true,
|
|
340
|
+
subtle,
|
|
341
|
+
signing: subtle,
|
|
342
|
+
usages: sig
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function rsa(bits, saltLength) {
|
|
346
|
+
const subtle = {
|
|
347
|
+
name: saltLength ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
|
|
348
|
+
hash: `SHA-${bits}`
|
|
349
|
+
};
|
|
350
|
+
return {
|
|
351
|
+
kty: ["RSA"],
|
|
352
|
+
subtle,
|
|
353
|
+
signing: saltLength ? {
|
|
354
|
+
...subtle,
|
|
355
|
+
saltLength
|
|
356
|
+
} : subtle,
|
|
357
|
+
usages: sig,
|
|
358
|
+
minRsaBits: 2048
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
function ecdsa(crv, bits) {
|
|
362
|
+
return {
|
|
363
|
+
kty: ["EC"],
|
|
364
|
+
crv,
|
|
365
|
+
subtle: {
|
|
366
|
+
name: "ECDSA",
|
|
367
|
+
namedCurve: crv
|
|
368
|
+
},
|
|
369
|
+
signing: {
|
|
370
|
+
name: "ECDSA",
|
|
371
|
+
hash: `SHA-${bits}`
|
|
372
|
+
},
|
|
373
|
+
usages: sig
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
function eddsa() {
|
|
377
|
+
const subtle = { name: "Ed25519" };
|
|
378
|
+
return {
|
|
379
|
+
kty: ["OKP"],
|
|
380
|
+
crv: "Ed25519",
|
|
381
|
+
subtle,
|
|
382
|
+
signing: subtle,
|
|
383
|
+
usages: sig
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
function mldsa(bits) {
|
|
387
|
+
const subtle = { name: `ML-DSA-${bits}` };
|
|
388
|
+
return {
|
|
389
|
+
kty: ["AKP"],
|
|
390
|
+
subtle,
|
|
391
|
+
signing: subtle,
|
|
392
|
+
usages: sig
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
const JWS = table({
|
|
396
|
+
HS256: hmac(256),
|
|
397
|
+
HS384: hmac(384),
|
|
398
|
+
HS512: hmac(512),
|
|
399
|
+
RS256: rsa(256),
|
|
400
|
+
RS384: rsa(384),
|
|
401
|
+
RS512: rsa(512),
|
|
402
|
+
PS256: rsa(256, 32),
|
|
403
|
+
PS384: rsa(384, 48),
|
|
404
|
+
PS512: rsa(512, 64),
|
|
405
|
+
ES256: ecdsa("P-256", 256),
|
|
406
|
+
ES384: ecdsa("P-384", 384),
|
|
407
|
+
ES512: ecdsa("P-521", 512),
|
|
408
|
+
EdDSA: eddsa(),
|
|
409
|
+
Ed25519: eddsa(),
|
|
410
|
+
"ML-DSA-44": mldsa(44),
|
|
411
|
+
"ML-DSA-65": mldsa(65),
|
|
412
|
+
"ML-DSA-87": mldsa(87)
|
|
413
|
+
});
|
|
414
|
+
function jwsAlgorithm(alg) {
|
|
415
|
+
const entry = typeof alg === "string" ? JWS[alg] : void 0;
|
|
416
|
+
if (!entry) throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
417
|
+
return entry;
|
|
418
|
+
}
|
|
419
|
+
//#endregion
|
|
420
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/jwt_claims_set.js
|
|
421
|
+
const epoch = (date) => Math.floor(date.getTime() / 1e3);
|
|
422
|
+
const multipliers = {
|
|
423
|
+
s: 1,
|
|
424
|
+
m: 60,
|
|
425
|
+
h: 3600,
|
|
426
|
+
d: 86400,
|
|
427
|
+
w: 604800,
|
|
428
|
+
y: 31557600
|
|
429
|
+
};
|
|
430
|
+
const REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
|
|
431
|
+
function secs(str) {
|
|
432
|
+
const matched = REGEX.exec(str);
|
|
433
|
+
if (!matched || matched[4] && matched[1]) throw new TypeError("Invalid time period format");
|
|
434
|
+
const value = parseFloat(matched[2]);
|
|
435
|
+
const numericDate = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
|
|
436
|
+
if (matched[1] === "-" || matched[4] === "ago") return -numericDate;
|
|
437
|
+
return numericDate;
|
|
438
|
+
}
|
|
439
|
+
function validateInput(label, input) {
|
|
440
|
+
if (!Number.isFinite(input)) throw new TypeError(`Invalid ${label} input`);
|
|
441
|
+
return input;
|
|
442
|
+
}
|
|
443
|
+
function numericDate(value, label) {
|
|
444
|
+
if (typeof value === "number") return validateInput(label, value);
|
|
445
|
+
if (value instanceof Date) return validateInput(label, epoch(value));
|
|
446
|
+
return epoch(/* @__PURE__ */ new Date()) + secs(value);
|
|
447
|
+
}
|
|
448
|
+
var JWTClaimsBuilder = class {
|
|
449
|
+
#payload;
|
|
450
|
+
constructor(payload) {
|
|
451
|
+
if (!isObject(payload)) throw new TypeError("JWT Claims Set MUST be an object");
|
|
452
|
+
this.#payload = structuredClone(payload);
|
|
453
|
+
}
|
|
454
|
+
data() {
|
|
455
|
+
return encoder.encode(JSON.stringify(this.#payload));
|
|
456
|
+
}
|
|
457
|
+
get iss() {
|
|
458
|
+
return this.#payload.iss;
|
|
459
|
+
}
|
|
460
|
+
set iss(value) {
|
|
461
|
+
this.#payload.iss = value;
|
|
462
|
+
}
|
|
463
|
+
get sub() {
|
|
464
|
+
return this.#payload.sub;
|
|
465
|
+
}
|
|
466
|
+
set sub(value) {
|
|
467
|
+
this.#payload.sub = value;
|
|
468
|
+
}
|
|
469
|
+
get aud() {
|
|
470
|
+
return this.#payload.aud;
|
|
471
|
+
}
|
|
472
|
+
set aud(value) {
|
|
473
|
+
this.#payload.aud = value;
|
|
474
|
+
}
|
|
475
|
+
set jti(value) {
|
|
476
|
+
this.#payload.jti = value;
|
|
477
|
+
}
|
|
478
|
+
set nbf(value) {
|
|
479
|
+
this.#payload.nbf = numericDate(value, "setNotBefore");
|
|
480
|
+
}
|
|
481
|
+
set exp(value) {
|
|
482
|
+
this.#payload.exp = numericDate(value, "setExpirationTime");
|
|
483
|
+
}
|
|
484
|
+
set iat(value) {
|
|
485
|
+
if (value === void 0) this.#payload.iat = epoch(/* @__PURE__ */ new Date());
|
|
486
|
+
else if (typeof value === "string") this.#payload.iat = validateInput("setIssuedAt", epoch(/* @__PURE__ */ new Date()) + secs(value));
|
|
487
|
+
else this.#payload.iat = numericDate(value, "setIssuedAt");
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
//#endregion
|
|
491
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/lib/jws_sign.js
|
|
492
|
+
function unencodedPayload(protectedHeader) {
|
|
493
|
+
return protectedHeader?.b64 === false && Array.isArray(protectedHeader.crit) && protectedHeader.crit.includes("b64");
|
|
494
|
+
}
|
|
495
|
+
async function createSignature(input, key) {
|
|
496
|
+
const { protectedHeader, unprotectedHeader } = input;
|
|
497
|
+
if (!protectedHeader && !unprotectedHeader) throw new JWSInvalid("either setProtectedHeader or setUnprotectedHeader must be called before #sign()");
|
|
498
|
+
if (!isDisjoint(protectedHeader, unprotectedHeader)) throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
499
|
+
const joseHeader = {
|
|
500
|
+
...protectedHeader,
|
|
501
|
+
...unprotectedHeader
|
|
502
|
+
};
|
|
503
|
+
validateCritDuplicates(JWSInvalid, protectedHeader);
|
|
504
|
+
const extensions = validateCrit(JWSInvalid, JWS_RECOGNIZED, input.crit, protectedHeader, joseHeader);
|
|
505
|
+
let b64 = true;
|
|
506
|
+
if (extensions.includes("b64")) {
|
|
507
|
+
b64 = protectedHeader.b64;
|
|
508
|
+
if (typeof b64 !== "boolean") throw new JWSInvalid("The \"b64\" (base64url-encode payload) Header Parameter must be a boolean");
|
|
509
|
+
}
|
|
510
|
+
const { alg } = joseHeader;
|
|
511
|
+
if (typeof alg !== "string" || !alg) throw new JWSInvalid("JWS \"alg\" (Algorithm) Header Parameter missing or invalid");
|
|
512
|
+
const entry = jwsAlgorithm(alg);
|
|
513
|
+
let payloadS;
|
|
514
|
+
let payloadB;
|
|
515
|
+
if (b64) {
|
|
516
|
+
const encoded = input.encoded ??= [];
|
|
517
|
+
encoded[0] ??= encode(input.payload);
|
|
518
|
+
encoded[1] ??= encode$1(encoded[0]);
|
|
519
|
+
payloadS = encoded[0];
|
|
520
|
+
payloadB = encoded[1];
|
|
521
|
+
} else {
|
|
522
|
+
payloadB = input.payload;
|
|
523
|
+
payloadS = "";
|
|
524
|
+
}
|
|
525
|
+
let protectedHeaderString;
|
|
526
|
+
let protectedHeaderBytes;
|
|
527
|
+
if (protectedHeader) {
|
|
528
|
+
protectedHeaderString = encode(JSON.stringify(protectedHeader));
|
|
529
|
+
protectedHeaderBytes = encode$1(protectedHeaderString);
|
|
530
|
+
} else {
|
|
531
|
+
protectedHeaderString = "";
|
|
532
|
+
protectedHeaderBytes = /* @__PURE__ */ new Uint8Array();
|
|
533
|
+
}
|
|
534
|
+
const data = concat(protectedHeaderBytes, encode$1("."), payloadB);
|
|
535
|
+
const jws = {
|
|
536
|
+
signature: encode(await sign(entry, await prepareKey(entry, key, "sign"), data)),
|
|
537
|
+
payload: payloadS
|
|
538
|
+
};
|
|
539
|
+
if (protectedHeader) jws.protected = protectedHeaderString;
|
|
540
|
+
if (unprotectedHeader) jws.header = unprotectedHeader;
|
|
541
|
+
return jws;
|
|
542
|
+
}
|
|
543
|
+
//#endregion
|
|
544
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/jws/flattened/sign.js
|
|
545
|
+
var FlattenedSign = class {
|
|
546
|
+
#payload;
|
|
547
|
+
#protectedHeader;
|
|
548
|
+
#unprotectedHeader;
|
|
549
|
+
constructor(payload) {
|
|
550
|
+
if (!(payload instanceof Uint8Array)) throw new TypeError("payload must be an instance of Uint8Array");
|
|
551
|
+
this.#payload = payload;
|
|
552
|
+
}
|
|
553
|
+
setProtectedHeader(protectedHeader) {
|
|
554
|
+
assertNotSet(this.#protectedHeader, "setProtectedHeader");
|
|
555
|
+
this.#protectedHeader = protectedHeader;
|
|
556
|
+
return this;
|
|
557
|
+
}
|
|
558
|
+
setUnprotectedHeader(unprotectedHeader) {
|
|
559
|
+
assertNotSet(this.#unprotectedHeader, "setUnprotectedHeader");
|
|
560
|
+
this.#unprotectedHeader = unprotectedHeader;
|
|
561
|
+
return this;
|
|
562
|
+
}
|
|
563
|
+
async sign(key, options) {
|
|
564
|
+
return createSignature({
|
|
565
|
+
payload: this.#payload,
|
|
566
|
+
protectedHeader: this.#protectedHeader,
|
|
567
|
+
unprotectedHeader: this.#unprotectedHeader,
|
|
568
|
+
crit: options?.crit
|
|
569
|
+
}, key);
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
//#endregion
|
|
573
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/jws/compact/sign.js
|
|
574
|
+
var CompactSign = class {
|
|
575
|
+
#flattened;
|
|
576
|
+
#protectedHeader;
|
|
577
|
+
constructor(payload) {
|
|
578
|
+
this.#flattened = new FlattenedSign(payload);
|
|
579
|
+
}
|
|
580
|
+
setProtectedHeader(protectedHeader) {
|
|
581
|
+
this.#flattened.setProtectedHeader(protectedHeader);
|
|
582
|
+
this.#protectedHeader = protectedHeader;
|
|
583
|
+
return this;
|
|
584
|
+
}
|
|
585
|
+
async sign(key, options) {
|
|
586
|
+
if (unencodedPayload(this.#protectedHeader)) throw new TypeError("use the flattened module for creating JWS with b64: false");
|
|
587
|
+
const jws = await this.#flattened.sign(key, options);
|
|
588
|
+
return `${jws.protected}.${jws.payload}.${jws.signature}`;
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
//#endregion
|
|
592
|
+
//#region node_modules/.deno/jose@6.2.9/node_modules/jose/dist/webapi/jwt/sign.js
|
|
593
|
+
var SignJWT = class {
|
|
594
|
+
#protectedHeader;
|
|
595
|
+
#jwt;
|
|
596
|
+
constructor(payload = {}) {
|
|
597
|
+
this.#jwt = new JWTClaimsBuilder(payload);
|
|
598
|
+
}
|
|
599
|
+
setIssuer(issuer) {
|
|
600
|
+
this.#jwt.iss = issuer;
|
|
601
|
+
return this;
|
|
602
|
+
}
|
|
603
|
+
setSubject(subject) {
|
|
604
|
+
this.#jwt.sub = subject;
|
|
605
|
+
return this;
|
|
606
|
+
}
|
|
607
|
+
setAudience(audience) {
|
|
608
|
+
this.#jwt.aud = audience;
|
|
609
|
+
return this;
|
|
610
|
+
}
|
|
611
|
+
setJti(jwtId) {
|
|
612
|
+
this.#jwt.jti = jwtId;
|
|
613
|
+
return this;
|
|
614
|
+
}
|
|
615
|
+
setNotBefore(input) {
|
|
616
|
+
this.#jwt.nbf = input;
|
|
617
|
+
return this;
|
|
618
|
+
}
|
|
619
|
+
setExpirationTime(input) {
|
|
620
|
+
this.#jwt.exp = input;
|
|
621
|
+
return this;
|
|
622
|
+
}
|
|
623
|
+
setIssuedAt(input) {
|
|
624
|
+
this.#jwt.iat = input;
|
|
625
|
+
return this;
|
|
626
|
+
}
|
|
627
|
+
setProtectedHeader(protectedHeader) {
|
|
628
|
+
this.#protectedHeader = protectedHeader;
|
|
629
|
+
return this;
|
|
630
|
+
}
|
|
631
|
+
async sign(key, options) {
|
|
632
|
+
const sig = new CompactSign(this.#jwt.data());
|
|
633
|
+
sig.setProtectedHeader(this.#protectedHeader);
|
|
634
|
+
if (unencodedPayload(this.#protectedHeader)) throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
635
|
+
return sig.sign(key, options);
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
//#endregion
|
|
1
639
|
//#region src/server.ts
|
|
2
|
-
const
|
|
640
|
+
const ASTRALBEAM_CHAT_TOKEN_AUDIENCE = "astralbeam-chat";
|
|
641
|
+
const ASTRALBEAM_CHAT_TOKEN_ISSUER = "astralbeam-global";
|
|
642
|
+
const ASTRALBEAM_CHAT_TOKEN_TYPE = "astralbeam-chat+jwt";
|
|
643
|
+
const ASTRALBEAM_CHAT_TOKEN_KEY_ID = "global-v1";
|
|
644
|
+
const ASTRALBEAM_CHAT_TOKEN_LIFETIME_SECONDS = 300;
|
|
645
|
+
const ASTRALBEAM_CHAT_TOKEN_MAX_LIFETIME_SECONDS = 600;
|
|
646
|
+
const textEncoder = new TextEncoder();
|
|
647
|
+
function signingKey(secret) {
|
|
648
|
+
const key = typeof secret === "string" ? textEncoder.encode(secret) : secret;
|
|
649
|
+
if (key.byteLength < 32) throw new Error("AstralBeam chat signing secrets need at least 32 bytes");
|
|
650
|
+
return key;
|
|
651
|
+
}
|
|
652
|
+
function requiredText(value, label, maxLength) {
|
|
653
|
+
const text = value.trim();
|
|
654
|
+
if (!text || text.length > maxLength) throw new Error(`${label} must be 1-${maxLength} characters`);
|
|
655
|
+
return text;
|
|
656
|
+
}
|
|
657
|
+
function optionalText(value, label, maxLength) {
|
|
658
|
+
if (value === void 0) return void 0;
|
|
659
|
+
return requiredText(value, label, maxLength);
|
|
660
|
+
}
|
|
661
|
+
function optionalUrl(value, label) {
|
|
662
|
+
const text = optionalText(value, label, 2048);
|
|
663
|
+
if (text === void 0) return void 0;
|
|
664
|
+
const url = new URL(text);
|
|
665
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") throw new Error(`${label} must use http or https`);
|
|
666
|
+
return url.href;
|
|
667
|
+
}
|
|
668
|
+
/** Creates the short-lived bearer token returned by an application's auth endpoint. */
|
|
669
|
+
async function createAstralBeamChatToken({ secret, user, tenant, expiresInSeconds = 300 }) {
|
|
670
|
+
if (!Number.isInteger(expiresInSeconds) || expiresInSeconds < 60 || expiresInSeconds > 600) throw new Error("AstralBeam chat tokens must live for 60-600 seconds");
|
|
671
|
+
const userId = requiredText(user.id, "user.id", 255);
|
|
672
|
+
const tenantId = requiredText(tenant.id, "tenant.id", 255);
|
|
673
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
674
|
+
return await new SignJWT({
|
|
675
|
+
ver: 1,
|
|
676
|
+
user: {
|
|
677
|
+
id: userId,
|
|
678
|
+
name: optionalText(user.name, "user.name", 200),
|
|
679
|
+
email: optionalText(user.email, "user.email", 320),
|
|
680
|
+
avatarUrl: optionalUrl(user.avatarUrl, "user.avatarUrl")
|
|
681
|
+
},
|
|
682
|
+
tenant: {
|
|
683
|
+
id: tenantId,
|
|
684
|
+
name: optionalText(tenant.name, "tenant.name", 200),
|
|
685
|
+
logoUrl: optionalUrl(tenant.logoUrl, "tenant.logoUrl")
|
|
686
|
+
}
|
|
687
|
+
}).setProtectedHeader({
|
|
688
|
+
alg: "HS256",
|
|
689
|
+
typ: ASTRALBEAM_CHAT_TOKEN_TYPE,
|
|
690
|
+
kid: ASTRALBEAM_CHAT_TOKEN_KEY_ID
|
|
691
|
+
}).setIssuer(ASTRALBEAM_CHAT_TOKEN_ISSUER).setAudience(ASTRALBEAM_CHAT_TOKEN_AUDIENCE).setSubject(userId).setIssuedAt(now).setExpirationTime(now + expiresInSeconds).sign(signingKey(secret));
|
|
692
|
+
}
|
|
3
693
|
//#endregion
|
|
4
|
-
export {
|
|
694
|
+
export { ASTRALBEAM_CHAT_TOKEN_AUDIENCE, ASTRALBEAM_CHAT_TOKEN_ISSUER, ASTRALBEAM_CHAT_TOKEN_KEY_ID, ASTRALBEAM_CHAT_TOKEN_LIFETIME_SECONDS, ASTRALBEAM_CHAT_TOKEN_MAX_LIFETIME_SECONDS, ASTRALBEAM_CHAT_TOKEN_TYPE, createAstralBeamChatToken };
|