@vtechcom/hexcore 2.0.0-beta.1

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 (173) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/LICENSE +201 -0
  3. package/README.md +283 -0
  4. package/dist/app.module.js +55 -0
  5. package/dist/app.module.js.map +1 -0
  6. package/dist/auth.js +151 -0
  7. package/dist/auth.js.map +1 -0
  8. package/dist/chain/cost-models.js +81 -0
  9. package/dist/chain/cost-models.js.map +1 -0
  10. package/dist/chain/provider.js +269 -0
  11. package/dist/chain/provider.js.map +1 -0
  12. package/dist/chain/socket.js +48 -0
  13. package/dist/chain/socket.js.map +1 -0
  14. package/dist/cli/doctor.js +43 -0
  15. package/dist/cli/doctor.js.map +1 -0
  16. package/dist/cli/hexcore.js +435 -0
  17. package/dist/cli/hexcore.js.map +1 -0
  18. package/dist/common/auth.guard.js +66 -0
  19. package/dist/common/auth.guard.js.map +1 -0
  20. package/dist/common/http.js +171 -0
  21. package/dist/common/http.js.map +1 -0
  22. package/dist/common/zod-validation.pipe.js +47 -0
  23. package/dist/common/zod-validation.pipe.js.map +1 -0
  24. package/dist/config.js +354 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/config.module.js +35 -0
  27. package/dist/config.module.js.map +1 -0
  28. package/dist/controllers/cardano.controller.js +173 -0
  29. package/dist/controllers/cardano.controller.js.map +1 -0
  30. package/dist/controllers/heads.controller.js +225 -0
  31. package/dist/controllers/heads.controller.js.map +1 -0
  32. package/dist/controllers/setup.controller.js +127 -0
  33. package/dist/controllers/setup.controller.js.map +1 -0
  34. package/dist/controllers/system.controller.js +153 -0
  35. package/dist/controllers/system.controller.js.map +1 -0
  36. package/dist/db/database.module.js +73 -0
  37. package/dist/db/database.module.js.map +1 -0
  38. package/dist/db/index.js +135 -0
  39. package/dist/db/index.js.map +1 -0
  40. package/dist/db/repositories.js +220 -0
  41. package/dist/db/repositories.js.map +1 -0
  42. package/dist/docker/container-stats.js +134 -0
  43. package/dist/docker/container-stats.js.map +1 -0
  44. package/dist/docker/docker.service.js +335 -0
  45. package/dist/docker/docker.service.js.map +1 -0
  46. package/dist/hydra/argv.js +172 -0
  47. package/dist/hydra/argv.js.map +1 -0
  48. package/dist/hydra/blockfrost-keys.js +15 -0
  49. package/dist/hydra/blockfrost-keys.js.map +1 -0
  50. package/dist/hydra/boot-progress.js +165 -0
  51. package/dist/hydra/boot-progress.js.map +1 -0
  52. package/dist/hydra/capabilities.js +131 -0
  53. package/dist/hydra/capabilities.js.map +1 -0
  54. package/dist/hydra/head.service.js +1072 -0
  55. package/dist/hydra/head.service.js.map +1 -0
  56. package/dist/hydra/keys.js +301 -0
  57. package/dist/hydra/keys.js.map +1 -0
  58. package/dist/hydra/node-monitor.service.js +265 -0
  59. package/dist/hydra/node-monitor.service.js.map +1 -0
  60. package/dist/hydra/ws-client.js +177 -0
  61. package/dist/hydra/ws-client.js.map +1 -0
  62. package/dist/main.js +106 -0
  63. package/dist/main.js.map +1 -0
  64. package/dist/preflight.js +215 -0
  65. package/dist/preflight.js.map +1 -0
  66. package/dist/settings.js +243 -0
  67. package/dist/settings.js.map +1 -0
  68. package/dist/setup.service.js +257 -0
  69. package/dist/setup.service.js.map +1 -0
  70. package/dist/version.js +46 -0
  71. package/dist/version.js.map +1 -0
  72. package/node_modules/@hexcore/shared/dist/cjs/api.d.ts +730 -0
  73. package/node_modules/@hexcore/shared/dist/cjs/api.d.ts.map +1 -0
  74. package/node_modules/@hexcore/shared/dist/cjs/api.js +358 -0
  75. package/node_modules/@hexcore/shared/dist/cjs/api.js.map +1 -0
  76. package/node_modules/@hexcore/shared/dist/cjs/domain.d.ts +298 -0
  77. package/node_modules/@hexcore/shared/dist/cjs/domain.d.ts.map +1 -0
  78. package/node_modules/@hexcore/shared/dist/cjs/domain.js +49 -0
  79. package/node_modules/@hexcore/shared/dist/cjs/domain.js.map +1 -0
  80. package/node_modules/@hexcore/shared/dist/cjs/hydra-versions.d.ts +279 -0
  81. package/node_modules/@hexcore/shared/dist/cjs/hydra-versions.d.ts.map +1 -0
  82. package/node_modules/@hexcore/shared/dist/cjs/hydra-versions.js +453 -0
  83. package/node_modules/@hexcore/shared/dist/cjs/hydra-versions.js.map +1 -0
  84. package/node_modules/@hexcore/shared/dist/cjs/index.d.ts +7 -0
  85. package/node_modules/@hexcore/shared/dist/cjs/index.d.ts.map +1 -0
  86. package/node_modules/@hexcore/shared/dist/cjs/index.js +23 -0
  87. package/node_modules/@hexcore/shared/dist/cjs/index.js.map +1 -0
  88. package/node_modules/@hexcore/shared/dist/cjs/naming.d.ts +118 -0
  89. package/node_modules/@hexcore/shared/dist/cjs/naming.d.ts.map +1 -0
  90. package/node_modules/@hexcore/shared/dist/cjs/naming.js +103 -0
  91. package/node_modules/@hexcore/shared/dist/cjs/naming.js.map +1 -0
  92. package/node_modules/@hexcore/shared/dist/cjs/offline.d.ts +73 -0
  93. package/node_modules/@hexcore/shared/dist/cjs/offline.d.ts.map +1 -0
  94. package/node_modules/@hexcore/shared/dist/cjs/offline.js +80 -0
  95. package/node_modules/@hexcore/shared/dist/cjs/offline.js.map +1 -0
  96. package/node_modules/@hexcore/shared/dist/cjs/protocol-params.d.ts +79 -0
  97. package/node_modules/@hexcore/shared/dist/cjs/protocol-params.d.ts.map +1 -0
  98. package/node_modules/@hexcore/shared/dist/cjs/protocol-params.js +223 -0
  99. package/node_modules/@hexcore/shared/dist/cjs/protocol-params.js.map +1 -0
  100. package/node_modules/@hexcore/shared/dist/esm/api.js +355 -0
  101. package/node_modules/@hexcore/shared/dist/esm/api.js.map +1 -0
  102. package/node_modules/@hexcore/shared/dist/esm/domain.js +46 -0
  103. package/node_modules/@hexcore/shared/dist/esm/domain.js.map +1 -0
  104. package/node_modules/@hexcore/shared/dist/esm/hydra-versions.js +441 -0
  105. package/node_modules/@hexcore/shared/dist/esm/hydra-versions.js.map +1 -0
  106. package/node_modules/@hexcore/shared/dist/esm/index.js +7 -0
  107. package/node_modules/@hexcore/shared/dist/esm/index.js.map +1 -0
  108. package/node_modules/@hexcore/shared/dist/esm/naming.js +95 -0
  109. package/node_modules/@hexcore/shared/dist/esm/naming.js.map +1 -0
  110. package/node_modules/@hexcore/shared/dist/esm/offline.js +75 -0
  111. package/node_modules/@hexcore/shared/dist/esm/offline.js.map +1 -0
  112. package/node_modules/@hexcore/shared/dist/esm/package.json +3 -0
  113. package/node_modules/@hexcore/shared/dist/esm/protocol-params.js +217 -0
  114. package/node_modules/@hexcore/shared/dist/esm/protocol-params.js.map +1 -0
  115. package/node_modules/@hexcore/shared/package.json +15 -0
  116. package/package.json +67 -0
  117. package/web/200.html +23 -0
  118. package/web/404.html +23 -0
  119. package/web/_nuxt/2MxohCD-.js +1 -0
  120. package/web/_nuxt/4pFXjB_u.js +1 -0
  121. package/web/_nuxt/B-v0dEQX.js +1 -0
  122. package/web/_nuxt/B4yE3U25.js +1 -0
  123. package/web/_nuxt/BFh8Ai0L.js +1 -0
  124. package/web/_nuxt/BgPn4NJH.js +1 -0
  125. package/web/_nuxt/Bj1xviSh.js +1 -0
  126. package/web/_nuxt/BnotlrL7.js +1 -0
  127. package/web/_nuxt/C1YRg2ic.js +1 -0
  128. package/web/_nuxt/CGD7MYQH.js +1 -0
  129. package/web/_nuxt/CQcG7Bu4.js +1 -0
  130. package/web/_nuxt/CS3KqpH_.js +1 -0
  131. package/web/_nuxt/CT-yt694.js +1 -0
  132. package/web/_nuxt/CZK6xUH-.js +1 -0
  133. package/web/_nuxt/CcdyYRYz.js +1 -0
  134. package/web/_nuxt/CePNTU1S.js +1 -0
  135. package/web/_nuxt/CgPLsCeU.js +5 -0
  136. package/web/_nuxt/CkCrahXt.js +1 -0
  137. package/web/_nuxt/CnOqDT9k.js +3 -0
  138. package/web/_nuxt/CqsSss-D.js +1 -0
  139. package/web/_nuxt/Cr8dL64Q.js +1 -0
  140. package/web/_nuxt/D3CwzwU0.js +1 -0
  141. package/web/_nuxt/DDANn6-H.js +1 -0
  142. package/web/_nuxt/DDl9uKIA.js +1 -0
  143. package/web/_nuxt/DL9i0ayn.js +1 -0
  144. package/web/_nuxt/DLNoK9BC.js +1 -0
  145. package/web/_nuxt/DLztFeOQ.js +1 -0
  146. package/web/_nuxt/DPihKXdt.js +1 -0
  147. package/web/_nuxt/DXyr6Naa.js +1 -0
  148. package/web/_nuxt/DeDg5p0D.js +1 -0
  149. package/web/_nuxt/DgDlQiDU.js +1 -0
  150. package/web/_nuxt/DyPI7qJE.js +30 -0
  151. package/web/_nuxt/LGfPBi70.js +1 -0
  152. package/web/_nuxt/Onf26W-r.js +1 -0
  153. package/web/_nuxt/QZNQe_OX.js +1 -0
  154. package/web/_nuxt/Y8IJM-iz.js +1 -0
  155. package/web/_nuxt/YUGC0nt0.js +1 -0
  156. package/web/_nuxt/builds/latest.json +1 -0
  157. package/web/_nuxt/builds/meta/7e461629-93e2-4694-b237-6d5c6a85c97c.json +1 -0
  158. package/web/_nuxt/builds/meta/dev.json +1 -0
  159. package/web/_nuxt/entry.BxsAxZxf.css +1 -0
  160. package/web/_nuxt/error-404.XbtAw-qw.css +1 -0
  161. package/web/_nuxt/error-500.CNHVltWM.css +1 -0
  162. package/web/_nuxt/rS90pPZ_.js +1 -0
  163. package/web/_nuxt/rhEiP908.js +1 -0
  164. package/web/_nuxt/vSj9Ec0g.js +1 -0
  165. package/web/_nuxt/woNjBJMN.js +1 -0
  166. package/web/favicon.svg +28 -0
  167. package/web/heads/index.html +23 -0
  168. package/web/heads/new/index.html +23 -0
  169. package/web/index.html +23 -0
  170. package/web/login/index.html +23 -0
  171. package/web/logo.svg +56 -0
  172. package/web/settings/index.html +23 -0
  173. package/web/setup/index.html +23 -0
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SECRET_KEYS = exports.SETTINGS_KEYS = void 0;
4
+ exports.hexcoreHome = hexcoreHome;
5
+ exports.settingsPath = settingsPath;
6
+ exports.defaultStateDir = defaultStateDir;
7
+ exports.expandHome = expandHome;
8
+ exports.absolute = absolute;
9
+ exports.readSettings = readSettings;
10
+ exports.writeSettings = writeSettings;
11
+ exports.clearSettings = clearSettings;
12
+ exports.installId = installId;
13
+ exports.ensureSetupToken = ensureSetupToken;
14
+ exports.readSetupToken = readSetupToken;
15
+ exports.clearSetupToken = clearSetupToken;
16
+ exports.mergeLayers = mergeLayers;
17
+ exports.sourceOf = sourceOf;
18
+ /**
19
+ * Persisted settings, and where Hexcore keeps its things.
20
+ *
21
+ * `config.ts` answers "what is the running configuration". This answers the
22
+ * question underneath it: **where does that configuration come from when nobody
23
+ * has written a `.env`.** Standing Hexcore up used to mean editing 123 lines of
24
+ * `.env` by hand, which is where a non-technical operator stopped — and which a
25
+ * globally installed CLI cannot use at all, since `.env` is read from the
26
+ * current directory and `hexcore` is run from wherever you happen to be.
27
+ *
28
+ * ## Layering
29
+ *
30
+ * Four sources, highest first. Every one of them is reported by
31
+ * `describeProvenance`, because the failure mode of layered configuration is
32
+ * not a wrong value, it is a value nobody can explain.
33
+ *
34
+ * 1. **A real environment variable.** Containers and CI set these, and they
35
+ * must beat anything on disk.
36
+ * 2. **`.env` in the current directory**, loaded by dotenv, which does not
37
+ * overwrite an existing environment variable — so (1) still wins.
38
+ * 3. **`<home>/config.json`**, written by the setup wizard or `hexcore init`.
39
+ * 4. The schema defaults in `config.ts`.
40
+ *
41
+ * The settings file holds env-style keys deliberately: it IS an env layer that
42
+ * lives somewhere stable, and describing it as anything else would invite a
43
+ * second name for every setting.
44
+ *
45
+ * ## Where "here" is
46
+ *
47
+ * The home is `HEXCORE_HOME`, else `~/.hexcore`. The STATE_DIR default is more
48
+ * careful than that, because getting it wrong orphans key material that
49
+ * controls funded addresses — see `defaultStateDir`.
50
+ */
51
+ const node_fs_1 = require("node:fs");
52
+ const node_os_1 = require("node:os");
53
+ const node_path_1 = require("node:path");
54
+ const node_crypto_1 = require("node:crypto");
55
+ /** Env keys the settings file is allowed to carry. Nothing else is written. */
56
+ exports.SETTINGS_KEYS = [
57
+ 'CARDANO_NETWORK',
58
+ 'CHAIN_BACKEND',
59
+ 'BLOCKFROST_PROJECT_ID',
60
+ 'CARDANO_NODE_SOCKET',
61
+ 'HYDRA_NODE_IMAGE',
62
+ 'ADMIN_USERNAME',
63
+ ];
64
+ /** Keys whose value is never returned by an API or printed by the CLI. */
65
+ exports.SECRET_KEYS = new Set(['BLOCKFROST_PROJECT_ID', 'JWT_SECRET', 'ADMIN_PASSWORD']);
66
+ const EMPTY = { version: 1, env: {} };
67
+ function hexcoreHome(env = process.env) {
68
+ const configured = env.HEXCORE_HOME?.trim();
69
+ if (configured)
70
+ return expandHome(configured);
71
+ return (0, node_path_1.resolve)((0, node_os_1.homedir)(), '.hexcore');
72
+ }
73
+ function settingsPath(env = process.env) {
74
+ return (0, node_path_1.resolve)(hexcoreHome(env), 'config.json');
75
+ }
76
+ /**
77
+ * Where mutable state lives when nothing names it.
78
+ *
79
+ * The obvious answer — always `<home>/.hexcore` — would have moved an existing
80
+ * installation's state dir out from under it. Before this file existed the
81
+ * default was `./.hexcore`, resolved against the current directory, so anyone
82
+ * running the control-plane from its package directory has a populated
83
+ * `apps/control-plane/.hexcore` holding the Cardano signing keys for every head
84
+ * they have created. Those keys control addresses that may hold real funds and
85
+ * exist nowhere else. Silently pointing at a new empty directory would present
86
+ * as "all my heads are gone".
87
+ *
88
+ * So: adopt a `.hexcore` that is already in the current directory, and only
89
+ * fall back to the home when there is nothing to adopt. A fresh install has
90
+ * nothing to adopt and lands in `~/.hexcore`, which is what a CLI needs.
91
+ */
92
+ function defaultStateDir(cwd = process.cwd(), env = process.env) {
93
+ const legacy = (0, node_path_1.resolve)(cwd, '.hexcore');
94
+ if ((0, node_fs_1.existsSync)(legacy))
95
+ return legacy;
96
+ return hexcoreHome(env);
97
+ }
98
+ function expandHome(p) {
99
+ return p.startsWith('~') ? (0, node_path_1.resolve)((0, node_os_1.homedir)(), p.slice(1).replace(/^\/+/, '')) : p;
100
+ }
101
+ function absolute(p, cwd = process.cwd()) {
102
+ const expanded = expandHome(p);
103
+ return (0, node_path_1.isAbsolute)(expanded) ? expanded : (0, node_path_1.resolve)(cwd, expanded);
104
+ }
105
+ /**
106
+ * Read the settings file, or an empty one.
107
+ *
108
+ * A file that cannot be parsed returns empty rather than throwing. Refusing to
109
+ * boot over a corrupt settings file would leave an operator with a process that
110
+ * will not start and no UI to fix it in — the wizard is the repair path, so it
111
+ * has to be reachable.
112
+ */
113
+ function readSettings(env = process.env) {
114
+ const path = settingsPath(env);
115
+ if (!(0, node_fs_1.existsSync)(path))
116
+ return { ...EMPTY, env: {} };
117
+ try {
118
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(path, 'utf8'));
119
+ const values = {};
120
+ for (const key of exports.SETTINGS_KEYS) {
121
+ const value = parsed.env?.[key];
122
+ if (typeof value === 'string' && value !== '')
123
+ values[key] = value;
124
+ }
125
+ return { version: 1, setupCompletedAt: parsed.setupCompletedAt, env: values };
126
+ }
127
+ catch {
128
+ return { ...EMPTY, env: {} };
129
+ }
130
+ }
131
+ /**
132
+ * Write the settings file, 0600.
133
+ *
134
+ * It carries a Blockfrost project id, which is a credential — the same one
135
+ * `.env` has always held in plaintext, kept next to `secrets.json` under the
136
+ * same permissions rather than given a weaker home.
137
+ */
138
+ function writeSettings(settings, env = process.env) {
139
+ const path = settingsPath(env);
140
+ (0, node_fs_1.mkdirSync)(hexcoreHome(env), { recursive: true });
141
+ (0, node_fs_1.writeFileSync)(path, `${JSON.stringify(settings, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
142
+ // writeFileSync only applies `mode` when it creates the file, so an
143
+ // existing world-readable one would keep its permissions forever.
144
+ (0, node_fs_1.chmodSync)(path, 0o600);
145
+ }
146
+ function clearSettings(env = process.env) {
147
+ (0, node_fs_1.rmSync)(settingsPath(env), { force: true });
148
+ clearSetupToken(env);
149
+ }
150
+ // ---------------------------------------------------------- installation id
151
+ const INSTALL_FILE = 'install-id';
152
+ /**
153
+ * A stable id for THIS state directory.
154
+ *
155
+ * Stamped onto every container as `LABEL_INSTALL` so bulk operations can tell
156
+ * one installation's containers from another's. More than one installation on a
157
+ * machine is normal — a checkout being developed on and a globally installed
158
+ * `hexcore` share a Docker daemon — and the label that existed before this,
159
+ * `LABEL_MANAGED`, is true of both. Matching on it alone is what let a `clean`
160
+ * in one installation remove a running head belonging to the other.
161
+ *
162
+ * Tied to the state dir rather than the host or the user, because the state dir
163
+ * is what actually owns the heads: move it and the containers move with it.
164
+ */
165
+ function installId(stateDir) {
166
+ const path = (0, node_path_1.resolve)(stateDir, INSTALL_FILE);
167
+ if ((0, node_fs_1.existsSync)(path)) {
168
+ const existing = (0, node_fs_1.readFileSync)(path, 'utf8').trim();
169
+ if (existing)
170
+ return existing;
171
+ }
172
+ const id = (0, node_crypto_1.randomBytes)(8).toString('hex');
173
+ (0, node_fs_1.mkdirSync)(stateDir, { recursive: true });
174
+ (0, node_fs_1.writeFileSync)(path, `${id}\n`, 'utf8');
175
+ return id;
176
+ }
177
+ // ------------------------------------------------------------- setup token
178
+ const TOKEN_FILE = 'setup-token';
179
+ /**
180
+ * A secret that proves the caller can see the terminal Hexcore was started in.
181
+ *
182
+ * The setup endpoint cannot require a login — it is where the login is created
183
+ * — so without this, on any interface but loopback, whoever reaches the port
184
+ * first chooses the admin password. That is a takeover on a shared network, and
185
+ * "bind to localhost" is not an answer for the person running this on a server
186
+ * to use from a laptop.
187
+ *
188
+ * The cost is one paste, and not even that: the CLI prints the URL with the
189
+ * token already in it.
190
+ */
191
+ function ensureSetupToken(env = process.env) {
192
+ const path = (0, node_path_1.resolve)(hexcoreHome(env), TOKEN_FILE);
193
+ if ((0, node_fs_1.existsSync)(path)) {
194
+ const existing = (0, node_fs_1.readFileSync)(path, 'utf8').trim();
195
+ if (existing)
196
+ return existing;
197
+ }
198
+ const token = (0, node_crypto_1.randomBytes)(24).toString('base64url');
199
+ (0, node_fs_1.mkdirSync)(hexcoreHome(env), { recursive: true });
200
+ (0, node_fs_1.writeFileSync)(path, `${token}\n`, { encoding: 'utf8', mode: 0o600 });
201
+ (0, node_fs_1.chmodSync)(path, 0o600);
202
+ return token;
203
+ }
204
+ function readSetupToken(env = process.env) {
205
+ const path = (0, node_path_1.resolve)(hexcoreHome(env), TOKEN_FILE);
206
+ if (!(0, node_fs_1.existsSync)(path))
207
+ return null;
208
+ return (0, node_fs_1.readFileSync)(path, 'utf8').trim() || null;
209
+ }
210
+ function clearSetupToken(env = process.env) {
211
+ (0, node_fs_1.rmSync)((0, node_path_1.resolve)(hexcoreHome(env), TOKEN_FILE), { force: true });
212
+ }
213
+ /**
214
+ * Flatten the layers into the object the zod schema parses.
215
+ *
216
+ * Empty strings are dropped from the higher layers on the way through. An
217
+ * exported-but-empty `BLOCKFROST_PROJECT_ID` — which is what `export VAR=` and
218
+ * several process managers produce — would otherwise beat a real saved value
219
+ * with nothing, and present as a credential that vanished on restart.
220
+ */
221
+ function mergeLayers(layers) {
222
+ const merged = { ...layers.file };
223
+ for (const [key, value] of Object.entries(layers.dotenv)) {
224
+ if (value !== '')
225
+ merged[key] = value;
226
+ }
227
+ for (const [key, value] of Object.entries(layers.environment)) {
228
+ if (value !== undefined && value !== '')
229
+ merged[key] = value;
230
+ }
231
+ return merged;
232
+ }
233
+ /** Which layer a given key's value actually came from. */
234
+ function sourceOf(key, layers) {
235
+ if (layers.environment[key] !== undefined && layers.environment[key] !== '')
236
+ return 'environment';
237
+ if (layers.dotenv[key] !== undefined && layers.dotenv[key] !== '')
238
+ return 'env-file';
239
+ if (layers.file[key] !== undefined)
240
+ return 'settings-file';
241
+ return 'default';
242
+ }
243
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var SetupService_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.SetupService = exports.SetupForbiddenError = exports.SettingsValidationError = void 0;
17
+ exports.wipeEverything = wipeEverything;
18
+ /**
19
+ * First-run setup, settings changes, and wiping.
20
+ *
21
+ * The problem this exists for: until now the only way to configure Hexcore was
22
+ * to edit a 123-line `.env`. That works for whoever wrote it and stops everyone
23
+ * else — and it cannot work at all for a globally installed `hexcore`, since
24
+ * `.env` is read from the current directory.
25
+ *
26
+ * Setup is reachable without a login, because it is where the login is created.
27
+ * That makes the guard rails here load-bearing rather than defensive:
28
+ *
29
+ * - `complete()` refuses once setup is done. Without that, anyone who can
30
+ * reach the port could re-run setup and choose a new admin password.
31
+ * - It requires the setup token, which is only readable from the terminal
32
+ * Hexcore was started in (or the file system it runs on).
33
+ * - The admin password passes through and is never written to the settings
34
+ * file — it goes to `AuthService`, which hashes it into `secrets.json`.
35
+ */
36
+ const common_1 = require("@nestjs/common");
37
+ const node_os_1 = require("node:os");
38
+ const promises_1 = require("node:fs/promises");
39
+ const node_crypto_1 = require("node:crypto");
40
+ const node_crypto_2 = require("node:crypto");
41
+ const config_module_1 = require("./config.module");
42
+ const config_1 = require("./config");
43
+ const settings_1 = require("./settings");
44
+ const auth_1 = require("./auth");
45
+ const head_service_1 = require("./hydra/head.service");
46
+ /** A setting that is well-formed on its own but cannot work with the others. */
47
+ class SettingsValidationError extends Error {
48
+ field;
49
+ constructor(field, message) {
50
+ super(message);
51
+ this.field = field;
52
+ this.name = 'SettingsValidationError';
53
+ }
54
+ }
55
+ exports.SettingsValidationError = SettingsValidationError;
56
+ /** Setup attempted with the wrong token, or after it was already done. */
57
+ class SetupForbiddenError extends Error {
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = 'SetupForbiddenError';
61
+ }
62
+ }
63
+ exports.SetupForbiddenError = SetupForbiddenError;
64
+ let SetupService = SetupService_1 = class SetupService {
65
+ config;
66
+ auth;
67
+ heads;
68
+ logger = new common_1.Logger(SetupService_1.name);
69
+ constructor(config, auth, heads) {
70
+ this.config = config;
71
+ this.auth = auth;
72
+ this.heads = heads;
73
+ }
74
+ /**
75
+ * Whether this installation still needs configuring.
76
+ *
77
+ * Three ways to be already configured, and the last two matter as much as
78
+ * the first: a `.env` in the working directory is the shape every existing
79
+ * deployment uses, and a container started with `-e CHAIN_BACKEND=…` was
80
+ * configured by whoever wrote the compose file. Nagging either with a
81
+ * wizard would be Hexcore failing to recognise its own configuration.
82
+ */
83
+ status() {
84
+ const stored = (0, settings_1.readSettings)();
85
+ const via = this.completedVia(stored);
86
+ return {
87
+ required: via === undefined,
88
+ completedVia: via,
89
+ completedAt: stored.setupCompletedAt,
90
+ defaults: {
91
+ network: this.config.network,
92
+ chainBackend: this.config.chainBackend,
93
+ blockfrostProjectId: '',
94
+ cardanoNodeSocket: this.config.cardanoNodeSocket || '',
95
+ hydraNodeImage: this.config.hydraNodeImage,
96
+ adminUsername: this.config.adminUsername,
97
+ },
98
+ loopbackOnly: this.config.host === '127.0.0.1' || this.config.host === 'localhost',
99
+ };
100
+ }
101
+ completedVia(stored) {
102
+ if (stored.setupCompletedAt)
103
+ return 'wizard';
104
+ if (config_1.dotenvFound)
105
+ return 'env-file';
106
+ /**
107
+ * Any one of these in the real environment means somebody configured
108
+ * this deliberately — a compose file, a CI job, a systemd unit.
109
+ * Checking the merged view instead would count our own defaults.
110
+ */
111
+ const env = (0, config_1.currentLayers)().environment;
112
+ const configured = ['CHAIN_BACKEND', 'BLOCKFROST_PROJECT_ID', 'CARDANO_NODE_SOCKET', 'ADMIN_PASSWORD'];
113
+ if (configured.some(key => env[key]))
114
+ return 'environment';
115
+ return undefined;
116
+ }
117
+ /** The token the wizard must present, minted on demand while setup is due. */
118
+ setupToken() {
119
+ return this.status().required ? (0, settings_1.ensureSetupToken)() : null;
120
+ }
121
+ /**
122
+ * Finish setup.
123
+ *
124
+ * Returns a generated password when the caller did not choose one, so
125
+ * `hexcore init` can print it. That is safe to return here and nowhere
126
+ * else: the caller has already proved it holds the setup token.
127
+ */
128
+ complete(input) {
129
+ if (!this.status().required) {
130
+ throw new SetupForbiddenError('Hexcore is already configured. Change settings from the Settings screen, or run ' +
131
+ '`hexcore reset` to start over.');
132
+ }
133
+ const expected = (0, settings_1.readSetupToken)();
134
+ if (!expected || !constantTimeEquals(input.setupToken, expected)) {
135
+ throw new SetupForbiddenError('That setup link is not valid. Use the URL printed in the terminal where Hexcore was started.');
136
+ }
137
+ this.applySettings(input, { setupCompletedAt: new Date().toISOString() });
138
+ const password = input.adminPassword || (0, node_crypto_2.randomBytes)(9).toString('base64url');
139
+ this.auth.setCredentials(input.adminUsername ?? this.config.adminUsername, password);
140
+ (0, settings_1.clearSetupToken)();
141
+ this.logger.log(`setup completed — network=${this.config.network} backend=${this.config.chainBackend}`);
142
+ return input.adminPassword ? {} : { generatedPassword: password };
143
+ }
144
+ /** Change settings after setup. Authenticated; no token, no password. */
145
+ saveSettings(input) {
146
+ const stored = (0, settings_1.readSettings)();
147
+ this.applySettings(input, { setupCompletedAt: stored.setupCompletedAt ?? new Date().toISOString() });
148
+ this.logger.log(`settings updated — network=${this.config.network} backend=${this.config.chainBackend}`);
149
+ }
150
+ /**
151
+ * Validate, write, and make the running process agree.
152
+ *
153
+ * The reload mutates the injected config object rather than replacing it,
154
+ * so every service that captured a reference sees the change. Settings that
155
+ * cannot survive that — a port already bound, a Docker client already built
156
+ * — are not offered by the schema at all.
157
+ */
158
+ applySettings(input, meta) {
159
+ this.validate(input);
160
+ const env = {
161
+ CARDANO_NETWORK: input.network,
162
+ CHAIN_BACKEND: input.chainBackend,
163
+ };
164
+ if (input.blockfrostProjectId)
165
+ env.BLOCKFROST_PROJECT_ID = input.blockfrostProjectId;
166
+ if (input.cardanoNodeSocket)
167
+ env.CARDANO_NODE_SOCKET = input.cardanoNodeSocket;
168
+ if (input.hydraNodeImage)
169
+ env.HYDRA_NODE_IMAGE = input.hydraNodeImage;
170
+ if (input.adminUsername)
171
+ env.ADMIN_USERNAME = input.adminUsername;
172
+ (0, settings_1.writeSettings)({ version: 1, setupCompletedAt: meta.setupCompletedAt, env });
173
+ (0, config_1.reloadConfigInto)(this.config);
174
+ }
175
+ /**
176
+ * The cross-field rules a per-field schema cannot express.
177
+ *
178
+ * Both are the difference between a setting that is merely wrong and one
179
+ * that produces a head which boots and then never observes its own init
180
+ * transaction — a failure that surfaces minutes later, somewhere else.
181
+ */
182
+ validate(input) {
183
+ if (input.chainBackend === 'blockfrost') {
184
+ const key = input.blockfrostProjectId?.trim();
185
+ if (!key) {
186
+ throw new SettingsValidationError('blockfrostProjectId', 'The Blockfrost backend needs a project id. Get a free one at blockfrost.io, or choose ' +
187
+ 'the offline backend, which needs no credential at all.');
188
+ }
189
+ if (!key.startsWith(input.network)) {
190
+ throw new SettingsValidationError('blockfrostProjectId', `This project id is for a different network — it must start with "${input.network}". ` +
191
+ 'A mismatched key does not fail loudly; the head boots and never sees its own ' +
192
+ 'transactions.');
193
+ }
194
+ }
195
+ if (input.chainBackend === 'cardano-node' && !input.cardanoNodeSocket?.trim()) {
196
+ throw new SettingsValidationError('cardanoNodeSocket', 'The cardano-node backend needs the path to a running node socket.');
197
+ }
198
+ }
199
+ /** What the operator must type to confirm a wipe. Their own machine's name. */
200
+ confirmationPhrase() {
201
+ return (0, node_os_1.hostname)();
202
+ }
203
+ /**
204
+ * Wipe, as far as the scope says.
205
+ *
206
+ * `everything` is not reachable here on purpose — it deletes the signing
207
+ * keys behind funded addresses and the database this request is being
208
+ * served from. `hexcore clean --all` does it with the process stopped.
209
+ */
210
+ async clean(scope, confirm) {
211
+ if (confirm.trim() !== this.confirmationPhrase()) {
212
+ throw new SettingsValidationError('confirm', `Type "${this.confirmationPhrase()}" to confirm. Nothing has been deleted.`);
213
+ }
214
+ let headsRemoved = 0;
215
+ let containersRemoved = 0;
216
+ if (scope === 'heads') {
217
+ for (const head of await this.heads.list()) {
218
+ containersRemoved += head.nodes.length;
219
+ await this.heads.delete(head.id);
220
+ headsRemoved += 1;
221
+ }
222
+ }
223
+ if (scope === 'config') {
224
+ (0, settings_1.clearSettings)();
225
+ (0, config_1.reloadConfigInto)(this.config);
226
+ }
227
+ this.logger.warn(`clean(${scope}) removed ${headsRemoved} head(s)`);
228
+ return { scope, headsRemoved, containersRemoved, setupRequired: this.status().required };
229
+ }
230
+ };
231
+ exports.SetupService = SetupService;
232
+ exports.SetupService = SetupService = SetupService_1 = __decorate([
233
+ (0, common_1.Injectable)(),
234
+ __param(0, (0, common_1.Inject)(config_module_1.APP_CONFIG)),
235
+ __metadata("design:paramtypes", [Object, auth_1.AuthService,
236
+ head_service_1.HeadService])
237
+ ], SetupService);
238
+ /**
239
+ * Compare without leaking the answer through timing.
240
+ *
241
+ * `timingSafeEqual` throws on a length mismatch, which would leak the length,
242
+ * so the lengths are compared first and the result folded in — a wrong-length
243
+ * token takes the same path as a wrong-value one.
244
+ */
245
+ function constantTimeEquals(a, b) {
246
+ const left = Buffer.from(a);
247
+ const right = Buffer.from(b);
248
+ if (left.length !== right.length)
249
+ return false;
250
+ return (0, node_crypto_1.timingSafeEqual)(left, right);
251
+ }
252
+ /** Delete every trace of Hexcore. Used by `hexcore clean --all`, never by HTTP. */
253
+ async function wipeEverything(paths) {
254
+ await (0, promises_1.rm)(paths.stateDir, { recursive: true, force: true });
255
+ await (0, promises_1.rm)(paths.home, { recursive: true, force: true });
256
+ }
257
+ //# sourceMappingURL=setup.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.service.js","sourceRoot":"","sources":["../src/setup.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VERSION = void 0;
4
+ /**
5
+ * The one place the running version comes from.
6
+ *
7
+ * It was written out by hand in three: the health payload, the Swagger
8
+ * document, and the CLI's `--version`. Two of them said `2.0.0` as a string
9
+ * literal, so a release bumps package.json and the Settings screen keeps
10
+ * reporting whatever the last person remembered to edit — a version that lies
11
+ * is worse than no version, because it is what someone quotes in a bug report.
12
+ *
13
+ * Read from package.json, which `npm version` and the pack script both already
14
+ * treat as the source of truth.
15
+ */
16
+ const node_fs_1 = require("node:fs");
17
+ const node_path_1 = require("node:path");
18
+ function read() {
19
+ /**
20
+ * Two layouts, same as the web dist: installed from npm, `dist/version.js`
21
+ * sits one directory below package.json; in the monorepo it is the same
22
+ * shape. A missing or unreadable file yields '0.0.0-unknown' rather than
23
+ * throwing — a bad version string must never be the reason a server will
24
+ * not start.
25
+ */
26
+ for (const candidate of ['../package.json', '../../package.json']) {
27
+ try {
28
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.resolve)(__dirname, candidate), 'utf8'));
29
+ /**
30
+ * Matched by name so a stray package.json further up the tree
31
+ * cannot answer. The published name is scoped (`@vtechcom/hexcore`)
32
+ * and the workspace one is not, so both are accepted — and the
33
+ * suffix check keeps a fork's own scope working.
34
+ */
35
+ if (parsed.version && (parsed.name?.endsWith('hexcore') || parsed.name === '@hexcore/control-plane')) {
36
+ return parsed.version;
37
+ }
38
+ }
39
+ catch {
40
+ // Try the next candidate.
41
+ }
42
+ }
43
+ return '0.0.0-unknown';
44
+ }
45
+ exports.VERSION = read();
46
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;GAWG;AACH,qCAAuC;AACvC,yCAAoC;AAEpC,SAAS,IAAI;IACT;;;;;;OAMG;IACH,KAAK,MAAM,SAAS,IAAI,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,EAAE,CAAC;QAChE,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAA,mBAAO,EAAC,SAAS,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,CAG5E,CAAC;YACF;;;;;eAKG;YACH,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,IAAI,KAAK,wBAAwB,CAAC,EAAE,CAAC;gBACnG,OAAO,MAAM,CAAC,OAAO,CAAC;YAC1B,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACL,0BAA0B;QAC9B,CAAC;IACL,CAAC;IACD,OAAO,eAAe,CAAC;AAC3B,CAAC;AAEY,QAAA,OAAO,GAAW,IAAI,EAAE,CAAC"}