@docyrus/docyrus 0.0.2 → 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 +33 -0
- package/main.js +1164 -69
- 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,7 +40895,7 @@ function createDsCli(dependencies) {
|
|
|
40752
40895
|
}
|
|
40753
40896
|
|
|
40754
40897
|
// src/commands/discoverCommands.ts
|
|
40755
|
-
var
|
|
40898
|
+
var import_promises3 = require("node:fs/promises");
|
|
40756
40899
|
var SUPPORTED_HTTP_METHODS2 = [
|
|
40757
40900
|
"GET",
|
|
40758
40901
|
"POST",
|
|
@@ -40763,7 +40906,7 @@ var SUPPORTED_HTTP_METHODS2 = [
|
|
|
40763
40906
|
"OPTIONS",
|
|
40764
40907
|
"TRACE"
|
|
40765
40908
|
];
|
|
40766
|
-
function
|
|
40909
|
+
function isRecord2(value) {
|
|
40767
40910
|
return typeof value === "object" && value !== null;
|
|
40768
40911
|
}
|
|
40769
40912
|
function isEnoentError(error48) {
|
|
@@ -40817,15 +40960,15 @@ function parseEndpointSelector(input) {
|
|
|
40817
40960
|
}
|
|
40818
40961
|
function getPaths(document) {
|
|
40819
40962
|
const rawPaths = document.paths;
|
|
40820
|
-
return
|
|
40963
|
+
return isRecord2(rawPaths) ? rawPaths : {};
|
|
40821
40964
|
}
|
|
40822
40965
|
function getEntities(document) {
|
|
40823
|
-
const components =
|
|
40824
|
-
if (components &&
|
|
40966
|
+
const components = isRecord2(document.components) ? document.components : null;
|
|
40967
|
+
if (components && isRecord2(components.schemas)) {
|
|
40825
40968
|
return components.schemas;
|
|
40826
40969
|
}
|
|
40827
40970
|
const definitions = document.definitions;
|
|
40828
|
-
if (
|
|
40971
|
+
if (isRecord2(definitions)) {
|
|
40829
40972
|
return definitions;
|
|
40830
40973
|
}
|
|
40831
40974
|
return {};
|
|
@@ -40845,19 +40988,19 @@ function extractNamespaces(paths) {
|
|
|
40845
40988
|
return Array.from(namespaces.values()).sort((left, right) => left.localeCompare(right));
|
|
40846
40989
|
}
|
|
40847
40990
|
function getPathOperation(pathItem, method) {
|
|
40848
|
-
if (!
|
|
40991
|
+
if (!isRecord2(pathItem)) {
|
|
40849
40992
|
return null;
|
|
40850
40993
|
}
|
|
40851
40994
|
const normalizedMethod = method.toLowerCase();
|
|
40852
40995
|
const operation = pathItem[normalizedMethod];
|
|
40853
|
-
return
|
|
40996
|
+
return isRecord2(operation) ? operation : null;
|
|
40854
40997
|
}
|
|
40855
40998
|
function toEndpointMethodEntries(paths, pathFilter) {
|
|
40856
40999
|
const entries = [];
|
|
40857
41000
|
const sortedPaths = Object.keys(paths).filter(pathFilter).sort((left, right) => left.localeCompare(right));
|
|
40858
41001
|
for (const path3 of sortedPaths) {
|
|
40859
41002
|
const pathItem = paths[path3];
|
|
40860
|
-
if (!
|
|
41003
|
+
if (!isRecord2(pathItem)) {
|
|
40861
41004
|
continue;
|
|
40862
41005
|
}
|
|
40863
41006
|
for (const method of SUPPORTED_HTTP_METHODS2) {
|
|
@@ -40886,7 +41029,7 @@ function parseOpenApiDocument(raw) {
|
|
|
40886
41029
|
cause: error48
|
|
40887
41030
|
});
|
|
40888
41031
|
}
|
|
40889
|
-
if (!
|
|
41032
|
+
if (!isRecord2(parsed)) {
|
|
40890
41033
|
throw new UserInputError("Stored OpenAPI spec must be a JSON object. Run 'docyrus discover api' to re-download.");
|
|
40891
41034
|
}
|
|
40892
41035
|
return parsed;
|
|
@@ -40897,7 +41040,7 @@ async function loadOpenApiSpec(dependencies, tenantId) {
|
|
|
40897
41040
|
let sourceUrl;
|
|
40898
41041
|
let content;
|
|
40899
41042
|
try {
|
|
40900
|
-
content = await (0,
|
|
41043
|
+
content = await (0, import_promises3.readFile)(filePath, "utf8");
|
|
40901
41044
|
} catch (error48) {
|
|
40902
41045
|
if (!isEnoentError(error48)) {
|
|
40903
41046
|
throw new UserInputError("Failed to read downloaded OpenAPI spec file.", {
|
|
@@ -40909,7 +41052,7 @@ async function loadOpenApiSpec(dependencies, tenantId) {
|
|
|
40909
41052
|
downloaded = true;
|
|
40910
41053
|
sourceUrl = downloadResult.sourceUrl;
|
|
40911
41054
|
filePath = downloadResult.filePath;
|
|
40912
|
-
content = await (0,
|
|
41055
|
+
content = await (0, import_promises3.readFile)(filePath, "utf8");
|
|
40913
41056
|
}
|
|
40914
41057
|
return {
|
|
40915
41058
|
filePath,
|
|
@@ -41146,6 +41289,952 @@ function createEnvCli(dependencies) {
|
|
|
41146
41289
|
return envCli;
|
|
41147
41290
|
}
|
|
41148
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
|
+
|
|
41149
42238
|
// src/services/apiClient.ts
|
|
41150
42239
|
function normalizeResponseHeaders(headers) {
|
|
41151
42240
|
const normalized = {};
|
|
@@ -41299,7 +42388,7 @@ var ApiClient = class {
|
|
|
41299
42388
|
};
|
|
41300
42389
|
|
|
41301
42390
|
// src/services/authSession.ts
|
|
41302
|
-
function
|
|
42391
|
+
function isRecord5(value) {
|
|
41303
42392
|
return typeof value === "object" && value !== null;
|
|
41304
42393
|
}
|
|
41305
42394
|
function extractRecordValue(record2, keys) {
|
|
@@ -41310,7 +42399,7 @@ function extractRecordValue(record2, keys) {
|
|
|
41310
42399
|
}
|
|
41311
42400
|
return void 0;
|
|
41312
42401
|
}
|
|
41313
|
-
function
|
|
42402
|
+
function extractString2(record2, keys) {
|
|
41314
42403
|
const value = extractRecordValue(record2, keys);
|
|
41315
42404
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
41316
42405
|
}
|
|
@@ -41598,15 +42687,15 @@ var AuthSessionService = class {
|
|
|
41598
42687
|
fetchFn: this.params.fetchFn
|
|
41599
42688
|
});
|
|
41600
42689
|
const payload = response.data;
|
|
41601
|
-
const dataCandidate =
|
|
41602
|
-
if (!
|
|
42690
|
+
const dataCandidate = isRecord5(payload) && isRecord5(payload.data) ? payload.data : payload;
|
|
42691
|
+
if (!isRecord5(dataCandidate)) {
|
|
41603
42692
|
throw new AuthSessionError("Unable to parse /users/me response.");
|
|
41604
42693
|
}
|
|
41605
|
-
const tenantCandidate =
|
|
41606
|
-
const userId =
|
|
41607
|
-
const email3 =
|
|
41608
|
-
const tenantId = tenantCandidate ?
|
|
41609
|
-
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"]);
|
|
41610
42699
|
const tenantNo = tenantCandidate ? extractNumber(tenantCandidate, ["no", "tenant_no"]) : extractNumber(dataCandidate, ["tenant_no", "tenantNo"]);
|
|
41611
42700
|
if (!userId || !email3 || !tenantId || !tenantName || !tenantNo) {
|
|
41612
42701
|
throw new AuthSessionError("Incomplete identity data returned from /users/me.");
|
|
@@ -41628,17 +42717,17 @@ var AuthSessionService = class {
|
|
|
41628
42717
|
fetchFn: this.params.fetchFn
|
|
41629
42718
|
});
|
|
41630
42719
|
const payload = response.data;
|
|
41631
|
-
const listCandidate = Array.isArray(payload) ? payload :
|
|
42720
|
+
const listCandidate = Array.isArray(payload) ? payload : isRecord5(payload) && Array.isArray(payload.data) ? payload.data : null;
|
|
41632
42721
|
if (!listCandidate) {
|
|
41633
42722
|
throw new AuthSessionError("Unable to parse tenant catalog response.");
|
|
41634
42723
|
}
|
|
41635
42724
|
const mapped = [];
|
|
41636
42725
|
for (const item of listCandidate) {
|
|
41637
|
-
if (!
|
|
42726
|
+
if (!isRecord5(item)) {
|
|
41638
42727
|
continue;
|
|
41639
42728
|
}
|
|
41640
|
-
const tenantId =
|
|
41641
|
-
const tenantName =
|
|
42729
|
+
const tenantId = extractString2(item, ["id", "tenant_id"]);
|
|
42730
|
+
const tenantName = extractString2(item, ["name"]);
|
|
41642
42731
|
const tenantNo = extractNumber(item, ["tenant_no", "tenantNo", "no"]);
|
|
41643
42732
|
const logoValue = extractRecordValue(item, ["logo"]);
|
|
41644
42733
|
const logo = typeof logoValue === "string" || logoValue === null ? logoValue : void 0;
|
|
@@ -41793,8 +42882,8 @@ var AuthSessionService = class {
|
|
|
41793
42882
|
};
|
|
41794
42883
|
|
|
41795
42884
|
// src/services/authStore.ts
|
|
41796
|
-
var
|
|
41797
|
-
var
|
|
42885
|
+
var import_promises5 = require("node:fs/promises");
|
|
42886
|
+
var import_node_path6 = require("node:path");
|
|
41798
42887
|
function createEmptyState() {
|
|
41799
42888
|
return {
|
|
41800
42889
|
version: 2,
|
|
@@ -41833,7 +42922,7 @@ var AuthStore = class {
|
|
|
41833
42922
|
}
|
|
41834
42923
|
async readState() {
|
|
41835
42924
|
try {
|
|
41836
|
-
const raw = await (0,
|
|
42925
|
+
const raw = await (0, import_promises5.readFile)(this.authFilePath, "utf8");
|
|
41837
42926
|
const parsed = JSON.parse(raw);
|
|
41838
42927
|
const legacy = LegacyAuthSessionSchema.safeParse(parsed);
|
|
41839
42928
|
if (legacy.success) {
|
|
@@ -41869,17 +42958,17 @@ var AuthStore = class {
|
|
|
41869
42958
|
});
|
|
41870
42959
|
}
|
|
41871
42960
|
const normalized = normalizeState(validated.data);
|
|
41872
|
-
const directory = (0,
|
|
41873
|
-
await (0,
|
|
42961
|
+
const directory = (0, import_node_path6.dirname)(this.authFilePath);
|
|
42962
|
+
await (0, import_promises5.mkdir)(directory, {
|
|
41874
42963
|
recursive: true,
|
|
41875
42964
|
mode: 448
|
|
41876
42965
|
});
|
|
41877
|
-
await (0,
|
|
42966
|
+
await (0, import_promises5.writeFile)(this.authFilePath, `${JSON.stringify(normalized, null, 2)}
|
|
41878
42967
|
`, {
|
|
41879
42968
|
encoding: "utf8",
|
|
41880
42969
|
mode: 384
|
|
41881
42970
|
});
|
|
41882
|
-
await (0,
|
|
42971
|
+
await (0, import_promises5.chmod)(this.authFilePath, 384);
|
|
41883
42972
|
}
|
|
41884
42973
|
async getActiveProfile(apiBaseUrl) {
|
|
41885
42974
|
const normalizedApiBaseUrl = normalizeApiBaseUrl(apiBaseUrl);
|
|
@@ -42076,15 +43165,15 @@ var AuthStore = class {
|
|
|
42076
43165
|
await this.writeState(state);
|
|
42077
43166
|
}
|
|
42078
43167
|
async clear() {
|
|
42079
|
-
await (0,
|
|
43168
|
+
await (0, import_promises5.rm)(this.authFilePath, {
|
|
42080
43169
|
force: true
|
|
42081
43170
|
});
|
|
42082
43171
|
}
|
|
42083
43172
|
};
|
|
42084
43173
|
|
|
42085
43174
|
// src/services/environmentConfig.ts
|
|
42086
|
-
var
|
|
42087
|
-
var
|
|
43175
|
+
var import_promises6 = require("node:fs/promises");
|
|
43176
|
+
var import_node_path7 = require("node:path");
|
|
42088
43177
|
var ENVIRONMENT_ID_ALIASES = {
|
|
42089
43178
|
"local-development": "dev",
|
|
42090
43179
|
prod: "live"
|
|
@@ -42170,7 +43259,7 @@ var EnvironmentConfigService = class {
|
|
|
42170
43259
|
}
|
|
42171
43260
|
async readState() {
|
|
42172
43261
|
try {
|
|
42173
|
-
const raw = await (0,
|
|
43262
|
+
const raw = await (0, import_promises6.readFile)(this.configFilePath, "utf8");
|
|
42174
43263
|
const parsed = JSON.parse(raw);
|
|
42175
43264
|
const validated = EnvironmentConfigStateSchema.safeParse(parsed);
|
|
42176
43265
|
if (!validated.success) {
|
|
@@ -42204,17 +43293,17 @@ var EnvironmentConfigService = class {
|
|
|
42204
43293
|
});
|
|
42205
43294
|
}
|
|
42206
43295
|
const normalized = normalizeState2(validated.data);
|
|
42207
|
-
const directory = (0,
|
|
42208
|
-
await (0,
|
|
43296
|
+
const directory = (0, import_node_path7.dirname)(this.configFilePath);
|
|
43297
|
+
await (0, import_promises6.mkdir)(directory, {
|
|
42209
43298
|
recursive: true,
|
|
42210
43299
|
mode: 448
|
|
42211
43300
|
});
|
|
42212
|
-
await (0,
|
|
43301
|
+
await (0, import_promises6.writeFile)(this.configFilePath, `${JSON.stringify(normalized, null, 2)}
|
|
42213
43302
|
`, {
|
|
42214
43303
|
encoding: "utf8",
|
|
42215
43304
|
mode: 384
|
|
42216
43305
|
});
|
|
42217
|
-
await (0,
|
|
43306
|
+
await (0, import_promises6.chmod)(this.configFilePath, 384);
|
|
42218
43307
|
}
|
|
42219
43308
|
async getActiveEnvironment() {
|
|
42220
43309
|
const state = await this.#readStateWithDefaults();
|
|
@@ -42280,8 +43369,8 @@ var EnvironmentConfigService = class {
|
|
|
42280
43369
|
};
|
|
42281
43370
|
|
|
42282
43371
|
// src/services/tenantOpenApi.ts
|
|
42283
|
-
var
|
|
42284
|
-
var
|
|
43372
|
+
var import_promises7 = require("node:fs/promises");
|
|
43373
|
+
var import_node_path8 = require("node:path");
|
|
42285
43374
|
function resolveSourceUrl(tenantId, template) {
|
|
42286
43375
|
return template.replace("{tenantId}", encodeURIComponent(tenantId));
|
|
42287
43376
|
}
|
|
@@ -42295,7 +43384,7 @@ var TenantOpenApiService = class {
|
|
|
42295
43384
|
throw new AuthSessionError("Tenant ID is required to resolve OpenAPI spec path.");
|
|
42296
43385
|
}
|
|
42297
43386
|
const rootPath = this.params?.rootPath || TENANT_OPENAPI_ROOT_PATH;
|
|
42298
|
-
return (0,
|
|
43387
|
+
return (0, import_node_path8.join)(rootPath, normalizedTenantId, "openapi.json");
|
|
42299
43388
|
}
|
|
42300
43389
|
async downloadTenantOpenApi(tenantId) {
|
|
42301
43390
|
const normalizedTenantId = tenantId.trim();
|
|
@@ -42329,16 +43418,16 @@ var TenantOpenApiService = class {
|
|
|
42329
43418
|
});
|
|
42330
43419
|
}
|
|
42331
43420
|
const filePath = this.getTenantOpenApiFilePath(normalizedTenantId);
|
|
42332
|
-
await (0,
|
|
43421
|
+
await (0, import_promises7.mkdir)((0, import_node_path8.dirname)(filePath), {
|
|
42333
43422
|
recursive: true,
|
|
42334
43423
|
mode: 448
|
|
42335
43424
|
});
|
|
42336
|
-
await (0,
|
|
43425
|
+
await (0, import_promises7.writeFile)(filePath, `${JSON.stringify(parsedContent, null, 2)}
|
|
42337
43426
|
`, {
|
|
42338
43427
|
encoding: "utf8",
|
|
42339
43428
|
mode: 384
|
|
42340
43429
|
});
|
|
42341
|
-
await (0,
|
|
43430
|
+
await (0, import_promises7.chmod)(filePath, 384);
|
|
42342
43431
|
return {
|
|
42343
43432
|
tenantId: normalizedTenantId,
|
|
42344
43433
|
sourceUrl,
|
|
@@ -42362,6 +43451,7 @@ var ROOT_HELP_COMMANDS = [
|
|
|
42362
43451
|
{ command: "discover search <terms>", description: "Search in endpoint paths and entity names" },
|
|
42363
43452
|
{ command: "ds list <appSlug> <dataSourceSlug>", description: "List data source items" },
|
|
42364
43453
|
{ command: "apps list", description: "List apps" },
|
|
43454
|
+
{ command: "studio list-data-sources --appSlug <slug>", description: "List studio data sources" },
|
|
42365
43455
|
{ command: "curl <path>", description: "Send arbitrary API requests" }
|
|
42366
43456
|
];
|
|
42367
43457
|
function createDocyrusCli(params) {
|
|
@@ -42429,6 +43519,11 @@ function createDocyrusCli(params) {
|
|
|
42429
43519
|
environmentConfigService,
|
|
42430
43520
|
authStore
|
|
42431
43521
|
}));
|
|
43522
|
+
cli2.command(createStudioCli({
|
|
43523
|
+
createApiClient,
|
|
43524
|
+
environmentConfigService,
|
|
43525
|
+
authStore
|
|
43526
|
+
}));
|
|
42432
43527
|
cli2.command(createCurlCli({
|
|
42433
43528
|
createApiClient,
|
|
42434
43529
|
environmentConfigService,
|