@mondaydotcomorg/z2h-cli 0.1.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 +16 -0
- package/bin/z2h-cli.js +2 -0
- package/dist/commands/build.d.ts +5 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +37 -0
- package/dist/commands/clean.d.ts +5 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +24 -0
- package/dist/commands/deploy.d.ts +6 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +92 -0
- package/dist/commands/dev.d.ts +5 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +58 -0
- package/dist/constants.d.ts +25 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +67 -0
- package/dist/esm/commands/build.d.ts +5 -0
- package/dist/esm/commands/build.d.ts.map +1 -0
- package/dist/esm/commands/build.mjs +35 -0
- package/dist/esm/commands/clean.d.ts +5 -0
- package/dist/esm/commands/clean.d.ts.map +1 -0
- package/dist/esm/commands/clean.mjs +22 -0
- package/dist/esm/commands/deploy.d.ts +6 -0
- package/dist/esm/commands/deploy.d.ts.map +1 -0
- package/dist/esm/commands/deploy.mjs +86 -0
- package/dist/esm/commands/dev.d.ts +5 -0
- package/dist/esm/commands/dev.d.ts.map +1 -0
- package/dist/esm/commands/dev.mjs +56 -0
- package/dist/esm/constants.d.ts +25 -0
- package/dist/esm/constants.d.ts.map +1 -0
- package/dist/esm/constants.mjs +57 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.mjs +86 -0
- package/dist/esm/shadow/consumer-pkg.d.ts +24 -0
- package/dist/esm/shadow/consumer-pkg.d.ts.map +1 -0
- package/dist/esm/shadow/consumer-pkg.mjs +81 -0
- package/dist/esm/shadow/gitignore.d.ts +7 -0
- package/dist/esm/shadow/gitignore.d.ts.map +1 -0
- package/dist/esm/shadow/gitignore.mjs +29 -0
- package/dist/esm/shadow/merge-package-json.d.ts +16 -0
- package/dist/esm/shadow/merge-package-json.d.ts.map +1 -0
- package/dist/esm/shadow/merge-package-json.mjs +58 -0
- package/dist/esm/shadow/metadata.d.ts +4 -0
- package/dist/esm/shadow/metadata.d.ts.map +1 -0
- package/dist/esm/shadow/metadata.mjs +18 -0
- package/dist/esm/shadow/paths.d.ts +3 -0
- package/dist/esm/shadow/paths.d.ts.map +1 -0
- package/dist/esm/shadow/paths.mjs +25 -0
- package/dist/esm/shadow/port.d.ts +7 -0
- package/dist/esm/shadow/port.d.ts.map +1 -0
- package/dist/esm/shadow/port.mjs +34 -0
- package/dist/esm/shadow/prepare.d.ts +3 -0
- package/dist/esm/shadow/prepare.d.ts.map +1 -0
- package/dist/esm/shadow/prepare.mjs +60 -0
- package/dist/esm/shadow/scaffold.d.ts +7 -0
- package/dist/esm/shadow/scaffold.d.ts.map +1 -0
- package/dist/esm/shadow/scaffold.mjs +112 -0
- package/dist/esm/shadow/sync.d.ts +9 -0
- package/dist/esm/shadow/sync.d.ts.map +1 -0
- package/dist/esm/shadow/sync.mjs +29 -0
- package/dist/esm/shadow/yarnrc.d.ts +10 -0
- package/dist/esm/shadow/yarnrc.d.ts.map +1 -0
- package/dist/esm/shadow/yarnrc.mjs +27 -0
- package/dist/esm/types.d.ts +53 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.mjs +1 -0
- package/dist/esm/util/app-name.d.ts +12 -0
- package/dist/esm/util/app-name.d.ts.map +1 -0
- package/dist/esm/util/app-name.mjs +17 -0
- package/dist/esm/util/logger.d.ts +22 -0
- package/dist/esm/util/logger.d.ts.map +1 -0
- package/dist/esm/util/logger.mjs +59 -0
- package/dist/esm/util/manifest.d.ts +31 -0
- package/dist/esm/util/manifest.d.ts.map +1 -0
- package/dist/esm/util/manifest.mjs +31 -0
- package/dist/esm/util/s3/client.d.ts +11 -0
- package/dist/esm/util/s3/client.d.ts.map +1 -0
- package/dist/esm/util/s3/client.mjs +38 -0
- package/dist/esm/util/s3/upload.d.ts +2 -0
- package/dist/esm/util/s3/upload.d.ts.map +1 -0
- package/dist/esm/util/s3/upload.mjs +32 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +86 -0
- package/dist/shadow/consumer-pkg.d.ts +24 -0
- package/dist/shadow/consumer-pkg.d.ts.map +1 -0
- package/dist/shadow/consumer-pkg.js +84 -0
- package/dist/shadow/gitignore.d.ts +7 -0
- package/dist/shadow/gitignore.d.ts.map +1 -0
- package/dist/shadow/gitignore.js +35 -0
- package/dist/shadow/merge-package-json.d.ts +16 -0
- package/dist/shadow/merge-package-json.d.ts.map +1 -0
- package/dist/shadow/merge-package-json.js +66 -0
- package/dist/shadow/metadata.d.ts +4 -0
- package/dist/shadow/metadata.d.ts.map +1 -0
- package/dist/shadow/metadata.js +21 -0
- package/dist/shadow/paths.d.ts +3 -0
- package/dist/shadow/paths.d.ts.map +1 -0
- package/dist/shadow/paths.js +31 -0
- package/dist/shadow/port.d.ts +7 -0
- package/dist/shadow/port.d.ts.map +1 -0
- package/dist/shadow/port.js +41 -0
- package/dist/shadow/prepare.d.ts +3 -0
- package/dist/shadow/prepare.d.ts.map +1 -0
- package/dist/shadow/prepare.js +62 -0
- package/dist/shadow/scaffold.d.ts +7 -0
- package/dist/shadow/scaffold.d.ts.map +1 -0
- package/dist/shadow/scaffold.js +118 -0
- package/dist/shadow/sync.d.ts +9 -0
- package/dist/shadow/sync.d.ts.map +1 -0
- package/dist/shadow/sync.js +31 -0
- package/dist/shadow/yarnrc.d.ts +10 -0
- package/dist/shadow/yarnrc.d.ts.map +1 -0
- package/dist/shadow/yarnrc.js +33 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/util/app-name.d.ts +12 -0
- package/dist/util/app-name.d.ts.map +1 -0
- package/dist/util/app-name.js +20 -0
- package/dist/util/logger.d.ts +22 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +71 -0
- package/dist/util/manifest.d.ts +31 -0
- package/dist/util/manifest.d.ts.map +1 -0
- package/dist/util/manifest.js +36 -0
- package/dist/util/s3/client.d.ts +11 -0
- package/dist/util/s3/client.d.ts.map +1 -0
- package/dist/util/s3/client.js +48 -0
- package/dist/util/s3/upload.d.ts +2 -0
- package/dist/util/s3/upload.d.ts.map +1 -0
- package/dist/util/s3/upload.js +39 -0
- package/package.json +56 -0
- package/src/commands/build.ts +42 -0
- package/src/commands/clean.ts +26 -0
- package/src/commands/deploy.ts +114 -0
- package/src/commands/dev.ts +64 -0
- package/src/constants.ts +63 -0
- package/src/index.ts +90 -0
- package/src/shadow/consumer-pkg.ts +100 -0
- package/src/shadow/gitignore.ts +30 -0
- package/src/shadow/merge-package-json.ts +62 -0
- package/src/shadow/metadata.ts +17 -0
- package/src/shadow/paths.ts +24 -0
- package/src/shadow/port.ts +34 -0
- package/src/shadow/prepare.ts +68 -0
- package/src/shadow/scaffold.ts +120 -0
- package/src/shadow/sync.ts +30 -0
- package/src/shadow/yarnrc.ts +29 -0
- package/src/types.ts +60 -0
- package/src/util/app-name.ts +16 -0
- package/src/util/logger.ts +64 -0
- package/src/util/manifest.ts +65 -0
- package/src/util/s3/client.ts +40 -0
- package/src/util/s3/upload.ts +41 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fsExtra = require('fs-extra');
|
|
5
|
+
const constants = require('../constants.js');
|
|
6
|
+
|
|
7
|
+
const _interopDefault = e => e && e.__esModule ? e : { default: e };
|
|
8
|
+
|
|
9
|
+
const path__default = /*#__PURE__*/_interopDefault(path);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Ensure the consumer has a `.yarnrc.yml` that pins `nodeLinker: node-modules`.
|
|
13
|
+
*
|
|
14
|
+
* Yarn 4 defaults to PnP, which trident-toolkit's webpack pipeline doesn't
|
|
15
|
+
* support cleanly (webpack expects a flat node_modules). We force the
|
|
16
|
+
* classic linker so installs produce a real `node_modules/`. Idempotent —
|
|
17
|
+
* leaves any other settings the user added alone.
|
|
18
|
+
*/
|
|
19
|
+
async function ensureYarnRc(consumerDir) {
|
|
20
|
+
const yarnrcPath = path__default.default.join(consumerDir, '.yarnrc.yml');
|
|
21
|
+
if (!(await fsExtra.pathExists(yarnrcPath))) {
|
|
22
|
+
await fsExtra.writeFile(yarnrcPath, constants.YARNRC_LINES.join('\n\n') + '\n');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const body = await fsExtra.readFile(yarnrcPath, 'utf8');
|
|
26
|
+
if (/^\s*nodeLinker\s*:/m.test(body)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const prefix = body.length && !body.endsWith('\n') ? '\n' : '';
|
|
30
|
+
await fsExtra.writeFile(yarnrcPath, body + prefix + 'nodeLinker: node-modules\n');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
exports.ensureYarnRc = ensureYarnRc;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared domain types for the Z2H CLI. Command-scoped option types live
|
|
3
|
+
* with their command; narrow single-use types stay local to their file.
|
|
4
|
+
*/
|
|
5
|
+
export interface ConsumerPkg {
|
|
6
|
+
name: string;
|
|
7
|
+
version?: string;
|
|
8
|
+
private?: boolean;
|
|
9
|
+
workspaces?: string[] | {
|
|
10
|
+
packages?: string[];
|
|
11
|
+
};
|
|
12
|
+
dependencies?: Record<string, string>;
|
|
13
|
+
devDependencies?: Record<string, string>;
|
|
14
|
+
peerDependencies?: Record<string, string>;
|
|
15
|
+
scripts?: Record<string, string>;
|
|
16
|
+
[k: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
export interface ShadowPkg {
|
|
19
|
+
name: string;
|
|
20
|
+
version: string;
|
|
21
|
+
private: true;
|
|
22
|
+
scripts: Record<string, string>;
|
|
23
|
+
peerDependencies: Record<string, string>;
|
|
24
|
+
devDependencies: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
export interface ShadowMetadata {
|
|
27
|
+
createdAt: string;
|
|
28
|
+
appName: string;
|
|
29
|
+
port: number;
|
|
30
|
+
}
|
|
31
|
+
export interface ConsumerPaths {
|
|
32
|
+
consumerDir: string;
|
|
33
|
+
consumerPkg: string;
|
|
34
|
+
consumerSrc: string;
|
|
35
|
+
consumerSrcEntry: string;
|
|
36
|
+
shadowDir: string;
|
|
37
|
+
shadowPkg: string;
|
|
38
|
+
shadowSrc: string;
|
|
39
|
+
shadowWrapper: string;
|
|
40
|
+
shadowTridentrc: string;
|
|
41
|
+
shadowNvmrc: string;
|
|
42
|
+
shadowDts: string;
|
|
43
|
+
shadowTsconfig: string;
|
|
44
|
+
shadowBuild: string;
|
|
45
|
+
shadowDepsHash: string;
|
|
46
|
+
shadowMetadata: string;
|
|
47
|
+
}
|
|
48
|
+
export interface PreparedShadow {
|
|
49
|
+
appName: string;
|
|
50
|
+
port: number;
|
|
51
|
+
paths: ConsumerPaths;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAGD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAGD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAGD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,aAAa,CAAC;CACtB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip any npm scope (`@scope/`) from a package name.
|
|
3
|
+
* e.g. `@trident/customer-viewer` → `customer-viewer`, `foo` → `foo`.
|
|
4
|
+
*/
|
|
5
|
+
export declare function cleanAppName(name: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Canonical MF bundle name: the de-scoped app name with an `mf-` prefix.
|
|
8
|
+
* This matches the trident convention (shadow pkg is `@trident/mf-<app>`,
|
|
9
|
+
* emitted bundle is `MF-mf-<app>`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function mfAppName(name: string): string;
|
|
12
|
+
//# sourceMappingURL=app-name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-name.d.ts","sourceRoot":"","sources":["../../src/util/app-name.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Strip any npm scope (`@scope/`) from a package name.
|
|
5
|
+
* e.g. `@trident/customer-viewer` → `customer-viewer`, `foo` → `foo`.
|
|
6
|
+
*/
|
|
7
|
+
function cleanAppName(name) {
|
|
8
|
+
return name.replace(/^@[^/]+\//, '');
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Canonical MF bundle name: the de-scoped app name with an `mf-` prefix.
|
|
12
|
+
* This matches the trident convention (shadow pkg is `@trident/mf-<app>`,
|
|
13
|
+
* emitted bundle is `MF-mf-<app>`).
|
|
14
|
+
*/
|
|
15
|
+
function mfAppName(name) {
|
|
16
|
+
return `mf-${cleanAppName(name)}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
exports.cleanAppName = cleanAppName;
|
|
20
|
+
exports.mfAppName = mfAppName;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type OutputMode = 'human' | 'json';
|
|
2
|
+
export declare function setOutputMode(next: OutputMode): void;
|
|
3
|
+
export declare function getOutputMode(): OutputMode;
|
|
4
|
+
/**
|
|
5
|
+
* Progress, info, and warnings go to stderr so stdout stays clean
|
|
6
|
+
* for machine-readable output. Always suppressed in JSON mode except
|
|
7
|
+
* when the consumer explicitly wants chatty progress (e.g. setup).
|
|
8
|
+
*/
|
|
9
|
+
export declare function info(msg: string): void;
|
|
10
|
+
export declare function warn(msg: string): void;
|
|
11
|
+
export declare function errorLog(msg: string): void;
|
|
12
|
+
/**
|
|
13
|
+
* Data output. In human mode writes `human` to stdout; in JSON mode writes
|
|
14
|
+
* JSON-stringified `data` to stdout. Exactly one line of stdout per call.
|
|
15
|
+
*/
|
|
16
|
+
export declare function output(human: string, data: unknown): void;
|
|
17
|
+
/**
|
|
18
|
+
* Emit a structured failure payload (JSON mode) or a red error line (human mode),
|
|
19
|
+
* then exit with the given code.
|
|
20
|
+
*/
|
|
21
|
+
export declare function fail(message: string, payload: Record<string, unknown>, exitCode?: number): never;
|
|
22
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/util/logger.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;AAI1C,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAEpD;AAED,wBAAgB,aAAa,IAAI,UAAU,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAItC;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAItC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAI1C;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAMzD;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,SAAI,GAAG,KAAK,CAU3F"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const pc = require('picocolors');
|
|
4
|
+
|
|
5
|
+
const _interopDefault = e => e && e.__esModule ? e : { default: e };
|
|
6
|
+
|
|
7
|
+
const pc__default = /*#__PURE__*/_interopDefault(pc);
|
|
8
|
+
|
|
9
|
+
let mode = 'human';
|
|
10
|
+
function setOutputMode(next) {
|
|
11
|
+
mode = next;
|
|
12
|
+
}
|
|
13
|
+
function getOutputMode() {
|
|
14
|
+
return mode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Progress, info, and warnings go to stderr so stdout stays clean
|
|
18
|
+
* for machine-readable output. Always suppressed in JSON mode except
|
|
19
|
+
* when the consumer explicitly wants chatty progress (e.g. setup).
|
|
20
|
+
*/
|
|
21
|
+
function info(msg) {
|
|
22
|
+
if (mode === 'human') {
|
|
23
|
+
process.stderr.write(pc__default.default.cyan(`[z2h-cli] ${msg}\n`));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function warn(msg) {
|
|
27
|
+
if (mode === 'human') {
|
|
28
|
+
process.stderr.write(pc__default.default.yellow(`[z2h-cli] ${msg}\n`));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function errorLog(msg) {
|
|
32
|
+
if (mode === 'human') {
|
|
33
|
+
process.stderr.write(pc__default.default.red(`[z2h-cli] ${msg}\n`));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Data output. In human mode writes `human` to stdout; in JSON mode writes
|
|
38
|
+
* JSON-stringified `data` to stdout. Exactly one line of stdout per call.
|
|
39
|
+
*/
|
|
40
|
+
function output(human, data) {
|
|
41
|
+
if (mode === 'json') {
|
|
42
|
+
process.stdout.write(`${JSON.stringify(data)}\n`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
process.stdout.write(`${human}\n`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Emit a structured failure payload (JSON mode) or a red error line (human mode),
|
|
50
|
+
* then exit with the given code.
|
|
51
|
+
*/
|
|
52
|
+
function fail(message, payload, exitCode = 1) {
|
|
53
|
+
if (mode === 'json') {
|
|
54
|
+
process.stdout.write(`${JSON.stringify({ ok: false, error: message, ...payload })}\n`);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
process.stderr.write(pc__default.default.red(`[z2h-cli] ${message}\n`));
|
|
58
|
+
if (typeof payload.suggestedCommand === 'string') {
|
|
59
|
+
process.stderr.write(pc__default.default.dim(` → ${payload.suggestedCommand}\n`));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
process.exit(exitCode);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
exports.errorLog = errorLog;
|
|
66
|
+
exports.fail = fail;
|
|
67
|
+
exports.getOutputMode = getOutputMode;
|
|
68
|
+
exports.info = info;
|
|
69
|
+
exports.output = output;
|
|
70
|
+
exports.setOutputMode = setOutputMode;
|
|
71
|
+
exports.warn = warn;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface SharedDep {
|
|
2
|
+
name?: string;
|
|
3
|
+
globalName: string;
|
|
4
|
+
url?: string;
|
|
5
|
+
minVersion?: string;
|
|
6
|
+
dependencies: Record<string, number>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Shape of the `asset-manifest.json` trident-toolkit emits alongside the
|
|
10
|
+
* bundle. We consume this file directly as the base for a Z2H registry
|
|
11
|
+
* entry — deploy.ts only overlays `version` and `url`.
|
|
12
|
+
*/
|
|
13
|
+
export interface AssetManifestFile {
|
|
14
|
+
sameAsHost: boolean;
|
|
15
|
+
skipTranslationFetch: boolean;
|
|
16
|
+
shared: SharedDep[];
|
|
17
|
+
entrypoints: string[];
|
|
18
|
+
nonExternalsEntrypoints?: string[];
|
|
19
|
+
scriptType?: 'module' | 'classic';
|
|
20
|
+
mfs?: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface ManifestEntry extends AssetManifestFile {
|
|
23
|
+
version: number;
|
|
24
|
+
url: string;
|
|
25
|
+
}
|
|
26
|
+
export type Manifest = Record<string, ManifestEntry>;
|
|
27
|
+
export declare function readManifest(): Promise<Manifest>;
|
|
28
|
+
export declare function nextVersion(manifest: Manifest, app: string): number;
|
|
29
|
+
export declare function upsertEntry(manifest: Manifest, app: string, entry: ManifestEntry): Manifest;
|
|
30
|
+
export declare function writeManifest(manifest: Manifest): Promise<void>;
|
|
31
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/util/manifest.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,UAAU,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAClC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAErD,wBAAsB,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,CAQtD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,UAI1D;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,QAAQ,CAE3F;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAWrE"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const clientS3 = require('@aws-sdk/client-s3');
|
|
4
|
+
const util_s3_client = require('./s3/client.js');
|
|
5
|
+
|
|
6
|
+
async function readManifest() {
|
|
7
|
+
// Read via the public CDN endpoint, no AWS auth required.
|
|
8
|
+
const res = await fetch(util_s3_client.MANIFEST_READ_URL);
|
|
9
|
+
if (!res.ok) {
|
|
10
|
+
throw new Error(`failed to read manifest from ${util_s3_client.MANIFEST_READ_URL}: HTTP ${res.status}`);
|
|
11
|
+
}
|
|
12
|
+
return (await res.json());
|
|
13
|
+
}
|
|
14
|
+
function nextVersion(manifest, app) {
|
|
15
|
+
const current = manifest[app]?.version;
|
|
16
|
+
const n = current ? Number(current) : 0;
|
|
17
|
+
return (Number.isNaN(n) ? 0 : n) + 1;
|
|
18
|
+
}
|
|
19
|
+
function upsertEntry(manifest, app, entry) {
|
|
20
|
+
return { ...manifest, [app]: entry };
|
|
21
|
+
}
|
|
22
|
+
async function writeManifest(manifest) {
|
|
23
|
+
const s3 = util_s3_client.getS3Client();
|
|
24
|
+
await s3.send(new clientS3.PutObjectCommand({
|
|
25
|
+
Bucket: util_s3_client.BUCKET_WRITE_NAME,
|
|
26
|
+
Key: util_s3_client.MANIFEST_KEY,
|
|
27
|
+
Body: JSON.stringify(manifest, null, 2),
|
|
28
|
+
ContentType: 'application/json',
|
|
29
|
+
CacheControl: 'no-cache',
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
exports.nextVersion = nextVersion;
|
|
34
|
+
exports.readManifest = readManifest;
|
|
35
|
+
exports.upsertEntry = upsertEntry;
|
|
36
|
+
exports.writeManifest = writeManifest;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
export declare const BUCKET_WRITE_NAME = "prod-use1-bigbrain-zth-mf-assets";
|
|
3
|
+
export declare const REGION = "us-east-1";
|
|
4
|
+
export declare const BUCKET_WRITE_URL = "https://prod-use1-bigbrain-zth-mf-assets.s3.us-east-1.amazonaws.com";
|
|
5
|
+
export declare const BUCKET_READ_DNS_NAME = "bigbrain-zth-mf-assets";
|
|
6
|
+
export declare const BUCKET_READ_DNS_URL = "https://bigbrain-zth-mf-assets.bigbrain.me";
|
|
7
|
+
export declare const MANIFEST_KEY = "mf-assets";
|
|
8
|
+
export declare const MANIFEST_READ_URL = "https://bigbrain-zth-mf-assets.bigbrain.me/mf-assets";
|
|
9
|
+
export declare function getS3Client(): S3Client;
|
|
10
|
+
export declare function assertBucketExists(): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/util/s3/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAsB,MAAM,oBAAoB,CAAC;AAErF,eAAO,MAAM,iBAAiB,qCAAqC,CAAC;AACpE,eAAO,MAAM,MAAM,cAAc,CAAC;AAClC,eAAO,MAAM,gBAAgB,wEAA4D,CAAC;AAE1F,eAAO,MAAM,oBAAoB,2BAA2B,CAAC;AAC7D,eAAO,MAAM,mBAAmB,+CAAgD,CAAC;AAKjF,eAAO,MAAM,YAAY,cAAc,CAAC;AACxC,eAAO,MAAM,iBAAiB,yDAA2C,CAAC;AAI1E,wBAAgB,WAAW,IAAI,QAAQ,CAKtC;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAexD"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const clientS3 = require('@aws-sdk/client-s3');
|
|
4
|
+
|
|
5
|
+
const BUCKET_WRITE_NAME = 'prod-use1-bigbrain-zth-mf-assets';
|
|
6
|
+
const REGION = 'us-east-1';
|
|
7
|
+
const BUCKET_WRITE_URL = `https://${BUCKET_WRITE_NAME}.s3.${REGION}.amazonaws.com`;
|
|
8
|
+
const BUCKET_READ_DNS_NAME = 'bigbrain-zth-mf-assets';
|
|
9
|
+
const BUCKET_READ_DNS_URL = `https://${BUCKET_READ_DNS_NAME}.bigbrain.me`;
|
|
10
|
+
// No `.json` extension — TridentSkeleton's `mfUrl` API appends `/mf-assets`
|
|
11
|
+
// to the bucket base when fetching, so the manifest must live at this exact
|
|
12
|
+
// key. See microfrontends/mf-bigbrain-zth/.../ZeroToHeroHost.tsx.
|
|
13
|
+
const MANIFEST_KEY = 'mf-assets';
|
|
14
|
+
const MANIFEST_READ_URL = `${BUCKET_READ_DNS_URL}/${MANIFEST_KEY}`;
|
|
15
|
+
let client = null;
|
|
16
|
+
function getS3Client() {
|
|
17
|
+
if (!client) {
|
|
18
|
+
client = new clientS3.S3Client({ region: REGION });
|
|
19
|
+
}
|
|
20
|
+
return client;
|
|
21
|
+
}
|
|
22
|
+
async function assertBucketExists() {
|
|
23
|
+
try {
|
|
24
|
+
await getS3Client().send(new clientS3.HeadBucketCommand({ Bucket: BUCKET_WRITE_NAME }));
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
if (err instanceof clientS3.S3ServiceException) {
|
|
28
|
+
const status = err.$metadata.httpStatusCode;
|
|
29
|
+
if (status === 404 || err.name === 'NotFound' || err.name === 'NoSuchBucket') {
|
|
30
|
+
throw new Error(`S3 bucket "${BUCKET_WRITE_NAME}" does not exist (region: ${REGION}).`);
|
|
31
|
+
}
|
|
32
|
+
if (status === 403) {
|
|
33
|
+
throw new Error(`No access to S3 bucket "${BUCKET_WRITE_NAME}" (region: ${REGION}). Check AWS credentials.`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.BUCKET_READ_DNS_NAME = BUCKET_READ_DNS_NAME;
|
|
41
|
+
exports.BUCKET_READ_DNS_URL = BUCKET_READ_DNS_URL;
|
|
42
|
+
exports.BUCKET_WRITE_NAME = BUCKET_WRITE_NAME;
|
|
43
|
+
exports.BUCKET_WRITE_URL = BUCKET_WRITE_URL;
|
|
44
|
+
exports.MANIFEST_KEY = MANIFEST_KEY;
|
|
45
|
+
exports.MANIFEST_READ_URL = MANIFEST_READ_URL;
|
|
46
|
+
exports.REGION = REGION;
|
|
47
|
+
exports.assertBucketExists = assertBucketExists;
|
|
48
|
+
exports.getS3Client = getS3Client;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../src/util/s3/upload.ts"],"names":[],"mappings":"AAcA,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BtF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fsExtra = require('fs-extra');
|
|
5
|
+
const promises = require('node:fs/promises');
|
|
6
|
+
const mimeTypes = require('mime-types');
|
|
7
|
+
const pMap = require('p-map');
|
|
8
|
+
const clientS3 = require('@aws-sdk/client-s3');
|
|
9
|
+
const util_s3_client = require('./client.js');
|
|
10
|
+
|
|
11
|
+
const _interopDefault = e => e && e.__esModule ? e : { default: e };
|
|
12
|
+
|
|
13
|
+
const path__default = /*#__PURE__*/_interopDefault(path);
|
|
14
|
+
const pMap__default = /*#__PURE__*/_interopDefault(pMap);
|
|
15
|
+
|
|
16
|
+
// Each deploy uploads to a version-prefixed path (<app>/<version>/...), so
|
|
17
|
+
// the URL itself is the cache key. Assets never need to be revalidated.
|
|
18
|
+
const FOREVER = 'public, immutable';
|
|
19
|
+
const UPLOAD_CONCURRENCY = 5;
|
|
20
|
+
async function uploadDir(localDir, keyPrefix) {
|
|
21
|
+
const entries = await promises.readdir(localDir, { recursive: true, withFileTypes: true });
|
|
22
|
+
const files = entries.filter(e => e.isFile()).map(e => path__default.default.relative(localDir, path__default.default.join(e.parentPath, e.name)));
|
|
23
|
+
const s3 = util_s3_client.getS3Client();
|
|
24
|
+
await pMap__default.default(files, async (rel) => {
|
|
25
|
+
const body = await fsExtra.readFile(path__default.default.join(localDir, rel));
|
|
26
|
+
const contentType = mimeTypes.lookup(rel) || 'application/octet-stream';
|
|
27
|
+
const key = `${keyPrefix}/${rel.split(path__default.default.sep).join('/')}`;
|
|
28
|
+
await s3.send(new clientS3.PutObjectCommand({
|
|
29
|
+
Bucket: util_s3_client.BUCKET_WRITE_NAME,
|
|
30
|
+
Key: key,
|
|
31
|
+
Body: body,
|
|
32
|
+
ContentType: contentType,
|
|
33
|
+
CacheControl: FOREVER,
|
|
34
|
+
}));
|
|
35
|
+
}, { concurrency: UPLOAD_CONCURRENCY });
|
|
36
|
+
return files.map(f => f.split(path__default.default.sep).join('/'));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
exports.uploadDir = uploadDir;
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mondaydotcomorg/z2h-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"bin": "./bin/z2h-cli.js",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/esm/index.mjs",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"nx": {
|
|
16
|
+
"name": "z2h-cli",
|
|
17
|
+
"tags": [
|
|
18
|
+
"type:package",
|
|
19
|
+
"package"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"test": "echo noop",
|
|
24
|
+
"lint": "trident-library lint",
|
|
25
|
+
"build": "trident-library build",
|
|
26
|
+
"watch": "trident-library build -w"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin/",
|
|
30
|
+
"dist/",
|
|
31
|
+
"src/"
|
|
32
|
+
],
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@aws-sdk/client-s3": "^3.706.0",
|
|
35
|
+
"chokidar": "^3.6.0",
|
|
36
|
+
"commander": "^12.1.0",
|
|
37
|
+
"execa": "^9.5.1",
|
|
38
|
+
"fs-extra": "^11.2.0",
|
|
39
|
+
"mime-types": "^2.1.35",
|
|
40
|
+
"p-map": "^7.0.2",
|
|
41
|
+
"picocolors": "^1.1.1",
|
|
42
|
+
"tsx": "^4.19.2"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@mondaydotcomorg/trident-library": "^1.2.7",
|
|
46
|
+
"@types/fs-extra": "^11.0.4",
|
|
47
|
+
"@types/mime-types": "^2.1.4",
|
|
48
|
+
"@types/node": "^22.19.0",
|
|
49
|
+
"typescript": "^5.7.2"
|
|
50
|
+
},
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "https://github.com/DaPulse/bigbrain-z2h.git",
|
|
54
|
+
"directory": "packages/z2h-cli"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { pathExists } from 'fs-extra';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import { info, output, setOutputMode } from '../util/logger';
|
|
4
|
+
import { prepareShadow } from '../shadow/prepare';
|
|
5
|
+
|
|
6
|
+
export interface BuildOptions {
|
|
7
|
+
json?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function buildCommand(opts: BuildOptions): Promise<void> {
|
|
11
|
+
if (opts.json) {
|
|
12
|
+
setOutputMode('json');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const ctx = await prepareShadow();
|
|
16
|
+
|
|
17
|
+
// Typecheck against the shadow's tsconfig (the consumer dir has none).
|
|
18
|
+
// Errors fail the build before we waste time on the Trident pipeline.
|
|
19
|
+
// preferLocal=true makes execa prepend the consumer's node_modules/.bin
|
|
20
|
+
// to PATH, so `tsc` resolves to the version hoisted from .zth's
|
|
21
|
+
// trident-toolkit dep — no npx overhead, no extra template deps.
|
|
22
|
+
info(`type-checking "${ctx.appName}"`);
|
|
23
|
+
await execa('tsc', ['--noEmit', '-p', ctx.paths.shadowTsconfig], {
|
|
24
|
+
cwd: ctx.paths.consumerDir,
|
|
25
|
+
preferLocal: true,
|
|
26
|
+
stdio: 'inherit',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
info(`building "${ctx.appName}" via trident`);
|
|
30
|
+
await execa('yarn', ['build'], { cwd: ctx.paths.shadowDir, stdio: 'inherit' });
|
|
31
|
+
|
|
32
|
+
if (!(await pathExists(ctx.paths.shadowBuild))) {
|
|
33
|
+
throw new Error(`Expected build output at ${ctx.paths.shadowBuild} — not found.`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
output(`[z2h-cli] build complete — artifacts at ${ctx.paths.shadowBuild}`, {
|
|
37
|
+
ok: true,
|
|
38
|
+
appName: ctx.appName,
|
|
39
|
+
port: ctx.port,
|
|
40
|
+
buildDir: ctx.paths.shadowBuild,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { pathExists, remove } from 'fs-extra';
|
|
2
|
+
import { info, output, setOutputMode } from '../util/logger';
|
|
3
|
+
import { resolveConsumerPaths } from '../shadow/paths';
|
|
4
|
+
|
|
5
|
+
export interface CleanOptions {
|
|
6
|
+
json?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function cleanCommand(opts: CleanOptions): Promise<void> {
|
|
10
|
+
if (opts.json) {
|
|
11
|
+
setOutputMode('json');
|
|
12
|
+
}
|
|
13
|
+
const paths = resolveConsumerPaths(process.cwd());
|
|
14
|
+
|
|
15
|
+
const existed = await pathExists(paths.shadowDir);
|
|
16
|
+
if (existed) {
|
|
17
|
+
info(`removing ${paths.shadowDir}`);
|
|
18
|
+
await remove(paths.shadowDir);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
output(existed ? `[z2h-cli] cleaned shadow at ${paths.shadowDir}` : '[z2h-cli] nothing to clean', {
|
|
22
|
+
ok: true,
|
|
23
|
+
shadowDir: paths.shadowDir,
|
|
24
|
+
removed: existed,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { pathExists, readJson } from 'fs-extra';
|
|
3
|
+
import { execa } from 'execa';
|
|
4
|
+
import { info, warn, output, setOutputMode } from '../util/logger';
|
|
5
|
+
import { resolveConsumerPaths } from '../shadow/paths';
|
|
6
|
+
import {
|
|
7
|
+
nextVersion,
|
|
8
|
+
readManifest,
|
|
9
|
+
upsertEntry,
|
|
10
|
+
writeManifest,
|
|
11
|
+
type AssetManifestFile,
|
|
12
|
+
type ManifestEntry,
|
|
13
|
+
} from '../util/manifest';
|
|
14
|
+
import { uploadDir } from '../util/s3/upload';
|
|
15
|
+
import { assertBucketExists, BUCKET_WRITE_NAME, BUCKET_READ_DNS_URL } from '../util/s3/client';
|
|
16
|
+
import { cleanAppName, mfAppName } from '../util/app-name';
|
|
17
|
+
import { buildCommand } from './build';
|
|
18
|
+
|
|
19
|
+
const APONO_BUNDLE = '<APONO_BUNDLE_NAME>'; // TODO: replace with actual bundle name once infra setup is complete
|
|
20
|
+
|
|
21
|
+
export interface DeployOptions {
|
|
22
|
+
dryRun?: boolean;
|
|
23
|
+
json?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function requestAponoAccess(): Promise<void> {
|
|
27
|
+
if (APONO_BUNDLE === '<APONO_BUNDLE_NAME>') {
|
|
28
|
+
warn(
|
|
29
|
+
`skipping Apono request — APONO_BUNDLE is still a placeholder ("${APONO_BUNDLE}"). Set it in deploy.ts before relying on auto-grant.`
|
|
30
|
+
);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
info(`requesting Apono access for bundle "${APONO_BUNDLE}"`);
|
|
34
|
+
await execa('apono', ['bundles', 'grant', APONO_BUNDLE], { stdio: 'inherit' });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function deployCommand(opts: DeployOptions): Promise<void> {
|
|
38
|
+
if (opts.json) {
|
|
39
|
+
setOutputMode('json');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
info('checking S3 bucket');
|
|
43
|
+
await assertBucketExists();
|
|
44
|
+
|
|
45
|
+
info('building');
|
|
46
|
+
await buildCommand({ json: opts.json });
|
|
47
|
+
|
|
48
|
+
const paths = resolveConsumerPaths(process.cwd());
|
|
49
|
+
const consumerPkg = (await readJson(paths.consumerPkg)) as { name?: string };
|
|
50
|
+
if (!consumerPkg.name) {
|
|
51
|
+
throw new Error('Consumer package.json must have a "name" field');
|
|
52
|
+
}
|
|
53
|
+
const appName = mfAppName(consumerPkg.name);
|
|
54
|
+
|
|
55
|
+
if (!(await pathExists(paths.shadowBuild))) {
|
|
56
|
+
throw new Error(`No build output at ${paths.shadowBuild} after build step.`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Trident emits the canonical per-MF manifest at build/asset-manifest.json.
|
|
60
|
+
const assetManifestPath = path.join(paths.shadowBuild, 'asset-manifest.json');
|
|
61
|
+
if (!(await pathExists(assetManifestPath))) {
|
|
62
|
+
throw new Error(`Missing asset-manifest.json at ${assetManifestPath}.`);
|
|
63
|
+
}
|
|
64
|
+
const assetManifest = (await readJson(assetManifestPath)) as AssetManifestFile;
|
|
65
|
+
|
|
66
|
+
info('reading current Z2H manifest');
|
|
67
|
+
const manifest = await readManifest();
|
|
68
|
+
const version = nextVersion(manifest, appName);
|
|
69
|
+
const keyPrefix = `${appName}/${version}`;
|
|
70
|
+
const url = `${BUCKET_READ_DNS_URL}/${keyPrefix}`;
|
|
71
|
+
|
|
72
|
+
if (opts.dryRun) {
|
|
73
|
+
output(`[z2h-cli] dry-run: would upload to s3://${BUCKET_WRITE_NAME}/${keyPrefix}/ as v${version}`, {
|
|
74
|
+
ok: true,
|
|
75
|
+
dryRun: true,
|
|
76
|
+
appName,
|
|
77
|
+
version,
|
|
78
|
+
bucket: BUCKET_WRITE_NAME,
|
|
79
|
+
keyPrefix,
|
|
80
|
+
url,
|
|
81
|
+
entry: { ...assetManifest, version, url },
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
await requestAponoAccess();
|
|
87
|
+
|
|
88
|
+
info(`uploading build → s3://${BUCKET_WRITE_NAME}/${keyPrefix}/`);
|
|
89
|
+
await uploadDir(paths.shadowBuild, keyPrefix);
|
|
90
|
+
|
|
91
|
+
const entry: ManifestEntry = {
|
|
92
|
+
...assetManifest,
|
|
93
|
+
version,
|
|
94
|
+
url,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
info(`updating manifest entry "${appName}" → v${version}`);
|
|
98
|
+
await writeManifest(upsertEntry(manifest, appName, entry));
|
|
99
|
+
|
|
100
|
+
// The host MF parses the app name from the URL and prepends `mf-` itself
|
|
101
|
+
// before looking it up in the manifest. So the user-facing URL must use
|
|
102
|
+
// the consumer's de-scoped package name (no `mf-` prefix, no `@scope/`).
|
|
103
|
+
const liveUrl = `https://bigbrain.me/bigbrain-vibe/${cleanAppName(consumerPkg.name)}`;
|
|
104
|
+
output(`[z2h-cli] deployed ✅\n app: ${appName}\n version: ${version}\n open: ${liveUrl}`, {
|
|
105
|
+
ok: true,
|
|
106
|
+
appName,
|
|
107
|
+
version,
|
|
108
|
+
bucket: BUCKET_WRITE_NAME,
|
|
109
|
+
keyPrefix,
|
|
110
|
+
url,
|
|
111
|
+
liveUrl,
|
|
112
|
+
entry,
|
|
113
|
+
});
|
|
114
|
+
}
|