@happier-dev/relay-server 0.1.2 → 0.2.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.
Files changed (52) hide show
  1. package/bin/happier-server.mjs +92 -101
  2. package/node_modules/@happier-dev/release-runtime/dist/.tsbuildinfo +1 -0
  3. package/node_modules/@happier-dev/release-runtime/dist/_cjs/releaseRings.js +134 -0
  4. package/node_modules/@happier-dev/release-runtime/dist/assets.d.ts +22 -0
  5. package/node_modules/@happier-dev/release-runtime/dist/assets.d.ts.map +1 -0
  6. package/node_modules/@happier-dev/release-runtime/dist/assets.js +44 -0
  7. package/node_modules/@happier-dev/release-runtime/dist/assets.js.map +1 -0
  8. package/node_modules/@happier-dev/release-runtime/dist/checksums.d.ts +5 -0
  9. package/node_modules/@happier-dev/release-runtime/dist/checksums.d.ts.map +1 -0
  10. package/node_modules/@happier-dev/release-runtime/dist/checksums.js +21 -0
  11. package/node_modules/@happier-dev/release-runtime/dist/checksums.js.map +1 -0
  12. package/node_modules/@happier-dev/release-runtime/dist/extractPlan.d.ts +14 -0
  13. package/node_modules/@happier-dev/release-runtime/dist/extractPlan.d.ts.map +1 -0
  14. package/node_modules/@happier-dev/release-runtime/dist/extractPlan.js +48 -0
  15. package/node_modules/@happier-dev/release-runtime/dist/extractPlan.js.map +1 -0
  16. package/node_modules/@happier-dev/release-runtime/dist/github.d.ts +26 -0
  17. package/node_modules/@happier-dev/release-runtime/dist/github.d.ts.map +1 -0
  18. package/node_modules/@happier-dev/release-runtime/dist/github.js +141 -0
  19. package/node_modules/@happier-dev/release-runtime/dist/github.js.map +1 -0
  20. package/node_modules/@happier-dev/release-runtime/dist/http.d.ts +18 -0
  21. package/node_modules/@happier-dev/release-runtime/dist/http.d.ts.map +1 -0
  22. package/node_modules/@happier-dev/release-runtime/dist/http.js +112 -0
  23. package/node_modules/@happier-dev/release-runtime/dist/http.js.map +1 -0
  24. package/node_modules/@happier-dev/release-runtime/dist/index.d.ts +8 -0
  25. package/node_modules/@happier-dev/release-runtime/dist/index.d.ts.map +1 -0
  26. package/node_modules/@happier-dev/release-runtime/dist/index.js +8 -0
  27. package/node_modules/@happier-dev/release-runtime/dist/index.js.map +1 -0
  28. package/node_modules/@happier-dev/release-runtime/dist/minisign.d.ts +7 -0
  29. package/node_modules/@happier-dev/release-runtime/dist/minisign.d.ts.map +1 -0
  30. package/node_modules/@happier-dev/release-runtime/dist/minisign.js +92 -0
  31. package/node_modules/@happier-dev/release-runtime/dist/minisign.js.map +1 -0
  32. package/node_modules/@happier-dev/release-runtime/dist/releaseRings.cjs +134 -0
  33. package/node_modules/@happier-dev/release-runtime/dist/releaseRings.d.ts +27 -0
  34. package/node_modules/@happier-dev/release-runtime/dist/releaseRings.d.ts.map +1 -0
  35. package/node_modules/@happier-dev/release-runtime/dist/releaseRings.js +124 -0
  36. package/node_modules/@happier-dev/release-runtime/dist/releaseRings.js.map +1 -0
  37. package/node_modules/@happier-dev/release-runtime/dist/verifiedDownload.d.ts +26 -0
  38. package/node_modules/@happier-dev/release-runtime/dist/verifiedDownload.d.ts.map +1 -0
  39. package/node_modules/@happier-dev/release-runtime/dist/verifiedDownload.js +47 -0
  40. package/node_modules/@happier-dev/release-runtime/dist/verifiedDownload.js.map +1 -0
  41. package/node_modules/@happier-dev/release-runtime/package.json +43 -0
  42. package/package.json +10 -4
  43. package/src/checksums.mjs +1 -17
  44. package/src/checksums.test.mjs +1 -2
  45. package/src/minisign.mjs +1 -94
  46. package/src/minisign.verify.test.mjs +1 -2
  47. package/src/releaseAssets.mjs +30 -30
  48. package/src/releaseAssets.test.mjs +33 -1
  49. package/src/runnerConfig.mjs +69 -0
  50. package/src/runnerConfig.test.mjs +37 -0
  51. package/src/target.mjs +48 -0
  52. package/src/target.test.mjs +54 -0
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PUBLIC_RELEASE_RING_IDS = exports.RELEASE_RING_IDS = void 0;
4
+ exports.getReleaseRingCatalogEntry = getReleaseRingCatalogEntry;
5
+ exports.listReleaseRingCatalogEntries = listReleaseRingCatalogEntries;
6
+ exports.isPublicReleaseRingId = isPublicReleaseRingId;
7
+ exports.getReleaseRingPublicLabel = getReleaseRingPublicLabel;
8
+ exports.normalizeReleaseRingId = normalizeReleaseRingId;
9
+ exports.listPublicReleaseRingCatalogEntries = listPublicReleaseRingCatalogEntries;
10
+ exports.listPublicReleaseRingLabels = listPublicReleaseRingLabels;
11
+ exports.normalizePublicReleaseRingId = normalizePublicReleaseRingId;
12
+ exports.RELEASE_RING_IDS = [
13
+ 'stable',
14
+ 'preview',
15
+ 'publicdev',
16
+ 'internalpreview',
17
+ 'internaldev',
18
+ ];
19
+ exports.PUBLIC_RELEASE_RING_IDS = ['stable', 'preview', 'publicdev'];
20
+ const releaseRingCatalog = {
21
+ stable: {
22
+ id: 'stable',
23
+ visibility: 'public',
24
+ publicLabel: 'stable',
25
+ sourceBranch: 'main',
26
+ manifestChannel: 'stable',
27
+ rollingReleaseSuffix: 'stable',
28
+ embeddedPolicyEnv: 'production',
29
+ expoAppEnv: 'production',
30
+ expoUpdatesChannel: 'production',
31
+ supportsMobileStoreSubmit: true,
32
+ },
33
+ preview: {
34
+ id: 'preview',
35
+ visibility: 'public',
36
+ publicLabel: 'preview',
37
+ sourceBranch: 'preview',
38
+ manifestChannel: 'preview',
39
+ rollingReleaseSuffix: 'preview',
40
+ embeddedPolicyEnv: 'preview',
41
+ expoAppEnv: 'preview',
42
+ expoUpdatesChannel: 'preview',
43
+ supportsMobileStoreSubmit: true,
44
+ },
45
+ publicdev: {
46
+ id: 'publicdev',
47
+ visibility: 'public',
48
+ publicLabel: 'dev',
49
+ sourceBranch: 'dev',
50
+ manifestChannel: 'publicdev',
51
+ rollingReleaseSuffix: 'dev',
52
+ embeddedPolicyEnv: 'preview',
53
+ expoAppEnv: 'preview',
54
+ expoUpdatesChannel: 'dev',
55
+ supportsMobileStoreSubmit: true,
56
+ },
57
+ internalpreview: {
58
+ id: 'internalpreview',
59
+ visibility: 'internal',
60
+ publicLabel: 'preview',
61
+ sourceBranch: 'dev',
62
+ manifestChannel: null,
63
+ rollingReleaseSuffix: null,
64
+ embeddedPolicyEnv: 'preview',
65
+ expoAppEnv: 'preview',
66
+ expoUpdatesChannel: 'internalpreview',
67
+ supportsMobileStoreSubmit: false,
68
+ },
69
+ internaldev: {
70
+ id: 'internaldev',
71
+ visibility: 'internal',
72
+ publicLabel: 'dev',
73
+ sourceBranch: 'dev',
74
+ manifestChannel: null,
75
+ rollingReleaseSuffix: null,
76
+ embeddedPolicyEnv: '',
77
+ expoAppEnv: 'development',
78
+ expoUpdatesChannel: 'internaldev',
79
+ supportsMobileStoreSubmit: false,
80
+ },
81
+ };
82
+ function getReleaseRingCatalogEntry(id) {
83
+ const entry = releaseRingCatalog[id];
84
+ if (!entry) {
85
+ throw new Error(`Unknown release ring: ${String(id)}`);
86
+ }
87
+ return entry;
88
+ }
89
+ function listReleaseRingCatalogEntries() {
90
+ return exports.RELEASE_RING_IDS.map((id) => releaseRingCatalog[id]);
91
+ }
92
+ function isPublicReleaseRingId(id) {
93
+ return getReleaseRingCatalogEntry(id).visibility === 'public';
94
+ }
95
+ function getReleaseRingPublicLabel(id) {
96
+ return getReleaseRingCatalogEntry(id).publicLabel;
97
+ }
98
+ const releaseRingAliases = {
99
+ stable: 'stable',
100
+ production: 'stable',
101
+ prod: 'stable',
102
+ preview: 'preview',
103
+ publicdev: 'publicdev',
104
+ 'public-dev': 'publicdev',
105
+ public_dev: 'publicdev',
106
+ dev: 'publicdev',
107
+ internalpreview: 'internalpreview',
108
+ 'internal-preview': 'internalpreview',
109
+ internal_preview: 'internalpreview',
110
+ canary: 'internalpreview',
111
+ internaldev: 'internaldev',
112
+ 'internal-dev': 'internaldev',
113
+ internal_dev: 'internaldev',
114
+ development: 'internaldev',
115
+ };
116
+ function normalizeReleaseRingId(raw) {
117
+ const value = String(raw ?? '').trim().toLowerCase();
118
+ if (!value)
119
+ return '';
120
+ return releaseRingAliases[value] ?? '';
121
+ }
122
+ function listPublicReleaseRingCatalogEntries() {
123
+ return listReleaseRingCatalogEntries().filter((entry) => entry.visibility === 'public');
124
+ }
125
+ function listPublicReleaseRingLabels() {
126
+ return exports.PUBLIC_RELEASE_RING_IDS.map((id) => releaseRingCatalog[id].publicLabel);
127
+ }
128
+ function normalizePublicReleaseRingId(raw) {
129
+ const ringId = normalizeReleaseRingId(raw);
130
+ if (!ringId || !isPublicReleaseRingId(ringId)) {
131
+ return '';
132
+ }
133
+ return ringId;
134
+ }
@@ -0,0 +1,27 @@
1
+ export declare const RELEASE_RING_IDS: readonly ["stable", "preview", "publicdev", "internalpreview", "internaldev"];
2
+ export type ReleaseRingId = (typeof RELEASE_RING_IDS)[number];
3
+ export declare const PUBLIC_RELEASE_RING_IDS: readonly ["stable", "preview", "publicdev"];
4
+ export type PublicReleaseRingId = (typeof PUBLIC_RELEASE_RING_IDS)[number];
5
+ export type ReleaseRingVisibility = 'public' | 'internal';
6
+ export type PublicReleaseRingLabel = 'stable' | 'preview' | 'dev';
7
+ export interface ReleaseRingCatalogEntry {
8
+ id: ReleaseRingId;
9
+ visibility: ReleaseRingVisibility;
10
+ publicLabel: PublicReleaseRingLabel;
11
+ sourceBranch: 'main' | 'preview' | 'dev';
12
+ manifestChannel: 'stable' | 'preview' | 'publicdev' | null;
13
+ rollingReleaseSuffix: 'stable' | 'preview' | 'dev' | null;
14
+ embeddedPolicyEnv: 'production' | 'preview' | '';
15
+ expoAppEnv: 'production' | 'preview' | 'development';
16
+ expoUpdatesChannel: 'production' | 'preview' | 'dev' | 'internalpreview' | 'internaldev';
17
+ supportsMobileStoreSubmit: boolean;
18
+ }
19
+ export declare function getReleaseRingCatalogEntry(id: ReleaseRingId): ReleaseRingCatalogEntry;
20
+ export declare function listReleaseRingCatalogEntries(): readonly ReleaseRingCatalogEntry[];
21
+ export declare function isPublicReleaseRingId(id: ReleaseRingId): boolean;
22
+ export declare function getReleaseRingPublicLabel(id: ReleaseRingId): PublicReleaseRingLabel;
23
+ export declare function normalizeReleaseRingId(raw: unknown): ReleaseRingId | '';
24
+ export declare function listPublicReleaseRingCatalogEntries(): readonly ReleaseRingCatalogEntry[];
25
+ export declare function listPublicReleaseRingLabels(): readonly PublicReleaseRingLabel[];
26
+ export declare function normalizePublicReleaseRingId(raw: unknown): PublicReleaseRingId | '';
27
+ //# sourceMappingURL=releaseRings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"releaseRings.d.ts","sourceRoot":"","sources":["../src/releaseRings.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,+EAMnB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC9D,eAAO,MAAM,uBAAuB,6CAA8C,CAAC;AACnF,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC3E,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC1D,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAC;AAElE,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,aAAa,CAAC;IAClB,UAAU,EAAE,qBAAqB,CAAC;IAClC,WAAW,EAAE,sBAAsB,CAAC;IACpC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC;IACzC,eAAe,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,IAAI,CAAC;IAC3D,oBAAoB,EAAE,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC;IAC1D,iBAAiB,EAAE,YAAY,GAAG,SAAS,GAAG,EAAE,CAAC;IACjD,UAAU,EAAE,YAAY,GAAG,SAAS,GAAG,aAAa,CAAC;IACrD,kBAAkB,EAAE,YAAY,GAAG,SAAS,GAAG,KAAK,GAAG,iBAAiB,GAAG,aAAa,CAAC;IACzF,yBAAyB,EAAE,OAAO,CAAC;CACpC;AAiED,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,aAAa,GAAG,uBAAuB,CAMrF;AAED,wBAAgB,6BAA6B,IAAI,SAAS,uBAAuB,EAAE,CAElF;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,aAAa,GAAG,OAAO,CAEhE;AAED,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,aAAa,GAAG,sBAAsB,CAEnF;AAqBD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,GAAG,EAAE,CAIvE;AAED,wBAAgB,mCAAmC,IAAI,SAAS,uBAAuB,EAAE,CAExF;AAED,wBAAgB,2BAA2B,IAAI,SAAS,sBAAsB,EAAE,CAE/E;AAED,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,OAAO,GAAG,mBAAmB,GAAG,EAAE,CAMnF"}
@@ -0,0 +1,124 @@
1
+ export const RELEASE_RING_IDS = [
2
+ 'stable',
3
+ 'preview',
4
+ 'publicdev',
5
+ 'internalpreview',
6
+ 'internaldev',
7
+ ];
8
+ export const PUBLIC_RELEASE_RING_IDS = ['stable', 'preview', 'publicdev'];
9
+ const releaseRingCatalog = {
10
+ stable: {
11
+ id: 'stable',
12
+ visibility: 'public',
13
+ publicLabel: 'stable',
14
+ sourceBranch: 'main',
15
+ manifestChannel: 'stable',
16
+ rollingReleaseSuffix: 'stable',
17
+ embeddedPolicyEnv: 'production',
18
+ expoAppEnv: 'production',
19
+ expoUpdatesChannel: 'production',
20
+ supportsMobileStoreSubmit: true,
21
+ },
22
+ preview: {
23
+ id: 'preview',
24
+ visibility: 'public',
25
+ publicLabel: 'preview',
26
+ sourceBranch: 'preview',
27
+ manifestChannel: 'preview',
28
+ rollingReleaseSuffix: 'preview',
29
+ embeddedPolicyEnv: 'preview',
30
+ expoAppEnv: 'preview',
31
+ expoUpdatesChannel: 'preview',
32
+ supportsMobileStoreSubmit: true,
33
+ },
34
+ publicdev: {
35
+ id: 'publicdev',
36
+ visibility: 'public',
37
+ publicLabel: 'dev',
38
+ sourceBranch: 'dev',
39
+ manifestChannel: 'publicdev',
40
+ rollingReleaseSuffix: 'dev',
41
+ embeddedPolicyEnv: 'preview',
42
+ expoAppEnv: 'preview',
43
+ expoUpdatesChannel: 'dev',
44
+ supportsMobileStoreSubmit: true,
45
+ },
46
+ internalpreview: {
47
+ id: 'internalpreview',
48
+ visibility: 'internal',
49
+ publicLabel: 'preview',
50
+ sourceBranch: 'dev',
51
+ manifestChannel: null,
52
+ rollingReleaseSuffix: null,
53
+ embeddedPolicyEnv: 'preview',
54
+ expoAppEnv: 'preview',
55
+ expoUpdatesChannel: 'internalpreview',
56
+ supportsMobileStoreSubmit: false,
57
+ },
58
+ internaldev: {
59
+ id: 'internaldev',
60
+ visibility: 'internal',
61
+ publicLabel: 'dev',
62
+ sourceBranch: 'dev',
63
+ manifestChannel: null,
64
+ rollingReleaseSuffix: null,
65
+ embeddedPolicyEnv: '',
66
+ expoAppEnv: 'development',
67
+ expoUpdatesChannel: 'internaldev',
68
+ supportsMobileStoreSubmit: false,
69
+ },
70
+ };
71
+ export function getReleaseRingCatalogEntry(id) {
72
+ const entry = releaseRingCatalog[id];
73
+ if (!entry) {
74
+ throw new Error(`Unknown release ring: ${String(id)}`);
75
+ }
76
+ return entry;
77
+ }
78
+ export function listReleaseRingCatalogEntries() {
79
+ return RELEASE_RING_IDS.map((id) => releaseRingCatalog[id]);
80
+ }
81
+ export function isPublicReleaseRingId(id) {
82
+ return getReleaseRingCatalogEntry(id).visibility === 'public';
83
+ }
84
+ export function getReleaseRingPublicLabel(id) {
85
+ return getReleaseRingCatalogEntry(id).publicLabel;
86
+ }
87
+ const releaseRingAliases = {
88
+ stable: 'stable',
89
+ production: 'stable',
90
+ prod: 'stable',
91
+ preview: 'preview',
92
+ publicdev: 'publicdev',
93
+ 'public-dev': 'publicdev',
94
+ public_dev: 'publicdev',
95
+ dev: 'publicdev',
96
+ internalpreview: 'internalpreview',
97
+ 'internal-preview': 'internalpreview',
98
+ internal_preview: 'internalpreview',
99
+ canary: 'internalpreview',
100
+ internaldev: 'internaldev',
101
+ 'internal-dev': 'internaldev',
102
+ internal_dev: 'internaldev',
103
+ development: 'internaldev',
104
+ };
105
+ export function normalizeReleaseRingId(raw) {
106
+ const value = String(raw ?? '').trim().toLowerCase();
107
+ if (!value)
108
+ return '';
109
+ return releaseRingAliases[value] ?? '';
110
+ }
111
+ export function listPublicReleaseRingCatalogEntries() {
112
+ return listReleaseRingCatalogEntries().filter((entry) => entry.visibility === 'public');
113
+ }
114
+ export function listPublicReleaseRingLabels() {
115
+ return PUBLIC_RELEASE_RING_IDS.map((id) => releaseRingCatalog[id].publicLabel);
116
+ }
117
+ export function normalizePublicReleaseRingId(raw) {
118
+ const ringId = normalizeReleaseRingId(raw);
119
+ if (!ringId || !isPublicReleaseRingId(ringId)) {
120
+ return '';
121
+ }
122
+ return ringId;
123
+ }
124
+ //# sourceMappingURL=releaseRings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"releaseRings.js","sourceRoot":"","sources":["../src/releaseRings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ type ReleaseAsset = Readonly<{
2
+ name: string;
3
+ url: string;
4
+ }>;
5
+ export type ReleaseAssetBundle = Readonly<{
6
+ version: string;
7
+ archive: ReleaseAsset;
8
+ checksums: ReleaseAsset;
9
+ checksumsSig: ReleaseAsset;
10
+ }>;
11
+ export declare function downloadVerifiedReleaseAssetBundle(params: Readonly<{
12
+ bundle: ReleaseAssetBundle;
13
+ destDir: string;
14
+ pubkeyFile: string;
15
+ userAgent?: string;
16
+ }>): Promise<Readonly<{
17
+ version: string;
18
+ archiveName: string;
19
+ archivePath: string;
20
+ source: {
21
+ archiveUrl: string;
22
+ checksumsUrl: string;
23
+ };
24
+ }>>;
25
+ export {};
26
+ //# sourceMappingURL=verifiedDownload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifiedDownload.d.ts","sourceRoot":"","sources":["../src/verifiedDownload.ts"],"names":[],"mappings":"AAQA,KAAK,YAAY,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE5D,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,YAAY,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC,CAAC;AAcH,wBAAsB,kCAAkC,CAAC,MAAM,EAAE,QAAQ,CAAC;IACxE,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD,CAAC,CAAC,CAgCF"}
@@ -0,0 +1,47 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, writeFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { lookupSha256 } from './checksums.js';
5
+ import { requestBytes, requestText } from './http.js';
6
+ import { verifyMinisign } from './minisign.js';
7
+ async function fetchText(url, { userAgent = 'happier-release-runtime' } = {}) {
8
+ return await requestText({ url, headers: { 'user-agent': userAgent } });
9
+ }
10
+ async function fetchBytes(url, { userAgent = 'happier-release-runtime' } = {}) {
11
+ return await requestBytes({ url, headers: { 'user-agent': userAgent } });
12
+ }
13
+ function sha256Hex(bytes) {
14
+ return createHash('sha256').update(bytes).digest('hex');
15
+ }
16
+ export async function downloadVerifiedReleaseAssetBundle(params) {
17
+ const bundle = params.bundle;
18
+ const destDir = String(params.destDir ?? '').trim();
19
+ const pubkeyFile = String(params.pubkeyFile ?? '');
20
+ const userAgent = String(params.userAgent ?? '').trim() || 'happier-release-runtime';
21
+ if (!destDir)
22
+ throw new Error('[download] destDir is required');
23
+ if (!pubkeyFile.trim())
24
+ throw new Error('[download] pubkeyFile is required');
25
+ await mkdir(destDir, { recursive: true });
26
+ const checksumsText = await fetchText(bundle.checksums.url, { userAgent });
27
+ const sigFile = await fetchText(bundle.checksumsSig.url, { userAgent });
28
+ const ok = verifyMinisign({ message: Buffer.from(checksumsText, 'utf-8'), pubkeyFile, sigFile });
29
+ if (!ok) {
30
+ throw new Error('[download] signature verification failed for checksums file');
31
+ }
32
+ const expected = lookupSha256({ checksumsText, filename: bundle.archive.name });
33
+ const bytes = await fetchBytes(bundle.archive.url, { userAgent });
34
+ const actual = sha256Hex(bytes);
35
+ if (actual !== expected) {
36
+ throw new Error(`[download] checksum verification failed for ${bundle.archive.name}`);
37
+ }
38
+ const archivePath = join(destDir, bundle.archive.name);
39
+ await writeFile(archivePath, bytes);
40
+ return {
41
+ version: String(bundle.version ?? ''),
42
+ archiveName: bundle.archive.name,
43
+ archivePath,
44
+ source: { archiveUrl: bundle.archive.url, checksumsUrl: bundle.checksums.url },
45
+ };
46
+ }
47
+ //# sourceMappingURL=verifiedDownload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifiedDownload.js","sourceRoot":"","sources":["../src/verifiedDownload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@happier-dev/release-runtime",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ },
13
+ "./minisign": {
14
+ "types": "./dist/minisign.d.ts",
15
+ "default": "./dist/minisign.js"
16
+ },
17
+ "./checksums": {
18
+ "types": "./dist/checksums.d.ts",
19
+ "default": "./dist/checksums.js"
20
+ },
21
+ "./assets": {
22
+ "types": "./dist/assets.d.ts",
23
+ "default": "./dist/assets.js"
24
+ },
25
+ "./extractPlan": {
26
+ "types": "./dist/extractPlan.d.ts",
27
+ "default": "./dist/extractPlan.js"
28
+ },
29
+ "./verifiedDownload": {
30
+ "types": "./dist/verifiedDownload.d.ts",
31
+ "default": "./dist/verifiedDownload.js"
32
+ },
33
+ "./github": {
34
+ "types": "./dist/github.d.ts",
35
+ "default": "./dist/github.js"
36
+ },
37
+ "./releaseRings": {
38
+ "types": "./dist/releaseRings.d.ts",
39
+ "require": "./releaseRings.cjs",
40
+ "default": "./dist/releaseRings.js"
41
+ }
42
+ }
43
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happier-dev/relay-server",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Happier server runner (downloads and verifies the correct server binary for your platform).",
5
5
  "repository": "https://github.com/happier-dev/happier.git",
