@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.
@@ -0,0 +1,27 @@
1
+ //#region src/artifactMetadata.ts
2
+ var e = (e) => typeof e == "string" && e.trim().length > 0 && !/[\u0000-\u001f\u007f]/.test(e), t = (t) => e(t) && t.length <= 200, n = (e) => typeof e == "string" && /^[a-f0-9]{64}$/i.test(e), r = (e) => Number.isSafeInteger(e) && e > 0, i = (e) => typeof e == "string" && e.trim().length > 0 && !e.includes("\0"), a = (a) => {
3
+ for (let t of [
4
+ "releaseId",
5
+ "kind",
6
+ "url"
7
+ ]) if (!e(a[t])) return `Artifact ${t} must be nonblank text without control characters`;
8
+ if (a.operationId !== void 0 && !t(a.operationId)) return "Artifact operationId must be nonblank text without control characters and at most 200 characters";
9
+ if (!n(a.sha256)) return "Artifact sha256 must contain exactly 64 hexadecimal characters";
10
+ if (!r(a.size)) return "Artifact size must be a positive safe integer";
11
+ for (let t of [
12
+ "target",
13
+ "assetKey",
14
+ "contentType"
15
+ ]) {
16
+ let n = a[t];
17
+ if (n !== void 0 && !e(n)) return `Artifact ${t} must be nonblank text without control characters`;
18
+ }
19
+ if (a.signature !== void 0 && !i(a.signature)) return "Artifact signature must not be blank or contain NUL";
20
+ }, o = (e) => {
21
+ if (typeof e != "string" || !/^[1-9][0-9]*$/.test(e)) throw Error("Stored artifact size must be a positive integer");
22
+ let t = Number(e);
23
+ if (!r(t)) throw Error("Stored artifact size exceeds the numeric feed range");
24
+ return t;
25
+ };
26
+ //#endregion
27
+ export { n as artifactHash, a as artifactMetadataIssue, t as artifactOperationId, r as artifactSize, o as artifactStoredSize, e as artifactText, i as hasArtifactSignature };
package/dist/errors.d.ts CHANGED
@@ -1,25 +1,23 @@
1
1
  import { Schema } from 'effect';
2
+ import { YieldableError } from 'effect/Cause';
2
3
 
3
4
  export declare const releaseErrors: readonly [typeof ReleaseNotFound, typeof ReleaseRefused];
4
5
 
5
6
  export declare class ReleaseNotFound extends ReleaseNotFound_base {
6
7
  }
7
8
 
8
- declare const ReleaseNotFound_base: Schema.TaggedErrorClass<ReleaseNotFound, "ReleaseNotFound", {
9
- readonly _tag: Schema.tag<"ReleaseNotFound">;
10
- } & {
11
- app: typeof Schema.String;
12
- version: Schema.optional<typeof Schema.String>;
13
- channel: Schema.optional<typeof Schema.String>;
14
- }>;
9
+ declare const ReleaseNotFound_base: Schema.Class<ReleaseNotFound, Schema.TaggedStruct<"ReleaseNotFound", {
10
+ readonly app: Schema.String;
11
+ readonly version: Schema.optional<Schema.String>;
12
+ readonly channel: Schema.optional<Schema.String>;
13
+ }>, YieldableError>;
15
14
 
16
15
  export declare class ReleaseRefused extends ReleaseRefused_base {
16
+ get message(): string;
17
17
  }
18
18
 
19
- declare const ReleaseRefused_base: Schema.TaggedErrorClass<ReleaseRefused, "ReleaseRefused", {
20
- readonly _tag: Schema.tag<"ReleaseRefused">;
21
- } & {
22
- reason: typeof Schema.String;
23
- }>;
19
+ declare const ReleaseRefused_base: Schema.Class<ReleaseRefused, Schema.TaggedStruct<"ReleaseRefused", {
20
+ readonly reason: Schema.String;
21
+ }>, YieldableError>;
24
22
 
25
23
  export { }
package/dist/errors.js CHANGED
@@ -4,6 +4,10 @@ var t = class extends e.TaggedError()("ReleaseNotFound", {
4
4
  app: e.String,
5
5
  version: e.optional(e.String),
6
6
  channel: e.optional(e.String)
7
- }) {}, n = class extends e.TaggedError()("ReleaseRefused", { reason: e.String }) {}, r = [t, n];
7
+ }) {}, n = class extends e.TaggedError()("ReleaseRefused", { reason: e.String }) {
8
+ get message() {
9
+ return this.reason;
10
+ }
11
+ }, r = [t, n];
8
12
  //#endregion
