@khal-os/types 1.0.14 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -92,6 +92,23 @@ var KhalAppManifestSchema = import_zod.z.object({
92
92
  }).optional(),
93
93
  /** Relative path to the pre-built ESM bundle within the package (e.g., "dist/bundle.mjs"). */
94
94
  bundlePath: import_zod.z.string().optional(),
95
+ /** Sandbox configuration for per-user container provisioning. */
96
+ sandbox: import_zod.z.object({
97
+ enabled: import_zod.z.boolean(),
98
+ image: import_zod.z.string().optional(),
99
+ requests: import_zod.z.object({ cpu: import_zod.z.string(), memory: import_zod.z.string() }).optional(),
100
+ limits: import_zod.z.object({ cpu: import_zod.z.string(), memory: import_zod.z.string() }).optional(),
101
+ mounts: import_zod.z.array(
102
+ import_zod.z.object({
103
+ mountPath: import_zod.z.string(),
104
+ source: import_zod.z.enum(["files", "pvc"]),
105
+ pvcName: import_zod.z.string().optional(),
106
+ readOnly: import_zod.z.boolean().optional()
107
+ })
108
+ ).optional(),
109
+ sudoers: import_zod.z.boolean().optional(),
110
+ natsPrefix: import_zod.z.string().optional()
111
+ }).optional(),
95
112
  /**
96
113
  * When apps is present, the root frontend field is ignored —
97
114
  * each entry has its own frontend.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/manifest.ts","../src/roles.ts"],"sourcesContent":["export type { KhalAuth } from './auth';\nexport type {\n\tAppDeployConfig,\n\tAppDesktopConfig,\n\tAppEnvVar,\n\tAppManifest,\n\tAppManifestView,\n\tAppServiceConfig,\n\tAppTauriConfig,\n\tKhalAppEntry,\n\tKhalAppManifest,\n\tKhalPermission,\n\tKhalServiceSpec,\n\tKhalWindowSpec,\n\tServiceHealthConfig,\n} from './manifest';\nexport {\n\tKhalAppEntrySchema,\n\tKhalAppManifestSchema,\n\tvalidateManifest,\n} from './manifest';\nexport type { ConnectionState } from './nats';\nexport type { Role } from './roles';\nexport { ROLE_HIERARCHY } from './roles';\n","import { z } from 'zod';\nimport type { Role } from './roles';\n\n/** Desktop integration metadata for an app. */\nexport interface AppDesktopConfig {\n\t/** Path to the app icon (relative to the public directory). */\n\ticon: string;\n\t/** Categories for desktop launcher grouping. */\n\tcategories: string[];\n\t/** Short description shown in the desktop launcher. */\n\tcomment: string;\n}\n\n/** A single view within an app manifest. */\nexport interface AppManifestView {\n\t/** Unique view identifier within the app. */\n\tid: string;\n\t/** Human-readable label for the view. */\n\tlabel: string;\n\t/** Permission string required to access this view. */\n\tpermission: string;\n\t/** Minimum role level required. */\n\tminRole: Role;\n\t/** NATS subject segment after `khal.<orgId>.` for this view's services. */\n\tnatsPrefix?: string;\n\t/** Default window dimensions. */\n\tdefaultSize: { width: number; height: number };\n\t/** Relative path to the view's React component. */\n\tcomponent: string;\n}\n\n/** Health check configuration for a service. */\nexport interface ServiceHealthConfig {\n\t/** Check type: tcp (connect to port), http (GET endpoint), command (run shell). */\n\ttype: 'tcp' | 'http' | 'command';\n\t/** Target: port number for tcp, URL for http, shell command for command. */\n\ttarget: string | number;\n\t/** Check interval in milliseconds (default: 30000). */\n\tinterval?: number;\n\t/** Timeout in milliseconds (default: 5000). */\n\ttimeout?: number;\n}\n\n/** Service declaration within an app manifest. */\nexport interface AppServiceConfig {\n\t/** Service name (must be unique across the app). */\n\tname: string;\n\t/** Shell command to start the service (alternative to entry). */\n\tcommand?: string;\n\t/** Entry point file path relative to the package root. */\n\tentry?: string;\n\t/** Runtime environment. */\n\truntime?: 'node' | 'python';\n\t/** Health check configuration. */\n\thealth?: ServiceHealthConfig;\n\t/** Restart policy. */\n\trestart?: 'always' | 'on-failure' | 'never';\n\t/** Ports the service binds to internally. Khal assigns proxy ports. */\n\tports?: number[];\n}\n\n/** Environment variable declaration for app configuration. */\nexport interface AppEnvVar {\n\t/** Variable name (e.g., \"API_KEY\"). */\n\tkey: string;\n\t/** Human-readable description shown in the config UI. */\n\tdescription: string;\n\t/** Whether the variable is required for the app to run. */\n\trequired: boolean;\n\t/** Default value if not configured. */\n\tdefault?: string;\n\t/** Value type — affects config UI rendering and validation. */\n\ttype?: 'string' | 'number' | 'boolean' | 'secret' | 'url';\n\t/** Storage: 'config' for plain ConfigMap, 'vault' for Kubernetes Secret. */\n\tvisibility?: 'config' | 'vault';\n}\n\n/** Kubernetes deployment configuration for apps with backends. */\nexport interface AppDeployConfig {\n\t/** Dockerfile path relative to app root (default: \"Dockerfile\"). */\n\tdockerfile?: string;\n\t/** Build args passed to docker build. */\n\tbuildArgs?: Record<string, string>;\n\t/** Container port the app listens on. */\n\tport?: number;\n\t/** Resource requests and limits for the pod. */\n\tresources?: {\n\t\trequests?: { cpu?: string; memory?: string };\n\t\tlimits?: { cpu?: string; memory?: string };\n\t};\n\t/** Replica count (default: 1). */\n\treplicas?: number;\n\t/** Health check path for k8s readiness/liveness probes. */\n\thealthPath?: string;\n\t/** Ingress configuration for per-app routing. */\n\tingress?: {\n\t\t/** Subdomain prefix: <value>.apps.<domain>. Defaults to app id. */\n\t\tsubdomain?: string;\n\t\t/** Additional path prefixes to route to this app. */\n\t\tpathPrefixes?: string[];\n\t};\n\t/** Horizontal Pod Autoscaler configuration. */\n\tautoscaling?: {\n\t\tenabled: boolean;\n\t\tminReplicas?: number;\n\t\tmaxReplicas?: number;\n\t\ttargetCPU?: number;\n\t};\n\t/** Environment sources injected at runtime from k8s resources. */\n\tenvFrom?: Array<{ secretRef?: string; configMapRef?: string }>;\n}\n\n/** Tauri standalone export configuration. */\nexport interface AppTauriConfig {\n\t/** Whether this app supports standalone Tauri export. */\n\texportable: boolean;\n\t/** Path to src-tauri/ directory (default: \"./src-tauri\"). */\n\ttauriDir?: string;\n\t/** App name for the exported binary. */\n\tappName?: string;\n\t/** App icon path relative to app root. */\n\ticon?: string;\n\t/** Window configuration for standalone mode. */\n\twindow?: { width?: number; height?: number; title?: string };\n}\n\n/**\n * Full app manifest — the type for `manifest.ts` files in KhalOS app packages.\n *\n * Every app package must export a default manifest conforming to this shape.\n * Use `defineManifest()` for compile-time validation and autocomplete.\n *\n * The JSON equivalent (`khal-app.json`) uses the same shape and is the\n * language-agnostic install-time contract that the marketplace reads.\n */\nexport interface AppManifest {\n\t/** Unique app identifier (must match the package directory name). */\n\tid: string;\n\t/** One or more views the app exposes. */\n\tviews: AppManifestView[];\n\t/** Desktop integration configuration. */\n\tdesktop: AppDesktopConfig;\n\t/** Backend services this app runs. Optional — pure UI apps have no services. */\n\tservices?: AppServiceConfig[];\n\n\t// ── v2 fields (all optional for backward compatibility) ──\n\n\t/** Schema version for forward compatibility (default: 1). */\n\tschemaVersion?: number;\n\t/** Human-readable app name. */\n\tname?: string;\n\t/** Semantic version of the app. */\n\tversion?: string;\n\t/** Short description for the marketplace listing. */\n\tdescription?: string;\n\t/** Author name or organization. */\n\tauthor?: string;\n\t/** SPDX license identifier. */\n\tlicense?: string;\n\t/** Source repository URL. */\n\trepository?: string;\n\t/** Minimum KhalOS host version required. */\n\tminHostVersion?: string;\n\t/** Environment variables the app needs — auto-generates config UI. */\n\tenv?: AppEnvVar[];\n\t/** Native Kubernetes deployment configuration. */\n\tdeploy?: AppDeployConfig;\n\t/** Tauri standalone export configuration. */\n\ttauri?: AppTauriConfig;\n\t/** URL to the app's pre-built ESM bundle for runtime loading by desktop. */\n\tbundleUrl?: string;\n}\n\n// ── Pack Contract Types (for standalone pack-* repos) ──\n\nexport const KhalPermission = z.enum([\n\t'nats:publish',\n\t'nats:subscribe',\n\t'files:read',\n\t'files:write',\n\t'pty:spawn',\n\t'http:fetch',\n\t'system:clipboard',\n\t'system:notifications',\n]);\nexport type KhalPermission = z.infer<typeof KhalPermission>;\n\nexport const KhalServiceSpec = z.object({\n\tname: z.string(),\n\tcommand: z.string().optional(),\n\tentry: z.string().optional(),\n\truntime: z.enum(['node', 'bun', 'python']).optional(),\n\tports: z.array(z.number()).optional(),\n\thealth: z\n\t\t.object({\n\t\t\ttype: z.enum(['tcp', 'http', 'command']),\n\t\t\ttarget: z.union([z.string(), z.number()]),\n\t\t\tinterval: z.number().optional(),\n\t\t\ttimeout: z.number().optional(),\n\t\t})\n\t\t.optional(),\n});\nexport type KhalServiceSpec = z.infer<typeof KhalServiceSpec>;\n\nexport const KhalWindowSpec = z.object({\n\tid: z.string(),\n\ttitle: z.string().optional(),\n\twidth: z.number().default(800),\n\theight: z.number().default(600),\n\tresizable: z.boolean().default(true),\n});\nexport type KhalWindowSpec = z.infer<typeof KhalWindowSpec>;\n\n/** A single app entry within a bundle pack manifest. */\nexport const KhalAppEntrySchema = z.object({\n\t/** Unique app identifier within the bundle. */\n\tid: z.string(),\n\t/** Human-readable app name. */\n\tname: z.string(),\n\t/** Frontend package reference for this app. */\n\tfrontend: z\n\t\t.object({\n\t\t\tpackage: z.string(),\n\t\t})\n\t\t.optional(),\n});\nexport type KhalAppEntry = z.infer<typeof KhalAppEntrySchema>;\n\nexport const KhalAppManifestSchema = z\n\t.object({\n\t\t$schema: z.string().optional(),\n\t\tid: z.string(),\n\t\tname: z.string(),\n\t\tversion: z.string(),\n\t\ticon: z.string(),\n\t\tdescription: z.string(),\n\t\tauthor: z.string(),\n\t\tpermissions: z.array(KhalPermission),\n\t\tservices: z.array(KhalServiceSpec).optional(),\n\t\twindows: z.array(KhalWindowSpec).optional(),\n\t\tfrontend: z\n\t\t\t.object({\n\t\t\t\tpackage: z.string(),\n\t\t\t\tentry: z.string().default('default'),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbackend: z\n\t\t\t.object({\n\t\t\t\timage: z.string(),\n\t\t\t\thelmChart: z.string().optional(),\n\t\t\t\tenv: z.record(z.string(), z.string()),\n\t\t\t\tports: z.array(z.number()),\n\t\t\t})\n\t\t\t.optional(),\n\t\t/** Relative path to the pre-built ESM bundle within the package (e.g., \"dist/bundle.mjs\"). */\n\t\tbundlePath: z.string().optional(),\n\t\t/**\n\t\t * When apps is present, the root frontend field is ignored —\n\t\t * each entry has its own frontend.\n\t\t */\n\t\tapps: z.array(KhalAppEntrySchema).optional(),\n\t})\n\t.strict();\n\nexport type KhalAppManifest = z.infer<typeof KhalAppManifestSchema>;\n\n/** Validate a raw object as KhalAppManifest. Throws ZodError with detailed messages on failure. */\nexport function validateManifest(raw: unknown): KhalAppManifest {\n\treturn KhalAppManifestSchema.parse(raw);\n}\n","/** Canonical role hierarchy from least to most privileged. */\nexport const ROLE_HIERARCHY = ['member', 'platform-dev', 'platform-admin', 'platform-owner'] as const;\nexport type Role = (typeof ROLE_HIERARCHY)[number];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,iBAAkB;AA+KX,IAAM,iBAAiB,aAAE,KAAK;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAGM,IAAM,kBAAkB,aAAE,OAAO;AAAA,EACvC,MAAM,aAAE,OAAO;AAAA,EACf,SAAS,aAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,OAAO,aAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,SAAS,aAAE,KAAK,CAAC,QAAQ,OAAO,QAAQ,CAAC,EAAE,SAAS;AAAA,EACpD,OAAO,aAAE,MAAM,aAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACpC,QAAQ,aACN,OAAO;AAAA,IACP,MAAM,aAAE,KAAK,CAAC,OAAO,QAAQ,SAAS,CAAC;AAAA,IACvC,QAAQ,aAAE,MAAM,CAAC,aAAE,OAAO,GAAG,aAAE,OAAO,CAAC,CAAC;AAAA,IACxC,UAAU,aAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,SAAS,aAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,CAAC,EACA,SAAS;AACZ,CAAC;AAGM,IAAM,iBAAiB,aAAE,OAAO;AAAA,EACtC,IAAI,aAAE,OAAO;AAAA,EACb,OAAO,aAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,OAAO,aAAE,OAAO,EAAE,QAAQ,GAAG;AAAA,EAC7B,QAAQ,aAAE,OAAO,EAAE,QAAQ,GAAG;AAAA,EAC9B,WAAW,aAAE,QAAQ,EAAE,QAAQ,IAAI;AACpC,CAAC;AAIM,IAAM,qBAAqB,aAAE,OAAO;AAAA;AAAA,EAE1C,IAAI,aAAE,OAAO;AAAA;AAAA,EAEb,MAAM,aAAE,OAAO;AAAA;AAAA,EAEf,UAAU,aACR,OAAO;AAAA,IACP,SAAS,aAAE,OAAO;AAAA,EACnB,CAAC,EACA,SAAS;AACZ,CAAC;AAGM,IAAM,wBAAwB,aACnC,OAAO;AAAA,EACP,SAAS,aAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,IAAI,aAAE,OAAO;AAAA,EACb,MAAM,aAAE,OAAO;AAAA,EACf,SAAS,aAAE,OAAO;AAAA,EAClB,MAAM,aAAE,OAAO;AAAA,EACf,aAAa,aAAE,OAAO;AAAA,EACtB,QAAQ,aAAE,OAAO;AAAA,EACjB,aAAa,aAAE,MAAM,cAAc;AAAA,EACnC,UAAU,aAAE,MAAM,eAAe,EAAE,SAAS;AAAA,EAC5C,SAAS,aAAE,MAAM,cAAc,EAAE,SAAS;AAAA,EAC1C,UAAU,aACR,OAAO;AAAA,IACP,SAAS,aAAE,OAAO;AAAA,IAClB,OAAO,aAAE,OAAO,EAAE,QAAQ,SAAS;AAAA,EACpC,CAAC,EACA,SAAS;AAAA,EACX,SAAS,aACP,OAAO;AAAA,IACP,OAAO,aAAE,OAAO;AAAA,IAChB,WAAW,aAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,KAAK,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,OAAO,CAAC;AAAA,IACpC,OAAO,aAAE,MAAM,aAAE,OAAO,CAAC;AAAA,EAC1B,CAAC,EACA,SAAS;AAAA;AAAA,EAEX,YAAY,aAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhC,MAAM,aAAE,MAAM,kBAAkB,EAAE,SAAS;AAC5C,CAAC,EACA,OAAO;AAKF,SAAS,iBAAiB,KAA+B;AAC/D,SAAO,sBAAsB,MAAM,GAAG;AACvC;;;AC5QO,IAAM,iBAAiB,CAAC,UAAU,gBAAgB,kBAAkB,gBAAgB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/manifest.ts","../src/roles.ts"],"sourcesContent":["export type { KhalAuth } from './auth';\nexport type {\n\tAppDeployConfig,\n\tAppDesktopConfig,\n\tAppEnvVar,\n\tAppManifest,\n\tAppManifestView,\n\tAppServiceConfig,\n\tAppTauriConfig,\n\tKhalAppEntry,\n\tKhalAppManifest,\n\tKhalPermission,\n\tKhalServiceSpec,\n\tKhalWindowSpec,\n\tSandboxConfig,\n\tSandboxMount,\n\tSandboxResourceSpec,\n\tServiceHealthConfig,\n} from './manifest';\nexport {\n\tKhalAppEntrySchema,\n\tKhalAppManifestSchema,\n\tvalidateManifest,\n} from './manifest';\nexport type { ConnectionState } from './nats';\nexport type { Role } from './roles';\nexport { ROLE_HIERARCHY } from './roles';\n","import { z } from 'zod';\nimport type { Role } from './roles';\n\n/** Desktop integration metadata for an app. */\nexport interface AppDesktopConfig {\n\t/** Path to the app icon (relative to the public directory). */\n\ticon: string;\n\t/** Categories for desktop launcher grouping. */\n\tcategories: string[];\n\t/** Short description shown in the desktop launcher. */\n\tcomment: string;\n}\n\n/** A single view within an app manifest. */\nexport interface AppManifestView {\n\t/** Unique view identifier within the app. */\n\tid: string;\n\t/** Human-readable label for the view. */\n\tlabel: string;\n\t/** Permission string required to access this view. */\n\tpermission: string;\n\t/** Minimum role level required. */\n\tminRole: Role;\n\t/** NATS subject segment after `khal.<orgId>.` for this view's services. */\n\tnatsPrefix?: string;\n\t/** Default window dimensions. */\n\tdefaultSize: { width: number; height: number };\n\t/** Relative path to the view's React component. */\n\tcomponent: string;\n}\n\n/** Health check configuration for a service. */\nexport interface ServiceHealthConfig {\n\t/** Check type: tcp (connect to port), http (GET endpoint), command (run shell). */\n\ttype: 'tcp' | 'http' | 'command';\n\t/** Target: port number for tcp, URL for http, shell command for command. */\n\ttarget: string | number;\n\t/** Check interval in milliseconds (default: 30000). */\n\tinterval?: number;\n\t/** Timeout in milliseconds (default: 5000). */\n\ttimeout?: number;\n}\n\n/** Service declaration within an app manifest. */\nexport interface AppServiceConfig {\n\t/** Service name (must be unique across the app). */\n\tname: string;\n\t/** Shell command to start the service (alternative to entry). */\n\tcommand?: string;\n\t/** Entry point file path relative to the package root. */\n\tentry?: string;\n\t/** Runtime environment. */\n\truntime?: 'node' | 'python';\n\t/** Health check configuration. */\n\thealth?: ServiceHealthConfig;\n\t/** Restart policy. */\n\trestart?: 'always' | 'on-failure' | 'never';\n\t/** Ports the service binds to internally. Khal assigns proxy ports. */\n\tports?: number[];\n}\n\n/** Environment variable declaration for app configuration. */\nexport interface AppEnvVar {\n\t/** Variable name (e.g., \"API_KEY\"). */\n\tkey: string;\n\t/** Human-readable description shown in the config UI. */\n\tdescription: string;\n\t/** Whether the variable is required for the app to run. */\n\trequired: boolean;\n\t/** Default value if not configured. */\n\tdefault?: string;\n\t/** Value type — affects config UI rendering and validation. */\n\ttype?: 'string' | 'number' | 'boolean' | 'secret' | 'url';\n\t/** Storage: 'config' for plain ConfigMap, 'vault' for Kubernetes Secret. */\n\tvisibility?: 'config' | 'vault';\n}\n\n/** Kubernetes deployment configuration for apps with backends. */\nexport interface AppDeployConfig {\n\t/** Dockerfile path relative to app root (default: \"Dockerfile\"). */\n\tdockerfile?: string;\n\t/** Build args passed to docker build. */\n\tbuildArgs?: Record<string, string>;\n\t/** Container port the app listens on. */\n\tport?: number;\n\t/** Resource requests and limits for the pod. */\n\tresources?: {\n\t\trequests?: { cpu?: string; memory?: string };\n\t\tlimits?: { cpu?: string; memory?: string };\n\t};\n\t/** Replica count (default: 1). */\n\treplicas?: number;\n\t/** Health check path for k8s readiness/liveness probes. */\n\thealthPath?: string;\n\t/** Ingress configuration for per-app routing. */\n\tingress?: {\n\t\t/** Subdomain prefix: <value>.apps.<domain>. Defaults to app id. */\n\t\tsubdomain?: string;\n\t\t/** Additional path prefixes to route to this app. */\n\t\tpathPrefixes?: string[];\n\t};\n\t/** Horizontal Pod Autoscaler configuration. */\n\tautoscaling?: {\n\t\tenabled: boolean;\n\t\tminReplicas?: number;\n\t\tmaxReplicas?: number;\n\t\ttargetCPU?: number;\n\t};\n\t/** Environment sources injected at runtime from k8s resources. */\n\tenvFrom?: Array<{ secretRef?: string; configMapRef?: string }>;\n}\n\n/** Sandbox resource specification for per-user container provisioning. */\nexport interface SandboxResourceSpec {\n\t/** CPU request (e.g., \"4\"). */\n\tcpu: string;\n\t/** Memory request (e.g., \"4Gi\"). */\n\tmemory: string;\n}\n\n/** Volume mount configuration for sandbox containers. */\nexport interface SandboxMount {\n\t/** Mount path inside the sandbox container. */\n\tmountPath: string;\n\t/** Source type: 'files' mounts user's Files PVC, 'pvc' mounts a named PVC. */\n\tsource: 'files' | 'pvc';\n\t/** PVC name (required when source is 'pvc'). */\n\tpvcName?: string;\n\t/** Read-only mount. Default: false. */\n\treadOnly?: boolean;\n}\n\n/**\n * Sandbox configuration for apps that require a per-user container.\n * When present on an app manifest, installing the app triggers sandbox\n * provisioning via `os.sandbox.create`.\n */\nexport interface SandboxConfig {\n\t/** Enable sandbox provisioning on install. */\n\tenabled: boolean;\n\t/** Base container image (e.g., \"khal-os/sandbox-ubuntu:latest\"). */\n\timage?: string;\n\t/** Resource requests for the sandbox pod. */\n\trequests?: SandboxResourceSpec;\n\t/** Resource limits for the sandbox pod (burstable). */\n\tlimits?: SandboxResourceSpec;\n\t/** Volume mounts inside the sandbox. */\n\tmounts?: SandboxMount[];\n\t/** Whether the sandbox user gets sudo access. Default: true. */\n\tsudoers?: boolean;\n\t/** NATS subject prefix for sandbox communication (default: \"os.sandbox\"). */\n\tnatsPrefix?: string;\n}\n\n/** Tauri standalone export configuration. */\nexport interface AppTauriConfig {\n\t/** Whether this app supports standalone Tauri export. */\n\texportable: boolean;\n\t/** Path to src-tauri/ directory (default: \"./src-tauri\"). */\n\ttauriDir?: string;\n\t/** App name for the exported binary. */\n\tappName?: string;\n\t/** App icon path relative to app root. */\n\ticon?: string;\n\t/** Window configuration for standalone mode. */\n\twindow?: { width?: number; height?: number; title?: string };\n}\n\n/**\n * Full app manifest — the type for `manifest.ts` files in KhalOS app packages.\n *\n * Every app package must export a default manifest conforming to this shape.\n * Use `defineManifest()` for compile-time validation and autocomplete.\n *\n * The JSON equivalent (`khal-app.json`) uses the same shape and is the\n * language-agnostic install-time contract that the marketplace reads.\n */\nexport interface AppManifest {\n\t/** Unique app identifier (must match the package directory name). */\n\tid: string;\n\t/** One or more views the app exposes. */\n\tviews: AppManifestView[];\n\t/** Desktop integration configuration. */\n\tdesktop: AppDesktopConfig;\n\t/** Backend services this app runs. Optional — pure UI apps have no services. */\n\tservices?: AppServiceConfig[];\n\n\t// ── v2 fields (all optional for backward compatibility) ──\n\n\t/** Schema version for forward compatibility (default: 1). */\n\tschemaVersion?: number;\n\t/** Human-readable app name. */\n\tname?: string;\n\t/** Semantic version of the app. */\n\tversion?: string;\n\t/** Short description for the marketplace listing. */\n\tdescription?: string;\n\t/** Author name or organization. */\n\tauthor?: string;\n\t/** SPDX license identifier. */\n\tlicense?: string;\n\t/** Source repository URL. */\n\trepository?: string;\n\t/** Minimum KhalOS host version required. */\n\tminHostVersion?: string;\n\t/** Environment variables the app needs — auto-generates config UI. */\n\tenv?: AppEnvVar[];\n\t/** Native Kubernetes deployment configuration. */\n\tdeploy?: AppDeployConfig;\n\t/** Tauri standalone export configuration. */\n\ttauri?: AppTauriConfig;\n\t/** URL to the app's pre-built ESM bundle for runtime loading by desktop. */\n\tbundleUrl?: string;\n\t/** Sandbox configuration — when present, installing this app provisions a per-user container. */\n\tsandbox?: SandboxConfig;\n}\n\n// ── Pack Contract Types (for standalone pack-* repos) ──\n\nexport const KhalPermission = z.enum([\n\t'nats:publish',\n\t'nats:subscribe',\n\t'files:read',\n\t'files:write',\n\t'pty:spawn',\n\t'http:fetch',\n\t'system:clipboard',\n\t'system:notifications',\n]);\nexport type KhalPermission = z.infer<typeof KhalPermission>;\n\nexport const KhalServiceSpec = z.object({\n\tname: z.string(),\n\tcommand: z.string().optional(),\n\tentry: z.string().optional(),\n\truntime: z.enum(['node', 'bun', 'python']).optional(),\n\tports: z.array(z.number()).optional(),\n\thealth: z\n\t\t.object({\n\t\t\ttype: z.enum(['tcp', 'http', 'command']),\n\t\t\ttarget: z.union([z.string(), z.number()]),\n\t\t\tinterval: z.number().optional(),\n\t\t\ttimeout: z.number().optional(),\n\t\t})\n\t\t.optional(),\n});\nexport type KhalServiceSpec = z.infer<typeof KhalServiceSpec>;\n\nexport const KhalWindowSpec = z.object({\n\tid: z.string(),\n\ttitle: z.string().optional(),\n\twidth: z.number().default(800),\n\theight: z.number().default(600),\n\tresizable: z.boolean().default(true),\n});\nexport type KhalWindowSpec = z.infer<typeof KhalWindowSpec>;\n\n/** A single app entry within a bundle pack manifest. */\nexport const KhalAppEntrySchema = z.object({\n\t/** Unique app identifier within the bundle. */\n\tid: z.string(),\n\t/** Human-readable app name. */\n\tname: z.string(),\n\t/** Frontend package reference for this app. */\n\tfrontend: z\n\t\t.object({\n\t\t\tpackage: z.string(),\n\t\t})\n\t\t.optional(),\n});\nexport type KhalAppEntry = z.infer<typeof KhalAppEntrySchema>;\n\nexport const KhalAppManifestSchema = z\n\t.object({\n\t\t$schema: z.string().optional(),\n\t\tid: z.string(),\n\t\tname: z.string(),\n\t\tversion: z.string(),\n\t\ticon: z.string(),\n\t\tdescription: z.string(),\n\t\tauthor: z.string(),\n\t\tpermissions: z.array(KhalPermission),\n\t\tservices: z.array(KhalServiceSpec).optional(),\n\t\twindows: z.array(KhalWindowSpec).optional(),\n\t\tfrontend: z\n\t\t\t.object({\n\t\t\t\tpackage: z.string(),\n\t\t\t\tentry: z.string().default('default'),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbackend: z\n\t\t\t.object({\n\t\t\t\timage: z.string(),\n\t\t\t\thelmChart: z.string().optional(),\n\t\t\t\tenv: z.record(z.string(), z.string()),\n\t\t\t\tports: z.array(z.number()),\n\t\t\t})\n\t\t\t.optional(),\n\t\t/** Relative path to the pre-built ESM bundle within the package (e.g., \"dist/bundle.mjs\"). */\n\t\tbundlePath: z.string().optional(),\n\t\t/** Sandbox configuration for per-user container provisioning. */\n\t\tsandbox: z\n\t\t\t.object({\n\t\t\t\tenabled: z.boolean(),\n\t\t\t\timage: z.string().optional(),\n\t\t\t\trequests: z\n\t\t\t\t\t.object({ cpu: z.string(), memory: z.string() })\n\t\t\t\t\t.optional(),\n\t\t\t\tlimits: z\n\t\t\t\t\t.object({ cpu: z.string(), memory: z.string() })\n\t\t\t\t\t.optional(),\n\t\t\t\tmounts: z\n\t\t\t\t\t.array(\n\t\t\t\t\t\tz.object({\n\t\t\t\t\t\t\tmountPath: z.string(),\n\t\t\t\t\t\t\tsource: z.enum(['files', 'pvc']),\n\t\t\t\t\t\t\tpvcName: z.string().optional(),\n\t\t\t\t\t\t\treadOnly: z.boolean().optional(),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\t.optional(),\n\t\t\t\tsudoers: z.boolean().optional(),\n\t\t\t\tnatsPrefix: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\t/**\n\t\t * When apps is present, the root frontend field is ignored —\n\t\t * each entry has its own frontend.\n\t\t */\n\t\tapps: z.array(KhalAppEntrySchema).optional(),\n\t})\n\t.strict();\n\nexport type KhalAppManifest = z.infer<typeof KhalAppManifestSchema>;\n\n/** Validate a raw object as KhalAppManifest. Throws ZodError with detailed messages on failure. */\nexport function validateManifest(raw: unknown): KhalAppManifest {\n\treturn KhalAppManifestSchema.parse(raw);\n}\n","/** Canonical role hierarchy from least to most privileged. */\nexport const ROLE_HIERARCHY = ['member', 'platform-dev', 'platform-admin', 'platform-owner'] as const;\nexport type Role = (typeof ROLE_HIERARCHY)[number];\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -128,6 +128,45 @@ interface AppDeployConfig {
128
128
  configMapRef?: string;
129
129
  }>;
