@mondaydotcomorg/z2h-cli 0.5.2 → 0.6.1

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 (105) hide show
  1. package/dist/commands/create-workspace.d.ts.map +1 -1
  2. package/dist/commands/create-workspace.js +2 -5
  3. package/dist/commands/create.d.ts.map +1 -1
  4. package/dist/commands/create.js +2 -5
  5. package/dist/constants.d.ts +18 -0
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +41 -0
  8. package/dist/esm/commands/create-workspace.d.ts.map +1 -1
  9. package/dist/esm/commands/create-workspace.mjs +2 -5
  10. package/dist/esm/commands/create.d.ts.map +1 -1
  11. package/dist/esm/commands/create.mjs +2 -5
  12. package/dist/esm/constants.d.ts +18 -0
  13. package/dist/esm/constants.d.ts.map +1 -1
  14. package/dist/esm/constants.mjs +35 -1
  15. package/dist/esm/index.mjs +18 -6
  16. package/dist/esm/migrations/003-npm-broker-scope-split.d.ts +14 -0
  17. package/dist/esm/migrations/003-npm-broker-scope-split.d.ts.map +1 -0
  18. package/dist/esm/migrations/003-npm-broker-scope-split.mjs +49 -0
  19. package/dist/esm/migrations/__tests__/003-npm-broker-scope-split.test.d.ts +2 -0
  20. package/dist/esm/migrations/__tests__/003-npm-broker-scope-split.test.d.ts.map +1 -0
  21. package/dist/esm/migrations/auto-migrate.mjs +4 -4
  22. package/dist/esm/shadow/sync.d.ts.map +1 -1
  23. package/dist/esm/shadow/sync.mjs +4 -6
  24. package/dist/esm/util/auth/auth-store.d.ts +10 -0
  25. package/dist/esm/util/auth/auth-store.d.ts.map +1 -1
  26. package/dist/esm/util/auth/auth-store.mjs +20 -2
  27. package/dist/esm/util/auth/broker-credential-provider.d.ts +0 -1
  28. package/dist/esm/util/auth/broker-credential-provider.d.ts.map +1 -1
  29. package/dist/esm/util/auth/broker-credential-provider.mjs +2 -5
  30. package/dist/esm/util/logger.d.ts.map +1 -1
  31. package/dist/esm/util/logger.mjs +2 -0
  32. package/dist/esm/util/npm/__tests__/broker-config.test.d.ts +2 -0
  33. package/dist/esm/util/npm/__tests__/broker-config.test.d.ts.map +1 -0
  34. package/dist/esm/util/npm/__tests__/install.test.d.ts +2 -0
  35. package/dist/esm/util/npm/__tests__/install.test.d.ts.map +1 -0
  36. package/dist/esm/util/npm/broker-config.d.ts +20 -0
  37. package/dist/esm/util/npm/broker-config.d.ts.map +1 -0
  38. package/dist/esm/util/npm/broker-config.mjs +59 -0
  39. package/dist/esm/util/npm/ensure-token.d.ts +19 -0
  40. package/dist/esm/util/npm/ensure-token.d.ts.map +1 -0
  41. package/dist/esm/util/npm/ensure-token.mjs +22 -0
  42. package/dist/esm/util/npm/install.d.ts +18 -0
  43. package/dist/esm/util/npm/install.d.ts.map +1 -0
  44. package/dist/esm/util/npm/install.mjs +74 -0
  45. package/dist/esm/util/tracker.d.ts +3 -0
  46. package/dist/esm/util/tracker.d.ts.map +1 -0
  47. package/dist/esm/util/tracker.mjs +20 -0
  48. package/dist/index.js +18 -6
  49. package/dist/migrations/003-npm-broker-scope-split.d.ts +14 -0
  50. package/dist/migrations/003-npm-broker-scope-split.d.ts.map +1 -0
  51. package/dist/migrations/003-npm-broker-scope-split.js +51 -0
  52. package/dist/migrations/__tests__/003-npm-broker-scope-split.test.d.ts +2 -0
  53. package/dist/migrations/__tests__/003-npm-broker-scope-split.test.d.ts.map +1 -0
  54. package/dist/migrations/auto-migrate.js +3 -3
  55. package/dist/shadow/sync.d.ts.map +1 -1
  56. package/dist/shadow/sync.js +4 -6
  57. package/dist/util/auth/auth-store.d.ts +10 -0
  58. package/dist/util/auth/auth-store.d.ts.map +1 -1
  59. package/dist/util/auth/auth-store.js +19 -0
  60. package/dist/util/auth/broker-credential-provider.d.ts +0 -1
  61. package/dist/util/auth/broker-credential-provider.d.ts.map +1 -1
  62. package/dist/util/auth/broker-credential-provider.js +2 -6
  63. package/dist/util/logger.d.ts.map +1 -1
  64. package/dist/util/logger.js +2 -0
  65. package/dist/util/npm/__tests__/broker-config.test.d.ts +2 -0
  66. package/dist/util/npm/__tests__/broker-config.test.d.ts.map +1 -0
  67. package/dist/util/npm/__tests__/install.test.d.ts +2 -0
  68. package/dist/util/npm/__tests__/install.test.d.ts.map +1 -0
  69. package/dist/util/npm/broker-config.d.ts +20 -0
  70. package/dist/util/npm/broker-config.d.ts.map +1 -0
  71. package/dist/util/npm/broker-config.js +63 -0
  72. package/dist/util/npm/ensure-token.d.ts +19 -0
  73. package/dist/util/npm/ensure-token.d.ts.map +1 -0
  74. package/dist/util/npm/ensure-token.js +24 -0
  75. package/dist/util/npm/install.d.ts +18 -0
  76. package/dist/util/npm/install.d.ts.map +1 -0
  77. package/dist/util/npm/install.js +76 -0
  78. package/dist/util/tracker.d.ts +3 -0
  79. package/dist/util/tracker.d.ts.map +1 -0
  80. package/dist/util/tracker.js +27 -0
  81. package/migrations.json +5 -0
  82. package/package.json +1 -1
  83. package/src/commands/__tests__/create-workspace.test.ts +9 -11
  84. package/src/commands/__tests__/create.test.ts +9 -6
  85. package/src/commands/create-workspace.ts +2 -5
  86. package/src/commands/create.ts +2 -5
  87. package/src/constants.ts +41 -0
  88. package/src/index.ts +18 -6
  89. package/src/migrations/003-npm-broker-scope-split.ts +52 -0
  90. package/src/migrations/__tests__/003-npm-broker-scope-split.test.ts +99 -0
  91. package/src/migrations/auto-migrate.ts +4 -4
  92. package/src/shadow/sync.ts +4 -6
  93. package/src/templates/workspace/npmrc +3 -2
  94. package/src/templates/workspace/yarnrc.yml +6 -2
  95. package/src/util/__tests__/workspace-templates-shipped.test.ts +19 -0
  96. package/src/util/auth/__tests__/broker-credential-provider.test.ts +2 -1
  97. package/src/util/auth/auth-store.ts +19 -1
  98. package/src/util/auth/broker-credential-provider.ts +1 -5
  99. package/src/util/logger.ts +2 -0
  100. package/src/util/npm/__tests__/broker-config.test.ts +48 -0
  101. package/src/util/npm/__tests__/install.test.ts +94 -0
  102. package/src/util/npm/broker-config.ts +63 -0
  103. package/src/util/npm/ensure-token.ts +28 -0
  104. package/src/util/npm/install.ts +84 -0
  105. package/src/util/tracker.ts +25 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker-config.d.ts","sourceRoot":"","sources":["../../../../src/util/npm/broker-config.ts"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAK3C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAiBhD"}