9
13
  export { t as ReleaseNotFound, n as ReleaseRefused, r as releaseErrors };
package/dist/feeds.js ADDED
@@ -0,0 +1,112 @@
1
+ import { hasArtifactSignature as e } from "./artifactMetadata.js";
2
+ import { compareVersions as t, inRollout as n } from "./rollout.js";
3
+ //#region src/feeds.ts
4
+ var r = (e, r) => r.currentVersion !== null && t(e.version, r.currentVersion) <= 0 ? !1 : n({
5
+ installId: r.installId,
6
+ salt: e.rolloutSalt,
7
+ percent: e.rolloutPercent,
8
+ ...r.cohorts === void 0 ? {} : { installCohorts: r.cohorts },
9
+ releaseCohorts: e.cohorts
10
+ }), i = (t, n) => {
11
+ if (!r(t, n)) return null;
12
+ let i = t.artifacts.find((t) => t.target === n.target && e(t.signature)) ?? (n.target === "darwin-aarch64" || n.target === "darwin-x86_64" ? t.artifacts.find((t) => t.target === "darwin-universal" && e(t.signature)) : void 0);
13
+ return !i || !e(i.signature) ? null : {
14
+ version: t.version,
15
+ notes: t.notes ?? "",
16
+ pub_date: t.createdAt.toISOString(),
17
+ platforms: { [n.target]: {
18
+ signature: i.signature,
19
+ url: i.url
20
+ } }
21
+ };
22
+ }, a = (e, t, n = {}) => {
23
+ let r = {
24
+ win: [
25
+ "nsis",
26
+ "msi",
27
+ "exe"
28
+ ],
29
+ mac: ["dmg", "zip"],
30
+ linux: [
31
+ "appimage",
32
+ "deb",
33
+ "rpm"
34
+ ]
35
+ }, i = e.artifacts.filter((e) => r[t].includes(e.kind));
36
+ if (i.length === 0) return null;
37
+ let a = [`version: ${e.version}`, "files:"];
38
+ for (let e of i) {
39
+ a.push(` - url: ${e.url}`);
40
+ let t = n[e.sha256];
41
+ a.push(t === void 0 ? ` sha256: ${e.sha256}` : ` sha512: ${t}`), a.push(` size: ${e.size}`);
42
+ }
43
+ let o = i[0];
44
+ a.push(`path: ${o.url}`);
45
+ let s = n[o.sha256];
46
+ 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";
47
+ }, o = (e, t, n) => {
48
+ if (n.rolledBackTo !== null) return {
49
+ kind: "rollback",
50
+ commitTime: n.rolledBackTo.commitTime.toISOString()
51
+ };
52
+ if (e === null || n.runtimeVersion !== null && n.runtimeVersion !== t.runtimeVersion) return { kind: "no-update" };
53
+ let i = e.buildId ?? e.id;
54
+ if (t.currentUpdateId === i || !r(e, {
55
+ installId: t.installId,
56
+ currentVersion: null,
57
+ ...t.cohorts === void 0 ? {} : { cohorts: t.cohorts }
58
+ })) return { kind: "no-update" };
59
+ let a = e.artifacts.find((e) => e.kind === "expo-bundle" && e.target === t.platform);
60
+ if (!a) return { kind: "no-update" };
61
+ let o = e.artifacts.filter((e) => e.kind === "expo-asset" && (e.target === null || e.target === t.platform)).map((e) => ({
62
+ hash: e.sha256,
63
+ key: e.assetKey ?? e.sha256,
64
+ contentType: e.contentType ?? "application/octet-stream",
65
+ url: e.url
66
+ }));
67
+ return {
68
+ kind: "manifest",
69
+ manifest: {
70
+ id: i,
71
+ createdAt: e.createdAt.toISOString(),
72
+ runtimeVersion: t.runtimeVersion,
73
+ launchAsset: {
74
+ hash: a.sha256,
75
+ key: a.assetKey ?? "bundle",
76
+ contentType: a.contentType ?? "application/javascript",
77
+ url: a.url
78
+ },
79
+ assets: o,
80
+ metadata: {},
81
+ extra: {
82
+ version: e.version,
83
+ ...e.notes ? { notes: e.notes } : {}
84
+ }
85
+ }
86
+ };
87
+ }, s = {
88
+ macos: ["dmg", "zip"],
89
+ windows: [
90
+ "nsis",
91
+ "msi",
92
+ "exe"
93
+ ],
94
+ linux: [
95
+ "appimage",
96
+ "deb",
97
+ "rpm"
98
+ ],
99
+ ios: ["ipa"],
100
+ android: ["apk", "aab"]
101
+ }, c = (e, t, n) => {
102
+ let r = s[t] ?? [], i = e.artifacts.filter((e) => r.includes(e.kind));
103
+ return i.length === 0 ? null : n === void 0 ? (t === "macos" ? i.find((e) => e.target === "darwin-universal") : void 0) ?? i[0] : i.find((e) => e.target === `${t === "macos" ? "darwin" : t}-${n}`) || (t === "macos" && (n === "aarch64" || n === "x86_64") ? i.find((e) => e.target === "darwin-universal") ?? null : null);
104
+ }, l = (e) => /Windows/i.test(e) ? {
105
+ os: "windows",
106
+ arch: /ARM64|aarch64/i.test(e) ? "aarch64" : "x86_64"
107
+ } : /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) ? {
108
+ os: "linux",
109
+ arch: /aarch64|arm64/i.test(e) ? "aarch64" : "x86_64"
110
+ } : null;
111
+ //#endregion
112
+ export { r as offeredTo, l as osFromUserAgent, c as pickDownload, a as renderElectronLatestYml, o as renderExpoFeed, i as renderTauriFeed };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,13 @@
1
1
  import { ColumnBuilder } from '@voltro/database';
