@docyrus/docyrus 0.0.14 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/main.js +348 -58
  2. package/main.js.map +3 -3
  3. package/package.json +1 -1
package/main.js CHANGED
@@ -124678,7 +124678,7 @@ function buildInputSchema(args, env2, options2) {
124678
124678
  // package.json
124679
124679
  var package_default = {
124680
124680
  name: "@docyrus/docyrus",
124681
- version: "0.0.14",
124681
+ version: "0.0.16",
124682
124682
  private: false,
124683
124683
  description: "Docyrus API CLI",
124684
124684
  main: "./main.js",
@@ -125009,6 +125009,54 @@ function createAiCli(dependencies) {
125009
125009
  }
125010
125010
 
125011
125011
  // src/commands/appsCommands.ts
125012
+ function normalizeOptional(value) {
125013
+ const trimmed = value?.trim();
125014
+ return trimmed && trimmed.length > 0 ? trimmed : void 0;
125015
+ }
125016
+ function extractAppRecords(payload) {
125017
+ if (Array.isArray(payload)) {
125018
+ return payload.filter((item) => typeof item === "object" && item !== null);
125019
+ }
125020
+ if (typeof payload === "object" && payload !== null && Array.isArray(payload.data)) {
125021
+ return payload.data.filter((item) => typeof item === "object" && item !== null);
125022
+ }
125023
+ return [];
125024
+ }
125025
+ function extractString(record2, key) {
125026
+ const value = record2[key];
125027
+ return typeof value === "string" && value.length > 0 ? value : void 0;
125028
+ }
125029
+ async function resolveAppId(params) {
125030
+ const appId = normalizeOptional(params.appId);
125031
+ const appSlug = normalizeOptional(params.appSlug);
125032
+ if (appId && appSlug) {
125033
+ throw new UserInputError("Provide either --appId or --appSlug, not both.");
125034
+ }
125035
+ if (!appId && !appSlug) {
125036
+ throw new UserInputError("Provide --appId or --appSlug.");
125037
+ }
125038
+ if (appId) {
125039
+ return appId;
125040
+ }
125041
+ const response = await params.apiClient.request({
125042
+ method: "GET",
125043
+ path: "/apps"
125044
+ });
125045
+ const apps = extractAppRecords(response.data);
125046
+ const matches = apps.filter((item) => extractString(item, "slug") === appSlug);
125047
+ if (matches.length === 0) {
125048
+ throw new UserInputError(`App slug '${appSlug}' was not found.`);
125049
+ }
125050
+ if (matches.length > 1) {
125051
+ const matchingIds = matches.map((item) => extractString(item, "id")).filter((value) => Boolean(value));
125052
+ throw new UserInputError(`App slug '${appSlug}' is ambiguous. Matching IDs: ${matchingIds.join(", ")}`);
125053
+ }
125054
+ const resolvedId = extractString(matches[0], "id");
125055
+ if (!resolvedId) {
125056
+ throw new UserInputError(`App slug '${appSlug}' resolved to an invalid item without id.`);
125057
+ }
125058
+ return resolvedId;
125059
+ }
125012
125060
  function createAppsCli(dependencies) {
125013
125061
  const appsCli = Cli_exports.create("apps", {
125014
125062
  description: "App commands",
@@ -125036,6 +125084,81 @@ function createAppsCli(dependencies) {
125036
125084
  });
125037
125085
  }
125038
125086
  });
125087
+ appsCli.command("delete", {
125088
+ description: "Archive an app",
125089
+ options: external_exports.object({
125090
+ appId: external_exports.string().optional().describe("App ID"),
125091
+ appSlug: external_exports.string().optional().describe("App slug")
125092
+ }),
125093
+ run: async (context) => {
125094
+ const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
125095
+ const apiClient = dependencies.createApiClient(apiBaseUrl);
125096
+ const appId = await resolveAppId({
125097
+ apiClient,
125098
+ appId: context.options.appId,
125099
+ appSlug: context.options.appSlug
125100
+ });
125101
+ const response = await apiClient.request({
125102
+ method: "DELETE",
125103
+ path: `/dev/apps/${appId}`
125104
+ });
125105
+ return await injectContext({
125106
+ apiBaseUrl,
125107
+ authStore: dependencies.authStore,
125108
+ payload: response.data
125109
+ });
125110
+ }
125111
+ });
125112
+ appsCli.command("restore", {
125113
+ description: "Restore an archived app",
125114
+ options: external_exports.object({
125115
+ appId: external_exports.string().optional().describe("App ID"),
125116
+ appSlug: external_exports.string().optional().describe("App slug")
125117
+ }),
125118
+ run: async (context) => {
125119
+ const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
125120
+ const apiClient = dependencies.createApiClient(apiBaseUrl);
125121
+ const appId = await resolveAppId({
125122
+ apiClient,
125123
+ appId: context.options.appId,
125124
+ appSlug: context.options.appSlug
125125
+ });
125126
+ const response = await apiClient.request({
125127
+ method: "POST",
125128
+ path: `/dev/apps/${appId}/restore`
125129
+ });
125130
+ return await injectContext({
125131
+ apiBaseUrl,
125132
+ authStore: dependencies.authStore,
125133
+ payload: response.data
125134
+ });
125135
+ }
125136
+ });
125137
+ appsCli.command("permanent-delete", {
125138
+ description: "Permanently delete an app",
125139
+ options: external_exports.object({
125140
+ appId: external_exports.string().optional().describe("App ID"),
125141
+ appSlug: external_exports.string().optional().describe("App slug")
125142
+ }),
125143
+ run: async (context) => {
125144
+ const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
125145
+ const apiClient = dependencies.createApiClient(apiBaseUrl);
125146
+ const appId = await resolveAppId({
125147
+ apiClient,
125148
+ appId: context.options.appId,
125149
+ appSlug: context.options.appSlug
125150
+ });
125151
+ const response = await apiClient.request({
125152
+ method: "DELETE",
125153
+ path: `/dev/apps/${appId}/permanent`
125154
+ });
125155
+ return await injectContext({
125156
+ apiBaseUrl,
125157
+ authStore: dependencies.authStore,
125158
+ payload: response.data
125159
+ });
125160
+ }
125161
+ });
125039
125162
  return appsCli;
125040
125163
  }