6
6
  "author": "Leeroy Brun <leeroy.brun@gmail.com>",
@@ -15,14 +15,20 @@
15
15
  "bin",
16
16
  "src"
17
17
  ],
18
+ "bundledDependencies": [
19
+ "@happier-dev/release-runtime"
20
+ ],
21
+ "dependencies": {
22
+ "@happier-dev/release-runtime": "0.0.0"
23
+ },
18
24
  "engines": {
19
25
  "node": ">=22"
20
26
  },
21
27
  "publishConfig": {
22
- "access": "public",
23
- "provenance": true
28
+ "access": "public"
24
29
  },
25
30
  "scripts": {
26
- "test": "node --test"
31
+ "prepack": "node ./scripts/bundleWorkspaceDeps.mjs",
32
+ "test": "HAPPIER_FEATURE_POLICY_ENV= node --test"
27
33
  }
28
34
  }
package/src/checksums.mjs CHANGED
@@ -1,17 +1 @@
1
- export function lookupSha256({ checksumsText, filename }) {
2
- const target = String(filename ?? '').trim();
3
- if (!target) throw new Error('[checksums] filename is required');
4
-
5
- const text = String(checksumsText ?? '');
6
- const lines = text.split('\n');
7
- for (const line of lines) {
8
- const trimmed = line.trim();
9
- if (!trimmed) continue;
10
- const m = /^([0-9a-fA-F]{8,})\s+(.+)$/.exec(trimmed);
11
- if (!m) continue;
12
- const hash = m[1].toLowerCase();
13
- const file = m[2].trim();
14
- if (file === target) return hash;
15
- }
16
- throw new Error(`[checksums] sha256 not found for ${target}`);
17
- }
1
+ export { lookupSha256 } from '@happier-dev/release-runtime/checksums';
@@ -1,7 +1,7 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
 