@@ -0,0 +1,59 @@
1
+ import { BROKER_NPM_SCOPE, Z2H_NPM_TOKEN_ENV, PUBLIC_NPM_REGISTRY_URL, brokerNpmRegistryUrl } from '../../constants.mjs';
2
+
3
+ /** `https://host/path/` (with trailing slash) for the registry= line. */
4
+ function registryUrlWithSlash() {
5
+ const url = brokerNpmRegistryUrl();
6
+ return url.endsWith('/') ? url : `${url}/`;
7
+ }
8
+ /**
9
+ * The `//host/path/` prefix (scheme stripped, trailing slash kept) that npm
10
+ * requires the `:_authToken` key to be keyed under so it aligns with the
11
+ * registry path. Derived from the same registry URL so staging overrides flow
12
+ * through.
13
+ */
14
+ function authKeyPrefix() {
15
+ return registryUrlWithSlash().replace(/^https?:/, '');
16
+ }
17
+ /**
18
+ * The two npm config lines (§3.1 / §3.3) that route the brokered scope to the
19
+ * proxy and supply the `${Z2H_NPM_TOKEN}` placeholder. No literal token — npm
20
+ * interpolates the placeholder from the env at invocation time.
21
+ */
22
+ function brokerNpmrcLines() {
23
+ return [
24
+ `${BROKER_NPM_SCOPE}:registry=${registryUrlWithSlash()}`,
25
+ `${authKeyPrefix()}:_authToken=\${${Z2H_NPM_TOKEN_ENV}}`,
26
+ ];
27
+ }
28
+ /**
29
+ * Full contents for a **workspace** `.npmrc` (§3.3): broker scope-split plus an
30
+ * explicit public default registry and always-auth. Used by the template and
31
+ * the migration so both stay byte-identical.
32
+ */
33
+ function workspaceNpmrcContents() {
34
+ return [...brokerNpmrcLines(), `registry=${PUBLIC_NPM_REGISTRY_URL}`, 'always-auth=true'].join('\n') + '\n';
35
+ }
36
+ /**
37
+ * Full contents for a **workspace** `.yarnrc.yml` (§3.2): the brokered scope
38
+ * points at the proxy with the `${Z2H_NPM_TOKEN}` placeholder + always-auth;
39
+ * the default `npmRegistryServer` stays the public registry (direct, unchanged
40
+ * speed). `yarnPath` keeps the bundled Berry release so any `yarn` runs 4.x.
41
+ */
42
+ function workspaceYarnrcContents() {
43
+ const scopeKey = BROKER_NPM_SCOPE.replace(/^@/, '');
44
+ return ([
45
+ 'nodeLinker: node-modules',
46
+ '',
47
+ 'npmScopes:',
48
+ ` ${scopeKey}:`,
49
+ ` npmRegistryServer: "${brokerNpmRegistryUrl()}"`,
50
+ ` npmAuthToken: "\${${Z2H_NPM_TOKEN_ENV}}"`,
51
+ ' npmAlwaysAuth: true',
52
+ '',
53
+ `npmRegistryServer: "${PUBLIC_NPM_REGISTRY_URL}"`,
54
+ '',
55
+ 'yarnPath: .yarn/releases/yarn-4.5.1.cjs',
56
+ ].join('\n') + '\n');
57
+ }
58
+
59
+ export { brokerNpmrcLines, workspaceNpmrcContents, workspaceYarnrcContents };
@@ -0,0 +1,19 @@
1
+ export interface EnsureZ2hTokenOptions {
2
+ /**
3
+ * Re-run the token flow even if a token already exists on disk. Used after a
4
+ * broker 401, where the stored token is present but expired/invalid.
5
+ */
6
+ forceRefresh?: boolean;
7
+ }
8
+ /**
9
+ * Ensure a z2h JWT exists at `~/.zth/auth.json` before an install-bearing
10
+ * command runs. If none is present (or `forceRefresh` is set), drive the
11
+ * existing `generate-z2h-token` flow — loopback capture with manual-paste
12
+ * fallback — which writes the token. No-ops when a token already exists and no
13
+ * refresh was requested.
14
+ *
15
+ * This is the install preflight: it keeps a friendly auth prompt in front of
16
+ * the raw npm error a non-technical user would otherwise hit.
17
+ */
18
+ export declare function ensureZ2hToken(opts?: EnsureZ2hTokenOptions): Promise<void>;
19
+ //# sourceMappingURL=ensure-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensure-token.d.ts","sourceRoot":"","sources":["../../../../src/util/npm/ensure-token.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAKpF"}
@@ -0,0 +1,22 @@
1
+ import { tryReadAuthTokenSync } from '../auth/auth-store.mjs';
2
+ import { info } from '../logger.mjs';
3
+ import { generateZ2HTokenCommand } from '../../commands/generate-z2h-token.mjs';
4
+
5
+ /**
6
+ * Ensure a z2h JWT exists at `~/.zth/auth.json` before an install-bearing
7
+ * command runs. If none is present (or `forceRefresh` is set), drive the
8
+ * existing `generate-z2h-token` flow — loopback capture with manual-paste
9
+ * fallback — which writes the token. No-ops when a token already exists and no
10
+ * refresh was requested.
11
+ *
12
+ * This is the install preflight: it keeps a friendly auth prompt in front of
13
+ * the raw npm error a non-technical user would otherwise hit.
14
+ */
15
+ async function ensureZ2hToken(opts = {}) {
16
+ if (opts.forceRefresh || !tryReadAuthTokenSync()) {
17
+ info('you need to sign in to install monday packages — opening the sign-in page');
18
+ await generateZ2HTokenCommand();
19
+ }
20
+ }
21
+
22
+ export { ensureZ2hToken };
@@ -0,0 +1,18 @@
1
+ export interface RunYarnInstallOptions {
2
+ /** Directory to run `yarn install` in. */
3
+ cwd: string;
4
+ /** Extra env to merge on top of `process.env` + the broker token. */
5
+ extraEnv?: NodeJS.ProcessEnv;
6
+ }
7
+ /**
8
+ * Run `yarn install` for an install-bearing command:
9
+ * 1. Preflight — ensure a z2h token exists (prompt `generate-z2h-token` if not).
10
+ * 2. Install through the broker.
11
+ * 3. On a broker 401, surface a friendly "your access expired — refreshing it"
12
+ * message, re-auth, and retry the install exactly once.
13
+ *
14
+ * A non-auth failure (real dependency error, network, etc.) propagates as-is so
15
+ * the command's normal error path reports it.
16
+ */
17
+ export declare function runYarnInstall(opts: RunYarnInstallOptions): Promise<void>;
18
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../../src/util/npm/install.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,qBAAqB;IACpC,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAC9B;AAqCD;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAc/E"}
@@ -0,0 +1,74 @@
1
+ import { execa } from 'execa';
2
+ import { warn, info } from '../logger.mjs';
3
+ import { tryReadAuthTokenSync } from '../auth/auth-store.mjs';
4
+ import { Z2H_NPM_TOKEN_ENV } from '../../constants.mjs';
5
+ import { ensureZ2hToken } from './ensure-token.mjs';
6
+
7
+ // Substrings that, in a failed install's output, indicate the broker rejected
8
+ // the z2h JWT (expired/invalid). npm surfaces `E401`/`code E401`; yarn berry
9
+ // surfaces an HTTP 401 line. We re-auth on any of these rather than dumping a
10
+ // raw npm error on a non-technical user.
11
+ const AUTH_FAILURE_MARKERS = ['401', 'e401', 'unauthorized', 'authentication'];
12
+ function looksLikeAuthFailure(text) {
13
+ const haystack = text.toLowerCase();
14
+ return AUTH_FAILURE_MARKERS.some(marker => haystack.includes(marker));
15
+ }
16
+ /**
17
+ * Spawn `yarn install` in `cwd` with the npm-broker credential injected, while
18
+ * streaming yarn's output live to the user. stdout is inherited; stderr is
19
+ * piped so we can both echo it and inspect it for a broker auth failure.
20
+ *
21
+ * Returns the captured stderr on success; throws an Error tagged
22
+ * `isAuthFailure` when the failure output looks like a broker 401 so the
23
+ * caller can re-auth, or rethrows the raw execa error otherwise.
24
+ */
25
+ async function spawnYarnInstall(opts) {
26
+ const token = tryReadAuthTokenSync();
27
+ const env = { ...process.env, ...(token && { [Z2H_NPM_TOKEN_ENV]: token }), ...opts.extraEnv };
28
+ const child = execa('yarn', ['install'], {
29
+ cwd: opts.cwd,
30
+ stdout: 'inherit',
31
+ stderr: ['inherit', 'pipe'],
32
+ env,
33
+ });
34
+ try {
35
+ await child;
36
+ }
37
+ catch (err) {
38
+ const e = err;
39
+ const combined = `${e.stderr}\n${e.message ?? ''}`;
40
+ if (looksLikeAuthFailure(combined)) {
41
+ const authErr = new Error('broker rejected the z2h token during install');
42
+ authErr.isAuthFailure = true;
43
+ throw authErr;
44
+ }
45
+ throw err;
46
+ }
47
+ }
48
+ /**
49
+ * Run `yarn install` for an install-bearing command:
50
+ * 1. Preflight — ensure a z2h token exists (prompt `generate-z2h-token` if not).
51
+ * 2. Install through the broker.
52
+ * 3. On a broker 401, surface a friendly "your access expired — refreshing it"
53
+ * message, re-auth, and retry the install exactly once.
54
+ *
55
+ * A non-auth failure (real dependency error, network, etc.) propagates as-is so
56
+ * the command's normal error path reports it.
57
+ */
58
+ async function runYarnInstall(opts) {
59
+ await ensureZ2hToken();
60
+ try {
61
+ await spawnYarnInstall(opts);
62
+ }
63
+ catch (err) {
64
+ if (!err.isAuthFailure) {
65
+ throw err;
66
+ }
67
+ warn('your access expired — refreshing it now…');
68
+ await ensureZ2hToken({ forceRefresh: true });
69
+ info('access refreshed — retrying install');
70
+ await spawnYarnInstall(opts);
71
+ }
72
+ }
73
+
74
+ export { runYarnInstall };
@@ -0,0 +1,3 @@
1
+ export declare function trackEvent(name: string, data: Record<string, unknown>): void;
2
+ export declare function trackDuration<T>(eventName: string, fn: () => Promise<T>, data?: Record<string, unknown>): Promise<T>;
3
+ //# sourceMappingURL=tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../../src/util/tracker.ts"],"names":[],"mappings":"AAMA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAO5E;AAED,wBAAsB,aAAa,CAAC,CAAC,EACnC,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,CAAC,CAAC,CAKZ"}
@@ -0,0 +1,20 @@
1
+ import os from 'node:os';
2
+
3
+ const DOORMAN_URL = 'https://track.bigbrain.me/prod/event';
4
+ const username = os.userInfo().username;
5
+ function trackEvent(name, data) {
6
+ void fetch(DOORMAN_URL, {
7
+ method: 'POST',
8
+ headers: { 'Content-Type': 'application/json' },
9
+ body: JSON.stringify({ name, source: 'z2h-cli', data: { username, ...data } }),
10
+ signal: AbortSignal.timeout(5000),
11
+ }).catch(() => { });
12
+ }
13
+ async function trackDuration(eventName, fn, data) {
14
+ const start = Date.now();
15
+ const result = await fn();
16
+ trackEvent(eventName, { ...data, duration_ms: Date.now() - start });
17
+ return result;
18
+ }
19
+
20
+ export { trackDuration, trackEvent };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const node_module = require('node:module');
2
+ const fs = require('node:fs');
2
3
  const commander = require('commander');
