@coherent.js/state 1.0.0-beta.5 → 1.0.0-beta.7

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/state-validation.js"],
4
+ "sourcesContent": ["/**\n * @fileoverview State Validation for Coherent.js\n * Provides JSON Schema validation and custom validators for state management\n * @module @coherent.js/core/state/state-validation\n */\n\n/**\n * @typedef {Object} ValidationOptions\n * @property {Object} [schema] - JSON Schema for validation\n * @property {Object<string, Function>} [validators] - Custom validator functions\n * @property {boolean} [strict=false] - Strict mode (throw on validation errors)\n * @property {boolean} [coerce=false] - Coerce types to match schema\n * @property {Function} [onError] - Validation error callback\n * @property {boolean} [validateOnSet=true] - Validate on state updates\n * @property {boolean} [validateOnGet=false] - Validate on state reads\n * @property {Array<string>} [required] - Required fields\n * @property {boolean} [allowUnknown=true] - Allow unknown properties\n */\n\n/**\n * @typedef {Object} ValidationResult\n * @property {boolean} valid - Whether validation passed\n * @property {Array<ValidationError>} errors - Array of validation errors\n * @property {*} value - Validated/coerced value\n */\n\n/**\n * @typedef {Object} ValidationError\n * @property {string} path - Property path that failed validation\n * @property {string} message - Error message\n * @property {string} type - Error type\n * @property {*} value - The invalid value\n * @property {*} expected - Expected value/type\n */\n\n/**\n * Simple JSON Schema validator\n */\nclass SchemaValidator {\n constructor(schema, options = {}) {\n this.schema = schema;\n this.options = {\n coerce: false,\n allowUnknown: true,\n ...options\n };\n }\n\n /**\n * Validate value against schema\n * @param {*} value - Value to validate\n * @param {Object} schema - Schema to validate against\n * @param {string} path - Current path in object\n * @returns {ValidationResult} Validation result\n */\n validate(value, schema = this.schema, path = '') {\n const errors = [];\n let coercedValue = value;\n\n // Type validation\n if (schema.type) {\n const typeResult = this.validateType(value, schema.type, path);\n if (!typeResult.valid) {\n errors.push(...typeResult.errors);\n if (!this.options.coerce) {\n return { valid: false, errors, value };\n }\n }\n coercedValue = typeResult.value;\n }\n\n // Enum validation\n if (schema.enum) {\n const enumResult = this.validateEnum(coercedValue, schema.enum, path);\n if (!enumResult.valid) {\n errors.push(...enumResult.errors);\n }\n }\n\n // String validations\n if (schema.type === 'string') {\n const stringResult = this.validateString(coercedValue, schema, path);\n if (!stringResult.valid) {\n errors.push(...stringResult.errors);\n }\n }\n\n // Number validations\n if (schema.type === 'number' || schema.type === 'integer') {\n const numberResult = this.validateNumber(coercedValue, schema, path);\n if (!numberResult.valid) {\n errors.push(...numberResult.errors);\n }\n }\n\n // Array validations\n if (schema.type === 'array') {\n const arrayResult = this.validateArray(coercedValue, schema, path);\n if (!arrayResult.valid) {\n errors.push(...arrayResult.errors);\n }\n coercedValue = arrayResult.value;\n }\n\n // Object validations\n if (schema.type === 'object') {\n const objectResult = this.validateObject(coercedValue, schema, path);\n if (!objectResult.valid) {\n errors.push(...objectResult.errors);\n }\n coercedValue = objectResult.value;\n }\n\n // Custom validation function\n if (schema.validate && typeof schema.validate === 'function') {\n const customResult = schema.validate(coercedValue);\n if (customResult !== true) {\n errors.push({\n path,\n message: typeof customResult === 'string' ? customResult : 'Custom validation failed',\n type: 'custom',\n value: coercedValue\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n value: coercedValue\n };\n }\n\n validateType(value, type, path) {\n const actualType = Array.isArray(value) ? 'array' : typeof value;\n const errors = [];\n let coercedValue = value;\n\n // Support array of types\n const types = Array.isArray(type) ? type : [type];\n\n const isValid = types.some(t => {\n if (t === 'array') return Array.isArray(value);\n if (t === 'null') return value === null;\n if (t === 'integer') return typeof value === 'number' && Number.isInteger(value);\n return typeof value === t;\n });\n\n if (!isValid) {\n if (this.options.coerce) {\n // Try to coerce\n const primaryType = types[0];\n try {\n if (primaryType === 'string') {\n coercedValue = String(value);\n } else if (primaryType === 'number') {\n coercedValue = Number(value);\n if (isNaN(coercedValue)) {\n errors.push({\n path,\n message: `Cannot coerce \"${value}\" to number`,\n type: 'type',\n value,\n expected: primaryType\n });\n }\n } else if (primaryType === 'boolean') {\n coercedValue = Boolean(value);\n } else if (primaryType === 'integer') {\n coercedValue = parseInt(value, 10);\n if (isNaN(coercedValue)) {\n errors.push({\n path,\n message: `Cannot coerce \"${value}\" to integer`,\n type: 'type',\n value,\n expected: primaryType\n });\n }\n }\n } catch {\n errors.push({\n path,\n message: `Cannot coerce value to ${primaryType}`,\n type: 'type',\n value,\n expected: primaryType\n });\n }\n } else {\n errors.push({\n path,\n message: `Expected type ${types.join(' or ')}, got ${actualType}`,\n type: 'type',\n value,\n expected: type\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n value: coercedValue\n };\n }\n\n validateEnum(value, enumValues, path) {\n const errors = [];\n if (!enumValues.includes(value)) {\n errors.push({\n path,\n message: `Value must be one of: ${enumValues.join(', ')}`,\n type: 'enum',\n value,\n expected: enumValues\n });\n }\n return { valid: errors.length === 0, errors };\n }\n\n validateString(value, schema, path) {\n const errors = [];\n\n if (schema.minLength !== undefined && value.length < schema.minLength) {\n errors.push({\n path,\n message: `String length must be >= ${schema.minLength}`,\n type: 'minLength',\n value\n });\n }\n\n if (schema.maxLength !== undefined && value.length > schema.maxLength) {\n errors.push({\n path,\n message: `String length must be <= ${schema.maxLength}`,\n type: 'maxLength',\n value\n });\n }\n\n if (schema.pattern) {\n const regex = new RegExp(schema.pattern);\n if (!regex.test(value)) {\n errors.push({\n path,\n message: `String does not match pattern: ${schema.pattern}`,\n type: 'pattern',\n value\n });\n }\n }\n\n if (schema.format) {\n const formatResult = this.validateFormat(value, schema.format, path);\n if (!formatResult.valid) {\n errors.push(...formatResult.errors);\n }\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n validateFormat(value, format, path) {\n const errors = [];\n const formats = {\n email: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/,\n url: /^https?:\\/\\/.+/,\n uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n date: /^\\d{4}-\\d{2}-\\d{2}$/,\n 'date-time': /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/\n };\n\n if (formats[format] && !formats[format].test(value)) {\n errors.push({\n path,\n message: `String does not match format: ${format}`,\n type: 'format',\n value,\n expected: format\n });\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n validateNumber(value, schema, path) {\n const errors = [];\n\n if (schema.minimum !== undefined && value < schema.minimum) {\n errors.push({\n path,\n message: `Number must be >= ${schema.minimum}`,\n type: 'minimum',\n value\n });\n }\n\n if (schema.maximum !== undefined && value > schema.maximum) {\n errors.push({\n path,\n message: `Number must be <= ${schema.maximum}`,\n type: 'maximum',\n value\n });\n }\n\n if (schema.exclusiveMinimum !== undefined && value <= schema.exclusiveMinimum) {\n errors.push({\n path,\n message: `Number must be > ${schema.exclusiveMinimum}`,\n type: 'exclusiveMinimum',\n value\n });\n }\n\n if (schema.exclusiveMaximum !== undefined && value >= schema.exclusiveMaximum) {\n errors.push({\n path,\n message: `Number must be < ${schema.exclusiveMaximum}`,\n type: 'exclusiveMaximum',\n value\n });\n }\n\n if (schema.multipleOf !== undefined && value % schema.multipleOf !== 0) {\n errors.push({\n path,\n message: `Number must be multiple of ${schema.multipleOf}`,\n type: 'multipleOf',\n value\n });\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n validateArray(value, schema, path) {\n const errors = [];\n const coercedValue = [...value];\n\n if (schema.minItems !== undefined && value.length < schema.minItems) {\n errors.push({\n path,\n message: `Array must have at least ${schema.minItems} items`,\n type: 'minItems',\n value\n });\n }\n\n if (schema.maxItems !== undefined && value.length > schema.maxItems) {\n errors.push({\n path,\n message: `Array must have at most ${schema.maxItems} items`,\n type: 'maxItems',\n value\n });\n }\n\n if (schema.uniqueItems) {\n const seen = new Set();\n const duplicates = [];\n value.forEach((item, index) => {\n const key = JSON.stringify(item);\n if (seen.has(key)) {\n duplicates.push(index);\n }\n seen.add(key);\n });\n if (duplicates.length > 0) {\n errors.push({\n path,\n message: 'Array items must be unique',\n type: 'uniqueItems',\n value\n });\n }\n }\n\n // Validate items\n if (schema.items) {\n value.forEach((item, index) => {\n const itemPath = `${path}[${index}]`;\n const itemResult = this.validate(item, schema.items, itemPath);\n if (!itemResult.valid) {\n errors.push(...itemResult.errors);\n }\n if (this.options.coerce) {\n coercedValue[index] = itemResult.value;\n }\n });\n }\n\n return {\n valid: errors.length === 0,\n errors,\n value: coercedValue\n };\n }\n\n validateObject(value, schema, path) {\n const errors = [];\n const coercedValue = { ...value };\n\n // Required properties\n if (schema.required) {\n schema.required.forEach(prop => {\n if (!(prop in value)) {\n errors.push({\n path: path ? `${path}.${prop}` : prop,\n message: `Required property \"${prop}\" is missing`,\n type: 'required',\n value: undefined\n });\n }\n });\n }\n\n // Validate properties\n if (schema.properties) {\n Object.entries(schema.properties).forEach(([prop, propSchema]) => {\n if (prop in value) {\n const propPath = path ? `${path}.${prop}` : prop;\n const propResult = this.validate(value[prop], propSchema, propPath);\n if (!propResult.valid) {\n errors.push(...propResult.errors);\n }\n if (this.options.coerce) {\n coercedValue[prop] = propResult.value;\n }\n }\n });\n }\n\n // Additional properties\n if (schema.additionalProperties === false && !this.options.allowUnknown) {\n const allowedProps = new Set(Object.keys(schema.properties || {}));\n Object.keys(value).forEach(prop => {\n if (!allowedProps.has(prop)) {\n errors.push({\n path: path ? `${path}.${prop}` : prop,\n message: `Unknown property \"${prop}\"`,\n type: 'additionalProperties',\n value: value[prop]\n });\n }\n });\n }\n\n // Min/max properties\n const propCount = Object.keys(value).length;\n if (schema.minProperties !== undefined && propCount < schema.minProperties) {\n errors.push({\n path,\n message: `Object must have at least ${schema.minProperties} properties`,\n type: 'minProperties',\n value\n });\n }\n\n if (schema.maxProperties !== undefined && propCount > schema.maxProperties) {\n errors.push({\n path,\n message: `Object must have at most ${schema.maxProperties} properties`,\n type: 'maxProperties',\n value\n });\n }\n\n return {\n valid: errors.length === 0,\n errors,\n value: coercedValue\n };\n }\n}\n\n/**\n * Create validated state manager\n * @param {Object} initialState - Initial state\n * @param {ValidationOptions} options - Validation options\n * @returns {Object} Validated state manager\n */\nexport function createValidatedState(initialState = {}, options = {}) {\n const opts = {\n schema: null,\n validators: {},\n strict: false,\n coerce: false,\n onError: null,\n validateOnSet: true,\n validateOnGet: false,\n required: [],\n allowUnknown: true,\n ...options\n };\n\n const schemaValidator = opts.schema ? new SchemaValidator(opts.schema, {\n coerce: opts.coerce,\n allowUnknown: opts.allowUnknown\n }) : null;\n\n let state = { ...initialState };\n const listeners = new Set();\n const validationErrors = new Map();\n\n /**\n * Validate state\n * @param {Object} value - State to validate\n * @param {string} key - State key (for partial validation)\n * @returns {ValidationResult} Validation result\n */\n function validateState(value, key = null) {\n const errors = [];\n let validatedValue = value;\n\n // JSON Schema validation\n if (schemaValidator) {\n const schema = key && opts.schema.properties\n ? opts.schema.properties[key]\n : opts.schema;\n\n const result = schemaValidator.validate(value, schema, key || '');\n if (!result.valid) {\n errors.push(...result.errors);\n }\n validatedValue = result.value;\n }\n\n // Custom validators\n if (key && opts.validators[key]) {\n const validator = opts.validators[key];\n const result = validator(value);\n if (result !== true) {\n errors.push({\n path: key,\n message: typeof result === 'string' ? result : 'Validation failed',\n type: 'custom',\n value\n });\n }\n } else if (!key) {\n // Run custom validators for all fields when validating full state\n Object.entries(opts.validators).forEach(([fieldKey, validator]) => {\n if (fieldKey in value) {\n const result = validator(value[fieldKey]);\n if (result !== true) {\n errors.push({\n path: fieldKey,\n message: typeof result === 'string' ? result : 'Validation failed',\n type: 'custom',\n value: value[fieldKey]\n });\n }\n }\n });\n }\n\n // Required fields\n if (opts.required.length > 0 && !key) {\n opts.required.forEach(field => {\n if (!(field in value)) {\n errors.push({\n path: field,\n message: `Required field \"${field}\" is missing`,\n type: 'required',\n value: undefined\n });\n }\n });\n }\n\n return {\n valid: errors.length === 0,\n errors,\n value: validatedValue\n };\n }\n\n /**\n * Get state\n * @param {string} key - State key\n * @returns {*} State value\n */\n function getState(key) {\n const value = key ? state[key] : { ...state };\n\n if (opts.validateOnGet) {\n const result = validateState(value, key);\n if (!result.valid) {\n validationErrors.set(key || '__root__', result.errors);\n if (opts.onError) {\n opts.onError(result.errors);\n }\n }\n }\n\n return value;\n }\n\n /**\n * Set state\n * @param {Object|Function} updates - State updates\n * @throws {Error} If validation fails in strict mode\n */\n function setState(updates) {\n const oldState = { ...state };\n\n if (typeof updates === 'function') {\n updates = updates(oldState);\n }\n\n // Create the new full state for validation\n const newState = { ...state, ...updates };\n\n // Validate before setting\n if (opts.validateOnSet) {\n const result = validateState(newState);\n\n if (!result.valid) {\n validationErrors.set('__root__', result.errors);\n\n if (opts.onError) {\n opts.onError(result.errors);\n }\n\n if (opts.strict) {\n const error = new Error('Validation failed');\n error.validationErrors = result.errors;\n throw error;\n }\n\n // Don't update state if validation fails in non-strict mode\n return;\n }\n\n // Use coerced value if coercion is enabled\n if (opts.coerce) {\n const updatedKeys = Object.keys(updates);\n const newUpdates = {};\n updatedKeys.forEach(key => {\n if (result.value[key] !== state[key]) {\n newUpdates[key] = result.value[key];\n }\n });\n updates = newUpdates;\n }\n\n // Clear errors on successful validation\n validationErrors.clear();\n }\n\n state = { ...state, ...updates };\n\n // Notify listeners\n listeners.forEach(listener => {\n try {\n listener(state, oldState);\n } catch (error) {\n console.error('Listener error:', error);\n }\n });\n }\n\n /**\n * Subscribe to state changes\n * @param {Function} listener - Change listener\n * @returns {Function} Unsubscribe function\n */\n function subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n }\n\n /**\n * Get validation errors\n * @param {string} key - State key\n * @returns {Array<ValidationError>} Validation errors\n */\n function getErrors(key = '__root__') {\n return validationErrors.get(key) || [];\n }\n\n /**\n * Check if state is valid\n * @returns {boolean} Whether state is valid\n */\n function isValid() {\n const result = validateState(state);\n if (!result.valid) {\n validationErrors.set('__root__', result.errors);\n }\n return result.valid;\n }\n\n /**\n * Validate specific field\n * @param {string} key - Field key\n * @param {*} value - Field value\n * @returns {ValidationResult} Validation result\n */\n function validateField(key, value) {\n return validateState(value, key);\n }\n\n return {\n getState,\n setState,\n subscribe,\n getErrors,\n isValid,\n validateField,\n validate: () => validateState(state)\n };\n}\n\n/**\n * Common validators\n */\nexport const validators = {\n /**\n * Email validator\n * @param {string} value - Email to validate\n * @returns {boolean|string} True if valid, error message otherwise\n */\n email: (value) => {\n if (typeof value !== 'string') return 'Email must be a string';\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)) return 'Invalid email format';\n return true;\n },\n\n /**\n * URL validator\n * @param {string} value - URL to validate\n * @returns {boolean|string} True if valid, error message otherwise\n */\n url: (value) => {\n if (typeof value !== 'string') return 'URL must be a string';\n try {\n new URL(value);\n return true;\n } catch {\n return 'Invalid URL format';\n }\n },\n\n /**\n * Range validator\n * @param {number} min - Minimum value\n * @param {number} max - Maximum value\n * @returns {Function} Validator function\n */\n range: (min, max) => (value) => {\n if (typeof value !== 'number') return 'Value must be a number';\n if (value < min || value > max) return `Value must be between ${min} and ${max}`;\n return true;\n },\n\n /**\n * Length validator\n * @param {number} min - Minimum length\n * @param {number} max - Maximum length\n * @returns {Function} Validator function\n */\n length: (min, max) => (value) => {\n if (typeof value !== 'string') return 'Value must be a string';\n if (value.length < min || value.length > max) {\n return `Length must be between ${min} and ${max}`;\n }\n return true;\n },\n\n /**\n * Pattern validator\n * @param {RegExp|string} pattern - Pattern to match\n * @returns {Function} Validator function\n */\n pattern: (pattern) => (value) => {\n if (typeof value !== 'string') return 'Value must be a string';\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\n if (!regex.test(value)) return `Value does not match pattern: ${pattern}`;\n return true;\n },\n\n /**\n * Required validator\n * @param {*} value - Value to validate\n * @returns {boolean|string} True if valid, error message otherwise\n */\n required: (value) => {\n if (value === undefined || value === null || value === '') {\n return 'Value is required';\n }\n return true;\n }\n};\n\nexport default {\n createValidatedState,\n validators,\n SchemaValidator\n};\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coherent.js/state",
3
- "version": "1.0.0-beta.5",
3
+ "version": "1.0.0-beta.7",
4
4
  "description": "Reactive state management for Coherent.js applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,14 +25,22 @@
25
25
  "type": "git",
26
26
  "url": "git+https://github.com/Tomdrouv1/coherent.js.git"
27
27
  },
