@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.
@@ -1,4 +1,4 @@
1
- import * as react from 'react';
1
+ import { Context } from 'react';
2
2
 
3
3
  type AppSource = 'BUILT_IN' | 'MARKETPLACE' | 'CUSTOM';
4
4
  type AppStatusType = 'AVAILABLE' | 'DEPRECATED' | 'REMOVED';
@@ -39,6 +39,13 @@ interface AppManifest {
39
39
  entry: string;
40
40
  pages?: AppPageDeclaration[];
41
41
  };
42
+ /**
43
+ * Vendor brand identity, applied by the platform in defined slots only —
44
+ * the app navbar (logo, accent) and scoped CSS variables. The platform,
45
+ * not the app, decides where brand color appears, so one vendor's palette
46
+ * never overwhelms the product shell.
47
+ */
48
+ branding?: AppBrandingDeclaration;
42
49
  hooks?: {
43
50
  onInstall?: string;
44
51
  onUninstall?: string;
@@ -49,6 +56,25 @@ interface AppManifest {
49
56
  events?: string[];
50
57
  settings?: AppSettingDeclaration[];
51
58
  }
59
+ /**
60
+ * App brand identity. The platform renders it in a per-app navbar above the
61
+ * app's pages and exposes the colors to app pages as scoped CSS variables
62
+ * (--veltrix-app-primary, --veltrix-app-accent).
63
+ */
64
+ interface AppBrandingDeclaration {
65
+ /** Brand accent color as #RGB or #RRGGBB hex (e.g. CrowdStrike red). */
66
+ primaryColor?: string;
67
+ /** Optional secondary color as #RGB or #RRGGBB hex. */
68
+ accentColor?: string;
69
+ /**
70
+ * Vendor logo shown in the app navbar. Repo-relative .svg (preferred) or
71
+ * .png, at most 128 KB; rendered at 28px height, so use a wide/landscape
72
+ * mark with transparent background.
73
+ */
74
+ logo?: string;
75
+ /** Optional logo variant for dark backgrounds; same constraints as logo. */
76
+ logoDark?: string;
77
+ }
52
78
  interface AppConfigurationTypeManifest {
53
79
  id: string;
54
80
  name: string;
@@ -74,13 +100,50 @@ interface AppPermissionDeclaration {
74
100
  actions: string[];
75
101
  description?: string;
76
102
  }
103
+ /**
104
+ * How the platform frames an app page.
105
+ * - `standard` — page header + padded content area (default; use for most pages)
106
+ * - `full-bleed` — content area with no padding/toolbar (custom canvases, maps)
107
+ * - `canvas` — Configuration Canvas chrome (section rail + save/validate bar)
108
+ */
109
+ type AppPageLayout = 'standard' | 'full-bleed' | 'canvas';
110
+ declare const APP_PAGE_LAYOUTS: readonly ["standard", "full-bleed", "canvas"];
111
+ /**
112
+ * Where the page surfaces in navigation.
113
+ * - `sidebar` — an entry beneath the app in the sidebar
114
+ * - `tab` — a tab within its `parent` page
115
+ * - `hidden` — routable but not linked (details/drill-down pages)
116
+ */
117
+ type AppPageNav = 'sidebar' | 'tab' | 'hidden';
118
+ declare const APP_PAGE_NAV: readonly ["sidebar", "tab", "hidden"];
119
+ /** An app-scoped permission (declared in `permissions.app`) required to see a page. */
120
+ interface AppPagePermission {
121
+ resource: string;
122
+ action: string;
123
+ }
77
124
  interface AppPageDeclaration {
125
+ /** Route beneath the app, e.g. `/indexes` → `/apps/<app-id>/indexes` */
78
126
  path: string;
127
+ /** Exported component name from the app's client entry */
79
128
  component: string;
80
129
  label: string;
130
+ description?: string;
131
+ /** Icon name from the platform icon set; falls back to the app icon */
81
132
  icon?: string;
133
+ /** @deprecated use `nav: 'sidebar' | 'hidden'` — kept for backward compatibility */
82
134
  sidebar?: boolean;
135
+ /** Navigation placement. Defaults to `sidebar` when `sidebar: true`, else `hidden`. */
136
+ nav?: AppPageNav;
137
+ /** Parent page `path` — required for `nav: 'tab'`, optional nesting for sidebar entries */
83
138
  parent?: string;
139
+ /** Optional sidebar section label, for apps with many pages */
140
+ group?: string;
141
+ /** Deterministic ordering within its group/parent (ascending; ties break on label) */
142
+ order?: number;
143
+ /** Layout preset the platform renders around the page body */
144
+ layout?: AppPageLayout;
145
+ /** Hide the page (and its nav entry) unless the user holds this app permission */
146
+ requiresPermission?: AppPagePermission;
84
147
  }
85
148
  interface AppSettingDeclaration {
86
149
  key: string;
@@ -231,8 +294,10 @@ interface AppContextValue {
231
294
  getCredentials: () => Promise<Credential[]>;
232
295
  getTags: () => Promise<Tag[]>;
233
296
  settings: Record<string, unknown>;
297
+ /** The app's manifest branding, resolved by the platform (null when unset). */
298
+ branding?: AppBrandingDeclaration | null;
234
299
  }
235
- declare const AppContext: react.Context<AppContextValue | null>;
300
+ declare const AppContext: Context<AppContextValue | null>;
236
301
  /**
237
302
  * Access the app context in any app component.
238
303
  *
@@ -248,39 +313,4 @@ declare const AppContext: react.Context<AppContextValue | null>;
248
313
  */
249
314
  declare function useAppContext(): AppContextValue;
250
315
 
251
- interface PipelineStatusData {
252
- pendingApprovals: number;
253
- activeDeployments: number;
254
- failedDeployments: number;
255
- unresolvedDrifts: number;
256
- recentDeployments: Array<{
257
- id: string;
258
- canvasName: string;
259
- environment: string;
260
- status: string;
261
- startedAt: string;
262
- completedAt?: string;
263
- }>;
264
- }
265
- /**
266
- * Hook to access pipeline status for the current app/customer.
267
- *
268
- * @example
269
- * ```tsx
270
- * import { usePipelineStatus } from '@veltrixsecops/app-sdk/hooks'
271
- *
272
- * function Dashboard() {
273
- * const { data, isLoading } = usePipelineStatus('my-app')
274
- * if (isLoading) return <Spinner />
275
- * return <div>{data.activeDeployments} active deployments</div>
276
- * }
277
- * ```
278
- */
279
- declare function usePipelineStatus(appId: string): {
280
- data: PipelineStatusData | null;
281
- isLoading: boolean;
282
- error: Error | null;
283
- refresh: () => Promise<void>;
284
- };
285
-
286
- export { type AppConfigurationTypeManifest as A, type Component as C, type PipelineStatusData as P, type Tag as T, type User as U, AppContext as a, type AppContextValue as b, type AppDetail as c, type AppHookContext as d, type AppInstallationDetail as e, type AppInstallationStatus as f, type AppListItem as g, type AppManifest as h, type AppPageDeclaration as i, type AppPermissionDeclaration as j, type AppRouteContext as k, type AppSettingDeclaration as l, type AppSource as m, type AppStatusType as n, type Connectivity as o, type Credential as p, type Customer as q, type PlatformDatabaseClient as r, usePipelineStatus as s, useAppContext as u };
316
+ export { type AppContextValue as A, type Component as C, type PlatformDatabaseClient as P, type Tag as T, type User as U, type AppBrandingDeclaration as a, APP_PAGE_LAYOUTS as b, APP_PAGE_NAV as c, type AppConfigurationTypeManifest as d, AppContext as e, type AppDetail as f, type AppHookContext as g, type AppInstallationDetail as h, type AppInstallationStatus as i, type AppListItem as j, type AppManifest as k, type AppPageDeclaration as l, type AppPageLayout as m, type AppPageNav as n, type AppPagePermission as o, type AppPermissionDeclaration as p, type AppRouteContext as q, type AppSettingDeclaration as r, type AppSource as s, type AppStatusType as t, type Connectivity as u, type Credential as v, type Customer as w, useAppContext as x };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veltrixsecops/app-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.3.0",
4
4
  "description": "Official SDK for building Veltrix Security-as-Code apps — typed pipeline handler contracts, lifecycle hook types, manifest types, and React hooks.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
@@ -38,6 +38,16 @@
38
38
  "default": "./dist/hooks/index.cjs"
39
39
  }
40
40
  },
41
+ "./client": {
42
+ "import": {
43
+ "types": "./dist/client/index.d.ts",
44
+ "default": "./dist/client/index.js"
45
+ },
46
+ "require": {
47
+ "types": "./dist/client/index.d.cts",
48
+ "default": "./dist/client/index.cjs"
49
+ }
50
+ },
41
51
  "./package.json": "./package.json"
42
52
  },
43
53
  "files": [
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/use-app-context.ts","../src/hooks/use-pipeline-status.ts"],"sourcesContent":["// ========================================================================\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":";AAKA,SAAS,eAAe,kBAAkB;AAkBnC,IAAM,aAAa,cAAsC,IAAI;AAe7D,SAAS,gBAAiC;AAC/C,QAAM,MAAM,WAAW,UAAU;AACjC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO;AACT;;;AC5CA,SAAS,UAAU,WAAW,mBAAmB;AA+B1C,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;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,YAAU,MAAM;AACd,YAAQ;AAAA,EACV,GAAG,CAAC,OAAO,CAAC;AAEZ,SAAO,EAAE,MAAM,WAAW,OAAO,QAAQ;AAC3C;","names":[]}