@mondaydotcomorg/z2h-cli 0.10.1 → 0.11.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 (104) hide show
  1. package/dist/commands/__tests__/edit.test.d.ts +2 -0
  2. package/dist/commands/__tests__/edit.test.d.ts.map +1 -0
  3. package/dist/commands/create.d.ts +2 -2
  4. package/dist/commands/create.d.ts.map +1 -1
  5. package/dist/commands/create.js +14 -34
  6. package/dist/commands/deploy.d.ts +3 -0
  7. package/dist/commands/deploy.d.ts.map +1 -1
  8. package/dist/commands/deploy.js +120 -21
  9. package/dist/commands/edit.d.ts +5 -0
  10. package/dist/commands/edit.d.ts.map +1 -0
  11. package/dist/commands/edit.js +61 -0
  12. package/dist/commands/grant.d.ts +12 -0
  13. package/dist/commands/grant.d.ts.map +1 -0
  14. package/dist/commands/grant.js +94 -0
  15. package/dist/constants.d.ts +1 -0
  16. package/dist/constants.d.ts.map +1 -1
  17. package/dist/constants.js +7 -0
  18. package/dist/esm/commands/__tests__/edit.test.d.ts +2 -0
  19. package/dist/esm/commands/__tests__/edit.test.d.ts.map +1 -0
  20. package/dist/esm/commands/create.d.ts +2 -2
  21. package/dist/esm/commands/create.d.ts.map +1 -1
  22. package/dist/esm/commands/create.mjs +16 -35
  23. package/dist/esm/commands/deploy.d.ts +3 -0
  24. package/dist/esm/commands/deploy.d.ts.map +1 -1
  25. package/dist/esm/commands/deploy.mjs +122 -23
  26. package/dist/esm/commands/edit.d.ts +5 -0
  27. package/dist/esm/commands/edit.d.ts.map +1 -0
  28. package/dist/esm/commands/edit.mjs +55 -0
  29. package/dist/esm/commands/grant.d.ts +12 -0
  30. package/dist/esm/commands/grant.d.ts.map +1 -0
  31. package/dist/esm/commands/grant.mjs +90 -0
  32. package/dist/esm/constants.d.ts +1 -0
  33. package/dist/esm/constants.d.ts.map +1 -1
  34. package/dist/esm/constants.mjs +7 -1
  35. package/dist/esm/index.mjs +67 -10
  36. package/dist/esm/shadow/prepare.d.ts +1 -1
  37. package/dist/esm/shadow/prepare.d.ts.map +1 -1
  38. package/dist/esm/shadow/prepare.mjs +2 -2
  39. package/dist/esm/util/app-name.d.ts +1 -0
  40. package/dist/esm/util/app-name.d.ts.map +1 -1
  41. package/dist/esm/util/app-name.mjs +11 -1
  42. package/dist/esm/util/auth/broker-credential-provider.d.ts +10 -2
  43. package/dist/esm/util/auth/broker-credential-provider.d.ts.map +1 -1
  44. package/dist/esm/util/auth/broker-credential-provider.mjs +35 -13
  45. package/dist/esm/util/broker/app.d.ts +14 -0
  46. package/dist/esm/util/broker/app.d.ts.map +1 -0
  47. package/dist/esm/util/broker/app.mjs +27 -0
  48. package/dist/esm/util/git/git-env.d.ts +9 -0
  49. package/dist/esm/util/git/git-env.d.ts.map +1 -0
  50. package/dist/esm/util/git/git-env.mjs +22 -0
  51. package/dist/esm/util/git/remote-options.d.ts +17 -0
  52. package/dist/esm/util/git/remote-options.d.ts.map +1 -0
  53. package/dist/esm/util/git/remote-options.mjs +30 -0
  54. package/dist/esm/util/git/repo.d.ts +21 -3
  55. package/dist/esm/util/git/repo.d.ts.map +1 -1
  56. package/dist/esm/util/git/repo.mjs +96 -48
  57. package/dist/esm/util/s3/client.d.ts +2 -7
  58. package/dist/esm/util/s3/client.d.ts.map +1 -1
  59. package/dist/esm/util/s3/client.mjs +3 -11
  60. package/dist/index.js +69 -12
  61. package/dist/shadow/prepare.d.ts +1 -1
  62. package/dist/shadow/prepare.d.ts.map +1 -1
  63. package/dist/shadow/prepare.js +2 -2
  64. package/dist/util/app-name.d.ts +1 -0
  65. package/dist/util/app-name.d.ts.map +1 -1
  66. package/dist/util/app-name.js +11 -0
  67. package/dist/util/auth/broker-credential-provider.d.ts +10 -2
  68. package/dist/util/auth/broker-credential-provider.d.ts.map +1 -1
  69. package/dist/util/auth/broker-credential-provider.js +35 -11
  70. package/dist/util/broker/app.d.ts +14 -0
  71. package/dist/util/broker/app.d.ts.map +1 -0
  72. package/dist/util/broker/app.js +29 -0
  73. package/dist/util/git/git-env.d.ts +9 -0
  74. package/dist/util/git/git-env.d.ts.map +1 -0
  75. package/dist/util/git/git-env.js +24 -0
  76. package/dist/util/git/remote-options.d.ts +17 -0
  77. package/dist/util/git/remote-options.d.ts.map +1 -0
  78. package/dist/util/git/remote-options.js +34 -0
  79. package/dist/util/git/repo.d.ts +21 -3
  80. package/dist/util/git/repo.d.ts.map +1 -1
  81. package/dist/util/git/repo.js +97 -48
  82. package/dist/util/s3/client.d.ts +2 -7
  83. package/dist/util/s3/client.d.ts.map +1 -1
  84. package/dist/util/s3/client.js +3 -11
  85. package/package.json +1 -1
  86. package/src/commands/__tests__/create.test.ts +9 -7
  87. package/src/commands/__tests__/edit.test.ts +184 -0
  88. package/src/commands/create.ts +15 -33
  89. package/src/commands/deploy.ts +145 -31
  90. package/src/commands/edit.ts +63 -0
  91. package/src/commands/grant.ts +115 -0
  92. package/src/constants.ts +7 -0
  93. package/src/index.ts +83 -13
  94. package/src/shadow/prepare.ts +2 -2
  95. package/src/templates/app/CLAUDE.md +15 -0
  96. package/src/util/app-name.ts +10 -0
  97. package/src/util/auth/__tests__/broker-credential-provider.test.ts +34 -2
  98. package/src/util/auth/broker-credential-provider.ts +43 -15
  99. package/src/util/broker/app.ts +34 -0
  100. package/src/util/git/__tests__/repo.test.ts +114 -90
  101. package/src/util/git/git-env.ts +23 -0
  102. package/src/util/git/remote-options.ts +37 -0
  103. package/src/util/git/repo.ts +109 -48
  104. package/src/util/s3/client.ts +4 -11
