@rebasepro/client 0.0.1-canary.4d4fb3e → 0.0.1-canary.ca2cb6e
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/admin.d.ts +6 -6
- package/dist/auth.d.ts +67 -1
- package/dist/collection.d.ts +3 -3
- package/dist/cron.d.ts +25 -0
- package/dist/cron.test.d.ts +1 -0
- package/dist/index.d.ts +12 -7
- package/dist/index.es.js +523 -128
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +522 -129
- package/dist/index.umd.js.map +1 -1
- package/dist/query_builder.d.ts +3 -3
- package/dist/reviver.d.ts +1 -0
- package/dist/transport.d.ts +5 -5
- package/dist/websocket.d.ts +16 -10
- package/package.json +78 -74
- package/src/admin.ts +12 -12
- package/src/auth.ts +137 -25
- package/src/collection.ts +130 -79
- package/src/cron.test.ts +164 -0
- package/src/cron.ts +62 -0
- package/src/index.ts +39 -26
- package/src/query_builder.ts +7 -8
- package/src/reviver.ts +39 -0
- package/src/storage.ts +38 -38
- package/src/transport.ts +109 -23
- package/src/websocket.ts +104 -42
package/dist/index.es.js
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
import { Vector, GeoPoint, EntityRelation, EntityReference } from "@rebasepro/types";
|
|
2
|
+
import { toSnakeCase } from "@rebasepro/utils";
|
|
3
|
+
function rebaseReviver(_key, value) {
|
|
4
|
+
if (value && typeof value === "object" && "__type" in value) {
|
|
5
|
+
const record = value;
|
|
6
|
+
switch (record.__type) {
|
|
7
|
+
case "date":
|
|
8
|
+
case "Date": {
|
|
9
|
+
if (typeof record.value !== "string") {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
const date = new Date(record.value);
|
|
13
|
+
return isNaN(date.getTime()) ? null : date;
|
|
14
|
+
}
|
|
15
|
+
case "reference":
|
|
16
|
+
case "EntityReference":
|
|
17
|
+
return new EntityReference({
|
|
18
|
+
id: String(record.id),
|
|
19
|
+
path: record.path,
|
|
20
|
+
driver: record.driver,
|
|
21
|
+
databaseId: record.databaseId
|
|
22
|
+
});
|
|
23
|
+
case "relation":
|
|
24
|
+
case "EntityRelation":
|
|
25
|
+
return new EntityRelation(
|
|
26
|
+
record.id,
|
|
27
|
+
record.path,
|
|
28
|
+
record.data
|
|
29
|
+
);
|
|
30
|
+
case "GeoPoint":
|
|
31
|
+
return new GeoPoint(record.latitude, record.longitude);
|
|
32
|
+
case "Vector":
|
|
33
|
+
return new Vector(record.value);
|
|
34
|
+
default:
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
1
40
|
class RebaseApiError extends Error {
|
|
2
41
|
status;
|
|
3
42
|
code;
|
|
@@ -10,6 +49,30 @@ class RebaseApiError extends Error {
|
|
|
10
49
|
this.details = details;
|
|
11
50
|
}
|
|
12
51
|
}
|
|
52
|
+
const OP_MAP = {
|
|
53
|
+
"==": "eq",
|
|
54
|
+
"!=": "neq",
|
|
55
|
+
">": "gt",
|
|
56
|
+
">=": "gte",
|
|
57
|
+
"<": "lt",
|
|
58
|
+
"<=": "lte",
|
|
59
|
+
"not-in": "nin",
|
|
60
|
+
"array-contains": "cs",
|
|
61
|
+
"array-contains-any": "csa"
|
|
62
|
+
};
|
|
63
|
+
function normalizeWhereValue(value) {
|
|
64
|
+
if (value === null) return "eq.null";
|
|
65
|
+
if (typeof value === "boolean") return `eq.${value}`;
|
|
66
|
+
if (typeof value === "number") return String(value);
|
|
67
|
+
if (Array.isArray(value) && value.length === 2) {
|
|
68
|
+
const [rawOp, val] = value;
|
|
69
|
+
const op = OP_MAP[rawOp] ?? rawOp;
|
|
70
|
+
if (val === null) return `${op}.null`;
|
|
71
|
+
if (Array.isArray(val)) return `${op}.(${val.join(",")})`;
|
|
72
|
+
return `${op}.${val}`;
|
|
73
|
+
}
|
|
74
|
+
return String(value);
|
|
75
|
+
}
|
|
13
76
|
function buildQueryString(params) {
|
|
14
77
|
if (!params) return "";
|
|
15
78
|
const parts = [];
|
|
@@ -19,12 +82,16 @@ function buildQueryString(params) {
|
|
|
19
82
|
if (params.orderBy) {
|
|
20
83
|
parts.push(`orderBy=${encodeURIComponent(params.orderBy)}`);
|
|
21
84
|
}
|
|
85
|
+
if (params.searchString) {
|
|
86
|
+
parts.push(`searchString=${encodeURIComponent(params.searchString)}`);
|
|
87
|
+
}
|
|
22
88
|
if (params.include && params.include.length > 0) {
|
|
23
89
|
parts.push(`include=${encodeURIComponent(params.include.join(","))}`);
|
|
24
90
|
}
|
|
25
91
|
if (params.where) {
|
|
26
92
|
for (const [field, value] of Object.entries(params.where)) {
|
|
27
|
-
|
|
93
|
+
const normalized = normalizeWhereValue(value);
|
|
94
|
+
parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(normalized)}`);
|
|
28
95
|
}
|
|
29
96
|
}
|
|
30
97
|
return parts.length > 0 ? "?" + parts.join("&") : "";
|
|
@@ -43,7 +110,8 @@ function createTransport(config) {
|
|
|
43
110
|
};
|
|
44
111
|
}
|
|
45
112
|
async function request(path, init) {
|
|
46
|
-
const
|
|
113
|
+
const base = config.baseUrl ? config.baseUrl.replace(/\/$/, "") : "";
|
|
114
|
+
const url = base + apiPath + path;
|
|
47
115
|
let activeToken = token;
|
|
48
116
|
if (tokenGetter) {
|
|
49
117
|
try {
|
|
@@ -58,9 +126,19 @@ function createTransport(config) {
|
|
|
58
126
|
if (init?.body instanceof FormData) {
|
|
59
127
|
delete headers["Content-Type"];
|
|
60
128
|
}
|
|
61
|
-
const res = await fetchFn(url, {
|
|
129
|
+
const res = await fetchFn(url, {
|
|
130
|
+
...init,
|
|
131
|
+
headers
|
|
132
|
+
});
|
|
62
133
|
if (res.status === 204) return void 0;
|
|
63
|
-
const
|
|
134
|
+
const text = await res.text().catch(() => "");
|
|
135
|
+
let body = {};
|
|
136
|
+
if (text) {
|
|
137
|
+
try {
|
|
138
|
+
body = JSON.parse(text, rebaseReviver);
|
|
139
|
+
} catch (e) {
|
|
140
|
+
}
|
|
141
|
+
}
|
|
64
142
|
if (res.status === 401 && onUnauthorizedHandler) {
|
|
65
143
|
const retried = await onUnauthorizedHandler();
|
|
66
144
|
if (retried) {
|
|
@@ -75,13 +153,28 @@ function createTransport(config) {
|
|
|
75
153
|
}
|
|
76
154
|
}
|
|
77
155
|
const retryHeaders = getHeaders(retryToken, init);
|
|
78
|
-
const retryRes = await fetchFn(url, {
|
|
156
|
+
const retryRes = await fetchFn(url, {
|
|
157
|
+
...init,
|
|
158
|
+
headers: retryHeaders
|
|
159
|
+
});
|
|
79
160
|
if (retryRes.status === 204) return void 0;
|
|
80
|
-
const
|
|
161
|
+
const retryText = await retryRes.text().catch(() => "");
|
|
162
|
+
let retryBody = {};
|
|
163
|
+
if (retryText) {
|
|
164
|
+
try {
|
|
165
|
+
retryBody = JSON.parse(retryText, rebaseReviver);
|
|
166
|
+
} catch (e) {
|
|
167
|
+
}
|
|
168
|
+
}
|
|
81
169
|
if (!retryRes.ok) {
|
|
170
|
+
let fallbackMessage = retryRes.statusText;
|
|
171
|
+
if (retryRes.status === 404 && !fallbackMessage) {
|
|
172
|
+
const method = init?.method || "GET";
|
|
173
|
+
fallbackMessage = `Endpoint not found (${method} ${path}). This usually means the collection is not registered on the backend, or the frontend API URL configuration (e.g. VITE_API_URL) is missing or pointing to the wrong host.`;
|
|
174
|
+
}
|
|
82
175
|
throw new RebaseApiError(
|
|
83
176
|
retryRes.status,
|
|
84
|
-
retryBody?.error?.message || retryBody?.message || retryRes.
|
|
177
|
+
retryBody?.error?.message || retryBody?.message || fallbackMessage || `Request failed with status ${retryRes.status}`,
|
|
85
178
|
retryBody?.error?.code || retryBody?.code,
|
|
86
179
|
retryBody?.error?.details || retryBody?.details
|
|
87
180
|
);
|
|
@@ -90,9 +183,14 @@ function createTransport(config) {
|
|
|
90
183
|
}
|
|
91
184
|
}
|
|
92
185
|
if (!res.ok) {
|
|
186
|
+
let fallbackMessage = res.statusText;
|
|
187
|
+
if (res.status === 404 && !fallbackMessage) {
|
|
188
|
+
const method = init?.method || "GET";
|
|
189
|
+
fallbackMessage = `Endpoint not found (${method} ${path}). This usually means the collection is not registered on the backend, or the frontend API URL configuration (e.g. VITE_API_URL) is missing or pointing to the wrong host.`;
|
|
190
|
+
}
|
|
93
191
|
throw new RebaseApiError(
|
|
94
192
|
res.status,
|
|
95
|
-
body?.error?.message || body?.message || res.
|
|
193
|
+
body?.error?.message || body?.message || fallbackMessage || `Request failed with status ${res.status}`,
|
|
96
194
|
body?.error?.code || body?.code,
|
|
97
195
|
body?.error?.details || body?.details
|
|
98
196
|
);
|
|
@@ -111,7 +209,7 @@ function createTransport(config) {
|
|
|
111
209
|
onUnauthorizedHandler = handler;
|
|
112
210
|
},
|
|
113
211
|
get baseUrl() {
|
|
114
|
-
return config.baseUrl.replace(/\/$/, "");
|
|
212
|
+
return config.baseUrl ? config.baseUrl.replace(/\/$/, "") : "";
|
|
115
213
|
},
|
|
116
214
|
get apiPath() {
|
|
117
215
|
return apiPath;
|
|
@@ -248,16 +346,26 @@ function createAuth(transport, options) {
|
|
|
248
346
|
const res = await fetchFn(authUrl("/login"), {
|
|
249
347
|
method: "POST",
|
|
250
348
|
headers: { "Content-Type": "application/json" },
|
|
251
|
-
body: JSON.stringify({
|
|
349
|
+
body: JSON.stringify({
|
|
350
|
+
email,
|
|
351
|
+
password
|
|
352
|
+
})
|
|
252
353
|
});
|
|
253
354
|
const body = await res.json().catch(() => ({}));
|
|
254
355
|
if (!res.ok) throwApiError(res.status, body, res.statusText);
|
|
255
356
|
const session = handleAuthResponse(body, "SIGNED_IN");
|
|
256
|
-
return {
|
|
357
|
+
return {
|
|
358
|
+
user: session.user,
|
|
359
|
+
accessToken: session.accessToken,
|
|
360
|
+
refreshToken: session.refreshToken
|
|
361
|
+
};
|
|
257
362
|
}
|
|
258
363
|
async function signUp(email, password, displayName) {
|
|
259
364
|
const fetchFn = getFetch();
|
|
260
|
-
const payload = {
|
|
365
|
+
const payload = {
|
|
366
|
+
email,
|
|
367
|
+
password
|
|
368
|
+
};
|
|
261
369
|
if (displayName !== void 0) payload.displayName = displayName;
|
|
262
370
|
const res = await fetchFn(authUrl("/register"), {
|
|
263
371
|
method: "POST",
|
|
@@ -267,7 +375,11 @@ function createAuth(transport, options) {
|
|
|
267
375
|
const body = await res.json().catch(() => ({}));
|
|
268
376
|
if (!res.ok) throwApiError(res.status, body, res.statusText);
|
|
269
377
|
const session = handleAuthResponse(body, "SIGNED_IN");
|
|
270
|
-
return {
|
|
378
|
+
return {
|
|
379
|
+
user: session.user,
|
|
380
|
+
accessToken: session.accessToken,
|
|
381
|
+
refreshToken: session.refreshToken
|
|
382
|
+
};
|
|
271
383
|
}
|
|
272
384
|
async function signInWithGoogle(idToken) {
|
|
273
385
|
const fetchFn = getFetch();
|
|
@@ -279,7 +391,108 @@ function createAuth(transport, options) {
|
|
|
279
391
|
const body = await res.json().catch(() => ({}));
|
|
280
392
|
if (!res.ok) throwApiError(res.status, body, res.statusText);
|
|
281
393
|
const session = handleAuthResponse(body, "SIGNED_IN");
|
|
282
|
-
return {
|
|
394
|
+
return {
|
|
395
|
+
user: session.user,
|
|
396
|
+
accessToken: session.accessToken,
|
|
397
|
+
refreshToken: session.refreshToken
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
async function signInWithLinkedin(code, redirectUri) {
|
|
401
|
+
const fetchFn = getFetch();
|
|
402
|
+
const res = await fetchFn(authUrl("/linkedin"), {
|
|
403
|
+
method: "POST",
|
|
404
|
+
headers: { "Content-Type": "application/json" },
|
|
405
|
+
body: JSON.stringify({
|
|
406
|
+
code,
|
|
407
|
+
redirectUri
|
|
408
|
+
})
|
|
409
|
+
});
|
|
410
|
+
const body = await res.json().catch(() => ({}));
|
|
411
|
+
if (!res.ok) throwApiError(res.status, body, res.statusText);
|
|
412
|
+
const session = handleAuthResponse(body, "SIGNED_IN");
|
|
413
|
+
return {
|
|
414
|
+
user: session.user,
|
|
415
|
+
accessToken: session.accessToken,
|
|
416
|
+
refreshToken: session.refreshToken
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
async function signInWithOAuth(providerId, payload) {
|
|
420
|
+
const fetchFn = getFetch();
|
|
421
|
+
const res = await fetchFn(authUrl(`/${providerId}`), {
|
|
422
|
+
method: "POST",
|
|
423
|
+
headers: { "Content-Type": "application/json" },
|
|
424
|
+
body: JSON.stringify(payload)
|
|
425
|
+
});
|
|
426
|
+
const body = await res.json().catch(() => ({}));
|
|
427
|
+
if (!res.ok) throwApiError(res.status, body, res.statusText);
|
|
428
|
+
const session = handleAuthResponse(body, "SIGNED_IN");
|
|
429
|
+
return {
|
|
430
|
+
user: session.user,
|
|
431
|
+
accessToken: session.accessToken,
|
|
432
|
+
refreshToken: session.refreshToken
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
async function signInWithGitHub(code, redirectUri) {
|
|
436
|
+
return signInWithOAuth("github", {
|
|
437
|
+
code,
|
|
438
|
+
redirectUri
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
async function signInWithMicrosoft(code, redirectUri) {
|
|
442
|
+
return signInWithOAuth("microsoft", {
|
|
443
|
+
code,
|
|
444
|
+
redirectUri
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
async function signInWithApple(code, redirectUri, user) {
|
|
448
|
+
return signInWithOAuth("apple", {
|
|
449
|
+
code,
|
|
450
|
+
redirectUri,
|
|
451
|
+
user
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
async function signInWithFacebook(code, redirectUri) {
|
|
455
|
+
return signInWithOAuth("facebook", {
|
|
456
|
+
code,
|
|
457
|
+
redirectUri
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
async function signInWithTwitter(code, redirectUri, codeVerifier) {
|
|
461
|
+
return signInWithOAuth("twitter", {
|
|
462
|
+
code,
|
|
463
|
+
redirectUri,
|
|
464
|
+
codeVerifier
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
async function signInWithDiscord(code, redirectUri) {
|
|
468
|
+
return signInWithOAuth("discord", {
|
|
469
|
+
code,
|
|
470
|
+
redirectUri
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
async function signInWithGitLab(code, redirectUri) {
|
|
474
|
+
return signInWithOAuth("gitlab", {
|
|
475
|
+
code,
|
|
476
|
+
redirectUri
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
async function signInWithBitbucket(code, redirectUri) {
|
|
480
|
+
return signInWithOAuth("bitbucket", {
|
|
481
|
+
code,
|
|
482
|
+
redirectUri
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
async function signInWithSlack(code, redirectUri) {
|
|
486
|
+
return signInWithOAuth("slack", {
|
|
487
|
+
code,
|
|
488
|
+
redirectUri
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
async function signInWithSpotify(code, redirectUri) {
|
|
492
|
+
return signInWithOAuth("spotify", {
|
|
493
|
+
code,
|
|
494
|
+
redirectUri
|
|
495
|
+
});
|
|
283
496
|
}
|
|
284
497
|
async function signOut() {
|
|
285
498
|
const fetchFn = getFetch();
|
|
@@ -337,7 +550,10 @@ function createAuth(transport, options) {
|
|
|
337
550
|
body: JSON.stringify(updates)
|
|
338
551
|
});
|
|
339
552
|
if (currentSession) {
|
|
340
|
-
currentSession = {
|
|
553
|
+
currentSession = {
|
|
554
|
+
...currentSession,
|
|
555
|
+
user: data.user
|
|
556
|
+
};
|
|
341
557
|
saveSession(currentSession);
|
|
342
558
|
emit("USER_UPDATED", currentSession);
|
|
343
559
|
}
|
|
@@ -359,7 +575,10 @@ function createAuth(transport, options) {
|
|
|
359
575
|
const res = await fetchFn(authUrl("/reset-password"), {
|
|
360
576
|
method: "POST",
|
|
361
577
|
headers: { "Content-Type": "application/json" },
|
|
362
|
-
body: JSON.stringify({
|
|
578
|
+
body: JSON.stringify({
|
|
579
|
+
token,
|
|
580
|
+
password
|
|
581
|
+
})
|
|
363
582
|
});
|
|
364
583
|
const body = await res.json().catch(() => ({}));
|
|
365
584
|
if (!res.ok) throwApiError(res.status, body, res.statusText);
|
|
@@ -368,7 +587,10 @@ function createAuth(transport, options) {
|
|
|
368
587
|
async function changePassword(oldPassword, newPassword) {
|
|
369
588
|
return transport.request(authPath + "/change-password", {
|
|
370
589
|
method: "POST",
|
|
371
|
-
body: JSON.stringify({
|
|
590
|
+
body: JSON.stringify({
|
|
591
|
+
oldPassword,
|
|
592
|
+
newPassword
|
|
593
|
+
})
|
|
372
594
|
});
|
|
373
595
|
}
|
|
374
596
|
async function sendVerificationEmail() {
|
|
@@ -447,6 +669,18 @@ function createAuth(transport, options) {
|
|
|
447
669
|
signInWithEmail,
|
|
448
670
|
signUp,
|
|
449
671
|
signInWithGoogle,
|
|
672
|
+
signInWithLinkedin,
|
|
673
|
+
signInWithOAuth,
|
|
674
|
+
signInWithGitHub,
|
|
675
|
+
signInWithMicrosoft,
|
|
676
|
+
signInWithApple,
|
|
677
|
+
signInWithFacebook,
|
|
678
|
+
signInWithTwitter,
|
|
679
|
+
signInWithDiscord,
|
|
680
|
+
signInWithGitLab,
|
|
681
|
+
signInWithBitbucket,
|
|
682
|
+
signInWithSlack,
|
|
683
|
+
signInWithSpotify,
|
|
450
684
|
signOut,
|
|
451
685
|
refreshSession,
|
|
452
686
|
getUser,
|
|
@@ -546,6 +780,49 @@ function createAdmin(transport, options) {
|
|
|
546
780
|
bootstrap
|
|
547
781
|
};
|
|
548
782
|
}
|
|
783
|
+
function createCron(transport, options) {
|
|
784
|
+
const cronPath = options?.cronPath || "/cron";
|
|
785
|
+
async function listJobs() {
|
|
786
|
+
return transport.request(cronPath, { method: "GET" });
|
|
787
|
+
}
|
|
788
|
+
async function getJob(jobId) {
|
|
789
|
+
return transport.request(
|
|
790
|
+
cronPath + "/" + encodeURIComponent(jobId),
|
|
791
|
+
{ method: "GET" }
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
async function triggerJob(jobId) {
|
|
795
|
+
return transport.request(
|
|
796
|
+
cronPath + "/" + encodeURIComponent(jobId) + "/trigger",
|
|
797
|
+
{ method: "POST" }
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
async function getJobLogs(jobId, options2) {
|
|
801
|
+
const params = new URLSearchParams();
|
|
802
|
+
if (options2?.limit !== void 0) params.set("limit", String(options2.limit));
|
|
803
|
+
const qs = params.toString();
|
|
804
|
+
return transport.request(
|
|
805
|
+
cronPath + "/" + encodeURIComponent(jobId) + "/logs" + (qs ? "?" + qs : ""),
|
|
806
|
+
{ method: "GET" }
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
async function toggleJob(jobId, enabled) {
|
|
810
|
+
return transport.request(
|
|
811
|
+
cronPath + "/" + encodeURIComponent(jobId),
|
|
812
|
+
{
|
|
813
|
+
method: "PUT",
|
|
814
|
+
body: JSON.stringify({ enabled })
|
|
815
|
+
}
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
return {
|
|
819
|
+
listJobs,
|
|
820
|
+
getJob,
|
|
821
|
+
triggerJob,
|
|
822
|
+
getJobLogs,
|
|
823
|
+
toggleJob
|
|
824
|
+
};
|
|
825
|
+
}
|
|
549
826
|
function mapOperator(op) {
|
|
550
827
|
switch (op) {
|
|
551
828
|
case "==":
|
|
@@ -577,7 +854,7 @@ class QueryBuilder {
|
|
|
577
854
|
params = { where: {} };
|
|
578
855
|
/**
|
|
579
856
|
* Add a filter condition to your query.
|
|
580
|
-
* @example
|
|
857
|
+
* @example
|
|
581
858
|
* client.collection('users').where('age', '>=', 18).find()
|
|
582
859
|
*/
|
|
583
860
|
where(column, operator, value) {
|
|
@@ -596,7 +873,7 @@ class QueryBuilder {
|
|
|
596
873
|
}
|
|
597
874
|
/**
|
|
598
875
|
* Order the results by a specific column.
|
|
599
|
-
* @example
|
|
876
|
+
* @example
|
|
600
877
|
* client.collection('users').orderBy('createdAt', 'desc').find()
|
|
601
878
|
*/
|
|
602
879
|
orderBy(column, ascending = "asc") {
|
|
@@ -659,7 +936,46 @@ class QueryBuilder {
|
|
|
659
936
|
function parseWhereFilter(where) {
|
|
660
937
|
if (!where) return void 0;
|
|
661
938
|
const filters = {};
|
|
662
|
-
for (const [key,
|
|
939
|
+
for (const [key, rawValue] of Object.entries(where)) {
|
|
940
|
+
if (rawValue === null) {
|
|
941
|
+
filters[key] = ["==", null];
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
944
|
+
if (typeof rawValue === "boolean") {
|
|
945
|
+
filters[key] = ["==", rawValue];
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
if (typeof rawValue === "number") {
|
|
949
|
+
filters[key] = ["==", rawValue];
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
if (Array.isArray(rawValue) && rawValue.length === 2) {
|
|
953
|
+
const [rawOp, val] = rawValue;
|
|
954
|
+
const OP_TO_FILTER = {
|
|
955
|
+
"eq": "==",
|
|
956
|
+
"neq": "!=",
|
|
957
|
+
"gt": ">",
|
|
958
|
+
"gte": ">=",
|
|
959
|
+
"lt": "<",
|
|
960
|
+
"lte": "<=",
|
|
961
|
+
"==": "==",
|
|
962
|
+
"!=": "!=",
|
|
963
|
+
">": ">",
|
|
964
|
+
">=": ">=",
|
|
965
|
+
"<": "<",
|
|
966
|
+
"<=": "<=",
|
|
967
|
+
"in": "in",
|
|
968
|
+
"nin": "not-in",
|
|
969
|
+
"not-in": "not-in",
|
|
970
|
+
"cs": "array-contains",
|
|
971
|
+
"csa": "array-contains-any",
|
|
972
|
+
"array-contains": "array-contains",
|
|
973
|
+
"array-contains-any": "array-contains-any"
|
|
974
|
+
};
|
|
975
|
+
filters[key] = [OP_TO_FILTER[rawOp] ?? "==", val];
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
const value = String(rawValue);
|
|
663
979
|
const dotIndex = value.indexOf(".");
|
|
664
980
|
if (dotIndex > 0) {
|
|
665
981
|
const opStr = value.substring(0, dotIndex);
|
|
@@ -707,7 +1023,7 @@ function parseWhereFilter(where) {
|
|
|
707
1023
|
if (val === "true") val = true;
|
|
708
1024
|
else if (val === "false") val = false;
|
|
709
1025
|
else if (val === "null") val = null;
|
|
710
|
-
else if (typeof val === "string" && /^[0-9]+(\.[0-9]+)?$/.test(val)) val = Number(val);
|
|
1026
|
+
else if (typeof val === "string" && /^[0-9]+(\.[0-9]+)?$/.test(val) && key !== "id" && !key.endsWith("_id")) val = Number(val);
|
|
711
1027
|
filters[key] = [op, val];
|
|
712
1028
|
} else {
|
|
713
1029
|
filters[key] = ["==", value];
|
|
@@ -724,7 +1040,7 @@ function rowToEntity(row, slug) {
|
|
|
724
1040
|
}
|
|
725
1041
|
function createCollectionClient(transport, slug, ws) {
|
|
726
1042
|
const basePath = `/data/${slug}`;
|
|
727
|
-
|
|
1043
|
+
const client = {
|
|
728
1044
|
async find(params) {
|
|
729
1045
|
const qs = buildQueryString(params);
|
|
730
1046
|
const raw = await transport.request(basePath + qs, { method: "GET" });
|
|
@@ -761,74 +1077,84 @@ function createCollectionClient(transport, slug, ws) {
|
|
|
761
1077
|
method: "DELETE"
|
|
762
1078
|
});
|
|
763
1079
|
},
|
|
764
|
-
...ws && {
|
|
765
|
-
listen(params, onUpdate, onError) {
|
|
766
|
-
return ws.listenCollection(
|
|
767
|
-
{
|
|
768
|
-
path: slug,
|
|
769
|
-
filter: parseWhereFilter(params?.where),
|
|
770
|
-
limit: params?.limit,
|
|
771
|
-
startAfter: params?.offset ? String(params.offset) : void 0,
|
|
772
|
-
orderBy: params?.orderBy?.split(":")[0],
|
|
773
|
-
order: params?.orderBy?.split(":")[1],
|
|
774
|
-
searchString: params?.searchString
|
|
775
|
-
},
|
|
776
|
-
(entities) => {
|
|
777
|
-
const requestedLimit = params?.limit || 20;
|
|
778
|
-
onUpdate({
|
|
779
|
-
data: entities,
|
|
780
|
-
meta: {
|
|
781
|
-
total: entities.length,
|
|
782
|
-
limit: requestedLimit,
|
|
783
|
-
offset: params?.offset || 0,
|
|
784
|
-
hasMore: entities.length >= requestedLimit
|
|
785
|
-
}
|
|
786
|
-
});
|
|
787
|
-
},
|
|
788
|
-
onError
|
|
789
|
-
);
|
|
790
|
-
},
|
|
791
|
-
listenById(id, onUpdate, onError) {
|
|
792
|
-
return ws.listenEntity(
|
|
793
|
-
{ path: slug, entityId: String(id) },
|
|
794
|
-
(entity) => {
|
|
795
|
-
if (entity) {
|
|
796
|
-
onUpdate(entity);
|
|
797
|
-
} else {
|
|
798
|
-
onUpdate(void 0);
|
|
799
|
-
}
|
|
800
|
-
},
|
|
801
|
-
onError
|
|
802
|
-
);
|
|
803
|
-
}
|
|
804
|
-
},
|
|
805
1080
|
// Fluent builder instantiation
|
|
806
1081
|
where(column, operator, value) {
|
|
807
|
-
return new QueryBuilder(
|
|
1082
|
+
return new QueryBuilder(client).where(column, operator, value);
|
|
808
1083
|
},
|
|
809
1084
|
orderBy(column, ascending) {
|
|
810
|
-
return new QueryBuilder(
|
|
1085
|
+
return new QueryBuilder(client).orderBy(column, ascending);
|
|
811
1086
|
},
|
|
812
1087
|
limit(count) {
|
|
813
|
-
return new QueryBuilder(
|
|
1088
|
+
return new QueryBuilder(client).limit(count);
|
|
814
1089
|
},
|
|
815
1090
|
offset(count) {
|
|
816
|
-
return new QueryBuilder(
|
|
1091
|
+
return new QueryBuilder(client).offset(count);
|
|
817
1092
|
},
|
|
818
1093
|
search(searchString) {
|
|
819
|
-
return new QueryBuilder(
|
|
1094
|
+
return new QueryBuilder(client).search(searchString);
|
|
820
1095
|
},
|
|
821
1096
|
include(...relations) {
|
|
822
|
-
return new QueryBuilder(
|
|
1097
|
+
return new QueryBuilder(client).include(...relations);
|
|
823
1098
|
}
|
|
824
1099
|
};
|
|
1100
|
+
if (ws) {
|
|
1101
|
+
client.listen = (params, onUpdate, onError) => {
|
|
1102
|
+
return ws.listenCollection(
|
|
1103
|
+
{
|
|
1104
|
+
path: slug,
|
|
1105
|
+
filter: parseWhereFilter(params?.where),
|
|
1106
|
+
limit: params?.limit,
|
|
1107
|
+
startAfter: params?.offset ? String(params.offset) : void 0,
|
|
1108
|
+
orderBy: params?.orderBy?.split(":")[0],
|
|
1109
|
+
order: params?.orderBy?.split(":")[1],
|
|
1110
|
+
searchString: params?.searchString
|
|
1111
|
+
},
|
|
1112
|
+
(entities) => {
|
|
1113
|
+
const requestedLimit = params?.limit || 20;
|
|
1114
|
+
onUpdate({
|
|
1115
|
+
data: entities,
|
|
1116
|
+
meta: {
|
|
1117
|
+
total: entities.length,
|
|
1118
|
+
limit: requestedLimit,
|
|
1119
|
+
offset: params?.offset || 0,
|
|
1120
|
+
hasMore: entities.length >= requestedLimit
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
},
|
|
1124
|
+
onError
|
|
1125
|
+
);
|
|
1126
|
+
};
|
|
1127
|
+
client.listenById = (id, onUpdate, onError) => {
|
|
1128
|
+
return ws.listenEntity(
|
|
1129
|
+
{
|
|
1130
|
+
path: slug,
|
|
1131
|
+
entityId: String(id)
|
|
1132
|
+
},
|
|
1133
|
+
(entity) => {
|
|
1134
|
+
if (entity) {
|
|
1135
|
+
onUpdate(entity);
|
|
1136
|
+
} else {
|
|
1137
|
+
onUpdate(void 0);
|
|
1138
|
+
}
|
|
1139
|
+
},
|
|
1140
|
+
onError
|
|
1141
|
+
);
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
return client;
|
|
1145
|
+
}
|
|
1146
|
+
function rehydrateEntity(entity) {
|
|
1147
|
+
return entity;
|
|
825
1148
|
}
|
|
826
1149
|
function extractMessageError(message) {
|
|
827
1150
|
const payload = message.payload;
|
|
828
1151
|
const errPayload = payload?.error;
|
|
829
1152
|
const errorMessage = typeof errPayload === "object" ? errPayload.message : payload?.message || (typeof errPayload === "string" ? errPayload : void 0) || message.error || "Unknown error";
|
|
830
1153
|
const errorCode = typeof errPayload === "object" ? errPayload.code : payload?.code;
|
|
831
|
-
return {
|
|
1154
|
+
return {
|
|
1155
|
+
errorMessage,
|
|
1156
|
+
errorCode
|
|
1157
|
+
};
|
|
832
1158
|
}
|
|
833
1159
|
class ApiError extends Error {
|
|
834
1160
|
code;
|
|
@@ -869,6 +1195,7 @@ class RebaseWebSocketClient {
|
|
|
869
1195
|
maxReconnectAttempts = 5;
|
|
870
1196
|
isConnected = false;
|
|
871
1197
|
messageQueue = [];
|
|
1198
|
+
reconnectTimeout = null;
|
|
872
1199
|
isAuthenticated = false;
|
|
873
1200
|
authPromise = null;
|
|
874
1201
|
WebSocketConstructor;
|
|
@@ -924,18 +1251,29 @@ class RebaseWebSocketClient {
|
|
|
924
1251
|
if (this.isConnected && !this.isAuthenticated && !this.authPromise) {
|
|
925
1252
|
console.log("WebSocket auto-authenticating after token getter set");
|
|
926
1253
|
this.getAuthToken().then((token) => {
|
|
1254
|
+
if (!this.ws) return;
|
|
927
1255
|
if (token) {
|
|
928
|
-
this.authenticate(token).catch((e) =>
|
|
1256
|
+
this.authenticate(token).catch((e) => {
|
|
1257
|
+
if (this.ws) console.warn("WebSocket auto-auth failed:", e);
|
|
1258
|
+
});
|
|
929
1259
|
}
|
|
930
1260
|
}).catch((e) => {
|
|
931
|
-
console.warn("WebSocket auto-auth failed:", e);
|
|
1261
|
+
if (this.ws) console.warn("WebSocket auto-auth failed:", e);
|
|
932
1262
|
});
|
|
933
1263
|
}
|
|
934
1264
|
}
|
|
935
1265
|
disconnect() {
|
|
936
1266
|
this.isAuthenticated = false;
|
|
937
1267
|
this.authPromise = null;
|
|
1268
|
+
if (this.reconnectTimeout) {
|
|
1269
|
+
clearTimeout(this.reconnectTimeout);
|
|
1270
|
+
this.reconnectTimeout = null;
|
|
1271
|
+
}
|
|
938
1272
|
if (this.ws) {
|
|
1273
|
+
this.ws.onclose = null;
|
|
1274
|
+
this.ws.onerror = null;
|
|
1275
|
+
this.ws.onopen = null;
|
|
1276
|
+
this.ws.onmessage = null;
|
|
939
1277
|
this.ws.close();
|
|
940
1278
|
this.ws = null;
|
|
941
1279
|
}
|
|
@@ -970,7 +1308,7 @@ class RebaseWebSocketClient {
|
|
|
970
1308
|
};
|
|
971
1309
|
this.ws.onmessage = (event) => {
|
|
972
1310
|
try {
|
|
973
|
-
const message = JSON.parse(event.data);
|
|
1311
|
+
const message = JSON.parse(event.data, rebaseReviver);
|
|
974
1312
|
this.handleWebSocketMessage(message);
|
|
975
1313
|
} catch (error) {
|
|
976
1314
|
console.error("Error parsing WebSocket message:", error);
|
|
@@ -1020,7 +1358,11 @@ class RebaseWebSocketClient {
|
|
|
1020
1358
|
this.reconnectAttempts++;
|
|
1021
1359
|
const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts), 3e4);
|
|
1022
1360
|
console.log(`Attempting to reconnect in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
|
1023
|
-
|
|
1361
|
+
if (this.reconnectTimeout) {
|
|
1362
|
+
clearTimeout(this.reconnectTimeout);
|
|
1363
|
+
}
|
|
1364
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
1365
|
+
this.reconnectTimeout = null;
|
|
1024
1366
|
this.initWebSocket();
|
|
1025
1367
|
}, delay);
|
|
1026
1368
|
}
|
|
@@ -1049,7 +1391,7 @@ class RebaseWebSocketClient {
|
|
|
1049
1391
|
if (subscriptionKey) {
|
|
1050
1392
|
const collectionSub = this.collectionSubscriptions.get(subscriptionKey);
|
|
1051
1393
|
if (collectionSub) {
|
|
1052
|
-
const incomingEntities = message.entities || [];
|
|
1394
|
+
const incomingEntities = (message.entities || []).map((e) => rehydrateEntity(e));
|
|
1053
1395
|
const entities = this.mergeEntities(collectionSub.latestData, incomingEntities);
|
|
1054
1396
|
collectionSub.latestData = entities;
|
|
1055
1397
|
collectionSub.lastUpdated = Date.now();
|
|
@@ -1073,7 +1415,7 @@ class RebaseWebSocketClient {
|
|
|
1073
1415
|
if (subscriptionKey) {
|
|
1074
1416
|
const collectionSub = this.collectionSubscriptions.get(subscriptionKey);
|
|
1075
1417
|
if (collectionSub && collectionSub.isInitialDataReceived && collectionSub.latestData) {
|
|
1076
|
-
const patchEntity = message.entity;
|
|
1418
|
+
const patchEntity = message.entity ? rehydrateEntity(message.entity) : message.entity;
|
|
1077
1419
|
const patchEntityId = message.entityId;
|
|
1078
1420
|
let updated;
|
|
1079
1421
|
if (patchEntity === null || patchEntity === void 0) {
|
|
@@ -1108,7 +1450,7 @@ class RebaseWebSocketClient {
|
|
|
1108
1450
|
if (subscriptionKey) {
|
|
1109
1451
|
const entitySub = this.entitySubscriptions.get(subscriptionKey);
|
|
1110
1452
|
if (entitySub) {
|
|
1111
|
-
const entity = message.entity
|
|
1453
|
+
const entity = message.entity ? rehydrateEntity(message.entity) : null;
|
|
1112
1454
|
entitySub.latestData = entity;
|
|
1113
1455
|
entitySub.lastUpdated = Date.now();
|
|
1114
1456
|
entitySub.isInitialDataReceived = true;
|
|
@@ -1276,21 +1618,21 @@ class RebaseWebSocketClient {
|
|
|
1276
1618
|
type: "FETCH_COLLECTION",
|
|
1277
1619
|
payload: props
|
|
1278
1620
|
});
|
|
1279
|
-
return response.entities || [];
|
|
1621
|
+
return (response.entities || []).map((e) => rehydrateEntity(e));
|
|
1280
1622
|
}
|
|
1281
1623
|
async fetchEntity(props) {
|
|
1282
1624
|
const response = await this.sendMessage({
|
|
1283
1625
|
type: "FETCH_ENTITY",
|
|
1284
1626
|
payload: props
|
|
1285
1627
|
});
|
|
1286
|
-
return response.entity;
|
|
1628
|
+
return response.entity ? rehydrateEntity(response.entity) : void 0;
|
|
1287
1629
|
}
|
|
1288
1630
|
async saveEntity(props) {
|
|
1289
1631
|
const response = await this.sendMessage({
|
|
1290
1632
|
type: "SAVE_ENTITY",
|
|
1291
1633
|
payload: props
|
|
1292
1634
|
});
|
|
1293
|
-
return response.entity;
|
|
1635
|
+
return rehydrateEntity(response.entity);
|
|
1294
1636
|
}
|
|
1295
1637
|
async deleteEntity(props) {
|
|
1296
1638
|
await this.sendMessage({
|
|
@@ -1301,7 +1643,10 @@ class RebaseWebSocketClient {
|
|
|
1301
1643
|
async executeSql(sql, options) {
|
|
1302
1644
|
const response = await this.sendMessage({
|
|
1303
1645
|
type: "EXECUTE_SQL",
|
|
1304
|
-
payload: {
|
|
1646
|
+
payload: {
|
|
1647
|
+
sql,
|
|
1648
|
+
options
|
|
1649
|
+
}
|
|
1305
1650
|
});
|
|
1306
1651
|
return response.result || [];
|
|
1307
1652
|
}
|
|
@@ -1356,7 +1701,35 @@ class RebaseWebSocketClient {
|
|
|
1356
1701
|
type: "FETCH_TABLE_METADATA",
|
|
1357
1702
|
payload: { tableName }
|
|
1358
1703
|
});
|
|
1359
|
-
return response.metadata || {
|
|
1704
|
+
return response.metadata || {
|
|
1705
|
+
columns: [],
|
|
1706
|
+
foreignKeys: [],
|
|
1707
|
+
junctions: [],
|
|
1708
|
+
policies: []
|
|
1709
|
+
};
|
|
1710
|
+
}
|
|
1711
|
+
async createBranch(name, options) {
|
|
1712
|
+
const response = await this.sendMessage({
|
|
1713
|
+
type: "CREATE_BRANCH",
|
|
1714
|
+
payload: {
|
|
1715
|
+
name,
|
|
1716
|
+
options
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
return response.branch;
|
|
1720
|
+
}
|
|
1721
|
+
async deleteBranch(name) {
|
|
1722
|
+
await this.sendMessage({
|
|
1723
|
+
type: "DELETE_BRANCH",
|
|
1724
|
+
payload: { name }
|
|
1725
|
+
});
|
|
1726
|
+
}
|
|
1727
|
+
async listBranches() {
|
|
1728
|
+
const response = await this.sendMessage({
|
|
1729
|
+
type: "LIST_BRANCHES",
|
|
1730
|
+
payload: {}
|
|
1731
|
+
});
|
|
1732
|
+
return response.branches || [];
|
|
1360
1733
|
}
|
|
1361
1734
|
/**
|
|
1362
1735
|
* Recursively compare two values for structural equality.
|
|
@@ -1442,7 +1815,10 @@ class RebaseWebSocketClient {
|
|
|
1442
1815
|
const allKeys = /* @__PURE__ */ new Set([...Object.keys(normCached), ...Object.keys(normIncoming)]);
|
|
1443
1816
|
for (const key of allKeys) {
|
|
1444
1817
|
if (!this.deepEqual(normCached[key], normIncoming[key])) {
|
|
1445
|
-
mismatches[key] = {
|
|
1818
|
+
mismatches[key] = {
|
|
1819
|
+
cached: normCached[key],
|
|
1820
|
+
incoming: normIncoming[key]
|
|
1821
|
+
};
|
|
1446
1822
|
}
|
|
1447
1823
|
}
|
|
1448
1824
|
console.log(`[RebaseWS] Row ${incomingEntity.id} refetch mismatch:
|
|
@@ -1459,7 +1835,10 @@ class RebaseWebSocketClient {
|
|
|
1459
1835
|
const existingSubscription = this.collectionSubscriptions.get(subscriptionKey);
|
|
1460
1836
|
if (existingSubscription) {
|
|
1461
1837
|
const callbackMap2 = existingSubscription.callbacks;
|
|
1462
|
-
callbackMap2.set(callbackId, {
|
|
1838
|
+
callbackMap2.set(callbackId, {
|
|
1839
|
+
onUpdate,
|
|
1840
|
+
onError
|
|
1841
|
+
});
|
|
1463
1842
|
if (existingSubscription.latestData !== void 0 && existingSubscription.isInitialDataReceived) {
|
|
1464
1843
|
try {
|
|
1465
1844
|
onUpdate(existingSubscription.latestData);
|
|
@@ -1486,7 +1865,10 @@ class RebaseWebSocketClient {
|
|
|
1486
1865
|
}
|
|
1487
1866
|
const backendSubscriptionId = `collection_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
1488
1867
|
const callbackMap = /* @__PURE__ */ new Map();
|
|
1489
|
-
callbackMap.set(callbackId, {
|
|
1868
|
+
callbackMap.set(callbackId, {
|
|
1869
|
+
onUpdate,
|
|
1870
|
+
onError
|
|
1871
|
+
});
|
|
1490
1872
|
this.collectionSubscriptions.set(subscriptionKey, {
|
|
1491
1873
|
backendSubscriptionId,
|
|
1492
1874
|
callbacks: callbackMap,
|
|
@@ -1526,7 +1908,10 @@ class RebaseWebSocketClient {
|
|
|
1526
1908
|
const existingSubscription = this.entitySubscriptions.get(subscriptionKey);
|
|
1527
1909
|
if (existingSubscription) {
|
|
1528
1910
|
const callbackMap2 = existingSubscription.callbacks;
|
|
1529
|
-
callbackMap2.set(callbackId, {
|
|
1911
|
+
callbackMap2.set(callbackId, {
|
|
1912
|
+
onUpdate,
|
|
1913
|
+
onError
|
|
1914
|
+
});
|
|
1530
1915
|
if (existingSubscription.latestData !== void 0 && existingSubscription.isInitialDataReceived) {
|
|
1531
1916
|
try {
|
|
1532
1917
|
onUpdate(existingSubscription.latestData);
|
|
@@ -1553,7 +1938,10 @@ class RebaseWebSocketClient {
|
|
|
1553
1938
|
}
|
|
1554
1939
|
const backendSubscriptionId = `entity_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
1555
1940
|
const callbackMap = /* @__PURE__ */ new Map();
|
|
1556
|
-
callbackMap.set(callbackId, {
|
|
1941
|
+
callbackMap.set(callbackId, {
|
|
1942
|
+
onUpdate,
|
|
1943
|
+
onError
|
|
1944
|
+
});
|
|
1557
1945
|
this.entitySubscriptions.set(subscriptionKey, {
|
|
1558
1946
|
backendSubscriptionId,
|
|
1559
1947
|
callbacks: callbackMap,
|
|
@@ -1654,23 +2042,21 @@ class RebaseWebSocketClient {
|
|
|
1654
2042
|
}
|
|
1655
2043
|
function createStorage(transport) {
|
|
1656
2044
|
const urlsCache = /* @__PURE__ */ new Map();
|
|
1657
|
-
async function
|
|
2045
|
+
async function putObject({
|
|
1658
2046
|
file,
|
|
1659
|
-
|
|
1660
|
-
path,
|
|
2047
|
+
key,
|
|
1661
2048
|
metadata,
|
|
1662
2049
|
bucket
|
|
1663
2050
|
}) {
|
|
1664
2051
|
const formData = new FormData();
|
|
1665
2052
|
formData.append("file", file);
|
|
1666
|
-
if (
|
|
1667
|
-
if (path) formData.append("path", path);
|
|
2053
|
+
if (key) formData.append("key", key);
|
|
1668
2054
|
if (bucket) formData.append("bucket", bucket);
|
|
1669
2055
|
if (metadata) {
|
|
1670
|
-
for (const [
|
|
2056
|
+
for (const [key2, value] of Object.entries(metadata)) {
|
|
1671
2057
|
if (value !== void 0 && value !== null) {
|
|
1672
2058
|
formData.append(
|
|
1673
|
-
`metadata_${
|
|
2059
|
+
`metadata_${key2}`,
|
|
1674
2060
|
typeof value === "string" ? value : JSON.stringify(value)
|
|
1675
2061
|
);
|
|
1676
2062
|
}
|
|
@@ -1680,18 +2066,18 @@ function createStorage(transport) {
|
|
|
1680
2066
|
method: "POST",
|
|
1681
2067
|
body: formData,
|
|
1682
2068
|
headers: {
|
|
1683
|
-
// transport.request merges headers, so to prevent it setting application/json we can delete it
|
|
2069
|
+
// transport.request merges headers, so to prevent it setting application/json we can delete it
|
|
1684
2070
|
// in transport if body is FormData, or we can explicitly set it to an empty string.
|
|
1685
2071
|
// Let's rely on standard behaviour for now and adjust transport if it fails.
|
|
1686
2072
|
}
|
|
1687
2073
|
});
|
|
1688
2074
|
return result.data;
|
|
1689
2075
|
}
|
|
1690
|
-
async function
|
|
1691
|
-
const cacheKey = bucket ? `${bucket}/${
|
|
2076
|
+
async function getSignedUrl(keyOrUrl, bucket) {
|
|
2077
|
+
const cacheKey = bucket ? `${bucket}/${keyOrUrl}` : keyOrUrl;
|
|
1692
2078
|
const cached = urlsCache.get(cacheKey);
|
|
1693
2079
|
if (cached) return cached;
|
|
1694
|
-
let filePath =
|
|
2080
|
+
let filePath = keyOrUrl;
|
|
1695
2081
|
if (filePath && (filePath.startsWith("local://") || filePath.startsWith("s3://"))) {
|
|
1696
2082
|
filePath = filePath.substring(filePath.indexOf("://") + 3);
|
|
1697
2083
|
}
|
|
@@ -1699,7 +2085,10 @@ function createStorage(transport) {
|
|
|
1699
2085
|
filePath = `${bucket}/${filePath}`;
|
|
1700
2086
|
}
|
|
1701
2087
|
if (!filePath || filePath.trim() === "" || filePath === "/") {
|
|
1702
|
-
return {
|
|
2088
|
+
return {
|
|
2089
|
+
url: null,
|
|
2090
|
+
fileNotFound: true
|
|
2091
|
+
};
|
|
1703
2092
|
}
|
|
1704
2093
|
try {
|
|
1705
2094
|
const result = await transport.request(`/storage/metadata/${filePath}`);
|
|
@@ -1713,13 +2102,16 @@ function createStorage(transport) {
|
|
|
1713
2102
|
return downloadConfig;
|
|
1714
2103
|
} catch (e) {
|
|
1715
2104
|
if (e instanceof Error && "status" in e && e.status === 404) {
|
|
1716
|
-
return {
|
|
2105
|
+
return {
|
|
2106
|
+
url: null,
|
|
2107
|
+
fileNotFound: true
|
|
2108
|
+
};
|
|
1717
2109
|
}
|
|
1718
2110
|
throw e;
|
|
1719
2111
|
}
|
|
1720
2112
|
}
|
|
1721
|
-
async function
|
|
1722
|
-
let filePath =
|
|
2113
|
+
async function getObject(key, bucket) {
|
|
2114
|
+
let filePath = key;
|
|
1723
2115
|
if (filePath && (filePath.startsWith("local://") || filePath.startsWith("s3://"))) {
|
|
1724
2116
|
filePath = filePath.substring(filePath.indexOf("://") + 3);
|
|
1725
2117
|
}
|
|
@@ -1739,8 +2131,8 @@ function createStorage(transport) {
|
|
|
1739
2131
|
const fileName = filePath.split("/").pop() || "file";
|
|
1740
2132
|
return new File([blob], fileName, { type: blob.type });
|
|
1741
2133
|
}
|
|
1742
|
-
async function
|
|
1743
|
-
let filePath =
|
|
2134
|
+
async function deleteObject(key, bucket) {
|
|
2135
|
+
let filePath = key;
|
|
1744
2136
|
if (filePath && (filePath.startsWith("local://") || filePath.startsWith("s3://"))) {
|
|
1745
2137
|
filePath = filePath.substring(filePath.indexOf("://") + 3);
|
|
1746
2138
|
}
|
|
@@ -1755,11 +2147,11 @@ function createStorage(transport) {
|
|
|
1755
2147
|
} catch (e) {
|
|
1756
2148
|
if (!(e instanceof Error && "status" in e && e.status === 404)) throw e;
|
|
1757
2149
|
}
|
|
1758
|
-
urlsCache.delete(bucket ? `${bucket}/${
|
|
2150
|
+
urlsCache.delete(bucket ? `${bucket}/${key}` : key);
|
|
1759
2151
|
}
|
|
1760
|
-
async function
|
|
2152
|
+
async function listObjects(prefix, options) {
|
|
1761
2153
|
const params = new URLSearchParams();
|
|
1762
|
-
if (
|
|
2154
|
+
if (prefix) params.set("prefix", prefix);
|
|
1763
2155
|
if (options?.bucket) params.set("bucket", options.bucket);
|
|
1764
2156
|
if (options?.maxResults) params.set("maxResults", String(options.maxResults));
|
|
1765
2157
|
if (options?.pageToken) params.set("pageToken", options.pageToken);
|
|
@@ -1767,20 +2159,28 @@ function createStorage(transport) {
|
|
|
1767
2159
|
return result.data;
|
|
1768
2160
|
}
|
|
1769
2161
|
return {
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
2162
|
+
putObject,
|
|
2163
|
+
getSignedUrl,
|
|
2164
|
+
getObject,
|
|
2165
|
+
deleteObject,
|
|
2166
|
+
listObjects
|
|
1775
2167
|
};
|
|
1776
2168
|
}
|
|
1777
2169
|
function deriveWebSocketUrl(baseUrl) {
|
|
2170
|
+
if (!baseUrl) {
|
|
2171
|
+
if (typeof window !== "undefined") {
|
|
2172
|
+
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
2173
|
+
return `${protocol}//${window.location.host}`;
|
|
2174
|
+
}
|
|
2175
|
+
return "";
|
|
2176
|
+
}
|
|
1778
2177
|
return baseUrl.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://").replace(/\/$/, "");
|
|
1779
2178
|
}
|
|
1780
2179
|
function createRebaseClient(options) {
|
|
1781
2180
|
const transport = createTransport(options);
|
|
1782
2181
|
const auth = createAuth(transport, options.auth);
|
|
1783
2182
|
const admin = createAdmin(transport, options.admin);
|
|
2183
|
+
const cron = createCron(transport, options.cron);
|
|
1784
2184
|
const storage = createStorage(transport);
|
|
1785
2185
|
const resolvedWsUrl = options.websocketUrl ?? deriveWebSocketUrl(options.baseUrl);
|
|
1786
2186
|
let ws;
|
|
@@ -1804,14 +2204,14 @@ function createRebaseClient(options) {
|
|
|
1804
2204
|
});
|
|
1805
2205
|
}
|
|
1806
2206
|
if (!options.onUnauthorized) {
|
|
1807
|
-
|
|
2207
|
+
transport.setOnUnauthorized(async () => {
|
|
1808
2208
|
try {
|
|
1809
2209
|
await auth.refreshSession();
|
|
1810
2210
|
return true;
|
|
1811
2211
|
} catch (e) {
|
|
1812
2212
|
return false;
|
|
1813
2213
|
}
|
|
1814
|
-
};
|
|
2214
|
+
});
|
|
1815
2215
|
}
|
|
1816
2216
|
const collectionClients = /* @__PURE__ */ new Map();
|
|
1817
2217
|
function collection(slug) {
|
|
@@ -1828,7 +2228,8 @@ function createRebaseClient(options) {
|
|
|
1828
2228
|
}
|
|
1829
2229
|
if (typeof prop === "symbol") return void 0;
|
|
1830
2230
|
if (typeof prop === "string" && prop !== "then" && prop !== "toJSON" && prop !== "$$typeof") {
|
|
1831
|
-
|
|
2231
|
+
const slug = toSnakeCase(prop);
|
|
2232
|
+
return collection(slug);
|
|
1832
2233
|
}
|
|
1833
2234
|
return void 0;
|
|
1834
2235
|
}
|
|
@@ -1836,6 +2237,7 @@ function createRebaseClient(options) {
|
|
|
1836
2237
|
const target = {
|
|
1837
2238
|
auth,
|
|
1838
2239
|
admin,
|
|
2240
|
+
cron,
|
|
1839
2241
|
storage,
|
|
1840
2242
|
ws,
|
|
1841
2243
|
setToken: transport.setToken,
|
|
@@ -1852,19 +2254,10 @@ function createRebaseClient(options) {
|
|
|
1852
2254
|
});
|
|
1853
2255
|
return res.data ?? res;
|
|
1854
2256
|
},
|
|
1855
|
-
data: dataProxy
|
|
2257
|
+
data: dataProxy,
|
|
2258
|
+
email: void 0
|
|
1856
2259
|
};
|
|
1857
|
-
return
|
|
1858
|
-
get(obj, prop) {
|
|
1859
|
-
if (prop in obj) {
|
|
1860
|
-
return obj[prop];
|
|
1861
|
-
}
|
|
1862
|
-
if (typeof prop === "string" && prop !== "then") {
|
|
1863
|
-
return collection(prop);
|
|
1864
|
-
}
|
|
1865
|
-
return void 0;
|
|
1866
|
-
}
|
|
1867
|
-
});
|
|
2260
|
+
return target;
|
|
1868
2261
|
}
|
|
1869
2262
|
export {
|
|
1870
2263
|
ApiError,
|
|
@@ -1874,9 +2267,11 @@ export {
|
|
|
1874
2267
|
createAdmin,
|
|
1875
2268
|
createAuth,
|
|
1876
2269
|
createCollectionClient,
|
|
2270
|
+
createCron,
|
|
1877
2271
|
createMemoryStorage,
|
|
1878
2272
|
createRebaseClient,
|
|
1879
2273
|
createStorage,
|
|
1880
|
-
createTransport
|
|
2274
|
+
createTransport,
|
|
2275
|
+
rebaseReviver
|
|
1881
2276
|
};
|
|
1882
2277
|
//# sourceMappingURL=index.es.js.map
|