130
130
  }
131
+ /** Sandbox resource specification for per-user container provisioning. */
132
+ interface SandboxResourceSpec {
133
+ /** CPU request (e.g., "4"). */
134
+ cpu: string;
135
+ /** Memory request (e.g., "4Gi"). */
136
+ memory: string;
137
+ }
138
+ /** Volume mount configuration for sandbox containers. */
139
+ interface SandboxMount {
140
+ /** Mount path inside the sandbox container. */
141
+ mountPath: string;
142
+ /** Source type: 'files' mounts user's Files PVC, 'pvc' mounts a named PVC. */
143
+ source: 'files' | 'pvc';
144
+ /** PVC name (required when source is 'pvc'). */
145
+ pvcName?: string;
146
+ /** Read-only mount. Default: false. */
147
+ readOnly?: boolean;
148
+ }
149
+ /**
150
+ * Sandbox configuration for apps that require a per-user container.
151
+ * When present on an app manifest, installing the app triggers sandbox
152
+ * provisioning via `os.sandbox.create`.
153
+ */
154
+ interface SandboxConfig {
155
+ /** Enable sandbox provisioning on install. */
156
+ enabled: boolean;
157
+ /** Base container image (e.g., "khal-os/sandbox-ubuntu:latest"). */
158
+ image?: string;
159
+ /** Resource requests for the sandbox pod. */
160
+ requests?: SandboxResourceSpec;
161
+ /** Resource limits for the sandbox pod (burstable). */
162
+ limits?: SandboxResourceSpec;
163
+ /** Volume mounts inside the sandbox. */
164
+ mounts?: SandboxMount[];
165
+ /** Whether the sandbox user gets sudo access. Default: true. */
166
+ sudoers?: boolean;
167
+ /** NATS subject prefix for sandbox communication (default: "os.sandbox"). */
168
+ natsPrefix?: string;
169
+ }
131
170
  /** Tauri standalone export configuration. */
