@mondaydotcomorg/z2h-cli 0.1.1 → 0.3.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 (122) hide show
  1. package/dist/commands/build.d.ts +1 -0
  2. package/dist/commands/build.d.ts.map +1 -1
  3. package/dist/commands/build.js +5 -1
  4. package/dist/commands/create-workspace.d.ts.map +1 -1
  5. package/dist/commands/create-workspace.js +1 -0
  6. package/dist/commands/create.d.ts.map +1 -1
  7. package/dist/commands/create.js +16 -2
  8. package/dist/commands/deploy.d.ts.map +1 -1
  9. package/dist/commands/deploy.js +27 -28
  10. package/dist/commands/dev.d.ts.map +1 -1
  11. package/dist/commands/dev.js +29 -0
  12. package/dist/commands/generate-z2h-token.d.ts +16 -0
  13. package/dist/commands/generate-z2h-token.d.ts.map +1 -0
  14. package/dist/commands/generate-z2h-token.js +107 -0
  15. package/dist/constants.d.ts +8 -0
  16. package/dist/constants.d.ts.map +1 -1
  17. package/dist/constants.js +28 -0
  18. package/dist/esm/commands/build.d.ts +1 -0
  19. package/dist/esm/commands/build.d.ts.map +1 -1
  20. package/dist/esm/commands/build.mjs +5 -1
  21. package/dist/esm/commands/create-workspace.d.ts.map +1 -1
  22. package/dist/esm/commands/create-workspace.mjs +1 -0
  23. package/dist/esm/commands/create.d.ts.map +1 -1
  24. package/dist/esm/commands/create.mjs +16 -2
  25. package/dist/esm/commands/deploy.d.ts.map +1 -1
  26. package/dist/esm/commands/deploy.mjs +24 -26
  27. package/dist/esm/commands/dev.d.ts.map +1 -1
  28. package/dist/esm/commands/dev.mjs +25 -1
  29. package/dist/esm/commands/generate-z2h-token.d.ts +16 -0
  30. package/dist/esm/commands/generate-z2h-token.d.ts.map +1 -0
  31. package/dist/esm/commands/generate-z2h-token.mjs +99 -0
  32. package/dist/esm/constants.d.ts +8 -0
  33. package/dist/esm/constants.d.ts.map +1 -1
  34. package/dist/esm/constants.mjs +21 -1
  35. package/dist/esm/index.mjs +15 -0
  36. package/dist/esm/shadow/scaffold.d.ts.map +1 -1
  37. package/dist/esm/shadow/scaffold.mjs +5 -0
  38. package/dist/esm/templates/app/claude-settings.mjs +15 -2
  39. package/dist/esm/util/auth/__tests__/auth-store.test.d.ts +2 -0
  40. package/dist/esm/util/auth/__tests__/auth-store.test.d.ts.map +1 -0
  41. package/dist/esm/util/auth/__tests__/broker-credential-provider.test.d.ts +2 -0
  42. package/dist/esm/util/auth/__tests__/broker-credential-provider.test.d.ts.map +1 -0
  43. package/dist/esm/util/auth/__tests__/loopback-server.test.d.ts +2 -0
  44. package/dist/esm/util/auth/__tests__/loopback-server.test.d.ts.map +1 -0
  45. package/dist/esm/util/auth/__tests__/write-auth.test.d.ts +2 -0
  46. package/dist/esm/util/auth/__tests__/write-auth.test.d.ts.map +1 -0
  47. package/dist/esm/util/auth/auth-store.d.ts +11 -0
  48. package/dist/esm/util/auth/auth-store.d.ts.map +1 -0
  49. package/dist/esm/util/auth/auth-store.mjs +29 -0
  50. package/dist/esm/util/auth/broker-credential-provider.d.ts +12 -0
  51. package/dist/esm/util/auth/broker-credential-provider.d.ts.map +1 -0
  52. package/dist/esm/util/auth/broker-credential-provider.mjs +76 -0
  53. package/dist/esm/util/auth/loopback-server.d.ts +12 -0
  54. package/dist/esm/util/auth/loopback-server.d.ts.map +1 -0
  55. package/dist/esm/util/auth/loopback-server.mjs +87 -0
  56. package/dist/esm/util/auth/write-auth.d.ts +11 -0
  57. package/dist/esm/util/auth/write-auth.d.ts.map +1 -0
  58. package/dist/esm/util/auth/write-auth.mjs +22 -0
  59. package/dist/esm/util/manifest.d.ts +1 -0
  60. package/dist/esm/util/manifest.d.ts.map +1 -1
  61. package/dist/esm/util/manifest.mjs +2 -1
  62. package/dist/esm/util/s3/client.d.ts +7 -8
  63. package/dist/esm/util/s3/client.d.ts.map +1 -1
  64. package/dist/esm/util/s3/client.mjs +15 -30
  65. package/dist/esm/util/s3/upload.d.ts.map +1 -1
  66. package/dist/esm/util/s3/upload.mjs +2 -1
  67. package/dist/index.js +15 -0
  68. package/dist/shadow/scaffold.d.ts.map +1 -1
  69. package/dist/shadow/scaffold.js +5 -0
  70. package/dist/templates/app/claude-settings.js +15 -1
  71. package/dist/util/auth/__tests__/auth-store.test.d.ts +2 -0
  72. package/dist/util/auth/__tests__/auth-store.test.d.ts.map +1 -0
  73. package/dist/util/auth/__tests__/broker-credential-provider.test.d.ts +2 -0
  74. package/dist/util/auth/__tests__/broker-credential-provider.test.d.ts.map +1 -0
  75. package/dist/util/auth/__tests__/loopback-server.test.d.ts +2 -0
  76. package/dist/util/auth/__tests__/loopback-server.test.d.ts.map +1 -0
  77. package/dist/util/auth/__tests__/write-auth.test.d.ts +2 -0
  78. package/dist/util/auth/__tests__/write-auth.test.d.ts.map +1 -0
  79. package/dist/util/auth/auth-store.d.ts +11 -0
  80. package/dist/util/auth/auth-store.d.ts.map +1 -0
  81. package/dist/util/auth/auth-store.js +39 -0
  82. package/dist/util/auth/broker-credential-provider.d.ts +12 -0
  83. package/dist/util/auth/broker-credential-provider.d.ts.map +1 -0
  84. package/dist/util/auth/broker-credential-provider.js +80 -0
  85. package/dist/util/auth/loopback-server.d.ts +12 -0
  86. package/dist/util/auth/loopback-server.d.ts.map +1 -0
  87. package/dist/util/auth/loopback-server.js +94 -0
  88. package/dist/util/auth/write-auth.d.ts +11 -0
  89. package/dist/util/auth/write-auth.d.ts.map +1 -0
  90. package/dist/util/auth/write-auth.js +26 -0
  91. package/dist/util/manifest.d.ts +1 -0
  92. package/dist/util/manifest.d.ts.map +1 -1
  93. package/dist/util/manifest.js +5 -4
  94. package/dist/util/s3/client.d.ts +7 -8
  95. package/dist/util/s3/client.d.ts.map +1 -1
  96. package/dist/util/s3/client.js +14 -36
  97. package/dist/util/s3/upload.d.ts.map +1 -1
  98. package/dist/util/s3/upload.js +2 -1
  99. package/package.json +10 -1
  100. package/src/commands/__tests__/create.test.ts +3 -0
  101. package/src/commands/build.ts +6 -1
  102. package/src/commands/create-workspace.ts +1 -0
  103. package/src/commands/create.ts +19 -2
  104. package/src/commands/deploy.ts +27 -36
  105. package/src/commands/dev.ts +26 -1
  106. package/src/commands/generate-z2h-token.ts +124 -0
  107. package/src/constants.ts +25 -0
  108. package/src/index.ts +17 -0
  109. package/src/shadow/scaffold.ts +5 -0
  110. package/src/templates/app/claude-settings.json +12 -0
  111. package/src/templates/workspace/yarnlock +0 -0
  112. package/src/util/auth/__tests__/auth-store.test.ts +50 -0
  113. package/src/util/auth/__tests__/broker-credential-provider.test.ts +115 -0
  114. package/src/util/auth/__tests__/loopback-server.test.ts +85 -0
  115. package/src/util/auth/__tests__/write-auth.test.ts +79 -0
  116. package/src/util/auth/auth-store.ts +31 -0
  117. package/src/util/auth/broker-credential-provider.ts +93 -0
  118. package/src/util/auth/loopback-server.ts +103 -0
  119. package/src/util/auth/write-auth.ts +24 -0
  120. package/src/util/manifest.ts +3 -1
  121. package/src/util/s3/client.ts +15 -32
  122. package/src/util/s3/upload.ts +2 -1
