wawesome 0.7.0 → 0.8.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/index.mjs +255 -107
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -18,6 +18,7 @@ import zlib from "node:zlib";
|
|
|
18
18
|
* These are public values — the anon key is designed to be embedded in clients.
|
|
19
19
|
*/
|
|
20
20
|
const SUPABASE_URL = "https://vclasavxxoufwymrutai.supabase.co";
|
|
21
|
+
const SUPABASE_ANON_KEY = "sb_publishable_ZlgDAI9cNZkefEwVPKIngA_ktuvTpjD";
|
|
21
22
|
/** Path to the user-level settings file (~/.wawesome/settings.json) */
|
|
22
23
|
function getSettingsPath() {
|
|
23
24
|
return path.join(os.homedir(), ".wawesome", "settings.json");
|
|
@@ -90,12 +91,23 @@ function readCredentials() {
|
|
|
90
91
|
}
|
|
91
92
|
/**
|
|
92
93
|
* Write credentials to disk, creating the directory if needed.
|
|
94
|
+
*
|
|
95
|
+
* Owner-only, because the file holds a refresh token. The `chmod` is what
|
|
96
|
+
* tightens a file an older CLI left world-readable; a mode passed to
|
|
97
|
+
* `writeFileSync` applies only where it creates the file.
|
|
93
98
|
*/
|
|
94
99
|
function writeCredentials(creds) {
|
|
95
100
|
const credPath = getCredentialsPath();
|
|
96
101
|
const dir = path.dirname(credPath);
|
|
97
|
-
fs.mkdirSync(dir, {
|
|
98
|
-
|
|
102
|
+
fs.mkdirSync(dir, {
|
|
103
|
+
recursive: true,
|
|
104
|
+
mode: 448
|
|
105
|
+
});
|
|
106
|
+
fs.writeFileSync(credPath, JSON.stringify(creds, null, 2), {
|
|
107
|
+
encoding: "utf-8",
|
|
108
|
+
mode: 384
|
|
109
|
+
});
|
|
110
|
+
fs.chmodSync(credPath, 384);
|
|
99
111
|
}
|
|
100
112
|
/**
|
|
101
113
|
* Delete stored credentials.
|
|
@@ -759,7 +771,7 @@ async function buildJs(entryInput, options) {
|
|
|
759
771
|
* that has to name this version — `--version`, the dependency a scaffolded
|
|
760
772
|
* project pins — reads it here, so a release bumps one file.
|
|
761
773
|
*/
|
|
762
|
-
const CLI_VERSION = "0.
|
|
774
|
+
const CLI_VERSION = "0.8.0";
|
|
763
775
|
//#endregion
|
|
764
776
|
//#region src/prompt.ts
|
|
765
777
|
/**
|
|
@@ -816,6 +828,126 @@ function isInteractive() {
|
|
|
816
828
|
return Boolean(process.stdin.isTTY);
|
|
817
829
|
}
|
|
818
830
|
//#endregion
|
|
831
|
+
//#region src/session.ts
|
|
832
|
+
/**
|
|
833
|
+
* A gateway request, retried once against a renewed session if it comes back 401.
|
|
834
|
+
*
|
|
835
|
+
* A caller's `Authorization` is a snapshot of what was on disk when the command
|
|
836
|
+
* started, so a renewal here replaces it. Otherwise every later request in the
|
|
837
|
+
* same command would spend a 401 learning what this already knows.
|
|
838
|
+
*
|
|
839
|
+
* A body that can only be read once, an asset streamed off disk, passes a
|
|
840
|
+
* function so the retry is built one of its own.
|
|
841
|
+
*/
|
|
842
|
+
async function authorizedFetch(url, init = {}) {
|
|
843
|
+
const request = typeof init === "function" ? init : () => init;
|
|
844
|
+
const sentAt = Date.now();
|
|
845
|
+
const res = await fetch(url, renewedJwt ? withBearer(request(), renewedJwt) : request());
|
|
846
|
+
if (res.status !== 401) return res;
|
|
847
|
+
if (renewedJwt && renewedAt > sentAt) return retry(url, request, renewedJwt, res);
|
|
848
|
+
if (renewedJwt && Date.now() - renewedAt < JUST_RENEWED_MS) return res;
|
|
849
|
+
const renewed = await renewSession();
|
|
850
|
+
if (!renewed) return res;
|
|
851
|
+
return retry(url, request, renewed.tenant_jwt, res);
|
|
852
|
+
}
|
|
853
|
+
/** Thirty minutes of token life leaves this nowhere near a genuine expiry. */
|
|
854
|
+
const JUST_RENEWED_MS = 6e4;
|
|
855
|
+
async function retry(url, request, tenantJwt, refused) {
|
|
856
|
+
await refused.body?.cancel().catch(() => {});
|
|
857
|
+
return fetch(url, withBearer(request(), tenantJwt));
|
|
858
|
+
}
|
|
859
|
+
function withBearer(init, tenantJwt) {
|
|
860
|
+
return {
|
|
861
|
+
...init,
|
|
862
|
+
headers: {
|
|
863
|
+
...headerRecord(init.headers),
|
|
864
|
+
Authorization: `Bearer ${tenantJwt}`
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
function headerRecord(headers) {
|
|
869
|
+
if (!headers) return {};
|
|
870
|
+
if (headers instanceof Headers || Array.isArray(headers)) return Object.fromEntries(new Headers(headers).entries());
|
|
871
|
+
return { ...headers };
|
|
872
|
+
}
|
|
873
|
+
let renewal = null;
|
|
874
|
+
let renewedJwt = null;
|
|
875
|
+
let renewedAt = 0;
|
|
876
|
+
/** Drop what this process learned about the session, as ending one does. */
|
|
877
|
+
function forgetRenewedSession() {
|
|
878
|
+
renewal = null;
|
|
879
|
+
renewedJwt = null;
|
|
880
|
+
renewedAt = 0;
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Supabase rotates the refresh token on every use and revokes the whole family
|
|
884
|
+
* if a spent one comes back, so requests that meet the 401 together share one
|
|
885
|
+
* renewal instead of racing with the same token.
|
|
886
|
+
*/
|
|
887
|
+
function renewSession() {
|
|
888
|
+
if (!renewal) {
|
|
889
|
+
const inFlight = renewOnce().finally(() => {
|
|
890
|
+
if (renewal === inFlight) renewal = null;
|
|
891
|
+
});
|
|
892
|
+
renewal = inFlight;
|
|
893
|
+
}
|
|
894
|
+
return renewal;
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* Null where there is nothing to renew from. Credentials written before refresh
|
|
898
|
+
* tokens were stored still describe a session, so the 401 goes back to the
|
|
899
|
+
* caller, whose own message for it is the right one.
|
|
900
|
+
*/
|
|
901
|
+
async function renewOnce() {
|
|
902
|
+
const creds = readCredentials();
|
|
903
|
+
if (!creds?.refresh_token) return null;
|
|
904
|
+
const session = await refreshSupabaseSession(creds.refresh_token);
|
|
905
|
+
const exchanged = await exchangeForTenantJwt(creds, session.access_token);
|
|
906
|
+
const renewed = {
|
|
907
|
+
...creds,
|
|
908
|
+
tenant_jwt: exchanged.tenant_jwt,
|
|
909
|
+
refresh_token: session.refresh_token || creds.refresh_token,
|
|
910
|
+
tenant_slug: exchanged.tenant_slug || creds.tenant_slug,
|
|
911
|
+
tenant_name: exchanged.tenant_name || creds.tenant_name
|
|
912
|
+
};
|
|
913
|
+
writeCredentials(renewed);
|
|
914
|
+
renewedJwt = renewed.tenant_jwt;
|
|
915
|
+
renewedAt = Date.now();
|
|
916
|
+
return renewed;
|
|
917
|
+
}
|
|
918
|
+
async function refreshSupabaseSession(refreshToken) {
|
|
919
|
+
const res = await fetch(`${SUPABASE_URL}/auth/v1/token?grant_type=refresh_token`, {
|
|
920
|
+
method: "POST",
|
|
921
|
+
headers: {
|
|
922
|
+
apikey: SUPABASE_ANON_KEY,
|
|
923
|
+
"Content-Type": "application/json"
|
|
924
|
+
},
|
|
925
|
+
body: JSON.stringify({ refresh_token: refreshToken })
|
|
926
|
+
});
|
|
927
|
+
if (res.status >= 400 && res.status < 500 && res.status !== 429) endSession("Your sign-in was revoked or has expired, so the session could not be renewed.");
|
|
928
|
+
if (!res.ok) throw new Error(`Could not renew your session (Supabase HTTP ${res.status}).`);
|
|
929
|
+
const session = await res.json();
|
|
930
|
+
if (!session.access_token) throw new Error("Could not renew your session (Supabase returned no access token).");
|
|
931
|
+
return session;
|
|
932
|
+
}
|
|
933
|
+
async function exchangeForTenantJwt(creds, supabaseAccessToken) {
|
|
934
|
+
const res = await fetch(`${creds.gateway_url}/api/v1/auth/token-exchange`, {
|
|
935
|
+
method: "POST",
|
|
936
|
+
headers: {
|
|
937
|
+
Authorization: `Bearer ${supabaseAccessToken}`,
|
|
938
|
+
"Content-Type": "application/json"
|
|
939
|
+
},
|
|
940
|
+
body: JSON.stringify({ tenant_id: creds.tenant_id })
|
|
941
|
+
});
|
|
942
|
+
if (res.status === 401 || res.status === 403) endSession("Your access to this workspace has been withdrawn.");
|
|
943
|
+
if (!res.ok) throw new Error(`Could not renew your session (token exchange HTTP ${res.status}).`);
|
|
944
|
+
return await res.json();
|
|
945
|
+
}
|
|
946
|
+
function endSession(reason) {
|
|
947
|
+
console.error(`[wawesome] Error: ${reason} Run 'wawesome login' to sign in again.`);
|
|
948
|
+
process.exit(1);
|
|
949
|
+
}
|
|
950
|
+
//#endregion
|
|
819
951
|
//#region src/errors.ts
|
|
820
952
|
/** A rejection carrying the gateway's own prose and, where given, its reason. */
|
|
821
953
|
var GatewayError = class extends Error {
|
|
@@ -862,7 +994,7 @@ function errorText(err) {
|
|
|
862
994
|
//#endregion
|
|
863
995
|
//#region src/tenant.ts
|
|
864
996
|
async function fetchTenantDetails(creds) {
|
|
865
|
-
const res = await
|
|
997
|
+
const res = await authorizedFetch(`${creds.gateway_url}/v1/tenant`, { headers: { Authorization: `Bearer ${creds.tenant_jwt}` } });
|
|
866
998
|
if (!res.ok) throw await asGatewayError(res, `Failed to read workspace (HTTP ${res.status}).`);
|
|
867
999
|
return await res.json();
|
|
868
1000
|
}
|
|
@@ -928,7 +1060,7 @@ function renameAdvice(reason) {
|
|
|
928
1060
|
* unusable name comes back as a `malformed` rejection instead.
|
|
929
1061
|
*/
|
|
930
1062
|
async function renameTenantSlug(creds, slug) {
|
|
931
|
-
const res = await
|
|
1063
|
+
const res = await authorizedFetch(`${creds.gateway_url}/v1/tenant/slug`, {
|
|
932
1064
|
method: "PUT",
|
|
933
1065
|
headers: {
|
|
934
1066
|
Authorization: `Bearer ${creds.tenant_jwt}`,
|
|
@@ -972,6 +1104,80 @@ async function promptForWorkspaceName(options) {
|
|
|
972
1104
|
throw new Error("No workspace name given. Nothing was created.");
|
|
973
1105
|
}
|
|
974
1106
|
/**
|
|
1107
|
+
* Turn a finished OAuth callback into stored credentials.
|
|
1108
|
+
*
|
|
1109
|
+
* Split from the callback server so what login stores can be exercised without
|
|
1110
|
+
* a browser and a port.
|
|
1111
|
+
*/
|
|
1112
|
+
async function completeLogin({ gatewayUrl, dashboardUrl, accessToken, refreshToken, options }) {
|
|
1113
|
+
const isVerbose = Boolean(options.verbose);
|
|
1114
|
+
console.log("[wawesome] Fetching your workspaces...");
|
|
1115
|
+
const tenantsRes = await fetch(`${gatewayUrl}/api/v1/me/tenants`, { headers: { Authorization: `Bearer ${accessToken}` } });
|
|
1116
|
+
if (!tenantsRes.ok) throw new Error(`Failed to fetch tenants (HTTP ${tenantsRes.status}). Have you completed onboarding?`);
|
|
1117
|
+
const tenants = await tenantsRes.json();
|
|
1118
|
+
let primaryTenantId;
|
|
1119
|
+
let workspaceName;
|
|
1120
|
+
let workspaceSlug;
|
|
1121
|
+
if (tenants.length === 0) {
|
|
1122
|
+
const chosenName = await promptForWorkspaceName(options);
|
|
1123
|
+
console.log(`[wawesome] Creating workspace "${chosenName}"...`);
|
|
1124
|
+
const initRes = await fetch(`${gatewayUrl}/api/v1/onboarding/init`, {
|
|
1125
|
+
method: "POST",
|
|
1126
|
+
headers: {
|
|
1127
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1128
|
+
"Content-Type": "application/json"
|
|
1129
|
+
},
|
|
1130
|
+
body: JSON.stringify({ tenant_name: chosenName })
|
|
1131
|
+
});
|
|
1132
|
+
if (!initRes.ok) throw new Error(`Failed to initialize workspace (HTTP ${initRes.status}).`);
|
|
1133
|
+
const initData = await initRes.json();
|
|
1134
|
+
primaryTenantId = initData.tenant_id;
|
|
1135
|
+
workspaceSlug = initData.tenant_slug;
|
|
1136
|
+
workspaceName = initData.tenant_name || chosenName;
|
|
1137
|
+
} else primaryTenantId = tenants[0].tenant_id;
|
|
1138
|
+
if (isVerbose) console.log(`[wawesome:verbose] Using tenant: ${primaryTenantId}`);
|
|
1139
|
+
console.log("[wawesome] Exchanging for tenant-scoped credentials...");
|
|
1140
|
+
const exchangeRes = await fetch(`${gatewayUrl}/api/v1/auth/token-exchange`, {
|
|
1141
|
+
method: "POST",
|
|
1142
|
+
headers: {
|
|
1143
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1144
|
+
"Content-Type": "application/json"
|
|
1145
|
+
},
|
|
1146
|
+
body: JSON.stringify({ tenant_id: primaryTenantId })
|
|
1147
|
+
});
|
|
1148
|
+
if (!exchangeRes.ok) throw new Error(`Token exchange failed (HTTP ${exchangeRes.status}).`);
|
|
1149
|
+
const exchangeData = await exchangeRes.json();
|
|
1150
|
+
workspaceSlug = exchangeData.tenant_slug || workspaceSlug;
|
|
1151
|
+
workspaceName = exchangeData.tenant_name || workspaceName;
|
|
1152
|
+
let userEmail = exchangeData.email || "unknown";
|
|
1153
|
+
try {
|
|
1154
|
+
const payloadPart = exchangeData.tenant_jwt.split(".")[1];
|
|
1155
|
+
const decoded = JSON.parse(Buffer.from(payloadPart, "base64url").toString("utf-8"));
|
|
1156
|
+
if (decoded.email) userEmail = decoded.email;
|
|
1157
|
+
} catch {}
|
|
1158
|
+
forgetRenewedSession();
|
|
1159
|
+
writeCredentials({
|
|
1160
|
+
gateway_url: gatewayUrl,
|
|
1161
|
+
dashboard_url: dashboardUrl,
|
|
1162
|
+
tenant_jwt: exchangeData.tenant_jwt,
|
|
1163
|
+
refresh_token: refreshToken,
|
|
1164
|
+
tenant_id: primaryTenantId,
|
|
1165
|
+
user_email: userEmail,
|
|
1166
|
+
tenant_slug: workspaceSlug,
|
|
1167
|
+
tenant_name: workspaceName
|
|
1168
|
+
});
|
|
1169
|
+
console.log("\n======================================================");
|
|
1170
|
+
console.log("🎉 \x1B[32mLOGIN SUCCESSFUL!\x1B[0m");
|
|
1171
|
+
console.log("======================================================");
|
|
1172
|
+
if (workspaceName) console.log(`\n Workspace: ${workspaceName}`);
|
|
1173
|
+
if (workspaceSlug) console.log(` Address: ${workspaceSlug}`);
|
|
1174
|
+
console.log(` Tenant: ${primaryTenantId}`);
|
|
1175
|
+
console.log(` Gateway: ${gatewayUrl}`);
|
|
1176
|
+
console.log(` Email: ${userEmail}`);
|
|
1177
|
+
console.log("\n Credentials saved to ~/.wawesome/credentials.json");
|
|
1178
|
+
console.log("======================================================\n");
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
975
1181
|
* OAuth login flow:
|
|
976
1182
|
* 1. Build Supabase OAuth URL
|
|
977
1183
|
* 2. Open browser
|
|
@@ -1025,6 +1231,7 @@ async function login(options) {
|
|
|
1025
1231
|
}
|
|
1026
1232
|
if (reqUrl.pathname === "/token") {
|
|
1027
1233
|
const accessToken = reqUrl.searchParams.get("access_token");
|
|
1234
|
+
const refreshToken = reqUrl.searchParams.get("refresh_token");
|
|
1028
1235
|
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
1029
1236
|
res.end("Token received by CLI.");
|
|
1030
1237
|
if (!accessToken) {
|
|
@@ -1035,69 +1242,13 @@ async function login(options) {
|
|
|
1035
1242
|
}
|
|
1036
1243
|
if (isVerbose) console.log("[wawesome:verbose] Supabase access token received.");
|
|
1037
1244
|
try {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
let workspaceSlug;
|
|
1045
|
-
if (tenants.length === 0) {
|
|
1046
|
-
const chosenName = await promptForWorkspaceName(options);
|
|
1047
|
-
console.log(`[wawesome] Creating workspace "${chosenName}"...`);
|
|
1048
|
-
const initRes = await fetch(`${gatewayUrl}/api/v1/onboarding/init`, {
|
|
1049
|
-
method: "POST",
|
|
1050
|
-
headers: {
|
|
1051
|
-
Authorization: `Bearer ${accessToken}`,
|
|
1052
|
-
"Content-Type": "application/json"
|
|
1053
|
-
},
|
|
1054
|
-
body: JSON.stringify({ tenant_name: chosenName })
|
|
1055
|
-
});
|
|
1056
|
-
if (!initRes.ok) throw new Error(`Failed to initialize workspace (HTTP ${initRes.status}).`);
|
|
1057
|
-
const initData = await initRes.json();
|
|
1058
|
-
primaryTenantId = initData.tenant_id;
|
|
1059
|
-
workspaceSlug = initData.tenant_slug;
|
|
1060
|
-
workspaceName = initData.tenant_name || chosenName;
|
|
1061
|
-
} else primaryTenantId = tenants[0].tenant_id;
|
|
1062
|
-
if (isVerbose) console.log(`[wawesome:verbose] Using tenant: ${primaryTenantId}`);
|
|
1063
|
-
console.log("[wawesome] Exchanging for tenant-scoped credentials...");
|
|
1064
|
-
const exchangeRes = await fetch(`${gatewayUrl}/api/v1/auth/token-exchange`, {
|
|
1065
|
-
method: "POST",
|
|
1066
|
-
headers: {
|
|
1067
|
-
Authorization: `Bearer ${accessToken}`,
|
|
1068
|
-
"Content-Type": "application/json"
|
|
1069
|
-
},
|
|
1070
|
-
body: JSON.stringify({ tenant_id: primaryTenantId })
|
|
1071
|
-
});
|
|
1072
|
-
if (!exchangeRes.ok) throw new Error(`Token exchange failed (HTTP ${exchangeRes.status}).`);
|
|
1073
|
-
const exchangeData = await exchangeRes.json();
|
|
1074
|
-
workspaceSlug = exchangeData.tenant_slug || workspaceSlug;
|
|
1075
|
-
workspaceName = exchangeData.tenant_name || workspaceName;
|
|
1076
|
-
let userEmail = exchangeData.email || "unknown";
|
|
1077
|
-
try {
|
|
1078
|
-
const payloadPart = exchangeData.tenant_jwt.split(".")[1];
|
|
1079
|
-
const decoded = JSON.parse(Buffer.from(payloadPart, "base64url").toString("utf-8"));
|
|
1080
|
-
if (decoded.email) userEmail = decoded.email;
|
|
1081
|
-
} catch {}
|
|
1082
|
-
writeCredentials({
|
|
1083
|
-
gateway_url: gatewayUrl,
|
|
1084
|
-
dashboard_url: dashboardUrl,
|
|
1085
|
-
tenant_jwt: exchangeData.tenant_jwt,
|
|
1086
|
-
tenant_id: primaryTenantId,
|
|
1087
|
-
user_email: userEmail,
|
|
1088
|
-
tenant_slug: workspaceSlug,
|
|
1089
|
-
tenant_name: workspaceName
|
|
1245
|
+
await completeLogin({
|
|
1246
|
+
gatewayUrl,
|
|
1247
|
+
dashboardUrl,
|
|
1248
|
+
accessToken,
|
|
1249
|
+
refreshToken: refreshToken || void 0,
|
|
1250
|
+
options
|
|
1090
1251
|
});
|
|
1091
|
-
console.log("\n======================================================");
|
|
1092
|
-
console.log("🎉 \x1B[32mLOGIN SUCCESSFUL!\x1B[0m");
|
|
1093
|
-
console.log("======================================================");
|
|
1094
|
-
if (workspaceName) console.log(`\n Workspace: ${workspaceName}`);
|
|
1095
|
-
if (workspaceSlug) console.log(` Address: ${workspaceSlug}`);
|
|
1096
|
-
console.log(` Tenant: ${primaryTenantId}`);
|
|
1097
|
-
console.log(` Gateway: ${gatewayUrl}`);
|
|
1098
|
-
console.log(` Email: ${userEmail}`);
|
|
1099
|
-
console.log("\n Credentials saved to ~/.wawesome/credentials.json");
|
|
1100
|
-
console.log("======================================================\n");
|
|
1101
1252
|
server.close();
|
|
1102
1253
|
resolve();
|
|
1103
1254
|
} catch (err) {
|
|
@@ -1127,6 +1278,7 @@ async function login(options) {
|
|
|
1127
1278
|
* Clear stored credentials.
|
|
1128
1279
|
*/
|
|
1129
1280
|
function logout() {
|
|
1281
|
+
forgetRenewedSession();
|
|
1130
1282
|
if (deleteCredentials()) console.log("[wawesome] ✅ Logged out. Credentials removed.");
|
|
1131
1283
|
else console.log("[wawesome] Not logged in (no credentials found).");
|
|
1132
1284
|
}
|
|
@@ -1201,7 +1353,7 @@ async function fetchTenantUsage(creds, timeoutMs = USAGE_TIMEOUT_MS) {
|
|
|
1201
1353
|
const controller = new AbortController();
|
|
1202
1354
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1203
1355
|
try {
|
|
1204
|
-
const res = await
|
|
1356
|
+
const res = await authorizedFetch(`${creds.gateway_url}/v1/tenant/usage`, {
|
|
1205
1357
|
headers: { Authorization: `Bearer ${creds.tenant_jwt}` },
|
|
1206
1358
|
signal: controller.signal
|
|
1207
1359
|
});
|
|
@@ -1697,7 +1849,7 @@ async function deploy(entryInput, options) {
|
|
|
1697
1849
|
const uploadUrl = `${creds.gateway_url}/v1/apps/${encodeURIComponent(app)}/functions/${encodeURIComponent(funcName)}/code`;
|
|
1698
1850
|
if (isVerbose) console.log(`[wawesome:verbose] POST ${uploadUrl}`);
|
|
1699
1851
|
const declaredOnTheWire = declaredFields(declared);
|
|
1700
|
-
const uploadRes = assets.length > 0 || declaresSchedules || Object.keys(declaredOnTheWire).length > 0 ? await
|
|
1852
|
+
const uploadRes = assets.length > 0 || declaresSchedules || Object.keys(declaredOnTheWire).length > 0 ? await authorizedFetch(uploadUrl, {
|
|
1701
1853
|
method: "POST",
|
|
1702
1854
|
headers: {
|
|
1703
1855
|
Authorization: `Bearer ${creds.tenant_jwt}`,
|
|
@@ -1709,7 +1861,7 @@ async function deploy(entryInput, options) {
|
|
|
1709
1861
|
...declaresSchedules ? { schedules: config.schedules } : {},
|
|
1710
1862
|
...declaredOnTheWire
|
|
1711
1863
|
})
|
|
1712
|
-
}) : await
|
|
1864
|
+
}) : await authorizedFetch(uploadUrl, {
|
|
1713
1865
|
method: "POST",
|
|
1714
1866
|
headers: {
|
|
1715
1867
|
Authorization: `Bearer ${creds.tenant_jwt}`,
|
|
@@ -1755,7 +1907,7 @@ async function deploy(entryInput, options) {
|
|
|
1755
1907
|
if (isVerbose) console.log(`[wawesome:verbose] POST ${deployUrl}`);
|
|
1756
1908
|
const deployBody = {};
|
|
1757
1909
|
if (version !== void 0) deployBody.version_number = version;
|
|
1758
|
-
const deployRes = await
|
|
1910
|
+
const deployRes = await authorizedFetch(deployUrl, {
|
|
1759
1911
|
method: "POST",
|
|
1760
1912
|
headers: {
|
|
1761
1913
|
Authorization: `Bearer ${creds.tenant_jwt}`,
|
|
@@ -1836,8 +1988,7 @@ async function deploy(entryInput, options) {
|
|
|
1836
1988
|
* changed nothing at all is refused here — before a byte of it has moved.
|
|
1837
1989
|
*/
|
|
1838
1990
|
async function uploadAssets(creds, app, funcName, bundle, assets, declared, isVerbose, continueWhenUnchanged) {
|
|
1839
|
-
const
|
|
1840
|
-
const manifestRes = await fetch(manifestUrl, {
|
|
1991
|
+
const manifestRes = await authorizedFetch(`${creds.gateway_url}/v1/apps/${encodeURIComponent(app)}/functions/${encodeURIComponent(funcName)}/assets/manifest`, {
|
|
1841
1992
|
method: "POST",
|
|
1842
1993
|
headers: {
|
|
1843
1994
|
Authorization: `Bearer ${creds.tenant_jwt}`,
|
|
@@ -1880,7 +2031,7 @@ async function uploadAssets(creds, app, funcName, bundle, assets, declared, isVe
|
|
|
1880
2031
|
console.log(`[wawesome] Uploading ${toUpload.length} of ${assets.length} asset(s)...`);
|
|
1881
2032
|
for (const asset of toUpload) {
|
|
1882
2033
|
if (isVerbose) console.log(`[wawesome:verbose] PUT ${asset.path} (${asset.size_bytes} bytes)`);
|
|
1883
|
-
const res = await
|
|
2034
|
+
const res = await authorizedFetch(`${creds.gateway_url}/v1/assets/${asset.content_hash}`, () => ({
|
|
1884
2035
|
method: "PUT",
|
|
1885
2036
|
headers: {
|
|
1886
2037
|
Authorization: `Bearer ${creds.tenant_jwt}`,
|
|
@@ -1889,7 +2040,7 @@ async function uploadAssets(creds, app, funcName, bundle, assets, declared, isVe
|
|
|
1889
2040
|
},
|
|
1890
2041
|
body: Readable.toWeb(fs.createReadStream(asset.source)),
|
|
1891
2042
|
duplex: "half"
|
|
1892
|
-
});
|
|
2043
|
+
}));
|
|
1893
2044
|
if (!res.ok) {
|
|
1894
2045
|
const errorBody = await res.text();
|
|
1895
2046
|
const refusal = rejectionOf(errorBody, res.status, `Upload of '${asset.path}' failed (HTTP ${res.status}).`);
|
|
@@ -1937,8 +2088,7 @@ function loadClientContext() {
|
|
|
1937
2088
|
* the time it does, so it needs to say what did land before it gives up.
|
|
1938
2089
|
*/
|
|
1939
2090
|
async function putEnvVar(creds, app, key, value, isSecret) {
|
|
1940
|
-
const
|
|
1941
|
-
const res = await fetch(url, {
|
|
2091
|
+
const res = await authorizedFetch(`${creds.gateway_url}/v1/apps/${encodeURIComponent(app)}/env`, {
|
|
1942
2092
|
method: "POST",
|
|
1943
2093
|
headers: {
|
|
1944
2094
|
Authorization: `Bearer ${creds.tenant_jwt}`,
|
|
@@ -2001,7 +2151,7 @@ async function listEnvVars(options) {
|
|
|
2001
2151
|
const { creds, app } = loadClientContext();
|
|
2002
2152
|
const url = `${creds.gateway_url}/v1/apps/${encodeURIComponent(app)}/env`;
|
|
2003
2153
|
if (isVerbose) console.log(`[wawesome:verbose] GET ${url}`);
|
|
2004
|
-
const res = await
|
|
2154
|
+
const res = await authorizedFetch(url, {
|
|
2005
2155
|
method: "GET",
|
|
2006
2156
|
headers: { Authorization: `Bearer ${creds.tenant_jwt}` }
|
|
2007
2157
|
});
|
|
@@ -2055,7 +2205,7 @@ async function removeEnvVar(key, options) {
|
|
|
2055
2205
|
const { creds, app } = loadClientContext();
|
|
2056
2206
|
const url = `${creds.gateway_url}/v1/apps/${encodeURIComponent(app)}/env/${encodeURIComponent(key)}`;
|
|
2057
2207
|
if (isVerbose) console.log(`[wawesome:verbose] DELETE ${url}`);
|
|
2058
|
-
const res = await
|
|
2208
|
+
const res = await authorizedFetch(url, {
|
|
2059
2209
|
method: "DELETE",
|
|
2060
2210
|
headers: { Authorization: `Bearer ${creds.tenant_jwt}` }
|
|
2061
2211
|
});
|
|
@@ -2158,10 +2308,10 @@ function authHeaders(creds) {
|
|
|
2158
2308
|
* between is still treated as the success it is.
|
|
2159
2309
|
*/
|
|
2160
2310
|
async function ensureApp(creds, appSlug) {
|
|
2161
|
-
const listRes = await
|
|
2311
|
+
const listRes = await authorizedFetch(`${creds.gateway_url}/v1/apps`, { headers: { Authorization: `Bearer ${creds.tenant_jwt}` } });
|
|
2162
2312
|
if (!listRes.ok) throw await rejected(listRes, "Could not list the Tenant's apps");
|
|
2163
2313
|
if ((await listRes.json()).applications?.some((app) => app.slug === appSlug)) return;
|
|
2164
|
-
const createRes = await
|
|
2314
|
+
const createRes = await authorizedFetch(`${creds.gateway_url}/v1/apps`, {
|
|
2165
2315
|
method: "POST",
|
|
2166
2316
|
headers: authHeaders(creds),
|
|
2167
2317
|
body: JSON.stringify({
|
|
@@ -2182,8 +2332,7 @@ async function ensureApp(creds, appSlug) {
|
|
|
2182
2332
|
* scaffolded template and an outbound request that silently fails at runtime.
|
|
2183
2333
|
*/
|
|
2184
2334
|
async function enableEgressProvider(creds, appSlug, providerKey) {
|
|
2185
|
-
const
|
|
2186
|
-
const res = await fetch(url, {
|
|
2335
|
+
const res = await authorizedFetch(`${creds.gateway_url}/v1/apps/${encodeURIComponent(appSlug)}/egress/subscriptions`, {
|
|
2187
2336
|
method: "POST",
|
|
2188
2337
|
headers: authHeaders(creds),
|
|
2189
2338
|
body: JSON.stringify({ provider_key: providerKey })
|
|
@@ -3086,7 +3235,7 @@ const RECLAIMED = "⚠ [assets reclaimed]";
|
|
|
3086
3235
|
async function fetchVersions(gatewayUrl, tenantJwt, app, funcName, env, isVerbose) {
|
|
3087
3236
|
const url = `${gatewayUrl}/v1/apps/${encodeURIComponent(app)}/functions/${encodeURIComponent(funcName)}/versions?environment=${encodeURIComponent(env)}`;
|
|
3088
3237
|
if (isVerbose) console.log(`[wawesome:verbose] GET ${url}`);
|
|
3089
|
-
const res = await
|
|
3238
|
+
const res = await authorizedFetch(url, {
|
|
3090
3239
|
method: "GET",
|
|
3091
3240
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
3092
3241
|
});
|
|
@@ -3199,8 +3348,7 @@ async function switchVersion(targetInput, options) {
|
|
|
3199
3348
|
}
|
|
3200
3349
|
}
|
|
3201
3350
|
console.log(`[wawesome] Promoting v${selectedVersionNum} to ${env}...`);
|
|
3202
|
-
const
|
|
3203
|
-
const deployRes = await fetch(deployUrl, {
|
|
3351
|
+
const deployRes = await authorizedFetch(`${creds.gateway_url}/v1/apps/${encodeURIComponent(app)}/functions/${encodeURIComponent(funcName)}/deploy`, {
|
|
3204
3352
|
method: "POST",
|
|
3205
3353
|
headers: {
|
|
3206
3354
|
Authorization: `Bearer ${creds.tenant_jwt}`,
|
|
@@ -3290,7 +3438,7 @@ async function logsCommand(target, options = {}) {
|
|
|
3290
3438
|
async function fetchInvocationLogBody(gatewayUrl, tenantJwt, invocationId, isVerbose) {
|
|
3291
3439
|
const url = `${gatewayUrl}/v1/invocations/${encodeURIComponent(invocationId)}/logs`;
|
|
3292
3440
|
if (isVerbose) console.log(`[wawesome:verbose] GET ${url}`);
|
|
3293
|
-
const res = await
|
|
3441
|
+
const res = await authorizedFetch(url, {
|
|
3294
3442
|
method: "GET",
|
|
3295
3443
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
3296
3444
|
});
|
|
@@ -3366,7 +3514,7 @@ async function listInvocations(gatewayUrl, tenantJwt, funcNameInput, appOverride
|
|
|
3366
3514
|
async function fetchInvocationsResponse(gatewayUrl, tenantJwt, funcName, appSlug, appOverride, queryString, isVerbose) {
|
|
3367
3515
|
const url = appSlug ? `${gatewayUrl}/v1/apps/${encodeURIComponent(appSlug)}/functions/${encodeURIComponent(funcName)}/invocations${queryString}` : `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/invocations${queryString}`;
|
|
3368
3516
|
if (isVerbose) console.log(`[wawesome:verbose] GET ${url}`);
|
|
3369
|
-
let res = await
|
|
3517
|
+
let res = await authorizedFetch(url, {
|
|
3370
3518
|
method: "GET",
|
|
3371
3519
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
3372
3520
|
});
|
|
@@ -3374,7 +3522,7 @@ async function fetchInvocationsResponse(gatewayUrl, tenantJwt, funcName, appSlug
|
|
|
3374
3522
|
const fallbackUrl = `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/invocations${queryString}`;
|
|
3375
3523
|
if (isVerbose) console.log(`[wawesome:verbose] 404 on app-scoped route. Retrying unscoped: GET ${fallbackUrl}`);
|
|
3376
3524
|
try {
|
|
3377
|
-
const fallbackRes = await
|
|
3525
|
+
const fallbackRes = await authorizedFetch(fallbackUrl, {
|
|
3378
3526
|
method: "GET",
|
|
3379
3527
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
3380
3528
|
});
|
|
@@ -3486,7 +3634,7 @@ async function followInvocationLog(gatewayUrl, tenantJwt, invocationId, isVerbos
|
|
|
3486
3634
|
while (true) {
|
|
3487
3635
|
let res = null;
|
|
3488
3636
|
try {
|
|
3489
|
-
res = await
|
|
3637
|
+
res = await authorizedFetch(url, {
|
|
3490
3638
|
method: "GET",
|
|
3491
3639
|
headers: {
|
|
3492
3640
|
Authorization: `Bearer ${tenantJwt}`,
|
|
@@ -3618,18 +3766,18 @@ async function followFunctionLog(gatewayUrl, tenantJwt, funcNameInput, appOverri
|
|
|
3618
3766
|
let res = null;
|
|
3619
3767
|
try {
|
|
3620
3768
|
if (scopedUrl) {
|
|
3621
|
-
res = await
|
|
3769
|
+
res = await authorizedFetch(scopedUrl, {
|
|
3622
3770
|
headers,
|
|
3623
3771
|
signal: controller.signal
|
|
3624
3772
|
});
|
|
3625
3773
|
if (res.status === 404) {
|
|
3626
3774
|
if (isVerbose) console.error(`[wawesome:verbose] 404 on app-scoped route, retrying unscoped.`);
|
|
3627
|
-
res = await
|
|
3775
|
+
res = await authorizedFetch(unscopedUrl, {
|
|
3628
3776
|
headers,
|
|
3629
3777
|
signal: controller.signal
|
|
3630
3778
|
});
|
|
3631
3779
|
}
|
|
3632
|
-
} else res = await
|
|
3780
|
+
} else res = await authorizedFetch(unscopedUrl, {
|
|
3633
3781
|
headers,
|
|
3634
3782
|
signal: controller.signal
|
|
3635
3783
|
});
|
|
@@ -3733,7 +3881,7 @@ function printOutcome(meta) {
|
|
|
3733
3881
|
async function triggerRun(gatewayUrl, tenantJwt, funcName, appSlug, appOverride, payload, isVerbose) {
|
|
3734
3882
|
const url = appSlug ? `${gatewayUrl}/v1/apps/${encodeURIComponent(appSlug)}/functions/${encodeURIComponent(funcName)}/runs` : `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/runs`;
|
|
3735
3883
|
if (isVerbose) console.log(`[wawesome:verbose] POST ${url}`);
|
|
3736
|
-
let res = await
|
|
3884
|
+
let res = await authorizedFetch(url, {
|
|
3737
3885
|
method: "POST",
|
|
3738
3886
|
headers: {
|
|
3739
3887
|
Authorization: `Bearer ${tenantJwt}`,
|
|
@@ -3745,7 +3893,7 @@ async function triggerRun(gatewayUrl, tenantJwt, funcName, appSlug, appOverride,
|
|
|
3745
3893
|
const fallbackUrl = `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/runs`;
|
|
3746
3894
|
if (isVerbose) console.log(`[wawesome:verbose] 404 on app-scoped route. Retrying unscoped: POST ${fallbackUrl}`);
|
|
3747
3895
|
try {
|
|
3748
|
-
const fallbackRes = await
|
|
3896
|
+
const fallbackRes = await authorizedFetch(fallbackUrl, {
|
|
3749
3897
|
method: "POST",
|
|
3750
3898
|
headers: {
|
|
3751
3899
|
Authorization: `Bearer ${tenantJwt}`,
|
|
@@ -3761,7 +3909,7 @@ async function triggerRun(gatewayUrl, tenantJwt, funcName, appSlug, appOverride,
|
|
|
3761
3909
|
async function fetchInvocationMetadata(gatewayUrl, tenantJwt, invocationId, isVerbose) {
|
|
3762
3910
|
const url = `${gatewayUrl}/v1/invocations/${encodeURIComponent(invocationId)}`;
|
|
3763
3911
|
if (isVerbose) console.log(`[wawesome:verbose] GET ${url}`);
|
|
3764
|
-
const res = await
|
|
3912
|
+
const res = await authorizedFetch(url, {
|
|
3765
3913
|
method: "GET",
|
|
3766
3914
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
3767
3915
|
});
|
|
@@ -3771,7 +3919,7 @@ async function fetchInvocationMetadata(gatewayUrl, tenantJwt, invocationId, isVe
|
|
|
3771
3919
|
async function fetchInvocationLogs(gatewayUrl, tenantJwt, invocationId, isVerbose) {
|
|
3772
3920
|
const url = `${gatewayUrl}/v1/invocations/${encodeURIComponent(invocationId)}/logs`;
|
|
3773
3921
|
if (isVerbose) console.log(`[wawesome:verbose] GET ${url}`);
|
|
3774
|
-
const res = await
|
|
3922
|
+
const res = await authorizedFetch(url, {
|
|
3775
3923
|
method: "GET",
|
|
3776
3924
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
3777
3925
|
});
|
|
@@ -3795,7 +3943,7 @@ async function followRun(gatewayUrl, tenantJwt, invocationId, isVerbose, pollInt
|
|
|
3795
3943
|
if (controller.signal.aborted) return;
|
|
3796
3944
|
let res = null;
|
|
3797
3945
|
try {
|
|
3798
|
-
res = await
|
|
3946
|
+
res = await authorizedFetch(streamUrl, {
|
|
3799
3947
|
method: "GET",
|
|
3800
3948
|
headers: {
|
|
3801
3949
|
Authorization: `Bearer ${tenantJwt}`,
|
|
@@ -4145,7 +4293,7 @@ function formatRunHistoryTable(runs) {
|
|
|
4145
4293
|
async function fetchFunctionSchedules(gatewayUrl, tenantJwt, funcName, appSlug, isVerbose) {
|
|
4146
4294
|
const scopedUrl = appSlug ? `${gatewayUrl}/v1/apps/${encodeURIComponent(appSlug)}/functions/${encodeURIComponent(funcName)}/schedules` : `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/schedules`;
|
|
4147
4295
|
if (isVerbose) console.log(`[wawesome:verbose] GET ${scopedUrl}`);
|
|
4148
|
-
let res = await
|
|
4296
|
+
let res = await authorizedFetch(scopedUrl, {
|
|
4149
4297
|
method: "GET",
|
|
4150
4298
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
4151
4299
|
});
|
|
@@ -4153,7 +4301,7 @@ async function fetchFunctionSchedules(gatewayUrl, tenantJwt, funcName, appSlug,
|
|
|
4153
4301
|
const fallbackUrl = `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/schedules`;
|
|
4154
4302
|
if (isVerbose) console.log(`[wawesome:verbose] 404 on app-scoped route. Retrying unscoped: GET ${fallbackUrl}`);
|
|
4155
4303
|
try {
|
|
4156
|
-
const fallbackRes = await
|
|
4304
|
+
const fallbackRes = await authorizedFetch(fallbackUrl, {
|
|
4157
4305
|
method: "GET",
|
|
4158
4306
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
4159
4307
|
});
|
|
@@ -4167,7 +4315,7 @@ async function fetchFunctionSchedules(gatewayUrl, tenantJwt, funcName, appSlug,
|
|
|
4167
4315
|
async function fetchAppFunctions(gatewayUrl, tenantJwt, appSlug, isVerbose) {
|
|
4168
4316
|
const url = `${gatewayUrl}/v1/apps/${encodeURIComponent(appSlug)}/functions`;
|
|
4169
4317
|
if (isVerbose) console.log(`[wawesome:verbose] GET ${url}`);
|
|
4170
|
-
const res = await
|
|
4318
|
+
const res = await authorizedFetch(url, {
|
|
4171
4319
|
method: "GET",
|
|
4172
4320
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
4173
4321
|
});
|
|
@@ -4178,7 +4326,7 @@ async function pauseScheduleApi(gatewayUrl, tenantJwt, funcName, scheduleName, a
|
|
|
4178
4326
|
const scopedUrl = appSlug ? `${gatewayUrl}/v1/apps/${encodeURIComponent(appSlug)}/functions/${encodeURIComponent(funcName)}/schedules/${encodeURIComponent(scheduleName)}/pause` : `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/schedules/${encodeURIComponent(scheduleName)}/pause`;
|
|
4179
4327
|
const body = reason?.trim() ? JSON.stringify({ reason: reason.trim() }) : void 0;
|
|
4180
4328
|
if (isVerbose) console.log(`[wawesome:verbose] POST ${scopedUrl}`);
|
|
4181
|
-
let res = await
|
|
4329
|
+
let res = await authorizedFetch(scopedUrl, {
|
|
4182
4330
|
method: "POST",
|
|
4183
4331
|
headers: {
|
|
4184
4332
|
Authorization: `Bearer ${tenantJwt}`,
|
|
@@ -4190,7 +4338,7 @@ async function pauseScheduleApi(gatewayUrl, tenantJwt, funcName, scheduleName, a
|
|
|
4190
4338
|
const fallbackUrl = `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/schedules/${encodeURIComponent(scheduleName)}/pause`;
|
|
4191
4339
|
if (isVerbose) console.log(`[wawesome:verbose] 404 on app-scoped route. Retrying unscoped: POST ${fallbackUrl}`);
|
|
4192
4340
|
try {
|
|
4193
|
-
const fallbackRes = await
|
|
4341
|
+
const fallbackRes = await authorizedFetch(fallbackUrl, {
|
|
4194
4342
|
method: "POST",
|
|
4195
4343
|
headers: {
|
|
4196
4344
|
Authorization: `Bearer ${tenantJwt}`,
|
|
@@ -4206,7 +4354,7 @@ async function pauseScheduleApi(gatewayUrl, tenantJwt, funcName, scheduleName, a
|
|
|
4206
4354
|
async function resumeScheduleApi(gatewayUrl, tenantJwt, funcName, scheduleName, appSlug, isVerbose) {
|
|
4207
4355
|
const scopedUrl = appSlug ? `${gatewayUrl}/v1/apps/${encodeURIComponent(appSlug)}/functions/${encodeURIComponent(funcName)}/schedules/${encodeURIComponent(scheduleName)}/resume` : `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/schedules/${encodeURIComponent(scheduleName)}/resume`;
|
|
4208
4356
|
if (isVerbose) console.log(`[wawesome:verbose] POST ${scopedUrl}`);
|
|
4209
|
-
let res = await
|
|
4357
|
+
let res = await authorizedFetch(scopedUrl, {
|
|
4210
4358
|
method: "POST",
|
|
4211
4359
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
4212
4360
|
});
|
|
@@ -4214,7 +4362,7 @@ async function resumeScheduleApi(gatewayUrl, tenantJwt, funcName, scheduleName,
|
|
|
4214
4362
|
const fallbackUrl = `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/schedules/${encodeURIComponent(scheduleName)}/resume`;
|
|
4215
4363
|
if (isVerbose) console.log(`[wawesome:verbose] 404 on app-scoped route. Retrying unscoped: POST ${fallbackUrl}`);
|
|
4216
4364
|
try {
|
|
4217
|
-
const fallbackRes = await
|
|
4365
|
+
const fallbackRes = await authorizedFetch(fallbackUrl, {
|
|
4218
4366
|
method: "POST",
|
|
4219
4367
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
4220
4368
|
});
|
|
@@ -4231,7 +4379,7 @@ async function fetchBackgroundRunsApi(gatewayUrl, tenantJwt, funcName, appSlug,
|
|
|
4231
4379
|
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
4232
4380
|
const scopedUrl = appSlug ? `${gatewayUrl}/v1/apps/${encodeURIComponent(appSlug)}/functions/${encodeURIComponent(funcName)}/runs${qs}` : `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/runs${qs}`;
|
|
4233
4381
|
if (isVerbose) console.log(`[wawesome:verbose] GET ${scopedUrl}`);
|
|
4234
|
-
let res = await
|
|
4382
|
+
let res = await authorizedFetch(scopedUrl, {
|
|
4235
4383
|
method: "GET",
|
|
4236
4384
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
4237
4385
|
});
|
|
@@ -4239,7 +4387,7 @@ async function fetchBackgroundRunsApi(gatewayUrl, tenantJwt, funcName, appSlug,
|
|
|
4239
4387
|
const fallbackUrl = `${gatewayUrl}/v1/functions/${encodeURIComponent(funcName)}/runs${qs}`;
|
|
4240
4388
|
if (isVerbose) console.log(`[wawesome:verbose] 404 on app-scoped route. Retrying unscoped: GET ${fallbackUrl}`);
|
|
4241
4389
|
try {
|
|
4242
|
-
const fallbackRes = await
|
|
4390
|
+
const fallbackRes = await authorizedFetch(fallbackUrl, {
|
|
4243
4391
|
method: "GET",
|
|
4244
4392
|
headers: { Authorization: `Bearer ${tenantJwt}` }
|
|
4245
4393
|
});
|