28
+ "homepage": "https://github.com/Tomdrouv1/coherent.js",
29
+ "bugs": {
30
+ "url": "https://github.com/Tomdrouv1/coherent.js/issues"
31
+ },
28
32
  "publishConfig": {
29
33
  "access": "public"
30
34
  },
35
+ "engines": {
36
+ "node": ">=20.0.0"
37
+ },
31
38
  "peerDependencies": {
32
- "@coherent.js/core": "1.0.0-beta.5"
39
+ "@coherent.js/core": "1.0.0-beta.7"
33
40
  },
34
41
  "types": "./types/index.d.ts",
35
42
  "files": [
43
+ "dist/",
36
44
  "LICENSE",
37
45
  "README.md",
38
46
  "types/"
@@ -40,6 +48,8 @@
40
48
  "sideEffects": false,
41
49
  "scripts": {
42
50
  "build": "node build.mjs",
43
- "clean": "rm -rf dist"
51
+ "clean": "rm -rf dist",
52
+ "test": "vitest run",
53
+ "test:watch": "vitest"
44
54
  }
45
55
  }
package/types/index.d.ts CHANGED
@@ -3,138 +3,463 @@
3
3
  * @module @coherent.js/state
4
4
  */
5
5
 
6
- // ===== Reactive State Types =====
6
+ import type { CoherentNode, ComponentState } from '@coherent.js/core';
7
7
 