125041
125164
 
@@ -126104,7 +126227,7 @@ function parseOpenApiDocument(raw) {
126104
126227
  }
126105
126228
  return parsed;
126106
126229
  }
126107
- async function loadOpenApiSpec(dependencies, tenantId) {
126230
+ async function loadOpenApiSpec(dependencies, tenantId, options2) {
126108
126231
  let filePath = dependencies.tenantOpenApiService.getTenantOpenApiFilePath(tenantId);
126109
126232
  let downloaded = false;
126110
126233
  let sourceUrl;
@@ -126118,7 +126241,7 @@ async function loadOpenApiSpec(dependencies, tenantId) {
126118
126241
  cause: error48
126119
126242
  });
126120
126243
  }
126121
- const downloadResult = await dependencies.tenantOpenApiService.downloadTenantOpenApi(tenantId);
126244
+ const downloadResult = await dependencies.tenantOpenApiService.downloadTenantOpenApi(tenantId, options2);
126122
126245
  downloaded = true;
126123
126246
  sourceUrl = downloadResult.sourceUrl;
126124
126247
  filePath = downloadResult.filePath;
@@ -126137,11 +126260,15 @@ async function withActiveTenantSpec(dependencies) {
126137
126260
  if (!activeProfile) {
126138
126261
  throw new AuthSessionError("No active session found. Run 'docyrus auth login'.");
126139
126262
  }
126140
- const spec = await loadOpenApiSpec(dependencies, activeProfile.tenantId);
126263
+ const authSessionService = dependencies.createAuthSessionService(apiBaseUrl);
126264
+ const authToken = await authSessionService.getValidAccessToken();
126141
126265
  return {
126142
126266
  apiBaseUrl,
126143
126267
  activeProfile,
126144
- spec
126268
+ spec: await loadOpenApiSpec(dependencies, activeProfile.tenantId, {
126269
+ apiBaseUrl,
126270
+ authToken
126271
+ })
126145
126272
  };
126146
126273
  }
