@veltrixsecops/app-sdk 1.0.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -73,6 +73,66 @@ export default async function onInstall({ db, appId }: AppHookContext): Promise<
73
73
 
74
74
  ```tsx
75
75
  import { useAppContext, usePipelineStatus } from '@veltrixsecops/app-sdk/hooks'
76
+ import { authFetch } from '@veltrixsecops/app-sdk/client'
77
+ ```
78
+
79
+ Your `client/index.tsx` default-exports an `AppClientModule` (`{ id, pages, sidebarItems }`;
80
+ `pages` keys must match `manifest.client.pages[].component`). At packaging time the CLI
81
+ compiles it into a hermetic browser bundle (`client/dist/index.mjs`): `react`, `react-dom`,
82
+ `react/jsx-runtime`, and all `@veltrixsecops/app-sdk` imports are replaced with shims that
83
+ read the platform-provided runtime from `globalThis.__VELTRIX_APP_RUNTIME__`, so your
84
+ components render inside the host React tree with working hooks and shared context — never
85
+ bundle your own copy of React.
86
+
87
+ Two rules for app pages:
88
+
89
+ - Use **`authFetch`** (not plain `fetch`) for calls to your app's server routes
90
+ (`/api/apps/<app-id>/...`) — they are bearer-token protected and a plain `fetch`
91
+ receives 401s.
92
+ - Only import third-party client libraries if you accept them being compiled into your
93
+ bundle; keep pages lean.
94
+
95
+ ## Branding
96
+
97
+ Declare your vendor identity in the manifest and the platform applies it in defined
98
+ slots — the app's navbar (logo + accent color) and scoped CSS variables. The platform
99
+ controls where brand color appears, so it stays meaningful rather than theming the shell:
100
+
101
+ ```yaml
102
+ branding:
103
+ primaryColor: "#FC0000" # #RGB or #RRGGBB
104
+ logo: ./assets/logo.svg # svg (preferred) or png, <=128 KB, ~28px display height
105
+ ```
106
+
107
+ In pages, prefer the CSS variables (`--veltrix-app-primary`, `--veltrix-app-accent`);
108
+ use `useAppBranding()` from `./hooks` when you need the values programmatically.
109
+ SVG logos must not contain scripts or event handlers — the validator rejects them.
110
+
111
+ ## Standard app layout
112
+
113
+ Every Veltrix app follows one canonical folder structure — the CLI scaffolds it (`veltrix init`), `veltrix validate` warns on deviations, and the SDK exports it as constants (`APP_LAYOUT`, `HANDLER_NAMES`, `conventionalPaths(configTypeId)`):
114
+
115
+ ```
116
+ apps/<app-id>/
117
+ ├── manifest.yaml # App contract
118
+ ├── package.json / tsconfig.json / README.md
119
+ ├── config-types/<configTypeId>/ # Everything for one configuration type:
120
+ │ ├── canvas.yaml # form schema
121
+ │ ├── defaults.yaml # default values
122
+ │ ├── validate.ts, deploy.ts, rollback.ts,
123
+ │ ├── healthCheck.ts, driftDetect.ts, getStatus.ts
124
+ │ └── __tests__/
125
+ ├── lib/ # Shared app code (API clients)
126
+ ├── hooks/ # onInstall.ts, onUninstall.ts, ...
127
+ ├── migrations/ # SQL (with database.tablePrefix)
128
+ ├── server/index.ts # Route module (AppRouteContext)
129
+ ├── client/index.tsx + client/pages/ # Optional UI
130
+ └── assets/ # Optional icons
131
+ ```
132
+
133
+ ```ts
134
+ import { conventionalPaths } from '@veltrixsecops/app-sdk'
135
+ conventionalPaths('indexes').handlers.deploy // 'config-types/indexes/deploy'
76
136
  ```
77
137
 
78
138
  ## Package layout
@@ -1,6 +1,11 @@
1
+ import {
2
+ authFetch
3
+ } from "./chunk-PJN3ATPH.js";
4
+
1
5
  // src/hooks/use-app-context.ts
2
6
  import { createContext, useContext } from "react";
