@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/dist/index.cjs CHANGED
@@ -20,12 +20,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ APP_LAYOUT: () => APP_LAYOUT,
24
+ APP_PAGE_LAYOUTS: () => APP_PAGE_LAYOUTS,
25
+ APP_PAGE_NAV: () => APP_PAGE_NAV,
23
26
  AppContext: () => AppContext,
27
+ HANDLER_NAMES: () => HANDLER_NAMES,
28
+ conventionalPaths: () => conventionalPaths,
24
29
  defineDeployer: () => defineDeployer,
25
30
  defineDriftDetector: () => defineDriftDetector,
26
31
  defineHealthChecker: () => defineHealthChecker,
27
32
  defineRollbackHandler: () => defineRollbackHandler,
28
33
  defineValidator: () => defineValidator,
34
+ useAppBranding: () => useAppBranding,
29
35
  useAppContext: () => useAppContext,
30
36
  usePipelineStatus: () => usePipelineStatus
31
37
  });
@@ -58,7 +64,8 @@ function defineDriftDetector(handler) {
58
64
 
59
65
  // src/hooks/use-app-context.ts
60
66
  var import_react = require("react");
61
- var AppContext = (0, import_react.createContext)(null);
67
+ var hostContext = globalThis.__VELTRIX_APP_RUNTIME__?.AppContext;
68
+ var AppContext = hostContext ?? (0, import_react.createContext)(null);
62
69
  function useAppContext() {
63
70
  const ctx = (0, import_react.useContext)(AppContext);
64
71
  if (!ctx) {
@@ -69,6 +76,20 @@ function useAppContext() {
69
76
 
70
77
  // src/hooks/use-pipeline-status.ts
71
78
  var import_react2 = require("react");
79
+
80
+ // src/client/index.ts
81
+ var HOST_RUNTIME_GLOBAL = "__VELTRIX_APP_RUNTIME__";
82
+ function getHostRuntime() {
83
+ const runtime = globalThis[HOST_RUNTIME_GLOBAL];
84
+ return runtime ?? null;
85
+ }
86
+ function authFetch(input, init) {
87
+ const runtime = getHostRuntime();
88
+ if (runtime) return runtime.authFetch(input, init);
89
+ return fetch(input, init);
90
+ }
91
+
92
+ // src/hooks/use-pipeline-status.ts
72
93
  function usePipelineStatus(appId) {
73
94
  const [data, setData] = (0, import_react2.useState)(null);
74
95
  const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
@@ -76,7 +97,7 @@ function usePipelineStatus(appId) {
76
97
  const refresh = (0, import_react2.useCallback)(async () => {
77
98
  try {
78
99
  setIsLoading(true);
79
- const response = await fetch(`/api/pipeline/summary?appId=${appId}`);
100
+ const response = await authFetch(`/api/pipeline/summary?appId=${appId}`);
80
101
  if (!response.ok) throw new Error(`Failed to fetch pipeline status`);
81
102
  const result = await response.json();
82
103
  setData(result);
@@ -92,14 +113,79 @@ function usePipelineStatus(appId) {
92
113
  }, [refresh]);
93
114
  return { data, isLoading, error, refresh };
94
115
  }
116
+
117
+ // src/hooks/use-app-branding.ts
118
+ function useAppBranding() {
119
+ return useAppContext().branding ?? null;
120
+ }
121
+
122
+ // src/types/manifest.ts
123
+ var APP_PAGE_LAYOUTS = ["standard", "full-bleed", "canvas"];
124
+ var APP_PAGE_NAV = ["sidebar", "tab", "hidden"];
125
+
126
+ // src/structure.ts
127
+ var APP_LAYOUT = {
128
+ /** The app contract. Always at the app root. */
129
+ manifest: "manifest.yaml",
130
+ /**
131
+ * The unit of extension: config-types/<configTypeId>/ colocates everything
132
+ * for one configuration type — canvas.yaml, defaults.yaml, the six pipeline
133
+ * handlers (extensionless in the manifest), and __tests__/.
134
+ */
135
+ configTypesDir: "config-types",
136
+ /** Canvas form schema filename inside a config-type folder. */
137
+ canvasFile: "canvas.yaml",
138
+ /** Default field values filename inside a config-type folder. */
139
+ defaultsFile: "defaults.yaml",
140
+ /** Lifecycle hooks (camelCase): hooks/onInstall, hooks/onUninstall, ... */
141
+ hooksDir: "hooks",
142
+ /** Shared app code used by multiple handlers (API clients, parsers). */
143
+ libDir: "lib",
144
+ /** SQL migrations (requires manifest `database.tablePrefix`). */
145
+ migrationsDir: "migrations",
146
+ /** Fastify route module receiving (fastify, AppRouteContext). */
147
+ serverEntry: "server/index",
148
+ /** Client entry registering pages/sidebar items (optional). */
149
+ clientEntry: "client/index",
150
+ /** Icons and logos (optional). */
151
+ assetsDir: "assets",
152
+ /** Tests live next to the code they cover: handlers/<id>/__tests__/ */
153
+ testsDirName: "__tests__"
154
+ };
155
+ var HANDLER_NAMES = [
156
+ "validate",
157
+ "deploy",
158
+ "rollback",
159
+ "healthCheck",
160
+ "driftDetect",
161
+ "getStatus"
162
+ ];
163
+ function conventionalPaths(configTypeId) {
164
+ const base = `${APP_LAYOUT.configTypesDir}/${configTypeId}`;
165
+ const handlers = {};
166
+ for (const name of HANDLER_NAMES) {
167
+ handlers[name] = `${base}/${name}`;
168
+ }
169
+ return {
170
+ canvasTemplate: `${base}/${APP_LAYOUT.canvasFile}`,
171
+ defaultConfig: `${base}/${APP_LAYOUT.defaultsFile}`,
172
+ handlers
173
+ };
174
+ }
95
175
  // Annotate the CommonJS export names for ESM import in node:
96
176
  0 && (module.exports = {
177
+ APP_LAYOUT,
178
+ APP_PAGE_LAYOUTS,
179
+ APP_PAGE_NAV,
97
180
  AppContext,
181
+ HANDLER_NAMES,
182
+ conventionalPaths,
98
183
  defineDeployer,
99
184
  defineDriftDetector,
100
185
  defineHealthChecker,
101
186
  defineRollbackHandler,
102
187
  defineValidator,
188
+ useAppBranding,
103
189
  useAppContext,
104
190
  usePipelineStatus
105
191
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../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","../src/hooks/use-app-context.ts","../src/hooks/use-pipeline-status.ts"],"sourcesContent":["// ========================================================================\n// @veltrixsecops/app-sdk\n//\n// The official SDK for building Veltrix Security-as-Code apps.\n// Import pipeline helpers, hooks, and types to build your app.\n//\n// Usage:\n// import { defineValidator, defineDeployer } from '@veltrixsecops/app-sdk/pipeline'\n// import { useAppContext, usePipelineStatus } from '@veltrixsecops/app-sdk/hooks'\n// import type { PipelineContext, DeployContext } from '@veltrixsecops/app-sdk'\n// ========================================================================\n\n// Pipeline handler helpers\nexport {\n defineValidator,\n defineDeployer,\n defineRollbackHandler,\n defineHealthChecker,\n defineDriftDetector,\n} from './pipeline'\n\n// React hooks\nexport {\n useAppContext,\n AppContext,\n usePipelineStatus,\n} from './hooks'\n\n// Pipeline types\nexport type {\n PipelineContext,\n DeployContext,\n RollbackContext,\n HealthCheckContext,\n DriftContext,\n ValidationResult,\n ValidationError,\n ValidationWarning,\n DeployResult,\n RollbackResult,\n HealthCheckResult,\n HealthCheck,\n DriftResult,\n DriftDiff,\n ConfigStatus,\n ComponentConfigStatus,\n CanvasSnapshot,\n CanvasSectionSnapshot,\n DeploymentStrategy,\n EnvironmentRef,\n UserRef,\n ComponentRef,\n CredentialRef,\n ConnectivityRef,\n ConnectivityProviderRef,\n PlatformDataApi,\n DeploymentSummary,\n ValidateHandler,\n DeployHandler,\n RollbackHandler,\n HealthCheckHandler,\n DriftDetectHandler,\n GetStatusHandler,\n} from './types/pipeline'\n\n// Platform types\nexport type {\n Component,\n Credential,\n Connectivity,\n Tag,\n User,\n Customer,\n PlatformDatabaseClient,\n AppHookContext,\n AppRouteContext,\n} from './types/platform'\n\n// Manifest types\nexport type {\n AppManifest,\n AppConfigurationTypeManifest,\n AppPermissionDeclaration,\n AppPageDeclaration,\n AppSettingDeclaration,\n AppSource,\n AppStatusType,\n AppInstallationStatus,\n AppListItem,\n AppDetail,\n AppInstallationDetail,\n} from './types/manifest'\n\n// Hooks types\nexport type { AppContextValue, PipelineStatusData } from './hooks'\n","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","// ========================================================================\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;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACmBO,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;;;ACJA,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/index.ts","../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","../src/hooks/use-app-context.ts","../src/hooks/use-pipeline-status.ts","../src/client/index.ts","../src/hooks/use-app-branding.ts","../src/types/manifest.ts","../src/structure.ts"],"sourcesContent":["// ========================================================================\n// @veltrixsecops/app-sdk\n//\n// The official SDK for building Veltrix Security-as-Code apps.\n// Import pipeline helpers, hooks, and types to build your app.\n//\n// Usage:\n// import { defineValidator, defineDeployer } from '@veltrixsecops/app-sdk/pipeline'\n// import { useAppContext, usePipelineStatus } from '@veltrixsecops/app-sdk/hooks'\n// import type { PipelineContext, DeployContext } from '@veltrixsecops/app-sdk'\n// ========================================================================\n\n// Pipeline handler helpers\nexport {\n defineValidator,\n defineDeployer,\n defineRollbackHandler,\n defineHealthChecker,\n defineDriftDetector,\n} from './pipeline'\n\n// React hooks\nexport {\n useAppContext,\n AppContext,\n usePipelineStatus,\n useAppBranding,\n} from './hooks'\n\n// Pipeline types\nexport type {\n PipelineContext,\n DeployContext,\n RollbackContext,\n HealthCheckContext,\n DriftContext,\n ValidationResult,\n ValidationError,\n ValidationWarning,\n DeployResult,\n RollbackResult,\n HealthCheckResult,\n HealthCheck,\n DriftResult,\n DriftDiff,\n ConfigStatus,\n ComponentConfigStatus,\n CanvasSnapshot,\n CanvasSectionSnapshot,\n DeploymentStrategy,\n EnvironmentRef,\n UserRef,\n ComponentRef,\n CredentialRef,\n ConnectivityRef,\n ConnectivityProviderRef,\n PlatformDataApi,\n DeploymentSummary,\n ValidateHandler,\n DeployHandler,\n RollbackHandler,\n HealthCheckHandler,\n DriftDetectHandler,\n GetStatusHandler,\n} from './types/pipeline'\n\n// Platform types\nexport type {\n Component,\n Credential,\n Connectivity,\n Tag,\n User,\n Customer,\n PlatformDatabaseClient,\n AppHookContext,\n AppRouteContext,\n} from './types/platform'\n\n// App UI & navigation contract\nexport { APP_PAGE_LAYOUTS, APP_PAGE_NAV } from './types/manifest'\nexport type { AppPageLayout, AppPageNav, AppPagePermission } from './types/manifest'\n\n// Manifest types\nexport type {\n AppManifest,\n AppBrandingDeclaration,\n AppConfigurationTypeManifest,\n AppPermissionDeclaration,\n AppPageDeclaration,\n AppSettingDeclaration,\n AppSource,\n AppStatusType,\n AppInstallationStatus,\n AppListItem,\n AppDetail,\n AppInstallationDetail,\n} from './types/manifest'\n\n// Canonical app layout\nexport { APP_LAYOUT, HANDLER_NAMES, conventionalPaths } from './structure'\nexport type { HandlerName } from './structure'\n\n// Hooks types\nexport type { AppContextValue, PipelineStatusData } from './hooks'\n","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","// ========================================================================\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","// ========================================================================\n// App manifest types\n//\n// Self-contained copy of the platform's manifest contract so the SDK can\n// be published and consumed outside the platform monorepo. The platform\n// keeps its own copy in shared/types/app.ts — changes to the manifest\n// contract must be applied to both files.\n// ========================================================================\n\nexport type AppSource = 'BUILT_IN' | 'MARKETPLACE' | 'CUSTOM'\nexport type AppStatusType = 'AVAILABLE' | 'DEPRECATED' | 'REMOVED'\nexport type AppInstallationStatus =\n | 'INSTALLING'\n | 'INSTALLED'\n | 'ENABLED'\n | 'DISABLED'\n | 'FAILED'\n | 'UNINSTALLING'\n\n// --- Manifest Types (parsed from manifest.yaml) ---\n\nexport interface AppManifest {\n id: string\n name: string\n version: string\n vendor: string\n description: string\n category: string\n license?: string\n homepage?: string\n icon?: string\n logo?: string\n\n platform: {\n minVersion: string\n }\n\n permissions: {\n platform: string[] // Platform permissions the app needs\n app: AppPermissionDeclaration[] // Permissions the app exposes\n }\n\n database?: {\n migrations: string\n tablePrefix: string\n }\n\n pipeline: {\n configurationTypes: AppConfigurationTypeManifest[]\n pipelineEvents?: string[]\n }\n\n server: {\n entry: string\n routes?: {\n prefix: string\n }\n }\n\n client?: {\n entry: string\n pages?: AppPageDeclaration[]\n }\n\n /**\n * Vendor brand identity, applied by the platform in defined slots only —\n * the app navbar (logo, accent) and scoped CSS variables. The platform,\n * not the app, decides where brand color appears, so one vendor's palette\n * never overwhelms the product shell.\n */\n branding?: AppBrandingDeclaration\n\n hooks?: {\n onInstall?: string\n onUninstall?: string\n onEnable?: string\n onDisable?: string\n onUpgrade?: string\n }\n\n events?: string[] // Platform events this app subscribes to\n\n settings?: AppSettingDeclaration[]\n}\n\n/**\n * App brand identity. The platform renders it in a per-app navbar above the\n * app's pages and exposes the colors to app pages as scoped CSS variables\n * (--veltrix-app-primary, --veltrix-app-accent).\n */\nexport interface AppBrandingDeclaration {\n /** Brand accent color as #RGB or #RRGGBB hex (e.g. CrowdStrike red). */\n primaryColor?: string\n /** Optional secondary color as #RGB or #RRGGBB hex. */\n accentColor?: string\n /**\n * Vendor logo shown in the app navbar. Repo-relative .svg (preferred) or\n * .png, at most 128 KB; rendered at 28px height, so use a wide/landscape\n * mark with transparent background.\n */\n logo?: string\n /** Optional logo variant for dark backgrounds; same constraints as logo. */\n logoDark?: string\n}\n\nexport interface AppConfigurationTypeManifest {\n id: string\n name: string\n description?: string\n canvasTemplate: string // Path to canvas template YAML\n defaultConfig?: string // Path to default config YAML\n\n handlers: {\n validate: string\n deploy: string\n rollback: string\n healthCheck: string\n driftDetect?: string | null\n getStatus: string\n }\n\n targets: {\n componentTypes: string[]\n requiresCredential: boolean\n requiresConnectivity: boolean\n }\n}\n\nexport interface AppPermissionDeclaration {\n resource: string\n actions: string[]\n description?: string\n}\n\n// --- App UI & navigation contract ---\n//\n// The platform owns the chrome: breadcrumb, app header, navigation, permission\n// gating, error boundary and loading states are rendered identically for every\n// app. Apps own the page body and compose it from @veltrixsecops/ui.\n// Predictable shell, flexible body.\n\n/**\n * How the platform frames an app page.\n * - `standard` — page header + padded content area (default; use for most pages)\n * - `full-bleed` — content area with no padding/toolbar (custom canvases, maps)\n * - `canvas` — Configuration Canvas chrome (section rail + save/validate bar)\n */\nexport type AppPageLayout = 'standard' | 'full-bleed' | 'canvas'\nexport const APP_PAGE_LAYOUTS = ['standard', 'full-bleed', 'canvas'] as const\n\n/**\n * Where the page surfaces in navigation.\n * - `sidebar` — an entry beneath the app in the sidebar\n * - `tab` — a tab within its `parent` page\n * - `hidden` — routable but not linked (details/drill-down pages)\n */\nexport type AppPageNav = 'sidebar' | 'tab' | 'hidden'\nexport const APP_PAGE_NAV = ['sidebar', 'tab', 'hidden'] as const\n\n/** An app-scoped permission (declared in `permissions.app`) required to see a page. */\nexport interface AppPagePermission {\n resource: string\n action: string\n}\n\nexport interface AppPageDeclaration {\n /** Route beneath the app, e.g. `/indexes` → `/apps/<app-id>/indexes` */\n path: string\n /** Exported component name from the app's client entry */\n component: string\n label: string\n description?: string\n /** Icon name from the platform icon set; falls back to the app icon */\n icon?: string\n /** @deprecated use `nav: 'sidebar' | 'hidden'` — kept for backward compatibility */\n sidebar?: boolean\n /** Navigation placement. Defaults to `sidebar` when `sidebar: true`, else `hidden`. */\n nav?: AppPageNav\n /** Parent page `path` — required for `nav: 'tab'`, optional nesting for sidebar entries */\n parent?: string\n /** Optional sidebar section label, for apps with many pages */\n group?: string\n /** Deterministic ordering within its group/parent (ascending; ties break on label) */\n order?: number\n /** Layout preset the platform renders around the page body */\n layout?: AppPageLayout\n /** Hide the page (and its nav entry) unless the user holds this app permission */\n requiresPermission?: AppPagePermission\n}\n\nexport interface AppSettingDeclaration {\n key: string\n type: 'string' | 'number' | 'boolean' | 'select'\n label: string\n description?: string\n default?: string | number | boolean\n required?: boolean\n options?: Array<{ label: string; value: string }>\n}\n\n// --- API Response Types ---\n\nexport interface AppListItem {\n id: string\n appId: string\n name: string\n version: string\n vendor: string\n description: string\n category: string\n icon?: string\n logo?: string\n source: AppSource\n isDefault: boolean\n status: AppStatusType\n installed?: boolean\n enabled?: boolean\n}\n\nexport interface AppDetail extends AppListItem {\n license?: string\n homepage?: string\n repository?: string\n configurationTypes: Array<{\n id: string\n name: string\n description?: string\n componentTypes: string[]\n }>\n permissions: AppPermissionDeclaration[]\n settings: AppSettingDeclaration[]\n}\n\nexport interface AppInstallationDetail {\n id: string\n appId: string\n customerId: string\n version: string\n enabled: boolean\n installedBy: string\n installedAt: string\n settings: Record<string, unknown>\n status: AppInstallationStatus\n app: AppListItem\n}\n","// ========================================================================\n// Canonical app layout\n//\n// Every Veltrix app follows one predictable folder structure so apps are\n// easy to set up, review, and load. The `veltrix` CLI scaffolds it,\n// `veltrix validate` (and repo CI) warn on deviations, and the platform's\n// app engine resolves manifest references against it.\n// ========================================================================\n\n/** Canonical locations inside an app directory. */\nexport const APP_LAYOUT = {\n /** The app contract. Always at the app root. */\n manifest: 'manifest.yaml',\n /**\n * The unit of extension: config-types/<configTypeId>/ colocates everything\n * for one configuration type — canvas.yaml, defaults.yaml, the six pipeline\n * handlers (extensionless in the manifest), and __tests__/.\n */\n configTypesDir: 'config-types',\n /** Canvas form schema filename inside a config-type folder. */\n canvasFile: 'canvas.yaml',\n /** Default field values filename inside a config-type folder. */\n defaultsFile: 'defaults.yaml',\n /** Lifecycle hooks (camelCase): hooks/onInstall, hooks/onUninstall, ... */\n hooksDir: 'hooks',\n /** Shared app code used by multiple handlers (API clients, parsers). */\n libDir: 'lib',\n /** SQL migrations (requires manifest `database.tablePrefix`). */\n migrationsDir: 'migrations',\n /** Fastify route module receiving (fastify, AppRouteContext). */\n serverEntry: 'server/index',\n /** Client entry registering pages/sidebar items (optional). */\n clientEntry: 'client/index',\n /** Icons and logos (optional). */\n assetsDir: 'assets',\n /** Tests live next to the code they cover: handlers/<id>/__tests__/ */\n testsDirName: '__tests__',\n} as const\n\n/** The six pipeline handler names, in lifecycle order. */\nexport const HANDLER_NAMES = [\n 'validate',\n 'deploy',\n 'rollback',\n 'healthCheck',\n 'driftDetect',\n 'getStatus',\n] as const\n\nexport type HandlerName = (typeof HANDLER_NAMES)[number]\n\n/**\n * Conventional manifest paths for one configuration type — handy when\n * generating or checking a manifest programmatically.\n *\n * @example\n * conventionalPaths('indexes').handlers.deploy // 'config-types/indexes/deploy'\n */\nexport function conventionalPaths(configTypeId: string): {\n canvasTemplate: string\n defaultConfig: string\n handlers: Record<HandlerName, string>\n} {\n const base = `${APP_LAYOUT.configTypesDir}/${configTypeId}`\n const handlers = {} as Record<HandlerName, string>\n for (const name of HANDLER_NAMES) {\n handlers[name] = `${base}/${name}`\n }\n return {\n canvasTemplate: `${base}/${APP_LAYOUT.canvasFile}`,\n defaultConfig: `${base}/${APP_LAYOUT.defaultsFile}`,\n handlers,\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACmBO,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;;;ACJA,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;;;ACkIO,IAAM,mBAAmB,CAAC,YAAY,cAAc,QAAQ;AAS5D,IAAM,eAAe,CAAC,WAAW,OAAO,QAAQ;;;ACnJhD,IAAM,aAAa;AAAA;AAAA,EAExB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMV,gBAAgB;AAAA;AAAA,EAEhB,YAAY;AAAA;AAAA,EAEZ,cAAc;AAAA;AAAA,EAEd,UAAU;AAAA;AAAA,EAEV,QAAQ;AAAA;AAAA,EAER,eAAe;AAAA;AAAA,EAEf,aAAa;AAAA;AAAA,EAEb,aAAa;AAAA;AAAA,EAEb,WAAW;AAAA;AAAA,EAEX,cAAc;AAChB;AAGO,IAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAWO,SAAS,kBAAkB,cAIhC;AACA,QAAM,OAAO,GAAG,WAAW,cAAc,IAAI,YAAY;AACzD,QAAM,WAAW,CAAC;AAClB,aAAW,QAAQ,eAAe;AAChC,aAAS,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI;AAAA,EAClC;AACA,SAAO;AAAA,IACL,gBAAgB,GAAG,IAAI,IAAI,WAAW,UAAU;AAAA,IAChD,eAAe,GAAG,IAAI,IAAI,WAAW,YAAY;AAAA,IACjD;AAAA,EACF;AACF;","names":["import_react"]}
package/dist/index.d.cts CHANGED
@@ -1,3 +1,51 @@
1
1
  export { C as CanvasSectionSnapshot, a as CanvasSnapshot, b as ComponentConfigStatus, c as ComponentRef, d as ConfigStatus, e as ConnectivityProviderRef, f as ConnectivityRef, g as CredentialRef, D as DeployContext, h as DeployHandler, i as DeployResult, j as DeploymentStrategy, k as DeploymentSummary, l as DriftContext, m as DriftDetectHandler, n as DriftDiff, o as DriftResult, E as EnvironmentRef, G as GetStatusHandler, H as HealthCheck, p as HealthCheckContext, q as HealthCheckHandler, r as HealthCheckResult, P as PipelineContext, s as PlatformDataApi, R as RollbackContext, t as RollbackHandler, u as RollbackResult, U as UserRef, V as ValidateHandler, v as ValidationError, w as ValidationResult, x as ValidationWarning, y as defineDeployer, z as defineDriftDetector, A as defineHealthChecker, B as defineRollbackHandler, F as defineValidator } from './index-CKeIf4Jx.cjs';
2
- export { A as AppConfigurationTypeManifest, a as AppContext, b as AppContextValue, c as AppDetail, d as AppHookContext, e as AppInstallationDetail, f as AppInstallationStatus, g as AppListItem, h as AppManifest, i as AppPageDeclaration, j as AppPermissionDeclaration, k as AppRouteContext, l as AppSettingDeclaration, m as AppSource, n as AppStatusType, C as Component, o as Connectivity, p as Credential, q as Customer, P as PipelineStatusData, r as PlatformDatabaseClient, T as Tag, U as User, u as useAppContext, s as usePipelineStatus } from './index-BI8f_mBw.cjs';
2
+ export { b as APP_PAGE_LAYOUTS, c as APP_PAGE_NAV, a as AppBrandingDeclaration, d as AppConfigurationTypeManifest, e as AppContext, A as AppContextValue, f as AppDetail, g as AppHookContext, h as AppInstallationDetail, i as AppInstallationStatus, j as AppListItem, k as AppManifest, l as AppPageDeclaration, m as AppPageLayout, n as AppPageNav, o as AppPagePermission, p as AppPermissionDeclaration, q as AppRouteContext, r as AppSettingDeclaration, s as AppSource, t as AppStatusType, C as Component, u as Connectivity, v as Credential, w as Customer, P as PlatformDatabaseClient, T as Tag, U as User, x as useAppContext } from './use-app-context-DdrtEPeb.cjs';
3
+ export { PipelineStatusData, useAppBranding, usePipelineStatus } from './hooks/index.cjs';
3
4
  import 'react';
5
+
6
+ /** Canonical locations inside an app directory. */
7
+ declare const APP_LAYOUT: {
8
+ /** The app contract. Always at the app root. */
9
+ readonly manifest: "manifest.yaml";
10
+ /**
11
+ * The unit of extension: config-types/<configTypeId>/ colocates everything
12
+ * for one configuration type — canvas.yaml, defaults.yaml, the six pipeline
13
+ * handlers (extensionless in the manifest), and __tests__/.
14
+ */
15
+ readonly configTypesDir: "config-types";
16
+ /** Canvas form schema filename inside a config-type folder. */
17
+ readonly canvasFile: "canvas.yaml";
18
+ /** Default field values filename inside a config-type folder. */
19
+ readonly defaultsFile: "defaults.yaml";
20
+ /** Lifecycle hooks (camelCase): hooks/onInstall, hooks/onUninstall, ... */
21
+ readonly hooksDir: "hooks";
22
+ /** Shared app code used by multiple handlers (API clients, parsers). */
23
+ readonly libDir: "lib";
24
+ /** SQL migrations (requires manifest `database.tablePrefix`). */
25
+ readonly migrationsDir: "migrations";
26
+ /** Fastify route module receiving (fastify, AppRouteContext). */
27
+ readonly serverEntry: "server/index";
28
+ /** Client entry registering pages/sidebar items (optional). */
29
+ readonly clientEntry: "client/index";
30
+ /** Icons and logos (optional). */
31
+ readonly assetsDir: "assets";
32
+ /** Tests live next to the code they cover: handlers/<id>/__tests__/ */
33
+ readonly testsDirName: "__tests__";
34
+ };
35
+ /** The six pipeline handler names, in lifecycle order. */
36
+ declare const HANDLER_NAMES: readonly ["validate", "deploy", "rollback", "healthCheck", "driftDetect", "getStatus"];
37
+ type HandlerName = (typeof HANDLER_NAMES)[number];
38
+ /**
39
+ * Conventional manifest paths for one configuration type — handy when
40
+ * generating or checking a manifest programmatically.
41
+ *
42
+ * @example
43
+ * conventionalPaths('indexes').handlers.deploy // 'config-types/indexes/deploy'
44
+ */
45
+ declare function conventionalPaths(configTypeId: string): {
46
+ canvasTemplate: string;
47
+ defaultConfig: string;
48
+ handlers: Record<HandlerName, string>;
49
+ };
50
+
51
+ export { APP_LAYOUT, HANDLER_NAMES, type HandlerName, conventionalPaths };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,51 @@
1
1
  export { C as CanvasSectionSnapshot, a as CanvasSnapshot, b as ComponentConfigStatus, c as ComponentRef, d as ConfigStatus, e as ConnectivityProviderRef, f as ConnectivityRef, g as CredentialRef, D as DeployContext, h as DeployHandler, i as DeployResult, j as DeploymentStrategy, k as DeploymentSummary, l as DriftContext, m as DriftDetectHandler, n as DriftDiff, o as DriftResult, E as EnvironmentRef, G as GetStatusHandler, H as HealthCheck, p as HealthCheckContext, q as HealthCheckHandler, r as HealthCheckResult, P as PipelineContext, s as PlatformDataApi, R as RollbackContext, t as RollbackHandler, u as RollbackResult, U as UserRef, V as ValidateHandler, v as ValidationError, w as ValidationResult, x as ValidationWarning, y as defineDeployer, z as defineDriftDetector, A as defineHealthChecker, B as defineRollbackHandler, F as defineValidator } from './index-CKeIf4Jx.js';
2
- export { A as AppConfigurationTypeManifest, a as AppContext, b as AppContextValue, c as AppDetail, d as AppHookContext, e as AppInstallationDetail, f as AppInstallationStatus, g as AppListItem, h as AppManifest, i as AppPageDeclaration, j as AppPermissionDeclaration, k as AppRouteContext, l as AppSettingDeclaration, m as AppSource, n as AppStatusType, C as Component, o as Connectivity, p as Credential, q as Customer, P as PipelineStatusData, r as PlatformDatabaseClient, T as Tag, U as User, u as useAppContext, s as usePipelineStatus } from './index-BI8f_mBw.js';
2
+ export { b as APP_PAGE_LAYOUTS, c as APP_PAGE_NAV, a as AppBrandingDeclaration, d as AppConfigurationTypeManifest, e as AppContext, A as AppContextValue, f as AppDetail, g as AppHookContext, h as AppInstallationDetail, i as AppInstallationStatus, j as AppListItem, k as AppManifest, l as AppPageDeclaration, m as AppPageLayout, n as AppPageNav, o as AppPagePermission, p as AppPermissionDeclaration, q as AppRouteContext, r as AppSettingDeclaration, s as AppSource, t as AppStatusType, C as Component, u as Connectivity, v as Credential, w as Customer, P as PlatformDatabaseClient, T as Tag, U as User, x as useAppContext } from './use-app-context-DdrtEPeb.js';
3
+ export { PipelineStatusData, useAppBranding, usePipelineStatus } from './hooks/index.js';
3
4
  import 'react';
5
+
6
+ /** Canonical locations inside an app directory. */
7
+ declare const APP_LAYOUT: {
8
+ /** The app contract. Always at the app root. */
9
+ readonly manifest: "manifest.yaml";
10
+ /**
11
+ * The unit of extension: config-types/<configTypeId>/ colocates everything
12
+ * for one configuration type — canvas.yaml, defaults.yaml, the six pipeline
13
+ * handlers (extensionless in the manifest), and __tests__/.
14
+ */
15
+ readonly configTypesDir: "config-types";
16
+ /** Canvas form schema filename inside a config-type folder. */
17
+ readonly canvasFile: "canvas.yaml";
18
+ /** Default field values filename inside a config-type folder. */
19
+ readonly defaultsFile: "defaults.yaml";
20
+ /** Lifecycle hooks (camelCase): hooks/onInstall, hooks/onUninstall, ... */
21
+ readonly hooksDir: "hooks";
22
+ /** Shared app code used by multiple handlers (API clients, parsers). */
23
+ readonly libDir: "lib";
24
+ /** SQL migrations (requires manifest `database.tablePrefix`). */
25
+ readonly migrationsDir: "migrations";
26
+ /** Fastify route module receiving (fastify, AppRouteContext). */
27
+ readonly serverEntry: "server/index";
28
+ /** Client entry registering pages/sidebar items (optional). */
29
+ readonly clientEntry: "client/index";
30
+ /** Icons and logos (optional). */
31
+ readonly assetsDir: "assets";
32
+ /** Tests live next to the code they cover: handlers/<id>/__tests__/ */
33
+ readonly testsDirName: "__tests__";
34
+ };
35
+ /** The six pipeline handler names, in lifecycle order. */
36
+ declare const HANDLER_NAMES: readonly ["validate", "deploy", "rollback", "healthCheck", "driftDetect", "getStatus"];
37
+ type HandlerName = (typeof HANDLER_NAMES)[number];
38
+ /**
39
+ * Conventional manifest paths for one configuration type — handy when
40
+ * generating or checking a manifest programmatically.
41
+ *
42
+ * @example
43
+ * conventionalPaths('indexes').handlers.deploy // 'config-types/indexes/deploy'
44
+ */
45
+ declare function conventionalPaths(configTypeId: string): {
46
+ canvasTemplate: string;
47
+ defaultConfig: string;
48
+ handlers: Record<HandlerName, string>;
49
+ };
50
+
51
+ export { APP_LAYOUT, HANDLER_NAMES, type HandlerName, conventionalPaths };
package/dist/index.js CHANGED
@@ -4,19 +4,81 @@ import {
4
4
  defineHealthChecker,
5
5
  defineRollbackHandler,
6
6
  defineValidator
7
- } from "./chunk-PJCHU6ZZ.js";
7
+ } from "./chunk-VWFTOFTI.js";
8
8
  import {
9
9
  AppContext,
10
+ useAppBranding,
10
11
  useAppContext,
11
12
  usePipelineStatus
12
- } from "./chunk-TSEIWO6T.js";
13
+ } from "./chunk-JOJTOQZQ.js";
14
+ import "./chunk-PJN3ATPH.js";
15
+
16
+ // src/types/manifest.ts
17
+ var APP_PAGE_LAYOUTS = ["standard", "full-bleed", "canvas"];
18
+ var APP_PAGE_NAV = ["sidebar", "tab", "hidden"];
19
+
20
+ // src/structure.ts
21
+ var APP_LAYOUT = {
22
+ /** The app contract. Always at the app root. */
23
+ manifest: "manifest.yaml",
24
+ /**
25
+ * The unit of extension: config-types/<configTypeId>/ colocates everything
26
+ * for one configuration type — canvas.yaml, defaults.yaml, the six pipeline
27
+ * handlers (extensionless in the manifest), and __tests__/.
28
+ */
29
+ configTypesDir: "config-types",
30
+ /** Canvas form schema filename inside a config-type folder. */
31
+ canvasFile: "canvas.yaml",
32
+ /** Default field values filename inside a config-type folder. */
33
+ defaultsFile: "defaults.yaml",
34
+ /** Lifecycle hooks (camelCase): hooks/onInstall, hooks/onUninstall, ... */
35
+ hooksDir: "hooks",
36
+ /** Shared app code used by multiple handlers (API clients, parsers). */
37
+ libDir: "lib",
38
+ /** SQL migrations (requires manifest `database.tablePrefix`). */
39
+ migrationsDir: "migrations",
40
+ /** Fastify route module receiving (fastify, AppRouteContext). */
41
+ serverEntry: "server/index",
42
+ /** Client entry registering pages/sidebar items (optional). */
43
+ clientEntry: "client/index",
44
+ /** Icons and logos (optional). */
45
+ assetsDir: "assets",
46
+ /** Tests live next to the code they cover: handlers/<id>/__tests__/ */
47
+ testsDirName: "__tests__"
48
+ };
49
+ var HANDLER_NAMES = [
50
+ "validate",
51
+ "deploy",
52
+ "rollback",
53
+ "healthCheck",
54
+ "driftDetect",
55
+ "getStatus"
56
+ ];
57
+ function conventionalPaths(configTypeId) {
58
+ const base = `${APP_LAYOUT.configTypesDir}/${configTypeId}`;
59
+ const handlers = {};
60
+ for (const name of HANDLER_NAMES) {
61
+ handlers[name] = `${base}/${name}`;
62
+ }
63
+ return {
64
+ canvasTemplate: `${base}/${APP_LAYOUT.canvasFile}`,
65
+ defaultConfig: `${base}/${APP_LAYOUT.defaultsFile}`,
66
+ handlers
67
+ };
68
+ }
13
69
  export {
70
+ APP_LAYOUT,
71
+ APP_PAGE_LAYOUTS,
72
+ APP_PAGE_NAV,
14
73
  AppContext,
74
+ HANDLER_NAMES,
75
+ conventionalPaths,
15
76
  defineDeployer,
16
77
  defineDriftDetector,
17
78
  defineHealthChecker,
18
79
  defineRollbackHandler,
19
80
  defineValidator,
81
+ useAppBranding,
20
82
  useAppContext,
21
83
  usePipelineStatus
22
84
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/types/manifest.ts","../src/structure.ts"],"sourcesContent":["// ========================================================================\n// App manifest types\n//\n// Self-contained copy of the platform's manifest contract so the SDK can\n// be published and consumed outside the platform monorepo. The platform\n// keeps its own copy in shared/types/app.ts — changes to the manifest\n// contract must be applied to both files.\n// ========================================================================\n\nexport type AppSource = 'BUILT_IN' | 'MARKETPLACE' | 'CUSTOM'\nexport type AppStatusType = 'AVAILABLE' | 'DEPRECATED' | 'REMOVED'\nexport type AppInstallationStatus =\n | 'INSTALLING'\n | 'INSTALLED'\n | 'ENABLED'\n | 'DISABLED'\n | 'FAILED'\n | 'UNINSTALLING'\n\n// --- Manifest Types (parsed from manifest.yaml) ---\n\nexport interface AppManifest {\n id: string\n name: string\n version: string\n vendor: string\n description: string\n category: string\n license?: string\n homepage?: string\n icon?: string\n logo?: string\n\n platform: {\n minVersion: string\n }\n\n permissions: {\n platform: string[] // Platform permissions the app needs\n app: AppPermissionDeclaration[] // Permissions the app exposes\n }\n\n database?: {\n migrations: string\n tablePrefix: string\n }\n\n pipeline: {\n configurationTypes: AppConfigurationTypeManifest[]\n pipelineEvents?: string[]\n }\n\n server: {\n entry: string\n routes?: {\n prefix: string\n }\n }\n\n client?: {\n entry: string\n pages?: AppPageDeclaration[]\n }\n\n /**\n * Vendor brand identity, applied by the platform in defined slots only —\n * the app navbar (logo, accent) and scoped CSS variables. The platform,\n * not the app, decides where brand color appears, so one vendor's palette\n * never overwhelms the product shell.\n */\n branding?: AppBrandingDeclaration\n\n hooks?: {\n onInstall?: string\n onUninstall?: string\n onEnable?: string\n onDisable?: string\n onUpgrade?: string\n }\n\n events?: string[] // Platform events this app subscribes to\n\n settings?: AppSettingDeclaration[]\n}\n\n/**\n * App brand identity. The platform renders it in a per-app navbar above the\n * app's pages and exposes the colors to app pages as scoped CSS variables\n * (--veltrix-app-primary, --veltrix-app-accent).\n */\nexport interface AppBrandingDeclaration {\n /** Brand accent color as #RGB or #RRGGBB hex (e.g. CrowdStrike red). */\n primaryColor?: string\n /** Optional secondary color as #RGB or #RRGGBB hex. */\n accentColor?: string\n /**\n * Vendor logo shown in the app navbar. Repo-relative .svg (preferred) or\n * .png, at most 128 KB; rendered at 28px height, so use a wide/landscape\n * mark with transparent background.\n */\n logo?: string\n /** Optional logo variant for dark backgrounds; same constraints as logo. */\n logoDark?: string\n}\n\nexport interface AppConfigurationTypeManifest {\n id: string\n name: string\n description?: string\n canvasTemplate: string // Path to canvas template YAML\n defaultConfig?: string // Path to default config YAML\n\n handlers: {\n validate: string\n deploy: string\n rollback: string\n healthCheck: string\n driftDetect?: string | null\n getStatus: string\n }\n\n targets: {\n componentTypes: string[]\n requiresCredential: boolean\n requiresConnectivity: boolean\n }\n}\n\nexport interface AppPermissionDeclaration {\n resource: string\n actions: string[]\n description?: string\n}\n\n// --- App UI & navigation contract ---\n//\n// The platform owns the chrome: breadcrumb, app header, navigation, permission\n// gating, error boundary and loading states are rendered identically for every\n// app. Apps own the page body and compose it from @veltrixsecops/ui.\n// Predictable shell, flexible body.\n\n/**\n * How the platform frames an app page.\n * - `standard` — page header + padded content area (default; use for most pages)\n * - `full-bleed` — content area with no padding/toolbar (custom canvases, maps)\n * - `canvas` — Configuration Canvas chrome (section rail + save/validate bar)\n */\nexport type AppPageLayout = 'standard' | 'full-bleed' | 'canvas'\nexport const APP_PAGE_LAYOUTS = ['standard', 'full-bleed', 'canvas'] as const\n\n/**\n * Where the page surfaces in navigation.\n * - `sidebar` — an entry beneath the app in the sidebar\n * - `tab` — a tab within its `parent` page\n * - `hidden` — routable but not linked (details/drill-down pages)\n */\nexport type AppPageNav = 'sidebar' | 'tab' | 'hidden'\nexport const APP_PAGE_NAV = ['sidebar', 'tab', 'hidden'] as const\n\n/** An app-scoped permission (declared in `permissions.app`) required to see a page. */\nexport interface AppPagePermission {\n resource: string\n action: string\n}\n\nexport interface AppPageDeclaration {\n /** Route beneath the app, e.g. `/indexes` → `/apps/<app-id>/indexes` */\n path: string\n /** Exported component name from the app's client entry */\n component: string\n label: string\n description?: string\n /** Icon name from the platform icon set; falls back to the app icon */\n icon?: string\n /** @deprecated use `nav: 'sidebar' | 'hidden'` — kept for backward compatibility */\n sidebar?: boolean\n /** Navigation placement. Defaults to `sidebar` when `sidebar: true`, else `hidden`. */\n nav?: AppPageNav\n /** Parent page `path` — required for `nav: 'tab'`, optional nesting for sidebar entries */\n parent?: string\n /** Optional sidebar section label, for apps with many pages */\n group?: string\n /** Deterministic ordering within its group/parent (ascending; ties break on label) */\n order?: number\n /** Layout preset the platform renders around the page body */\n layout?: AppPageLayout\n /** Hide the page (and its nav entry) unless the user holds this app permission */\n requiresPermission?: AppPagePermission\n}\n\nexport interface AppSettingDeclaration {\n key: string\n type: 'string' | 'number' | 'boolean' | 'select'\n label: string\n description?: string\n default?: string | number | boolean\n required?: boolean\n options?: Array<{ label: string; value: string }>\n}\n\n// --- API Response Types ---\n\nexport interface AppListItem {\n id: string\n appId: string\n name: string\n version: string\n vendor: string\n description: string\n category: string\n icon?: string\n logo?: string\n source: AppSource\n isDefault: boolean\n status: AppStatusType\n installed?: boolean\n enabled?: boolean\n}\n\nexport interface AppDetail extends AppListItem {\n license?: string\n homepage?: string\n repository?: string\n configurationTypes: Array<{\n id: string\n name: string\n description?: string\n componentTypes: string[]\n }>\n permissions: AppPermissionDeclaration[]\n settings: AppSettingDeclaration[]\n}\n\nexport interface AppInstallationDetail {\n id: string\n appId: string\n customerId: string\n version: string\n enabled: boolean\n installedBy: string\n installedAt: string\n settings: Record<string, unknown>\n status: AppInstallationStatus\n app: AppListItem\n}\n","// ========================================================================\n// Canonical app layout\n//\n// Every Veltrix app follows one predictable folder structure so apps are\n// easy to set up, review, and load. The `veltrix` CLI scaffolds it,\n// `veltrix validate` (and repo CI) warn on deviations, and the platform's\n// app engine resolves manifest references against it.\n// ========================================================================\n\n/** Canonical locations inside an app directory. */\nexport const APP_LAYOUT = {\n /** The app contract. Always at the app root. */\n manifest: 'manifest.yaml',\n /**\n * The unit of extension: config-types/<configTypeId>/ colocates everything\n * for one configuration type — canvas.yaml, defaults.yaml, the six pipeline\n * handlers (extensionless in the manifest), and __tests__/.\n */\n configTypesDir: 'config-types',\n /** Canvas form schema filename inside a config-type folder. */\n canvasFile: 'canvas.yaml',\n /** Default field values filename inside a config-type folder. */\n defaultsFile: 'defaults.yaml',\n /** Lifecycle hooks (camelCase): hooks/onInstall, hooks/onUninstall, ... */\n hooksDir: 'hooks',\n /** Shared app code used by multiple handlers (API clients, parsers). */\n libDir: 'lib',\n /** SQL migrations (requires manifest `database.tablePrefix`). */\n migrationsDir: 'migrations',\n /** Fastify route module receiving (fastify, AppRouteContext). */\n serverEntry: 'server/index',\n /** Client entry registering pages/sidebar items (optional). */\n clientEntry: 'client/index',\n /** Icons and logos (optional). */\n assetsDir: 'assets',\n /** Tests live next to the code they cover: handlers/<id>/__tests__/ */\n testsDirName: '__tests__',\n} as const\n\n/** The six pipeline handler names, in lifecycle order. */\nexport const HANDLER_NAMES = [\n 'validate',\n 'deploy',\n 'rollback',\n 'healthCheck',\n 'driftDetect',\n 'getStatus',\n] as const\n\nexport type HandlerName = (typeof HANDLER_NAMES)[number]\n\n/**\n * Conventional manifest paths for one configuration type — handy when\n * generating or checking a manifest programmatically.\n *\n * @example\n * conventionalPaths('indexes').handlers.deploy // 'config-types/indexes/deploy'\n */\nexport function conventionalPaths(configTypeId: string): {\n canvasTemplate: string\n defaultConfig: string\n handlers: Record<HandlerName, string>\n} {\n const base = `${APP_LAYOUT.configTypesDir}/${configTypeId}`\n const handlers = {} as Record<HandlerName, string>\n for (const name of HANDLER_NAMES) {\n handlers[name] = `${base}/${name}`\n }\n return {\n canvasTemplate: `${base}/${APP_LAYOUT.canvasFile}`,\n defaultConfig: `${base}/${APP_LAYOUT.defaultsFile}`,\n handlers,\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoJO,IAAM,mBAAmB,CAAC,YAAY,cAAc,QAAQ;AAS5D,IAAM,eAAe,CAAC,WAAW,OAAO,QAAQ;;;ACnJhD,IAAM,aAAa;AAAA;AAAA,EAExB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMV,gBAAgB;AAAA;AAAA,EAEhB,YAAY;AAAA;AAAA,EAEZ,cAAc;AAAA;AAAA,EAEd,UAAU;AAAA;AAAA,EAEV,QAAQ;AAAA;AAAA,EAER,eAAe;AAAA;AAAA,EAEf,aAAa;AAAA;AAAA,EAEb,aAAa;AAAA;AAAA,EAEb,WAAW;AAAA;AAAA,EAEX,cAAc;AAChB;AAGO,IAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAWO,SAAS,kBAAkB,cAIhC;AACA,QAAM,OAAO,GAAG,WAAW,cAAc,IAAI,YAAY;AACzD,QAAM,WAAW,CAAC;AAClB,aAAW,QAAQ,eAAe;AAChC,aAAS,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI;AAAA,EAClC;AACA,SAAO;AAAA,IACL,gBAAgB,GAAG,IAAI,IAAI,WAAW,UAAU;AAAA,IAChD,eAAe,GAAG,IAAI,IAAI,WAAW,YAAY;AAAA,IACjD;AAAA,EACF;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pipeline/index.ts","../../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":["export { defineValidator } from './define-validator'\r\nexport { defineDeployer } from './define-deployer'\r\nexport { defineRollbackHandler } from './define-rollback-handler'\r\nexport { defineHealthChecker } from './define-health-checker'\r\nexport { defineDriftDetector } from './define-drift-detector'\r\n","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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACmBO,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/index.ts","../../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":["export { defineValidator } from './define-validator'\nexport { defineDeployer } from './define-deployer'\nexport { defineRollbackHandler } from './define-rollback-handler'\nexport { defineHealthChecker } from './define-health-checker'\nexport { defineDriftDetector } from './define-drift-detector'\n","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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACmBO,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":[]}
@@ -4,7 +4,7 @@ import {
4
4
  defineHealthChecker,
5
5
  defineRollbackHandler,
6
6
  defineValidator
7
- } from "../chunk-PJCHU6ZZ.js";
7
+ } from "../chunk-VWFTOFTI.js";
8
8
  export {
9
9
  defineDeployer,
10
10
  defineDriftDetector,
@@ -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 };