@stackable-labs/cli-app-extension 1.36.3 → 1.38.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/README.md +73 -14
- package/dist/index.js +839 -923
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,20 +1,79 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import { program } from 'commander';
|
|
4
|
+
import { render, useApp, Box, Text, useInput, useFocus, useFocusManager } from 'ink';
|
|
5
|
+
import { unlink, readFile, writeFile, mkdir, readdir, rm } from 'fs/promises';
|
|
6
|
+
import { join, dirname } from 'path';
|
|
7
|
+
import Spinner5 from 'ink-spinner';
|
|
8
|
+
import { useState, useCallback, useEffect, useRef, useMemo } from 'react';
|
|
9
|
+
import { delay } from '@stackable-labs/lib-utils-js';
|
|
10
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
11
|
+
import TextInput from 'ink-text-input';
|
|
12
|
+
import { execFile, spawn } from 'child_process';
|
|
13
|
+
import { promisify } from 'util';
|
|
14
|
+
import { installDependencies } from 'nypm';
|
|
15
|
+
import { downloadTemplate } from 'giget';
|
|
16
|
+
import { Tunnel } from 'cloudflared';
|
|
17
|
+
import clipboard from 'clipboardy';
|
|
18
|
+
import { existsSync, readFileSync } from 'fs';
|
|
19
|
+
import AdmZip from 'adm-zip';
|
|
20
|
+
import { createServer } from 'http';
|
|
21
|
+
import open from 'open';
|
|
22
|
+
import { homedir } from 'os';
|
|
23
|
+
import https from 'https';
|
|
2
24
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
var WORDMARK = [
|
|
26
|
+
" _ _ _ _ ",
|
|
27
|
+
" ___| |_ __ _ ___| | ____ _| |__ | | ___",
|
|
28
|
+
"/ __| __/ _` |/ __| |/ / _` | '_ \\| |/ _ \\",
|
|
29
|
+
"\\__ \\ || (_| | (__| < (_| | |_) | | __/",
|
|
30
|
+
"|___/\\__\\__,_|\\___|_|\\_\\__,_|_.__/|_|\\___|"
|
|
31
|
+
];
|
|
32
|
+
var COLORS = [
|
|
33
|
+
[232, 218, 234],
|
|
34
|
+
// Lit Lilac #E8DAEA
|
|
35
|
+
[197, 96, 255],
|
|
36
|
+
// Poppy Purple #C560FF
|
|
37
|
+
[0, 174, 247],
|
|
38
|
+
// Bluetooth Blue #00AEF7
|
|
39
|
+
[70, 224, 177],
|
|
40
|
+
// Tropical Teal #46E0B1
|
|
41
|
+
[252, 248, 161]
|
|
42
|
+
// Not Mellow Yellow #FCF8A1
|
|
43
|
+
];
|
|
44
|
+
var lerp = (a, b, t) => {
|
|
45
|
+
const r = Math.round(a[0] + (b[0] - a[0]) * t);
|
|
46
|
+
const g = Math.round(a[1] + (b[1] - a[1]) * t);
|
|
47
|
+
const bl = Math.round(a[2] + (b[2] - a[2]) * t);
|
|
48
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${bl.toString(16).padStart(2, "0")}`;
|
|
49
|
+
};
|
|
50
|
+
var gradientColor = (row, col, rows, cols) => {
|
|
51
|
+
const t = (row / (rows - 1) + col / (cols - 1)) / 2;
|
|
52
|
+
const idx = t * (COLORS.length - 1);
|
|
53
|
+
const lo = Math.floor(idx);
|
|
54
|
+
const hi = Math.min(lo + 1, COLORS.length - 1);
|
|
55
|
+
return lerp(COLORS[lo], COLORS[hi], idx - lo);
|
|
56
|
+
};
|
|
57
|
+
var Banner = ({ userId, orgId } = {}) => {
|
|
58
|
+
const termWidth = process.stdout.columns ?? 80;
|
|
59
|
+
const maxLen = Math.max(...WORDMARK.map((l) => l.length));
|
|
60
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
61
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(termWidth) }),
|
|
62
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
|
|
63
|
+
WORDMARK.map((line, row) => /* @__PURE__ */ jsx(Box, { children: line.split("").map((ch, col) => /* @__PURE__ */ jsx(Text, { bold: true, color: ch === " " ? void 0 : gradientColor(row, col, WORDMARK.length, maxLen), children: ch }, col)) }, row)),
|
|
64
|
+
userId && orgId && /* @__PURE__ */ jsxs(Box, { gap: 2, marginTop: 1, children: [
|
|
65
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
66
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "User:" }),
|
|
67
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: userId })
|
|
68
|
+
] }),
|
|
69
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
70
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Org:" }),
|
|
71
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: orgId })
|
|
72
|
+
] })
|
|
73
|
+
] })
|
|
74
|
+
] })
|
|
75
|
+
] });
|
|
76
|
+
};
|
|
18
77
|
|
|
19
78
|
// src/constants.ts
|
|
20
79
|
var TEMPLATE_SOURCES = {
|
|
@@ -49,10 +108,6 @@ var TARGET_PERMISSION_MAP = {
|
|
|
49
108
|
"slot.footer": [],
|
|
50
109
|
"slot.footer-links": []
|
|
51
110
|
};
|
|
52
|
-
|
|
53
|
-
// src/components/StepShell.tsx
|
|
54
|
-
import { Box, Text, useInput } from "ink";
|
|
55
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
56
111
|
var divider = (width) => "\u2500".repeat(width);
|
|
57
112
|
var INNER_DIVIDER_WIDTH = 40;
|
|
58
113
|
var StepShell = ({ title, hint, children, footer, onBack }) => {
|
|
@@ -82,9 +137,6 @@ var StepShell = ({ title, hint, children, footer, onBack }) => {
|
|
|
82
137
|
] })
|
|
83
138
|
] });
|
|
84
139
|
};
|
|
85
|
-
|
|
86
|
-
// src/components/Confirm.tsx
|
|
87
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
88
140
|
var compareSemver = (a, b) => {
|
|
89
141
|
const pa = a.split(".").map(Number);
|
|
90
142
|
const pb = b.split(".").map(Number);
|
|
@@ -97,7 +149,7 @@ var compareSemver = (a, b) => {
|
|
|
97
149
|
var VersionRow = ({ currentVersion, value, onChange, onFocusChange, onConfirm, onCancel, selected }) => {
|
|
98
150
|
const { isFocused } = useFocus();
|
|
99
151
|
const { focusPrevious, focusNext } = useFocusManager();
|
|
100
|
-
|
|
152
|
+
useInput((_, key) => {
|
|
101
153
|
if (!isFocused) return;
|
|
102
154
|
if (key.upArrow) {
|
|
103
155
|
focusPrevious();
|
|
@@ -120,17 +172,17 @@ var VersionRow = ({ currentVersion, value, onChange, onFocusChange, onConfirm, o
|
|
|
120
172
|
const isValid = /^\d+\.\d+\.\d+$/.test(value) && compareSemver(value, currentVersion) > 0;
|
|
121
173
|
const showError = isFocused && value !== "" && !isValid;
|
|
122
174
|
const hasChange = value !== currentVersion;
|
|
123
|
-
return /* @__PURE__ */
|
|
124
|
-
/* @__PURE__ */
|
|
125
|
-
/* @__PURE__ */
|
|
126
|
-
/* @__PURE__ */
|
|
175
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
176
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
177
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Version " }),
|
|
178
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
127
179
|
currentVersion,
|
|
128
180
|
hasChange ? " \u2192 " : ""
|
|
129
181
|
] }),
|
|
130
|
-
isFocused ? /* @__PURE__ */
|
|
131
|
-
isFocused && /* @__PURE__ */
|
|
182
|
+
isFocused ? /* @__PURE__ */ jsx(TextInput, { value, onChange, placeholder: value }) : hasChange && /* @__PURE__ */ jsx(Text, { dimColor: true, children: value }),
|
|
183
|
+
isFocused && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(edit to override)" })
|
|
132
184
|
] }),
|
|
133
|
-
showError && /* @__PURE__ */
|
|
185
|
+
showError && /* @__PURE__ */ jsx(Text, { color: "red", children: " Version must be greater than " + currentVersion })
|
|
134
186
|
] });
|
|
135
187
|
};
|
|
136
188
|
var Confirm = ({
|
|
@@ -157,7 +209,7 @@ var Confirm = ({
|
|
|
157
209
|
}) => {
|
|
158
210
|
const [selected, setSelected] = useState("y");
|
|
159
211
|
const [overrideFocused, setOverrideFocused] = useState(false);
|
|
160
|
-
|
|
212
|
+
useInput((input, key) => {
|
|
161
213
|
if (overrideFocused) return;
|
|
162
214
|
if (key.leftArrow || key.rightArrow) {
|
|
163
215
|
setSelected((s) => s === "y" ? "n" : "y");
|
|
@@ -181,29 +233,29 @@ var Confirm = ({
|
|
|
181
233
|
}
|
|
182
234
|
}
|
|
183
235
|
});
|
|
184
|
-
return /* @__PURE__ */
|
|
236
|
+
return /* @__PURE__ */ jsx(
|
|
185
237
|
StepShell,
|
|
186
238
|
{
|
|
187
239
|
title: command === "update" /* UPDATE */ ? "Ready to update" : "Ready to scaffold",
|
|
188
240
|
hint: "Review your settings before proceeding",
|
|
189
241
|
onBack,
|
|
190
|
-
footer: /* @__PURE__ */
|
|
242
|
+
footer: /* @__PURE__ */ jsxs(Text, { children: [
|
|
191
243
|
"Proceed?",
|
|
192
244
|
" ",
|
|
193
|
-
/* @__PURE__ */
|
|
194
|
-
/* @__PURE__ */
|
|
195
|
-
/* @__PURE__ */
|
|
245
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "green", inverse: selected === "y", children: "Y" }),
|
|
246
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "/" }),
|
|
247
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "red", inverse: selected === "n", children: "n" })
|
|
196
248
|
] }),
|
|
197
|
-
children: /* @__PURE__ */
|
|
198
|
-
/* @__PURE__ */
|
|
199
|
-
/* @__PURE__ */
|
|
200
|
-
/* @__PURE__ */
|
|
249
|
+
children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
250
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
251
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Name " }),
|
|
252
|
+
/* @__PURE__ */ jsx(Text, { dimColor: !!extensionVersion, children: name })
|
|
201
253
|
] }),
|
|
202
|
-
templateFlavor && /* @__PURE__ */
|
|
203
|
-
/* @__PURE__ */
|
|
204
|
-
/* @__PURE__ */
|
|
254
|
+
templateFlavor && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
255
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Template " }),
|
|
256
|
+
/* @__PURE__ */ jsx(Text, { children: TEMPLATE_FLAVOR_META[templateFlavor].label })
|
|
205
257
|
] }),
|
|
206
|
-
extensionVersion && command === "update" /* UPDATE */ && newVersion && onVersionOverride && /* @__PURE__ */
|
|
258
|
+
extensionVersion && command === "update" /* UPDATE */ && newVersion && onVersionOverride && /* @__PURE__ */ jsx(
|
|
207
259
|
VersionRow,
|
|
208
260
|
{
|
|
209
261
|
currentVersion: extensionVersion,
|
|
@@ -215,84 +267,84 @@ var Confirm = ({
|
|
|
215
267
|
selected
|
|
216
268
|
}
|
|
217
269
|
),
|
|
218
|
-
extensionVersion && !(command === "update" /* UPDATE */ && newVersion && onVersionOverride) && /* @__PURE__ */
|
|
219
|
-
/* @__PURE__ */
|
|
220
|
-
/* @__PURE__ */
|
|
270
|
+
extensionVersion && !(command === "update" /* UPDATE */ && newVersion && onVersionOverride) && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
271
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Version " }),
|
|
272
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
221
273
|
extensionVersion,
|
|
222
274
|
newVersion && newVersion !== extensionVersion ? ` \u2192 ${newVersion}` : ""
|
|
223
275
|
] })
|
|
224
276
|
] }),
|
|
225
|
-
command !== "update" /* UPDATE */ && outputDir && /* @__PURE__ */
|
|
226
|
-
/* @__PURE__ */
|
|
227
|
-
/* @__PURE__ */
|
|
277
|
+
command !== "update" /* UPDATE */ && outputDir && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
278
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Directory " }),
|
|
279
|
+
/* @__PURE__ */ jsx(Text, { children: outputDir })
|
|
228
280
|
] }),
|
|
229
|
-
command !== "update" /* UPDATE */ && extensionPort !== void 0 && /* @__PURE__ */
|
|
230
|
-
/* @__PURE__ */
|
|
231
|
-
/* @__PURE__ */
|
|
281
|
+
command !== "update" /* UPDATE */ && extensionPort !== void 0 && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
282
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Extension port" }),
|
|
283
|
+
/* @__PURE__ */ jsx(Text, { children: extensionPort })
|
|
232
284
|
] }),
|
|
233
|
-
command !== "update" /* UPDATE */ && previewPort !== void 0 && /* @__PURE__ */
|
|
234
|
-
/* @__PURE__ */
|
|
235
|
-
/* @__PURE__ */
|
|
285
|
+
command !== "update" /* UPDATE */ && previewPort !== void 0 && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
286
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Preview port " }),
|
|
287
|
+
/* @__PURE__ */ jsx(Text, { children: previewPort })
|
|
236
288
|
] }),
|
|
237
|
-
command === "update" /* UPDATE */ && bundleUrl && /* @__PURE__ */
|
|
238
|
-
/* @__PURE__ */
|
|
239
|
-
/* @__PURE__ */
|
|
289
|
+
command === "update" /* UPDATE */ && bundleUrl && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
290
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Bundle URL " }),
|
|
291
|
+
/* @__PURE__ */ jsx(Text, { children: bundleUrl })
|
|
240
292
|
] }),
|
|
241
|
-
command === "update" /* UPDATE */ && enabled !== void 0 && /* @__PURE__ */
|
|
242
|
-
/* @__PURE__ */
|
|
243
|
-
/* @__PURE__ */
|
|
293
|
+
command === "update" /* UPDATE */ && enabled !== void 0 && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
294
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Enabled " }),
|
|
295
|
+
/* @__PURE__ */ jsx(Text, { color: enabled ? "green" : "red", children: enabled ? "Yes" : "No" })
|
|
244
296
|
] }),
|
|
245
|
-
/* @__PURE__ */
|
|
246
|
-
/* @__PURE__ */
|
|
247
|
-
/* @__PURE__ */
|
|
297
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
298
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Targets " }),
|
|
299
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
248
300
|
targets.map((t) => {
|
|
249
301
|
const isAdded = registryTargets && !registryTargets.includes(t);
|
|
250
|
-
return /* @__PURE__ */
|
|
251
|
-
/* @__PURE__ */
|
|
252
|
-
/* @__PURE__ */
|
|
253
|
-
isAdded && /* @__PURE__ */
|
|
302
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
303
|
+
/* @__PURE__ */ jsx(Text, { color: "green", children: "\u2022 " }),
|
|
304
|
+
/* @__PURE__ */ jsx(Text, { children: t }),
|
|
305
|
+
isAdded && /* @__PURE__ */ jsx(Text, { color: "green", dimColor: true, children: "(+ added)" })
|
|
254
306
|
] }, t);
|
|
255
307
|
}),
|
|
256
|
-
registryTargets?.filter((t) => !targets.includes(t)).map((t) => /* @__PURE__ */
|
|
257
|
-
/* @__PURE__ */
|
|
258
|
-
/* @__PURE__ */
|
|
259
|
-
/* @__PURE__ */
|
|
308
|
+
registryTargets?.filter((t) => !targets.includes(t)).map((t) => /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
309
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: "\u2022 " }),
|
|
310
|
+
/* @__PURE__ */ jsx(Text, { color: "red", dimColor: true, strikethrough: true, children: t }),
|
|
311
|
+
/* @__PURE__ */ jsx(Text, { color: "red", dimColor: true, children: "(- removed)" })
|
|
260
312
|
] }, t))
|
|
261
313
|
] })
|
|
262
314
|
] }),
|
|
263
|
-
permissions && (permissions.length > 0 || registryPermissions?.some((p) => !permissions.includes(p))) && /* @__PURE__ */
|
|
264
|
-
/* @__PURE__ */
|
|
265
|
-
/* @__PURE__ */
|
|
315
|
+
permissions && (permissions.length > 0 || registryPermissions?.some((p) => !permissions.includes(p))) && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
316
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Permissions " }),
|
|
317
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
266
318
|
permissions.map((p) => {
|
|
267
319
|
const isAdded = registryPermissions && !registryPermissions.includes(p);
|
|
268
|
-
return /* @__PURE__ */
|
|
269
|
-
/* @__PURE__ */
|
|
270
|
-
/* @__PURE__ */
|
|
271
|
-
isAdded && /* @__PURE__ */
|
|
320
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
321
|
+
/* @__PURE__ */ jsx(Text, { color: "green", children: "\u2022 " }),
|
|
322
|
+
/* @__PURE__ */ jsx(Text, { children: p }),
|
|
323
|
+
isAdded && /* @__PURE__ */ jsx(Text, { color: "green", dimColor: true, children: "(+ added)" })
|
|
272
324
|
] }, p);
|
|
273
325
|
}),
|
|
274
|
-
registryPermissions?.filter((p) => !permissions.includes(p)).map((p) => /* @__PURE__ */
|
|
275
|
-
/* @__PURE__ */
|
|
276
|
-
/* @__PURE__ */
|
|
277
|
-
/* @__PURE__ */
|
|
326
|
+
registryPermissions?.filter((p) => !permissions.includes(p)).map((p) => /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
327
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: "\u2022 " }),
|
|
328
|
+
/* @__PURE__ */ jsx(Text, { color: "red", dimColor: true, strikethrough: true, children: p }),
|
|
329
|
+
/* @__PURE__ */ jsx(Text, { color: "red", dimColor: true, children: "(- removed)" })
|
|
278
330
|
] }, p))
|
|
279
331
|
] })
|
|
280
332
|
] }),
|
|
281
|
-
allowedDomains && (allowedDomains.length > 0 || registryAllowedDomains?.some((d) => !allowedDomains.includes(d))) && /* @__PURE__ */
|
|
282
|
-
/* @__PURE__ */
|
|
283
|
-
/* @__PURE__ */
|
|
333
|
+
allowedDomains && (allowedDomains.length > 0 || registryAllowedDomains?.some((d) => !allowedDomains.includes(d))) && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
334
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Domains " }),
|
|
335
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
284
336
|
allowedDomains.map((d) => {
|
|
285
337
|
const isAdded = registryAllowedDomains && !registryAllowedDomains.includes(d);
|
|
286
|
-
return /* @__PURE__ */
|
|
287
|
-
/* @__PURE__ */
|
|
288
|
-
/* @__PURE__ */
|
|
289
|
-
isAdded && /* @__PURE__ */
|
|
338
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
339
|
+
/* @__PURE__ */ jsx(Text, { color: "green", children: "\u2022 " }),
|
|
340
|
+
/* @__PURE__ */ jsx(Text, { children: d }),
|
|
341
|
+
isAdded && /* @__PURE__ */ jsx(Text, { color: "green", dimColor: true, children: "(+ added)" })
|
|
290
342
|
] }, d);
|
|
291
343
|
}),
|
|
292
|
-
registryAllowedDomains?.filter((d) => !allowedDomains.includes(d)).map((d) => /* @__PURE__ */
|
|
293
|
-
/* @__PURE__ */
|
|
294
|
-
/* @__PURE__ */
|
|
295
|
-
/* @__PURE__ */
|
|
344
|
+
registryAllowedDomains?.filter((d) => !allowedDomains.includes(d)).map((d) => /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
345
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: "\u2022 " }),
|
|
346
|
+
/* @__PURE__ */ jsx(Text, { color: "red", dimColor: true, strikethrough: true, children: d }),
|
|
347
|
+
/* @__PURE__ */ jsx(Text, { color: "red", dimColor: true, children: "(- removed)" })
|
|
296
348
|
] }, d))
|
|
297
349
|
] })
|
|
298
350
|
] })
|
|
@@ -300,75 +352,59 @@ var Confirm = ({
|
|
|
300
352
|
}
|
|
301
353
|
);
|
|
302
354
|
};
|
|
303
|
-
|
|
304
|
-
// src/components/Done.tsx
|
|
305
|
-
import { Box as Box3, Text as Text3 } from "ink";
|
|
306
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
307
355
|
var FLAVOR_HINTS = {
|
|
308
356
|
minimal: "A clean slate \u2014 add surfaces and capabilities as you need them.",
|
|
309
357
|
starter: "Common patterns included \u2014 customize and build from here.",
|
|
310
358
|
"kitchen-sink": "We threw in everything \u2014 including the kitchen sink. Poke around, steal patterns, then delete what you don't need."
|
|
311
359
|
};
|
|
312
|
-
var Done = ({ name, outputDir, templateFlavor }) => /* @__PURE__ */
|
|
313
|
-
/* @__PURE__ */
|
|
314
|
-
/* @__PURE__ */
|
|
315
|
-
/* @__PURE__ */
|
|
360
|
+
var Done = ({ name, outputDir, templateFlavor }) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
361
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
362
|
+
/* @__PURE__ */ jsx(Text, { color: "green", bold: true, children: "\u2714" }),
|
|
363
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Extension scaffolded successfully!" })
|
|
316
364
|
] }),
|
|
317
|
-
/* @__PURE__ */
|
|
318
|
-
/* @__PURE__ */
|
|
365
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [
|
|
366
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
319
367
|
"Created: ",
|
|
320
|
-
/* @__PURE__ */
|
|
368
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: name })
|
|
321
369
|
] }),
|
|
322
|
-
templateFlavor && /* @__PURE__ */
|
|
370
|
+
templateFlavor && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
323
371
|
"Template: ",
|
|
324
|
-
/* @__PURE__ */
|
|
372
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: TEMPLATE_FLAVOR_META[templateFlavor].label })
|
|
325
373
|
] }),
|
|
326
|
-
/* @__PURE__ */
|
|
374
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
327
375
|
"Location: ",
|
|
328
|
-
/* @__PURE__ */
|
|
376
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: outputDir })
|
|
329
377
|
] })
|
|
330
378
|
] }),
|
|
331
|
-
templateFlavor && /* @__PURE__ */
|
|
332
|
-
/* @__PURE__ */
|
|
333
|
-
/* @__PURE__ */
|
|
334
|
-
/* @__PURE__ */
|
|
335
|
-
/* @__PURE__ */
|
|
336
|
-
/* @__PURE__ */
|
|
337
|
-
/* @__PURE__ */
|
|
338
|
-
/* @__PURE__ */
|
|
339
|
-
/* @__PURE__ */
|
|
379
|
+
templateFlavor && /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: FLAVOR_HINTS[templateFlavor] }) }),
|
|
380
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, children: [
|
|
381
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Next steps:" }),
|
|
382
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, gap: 1, children: [
|
|
383
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
384
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "1." }),
|
|
385
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
386
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "cd " }),
|
|
387
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: outputDir })
|
|
340
388
|
] })
|
|
341
389
|
] }),
|
|
342
|
-
/* @__PURE__ */
|
|
343
|
-
/* @__PURE__ */
|
|
344
|
-
/* @__PURE__ */
|
|
390
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
391
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "2." }),
|
|
392
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "pnpm install" })
|
|
345
393
|
] }),
|
|
346
|
-
/* @__PURE__ */
|
|
347
|
-
/* @__PURE__ */
|
|
348
|
-
/* @__PURE__ */
|
|
394
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
395
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "3." }),
|
|
396
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "pnpm dev" })
|
|
349
397
|
] })
|
|
350
398
|
] })
|
|
351
399
|
] })
|
|
352
400
|
] });
|
|
353
|
-
|
|
354
|
-
// src/components/NamePrompt.tsx
|
|
355
|
-
import { Box as Box5, Text as Text5 } from "ink";
|
|
356
|
-
import TextInput2 from "ink-text-input";
|
|
357
|
-
import { useState as useState2 } from "react";
|
|
358
|
-
|
|
359
|
-
// src/components/BackableInput.tsx
|
|
360
|
-
import { Box as Box4, Text as Text4 } from "ink";
|
|
361
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
362
|
-
var BackableInput = ({ label, hint, onBack, children, error }) => /* @__PURE__ */ jsx4(StepShell, { title: label, hint, onBack, children: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, children: [
|
|
401
|
+
var BackableInput = ({ label, hint, onBack, children, error }) => /* @__PURE__ */ jsx(StepShell, { title: label, hint, onBack, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
363
402
|
children(true),
|
|
364
|
-
error && /* @__PURE__ */
|
|
403
|
+
error && /* @__PURE__ */ jsx(Text, { color: "red", children: error })
|
|
365
404
|
] }) });
|
|
366
|
-
|
|
367
|
-
// src/components/NamePrompt.tsx
|
|
368
|
-
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
369
405
|
var NamePrompt = ({ initialValue = "", onSubmit, onBack }) => {
|
|
370
|
-
const [value, setValue] =
|
|
371
|
-
const [error, setError] =
|
|
406
|
+
const [value, setValue] = useState(initialValue);
|
|
407
|
+
const [error, setError] = useState();
|
|
372
408
|
const handleSubmit = (val) => {
|
|
373
409
|
const trimmed = val.trim();
|
|
374
410
|
if (trimmed.length === 0) {
|
|
@@ -378,33 +414,27 @@ var NamePrompt = ({ initialValue = "", onSubmit, onBack }) => {
|
|
|
378
414
|
setError(void 0);
|
|
379
415
|
onSubmit(trimmed);
|
|
380
416
|
};
|
|
381
|
-
return /* @__PURE__ */
|
|
382
|
-
/* @__PURE__ */
|
|
383
|
-
/* @__PURE__ */
|
|
417
|
+
return /* @__PURE__ */ jsx(BackableInput, { label: "What is your Extension name?", hint: "Press Enter to confirm", onBack, error, children: (isFocused) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
418
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "> " }),
|
|
419
|
+
/* @__PURE__ */ jsx(TextInput, { value, onChange: setValue, onSubmit: handleSubmit, focus: isFocused })
|
|
384
420
|
] }) });
|
|
385
421
|
};
|
|
386
|
-
|
|
387
|
-
// src/components/SettingsPrompt.tsx
|
|
388
|
-
import { Box as Box6, Text as Text6, useFocus as useFocus2, useFocusManager as useFocusManager2, useInput as useInput3 } from "ink";
|
|
389
|
-
import TextInput3 from "ink-text-input";
|
|
390
|
-
import { useState as useState3 } from "react";
|
|
391
|
-
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
392
422
|
var DEFAULT_EXTENSION_PORT = 6543;
|
|
393
423
|
var DEFAULT_PREVIEW_PORT = DEFAULT_EXTENSION_PORT + 1;
|
|
394
424
|
var FieldRow = ({ label, value, onChange, onSubmit, onConfirm, placeholder, autoFocus, isFirst, isLast }) => {
|
|
395
|
-
const { isFocused } =
|
|
396
|
-
const { focusNext, focusPrevious } =
|
|
397
|
-
|
|
425
|
+
const { isFocused } = useFocus({ autoFocus });
|
|
426
|
+
const { focusNext, focusPrevious } = useFocusManager();
|
|
427
|
+
useInput((_input, key) => {
|
|
398
428
|
if (!isFocused) return;
|
|
399
429
|
if (key.downArrow && !isLast) focusNext();
|
|
400
430
|
if (key.upArrow && !isFirst) focusPrevious();
|
|
401
431
|
});
|
|
402
|
-
return /* @__PURE__ */
|
|
403
|
-
/* @__PURE__ */
|
|
404
|
-
isFocused ? /* @__PURE__ */
|
|
405
|
-
/* @__PURE__ */
|
|
406
|
-
/* @__PURE__ */
|
|
407
|
-
|
|
432
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
433
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: label }),
|
|
434
|
+
isFocused ? /* @__PURE__ */ jsxs(Box, { children: [
|
|
435
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u2192 " }),
|
|
436
|
+
/* @__PURE__ */ jsx(
|
|
437
|
+
TextInput,
|
|
408
438
|
{
|
|
409
439
|
value,
|
|
410
440
|
onChange,
|
|
@@ -416,13 +446,13 @@ var FieldRow = ({ label, value, onChange, onSubmit, onConfirm, placeholder, auto
|
|
|
416
446
|
focus: isFocused
|
|
417
447
|
}
|
|
418
448
|
)
|
|
419
|
-
] }) : /* @__PURE__ */
|
|
449
|
+
] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: value })
|
|
420
450
|
] });
|
|
421
451
|
};
|
|
422
452
|
var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
|
|
423
|
-
const [extensionPort, setExtensionPort] =
|
|
424
|
-
const [previewPort, setPreviewPort] =
|
|
425
|
-
const [outputDir, setOutputDir] =
|
|
453
|
+
const [extensionPort, setExtensionPort] = useState(String(DEFAULT_EXTENSION_PORT));
|
|
454
|
+
const [previewPort, setPreviewPort] = useState(String(DEFAULT_PREVIEW_PORT));
|
|
455
|
+
const [outputDir, setOutputDir] = useState(defaultDir);
|
|
426
456
|
const handleConfirm = (resolvedExtPort, resolvedPrevPort, resolvedDir) => {
|
|
427
457
|
const dir = resolvedDir.trim();
|
|
428
458
|
if (!dir) return;
|
|
@@ -453,14 +483,14 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
|
|
|
453
483
|
setOutputDir(trimmed);
|
|
454
484
|
return [extensionPort, previewPort, trimmed];
|
|
455
485
|
};
|
|
456
|
-
return /* @__PURE__ */
|
|
486
|
+
return /* @__PURE__ */ jsx(
|
|
457
487
|
StepShell,
|
|
458
488
|
{
|
|
459
489
|
title: "Project settings",
|
|
460
490
|
hint: "\u2191\u2193 or Tab to move between fields, Enter to confirm",
|
|
461
491
|
onBack,
|
|
462
|
-
children: /* @__PURE__ */
|
|
463
|
-
/* @__PURE__ */
|
|
492
|
+
children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
493
|
+
/* @__PURE__ */ jsx(
|
|
464
494
|
FieldRow,
|
|
465
495
|
{
|
|
466
496
|
label: "Extension port ",
|
|
@@ -473,7 +503,7 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
|
|
|
473
503
|
isFirst: true
|
|
474
504
|
}
|
|
475
505
|
),
|
|
476
|
-
/* @__PURE__ */
|
|
506
|
+
/* @__PURE__ */ jsx(
|
|
477
507
|
FieldRow,
|
|
478
508
|
{
|
|
479
509
|
label: "Preview port ",
|
|
@@ -484,7 +514,7 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
|
|
|
484
514
|
placeholder: String(DEFAULT_PREVIEW_PORT)
|
|
485
515
|
}
|
|
486
516
|
),
|
|
487
|
-
/* @__PURE__ */
|
|
517
|
+
/* @__PURE__ */ jsx(
|
|
488
518
|
FieldRow,
|
|
489
519
|
{
|
|
490
520
|
label: "Output directory",
|
|
@@ -500,10 +530,6 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
|
|
|
500
530
|
);
|
|
501
531
|
};
|
|
502
532
|
|
|
503
|
-
// src/components/ManifestReviewPrompt.tsx
|
|
504
|
-
import { Box as Box7, Text as Text7, useInput as useInput4 } from "ink";
|
|
505
|
-
import { useState as useState4 } from "react";
|
|
506
|
-
|
|
507
533
|
// src/lib/manifest-diff.ts
|
|
508
534
|
var diffManifestValues = (localValues, registryValues) => {
|
|
509
535
|
const localSet = new Set(localValues ?? []);
|
|
@@ -518,9 +544,6 @@ var diffManifestValues = (localValues, registryValues) => {
|
|
|
518
544
|
return inRegistry ? { value, status: "unchanged", enabled: true } : { value, status: "new", enabled: false };
|
|
519
545
|
});
|
|
520
546
|
};
|
|
521
|
-
|
|
522
|
-
// src/components/ManifestReviewPrompt.tsx
|
|
523
|
-
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
524
547
|
var statusLabel = (status) => {
|
|
525
548
|
switch (status) {
|
|
526
549
|
case "new":
|
|
@@ -547,9 +570,9 @@ var ManifestReviewPrompt = ({
|
|
|
547
570
|
onSubmit,
|
|
548
571
|
onBack
|
|
549
572
|
}) => {
|
|
550
|
-
const [permItems, setPermItems] =
|
|
551
|
-
const [domainItems, setDomainItems] =
|
|
552
|
-
const [cursor, setCursor] =
|
|
573
|
+
const [permItems, setPermItems] = useState(() => diffManifestValues(localManifest?.permissions, registryManifest.permissions));
|
|
574
|
+
const [domainItems, setDomainItems] = useState(() => diffManifestValues(localManifest?.allowedDomains, registryManifest.allowedDomains));
|
|
575
|
+
const [cursor, setCursor] = useState(0);
|
|
553
576
|
const totalItems = permItems.length + domainItems.length;
|
|
554
577
|
const cursorInPerms = cursor < permItems.length;
|
|
555
578
|
const cursorInDomains = cursor >= permItems.length;
|
|
@@ -568,7 +591,7 @@ var ManifestReviewPrompt = ({
|
|
|
568
591
|
});
|
|
569
592
|
};
|
|
570
593
|
const domainSectionStart = permItems.length;
|
|
571
|
-
|
|
594
|
+
useInput((input, key) => {
|
|
572
595
|
if (key.downArrow) {
|
|
573
596
|
setCursor((c) => Math.min(c + 1, totalItems - 1));
|
|
574
597
|
return;
|
|
@@ -601,49 +624,43 @@ var ManifestReviewPrompt = ({
|
|
|
601
624
|
});
|
|
602
625
|
const renderItem = (item, index) => {
|
|
603
626
|
const isCursor = index === cursor;
|
|
604
|
-
return /* @__PURE__ */
|
|
605
|
-
/* @__PURE__ */
|
|
606
|
-
/* @__PURE__ */
|
|
607
|
-
/* @__PURE__ */
|
|
608
|
-
statusLabel(item.status) && /* @__PURE__ */
|
|
627
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
628
|
+
/* @__PURE__ */ jsx(Text, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
|
|
629
|
+
/* @__PURE__ */ jsx(Text, { color: item.enabled ? "green" : "gray", children: item.enabled ? "\u25C9" : "\u25CB" }),
|
|
630
|
+
/* @__PURE__ */ jsx(Text, { bold: isCursor, children: item.value }),
|
|
631
|
+
statusLabel(item.status) && /* @__PURE__ */ jsx(Text, { color: statusColor(item.status), dimColor: true, children: statusLabel(item.status) })
|
|
609
632
|
] }, item.value);
|
|
610
633
|
};
|
|
611
|
-
return /* @__PURE__ */
|
|
634
|
+
return /* @__PURE__ */ jsx(
|
|
612
635
|
StepShell,
|
|
613
636
|
{
|
|
614
637
|
title: "Review Manifest changes",
|
|
615
638
|
hint: "Tab/shift-tab to jump section, \u2191/\u2193 navigate. Enter to submit",
|
|
616
639
|
onBack,
|
|
617
|
-
children: /* @__PURE__ */
|
|
618
|
-
!localManifest && /* @__PURE__ */
|
|
619
|
-
/* @__PURE__ */
|
|
620
|
-
/* @__PURE__ */
|
|
621
|
-
/* @__PURE__ */
|
|
622
|
-
permItems.length > 0 ? permItems.map((item, i) => renderItem(item, i)) : /* @__PURE__ */
|
|
623
|
-
cursorInPerms && /* @__PURE__ */
|
|
640
|
+
children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
641
|
+
!localManifest && /* @__PURE__ */ jsx(Text, { color: "yellow", children: "No local manifest.json found \u2014 showing registry values only" }),
|
|
642
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
643
|
+
/* @__PURE__ */ jsx(Text, { dimColor: !cursorInPerms, bold: cursorInPerms, children: "Permissions".padEnd(14) }),
|
|
644
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 2, children: [
|
|
645
|
+
permItems.length > 0 ? permItems.map((item, i) => renderItem(item, i)) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (none)" }),
|
|
646
|
+
cursorInPerms && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (space to toggle)" })
|
|
624
647
|
] })
|
|
625
648
|
] }),
|
|
626
|
-
/* @__PURE__ */
|
|
627
|
-
/* @__PURE__ */
|
|
628
|
-
/* @__PURE__ */
|
|
629
|
-
domainItems.length > 0 ? domainItems.map((item, i) => renderItem(item, i + permItems.length)) : /* @__PURE__ */
|
|
630
|
-
cursorInDomains && /* @__PURE__ */
|
|
649
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
650
|
+
/* @__PURE__ */ jsx(Text, { dimColor: !cursorInDomains, bold: cursorInDomains, children: "Allowed Domains".padEnd(14) }),
|
|
651
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 2, children: [
|
|
652
|
+
domainItems.length > 0 ? domainItems.map((item, i) => renderItem(item, i + permItems.length)) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (none)" }),
|
|
653
|
+
cursorInDomains && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (space to toggle)" })
|
|
631
654
|
] })
|
|
632
655
|
] })
|
|
633
656
|
] })
|
|
634
657
|
}
|
|
635
658
|
);
|
|
636
659
|
};
|
|
637
|
-
|
|
638
|
-
// src/components/UpdateSettingsPrompt.tsx
|
|
639
|
-
import { Box as Box8, Text as Text8, useFocus as useFocus3, useFocusManager as useFocusManager3, useInput as useInput5 } from "ink";
|
|
640
|
-
import TextInput4 from "ink-text-input";
|
|
641
|
-
import { useState as useState5 } from "react";
|
|
642
|
-
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
643
660
|
var FieldRow2 = ({ label, value, onChange, placeholder, autoFocus, isFirst, isLast, onSubmitAll }) => {
|
|
644
|
-
const { isFocused } =
|
|
645
|
-
const { focusNext, focusPrevious } =
|
|
646
|
-
|
|
661
|
+
const { isFocused } = useFocus({ autoFocus });
|
|
662
|
+
const { focusNext, focusPrevious } = useFocusManager();
|
|
663
|
+
useInput((_, key) => {
|
|
647
664
|
if (!isFocused) return;
|
|
648
665
|
if (key.downArrow) {
|
|
649
666
|
if (!isLast) focusNext();
|
|
@@ -657,16 +674,16 @@ var FieldRow2 = ({ label, value, onChange, placeholder, autoFocus, isFirst, isLa
|
|
|
657
674
|
onSubmitAll();
|
|
658
675
|
}
|
|
659
676
|
});
|
|
660
|
-
return /* @__PURE__ */
|
|
661
|
-
/* @__PURE__ */
|
|
662
|
-
isFocused ? /* @__PURE__ */
|
|
677
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
678
|
+
/* @__PURE__ */ jsx(Text, { dimColor: !isFocused, bold: isFocused, children: label.padEnd(14) }),
|
|
679
|
+
isFocused ? /* @__PURE__ */ jsx(TextInput, { value, onChange, placeholder }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: value || placeholder || "" })
|
|
663
680
|
] });
|
|
664
681
|
};
|
|
665
682
|
var TargetToggleRow = ({ targets, availableTargets, onToggle, autoFocus, isLast, onSubmitAll }) => {
|
|
666
|
-
const { isFocused } =
|
|
667
|
-
const { focusNext, focusPrevious } =
|
|
668
|
-
const [cursor, setCursor] =
|
|
669
|
-
|
|
683
|
+
const { isFocused } = useFocus({ autoFocus });
|
|
684
|
+
const { focusNext, focusPrevious } = useFocusManager();
|
|
685
|
+
const [cursor, setCursor] = useState(0);
|
|
686
|
+
useInput((input, key) => {
|
|
670
687
|
if (!isFocused) return;
|
|
671
688
|
if (key.downArrow) {
|
|
672
689
|
if (cursor < availableTargets.length - 1) {
|
|
@@ -692,26 +709,26 @@ var TargetToggleRow = ({ targets, availableTargets, onToggle, autoFocus, isLast,
|
|
|
692
709
|
onSubmitAll();
|
|
693
710
|
}
|
|
694
711
|
});
|
|
695
|
-
return /* @__PURE__ */
|
|
696
|
-
/* @__PURE__ */
|
|
697
|
-
/* @__PURE__ */
|
|
712
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
713
|
+
/* @__PURE__ */ jsx(Text, { dimColor: !isFocused, bold: isFocused, children: "Targets".padEnd(14) }),
|
|
714
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 2, children: [
|
|
698
715
|
availableTargets.map((t, i) => {
|
|
699
716
|
const selected = targets.includes(t);
|
|
700
717
|
const isCursor = isFocused && i === cursor;
|
|
701
|
-
return /* @__PURE__ */
|
|
702
|
-
/* @__PURE__ */
|
|
703
|
-
/* @__PURE__ */
|
|
704
|
-
/* @__PURE__ */
|
|
718
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
719
|
+
/* @__PURE__ */ jsx(Text, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
|
|
720
|
+
/* @__PURE__ */ jsx(Text, { color: selected ? "green" : "gray", children: selected ? "\u25C9" : "\u25CB" }),
|
|
721
|
+
/* @__PURE__ */ jsx(Text, { bold: isCursor, children: t })
|
|
705
722
|
] }, t);
|
|
706
723
|
}),
|
|
707
|
-
isFocused && /* @__PURE__ */
|
|
724
|
+
isFocused && /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (space to toggle)" })
|
|
708
725
|
] })
|
|
709
726
|
] });
|
|
710
727
|
};
|
|
711
728
|
var EnabledToggleRow = ({ enabled, onToggle, autoFocus, isLast, onSubmitAll }) => {
|
|
712
|
-
const { isFocused } =
|
|
713
|
-
const { focusNext, focusPrevious } =
|
|
714
|
-
|
|
729
|
+
const { isFocused } = useFocus({ autoFocus });
|
|
730
|
+
const { focusNext, focusPrevious } = useFocusManager();
|
|
731
|
+
useInput((input, key) => {
|
|
715
732
|
if (!isFocused) return;
|
|
716
733
|
if (key.downArrow) {
|
|
717
734
|
if (!isLast) focusNext();
|
|
@@ -729,16 +746,16 @@ var EnabledToggleRow = ({ enabled, onToggle, autoFocus, isLast, onSubmitAll }) =
|
|
|
729
746
|
onSubmitAll();
|
|
730
747
|
}
|
|
731
748
|
});
|
|
732
|
-
return /* @__PURE__ */
|
|
733
|
-
/* @__PURE__ */
|
|
734
|
-
/* @__PURE__ */
|
|
735
|
-
isFocused && /* @__PURE__ */
|
|
749
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
750
|
+
/* @__PURE__ */ jsx(Text, { dimColor: !isFocused, bold: isFocused, children: "Enabled".padEnd(14) }),
|
|
751
|
+
/* @__PURE__ */ jsx(Text, { color: enabled ? "green" : "red", bold: isFocused, children: enabled ? "Yes" : "No" }),
|
|
752
|
+
isFocused && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(space/arrows to toggle)" })
|
|
736
753
|
] });
|
|
737
754
|
};
|
|
738
755
|
var ForceMajorToggleRow = ({ forceMajor, onToggle, autoFocus, isLast, onSubmitAll }) => {
|
|
739
|
-
const { isFocused } =
|
|
740
|
-
const { focusPrevious, focusNext } =
|
|
741
|
-
|
|
756
|
+
const { isFocused } = useFocus({ autoFocus });
|
|
757
|
+
const { focusPrevious, focusNext } = useFocusManager();
|
|
758
|
+
useInput((input, key) => {
|
|
742
759
|
if (!isFocused) return;
|
|
743
760
|
if (key.downArrow) {
|
|
744
761
|
if (!isLast) focusNext();
|
|
@@ -756,10 +773,10 @@ var ForceMajorToggleRow = ({ forceMajor, onToggle, autoFocus, isLast, onSubmitAl
|
|
|
756
773
|
onSubmitAll();
|
|
757
774
|
}
|
|
758
775
|
});
|
|
759
|
-
return /* @__PURE__ */
|
|
760
|
-
/* @__PURE__ */
|
|
761
|
-
/* @__PURE__ */
|
|
762
|
-
isFocused && /* @__PURE__ */
|
|
776
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
777
|
+
/* @__PURE__ */ jsx(Text, { dimColor: !isFocused, bold: isFocused, children: "Force major".padEnd(14) }),
|
|
778
|
+
/* @__PURE__ */ jsx(Text, { color: forceMajor ? "yellow" : "gray", bold: isFocused, children: forceMajor ? "Yes" : "No" }),
|
|
779
|
+
isFocused && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(space/arrows to toggle)" })
|
|
763
780
|
] });
|
|
764
781
|
};
|
|
765
782
|
var UpdateSettingsPrompt = ({
|
|
@@ -767,15 +784,17 @@ var UpdateSettingsPrompt = ({
|
|
|
767
784
|
targets: initialTargets,
|
|
768
785
|
availableTargets,
|
|
769
786
|
bundleUrl: initialBundleUrl,
|
|
787
|
+
allowedDomains: initialAllowedDomains,
|
|
770
788
|
enabled: initialEnabled,
|
|
771
789
|
onSubmit,
|
|
772
790
|
onBack
|
|
773
791
|
}) => {
|
|
774
|
-
const [nameValue, setNameValue] =
|
|
775
|
-
const [targetsValue, setTargetsValue] =
|
|
776
|
-
const [bundleUrlValue, setBundleUrlValue] =
|
|
777
|
-
const [
|
|
778
|
-
const [
|
|
792
|
+
const [nameValue, setNameValue] = useState(initialName);
|
|
793
|
+
const [targetsValue, setTargetsValue] = useState(initialTargets);
|
|
794
|
+
const [bundleUrlValue, setBundleUrlValue] = useState(initialBundleUrl);
|
|
795
|
+
const [allowedDomainsValue, setAllowedDomainsValue] = useState(initialAllowedDomains.join(", "));
|
|
796
|
+
const [enabledValue, setEnabledValue] = useState(initialEnabled);
|
|
797
|
+
const [forceMajorValue, setForceMajorValue] = useState(false);
|
|
779
798
|
const handleToggleTarget = (target) => {
|
|
780
799
|
setTargetsValue((prev) => prev.includes(target) ? prev.filter((t) => t !== target) : [...prev, target]);
|
|
781
800
|
};
|
|
@@ -785,18 +804,19 @@ var UpdateSettingsPrompt = ({
|
|
|
785
804
|
name: nameValue,
|
|
786
805
|
targets: targetsValue,
|
|
787
806
|
bundleUrl: bundleUrlValue,
|
|
807
|
+
allowedDomains: allowedDomainsValue.split(",").map((d) => d.trim()).filter(Boolean),
|
|
788
808
|
enabled: enabledValue,
|
|
789
809
|
forceMajor: forceMajorValue
|
|
790
810
|
});
|
|
791
811
|
};
|
|
792
|
-
return /* @__PURE__ */
|
|
812
|
+
return /* @__PURE__ */ jsx(
|
|
793
813
|
StepShell,
|
|
794
814
|
{
|
|
795
815
|
title: "Update Extension settings",
|
|
796
816
|
hint: "Tab/shift-tab to jump section, \u2191/\u2193 navigate. Enter to submit",
|
|
797
817
|
onBack,
|
|
798
|
-
children: /* @__PURE__ */
|
|
799
|
-
/* @__PURE__ */
|
|
818
|
+
children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
819
|
+
/* @__PURE__ */ jsx(
|
|
800
820
|
FieldRow2,
|
|
801
821
|
{
|
|
802
822
|
label: "Name",
|
|
@@ -808,7 +828,7 @@ var UpdateSettingsPrompt = ({
|
|
|
808
828
|
onSubmitAll: handleSubmitAll
|
|
809
829
|
}
|
|
810
830
|
),
|
|
811
|
-
/* @__PURE__ */
|
|
831
|
+
/* @__PURE__ */ jsx(
|
|
812
832
|
TargetToggleRow,
|
|
813
833
|
{
|
|
814
834
|
targets: targetsValue,
|
|
@@ -817,7 +837,7 @@ var UpdateSettingsPrompt = ({
|
|
|
817
837
|
onSubmitAll: handleSubmitAll
|
|
818
838
|
}
|
|
819
839
|
),
|
|
820
|
-
/* @__PURE__ */
|
|
840
|
+
/* @__PURE__ */ jsx(
|
|
821
841
|
FieldRow2,
|
|
822
842
|
{
|
|
823
843
|
label: "Bundle URL",
|
|
@@ -827,7 +847,17 @@ var UpdateSettingsPrompt = ({
|
|
|
827
847
|
onSubmitAll: handleSubmitAll
|
|
828
848
|
}
|
|
829
849
|
),
|
|
830
|
-
/* @__PURE__ */
|
|
850
|
+
/* @__PURE__ */ jsx(
|
|
851
|
+
FieldRow2,
|
|
852
|
+
{
|
|
853
|
+
label: "Allowed Domains",
|
|
854
|
+
value: allowedDomainsValue,
|
|
855
|
+
onChange: setAllowedDomainsValue,
|
|
856
|
+
placeholder: "api.example.com, cdn.example.com",
|
|
857
|
+
onSubmitAll: handleSubmitAll
|
|
858
|
+
}
|
|
859
|
+
),
|
|
860
|
+
/* @__PURE__ */ jsx(
|
|
831
861
|
EnabledToggleRow,
|
|
832
862
|
{
|
|
833
863
|
enabled: enabledValue,
|
|
@@ -835,7 +865,7 @@ var UpdateSettingsPrompt = ({
|
|
|
835
865
|
onSubmitAll: handleSubmitAll
|
|
836
866
|
}
|
|
837
867
|
),
|
|
838
|
-
/* @__PURE__ */
|
|
868
|
+
/* @__PURE__ */ jsx(
|
|
839
869
|
ForceMajorToggleRow,
|
|
840
870
|
{
|
|
841
871
|
forceMajor: forceMajorValue,
|
|
@@ -848,35 +878,25 @@ var UpdateSettingsPrompt = ({
|
|
|
848
878
|
}
|
|
849
879
|
);
|
|
850
880
|
};
|
|
851
|
-
|
|
852
|
-
// src/components/ScaffoldProgress.tsx
|
|
853
|
-
import { Box as Box9, Text as Text9 } from "ink";
|
|
854
|
-
import Spinner from "ink-spinner";
|
|
855
|
-
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
856
881
|
var stepIcon = (status) => {
|
|
857
882
|
switch (status) {
|
|
858
883
|
case "running":
|
|
859
|
-
return /* @__PURE__ */
|
|
884
|
+
return /* @__PURE__ */ jsx(Spinner5, { type: "dots" });
|
|
860
885
|
case "done":
|
|
861
|
-
return /* @__PURE__ */
|
|
886
|
+
return /* @__PURE__ */ jsx(Text, { color: "green", children: "\u2714" });
|
|
862
887
|
case "error":
|
|
863
|
-
return /* @__PURE__ */
|
|
888
|
+
return /* @__PURE__ */ jsx(Text, { color: "red", children: "\u2716" });
|
|
864
889
|
default:
|
|
865
|
-
return /* @__PURE__ */
|
|
890
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u25CB" });
|
|
866
891
|
}
|
|
867
892
|
};
|
|
868
|
-
var ScaffoldProgress = ({ steps }) => /* @__PURE__ */
|
|
869
|
-
/* @__PURE__ */
|
|
870
|
-
/* @__PURE__ */
|
|
893
|
+
var ScaffoldProgress = ({ steps }) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
894
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Scaffolding your Extension\u2026" }),
|
|
895
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", children: steps.map((step) => /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
871
896
|
stepIcon(step.status),
|
|
872
|
-
/* @__PURE__ */
|
|
897
|
+
/* @__PURE__ */ jsx(Text, { dimColor: step.status === "pending", color: step.status === "running" ? "cyan" : void 0, children: step.label })
|
|
873
898
|
] }, step.label)) })
|
|
874
899
|
] });
|
|
875
|
-
|
|
876
|
-
// src/components/TargetSelect.tsx
|
|
877
|
-
import { Box as Box10, Text as Text10, useInput as useInput6 } from "ink";
|
|
878
|
-
import { useState as useState6 } from "react";
|
|
879
|
-
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
880
900
|
var TARGET_DESCRIPTIONS = {
|
|
881
901
|
"slot.header": "Renders content in the panel header area",
|
|
882
902
|
"slot.content": "Renders the main panel body (includes store + navigation state)",
|
|
@@ -884,12 +904,12 @@ var TARGET_DESCRIPTIONS = {
|
|
|
884
904
|
"slot.footer-links": "Renders a link row in the global footer"
|
|
885
905
|
};
|
|
886
906
|
var TargetSelect = ({ availableTargets, preSelected, onSubmit, onBack }) => {
|
|
887
|
-
const [cursor, setCursor] =
|
|
888
|
-
const [selected, setSelected] =
|
|
907
|
+
const [cursor, setCursor] = useState(0);
|
|
908
|
+
const [selected, setSelected] = useState(
|
|
889
909
|
new Set(preSelected ?? (availableTargets.includes("slot.content") ? ["slot.content"] : []))
|
|
890
910
|
);
|
|
891
|
-
const [error, setError] =
|
|
892
|
-
|
|
911
|
+
const [error, setError] = useState();
|
|
912
|
+
useInput((input, key) => {
|
|
893
913
|
if (key.upArrow) {
|
|
894
914
|
setCursor((c) => Math.max(0, c - 1));
|
|
895
915
|
return;
|
|
@@ -920,39 +940,34 @@ var TargetSelect = ({ availableTargets, preSelected, onSubmit, onBack }) => {
|
|
|
920
940
|
onSubmit([...selected]);
|
|
921
941
|
}
|
|
922
942
|
});
|
|
923
|
-
return /* @__PURE__ */
|
|
943
|
+
return /* @__PURE__ */ jsxs(
|
|
924
944
|
StepShell,
|
|
925
945
|
{
|
|
926
946
|
title: "Select Surface targets/slots",
|
|
927
947
|
hint: "Space to toggle, Enter to confirm",
|
|
928
948
|
onBack,
|
|
929
949
|
children: [
|
|
930
|
-
/* @__PURE__ */
|
|
950
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", gap: 1, children: availableTargets.map((target, i) => {
|
|
931
951
|
const isSelected = selected.has(target);
|
|
932
952
|
const isCursor = i === cursor;
|
|
933
|
-
return /* @__PURE__ */
|
|
934
|
-
/* @__PURE__ */
|
|
935
|
-
/* @__PURE__ */
|
|
936
|
-
/* @__PURE__ */
|
|
937
|
-
/* @__PURE__ */
|
|
938
|
-
/* @__PURE__ */
|
|
953
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
954
|
+
/* @__PURE__ */ jsx(Text, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
|
|
955
|
+
/* @__PURE__ */ jsx(Text, { color: isSelected ? "green" : void 0, children: isSelected ? "\u25C9" : "\u25CB" }),
|
|
956
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
957
|
+
/* @__PURE__ */ jsx(Text, { bold: isSelected, children: target }),
|
|
958
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: TARGET_DESCRIPTIONS[target] ?? target })
|
|
939
959
|
] })
|
|
940
960
|
] }, target);
|
|
941
961
|
}) }),
|
|
942
|
-
error && /* @__PURE__ */
|
|
962
|
+
error && /* @__PURE__ */ jsx(Text, { color: "red", children: error })
|
|
943
963
|
]
|
|
944
964
|
}
|
|
945
965
|
);
|
|
946
966
|
};
|
|
947
|
-
|
|
948
|
-
// src/components/TemplateSelect.tsx
|
|
949
|
-
import { Box as Box11, Text as Text11, useInput as useInput7 } from "ink";
|
|
950
|
-
import { useState as useState7 } from "react";
|
|
951
|
-
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
952
967
|
var FLAVORS = ["minimal", "starter", "kitchen-sink"];
|
|
953
968
|
var TemplateSelect = ({ onSubmit, onBack }) => {
|
|
954
|
-
const [cursor, setCursor] =
|
|
955
|
-
|
|
969
|
+
const [cursor, setCursor] = useState(1);
|
|
970
|
+
useInput((_input, key) => {
|
|
956
971
|
if (key.upArrow) {
|
|
957
972
|
setCursor((c) => Math.max(0, c - 1));
|
|
958
973
|
return;
|
|
@@ -965,21 +980,21 @@ var TemplateSelect = ({ onSubmit, onBack }) => {
|
|
|
965
980
|
onSubmit(FLAVORS[cursor]);
|
|
966
981
|
}
|
|
967
982
|
});
|
|
968
|
-
return /* @__PURE__ */
|
|
983
|
+
return /* @__PURE__ */ jsx(
|
|
969
984
|
StepShell,
|
|
970
985
|
{
|
|
971
986
|
title: "Choose a template",
|
|
972
987
|
hint: "\u2191\u2193 to navigate, Enter to select",
|
|
973
988
|
onBack,
|
|
974
|
-
children: /* @__PURE__ */
|
|
989
|
+
children: /* @__PURE__ */ jsx(Box, { flexDirection: "column", gap: 1, children: FLAVORS.map((flavor, i) => {
|
|
975
990
|
const meta = TEMPLATE_FLAVOR_META[flavor];
|
|
976
991
|
const isCursor = i === cursor;
|
|
977
|
-
return /* @__PURE__ */
|
|
978
|
-
/* @__PURE__ */
|
|
979
|
-
/* @__PURE__ */
|
|
980
|
-
/* @__PURE__ */
|
|
981
|
-
/* @__PURE__ */
|
|
982
|
-
/* @__PURE__ */
|
|
992
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
993
|
+
/* @__PURE__ */ jsx(Text, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
|
|
994
|
+
/* @__PURE__ */ jsx(Text, { color: isCursor ? "green" : void 0, children: isCursor ? "\u25C9" : "\u25CB" }),
|
|
995
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
996
|
+
/* @__PURE__ */ jsx(Text, { bold: isCursor, children: meta.label }),
|
|
997
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: meta.description })
|
|
983
998
|
] })
|
|
984
999
|
] }, flavor);
|
|
985
1000
|
}) })
|
|
@@ -987,14 +1002,11 @@ var TemplateSelect = ({ onSubmit, onBack }) => {
|
|
|
987
1002
|
);
|
|
988
1003
|
};
|
|
989
1004
|
|
|
990
|
-
// src/components/AppSelect.tsx
|
|
991
|
-
import { Box as Box13, Text as Text13, useInput as useInput8 } from "ink";
|
|
992
|
-
import Spinner2 from "ink-spinner";
|
|
993
|
-
import { useEffect as useEffect2, useState as useState8 } from "react";
|
|
994
|
-
|
|
995
1005
|
// src/lib/api.ts
|
|
996
1006
|
var DEFAULT_ADMIN_API_URL = "https://api-use1.stackablelabs.io/admin";
|
|
1007
|
+
var DEFAULT_PUBLIC_API_URL = "https://api.stackablelabs.io/app-extension/v1";
|
|
997
1008
|
var getAdminApiBaseUrl = () => process.env.ADMIN_API_BASE_URL ?? DEFAULT_ADMIN_API_URL;
|
|
1009
|
+
var getPublicApiBaseUrl = () => process.env.APP_EXTENSION_API_BASE_URL ?? DEFAULT_PUBLIC_API_URL;
|
|
998
1010
|
var CLI_CLIENT_NAME = "@stackable-labs/cli-app-extension";
|
|
999
1011
|
var authHeaders = (token) => ({
|
|
1000
1012
|
authorization: `Bearer ${token}`,
|
|
@@ -1053,6 +1065,26 @@ var fetchExtensions = async (token, appId) => {
|
|
|
1053
1065
|
])
|
|
1054
1066
|
);
|
|
1055
1067
|
};
|
|
1068
|
+
var resolveAppForExtension = async (token, extensionId) => {
|
|
1069
|
+
const apps = await fetchApps(token);
|
|
1070
|
+
const publicBaseUrl = getPublicApiBaseUrl();
|
|
1071
|
+
for (const app of apps) {
|
|
1072
|
+
try {
|
|
1073
|
+
const res = await fetch(`${publicBaseUrl}/extensions/${app.id}`, {
|
|
1074
|
+
headers: authHeaders(token)
|
|
1075
|
+
});
|
|
1076
|
+
if (!res.ok) continue;
|
|
1077
|
+
const extensions = await res.json();
|
|
1078
|
+
const ext = extensions[extensionId];
|
|
1079
|
+
if (ext) {
|
|
1080
|
+
return { app, extension: ext };
|
|
1081
|
+
}
|
|
1082
|
+
} catch {
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
return null;
|
|
1087
|
+
};
|
|
1056
1088
|
var fetchProject = async (token, appId, projectId) => {
|
|
1057
1089
|
const baseUrl = getAdminApiBaseUrl();
|
|
1058
1090
|
const res = await fetch(`${baseUrl}/app-extension/${appId}/projects/${projectId}`, {
|
|
@@ -1101,74 +1133,15 @@ var updateExtension = async (token, appId, extensionId, payload) => {
|
|
|
1101
1133
|
throw new Error(`Failed to update extension: ${res.status} ${body}`);
|
|
1102
1134
|
}
|
|
1103
1135
|
};
|
|
1104
|
-
|
|
1105
|
-
// src/components/Banner.tsx
|
|
1106
|
-
import { Box as Box12, Text as Text12 } from "ink";
|
|
1107
|
-
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1108
|
-
var WORDMARK = [
|
|
1109
|
-
" _ _ _ _ ",
|
|
1110
|
-
" ___| |_ __ _ ___| | ____ _| |__ | | ___",
|
|
1111
|
-
"/ __| __/ _` |/ __| |/ / _` | '_ \\| |/ _ \\",
|
|
1112
|
-
"\\__ \\ || (_| | (__| < (_| | |_) | | __/",
|
|
1113
|
-
"|___/\\__\\__,_|\\___|_|\\_\\__,_|_.__/|_|\\___|"
|
|
1114
|
-
];
|
|
1115
|
-
var COLORS = [
|
|
1116
|
-
[232, 218, 234],
|
|
1117
|
-
// Lit Lilac #E8DAEA
|
|
1118
|
-
[197, 96, 255],
|
|
1119
|
-
// Poppy Purple #C560FF
|
|
1120
|
-
[0, 174, 247],
|
|
1121
|
-
// Bluetooth Blue #00AEF7
|
|
1122
|
-
[70, 224, 177],
|
|
1123
|
-
// Tropical Teal #46E0B1
|
|
1124
|
-
[252, 248, 161]
|
|
1125
|
-
// Not Mellow Yellow #FCF8A1
|
|
1126
|
-
];
|
|
1127
|
-
var lerp = (a, b, t) => {
|
|
1128
|
-
const r = Math.round(a[0] + (b[0] - a[0]) * t);
|
|
1129
|
-
const g = Math.round(a[1] + (b[1] - a[1]) * t);
|
|
1130
|
-
const bl = Math.round(a[2] + (b[2] - a[2]) * t);
|
|
1131
|
-
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${bl.toString(16).padStart(2, "0")}`;
|
|
1132
|
-
};
|
|
1133
|
-
var gradientColor = (row, col, rows, cols) => {
|
|
1134
|
-
const t = (row / (rows - 1) + col / (cols - 1)) / 2;
|
|
1135
|
-
const idx = t * (COLORS.length - 1);
|
|
1136
|
-
const lo = Math.floor(idx);
|
|
1137
|
-
const hi = Math.min(lo + 1, COLORS.length - 1);
|
|
1138
|
-
return lerp(COLORS[lo], COLORS[hi], idx - lo);
|
|
1139
|
-
};
|
|
1140
|
-
var Banner = ({ userId, orgId } = {}) => {
|
|
1141
|
-
const termWidth = process.stdout.columns ?? 80;
|
|
1142
|
-
const maxLen = Math.max(...WORDMARK.map((l) => l.length));
|
|
1143
|
-
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
1144
|
-
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "\u2500".repeat(termWidth) }),
|
|
1145
|
-
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
|
|
1146
|
-
WORDMARK.map((line, row) => /* @__PURE__ */ jsx12(Box12, { children: line.split("").map((ch, col) => /* @__PURE__ */ jsx12(Text12, { bold: true, color: ch === " " ? void 0 : gradientColor(row, col, WORDMARK.length, maxLen), children: ch }, col)) }, row)),
|
|
1147
|
-
userId && orgId && /* @__PURE__ */ jsxs12(Box12, { gap: 2, marginTop: 1, children: [
|
|
1148
|
-
/* @__PURE__ */ jsxs12(Box12, { gap: 1, children: [
|
|
1149
|
-
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "User:" }),
|
|
1150
|
-
/* @__PURE__ */ jsx12(Text12, { color: "cyan", children: userId })
|
|
1151
|
-
] }),
|
|
1152
|
-
/* @__PURE__ */ jsxs12(Box12, { gap: 1, children: [
|
|
1153
|
-
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Org:" }),
|
|
1154
|
-
/* @__PURE__ */ jsx12(Text12, { color: "cyan", children: orgId })
|
|
1155
|
-
] })
|
|
1156
|
-
] })
|
|
1157
|
-
] })
|
|
1158
|
-
] });
|
|
1159
|
-
};
|
|
1160
|
-
|
|
1161
|
-
// src/components/AppSelect.tsx
|
|
1162
|
-
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1163
1136
|
var AppSelect = ({ token, userId, orgId, onSubmit }) => {
|
|
1164
|
-
const [apps, setApps] =
|
|
1165
|
-
const [loading, setLoading] =
|
|
1166
|
-
const [error, setError] =
|
|
1167
|
-
const [cursor, setCursor] =
|
|
1168
|
-
|
|
1137
|
+
const [apps, setApps] = useState([]);
|
|
1138
|
+
const [loading, setLoading] = useState(true);
|
|
1139
|
+
const [error, setError] = useState();
|
|
1140
|
+
const [cursor, setCursor] = useState(0);
|
|
1141
|
+
useEffect(() => {
|
|
1169
1142
|
fetchApps(token).then(setApps).catch((err) => setError(err instanceof Error ? err.message : String(err))).finally(() => setLoading(false));
|
|
1170
1143
|
}, [token]);
|
|
1171
|
-
|
|
1144
|
+
useInput((_, key) => {
|
|
1172
1145
|
if (loading || error || apps.length === 0) return;
|
|
1173
1146
|
if (key.upArrow) {
|
|
1174
1147
|
setCursor((c) => Math.max(0, c - 1));
|
|
@@ -1180,26 +1153,26 @@ var AppSelect = ({ token, userId, orgId, onSubmit }) => {
|
|
|
1180
1153
|
});
|
|
1181
1154
|
const renderContent = () => {
|
|
1182
1155
|
if (loading) {
|
|
1183
|
-
return /* @__PURE__ */
|
|
1184
|
-
/* @__PURE__ */
|
|
1185
|
-
/* @__PURE__ */
|
|
1156
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
1157
|
+
/* @__PURE__ */ jsx(Spinner5, { type: "dots" }),
|
|
1158
|
+
/* @__PURE__ */ jsx(Text, { children: "Loading available Apps\u2026" })
|
|
1186
1159
|
] });
|
|
1187
1160
|
}
|
|
1188
1161
|
if (error) {
|
|
1189
|
-
return /* @__PURE__ */
|
|
1190
|
-
/* @__PURE__ */
|
|
1191
|
-
/* @__PURE__ */
|
|
1162
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
1163
|
+
/* @__PURE__ */ jsx(Text, { color: "red", bold: true, children: "Failed to load Apps" }),
|
|
1164
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: error })
|
|
1192
1165
|
] });
|
|
1193
1166
|
}
|
|
1194
1167
|
if (apps.length === 0) {
|
|
1195
|
-
return /* @__PURE__ */
|
|
1168
|
+
return /* @__PURE__ */ jsx(Text, { color: "yellow", children: "No Apps available. Contact your administrator." });
|
|
1196
1169
|
}
|
|
1197
|
-
return /* @__PURE__ */
|
|
1170
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: apps.map((app, i) => {
|
|
1198
1171
|
const isCursor = i === cursor;
|
|
1199
|
-
return /* @__PURE__ */
|
|
1200
|
-
/* @__PURE__ */
|
|
1201
|
-
/* @__PURE__ */
|
|
1202
|
-
/* @__PURE__ */
|
|
1172
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
1173
|
+
/* @__PURE__ */ jsx(Text, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
|
|
1174
|
+
/* @__PURE__ */ jsx(Text, { bold: isCursor, children: app.name }),
|
|
1175
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1203
1176
|
"(",
|
|
1204
1177
|
app.id,
|
|
1205
1178
|
")"
|
|
@@ -1207,26 +1180,20 @@ var AppSelect = ({ token, userId, orgId, onSubmit }) => {
|
|
|
1207
1180
|
] }, app.id);
|
|
1208
1181
|
}) });
|
|
1209
1182
|
};
|
|
1210
|
-
return /* @__PURE__ */
|
|
1211
|
-
/* @__PURE__ */
|
|
1212
|
-
/* @__PURE__ */
|
|
1183
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1184
|
+
/* @__PURE__ */ jsx(Banner, { userId, orgId }),
|
|
1185
|
+
/* @__PURE__ */ jsx(StepShell, { title: "Select the App you are building an Extension for:", children: renderContent() })
|
|
1213
1186
|
] });
|
|
1214
1187
|
};
|
|
1215
|
-
|
|
1216
|
-
// src/components/ExtensionSelect.tsx
|
|
1217
|
-
import { Box as Box14, Text as Text14, useInput as useInput9 } from "ink";
|
|
1218
|
-
import Spinner3 from "ink-spinner";
|
|
1219
|
-
import { useEffect as useEffect3, useState as useState9 } from "react";
|
|
1220
|
-
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1221
1188
|
var ExtensionSelect = ({ appId, token, command, onSubmit, onBack }) => {
|
|
1222
|
-
const [extensions, setExtensions] =
|
|
1223
|
-
const [loading, setLoading] =
|
|
1224
|
-
const [error, setError] =
|
|
1225
|
-
const [cursor, setCursor] =
|
|
1226
|
-
|
|
1189
|
+
const [extensions, setExtensions] = useState([]);
|
|
1190
|
+
const [loading, setLoading] = useState(true);
|
|
1191
|
+
const [error, setError] = useState();
|
|
1192
|
+
const [cursor, setCursor] = useState(0);
|
|
1193
|
+
useEffect(() => {
|
|
1227
1194
|
fetchExtensions(token, appId).then((byId) => setExtensions(Object.values(byId))).catch((err) => setError(err instanceof Error ? err.message : String(err))).finally(() => setLoading(false));
|
|
1228
1195
|
}, [appId, token]);
|
|
1229
|
-
|
|
1196
|
+
useInput((_, key) => {
|
|
1230
1197
|
if (key.upArrow) {
|
|
1231
1198
|
if (!loading && !error && extensions.length > 0) {
|
|
1232
1199
|
setCursor((c) => Math.max(0, c - 1));
|
|
@@ -1247,30 +1214,30 @@ var ExtensionSelect = ({ appId, token, command, onSubmit, onBack }) => {
|
|
|
1247
1214
|
});
|
|
1248
1215
|
const renderContent = () => {
|
|
1249
1216
|
if (loading) {
|
|
1250
|
-
return /* @__PURE__ */
|
|
1251
|
-
/* @__PURE__ */
|
|
1252
|
-
/* @__PURE__ */
|
|
1217
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
1218
|
+
/* @__PURE__ */ jsx(Spinner5, { type: "dots" }),
|
|
1219
|
+
/* @__PURE__ */ jsx(Text, { children: "Loading Extensions\u2026" })
|
|
1253
1220
|
] });
|
|
1254
1221
|
}
|
|
1255
1222
|
if (error) {
|
|
1256
|
-
return /* @__PURE__ */
|
|
1257
|
-
/* @__PURE__ */
|
|
1258
|
-
/* @__PURE__ */
|
|
1223
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
1224
|
+
/* @__PURE__ */ jsx(Text, { color: "red", bold: true, children: "Failed to load Extensions" }),
|
|
1225
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: error })
|
|
1259
1226
|
] });
|
|
1260
1227
|
}
|
|
1261
1228
|
if (extensions.length === 0) {
|
|
1262
|
-
return /* @__PURE__ */
|
|
1229
|
+
return /* @__PURE__ */ jsx(Text, { color: "yellow", children: "No Extensions found for this App." });
|
|
1263
1230
|
}
|
|
1264
|
-
return /* @__PURE__ */
|
|
1231
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: extensions.map((ext, i) => {
|
|
1265
1232
|
const isCursor = i === cursor;
|
|
1266
|
-
return /* @__PURE__ */
|
|
1267
|
-
/* @__PURE__ */
|
|
1268
|
-
/* @__PURE__ */
|
|
1269
|
-
/* @__PURE__ */
|
|
1233
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
1234
|
+
/* @__PURE__ */ jsx(Text, { color: isCursor ? "cyan" : void 0, children: isCursor ? "\u276F" : " " }),
|
|
1235
|
+
/* @__PURE__ */ jsx(Text, { bold: isCursor, children: ext.manifest.name }),
|
|
1236
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1270
1237
|
"v",
|
|
1271
1238
|
ext.manifest.version
|
|
1272
1239
|
] }),
|
|
1273
|
-
/* @__PURE__ */
|
|
1240
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1274
1241
|
"(",
|
|
1275
1242
|
ext.id,
|
|
1276
1243
|
")"
|
|
@@ -1278,7 +1245,7 @@ var ExtensionSelect = ({ appId, token, command, onSubmit, onBack }) => {
|
|
|
1278
1245
|
] }, ext.id);
|
|
1279
1246
|
}) });
|
|
1280
1247
|
};
|
|
1281
|
-
return /* @__PURE__ */
|
|
1248
|
+
return /* @__PURE__ */ jsx(
|
|
1282
1249
|
StepShell,
|
|
1283
1250
|
{
|
|
1284
1251
|
title: command === "update" /* UPDATE */ ? "Select an Extension to update:" : "Select an existing Extension to scaffold:",
|
|
@@ -1287,11 +1254,87 @@ var ExtensionSelect = ({ appId, token, command, onSubmit, onBack }) => {
|
|
|
1287
1254
|
}
|
|
1288
1255
|
);
|
|
1289
1256
|
};
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1257
|
+
var STEPS = {
|
|
1258
|
+
["create" /* CREATE */]: ["app", "name", "template", "targets", "settings", "confirm"],
|
|
1259
|
+
["scaffold" /* SCAFFOLD */]: ["app", "extensionSelect", "template", "confirmTargets", "settings", "confirm"],
|
|
1260
|
+
["update" /* UPDATE */]: ["app", "extensionSelect", "updateSettings", "manifestReview", "confirm"],
|
|
1261
|
+
["dev" /* DEV */]: []
|
|
1262
|
+
};
|
|
1263
|
+
var computeActiveSteps = (conditions) => {
|
|
1264
|
+
const { command, initialName, initialExtensionId, templateFlavor, studioProject, options } = conditions;
|
|
1265
|
+
const base = STEPS[command];
|
|
1266
|
+
const skipped = /* @__PURE__ */ new Set();
|
|
1267
|
+
if (command === "create" /* CREATE */ && initialName) skipped.add("name");
|
|
1268
|
+
if (command === "create" /* CREATE */ && options?.template) skipped.add("template");
|
|
1269
|
+
if (command === "create" /* CREATE */ && TEMPLATE_FLAVOR_META[templateFlavor].skipTargetStep) {
|
|
1270
|
+
skipped.add("targets");
|
|
1271
|
+
}
|
|
1272
|
+
if (options?.extensionPort || options?.previewPort) skipped.add("settings");
|
|
1273
|
+
if (options?.appId) skipped.add("app");
|
|
1274
|
+
if (initialExtensionId && (command === "update" /* UPDATE */ || command === "scaffold" /* SCAFFOLD */)) {
|
|
1275
|
+
skipped.add("app");
|
|
1276
|
+
skipped.add("extensionSelect");
|
|
1277
|
+
}
|
|
1278
|
+
if (studioProject) {
|
|
1279
|
+
if (command === "create" /* CREATE */) {
|
|
1280
|
+
skipped.add("template");
|
|
1281
|
+
}
|
|
1282
|
+
if (command === "scaffold" /* SCAFFOLD */) {
|
|
1283
|
+
skipped.add("template");
|
|
1284
|
+
if (studioProject.extensionId) {
|
|
1285
|
+
skipped.add("extensionSelect");
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
if (command === "scaffold" /* SCAFFOLD */ && (options?.template || conditions.hasLocalProject)) {
|
|
1290
|
+
skipped.add("template");
|
|
1291
|
+
}
|
|
1292
|
+
return base.filter((s) => !skipped.has(s));
|
|
1293
|
+
};
|
|
1294
|
+
var useWizardSteps = (opts) => {
|
|
1295
|
+
const [step, setStep] = useState("app");
|
|
1296
|
+
const activeSteps = useMemo(
|
|
1297
|
+
() => computeActiveSteps(opts),
|
|
1298
|
+
[
|
|
1299
|
+
opts.command,
|
|
1300
|
+
opts.initialName,
|
|
1301
|
+
opts.initialExtensionId,
|
|
1302
|
+
opts.templateFlavor,
|
|
1303
|
+
opts.studioProject,
|
|
1304
|
+
opts.hasLocalProject,
|
|
1305
|
+
opts.options?.template,
|
|
1306
|
+
opts.options?.extensionPort,
|
|
1307
|
+
opts.options?.previewPort,
|
|
1308
|
+
opts.options?.appId
|
|
1309
|
+
]
|
|
1310
|
+
);
|
|
1311
|
+
const goForward = useCallback(
|
|
1312
|
+
(overrides) => {
|
|
1313
|
+
setStep((prev) => {
|
|
1314
|
+
const steps = computeActiveSteps({ ...opts, ...overrides });
|
|
1315
|
+
const idx = steps.indexOf(prev);
|
|
1316
|
+
if (idx >= 0 && idx < steps.length - 1) {
|
|
1317
|
+
return steps[idx + 1];
|
|
1318
|
+
}
|
|
1319
|
+
if (idx === -1 && steps.length > 0) {
|
|
1320
|
+
return steps[0];
|
|
1321
|
+
}
|
|
1322
|
+
return prev;
|
|
1323
|
+
});
|
|
1324
|
+
},
|
|
1325
|
+
[opts]
|
|
1326
|
+
);
|
|
1327
|
+
const goBack = useCallback(() => {
|
|
1328
|
+
setStep((prev) => {
|
|
1329
|
+
const idx = activeSteps.indexOf(prev);
|
|
1330
|
+
return idx > 0 ? activeSteps[idx - 1] : prev;
|
|
1331
|
+
});
|
|
1332
|
+
}, [activeSteps]);
|
|
1333
|
+
const goTo = useCallback((target) => {
|
|
1334
|
+
setStep(target);
|
|
1335
|
+
}, []);
|
|
1336
|
+
return { step, activeSteps, goForward, goBack, goTo };
|
|
1337
|
+
};
|
|
1295
1338
|
var execFileAsync = promisify(execFile);
|
|
1296
1339
|
var gitInit = async (dir) => {
|
|
1297
1340
|
try {
|
|
@@ -1305,19 +1348,10 @@ var postScaffold = async (options) => {
|
|
|
1305
1348
|
if (!options.skipGit) {
|
|
1306
1349
|
await gitInit(options.outputDir);
|
|
1307
1350
|
}
|
|
1308
|
-
|
|
1351
|
+
{
|
|
1309
1352
|
await installDependencies({ cwd: options.outputDir, silent: true });
|
|
1310
1353
|
}
|
|
1311
1354
|
};
|
|
1312
|
-
|
|
1313
|
-
// src/lib/scaffold.ts
|
|
1314
|
-
import { readFile as readFile2, readdir, rm, writeFile as writeFile2 } from "fs/promises";
|
|
1315
|
-
import { join as join2 } from "path";
|
|
1316
|
-
import { downloadTemplate } from "giget";
|
|
1317
|
-
|
|
1318
|
-
// src/lib/devContext.ts
|
|
1319
|
-
import { readFile, writeFile } from "fs/promises";
|
|
1320
|
-
import { join } from "path";
|
|
1321
1355
|
var parseEnvFile = (content) => {
|
|
1322
1356
|
const lines = content.split("\n");
|
|
1323
1357
|
const env = {};
|
|
@@ -1421,7 +1455,7 @@ var deriveScaffoldPermissions = (targets) => {
|
|
|
1421
1455
|
};
|
|
1422
1456
|
var upsertOrRemove = async (filePath, shouldExist, content) => {
|
|
1423
1457
|
if (shouldExist) {
|
|
1424
|
-
await
|
|
1458
|
+
await writeFile(filePath, content);
|
|
1425
1459
|
return;
|
|
1426
1460
|
}
|
|
1427
1461
|
await rm(filePath, { force: true });
|
|
@@ -1433,7 +1467,7 @@ var walkFiles = async (rootDir) => {
|
|
|
1433
1467
|
if (entry.name === ".git" || entry.name === "node_modules" || entry.name === "dist") {
|
|
1434
1468
|
continue;
|
|
1435
1469
|
}
|
|
1436
|
-
const fullPath =
|
|
1470
|
+
const fullPath = join(rootDir, entry.name);
|
|
1437
1471
|
if (entry.isDirectory()) {
|
|
1438
1472
|
files.push(...await walkFiles(fullPath));
|
|
1439
1473
|
continue;
|
|
@@ -1448,7 +1482,7 @@ var replacePlaceholders = async (rootDir, replacements) => {
|
|
|
1448
1482
|
if (!isTextFile(filePath)) {
|
|
1449
1483
|
continue;
|
|
1450
1484
|
}
|
|
1451
|
-
let content = await
|
|
1485
|
+
let content = await readFile(filePath, "utf8");
|
|
1452
1486
|
let changed = false;
|
|
1453
1487
|
for (const [needle, value] of Object.entries(replacements)) {
|
|
1454
1488
|
if (content.includes(needle)) {
|
|
@@ -1457,18 +1491,18 @@ var replacePlaceholders = async (rootDir, replacements) => {
|
|
|
1457
1491
|
}
|
|
1458
1492
|
}
|
|
1459
1493
|
if (changed) {
|
|
1460
|
-
await
|
|
1494
|
+
await writeFile(filePath, content);
|
|
1461
1495
|
}
|
|
1462
1496
|
}
|
|
1463
1497
|
};
|
|
1464
1498
|
var generateManifest = async (rootDir, extensionName, targets, permissions) => {
|
|
1465
|
-
const manifestPath =
|
|
1466
|
-
const raw = await
|
|
1499
|
+
const manifestPath = join(rootDir, "packages/extension/public/manifest.json");
|
|
1500
|
+
const raw = await readFile(manifestPath, "utf8");
|
|
1467
1501
|
const manifest = JSON.parse(raw);
|
|
1468
1502
|
manifest.name = extensionName;
|
|
1469
1503
|
manifest.targets = targets;
|
|
1470
1504
|
manifest.permissions = permissions;
|
|
1471
|
-
await
|
|
1505
|
+
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
1472
1506
|
`);
|
|
1473
1507
|
};
|
|
1474
1508
|
var buildFooterSurface = (targets) => {
|
|
@@ -1495,12 +1529,12 @@ ${blocks.join("\n")}
|
|
|
1495
1529
|
`;
|
|
1496
1530
|
};
|
|
1497
1531
|
var generateSurfaceFiles = async (rootDir, targets) => {
|
|
1498
|
-
const surfaceDir =
|
|
1532
|
+
const surfaceDir = join(rootDir, "packages/extension/src/surfaces");
|
|
1499
1533
|
const wantsHeader = targets.includes("slot.header");
|
|
1500
1534
|
const wantsContent = targets.includes("slot.content");
|
|
1501
1535
|
const wantsFooter = targets.includes("slot.footer") || targets.includes("slot.footer-links");
|
|
1502
1536
|
await upsertOrRemove(
|
|
1503
|
-
|
|
1537
|
+
join(surfaceDir, "Header.tsx"),
|
|
1504
1538
|
wantsHeader,
|
|
1505
1539
|
`import { ui, Surface } from '@stackable-labs/sdk-extension-react'
|
|
1506
1540
|
|
|
@@ -1514,7 +1548,7 @@ export function Header() {
|
|
|
1514
1548
|
`
|
|
1515
1549
|
);
|
|
1516
1550
|
await upsertOrRemove(
|
|
1517
|
-
|
|
1551
|
+
join(surfaceDir, "Content.tsx"),
|
|
1518
1552
|
wantsContent,
|
|
1519
1553
|
`import { ui, useStore, useContextData, Surface } from '@stackable-labs/sdk-extension-react'
|
|
1520
1554
|
import { appStore } from '../store'
|
|
@@ -1547,14 +1581,14 @@ export function Content() {
|
|
|
1547
1581
|
`
|
|
1548
1582
|
);
|
|
1549
1583
|
await upsertOrRemove(
|
|
1550
|
-
|
|
1584
|
+
join(rootDir, "packages/extension/src/store.ts"),
|
|
1551
1585
|
wantsContent,
|
|
1552
1586
|
"import { createStore } from '@stackable-labs/sdk-extension-react'\n\nexport type ViewState = { type: 'menu' }\n\nexport interface AppState {\n viewState: ViewState\n}\n\nexport const appStore = createStore<AppState>({\n viewState: { type: 'menu' },\n})\n"
|
|
1553
1587
|
);
|
|
1554
|
-
await upsertOrRemove(
|
|
1588
|
+
await upsertOrRemove(join(surfaceDir, "Footer.tsx"), wantsFooter, buildFooterSurface(targets));
|
|
1555
1589
|
};
|
|
1556
1590
|
var rewriteExtensionIndex = async (rootDir, extensionId, targets) => {
|
|
1557
|
-
const indexPath =
|
|
1591
|
+
const indexPath = join(rootDir, "packages/extension/src/index.tsx");
|
|
1558
1592
|
const imports = ["import { createExtension } from '@stackable-labs/sdk-extension-react'"];
|
|
1559
1593
|
const components = [];
|
|
1560
1594
|
if (targets.includes("slot.header")) {
|
|
@@ -1580,10 +1614,10 @@ ${components.join("\n")}
|
|
|
1580
1614
|
{ extensionId: '${toKebabCase(extensionId)}' },
|
|
1581
1615
|
)
|
|
1582
1616
|
`;
|
|
1583
|
-
await
|
|
1617
|
+
await writeFile(indexPath, content);
|
|
1584
1618
|
};
|
|
1585
1619
|
var rewritePreviewApp = async (rootDir, targets, permissions) => {
|
|
1586
|
-
const appPath =
|
|
1620
|
+
const appPath = join(rootDir, "packages/preview/src/App.tsx");
|
|
1587
1621
|
const includeDataQuery = permissions.includes("data:query");
|
|
1588
1622
|
const includeToast = permissions.includes("actions:toast");
|
|
1589
1623
|
const includeInvoke = permissions.includes("actions:invoke");
|
|
@@ -1662,17 +1696,17 @@ export default function App() {
|
|
|
1662
1696
|
)
|
|
1663
1697
|
}
|
|
1664
1698
|
`;
|
|
1665
|
-
await
|
|
1699
|
+
await writeFile(appPath, appContent);
|
|
1666
1700
|
};
|
|
1667
1701
|
var patchViteAllowedHosts = async (rootDir) => {
|
|
1668
1702
|
const configs = [
|
|
1669
|
-
|
|
1670
|
-
|
|
1703
|
+
join(rootDir, "packages/extension/vite.config.ts"),
|
|
1704
|
+
join(rootDir, "packages/preview/vite.config.ts")
|
|
1671
1705
|
];
|
|
1672
1706
|
for (const configPath of configs) {
|
|
1673
1707
|
let content;
|
|
1674
1708
|
try {
|
|
1675
|
-
content = await
|
|
1709
|
+
content = await readFile(configPath, "utf8");
|
|
1676
1710
|
} catch {
|
|
1677
1711
|
continue;
|
|
1678
1712
|
}
|
|
@@ -1682,38 +1716,38 @@ var patchViteAllowedHosts = async (rootDir) => {
|
|
|
1682
1716
|
"server: {\n allowedHosts: true,"
|
|
1683
1717
|
);
|
|
1684
1718
|
if (patched !== content) {
|
|
1685
|
-
await
|
|
1719
|
+
await writeFile(configPath, patched);
|
|
1686
1720
|
}
|
|
1687
1721
|
}
|
|
1688
1722
|
};
|
|
1689
1723
|
var rewriteTurboJson = async (rootDir) => {
|
|
1690
|
-
const turboPath =
|
|
1691
|
-
const raw = await
|
|
1724
|
+
const turboPath = join(rootDir, "turbo.json");
|
|
1725
|
+
const raw = await readFile(turboPath, "utf8");
|
|
1692
1726
|
const turbo = JSON.parse(raw);
|
|
1693
1727
|
delete turbo["extends"];
|
|
1694
1728
|
turbo["globalEnv"] = ["VITE_EXTENSION_PORT", "VITE_PREVIEW_PORT", "VITE_EXTENSION_BUNDLE_URL"];
|
|
1695
|
-
await
|
|
1729
|
+
await writeFile(turboPath, `${JSON.stringify(turbo, null, 2)}
|
|
1696
1730
|
`);
|
|
1697
1731
|
};
|
|
1698
1732
|
var writeEnvFile2 = async (dir, extensionPort, previewPort) => {
|
|
1699
|
-
const envPath =
|
|
1733
|
+
const envPath = join(dir, ".env");
|
|
1700
1734
|
const content = `VITE_EXTENSION_PORT=${extensionPort}
|
|
1701
1735
|
VITE_PREVIEW_PORT=${previewPort}
|
|
1702
1736
|
`;
|
|
1703
|
-
await
|
|
1737
|
+
await writeFile(envPath, content);
|
|
1704
1738
|
};
|
|
1705
1739
|
var updateGitignore = async (dir) => {
|
|
1706
|
-
const gitignorePath =
|
|
1740
|
+
const gitignorePath = join(dir, ".gitignore");
|
|
1707
1741
|
let gitignore = "";
|
|
1708
1742
|
try {
|
|
1709
|
-
gitignore = await
|
|
1743
|
+
gitignore = await readFile(gitignorePath, "utf8");
|
|
1710
1744
|
} catch {
|
|
1711
1745
|
}
|
|
1712
1746
|
if (!gitignore.includes(".env.stackable")) {
|
|
1713
1747
|
const newGitignore = gitignore ? `${gitignore}
|
|
1714
1748
|
.env.stackable
|
|
1715
1749
|
` : ".env.stackable\n";
|
|
1716
|
-
await
|
|
1750
|
+
await writeFile(gitignorePath, newGitignore);
|
|
1717
1751
|
}
|
|
1718
1752
|
};
|
|
1719
1753
|
var scaffold = async (options) => {
|
|
@@ -1743,39 +1777,25 @@ var scaffold = async (options) => {
|
|
|
1743
1777
|
await writeEnvFile2(dir, options.extensionPort, options.previewPort);
|
|
1744
1778
|
await updateGitignore(dir);
|
|
1745
1779
|
await writeDevContext(dir, {
|
|
1746
|
-
projectRoot: dir,
|
|
1747
|
-
orgId: null,
|
|
1748
1780
|
appId: options.appId,
|
|
1749
1781
|
extensionId: toKebabCase(options.extensionId || options.name),
|
|
1750
1782
|
appName: options.appName || null,
|
|
1751
1783
|
extensionName: options.name,
|
|
1752
1784
|
extensionPort: options.extensionPort,
|
|
1753
|
-
previewPort: options.previewPort
|
|
1754
|
-
manifest: null
|
|
1755
|
-
});
|
|
1785
|
+
previewPort: options.previewPort});
|
|
1756
1786
|
if (options.projectFiles) {
|
|
1757
|
-
const extensionSrcDir =
|
|
1787
|
+
const extensionSrcDir = join(dir, "packages/extension/src");
|
|
1758
1788
|
for (const [filename, content] of Object.entries(options.projectFiles)) {
|
|
1759
|
-
await
|
|
1789
|
+
await writeFile(join(extensionSrcDir, filename), content);
|
|
1760
1790
|
}
|
|
1761
1791
|
}
|
|
1762
1792
|
if (options.projectManifest) {
|
|
1763
|
-
const manifestPath =
|
|
1764
|
-
await
|
|
1793
|
+
const manifestPath = join(dir, "packages/extension/public/manifest.json");
|
|
1794
|
+
await writeFile(manifestPath, `${JSON.stringify(options.projectManifest, null, 2)}
|
|
1765
1795
|
`);
|
|
1766
1796
|
}
|
|
1767
1797
|
return options;
|
|
1768
1798
|
};
|
|
1769
|
-
|
|
1770
|
-
// src/App.tsx
|
|
1771
|
-
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1772
|
-
var STEPS = {
|
|
1773
|
-
["create" /* CREATE */]: ["app", "name", "template", "targets", "settings", "confirm"],
|
|
1774
|
-
["scaffold" /* SCAFFOLD */]: ["app", "extensionSelect", "confirmTargets", "settings", "confirm"],
|
|
1775
|
-
["update" /* UPDATE */]: ["app", "extensionSelect", "updateSettings", "manifestReview", "confirm"],
|
|
1776
|
-
["dev" /* DEV */]: []
|
|
1777
|
-
// Dev command has no wizard steps
|
|
1778
|
-
};
|
|
1779
1799
|
var PROGRESS_STEPS = {
|
|
1780
1800
|
["create" /* CREATE */]: [
|
|
1781
1801
|
{ label: "Registering Extension", status: "pending" },
|
|
@@ -1813,115 +1833,72 @@ var deriveRegistryPermissions = (targets) => {
|
|
|
1813
1833
|
};
|
|
1814
1834
|
var App = ({ command, token, userId, orgId, initialName, initialExtensionId, options }) => {
|
|
1815
1835
|
const { exit } = useApp();
|
|
1816
|
-
const [
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
return "app";
|
|
1822
|
-
});
|
|
1823
|
-
const [name, setName] = useState10(initialName ?? options?.name ?? "");
|
|
1824
|
-
const [extensionId, setExtensionId] = useState10(initialExtensionId ?? "");
|
|
1825
|
-
const [extensionVersion, setExtensionVersion] = useState10("");
|
|
1826
|
-
const [bundleUrl, setBundleUrl] = useState10(options?.bundleUrl ?? "");
|
|
1827
|
-
const [enabled, setEnabled] = useState10(
|
|
1836
|
+
const [name, setName] = useState(initialName ?? options?.name ?? "");
|
|
1837
|
+
const [extensionId, setExtensionId] = useState(initialExtensionId ?? "");
|
|
1838
|
+
const [extensionVersion, setExtensionVersion] = useState("");
|
|
1839
|
+
const [bundleUrl, setBundleUrl] = useState(options?.bundleUrl ?? "");
|
|
1840
|
+
const [enabled, setEnabled] = useState(
|
|
1828
1841
|
options?.enabled !== void 0 ? options.enabled !== "false" : true
|
|
1829
1842
|
);
|
|
1830
|
-
const [versionOverride, setVersionOverride] =
|
|
1831
|
-
const [forceMajor, setForceMajor] =
|
|
1832
|
-
const [initialExtension, setInitialExtension] =
|
|
1833
|
-
const [templateFlavor, setTemplateFlavor] =
|
|
1843
|
+
const [versionOverride, setVersionOverride] = useState(void 0);
|
|
1844
|
+
const [forceMajor, setForceMajor] = useState(false);
|
|
1845
|
+
const [initialExtension, setInitialExtension] = useState(null);
|
|
1846
|
+
const [templateFlavor, setTemplateFlavor] = useState(
|
|
1834
1847
|
options?.template ?? "starter"
|
|
1835
1848
|
);
|
|
1836
|
-
const [targets, setTargets] =
|
|
1849
|
+
const [targets, setTargets] = useState(
|
|
1837
1850
|
options?.targets ? options.targets.split(",").map((t) => t.trim()) : []
|
|
1838
1851
|
);
|
|
1839
|
-
const [selectedApp, setSelectedApp] =
|
|
1840
|
-
const [extensionPort, setExtensionPort] =
|
|
1852
|
+
const [selectedApp, setSelectedApp] = useState(null);
|
|
1853
|
+
const [extensionPort, setExtensionPort] = useState(
|
|
1841
1854
|
options?.extensionPort ? parseInt(options.extensionPort, 10) : 6543
|
|
1842
1855
|
);
|
|
1843
|
-
const [previewPort, setPreviewPort] =
|
|
1856
|
+
const [previewPort, setPreviewPort] = useState(
|
|
1844
1857
|
options?.previewPort ? parseInt(options.previewPort, 10) : 6544
|
|
1845
1858
|
);
|
|
1846
|
-
const [registryManifest, setRegistryManifest] =
|
|
1847
|
-
const [localManifest, setLocalManifest] =
|
|
1848
|
-
const [confirmedPermissions, setConfirmedPermissions] =
|
|
1849
|
-
const [confirmedAllowedDomains, setConfirmedAllowedDomains] =
|
|
1850
|
-
const [
|
|
1851
|
-
const [
|
|
1852
|
-
const [
|
|
1853
|
-
const [
|
|
1854
|
-
const
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
const activeSteps = useCallback(() => {
|
|
1858
|
-
const base = STEPS[command];
|
|
1859
|
-
const skipped = /* @__PURE__ */ new Set();
|
|
1860
|
-
if (command === "create" /* CREATE */ && initialName) skipped.add("name");
|
|
1861
|
-
if (command === "create" /* CREATE */ && options?.template) skipped.add("template");
|
|
1862
|
-
if (command === "create" /* CREATE */ && TEMPLATE_FLAVOR_META[templateFlavor].skipTargetStep) {
|
|
1863
|
-
skipped.add("targets");
|
|
1864
|
-
}
|
|
1865
|
-
if (options?.extensionPort || options?.previewPort) skipped.add("settings");
|
|
1866
|
-
if (options?.appId) skipped.add("app");
|
|
1867
|
-
if (command === "update" /* UPDATE */ && initialExtensionId) skipped.add("extensionSelect");
|
|
1868
|
-
if (studioProject) {
|
|
1869
|
-
if (command === "create" /* CREATE */) {
|
|
1870
|
-
skipped.add("template");
|
|
1871
|
-
skipped.add("targets");
|
|
1872
|
-
}
|
|
1873
|
-
if (command === "scaffold" /* SCAFFOLD */ && studioProject.extensionId) {
|
|
1874
|
-
skipped.add("extensionSelect");
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1877
|
-
return base.filter((s) => !skipped.has(s));
|
|
1878
|
-
}, [
|
|
1859
|
+
const [registryManifest, setRegistryManifest] = useState(null);
|
|
1860
|
+
const [localManifest, setLocalManifest] = useState(null);
|
|
1861
|
+
const [confirmedPermissions, setConfirmedPermissions] = useState([]);
|
|
1862
|
+
const [confirmedAllowedDomains, setConfirmedAllowedDomains] = useState([]);
|
|
1863
|
+
const [userEditedAllowedDomains, setUserEditedAllowedDomains] = useState([]);
|
|
1864
|
+
const [outputDir, setOutputDir] = useState("");
|
|
1865
|
+
const [studioProject, setStudioProject] = useState(null);
|
|
1866
|
+
const [hasLocalProject, setHasLocalProject] = useState(false);
|
|
1867
|
+
const [progressSteps, setProgressSteps] = useState(PROGRESS_STEPS[command]);
|
|
1868
|
+
const [errorMessage, setErrorMessage] = useState();
|
|
1869
|
+
const { step, goForward, goBack, goTo } = useWizardSteps({
|
|
1879
1870
|
command,
|
|
1880
1871
|
initialName,
|
|
1881
1872
|
initialExtensionId,
|
|
1882
1873
|
templateFlavor,
|
|
1883
1874
|
studioProject,
|
|
1884
|
-
|
|
1885
|
-
options
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
setStep((prev) => {
|
|
1891
|
-
const steps = activeSteps();
|
|
1892
|
-
const idx = steps.indexOf(prev);
|
|
1893
|
-
return idx > 0 ? steps[idx - 1] : prev;
|
|
1894
|
-
});
|
|
1895
|
-
}, [activeSteps]);
|
|
1875
|
+
hasLocalProject,
|
|
1876
|
+
options
|
|
1877
|
+
});
|
|
1878
|
+
const updateStep = useCallback((index, status) => {
|
|
1879
|
+
setProgressSteps((prev) => prev.map((s, i) => i === index ? { ...s, status } : s));
|
|
1880
|
+
}, []);
|
|
1896
1881
|
const handleAppSelect = async (app) => {
|
|
1897
1882
|
setSelectedApp(app);
|
|
1898
|
-
if (options?.
|
|
1883
|
+
if (options?.projectId && (command === "create" /* CREATE */ || command === "scaffold" /* SCAFFOLD */)) {
|
|
1899
1884
|
try {
|
|
1900
|
-
const project = await fetchProject(token, app.id, options.
|
|
1885
|
+
const project = await fetchProject(token, app.id, options.projectId);
|
|
1901
1886
|
setStudioProject(project);
|
|
1902
1887
|
setName(project.name);
|
|
1903
1888
|
setTargets(project.manifest.targets);
|
|
1904
1889
|
if (project.extensionId) {
|
|
1905
1890
|
setExtensionId(project.extensionId);
|
|
1906
1891
|
}
|
|
1907
|
-
|
|
1908
|
-
setStep("name");
|
|
1909
|
-
} else if (command === "scaffold" /* SCAFFOLD */) {
|
|
1910
|
-
if (project.extensionId) {
|
|
1911
|
-
setStep("confirmTargets");
|
|
1912
|
-
} else {
|
|
1913
|
-
setStep("extensionSelect");
|
|
1914
|
-
}
|
|
1915
|
-
}
|
|
1892
|
+
goForward({ studioProject: project });
|
|
1916
1893
|
return;
|
|
1917
1894
|
} catch (err) {
|
|
1918
1895
|
const message = err instanceof Error ? err.message : String(err);
|
|
1919
1896
|
setErrorMessage(`Failed to fetch Studio project: ${message}`);
|
|
1920
|
-
|
|
1897
|
+
goTo("error");
|
|
1921
1898
|
return;
|
|
1922
1899
|
}
|
|
1923
1900
|
}
|
|
1924
|
-
if (command === "update" /* UPDATE */ && initialExtensionId) {
|
|
1901
|
+
if ((command === "update" /* UPDATE */ || command === "scaffold" /* SCAFFOLD */) && initialExtensionId) {
|
|
1925
1902
|
try {
|
|
1926
1903
|
const extensions = await fetchExtensions(token, app.id);
|
|
1927
1904
|
const ext = extensions[initialExtensionId];
|
|
@@ -1929,7 +1906,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
1929
1906
|
setErrorMessage(
|
|
1930
1907
|
`Extension "${initialExtensionId}" not found or is disabled. If disabled, re-enable it in the admin dashboard before updating.`
|
|
1931
1908
|
);
|
|
1932
|
-
|
|
1909
|
+
goTo("error");
|
|
1933
1910
|
return;
|
|
1934
1911
|
}
|
|
1935
1912
|
setName(ext.manifest.name);
|
|
@@ -1944,48 +1921,39 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
1944
1921
|
bundleUrl: ext.bundleUrl
|
|
1945
1922
|
});
|
|
1946
1923
|
setRegistryManifest(ext.manifest);
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
const
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1924
|
+
let localProjectFound = false;
|
|
1925
|
+
if (command === "update" /* UPDATE */ || command === "scaffold" /* SCAFFOLD */) {
|
|
1926
|
+
const projectRoot = options?.dir || process.cwd();
|
|
1927
|
+
try {
|
|
1928
|
+
const manifestPath = join(projectRoot, "packages/extension/public/manifest.json");
|
|
1929
|
+
const content = await readFile(manifestPath, "utf8");
|
|
1930
|
+
setLocalManifest(JSON.parse(content));
|
|
1931
|
+
setHasLocalProject(true);
|
|
1932
|
+
localProjectFound = true;
|
|
1933
|
+
} catch {
|
|
1934
|
+
setLocalManifest(null);
|
|
1935
|
+
}
|
|
1954
1936
|
}
|
|
1955
|
-
|
|
1937
|
+
goForward({ hasLocalProject: localProjectFound });
|
|
1956
1938
|
} catch (err) {
|
|
1957
1939
|
const message = err instanceof Error ? err.message : String(err);
|
|
1958
1940
|
setErrorMessage(message);
|
|
1959
|
-
|
|
1941
|
+
goTo("error");
|
|
1960
1942
|
}
|
|
1961
1943
|
return;
|
|
1962
1944
|
}
|
|
1963
|
-
if (
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
const meta = TEMPLATE_FLAVOR_META[templateFlavor];
|
|
1970
|
-
if (meta.skipTargetStep && meta.defaultTargets) {
|
|
1971
|
-
setTargets(meta.defaultTargets);
|
|
1972
|
-
if (options?.extensionPort || options?.previewPort) {
|
|
1973
|
-
setOutputDir(join3(process.cwd(), toKebabCase(initialName)));
|
|
1974
|
-
setStep("confirm");
|
|
1975
|
-
} else {
|
|
1976
|
-
setStep("settings");
|
|
1977
|
-
}
|
|
1978
|
-
return;
|
|
1945
|
+
if (initialName && options?.template) {
|
|
1946
|
+
const meta = TEMPLATE_FLAVOR_META[templateFlavor];
|
|
1947
|
+
if (meta.skipTargetStep && meta.defaultTargets) {
|
|
1948
|
+
setTargets(meta.defaultTargets);
|
|
1949
|
+
if (options?.extensionPort || options?.previewPort) {
|
|
1950
|
+
setOutputDir(join(process.cwd(), toKebabCase(initialName)));
|
|
1979
1951
|
}
|
|
1980
|
-
setStep("targets");
|
|
1981
|
-
} else {
|
|
1982
|
-
setStep("template");
|
|
1983
1952
|
}
|
|
1984
|
-
} else {
|
|
1985
|
-
setStep("name");
|
|
1986
1953
|
}
|
|
1954
|
+
goForward();
|
|
1987
1955
|
};
|
|
1988
|
-
|
|
1956
|
+
useEffect(() => {
|
|
1989
1957
|
if (!options?.appId) return;
|
|
1990
1958
|
fetchApps(token).then((apps) => {
|
|
1991
1959
|
const app = apps.find((a) => a.id === options.appId);
|
|
@@ -1993,11 +1961,28 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
1993
1961
|
handleAppSelect(app);
|
|
1994
1962
|
} else {
|
|
1995
1963
|
setErrorMessage(`App "${options.appId}" not found or is disabled.`);
|
|
1996
|
-
|
|
1964
|
+
goTo("error");
|
|
1965
|
+
}
|
|
1966
|
+
}).catch((err) => {
|
|
1967
|
+
setErrorMessage(err instanceof Error ? err.message : String(err));
|
|
1968
|
+
goTo("error");
|
|
1969
|
+
});
|
|
1970
|
+
}, []);
|
|
1971
|
+
useEffect(() => {
|
|
1972
|
+
if (options?.appId || !initialExtensionId) return;
|
|
1973
|
+
if (command !== "update" /* UPDATE */ && command !== "scaffold" /* SCAFFOLD */) return;
|
|
1974
|
+
resolveAppForExtension(token, initialExtensionId).then((result) => {
|
|
1975
|
+
if (result) {
|
|
1976
|
+
handleAppSelect(result.app);
|
|
1977
|
+
} else {
|
|
1978
|
+
setErrorMessage(
|
|
1979
|
+
`Extension "${initialExtensionId}" not found across your apps. Verify the extension ID or provide --app-id explicitly.`
|
|
1980
|
+
);
|
|
1981
|
+
goTo("error");
|
|
1997
1982
|
}
|
|
1998
1983
|
}).catch((err) => {
|
|
1999
1984
|
setErrorMessage(err instanceof Error ? err.message : String(err));
|
|
2000
|
-
|
|
1985
|
+
goTo("error");
|
|
2001
1986
|
});
|
|
2002
1987
|
}, []);
|
|
2003
1988
|
const handleExtensionSelect = async (ext) => {
|
|
@@ -2013,28 +1998,25 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2013
1998
|
bundleUrl: ext.bundleUrl
|
|
2014
1999
|
});
|
|
2015
2000
|
setRegistryManifest(ext.manifest);
|
|
2001
|
+
let localProjectFound = false;
|
|
2016
2002
|
const projectRoot = options?.dir || process.cwd();
|
|
2017
2003
|
try {
|
|
2018
|
-
const manifestPath =
|
|
2019
|
-
const content = await
|
|
2004
|
+
const manifestPath = join(projectRoot, "packages/extension/public/manifest.json");
|
|
2005
|
+
const content = await readFile(manifestPath, "utf8");
|
|
2020
2006
|
setLocalManifest(JSON.parse(content));
|
|
2007
|
+
setHasLocalProject(true);
|
|
2008
|
+
localProjectFound = true;
|
|
2021
2009
|
} catch {
|
|
2022
2010
|
setLocalManifest(null);
|
|
2023
2011
|
}
|
|
2024
|
-
|
|
2025
|
-
setStep("confirmTargets");
|
|
2026
|
-
} else if (command === "update" /* UPDATE */) {
|
|
2027
|
-
setStep("updateSettings");
|
|
2028
|
-
}
|
|
2012
|
+
goForward({ hasLocalProject: localProjectFound });
|
|
2029
2013
|
};
|
|
2030
2014
|
const handleConfirmTargets = (value) => {
|
|
2031
2015
|
setTargets(value);
|
|
2032
2016
|
if (options?.extensionPort || options?.previewPort) {
|
|
2033
|
-
setOutputDir(
|
|
2034
|
-
setStep("confirm");
|
|
2035
|
-
} else {
|
|
2036
|
-
setStep("settings");
|
|
2017
|
+
setOutputDir(join(process.cwd(), toKebabCase(name || extensionId)));
|
|
2037
2018
|
}
|
|
2019
|
+
goForward();
|
|
2038
2020
|
};
|
|
2039
2021
|
const handleName = (value) => {
|
|
2040
2022
|
setName(value);
|
|
@@ -2043,48 +2025,36 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2043
2025
|
const meta = TEMPLATE_FLAVOR_META[templateFlavor];
|
|
2044
2026
|
if (meta.skipTargetStep && meta.defaultTargets) {
|
|
2045
2027
|
setTargets(meta.defaultTargets);
|
|
2046
|
-
if (options?.extensionPort || options?.previewPort) {
|
|
2047
|
-
setOutputDir(join3(process.cwd(), toKebabCase(value)));
|
|
2048
|
-
setStep("confirm");
|
|
2049
|
-
} else {
|
|
2050
|
-
setStep("settings");
|
|
2051
|
-
}
|
|
2052
|
-
return;
|
|
2053
2028
|
}
|
|
2054
|
-
setStep("targets");
|
|
2055
|
-
} else {
|
|
2056
|
-
setStep("template");
|
|
2057
2029
|
}
|
|
2030
|
+
if (options?.extensionPort || options?.previewPort) {
|
|
2031
|
+
setOutputDir(join(process.cwd(), toKebabCase(value)));
|
|
2032
|
+
}
|
|
2033
|
+
goForward();
|
|
2058
2034
|
};
|
|
2059
2035
|
const handleTemplateSelect = (flavor) => {
|
|
2060
2036
|
setTemplateFlavor(flavor);
|
|
2061
2037
|
const meta = TEMPLATE_FLAVOR_META[flavor];
|
|
2062
2038
|
if (meta.skipTargetStep && meta.defaultTargets) {
|
|
2063
2039
|
setTargets(meta.defaultTargets);
|
|
2064
|
-
if (options?.extensionPort || options?.previewPort) {
|
|
2065
|
-
setOutputDir(join3(process.cwd(), toKebabCase(extensionId || name)));
|
|
2066
|
-
setStep("confirm");
|
|
2067
|
-
} else {
|
|
2068
|
-
setStep("settings");
|
|
2069
|
-
}
|
|
2070
|
-
return;
|
|
2071
2040
|
}
|
|
2072
|
-
|
|
2041
|
+
if (options?.extensionPort || options?.previewPort) {
|
|
2042
|
+
setOutputDir(join(process.cwd(), toKebabCase(name || extensionId)));
|
|
2043
|
+
}
|
|
2044
|
+
goForward({ templateFlavor: flavor });
|
|
2073
2045
|
};
|
|
2074
2046
|
const handleTargets = (value) => {
|
|
2075
2047
|
setTargets(value);
|
|
2076
2048
|
if (options?.extensionPort || options?.previewPort) {
|
|
2077
|
-
setOutputDir(
|
|
2078
|
-
setStep("confirm");
|
|
2079
|
-
} else {
|
|
2080
|
-
setStep("settings");
|
|
2049
|
+
setOutputDir(join(process.cwd(), toKebabCase(name || extensionId)));
|
|
2081
2050
|
}
|
|
2051
|
+
goForward();
|
|
2082
2052
|
};
|
|
2083
2053
|
const handleSettings = (extPort, prevPort, dir) => {
|
|
2084
2054
|
setExtensionPort(extPort);
|
|
2085
2055
|
setPreviewPort(prevPort);
|
|
2086
2056
|
setOutputDir(dir);
|
|
2087
|
-
|
|
2057
|
+
goForward();
|
|
2088
2058
|
};
|
|
2089
2059
|
const computeVersionBump = (currentVersion, newName, newTargets, newBundleUrl, isForceMajor) => {
|
|
2090
2060
|
const [major, minor, patch] = currentVersion.split(".").map(Number);
|
|
@@ -2100,7 +2070,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2100
2070
|
};
|
|
2101
2071
|
const handleConfirm = async () => {
|
|
2102
2072
|
if (command === "update" /* UPDATE */) {
|
|
2103
|
-
|
|
2073
|
+
goTo("updating");
|
|
2104
2074
|
setProgressSteps(PROGRESS_STEPS[command]);
|
|
2105
2075
|
try {
|
|
2106
2076
|
updateStep(0, "running");
|
|
@@ -2118,15 +2088,15 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2118
2088
|
});
|
|
2119
2089
|
updateStep(0, "done");
|
|
2120
2090
|
setExtensionVersion(resolvedVersion);
|
|
2121
|
-
|
|
2091
|
+
goTo("updateDone");
|
|
2122
2092
|
} catch (err) {
|
|
2123
2093
|
const message = err instanceof Error ? err.message : String(err);
|
|
2124
2094
|
setErrorMessage(message);
|
|
2125
|
-
|
|
2095
|
+
goTo("error");
|
|
2126
2096
|
}
|
|
2127
2097
|
return;
|
|
2128
2098
|
}
|
|
2129
|
-
|
|
2099
|
+
goTo("scaffolding");
|
|
2130
2100
|
setProgressSteps(PROGRESS_STEPS[command]);
|
|
2131
2101
|
try {
|
|
2132
2102
|
let resolvedExtensionId = extensionId || toKebabCase(name);
|
|
@@ -2155,7 +2125,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2155
2125
|
name,
|
|
2156
2126
|
extensionId: resolvedExtensionId,
|
|
2157
2127
|
targets,
|
|
2158
|
-
templateFlavor: command === "create" /* CREATE */ ? templateFlavor : void 0,
|
|
2128
|
+
templateFlavor: command === "create" /* CREATE */ || command === "scaffold" /* SCAFFOLD */ ? templateFlavor : void 0,
|
|
2159
2129
|
outputDir,
|
|
2160
2130
|
extensionPort,
|
|
2161
2131
|
previewPort,
|
|
@@ -2174,9 +2144,9 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2174
2144
|
}
|
|
2175
2145
|
}
|
|
2176
2146
|
if (command === "create" /* CREATE */) {
|
|
2177
|
-
const manifestPath =
|
|
2147
|
+
const manifestPath = join(outputDir, "packages/extension/public/manifest.json");
|
|
2178
2148
|
try {
|
|
2179
|
-
const manifestContent = await
|
|
2149
|
+
const manifestContent = await readFile(manifestPath, "utf8");
|
|
2180
2150
|
const manifest = JSON.parse(manifestContent);
|
|
2181
2151
|
await updateExtension(token, selectedApp.id, resolvedExtensionId, {
|
|
2182
2152
|
manifest: { ...manifest, allowedDomains: [] }
|
|
@@ -2185,7 +2155,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2185
2155
|
}
|
|
2186
2156
|
}
|
|
2187
2157
|
updateStep(scaffoldStepOffset + 1, "running");
|
|
2188
|
-
await
|
|
2158
|
+
await delay(200);
|
|
2189
2159
|
updateStep(scaffoldStepOffset + 1, "done");
|
|
2190
2160
|
if (!options?.skipInstall) {
|
|
2191
2161
|
updateStep(scaffoldStepOffset + 2, "running");
|
|
@@ -2194,11 +2164,11 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2194
2164
|
} else {
|
|
2195
2165
|
updateStep(scaffoldStepOffset + 2, "done");
|
|
2196
2166
|
}
|
|
2197
|
-
|
|
2167
|
+
goTo("done");
|
|
2198
2168
|
} catch (err) {
|
|
2199
2169
|
const message = err instanceof Error ? err.message : String(err);
|
|
2200
2170
|
setErrorMessage(message);
|
|
2201
|
-
|
|
2171
|
+
goTo("error");
|
|
2202
2172
|
}
|
|
2203
2173
|
};
|
|
2204
2174
|
const handleCancel = () => {
|
|
@@ -2206,7 +2176,16 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2206
2176
|
};
|
|
2207
2177
|
switch (step) {
|
|
2208
2178
|
case "app": {
|
|
2209
|
-
|
|
2179
|
+
if (options?.appId || initialExtensionId && (command === "update" /* UPDATE */ || command === "scaffold" /* SCAFFOLD */)) {
|
|
2180
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2181
|
+
/* @__PURE__ */ jsx(Banner, { userId, orgId }),
|
|
2182
|
+
/* @__PURE__ */ jsx(StepShell, { title: "Loading App\u2026", children: /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
2183
|
+
/* @__PURE__ */ jsx(Spinner5, { type: "dots" }),
|
|
2184
|
+
/* @__PURE__ */ jsx(Text, { children: options?.appId ? "Fetching app details\u2026" : "Resolving app from extension\u2026" })
|
|
2185
|
+
] }) })
|
|
2186
|
+
] });
|
|
2187
|
+
}
|
|
2188
|
+
return /* @__PURE__ */ jsx(
|
|
2210
2189
|
AppSelect,
|
|
2211
2190
|
{
|
|
2212
2191
|
token,
|
|
@@ -2217,7 +2196,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2217
2196
|
);
|
|
2218
2197
|
}
|
|
2219
2198
|
case "extensionSelect": {
|
|
2220
|
-
return /* @__PURE__ */
|
|
2199
|
+
return /* @__PURE__ */ jsx(
|
|
2221
2200
|
ExtensionSelect,
|
|
2222
2201
|
{
|
|
2223
2202
|
appId: selectedApp.id,
|
|
@@ -2229,7 +2208,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2229
2208
|
);
|
|
2230
2209
|
}
|
|
2231
2210
|
case "confirmTargets": {
|
|
2232
|
-
return /* @__PURE__ */
|
|
2211
|
+
return /* @__PURE__ */ jsx(
|
|
2233
2212
|
TargetSelect,
|
|
2234
2213
|
{
|
|
2235
2214
|
availableTargets: selectedApp?.targets ?? [],
|
|
@@ -2240,7 +2219,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2240
2219
|
);
|
|
2241
2220
|
}
|
|
2242
2221
|
case "name": {
|
|
2243
|
-
return /* @__PURE__ */
|
|
2222
|
+
return /* @__PURE__ */ jsx(
|
|
2244
2223
|
NamePrompt,
|
|
2245
2224
|
{
|
|
2246
2225
|
initialValue: name,
|
|
@@ -2250,7 +2229,7 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2250
2229
|
);
|
|
2251
2230
|
}
|
|
2252
2231
|
case "template": {
|
|
2253
|
-
return /* @__PURE__ */
|
|
2232
|
+
return /* @__PURE__ */ jsx(
|
|
2254
2233
|
TemplateSelect,
|
|
2255
2234
|
{
|
|
2256
2235
|
onSubmit: handleTemplateSelect,
|
|
@@ -2259,27 +2238,28 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2259
2238
|
);
|
|
2260
2239
|
}
|
|
2261
2240
|
case "targets": {
|
|
2262
|
-
return /* @__PURE__ */
|
|
2241
|
+
return /* @__PURE__ */ jsx(
|
|
2263
2242
|
TargetSelect,
|
|
2264
2243
|
{
|
|
2265
2244
|
availableTargets: selectedApp?.targets ?? [],
|
|
2245
|
+
preSelected: targets,
|
|
2266
2246
|
onSubmit: handleTargets,
|
|
2267
2247
|
onBack: goBack
|
|
2268
2248
|
}
|
|
2269
2249
|
);
|
|
2270
2250
|
}
|
|
2271
2251
|
case "settings": {
|
|
2272
|
-
return /* @__PURE__ */
|
|
2252
|
+
return /* @__PURE__ */ jsx(
|
|
2273
2253
|
SettingsPrompt,
|
|
2274
2254
|
{
|
|
2275
|
-
defaultDir:
|
|
2255
|
+
defaultDir: join(process.cwd(), toKebabCase(name || extensionId)),
|
|
2276
2256
|
onSubmit: handleSettings,
|
|
2277
2257
|
onBack: goBack
|
|
2278
2258
|
}
|
|
2279
2259
|
);
|
|
2280
2260
|
}
|
|
2281
2261
|
case "confirm": {
|
|
2282
|
-
return /* @__PURE__ */
|
|
2262
|
+
return /* @__PURE__ */ jsx(
|
|
2283
2263
|
Confirm,
|
|
2284
2264
|
{
|
|
2285
2265
|
command,
|
|
@@ -2306,89 +2286,94 @@ var App = ({ command, token, userId, orgId, initialName, initialExtensionId, opt
|
|
|
2306
2286
|
);
|
|
2307
2287
|
}
|
|
2308
2288
|
case "scaffolding": {
|
|
2309
|
-
return /* @__PURE__ */
|
|
2289
|
+
return /* @__PURE__ */ jsx(ScaffoldProgress, { steps: progressSteps });
|
|
2310
2290
|
}
|
|
2311
2291
|
case "updateSettings": {
|
|
2312
|
-
return /* @__PURE__ */
|
|
2292
|
+
return /* @__PURE__ */ jsx(
|
|
2313
2293
|
UpdateSettingsPrompt,
|
|
2314
2294
|
{
|
|
2315
2295
|
name,
|
|
2316
2296
|
targets,
|
|
2317
2297
|
enabled,
|
|
2318
2298
|
bundleUrl,
|
|
2299
|
+
allowedDomains: registryManifest?.allowedDomains ?? [],
|
|
2319
2300
|
availableTargets: selectedApp?.targets ?? [],
|
|
2320
2301
|
onSubmit: (updated) => {
|
|
2321
2302
|
setName(updated.name);
|
|
2322
2303
|
setTargets(updated.targets);
|
|
2323
2304
|
setBundleUrl(updated.bundleUrl);
|
|
2305
|
+
setUserEditedAllowedDomains(updated.allowedDomains);
|
|
2324
2306
|
setEnabled(updated.enabled);
|
|
2325
2307
|
setForceMajor(updated.forceMajor);
|
|
2326
2308
|
setVersionOverride(void 0);
|
|
2327
|
-
|
|
2309
|
+
goForward();
|
|
2328
2310
|
},
|
|
2329
2311
|
onBack: goBack
|
|
2330
2312
|
}
|
|
2331
2313
|
);
|
|
2332
2314
|
}
|
|
2333
2315
|
case "manifestReview": {
|
|
2334
|
-
|
|
2316
|
+
const buildEffectiveManifest = () => {
|
|
2317
|
+
if (localManifest) {
|
|
2318
|
+
return { ...localManifest, allowedDomains: userEditedAllowedDomains };
|
|
2319
|
+
}
|
|
2320
|
+
if (userEditedAllowedDomains.length > 0) {
|
|
2321
|
+
return { name, version: "0.0.0", targets, permissions: [], allowedDomains: userEditedAllowedDomains };
|
|
2322
|
+
}
|
|
2323
|
+
return localManifest;
|
|
2324
|
+
};
|
|
2325
|
+
const effectiveLocalManifest = buildEffectiveManifest();
|
|
2326
|
+
return /* @__PURE__ */ jsx(
|
|
2335
2327
|
ManifestReviewPrompt,
|
|
2336
2328
|
{
|
|
2337
|
-
localManifest,
|
|
2329
|
+
localManifest: effectiveLocalManifest,
|
|
2338
2330
|
registryManifest,
|
|
2339
2331
|
onSubmit: (result) => {
|
|
2340
2332
|
setConfirmedPermissions(result.permissions);
|
|
2341
2333
|
setConfirmedAllowedDomains(result.allowedDomains);
|
|
2342
|
-
|
|
2334
|
+
goForward();
|
|
2343
2335
|
},
|
|
2344
2336
|
onBack: goBack
|
|
2345
2337
|
}
|
|
2346
2338
|
);
|
|
2347
2339
|
}
|
|
2348
2340
|
case "updating": {
|
|
2349
|
-
return /* @__PURE__ */
|
|
2341
|
+
return /* @__PURE__ */ jsx(ScaffoldProgress, { steps: progressSteps });
|
|
2350
2342
|
}
|
|
2351
2343
|
case "updateDone": {
|
|
2352
|
-
return /* @__PURE__ */
|
|
2353
|
-
/* @__PURE__ */
|
|
2354
|
-
/* @__PURE__ */
|
|
2344
|
+
return /* @__PURE__ */ jsx(StepShell, { title: "Extension updated", onBack: goBack, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
2345
|
+
/* @__PURE__ */ jsx(Text, { color: "green", bold: true, children: "Extension updated successfully!" }),
|
|
2346
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
2355
2347
|
"Name: ",
|
|
2356
2348
|
name
|
|
2357
2349
|
] }),
|
|
2358
|
-
/* @__PURE__ */
|
|
2350
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
2359
2351
|
"ID: ",
|
|
2360
2352
|
extensionId
|
|
2361
2353
|
] }),
|
|
2362
|
-
/* @__PURE__ */
|
|
2354
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
2363
2355
|
"Version: ",
|
|
2364
2356
|
extensionVersion
|
|
2365
2357
|
] })
|
|
2366
2358
|
] }) });
|
|
2367
2359
|
}
|
|
2368
2360
|
case "done": {
|
|
2369
|
-
return /* @__PURE__ */
|
|
2361
|
+
return /* @__PURE__ */ jsx(Done, { name, outputDir, templateFlavor: command === "create" /* CREATE */ ? templateFlavor : void 0 });
|
|
2370
2362
|
}
|
|
2371
2363
|
case "error": {
|
|
2372
|
-
return /* @__PURE__ */
|
|
2373
|
-
/* @__PURE__ */
|
|
2374
|
-
errorMessage && /* @__PURE__ */
|
|
2364
|
+
return /* @__PURE__ */ jsx(StepShell, { title: "Operation failed", onBack: goBack, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
2365
|
+
/* @__PURE__ */ jsx(Text, { color: "red", bold: true, children: "An error occurred" }),
|
|
2366
|
+
errorMessage && /* @__PURE__ */ jsx(Text, { color: "red", children: errorMessage })
|
|
2375
2367
|
] }) });
|
|
2376
2368
|
}
|
|
2377
2369
|
default: {
|
|
2378
|
-
return /* @__PURE__ */
|
|
2379
|
-
/* @__PURE__ */
|
|
2380
|
-
errorMessage && /* @__PURE__ */
|
|
2370
|
+
return /* @__PURE__ */ jsx(StepShell, { title: "Scaffold failed", onBack: goBack, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
2371
|
+
/* @__PURE__ */ jsx(Text, { color: "red", bold: true, children: "An error occurred" }),
|
|
2372
|
+
errorMessage && /* @__PURE__ */ jsx(Text, { color: "red", children: errorMessage })
|
|
2381
2373
|
] }) });
|
|
2382
2374
|
}
|
|
2383
2375
|
}
|
|
2384
2376
|
};
|
|
2385
|
-
|
|
2386
|
-
// src/components/DevApp.tsx
|
|
2387
|
-
import { useRef, useState as useState13, useEffect as useEffect7, useCallback as useCallback3 } from "react";
|
|
2388
|
-
import { useInput as useInput12, Box as Box19, Text as Text19 } from "ink";
|
|
2389
|
-
|
|
2390
|
-
// src/lib/devServer.ts
|
|
2391
|
-
import { spawn } from "child_process";
|
|
2392
2377
|
var startDevServer = (projectRoot) => {
|
|
2393
2378
|
const child = spawn("pnpm", ["dev"], {
|
|
2394
2379
|
cwd: projectRoot,
|
|
@@ -2399,9 +2384,6 @@ var startDevServer = (projectRoot) => {
|
|
|
2399
2384
|
};
|
|
2400
2385
|
return { process: child, stop };
|
|
2401
2386
|
};
|
|
2402
|
-
|
|
2403
|
-
// src/lib/tunnel.ts
|
|
2404
|
-
import { Tunnel } from "cloudflared";
|
|
2405
2387
|
var MAX_RETRIES = 3;
|
|
2406
2388
|
var RETRY_DELAY_MS = 2e3;
|
|
2407
2389
|
var isValidTunnelUrl = (url) => {
|
|
@@ -2438,7 +2420,6 @@ var startTunnelOnce = (port) => new Promise((resolve, reject) => {
|
|
|
2438
2420
|
reject(err);
|
|
2439
2421
|
});
|
|
2440
2422
|
});
|
|
2441
|
-
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2442
2423
|
var startTunnel = async (port) => {
|
|
2443
2424
|
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
2444
2425
|
try {
|
|
@@ -2455,15 +2436,10 @@ var startTunnel = async (port) => {
|
|
|
2455
2436
|
}
|
|
2456
2437
|
throw new Error(`Tunnel failed to return a valid URL after ${MAX_RETRIES} attempts`);
|
|
2457
2438
|
};
|
|
2458
|
-
|
|
2459
|
-
// src/components/DevSetup.tsx
|
|
2460
|
-
import { Box as Box16, Text as Text16 } from "ink";
|
|
2461
|
-
import { useState as useState11, useEffect as useEffect5 } from "react";
|
|
2462
|
-
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2463
2439
|
var DevSetup = ({ initialContext, token, onReady }) => {
|
|
2464
|
-
const [step, setStep] =
|
|
2465
|
-
const [selectedApp, setSelectedApp] =
|
|
2466
|
-
|
|
2440
|
+
const [step, setStep] = useState("app");
|
|
2441
|
+
const [selectedApp, setSelectedApp] = useState(null);
|
|
2442
|
+
useEffect(() => {
|
|
2467
2443
|
if (initialContext.appId) {
|
|
2468
2444
|
setStep("extension");
|
|
2469
2445
|
}
|
|
@@ -2480,9 +2456,9 @@ var DevSetup = ({ initialContext, token, onReady }) => {
|
|
|
2480
2456
|
});
|
|
2481
2457
|
};
|
|
2482
2458
|
if (step === "app") {
|
|
2483
|
-
return /* @__PURE__ */
|
|
2484
|
-
/* @__PURE__ */
|
|
2485
|
-
/* @__PURE__ */
|
|
2459
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2460
|
+
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { children: "Select the App for your extension:" }) }),
|
|
2461
|
+
/* @__PURE__ */ jsx(
|
|
2486
2462
|
AppSelect,
|
|
2487
2463
|
{
|
|
2488
2464
|
token,
|
|
@@ -2491,9 +2467,9 @@ var DevSetup = ({ initialContext, token, onReady }) => {
|
|
|
2491
2467
|
)
|
|
2492
2468
|
] });
|
|
2493
2469
|
}
|
|
2494
|
-
return /* @__PURE__ */
|
|
2495
|
-
/* @__PURE__ */
|
|
2496
|
-
/* @__PURE__ */
|
|
2470
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2471
|
+
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { children: "Select the Extension to develop:" }) }),
|
|
2472
|
+
/* @__PURE__ */ jsx(
|
|
2497
2473
|
ExtensionSelect,
|
|
2498
2474
|
{
|
|
2499
2475
|
token,
|
|
@@ -2503,16 +2479,6 @@ var DevSetup = ({ initialContext, token, onReady }) => {
|
|
|
2503
2479
|
)
|
|
2504
2480
|
] });
|
|
2505
2481
|
};
|
|
2506
|
-
|
|
2507
|
-
// src/components/DevDashboard.tsx
|
|
2508
|
-
import { Box as Box18, Text as Text18, useInput as useInput11 } from "ink";
|
|
2509
|
-
import { useEffect as useEffect6, useMemo } from "react";
|
|
2510
|
-
|
|
2511
|
-
// src/components/CopyableField.tsx
|
|
2512
|
-
import { useState as useState12, useCallback as useCallback2 } from "react";
|
|
2513
|
-
import { useInput as useInput10, Box as Box17, Text as Text17 } from "ink";
|
|
2514
|
-
import clipboard from "clipboardy";
|
|
2515
|
-
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2516
2482
|
var CopyableField = ({
|
|
2517
2483
|
label,
|
|
2518
2484
|
value,
|
|
@@ -2522,9 +2488,9 @@ var CopyableField = ({
|
|
|
2522
2488
|
labelColor,
|
|
2523
2489
|
children
|
|
2524
2490
|
}) => {
|
|
2525
|
-
const [expanded, setExpanded] =
|
|
2526
|
-
const [copied, setCopied] =
|
|
2527
|
-
const handleCopy =
|
|
2491
|
+
const [expanded, setExpanded] = useState(false);
|
|
2492
|
+
const [copied, setCopied] = useState(false);
|
|
2493
|
+
const handleCopy = useCallback(async () => {
|
|
2528
2494
|
if (expanded) {
|
|
2529
2495
|
setExpanded(false);
|
|
2530
2496
|
setCopied(false);
|
|
@@ -2542,20 +2508,20 @@ var CopyableField = ({
|
|
|
2542
2508
|
setExpanded(true);
|
|
2543
2509
|
}
|
|
2544
2510
|
}, [expanded, value]);
|
|
2545
|
-
|
|
2511
|
+
useInput((input) => {
|
|
2546
2512
|
if (input === shortcutKey) {
|
|
2547
2513
|
handleCopy();
|
|
2548
2514
|
}
|
|
2549
2515
|
});
|
|
2550
2516
|
const truncated = value.length > maxLength ? `${value.slice(0, maxLength)}...` : value;
|
|
2551
2517
|
const keyHint = shortcutLabel || shortcutKey;
|
|
2552
|
-
return /* @__PURE__ */
|
|
2553
|
-
/* @__PURE__ */
|
|
2554
|
-
/* @__PURE__ */
|
|
2555
|
-
copied && /* @__PURE__ */
|
|
2556
|
-
!copied && /* @__PURE__ */
|
|
2518
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2519
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
2520
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: label }),
|
|
2521
|
+
copied && /* @__PURE__ */ jsx(Text, { color: "green", bold: true, children: "Copied!" }),
|
|
2522
|
+
!copied && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
2557
2523
|
"press ",
|
|
2558
|
-
/* @__PURE__ */
|
|
2524
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", children: [
|
|
2559
2525
|
"[",
|
|
2560
2526
|
keyHint,
|
|
2561
2527
|
"]"
|
|
@@ -2563,12 +2529,9 @@ var CopyableField = ({
|
|
|
2563
2529
|
" to copy (and see full value)"
|
|
2564
2530
|
] })
|
|
2565
2531
|
] }),
|
|
2566
|
-
/* @__PURE__ */
|
|
2532
|
+
/* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: expanded ? /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: value }) : children || /* @__PURE__ */ jsx(Text, { children: labelColor ? /* @__PURE__ */ jsx(Text, { color: labelColor, children: truncated }) : truncated }) })
|
|
2567
2533
|
] });
|
|
2568
2534
|
};
|
|
2569
|
-
|
|
2570
|
-
// src/components/DevDashboard.tsx
|
|
2571
|
-
import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2572
2535
|
var toBase64Url = (input) => btoa(input).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
2573
2536
|
var DevDashboard = ({
|
|
2574
2537
|
previewTunnelUrl,
|
|
@@ -2585,7 +2548,7 @@ var DevDashboard = ({
|
|
|
2585
2548
|
devSessionToken,
|
|
2586
2549
|
onQuit
|
|
2587
2550
|
}) => {
|
|
2588
|
-
|
|
2551
|
+
useEffect(() => {
|
|
2589
2552
|
const handler = () => {
|
|
2590
2553
|
onQuit();
|
|
2591
2554
|
};
|
|
@@ -2598,103 +2561,103 @@ var DevDashboard = ({
|
|
|
2598
2561
|
if (!tunnelUrl || !devSessionToken) return "";
|
|
2599
2562
|
return toBase64Url(JSON.stringify({ url: tunnelUrl, token: devSessionToken }));
|
|
2600
2563
|
}, [tunnelUrl, devSessionToken]);
|
|
2601
|
-
|
|
2564
|
+
useInput((input, key) => {
|
|
2602
2565
|
if (input === "q" || key.ctrl && input === "c") {
|
|
2603
2566
|
onQuit();
|
|
2604
2567
|
}
|
|
2605
2568
|
});
|
|
2606
|
-
return /* @__PURE__ */
|
|
2607
|
-
/* @__PURE__ */
|
|
2608
|
-
/* @__PURE__ */
|
|
2569
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2570
|
+
/* @__PURE__ */ jsx(Banner, { userId, orgId }),
|
|
2571
|
+
/* @__PURE__ */ jsxs(
|
|
2609
2572
|
StepShell,
|
|
2610
2573
|
{
|
|
2611
2574
|
title: "dev",
|
|
2612
2575
|
hint: `Live development ${tunnelUrl ? "with" : "w/o"} Tunnel \u2014 ${appName ? `${appName} ` : ""}(${appId})`,
|
|
2613
|
-
footer: /* @__PURE__ */
|
|
2614
|
-
devParamBlob && /* @__PURE__ */
|
|
2576
|
+
footer: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
2577
|
+
devParamBlob && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
2615
2578
|
"Press ",
|
|
2616
|
-
/* @__PURE__ */
|
|
2579
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: "[d]" }),
|
|
2617
2580
|
" to copy Dev Param, ",
|
|
2618
|
-
/* @__PURE__ */
|
|
2581
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: "[s]" }),
|
|
2619
2582
|
" to copy Staging Param"
|
|
2620
2583
|
] }),
|
|
2621
|
-
/* @__PURE__ */
|
|
2584
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
2622
2585
|
"Press ",
|
|
2623
|
-
/* @__PURE__ */
|
|
2586
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "yellow", children: "[q]" }),
|
|
2624
2587
|
" or Ctrl-C to quit"
|
|
2625
2588
|
] })
|
|
2626
2589
|
] }),
|
|
2627
2590
|
children: [
|
|
2628
|
-
/* @__PURE__ */
|
|
2629
|
-
/* @__PURE__ */
|
|
2630
|
-
/* @__PURE__ */
|
|
2631
|
-
/* @__PURE__ */
|
|
2591
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2592
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
2593
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Extension:" }),
|
|
2594
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2632
2595
|
extensionName,
|
|
2633
2596
|
" (",
|
|
2634
2597
|
extensionId,
|
|
2635
2598
|
")"
|
|
2636
2599
|
] })
|
|
2637
2600
|
] }),
|
|
2638
|
-
/* @__PURE__ */
|
|
2639
|
-
/* @__PURE__ */
|
|
2640
|
-
/* @__PURE__ */
|
|
2601
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
2602
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Bundle URL:" }),
|
|
2603
|
+
/* @__PURE__ */ jsx(Text, { children: tunnelUrl || `http://localhost:${extensionPort}` })
|
|
2641
2604
|
] })
|
|
2642
2605
|
] }),
|
|
2643
|
-
/* @__PURE__ */
|
|
2644
|
-
previewTunnelUrl && /* @__PURE__ */
|
|
2645
|
-
/* @__PURE__ */
|
|
2646
|
-
/* @__PURE__ */
|
|
2606
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2607
|
+
previewTunnelUrl && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
2608
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Tunnel Dev - Preview:" }),
|
|
2609
|
+
/* @__PURE__ */ jsx(Text, { children: previewTunnelUrl })
|
|
2647
2610
|
] }),
|
|
2648
|
-
/* @__PURE__ */
|
|
2649
|
-
/* @__PURE__ */
|
|
2650
|
-
/* @__PURE__ */
|
|
2611
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
2612
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Local Dev - Preview:" }),
|
|
2613
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2651
2614
|
"http://localhost:",
|
|
2652
2615
|
previewPort
|
|
2653
2616
|
] })
|
|
2654
2617
|
] })
|
|
2655
2618
|
] }),
|
|
2656
|
-
/* @__PURE__ */
|
|
2657
|
-
tunnelUrl && /* @__PURE__ */
|
|
2658
|
-
/* @__PURE__ */
|
|
2659
|
-
/* @__PURE__ */
|
|
2619
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2620
|
+
tunnelUrl && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
2621
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Tunnel Dev - Extension:" }),
|
|
2622
|
+
/* @__PURE__ */ jsx(Text, { children: tunnelUrl })
|
|
2660
2623
|
] }),
|
|
2661
|
-
/* @__PURE__ */
|
|
2662
|
-
/* @__PURE__ */
|
|
2663
|
-
/* @__PURE__ */
|
|
2624
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
2625
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Local Dev - Extension:" }),
|
|
2626
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2664
2627
|
"http://localhost:",
|
|
2665
2628
|
extensionPort
|
|
2666
2629
|
] })
|
|
2667
2630
|
] })
|
|
2668
2631
|
] }),
|
|
2669
|
-
tunnelUrl && devSessionToken && /* @__PURE__ */
|
|
2670
|
-
/* @__PURE__ */
|
|
2632
|
+
tunnelUrl && devSessionToken && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2633
|
+
/* @__PURE__ */ jsx(
|
|
2671
2634
|
CopyableField,
|
|
2672
2635
|
{
|
|
2673
2636
|
label: "Dev Param (no encryption):",
|
|
2674
2637
|
value: `?_stackable_dev=${extensionId}:${devParamBlob}`,
|
|
2675
2638
|
shortcutKey: "d",
|
|
2676
|
-
children: /* @__PURE__ */
|
|
2639
|
+
children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
2677
2640
|
"?",
|
|
2678
|
-
/* @__PURE__ */
|
|
2641
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: "_stackable_dev" }),
|
|
2679
2642
|
"=",
|
|
2680
|
-
/* @__PURE__ */
|
|
2643
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: extensionId }),
|
|
2681
2644
|
":",
|
|
2682
2645
|
devParamBlob.slice(0, 20),
|
|
2683
2646
|
"..."
|
|
2684
2647
|
] })
|
|
2685
2648
|
}
|
|
2686
2649
|
),
|
|
2687
|
-
/* @__PURE__ */
|
|
2650
|
+
/* @__PURE__ */ jsx(
|
|
2688
2651
|
CopyableField,
|
|
2689
2652
|
{
|
|
2690
2653
|
label: "Staging Param (with encryption):",
|
|
2691
2654
|
value: `?_stackable_staging=${extensionId}:${devParamBlob}`,
|
|
2692
2655
|
shortcutKey: "s",
|
|
2693
|
-
children: /* @__PURE__ */
|
|
2656
|
+
children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
2694
2657
|
"?",
|
|
2695
|
-
/* @__PURE__ */
|
|
2658
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: "_stackable_staging" }),
|
|
2696
2659
|
"=",
|
|
2697
|
-
/* @__PURE__ */
|
|
2660
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: extensionId }),
|
|
2698
2661
|
":",
|
|
2699
2662
|
devParamBlob.slice(0, 20),
|
|
2700
2663
|
"..."
|
|
@@ -2702,47 +2665,44 @@ var DevDashboard = ({
|
|
|
2702
2665
|
}
|
|
2703
2666
|
)
|
|
2704
2667
|
] }),
|
|
2705
|
-
tunnelUrl && !devSessionToken && /* @__PURE__ */
|
|
2706
|
-
/* @__PURE__ */
|
|
2707
|
-
/* @__PURE__ */
|
|
2668
|
+
tunnelUrl && !devSessionToken && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
2669
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Host Dev - Query Param:" }),
|
|
2670
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2708
2671
|
"?",
|
|
2709
|
-
/* @__PURE__ */
|
|
2672
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: "_stackable_dev" }),
|
|
2710
2673
|
"=",
|
|
2711
|
-
/* @__PURE__ */
|
|
2674
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: extensionId }),
|
|
2712
2675
|
":",
|
|
2713
2676
|
tunnelUrl
|
|
2714
2677
|
] })
|
|
2715
2678
|
] }),
|
|
2716
|
-
manifestWarnings.length > 0 && /* @__PURE__ */
|
|
2717
|
-
/* @__PURE__ */
|
|
2718
|
-
manifestWarnings.map((w, i) => /* @__PURE__ */
|
|
2679
|
+
manifestWarnings.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
2680
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: "Local manifest differs from registry:" }),
|
|
2681
|
+
manifestWarnings.map((w, i) => /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
2719
2682
|
" ",
|
|
2720
2683
|
w
|
|
2721
2684
|
] }, i)),
|
|
2722
|
-
/* @__PURE__ */
|
|
2685
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " Run `pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest update` to review and sync." })
|
|
2723
2686
|
] })
|
|
2724
2687
|
]
|
|
2725
2688
|
}
|
|
2726
2689
|
)
|
|
2727
2690
|
] });
|
|
2728
2691
|
};
|
|
2729
|
-
|
|
2730
|
-
// src/components/DevApp.tsx
|
|
2731
|
-
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
2732
2692
|
var DevApp = ({ token, userId, orgId, options = {} }) => {
|
|
2733
|
-
const [state, setState] =
|
|
2734
|
-
const [devContext, setDevContext] =
|
|
2735
|
-
const [resolvedContext, setResolvedContext] =
|
|
2736
|
-
const [tunnelUrl, setTunnelUrl] =
|
|
2737
|
-
const [previewTunnelUrl, setPreviewTunnelUrl] =
|
|
2738
|
-
const [tunnelHandle, setTunnelHandle] =
|
|
2739
|
-
const [previewTunnelHandle, setPreviewTunnelHandle] =
|
|
2740
|
-
const [devServerHandle, setDevServerHandle] =
|
|
2741
|
-
const [manifestWarnings, setManifestWarnings] =
|
|
2742
|
-
const [devSessionToken, setDevSessionToken] =
|
|
2693
|
+
const [state, setState] = useState("setup");
|
|
2694
|
+
const [devContext, setDevContext] = useState(null);
|
|
2695
|
+
const [resolvedContext, setResolvedContext] = useState(null);
|
|
2696
|
+
const [tunnelUrl, setTunnelUrl] = useState(null);
|
|
2697
|
+
const [previewTunnelUrl, setPreviewTunnelUrl] = useState(null);
|
|
2698
|
+
const [tunnelHandle, setTunnelHandle] = useState(null);
|
|
2699
|
+
const [previewTunnelHandle, setPreviewTunnelHandle] = useState(null);
|
|
2700
|
+
const [devServerHandle, setDevServerHandle] = useState(null);
|
|
2701
|
+
const [manifestWarnings, setManifestWarnings] = useState([]);
|
|
2702
|
+
const [devSessionToken, setDevSessionToken] = useState(null);
|
|
2743
2703
|
const shuttingDown = useRef(false);
|
|
2744
2704
|
const useTunnel = options.tunnel !== false;
|
|
2745
|
-
|
|
2705
|
+
useEffect(() => {
|
|
2746
2706
|
const projectRoot = options.dir || process.cwd();
|
|
2747
2707
|
console.log(`[dev] Reading context from ${projectRoot}`);
|
|
2748
2708
|
readDevContext(projectRoot).then((ctx) => {
|
|
@@ -2750,7 +2710,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
|
|
|
2750
2710
|
setDevContext(ctx);
|
|
2751
2711
|
});
|
|
2752
2712
|
}, [options.dir]);
|
|
2753
|
-
const handleSetupReady =
|
|
2713
|
+
const handleSetupReady = useCallback(async (resolved) => {
|
|
2754
2714
|
if (!devContext) return;
|
|
2755
2715
|
setResolvedContext(resolved);
|
|
2756
2716
|
console.log(`[dev] Saving context: appId=${resolved.appId} extensionId=${resolved.extensionId}`);
|
|
@@ -2822,7 +2782,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
|
|
|
2822
2782
|
console.log("[dev] Ready");
|
|
2823
2783
|
setState("running");
|
|
2824
2784
|
}, [devContext, token, options.extensionPort, options.previewPort, useTunnel]);
|
|
2825
|
-
|
|
2785
|
+
useEffect(() => {
|
|
2826
2786
|
if (state === "setup" && devContext && devContext.appId && devContext.extensionId) {
|
|
2827
2787
|
handleSetupReady({
|
|
2828
2788
|
appId: devContext.appId,
|
|
@@ -2857,7 +2817,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
|
|
|
2857
2817
|
console.log("[dev] Done");
|
|
2858
2818
|
process.exit(0);
|
|
2859
2819
|
};
|
|
2860
|
-
|
|
2820
|
+
useInput((input, key) => {
|
|
2861
2821
|
if (input === "c" && key.ctrl) {
|
|
2862
2822
|
if (state === "running") {
|
|
2863
2823
|
handleQuit();
|
|
@@ -2868,7 +2828,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
|
|
|
2868
2828
|
});
|
|
2869
2829
|
if (state === "setup" && devContext) {
|
|
2870
2830
|
if (!devContext.appId || !devContext.extensionId) {
|
|
2871
|
-
return /* @__PURE__ */
|
|
2831
|
+
return /* @__PURE__ */ jsx(
|
|
2872
2832
|
DevSetup,
|
|
2873
2833
|
{
|
|
2874
2834
|
token,
|
|
@@ -2880,7 +2840,7 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
|
|
|
2880
2840
|
return null;
|
|
2881
2841
|
}
|
|
2882
2842
|
if (state === "running" && devContext && resolvedContext) {
|
|
2883
|
-
return /* @__PURE__ */
|
|
2843
|
+
return /* @__PURE__ */ jsx(
|
|
2884
2844
|
DevDashboard,
|
|
2885
2845
|
{
|
|
2886
2846
|
previewTunnelUrl,
|
|
@@ -2902,19 +2862,8 @@ var DevApp = ({ token, userId, orgId, options = {} }) => {
|
|
|
2902
2862
|
if (state === "stopping") {
|
|
2903
2863
|
return null;
|
|
2904
2864
|
}
|
|
2905
|
-
return /* @__PURE__ */
|
|
2865
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: "Loading..." }) });
|
|
2906
2866
|
};
|
|
2907
|
-
|
|
2908
|
-
// src/components/AIScaffold.tsx
|
|
2909
|
-
import { Box as Box20, Text as Text20, useApp as useApp2 } from "ink";
|
|
2910
|
-
import Spinner4 from "ink-spinner";
|
|
2911
|
-
import { useState as useState14, useEffect as useEffect8 } from "react";
|
|
2912
|
-
|
|
2913
|
-
// src/lib/aiDocs.ts
|
|
2914
|
-
import { existsSync, readFileSync } from "fs";
|
|
2915
|
-
import { join as join4, dirname } from "path";
|
|
2916
|
-
import { mkdir, writeFile as writeFile3 } from "fs/promises";
|
|
2917
|
-
import AdmZip from "adm-zip";
|
|
2918
2867
|
var DEFAULT_STATIC_CDN_URL = "https://static.stackablelabs.io";
|
|
2919
2868
|
var AI_DOCS_FILENAME = "extension-ai-docs.zip";
|
|
2920
2869
|
var getStaticCdnBaseUrl = () => process.env.STATIC_CDN_BASE_URL ?? DEFAULT_STATIC_CDN_URL;
|
|
@@ -2924,7 +2873,7 @@ var isValidManifest = (data) => {
|
|
|
2924
2873
|
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);
|
|
2925
2874
|
};
|
|
2926
2875
|
var isExtensionProject = (dir) => {
|
|
2927
|
-
const manifestPath =
|
|
2876
|
+
const manifestPath = join(dir, "packages/extension/public/manifest.json");
|
|
2928
2877
|
if (!existsSync(manifestPath)) {
|
|
2929
2878
|
return { valid: false, reason: "No manifest.json found at packages/extension/public/manifest.json \u2014 is this an Extension project?" };
|
|
2930
2879
|
}
|
|
@@ -2952,22 +2901,19 @@ var downloadAndExtractAiDocs = async (targetDir, version2) => {
|
|
|
2952
2901
|
const extractedFiles = [];
|
|
2953
2902
|
for (const entry of entries) {
|
|
2954
2903
|
if (entry.isDirectory) continue;
|
|
2955
|
-
const targetPath =
|
|
2904
|
+
const targetPath = join(targetDir, entry.entryName);
|
|
2956
2905
|
await mkdir(dirname(targetPath), { recursive: true });
|
|
2957
|
-
await
|
|
2906
|
+
await writeFile(targetPath, entry.getData());
|
|
2958
2907
|
extractedFiles.push(entry.entryName);
|
|
2959
2908
|
}
|
|
2960
2909
|
return { files: extractedFiles.sort() };
|
|
2961
2910
|
};
|
|
2962
|
-
|
|
2963
|
-
// src/components/AIScaffold.tsx
|
|
2964
|
-
import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2965
2911
|
var AIScaffold = ({ version: version2 }) => {
|
|
2966
|
-
const { exit } =
|
|
2967
|
-
const [state, setState] =
|
|
2968
|
-
const [files, setFiles] =
|
|
2969
|
-
const [errorMessage, setErrorMessage] =
|
|
2970
|
-
|
|
2912
|
+
const { exit } = useApp();
|
|
2913
|
+
const [state, setState] = useState("validating");
|
|
2914
|
+
const [files, setFiles] = useState([]);
|
|
2915
|
+
const [errorMessage, setErrorMessage] = useState("");
|
|
2916
|
+
useEffect(() => {
|
|
2971
2917
|
const run = async () => {
|
|
2972
2918
|
const projectDir = process.cwd();
|
|
2973
2919
|
const check = isExtensionProject(projectDir);
|
|
@@ -2990,64 +2936,52 @@ var AIScaffold = ({ version: version2 }) => {
|
|
|
2990
2936
|
};
|
|
2991
2937
|
run();
|
|
2992
2938
|
}, []);
|
|
2993
|
-
return /* @__PURE__ */
|
|
2994
|
-
/* @__PURE__ */
|
|
2995
|
-
/* @__PURE__ */
|
|
2996
|
-
state === "validating" && /* @__PURE__ */
|
|
2997
|
-
/* @__PURE__ */
|
|
2998
|
-
/* @__PURE__ */
|
|
2939
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2940
|
+
/* @__PURE__ */ jsx(Banner, {}),
|
|
2941
|
+
/* @__PURE__ */ jsxs(StepShell, { title: "AI Editor Config", children: [
|
|
2942
|
+
state === "validating" && /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
2943
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: /* @__PURE__ */ jsx(Spinner5, { type: "dots" }) }),
|
|
2944
|
+
/* @__PURE__ */ jsx(Text, { children: "Checking project..." })
|
|
2999
2945
|
] }),
|
|
3000
|
-
state === "downloading" && /* @__PURE__ */
|
|
3001
|
-
/* @__PURE__ */
|
|
3002
|
-
/* @__PURE__ */
|
|
2946
|
+
state === "downloading" && /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
2947
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: /* @__PURE__ */ jsx(Spinner5, { type: "dots" }) }),
|
|
2948
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3003
2949
|
"Downloading AI editor configs (",
|
|
3004
2950
|
version2,
|
|
3005
2951
|
")..."
|
|
3006
2952
|
] })
|
|
3007
2953
|
] }),
|
|
3008
|
-
state === "done" && /* @__PURE__ */
|
|
3009
|
-
/* @__PURE__ */
|
|
3010
|
-
/* @__PURE__ */
|
|
3011
|
-
/* @__PURE__ */
|
|
2954
|
+
state === "done" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
2955
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
2956
|
+
/* @__PURE__ */ jsx(Text, { color: "green", bold: true, children: "\u2714" }),
|
|
2957
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
3012
2958
|
"AI editor configs installed (",
|
|
3013
2959
|
files.length,
|
|
3014
2960
|
" files)"
|
|
3015
2961
|
] })
|
|
3016
2962
|
] }),
|
|
3017
|
-
/* @__PURE__ */
|
|
2963
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: files.map((f) => /* @__PURE__ */ jsx(Text, { dimColor: true, children: f }, f)) })
|
|
3018
2964
|
] }),
|
|
3019
|
-
state === "error" && /* @__PURE__ */
|
|
3020
|
-
/* @__PURE__ */
|
|
3021
|
-
/* @__PURE__ */
|
|
2965
|
+
state === "error" && /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
2966
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: "\u2716" }),
|
|
2967
|
+
/* @__PURE__ */ jsx(Text, { children: errorMessage })
|
|
3022
2968
|
] })
|
|
3023
2969
|
] })
|
|
3024
2970
|
] });
|
|
3025
2971
|
};
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
import { createServer } from "http";
|
|
3029
|
-
import { Box as Box21, Text as Text21, useApp as useApp3 } from "ink";
|
|
3030
|
-
import Spinner5 from "ink-spinner";
|
|
3031
|
-
import open from "open";
|
|
3032
|
-
import { useState as useState15, useEffect as useEffect9 } from "react";
|
|
3033
|
-
|
|
3034
|
-
// src/lib/auth.ts
|
|
3035
|
-
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir2, unlink } from "fs/promises";
|
|
3036
|
-
import { join as join5 } from "path";
|
|
3037
|
-
import { homedir } from "os";
|
|
3038
|
-
var AUTH_DIR = join5(homedir(), ".stackable");
|
|
3039
|
-
var AUTH_FILE = join5(AUTH_DIR, "auth.json");
|
|
2972
|
+
var AUTH_DIR = join(homedir(), ".stackable");
|
|
2973
|
+
var AUTH_FILE = join(AUTH_DIR, "auth.json");
|
|
3040
2974
|
var readAuthState = async () => {
|
|
3041
2975
|
try {
|
|
3042
|
-
const content = await
|
|
2976
|
+
const content = await readFile(AUTH_FILE, "utf8");
|
|
3043
2977
|
return JSON.parse(content);
|
|
3044
2978
|
} catch {
|
|
3045
2979
|
return null;
|
|
3046
2980
|
}
|
|
3047
2981
|
};
|
|
3048
2982
|
var writeAuthState = async (state) => {
|
|
3049
|
-
await
|
|
3050
|
-
await
|
|
2983
|
+
await mkdir(AUTH_DIR, { recursive: true, mode: 448 });
|
|
2984
|
+
await writeFile(AUTH_FILE, JSON.stringify(state, null, 2), { mode: 384 });
|
|
3051
2985
|
};
|
|
3052
2986
|
var clearAuthState = async () => {
|
|
3053
2987
|
try {
|
|
@@ -3080,9 +3014,6 @@ var getToken = async () => {
|
|
|
3080
3014
|
}
|
|
3081
3015
|
return state.token;
|
|
3082
3016
|
};
|
|
3083
|
-
|
|
3084
|
-
// src/components/AuthLogin.tsx
|
|
3085
|
-
import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3086
3017
|
var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
3087
3018
|
var callbackPage = (heading, sub, redirectUrl) => `<!DOCTYPE html>
|
|
3088
3019
|
<html><head><meta charset="utf-8"><title>Stackable CLI</title>
|
|
@@ -3092,13 +3023,13 @@ var callbackPage = (heading, sub, redirectUrl) => `<!DOCTYPE html>
|
|
|
3092
3023
|
${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>` : ""}
|
|
3093
3024
|
</body></html>`;
|
|
3094
3025
|
var AuthLogin = ({ dashboardUrl }) => {
|
|
3095
|
-
const { exit } =
|
|
3096
|
-
const [state, setState] =
|
|
3097
|
-
const [loginUrl, setLoginUrl] =
|
|
3098
|
-
const [userIdLabel, setUserIdLabel] =
|
|
3099
|
-
const [orgIdLabel, setOrgIdLabel] =
|
|
3100
|
-
const [errorMessage, setErrorMessage] =
|
|
3101
|
-
|
|
3026
|
+
const { exit } = useApp();
|
|
3027
|
+
const [state, setState] = useState("waiting");
|
|
3028
|
+
const [loginUrl, setLoginUrl] = useState("");
|
|
3029
|
+
const [userIdLabel, setUserIdLabel] = useState("");
|
|
3030
|
+
const [orgIdLabel, setOrgIdLabel] = useState("");
|
|
3031
|
+
const [errorMessage, setErrorMessage] = useState("");
|
|
3032
|
+
useEffect(() => {
|
|
3102
3033
|
let server;
|
|
3103
3034
|
let timeout;
|
|
3104
3035
|
const run = async () => {
|
|
@@ -3173,116 +3104,103 @@ var AuthLogin = ({ dashboardUrl }) => {
|
|
|
3173
3104
|
server?.close();
|
|
3174
3105
|
};
|
|
3175
3106
|
}, []);
|
|
3176
|
-
return /* @__PURE__ */
|
|
3177
|
-
/* @__PURE__ */
|
|
3178
|
-
/* @__PURE__ */
|
|
3179
|
-
state === "waiting" && /* @__PURE__ */
|
|
3180
|
-
/* @__PURE__ */
|
|
3181
|
-
/* @__PURE__ */
|
|
3182
|
-
/* @__PURE__ */
|
|
3107
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3108
|
+
/* @__PURE__ */ jsx(Banner, {}),
|
|
3109
|
+
/* @__PURE__ */ jsxs(StepShell, { title: "Authenticate with Stackable", children: [
|
|
3110
|
+
state === "waiting" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
3111
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
3112
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: /* @__PURE__ */ jsx(Spinner5, { type: "dots" }) }),
|
|
3113
|
+
/* @__PURE__ */ jsx(Text, { children: "Waiting for browser authentication..." })
|
|
3183
3114
|
] }),
|
|
3184
|
-
loginUrl && /* @__PURE__ */
|
|
3115
|
+
loginUrl && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
3185
3116
|
" ",
|
|
3186
3117
|
loginUrl
|
|
3187
3118
|
] })
|
|
3188
3119
|
] }),
|
|
3189
|
-
state === "success" && /* @__PURE__ */
|
|
3190
|
-
/* @__PURE__ */
|
|
3191
|
-
/* @__PURE__ */
|
|
3192
|
-
/* @__PURE__ */
|
|
3193
|
-
/* @__PURE__ */
|
|
3120
|
+
state === "success" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
3121
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3122
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
3123
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "User:" }),
|
|
3124
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: userIdLabel })
|
|
3194
3125
|
] }),
|
|
3195
|
-
/* @__PURE__ */
|
|
3196
|
-
/* @__PURE__ */
|
|
3197
|
-
/* @__PURE__ */
|
|
3126
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
3127
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Org: " }),
|
|
3128
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: orgIdLabel })
|
|
3198
3129
|
] })
|
|
3199
3130
|
] }),
|
|
3200
|
-
/* @__PURE__ */
|
|
3201
|
-
/* @__PURE__ */
|
|
3202
|
-
/* @__PURE__ */
|
|
3131
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
3132
|
+
/* @__PURE__ */ jsx(Text, { color: "green", bold: true, children: "\u2714" }),
|
|
3133
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Authenticated" })
|
|
3203
3134
|
] })
|
|
3204
3135
|
] }),
|
|
3205
|
-
state === "error" && /* @__PURE__ */
|
|
3206
|
-
/* @__PURE__ */
|
|
3207
|
-
/* @__PURE__ */
|
|
3136
|
+
state === "error" && /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
3137
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: "\u2716" }),
|
|
3138
|
+
/* @__PURE__ */ jsx(Text, { children: errorMessage })
|
|
3208
3139
|
] })
|
|
3209
3140
|
] })
|
|
3210
3141
|
] });
|
|
3211
3142
|
};
|
|
3212
|
-
|
|
3213
|
-
// src/components/AuthLogout.tsx
|
|
3214
|
-
import { useEffect as useEffect10 } from "react";
|
|
3215
|
-
import { Box as Box22, Text as Text22, useApp as useApp4 } from "ink";
|
|
3216
|
-
import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
3217
3143
|
var AuthLogout = () => {
|
|
3218
|
-
const { exit } =
|
|
3219
|
-
|
|
3144
|
+
const { exit } = useApp();
|
|
3145
|
+
useEffect(() => {
|
|
3220
3146
|
exit();
|
|
3221
3147
|
}, [exit]);
|
|
3222
|
-
return /* @__PURE__ */
|
|
3223
|
-
/* @__PURE__ */
|
|
3224
|
-
/* @__PURE__ */
|
|
3225
|
-
/* @__PURE__ */
|
|
3226
|
-
/* @__PURE__ */
|
|
3148
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3149
|
+
/* @__PURE__ */ jsx(Banner, {}),
|
|
3150
|
+
/* @__PURE__ */ jsx(StepShell, { title: "Authenticate with Stackable", children: /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
3151
|
+
/* @__PURE__ */ jsx(Text, { color: "green", bold: true, children: "\u2714" }),
|
|
3152
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Logged out" })
|
|
3227
3153
|
] }) })
|
|
3228
3154
|
] });
|
|
3229
3155
|
};
|
|
3230
|
-
|
|
3231
|
-
// src/components/AuthStatus.tsx
|
|
3232
|
-
import { useEffect as useEffect11 } from "react";
|
|
3233
|
-
import { useApp as useApp5, Box as Box23, Text as Text23 } from "ink";
|
|
3234
|
-
import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3235
3156
|
var AuthStatus = ({ state, userId, orgId, expiry }) => {
|
|
3236
|
-
const { exit } =
|
|
3237
|
-
|
|
3157
|
+
const { exit } = useApp();
|
|
3158
|
+
useEffect(() => {
|
|
3238
3159
|
exit();
|
|
3239
3160
|
}, [exit]);
|
|
3240
|
-
return /* @__PURE__ */
|
|
3241
|
-
/* @__PURE__ */
|
|
3242
|
-
/* @__PURE__ */
|
|
3243
|
-
state === "authenticated" && /* @__PURE__ */
|
|
3244
|
-
/* @__PURE__ */
|
|
3245
|
-
/* @__PURE__ */
|
|
3246
|
-
/* @__PURE__ */
|
|
3247
|
-
/* @__PURE__ */
|
|
3161
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3162
|
+
/* @__PURE__ */ jsx(Banner, {}),
|
|
3163
|
+
/* @__PURE__ */ jsxs(StepShell, { title: "Authenticate with Stackable", children: [
|
|
3164
|
+
state === "authenticated" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
3165
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3166
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
3167
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "User:" }),
|
|
3168
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: userId })
|
|
3248
3169
|
] }),
|
|
3249
|
-
/* @__PURE__ */
|
|
3250
|
-
/* @__PURE__ */
|
|
3251
|
-
/* @__PURE__ */
|
|
3170
|
+
/* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
3171
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Org: " }),
|
|
3172
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: orgId })
|
|
3252
3173
|
] }),
|
|
3253
|
-
expiry && /* @__PURE__ */
|
|
3254
|
-
/* @__PURE__ */
|
|
3255
|
-
/* @__PURE__ */
|
|
3174
|
+
expiry && /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
|
|
3175
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Exp: " }),
|
|
3176
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: expiry.toLocaleDateString() })
|
|
3256
3177
|
] })
|
|
3257
3178
|
] }),
|
|
3258
|
-
/* @__PURE__ */
|
|
3259
|
-
/* @__PURE__ */
|
|
3260
|
-
/* @__PURE__ */
|
|
3179
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
3180
|
+
/* @__PURE__ */ jsx(Text, { color: "green", bold: true, children: "\u2714" }),
|
|
3181
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Authenticated" })
|
|
3261
3182
|
] })
|
|
3262
3183
|
] }),
|
|
3263
|
-
state === "expired" && /* @__PURE__ */
|
|
3264
|
-
/* @__PURE__ */
|
|
3265
|
-
/* @__PURE__ */
|
|
3266
|
-
/* @__PURE__ */
|
|
3184
|
+
state === "expired" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
3185
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
3186
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: "\u2716" }),
|
|
3187
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3267
3188
|
"Session expired",
|
|
3268
3189
|
expiry ? ` (${expiry.toLocaleDateString()})` : ""
|
|
3269
3190
|
] })
|
|
3270
3191
|
] }),
|
|
3271
|
-
/* @__PURE__ */
|
|
3192
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Run `stackable-app-extension auth login` to re-authenticate." })
|
|
3272
3193
|
] }),
|
|
3273
|
-
state === "not-logged-in" && /* @__PURE__ */
|
|
3274
|
-
/* @__PURE__ */
|
|
3275
|
-
/* @__PURE__ */
|
|
3276
|
-
/* @__PURE__ */
|
|
3194
|
+
state === "not-logged-in" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
3195
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
3196
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: "\u2716" }),
|
|
3197
|
+
/* @__PURE__ */ jsx(Text, { children: "Not logged in" })
|
|
3277
3198
|
] }),
|
|
3278
|
-
/* @__PURE__ */
|
|
3199
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Run `stackable-app-extension auth login`" })
|
|
3279
3200
|
] })
|
|
3280
3201
|
] })
|
|
3281
3202
|
] });
|
|
3282
3203
|
};
|
|
3283
|
-
|
|
3284
|
-
// src/lib/versionCheck.ts
|
|
3285
|
-
import https from "https";
|
|
3286
3204
|
var PACKAGE_NAME = "@stackable-labs/cli-app-extension";
|
|
3287
3205
|
var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
3288
3206
|
var TIMEOUT_MS = 3e3;
|
|
@@ -3327,9 +3245,6 @@ var checkForUpdate = (currentVersion) => {
|
|
|
3327
3245
|
} catch {
|
|
3328
3246
|
}
|
|
3329
3247
|
};
|
|
3330
|
-
|
|
3331
|
-
// src/index.tsx
|
|
3332
|
-
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
3333
3248
|
var require2 = createRequire(import.meta.url);
|
|
3334
3249
|
var { version } = require2("../package.json");
|
|
3335
3250
|
checkForUpdate(version);
|
|
@@ -3342,20 +3257,20 @@ var ensureToken = async () => {
|
|
|
3342
3257
|
const message = err instanceof Error ? err.message : String(err);
|
|
3343
3258
|
const isExpired = message.toLowerCase().includes("expired");
|
|
3344
3259
|
render(
|
|
3345
|
-
/* @__PURE__ */
|
|
3260
|
+
/* @__PURE__ */ jsx(AuthStatus, { state: isExpired ? "expired" : "not-logged-in" })
|
|
3346
3261
|
);
|
|
3347
3262
|
return null;
|
|
3348
3263
|
}
|
|
3349
3264
|
};
|
|
3350
3265
|
program.name("stackable-app-extension").description("Stackable Labs - App Extension developer CLI").version(version);
|
|
3351
|
-
program.command("create" /* CREATE */).description("Create a new Extension project").argument("[name]", "Extension project name").option("--app-id <id>", "Skip App selection").option("--project <id>", "Studio project ID (fetches files/manifest from Studio)").option("--template <flavor>", "Template flavor: minimal, starter, kitchen-sink").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) => {
|
|
3266
|
+
program.command("create" /* CREATE */).description("Create a new Extension project").argument("[name]", "Extension project name").option("--app-id <id>", "Skip App selection").option("--project-id <id>", "Studio project ID (fetches files/manifest from Studio)").option("--template <flavor>", "Template flavor: minimal, starter, kitchen-sink").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) => {
|
|
3352
3267
|
const auth2 = await ensureToken();
|
|
3353
3268
|
if (!auth2) {
|
|
3354
3269
|
return;
|
|
3355
3270
|
}
|
|
3356
3271
|
const { token, userId, orgId } = auth2;
|
|
3357
3272
|
render(
|
|
3358
|
-
/* @__PURE__ */
|
|
3273
|
+
/* @__PURE__ */ jsx(
|
|
3359
3274
|
App,
|
|
3360
3275
|
{
|
|
3361
3276
|
command: "create" /* CREATE */,
|
|
@@ -3368,17 +3283,18 @@ program.command("create" /* CREATE */).description("Create a new Extension proje
|
|
|
3368
3283
|
)
|
|
3369
3284
|
);
|
|
3370
3285
|
});
|
|
3371
|
-
program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project from an existing Extension").option("--app-id <id>", "
|
|
3286
|
+
program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project from an existing Extension").argument("[extensionId]", "Extension ID to scaffold from").option("--app-id <id>", "App ID (auto-resolved from extensionId if omitted)").option("--project-id <id>", "Studio project ID (fetches files/manifest from Studio)").option("--template <flavor>", "Template flavor: minimal, starter, kitchen-sink").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 (extensionId, options) => {
|
|
3372
3287
|
const auth2 = await ensureToken();
|
|
3373
3288
|
if (!auth2) {
|
|
3374
3289
|
return;
|
|
3375
3290
|
}
|
|
3376
3291
|
const { token, userId, orgId } = auth2;
|
|
3377
3292
|
render(
|
|
3378
|
-
/* @__PURE__ */
|
|
3293
|
+
/* @__PURE__ */ jsx(
|
|
3379
3294
|
App,
|
|
3380
3295
|
{
|
|
3381
3296
|
command: "scaffold" /* SCAFFOLD */,
|
|
3297
|
+
initialExtensionId: extensionId,
|
|
3382
3298
|
options,
|
|
3383
3299
|
token,
|
|
3384
3300
|
orgId,
|
|
@@ -3387,14 +3303,14 @@ program.command("scaffold" /* SCAFFOLD */).description("Scaffold a local project
|
|
|
3387
3303
|
)
|
|
3388
3304
|
);
|
|
3389
3305
|
});
|
|
3390
|
-
program.command("update" /* UPDATE */).description("Update an existing Extension").argument("[extensionId]", "Extension ID to update").option("--app-id <id>", "
|
|
3306
|
+
program.command("update" /* UPDATE */).description("Update an existing Extension").argument("[extensionId]", "Extension ID to update").option("--app-id <id>", "App ID (auto-resolved from extensionId if omitted)").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)").option("--dir <path>", "Project root (default: cwd)").action(async (extensionId, options) => {
|
|
3391
3307
|
const auth2 = await ensureToken();
|
|
3392
3308
|
if (!auth2) {
|
|
3393
3309
|
return;
|
|
3394
3310
|
}
|
|
3395
3311
|
const { token, userId, orgId } = auth2;
|
|
3396
3312
|
render(
|
|
3397
|
-
/* @__PURE__ */
|
|
3313
|
+
/* @__PURE__ */ jsx(
|
|
3398
3314
|
App,
|
|
3399
3315
|
{
|
|
3400
3316
|
command: "update" /* UPDATE */,
|
|
@@ -3414,7 +3330,7 @@ program.command("dev" /* DEV */).description("Start dev servers with a public tu
|
|
|
3414
3330
|
}
|
|
3415
3331
|
const { token, userId, orgId } = auth2;
|
|
3416
3332
|
render(
|
|
3417
|
-
/* @__PURE__ */
|
|
3333
|
+
/* @__PURE__ */ jsx(
|
|
3418
3334
|
DevApp,
|
|
3419
3335
|
{
|
|
3420
3336
|
options,
|
|
@@ -3429,17 +3345,17 @@ program.command("dev" /* DEV */).description("Start dev servers with a public tu
|
|
|
3429
3345
|
var DASHBOARD_URL = process.env.ADMIN_DASHBOARD_URL ?? "https://admin.stackablelabs.io";
|
|
3430
3346
|
var auth = program.command("auth").description("Manage CLI authentication");
|
|
3431
3347
|
auth.command("login").description("Authenticate with Stackable via browser").action(async () => {
|
|
3432
|
-
render(/* @__PURE__ */
|
|
3348
|
+
render(/* @__PURE__ */ jsx(AuthLogin, { dashboardUrl: DASHBOARD_URL }));
|
|
3433
3349
|
});
|
|
3434
3350
|
auth.command("logout").description("Clear stored CLI credentials").action(async () => {
|
|
3435
3351
|
await clearAuthState();
|
|
3436
|
-
render(/* @__PURE__ */
|
|
3352
|
+
render(/* @__PURE__ */ jsx(AuthLogout, {}));
|
|
3437
3353
|
});
|
|
3438
3354
|
auth.command("status").description("Show current authentication status").action(async () => {
|
|
3439
3355
|
const state = await readAuthState();
|
|
3440
3356
|
if (!state) {
|
|
3441
3357
|
render(
|
|
3442
|
-
/* @__PURE__ */
|
|
3358
|
+
/* @__PURE__ */ jsx(AuthStatus, { state: "not-logged-in" })
|
|
3443
3359
|
);
|
|
3444
3360
|
return;
|
|
3445
3361
|
}
|
|
@@ -3447,11 +3363,11 @@ auth.command("status").description("Show current authentication status").action(
|
|
|
3447
3363
|
const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString());
|
|
3448
3364
|
const expiry = payload.exp ? new Date(payload.exp * 1e3) : null;
|
|
3449
3365
|
if (expiry && Date.now() >= expiry.getTime()) {
|
|
3450
|
-
render(/* @__PURE__ */
|
|
3366
|
+
render(/* @__PURE__ */ jsx(AuthStatus, { state: "expired", expiry }));
|
|
3451
3367
|
return;
|
|
3452
3368
|
}
|
|
3453
3369
|
render(
|
|
3454
|
-
/* @__PURE__ */
|
|
3370
|
+
/* @__PURE__ */ jsx(
|
|
3455
3371
|
AuthStatus,
|
|
3456
3372
|
{
|
|
3457
3373
|
state: "authenticated",
|
|
@@ -3464,6 +3380,6 @@ auth.command("status").description("Show current authentication status").action(
|
|
|
3464
3380
|
});
|
|
3465
3381
|
var ai = program.command("ai").description("AI editor configuration tools");
|
|
3466
3382
|
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) => {
|
|
3467
|
-
render(/* @__PURE__ */
|
|
3383
|
+
render(/* @__PURE__ */ jsx(AIScaffold, { version: options.version }));
|
|
3468
3384
|
});
|
|
3469
3385
|
program.parse(process.argv.filter((arg) => arg !== "--"));
|