@stackable-labs/cli-app-extension 3.1.0 → 3.3.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 +101 -93
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3,13 +3,13 @@ import { createRequire } from 'module';
3
3
  import { program, InvalidArgumentError } from 'commander';
4
4
  import { render, useApp, Box, Text, useInput, useFocus, useFocusManager } from 'ink';
5
5
  import { SURFACE_TARGET, TEMPLATE_FLAVORS } from '@stackable-labs/sdk-extension-contracts';
6
- import { unlink, readFile, mkdir, writeFile, rm, readdir, rmdir } from 'fs/promises';
7
6
  import { join, dirname, relative } from 'path';
7
+ import { unlink, readFile, mkdir, writeFile, rm, readdir, rmdir } from 'fs/promises';
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';
@@ -66,6 +66,99 @@ var toKebabCase = (value) => value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "
66
66
 
67
67
  // ../../lib/utils-js/src/promise.ts
68
68
  var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
69
+
70
+ // ../../lib/utils-auth/src/constants.ts
71
+ var STANDALONE_CLIENT_DATA = {
72
+ STACKABLE_LABS: {
73
+ CLI: { name: "@stackable-labs/cli-app-extension", authFile: "cli-auth.json" },
74
+ MCP: { name: "@stackable-labs/mcp-app-extension", authFile: "mcp-auth.json" }
75
+ },
76
+ STACKABLE_OPS: {
77
+ MCP: { name: "@stackable-ops/mcp", authFile: "mcp-ops-auth.json" }
78
+ }
79
+ };
80
+ var projectField = (field) => Object.fromEntries(
81
+ Object.entries(STANDALONE_CLIENT_DATA).map(([org, roles]) => [
82
+ org,
83
+ Object.fromEntries(Object.entries(roles).map(([role, entry]) => [role, entry[field]]))
84
+ ])
85
+ );
86
+ var STANDALONE_CLIENT = projectField("name");
87
+ var STANDALONE_CLIENT_AUTH_FILE = projectField("authFile");
88
+ Object.values(STANDALONE_CLIENT_DATA).flatMap((roles) => Object.values(roles).map((entry) => entry.name));
89
+ var AUTH_DIR = join(homedir(), ".stackable");
90
+ var resolveAuthFile = (filename) => join(AUTH_DIR, STANDALONE_CLIENT_AUTH_FILE.STACKABLE_LABS.CLI);
91
+ var readAuthState = async (filename) => {
92
+ try {
93
+ const content = await readFile(resolveAuthFile(filename), "utf8");
94
+ return JSON.parse(content);
95
+ } catch {
96
+ return null;
97
+ }
98
+ };
99
+ var writeAuthState = async (state, filename) => {
100
+ await mkdir(AUTH_DIR, { recursive: true, mode: 448 });
101
+ await writeFile(resolveAuthFile(), JSON.stringify(state, null, 2), { mode: 384 });
102
+ };
103
+ var clearAuthState = async (filename) => {
104
+ try {
105
+ await unlink(resolveAuthFile(filename));
106
+ } catch {
107
+ }
108
+ };
109
+ var decodeJwtPayload = (token) => {
110
+ try {
111
+ const [, payload] = token.split(".");
112
+ if (!payload) {
113
+ return null;
114
+ }
115
+ const json = Buffer.from(payload, "base64url").toString("utf8");
116
+ return JSON.parse(json);
117
+ } catch {
118
+ return null;
119
+ }
120
+ };
121
+ var getToken = async (filename) => {
122
+ const state = await readAuthState(filename);
123
+ if (!state) {
124
+ throw new Error("Not authenticated. Run `stackable-app-extension auth login` first.");
125
+ }
126
+ const payload = decodeJwtPayload(state.token);
127
+ if (payload?.exp && typeof payload.exp === "number") {
128
+ if (Date.now() >= payload.exp * 1e3) {
129
+ throw new Error("Session expired. Run `stackable-app-extension auth login` to re-authenticate.");
130
+ }
131
+ }
132
+ return state.token;
133
+ };
134
+
135
+ // ../../lib/contracts/src/base.ts
136
+ var asClerkUserId = (value) => value;
137
+ var asClerkOrgId = (value) => value;
138
+
139
+ // ../../lib/contracts/src/fields.ts
140
+ var FIELD_TYPE = {
141
+ TEXTAREA: "textarea",
142
+ TEXT: "text",
143
+ EMAIL: "email",
144
+ /** Non-rendered field — value still persists. Use with `lookup` to derive the
145
+ * value at save time from other fields via the resolver registry. */
146
+ HIDDEN: "hidden"
147
+ };
148
+ var SECUREABLE_FIELD_TYPE = {
149
+ TEXT: FIELD_TYPE.TEXT,
150
+ TEXTAREA: FIELD_TYPE.TEXTAREA,
151
+ EMAIL: FIELD_TYPE.EMAIL,
152
+ HIDDEN: FIELD_TYPE.HIDDEN
153
+ };
154
+ var typeAllowsSecret = (fieldType) => Object.values(SECUREABLE_FIELD_TYPE).includes(fieldType);
155
+ var allowsSecret = (field) => typeAllowsSecret(field.type);
156
+
157
+ // ../../lib/utils-auth/src/index.ts
158
+ var deriveDcrClientId = async (clientName) => (await getDigest(clientName)).slice(0, 32);
159
+ var deriveClientId = async (clientName) => deriveDcrClientId(clientName);
160
+ join(AUTH_DIR, STANDALONE_CLIENT_AUTH_FILE.STACKABLE_LABS.CLI);
161
+ join(AUTH_DIR, STANDALONE_CLIENT_AUTH_FILE.STACKABLE_LABS.MCP);
69
162
  var WORDMARK = [
70
163
  " _ _ _ _ ",
71
164
  " ___| |_ __ _ ___| | ____ _| |__ | | ___",
@@ -614,28 +707,6 @@ var SettingsPrompt = ({ defaultDir, onSubmit, onBack }) => {
614
707
  );
615
708
  };
