@hot-updater/cloudflare 1.2.0-rc.12 → 1.2.0-rc.13
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/cloudflare",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.2.0-rc.
|
|
4
|
+
"version": "1.2.0-rc.13",
|
|
5
5
|
"description": "React Native OTA solution for self-hosted",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
@@ -52,11 +52,11 @@
|
|
|
52
52
|
"cloudflare": "4.2.0",
|
|
53
53
|
"hono": "4.12.34",
|
|
54
54
|
"uuidv7": "^1.0.2",
|
|
55
|
-
"@hot-updater/protocol": "1.2.0-rc.
|
|
56
|
-
"@hot-updater/
|
|
57
|
-
"@hot-updater/
|
|
58
|
-
"@hot-updater/storage-s3": "1.2.0-rc.
|
|
59
|
-
"@hot-updater/
|
|
55
|
+
"@hot-updater/protocol": "1.2.0-rc.13",
|
|
56
|
+
"@hot-updater/plugin-core": "1.2.0-rc.13",
|
|
57
|
+
"@hot-updater/server": "1.2.0-rc.13",
|
|
58
|
+
"@hot-updater/storage-s3": "1.2.0-rc.13",
|
|
59
|
+
"@hot-updater/cli-tools": "1.2.0-rc.13"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@aws-sdk/client-s3": "3.1066.0",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"vitest": "4.1.4",
|
|
76
76
|
"wrangler": "^4.69.0",
|
|
77
77
|
"xdg-app-paths": "^8.3.0",
|
|
78
|
-
"@hot-updater/test-utils": "1.2.0-rc.
|
|
78
|
+
"@hot-updater/test-utils": "1.2.0-rc.13"
|
|
79
79
|
},
|
|
80
80
|
"scripts": {
|
|
81
81
|
"build": "tsdown && pnpm build:worker",
|
package/sql/bundles.sql
CHANGED
|
@@ -36,12 +36,14 @@ CREATE UNIQUE INDEX IF NOT EXISTS "channels_name" ON "channels" ("name");
|
|
|
36
36
|
|
|
37
37
|
CREATE TABLE IF NOT EXISTS "bundle_totals" ("platform_key" TEXT NOT NULL, "_shard" INTEGER NOT NULL, "bundles" INTEGER NOT NULL, "_v" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY ("platform_key", "_shard"));
|
|
38
38
|
|
|
39
|
-
CREATE TABLE IF NOT EXISTS "native_builds" ("id" TEXT NOT NULL, "scope_key" TEXT NOT NULL, "platform" TEXT NOT NULL, "channel_id" TEXT NOT NULL, "fingerprint_hash" TEXT, "app_version" TEXT, "min_bundle_id" TEXT NOT NULL, "artifact_kind" TEXT NOT NULL, "artifact_storage_uri" TEXT NOT NULL, "byte_size" INTEGER NOT NULL, "git_commit_hash" TEXT, "created_at_ms" INTEGER NOT NULL, "build_key" TEXT, "build_number" TEXT, "submitted_to" TEXT, "submitted_at_ms" INTEGER, "submitted_version" TEXT, "_v" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY ("id"));
|
|
39
|
+
CREATE TABLE IF NOT EXISTS "native_builds" ("id" TEXT NOT NULL, "scope_key" TEXT NOT NULL, "platform" TEXT NOT NULL, "channel_id" TEXT NOT NULL, "fingerprint_hash" TEXT, "app_version" TEXT, "min_bundle_id" TEXT NOT NULL, "artifact_kind" TEXT NOT NULL, "artifact_storage_uri" TEXT NOT NULL, "byte_size" INTEGER NOT NULL, "git_commit_hash" TEXT, "created_at_ms" INTEGER NOT NULL, "build_key" TEXT, "build_number" TEXT, "submitted_to" TEXT, "submitted_at_ms" INTEGER, "submitted_version" TEXT, "store_build" INTEGER, "_v" INTEGER NOT NULL DEFAULT 0, PRIMARY KEY ("id"));
|
|
40
40
|
|
|
41
41
|
CREATE INDEX IF NOT EXISTS "native_builds_byScope" ON "native_builds" ("scope_key", "id");
|
|
42
42
|
|
|
43
43
|
CREATE INDEX IF NOT EXISTS "native_builds_byBuildKey" ON "native_builds" ("scope_key", "build_key", "id");
|
|
44
44
|
|
|
45
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "native_builds_byStoreBuild" ON "native_builds" ("scope_key", "store_build");
|
|
46
|
+
|
|
45
47
|
CREATE INDEX IF NOT EXISTS "native_builds_byChannel" ON "native_builds" ("channel_id", "id");
|
|
46
48
|
|
|
47
49
|
CREATE UNIQUE INDEX IF NOT EXISTS "native_builds_min_bundle_id" ON "native_builds" ("min_bundle_id");
|
package/worker/dist/README.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
This folder contains the built output assets for the worker "hot-updater" generated at 2026-
|
|
1
|
+
This folder contains the built output assets for the worker "hot-updater" generated at 2026-11-03T07:59:35.818Z.
|
package/worker/dist/index.js
CHANGED
|
@@ -2600,6 +2600,10 @@ var nativeBuilds = defineTable({
|
|
|
2600
2600
|
type: "string",
|
|
2601
2601
|
maxLength: 255,
|
|
2602
2602
|
required: false
|
|
2603
|
+
},
|
|
2604
|
+
store_build: {
|
|
2605
|
+
type: "boolean",
|
|
2606
|
+
required: false
|
|
2603
2607
|
}
|
|
2604
2608
|
}, {
|
|
2605
2609
|
key: ["id"],
|
|
@@ -2612,6 +2616,11 @@ var nativeBuilds = defineTable({
|
|
|
2612
2616
|
eq: ["scope_key", "build_key"],
|
|
2613
2617
|
sort: ["id"]
|
|
2614
2618
|
},
|
|
2619
|
+
byStoreBuild: {
|
|
2620
|
+
eq: ["scope_key", "store_build"],
|
|
2621
|
+
sort: [],
|
|
2622
|
+
unique: true
|
|
2623
|
+
},
|
|
2615
2624
|
byChannel: {
|
|
2616
2625
|
eq: ["channel_id"],
|
|
2617
2626
|
sort: ["id"],
|
|
@@ -2813,10 +2822,7 @@ var LOG_TABLES = [
|
|
|
2813
2822
|
var LEASE_TABLE = "aggregate_lease";
|
|
2814
2823
|
var LEASE = { id: "compaction" };
|
|
2815
2824
|
var LEASE_MS = 3e4;
|
|
2816
|
-
var WINDOW_MS =
|
|
2817
|
-
log: 6e4,
|
|
2818
|
-
memory: 15e3
|
|
2819
|
-
};
|
|
2825
|
+
var WINDOW_MS = 6e4;
|
|
2820
2826
|
var LOG_PAGE = 200;
|
|
2821
2827
|
var GROUPS = {
|
|
2822
2828
|
commit: 1,
|
|
@@ -2824,7 +2830,6 @@ var GROUPS = {
|
|
|
2824
2830
|
flush: 256
|
|
2825
2831
|
};
|
|
2826
2832
|
var ATTEMPTS = 5;
|
|
2827
|
-
var MAX_BUFFERED = 1e4;
|
|
2828
2833
|
var log = defineTable({
|
|
2829
2834
|
id: {
|
|
2830
2835
|
type: "string",
|
|
@@ -2926,8 +2931,8 @@ var rewrite2 = /* @__PURE__ */ __name((change, key, current) => {
|
|
|
2926
2931
|
previous: current
|
|
2927
2932
|
};
|
|
2928
2933
|
}, "rewrite");
|
|
2929
|
-
var compile = /* @__PURE__ */ __name(async (adapter, changes
|
|
2930
|
-
const keys = changes.map(({
|
|
2934
|
+
var compile = /* @__PURE__ */ __name(async (adapter, changes) => {
|
|
2935
|
+
const keys = changes.map(({ key }) => [...key.slice(0, -1), 0]);
|
|
2931
2936
|
const reads = /* @__PURE__ */ new Map();
|
|
2932
2937
|
changes.forEach((change, at) => {
|
|
2933
2938
|
if (rewrites(change)) reads.set(change.model, [...reads.get(change.model) ?? [], at]);
|
|
@@ -2973,7 +2978,7 @@ var encode2 = /* @__PURE__ */ __name(async (changes) => {
|
|
|
2973
2978
|
const zipped = await deflate(json4);
|
|
2974
2979
|
return zipped !== void 0 && zipped.length < json4.length ? `z${zipped}` : json4;
|
|
2975
2980
|
}, "encode");
|
|
2976
|
-
var createAggregateBatches = /* @__PURE__ */ __name(({ engine, adapter, schema, batching: {
|
|
2981
|
+
var createAggregateBatches = /* @__PURE__ */ __name(({ engine, adapter, schema, batching: { windowMs = WINDOW_MS }, now }) => {
|
|
2977
2982
|
if (!schema.models.has(LEASE_TABLE)) throw new DatabaseTransactionError("An engine that batches aggregates needs aggregateBatchingModule in its schema.");
|
|
2978
2983
|
const holder = crypto.randomUUID().replaceAll("-", "");
|
|
2979
2984
|
const table = /* @__PURE__ */ __name((name) => schema.models.get(name).table, "table");
|
|
@@ -3000,61 +3005,6 @@ var createAggregateBatches = /* @__PURE__ */ __name(({ engine, adapter, schema,
|
|
|
3000
3005
|
}
|
|
3001
3006
|
return changes;
|
|
3002
3007
|
}, "decode");
|
|
3003
|
-
const apply = /* @__PURE__ */ __name(async (changes, shard) => {
|
|
3004
|
-
let rest = changes;
|
|
3005
|
-
let ops = [];
|
|
3006
|
-
let read = true;
|
|
3007
|
-
for (let failures = 0; rest.length > 0 && failures < ATTEMPTS; ) try {
|
|
3008
|
-
if (read) ops = await compile(adapter, rest, shard);
|
|
3009
|
-
let size = rest.length;
|
|
3010
|
-
const chunk = /* @__PURE__ */ __name(() => ops.slice(0, size).filter(isOp), "chunk");
|
|
3011
|
-
while (size > 1 && !adapter.fits(chunk())) size = Math.ceil(size / 2);
|
|
3012
|
-
let result = { ok: true };
|
|
3013
|
-
if (chunk().length > 0) result = await adapter.write(chunk()).catch((error) => {
|
|
3014
|
-
warn("flush")(error);
|
|
3015
|
-
return { ok: true };
|
|
3016
|
-
});
|
|
3017
|
-
read = !result.ok && !("retry" in result);
|
|
3018
|
-
if (result.ok) {
|
|
3019
|
-
rest = rest.slice(size);
|
|
3020
|
-
ops = ops.slice(size);
|
|
3021
|
-
failures = 0;
|
|
3022
|
-
} else {
|
|
3023
|
-
failures += 1;
|
|
3024
|
-
if (!read) await sleep(failures);
|
|
3025
|
-
}
|
|
3026
|
-
} catch (error) {
|
|
3027
|
-
warn("flush")(error);
|
|
3028
|
-
return rest;
|
|
3029
|
-
}
|
|
3030
|
-
return rest;
|
|
3031
|
-
}, "apply");
|
|
3032
|
-
let buffer = /* @__PURE__ */ new Map();
|
|
3033
|
-
let timer;
|
|
3034
|
-
let flushing;
|
|
3035
|
-
const shards = /* @__PURE__ */ new Map();
|
|
3036
|
-
const processShard = /* @__PURE__ */ __name((model) => {
|
|
3037
|
-
if (!shards.has(model)) shards.set(model, Math.floor(Math.random() * shapeOf(model).shards));
|
|
3038
|
-
return shards.get(model);
|
|
3039
|
-
}, "processShard");
|
|
3040
|
-
const schedule = /* @__PURE__ */ __name(() => {
|
|
3041
|
-
if (timer !== void 0 || buffer.size === 0) return;
|
|
3042
|
-
timer = setTimeout(() => {
|
|
3043
|
-
timer = void 0;
|
|
3044
|
-
flushBuffer();
|
|
3045
|
-
}, windowMs);
|
|
3046
|
-
timer.unref?.();
|
|
3047
|
-
}, "schedule");
|
|
3048
|
-
const flushBuffer = /* @__PURE__ */ __name(() => flushing ??= (async () => {
|
|
3049
|
-
clearTimeout(timer);
|
|
3050
|
-
timer = void 0;
|
|
3051
|
-
const pending = [...buffer.values()];
|
|
3052
|
-
buffer = /* @__PURE__ */ new Map();
|
|
3053
|
-
mergeAll(buffer, await apply(pending, processShard));
|
|
3054
|
-
})().catch(warn("flush")).finally(() => {
|
|
3055
|
-
flushing = void 0;
|
|
3056
|
-
schedule();
|
|
3057
|
-
}), "flushBuffer");
|
|
3058
3008
|
let nextDue = 0;
|
|
3059
3009
|
let compacting;
|
|
3060
3010
|
const known = /* @__PURE__ */ new Map();
|
|
@@ -3176,7 +3126,7 @@ var createAggregateBatches = /* @__PURE__ */ __name(({ engine, adapter, schema,
|
|
|
3176
3126
|
more
|
|
3177
3127
|
};
|
|
3178
3128
|
}, "readLogs");
|
|
3179
|
-
const rowsFor = /* @__PURE__ */ __name(async (changes) => (await compile(adapter, changes
|
|
3129
|
+
const rowsFor = /* @__PURE__ */ __name(async (changes) => (await compile(adapter, changes)).filter(isOp), "rowsFor");
|
|
3180
3130
|
const applyGroup = /* @__PURE__ */ __name(async (held, logs) => {
|
|
3181
3131
|
for (let count = logs.length; count > 0; count = Math.floor(count / 2)) {
|
|
3182
3132
|
const batch = logs.slice(0, count);
|
|
@@ -3256,19 +3206,6 @@ var createAggregateBatches = /* @__PURE__ */ __name(({ engine, adapter, schema,
|
|
|
3256
3206
|
}))).then((pages) => pages.some((page2) => page2.rows.length > 0)).finally(() => {
|
|
3257
3207
|
checking = void 0;
|
|
3258
3208
|
}), "hasPending");
|
|
3259
|
-
const committed = /* @__PURE__ */ __name(async (changes) => {
|
|
3260
|
-
if (mode === "log") {
|
|
3261
|
-
if (now() >= nextDue) await compact(false, GROUPS.commit);
|
|
3262
|
-
return;
|
|
3263
|
-
}
|
|
3264
|
-
mergeAll(buffer, changes.values());
|
|
3265
|
-
schedule();
|
|
3266
|
-
if (buffer.size >= MAX_BUFFERED) await flushBuffer();
|
|
3267
|
-
}, "committed");
|
|
3268
|
-
const flush = /* @__PURE__ */ __name(async () => {
|
|
3269
|
-
await flushBuffer();
|
|
3270
|
-
if (mode === "log" && await hasPending()) await compact(true, GROUPS.flush);
|
|
3271
|
-
}, "flush");
|
|
3272
3209
|
return {
|
|
3273
3210
|
async transaction(fn) {
|
|
3274
3211
|
let changes = /* @__PURE__ */ new Map();
|
|
@@ -3294,7 +3231,7 @@ var createAggregateBatches = /* @__PURE__ */ __name(({ engine, adapter, schema,
|
|
|
3294
3231
|
aggregate
|
|
3295
3232
|
});
|
|
3296
3233
|
if (failure) throw failure.error;
|
|
3297
|
-
if (
|
|
3234
|
+
if (attempt.size > 0) {
|
|
3298
3235
|
const id = `${now().toString(36).padStart(9, "0")}${holder.slice(0, 8)}${crypto.randomUUID().slice(0, 8)}`;
|
|
3299
3236
|
const shard = Math.floor(Math.random() * LOG_TABLES.length);
|
|
3300
3237
|
const merged = mergeAll(/* @__PURE__ */ new Map(), attempt.values());
|
|
@@ -3308,24 +3245,18 @@ var createAggregateBatches = /* @__PURE__ */ __name(({ engine, adapter, schema,
|
|
|
3308
3245
|
open = false;
|
|
3309
3246
|
}
|
|
3310
3247
|
});
|
|
3311
|
-
if (changes.size > 0) await
|
|
3248
|
+
if (changes.size > 0 && now() >= nextDue) await compact(false, GROUPS.commit);
|
|
3312
3249
|
return result;
|
|
3313
3250
|
},
|
|
3314
3251
|
async beforeRead(name) {
|
|
3315
3252
|
if (!isBatched(schema.models.get(name))) return;
|
|
3316
|
-
if (
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
return false;
|
|
3321
|
-
})) await compact(true, GROUPS.read);
|
|
3322
|
-
}
|
|
3253
|
+
if (await hasPending().catch((error) => {
|
|
3254
|
+
warn("read")(error);
|
|
3255
|
+
return false;
|
|
3256
|
+
})) await compact(true, GROUPS.read);
|
|
3323
3257
|
},
|
|
3324
|
-
flush
|
|
3325
|
-
|
|
3326
|
-
clearTimeout(timer);
|
|
3327
|
-
timer = void 0;
|
|
3328
|
-
await flush();
|
|
3258
|
+
async flush() {
|
|
3259
|
+
if (await hasPending()) await compact(true, GROUPS.flush);
|
|
3329
3260
|
}
|
|
3330
3261
|
};
|
|
3331
3262
|
}, "createAggregateBatches");
|
|
@@ -4294,13 +4225,10 @@ var createDatabaseEngine = /* @__PURE__ */ __name(({ batching, now = Date.now, m
|
|
|
4294
4225
|
}, "barePage");
|
|
4295
4226
|
return {
|
|
4296
4227
|
...engine,
|
|
4297
|
-
/** Applies batched aggregate changes still
|
|
4228
|
+
/** Applies the batched aggregate changes still in the log. */
|
|
4298
4229
|
flush: /* @__PURE__ */ __name(async () => {
|
|
4299
4230
|
await batches?.flush();
|
|
4300
4231
|
}, "flush"),
|
|
4301
|
-
dispose: /* @__PURE__ */ __name(async () => {
|
|
4302
|
-
await batches?.dispose();
|
|
4303
|
-
}, "dispose"),
|
|
4304
4232
|
database(module) {
|
|
4305
4233
|
const name = /* @__PURE__ */ __name((model) => module.namespace ? `${module.namespace}_${model}` : model, "name");
|
|
4306
4234
|
return {
|
|
@@ -4368,8 +4296,7 @@ var createEngine = /* @__PURE__ */ __name((database, { plugins = [], now = Date.
|
|
|
4368
4296
|
if (module === void 0) throw new HotUpdaterConfigError(`Plugin "${plugin.id}" is not one of this engine's plugins.`);
|
|
4369
4297
|
return engine.database(module);
|
|
4370
4298
|
}, "database"),
|
|
4371
|
-
flush: /* @__PURE__ */ __name(() => engine.flush(), "flush")
|
|
4372
|
-
dispose: /* @__PURE__ */ __name(() => engine.dispose(), "dispose")
|
|
4299
|
+
flush: /* @__PURE__ */ __name(() => engine.flush(), "flush")
|
|
4373
4300
|
};
|
|
4374
4301
|
}, "createEngine");
|
|
4375
4302
|
|
|
@@ -4632,7 +4559,7 @@ var createSqlAdapter = /* @__PURE__ */ __name(({ executor, tablePrefix = "", max
|
|
|
4632
4559
|
}, "createSqlAdapter");
|
|
4633
4560
|
|
|
4634
4561
|
// ../../packages/server/dist/package.mjs
|
|
4635
|
-
var version = "1.2.0-rc.
|
|
4562
|
+
var version = "1.2.0-rc.13";
|
|
4636
4563
|
|
|
4637
4564
|
// ../../packages/server/dist/version.mjs
|
|
4638
4565
|
var HOT_UPDATER_SERVER_VERSION = version;
|
|
@@ -5807,8 +5734,12 @@ var pick2 = /* @__PURE__ */ __name((row) => ({
|
|
|
5807
5734
|
build_number: row.build_number ?? null,
|
|
5808
5735
|
submitted_to: row.submitted_to ?? null,
|
|
5809
5736
|
submitted_at_ms: row.submitted_at_ms ?? null,
|
|
5810
|
-
submitted_version: row.submitted_version ?? null
|
|
5737
|
+
submitted_version: row.submitted_version ?? null,
|
|
5738
|
+
store_build: row.store_build === true ? true : null
|
|
5811
5739
|
}), "pick");
|
|
5740
|
+
var SANDBOX_CHANNEL_PREFIX = "sandbox-";
|
|
5741
|
+
var OLDER_BUILDS_PAGE = 20;
|
|
5742
|
+
var MARK_ATTEMPTS = 8;
|
|
5812
5743
|
var SUBMISSION_DESTINATIONS = {
|
|
5813
5744
|
android: "play-internal",
|
|
5814
5745
|
ios: "testflight"
|
|
@@ -5874,7 +5805,8 @@ var createNativeBuildApi = /* @__PURE__ */ __name((db, { now = Date.now } = {})
|
|
|
5874
5805
|
build_number: registration.buildNumber ?? null,
|
|
5875
5806
|
submitted_to: null,
|
|
5876
5807
|
submitted_at_ms: null,
|
|
5877
|
-
submitted_version: null
|
|
5808
|
+
submitted_version: null,
|
|
5809
|
+
store_build: null
|
|
5878
5810
|
};
|
|
5879
5811
|
for (let attempt = 1; ; attempt += 1) {
|
|
5880
5812
|
await insertChannel(db, {
|
|
@@ -5912,21 +5844,45 @@ var createNativeBuildApi = /* @__PURE__ */ __name((db, { now = Date.now } = {})
|
|
|
5912
5844
|
const scopeKey = nativeBuildScopeKey(scope);
|
|
5913
5845
|
const buildKey = options?.buildKey;
|
|
5914
5846
|
if (buildKey !== void 0 && !BUILD_KEY.test(buildKey)) throw new NativeBuildInputError("Invalid native build key: it must be nbk1: and a SHA-256.");
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
where: { scope_key: scopeKey },
|
|
5918
|
-
order: "desc",
|
|
5919
|
-
limit: 1
|
|
5920
|
-
}) : await db.findMany("native_builds", {
|
|
5921
|
-
index: "byBuildKey",
|
|
5922
|
-
where: {
|
|
5847
|
+
if (options?.storeBuild) {
|
|
5848
|
+
const marked = await db.findOne("native_builds", {
|
|
5923
5849
|
scope_key: scopeKey,
|
|
5924
|
-
|
|
5925
|
-
}
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5850
|
+
store_build: true
|
|
5851
|
+
});
|
|
5852
|
+
return marked === null ? null : pick2(marked);
|
|
5853
|
+
}
|
|
5854
|
+
const read = /* @__PURE__ */ __name((limit, before) => {
|
|
5855
|
+
const page2 = {
|
|
5856
|
+
order: "desc",
|
|
5857
|
+
limit,
|
|
5858
|
+
...before === void 0 ? {} : { range: { lt: before } }
|
|
5859
|
+
};
|
|
5860
|
+
return buildKey === void 0 ? db.findMany("native_builds", {
|
|
5861
|
+
index: "byScope",
|
|
5862
|
+
where: { scope_key: scopeKey },
|
|
5863
|
+
...page2
|
|
5864
|
+
}) : db.findMany("native_builds", {
|
|
5865
|
+
index: "byBuildKey",
|
|
5866
|
+
where: {
|
|
5867
|
+
scope_key: scopeKey,
|
|
5868
|
+
build_key: buildKey
|
|
5869
|
+
},
|
|
5870
|
+
...page2
|
|
5871
|
+
});
|
|
5872
|
+
}, "read");
|
|
5873
|
+
const { rows } = await read(1);
|
|
5874
|
+
const newest = rows[0];
|
|
5875
|
+
if (newest === void 0) return null;
|
|
5876
|
+
const bundleId = options?.builtInOlderThan;
|
|
5877
|
+
if (bundleId === void 0 || newest.min_bundle_id < bundleId) return pick2(newest);
|
|
5878
|
+
for (let before = newest.id; ; ) {
|
|
5879
|
+
const { rows: older } = await read(OLDER_BUILDS_PAGE, before);
|
|
5880
|
+
const usable = older.find(({ min_bundle_id }) => min_bundle_id < bundleId);
|
|
5881
|
+
if (usable !== void 0) return pick2(usable);
|
|
5882
|
+
const last = older.at(-1);
|
|
5883
|
+
if (older.length < OLDER_BUILDS_PAGE || last === void 0) return null;
|
|
5884
|
+
before = last.id;
|
|
5885
|
+
}
|
|
5930
5886
|
},
|
|
5931
5887
|
async recordNativeBuildSubmission(id, { destination, version: version2 }) {
|
|
5932
5888
|
if (version2.trim().length === 0 || version2.length > SUBMITTED_VERSION_MAX_LENGTH) throw new NativeBuildInputError(`Invalid native build submission: version must be the store's label of the build, up to ${SUBMITTED_VERSION_MAX_LENGTH} characters.`);
|
|
@@ -5947,6 +5903,49 @@ var createNativeBuildApi = /* @__PURE__ */ __name((db, { now = Date.now } = {})
|
|
|
5947
5903
|
};
|
|
5948
5904
|
});
|
|
5949
5905
|
},
|
|
5906
|
+
async markNativeBuild(id, { storeBuild }) {
|
|
5907
|
+
for (let attempt = 1; ; attempt += 1) try {
|
|
5908
|
+
return await db.transaction(async (tx) => {
|
|
5909
|
+
const row = await tx.findOne("native_builds", { id });
|
|
5910
|
+
if (row === null) return null;
|
|
5911
|
+
const build = pick2(row);
|
|
5912
|
+
if (!storeBuild) {
|
|
5913
|
+
if (build.store_build !== null) tx.update("native_builds", row, { store_build: null });
|
|
5914
|
+
return {
|
|
5915
|
+
nativeBuild: {
|
|
5916
|
+
...build,
|
|
5917
|
+
store_build: null
|
|
5918
|
+
},
|
|
5919
|
+
previous: null
|
|
5920
|
+
};
|
|
5921
|
+
}
|
|
5922
|
+
if (decodeChannelKey(build.channel_id.slice(8)).startsWith(SANDBOX_CHANNEL_PREFIX)) throw new NativeBuildInputError("A build on a sandbox channel can't be the store build.");
|
|
5923
|
+
if (build.store_build !== null) return {
|
|
5924
|
+
nativeBuild: build,
|
|
5925
|
+
previous: null
|
|
5926
|
+
};
|
|
5927
|
+
const holder = await tx.findOne("native_builds", {
|
|
5928
|
+
scope_key: build.scope_key,
|
|
5929
|
+
store_build: true
|
|
5930
|
+
});
|
|
5931
|
+
if (holder !== null) tx.update("native_builds", holder, { store_build: null });
|
|
5932
|
+
tx.update("native_builds", row, { store_build: true });
|
|
5933
|
+
return {
|
|
5934
|
+
nativeBuild: {
|
|
5935
|
+
...build,
|
|
5936
|
+
store_build: true
|
|
5937
|
+
},
|
|
5938
|
+
previous: holder === null ? null : {
|
|
5939
|
+
...pick2(holder),
|
|
5940
|
+
store_build: null
|
|
5941
|
+
}
|
|
5942
|
+
};
|
|
5943
|
+
});
|
|
5944
|
+
} catch (error) {
|
|
5945
|
+
if (attempt < MARK_ATTEMPTS && error instanceof DatabaseConstraintError && error.reason === "unique") continue;
|
|
5946
|
+
throw error;
|
|
5947
|
+
}
|
|
5948
|
+
},
|
|
5950
5949
|
async deleteNativeBuild(id) {
|
|
5951
5950
|
return db.transaction(async (tx) => {
|
|
5952
5951
|
const row = await tx.findOne("native_builds", { id });
|
|
@@ -6984,7 +6983,13 @@ var createAdminRouteHandlers = /* @__PURE__ */ __name(() => ({
|
|
|
6984
6983
|
const url = new URL(request.url);
|
|
6985
6984
|
const scope = nativeBuildScopeOf(url);
|
|
6986
6985
|
const buildKey = url.searchParams.get("buildKey");
|
|
6987
|
-
|
|
6986
|
+
const builtInOlderThan = url.searchParams.get("builtInOlderThan");
|
|
6987
|
+
const options = {
|
|
6988
|
+
...buildKey === null ? {} : { buildKey },
|
|
6989
|
+
...url.searchParams.get("storeBuild") === "true" ? { storeBuild: true } : {},
|
|
6990
|
+
...builtInOlderThan === null ? {} : { builtInOlderThan }
|
|
6991
|
+
};
|
|
6992
|
+
return json({ data: await refusingInvalid(() => Object.keys(options).length === 0 ? core.findNativeBuild(scope) : core.findNativeBuild(scope, options)) });
|
|
6988
6993
|
}),
|
|
6989
6994
|
getNativeBuild: onCore(async (core, _request, params) => json({ data: await core.getNativeBuild(requireRouteParam(params, "id")) })),
|
|
6990
6995
|
listNativeBuilds: onCore(async (core, request) => {
|
|
@@ -7005,6 +7010,12 @@ var createAdminRouteHandlers = /* @__PURE__ */ __name(() => ({
|
|
|
7005
7010
|
};
|
|
7006
7011
|
return json({ data: await refusingInvalid(() => core.recordNativeBuildSubmission(requireRouteParam(params, "id"), submission)) });
|
|
7007
7012
|
}),
|
|
7013
|
+
markNativeBuild: onCore(async (core, request, params) => {
|
|
7014
|
+
const input = await body(request);
|
|
7015
|
+
if (!isRecord3(input) || typeof input.storeBuild !== "boolean") throw new HandlerBadRequestError("A native build's store build mark needs storeBuild, true or false.");
|
|
7016
|
+
const mark = { storeBuild: input.storeBuild };
|
|
7017
|
+
return json({ data: await refusingInvalid(() => core.markNativeBuild(requireRouteParam(params, "id"), mark)) });
|
|
7018
|
+
}),
|
|
7008
7019
|
deleteNativeBuild: onCore(async (core, _request, params) => json({ data: await core.deleteNativeBuild(requireRouteParam(params, "id")) })),
|
|
7009
7020
|
deleteBundles: onCore(async (core, request) => {
|
|
7010
7021
|
const { ids } = await body(request);
|
|
@@ -7149,6 +7160,11 @@ var ADMIN_ROUTES = [
|
|
|
7149
7160
|
path: "/native-builds/:id/submission",
|
|
7150
7161
|
handler: "recordNativeBuildSubmission"
|
|
7151
7162
|
},
|
|
7163
|
+
{
|
|
7164
|
+
method: "POST",
|
|
7165
|
+
path: "/native-builds/:id/store-build",
|
|
7166
|
+
handler: "markNativeBuild"
|
|
7167
|
+
},
|
|
7152
7168
|
{
|
|
7153
7169
|
method: "DELETE",
|
|
7154
7170
|
path: "/native-builds/:id",
|