@hsuite/smart-engines-cli 1.2.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +272 -58
  2. package/dist/_lib/attestation.d.ts +45 -0
  3. package/dist/_lib/attestation.d.ts.map +1 -0
  4. package/dist/_lib/attestation.js +76 -0
  5. package/dist/_lib/attestation.js.map +1 -0
  6. package/dist/_lib/baas.d.ts +147 -0
  7. package/dist/_lib/baas.d.ts.map +1 -0
  8. package/dist/_lib/baas.js +260 -0
  9. package/dist/_lib/baas.js.map +1 -0
  10. package/dist/_lib/cluster.d.ts +6 -6
  11. package/dist/_lib/cluster.js +6 -6
  12. package/dist/_lib/deploy-manifest.d.ts +69 -0
  13. package/dist/_lib/deploy-manifest.d.ts.map +1 -0
  14. package/dist/_lib/deploy-manifest.js +87 -0
  15. package/dist/_lib/deploy-manifest.js.map +1 -0
  16. package/dist/_lib/docker.d.ts +82 -0
  17. package/dist/_lib/docker.d.ts.map +1 -0
  18. package/dist/_lib/docker.js +164 -0
  19. package/dist/_lib/docker.js.map +1 -0
  20. package/dist/_lib/faucet-client.d.ts +64 -0
  21. package/dist/_lib/faucet-client.d.ts.map +1 -0
  22. package/dist/_lib/faucet-client.js +92 -0
  23. package/dist/_lib/faucet-client.js.map +1 -0
  24. package/dist/_lib/framework.d.ts +59 -0
  25. package/dist/_lib/framework.d.ts.map +1 -0
  26. package/dist/_lib/framework.js +149 -0
  27. package/dist/_lib/framework.js.map +1 -0
  28. package/dist/_lib/frontend-guard.d.ts +13 -0
  29. package/dist/_lib/frontend-guard.d.ts.map +1 -0
  30. package/dist/_lib/frontend-guard.js +41 -0
  31. package/dist/_lib/frontend-guard.js.map +1 -0
  32. package/dist/_lib/registry-fanout.d.ts +114 -0
  33. package/dist/_lib/registry-fanout.d.ts.map +1 -0
  34. package/dist/_lib/registry-fanout.js +435 -0
  35. package/dist/_lib/registry-fanout.js.map +1 -0
  36. package/dist/_lib/runtime-env.d.ts +126 -0
  37. package/dist/_lib/runtime-env.d.ts.map +1 -0
  38. package/dist/_lib/runtime-env.js +172 -0
  39. package/dist/_lib/runtime-env.js.map +1 -0
  40. package/dist/_lib/subscription-client.d.ts +129 -18
  41. package/dist/_lib/subscription-client.d.ts.map +1 -1
  42. package/dist/_lib/subscription-client.js +268 -40
  43. package/dist/_lib/subscription-client.js.map +1 -1
  44. package/dist/_lib/subscription-env.d.ts +35 -0
  45. package/dist/_lib/subscription-env.d.ts.map +1 -1
  46. package/dist/_lib/subscription-env.js +46 -2
  47. package/dist/_lib/subscription-env.js.map +1 -1
  48. package/dist/commands/app-lifecycle.d.ts +36 -0
  49. package/dist/commands/app-lifecycle.d.ts.map +1 -0
  50. package/dist/commands/app-lifecycle.js +145 -0
  51. package/dist/commands/app-lifecycle.js.map +1 -0
  52. package/dist/commands/ci.d.ts +45 -0
  53. package/dist/commands/ci.d.ts.map +1 -0
  54. package/dist/commands/ci.js +174 -0
  55. package/dist/commands/ci.js.map +1 -0
  56. package/dist/commands/deploy-manifest.d.ts +11 -0
  57. package/dist/commands/deploy-manifest.d.ts.map +1 -0
  58. package/dist/commands/deploy-manifest.js +17 -0
  59. package/dist/commands/deploy-manifest.js.map +1 -0
  60. package/dist/commands/deploy.d.ts +70 -11
  61. package/dist/commands/deploy.d.ts.map +1 -1
  62. package/dist/commands/deploy.js +263 -150
  63. package/dist/commands/deploy.js.map +1 -1
  64. package/dist/commands/downgrade.js +1 -1
  65. package/dist/commands/downgrade.js.map +1 -1
  66. package/dist/commands/faucet.d.ts +78 -0
  67. package/dist/commands/faucet.d.ts.map +1 -0
  68. package/dist/commands/faucet.js +184 -0
  69. package/dist/commands/faucet.js.map +1 -0
  70. package/dist/commands/governance.js +1 -1
  71. package/dist/commands/governance.js.map +1 -1
  72. package/dist/commands/hist-balance.d.ts +1 -1
  73. package/dist/commands/hist-balance.js +1 -1
  74. package/dist/commands/init.js +1 -1
  75. package/dist/commands/list.d.ts +22 -0
  76. package/dist/commands/list.d.ts.map +1 -0
  77. package/dist/commands/list.js +81 -0
  78. package/dist/commands/list.js.map +1 -0
  79. package/dist/commands/personhood.js +2 -2
  80. package/dist/commands/personhood.js.map +1 -1
  81. package/dist/commands/redeploy.d.ts +62 -0
  82. package/dist/commands/redeploy.d.ts.map +1 -0
  83. package/dist/commands/redeploy.js +310 -0
  84. package/dist/commands/redeploy.js.map +1 -0
  85. package/dist/commands/status.d.ts +51 -0
  86. package/dist/commands/status.d.ts.map +1 -0
  87. package/dist/commands/status.js +138 -0
  88. package/dist/commands/status.js.map +1 -0
  89. package/dist/commands/subscribe.d.ts +94 -17
  90. package/dist/commands/subscribe.d.ts.map +1 -1
  91. package/dist/commands/subscribe.js +450 -81
  92. package/dist/commands/subscribe.js.map +1 -1
  93. package/dist/commands/transactions.d.ts +60 -0
  94. package/dist/commands/transactions.d.ts.map +1 -0
  95. package/dist/commands/transactions.js +101 -0
  96. package/dist/commands/transactions.js.map +1 -0
  97. package/dist/commands/update.d.ts +40 -0
  98. package/dist/commands/update.d.ts.map +1 -0
  99. package/dist/commands/update.js +114 -0
  100. package/dist/commands/update.js.map +1 -0
  101. package/dist/commands/verify.d.ts +10 -19
  102. package/dist/commands/verify.d.ts.map +1 -1
  103. package/dist/commands/verify.js +14 -23
  104. package/dist/commands/verify.js.map +1 -1
  105. package/dist/index.d.ts +12 -3
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +32 -3
  108. package/dist/index.js.map +1 -1
  109. package/package.json +11 -4
