@voltro/plugin-releases 0.84.0 → 0.86.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/CHANGELOG.md +1215 -0
- package/THIRD-PARTY-NOTICES.md +127 -609
- package/dist/artifactMetadata.js +27 -0
- package/dist/errors.d.ts +10 -12
- package/dist/errors.js +5 -1
- package/dist/feeds.js +112 -0
- package/dist/index.d.ts +37 -23
- package/dist/index.js +441 -536
- package/dist/names.js +4 -0
- package/dist/retention.js +13 -0
- package/dist/{rollout-CGRKMTfv.js → rollout.js} +1 -1
- package/dist/rpc.d.ts +162 -132
- package/dist/rpc.js +263 -2
- package/dist/schema.js +85 -0
- package/dist/uploadIdentity.server.js +5 -0
- package/dist/web.js +2 -2
- package/package.json +7 -7
- package/dist/rpc-DeEV8l3U.js +0 -226
package/dist/index.js
CHANGED
|
@@ -1,212 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return i;
|
|
19
|
-
}, k = [
|
|
20
|
-
"web",
|
|
21
|
-
"ios",
|
|
22
|
-
"android",
|
|
23
|
-
"macos",
|
|
24
|
-
"windows",
|
|
25
|
-
"linux"
|
|
26
|
-
], A = [
|
|
27
|
-
"pwa",
|
|
28
|
-
"expo",
|
|
29
|
-
"tauri",
|
|
30
|
-
"electron"
|
|
31
|
-
], j = E(d, {
|
|
32
|
-
id: S({ prefix: "relapp" }),
|
|
33
|
-
app: D(),
|
|
34
|
-
platform: D(),
|
|
35
|
-
shell: D(),
|
|
36
|
-
revision: C().default(0),
|
|
37
|
-
bundleId: D().nullable(),
|
|
38
|
-
updaterPublicKey: D().nullable(),
|
|
39
|
-
runtimeVersion: D().nullable(),
|
|
40
|
-
createdAt: O().default("now")
|
|
41
|
-
}).index("byReleaseAppTarget", [
|
|
42
|
-
"app",
|
|
43
|
-
"platform",
|
|
44
|
-
"shell"
|
|
45
|
-
]), M = E(h, {
|
|
46
|
-
id: S({ prefix: "relch" }),
|
|
47
|
-
appId: D(),
|
|
48
|
-
name: D(),
|
|
49
|
-
currentReleaseId: D().nullable(),
|
|
50
|
-
minSupportedVersion: D().nullable(),
|
|
51
|
-
killSwitches: w().nullable(),
|
|
52
|
-
public: b().default(!1),
|
|
53
|
-
allowUnsigned: b().default(!1),
|
|
54
|
-
updatedAt: O().default("now").onUpdate("now")
|
|
55
|
-
}).index("byReleaseChannelApp", ["appId", "name"]), N = E(f, {
|
|
56
|
-
id: S({ prefix: "rel" }),
|
|
57
|
-
appId: D(),
|
|
58
|
-
channelId: D(),
|
|
59
|
-
version: D(),
|
|
60
|
-
buildId: D().nullable(),
|
|
61
|
-
notes: D().nullable(),
|
|
62
|
-
state: D().default("draft"),
|
|
63
|
-
rolloutPercent: C().default(0),
|
|
64
|
-
rolloutSalt: D(),
|
|
65
|
-
cohorts: w().nullable(),
|
|
66
|
-
createdBy: D().nullable(),
|
|
67
|
-
createdAt: O().default("now"),
|
|
68
|
-
updatedAt: O().default("now").onUpdate("now")
|
|
69
|
-
}).index("byReleaseAppChannel", ["appId", "channelId"]).index("byReleaseVersion", ["appId", "version"]), P = E(l, {
|
|
70
|
-
id: S({ prefix: "relart" }),
|
|
71
|
-
releaseId: D(),
|
|
72
|
-
kind: D(),
|
|
73
|
-
target: D().nullable(),
|
|
74
|
-
url: D(),
|
|
75
|
-
sha256: D(),
|
|
76
|
-
size: C(),
|
|
77
|
-
signature: D().nullable(),
|
|
78
|
-
notarized: b().default(!1),
|
|
79
|
-
assetKey: D().nullable(),
|
|
80
|
-
contentType: D().nullable(),
|
|
81
|
-
createdAt: O().default("now")
|
|
82
|
-
}).index("byReleaseArtifactRelease", ["releaseId"]), F = E(g, {
|
|
83
|
-
id: S({ prefix: "relev" }),
|
|
84
|
-
appId: D(),
|
|
85
|
-
channelId: D().nullable(),
|
|
86
|
-
releaseId: D().nullable(),
|
|
87
|
-
kind: D(),
|
|
88
|
-
reason: D().nullable(),
|
|
89
|
-
actorId: D().nullable(),
|
|
90
|
-
detail: w().nullable(),
|
|
91
|
-
at: O().default("now")
|
|
92
|
-
}).index("byReleaseEventApp", ["appId", "at"]), I = [
|
|
93
|
-
j,
|
|
94
|
-
M,
|
|
95
|
-
N,
|
|
96
|
-
P,
|
|
97
|
-
F
|
|
98
|
-
], L = (e, t) => t.currentVersion !== null && c(e.version, t.currentVersion) <= 0 ? !1 : o({
|
|
99
|
-
installId: t.installId,
|
|
100
|
-
salt: e.rolloutSalt,
|
|
101
|
-
percent: e.rolloutPercent,
|
|
102
|
-
...t.cohorts === void 0 ? {} : { installCohorts: t.cohorts },
|
|
103
|
-
releaseCohorts: e.cohorts
|
|
104
|
-
}), R = (e, t) => {
|
|
105
|
-
if (!L(e, t)) return null;
|
|
106
|
-
let n = e.artifacts.find((e) => e.target === t.target && e.signature !== null);
|
|
107
|
-
return !n || n.signature === null ? null : {
|
|
108
|
-
version: e.version,
|
|
109
|
-
notes: e.notes ?? "",
|
|
110
|
-
pub_date: e.createdAt.toISOString(),
|
|
111
|
-
platforms: { [t.target]: {
|
|
112
|
-
signature: n.signature,
|
|
113
|
-
url: n.url
|
|
114
|
-
} }
|
|
115
|
-
};
|
|
116
|
-
}, z = (e, t, n = {}) => {
|
|
117
|
-
let r = {
|
|
118
|
-
win: [
|
|
119
|
-
"nsis",
|
|
120
|
-
"msi",
|
|
121
|
-
"exe"
|
|
122
|
-
],
|
|
123
|
-
mac: ["dmg", "zip"],
|
|
124
|
-
linux: [
|
|
125
|
-
"appimage",
|
|
126
|
-
"deb",
|
|
127
|
-
"rpm"
|
|
128
|
-
]
|
|
129
|
-
}, i = e.artifacts.filter((e) => r[t].includes(e.kind));
|
|
130
|
-
if (i.length === 0) return null;
|
|
131
|
-
let a = [`version: ${e.version}`, "files:"];
|
|
132
|
-
for (let e of i) {
|
|
133
|
-
a.push(` - url: ${e.url}`);
|
|
134
|
-
let t = n[e.sha256];
|
|
135
|
-
a.push(t === void 0 ? ` sha256: ${e.sha256}` : ` sha512: ${t}`), a.push(` size: ${e.size}`);
|
|
136
|
-
}
|
|
137
|
-
let o = i[0];
|
|
138
|
-
a.push(`path: ${o.url}`);
|
|
139
|
-
let s = n[o.sha256];
|
|
140
|
-
return a.push(s === void 0 ? `sha256: ${o.sha256}` : `sha512: ${s}`), a.push(`releaseDate: '${e.createdAt.toISOString()}'`), e.notes && a.push(`releaseNotes: ${JSON.stringify(e.notes)}`), a.join("\n") + "\n";
|
|
141
|
-
}, B = (e, t, n) => {
|
|
142
|
-
if (n.rolledBackTo !== null) return {
|
|
143
|
-
kind: "rollback",
|
|
144
|
-
commitTime: n.rolledBackTo.commitTime.toISOString()
|
|
145
|
-
};
|
|
146
|
-
if (e === null || n.runtimeVersion !== null && n.runtimeVersion !== t.runtimeVersion) return { kind: "no-update" };
|
|
147
|
-
let r = e.buildId ?? e.id;
|
|
148
|
-
if (t.currentUpdateId === r || !L(e, {
|
|
149
|
-
installId: t.installId,
|
|
150
|
-
currentVersion: null,
|
|
151
|
-
...t.cohorts === void 0 ? {} : { cohorts: t.cohorts }
|
|
152
|
-
})) return { kind: "no-update" };
|
|
153
|
-
let i = e.artifacts.find((e) => e.kind === "expo-bundle" && e.target === t.platform);
|
|
154
|
-
if (!i) return { kind: "no-update" };
|
|
155
|
-
let a = e.artifacts.filter((e) => e.kind === "expo-asset" && (e.target === null || e.target === t.platform)).map((e) => ({
|
|
156
|
-
hash: e.sha256,
|
|
157
|
-
key: e.assetKey ?? e.sha256,
|
|
158
|
-
contentType: e.contentType ?? "application/octet-stream",
|
|
159
|
-
url: e.url
|
|
160
|
-
}));
|
|
161
|
-
return {
|
|
162
|
-
kind: "manifest",
|
|
163
|
-
manifest: {
|
|
164
|
-
id: r,
|
|
165
|
-
createdAt: e.createdAt.toISOString(),
|
|
166
|
-
runtimeVersion: t.runtimeVersion,
|
|
167
|
-
launchAsset: {
|
|
168
|
-
hash: i.sha256,
|
|
169
|
-
key: i.assetKey ?? "bundle",
|
|
170
|
-
contentType: i.contentType ?? "application/javascript",
|
|
171
|
-
url: i.url
|
|
172
|
-
},
|
|
173
|
-
assets: a,
|
|
174
|
-
metadata: {},
|
|
175
|
-
extra: {
|
|
176
|
-
version: e.version,
|
|
177
|
-
...e.notes ? { notes: e.notes } : {}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
}, V = {
|
|
182
|
-
macos: ["dmg", "zip"],
|
|
183
|
-
windows: [
|
|
184
|
-
"nsis",
|
|
185
|
-
"msi",
|
|
186
|
-
"exe"
|
|
187
|
-
],
|
|
188
|
-
linux: [
|
|
189
|
-
"appimage",
|
|
190
|
-
"deb",
|
|
191
|
-
"rpm"
|
|
192
|
-
],
|
|
193
|
-
ios: ["ipa"],
|
|
194
|
-
android: ["apk", "aab"]
|
|
195
|
-
}, _e = (e, t, n) => {
|
|
196
|
-
let r = V[t] ?? [], i = e.artifacts.filter((e) => r.includes(e.kind));
|
|
197
|
-
if (i.length === 0) return null;
|
|
198
|
-
if (n !== void 0) {
|
|
199
|
-
let e = i.find((e) => e.target !== null && e.target.endsWith(n));
|
|
200
|
-
if (e) return e;
|
|
201
|
-
}
|
|
202
|
-
return i[0];
|
|
203
|
-
}, H = (e) => /Windows/i.test(e) ? {
|
|
204
|
-
os: "windows",
|
|
205
|
-
arch: /ARM64|aarch64/i.test(e) ? "aarch64" : "x86_64"
|
|
206
|
-
} : /Macintosh|Mac OS X/i.test(e) ? { os: "macos" } : /Android/i.test(e) ? { os: "android" } : /iPhone|iPad|iPod/i.test(e) ? { os: "ios" } : /Linux/i.test(e) ? {
|
|
207
|
-
os: "linux",
|
|
208
|
-
arch: /aarch64|arm64/i.test(e) ? "aarch64" : "x86_64"
|
|
209
|
-
} : null, U = (e, t, n = {}) => ({
|
|
1
|
+
import { artifactMetadataIssue as e, artifactOperationId as t, artifactStoredSize as n, hasArtifactSignature as r } from "./artifactMetadata.js";
|
|
2
|
+
import { matchesUploadArtifact as i, uploadArtifactId as a } from "./uploadIdentity.server.js";
|
|
3
|
+
import { ReleaseNotFound as o, ReleaseRefused as s } from "./errors.js";
|
|
4
|
+
import { compareVersions as c, evaluatePolicy as l, inRollout as u, isNewerVersion as d, parseVersion as f, rolloutBucket as p, sortVersionsDesc as ee } from "./rollout.js";
|
|
5
|
+
import { planRetention as te } from "./retention.js";
|
|
6
|
+
import { RELEASES_TABLE as m, RELEASE_APPS_TABLE as ne, RELEASE_ARTIFACTS_TABLE as h, RELEASE_CHANNELS_TABLE as g, RELEASE_EVENTS_TABLE as _ } from "./names.js";
|
|
7
|
+
import { BASE_NAME as v, RELEASES_MANAGE_SCOPE as y, createDescriptor as re, listDescriptor as ie, policyDescriptor as ae, prepareUploadDescriptor as oe, promoteDescriptor as se, registerAppDescriptor as ce, releasesRpcClientImports as le, rollbackDescriptor as ue, rolloutDescriptor as de, setPolicyDescriptor as fe, uploadDescriptor as pe } from "./rpc.js";
|
|
8
|
+
import { RELEASE_PLATFORMS as b, RELEASE_SHELLS as x, releaseAppsTable as S, releaseArtifactsTable as C, releaseChannelsTable as w, releaseEventsTable as me, releaseTables as he, releasesTable as T } from "./schema.js";
|
|
9
|
+
import { offeredTo as ge, osFromUserAgent as _e, pickDownload as ve, renderElectronLatestYml as ye, renderExpoFeed as be, renderTauriFeed as xe } from "./feeds.js";
|
|
10
|
+
import { Effect as E, Result as D, Schema as Se } from "effect";
|
|
11
|
+
import { randomBytes as Ce } from "node:crypto";
|
|
12
|
+
import { AsyncLocalStorage as we } from "node:async_hooks";
|
|
13
|
+
import { definePlugin as Te } from "@voltro/protocol";
|
|
14
|
+
import { and as Ee, eq as O, inSet as De, queryFor as k, registerRetention as Oe, retentionTtlMsFromEnv as ke } from "@voltro/database";
|
|
15
|
+
import { newTraceId as Ae } from "@voltro/runtime";
|
|
16
|
+
//#region src/index.ts
|
|
17
|
+
var A = (e, t, n = {}) => ({
|
|
210
18
|
status: e,
|
|
211
19
|
body: JSON.stringify(t),
|
|
212
20
|
contentType: "application/json; charset=utf-8",
|
|
@@ -214,25 +22,25 @@ var ge = (e, t, n) => {
|
|
|
214
22
|
"cache-control": "no-store",
|
|
215
23
|
...n
|
|
216
24
|
}
|
|
217
|
-
}),
|
|
25
|
+
}), je = (e, t, n) => ({
|
|
218
26
|
status: e,
|
|
219
27
|
body: t,
|
|
220
28
|
contentType: n,
|
|
221
29
|
headers: { "cache-control": "no-store" }
|
|
222
|
-
}),
|
|
30
|
+
}), j = (e) => ({
|
|
223
31
|
status: e,
|
|
224
32
|
body: "",
|
|
225
33
|
headers: { "cache-control": "no-store" }
|
|
226
|
-
}),
|
|
227
|
-
let
|
|
228
|
-
let e =
|
|
34
|
+
}), M = (e) => `${e}_${Ce(9).toString("base64url")}`, N = (u) => {
|
|
35
|
+
let d = (u.prefix ?? "/releases").replace(/\/+$/, ""), f = u.now ?? Date.now, p, ee = new we(), y = new we(), b = () => {
|
|
36
|
+
let e = ee.getStore();
|
|
229
37
|
if (e) return e;
|
|
230
|
-
if (!
|
|
231
|
-
return
|
|
232
|
-
},
|
|
233
|
-
let t = (await
|
|
234
|
-
t ||= await
|
|
235
|
-
id:
|
|
38
|
+
if (!p) throw new s({ reason: "releases: the app store is not bound yet" });
|
|
39
|
+
return p;
|
|
40
|
+
}, x = null, ge = async (e) => {
|
|
41
|
+
let t = (await b().query(k(S).where(O("app", e.app)).descriptor)).find((t) => t.platform === e.platform && t.shell === e.shell), n = !t;
|
|
42
|
+
t ||= await b().insert(ne, {
|
|
43
|
+
id: M("relapp"),
|
|
236
44
|
app: e.app,
|
|
237
45
|
platform: e.platform,
|
|
238
46
|
shell: e.shell,
|
|
@@ -240,15 +48,15 @@ var ge = (e, t, n) => {
|
|
|
240
48
|
bundleId: e.bundleId ?? null,
|
|
241
49
|
updaterPublicKey: e.updaterPublicKey ?? null,
|
|
242
50
|
runtimeVersion: e.runtimeVersion ?? null,
|
|
243
|
-
createdAt: new Date(
|
|
51
|
+
createdAt: new Date(f())
|
|
244
52
|
});
|
|
245
|
-
let r = await
|
|
53
|
+
let r = await b().query(k(w).where(O("appId", t.id)).descriptor);
|
|
246
54
|
for (let n of e.channels ?? [
|
|
247
55
|
"stable",
|
|
248
56
|
"beta",
|
|
249
57
|
"internal"
|
|
250
|
-
]) r.some((e) => e.name === n) || await
|
|
251
|
-
id:
|
|
58
|
+
]) r.some((e) => e.name === n) || await b().insert(g, {
|
|
59
|
+
id: M("relch"),
|
|
252
60
|
appId: t.id,
|
|
253
61
|
name: n,
|
|
254
62
|
currentReleaseId: null,
|
|
@@ -256,40 +64,43 @@ var ge = (e, t, n) => {
|
|
|
256
64
|
killSwitches: null,
|
|
257
65
|
public: n === "stable",
|
|
258
66
|
allowUnsigned: n === "internal",
|
|
259
|
-
updatedAt: new Date(
|
|
67
|
+
updatedAt: new Date(f())
|
|
260
68
|
});
|
|
261
69
|
return {
|
|
262
70
|
row: t,
|
|
263
71
|
created: n
|
|
264
72
|
};
|
|
265
|
-
},
|
|
266
|
-
for (let e of
|
|
267
|
-
},
|
|
73
|
+
}, Ce = async () => {
|
|
74
|
+
for (let e of u.apps) await ge(e);
|
|
75
|
+
}, N = () => x ?? Promise.resolve(), P = (e, t, n) => E.tryPromise({
|
|
268
76
|
try: async () => {
|
|
269
|
-
await
|
|
270
|
-
let
|
|
271
|
-
if (!
|
|
272
|
-
return
|
|
77
|
+
await N();
|
|
78
|
+
let r = await b().query(k(S).where(O("app", e)).descriptor), i = y.getStore(), a = r.find((e) => (i === void 0 || e.id === i) && (t === void 0 || e.platform === t) && (n === void 0 || e.shell === n));
|
|
79
|
+
if (!a) throw new o({ app: e });
|
|
80
|
+
return a;
|
|
273
81
|
},
|
|
274
|
-
catch: (
|
|
275
|
-
}),
|
|
82
|
+
catch: (t) => t instanceof o ? t : new o({ app: e })
|
|
83
|
+
}), F = (e, t, n) => E.tryPromise({
|
|
276
84
|
try: async () => {
|
|
277
|
-
let
|
|
278
|
-
if (!
|
|
279
|
-
app:
|
|
280
|
-
channel:
|
|
85
|
+
let r = (await b().query(k(w).where(O("appId", e)).descriptor)).find((e) => e.name === t);
|
|
86
|
+
if (!r) throw new o({
|
|
87
|
+
app: n,
|
|
88
|
+
channel: t
|
|
281
89
|
});
|
|
282
|
-
return
|
|
90
|
+
return r;
|
|
283
91
|
},
|
|
284
|
-
catch: (
|
|
285
|
-
app:
|
|
286
|
-
channel:
|
|
92
|
+
catch: (e) => e instanceof o ? e : new o({
|
|
93
|
+
app: n,
|
|
94
|
+
channel: t
|
|
287
95
|
})
|
|
288
|
-
}),
|
|
289
|
-
let n =
|
|
96
|
+
}), I = (e, t = !1) => {
|
|
97
|
+
let n = k(T).where(O("id", e));
|
|
98
|
+
return b().query((t ? n.forUpdate() : n).descriptor).then((e) => e[0] ?? null);
|
|
99
|
+
}, L = (e) => b().query(k(T).where(O("appId", e)).descriptor), Pe = (e) => b().query(k(C).where(O("releaseId", e)).descriptor), Fe = (e) => b().query(k(w).where(O("appId", e)).descriptor), Ie = (e) => u.retention?.perChannel?.[e] ?? u.retention?.keep ?? 10, Le = async (e, t) => {
|
|
100
|
+
let n = await Fe(e), r = te(await L(e), n, Ie);
|
|
290
101
|
if (r.length === 0) return [];
|
|
291
|
-
for (let e of r) await
|
|
292
|
-
return await
|
|
102
|
+
for (let e of r) await b().deleteMany(h, { where: O("releaseId", e.id) }), await b().delete(m, e.id);
|
|
103
|
+
return await z({
|
|
293
104
|
appId: e,
|
|
294
105
|
kind: "prune",
|
|
295
106
|
actorId: t,
|
|
@@ -298,8 +109,8 @@ var ge = (e, t, n) => {
|
|
|
298
109
|
channel: n.find((t) => t.id === e.channelId)?.name ?? null
|
|
299
110
|
})) }
|
|
300
111
|
}), r;
|
|
301
|
-
},
|
|
302
|
-
let t = await
|
|
112
|
+
}, Re = async (e) => {
|
|
113
|
+
let t = await Pe(e.id);
|
|
303
114
|
return {
|
|
304
115
|
id: e.id,
|
|
305
116
|
version: e.version,
|
|
@@ -314,14 +125,14 @@ var ge = (e, t, n) => {
|
|
|
314
125
|
target: e.target,
|
|
315
126
|
url: e.url,
|
|
316
127
|
sha256: e.sha256,
|
|
317
|
-
size: e.size,
|
|
128
|
+
size: n(e.size),
|
|
318
129
|
signature: e.signature,
|
|
319
130
|
assetKey: e.assetKey,
|
|
320
131
|
contentType: e.contentType
|
|
321
132
|
}))
|
|
322
133
|
};
|
|
323
|
-
},
|
|
324
|
-
let n = await
|
|
134
|
+
}, R = async (e, t) => {
|
|
135
|
+
let n = await E.runPromise(P(e)), r = await E.runPromise(F(n.id, t, e)), i = r.currentReleaseId ? await I(r.currentReleaseId) : null;
|
|
325
136
|
return {
|
|
326
137
|
app: e,
|
|
327
138
|
channel: t,
|
|
@@ -332,8 +143,8 @@ var ge = (e, t, n) => {
|
|
|
332
143
|
rolloutSalt: i?.rolloutSalt ?? null,
|
|
333
144
|
cohorts: i?.cohorts ?? null
|
|
334
145
|
};
|
|
335
|
-
},
|
|
336
|
-
id:
|
|
146
|
+
}, z = (e) => b().insert(_, {
|
|
147
|
+
id: M("relev"),
|
|
337
148
|
appId: e.appId,
|
|
338
149
|
channelId: e.channelId ?? null,
|
|
339
150
|
releaseId: e.releaseId ?? null,
|
|
@@ -341,42 +152,55 @@ var ge = (e, t, n) => {
|
|
|
341
152
|
reason: e.reason ?? null,
|
|
342
153
|
actorId: e.actorId ?? null,
|
|
343
154
|
detail: e.detail ?? null,
|
|
344
|
-
at: new Date(
|
|
345
|
-
}),
|
|
346
|
-
...
|
|
155
|
+
at: new Date(f())
|
|
156
|
+
}), B = (e) => e.request.subject.type === "user" ? e.request.subject.id : null, ze = {
|
|
157
|
+
...ae,
|
|
347
158
|
description: "The reactive release policy of a channel: latest version, minimum supported version, kill switches, rollout.",
|
|
348
|
-
execute: (e) =>
|
|
349
|
-
try: () =>
|
|
159
|
+
execute: (e) => E.tryPromise({
|
|
160
|
+
try: () => R(e.app, e.channel),
|
|
350
161
|
catch: (e) => e
|
|
351
162
|
})
|
|
352
|
-
},
|
|
353
|
-
...
|
|
163
|
+
}, Be = {
|
|
164
|
+
...ie,
|
|
354
165
|
description: "Every release of an app target, newest first.",
|
|
355
|
-
execute: (e) =>
|
|
356
|
-
let t = yield*
|
|
166
|
+
execute: (e) => E.gen(function* () {
|
|
167
|
+
let t = yield* P(e.app), n = yield* E.promise(() => L(t.id)), i = yield* E.promise(() => b().query(k(w).where(O("appId", t.id)).descriptor)), a = /* @__PURE__ */ new Map();
|
|
168
|
+
for (let e of i) a.has(e.id) || a.set(e.id, e.name);
|
|
169
|
+
let o = /* @__PURE__ */ new Map(), s = [...new Set(n.map((e) => e.id))];
|
|
170
|
+
for (let e = 0; e < s.length; e += 500) {
|
|
171
|
+
let t = yield* E.promise(() => b().query(k(C).where(De("releaseId", s.slice(e, e + 500))).descriptor));
|
|
172
|
+
for (let e of t) {
|
|
173
|
+
let t = o.get(e.releaseId) ?? {
|
|
174
|
+
count: 0,
|
|
175
|
+
signed: !0
|
|
176
|
+
};
|
|
177
|
+
t.count++, t.signed &&= r(e.signature), o.set(e.releaseId, t);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
let l = [];
|
|
357
181
|
for (let e of [...n].sort((e, t) => t.createdAt.getTime() - e.createdAt.getTime() || c(t.version, e.version))) {
|
|
358
|
-
let t =
|
|
359
|
-
|
|
182
|
+
let t = o.get(e.id);
|
|
183
|
+
l.push({
|
|
360
184
|
id: e.id,
|
|
361
185
|
version: e.version,
|
|
362
186
|
buildId: e.buildId,
|
|
363
187
|
state: e.state,
|
|
364
188
|
rolloutPercent: e.rolloutPercent,
|
|
365
|
-
channel:
|
|
189
|
+
channel: a.get(e.channelId) ?? "?",
|
|
366
190
|
createdAt: e.createdAt.toISOString(),
|
|
367
|
-
artifacts: t
|
|
368
|
-
signed: t
|
|
191
|
+
artifacts: t?.count ?? 0,
|
|
192
|
+
signed: t !== void 0 && t.count > 0 && t.signed
|
|
369
193
|
});
|
|
370
194
|
}
|
|
371
|
-
return
|
|
195
|
+
return l;
|
|
372
196
|
})
|
|
373
|
-
},
|
|
374
|
-
...
|
|
197
|
+
}, V = {
|
|
198
|
+
...ce,
|
|
375
199
|
description: "Register an app target at runtime, with its channels; idempotent.",
|
|
376
|
-
execute: (e) =>
|
|
200
|
+
execute: (e) => E.tryPromise({
|
|
377
201
|
try: async () => {
|
|
378
|
-
await
|
|
379
|
-
let { row: t, created: n } = await
|
|
202
|
+
await N();
|
|
203
|
+
let { row: t, created: n } = await ge({
|
|
380
204
|
app: e.app,
|
|
381
205
|
platform: e.platform,
|
|
382
206
|
shell: e.shell,
|
|
@@ -390,255 +214,297 @@ var ge = (e, t, n) => {
|
|
|
390
214
|
created: n
|
|
391
215
|
};
|
|
392
216
|
},
|
|
393
|
-
catch: (
|
|
217
|
+
catch: (t) => new s({ reason: `releases: ${e.app} could not be registered: ${t instanceof Error ? t.message : String(t)}` })
|
|
394
218
|
})
|
|
395
|
-
},
|
|
396
|
-
...
|
|
219
|
+
}, H = {
|
|
220
|
+
...re,
|
|
397
221
|
description: "Create a draft release of a version on a channel.",
|
|
398
|
-
execute: (e,
|
|
399
|
-
let
|
|
400
|
-
if ((yield*
|
|
401
|
-
let
|
|
402
|
-
return yield*
|
|
403
|
-
id:
|
|
404
|
-
appId:
|
|
405
|
-
channelId:
|
|
222
|
+
execute: (e, t) => E.gen(function* () {
|
|
223
|
+
let n = yield* P(e.app), r = yield* F(n.id, e.channel, e.app);
|
|
224
|
+
if ((yield* E.promise(() => L(n.id))).some((t) => t.version === e.version)) return yield* E.fail(new s({ reason: `version ${e.version} already exists for ${e.app}` }));
|
|
225
|
+
let i = M("rel");
|
|
226
|
+
return yield* E.promise(() => b().insert(m, {
|
|
227
|
+
id: i,
|
|
228
|
+
appId: n.id,
|
|
229
|
+
channelId: r.id,
|
|
406
230
|
version: e.version,
|
|
407
231
|
buildId: e.buildId ?? null,
|
|
408
232
|
notes: e.notes ?? null,
|
|
409
233
|
state: "draft",
|
|
410
234
|
rolloutPercent: 0,
|
|
411
|
-
rolloutSalt:
|
|
235
|
+
rolloutSalt: M("salt"),
|
|
412
236
|
cohorts: e.cohorts ?? null,
|
|
413
|
-
createdBy:
|
|
414
|
-
createdAt: new Date(
|
|
415
|
-
updatedAt: new Date(
|
|
416
|
-
})), yield*
|
|
417
|
-
appId:
|
|
418
|
-
channelId:
|
|
419
|
-
releaseId:
|
|
237
|
+
createdBy: B(t),
|
|
238
|
+
createdAt: new Date(f()),
|
|
239
|
+
updatedAt: new Date(f())
|
|
240
|
+
})), yield* E.promise(() => z({
|
|
241
|
+
appId: n.id,
|
|
242
|
+
channelId: r.id,
|
|
243
|
+
releaseId: i,
|
|
420
244
|
kind: "create",
|
|
421
|
-
actorId:
|
|
245
|
+
actorId: B(t),
|
|
422
246
|
detail: { version: e.version }
|
|
423
|
-
})), yield*
|
|
247
|
+
})), yield* E.promise(() => Le(n.id, B(t))), { id: i };
|
|
424
248
|
})
|
|
425
|
-
},
|
|
426
|
-
|
|
249
|
+
}, Ve = async (e, n) => {
|
|
250
|
+
if (n.operationId !== void 0 && !t(n.operationId)) throw new s({ reason: "Invalid artifact operationId." });
|
|
251
|
+
let r = (await e.query(k(T).where(O("id", n.releaseId)).descriptor))[0];
|
|
252
|
+
if (!r) throw new o({
|
|
253
|
+
app: "?",
|
|
254
|
+
version: n.releaseId
|
|
255
|
+
});
|
|
256
|
+
let i = (await e.query(k(S).where(O("id", r.appId)).forUpdate().descriptor))[0], c = (await e.query(k(T).where(O("id", n.releaseId)).forUpdate().descriptor))[0];
|
|
257
|
+
if (!i || !c || n.appPrefix !== void 0 && !i.app.startsWith(n.appPrefix)) throw new o({
|
|
258
|
+
app: "?",
|
|
259
|
+
version: n.releaseId
|
|
260
|
+
});
|
|
261
|
+
if (c.appId !== i.id || n.app !== void 0 && n.app !== i.app || n.version !== void 0 && n.version !== c.version) throw new s({ reason: "Release does not match requested upload destination." });
|
|
262
|
+
let l = n.operationId === void 0 ? void 0 : (await e.query(k(C).where(O("id", a(n.releaseId, n.operationId))).forUpdate().descriptor))[0];
|
|
263
|
+
if (l && l.releaseId !== c.id) throw new s({ reason: "Upload operation does not match the current release." });
|
|
264
|
+
let u = n.expectedTarget;
|
|
265
|
+
if (u !== void 0 && (u.id !== i.id || !Number.isSafeInteger(u.revision) || u.revision < 0 || u.revision >= 2 ** 53 - 1 || !l && u.revision !== i.revision)) throw new s({ reason: "Release target changed. Refresh and review the action again." });
|
|
266
|
+
return {
|
|
267
|
+
release: c,
|
|
268
|
+
target: i,
|
|
269
|
+
completed: l
|
|
270
|
+
};
|
|
271
|
+
}, U = {
|
|
272
|
+
...oe,
|
|
273
|
+
description: "Resolve a release upload destination before transferring bytes; does not reserve publication.",
|
|
274
|
+
execute: (e, t) => E.tryPromise({
|
|
275
|
+
try: async () => {
|
|
276
|
+
await N();
|
|
277
|
+
let n = async (t) => {
|
|
278
|
+
let { release: n, target: r } = await Ve(t, e);
|
|
279
|
+
return {
|
|
280
|
+
releaseId: n.id,
|
|
281
|
+
app: r.app,
|
|
282
|
+
version: n.version
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
return t.mutationStore ? n(t.mutationStore) : b().transactional(n);
|
|
286
|
+
},
|
|
287
|
+
catch: (e) => e
|
|
288
|
+
})
|
|
289
|
+
}, W = {
|
|
290
|
+
...pe,
|
|
427
291
|
description: "Attach an artefact (a file the client downloads) to a release.",
|
|
428
|
-
execute: (
|
|
429
|
-
let
|
|
430
|
-
if (!
|
|
292
|
+
execute: (t, n) => E.gen(function* () {
|
|
293
|
+
let r = yield* E.promise(() => I(t.releaseId));
|
|
294
|
+
if (!r) return yield* E.fail(new o({
|
|
431
295
|
app: "?",
|
|
432
|
-
version:
|
|
296
|
+
version: t.releaseId
|
|
433
297
|
}));
|
|
434
|
-
if (
|
|
435
|
-
let
|
|
436
|
-
return yield*
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
298
|
+
if (t.version !== void 0 && t.version !== r.version) return yield* E.fail(new s({ reason: "Release does not match the requested upload version." }));
|
|
299
|
+
let i = e(t);
|
|
300
|
+
if (i !== void 0) return yield* E.fail(new s({ reason: i }));
|
|
301
|
+
let c = t.operationId === void 0 ? M("relart") : a(t.releaseId, t.operationId);
|
|
302
|
+
return yield* E.promise(() => b().insert(h, {
|
|
303
|
+
id: c,
|
|
304
|
+
releaseId: r.id,
|
|
305
|
+
kind: t.kind,
|
|
306
|
+
target: t.target ?? null,
|
|
307
|
+
url: t.url,
|
|
308
|
+
sha256: t.sha256.toLowerCase(),
|
|
309
|
+
size: String(t.size),
|
|
310
|
+
signature: t.signature ?? null,
|
|
311
|
+
notarized: t.notarized ?? !1,
|
|
312
|
+
assetKey: t.assetKey ?? null,
|
|
313
|
+
contentType: t.contentType ?? null,
|
|
314
|
+
createdAt: new Date(f())
|
|
315
|
+
})), yield* E.promise(() => z({
|
|
316
|
+
appId: r.appId,
|
|
317
|
+
releaseId: r.id,
|
|
452
318
|
kind: "upload",
|
|
453
|
-
actorId:
|
|
319
|
+
actorId: B(n),
|
|
454
320
|
detail: {
|
|
455
|
-
kind:
|
|
456
|
-
target:
|
|
321
|
+
kind: t.kind,
|
|
322
|
+
target: t.target ?? null
|
|
457
323
|
}
|
|
458
|
-
})), { id:
|
|
324
|
+
})), { id: c };
|
|
459
325
|
})
|
|
460
|
-
},
|
|
461
|
-
...
|
|
326
|
+
}, G = {
|
|
327
|
+
...se,
|
|
462
328
|
description: "Point a channel at a release (no rebuild) and start its rollout.",
|
|
463
|
-
execute: (
|
|
464
|
-
let
|
|
465
|
-
if (!c) return yield*
|
|
466
|
-
app:
|
|
467
|
-
version:
|
|
329
|
+
execute: (e, t) => E.gen(function* () {
|
|
330
|
+
let n = yield* P(e.app), i = yield* F(n.id, e.to, e.app), a = yield* E.promise(() => L(n.id)), c = a.find((t) => t.version === e.version);
|
|
331
|
+
if (!c) return yield* E.fail(new o({
|
|
332
|
+
app: e.app,
|
|
333
|
+
version: e.version
|
|
468
334
|
}));
|
|
469
|
-
let l = yield*
|
|
470
|
-
if (!
|
|
471
|
-
let u = Math.max(0, Math.min(100,
|
|
472
|
-
return yield*
|
|
473
|
-
channelId:
|
|
335
|
+
let l = yield* E.promise(() => Pe(c.id));
|
|
336
|
+
if (!i.allowUnsigned && l.some((e) => !r(e.signature))) return yield* E.fail(new s({ reason: `release ${e.version} has unsigned artefacts; channel ${e.to} refuses them` }));
|
|
337
|
+
let u = Math.max(0, Math.min(100, e.rolloutPercent ?? 100));
|
|
338
|
+
return yield* E.promise(() => b().update(m, c.id, {
|
|
339
|
+
channelId: i.id,
|
|
474
340
|
state: u >= 100 ? "complete" : "rolling",
|
|
475
341
|
rolloutPercent: u,
|
|
476
|
-
updatedAt: new Date(
|
|
477
|
-
})), yield*
|
|
342
|
+
updatedAt: new Date(f())
|
|
343
|
+
})), yield* E.promise(() => b().update(g, i.id, {
|
|
478
344
|
currentReleaseId: c.id,
|
|
479
|
-
updatedAt: new Date(
|
|
480
|
-
})), yield*
|
|
481
|
-
appId:
|
|
482
|
-
channelId:
|
|
345
|
+
updatedAt: new Date(f())
|
|
346
|
+
})), yield* E.promise(() => z({
|
|
347
|
+
appId: n.id,
|
|
348
|
+
channelId: i.id,
|
|
483
349
|
releaseId: c.id,
|
|
484
350
|
kind: "promote",
|
|
485
|
-
actorId:
|
|
351
|
+
actorId: B(t),
|
|
486
352
|
detail: {
|
|
487
|
-
from:
|
|
488
|
-
to:
|
|
353
|
+
from: a.find((e) => e.id === i.currentReleaseId)?.version ?? null,
|
|
354
|
+
to: e.version,
|
|
489
355
|
rolloutPercent: u
|
|
490
356
|
}
|
|
491
357
|
})), {
|
|
492
|
-
channel:
|
|
493
|
-
version:
|
|
358
|
+
channel: e.to,
|
|
359
|
+
version: e.version,
|
|
494
360
|
rolloutPercent: u
|
|
495
361
|
};
|
|
496
362
|
})
|
|
497
|
-
},
|
|
498
|
-
...
|
|
363
|
+
}, K = {
|
|
364
|
+
...de,
|
|
499
365
|
description: "Change the rollout percentage of the channel's current release.",
|
|
500
|
-
execute: (
|
|
501
|
-
let
|
|
502
|
-
if (!
|
|
503
|
-
let
|
|
504
|
-
if (!
|
|
505
|
-
app:
|
|
506
|
-
channel:
|
|
366
|
+
execute: (e, t) => E.gen(function* () {
|
|
367
|
+
let n = yield* P(e.app), r = yield* F(n.id, e.channel, e.app);
|
|
368
|
+
if (!r.currentReleaseId) return yield* E.fail(new s({ reason: `channel ${e.channel} has no current release` }));
|
|
369
|
+
let i = yield* E.promise(() => I(r.currentReleaseId));
|
|
370
|
+
if (!i) return yield* E.fail(new o({
|
|
371
|
+
app: e.app,
|
|
372
|
+
channel: e.channel
|
|
507
373
|
}));
|
|
508
|
-
let
|
|
509
|
-
return yield*
|
|
510
|
-
rolloutPercent:
|
|
511
|
-
state:
|
|
512
|
-
updatedAt: new Date(
|
|
513
|
-
})), yield*
|
|
514
|
-
appId:
|
|
515
|
-
channelId:
|
|
516
|
-
releaseId:
|
|
374
|
+
let a = Math.max(0, Math.min(100, e.percent));
|
|
375
|
+
return yield* E.promise(() => b().update(m, i.id, {
|
|
376
|
+
rolloutPercent: a,
|
|
377
|
+
state: a >= 100 ? "complete" : "rolling",
|
|
378
|
+
updatedAt: new Date(f())
|
|
379
|
+
})), yield* E.promise(() => z({
|
|
380
|
+
appId: n.id,
|
|
381
|
+
channelId: r.id,
|
|
382
|
+
releaseId: i.id,
|
|
517
383
|
kind: "rollout",
|
|
518
|
-
actorId:
|
|
519
|
-
detail: { percent:
|
|
384
|
+
actorId: B(t),
|
|
385
|
+
detail: { percent: a }
|
|
520
386
|
})), {
|
|
521
|
-
version:
|
|
522
|
-
rolloutPercent:
|
|
387
|
+
version: i.version,
|
|
388
|
+
rolloutPercent: a
|
|
523
389
|
};
|
|
524
390
|
})
|
|
525
|
-
},
|
|
526
|
-
...
|
|
391
|
+
}, q = {
|
|
392
|
+
...ue,
|
|
527
393
|
description: "Point the channel back at the previous release; the current one is marked rolled back.",
|
|
528
|
-
execute: (e,
|
|
529
|
-
let
|
|
530
|
-
if (!
|
|
531
|
-
let
|
|
532
|
-
return
|
|
394
|
+
execute: (e, t) => E.gen(function* () {
|
|
395
|
+
let n = yield* P(e.app), r = yield* F(n.id, e.channel, e.app);
|
|
396
|
+
if (!r.currentReleaseId) return yield* E.fail(new s({ reason: `channel ${e.channel} has no current release` }));
|
|
397
|
+
let i = yield* E.promise(() => L(n.id)), a = i.find((e) => e.id === r.currentReleaseId), o = i.filter((e) => e.channelId === r.id && e.id !== r.currentReleaseId && e.state !== "rolledBack").sort((e, t) => c(t.version, e.version))[0];
|
|
398
|
+
return a && (yield* E.promise(() => b().update(m, a.id, {
|
|
533
399
|
state: "rolledBack",
|
|
534
|
-
updatedAt: new Date(
|
|
535
|
-
}))), yield*
|
|
536
|
-
currentReleaseId:
|
|
537
|
-
updatedAt: new Date(
|
|
538
|
-
})), yield*
|
|
539
|
-
appId:
|
|
540
|
-
channelId:
|
|
541
|
-
releaseId:
|
|
400
|
+
updatedAt: new Date(f())
|
|
401
|
+
}))), yield* E.promise(() => b().update(g, r.id, {
|
|
402
|
+
currentReleaseId: o?.id ?? null,
|
|
403
|
+
updatedAt: new Date(f())
|
|
404
|
+
})), yield* E.promise(() => z({
|
|
405
|
+
appId: n.id,
|
|
406
|
+
channelId: r.id,
|
|
407
|
+
releaseId: a?.id ?? null,
|
|
542
408
|
kind: "rollback",
|
|
543
409
|
reason: e.reason,
|
|
544
|
-
actorId:
|
|
410
|
+
actorId: B(t),
|
|
545
411
|
detail: {
|
|
546
|
-
from:
|
|
547
|
-
to:
|
|
412
|
+
from: a?.version ?? null,
|
|
413
|
+
to: o?.version ?? null
|
|
548
414
|
}
|
|
549
|
-
})), { version:
|
|
415
|
+
})), { version: o?.version ?? null };
|
|
550
416
|
})
|
|
551
|
-
},
|
|
552
|
-
...
|
|
417
|
+
}, J = {
|
|
418
|
+
...fe,
|
|
553
419
|
description: "Set the minimum supported version and kill switches of a channel.",
|
|
554
|
-
execute: (e, t) =>
|
|
555
|
-
let n = yield*
|
|
556
|
-
return yield*
|
|
420
|
+
execute: (e, t) => E.gen(function* () {
|
|
421
|
+
let n = yield* P(e.app), r = yield* F(n.id, e.channel, e.app);
|
|
422
|
+
return yield* E.promise(() => b().update(g, r.id, {
|
|
557
423
|
...e.minSupportedVersion === void 0 ? {} : { minSupportedVersion: e.minSupportedVersion },
|
|
558
424
|
...e.killSwitches === void 0 ? {} : { killSwitches: e.killSwitches },
|
|
559
|
-
updatedAt: new Date(
|
|
560
|
-
})), yield*
|
|
425
|
+
updatedAt: new Date(f())
|
|
426
|
+
})), yield* E.promise(() => z({
|
|
561
427
|
appId: n.id,
|
|
562
428
|
channelId: r.id,
|
|
563
429
|
kind: "policy",
|
|
564
430
|
reason: e.reason,
|
|
565
|
-
actorId:
|
|
431
|
+
actorId: B(t),
|
|
566
432
|
detail: {
|
|
567
433
|
minSupportedVersion: e.minSupportedVersion ?? null,
|
|
568
434
|
killSwitches: e.killSwitches ?? null
|
|
569
435
|
}
|
|
570
|
-
})), yield*
|
|
436
|
+
})), yield* E.promise(() => R(e.app, e.channel));
|
|
571
437
|
})
|
|
572
438
|
}, Y = async (e, t) => {
|
|
573
|
-
let n = await
|
|
439
|
+
let n = await E.runPromise(P(e)), r = await E.runPromise(F(n.id, t, e)), i = r.currentReleaseId ? await I(r.currentReleaseId) : null;
|
|
574
440
|
return {
|
|
575
441
|
app: n,
|
|
576
442
|
channel: r,
|
|
577
|
-
release: i ? await
|
|
443
|
+
release: i ? await Re(i) : null
|
|
578
444
|
};
|
|
579
|
-
}, X = (e, t) => t.get("install") ?? e.headers["x-voltro-install-id"] ?? e.headers["expo-embedded-update-id"] ?? "anonymous",
|
|
445
|
+
}, X = (e, t) => t.get("install") ?? e.headers["x-voltro-install-id"] ?? e.headers["expo-embedded-update-id"] ?? "anonymous", He = {
|
|
580
446
|
method: "GET",
|
|
581
|
-
path:
|
|
582
|
-
handle: async (
|
|
583
|
-
if (
|
|
584
|
-
let
|
|
585
|
-
if (!
|
|
447
|
+
path: d,
|
|
448
|
+
handle: async (e) => {
|
|
449
|
+
if (e.method !== "GET" && e.method !== "HEAD") return A(405, { error: "method_not_allowed" });
|
|
450
|
+
let t = e.path.slice(d.length).split("/").filter((e) => e.length > 0).map(decodeURIComponent), n = new URLSearchParams(e.query), [r, i] = t;
|
|
451
|
+
if (!r || !i) return A(404, { error: "not_found" });
|
|
586
452
|
try {
|
|
587
|
-
if (
|
|
588
|
-
let [, ,
|
|
589
|
-
if (!
|
|
590
|
-
let { release: s } = await Y(
|
|
591
|
-
installId: X(
|
|
592
|
-
currentVersion:
|
|
593
|
-
target:
|
|
453
|
+
if (i === "tauri") {
|
|
454
|
+
let [, , i, a, o] = t;
|
|
455
|
+
if (!i || !a || !o) return A(400, { error: "expected /tauri/:channel/:target/:currentVersion" });
|
|
456
|
+
let { release: s } = await Y(r, i), c = s ? xe(s, {
|
|
457
|
+
installId: X(e, n),
|
|
458
|
+
currentVersion: o,
|
|
459
|
+
target: a
|
|
594
460
|
}) : null;
|
|
595
|
-
return c ?
|
|
461
|
+
return c ? A(200, c) : j(204);
|
|
596
462
|
}
|
|
597
|
-
if (
|
|
598
|
-
let
|
|
599
|
-
if (
|
|
600
|
-
let { app:
|
|
601
|
-
installId: X(
|
|
463
|
+
if (i === "expo" && t[2] === "manifest") {
|
|
464
|
+
let t = e.headers["expo-channel-name"] ?? n.get("channel") ?? "stable", i = e.headers["expo-platform"] ?? n.get("platform"), a = e.headers["expo-runtime-version"] ?? n.get("runtimeVersion") ?? "";
|
|
465
|
+
if (i !== "ios" && i !== "android") return A(400, { error: "expo-platform must be ios or android" });
|
|
466
|
+
let { app: o, release: s } = await Y(r, t), c = be(s, {
|
|
467
|
+
installId: X(e, n),
|
|
602
468
|
currentVersion: null,
|
|
603
|
-
platform:
|
|
604
|
-
runtimeVersion:
|
|
605
|
-
currentUpdateId:
|
|
469
|
+
platform: i,
|
|
470
|
+
runtimeVersion: a,
|
|
471
|
+
currentUpdateId: e.headers["expo-current-update-id"] ?? null
|
|
606
472
|
}, {
|
|
607
|
-
runtimeVersion:
|
|
473
|
+
runtimeVersion: o.runtimeVersion,
|
|
608
474
|
rolledBackTo: null
|
|
609
475
|
});
|
|
610
|
-
return c.kind === "no-update" ?
|
|
476
|
+
return c.kind === "no-update" ? A(200, { type: "noUpdateAvailable" }, {
|
|
611
477
|
"expo-protocol-version": "1",
|
|
612
478
|
"expo-sfv-version": "0"
|
|
613
|
-
}) : c.kind === "rollback" ?
|
|
479
|
+
}) : c.kind === "rollback" ? A(200, {
|
|
614
480
|
type: "rollBackToEmbedded",
|
|
615
481
|
parameters: { commitTime: c.commitTime }
|
|
616
482
|
}, {
|
|
617
483
|
"expo-protocol-version": "1",
|
|
618
484
|
"expo-sfv-version": "0"
|
|
619
|
-
}) :
|
|
485
|
+
}) : A(200, c.manifest, {
|
|
620
486
|
"expo-protocol-version": "1",
|
|
621
487
|
"expo-sfv-version": "0",
|
|
622
488
|
"expo-manifest-filters": ""
|
|
623
489
|
});
|
|
624
490
|
}
|
|
625
|
-
if (
|
|
626
|
-
let [, , e,
|
|
627
|
-
if (!e || !
|
|
628
|
-
let
|
|
629
|
-
if (
|
|
630
|
-
let { release:
|
|
631
|
-
return
|
|
491
|
+
if (i === "electron") {
|
|
492
|
+
let [, , e, n] = t;
|
|
493
|
+
if (!e || !n) return A(400, { error: "expected /electron/:channel/latest.yml" });
|
|
494
|
+
let i = n === "latest-mac.yml" ? "mac" : n === "latest-linux.yml" ? "linux" : n === "latest.yml" ? "win" : null;
|
|
495
|
+
if (i === null) return A(404, { error: "not_found" });
|
|
496
|
+
let { release: a } = await Y(r, e), o = a ? ye(a, i) : null;
|
|
497
|
+
return o ? je(200, o, "text/yaml; charset=utf-8") : j(204);
|
|
632
498
|
}
|
|
633
|
-
if (
|
|
634
|
-
let [, ,
|
|
635
|
-
if (!
|
|
636
|
-
let { channel:
|
|
637
|
-
if (!
|
|
638
|
-
if (!
|
|
639
|
-
let s =
|
|
640
|
-
if (!s) return
|
|
641
|
-
let l =
|
|
499
|
+
if (i === "download") {
|
|
500
|
+
let [, , i] = t;
|
|
501
|
+
if (!i) return A(400, { error: "expected /download/:channel" });
|
|
502
|
+
let { channel: a, release: o } = await Y(r, i);
|
|
503
|
+
if (!a.public) return A(403, { error: "channel_not_public" });
|
|
504
|
+
if (!o) return j(204);
|
|
505
|
+
let s = n.get("os") ?? _e(e.headers["user-agent"] ?? "")?.os, c = n.get("arch") ?? _e(e.headers["user-agent"] ?? "")?.arch;
|
|
506
|
+
if (!s) return A(400, { error: "os is required (?os=macos|windows|linux|ios|android)" });
|
|
507
|
+
let l = ve(o, s, c);
|
|
642
508
|
return l ? {
|
|
643
509
|
status: 302,
|
|
644
510
|
body: "",
|
|
@@ -646,47 +512,53 @@ var ge = (e, t, n) => {
|
|
|
646
512
|
location: l.url,
|
|
647
513
|
"cache-control": "no-store"
|
|
648
514
|
}
|
|
649
|
-
} :
|
|
515
|
+
} : A(404, { error: "no_artifact_for_os" });
|
|
650
516
|
}
|
|
651
|
-
if (
|
|
652
|
-
let [, ,
|
|
653
|
-
if (!
|
|
654
|
-
let
|
|
655
|
-
version:
|
|
656
|
-
installId: X(
|
|
517
|
+
if (i === "policy") {
|
|
518
|
+
let [, , i] = t;
|
|
519
|
+
if (!i) return A(400, { error: "expected /policy/:channel" });
|
|
520
|
+
let a = await R(r, i), o = n.get("version"), s = o ? l(a, {
|
|
521
|
+
version: o,
|
|
522
|
+
installId: X(e, n)
|
|
657
523
|
}) : null;
|
|
658
|
-
return
|
|
659
|
-
policy:
|
|
660
|
-
...
|
|
524
|
+
return A(200, {
|
|
525
|
+
policy: a,
|
|
526
|
+
...s ? { verdict: s } : {}
|
|
661
527
|
});
|
|
662
528
|
}
|
|
663
|
-
return
|
|
664
|
-
} catch (
|
|
665
|
-
if (
|
|
529
|
+
return A(404, { error: "not_found" });
|
|
530
|
+
} catch (e) {
|
|
531
|
+
if (e instanceof o) return A(404, {
|
|
666
532
|
error: "not_found",
|
|
667
|
-
app:
|
|
533
|
+
app: e.app
|
|
668
534
|
});
|
|
669
|
-
throw
|
|
535
|
+
throw e;
|
|
670
536
|
}
|
|
671
537
|
}
|
|
672
538
|
}, Z = (e) => ({
|
|
673
539
|
kind: "json",
|
|
674
540
|
data: e
|
|
675
|
-
}),
|
|
541
|
+
}), Ue = [{
|
|
676
542
|
method: "GET",
|
|
677
543
|
path: "/overview",
|
|
678
544
|
scope: "shared-store",
|
|
679
545
|
description: "Every app target with its channels, current versions and rollout state.",
|
|
680
|
-
handler: () =>
|
|
681
|
-
let e = await
|
|
546
|
+
handler: () => E.promise(async () => {
|
|
547
|
+
let e = await b().query(k(S).descriptor), t = await b().query(k(w).descriptor), n = await b().query(k(T).descriptor), r = /* @__PURE__ */ new Map();
|
|
548
|
+
for (let e of t) {
|
|
549
|
+
let t = r.get(e.appId);
|
|
550
|
+
t === void 0 ? r.set(e.appId, [e]) : t.push(e);
|
|
551
|
+
}
|
|
552
|
+
let i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map();
|
|
553
|
+
for (let e of n) i.has(e.id) || i.set(e.id, e), a.set(e.appId, (a.get(e.appId) ?? 0) + 1);
|
|
682
554
|
return Z({ apps: e.map((e) => ({
|
|
683
555
|
id: e.id,
|
|
684
556
|
app: e.app,
|
|
685
557
|
platform: e.platform,
|
|
686
558
|
shell: e.shell,
|
|
687
559
|
revision: e.revision,
|
|
688
|
-
channels:
|
|
689
|
-
let t =
|
|
560
|
+
channels: (r.get(e.id) ?? []).map((e) => {
|
|
561
|
+
let t = e.currentReleaseId === null ? void 0 : i.get(e.currentReleaseId);
|
|
690
562
|
return {
|
|
691
563
|
name: e.name,
|
|
692
564
|
current: t?.version ?? null,
|
|
@@ -696,7 +568,7 @@ var ge = (e, t, n) => {
|
|
|
696
568
|
public: e.public
|
|
697
569
|
};
|
|
698
570
|
}),
|
|
699
|
-
releases:
|
|
571
|
+
releases: a.get(e.id) ?? 0
|
|
700
572
|
})) });
|
|
701
573
|
})
|
|
702
574
|
}, {
|
|
@@ -704,90 +576,122 @@ var ge = (e, t, n) => {
|
|
|
704
576
|
path: "/events",
|
|
705
577
|
scope: "shared-store",
|
|
706
578
|
description: "The last 100 release events (promote, rollback, rollout, policy).",
|
|
707
|
-
handler: () =>
|
|
708
|
-
let e = await
|
|
579
|
+
handler: () => E.promise(async () => {
|
|
580
|
+
let e = await b().query(k(me).descriptor), t = await b().query(k(w).descriptor), n = new Map(t.map((e) => [e.id, e.name]));
|
|
709
581
|
return Z({ events: [...e].sort((e, t) => t.at.getTime() - e.at.getTime()).slice(0, 100).map((e) => ({
|
|
710
582
|
...e,
|
|
711
583
|
channelName: e.channelId === null ? null : n.get(e.channelId) ?? null,
|
|
712
584
|
at: e.at.toISOString()
|
|
713
585
|
})) });
|
|
714
586
|
})
|
|
715
|
-
}],
|
|
716
|
-
let
|
|
717
|
-
if (
|
|
718
|
-
let
|
|
719
|
-
if (
|
|
720
|
-
if (
|
|
721
|
-
if (
|
|
722
|
-
let
|
|
723
|
-
if (!Number.isSafeInteger(
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
587
|
+
}], We = async (e, t) => {
|
|
588
|
+
let n = e.releaseId === void 0 ? null : await I(e.releaseId);
|
|
589
|
+
if (e.releaseId !== void 0 && !n) throw new o({ app: e.releaseId });
|
|
590
|
+
let r = (await b().query(k(S).descriptor)).filter((t) => (e.appPrefix === void 0 || t.app.startsWith(e.appPrefix)) && (e.app === void 0 || t.app === e.app) && (e.platform === void 0 || t.platform === e.platform) && (e.shell === void 0 || t.shell === e.shell) && (n === null || t.id === n.appId) && (e.expectedTarget === void 0 || t.id === e.expectedTarget.id));
|
|
591
|
+
if (r.length === 0 && t) return;
|
|
592
|
+
if (r.length === 0) throw new o({ app: e.app ?? e.releaseId ?? "" });
|
|
593
|
+
if (r.length !== 1) throw new s({ reason: "Multiple release targets match this app. Select an exact target." });
|
|
594
|
+
let i = r[0], a = e.expectedTarget?.revision ?? i.revision;
|
|
595
|
+
if (!Number.isSafeInteger(a) || a < 0 || a >= 2 ** 53 - 1 || i.revision !== a || await b().updateMany("_voltro_release_apps", { revision: a + 1 }, { where: Ee(O("id", i.id), O("revision", a), O("app", i.app), O("platform", i.platform), O("shell", i.shell)) }) !== 1) throw new s({ reason: "Release target changed. Refresh and review the action again." });
|
|
596
|
+
let c = (await b().query(k(S).where(O("id", i.id)).forUpdate().descriptor))[0];
|
|
597
|
+
if (c === void 0 || c.app !== i.app || c.platform !== i.platform || c.shell !== i.shell || c.revision !== a + 1 || e.appPrefix !== void 0 && !c.app.startsWith(e.appPrefix)) throw new s({ reason: "Release target changed. Refresh and review the action again." });
|
|
598
|
+
if (e.releaseId !== void 0) {
|
|
599
|
+
let t = await I(e.releaseId, !0);
|
|
600
|
+
if (t === null || t.appId !== i.id) throw new s({ reason: "Release target changed. Refresh and review the action again." });
|
|
601
|
+
}
|
|
602
|
+
return i.id;
|
|
603
|
+
}, Ge = (t) => t.kind === "mutation" ? {
|
|
604
|
+
...t,
|
|
605
|
+
execute: (n, r) => E.gen(function* () {
|
|
606
|
+
let a = yield* E.context();
|
|
607
|
+
return yield* E.tryPromise({
|
|
608
|
+
try: async (o) => {
|
|
609
|
+
await N();
|
|
610
|
+
let c = (c) => ee.run(c, async () => {
|
|
611
|
+
if (t.name === "releases.upload") {
|
|
612
|
+
let t = n;
|
|
613
|
+
if (t.operationId !== void 0) {
|
|
614
|
+
let n = e(t);
|
|
615
|
+
if (n !== void 0) throw new s({ reason: n });
|
|
616
|
+
let { completed: r } = await Ve(c, t);
|
|
617
|
+
if (r) {
|
|
618
|
+
if (!i(r, t)) throw new s({ reason: "Upload operationId was already used for different artifact metadata." });
|
|
619
|
+
return { id: r.id };
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
let l = await We(n, t.name === "releases.registerApp"), u = () => E.runPromiseWith(a)(t.execute(n, r).pipe(E.result), { signal: o }), d = l === void 0 ? await u() : await y.run(l, u);
|
|
624
|
+
if (D.isFailure(d)) throw d.failure;
|
|
625
|
+
return d.success;
|
|
736
626
|
});
|
|
737
|
-
return
|
|
627
|
+
return r.mutationStore ? c(r.mutationStore) : b().transactional(c);
|
|
738
628
|
},
|
|
739
629
|
catch: (e) => e
|
|
740
630
|
});
|
|
741
631
|
})
|
|
742
|
-
} :
|
|
632
|
+
} : t, Ke = {
|
|
633
|
+
apps: V,
|
|
634
|
+
create: H,
|
|
635
|
+
"prepare-upload": U,
|
|
636
|
+
upload: W,
|
|
637
|
+
promote: G,
|
|
638
|
+
rollout: K,
|
|
639
|
+
rollback: q,
|
|
640
|
+
policy: J
|
|
641
|
+
}, qe = (e, t, n) => {
|
|
642
|
+
if (!Object.hasOwn(Ke, e)) return E.fail(new s({ reason: "Unknown release management action." }));
|
|
643
|
+
let r = Ke[e];
|
|
644
|
+
return Se.decodeUnknownEffect(r.input)(t).pipe(E.flatMap((e) => Ge(r).execute(e, n)));
|
|
645
|
+
}, Je = () => ({ request: {
|
|
743
646
|
subject: {
|
|
744
647
|
type: "anonymous",
|
|
745
648
|
id: null,
|
|
746
649
|
tenantId: null
|
|
747
650
|
},
|
|
748
|
-
traceId:
|
|
651
|
+
traceId: Ae()
|
|
749
652
|
} }), Q = (e, t) => ({
|
|
750
653
|
kind: "json",
|
|
751
654
|
status: e,
|
|
752
655
|
data: { error: t }
|
|
753
|
-
}), $ = (
|
|
656
|
+
}), $ = (e, t, n) => ({
|
|
754
657
|
method: "POST",
|
|
755
|
-
path:
|
|
756
|
-
description:
|
|
757
|
-
handler: (
|
|
758
|
-
let
|
|
658
|
+
path: e,
|
|
659
|
+
description: n,
|
|
660
|
+
handler: (e) => E.gen(function* () {
|
|
661
|
+
let n;
|
|
759
662
|
try {
|
|
760
|
-
|
|
663
|
+
n = JSON.parse(e.body || "{}");
|
|
761
664
|
} catch {
|
|
762
665
|
return Q(400, "invalid JSON body");
|
|
763
666
|
}
|
|
764
|
-
if (typeof
|
|
765
|
-
let
|
|
766
|
-
if (
|
|
767
|
-
let
|
|
768
|
-
if (
|
|
769
|
-
let
|
|
770
|
-
return
|
|
667
|
+
if (typeof n != "object" || !n || Array.isArray(n)) return Q(400, "expected a JSON object body");
|
|
668
|
+
let r = yield* Se.decodeUnknownEffect(t.input)(n).pipe(E.result);
|
|
669
|
+
if (D.isFailure(r)) return Q(400, "invalid action input");
|
|
670
|
+
let i = yield* Ge(t).execute(r.success, Je()).pipe(E.result);
|
|
671
|
+
if (D.isFailure(i)) {
|
|
672
|
+
let e = i.failure;
|
|
673
|
+
return e instanceof o ? Q(404, `not found: ${e.app}${e.version ? ` ${e.version}` : ""}${e.channel ? ` (${e.channel})` : ""}`) : e instanceof s ? Q(409, e.reason) : Q(500, "release action failed");
|
|
771
674
|
}
|
|
772
|
-
return Z({ result:
|
|
675
|
+
return Z({ result: i.success });
|
|
773
676
|
})
|
|
774
|
-
}),
|
|
775
|
-
$("/apps",
|
|
776
|
-
$("/create",
|
|
777
|
-
$("/upload",
|
|
778
|
-
$("/
|
|
779
|
-
$("/
|
|
780
|
-
$("/
|
|
781
|
-
$("/
|
|
677
|
+
}), Ye = [
|
|
678
|
+
$("/apps", V, "Register an app target at runtime: { app, platform, shell, channels? }."),
|
|
679
|
+
$("/create", H, "Create a draft release: { app, channel, version, buildId?, notes? }."),
|
|
680
|
+
$("/prepare-upload", U, "Resolve current release/app/version before file transfer; no metadata writes."),
|
|
681
|
+
$("/upload", W, "Attach an artefact: { releaseId, kind, target?, url, sha256, size, signature? }."),
|
|
682
|
+
$("/promote", G, "Promote a version onto a channel: { app, version, to, rolloutPercent? }."),
|
|
683
|
+
$("/rollout", K, "Set the rollout percentage: { app, channel, percent }."),
|
|
684
|
+
$("/rollback", q, "Roll a channel back: { app, channel, reason }."),
|
|
685
|
+
$("/policy", J, "Set the policy: { app, channel, minSupportedVersion?, killSwitches?, reason }.")
|
|
782
686
|
];
|
|
783
|
-
return
|
|
687
|
+
return Oe({
|
|
784
688
|
source: "plugin",
|
|
785
|
-
table:
|
|
689
|
+
table: _,
|
|
786
690
|
timeColumn: "at",
|
|
787
|
-
ttlMs:
|
|
691
|
+
ttlMs: ke(process.env.VOLTRO_RELEASE_EVENTS_TTL_HOURS, 8760),
|
|
788
692
|
envVar: "VOLTRO_RELEASE_EVENTS_TTL_HOURS"
|
|
789
|
-
}),
|
|
790
|
-
name:
|
|
693
|
+
}), Object.assign(Te({
|
|
694
|
+
name: u.name ? `${v}#${u.name}` : v,
|
|
791
695
|
description: "Release channels, artefacts and rollouts — the self-hosted update server behind Tauri, Expo OTA, electron-updater and PWA feeds, with a reactive release policy.",
|
|
792
696
|
permissions: [
|
|
793
697
|
"inspect:read",
|
|
@@ -795,40 +699,41 @@ var ge = (e, t, n) => {
|
|
|
795
699
|
"store:write"
|
|
796
700
|
],
|
|
797
701
|
routes: [
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
702
|
+
ze,
|
|
703
|
+
Be,
|
|
704
|
+
V,
|
|
705
|
+
H,
|
|
706
|
+
U,
|
|
707
|
+
W,
|
|
708
|
+
G,
|
|
709
|
+
K,
|
|
710
|
+
q,
|
|
711
|
+
J
|
|
712
|
+
].map(Ge),
|
|
713
|
+
rpcClientDescriptors: le,
|
|
714
|
+
httpRoutes: [He],
|
|
715
|
+
inspectEndpoints: [...Ue, ...Ye],
|
|
716
|
+
extendSchema: { tables: [...he] },
|
|
717
|
+
declaredEnv: Ne,
|
|
718
|
+
privacy: Me,
|
|
814
719
|
bindDataStore: (e) => {
|
|
815
|
-
|
|
720
|
+
p = e, x = Ce(), x.catch(() => {});
|
|
816
721
|
},
|
|
817
|
-
onActivate: () =>
|
|
722
|
+
onActivate: () => E.tryPromise({
|
|
818
723
|
catch: (e) => /* @__PURE__ */ Error(`@voltro/plugin-releases could not seed its targets and channels: ${e instanceof Error ? e.message : String(e)}`),
|
|
819
|
-
try: () =>
|
|
724
|
+
try: () => N()
|
|
820
725
|
})
|
|
821
|
-
});
|
|
822
|
-
},
|
|
726
|
+
}), { manage: qe });
|
|
727
|
+
}, Me = { collects: [{
|
|
823
728
|
category: "device-id",
|
|
824
729
|
linked: !1,
|
|
825
730
|
tracking: !1,
|
|
826
731
|
purposes: ["app-functionality"]
|
|
827
|
-
}] },
|
|
732
|
+
}] }, Ne = [{
|
|
828
733
|
name: "VOLTRO_RELEASE_EVENTS_TTL_HOURS",
|
|
829
734
|
required: !1,
|
|
830
735
|
secret: !1,
|
|
831
736
|
description: "Hours a release event (create, upload, promote, rollout, rollback, policy, prune) is kept before the retention sweep removes it. Default 8760 (one year)."
|
|
832
737
|
}];
|
|
833
738
|
//#endregion
|
|
834
|
-
export {
|
|
739
|
+
export { v as BASE_NAME, y as RELEASES_MANAGE_SCOPE, m as RELEASES_TABLE, ne as RELEASE_APPS_TABLE, h as RELEASE_ARTIFACTS_TABLE, g as RELEASE_CHANNELS_TABLE, _ as RELEASE_EVENTS_TABLE, b as RELEASE_PLATFORMS, x as RELEASE_SHELLS, o as ReleaseNotFound, s as ReleaseRefused, c as compareVersions, l as evaluatePolicy, u as inRollout, d as isNewerVersion, ge as offeredTo, _e as osFromUserAgent, f as parseVersion, ve as pickDownload, S as releaseAppsTable, C as releaseArtifactsTable, w as releaseChannelsTable, me as releaseEventsTable, he as releaseTables, N as releasesPlugin, T as releasesTable, ye as renderElectronLatestYml, be as renderExpoFeed, xe as renderTauriFeed, p as rolloutBucket, ee as sortVersionsDesc };
|