@@ -1,19 +1,22 @@
1
1
  import { createRequire } from 'node:module';
2
- import { readFileSync } from 'node:fs';
3
2
  import os from 'node:os';
4
3
  import path from 'node:path';
5
4
  import { Command } from 'commander';
6
5
  import { execa } from 'execa';
6
+ import { getWorkspaceHome } from './util/workspace.mjs';
7
7
  import { devCommand } from './commands/dev.mjs';
8
8
  import { buildCommand } from './commands/build.mjs';
9
9
  import { cleanCommand } from './commands/clean.mjs';
10
10
  import { deployCommand } from './commands/deploy.mjs';
11
+ import { grantCommand, revokeCommand, transferOwnerCommand } from './commands/grant.mjs';
11
12
  import { createWorkspaceCommand } from './commands/create-workspace.mjs';
12
13
  import { createCommand } from './commands/create.mjs';
13
14
  import { generateZ2HTokenCommand } from './commands/generate-z2h-token.mjs';
14
15
  import { migrateCommand } from './commands/migrate.mjs';
16
+ import { editCommand } from './commands/edit.mjs';
15
17
  import { fail, errorLog, getOutputMode } from './util/logger.mjs';
16
18
  import { trackDuration } from './util/tracker.mjs';
19
+ import { getCwdAppName } from './util/app-name.mjs';
17
20
 