@@ -0,0 +1,147 @@
1
+ import { BaasClient } from '@hsuite/smart-engines-sdk';
2
+ import type { EnvMap } from './env';
3
+ /** Default per-app deploy timeout — `init` runs the smart-app entity DKG ceremony. */
4
+ export declare const DEFAULT_DEPLOY_TIMEOUT_MS = 240000;
5
+ /**
6
+ * Target build platform for the backend image. The cluster nodes are amd64, so
7
+ * a single-arch `linux/amd64` image is the standard — never a multi-arch OCI
8
+ * index. See {@link buildAndPush} for why this is load-bearing (an arm64 build
9
+ * host with the buildkit/containerd snapshotter otherwise emits an arm64-only
10
+ * provenance-attested OCI index the amd64 nodes can't pull/run).
11
+ */
12
+ export declare const DEFAULT_BUILD_PLATFORM = "linux/amd64";
13
+ /** Registry coordinates returned by `deployment.init` (`BaasInitResponse`). */
14
+ export type RegistryCreds = {
15
+ server: string;
16
+ username: string;
17
+ password: string;
18
+ repository: string;
19
+ };
20
+ /**
21
+ * `execFileSync`-shaped seam. Throwing on a non-zero exit is the contract
22
+ * `execFileSync` provides.
23
+ *
24
+ * The return value MATTERS for stdout-capturing invocations (the `docker push`
25
+ * and `docker inspect` legs in {@link buildAndPush}): `execFileSync` returns the
26
+ * child's stdout, and with `encoding: 'utf8'` that is a `string`. We parse the
27
+ * push summary / `RepoDigests` out of it to recover the pushed manifest digest.
28
+ * Legs run with inherited stdio (build/tag/login) return nothing meaningful.
29
+ * Unit tests supply a fake that returns canned push/inspect stdout.
30
+ */
31
+ export type RunFn = (file: string, args: string[], options: {
32
+ input?: string;
33
+ stdio?: unknown;
34
+ env?: NodeJS.ProcessEnv;
35
+ cwd?: string;
36
+ encoding?: BufferEncoding;
37
+ }) => unknown;
38
+ export type ConnectAndAuthOpts = {
39
+ /** Public gateway/host URL. */
40
+ gateway: string;
41
+ /** Parsed env (XRPL signer is built from it). */
42
+ env: EnvMap;
43
+ /** Existing appId to bind the client to. Falls back to `'pending'`. */
44
+ appId?: string;
45
+ /** Request timeout (ms). Defaults to {@link DEFAULT_DEPLOY_TIMEOUT_MS}. */
46
+ timeout?: number;
47
+ /**
48
+ * Test seam — build the client (and auth on it) without a real `new
49
+ * BaasClient`. Defaults to the real single-construction path.
50
+ */
51
+ clientFactory?: (config: {
52
+ hostUrl: string;
53
+ appId: string;
54
+ allowInsecure: boolean;
55
+ pathPrefix: string;
56
+ timeout: number;
57
+ }) => BaasClient;
58
+ };
59
+ /**
60
+ * Construct the ONE {@link BaasClient} and authenticate it with the env XRPL
61
+ * signer. Returns the authenticated client. Throws on a missing signer or an
62
+ * auth failure (the command-level action renders + exits).
63
+ */
64
+ export declare function connectAndAuth(opts: ConnectAndAuthOpts): Promise<BaasClient>;
65
+ export type BuildAndPushOpts = {
66
+ registry: RegistryCreds;
67
+ tag: string;
68
+ /** Docker build context directory. */
69
+ context: string;
70
+ /** Dockerfile path (relative to `context` or absolute). */
71
+ dockerfile: string;
72
+ /** Optional pre-build command (e.g. `yarn build`), run in `context`. */
73
+ build?: string;
74
+ /** Skip the `docker build` (image already built locally under the local tag). */
75
+ skipBuild?: boolean;
76
+ /** Skip the `docker push` (image already present at the registry). */
77
+ skipPush?: boolean;
78
+ /** `DOCKER_HOST` to thread to every docker invocation (defaults to env). */
79
+ dockerHost?: string;
80
+ /** App name — used to compose the deterministic local tag. */
81
+ name: string;
82
+ /**
83
+ * Target build platform. Defaults to {@link DEFAULT_BUILD_PLATFORM}
84
+ * (`linux/amd64`, the cluster-node standard). Overridable via the manifest's
85
+ * `backend.platform` only if a customer genuinely targets a different arch —
86
+ * the default is correct for every testnet/mainnet node today.
87
+ */
88
+ platform?: string;
89
+ /** Test seam — defaults to `execFileSync`. */
90
+ runFn?: RunFn;
91
+ /** Push retry attempts (round-robin robot-auth can need a couple). Default 6. */
92
+ pushAttempts?: number;
93
+ };
94
+ /**
95
+ * The fully-qualified target image reference: `<server>/<repository>:<tag>`.
96
+ */
97
+ export declare function imageTarget(registry: RegistryCreds, tag: string): string;
98
+ /**
99
+ * Build the backend image, tag it for the per-app Harbor repo, log in with the
100
+ * init-issued robot creds, push (with retries), and RECORD the pushed image's
101
+ * `sha256:<64hex>` registry manifest digest.
102
+ *
103
+ * Mirrors the working `deploy-v9.cjs` docker leg exactly, plus the single-arch
104
+ * pin (below):
105
+ * - optional `<build>` (shell command) in `context`
106
+ * - `docker build --platform linux/amd64 --provenance=false --sbom=false
107
+ * -t hsuite-local/<name>:<tag> -f <dockerfile> <context>`
108
+ * - `docker tag <local> <server>/<repo>:<tag>`
109
+ * - `docker login <server> -u <username> --password-stdin` ← username a
110
+ * DISCRETE argv element; password on stdin
111
+ * - `docker push <target>` retried up to `pushAttempts` times, stdout CAPTURED
112
+ *
113
+ * Returns the pushed image's `sha256:<64hex>` manifest digest — NOT the tag-form
114
+ * ref. The build attestation's `imageDigest` must carry this digest: the host
115
+ * binds it to the digest Harbor serves for the tag with strict equality, so a
116
+ * tag-form ref is rejected once `requireSignature` is enforced. The digest is
117
+ * read from the `docker push` summary ({@link parsePushDigest}); if the summary
118
+ * lacked one (older docker / buildx drivers / `--skip-push`), it falls back to a
119
+ * `docker inspect ... .RepoDigests` parse ({@link parseRepoDigests}). Throws if
120
+ * no digest can be recovered — a deploy must never proceed with an unverifiable
121
+ * artifact reference.
122
+ *
123
+ * NOTE: for a single-arch (linux/amd64, the platform standard) push the push
124
+ * summary digest IS the artifact digest Harbor serves. A multi-arch / manifest-
125
+ * list push could surface the LIST digest here, which may differ from the
126
+ * per-arch artifact digest the host resolves — out of scope for the single-arch
127
+ * deploy flow.
128
+ */
129
+ export declare function buildAndPush(opts: BuildAndPushOpts): string;
130
+ export type TarFrontendOpts = {
131
+ /** Directory whose contents become the SPA bundle. */
132
+ dir: string;
133
+ /** Output tarball path. */
134
+ out: string;
135
+ /** Test seam — defaults to `execFileSync`. */
136
+ runFn?: RunFn;
137
+ };
138
+ /**
139
+ * Tar a frontend `dir` into a plain `.tar` at `out` (the smart-host accepts a
140
+ * plain tar; it content-addresses + mounts it read-only). `-C <dir> .` tars the
141
+ * directory CONTENTS, not the directory itself, so the SPA's `index.html` lands
142
+ * at the bundle root where the edge sidecar serves `/srv/spa`.
143
+ *
144
+ * Returns `out`.
145
+ */
146
+ export declare function tarFrontend(opts: TarFrontendOpts): string;
147
+ //# sourceMappingURL=baas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baas.d.ts","sourceRoot":"","sources":["../../src/_lib/baas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,260 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_BUILD_PLATFORM = exports.DEFAULT_DEPLOY_TIMEOUT_MS = void 0;
4
+ exports.connectAndAuth = connectAndAuth;
5
+ exports.imageTarget = imageTarget;
6
+ exports.buildAndPush = buildAndPush;
7
+ exports.tarFrontend = tarFrontend;
8
+ /**
9
+ * The ONE place the CLI constructs + authenticates a {@link BaasClient}, plus
10
+ * the injectable docker/tar shell-out seams the deploy commands use.
11
+ *
12
+ * ## Single client construction
13
+ *
14
+ * Every deploy-family command (`deploy`, `redeploy`, `update`, `suspend`,
15
+ * `resume`, `delete`, `status`, `list`) routes through {@link connectAndAuth}.
16
+ * It does exactly one `new BaasClient({ hostUrl, appId, allowInsecure,
17
+ * pathPrefix: '/host', timeout })` and authenticates with the env XRPL signer.
18
+ *
19
+ * We deliberately do NOT use the SDK's `BaasClient.connectToCluster(...)`
20
+ * discovery factory here: it fetches `/api/v3/discovery/clusters` and random-
21
+ * picks a cluster, whose per-cluster gateway hostnames are not public DNS and
22
+ * so are unreachable from a developer machine. The public round-robin
23
+ * `gateway.testnet.hsuite.network` (DEFAULT_GATEWAY) is the correct, reachable
24
+ * entrypoint. The discovery factory stays in the SDK for in-cluster consumers;
25
+ * the CLI just doesn't use it. (Matches the working showcase scratch
26
+ * `deploy-v9.cjs`.)
27
+ *
28
+ * The `clientFactory` parameter is the unit-test seam (mirrors faucet.ts's
29
+ * `xrplClientFactory`): specs inject a fake so no real `new BaasClient` /
30
+ * network call happens.
31
+ *
32
+ * ## Docker / tar seams
33
+ *
34
+ * {@link buildAndPush} and {@link tarFrontend} shell out via `execFileSync`
35
+ * with the argv passed as a discrete array — NEVER a shell string. This is
36
+ * load-bearing for the Harbor robot login: robot usernames are
37
+ * `robot$<project>+<name>`, and a shell-interpolated `-u "robot$project+name"`
38
+ * would expand `$project` to empty → a corrupted username → 401. `execFileSync`
39
+ * runs no shell, so `$` is literal. The push password is fed on stdin
40
+ * (`--password-stdin`), never on argv. Both accept an injectable `runFn`
41
+ * (default `execFileSync`) so unit tests never invoke docker for real.
42
+ *
43
+ * {@link buildAndPush} additionally CAPTURES the `docker push` stdout (rather
44
+ * than inheriting it) so it can recover the pushed image's `sha256:<64hex>`
45
+ * registry manifest digest — via {@link parsePushDigest}, falling back to a
46
+ * `docker inspect ... .RepoDigests` parse ({@link parseRepoDigests}). That
47
+ * digest is the value the build attestation's `imageDigest` must carry: the
48
+ * host binds it to the digest Harbor serves for the tag with STRICT equality,
49
+ * so a tag-form ref would be rejected once `requireSignature` is enforced.
50
+ */
51
+ const child_process_1 = require("child_process");
52
+ const smart_engines_sdk_1 = require("@hsuite/smart-engines-sdk");
53
+ const env_1 = require("./env");
54
+ const docker_1 = require("./docker");
55
+ /** Default per-app deploy timeout — `init` runs the smart-app entity DKG ceremony. */
56
+ exports.DEFAULT_DEPLOY_TIMEOUT_MS = 240_000;
57
+ /**
58
+ * Target build platform for the backend image. The cluster nodes are amd64, so
59
+ * a single-arch `linux/amd64` image is the standard — never a multi-arch OCI
60
+ * index. See {@link buildAndPush} for why this is load-bearing (an arm64 build
61
+ * host with the buildkit/containerd snapshotter otherwise emits an arm64-only
62
+ * provenance-attested OCI index the amd64 nodes can't pull/run).
63
+ */
64
+ exports.DEFAULT_BUILD_PLATFORM = 'linux/amd64';
65
+ /**
66
+ * Construct the ONE {@link BaasClient} and authenticate it with the env XRPL
67
+ * signer. Returns the authenticated client. Throws on a missing signer or an
68
+ * auth failure (the command-level action renders + exits).
69
+ */
70
+ async function connectAndAuth(opts) {
71
+ const signer = (0, env_1.buildSignerFromEnv)(opts.env);
72
+ const config = {
73
+ hostUrl: opts.gateway,
74
+ appId: opts.appId ?? 'pending',
75
+ allowInsecure: opts.gateway.startsWith('http://'),
76
+ pathPrefix: '/host',
77
+ timeout: opts.timeout ?? exports.DEFAULT_DEPLOY_TIMEOUT_MS,
78
+ };
79
+ const client = (opts.clientFactory ?? ((c) => new smart_engines_sdk_1.BaasClient(c)))(config);
80
+ await client.authenticate({
81
+ chain: signer.chain,
82
+ walletAddress: signer.walletAddress,
83
+ publicKey: signer.publicKey,
84
+ signFn: signer.signFn,
85
+ });
86
+ return client;
87
+ }
88
+ /**
89
+ * The fully-qualified target image reference: `<server>/<repository>:<tag>`.
90
+ */
91
+ function imageTarget(registry, tag) {
92
+ return `${registry.server}/${registry.repository}:${tag}`;
93
+ }
94
+ /**
95
+ * Build the backend image, tag it for the per-app Harbor repo, log in with the
96
+ * init-issued robot creds, push (with retries), and RECORD the pushed image's
97
+ * `sha256:<64hex>` registry manifest digest.
98
+ *
99
+ * Mirrors the working `deploy-v9.cjs` docker leg exactly, plus the single-arch
100
+ * pin (below):
101
+ * - optional `<build>` (shell command) in `context`
102
+ * - `docker build --platform linux/amd64 --provenance=false --sbom=false
103
+ * -t hsuite-local/<name>:<tag> -f <dockerfile> <context>`
104
+ * - `docker tag <local> <server>/<repo>:<tag>`
105
+ * - `docker login <server> -u <username> --password-stdin` ← username a
106
+ * DISCRETE argv element; password on stdin
107
+ * - `docker push <target>` retried up to `pushAttempts` times, stdout CAPTURED
108
+ *
109
+ * Returns the pushed image's `sha256:<64hex>` manifest digest — NOT the tag-form
110
+ * ref. The build attestation's `imageDigest` must carry this digest: the host
111
+ * binds it to the digest Harbor serves for the tag with strict equality, so a
112
+ * tag-form ref is rejected once `requireSignature` is enforced. The digest is
113
+ * read from the `docker push` summary ({@link parsePushDigest}); if the summary
114
+ * lacked one (older docker / buildx drivers / `--skip-push`), it falls back to a
115
+ * `docker inspect ... .RepoDigests` parse ({@link parseRepoDigests}). Throws if
116
+ * no digest can be recovered — a deploy must never proceed with an unverifiable
117
+ * artifact reference.
118
+ *
119
+ * NOTE: for a single-arch (linux/amd64, the platform standard) push the push
120
+ * summary digest IS the artifact digest Harbor serves. A multi-arch / manifest-
121
+ * list push could surface the LIST digest here, which may differ from the
122
+ * per-arch artifact digest the host resolves — out of scope for the single-arch
123
+ * deploy flow.
124
+ */
125
+ function buildAndPush(opts) {
126
+ const run = opts.runFn ?? child_process_1.execFileSync;
127
+ const dockerEnv = {
128
+ ...process.env,
129
+ ...(opts.dockerHost ? { DOCKER_HOST: opts.dockerHost } : {}),
130
+ };
131
+ // Login feeds the password on stdin → stdin must be a pipe; stderr inherits.
132
+ const loginStdio = ['pipe', 'inherit', 'inherit'];
133
+ // Push CAPTURES stdout so we can parse the `digest: sha256:...` summary; build
134
+ // output still inherits (we only need the push summary, not build logs).
135
+ const captureStdio = ['ignore', 'pipe', 'inherit'];
136
+ // Optional pre-build (the manifest's `backend.build`). Shell command — run via
137
+ // the shell since it's a user-authored build string, not an argv. No secrets.
138
+ // CRITICAL: run it IN `context` (the smart-app dir). Setting `PWD` alone does
139
+ // NOT change the child's working directory — `sh -c` inherits the parent's
140
+ // real cwd, so a relative build like `tsc` would compile whatever repo the CLI
141
+ // happens to be invoked from (e.g. smart-engines) instead of the smart-app.
142
+ // `cwd` is the actual chdir; we keep `PWD` in sync so shells report it right.
143
+ if (opts.build && !opts.skipBuild) {
144
+ run('sh', ['-c', opts.build], {
145
+ stdio: 'inherit',
146
+ cwd: opts.context,
147
+ env: { ...dockerEnv, PWD: opts.context },
148
+ });
149
+ }
150
+ const localTag = `hsuite-local/${opts.name}:${opts.tag}`;
151
+ if (!opts.skipBuild) {
152
+ // Run the build IN `context` too: a relative `dockerfile` and any relative
153
+ // paths inside it resolve against the child's cwd, not the CLI's cwd.
154
+ //
155
+ // SINGLE-ARCH amd64 (load-bearing): the cluster nodes are amd64. Without
156
+ // `--platform` a buildkit/containerd-snapshotter build host (Colima / Apple
157
+ // Silicon) builds for the HOST arch (arm64). `--provenance=false
158
+ // --sbom=false` suppress the buildkit attestation manifests that otherwise
159
+ // turn the push into a multi-manifest OCI image INDEX (arm64 child +
160
+ // `unknown/unknown` attestation, NO linux/amd64 child) — the pod then can't
161
+ // pull/run on amd64 nodes. With these flags buildkit emits a single
162
+ // `linux/amd64` image manifest whose push digest is a normal
163
+ // `sha256:<64hex>` equal to what Harbor serves. The flags are buildx/
164
+ // buildkit-specific; the classic (non-buildkit) builder ignores them and
165
+ // never emits an index anyway, so the invocation is robust on both.
166
+ const platform = opts.platform ?? exports.DEFAULT_BUILD_PLATFORM;
167
+ run('docker', [
168
+ 'build',
169
+ '--platform',
170
+ platform,
171
+ '--provenance=false',
172
+ '--sbom=false',
173
+ '-t',
174
+ localTag,
175
+ '-f',
176
+ opts.dockerfile,
177
+ opts.context,
178
+ ], {
179
+ stdio: 'inherit',
180
+ cwd: opts.context,
181
+ env: dockerEnv,
182
+ });
183
+ }
184
+ const target = imageTarget(opts.registry, opts.tag);
185
+ run('docker', ['tag', localTag, target], { stdio: 'inherit', env: dockerEnv });
186
+ if (opts.skipPush) {
187
+ // Nothing was pushed this run, but the image is asserted present at the
188
+ // registry — recover its digest from `RepoDigests` so the attestation is
189
+ // still bound to the real artifact.
190
+ return inspectDigestOrThrow(run, target, dockerEnv, opts.registry, opts.tag);
191
+ }
192
+ // CRITICAL: username is a discrete argv element (no shell, no `$` expansion);
193
+ // password via stdin. See the module header.
194
+ run('docker', ['login', opts.registry.server, '-u', opts.registry.username, '--password-stdin'], { input: opts.registry.password, stdio: loginStdio, env: dockerEnv });
195
+ const attempts = opts.pushAttempts ?? 6;
196
+ let lastErr;
197
+ for (let i = 1; i <= attempts; i++) {
198
+ try {
199
+ // Capture stdout (encoding 'utf8' → a string) so `parsePushDigest` can
200
+ // read the `… : digest: sha256:<64hex> size: …` summary line.
201
+ const pushOut = run('docker', ['push', target], {
202
+ stdio: captureStdio,
203
+ encoding: 'utf8',
204
+ env: dockerEnv,
205
+ });
206
+ const fromPush = (0, docker_1.parsePushDigest)(asStdout(pushOut));
207
+ if (fromPush)
208
+ return fromPush;
209
+ // Push succeeded but the summary carried no digest (older docker / buildx
210
+ // drivers). Recover it from `RepoDigests`.
211
+ return inspectDigestOrThrow(run, target, dockerEnv, opts.registry, opts.tag);
212
+ }
213
+ catch (err) {
214
+ lastErr = err;
215
+ // Harbor round-robin robot-auth occasionally 401s the first hit; retry.
216
+ }
217
+ }
218
+ throw new Error(`docker push failed after ${attempts} attempts: ${lastErr?.message ?? 'unknown'}`);
219
+ }
220
+ /** Coerce a `runFn` stdout return (string under `encoding:'utf8'`, else Buffer) to a string. */
221
+ function asStdout(out) {
222
+ if (typeof out === 'string')
223
+ return out;
224
+ if (out && typeof out.toString === 'function')
225
+ return out.toString('utf8');
226
+ return '';
227
+ }
228
+ /**
229
+ * `docker inspect --format '{{json .RepoDigests}}' <target>` via the shared
230
+ * `runFn` seam, returning the `sha256:<64hex>` digest for `<server>/<repo>` (the
231
+ * inspect-fallback path of {@link buildAndPush}). Throws if no matching digest
232
+ * is present — a deploy must never proceed with an unverifiable artifact ref.
233
+ */
234
+ function inspectDigestOrThrow(run, target, env, registry, tag) {
235
+ const inspectOut = asStdout(run('docker', ['inspect', '--format', '{{json .RepoDigests}}', target], {
236
+ stdio: ['ignore', 'pipe', 'ignore'],
237
+ encoding: 'utf8',
238
+ env,
239
+ }));
240
+ const digest = (0, docker_1.parseRepoDigests)(inspectOut, registry);
241
+ if (digest)
242
+ return digest;
243
+ throw new Error(`pushed ${registry.server}/${registry.repository}:${tag} but could not determine its ` +
244
+ 'registry manifest digest (no `digest: sha256:...` in push output and no matching ' +
245
+ 'RepoDigests from `docker inspect`).');
246
+ }
247
+ /**
248
+ * Tar a frontend `dir` into a plain `.tar` at `out` (the smart-host accepts a
249
+ * plain tar; it content-addresses + mounts it read-only). `-C <dir> .` tars the
250
+ * directory CONTENTS, not the directory itself, so the SPA's `index.html` lands
251
+ * at the bundle root where the edge sidecar serves `/srv/spa`.
252
+ *
253
+ * Returns `out`.
254
+ */
255
+ function tarFrontend(opts) {
256
+ const run = opts.runFn ?? child_process_1.execFileSync;
257
+ run('tar', ['-cf', opts.out, '-C', opts.dir, '.'], { stdio: 'inherit' });
258
+ return opts.out;
259
+ }
260
+ //# sourceMappingURL=baas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baas.js","sourceRoot":"","sources":["../../src/_lib/baas.ts"],"names":[],"mappings":"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"}
@@ -2,13 +2,13 @@
2
2
  * Cluster bootstrap constants.
