@docyrus/docyrus 0.0.1 → 0.0.3
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 +44 -0
- package/main.js +1492 -58
- package/main.js.map +4 -4
- package/package.json +1 -1
package/main.js
CHANGED
|
@@ -39952,7 +39952,7 @@ function buildInputSchema(args, env, options) {
|
|
|
39952
39952
|
// package.json
|
|
39953
39953
|
var package_default = {
|
|
39954
39954
|
name: "@docyrus/docyrus",
|
|
39955
|
-
version: "0.0.
|
|
39955
|
+
version: "0.0.3",
|
|
39956
39956
|
private: false,
|
|
39957
39957
|
description: "Docyrus API CLI",
|
|
39958
39958
|
main: "./main.js",
|
|
@@ -40428,6 +40428,8 @@ function createAuthCli(dependencies) {
|
|
|
40428
40428
|
}
|
|
40429
40429
|
|
|
40430
40430
|
// src/services/inputReader.ts
|
|
40431
|
+
var import_promises2 = require("node:fs/promises");
|
|
40432
|
+
var import_node_path4 = require("node:path");
|
|
40431
40433
|
async function readStdinText() {
|
|
40432
40434
|
if (process.stdin.isTTY) {
|
|
40433
40435
|
return "";
|
|
@@ -40451,20 +40453,99 @@ function parseJsonData(raw, source) {
|
|
|
40451
40453
|
});
|
|
40452
40454
|
}
|
|
40453
40455
|
}
|
|
40454
|
-
|
|
40455
|
-
const
|
|
40456
|
-
let
|
|
40457
|
-
|
|
40458
|
-
|
|
40456
|
+
function parseCsvRow(line) {
|
|
40457
|
+
const values = [];
|
|
40458
|
+
let current = "";
|
|
40459
|
+
let inQuotes = false;
|
|
40460
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
40461
|
+
const char = line[index];
|
|
40462
|
+
const next = line[index + 1];
|
|
40463
|
+
if (char === '"') {
|
|
40464
|
+
if (inQuotes && next === '"') {
|
|
40465
|
+
current += '"';
|
|
40466
|
+
index += 1;
|
|
40467
|
+
} else {
|
|
40468
|
+
inQuotes = !inQuotes;
|
|
40469
|
+
}
|
|
40470
|
+
continue;
|
|
40471
|
+
}
|
|
40472
|
+
if (char === "," && !inQuotes) {
|
|
40473
|
+
values.push(current.trim());
|
|
40474
|
+
current = "";
|
|
40475
|
+
continue;
|
|
40476
|
+
}
|
|
40477
|
+
current += char;
|
|
40459
40478
|
}
|
|
40460
|
-
if (
|
|
40461
|
-
throw new UserInputError("
|
|
40479
|
+
if (inQuotes) {
|
|
40480
|
+
throw new UserInputError("Invalid CSV. Unterminated quoted value detected.");
|
|
40462
40481
|
}
|
|
40463
|
-
|
|
40464
|
-
|
|
40465
|
-
|
|
40482
|
+
values.push(current.trim());
|
|
40483
|
+
return values;
|
|
40484
|
+
}
|
|
40485
|
+
function parseCsvData(raw, source) {
|
|
40486
|
+
const trimmed = raw.trim();
|
|
40487
|
+
if (!trimmed) {
|
|
40488
|
+
throw new UserInputError(`CSV input is empty in ${source}.`);
|
|
40489
|
+
}
|
|
40490
|
+
const lines = trimmed.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
40491
|
+
if (lines.length < 2) {
|
|
40492
|
+
throw new UserInputError(`CSV input in ${source} must include a header row and at least one data row.`);
|
|
40493
|
+
}
|
|
40494
|
+
const header = parseCsvRow(lines[0]);
|
|
40495
|
+
if (header.length === 0 || header.some((name) => name.length === 0)) {
|
|
40496
|
+
throw new UserInputError(`CSV header in ${source} contains empty column names.`);
|
|
40497
|
+
}
|
|
40498
|
+
const records = [];
|
|
40499
|
+
for (let rowIndex = 1; rowIndex < lines.length; rowIndex += 1) {
|
|
40500
|
+
const rowValues = parseCsvRow(lines[rowIndex]);
|
|
40501
|
+
if (rowValues.length !== header.length) {
|
|
40502
|
+
throw new UserInputError(
|
|
40503
|
+
`CSV row ${rowIndex + 1} in ${source} has ${rowValues.length} values but header has ${header.length}.`
|
|
40504
|
+
);
|
|
40505
|
+
}
|
|
40506
|
+
const record2 = {};
|
|
40507
|
+
for (let columnIndex = 0; columnIndex < header.length; columnIndex += 1) {
|
|
40508
|
+
record2[header[columnIndex]] = rowValues[columnIndex];
|
|
40509
|
+
}
|
|
40510
|
+
records.push(record2);
|
|
40466
40511
|
}
|
|
40467
|
-
return
|
|
40512
|
+
return records;
|
|
40513
|
+
}
|
|
40514
|
+
async function readDataInput(params) {
|
|
40515
|
+
const {
|
|
40516
|
+
data,
|
|
40517
|
+
fromFile,
|
|
40518
|
+
readStdin = readStdinText,
|
|
40519
|
+
readFileFn = async (path3, encoding) => await (0, import_promises2.readFile)(path3, encoding)
|
|
40520
|
+
} = params;
|
|
40521
|
+
const trimmedData = data?.trim();
|
|
40522
|
+
const trimmedFromFile = fromFile?.trim();
|
|
40523
|
+
if (trimmedData && trimmedFromFile) {
|
|
40524
|
+
throw new UserInputError("Provide either --data or --from-file, not both.");
|
|
40525
|
+
}
|
|
40526
|
+
if (trimmedFromFile) {
|
|
40527
|
+
let content;
|
|
40528
|
+
try {
|
|
40529
|
+
content = await readFileFn(trimmedFromFile, "utf8");
|
|
40530
|
+
} catch (error48) {
|
|
40531
|
+
throw new UserInputError(`Unable to read file '${trimmedFromFile}'.`, {
|
|
40532
|
+
cause: error48
|
|
40533
|
+
});
|
|
40534
|
+
}
|
|
40535
|
+
const extension = (0, import_node_path4.extname)(trimmedFromFile).toLowerCase();
|
|
40536
|
+
if (extension === ".csv") {
|
|
40537
|
+
return parseCsvData(content, "--from-file");
|
|
40538
|
+
}
|
|
40539
|
+
return parseJsonData(content, "--from-file");
|
|
40540
|
+
}
|
|
40541
|
+
if (trimmedData) {
|
|
40542
|
+
return parseJsonData(trimmedData, "--data");
|
|
40543
|
+
}
|
|
40544
|
+
const stdinContent = (await readStdin()).trim();
|
|
40545
|
+
if (!stdinContent) {
|
|
40546
|
+
throw new UserInputError("JSON input is required. Provide --data, --from-file, or pipe JSON via stdin.");
|
|
40547
|
+
}
|
|
40548
|
+
return parseJsonData(stdinContent, "stdin");
|
|
40468
40549
|
}
|
|
40469
40550
|
|
|
40470
40551
|
// src/commands/curlCommand.ts
|
|
@@ -40610,6 +40691,42 @@ function createCurlCli(dependencies) {
|
|
|
40610
40691
|
}
|
|
40611
40692
|
|
|
40612
40693
|
// src/commands/dsCommands.ts
|
|
40694
|
+
var BULK_OPERATION_LIMIT = 50;
|
|
40695
|
+
function isRecord(value) {
|
|
40696
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40697
|
+
}
|
|
40698
|
+
function toBulkPayload(payload, mode) {
|
|
40699
|
+
if (!Array.isArray(payload)) {
|
|
40700
|
+
return null;
|
|
40701
|
+
}
|
|
40702
|
+
if (payload.length === 0) {
|
|
40703
|
+
throw new UserInputError("Batch payload cannot be empty.");
|
|
40704
|
+
}
|
|
40705
|
+
if (payload.length > BULK_OPERATION_LIMIT) {
|
|
40706
|
+
throw new UserInputError(`Batch payload cannot exceed ${BULK_OPERATION_LIMIT} items.`);
|
|
40707
|
+
}
|
|
40708
|
+
const records = [];
|
|
40709
|
+
for (let index = 0; index < payload.length; index += 1) {
|
|
40710
|
+
const item = payload[index];
|
|
40711
|
+
if (!isRecord(item)) {
|
|
40712
|
+
throw new UserInputError(`Batch item at index ${index} must be a JSON object.`);
|
|
40713
|
+
}
|
|
40714
|
+
if (mode === "update") {
|
|
40715
|
+
const itemId = item.id;
|
|
40716
|
+
if (itemId === void 0 || itemId === null || typeof itemId === "string" && itemId.trim().length === 0) {
|
|
40717
|
+
throw new UserInputError(`Batch update item at index ${index} is missing required 'id'.`);
|
|
40718
|
+
}
|
|
40719
|
+
}
|
|
40720
|
+
records.push(item);
|
|
40721
|
+
}
|
|
40722
|
+
return records;
|
|
40723
|
+
}
|
|
40724
|
+
function toSinglePayload(payload) {
|
|
40725
|
+
if (!isRecord(payload)) {
|
|
40726
|
+
throw new UserInputError("Expected a JSON object for single-item operation.");
|
|
40727
|
+
}
|
|
40728
|
+
return payload;
|
|
40729
|
+
}
|
|
40613
40730
|
function createDsCli(dependencies) {
|
|
40614
40731
|
const dsCli = Cli_exports.create("ds", {
|
|
40615
40732
|
description: "Data source commands",
|
|
@@ -40683,16 +40800,25 @@ function createDsCli(dependencies) {
|
|
|
40683
40800
|
dataSourceSlug: external_exports.string().min(1)
|
|
40684
40801
|
}),
|
|
40685
40802
|
options: external_exports.object({
|
|
40686
|
-
data: external_exports.string().optional().describe("JSON payload for record fields")
|
|
40803
|
+
data: external_exports.string().optional().describe("JSON payload for record fields"),
|
|
40804
|
+
fromFile: external_exports.string().optional().describe("Path to JSON or CSV payload file")
|
|
40687
40805
|
}),
|
|
40688
40806
|
run: async (context) => {
|
|
40689
40807
|
const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
|
|
40690
40808
|
const apiClient = dependencies.createApiClient(apiBaseUrl);
|
|
40691
|
-
const payload = await
|
|
40692
|
-
|
|
40809
|
+
const payload = await readDataInput({
|
|
40810
|
+
data: context.options.data,
|
|
40811
|
+
fromFile: context.options.fromFile
|
|
40812
|
+
});
|
|
40813
|
+
const bulkPayload = toBulkPayload(payload, "create");
|
|
40814
|
+
const response = bulkPayload ? await apiClient.request({
|
|
40815
|
+
method: "POST",
|
|
40816
|
+
path: `/apps/${context.args.appSlug}/data-sources/${context.args.dataSourceSlug}/items/bulk`,
|
|
40817
|
+
body: bulkPayload
|
|
40818
|
+
}) : await apiClient.request({
|
|
40693
40819
|
method: "POST",
|
|
40694
40820
|
path: `/apps/${context.args.appSlug}/data-sources/${context.args.dataSourceSlug}/items`,
|
|
40695
|
-
body: payload
|
|
40821
|
+
body: toSinglePayload(payload)
|
|
40696
40822
|
});
|
|
40697
40823
|
return await injectContext({
|
|
40698
40824
|
apiBaseUrl,
|
|
@@ -40706,20 +40832,37 @@ function createDsCli(dependencies) {
|
|
|
40706
40832
|
args: external_exports.object({
|
|
40707
40833
|
appSlug: external_exports.string().min(1),
|
|
40708
40834
|
dataSourceSlug: external_exports.string().min(1),
|
|
40709
|
-
recordId: external_exports.string().min(1)
|
|
40835
|
+
recordId: external_exports.string().min(1).optional()
|
|
40710
40836
|
}),
|
|
40711
40837
|
options: external_exports.object({
|
|
40712
|
-
data: external_exports.string().optional().describe("JSON payload for record fields")
|
|
40838
|
+
data: external_exports.string().optional().describe("JSON payload for record fields"),
|
|
40839
|
+
fromFile: external_exports.string().optional().describe("Path to JSON or CSV payload file")
|
|
40713
40840
|
}),
|
|
40714
40841
|
run: async (context) => {
|
|
40715
40842
|
const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
|
|
40716
40843
|
const apiClient = dependencies.createApiClient(apiBaseUrl);
|
|
40717
|
-
const payload = await
|
|
40718
|
-
|
|
40719
|
-
|
|
40720
|
-
path: `/apps/${context.args.appSlug}/data-sources/${context.args.dataSourceSlug}/items/${context.args.recordId}`,
|
|
40721
|
-
body: payload
|
|
40844
|
+
const payload = await readDataInput({
|
|
40845
|
+
data: context.options.data,
|
|
40846
|
+
fromFile: context.options.fromFile
|
|
40722
40847
|
});
|
|
40848
|
+
const bulkPayload = toBulkPayload(payload, "update");
|
|
40849
|
+
if (bulkPayload && context.args.recordId) {
|
|
40850
|
+
throw new UserInputError("Do not provide recordId for batch update. Include 'id' in each item instead.");
|
|
40851
|
+
}
|
|
40852
|
+
const response = bulkPayload ? await apiClient.request({
|
|
40853
|
+
method: "PATCH",
|
|
40854
|
+
path: `/apps/${context.args.appSlug}/data-sources/${context.args.dataSourceSlug}/items/bulk`,
|
|
40855
|
+
body: bulkPayload
|
|
40856
|
+
}) : await (() => {
|
|
40857
|
+
if (!context.args.recordId) {
|
|
40858
|
+
throw new UserInputError("recordId is required for single-item update.");
|
|
40859
|
+
}
|
|
40860
|
+
return apiClient.request({
|
|
40861
|
+
method: "PATCH",
|
|
40862
|
+
path: `/apps/${context.args.appSlug}/data-sources/${context.args.dataSourceSlug}/items/${context.args.recordId}`,
|
|
40863
|
+
body: toSinglePayload(payload)
|
|
40864
|
+
});
|
|
40865
|
+
})();
|
|
40723
40866
|
return await injectContext({
|
|
40724
40867
|
apiBaseUrl,
|
|
40725
40868
|
authStore: dependencies.authStore,
|
|
@@ -40752,6 +40895,185 @@ function createDsCli(dependencies) {
|
|
|
40752
40895
|
}
|
|
40753
40896
|
|
|
40754
40897
|
// src/commands/discoverCommands.ts
|
|
40898
|
+
var import_promises3 = require("node:fs/promises");
|
|
40899
|
+
var SUPPORTED_HTTP_METHODS2 = [
|
|
40900
|
+
"GET",
|
|
40901
|
+
"POST",
|
|
40902
|
+
"PUT",
|
|
40903
|
+
"PATCH",
|
|
40904
|
+
"DELETE",
|
|
40905
|
+
"HEAD",
|
|
40906
|
+
"OPTIONS",
|
|
40907
|
+
"TRACE"
|
|
40908
|
+
];
|
|
40909
|
+
function isRecord2(value) {
|
|
40910
|
+
return typeof value === "object" && value !== null;
|
|
40911
|
+
}
|
|
40912
|
+
function isEnoentError(error48) {
|
|
40913
|
+
return typeof error48 === "object" && error48 !== null && "code" in error48 && error48.code === "ENOENT";
|
|
40914
|
+
}
|
|
40915
|
+
function normalizePathInput(pathValue) {
|
|
40916
|
+
const trimmed = pathValue.trim();
|
|
40917
|
+
if (!trimmed) {
|
|
40918
|
+
throw new UserInputError("Path is required.");
|
|
40919
|
+
}
|
|
40920
|
+
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
40921
|
+
}
|
|
40922
|
+
function buildPathCandidates(pathValue) {
|
|
40923
|
+
const normalized = normalizePathInput(pathValue);
|
|
40924
|
+
const candidates = /* @__PURE__ */ new Set([normalized]);
|
|
40925
|
+
if (normalized === "/v1") {
|
|
40926
|
+
candidates.add("/");
|
|
40927
|
+
} else if (normalized.startsWith("/v1/")) {
|
|
40928
|
+
candidates.add(normalized.substring(3));
|
|
40929
|
+
} else {
|
|
40930
|
+
candidates.add(`/v1${normalized}`);
|
|
40931
|
+
}
|
|
40932
|
+
return Array.from(candidates.values());
|
|
40933
|
+
}
|
|
40934
|
+
function toOutputPath(pathValue) {
|
|
40935
|
+
const normalized = normalizePathInput(pathValue);
|
|
40936
|
+
if (normalized === "/") {
|
|
40937
|
+
return "/v1";
|
|
40938
|
+
}
|
|
40939
|
+
if (normalized.startsWith("/v1/") || normalized === "/v1") {
|
|
40940
|
+
return normalized;
|
|
40941
|
+
}
|
|
40942
|
+
return `/v1${normalized}`;
|
|
40943
|
+
}
|
|
40944
|
+
function parseEndpointSelector(input) {
|
|
40945
|
+
const trimmed = input.trim();
|
|
40946
|
+
if (!trimmed) {
|
|
40947
|
+
throw new UserInputError("Endpoint selector is required.");
|
|
40948
|
+
}
|
|
40949
|
+
const methodPathMatch = trimmed.match(/^\[([a-z]+)\](\/.*)$/i);
|
|
40950
|
+
if (!methodPathMatch) {
|
|
40951
|
+
return {
|
|
40952
|
+
path: trimmed,
|
|
40953
|
+
method: "GET"
|
|
40954
|
+
};
|
|
40955
|
+
}
|
|
40956
|
+
return {
|
|
40957
|
+
method: methodPathMatch[1].toUpperCase(),
|
|
40958
|
+
path: methodPathMatch[2]
|
|
40959
|
+
};
|
|
40960
|
+
}
|
|
40961
|
+
function getPaths(document) {
|
|
40962
|
+
const rawPaths = document.paths;
|
|
40963
|
+
return isRecord2(rawPaths) ? rawPaths : {};
|
|
40964
|
+
}
|
|
40965
|
+
function getEntities(document) {
|
|
40966
|
+
const components = isRecord2(document.components) ? document.components : null;
|
|
40967
|
+
if (components && isRecord2(components.schemas)) {
|
|
40968
|
+
return components.schemas;
|
|
40969
|
+
}
|
|
40970
|
+
const definitions = document.definitions;
|
|
40971
|
+
if (isRecord2(definitions)) {
|
|
40972
|
+
return definitions;
|
|
40973
|
+
}
|
|
40974
|
+
return {};
|
|
40975
|
+
}
|
|
40976
|
+
function extractNamespaces(paths) {
|
|
40977
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
40978
|
+
for (const path3 of Object.keys(paths)) {
|
|
40979
|
+
const segments = path3.split("/").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
40980
|
+
if (segments.length === 0) {
|
|
40981
|
+
continue;
|
|
40982
|
+
}
|
|
40983
|
+
const namespace = segments[0] === "v1" ? segments[1] : segments[0];
|
|
40984
|
+
if (namespace) {
|
|
40985
|
+
namespaces.add(`/v1/${namespace}`);
|
|
40986
|
+
}
|
|
40987
|
+
}
|
|
40988
|
+
return Array.from(namespaces.values()).sort((left, right) => left.localeCompare(right));
|
|
40989
|
+
}
|
|
40990
|
+
function getPathOperation(pathItem, method) {
|
|
40991
|
+
if (!isRecord2(pathItem)) {
|
|
40992
|
+
return null;
|
|
40993
|
+
}
|
|
40994
|
+
const normalizedMethod = method.toLowerCase();
|
|
40995
|
+
const operation = pathItem[normalizedMethod];
|
|
40996
|
+
return isRecord2(operation) ? operation : null;
|
|
40997
|
+
}
|
|
40998
|
+
function toEndpointMethodEntries(paths, pathFilter) {
|
|
40999
|
+
const entries = [];
|
|
41000
|
+
const sortedPaths = Object.keys(paths).filter(pathFilter).sort((left, right) => left.localeCompare(right));
|
|
41001
|
+
for (const path3 of sortedPaths) {
|
|
41002
|
+
const pathItem = paths[path3];
|
|
41003
|
+
if (!isRecord2(pathItem)) {
|
|
41004
|
+
continue;
|
|
41005
|
+
}
|
|
41006
|
+
for (const method of SUPPORTED_HTTP_METHODS2) {
|
|
41007
|
+
const operation = getPathOperation(pathItem, method);
|
|
41008
|
+
if (!operation) {
|
|
41009
|
+
continue;
|
|
41010
|
+
}
|
|
41011
|
+
const descriptionValue = operation.description;
|
|
41012
|
+
const summaryValue = operation.summary;
|
|
41013
|
+
const description = typeof descriptionValue === "string" ? descriptionValue : typeof summaryValue === "string" ? summaryValue : void 0;
|
|
41014
|
+
entries.push({
|
|
41015
|
+
path: toOutputPath(path3),
|
|
41016
|
+
method,
|
|
41017
|
+
description
|
|
41018
|
+
});
|
|
41019
|
+
}
|
|
41020
|
+
}
|
|
41021
|
+
return entries;
|
|
41022
|
+
}
|
|
41023
|
+
function parseOpenApiDocument(raw) {
|
|
41024
|
+
let parsed;
|
|
41025
|
+
try {
|
|
41026
|
+
parsed = JSON.parse(raw);
|
|
41027
|
+
} catch (error48) {
|
|
41028
|
+
throw new UserInputError("Stored OpenAPI spec is invalid JSON. Run 'docyrus discover api' to re-download.", {
|
|
41029
|
+
cause: error48
|
|
41030
|
+
});
|
|
41031
|
+
}
|
|
41032
|
+
if (!isRecord2(parsed)) {
|
|
41033
|
+
throw new UserInputError("Stored OpenAPI spec must be a JSON object. Run 'docyrus discover api' to re-download.");
|
|
41034
|
+
}
|
|
41035
|
+
return parsed;
|
|
41036
|
+
}
|
|
41037
|
+
async function loadOpenApiSpec(dependencies, tenantId) {
|
|
41038
|
+
let filePath = dependencies.tenantOpenApiService.getTenantOpenApiFilePath(tenantId);
|
|
41039
|
+
let downloaded = false;
|
|
41040
|
+
let sourceUrl;
|
|
41041
|
+
let content;
|
|
41042
|
+
try {
|
|
41043
|
+
content = await (0, import_promises3.readFile)(filePath, "utf8");
|
|
41044
|
+
} catch (error48) {
|
|
41045
|
+
if (!isEnoentError(error48)) {
|
|
41046
|
+
throw new UserInputError("Failed to read downloaded OpenAPI spec file.", {
|
|
41047
|
+
filePath,
|
|
41048
|
+
cause: error48
|
|
41049
|
+
});
|
|
41050
|
+
}
|
|
41051
|
+
const downloadResult = await dependencies.tenantOpenApiService.downloadTenantOpenApi(tenantId);
|
|
41052
|
+
downloaded = true;
|
|
41053
|
+
sourceUrl = downloadResult.sourceUrl;
|
|
41054
|
+
filePath = downloadResult.filePath;
|
|
41055
|
+
content = await (0, import_promises3.readFile)(filePath, "utf8");
|
|
41056
|
+
}
|
|
41057
|
+
return {
|
|
41058
|
+
filePath,
|
|
41059
|
+
downloaded,
|
|
41060
|
+
sourceUrl,
|
|
41061
|
+
document: parseOpenApiDocument(content)
|
|
41062
|
+
};
|
|
41063
|
+
}
|
|
41064
|
+
async function withActiveTenantSpec(dependencies) {
|
|
41065
|
+
const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
|
|
41066
|
+
const activeProfile = await dependencies.authStore.getActiveProfile(apiBaseUrl);
|
|
41067
|
+
if (!activeProfile) {
|
|
41068
|
+
throw new AuthSessionError("No active session found. Run 'docyrus auth login'.");
|
|
41069
|
+
}
|
|
41070
|
+
const spec = await loadOpenApiSpec(dependencies, activeProfile.tenantId);
|
|
41071
|
+
return {
|
|
41072
|
+
apiBaseUrl,
|
|
41073
|
+
activeProfile,
|
|
41074
|
+
spec
|
|
41075
|
+
};
|
|
41076
|
+
}
|
|
40755
41077
|
function createDiscoverCli(dependencies) {
|
|
40756
41078
|
const discoverCli = Cli_exports.create("discover", {
|
|
40757
41079
|
description: "Discovery commands",
|
|
@@ -40778,6 +41100,154 @@ function createDiscoverCli(dependencies) {
|
|
|
40778
41100
|
});
|
|
40779
41101
|
}
|
|
40780
41102
|
});
|
|
41103
|
+
discoverCli.command("namespaces", {
|
|
41104
|
+
description: "List API namespaces from active tenant OpenAPI spec",
|
|
41105
|
+
run: async () => {
|
|
41106
|
+
const { apiBaseUrl, spec } = await withActiveTenantSpec(dependencies);
|
|
41107
|
+
const namespaces = extractNamespaces(getPaths(spec.document));
|
|
41108
|
+
return await injectContext({
|
|
41109
|
+
apiBaseUrl,
|
|
41110
|
+
authStore: dependencies.authStore,
|
|
41111
|
+
payload: {
|
|
41112
|
+
namespaces,
|
|
41113
|
+
count: namespaces.length,
|
|
41114
|
+
specFilePath: spec.filePath,
|
|
41115
|
+
downloaded: spec.downloaded,
|
|
41116
|
+
sourceUrl: spec.sourceUrl
|
|
41117
|
+
}
|
|
41118
|
+
});
|
|
41119
|
+
}
|
|
41120
|
+
});
|
|
41121
|
+
discoverCli.command("path", {
|
|
41122
|
+
description: "List endpoints with method and description for matching path prefix",
|
|
41123
|
+
args: external_exports.object({
|
|
41124
|
+
prefix: external_exports.string().min(1).describe("Path prefix, e.g. /v1/users")
|
|
41125
|
+
}),
|
|
41126
|
+
run: async (context) => {
|
|
41127
|
+
const { apiBaseUrl, spec } = await withActiveTenantSpec(dependencies);
|
|
41128
|
+
const paths = getPaths(spec.document);
|
|
41129
|
+
const candidates = buildPathCandidates(context.args.prefix);
|
|
41130
|
+
const endpoints = toEndpointMethodEntries(
|
|
41131
|
+
paths,
|
|
41132
|
+
(path3) => candidates.some((candidate) => path3.startsWith(candidate))
|
|
41133
|
+
);
|
|
41134
|
+
return await injectContext({
|
|
41135
|
+
apiBaseUrl,
|
|
41136
|
+
authStore: dependencies.authStore,
|
|
41137
|
+
payload: {
|
|
41138
|
+
prefix: context.args.prefix,
|
|
41139
|
+
normalizedPrefixes: candidates,
|
|
41140
|
+
endpoints,
|
|
41141
|
+
count: endpoints.length,
|
|
41142
|
+
specFilePath: spec.filePath,
|
|
41143
|
+
downloaded: spec.downloaded,
|
|
41144
|
+
sourceUrl: spec.sourceUrl
|
|
41145
|
+
}
|
|
41146
|
+
});
|
|
41147
|
+
}
|
|
41148
|
+
});
|
|
41149
|
+
discoverCli.command("endpoint", {
|
|
41150
|
+
description: "Return full endpoint object for a path and HTTP method",
|
|
41151
|
+
args: external_exports.object({
|
|
41152
|
+
selector: external_exports.string().min(1).describe("Endpoint selector, e.g. /v1/users/me or [PUT]/v1/users/me/photo")
|
|
41153
|
+
}),
|
|
41154
|
+
run: async (context) => {
|
|
41155
|
+
const { apiBaseUrl, spec } = await withActiveTenantSpec(dependencies);
|
|
41156
|
+
const paths = getPaths(spec.document);
|
|
41157
|
+
const selector = parseEndpointSelector(context.args.selector);
|
|
41158
|
+
const candidates = buildPathCandidates(selector.path);
|
|
41159
|
+
const resolvedPath = candidates.find((candidate) => candidate in paths);
|
|
41160
|
+
if (!resolvedPath) {
|
|
41161
|
+
throw new UserInputError(`Endpoint '${selector.path}' was not found in downloaded OpenAPI spec.`);
|
|
41162
|
+
}
|
|
41163
|
+
if (!SUPPORTED_HTTP_METHODS2.includes(selector.method)) {
|
|
41164
|
+
throw new UserInputError(`Unsupported HTTP method '${selector.method}'.`);
|
|
41165
|
+
}
|
|
41166
|
+
const operation = getPathOperation(paths[resolvedPath], selector.method);
|
|
41167
|
+
if (!operation) {
|
|
41168
|
+
throw new UserInputError(
|
|
41169
|
+
`Method '${selector.method}' is not available for endpoint '${toOutputPath(resolvedPath)}'.`
|
|
41170
|
+
);
|
|
41171
|
+
}
|
|
41172
|
+
return await injectContext({
|
|
41173
|
+
apiBaseUrl,
|
|
41174
|
+
authStore: dependencies.authStore,
|
|
41175
|
+
payload: {
|
|
41176
|
+
requestedSelector: context.args.selector,
|
|
41177
|
+
method: selector.method,
|
|
41178
|
+
resolvedPath: toOutputPath(resolvedPath),
|
|
41179
|
+
endpoint: operation,
|
|
41180
|
+
specFilePath: spec.filePath,
|
|
41181
|
+
downloaded: spec.downloaded,
|
|
41182
|
+
sourceUrl: spec.sourceUrl
|
|
41183
|
+
}
|
|
41184
|
+
});
|
|
41185
|
+
}
|
|
41186
|
+
});
|
|
41187
|
+
discoverCli.command("entity", {
|
|
41188
|
+
description: "Return full entity object by name",
|
|
41189
|
+
args: external_exports.object({
|
|
41190
|
+
name: external_exports.string().min(1).describe("Entity name, e.g. UserEntity")
|
|
41191
|
+
}),
|
|
41192
|
+
run: async (context) => {
|
|
41193
|
+
const { apiBaseUrl, spec } = await withActiveTenantSpec(dependencies);
|
|
41194
|
+
const entities = getEntities(spec.document);
|
|
41195
|
+
const requestedName = context.args.name.trim();
|
|
41196
|
+
if (!(requestedName in entities)) {
|
|
41197
|
+
throw new UserInputError(`Entity '${context.args.name}' was not found in downloaded OpenAPI spec.`);
|
|
41198
|
+
}
|
|
41199
|
+
return await injectContext({
|
|
41200
|
+
apiBaseUrl,
|
|
41201
|
+
authStore: dependencies.authStore,
|
|
41202
|
+
payload: {
|
|
41203
|
+
entityName: requestedName,
|
|
41204
|
+
entity: entities[requestedName],
|
|
41205
|
+
specFilePath: spec.filePath,
|
|
41206
|
+
downloaded: spec.downloaded,
|
|
41207
|
+
sourceUrl: spec.sourceUrl
|
|
41208
|
+
}
|
|
41209
|
+
});
|
|
41210
|
+
}
|
|
41211
|
+
});
|
|
41212
|
+
discoverCli.command("search", {
|
|
41213
|
+
description: "Search endpoint paths and entity names (endpoint results include method and description)",
|
|
41214
|
+
args: external_exports.object({
|
|
41215
|
+
query: external_exports.string().min(1).describe("One or more comma-separated search strings")
|
|
41216
|
+
}),
|
|
41217
|
+
run: async (context) => {
|
|
41218
|
+
const { apiBaseUrl, spec } = await withActiveTenantSpec(dependencies);
|
|
41219
|
+
const terms = context.args.query.split(",").map((term) => term.trim()).filter((term) => term.length > 0);
|
|
41220
|
+
if (terms.length === 0) {
|
|
41221
|
+
throw new UserInputError("Provide at least one non-empty search term.");
|
|
41222
|
+
}
|
|
41223
|
+
const entityNames = Object.keys(getEntities(spec.document));
|
|
41224
|
+
const pathMap = getPaths(spec.document);
|
|
41225
|
+
const results = terms.map((term) => {
|
|
41226
|
+
const loweredTerm = term.toLowerCase();
|
|
41227
|
+
const matchingEndpoints = toEndpointMethodEntries(
|
|
41228
|
+
pathMap,
|
|
41229
|
+
(path3) => path3.toLowerCase().includes(loweredTerm)
|
|
41230
|
+
);
|
|
41231
|
+
const matchingEntities = entityNames.filter((entityName) => entityName.toLowerCase().includes(loweredTerm));
|
|
41232
|
+
return {
|
|
41233
|
+
term,
|
|
41234
|
+
endpoints: matchingEndpoints,
|
|
41235
|
+
entityNames: matchingEntities.sort((left, right) => left.localeCompare(right))
|
|
41236
|
+
};
|
|
41237
|
+
});
|
|
41238
|
+
return await injectContext({
|
|
41239
|
+
apiBaseUrl,
|
|
41240
|
+
authStore: dependencies.authStore,
|
|
41241
|
+
payload: {
|
|
41242
|
+
terms,
|
|
41243
|
+
results,
|
|
41244
|
+
specFilePath: spec.filePath,
|
|
41245
|
+
downloaded: spec.downloaded,
|
|
41246
|
+
sourceUrl: spec.sourceUrl
|
|
41247
|
+
}
|
|
41248
|
+
});
|
|
41249
|
+
}
|
|
41250
|
+
});
|
|
40781
41251
|
return discoverCli;
|
|
40782
41252
|
}
|
|
40783
41253
|
|
|
@@ -40819,6 +41289,952 @@ function createEnvCli(dependencies) {
|
|
|
40819
41289
|
return envCli;
|
|
40820
41290
|
}
|
|
40821
41291
|
|
|
41292
|
+
// src/services/studioPayload.ts
|
|
41293
|
+
var import_promises4 = require("node:fs/promises");
|
|
41294
|
+
var import_node_path5 = require("node:path");
|
|
41295
|
+
async function readStdinText2() {
|
|
41296
|
+
if (process.stdin.isTTY) {
|
|
41297
|
+
return "";
|
|
41298
|
+
}
|
|
41299
|
+
const chunks = [];
|
|
41300
|
+
for await (const chunk of process.stdin) {
|
|
41301
|
+
if (typeof chunk === "string") {
|
|
41302
|
+
chunks.push(Buffer.from(chunk));
|
|
41303
|
+
} else {
|
|
41304
|
+
chunks.push(Buffer.from(chunk));
|
|
41305
|
+
}
|
|
41306
|
+
}
|
|
41307
|
+
return Buffer.concat(chunks).toString("utf8").trim();
|
|
41308
|
+
}
|
|
41309
|
+
function isRecord3(value) {
|
|
41310
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
41311
|
+
}
|
|
41312
|
+
async function readStudioWriteInput(params) {
|
|
41313
|
+
const {
|
|
41314
|
+
data,
|
|
41315
|
+
fromFile,
|
|
41316
|
+
readStdin = readStdinText2,
|
|
41317
|
+
readFileFn = async (path3, encoding) => await (0, import_promises4.readFile)(path3, encoding)
|
|
41318
|
+
} = params;
|
|
41319
|
+
const trimmedData = data?.trim();
|
|
41320
|
+
const trimmedFromFile = fromFile?.trim();
|
|
41321
|
+
if (trimmedData && trimmedFromFile) {
|
|
41322
|
+
throw new UserInputError("Provide either --data or --from-file, not both.");
|
|
41323
|
+
}
|
|
41324
|
+
if (trimmedFromFile) {
|
|
41325
|
+
const extension = (0, import_node_path5.extname)(trimmedFromFile).toLowerCase();
|
|
41326
|
+
if (extension && extension !== ".json") {
|
|
41327
|
+
throw new UserInputError("Studio commands support only JSON files in --from-file.");
|
|
41328
|
+
}
|
|
41329
|
+
let content;
|
|
41330
|
+
try {
|
|
41331
|
+
content = await readFileFn(trimmedFromFile, "utf8");
|
|
41332
|
+
} catch (error48) {
|
|
41333
|
+
throw new UserInputError(`Unable to read file '${trimmedFromFile}'.`, {
|
|
41334
|
+
cause: error48
|
|
41335
|
+
});
|
|
41336
|
+
}
|
|
41337
|
+
return parseJsonData(content, "--from-file");
|
|
41338
|
+
}
|
|
41339
|
+
if (trimmedData) {
|
|
41340
|
+
return parseJsonData(trimmedData, "--data");
|
|
41341
|
+
}
|
|
41342
|
+
const stdinContent = (await readStdin()).trim();
|
|
41343
|
+
if (!stdinContent) {
|
|
41344
|
+
return {};
|
|
41345
|
+
}
|
|
41346
|
+
return parseJsonData(stdinContent, "stdin");
|
|
41347
|
+
}
|
|
41348
|
+
function ensureObjectPayload(payload, label) {
|
|
41349
|
+
if (!isRecord3(payload)) {
|
|
41350
|
+
throw new UserInputError(`${label} expects a JSON object payload.`);
|
|
41351
|
+
}
|
|
41352
|
+
return payload;
|
|
41353
|
+
}
|
|
41354
|
+
function mergeObjectWithFlags(basePayload, overrides) {
|
|
41355
|
+
const merged = {
|
|
41356
|
+
...basePayload
|
|
41357
|
+
};
|
|
41358
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
41359
|
+
if (value === void 0) {
|
|
41360
|
+
continue;
|
|
41361
|
+
}
|
|
41362
|
+
merged[key] = value;
|
|
41363
|
+
}
|
|
41364
|
+
return merged;
|
|
41365
|
+
}
|
|
41366
|
+
function normalizeBatchPayload(payload, key) {
|
|
41367
|
+
if (Array.isArray(payload)) {
|
|
41368
|
+
return {
|
|
41369
|
+
[key]: payload
|
|
41370
|
+
};
|
|
41371
|
+
}
|
|
41372
|
+
if (isRecord3(payload)) {
|
|
41373
|
+
if (key in payload) {
|
|
41374
|
+
return payload;
|
|
41375
|
+
}
|
|
41376
|
+
if (Object.keys(payload).length === 0) {
|
|
41377
|
+
throw new UserInputError(`Batch payload is required. Provide --data/--from-file with '${key}'.`);
|
|
41378
|
+
}
|
|
41379
|
+
}
|
|
41380
|
+
throw new UserInputError(`Batch payload must be an array or object containing '${key}'.`);
|
|
41381
|
+
}
|
|
41382
|
+
|
|
41383
|
+
// src/services/studioResolver.ts
|
|
41384
|
+
function isRecord4(value) {
|
|
41385
|
+
return typeof value === "object" && value !== null;
|
|
41386
|
+
}
|
|
41387
|
+
function extractString(record2, key) {
|
|
41388
|
+
const value = record2[key];
|
|
41389
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
41390
|
+
}
|
|
41391
|
+
function extractArray(payload) {
|
|
41392
|
+
if (Array.isArray(payload)) {
|
|
41393
|
+
return payload.filter((item) => isRecord4(item));
|
|
41394
|
+
}
|
|
41395
|
+
if (isRecord4(payload) && Array.isArray(payload.data)) {
|
|
41396
|
+
return payload.data.filter((item) => isRecord4(item));
|
|
41397
|
+
}
|
|
41398
|
+
return [];
|
|
41399
|
+
}
|
|
41400
|
+
function ensureExclusiveSelector(label, idValue, slugValue) {
|
|
41401
|
+
if (idValue && slugValue) {
|
|
41402
|
+
throw new UserInputError(`Provide either --${label}Id or --${label}Slug, not both.`);
|
|
41403
|
+
}
|
|
41404
|
+
if (!idValue && !slugValue) {
|
|
41405
|
+
throw new UserInputError(`Provide --${label}Id or --${label}Slug.`);
|
|
41406
|
+
}
|
|
41407
|
+
}
|
|
41408
|
+
function normalizeOptional(value) {
|
|
41409
|
+
const trimmed = value?.trim();
|
|
41410
|
+
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
41411
|
+
}
|
|
41412
|
+
function resolveBySlug(label, items, slug) {
|
|
41413
|
+
const matches = items.filter((item) => extractString(item, "slug") === slug);
|
|
41414
|
+
if (matches.length === 0) {
|
|
41415
|
+
throw new UserInputError(`${label} slug '${slug}' was not found.`);
|
|
41416
|
+
}
|
|
41417
|
+
if (matches.length > 1) {
|
|
41418
|
+
const matchingIds = matches.map((item) => extractString(item, "id")).filter((id) => Boolean(id));
|
|
41419
|
+
throw new UserInputError(`${label} slug '${slug}' is ambiguous. Matching IDs: ${matchingIds.join(", ")}`);
|
|
41420
|
+
}
|
|
41421
|
+
const matchId = extractString(matches[0], "id");
|
|
41422
|
+
if (!matchId) {
|
|
41423
|
+
throw new UserInputError(`${label} slug '${slug}' resolved to an invalid item without id.`);
|
|
41424
|
+
}
|
|
41425
|
+
return matchId;
|
|
41426
|
+
}
|
|
41427
|
+
var StudioResolver = class {
|
|
41428
|
+
constructor(apiClient) {
|
|
41429
|
+
this.apiClient = apiClient;
|
|
41430
|
+
}
|
|
41431
|
+
#appsCache = /* @__PURE__ */ new Map();
|
|
41432
|
+
#dataSourcesByAppId = /* @__PURE__ */ new Map();
|
|
41433
|
+
#fieldsByAppAndDataSource = /* @__PURE__ */ new Map();
|
|
41434
|
+
async resolveAppId(options) {
|
|
41435
|
+
const appId = normalizeOptional(options.appId);
|
|
41436
|
+
const appSlug = normalizeOptional(options.appSlug);
|
|
41437
|
+
ensureExclusiveSelector("app", appId, appSlug);
|
|
41438
|
+
if (appId) {
|
|
41439
|
+
return appId;
|
|
41440
|
+
}
|
|
41441
|
+
const apps = await this.#getApps();
|
|
41442
|
+
return resolveBySlug("App", apps, appSlug);
|
|
41443
|
+
}
|
|
41444
|
+
async resolveDataSourceId(options) {
|
|
41445
|
+
const dataSourceId = normalizeOptional(options.dataSourceId);
|
|
41446
|
+
const dataSourceSlug = normalizeOptional(options.dataSourceSlug);
|
|
41447
|
+
ensureExclusiveSelector("dataSource", dataSourceId, dataSourceSlug);
|
|
41448
|
+
if (dataSourceId) {
|
|
41449
|
+
return dataSourceId;
|
|
41450
|
+
}
|
|
41451
|
+
const dataSources = await this.getDataSourcesForApp(options.appId);
|
|
41452
|
+
return resolveBySlug("Data source", dataSources, dataSourceSlug);
|
|
41453
|
+
}
|
|
41454
|
+
async resolveFieldId(options) {
|
|
41455
|
+
const fieldId = normalizeOptional(options.fieldId);
|
|
41456
|
+
const fieldSlug = normalizeOptional(options.fieldSlug);
|
|
41457
|
+
ensureExclusiveSelector("field", fieldId, fieldSlug);
|
|
41458
|
+
if (fieldId) {
|
|
41459
|
+
return fieldId;
|
|
41460
|
+
}
|
|
41461
|
+
const fields = await this.getFieldsForDataSource(options.appId, options.dataSourceId);
|
|
41462
|
+
return resolveBySlug("Field", fields, fieldSlug);
|
|
41463
|
+
}
|
|
41464
|
+
async getDataSourcesForApp(appId) {
|
|
41465
|
+
const cacheKey = appId;
|
|
41466
|
+
const cached2 = this.#dataSourcesByAppId.get(cacheKey);
|
|
41467
|
+
if (cached2) {
|
|
41468
|
+
return cached2;
|
|
41469
|
+
}
|
|
41470
|
+
const response = await this.apiClient.request({
|
|
41471
|
+
method: "GET",
|
|
41472
|
+
path: `/dev/apps/${appId}/data-sources`
|
|
41473
|
+
});
|
|
41474
|
+
const resolved = extractArray(response.data);
|
|
41475
|
+
this.#dataSourcesByAppId.set(cacheKey, resolved);
|
|
41476
|
+
return resolved;
|
|
41477
|
+
}
|
|
41478
|
+
async getFieldsForDataSource(appId, dataSourceId) {
|
|
41479
|
+
const cacheKey = `${appId}::${dataSourceId}`;
|
|
41480
|
+
const cached2 = this.#fieldsByAppAndDataSource.get(cacheKey);
|
|
41481
|
+
if (cached2) {
|
|
41482
|
+
return cached2;
|
|
41483
|
+
}
|
|
41484
|
+
const response = await this.apiClient.request({
|
|
41485
|
+
method: "GET",
|
|
41486
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields`
|
|
41487
|
+
});
|
|
41488
|
+
const resolved = extractArray(response.data);
|
|
41489
|
+
this.#fieldsByAppAndDataSource.set(cacheKey, resolved);
|
|
41490
|
+
return resolved;
|
|
41491
|
+
}
|
|
41492
|
+
async #getApps() {
|
|
41493
|
+
const cacheKey = "all";
|
|
41494
|
+
const cached2 = this.#appsCache.get(cacheKey);
|
|
41495
|
+
if (cached2) {
|
|
41496
|
+
return cached2;
|
|
41497
|
+
}
|
|
41498
|
+
const response = await this.apiClient.request({
|
|
41499
|
+
method: "GET",
|
|
41500
|
+
path: "/dev/apps"
|
|
41501
|
+
});
|
|
41502
|
+
const resolved = extractArray(response.data);
|
|
41503
|
+
this.#appsCache.set(cacheKey, resolved);
|
|
41504
|
+
return resolved;
|
|
41505
|
+
}
|
|
41506
|
+
};
|
|
41507
|
+
|
|
41508
|
+
// src/commands/studioCommands.ts
|
|
41509
|
+
function parseOptionalJsonFlag(raw, source) {
|
|
41510
|
+
if (!raw || raw.trim().length === 0) {
|
|
41511
|
+
return void 0;
|
|
41512
|
+
}
|
|
41513
|
+
return parseJsonData(raw, source);
|
|
41514
|
+
}
|
|
41515
|
+
function wrapStudioPayload(apiBaseUrl, dependencies, payload) {
|
|
41516
|
+
return injectContext({
|
|
41517
|
+
apiBaseUrl,
|
|
41518
|
+
authStore: dependencies.authStore,
|
|
41519
|
+
payload
|
|
41520
|
+
});
|
|
41521
|
+
}
|
|
41522
|
+
async function getStudioRunContext(dependencies) {
|
|
41523
|
+
const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
|
|
41524
|
+
const apiClient = dependencies.createApiClient(apiBaseUrl);
|
|
41525
|
+
const resolver = new StudioResolver(apiClient);
|
|
41526
|
+
return {
|
|
41527
|
+
apiBaseUrl,
|
|
41528
|
+
apiClient,
|
|
41529
|
+
resolver
|
|
41530
|
+
};
|
|
41531
|
+
}
|
|
41532
|
+
function dataSourceFlags(options) {
|
|
41533
|
+
return {
|
|
41534
|
+
title: options.title,
|
|
41535
|
+
name: options.name,
|
|
41536
|
+
slug: options.slug,
|
|
41537
|
+
type: options.type,
|
|
41538
|
+
icon: options.icon,
|
|
41539
|
+
data_sharing: options.dataSharing,
|
|
41540
|
+
meta: parseOptionalJsonFlag(options.meta, "--meta")
|
|
41541
|
+
};
|
|
41542
|
+
}
|
|
41543
|
+
function fieldFlags(options) {
|
|
41544
|
+
return {
|
|
41545
|
+
name: options.name,
|
|
41546
|
+
slug: options.slug,
|
|
41547
|
+
type: options.type,
|
|
41548
|
+
read_only: options.readOnly,
|
|
41549
|
+
status: options.status,
|
|
41550
|
+
default_value: options.defaultValue,
|
|
41551
|
+
relation_data_source_id: options.relationDataSourceId,
|
|
41552
|
+
sort_order: options.sortOrder,
|
|
41553
|
+
tenant_enum_set_id: options.tenantEnumSetId,
|
|
41554
|
+
options: parseOptionalJsonFlag(options.options, "--options"),
|
|
41555
|
+
validations: parseOptionalJsonFlag(options.validations, "--validations")
|
|
41556
|
+
};
|
|
41557
|
+
}
|
|
41558
|
+
function requireNonEmptyObject(payload, label) {
|
|
41559
|
+
if (Object.keys(payload).length === 0) {
|
|
41560
|
+
throw new UserInputError(`${label} payload is empty. Provide flags, --data, or --from-file.`);
|
|
41561
|
+
}
|
|
41562
|
+
}
|
|
41563
|
+
function createStudioCli(dependencies) {
|
|
41564
|
+
const studioCli = Cli_exports.create("studio", {
|
|
41565
|
+
description: "Studio (dev app data source CRUD) commands",
|
|
41566
|
+
env: EnvSchema
|
|
41567
|
+
});
|
|
41568
|
+
studioCli.command("list-data-sources", {
|
|
41569
|
+
description: "List data sources for an app",
|
|
41570
|
+
options: external_exports.object({
|
|
41571
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41572
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41573
|
+
expand: external_exports.string().optional().describe("Optional comma-separated expansions, e.g. fields")
|
|
41574
|
+
}),
|
|
41575
|
+
run: async (context) => {
|
|
41576
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41577
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41578
|
+
appId: context.options.appId,
|
|
41579
|
+
appSlug: context.options.appSlug
|
|
41580
|
+
});
|
|
41581
|
+
const response = await studio.apiClient.request({
|
|
41582
|
+
method: "GET",
|
|
41583
|
+
path: `/dev/apps/${appId}/data-sources`,
|
|
41584
|
+
query: {
|
|
41585
|
+
expand: context.options.expand
|
|
41586
|
+
}
|
|
41587
|
+
});
|
|
41588
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41589
|
+
}
|
|
41590
|
+
});
|
|
41591
|
+
studioCli.command("get-data-source", {
|
|
41592
|
+
description: "Get a single data source",
|
|
41593
|
+
options: external_exports.object({
|
|
41594
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41595
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41596
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
41597
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug")
|
|
41598
|
+
}),
|
|
41599
|
+
run: async (context) => {
|
|
41600
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41601
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41602
|
+
appId: context.options.appId,
|
|
41603
|
+
appSlug: context.options.appSlug
|
|
41604
|
+
});
|
|
41605
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
41606
|
+
appId,
|
|
41607
|
+
dataSourceId: context.options.dataSourceId,
|
|
41608
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
41609
|
+
});
|
|
41610
|
+
const response = await studio.apiClient.request({
|
|
41611
|
+
method: "GET",
|
|
41612
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}`
|
|
41613
|
+
});
|
|
41614
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41615
|
+
}
|
|
41616
|
+
});
|
|
41617
|
+
studioCli.command("create-data-source", {
|
|
41618
|
+
description: "Create a data source",
|
|
41619
|
+
options: external_exports.object({
|
|
41620
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41621
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41622
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
41623
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file"),
|
|
41624
|
+
title: external_exports.string().optional().describe("Data source title"),
|
|
41625
|
+
name: external_exports.string().optional().describe("Data source name"),
|
|
41626
|
+
slug: external_exports.string().optional().describe("Data source slug"),
|
|
41627
|
+
type: external_exports.string().optional().describe("Data source type"),
|
|
41628
|
+
icon: external_exports.string().optional().describe("Icon"),
|
|
41629
|
+
dataSharing: external_exports.string().optional().describe("Data sharing value"),
|
|
41630
|
+
meta: external_exports.string().optional().describe("JSON meta payload")
|
|
41631
|
+
}),
|
|
41632
|
+
run: async (context) => {
|
|
41633
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41634
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41635
|
+
appId: context.options.appId,
|
|
41636
|
+
appSlug: context.options.appSlug
|
|
41637
|
+
});
|
|
41638
|
+
const basePayload = ensureObjectPayload(
|
|
41639
|
+
await readStudioWriteInput({
|
|
41640
|
+
data: context.options.data,
|
|
41641
|
+
fromFile: context.options.fromFile
|
|
41642
|
+
}),
|
|
41643
|
+
"create-data-source"
|
|
41644
|
+
);
|
|
41645
|
+
const payload = mergeObjectWithFlags(basePayload, dataSourceFlags(context.options));
|
|
41646
|
+
requireNonEmptyObject(payload, "create-data-source");
|
|
41647
|
+
const response = await studio.apiClient.request({
|
|
41648
|
+
method: "POST",
|
|
41649
|
+
path: `/dev/apps/${appId}/data-sources`,
|
|
41650
|
+
body: payload
|
|
41651
|
+
});
|
|
41652
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41653
|
+
}
|
|
41654
|
+
});
|
|
41655
|
+
studioCli.command("update-data-source", {
|
|
41656
|
+
description: "Update a data source",
|
|
41657
|
+
options: external_exports.object({
|
|
41658
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41659
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41660
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
41661
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
41662
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
41663
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file"),
|
|
41664
|
+
title: external_exports.string().optional().describe("Data source title"),
|
|
41665
|
+
name: external_exports.string().optional().describe("Data source name"),
|
|
41666
|
+
slug: external_exports.string().optional().describe("Data source slug"),
|
|
41667
|
+
type: external_exports.string().optional().describe("Data source type"),
|
|
41668
|
+
icon: external_exports.string().optional().describe("Icon"),
|
|
41669
|
+
dataSharing: external_exports.string().optional().describe("Data sharing value"),
|
|
41670
|
+
meta: external_exports.string().optional().describe("JSON meta payload")
|
|
41671
|
+
}),
|
|
41672
|
+
run: async (context) => {
|
|
41673
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41674
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41675
|
+
appId: context.options.appId,
|
|
41676
|
+
appSlug: context.options.appSlug
|
|
41677
|
+
});
|
|
41678
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
41679
|
+
appId,
|
|
41680
|
+
dataSourceId: context.options.dataSourceId,
|
|
41681
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
41682
|
+
});
|
|
41683
|
+
const basePayload = ensureObjectPayload(
|
|
41684
|
+
await readStudioWriteInput({
|
|
41685
|
+
data: context.options.data,
|
|
41686
|
+
fromFile: context.options.fromFile
|
|
41687
|
+
}),
|
|
41688
|
+
"update-data-source"
|
|
41689
|
+
);
|
|
41690
|
+
const payload = mergeObjectWithFlags(basePayload, dataSourceFlags(context.options));
|
|
41691
|
+
requireNonEmptyObject(payload, "update-data-source");
|
|
41692
|
+
const response = await studio.apiClient.request({
|
|
41693
|
+
method: "PATCH",
|
|
41694
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}`,
|
|
41695
|
+
body: payload
|
|
41696
|
+
});
|
|
41697
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41698
|
+
}
|
|
41699
|
+
});
|
|
41700
|
+
studioCli.command("delete-data-source", {
|
|
41701
|
+
description: "Delete a data source",
|
|
41702
|
+
options: external_exports.object({
|
|
41703
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41704
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41705
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
41706
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug")
|
|
41707
|
+
}),
|
|
41708
|
+
run: async (context) => {
|
|
41709
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41710
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41711
|
+
appId: context.options.appId,
|
|
41712
|
+
appSlug: context.options.appSlug
|
|
41713
|
+
});
|
|
41714
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
41715
|
+
appId,
|
|
41716
|
+
dataSourceId: context.options.dataSourceId,
|
|
41717
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
41718
|
+
});
|
|
41719
|
+
const response = await studio.apiClient.request({
|
|
41720
|
+
method: "DELETE",
|
|
41721
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}`
|
|
41722
|
+
});
|
|
41723
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41724
|
+
}
|
|
41725
|
+
});
|
|
41726
|
+
studioCli.command("bulk-create-data-sources", {
|
|
41727
|
+
description: "Bulk create data sources",
|
|
41728
|
+
options: external_exports.object({
|
|
41729
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41730
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41731
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
41732
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file")
|
|
41733
|
+
}),
|
|
41734
|
+
run: async (context) => {
|
|
41735
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41736
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41737
|
+
appId: context.options.appId,
|
|
41738
|
+
appSlug: context.options.appSlug
|
|
41739
|
+
});
|
|
41740
|
+
const batchPayload = normalizeBatchPayload(
|
|
41741
|
+
await readStudioWriteInput({
|
|
41742
|
+
data: context.options.data,
|
|
41743
|
+
fromFile: context.options.fromFile
|
|
41744
|
+
}),
|
|
41745
|
+
"dataSources"
|
|
41746
|
+
);
|
|
41747
|
+
const response = await studio.apiClient.request({
|
|
41748
|
+
method: "POST",
|
|
41749
|
+
path: `/dev/apps/${appId}/data-sources/bulk`,
|
|
41750
|
+
body: batchPayload
|
|
41751
|
+
});
|
|
41752
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41753
|
+
}
|
|
41754
|
+
});
|
|
41755
|
+
studioCli.command("list-fields", {
|
|
41756
|
+
description: "List fields for a data source",
|
|
41757
|
+
options: external_exports.object({
|
|
41758
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41759
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41760
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
41761
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug")
|
|
41762
|
+
}),
|
|
41763
|
+
run: async (context) => {
|
|
41764
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41765
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41766
|
+
appId: context.options.appId,
|
|
41767
|
+
appSlug: context.options.appSlug
|
|
41768
|
+
});
|
|
41769
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
41770
|
+
appId,
|
|
41771
|
+
dataSourceId: context.options.dataSourceId,
|
|
41772
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
41773
|
+
});
|
|
41774
|
+
const response = await studio.apiClient.request({
|
|
41775
|
+
method: "GET",
|
|
41776
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields`
|
|
41777
|
+
});
|
|
41778
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41779
|
+
}
|
|
41780
|
+
});
|
|
41781
|
+
studioCli.command("get-field", {
|
|
41782
|
+
description: "Get a single field",
|
|
41783
|
+
options: external_exports.object({
|
|
41784
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41785
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41786
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
41787
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
41788
|
+
fieldId: external_exports.string().optional().describe("Field ID"),
|
|
41789
|
+
fieldSlug: external_exports.string().optional().describe("Field slug")
|
|
41790
|
+
}),
|
|
41791
|
+
run: async (context) => {
|
|
41792
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41793
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41794
|
+
appId: context.options.appId,
|
|
41795
|
+
appSlug: context.options.appSlug
|
|
41796
|
+
});
|
|
41797
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
41798
|
+
appId,
|
|
41799
|
+
dataSourceId: context.options.dataSourceId,
|
|
41800
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
41801
|
+
});
|
|
41802
|
+
const fieldId = await studio.resolver.resolveFieldId({
|
|
41803
|
+
appId,
|
|
41804
|
+
dataSourceId,
|
|
41805
|
+
fieldId: context.options.fieldId,
|
|
41806
|
+
fieldSlug: context.options.fieldSlug
|
|
41807
|
+
});
|
|
41808
|
+
const response = await studio.apiClient.request({
|
|
41809
|
+
method: "GET",
|
|
41810
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/${fieldId}`
|
|
41811
|
+
});
|
|
41812
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41813
|
+
}
|
|
41814
|
+
});
|
|
41815
|
+
studioCli.command("create-field", {
|
|
41816
|
+
description: "Create a field",
|
|
41817
|
+
options: external_exports.object({
|
|
41818
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41819
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41820
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
41821
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
41822
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
41823
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file"),
|
|
41824
|
+
name: external_exports.string().optional().describe("Field name"),
|
|
41825
|
+
slug: external_exports.string().optional().describe("Field slug"),
|
|
41826
|
+
type: external_exports.string().optional().describe("Field type"),
|
|
41827
|
+
readOnly: external_exports.boolean().optional().describe("Field read only"),
|
|
41828
|
+
status: external_exports.number().optional().describe("Field status"),
|
|
41829
|
+
defaultValue: external_exports.string().optional().describe("Default value"),
|
|
41830
|
+
relationDataSourceId: external_exports.string().optional().describe("Relation data source ID"),
|
|
41831
|
+
sortOrder: external_exports.number().optional().describe("Sort order"),
|
|
41832
|
+
tenantEnumSetId: external_exports.string().optional().describe("Tenant enum set ID"),
|
|
41833
|
+
options: external_exports.string().optional().describe("JSON options"),
|
|
41834
|
+
validations: external_exports.string().optional().describe("JSON validations")
|
|
41835
|
+
}),
|
|
41836
|
+
run: async (context) => {
|
|
41837
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41838
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41839
|
+
appId: context.options.appId,
|
|
41840
|
+
appSlug: context.options.appSlug
|
|
41841
|
+
});
|
|
41842
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
41843
|
+
appId,
|
|
41844
|
+
dataSourceId: context.options.dataSourceId,
|
|
41845
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
41846
|
+
});
|
|
41847
|
+
const basePayload = ensureObjectPayload(
|
|
41848
|
+
await readStudioWriteInput({
|
|
41849
|
+
data: context.options.data,
|
|
41850
|
+
fromFile: context.options.fromFile
|
|
41851
|
+
}),
|
|
41852
|
+
"create-field"
|
|
41853
|
+
);
|
|
41854
|
+
const payload = mergeObjectWithFlags(basePayload, fieldFlags(context.options));
|
|
41855
|
+
requireNonEmptyObject(payload, "create-field");
|
|
41856
|
+
const response = await studio.apiClient.request({
|
|
41857
|
+
method: "POST",
|
|
41858
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields`,
|
|
41859
|
+
body: payload
|
|
41860
|
+
});
|
|
41861
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41862
|
+
}
|
|
41863
|
+
});
|
|
41864
|
+
studioCli.command("update-field", {
|
|
41865
|
+
description: "Update a field",
|
|
41866
|
+
options: external_exports.object({
|
|
41867
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41868
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41869
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
41870
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
41871
|
+
fieldId: external_exports.string().optional().describe("Field ID"),
|
|
41872
|
+
fieldSlug: external_exports.string().optional().describe("Field slug"),
|
|
41873
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
41874
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file"),
|
|
41875
|
+
name: external_exports.string().optional().describe("Field name"),
|
|
41876
|
+
slug: external_exports.string().optional().describe("Field slug"),
|
|
41877
|
+
type: external_exports.string().optional().describe("Field type"),
|
|
41878
|
+
readOnly: external_exports.boolean().optional().describe("Field read only"),
|
|
41879
|
+
status: external_exports.number().optional().describe("Field status"),
|
|
41880
|
+
defaultValue: external_exports.string().optional().describe("Default value"),
|
|
41881
|
+
relationDataSourceId: external_exports.string().optional().describe("Relation data source ID"),
|
|
41882
|
+
sortOrder: external_exports.number().optional().describe("Sort order"),
|
|
41883
|
+
tenantEnumSetId: external_exports.string().optional().describe("Tenant enum set ID"),
|
|
41884
|
+
options: external_exports.string().optional().describe("JSON options"),
|
|
41885
|
+
validations: external_exports.string().optional().describe("JSON validations")
|
|
41886
|
+
}),
|
|
41887
|
+
run: async (context) => {
|
|
41888
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41889
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41890
|
+
appId: context.options.appId,
|
|
41891
|
+
appSlug: context.options.appSlug
|
|
41892
|
+
});
|
|
41893
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
41894
|
+
appId,
|
|
41895
|
+
dataSourceId: context.options.dataSourceId,
|
|
41896
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
41897
|
+
});
|
|
41898
|
+
const fieldId = await studio.resolver.resolveFieldId({
|
|
41899
|
+
appId,
|
|
41900
|
+
dataSourceId,
|
|
41901
|
+
fieldId: context.options.fieldId,
|
|
41902
|
+
fieldSlug: context.options.fieldSlug
|
|
41903
|
+
});
|
|
41904
|
+
const basePayload = ensureObjectPayload(
|
|
41905
|
+
await readStudioWriteInput({
|
|
41906
|
+
data: context.options.data,
|
|
41907
|
+
fromFile: context.options.fromFile
|
|
41908
|
+
}),
|
|
41909
|
+
"update-field"
|
|
41910
|
+
);
|
|
41911
|
+
const payload = mergeObjectWithFlags(basePayload, fieldFlags(context.options));
|
|
41912
|
+
requireNonEmptyObject(payload, "update-field");
|
|
41913
|
+
const response = await studio.apiClient.request({
|
|
41914
|
+
method: "PATCH",
|
|
41915
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/${fieldId}`,
|
|
41916
|
+
body: payload
|
|
41917
|
+
});
|
|
41918
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41919
|
+
}
|
|
41920
|
+
});
|
|
41921
|
+
studioCli.command("delete-field", {
|
|
41922
|
+
description: "Delete a field",
|
|
41923
|
+
options: external_exports.object({
|
|
41924
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41925
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41926
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
41927
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
41928
|
+
fieldId: external_exports.string().optional().describe("Field ID"),
|
|
41929
|
+
fieldSlug: external_exports.string().optional().describe("Field slug")
|
|
41930
|
+
}),
|
|
41931
|
+
run: async (context) => {
|
|
41932
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41933
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41934
|
+
appId: context.options.appId,
|
|
41935
|
+
appSlug: context.options.appSlug
|
|
41936
|
+
});
|
|
41937
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
41938
|
+
appId,
|
|
41939
|
+
dataSourceId: context.options.dataSourceId,
|
|
41940
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
41941
|
+
});
|
|
41942
|
+
const fieldId = await studio.resolver.resolveFieldId({
|
|
41943
|
+
appId,
|
|
41944
|
+
dataSourceId,
|
|
41945
|
+
fieldId: context.options.fieldId,
|
|
41946
|
+
fieldSlug: context.options.fieldSlug
|
|
41947
|
+
});
|
|
41948
|
+
const response = await studio.apiClient.request({
|
|
41949
|
+
method: "DELETE",
|
|
41950
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/${fieldId}`
|
|
41951
|
+
});
|
|
41952
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41953
|
+
}
|
|
41954
|
+
});
|
|
41955
|
+
studioCli.command("create-fields-batch", {
|
|
41956
|
+
description: "Batch create fields",
|
|
41957
|
+
options: external_exports.object({
|
|
41958
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41959
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41960
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
41961
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
41962
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
41963
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file")
|
|
41964
|
+
}),
|
|
41965
|
+
run: async (context) => {
|
|
41966
|
+
const studio = await getStudioRunContext(dependencies);
|
|
41967
|
+
const appId = await studio.resolver.resolveAppId({
|
|
41968
|
+
appId: context.options.appId,
|
|
41969
|
+
appSlug: context.options.appSlug
|
|
41970
|
+
});
|
|
41971
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
41972
|
+
appId,
|
|
41973
|
+
dataSourceId: context.options.dataSourceId,
|
|
41974
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
41975
|
+
});
|
|
41976
|
+
const payload = normalizeBatchPayload(
|
|
41977
|
+
await readStudioWriteInput({
|
|
41978
|
+
data: context.options.data,
|
|
41979
|
+
fromFile: context.options.fromFile
|
|
41980
|
+
}),
|
|
41981
|
+
"fields"
|
|
41982
|
+
);
|
|
41983
|
+
const response = await studio.apiClient.request({
|
|
41984
|
+
method: "POST",
|
|
41985
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/batch`,
|
|
41986
|
+
body: payload
|
|
41987
|
+
});
|
|
41988
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
41989
|
+
}
|
|
41990
|
+
});
|
|
41991
|
+
studioCli.command("update-fields-batch", {
|
|
41992
|
+
description: "Batch update fields",
|
|
41993
|
+
options: external_exports.object({
|
|
41994
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
41995
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
41996
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
41997
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
41998
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
41999
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file")
|
|
42000
|
+
}),
|
|
42001
|
+
run: async (context) => {
|
|
42002
|
+
const studio = await getStudioRunContext(dependencies);
|
|
42003
|
+
const appId = await studio.resolver.resolveAppId({
|
|
42004
|
+
appId: context.options.appId,
|
|
42005
|
+
appSlug: context.options.appSlug
|
|
42006
|
+
});
|
|
42007
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
42008
|
+
appId,
|
|
42009
|
+
dataSourceId: context.options.dataSourceId,
|
|
42010
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
42011
|
+
});
|
|
42012
|
+
const payload = normalizeBatchPayload(
|
|
42013
|
+
await readStudioWriteInput({
|
|
42014
|
+
data: context.options.data,
|
|
42015
|
+
fromFile: context.options.fromFile
|
|
42016
|
+
}),
|
|
42017
|
+
"fields"
|
|
42018
|
+
);
|
|
42019
|
+
const response = await studio.apiClient.request({
|
|
42020
|
+
method: "PATCH",
|
|
42021
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/batch`,
|
|
42022
|
+
body: payload
|
|
42023
|
+
});
|
|
42024
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
42025
|
+
}
|
|
42026
|
+
});
|
|
42027
|
+
studioCli.command("delete-fields-batch", {
|
|
42028
|
+
description: "Batch delete fields",
|
|
42029
|
+
options: external_exports.object({
|
|
42030
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
42031
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
42032
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
42033
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
42034
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
42035
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file")
|
|
42036
|
+
}),
|
|
42037
|
+
run: async (context) => {
|
|
42038
|
+
const studio = await getStudioRunContext(dependencies);
|
|
42039
|
+
const appId = await studio.resolver.resolveAppId({
|
|
42040
|
+
appId: context.options.appId,
|
|
42041
|
+
appSlug: context.options.appSlug
|
|
42042
|
+
});
|
|
42043
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
42044
|
+
appId,
|
|
42045
|
+
dataSourceId: context.options.dataSourceId,
|
|
42046
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
42047
|
+
});
|
|
42048
|
+
const payload = normalizeBatchPayload(
|
|
42049
|
+
await readStudioWriteInput({
|
|
42050
|
+
data: context.options.data,
|
|
42051
|
+
fromFile: context.options.fromFile
|
|
42052
|
+
}),
|
|
42053
|
+
"fieldIds"
|
|
42054
|
+
);
|
|
42055
|
+
const response = await studio.apiClient.request({
|
|
42056
|
+
method: "DELETE",
|
|
42057
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/batch`,
|
|
42058
|
+
body: payload
|
|
42059
|
+
});
|
|
42060
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
42061
|
+
}
|
|
42062
|
+
});
|
|
42063
|
+
studioCli.command("list-enums", {
|
|
42064
|
+
description: "List enums for a field",
|
|
42065
|
+
options: external_exports.object({
|
|
42066
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
42067
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
42068
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
42069
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
42070
|
+
fieldId: external_exports.string().optional().describe("Field ID"),
|
|
42071
|
+
fieldSlug: external_exports.string().optional().describe("Field slug")
|
|
42072
|
+
}),
|
|
42073
|
+
run: async (context) => {
|
|
42074
|
+
const studio = await getStudioRunContext(dependencies);
|
|
42075
|
+
const appId = await studio.resolver.resolveAppId({
|
|
42076
|
+
appId: context.options.appId,
|
|
42077
|
+
appSlug: context.options.appSlug
|
|
42078
|
+
});
|
|
42079
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
42080
|
+
appId,
|
|
42081
|
+
dataSourceId: context.options.dataSourceId,
|
|
42082
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
42083
|
+
});
|
|
42084
|
+
const fieldId = await studio.resolver.resolveFieldId({
|
|
42085
|
+
appId,
|
|
42086
|
+
dataSourceId,
|
|
42087
|
+
fieldId: context.options.fieldId,
|
|
42088
|
+
fieldSlug: context.options.fieldSlug
|
|
42089
|
+
});
|
|
42090
|
+
const response = await studio.apiClient.request({
|
|
42091
|
+
method: "GET",
|
|
42092
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/${fieldId}/enums`
|
|
42093
|
+
});
|
|
42094
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
42095
|
+
}
|
|
42096
|
+
});
|
|
42097
|
+
studioCli.command("create-enums", {
|
|
42098
|
+
description: "Create enums for a field",
|
|
42099
|
+
options: external_exports.object({
|
|
42100
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
42101
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
42102
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
42103
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
42104
|
+
fieldId: external_exports.string().optional().describe("Field ID"),
|
|
42105
|
+
fieldSlug: external_exports.string().optional().describe("Field slug"),
|
|
42106
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
42107
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file"),
|
|
42108
|
+
enumSetId: external_exports.string().optional().describe("Enum set ID")
|
|
42109
|
+
}),
|
|
42110
|
+
run: async (context) => {
|
|
42111
|
+
const studio = await getStudioRunContext(dependencies);
|
|
42112
|
+
const appId = await studio.resolver.resolveAppId({
|
|
42113
|
+
appId: context.options.appId,
|
|
42114
|
+
appSlug: context.options.appSlug
|
|
42115
|
+
});
|
|
42116
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
42117
|
+
appId,
|
|
42118
|
+
dataSourceId: context.options.dataSourceId,
|
|
42119
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
42120
|
+
});
|
|
42121
|
+
const fieldId = await studio.resolver.resolveFieldId({
|
|
42122
|
+
appId,
|
|
42123
|
+
dataSourceId,
|
|
42124
|
+
fieldId: context.options.fieldId,
|
|
42125
|
+
fieldSlug: context.options.fieldSlug
|
|
42126
|
+
});
|
|
42127
|
+
const payload = mergeObjectWithFlags(
|
|
42128
|
+
normalizeBatchPayload(
|
|
42129
|
+
await readStudioWriteInput({
|
|
42130
|
+
data: context.options.data,
|
|
42131
|
+
fromFile: context.options.fromFile
|
|
42132
|
+
}),
|
|
42133
|
+
"enums"
|
|
42134
|
+
),
|
|
42135
|
+
{
|
|
42136
|
+
enumSetId: context.options.enumSetId
|
|
42137
|
+
}
|
|
42138
|
+
);
|
|
42139
|
+
const response = await studio.apiClient.request({
|
|
42140
|
+
method: "POST",
|
|
42141
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/${fieldId}/enums`,
|
|
42142
|
+
body: payload
|
|
42143
|
+
});
|
|
42144
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
42145
|
+
}
|
|
42146
|
+
});
|
|
42147
|
+
studioCli.command("update-enums", {
|
|
42148
|
+
description: "Update enums for a field",
|
|
42149
|
+
options: external_exports.object({
|
|
42150
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
42151
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
42152
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
42153
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
42154
|
+
fieldId: external_exports.string().optional().describe("Field ID"),
|
|
42155
|
+
fieldSlug: external_exports.string().optional().describe("Field slug"),
|
|
42156
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
42157
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file")
|
|
42158
|
+
}),
|
|
42159
|
+
run: async (context) => {
|
|
42160
|
+
const studio = await getStudioRunContext(dependencies);
|
|
42161
|
+
const appId = await studio.resolver.resolveAppId({
|
|
42162
|
+
appId: context.options.appId,
|
|
42163
|
+
appSlug: context.options.appSlug
|
|
42164
|
+
});
|
|
42165
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
42166
|
+
appId,
|
|
42167
|
+
dataSourceId: context.options.dataSourceId,
|
|
42168
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
42169
|
+
});
|
|
42170
|
+
const fieldId = await studio.resolver.resolveFieldId({
|
|
42171
|
+
appId,
|
|
42172
|
+
dataSourceId,
|
|
42173
|
+
fieldId: context.options.fieldId,
|
|
42174
|
+
fieldSlug: context.options.fieldSlug
|
|
42175
|
+
});
|
|
42176
|
+
const payload = normalizeBatchPayload(
|
|
42177
|
+
await readStudioWriteInput({
|
|
42178
|
+
data: context.options.data,
|
|
42179
|
+
fromFile: context.options.fromFile
|
|
42180
|
+
}),
|
|
42181
|
+
"enums"
|
|
42182
|
+
);
|
|
42183
|
+
const response = await studio.apiClient.request({
|
|
42184
|
+
method: "PATCH",
|
|
42185
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/${fieldId}/enums`,
|
|
42186
|
+
body: payload
|
|
42187
|
+
});
|
|
42188
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
42189
|
+
}
|
|
42190
|
+
});
|
|
42191
|
+
studioCli.command("delete-enums", {
|
|
42192
|
+
description: "Delete enums for a field",
|
|
42193
|
+
options: external_exports.object({
|
|
42194
|
+
appId: external_exports.string().optional().describe("App ID"),
|
|
42195
|
+
appSlug: external_exports.string().optional().describe("App slug"),
|
|
42196
|
+
dataSourceId: external_exports.string().optional().describe("Data source ID"),
|
|
42197
|
+
dataSourceSlug: external_exports.string().optional().describe("Data source slug"),
|
|
42198
|
+
fieldId: external_exports.string().optional().describe("Field ID"),
|
|
42199
|
+
fieldSlug: external_exports.string().optional().describe("Field slug"),
|
|
42200
|
+
data: external_exports.string().optional().describe("JSON payload"),
|
|
42201
|
+
fromFile: external_exports.string().optional().describe("Path to JSON payload file")
|
|
42202
|
+
}),
|
|
42203
|
+
run: async (context) => {
|
|
42204
|
+
const studio = await getStudioRunContext(dependencies);
|
|
42205
|
+
const appId = await studio.resolver.resolveAppId({
|
|
42206
|
+
appId: context.options.appId,
|
|
42207
|
+
appSlug: context.options.appSlug
|
|
42208
|
+
});
|
|
42209
|
+
const dataSourceId = await studio.resolver.resolveDataSourceId({
|
|
42210
|
+
appId,
|
|
42211
|
+
dataSourceId: context.options.dataSourceId,
|
|
42212
|
+
dataSourceSlug: context.options.dataSourceSlug
|
|
42213
|
+
});
|
|
42214
|
+
const fieldId = await studio.resolver.resolveFieldId({
|
|
42215
|
+
appId,
|
|
42216
|
+
dataSourceId,
|
|
42217
|
+
fieldId: context.options.fieldId,
|
|
42218
|
+
fieldSlug: context.options.fieldSlug
|
|
42219
|
+
});
|
|
42220
|
+
const payload = normalizeBatchPayload(
|
|
42221
|
+
await readStudioWriteInput({
|
|
42222
|
+
data: context.options.data,
|
|
42223
|
+
fromFile: context.options.fromFile
|
|
42224
|
+
}),
|
|
42225
|
+
"enumIds"
|
|
42226
|
+
);
|
|
42227
|
+
const response = await studio.apiClient.request({
|
|
42228
|
+
method: "DELETE",
|
|
42229
|
+
path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/${fieldId}/enums`,
|
|
42230
|
+
body: payload
|
|
42231
|
+
});
|
|
42232
|
+
return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
|
|
42233
|
+
}
|
|
42234
|
+
});
|
|
42235
|
+
return studioCli;
|
|
42236
|
+
}
|
|
42237
|
+
|
|
40822
42238
|
// src/services/apiClient.ts
|
|
40823
42239
|
function normalizeResponseHeaders(headers) {
|
|
40824
42240
|
const normalized = {};
|
|
@@ -40972,7 +42388,7 @@ var ApiClient = class {
|
|
|
40972
42388
|
};
|
|
40973
42389
|
|
|
40974
42390
|
// src/services/authSession.ts
|
|
40975
|
-
function
|
|
42391
|
+
function isRecord5(value) {
|
|
40976
42392
|
return typeof value === "object" && value !== null;
|
|
40977
42393
|
}
|
|
40978
42394
|
function extractRecordValue(record2, keys) {
|
|
@@ -40983,7 +42399,7 @@ function extractRecordValue(record2, keys) {
|
|
|
40983
42399
|
}
|
|
40984
42400
|
return void 0;
|
|
40985
42401
|
}
|
|
40986
|
-
function
|
|
42402
|
+
function extractString2(record2, keys) {
|
|
40987
42403
|
const value = extractRecordValue(record2, keys);
|
|
40988
42404
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
40989
42405
|
}
|
|
@@ -41271,15 +42687,15 @@ var AuthSessionService = class {
|
|
|
41271
42687
|
fetchFn: this.params.fetchFn
|
|
41272
42688
|
});
|
|
41273
42689
|
const payload = response.data;
|
|
41274
|
-
const dataCandidate =
|
|
41275
|
-
if (!
|
|
42690
|
+
const dataCandidate = isRecord5(payload) && isRecord5(payload.data) ? payload.data : payload;
|
|
42691
|
+
if (!isRecord5(dataCandidate)) {
|
|
41276
42692
|
throw new AuthSessionError("Unable to parse /users/me response.");
|
|
41277
42693
|
}
|
|
41278
|
-
const tenantCandidate =
|
|
41279
|
-
const userId =
|
|
41280
|
-
const email3 =
|
|
41281
|
-
const tenantId = tenantCandidate ?
|
|
41282
|
-
const tenantName = tenantCandidate ?
|
|
42694
|
+
const tenantCandidate = isRecord5(dataCandidate.tenant) ? dataCandidate.tenant : void 0;
|
|
42695
|
+
const userId = extractString2(dataCandidate, ["id", "user_id"]);
|
|
42696
|
+
const email3 = extractString2(dataCandidate, ["email"]);
|
|
42697
|
+
const tenantId = tenantCandidate ? extractString2(tenantCandidate, ["id"]) : extractString2(dataCandidate, ["tenant_id", "tenantId"]);
|
|
42698
|
+
const tenantName = tenantCandidate ? extractString2(tenantCandidate, ["name"]) : extractString2(dataCandidate, ["tenant_name", "tenantName"]);
|
|
41283
42699
|
const tenantNo = tenantCandidate ? extractNumber(tenantCandidate, ["no", "tenant_no"]) : extractNumber(dataCandidate, ["tenant_no", "tenantNo"]);
|
|
41284
42700
|
if (!userId || !email3 || !tenantId || !tenantName || !tenantNo) {
|
|
41285
42701
|
throw new AuthSessionError("Incomplete identity data returned from /users/me.");
|
|
@@ -41301,17 +42717,17 @@ var AuthSessionService = class {
|
|
|
41301
42717
|
fetchFn: this.params.fetchFn
|
|
41302
42718
|
});
|
|
41303
42719
|
const payload = response.data;
|
|
41304
|
-
const listCandidate = Array.isArray(payload) ? payload :
|
|
42720
|
+
const listCandidate = Array.isArray(payload) ? payload : isRecord5(payload) && Array.isArray(payload.data) ? payload.data : null;
|
|
41305
42721
|
if (!listCandidate) {
|
|
41306
42722
|
throw new AuthSessionError("Unable to parse tenant catalog response.");
|
|
41307
42723
|
}
|
|
41308
42724
|
const mapped = [];
|
|
41309
42725
|
for (const item of listCandidate) {
|
|
41310
|
-
if (!
|
|
42726
|
+
if (!isRecord5(item)) {
|
|
41311
42727
|
continue;
|
|
41312
42728
|
}
|
|
41313
|
-
const tenantId =
|
|
41314
|
-
const tenantName =
|
|
42729
|
+
const tenantId = extractString2(item, ["id", "tenant_id"]);
|
|
42730
|
+
const tenantName = extractString2(item, ["name"]);
|
|
41315
42731
|
const tenantNo = extractNumber(item, ["tenant_no", "tenantNo", "no"]);
|
|
41316
42732
|
const logoValue = extractRecordValue(item, ["logo"]);
|
|
41317
42733
|
const logo = typeof logoValue === "string" || logoValue === null ? logoValue : void 0;
|
|
@@ -41466,8 +42882,8 @@ var AuthSessionService = class {
|
|
|
41466
42882
|
};
|
|
41467
42883
|
|
|
41468
42884
|
// src/services/authStore.ts
|
|
41469
|
-
var
|
|
41470
|
-
var
|
|
42885
|
+
var import_promises5 = require("node:fs/promises");
|
|
42886
|
+
var import_node_path6 = require("node:path");
|
|
41471
42887
|
function createEmptyState() {
|
|
41472
42888
|
return {
|
|
41473
42889
|
version: 2,
|
|
@@ -41506,7 +42922,7 @@ var AuthStore = class {
|
|
|
41506
42922
|
}
|
|
41507
42923
|
async readState() {
|
|
41508
42924
|
try {
|
|
41509
|
-
const raw = await (0,
|
|
42925
|
+
const raw = await (0, import_promises5.readFile)(this.authFilePath, "utf8");
|
|
41510
42926
|
const parsed = JSON.parse(raw);
|
|
41511
42927
|
const legacy = LegacyAuthSessionSchema.safeParse(parsed);
|
|
41512
42928
|
if (legacy.success) {
|
|
@@ -41542,17 +42958,17 @@ var AuthStore = class {
|
|
|
41542
42958
|
});
|
|
41543
42959
|
}
|
|
41544
42960
|
const normalized = normalizeState(validated.data);
|
|
41545
|
-
const directory = (0,
|
|
41546
|
-
await (0,
|
|
42961
|
+
const directory = (0, import_node_path6.dirname)(this.authFilePath);
|
|
42962
|
+
await (0, import_promises5.mkdir)(directory, {
|
|
41547
42963
|
recursive: true,
|
|
41548
42964
|
mode: 448
|
|
41549
42965
|
});
|
|
41550
|
-
await (0,
|
|
42966
|
+
await (0, import_promises5.writeFile)(this.authFilePath, `${JSON.stringify(normalized, null, 2)}
|
|
41551
42967
|
`, {
|
|
41552
42968
|
encoding: "utf8",
|
|
41553
42969
|
mode: 384
|
|
41554
42970
|
});
|
|
41555
|
-
await (0,
|
|
42971
|
+
await (0, import_promises5.chmod)(this.authFilePath, 384);
|
|
41556
42972
|
}
|
|
41557
42973
|
async getActiveProfile(apiBaseUrl) {
|
|
41558
42974
|
const normalizedApiBaseUrl = normalizeApiBaseUrl(apiBaseUrl);
|
|
@@ -41749,15 +43165,15 @@ var AuthStore = class {
|
|
|
41749
43165
|
await this.writeState(state);
|
|
41750
43166
|
}
|
|
41751
43167
|
async clear() {
|
|
41752
|
-
await (0,
|
|
43168
|
+
await (0, import_promises5.rm)(this.authFilePath, {
|
|
41753
43169
|
force: true
|
|
41754
43170
|
});
|
|
41755
43171
|
}
|
|
41756
43172
|
};
|
|
41757
43173
|
|
|
41758
43174
|
// src/services/environmentConfig.ts
|
|
41759
|
-
var
|
|
41760
|
-
var
|
|
43175
|
+
var import_promises6 = require("node:fs/promises");
|
|
43176
|
+
var import_node_path7 = require("node:path");
|
|
41761
43177
|
var ENVIRONMENT_ID_ALIASES = {
|
|
41762
43178
|
"local-development": "dev",
|
|
41763
43179
|
prod: "live"
|
|
@@ -41843,7 +43259,7 @@ var EnvironmentConfigService = class {
|
|
|
41843
43259
|
}
|
|
41844
43260
|
async readState() {
|
|
41845
43261
|
try {
|
|
41846
|
-
const raw = await (0,
|
|
43262
|
+
const raw = await (0, import_promises6.readFile)(this.configFilePath, "utf8");
|
|
41847
43263
|
const parsed = JSON.parse(raw);
|
|
41848
43264
|
const validated = EnvironmentConfigStateSchema.safeParse(parsed);
|
|
41849
43265
|
if (!validated.success) {
|
|
@@ -41877,17 +43293,17 @@ var EnvironmentConfigService = class {
|
|
|
41877
43293
|
});
|
|
41878
43294
|
}
|
|
41879
43295
|
const normalized = normalizeState2(validated.data);
|
|
41880
|
-
const directory = (0,
|
|
41881
|
-
await (0,
|
|
43296
|
+
const directory = (0, import_node_path7.dirname)(this.configFilePath);
|
|
43297
|
+
await (0, import_promises6.mkdir)(directory, {
|
|
41882
43298
|
recursive: true,
|
|
41883
43299
|
mode: 448
|
|
41884
43300
|
});
|
|
41885
|
-
await (0,
|
|
43301
|
+
await (0, import_promises6.writeFile)(this.configFilePath, `${JSON.stringify(normalized, null, 2)}
|
|
41886
43302
|
`, {
|
|
41887
43303
|
encoding: "utf8",
|
|
41888
43304
|
mode: 384
|
|
41889
43305
|
});
|
|
41890
|
-
await (0,
|
|
43306
|
+
await (0, import_promises6.chmod)(this.configFilePath, 384);
|
|
41891
43307
|
}
|
|
41892
43308
|
async getActiveEnvironment() {
|
|
41893
43309
|
const state = await this.#readStateWithDefaults();
|
|
@@ -41953,8 +43369,8 @@ var EnvironmentConfigService = class {
|
|
|
41953
43369
|
};
|
|
41954
43370
|
|
|
41955
43371
|
// src/services/tenantOpenApi.ts
|
|
41956
|
-
var
|
|
41957
|
-
var
|
|
43372
|
+
var import_promises7 = require("node:fs/promises");
|
|
43373
|
+
var import_node_path8 = require("node:path");
|
|
41958
43374
|
function resolveSourceUrl(tenantId, template) {
|
|
41959
43375
|
return template.replace("{tenantId}", encodeURIComponent(tenantId));
|
|
41960
43376
|
}
|
|
@@ -41962,6 +43378,14 @@ var TenantOpenApiService = class {
|
|
|
41962
43378
|
constructor(params) {
|
|
41963
43379
|
this.params = params;
|
|
41964
43380
|
}
|
|
43381
|
+
getTenantOpenApiFilePath(tenantId) {
|
|
43382
|
+
const normalizedTenantId = tenantId.trim();
|
|
43383
|
+
if (!normalizedTenantId) {
|
|
43384
|
+
throw new AuthSessionError("Tenant ID is required to resolve OpenAPI spec path.");
|
|
43385
|
+
}
|
|
43386
|
+
const rootPath = this.params?.rootPath || TENANT_OPENAPI_ROOT_PATH;
|
|
43387
|
+
return (0, import_node_path8.join)(rootPath, normalizedTenantId, "openapi.json");
|
|
43388
|
+
}
|
|
41965
43389
|
async downloadTenantOpenApi(tenantId) {
|
|
41966
43390
|
const normalizedTenantId = tenantId.trim();
|
|
41967
43391
|
if (!normalizedTenantId) {
|
|
@@ -41993,18 +43417,17 @@ var TenantOpenApiService = class {
|
|
|
41993
43417
|
cause: error48
|
|
41994
43418
|
});
|
|
41995
43419
|
}
|
|
41996
|
-
const
|
|
41997
|
-
|
|
41998
|
-
await (0, import_promises4.mkdir)((0, import_node_path6.dirname)(filePath), {
|
|
43420
|
+
const filePath = this.getTenantOpenApiFilePath(normalizedTenantId);
|
|
43421
|
+
await (0, import_promises7.mkdir)((0, import_node_path8.dirname)(filePath), {
|
|
41999
43422
|
recursive: true,
|
|
42000
43423
|
mode: 448
|
|
42001
43424
|
});
|
|
42002
|
-
await (0,
|
|
43425
|
+
await (0, import_promises7.writeFile)(filePath, `${JSON.stringify(parsedContent, null, 2)}
|
|
42003
43426
|
`, {
|
|
42004
43427
|
encoding: "utf8",
|
|
42005
43428
|
mode: 384
|
|
42006
43429
|
});
|
|
42007
|
-
await (0,
|
|
43430
|
+
await (0, import_promises7.chmod)(filePath, 384);
|
|
42008
43431
|
return {
|
|
42009
43432
|
tenantId: normalizedTenantId,
|
|
42010
43433
|
sourceUrl,
|
|
@@ -42021,8 +43444,14 @@ var ROOT_HELP_COMMANDS = [
|
|
|
42021
43444
|
{ command: "auth accounts list", description: "List saved user accounts" },
|
|
42022
43445
|
{ command: "auth tenants use --tenantId <id>", description: "Switch active tenant for selected user" },
|
|
42023
43446
|
{ command: "discover api", description: "Download active tenant OpenAPI spec" },
|
|
43447
|
+
{ command: "discover namespaces", description: "List namespaces from tenant OpenAPI spec" },
|
|
43448
|
+
{ command: "discover path <prefix>", description: "List endpoint paths by prefix" },
|
|
43449
|
+
{ command: "discover endpoint <path>", description: "Show endpoint object by exact path" },
|
|
43450
|
+
{ command: "discover entity <name>", description: "Show entity object by name" },
|
|
43451
|
+
{ command: "discover search <terms>", description: "Search in endpoint paths and entity names" },
|
|
42024
43452
|
{ command: "ds list <appSlug> <dataSourceSlug>", description: "List data source items" },
|
|
42025
43453
|
{ command: "apps list", description: "List apps" },
|
|
43454
|
+
{ command: "studio list-data-sources --appSlug <slug>", description: "List studio data sources" },
|
|
42026
43455
|
{ command: "curl <path>", description: "Send arbitrary API requests" }
|
|
42027
43456
|
];
|
|
42028
43457
|
function createDocyrusCli(params) {
|
|
@@ -42090,6 +43519,11 @@ function createDocyrusCli(params) {
|
|
|
42090
43519
|
environmentConfigService,
|
|
42091
43520
|
authStore
|
|
42092
43521
|
}));
|
|
43522
|
+
cli2.command(createStudioCli({
|
|
43523
|
+
createApiClient,
|
|
43524
|
+
environmentConfigService,
|
|
43525
|
+
authStore
|
|
43526
|
+
}));
|
|
42093
43527
|
cli2.command(createCurlCli({
|
|
42094
43528
|
createApiClient,
|
|
42095
43529
|
environmentConfigService,
|