@mondaydotcomorg/z2h-cli 0.17.0 → 0.18.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.
@@ -66,14 +66,14 @@ async function deployPreview({ paths, consumerName, appName, token, opts }) {
66
66
  const previewId = opts.previewId ?? crypto.randomUUID().slice(0, 8);
67
67
  const previewSlug = util_appName.buildPreviewSlug(consumerName, previewId);
68
68
  const previewAppName = util_appName.mfAppName(previewSlug);
69
- const keyPrefix = `${constants.S3_PREVIEWS_FOLDER}/${appName}/${previewId}/MF`;
69
+ const keyPrefix = `${constants.S3_PREVIEWS_FOLDER}/${previewAppName}/MF`;
70
70
  // Full CDN URL, not a relative path — trident-skeleton uses a manifest
71
71
  // entry's `url` verbatim as the asset base, never joined with its own mfUrl.
72
72
  const url = `${constants.BUCKET_READ_DNS_URL}/${keyPrefix}`;
73
73
  const nextVersion = (await util_auth_brokerCredentialProvider.fetchDeployVersion(previewAppName)) + 1;
74
74
  util_logger.info('building');
75
75
  const entry = await buildAndStamp({ paths, publicUrl: url, nextVersion, gitRemote: '' });
76
- const creds = await util_auth_brokerCredentialProvider.brokerCredentialProvider({ appName, previewId })();
76
+ const creds = await util_auth_brokerCredentialProvider.brokerCredentialProvider({ appName: previewAppName, previewId })();
77
77
  util_s3_client.setupS3Client(creds);
78
78
  util_logger.info(`uploading preview build → s3://${constants.BUCKET_WRITE_NAME}/${keyPrefix}/`);
79
79
  await util_s3_upload.uploadDir(paths.shadowBuild, keyPrefix);
@@ -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,CAEjD,CAAC;AAKF,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;AAQ3C,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;AAIjF,eAAO,MAAM,kBAAkB,aAAa,CAAC;AAK7C,eAAO,MAAM,YAAY,cAAc,CAAC;AACxC,eAAO,MAAM,iBAAiB,yDAA2C,CAAC;AAM1E,eAAO,MAAM,gBAAgB,QAA2B,CAAC;AAEzD,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAKtD,eAAO,MAAM,uBAAuB,qCAAqC,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAID,wBAAgB,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGvD;AAKD,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAG9C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AAMrE,eAAO,MAAM,iBAAiB,EAAG,eAAwB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
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,CAEjD,CAAC;AAKF,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;AAQ3C,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,kBAAkB,aAAa,CAAC;AAK7C,eAAO,MAAM,YAAY,cAAc,CAAC;AACxC,eAAO,MAAM,iBAAiB,yDAA2C,CAAC;AAM1E,eAAO,MAAM,gBAAgB,QAA2B,CAAC;AAEzD,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAKtD,eAAO,MAAM,uBAAuB,qCAAqC,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAID,wBAAgB,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGvD;AAKD,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAG9C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AAMrE,eAAO,MAAM,iBAAiB,EAAG,eAAwB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
package/dist/constants.js CHANGED
@@ -34,7 +34,8 @@ const REGION = 'us-east-1';
34
34
  const BUCKET_WRITE_URL = `https://${BUCKET_WRITE_NAME}.s3.${REGION}.amazonaws.com`;
35
35
  const BUCKET_READ_DNS_NAME = 'bigbrain-zth-mf-assets';
36
36
  const BUCKET_READ_DNS_URL = `https://${BUCKET_READ_DNS_NAME}.bigbrain.me`;
37
- // Root prefix for ephemeral preview uploads: `previews/<appName>/<previewId>/MF/...`.
37
+ // Root prefix for ephemeral preview uploads: `previews/<previewAppName>/MF/...`,
38
+ // where previewAppName is the preview's own `mf-zth-preview-<id>-<app>` name.
38
39
  // Shared by the CLI (upload path) and bigbrain-zth (STS policy + manifest overlay).
39
40
  const S3_PREVIEWS_FOLDER = 'previews';
40
41
  // No `.json` extension — TridentSkeleton's `mfUrl` API appends `/mf-assets`
@@ -60,14 +60,14 @@ async function deployPreview({ paths, consumerName, appName, token, opts }) {
60
60
  const previewId = opts.previewId ?? randomUUID().slice(0, 8);
61
61
  const previewSlug = buildPreviewSlug(consumerName, previewId);
62
62
  const previewAppName = mfAppName(previewSlug);
63
- const keyPrefix = `${S3_PREVIEWS_FOLDER}/${appName}/${previewId}/MF`;
63
+ const keyPrefix = `${S3_PREVIEWS_FOLDER}/${previewAppName}/MF`;
64
64
  // Full CDN URL, not a relative path — trident-skeleton uses a manifest
65
65
  // entry's `url` verbatim as the asset base, never joined with its own mfUrl.
66
66
  const url = `${BUCKET_READ_DNS_URL}/${keyPrefix}`;
67
67
  const nextVersion = (await fetchDeployVersion(previewAppName)) + 1;
68
68
  info('building');
69
69
  const entry = await buildAndStamp({ paths, publicUrl: url, nextVersion, gitRemote: '' });
70
- const creds = await brokerCredentialProvider({ appName, previewId })();
70
+ const creds = await brokerCredentialProvider({ appName: previewAppName, previewId })();
71
71
  setupS3Client(creds);
72
72
  info(`uploading preview build → s3://${BUCKET_WRITE_NAME}/${keyPrefix}/`);
73
73
  await uploadDir(paths.shadowBuild, keyPrefix);
@@ -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,CAEjD,CAAC;AAKF,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;AAQ3C,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;AAIjF,eAAO,MAAM,kBAAkB,aAAa,CAAC;AAK7C,eAAO,MAAM,YAAY,cAAc,CAAC;AACxC,eAAO,MAAM,iBAAiB,yDAA2C,CAAC;AAM1E,eAAO,MAAM,gBAAgB,QAA2B,CAAC;AAEzD,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAKtD,eAAO,MAAM,uBAAuB,qCAAqC,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAID,wBAAgB,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGvD;AAKD,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAG9C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AAMrE,eAAO,MAAM,iBAAiB,EAAG,eAAwB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
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,CAEjD,CAAC;AAKF,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;AAQ3C,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,kBAAkB,aAAa,CAAC;AAK7C,eAAO,MAAM,YAAY,cAAc,CAAC;AACxC,eAAO,MAAM,iBAAiB,yDAA2C,CAAC;AAM1E,eAAO,MAAM,gBAAgB,QAA2B,CAAC;AAEzD,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAKtD,eAAO,MAAM,uBAAuB,qCAAqC,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAID,wBAAgB,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGvD;AAKD,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAG9C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AAMrE,eAAO,MAAM,iBAAiB,EAAG,eAAwB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
@@ -32,7 +32,8 @@ const REGION = 'us-east-1';
32
32
  const BUCKET_WRITE_URL = `https://${BUCKET_WRITE_NAME}.s3.${REGION}.amazonaws.com`;
33
33
  const BUCKET_READ_DNS_NAME = 'bigbrain-zth-mf-assets';
34
34
  const BUCKET_READ_DNS_URL = `https://${BUCKET_READ_DNS_NAME}.bigbrain.me`;
35
- // Root prefix for ephemeral preview uploads: `previews/<appName>/<previewId>/MF/...`.
35
+ // Root prefix for ephemeral preview uploads: `previews/<previewAppName>/MF/...`,
36
+ // where previewAppName is the preview's own `mf-zth-preview-<id>-<app>` name.
36
37
  // Shared by the CLI (upload path) and bigbrain-zth (STS policy + manifest overlay).
37
38
  const S3_PREVIEWS_FOLDER = 'previews';
38
39
  // No `.json` extension — TridentSkeleton's `mfUrl` API appends `/mf-assets`
@@ -10,9 +10,10 @@ export declare function fetchDeployVersion(appName: string): Promise<number>;
10
10
  /**
11
11
  * AWS SDK credential provider that fetches short-lived credentials from the
12
12
  * bigbrain-zth STS broker, scoped to `appName` — or, when `previewId` is
13
- * given, to a single `previews/<appName>/<previewId>/*` slot instead of the
14
- * full deploy path. Credentials are cached in memory until 5 minutes before
15
- * expiry; concurrent calls share a single in-flight fetch.
13
+ * given, to a single `previews/<appName>/*` slot instead of the full deploy
14
+ * path (`appName` being the preview's own app name, which already embeds the
15
+ * id). Credentials are cached in memory until 5 minutes before expiry;
16
+ * concurrent calls share a single in-flight fetch.
16
17
  */
17
18
  export declare function brokerCredentialProvider({ appName, previewId, }: {
18
19
  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;AAC1D,eAAO,MAAM,mBAAmB,0BAA0B,CAAC;AA4C3D;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUzE;AA4DD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,SAAS,GACV,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,6BAA6B,CAIhC"}
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;AA4DD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,SAAS,GACV,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,6BAA6B,CAIhC"}
@@ -96,9 +96,10 @@ function createCachedCredentialProvider(fetchOnce) {
96
96
  /**
97
97
  * AWS SDK credential provider that fetches short-lived credentials from the
98
98
  * bigbrain-zth STS broker, scoped to `appName` — or, when `previewId` is
99
- * given, to a single `previews/<appName>/<previewId>/*` slot instead of the
100
- * full deploy path. Credentials are cached in memory until 5 minutes before
101
- * expiry; concurrent calls share a single in-flight fetch.
99
+ * given, to a single `previews/<appName>/*` slot instead of the full deploy
100
+ * path (`appName` being the preview's own app name, which already embeds the
101
+ * id). Credentials are cached in memory until 5 minutes before expiry;
102
+ * concurrent calls share a single in-flight fetch.
102
103
  */
103
104
  function brokerCredentialProvider({ appName, previewId, }) {
104
105
  return createCachedCredentialProvider(() => requestSts(STS_BROKER_PATH, { appName, previewId }, previewId ? 'preview' : 'deploy'));
@@ -10,9 +10,10 @@ export declare function fetchDeployVersion(appName: string): Promise<number>;
10
10
  /**
11
11
  * AWS SDK credential provider that fetches short-lived credentials from the
12
12
  * bigbrain-zth STS broker, scoped to `appName` — or, when `previewId` is
13
- * given, to a single `previews/<appName>/<previewId>/*` slot instead of the
14
- * full deploy path. Credentials are cached in memory until 5 minutes before
15
- * expiry; concurrent calls share a single in-flight fetch.
13
+ * given, to a single `previews/<appName>/*` slot instead of the full deploy
14
+ * path (`appName` being the preview's own app name, which already embeds the
15
+ * id). Credentials are cached in memory until 5 minutes before expiry;
16
+ * concurrent calls share a single in-flight fetch.
16
17
  */
17
18
  export declare function brokerCredentialProvider({ appName, previewId, }: {
18
19
  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;AAC1D,eAAO,MAAM,mBAAmB,0BAA0B,CAAC;AA4C3D;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUzE;AA4DD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,SAAS,GACV,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,6BAA6B,CAIhC"}
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;AA4DD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,OAAO,EACP,SAAS,GACV,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,6BAA6B,CAIhC"}
@@ -98,9 +98,10 @@ function createCachedCredentialProvider(fetchOnce) {
98
98
  /**
99
99
  * AWS SDK credential provider that fetches short-lived credentials from the
100
100
  * bigbrain-zth STS broker, scoped to `appName` — or, when `previewId` is
101
- * given, to a single `previews/<appName>/<previewId>/*` slot instead of the
102
- * full deploy path. Credentials are cached in memory until 5 minutes before
103
- * expiry; concurrent calls share a single in-flight fetch.
101
+ * given, to a single `previews/<appName>/*` slot instead of the full deploy
102
+ * path (`appName` being the preview's own app name, which already embeds the
103
+ * id). Credentials are cached in memory until 5 minutes before expiry;
104
+ * concurrent calls share a single in-flight fetch.
104
105
  */
105
106
  function brokerCredentialProvider({ appName, previewId, }) {
106
107
  return createCachedCredentialProvider(() => requestSts(STS_BROKER_PATH, { appName, previewId }, previewId ? 'preview' : 'deploy'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mondaydotcomorg/z2h-cli",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "bin": "./bin/z2h-cli.js",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -104,15 +104,18 @@ describe('deploy --preview', () => {
104
104
  await expect(deployCommand({ preview: true })).rejects.toThrow(/must have a "name" field/);
105
105
  });
106
106
 
107
- it('mints a fresh previewId and uploads to previews/<mfApp>/<id>/MF', async () => {
107
+ it('mints a fresh previewId and uploads to previews/<previewApp>/MF', async () => {
108
108
  await deployCommand({ preview: true });
109
109
 
110
110
  expect(brokerProvider.brokerCredentialProvider).toHaveBeenCalledTimes(1);
111
111
  const call = vi.mocked(brokerProvider.brokerCredentialProvider).mock.calls[0][0];
112
- expect(call.appName).toBe('mf-my-app');
113
112
  expect(call.previewId).toMatch(/^[0-9a-f]{8}$/);
114
113
 
115
- expect(uploadDir).toHaveBeenCalledWith(path.join(tmp, '.zth', 'build'), `previews/mf-my-app/${call.previewId}/MF`);
114
+ const previewAppName = `mf-${buildPreviewSlug('my-app', call.previewId as string)}`;
115
+ // Credentials are scoped to the folder the upload actually writes, so the
116
+ // broker is asked for the preview's own name rather than the real app's.
117
+ expect(call.appName).toBe(previewAppName);
118
+ expect(uploadDir).toHaveBeenCalledWith(path.join(tmp, '.zth', 'build'), `previews/${previewAppName}/MF`);
116
119
  });
117
120
 
118
121
  it('calls registerOrUpdateApp for a brand-new preview at version 1 with an empty gitRemote', async () => {
@@ -140,13 +143,11 @@ describe('deploy --preview', () => {
140
143
  const call = vi.mocked(brokerProvider.brokerCredentialProvider).mock.calls[0][0];
141
144
  expect(call.previewId).toBe('existing-preview-id');
142
145
 
143
- expect(uploadDir).toHaveBeenCalledWith(
144
- path.join(tmp, '.zth', 'build'),
145
- 'previews/mf-my-app/existing-preview-id/MF'
146
- );
147
-
148
146
  const previewSlug = buildPreviewSlug('my-app', 'existing-preview-id');
149
147
  const previewAppName = `mf-${previewSlug}`;
148
+
149
+ expect(uploadDir).toHaveBeenCalledWith(path.join(tmp, '.zth', 'build'), `previews/${previewAppName}/MF`);
150
+
150
151
  expect(brokerApp.registerOrUpdateApp).toHaveBeenCalledWith({
151
152
  appName: previewAppName,
152
153
  token: 'jwt-stub',
@@ -159,9 +160,10 @@ describe('deploy --preview', () => {
159
160
  it('passes a full CDN URL (not a relative path) as publicUrl to the build', async () => {
160
161
  await deployCommand({ preview: true, previewId: 'existing-preview-id' });
161
162
 
163
+ const previewAppName = `mf-${buildPreviewSlug('my-app', 'existing-preview-id')}`;
162
164
  expect(buildCommand).toHaveBeenCalledWith(
163
165
  expect.objectContaining({
164
- publicUrl: 'https://bigbrain-zth-mf-assets.bigbrain.me/previews/mf-my-app/existing-preview-id/MF',
166
+ publicUrl: `https://bigbrain-zth-mf-assets.bigbrain.me/previews/${previewAppName}/MF`,
165
167
  })
166
168
  );
167
169
  });
@@ -98,7 +98,7 @@ async function deployPreview({ paths, consumerName, appName, token, opts }: Depl
98
98
  const previewId = opts.previewId ?? randomUUID().slice(0, 8);
99
99
  const previewSlug = buildPreviewSlug(consumerName, previewId);
100
100
  const previewAppName = mfAppName(previewSlug);
101
- const keyPrefix = `${S3_PREVIEWS_FOLDER}/${appName}/${previewId}/MF`;
101
+ const keyPrefix = `${S3_PREVIEWS_FOLDER}/${previewAppName}/MF`;
102
102
  // Full CDN URL, not a relative path — trident-skeleton uses a manifest
103
103
  // entry's `url` verbatim as the asset base, never joined with its own mfUrl.
104
104
  const url = `${BUCKET_READ_DNS_URL}/${keyPrefix}`;
@@ -108,7 +108,7 @@ async function deployPreview({ paths, consumerName, appName, token, opts }: Depl
108
108
  info('building');
109
109
  const entry = await buildAndStamp({ paths, publicUrl: url, nextVersion, gitRemote: '' });
110
110
 
111
- const creds = await brokerCredentialProvider({ appName, previewId })();
111
+ const creds = await brokerCredentialProvider({ appName: previewAppName, previewId })();
112
112
  setupS3Client(creds);
113
113
 
114
114
  info(`uploading preview build → s3://${BUCKET_WRITE_NAME}/${keyPrefix}/`);
package/src/constants.ts CHANGED
@@ -41,7 +41,8 @@ export const BUCKET_WRITE_URL = `https://${BUCKET_WRITE_NAME}.s3.${REGION}.amazo
41
41
  export const BUCKET_READ_DNS_NAME = 'bigbrain-zth-mf-assets';
42
42
  export const BUCKET_READ_DNS_URL = `https://${BUCKET_READ_DNS_NAME}.bigbrain.me`;
43
43
 
44
- // Root prefix for ephemeral preview uploads: `previews/<appName>/<previewId>/MF/...`.
44
+ // Root prefix for ephemeral preview uploads: `previews/<previewAppName>/MF/...`,
45
+ // where previewAppName is the preview's own `mf-zth-preview-<id>-<app>` name.
45
46
  // Shared by the CLI (upload path) and bigbrain-zth (STS policy + manifest overlay).
46
47
  export const S3_PREVIEWS_FOLDER = 'previews';
47
48
 
@@ -125,9 +125,10 @@ function createCachedCredentialProvider(
125
125
  /**
126
126
  * AWS SDK credential provider that fetches short-lived credentials from the
127
127
  * bigbrain-zth STS broker, scoped to `appName` — or, when `previewId` is
128
- * given, to a single `previews/<appName>/<previewId>/*` slot instead of the
129
- * full deploy path. Credentials are cached in memory until 5 minutes before
130
- * expiry; concurrent calls share a single in-flight fetch.
128
+ * given, to a single `previews/<appName>/*` slot instead of the full deploy
129
+ * path (`appName` being the preview's own app name, which already embeds the
130
+ * id). Credentials are cached in memory until 5 minutes before expiry;
131
+ * concurrent calls share a single in-flight fetch.
131
132
  */
132
133
  export function brokerCredentialProvider({
133
134
  appName,