3
3
  *
4
4
  * The CLI bootstraps against the public round-robin host
5
- * `gateway.testnet.hsuite.network` — 3 DNS A-records over the 3 genesis
6
- * cluster ingress LBs (HANDOFF arc-v13-do-deploy §11).
5
+ * `gateway.testnet.hsuite.network` — DNS A-records over the genesis cluster
6
+ * ingress LBs.
7
7
  *
8
- * Decentralized cluster discovery itself is no longer implemented here:
9
- * the canonical `BaasClient.connectToCluster({ bootstrap: [...] })` factory
10
- * in `@hsuite/smart-engines-sdk` (3.4.0+) owns it, and the CLI consumes
11
- * that factory rather than maintaining a parallel discovery path.
8
+ * Decentralized cluster discovery is owned by the canonical
9
+ * `BaasClient.connectToCluster({ bootstrap: [...] })` factory in
10
+ * `@hsuite/smart-engines-sdk`; the CLI consumes that factory rather than
11
+ * maintaining a parallel discovery path.
12
12
  */
13
13
  /** Public SDK-bootstrap host for the Smart Engines testnet. */
14
14
  export declare const DEFAULT_GATEWAY = "https://gateway.testnet.hsuite.network";
@@ -3,13 +3,13 @@
3
3
  * Cluster bootstrap constants.