616
709
 
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
710
  // src/lib/manifest-diff.ts
640
711
  var diffItems = (previous, next, getKey) => {
641
712
  const prevMap = new Map(previous.map((item) => [getKey(item), item]));
@@ -1199,78 +1270,15 @@ var TemplateSelect = ({ onSubmit, onBack }) => {
1199
1270
  );
1200
1271
  };
1201
1272
 
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
- // ../../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
- };
1264
-
1265
1273
  // src/lib/api.ts
1266
- var DEFAULT_ADMIN_API_URL = "https://api-use1.stackablelabs.io/admin";
1274
+ var DEFAULT_ADMIN_LABS_API_URL = "https://api-x.stackablelabs.io/admin";
1267
1275
  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;
1276
+ var getAdminApiBaseUrl = () => process.env.ADMIN_LABS_API_BASE_URL ?? DEFAULT_ADMIN_LABS_API_URL;
1269
1277
  var getPublicApiBaseUrl = () => process.env.PUBLIC_API_BASE_URL ?? DEFAULT_PUBLIC_API_URL;
1270
1278
  var authHeaders = (token) => ({
1271
1279
  authorization: `Bearer ${token}`,
1272
1280
  "content-type": "application/json",
1273
- "x-client-name": STANDALONE_CLIENT.CLI
1281
+ "x-client-name": STANDALONE_CLIENT.STACKABLE_LABS.CLI
1274
1282
  });
1275
1283
  var fetchApps = async (token) => {
1276
1284
  const baseUrl = getAdminApiBaseUrl();
@@ -1278,7 +1286,7 @@ var fetchApps = async (token) => {
1278
1286
  headers: authHeaders(token)
1279
1287
  });
1280
1288
  if (!res.ok) {
1281
- throw new Error(`Failed to fetch apps${baseUrl !== DEFAULT_ADMIN_API_URL ? ` (from ${baseUrl})` : ""}: ${res.status} ${res.statusText}`);
1289
+ throw new Error(`Failed to fetch apps${baseUrl !== DEFAULT_ADMIN_LABS_API_URL ? ` (from ${baseUrl})` : ""}: ${res.status} ${res.statusText}`);
1282
1290
  }
1283
1291
  const adminApps = await res.json();
1284
1292
  return adminApps.filter((app) => app.enabled).map(({ id, name, targets, iconUrl }) => ({
@@ -3716,7 +3724,7 @@ var callbackPage = (heading, sub, redirectUrl) => `<!DOCTYPE html>
3716
3724
  ${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
3725
  </body></html>`;
3718
3726
  var performCLIOAuthFlow = async ({ dashboardUrl, adminApiBaseUrl }) => {
3719
- const clientId = await deriveClientId(STANDALONE_CLIENT.CLI);
3727
+ const clientId = await deriveClientId(STANDALONE_CLIENT.STACKABLE_LABS.CLI);
3720
3728
  const codeVerifier = getVerifier();
3721
3729
  const codeChallenge = await getDigest(codeVerifier, "base64url");
3722
3730
  const state = getNonce();
@@ -4001,7 +4009,7 @@ var checkForUpdate = (currentVersion) => {
4001
4009
  var require2 = createRequire(import.meta.url);
4002
4010
  var { version } = require2("../package.json");
4003
4011
  checkForUpdate(version);
4004
- var DASHBOARD_URL = process.env.ADMIN_DASHBOARD_URL ?? "https://admin.stackablelabs.com";
4012
+ var DASHBOARD_URL = process.env.ADMIN_LABS_DASHBOARD_URL ?? "https://admin.stackablelabs.com";
4005
4013
  var parseTemplateFlavor = (value) => {
4006
4014
  if (!TEMPLATE_FLAVORS.includes(value)) {
4007
4015
  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.1.0",
3
+ "version": "3.3.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "bin": {