18
21
  const { version } = createRequire(import.meta.url)('../package.json');
19
22
  const UPDATE_SCRIPT = path.join(os.homedir(), 'Development', 'bigbrain-z2h', 'z2h', 'setup', 'update.sh');
@@ -28,15 +31,14 @@ function selfUpdate() {
28
31
  errorLog(`Z2H auto-update failed to start: ${err.message}`);
29
32
  }
30
33
  }
31
- function getCwdAppName() {
32
- try {
33
- return JSON.parse(readFileSync('package.json', 'utf8')).name;
34
- }
35
- catch {
36
- return undefined;
34
+ const CONFLICTING_ENV_VARS = ['AWS_PROFILE'];
35
+ function stripConflictingEnvVars() {
36
+ for (const name of CONFLICTING_ENV_VARS) {
37
+ delete process.env[name];
37
38
  }
38
39
  }
39
40
  async function main() {
41
+ stripConflictingEnvVars();
40
42
  const program = new Command();
41
43
  program
42
44
  .name('z2h-cli')
@@ -91,9 +93,11 @@ async function main() {
91
93
  });
92
94
  program
93
95
  .command('deploy')
94
- .description('Build, upload artifacts to S3, and update the Z2H manifest')
96
+ .description('Build, upload to S3, and register the app with the Z2H backend')
95
97
  .option('--dry-run', 'print what would happen without uploading anything')
96
98
  .option('--json', 'emit structured JSON on stdout')
99
+ .option('--remote <type>', 'First deploy only: source control remote to initialise — s3 (shared storage) or github (your repo). Error if the app already has a git remote.')
100
+ .option('--repo-url <url>', 'First deploy only: GitHub repo URL — required when --remote=github. Error if the app already has a git remote.')
97
101
  .action(async (opts) => {
98
102
  try {
99
103
  await trackDuration('z2h_app_deploy_success', () => deployCommand(opts), {
@@ -106,7 +110,7 @@ async function main() {
106
110
  });
107
111
  program
108
112
  .command('create-workspace')
109
- .description('Bootstrap the ~/zth-projects/ yarn workspace (one-time setup)')
113
+ .description(`Bootstrap the ${getWorkspaceHome()}/ yarn workspace (one-time setup)`)
110
114
  .option('--json', 'emit structured JSON on stdout')
111
115
  .action(async (opts) => {
112
116
  try {
@@ -132,7 +136,7 @@ async function main() {
132
136
  });
133
137
  program
134
138
  .command('create <app-name>')
135
- .description('Scaffold a new Z2H consumer app inside ~/zth-projects/')
139
+ .description(`Scaffold a new Z2H consumer app inside ${getWorkspaceHome()}/`)
136
140
  .option('--template <name>', 'Template name (default | html-embed)')
137
141
  .option('--html-file <path>', 'Path to an HTML file to embed (implies --template html-embed)')
138
142
  .option('--remote <type>', 'Source control remote: s3 (shared storage) or github (your repo)')
@@ -150,6 +154,59 @@ async function main() {
150
154
  await fail(`create failed: ${err.message}`, { command: 'create' }, 1);
151
155
  }
152
156
  });
157
+ program
158
+ .command('edit <app-name>')
159
+ .description(`Pull the latest version of an app into ${getWorkspaceHome()}/<app-name>, cloning it first if needed`)
160
+ .option('--json', 'emit structured JSON on stdout')
161
+ .action(async (appName, opts) => {
162
+ try {
163
+ await trackDuration('z2h_app_edit_pulled', () => editCommand(appName, opts), {
164
+ app_name: appName,
165
+ });
166
+ }
167
+ catch (err) {
168
+ await fail(`edit failed: ${err.message}`, { command: 'edit' }, 1);
169
+ }
170
+ });
171
+ program
172
+ .command('grant [email]')
173
+ .description('Grant access to the current app (email, --public, or both)')
174
+ .option('--public', 'make the app visible to all monday.com employees')
175
+ .option('--level <level>', 'access level for user grants: owner, editor, or viewer (default: viewer)')
176
+ .option('--json', 'emit structured JSON on stdout')
177
+ .action(async (email, opts) => {
178
+ try {
179
+ await grantCommand(email, opts);
180
+ }
181
+ catch (err) {
182
+ await fail(`grant failed: ${err.message}`, { command: 'grant' }, 1);
183
+ }
184
+ });
185
+ program
186
+ .command('revoke [email]')
187
+ .description('Revoke access to the current app (email or --public; owners/admins only)')
188
+ .option('--public', 'remove the public grant, making the app visible to owners/admins only')
189
+ .option('--json', 'emit structured JSON on stdout')
190
+ .action(async (email, opts) => {
191
+ try {
192
+ await revokeCommand(email, opts);
193
+ }
194
+ catch (err) {
195
+ await fail(`revoke failed: ${err.message}`, { command: 'revoke' }, 1);
196
+ }
197
+ });
198
+ program
199
+ .command('transfer-owner [email]')
200
+ .description('Transfer ownership of the current app to another monday.com user')
201
+ .option('--json', 'emit structured JSON on stdout')
202
+ .action(async (email, opts) => {
203
+ try {
204
+ await transferOwnerCommand(email, opts);
205
+ }
206
+ catch (err) {
207
+ await fail(`transfer-owner failed: ${err.message}`, { command: 'transfer-owner' }, 1);
208
+ }
209
+ });
153
210
  program
154
211
  .command('migrate')
155
212
  .description('Run pending workspace migrations')
@@ -1,3 +1,3 @@
1
1
  import type { PreparedShadow } from '../types';
2
- export declare function prepareShadow(): Promise<PreparedShadow>;
2
+ export declare function prepareShadow(consumerDir?: string): Promise<PreparedShadow>;
3
3
  //# sourceMappingURL=prepare.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prepare.d.ts","sourceRoot":"","sources":["../../../src/shadow/prepare.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAA8B,cAAc,EAAkB,MAAM,UAAU,CAAC;AAE3F,wBAAsB,aAAa,IAAI,OAAO,CAAC,cAAc,CAAC,CAgC7D"}
1
+ {"version":3,"file":"prepare.d.ts","sourceRoot":"","sources":["../../../src/shadow/prepare.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAA8B,cAAc,EAAkB,MAAM,UAAU,CAAC;AAE3F,wBAAsB,aAAa,CAAC,WAAW,GAAE,MAAsB,GAAG,OAAO,CAAC,cAAc,CAAC,CAgChG"}
@@ -9,8 +9,8 @@ import { readMetadata, writeMetadata } from './metadata.mjs';
9
9
  import { isPortFree, pickPort } from './port.mjs';
10
10
  import { syncShadow } from './sync.mjs';
11
11
 
12
- async function prepareShadow() {
13
- const paths = resolveConsumerPaths(process.cwd());
12
+ async function prepareShadow(consumerDir = process.cwd()) {
13
+ const paths = resolveConsumerPaths(consumerDir);
14
14
  if (!(await pathExists(paths.consumerPkg))) {
15
15
  throw new Error(`No package.json found in ${paths.consumerDir}`);
16
16
  }
@@ -3,6 +3,7 @@
3
3
  * e.g. `@trident/customer-viewer` → `customer-viewer`, `foo` → `foo`.
4
4
  */
5
5
  export declare function cleanAppName(name: string): string;
6
+ export declare function getCwdAppName(): string | undefined;
6
7
  /**
7
8
  * Canonical MF bundle name: the de-scoped app name with an `mf-` prefix.
8
9
  * This matches the trident convention (shadow pkg is `@trident/mf-<app>`,
@@ -1 +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"}
1
+ {"version":3,"file":"app-name.d.ts","sourceRoot":"","sources":["../../../src/util/app-name.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,aAAa,IAAI,MAAM,GAAG,SAAS,CAMlD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C"}
@@ -1,3 +1,5 @@
1
+ import { readFileSync } from 'node:fs';
2
+
1
3
  /**
2
4
  * Strip any npm scope (`@scope/`) from a package name.
3
5
  * e.g. `@trident/customer-viewer` → `customer-viewer`, `foo` → `foo`.
@@ -5,6 +7,14 @@
5
7
  function cleanAppName(name) {
6
8
  return name.replace(/^@[^/]+\//, '');
7
9
  }
10
+ function getCwdAppName() {
11
+ try {
12
+ return JSON.parse(readFileSync('package.json', 'utf8')).name;
13
+ }
14
+ catch {
15
+ return undefined;
16
+ }
17
+ }
8
18
  /**
9
19
  * Canonical MF bundle name: the de-scoped app name with an `mf-` prefix.
10
20
  * This matches the trident convention (shadow pkg is `@trident/mf-<app>`,
@@ -14,4 +24,4 @@ function mfAppName(name) {
14
24
  return `mf-${cleanAppName(name)}`;
15
25
  }
16
26
 
17
- export { cleanAppName, mfAppName };
27
+ export { cleanAppName, getCwdAppName, mfAppName };
@@ -1,9 +1,17 @@
1
1
  import type { AwsCredentialIdentityProvider } from '@aws-sdk/types';
2
2
  export declare const STS_BROKER_PATH = "/z2h-cli/sts/credentials";
3
+ export declare const DEPLOY_VERSION_PATH = "/z2h-cli/apps/version";
4
+ /**
5
+ * Reserve the version this deploy will write to. Split out of the STS
6
+ * credentials call so version derivation lives on its own endpoint — the CLI
7
+ * asks for the version first, then requests credentials scoped to it.
8
+ */
9
+ export declare function fetchDeployVersion(appName: string): Promise<number>;
3
10
  /**
4
11
  * AWS SDK credential provider that fetches short-lived deploy credentials
5
- * from the bigbrain-zth STS broker. Credentials are cached in memory until
6
- * 5 minutes before expiry; concurrent calls share a single in-flight fetch.
12
+ * from the bigbrain-zth STS broker for a specific version. Credentials are
13
+ * cached in memory until 5 minutes before expiry; concurrent calls share a
14
+ * single in-flight fetch.
7
15
  */
8
16
  export declare function brokerCredentialProvider({ appName }: {
9
17
  appName: string;
@@ -1 +1 @@
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
+ {"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;AAC1D,eAAO,MAAM,mBAAmB,0BAA0B,CAAC;AA4C3D;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUzE;AAuBD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,6BAA6B,CAuBxG"}
@@ -1,32 +1,53 @@
1
- import { brokerBaseUrl } from '../../constants.mjs';
1
+ import { brokerBaseUrl, routingHeaders } from '../../constants.mjs';
2
2
  import { readZthAuth } from './auth-store.mjs';
3
3
 
4
4
  const STS_BROKER_PATH = '/z2h-cli/sts/credentials';
5
+ const DEPLOY_VERSION_PATH = '/z2h-cli/apps/version';
5
6
  // Refresh the cached credentials this many ms before they expire so the next
6
7
  // AWS API call doesn't race the broker round-trip against a hard expiry.
7
8
  const REFRESH_BUFFER_MS = 5 * 60 * 1000;
8
- async function fetchCredentialsOnce(appName) {
9
+ async function postToBroker(path, body) {
9
10
  const { token } = await readZthAuth();
10
- const url = `${brokerBaseUrl()}${STS_BROKER_PATH}`;
11
- let res;
12
11
  try {
13
- res = await fetch(url, {
12
+ return await fetch(`${brokerBaseUrl()}${path}`, {
14
13
  method: 'POST',
15
14
  headers: {
16
15
  Authorization: `Bearer ${token}`,
17
16
  'Content-Type': 'application/json',
18
17
  Accept: 'application/json',
18
+ ...routingHeaders(),
19
19
  },
20
- body: JSON.stringify({ appName }),
20
+ body: JSON.stringify(body),
21
21
  });
22
22
  }
23
23
  catch (err) {
24
24
  const message = err instanceof Error ? err.message : String(err);
25
25
  throw new Error(`Z2H deploy broker request failed: ${message}`);
26
26
  }
27
+ }
28
+ function assertBrokerOk(res) {
27
29
  if (res.status === 401 || res.status === 403) {
28
30
  throw new Error(`Z2H deploy token rejected by the broker (${res.status}). Refresh user token by running 'z2h-cli generate-z2h-token'.`);
29
31
  }
32
+ }
33
+ /**
34
+ * Reserve the version this deploy will write to. Split out of the STS
35
+ * credentials call so version derivation lives on its own endpoint — the CLI
36
+ * asks for the version first, then requests credentials scoped to it.
37
+ */
38
+ async function fetchDeployVersion(appName) {
39
+ const res = await postToBroker(DEPLOY_VERSION_PATH, { appName });
40
+ assertBrokerOk(res);
41
+ if (!res.ok) {
42
+ const text = await res.text();
43
+ throw new Error(`Z2H deploy broker returned ${res.status}: ${text.slice(0, 1024)}`);
44
+ }
45
+ const body = (await res.json());
46
+ return body.version ?? 0;
47
+ }
48
+ async function fetchStsOnce(appName) {
49
+ const res = await postToBroker(STS_BROKER_PATH, { appName });
50
+ assertBrokerOk(res);
30
51
  if (!res.ok) {
31
52
  const text = await res.text();
32
53
  throw new Error(`Z2H deploy broker returned ${res.status}: ${text.slice(0, 1024)}`);
@@ -44,8 +65,9 @@ async function fetchCredentialsOnce(appName) {
44
65
  }
45
66
  /**
46
67
  * AWS SDK credential provider that fetches short-lived deploy credentials
47
- * from the bigbrain-zth STS broker. Credentials are cached in memory until
48
- * 5 minutes before expiry; concurrent calls share a single in-flight fetch.
68
+ * from the bigbrain-zth STS broker for a specific version. Credentials are
69
+ * cached in memory until 5 minutes before expiry; concurrent calls share a
70
+ * single in-flight fetch.
49
71
  */
50
72
  function brokerCredentialProvider({ appName }) {
51
73
  let cached;
@@ -58,10 +80,10 @@ function brokerCredentialProvider({ appName }) {
58
80
  if (inflight) {
59
81
  return inflight;
60
82
  }
61
- inflight = fetchCredentialsOnce(appName)
62
- .then(creds => {
63
- cached = creds;
64
- return creds;
83
+ inflight = fetchStsOnce(appName)
84
+ .then(credentials => {
85
+ cached = credentials;
86
+ return credentials;
65
87
  })
66
88
  .finally(() => {
67
89
  inflight = undefined;
@@ -70,4 +92,4 @@ function brokerCredentialProvider({ appName }) {
70
92
  };
71
93
  }
72
94
 
73
- export { STS_BROKER_PATH, brokerCredentialProvider };
95
+ export { DEPLOY_VERSION_PATH, STS_BROKER_PATH, brokerCredentialProvider, fetchDeployVersion };
@@ -0,0 +1,14 @@
1
+ export interface AppInfo {
2
+ appName: string;
3
+ version: number;
4
+ entry: Record<string, unknown>;
5
+ deployedBy: string;
6
+ gitRemote: string;
7
+ createdBy: string;
8
+ }
9
+ /**
10
+ * Fetches a single app's current state from the broker.
11
+ * Returns null if the app has never been deployed (404).
12
+ */
13
+ export declare function fetchApp(appName: string): Promise<AppInfo | null>;
14
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../../src/util/broker/app.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAiBvE"}
@@ -0,0 +1,27 @@
1
+ import { brokerBaseUrl, routingHeaders } from '../../constants.mjs';
2
+ import { readZthAuth } from '../auth/auth-store.mjs';
3
+
4
+ /**
5
+ * Fetches a single app's current state from the broker.
6
+ * Returns null if the app has never been deployed (404).
7
+ */
8
+ async function fetchApp(appName) {
9
+ const { token } = await readZthAuth();
10
+ const res = await fetch(`${brokerBaseUrl()}/z2h-cli/apps/${encodeURIComponent(appName)}`, {
11
+ headers: {
12
+ Authorization: `Bearer ${token}`,
13
+ Accept: 'application/json',
14
+ ...routingHeaders(),
15
+ },
16
+ });
17
+ if (res.status === 404) {
18
+ return null;
19
+ }
20
+ if (!res.ok) {
21
+ const text = await res.text();
22
+ throw new Error(`Z2H app lookup failed (${res.status}): ${text.slice(0, 512)}`);
23
+ }
24
+ return res.json();
25
+ }
26
+
27
+ export { fetchApp };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Builds the AWS_* environment that `git-remote-s3` needs to talk to an S3-backed
3
+ * git remote, by minting short-lived broker credentials scoped to the app.
4
+ *
5
+ * Returns `undefined` for non-S3 remotes (GitHub apps ride the user's own git
6
+ * credential helper) and when there is no remote at all.
7
+ */
8
+ export declare function resolveGitEnv(appName: string, gitRemote: string | undefined): Promise<Record<string, string> | undefined>;
9
+ //# sourceMappingURL=git-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-env.d.ts","sourceRoot":"","sources":["../../../../src/util/git/git-env.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAU7C"}
@@ -0,0 +1,22 @@
1
+ import { brokerCredentialProvider } from '../auth/broker-credential-provider.mjs';
2
+
3
+ /**
4
+ * Builds the AWS_* environment that `git-remote-s3` needs to talk to an S3-backed
5
+ * git remote, by minting short-lived broker credentials scoped to the app.
6
+ *
7
+ * Returns `undefined` for non-S3 remotes (GitHub apps ride the user's own git
8
+ * credential helper) and when there is no remote at all.
9
+ */
10
+ async function resolveGitEnv(appName, gitRemote) {
11
+ if (!gitRemote?.startsWith('s3://')) {
12
+ return undefined;
13
+ }
14
+ const creds = await brokerCredentialProvider({ appName })();
15
+ return {
16
+ AWS_ACCESS_KEY_ID: creds.accessKeyId,
17
+ AWS_SECRET_ACCESS_KEY: creds.secretAccessKey,
18
+ AWS_SESSION_TOKEN: creds.sessionToken ?? '',
19
+ };
20
+ }
21
+
22
+ export { resolveGitEnv };
@@ -0,0 +1,17 @@
1
+ export declare const REMOTE_TYPES: readonly ["s3", "github"];
2
+ export type RemoteType = (typeof REMOTE_TYPES)[number];
3
+ export interface RemoteOptions {
4
+ remote?: RemoteType;
5
+ repoUrl?: string;
6
+ }
7
+ /**
8
+ * Validates --remote and --repo-url option values.
9
+ * Pass `requireRemote: true` when the flag is mandatory (e.g. create).
10
+ */
11
+ export declare function validateRemoteOptions(opts: RemoteOptions, requireRemote?: boolean): void;
12
+ /**
13
+ * Resolves the git remote URL from --remote / --repo-url options.
14
+ * Call after validateRemoteOptions.
15
+ */
16
+ export declare function resolveRemoteUrl(remote: RemoteType, appName: string, repoUrl?: string): string;
17
+ //# sourceMappingURL=remote-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-options.d.ts","sourceRoot":"","sources":["../../../../src/util/git/remote-options.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,2BAA4B,CAAC;AAEtD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,EAAE,aAAa,UAAQ,GAAG,IAAI,CAatF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9F"}
@@ -0,0 +1,30 @@
1
+ import { defaultS3Remote } from './repo.mjs';
2
+
3
+ const REMOTE_TYPES = ['s3', 'github'];
4
+ /**
5
+ * Validates --remote and --repo-url option values.
6
+ * Pass `requireRemote: true` when the flag is mandatory (e.g. create).
7
+ */
8
+ function validateRemoteOptions(opts, requireRemote = false) {
9
+ if (!opts.remote) {
10
+ if (requireRemote) {
11
+ throw new Error(`--remote is required. Use --remote=s3 (shared storage) or --remote=github (your GitHub repo).`);
12
+ }
13
+ return;
14
+ }
15
+ if (!REMOTE_TYPES.includes(opts.remote)) {
16
+ throw new Error(`Unknown remote "${opts.remote}". Use ${REMOTE_TYPES.join(' or ')}.`);
17
+ }
18
+ if (opts.remote === 'github' && !opts.repoUrl) {
19
+ throw new Error('--repo-url is required when using --remote=github.');
20
+ }
21
+ }
22
+ /**
23
+ * Resolves the git remote URL from --remote / --repo-url options.
24
+ * Call after validateRemoteOptions.
25
+ */
26
+ function resolveRemoteUrl(remote, appName, repoUrl) {
27
+ return remote === 's3' ? defaultS3Remote(appName) : repoUrl;
28
+ }
29
+
30
+ export { REMOTE_TYPES, resolveRemoteUrl, validateRemoteOptions };
@@ -1,13 +1,31 @@
1
1
  export declare class GitConflictError extends Error {
2
2
  constructor(message: string);
3
3
  }
4
+ export interface ConflictInfo {
5
+ localCommits: string[];
6
+ remoteCommits: string[];
7
+ conflictingFiles: string[];
8
+ }
4
9
  export declare function defaultS3Remote(app: string): string;
5
10
  export declare function initRepo(dir: string, remote: string): Promise<void>;
6
11
  export declare function getRemoteUrl(dir: string): Promise<string | undefined>;
7
- export declare function cloneRepo(remote: string, dir: string): Promise<void>;
12
+ /**
13
+ * Throws if the working tree has uncommitted changes. Call only on a known git
14
+ * repo (e.g. guarded by a resolved remote) — a failing `git status` propagates
15
+ * rather than being silently treated as "clean".
16
+ */
17
+ export declare function guardCleanTree(dir: string): Promise<void>;
18
+ export declare function cloneRepo(remote: string, dir: string, env?: Record<string, string>): Promise<void>;
8
19
  export declare function safeBackupIfDirty(dir: string): Promise<void>;
9
- export declare function pullAndResolve(dir: string): Promise<void>;
20
+ export declare function pullAndResolve(dir: string, env?: Record<string, string>): Promise<void>;
21
+ /**
22
+ * Pushes the local master branch to origin. On a rejected (non-fast-forward) push —
23
+ * i.e. a deploy landed while we were building — gathers structured conflict info and
24
+ * throws GitConflictError so the deploy stops before anything goes live (spec: push
25
+ * must stop the deploy before the bundle upload). The skill re-resolves and re-runs,
26
+ * which rebuilds against the latest. Non-conflict push errors re-throw as-is.
27
+ */
28
+ export declare function pushToRemote(dir: string, env?: Record<string, string>): Promise<void>;
10
29
  export declare function remoteHead(dir: string): Promise<string>;
11
30
  export declare function localHead(dir: string): Promise<string>;
12
- export declare function commitDetailedAndPush(dir: string, version: number): Promise<void>;
13
31
  //# sourceMappingURL=repo.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../../../src/util/git/repo.ts"],"names":[],"mappings":"AAMA,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAID,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMzE;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAI3E;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1E;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAclE;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS/D;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO7D;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG5D;AAED,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBvF"}
1
+ {"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../../../src/util/git/repo.ts"],"names":[],"mappings":"AAkBA,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAKD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOzE;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAI3E;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK/D;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5G;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAclE;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAe7F;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB3F;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO7D;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG5D"}