akanjs 3.1.1-rc.7 → 3.1.1-rc.9

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/index.ts CHANGED
@@ -127,20 +127,20 @@ export interface AkanNativeDeepLinks {
127
127
  */
128
128
  export interface AkanNativeUpdatesConfig {
129
129
  /**
130
- * A static base URL, https in a release build, with no query: `<url>/<os>-<arch>/<channel>.json` (desktop) or
130
+ * A static base URL, https in a release build, with no query: `<url>/<os>-<arch>/<channel>/app.json` (desktop) or
131
131
  * `<url>/<platform>/<channel>/<nativeApi>.json` (a phone's web bundle, one envelope per binary generation).
132
132
  */
133
133
  url: string;
134
134
  /**
135
- * The keys a phone binary trusts, raw 32-byte Ed25519 public keys in base64 (`akan update-keygen` prints one), 1 to
136
- * 3: the online signing key first, offline spares after it, since a key may revoke only keys listed before it. A
137
- * desktop app trusts the first.
135
+ * The keys a binary trusts, raw 32-byte Ed25519 public keys in base64 (`akan update-keygen` prints one), 1 to 3:
136
+ * the online signing key first, offline spares after it, since a key may revoke only keys listed before it. A desktop
137
+ * app built before protocol v2 trusts the first.
138
138
  */
139
139
  publicKeys?: string[];
140
140
  /** The one-key form of `publicKeys`, never beside it: a target overriding native.updates' keys keeps its form. */
141
141
  publicKey?: string;
142
142
  /**
143
- * keyIds every phone release revokes (`akan update-keygen` prints a key's), kept here so a release published from a
143
+ * keyIds every release revokes (`akan update-keygen` prints a key's), kept here so a release published from a
144
144
  * fresh checkout still revokes them; `akan publish-update --revoke` starts a revocation. A key may revoke only keys
145
145
  * listed before it in publicKeys, so a release is signed with one listed after them.
146
146
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akanjs",
3
- "version": "3.1.1-rc.7",
3
+ "version": "3.1.1-rc.9",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
package/types/index.d.ts CHANGED
@@ -113,20 +113,20 @@ export interface AkanNativeDeepLinks {
113
113
  */
114
114
  export interface AkanNativeUpdatesConfig {
115
115
  /**
116
- * A static base URL, https in a release build, with no query: `<url>/<os>-<arch>/<channel>.json` (desktop) or
116
+ * A static base URL, https in a release build, with no query: `<url>/<os>-<arch>/<channel>/app.json` (desktop) or
117
117
  * `<url>/<platform>/<channel>/<nativeApi>.json` (a phone's web bundle, one envelope per binary generation).
118
118
  */
119
119
  url: string;
120
120
  /**
121
- * The keys a phone binary trusts, raw 32-byte Ed25519 public keys in base64 (`akan update-keygen` prints one), 1 to
122
- * 3: the online signing key first, offline spares after it, since a key may revoke only keys listed before it. A
123
- * desktop app trusts the first.
121
+ * The keys a binary trusts, raw 32-byte Ed25519 public keys in base64 (`akan update-keygen` prints one), 1 to 3:
122
+ * the online signing key first, offline spares after it, since a key may revoke only keys listed before it. A desktop
123
+ * app built before protocol v2 trusts the first.
124
124
  */
125
125
  publicKeys?: string[];
126
126
  /** The one-key form of `publicKeys`, never beside it: a target overriding native.updates' keys keeps its form. */
127
127
  publicKey?: string;
128
128
  /**
129
- * keyIds every phone release revokes (`akan update-keygen` prints a key's), kept here so a release published from a
129
+ * keyIds every release revokes (`akan update-keygen` prints a key's), kept here so a release published from a
130
130
  * fresh checkout still revokes them; `akan publish-update --revoke` starts a revocation. A key may revoke only keys
131
131
  * listed before it in publicKeys, so a release is signed with one listed after them.
132
132
  */
@@ -18,7 +18,7 @@ export type { UpdateEnvelope, UpdateFile, UpdateManifest } from "./lib/updates.t
18
18
  * A phone's update protocol as the apps run it, for a signer or a server that checks what it publishes or registers:
19
19
  * the envelope's verification, the keyId of a public key, and what a verified manifest means to a binary.
20
20
  */
21
- export { keyIdOf, openEnvelope } from "./lib/updates.ts";
21
+ export { keyIdOf, openEnvelope, verifyManifest } from "./lib/updates.ts";
22
22
  export type { AkanNativeConfig, AndroidSigning, DesktopArch, Device, DeviceSelector, DoctorCheck, IosBuild, IosSigning, IosSigningResult, LinuxBuild, LogEvent, MacosBuild, MacosNotarization, MacosSigning, TargetPlatform, WindowsBuild, WindowsSigning, };
23
23
  /**
24
24
  * The macOS signing and notarization the AKAN_NATIVE_MACOS_* variables name, for a caller that keeps them in its
@@ -27,7 +27,7 @@ export type { AkanNativeConfig, AndroidSigning, DesktopArch, Device, DeviceSelec
27
27
  /** The Authenticode settings the AKAN_NATIVE_WINDOWS_* variables name: pass the result as `windows.signing`. */
28
28
  export { macosDistributionFromEnv, requestedDistribution, windowsSigningFromEnv };
29
29
  /** semver of this API. A caller checks the major before it relies on anything here. */
30
- export declare const API_VERSION = "0.12.0";
30
+ export declare const API_VERSION = "0.13.0";
31
31
  export type AkanNativeErrorCode = "CONFIG_INVALID" | "TOOLCHAIN_MISSING" | "WEB_INPUT_INVALID" | "WEB_BUILD_FAILED" | "NATIVE_BUILD_FAILED" | "SIGNING_FAILED" | "DEVICE_FAILED" | "CANCELLED" | "INTERNAL";
32
32
  export declare class AkanNativeError extends Error {
33
33
  readonly code: AkanNativeErrorCode;
@@ -159,17 +159,17 @@ export interface PublishCheckOptions extends Pick<TaskOptions, "appDir" | "confi
159
159
  /** A desktop release's CPU, which names its feed folder: this computer's by default. */
160
160
  arch?: DesktopArch;
161
161
  /**
162
- * A phone release: keyIds of updates.publicKeys it starts revoking, beside updates.revokedKeys and what the channel's
163
- * releases revoke. It is signed with a key listed after every key it revokes.
162
+ * keyIds of updates.publicKeys the release starts revoking, beside updates.revokedKeys and what the channel's releases
163
+ * revoke. It is signed with a key listed after every key it revokes.
164
164
  */
165
165
  revoke?: string[];
166
- /** A phone release that revokes a key: phones compare it with their own bundle instead of the running one. */
166
+ /** A release that revokes a key: apps compare it with their own build instead of the running release. */
167
167
  resetSequence?: boolean;
168
168
  }
169
169
  /**
170
170
  * What publishUpdate() refuses before it builds, without building (CONFIG_INVALID): no updates settings, a channel no
171
171
  * app could be configured for, no signing key on this machine or another app's, a desktop release whose server
172
- * presence is not the channel's previous release's, and a phone release whose revocations no phone would take. For a
172
+ * presence is not the channel's previous release's, and a release whose revocations no app would take. For a
173
173
  * caller with a long build of its own before publishUpdate.
174
174
  */
175
175
  export declare function checkPublishUpdate(options: PublishCheckOptions): {
@@ -177,8 +177,8 @@ export declare function checkPublishUpdate(options: PublishCheckOptions): {
177
177
  out: string;
178
178
  };
179
179
  /**
180
- * A signed release for the updates plugin (UP-1, UP-2): a release build, then `<channel>.json`, its signature and
181
- * its files under `out` (default <appDir>/.akan/native/updates), signed with the key updateKeygen() made.
180
+ * A signed release for the updates plugin (UP-1, UP-2): a release build, then its envelope and its files under `out`
181
+ * (default <appDir>/.akan/native/updates), signed with the key updateKeygen() made.
182
182
  */
183
183
  export declare function publishUpdate(options: TaskOptions & {
184
184
  platform: Exclude<TargetPlatform, "web">;
@@ -190,9 +190,9 @@ export declare function publishUpdate(options: TaskOptions & {
190
190
  windows?: Pick<WindowsBuild, "signing">;
191
191
  /** A desktop release's CPU, of the same OS: an x64 release from an arm64 machine. Default this computer's. */
192
192
  arch?: DesktopArch;
193
- /** A phone release: keyIds of updates.publicKeys it starts revoking (PublishCheckOptions.revoke). */
193
+ /** keyIds of updates.publicKeys the release starts revoking (PublishCheckOptions.revoke). */
194
194
  revoke?: string[];
195
- /** A phone release that revokes a key: phones compare it with their own bundle instead of the running one. */
195
+ /** A release that revokes a key: apps compare it with their own build instead of the running release. */
196
196
  resetSequence?: boolean;
197
197
  }): Promise<PublishResult>;
198
198
  /**
@@ -115,17 +115,17 @@ export interface AkanNativeConfig {
115
115
  /**
116
116
  * Over-the-air updates (UP-2 web bundles on iOS / Android, UP-1 app updates on macOS), used by
117
117
  * @akanjs/native/plugins/updates. `akan-native update keygen` makes the signing key and prints its public key;
118
- * `akan-native update publish <platform>` writes signed releases for `url`. `publicKeys` lists the keys a phone
118
+ * `akan-native update publish <platform>` writes signed releases for `url`. `publicKeys` lists the keys an app
119
119
  * trusts, the online signing key first and offline spares after (a key revokes only keys before it); `publicKey` is
120
- * the one-key form, and a desktop app trusts the first. `report.url` is where a phone posts what became of each
121
- * release, at its next launch or return to the foreground.
120
+ * the one-key form, and a desktop app built before protocol v2 trusts the first. `report.url` is where a phone posts
121
+ * what became of each release, at its next launch or return to the foreground.
122
122
  */
123
123
  updates?: {
124
124
  url: string;
125
125
  publicKey?: string;
126
126
  publicKeys?: string[];
127
127
  /**
128
- * keyIds every phone release revokes (`update keygen` prints a key's), kept here so a release published from a fresh
128
+ * keyIds every release revokes (`update keygen` prints a key's), kept here so a release published from a fresh
129
129
  * folder still revokes them; `update publish --revoke` starts a revocation. A key may revoke only keys listed
130
130
  * before it in publicKeys, so a release is signed with one listed after them.
131
131
  */
@@ -135,6 +135,11 @@ export interface AkanNativeConfig {
135
135
  report?: {
136
136
  url: string;
137
137
  };
138
+ /**
139
+ * The release target a desktop binary is built for: its manifests name it and the app takes only its own, so a
140
+ * release signed for one target cannot be served to another's apps. akan sets the native target's name.
141
+ */
142
+ target?: string;
138
143
  };
139
144
  /** Links that open the app, delivered through the app plugin's urlOpen (and getLaunchUrl). */
140
145
  deepLinks?: {
@@ -5,7 +5,7 @@ export interface PublishedRelease {
5
5
  /** `<out>/<os>-<arch>` for a desktop app, `<out>/<platform>` for a phone's web bundle. */
6
6
  dir: string;
7
7
  manifest: UpdateManifest;
8
- /** The file installed apps read: `<dir>/<channel>.json`, or a phone's `<dir>/<channel>/<nativeApi>.json`. */
8
+ /** The envelope installed apps read: a desktop's `<dir>/<channel>/app.json`, a phone's `<dir>/<channel>/<nativeApi>.json`. */
9
9
  file: string;
10
10
  }
11
11
  /**
@@ -22,23 +22,19 @@ export declare function assertServerOfChannel(config: {
22
22
  server?: unknown;
23
23
  };
24
24
  }, platform: ReleasePlatform, out: string, channel: string, arch?: DesktopArch): void;
25
- /**
26
- * Refuses before the build a release that could not be signed: no key on this machine, another app's, or for a desktop
27
- * app one the app does not trust (it trusts the first of updates.publicKeys).
28
- */
25
+ /** Refuses before the build a release that could not be signed: no key on this machine, or another app's. */
29
26
  export declare function assertSigningKey(config: {
30
27
  app: {
31
28
  id: string;
32
29
  };
33
30
  updates?: {
34
31
  publicKeys: string[];
35
- revokedKeys?: readonly string[];
36
32
  } | null;
37
- }, platform?: ReleasePlatform): void;
33
+ }): void;
38
34
  export interface RevocationRequest {
39
35
  /** keyIds of updates.publicKeys this release starts revoking (`update publish --revoke`). */
40
36
  revoke?: readonly string[];
41
- /** With a revocation, a phone compares the release with its own bundle instead of the running one. */
37
+ /** With a revocation, an app compares the release with its own build instead of the running release. */
42
38
  resetSequence?: boolean;
43
39
  }
44
40
  interface RevocationConfig {
@@ -51,16 +47,20 @@ interface RevocationConfig {
51
47
  } | null;
52
48
  }
53
49
  /**
54
- * The revokeKeys and resetSequence of a phone release of `channel` under `out`: updates.revokedKeys, what the channel's
55
- * releases revoke, and `revoke`, since a phone that never saw a revocation (a new install, cleared data) learns it only
50
+ * The revokeKeys and resetSequence of a release of `channel` under `out`: updates.revokedKeys, what the channel's
51
+ * releases revoke, and `revoke`, since an app that never saw a revocation (a new install, cleared data) learns it only
56
52
  * from a later manifest. Refuses a `revoke` the ring does not hold, more keys than a manifest may revoke, a reset that
57
- * revokes nothing, and a signing key the release revokes or that is listed before a key it revokes: every phone would
53
+ * revokes nothing, and a signing key the release revokes or that is listed before a key it revokes: every app would
58
54
  * refuse that manifest, since a key may revoke only keys listed before it.
59
55
  */
60
- export declare function releaseRevocations(config: RevocationConfig, platform: ReleasePlatform, out: string, channel: string, { revoke, resetSequence }?: RevocationRequest): {
56
+ export declare function releaseRevocations(config: RevocationConfig, platform: ReleasePlatform, out: string, channel: string, { revoke, resetSequence }?: RevocationRequest, arch?: DesktopArch): {
61
57
  revokeKeys: string[];
62
58
  resetSequence: boolean;
63
59
  };
64
- /** Writes the release of `artifact` (the app a release build made) and its signed manifest under `out`. */
60
+ /**
61
+ * Writes the release of `artifact` (the app a release build made) and its envelope under `out`. A desktop release also
62
+ * gets the v1 pair when signed with the first key, the only one an app built before protocol v2 trusts: that is how
63
+ * such an app takes a binary that reads envelopes.
64
+ */
65
65
  export declare function publishRelease(ctx: BuildContext, platform: ReleasePlatform, artifact: string, out: string, channel: string, request?: RevocationRequest): Promise<PublishedRelease>;
66
66
  export {};
@@ -3,17 +3,22 @@ export interface UpdatesConfig {
3
3
  /** Base URL of the update files, e.g. "https://example.com/updates". http:// only for localhost / 10.0.2.2 in dev builds. */
4
4
  url: string;
5
5
  /**
6
- * Raw 32-byte Ed25519 public keys, base64 (`akan-native update keygen` prints one): the keys a phone binary trusts, the
6
+ * Raw 32-byte Ed25519 public keys, base64 (`akan-native update keygen` prints one): the keys a binary trusts, the
7
7
  * online signing key first and offline spares after it, since a key may revoke only keys listed before it. A desktop
8
- * app trusts the first.
8
+ * app built before protocol v2 trusts the first.
9
9
  */
10
10
  publicKeys: string[];
11
11
  /**
12
- * keyIds every phone release revokes, kept in the config so a release published from another folder (a fresh CI
13
- * checkout) still revokes them. `akan-native update publish --revoke` starts a revocation. A phone build trusts none
14
- * of them, though publicKeys still lists them.
12
+ * keyIds every release revokes, kept in the config so a release published from another folder (a fresh CI checkout)
13
+ * still revokes them. `akan-native update publish --revoke` starts a revocation. A build trusts none of them, though
14
+ * publicKeys still lists them.
15
15
  */
16
16
  revokedKeys: string[];
17
+ /**
18
+ * The release target a desktop binary is built for (akan's native target): its manifests name it and the app takes
19
+ * only its own, so a release signed for one target cannot be served to another's apps. null: the manifest names none.
20
+ */
21
+ target: string | null;
17
22
  /** Manifest name under <platform>/. Default "production". */
18
23
  channel: string;
19
24
  /** How long a newly applied bundle has to call notifyReady() before it is rolled back, ms. Default 10000. */
@@ -31,7 +36,7 @@ export type DesktopArch = "arm64" | "x64";
31
36
  /** The CPU of the desktop apps this machine builds (cargo and bun build for the host). */
32
37
  export declare function hostArch(): DesktopArch;
33
38
  export interface UpdateManifest {
34
- /** 2 for a phone's web bundle, which travels in an UpdateEnvelope; 1 for a desktop app. */
39
+ /** 2 for a release in an UpdateEnvelope (a phone's web bundle, a desktop app); 1 for a desktop app's v1 pair. */
35
40
  schema: 1 | 2;
36
41
  kind: "web" | "app";
37
42
  app: string;
@@ -67,12 +72,17 @@ export interface UpdateManifest {
67
72
  }[];
68
73
  /** App updates: whether the app carries a server; an installed app refuses a release that differs from itself. */
69
74
  server?: boolean;
70
- /** Web bundles: keyIds the phone stops trusting for good; each listed before the signer's key in its updates.publicKeys. */
75
+ /** App updates of schema 2: updates.target of the apps the release is for; absent when that is null. */
76
+ target?: string;
77
+ /** Schema 2: keyIds the app stops trusting for good; each listed before the signer's key in its updates.publicKeys. */
71
78
  revokeKeys?: string[];
72
- /** Web bundles: with a new revocation, compare this release with the binary's own bundle instead of the running one. */
79
+ /** Schema 2: with a new revocation, compare this release with the binary's own bundle instead of the running one. */
73
80
  resetSequence?: boolean;
74
81
  }
75
- /** A phone's `<platform>/<channel>/<nativeApi>.json`: one object, so a new manifest never meets an old signature. */
82
+ /**
83
+ * A phone's `<platform>/<channel>/<nativeApi>.json` or a desktop app's `<os>-<arch>/<channel>/app.json`: one object, so
84
+ * a new manifest never meets an old signature.
85
+ */
76
86
  export interface UpdateEnvelope {
77
87
  /** The manifest's exact bytes, base64. */
78
88
  manifest: string;
@@ -146,10 +156,10 @@ export declare function updatesResource(updates: UpdatesConfig, app: {
146
156
  version: string;
147
157
  }, platform: Platform, nativeApi: string | undefined, dev: boolean, embeddedSequence?: number): string;
148
158
  /**
149
- * The keys a phone build trusts: updates.publicKeys without the revoked ones, so a fresh install trusts none of them
150
- * before its first release tells it. A manifest that revokes a key the binary does not hold is still taken.
159
+ * The keys a build trusts: updates.publicKeys without the revoked ones, so a fresh install trusts none of them before
160
+ * its first release tells it. A manifest that revokes a key the binary does not hold is still taken.
151
161
  */
152
- export declare const phoneRing: (updates: Pick<UpdatesConfig, "publicKeys" | "revokedKeys">) => string[];
162
+ export declare const updateRing: (updates: Pick<UpdatesConfig, "publicKeys" | "revokedKeys">) => string[];
153
163
  /**
154
164
  * updates.json of a phone build, and the same facts in the build's bundle.json: a signer that registers the store build
155
165
  * checks the binary reads its URL and keys, and takes `embeddedSequence` as the floor every release must pass.
@@ -1,6 +1,11 @@
1
1
  import type { BuildContext } from "../lib/prepare.ts";
2
2
  import { type UpdateManifest } from "../lib/updates.ts";
3
3
  import { type DesktopOs } from "./desktop.ts";
4
+ /**
5
+ * The release of `channel` in `dir`: the manifest of its envelope, else the v1 `<channel>.json` of a folder published
6
+ * before protocol v2. Read unverified, as the publisher's own folder.
7
+ */
8
+ export declare function publishedApp(dir: string, channel: string): Partial<UpdateManifest> | null;
4
9
  /**
5
10
  * An installed app refuses a release whose server presence is not its own (plugins/updates): published, this one would
6
11
  * be refused by every app the channel reached, and so would every release after it. A manifest from before the field
@@ -146,8 +146,19 @@ export declare function updateDecision(input: UpdateDecisionInput): UpdateDecisi
146
146
  export declare const updateDecisionWire: (decision: UpdateDecision) => string;
147
147
  /** The v2 envelope of a channel for one native API: one file per binary generation, so each takes its own fixes. */
148
148
  export declare const updateManifestUrl: (url: string, platform: string, channel: string, nativeApi: string) => string;
149
+ /**
150
+ * A desktop app's v2 envelope of a channel: the whole app is one release per OS and CPU, so one file. `app` is a
151
+ * reserved channel name, since `<os>-<arch>/app/` holds the archives.
152
+ */
153
+ export declare const appManifestUrl: (url: string, os: string, arch: string, channel: string) => string;
149
154
  /** An envelope's signer or a revokeKeys entry: the first 8 bytes of the raw public key's SHA-256, in hex. */
150
155
  export declare const isUpdateKeyId: (s: string) => boolean;
156
+ /**
157
+ * Whether a base64 string is an Ed25519 public key a release may be signed for: strict base64 of 32 bytes, the
158
+ * canonical encoding of a curve point (RFC 8032 §5.1.3, y < p and no negative zero), not of small order. A small-order
159
+ * key verifies signatures nobody made with a private key, so a config listing one would trust forged releases.
160
+ */
161
+ export declare function isUpdatePublicKey(key: string): boolean;
151
162
  /** The most keys a manifest may revoke: every host refuses a longer revokeKeys. */
152
163
  export declare const MAX_REVOKE_KEYS = 16;
153
164
  /** The largest manifest an envelope may carry, in bytes. */
@@ -7,7 +7,14 @@ export interface UpdatesConfig {
7
7
  nativeApi: string | null;
8
8
  embeddedSequence: number;
9
9
  url: string;
10
- publicKey: string;
10
+ /** 2: envelopes signed by any key of `publicKeys`; absent, the v1 pair signed by `publicKey`. */
11
+ protocol?: number;
12
+ /** v2: the keys of updates.publicKeys this build trusts, revoked ones left out. */
13
+ publicKeys?: string[];
14
+ /** The first of updates.publicKeys, the one key v1 trusts. */
15
+ publicKey?: string;
16
+ /** v2: updates.target, which a release must name; absent, it must name none. */
17
+ target?: string;
11
18
  channel: string;
12
19
  readyTimeout: number;
13
20
  }
@@ -76,7 +76,7 @@ export type { UpdateEnvelope, UpdateFile, UpdateManifest } from "./lib/updates.t
76
76
  * A phone's update protocol as the apps run it, for a signer or a server that checks what it publishes or registers:
77
77
  * the envelope's verification, the keyId of a public key, and what a verified manifest means to a binary.
78
78
  */
79
- export { keyIdOf, openEnvelope } from "./lib/updates.ts";
79
+ export { keyIdOf, openEnvelope, verifyManifest } from "./lib/updates.ts";
80
80
  export type {
81
81
  AkanNativeConfig,
82
82
  AndroidSigning,
@@ -104,7 +104,7 @@ export type {
104
104
  export { macosDistributionFromEnv, requestedDistribution, windowsSigningFromEnv };
105
105
 
106
106
  /** semver of this API. A caller checks the major before it relies on anything here. */
107
- export const API_VERSION = "0.12.0";
107
+ export const API_VERSION = "0.13.0";
108
108
 
109
109
  export type AkanNativeErrorCode =
110
110
  | "CONFIG_INVALID"
@@ -326,18 +326,18 @@ export interface PublishCheckOptions extends Pick<TaskOptions, "appDir" | "confi
326
326
  /** A desktop release's CPU, which names its feed folder: this computer's by default. */
327
327
  arch?: DesktopArch;
328
328
  /**
329
- * A phone release: keyIds of updates.publicKeys it starts revoking, beside updates.revokedKeys and what the channel's
330
- * releases revoke. It is signed with a key listed after every key it revokes.
329
+ * keyIds of updates.publicKeys the release starts revoking, beside updates.revokedKeys and what the channel's releases
330
+ * revoke. It is signed with a key listed after every key it revokes.
331
331
  */
332
332
  revoke?: string[];
333
- /** A phone release that revokes a key: phones compare it with their own bundle instead of the running one. */
333
+ /** A release that revokes a key: apps compare it with their own build instead of the running release. */
334
334
  resetSequence?: boolean;
335
335
  }
336
336
 
337
337
  /**
338
338
  * What publishUpdate() refuses before it builds, without building (CONFIG_INVALID): no updates settings, a channel no
339
339
  * app could be configured for, no signing key on this machine or another app's, a desktop release whose server
340
- * presence is not the channel's previous release's, and a phone release whose revocations no phone would take. For a
340
+ * presence is not the channel's previous release's, and a release whose revocations no app would take. For a
341
341
  * caller with a long build of its own before publishUpdate.
342
342
  */
343
343
  export function checkPublishUpdate(options: PublishCheckOptions): { channel: string; out: string } {
@@ -352,8 +352,8 @@ export function checkPublishUpdate(options: PublishCheckOptions): { channel: str
352
352
  try {
353
353
  if (options.channel !== undefined) assertChannel(options.channel);
354
354
  const target = { app: options.config.app, updates };
355
- assertSigningKey(target, options.platform);
356
- releaseRevocations(target, options.platform, out, channel, options);
355
+ assertSigningKey(target);
356
+ releaseRevocations(target, options.platform, out, channel, options, options.arch);
357
357
  const server = options.server ?? !!options.config.desktop?.server;
358
358
  assertServerOfChannel({ desktop: server ? { server } : {} }, options.platform, out, channel, options.arch);
359
359
  } catch (error) {
@@ -363,8 +363,8 @@ export function checkPublishUpdate(options: PublishCheckOptions): { channel: str
363
363
  }
364
364
 
365
365
  /**
366
- * A signed release for the updates plugin (UP-1, UP-2): a release build, then `<channel>.json`, its signature and
367
- * its files under `out` (default <appDir>/.akan/native/updates), signed with the key updateKeygen() made.
366
+ * A signed release for the updates plugin (UP-1, UP-2): a release build, then its envelope and its files under `out`
367
+ * (default <appDir>/.akan/native/updates), signed with the key updateKeygen() made.
368
368
  */
369
369
  export function publishUpdate(
370
370
  options: TaskOptions & {
@@ -377,9 +377,9 @@ export function publishUpdate(
377
377
  windows?: Pick<WindowsBuild, "signing">;
378
378
  /** A desktop release's CPU, of the same OS: an x64 release from an arm64 machine. Default this computer's. */
379
379
  arch?: DesktopArch;
380
- /** A phone release: keyIds of updates.publicKeys it starts revoking (PublishCheckOptions.revoke). */
380
+ /** keyIds of updates.publicKeys the release starts revoking (PublishCheckOptions.revoke). */
381
381
  revoke?: string[];
382
- /** A phone release that revokes a key: phones compare it with their own bundle instead of the running one. */
382
+ /** A release that revokes a key: apps compare it with their own build instead of the running release. */
383
383
  resetSequence?: boolean;
384
384
  },
385
385
  ): Promise<PublishResult> {
@@ -64,16 +64,11 @@ async function publish(args: ParsedArgs, request: RevocationRequest): Promise<nu
64
64
  const requested = stringFlag(args, "channel");
65
65
  if (requested !== undefined) assertChannel(requested);
66
66
  const project = await loadProject(findAppDir(stringFlag(args, "app") ?? process.cwd()));
67
- assertSigningKey(project.config, platform);
67
+ assertSigningKey(project.config);
68
68
  const planned = requested ?? project.config.updates?.channel ?? "production";
69
- assertServerOfChannel(
70
- project.config,
71
- platform,
72
- outDir(args, project.appDir),
73
- planned,
74
- desktopArch(platform, stringFlag(args, "arch") as DesktopArch | undefined),
75
- );
76
- releaseRevocations(project.config, platform, outDir(args, project.appDir), planned, request);
69
+ const arch = desktopArch(platform, stringFlag(args, "arch") as DesktopArch | undefined);
70
+ assertServerOfChannel(project.config, platform, outDir(args, project.appDir), planned, arch);
71
+ releaseRevocations(project.config, platform, outDir(args, project.appDir), planned, request, arch);
77
72
  const { ctx, artifact } = await buildFromArgs(
78
73
  { positional: [platform], flags: args.flags },
79
74
  { mode: "production", profile: "release" },
@@ -115,17 +115,17 @@ export interface AkanNativeConfig {
115
115
  /**
116
116
  * Over-the-air updates (UP-2 web bundles on iOS / Android, UP-1 app updates on macOS), used by
117
117
  * @akanjs/native/plugins/updates. `akan-native update keygen` makes the signing key and prints its public key;
118
- * `akan-native update publish <platform>` writes signed releases for `url`. `publicKeys` lists the keys a phone
118
+ * `akan-native update publish <platform>` writes signed releases for `url`. `publicKeys` lists the keys an app
119
119
  * trusts, the online signing key first and offline spares after (a key revokes only keys before it); `publicKey` is
120
- * the one-key form, and a desktop app trusts the first. `report.url` is where a phone posts what became of each
121
- * release, at its next launch or return to the foreground.
120
+ * the one-key form, and a desktop app built before protocol v2 trusts the first. `report.url` is where a phone posts
121
+ * what became of each release, at its next launch or return to the foreground.
122
122
  */
123
123
  updates?: {
124
124
  url: string;
125
125
  publicKey?: string;
126
126
  publicKeys?: string[];
127
127
  /**
128
- * keyIds every phone release revokes (`update keygen` prints a key's), kept here so a release published from a fresh
128
+ * keyIds every release revokes (`update keygen` prints a key's), kept here so a release published from a fresh
129
129
  * folder still revokes them; `update publish --revoke` starts a revocation. A key may revoke only keys listed
130
130
  * before it in publicKeys, so a release is signed with one listed after them.
131
131
  */
@@ -133,6 +133,11 @@ export interface AkanNativeConfig {
133
133
  channel?: string;
134
134
  readyTimeout?: number;
135
135
  report?: { url: string };
136
+ /**
137
+ * The release target a desktop binary is built for: its manifests name it and the app takes only its own, so a
138
+ * release signed for one target cannot be served to another's apps. akan sets the native target's name.
139
+ */
140
+ target?: string;
136
141
  };
137
142
  /** Links that open the app, delivered through the app plugin's urlOpen (and getLaunchUrl). */
138
143
  deepLinks?: {
@@ -20,7 +20,16 @@ const KNOWN: Shape = {
20
20
  usageDescriptions: true,
21
21
  privacy: { tracking: true, trackingDomains: true, collectedDataTypes: true, accessedApis: true },
22
22
  permissions: { camera: true, microphone: true, location: true },
23
- updates: { url: true, publicKey: true, publicKeys: true, channel: true, readyTimeout: true, report: { url: true } },
23
+ updates: {
24
+ url: true,
25
+ publicKey: true,
26
+ publicKeys: true,
27
+ revokedKeys: true,
28
+ channel: true,
29
+ readyTimeout: true,
30
+ report: { url: true },
31
+ target: true,
32
+ },
24
33
  deepLinks: { schemes: true, domains: { "[]": { host: true, pathPrefixes: true } } },
25
34
  native: {
26
35
  ios: { infoPlist: true, entitlements: true },