@supacloud/lite 0.33.0 → 0.33.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/CHANGELOG.md +19 -0
- package/dist/cli.js +121 -108
- package/dist/index.js +121 -108
- package/dist/runtime/realtime/engine.d.ts +1 -0
- package/dist/runtime/realtime/engine.d.ts.map +1 -1
- package/package.json +18 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.33.2](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.33.1...supacloud-lite-v0.33.2) (2026-10-25)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **lite:** preserve shared realtime presence sessions ([#2242](https://github.com/vibeunion/supacloud/issues/2242)) ([b6cff5a](https://github.com/vibeunion/supacloud/commit/b6cff5a4117a093fb7c75034bf09575eddb74bd8))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Miscellaneous Chores
|
|
12
|
+
|
|
13
|
+
* **deps:** refresh the Elysia runtime and dependency matrix ([#2243](https://github.com/vibeunion/supacloud/issues/2243)) ([917ff0f](https://github.com/vibeunion/supacloud/commit/917ff0fa81e3c47d86d18e8c58fff79c0f0f67f5))
|
|
14
|
+
|
|
15
|
+
## [0.33.1](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.33.0...supacloud-lite-v0.33.1) (2026-10-19)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Miscellaneous Chores
|
|
19
|
+
|
|
20
|
+
* **lite:** restore Supabase SDK 2.118.0 ([#2161](https://github.com/vibeunion/supacloud/issues/2161)) ([0c7d4d0](https://github.com/vibeunion/supacloud/commit/0c7d4d08ed10cce4adcf5d30c9e7e473bc7f492a))
|
|
21
|
+
|
|
3
22
|
## [0.33.0](https://github.com/vibeunion/supacloud/compare/supacloud-lite-v0.32.0...supacloud-lite-v0.33.0) (2026-10-19)
|
|
4
23
|
|
|
5
24
|
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { dirname as dirname8, join as join10, resolve as resolve6 } from "path";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "@supacloud/lite",
|
|
11
|
-
version: "0.33.
|
|
11
|
+
version: "0.33.2",
|
|
12
12
|
description: "Bun-native, single-project Supabase-compatible backend powered by PGlite or native PostgreSQL",
|
|
13
13
|
type: "module",
|
|
14
14
|
license: "Apache-2.0",
|
|
@@ -47,7 +47,7 @@ var package_default = {
|
|
|
47
47
|
clean: "bun -e 'import { $ } from \"bun\"; await $`rm -rf dist`'",
|
|
48
48
|
dev: "bun run src/cli.ts start",
|
|
49
49
|
start: "bun run src/cli.ts start",
|
|
50
|
-
test: "bun
|
|
50
|
+
test: "bun run scripts/run-tests.ts",
|
|
51
51
|
"test:native": "SUPACLOUD_LITE_TEST_NATIVE=1 bun test test/native-engine.test.ts test/qauth-workflow-matrix.test.ts test/maker-checker-workflow.test.ts test/commands-artifacts.test.ts --timeout 180000",
|
|
52
52
|
"test:graphql": "SUPACLOUD_LITE_TEST_GRAPHQL=1 bun test test/graphql-native.test.ts --timeout 180000",
|
|
53
53
|
benchmark: "bun run scripts/benchmark.ts",
|
|
@@ -67,31 +67,31 @@ var package_default = {
|
|
|
67
67
|
"@electric-sql/pglite-pgmq": "0.0.8",
|
|
68
68
|
"@electric-sql/pglite-pgvector": "0.0.11",
|
|
69
69
|
"@electric-sql/pglite-postgis": "0.2.10",
|
|
70
|
-
"@supacloud/db": "0.20.
|
|
70
|
+
"@supacloud/db": "0.20.1",
|
|
71
71
|
"exact-mirror": "1.2.6",
|
|
72
72
|
tar: "^7.5.22",
|
|
73
|
-
typebox: "1.
|
|
73
|
+
typebox: "1.4.2"
|
|
74
74
|
},
|
|
75
75
|
devDependencies: {
|
|
76
|
-
"@supacloud/app": "0.
|
|
77
|
-
"@supacloud/contracts": "0.
|
|
78
|
-
"@supacloud/compiler": "0.
|
|
79
|
-
"@supacloud/elysia": "0.
|
|
80
|
-
"@supabase/supabase-js": "^2.
|
|
76
|
+
"@supacloud/app": "0.33.0",
|
|
77
|
+
"@supacloud/contracts": "0.15.1",
|
|
78
|
+
"@supacloud/compiler": "0.51.1",
|
|
79
|
+
"@supacloud/elysia": "0.36.1",
|
|
80
|
+
"@supabase/supabase-js": "^2.118.0",
|
|
81
81
|
"@types/bun": "^1.4.3",
|
|
82
82
|
effect: "4.0.5",
|
|
83
|
-
elysia: "2.0.0-
|
|
84
|
-
jose: "^6.2.
|
|
83
|
+
elysia: "2.0.0-rc.0",
|
|
84
|
+
jose: "^6.2.13",
|
|
85
85
|
typescript: "^7.0.2"
|
|
86
86
|
},
|
|
87
87
|
overrides: {
|
|
88
|
-
"@supacloud/db": "0.20.
|
|
89
|
-
"@supacloud/app": "0.
|
|
90
|
-
"@supacloud/compiler": "0.
|
|
91
|
-
"@supacloud/elysia": "0.
|
|
92
|
-
"@supacloud/contracts": "0.
|
|
93
|
-
"@supacloud/commands": "0.11.
|
|
94
|
-
"@supacloud/delivery": "0.21.
|
|
88
|
+
"@supacloud/db": "0.20.1",
|
|
89
|
+
"@supacloud/app": "0.33.0",
|
|
90
|
+
"@supacloud/compiler": "0.51.1",
|
|
91
|
+
"@supacloud/elysia": "0.36.1",
|
|
92
|
+
"@supacloud/contracts": "0.15.1",
|
|
93
|
+
"@supacloud/commands": "0.11.1",
|
|
94
|
+
"@supacloud/delivery": "0.21.1",
|
|
95
95
|
"@graphql-tools/utils": "^12.0.4"
|
|
96
96
|
},
|
|
97
97
|
engines: {
|
|
@@ -245,7 +245,7 @@ function isAllowedRedirect(requested, siteUrl, allowList = []) {
|
|
|
245
245
|
var encoder2 = new TextEncoder;
|
|
246
246
|
var decoder2 = new TextDecoder;
|
|
247
247
|
var strictDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
248
|
-
var
|
|
248
|
+
var UINT32_RANGE = 2 ** 32;
|
|
249
249
|
function concat(...buffers) {
|
|
250
250
|
const size = buffers.reduce((acc, { length }) => acc + length, 0), buf = new Uint8Array(size);
|
|
251
251
|
let i = 0;
|
|
@@ -404,23 +404,23 @@ function isDisjoint(...headers) {
|
|
|
404
404
|
function decodeBase64url(value, label, ErrorClass) {
|
|
405
405
|
try {
|
|
406
406
|
return decode(value);
|
|
407
|
-
} catch {
|
|
408
|
-
throw new ErrorClass(`Failed to base64url decode the ${label}
|
|
407
|
+
} catch (cause) {
|
|
408
|
+
throw new ErrorClass(`Failed to base64url decode the ${label}`, { cause });
|
|
409
409
|
}
|
|
410
410
|
}
|
|
411
|
-
function
|
|
411
|
+
function encodeAsciiMember(value, label, ErrorClass) {
|
|
412
412
|
try {
|
|
413
413
|
return encode(value);
|
|
414
|
-
} catch {
|
|
415
|
-
throw new ErrorClass(`The ${label} is not a valid base64url string
|
|
414
|
+
} catch (cause) {
|
|
415
|
+
throw new ErrorClass(`The ${label} is not a valid base64url string`, { cause });
|
|
416
416
|
}
|
|
417
417
|
}
|
|
418
|
-
function parseJoseHeader(
|
|
418
|
+
function parseJoseHeader(encodedProtectedHeader, ErrorClass, message) {
|
|
419
419
|
let parsed;
|
|
420
420
|
try {
|
|
421
|
-
parsed = JSON.parse(strictDecoder.decode(decode(
|
|
422
|
-
} catch {
|
|
423
|
-
throw new ErrorClass(message);
|
|
421
|
+
parsed = JSON.parse(strictDecoder.decode(decode(encodedProtectedHeader)));
|
|
422
|
+
} catch (cause) {
|
|
423
|
+
throw new ErrorClass(message, { cause });
|
|
424
424
|
}
|
|
425
425
|
if (!isObject(parsed))
|
|
426
426
|
throw new ErrorClass(message);
|
|
@@ -478,15 +478,15 @@ var jwkMatchesOp = (entry, key, usage) => {
|
|
|
478
478
|
}
|
|
479
479
|
};
|
|
480
480
|
async function prepareKey(entry, key, usage) {
|
|
481
|
-
const { alg, secret } = entry,
|
|
481
|
+
const { alg, secret } = entry, requiresPrivateKey = usage === "decrypt" || usage === "sign";
|
|
482
482
|
if (secret && key instanceof Uint8Array)
|
|
483
483
|
return key;
|
|
484
484
|
let normalized, keyObject;
|
|
485
485
|
if (isObject(key)) {
|
|
486
486
|
if (normalized = normalizeJwk(key), typeof normalized.kty != "string")
|
|
487
487
|
throw invalidKeyType(alg, key, secret);
|
|
488
|
-
if (!(secret ? normalized.kty === "oct" && typeof normalized.k == "string" : normalized.kty !== "oct" && (
|
|
489
|
-
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 ${
|
|
488
|
+
if (!(secret ? normalized.kty === "oct" && typeof normalized.k == "string" : normalized.kty !== "oct" && (requiresPrivateKey ? normalized.kty === "AKP" && typeof normalized.priv == "string" || typeof normalized.d == "string" : normalized.d === undefined && normalized.priv === undefined)))
|
|
489
|
+
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 ${requiresPrivateKey ? "private" : "public"} JWK`);
|
|
490
490
|
if (jwkMatchesOp(entry, normalized, usage), normalized.kty === "oct")
|
|
491
491
|
return decode(normalized.k);
|
|
492
492
|
if (!Object.isFrozen(key)) {
|
|
@@ -496,7 +496,7 @@ async function prepareKey(entry, key, usage) {
|
|
|
496
496
|
} else {
|
|
497
497
|
if (!isKeyLike(key))
|
|
498
498
|
throw invalidKeyType(alg, key, secret);
|
|
499
|
-
const expectedType = secret ? "secret" :
|
|
499
|
+
const expectedType = secret ? "secret" : requiresPrivateKey ? "private" : "public";
|
|
500
500
|
if (key.type !== expectedType && (secret || ["secret", "public", "private"].includes(key.type)))
|
|
501
501
|
throw new TypeError(`${tag(key)} instances must be of type "${expectedType}" for the ${alg} algorithm`);
|
|
502
502
|
if (isCryptoKey(key))
|
|
@@ -635,8 +635,8 @@ function eddsa() {
|
|
|
635
635
|
usages: sig
|
|
636
636
|
};
|
|
637
637
|
}
|
|
638
|
-
function mldsa(
|
|
639
|
-
const subtle = { name: `ML-DSA-${
|
|
638
|
+
function mldsa(parameterSet) {
|
|
639
|
+
const subtle = { name: `ML-DSA-${parameterSet}` };
|
|
640
640
|
return {
|
|
641
641
|
kty: ["AKP"],
|
|
642
642
|
subtle,
|
|
@@ -674,21 +674,23 @@ function jwsAlgorithm(alg) {
|
|
|
674
674
|
function prepareVerify(options) {
|
|
675
675
|
return [options && validateAlgorithms("algorithms", options.algorithms), options?.crit];
|
|
676
676
|
}
|
|
677
|
-
function parseProtectedHeader(
|
|
678
|
-
return
|
|
677
|
+
function parseProtectedHeader(encodedProtectedHeader) {
|
|
678
|
+
return encodedProtectedHeader === undefined ? {} : parseJoseHeader(encodedProtectedHeader, JWSInvalid, "JWS Protected Header is invalid");
|
|
679
679
|
}
|
|
680
680
|
function encodeCompactUnencodedPayload(payload) {
|
|
681
681
|
try {
|
|
682
682
|
return encode(payload);
|
|
683
|
-
} catch {
|
|
684
|
-
throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters"
|
|
683
|
+
} catch (cause) {
|
|
684
|
+
throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters", {
|
|
685
|
+
cause
|
|
686
|
+
});
|
|
685
687
|
}
|
|
686
688
|
}
|
|
687
689
|
async function verifySignature(jws, shared, key, encodeUnencodedPayload, parsedProtected) {
|
|
688
|
-
const { protected:
|
|
689
|
-
if (!isDisjoint(
|
|
690
|
+
const { protected: encodedProtectedHeader, header, payload: inputPayload } = jws, protectedHeader = parsedProtected ?? parseProtectedHeader(encodedProtectedHeader);
|
|
691
|
+
if (!isDisjoint(protectedHeader, header))
|
|
690
692
|
throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
691
|
-
const joseHeader = { ...
|
|
693
|
+
const joseHeader = { ...protectedHeader, ...header }, b64 = validateB64(protectedHeader, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], protectedHeader, joseHeader)), { alg } = joseHeader;
|
|
692
694
|
if (typeof alg != "string" || !alg)
|
|
693
695
|
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
694
696
|
if (shared[0] && !shared[0].has(alg))
|
|
@@ -700,17 +702,19 @@ async function verifySignature(jws, shared, key, encodeUnencodedPayload, parsedP
|
|
|
700
702
|
throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
|
|
701
703
|
const signingPayload = b64 || typeof inputPayload != "string" ? inputPayload : encodeUnencodedPayload(inputPayload);
|
|
702
704
|
let resolvedKey = false;
|
|
703
|
-
typeof key == "function" && (key = await key(
|
|
704
|
-
const entry = jwsAlgorithm(alg),
|
|
705
|
+
typeof key == "function" && (key = await key(protectedHeader, jws), resolvedKey = true);
|
|
706
|
+
const entry = jwsAlgorithm(alg), signingInput = concat(encodedProtectedHeader !== undefined ? encode(encodedProtectedHeader) : new Uint8Array, encode("."), typeof signingPayload == "string" ? shared[2] ??= encodeAsciiMember(signingPayload, "payload", JWSInvalid) : signingPayload), signature = decodeBase64url(jws.signature, "signature", JWSInvalid), verificationKey = await prepareKey(entry, key, "verify"), cryptoKey = await rawKey(verificationKey, entry.subtle, "verify");
|
|
705
707
|
entry.minRsaBits && checkModulusLength(entry.alg, cryptoKey);
|
|
706
708
|
let verified = false;
|
|
707
709
|
try {
|
|
708
|
-
verified = await crypto.subtle.verify(entry.signing, cryptoKey, signature,
|
|
709
|
-
} catch {
|
|
710
|
+
verified = await crypto.subtle.verify(entry.signing, cryptoKey, signature, signingInput);
|
|
711
|
+
} catch (cause) {
|
|
712
|
+
throw new JWSSignatureVerificationFailed(undefined, { cause });
|
|
713
|
+
}
|
|
710
714
|
if (!verified)
|
|
711
715
|
throw new JWSSignatureVerificationFailed;
|
|
712
716
|
const result = { payload: typeof signingPayload == "string" ? decodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload };
|
|
713
|
-
return
|
|
717
|
+
return encodedProtectedHeader !== undefined && (result.protectedHeader = protectedHeader), header !== undefined && (result.unprotectedHeader = header), resolvedKey ? [{ ...result, key: verificationKey }, b64] : [result, b64];
|
|
714
718
|
}
|
|
715
719
|
async function verifyCompact(jws, shared, key) {
|
|
716
720
|
if (jws instanceof Uint8Array && (jws = decoder2.decode(jws)), typeof jws != "string")
|
|
@@ -740,8 +744,8 @@ function secs(str) {
|
|
|
740
744
|
typeof str != "string" && invalidDuration();
|
|
741
745
|
const matched = REGEX.exec(str);
|
|
742
746
|
(!matched || matched[4] && matched[1]) && invalidDuration();
|
|
743
|
-
const value = parseFloat(matched[2]),
|
|
744
|
-
return Number.isFinite(
|
|
747
|
+
const value = parseFloat(matched[2]), durationSeconds = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
|
|
748
|
+
return Number.isFinite(durationSeconds) || invalidDuration(), matched[1] === "-" || matched[4] === "ago" ? -durationSeconds : durationSeconds;
|
|
745
749
|
}
|
|
746
750
|
function validateInput(label, input) {
|
|
747
751
|
if (!Number.isFinite(input))
|
|
@@ -753,33 +757,35 @@ var normalizeTyp = (value) => {
|
|
|
753
757
|
return value.includes("/") ? normalized : `application/${normalized}`;
|
|
754
758
|
};
|
|
755
759
|
var checkAudiencePresence = (audPayload, audOption) => typeof audPayload == "string" ? audOption.includes(audPayload) : Array.isArray(audPayload) ? audOption.some((aud) => audPayload.includes(aud)) : false;
|
|
756
|
-
function validateNumericDate(
|
|
757
|
-
const value =
|
|
760
|
+
function validateNumericDate(claimsSet, claim, required = false) {
|
|
761
|
+
const value = claimsSet[claim];
|
|
758
762
|
if (!(value === undefined && !required)) {
|
|
759
763
|
if (typeof value != "number")
|
|
760
|
-
throw new JWTClaimValidationFailed(`"${claim}" claim must be a number`,
|
|
764
|
+
throw new JWTClaimValidationFailed(`"${claim}" claim must be a number`, claimsSet, claim, "invalid");
|
|
761
765
|
return value;
|
|
762
766
|
}
|
|
763
767
|
}
|
|
764
|
-
function unexpectedClaim(
|
|
765
|
-
throw new JWTClaimValidationFailed(`unexpected "${claim}" claim value`,
|
|
768
|
+
function unexpectedClaim(claimsSet, claim) {
|
|
769
|
+
throw new JWTClaimValidationFailed(`unexpected "${claim}" claim value`, claimsSet, claim, checkFailed);
|
|
766
770
|
}
|
|
767
|
-
function validateClaimsSet(protectedHeader,
|
|
768
|
-
let
|
|
771
|
+
function validateClaimsSet(protectedHeader, claimsSetBytes, options = {}) {
|
|
772
|
+
let claimsSet;
|
|
769
773
|
try {
|
|
770
|
-
|
|
771
|
-
} catch {
|
|
772
|
-
|
|
774
|
+
claimsSet = JSON.parse(strictDecoder.decode(claimsSetBytes));
|
|
775
|
+
} catch (cause) {
|
|
776
|
+
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object", { cause });
|
|
777
|
+
}
|
|
778
|
+
if (!isObject(claimsSet))
|
|
773
779
|
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
|
|
774
780
|
const { typ } = options;
|
|
775
781
|
if (typ !== undefined && (typeof protectedHeader.typ != "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ)))
|
|
776
|
-
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value',
|
|
782
|
+
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', claimsSet, "typ", checkFailed);
|
|
777
783
|
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options, presenceCheck = [...requiredClaims];
|
|
778
784
|
maxTokenAge !== undefined && presenceCheck.push("iat"), audience !== undefined && presenceCheck.push("aud"), subject !== undefined && presenceCheck.push("sub"), issuer !== undefined && presenceCheck.push("iss");
|
|
779
785
|
for (const claim of new Set(presenceCheck.reverse()))
|
|
780
|
-
if (!Object.hasOwn(
|
|
781
|
-
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`,
|
|
782
|
-
issuer !== undefined && !(Array.isArray(issuer) ? issuer : [issuer]).includes(
|
|
786
|
+
if (!Object.hasOwn(claimsSet, claim))
|
|
787
|
+
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, claimsSet, claim, "missing");
|
|
788
|
+
issuer !== undefined && !(Array.isArray(issuer) ? issuer : [issuer]).includes(claimsSet.iss) && unexpectedClaim(claimsSet, "iss"), subject !== undefined && claimsSet.sub !== subject && unexpectedClaim(claimsSet, "sub"), audience !== undefined && !checkAudiencePresence(claimsSet.aud, typeof audience == "string" ? [audience] : audience) && unexpectedClaim(claimsSet, "aud");
|
|
783
789
|
const { clockTolerance } = options;
|
|
784
790
|
let tolerance = 0;
|
|
785
791
|
if (typeof clockTolerance == "string")
|
|
@@ -790,20 +796,20 @@ function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
|
|
|
790
796
|
tolerance = clockTolerance;
|
|
791
797
|
}
|
|
792
798
|
validateInput("clockTolerance option", tolerance);
|
|
793
|
-
const { currentDate } = options, now = validateInput("currentDate option", epoch(currentDate === undefined ? /* @__PURE__ */ new Date : currentDate)), iat = validateNumericDate(
|
|
799
|
+
const { currentDate } = options, now = validateInput("currentDate option", epoch(currentDate === undefined ? /* @__PURE__ */ new Date : currentDate)), iat = validateNumericDate(claimsSet, "iat", maxTokenAge !== undefined), nbf = validateNumericDate(claimsSet, "nbf");
|
|
794
800
|
if (nbf !== undefined && nbf > now + tolerance)
|
|
795
|
-
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed',
|
|
796
|
-
const exp = validateNumericDate(
|
|
801
|
+
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', claimsSet, "nbf", checkFailed);
|
|
802
|
+
const exp = validateNumericDate(claimsSet, "exp");
|
|
797
803
|
if (exp !== undefined && exp <= now - tolerance)
|
|
798
|
-
throw new JWTExpired('"exp" claim timestamp check failed',
|
|
804
|
+
throw new JWTExpired('"exp" claim timestamp check failed', claimsSet, "exp", checkFailed);
|
|
799
805
|
if (maxTokenAge !== undefined) {
|
|
800
806
|
const age = now - iat, max = validateInput("maxTokenAge option", typeof maxTokenAge == "number" ? maxTokenAge : secs(maxTokenAge));
|
|
801
807
|
if (age - tolerance > max)
|
|
802
|
-
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)',
|
|
808
|
+
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', claimsSet, "iat", checkFailed);
|
|
803
809
|
if (age < -tolerance)
|
|
804
|
-
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)',
|
|
810
|
+
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', claimsSet, "iat", checkFailed);
|
|
805
811
|
}
|
|
806
|
-
return
|
|
812
|
+
return claimsSet;
|
|
807
813
|
}
|
|
808
814
|
|
|
809
815
|
// node_modules/jose/dist/webapi/jwt/verify.js
|
|
@@ -838,7 +844,9 @@ function createLocalJWKSet(jwks) {
|
|
|
838
844
|
let snapshot;
|
|
839
845
|
try {
|
|
840
846
|
snapshot = structuredClone(jwks);
|
|
841
|
-
} catch {
|
|
847
|
+
} catch (cause) {
|
|
848
|
+
throw new JWKSInvalid("JSON Web Key Set malformed", { cause });
|
|
849
|
+
}
|
|
842
850
|
if (!isJwkSet(snapshot))
|
|
843
851
|
throw new JWKSInvalid("JSON Web Key Set malformed");
|
|
844
852
|
const metadata = snapshot.keys.map((jwk) => {
|
|
@@ -872,7 +880,7 @@ function isCloudflareWorkers() {
|
|
|
872
880
|
return typeof WebSocketPair < "u" || typeof navigator < "u" && navigator.userAgent === "Cloudflare-Workers" || typeof EdgeRuntime < "u" && EdgeRuntime === "vercel";
|
|
873
881
|
}
|
|
874
882
|
var USER_AGENT;
|
|
875
|
-
(typeof navigator > "u" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) && (USER_AGENT = "jose/v6.2.
|
|
883
|
+
(typeof navigator > "u" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) && (USER_AGENT = "jose/v6.2.13");
|
|
876
884
|
var customFetch = /* @__PURE__ */ Symbol();
|
|
877
885
|
async function fetchJwks(url, headers, signal, fetchImpl = fetch) {
|
|
878
886
|
const response = await fetchImpl(url, {
|
|
@@ -881,14 +889,14 @@ async function fetchJwks(url, headers, signal, fetchImpl = fetch) {
|
|
|
881
889
|
redirect: "manual",
|
|
882
890
|
headers
|
|
883
891
|
}).catch((err) => {
|
|
884
|
-
throw err.name === "TimeoutError" ? new JWKSTimeout : err;
|
|
892
|
+
throw err.name === "TimeoutError" ? new JWKSTimeout(undefined, { cause: err }) : err;
|
|
885
893
|
});
|
|
886
894
|
if (response.status !== 200)
|
|
887
895
|
throw new JOSEError("Expected 200 OK from the JSON Web Key Set HTTP response");
|
|
888
896
|
try {
|
|
889
897
|
return await response.json();
|
|
890
|
-
} catch {
|
|
891
|
-
throw new JOSEError("Failed to parse the JSON Web Key Set HTTP response as JSON");
|
|
898
|
+
} catch (cause) {
|
|
899
|
+
throw new JOSEError("Failed to parse the JSON Web Key Set HTTP response as JSON", { cause });
|
|
892
900
|
}
|
|
893
901
|
}
|
|
894
902
|
var jwksCache = /* @__PURE__ */ Symbol();
|
|
@@ -9772,8 +9780,7 @@ class RealtimeEngine {
|
|
|
9772
9780
|
private: isPrivate,
|
|
9773
9781
|
canBroadcast
|
|
9774
9782
|
};
|
|
9775
|
-
|
|
9776
|
-
this.leaveChannel(conn, msg.topic);
|
|
9783
|
+
this.leaveChannel(conn, msg.topic);
|
|
9777
9784
|
conn.channels.set(msg.topic, channel);
|
|
9778
9785
|
this.scheduleExternalExpiry(conn, channel);
|
|
9779
9786
|
this.reply(conn, msg, "ok", {
|
|
@@ -9813,21 +9820,32 @@ class RealtimeEngine {
|
|
|
9813
9820
|
if (channel.expiryTimer)
|
|
9814
9821
|
clearTimeout(channel.expiryTimer);
|
|
9815
9822
|
conn.channels.delete(topic);
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9823
|
+
this.removePresence(channel);
|
|
9824
|
+
}
|
|
9825
|
+
removePresence(channel) {
|
|
9826
|
+
const presenceRef = channel.presenceRef;
|
|
9827
|
+
if (!presenceRef)
|
|
9828
|
+
return;
|
|
9829
|
+
channel.presenceRef = undefined;
|
|
9830
|
+
const state = this.presence.get(channel.topic);
|
|
9831
|
+
const current = state?.get(channel.presenceKey);
|
|
9832
|
+
const leaving = current?.metas.find((meta) => meta.phx_ref === presenceRef);
|
|
9833
|
+
if (!state || !current || !leaving)
|
|
9834
|
+
return;
|
|
9835
|
+
const remaining = current.metas.filter((meta) => meta.phx_ref !== presenceRef);
|
|
9836
|
+
if (remaining.length > 0) {
|
|
9837
|
+
state.set(channel.presenceKey, { metas: remaining });
|
|
9838
|
+
} else {
|
|
9821
9839
|
state.delete(channel.presenceKey);
|
|
9822
9840
|
if (state.size === 0)
|
|
9823
|
-
this.presence.delete(topic);
|
|
9824
|
-
this.broadcastToTopic(topic, {
|
|
9825
|
-
topic,
|
|
9826
|
-
event: "presence_diff",
|
|
9827
|
-
payload: { joins: {}, leaves: { [channel.presenceKey]: metas } },
|
|
9828
|
-
ref: null
|
|
9829
|
-
});
|
|
9841
|
+
this.presence.delete(channel.topic);
|
|
9830
9842
|
}
|
|
9843
|
+
this.broadcastToTopic(channel.topic, {
|
|
9844
|
+
topic: channel.topic,
|
|
9845
|
+
event: "presence_diff",
|
|
9846
|
+
payload: { joins: {}, leaves: { [channel.presenceKey]: { metas: [leaving] } } },
|
|
9847
|
+
ref: null
|
|
9848
|
+
});
|
|
9831
9849
|
}
|
|
9832
9850
|
scheduleExternalExpiry(conn, channel) {
|
|
9833
9851
|
if (channel.expiryTimer)
|
|
@@ -9907,23 +9925,30 @@ class RealtimeEngine {
|
|
|
9907
9925
|
return;
|
|
9908
9926
|
const event = String(msg.payload?.event ?? "").toLowerCase();
|
|
9909
9927
|
if (event === "track") {
|
|
9910
|
-
const
|
|
9911
|
-
|
|
9912
|
-
|
|
9913
|
-
};
|
|
9928
|
+
const payload = { ...msg.payload?.payload ?? {} };
|
|
9929
|
+
delete payload.phx_ref;
|
|
9930
|
+
delete payload.phx_ref_prev;
|
|
9914
9931
|
let state = this.presence.get(msg.topic);
|
|
9915
9932
|
if (!state) {
|
|
9916
9933
|
state = new Map;
|
|
9917
9934
|
this.presence.set(msg.topic, state);
|
|
9918
9935
|
}
|
|
9919
|
-
const
|
|
9920
|
-
|
|
9936
|
+
const current = state.get(channel.presenceKey);
|
|
9937
|
+
const previous = current?.metas.find((meta) => meta.phx_ref === channel.presenceRef);
|
|
9938
|
+
const meta = {
|
|
9939
|
+
...payload,
|
|
9940
|
+
phx_ref: `F${this.phxRefCounter++}`,
|
|
9941
|
+
...previous ? { phx_ref_prev: previous.phx_ref } : {}
|
|
9942
|
+
};
|
|
9943
|
+
const others = current?.metas.filter((meta) => meta.phx_ref !== channel.presenceRef) ?? [];
|
|
9944
|
+
state.set(channel.presenceKey, { metas: [...others, meta] });
|
|
9945
|
+
channel.presenceRef = meta.phx_ref;
|
|
9921
9946
|
this.broadcastToTopic(msg.topic, {
|
|
9922
9947
|
topic: msg.topic,
|
|
9923
9948
|
event: "presence_diff",
|
|
9924
9949
|
payload: {
|
|
9925
9950
|
joins: { [channel.presenceKey]: { metas: [meta] } },
|
|
9926
|
-
leaves: previous ? { [channel.presenceKey]: previous } : {}
|
|
9951
|
+
leaves: previous ? { [channel.presenceKey]: { metas: [previous] } } : {}
|
|
9927
9952
|
},
|
|
9928
9953
|
ref: null
|
|
9929
9954
|
});
|
|
@@ -9932,19 +9957,7 @@ class RealtimeEngine {
|
|
|
9932
9957
|
return;
|
|
9933
9958
|
}
|
|
9934
9959
|
if (event === "untrack") {
|
|
9935
|
-
|
|
9936
|
-
const metas = state?.get(channel.presenceKey);
|
|
9937
|
-
if (state && metas) {
|
|
9938
|
-
state.delete(channel.presenceKey);
|
|
9939
|
-
if (state.size === 0)
|
|
9940
|
-
this.presence.delete(msg.topic);
|
|
9941
|
-
this.broadcastToTopic(msg.topic, {
|
|
9942
|
-
topic: msg.topic,
|
|
9943
|
-
event: "presence_diff",
|
|
9944
|
-
payload: { joins: {}, leaves: { [channel.presenceKey]: metas } },
|
|
9945
|
-
ref: null
|
|
9946
|
-
});
|
|
9947
|
-
}
|
|
9960
|
+
this.removePresence(channel);
|
|
9948
9961
|
if (msg.ref)
|
|
9949
9962
|
this.reply(conn, msg, "ok", {});
|
|
9950
9963
|
}
|
package/dist/index.js
CHANGED
|
@@ -88,7 +88,7 @@ function randomToken(bytes = 32) {
|
|
|
88
88
|
// package.json
|
|
89
89
|
var package_default = {
|
|
90
90
|
name: "@supacloud/lite",
|
|
91
|
-
version: "0.33.
|
|
91
|
+
version: "0.33.2",
|
|
92
92
|
description: "Bun-native, single-project Supabase-compatible backend powered by PGlite or native PostgreSQL",
|
|
93
93
|
type: "module",
|
|
94
94
|
license: "Apache-2.0",
|
|
@@ -127,7 +127,7 @@ var package_default = {
|
|
|
127
127
|
clean: "bun -e 'import { $ } from \"bun\"; await $`rm -rf dist`'",
|
|
128
128
|
dev: "bun run src/cli.ts start",
|
|
129
129
|
start: "bun run src/cli.ts start",
|
|
130
|
-
test: "bun
|
|
130
|
+
test: "bun run scripts/run-tests.ts",
|
|
131
131
|
"test:native": "SUPACLOUD_LITE_TEST_NATIVE=1 bun test test/native-engine.test.ts test/qauth-workflow-matrix.test.ts test/maker-checker-workflow.test.ts test/commands-artifacts.test.ts --timeout 180000",
|
|
132
132
|
"test:graphql": "SUPACLOUD_LITE_TEST_GRAPHQL=1 bun test test/graphql-native.test.ts --timeout 180000",
|
|
133
133
|
benchmark: "bun run scripts/benchmark.ts",
|
|
@@ -147,31 +147,31 @@ var package_default = {
|
|
|
147
147
|
"@electric-sql/pglite-pgmq": "0.0.8",
|
|
148
148
|
"@electric-sql/pglite-pgvector": "0.0.11",
|
|
149
149
|
"@electric-sql/pglite-postgis": "0.2.10",
|
|
150
|
-
"@supacloud/db": "0.20.
|
|
150
|
+
"@supacloud/db": "0.20.1",
|
|
151
151
|
"exact-mirror": "1.2.6",
|
|
152
152
|
tar: "^7.5.22",
|
|
153
|
-
typebox: "1.
|
|
153
|
+
typebox: "1.4.2"
|
|
154
154
|
},
|
|
155
155
|
devDependencies: {
|
|
156
|
-
"@supacloud/app": "0.
|
|
157
|
-
"@supacloud/contracts": "0.
|
|
158
|
-
"@supacloud/compiler": "0.
|
|
159
|
-
"@supacloud/elysia": "0.
|
|
160
|
-
"@supabase/supabase-js": "^2.
|
|
156
|
+
"@supacloud/app": "0.33.0",
|
|
157
|
+
"@supacloud/contracts": "0.15.1",
|
|
158
|
+
"@supacloud/compiler": "0.51.1",
|
|
159
|
+
"@supacloud/elysia": "0.36.1",
|
|
160
|
+
"@supabase/supabase-js": "^2.118.0",
|
|
161
161
|
"@types/bun": "^1.4.3",
|
|
162
162
|
effect: "4.0.5",
|
|
163
|
-
elysia: "2.0.0-
|
|
164
|
-
jose: "^6.2.
|
|
163
|
+
elysia: "2.0.0-rc.0",
|
|
164
|
+
jose: "^6.2.13",
|
|
165
165
|
typescript: "^7.0.2"
|
|
166
166
|
},
|
|
167
167
|
overrides: {
|
|
168
|
-
"@supacloud/db": "0.20.
|
|
169
|
-
"@supacloud/app": "0.
|
|
170
|
-
"@supacloud/compiler": "0.
|
|
171
|
-
"@supacloud/elysia": "0.
|
|
172
|
-
"@supacloud/contracts": "0.
|
|
173
|
-
"@supacloud/commands": "0.11.
|
|
174
|
-
"@supacloud/delivery": "0.21.
|
|
168
|
+
"@supacloud/db": "0.20.1",
|
|
169
|
+
"@supacloud/app": "0.33.0",
|
|
170
|
+
"@supacloud/compiler": "0.51.1",
|
|
171
|
+
"@supacloud/elysia": "0.36.1",
|
|
172
|
+
"@supacloud/contracts": "0.15.1",
|
|
173
|
+
"@supacloud/commands": "0.11.1",
|
|
174
|
+
"@supacloud/delivery": "0.21.1",
|
|
175
175
|
"@graphql-tools/utils": "^12.0.4"
|
|
176
176
|
},
|
|
177
177
|
engines: {
|
|
@@ -251,7 +251,7 @@ function isAllowedRedirect(requested, siteUrl, allowList = []) {
|
|
|
251
251
|
var encoder2 = new TextEncoder;
|
|
252
252
|
var decoder2 = new TextDecoder;
|
|
253
253
|
var strictDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
254
|
-
var
|
|
254
|
+
var UINT32_RANGE = 2 ** 32;
|
|
255
255
|
function concat(...buffers) {
|
|
256
256
|
const size = buffers.reduce((acc, { length }) => acc + length, 0), buf = new Uint8Array(size);
|
|
257
257
|
let i = 0;
|
|
@@ -410,23 +410,23 @@ function isDisjoint(...headers) {
|
|
|
410
410
|
function decodeBase64url(value, label, ErrorClass) {
|
|
411
411
|
try {
|
|
412
412
|
return decode(value);
|
|
413
|
-
} catch {
|
|
414
|
-
throw new ErrorClass(`Failed to base64url decode the ${label}
|
|
413
|
+
} catch (cause) {
|
|
414
|
+
throw new ErrorClass(`Failed to base64url decode the ${label}`, { cause });
|
|
415
415
|
}
|
|
416
416
|
}
|
|
417
|
-
function
|
|
417
|
+
function encodeAsciiMember(value, label, ErrorClass) {
|
|
418
418
|
try {
|
|
419
419
|
return encode(value);
|
|
420
|
-
} catch {
|
|
421
|
-
throw new ErrorClass(`The ${label} is not a valid base64url string
|
|
420
|
+
} catch (cause) {
|
|
421
|
+
throw new ErrorClass(`The ${label} is not a valid base64url string`, { cause });
|
|
422
422
|
}
|
|
423
423
|
}
|
|
424
|
-
function parseJoseHeader(
|
|
424
|
+
function parseJoseHeader(encodedProtectedHeader, ErrorClass, message) {
|
|
425
425
|
let parsed;
|
|
426
426
|
try {
|
|
427
|
-
parsed = JSON.parse(strictDecoder.decode(decode(
|
|
428
|
-
} catch {
|
|
429
|
-
throw new ErrorClass(message);
|
|
427
|
+
parsed = JSON.parse(strictDecoder.decode(decode(encodedProtectedHeader)));
|
|
428
|
+
} catch (cause) {
|
|
429
|
+
throw new ErrorClass(message, { cause });
|
|
430
430
|
}
|
|
431
431
|
if (!isObject(parsed))
|
|
432
432
|
throw new ErrorClass(message);
|
|
@@ -484,15 +484,15 @@ var jwkMatchesOp = (entry, key, usage) => {
|
|
|
484
484
|
}
|
|
485
485
|
};
|
|
486
486
|
async function prepareKey(entry, key, usage) {
|
|
487
|
-
const { alg, secret } = entry,
|
|
487
|
+
const { alg, secret } = entry, requiresPrivateKey = usage === "decrypt" || usage === "sign";
|
|
488
488
|
if (secret && key instanceof Uint8Array)
|
|
489
489
|
return key;
|
|
490
490
|
let normalized, keyObject;
|
|
491
491
|
if (isObject(key)) {
|
|
492
492
|
if (normalized = normalizeJwk(key), typeof normalized.kty != "string")
|
|
493
493
|
throw invalidKeyType(alg, key, secret);
|
|
494
|
-
if (!(secret ? normalized.kty === "oct" && typeof normalized.k == "string" : normalized.kty !== "oct" && (
|
|
495
|
-
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 ${
|
|
494
|
+
if (!(secret ? normalized.kty === "oct" && typeof normalized.k == "string" : normalized.kty !== "oct" && (requiresPrivateKey ? normalized.kty === "AKP" && typeof normalized.priv == "string" || typeof normalized.d == "string" : normalized.d === undefined && normalized.priv === undefined)))
|
|
495
|
+
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 ${requiresPrivateKey ? "private" : "public"} JWK`);
|
|
496
496
|
if (jwkMatchesOp(entry, normalized, usage), normalized.kty === "oct")
|
|
497
497
|
return decode(normalized.k);
|
|
498
498
|
if (!Object.isFrozen(key)) {
|
|
@@ -502,7 +502,7 @@ async function prepareKey(entry, key, usage) {
|
|
|
502
502
|
} else {
|
|
503
503
|
if (!isKeyLike(key))
|
|
504
504
|
throw invalidKeyType(alg, key, secret);
|
|
505
|
-
const expectedType = secret ? "secret" :
|
|
505
|
+
const expectedType = secret ? "secret" : requiresPrivateKey ? "private" : "public";
|
|
506
506
|
if (key.type !== expectedType && (secret || ["secret", "public", "private"].includes(key.type)))
|
|
507
507
|
throw new TypeError(`${tag(key)} instances must be of type "${expectedType}" for the ${alg} algorithm`);
|
|
508
508
|
if (isCryptoKey(key))
|
|
@@ -641,8 +641,8 @@ function eddsa() {
|
|
|
641
641
|
usages: sig
|
|
642
642
|
};
|
|
643
643
|
}
|
|
644
|
-
function mldsa(
|
|
645
|
-
const subtle = { name: `ML-DSA-${
|
|
644
|
+
function mldsa(parameterSet) {
|
|
645
|
+
const subtle = { name: `ML-DSA-${parameterSet}` };
|
|
646
646
|
return {
|
|
647
647
|
kty: ["AKP"],
|
|
648
648
|
subtle,
|
|
@@ -680,21 +680,23 @@ function jwsAlgorithm(alg) {
|
|
|
680
680
|
function prepareVerify(options) {
|
|
681
681
|
return [options && validateAlgorithms("algorithms", options.algorithms), options?.crit];
|
|
682
682
|
}
|
|
683
|
-
function parseProtectedHeader(
|
|
684
|
-
return
|
|
683
|
+
function parseProtectedHeader(encodedProtectedHeader) {
|
|
684
|
+
return encodedProtectedHeader === undefined ? {} : parseJoseHeader(encodedProtectedHeader, JWSInvalid, "JWS Protected Header is invalid");
|
|
685
685
|
}
|
|
686
686
|
function encodeCompactUnencodedPayload(payload) {
|
|
687
687
|
try {
|
|
688
688
|
return encode(payload);
|
|
689
|
-
} catch {
|
|
690
|
-
throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters"
|
|
689
|
+
} catch (cause) {
|
|
690
|
+
throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters", {
|
|
691
|
+
cause
|
|
692
|
+
});
|
|
691
693
|
}
|
|
692
694
|
}
|
|
693
695
|
async function verifySignature(jws, shared, key, encodeUnencodedPayload, parsedProtected) {
|
|
694
|
-
const { protected:
|
|
695
|
-
if (!isDisjoint(
|
|
696
|
+
const { protected: encodedProtectedHeader, header, payload: inputPayload } = jws, protectedHeader = parsedProtected ?? parseProtectedHeader(encodedProtectedHeader);
|
|
697
|
+
if (!isDisjoint(protectedHeader, header))
|
|
696
698
|
throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
697
|
-
const joseHeader = { ...
|
|
699
|
+
const joseHeader = { ...protectedHeader, ...header }, b64 = validateB64(protectedHeader, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], protectedHeader, joseHeader)), { alg } = joseHeader;
|
|
698
700
|
if (typeof alg != "string" || !alg)
|
|
699
701
|
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
700
702
|
if (shared[0] && !shared[0].has(alg))
|
|
@@ -706,17 +708,19 @@ async function verifySignature(jws, shared, key, encodeUnencodedPayload, parsedP
|
|
|
706
708
|
throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
|
|
707
709
|
const signingPayload = b64 || typeof inputPayload != "string" ? inputPayload : encodeUnencodedPayload(inputPayload);
|
|
708
710
|
let resolvedKey = false;
|
|
709
|
-
typeof key == "function" && (key = await key(
|
|
710
|
-
const entry = jwsAlgorithm(alg),
|
|
711
|
+
typeof key == "function" && (key = await key(protectedHeader, jws), resolvedKey = true);
|
|
712
|
+
const entry = jwsAlgorithm(alg), signingInput = concat(encodedProtectedHeader !== undefined ? encode(encodedProtectedHeader) : new Uint8Array, encode("."), typeof signingPayload == "string" ? shared[2] ??= encodeAsciiMember(signingPayload, "payload", JWSInvalid) : signingPayload), signature = decodeBase64url(jws.signature, "signature", JWSInvalid), verificationKey = await prepareKey(entry, key, "verify"), cryptoKey = await rawKey(verificationKey, entry.subtle, "verify");
|
|
711
713
|
entry.minRsaBits && checkModulusLength(entry.alg, cryptoKey);
|
|
712
714
|
let verified = false;
|
|
713
715
|
try {
|
|
714
|
-
verified = await crypto.subtle.verify(entry.signing, cryptoKey, signature,
|
|
715
|
-
} catch {
|
|
716
|
+
verified = await crypto.subtle.verify(entry.signing, cryptoKey, signature, signingInput);
|
|
717
|
+
} catch (cause) {
|
|
718
|
+
throw new JWSSignatureVerificationFailed(undefined, { cause });
|
|
719
|
+
}
|
|
716
720
|
if (!verified)
|
|
717
721
|
throw new JWSSignatureVerificationFailed;
|
|
718
722
|
const result = { payload: typeof signingPayload == "string" ? decodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload };
|
|
719
|
-
return
|
|
723
|
+
return encodedProtectedHeader !== undefined && (result.protectedHeader = protectedHeader), header !== undefined && (result.unprotectedHeader = header), resolvedKey ? [{ ...result, key: verificationKey }, b64] : [result, b64];
|
|
720
724
|
}
|
|
721
725
|
async function verifyCompact(jws, shared, key) {
|
|
722
726
|
if (jws instanceof Uint8Array && (jws = decoder2.decode(jws)), typeof jws != "string")
|
|
@@ -746,8 +750,8 @@ function secs(str) {
|
|
|
746
750
|
typeof str != "string" && invalidDuration();
|
|
747
751
|
const matched = REGEX.exec(str);
|
|
748
752
|
(!matched || matched[4] && matched[1]) && invalidDuration();
|
|
749
|
-
const value = parseFloat(matched[2]),
|
|
750
|
-
return Number.isFinite(
|
|
753
|
+
const value = parseFloat(matched[2]), durationSeconds = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
|
|
754
|
+
return Number.isFinite(durationSeconds) || invalidDuration(), matched[1] === "-" || matched[4] === "ago" ? -durationSeconds : durationSeconds;
|
|
751
755
|
}
|
|
752
756
|
function validateInput(label, input) {
|
|
753
757
|
if (!Number.isFinite(input))
|
|
@@ -759,33 +763,35 @@ var normalizeTyp = (value) => {
|
|
|
759
763
|
return value.includes("/") ? normalized : `application/${normalized}`;
|
|
760
764
|
};
|
|
761
765
|
var checkAudiencePresence = (audPayload, audOption) => typeof audPayload == "string" ? audOption.includes(audPayload) : Array.isArray(audPayload) ? audOption.some((aud) => audPayload.includes(aud)) : false;
|
|
762
|
-
function validateNumericDate(
|
|
763
|
-
const value =
|
|
766
|
+
function validateNumericDate(claimsSet, claim, required = false) {
|
|
767
|
+
const value = claimsSet[claim];
|
|
764
768
|
if (!(value === undefined && !required)) {
|
|
765
769
|
if (typeof value != "number")
|
|
766
|
-
throw new JWTClaimValidationFailed(`"${claim}" claim must be a number`,
|
|
770
|
+
throw new JWTClaimValidationFailed(`"${claim}" claim must be a number`, claimsSet, claim, "invalid");
|
|
767
771
|
return value;
|
|
768
772
|
}
|
|
769
773
|
}
|
|
770
|
-
function unexpectedClaim(
|
|
771
|
-
throw new JWTClaimValidationFailed(`unexpected "${claim}" claim value`,
|
|
774
|
+
function unexpectedClaim(claimsSet, claim) {
|
|
775
|
+
throw new JWTClaimValidationFailed(`unexpected "${claim}" claim value`, claimsSet, claim, checkFailed);
|
|
772
776
|
}
|
|
773
|
-
function validateClaimsSet(protectedHeader,
|
|
774
|
-
let
|
|
777
|
+
function validateClaimsSet(protectedHeader, claimsSetBytes, options = {}) {
|
|
778
|
+
let claimsSet;
|
|
775
779
|
try {
|
|
776
|
-
|
|
777
|
-
} catch {
|
|
778
|
-
|
|
780
|
+
claimsSet = JSON.parse(strictDecoder.decode(claimsSetBytes));
|
|
781
|
+
} catch (cause) {
|
|
782
|
+
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object", { cause });
|
|
783
|
+
}
|
|
784
|
+
if (!isObject(claimsSet))
|
|
779
785
|
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
|
|
780
786
|
const { typ } = options;
|
|
781
787
|
if (typ !== undefined && (typeof protectedHeader.typ != "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ)))
|
|
782
|
-
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value',
|
|
788
|
+
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', claimsSet, "typ", checkFailed);
|
|
783
789
|
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options, presenceCheck = [...requiredClaims];
|
|
784
790
|
maxTokenAge !== undefined && presenceCheck.push("iat"), audience !== undefined && presenceCheck.push("aud"), subject !== undefined && presenceCheck.push("sub"), issuer !== undefined && presenceCheck.push("iss");
|
|
785
791
|
for (const claim of new Set(presenceCheck.reverse()))
|
|
786
|
-
if (!Object.hasOwn(
|
|
787
|
-
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`,
|
|
788
|
-
issuer !== undefined && !(Array.isArray(issuer) ? issuer : [issuer]).includes(
|
|
792
|
+
if (!Object.hasOwn(claimsSet, claim))
|
|
793
|
+
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, claimsSet, claim, "missing");
|
|
794
|
+
issuer !== undefined && !(Array.isArray(issuer) ? issuer : [issuer]).includes(claimsSet.iss) && unexpectedClaim(claimsSet, "iss"), subject !== undefined && claimsSet.sub !== subject && unexpectedClaim(claimsSet, "sub"), audience !== undefined && !checkAudiencePresence(claimsSet.aud, typeof audience == "string" ? [audience] : audience) && unexpectedClaim(claimsSet, "aud");
|
|
789
795
|
const { clockTolerance } = options;
|
|
790
796
|
let tolerance = 0;
|
|
791
797
|
if (typeof clockTolerance == "string")
|
|
@@ -796,20 +802,20 @@ function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
|
|
|
796
802
|
tolerance = clockTolerance;
|
|
797
803
|
}
|
|
798
804
|
validateInput("clockTolerance option", tolerance);
|
|
799
|
-
const { currentDate } = options, now = validateInput("currentDate option", epoch(currentDate === undefined ? /* @__PURE__ */ new Date : currentDate)), iat = validateNumericDate(
|
|
805
|
+
const { currentDate } = options, now = validateInput("currentDate option", epoch(currentDate === undefined ? /* @__PURE__ */ new Date : currentDate)), iat = validateNumericDate(claimsSet, "iat", maxTokenAge !== undefined), nbf = validateNumericDate(claimsSet, "nbf");
|
|
800
806
|
if (nbf !== undefined && nbf > now + tolerance)
|
|
801
|
-
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed',
|
|
802
|
-
const exp = validateNumericDate(
|
|
807
|
+
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', claimsSet, "nbf", checkFailed);
|
|
808
|
+
const exp = validateNumericDate(claimsSet, "exp");
|
|
803
809
|
if (exp !== undefined && exp <= now - tolerance)
|
|
804
|
-
throw new JWTExpired('"exp" claim timestamp check failed',
|
|
810
|
+
throw new JWTExpired('"exp" claim timestamp check failed', claimsSet, "exp", checkFailed);
|
|
805
811
|
if (maxTokenAge !== undefined) {
|
|
806
812
|
const age = now - iat, max = validateInput("maxTokenAge option", typeof maxTokenAge == "number" ? maxTokenAge : secs(maxTokenAge));
|
|
807
813
|
if (age - tolerance > max)
|
|
808
|
-
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)',
|
|
814
|
+
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', claimsSet, "iat", checkFailed);
|
|
809
815
|
if (age < -tolerance)
|
|
810
|
-
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)',
|
|
816
|
+
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', claimsSet, "iat", checkFailed);
|
|
811
817
|
}
|
|
812
|
-
return
|
|
818
|
+
return claimsSet;
|
|
813
819
|
}
|
|
814
820
|
|
|
815
821
|
// node_modules/jose/dist/webapi/jwt/verify.js
|
|
@@ -844,7 +850,9 @@ function createLocalJWKSet(jwks) {
|
|
|
844
850
|
let snapshot;
|
|
845
851
|
try {
|
|
846
852
|
snapshot = structuredClone(jwks);
|
|
847
|
-
} catch {
|
|
853
|
+
} catch (cause) {
|
|
854
|
+
throw new JWKSInvalid("JSON Web Key Set malformed", { cause });
|
|
855
|
+
}
|
|
848
856
|
if (!isJwkSet(snapshot))
|
|
849
857
|
throw new JWKSInvalid("JSON Web Key Set malformed");
|
|
850
858
|
const metadata = snapshot.keys.map((jwk) => {
|
|
@@ -878,7 +886,7 @@ function isCloudflareWorkers() {
|
|
|
878
886
|
return typeof WebSocketPair < "u" || typeof navigator < "u" && navigator.userAgent === "Cloudflare-Workers" || typeof EdgeRuntime < "u" && EdgeRuntime === "vercel";
|
|
879
887
|
}
|
|
880
888
|
var USER_AGENT;
|
|
881
|
-
(typeof navigator > "u" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) && (USER_AGENT = "jose/v6.2.
|
|
889
|
+
(typeof navigator > "u" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) && (USER_AGENT = "jose/v6.2.13");
|
|
882
890
|
var customFetch = /* @__PURE__ */ Symbol();
|
|
883
891
|
async function fetchJwks(url, headers, signal, fetchImpl = fetch) {
|
|
884
892
|
const response = await fetchImpl(url, {
|
|
@@ -887,14 +895,14 @@ async function fetchJwks(url, headers, signal, fetchImpl = fetch) {
|
|
|
887
895
|
redirect: "manual",
|
|
888
896
|
headers
|
|
889
897
|
}).catch((err) => {
|
|
890
|
-
throw err.name === "TimeoutError" ? new JWKSTimeout : err;
|
|
898
|
+
throw err.name === "TimeoutError" ? new JWKSTimeout(undefined, { cause: err }) : err;
|
|
891
899
|
});
|
|
892
900
|
if (response.status !== 200)
|
|
893
901
|
throw new JOSEError("Expected 200 OK from the JSON Web Key Set HTTP response");
|
|
894
902
|
try {
|
|
895
903
|
return await response.json();
|
|
896
|
-
} catch {
|
|
897
|
-
throw new JOSEError("Failed to parse the JSON Web Key Set HTTP response as JSON");
|
|
904
|
+
} catch (cause) {
|
|
905
|
+
throw new JOSEError("Failed to parse the JSON Web Key Set HTTP response as JSON", { cause });
|
|
898
906
|
}
|
|
899
907
|
}
|
|
900
908
|
var jwksCache = /* @__PURE__ */ Symbol();
|
|
@@ -9766,8 +9774,7 @@ class RealtimeEngine {
|
|
|
9766
9774
|
private: isPrivate,
|
|
9767
9775
|
canBroadcast
|
|
9768
9776
|
};
|
|
9769
|
-
|
|
9770
|
-
this.leaveChannel(conn, msg.topic);
|
|
9777
|
+
this.leaveChannel(conn, msg.topic);
|
|
9771
9778
|
conn.channels.set(msg.topic, channel);
|
|
9772
9779
|
this.scheduleExternalExpiry(conn, channel);
|
|
9773
9780
|
this.reply(conn, msg, "ok", {
|
|
@@ -9807,21 +9814,32 @@ class RealtimeEngine {
|
|
|
9807
9814
|
if (channel.expiryTimer)
|
|
9808
9815
|
clearTimeout(channel.expiryTimer);
|
|
9809
9816
|
conn.channels.delete(topic);
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9817
|
+
this.removePresence(channel);
|
|
9818
|
+
}
|
|
9819
|
+
removePresence(channel) {
|
|
9820
|
+
const presenceRef = channel.presenceRef;
|
|
9821
|
+
if (!presenceRef)
|
|
9822
|
+
return;
|
|
9823
|
+
channel.presenceRef = undefined;
|
|
9824
|
+
const state = this.presence.get(channel.topic);
|
|
9825
|
+
const current = state?.get(channel.presenceKey);
|
|
9826
|
+
const leaving = current?.metas.find((meta) => meta.phx_ref === presenceRef);
|
|
9827
|
+
if (!state || !current || !leaving)
|
|
9828
|
+
return;
|
|
9829
|
+
const remaining = current.metas.filter((meta) => meta.phx_ref !== presenceRef);
|
|
9830
|
+
if (remaining.length > 0) {
|
|
9831
|
+
state.set(channel.presenceKey, { metas: remaining });
|
|
9832
|
+
} else {
|
|
9815
9833
|
state.delete(channel.presenceKey);
|
|
9816
9834
|
if (state.size === 0)
|
|
9817
|
-
this.presence.delete(topic);
|
|
9818
|
-
this.broadcastToTopic(topic, {
|
|
9819
|
-
topic,
|
|
9820
|
-
event: "presence_diff",
|
|
9821
|
-
payload: { joins: {}, leaves: { [channel.presenceKey]: metas } },
|
|
9822
|
-
ref: null
|
|
9823
|
-
});
|
|
9835
|
+
this.presence.delete(channel.topic);
|
|
9824
9836
|
}
|
|
9837
|
+
this.broadcastToTopic(channel.topic, {
|
|
9838
|
+
topic: channel.topic,
|
|
9839
|
+
event: "presence_diff",
|
|
9840
|
+
payload: { joins: {}, leaves: { [channel.presenceKey]: { metas: [leaving] } } },
|
|
9841
|
+
ref: null
|
|
9842
|
+
});
|
|
9825
9843
|
}
|
|
9826
9844
|
scheduleExternalExpiry(conn, channel) {
|
|
9827
9845
|
if (channel.expiryTimer)
|
|
@@ -9901,23 +9919,30 @@ class RealtimeEngine {
|
|
|
9901
9919
|
return;
|
|
9902
9920
|
const event = String(msg.payload?.event ?? "").toLowerCase();
|
|
9903
9921
|
if (event === "track") {
|
|
9904
|
-
const
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
};
|
|
9922
|
+
const payload = { ...msg.payload?.payload ?? {} };
|
|
9923
|
+
delete payload.phx_ref;
|
|
9924
|
+
delete payload.phx_ref_prev;
|
|
9908
9925
|
let state = this.presence.get(msg.topic);
|
|
9909
9926
|
if (!state) {
|
|
9910
9927
|
state = new Map;
|
|
9911
9928
|
this.presence.set(msg.topic, state);
|
|
9912
9929
|
}
|
|
9913
|
-
const
|
|
9914
|
-
|
|
9930
|
+
const current = state.get(channel.presenceKey);
|
|
9931
|
+
const previous = current?.metas.find((meta) => meta.phx_ref === channel.presenceRef);
|
|
9932
|
+
const meta = {
|
|
9933
|
+
...payload,
|
|
9934
|
+
phx_ref: `F${this.phxRefCounter++}`,
|
|
9935
|
+
...previous ? { phx_ref_prev: previous.phx_ref } : {}
|
|
9936
|
+
};
|
|
9937
|
+
const others = current?.metas.filter((meta) => meta.phx_ref !== channel.presenceRef) ?? [];
|
|
9938
|
+
state.set(channel.presenceKey, { metas: [...others, meta] });
|
|
9939
|
+
channel.presenceRef = meta.phx_ref;
|
|
9915
9940
|
this.broadcastToTopic(msg.topic, {
|
|
9916
9941
|
topic: msg.topic,
|
|
9917
9942
|
event: "presence_diff",
|
|
9918
9943
|
payload: {
|
|
9919
9944
|
joins: { [channel.presenceKey]: { metas: [meta] } },
|
|
9920
|
-
leaves: previous ? { [channel.presenceKey]: previous } : {}
|
|
9945
|
+
leaves: previous ? { [channel.presenceKey]: { metas: [previous] } } : {}
|
|
9921
9946
|
},
|
|
9922
9947
|
ref: null
|
|
9923
9948
|
});
|
|
@@ -9926,19 +9951,7 @@ class RealtimeEngine {
|
|
|
9926
9951
|
return;
|
|
9927
9952
|
}
|
|
9928
9953
|
if (event === "untrack") {
|
|
9929
|
-
|
|
9930
|
-
const metas = state?.get(channel.presenceKey);
|
|
9931
|
-
if (state && metas) {
|
|
9932
|
-
state.delete(channel.presenceKey);
|
|
9933
|
-
if (state.size === 0)
|
|
9934
|
-
this.presence.delete(msg.topic);
|
|
9935
|
-
this.broadcastToTopic(msg.topic, {
|
|
9936
|
-
topic: msg.topic,
|
|
9937
|
-
event: "presence_diff",
|
|
9938
|
-
payload: { joins: {}, leaves: { [channel.presenceKey]: metas } },
|
|
9939
|
-
ref: null
|
|
9940
|
-
});
|
|
9941
|
-
}
|
|
9954
|
+
this.removePresence(channel);
|
|
9942
9955
|
if (msg.ref)
|
|
9943
9956
|
this.reply(conn, msg, "ok", {});
|
|
9944
9957
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/runtime/realtime/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAI3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,gFAAgF;AAChF,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAA;IACrC,wEAAwE;IACxE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5C;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/runtime/realtime/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAI3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,gFAAgF;AAChF,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAA;IACrC,wEAAwE;IACxE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5C;AAkED,uFAAuF;AACvF,qBAAa,cAAc;IAUvB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,SAAS,CAAC;IAClB,OAAO,CAAC,oBAAoB,CAAC;IAX/B,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,aAAa,CAAI;IACzB,0BAA0B;IAC1B,OAAO,CAAC,QAAQ,CAAgD;IAChE,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,eAAe,CAAiC;gBAG9C,EAAE,EAAE,QAAQ,EACZ,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,oBAAoB,CAAC,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,aAAA;IAG3E,oEAAoE;YACtD,gBAAgB;IAS9B;;;;;OAKG;YACW,gBAAgB;IA0C9B,6EAA6E;IAC7E,OAAO,CAAC,mBAAmB;IAc3B,iFAAiF;IAC3E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5B,sEAAsE;IAChE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B,qEAAqE;IACrE,OAAO,CAAC,MAAM,EAAE,kBAAkB,EAAE,IAAI,GAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG;QAChE,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,KAAK,IAAI,CAAA;QAC9C,OAAO,EAAE,MAAM,IAAI,CAAA;KACpB;IAcD,OAAO,CAAC,IAAI;IAYZ,OAAO,CAAC,KAAK;YAUC,aAAa;YA+Eb,UAAU;IA0GxB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,cAAc;IAuBtB,OAAO,CAAC,sBAAsB;IAY9B;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IA+BpB,OAAO,CAAC,eAAe;IA8BvB,OAAO,CAAC,cAAc;IA4CtB,OAAO,CAAC,gBAAgB;YAQV,WAAW;IAoDzB;;;;;;;OAOG;YACW,MAAM;IA6BpB,OAAO,CAAC,cAAc;CAUvB;AAkBD,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CA2BjF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supacloud/lite",
|
|
3
|
-
"version": "0.33.
|
|
3
|
+
"version": "0.33.2",
|
|
4
4
|
"description": "Bun-native, single-project Supabase-compatible backend powered by PGlite or native PostgreSQL",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"clean": "bun -e 'import { $ } from \"bun\"; await $`rm -rf dist`'",
|
|
40
40
|
"dev": "bun run src/cli.ts start",
|
|
41
41
|
"start": "bun run src/cli.ts start",
|
|
42
|
-
"test": "bun
|
|
42
|
+
"test": "bun run scripts/run-tests.ts",
|
|
43
43
|
"test:native": "SUPACLOUD_LITE_TEST_NATIVE=1 bun test test/native-engine.test.ts test/qauth-workflow-matrix.test.ts test/maker-checker-workflow.test.ts test/commands-artifacts.test.ts --timeout 180000",
|
|
44
44
|
"test:graphql": "SUPACLOUD_LITE_TEST_GRAPHQL=1 bun test test/graphql-native.test.ts --timeout 180000",
|
|
45
45
|
"benchmark": "bun run scripts/benchmark.ts",
|
|
@@ -59,31 +59,31 @@
|
|
|
59
59
|
"@electric-sql/pglite-pgmq": "0.0.8",
|
|
60
60
|
"@electric-sql/pglite-pgvector": "0.0.11",
|
|
61
61
|
"@electric-sql/pglite-postgis": "0.2.10",
|
|
62
|
-
"@supacloud/db": "0.20.
|
|
62
|
+
"@supacloud/db": "0.20.1",
|
|
63
63
|
"exact-mirror": "1.2.6",
|
|
64
64
|
"tar": "^7.5.22",
|
|
65
|
-
"typebox": "1.
|
|
65
|
+
"typebox": "1.4.2"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@supacloud/app": "0.
|
|
69
|
-
"@supacloud/contracts": "0.
|
|
70
|
-
"@supacloud/compiler": "0.
|
|
71
|
-
"@supacloud/elysia": "0.
|
|
72
|
-
"@supabase/supabase-js": "^2.
|
|
68
|
+
"@supacloud/app": "0.33.0",
|
|
69
|
+
"@supacloud/contracts": "0.15.1",
|
|
70
|
+
"@supacloud/compiler": "0.51.1",
|
|
71
|
+
"@supacloud/elysia": "0.36.1",
|
|
72
|
+
"@supabase/supabase-js": "^2.118.0",
|
|
73
73
|
"@types/bun": "^1.4.3",
|
|
74
74
|
"effect": "4.0.5",
|
|
75
|
-
"elysia": "2.0.0-
|
|
76
|
-
"jose": "^6.2.
|
|
75
|
+
"elysia": "2.0.0-rc.0",
|
|
76
|
+
"jose": "^6.2.13",
|
|
77
77
|
"typescript": "^7.0.2"
|
|
78
78
|
},
|
|
79
79
|
"overrides": {
|
|
80
|
-
"@supacloud/db": "0.20.
|
|
81
|
-
"@supacloud/app": "0.
|
|
82
|
-
"@supacloud/compiler": "0.
|
|
83
|
-
"@supacloud/elysia": "0.
|
|
84
|
-
"@supacloud/contracts": "0.
|
|
85
|
-
"@supacloud/commands": "0.11.
|
|
86
|
-
"@supacloud/delivery": "0.21.
|
|
80
|
+
"@supacloud/db": "0.20.1",
|
|
81
|
+
"@supacloud/app": "0.33.0",
|
|
82
|
+
"@supacloud/compiler": "0.51.1",
|
|
83
|
+
"@supacloud/elysia": "0.36.1",
|
|
84
|
+
"@supacloud/contracts": "0.15.1",
|
|
85
|
+
"@supacloud/commands": "0.11.1",
|
|
86
|
+
"@supacloud/delivery": "0.21.1",
|
|
87
87
|
"@graphql-tools/utils": "^12.0.4"
|
|
88
88
|
},
|
|
89
89
|
"engines": {
|