132
171
  interface AppTauriConfig {
133
172
  /** Whether this app supports standalone Tauri export. */
@@ -187,6 +226,8 @@ interface AppManifest {
187
226
  tauri?: AppTauriConfig;
188
227
  /** URL to the app's pre-built ESM bundle for runtime loading by desktop. */
189
228
  bundleUrl?: string;
229
+ /** Sandbox configuration — when present, installing this app provisions a per-user container. */
230
+ sandbox?: SandboxConfig;
190
231
  }
191
232
  declare const KhalPermission: z.ZodEnum<{
192
233
  "nats:publish": "nats:publish";
@@ -295,6 +336,29 @@ declare const KhalAppManifestSchema: z.ZodObject<{
295
336
  ports: z.ZodArray<z.ZodNumber>;
296
337
  }, z.core.$strip>>;
297
338
  bundlePath: z.ZodOptional<z.ZodString>;
339
+ sandbox: z.ZodOptional<z.ZodObject<{
340
+ enabled: z.ZodBoolean;
341
+ image: z.ZodOptional<z.ZodString>;
342
+ requests: z.ZodOptional<z.ZodObject<{
343
+ cpu: z.ZodString;
344
+ memory: z.ZodString;
345
+ }, z.core.$strip>>;
346
+ limits: z.ZodOptional<z.ZodObject<{
347
+ cpu: z.ZodString;
348
+ memory: z.ZodString;
349
+ }, z.core.$strip>>;
350
+ mounts: z.ZodOptional<z.ZodArray<z.ZodObject<{
351
+ mountPath: z.ZodString;
352
+ source: z.ZodEnum<{
353
+ files: "files";
354
+ pvc: "pvc";
355
+ }>;
356
+ pvcName: z.ZodOptional<z.ZodString>;
357
+ readOnly: z.ZodOptional<z.ZodBoolean>;
358
+ }, z.core.$strip>>>;
359
+ sudoers: z.ZodOptional<z.ZodBoolean>;
360
+ natsPrefix: z.ZodOptional<z.ZodString>;
361
+ }, z.core.$strip>>;
298
362
  apps: z.ZodOptional<z.ZodArray<z.ZodObject<{
299
363
  id: z.ZodString;
300
364
  name: z.ZodString;
@@ -310,4 +374,4 @@ declare function validateManifest(raw: unknown): KhalAppManifest;
310
374
  /** Connection states reported by the WS relay. */
311
375
  type ConnectionState = 'connected' | 'reconnecting' | 'disconnected' | 'auth_expired' | 'version_mismatch';
312
376
 
313
- export { type AppDeployConfig, type AppDesktopConfig, type AppEnvVar, type AppManifest, type AppManifestView, type AppServiceConfig, type AppTauriConfig, type ConnectionState, type KhalAppEntry, KhalAppEntrySchema, type KhalAppManifest, KhalAppManifestSchema, type KhalAuth, KhalPermission, KhalServiceSpec, KhalWindowSpec, ROLE_HIERARCHY, type Role, type ServiceHealthConfig, validateManifest };
377
+ export { type AppDeployConfig, type AppDesktopConfig, type AppEnvVar, type AppManifest, type AppManifestView, type AppServiceConfig, type AppTauriConfig, type ConnectionState, type KhalAppEntry, KhalAppEntrySchema, type KhalAppManifest, KhalAppManifestSchema, type KhalAuth, KhalPermission, KhalServiceSpec, KhalWindowSpec, ROLE_HIERARCHY, type Role, type SandboxConfig, type SandboxMount, type SandboxResourceSpec, type ServiceHealthConfig, validateManifest };
package/dist/index.d.ts CHANGED
@@ -128,6 +128,45 @@ interface AppDeployConfig {
128
128
  configMapRef?: string;
129
129
  }>;
130
130
  }
131
+ /** Sandbox resource specification for per-user container provisioning. */
132
+ interface SandboxResourceSpec {
133
+ /** CPU request (e.g., "4"). */
134
+ cpu: string;
135
+ /** Memory request (e.g., "4Gi"). */
136
+ memory: string;
137
+ }
138
+ /** Volume mount configuration for sandbox containers. */
139
+ interface SandboxMount {
140
+ /** Mount path inside the sandbox container. */
141
+ mountPath: string;
142
+ /** Source type: 'files' mounts user's Files PVC, 'pvc' mounts a named PVC. */
143
+ source: 'files' | 'pvc';
144
+ /** PVC name (required when source is 'pvc'). */
145
+ pvcName?: string;
146
+ /** Read-only mount. Default: false. */
147
+ readOnly?: boolean;
148
+ }
149
+ /**
150
+ * Sandbox configuration for apps that require a per-user container.
151
+ * When present on an app manifest, installing the app triggers sandbox
152
+ * provisioning via `os.sandbox.create`.
153
+ */
154
+ interface SandboxConfig {
155
+ /** Enable sandbox provisioning on install. */
156
+ enabled: boolean;
157
+ /** Base container image (e.g., "khal-os/sandbox-ubuntu:latest"). */
158
+ image?: string;
159
+ /** Resource requests for the sandbox pod. */
160
+ requests?: SandboxResourceSpec;
161
+ /** Resource limits for the sandbox pod (burstable). */
162
+ limits?: SandboxResourceSpec;
163
+ /** Volume mounts inside the sandbox. */
164
+ mounts?: SandboxMount[];
165
+ /** Whether the sandbox user gets sudo access. Default: true. */
166
+ sudoers?: boolean;
167
+ /** NATS subject prefix for sandbox communication (default: "os.sandbox"). */
168
+ natsPrefix?: string;
169
+ }
131
170
  /** Tauri standalone export configuration. */
132
171
  interface AppTauriConfig {
133
172
  /** Whether this app supports standalone Tauri export. */
@@ -187,6 +226,8 @@ interface AppManifest {
187
226
  tauri?: AppTauriConfig;
188
227
  /** URL to the app's pre-built ESM bundle for runtime loading by desktop. */
189
228
  bundleUrl?: string;
229
+ /** Sandbox configuration — when present, installing this app provisions a per-user container. */
230
+ sandbox?: SandboxConfig;
190
231
  }
191
232
  declare const KhalPermission: z.ZodEnum<{
192
233
  "nats:publish": "nats:publish";
@@ -295,6 +336,29 @@ declare const KhalAppManifestSchema: z.ZodObject<{
295
336
  ports: z.ZodArray<z.ZodNumber>;
296
337
  }, z.core.$strip>>;
297
338
  bundlePath: z.ZodOptional<z.ZodString>;
339
+ sandbox: z.ZodOptional<z.ZodObject<{
340
+ enabled: z.ZodBoolean;
341
+ image: z.ZodOptional<z.ZodString>;
342
+ requests: z.ZodOptional<z.ZodObject<{
343
+ cpu: z.ZodString;
344
+ memory: z.ZodString;
345
+ }, z.core.$strip>>;
346
+ limits: z.ZodOptional<z.ZodObject<{
347
+ cpu: z.ZodString;
348
+ memory: z.ZodString;
349
+ }, z.core.$strip>>;
350
+ mounts: z.ZodOptional<z.ZodArray<z.ZodObject<{
351
+ mountPath: z.ZodString;
352
+ source: z.ZodEnum<{
353
+ files: "files";
354
+ pvc: "pvc";
355
+ }>;
356
+ pvcName: z.ZodOptional<z.ZodString>;
357
+ readOnly: z.ZodOptional<z.ZodBoolean>;
358
+ }, z.core.$strip>>>;
359
+ sudoers: z.ZodOptional<z.ZodBoolean>;
360
+ natsPrefix: z.ZodOptional<z.ZodString>;
361
+ }, z.core.$strip>>;
298
362
  apps: z.ZodOptional<z.ZodArray<z.ZodObject<{
299
363
  id: z.ZodString;
300
364
  name: z.ZodString;
@@ -310,4 +374,4 @@ declare function validateManifest(raw: unknown): KhalAppManifest;
310
374
  /** Connection states reported by the WS relay. */
311
375
  type ConnectionState = 'connected' | 'reconnecting' | 'disconnected' | 'auth_expired' | 'version_mismatch';
312
376
 
313
- export { type AppDeployConfig, type AppDesktopConfig, type AppEnvVar, type AppManifest, type AppManifestView, type AppServiceConfig, type AppTauriConfig, type ConnectionState, type KhalAppEntry, KhalAppEntrySchema, type KhalAppManifest, KhalAppManifestSchema, type KhalAuth, KhalPermission, KhalServiceSpec, KhalWindowSpec, ROLE_HIERARCHY, type Role, type ServiceHealthConfig, validateManifest };
377
+ export { type AppDeployConfig, type AppDesktopConfig, type AppEnvVar, type AppManifest, type AppManifestView, type AppServiceConfig, type AppTauriConfig, type ConnectionState, type KhalAppEntry, KhalAppEntrySchema, type KhalAppManifest, KhalAppManifestSchema, type KhalAuth, KhalPermission, KhalServiceSpec, KhalWindowSpec, ROLE_HIERARCHY, type Role, type SandboxConfig, type SandboxMount, type SandboxResourceSpec, type ServiceHealthConfig, validateManifest };
package/dist/index.js CHANGED
@@ -63,6 +63,23 @@ var KhalAppManifestSchema = z.object({
63
63
  }).optional(),
64
64
  /** Relative path to the pre-built ESM bundle within the package (e.g., "dist/bundle.mjs"). */
65
65
  bundlePath: z.string().optional(),
66
+ /** Sandbox configuration for per-user container provisioning. */
67
+ sandbox: z.object({
68
+ enabled: z.boolean(),
69
+ image: z.string().optional(),
70
+ requests: z.object({ cpu: z.string(), memory: z.string() }).optional(),
71
+ limits: z.object({ cpu: z.string(), memory: z.string() }).optional(),
72
+ mounts: z.array(
73
+ z.object({
74
+ mountPath: z.string(),
75
+ source: z.enum(["files", "pvc"]),
76
+ pvcName: z.string().optional(),
77
+ readOnly: z.boolean().optional()
78
+ })
79
+ ).optional(),
80
+ sudoers: z.boolean().optional(),
81
+ natsPrefix: z.string().optional()
82
+ }).optional(),
66
83
  /**
67
84
  * When apps is present, the root frontend field is ignored —
68
85
  * each entry has its own frontend.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/manifest.ts","../src/roles.ts"],"sourcesContent":["import { z } from 'zod';\nimport type { Role } from './roles';\n\n/** Desktop integration metadata for an app. */\nexport interface AppDesktopConfig {\n\t/** Path to the app icon (relative to the public directory). */\n\ticon: string;\n\t/** Categories for desktop launcher grouping. */\n\tcategories: string[];\n\t/** Short description shown in the desktop launcher. */\n\tcomment: string;\n}\n\n/** A single view within an app manifest. */\nexport interface AppManifestView {\n\t/** Unique view identifier within the app. */\n\tid: string;\n\t/** Human-readable label for the view. */\n\tlabel: string;\n\t/** Permission string required to access this view. */\n\tpermission: string;\n\t/** Minimum role level required. */\n\tminRole: Role;\n\t/** NATS subject segment after `khal.<orgId>.` for this view's services. */\n\tnatsPrefix?: string;\n\t/** Default window dimensions. */\n\tdefaultSize: { width: number; height: number };\n\t/** Relative path to the view's React component. */\n\tcomponent: string;\n}\n\n/** Health check configuration for a service. */\nexport interface ServiceHealthConfig {\n\t/** Check type: tcp (connect to port), http (GET endpoint), command (run shell). */\n\ttype: 'tcp' | 'http' | 'command';\n\t/** Target: port number for tcp, URL for http, shell command for command. */\n\ttarget: string | number;\n\t/** Check interval in milliseconds (default: 30000). */\n\tinterval?: number;\n\t/** Timeout in milliseconds (default: 5000). */\n\ttimeout?: number;\n}\n\n/** Service declaration within an app manifest. */\nexport interface AppServiceConfig {\n\t/** Service name (must be unique across the app). */\n\tname: string;\n\t/** Shell command to start the service (alternative to entry). */\n\tcommand?: string;\n\t/** Entry point file path relative to the package root. */\n\tentry?: string;\n\t/** Runtime environment. */\n\truntime?: 'node' | 'python';\n\t/** Health check configuration. */\n\thealth?: ServiceHealthConfig;\n\t/** Restart policy. */\n\trestart?: 'always' | 'on-failure' | 'never';\n\t/** Ports the service binds to internally. Khal assigns proxy ports. */\n\tports?: number[];\n}\n\n/** Environment variable declaration for app configuration. */\nexport interface AppEnvVar {\n\t/** Variable name (e.g., \"API_KEY\"). */\n\tkey: string;\n\t/** Human-readable description shown in the config UI. */\n\tdescription: string;\n\t/** Whether the variable is required for the app to run. */\n\trequired: boolean;\n\t/** Default value if not configured. */\n\tdefault?: string;\n\t/** Value type — affects config UI rendering and validation. */\n\ttype?: 'string' | 'number' | 'boolean' | 'secret' | 'url';\n\t/** Storage: 'config' for plain ConfigMap, 'vault' for Kubernetes Secret. */\n\tvisibility?: 'config' | 'vault';\n}\n\n/** Kubernetes deployment configuration for apps with backends. */\nexport interface AppDeployConfig {\n\t/** Dockerfile path relative to app root (default: \"Dockerfile\"). */\n\tdockerfile?: string;\n\t/** Build args passed to docker build. */\n\tbuildArgs?: Record<string, string>;\n\t/** Container port the app listens on. */\n\tport?: number;\n\t/** Resource requests and limits for the pod. */\n\tresources?: {\n\t\trequests?: { cpu?: string; memory?: string };\n\t\tlimits?: { cpu?: string; memory?: string };\n\t};\n\t/** Replica count (default: 1). */\n\treplicas?: number;\n\t/** Health check path for k8s readiness/liveness probes. */\n\thealthPath?: string;\n\t/** Ingress configuration for per-app routing. */\n\tingress?: {\n\t\t/** Subdomain prefix: <value>.apps.<domain>. Defaults to app id. */\n\t\tsubdomain?: string;\n\t\t/** Additional path prefixes to route to this app. */\n\t\tpathPrefixes?: string[];\n\t};\n\t/** Horizontal Pod Autoscaler configuration. */\n\tautoscaling?: {\n\t\tenabled: boolean;\n\t\tminReplicas?: number;\n\t\tmaxReplicas?: number;\n\t\ttargetCPU?: number;\n\t};\n\t/** Environment sources injected at runtime from k8s resources. */\n\tenvFrom?: Array<{ secretRef?: string; configMapRef?: string }>;\n}\n\n/** Tauri standalone export configuration. */\nexport interface AppTauriConfig {\n\t/** Whether this app supports standalone Tauri export. */\n\texportable: boolean;\n\t/** Path to src-tauri/ directory (default: \"./src-tauri\"). */\n\ttauriDir?: string;\n\t/** App name for the exported binary. */\n\tappName?: string;\n\t/** App icon path relative to app root. */\n\ticon?: string;\n\t/** Window configuration for standalone mode. */\n\twindow?: { width?: number; height?: number; title?: string };\n}\n\n/**\n * Full app manifest — the type for `manifest.ts` files in KhalOS app packages.\n *\n * Every app package must export a default manifest conforming to this shape.\n * Use `defineManifest()` for compile-time validation and autocomplete.\n *\n * The JSON equivalent (`khal-app.json`) uses the same shape and is the\n * language-agnostic install-time contract that the marketplace reads.\n */\nexport interface AppManifest {\n\t/** Unique app identifier (must match the package directory name). */\n\tid: string;\n\t/** One or more views the app exposes. */\n\tviews: AppManifestView[];\n\t/** Desktop integration configuration. */\n\tdesktop: AppDesktopConfig;\n\t/** Backend services this app runs. Optional — pure UI apps have no services. */\n\tservices?: AppServiceConfig[];\n\n\t// ── v2 fields (all optional for backward compatibility) ──\n\n\t/** Schema version for forward compatibility (default: 1). */\n\tschemaVersion?: number;\n\t/** Human-readable app name. */\n\tname?: string;\n\t/** Semantic version of the app. */\n\tversion?: string;\n\t/** Short description for the marketplace listing. */\n\tdescription?: string;\n\t/** Author name or organization. */\n\tauthor?: string;\n\t/** SPDX license identifier. */\n\tlicense?: string;\n\t/** Source repository URL. */\n\trepository?: string;\n\t/** Minimum KhalOS host version required. */\n\tminHostVersion?: string;\n\t/** Environment variables the app needs — auto-generates config UI. */\n\tenv?: AppEnvVar[];\n\t/** Native Kubernetes deployment configuration. */\n\tdeploy?: AppDeployConfig;\n\t/** Tauri standalone export configuration. */\n\ttauri?: AppTauriConfig;\n\t/** URL to the app's pre-built ESM bundle for runtime loading by desktop. */\n\tbundleUrl?: string;\n}\n\n// ── Pack Contract Types (for standalone pack-* repos) ──\n\nexport const KhalPermission = z.enum([\n\t'nats:publish',\n\t'nats:subscribe',\n\t'files:read',\n\t'files:write',\n\t'pty:spawn',\n\t'http:fetch',\n\t'system:clipboard',\n\t'system:notifications',\n]);\nexport type KhalPermission = z.infer<typeof KhalPermission>;\n\nexport const KhalServiceSpec = z.object({\n\tname: z.string(),\n\tcommand: z.string().optional(),\n\tentry: z.string().optional(),\n\truntime: z.enum(['node', 'bun', 'python']).optional(),\n\tports: z.array(z.number()).optional(),\n\thealth: z\n\t\t.object({\n\t\t\ttype: z.enum(['tcp', 'http', 'command']),\n\t\t\ttarget: z.union([z.string(), z.number()]),\n\t\t\tinterval: z.number().optional(),\n\t\t\ttimeout: z.number().optional(),\n\t\t})\n\t\t.optional(),\n});\nexport type KhalServiceSpec = z.infer<typeof KhalServiceSpec>;\n\nexport const KhalWindowSpec = z.object({\n\tid: z.string(),\n\ttitle: z.string().optional(),\n\twidth: z.number().default(800),\n\theight: z.number().default(600),\n\tresizable: z.boolean().default(true),\n});\nexport type KhalWindowSpec = z.infer<typeof KhalWindowSpec>;\n\n/** A single app entry within a bundle pack manifest. */\nexport const KhalAppEntrySchema = z.object({\n\t/** Unique app identifier within the bundle. */\n\tid: z.string(),\n\t/** Human-readable app name. */\n\tname: z.string(),\n\t/** Frontend package reference for this app. */\n\tfrontend: z\n\t\t.object({\n\t\t\tpackage: z.string(),\n\t\t})\n\t\t.optional(),\n});\nexport type KhalAppEntry = z.infer<typeof KhalAppEntrySchema>;\n\nexport const KhalAppManifestSchema = z\n\t.object({\n\t\t$schema: z.string().optional(),\n\t\tid: z.string(),\n\t\tname: z.string(),\n\t\tversion: z.string(),\n\t\ticon: z.string(),\n\t\tdescription: z.string(),\n\t\tauthor: z.string(),\n\t\tpermissions: z.array(KhalPermission),\n\t\tservices: z.array(KhalServiceSpec).optional(),\n\t\twindows: z.array(KhalWindowSpec).optional(),\n\t\tfrontend: z\n\t\t\t.object({\n\t\t\t\tpackage: z.string(),\n\t\t\t\tentry: z.string().default('default'),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbackend: z\n\t\t\t.object({\n\t\t\t\timage: z.string(),\n\t\t\t\thelmChart: z.string().optional(),\n\t\t\t\tenv: z.record(z.string(), z.string()),\n\t\t\t\tports: z.array(z.number()),\n\t\t\t})\n\t\t\t.optional(),\n\t\t/** Relative path to the pre-built ESM bundle within the package (e.g., \"dist/bundle.mjs\"). */\n\t\tbundlePath: z.string().optional(),\n\t\t/**\n\t\t * When apps is present, the root frontend field is ignored —\n\t\t * each entry has its own frontend.\n\t\t */\n\t\tapps: z.array(KhalAppEntrySchema).optional(),\n\t})\n\t.strict();\n\nexport type KhalAppManifest = z.infer<typeof KhalAppManifestSchema>;\n\n/** Validate a raw object as KhalAppManifest. Throws ZodError with detailed messages on failure. */\nexport function validateManifest(raw: unknown): KhalAppManifest {\n\treturn KhalAppManifestSchema.parse(raw);\n}\n","/** Canonical role hierarchy from least to most privileged. */\nexport const ROLE_HIERARCHY = ['member', 'platform-dev', 'platform-admin', 'platform-owner'] as const;\nexport type Role = (typeof ROLE_HIERARCHY)[number];\n"],"mappings":";AAAA,SAAS,SAAS;AA+KX,IAAM,iBAAiB,EAAE,KAAK;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAGM,IAAM,kBAAkB,EAAE,OAAO;AAAA,EACvC,MAAM,EAAE,OAAO;AAAA,EACf,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,SAAS,EAAE,KAAK,CAAC,QAAQ,OAAO,QAAQ,CAAC,EAAE,SAAS;AAAA,EACpD,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACpC,QAAQ,EACN,OAAO;AAAA,IACP,MAAM,EAAE,KAAK,CAAC,OAAO,QAAQ,SAAS,CAAC;AAAA,IACvC,QAAQ,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC;AAAA,IACxC,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,CAAC,EACA,SAAS;AACZ,CAAC;AAGM,IAAM,iBAAiB,EAAE,OAAO;AAAA,EACtC,IAAI,EAAE,OAAO;AAAA,EACb,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,OAAO,EAAE,OAAO,EAAE,QAAQ,GAAG;AAAA,EAC7B,QAAQ,EAAE,OAAO,EAAE,QAAQ,GAAG;AAAA,EAC9B,WAAW,EAAE,QAAQ,EAAE,QAAQ,IAAI;AACpC,CAAC;AAIM,IAAM,qBAAqB,EAAE,OAAO;AAAA;AAAA,EAE1C,IAAI,EAAE,OAAO;AAAA;AAAA,EAEb,MAAM,EAAE,OAAO;AAAA;AAAA,EAEf,UAAU,EACR,OAAO;AAAA,IACP,SAAS,EAAE,OAAO;AAAA,EACnB,CAAC,EACA,SAAS;AACZ,CAAC;AAGM,IAAM,wBAAwB,EACnC,OAAO;AAAA,EACP,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,IAAI,EAAE,OAAO;AAAA,EACb,MAAM,EAAE,OAAO;AAAA,EACf,SAAS,EAAE,OAAO;AAAA,EAClB,MAAM,EAAE,OAAO;AAAA,EACf,aAAa,EAAE,OAAO;AAAA,EACtB,QAAQ,EAAE,OAAO;AAAA,EACjB,aAAa,EAAE,MAAM,cAAc;AAAA,EACnC,UAAU,EAAE,MAAM,eAAe,EAAE,SAAS;AAAA,EAC5C,SAAS,EAAE,MAAM,cAAc,EAAE,SAAS;AAAA,EAC1C,UAAU,EACR,OAAO;AAAA,IACP,SAAS,EAAE,OAAO;AAAA,IAClB,OAAO,EAAE,OAAO,EAAE,QAAQ,SAAS;AAAA,EACpC,CAAC,EACA,SAAS;AAAA,EACX,SAAS,EACP,OAAO;AAAA,IACP,OAAO,EAAE,OAAO;AAAA,IAChB,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC;AAAA,IACpC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EAC1B,CAAC,EACA,SAAS;AAAA;AAAA,EAEX,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhC,MAAM,EAAE,MAAM,kBAAkB,EAAE,SAAS;AAC5C,CAAC,EACA,OAAO;AAKF,SAAS,iBAAiB,KAA+B;AAC/D,SAAO,sBAAsB,MAAM,GAAG;AACvC;;;AC5QO,IAAM,iBAAiB,CAAC,UAAU,gBAAgB,kBAAkB,gBAAgB;","names":[]}
1
+ {"version":3,"sources":["../src/manifest.ts","../src/roles.ts"],"sourcesContent":["import { z } from 'zod';\nimport type { Role } from './roles';\n\n/** Desktop integration metadata for an app. */\nexport interface AppDesktopConfig {\n\t/** Path to the app icon (relative to the public directory). */\n\ticon: string;\n\t/** Categories for desktop launcher grouping. */\n\tcategories: string[];\n\t/** Short description shown in the desktop launcher. */\n\tcomment: string;\n}\n\n/** A single view within an app manifest. */\nexport interface AppManifestView {\n\t/** Unique view identifier within the app. */\n\tid: string;\n\t/** Human-readable label for the view. */\n\tlabel: string;\n\t/** Permission string required to access this view. */\n\tpermission: string;\n\t/** Minimum role level required. */\n\tminRole: Role;\n\t/** NATS subject segment after `khal.<orgId>.` for this view's services. */\n\tnatsPrefix?: string;\n\t/** Default window dimensions. */\n\tdefaultSize: { width: number; height: number };\n\t/** Relative path to the view's React component. */\n\tcomponent: string;\n}\n\n/** Health check configuration for a service. */\nexport interface ServiceHealthConfig {\n\t/** Check type: tcp (connect to port), http (GET endpoint), command (run shell). */\n\ttype: 'tcp' | 'http' | 'command';\n\t/** Target: port number for tcp, URL for http, shell command for command. */\n\ttarget: string | number;\n\t/** Check interval in milliseconds (default: 30000). */\n\tinterval?: number;\n\t/** Timeout in milliseconds (default: 5000). */\n\ttimeout?: number;\n}\n\n/** Service declaration within an app manifest. */\nexport interface AppServiceConfig {\n\t/** Service name (must be unique across the app). */\n\tname: string;\n\t/** Shell command to start the service (alternative to entry). */\n\tcommand?: string;\n\t/** Entry point file path relative to the package root. */\n\tentry?: string;\n\t/** Runtime environment. */\n\truntime?: 'node' | 'python';\n\t/** Health check configuration. */\n\thealth?: ServiceHealthConfig;\n\t/** Restart policy. */\n\trestart?: 'always' | 'on-failure' | 'never';\n\t/** Ports the service binds to internally. Khal assigns proxy ports. */\n\tports?: number[];\n}\n\n/** Environment variable declaration for app configuration. */\nexport interface AppEnvVar {\n\t/** Variable name (e.g., \"API_KEY\"). */\n\tkey: string;\n\t/** Human-readable description shown in the config UI. */\n\tdescription: string;\n\t/** Whether the variable is required for the app to run. */\n\trequired: boolean;\n\t/** Default value if not configured. */\n\tdefault?: string;\n\t/** Value type — affects config UI rendering and validation. */\n\ttype?: 'string' | 'number' | 'boolean' | 'secret' | 'url';\n\t/** Storage: 'config' for plain ConfigMap, 'vault' for Kubernetes Secret. */\n\tvisibility?: 'config' | 'vault';\n}\n\n/** Kubernetes deployment configuration for apps with backends. */\nexport interface AppDeployConfig {\n\t/** Dockerfile path relative to app root (default: \"Dockerfile\"). */\n\tdockerfile?: string;\n\t/** Build args passed to docker build. */\n\tbuildArgs?: Record<string, string>;\n\t/** Container port the app listens on. */\n\tport?: number;\n\t/** Resource requests and limits for the pod. */\n\tresources?: {\n\t\trequests?: { cpu?: string; memory?: string };\n\t\tlimits?: { cpu?: string; memory?: string };\n\t};\n\t/** Replica count (default: 1). */\n\treplicas?: number;\n\t/** Health check path for k8s readiness/liveness probes. */\n\thealthPath?: string;\n\t/** Ingress configuration for per-app routing. */\n\tingress?: {\n\t\t/** Subdomain prefix: <value>.apps.<domain>. Defaults to app id. */\n\t\tsubdomain?: string;\n\t\t/** Additional path prefixes to route to this app. */\n\t\tpathPrefixes?: string[];\n\t};\n\t/** Horizontal Pod Autoscaler configuration. */\n\tautoscaling?: {\n\t\tenabled: boolean;\n\t\tminReplicas?: number;\n\t\tmaxReplicas?: number;\n\t\ttargetCPU?: number;\n\t};\n\t/** Environment sources injected at runtime from k8s resources. */\n\tenvFrom?: Array<{ secretRef?: string; configMapRef?: string }>;\n}\n\n/** Sandbox resource specification for per-user container provisioning. */\nexport interface SandboxResourceSpec {\n\t/** CPU request (e.g., \"4\"). */\n\tcpu: string;\n\t/** Memory request (e.g., \"4Gi\"). */\n\tmemory: string;\n}\n\n/** Volume mount configuration for sandbox containers. */\nexport interface SandboxMount {\n\t/** Mount path inside the sandbox container. */\n\tmountPath: string;\n\t/** Source type: 'files' mounts user's Files PVC, 'pvc' mounts a named PVC. */\n\tsource: 'files' | 'pvc';\n\t/** PVC name (required when source is 'pvc'). */\n\tpvcName?: string;\n\t/** Read-only mount. Default: false. */\n\treadOnly?: boolean;\n}\n\n/**\n * Sandbox configuration for apps that require a per-user container.\n * When present on an app manifest, installing the app triggers sandbox\n * provisioning via `os.sandbox.create`.\n */\nexport interface SandboxConfig {\n\t/** Enable sandbox provisioning on install. */\n\tenabled: boolean;\n\t/** Base container image (e.g., \"khal-os/sandbox-ubuntu:latest\"). */\n\timage?: string;\n\t/** Resource requests for the sandbox pod. */\n\trequests?: SandboxResourceSpec;\n\t/** Resource limits for the sandbox pod (burstable). */\n\tlimits?: SandboxResourceSpec;\n\t/** Volume mounts inside the sandbox. */\n\tmounts?: SandboxMount[];\n\t/** Whether the sandbox user gets sudo access. Default: true. */\n\tsudoers?: boolean;\n\t/** NATS subject prefix for sandbox communication (default: \"os.sandbox\"). */\n\tnatsPrefix?: string;\n}\n\n/** Tauri standalone export configuration. */\nexport interface AppTauriConfig {\n\t/** Whether this app supports standalone Tauri export. */\n\texportable: boolean;\n\t/** Path to src-tauri/ directory (default: \"./src-tauri\"). */\n\ttauriDir?: string;\n\t/** App name for the exported binary. */\n\tappName?: string;\n\t/** App icon path relative to app root. */\n\ticon?: string;\n\t/** Window configuration for standalone mode. */\n\twindow?: { width?: number; height?: number; title?: string };\n}\n\n/**\n * Full app manifest — the type for `manifest.ts` files in KhalOS app packages.\n *\n * Every app package must export a default manifest conforming to this shape.\n * Use `defineManifest()` for compile-time validation and autocomplete.\n *\n * The JSON equivalent (`khal-app.json`) uses the same shape and is the\n * language-agnostic install-time contract that the marketplace reads.\n */\nexport interface AppManifest {\n\t/** Unique app identifier (must match the package directory name). */\n\tid: string;\n\t/** One or more views the app exposes. */\n\tviews: AppManifestView[];\n\t/** Desktop integration configuration. */\n\tdesktop: AppDesktopConfig;\n\t/** Backend services this app runs. Optional — pure UI apps have no services. */\n\tservices?: AppServiceConfig[];\n\n\t// ── v2 fields (all optional for backward compatibility) ──\n\n\t/** Schema version for forward compatibility (default: 1). */\n\tschemaVersion?: number;\n\t/** Human-readable app name. */\n\tname?: string;\n\t/** Semantic version of the app. */\n\tversion?: string;\n\t/** Short description for the marketplace listing. */\n\tdescription?: string;\n\t/** Author name or organization. */\n\tauthor?: string;\n\t/** SPDX license identifier. */\n\tlicense?: string;\n\t/** Source repository URL. */\n\trepository?: string;\n\t/** Minimum KhalOS host version required. */\n\tminHostVersion?: string;\n\t/** Environment variables the app needs — auto-generates config UI. */\n\tenv?: AppEnvVar[];\n\t/** Native Kubernetes deployment configuration. */\n\tdeploy?: AppDeployConfig;\n\t/** Tauri standalone export configuration. */\n\ttauri?: AppTauriConfig;\n\t/** URL to the app's pre-built ESM bundle for runtime loading by desktop. */\n\tbundleUrl?: string;\n\t/** Sandbox configuration — when present, installing this app provisions a per-user container. */\n\tsandbox?: SandboxConfig;\n}\n\n// ── Pack Contract Types (for standalone pack-* repos) ──\n\nexport const KhalPermission = z.enum([\n\t'nats:publish',\n\t'nats:subscribe',\n\t'files:read',\n\t'files:write',\n\t'pty:spawn',\n\t'http:fetch',\n\t'system:clipboard',\n\t'system:notifications',\n]);\nexport type KhalPermission = z.infer<typeof KhalPermission>;\n\nexport const KhalServiceSpec = z.object({\n\tname: z.string(),\n\tcommand: z.string().optional(),\n\tentry: z.string().optional(),\n\truntime: z.enum(['node', 'bun', 'python']).optional(),\n\tports: z.array(z.number()).optional(),\n\thealth: z\n\t\t.object({\n\t\t\ttype: z.enum(['tcp', 'http', 'command']),\n\t\t\ttarget: z.union([z.string(), z.number()]),\n\t\t\tinterval: z.number().optional(),\n\t\t\ttimeout: z.number().optional(),\n\t\t})\n\t\t.optional(),\n});\nexport type KhalServiceSpec = z.infer<typeof KhalServiceSpec>;\n\nexport const KhalWindowSpec = z.object({\n\tid: z.string(),\n\ttitle: z.string().optional(),\n\twidth: z.number().default(800),\n\theight: z.number().default(600),\n\tresizable: z.boolean().default(true),\n});\nexport type KhalWindowSpec = z.infer<typeof KhalWindowSpec>;\n\n/** A single app entry within a bundle pack manifest. */\nexport const KhalAppEntrySchema = z.object({\n\t/** Unique app identifier within the bundle. */\n\tid: z.string(),\n\t/** Human-readable app name. */\n\tname: z.string(),\n\t/** Frontend package reference for this app. */\n\tfrontend: z\n\t\t.object({\n\t\t\tpackage: z.string(),\n\t\t})\n\t\t.optional(),\n});\nexport type KhalAppEntry = z.infer<typeof KhalAppEntrySchema>;\n\nexport const KhalAppManifestSchema = z\n\t.object({\n\t\t$schema: z.string().optional(),\n\t\tid: z.string(),\n\t\tname: z.string(),\n\t\tversion: z.string(),\n\t\ticon: z.string(),\n\t\tdescription: z.string(),\n\t\tauthor: z.string(),\n\t\tpermissions: z.array(KhalPermission),\n\t\tservices: z.array(KhalServiceSpec).optional(),\n\t\twindows: z.array(KhalWindowSpec).optional(),\n\t\tfrontend: z\n\t\t\t.object({\n\t\t\t\tpackage: z.string(),\n\t\t\t\tentry: z.string().default('default'),\n\t\t\t})\n\t\t\t.optional(),\n\t\tbackend: z\n\t\t\t.object({\n\t\t\t\timage: z.string(),\n\t\t\t\thelmChart: z.string().optional(),\n\t\t\t\tenv: z.record(z.string(), z.string()),\n\t\t\t\tports: z.array(z.number()),\n\t\t\t})\n\t\t\t.optional(),\n\t\t/** Relative path to the pre-built ESM bundle within the package (e.g., \"dist/bundle.mjs\"). */\n\t\tbundlePath: z.string().optional(),\n\t\t/** Sandbox configuration for per-user container provisioning. */\n\t\tsandbox: z\n\t\t\t.object({\n\t\t\t\tenabled: z.boolean(),\n\t\t\t\timage: z.string().optional(),\n\t\t\t\trequests: z\n\t\t\t\t\t.object({ cpu: z.string(), memory: z.string() })\n\t\t\t\t\t.optional(),\n\t\t\t\tlimits: z\n\t\t\t\t\t.object({ cpu: z.string(), memory: z.string() })\n\t\t\t\t\t.optional(),\n\t\t\t\tmounts: z\n\t\t\t\t\t.array(\n\t\t\t\t\t\tz.object({\n\t\t\t\t\t\t\tmountPath: z.string(),\n\t\t\t\t\t\t\tsource: z.enum(['files', 'pvc']),\n\t\t\t\t\t\t\tpvcName: z.string().optional(),\n\t\t\t\t\t\t\treadOnly: z.boolean().optional(),\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\t.optional(),\n\t\t\t\tsudoers: z.boolean().optional(),\n\t\t\t\tnatsPrefix: z.string().optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t\t/**\n\t\t * When apps is present, the root frontend field is ignored —\n\t\t * each entry has its own frontend.\n\t\t */\n\t\tapps: z.array(KhalAppEntrySchema).optional(),\n\t})\n\t.strict();\n\nexport type KhalAppManifest = z.infer<typeof KhalAppManifestSchema>;\n\n/** Validate a raw object as KhalAppManifest. Throws ZodError with detailed messages on failure. */\nexport function validateManifest(raw: unknown): KhalAppManifest {\n\treturn KhalAppManifestSchema.parse(raw);\n}\n","/** Canonical role hierarchy from least to most privileged. */\nexport const ROLE_HIERARCHY = ['member', 'platform-dev', 'platform-admin', 'platform-owner'] as const;\nexport type Role = (typeof ROLE_HIERARCHY)[number];\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khal-os/types",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "main": "./dist/index.cjs",