@stackable-labs/cli-app-extension 3.2.0 → 3.4.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.
Files changed (2) hide show
  1. package/dist/index.js +100 -90
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5,11 +5,11 @@ import { render, useApp, Box, Text, useInput, useFocus, useFocusManager } from '
5
5
  import { SURFACE_TARGET, TEMPLATE_FLAVORS } from '@stackable-labs/sdk-extension-contracts';
6
6
  import { unlink, readFile, mkdir, writeFile, rm, readdir, rmdir } from 'fs/promises';
7
7
  import { join, dirname, relative } from 'path';
8
+ import { homedir } from 'os';
8
9
  import Spinner5 from 'ink-spinner';
9
10
  import { useState, useCallback, useEffect, useRef, useMemo } from 'react';
10
11
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
12
  import TextInput from 'ink-text-input';
12
- import { homedir } from 'os';
13
13
  import { execFile, spawn, execSync } from 'child_process';
14
14
  import { promisify } from 'util';
15
15
  import { installDependencies } from 'nypm';
@@ -22,6 +22,97 @@ import { createServer } from 'http';
22
22
  import open from 'open';
23
23
  import https from 'https';
24
24
 
25
+ // ../../lib/utils-auth/src/constants.ts
26
+ var STANDALONE_CLIENT_DATA = {
27
+ STACKABLE_LABS: {
28
+ CLI: { name: "@stackable-labs/cli-app-extension", authFile: "cli-auth.json" },
29
+ MCP: { name: "@stackable-labs/mcp-app-extension", authFile: "mcp-auth.json" }
30
+ },
31
+ STACKABLE_OPS: {
32
+ MCP: { name: "@stackable-ops/mcp", authFile: "mcp-ops-auth.json" }
33
+ }
34
+ };
35
+ var projectField = (field) => Object.fromEntries(
36
+ Object.entries(STANDALONE_CLIENT_DATA).map(([org, roles]) => [
37
+ org,
38
+ Object.fromEntries(Object.entries(roles).map(([role, entry]) => [role, entry[field]]))
39
+ ])
40
+ );
41
+ var STANDALONE_CLIENT = projectField("name");
42
+ var STANDALONE_CLIENT_AUTH_FILE = projectField("authFile");
43
+ Object.values(STANDALONE_CLIENT_DATA).flatMap((roles) => Object.values(roles).map((entry) => entry.name));
44
+
45
+ // ../../lib/utils-auth/src/cli/shared.ts
46
+ var AUTH_DIR = join(homedir(), ".stackable");
47
+ join(AUTH_DIR, STANDALONE_CLIENT_AUTH_FILE.STACKABLE_LABS.CLI);
48
+ join(AUTH_DIR, STANDALONE_CLIENT_AUTH_FILE.STACKABLE_LABS.MCP);
49
+ var resolveAuthFile = (filename) => join(AUTH_DIR, STANDALONE_CLIENT_AUTH_FILE.STACKABLE_LABS.CLI);
50
+ var readAuthState = async (filename) => {
51
+ try {
52
+ const content = await readFile(resolveAuthFile(filename), "utf8");
53
+ return JSON.parse(content);
54
+ } catch {
55
+ return null;
56
+ }
57
+ };
58
+ var writeAuthState = async (state, filename) => {
59
+ await mkdir(AUTH_DIR, { recursive: true, mode: 448 });
60
+ await writeFile(resolveAuthFile(), JSON.stringify(state, null, 2), { mode: 384 });
61
+ };
62
+ var clearAuthState = async (filename) => {
63
+ try {
64
+ await unlink(resolveAuthFile(filename));
65
+ } catch {
66
+ }
67
+ };
68
+ var decodeJwtPayload = (token) => {
69
+ try {
70
+ const [, payload] = token.split(".");
71
+ if (!payload) {
72
+ return null;
73
+ }
74
+ const json = Buffer.from(payload, "base64url").toString("utf8");
75
+ return JSON.parse(json);
76
+ } catch {
77
+ return null;
78
+ }
79
+ };
80
+ var getToken = async (filename) => {
81
+ const state = await readAuthState(filename);
82
+ if (!state) {
83
+ throw new Error("Not authenticated. Run `stackable-app-extension auth login` first.");
84
+ }
85
+ const payload = decodeJwtPayload(state.token);
86
+ if (payload?.exp && typeof payload.exp === "number") {
87
+ if (Date.now() >= payload.exp * 1e3) {
88
+ throw new Error("Session expired. Run `stackable-app-extension auth login` to re-authenticate.");
89
+ }
90
+ }
91
+ return state.token;
92
+ };
93
+
94
+ // ../../lib/contracts/src/base.ts
95
+ var asClerkUserId = (value) => value;
96
+ var asClerkOrgId = (value) => value;
97
+
98
+ // ../../lib/contracts/src/fields.ts
99
+ var FIELD_TYPE = {
100
+ TEXTAREA: "textarea",
101
+ TEXT: "text",
102
+ EMAIL: "email",
103
+ /** Non-rendered field — value still persists. Use with `lookup` to derive the
104
+ * value at save time from other fields via the resolver registry. */
105
+ HIDDEN: "hidden"
106
+ };
107
+ var SECUREABLE_FIELD_TYPE = {
108
+ TEXT: FIELD_TYPE.TEXT,
109
+ TEXTAREA: FIELD_TYPE.TEXTAREA,
110
+ EMAIL: FIELD_TYPE.EMAIL,
111
+ HIDDEN: FIELD_TYPE.HIDDEN
112
+ };
113
+ var typeAllowsSecret = (fieldType) => Object.values(SECUREABLE_FIELD_TYPE).includes(fieldType);
114
+ var allowsSecret = (field) => typeAllowsSecret(field.type);
115
+
25
116
  // ../../lib/utils-js/src/crypto.ts
