@rebasepro/client 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/api-keys.d.ts +1 -0
- package/dist/collection.d.ts +3 -3
- package/dist/index.d.ts +20 -1
- package/dist/index.es.js +135 -168
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +138 -170
- package/dist/index.umd.js.map +1 -1
- package/dist/storage-registry.d.ts +42 -0
- package/dist/storage.d.ts +9 -1
- package/package.json +13 -12
- package/src/api-keys.ts +1 -0
- package/src/collection.test.ts +2 -2
- package/src/collection.ts +41 -119
- package/src/index.ts +77 -2
- package/src/storage-registry.ts +102 -0
- package/src/storage.ts +30 -20
- package/src/transport.ts +8 -82
package/dist/index.umd.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
(function(global, factory) {
|
|
2
|
-
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@rebasepro/
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@rebasepro/common"), require("@rebasepro/types"), require("@rebasepro/utils")) : typeof define === "function" && define.amd ? define([
|
|
3
3
|
"exports",
|
|
4
|
-
"@rebasepro/types",
|
|
5
4
|
"@rebasepro/common",
|
|
5
|
+
"@rebasepro/types",
|
|
6
6
|
"@rebasepro/utils"
|
|
7
|
-
], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["Rebase Client"] = {}, global.
|
|
8
|
-
})(this, function(exports,
|
|
7
|
+
], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["Rebase Client"] = {}, global._rebasepro_common, global._rebasepro_types, global._rebasepro_utils));
|
|
8
|
+
})(this, function(exports, _rebasepro_common, _rebasepro_types, _rebasepro_utils) {
|
|
9
9
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
10
10
|
//#region src/reviver.ts
|
|
11
11
|
function rebaseReviver(_key, value) {
|
|
@@ -48,61 +48,6 @@
|
|
|
48
48
|
this.details = details;
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
|
-
/**
|
|
52
|
-
* Maps a short operator alias to the PostgREST-style short code.
|
|
53
|
-
*/
|
|
54
|
-
var OP_MAP = {
|
|
55
|
-
"==": "eq",
|
|
56
|
-
"!=": "neq",
|
|
57
|
-
">": "gt",
|
|
58
|
-
">=": "gte",
|
|
59
|
-
"<": "lt",
|
|
60
|
-
"<=": "lte",
|
|
61
|
-
"not-in": "nin",
|
|
62
|
-
"array-contains": "cs",
|
|
63
|
-
"array-contains-any": "csa"
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* Normalise a single `WhereFieldValue` into the PostgREST query-string
|
|
67
|
-
* representation the backend expects.
|
|
68
|
-
*
|
|
69
|
-
* Supports:
|
|
70
|
-
* - `null` → `"eq.null"`
|
|
71
|
-
* - `true`/`false` → `"eq.true"` / `"eq.false"`
|
|
72
|
-
* - `42` → `"42"` (plain equality)
|
|
73
|
-
* - `"active"` → `"active"` (plain equality, backward-compat)
|
|
74
|
-
* - `"gte.18"` → `"gte.18"` (pass-through PostgREST string)
|
|
75
|
-
* - `[">=", 18]` → `"gte.18"` (tuple syntax)
|
|
76
|
-
* - `["in", [1,2]]` → `"in.(1,2)"` (tuple with array value)
|
|
77
|
-
* - `["!=", null]` → `"neq.null"`
|
|
78
|
-
*/
|
|
79
|
-
function normalizeWhereValue(value) {
|
|
80
|
-
if (value === null) return "eq.null";
|
|
81
|
-
if (typeof value === "boolean") return `eq.${value}`;
|
|
82
|
-
if (typeof value === "number") return String(value);
|
|
83
|
-
if (Array.isArray(value)) {
|
|
84
|
-
const [rawOp, val] = (Array.isArray(value[0]) ? value : [value])[0] || [];
|
|
85
|
-
if (rawOp) {
|
|
86
|
-
const op = OP_MAP[rawOp] ?? rawOp;
|
|
87
|
-
if (val === null) return `${op}.null`;
|
|
88
|
-
if (Array.isArray(val)) return `${op}.(${val.join(",")})`;
|
|
89
|
-
return `${op}.${val}`;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return String(value);
|
|
93
|
-
}
|
|
94
|
-
function serializeLogicalCondition(cond) {
|
|
95
|
-
if ("type" in cond) {
|
|
96
|
-
const sub = (cond.conditions ?? []).map(serializeLogicalCondition).join(",");
|
|
97
|
-
return `${cond.type}(${sub})`;
|
|
98
|
-
} else {
|
|
99
|
-
const op = OP_MAP[cond.operator] ?? cond.operator;
|
|
100
|
-
let formattedValue = cond.value;
|
|
101
|
-
if (Array.isArray(cond.value)) formattedValue = `(${cond.value.join(",")})`;
|
|
102
|
-
else if (cond.value === null) formattedValue = "null";
|
|
103
|
-
return `${cond.column}.${op}.${formattedValue}`;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
51
|
function buildQueryString(params) {
|
|
107
52
|
if (!params) return "";
|
|
108
53
|
const parts = [];
|
|
@@ -114,16 +59,13 @@
|
|
|
114
59
|
if (params.include && params.include.length > 0) parts.push(`include=${encodeURIComponent(params.include.join(","))}`);
|
|
115
60
|
if (params.logical) {
|
|
116
61
|
const root = params.logical;
|
|
117
|
-
const serialized = (root.conditions ?? []).map(serializeLogicalCondition).join(",");
|
|
62
|
+
const serialized = (root.conditions ?? []).map(_rebasepro_common.serializeLogicalCondition).join(",");
|
|
118
63
|
parts.push(`${root.type}=${encodeURIComponent(`(${serialized})`)}`);
|
|
119
64
|
}
|
|
120
|
-
if (params.where)
|
|
121
|
-
const
|
|
122
|
-
parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(
|
|
123
|
-
|
|
124
|
-
else {
|
|
125
|
-
const normalized = normalizeWhereValue(value);
|
|
126
|
-
parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(normalized)}`);
|
|
65
|
+
if (params.where) {
|
|
66
|
+
const serialized = (0, _rebasepro_common.serializeFilter)(params.where);
|
|
67
|
+
for (const [field, value] of Object.entries(serialized)) if (Array.isArray(value)) for (const v of value) parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(v)}`);
|
|
68
|
+
else parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(value)}`);
|
|
127
69
|
}
|
|
128
70
|
return parts.length > 0 ? "?" + parts.join("&") : "";
|
|
129
71
|
}
|
|
@@ -875,94 +817,6 @@
|
|
|
875
817
|
}
|
|
876
818
|
//#endregion
|
|
877
819
|
//#region src/collection.ts
|
|
878
|
-
function parseWhereFilter(where) {
|
|
879
|
-
if (!where) return void 0;
|
|
880
|
-
const filters = {};
|
|
881
|
-
const OP_TO_FILTER = {
|
|
882
|
-
"eq": "==",
|
|
883
|
-
"neq": "!=",
|
|
884
|
-
"gt": ">",
|
|
885
|
-
"gte": ">=",
|
|
886
|
-
"lt": "<",
|
|
887
|
-
"lte": "<=",
|
|
888
|
-
"==": "==",
|
|
889
|
-
"!=": "!=",
|
|
890
|
-
">": ">",
|
|
891
|
-
">=": ">=",
|
|
892
|
-
"<": "<",
|
|
893
|
-
"<=": "<=",
|
|
894
|
-
"in": "in",
|
|
895
|
-
"nin": "not-in",
|
|
896
|
-
"not-in": "not-in",
|
|
897
|
-
"cs": "array-contains",
|
|
898
|
-
"csa": "array-contains-any",
|
|
899
|
-
"array-contains": "array-contains",
|
|
900
|
-
"array-contains-any": "array-contains-any"
|
|
901
|
-
};
|
|
902
|
-
const parseSingle = (rawValue, fieldKey) => {
|
|
903
|
-
if (rawValue === null) return ["==", null];
|
|
904
|
-
if (typeof rawValue === "boolean") return ["==", rawValue];
|
|
905
|
-
if (typeof rawValue === "number") return ["==", rawValue];
|
|
906
|
-
if (Array.isArray(rawValue) && rawValue.length === 2 && typeof rawValue[0] === "string") {
|
|
907
|
-
const [rawOp, val] = rawValue;
|
|
908
|
-
return [OP_TO_FILTER[rawOp] ?? "==", val];
|
|
909
|
-
}
|
|
910
|
-
const value = String(rawValue);
|
|
911
|
-
const dotIndex = value.indexOf(".");
|
|
912
|
-
if (dotIndex > 0) {
|
|
913
|
-
const opStr = value.substring(0, dotIndex);
|
|
914
|
-
const valStr = value.substring(dotIndex + 1);
|
|
915
|
-
let op = "==";
|
|
916
|
-
let val = valStr;
|
|
917
|
-
switch (opStr) {
|
|
918
|
-
case "eq":
|
|
919
|
-
op = "==";
|
|
920
|
-
break;
|
|
921
|
-
case "neq":
|
|
922
|
-
op = "!=";
|
|
923
|
-
break;
|
|
924
|
-
case "gt":
|
|
925
|
-
op = ">";
|
|
926
|
-
break;
|
|
927
|
-
case "gte":
|
|
928
|
-
op = ">=";
|
|
929
|
-
break;
|
|
930
|
-
case "lt":
|
|
931
|
-
op = "<";
|
|
932
|
-
break;
|
|
933
|
-
case "lte":
|
|
934
|
-
op = "<=";
|
|
935
|
-
break;
|
|
936
|
-
case "in":
|
|
937
|
-
op = "in";
|
|
938
|
-
val = valStr.startsWith("(") && valStr.endsWith(")") ? valStr.slice(1, -1).split(",").map((v) => v.trim()) : valStr.split(",");
|
|
939
|
-
break;
|
|
940
|
-
case "nin":
|
|
941
|
-
op = "not-in";
|
|
942
|
-
val = valStr.startsWith("(") && valStr.endsWith(")") ? valStr.slice(1, -1).split(",").map((v) => v.trim()) : valStr.split(",");
|
|
943
|
-
break;
|
|
944
|
-
case "cs":
|
|
945
|
-
op = "array-contains";
|
|
946
|
-
break;
|
|
947
|
-
case "csa":
|
|
948
|
-
op = "array-contains-any";
|
|
949
|
-
val = valStr.startsWith("(") && valStr.endsWith(")") ? valStr.slice(1, -1).split(",").map((v) => v.trim()) : valStr.split(",");
|
|
950
|
-
break;
|
|
951
|
-
default:
|
|
952
|
-
op = "==";
|
|
953
|
-
val = value;
|
|
954
|
-
}
|
|
955
|
-
if (val === "true") val = true;
|
|
956
|
-
else if (val === "false") val = false;
|
|
957
|
-
else if (val === "null") val = null;
|
|
958
|
-
else if (typeof val === "string" && /^[0-9]+(\.[0-9]+)?$/.test(val) && fieldKey !== "id" && !fieldKey.endsWith("_id")) val = Number(val);
|
|
959
|
-
return [op, val];
|
|
960
|
-
} else return ["==", value];
|
|
961
|
-
};
|
|
962
|
-
for (const [key, rawValue] of Object.entries(where)) if (Array.isArray(rawValue) && rawValue.length > 0 && Array.isArray(rawValue[0])) filters[key] = rawValue.map((r) => parseSingle(r, key));
|
|
963
|
-
else filters[key] = parseSingle(rawValue, key);
|
|
964
|
-
return filters;
|
|
965
|
-
}
|
|
966
820
|
/**
|
|
967
821
|
* Wrap a flat row (returned by the REST API as `{ id, ...fields }`) into
|
|
968
822
|
* a proper `Entity<M>` structure expected by the core framework.
|
|
@@ -1027,8 +881,8 @@
|
|
|
1027
881
|
if (typeof columnOrCondition === "object") return builder.where(columnOrCondition);
|
|
1028
882
|
return builder.where(columnOrCondition, operator, value);
|
|
1029
883
|
},
|
|
1030
|
-
orderBy(column,
|
|
1031
|
-
return new _rebasepro_common.QueryBuilder(client).orderBy(column,
|
|
884
|
+
orderBy(column, direction) {
|
|
885
|
+
return new _rebasepro_common.QueryBuilder(client).orderBy(column, direction);
|
|
1032
886
|
},
|
|
1033
887
|
limit(count) {
|
|
1034
888
|
return new _rebasepro_common.QueryBuilder(client).limit(count);
|
|
@@ -1045,26 +899,45 @@
|
|
|
1045
899
|
};
|
|
1046
900
|
if (ws) {
|
|
1047
901
|
client.listen = (params, onUpdate, onError) => {
|
|
1048
|
-
|
|
902
|
+
let active = true;
|
|
903
|
+
let lastUpdateId = 0;
|
|
904
|
+
const unsub = ws.listenCollection({
|
|
1049
905
|
path: slug,
|
|
1050
|
-
filter:
|
|
906
|
+
filter: params?.where,
|
|
1051
907
|
limit: params?.limit,
|
|
1052
908
|
startAfter: params?.offset ? String(params.offset) : void 0,
|
|
1053
909
|
orderBy: params?.orderBy?.split(":")[0],
|
|
1054
910
|
order: params?.orderBy?.split(":")[1],
|
|
1055
911
|
searchString: params?.searchString
|
|
1056
912
|
}, (entities) => {
|
|
913
|
+
const currentUpdateId = ++lastUpdateId;
|
|
1057
914
|
const requestedLimit = params?.limit || 20;
|
|
915
|
+
const offset = params?.offset || 0;
|
|
1058
916
|
onUpdate({
|
|
1059
917
|
data: entities,
|
|
1060
918
|
meta: {
|
|
1061
919
|
total: entities.length,
|
|
1062
920
|
limit: requestedLimit,
|
|
1063
|
-
offset
|
|
921
|
+
offset,
|
|
1064
922
|
hasMore: entities.length >= requestedLimit
|
|
1065
923
|
}
|
|
1066
924
|
});
|
|
925
|
+
if (client.count) client.count(params).then((total) => {
|
|
926
|
+
if (active && currentUpdateId === lastUpdateId) onUpdate({
|
|
927
|
+
data: entities,
|
|
928
|
+
meta: {
|
|
929
|
+
total,
|
|
930
|
+
limit: requestedLimit,
|
|
931
|
+
offset,
|
|
932
|
+
hasMore: offset + entities.length < total
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
}).catch(() => {});
|
|
1067
936
|
}, onError);
|
|
937
|
+
return () => {
|
|
938
|
+
active = false;
|
|
939
|
+
unsub();
|
|
940
|
+
};
|
|
1068
941
|
};
|
|
1069
942
|
client.listenById = (id, onUpdate, onError) => {
|
|
1070
943
|
return ws.listenEntity({
|
|
@@ -1104,17 +977,31 @@
|
|
|
1104
977
|
}
|
|
1105
978
|
//#endregion
|
|
1106
979
|
//#region src/storage.ts
|
|
1107
|
-
|
|
980
|
+
/**
|
|
981
|
+
* Create a StorageSource that talks to the Rebase backend REST API.
|
|
982
|
+
*
|
|
983
|
+
* @param transport - HTTP transport instance
|
|
984
|
+
* @param storageId - Optional storage-source key for multi-backend routing.
|
|
985
|
+
* When set, it is forwarded to the server so the correct
|
|
986
|
+
* `StorageController` is resolved from the registry.
|
|
987
|
+
*/
|
|
988
|
+
function createStorage(transport, storageId) {
|
|
1108
989
|
const urlsCache = /* @__PURE__ */ new Map();
|
|
990
|
+
/** Append ?storageId=... to a path when multi-backend routing is active. */
|
|
991
|
+
const withStorageId = (path) => {
|
|
992
|
+
if (!storageId) return path;
|
|
993
|
+
return `${path}${path.includes("?") ? "&" : "?"}storageId=${encodeURIComponent(storageId)}`;
|
|
994
|
+
};
|
|
1109
995
|
async function putObject({ file, key, metadata, bucket }) {
|
|
1110
996
|
const formData = new FormData();
|
|
1111
997
|
formData.append("file", file);
|
|
1112
998
|
if (key) formData.append("key", key);
|
|
1113
999
|
if (bucket) formData.append("bucket", bucket);
|
|
1000
|
+
if (storageId) formData.append("storageId", storageId);
|
|
1114
1001
|
if (metadata) {
|
|
1115
1002
|
for (const [key, value] of Object.entries(metadata)) if (value !== void 0 && value !== null) formData.append(`metadata_${key}`, typeof value === "string" ? value : JSON.stringify(value));
|
|
1116
1003
|
}
|
|
1117
|
-
return (await transport.request("/storage/upload", {
|
|
1004
|
+
return (await transport.request(withStorageId("/storage/upload"), {
|
|
1118
1005
|
method: "POST",
|
|
1119
1006
|
body: formData,
|
|
1120
1007
|
headers: {}
|
|
@@ -1125,18 +1012,18 @@
|
|
|
1125
1012
|
const cached = urlsCache.get(cacheKey);
|
|
1126
1013
|
if (cached) return cached;
|
|
1127
1014
|
let filePath = keyOrUrl;
|
|
1128
|
-
if (filePath && (filePath.startsWith("local://") || filePath.startsWith("s3://"))) filePath = filePath.substring(filePath.indexOf("://") + 3);
|
|
1015
|
+
if (filePath && (filePath.startsWith("local://") || filePath.startsWith("s3://") || filePath.startsWith("gs://"))) filePath = filePath.substring(filePath.indexOf("://") + 3);
|
|
1129
1016
|
if (bucket && filePath && !filePath.startsWith(bucket)) filePath = `${bucket}/${filePath}`;
|
|
1130
1017
|
if (!filePath || filePath.trim() === "" || filePath === "/") return {
|
|
1131
1018
|
url: null,
|
|
1132
1019
|
fileNotFound: true
|
|
1133
1020
|
};
|
|
1134
1021
|
try {
|
|
1135
|
-
const result = await transport.request(`/storage/metadata/${filePath}`);
|
|
1022
|
+
const result = await transport.request(withStorageId(`/storage/metadata/${filePath}`));
|
|
1136
1023
|
const activeToken = await transport.resolveToken();
|
|
1137
1024
|
const tokenQuery = activeToken ? `?token=${activeToken}` : "";
|
|
1138
1025
|
const downloadConfig = {
|
|
1139
|
-
url: `${transport.baseUrl}${transport.apiPath}/storage/file/${filePath}${tokenQuery}
|
|
1026
|
+
url: withStorageId(`${transport.baseUrl}${transport.apiPath}/storage/file/${filePath}${tokenQuery}`),
|
|
1140
1027
|
metadata: result.data
|
|
1141
1028
|
};
|
|
1142
1029
|
urlsCache.set(cacheKey, downloadConfig);
|
|
@@ -1151,10 +1038,10 @@
|
|
|
1151
1038
|
}
|
|
1152
1039
|
async function getObject(key, bucket) {
|
|
1153
1040
|
let filePath = key;
|
|
1154
|
-
if (filePath && (filePath.startsWith("local://") || filePath.startsWith("s3://"))) filePath = filePath.substring(filePath.indexOf("://") + 3);
|
|
1041
|
+
if (filePath && (filePath.startsWith("local://") || filePath.startsWith("s3://") || filePath.startsWith("gs://"))) filePath = filePath.substring(filePath.indexOf("://") + 3);
|
|
1155
1042
|
if (bucket && filePath && !filePath.startsWith(bucket)) filePath = `${bucket}/${filePath}`;
|
|
1156
1043
|
if (!filePath || filePath.trim() === "" || filePath === "/") return null;
|
|
1157
|
-
const url = `${transport.baseUrl}${transport.apiPath}/storage/file/${filePath}
|
|
1044
|
+
const url = withStorageId(`${transport.baseUrl}${transport.apiPath}/storage/file/${filePath}`);
|
|
1158
1045
|
const response = await transport.fetchFn(url, { headers: transport.getHeaders ? transport.getHeaders() : {} });
|
|
1159
1046
|
if (response.status === 404) return null;
|
|
1160
1047
|
if (!response.ok) throw new Error("Failed to get file");
|
|
@@ -1164,11 +1051,11 @@
|
|
|
1164
1051
|
}
|
|
1165
1052
|
async function deleteObject(key, bucket) {
|
|
1166
1053
|
let filePath = key;
|
|
1167
|
-
if (filePath && (filePath.startsWith("local://") || filePath.startsWith("s3://"))) filePath = filePath.substring(filePath.indexOf("://") + 3);
|
|
1054
|
+
if (filePath && (filePath.startsWith("local://") || filePath.startsWith("s3://") || filePath.startsWith("gs://"))) filePath = filePath.substring(filePath.indexOf("://") + 3);
|
|
1168
1055
|
if (bucket && filePath && !filePath.startsWith(bucket)) filePath = `${bucket}/${filePath}`;
|
|
1169
1056
|
if (!filePath || filePath.trim() === "" || filePath === "/") return;
|
|
1170
1057
|
try {
|
|
1171
|
-
await transport.request(`/storage/file/${filePath}
|
|
1058
|
+
await transport.request(withStorageId(`/storage/file/${filePath}`), { method: "DELETE" });
|
|
1172
1059
|
} catch (e) {
|
|
1173
1060
|
if (!(e instanceof Error && "status" in e && e.status === 404)) throw e;
|
|
1174
1061
|
}
|
|
@@ -1180,6 +1067,7 @@
|
|
|
1180
1067
|
if (options?.bucket) params.set("bucket", options.bucket);
|
|
1181
1068
|
if (options?.maxResults) params.set("maxResults", String(options.maxResults));
|
|
1182
1069
|
if (options?.pageToken) params.set("pageToken", options.pageToken);
|
|
1070
|
+
if (storageId) params.set("storageId", storageId);
|
|
1183
1071
|
return (await transport.request(`/storage/list?${params.toString()}`)).data;
|
|
1184
1072
|
}
|
|
1185
1073
|
return {
|
|
@@ -1191,6 +1079,62 @@
|
|
|
1191
1079
|
};
|
|
1192
1080
|
}
|
|
1193
1081
|
//#endregion
|
|
1082
|
+
//#region src/storage-registry.ts
|
|
1083
|
+
/**
|
|
1084
|
+
* Default implementation of the client-side `StorageSourceRegistry`.
|
|
1085
|
+
*/
|
|
1086
|
+
var ClientStorageSourceRegistry = class ClientStorageSourceRegistry {
|
|
1087
|
+
sources = /* @__PURE__ */ new Map();
|
|
1088
|
+
/**
|
|
1089
|
+
* Register a storage source.
|
|
1090
|
+
* @param key - Unique key matching a `StorageSourceDefinition.key`
|
|
1091
|
+
* @param source - The `StorageSource` instance
|
|
1092
|
+
*/
|
|
1093
|
+
register(key, source) {
|
|
1094
|
+
this.sources.set(key, source);
|
|
1095
|
+
}
|
|
1096
|
+
getDefault() {
|
|
1097
|
+
const source = this.sources.get(_rebasepro_types.DEFAULT_STORAGE_SOURCE_KEY);
|
|
1098
|
+
if (!source) throw new Error(`[StorageSourceRegistry] No default storage source registered. Register one with key "${_rebasepro_types.DEFAULT_STORAGE_SOURCE_KEY}".`);
|
|
1099
|
+
return source;
|
|
1100
|
+
}
|
|
1101
|
+
get(key) {
|
|
1102
|
+
if (key === void 0 || key === null) return this.sources.get(_rebasepro_types.DEFAULT_STORAGE_SOURCE_KEY);
|
|
1103
|
+
return this.sources.get(key);
|
|
1104
|
+
}
|
|
1105
|
+
getOrDefault(key) {
|
|
1106
|
+
if (key === void 0 || key === null) return this.getDefault();
|
|
1107
|
+
const source = this.sources.get(key);
|
|
1108
|
+
if (source) return source;
|
|
1109
|
+
console.warn(`[StorageSourceRegistry] Storage source "${key}" not found, falling back to "${_rebasepro_types.DEFAULT_STORAGE_SOURCE_KEY}".`);
|
|
1110
|
+
return this.getDefault();
|
|
1111
|
+
}
|
|
1112
|
+
has(key) {
|
|
1113
|
+
return this.sources.has(key);
|
|
1114
|
+
}
|
|
1115
|
+
list() {
|
|
1116
|
+
return Array.from(this.sources.keys());
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Build a registry from `StorageSourceDefinition[]` and an HTTP transport.
|
|
1120
|
+
*
|
|
1121
|
+
* - Sources with `transport: "server"` are auto-wired via `createStorage(transport, key)`.
|
|
1122
|
+
* - Sources with `transport: "direct"` are **not** auto-wired — they must
|
|
1123
|
+
* be registered manually after this call (e.g. via a Firebase hook).
|
|
1124
|
+
*
|
|
1125
|
+
* @param definitions - Array of storage source definitions
|
|
1126
|
+
* @param transport - HTTP transport for server-backed sources
|
|
1127
|
+
*/
|
|
1128
|
+
static fromDefinitions(definitions, transport) {
|
|
1129
|
+
const registry = new ClientStorageSourceRegistry();
|
|
1130
|
+
for (const def of definitions) if (def.transport === "server") {
|
|
1131
|
+
const source = createStorage(transport, def.key === _rebasepro_types.DEFAULT_STORAGE_SOURCE_KEY ? void 0 : def.key);
|
|
1132
|
+
registry.register(def.key, source);
|
|
1133
|
+
}
|
|
1134
|
+
return registry;
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
//#endregion
|
|
1194
1138
|
//#region src/websocket.ts
|
|
1195
1139
|
/**
|
|
1196
1140
|
* Extract error message and code from a WebSocket message payload.
|
|
@@ -2128,6 +2072,23 @@
|
|
|
2128
2072
|
const apiKeys = createApiKeys(transport, options.apiKeys);
|
|
2129
2073
|
const storage = createStorage(transport);
|
|
2130
2074
|
const functions = createFunctionsClient(transport);
|
|
2075
|
+
const createStorageSource = (storageId) => storageId === _rebasepro_types.DEFAULT_STORAGE_SOURCE_KEY ? storage : createStorage(transport, storageId);
|
|
2076
|
+
const storageRegistry = new ClientStorageSourceRegistry();
|
|
2077
|
+
storageRegistry.register(_rebasepro_types.DEFAULT_STORAGE_SOURCE_KEY, storage);
|
|
2078
|
+
for (const def of options.storageSources ?? []) if (def.transport === "server" && def.key !== _rebasepro_types.DEFAULT_STORAGE_SOURCE_KEY) storageRegistry.register(def.key, createStorageSource(def.key));
|
|
2079
|
+
let storageSourcesPromise;
|
|
2080
|
+
const fetchStorageSources = () => {
|
|
2081
|
+
if (storageSourcesPromise) return storageSourcesPromise;
|
|
2082
|
+
storageSourcesPromise = transport.request("/storage/sources").then((res) => {
|
|
2083
|
+
const defs = res.data ?? [];
|
|
2084
|
+
for (const def of defs) if (def.transport === "server" && def.key !== _rebasepro_types.DEFAULT_STORAGE_SOURCE_KEY && !storageRegistry.has(def.key)) storageRegistry.register(def.key, createStorageSource(def.key));
|
|
2085
|
+
return defs;
|
|
2086
|
+
}).catch((e) => {
|
|
2087
|
+
storageSourcesPromise = void 0;
|
|
2088
|
+
throw e;
|
|
2089
|
+
});
|
|
2090
|
+
return storageSourcesPromise;
|
|
2091
|
+
};
|
|
2131
2092
|
const resolvedWsUrl = options.websocketUrl ?? deriveWebSocketUrl(options.baseUrl);
|
|
2132
2093
|
let ws;
|
|
2133
2094
|
if (resolvedWsUrl) {
|
|
@@ -2173,7 +2134,10 @@
|
|
|
2173
2134
|
const dataProxy = new Proxy({ collection }, { get(_target, prop) {
|
|
2174
2135
|
if (prop === "collection") return collection;
|
|
2175
2136
|
if (typeof prop === "symbol") return void 0;
|
|
2176
|
-
if (typeof prop === "string" && prop !== "then" && prop !== "toJSON" && prop !== "$$typeof")
|
|
2137
|
+
if (typeof prop === "string" && prop !== "then" && prop !== "toJSON" && prop !== "$$typeof") {
|
|
2138
|
+
if (options.collections && prop in options.collections) return collection(options.collections[prop]);
|
|
2139
|
+
return collection((0, _rebasepro_utils.toSnakeCase)(prop));
|
|
2140
|
+
}
|
|
2177
2141
|
} });
|
|
2178
2142
|
return {
|
|
2179
2143
|
auth,
|
|
@@ -2182,6 +2146,9 @@
|
|
|
2182
2146
|
apiKeys,
|
|
2183
2147
|
functions,
|
|
2184
2148
|
storage,
|
|
2149
|
+
storageRegistry,
|
|
2150
|
+
createStorageSource,
|
|
2151
|
+
fetchStorageSources,
|
|
2185
2152
|
ws,
|
|
2186
2153
|
setToken: transport.setToken,
|
|
2187
2154
|
setAuthTokenGetter: transport.setAuthTokenGetter,
|
|
@@ -2203,6 +2170,7 @@
|
|
|
2203
2170
|
}
|
|
2204
2171
|
//#endregion
|
|
2205
2172
|
exports.ApiError = ApiError;
|
|
2173
|
+
exports.ClientStorageSourceRegistry = ClientStorageSourceRegistry;
|
|
2206
2174
|
Object.defineProperty(exports, "QueryBuilder", {
|
|
2207
2175
|
enumerable: true,
|
|
2208
2176
|
get: function() {
|