@stackable-labs/cli-app-extension 1.16.0 → 1.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.
- package/dist/index.js +182 -27
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.tsx
|
|
4
4
|
import { createRequire } from "module";
|
|
5
|
+
import { createServer } from "http";
|
|
5
6
|
import { program } from "commander";
|
|
6
7
|
import { render } from "ink";
|
|
8
|
+
import open from "open";
|
|
7
9
|
|
|
8
10
|
// src/App.tsx
|
|
9
11
|
import { join as join3 } from "path";
|
|
@@ -752,9 +754,17 @@ import { useEffect as useEffect2, useState as useState6 } from "react";
|
|
|
752
754
|
// src/lib/api.ts
|
|
753
755
|
var DEFAULT_ADMIN_API_URL = "https://api-use1.stackablelabs.io/admin";
|
|
754
756
|
var getAdminApiBaseUrl = () => process.env.ADMIN_API_BASE_URL ?? DEFAULT_ADMIN_API_URL;
|
|
755
|
-
var
|
|
757
|
+
var CLI_CLIENT_NAME = "@stackable-labs/cli-app-extension";
|
|
758
|
+
var authHeaders = (token) => ({
|
|
759
|
+
authorization: `Bearer ${token}`,
|
|
760
|
+
"content-type": "application/json",
|
|
761
|
+
"x-client-name": CLI_CLIENT_NAME
|
|
762
|
+
});
|
|
763
|
+
var fetchApps = async (token) => {
|
|
756
764
|
const baseUrl = getAdminApiBaseUrl();
|
|
757
|
-
const res = await fetch(`${baseUrl}/app-extension
|
|
765
|
+
const res = await fetch(`${baseUrl}/app-extension`, {
|
|
766
|
+
headers: authHeaders(token)
|
|
767
|
+
});
|
|
758
768
|
if (!res.ok) {
|
|
759
769
|
throw new Error(`Failed to fetch apps${baseUrl !== DEFAULT_ADMIN_API_URL ? ` (from ${baseUrl})` : ""}: ${res.status} ${res.statusText}`);
|
|
760
770
|
}
|
|
@@ -767,11 +777,11 @@ var fetchApps = async () => {
|
|
|
767
777
|
iconUrl
|
|
768
778
|
}));
|
|
769
779
|
};
|
|
770
|
-
var createExtensionRemote = async (appId, payload) => {
|
|
780
|
+
var createExtensionRemote = async (appId, payload, token) => {
|
|
771
781
|
const baseUrl = getAdminApiBaseUrl();
|
|
772
782
|
const res = await fetch(`${baseUrl}/app-extension/${appId}/extensions`, {
|
|
773
783
|
method: "POST",
|
|
774
|
-
headers:
|
|
784
|
+
headers: authHeaders(token),
|
|
775
785
|
body: JSON.stringify(payload)
|
|
776
786
|
});
|
|
777
787
|
if (!res.ok) {
|
|
@@ -780,9 +790,11 @@ var createExtensionRemote = async (appId, payload) => {
|
|
|
780
790
|
}
|
|
781
791
|
return res.json();
|
|
782
792
|
};
|
|
783
|
-
var fetchExtensions = async (appId) => {
|
|
793
|
+
var fetchExtensions = async (appId, token) => {
|
|
784
794
|
const baseUrl = getAdminApiBaseUrl();
|
|
785
|
-
const res = await fetch(`${baseUrl}/app-extension/${appId}/extensions
|
|
795
|
+
const res = await fetch(`${baseUrl}/app-extension/${appId}/extensions`, {
|
|
796
|
+
headers: authHeaders(token)
|
|
797
|
+
});
|
|
786
798
|
if (!res.ok) {
|
|
787
799
|
throw new Error(`Failed to fetch Extensions: ${res.status} ${res.statusText}`);
|
|
788
800
|
}
|
|
@@ -800,11 +812,11 @@ var fetchExtensions = async (appId) => {
|
|
|
800
812
|
])
|
|
801
813
|
);
|
|
802
814
|
};
|
|
803
|
-
var updateExtension = async (appId, extensionId, payload) => {
|
|
815
|
+
var updateExtension = async (appId, extensionId, payload, token) => {
|
|
804
816
|
const baseUrl = getAdminApiBaseUrl();
|
|
805
817
|
const res = await fetch(`${baseUrl}/app-extension/${appId}/extensions/${extensionId}`, {
|
|
806
818
|
method: "PUT",
|
|
807
|
-
headers:
|
|
819
|
+
headers: authHeaders(token),
|
|
808
820
|
body: JSON.stringify(payload)
|
|
809
821
|
});
|
|
810
822
|
if (!res.ok) {
|
|
@@ -859,13 +871,13 @@ var Banner = () => {
|
|
|
859
871
|
|
|
860
872
|
// src/components/AppSelect.tsx
|
|
861
873
|
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
862
|
-
var AppSelect = ({ onSubmit }) => {
|
|
874
|
+
var AppSelect = ({ token, onSubmit }) => {
|
|
863
875
|
const [apps, setApps] = useState6([]);
|
|
864
876
|
const [loading, setLoading] = useState6(true);
|
|
865
877
|
const [error, setError] = useState6();
|
|
866
878
|
const [cursor, setCursor] = useState6(0);
|
|
867
879
|
useEffect2(() => {
|
|
868
|
-
fetchApps().then(setApps).catch((err) => setError(err instanceof Error ? err.message : String(err))).finally(() => setLoading(false));
|
|
880
|
+
fetchApps(token).then(setApps).catch((err) => setError(err instanceof Error ? err.message : String(err))).finally(() => setLoading(false));
|
|
869
881
|
}, []);
|
|
870
882
|
useInput6((_, key) => {
|
|
871
883
|
if (loading || error || apps.length === 0) return;
|
|
@@ -917,13 +929,13 @@ import { Box as Box12, Text as Text12, useInput as useInput7 } from "ink";
|
|
|
917
929
|
import Spinner3 from "ink-spinner";
|
|
918
930
|
import { useEffect as useEffect3, useState as useState7 } from "react";
|
|
919
931
|
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
920
|
-
var ExtensionSelect = ({ appId, command, onSubmit, onBack }) => {
|
|
932
|
+
var ExtensionSelect = ({ appId, token, command, onSubmit, onBack }) => {
|
|
921
933
|
const [extensions, setExtensions] = useState7([]);
|
|
922
934
|
const [loading, setLoading] = useState7(true);
|
|
923
935
|
const [error, setError] = useState7();
|
|
924
936
|
const [cursor, setCursor] = useState7(0);
|
|
925
937
|
useEffect3(() => {
|
|
926
|
-
fetchExtensions(appId).then((byId) => setExtensions(Object.values(byId))).catch((err) => setError(err instanceof Error ? err.message : String(err))).finally(() => setLoading(false));
|
|
938
|
+
fetchExtensions(appId, token).then((byId) => setExtensions(Object.values(byId))).catch((err) => setError(err instanceof Error ? err.message : String(err))).finally(() => setLoading(false));
|
|
927
939
|
}, [appId]);
|
|
928
940
|
useInput7((_, key) => {
|
|
929
941
|
if (key.upArrow) {
|
|
@@ -1074,6 +1086,7 @@ var readDevContext = async (projectRoot) => {
|
|
|
1074
1086
|
appId: stackableEnv.APP_ID || null,
|
|
1075
1087
|
extensionId: stackableEnv.EXTENSION_ID || null,
|
|
1076
1088
|
appName: stackableEnv.APP_NAME || null,
|
|
1089
|
+
orgId: stackableEnv.ORG_ID || null,
|
|
1077
1090
|
extensionPort,
|
|
1078
1091
|
previewPort
|
|
1079
1092
|
};
|
|
@@ -1498,7 +1511,7 @@ var derivePermissions2 = (targets) => {
|
|
|
1498
1511
|
}
|
|
1499
1512
|
return [...permissions];
|
|
1500
1513
|
};
|
|
1501
|
-
var App = ({ command, initialName, initialExtensionId, options }) => {
|
|
1514
|
+
var App = ({ command, token, initialName, initialExtensionId, options }) => {
|
|
1502
1515
|
const { exit } = useApp();
|
|
1503
1516
|
const [step, setStep] = useState8("app");
|
|
1504
1517
|
const [name, setName] = useState8(initialName ?? options?.name ?? "");
|
|
@@ -1636,7 +1649,7 @@ var App = ({ command, initialName, initialExtensionId, options }) => {
|
|
|
1636
1649
|
},
|
|
1637
1650
|
bundleUrl: bundleUrl || void 0,
|
|
1638
1651
|
enabled
|
|
1639
|
-
});
|
|
1652
|
+
}, token);
|
|
1640
1653
|
updateStep(0, "done");
|
|
1641
1654
|
setExtensionVersion(resolvedVersion);
|
|
1642
1655
|
setStep("updateDone");
|
|
@@ -1664,7 +1677,7 @@ var App = ({ command, initialName, initialExtensionId, options }) => {
|
|
|
1664
1677
|
allowedDomains: []
|
|
1665
1678
|
},
|
|
1666
1679
|
bundleUrl: `http://localhost:${extensionPort}`
|
|
1667
|
-
});
|
|
1680
|
+
}, token);
|
|
1668
1681
|
resolvedExtensionId = created.id;
|
|
1669
1682
|
setExtensionId(created.id);
|
|
1670
1683
|
updateStep(0, "done");
|
|
@@ -1703,13 +1716,14 @@ var App = ({ command, initialName, initialExtensionId, options }) => {
|
|
|
1703
1716
|
};
|
|
1704
1717
|
switch (step) {
|
|
1705
1718
|
case "app": {
|
|
1706
|
-
return /* @__PURE__ */ jsx13(AppSelect, { onSubmit: handleAppSelect });
|
|
1719
|
+
return /* @__PURE__ */ jsx13(AppSelect, { token, onSubmit: handleAppSelect });
|
|
1707
1720
|
}
|
|
1708
1721
|
case "extensionSelect": {
|
|
1709
1722
|
return /* @__PURE__ */ jsx13(
|
|
1710
1723
|
ExtensionSelect,
|
|
1711
1724
|
{
|
|
1712
1725
|
appId: selectedApp.id,
|
|
1726
|
+
token,
|
|
1713
1727
|
command,
|
|
1714
1728
|
onSubmit: handleExtensionSelect,
|
|
1715
1729
|
onBack: goBack
|
|
@@ -1880,7 +1894,7 @@ var startDevServer = (projectRoot) => {
|
|
|
1880
1894
|
import { Box as Box14, Text as Text14 } from "ink";
|
|
1881
1895
|
import { useState as useState9, useEffect as useEffect4 } from "react";
|
|
1882
1896
|
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1883
|
-
var DevSetup = ({ initialContext, onReady }) => {
|
|
1897
|
+
var DevSetup = ({ initialContext, token, onReady }) => {
|
|
1884
1898
|
const [step, setStep] = useState9("app");
|
|
1885
1899
|
const [selectedApp, setSelectedApp] = useState9(null);
|
|
1886
1900
|
useEffect4(() => {
|
|
@@ -1902,7 +1916,7 @@ var DevSetup = ({ initialContext, onReady }) => {
|
|
|
1902
1916
|
if (step === "app") {
|
|
1903
1917
|
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
1904
1918
|
/* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { children: "Select the App for your extension:" }) }),
|
|
1905
|
-
/* @__PURE__ */ jsx14(AppSelect, { onSubmit: handleAppSelect })
|
|
1919
|
+
/* @__PURE__ */ jsx14(AppSelect, { token, onSubmit: handleAppSelect })
|
|
1906
1920
|
] });
|
|
1907
1921
|
}
|
|
1908
1922
|
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
@@ -1911,6 +1925,7 @@ var DevSetup = ({ initialContext, onReady }) => {
|
|
|
1911
1925
|
ExtensionSelect,
|
|
1912
1926
|
{
|
|
1913
1927
|
appId: selectedApp?.id || initialContext.appId,
|
|
1928
|
+
token,
|
|
1914
1929
|
onSubmit: handleExtensionSelect
|
|
1915
1930
|
}
|
|
1916
1931
|
)
|
|
@@ -2015,7 +2030,7 @@ var DevDashboard = ({
|
|
|
2015
2030
|
|
|
2016
2031
|
// src/components/DevApp.tsx
|
|
2017
2032
|
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
2018
|
-
var DevApp = ({ options = {} }) => {
|
|
2033
|
+
var DevApp = ({ token, options = {} }) => {
|
|
2019
2034
|
const [state, setState] = useState10("setup");
|
|
2020
2035
|
const [devContext, setDevContext] = useState10(null);
|
|
2021
2036
|
const [resolvedContext, setResolvedContext] = useState10(null);
|
|
@@ -2114,6 +2129,7 @@ var DevApp = ({ options = {} }) => {
|
|
|
2114
2129
|
DevSetup,
|
|
2115
2130
|
{
|
|
2116
2131
|
initialContext: devContext,
|
|
2132
|
+
token,
|
|
2117
2133
|
onReady: handleSetupReady
|
|
2118
2134
|
}
|
|
2119
2135
|
);
|
|
@@ -2142,6 +2158,54 @@ var DevApp = ({ options = {} }) => {
|
|
|
2142
2158
|
return /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(Text16, { children: "Loading..." }) });
|
|
2143
2159
|
};
|
|
2144
2160
|
|
|
2161
|
+
// src/lib/auth.ts
|
|
2162
|
+
import { readFile as readFile3, writeFile as writeFile3, mkdir, unlink } from "fs/promises";
|
|
2163
|
+
import { join as join4 } from "path";
|
|
2164
|
+
import { homedir } from "os";
|
|
2165
|
+
var AUTH_DIR = join4(homedir(), ".stackable");
|
|
2166
|
+
var AUTH_FILE = join4(AUTH_DIR, "auth.json");
|
|
2167
|
+
var readAuthState = async () => {
|
|
2168
|
+
try {
|
|
2169
|
+
const content = await readFile3(AUTH_FILE, "utf8");
|
|
2170
|
+
return JSON.parse(content);
|
|
2171
|
+
} catch {
|
|
2172
|
+
return null;
|
|
2173
|
+
}
|
|
2174
|
+
};
|
|
2175
|
+
var writeAuthState = async (state) => {
|
|
2176
|
+
await mkdir(AUTH_DIR, { recursive: true, mode: 448 });
|
|
2177
|
+
await writeFile3(AUTH_FILE, JSON.stringify(state, null, 2), { mode: 384 });
|
|
2178
|
+
};
|
|
2179
|
+
var clearAuthState = async () => {
|
|
2180
|
+
try {
|
|
2181
|
+
await unlink(AUTH_FILE);
|
|
2182
|
+
} catch {
|
|
2183
|
+
}
|
|
2184
|
+
};
|
|
2185
|
+
var decodeJwtPayload = (token) => {
|
|
2186
|
+
try {
|
|
2187
|
+
const [, payload] = token.split(".");
|
|
2188
|
+
if (!payload) return null;
|
|
2189
|
+
const json = Buffer.from(payload, "base64url").toString("utf8");
|
|
2190
|
+
return JSON.parse(json);
|
|
2191
|
+
} catch {
|
|
2192
|
+
return null;
|
|
2193
|
+
}
|
|
2194
|
+
};
|
|
2195
|
+
var getToken = async () => {
|
|
2196
|
+
const state = await readAuthState();
|
|
2197
|
+
if (!state) {
|
|
2198
|
+
throw new Error("Not authenticated. Run `stackable auth login` first.");
|
|
2199
|
+
}
|
|
2200
|
+
const payload = decodeJwtPayload(state.token);
|
|
2201
|
+
if (payload?.exp && typeof payload.exp === "number") {
|
|
2202
|
+
if (Date.now() >= payload.exp * 1e3) {
|
|
2203
|
+
throw new Error("Session expired. Run `stackable auth login` to re-authenticate.");
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
return state.token;
|
|
2207
|
+
};
|
|
2208
|
+
|
|
2145
2209
|
// src/lib/versionCheck.ts
|
|
2146
2210
|
import https from "https";
|
|
2147
2211
|
var PACKAGE_NAME = "@stackable-labs/cli-app-extension";
|
|
@@ -2195,16 +2259,107 @@ var require2 = createRequire(import.meta.url);
|
|
|
2195
2259
|
var { version } = require2("../package.json");
|
|
2196
2260
|
checkForUpdate(version);
|
|
2197
2261
|
program.name("stackable-app-extension").description("Stackable Labs - App Extension developer CLI").version(version);
|
|
2198
|
-
program.command("create" /* CREATE */).description("Create a new Extension project").argument("[name]", "Extension project name").option("--extension-port <port>", "Extension dev server port (default: 6543)").option("--preview-port <port>", "Preview dev server port").option("--skip-install", "Skip package manager install").option("--skip-git", "Skip git initialization").action((name, options) => {
|
|
2199
|
-
|
|
2262
|
+
program.command("create" /* CREATE */).description("Create a new Extension project").argument("[name]", "Extension project name").option("--extension-port <port>", "Extension dev server port (default: 6543)").option("--preview-port <port>", "Preview dev server port").option("--skip-install", "Skip package manager install").option("--skip-git", "Skip git initialization").action(async (name, options) => {
|
|
2263
|
+
const token = await getToken();
|
|
2264
|
+
render(/* @__PURE__ */ jsx17(App, { command: "create" /* CREATE */, initialName: name, options, token }));
|
|
2265
|
+
});
|
|
2266
|
+
program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project from an existing Extension").option("--extension-port <port>", "Extension dev server port (default: 6543)").option("--preview-port <port>", "Preview dev server port").option("--skip-install", "Skip package manager install").option("--skip-git", "Skip git initialization").action(async (options) => {
|
|
2267
|
+
const token = await getToken();
|
|
2268
|
+
render(/* @__PURE__ */ jsx17(App, { command: "scaffold" /* SCAFFOLD */, options, token }));
|
|
2269
|
+
});
|
|
2270
|
+
program.command("update" /* UPDATE */).description("Update an existing Extension").argument("[extensionId]", "Extension ID to update").option("--app-id <id>", "Skip App selection").option("--name <name>", "New Extension name").option("--targets <targets>", "Comma-separated target slots (validated against app)").option("--bundle-url <url>", "New bundle URL").option("--enabled <bool>", "Enable/disable Extension").option("--set-version <version>", "Explicit version (skips auto-compute)").action(async (extensionId, options) => {
|
|
2271
|
+
const token = await getToken();
|
|
2272
|
+
render(/* @__PURE__ */ jsx17(App, { command: "update" /* UPDATE */, initialExtensionId: extensionId, options, token }));
|
|
2200
2273
|
});
|
|
2201
|
-
program.command("
|
|
2202
|
-
|
|
2274
|
+
program.command("dev" /* DEV */).description("Start dev servers with a public tunnel").option("--dir <path>", "Project root (default: cwd)").option("--extension-port <port>", "Override Extension port").option("--preview-port <port>", "Override Preview port").option("--no-tunnel", "Skip tunnel, just run vite dev").action(async (options) => {
|
|
2275
|
+
const token = await getToken();
|
|
2276
|
+
render(/* @__PURE__ */ jsx17(DevApp, { options, token }), { exitOnCtrlC: false });
|
|
2277
|
+
});
|
|
2278
|
+
var DASHBOARD_URL = process.env.ADMIN_DASHBOARD_URL ?? "https://admin.stackablelabs.io";
|
|
2279
|
+
var auth = program.command("auth").description("Manage CLI authentication");
|
|
2280
|
+
var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2281
|
+
auth.command("login").description("Authenticate with Stackable via browser").action(async () => {
|
|
2282
|
+
let resolveToken;
|
|
2283
|
+
let rejectToken;
|
|
2284
|
+
const tokenPromise = new Promise((resolve, reject) => {
|
|
2285
|
+
resolveToken = resolve;
|
|
2286
|
+
rejectToken = reject;
|
|
2287
|
+
});
|
|
2288
|
+
const server = createServer((req, res) => {
|
|
2289
|
+
const url = new URL(req.url, "http://localhost");
|
|
2290
|
+
if (url.pathname === "/callback") {
|
|
2291
|
+
const error = url.searchParams.get("error");
|
|
2292
|
+
if (error) {
|
|
2293
|
+
res.writeHead(200, { "content-type": "text/html" });
|
|
2294
|
+
res.end("<html><body><h2>Authentication failed \u2014 you can close this tab.</h2></body></html>");
|
|
2295
|
+
rejectToken(new Error(error));
|
|
2296
|
+
return;
|
|
2297
|
+
}
|
|
2298
|
+
const token2 = url.searchParams.get("token");
|
|
2299
|
+
if (token2) {
|
|
2300
|
+
res.writeHead(200, { "content-type": "text/html" });
|
|
2301
|
+
res.end("<html><body><h2>CLI authenticated \u2014 you can close this tab.</h2></body></html>");
|
|
2302
|
+
resolveToken(token2);
|
|
2303
|
+
} else {
|
|
2304
|
+
res.writeHead(400, { "content-type": "text/plain" });
|
|
2305
|
+
res.end("Missing token");
|
|
2306
|
+
}
|
|
2307
|
+
} else {
|
|
2308
|
+
res.writeHead(404);
|
|
2309
|
+
res.end();
|
|
2310
|
+
}
|
|
2311
|
+
});
|
|
2312
|
+
await new Promise((r) => server.listen(0, "127.0.0.1", r));
|
|
2313
|
+
const port = server.address().port;
|
|
2314
|
+
const callbackUrl = `http://localhost:${port}/callback`;
|
|
2315
|
+
const loginUrl = `${DASHBOARD_URL}/cli-auth?callback=${encodeURIComponent(callbackUrl)}`;
|
|
2316
|
+
console.log(`
|
|
2317
|
+
Opening browser to authenticate...
|
|
2318
|
+
${loginUrl}
|
|
2319
|
+
`);
|
|
2320
|
+
await open(loginUrl);
|
|
2321
|
+
const timeout = setTimeout(() => {
|
|
2322
|
+
server.close();
|
|
2323
|
+
rejectToken(new Error("Login timed out. Please try again."));
|
|
2324
|
+
}, LOGIN_TIMEOUT_MS);
|
|
2325
|
+
let token;
|
|
2326
|
+
try {
|
|
2327
|
+
token = await tokenPromise;
|
|
2328
|
+
} catch (err) {
|
|
2329
|
+
clearTimeout(timeout);
|
|
2330
|
+
server.close();
|
|
2331
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
2332
|
+
process.exit(1);
|
|
2333
|
+
}
|
|
2334
|
+
clearTimeout(timeout);
|
|
2335
|
+
server.close();
|
|
2336
|
+
const [, payloadB64] = token.split(".");
|
|
2337
|
+
const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
|
|
2338
|
+
await writeAuthState({
|
|
2339
|
+
token,
|
|
2340
|
+
userId: payload.sub,
|
|
2341
|
+
orgId: payload.orgId,
|
|
2342
|
+
orgSlug: payload.orgSlug
|
|
2343
|
+
});
|
|
2344
|
+
console.log(`Logged in \u2014 org: ${payload.orgSlug ?? payload.orgId}`);
|
|
2203
2345
|
});
|
|
2204
|
-
|
|
2205
|
-
|
|
2346
|
+
auth.command("logout").description("Clear stored CLI credentials").action(async () => {
|
|
2347
|
+
await clearAuthState();
|
|
2348
|
+
console.log("Logged out.");
|
|
2206
2349
|
});
|
|
2207
|
-
|
|
2208
|
-
|
|
2350
|
+
auth.command("status").description("Show current authentication status").action(async () => {
|
|
2351
|
+
const state = await readAuthState();
|
|
2352
|
+
if (!state) {
|
|
2353
|
+
console.log("Not logged in. Run `stackable auth login`.");
|
|
2354
|
+
return;
|
|
2355
|
+
}
|
|
2356
|
+
const [, payloadB64] = state.token.split(".");
|
|
2357
|
+
const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
|
|
2358
|
+
const expiry = payload.exp ? new Date(payload.exp * 1e3) : null;
|
|
2359
|
+
if (expiry && Date.now() >= expiry.getTime()) {
|
|
2360
|
+
console.log(`Session expired (${expiry.toLocaleDateString()}). Run \`stackable auth login\` to re-authenticate.`);
|
|
2361
|
+
return;
|
|
2362
|
+
}
|
|
2363
|
+
console.log(`Logged in \u2014 org: ${state.orgSlug ?? state.orgId}${expiry ? `. Token expires: ${expiry.toLocaleDateString()}.` : ""}`);
|
|
2209
2364
|
});
|
|
2210
2365
|
program.parse(process.argv.filter((arg) => arg !== "--"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackable-labs/cli-app-extension",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"bin": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"ink-spinner": "5.x",
|
|
20
20
|
"ink-text-input": "6.x",
|
|
21
21
|
"nypm": "0.4.x",
|
|
22
|
+
"open": "10.x",
|
|
22
23
|
"react": "18.x"
|
|
23
24
|
},
|
|
24
25
|
"description": "CLI for scaffolding Stackable extension projects.",
|