@hsuite/smart-engines-cli 1.2.0 → 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.
- 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 +114 -0
- package/dist/_lib/registry-fanout.d.ts.map +1 -0
- package/dist/_lib/registry-fanout.js +435 -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 +263 -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 +310 -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 +450 -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
|
@@ -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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"}
|
package/dist/_lib/cluster.d.ts
CHANGED
|
@@ -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` —
|
|
6
|
-
*
|
|
5
|
+
* `gateway.testnet.hsuite.network` — DNS A-records over the genesis cluster
|
|
6
|
+
* ingress LBs.
|
|
7
7
|
*
|
|
8
|
-
* Decentralized cluster discovery
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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";
|
package/dist/_lib/cluster.js
CHANGED
|
@@ -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` —
|
|
7
|
-
*
|
|
6
|
+
* `gateway.testnet.hsuite.network` — DNS A-records over the genesis cluster
|
|
7
|
+
* ingress LBs.
|
|
8
8
|
*
|
|
9
|
-
* Decentralized cluster discovery
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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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"}
|