3
4
  const commands_dev = require('./commands/dev.js');
4
5
  const commands_build = require('./commands/build.js');
@@ -9,9 +10,18 @@ const commands_create = require('./commands/create.js');
9
10
  const commands_generateZ2hToken = require('./commands/generate-z2h-token.js');
10
11
  const commands_migrate = require('./commands/migrate.js');
11
12
  const util_logger = require('./util/logger.js');
13
+ const util_tracker = require('./util/tracker.js');
12
14
 
13
15
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
14
16
  const { version } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)))('../package.json');
17
+ function getCwdAppName() {
18
+ try {
19
+ return JSON.parse(fs.readFileSync('package.json', 'utf8')).name;
20
+ }
21
+ catch {
22
+ return undefined;
23
+ }
24
+ }
15
25
  async function main() {
16
26
  const program = new commander.Command();
17
27
  program
@@ -35,12 +45,9 @@ async function main() {
35
45
  .option('--json', 'emit structured JSON on stdout')
36
46
  .action(async (opts) => {
37
47
  try {
38
- await commands_build.buildCommand(opts);
48
+ await util_tracker.trackDuration('z2h_app_build_success', () => commands_build.buildCommand(opts), { app_name: getCwdAppName() });
39
49
  }
40
50
  catch (err) {
41
- // fail() emits a structured JSON error on stdout in --json mode and
42
- // a red line on stderr in human mode, then exits. errorLog alone is
43
- // silent in JSON mode, which leaves machine consumers with no signal.
44
51
  util_logger.fail(`build failed: ${err.message}`, { command: 'build' }, 2);
45
52
  }
46
53
  });
@@ -75,7 +82,9 @@ async function main() {
75
82
  .option('--json', 'emit structured JSON on stdout')
76
83
  .action(async (opts) => {
77
84
  try {
78
- await commands_deploy.deployCommand(opts);
85
+ await util_tracker.trackDuration('z2h_app_deploy_success', () => commands_deploy.deployCommand(opts), {
86
+ app_name: getCwdAppName(),
87
+ });
79
88
  }
80
89
  catch (err) {
81
90
  util_logger.fail(`deploy failed: ${err.message}`, { command: 'deploy' }, 2);
@@ -115,7 +124,10 @@ async function main() {
115
124
  .option('--json', 'emit structured JSON on stdout')
116
125
  .action(async (appName, opts) => {
117
126
  try {
118
- await commands_create.createCommand(appName, opts);
127
+ await util_tracker.trackDuration('z2h_app_created', () => commands_create.createCommand(appName, opts), {
128
+ app_name: appName,
129
+ template: opts.template ?? 'default',
130
+ });
119
131
  }
120
132
  catch (err) {
121
133
  util_logger.fail(`create failed: ${err.message}`, { command: 'create' }, 1);
@@ -0,0 +1,14 @@
1
+ import type { Tree } from '@nx/devkit';
2
+ /**
3
+ * Migrate the workspace npm/yarn config from the legacy single-registry
4
+ * `${NPM_TOKEN}` form to the `@mondaydotcomorg`→broker scope-split
5
+ * (`${Z2H_NPM_TOKEN}` placeholder). Rewrites the workspace-root `.yarnrc.yml`
6
+ * and `.npmrc`, plus any consumer-app copies that still carry the legacy
7
+ * placeholder (migration 001 normally removes per-consumer `.yarnrc.yml`, so
8
+ * this is just defensive cleanup).
9
+ *
10
+ * The global `~/.npmrc` broker block is written separately by `migrateCommand`
11
+ * (it lives outside the workspace Tree).
12
+ */
13
+ export default function npmBrokerScopeSplit(tree: Tree): void;
14
+ //# sourceMappingURL=003-npm-broker-scope-split.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"003-npm-broker-scope-split.d.ts","sourceRoot":"","sources":["../../src/migrations/003-npm-broker-scope-split.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAuBvC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAgB5D"}
@@ -0,0 +1,51 @@
1
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
2
+
3
+ const util_npm_brokerConfig = require('../util/npm/broker-config.js');
4
+
5
+ // Legacy marker: the old configs interpolated a real npm token via
6
+ // `${NPM_TOKEN}`. Its presence means the file predates npm brokering and must
7
+ // be rewritten to the scope-split. Once rewritten (placeholder is now
8
+ // `${Z2H_NPM_TOKEN}`) this no longer matches, so the migration is idempotent.
9
+ const LEGACY_TOKEN_PLACEHOLDER = '${NPM_TOKEN}';
10
+ /**
11
+ * Rewrite a single rc file to `contents` iff it exists and still carries the
12
+ * legacy `${NPM_TOKEN}` placeholder. Returns nothing; mutates the Tree.
13
+ */
14
+ function rewriteIfLegacy(tree, filePath, contents) {
15
+ if (!tree.exists(filePath)) {
16
+ return;
17
+ }
18
+ const current = tree.read(filePath, 'utf-8') ?? '';
19
+ if (!current.includes(LEGACY_TOKEN_PLACEHOLDER)) {
20
+ return; // already migrated (or never legacy) — leave untouched
21
+ }
22
+ tree.write(filePath, contents);
23
+ }
24
+ /**
25
+ * Migrate the workspace npm/yarn config from the legacy single-registry
26
+ * `${NPM_TOKEN}` form to the `@mondaydotcomorg`→broker scope-split
27
+ * (`${Z2H_NPM_TOKEN}` placeholder). Rewrites the workspace-root `.yarnrc.yml`
28
+ * and `.npmrc`, plus any consumer-app copies that still carry the legacy
29
+ * placeholder (migration 001 normally removes per-consumer `.yarnrc.yml`, so
30
+ * this is just defensive cleanup).
31
+ *
32
+ * The global `~/.npmrc` broker block is written separately by `migrateCommand`
33
+ * (it lives outside the workspace Tree).
34
+ */
35
+ function npmBrokerScopeSplit(tree) {
36
+ const yarnrc = util_npm_brokerConfig.workspaceYarnrcContents();
37
+ const npmrc = util_npm_brokerConfig.workspaceNpmrcContents();
38
+ // Workspace root.
39
+ rewriteIfLegacy(tree, '.yarnrc.yml', yarnrc);
40
+ rewriteIfLegacy(tree, '.npmrc', npmrc);
41
+ // Any consumer apps that still carry their own legacy rc files.
42
+ for (const entry of tree.children('.')) {
43
+ if (entry.startsWith('.')) {
44
+ continue;
45
+ }
46
+ rewriteIfLegacy(tree, `${entry}/.yarnrc.yml`, yarnrc);
47
+ rewriteIfLegacy(tree, `${entry}/.npmrc`, npmrc);
48
+ }
49
+ }
50
+
51
+ exports.default = npmBrokerScopeSplit;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=003-npm-broker-scope-split.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"003-npm-broker-scope-split.test.d.ts","sourceRoot":"","sources":["../../../src/migrations/__tests__/003-npm-broker-scope-split.test.ts"],"names":[],"mappings":""}
@@ -159,9 +159,9 @@ async function autoMigrate(cliVersion, dryRun = false) {
159
159
  }
160
160
  }
161
161
  catch (err) {
162
- util_logger.warn(` ✗ migration "${name}" failed: ${err.message}`);
163
- util_logger.warn(' skipping remaining migrations. Run "z2h-cli migrate" to retry.');
164
- return;
162
+ const errorMessage = `migration "${name}" failed: ${err.message}`;
163
+ util_logger.errorLog(`${errorMessage}\nSkipping remaining migrations — run "z2h-cli migrate" to retry.`);
164
+ throw new Error(errorMessage);
165
165
  }
166
166
  }
167
167
  if (needsInstall) {
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/shadow/sync.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE3D;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9F"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/shadow/sync.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE3D;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAe9F"}
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const fsExtra = require('fs-extra');
4
- const execa = require('execa');
5
4
  const util_logger = require('../util/logger.js');
5
+ const util_npm_install = require('../util/npm/install.js');
6
6
  const shadow_mergePackageJson = require('./merge-package-json.js');
7
7
 
8
8
  /**
@@ -19,11 +19,9 @@ async function syncShadow(paths, consumerPkg) {
19
19
  if (oldHash !== newHash) {
20
20
  util_logger.info(oldHash ? 'consumer deps changed — yarn install' : 'first run — yarn install');
21
21
  // Yarn 4 is cache-first and non-interactive by default in non-TTY
22
- // contexts, so plain `yarn install` is all we need.
23
- await execa.execa('yarn', ['install'], {
24
- cwd: paths.consumerDir,
25
- stdio: 'inherit',
26
- });
22
+ // contexts, so plain `yarn install` is all we need. runYarnInstall injects
23
+ // the npm-broker token, preflights auth, and re-auths on a broker 401.
24
+ await util_npm_install.runYarnInstall({ cwd: paths.consumerDir });
27
25
  await fsExtra.writeFile(paths.shadowDepsHash, newHash);
28
26
  }
29
27
  }
@@ -8,4 +8,14 @@ export declare class Z2hAuthMissingError extends Error {
8
8
  constructor(authFilePath: string);
9
9
  }
10
10
  export declare function readZthAuth(): Promise<ZthAuth>;
11
+ /**
12
+ * Synchronous, never-throws read of the z2h JWT from `~/.zth/auth.json`.
13
+ * Returns the token string, or `null` when the file is absent, unreadable,
14
+ * malformed, or missing the `token` field.
15
+ *
16
+ * Used when building the env for a spawned package-manager process, where a
17
+ * missing token must degrade gracefully (best-effort self-update) rather than
18
+ * blow up — and where an inline sync read keeps the spawn call site simple.
19
+ */
20
+ export declare function tryReadAuthTokenSync(): string | null;
11
21
  //# sourceMappingURL=auth-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-store.d.ts","sourceRoot":"","sources":["../../../src/util/auth/auth-store.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,YAAY,QAAkC,CAAC;AAC5D,eAAO,MAAM,aAAa,QAAuC,CAAC;AAElE,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,mBAAoB,SAAQ,KAAK;aAChB,YAAY,EAAE,MAAM;gBAApB,YAAY,EAAE,MAAM;CAIjD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CASpD"}
1
+ {"version":3,"file":"auth-store.d.ts","sourceRoot":"","sources":["../../../src/util/auth/auth-store.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,YAAY,QAAkC,CAAC;AAC5D,eAAO,MAAM,aAAa,QAAuC,CAAC;AAElE,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,mBAAoB,SAAQ,KAAK;aAChB,YAAY,EAAE,MAAM;gBAApB,YAAY,EAAE,MAAM;CAIjD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CASpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,IAAI,CAOpD"}
@@ -32,8 +32,27 @@ async function readZthAuth() {
32
32
  }
33
33
  return { token: parsed.token };
34
34
  }
35
+ /**
36
+ * Synchronous, never-throws read of the z2h JWT from `~/.zth/auth.json`.
37
+ * Returns the token string, or `null` when the file is absent, unreadable,
38
+ * malformed, or missing the `token` field.
39
+ *
40
+ * Used when building the env for a spawned package-manager process, where a
41
+ * missing token must degrade gracefully (best-effort self-update) rather than
42
+ * blow up — and where an inline sync read keeps the spawn call site simple.
43
+ */
44
+ function tryReadAuthTokenSync() {
45
+ try {
46
+ const parsed = fsExtra.readJsonSync(Z2H_AUTH_FILE);
47
+ return parsed?.token ?? null;
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
35
53
 
36
54
  exports.Z2H_AUTH_DIR = Z2H_AUTH_DIR;
37
55
  exports.Z2H_AUTH_FILE = Z2H_AUTH_FILE;
38
56
  exports.Z2hAuthMissingError = Z2hAuthMissingError;
39
57
  exports.readZthAuth = readZthAuth;
58
+ exports.tryReadAuthTokenSync = tryReadAuthTokenSync;
@@ -1,5 +1,4 @@
1
1
  import type { AwsCredentialIdentityProvider } from '@aws-sdk/types';
2
- export declare const DEFAULT_BROKER_BASE_URL = "https://bigbrain-zth.bigbrain.me";
3
2
  export declare const STS_BROKER_PATH = "/z2h-cli/sts/credentials";
4
3
  /**
5
4
  * AWS SDK credential provider that fetches short-lived deploy credentials
@@ -1 +1 @@
1
- {"version":3,"file":"broker-credential-provider.d.ts","sourceRoot":"","sources":["../../../src/util/auth/broker-credential-provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAyB,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAE3F,eAAO,MAAM,uBAAuB,qCAAqC,CAAC;AAC1E,eAAO,MAAM,eAAe,6BAA6B,CAAC;AA4D1D;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,6BAA6B,CAuBxG"}
1
+ {"version":3,"file":"broker-credential-provider.d.ts","sourceRoot":"","sources":["../../../src/util/auth/broker-credential-provider.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAyB,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAE3F,eAAO,MAAM,eAAe,6BAA6B,CAAC;AAwD1D;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,6BAA6B,CAuBxG"}
@@ -1,18 +1,15 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
+ const constants = require('../../constants.js');
3
4
  const util_auth_authStore = require('./auth-store.js');
4
5
 
5
- const DEFAULT_BROKER_BASE_URL = 'https://bigbrain-zth.bigbrain.me';
6
6
  const STS_BROKER_PATH = '/z2h-cli/sts/credentials';
7
7
  // Refresh the cached credentials this many ms before they expire so the next
8
8
  // AWS API call doesn't race the broker round-trip against a hard expiry.
9
9
  const REFRESH_BUFFER_MS = 5 * 60 * 1000;
10
- function brokerBaseUrl() {
11
- return process.env.Z2H_BROKER_BASE_URL || DEFAULT_BROKER_BASE_URL;
12
- }
13
10
  async function fetchCredentialsOnce(appName) {
14
11
  const { token } = await util_auth_authStore.readZthAuth();
15
- const url = `${brokerBaseUrl()}${STS_BROKER_PATH}`;
12
+ const url = `${constants.brokerBaseUrl()}${STS_BROKER_PATH}`;
16
13
  let res;
17
14
  try {
18
15
  res = await fetch(url, {
@@ -75,6 +72,5 @@ function brokerCredentialProvider({ appName }) {
75
72
  };
76
73
  }
77
74
 
78
- exports.DEFAULT_BROKER_BASE_URL = DEFAULT_BROKER_BASE_URL;
79
75
  exports.STS_BROKER_PATH = STS_BROKER_PATH;
80
76
  exports.brokerCredentialProvider = brokerCredentialProvider;
@@ -1 +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"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/util/logger.ts"],"names":[],"mappings":"AAGA,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,CAW3F"}
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const pc = require('picocolors');
4
+ const util_tracker = require('./tracker.js');
4
5
 
5
6
  const _interopDefault = e => e && e.__esModule ? e : { default: e };
6
7
 
@@ -59,6 +60,7 @@ function fail(message, payload, exitCode = 1) {
59
60
  process.stderr.write(pc__default.default.dim(` → ${payload.suggestedCommand}\n`));
60
61
  }
61
62
  }
63
+ util_tracker.trackEvent('z2h_cli_error', { action: payload.command ?? 'unknown', error: message });
62
64
  process.exit(exitCode);
63
65
  }
64
66
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=broker-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker-config.test.d.ts","sourceRoot":"","sources":["../../../../src/util/npm/__tests__/broker-config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=install.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.test.d.ts","sourceRoot":"","sources":["../../../../src/util/npm/__tests__/install.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The two npm config lines (§3.1 / §3.3) that route the brokered scope to the
3
+ * proxy and supply the `${Z2H_NPM_TOKEN}` placeholder. No literal token — npm
4
+ * interpolates the placeholder from the env at invocation time.
5
+ */
6
+ export declare function brokerNpmrcLines(): string[];
7
+ /**
8
+ * Full contents for a **workspace** `.npmrc` (§3.3): broker scope-split plus an
9
+ * explicit public default registry and always-auth. Used by the template and
10
+ * the migration so both stay byte-identical.
11
+ */
12
+ export declare function workspaceNpmrcContents(): string;
13
+ /**
14
+ * Full contents for a **workspace** `.yarnrc.yml` (§3.2): the brokered scope
15
+ * points at the proxy with the `${Z2H_NPM_TOKEN}` placeholder + always-auth;
16
+ * the default `npmRegistryServer` stays the public registry (direct, unchanged
17
+ * speed). `yarnPath` keeps the bundled Berry release so any `yarn` runs 4.x.
18
+ */
19
+ export declare function workspaceYarnrcContents(): string;
20
+ //# sourceMappingURL=broker-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker-config.d.ts","sourceRoot":"","sources":["../../../src/util/npm/broker-config.ts"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAK3C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAiBhD"}
@@ -0,0 +1,63 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const constants = require('../../constants.js');
4
+
5
+ /** `https://host/path/` (with trailing slash) for the registry= line. */
6
+ function registryUrlWithSlash() {
7
+ const url = constants.brokerNpmRegistryUrl();
8
+ return url.endsWith('/') ? url : `${url}/`;
9
+ }
10
+ /**
11
+ * The `//host/path/` prefix (scheme stripped, trailing slash kept) that npm
12
+ * requires the `:_authToken` key to be keyed under so it aligns with the
13
+ * registry path. Derived from the same registry URL so staging overrides flow
14
+ * through.
15
+ */
16
+ function authKeyPrefix() {
17
+ return registryUrlWithSlash().replace(/^https?:/, '');
18
+ }
19
+ /**
20
+ * The two npm config lines (§3.1 / §3.3) that route the brokered scope to the
21
+ * proxy and supply the `${Z2H_NPM_TOKEN}` placeholder. No literal token — npm
22
+ * interpolates the placeholder from the env at invocation time.
23
+ */
24
+ function brokerNpmrcLines() {
25
+ return [
26
+ `${constants.BROKER_NPM_SCOPE}:registry=${registryUrlWithSlash()}`,
27
+ `${authKeyPrefix()}:_authToken=\${${constants.Z2H_NPM_TOKEN_ENV}}`,
28
+ ];
29
+ }
30
+ /**
31
+ * Full contents for a **workspace** `.npmrc` (§3.3): broker scope-split plus an
32
+ * explicit public default registry and always-auth. Used by the template and
33
+ * the migration so both stay byte-identical.
34
+ */
35
+ function workspaceNpmrcContents() {
36
+ return [...brokerNpmrcLines(), `registry=${constants.PUBLIC_NPM_REGISTRY_URL}`, 'always-auth=true'].join('\n') + '\n';
37
+ }
38
+ /**
39
+ * Full contents for a **workspace** `.yarnrc.yml` (§3.2): the brokered scope
40
+ * points at the proxy with the `${Z2H_NPM_TOKEN}` placeholder + always-auth;
41
+ * the default `npmRegistryServer` stays the public registry (direct, unchanged
42
+ * speed). `yarnPath` keeps the bundled Berry release so any `yarn` runs 4.x.
43
+ */
44
+ function workspaceYarnrcContents() {
45
+ const scopeKey = constants.BROKER_NPM_SCOPE.replace(/^@/, '');
46
+ return ([
47
+ 'nodeLinker: node-modules',
48
+ '',
49
+ 'npmScopes:',
50
+ ` ${scopeKey}:`,
51
+ ` npmRegistryServer: "${constants.brokerNpmRegistryUrl()}"`,
52
+ ` npmAuthToken: "\${${constants.Z2H_NPM_TOKEN_ENV}}"`,
53
+ ' npmAlwaysAuth: true',
54
+ '',
55
+ `npmRegistryServer: "${constants.PUBLIC_NPM_REGISTRY_URL}"`,
56
+ '',
57
+ 'yarnPath: .yarn/releases/yarn-4.5.1.cjs',
58
+ ].join('\n') + '\n');
59
+ }
60
+
61
+ exports.brokerNpmrcLines = brokerNpmrcLines;
62
+ exports.workspaceNpmrcContents = workspaceNpmrcContents;
63
+ exports.workspaceYarnrcContents = workspaceYarnrcContents;