@kb-labs/shared 1.1.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/.cursorrules +32 -0
- package/.github/workflows/ci.yml +13 -0
- package/.github/workflows/deploy.yml +28 -0
- package/.github/workflows/docker-build.yml +25 -0
- package/.github/workflows/drift-check.yml +10 -0
- package/.github/workflows/profiles-validate.yml +16 -0
- package/.github/workflows/release.yml +8 -0
- package/.kb/devkit/agents/devkit-maintainer/context.globs +15 -0
- package/.kb/devkit/agents/devkit-maintainer/permissions.yml +17 -0
- package/.kb/devkit/agents/devkit-maintainer/prompt.md +28 -0
- package/.kb/devkit/agents/devkit-maintainer/runbook.md +31 -0
- package/.kb/devkit/agents/docs-crafter/prompt.md +24 -0
- package/.kb/devkit/agents/docs-crafter/runbook.md +18 -0
- package/.kb/devkit/agents/release-manager/context.globs +7 -0
- package/.kb/devkit/agents/release-manager/prompt.md +27 -0
- package/.kb/devkit/agents/release-manager/runbook.md +17 -0
- package/.kb/devkit/agents/test-generator/context.globs +7 -0
- package/.kb/devkit/agents/test-generator/prompt.md +27 -0
- package/.kb/devkit/agents/test-generator/runbook.md +18 -0
- package/.vscode/settings.json +23 -0
- package/CHANGELOG.md +33 -0
- package/CONTRIBUTING.md +117 -0
- package/LICENSE +21 -0
- package/README.md +306 -0
- package/docs/DECLARATIVE-FLAGS-AND-ENV.md +622 -0
- package/docs/DOCUMENTATION.md +70 -0
- package/docs/adr/0000-template.md +52 -0
- package/docs/adr/0001-architecture-and-repository-layout.md +31 -0
- package/docs/adr/0002-plugins-and-extensibility.md +44 -0
- package/docs/adr/0003-package-and-module-boundaries.md +35 -0
- package/docs/adr/0004-versioning-and-release-policy.md +36 -0
- package/docs/adr/0005-reactive-loader-pattern.md +179 -0
- package/docs/adr/0006-declarative-flags-and-env-systems.md +376 -0
- package/eslint.config.js +27 -0
- package/kb-labs.config.json +5 -0
- package/package.json +88 -0
- package/package.json.bin +25 -0
- package/package.json.lib +30 -0
- package/packages/shared-cli-ui/CHANGELOG.md +20 -0
- package/packages/shared-cli-ui/README.md +342 -0
- package/packages/shared-cli-ui/docs/ARCHITECTURE.md +105 -0
- package/packages/shared-cli-ui/eslint.config.js +27 -0
- package/packages/shared-cli-ui/package.json +72 -0
- package/packages/shared-cli-ui/src/__tests__/artifacts-display.spec.ts +89 -0
- package/packages/shared-cli-ui/src/__tests__/format.spec.ts +44 -0
- package/packages/shared-cli-ui/src/__tests__/loader-json-mode.test.ts +119 -0
- package/packages/shared-cli-ui/src/artifacts-display.ts +266 -0
- package/packages/shared-cli-ui/src/cli-auto-discovery.ts +120 -0
- package/packages/shared-cli-ui/src/colors.ts +142 -0
- package/packages/shared-cli-ui/src/command-discovery.ts +72 -0
- package/packages/shared-cli-ui/src/command-output.ts +153 -0
- package/packages/shared-cli-ui/src/command-result.ts +267 -0
- package/packages/shared-cli-ui/src/command-runner.ts +310 -0
- package/packages/shared-cli-ui/src/command-suggestions.ts +204 -0
- package/packages/shared-cli-ui/src/debug/components/output.ts +141 -0
- package/packages/shared-cli-ui/src/debug/components/trace.ts +101 -0
- package/packages/shared-cli-ui/src/debug/components/tree.ts +88 -0
- package/packages/shared-cli-ui/src/debug/formatters/ai.ts +17 -0
- package/packages/shared-cli-ui/src/debug/formatters/human.ts +98 -0
- package/packages/shared-cli-ui/src/debug/formatters/timeline.ts +94 -0
- package/packages/shared-cli-ui/src/debug/index.ts +56 -0
- package/packages/shared-cli-ui/src/debug/types.ts +57 -0
- package/packages/shared-cli-ui/src/debug/utilities.ts +203 -0
- package/packages/shared-cli-ui/src/dynamic-command-discovery.ts +131 -0
- package/packages/shared-cli-ui/src/format.ts +412 -0
- package/packages/shared-cli-ui/src/index.ts +34 -0
- package/packages/shared-cli-ui/src/loader.ts +196 -0
- package/packages/shared-cli-ui/src/manifest-parser.ts +151 -0
- package/packages/shared-cli-ui/src/modern-format.ts +271 -0
- package/packages/shared-cli-ui/src/multi-cli-suggestions.ts +159 -0
- package/packages/shared-cli-ui/src/table.ts +134 -0
- package/packages/shared-cli-ui/src/timing-tracker.ts +68 -0
- package/packages/shared-cli-ui/src/utils/context.ts +12 -0
- package/packages/shared-cli-ui/src/utils/env.ts +164 -0
- package/packages/shared-cli-ui/src/utils/flags.ts +269 -0
- package/packages/shared-cli-ui/src/utils/path.ts +8 -0
- package/packages/shared-cli-ui/tsconfig.build.json +15 -0
- package/packages/shared-cli-ui/tsconfig.json +9 -0
- package/packages/shared-cli-ui/tsup.config.ts +11 -0
- package/packages/shared-cli-ui/vitest.config.ts +15 -0
- package/packages/shared-command-kit/CHANGELOG.md +20 -0
- package/packages/shared-command-kit/LICENSE +22 -0
- package/packages/shared-command-kit/README.md +1030 -0
- package/packages/shared-command-kit/docs/HIGH-LEVEL-API.md +89 -0
- package/packages/shared-command-kit/docs/LOW-LEVEL-API.md +105 -0
- package/packages/shared-command-kit/docs/MIGRATION-GUIDE.md +135 -0
- package/packages/shared-command-kit/eslint.config.js +27 -0
- package/packages/shared-command-kit/eslint.config.ts +14 -0
- package/packages/shared-command-kit/package.json +76 -0
- package/packages/shared-command-kit/prettierrc.json +5 -0
- package/packages/shared-command-kit/src/__tests__/define-command.spec.ts +294 -0
- package/packages/shared-command-kit/src/__tests__/define-route.test.ts +285 -0
- package/packages/shared-command-kit/src/__tests__/define-system-command.spec.ts +508 -0
- package/packages/shared-command-kit/src/__tests__/define-webhook.test.ts +156 -0
- package/packages/shared-command-kit/src/__tests__/define-websocket.test.ts +316 -0
- package/packages/shared-command-kit/src/__tests__/errors.spec.ts +45 -0
- package/packages/shared-command-kit/src/__tests__/flags.spec.ts +353 -0
- package/packages/shared-command-kit/src/__tests__/platform-api.test.ts +135 -0
- package/packages/shared-command-kit/src/__tests__/plugin-context-v3.snapshot.spec.ts +240 -0
- package/packages/shared-command-kit/src/__tests__/ws-types.test.ts +359 -0
- package/packages/shared-command-kit/src/analytics/index.ts +6 -0
- package/packages/shared-command-kit/src/analytics/with-analytics.ts +195 -0
- package/packages/shared-command-kit/src/define-action.ts +100 -0
- package/packages/shared-command-kit/src/define-command.ts +113 -0
- package/packages/shared-command-kit/src/define-route.ts +113 -0
- package/packages/shared-command-kit/src/define-system-command.ts +362 -0
- package/packages/shared-command-kit/src/define-webhook.ts +115 -0
- package/packages/shared-command-kit/src/define-websocket.ts +308 -0
- package/packages/shared-command-kit/src/errors/factory.ts +282 -0
- package/packages/shared-command-kit/src/errors/format-validation.ts +144 -0
- package/packages/shared-command-kit/src/errors/format.ts +92 -0
- package/packages/shared-command-kit/src/errors/index.ts +9 -0
- package/packages/shared-command-kit/src/errors/types.ts +32 -0
- package/packages/shared-command-kit/src/flags/define.ts +92 -0
- package/packages/shared-command-kit/src/flags/index.ts +9 -0
- package/packages/shared-command-kit/src/flags/types.ts +153 -0
- package/packages/shared-command-kit/src/flags/validate.ts +358 -0
- package/packages/shared-command-kit/src/helpers/context.ts +8 -0
- package/packages/shared-command-kit/src/helpers/flags.ts +84 -0
- package/packages/shared-command-kit/src/helpers/index.ts +42 -0
- package/packages/shared-command-kit/src/helpers/patterns.ts +464 -0
- package/packages/shared-command-kit/src/helpers/platform.ts +335 -0
- package/packages/shared-command-kit/src/helpers/use-analytics.ts +95 -0
- package/packages/shared-command-kit/src/helpers/use-cache.ts +97 -0
- package/packages/shared-command-kit/src/helpers/use-config.ts +99 -0
- package/packages/shared-command-kit/src/helpers/use-embeddings.ts +49 -0
- package/packages/shared-command-kit/src/helpers/use-llm.ts +316 -0
- package/packages/shared-command-kit/src/helpers/use-logger.ts +77 -0
- package/packages/shared-command-kit/src/helpers/use-platform.ts +111 -0
- package/packages/shared-command-kit/src/helpers/use-resource-broker.ts +106 -0
- package/packages/shared-command-kit/src/helpers/use-storage.ts +71 -0
- package/packages/shared-command-kit/src/helpers/use-vector-store.ts +49 -0
- package/packages/shared-command-kit/src/helpers/validation.ts +398 -0
- package/packages/shared-command-kit/src/index.ts +410 -0
- package/packages/shared-command-kit/src/jobs.ts +132 -0
- package/packages/shared-command-kit/src/lifecycle/define-handlers.ts +366 -0
- package/packages/shared-command-kit/src/lifecycle/index.ts +6 -0
- package/packages/shared-command-kit/src/manifest.ts +127 -0
- package/packages/shared-command-kit/src/rest/define-handler.ts +187 -0
- package/packages/shared-command-kit/src/rest/index.ts +11 -0
- package/packages/shared-command-kit/src/studio/index.ts +12 -0
- package/packages/shared-command-kit/src/validation/index.ts +6 -0
- package/packages/shared-command-kit/src/validation/schema-builders.ts +409 -0
- package/packages/shared-command-kit/src/ws-types.ts +106 -0
- package/packages/shared-command-kit/tsconfig.build.json +15 -0
- package/packages/shared-command-kit/tsconfig.json +9 -0
- package/packages/shared-command-kit/tsup.config.ts +30 -0
- package/packages/shared-command-kit/vitest.config.ts +4 -0
- package/packages/shared-http/package.json +67 -0
- package/packages/shared-http/src/__tests__/log-correlation.test.ts +81 -0
- package/packages/shared-http/src/__tests__/operation-metrics-tracker.test.ts +55 -0
- package/packages/shared-http/src/http-observability-collector.ts +363 -0
- package/packages/shared-http/src/index.ts +36 -0
- package/packages/shared-http/src/log-correlation.ts +89 -0
- package/packages/shared-http/src/operation-metrics-tracker.ts +107 -0
- package/packages/shared-http/src/register-openapi.ts +108 -0
- package/packages/shared-http/src/resolve-schema-ref.ts +75 -0
- package/packages/shared-http/src/schemas.ts +29 -0
- package/packages/shared-http/src/service-observability.ts +63 -0
- package/packages/shared-http/tsconfig.build.json +15 -0
- package/packages/shared-http/tsconfig.json +9 -0
- package/packages/shared-http/tsup.config.ts +23 -0
- package/packages/shared-http/vitest.config.ts +13 -0
- package/packages/shared-perm-presets/CHANGELOG.md +20 -0
- package/packages/shared-perm-presets/README.md +78 -0
- package/packages/shared-perm-presets/eslint.config.js +27 -0
- package/packages/shared-perm-presets/package.json +45 -0
- package/packages/shared-perm-presets/src/__tests__/combine.test.ts +403 -0
- package/packages/shared-perm-presets/src/__tests__/presets.test.ts +205 -0
- package/packages/shared-perm-presets/src/combine.ts +278 -0
- package/packages/shared-perm-presets/src/index.ts +18 -0
- package/packages/shared-perm-presets/src/presets/ci-environment.ts +34 -0
- package/packages/shared-perm-presets/src/presets/full-env.ts +16 -0
- package/packages/shared-perm-presets/src/presets/git-workflow.ts +40 -0
- package/packages/shared-perm-presets/src/presets/index.ts +8 -0
- package/packages/shared-perm-presets/src/presets/kb-platform.ts +30 -0
- package/packages/shared-perm-presets/src/presets/llm-access.ts +29 -0
- package/packages/shared-perm-presets/src/presets/minimal.ts +21 -0
- package/packages/shared-perm-presets/src/presets/npm-publish.ts +48 -0
- package/packages/shared-perm-presets/src/presets/vector-store.ts +40 -0
- package/packages/shared-perm-presets/src/types.ts +192 -0
- package/packages/shared-perm-presets/tsconfig.build.json +15 -0
- package/packages/shared-perm-presets/tsconfig.json +9 -0
- package/packages/shared-perm-presets/tsup.config.ts +8 -0
- package/packages/shared-perm-presets/vitest.config.ts +9 -0
- package/packages/shared-testing/CHANGELOG.md +20 -0
- package/packages/shared-testing/README.md +430 -0
- package/packages/shared-testing/package.json +51 -0
- package/packages/shared-testing/src/__tests__/create-test-context.test.ts +199 -0
- package/packages/shared-testing/src/__tests__/mock-cache.test.ts +174 -0
- package/packages/shared-testing/src/__tests__/mock-llm.test.ts +212 -0
- package/packages/shared-testing/src/__tests__/setup-platform.test.ts +90 -0
- package/packages/shared-testing/src/__tests__/test-command.test.ts +557 -0
- package/packages/shared-testing/src/create-test-context.ts +550 -0
- package/packages/shared-testing/src/index.ts +77 -0
- package/packages/shared-testing/src/mock-cache.ts +179 -0
- package/packages/shared-testing/src/mock-llm.ts +319 -0
- package/packages/shared-testing/src/mock-logger.ts +97 -0
- package/packages/shared-testing/src/mock-storage.ts +108 -0
- package/packages/shared-testing/src/setup-platform.ts +101 -0
- package/packages/shared-testing/src/test-command.ts +288 -0
- package/packages/shared-testing/tsconfig.build.json +15 -0
- package/packages/shared-testing/tsconfig.json +9 -0
- package/packages/shared-testing/tsup.config.ts +20 -0
- package/packages/shared-testing/vitest.config.ts +3 -0
- package/packages/shared-tool-kit/CHANGELOG.md +20 -0
- package/packages/shared-tool-kit/package.json +47 -0
- package/packages/shared-tool-kit/src/__tests__/factory.test.ts +103 -0
- package/packages/shared-tool-kit/src/__tests__/mock-tool.test.ts +95 -0
- package/packages/shared-tool-kit/src/factory.ts +126 -0
- package/packages/shared-tool-kit/src/index.ts +32 -0
- package/packages/shared-tool-kit/src/testing/index.ts +84 -0
- package/packages/shared-tool-kit/tsconfig.build.json +15 -0
- package/packages/shared-tool-kit/tsconfig.json +9 -0
- package/packages/shared-tool-kit/tsup.config.ts +21 -0
- package/pnpm-workspace.yaml +11070 -0
- package/prettierrc.json +1 -0
- package/scripts/devkit-sync.mjs +37 -0
- package/scripts/hooks/post-push +9 -0
- package/scripts/hooks/pre-commit +9 -0
- package/scripts/hooks/pre-push +9 -0
- package/tsconfig.base.json +9 -0
- package/tsconfig.build.json +15 -0
- package/tsconfig.json +9 -0
- package/tsconfig.paths.json +50 -0
- package/tsconfig.tools.json +18 -0
- package/tsup.config.bin.ts +34 -0
- package/tsup.config.cli.ts +41 -0
- package/tsup.config.dual.ts +46 -0
- package/tsup.config.ts +36 -0
- package/tsup.external.json +104 -0
- package/vitest.config.ts +48 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/shared-command-kit/helpers/use-vector-store
|
|
3
|
+
* Global VectorStore access helper
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { usePlatform } from './use-platform';
|
|
7
|
+
import type { IVectorStore } from '@kb-labs/core-platform';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Access global VectorStore adapter
|
|
11
|
+
*
|
|
12
|
+
* Returns the platform vector store adapter (Qdrant, local, etc.).
|
|
13
|
+
* Returns undefined if vectorStore is not configured (graceful degradation).
|
|
14
|
+
*
|
|
15
|
+
* @returns VectorStore adapter or undefined if not configured
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const vectorStore = useVectorStore();
|
|
20
|
+
*
|
|
21
|
+
* if (vectorStore) {
|
|
22
|
+
* await vectorStore.upsert([{ id: '1', vector: [0.1, 0.2], metadata: {} }]);
|
|
23
|
+
* const results = await vectorStore.search([0.1, 0.2], 10);
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function useVectorStore(): IVectorStore | undefined {
|
|
28
|
+
const platform = usePlatform();
|
|
29
|
+
return platform.vectorStore;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Check if VectorStore is available
|
|
34
|
+
*
|
|
35
|
+
* @returns true if vectorStore is configured and ready
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* if (isVectorStoreAvailable()) {
|
|
40
|
+
* await vectorStore.upsert(records);
|
|
41
|
+
* } else {
|
|
42
|
+
* // Use local fallback
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function isVectorStoreAvailable(): boolean {
|
|
47
|
+
const vectorStore = useVectorStore();
|
|
48
|
+
return !!vectorStore;
|
|
49
|
+
}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/shared-command-kit/helpers/validation
|
|
3
|
+
* Validation helpers with common schemas and Zod integration.
|
|
4
|
+
*
|
|
5
|
+
* Provides ready-to-use validation schemas and helpers for common use cases.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Validation error with formatted message.
|
|
12
|
+
*/
|
|
13
|
+
export class ValidationError extends Error {
|
|
14
|
+
constructor(
|
|
15
|
+
message: string,
|
|
16
|
+
public readonly issues?: Array<{ path: string; message: string }>
|
|
17
|
+
) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'ValidationError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
24
|
+
// COMMON SCHEMAS
|
|
25
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Common validation schemas for reuse across plugins.
|
|
29
|
+
*/
|
|
30
|
+
export const schemas = {
|
|
31
|
+
/**
|
|
32
|
+
* NPM package name (scoped or unscoped).
|
|
33
|
+
* @example "@kb-labs/plugin-template", "lodash"
|
|
34
|
+
*/
|
|
35
|
+
packageName: z.string().regex(/^(@[\w-]+\/)?[\w-]+$/, 'Invalid package name'),
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Scoped NPM package name (must start with @).
|
|
39
|
+
* @example "@kb-labs/plugin-template"
|
|
40
|
+
*/
|
|
41
|
+
scopedPackageName: z.string().regex(/^@[\w-]+\/[\w-]+$/, 'Invalid scoped package name'),
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Semantic version (semver).
|
|
45
|
+
* @example "1.0.0", "2.1.3-beta.1"
|
|
46
|
+
*/
|
|
47
|
+
semver: z.string().regex(/^\d+\.\d+\.\d+(-[\w.]+)?$/, 'Invalid semver'),
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Email address.
|
|
51
|
+
*/
|
|
52
|
+
email: z.string().email('Invalid email address'),
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* HTTP/HTTPS URL.
|
|
56
|
+
*/
|
|
57
|
+
url: z.string().url('Invalid URL'),
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* GitHub repository URL.
|
|
61
|
+
* @example "https://github.com/owner/repo"
|
|
62
|
+
*/
|
|
63
|
+
githubUrl: z
|
|
64
|
+
.string()
|
|
65
|
+
.regex(/^https:\/\/github\.com\/[\w-]+\/[\w-]+$/, 'Invalid GitHub URL'),
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* File path (Unix-style).
|
|
69
|
+
* @example "src/index.ts", "path/to/file.json"
|
|
70
|
+
*/
|
|
71
|
+
filePath: z.string().regex(/^[\w\-./]+$/, 'Invalid file path'),
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Non-empty string (trimmed).
|
|
75
|
+
*/
|
|
76
|
+
nonEmptyString: z.string().trim().min(1, 'String cannot be empty'),
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Positive integer.
|
|
80
|
+
*/
|
|
81
|
+
positiveInt: z.number().int().positive('Must be positive integer'),
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Non-negative integer (including 0).
|
|
85
|
+
*/
|
|
86
|
+
nonNegativeInt: z.number().int().min(0, 'Must be non-negative integer'),
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Port number (1-65535).
|
|
90
|
+
*/
|
|
91
|
+
port: z.number().int().min(1).max(65535, 'Invalid port number'),
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* UUID v4.
|
|
95
|
+
*/
|
|
96
|
+
uuid: z.string().uuid('Invalid UUID'),
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* ISO 8601 date string.
|
|
100
|
+
* @example "2025-12-05T12:00:00Z"
|
|
101
|
+
*/
|
|
102
|
+
isoDate: z.string().datetime('Invalid ISO 8601 date'),
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* JSON string (can be parsed).
|
|
106
|
+
*/
|
|
107
|
+
jsonString: z.string().refine(
|
|
108
|
+
(val) => {
|
|
109
|
+
try {
|
|
110
|
+
JSON.parse(val);
|
|
111
|
+
return true;
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
{ message: 'Invalid JSON string' }
|
|
117
|
+
),
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Hexadecimal color code.
|
|
121
|
+
* @example "#FF5733", "#FFF"
|
|
122
|
+
*/
|
|
123
|
+
hexColor: z.string().regex(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/, 'Invalid hex color'),
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Tenant ID (alphanumeric, dash, underscore).
|
|
127
|
+
* @example "default", "acme-corp", "tenant_123"
|
|
128
|
+
*/
|
|
129
|
+
tenantId: z.string().regex(/^[\w-]+$/, 'Invalid tenant ID'),
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Plugin ID (scoped package name).
|
|
133
|
+
* @example "@kb-labs/plugin-template"
|
|
134
|
+
*/
|
|
135
|
+
pluginId: z.string().regex(/^@[\w-]+\/[\w-]+$/, 'Invalid plugin ID'),
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
139
|
+
// VALIDATION FUNCTIONS
|
|
140
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Format Zod error into readable message.
|
|
144
|
+
*/
|
|
145
|
+
function formatZodError(error: z.ZodError): string {
|
|
146
|
+
const issues = error.issues
|
|
147
|
+
.map((issue) => {
|
|
148
|
+
const path = issue.path.join('.');
|
|
149
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
150
|
+
})
|
|
151
|
+
.join('\n ');
|
|
152
|
+
|
|
153
|
+
return `Validation failed:\n ${issues}`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Validate data against a Zod schema.
|
|
158
|
+
* Throws ValidationError with formatted message on failure.
|
|
159
|
+
*
|
|
160
|
+
* @param schema - Zod schema
|
|
161
|
+
* @param data - Data to validate
|
|
162
|
+
* @returns Validated data (typed)
|
|
163
|
+
* @throws {ValidationError} If validation fails
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* const userSchema = z.object({
|
|
168
|
+
* name: z.string(),
|
|
169
|
+
* email: schemas.email,
|
|
170
|
+
* });
|
|
171
|
+
*
|
|
172
|
+
* const user = validateInput(userSchema, rawInput);
|
|
173
|
+
* // user is typed as { name: string; email: string }
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
export function validateInput<T>(schema: z.Schema<T>, data: unknown): T {
|
|
177
|
+
try {
|
|
178
|
+
return schema.parse(data);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
if (error instanceof z.ZodError) {
|
|
181
|
+
const issues = error.issues.map((issue) => ({
|
|
182
|
+
path: issue.path.join('.'),
|
|
183
|
+
message: issue.message,
|
|
184
|
+
}));
|
|
185
|
+
throw new ValidationError(formatZodError(error), issues);
|
|
186
|
+
}
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Safely validate data against a schema.
|
|
193
|
+
* Returns success/failure result instead of throwing.
|
|
194
|
+
*
|
|
195
|
+
* @param schema - Zod schema
|
|
196
|
+
* @param data - Data to validate
|
|
197
|
+
* @returns Validation result
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const result = safeValidate(schemas.email, input);
|
|
202
|
+
*
|
|
203
|
+
* if (result.success) {
|
|
204
|
+
* console.log('Valid email:', result.data);
|
|
205
|
+
* } else {
|
|
206
|
+
* console.error('Invalid:', result.error);
|
|
207
|
+
* }
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
export function safeValidate<T>(
|
|
211
|
+
schema: z.Schema<T>,
|
|
212
|
+
data: unknown
|
|
213
|
+
): { success: true; data: T } | { success: false; error: string; issues: Array<{ path: string; message: string }> } {
|
|
214
|
+
const result = schema.safeParse(data);
|
|
215
|
+
|
|
216
|
+
if (result.success) {
|
|
217
|
+
return { success: true, data: result.data };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const issues = result.error.issues.map((issue) => ({
|
|
221
|
+
path: issue.path.join('.'),
|
|
222
|
+
message: issue.message,
|
|
223
|
+
}));
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
success: false,
|
|
227
|
+
error: formatZodError(result.error),
|
|
228
|
+
issues,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Validate schema against data (general purpose).
|
|
234
|
+
* Use this for any data validation, not just flags.
|
|
235
|
+
*
|
|
236
|
+
* @param schema - Zod schema
|
|
237
|
+
* @param data - Data to validate
|
|
238
|
+
* @returns Validated data (typed)
|
|
239
|
+
* @throws {ValidationError} If validation fails
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* const configSchema = z.object({
|
|
244
|
+
* output: z.string().optional(),
|
|
245
|
+
* force: z.boolean().default(false),
|
|
246
|
+
* });
|
|
247
|
+
*
|
|
248
|
+
* const validConfig = validateSchema(configSchema, rawConfig);
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
export function validateSchema<T>(schema: z.Schema<T>, data: unknown): T {
|
|
252
|
+
try {
|
|
253
|
+
return validateInput(schema, data);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
if (error instanceof ValidationError) {
|
|
256
|
+
throw new ValidationError(`Validation failed: ${error.message}`, error.issues);
|
|
257
|
+
}
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Validate array of items against schema.
|
|
264
|
+
* Returns validated items and any errors.
|
|
265
|
+
*
|
|
266
|
+
* @param schema - Zod schema for single item
|
|
267
|
+
* @param items - Array of items
|
|
268
|
+
* @returns Validated items and errors
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* const { valid, invalid } = validateArray(schemas.email, emails);
|
|
273
|
+
*
|
|
274
|
+
* console.log(`${valid.length} valid, ${invalid.length} invalid`);
|
|
275
|
+
* for (const { index, error } of invalid) {
|
|
276
|
+
* console.error(`Item ${index}: ${error}`);
|
|
277
|
+
* }
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
export function validateArray<T>(
|
|
281
|
+
schema: z.Schema<T>,
|
|
282
|
+
items: unknown[]
|
|
283
|
+
): {
|
|
284
|
+
valid: T[];
|
|
285
|
+
invalid: Array<{ index: number; item: unknown; error: string }>;
|
|
286
|
+
} {
|
|
287
|
+
const valid: T[] = [];
|
|
288
|
+
const invalid: Array<{ index: number; item: unknown; error: string }> = [];
|
|
289
|
+
|
|
290
|
+
for (let i = 0; i < items.length; i++) {
|
|
291
|
+
const result = safeValidate(schema, items[i]);
|
|
292
|
+
if (result.success) {
|
|
293
|
+
valid.push(result.data);
|
|
294
|
+
} else {
|
|
295
|
+
invalid.push({ index: i, item: items[i], error: result.error });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return { valid, invalid };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
303
|
+
// CUSTOM VALIDATORS
|
|
304
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Check if value is a valid package name.
|
|
308
|
+
*/
|
|
309
|
+
export function isPackageName(value: unknown): value is string {
|
|
310
|
+
return schemas.packageName.safeParse(value).success;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Check if value is a valid semver.
|
|
315
|
+
*/
|
|
316
|
+
export function isSemver(value: unknown): value is string {
|
|
317
|
+
return schemas.semver.safeParse(value).success;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Check if value is a valid email.
|
|
322
|
+
*/
|
|
323
|
+
export function isEmail(value: unknown): value is string {
|
|
324
|
+
return schemas.email.safeParse(value).success;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Check if value is a valid URL.
|
|
329
|
+
*/
|
|
330
|
+
export function isUrl(value: unknown): value is string {
|
|
331
|
+
return schemas.url.safeParse(value).success;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Check if value is a valid UUID.
|
|
336
|
+
*/
|
|
337
|
+
export function isUUID(value: unknown): value is string {
|
|
338
|
+
return schemas.uuid.safeParse(value).success;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
342
|
+
// COMMON PATTERNS
|
|
343
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Create optional string field with default.
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```typescript
|
|
350
|
+
* const schema = z.object({
|
|
351
|
+
* format: optionalString('json'), // defaults to 'json' if not provided
|
|
352
|
+
* });
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
355
|
+
export function optionalString(defaultValue: string) {
|
|
356
|
+
return z.string().default(defaultValue);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Create optional boolean field with default.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```typescript
|
|
364
|
+
* const schema = z.object({
|
|
365
|
+
* force: optionalBoolean(false), // defaults to false if not provided
|
|
366
|
+
* });
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
export function optionalBoolean(defaultValue: boolean) {
|
|
370
|
+
return z.boolean().default(defaultValue);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Create optional number field with default.
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* ```typescript
|
|
378
|
+
* const schema = z.object({
|
|
379
|
+
* timeout: optionalNumber(5000), // defaults to 5000 if not provided
|
|
380
|
+
* });
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
export function optionalNumber(defaultValue: number) {
|
|
384
|
+
return z.number().default(defaultValue);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Create enum schema from array of values.
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```typescript
|
|
392
|
+
* const formatSchema = enumFromArray(['json', 'yaml', 'toml'] as const);
|
|
393
|
+
* // Type: 'json' | 'yaml' | 'toml'
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
export function enumFromArray<T extends readonly [string, ...string[]]>(values: T) {
|
|
397
|
+
return z.enum(values);
|
|
398
|
+
}
|