2
+ import { DataStore } from '@voltro/database';
3
+ import { Effect } from 'effect';
2
4
  import { FieldDefinitions } from '@voltro/database';
3
5
  import { InferRow } from '@voltro/database';
6
+ import { PluginRouteContext } from '@voltro/protocol';
4
7
  import { Schema } from 'effect';
5
8
  import { Table } from '@voltro/database';
6
9
  import { VoltroPlugin } from '@voltro/protocol';
10
+ import { YieldableError } from 'effect/Cause';
7
11
 
8
12
  export declare const BASE_NAME = "@voltro/plugin-releases";
9
13
 
@@ -105,14 +109,14 @@ export declare const parseVersion: (raw: string) => {
105
109
  export declare const pickDownload: (release: FeedRelease, os: string, arch?: string) => FeedArtifact | null;
106
110
 
107
111
  declare const PolicySchema: Schema.Struct<{
108
- app: typeof Schema.String;
109
- channel: typeof Schema.String;
110
- latestVersion: Schema.NullOr<typeof Schema.String>;
111
- minSupportedVersion: Schema.NullOr<typeof Schema.String>;
112
- killSwitches: Schema.Record$<typeof Schema.String, Schema.Array$<typeof Schema.String>>;
113
- rolloutPercent: typeof Schema.Number;
114
- rolloutSalt: Schema.NullOr<typeof Schema.String>;
115
- cohorts: Schema.NullOr<Schema.Array$<typeof Schema.String>>;
112
+ readonly app: Schema.String;
113
+ readonly channel: Schema.String;
114
+ readonly latestVersion: Schema.NullOr<Schema.String>;
115
+ readonly minSupportedVersion: Schema.NullOr<Schema.String>;
116
+ readonly killSwitches: Schema.$Record<Schema.String, Schema.$Array<Schema.String>>;
117
+ readonly rolloutPercent: Schema.Number;
118
+ readonly rolloutSalt: Schema.NullOr<Schema.String>;
119
+ readonly cohorts: Schema.NullOr<Schema.$Array<Schema.String>>;
116
120
  }>;
117
121
 
118
122
  export declare interface PolicyVerdict {
@@ -183,7 +187,7 @@ export declare const releaseArtifactsTable: Table<"_voltro_release_artifacts", F
183
187
  /** Where the bytes are — a storage ref URL, a CDN URL. The feed hands this out. */
184
188
  readonly url: ColumnBuilder<string, "text", boolean>;
185
189
  readonly sha256: ColumnBuilder<string, "text", boolean>;
186
- readonly size: ColumnBuilder<number, "integer", boolean>;
190
+ readonly size: ColumnBuilder<string, "bigint", boolean>;
187
191
  /** minisign / Expo code-signing signature over the bytes. */
188
192
  readonly signature: ColumnBuilder<string | null, "text", boolean>;
189
193
  readonly notarized: ColumnBuilder<boolean, "boolean", true>;
@@ -227,16 +231,20 @@ export declare const releaseEventsTable: Table<"_voltro_release_events", FieldDe
227
231
  readonly at: ColumnBuilder<Date, "timestamp", true>;
228
232
  }>, true, "byReleaseEventApp">;
229
233
 
234
+ export declare type ReleaseManagementAction = 'apps' | 'create' | 'prepare-upload' | 'upload' | 'promote' | 'rollout' | 'rollback' | 'policy';
235
+
236
+ export declare interface ReleaseManagementContext extends PluginRouteContext {
237
+ readonly mutationStore: DataStore;
238
+ }
239
+
230
240
  export declare class ReleaseNotFound extends ReleaseNotFound_base {
231
241
  }
232
242
 
233
- declare const ReleaseNotFound_base: Schema.TaggedErrorClass<ReleaseNotFound, "ReleaseNotFound", {
234
- readonly _tag: Schema.tag<"ReleaseNotFound">;
235
- } & {
236
- app: typeof Schema.String;
237
- version: Schema.optional<typeof Schema.String>;
238
- channel: Schema.optional<typeof Schema.String>;
239
- }>;
243
+ declare const ReleaseNotFound_base: Schema.Class<ReleaseNotFound, Schema.TaggedStruct<"ReleaseNotFound", {
244
+ readonly app: Schema.String;
245
+ readonly version: Schema.optional<Schema.String>;
246
+ readonly channel: Schema.optional<Schema.String>;
247
+ }>, YieldableError>;
240
248
 
241
249
  export declare type ReleasePlatform = (typeof RELEASE_PLATFORMS)[number];
242
250
 
@@ -254,13 +262,12 @@ export declare interface ReleasePolicy {
254
262
  }
255
263
 
256
264
  export declare class ReleaseRefused extends ReleaseRefused_base {
265
+ get message(): string;
257
266
  }
258
267
 
259
- declare const ReleaseRefused_base: Schema.TaggedErrorClass<ReleaseRefused, "ReleaseRefused", {
260
- readonly _tag: Schema.tag<"ReleaseRefused">;
261
- } & {
262
- reason: typeof Schema.String;
263
- }>;
268
+ declare const ReleaseRefused_base: Schema.Class<ReleaseRefused, Schema.TaggedStruct<"ReleaseRefused", {
269
+ readonly reason: Schema.String;
270
+ }>, YieldableError>;
264
271
 
265
272
  export declare type ReleaseRow = InferRow<typeof releasesTable>;
266
273
 
@@ -271,7 +278,14 @@ export declare const RELEASES_TABLE = "_voltro_releases";
271
278
 
272
279
  export declare type ReleaseShell = (typeof RELEASE_SHELLS)[number];
273
280
 
274
- export declare const releasesPlugin: (options: ReleasesPluginOptions) => VoltroPlugin;
281
+ export declare interface ReleasesPlugin extends VoltroPlugin {
282
+ /** Trusted server capability. Authorize the caller and execute inside its
283
+ * transaction; failed Effects must escape that transaction to roll it back.
284
+ * Uses the same input schemas and atomic writers as RPC and Inspect. */
285
+ readonly manage: (action: ReleaseManagementAction, input: unknown, context: ReleaseManagementContext) => Effect.Effect<unknown, unknown>;
286
+ }
287
+
288
+ export declare const releasesPlugin: (options: ReleasesPluginOptions) => ReleasesPlugin;
275
289
 
276
290
  export declare interface ReleasesPluginOptions {
277
291
  /** The app targets this api releases for; created on activation if absent. */
@@ -374,7 +388,7 @@ export declare const releaseTables: readonly [ Table<"_voltro_release_apps", Fie
374
388
  /** Where the bytes are — a storage ref URL, a CDN URL. The feed hands this out. */
375
389
  readonly url: ColumnBuilder<string, "text", boolean>;
376
390
  readonly sha256: ColumnBuilder<string, "text", boolean>;
377
- readonly size: ColumnBuilder<number, "integer", boolean>;
391
+ readonly size: ColumnBuilder<string, "bigint", boolean>;
378
392
  /** minisign / Expo code-signing signature over the bytes. */
379
393
  readonly signature: ColumnBuilder<string | null, "text", boolean>;
380
394
  readonly notarized: ColumnBuilder<boolean, "boolean", true>;