4
- import { lookupSha256 } from './checksums.mjs';
4
+ import { lookupSha256 } from '@happier-dev/release-runtime/checksums';
5
5
 
6
6
  test('lookupSha256 returns sha256 for matching filename', () => {
7
7
  const text = [
@@ -15,4 +15,3 @@ test('lookupSha256 returns sha256 for matching filename', () => {
15
15
  test('lookupSha256 throws when filename not present', () => {
16
16
  assert.throws(() => lookupSha256({ checksumsText: 'aaaa other', filename: 'missing' }));
17
17
  });
18
-
package/src/minisign.mjs CHANGED
@@ -1,94 +1 @@
1
- import { createHash, createPublicKey, verify } from 'node:crypto';
2
-
3
- const ED25519_SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex');
4
-
5
- function decodeBase64Line(line, expectedBytes) {
6
- const bytes = Buffer.from(String(line ?? '').trim(), 'base64');
7
- if (expectedBytes != null && bytes.length !== expectedBytes) {
8
- throw new Error(`[minisign] expected ${expectedBytes} bytes, got ${bytes.length}`);
9
- }
10
- return bytes;
11
- }
12
-
13
- function parseMinisignPublicKeyFile(pubkeyFile) {
14
- const lines = String(pubkeyFile ?? '')
15
- .split('\n')
16
- .map((l) => l.trim())
17
- .filter(Boolean);
18
- if (lines.length < 2) throw new Error('[minisign] invalid public key file');
19
- const payload = lines.at(-1);
20
- const bytes = decodeBase64Line(payload, 42);
21
- const signatureAlgorithm = bytes.subarray(0, 2);
22
- const keyId = bytes.subarray(2, 10);
23
- const rawPublicKey = bytes.subarray(10, 42);
24
- return { signatureAlgorithm, keyId, rawPublicKey };
25
- }
26
-
27
- function parseMinisignSignatureFile(sigFile) {
28
- const lines = String(sigFile ?? '').split('\n');
29
- if (lines.length < 4) throw new Error('[minisign] invalid signature file');
30
-
31
- const untrustedPayload = String(lines[1] ?? '').trim();
32
- const trustedComment = String(lines[2] ?? '');
33
- const globalPayload = String(lines[3] ?? '').trim();
34
-
35
- const untrustedBytes = decodeBase64Line(untrustedPayload, 74);
36
- const signatureAlgorithm = untrustedBytes.subarray(0, 2);
37
- const keyId = untrustedBytes.subarray(2, 10);
38
- const signature = untrustedBytes.subarray(10, 74);
39
-
40
- const globalSignature = decodeBase64Line(globalPayload, 64);
41
-
42
- if (!trustedComment.startsWith('trusted comment: ')) {
43
- throw new Error('[minisign] unexpected trusted comment format');
44
- }
45
- const trustedSuffix = Buffer.from(trustedComment.slice('trusted comment: '.length), 'utf-8');
46
-
47
- return { signatureAlgorithm, keyId, signature, trustedSuffix, globalSignature };
48
- }
49
-
50
- function createEd25519PublicKey(rawPublicKey) {
51
- if (!Buffer.isBuffer(rawPublicKey) || rawPublicKey.length !== 32) {
52
- throw new Error('[minisign] invalid Ed25519 public key length');
53
- }
54
- const spki = Buffer.concat([ED25519_SPKI_PREFIX, rawPublicKey]);
55
- return createPublicKey({ key: spki, format: 'der', type: 'spki' });
56
- }
57
-
58
- function bytesEqual(a, b) {
59
- if (!a || !b) return false;
60
- if (a.length !== b.length) return false;
61
- // constant-time compare not required here (public data), but keep it simple.
62
- return Buffer.compare(a, b) === 0;
63
- }
64
-
65
- export function verifyMinisign({ message, pubkeyFile, sigFile }) {
66
- const bin = Buffer.isBuffer(message) ? message : Buffer.from(message ?? '');
67
- const pubkey = parseMinisignPublicKeyFile(pubkeyFile);
68
- const sig = parseMinisignSignatureFile(sigFile);
69
-
70
- if (!bytesEqual(pubkey.signatureAlgorithm, Buffer.from('Ed'))) {
71
- throw new Error('[minisign] incompatible public key signature algorithm');
72
- }
73
- if (!bytesEqual(pubkey.keyId, sig.keyId)) {
74
- throw new Error('[minisign] incompatible key identifiers');
75
- }
76
-
77
- let prehashed = false;
78
- if (bytesEqual(sig.signatureAlgorithm, Buffer.from('Ed'))) {
79
- prehashed = false;
80
- } else if (bytesEqual(sig.signatureAlgorithm, Buffer.from('ED'))) {
81
- prehashed = true;
82
- } else {
83
- throw new Error('[minisign] unsupported signature algorithm');
84
- }
85
-
86
- const publicKey = createEd25519PublicKey(pubkey.rawPublicKey);
87
- const payload = prehashed ? createHash('blake2b512').update(bin).digest() : bin;
88
-
89
- const okSig = verify(null, payload, publicKey, sig.signature);
90
- if (!okSig) return false;
91
-
92
- const okGlobal = verify(null, Buffer.concat([sig.signature, sig.trustedSuffix]), publicKey, sig.globalSignature);
93
- return okGlobal;
94
- }
1
+ export { verifyMinisign } from '@happier-dev/release-runtime/minisign';
@@ -2,7 +2,7 @@ import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { generateKeyPairSync, sign } from 'node:crypto';
4
4
 
5
- import { verifyMinisign } from './minisign.mjs';
5
+ import { verifyMinisign } from '@happier-dev/release-runtime/minisign';
6
6
 
7
7
  function b64(buf) {
8
8
  return Buffer.from(buf).toString('base64');
@@ -72,4 +72,3 @@ test('verifyMinisign rejects invalid signatures', () => {
72
72
 
73
73
  assert.equal(verifyMinisign({ message: Buffer.from('tampered', 'utf-8'), pubkeyFile, sigFile }), false);
74
74
  });
75
-