@@ -1,5 +1,6 @@
1
1
  export interface BuildOptions {
2
2
  json?: boolean;
3
+ publicUrl?: string;
3
4
  }
4
5
  export declare function buildCommand(opts: BuildOptions): Promise<void>;
5
6
  //# sourceMappingURL=build.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCpE"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCpE"}
@@ -22,7 +22,11 @@ async function buildCommand(opts) {
22
22
  stdio: 'inherit',
23
23
  });
24
24
  util_logger.info(`building "${ctx.appName}" via trident`);
25
- await execa.execa('yarn', ['build'], { cwd: ctx.paths.shadowDir, stdio: 'inherit' });
25
+ await execa.execa('yarn', ['build'], {
26
+ cwd: ctx.paths.shadowDir,
27
+ stdio: 'inherit',
28
+ env: { ...process.env, ...(opts.publicUrl ? { PUBLIC_URL: opts.publicUrl } : {}) },
29
+ });
26
30
  if (!(await fsExtra.pathExists(ctx.paths.shadowBuild))) {
27
31
  throw new Error(`Expected build output at ${ctx.paths.shadowBuild} — not found.`);
28
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../src/commands/create-workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAiBD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDxF"}
1
+ {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../src/commands/create-workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAiBD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DxF"}
@@ -60,6 +60,7 @@ async function createWorkspaceCommand(opts) {
60
60
  fsExtra.writeFile(path__default.default.join(home, 'package.json'), util_templates.renderTemplate(pkgRaw, { __Z2H_CLI_VERSION__: cliVersion })),
61
61
  fsExtra.copy(path__default.default.join(wsTemplatesDir, 'gitignore'), path__default.default.join(home, '.gitignore')),
62
62
  fsExtra.copy(path__default.default.join(wsTemplatesDir, 'yarnrc.yml'), path__default.default.join(home, '.yarnrc.yml')),
63
+ fsExtra.copy(path__default.default.join(wsTemplatesDir, 'yarnlock'), path__default.default.join(home, 'yarn.lock')),
63
64
  fsExtra.copy(path__default.default.join(wsTemplatesDir, 'nvmrc'), path__default.default.join(home, '.nvmrc')),
64
65
  fsExtra.copy(path__default.default.join(wsTemplatesDir, 'npmrc'), path__default.default.join(home, '.npmrc')),
65
66
  fsExtra.copy(path__default.default.join(wsTemplatesDir, 'README.md'), path__default.default.join(home, 'README.md')),
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA0BD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EvF"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA6BD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAqFvF"}
@@ -7,12 +7,18 @@ const execa = require('execa');
7
7
  const util_logger = require('../util/logger.js');
8
8
  const util_workspace = require('../util/workspace.js');
9
9
  const util_templates = require('../util/templates.js');
10
+ const util_manifest = require('../util/manifest.js');
11
+ const util_appName = require('../util/app-name.js');
12
+ const constants = require('../constants.js');
10
13
 
11
14
  const _interopDefault = e => e && e.__esModule ? e : { default: e };
12
15
 
13
16
  const path__default = /*#__PURE__*/_interopDefault(path);
14
17
 
15
- const APP_NAME_RE = /^[a-z][a-z0-9-]{1,49}$/;
18
+ // Names reserved by the host MF (mf-bigbrain-zth) for platform pages under
19
+ // /bigbrain-vibe/<name>. Creating an app with one of these would shadow the
20
+ // platform page in the URL, so we refuse upfront.
21
+ const RESERVED_APP_NAMES = new Set(['generate-z2h-token']);
16
22
  /**
17
23
  * Convert kebab-case to PascalCase. `demo-app` → `DemoApp`.
18
24
  */
@@ -40,7 +46,10 @@ async function createCommand(appName, opts) {
40
46
  // Validate workspace.
41
47
  const workspace = await util_workspace.assertWorkspace();
42
48
  // Validate app name.
43
- if (!APP_NAME_RE.test(appName)) {
49
+ if (RESERVED_APP_NAMES.has(appName)) {
50
+ throw new Error(`App name "${appName}" is reserved by the Z2H host for a platform page under /bigbrain-vibe/${appName}. Pick a different name.`);
51
+ }
52
+ if (!constants.APP_NAME_PATTERN.test(appName)) {
44
53
  throw new Error(`App name "${appName}" is invalid. Use lowercase kebab-case (a-z, 0-9, -), ` +
45
54
  `2-50 chars, starting with a letter.`);
46
55
  }
@@ -58,6 +67,11 @@ async function createCommand(appName, opts) {
58
67
  if (!(await isDirEmpty(appDir))) {
59
68
  throw new Error(`${appDir} is non-empty. Pick a different name or wipe it first.`);
60
69
  }
70
+ // Check for manifest collision (network call — after all local checks).
71
+ const manifest = await util_manifest.readManifest();
72
+ if (manifest[util_appName.mfAppName(appName)]) {
73
+ throw new Error(`An app named "${appName}" already exists in the Z2H registry. Pick a different name.`);
74
+ }
61
75
  // Compute substitutions.
62
76
  const vars = {
63
77
  __APP_NAME__: appName,
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAaD,wBAAsB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA6EtE"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA+EtE"}
@@ -1,41 +1,44 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const path = require('node:path');
4
+ const os = require('node:os');
4
5
  const fsExtra = require('fs-extra');
5
- require('execa');
6
6
  const util_logger = require('../util/logger.js');
7
7
  const shadow_paths = require('../shadow/paths.js');
8
8
  const util_manifest = require('../util/manifest.js');
9
9
  const util_s3_upload = require('../util/s3/upload.js');
10
+ const constants = require('../constants.js');
10
11
  const util_s3_client = require('../util/s3/client.js');
12
+ const util_auth_authStore = require('../util/auth/auth-store.js');
11
13
  const util_appName = require('../util/app-name.js');
12
14
  const commands_build = require('./build.js');
13
15
 
14
16
  const _interopDefault = e => e && e.__esModule ? e : { default: e };
15
17
 
16
18
  const path__default = /*#__PURE__*/_interopDefault(path);
19
+ const os__default = /*#__PURE__*/_interopDefault(os);
17
20
 
18
- const APONO_BUNDLE = '<APONO_BUNDLE_NAME>'; // TODO: replace with actual bundle name once infra setup is complete
19
- async function requestAponoAccess() {
20
- {
21
- util_logger.warn(`skipping Apono request — APONO_BUNDLE is still a placeholder ("${APONO_BUNDLE}"). Set it in deploy.ts before relying on auto-grant.`);
22
- return;
23
- }
24
- }
25
21
  async function deployCommand(opts) {
26
22
  if (opts.json) {
27
23
  util_logger.setOutputMode('json');
28
24
  }
29
- util_logger.info('checking S3 bucket');
30
- await util_s3_client.assertBucketExists();
31
- util_logger.info('building');
32
- await commands_build.buildCommand({ json: opts.json });
33
25
  const paths = shadow_paths.resolveConsumerPaths(process.cwd());
34
26
  const consumerPkg = (await fsExtra.readJson(paths.consumerPkg));
35
27
  if (!consumerPkg.name) {
36
28
  throw new Error('Consumer package.json must have a "name" field');
37
29
  }
38
30
  const appName = util_appName.mfAppName(consumerPkg.name);
31
+ // Validate the user's deploy token is on disk before doing any expensive
32
+ // work. Throws Z2hAuthMissingError with a remediation hint if not.
33
+ await util_auth_authStore.readZthAuth();
34
+ util_s3_client.setupS3Client({ appName });
35
+ util_logger.info('reading current Z2H manifest');
36
+ const manifest = await util_manifest.readManifest();
37
+ const version = util_manifest.nextVersion(manifest, appName);
38
+ const keyPrefix = `${appName}/${version}`;
39
+ const url = `${constants.BUCKET_READ_DNS_URL}/${keyPrefix}`;
40
+ util_logger.info('building');
41
+ await commands_build.buildCommand({ json: opts.json, publicUrl: url });
39
42
  if (!(await fsExtra.pathExists(paths.shadowBuild))) {
40
43
  throw new Error(`No build output at ${paths.shadowBuild} after build step.`);
41
44
  }
@@ -45,32 +48,28 @@ async function deployCommand(opts) {
45
48
  throw new Error(`Missing asset-manifest.json at ${assetManifestPath}.`);
46
49
  }
47
50
  const assetManifest = (await fsExtra.readJson(assetManifestPath));
48
- util_logger.info('reading current Z2H manifest');
49
- const manifest = await util_manifest.readManifest();
50
- const version = util_manifest.nextVersion(manifest, appName);
51
- const keyPrefix = `${appName}/${version}`;
52
- const url = `${util_s3_client.BUCKET_READ_DNS_URL}/${keyPrefix}`;
51
+ const deployedBy = os__default.default.userInfo().username;
52
+ const entry = {
53
+ ...assetManifest,
54
+ version,
55
+ url,
56
+ deployedBy,
57
+ };
53
58
  if (opts.dryRun) {
54
- util_logger.output(`[z2h-cli] dry-run: would upload to s3://${util_s3_client.BUCKET_WRITE_NAME}/${keyPrefix}/ as v${version}`, {
59
+ util_logger.output(`[z2h-cli] dry-run: would upload to s3://${constants.BUCKET_WRITE_NAME}/${keyPrefix}/ as v${version}`, {
55
60
  ok: true,
56
61
  dryRun: true,
57
62
  appName,
58
63
  version,
59
- bucket: util_s3_client.BUCKET_WRITE_NAME,
64
+ bucket: constants.BUCKET_WRITE_NAME,
60
65
  keyPrefix,
61
66
  url,
62
- entry: { ...assetManifest, version, url },
67
+ entry,
63
68
  });
64
69
  return;
65
70
  }
66
- await requestAponoAccess();
67
- util_logger.info(`uploading build → s3://${util_s3_client.BUCKET_WRITE_NAME}/${keyPrefix}/`);
71
+ util_logger.info(`uploading build → s3://${constants.BUCKET_WRITE_NAME}/${keyPrefix}/`);
68
72
  await util_s3_upload.uploadDir(paths.shadowBuild, keyPrefix);
69
- const entry = {
70
- ...assetManifest,
71
- version,
72
- url,
73
- };
74
73
  util_logger.info(`updating manifest entry "${appName}" → v${version}`);
75
74
  await util_manifest.writeManifest(util_manifest.upsertEntry(manifest, appName, entry));
76
75
  // The host MF parses the app name from the URL and prepends `mf-` itself
@@ -81,7 +80,7 @@ async function deployCommand(opts) {
81
80
  ok: true,
82
81
  appName,
83
82
  version,
84
- bucket: util_s3_client.BUCKET_WRITE_NAME,
83
+ bucket: constants.BUCKET_WRITE_NAME,
85
84
  keyPrefix,
86
85
  url,
87
86
  liveUrl,
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAID,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgDhE"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAID,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAuEhE"}
@@ -1,5 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
+ const path = require('node:path');
4
+ const fs = require('node:fs');
3
5
  const fsExtra = require('fs-extra');
4
6
  const chokidar = require('chokidar');
5
7
  const execa = require('execa');
@@ -8,6 +10,11 @@ const shadow_prepare = require('../shadow/prepare.js');
8
10
  const shadow_consumerPkg = require('../shadow/consumer-pkg.js');
9
11
  const shadow_sync = require('../shadow/sync.js');
10
12
 
13
+ const _interopDefault = e => e && e.__esModule ? e : { default: e };
14
+
15
+ const path__default = /*#__PURE__*/_interopDefault(path);
16
+ const fs__default = /*#__PURE__*/_interopDefault(fs);
17
+
11
18
  const TRIDENT_READY_PATTERN = /Server started at/i;
12
19
  async function devCommand(opts) {
13
20
  if (opts.json) {
@@ -24,6 +31,28 @@ async function devCommand(opts) {
24
31
  cwd: ctx.paths.shadowDir,
25
32
  stdio: ['inherit', 'pipe', 'inherit'],
26
33
  });
34
+ const pidFile = path__default.default.join(ctx.paths.shadowDir, 'dev.pid');
35
+ if (server.pid) {
36
+ await fsExtra.writeFile(pidFile, String(server.pid));
37
+ }
38
+ const cleanupPid = () => {
39
+ try {
40
+ fs__default.default.unlinkSync(pidFile);
41
+ }
42
+ catch (_) {
43
+ // file already gone — ignore
44
+ }
45
+ };
46
+ server.on('exit', cleanupPid);
47
+ process.on('exit', cleanupPid);
48
+ process.on('SIGINT', () => {
49
+ server.kill();
50
+ process.exit(0);
51
+ });
52
+ process.on('SIGTERM', () => {
53
+ server.kill();
54
+ process.exit(0);
55
+ });
27
56
  let readyPrinted = false;
28
57
  server.stdout?.on('data', (chunk) => {
29
58
  process.stdout.write(chunk);
@@ -0,0 +1,16 @@
1
+ export declare const DEFAULT_TOKEN_PAGE_URL = "https://bigbrain.me/bigbrain-vibe/generate-z2h-token";
2
+ export declare const LOOPBACK_TIMEOUT_MS = 120000;
3
+ export interface GenerateZ2HTokenOptions {
4
+ /**
5
+ * Skip browser auto-open AND skip the loopback callback. Prints the URL
6
+ * for the user to open manually, then waits for them to paste the token
7
+ * into the prompt. Use for SSH sessions, CI, or when the loopback can't
8
+ * reach the CLI for any reason.
9
+ */
10
+ noBrowser?: boolean;
11
+ /** Override the page URL — useful when pointing at staging. */
12
+ url?: string;
13
+ json?: boolean;
14
+ }
15
+ export declare function generateZ2HTokenCommand(opts?: GenerateZ2HTokenOptions): Promise<void>;
16
+ //# sourceMappingURL=generate-z2h-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-z2h-token.d.ts","sourceRoot":"","sources":["../../src/commands/generate-z2h-token.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,sBAAsB,yDAAyD,CAAC;AAC7F,eAAO,MAAM,mBAAmB,SAAU,CAAC;AAE3C,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAuED,wBAAsB,uBAAuB,CAAC,IAAI,GAAE,uBAA4B,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B/F"}
@@ -0,0 +1,107 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const readline = require('node:readline/promises');
4
+ const node_process = require('node:process');
5
+ const execa = require('execa');
6
+ const util_logger = require('../util/logger.js');
7
+ const util_auth_writeAuth = require('../util/auth/write-auth.js');
8
+ const util_auth_loopbackServer = require('../util/auth/loopback-server.js');
9
+
10
+ const _interopDefault = e => e && e.__esModule ? e : { default: e };
11
+
12
+ const readline__default = /*#__PURE__*/_interopDefault(readline);
13
+
14
+ const DEFAULT_TOKEN_PAGE_URL = 'https://bigbrain.me/bigbrain-vibe/generate-z2h-token';
15
+ const LOOPBACK_TIMEOUT_MS = 120_000;
16
+ function browserOpenCommand() {
17
+ switch (process.platform) {
18
+ case 'darwin':
19
+ return 'open';
20
+ case 'win32':
21
+ return 'start';
22
+ default:
23
+ return 'xdg-open';
24
+ }
25
+ }
26
+ async function openInBrowser(url) {
27
+ await execa.execa(browserOpenCommand(), [url], { stdio: 'ignore' });
28
+ }
29
+ async function promptForToken() {
30
+ const rl = readline__default.default.createInterface({ input: node_process.stdin, output: node_process.stdout });
31
+ try {
32
+ const raw = await rl.question('Paste your token here, then press Enter:\n> ');
33
+ return raw.trim();
34
+ }
35
+ finally {
36
+ rl.close();
37
+ }
38
+ }
39
+ function withQueryParam(url, key, value) {
40
+ const sep = url.includes('?') ? '&' : '?';
41
+ return `${url}${sep}${key}=${encodeURIComponent(value)}`;
42
+ }
43
+ async function runManualFlow(pageUrl) {
44
+ util_logger.info(`open this URL in your browser to mint a Z2H deploy token:\n` +
45
+ ` ${pageUrl}\n\n` +
46
+ `1. Click "Generate token" on the page.\n` +
47
+ `2. Copy the token shown.\n` +
48
+ `3. Paste it below and press Enter.\n`);
49
+ const token = await promptForToken();
50
+ if (!token) {
51
+ throw new Error('No token entered.');
52
+ }
53
+ return token;
54
+ }
55
+ async function runLoopbackFlow(pageUrl) {
56
+ const loopback = await util_auth_loopbackServer.startLoopbackServer();
57
+ const fullUrl = withQueryParam(pageUrl, 'cli_callback', loopback.callbackUrl);
58
+ util_logger.info('opening your browser to mint a Z2H deploy token');
59
+ util_logger.info(` ${fullUrl}`);
60
+ try {
61
+ await openInBrowser(fullUrl);
62
+ }
63
+ catch {
64
+ util_logger.warn('could not auto-open the browser. please visit the URL above manually.');
65
+ }
66
+ util_logger.info('waiting for the page to send the token (Ctrl+C to fall back to manual paste)…');
67
+ try {
68
+ return await loopback.waitForToken(LOOPBACK_TIMEOUT_MS);
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ finally {
74
+ loopback.close();
75
+ }
76
+ }
77
+ async function generateZ2HTokenCommand(opts = {}) {
78
+ if (opts.json) {
79
+ util_logger.setOutputMode('json');
80
+ }
81
+ const pageUrl = opts.url ?? process.env.Z2H_TOKEN_PAGE_URL ?? DEFAULT_TOKEN_PAGE_URL;
82
+ // --no-browser bypasses both auto-open and the loopback round-trip — the
83
+ // user opens the URL themselves and pastes the token. Useful when the
84
+ // loopback can't be reached (SSH, CI, locked-down browsers).
85
+ let token = null;
86
+ if (!opts.noBrowser) {
87
+ token = await runLoopbackFlow(pageUrl);
88
+ if (!token) {
89
+ util_logger.warn('loopback flow timed out or was cancelled — falling back to manual paste.');
90
+ }
91
+ }
92
+ if (!token) {
93
+ token = await runManualFlow(pageUrl);
94
+ }
95
+ if (!util_auth_writeAuth.validateJwtPattern(token)) {
96
+ throw new Error('That does not look like a JWT (expected three dot-separated segments).');
97
+ }
98
+ const { filePath } = await util_auth_writeAuth.writeZthAuth({ token });
99
+ util_logger.output(`[z2h-cli] token saved ✅ ${filePath}`, {
100
+ ok: true,
101
+ filePath,
102
+ });
103
+ }
104
+
105
+ exports.DEFAULT_TOKEN_PAGE_URL = DEFAULT_TOKEN_PAGE_URL;
106
+ exports.LOOPBACK_TIMEOUT_MS = LOOPBACK_TIMEOUT_MS;
107
+ exports.generateZ2HTokenCommand = generateZ2HTokenCommand;
@@ -9,4 +9,12 @@ export declare const MIN_PORT = 13000;
9
9
  export declare const MAX_PORT = 19999;
10
10
  export declare const GITIGNORE_ENTRIES: string[];
11
11
  export declare const YARNRC_LINES: string[];
12
+ export declare const BUCKET_WRITE_NAME = "prod-use1-bigbrain-zth-mf-assets";
13
+ export declare const REGION = "us-east-1";
14
+ export declare const BUCKET_WRITE_URL = "https://prod-use1-bigbrain-zth-mf-assets.s3.us-east-1.amazonaws.com";
15
+ export declare const BUCKET_READ_DNS_NAME = "bigbrain-zth-mf-assets";
16
+ export declare const BUCKET_READ_DNS_URL = "https://bigbrain-zth-mf-assets.bigbrain.me";
17
+ export declare const MANIFEST_KEY = "mf-assets";
18
+ export declare const MANIFEST_READ_URL = "https://bigbrain-zth-mf-assets.bigbrain.me/mf-assets";
19
+ export declare const APP_NAME_PATTERN: RegExp;
12
20
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,eAAe,SAAS,CAAC;AAGtC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGjD,CAAC;AAQF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAElD,CAAC;AAMF,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAG9B,eAAO,MAAM,iBAAiB,UAAY,CAAC;AAG3C,eAAO,MAAM,YAAY,UAIxB,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,eAAe,SAAS,CAAC;AAGtC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGjD,CAAC;AAQF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAElD,CAAC;AAMF,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAG9B,eAAO,MAAM,iBAAiB,UAAY,CAAC;AAG3C,eAAO,MAAM,YAAY,UAIxB,CAAC;AAQF,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;AAM1E,eAAO,MAAM,gBAAgB,QAA2B,CAAC"}
package/dist/constants.js CHANGED
@@ -34,10 +34,38 @@ const YARNRC_LINES = [
34
34
  "npmAuthToken: '${NPM_TOKEN}'",
35
35
  "npmRegistryServer: 'https://registry.npmjs.org/'",
36
36
  ];
37
+ // ─────────── Z2H deploy bucket / contract ─────────
38
+ // Source of truth for the bucket layout. The CLI uses these when configuring
39
+ // the S3 client + uploading; bigbrain-zth's STS broker imports them via
40
+ // `@mondaydotcomorg/z2h-cli/constants` to scope the per-deploy session
41
+ // policy to the same bucket + manifest key.
42
+ const BUCKET_WRITE_NAME = 'prod-use1-bigbrain-zth-mf-assets';
43
+ const REGION = 'us-east-1';
44
+ const BUCKET_WRITE_URL = `https://${BUCKET_WRITE_NAME}.s3.${REGION}.amazonaws.com`;
45
+ const BUCKET_READ_DNS_NAME = 'bigbrain-zth-mf-assets';
46
+ const BUCKET_READ_DNS_URL = `https://${BUCKET_READ_DNS_NAME}.bigbrain.me`;
47
+ // No `.json` extension — TridentSkeleton's `mfUrl` API appends `/mf-assets`
48
+ // to the bucket base when fetching, so the manifest must live at this exact
49
+ // key. See microfrontends/mf-bigbrain-zth/.../ZeroToHeroHost.tsx.
50
+ const MANIFEST_KEY = 'mf-assets';
51
+ const MANIFEST_READ_URL = `${BUCKET_READ_DNS_URL}/${MANIFEST_KEY}`;
52
+ // ─────────── App-name slug — backend & CLI both honor this ─────
53
+ // Lowercase kebab-case, must start with a letter, 2-50 chars total. The
54
+ // backend STS broker rejects anything else with 400; the CLI can validate
55
+ // upfront for friendlier errors.
56
+ const APP_NAME_PATTERN = /^[a-z][a-z0-9-]{1,49}$/;
37
57
 
58
+ exports.APP_NAME_PATTERN = APP_NAME_PATTERN;
59
+ exports.BUCKET_READ_DNS_NAME = BUCKET_READ_DNS_NAME;
60
+ exports.BUCKET_READ_DNS_URL = BUCKET_READ_DNS_URL;
61
+ exports.BUCKET_WRITE_NAME = BUCKET_WRITE_NAME;
62
+ exports.BUCKET_WRITE_URL = BUCKET_WRITE_URL;
38
63
  exports.GITIGNORE_ENTRIES = GITIGNORE_ENTRIES;
64
+ exports.MANIFEST_KEY = MANIFEST_KEY;
65
+ exports.MANIFEST_READ_URL = MANIFEST_READ_URL;
39
66
  exports.MAX_PORT = MAX_PORT;
40
67
  exports.MIN_PORT = MIN_PORT;
68
+ exports.REGION = REGION;
41
69
  exports.SHADOW_DEV_DEPS = SHADOW_DEV_DEPS;
42
70
  exports.SHADOW_DIR_NAME = SHADOW_DIR_NAME;
43
71
  exports.SHADOW_SCRIPTS = SHADOW_SCRIPTS;
@@ -1,5 +1,6 @@
1
1
  export interface BuildOptions {
2
2
  json?: boolean;
3
+ publicUrl?: string;
3
4
  }
4
5
  export declare function buildCommand(opts: BuildOptions): Promise<void>;
5
6
  //# sourceMappingURL=build.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCpE"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCpE"}
@@ -20,7 +20,11 @@ async function buildCommand(opts) {
20
20
  stdio: 'inherit',
21
21
  });
22
22
  info(`building "${ctx.appName}" via trident`);
23
- await execa('yarn', ['build'], { cwd: ctx.paths.shadowDir, stdio: 'inherit' });
23
+ await execa('yarn', ['build'], {
24
+ cwd: ctx.paths.shadowDir,
25
+ stdio: 'inherit',
26
+ env: { ...process.env, ...(opts.publicUrl ? { PUBLIC_URL: opts.publicUrl } : {}) },
27
+ });
24
28
  if (!(await pathExists(ctx.paths.shadowBuild))) {
25
29
  throw new Error(`Expected build output at ${ctx.paths.shadowBuild} — not found.`);
26
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../../src/commands/create-workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAiBD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDxF"}
1
+ {"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../../src/commands/create-workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAiBD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DxF"}
@@ -54,6 +54,7 @@ async function createWorkspaceCommand(opts) {
54
54
  writeFile(path.join(home, 'package.json'), renderTemplate(pkgRaw, { __Z2H_CLI_VERSION__: cliVersion })),
55
55
  copy(path.join(wsTemplatesDir, 'gitignore'), path.join(home, '.gitignore')),
56
56
  copy(path.join(wsTemplatesDir, 'yarnrc.yml'), path.join(home, '.yarnrc.yml')),
57
+ copy(path.join(wsTemplatesDir, 'yarnlock'), path.join(home, 'yarn.lock')),
57
58
  copy(path.join(wsTemplatesDir, 'nvmrc'), path.join(home, '.nvmrc')),
58
59
  copy(path.join(wsTemplatesDir, 'npmrc'), path.join(home, '.npmrc')),
59
60
  copy(path.join(wsTemplatesDir, 'README.md'), path.join(home, 'README.md')),
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA0BD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EvF"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA6BD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAqFvF"}
@@ -5,8 +5,14 @@ import { execa } from 'execa';
5
5
  import { setOutputMode, info, output } from '../util/logger.mjs';
6
6
  import { assertWorkspace } from '../util/workspace.mjs';
7
7
  import { APP_TEMPLATES, getTemplatesDir, renderTemplate } from '../util/templates.mjs';
8
+ import { readManifest } from '../util/manifest.mjs';
9
+ import { mfAppName } from '../util/app-name.mjs';
10
+ import { APP_NAME_PATTERN } from '../constants.mjs';
8
11
 
9
- const APP_NAME_RE = /^[a-z][a-z0-9-]{1,49}$/;
12
+ // Names reserved by the host MF (mf-bigbrain-zth) for platform pages under
13
+ // /bigbrain-vibe/<name>. Creating an app with one of these would shadow the
14
+ // platform page in the URL, so we refuse upfront.
15
+ const RESERVED_APP_NAMES = new Set(['generate-z2h-token']);
10
16
  /**
11
17
  * Convert kebab-case to PascalCase. `demo-app` → `DemoApp`.
12
18
  */
@@ -34,7 +40,10 @@ async function createCommand(appName, opts) {
34
40
  // Validate workspace.
35
41
  const workspace = await assertWorkspace();
36
42
  // Validate app name.
37
- if (!APP_NAME_RE.test(appName)) {
43
+ if (RESERVED_APP_NAMES.has(appName)) {
44
+ throw new Error(`App name "${appName}" is reserved by the Z2H host for a platform page under /bigbrain-vibe/${appName}. Pick a different name.`);
45
+ }
46
+ if (!APP_NAME_PATTERN.test(appName)) {
38
47
  throw new Error(`App name "${appName}" is invalid. Use lowercase kebab-case (a-z, 0-9, -), ` +
39
48
  `2-50 chars, starting with a letter.`);
40
49
  }
@@ -52,6 +61,11 @@ async function createCommand(appName, opts) {
52
61
  if (!(await isDirEmpty(appDir))) {
53
62
  throw new Error(`${appDir} is non-empty. Pick a different name or wipe it first.`);
54
63
  }
64
+ // Check for manifest collision (network call — after all local checks).
65
+ const manifest = await readManifest();
66
+ if (manifest[mfAppName(appName)]) {
67
+ throw new Error(`An app named "${appName}" already exists in the Z2H registry. Pick a different name.`);
68
+ }
55
69
  // Compute substitutions.
56
70
  const vars = {
57
71
  __APP_NAME__: appName,
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/commands/deploy.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAaD,wBAAsB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA6EtE"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/commands/deploy.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA+EtE"}
@@ -1,35 +1,37 @@
1
1
  import path from 'node:path';
2
+ import os from 'node:os';
2
3
  import { readJson, pathExists } from 'fs-extra';
3
- import 'execa';
4
- import { setOutputMode, info, output, warn } from '../util/logger.mjs';
4
+ import { setOutputMode, info, output } from '../util/logger.mjs';
5
5
  import { resolveConsumerPaths } from '../shadow/paths.mjs';
6
6
  import { readManifest, nextVersion, writeManifest, upsertEntry } from '../util/manifest.mjs';
7
7
  import { uploadDir } from '../util/s3/upload.mjs';
8
- import { assertBucketExists, BUCKET_WRITE_NAME, BUCKET_READ_DNS_URL } from '../util/s3/client.mjs';
8
+ import { BUCKET_WRITE_NAME, BUCKET_READ_DNS_URL } from '../constants.mjs';
9
+ import { setupS3Client } from '../util/s3/client.mjs';
10
+ import { readZthAuth } from '../util/auth/auth-store.mjs';
9
11
  import { mfAppName, cleanAppName } from '../util/app-name.mjs';
10
12
  import { buildCommand } from './build.mjs';
11
13
 
12
- const APONO_BUNDLE = '<APONO_BUNDLE_NAME>'; // TODO: replace with actual bundle name once infra setup is complete
13
- async function requestAponoAccess() {
14
- {
15
- warn(`skipping Apono request — APONO_BUNDLE is still a placeholder ("${APONO_BUNDLE}"). Set it in deploy.ts before relying on auto-grant.`);
16
- return;
17
- }
18
- }
19
14
  async function deployCommand(opts) {
20
15
  if (opts.json) {
21
16
  setOutputMode('json');
22
17
  }
23
- info('checking S3 bucket');
24
- await assertBucketExists();
25
- info('building');
26
- await buildCommand({ json: opts.json });
27
18
  const paths = resolveConsumerPaths(process.cwd());
28
19
  const consumerPkg = (await readJson(paths.consumerPkg));
29
20
  if (!consumerPkg.name) {
30
21
  throw new Error('Consumer package.json must have a "name" field');
31
22
  }
32
23
  const appName = mfAppName(consumerPkg.name);
24
+ // Validate the user's deploy token is on disk before doing any expensive
25
+ // work. Throws Z2hAuthMissingError with a remediation hint if not.
26
+ await readZthAuth();
27
+ setupS3Client({ appName });
28
+ info('reading current Z2H manifest');
29
+ const manifest = await readManifest();
30
+ const version = nextVersion(manifest, appName);
31
+ const keyPrefix = `${appName}/${version}`;
32
+ const url = `${BUCKET_READ_DNS_URL}/${keyPrefix}`;
33
+ info('building');
34
+ await buildCommand({ json: opts.json, publicUrl: url });
33
35
  if (!(await pathExists(paths.shadowBuild))) {
34
36
  throw new Error(`No build output at ${paths.shadowBuild} after build step.`);
35
37
  }
@@ -39,11 +41,13 @@ async function deployCommand(opts) {
39
41
  throw new Error(`Missing asset-manifest.json at ${assetManifestPath}.`);
40
42
  }
41
43
  const assetManifest = (await readJson(assetManifestPath));
42
- info('reading current Z2H manifest');
43
- const manifest = await readManifest();
44
- const version = nextVersion(manifest, appName);
45
- const keyPrefix = `${appName}/${version}`;
46
- const url = `${BUCKET_READ_DNS_URL}/${keyPrefix}`;
44
+ const deployedBy = os.userInfo().username;
45
+ const entry = {
46
+ ...assetManifest,
47
+ version,
48
+ url,
49
+ deployedBy,
50
+ };
47
51
  if (opts.dryRun) {
48
52
  output(`[z2h-cli] dry-run: would upload to s3://${BUCKET_WRITE_NAME}/${keyPrefix}/ as v${version}`, {
49
53
  ok: true,
@@ -53,18 +57,12 @@ async function deployCommand(opts) {
53
57
  bucket: BUCKET_WRITE_NAME,
54
58
  keyPrefix,
55
59
  url,
56
- entry: { ...assetManifest, version, url },
60
+ entry,
57
61
  });
58
62
  return;
59
63
  }
60
- await requestAponoAccess();
61
64
  info(`uploading build → s3://${BUCKET_WRITE_NAME}/${keyPrefix}/`);
62
65
  await uploadDir(paths.shadowBuild, keyPrefix);
63
- const entry = {
64
- ...assetManifest,
65
- version,
66
- url,
67
- };
68
66
  info(`updating manifest entry "${appName}" → v${version}`);
69
67
  await writeManifest(upsertEntry(manifest, appName, entry));
70
68
  // The host MF parses the app name from the URL and prepends `mf-` itself
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/commands/dev.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAID,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgDhE"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/commands/dev.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAID,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAuEhE"}