deepspace 0.3.11 → 0.4.1
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/dist/cli.js +258 -120
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +68 -26
- package/dist/index.js +108 -48
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +72 -73
- package/dist/server.js +371 -338
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +72 -73
- package/dist/worker.js +425 -392
- package/dist/worker.js.map +1 -1
- package/package.json +2 -2
- package/dist/testing.d.ts +0 -115
package/dist/server.js
CHANGED
|
@@ -165,6 +165,11 @@ var BUILT_IN_TOOLS = [
|
|
|
165
165
|
|
|
166
166
|
// src/server/utils/scoped-r2-files.ts
|
|
167
167
|
var CORS_HEADERS = { "Access-Control-Allow-Origin": "*" };
|
|
168
|
+
function contentDisposition(originalName) {
|
|
169
|
+
const safe = originalName.replace(/[\x00-\x1f\x7f"\\]/g, "_") || "download";
|
|
170
|
+
const encoded = encodeURIComponent(originalName);
|
|
171
|
+
return `inline; filename="${safe}"; filename*=UTF-8''${encoded}`;
|
|
172
|
+
}
|
|
168
173
|
function sanitizeSubpath(raw) {
|
|
169
174
|
if (!raw) return "";
|
|
170
175
|
const segments = raw.split("/");
|
|
@@ -201,7 +206,9 @@ function createScopedR2Handler(config) {
|
|
|
201
206
|
{ status: 400, headers: CORS_HEADERS }
|
|
202
207
|
);
|
|
203
208
|
}
|
|
204
|
-
const
|
|
209
|
+
const isKeyedGet = subpath !== "" && request.method === "GET";
|
|
210
|
+
const defaultScope = isKeyedGet ? "app" : "self";
|
|
211
|
+
const scope = url.searchParams.get("scope") || defaultScope;
|
|
205
212
|
const result = config.resolvePrefix(scope, { userId: auth.userId, url });
|
|
206
213
|
if (!result.prefix) {
|
|
207
214
|
const errorMsg = result.error ?? "Invalid scope";
|
|
@@ -352,339 +359,11 @@ async function handleDownload(bucket, key) {
|
|
|
352
359
|
headers.set("Cache-Control", "public, max-age=31536000, immutable");
|
|
353
360
|
headers.set("Access-Control-Allow-Origin", "*");
|
|
354
361
|
if (object.customMetadata?.originalName) {
|
|
355
|
-
headers.set("Content-Disposition",
|
|
362
|
+
headers.set("Content-Disposition", contentDisposition(object.customMetadata.originalName));
|
|
356
363
|
}
|
|
357
364
|
return new Response(object.body, { headers });
|
|
358
365
|
}
|
|
359
366
|
|
|
360
|
-
// src/server/auth/jwtVerifier.ts
|
|
361
|
-
import { importSPKI, jwtVerify } from "jose";
|
|
362
|
-
|
|
363
|
-
// src/server/auth/utils.ts
|
|
364
|
-
var BASE64_URL_REGEX = /^[A-Za-z0-9-_]+$/;
|
|
365
|
-
function bufferToHex(bytes) {
|
|
366
|
-
const view = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
|
|
367
|
-
let hex = "";
|
|
368
|
-
for (const byte of view) {
|
|
369
|
-
hex += byte.toString(16).padStart(2, "0");
|
|
370
|
-
}
|
|
371
|
-
return hex;
|
|
372
|
-
}
|
|
373
|
-
function normalizeArray(value) {
|
|
374
|
-
if (value == null) return void 0;
|
|
375
|
-
if (Array.isArray(value)) {
|
|
376
|
-
return value.length ? value : void 0;
|
|
377
|
-
}
|
|
378
|
-
return [value];
|
|
379
|
-
}
|
|
380
|
-
function decodeJwtPayload(token) {
|
|
381
|
-
if (!token) return void 0;
|
|
382
|
-
const parts = token.split(".");
|
|
383
|
-
if (parts.length < 2) return void 0;
|
|
384
|
-
const payloadSegment = parts[1];
|
|
385
|
-
if (!payloadSegment) return void 0;
|
|
386
|
-
if (!BASE64_URL_REGEX.test(payloadSegment)) return void 0;
|
|
387
|
-
try {
|
|
388
|
-
const normalized = payloadSegment.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(payloadSegment.length / 4) * 4, "=");
|
|
389
|
-
const bytes = base64ToUint8Array(normalized);
|
|
390
|
-
const json = new TextDecoder().decode(bytes);
|
|
391
|
-
const payload = JSON.parse(json);
|
|
392
|
-
return {
|
|
393
|
-
iss: payload.iss ?? null,
|
|
394
|
-
aud: payload.aud ?? null,
|
|
395
|
-
azp: payload?.azp ?? null,
|
|
396
|
-
exp: payload.exp ?? null,
|
|
397
|
-
iat: payload.iat ?? null
|
|
398
|
-
};
|
|
399
|
-
} catch {
|
|
400
|
-
return void 0;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
function nowMs() {
|
|
404
|
-
return Date.now();
|
|
405
|
-
}
|
|
406
|
-
function base64ToUint8Array(value) {
|
|
407
|
-
if (typeof atob === "function") {
|
|
408
|
-
const binary = atob(value);
|
|
409
|
-
const out = new Uint8Array(binary.length);
|
|
410
|
-
for (let i = 0; i < binary.length; i += 1) {
|
|
411
|
-
out[i] = binary.charCodeAt(i);
|
|
412
|
-
}
|
|
413
|
-
return out;
|
|
414
|
-
}
|
|
415
|
-
if (typeof Buffer !== "undefined") {
|
|
416
|
-
return Uint8Array.from(Buffer.from(value, "base64"));
|
|
417
|
-
}
|
|
418
|
-
throw new Error("No base64 decoder available in current environment");
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// src/server/auth/jwtVerifier.ts
|
|
422
|
-
var DEFAULT_CLOCK_SKEW_MS = 5e3;
|
|
423
|
-
function matchesAuthorizedParty(azp, patterns) {
|
|
424
|
-
if (!azp) return true;
|
|
425
|
-
for (const pattern of patterns) {
|
|
426
|
-
if (pattern === azp) return true;
|
|
427
|
-
if (pattern.includes("*")) {
|
|
428
|
-
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
429
|
-
const regexPattern = escaped.replace(/\*/g, "[^/]*");
|
|
430
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
431
|
-
if (regex.test(azp)) return true;
|
|
432
|
-
if (pattern.includes("*.")) {
|
|
433
|
-
const rootPattern = pattern.replace("*.", "");
|
|
434
|
-
if (rootPattern === azp) return true;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
return false;
|
|
439
|
-
}
|
|
440
|
-
var keyCache = /* @__PURE__ */ new Map();
|
|
441
|
-
async function getPublicKey(pem) {
|
|
442
|
-
const cached = keyCache.get(pem);
|
|
443
|
-
if (cached) return cached;
|
|
444
|
-
const normalized = pem.replace(/\\n/g, "\n");
|
|
445
|
-
const key = await importSPKI(normalized, "ES256");
|
|
446
|
-
keyCache.set(pem, key);
|
|
447
|
-
return key;
|
|
448
|
-
}
|
|
449
|
-
async function verifyJwt(config, token) {
|
|
450
|
-
if (!token) {
|
|
451
|
-
return { result: null };
|
|
452
|
-
}
|
|
453
|
-
try {
|
|
454
|
-
const publicKey = await getPublicKey(config.publicKey);
|
|
455
|
-
const audience = normalizeArray(config.audience);
|
|
456
|
-
const clockTolerance = Math.floor(
|
|
457
|
-
(config.clockSkewMs ?? DEFAULT_CLOCK_SKEW_MS) / 1e3
|
|
458
|
-
);
|
|
459
|
-
const { payload } = await jwtVerify(token, publicKey, {
|
|
460
|
-
issuer: config.issuer,
|
|
461
|
-
audience: audience && audience.length === 1 ? audience[0] : audience,
|
|
462
|
-
clockTolerance
|
|
463
|
-
});
|
|
464
|
-
const claims = payload;
|
|
465
|
-
if (!claims.sub) {
|
|
466
|
-
throw new Error("JWT verification succeeded but subject claim is missing");
|
|
467
|
-
}
|
|
468
|
-
const authorizedParties = normalizeArray(config.authorizedParties);
|
|
469
|
-
if (authorizedParties) {
|
|
470
|
-
const azp = claims.azp;
|
|
471
|
-
if (!matchesAuthorizedParty(azp, authorizedParties)) {
|
|
472
|
-
throw new Error(
|
|
473
|
-
`Authorized party '${azp}' does not match any allowed pattern`
|
|
474
|
-
);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
return {
|
|
478
|
-
result: {
|
|
479
|
-
userId: claims.sub,
|
|
480
|
-
claims
|
|
481
|
-
}
|
|
482
|
-
};
|
|
483
|
-
} catch (error) {
|
|
484
|
-
return {
|
|
485
|
-
result: null,
|
|
486
|
-
error,
|
|
487
|
-
debug: decodeJwtPayload(token)
|
|
488
|
-
};
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
// src/server/auth/internalAuth.ts
|
|
493
|
-
var DEFAULT_MAX_SKEW_MS = 5 * 6e4;
|
|
494
|
-
var nodeCryptoPromise = null;
|
|
495
|
-
async function loadNodeCrypto() {
|
|
496
|
-
if (!nodeCryptoPromise) {
|
|
497
|
-
nodeCryptoPromise = import("crypto").then((module) => module).catch(() => null);
|
|
498
|
-
}
|
|
499
|
-
return nodeCryptoPromise;
|
|
500
|
-
}
|
|
501
|
-
function hasSubtleCrypto() {
|
|
502
|
-
return typeof globalThis.crypto?.subtle?.importKey === "function";
|
|
503
|
-
}
|
|
504
|
-
async function computeHmacHex(secret, payload) {
|
|
505
|
-
if (hasSubtleCrypto()) {
|
|
506
|
-
const encoder = new TextEncoder();
|
|
507
|
-
const key = await crypto.subtle.importKey(
|
|
508
|
-
"raw",
|
|
509
|
-
encoder.encode(secret),
|
|
510
|
-
{ name: "HMAC", hash: "SHA-256" },
|
|
511
|
-
false,
|
|
512
|
-
["sign"]
|
|
513
|
-
);
|
|
514
|
-
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(payload));
|
|
515
|
-
return bufferToHex(signature);
|
|
516
|
-
}
|
|
517
|
-
const nodeCrypto = await loadNodeCrypto();
|
|
518
|
-
if (!nodeCrypto) {
|
|
519
|
-
throw new Error("Crypto implementation unavailable for HMAC computation");
|
|
520
|
-
}
|
|
521
|
-
return nodeCrypto.createHmac("sha256", secret).update(payload).digest("hex");
|
|
522
|
-
}
|
|
523
|
-
async function timingSafeEqualHex(a, b) {
|
|
524
|
-
if (a.length !== b.length) {
|
|
525
|
-
return false;
|
|
526
|
-
}
|
|
527
|
-
const nodeCrypto = await loadNodeCrypto();
|
|
528
|
-
if (nodeCrypto?.timingSafeEqual) {
|
|
529
|
-
const aBuf = Buffer.from(a, "hex");
|
|
530
|
-
const bBuf = Buffer.from(b, "hex");
|
|
531
|
-
try {
|
|
532
|
-
return nodeCrypto.timingSafeEqual(aBuf, bBuf);
|
|
533
|
-
} catch {
|
|
534
|
-
return false;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
let diff = 0;
|
|
538
|
-
for (let i = 0; i < a.length; i += 1) {
|
|
539
|
-
diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
540
|
-
}
|
|
541
|
-
return diff === 0;
|
|
542
|
-
}
|
|
543
|
-
async function signInternalPayload({
|
|
544
|
-
secret,
|
|
545
|
-
payload,
|
|
546
|
-
timestamp
|
|
547
|
-
}) {
|
|
548
|
-
const ts = timestamp ?? nowMs().toString();
|
|
549
|
-
const signature = await computeHmacHex(secret, `${ts}.${payload}`);
|
|
550
|
-
return { timestamp: ts, signature };
|
|
551
|
-
}
|
|
552
|
-
async function verifyInternalSignature({
|
|
553
|
-
secret,
|
|
554
|
-
timestamp,
|
|
555
|
-
signature,
|
|
556
|
-
payload,
|
|
557
|
-
maxSkewMs = DEFAULT_MAX_SKEW_MS
|
|
558
|
-
}) {
|
|
559
|
-
if (!secret || !timestamp || !signature) {
|
|
560
|
-
return false;
|
|
561
|
-
}
|
|
562
|
-
const tsNumber = Number(timestamp);
|
|
563
|
-
if (!Number.isFinite(tsNumber)) {
|
|
564
|
-
return false;
|
|
565
|
-
}
|
|
566
|
-
const skew = Math.abs(nowMs() - tsNumber);
|
|
567
|
-
if (skew > maxSkewMs) {
|
|
568
|
-
return false;
|
|
569
|
-
}
|
|
570
|
-
const expected = await computeHmacHex(secret, `${timestamp}.${payload}`);
|
|
571
|
-
return timingSafeEqualHex(signature.toLowerCase(), expected.toLowerCase());
|
|
572
|
-
}
|
|
573
|
-
function buildInternalPayload(body) {
|
|
574
|
-
if (body === void 0) return "{}";
|
|
575
|
-
if (typeof body === "string") return body;
|
|
576
|
-
try {
|
|
577
|
-
return JSON.stringify(body);
|
|
578
|
-
} catch {
|
|
579
|
-
return "{}";
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// src/server/auth/betterAuth.ts
|
|
584
|
-
import { betterAuth } from "better-auth";
|
|
585
|
-
import { organization, twoFactor } from "better-auth/plugins";
|
|
586
|
-
function createDeepSpaceAuth(config) {
|
|
587
|
-
const socialProviders = {};
|
|
588
|
-
if (config.google) {
|
|
589
|
-
socialProviders.google = config.google;
|
|
590
|
-
}
|
|
591
|
-
if (config.github) {
|
|
592
|
-
socialProviders.github = config.github;
|
|
593
|
-
}
|
|
594
|
-
return betterAuth({
|
|
595
|
-
database: config.database,
|
|
596
|
-
baseURL: config.baseURL,
|
|
597
|
-
secret: config.secret,
|
|
598
|
-
emailAndPassword: {
|
|
599
|
-
enabled: config.emailAndPassword ?? true
|
|
600
|
-
},
|
|
601
|
-
socialProviders,
|
|
602
|
-
trustedOrigins: config.trustedOrigins ?? [
|
|
603
|
-
"https://deep.space",
|
|
604
|
-
"https://*.deep.space",
|
|
605
|
-
"https://*.app.space",
|
|
606
|
-
"http://localhost:*"
|
|
607
|
-
],
|
|
608
|
-
plugins: [organization(), twoFactor()]
|
|
609
|
-
});
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// src/server/utils/cron.ts
|
|
613
|
-
var DEFAULT_API_BASE_URL = "https://api-worker.deep.space";
|
|
614
|
-
function buildCronContext(env, ownerUserId, roomId = "default") {
|
|
615
|
-
const hmacSecret = env.INTERNAL_STORAGE_HMAC_SECRET;
|
|
616
|
-
const apiBase = env.API_BASE_URL || DEFAULT_API_BASE_URL;
|
|
617
|
-
const roomIdObj = env.RECORD_ROOMS.idFromName(roomId);
|
|
618
|
-
const room = env.RECORD_ROOMS.get(roomIdObj);
|
|
619
|
-
async function executeTool3(tool, params) {
|
|
620
|
-
const response = await room.fetch(new Request("https://internal/api/tools/execute", {
|
|
621
|
-
method: "POST",
|
|
622
|
-
headers: {
|
|
623
|
-
"Content-Type": "application/json",
|
|
624
|
-
"X-User-Id": ownerUserId,
|
|
625
|
-
"X-App-Action": "true"
|
|
626
|
-
},
|
|
627
|
-
body: JSON.stringify({ tool, params })
|
|
628
|
-
}));
|
|
629
|
-
const result = await response.json();
|
|
630
|
-
if (!result.success) {
|
|
631
|
-
throw new Error(`RecordRoom tool ${tool} failed: ${result.error || "Unknown error"}`);
|
|
632
|
-
}
|
|
633
|
-
return result.data;
|
|
634
|
-
}
|
|
635
|
-
const records = {
|
|
636
|
-
async query(collection, opts) {
|
|
637
|
-
const params = { collection };
|
|
638
|
-
if (opts?.where) params.where = opts.where;
|
|
639
|
-
if (opts?.limit) params.limit = opts.limit;
|
|
640
|
-
const data = await executeTool3("records.query", params);
|
|
641
|
-
return data.records || [];
|
|
642
|
-
},
|
|
643
|
-
async create(collection, data) {
|
|
644
|
-
return executeTool3("records.create", { collection, data });
|
|
645
|
-
},
|
|
646
|
-
async update(collection, recordId, data) {
|
|
647
|
-
return executeTool3("records.update", { collection, recordId, data });
|
|
648
|
-
},
|
|
649
|
-
async delete(collection, recordId) {
|
|
650
|
-
return executeTool3("records.delete", { collection, recordId });
|
|
651
|
-
}
|
|
652
|
-
};
|
|
653
|
-
const integrations = {
|
|
654
|
-
async call(endpoint, params) {
|
|
655
|
-
if (!hmacSecret) {
|
|
656
|
-
throw new Error("INTERNAL_STORAGE_HMAC_SECRET not configured \u2014 cannot call integrations");
|
|
657
|
-
}
|
|
658
|
-
const payload = { userId: ownerUserId, ...params };
|
|
659
|
-
const payloadStr = buildInternalPayload(payload);
|
|
660
|
-
const { timestamp, signature } = await signInternalPayload({
|
|
661
|
-
secret: hmacSecret,
|
|
662
|
-
payload: payloadStr
|
|
663
|
-
});
|
|
664
|
-
const response = await fetch(`${apiBase}/api/internal/integrations/${endpoint}`, {
|
|
665
|
-
method: "POST",
|
|
666
|
-
headers: {
|
|
667
|
-
"Content-Type": "application/json",
|
|
668
|
-
"x-internal-timestamp": timestamp,
|
|
669
|
-
"x-internal-signature": signature
|
|
670
|
-
},
|
|
671
|
-
body: payloadStr
|
|
672
|
-
});
|
|
673
|
-
if (!response.ok) {
|
|
674
|
-
const errText = await response.text();
|
|
675
|
-
throw new Error(`Integration call ${endpoint} failed (${response.status}): ${errText}`);
|
|
676
|
-
}
|
|
677
|
-
return response.json();
|
|
678
|
-
}
|
|
679
|
-
};
|
|
680
|
-
return { records, integrations, ownerUserId };
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
// src/server/utils/ai.ts
|
|
684
|
-
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
685
|
-
import { createOpenAI } from "@ai-sdk/openai";
|
|
686
|
-
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
687
|
-
|
|
688
367
|
// src/server/utils/proxies.ts
|
|
689
368
|
function resolveApiTransport(env) {
|
|
690
369
|
if (env.API_WORKER) return { kind: "binding", fetcher: env.API_WORKER };
|
|
@@ -763,7 +442,79 @@ function authWorkerFetch(env, path, init) {
|
|
|
763
442
|
return fetch(`${baseUrl}${pathAndSearch}`, init);
|
|
764
443
|
}
|
|
765
444
|
|
|
445
|
+
// src/server/utils/cron.ts
|
|
446
|
+
function buildCronContext(env, ownerUserId, roomId = "default") {
|
|
447
|
+
const roomIdObj = env.RECORD_ROOMS.idFromName(roomId);
|
|
448
|
+
const room = env.RECORD_ROOMS.get(roomIdObj);
|
|
449
|
+
async function executeTool3(tool, params) {
|
|
450
|
+
const response = await room.fetch(new Request("https://internal/api/tools/execute", {
|
|
451
|
+
method: "POST",
|
|
452
|
+
headers: {
|
|
453
|
+
"Content-Type": "application/json",
|
|
454
|
+
"X-User-Id": ownerUserId,
|
|
455
|
+
"X-App-Action": "true"
|
|
456
|
+
},
|
|
457
|
+
body: JSON.stringify({ tool, params })
|
|
458
|
+
}));
|
|
459
|
+
const result = await response.json();
|
|
460
|
+
if (!result.success) {
|
|
461
|
+
throw new Error(`RecordRoom tool ${tool} failed: ${result.error || "Unknown error"}`);
|
|
462
|
+
}
|
|
463
|
+
return result.data;
|
|
464
|
+
}
|
|
465
|
+
const records = {
|
|
466
|
+
async query(collection, opts) {
|
|
467
|
+
const params = { collection };
|
|
468
|
+
if (opts?.where) params.where = opts.where;
|
|
469
|
+
if (opts?.limit) params.limit = opts.limit;
|
|
470
|
+
const data = await executeTool3("records.query", params);
|
|
471
|
+
return data.records || [];
|
|
472
|
+
},
|
|
473
|
+
async create(collection, data) {
|
|
474
|
+
return executeTool3("records.create", { collection, data });
|
|
475
|
+
},
|
|
476
|
+
async update(collection, recordId, data) {
|
|
477
|
+
return executeTool3("records.update", { collection, recordId, data });
|
|
478
|
+
},
|
|
479
|
+
async delete(collection, recordId) {
|
|
480
|
+
return executeTool3("records.delete", { collection, recordId });
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
const integrations = {
|
|
484
|
+
async call(endpoint, params = {}) {
|
|
485
|
+
if (!env.APP_OWNER_JWT) {
|
|
486
|
+
throw new Error(
|
|
487
|
+
"integrations.call requires env.APP_OWNER_JWT. Deployed apps receive this automatically; in dev, `deepspace dev` writes it into .dev.vars."
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
const response = await apiWorkerFetch(env, `/api/integrations/${endpoint}`, {
|
|
491
|
+
method: "POST",
|
|
492
|
+
headers: {
|
|
493
|
+
"Content-Type": "application/json",
|
|
494
|
+
Authorization: `Bearer ${env.APP_OWNER_JWT}`
|
|
495
|
+
},
|
|
496
|
+
body: JSON.stringify(params)
|
|
497
|
+
});
|
|
498
|
+
const text = await response.text();
|
|
499
|
+
let result = {};
|
|
500
|
+
try {
|
|
501
|
+
result = text ? JSON.parse(text) : {};
|
|
502
|
+
} catch {
|
|
503
|
+
}
|
|
504
|
+
if (!response.ok || !result.success) {
|
|
505
|
+
const detail = result.message || result.error || text || `HTTP ${response.status}`;
|
|
506
|
+
throw new Error(`Integration call ${endpoint} failed: ${detail}`);
|
|
507
|
+
}
|
|
508
|
+
return result.data;
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
return { records, integrations, ownerUserId };
|
|
512
|
+
}
|
|
513
|
+
|
|
766
514
|
// src/server/utils/ai.ts
|
|
515
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
516
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
517
|
+
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
767
518
|
var ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS = 4096;
|
|
768
519
|
function withDefaultAnthropicMaxTokens(body) {
|
|
769
520
|
if (typeof body !== "string") return body;
|
|
@@ -1566,6 +1317,13 @@ var MSG = {
|
|
|
1566
1317
|
USER_LIST: "user.list",
|
|
1567
1318
|
SET_ROLE: "user.set_role",
|
|
1568
1319
|
USER_UPDATE: "user.update",
|
|
1320
|
+
// ---- Auth signal -----------------------------------------------------
|
|
1321
|
+
// Server → client one-shot on connect from rooms that enforce role-based
|
|
1322
|
+
// writes (Canvas, Game, Cron). Tells the client whether this connection
|
|
1323
|
+
// can write so its hook can disable local write APIs and the UI can
|
|
1324
|
+
// render controls accordingly. Without this, a viewer's click would
|
|
1325
|
+
// round-trip to the server and silently come back as ERROR.
|
|
1326
|
+
AUTH: "auth",
|
|
1569
1327
|
// ---- Yjs JSON control frames (binary sync lives in ./yjs.ts) ---------
|
|
1570
1328
|
YJS_JOIN: "yjs.join",
|
|
1571
1329
|
YJS_LEAVE: "yjs.leave",
|
|
@@ -4201,7 +3959,20 @@ var YjsRoom = class extends BaseRoom {
|
|
|
4201
3959
|
}
|
|
4202
3960
|
};
|
|
4203
3961
|
|
|
3962
|
+
// src/shared/roles.ts
|
|
3963
|
+
var ROLES = {
|
|
3964
|
+
VIEWER: "viewer",
|
|
3965
|
+
MEMBER: "member",
|
|
3966
|
+
ADMIN: "admin"
|
|
3967
|
+
};
|
|
3968
|
+
|
|
4204
3969
|
// src/server/rooms/game-room.ts
|
|
3970
|
+
var GAME_WRITE_TYPES = /* @__PURE__ */ new Set([
|
|
3971
|
+
MSG.GAME_INPUT,
|
|
3972
|
+
MSG.GAME_PLAYER_READY,
|
|
3973
|
+
MSG.GAME_START,
|
|
3974
|
+
MSG.GAME_END
|
|
3975
|
+
]);
|
|
4205
3976
|
var GameRoom = class extends BaseRoom {
|
|
4206
3977
|
config;
|
|
4207
3978
|
players = /* @__PURE__ */ new Map();
|
|
@@ -4257,10 +4028,26 @@ var GameRoom = class extends BaseRoom {
|
|
|
4257
4028
|
// ==========================================================================
|
|
4258
4029
|
onConnect(ws, user) {
|
|
4259
4030
|
this.ensureInitialized();
|
|
4031
|
+
const role = user.role ?? ROLES.VIEWER;
|
|
4032
|
+
const canWrite = role === ROLES.MEMBER || role === ROLES.ADMIN;
|
|
4260
4033
|
const attachment = {
|
|
4261
4034
|
...user,
|
|
4262
|
-
joinedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4035
|
+
joinedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4036
|
+
canWrite
|
|
4263
4037
|
};
|
|
4038
|
+
this.sendTo(ws, { type: MSG.AUTH, payload: { canWrite } });
|
|
4039
|
+
if (!canWrite) {
|
|
4040
|
+
this.sendTo(ws, {
|
|
4041
|
+
type: MSG.GAME_STATE,
|
|
4042
|
+
payload: {
|
|
4043
|
+
state: this.gameState,
|
|
4044
|
+
tick: this.currentTick,
|
|
4045
|
+
players: Array.from(this.players.values()),
|
|
4046
|
+
running: this.running
|
|
4047
|
+
}
|
|
4048
|
+
});
|
|
4049
|
+
return attachment;
|
|
4050
|
+
}
|
|
4264
4051
|
const player = {
|
|
4265
4052
|
userId: user.userId,
|
|
4266
4053
|
userName: user.userName,
|
|
@@ -4289,6 +4076,13 @@ var GameRoom = class extends BaseRoom {
|
|
|
4289
4076
|
async onMessage(ws, user, message) {
|
|
4290
4077
|
this.ensureInitialized();
|
|
4291
4078
|
const { type, payload } = message;
|
|
4079
|
+
if (GAME_WRITE_TYPES.has(type) && !user.canWrite) {
|
|
4080
|
+
this.sendTo(ws, {
|
|
4081
|
+
type: MSG.ERROR,
|
|
4082
|
+
payload: { error: "Write access denied: spectators cannot drive the game" }
|
|
4083
|
+
});
|
|
4084
|
+
return;
|
|
4085
|
+
}
|
|
4292
4086
|
switch (type) {
|
|
4293
4087
|
case MSG.GAME_INPUT: {
|
|
4294
4088
|
this.inputBuffer.push({
|
|
@@ -4437,6 +4231,15 @@ var GameRoom = class extends BaseRoom {
|
|
|
4437
4231
|
|
|
4438
4232
|
// src/server/rooms/canvas-room.ts
|
|
4439
4233
|
import * as Y5 from "yjs";
|
|
4234
|
+
var CANVAS_WRITE_TYPES = /* @__PURE__ */ new Set([
|
|
4235
|
+
MSG.CANVAS_ADD,
|
|
4236
|
+
MSG.CANVAS_MOVE,
|
|
4237
|
+
MSG.CANVAS_RESIZE,
|
|
4238
|
+
MSG.CANVAS_DELETE,
|
|
4239
|
+
MSG.CANVAS_UPDATE,
|
|
4240
|
+
MSG.CANVAS_UNDO,
|
|
4241
|
+
MSG.CANVAS_REDO
|
|
4242
|
+
]);
|
|
4440
4243
|
var CanvasRoom = class extends BaseRoom {
|
|
4441
4244
|
doc = null;
|
|
4442
4245
|
initialized = false;
|
|
@@ -4496,10 +4299,14 @@ var CanvasRoom = class extends BaseRoom {
|
|
|
4496
4299
|
}
|
|
4497
4300
|
onConnect(ws, user) {
|
|
4498
4301
|
this.ensureInitialized();
|
|
4302
|
+
const role = user.role ?? ROLES.VIEWER;
|
|
4303
|
+
const canWrite = role === ROLES.MEMBER || role === ROLES.ADMIN;
|
|
4499
4304
|
const attachment = {
|
|
4500
4305
|
...user,
|
|
4501
|
-
viewport: null
|
|
4306
|
+
viewport: null,
|
|
4307
|
+
canWrite
|
|
4502
4308
|
};
|
|
4309
|
+
this.sendTo(ws, { type: MSG.AUTH, payload: { canWrite } });
|
|
4503
4310
|
const shapes = this.getAllShapes();
|
|
4504
4311
|
this.sendTo(ws, {
|
|
4505
4312
|
type: MSG.CANVAS_SHAPES,
|
|
@@ -4513,6 +4320,13 @@ var CanvasRoom = class extends BaseRoom {
|
|
|
4513
4320
|
async onMessage(ws, user, message) {
|
|
4514
4321
|
this.ensureInitialized();
|
|
4515
4322
|
const { type, payload } = message;
|
|
4323
|
+
if (CANVAS_WRITE_TYPES.has(type) && !user.canWrite) {
|
|
4324
|
+
this.sendTo(ws, {
|
|
4325
|
+
type: MSG.ERROR,
|
|
4326
|
+
payload: { error: "Write access denied: viewer role cannot modify the canvas" }
|
|
4327
|
+
});
|
|
4328
|
+
return;
|
|
4329
|
+
}
|
|
4516
4330
|
switch (type) {
|
|
4517
4331
|
case MSG.CANVAS_ADD: {
|
|
4518
4332
|
const shape = payload;
|
|
@@ -4807,6 +4621,11 @@ var PresenceRoom = class extends BaseRoom {
|
|
|
4807
4621
|
};
|
|
4808
4622
|
|
|
4809
4623
|
// src/server/rooms/cron-room.ts
|
|
4624
|
+
var CRON_WRITE_TYPES = /* @__PURE__ */ new Set([
|
|
4625
|
+
MSG.CRON_TRIGGER,
|
|
4626
|
+
MSG.CRON_PAUSE,
|
|
4627
|
+
MSG.CRON_RESUME
|
|
4628
|
+
]);
|
|
4810
4629
|
var CronRoom = class extends BaseRoom {
|
|
4811
4630
|
tasks;
|
|
4812
4631
|
initialized = false;
|
|
@@ -4885,6 +4704,9 @@ var CronRoom = class extends BaseRoom {
|
|
|
4885
4704
|
}
|
|
4886
4705
|
onConnect(ws, user) {
|
|
4887
4706
|
this.ensureInitialized();
|
|
4707
|
+
const role = user.role ?? ROLES.VIEWER;
|
|
4708
|
+
const canWrite = role === ROLES.MEMBER || role === ROLES.ADMIN;
|
|
4709
|
+
this.sendTo(ws, { type: MSG.AUTH, payload: { canWrite } });
|
|
4888
4710
|
this.sendTo(ws, {
|
|
4889
4711
|
type: MSG.CRON_TASKS,
|
|
4890
4712
|
payload: { tasks: this.getTaskStates() }
|
|
@@ -4893,11 +4715,18 @@ var CronRoom = class extends BaseRoom {
|
|
|
4893
4715
|
type: MSG.CRON_HISTORY,
|
|
4894
4716
|
payload: { history: this.getRecentHistory(50) }
|
|
4895
4717
|
});
|
|
4896
|
-
return user;
|
|
4718
|
+
return { ...user, canWrite };
|
|
4897
4719
|
}
|
|
4898
4720
|
async onMessage(ws, user, message) {
|
|
4899
4721
|
this.ensureInitialized();
|
|
4900
4722
|
const { type, payload } = message;
|
|
4723
|
+
if (CRON_WRITE_TYPES.has(type) && !user.canWrite) {
|
|
4724
|
+
this.sendTo(ws, {
|
|
4725
|
+
type: MSG.ERROR,
|
|
4726
|
+
payload: { error: "Write access denied: viewer role cannot modify cron tasks" }
|
|
4727
|
+
});
|
|
4728
|
+
return;
|
|
4729
|
+
}
|
|
4901
4730
|
switch (type) {
|
|
4902
4731
|
case MSG.CRON_TRIGGER: {
|
|
4903
4732
|
const taskName = payload.taskName;
|
|
@@ -5825,7 +5654,6 @@ var RESERVED_BINDING_NAMES = /* @__PURE__ */ new Set([
|
|
|
5825
5654
|
"AUTH_WORKER_URL",
|
|
5826
5655
|
"APP_IDENTITY_TOKEN",
|
|
5827
5656
|
"APP_OWNER_JWT",
|
|
5828
|
-
"INTERNAL_STORAGE_HMAC_SECRET",
|
|
5829
5657
|
"USAGE_EVENTS"
|
|
5830
5658
|
]);
|
|
5831
5659
|
function validateBindingManifest(manifest) {
|
|
@@ -6657,6 +6485,215 @@ var RESERVED_COLLECTION_NAMES = new Set(
|
|
|
6657
6485
|
GLOBAL_DO_TYPES.flatMap((t) => t.schemas.map((s) => s.name))
|
|
6658
6486
|
);
|
|
6659
6487
|
|
|
6488
|
+
// src/server/auth/jwtVerifier.ts
|
|
6489
|
+
import { importSPKI, jwtVerify } from "jose";
|
|
6490
|
+
|
|
6491
|
+
// src/server/auth/utils.ts
|
|
6492
|
+
var BASE64_URL_REGEX = /^[A-Za-z0-9-_]+$/;
|
|
6493
|
+
function bufferToHex(bytes) {
|
|
6494
|
+
const view = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
|
|
6495
|
+
let hex = "";
|
|
6496
|
+
for (const byte of view) {
|
|
6497
|
+
hex += byte.toString(16).padStart(2, "0");
|
|
6498
|
+
}
|
|
6499
|
+
return hex;
|
|
6500
|
+
}
|
|
6501
|
+
function normalizeArray(value) {
|
|
6502
|
+
if (value == null) return void 0;
|
|
6503
|
+
if (Array.isArray(value)) {
|
|
6504
|
+
return value.length ? value : void 0;
|
|
6505
|
+
}
|
|
6506
|
+
return [value];
|
|
6507
|
+
}
|
|
6508
|
+
function decodeJwtPayload(token) {
|
|
6509
|
+
if (!token) return void 0;
|
|
6510
|
+
const parts = token.split(".");
|
|
6511
|
+
if (parts.length < 2) return void 0;
|
|
6512
|
+
const payloadSegment = parts[1];
|
|
6513
|
+
if (!payloadSegment) return void 0;
|
|
6514
|
+
if (!BASE64_URL_REGEX.test(payloadSegment)) return void 0;
|
|
6515
|
+
try {
|
|
6516
|
+
const normalized = payloadSegment.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(payloadSegment.length / 4) * 4, "=");
|
|
6517
|
+
const bytes = base64ToUint8Array(normalized);
|
|
6518
|
+
const json = new TextDecoder().decode(bytes);
|
|
6519
|
+
const payload = JSON.parse(json);
|
|
6520
|
+
return {
|
|
6521
|
+
iss: payload.iss ?? null,
|
|
6522
|
+
aud: payload.aud ?? null,
|
|
6523
|
+
azp: payload?.azp ?? null,
|
|
6524
|
+
exp: payload.exp ?? null,
|
|
6525
|
+
iat: payload.iat ?? null
|
|
6526
|
+
};
|
|
6527
|
+
} catch {
|
|
6528
|
+
return void 0;
|
|
6529
|
+
}
|
|
6530
|
+
}
|
|
6531
|
+
function base64ToUint8Array(value) {
|
|
6532
|
+
if (typeof atob === "function") {
|
|
6533
|
+
const binary = atob(value);
|
|
6534
|
+
const out = new Uint8Array(binary.length);
|
|
6535
|
+
for (let i = 0; i < binary.length; i += 1) {
|
|
6536
|
+
out[i] = binary.charCodeAt(i);
|
|
6537
|
+
}
|
|
6538
|
+
return out;
|
|
6539
|
+
}
|
|
6540
|
+
if (typeof Buffer !== "undefined") {
|
|
6541
|
+
return Uint8Array.from(Buffer.from(value, "base64"));
|
|
6542
|
+
}
|
|
6543
|
+
throw new Error("No base64 decoder available in current environment");
|
|
6544
|
+
}
|
|
6545
|
+
|
|
6546
|
+
// src/server/auth/jwtVerifier.ts
|
|
6547
|
+
var DEFAULT_CLOCK_SKEW_MS = 5e3;
|
|
6548
|
+
function matchesAuthorizedParty(azp, patterns) {
|
|
6549
|
+
if (!azp) return true;
|
|
6550
|
+
for (const pattern of patterns) {
|
|
6551
|
+
if (pattern === azp) return true;
|
|
6552
|
+
if (pattern.includes("*")) {
|
|
6553
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
6554
|
+
const regexPattern = escaped.replace(/\*/g, "[^/]*");
|
|
6555
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
6556
|
+
if (regex.test(azp)) return true;
|
|
6557
|
+
if (pattern.includes("*.")) {
|
|
6558
|
+
const rootPattern = pattern.replace("*.", "");
|
|
6559
|
+
if (rootPattern === azp) return true;
|
|
6560
|
+
}
|
|
6561
|
+
}
|
|
6562
|
+
}
|
|
6563
|
+
return false;
|
|
6564
|
+
}
|
|
6565
|
+
var keyCache = /* @__PURE__ */ new Map();
|
|
6566
|
+
async function getPublicKey(pem) {
|
|
6567
|
+
const cached = keyCache.get(pem);
|
|
6568
|
+
if (cached) return cached;
|
|
6569
|
+
const normalized = pem.replace(/\\n/g, "\n");
|
|
6570
|
+
const key = await importSPKI(normalized, "ES256");
|
|
6571
|
+
keyCache.set(pem, key);
|
|
6572
|
+
return key;
|
|
6573
|
+
}
|
|
6574
|
+
async function verifyJwt(config, token) {
|
|
6575
|
+
if (!token) {
|
|
6576
|
+
return { result: null };
|
|
6577
|
+
}
|
|
6578
|
+
try {
|
|
6579
|
+
const publicKey = await getPublicKey(config.publicKey);
|
|
6580
|
+
const audience = normalizeArray(config.audience);
|
|
6581
|
+
const clockTolerance = Math.floor(
|
|
6582
|
+
(config.clockSkewMs ?? DEFAULT_CLOCK_SKEW_MS) / 1e3
|
|
6583
|
+
);
|
|
6584
|
+
const { payload } = await jwtVerify(token, publicKey, {
|
|
6585
|
+
issuer: config.issuer,
|
|
6586
|
+
audience: audience && audience.length === 1 ? audience[0] : audience,
|
|
6587
|
+
clockTolerance
|
|
6588
|
+
});
|
|
6589
|
+
const claims = payload;
|
|
6590
|
+
if (!claims.sub) {
|
|
6591
|
+
throw new Error("JWT verification succeeded but subject claim is missing");
|
|
6592
|
+
}
|
|
6593
|
+
const authorizedParties = normalizeArray(config.authorizedParties);
|
|
6594
|
+
if (authorizedParties) {
|
|
6595
|
+
const azp = claims.azp;
|
|
6596
|
+
if (!matchesAuthorizedParty(azp, authorizedParties)) {
|
|
6597
|
+
throw new Error(
|
|
6598
|
+
`Authorized party '${azp}' does not match any allowed pattern`
|
|
6599
|
+
);
|
|
6600
|
+
}
|
|
6601
|
+
}
|
|
6602
|
+
return {
|
|
6603
|
+
result: {
|
|
6604
|
+
userId: claims.sub,
|
|
6605
|
+
claims
|
|
6606
|
+
}
|
|
6607
|
+
};
|
|
6608
|
+
} catch (error) {
|
|
6609
|
+
return {
|
|
6610
|
+
result: null,
|
|
6611
|
+
error,
|
|
6612
|
+
debug: decodeJwtPayload(token)
|
|
6613
|
+
};
|
|
6614
|
+
}
|
|
6615
|
+
}
|
|
6616
|
+
|
|
6617
|
+
// src/server/auth/internalAuth.ts
|
|
6618
|
+
var nodeCryptoPromise = null;
|
|
6619
|
+
async function loadNodeCrypto() {
|
|
6620
|
+
if (!nodeCryptoPromise) {
|
|
6621
|
+
nodeCryptoPromise = import("crypto").then((module) => module).catch(() => null);
|
|
6622
|
+
}
|
|
6623
|
+
return nodeCryptoPromise;
|
|
6624
|
+
}
|
|
6625
|
+
function hasSubtleCrypto() {
|
|
6626
|
+
return typeof globalThis.crypto?.subtle?.importKey === "function";
|
|
6627
|
+
}
|
|
6628
|
+
async function computeHmacHex(secret, payload) {
|
|
6629
|
+
if (hasSubtleCrypto()) {
|
|
6630
|
+
const encoder = new TextEncoder();
|
|
6631
|
+
const key = await crypto.subtle.importKey(
|
|
6632
|
+
"raw",
|
|
6633
|
+
encoder.encode(secret),
|
|
6634
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
6635
|
+
false,
|
|
6636
|
+
["sign"]
|
|
6637
|
+
);
|
|
6638
|
+
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(payload));
|
|
6639
|
+
return bufferToHex(signature);
|
|
6640
|
+
}
|
|
6641
|
+
const nodeCrypto = await loadNodeCrypto();
|
|
6642
|
+
if (!nodeCrypto) {
|
|
6643
|
+
throw new Error("Crypto implementation unavailable for HMAC computation");
|
|
6644
|
+
}
|
|
6645
|
+
return nodeCrypto.createHmac("sha256", secret).update(payload).digest("hex");
|
|
6646
|
+
}
|
|
6647
|
+
async function timingSafeEqualHex(a, b) {
|
|
6648
|
+
if (a.length !== b.length) {
|
|
6649
|
+
return false;
|
|
6650
|
+
}
|
|
6651
|
+
const nodeCrypto = await loadNodeCrypto();
|
|
6652
|
+
if (nodeCrypto?.timingSafeEqual) {
|
|
6653
|
+
const aBuf = Buffer.from(a, "hex");
|
|
6654
|
+
const bBuf = Buffer.from(b, "hex");
|
|
6655
|
+
try {
|
|
6656
|
+
return nodeCrypto.timingSafeEqual(aBuf, bBuf);
|
|
6657
|
+
} catch {
|
|
6658
|
+
return false;
|
|
6659
|
+
}
|
|
6660
|
+
}
|
|
6661
|
+
let diff = 0;
|
|
6662
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
6663
|
+
diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
6664
|
+
}
|
|
6665
|
+
return diff === 0;
|
|
6666
|
+
}
|
|
6667
|
+
|
|
6668
|
+
// src/server/auth/betterAuth.ts
|
|
6669
|
+
import { betterAuth } from "better-auth";
|
|
6670
|
+
import { organization, twoFactor } from "better-auth/plugins";
|
|
6671
|
+
function createDeepSpaceAuth(config) {
|
|
6672
|
+
const socialProviders = {};
|
|
6673
|
+
if (config.google) {
|
|
6674
|
+
socialProviders.google = config.google;
|
|
6675
|
+
}
|
|
6676
|
+
if (config.github) {
|
|
6677
|
+
socialProviders.github = config.github;
|
|
6678
|
+
}
|
|
6679
|
+
return betterAuth({
|
|
6680
|
+
database: config.database,
|
|
6681
|
+
baseURL: config.baseURL,
|
|
6682
|
+
secret: config.secret,
|
|
6683
|
+
emailAndPassword: {
|
|
6684
|
+
enabled: config.emailAndPassword ?? true
|
|
6685
|
+
},
|
|
6686
|
+
socialProviders,
|
|
6687
|
+
trustedOrigins: config.trustedOrigins ?? [
|
|
6688
|
+
"https://deep.space",
|
|
6689
|
+
"https://*.deep.space",
|
|
6690
|
+
"https://*.app.space",
|
|
6691
|
+
"http://localhost:*"
|
|
6692
|
+
],
|
|
6693
|
+
plugins: [organization(), twoFactor()]
|
|
6694
|
+
});
|
|
6695
|
+
}
|
|
6696
|
+
|
|
6660
6697
|
// src/shared/subscription.ts
|
|
6661
6698
|
var ENTITLED_STATUSES = /* @__PURE__ */ new Set([
|
|
6662
6699
|
"active",
|
|
@@ -6821,7 +6858,6 @@ export {
|
|
|
6821
6858
|
CronRoom,
|
|
6822
6859
|
DEFAULT_CONTEXT_CONFIG,
|
|
6823
6860
|
DEFAULT_DO_MANIFEST,
|
|
6824
|
-
DEFAULT_MAX_SKEW_MS,
|
|
6825
6861
|
DIRECTORY_SCHEMAS,
|
|
6826
6862
|
GLOBAL_DO_TYPES,
|
|
6827
6863
|
GLOBAL_DO_TYPE_NAMES,
|
|
@@ -6853,7 +6889,6 @@ export {
|
|
|
6853
6889
|
broadcastChange,
|
|
6854
6890
|
broadcastYjsUpdate,
|
|
6855
6891
|
buildCronContext,
|
|
6856
|
-
buildInternalPayload,
|
|
6857
6892
|
buildTableSelect,
|
|
6858
6893
|
buildUiParts,
|
|
6859
6894
|
canCreate,
|
|
@@ -6924,7 +6959,6 @@ export {
|
|
|
6924
6959
|
rowToData,
|
|
6925
6960
|
runMigrations,
|
|
6926
6961
|
saveYjsDoc,
|
|
6927
|
-
signInternalPayload,
|
|
6928
6962
|
timingSafeEqualHex,
|
|
6929
6963
|
totalChars,
|
|
6930
6964
|
truncateOldToolResults,
|
|
@@ -6934,7 +6968,6 @@ export {
|
|
|
6934
6968
|
validateAppName,
|
|
6935
6969
|
validateBindingManifest,
|
|
6936
6970
|
validateDoManifest,
|
|
6937
|
-
verifyInternalSignature,
|
|
6938
6971
|
verifyJwt,
|
|
6939
6972
|
workspaceAccountsSchema,
|
|
6940
6973
|
workspaceContentSharesSchema,
|