8
- export interface Observer<T = any> {
8
+ // ============================================================================
9
+ // Core Store Types
10
+ // ============================================================================
11
+
12
+ /**
13
+ * Typed state store with subscribe and update capabilities
14
+ * @template T - The shape of the state object
15
+ */
16
+ export interface Store<T extends Record<string, unknown> = Record<string, unknown>> {
17
+ /**
18
+ * Get the current state
19
+ */
20
+ getState(): T;
21
+
22
+ /**
23
+ * Update state with partial object or updater function
24
+ */
25
+ setState(partial: Partial<T> | ((state: T) => Partial<T>)): void;
26
+
27
+ /**
28
+ * Subscribe to state changes
29
+ * @returns Unsubscribe function
30
+ */
31
+ subscribe(listener: (state: T, prevState: T) => void): () => void;
32
+
33
+ /**
34
+ * Destroy the store and clean up subscriptions
35
+ */
36
+ destroy(): void;
37
+ }
38
+
39
+ /**
40
+ * Store creation options
41
+ * @template T - The shape of the state object
42
+ */
43
+ export interface StoreOptions<T extends Record<string, unknown> = Record<string, unknown>> {
44
+ /** Initial state */
45
+ initialState: T;
46
+ /** Persistence configuration */
47
+ persist?: {
48
+ /** Storage key */
49
+ key: string;
50
+ /** Storage adapter (localStorage, sessionStorage, or custom) */
51
+ storage?: Storage;
52
+ /** Custom serialization */
53
+ serialize?: (state: T) => string;
54
+ /** Custom deserialization */
55
+ deserialize?: (value: string) => T;
56
+ /** Debounce persistence writes (ms) */
57
+ debounce?: number;
58
+ };
59
+ /** Enable devtools integration */
60
+ devtools?: boolean;
61
+ /** Store name for debugging */
62
+ name?: string;
63
+ /** Middleware functions */
64
+ middleware?: Array<StoreMiddleware<T>>;
65
+ }
66
+
67
+ /**
68
+ * Store middleware function
69
+ */
70
+ export type StoreMiddleware<T> = (
71
+ state: T,
72
+ action: string,
73
+ payload?: unknown
74
+ ) => T | void;
75
+
76
+ /**
77
+ * Create a typed state store
78
+ */
79
+ export function createStore<T extends Record<string, unknown>>(
80
+ options: StoreOptions<T>
81
+ ): Store<T>;
82
+
83
+ // ============================================================================
84
+ // Selector Types
85
+ // ============================================================================
86
+
87
+ /**
88
+ * Create a derived selector from store state
89
+ * @template T - Store state type
90
+ * @template R - Return type of selector
91
+ */
92
+ export function createSelector<T extends Record<string, unknown>, R>(
93
+ store: Store<T>,
94
+ selector: (state: T) => R
95
+ ): () => R;
96
+
97
+ /**
98
+ * Create a memoized selector with dependencies
99
+ */
100
+ export function createMemoizedSelector<T extends Record<string, unknown>, D extends unknown[], R>(
101
+ store: Store<T>,
102
+ dependencies: (...args: D) => unknown[],
103
+ selector: (state: T, ...deps: D) => R
104
+ ): (...args: D) => R;
105
+
106
+ // ============================================================================
107
+ // Action Types
108
+ // ============================================================================
109
+
110
+ /**
111
+ * Action type helper for type-safe actions
112
+ * @template T - Store state type
113
+ * @template P - Payload type (void for no payload)
114
+ */
115
+ export type Action<T, P = void> = P extends void
116
+ ? () => Partial<T>
117
+ : (payload: P) => Partial<T>;
118
+
119
+ /**
120
+ * Create typed action creators
121
+ */
122
+ export function createActions<
123
+ T extends Record<string, unknown>,
124
+ A extends Record<string, Action<T, unknown>>
125
+ >(
126
+ store: Store<T>,
127
+ actions: A
128
+ ): {
129
+ [K in keyof A]: A[K] extends Action<T, infer P>
130
+ ? P extends void
131
+ ? () => void
132
+ : (payload: P) => void
133
+ : never;
134
+ };
135
+
136
+ // ============================================================================
137
+ // Reactive State Types
138
+ // ============================================================================
139
+
140
+ /**
141
+ * Observer callback type
142
+ */
143
+ export interface Observer<T = unknown> {
9
144
  (value: T, oldValue: T): void;
10
145
  }
11
146
 
12
- export class Observable<T = any> {
147
+ /**
148
+ * Observable value wrapper
149
+ */
150
+ export class Observable<T = unknown> {
13
151
  constructor(initialValue: T);
152
+
153
+ /** Get current value */
14
154
  get(): T;
155
+
156
+ /** Set new value */
15
157
  set(value: T): void;
158
+
159
+ /** Subscribe to changes */
16
160
  subscribe(observer: Observer<T>): () => void;
161
+
162
+ /** Unsubscribe observer */
17
163
  unsubscribe(observer: Observer<T>): void;
164
+
165
+ /** Notify all observers */
18
166
  notify(): void;
19
167
  }
20
168
 
21
- export interface ReactiveStateOptions<T = any> {
169
+ /**
170
+ * Reactive state options
171
+ */
172
+ export interface ReactiveStateOptions<T = unknown> {
173
+ /** Initial state value */
22
174
  initialValue: T;
23
- computed?: Record<string, (state: T) => any>;
24
- watchers?: Record<string, Observer<any>>;
25
- middleware?: Array<(state: T, action: string, payload?: any) => T | void>;
175
+ /** Computed properties */
176
+ computed?: Record<string, (state: T) => unknown>;
177
+ /** Property watchers */
178
+ watchers?: Record<string, Observer<unknown>>;
179
+ /** Middleware functions */
180
+ middleware?: Array<(state: T, action: string, payload?: unknown) => T | void>;
26
181
  }
27
182
 
28
- export class ReactiveState<T = any> {
183
+ /**
184
+ * Reactive state class with computed properties and watchers
185
+ */
186
+ export class ReactiveState<T extends Record<string, unknown> = Record<string, unknown>> {
29
187
  constructor(options: ReactiveStateOptions<T>);
188
+
189
+ /** Get a property value */
30
190
  get<K extends keyof T>(key: K): T[K];
191
+
192
+ /** Set a property value */
31
193
  set<K extends keyof T>(key: K, value: T[K]): void;
194
+
195
+ /** Update multiple properties */
32
196
  update(partial: Partial<T>): void;
197
+
198
+ /** Subscribe to all changes */
33
199
  subscribe(observer: Observer<T>): () => void;
200
+
201
+ /** Watch a specific property */
34
202
  watch<K extends keyof T>(key: K, observer: Observer<T[K]>): () => void;
203
+
204
+ /** Get full state */
35
205
  getState(): T;
206
+
207
+ /** Reset to initial state */
36
208
  reset(): void;
37
209
  }
38
210
 
39
- export function createReactiveState<T = any>(options: ReactiveStateOptions<T>): ReactiveState<T>;
40
- export function observable<T = any>(initialValue: T): Observable<T>;
41
- export function computed<T = any>(fn: () => T, dependencies: Observable<any>[]): Observable<T>;
211
+ /**
212
+ * Create a reactive state instance
213
+ */
214
+ export function createReactiveState<T extends Record<string, unknown> = Record<string, unknown>>(
215
+ options: ReactiveStateOptions<T>
216
+ ): ReactiveState<T>;
217
+
218
+ /**
219
+ * Create a simple observable value
220
+ */
221
+ export function observable<T = unknown>(initialValue: T): Observable<T>;
222
+
223
+ /**
224
+ * Create a computed observable
225
+ */
226
+ export function computed<T = unknown>(
227
+ fn: () => T,
228
+ dependencies: Observable<unknown>[]
229
+ ): Observable<T>;
42
230
 
231
+ /**
232
+ * State utility functions
233
+ */
43
234
  export const stateUtils: {
235
+ /** Batch multiple state updates */
44
236
  batch<T>(fn: () => T): T;
237
+ /** Run updates in a transaction */
45
238
  transaction<T>(fn: () => T): T;
239
+ /** Freeze state (make immutable) */
46
240
  freeze<T>(state: T): Readonly<T>;
241
+ /** Deep clone state */
47
242
  clone<T>(state: T): T;
48
243
  };
49
244
 
50
- // ===== SSR-Compatible State Manager Types =====
245
+ // ============================================================================
246
+ // SSR-Compatible State Manager
247
+ // ============================================================================
51
248
 
52
- export interface StateManagerOptions<T = any> {
249
+ /**
250
+ * State manager options
251
+ */
252
+ export interface StateManagerOptions<T = unknown> {
253
+ /** Initial state */
53
254
  initialState?: T;
255
+ /** Enable persistence */
54
256
  persist?: boolean;
257
+ /** Persistence key */
55
258
  key?: string;
259
+ /** Middleware functions */
56
260
  middleware?: Array<(state: T, action: string) => T | void>;
57
261
  }
58
262
 
59
- export interface State<T = any> {
263
+ /**
264
+ * Simple state interface
265
+ */
266
+ export interface State<T = unknown> {
267
+ /** Get current state */
60
268
  get(): T;
269
+ /** Set new state */
61
270
  set(value: T): void;
271
+ /** Update with partial */
62
272
  update(partial: Partial<T>): void;
273
+ /** Subscribe to changes */
63
274
  subscribe(listener: (state: T) => void): () => void;
275
+ /** Reset to initial state */
64
276
  reset(): void;
65
277
  }
66
278
 
67
- export function createState<T = any>(initialState: T, options?: StateManagerOptions<T>): State<T>;
279
+ /**
280
+ * Create a simple state container
281
+ */
282
+ export function createState<T = unknown>(
283
+ initialState: T,
284
+ options?: StateManagerOptions<T>
285
+ ): State<T>;
68
286
 
287
+ /**
288
+ * Global state manager for SSR
289
+ */
69
290
  export const globalStateManager: {
70
- getState<T = any>(key: string): T | undefined;
71
- setState<T = any>(key: string, value: T): void;
72
- subscribe<T = any>(key: string, listener: (state: T) => void): () => void;
291
+ /** Get state by key */
292
+ getState<T = unknown>(key: string): T | undefined;
293
+ /** Set state by key */
294
+ setState<T = unknown>(key: string, value: T): void;
295
+ /** Subscribe to state key */
296
+ subscribe<T = unknown>(key: string, listener: (state: T) => void): () => void;
297
+ /** Clear state (optionally by key) */
73
298
  clear(key?: string): void;
74
299
  };
75
300
 
76
- // ===== Context API Types =====
301
+ // ============================================================================
302
+ // Context API
303
+ // ============================================================================
77
304
 
78
- export interface ContextValue<T = any> {
305
+ /**
306
+ * Context value wrapper
307
+ */
308
+ export interface ContextValue<T = unknown> {
79
309
  value: T;
80
310
  subscribers: Set<(value: T) => void>;
81
311
  }
82
312
 
83
- export function provideContext<T = any>(key: string, value: T): void;
84
- export function createContextProvider<T = any>(key: string, value: T): { key: string; value: T };
85
- export function useContext<T = any>(key: string, defaultValue?: T): T;
86
- export function restoreContext(contexts: Record<string, any>): void;
313
+ /**
314
+ * Provide a context value
315
+ */
316
+ export function provideContext<T = unknown>(key: string, value: T): void;
317
+
318
+ /**
319
+ * Create a context provider
320
+ */
321
+ export function createContextProvider<T = unknown>(
322
+ key: string,
323
+ value: T
324
+ ): { key: string; value: T };
325
+
326
+ /**
327
+ * Use/consume a context value
328
+ */
329
+ export function useContext<T = unknown>(key: string, defaultValue?: T): T;
330
+
331
+ /**
332
+ * Restore context from saved state
333
+ */
334
+ export function restoreContext(contexts: Record<string, unknown>): void;
335
+
336
+ /**
337
+ * Clear all context stacks
338
+ */
87
339
  export function clearAllContexts(): void;
88
340
 
89
- // ===== Persistent State Types =====
341
+ // ============================================================================
342
+ // Persistent State
343
+ // ============================================================================
90
344
 
345
+ /**
346
+ * Persistence adapter interface
347
+ */
91
348
  export interface PersistenceAdapter {
349
+ /** Get item from storage */
92
350
  getItem(key: string): Promise<string | null> | string | null;
351
+ /** Set item in storage */
93
352
  setItem(key: string, value: string): Promise<void> | void;
353
+ /** Remove item from storage */
94
354
  removeItem(key: string): Promise<void> | void;
95
355
  }
96
356
 
97
- export interface PersistentStateOptions<T = any> extends StateManagerOptions<T> {
357
+ /**
358
+ * Persistent state options
359
+ */
360
+ export interface PersistentStateOptions<T = unknown> extends StateManagerOptions<T> {
361
+ /** Required: storage key */
98
362
  key: string;
363
+ /** Storage adapter */
99
364
  storage?: PersistenceAdapter;
365
+ /** Custom serialization */
100
366
  serialize?: (state: T) => string;
367
+ /** Custom deserialization */
101
368
  deserialize?: (data: string) => T;
369
+ /** Debounce writes (ms) */
102
370
  debounce?: number;
103
371
  }
104
372
 
105
- export function createPersistentState<T = any>(options: PersistentStateOptions<T>): State<T>;
106
- export function withLocalStorage<T = any>(state: State<T>, key: string): State<T>;
107
- export function withSessionStorage<T = any>(state: State<T>, key: string): State<T>;
108
- export function withIndexedDB<T = any>(state: State<T>, key: string, dbName?: string): Promise<State<T>>;
373
+ /**
374
+ * Create a persistent state
375
+ */
376
+ export function createPersistentState<T = unknown>(
377
+ options: PersistentStateOptions<T>
378
+ ): State<T>;
379
+
380
+ /**
381
+ * Wrap state with localStorage persistence
382
+ */
383
+ export function withLocalStorage<T = unknown>(state: State<T>, key: string): State<T>;
384
+
385
+ /**
386
+ * Wrap state with sessionStorage persistence
387
+ */
388
+ export function withSessionStorage<T = unknown>(state: State<T>, key: string): State<T>;
389
+
390
+ /**
391
+ * Wrap state with IndexedDB persistence
392
+ */
393
+ export function withIndexedDB<T = unknown>(
394
+ state: State<T>,
395
+ key: string,
396
+ dbName?: string
397
+ ): Promise<State<T>>;
109
398
 
110
- // ===== Validated State Types =====
399
+ // ============================================================================
400
+ // Validated State
401
+ // ============================================================================
111
402
 
112
- export interface ValidationRule<T = any> {
403
+ /**
404
+ * Validation rule function
405
+ */
406
+ export interface ValidationRule<T = unknown> {
113
407
  (value: T): boolean | string;
114
408
  }
115
409
 
116
- export interface ValidatedStateOptions<T = any> extends StateManagerOptions<T> {
117
- validators: Record<keyof T, ValidationRule<T[keyof T]>[]>;
410
+ /**
411
+ * Validated state options
412
+ */
413
+ export interface ValidatedStateOptions<T extends Record<string, unknown> = Record<string, unknown>>
414
+ extends StateManagerOptions<T> {
415
+ /** Validation rules by property */
416
+ validators: { [K in keyof T]?: ValidationRule<T[K]>[] };
417
+ /** Validate on every change */
118
418
  validateOnChange?: boolean;
419
+ /** Throw on validation failure */
119
420
  strict?: boolean;
120
421
  }
121
422
 
122
- export interface ValidatedState<T = any> extends State<T> {
123
- validate(): { valid: boolean; errors: Record<keyof T, string[]> };
423
+ /**
424
+ * Validated state interface
425
+ */
426
+ export interface ValidatedState<T extends Record<string, unknown> = Record<string, unknown>>
427
+ extends State<T> {
428
+ /** Validate current state */
429
+ validate(): { valid: boolean; errors: { [K in keyof T]?: string[] } };
430
+ /** Check if state is valid */
124
431
  isValid(): boolean;
125
- getErrors(): Record<keyof T, string[]>;
432
+ /** Get validation errors */
433
+ getErrors(): { [K in keyof T]?: string[] };
126
434
  }
127
435
 
128
- export function createValidatedState<T = any>(options: ValidatedStateOptions<T>): ValidatedState<T>;
436
+ /**
437
+ * Create a validated state
438
+ */
439
+ export function createValidatedState<T extends Record<string, unknown> = Record<string, unknown>>(
440
+ options: ValidatedStateOptions<T>
441
+ ): ValidatedState<T>;
129
442
 
443
+ /**
444
+ * Built-in validators
445
+ */
130
446
  export const validators: {
447
+ /** Required value */
131
448
  required(message?: string): ValidationRule;
449
+ /** Minimum length */
132
450
  minLength(length: number, message?: string): ValidationRule;
451
+ /** Maximum length */
133
452
  maxLength(length: number, message?: string): ValidationRule;
453
+ /** Minimum value */
134
454
  min(value: number, message?: string): ValidationRule;
455
+ /** Maximum value */
135
456
  max(value: number, message?: string): ValidationRule;
457
+ /** Pattern matching */
136
458
  pattern(regex: RegExp, message?: string): ValidationRule;
459
+ /** Email format */
137
460
  email(message?: string): ValidationRule;
461
+ /** URL format */
138
462
  url(message?: string): ValidationRule;
139
- custom(fn: (value: any) => boolean | string): ValidationRule;
463
+ /** Custom validator */
464
+ custom(fn: (value: unknown) => boolean | string): ValidationRule;
140
465
  };