@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,153 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SystemController = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const swagger_1 = require("@nestjs/swagger");
18
+ const shared_1 = require("@hexcore/shared");
19
+ const socket_1 = require("../chain/socket");
20
+ const auth_1 = require("../auth");
21
+ const auth_guard_1 = require("../common/auth.guard");
22
+ const zod_validation_pipe_1 = require("../common/zod-validation.pipe");
23
+ const config_module_1 = require("../config.module");
24
+ const docker_service_1 = require("../docker/docker.service");
25
+ const version_1 = require("../version");
26
+ let SystemController = class SystemController {
27
+ config;
28
+ docker;
29
+ auth;
30
+ constructor(config, docker, auth) {
31
+ this.config = config;
32
+ this.docker = docker;
33
+ this.auth = auth;
34
+ }
35
+ async health() {
36
+ let dockerOk = true;
37
+ let dockerError;
38
+ try {
39
+ await this.docker.ping();
40
+ }
41
+ catch (err) {
42
+ dockerOk = false;
43
+ dockerError = err.message;
44
+ }
45
+ return {
46
+ status: dockerOk ? 'healthy' : 'degraded',
47
+ version: version_1.VERSION,
48
+ network: this.config.network,
49
+ chainBackend: this.config.chainBackend,
50
+ authEnabled: this.config.authEnabled,
51
+ docker: { ok: dockerOk, error: dockerError },
52
+ };
53
+ }
54
+ /**
55
+ * What this server can actually do, as opposed to what it prefers.
56
+ *
57
+ * The create form needs the difference: a backend whose credential is
58
+ * missing has to be steered away from while the user is still filling in
59
+ * the form, rather than discovered when the head refuses to boot. Carries
60
+ * no secrets — whether a Blockfrost key exists, never the key.
61
+ */
62
+ async systemConfig() {
63
+ const socket = await (0, socket_1.checkNodeSocket)(this.config.cardanoNodeSocket);
64
+ return {
65
+ network: this.config.network,
66
+ defaultChainBackend: this.config.chainBackend,
67
+ defaultHydraNodeImage: this.config.hydraNodeImage,
68
+ maxActiveNodes: this.config.maxActiveNodes,
69
+ stateDir: this.config.stateDir,
70
+ blockfrost: { configured: Boolean(this.config.blockfrostProjectId) },
71
+ cardanoNode: {
72
+ configured: socket.configured,
73
+ available: socket.available,
74
+ reason: socket.reason,
75
+ socketPath: this.config.cardanoNodeSocket || null,
76
+ },
77
+ };
78
+ }
79
+ /**
80
+ * hydra-node versions this build declares argv support for, plus the image
81
+ * a head gets by default. The create form lists these; the control-plane
82
+ * still accepts any other image and probes it, so this is a menu rather
83
+ * than an allow-list.
84
+ */
85
+ hydraVersions() {
86
+ /**
87
+ * The control-plane's own platform, because it is the machine the
88
+ * containers run on — the browser asking may be somewhere else entirely.
89
+ * Which image works is partly a property of this, not of the version:
90
+ * every upstream image is amd64-only, and Docker Desktop on Apple
91
+ * Silicon fails differently from arm64 Linux.
92
+ */
93
+ const hostPlatform = (0, shared_1.toHostPlatform)(process.platform, process.arch);
94
+ return {
95
+ defaultImage: this.config.hydraNodeImage,
96
+ defaultProfileId: (0, shared_1.findVersionProfile)(this.config.hydraNodeImage)?.id ?? null,
97
+ profiles: shared_1.HYDRA_VERSION_PROFILES.map(profile => (0, shared_1.toVersionInfo)(profile, hostPlatform)),
98
+ hostPlatform,
99
+ };
100
+ }
101
+ login(body) {
102
+ const token = this.auth.login(body.username, body.password);
103
+ if (!token) {
104
+ throw new common_1.UnauthorizedException({
105
+ code: 'INVALID_CREDENTIALS',
106
+ message: 'Wrong username or password',
107
+ });
108
+ }
109
+ return { token, username: body.username };
110
+ }
111
+ };
112
+ exports.SystemController = SystemController;
113
+ __decorate([
114
+ (0, auth_guard_1.Public)(),
115
+ (0, common_1.Get)('health'),
116
+ (0, swagger_1.ApiOperation)({ summary: 'Liveness probe plus Docker reachability' }),
117
+ __metadata("design:type", Function),
118
+ __metadata("design:paramtypes", []),
119
+ __metadata("design:returntype", Promise)
120
+ ], SystemController.prototype, "health", null);
121
+ __decorate([
122
+ (0, common_1.Get)('api/system/config'),
123
+ (0, swagger_1.ApiOperation)({ summary: 'Backend availability and non-secret server defaults' }),
124
+ __metadata("design:type", Function),
125
+ __metadata("design:paramtypes", []),
126
+ __metadata("design:returntype", Promise)
127
+ ], SystemController.prototype, "systemConfig", null);
128
+ __decorate([
129
+ (0, common_1.Get)('api/hydra/versions'),
130
+ (0, swagger_1.ApiOperation)({ summary: 'Supported hydra-node versions and the default image' }),
131
+ __metadata("design:type", Function),
132
+ __metadata("design:paramtypes", []),
133
+ __metadata("design:returntype", Object)
134
+ ], SystemController.prototype, "hydraVersions", null);
135
+ __decorate([
136
+ (0, auth_guard_1.Public)(),
137
+ (0, common_1.Post)('api/auth/login'),
138
+ (0, common_1.HttpCode)(200),
139
+ (0, swagger_1.ApiOperation)({ summary: 'Exchange admin credentials for a bearer token' }),
140
+ (0, common_1.UsePipes)(new zod_validation_pipe_1.ZodValidationPipe(shared_1.loginSchema)),
141
+ __param(0, (0, common_1.Body)()),
142
+ __metadata("design:type", Function),
143
+ __metadata("design:paramtypes", [Object]),
144
+ __metadata("design:returntype", void 0)
145
+ ], SystemController.prototype, "login", null);
146
+ exports.SystemController = SystemController = __decorate([
147
+ (0, swagger_1.ApiTags)('system'),
148
+ (0, common_1.Controller)(),
149
+ __param(0, (0, common_1.Inject)(config_module_1.APP_CONFIG)),
150
+ __metadata("design:paramtypes", [Object, docker_service_1.DockerService,
151
+ auth_1.AuthService])
152
+ ], SystemController);
153
+ //# sourceMappingURL=system.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system.controller.js","sourceRoot":"","sources":["../../src/controllers/system.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.DatabaseModule = exports.DatabaseLifecycle = exports.DB = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const config_module_1 = require("../config.module");
18
+ const index_1 = require("./index");
19
+ const repositories_1 = require("./repositories");
20
+ exports.DB = 'DB';
21
+ let DatabaseLifecycle = class DatabaseLifecycle {
22
+ db;
23
+ constructor(db) {
24
+ this.db = db;
25
+ }
26
+ onModuleDestroy() {
27
+ this.db.close();
28
+ }
29
+ };
30
+ exports.DatabaseLifecycle = DatabaseLifecycle;
31
+ exports.DatabaseLifecycle = DatabaseLifecycle = __decorate([
32
+ (0, common_1.Injectable)(),
33
+ __param(0, (0, common_1.Inject)(exports.DB)),
34
+ __metadata("design:paramtypes", [Object])
35
+ ], DatabaseLifecycle);
36
+ /**
37
+ * SQLite lives for the whole process; repositories are thin wrappers injected
38
+ * wherever they are needed. No connection pool, no migrations runner, no
39
+ * external service — the schema is applied idempotently on open.
40
+ */
41
+ let DatabaseModule = class DatabaseModule {
42
+ };
43
+ exports.DatabaseModule = DatabaseModule;
44
+ exports.DatabaseModule = DatabaseModule = __decorate([
45
+ (0, common_1.Global)(),
46
+ (0, common_1.Module)({
47
+ providers: [
48
+ {
49
+ provide: exports.DB,
50
+ useFactory: (config) => (0, index_1.openDb)(config.dbPath),
51
+ inject: [config_module_1.APP_CONFIG],
52
+ },
53
+ {
54
+ provide: repositories_1.HeadRepository,
55
+ useFactory: (db) => new repositories_1.HeadRepository(db),
56
+ inject: [exports.DB],
57
+ },
58
+ {
59
+ provide: repositories_1.NodeRepository,
60
+ useFactory: (db) => new repositories_1.NodeRepository(db),
61
+ inject: [exports.DB],
62
+ },
63
+ {
64
+ provide: repositories_1.EventRepository,
65
+ useFactory: (db) => new repositories_1.EventRepository(db),
66
+ inject: [exports.DB],
67
+ },
68
+ DatabaseLifecycle,
69
+ ],
70
+ exports: [exports.DB, repositories_1.HeadRepository, repositories_1.NodeRepository, repositories_1.EventRepository],
71
+ })
72
+ ], DatabaseModule);
73
+ //# sourceMappingURL=database.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.module.js","sourceRoot":"","sources":["../../src/db/database.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA0F;AAC1F,oDAA8C;AAE9C,mCAA0C;AAC1C,iDAAiF;AAEpE,QAAA,EAAE,GAAG,IAAI,CAAC;AAGhB,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IACe;IAAzC,YAAyC,EAAM;QAAN,OAAE,GAAF,EAAE,CAAI;IAAG,CAAC;IAEnD,eAAe;QACX,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;CACJ,CAAA;AANY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;IAEI,WAAA,IAAA,eAAM,EAAC,UAAE,CAAC,CAAA;;GADd,iBAAiB,CAM7B;AAED;;;;GAIG;AA4BI,IAAM,cAAc,GAApB,MAAM,cAAc;CAAG,CAAA;AAAjB,wCAAc;yBAAd,cAAc;IA3B1B,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACJ,SAAS,EAAE;YACP;gBACI,OAAO,EAAE,UAAE;gBACX,UAAU,EAAE,CAAC,MAAiB,EAAM,EAAE,CAAC,IAAA,cAAM,EAAC,MAAM,CAAC,MAAM,CAAC;gBAC5D,MAAM,EAAE,CAAC,0BAAU,CAAC;aACvB;YACD;gBACI,OAAO,EAAE,6BAAc;gBACvB,UAAU,EAAE,CAAC,EAAM,EAAE,EAAE,CAAC,IAAI,6BAAc,CAAC,EAAE,CAAC;gBAC9C,MAAM,EAAE,CAAC,UAAE,CAAC;aACf;YACD;gBACI,OAAO,EAAE,6BAAc;gBACvB,UAAU,EAAE,CAAC,EAAM,EAAE,EAAE,CAAC,IAAI,6BAAc,CAAC,EAAE,CAAC;gBAC9C,MAAM,EAAE,CAAC,UAAE,CAAC;aACf;YACD;gBACI,OAAO,EAAE,8BAAe;gBACxB,UAAU,EAAE,CAAC,EAAM,EAAE,EAAE,CAAC,IAAI,8BAAe,CAAC,EAAE,CAAC;gBAC/C,MAAM,EAAE,CAAC,UAAE,CAAC;aACf;YACD,iBAAiB;SACpB;QACD,OAAO,EAAE,CAAC,UAAE,EAAE,6BAAc,EAAE,6BAAc,EAAE,8BAAe,CAAC;KACjE,CAAC;GACW,cAAc,CAAG"}
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.openDb = openDb;
7
+ /**
8
+ * Persistence.
9
+ *
10
+ * v1 needed MySQL (docker-compose) + Redis before it would even start. v2 uses
11
+ * an embedded SQLite file under the state dir: nothing to provision, the schema
12
+ * is applied on boot, and the whole deployment is a single directory you can
13
+ * copy or delete.
14
+ */
15
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
16
+ const node_fs_1 = require("node:fs");
17
+ const node_path_1 = require("node:path");
18
+ const SCHEMA = `
19
+ PRAGMA journal_mode = WAL;
20
+ PRAGMA foreign_keys = ON;
21
+
22
+ CREATE TABLE IF NOT EXISTS heads (
23
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
24
+ name TEXT NOT NULL UNIQUE,
25
+ description TEXT,
26
+ network TEXT NOT NULL DEFAULT 'preprod',
27
+ chain_backend TEXT NOT NULL DEFAULT 'blockfrost',
28
+ node_count INTEGER NOT NULL DEFAULT 1,
29
+ contestation_period INTEGER NOT NULL DEFAULT 120,
30
+ deposit_period INTEGER NOT NULL DEFAULT 720,
31
+ persistence_rotate_after INTEGER NOT NULL DEFAULT 15000,
32
+ protocol_parameters TEXT,
33
+ blockfrost_project_id TEXT,
34
+ hydra_node_image TEXT NOT NULL,
35
+ log_quiet INTEGER NOT NULL DEFAULT 0,
36
+ log_max_size_mb INTEGER NOT NULL DEFAULT 10,
37
+ log_max_files INTEGER NOT NULL DEFAULT 3,
38
+ offline_head_seed TEXT,
39
+ offline_initial_utxo TEXT,
40
+ offline_seed_lovelace INTEGER,
41
+ offline_ledger_genesis TEXT,
42
+ status TEXT NOT NULL DEFAULT 'CONFIGURED',
43
+ hydra_state TEXT NOT NULL DEFAULT 'UNKNOWN',
44
+ last_error TEXT,
45
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
46
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
47
+ );
48
+
49
+ CREATE TABLE IF NOT EXISTS nodes (
50
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
51
+ head_id INTEGER NOT NULL REFERENCES heads(id) ON DELETE CASCADE,
52
+ node_index INTEGER NOT NULL,
53
+ name TEXT NOT NULL,
54
+ api_port INTEGER NOT NULL UNIQUE,
55
+ p2p_port INTEGER NOT NULL UNIQUE,
56
+ monitoring_port INTEGER NOT NULL UNIQUE,
57
+ status TEXT NOT NULL DEFAULT 'CREATED',
58
+ hydra_vkey TEXT,
59
+ cardano_address TEXT,
60
+ container_id TEXT,
61
+ /* Overrides the head's key for this node; null means "use the head's". */
62
+ blockfrost_project_id TEXT,
63
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
64
+ UNIQUE (head_id, node_index)
65
+ );
66
+
67
+ CREATE INDEX IF NOT EXISTS idx_nodes_head ON nodes(head_id);
68
+
69
+ /* Append-only audit of lifecycle actions — powers the activity feed in the UI. */
70
+ CREATE TABLE IF NOT EXISTS events (
71
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
72
+ head_id INTEGER,
73
+ level TEXT NOT NULL DEFAULT 'info',
74
+ kind TEXT NOT NULL,
75
+ message TEXT NOT NULL,
76
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
77
+ );
78
+
79
+ CREATE INDEX IF NOT EXISTS idx_events_head ON events(head_id, id DESC);
80
+ `;
81
+ /**
82
+ * Columns added after a release, in the order they were added.
83
+ *
84
+ * `CREATE TABLE IF NOT EXISTS` does nothing to a table that already exists, so
85
+ * a database created by an earlier build would silently keep the old shape and
86
+ * fail on the first insert naming the new column. There is no migration tool
87
+ * here on purpose — the whole state directory is disposable — so additive
88
+ * columns are applied one at a time, guarded by what the table actually has.
89
+ *
90
+ * Additive only: no renames, no drops, no NOT NULL without a default.
91
+ */
92
+ const ADDED_COLUMNS = [
93
+ { table: 'nodes', column: 'blockfrost_project_id', ddl: 'ALTER TABLE nodes ADD COLUMN blockfrost_project_id TEXT' },
94
+ // Logging and offline mode. The NOT NULL ones carry a default, which is
95
+ // what makes them addable to a table that already has rows.
96
+ {
97
+ table: 'heads',
98
+ column: 'log_quiet',
99
+ ddl: 'ALTER TABLE heads ADD COLUMN log_quiet INTEGER NOT NULL DEFAULT 0',
100
+ },
101
+ {
102
+ table: 'heads',
103
+ column: 'log_max_size_mb',
104
+ ddl: 'ALTER TABLE heads ADD COLUMN log_max_size_mb INTEGER NOT NULL DEFAULT 10',
105
+ },
106
+ {
107
+ table: 'heads',
108
+ column: 'log_max_files',
109
+ ddl: 'ALTER TABLE heads ADD COLUMN log_max_files INTEGER NOT NULL DEFAULT 3',
110
+ },
111
+ { table: 'heads', column: 'offline_head_seed', ddl: 'ALTER TABLE heads ADD COLUMN offline_head_seed TEXT' },
112
+ { table: 'heads', column: 'offline_initial_utxo', ddl: 'ALTER TABLE heads ADD COLUMN offline_initial_utxo TEXT' },
113
+ {
114
+ table: 'heads',
115
+ column: 'offline_seed_lovelace',
116
+ ddl: 'ALTER TABLE heads ADD COLUMN offline_seed_lovelace INTEGER',
117
+ },
118
+ {
119
+ table: 'heads',
120
+ column: 'offline_ledger_genesis',
121
+ ddl: 'ALTER TABLE heads ADD COLUMN offline_ledger_genesis TEXT',
122
+ },
123
+ ];
124
+ function openDb(dbPath) {
125
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(dbPath), { recursive: true });
126
+ const db = new better_sqlite3_1.default(dbPath);
127
+ db.exec(SCHEMA);
128
+ for (const { table, column, ddl } of ADDED_COLUMNS) {
129
+ const columns = db.prepare(`PRAGMA table_info(${table})`).all();
130
+ if (!columns.some(c => c.name === column))
131
+ db.exec(ddl);
132
+ }
133
+ return db;
134
+ }
135
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":";;;;;AA4KA,wBAWC;AAvLD;;;;;;;GAOG;AACH,oEAAsC;AACtC,qCAAoC;AACpC,yCAAoC;AAoDpC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Dd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,aAAa,GAA0D;IACzE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,uBAAuB,EAAE,GAAG,EAAE,yDAAyD,EAAE;IACnH,wEAAwE;IACxE,4DAA4D;IAC5D;QACI,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,WAAW;QACnB,GAAG,EAAE,mEAAmE;KAC3E;IACD;QACI,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,iBAAiB;QACzB,GAAG,EAAE,0EAA0E;KAClF;IACD;QACI,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,eAAe;QACvB,GAAG,EAAE,uEAAuE;KAC/E;IACD,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,GAAG,EAAE,qDAAqD,EAAE;IAC3G,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,sBAAsB,EAAE,GAAG,EAAE,wDAAwD,EAAE;IACjH;QACI,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,uBAAuB;QAC/B,GAAG,EAAE,4DAA4D;KACpE;IACD;QACI,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,wBAAwB;QAChC,GAAG,EAAE,0DAA0D;KAClE;CACJ,CAAC;AAIF,SAAgB,MAAM,CAAC,MAAc;IACjC,IAAA,mBAAS,EAAC,IAAA,mBAAO,EAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,EAAE,GAAG,IAAI,wBAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,KAAK,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,aAAa,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,qBAAqB,KAAK,GAAG,CAAC,CAAC,GAAG,EAA6B,CAAC;QAC3F,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;YAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,EAAE,CAAC;AACd,CAAC"}
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventRepository = exports.NodeRepository = exports.HeadRepository = void 0;
4
+ exports.toNodeView = toNodeView;
5
+ exports.toHeadView = toHeadView;
6
+ const shared_1 = require("@hexcore/shared");
7
+ const blockfrost_keys_1 = require("../hydra/blockfrost-keys");
8
+ /** Stored JSON, or null when absent or no longer parseable. */
9
+ function parseJsonOrNull(value) {
10
+ if (!value)
11
+ return null;
12
+ try {
13
+ const parsed = JSON.parse(value);
14
+ return parsed !== null && typeof parsed === 'object' ? parsed : null;
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ class HeadRepository {
21
+ db;
22
+ constructor(db) {
23
+ this.db = db;
24
+ }
25
+ create(input) {
26
+ const stmt = this.db.prepare(`
27
+ INSERT INTO heads (name, description, network, chain_backend, node_count, contestation_period,
28
+ deposit_period, persistence_rotate_after, protocol_parameters,
29
+ blockfrost_project_id, hydra_node_image,
30
+ log_quiet, log_max_size_mb, log_max_files,
31
+ offline_head_seed, offline_initial_utxo, offline_seed_lovelace,
32
+ offline_ledger_genesis)
33
+ VALUES (@name, @description, @network, @chain_backend, @node_count, @contestation_period,
34
+ @deposit_period, @persistence_rotate_after, @protocol_parameters,
35
+ @blockfrost_project_id, @hydra_node_image,
36
+ @log_quiet, @log_max_size_mb, @log_max_files,
37
+ @offline_head_seed, @offline_initial_utxo, @offline_seed_lovelace,
38
+ @offline_ledger_genesis)
39
+ `);
40
+ const info = stmt.run(input);
41
+ return Number(info.lastInsertRowid);
42
+ }
43
+ findById(id) {
44
+ return this.db.prepare('SELECT * FROM heads WHERE id = ?').get(id);
45
+ }
46
+ findByName(name) {
47
+ return this.db.prepare('SELECT * FROM heads WHERE name = ?').get(name);
48
+ }
49
+ list() {
50
+ return this.db.prepare('SELECT * FROM heads ORDER BY id DESC').all();
51
+ }
52
+ setStatus(id, status, lastError = null) {
53
+ this.db
54
+ .prepare(`UPDATE heads SET status = ?, last_error = ?, updated_at = datetime('now') WHERE id = ?`)
55
+ .run(status, lastError, id);
56
+ }
57
+ setHydraState(id, state) {
58
+ this.db.prepare(`UPDATE heads SET hydra_state = ?, updated_at = datetime('now') WHERE id = ?`).run(state, id);
59
+ }
60
+ update(id, patch) {
61
+ const allowed = [
62
+ 'description',
63
+ 'contestation_period',
64
+ 'deposit_period',
65
+ 'persistence_rotate_after',
66
+ 'protocol_parameters',
67
+ 'blockfrost_project_id',
68
+ 'hydra_node_image',
69
+ 'name',
70
+ 'network',
71
+ 'chain_backend',
72
+ 'log_quiet',
73
+ 'log_max_size_mb',
74
+ 'log_max_files',
75
+ 'offline_head_seed',
76
+ 'offline_initial_utxo',
77
+ 'offline_seed_lovelace',
78
+ 'offline_ledger_genesis',
79
+ ];
80
+ const entries = allowed.filter(k => patch[k] !== undefined);
81
+ if (entries.length === 0)
82
+ return;
83
+ const setSql = entries.map(k => `${k} = @${k}`).join(', ');
84
+ this.db
85
+ .prepare(`UPDATE heads SET ${setSql}, updated_at = datetime('now') WHERE id = @id`)
86
+ .run({ ...Object.fromEntries(entries.map(k => [k, patch[k]])), id });
87
+ }
88
+ delete(id) {
89
+ this.db.prepare('DELETE FROM heads WHERE id = ?').run(id);
90
+ }
91
+ }
92
+ exports.HeadRepository = HeadRepository;
93
+ class NodeRepository {
94
+ db;
95
+ constructor(db) {
96
+ this.db = db;
97
+ }
98
+ create(input) {
99
+ const info = this.db
100
+ .prepare(`INSERT INTO nodes (head_id, node_index, name, api_port, p2p_port, monitoring_port, hydra_vkey,
101
+ cardano_address, blockfrost_project_id)
102
+ VALUES (@head_id, @node_index, @name, @api_port, @p2p_port, @monitoring_port, @hydra_vkey,
103
+ @cardano_address, @blockfrost_project_id)`)
104
+ .run(input);
105
+ return Number(info.lastInsertRowid);
106
+ }
107
+ byHead(headId) {
108
+ return this.db
109
+ .prepare('SELECT * FROM nodes WHERE head_id = ? ORDER BY node_index ASC')
110
+ .all(headId);
111
+ }
112
+ all() {
113
+ return this.db.prepare('SELECT * FROM nodes').all();
114
+ }
115
+ setStatus(id, status, containerId = null) {
116
+ this.db.prepare('UPDATE nodes SET status = ?, container_id = ? WHERE id = ?').run(status, containerId, id);
117
+ }
118
+ setStatusForHead(headId, status) {
119
+ this.db.prepare('UPDATE nodes SET status = ? WHERE head_id = ?').run(status, headId);
120
+ }
121
+ /** Refresh vkey + address after keys are regenerated by a reset. */
122
+ setIdentity(nodeId, hydraVkey, cardanoAddress) {
123
+ this.db
124
+ .prepare('UPDATE nodes SET hydra_vkey = ?, cardano_address = ? WHERE id = ?')
125
+ .run(hydraVkey, cardanoAddress, nodeId);
126
+ }
127
+ /** Highest port slot in use — new heads allocate above it. */
128
+ maxApiPort() {
129
+ const row = this.db.prepare('SELECT MAX(api_port) AS m FROM nodes').get();
130
+ return row.m;
131
+ }
132
+ countRunning() {
133
+ const row = this.db.prepare(`SELECT COUNT(*) AS c FROM nodes WHERE status = 'RUNNING'`).get();
134
+ return row.c;
135
+ }
136
+ }
137
+ exports.NodeRepository = NodeRepository;
138
+ class EventRepository {
139
+ db;
140
+ constructor(db) {
141
+ this.db = db;
142
+ }
143
+ add(headId, kind, message, level = 'info') {
144
+ this.db
145
+ .prepare('INSERT INTO events (head_id, kind, message, level) VALUES (?, ?, ?, ?)')
146
+ .run(headId, kind, message, level);
147
+ }
148
+ recent(headId, limit = 100) {
149
+ return headId === undefined
150
+ ? this.db.prepare('SELECT * FROM events ORDER BY id DESC LIMIT ?').all(limit)
151
+ : this.db.prepare('SELECT * FROM events WHERE head_id = ? ORDER BY id DESC LIMIT ?').all(headId, limit);
152
+ }
153
+ }
154
+ exports.EventRepository = EventRepository;
155
+ function toNodeView(row, blockfrostKeySource = 'none') {
156
+ return {
157
+ id: row.id,
158
+ headId: row.head_id,
159
+ index: row.node_index,
160
+ name: row.name,
161
+ apiPort: row.api_port,
162
+ p2pPort: row.p2p_port,
163
+ monitoringPort: row.monitoring_port,
164
+ status: row.status,
165
+ cardanoAddress: row.cardano_address,
166
+ hydraVkey: row.hydra_vkey,
167
+ containerId: row.container_id,
168
+ createdAt: row.created_at,
169
+ blockfrostKeySource,
170
+ };
171
+ }
172
+ /**
173
+ * `serverKeyConfigured` decides whether a node with no key of its own would
174
+ * still find one at boot, so the caller has to pass what the config knows —
175
+ * the row alone cannot answer it.
176
+ */
177
+ function toHeadView(row, nodes, serverKeyConfigured = false) {
178
+ return {
179
+ id: row.id,
180
+ name: row.name,
181
+ description: row.description,
182
+ network: row.network,
183
+ chainBackend: row.chain_backend,
184
+ nodeCount: row.node_count,
185
+ contestationPeriod: row.contestation_period,
186
+ depositPeriod: row.deposit_period,
187
+ persistenceRotateAfter: row.persistence_rotate_after,
188
+ status: row.status,
189
+ hydraState: row.hydra_state,
190
+ hydraNodeImage: row.hydra_node_image,
191
+ logging: {
192
+ quiet: row.log_quiet === 1,
193
+ maxSizeMb: row.log_max_size_mb,
194
+ maxFiles: row.log_max_files,
195
+ },
196
+ offline: row.chain_backend === 'offline'
197
+ ? {
198
+ // Rows created before the seed column existed fall back to
199
+ // the same derivation `start` uses, so the view never
200
+ // shows a seed that differs from what the node will get.
201
+ headSeed: row.offline_head_seed ?? (0, shared_1.defaultOfflineHeadSeed)(row.id),
202
+ seedLovelace: row.offline_seed_lovelace ?? shared_1.DEFAULT_OFFLINE_SEED_LOVELACE,
203
+ customInitialUtxo: row.offline_initial_utxo !== null,
204
+ customLedgerGenesis: row.offline_ledger_genesis !== null,
205
+ }
206
+ : null,
207
+ // Parsed rather than passed through as a string: the UI shows which
208
+ // parameters were pinned, and a stored value that no longer parses is
209
+ // better reported as "none" than as a crash on the heads list.
210
+ protocolParameterOverrides: parseJsonOrNull(row.protocol_parameters),
211
+ lastError: row.last_error,
212
+ createdAt: row.created_at,
213
+ updatedAt: row.updated_at,
214
+ nodes: nodes.map(node => toNodeView(node, (0, blockfrost_keys_1.resolveBlockfrostKey)(node.blockfrost_project_id, row.blockfrost_project_id,
215
+ // Only whether one exists reaches here; the key itself must
216
+ // not travel to a view that the UI renders.
217
+ serverKeyConfigured ? 'configured' : null).source)),
218
+ };
219
+ }
220
+ //# sourceMappingURL=repositories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repositories.js","sourceRoot":"","sources":["../../src/db/repositories.ts"],"names":[],"mappings":"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"}