3
- var AppContext = createContext(null);
7
+ var hostContext = globalThis.__VELTRIX_APP_RUNTIME__?.AppContext;
8
+ var AppContext = hostContext ?? createContext(null);
4
9
  function useAppContext() {
5
10
  const ctx = useContext(AppContext);
6
11
  if (!ctx) {
@@ -18,7 +23,7 @@ function usePipelineStatus(appId) {
18
23
  const refresh = useCallback(async () => {
19
24
  try {
20
25
  setIsLoading(true);
21
- const response = await fetch(`/api/pipeline/summary?appId=${appId}`);
26
+ const response = await authFetch(`/api/pipeline/summary?appId=${appId}`);
22
27
  if (!response.ok) throw new Error(`Failed to fetch pipeline status`);
23
28
  const result = await response.json();
24
29
  setData(result);
@@ -35,9 +40,15 @@ function usePipelineStatus(appId) {
35
40
  return { data, isLoading, error, refresh };
36
41
  }
37
42
 
43
+ // src/hooks/use-app-branding.ts
44
+ function useAppBranding() {
45
+ return useAppContext().branding ?? null;
46
+ }
47
+
38
48
  export {
39
49
  AppContext,
40
50
  useAppContext,
41
- usePipelineStatus
51
+ usePipelineStatus,
52
+ useAppBranding
42
53
  };
43
- //# sourceMappingURL=chunk-TSEIWO6T.js.map
54
+ //# sourceMappingURL=chunk-JOJTOQZQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/use-app-context.ts","../src/hooks/use-pipeline-status.ts","../src/hooks/use-app-branding.ts"],"sourcesContent":["// ========================================================================\n// React hooks for app developers\n// These provide access to platform data and pipeline state\n// ========================================================================\n\nimport { createContext, useContext, type Context } from 'react'\nimport type { Component, Credential, Tag, User, Customer } from '../types/platform'\nimport type { AppBrandingDeclaration } from '../types/manifest'\n\nexport interface AppContextValue {\n appId: string\n customerId: string\n user: User | null\n customer: Customer | null\n\n // Platform data accessors\n getComponents: () => Promise<Component[]>\n getCredentials: () => Promise<Credential[]>\n getTags: () => Promise<Tag[]>\n\n // App settings\n settings: Record<string, unknown>\n\n /** The app's manifest branding, resolved by the platform (null when unset). */\n branding?: AppBrandingDeclaration | null\n}\n\n// Anchor the context on the host runtime when running inside the platform,\n// so a bundle that inlined its own SDK copy still shares the host's context\n// (two createContext objects never match, even with identical shapes).\nconst hostContext = (\n (globalThis as Record<string, unknown>).__VELTRIX_APP_RUNTIME__ as\n | { AppContext?: Context<AppContextValue | null> }\n | undefined\n)?.AppContext\n\nexport const AppContext: Context<AppContextValue | null> =\n hostContext ?? createContext<AppContextValue | null>(null)\n\n/**\n * Access the app context in any app component.\n *\n * @example\n * ```tsx\n * import { useAppContext } from '@veltrixsecops/app-sdk/hooks'\n *\n * function MyComponent() {\n * const { appId, settings, getComponents } = useAppContext()\n * // ...\n * }\n * ```\n */\nexport function useAppContext(): AppContextValue {\n const ctx = useContext(AppContext)\n if (!ctx) {\n throw new Error('useAppContext must be used within an AppContextProvider')\n }\n return ctx\n}\n","import { useState, useEffect, useCallback } from 'react'\nimport { authFetch } from '../client'\n\nexport interface PipelineStatusData {\n pendingApprovals: number\n activeDeployments: number\n failedDeployments: number\n unresolvedDrifts: number\n recentDeployments: Array<{\n id: string\n canvasName: string\n environment: string\n status: string\n startedAt: string\n completedAt?: string\n }>\n}\n\n/**\n * Hook to access pipeline status for the current app/customer.\n *\n * @example\n * ```tsx\n * import { usePipelineStatus } from '@veltrixsecops/app-sdk/hooks'\n *\n * function Dashboard() {\n * const { data, isLoading } = usePipelineStatus('my-app')\n * if (isLoading) return <Spinner />\n * return <div>{data.activeDeployments} active deployments</div>\n * }\n * ```\n */\nexport function usePipelineStatus(appId: string) {\n const [data, setData] = useState<PipelineStatusData | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const refresh = useCallback(async () => {\n try {\n setIsLoading(true)\n // Platform APIs are bearer-token protected — plain fetch would 401\n const response = await authFetch(`/api/pipeline/summary?appId=${appId}`)\n if (!response.ok) throw new Error(`Failed to fetch pipeline status`)\n const result = await response.json()\n setData(result)\n setError(null)\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Unknown error'))\n } finally {\n setIsLoading(false)\n }\n }, [appId])\n\n useEffect(() => {\n refresh()\n }, [refresh])\n\n return { data, isLoading, error, refresh }\n}\n","import { useAppContext } from './use-app-context'\nimport type { AppBrandingDeclaration } from '../types/manifest'\n\n/**\n * The app's brand identity as declared in manifest.yaml `branding`.\n *\n * The platform already applies it in the defined slots (the app navbar and\n * the scoped CSS variables --veltrix-app-primary / --veltrix-app-accent on\n * the app page container). Use this hook only when a page needs the values\n * programmatically — prefer the CSS variables for styling:\n *\n * @example\n * ```tsx\n * <span style={{ color: 'var(--veltrix-app-primary)' }}>12 detections</span>\n * ```\n */\nexport function useAppBranding(): AppBrandingDeclaration | null {\n return useAppContext().branding ?? null\n}\n"],"mappings":";;;;;AAKA,SAAS,eAAe,kBAAgC;AAyBxD,IAAM,cACH,WAAuC,yBAGvC;AAEI,IAAM,aACX,eAAe,cAAsC,IAAI;AAepD,SAAS,gBAAiC;AAC/C,QAAM,MAAM,WAAW,UAAU;AACjC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO;AACT;;;AC1DA,SAAS,UAAU,WAAW,mBAAmB;AAgC1C,SAAS,kBAAkB,OAAe;AAC/C,QAAM,CAAC,MAAM,OAAO,IAAI,SAAoC,IAAI;AAChE,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAC/C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAuB,IAAI;AAErD,QAAM,UAAU,YAAY,YAAY;AACtC,QAAI;AACF,mBAAa,IAAI;AAEjB,YAAM,WAAW,MAAM,UAAU,+BAA+B,KAAK,EAAE;AACvE,UAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,iCAAiC;AACnE,YAAM,SAAS,MAAM,SAAS,KAAK;AACnC,cAAQ,MAAM;AACd,eAAS,IAAI;AAAA,IACf,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,eAAe,CAAC;AAAA,IAClE,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AACd,YAAQ;AAAA,EACV,GAAG,CAAC,OAAO,CAAC;AAEZ,SAAO,EAAE,MAAM,WAAW,OAAO,QAAQ;AAC3C;;;AC1CO,SAAS,iBAAgD;AAC9D,SAAO,cAAc,EAAE,YAAY;AACrC;","names":[]}
@@ -0,0 +1,28 @@
1
+ // src/client/index.ts
2
+ var HOST_RUNTIME_GLOBAL = "__VELTRIX_APP_RUNTIME__";
3
+ function getHostRuntime() {
4
+ const runtime = globalThis[HOST_RUNTIME_GLOBAL];
5
+ return runtime ?? null;
6
+ }
7
+ function requireHostRuntime() {
8
+ const runtime = getHostRuntime();
9
+ if (!runtime) {
10
+ throw new Error(
11
+ `Veltrix host runtime not found \u2014 app client bundles only run inside the Veltrix platform (missing globalThis.${HOST_RUNTIME_GLOBAL})`
12
+ );
13
+ }
14
+ return runtime;
15
+ }
16
+ function authFetch(input, init) {
17
+ const runtime = getHostRuntime();
18
+ if (runtime) return runtime.authFetch(input, init);
19
+ return fetch(input, init);
20
+ }
21
+
22
+ export {
23
+ HOST_RUNTIME_GLOBAL,
24
+ getHostRuntime,
25
+ requireHostRuntime,
26
+ authFetch
27
+ };
28
+ //# sourceMappingURL=chunk-PJN3ATPH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client/index.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/** 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\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":";AAuBO,IAAM,sBAAsB;AA8B5B,SAAS,iBAA4C;AAC1D,QAAM,UAAW,WAAuC,mBAAmB;AAC3E,SAAQ,WAAkC;AAC5C;AAGO,SAAS,qBAAyC;AACvD,QAAM,UAAU,eAAe;AAC/B,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR,qHAC0C,mBAAmB;AAAA,IAC/D;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,UAAU,OAAe,MAAuC;AAC9E,QAAM,UAAU,eAAe;AAC/B,MAAI,QAAS,QAAO,QAAQ,UAAU,OAAO,IAAI;AACjD,SAAO,MAAM,OAAO,IAAI;AAC1B;","names":[]}
@@ -30,4 +30,4 @@ export {
30
30
  defineHealthChecker,
31
31
  defineDriftDetector
32
32
  };
33
- //# sourceMappingURL=chunk-PJCHU6ZZ.js.map
33
+ //# sourceMappingURL=chunk-VWFTOFTI.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/pipeline/define-validator.ts","../src/pipeline/define-deployer.ts","../src/pipeline/define-rollback-handler.ts","../src/pipeline/define-health-checker.ts","../src/pipeline/define-drift-detector.ts"],"sourcesContent":["import type { PipelineContext, ValidationResult } from '../types/pipeline'\n\n/**\n * Define a validation handler for a configuration type.\n *\n * @example\n * ```ts\n * import { defineValidator } from '@veltrixsecops/app-sdk/pipeline'\n *\n * export default defineValidator(async (ctx) => {\n * const errors = []\n * const name = ctx.canvas.sections[0]?.fields['name']\n * if (!name) {\n * errors.push({ field: 'name', message: 'Name is required', code: 'REQUIRED' })\n * }\n * return { valid: errors.length === 0, errors, warnings: [] }\n * })\n * ```\n */\nexport function defineValidator(\n handler: (ctx: PipelineContext) => Promise<ValidationResult>,\n): (ctx: PipelineContext) => Promise<ValidationResult> {\n return handler\n}\n","import type { DeployContext, DeployResult } from '../types/pipeline'\n\n/**\n * Define a deploy handler for a configuration type.\n *\n * @example\n * ```ts\n * import { defineDeployer } from '@veltrixsecops/app-sdk/pipeline'\n *\n * export default defineDeployer(async (ctx) => {\n * const { component, credential, connectivity, canvas } = ctx\n * // Push configuration to the tool\n * return { success: true, message: 'Deployed', rollbackData: previousState }\n * })\n * ```\n */\nexport function defineDeployer(\n handler: (ctx: DeployContext) => Promise<DeployResult>,\n): (ctx: DeployContext) => Promise<DeployResult> {\n return handler\n}\n","import type { RollbackContext, RollbackResult } from '../types/pipeline'\r\n\r\n/**\r\n * Define a rollback handler for a configuration type.\r\n */\r\nexport function defineRollbackHandler(\r\n handler: (ctx: RollbackContext) => Promise<RollbackResult>,\r\n): (ctx: RollbackContext) => Promise<RollbackResult> {\r\n return handler\r\n}\r\n","import type { HealthCheckContext, HealthCheckResult } from '../types/pipeline'\r\n\r\n/**\r\n * Define a health check handler for a configuration type.\r\n */\r\nexport function defineHealthChecker(\r\n handler: (ctx: HealthCheckContext) => Promise<HealthCheckResult>,\r\n): (ctx: HealthCheckContext) => Promise<HealthCheckResult> {\r\n return handler\r\n}\r\n","import type { DriftContext, DriftResult } from '../types/pipeline'\r\n\r\n/**\r\n * Define a drift detection handler for a configuration type.\r\n */\r\nexport function defineDriftDetector(\r\n handler: (ctx: DriftContext) => Promise<DriftResult>,\r\n): (ctx: DriftContext) => Promise<DriftResult> {\r\n return handler\r\n}\r\n"],"mappings":";AAmBO,SAAS,gBACd,SACqD;AACrD,SAAO;AACT;;;ACPO,SAAS,eACd,SAC+C;AAC/C,SAAO;AACT;;;ACfO,SAAS,sBACd,SACmD;AACnD,SAAO;AACT;;;ACJO,SAAS,oBACd,SACyD;AACzD,SAAO;AACT;;;ACJO,SAAS,oBACd,SAC6C;AAC7C,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/pipeline/define-validator.ts","../src/pipeline/define-deployer.ts","../src/pipeline/define-rollback-handler.ts","../src/pipeline/define-health-checker.ts","../src/pipeline/define-drift-detector.ts"],"sourcesContent":["import type { PipelineContext, ValidationResult } from '../types/pipeline'\n\n/**\n * Define a validation handler for a configuration type.\n *\n * @example\n * ```ts\n * import { defineValidator } from '@veltrixsecops/app-sdk/pipeline'\n *\n * export default defineValidator(async (ctx) => {\n * const errors = []\n * const name = ctx.canvas.sections[0]?.fields['name']\n * if (!name) {\n * errors.push({ field: 'name', message: 'Name is required', code: 'REQUIRED' })\n * }\n * return { valid: errors.length === 0, errors, warnings: [] }\n * })\n * ```\n */\nexport function defineValidator(\n handler: (ctx: PipelineContext) => Promise<ValidationResult>,\n): (ctx: PipelineContext) => Promise<ValidationResult> {\n return handler\n}\n","import type { DeployContext, DeployResult } from '../types/pipeline'\n\n/**\n * Define a deploy handler for a configuration type.\n *\n * @example\n * ```ts\n * import { defineDeployer } from '@veltrixsecops/app-sdk/pipeline'\n *\n * export default defineDeployer(async (ctx) => {\n * const { component, credential, connectivity, canvas } = ctx\n * // Push configuration to the tool\n * return { success: true, message: 'Deployed', rollbackData: previousState }\n * })\n * ```\n */\nexport function defineDeployer(\n handler: (ctx: DeployContext) => Promise<DeployResult>,\n): (ctx: DeployContext) => Promise<DeployResult> {\n return handler\n}\n","import type { RollbackContext, RollbackResult } from '../types/pipeline'\n\n/**\n * Define a rollback handler for a configuration type.\n */\nexport function defineRollbackHandler(\n handler: (ctx: RollbackContext) => Promise<RollbackResult>,\n): (ctx: RollbackContext) => Promise<RollbackResult> {\n return handler\n}\n","import type { HealthCheckContext, HealthCheckResult } from '../types/pipeline'\n\n/**\n * Define a health check handler for a configuration type.\n */\nexport function defineHealthChecker(\n handler: (ctx: HealthCheckContext) => Promise<HealthCheckResult>,\n): (ctx: HealthCheckContext) => Promise<HealthCheckResult> {\n return handler\n}\n","import type { DriftContext, DriftResult } from '../types/pipeline'\n\n/**\n * Define a drift detection handler for a configuration type.\n */\nexport function defineDriftDetector(\n handler: (ctx: DriftContext) => Promise<DriftResult>,\n): (ctx: DriftContext) => Promise<DriftResult> {\n return handler\n}\n"],"mappings":";AAmBO,SAAS,gBACd,SACqD;AACrD,SAAO;AACT;;;ACPO,SAAS,eACd,SAC+C;AAC/C,SAAO;AACT;;;ACfO,SAAS,sBACd,SACmD;AACnD,SAAO;AACT;;;ACJO,SAAS,oBACd,SACyD;AACzD,SAAO;AACT;;;ACJO,SAAS,oBACd,SAC6C;AAC7C,SAAO;AACT;","names":[]}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/client/index.ts
21
+ var client_exports = {};
22
+ __export(client_exports, {
23
+ HOST_RUNTIME_GLOBAL: () => HOST_RUNTIME_GLOBAL,
24
+ authFetch: () => authFetch,
25
+ getHostRuntime: () => getHostRuntime,
26
+ requireHostRuntime: () => requireHostRuntime
27
+ });
28
+ module.exports = __toCommonJS(client_exports);
29
+ var HOST_RUNTIME_GLOBAL = "__VELTRIX_APP_RUNTIME__";
30
+ function getHostRuntime() {
31
+ const runtime = globalThis[HOST_RUNTIME_GLOBAL];
32
+ return runtime ?? null;
33
+ }
34
+ function requireHostRuntime() {
35
+ const runtime = getHostRuntime();
36
+ if (!runtime) {
37
+ throw new Error(
38
+ `Veltrix host runtime not found \u2014 app client bundles only run inside the Veltrix platform (missing globalThis.${HOST_RUNTIME_GLOBAL})`
39
+ );
40
+ }
41
+ return runtime;
42
+ }
43
+ function authFetch(input, init) {
44
+ const runtime = getHostRuntime();
45
+ if (runtime) return runtime.authFetch(input, init);
46
+ return fetch(input, init);
47
+ }
48
+ // Annotate the CommonJS export names for ESM import in node:
49
+ 0 && (module.exports = {
50
+ HOST_RUNTIME_GLOBAL,
51
+ authFetch,
52
+ getHostRuntime,
53
+ requireHostRuntime
54
+ });
55
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/client/index.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/** 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\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBO,IAAM,sBAAsB;AA8B5B,SAAS,iBAA4C;AAC1D,QAAM,UAAW,WAAuC,mBAAmB;AAC3E,SAAQ,WAAkC;AAC5C;AAGO,SAAS,qBAAyC;AACvD,QAAM,UAAU,eAAe;AAC/B,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR,qHAC0C,mBAAmB;AAAA,IAC/D;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,UAAU,OAAe,MAAuC;AAC9E,QAAM,UAAU,eAAe;AAC/B,MAAI,QAAS,QAAO,QAAQ,UAAU,OAAO,IAAI;AACjD,SAAO,MAAM,OAAO,IAAI;AAC1B;","names":[]}
@@ -0,0 +1,59 @@
1
+ import { ComponentType, LazyExoticComponent, Context } from 'react';
2
+ import { A as AppContextValue } from '../use-app-context-DdrtEPeb.cjs';
3
+ export { a as AppBrandingDeclaration } from '../use-app-context-DdrtEPeb.cjs';
4
+
5
+ /** Name of the global the platform installs before loading app bundles. */
6
+ declare const HOST_RUNTIME_GLOBAL = "__VELTRIX_APP_RUNTIME__";
7
+ /**
8
+ * The runtime surface the platform exposes to app client bundles.
9
+ * The react/reactDom/jsxRuntime members are the host's own module objects —
10
+ * app bundles are compiled with shims that re-export them, guaranteeing a
11
+ * single React instance per page.
12
+ */
13
+ interface VeltrixHostRuntime {
14
+ /** The host's `react` module object. */
15
+ react: unknown;
16
+ /** The host's `react-dom` module object. */
17
+ reactDom: unknown;
18
+ /** The host's `react-dom/client` module object. */
19
+ reactDomClient?: unknown;
20
+ /** The host's `react/jsx-runtime` module object. */
21
+ jsxRuntime: unknown;
22
+ /** Shared app context — the host wraps app pages in its Provider. */
23
+ AppContext: Context<AppContextValue | null>;
24
+ /** fetch() with the platform's Authorization header attached. */
25
+ authFetch: (input: string, init?: RequestInit) => Promise<Response>;
26
+ /**
27
+ * The SDK surface app bundles receive for `@veltrixsecops/app-sdk`,
28
+ * `.../hooks`, and `.../client` imports (useAppContext, AppContext,
29
+ * usePipelineStatus, authFetch, getHostRuntime, ...).
30
+ */
31
+ sdk: Record<string, unknown>;
32
+ }
33
+ /** Read the host runtime, or null outside the platform (tests, storybook). */
34
+ declare function getHostRuntime(): VeltrixHostRuntime | null;
35
+ /** Read the host runtime, throwing a diagnosable error when absent. */
36
+ declare function requireHostRuntime(): VeltrixHostRuntime;
37
+ /**
38
+ * fetch() that carries the platform's Authorization header. Required for an
39
+ * app page to call its own server routes (/api/apps/<app-id>/...), which are
40
+ * bearer-token protected. Falls back to plain fetch outside the platform.
41
+ */
42
+ declare function authFetch(input: string, init?: RequestInit): Promise<Response>;
43
+ /** A sidebar entry contributed by the app's client entry module. */
44
+ interface AppSidebarItem {
45
+ path: string;
46
+ label: string;
47
+ icon?: string;
48
+ }
49
+ /**
50
+ * Shape of the default export of an app's `client/index.tsx`.
51
+ * `pages` keys must match `manifest.client.pages[].component`.
52
+ */
53
+ interface AppClientModule {
54
+ id: string;
55
+ pages: Record<string, ComponentType | LazyExoticComponent<ComponentType>>;
56
+ sidebarItems?: AppSidebarItem[];
57
+ }
58
+
59
+ export { type AppClientModule, type AppSidebarItem, HOST_RUNTIME_GLOBAL, type VeltrixHostRuntime, authFetch, getHostRuntime, requireHostRuntime };
@@ -0,0 +1,59 @@
1
+ import { ComponentType, LazyExoticComponent, Context } from 'react';
2
+ import { A as AppContextValue } from '../use-app-context-DdrtEPeb.js';
3
+ export { a as AppBrandingDeclaration } from '../use-app-context-DdrtEPeb.js';
4
+
5
+ /** Name of the global the platform installs before loading app bundles. */
6
+ declare const HOST_RUNTIME_GLOBAL = "__VELTRIX_APP_RUNTIME__";
7
+ /**
8
+ * The runtime surface the platform exposes to app client bundles.
9
+ * The react/reactDom/jsxRuntime members are the host's own module objects —
10
+ * app bundles are compiled with shims that re-export them, guaranteeing a
11
+ * single React instance per page.
12
+ */
13
+ interface VeltrixHostRuntime {
14
+ /** The host's `react` module object. */
15
+ react: unknown;
16
+ /** The host's `react-dom` module object. */
17
+ reactDom: unknown;
18
+ /** The host's `react-dom/client` module object. */
19
+ reactDomClient?: unknown;
20
+ /** The host's `react/jsx-runtime` module object. */
21
+ jsxRuntime: unknown;
22
+ /** Shared app context — the host wraps app pages in its Provider. */
23
+ AppContext: Context<AppContextValue | null>;
24
+ /** fetch() with the platform's Authorization header attached. */
25
+ authFetch: (input: string, init?: RequestInit) => Promise<Response>;
26
+ /**
27
+ * The SDK surface app bundles receive for `@veltrixsecops/app-sdk`,
28
+ * `.../hooks`, and `.../client` imports (useAppContext, AppContext,
29
+ * usePipelineStatus, authFetch, getHostRuntime, ...).
30
+ */
31
+ sdk: Record<string, unknown>;
32
+ }
33
+ /** Read the host runtime, or null outside the platform (tests, storybook). */
34
+ declare function getHostRuntime(): VeltrixHostRuntime | null;
35
+ /** Read the host runtime, throwing a diagnosable error when absent. */
36
+ declare function requireHostRuntime(): VeltrixHostRuntime;
37
+ /**
38
+ * fetch() that carries the platform's Authorization header. Required for an
39
+ * app page to call its own server routes (/api/apps/<app-id>/...), which are
40
+ * bearer-token protected. Falls back to plain fetch outside the platform.
41
+ */
42
+ declare function authFetch(input: string, init?: RequestInit): Promise<Response>;
43
+ /** A sidebar entry contributed by the app's client entry module. */
44
+ interface AppSidebarItem {
45
+ path: string;
46
+ label: string;
47
+ icon?: string;
48
+ }
49
+ /**
50
+ * Shape of the default export of an app's `client/index.tsx`.
51
+ * `pages` keys must match `manifest.client.pages[].component`.
52
+ */
53
+ interface AppClientModule {
54
+ id: string;
55
+ pages: Record<string, ComponentType | LazyExoticComponent<ComponentType>>;
56
+ sidebarItems?: AppSidebarItem[];
57
+ }
58
+
59
+ export { type AppClientModule, type AppSidebarItem, HOST_RUNTIME_GLOBAL, type VeltrixHostRuntime, authFetch, getHostRuntime, requireHostRuntime };
@@ -0,0 +1,13 @@
1
+ import {
2
+ HOST_RUNTIME_GLOBAL,
3
+ authFetch,
4
+ getHostRuntime,
5
+ requireHostRuntime
6
+ } from "../chunk-PJN3ATPH.js";
7
+ export {
8
+ HOST_RUNTIME_GLOBAL,
9
+ authFetch,
10
+ getHostRuntime,
11
+ requireHostRuntime
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var hooks_exports = {};
22
22
  __export(hooks_exports, {
23
23
  AppContext: () => AppContext,
24
+ useAppBranding: () => useAppBranding,
24
25
  useAppContext: () => useAppContext,
25
26
  usePipelineStatus: () => usePipelineStatus
26
27
  });
@@ -28,7 +29,8 @@ module.exports = __toCommonJS(hooks_exports);
28
29
 
29
30
  // src/hooks/use-app-context.ts
30
31
  var import_react = require("react");
31
- var AppContext = (0, import_react.createContext)(null);
32
+ var hostContext = globalThis.__VELTRIX_APP_RUNTIME__?.AppContext;
33
+ var AppContext = hostContext ?? (0, import_react.createContext)(null);
32
34
  function useAppContext() {
33
35
  const ctx = (0, import_react.useContext)(AppContext);
34
36
  if (!ctx) {
@@ -39,6 +41,20 @@ function useAppContext() {
39
41
 
40
42
  // src/hooks/use-pipeline-status.ts
41
43
  var import_react2 = require("react");
44
+
45
+ // src/client/index.ts
46
+ var HOST_RUNTIME_GLOBAL = "__VELTRIX_APP_RUNTIME__";
47
+ function getHostRuntime() {
48
+ const runtime = globalThis[HOST_RUNTIME_GLOBAL];
49
+ return runtime ?? null;
50
+ }
51
+ function authFetch(input, init) {
52
+ const runtime = getHostRuntime();
53
+ if (runtime) return runtime.authFetch(input, init);
54
+ return fetch(input, init);
55
+ }
56
+
57
+ // src/hooks/use-pipeline-status.ts
42
58
  function usePipelineStatus(appId) {
43
59
  const [data, setData] = (0, import_react2.useState)(null);
44
60
  const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
@@ -46,7 +62,7 @@ function usePipelineStatus(appId) {
46
62
  const refresh = (0, import_react2.useCallback)(async () => {
47
63
  try {
48
64
  setIsLoading(true);
49
- const response = await fetch(`/api/pipeline/summary?appId=${appId}`);
65
+ const response = await authFetch(`/api/pipeline/summary?appId=${appId}`);
50
66
  if (!response.ok) throw new Error(`Failed to fetch pipeline status`);
51
67
  const result = await response.json();
52
68
  setData(result);
@@ -62,9 +78,15 @@ function usePipelineStatus(appId) {
62
78
  }, [refresh]);
63
79
  return { data, isLoading, error, refresh };
64
80
  }
81
+
82
+ // src/hooks/use-app-branding.ts
83
+ function useAppBranding() {
84
+ return useAppContext().branding ?? null;
85
+ }
65
86
  // Annotate the CommonJS export names for ESM import in node:
66
87
  0 && (module.exports = {
67
88
  AppContext,
89
+ useAppBranding,
68
90
  useAppContext,
69
91
  usePipelineStatus
70
92
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/index.ts","../../src/hooks/use-app-context.ts","../../src/hooks/use-pipeline-status.ts"],"sourcesContent":["export { useAppContext, AppContext, type AppContextValue } from './use-app-context'\r\nexport { usePipelineStatus, type PipelineStatusData } from './use-pipeline-status'\r\n","// ========================================================================\n// React hooks for app developers\n// These provide access to platform data and pipeline state\n// ========================================================================\n\nimport { createContext, useContext } from 'react'\nimport type { Component, Credential, Tag, User, Customer } from '../types/platform'\n\nexport interface AppContextValue {\n appId: string\n customerId: string\n user: User | null\n customer: Customer | null\n\n // Platform data accessors\n getComponents: () => Promise<Component[]>\n getCredentials: () => Promise<Credential[]>\n getTags: () => Promise<Tag[]>\n\n // App settings\n settings: Record<string, unknown>\n}\n\nexport const AppContext = createContext<AppContextValue | null>(null)\n\n/**\n * Access the app context in any app component.\n *\n * @example\n * ```tsx\n * import { useAppContext } from '@veltrixsecops/app-sdk/hooks'\n *\n * function MyComponent() {\n * const { appId, settings, getComponents } = useAppContext()\n * // ...\n * }\n * ```\n */\nexport function useAppContext(): AppContextValue {\n const ctx = useContext(AppContext)\n if (!ctx) {\n throw new Error('useAppContext must be used within an AppContextProvider')\n }\n return ctx\n}\n","import { useState, useEffect, useCallback } from 'react'\n\nexport interface PipelineStatusData {\n pendingApprovals: number\n activeDeployments: number\n failedDeployments: number\n unresolvedDrifts: number\n recentDeployments: Array<{\n id: string\n canvasName: string\n environment: string\n status: string\n startedAt: string\n completedAt?: string\n }>\n}\n\n/**\n * Hook to access pipeline status for the current app/customer.\n *\n * @example\n * ```tsx\n * import { usePipelineStatus } from '@veltrixsecops/app-sdk/hooks'\n *\n * function Dashboard() {\n * const { data, isLoading } = usePipelineStatus('my-app')\n * if (isLoading) return <Spinner />\n * return <div>{data.activeDeployments} active deployments</div>\n * }\n * ```\n */\nexport function usePipelineStatus(appId: string) {\n const [data, setData] = useState<PipelineStatusData | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const refresh = useCallback(async () => {\n try {\n setIsLoading(true)\n const response = await fetch(`/api/pipeline/summary?appId=${appId}`)\n if (!response.ok) throw new Error(`Failed to fetch pipeline status`)\n const result = await response.json()\n setData(result)\n setError(null)\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Unknown error'))\n } finally {\n setIsLoading(false)\n }\n }, [appId])\n\n useEffect(() => {\n refresh()\n }, [refresh])\n\n return { data, isLoading, error, refresh }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACKA,mBAA0C;AAkBnC,IAAM,iBAAa,4BAAsC,IAAI;AAe7D,SAAS,gBAAiC;AAC/C,QAAM,UAAM,yBAAW,UAAU;AACjC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO;AACT;;;AC5CA,IAAAA,gBAAiD;AA+B1C,SAAS,kBAAkB,OAAe;AAC/C,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAoC,IAAI;AAChE,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,IAAI;AAC/C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AAErD,QAAM,cAAU,2BAAY,YAAY;AACtC,QAAI;AACF,mBAAa,IAAI;AACjB,YAAM,WAAW,MAAM,MAAM,+BAA+B,KAAK,EAAE;AACnE,UAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,iCAAiC;AACnE,YAAM,SAAS,MAAM,SAAS,KAAK;AACnC,cAAQ,MAAM;AACd,eAAS,IAAI;AAAA,IACf,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,eAAe,CAAC;AAAA,IAClE,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,+BAAU,MAAM;AACd,YAAQ;AAAA,EACV,GAAG,CAAC,OAAO,CAAC;AAEZ,SAAO,EAAE,MAAM,WAAW,OAAO,QAAQ;AAC3C;","names":["import_react"]}
1
+ {"version":3,"sources":["../../src/hooks/index.ts","../../src/hooks/use-app-context.ts","../../src/hooks/use-pipeline-status.ts","../../src/client/index.ts","../../src/hooks/use-app-branding.ts"],"sourcesContent":["export { useAppContext, AppContext, type AppContextValue } from './use-app-context'\nexport { usePipelineStatus, type PipelineStatusData } from './use-pipeline-status'\nexport { useAppBranding } from './use-app-branding'\n","// ========================================================================\n// React hooks for app developers\n// These provide access to platform data and pipeline state\n// ========================================================================\n\nimport { createContext, useContext, type Context } from 'react'\nimport type { Component, Credential, Tag, User, Customer } from '../types/platform'\nimport type { AppBrandingDeclaration } from '../types/manifest'\n\nexport interface AppContextValue {\n appId: string\n customerId: string\n user: User | null\n customer: Customer | null\n\n // Platform data accessors\n getComponents: () => Promise<Component[]>\n getCredentials: () => Promise<Credential[]>\n getTags: () => Promise<Tag[]>\n\n // App settings\n settings: Record<string, unknown>\n\n /** The app's manifest branding, resolved by the platform (null when unset). */\n branding?: AppBrandingDeclaration | null\n}\n\n// Anchor the context on the host runtime when running inside the platform,\n// so a bundle that inlined its own SDK copy still shares the host's context\n// (two createContext objects never match, even with identical shapes).\nconst hostContext = (\n (globalThis as Record<string, unknown>).__VELTRIX_APP_RUNTIME__ as\n | { AppContext?: Context<AppContextValue | null> }\n | undefined\n)?.AppContext\n\nexport const AppContext: Context<AppContextValue | null> =\n hostContext ?? createContext<AppContextValue | null>(null)\n\n/**\n * Access the app context in any app component.\n *\n * @example\n * ```tsx\n * import { useAppContext } from '@veltrixsecops/app-sdk/hooks'\n *\n * function MyComponent() {\n * const { appId, settings, getComponents } = useAppContext()\n * // ...\n * }\n * ```\n */\nexport function useAppContext(): AppContextValue {\n const ctx = useContext(AppContext)\n if (!ctx) {\n throw new Error('useAppContext must be used within an AppContextProvider')\n }\n return ctx\n}\n","import { useState, useEffect, useCallback } from 'react'\nimport { authFetch } from '../client'\n\nexport interface PipelineStatusData {\n pendingApprovals: number\n activeDeployments: number\n failedDeployments: number\n unresolvedDrifts: number\n recentDeployments: Array<{\n id: string\n canvasName: string\n environment: string\n status: string\n startedAt: string\n completedAt?: string\n }>\n}\n\n/**\n * Hook to access pipeline status for the current app/customer.\n *\n * @example\n * ```tsx\n * import { usePipelineStatus } from '@veltrixsecops/app-sdk/hooks'\n *\n * function Dashboard() {\n * const { data, isLoading } = usePipelineStatus('my-app')\n * if (isLoading) return <Spinner />\n * return <div>{data.activeDeployments} active deployments</div>\n * }\n * ```\n */\nexport function usePipelineStatus(appId: string) {\n const [data, setData] = useState<PipelineStatusData | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n const [error, setError] = useState<Error | null>(null)\n\n const refresh = useCallback(async () => {\n try {\n setIsLoading(true)\n // Platform APIs are bearer-token protected — plain fetch would 401\n const response = await authFetch(`/api/pipeline/summary?appId=${appId}`)\n if (!response.ok) throw new Error(`Failed to fetch pipeline status`)\n const result = await response.json()\n setData(result)\n setError(null)\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Unknown error'))\n } finally {\n setIsLoading(false)\n }\n }, [appId])\n\n useEffect(() => {\n refresh()\n }, [refresh])\n\n return { data, isLoading, error, refresh }\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/** 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\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","import { useAppContext } from './use-app-context'\nimport type { AppBrandingDeclaration } from '../types/manifest'\n\n/**\n * The app's brand identity as declared in manifest.yaml `branding`.\n *\n * The platform already applies it in the defined slots (the app navbar and\n * the scoped CSS variables --veltrix-app-primary / --veltrix-app-accent on\n * the app page container). Use this hook only when a page needs the values\n * programmatically — prefer the CSS variables for styling:\n *\n * @example\n * ```tsx\n * <span style={{ color: 'var(--veltrix-app-primary)' }}>12 detections</span>\n * ```\n */\nexport function useAppBranding(): AppBrandingDeclaration | null {\n return useAppContext().branding ?? null\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACKA,mBAAwD;AAyBxD,IAAM,cACH,WAAuC,yBAGvC;AAEI,IAAM,aACX,mBAAe,4BAAsC,IAAI;AAepD,SAAS,gBAAiC;AAC/C,QAAM,UAAM,yBAAW,UAAU;AACjC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO;AACT;;;AC1DA,IAAAA,gBAAiD;;;ACuB1C,IAAM,sBAAsB;AA8B5B,SAAS,iBAA4C;AAC1D,QAAM,UAAW,WAAuC,mBAAmB;AAC3E,SAAQ,WAAkC;AAC5C;AAmBO,SAAS,UAAU,OAAe,MAAuC;AAC9E,QAAM,UAAU,eAAe;AAC/B,MAAI,QAAS,QAAO,QAAQ,UAAU,OAAO,IAAI;AACjD,SAAO,MAAM,OAAO,IAAI;AAC1B;;;AD/CO,SAAS,kBAAkB,OAAe;AAC/C,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAoC,IAAI;AAChE,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,IAAI;AAC/C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AAErD,QAAM,cAAU,2BAAY,YAAY;AACtC,QAAI;AACF,mBAAa,IAAI;AAEjB,YAAM,WAAW,MAAM,UAAU,+BAA+B,KAAK,EAAE;AACvE,UAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,iCAAiC;AACnE,YAAM,SAAS,MAAM,SAAS,KAAK;AACnC,cAAQ,MAAM;AACd,eAAS,IAAI;AAAA,IACf,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,eAAe,CAAC;AAAA,IAClE,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,+BAAU,MAAM;AACd,YAAQ;AAAA,EACV,GAAG,CAAC,OAAO,CAAC;AAEZ,SAAO,EAAE,MAAM,WAAW,OAAO,QAAQ;AAC3C;;;AE1CO,SAAS,iBAAgD;AAC9D,SAAO,cAAc,EAAE,YAAY;AACrC;","names":["import_react"]}
@@ -1,2 +1,55 @@
1
- export { a as AppContext, b as AppContextValue, P as PipelineStatusData, u as useAppContext, s as usePipelineStatus } from '../index-BI8f_mBw.cjs';
1
+ import { a as AppBrandingDeclaration } from '../use-app-context-DdrtEPeb.cjs';
2
+ export { e as AppContext, A as AppContextValue, x as useAppContext } from '../use-app-context-DdrtEPeb.cjs';
2
3
  import 'react';
4
+
5
+ interface PipelineStatusData {
6
+ pendingApprovals: number;
7
+ activeDeployments: number;
8
+ failedDeployments: number;
9
+ unresolvedDrifts: number;
10
+ recentDeployments: Array<{
11
+ id: string;
12
+ canvasName: string;
13
+ environment: string;
14
+ status: string;
15
+ startedAt: string;
16
+ completedAt?: string;
17
+ }>;
18
+ }
19
+ /**
20
+ * Hook to access pipeline status for the current app/customer.
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * import { usePipelineStatus } from '@veltrixsecops/app-sdk/hooks'
25
+ *
26
+ * function Dashboard() {
27
+ * const { data, isLoading } = usePipelineStatus('my-app')
28
+ * if (isLoading) return <Spinner />
29
+ * return <div>{data.activeDeployments} active deployments</div>
30
+ * }
31
+ * ```
32
+ */
33
+ declare function usePipelineStatus(appId: string): {
34
+ data: PipelineStatusData | null;
35
+ isLoading: boolean;
36
+ error: Error | null;
37
+ refresh: () => Promise<void>;
38
+ };
39
+
40
+ /**
41
+ * The app's brand identity as declared in manifest.yaml `branding`.
42
+ *
43
+ * The platform already applies it in the defined slots (the app navbar and
44
+ * the scoped CSS variables --veltrix-app-primary / --veltrix-app-accent on
45
+ * the app page container). Use this hook only when a page needs the values
46
+ * programmatically — prefer the CSS variables for styling:
47
+ *
48
+ * @example
49
+ * ```tsx
50
+ * <span style={{ color: 'var(--veltrix-app-primary)' }}>12 detections</span>
51
+ * ```
52
+ */
53
+ declare function useAppBranding(): AppBrandingDeclaration | null;
54
+
55
+ export { type PipelineStatusData, useAppBranding, usePipelineStatus };
@@ -1,2 +1,55 @@
1
- export { a as AppContext, b as AppContextValue, P as PipelineStatusData, u as useAppContext, s as usePipelineStatus } from '../index-BI8f_mBw.js';
1
+ import { a as AppBrandingDeclaration } from '../use-app-context-DdrtEPeb.js';
2
+ export { e as AppContext, A as AppContextValue, x as useAppContext } from '../use-app-context-DdrtEPeb.js';
2
3
  import 'react';
4
+
5
+ interface PipelineStatusData {
6
+ pendingApprovals: number;
7
+ activeDeployments: number;
8
+ failedDeployments: number;
9
+ unresolvedDrifts: number;
10
+ recentDeployments: Array<{
11
+ id: string;
12
+ canvasName: string;
13
+ environment: string;
14
+ status: string;
15
+ startedAt: string;
16
+ completedAt?: string;
17
+ }>;
18
+ }
19
+ /**
20
+ * Hook to access pipeline status for the current app/customer.
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * import { usePipelineStatus } from '@veltrixsecops/app-sdk/hooks'
25
+ *
26
+ * function Dashboard() {
27
+ * const { data, isLoading } = usePipelineStatus('my-app')
28
+ * if (isLoading) return <Spinner />
29
+ * return <div>{data.activeDeployments} active deployments</div>
30
+ * }
31
+ * ```
32
+ */
33
+ declare function usePipelineStatus(appId: string): {
34
+ data: PipelineStatusData | null;
35
+ isLoading: boolean;
36
+ error: Error | null;
37
+ refresh: () => Promise<void>;
38
+ };
39
+
40
+ /**
41
+ * The app's brand identity as declared in manifest.yaml `branding`.
42
+ *
43
+ * The platform already applies it in the defined slots (the app navbar and
44
+ * the scoped CSS variables --veltrix-app-primary / --veltrix-app-accent on
45
+ * the app page container). Use this hook only when a page needs the values
46
+ * programmatically — prefer the CSS variables for styling:
47
+ *
48
+ * @example
49
+ * ```tsx
50
+ * <span style={{ color: 'var(--veltrix-app-primary)' }}>12 detections</span>
51
+ * ```
52
+ */
53
+ declare function useAppBranding(): AppBrandingDeclaration | null;
54
+
55
+ export { type PipelineStatusData, useAppBranding, usePipelineStatus };
@@ -1,10 +1,13 @@
1
1
  import {
2
2
  AppContext,
3
+ useAppBranding,
3
4
  useAppContext,
4
5
  usePipelineStatus
5
- } from "../chunk-TSEIWO6T.js";
6
+ } from "../chunk-JOJTOQZQ.js";
7
+ import "../chunk-PJN3ATPH.js";
6
8
  export {
7
9
  AppContext,
10
+ useAppBranding,
8
11
  useAppContext,
9
12
  usePipelineStatus
10
13
  };