@stackable-labs/cli-app-extension 1.19.0 → 1.20.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 +319 -120
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -775,7 +775,7 @@ var fetchApps = async (token) => {
|
|
|
775
775
|
iconUrl
|
|
776
776
|
}));
|
|
777
777
|
};
|
|
778
|
-
var createExtensionRemote = async (appId,
|
|
778
|
+
var createExtensionRemote = async (appId, token, payload) => {
|
|
779
779
|
const baseUrl = getAdminApiBaseUrl();
|
|
780
780
|
const res = await fetch(`${baseUrl}/app-extension/${appId}/extensions`, {
|
|
781
781
|
method: "POST",
|
|
@@ -1726,17 +1726,25 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
1726
1726
|
};
|
|
1727
1727
|
switch (step) {
|
|
1728
1728
|
case "app": {
|
|
1729
|
-
return /* @__PURE__ */ jsx13(
|
|
1729
|
+
return /* @__PURE__ */ jsx13(
|
|
1730
|
+
AppSelect,
|
|
1731
|
+
{
|
|
1732
|
+
token,
|
|
1733
|
+
orgId,
|
|
1734
|
+
userId,
|
|
1735
|
+
onSubmit: handleAppSelect
|
|
1736
|
+
}
|
|
1737
|
+
);
|
|
1730
1738
|
}
|
|
1731
1739
|
case "extensionSelect": {
|
|
1732
1740
|
return /* @__PURE__ */ jsx13(
|
|
1733
1741
|
ExtensionSelect,
|
|
1734
1742
|
{
|
|
1735
1743
|
appId: selectedApp.id,
|
|
1736
|
-
token,
|
|
1737
1744
|
command,
|
|
1738
|
-
|
|
1739
|
-
onBack: goBack
|
|
1745
|
+
token,
|
|
1746
|
+
onBack: goBack,
|
|
1747
|
+
onSubmit: handleExtensionSelect
|
|
1740
1748
|
}
|
|
1741
1749
|
);
|
|
1742
1750
|
}
|
|
@@ -1746,8 +1754,8 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
1746
1754
|
{
|
|
1747
1755
|
availableTargets: selectedApp?.targets ?? [],
|
|
1748
1756
|
preSelected: targets,
|
|
1749
|
-
|
|
1750
|
-
|
|
1757
|
+
onBack: goBack,
|
|
1758
|
+
onSubmit: handleConfirmTargets
|
|
1751
1759
|
}
|
|
1752
1760
|
);
|
|
1753
1761
|
}
|
|
@@ -1756,8 +1764,8 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
1756
1764
|
NamePrompt,
|
|
1757
1765
|
{
|
|
1758
1766
|
initialValue: name,
|
|
1759
|
-
|
|
1760
|
-
|
|
1767
|
+
onBack: goBack,
|
|
1768
|
+
onSubmit: handleName
|
|
1761
1769
|
}
|
|
1762
1770
|
);
|
|
1763
1771
|
}
|
|
@@ -1787,10 +1795,10 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
1787
1795
|
{
|
|
1788
1796
|
command,
|
|
1789
1797
|
name,
|
|
1790
|
-
extensionPort,
|
|
1791
|
-
previewPort,
|
|
1792
1798
|
targets,
|
|
1793
1799
|
outputDir,
|
|
1800
|
+
previewPort,
|
|
1801
|
+
extensionPort,
|
|
1794
1802
|
extensionVersion: command !== "create" /* CREATE */ ? extensionVersion : void 0,
|
|
1795
1803
|
bundleUrl: command === "update" /* UPDATE */ ? bundleUrl : void 0,
|
|
1796
1804
|
enabled: command === "update" /* UPDATE */ ? enabled : void 0,
|
|
@@ -1811,9 +1819,9 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
1811
1819
|
{
|
|
1812
1820
|
name,
|
|
1813
1821
|
targets,
|
|
1814
|
-
availableTargets: selectedApp?.targets ?? [],
|
|
1815
|
-
bundleUrl,
|
|
1816
1822
|
enabled,
|
|
1823
|
+
bundleUrl,
|
|
1824
|
+
availableTargets: selectedApp?.targets ?? [],
|
|
1817
1825
|
onSubmit: (updated) => {
|
|
1818
1826
|
setName(updated.name);
|
|
1819
1827
|
setTargets(updated.targets);
|
|
@@ -1866,8 +1874,8 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
1866
1874
|
};
|
|
1867
1875
|
|
|
1868
1876
|
// src/components/DevApp.tsx
|
|
1869
|
-
import { Box as Box16, Text as Text16, useInput as useInput9 } from "ink";
|
|
1870
1877
|
import { useRef, useState as useState10, useEffect as useEffect6, useCallback as useCallback2 } from "react";
|
|
1878
|
+
import { useInput as useInput9, Box as Box16, Text as Text16 } from "ink";
|
|
1871
1879
|
|
|
1872
1880
|
// src/lib/tunnel.ts
|
|
1873
1881
|
import { Tunnel } from "cloudflared";
|
|
@@ -1926,7 +1934,13 @@ var DevSetup = ({ initialContext, token, onReady }) => {
|
|
|
1926
1934
|
if (step === "app") {
|
|
1927
1935
|
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
1928
1936
|
/* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { children: "Select the App for your extension:" }) }),
|
|
1929
|
-
/* @__PURE__ */ jsx14(
|
|
1937
|
+
/* @__PURE__ */ jsx14(
|
|
1938
|
+
AppSelect,
|
|
1939
|
+
{
|
|
1940
|
+
token,
|
|
1941
|
+
onSubmit: handleAppSelect
|
|
1942
|
+
}
|
|
1943
|
+
)
|
|
1930
1944
|
] });
|
|
1931
1945
|
}
|
|
1932
1946
|
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
@@ -1934,8 +1948,8 @@ var DevSetup = ({ initialContext, token, onReady }) => {
|
|
|
1934
1948
|
/* @__PURE__ */ jsx14(
|
|
1935
1949
|
ExtensionSelect,
|
|
1936
1950
|
{
|
|
1937
|
-
appId: selectedApp?.id || initialContext.appId,
|
|
1938
1951
|
token,
|
|
1952
|
+
appId: selectedApp?.id || initialContext.appId,
|
|
1939
1953
|
onSubmit: handleExtensionSelect
|
|
1940
1954
|
}
|
|
1941
1955
|
)
|
|
@@ -1947,16 +1961,16 @@ import { Box as Box15, Text as Text15, useInput as useInput8 } from "ink";
|
|
|
1947
1961
|
import { useEffect as useEffect5 } from "react";
|
|
1948
1962
|
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1949
1963
|
var DevDashboard = ({
|
|
1964
|
+
previewTunnelUrl,
|
|
1965
|
+
tunnelUrl,
|
|
1950
1966
|
userId,
|
|
1951
1967
|
orgId,
|
|
1952
|
-
extensionName,
|
|
1953
|
-
extensionId,
|
|
1954
1968
|
appId,
|
|
1955
1969
|
appName,
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
previewPort,
|
|
1970
|
+
extensionId,
|
|
1971
|
+
extensionName,
|
|
1959
1972
|
extensionPort,
|
|
1973
|
+
previewPort,
|
|
1960
1974
|
onQuit
|
|
1961
1975
|
}) => {
|
|
1962
1976
|
useEffect5(() => {
|
|
@@ -2149,8 +2163,8 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
|
|
|
2149
2163
|
return /* @__PURE__ */ jsx16(
|
|
2150
2164
|
DevSetup,
|
|
2151
2165
|
{
|
|
2152
|
-
initialContext: devContext,
|
|
2153
2166
|
token,
|
|
2167
|
+
initialContext: devContext,
|
|
2154
2168
|
onReady: handleSetupReady
|
|
2155
2169
|
}
|
|
2156
2170
|
);
|
|
@@ -2161,16 +2175,16 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
|
|
|
2161
2175
|
return /* @__PURE__ */ jsx16(
|
|
2162
2176
|
DevDashboard,
|
|
2163
2177
|
{
|
|
2164
|
-
|
|
2178
|
+
previewTunnelUrl,
|
|
2179
|
+
tunnelUrl,
|
|
2165
2180
|
orgId,
|
|
2166
|
-
|
|
2167
|
-
extensionId: resolvedContext.extensionId,
|
|
2181
|
+
userId,
|
|
2168
2182
|
appId: resolvedContext.appId,
|
|
2169
2183
|
appName: resolvedContext.appName,
|
|
2184
|
+
extensionName: devContext.extensionName,
|
|
2185
|
+
extensionId: resolvedContext.extensionId,
|
|
2170
2186
|
extensionPort: options.extensionPort ? parseInt(options.extensionPort, 10) : devContext.extensionPort,
|
|
2171
2187
|
previewPort: options.previewPort ? parseInt(options.previewPort, 10) : devContext.previewPort,
|
|
2172
|
-
tunnelUrl,
|
|
2173
|
-
previewTunnelUrl,
|
|
2174
2188
|
onQuit: handleQuit
|
|
2175
2189
|
}
|
|
2176
2190
|
);
|
|
@@ -2181,19 +2195,138 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
|
|
|
2181
2195
|
return /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(Text16, { children: "Loading..." }) });
|
|
2182
2196
|
};
|
|
2183
2197
|
|
|
2184
|
-
// src/components/
|
|
2185
|
-
import { createServer } from "http";
|
|
2198
|
+
// src/components/AIScaffold.tsx
|
|
2186
2199
|
import { Box as Box17, Text as Text17, useApp as useApp2 } from "ink";
|
|
2187
2200
|
import Spinner4 from "ink-spinner";
|
|
2188
|
-
import open from "open";
|
|
2189
2201
|
import { useState as useState11, useEffect as useEffect7 } from "react";
|
|
2190
2202
|
|
|
2203
|
+
// src/lib/aiDocs.ts
|
|
2204
|
+
import { existsSync, readFileSync } from "fs";
|
|
2205
|
+
import { join as join4, dirname } from "path";
|
|
2206
|
+
import { mkdir, writeFile as writeFile3 } from "fs/promises";
|
|
2207
|
+
import AdmZip from "adm-zip";
|
|
2208
|
+
var DEFAULT_STATIC_CDN_URL = "https://static.stackablelabs.io";
|
|
2209
|
+
var AI_DOCS_FILENAME = "extension-ai-docs.zip";
|
|
2210
|
+
var getStaticCdnBaseUrl = () => process.env.STATIC_CDN_BASE_URL ?? DEFAULT_STATIC_CDN_URL;
|
|
2211
|
+
var isValidManifest = (data) => {
|
|
2212
|
+
if (!data || typeof data !== "object") return false;
|
|
2213
|
+
const m = data;
|
|
2214
|
+
return typeof m.name === "string" && m.name.length > 0 && typeof m.version === "string" && Array.isArray(m.targets) && Array.isArray(m.permissions) && Array.isArray(m.allowedDomains);
|
|
2215
|
+
};
|
|
2216
|
+
var isExtensionProject = (dir) => {
|
|
2217
|
+
const manifestPath = join4(dir, "packages/extension/public/manifest.json");
|
|
2218
|
+
if (!existsSync(manifestPath)) {
|
|
2219
|
+
return { valid: false, reason: "No manifest.json found at packages/extension/public/manifest.json \u2014 is this an Extension project?" };
|
|
2220
|
+
}
|
|
2221
|
+
try {
|
|
2222
|
+
const raw = readFileSync(manifestPath, "utf8");
|
|
2223
|
+
const data = JSON.parse(raw);
|
|
2224
|
+
if (!isValidManifest(data)) {
|
|
2225
|
+
return { valid: false, reason: "Invalid manifest: missing required fields (name, version, targets, permissions, allowedDomains)" };
|
|
2226
|
+
}
|
|
2227
|
+
} catch {
|
|
2228
|
+
return { valid: false, reason: "Failed to parse manifest.json" };
|
|
2229
|
+
}
|
|
2230
|
+
return { valid: true };
|
|
2231
|
+
};
|
|
2232
|
+
var downloadAndExtractAiDocs = async (targetDir, version2) => {
|
|
2233
|
+
const baseUrl = getStaticCdnBaseUrl();
|
|
2234
|
+
const zipUrl = `${baseUrl}/ai-docs/${version2}/${AI_DOCS_FILENAME}`;
|
|
2235
|
+
const response = await fetch(zipUrl);
|
|
2236
|
+
if (!response.ok) {
|
|
2237
|
+
throw new Error(`Failed to download AI docs from ${zipUrl}: ${response.status} ${response.statusText}`);
|
|
2238
|
+
}
|
|
2239
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
2240
|
+
const zip = new AdmZip(buffer);
|
|
2241
|
+
const entries = zip.getEntries();
|
|
2242
|
+
const extractedFiles = [];
|
|
2243
|
+
for (const entry of entries) {
|
|
2244
|
+
if (entry.isDirectory) continue;
|
|
2245
|
+
const targetPath = join4(targetDir, entry.entryName);
|
|
2246
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
2247
|
+
await writeFile3(targetPath, entry.getData());
|
|
2248
|
+
extractedFiles.push(entry.entryName);
|
|
2249
|
+
}
|
|
2250
|
+
return { files: extractedFiles.sort() };
|
|
2251
|
+
};
|
|
2252
|
+
|
|
2253
|
+
// src/components/AIScaffold.tsx
|
|
2254
|
+
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2255
|
+
var AIScaffold = ({ version: version2 }) => {
|
|
2256
|
+
const { exit } = useApp2();
|
|
2257
|
+
const [state, setState] = useState11("validating");
|
|
2258
|
+
const [files, setFiles] = useState11([]);
|
|
2259
|
+
const [errorMessage, setErrorMessage] = useState11("");
|
|
2260
|
+
useEffect7(() => {
|
|
2261
|
+
const run = async () => {
|
|
2262
|
+
const projectDir = process.cwd();
|
|
2263
|
+
const check = isExtensionProject(projectDir);
|
|
2264
|
+
if (!check.valid) {
|
|
2265
|
+
setErrorMessage(check.reason);
|
|
2266
|
+
setState("error");
|
|
2267
|
+
exit();
|
|
2268
|
+
return;
|
|
2269
|
+
}
|
|
2270
|
+
setState("downloading");
|
|
2271
|
+
try {
|
|
2272
|
+
const result = await downloadAndExtractAiDocs(projectDir, version2);
|
|
2273
|
+
setFiles(result.files);
|
|
2274
|
+
setState("done");
|
|
2275
|
+
} catch (err) {
|
|
2276
|
+
setErrorMessage(err instanceof Error ? err.message : String(err));
|
|
2277
|
+
setState("error");
|
|
2278
|
+
}
|
|
2279
|
+
exit();
|
|
2280
|
+
};
|
|
2281
|
+
run();
|
|
2282
|
+
}, []);
|
|
2283
|
+
return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", children: [
|
|
2284
|
+
/* @__PURE__ */ jsx17(Banner, {}),
|
|
2285
|
+
/* @__PURE__ */ jsxs16(StepShell, { title: "AI Editor Config", children: [
|
|
2286
|
+
state === "validating" && /* @__PURE__ */ jsxs16(Box17, { gap: 1, children: [
|
|
2287
|
+
/* @__PURE__ */ jsx17(Text17, { color: "cyan", children: /* @__PURE__ */ jsx17(Spinner4, { type: "dots" }) }),
|
|
2288
|
+
/* @__PURE__ */ jsx17(Text17, { children: "Checking project..." })
|
|
2289
|
+
] }),
|
|
2290
|
+
state === "downloading" && /* @__PURE__ */ jsxs16(Box17, { gap: 1, children: [
|
|
2291
|
+
/* @__PURE__ */ jsx17(Text17, { color: "cyan", children: /* @__PURE__ */ jsx17(Spinner4, { type: "dots" }) }),
|
|
2292
|
+
/* @__PURE__ */ jsxs16(Text17, { children: [
|
|
2293
|
+
"Downloading AI editor configs (",
|
|
2294
|
+
version2,
|
|
2295
|
+
")..."
|
|
2296
|
+
] })
|
|
2297
|
+
] }),
|
|
2298
|
+
state === "done" && /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", gap: 1, children: [
|
|
2299
|
+
/* @__PURE__ */ jsxs16(Box17, { gap: 1, children: [
|
|
2300
|
+
/* @__PURE__ */ jsx17(Text17, { color: "green", bold: true, children: "\u2714" }),
|
|
2301
|
+
/* @__PURE__ */ jsxs16(Text17, { bold: true, children: [
|
|
2302
|
+
"AI editor configs installed (",
|
|
2303
|
+
files.length,
|
|
2304
|
+
" files)"
|
|
2305
|
+
] })
|
|
2306
|
+
] }),
|
|
2307
|
+
/* @__PURE__ */ jsx17(Box17, { flexDirection: "column", marginLeft: 2, children: files.map((f) => /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: f }, f)) })
|
|
2308
|
+
] }),
|
|
2309
|
+
state === "error" && /* @__PURE__ */ jsxs16(Box17, { gap: 1, children: [
|
|
2310
|
+
/* @__PURE__ */ jsx17(Text17, { color: "red", children: "\u2716" }),
|
|
2311
|
+
/* @__PURE__ */ jsx17(Text17, { children: errorMessage })
|
|
2312
|
+
] })
|
|
2313
|
+
] })
|
|
2314
|
+
] });
|
|
2315
|
+
};
|
|
2316
|
+
|
|
2317
|
+
// src/components/AuthLogin.tsx
|
|
2318
|
+
import { createServer } from "http";
|
|
2319
|
+
import { Box as Box18, Text as Text18, useApp as useApp3 } from "ink";
|
|
2320
|
+
import Spinner5 from "ink-spinner";
|
|
2321
|
+
import open from "open";
|
|
2322
|
+
import { useState as useState12, useEffect as useEffect8 } from "react";
|
|
2323
|
+
|
|
2191
2324
|
// src/lib/auth.ts
|
|
2192
|
-
import { readFile as readFile3, writeFile as
|
|
2193
|
-
import { join as
|
|
2325
|
+
import { readFile as readFile3, writeFile as writeFile4, mkdir as mkdir2, unlink } from "fs/promises";
|
|
2326
|
+
import { join as join5 } from "path";
|
|
2194
2327
|
import { homedir } from "os";
|
|
2195
|
-
var AUTH_DIR =
|
|
2196
|
-
var AUTH_FILE =
|
|
2328
|
+
var AUTH_DIR = join5(homedir(), ".stackable");
|
|
2329
|
+
var AUTH_FILE = join5(AUTH_DIR, "auth.json");
|
|
2197
2330
|
var readAuthState = async () => {
|
|
2198
2331
|
try {
|
|
2199
2332
|
const content = await readFile3(AUTH_FILE, "utf8");
|
|
@@ -2203,8 +2336,8 @@ var readAuthState = async () => {
|
|
|
2203
2336
|
}
|
|
2204
2337
|
};
|
|
2205
2338
|
var writeAuthState = async (state) => {
|
|
2206
|
-
await
|
|
2207
|
-
await
|
|
2339
|
+
await mkdir2(AUTH_DIR, { recursive: true, mode: 448 });
|
|
2340
|
+
await writeFile4(AUTH_FILE, JSON.stringify(state, null, 2), { mode: 384 });
|
|
2208
2341
|
};
|
|
2209
2342
|
var clearAuthState = async () => {
|
|
2210
2343
|
try {
|
|
@@ -2215,7 +2348,9 @@ var clearAuthState = async () => {
|
|
|
2215
2348
|
var decodeJwtPayload = (token) => {
|
|
2216
2349
|
try {
|
|
2217
2350
|
const [, payload] = token.split(".");
|
|
2218
|
-
if (!payload)
|
|
2351
|
+
if (!payload) {
|
|
2352
|
+
return null;
|
|
2353
|
+
}
|
|
2219
2354
|
const json = Buffer.from(payload, "base64url").toString("utf8");
|
|
2220
2355
|
return JSON.parse(json);
|
|
2221
2356
|
} catch {
|
|
@@ -2237,7 +2372,7 @@ var getToken = async () => {
|
|
|
2237
2372
|
};
|
|
2238
2373
|
|
|
2239
2374
|
// src/components/AuthLogin.tsx
|
|
2240
|
-
import { jsx as
|
|
2375
|
+
import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2241
2376
|
var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2242
2377
|
var callbackPage = (heading, sub, redirectUrl) => `<!DOCTYPE html>
|
|
2243
2378
|
<html><head><meta charset="utf-8"><title>Stackable CLI</title>
|
|
@@ -2247,13 +2382,13 @@ var callbackPage = (heading, sub, redirectUrl) => `<!DOCTYPE html>
|
|
|
2247
2382
|
${redirectUrl ? `<script>(function(){var s=3,el=document.getElementById('h');function t(){if(s<=0){location.href='${redirectUrl}';return}el.textContent='Redirecting in '+s+'s\u2026';s--;setTimeout(t,1000)}t()})()</script>` : ""}
|
|
2248
2383
|
</body></html>`;
|
|
2249
2384
|
var AuthLogin = ({ dashboardUrl }) => {
|
|
2250
|
-
const { exit } =
|
|
2251
|
-
const [state, setState] =
|
|
2252
|
-
const [loginUrl, setLoginUrl] =
|
|
2253
|
-
const [userIdLabel, setUserIdLabel] =
|
|
2254
|
-
const [orgIdLabel, setOrgIdLabel] =
|
|
2255
|
-
const [errorMessage, setErrorMessage] =
|
|
2256
|
-
|
|
2385
|
+
const { exit } = useApp3();
|
|
2386
|
+
const [state, setState] = useState12("waiting");
|
|
2387
|
+
const [loginUrl, setLoginUrl] = useState12("");
|
|
2388
|
+
const [userIdLabel, setUserIdLabel] = useState12("");
|
|
2389
|
+
const [orgIdLabel, setOrgIdLabel] = useState12("");
|
|
2390
|
+
const [errorMessage, setErrorMessage] = useState12("");
|
|
2391
|
+
useEffect8(() => {
|
|
2257
2392
|
let server;
|
|
2258
2393
|
let timeout;
|
|
2259
2394
|
const run = async () => {
|
|
@@ -2328,109 +2463,109 @@ var AuthLogin = ({ dashboardUrl }) => {
|
|
|
2328
2463
|
server?.close();
|
|
2329
2464
|
};
|
|
2330
2465
|
}, []);
|
|
2331
|
-
return /* @__PURE__ */
|
|
2332
|
-
/* @__PURE__ */
|
|
2333
|
-
/* @__PURE__ */
|
|
2334
|
-
state === "waiting" && /* @__PURE__ */
|
|
2335
|
-
/* @__PURE__ */
|
|
2336
|
-
/* @__PURE__ */
|
|
2337
|
-
/* @__PURE__ */
|
|
2466
|
+
return /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", children: [
|
|
2467
|
+
/* @__PURE__ */ jsx18(Banner, {}),
|
|
2468
|
+
/* @__PURE__ */ jsxs17(StepShell, { title: "Authenticate with Stackable", children: [
|
|
2469
|
+
state === "waiting" && /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", gap: 1, children: [
|
|
2470
|
+
/* @__PURE__ */ jsxs17(Box18, { gap: 1, children: [
|
|
2471
|
+
/* @__PURE__ */ jsx18(Text18, { color: "cyan", children: /* @__PURE__ */ jsx18(Spinner5, { type: "dots" }) }),
|
|
2472
|
+
/* @__PURE__ */ jsx18(Text18, { children: "Waiting for browser authentication..." })
|
|
2338
2473
|
] }),
|
|
2339
|
-
loginUrl && /* @__PURE__ */
|
|
2474
|
+
loginUrl && /* @__PURE__ */ jsxs17(Text18, { dimColor: true, children: [
|
|
2340
2475
|
" ",
|
|
2341
2476
|
loginUrl
|
|
2342
2477
|
] })
|
|
2343
2478
|
] }),
|
|
2344
|
-
state === "success" && /* @__PURE__ */
|
|
2345
|
-
/* @__PURE__ */
|
|
2346
|
-
/* @__PURE__ */
|
|
2347
|
-
/* @__PURE__ */
|
|
2348
|
-
/* @__PURE__ */
|
|
2479
|
+
state === "success" && /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", gap: 1, children: [
|
|
2480
|
+
/* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", children: [
|
|
2481
|
+
/* @__PURE__ */ jsxs17(Box18, { gap: 2, children: [
|
|
2482
|
+
/* @__PURE__ */ jsx18(Text18, { dimColor: true, children: "User:" }),
|
|
2483
|
+
/* @__PURE__ */ jsx18(Text18, { color: "cyan", children: userIdLabel })
|
|
2349
2484
|
] }),
|
|
2350
|
-
/* @__PURE__ */
|
|
2351
|
-
/* @__PURE__ */
|
|
2352
|
-
/* @__PURE__ */
|
|
2485
|
+
/* @__PURE__ */ jsxs17(Box18, { gap: 2, children: [
|
|
2486
|
+
/* @__PURE__ */ jsx18(Text18, { dimColor: true, children: "Org: " }),
|
|
2487
|
+
/* @__PURE__ */ jsx18(Text18, { color: "cyan", children: orgIdLabel })
|
|
2353
2488
|
] })
|
|
2354
2489
|
] }),
|
|
2355
|
-
/* @__PURE__ */
|
|
2356
|
-
/* @__PURE__ */
|
|
2357
|
-
/* @__PURE__ */
|
|
2490
|
+
/* @__PURE__ */ jsxs17(Box18, { gap: 1, children: [
|
|
2491
|
+
/* @__PURE__ */ jsx18(Text18, { color: "green", bold: true, children: "\u2714" }),
|
|
2492
|
+
/* @__PURE__ */ jsx18(Text18, { bold: true, children: "Authenticated" })
|
|
2358
2493
|
] })
|
|
2359
2494
|
] }),
|
|
2360
|
-
state === "error" && /* @__PURE__ */
|
|
2361
|
-
/* @__PURE__ */
|
|
2362
|
-
/* @__PURE__ */
|
|
2495
|
+
state === "error" && /* @__PURE__ */ jsxs17(Box18, { gap: 1, children: [
|
|
2496
|
+
/* @__PURE__ */ jsx18(Text18, { color: "red", children: "\u2716" }),
|
|
2497
|
+
/* @__PURE__ */ jsx18(Text18, { children: errorMessage })
|
|
2363
2498
|
] })
|
|
2364
2499
|
] })
|
|
2365
2500
|
] });
|
|
2366
2501
|
};
|
|
2367
2502
|
|
|
2368
2503
|
// src/components/AuthLogout.tsx
|
|
2369
|
-
import { useEffect as
|
|
2370
|
-
import { Box as
|
|
2371
|
-
import { jsx as
|
|
2504
|
+
import { useEffect as useEffect9 } from "react";
|
|
2505
|
+
import { Box as Box19, Text as Text19, useApp as useApp4 } from "ink";
|
|
2506
|
+
import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2372
2507
|
var AuthLogout = () => {
|
|
2373
|
-
const { exit } =
|
|
2374
|
-
|
|
2508
|
+
const { exit } = useApp4();
|
|
2509
|
+
useEffect9(() => {
|
|
2375
2510
|
exit();
|
|
2376
2511
|
}, [exit]);
|
|
2377
|
-
return /* @__PURE__ */
|
|
2378
|
-
/* @__PURE__ */
|
|
2379
|
-
/* @__PURE__ */
|
|
2380
|
-
/* @__PURE__ */
|
|
2381
|
-
/* @__PURE__ */
|
|
2512
|
+
return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", children: [
|
|
2513
|
+
/* @__PURE__ */ jsx19(Banner, {}),
|
|
2514
|
+
/* @__PURE__ */ jsx19(StepShell, { title: "Authenticate with Stackable", children: /* @__PURE__ */ jsxs18(Box19, { gap: 1, children: [
|
|
2515
|
+
/* @__PURE__ */ jsx19(Text19, { color: "green", bold: true, children: "\u2714" }),
|
|
2516
|
+
/* @__PURE__ */ jsx19(Text19, { bold: true, children: "Logged out" })
|
|
2382
2517
|
] }) })
|
|
2383
2518
|
] });
|
|
2384
2519
|
};
|
|
2385
2520
|
|
|
2386
2521
|
// src/components/AuthStatus.tsx
|
|
2387
|
-
import { useEffect as
|
|
2388
|
-
import {
|
|
2389
|
-
import { jsx as
|
|
2522
|
+
import { useEffect as useEffect10 } from "react";
|
|
2523
|
+
import { useApp as useApp5, Box as Box20, Text as Text20 } from "ink";
|
|
2524
|
+
import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2390
2525
|
var AuthStatus = ({ state, userId, orgId, expiry }) => {
|
|
2391
|
-
const { exit } =
|
|
2392
|
-
|
|
2526
|
+
const { exit } = useApp5();
|
|
2527
|
+
useEffect10(() => {
|
|
2393
2528
|
exit();
|
|
2394
2529
|
}, [exit]);
|
|
2395
|
-
return /* @__PURE__ */
|
|
2396
|
-
/* @__PURE__ */
|
|
2397
|
-
/* @__PURE__ */
|
|
2398
|
-
state === "authenticated" && /* @__PURE__ */
|
|
2399
|
-
/* @__PURE__ */
|
|
2400
|
-
/* @__PURE__ */
|
|
2401
|
-
/* @__PURE__ */
|
|
2402
|
-
/* @__PURE__ */
|
|
2530
|
+
return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
|
|
2531
|
+
/* @__PURE__ */ jsx20(Banner, {}),
|
|
2532
|
+
/* @__PURE__ */ jsxs19(StepShell, { title: "Authenticate with Stackable", children: [
|
|
2533
|
+
state === "authenticated" && /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", gap: 1, children: [
|
|
2534
|
+
/* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
|
|
2535
|
+
/* @__PURE__ */ jsxs19(Box20, { gap: 2, children: [
|
|
2536
|
+
/* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "User:" }),
|
|
2537
|
+
/* @__PURE__ */ jsx20(Text20, { color: "cyan", children: userId })
|
|
2403
2538
|
] }),
|
|
2404
|
-
/* @__PURE__ */
|
|
2405
|
-
/* @__PURE__ */
|
|
2406
|
-
/* @__PURE__ */
|
|
2539
|
+
/* @__PURE__ */ jsxs19(Box20, { gap: 2, children: [
|
|
2540
|
+
/* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "Org: " }),
|
|
2541
|
+
/* @__PURE__ */ jsx20(Text20, { color: "cyan", children: orgId })
|
|
2407
2542
|
] }),
|
|
2408
|
-
expiry && /* @__PURE__ */
|
|
2409
|
-
/* @__PURE__ */
|
|
2410
|
-
/* @__PURE__ */
|
|
2543
|
+
expiry && /* @__PURE__ */ jsxs19(Box20, { gap: 2, children: [
|
|
2544
|
+
/* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "Exp: " }),
|
|
2545
|
+
/* @__PURE__ */ jsx20(Text20, { color: "cyan", children: expiry.toLocaleDateString() })
|
|
2411
2546
|
] })
|
|
2412
2547
|
] }),
|
|
2413
|
-
/* @__PURE__ */
|
|
2414
|
-
/* @__PURE__ */
|
|
2415
|
-
/* @__PURE__ */
|
|
2548
|
+
/* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
|
|
2549
|
+
/* @__PURE__ */ jsx20(Text20, { color: "green", bold: true, children: "\u2714" }),
|
|
2550
|
+
/* @__PURE__ */ jsx20(Text20, { bold: true, children: "Authenticated" })
|
|
2416
2551
|
] })
|
|
2417
2552
|
] }),
|
|
2418
|
-
state === "expired" && /* @__PURE__ */
|
|
2419
|
-
/* @__PURE__ */
|
|
2420
|
-
/* @__PURE__ */
|
|
2421
|
-
/* @__PURE__ */
|
|
2553
|
+
state === "expired" && /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", gap: 1, children: [
|
|
2554
|
+
/* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
|
|
2555
|
+
/* @__PURE__ */ jsx20(Text20, { color: "red", children: "\u2716" }),
|
|
2556
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
2422
2557
|
"Session expired",
|
|
2423
2558
|
expiry ? ` (${expiry.toLocaleDateString()})` : ""
|
|
2424
2559
|
] })
|
|
2425
2560
|
] }),
|
|
2426
|
-
/* @__PURE__ */
|
|
2561
|
+
/* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "Run `stackable-app-extension auth login` to re-authenticate." })
|
|
2427
2562
|
] }),
|
|
2428
|
-
state === "not-logged-in" && /* @__PURE__ */
|
|
2429
|
-
/* @__PURE__ */
|
|
2430
|
-
/* @__PURE__ */
|
|
2431
|
-
/* @__PURE__ */
|
|
2563
|
+
state === "not-logged-in" && /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", gap: 1, children: [
|
|
2564
|
+
/* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
|
|
2565
|
+
/* @__PURE__ */ jsx20(Text20, { color: "red", children: "\u2716" }),
|
|
2566
|
+
/* @__PURE__ */ jsx20(Text20, { children: "Not logged in" })
|
|
2432
2567
|
] }),
|
|
2433
|
-
/* @__PURE__ */
|
|
2568
|
+
/* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "Run `stackable-app-extension auth login`" })
|
|
2434
2569
|
] })
|
|
2435
2570
|
] })
|
|
2436
2571
|
] });
|
|
@@ -2484,7 +2619,7 @@ var checkForUpdate = (currentVersion) => {
|
|
|
2484
2619
|
};
|
|
2485
2620
|
|
|
2486
2621
|
// src/index.tsx
|
|
2487
|
-
import { jsx as
|
|
2622
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
2488
2623
|
var require2 = createRequire(import.meta.url);
|
|
2489
2624
|
var { version } = require2("../package.json");
|
|
2490
2625
|
checkForUpdate(version);
|
|
@@ -2496,7 +2631,9 @@ var ensureToken = async () => {
|
|
|
2496
2631
|
} catch (err) {
|
|
2497
2632
|
const message = err instanceof Error ? err.message : String(err);
|
|
2498
2633
|
const isExpired = message.toLowerCase().includes("expired");
|
|
2499
|
-
render(
|
|
2634
|
+
render(
|
|
2635
|
+
/* @__PURE__ */ jsx21(AuthStatus, { state: isExpired ? "expired" : "not-logged-in" })
|
|
2636
|
+
);
|
|
2500
2637
|
return null;
|
|
2501
2638
|
}
|
|
2502
2639
|
};
|
|
@@ -2507,7 +2644,19 @@ program.command("create" /* CREATE */).description("Create a new Extension proje
|
|
|
2507
2644
|
return;
|
|
2508
2645
|
}
|
|
2509
2646
|
const { token, userId, orgId } = auth2;
|
|
2510
|
-
render(
|
|
2647
|
+
render(
|
|
2648
|
+
/* @__PURE__ */ jsx21(
|
|
2649
|
+
App,
|
|
2650
|
+
{
|
|
2651
|
+
command: "create" /* CREATE */,
|
|
2652
|
+
initialName: name,
|
|
2653
|
+
options,
|
|
2654
|
+
token,
|
|
2655
|
+
orgId,
|
|
2656
|
+
userId
|
|
2657
|
+
}
|
|
2658
|
+
)
|
|
2659
|
+
);
|
|
2511
2660
|
});
|
|
2512
2661
|
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) => {
|
|
2513
2662
|
const auth2 = await ensureToken();
|
|
@@ -2515,7 +2664,18 @@ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project
|
|
|
2515
2664
|
return;
|
|
2516
2665
|
}
|
|
2517
2666
|
const { token, userId, orgId } = auth2;
|
|
2518
|
-
render(
|
|
2667
|
+
render(
|
|
2668
|
+
/* @__PURE__ */ jsx21(
|
|
2669
|
+
App,
|
|
2670
|
+
{
|
|
2671
|
+
command: "scaffold" /* SCAFFOLD */,
|
|
2672
|
+
options,
|
|
2673
|
+
token,
|
|
2674
|
+
orgId,
|
|
2675
|
+
userId
|
|
2676
|
+
}
|
|
2677
|
+
)
|
|
2678
|
+
);
|
|
2519
2679
|
});
|
|
2520
2680
|
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) => {
|
|
2521
2681
|
const auth2 = await ensureToken();
|
|
@@ -2523,7 +2683,19 @@ program.command("update" /* UPDATE */).description("Update an existing Extension
|
|
|
2523
2683
|
return;
|
|
2524
2684
|
}
|
|
2525
2685
|
const { token, userId, orgId } = auth2;
|
|
2526
|
-
render(
|
|
2686
|
+
render(
|
|
2687
|
+
/* @__PURE__ */ jsx21(
|
|
2688
|
+
App,
|
|
2689
|
+
{
|
|
2690
|
+
command: "update" /* UPDATE */,
|
|
2691
|
+
initialExtensionId: extensionId,
|
|
2692
|
+
options,
|
|
2693
|
+
token,
|
|
2694
|
+
userId,
|
|
2695
|
+
orgId
|
|
2696
|
+
}
|
|
2697
|
+
)
|
|
2698
|
+
);
|
|
2527
2699
|
});
|
|
2528
2700
|
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) => {
|
|
2529
2701
|
const auth2 = await ensureToken();
|
|
@@ -2531,30 +2703,57 @@ program.command("dev" /* DEV */).description("Start dev servers with a public tu
|
|
|
2531
2703
|
return;
|
|
2532
2704
|
}
|
|
2533
2705
|
const { token, userId, orgId } = auth2;
|
|
2534
|
-
render(
|
|
2706
|
+
render(
|
|
2707
|
+
/* @__PURE__ */ jsx21(
|
|
2708
|
+
DevApp,
|
|
2709
|
+
{
|
|
2710
|
+
options,
|
|
2711
|
+
token,
|
|
2712
|
+
userId,
|
|
2713
|
+
orgId
|
|
2714
|
+
}
|
|
2715
|
+
),
|
|
2716
|
+
{ exitOnCtrlC: false }
|
|
2717
|
+
);
|
|
2535
2718
|
});
|
|
2536
2719
|
var DASHBOARD_URL = process.env.ADMIN_DASHBOARD_URL ?? "https://admin.stackablelabs.io";
|
|
2537
2720
|
var auth = program.command("auth").description("Manage CLI authentication");
|
|
2538
2721
|
auth.command("login").description("Authenticate with Stackable via browser").action(async () => {
|
|
2539
|
-
render(/* @__PURE__ */
|
|
2722
|
+
render(/* @__PURE__ */ jsx21(AuthLogin, { dashboardUrl: DASHBOARD_URL }));
|
|
2540
2723
|
});
|
|
2541
2724
|
auth.command("logout").description("Clear stored CLI credentials").action(async () => {
|
|
2542
2725
|
await clearAuthState();
|
|
2543
|
-
render(/* @__PURE__ */
|
|
2726
|
+
render(/* @__PURE__ */ jsx21(AuthLogout, {}));
|
|
2544
2727
|
});
|
|
2545
2728
|
auth.command("status").description("Show current authentication status").action(async () => {
|
|
2546
2729
|
const state = await readAuthState();
|
|
2547
2730
|
if (!state) {
|
|
2548
|
-
render(
|
|
2731
|
+
render(
|
|
2732
|
+
/* @__PURE__ */ jsx21(AuthStatus, { state: "not-logged-in" })
|
|
2733
|
+
);
|
|
2549
2734
|
return;
|
|
2550
2735
|
}
|
|
2551
2736
|
const [, payloadB64] = state.token.split(".");
|
|
2552
2737
|
const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
|
|
2553
2738
|
const expiry = payload.exp ? new Date(payload.exp * 1e3) : null;
|
|
2554
2739
|
if (expiry && Date.now() >= expiry.getTime()) {
|
|
2555
|
-
render(/* @__PURE__ */
|
|
2740
|
+
render(/* @__PURE__ */ jsx21(AuthStatus, { state: "expired", expiry }));
|
|
2556
2741
|
return;
|
|
2557
2742
|
}
|
|
2558
|
-
render(
|
|
2743
|
+
render(
|
|
2744
|
+
/* @__PURE__ */ jsx21(
|
|
2745
|
+
AuthStatus,
|
|
2746
|
+
{
|
|
2747
|
+
state: "authenticated",
|
|
2748
|
+
userId: state.userId,
|
|
2749
|
+
orgId: state.orgId,
|
|
2750
|
+
expiry
|
|
2751
|
+
}
|
|
2752
|
+
)
|
|
2753
|
+
);
|
|
2754
|
+
});
|
|
2755
|
+
var ai = program.command("ai").description("AI editor configuration tools");
|
|
2756
|
+
ai.command("scaffold").description("Download AI editor config files into your Extension project").option("--version <version>", 'AI docs version (semver or "latest")', "latest").action(async (options) => {
|
|
2757
|
+
render(/* @__PURE__ */ jsx21(AIScaffold, { version: options.version }));
|
|
2559
2758
|
});
|
|
2560
2759
|
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.20.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"LICENSE"
|
|
13
13
|
],
|
|
14
14
|
"dependencies": {
|
|
15
|
+
"@stackable-labs/lib-contracts": "workspace:*",
|
|
16
|
+
"adm-zip": "0.x",
|
|
15
17
|
"cloudflared": "0.x",
|
|
16
18
|
"commander": "12.x",
|
|
17
19
|
"giget": "3.x",
|