126147
126274
  function createDiscoverCli(dependencies) {
@@ -126157,7 +126284,12 @@ function createDiscoverCli(dependencies) {
126157
126284
  if (!activeProfile) {
126158
126285
  throw new AuthSessionError("No active session found. Run 'docyrus auth login'.");
126159
126286
  }
126160
- const downloaded = await dependencies.tenantOpenApiService.downloadTenantOpenApi(activeProfile.tenantId);
126287
+ const authSessionService = dependencies.createAuthSessionService(apiBaseUrl);
126288
+ const authToken = await authSessionService.getValidAccessToken();
126289
+ const downloaded = await dependencies.tenantOpenApiService.downloadTenantOpenApi(activeProfile.tenantId, {
126290
+ apiBaseUrl,
126291
+ authToken
126292
+ });
126161
126293
  return await injectContext({
126162
126294
  apiBaseUrl,
126163
126295
  authStore: dependencies.authStore,
@@ -126454,7 +126586,7 @@ function normalizeBatchPayload(payload, key) {
126454
126586
  function isRecord4(value) {
126455
126587
  return typeof value === "object" && value !== null;
126456
126588
  }
126457
- function extractString(record2, key) {
126589
+ function extractString2(record2, key) {
126458
126590
  const value = record2[key];
126459
126591
  return typeof value === "string" && value.length > 0 ? value : void 0;
126460
126592
  }
@@ -126475,20 +126607,20 @@ function ensureExclusiveSelector(label, idValue, slugValue) {
126475
126607
  throw new UserInputError(`Provide --${label}Id or --${label}Slug.`);
126476
126608
  }
126477
126609
  }
126478
- function normalizeOptional(value) {
126610
+ function normalizeOptional2(value) {
126479
126611
  const trimmed = value?.trim();
126480
126612
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
126481
126613
  }
126482
126614
  function resolveBySlug(label, items, slug) {
126483
- const matches = items.filter((item) => extractString(item, "slug") === slug);
126615
+ const matches = items.filter((item) => extractString2(item, "slug") === slug);
126484
126616
  if (matches.length === 0) {
126485
126617
  throw new UserInputError(`${label} slug '${slug}' was not found.`);
126486
126618
  }
126487
126619
  if (matches.length > 1) {
126488
- const matchingIds = matches.map((item) => extractString(item, "id")).filter((id) => Boolean(id));
126620
+ const matchingIds = matches.map((item) => extractString2(item, "id")).filter((id) => Boolean(id));
126489
126621
  throw new UserInputError(`${label} slug '${slug}' is ambiguous. Matching IDs: ${matchingIds.join(", ")}`);
126490
126622
  }
126491
- const matchId = extractString(matches[0], "id");
126623
+ const matchId = extractString2(matches[0], "id");
126492
126624
  if (!matchId) {
126493
126625
  throw new UserInputError(`${label} slug '${slug}' resolved to an invalid item without id.`);
126494
126626
  }
@@ -126502,8 +126634,8 @@ var StudioResolver = class {
126502
126634
  #dataSourcesByAppId = /* @__PURE__ */ new Map();
126503
126635
  #fieldsByAppAndDataSource = /* @__PURE__ */ new Map();
126504
126636
  async resolveAppId(options2) {
126505
- const appId = normalizeOptional(options2.appId);
126506
- const appSlug = normalizeOptional(options2.appSlug);
126637
+ const appId = normalizeOptional2(options2.appId);
126638
+ const appSlug = normalizeOptional2(options2.appSlug);
126507
126639
  ensureExclusiveSelector("app", appId, appSlug);
126508
126640
  if (appId) {
126509
126641
  return appId;
@@ -126512,8 +126644,8 @@ var StudioResolver = class {
126512
126644
  return resolveBySlug("App", apps, appSlug);
126513
126645
  }
126514
126646
  async resolveDataSourceId(options2) {
126515
- const dataSourceId = normalizeOptional(options2.dataSourceId);
126516
- const dataSourceSlug = normalizeOptional(options2.dataSourceSlug);
126647
+ const dataSourceId = normalizeOptional2(options2.dataSourceId);
126648
+ const dataSourceSlug = normalizeOptional2(options2.dataSourceSlug);
126517
126649
  ensureExclusiveSelector("dataSource", dataSourceId, dataSourceSlug);
126518
126650
  if (dataSourceId) {
126519
126651
  return dataSourceId;
@@ -126522,8 +126654,8 @@ var StudioResolver = class {
126522
126654
  return resolveBySlug("Data source", dataSources, dataSourceSlug);
126523
126655
  }
126524
126656
  async resolveFieldId(options2) {
126525
- const fieldId = normalizeOptional(options2.fieldId);
126526
- const fieldSlug = normalizeOptional(options2.fieldSlug);
126657
+ const fieldId = normalizeOptional2(options2.fieldId);
126658
+ const fieldSlug = normalizeOptional2(options2.fieldSlug);
126527
126659
  ensureExclusiveSelector("field", fieldId, fieldSlug);
126528
126660
  if (fieldId) {
126529
126661
  return fieldId;
@@ -126630,6 +126762,65 @@ function requireNonEmptyObject(payload, label) {
126630
126762
  throw new UserInputError(`${label} payload is empty. Provide flags, --data, or --from-file.`);
126631
126763
  }
126632
126764
  }
126765
+ function isRecord5(value) {
126766
+ return typeof value === "object" && value !== null && !Array.isArray(value);
126767
+ }
126768
+ function normalizeBatchUpdateFieldItem(item) {
126769
+ if (!isRecord5(item)) {
126770
+ return item;
126771
+ }
126772
+ const normalized = {
126773
+ ...item
126774
+ };
126775
+ if (!("fieldId" in normalized) && typeof normalized.id === "string") {
126776
+ normalized.fieldId = normalized.id;
126777
+ }
126778
+ if (!("readOnly" in normalized) && "read_only" in normalized) {
126779
+ normalized.readOnly = normalized.read_only;
126780
+ }
126781
+ if (!("defaultValue" in normalized) && "default_value" in normalized) {
126782
+ normalized.defaultValue = normalized.default_value;
126783
+ }
126784
+ if (!("relationDataSourceId" in normalized) && "relation_data_source_id" in normalized) {
126785
+ normalized.relationDataSourceId = normalized.relation_data_source_id;
126786
+ }
126787
+ if (!("editorOptions" in normalized) && "options" in normalized) {
126788
+ normalized.editorOptions = normalized.options;
126789
+ }
126790
+ return normalized;
126791
+ }
126792
+ function normalizeBatchUpdateFieldsPayload(payload) {
126793
+ const fields = payload.fields;
126794
+ if (!Array.isArray(fields)) {
126795
+ return payload;
126796
+ }
126797
+ return {
126798
+ ...payload,
126799
+ fields: fields.map((item) => normalizeBatchUpdateFieldItem(item))
126800
+ };
126801
+ }
126802
+ function normalizeUpdateEnumItem(item) {
126803
+ if (!isRecord5(item)) {
126804
+ return item;
126805
+ }
126806
+ if (!("enumId" in item) && typeof item.id === "string") {
126807
+ return {
126808
+ ...item,
126809
+ enumId: item.id
126810
+ };
126811
+ }
126812
+ return item;
126813
+ }
126814
+ function normalizeUpdateEnumsPayload(payload) {
126815
+ const enums = payload.enums;
126816
+ if (!Array.isArray(enums)) {
126817
+ return payload;
126818
+ }
126819
+ return {
126820
+ ...payload,
126821
+ enums: enums.map((item) => normalizeUpdateEnumItem(item))
126822
+ };
126823
+ }
126633
126824
  function createStudioCli(dependencies) {
126634
126825
  const studioCli = Cli_exports.create("studio", {
126635
126826
  description: "Studio (dev app data source CRUD) commands",
@@ -126768,7 +126959,7 @@ function createStudioCli(dependencies) {
126768
126959
  }
126769
126960
  });
126770
126961
  studioCli.command("delete-data-source", {
126771
- description: "Delete a data source",
126962
+ description: "Archive a data source",
126772
126963
  options: external_exports.object({
126773
126964
  appId: external_exports.string().optional().describe("App ID"),
126774
126965
  appSlug: external_exports.string().optional().describe("App slug"),
@@ -126793,6 +126984,46 @@ function createStudioCli(dependencies) {
126793
126984
  return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
126794
126985
  }
126795
126986
  });
126987
+ studioCli.command("restore-data-source", {
126988
+ description: "Restore an archived data source",
126989
+ options: external_exports.object({
126990
+ appId: external_exports.string().optional().describe("App ID"),
126991
+ appSlug: external_exports.string().optional().describe("App slug"),
126992
+ dataSourceId: external_exports.string().min(1).describe("Data source ID")
126993
+ }),
126994
+ run: async (context) => {
126995
+ const studio = await getStudioRunContext(dependencies);
126996
+ const appId = await studio.resolver.resolveAppId({
126997
+ appId: context.options.appId,
126998
+ appSlug: context.options.appSlug
126999
+ });
127000
+ const response = await studio.apiClient.request({
127001
+ method: "POST",
127002
+ path: `/dev/apps/${appId}/data-sources/${context.options.dataSourceId}/restore`
127003
+ });
127004
+ return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
127005
+ }
127006
+ });
127007
+ studioCli.command("permanent-delete-data-source", {
127008
+ description: "Permanently delete a data source",
127009
+ options: external_exports.object({
127010
+ appId: external_exports.string().optional().describe("App ID"),
127011
+ appSlug: external_exports.string().optional().describe("App slug"),
127012
+ dataSourceId: external_exports.string().min(1).describe("Data source ID")
127013
+ }),
127014
+ run: async (context) => {
127015
+ const studio = await getStudioRunContext(dependencies);
127016
+ const appId = await studio.resolver.resolveAppId({
127017
+ appId: context.options.appId,
127018
+ appSlug: context.options.appSlug
127019
+ });
127020
+ const response = await studio.apiClient.request({
127021
+ method: "DELETE",
127022
+ path: `/dev/apps/${appId}/data-sources/${context.options.dataSourceId}/permanent`
127023
+ });
127024
+ return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
127025
+ }
127026
+ });
126796
127027
  studioCli.command("bulk-create-data-sources", {
126797
127028
  description: "Bulk create data sources",
126798
127029
  options: external_exports.object({
@@ -127086,10 +127317,11 @@ function createStudioCli(dependencies) {
127086
127317
  }),
127087
127318
  "fields"
127088
127319
  );
127320
+ const normalizedPayload = normalizeBatchUpdateFieldsPayload(payload);
127089
127321
  const response = await studio.apiClient.request({
127090
127322
  method: "PATCH",
127091
127323
  path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/batch`,
127092
- body: payload
127324
+ body: normalizedPayload
127093
127325
  });
127094
127326
  return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
127095
127327
  }
@@ -127250,10 +127482,11 @@ function createStudioCli(dependencies) {
127250
127482
  }),
127251
127483
  "enums"
127252
127484
  );
127485
+ const normalizedPayload = normalizeUpdateEnumsPayload(payload);
127253
127486
  const response = await studio.apiClient.request({
127254
127487
  method: "PATCH",
127255
127488
  path: `/dev/apps/${appId}/data-sources/${dataSourceId}/fields/${fieldId}/enums`,
127256
- body: payload
127489
+ body: normalizedPayload
127257
127490
  });
127258
127491
  return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
127259
127492
  }
@@ -127587,7 +127820,7 @@ var ApiClient = class {
127587
127820
 
127588
127821
  // src/services/authSession.ts
127589
127822
  var DEFAULT_MANUAL_ACCESS_TOKEN_EXPIRY_SECONDS = 3600;
127590
- function isRecord5(value) {
127823
+ function isRecord6(value) {
127591
127824
  return typeof value === "object" && value !== null;
127592
127825
  }
127593
127826
  function extractRecordValue(record2, keys) {
@@ -127598,7 +127831,7 @@ function extractRecordValue(record2, keys) {
127598
127831
  }
127599
127832
  return void 0;
127600
127833
  }
127601
- function extractString2(record2, keys) {
127834
+ function extractString3(record2, keys) {
127602
127835
  const value = extractRecordValue(record2, keys);
127603
127836
  return typeof value === "string" && value.length > 0 ? value : void 0;
127604
127837
  }
@@ -127900,15 +128133,15 @@ var AuthSessionService = class {
127900
128133
  fetchFn: this.params.fetchFn
127901
128134
  });
127902
128135
  const payload = response.data;
127903
- const dataCandidate = isRecord5(payload) && isRecord5(payload.data) ? payload.data : payload;
127904
- if (!isRecord5(dataCandidate)) {
128136
+ const dataCandidate = isRecord6(payload) && isRecord6(payload.data) ? payload.data : payload;
128137
+ if (!isRecord6(dataCandidate)) {
127905
128138
  throw new AuthSessionError("Unable to parse /users/me response.");
127906
128139
  }
127907
- const tenantCandidate = isRecord5(dataCandidate.tenant) ? dataCandidate.tenant : void 0;
127908
- const userId = extractString2(dataCandidate, ["id", "user_id"]);
127909
- const email3 = extractString2(dataCandidate, ["email"]);
127910
- const tenantId = tenantCandidate ? extractString2(tenantCandidate, ["id"]) : extractString2(dataCandidate, ["tenant_id", "tenantId"]);
127911
- const tenantName = tenantCandidate ? extractString2(tenantCandidate, ["name"]) : extractString2(dataCandidate, ["tenant_name", "tenantName"]);
128140
+ const tenantCandidate = isRecord6(dataCandidate.tenant) ? dataCandidate.tenant : void 0;
128141
+ const userId = extractString3(dataCandidate, ["id", "user_id"]);
128142
+ const email3 = extractString3(dataCandidate, ["email"]);
128143
+ const tenantId = tenantCandidate ? extractString3(tenantCandidate, ["id"]) : extractString3(dataCandidate, ["tenant_id", "tenantId"]);
128144
+ const tenantName = tenantCandidate ? extractString3(tenantCandidate, ["name"]) : extractString3(dataCandidate, ["tenant_name", "tenantName"]);
127912
128145
  const tenantNo = tenantCandidate ? extractNumber(tenantCandidate, ["no", "tenant_no"]) : extractNumber(dataCandidate, ["tenant_no", "tenantNo"]);
127913
128146
  if (!userId || !email3 || !tenantId || !tenantName || !tenantNo) {
127914
128147
  throw new AuthSessionError("Incomplete identity data returned from /users/me.");
@@ -127930,17 +128163,17 @@ var AuthSessionService = class {
127930
128163
  fetchFn: this.params.fetchFn
127931
128164
  });
127932
128165
  const payload = response.data;
127933
- const listCandidate = Array.isArray(payload) ? payload : isRecord5(payload) && Array.isArray(payload.data) ? payload.data : null;
128166
+ const listCandidate = Array.isArray(payload) ? payload : isRecord6(payload) && Array.isArray(payload.data) ? payload.data : null;
127934
128167
  if (!listCandidate) {
127935
128168
  throw new AuthSessionError("Unable to parse tenant catalog response.");
127936
128169
  }
127937
128170
  const mapped = [];
127938
128171
  for (const item of listCandidate) {
127939
- if (!isRecord5(item)) {
128172
+ if (!isRecord6(item)) {
127940
128173
  continue;
127941
128174
  }
127942
- const tenantId = extractString2(item, ["id", "tenant_id"]);
127943
- const tenantName = extractString2(item, ["name"]);
128175
+ const tenantId = extractString3(item, ["id", "tenant_id"]);
128176
+ const tenantName = extractString3(item, ["name"]);
127944
128177
  const tenantNo = extractNumber(item, ["tenant_no", "tenantNo", "no"]);
127945
128178
  const logoValue = extractRecordValue(item, ["logo"]);
127946
128179
  const logo = typeof logoValue === "string" || logoValue === null ? logoValue : void 0;
@@ -128618,10 +128851,66 @@ var import_node_path9 = require("node:path");
128618
128851
  function resolveSourceUrl(tenantId, template) {
128619
128852
  return template.replace("{tenantId}", encodeURIComponent(tenantId));
128620
128853
  }
128854
+ async function parseOpenApiJsonResponse(response, params) {
128855
+ const content = await response.text();
128856
+ let parsedContent;
128857
+ try {
128858
+ parsedContent = JSON.parse(content);
128859
+ } catch (error48) {
128860
+ throw new AuthSessionError("Downloaded tenant OpenAPI spec is invalid JSON.", {
128861
+ tenantId: params.tenantId,
128862
+ sourceUrl: params.sourceUrl,
128863
+ cause: error48
128864
+ });
128865
+ }
128866
+ return parsedContent;
128867
+ }
128621
128868
  var TenantOpenApiService = class {
128622
128869
  constructor(params) {
128623
128870
  this.params = params;
128624
128871
  }
128872
+ async #writeOpenApiFile(tenantId, parsedContent) {
128873
+ const filePath = this.getTenantOpenApiFilePath(tenantId);
128874
+ await (0, import_promises7.mkdir)((0, import_node_path9.dirname)(filePath), {
128875
+ recursive: true,
128876
+ mode: 448
128877
+ });
128878
+ await (0, import_promises7.writeFile)(filePath, `${JSON.stringify(parsedContent, null, 2)}
128879
+ `, {
128880
+ encoding: "utf8",
128881
+ mode: 384
128882
+ });
128883
+ await (0, import_promises7.chmod)(filePath, 384);
128884
+ return filePath;
128885
+ }
128886
+ async #generateTenantOpenApiViaAuthenticatedEndpoint(tenantId, options2) {
128887
+ if (!options2.apiBaseUrl || !options2.authToken) {
128888
+ throw new AuthSessionError("Failed to download tenant OpenAPI spec.", {
128889
+ tenantId,
128890
+ reason: "OpenAPI file is missing and no authenticated fallback request could be made."
128891
+ });
128892
+ }
128893
+ const apiUrl = `${normalizeApiBaseUrl(options2.apiBaseUrl)}/api/openapi.json`;
128894
+ const response = await (this.params?.fetchFn || fetch)(apiUrl, {
128895
+ method: "GET",
128896
+ headers: {
128897
+ Accept: "application/json",
128898
+ Authorization: `Bearer ${options2.authToken}`
128899
+ }
128900
+ });
128901
+ if (!response.ok) {
128902
+ throw new AuthSessionError("Failed to generate tenant OpenAPI spec via authenticated endpoint.", {
128903
+ tenantId,
128904
+ sourceUrl: apiUrl,
128905
+ status: response.status,
128906
+ statusText: response.statusText
128907
+ });
128908
+ }
128909
+ return await parseOpenApiJsonResponse(response, {
128910
+ tenantId,
128911
+ sourceUrl: apiUrl
128912
+ });
128913
+ }
128625
128914
  getTenantOpenApiFilePath(tenantId) {
128626
128915
  const normalizedTenantId = tenantId.trim();
128627
128916
  if (!normalizedTenantId) {
@@ -128630,7 +128919,7 @@ var TenantOpenApiService = class {
128630
128919
  const rootPath = this.params?.rootPath || TENANT_OPENAPI_ROOT_PATH;
128631
128920
  return (0, import_node_path9.join)(rootPath, normalizedTenantId, "openapi.json");
128632
128921
  }
128633
- async downloadTenantOpenApi(tenantId) {
128922
+ async downloadTenantOpenApi(tenantId, options2 = {}) {
128634
128923
  const normalizedTenantId = tenantId.trim();
128635
128924
  if (!normalizedTenantId) {
128636
128925
  throw new AuthSessionError("Tenant ID is required to download OpenAPI spec.");
@@ -128643,35 +128932,34 @@ var TenantOpenApiService = class {
128643
128932
  method: "GET"
128644
128933
  });
128645
128934
  if (!response.ok) {
128646
- throw new AuthSessionError("Failed to download tenant OpenAPI spec.", {
128647
- tenantId: normalizedTenantId,
128648
- sourceUrl,
128649
- status: response.status,
128650
- statusText: response.statusText
128935
+ if (response.status !== 404) {
128936
+ throw new AuthSessionError("Failed to download tenant OpenAPI spec.", {
128937
+ tenantId: normalizedTenantId,
128938
+ sourceUrl,
128939
+ status: response.status,
128940
+ statusText: response.statusText
128941
+ });
128942
+ }
128943
+ const generatedSpec = await this.#generateTenantOpenApiViaAuthenticatedEndpoint(normalizedTenantId, options2);
128944
+ const retryResponse = await (this.params?.fetchFn || fetch)(sourceUrl, {
128945
+ method: "GET"
128651
128946
  });
128652
- }
128653
- const content = await response.text();
128654
- let parsedContent;
128655
- try {
128656
- parsedContent = JSON.parse(content);
128657
- } catch (error48) {
128658
- throw new AuthSessionError("Downloaded tenant OpenAPI spec is invalid JSON.", {
128947
+ const parsedContent2 = retryResponse.ok ? await parseOpenApiJsonResponse(retryResponse, {
128948
+ tenantId: normalizedTenantId,
128949
+ sourceUrl
128950
+ }) : generatedSpec;
128951
+ const filePath2 = await this.#writeOpenApiFile(normalizedTenantId, parsedContent2);
128952
+ return {
128659
128953
  tenantId: normalizedTenantId,
128660
128954
  sourceUrl,
128661
- cause: error48
128662
- });
128955
+ filePath: filePath2
128956
+ };
128663
128957
  }
128664
- const filePath = this.getTenantOpenApiFilePath(normalizedTenantId);
128665
- await (0, import_promises7.mkdir)((0, import_node_path9.dirname)(filePath), {
128666
- recursive: true,
128667
- mode: 448
128668
- });
128669
- await (0, import_promises7.writeFile)(filePath, `${JSON.stringify(parsedContent, null, 2)}
128670
- `, {
128671
- encoding: "utf8",
128672
- mode: 384
128958
+ const parsedContent = await parseOpenApiJsonResponse(response, {
128959
+ tenantId: normalizedTenantId,
128960
+ sourceUrl
128673
128961
  });
128674
- await (0, import_promises7.chmod)(filePath, 384);
128962
+ const filePath = await this.#writeOpenApiFile(normalizedTenantId, parsedContent);
128675
128963
  return {
128676
128964
  tenantId: normalizedTenantId,
128677
128965
  sourceUrl,
@@ -128698,6 +128986,7 @@ var ROOT_HELP_COMMANDS = [
128698
128986
  { command: "discover search <terms>", description: "Search in endpoint paths and entity names" },
128699
128987
  { command: "ds list <appSlug> <dataSourceSlug>", description: "List data source items" },
128700
128988
  { command: "apps list", description: "List apps" },
128989
+ { command: "apps delete --appId <id>", description: "Archive an app" },
128701
128990
  { command: "studio list-data-sources --appSlug <slug>", description: "List studio data sources" },
128702
128991
  { command: "tui", description: "Launch terminal UI (OpenTUI, requires Bun)" },
128703
128992
  { command: "curl <path>", description: "Send arbitrary API requests" }
@@ -128773,6 +129062,7 @@ function createDocyrusCli(params) {
128773
129062
  }));
128774
129063
  cli2.command(createDiscoverCli({
128775
129064
  environmentConfigService,
129065
+ createAuthSessionService,
128776
129066
  authStore,
128777
129067
  tenantOpenApiService
128778
129068
  }));