26
117
  var getCrypto = () => {
27
118
  if (typeof globalThis !== "undefined" && globalThis.crypto) {
@@ -614,28 +705,6 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
614
705
  );
615
706
  };
616
707
 
617
- // ../../lib/contracts/src/base.ts
618
- var asClerkUserId = (value) => value;
619
- var asClerkOrgId = (value) => value;
620
-
621
- // ../../lib/contracts/src/fields.ts
622
- var FIELD_TYPE = {
623
- TEXTAREA: "textarea",
624
- TEXT: "text",
625
- EMAIL: "email",
626
- /** Non-rendered field — value still persists. Use with `lookup` to derive the
627
- * value at save time from other fields via the resolver registry. */
628
- HIDDEN: "hidden"
629
- };
630
- var SECUREABLE_FIELD_TYPE = {
631
- TEXT: FIELD_TYPE.TEXT,
632
- TEXTAREA: FIELD_TYPE.TEXTAREA,
633
- EMAIL: FIELD_TYPE.EMAIL,
634
- HIDDEN: FIELD_TYPE.HIDDEN
635
- };
636
- var typeAllowsSecret = (fieldType) => Object.values(SECUREABLE_FIELD_TYPE).includes(fieldType);
637
- var allowsSecret = (field) => typeAllowsSecret(field.type);
638
-
639
708
  // src/lib/manifest-diff.ts
640
709
  var diffItems = (previous, next, getKey) => {
641
710
  const prevMap = new Map(previous.map((item) => [getKey(item), item]));
@@ -1199,78 +1268,19 @@ var TemplateSelect = ({ onSubmit, onBack }) => {
1199
1268
  );
1200
1269
  };
1201
1270
 
1202
- // ../../lib/utils-auth/src/constants.ts
1203
- var STANDALONE_CLIENT_DATA = {
1204
- CLI: { name: "@stackable-labs/cli-app-extension", authFile: "cli-auth.json" },
1205
- MCP: { name: "@stackable-labs/mcp-app-extension", authFile: "mcp-auth.json" }
1206
- };
1207
- var STANDALONE_CLIENT = Object.fromEntries(
1208
- Object.entries(STANDALONE_CLIENT_DATA).map(([k, v]) => [k, v.name])
1209
- );
1210
- var STANDALONE_CLIENT_AUTH_FILE = Object.fromEntries(
1211
- Object.entries(STANDALONE_CLIENT_DATA).map(([k, v]) => [k, v.authFile])
1212
- );
1213
- Object.values(STANDALONE_CLIENT);
1214
-
1215
1271
  // ../../lib/utils-auth/src/index.ts
1216
- var deriveClientId = async (clientName) => (await getDigest(clientName)).slice(0, 32);
1217
- var AUTH_DIR = join(homedir(), ".stackable");
1218
- join(AUTH_DIR, STANDALONE_CLIENT_AUTH_FILE.CLI);
1219
- join(AUTH_DIR, STANDALONE_CLIENT_AUTH_FILE.MCP);
1220
- var resolveAuthFile = (filename) => join(AUTH_DIR, STANDALONE_CLIENT_AUTH_FILE.CLI);
1221
- var readAuthState = async (filename) => {
1222
- try {
1223
- const content = await readFile(resolveAuthFile(filename), "utf8");
1224
- return JSON.parse(content);
1225
- } catch {
1226
- return null;
1227
- }
1228
- };
1229
- var writeAuthState = async (state, filename) => {
1230
- await mkdir(AUTH_DIR, { recursive: true, mode: 448 });
1231
- await writeFile(resolveAuthFile(), JSON.stringify(state, null, 2), { mode: 384 });
1232
- };
1233
- var clearAuthState = async (filename) => {
1234
- try {
1235
- await unlink(resolveAuthFile(filename));
1236
- } catch {
1237
- }
1238
- };
1239
- var decodeJwtPayload = (token) => {
1240
- try {
1241
- const [, payload] = token.split(".");
1242
- if (!payload) {
1243
- return null;
1244
- }
1245
- const json = Buffer.from(payload, "base64url").toString("utf8");
1246
- return JSON.parse(json);
1247
- } catch {
1248
- return null;
1249
- }
1250
- };
1251
- var getToken = async (filename) => {
1252
- const state = await readAuthState(filename);
1253
- if (!state) {
1254
- throw new Error("Not authenticated. Run `stackable-app-extension auth login` first.");
1255
- }
1256
- const payload = decodeJwtPayload(state.token);
1257
- if (payload?.exp && typeof payload.exp === "number") {
1258
- if (Date.now() >= payload.exp * 1e3) {
1259
- throw new Error("Session expired. Run `stackable-app-extension auth login` to re-authenticate.");
1260
- }
1261
- }
1262
- return state.token;
1263
- };
1272
+ var deriveDcrClientId = async (clientName) => (await getDigest(clientName)).slice(0, 32);
1273
+ var deriveClientId = async (clientName) => deriveDcrClientId(clientName);
1264
1274
 
