@mondaydotcomorg/z2h-cli 0.2.0 → 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.
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +9 -2
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +19 -24
- package/dist/commands/generate-z2h-token.d.ts +16 -0
- package/dist/commands/generate-z2h-token.d.ts.map +1 -0
- package/dist/commands/generate-z2h-token.js +107 -0
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +28 -0
- package/dist/esm/commands/create.d.ts.map +1 -1
- package/dist/esm/commands/create.mjs +9 -2
- package/dist/esm/commands/deploy.d.ts.map +1 -1
- package/dist/esm/commands/deploy.mjs +16 -21
- package/dist/esm/commands/generate-z2h-token.d.ts +16 -0
- package/dist/esm/commands/generate-z2h-token.d.ts.map +1 -0
- package/dist/esm/commands/generate-z2h-token.mjs +99 -0
- package/dist/esm/constants.d.ts +8 -0
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.mjs +21 -1
- package/dist/esm/index.mjs +15 -0
- package/dist/esm/util/auth/__tests__/auth-store.test.d.ts +2 -0
- package/dist/esm/util/auth/__tests__/auth-store.test.d.ts.map +1 -0
- package/dist/esm/util/auth/__tests__/broker-credential-provider.test.d.ts +2 -0
- package/dist/esm/util/auth/__tests__/broker-credential-provider.test.d.ts.map +1 -0
- package/dist/esm/util/auth/__tests__/loopback-server.test.d.ts +2 -0
- package/dist/esm/util/auth/__tests__/loopback-server.test.d.ts.map +1 -0
- package/dist/esm/util/auth/__tests__/write-auth.test.d.ts +2 -0
- package/dist/esm/util/auth/__tests__/write-auth.test.d.ts.map +1 -0
- package/dist/esm/util/auth/auth-store.d.ts +11 -0
- package/dist/esm/util/auth/auth-store.d.ts.map +1 -0
- package/dist/esm/util/auth/auth-store.mjs +29 -0
- package/dist/esm/util/auth/broker-credential-provider.d.ts +12 -0
- package/dist/esm/util/auth/broker-credential-provider.d.ts.map +1 -0
- package/dist/esm/util/auth/broker-credential-provider.mjs +76 -0
- package/dist/esm/util/auth/loopback-server.d.ts +12 -0
- package/dist/esm/util/auth/loopback-server.d.ts.map +1 -0
- package/dist/esm/util/auth/loopback-server.mjs +87 -0
- package/dist/esm/util/auth/write-auth.d.ts +11 -0
- package/dist/esm/util/auth/write-auth.d.ts.map +1 -0
- package/dist/esm/util/auth/write-auth.mjs +22 -0
- package/dist/esm/util/manifest.d.ts.map +1 -1
- package/dist/esm/util/manifest.mjs +2 -1
- package/dist/esm/util/s3/client.d.ts +7 -8
- package/dist/esm/util/s3/client.d.ts.map +1 -1
- package/dist/esm/util/s3/client.mjs +15 -30
- package/dist/esm/util/s3/upload.d.ts.map +1 -1
- package/dist/esm/util/s3/upload.mjs +2 -1
- package/dist/index.js +15 -0
- package/dist/util/auth/__tests__/auth-store.test.d.ts +2 -0
- package/dist/util/auth/__tests__/auth-store.test.d.ts.map +1 -0
- package/dist/util/auth/__tests__/broker-credential-provider.test.d.ts +2 -0
- package/dist/util/auth/__tests__/broker-credential-provider.test.d.ts.map +1 -0
- package/dist/util/auth/__tests__/loopback-server.test.d.ts +2 -0
- package/dist/util/auth/__tests__/loopback-server.test.d.ts.map +1 -0
- package/dist/util/auth/__tests__/write-auth.test.d.ts +2 -0
- package/dist/util/auth/__tests__/write-auth.test.d.ts.map +1 -0
- package/dist/util/auth/auth-store.d.ts +11 -0
- package/dist/util/auth/auth-store.d.ts.map +1 -0
- package/dist/util/auth/auth-store.js +39 -0
- package/dist/util/auth/broker-credential-provider.d.ts +12 -0
- package/dist/util/auth/broker-credential-provider.d.ts.map +1 -0
- package/dist/util/auth/broker-credential-provider.js +80 -0
- package/dist/util/auth/loopback-server.d.ts +12 -0
- package/dist/util/auth/loopback-server.d.ts.map +1 -0
- package/dist/util/auth/loopback-server.js +94 -0
- package/dist/util/auth/write-auth.d.ts +11 -0
- package/dist/util/auth/write-auth.d.ts.map +1 -0
- package/dist/util/auth/write-auth.js +26 -0
- package/dist/util/manifest.d.ts.map +1 -1
- package/dist/util/manifest.js +5 -4
- package/dist/util/s3/client.d.ts +7 -8
- package/dist/util/s3/client.d.ts.map +1 -1
- package/dist/util/s3/client.js +14 -36
- package/dist/util/s3/upload.d.ts.map +1 -1
- package/dist/util/s3/upload.js +2 -1
- package/package.json +10 -1
- package/src/commands/create.ts +11 -2
- package/src/commands/deploy.ts +18 -31
- package/src/commands/generate-z2h-token.ts +124 -0
- package/src/constants.ts +25 -0
- package/src/index.ts +17 -0
- package/src/util/auth/__tests__/auth-store.test.ts +50 -0
- package/src/util/auth/__tests__/broker-credential-provider.test.ts +115 -0
- package/src/util/auth/__tests__/loopback-server.test.ts +85 -0
- package/src/util/auth/__tests__/write-auth.test.ts +79 -0
- package/src/util/auth/auth-store.ts +31 -0
- package/src/util/auth/broker-credential-provider.ts +93 -0
- package/src/util/auth/loopback-server.ts +103 -0
- package/src/util/auth/write-auth.ts +24 -0
- package/src/util/manifest.ts +2 -1
- package/src/util/s3/client.ts +15 -32
- package/src/util/s3/upload.ts +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broker-credential-provider.test.d.ts","sourceRoot":"","sources":["../../../../../src/util/auth/__tests__/broker-credential-provider.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopback-server.test.d.ts","sourceRoot":"","sources":["../../../../../src/util/auth/__tests__/loopback-server.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-auth.test.d.ts","sourceRoot":"","sources":["../../../../../src/util/auth/__tests__/write-auth.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const Z2H_AUTH_DIR: string;
|
|
2
|
+
export declare const Z2H_AUTH_FILE: string;
|
|
3
|
+
export interface ZthAuth {
|
|
4
|
+
token: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class Z2hAuthMissingError extends Error {
|
|
7
|
+
readonly authFilePath: string;
|
|
8
|
+
constructor(authFilePath: string);
|
|
9
|
+
}
|
|
10
|
+
export declare function readZthAuth(): Promise<ZthAuth>;
|
|
11
|
+
//# sourceMappingURL=auth-store.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { pathExists, readJson } from 'fs-extra';
|
|
4
|
+
|
|
5
|
+
// npm-style convention: per-user config under ~/.zth (mirrors ~/.npmrc, ~/.aws/).
|
|
6
|
+
// Kept out of the workspace dir so accidental `git init` in ~/zth-projects can't
|
|
7
|
+
// stage it.
|
|
8
|
+
const Z2H_AUTH_DIR = path.join(os.homedir(), '.zth');
|
|
9
|
+
const Z2H_AUTH_FILE = path.join(Z2H_AUTH_DIR, 'auth.json');
|
|
10
|
+
class Z2hAuthMissingError extends Error {
|
|
11
|
+
authFilePath;
|
|
12
|
+
constructor(authFilePath) {
|
|
13
|
+
super(`No Z2H deploy token found at ${authFilePath}. Please run 'z2h-cli generate-z2h-token' command.`);
|
|
14
|
+
this.authFilePath = authFilePath;
|
|
15
|
+
this.name = 'Z2hAuthMissingError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function readZthAuth() {
|
|
19
|
+
if (!(await pathExists(Z2H_AUTH_FILE))) {
|
|
20
|
+
throw new Z2hAuthMissingError(Z2H_AUTH_FILE);
|
|
21
|
+
}
|
|
22
|
+
const parsed = (await readJson(Z2H_AUTH_FILE));
|
|
23
|
+
if (!parsed.token) {
|
|
24
|
+
throw new Error(`${Z2H_AUTH_FILE} is missing a "token" string field.`);
|
|
25
|
+
}
|
|
26
|
+
return { token: parsed.token };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { Z2H_AUTH_DIR, Z2H_AUTH_FILE, Z2hAuthMissingError, readZthAuth };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AwsCredentialIdentityProvider } from '@aws-sdk/types';
|
|
2
|
+
export declare const DEFAULT_BROKER_BASE_URL = "https://bigbrain-zth.bigbrain.me";
|
|
3
|
+
export declare const STS_BROKER_PATH = "/z2h-cli/sts/credentials";
|
|
4
|
+
/**
|
|
5
|
+
* AWS SDK credential provider that fetches short-lived deploy credentials
|
|
6
|
+
* from the bigbrain-zth STS broker. Credentials are cached in memory until
|
|
7
|
+
* 5 minutes before expiry; concurrent calls share a single in-flight fetch.
|
|
8
|
+
*/
|
|
9
|
+
export declare function brokerCredentialProvider({ appName }: {
|
|
10
|
+
appName: string;
|
|
11
|
+
}): AwsCredentialIdentityProvider;
|
|
12
|
+
//# sourceMappingURL=broker-credential-provider.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { readZthAuth } from './auth-store.mjs';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_BROKER_BASE_URL = 'https://bigbrain-zth.bigbrain.me';
|
|
4
|
+
const STS_BROKER_PATH = '/z2h-cli/sts/credentials';
|
|
5
|
+
// Refresh the cached credentials this many ms before they expire so the next
|
|
6
|
+
// AWS API call doesn't race the broker round-trip against a hard expiry.
|
|
7
|
+
const REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
8
|
+
function brokerBaseUrl() {
|
|
9
|
+
return process.env.Z2H_BROKER_BASE_URL || DEFAULT_BROKER_BASE_URL;
|
|
10
|
+
}
|
|
11
|
+
async function fetchCredentialsOnce(appName) {
|
|
12
|
+
const { token } = await readZthAuth();
|
|
13
|
+
const url = `${brokerBaseUrl()}${STS_BROKER_PATH}`;
|
|
14
|
+
let res;
|
|
15
|
+
try {
|
|
16
|
+
res = await fetch(url, {
|
|
17
|
+
method: 'POST',
|
|
18
|
+
headers: {
|
|
19
|
+
Authorization: `Bearer ${token}`,
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
Accept: 'application/json',
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({ appName }),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
28
|
+
throw new Error(`Z2H deploy broker request failed: ${message}`);
|
|
29
|
+
}
|
|
30
|
+
if (res.status === 401 || res.status === 403) {
|
|
31
|
+
throw new Error(`Z2H deploy token rejected by the broker (${res.status}). Refresh user token by running 'z2h-cli generate-z2h-token'.`);
|
|
32
|
+
}
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
const text = await res.text();
|
|
35
|
+
throw new Error(`Z2H deploy broker returned ${res.status}: ${text.slice(0, 1024)}`);
|
|
36
|
+
}
|
|
37
|
+
const body = (await res.json());
|
|
38
|
+
if (!body.accessKeyId || !body.secretAccessKey || !body.sessionToken || !body.expiration) {
|
|
39
|
+
throw new Error('Z2H deploy broker response missing required credential fields');
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
accessKeyId: body.accessKeyId,
|
|
43
|
+
secretAccessKey: body.secretAccessKey,
|
|
44
|
+
sessionToken: body.sessionToken,
|
|
45
|
+
expiration: new Date(body.expiration),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* AWS SDK credential provider that fetches short-lived deploy credentials
|
|
50
|
+
* from the bigbrain-zth STS broker. Credentials are cached in memory until
|
|
51
|
+
* 5 minutes before expiry; concurrent calls share a single in-flight fetch.
|
|
52
|
+
*/
|
|
53
|
+
function brokerCredentialProvider({ appName }) {
|
|
54
|
+
let cached;
|
|
55
|
+
let inflight;
|
|
56
|
+
return async () => {
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
if (cached && cached.expiration && cached.expiration.getTime() - now > REFRESH_BUFFER_MS) {
|
|
59
|
+
return cached;
|
|
60
|
+
}
|
|
61
|
+
if (inflight) {
|
|
62
|
+
return inflight;
|
|
63
|
+
}
|
|
64
|
+
inflight = fetchCredentialsOnce(appName)
|
|
65
|
+
.then(creds => {
|
|
66
|
+
cached = creds;
|
|
67
|
+
return creds;
|
|
68
|
+
})
|
|
69
|
+
.finally(() => {
|
|
70
|
+
inflight = undefined;
|
|
71
|
+
});
|
|
72
|
+
return inflight;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { DEFAULT_BROKER_BASE_URL, STS_BROKER_PATH, brokerCredentialProvider };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface LoopbackHandle {
|
|
2
|
+
/** Fully-qualified URL the browser should POST to (e.g. http://127.0.0.1:53811/token). */
|
|
3
|
+
callbackUrl: string;
|
|
4
|
+
/**
|
|
5
|
+
* Resolves with the token once the page POSTs it back. Rejects on timeout
|
|
6
|
+
* or if the server is closed before a token arrives.
|
|
7
|
+
*/
|
|
8
|
+
waitForToken(timeoutMs: number): Promise<string>;
|
|
9
|
+
close(): void;
|
|
10
|
+
}
|
|
11
|
+
export declare function startLoopbackServer(): Promise<LoopbackHandle>;
|
|
12
|
+
//# sourceMappingURL=loopback-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopback-server.d.ts","sourceRoot":"","sources":["../../../../src/util/auth/loopback-server.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,cAAc;IAC7B,0FAA0F;IAC1F,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAAC,cAAc,CAAC,CAkF7D"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import cors from 'cors';
|
|
2
|
+
import express, { json } from 'express';
|
|
3
|
+
|
|
4
|
+
const ALLOWED_ORIGINS = new Set(['https://bigbrain.me', 'https://bigbrainstaging.me']);
|
|
5
|
+
const CALLBACK_PATH = '/token';
|
|
6
|
+
const REQUEST_BODY_LIMIT = '16kb';
|
|
7
|
+
const PREFLIGHT_MAX_AGE_SECONDS = 600;
|
|
8
|
+
function startLoopbackServer() {
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
let resolveToken = null;
|
|
11
|
+
let rejectToken = null;
|
|
12
|
+
const app = express();
|
|
13
|
+
// Reflect the origin if it's one of ours; otherwise wildcard. The
|
|
14
|
+
// endpoint is loopback-bound and single-shot, so the CORS surface is
|
|
15
|
+
// moot — we keep allowlist behavior so the test contract stays exact.
|
|
16
|
+
app.use(cors({
|
|
17
|
+
origin: (origin, cb) => {
|
|
18
|
+
if (origin && ALLOWED_ORIGINS.has(origin)) {
|
|
19
|
+
cb(null, origin);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
cb(null, '*');
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
methods: ['POST', 'OPTIONS'],
|
|
26
|
+
allowedHeaders: ['Content-Type'],
|
|
27
|
+
maxAge: PREFLIGHT_MAX_AGE_SECONDS,
|
|
28
|
+
}));
|
|
29
|
+
app.use(json({ limit: REQUEST_BODY_LIMIT }));
|
|
30
|
+
app.post(CALLBACK_PATH, (req, res) => {
|
|
31
|
+
const body = req.body;
|
|
32
|
+
const token = typeof body?.token === 'string' ? body.token.trim() : '';
|
|
33
|
+
if (!token) {
|
|
34
|
+
res.status(400).json({ error: 'missing token' });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Ack the page so it can transition to "Token sent ✓" and auto-close.
|
|
38
|
+
// The bigbrain.me page never displays this body — it just inspects res.ok.
|
|
39
|
+
res.status(200).json({ ok: true });
|
|
40
|
+
if (resolveToken) {
|
|
41
|
+
const fn = resolveToken;
|
|
42
|
+
resolveToken = null;
|
|
43
|
+
rejectToken = null;
|
|
44
|
+
fn(token);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const server = app.listen(0, '127.0.0.1', () => {
|
|
48
|
+
const address = server.address();
|
|
49
|
+
if (!address || typeof address === 'string') {
|
|
50
|
+
server.close();
|
|
51
|
+
reject(new Error('Failed to determine loopback port'));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
resolve({
|
|
55
|
+
callbackUrl: `http://127.0.0.1:${address.port}${CALLBACK_PATH}`,
|
|
56
|
+
waitForToken(timeoutMs) {
|
|
57
|
+
return new Promise((res, rej) => {
|
|
58
|
+
resolveToken = res;
|
|
59
|
+
rejectToken = rej;
|
|
60
|
+
const timer = setTimeout(() => {
|
|
61
|
+
if (rejectToken) {
|
|
62
|
+
const reject = rejectToken;
|
|
63
|
+
resolveToken = null;
|
|
64
|
+
rejectToken = null;
|
|
65
|
+
reject(new Error('Loopback callback timed out'));
|
|
66
|
+
}
|
|
67
|
+
}, timeoutMs);
|
|
68
|
+
// Don't keep the event loop alive on the timer alone.
|
|
69
|
+
timer.unref?.();
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
close() {
|
|
73
|
+
if (rejectToken) {
|
|
74
|
+
const reject = rejectToken;
|
|
75
|
+
resolveToken = null;
|
|
76
|
+
rejectToken = null;
|
|
77
|
+
reject(new Error('Loopback server closed before token arrived'));
|
|
78
|
+
}
|
|
79
|
+
server.close();
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
server.on('error', reject);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { startLoopbackServer };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ZthAuth } from './auth-store';
|
|
2
|
+
export declare function writeZthAuth(auth: ZthAuth): Promise<{
|
|
3
|
+
filePath: string;
|
|
4
|
+
}>;
|
|
5
|
+
/**
|
|
6
|
+
* Three base64url segments separated by dots — a structural sanity check,
|
|
7
|
+
* not a real verification. Server-side validation happens at the STS broker.
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateJwtPattern(token: string): boolean;
|
|
10
|
+
export { Z2H_AUTH_FILE } from './auth-store';
|
|
11
|
+
//# sourceMappingURL=write-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-auth.d.ts","sourceRoot":"","sources":["../../../../src/util/auth/write-auth.ts"],"names":[],"mappings":"AAEA,OAAO,EAA+B,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAMzE,wBAAsB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAK/E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { chmod } from 'node:fs/promises';
|
|
2
|
+
import { ensureDir, writeFile } from 'fs-extra';
|
|
3
|
+
import { Z2H_AUTH_DIR, Z2H_AUTH_FILE } from './auth-store.mjs';
|
|
4
|
+
|
|
5
|
+
// 0o600 — owner read/write only. The file holds a long-lived bearer token,
|
|
6
|
+
// so other local users on the machine must not be able to read it.
|
|
7
|
+
const OWNER_READ_WRITE_FILE_MODE = 0o600;
|
|
8
|
+
async function writeZthAuth(auth) {
|
|
9
|
+
await ensureDir(Z2H_AUTH_DIR);
|
|
10
|
+
await writeFile(Z2H_AUTH_FILE, `${JSON.stringify(auth, null, 2)}\n`);
|
|
11
|
+
await chmod(Z2H_AUTH_FILE, OWNER_READ_WRITE_FILE_MODE);
|
|
12
|
+
return { filePath: Z2H_AUTH_FILE };
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Three base64url segments separated by dots — a structural sanity check,
|
|
16
|
+
* not a real verification. Server-side validation happens at the STS broker.
|
|
17
|
+
*/
|
|
18
|
+
function validateJwtPattern(token) {
|
|
19
|
+
return /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(token);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { Z2H_AUTH_FILE, validateJwtPattern, writeZthAuth };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/util/manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/util/manifest.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,UAAU,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAClC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAErD,wBAAsB,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,CAQtD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,UAI1D;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,QAAQ,CAE3F;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAWrE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PutObjectCommand } from '@aws-sdk/client-s3';
|
|
2
|
-
import { MANIFEST_READ_URL,
|
|
2
|
+
import { MANIFEST_READ_URL, BUCKET_WRITE_NAME, MANIFEST_KEY } from '../constants.mjs';
|
|
3
|
+
import { getS3Client } from './s3/client.mjs';
|
|
3
4
|
|
|
4
5
|
async function readManifest() {
|
|
5
6
|
// Read via the public CDN endpoint, no AWS auth required.
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { S3Client } from '@aws-sdk/client-s3';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export declare
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Initialize the per-process S3 client with broker-issued credentials scoped
|
|
4
|
+
* to the given app's S3 prefix. Must be called once before any `getS3Client`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function setupS3Client({ appName }: {
|
|
7
|
+
appName: string;
|
|
8
|
+
}): void;
|
|
9
9
|
export declare function getS3Client(): S3Client;
|
|
10
|
-
export declare function assertBucketExists(): Promise<void>;
|
|
11
10
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/util/s3/client.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/util/s3/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAM9C;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKpE;AAED,wBAAgB,WAAW,IAAI,QAAQ,CAKtC"}
|
|
@@ -1,38 +1,23 @@
|
|
|
1
|
-
import { S3Client
|
|
1
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
import { brokerCredentialProvider } from '../auth/broker-credential-provider.mjs';
|
|
3
|
+
import { REGION } from '../../constants.mjs';
|
|
2
4
|
|
|
3
|
-
const BUCKET_WRITE_NAME = 'prod-use1-bigbrain-zth-mf-assets';
|
|
4
|
-
const REGION = 'us-east-1';
|
|
5
|
-
const BUCKET_WRITE_URL = `https://${BUCKET_WRITE_NAME}.s3.${REGION}.amazonaws.com`;
|
|
6
|
-
const BUCKET_READ_DNS_NAME = 'bigbrain-zth-mf-assets';
|
|
7
|
-
const BUCKET_READ_DNS_URL = `https://${BUCKET_READ_DNS_NAME}.bigbrain.me`;
|
|
8
|
-
// No `.json` extension — TridentSkeleton's `mfUrl` API appends `/mf-assets`
|
|
9
|
-
// to the bucket base when fetching, so the manifest must live at this exact
|
|
10
|
-
// key. See microfrontends/mf-bigbrain-zth/.../ZeroToHeroHost.tsx.
|
|
11
|
-
const MANIFEST_KEY = 'mf-assets';
|
|
12
|
-
const MANIFEST_READ_URL = `${BUCKET_READ_DNS_URL}/${MANIFEST_KEY}`;
|
|
13
5
|
let client = null;
|
|
6
|
+
/**
|
|
7
|
+
* Initialize the per-process S3 client with broker-issued credentials scoped
|
|
8
|
+
* to the given app's S3 prefix. Must be called once before any `getS3Client`.
|
|
9
|
+
*/
|
|
10
|
+
function setupS3Client({ appName }) {
|
|
11
|
+
client = new S3Client({
|
|
12
|
+
region: REGION,
|
|
13
|
+
credentials: brokerCredentialProvider({ appName }),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
14
16
|
function getS3Client() {
|
|
15
17
|
if (!client) {
|
|
16
|
-
client
|
|
18
|
+
throw new Error('S3 client not initialized — call setupS3Client({ appName }) first.');
|
|
17
19
|
}
|
|
18
20
|
return client;
|
|
19
21
|
}
|
|
20
|
-
async function assertBucketExists() {
|
|
21
|
-
try {
|
|
22
|
-
await getS3Client().send(new HeadBucketCommand({ Bucket: BUCKET_WRITE_NAME }));
|
|
23
|
-
}
|
|
24
|
-
catch (err) {
|
|
25
|
-
if (err instanceof S3ServiceException) {
|
|
26
|
-
const status = err.$metadata.httpStatusCode;
|
|
27
|
-
if (status === 404 || err.name === 'NotFound' || err.name === 'NoSuchBucket') {
|
|
28
|
-
throw new Error(`S3 bucket "${BUCKET_WRITE_NAME}" does not exist (region: ${REGION}).`);
|
|
29
|
-
}
|
|
30
|
-
if (status === 403) {
|
|
31
|
-
throw new Error(`No access to S3 bucket "${BUCKET_WRITE_NAME}" (region: ${REGION}). Check AWS credentials.`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
throw err;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
22
|
|
|
38
|
-
export {
|
|
23
|
+
export { getS3Client, setupS3Client };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../../src/util/s3/upload.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../../src/util/s3/upload.ts"],"names":[],"mappings":"AAeA,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BtF"}
|
|
@@ -4,7 +4,8 @@ import { readFile } from 'fs-extra';
|
|
|
4
4
|
import { lookup } from 'mime-types';
|
|
5
5
|
import pMap from 'p-map';
|
|
6
6
|
import { PutObjectCommand } from '@aws-sdk/client-s3';
|
|
7
|
-
import {
|
|
7
|
+
import { BUCKET_WRITE_NAME } from '../../constants.mjs';
|
|
8
|
+
import { getS3Client } from './client.mjs';
|
|
8
9
|
|
|
9
10
|
// Each deploy uploads to a version-prefixed path (<app>/<version>/...), so
|
|
10
11
|
// the URL itself is the cache key. Assets never need to be revalidated.
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const commands_clean = require('./commands/clean.js');
|
|
|
5
5
|
const commands_deploy = require('./commands/deploy.js');
|
|
6
6
|
const commands_createWorkspace = require('./commands/create-workspace.js');
|
|
7
7
|
const commands_create = require('./commands/create.js');
|
|
8
|
+
const commands_generateZ2hToken = require('./commands/generate-z2h-token.js');
|
|
8
9
|
const util_logger = require('./util/logger.js');
|
|
9
10
|
|
|
10
11
|
async function main() {
|
|
@@ -88,6 +89,20 @@ async function main() {
|
|
|
88
89
|
util_logger.fail(`create-workspace failed: ${err.message}`, { command: 'create-workspace' }, 1);
|
|
89
90
|
}
|
|
90
91
|
});
|
|
92
|
+
program
|
|
93
|
+
.command('generate-z2h-token')
|
|
94
|
+
.description('Open the bigbrain.me token page, capture the token via a loopback callback, and persist it to ~/.zth/auth.json')
|
|
95
|
+
.option('--no-browser', "don't auto-open the browser; print the URL and prompt for manual paste")
|
|
96
|
+
.option('--url <url>', 'Override the token page URL (e.g. for staging)')
|
|
97
|
+
.option('--json', 'emit structured JSON on stdout')
|
|
98
|
+
.action(async (opts) => {
|
|
99
|
+
try {
|
|
100
|
+
await commands_generateZ2hToken.generateZ2HTokenCommand(opts);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
util_logger.fail(`generate-z2h-token failed: ${err.message}`, { command: 'generate-z2h-token' }, 1);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
91
106
|
program
|
|
92
107
|
.command('create <app-name>')
|
|
93
108
|
.description('Scaffold a new Z2H consumer app inside ~/zth-projects/')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-store.test.d.ts","sourceRoot":"","sources":["../../../../src/util/auth/__tests__/auth-store.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broker-credential-provider.test.d.ts","sourceRoot":"","sources":["../../../../src/util/auth/__tests__/broker-credential-provider.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopback-server.test.d.ts","sourceRoot":"","sources":["../../../../src/util/auth/__tests__/loopback-server.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-auth.test.d.ts","sourceRoot":"","sources":["../../../../src/util/auth/__tests__/write-auth.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const Z2H_AUTH_DIR: string;
|
|
2
|
+
export declare const Z2H_AUTH_FILE: string;
|
|
3
|
+
export interface ZthAuth {
|
|
4
|
+
token: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class Z2hAuthMissingError extends Error {
|
|
7
|
+
readonly authFilePath: string;
|
|
8
|
+
constructor(authFilePath: string);
|
|
9
|
+
}
|
|
10
|
+
export declare function readZthAuth(): Promise<ZthAuth>;
|
|
11
|
+
//# sourceMappingURL=auth-store.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const os = require('node:os');
|
|
5
|
+
const fsExtra = require('fs-extra');
|
|
6
|
+
|
|
7
|
+
const _interopDefault = e => e && e.__esModule ? e : { default: e };
|
|
8
|
+
|
|
9
|
+
const path__default = /*#__PURE__*/_interopDefault(path);
|
|
10
|
+
const os__default = /*#__PURE__*/_interopDefault(os);
|
|
11
|
+
|
|
12
|
+
// npm-style convention: per-user config under ~/.zth (mirrors ~/.npmrc, ~/.aws/).
|
|
13
|
+
// Kept out of the workspace dir so accidental `git init` in ~/zth-projects can't
|
|
14
|
+
// stage it.
|
|
15
|
+
const Z2H_AUTH_DIR = path__default.default.join(os__default.default.homedir(), '.zth');
|
|
16
|
+
const Z2H_AUTH_FILE = path__default.default.join(Z2H_AUTH_DIR, 'auth.json');
|
|
17
|
+
class Z2hAuthMissingError extends Error {
|
|
18
|
+
authFilePath;
|
|
19
|
+
constructor(authFilePath) {
|
|
20
|
+
super(`No Z2H deploy token found at ${authFilePath}. Please run 'z2h-cli generate-z2h-token' command.`);
|
|
21
|
+
this.authFilePath = authFilePath;
|
|
22
|
+
this.name = 'Z2hAuthMissingError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function readZthAuth() {
|
|
26
|
+
if (!(await fsExtra.pathExists(Z2H_AUTH_FILE))) {
|
|
27
|
+
throw new Z2hAuthMissingError(Z2H_AUTH_FILE);
|
|
28
|
+
}
|
|
29
|
+
const parsed = (await fsExtra.readJson(Z2H_AUTH_FILE));
|
|
30
|
+
if (!parsed.token) {
|
|
31
|
+
throw new Error(`${Z2H_AUTH_FILE} is missing a "token" string field.`);
|
|
32
|
+
}
|
|
33
|
+
return { token: parsed.token };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
exports.Z2H_AUTH_DIR = Z2H_AUTH_DIR;
|
|
37
|
+
exports.Z2H_AUTH_FILE = Z2H_AUTH_FILE;
|
|
38
|
+
exports.Z2hAuthMissingError = Z2hAuthMissingError;
|
|
39
|
+
exports.readZthAuth = readZthAuth;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AwsCredentialIdentityProvider } from '@aws-sdk/types';
|
|
2
|
+
export declare const DEFAULT_BROKER_BASE_URL = "https://bigbrain-zth.bigbrain.me";
|
|
3
|
+
export declare const STS_BROKER_PATH = "/z2h-cli/sts/credentials";
|
|
4
|
+
/**
|
|
5
|
+
* AWS SDK credential provider that fetches short-lived deploy credentials
|
|
6
|
+
* from the bigbrain-zth STS broker. Credentials are cached in memory until
|
|
7
|
+
* 5 minutes before expiry; concurrent calls share a single in-flight fetch.
|
|
8
|
+
*/
|
|
9
|
+
export declare function brokerCredentialProvider({ appName }: {
|
|
10
|
+
appName: string;
|
|
11
|
+
}): AwsCredentialIdentityProvider;
|
|
12
|
+
//# sourceMappingURL=broker-credential-provider.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const util_auth_authStore = require('./auth-store.js');
|
|
4
|
+
|
|
5
|
+
const DEFAULT_BROKER_BASE_URL = 'https://bigbrain-zth.bigbrain.me';
|
|
6
|
+
const STS_BROKER_PATH = '/z2h-cli/sts/credentials';
|
|
7
|
+
// Refresh the cached credentials this many ms before they expire so the next
|
|
8
|
+
// AWS API call doesn't race the broker round-trip against a hard expiry.
|
|
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
|
+
async function fetchCredentialsOnce(appName) {
|
|
14
|
+
const { token } = await util_auth_authStore.readZthAuth();
|
|
15
|
+
const url = `${brokerBaseUrl()}${STS_BROKER_PATH}`;
|
|
16
|
+
let res;
|
|
17
|
+
try {
|
|
18
|
+
res = await fetch(url, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: {
|
|
21
|
+
Authorization: `Bearer ${token}`,
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
Accept: 'application/json',
|
|
24
|
+
},
|
|
25
|
+
body: JSON.stringify({ appName }),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
+
throw new Error(`Z2H deploy broker request failed: ${message}`);
|
|
31
|
+
}
|
|
32
|
+
if (res.status === 401 || res.status === 403) {
|
|
33
|
+
throw new Error(`Z2H deploy token rejected by the broker (${res.status}). Refresh user token by running 'z2h-cli generate-z2h-token'.`);
|
|
34
|
+
}
|
|
35
|
+
if (!res.ok) {
|
|
36
|
+
const text = await res.text();
|
|
37
|
+
throw new Error(`Z2H deploy broker returned ${res.status}: ${text.slice(0, 1024)}`);
|
|
38
|
+
}
|
|
39
|
+
const body = (await res.json());
|
|
40
|
+
if (!body.accessKeyId || !body.secretAccessKey || !body.sessionToken || !body.expiration) {
|
|
41
|
+
throw new Error('Z2H deploy broker response missing required credential fields');
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
accessKeyId: body.accessKeyId,
|
|
45
|
+
secretAccessKey: body.secretAccessKey,
|
|
46
|
+
sessionToken: body.sessionToken,
|
|
47
|
+
expiration: new Date(body.expiration),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* AWS SDK credential provider that fetches short-lived deploy credentials
|
|
52
|
+
* from the bigbrain-zth STS broker. Credentials are cached in memory until
|
|
53
|
+
* 5 minutes before expiry; concurrent calls share a single in-flight fetch.
|
|
54
|
+
*/
|
|
55
|
+
function brokerCredentialProvider({ appName }) {
|
|
56
|
+
let cached;
|
|
57
|
+
let inflight;
|
|
58
|
+
return async () => {
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
if (cached && cached.expiration && cached.expiration.getTime() - now > REFRESH_BUFFER_MS) {
|
|
61
|
+
return cached;
|
|
62
|
+
}
|
|
63
|
+
if (inflight) {
|
|
64
|
+
return inflight;
|
|
65
|
+
}
|
|
66
|
+
inflight = fetchCredentialsOnce(appName)
|
|
67
|
+
.then(creds => {
|
|
68
|
+
cached = creds;
|
|
69
|
+
return creds;
|
|
70
|
+
})
|
|
71
|
+
.finally(() => {
|
|
72
|
+
inflight = undefined;
|
|
73
|
+
});
|
|
74
|
+
return inflight;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
exports.DEFAULT_BROKER_BASE_URL = DEFAULT_BROKER_BASE_URL;
|
|
79
|
+
exports.STS_BROKER_PATH = STS_BROKER_PATH;
|
|
80
|
+
exports.brokerCredentialProvider = brokerCredentialProvider;
|