@hot-updater/supabase 0.29.5 → 0.29.6
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/edge.cjs +1 -1
- package/dist/edge.mjs +1 -1
- package/dist/iac/index.cjs +7 -5
- package/dist/iac/index.mjs +8 -6
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/supabaseEdgeFunctionStorage-Dd8ytWP1.cjs +545 -0
- package/dist/supabaseEdgeFunctionStorage-DnnViEfo.mjs +527 -0
- package/package.json +9 -9
- package/dist/supabaseEdgeFunctionStorage-B-gM2rZx.cjs +0 -192
- package/dist/supabaseEdgeFunctionStorage-CVEY5QJO.mjs +0 -174
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
import { DEFAULT_ROLLOUT_COHORT_COUNT, NIL_UUID } from "@hot-updater/core";
|
|
2
|
+
import { calculatePagination, createDatabasePlugin, filterCompatibleAppVersions } from "@hot-updater/plugin-core";
|
|
3
|
+
import { createClient } from "@supabase/supabase-js";
|
|
4
|
+
//#region ../../node_modules/.pnpm/map-obj@5.0.0/node_modules/map-obj/index.js
|
|
5
|
+
const isObject$1 = (value) => typeof value === "object" && value !== null;
|
|
6
|
+
const isObjectCustom = (value) => isObject$1(value) && !(value instanceof RegExp) && !(value instanceof Error) && !(value instanceof Date);
|
|
7
|
+
const mapObjectSkip = Symbol("mapObjectSkip");
|
|
8
|
+
const _mapObject = (object, mapper, options, isSeen = /* @__PURE__ */ new WeakMap()) => {
|
|
9
|
+
options = {
|
|
10
|
+
deep: false,
|
|
11
|
+
target: {},
|
|
12
|
+
...options
|
|
13
|
+
};
|
|
14
|
+
if (isSeen.has(object)) return isSeen.get(object);
|
|
15
|
+
isSeen.set(object, options.target);
|
|
16
|
+
const { target } = options;
|
|
17
|
+
delete options.target;
|
|
18
|
+
const mapArray = (array) => array.map((element) => isObjectCustom(element) ? _mapObject(element, mapper, options, isSeen) : element);
|
|
19
|
+
if (Array.isArray(object)) return mapArray(object);
|
|
20
|
+
for (const [key, value] of Object.entries(object)) {
|
|
21
|
+
const mapResult = mapper(key, value, object);
|
|
22
|
+
if (mapResult === mapObjectSkip) continue;
|
|
23
|
+
let [newKey, newValue, { shouldRecurse = true } = {}] = mapResult;
|
|
24
|
+
if (newKey === "__proto__") continue;
|
|
25
|
+
if (options.deep && shouldRecurse && isObjectCustom(newValue)) newValue = Array.isArray(newValue) ? mapArray(newValue) : _mapObject(newValue, mapper, options, isSeen);
|
|
26
|
+
target[newKey] = newValue;
|
|
27
|
+
}
|
|
28
|
+
return target;
|
|
29
|
+
};
|
|
30
|
+
function mapObject(object, mapper, options) {
|
|
31
|
+
if (!isObject$1(object)) throw new TypeError(`Expected an object, got \`${object}\` (${typeof object})`);
|
|
32
|
+
return _mapObject(object, mapper, options);
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region ../../node_modules/.pnpm/camelcase@8.0.0/node_modules/camelcase/index.js
|
|
36
|
+
const UPPERCASE = /[\p{Lu}]/u;
|
|
37
|
+
const LOWERCASE = /[\p{Ll}]/u;
|
|
38
|
+
const LEADING_CAPITAL = /^[\p{Lu}](?![\p{Lu}])/gu;
|
|
39
|
+
const IDENTIFIER = /([\p{Alpha}\p{N}_]|$)/u;
|
|
40
|
+
const SEPARATORS = /[_.\- ]+/;
|
|
41
|
+
const LEADING_SEPARATORS = new RegExp("^" + SEPARATORS.source);
|
|
42
|
+
const SEPARATORS_AND_IDENTIFIER = new RegExp(SEPARATORS.source + IDENTIFIER.source, "gu");
|
|
43
|
+
const NUMBERS_AND_IDENTIFIER = new RegExp("\\d+" + IDENTIFIER.source, "gu");
|
|
44
|
+
const preserveCamelCase = (string, toLowerCase, toUpperCase, preserveConsecutiveUppercase) => {
|
|
45
|
+
let isLastCharLower = false;
|
|
46
|
+
let isLastCharUpper = false;
|
|
47
|
+
let isLastLastCharUpper = false;
|
|
48
|
+
let isLastLastCharPreserved = false;
|
|
49
|
+
for (let index = 0; index < string.length; index++) {
|
|
50
|
+
const character = string[index];
|
|
51
|
+
isLastLastCharPreserved = index > 2 ? string[index - 3] === "-" : true;
|
|
52
|
+
if (isLastCharLower && UPPERCASE.test(character)) {
|
|
53
|
+
string = string.slice(0, index) + "-" + string.slice(index);
|
|
54
|
+
isLastCharLower = false;
|
|
55
|
+
isLastLastCharUpper = isLastCharUpper;
|
|
56
|
+
isLastCharUpper = true;
|
|
57
|
+
index++;
|
|
58
|
+
} else if (isLastCharUpper && isLastLastCharUpper && LOWERCASE.test(character) && (!isLastLastCharPreserved || preserveConsecutiveUppercase)) {
|
|
59
|
+
string = string.slice(0, index - 1) + "-" + string.slice(index - 1);
|
|
60
|
+
isLastLastCharUpper = isLastCharUpper;
|
|
61
|
+
isLastCharUpper = false;
|
|
62
|
+
isLastCharLower = true;
|
|
63
|
+
} else {
|
|
64
|
+
isLastCharLower = toLowerCase(character) === character && toUpperCase(character) !== character;
|
|
65
|
+
isLastLastCharUpper = isLastCharUpper;
|
|
66
|
+
isLastCharUpper = toUpperCase(character) === character && toLowerCase(character) !== character;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return string;
|
|
70
|
+
};
|
|
71
|
+
const preserveConsecutiveUppercase = (input, toLowerCase) => {
|
|
72
|
+
LEADING_CAPITAL.lastIndex = 0;
|
|
73
|
+
return input.replaceAll(LEADING_CAPITAL, (match) => toLowerCase(match));
|
|
74
|
+
};
|
|
75
|
+
const postProcess = (input, toUpperCase) => {
|
|
76
|
+
SEPARATORS_AND_IDENTIFIER.lastIndex = 0;
|
|
77
|
+
NUMBERS_AND_IDENTIFIER.lastIndex = 0;
|
|
78
|
+
return input.replaceAll(NUMBERS_AND_IDENTIFIER, (match, pattern, offset) => ["_", "-"].includes(input.charAt(offset + match.length)) ? match : toUpperCase(match)).replaceAll(SEPARATORS_AND_IDENTIFIER, (_, identifier) => toUpperCase(identifier));
|
|
79
|
+
};
|
|
80
|
+
function camelCase(input, options) {
|
|
81
|
+
if (!(typeof input === "string" || Array.isArray(input))) throw new TypeError("Expected the input to be `string | string[]`");
|
|
82
|
+
options = {
|
|
83
|
+
pascalCase: false,
|
|
84
|
+
preserveConsecutiveUppercase: false,
|
|
85
|
+
...options
|
|
86
|
+
};
|
|
87
|
+
if (Array.isArray(input)) input = input.map((x) => x.trim()).filter((x) => x.length).join("-");
|
|
88
|
+
else input = input.trim();
|
|
89
|
+
if (input.length === 0) return "";
|
|
90
|
+
const toLowerCase = options.locale === false ? (string) => string.toLowerCase() : (string) => string.toLocaleLowerCase(options.locale);
|
|
91
|
+
const toUpperCase = options.locale === false ? (string) => string.toUpperCase() : (string) => string.toLocaleUpperCase(options.locale);
|
|
92
|
+
if (input.length === 1) {
|
|
93
|
+
if (SEPARATORS.test(input)) return "";
|
|
94
|
+
return options.pascalCase ? toUpperCase(input) : toLowerCase(input);
|
|
95
|
+
}
|
|
96
|
+
if (input !== toLowerCase(input)) input = preserveCamelCase(input, toLowerCase, toUpperCase, options.preserveConsecutiveUppercase);
|
|
97
|
+
input = input.replace(LEADING_SEPARATORS, "");
|
|
98
|
+
input = options.preserveConsecutiveUppercase ? preserveConsecutiveUppercase(input, toLowerCase) : toLowerCase(input);
|
|
99
|
+
if (options.pascalCase) input = toUpperCase(input.charAt(0)) + input.slice(1);
|
|
100
|
+
return postProcess(input, toUpperCase);
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region ../../node_modules/.pnpm/quick-lru@6.1.2/node_modules/quick-lru/index.js
|
|
104
|
+
var QuickLRU = class extends Map {
|
|
105
|
+
constructor(options = {}) {
|
|
106
|
+
super();
|
|
107
|
+
if (!(options.maxSize && options.maxSize > 0)) throw new TypeError("`maxSize` must be a number greater than 0");
|
|
108
|
+
if (typeof options.maxAge === "number" && options.maxAge === 0) throw new TypeError("`maxAge` must be a number greater than 0");
|
|
109
|
+
this.maxSize = options.maxSize;
|
|
110
|
+
this.maxAge = options.maxAge || Number.POSITIVE_INFINITY;
|
|
111
|
+
this.onEviction = options.onEviction;
|
|
112
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
113
|
+
this.oldCache = /* @__PURE__ */ new Map();
|
|
114
|
+
this._size = 0;
|
|
115
|
+
}
|
|
116
|
+
_emitEvictions(cache) {
|
|
117
|
+
if (typeof this.onEviction !== "function") return;
|
|
118
|
+
for (const [key, item] of cache) this.onEviction(key, item.value);
|
|
119
|
+
}
|
|
120
|
+
_deleteIfExpired(key, item) {
|
|
121
|
+
if (typeof item.expiry === "number" && item.expiry <= Date.now()) {
|
|
122
|
+
if (typeof this.onEviction === "function") this.onEviction(key, item.value);
|
|
123
|
+
return this.delete(key);
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
_getOrDeleteIfExpired(key, item) {
|
|
128
|
+
if (this._deleteIfExpired(key, item) === false) return item.value;
|
|
129
|
+
}
|
|
130
|
+
_getItemValue(key, item) {
|
|
131
|
+
return item.expiry ? this._getOrDeleteIfExpired(key, item) : item.value;
|
|
132
|
+
}
|
|
133
|
+
_peek(key, cache) {
|
|
134
|
+
const item = cache.get(key);
|
|
135
|
+
return this._getItemValue(key, item);
|
|
136
|
+
}
|
|
137
|
+
_set(key, value) {
|
|
138
|
+
this.cache.set(key, value);
|
|
139
|
+
this._size++;
|
|
140
|
+
if (this._size >= this.maxSize) {
|
|
141
|
+
this._size = 0;
|
|
142
|
+
this._emitEvictions(this.oldCache);
|
|
143
|
+
this.oldCache = this.cache;
|
|
144
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
_moveToRecent(key, item) {
|
|
148
|
+
this.oldCache.delete(key);
|
|
149
|
+
this._set(key, item);
|
|
150
|
+
}
|
|
151
|
+
*_entriesAscending() {
|
|
152
|
+
for (const item of this.oldCache) {
|
|
153
|
+
const [key, value] = item;
|
|
154
|
+
if (!this.cache.has(key)) {
|
|
155
|
+
if (this._deleteIfExpired(key, value) === false) yield item;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
for (const item of this.cache) {
|
|
159
|
+
const [key, value] = item;
|
|
160
|
+
if (this._deleteIfExpired(key, value) === false) yield item;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
get(key) {
|
|
164
|
+
if (this.cache.has(key)) {
|
|
165
|
+
const item = this.cache.get(key);
|
|
166
|
+
return this._getItemValue(key, item);
|
|
167
|
+
}
|
|
168
|
+
if (this.oldCache.has(key)) {
|
|
169
|
+
const item = this.oldCache.get(key);
|
|
170
|
+
if (this._deleteIfExpired(key, item) === false) {
|
|
171
|
+
this._moveToRecent(key, item);
|
|
172
|
+
return item.value;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
set(key, value, { maxAge = this.maxAge } = {}) {
|
|
177
|
+
const expiry = typeof maxAge === "number" && maxAge !== Number.POSITIVE_INFINITY ? Date.now() + maxAge : void 0;
|
|
178
|
+
if (this.cache.has(key)) this.cache.set(key, {
|
|
179
|
+
value,
|
|
180
|
+
expiry
|
|
181
|
+
});
|
|
182
|
+
else this._set(key, {
|
|
183
|
+
value,
|
|
184
|
+
expiry
|
|
185
|
+
});
|
|
186
|
+
return this;
|
|
187
|
+
}
|
|
188
|
+
has(key) {
|
|
189
|
+
if (this.cache.has(key)) return !this._deleteIfExpired(key, this.cache.get(key));
|
|
190
|
+
if (this.oldCache.has(key)) return !this._deleteIfExpired(key, this.oldCache.get(key));
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
peek(key) {
|
|
194
|
+
if (this.cache.has(key)) return this._peek(key, this.cache);
|
|
195
|
+
if (this.oldCache.has(key)) return this._peek(key, this.oldCache);
|
|
196
|
+
}
|
|
197
|
+
delete(key) {
|
|
198
|
+
const deleted = this.cache.delete(key);
|
|
199
|
+
if (deleted) this._size--;
|
|
200
|
+
return this.oldCache.delete(key) || deleted;
|
|
201
|
+
}
|
|
202
|
+
clear() {
|
|
203
|
+
this.cache.clear();
|
|
204
|
+
this.oldCache.clear();
|
|
205
|
+
this._size = 0;
|
|
206
|
+
}
|
|
207
|
+
resize(newSize) {
|
|
208
|
+
if (!(newSize && newSize > 0)) throw new TypeError("`maxSize` must be a number greater than 0");
|
|
209
|
+
const items = [...this._entriesAscending()];
|
|
210
|
+
const removeCount = items.length - newSize;
|
|
211
|
+
if (removeCount < 0) {
|
|
212
|
+
this.cache = new Map(items);
|
|
213
|
+
this.oldCache = /* @__PURE__ */ new Map();
|
|
214
|
+
this._size = items.length;
|
|
215
|
+
} else {
|
|
216
|
+
if (removeCount > 0) this._emitEvictions(items.slice(0, removeCount));
|
|
217
|
+
this.oldCache = new Map(items.slice(removeCount));
|
|
218
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
219
|
+
this._size = 0;
|
|
220
|
+
}
|
|
221
|
+
this.maxSize = newSize;
|
|
222
|
+
}
|
|
223
|
+
*keys() {
|
|
224
|
+
for (const [key] of this) yield key;
|
|
225
|
+
}
|
|
226
|
+
*values() {
|
|
227
|
+
for (const [, value] of this) yield value;
|
|
228
|
+
}
|
|
229
|
+
*[Symbol.iterator]() {
|
|
230
|
+
for (const item of this.cache) {
|
|
231
|
+
const [key, value] = item;
|
|
232
|
+
if (this._deleteIfExpired(key, value) === false) yield [key, value.value];
|
|
233
|
+
}
|
|
234
|
+
for (const item of this.oldCache) {
|
|
235
|
+
const [key, value] = item;
|
|
236
|
+
if (!this.cache.has(key)) {
|
|
237
|
+
if (this._deleteIfExpired(key, value) === false) yield [key, value.value];
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
*entriesDescending() {
|
|
242
|
+
let items = [...this.cache];
|
|
243
|
+
for (let i = items.length - 1; i >= 0; --i) {
|
|
244
|
+
const [key, value] = items[i];
|
|
245
|
+
if (this._deleteIfExpired(key, value) === false) yield [key, value.value];
|
|
246
|
+
}
|
|
247
|
+
items = [...this.oldCache];
|
|
248
|
+
for (let i = items.length - 1; i >= 0; --i) {
|
|
249
|
+
const [key, value] = items[i];
|
|
250
|
+
if (!this.cache.has(key)) {
|
|
251
|
+
if (this._deleteIfExpired(key, value) === false) yield [key, value.value];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
*entriesAscending() {
|
|
256
|
+
for (const [key, value] of this._entriesAscending()) yield [key, value.value];
|
|
257
|
+
}
|
|
258
|
+
get size() {
|
|
259
|
+
if (!this._size) return this.oldCache.size;
|
|
260
|
+
let oldCacheSize = 0;
|
|
261
|
+
for (const key of this.oldCache.keys()) if (!this.cache.has(key)) oldCacheSize++;
|
|
262
|
+
return Math.min(this._size + oldCacheSize, this.maxSize);
|
|
263
|
+
}
|
|
264
|
+
entries() {
|
|
265
|
+
return this.entriesAscending();
|
|
266
|
+
}
|
|
267
|
+
forEach(callbackFunction, thisArgument = this) {
|
|
268
|
+
for (const [key, value] of this.entriesAscending()) callbackFunction.call(thisArgument, value, key, this);
|
|
269
|
+
}
|
|
270
|
+
get [Symbol.toStringTag]() {
|
|
271
|
+
return JSON.stringify([...this.entriesAscending()]);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region ../../node_modules/.pnpm/camelcase-keys@9.1.3/node_modules/camelcase-keys/index.js
|
|
276
|
+
const has = (array, key) => array.some((element) => {
|
|
277
|
+
if (typeof element === "string") return element === key;
|
|
278
|
+
element.lastIndex = 0;
|
|
279
|
+
return element.test(key);
|
|
280
|
+
});
|
|
281
|
+
const cache = new QuickLRU({ maxSize: 1e5 });
|
|
282
|
+
const isObject = (value) => typeof value === "object" && value !== null && !(value instanceof RegExp) && !(value instanceof Error) && !(value instanceof Date);
|
|
283
|
+
const transform = (input, options = {}) => {
|
|
284
|
+
if (!isObject(input)) return input;
|
|
285
|
+
const { exclude, pascalCase = false, stopPaths, deep = false, preserveConsecutiveUppercase = false } = options;
|
|
286
|
+
const stopPathsSet = new Set(stopPaths);
|
|
287
|
+
const makeMapper = (parentPath) => (key, value) => {
|
|
288
|
+
if (deep && isObject(value)) {
|
|
289
|
+
const path = parentPath === void 0 ? key : `${parentPath}.${key}`;
|
|
290
|
+
if (!stopPathsSet.has(path)) value = mapObject(value, makeMapper(path));
|
|
291
|
+
}
|
|
292
|
+
if (!(exclude && has(exclude, key))) {
|
|
293
|
+
const cacheKey = pascalCase ? `${key}_` : key;
|
|
294
|
+
if (cache.has(cacheKey)) key = cache.get(cacheKey);
|
|
295
|
+
else {
|
|
296
|
+
const returnValue = camelCase(key, {
|
|
297
|
+
pascalCase,
|
|
298
|
+
locale: false,
|
|
299
|
+
preserveConsecutiveUppercase
|
|
300
|
+
});
|
|
301
|
+
if (key.length < 100) cache.set(cacheKey, returnValue);
|
|
302
|
+
key = returnValue;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return [key, value];
|
|
306
|
+
};
|
|
307
|
+
return mapObject(input, makeMapper(void 0));
|
|
308
|
+
};
|
|
309
|
+
function camelcaseKeys(input, options) {
|
|
310
|
+
if (Array.isArray(input)) return Object.keys(input).map((key) => transform(input[key], options));
|
|
311
|
+
return transform(input, options);
|
|
312
|
+
}
|
|
313
|
+
//#endregion
|
|
314
|
+
//#region src/getUpdateInfo.ts
|
|
315
|
+
const appVersionStrategy = async (supabase, { platform, appVersion, bundleId, minBundleId = NIL_UUID, channel = "production", cohort }) => {
|
|
316
|
+
const { data: appVersionList, error: appVersionListError } = await supabase.rpc("get_target_app_version_list", {
|
|
317
|
+
app_platform: platform,
|
|
318
|
+
min_bundle_id: minBundleId
|
|
319
|
+
});
|
|
320
|
+
if (appVersionListError) throw appVersionListError;
|
|
321
|
+
const targetAppVersionList = filterCompatibleAppVersions((appVersionList ?? []).map((group) => group.target_app_version), appVersion);
|
|
322
|
+
const { data, error } = await supabase.rpc("get_update_info_by_app_version", {
|
|
323
|
+
app_platform: platform,
|
|
324
|
+
app_version: appVersion,
|
|
325
|
+
bundle_id: bundleId,
|
|
326
|
+
min_bundle_id: minBundleId,
|
|
327
|
+
target_channel: channel,
|
|
328
|
+
target_app_version_list: targetAppVersionList,
|
|
329
|
+
cohort: cohort ?? null
|
|
330
|
+
});
|
|
331
|
+
if (error) throw error;
|
|
332
|
+
const row = data?.[0];
|
|
333
|
+
return row ? camelcaseKeys(row) : null;
|
|
334
|
+
};
|
|
335
|
+
const fingerprintStrategy = async (supabase, { platform, fingerprintHash, bundleId, minBundleId = NIL_UUID, channel = "production", cohort }) => {
|
|
336
|
+
const { data, error } = await supabase.rpc("get_update_info_by_fingerprint_hash", {
|
|
337
|
+
app_platform: platform,
|
|
338
|
+
bundle_id: bundleId,
|
|
339
|
+
min_bundle_id: minBundleId,
|
|
340
|
+
target_channel: channel,
|
|
341
|
+
target_fingerprint_hash: fingerprintHash,
|
|
342
|
+
cohort: cohort ?? null
|
|
343
|
+
});
|
|
344
|
+
if (error) throw error;
|
|
345
|
+
const row = data?.[0];
|
|
346
|
+
return row ? camelcaseKeys(row) : null;
|
|
347
|
+
};
|
|
348
|
+
const getUpdateInfo = (supabase, args) => {
|
|
349
|
+
if (args._updateStrategy === "appVersion") return appVersionStrategy(supabase, args);
|
|
350
|
+
return fingerprintStrategy(supabase, args);
|
|
351
|
+
};
|
|
352
|
+
//#endregion
|
|
353
|
+
//#region src/supabaseDatabase.ts
|
|
354
|
+
const supabaseDatabase = createDatabasePlugin({
|
|
355
|
+
name: "supabaseDatabase",
|
|
356
|
+
factory: (config) => {
|
|
357
|
+
const supabase = createClient(config.supabaseUrl, config.supabaseAnonKey);
|
|
358
|
+
return {
|
|
359
|
+
async getUpdateInfo(args) {
|
|
360
|
+
return getUpdateInfo(supabase, args);
|
|
361
|
+
},
|
|
362
|
+
async getBundleById(bundleId) {
|
|
363
|
+
const { data, error } = await supabase.from("bundles").select("channel, enabled, should_force_update, file_hash, git_commit_hash, id, message, platform, target_app_version, fingerprint_hash, storage_uri, metadata, rollout_cohort_count, target_cohorts").eq("id", bundleId).single();
|
|
364
|
+
if (!data || error) return null;
|
|
365
|
+
return {
|
|
366
|
+
channel: data.channel,
|
|
367
|
+
enabled: data.enabled,
|
|
368
|
+
shouldForceUpdate: data.should_force_update,
|
|
369
|
+
fileHash: data.file_hash,
|
|
370
|
+
gitCommitHash: data.git_commit_hash,
|
|
371
|
+
id: data.id,
|
|
372
|
+
message: data.message,
|
|
373
|
+
platform: data.platform,
|
|
374
|
+
targetAppVersion: data.target_app_version,
|
|
375
|
+
fingerprintHash: data.fingerprint_hash,
|
|
376
|
+
storageUri: data.storage_uri,
|
|
377
|
+
metadata: data.metadata ?? {},
|
|
378
|
+
rolloutCohortCount: data.rollout_cohort_count ?? DEFAULT_ROLLOUT_COHORT_COUNT,
|
|
379
|
+
targetCohorts: data.target_cohorts ?? null
|
|
380
|
+
};
|
|
381
|
+
},
|
|
382
|
+
async getBundles(options) {
|
|
383
|
+
const { where, limit, orderBy } = options ?? {};
|
|
384
|
+
const offset = (options && "offset" in options ? options.offset : void 0) ?? 0;
|
|
385
|
+
if (where?.targetAppVersionIn && where.targetAppVersionIn.length === 0 || where?.id?.in && where.id.in.length === 0) return {
|
|
386
|
+
data: [],
|
|
387
|
+
pagination: calculatePagination(0, {
|
|
388
|
+
limit,
|
|
389
|
+
offset
|
|
390
|
+
})
|
|
391
|
+
};
|
|
392
|
+
let countQuery = supabase.from("bundles").select("*", {
|
|
393
|
+
count: "exact",
|
|
394
|
+
head: true
|
|
395
|
+
});
|
|
396
|
+
if (where?.channel) countQuery = countQuery.eq("channel", where.channel);
|
|
397
|
+
if (where?.platform) countQuery = countQuery.eq("platform", where.platform);
|
|
398
|
+
if (where?.enabled !== void 0) countQuery = countQuery.eq("enabled", where.enabled);
|
|
399
|
+
if (where?.fingerprintHash !== void 0) countQuery = where.fingerprintHash === null ? countQuery.is("fingerprint_hash", null) : countQuery.eq("fingerprint_hash", where.fingerprintHash);
|
|
400
|
+
if (where?.targetAppVersion !== void 0) countQuery = where.targetAppVersion === null ? countQuery.is("target_app_version", null) : countQuery.eq("target_app_version", where.targetAppVersion);
|
|
401
|
+
if (where?.targetAppVersionIn) countQuery = countQuery.in("target_app_version", where.targetAppVersionIn);
|
|
402
|
+
if (where?.targetAppVersionNotNull) countQuery = countQuery.not("target_app_version", "is", null);
|
|
403
|
+
if (where?.id?.eq) countQuery = countQuery.eq("id", where.id.eq);
|
|
404
|
+
if (where?.id?.gt) countQuery = countQuery.gt("id", where.id.gt);
|
|
405
|
+
if (where?.id?.gte) countQuery = countQuery.gte("id", where.id.gte);
|
|
406
|
+
if (where?.id?.lt) countQuery = countQuery.lt("id", where.id.lt);
|
|
407
|
+
if (where?.id?.lte) countQuery = countQuery.lte("id", where.id.lte);
|
|
408
|
+
if (where?.id?.in) countQuery = countQuery.in("id", where.id.in);
|
|
409
|
+
const { count: total = 0 } = await countQuery;
|
|
410
|
+
let query = supabase.from("bundles").select("id, channel, enabled, platform, should_force_update, file_hash, git_commit_hash, message, fingerprint_hash, target_app_version, storage_uri, metadata, rollout_cohort_count, target_cohorts").order("id", { ascending: orderBy?.direction === "asc" });
|
|
411
|
+
if (where?.channel) query = query.eq("channel", where.channel);
|
|
412
|
+
if (where?.platform) query = query.eq("platform", where.platform);
|
|
413
|
+
if (where?.enabled !== void 0) query = query.eq("enabled", where.enabled);
|
|
414
|
+
if (where?.fingerprintHash !== void 0) query = where.fingerprintHash === null ? query.is("fingerprint_hash", null) : query.eq("fingerprint_hash", where.fingerprintHash);
|
|
415
|
+
if (where?.targetAppVersion !== void 0) query = where.targetAppVersion === null ? query.is("target_app_version", null) : query.eq("target_app_version", where.targetAppVersion);
|
|
416
|
+
if (where?.targetAppVersionIn) query = query.in("target_app_version", where.targetAppVersionIn);
|
|
417
|
+
if (where?.targetAppVersionNotNull) query = query.not("target_app_version", "is", null);
|
|
418
|
+
if (where?.id?.eq) query = query.eq("id", where.id.eq);
|
|
419
|
+
if (where?.id?.gt) query = query.gt("id", where.id.gt);
|
|
420
|
+
if (where?.id?.gte) query = query.gte("id", where.id.gte);
|
|
421
|
+
if (where?.id?.lt) query = query.lt("id", where.id.lt);
|
|
422
|
+
if (where?.id?.lte) query = query.lte("id", where.id.lte);
|
|
423
|
+
if (where?.id?.in) query = query.in("id", where.id.in);
|
|
424
|
+
if (limit) query = query.limit(limit);
|
|
425
|
+
if (offset) query = query.range(offset, offset + (limit || 20) - 1);
|
|
426
|
+
const { data } = await query;
|
|
427
|
+
return {
|
|
428
|
+
data: data ? data.map((bundle) => ({
|
|
429
|
+
channel: bundle.channel,
|
|
430
|
+
enabled: bundle.enabled,
|
|
431
|
+
shouldForceUpdate: bundle.should_force_update,
|
|
432
|
+
fileHash: bundle.file_hash,
|
|
433
|
+
gitCommitHash: bundle.git_commit_hash,
|
|
434
|
+
id: bundle.id,
|
|
435
|
+
message: bundle.message,
|
|
436
|
+
platform: bundle.platform,
|
|
437
|
+
targetAppVersion: bundle.target_app_version,
|
|
438
|
+
fingerprintHash: bundle.fingerprint_hash,
|
|
439
|
+
storageUri: bundle.storage_uri,
|
|
440
|
+
metadata: bundle.metadata ?? {},
|
|
441
|
+
rolloutCohortCount: bundle.rollout_cohort_count ?? DEFAULT_ROLLOUT_COHORT_COUNT,
|
|
442
|
+
targetCohorts: bundle.target_cohorts ?? null
|
|
443
|
+
})) : [],
|
|
444
|
+
pagination: calculatePagination(total ?? 0, {
|
|
445
|
+
limit,
|
|
446
|
+
offset
|
|
447
|
+
})
|
|
448
|
+
};
|
|
449
|
+
},
|
|
450
|
+
async getChannels() {
|
|
451
|
+
const { data, error } = await supabase.rpc("get_channels");
|
|
452
|
+
if (error) throw error;
|
|
453
|
+
return data.map((bundle) => bundle.channel);
|
|
454
|
+
},
|
|
455
|
+
async commitBundle({ changedSets }) {
|
|
456
|
+
if (changedSets.length === 0) return;
|
|
457
|
+
for (const op of changedSets) if (op.operation === "delete") {
|
|
458
|
+
const { error } = await supabase.from("bundles").delete().eq("id", op.data.id);
|
|
459
|
+
if (error) throw new Error(`Failed to delete bundle: ${error.message}`);
|
|
460
|
+
} else if (op.operation === "insert" || op.operation === "update") {
|
|
461
|
+
const bundle = op.data;
|
|
462
|
+
const { error } = await supabase.from("bundles").upsert({
|
|
463
|
+
id: bundle.id,
|
|
464
|
+
channel: bundle.channel,
|
|
465
|
+
enabled: bundle.enabled,
|
|
466
|
+
should_force_update: bundle.shouldForceUpdate,
|
|
467
|
+
file_hash: bundle.fileHash,
|
|
468
|
+
git_commit_hash: bundle.gitCommitHash,
|
|
469
|
+
message: bundle.message,
|
|
470
|
+
platform: bundle.platform,
|
|
471
|
+
target_app_version: bundle.targetAppVersion,
|
|
472
|
+
fingerprint_hash: bundle.fingerprintHash,
|
|
473
|
+
storage_uri: bundle.storageUri,
|
|
474
|
+
metadata: bundle.metadata,
|
|
475
|
+
rollout_cohort_count: bundle.rolloutCohortCount ?? DEFAULT_ROLLOUT_COHORT_COUNT,
|
|
476
|
+
target_cohorts: bundle.targetCohorts ?? null
|
|
477
|
+
}, { onConflict: "id" });
|
|
478
|
+
if (error) throw error;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
//#endregion
|
|
485
|
+
//#region src/supabaseEdgeFunctionDatabase.ts
|
|
486
|
+
const supabaseEdgeFunctionDatabase = (config, hooks) => {
|
|
487
|
+
return supabaseDatabase({
|
|
488
|
+
supabaseUrl: config.supabaseUrl,
|
|
489
|
+
supabaseAnonKey: config.supabaseServiceRoleKey
|
|
490
|
+
}, hooks);
|
|
491
|
+
};
|
|
492
|
+
//#endregion
|
|
493
|
+
//#region src/supabaseEdgeFunctionStorage.ts
|
|
494
|
+
const supabaseEdgeFunctionStorage = (config) => {
|
|
495
|
+
const supabase = createClient(config.supabaseUrl, config.supabaseServiceRoleKey);
|
|
496
|
+
return () => {
|
|
497
|
+
return {
|
|
498
|
+
name: "supabaseEdgeFunctionStorage",
|
|
499
|
+
supportedProtocol: "supabase-storage",
|
|
500
|
+
async upload() {
|
|
501
|
+
throw new Error("supabaseEdgeFunctionStorage does not support upload() in the edge runtime.");
|
|
502
|
+
},
|
|
503
|
+
async delete(storageUri) {
|
|
504
|
+
const storageUrl = new URL(storageUri);
|
|
505
|
+
if (storageUrl.protocol !== "supabase-storage:") throw new Error("Invalid Supabase storage URI protocol");
|
|
506
|
+
const bucketName = storageUrl.host;
|
|
507
|
+
const key = storageUrl.pathname.replace(/^\/+/, "");
|
|
508
|
+
if (!bucketName || !key) throw new Error("Invalid Supabase storage URI");
|
|
509
|
+
const { error } = await supabase.storage.from(bucketName).remove([key]);
|
|
510
|
+
if (error) throw new Error(`Failed to delete bundle: ${error.message}`);
|
|
511
|
+
},
|
|
512
|
+
async getDownloadUrl(storageUri) {
|
|
513
|
+
const storageUrl = new URL(storageUri);
|
|
514
|
+
if (storageUrl.protocol !== "supabase-storage:") throw new Error("Invalid Supabase storage URI protocol");
|
|
515
|
+
const bucketName = storageUrl.host;
|
|
516
|
+
const key = storageUrl.pathname.replace(/^\/+/, "");
|
|
517
|
+
if (!bucketName || !key) throw new Error("Invalid Supabase storage URI");
|
|
518
|
+
const { data, error } = await supabase.storage.from(bucketName).createSignedUrl(key, config.signedUrlExpiresIn ?? 3600);
|
|
519
|
+
if (error) throw new Error(`Failed to generate download URL: ${error.message}`);
|
|
520
|
+
if (!data?.signedUrl) throw new Error("Failed to generate download URL");
|
|
521
|
+
return { fileUrl: data.signedUrl };
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
};
|
|
525
|
+
};
|
|
526
|
+
//#endregion
|
|
527
|
+
export { supabaseEdgeFunctionDatabase as n, supabaseDatabase as r, supabaseEdgeFunctionStorage as t };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/supabase",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.29.
|
|
4
|
+
"version": "0.29.6",
|
|
5
5
|
"description": "React Native OTA solution for self-hosted",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"@supabase/supabase-js": "^2.76.1",
|
|
48
48
|
"hono": "4.12.9",
|
|
49
49
|
"uuidv7": "^1.0.2",
|
|
50
|
-
"@hot-updater/core": "0.29.
|
|
51
|
-
"@hot-updater/
|
|
52
|
-
"@hot-updater/
|
|
53
|
-
"@hot-updater/server": "0.29.
|
|
50
|
+
"@hot-updater/core": "0.29.6",
|
|
51
|
+
"@hot-updater/cli-tools": "0.29.6",
|
|
52
|
+
"@hot-updater/plugin-core": "0.29.6",
|
|
53
|
+
"@hot-updater/server": "0.29.6"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@electric-sql/pglite": "^0.2.15",
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
"execa": "9.5.2",
|
|
61
61
|
"@types/node": "^20",
|
|
62
62
|
"mime": "^4.0.4",
|
|
63
|
-
"@hot-updater/
|
|
64
|
-
"@hot-updater/
|
|
65
|
-
"@hot-updater/test-utils": "0.29.
|
|
66
|
-
"@hot-updater/
|
|
63
|
+
"@hot-updater/mock": "0.29.6",
|
|
64
|
+
"@hot-updater/postgres": "0.29.6",
|
|
65
|
+
"@hot-updater/test-utils": "0.29.6",
|
|
66
|
+
"@hot-updater/js": "0.29.6"
|
|
67
67
|
},
|
|
68
68
|
"scripts": {
|
|
69
69
|
"build": "tsdown",
|