1265
1275
  // src/lib/api.ts
1266
- var DEFAULT_ADMIN_API_URL = "https://api-use1.stackablelabs.io/admin";
1276
+ var DEFAULT_ADMIN_LABS_API_URL = "https://api-x.stackablelabs.io/admin";
1267
1277
  var DEFAULT_PUBLIC_API_URL = "https://api.stackablelabs.io/app-extension/latest";
1268
- var getAdminApiBaseUrl = () => process.env.ADMIN_API_BASE_URL ?? DEFAULT_ADMIN_API_URL;
1278
+ var getAdminApiBaseUrl = () => process.env.ADMIN_LABS_API_BASE_URL ?? DEFAULT_ADMIN_LABS_API_URL;
1269
1279
  var getPublicApiBaseUrl = () => process.env.PUBLIC_API_BASE_URL ?? DEFAULT_PUBLIC_API_URL;
1270
1280
  var authHeaders = (token) => ({
1271
1281
  authorization: `Bearer ${token}`,
1272
1282
  "content-type": "application/json",
1273
- "x-client-name": STANDALONE_CLIENT.CLI
1283
+ "x-client-name": STANDALONE_CLIENT.STACKABLE_LABS.CLI
1274
1284
  });
1275
1285
  var fetchApps = async (token) => {
1276
1286
  const baseUrl = getAdminApiBaseUrl();
@@ -1278,7 +1288,7 @@ var fetchApps = async (token) => {
1278
1288
  headers: authHeaders(token)
1279
1289
  });
1280
1290
  if (!res.ok) {
1281
- throw new Error(`Failed to fetch apps${baseUrl !== DEFAULT_ADMIN_API_URL ? ` (from ${baseUrl})` : ""}: ${res.status} ${res.statusText}`);
1291
+ throw new Error(`Failed to fetch apps${baseUrl !== DEFAULT_ADMIN_LABS_API_URL ? ` (from ${baseUrl})` : ""}: ${res.status} ${res.statusText}`);
1282
1292
  }
1283
1293
  const adminApps = await res.json();
1284
1294
  return adminApps.filter((app) => app.enabled).map(({ id, name, targets, iconUrl }) => ({
@@ -3716,7 +3726,7 @@ var callbackPage = (heading, sub, redirectUrl) => `<!DOCTYPE html>
3716
3726
  ${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>` : ""}
3717
3727
  </body></html>`;
3718
3728
  var performCLIOAuthFlow = async ({ dashboardUrl, adminApiBaseUrl }) => {
3719
- const clientId = await deriveClientId(STANDALONE_CLIENT.CLI);
3729
+ const clientId = await deriveClientId(STANDALONE_CLIENT.STACKABLE_LABS.CLI);
3720
3730
  const codeVerifier = getVerifier();
3721
3731
  const codeChallenge = await getDigest(codeVerifier, "base64url");
3722
3732
  const state = getNonce();
@@ -4001,7 +4011,7 @@ var checkForUpdate = (currentVersion) => {
4001
4011
  var require2 = createRequire(import.meta.url);
4002
4012
  var { version } = require2("../package.json");
4003
4013
  checkForUpdate(version);
4004
- var DASHBOARD_URL = process.env.ADMIN_DASHBOARD_URL ?? "https://admin.stackablelabs.com";
4014
+ var DASHBOARD_URL = process.env.ADMIN_LABS_DASHBOARD_URL ?? "https://admin.stackablelabs.com";
4005
4015
  var parseTemplateFlavor = (value) => {
4006
4016
  if (!TEMPLATE_FLAVORS.includes(value)) {
4007
4017
  throw new InvalidArgumentError(`Invalid template flavor "${value}". Valid: ${TEMPLATE_FLAVORS.join(", ")}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackable-labs/cli-app-extension",
3
- "version": "3.2.0",
3
+ "version": "3.4.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "bin": {