@veltrixsecops/app-sdk 2.5.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,8 @@ function toInventoryItem(raw) {
22
22
  domains: Array.isArray(raw.domains) ? raw.domains : [],
23
23
  ipRanges: Array.isArray(raw.ipRanges) ? raw.ipRanges : [],
24
24
  tags: Array.isArray(raw.tags) ? raw.tags.map((tag) => ({ id: String(tag.id), name: String(tag.name) })) : [],
25
- connectivityProviderId: raw.connectivityProviderId ?? null
25
+ connectivityProviderId: raw.connectivityProviderId ?? null,
26
+ credentialId: raw.credentialId ?? null
26
27
  };
27
28
  }
28
29
  async function resolveTool(name) {
@@ -63,10 +64,9 @@ async function removeInventoryItem(id) {
63
64
  if (!res.ok && res.status !== 204) throw await inventoryError(res);
64
65
  }
65
66
 
66
- // src/client/access-servers.ts
67
- var ACCESS_SERVERS_API = "/api/access-servers";
67
+ // src/client/connectivity.ts
68
68
  var CONNECTIVITY_PROVIDERS_API = "/api/connectivity-providers";
69
- async function accessServerError(res) {
69
+ async function providerError(res) {
70
70
  const text = await res.text().catch(() => "");
71
71
  if (text) {
72
72
  try {
@@ -79,52 +79,9 @@ async function accessServerError(res) {
79
79
  }
80
80
  return new Error(`HTTP ${res.status}`);
81
81
  }
82
- function toAccessServer(raw) {
83
- return {
84
- id: String(raw.id),
85
- name: raw.name ?? "",
86
- endpoint: raw.endpoint ?? "",
87
- type: raw.type ?? void 0,
88
- region: raw.region ?? null,
89
- status: raw.status ?? void 0,
90
- description: raw.description ?? null,
91
- connectivityProviderId: raw.connectivityProviderId ?? null,
92
- connectivityProvider: raw.connectivityProvider ? { id: String(raw.connectivityProvider.id), name: String(raw.connectivityProvider.name) } : null
93
- };
94
- }
95
- async function listAccessServers() {
96
- const res = await authFetch(ACCESS_SERVERS_API);
97
- if (!res.ok) throw await accessServerError(res);
98
- const data = await res.json();
99
- return Array.isArray(data) ? data.map(toAccessServer) : [];
100
- }
101
- async function addAccessServer(input) {
102
- const res = await authFetch(ACCESS_SERVERS_API, {
103
- method: "POST",
104
- headers: { "Content-Type": "application/json" },
105
- body: JSON.stringify(input)
106
- });
107
- if (!res.ok) throw await accessServerError(res);
108
- return toAccessServer(await res.json());
109
- }
110
- async function updateAccessServer(id, input) {
111
- const res = await authFetch(`${ACCESS_SERVERS_API}/${encodeURIComponent(id)}`, {
112
- method: "PUT",
113
- headers: { "Content-Type": "application/json" },
114
- body: JSON.stringify(input)
115
- });
116
- if (!res.ok) throw await accessServerError(res);
117
- return toAccessServer(await res.json());
118
- }
119
- async function removeAccessServer(id) {
120
- const res = await authFetch(`${ACCESS_SERVERS_API}/${encodeURIComponent(id)}`, {
121
- method: "DELETE"
122
- });
123
- if (!res.ok && res.status !== 204) throw await accessServerError(res);
124
- }
125
82
  async function listConnectivityProviders() {
126
83
  const res = await authFetch(CONNECTIVITY_PROVIDERS_API);
127
- if (!res.ok) throw await accessServerError(res);
84
+ if (!res.ok) throw await providerError(res);
128
85
  const body = await res.json();
129
86
  const providers = Array.isArray(body) ? body : Array.isArray(body?.data) ? body.data : [];
130
87
  return providers.map((provider) => ({
@@ -151,12 +108,15 @@ async function credentialError(res) {
151
108
  return new Error(`HTTP ${res.status}`);
152
109
  }
153
110
  function toCredentialSummary(raw) {
154
- const hasSecret = Boolean(raw.apiToken && raw.apiToken.length > 0 || raw.password && raw.password.length > 0);
111
+ const hasSecret = Boolean(
112
+ raw.hasApiToken || raw.hasPassword || raw.apiToken && raw.apiToken.length > 0 || raw.password && raw.password.length > 0
113
+ );
155
114
  return {
156
115
  id: String(raw.id),
157
116
  name: raw.name ?? "",
158
117
  username: raw.username ?? "",
159
118
  type: raw.type ?? null,
119
+ endpoint: raw.endpoint ?? null,
160
120
  toolId: raw.toolId ?? "",
161
121
  hasSecret
162
122
  };
@@ -178,6 +138,7 @@ async function createCredential(input) {
178
138
  password: input.password ?? "",
179
139
  apiToken: input.apiToken,
180
140
  type: input.type,
141
+ endpoint: input.endpoint,
181
142
  toolId: input.toolId,
182
143
  tagIds: input.tagIds ?? []
183
144
  })
@@ -193,6 +154,7 @@ async function updateCredential(id, input) {
193
154
  if (input.password !== void 0) body.password = input.password;
194
155
  if (input.apiToken !== void 0) body.apiToken = input.apiToken;
195
156
  if (input.type !== void 0) body.type = input.type;
157
+ if (input.endpoint !== void 0) body.endpoint = input.endpoint;
196
158
  if (input.tagIds !== void 0) body.tagIds = input.tagIds;
197
159
  const res = await authFetch(`${CREDENTIALS_API}/${encodeURIComponent(id)}`, {
198
160
  method: "PUT",
@@ -237,10 +199,6 @@ export {
237
199
  addInventoryItem,
238
200
  updateInventoryItem,
239
201
  removeInventoryItem,
240
- listAccessServers,
241
- addAccessServer,
242
- updateAccessServer,
243
- removeAccessServer,
244
202
  listConnectivityProviders,
245
203
  listCredentials,
246
204
  createCredential,
@@ -251,4 +209,4 @@ export {
251
209
  requireHostRuntime,
252
210
  authFetch
253
211
  };
254
- //# sourceMappingURL=chunk-EVCWQYQY.js.map
212
+ //# sourceMappingURL=chunk-NY6C4REE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client/inventory.ts","../src/client/connectivity.ts","../src/client/credentials.ts","../src/client/index.ts"],"sourcesContent":["// ========================================================================\n// Inventory — the deployment targets an app can deploy configuration to.\n//\n// \"Inventory\" is the app-facing name for the platform's *components*: the\n// servers (hostname/port), domains, and IP/CIDR ranges a customer has\n// registered as deploy targets. These helpers are a typed, convenient\n// surface over the platform's components API (/api/components), enriched\n// with `domains` and `ipRanges`.\n//\n// Framework-free (no React) — safe to import from any client code. Every\n// call goes through the same `authFetch` the '/client' subpath exports, so\n// requests carry the platform's Authorization header. Non-2xx responses are\n// surfaced as thrown Errors carrying the platform's error text.\n// ========================================================================\n\nimport type { InventoryItem, InventoryItemInput } from '../types/platform'\nimport { authFetch } from './index'\n\n/** Base route for the platform's components (inventory) API. */\nconst INVENTORY_API = '/api/components'\n\n/**\n * Loosely-typed shape of a raw component as returned by the platform, before\n * it is normalized down to the {@link InventoryItem} surface.\n */\ninterface RawInventoryItem {\n id: string\n hostname?: string\n port?: string\n type?: string[]\n domains?: string[]\n ipRanges?: string[]\n tags?: Array<{ id: string; name: string }>\n connectivityProviderId?: string | null\n credentialId?: string | null\n}\n\n/** Build an Error from a non-2xx response, preferring the platform's message. */\nasync function inventoryError(res: Response): Promise<Error> {\n const text = await res.text().catch(() => '')\n if (text) {\n try {\n const body = JSON.parse(text) as { error?: string; message?: string }\n const message = body?.error ?? body?.message\n if (message) return new Error(message)\n } catch {\n // Body was not JSON — fall through and use the raw text.\n }\n return new Error(text)\n }\n return new Error(`HTTP ${res.status}`)\n}\n\n/** Normalize a raw platform component into the typed InventoryItem surface. */\nfunction toInventoryItem(raw: RawInventoryItem): InventoryItem {\n return {\n id: String(raw.id),\n hostname: raw.hostname ?? '',\n port: raw.port ?? undefined,\n type: Array.isArray(raw.type) ? raw.type : undefined,\n domains: Array.isArray(raw.domains) ? raw.domains : [],\n ipRanges: Array.isArray(raw.ipRanges) ? raw.ipRanges : [],\n tags: Array.isArray(raw.tags)\n ? raw.tags.map((tag) => ({ id: String(tag.id), name: String(tag.name) }))\n : [],\n connectivityProviderId: raw.connectivityProviderId ?? null,\n credentialId: raw.credentialId ?? null,\n }\n}\n\n/**\n * A platform Tool. Each installed app is upserted as a Tool keyed by its\n * manifest `name`, and inventory items (components) belong to a tool.\n */\nexport interface Tool {\n id: string\n name: string\n vendor?: string\n}\n\n/**\n * Resolve the platform Tool for an app by its manifest name (the platform\n * upserts `Tool.name === app name`). The tool id is required by the platform\n * when creating an inventory item, so call this once and pass the id as\n * `toolId` to {@link addInventoryItem}. Returns null when no tool matches.\n *\n * GET /api/tools (the endpoint is paginated — `{ data, pagination }` — or a\n * bare array; both are handled).\n */\nexport async function resolveTool(name: string): Promise<Tool | null> {\n const res = await authFetch('/api/tools')\n if (!res.ok) throw await inventoryError(res)\n const body = (await res.json()) as unknown\n const tools: Tool[] = Array.isArray(body)\n ? (body as Tool[])\n : Array.isArray((body as { data?: unknown })?.data)\n ? ((body as { data: Tool[] }).data)\n : []\n return tools.find((tool) => tool.name === name) ?? null\n}\n\n/** List the customer's inventory (deployment targets). GET /api/components */\nexport async function listInventory(): Promise<InventoryItem[]> {\n const res = await authFetch(INVENTORY_API)\n if (!res.ok) throw await inventoryError(res)\n const data = (await res.json()) as RawInventoryItem[]\n return Array.isArray(data) ? data.map(toInventoryItem) : []\n}\n\n/** Add a new inventory item (deployment target). POST /api/components */\nexport async function addInventoryItem(input: InventoryItemInput): Promise<InventoryItem> {\n const res = await authFetch(INVENTORY_API, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(input),\n })\n if (!res.ok) throw await inventoryError(res)\n return toInventoryItem((await res.json()) as RawInventoryItem)\n}\n\n/** Update an existing inventory item. PUT /api/components/:id */\nexport async function updateInventoryItem(\n id: string,\n input: InventoryItemInput,\n): Promise<InventoryItem> {\n const res = await authFetch(`${INVENTORY_API}/${encodeURIComponent(id)}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(input),\n })\n if (!res.ok) throw await inventoryError(res)\n return toInventoryItem((await res.json()) as RawInventoryItem)\n}\n\n/** Remove an inventory item. DELETE /api/components/:id */\nexport async function removeInventoryItem(id: string): Promise<void> {\n const res = await authFetch(`${INVENTORY_API}/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n })\n // 204 No Content is the platform's success response for delete.\n if (!res.ok && res.status !== 204) throw await inventoryError(res)\n}\n","// ========================================================================\n// Connectivity providers — the customer's ZTNA providers (Tailscale,\n// WireGuard, ZeroTier, …), platform-managed under Settings → Connectivity.\n//\n// A thin reader over the platform's connectivity-providers API\n// (/api/connectivity-providers), used to populate the ZTNA link picker when\n// creating or editing an Access Server (a component). Framework-free — every\n// call goes through the same `authFetch` the '/client' subpath exports.\n// ========================================================================\n\nimport type { ConnectivityProviderRef } from '../types/platform'\nimport { authFetch } from './index'\n\n/** Base route for the platform's connectivity-providers API. */\nconst CONNECTIVITY_PROVIDERS_API = '/api/connectivity-providers'\n\ninterface RawConnectivityProvider {\n id: string\n name?: string\n providerType?: string\n status?: string\n}\n\n/** Build an Error from a non-2xx response, preferring the platform's message. */\nasync function providerError(res: Response): Promise<Error> {\n const text = await res.text().catch(() => '')\n if (text) {\n try {\n const body = JSON.parse(text) as { error?: string; message?: string }\n const message = body?.error ?? body?.message\n if (message) return new Error(message)\n } catch {\n // Body was not JSON — fall through and use the raw text.\n }\n return new Error(text)\n }\n return new Error(`HTTP ${res.status}`)\n}\n\n/**\n * List the customer's ZTNA connectivity providers, used to populate the Access\n * Server link picker. GET /api/connectivity-providers (the endpoint may return\n * a bare array or a paginated `{ data, ... }` shape — both are handled).\n */\nexport async function listConnectivityProviders(): Promise<ConnectivityProviderRef[]> {\n const res = await authFetch(CONNECTIVITY_PROVIDERS_API)\n if (!res.ok) throw await providerError(res)\n const body = (await res.json()) as unknown\n const providers: RawConnectivityProvider[] = Array.isArray(body)\n ? (body as RawConnectivityProvider[])\n : Array.isArray((body as { data?: unknown })?.data)\n ? ((body as { data: RawConnectivityProvider[] }).data)\n : []\n return providers.map((provider) => ({\n id: String(provider.id),\n name: provider.name ?? '',\n providerType: provider.providerType ?? undefined,\n status: provider.status ?? undefined,\n }))\n}\n","// ========================================================================\n// Credentials — how an app authenticates to a server (\"connection\").\n//\n// A \"connection\" pairs a server (a platform *component* — see inventory.ts)\n// with a *credential*: the account and write-only secret used to reach that\n// server. These helpers are a typed surface over the platform's credentials\n// API (POST /api/credentials, GET /api/tools/:toolId/credentials, PUT/DELETE\n// /api/credentials/:id).\n//\n// Framework-free (no React). Every call goes through the same `authFetch` the\n// '/client' subpath exports, so requests carry the platform's Authorization\n// header. Non-2xx responses are surfaced as thrown Errors carrying the\n// platform's error text.\n//\n// SECURITY: `listCredentials` returns a REDACTED {@link CredentialSummary} —\n// secret material (password / apiToken / certificate) is dropped before it\n// reaches app code, so secrets are never held in memory or logged. Only whether\n// a secret exists is surfaced (`hasSecret`). Secrets are write-only: they can be\n// set via create/update, never read back.\n// ========================================================================\n\nimport type { CredentialInput, CredentialSummary } from '../types/platform'\nimport { authFetch } from './index'\n\n/** Base route for the platform's credentials API. */\nconst CREDENTIALS_API = '/api/credentials'\n\n/**\n * Loosely-typed shape of a raw credential as returned by the platform, before\n * it is redacted down to the {@link CredentialSummary} surface. The secret\n * fields (`password` / `apiToken` / `certificate`) are read here only to derive\n * `hasSecret` — they are never carried into app-visible data.\n */\ninterface RawCredential {\n id: string\n name?: string\n username?: string\n type?: string | null\n endpoint?: string | null\n toolId?: string\n // The platform redacts secrets from credential responses and surfaces only\n // whether each is set via these flags. Older platforms may still send the\n // secret fields instead — both shapes are handled below.\n hasPassword?: boolean\n hasApiToken?: boolean\n hasCertificate?: boolean\n password?: string | null\n apiToken?: string | null\n certificate?: string | null\n}\n\n/** Build an Error from a non-2xx response, preferring the platform's message. */\nasync function credentialError(res: Response): Promise<Error> {\n const text = await res.text().catch(() => '')\n if (text) {\n try {\n const body = JSON.parse(text) as { error?: string; message?: string }\n const message = body?.error ?? body?.message\n if (message) return new Error(message)\n } catch {\n // Body was not JSON — fall through and use the raw text.\n }\n return new Error(text)\n }\n return new Error(`HTTP ${res.status}`)\n}\n\n/**\n * Redact a raw platform credential down to the app-visible summary, dropping\n * every secret field and surfacing only whether a secret is stored.\n */\nfunction toCredentialSummary(raw: RawCredential): CredentialSummary {\n // Prefer the redacted has* flags; fall back to the presence of the secret\n // fields themselves for older platforms that still return them.\n const hasSecret = Boolean(\n raw.hasApiToken ||\n raw.hasPassword ||\n (raw.apiToken && raw.apiToken.length > 0) ||\n (raw.password && raw.password.length > 0),\n )\n return {\n id: String(raw.id),\n name: raw.name ?? '',\n username: raw.username ?? '',\n type: raw.type ?? null,\n endpoint: raw.endpoint ?? null,\n toolId: raw.toolId ?? '',\n hasSecret,\n }\n}\n\n/**\n * List the redacted credentials registered for a tool. GET\n * /api/tools/:toolId/credentials. Secrets are stripped before return — see the\n * module's SECURITY note. Returns an empty array when the tool has none.\n */\nexport async function listCredentials(toolId: string): Promise<CredentialSummary[]> {\n const res = await authFetch(`/api/tools/${encodeURIComponent(toolId)}/credentials`)\n if (!res.ok) throw await credentialError(res)\n const data = (await res.json()) as unknown\n const rows: RawCredential[] = Array.isArray(data)\n ? (data as RawCredential[])\n : Array.isArray((data as { data?: unknown })?.data)\n ? ((data as { data: RawCredential[] }).data)\n : []\n return rows.map(toCredentialSummary)\n}\n\n/**\n * Create a credential. POST /api/credentials. The platform requires `name`,\n * `username`, `password`, `toolId`, and `tagIds` — this helper defaults\n * `tagIds` to `[]` and `password` to `''` (valid for token-only auth, where the\n * secret travels in `apiToken`). Returns the new credential's id.\n */\nexport async function createCredential(input: CredentialInput): Promise<{ id: string }> {\n const res = await authFetch(CREDENTIALS_API, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: input.name,\n username: input.username,\n password: input.password ?? '',\n apiToken: input.apiToken,\n type: input.type,\n endpoint: input.endpoint,\n toolId: input.toolId,\n tagIds: input.tagIds ?? [],\n }),\n })\n if (!res.ok) throw await credentialError(res)\n const body = (await res.json()) as { id?: string }\n return { id: String(body.id) }\n}\n\n/**\n * Update a credential. PUT /api/credentials/:id. Only the fields you pass are\n * changed; omit `password`/`apiToken` to leave the stored secret untouched.\n */\nexport async function updateCredential(\n id: string,\n input: Partial<CredentialInput>,\n): Promise<{ id: string }> {\n const body: Record<string, unknown> = {}\n if (input.name !== undefined) body.name = input.name\n if (input.username !== undefined) body.username = input.username\n if (input.password !== undefined) body.password = input.password\n if (input.apiToken !== undefined) body.apiToken = input.apiToken\n if (input.type !== undefined) body.type = input.type\n if (input.endpoint !== undefined) body.endpoint = input.endpoint\n if (input.tagIds !== undefined) body.tagIds = input.tagIds\n const res = await authFetch(`${CREDENTIALS_API}/${encodeURIComponent(id)}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!res.ok) throw await credentialError(res)\n const result = (await res.json().catch(() => ({}))) as { id?: string }\n return { id: result.id ? String(result.id) : id }\n}\n\n/** Remove a credential. DELETE /api/credentials/:id. */\nexport async function removeCredential(id: string): Promise<void> {\n const res = await authFetch(`${CREDENTIALS_API}/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n })\n // 204 No Content is the platform's success response for delete.\n if (!res.ok && res.status !== 204) throw await credentialError(res)\n}\n","// ========================================================================\n// Client runtime contract — how app client bundles talk to the host.\n//\n// App client code is packaged as a hermetic ESM bundle in which `react`,\n// `react-dom`, `react/jsx-runtime`, and every `@veltrixsecops/app-sdk`\n// subpath are compile-time shims that read the host-provided runtime from\n// `globalThis.__VELTRIX_APP_RUNTIME__`. The platform installs that global\n// (with ITS React instance, the shared AppContext, and an authenticated\n// fetch) before dynamically importing any app bundle, so app components\n// render inside the host React tree with working hooks and context.\n//\n// App authors: import from '@veltrixsecops/app-sdk/client' (and /hooks) —\n// never bundle your own copy of react. Use `authFetch` for calls to your\n// app's server routes (/api/apps/<app-id>/...): plain fetch() lacks the\n// platform's Authorization header and will receive 401s.\n// ========================================================================\n\nimport type { ComponentType, Context, LazyExoticComponent } from 'react'\nimport type { AppContextValue } from '../hooks/use-app-context'\n\nexport type { AppBrandingDeclaration } from '../types/manifest'\n\n// Inventory — typed helpers over the platform's components API (deployment\n// targets: servers, domains, IP/CIDR ranges). Framework-free; they use the\n// `authFetch` exported below internally.\nexport {\n listInventory,\n addInventoryItem,\n updateInventoryItem,\n removeInventoryItem,\n resolveTool,\n} from './inventory'\nexport type { Tool } from './inventory'\nexport type { InventoryItem, InventoryItemInput } from '../types/platform'\n\n// Connectivity providers — reader over the customer's ZTNA providers, used to\n// populate the Access Server link picker. Framework-free; uses `authFetch`.\nexport { listConnectivityProviders } from './connectivity'\nexport type { ConnectivityProviderRef } from '../types/platform'\n\n// Credentials — typed helpers over the platform's credentials API. Paired with\n// a server (component) these form a \"connection\". Secrets are write-only:\n// `listCredentials` returns redacted summaries only. Framework-free; they use\n// the `authFetch` exported below internally.\nexport {\n listCredentials,\n createCredential,\n updateCredential,\n removeCredential,\n} from './credentials'\nexport type { Credential, CredentialSummary, CredentialInput } from '../types/platform'\n\n/** Name of the global the platform installs before loading app bundles. */\nexport const HOST_RUNTIME_GLOBAL = '__VELTRIX_APP_RUNTIME__'\n\n/**\n * The runtime surface the platform exposes to app client bundles.\n * The react/reactDom/jsxRuntime members are the host's own module objects —\n * app bundles are compiled with shims that re-export them, guaranteeing a\n * single React instance per page.\n */\nexport interface VeltrixHostRuntime {\n /** The host's `react` module object. */\n react: unknown\n /** The host's `react-dom` module object. */\n reactDom: unknown\n /** The host's `react-dom/client` module object. */\n reactDomClient?: unknown\n /** The host's `react/jsx-runtime` module object. */\n jsxRuntime: unknown\n /** Shared app context — the host wraps app pages in its Provider. */\n AppContext: Context<AppContextValue | null>\n /** fetch() with the platform's Authorization header attached. */\n authFetch: (input: string, init?: RequestInit) => Promise<Response>\n /**\n * The SDK surface app bundles receive for `@veltrixsecops/app-sdk`,\n * `.../hooks`, and `.../client` imports (useAppContext, AppContext,\n * usePipelineStatus, authFetch, getHostRuntime, ...).\n */\n sdk: Record<string, unknown>\n /**\n * The platform's design-system components and hooks, host-owned so they\n * share the single host React instance. Keyed by the exact component/hook\n * names re-exported from `@veltrixsecops/app-sdk/ui` (Button, Input, Card,\n * DataTable, useToast, ...). Present only inside the platform.\n */\n ui?: Record<string, unknown>\n}\n\n/** Read the host runtime, or null outside the platform (tests, storybook). */\nexport function getHostRuntime(): VeltrixHostRuntime | null {\n const runtime = (globalThis as Record<string, unknown>)[HOST_RUNTIME_GLOBAL]\n return (runtime as VeltrixHostRuntime) ?? null\n}\n\n/** Read the host runtime, throwing a diagnosable error when absent. */\nexport function requireHostRuntime(): VeltrixHostRuntime {\n const runtime = getHostRuntime()\n if (!runtime) {\n throw new Error(\n 'Veltrix host runtime not found — app client bundles only run inside the ' +\n `Veltrix platform (missing globalThis.${HOST_RUNTIME_GLOBAL})`,\n )\n }\n return runtime\n}\n\n/**\n * fetch() that carries the platform's Authorization header. Required for an\n * app page to call its own server routes (/api/apps/<app-id>/...), which are\n * bearer-token protected. Falls back to plain fetch outside the platform.\n */\nexport function authFetch(input: string, init?: RequestInit): Promise<Response> {\n const runtime = getHostRuntime()\n if (runtime) return runtime.authFetch(input, init)\n return fetch(input, init)\n}\n\n/** A sidebar entry contributed by the app's client entry module. */\nexport interface AppSidebarItem {\n path: string\n label: string\n icon?: string\n}\n\n/**\n * Shape of the default export of an app's `client/index.tsx`.\n * `pages` keys must match `manifest.client.pages[].component`.\n */\nexport interface AppClientModule {\n id: string\n pages: Record<string, ComponentType | LazyExoticComponent<ComponentType>>\n sidebarItems?: AppSidebarItem[]\n}\n"],"mappings":"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","names":[]}
@@ -21,21 +21,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var client_exports = {};
22
22
  __export(client_exports, {
23
23
  HOST_RUNTIME_GLOBAL: () => HOST_RUNTIME_GLOBAL,
24
- addAccessServer: () => addAccessServer,
25
24
  addInventoryItem: () => addInventoryItem,
26
25
  authFetch: () => authFetch,
27
26
  createCredential: () => createCredential,
28
27
  getHostRuntime: () => getHostRuntime,
29
- listAccessServers: () => listAccessServers,
30
28
  listConnectivityProviders: () => listConnectivityProviders,
31
29
  listCredentials: () => listCredentials,
32
30
  listInventory: () => listInventory,
33
- removeAccessServer: () => removeAccessServer,
34
31
  removeCredential: () => removeCredential,
35
32
  removeInventoryItem: () => removeInventoryItem,
36
33
  requireHostRuntime: () => requireHostRuntime,
37
34
  resolveTool: () => resolveTool,
38
- updateAccessServer: () => updateAccessServer,
39
35
  updateCredential: () => updateCredential,
40
36
  updateInventoryItem: () => updateInventoryItem
41
37
  });
@@ -65,7 +61,8 @@ function toInventoryItem(raw) {
65
61
  domains: Array.isArray(raw.domains) ? raw.domains : [],
66
62
  ipRanges: Array.isArray(raw.ipRanges) ? raw.ipRanges : [],
67
63
  tags: Array.isArray(raw.tags) ? raw.tags.map((tag) => ({ id: String(tag.id), name: String(tag.name) })) : [],
68
- connectivityProviderId: raw.connectivityProviderId ?? null
64
+ connectivityProviderId: raw.connectivityProviderId ?? null,
65
+ credentialId: raw.credentialId ?? null
69
66
  };
70
67
  }
71
68
  async function resolveTool(name) {
@@ -106,10 +103,9 @@ async function removeInventoryItem(id) {
106
103
  if (!res.ok && res.status !== 204) throw await inventoryError(res);
107
104
  }
108
105
 
109
- // src/client/access-servers.ts
110
- var ACCESS_SERVERS_API = "/api/access-servers";
106
+ // src/client/connectivity.ts
111
107
  var CONNECTIVITY_PROVIDERS_API = "/api/connectivity-providers";
112
- async function accessServerError(res) {
108
+ async function providerError(res) {
113
109
  const text = await res.text().catch(() => "");
114
110
  if (text) {
115
111
  try {
@@ -122,52 +118,9 @@ async function accessServerError(res) {
122
118
  }
123
119
  return new Error(`HTTP ${res.status}`);
124
120
  }
125
- function toAccessServer(raw) {
126
- return {
127
- id: String(raw.id),
128
- name: raw.name ?? "",
129
- endpoint: raw.endpoint ?? "",
130
- type: raw.type ?? void 0,
131
- region: raw.region ?? null,
132
- status: raw.status ?? void 0,
133
- description: raw.description ?? null,
134
- connectivityProviderId: raw.connectivityProviderId ?? null,
135
- connectivityProvider: raw.connectivityProvider ? { id: String(raw.connectivityProvider.id), name: String(raw.connectivityProvider.name) } : null
136
- };
137
- }
138
- async function listAccessServers() {
139
- const res = await authFetch(ACCESS_SERVERS_API);
140
- if (!res.ok) throw await accessServerError(res);
141
- const data = await res.json();
142
- return Array.isArray(data) ? data.map(toAccessServer) : [];
143
- }
144
- async function addAccessServer(input) {
145
- const res = await authFetch(ACCESS_SERVERS_API, {
146
- method: "POST",
147
- headers: { "Content-Type": "application/json" },
148
- body: JSON.stringify(input)
149
- });
150
- if (!res.ok) throw await accessServerError(res);
151
- return toAccessServer(await res.json());
152
- }
153
- async function updateAccessServer(id, input) {
154
- const res = await authFetch(`${ACCESS_SERVERS_API}/${encodeURIComponent(id)}`, {
155
- method: "PUT",
156
- headers: { "Content-Type": "application/json" },
157
- body: JSON.stringify(input)
158
- });
159
- if (!res.ok) throw await accessServerError(res);
160
- return toAccessServer(await res.json());
161
- }
162
- async function removeAccessServer(id) {
163
- const res = await authFetch(`${ACCESS_SERVERS_API}/${encodeURIComponent(id)}`, {
164
- method: "DELETE"
165
- });
166
- if (!res.ok && res.status !== 204) throw await accessServerError(res);
167
- }
168
121
  async function listConnectivityProviders() {
169
122
  const res = await authFetch(CONNECTIVITY_PROVIDERS_API);
170
- if (!res.ok) throw await accessServerError(res);
123
+ if (!res.ok) throw await providerError(res);
171
124
  const body = await res.json();
172
125
  const providers = Array.isArray(body) ? body : Array.isArray(body?.data) ? body.data : [];
173
126
  return providers.map((provider) => ({
@@ -194,12 +147,15 @@ async function credentialError(res) {
194
147
  return new Error(`HTTP ${res.status}`);
195
148
  }
196
149
  function toCredentialSummary(raw) {
197
- const hasSecret = Boolean(raw.apiToken && raw.apiToken.length > 0 || raw.password && raw.password.length > 0);
150
+ const hasSecret = Boolean(
151
+ raw.hasApiToken || raw.hasPassword || raw.apiToken && raw.apiToken.length > 0 || raw.password && raw.password.length > 0
152
+ );
198
153
  return {
199
154
  id: String(raw.id),
200
155
  name: raw.name ?? "",
201
156
  username: raw.username ?? "",
202
157
  type: raw.type ?? null,
158
+ endpoint: raw.endpoint ?? null,
203
159
  toolId: raw.toolId ?? "",
204
160
  hasSecret
205
161
  };
@@ -221,6 +177,7 @@ async function createCredential(input) {
221
177
  password: input.password ?? "",
222
178
  apiToken: input.apiToken,
223
179
  type: input.type,
180
+ endpoint: input.endpoint,
224
181
  toolId: input.toolId,
225
182
  tagIds: input.tagIds ?? []
226
183
  })
@@ -236,6 +193,7 @@ async function updateCredential(id, input) {
236
193
  if (input.password !== void 0) body.password = input.password;
237
194
  if (input.apiToken !== void 0) body.apiToken = input.apiToken;
238
195
  if (input.type !== void 0) body.type = input.type;
196
+ if (input.endpoint !== void 0) body.endpoint = input.endpoint;
239
197
  if (input.tagIds !== void 0) body.tagIds = input.tagIds;
240
198
  const res = await authFetch(`${CREDENTIALS_API}/${encodeURIComponent(id)}`, {
241
199
  method: "PUT",
@@ -276,21 +234,17 @@ function authFetch(input, init) {
276
234
  // Annotate the CommonJS export names for ESM import in node:
277
235
  0 && (module.exports = {
278
236
  HOST_RUNTIME_GLOBAL,
279
- addAccessServer,
280
237
  addInventoryItem,
281
238
  authFetch,
282
239
  createCredential,
283
240
  getHostRuntime,
284
- listAccessServers,
285
241
  listConnectivityProviders,
286
242
  listCredentials,
287
243
  listInventory,
288
- removeAccessServer,
289
244
  removeCredential,
290
245
  removeInventoryItem,
291
246
  requireHostRuntime,
292
247
  resolveTool,
293
- updateAccessServer,
294
248
  updateCredential,
295
249
  updateInventoryItem
296
250
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/index.ts","../../src/client/inventory.ts","../../src/client/access-servers.ts","../../src/client/credentials.ts"],"sourcesContent":["// ========================================================================\n// Client runtime contract — how app client bundles talk to the host.\n//\n// App client code is packaged as a hermetic ESM bundle in which `react`,\n// `react-dom`, `react/jsx-runtime`, and every `@veltrixsecops/app-sdk`\n// subpath are compile-time shims that read the host-provided runtime from\n// `globalThis.__VELTRIX_APP_RUNTIME__`. The platform installs that global\n// (with ITS React instance, the shared AppContext, and an authenticated\n// fetch) before dynamically importing any app bundle, so app components\n// render inside the host React tree with working hooks and context.\n//\n// App authors: import from '@veltrixsecops/app-sdk/client' (and /hooks) —\n// never bundle your own copy of react. Use `authFetch` for calls to your\n// app's server routes (/api/apps/<app-id>/...): plain fetch() lacks the\n// platform's Authorization header and will receive 401s.\n// ========================================================================\n\nimport type { ComponentType, Context, LazyExoticComponent } from 'react'\nimport type { AppContextValue } from '../hooks/use-app-context'\n\nexport type { AppBrandingDeclaration } from '../types/manifest'\n\n// Inventory — typed helpers over the platform's components API (deployment\n// targets: servers, domains, IP/CIDR ranges). Framework-free; they use the\n// `authFetch` exported below internally.\nexport {\n listInventory,\n addInventoryItem,\n updateInventoryItem,\n removeInventoryItem,\n resolveTool,\n} from './inventory'\nexport type { Tool } from './inventory'\nexport type { InventoryItem, InventoryItemInput } from '../types/platform'\n\n// Access Servers — typed helpers over the platform's access-servers API (ZTNA\n// gateways) plus a reader over connectivity providers for the link picker.\n// Framework-free; they use the `authFetch` exported below internally.\nexport {\n listAccessServers,\n addAccessServer,\n updateAccessServer,\n removeAccessServer,\n listConnectivityProviders,\n} from './access-servers'\nexport type { AccessServer, AccessServerInput, ConnectivityProviderRef } from '../types/platform'\n\n// Credentials — typed helpers over the platform's credentials API. Paired with\n// a server (component) these form a \"connection\". Secrets are write-only:\n// `listCredentials` returns redacted summaries only. Framework-free; they use\n// the `authFetch` exported below internally.\nexport {\n listCredentials,\n createCredential,\n updateCredential,\n removeCredential,\n} from './credentials'\nexport type { Credential, CredentialSummary, CredentialInput } from '../types/platform'\n\n/** Name of the global the platform installs before loading app bundles. */\nexport const HOST_RUNTIME_GLOBAL = '__VELTRIX_APP_RUNTIME__'\n\n/**\n * The runtime surface the platform exposes to app client bundles.\n * The react/reactDom/jsxRuntime members are the host's own module objects —\n * app bundles are compiled with shims that re-export them, guaranteeing a\n * single React instance per page.\n */\nexport interface VeltrixHostRuntime {\n /** The host's `react` module object. */\n react: unknown\n /** The host's `react-dom` module object. */\n reactDom: unknown\n /** The host's `react-dom/client` module object. */\n reactDomClient?: unknown\n /** The host's `react/jsx-runtime` module object. */\n jsxRuntime: unknown\n /** Shared app context — the host wraps app pages in its Provider. */\n AppContext: Context<AppContextValue | null>\n /** fetch() with the platform's Authorization header attached. */\n authFetch: (input: string, init?: RequestInit) => Promise<Response>\n /**\n * The SDK surface app bundles receive for `@veltrixsecops/app-sdk`,\n * `.../hooks`, and `.../client` imports (useAppContext, AppContext,\n * usePipelineStatus, authFetch, getHostRuntime, ...).\n */\n sdk: Record<string, unknown>\n /**\n * The platform's design-system components and hooks, host-owned so they\n * share the single host React instance. Keyed by the exact component/hook\n * names re-exported from `@veltrixsecops/app-sdk/ui` (Button, Input, Card,\n * DataTable, useToast, ...). Present only inside the platform.\n */\n ui?: Record<string, unknown>\n}\n\n/** Read the host runtime, or null outside the platform (tests, storybook). */\nexport function getHostRuntime(): VeltrixHostRuntime | null {\n const runtime = (globalThis as Record<string, unknown>)[HOST_RUNTIME_GLOBAL]\n return (runtime as VeltrixHostRuntime) ?? null\n}\n\n/** Read the host runtime, throwing a diagnosable error when absent. */\nexport function requireHostRuntime(): VeltrixHostRuntime {\n const runtime = getHostRuntime()\n if (!runtime) {\n throw new Error(\n 'Veltrix host runtime not found — app client bundles only run inside the ' +\n `Veltrix platform (missing globalThis.${HOST_RUNTIME_GLOBAL})`,\n )\n }\n return runtime\n}\n\n/**\n * fetch() that carries the platform's Authorization header. Required for an\n * app page to call its own server routes (/api/apps/<app-id>/...), which are\n * bearer-token protected. Falls back to plain fetch outside the platform.\n */\nexport function authFetch(input: string, init?: RequestInit): Promise<Response> {\n const runtime = getHostRuntime()\n if (runtime) return runtime.authFetch(input, init)\n return fetch(input, init)\n}\n\n/** A sidebar entry contributed by the app's client entry module. */\nexport interface AppSidebarItem {\n path: string\n label: string\n icon?: string\n}\n\n/**\n * Shape of the default export of an app's `client/index.tsx`.\n * `pages` keys must match `manifest.client.pages[].component`.\n */\nexport interface AppClientModule {\n id: string\n pages: Record<string, ComponentType | LazyExoticComponent<ComponentType>>\n sidebarItems?: AppSidebarItem[]\n}\n","// ========================================================================\n// Inventory — the deployment targets an app can deploy configuration to.\n//\n// \"Inventory\" is the app-facing name for the platform's *components*: the\n// servers (hostname/port), domains, and IP/CIDR ranges a customer has\n// registered as deploy targets. These helpers are a typed, convenient\n// surface over the platform's components API (/api/components), enriched\n// with `domains` and `ipRanges`.\n//\n// Framework-free (no React) — safe to import from any client code. Every\n// call goes through the same `authFetch` the '/client' subpath exports, so\n// requests carry the platform's Authorization header. Non-2xx responses are\n// surfaced as thrown Errors carrying the platform's error text.\n// ========================================================================\n\nimport type { InventoryItem, InventoryItemInput } from '../types/platform'\nimport { authFetch } from './index'\n\n/** Base route for the platform's components (inventory) API. */\nconst INVENTORY_API = '/api/components'\n\n/**\n * Loosely-typed shape of a raw component as returned by the platform, before\n * it is normalized down to the {@link InventoryItem} surface.\n */\ninterface RawInventoryItem {\n id: string\n hostname?: string\n port?: string\n type?: string[]\n domains?: string[]\n ipRanges?: string[]\n tags?: Array<{ id: string; name: string }>\n connectivityProviderId?: string | null\n}\n\n/** Build an Error from a non-2xx response, preferring the platform's message. */\nasync function inventoryError(res: Response): Promise<Error> {\n const text = await res.text().catch(() => '')\n if (text) {\n try {\n const body = JSON.parse(text) as { error?: string; message?: string }\n const message = body?.error ?? body?.message\n if (message) return new Error(message)\n } catch {\n // Body was not JSON — fall through and use the raw text.\n }\n return new Error(text)\n }\n return new Error(`HTTP ${res.status}`)\n}\n\n/** Normalize a raw platform component into the typed InventoryItem surface. */\nfunction toInventoryItem(raw: RawInventoryItem): InventoryItem {\n return {\n id: String(raw.id),\n hostname: raw.hostname ?? '',\n port: raw.port ?? undefined,\n type: Array.isArray(raw.type) ? raw.type : undefined,\n domains: Array.isArray(raw.domains) ? raw.domains : [],\n ipRanges: Array.isArray(raw.ipRanges) ? raw.ipRanges : [],\n tags: Array.isArray(raw.tags)\n ? raw.tags.map((tag) => ({ id: String(tag.id), name: String(tag.name) }))\n : [],\n connectivityProviderId: raw.connectivityProviderId ?? null,\n }\n}\n\n/**\n * A platform Tool. Each installed app is upserted as a Tool keyed by its\n * manifest `name`, and inventory items (components) belong to a tool.\n */\nexport interface Tool {\n id: string\n name: string\n vendor?: string\n}\n\n/**\n * Resolve the platform Tool for an app by its manifest name (the platform\n * upserts `Tool.name === app name`). The tool id is required by the platform\n * when creating an inventory item, so call this once and pass the id as\n * `toolId` to {@link addInventoryItem}. Returns null when no tool matches.\n *\n * GET /api/tools (the endpoint is paginated — `{ data, pagination }` — or a\n * bare array; both are handled).\n */\nexport async function resolveTool(name: string): Promise<Tool | null> {\n const res = await authFetch('/api/tools')\n if (!res.ok) throw await inventoryError(res)\n const body = (await res.json()) as unknown\n const tools: Tool[] = Array.isArray(body)\n ? (body as Tool[])\n : Array.isArray((body as { data?: unknown })?.data)\n ? ((body as { data: Tool[] }).data)\n : []\n return tools.find((tool) => tool.name === name) ?? null\n}\n\n/** List the customer's inventory (deployment targets). GET /api/components */\nexport async function listInventory(): Promise<InventoryItem[]> {\n const res = await authFetch(INVENTORY_API)\n if (!res.ok) throw await inventoryError(res)\n const data = (await res.json()) as RawInventoryItem[]\n return Array.isArray(data) ? data.map(toInventoryItem) : []\n}\n\n/** Add a new inventory item (deployment target). POST /api/components */\nexport async function addInventoryItem(input: InventoryItemInput): Promise<InventoryItem> {\n const res = await authFetch(INVENTORY_API, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(input),\n })\n if (!res.ok) throw await inventoryError(res)\n return toInventoryItem((await res.json()) as RawInventoryItem)\n}\n\n/** Update an existing inventory item. PUT /api/components/:id */\nexport async function updateInventoryItem(\n id: string,\n input: InventoryItemInput,\n): Promise<InventoryItem> {\n const res = await authFetch(`${INVENTORY_API}/${encodeURIComponent(id)}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(input),\n })\n if (!res.ok) throw await inventoryError(res)\n return toInventoryItem((await res.json()) as RawInventoryItem)\n}\n\n/** Remove an inventory item. DELETE /api/components/:id */\nexport async function removeInventoryItem(id: string): Promise<void> {\n const res = await authFetch(`${INVENTORY_API}/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n })\n // 204 No Content is the platform's success response for delete.\n if (!res.ok && res.status !== 204) throw await inventoryError(res)\n}\n","// ========================================================================\n// Access Servers — the Zero-Trust Access (ZTNA) gateways an app manages.\n//\n// Each Access Server is a ZTNA gateway (name + endpoint) a customer has\n// registered, optionally linked to one of their connectivity providers. These\n// helpers are a typed, convenient surface over the platform's access-servers\n// API (/api/access-servers), plus a thin reader over the connectivity\n// providers API (/api/connectivity-providers) used to populate the ZTNA link\n// picker.\n//\n// Framework-free (no React) — safe to import from any client code. Every call\n// goes through the same `authFetch` the '/client' subpath exports, so requests\n// carry the platform's Authorization header. Non-2xx responses are surfaced as\n// thrown Errors carrying the platform's error text.\n// ========================================================================\n\nimport type {\n AccessServer,\n AccessServerInput,\n ConnectivityProviderRef,\n} from '../types/platform'\nimport { authFetch } from './index'\n\n/** Base route for the platform's access-servers API. */\nconst ACCESS_SERVERS_API = '/api/access-servers'\n/** Base route for the platform's connectivity-providers API (ZTNA picker). */\nconst CONNECTIVITY_PROVIDERS_API = '/api/connectivity-providers'\n\n/**\n * Loosely-typed shape of a raw access server as returned by the platform,\n * before it is normalized down to the {@link AccessServer} surface.\n */\ninterface RawAccessServer {\n id: string\n name?: string\n endpoint?: string\n type?: string\n region?: string | null\n status?: string\n description?: string | null\n connectivityProviderId?: string | null\n connectivityProvider?: { id: string; name: string } | null\n}\n\n/**\n * Loosely-typed shape of a raw connectivity provider as returned by the\n * platform, before it is normalized to the {@link ConnectivityProviderRef}\n * picker surface.\n */\ninterface RawConnectivityProvider {\n id: string\n name?: string\n providerType?: string\n status?: string\n}\n\n/** Build an Error from a non-2xx response, preferring the platform's message. */\nasync function accessServerError(res: Response): Promise<Error> {\n const text = await res.text().catch(() => '')\n if (text) {\n try {\n const body = JSON.parse(text) as { error?: string; message?: string }\n const message = body?.error ?? body?.message\n if (message) return new Error(message)\n } catch {\n // Body was not JSON — fall through and use the raw text.\n }\n return new Error(text)\n }\n return new Error(`HTTP ${res.status}`)\n}\n\n/** Normalize a raw platform access server into the typed AccessServer surface. */\nfunction toAccessServer(raw: RawAccessServer): AccessServer {\n return {\n id: String(raw.id),\n name: raw.name ?? '',\n endpoint: raw.endpoint ?? '',\n type: raw.type ?? undefined,\n region: raw.region ?? null,\n status: raw.status ?? undefined,\n description: raw.description ?? null,\n connectivityProviderId: raw.connectivityProviderId ?? null,\n connectivityProvider: raw.connectivityProvider\n ? { id: String(raw.connectivityProvider.id), name: String(raw.connectivityProvider.name) }\n : null,\n }\n}\n\n/** List the customer's access servers (ZTNA gateways). GET /api/access-servers */\nexport async function listAccessServers(): Promise<AccessServer[]> {\n const res = await authFetch(ACCESS_SERVERS_API)\n if (!res.ok) throw await accessServerError(res)\n const data = (await res.json()) as RawAccessServer[]\n return Array.isArray(data) ? data.map(toAccessServer) : []\n}\n\n/** Add a new access server (ZTNA gateway). POST /api/access-servers */\nexport async function addAccessServer(input: AccessServerInput): Promise<AccessServer> {\n const res = await authFetch(ACCESS_SERVERS_API, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(input),\n })\n if (!res.ok) throw await accessServerError(res)\n return toAccessServer((await res.json()) as RawAccessServer)\n}\n\n/** Update an existing access server. PUT /api/access-servers/:id */\nexport async function updateAccessServer(\n id: string,\n input: AccessServerInput,\n): Promise<AccessServer> {\n const res = await authFetch(`${ACCESS_SERVERS_API}/${encodeURIComponent(id)}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(input),\n })\n if (!res.ok) throw await accessServerError(res)\n return toAccessServer((await res.json()) as RawAccessServer)\n}\n\n/** Remove an access server. DELETE /api/access-servers/:id */\nexport async function removeAccessServer(id: string): Promise<void> {\n const res = await authFetch(`${ACCESS_SERVERS_API}/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n })\n // 204 No Content is the platform's success response for delete.\n if (!res.ok && res.status !== 204) throw await accessServerError(res)\n}\n\n/**\n * List the customer's ZTNA connectivity providers, used to populate the Access\n * Server link picker. GET /api/connectivity-providers (the endpoint may return\n * a bare array or a paginated `{ data, ... }` shape — both are handled).\n */\nexport async function listConnectivityProviders(): Promise<ConnectivityProviderRef[]> {\n const res = await authFetch(CONNECTIVITY_PROVIDERS_API)\n if (!res.ok) throw await accessServerError(res)\n const body = (await res.json()) as unknown\n const providers: RawConnectivityProvider[] = Array.isArray(body)\n ? (body as RawConnectivityProvider[])\n : Array.isArray((body as { data?: unknown })?.data)\n ? ((body as { data: RawConnectivityProvider[] }).data)\n : []\n return providers.map((provider) => ({\n id: String(provider.id),\n name: provider.name ?? '',\n providerType: provider.providerType ?? undefined,\n status: provider.status ?? undefined,\n }))\n}\n","// ========================================================================\n// Credentials — how an app authenticates to a server (\"connection\").\n//\n// A \"connection\" pairs a server (a platform *component* — see inventory.ts)\n// with a *credential*: the account and write-only secret used to reach that\n// server. These helpers are a typed surface over the platform's credentials\n// API (POST /api/credentials, GET /api/tools/:toolId/credentials, PUT/DELETE\n// /api/credentials/:id).\n//\n// Framework-free (no React). Every call goes through the same `authFetch` the\n// '/client' subpath exports, so requests carry the platform's Authorization\n// header. Non-2xx responses are surfaced as thrown Errors carrying the\n// platform's error text.\n//\n// SECURITY: `listCredentials` returns a REDACTED {@link CredentialSummary} —\n// secret material (password / apiToken / certificate) is dropped before it\n// reaches app code, so secrets are never held in memory or logged. Only whether\n// a secret exists is surfaced (`hasSecret`). Secrets are write-only: they can be\n// set via create/update, never read back.\n// ========================================================================\n\nimport type { CredentialInput, CredentialSummary } from '../types/platform'\nimport { authFetch } from './index'\n\n/** Base route for the platform's credentials API. */\nconst CREDENTIALS_API = '/api/credentials'\n\n/**\n * Loosely-typed shape of a raw credential as returned by the platform, before\n * it is redacted down to the {@link CredentialSummary} surface. The secret\n * fields (`password` / `apiToken` / `certificate`) are read here only to derive\n * `hasSecret` — they are never carried into app-visible data.\n */\ninterface RawCredential {\n id: string\n name?: string\n username?: string\n type?: string | null\n toolId?: string\n password?: string | null\n apiToken?: string | null\n certificate?: string | null\n}\n\n/** Build an Error from a non-2xx response, preferring the platform's message. */\nasync function credentialError(res: Response): Promise<Error> {\n const text = await res.text().catch(() => '')\n if (text) {\n try {\n const body = JSON.parse(text) as { error?: string; message?: string }\n const message = body?.error ?? body?.message\n if (message) return new Error(message)\n } catch {\n // Body was not JSON — fall through and use the raw text.\n }\n return new Error(text)\n }\n return new Error(`HTTP ${res.status}`)\n}\n\n/**\n * Redact a raw platform credential down to the app-visible summary, dropping\n * every secret field and surfacing only whether a secret is stored.\n */\nfunction toCredentialSummary(raw: RawCredential): CredentialSummary {\n const hasSecret = Boolean((raw.apiToken && raw.apiToken.length > 0) || (raw.password && raw.password.length > 0))\n return {\n id: String(raw.id),\n name: raw.name ?? '',\n username: raw.username ?? '',\n type: raw.type ?? null,\n toolId: raw.toolId ?? '',\n hasSecret,\n }\n}\n\n/**\n * List the redacted credentials registered for a tool. GET\n * /api/tools/:toolId/credentials. Secrets are stripped before return — see the\n * module's SECURITY note. Returns an empty array when the tool has none.\n */\nexport async function listCredentials(toolId: string): Promise<CredentialSummary[]> {\n const res = await authFetch(`/api/tools/${encodeURIComponent(toolId)}/credentials`)\n if (!res.ok) throw await credentialError(res)\n const data = (await res.json()) as unknown\n const rows: RawCredential[] = Array.isArray(data)\n ? (data as RawCredential[])\n : Array.isArray((data as { data?: unknown })?.data)\n ? ((data as { data: RawCredential[] }).data)\n : []\n return rows.map(toCredentialSummary)\n}\n\n/**\n * Create a credential. POST /api/credentials. The platform requires `name`,\n * `username`, `password`, `toolId`, and `tagIds` — this helper defaults\n * `tagIds` to `[]` and `password` to `''` (valid for token-only auth, where the\n * secret travels in `apiToken`). Returns the new credential's id.\n */\nexport async function createCredential(input: CredentialInput): Promise<{ id: string }> {\n const res = await authFetch(CREDENTIALS_API, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: input.name,\n username: input.username,\n password: input.password ?? '',\n apiToken: input.apiToken,\n type: input.type,\n toolId: input.toolId,\n tagIds: input.tagIds ?? [],\n }),\n })\n if (!res.ok) throw await credentialError(res)\n const body = (await res.json()) as { id?: string }\n return { id: String(body.id) }\n}\n\n/**\n * Update a credential. PUT /api/credentials/:id. Only the fields you pass are\n * changed; omit `password`/`apiToken` to leave the stored secret untouched.\n */\nexport async function updateCredential(\n id: string,\n input: Partial<CredentialInput>,\n): Promise<{ id: string }> {\n const body: Record<string, unknown> = {}\n if (input.name !== undefined) body.name = input.name\n if (input.username !== undefined) body.username = input.username\n if (input.password !== undefined) body.password = input.password\n if (input.apiToken !== undefined) body.apiToken = input.apiToken\n if (input.type !== undefined) body.type = input.type\n if (input.tagIds !== undefined) body.tagIds = input.tagIds\n const res = await authFetch(`${CREDENTIALS_API}/${encodeURIComponent(id)}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!res.ok) throw await credentialError(res)\n const result = (await res.json().catch(() => ({}))) as { id?: string }\n return { id: result.id ? String(result.id) : id }\n}\n\n/** Remove a credential. DELETE /api/credentials/:id. */\nexport async function removeCredential(id: string): Promise<void> {\n const res = await authFetch(`${CREDENTIALS_API}/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n })\n // 204 No Content is the platform's success response for delete.\n if (!res.ok && res.status !== 204) throw await credentialError(res)\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/client/index.ts","../../src/client/inventory.ts","../../src/client/connectivity.ts","../../src/client/credentials.ts"],"sourcesContent":["// ========================================================================\n// Client runtime contract — how app client bundles talk to the host.\n//\n// App client code is packaged as a hermetic ESM bundle in which `react`,\n// `react-dom`, `react/jsx-runtime`, and every `@veltrixsecops/app-sdk`\n// subpath are compile-time shims that read the host-provided runtime from\n// `globalThis.__VELTRIX_APP_RUNTIME__`. The platform installs that global\n// (with ITS React instance, the shared AppContext, and an authenticated\n// fetch) before dynamically importing any app bundle, so app components\n// render inside the host React tree with working hooks and context.\n//\n// App authors: import from '@veltrixsecops/app-sdk/client' (and /hooks) —\n// never bundle your own copy of react. Use `authFetch` for calls to your\n// app's server routes (/api/apps/<app-id>/...): plain fetch() lacks the\n// platform's Authorization header and will receive 401s.\n// ========================================================================\n\nimport type { ComponentType, Context, LazyExoticComponent } from 'react'\nimport type { AppContextValue } from '../hooks/use-app-context'\n\nexport type { AppBrandingDeclaration } from '../types/manifest'\n\n// Inventory — typed helpers over the platform's components API (deployment\n// targets: servers, domains, IP/CIDR ranges). Framework-free; they use the\n// `authFetch` exported below internally.\nexport {\n listInventory,\n addInventoryItem,\n updateInventoryItem,\n removeInventoryItem,\n resolveTool,\n} from './inventory'\nexport type { Tool } from './inventory'\nexport type { InventoryItem, InventoryItemInput } from '../types/platform'\n\n// Connectivity providers — reader over the customer's ZTNA providers, used to\n// populate the Access Server link picker. Framework-free; uses `authFetch`.\nexport { listConnectivityProviders } from './connectivity'\nexport type { ConnectivityProviderRef } from '../types/platform'\n\n// Credentials — typed helpers over the platform's credentials API. Paired with\n// a server (component) these form a \"connection\". Secrets are write-only:\n// `listCredentials` returns redacted summaries only. Framework-free; they use\n// the `authFetch` exported below internally.\nexport {\n listCredentials,\n createCredential,\n updateCredential,\n removeCredential,\n} from './credentials'\nexport type { Credential, CredentialSummary, CredentialInput } from '../types/platform'\n\n/** Name of the global the platform installs before loading app bundles. */\nexport const HOST_RUNTIME_GLOBAL = '__VELTRIX_APP_RUNTIME__'\n\n/**\n * The runtime surface the platform exposes to app client bundles.\n * The react/reactDom/jsxRuntime members are the host's own module objects —\n * app bundles are compiled with shims that re-export them, guaranteeing a\n * single React instance per page.\n */\nexport interface VeltrixHostRuntime {\n /** The host's `react` module object. */\n react: unknown\n /** The host's `react-dom` module object. */\n reactDom: unknown\n /** The host's `react-dom/client` module object. */\n reactDomClient?: unknown\n /** The host's `react/jsx-runtime` module object. */\n jsxRuntime: unknown\n /** Shared app context — the host wraps app pages in its Provider. */\n AppContext: Context<AppContextValue | null>\n /** fetch() with the platform's Authorization header attached. */\n authFetch: (input: string, init?: RequestInit) => Promise<Response>\n /**\n * The SDK surface app bundles receive for `@veltrixsecops/app-sdk`,\n * `.../hooks`, and `.../client` imports (useAppContext, AppContext,\n * usePipelineStatus, authFetch, getHostRuntime, ...).\n */\n sdk: Record<string, unknown>\n /**\n * The platform's design-system components and hooks, host-owned so they\n * share the single host React instance. Keyed by the exact component/hook\n * names re-exported from `@veltrixsecops/app-sdk/ui` (Button, Input, Card,\n * DataTable, useToast, ...). Present only inside the platform.\n */\n ui?: Record<string, unknown>\n}\n\n/** Read the host runtime, or null outside the platform (tests, storybook). */\nexport function getHostRuntime(): VeltrixHostRuntime | null {\n const runtime = (globalThis as Record<string, unknown>)[HOST_RUNTIME_GLOBAL]\n return (runtime as VeltrixHostRuntime) ?? null\n}\n\n/** Read the host runtime, throwing a diagnosable error when absent. */\nexport function requireHostRuntime(): VeltrixHostRuntime {\n const runtime = getHostRuntime()\n if (!runtime) {\n throw new Error(\n 'Veltrix host runtime not found — app client bundles only run inside the ' +\n `Veltrix platform (missing globalThis.${HOST_RUNTIME_GLOBAL})`,\n )\n }\n return runtime\n}\n\n/**\n * fetch() that carries the platform's Authorization header. Required for an\n * app page to call its own server routes (/api/apps/<app-id>/...), which are\n * bearer-token protected. Falls back to plain fetch outside the platform.\n */\nexport function authFetch(input: string, init?: RequestInit): Promise<Response> {\n const runtime = getHostRuntime()\n if (runtime) return runtime.authFetch(input, init)\n return fetch(input, init)\n}\n\n/** A sidebar entry contributed by the app's client entry module. */\nexport interface AppSidebarItem {\n path: string\n label: string\n icon?: string\n}\n\n/**\n * Shape of the default export of an app's `client/index.tsx`.\n * `pages` keys must match `manifest.client.pages[].component`.\n */\nexport interface AppClientModule {\n id: string\n pages: Record<string, ComponentType | LazyExoticComponent<ComponentType>>\n sidebarItems?: AppSidebarItem[]\n}\n","// ========================================================================\n// Inventory — the deployment targets an app can deploy configuration to.\n//\n// \"Inventory\" is the app-facing name for the platform's *components*: the\n// servers (hostname/port), domains, and IP/CIDR ranges a customer has\n// registered as deploy targets. These helpers are a typed, convenient\n// surface over the platform's components API (/api/components), enriched\n// with `domains` and `ipRanges`.\n//\n// Framework-free (no React) — safe to import from any client code. Every\n// call goes through the same `authFetch` the '/client' subpath exports, so\n// requests carry the platform's Authorization header. Non-2xx responses are\n// surfaced as thrown Errors carrying the platform's error text.\n// ========================================================================\n\nimport type { InventoryItem, InventoryItemInput } from '../types/platform'\nimport { authFetch } from './index'\n\n/** Base route for the platform's components (inventory) API. */\nconst INVENTORY_API = '/api/components'\n\n/**\n * Loosely-typed shape of a raw component as returned by the platform, before\n * it is normalized down to the {@link InventoryItem} surface.\n */\ninterface RawInventoryItem {\n id: string\n hostname?: string\n port?: string\n type?: string[]\n domains?: string[]\n ipRanges?: string[]\n tags?: Array<{ id: string; name: string }>\n connectivityProviderId?: string | null\n credentialId?: string | null\n}\n\n/** Build an Error from a non-2xx response, preferring the platform's message. */\nasync function inventoryError(res: Response): Promise<Error> {\n const text = await res.text().catch(() => '')\n if (text) {\n try {\n const body = JSON.parse(text) as { error?: string; message?: string }\n const message = body?.error ?? body?.message\n if (message) return new Error(message)\n } catch {\n // Body was not JSON — fall through and use the raw text.\n }\n return new Error(text)\n }\n return new Error(`HTTP ${res.status}`)\n}\n\n/** Normalize a raw platform component into the typed InventoryItem surface. */\nfunction toInventoryItem(raw: RawInventoryItem): InventoryItem {\n return {\n id: String(raw.id),\n hostname: raw.hostname ?? '',\n port: raw.port ?? undefined,\n type: Array.isArray(raw.type) ? raw.type : undefined,\n domains: Array.isArray(raw.domains) ? raw.domains : [],\n ipRanges: Array.isArray(raw.ipRanges) ? raw.ipRanges : [],\n tags: Array.isArray(raw.tags)\n ? raw.tags.map((tag) => ({ id: String(tag.id), name: String(tag.name) }))\n : [],\n connectivityProviderId: raw.connectivityProviderId ?? null,\n credentialId: raw.credentialId ?? null,\n }\n}\n\n/**\n * A platform Tool. Each installed app is upserted as a Tool keyed by its\n * manifest `name`, and inventory items (components) belong to a tool.\n */\nexport interface Tool {\n id: string\n name: string\n vendor?: string\n}\n\n/**\n * Resolve the platform Tool for an app by its manifest name (the platform\n * upserts `Tool.name === app name`). The tool id is required by the platform\n * when creating an inventory item, so call this once and pass the id as\n * `toolId` to {@link addInventoryItem}. Returns null when no tool matches.\n *\n * GET /api/tools (the endpoint is paginated — `{ data, pagination }` — or a\n * bare array; both are handled).\n */\nexport async function resolveTool(name: string): Promise<Tool | null> {\n const res = await authFetch('/api/tools')\n if (!res.ok) throw await inventoryError(res)\n const body = (await res.json()) as unknown\n const tools: Tool[] = Array.isArray(body)\n ? (body as Tool[])\n : Array.isArray((body as { data?: unknown })?.data)\n ? ((body as { data: Tool[] }).data)\n : []\n return tools.find((tool) => tool.name === name) ?? null\n}\n\n/** List the customer's inventory (deployment targets). GET /api/components */\nexport async function listInventory(): Promise<InventoryItem[]> {\n const res = await authFetch(INVENTORY_API)\n if (!res.ok) throw await inventoryError(res)\n const data = (await res.json()) as RawInventoryItem[]\n return Array.isArray(data) ? data.map(toInventoryItem) : []\n}\n\n/** Add a new inventory item (deployment target). POST /api/components */\nexport async function addInventoryItem(input: InventoryItemInput): Promise<InventoryItem> {\n const res = await authFetch(INVENTORY_API, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(input),\n })\n if (!res.ok) throw await inventoryError(res)\n return toInventoryItem((await res.json()) as RawInventoryItem)\n}\n\n/** Update an existing inventory item. PUT /api/components/:id */\nexport async function updateInventoryItem(\n id: string,\n input: InventoryItemInput,\n): Promise<InventoryItem> {\n const res = await authFetch(`${INVENTORY_API}/${encodeURIComponent(id)}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(input),\n })\n if (!res.ok) throw await inventoryError(res)\n return toInventoryItem((await res.json()) as RawInventoryItem)\n}\n\n/** Remove an inventory item. DELETE /api/components/:id */\nexport async function removeInventoryItem(id: string): Promise<void> {\n const res = await authFetch(`${INVENTORY_API}/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n })\n // 204 No Content is the platform's success response for delete.\n if (!res.ok && res.status !== 204) throw await inventoryError(res)\n}\n","// ========================================================================\n// Connectivity providers — the customer's ZTNA providers (Tailscale,\n// WireGuard, ZeroTier, …), platform-managed under Settings → Connectivity.\n//\n// A thin reader over the platform's connectivity-providers API\n// (/api/connectivity-providers), used to populate the ZTNA link picker when\n// creating or editing an Access Server (a component). Framework-free — every\n// call goes through the same `authFetch` the '/client' subpath exports.\n// ========================================================================\n\nimport type { ConnectivityProviderRef } from '../types/platform'\nimport { authFetch } from './index'\n\n/** Base route for the platform's connectivity-providers API. */\nconst CONNECTIVITY_PROVIDERS_API = '/api/connectivity-providers'\n\ninterface RawConnectivityProvider {\n id: string\n name?: string\n providerType?: string\n status?: string\n}\n\n/** Build an Error from a non-2xx response, preferring the platform's message. */\nasync function providerError(res: Response): Promise<Error> {\n const text = await res.text().catch(() => '')\n if (text) {\n try {\n const body = JSON.parse(text) as { error?: string; message?: string }\n const message = body?.error ?? body?.message\n if (message) return new Error(message)\n } catch {\n // Body was not JSON — fall through and use the raw text.\n }\n return new Error(text)\n }\n return new Error(`HTTP ${res.status}`)\n}\n\n/**\n * List the customer's ZTNA connectivity providers, used to populate the Access\n * Server link picker. GET /api/connectivity-providers (the endpoint may return\n * a bare array or a paginated `{ data, ... }` shape — both are handled).\n */\nexport async function listConnectivityProviders(): Promise<ConnectivityProviderRef[]> {\n const res = await authFetch(CONNECTIVITY_PROVIDERS_API)\n if (!res.ok) throw await providerError(res)\n const body = (await res.json()) as unknown\n const providers: RawConnectivityProvider[] = Array.isArray(body)\n ? (body as RawConnectivityProvider[])\n : Array.isArray((body as { data?: unknown })?.data)\n ? ((body as { data: RawConnectivityProvider[] }).data)\n : []\n return providers.map((provider) => ({\n id: String(provider.id),\n name: provider.name ?? '',\n providerType: provider.providerType ?? undefined,\n status: provider.status ?? undefined,\n }))\n}\n","// ========================================================================\n// Credentials — how an app authenticates to a server (\"connection\").\n//\n// A \"connection\" pairs a server (a platform *component* — see inventory.ts)\n// with a *credential*: the account and write-only secret used to reach that\n// server. These helpers are a typed surface over the platform's credentials\n// API (POST /api/credentials, GET /api/tools/:toolId/credentials, PUT/DELETE\n// /api/credentials/:id).\n//\n// Framework-free (no React). Every call goes through the same `authFetch` the\n// '/client' subpath exports, so requests carry the platform's Authorization\n// header. Non-2xx responses are surfaced as thrown Errors carrying the\n// platform's error text.\n//\n// SECURITY: `listCredentials` returns a REDACTED {@link CredentialSummary} —\n// secret material (password / apiToken / certificate) is dropped before it\n// reaches app code, so secrets are never held in memory or logged. Only whether\n// a secret exists is surfaced (`hasSecret`). Secrets are write-only: they can be\n// set via create/update, never read back.\n// ========================================================================\n\nimport type { CredentialInput, CredentialSummary } from '../types/platform'\nimport { authFetch } from './index'\n\n/** Base route for the platform's credentials API. */\nconst CREDENTIALS_API = '/api/credentials'\n\n/**\n * Loosely-typed shape of a raw credential as returned by the platform, before\n * it is redacted down to the {@link CredentialSummary} surface. The secret\n * fields (`password` / `apiToken` / `certificate`) are read here only to derive\n * `hasSecret` — they are never carried into app-visible data.\n */\ninterface RawCredential {\n id: string\n name?: string\n username?: string\n type?: string | null\n endpoint?: string | null\n toolId?: string\n // The platform redacts secrets from credential responses and surfaces only\n // whether each is set via these flags. Older platforms may still send the\n // secret fields instead — both shapes are handled below.\n hasPassword?: boolean\n hasApiToken?: boolean\n hasCertificate?: boolean\n password?: string | null\n apiToken?: string | null\n certificate?: string | null\n}\n\n/** Build an Error from a non-2xx response, preferring the platform's message. */\nasync function credentialError(res: Response): Promise<Error> {\n const text = await res.text().catch(() => '')\n if (text) {\n try {\n const body = JSON.parse(text) as { error?: string; message?: string }\n const message = body?.error ?? body?.message\n if (message) return new Error(message)\n } catch {\n // Body was not JSON — fall through and use the raw text.\n }\n return new Error(text)\n }\n return new Error(`HTTP ${res.status}`)\n}\n\n/**\n * Redact a raw platform credential down to the app-visible summary, dropping\n * every secret field and surfacing only whether a secret is stored.\n */\nfunction toCredentialSummary(raw: RawCredential): CredentialSummary {\n // Prefer the redacted has* flags; fall back to the presence of the secret\n // fields themselves for older platforms that still return them.\n const hasSecret = Boolean(\n raw.hasApiToken ||\n raw.hasPassword ||\n (raw.apiToken && raw.apiToken.length > 0) ||\n (raw.password && raw.password.length > 0),\n )\n return {\n id: String(raw.id),\n name: raw.name ?? '',\n username: raw.username ?? '',\n type: raw.type ?? null,\n endpoint: raw.endpoint ?? null,\n toolId: raw.toolId ?? '',\n hasSecret,\n }\n}\n\n/**\n * List the redacted credentials registered for a tool. GET\n * /api/tools/:toolId/credentials. Secrets are stripped before return — see the\n * module's SECURITY note. Returns an empty array when the tool has none.\n */\nexport async function listCredentials(toolId: string): Promise<CredentialSummary[]> {\n const res = await authFetch(`/api/tools/${encodeURIComponent(toolId)}/credentials`)\n if (!res.ok) throw await credentialError(res)\n const data = (await res.json()) as unknown\n const rows: RawCredential[] = Array.isArray(data)\n ? (data as RawCredential[])\n : Array.isArray((data as { data?: unknown })?.data)\n ? ((data as { data: RawCredential[] }).data)\n : []\n return rows.map(toCredentialSummary)\n}\n\n/**\n * Create a credential. POST /api/credentials. The platform requires `name`,\n * `username`, `password`, `toolId`, and `tagIds` — this helper defaults\n * `tagIds` to `[]` and `password` to `''` (valid for token-only auth, where the\n * secret travels in `apiToken`). Returns the new credential's id.\n */\nexport async function createCredential(input: CredentialInput): Promise<{ id: string }> {\n const res = await authFetch(CREDENTIALS_API, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: input.name,\n username: input.username,\n password: input.password ?? '',\n apiToken: input.apiToken,\n type: input.type,\n endpoint: input.endpoint,\n toolId: input.toolId,\n tagIds: input.tagIds ?? [],\n }),\n })\n if (!res.ok) throw await credentialError(res)\n const body = (await res.json()) as { id?: string }\n return { id: String(body.id) }\n}\n\n/**\n * Update a credential. PUT /api/credentials/:id. Only the fields you pass are\n * changed; omit `password`/`apiToken` to leave the stored secret untouched.\n */\nexport async function updateCredential(\n id: string,\n input: Partial<CredentialInput>,\n): Promise<{ id: string }> {\n const body: Record<string, unknown> = {}\n if (input.name !== undefined) body.name = input.name\n if (input.username !== undefined) body.username = input.username\n if (input.password !== undefined) body.password = input.password\n if (input.apiToken !== undefined) body.apiToken = input.apiToken\n if (input.type !== undefined) body.type = input.type\n if (input.endpoint !== undefined) body.endpoint = input.endpoint\n if (input.tagIds !== undefined) body.tagIds = input.tagIds\n const res = await authFetch(`${CREDENTIALS_API}/${encodeURIComponent(id)}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!res.ok) throw await credentialError(res)\n const result = (await res.json().catch(() => ({}))) as { id?: string }\n return { id: result.id ? String(result.id) : id }\n}\n\n/** Remove a credential. DELETE /api/credentials/:id. */\nexport async function removeCredential(id: string): Promise<void> {\n const res = await authFetch(`${CREDENTIALS_API}/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n })\n // 204 No Content is the platform's success response for delete.\n if (!res.ok && res.status !== 204) throw await credentialError(res)\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import { ComponentType, LazyExoticComponent, Context } from 'react';
2
- import { F as InventoryItemInput, I as InventoryItem, f as AccessServerInput, e as AccessServer, y as ConnectivityProviderRef, B as CredentialInput, D as CredentialSummary, b as AppContextValue } from '../use-app-context-CEUSdc_c.cjs';
3
- export { A as AppBrandingDeclaration, z as Credential } from '../use-app-context-CEUSdc_c.cjs';
2
+ import { D as InventoryItemInput, I as InventoryItem, w as ConnectivityProviderRef, y as CredentialInput, z as CredentialSummary, b as AppContextValue } from '../use-app-context-hBtYClFu.cjs';
3
+ export { A as AppBrandingDeclaration, x as Credential } from '../use-app-context-hBtYClFu.cjs';
4
4
 
5
5
  /**
6
6
  * A platform Tool. Each installed app is upserted as a Tool keyed by its
@@ -30,14 +30,6 @@ declare function updateInventoryItem(id: string, input: InventoryItemInput): Pro
30
30
  /** Remove an inventory item. DELETE /api/components/:id */
31
31
  declare function removeInventoryItem(id: string): Promise<void>;
32
32
 
33
- /** List the customer's access servers (ZTNA gateways). GET /api/access-servers */
34
- declare function listAccessServers(): Promise<AccessServer[]>;
35
- /** Add a new access server (ZTNA gateway). POST /api/access-servers */
36
- declare function addAccessServer(input: AccessServerInput): Promise<AccessServer>;
37
- /** Update an existing access server. PUT /api/access-servers/:id */
38
- declare function updateAccessServer(id: string, input: AccessServerInput): Promise<AccessServer>;
39
- /** Remove an access server. DELETE /api/access-servers/:id */
40
- declare function removeAccessServer(id: string): Promise<void>;
41
33
  /**
42
34
  * List the customer's ZTNA connectivity providers, used to populate the Access
43
35
  * Server link picker. GET /api/connectivity-providers (the endpoint may return
@@ -131,4 +123,4 @@ interface AppClientModule {
131
123
  sidebarItems?: AppSidebarItem[];
132
124
  }
133
125
 
134
- export { AccessServer, AccessServerInput, type AppClientModule, type AppSidebarItem, ConnectivityProviderRef, CredentialInput, CredentialSummary, HOST_RUNTIME_GLOBAL, InventoryItem, InventoryItemInput, type Tool, type VeltrixHostRuntime, addAccessServer, addInventoryItem, authFetch, createCredential, getHostRuntime, listAccessServers, listConnectivityProviders, listCredentials, listInventory, removeAccessServer, removeCredential, removeInventoryItem, requireHostRuntime, resolveTool, updateAccessServer, updateCredential, updateInventoryItem };
126
+ export { type AppClientModule, type AppSidebarItem, ConnectivityProviderRef, CredentialInput, CredentialSummary, HOST_RUNTIME_GLOBAL, InventoryItem, InventoryItemInput, type Tool, type VeltrixHostRuntime, addInventoryItem, authFetch, createCredential, getHostRuntime, listConnectivityProviders, listCredentials, listInventory, removeCredential, removeInventoryItem, requireHostRuntime, resolveTool, updateCredential, updateInventoryItem };
@@ -1,6 +1,6 @@
1
1
  import { ComponentType, LazyExoticComponent, Context } from 'react';
2
- import { F as InventoryItemInput, I as InventoryItem, f as AccessServerInput, e as AccessServer, y as ConnectivityProviderRef, B as CredentialInput, D as CredentialSummary, b as AppContextValue } from '../use-app-context-CEUSdc_c.js';
3
- export { A as AppBrandingDeclaration, z as Credential } from '../use-app-context-CEUSdc_c.js';
2
+ import { D as InventoryItemInput, I as InventoryItem, w as ConnectivityProviderRef, y as CredentialInput, z as CredentialSummary, b as AppContextValue } from '../use-app-context-hBtYClFu.js';
3
+ export { A as AppBrandingDeclaration, x as Credential } from '../use-app-context-hBtYClFu.js';
4
4
 
5
5
  /**
6
6
  * A platform Tool. Each installed app is upserted as a Tool keyed by its
@@ -30,14 +30,6 @@ declare function updateInventoryItem(id: string, input: InventoryItemInput): Pro
30
30
  /** Remove an inventory item. DELETE /api/components/:id */
31
31
  declare function removeInventoryItem(id: string): Promise<void>;
32
32
 
33
- /** List the customer's access servers (ZTNA gateways). GET /api/access-servers */
34
- declare function listAccessServers(): Promise<AccessServer[]>;
35
- /** Add a new access server (ZTNA gateway). POST /api/access-servers */
36
- declare function addAccessServer(input: AccessServerInput): Promise<AccessServer>;
37
- /** Update an existing access server. PUT /api/access-servers/:id */
38
- declare function updateAccessServer(id: string, input: AccessServerInput): Promise<AccessServer>;
39
- /** Remove an access server. DELETE /api/access-servers/:id */
40
- declare function removeAccessServer(id: string): Promise<void>;
41
33
  /**
42
34
  * List the customer's ZTNA connectivity providers, used to populate the Access
43
35
  * Server link picker. GET /api/connectivity-providers (the endpoint may return
@@ -131,4 +123,4 @@ interface AppClientModule {
131
123
  sidebarItems?: AppSidebarItem[];
132
124
  }
133
125
 
134
- export { AccessServer, AccessServerInput, type AppClientModule, type AppSidebarItem, ConnectivityProviderRef, CredentialInput, CredentialSummary, HOST_RUNTIME_GLOBAL, InventoryItem, InventoryItemInput, type Tool, type VeltrixHostRuntime, addAccessServer, addInventoryItem, authFetch, createCredential, getHostRuntime, listAccessServers, listConnectivityProviders, listCredentials, listInventory, removeAccessServer, removeCredential, removeInventoryItem, requireHostRuntime, resolveTool, updateAccessServer, updateCredential, updateInventoryItem };
126
+ export { type AppClientModule, type AppSidebarItem, ConnectivityProviderRef, CredentialInput, CredentialSummary, HOST_RUNTIME_GLOBAL, InventoryItem, InventoryItemInput, type Tool, type VeltrixHostRuntime, addInventoryItem, authFetch, createCredential, getHostRuntime, listConnectivityProviders, listCredentials, listInventory, removeCredential, removeInventoryItem, requireHostRuntime, resolveTool, updateCredential, updateInventoryItem };
@@ -1,40 +1,32 @@
1
1
  import {
2
2
  HOST_RUNTIME_GLOBAL,
3
- addAccessServer,
4
3
  addInventoryItem,
5
4
  authFetch,
6
5
  createCredential,
7
6
  getHostRuntime,
8
- listAccessServers,
9
7
  listConnectivityProviders,
10
8
  listCredentials,
11
9
  listInventory,
12
- removeAccessServer,
13
10
  removeCredential,
14
11
  removeInventoryItem,
15
12
  requireHostRuntime,
16
13
  resolveTool,
17
- updateAccessServer,
18
14
  updateCredential,
19
15
  updateInventoryItem
20
- } from "../chunk-EVCWQYQY.js";
16
+ } from "../chunk-NY6C4REE.js";
21
17
  export {
22
18
  HOST_RUNTIME_GLOBAL,
23
- addAccessServer,
24
19
  addInventoryItem,
25
20
  authFetch,
26
21
  createCredential,
27
22
  getHostRuntime,
28
- listAccessServers,
29
23
  listConnectivityProviders,
30
24
  listCredentials,
31
25
  listInventory,
32
- removeAccessServer,
33
26
  removeCredential,
34
27
  removeInventoryItem,
35
28
  requireHostRuntime,
36
29
  resolveTool,
37
- updateAccessServer,
38
30
  updateCredential,
39
31
  updateInventoryItem
40
32
  };