4
4
  *
5
5
  * The CLI bootstraps against the public round-robin host
6
- * `gateway.testnet.hsuite.network` — 3 DNS A-records over the 3 genesis
7
- * cluster ingress LBs (HANDOFF arc-v13-do-deploy §11).
6
+ * `gateway.testnet.hsuite.network` — DNS A-records over the genesis cluster
7
+ * ingress LBs.
8
8
  *
9
- * Decentralized cluster discovery itself is no longer implemented here:
10
- * the canonical `BaasClient.connectToCluster({ bootstrap: [...] })` factory
11
- * in `@hsuite/smart-engines-sdk` (3.4.0+) owns it, and the CLI consumes
12
- * that factory rather than maintaining a parallel discovery path.
9
+ * Decentralized cluster discovery is owned by the canonical
10
+ * `BaasClient.connectToCluster({ bootstrap: [...] })` factory in
11
+ * `@hsuite/smart-engines-sdk`; the CLI consumes that factory rather than
12
+ * maintaining a parallel discovery path.
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.DEFAULT_GATEWAY = void 0;
@@ -0,0 +1,69 @@
1
+ type BaasService = 'auth' | 'database' | 'storage' | 'functions' | 'messaging';
2
+ /** Backend build + push + deploy inputs. REQUIRED — every smart-app has one. */
3
+ export type ManifestBackend = {
4
+ /** Backend listen port inside the customer container (1..65535, never 8080). */
5
+ port: number;
6
+ /** Image tag (the part after the colon in the Harbor ref). */
7
+ tag: string;
8
+ /** Pod replica count (per cluster). Default 1. */
9
+ replicas?: number;
10
+ /** Docker build context directory. Default '.'. */
11
+ context?: string;
12
+ /** Dockerfile path (relative to `context`). Default 'Dockerfile'. */
13
+ dockerfile?: string;
14
+ /**
15
+ * Target build platform passed to `docker build --platform`. Default
16
+ * `linux/amd64` (the cluster-node arch). Override only when targeting a
17
+ * different node arch — the default is correct for every node today.
18
+ */
19
+ platform?: string;
20
+ /** Optional pre-build command run in `context` before `docker build`. */
21
+ build?: string;
22
+ /** Customer-provided env (mirrored to a k8s Secret at reconcile time). */
23
+ env?: Record<string, string>;
24
+ /** Resource caps, clamped against the tenant ResourceQuota at deploy time. */
25
+ limits?: {
26
+ cpu?: string;
27
+ memory?: string;
28
+ };
29
+ };
30
+ /**
31
+ * Frontend tar + upload inputs. OPTIONAL — present iff the smart-app ships a
32
+ * static SPA for its NestJS backend to serve out of `public/`. Relative `dir` /
33
+ * `bundlePath` resolve against the backend's build `context` (the smart-app
34
+ * root), NOT the CLI's process.cwd().
35
+ */
36
+ export type ManifestFrontend = {
37
+ /** Optional pre-build command run before tarring `dir` (e.g. `ng build`). */
38
+ build?: string;
39
+ /** Directory to tar into the SPA bundle (e.g. `www` / `dist` / `public`). */
40
+ dir?: string;
41
+ /** Pre-built tarball path; takes precedence over `dir` when set. */
42
+ bundlePath?: string | null;
43
+ };
44
+ /**
45
+ * Deploy manifest schema — ONE canonical shape.
46
+ *
47
+ * Required: `name`, `services[]`, `backend` (with `port` + `tag`).
48
+ * `frontend` is optional (present iff the app ships a SPA bundle).
49
+ */
50
+ export type Manifest = {
51
+ name: string;
52
+ services: BaasService[];
53
+ /** Number of clusters to deploy across (>=3 default); distinct from replicas. */
54
+ degree?: number;
55
+ backend: ManifestBackend;
56
+ frontend?: ManifestFrontend;
57
+ };
58
+ /**
59
+ * Parse + validate a deploy manifest from a JSON file.
60
+ *
61
+ * @throws if the file is missing or fails schema validation. The error message
62
+ * names the offending field so a malformed manifest fails loudly here rather
63
+ * than as an opaque server 400/500 mid-deploy.
64
+ */
65
+ export declare function parseManifest(path: string): Manifest;
66
+ /** Validate an already-parsed manifest object. Shared by file + programmatic callers. */
67
+ export declare function validateManifest(raw: unknown): Manifest;
68
+ export {};
69
+ //# sourceMappingURL=deploy-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy-manifest.d.ts","sourceRoot":"","sources":["../../src/_lib/deploy-manifest.ts"],"names":[],"mappings":"AAmBA,KAAK,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,CAAC;AAK/E,gFAAgF;AAChF,MAAM,MAAM,eAAe,GAAG;IAC5B,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,8EAA8E;IAC9E,MAAM,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAYpD;AAED,yFAAyF;AACzF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CA4CvD"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseManifest = parseManifest;
4
+ exports.validateManifest = validateManifest;
5
+ /**
6
+ * Shared smart-app deploy manifest schema + loader.
7
+ *
8
+ * The manifest is the single declarative input to `hsuite deploy` /
9
+ * `hsuite redeploy`. There is ONE canonical shape: every smart-app has a NestJS
10
+ * `backend` container image, and MAY additionally ship a static SPA that the
11
+ * backend serves out of its own `public/` (so the SPA rides along inside the
12
+ * backend image / bundle — there is no SPA-only runtime on the platform).
13
+ *
14
+ * - `backend` (REQUIRED) → docker build → push the backend image.
15
+ * - `frontend` (OPTIONAL) → if present, tar + `uploadFrontend` the bundle.
16
+ * - then `deploy(...)` → reconcile to k8s.
17
+ *
18
+ * `name`, `services[]` and `backend` (with `port` + `tag`) are required;
19
+ * everything else is optional with documented defaults.
20
+ */
21
+ const fs_1 = require("fs");
22
+ const path_1 = require("path");
23
+ /** Lowest decentralization degree the host accepts (genesis cluster floor). */
24
+ const MIN_DEGREE = 3;
25
+ /**
26
+ * Parse + validate a deploy manifest from a JSON file.
27
+ *
28
+ * @throws if the file is missing or fails schema validation. The error message
29
+ * names the offending field so a malformed manifest fails loudly here rather
30
+ * than as an opaque server 400/500 mid-deploy.
31
+ */
32
+ function parseManifest(path) {
33
+ const manifestPath = (0, path_1.resolve)(path);
34
+ if (!(0, fs_1.existsSync)(manifestPath)) {
35
+ throw new Error(`manifest not found: ${manifestPath}`);
36
+ }
37
+ let raw;
38
+ try {
39
+ raw = JSON.parse((0, fs_1.readFileSync)(manifestPath, 'utf8'));
40
+ }
41
+ catch (err) {
42
+ throw new Error(`manifest is not valid JSON: ${err.message}`);
43
+ }
44
+ return validateManifest(raw);
45
+ }
46
+ /** Validate an already-parsed manifest object. Shared by file + programmatic callers. */
47
+ function validateManifest(raw) {
48
+ if (typeof raw !== 'object' || raw === null) {
49
+ throw new Error('manifest must be a JSON object');
50
+ }
51
+ const m = raw;
52
+ if (typeof m.name !== 'string' || !m.name) {
53
+ throw new Error('manifest.name is required (string)');
54
+ }
55
+ if (!Array.isArray(m.services)) {
56
+ throw new Error('manifest.services[] is required (array)');
57
+ }
58
+ if (m.degree !== undefined) {
59
+ if (typeof m.degree !== 'number' || !Number.isInteger(m.degree)) {
60
+ throw new Error('manifest.degree must be an integer when present');
61
+ }
62
+ // Mirror the host DTO floor (DeployAppDto: z.number().int().min(3)) so a
63
+ // too-low degree fails here with a clear CLI message instead of a Zod 500.
64
+ if (m.degree < MIN_DEGREE) {
65
+ throw new Error(`manifest.degree must be >= ${MIN_DEGREE} (genesis cluster floor)`);
66
+ }
67
+ }
68
+ const backend = m.backend;
69
+ const frontend = m.frontend;
70
+ if (!backend || typeof backend !== 'object') {
71
+ throw new Error('manifest.backend is required (object with port + tag)');
72
+ }
73
+ if (typeof backend.port !== 'number') {
74
+ throw new Error('manifest.backend.port is required (number)');
75
+ }
76
+ if (backend.port === 8080) {
77
+ throw new Error('manifest.backend.port 8080 is reserved for the edge sidecar');
78
+ }
79
+ if (typeof backend.tag !== 'string' || !backend.tag) {
80
+ throw new Error('manifest.backend.tag is required (string)');
81
+ }
82
+ if (frontend && !frontend.dir && !frontend.bundlePath) {
83
+ throw new Error('manifest.frontend requires `dir` or `bundlePath`');
84
+ }
85
+ return raw;
86
+ }
87
+ //# sourceMappingURL=deploy-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy-manifest.js","sourceRoot":"","sources":["../../src/_lib/deploy-manifest.ts"],"names":[],"mappings":"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"}