@hsuite/smart-engines-cli 1.2.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +272 -58
- package/dist/_lib/attestation.d.ts +45 -0
- package/dist/_lib/attestation.d.ts.map +1 -0
- package/dist/_lib/attestation.js +76 -0
- package/dist/_lib/attestation.js.map +1 -0
- package/dist/_lib/baas.d.ts +147 -0
- package/dist/_lib/baas.d.ts.map +1 -0
- package/dist/_lib/baas.js +260 -0
- package/dist/_lib/baas.js.map +1 -0
- package/dist/_lib/cluster.d.ts +6 -6
- package/dist/_lib/cluster.js +6 -6
- package/dist/_lib/deploy-manifest.d.ts +69 -0
- package/dist/_lib/deploy-manifest.d.ts.map +1 -0
- package/dist/_lib/deploy-manifest.js +87 -0
- package/dist/_lib/deploy-manifest.js.map +1 -0
- package/dist/_lib/docker.d.ts +82 -0
- package/dist/_lib/docker.d.ts.map +1 -0
- package/dist/_lib/docker.js +164 -0
- package/dist/_lib/docker.js.map +1 -0
- package/dist/_lib/faucet-client.d.ts +64 -0
- package/dist/_lib/faucet-client.d.ts.map +1 -0
- package/dist/_lib/faucet-client.js +92 -0
- package/dist/_lib/faucet-client.js.map +1 -0
- package/dist/_lib/framework.d.ts +59 -0
- package/dist/_lib/framework.d.ts.map +1 -0
- package/dist/_lib/framework.js +149 -0
- package/dist/_lib/framework.js.map +1 -0
- package/dist/_lib/frontend-guard.d.ts +13 -0
- package/dist/_lib/frontend-guard.d.ts.map +1 -0
- package/dist/_lib/frontend-guard.js +41 -0
- package/dist/_lib/frontend-guard.js.map +1 -0
- package/dist/_lib/registry-fanout.d.ts +178 -0
- package/dist/_lib/registry-fanout.d.ts.map +1 -0
- package/dist/_lib/registry-fanout.js +545 -0
- package/dist/_lib/registry-fanout.js.map +1 -0
- package/dist/_lib/runtime-env.d.ts +126 -0
- package/dist/_lib/runtime-env.d.ts.map +1 -0
- package/dist/_lib/runtime-env.js +172 -0
- package/dist/_lib/runtime-env.js.map +1 -0
- package/dist/_lib/subscription-client.d.ts +129 -18
- package/dist/_lib/subscription-client.d.ts.map +1 -1
- package/dist/_lib/subscription-client.js +268 -40
- package/dist/_lib/subscription-client.js.map +1 -1
- package/dist/_lib/subscription-env.d.ts +35 -0
- package/dist/_lib/subscription-env.d.ts.map +1 -1
- package/dist/_lib/subscription-env.js +46 -2
- package/dist/_lib/subscription-env.js.map +1 -1
- package/dist/commands/app-lifecycle.d.ts +36 -0
- package/dist/commands/app-lifecycle.d.ts.map +1 -0
- package/dist/commands/app-lifecycle.js +145 -0
- package/dist/commands/app-lifecycle.js.map +1 -0
- package/dist/commands/ci.d.ts +45 -0
- package/dist/commands/ci.d.ts.map +1 -0
- package/dist/commands/ci.js +174 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/deploy-manifest.d.ts +11 -0
- package/dist/commands/deploy-manifest.d.ts.map +1 -0
- package/dist/commands/deploy-manifest.js +17 -0
- package/dist/commands/deploy-manifest.js.map +1 -0
- package/dist/commands/deploy.d.ts +70 -11
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +273 -150
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/downgrade.js +1 -1
- package/dist/commands/downgrade.js.map +1 -1
- package/dist/commands/faucet.d.ts +78 -0
- package/dist/commands/faucet.d.ts.map +1 -0
- package/dist/commands/faucet.js +184 -0
- package/dist/commands/faucet.js.map +1 -0
- package/dist/commands/governance.js +1 -1
- package/dist/commands/governance.js.map +1 -1
- package/dist/commands/hist-balance.d.ts +1 -1
- package/dist/commands/hist-balance.js +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/list.d.ts +22 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +81 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/personhood.js +2 -2
- package/dist/commands/personhood.js.map +1 -1
- package/dist/commands/redeploy.d.ts +62 -0
- package/dist/commands/redeploy.d.ts.map +1 -0
- package/dist/commands/redeploy.js +322 -0
- package/dist/commands/redeploy.js.map +1 -0
- package/dist/commands/status.d.ts +51 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +138 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/subscribe.d.ts +94 -17
- package/dist/commands/subscribe.d.ts.map +1 -1
- package/dist/commands/subscribe.js +487 -81
- package/dist/commands/subscribe.js.map +1 -1
- package/dist/commands/transactions.d.ts +60 -0
- package/dist/commands/transactions.d.ts.map +1 -0
- package/dist/commands/transactions.js +101 -0
- package/dist/commands/transactions.js.map +1 -0
- package/dist/commands/update.d.ts +40 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +114 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/verify.d.ts +10 -19
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +14 -23
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.d.ts +12 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -3
- package/dist/index.js.map +1 -1
- package/package.json +11 -4
package/dist/commands/deploy.js
CHANGED
|
@@ -37,185 +37,308 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.deployCommand = void 0;
|
|
40
|
+
exports.runDeploy = runDeploy;
|
|
40
41
|
/**
|
|
41
|
-
* `hsuite deploy` —
|
|
42
|
+
* `hsuite deploy` — clean, manifest-driven deploy of a smart-app.
|
|
42
43
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
44
|
+
* Order of operations (the canonical flow, plus the trusted-deploy attestation
|
|
45
|
+
* the host requires by default):
|
|
45
46
|
*
|
|
46
|
-
* 1.
|
|
47
|
-
* 2.
|
|
48
|
-
* 3. `
|
|
49
|
-
* 4.
|
|
47
|
+
* 1. parse manifest → ONE canonical shape (backend required)
|
|
48
|
+
* 2. detect framework + SDK → ABORT if the project has no HSUITE SDK
|
|
49
|
+
* 3. connectAndAuth → the ONE `new BaasClient` (no discovery factory)
|
|
50
|
+
* 4. init → server allocates appId + ephemeral registry creds
|
|
51
|
+
* 5. docker build + push → backend image
|
|
52
|
+
* 6. tar + uploadFrontend → SPA bundle (when a `frontend` block is present)
|
|
53
|
+
* 7. assemble + sign → BuildAttestation signed with the dev's XRPL key
|
|
54
|
+
* 8. deploy → reconcile to k8s ({ tag, port, replicas, degree,
|
|
55
|
+
* env, resources, strategy, attestation })
|
|
50
56
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
57
|
+
* Every smart-app has a NestJS backend; the optional SPA (`frontend`) is served
|
|
58
|
+
* by that backend out of its own `public/`. There is no SPA-only path.
|
|
59
|
+
*
|
|
60
|
+
* All docker/tar shell-outs go through the injectable seams in `_lib/baas.ts`
|
|
61
|
+
* so unit tests never invoke docker for real.
|
|
55
62
|
*/
|
|
56
63
|
const commander_1 = require("commander");
|
|
57
64
|
const chalk_1 = __importDefault(require("chalk"));
|
|
58
|
-
const ora_1 = __importDefault(require("ora"));
|
|
59
65
|
const fs_1 = require("fs");
|
|
60
66
|
const path_1 = require("path");
|
|
61
|
-
const
|
|
62
|
-
const smart_engines_sdk_1 = require("@hsuite/smart-engines-sdk");
|
|
67
|
+
const os_1 = require("os");
|
|
63
68
|
const env_1 = require("../_lib/env");
|
|
69
|
+
const subscription_env_1 = require("../_lib/subscription-env");
|
|
70
|
+
const runtime_env_1 = require("../_lib/runtime-env");
|
|
64
71
|
const cluster_1 = require("../_lib/cluster");
|
|
72
|
+
const framework_1 = require("../_lib/framework");
|
|
73
|
+
const baas_1 = require("../_lib/baas");
|
|
74
|
+
const registry_fanout_1 = require("../_lib/registry-fanout");
|
|
75
|
+
const attestation_1 = require("../_lib/attestation");
|
|
76
|
+
const deploy_manifest_1 = require("../_lib/deploy-manifest");
|
|
77
|
+
const frontend_guard_1 = require("../_lib/frontend-guard");
|
|
78
|
+
const status_1 = require("./status");
|
|
65
79
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* assumed to have completed the docker push before invoking the CLI.
|
|
80
|
+
* Pure orchestration body — exported for unit tests. Throws on every error
|
|
81
|
+
* path; the command-level action wraps this and exits the process.
|
|
69
82
|
*/
|
|
70
|
-
async function
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
async function runDeploy(opts) {
|
|
84
|
+
const manifest = (0, deploy_manifest_1.parseManifest)(opts.manifestPath);
|
|
85
|
+
const env = (0, env_1.readEnv)(opts.envPath);
|
|
86
|
+
// ── Pre-flight: framework + SDK gate. The project MUST be built with the
|
|
87
|
+
// HSUITE SDK — abort before connecting to the cluster otherwise. ────────
|
|
88
|
+
const detection = (0, framework_1.detectFramework)(opts.projectDir);
|
|
89
|
+
const sdkVersion = (0, framework_1.resolveSdkVersion)(opts.projectDir, detection);
|
|
90
|
+
console.log(chalk_1.default.gray(` framework: ${detection.framework} (via ${detection.sdkPackage})`));
|
|
91
|
+
console.log(chalk_1.default.gray(` sdk: ${sdkVersion}`));
|
|
92
|
+
// ── The ONE client. ──────────────────────────────────────────────────────
|
|
93
|
+
// MINT-FIRST / DEPLOY-LAST: the appId is the developer's already-minted,
|
|
94
|
+
// ACTIVE subscription entity (`SUBSCRIPTION_APP_ID == DEPLOYED_APP_ID == DKG
|
|
95
|
+
// entityId`, created + paid by `hsuite subscribe`). `deploy` NEVER allocates
|
|
96
|
+
// an app — it requires that id as input and only fetches push creds for it.
|
|
97
|
+
// `requireSubscriptionAppId` reads it from `--subscription-app-id` else
|
|
98
|
+
// `SUBSCRIPTION_APP_ID`, throwing the "run `hsuite subscribe` first" guidance
|
|
99
|
+
// when absent.
|
|
100
|
+
const appId = (0, subscription_env_1.requireSubscriptionAppId)(env, {
|
|
101
|
+
subscriptionAppId: opts.subscriptionAppId,
|
|
102
|
+
});
|
|
103
|
+
const client = await (0, baas_1.connectAndAuth)({
|
|
104
|
+
gateway: opts.gateway,
|
|
105
|
+
env,
|
|
106
|
+
appId,
|
|
107
|
+
clientFactory: opts.clientFactory,
|
|
108
|
+
});
|
|
109
|
+
console.log(chalk_1.default.gray(' authenticated'));
|
|
110
|
+
// ── push credentials → ephemeral Harbor registry creds for THIS app. ─────
|
|
111
|
+
// Replaces the old `init` call: no entity is created, no subscription is
|
|
112
|
+
// made. The host asserts ownership + an ACTIVE subscription, then issues
|
|
113
|
+
// per-app push creds (idempotent). `init.appId` echoes back the same appId.
|
|
114
|
+
const b = manifest.backend;
|
|
115
|
+
const init = await client.deployment.pushCredentials(appId);
|
|
116
|
+
console.log(chalk_1.default.gray(` credentials: appId=${init.appId} registry=${init.registry.repository}`));
|
|
117
|
+
// ── backend: docker build + push. Returns the `docker push` SUMMARY digest —
|
|
118
|
+
// the digest the local client holds, which a containerd image store may
|
|
119
|
+
// report differently from the digest Harbor serves for the tag (#1589). ──
|
|
120
|
+
const pushDigest = (0, baas_1.buildAndPush)({
|
|
121
|
+
registry: init.registry,
|
|
122
|
+
tag: b.tag,
|
|
123
|
+
context: (0, path_1.resolve)(b.context ?? '.'),
|
|
124
|
+
dockerfile: b.dockerfile ?? 'Dockerfile',
|
|
125
|
+
platform: b.platform,
|
|
126
|
+
build: b.build,
|
|
127
|
+
skipBuild: opts.skipBuild,
|
|
128
|
+
skipPush: opts.skipPush,
|
|
129
|
+
dockerHost: opts.dockerHost,
|
|
130
|
+
name: manifest.name,
|
|
131
|
+
runFn: opts.runFn,
|
|
132
|
+
});
|
|
133
|
+
// #1589: attest the digest the registry SERVES for the tag (the same
|
|
134
|
+
// `Docker-Content-Digest` the deployer resolves + pins and the fan-out
|
|
135
|
+
// re-verifies), NOT the local `docker push` summary — otherwise the #1445
|
|
136
|
+
// strict-equality gate rejects a legitimate containerd-store developer build.
|
|
137
|
+
const imageDigest = await (0, registry_fanout_1.resolveAttestationDigest)({
|
|
138
|
+
registry: init.registry,
|
|
139
|
+
tag: b.tag,
|
|
140
|
+
pushDigest,
|
|
141
|
+
log: (m) => console.log(chalk_1.default.gray(m)),
|
|
142
|
+
});
|
|
143
|
+
console.log(chalk_1.default.gray(` pushed: ${init.registry.server}/${init.registry.repository}:${b.tag} (${imageDigest})`));
|
|
144
|
+
// ── distribute: fan the pushed image out to EVERY cluster Harbor. ─────────
|
|
145
|
+
// The federated registry host is public-DNS round-robin over the cluster
|
|
146
|
+
// ingresses, so the single `docker push` above lands the image on exactly ONE
|
|
147
|
+
// cluster. We copy it to the rest at the Registry-v2 level and BLOCK the
|
|
148
|
+
// deploy until every cluster serves the exact pushed digest — the async Harbor
|
|
149
|
+
// replication mesh is not load-bearing. `--skip-distribute` opts out (e.g. a
|
|
150
|
+
// single-cluster/dev registry); `--skip-push` already implies the bytes are
|
|
151
|
+
// wherever the prior push put them, so we still distribute from there. Throws
|
|
152
|
+
// (→ exit 1, deploy never called) if any cluster can't be made to serve it.
|
|
153
|
+
if (!opts.skipDistribute) {
|
|
154
|
+
await (0, registry_fanout_1.fanOutPushedImage)({
|
|
155
|
+
registry: init.registry,
|
|
156
|
+
tag: b.tag,
|
|
157
|
+
digest: imageDigest,
|
|
158
|
+
log: (m) => console.log(chalk_1.default.gray(m)),
|
|
76
159
|
});
|
|
160
|
+
}
|
|
161
|
+
// ── frontend: tar + upload (when a frontend source is present). ──────────
|
|
162
|
+
// Relative `frontend.dir`/`bundlePath` (and the frontend build hook) resolve
|
|
163
|
+
// against the smart-app root — the manifest's `backend.context` when present,
|
|
164
|
+
// else `--project` — NOT the CLI's process.cwd(). (Same cwd class as the
|
|
165
|
+
// backend build: a bare `public` must mean `<smart-app>/public`.)
|
|
166
|
+
const baseDir = (0, path_1.resolve)(b.context ?? opts.projectDir);
|
|
167
|
+
let bundleSha256 = '';
|
|
168
|
+
if (manifest.frontend) {
|
|
169
|
+
const bundlePath = await resolveFrontendBundle(manifest, baseDir, opts.runFn);
|
|
170
|
+
const bundle = await fs_1.promises.readFile(bundlePath);
|
|
171
|
+
const upload = await client.deployment.uploadFrontend(init.appId, bundle);
|
|
172
|
+
bundleSha256 = upload.bundleSha256;
|
|
173
|
+
console.log(chalk_1.default.gray(` frontend: sha256=${bundleSha256.slice(0, 12)}…`));
|
|
174
|
+
}
|
|
175
|
+
// ── runtime env: forward the developer's `.env.local` runtime creds into the
|
|
176
|
+
// deployed customer-env (issue #1564). Without this the container's env is
|
|
177
|
+
// ONLY `manifest.backend.env`, so a subscribed app boots credential-less →
|
|
178
|
+
// OPEN / in-memory mode. `manifest.backend.env` still wins for explicit
|
|
179
|
+
// non-secret overrides; secrets (XRPL_SEED, …) ride from `.env.local`
|
|
180
|
+
// automatically. Resolved BEFORE the attestation-seed check below so a
|
|
181
|
+
// subscribed-but-credential-less deploy fails with the specific #1564
|
|
182
|
+
// remedy (not the generic attestation error). FAILS LOUD unless
|
|
183
|
+
// `--allow-open-mode` is set — which then deliberately WITHHOLDS the seed
|
|
184
|
+
// from the container (open mode) while still using it locally to sign. The
|
|
185
|
+
// customer-env Secret is PQC-encrypted at rest — no secret in any committed
|
|
186
|
+
// file. ───────────────────────────────────────────────────────────────────
|
|
187
|
+
const runtimeEnv = (0, runtime_env_1.resolveRuntimeEnv)({
|
|
188
|
+
env,
|
|
189
|
+
manifestEnv: b.env,
|
|
190
|
+
allowOpenMode: opts.allowOpenMode,
|
|
191
|
+
warn: (m) => console.warn(chalk_1.default.yellow(` ⚠ ${m}`)),
|
|
77
192
|
});
|
|
193
|
+
console.log(chalk_1.default.gray(` runtime env: ${Object.keys(runtimeEnv).length} vars forwarded from ${opts.envPath} + manifest` +
|
|
194
|
+
(runtimeEnv.XRPL_SEED ? ' (cluster mode)' : ' (open mode)')));
|
|
195
|
+
// ── assemble + sign (AFTER upload so bundleSha256 is known). The host's
|
|
196
|
+
// hardened deploy policy requires a signed attestation, so the developer's
|
|
197
|
+
// seed is needed to SIGN regardless of open/cluster mode — an intentional
|
|
198
|
+
// open-mode deploy still signs with the local seed, it just doesn't forward
|
|
199
|
+
// it into the container (handled above). ─────────────────────────────────
|
|
200
|
+
const seed = env.get('XRPL_SEED');
|
|
201
|
+
if (!seed)
|
|
202
|
+
throw new Error('XRPL_SEED required to sign the build attestation');
|
|
203
|
+
const signed = (0, attestation_1.assembleAndSign)({
|
|
204
|
+
appId: init.appId,
|
|
205
|
+
developerWallet: env.get('XRPL_ADDRESS') ?? '',
|
|
206
|
+
developerChain: 'xrpl',
|
|
207
|
+
framework: detection.framework,
|
|
208
|
+
sdkVersion,
|
|
209
|
+
// The pushed image's `sha256:<64hex>` registry manifest digest (captured
|
|
210
|
+
// by buildAndPush). The host binds this to the digest Harbor serves for
|
|
211
|
+
// the tag with strict equality, so it MUST be the digest — not the
|
|
212
|
+
// tag-form ref, which the gate rejects once requireSignature is enforced.
|
|
213
|
+
imageDigest,
|
|
214
|
+
bundleSha256,
|
|
215
|
+
cliVersion: (0, attestation_1.readCliVersion)(),
|
|
216
|
+
}, seed);
|
|
217
|
+
const url = await deployBackend(client, init.appId, manifest, signed, runtimeEnv, opts.strategy);
|
|
218
|
+
// ── wait: block until the runtime settles (default on). `deploy()` returns a
|
|
219
|
+
// URL that is not live until the pods converge across every degree cluster,
|
|
220
|
+
// so a fire-and-forget deploy can print a URL that 502s. Poll until
|
|
221
|
+
// RUNNING/FAILED (or the budget elapses) and fail non-zero on FAILED. ────
|
|
222
|
+
if (opts.wait !== false) {
|
|
223
|
+
const status = await (0, status_1.waitForRunning)(client, init.appId, {
|
|
224
|
+
intervalMs: opts.waitIntervalMs,
|
|
225
|
+
maxPolls: opts.waitMaxPolls,
|
|
226
|
+
sleep: opts.sleep,
|
|
227
|
+
});
|
|
228
|
+
const rs = status.runtime?.runtimeState ?? status.state;
|
|
229
|
+
console.log(chalk_1.default.gray(` runtime: ${rs}`));
|
|
230
|
+
if (status.runtime?.runtimeState === 'FAILED') {
|
|
231
|
+
throw new Error(`deploy reached FAILED runtime for ${init.appId}` +
|
|
232
|
+
(status.runtime?.lastError ? `: ${status.runtime.lastError}` : ''));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return { appId: init.appId, url };
|
|
78
236
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Resolve the frontend bundle to a tarball path: `bundlePath` wins; otherwise
|
|
239
|
+
* tar `dir` (running its optional `build` first) into a temp `.tar`.
|
|
240
|
+
*
|
|
241
|
+
* `baseDir` is the smart-app root (`backend.context` / `--project`); relative
|
|
242
|
+
* `dir`/`bundlePath` resolve against it, NOT the CLI's process.cwd(), and the
|
|
243
|
+
* optional pre-build hook runs with `cwd` set to the resolved `dir`.
|
|
244
|
+
*/
|
|
245
|
+
async function resolveFrontendBundle(manifest, baseDir, runFn) {
|
|
246
|
+
const f = manifest.frontend;
|
|
247
|
+
if (f.bundlePath) {
|
|
248
|
+
const p = (0, path_1.resolve)(baseDir, f.bundlePath);
|
|
249
|
+
if (!(0, fs_1.existsSync)(p))
|
|
250
|
+
throw new Error(`frontend bundle not found: ${p}`);
|
|
251
|
+
return p;
|
|
252
|
+
}
|
|
253
|
+
const dir = (0, path_1.resolve)(baseDir, f.dir);
|
|
254
|
+
if (!(0, fs_1.existsSync)(dir))
|
|
255
|
+
throw new Error(`frontend dir not found: ${dir}`);
|
|
256
|
+
// Optional pre-build (e.g. `ng build`) — run via the injected seam IN `dir`
|
|
257
|
+
// (a real chdir; `PWD` alone does not move the child's working directory).
|
|
258
|
+
if (f.build) {
|
|
259
|
+
const run = runFn ?? (await Promise.resolve().then(() => __importStar(require('child_process')))).execFileSync;
|
|
260
|
+
run('sh', ['-c', f.build], {
|
|
261
|
+
stdio: 'inherit',
|
|
262
|
+
cwd: dir,
|
|
263
|
+
env: { ...process.env, PWD: dir },
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
// Fail-closed: never ship a bundle that still carries unfilled
|
|
267
|
+
// `REPLACE_BEFORE_DEPLOY:<key>` placeholders. Such a build refuses to
|
|
268
|
+
// bootstrap in the browser (main.ts asserts on the sentinel prefix), and the
|
|
269
|
+
// CLI would otherwise upload it silently. Catch it here — after any build,
|
|
270
|
+
// before tar — with a clear remedy, regardless of how the bundle was produced.
|
|
271
|
+
await (0, frontend_guard_1.assertNoDeploySentinels)(dir);
|
|
272
|
+
const out = (0, path_1.join)((0, os_1.tmpdir)(), `hsuite-frontend-${Date.now()}.tar`);
|
|
273
|
+
return (0, baas_1.tarFrontend)({ dir, out, runFn });
|
|
274
|
+
}
|
|
275
|
+
/** Run the server-side deploy with the manifest body PLUS the attestation. */
|
|
276
|
+
async function deployBackend(client, appId, manifest, attestation, runtimeEnv, strategy) {
|
|
277
|
+
const b = manifest.backend;
|
|
278
|
+
const body = {
|
|
279
|
+
tag: b.tag,
|
|
280
|
+
port: b.port,
|
|
281
|
+
replicas: b.replicas ?? 1,
|
|
282
|
+
degree: manifest.degree,
|
|
283
|
+
// The RESOLVED runtime env — `.env.local` runtime creds merged with
|
|
284
|
+
// `manifest.backend.env` (manifest wins) — NOT `manifest.backend.env` alone
|
|
285
|
+
// (issue #1564). This is mirrored into the per-app PQC-encrypted
|
|
286
|
+
// customer-env Secret and `envFrom`-mounted on the backend container.
|
|
287
|
+
env: runtimeEnv,
|
|
288
|
+
resources: b.limits,
|
|
289
|
+
...(strategy ? { strategy } : {}),
|
|
290
|
+
attestation,
|
|
291
|
+
};
|
|
292
|
+
const res = await client.deployment.deploy(appId, body);
|
|
293
|
+
return res.url;
|
|
87
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* `hsuite deploy` commander command — thin action over {@link runDeploy}.
|
|
297
|
+
*/
|
|
88
298
|
exports.deployCommand = new commander_1.Command('deploy')
|
|
89
|
-
.description('Deploy a smart-app from a JSON manifest (
|
|
299
|
+
.description('Deploy a smart-app from a JSON manifest (NestJS backend + optional SPA bundle)')
|
|
90
300
|
.requiredOption('--manifest <file>', 'JSON manifest path')
|
|
91
301
|
.option('--env <file>', 'Env file with auth creds', '.env.local')
|
|
92
|
-
.option('--
|
|
93
|
-
.option('--
|
|
302
|
+
.option('--project <dir>', 'Smart-app project root (for SDK/framework detection)', '.')
|
|
303
|
+
.option('--gateway <url>', 'Smart-engines gateway URL', cluster_1.DEFAULT_GATEWAY)
|
|
304
|
+
.option('--subscription-app-id <id>', 'Subscription appId to deploy to (else SUBSCRIPTION_APP_ID). Mint-first: this id is both the auth identity and the deploy target; deploy allocates nothing.')
|
|
305
|
+
.option('--strategy <strategy>', 'Update strategy: rolling | recreate')
|
|
306
|
+
.option('--docker-host <host>', 'DOCKER_HOST for the build/push (defaults to $DOCKER_HOST)')
|
|
307
|
+
.option('--non-interactive', 'No prompts (CI). Currently a no-op — the flow is already headless.', false)
|
|
308
|
+
.option('--skip-build', 'Skip `docker build` (image already built locally under the local tag)', false)
|
|
309
|
+
.option('--skip-push', 'Skip `docker push` (image already present at the registry)', false)
|
|
310
|
+
.option('--skip-distribute', 'Skip the multi-cluster image fan-out (single-cluster / dev registry)', false)
|
|
311
|
+
.option('--allow-open-mode', 'Allow an intentional zero-cred / open-mode deploy (no XRPL_SEED forwarded). Default: a subscribed-but-credential-less deploy FAILS LOUD (#1564).', false)
|
|
312
|
+
.option('--no-wait', 'Do not block until the runtime settles — exit as soon as deploy() is accepted (default: wait for RUNNING/FAILED)')
|
|
94
313
|
.action(async (opts) => {
|
|
95
314
|
console.log(chalk_1.default.bold.cyan('\n hsuite deploy\n'));
|
|
96
|
-
|
|
97
|
-
if (!(0, fs_1.existsSync)(manifestPath)) {
|
|
98
|
-
console.error(chalk_1.default.red(` manifest not found: ${manifestPath}\n`));
|
|
99
|
-
process.exit(1);
|
|
100
|
-
}
|
|
101
|
-
const manifest = JSON.parse((0, fs_1.readFileSync)(manifestPath, 'utf8'));
|
|
102
|
-
if (!manifest.name ||
|
|
103
|
-
typeof manifest.port !== 'number' ||
|
|
104
|
-
!Array.isArray(manifest.services) ||
|
|
105
|
-
!manifest.tag) {
|
|
106
|
-
console.error(chalk_1.default.red(` manifest must have at minimum {name, port, services[], tag}\n`));
|
|
107
|
-
process.exit(1);
|
|
108
|
-
}
|
|
109
|
-
console.log(chalk_1.default.gray(` manifest: ${manifestPath}`));
|
|
110
|
-
console.log(chalk_1.default.gray(` name: ${manifest.name}`));
|
|
111
|
-
console.log(chalk_1.default.gray(` port: ${manifest.port}`));
|
|
112
|
-
console.log(chalk_1.default.gray(` services: ${manifest.services.join(', ') || '(none)'}`));
|
|
113
|
-
console.log(chalk_1.default.gray(` tag: ${manifest.tag}`));
|
|
114
|
-
console.log(chalk_1.default.gray(` bootstrap: ${opts.gateway}\n`));
|
|
115
|
-
const env = (0, env_1.readEnv)(opts.env);
|
|
116
|
-
const signer = (0, env_1.buildSignerFromEnv)(env);
|
|
117
|
-
// Decentralized cluster discovery is now handled by the SDK's canonical
|
|
118
|
-
// `BaasClient.connectToCluster` factory (SDK 3.4.0+) — bootstrap →
|
|
119
|
-
// registry → random cluster → BaasClient pointed at the picked cluster's
|
|
120
|
-
// gateway. We no longer maintain a parallel discovery path in the CLI.
|
|
121
|
-
//
|
|
122
|
-
// `pathPrefix` is omitted: the SDK defaults to `/host`, which matches
|
|
123
|
-
// the gateway's `/host(/|$)(.*)` ingress rewrite to the host service
|
|
124
|
-
// (charts/smart-engines/templates/ingress.yaml:131).
|
|
125
|
-
let spinner = (0, ora_1.default)('connecting to cluster...').start();
|
|
126
|
-
let client;
|
|
127
|
-
try {
|
|
128
|
-
client = await smart_engines_sdk_1.BaasClient.connectToCluster({
|
|
129
|
-
bootstrap: [opts.gateway],
|
|
130
|
-
appId: env.get('SUBSCRIPTION_APP_ID') ?? 'pending',
|
|
131
|
-
allowInsecure: opts.gateway.startsWith('http://'),
|
|
132
|
-
// deployment.init runs the smart-app entity DKG ceremony
|
|
133
|
-
// synchronously across the validator cluster — well past the 30s
|
|
134
|
-
// default. 3 min.
|
|
135
|
-
timeout: 180_000,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
catch (err) {
|
|
139
|
-
spinner.fail(`cluster connect failed: ${err.message}`);
|
|
140
|
-
process.exit(1);
|
|
141
|
-
}
|
|
142
|
-
spinner.succeed(`cluster: ${client.getHostUrl()}`);
|
|
143
|
-
spinner = (0, ora_1.default)('authenticate...').start();
|
|
315
|
+
let result;
|
|
144
316
|
try {
|
|
145
|
-
await
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
317
|
+
result = await runDeploy({
|
|
318
|
+
manifestPath: opts.manifest,
|
|
319
|
+
envPath: opts.env,
|
|
320
|
+
gateway: opts.gateway,
|
|
321
|
+
projectDir: opts.project,
|
|
322
|
+
strategy: opts.strategy,
|
|
323
|
+
dockerHost: opts.dockerHost ?? process.env.DOCKER_HOST,
|
|
324
|
+
skipBuild: opts.skipBuild,
|
|
325
|
+
skipPush: opts.skipPush,
|
|
326
|
+
skipDistribute: opts.skipDistribute,
|
|
327
|
+
subscriptionAppId: opts.subscriptionAppId,
|
|
328
|
+
allowOpenMode: opts.allowOpenMode,
|
|
329
|
+
wait: opts.wait,
|
|
150
330
|
});
|
|
151
331
|
}
|
|
152
332
|
catch (err) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
spinner.succeed('authenticated');
|
|
157
|
-
// ── Step 1: init ──────────────────────────────────────────────────
|
|
158
|
-
spinner = (0, ora_1.default)('init...').start();
|
|
159
|
-
let init;
|
|
160
|
-
try {
|
|
161
|
-
init = await client.deployment.init({
|
|
162
|
-
name: manifest.name,
|
|
163
|
-
port: manifest.port,
|
|
164
|
-
services: manifest.services,
|
|
165
|
-
limits: manifest.limits,
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
catch (err) {
|
|
169
|
-
spinner.fail(`init failed: ${err.message}`);
|
|
170
|
-
process.exit(1);
|
|
171
|
-
}
|
|
172
|
-
spinner.succeed(`init: appId=${init.appId} registry=${init.registry.repository}`);
|
|
173
|
-
// ── Step 2 (out-of-band): docker push ─────────────────────────────
|
|
174
|
-
console.log(chalk_1.default.bold.yellow('\n → push your image now:'));
|
|
175
|
-
console.log(` echo ${JSON.stringify(init.registry.password)} | docker login ${init.registry.server} -u ${init.registry.username} --password-stdin`);
|
|
176
|
-
console.log(` docker push ${init.registry.server}/${init.registry.repository}:${manifest.tag}`);
|
|
177
|
-
if (!isNonInteractive(opts.nonInteractive)) {
|
|
178
|
-
console.log(chalk_1.default.bold.yellow('\n → press Enter when push is complete'));
|
|
179
|
-
await waitForEnter();
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
console.log(chalk_1.default.gray(' (non-interactive: assuming push already complete)'));
|
|
183
|
-
}
|
|
184
|
-
// ── Step 3 (optional): upload frontend ────────────────────────────
|
|
185
|
-
if (manifest.frontend?.bundlePath) {
|
|
186
|
-
const bundlePath = (0, path_1.resolve)(manifest.frontend.bundlePath);
|
|
187
|
-
if (!(0, fs_1.existsSync)(bundlePath)) {
|
|
188
|
-
console.error(chalk_1.default.red(` frontend bundle not found: ${bundlePath}\n`));
|
|
189
|
-
process.exit(1);
|
|
190
|
-
}
|
|
191
|
-
spinner = (0, ora_1.default)('uploading frontend bundle...').start();
|
|
192
|
-
try {
|
|
193
|
-
const bundle = await fs_1.promises.readFile(bundlePath);
|
|
194
|
-
const upload = await client.deployment.uploadFrontend(init.appId, bundle);
|
|
195
|
-
spinner.succeed(`frontend uploaded: sha256=${upload.bundleSha256.slice(0, 12)}…`);
|
|
333
|
+
if (err instanceof framework_1.NoSdkError) {
|
|
334
|
+
console.error(chalk_1.default.red(`\n ✗ ${err.message}\n`));
|
|
196
335
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
process.exit(1);
|
|
336
|
+
else {
|
|
337
|
+
console.error(chalk_1.default.red(`\n ✗ ${err.message}\n`));
|
|
200
338
|
}
|
|
201
|
-
}
|
|
202
|
-
// ── Step 4: deploy ────────────────────────────────────────────────
|
|
203
|
-
spinner = (0, ora_1.default)('deploying...').start();
|
|
204
|
-
let deployRes;
|
|
205
|
-
try {
|
|
206
|
-
deployRes = await client.deployment.deploy(init.appId, {
|
|
207
|
-
tag: manifest.tag,
|
|
208
|
-
port: manifest.port,
|
|
209
|
-
replicas: manifest.replicas ?? 1,
|
|
210
|
-
env: manifest.env,
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
catch (err) {
|
|
214
|
-
spinner.fail(`deploy failed: ${err.message}`);
|
|
215
339
|
process.exit(1);
|
|
216
340
|
}
|
|
217
|
-
|
|
218
|
-
(
|
|
219
|
-
console.log(chalk_1.default.bold.green('\n ✓ done\n'));
|
|
341
|
+
(0, env_1.upsertEnv)(opts.env, { DEPLOYED_APP_ID: result.appId });
|
|
342
|
+
console.log(chalk_1.default.bold.green(`\n ✓ deployed: ${result.url}\n`));
|
|
220
343
|
});
|
|
221
344
|
//# sourceMappingURL=deploy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,7 +34,7 @@ exports.downgradeCommand = new commander_1.Command('downgrade')
|
|
|
34
34
|
.option('--env <file>', 'Env file with subscription appId', '.env.local')
|
|
35
35
|
.option('--gateway <url>', 'Validator/gateway URL (defaults to VALIDATOR_URL in env)')
|
|
36
36
|
.option('--app-id <id>', 'Override SUBSCRIPTION_APP_ID from env')
|
|
37
|
-
.requiredOption('--to-tier <tier>', 'Target tier (
|
|
37
|
+
.requiredOption('--to-tier <tier>', 'Target tier (builder|growth|scale)')
|
|
38
38
|
.action(async (opts) => {
|
|
39
39
|
console.log(chalk_1.default.bold.cyan('\n hsuite downgrade\n'));
|
|
40
40
|
const spinner = (0, ora_1.default)(`scheduling downgrade to ${opts.toTier}...`).start();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"downgrade.js","sourceRoot":"","sources":["../../src/commands/downgrade.ts"],"names":[],"mappings":";;;;;;AAoBA,oCAeC;AAnCD;;;;GAIG;AACH,yCAAoC;AACpC,kDAA0B;AAC1B,8CAAsB;AACtB,qCAAsC;AACtC,qEAAiE;AACjE,+DAA6E;AAUtE,KAAK,UAAU,YAAY,CAAC,IAAmB;IAKpD,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,IAAA,aAAO,EAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAA,sCAAmB,EAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG,IAAA,+BAAY,EAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,wCAAkB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAChG,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvD,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,CAAC,OAAO,IAAI,eAAe,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;AACtE,CAAC;AAEY,QAAA,gBAAgB,GAAG,IAAI,mBAAO,CAAC,WAAW,CAAC;KACrD,WAAW,CAAC,gDAAgD,CAAC;KAC7D,MAAM,CAAC,cAAc,EAAE,kCAAkC,EAAE,YAAY,CAAC;KACxE,MAAM,CAAC,iBAAiB,EAAE,0DAA0D,CAAC;KACrF,MAAM,CAAC,eAAe,EAAE,uCAAuC,CAAC;KAChE,cAAc,CAAC,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"downgrade.js","sourceRoot":"","sources":["../../src/commands/downgrade.ts"],"names":[],"mappings":";;;;;;AAoBA,oCAeC;AAnCD;;;;GAIG;AACH,yCAAoC;AACpC,kDAA0B;AAC1B,8CAAsB;AACtB,qCAAsC;AACtC,qEAAiE;AACjE,+DAA6E;AAUtE,KAAK,UAAU,YAAY,CAAC,IAAmB;IAKpD,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,IAAA,aAAO,EAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAA,sCAAmB,EAAC,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG,IAAA,+BAAY,EAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,wCAAkB,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAChG,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvD,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,CAAC,OAAO,IAAI,eAAe,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;AACtE,CAAC;AAEY,QAAA,gBAAgB,GAAG,IAAI,mBAAO,CAAC,WAAW,CAAC;KACrD,WAAW,CAAC,gDAAgD,CAAC;KAC7D,MAAM,CAAC,cAAc,EAAE,kCAAkC,EAAE,YAAY,CAAC;KACxE,MAAM,CAAC,iBAAiB,EAAE,0DAA0D,CAAC;KACrF,MAAM,CAAC,eAAe,EAAE,uCAAuC,CAAC;KAChE,cAAc,CAAC,kBAAkB,EAAE,oCAAoC,CAAC;KACxE,MAAM,CAAC,KAAK,EAAE,IAAmB,EAAE,EAAE;IACpC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,IAAA,aAAG,EAAC,2BAA2B,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;IACzE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;QACxC,OAAO,CAAC,OAAO,CAAC,0BAA0B,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACrD,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `hsuite faucet` — Drip HSUITE-testnet tokens to the dev wallet against the
|
|
3
|
+
* validator's `@Public()` `/api/v3/faucet/hsuite/*` surface.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. Read XRPL_ADDRESS + XRPL_SEED from env (written by `hsuite init`).
|
|
7
|
+
* 2. POST /faucet/hsuite/challenge → sign the returned message → POST
|
|
8
|
+
* /faucet/hsuite to dispense.
|
|
9
|
+
* 3. Branch on the dispense response:
|
|
10
|
+
* - 'dispensed': print amount + txHash. Done.
|
|
11
|
+
* - 'trustline_required': set the HST trustline on the dev wallet via the
|
|
12
|
+
* XRPL testnet, then RETRY a fresh
|
|
13
|
+
* challenge→sign→dispense once.
|
|
14
|
+
* - 'rate_limited': print retryAfterSeconds and exit non-zero.
|
|
15
|
+
*
|
|
16
|
+
* Signing matches the cluster's Web3AuthService verifier (ripple-keypairs):
|
|
17
|
+
* hex-encode the UTF-8 message, uppercase, sign with the seed's private key.
|
|
18
|
+
*/
|
|
19
|
+
import { Command } from 'commander';
|
|
20
|
+
import { FaucetClient } from '../_lib/faucet-client';
|
|
21
|
+
/**
|
|
22
|
+
* Minimal structural shape of the bits of the `xrpl` Client we use. Lets the
|
|
23
|
+
* unit tests inject a fake without pulling the real websocket library.
|
|
24
|
+
*/
|
|
25
|
+
export type XrplClientLike = {
|
|
26
|
+
connect(): Promise<unknown>;
|
|
27
|
+
disconnect(): Promise<unknown>;
|
|
28
|
+
autofill(tx: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
29
|
+
submitAndWait(blob: string): Promise<{
|
|
30
|
+
result: {
|
|
31
|
+
meta?: any;
|
|
32
|
+
};
|
|
33
|
+
}>;
|
|
34
|
+
};
|
|
35
|
+
export type FaucetOpts = {
|
|
36
|
+
env: string;
|
|
37
|
+
gateway?: string;
|
|
38
|
+
chain: string;
|
|
39
|
+
clientFactory?: (baseUrl: string) => FaucetClient;
|
|
40
|
+
/** Builds an XRPL client for the trustline submit. Defaults to real `xrpl`. */
|
|
41
|
+
xrplClientFactory?: (wss: string) => XrplClientLike;
|
|
42
|
+
/** Signs the faucet challenge message; defaults to ripple-keypairs. */
|
|
43
|
+
signFactory?: (seed: string) => {
|
|
44
|
+
publicKey: string;
|
|
45
|
+
sign: (message: string) => string;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Signs a prepared XRPL TrustSet tx with the dev wallet seed, returning the
|
|
49
|
+
* tx_blob to submit. Defaults to `xrpl`'s `Wallet.fromSeed(seed).sign(tx)`.
|
|
50
|
+
* Injected by unit tests so they don't need a real-format seed.
|
|
51
|
+
*/
|
|
52
|
+
walletSignFactory?: (seed: string) => (tx: Record<string, unknown>) => string;
|
|
53
|
+
};
|
|
54
|
+
export type FaucetResult = {
|
|
55
|
+
status: 'dispensed';
|
|
56
|
+
amount: string;
|
|
57
|
+
txHash: string;
|
|
58
|
+
remainingDailyAllowance: string;
|
|
59
|
+
/** True when a trustline was set + a second dispense attempt was made. */
|
|
60
|
+
trustlineSet: boolean;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Error surfaced when the faucet is rate-limited. The command-level action
|
|
64
|
+
* catches it to print a friendly message + exit non-zero (vs. a crash trace).
|
|
65
|
+
*/
|
|
66
|
+
export declare class FaucetRateLimitedError extends Error {
|
|
67
|
+
readonly retryAfterSeconds: number;
|
|
68
|
+
constructor(retryAfterSeconds: number);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Pure orchestration body — exported for unit tests.
|
|
72
|
+
*
|
|
73
|
+
* Throws on every error path; the command-level action wraps this and exits
|
|
74
|
+
* the process. `FaucetRateLimitedError` is thrown for the rate-limited branch.
|
|
75
|
+
*/
|
|
76
|
+
export declare function runFaucet(opts: FaucetOpts): Promise<FaucetResult>;
|
|
77
|
+
export declare const faucetCommand: Command;
|
|
78
|
+
//# sourceMappingURL=faucet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faucet.d.ts","sourceRoot":"","sources":["../../src/commands/faucet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EACL,YAAY,EAIb,MAAM,uBAAuB,CAAC;AAM/B;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxE,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE;YAAE,IAAI,CAAC,EAAE,GAAG,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CAClE,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IAEd,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,YAAY,CAAC;IAClD,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,cAAc,CAAC;IACpD,uEAAuE;IACvE,WAAW,CAAC,EAAE,CACZ,IAAI,EAAE,MAAM,KACT;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;KAAE,CAAC;IAC9D;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAClB,IAAI,EAAE,MAAM,KACT,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB,EAAE,MAAM,CAAC;IAChC,0EAA0E;IAC1E,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAoCF;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;gBACvB,iBAAiB,EAAE,MAAM;CAKtC;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAkCvE;AA0DD,eAAO,MAAM,aAAa,SAkCtB,CAAC"}
|