digital-workers 2.1.3 → 2.4.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.
Files changed (183) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +17 -0
  3. package/README.md +2 -0
  4. package/dist/actions.d.ts.map +1 -1
  5. package/dist/actions.js +33 -21
  6. package/dist/actions.js.map +1 -1
  7. package/dist/agent-comms.d.ts.map +1 -1
  8. package/dist/agent-comms.js +36 -25
  9. package/dist/agent-comms.js.map +1 -1
  10. package/dist/approve.d.ts +40 -8
  11. package/dist/approve.d.ts.map +1 -1
  12. package/dist/approve.js +86 -20
  13. package/dist/approve.js.map +1 -1
  14. package/dist/ask.d.ts +38 -7
  15. package/dist/ask.d.ts.map +1 -1
  16. package/dist/ask.js +85 -25
  17. package/dist/ask.js.map +1 -1
  18. package/dist/browse.d.ts +223 -0
  19. package/dist/browse.d.ts.map +1 -0
  20. package/dist/browse.js +392 -0
  21. package/dist/browse.js.map +1 -0
  22. package/dist/capability-tiers.js +3 -3
  23. package/dist/capability-tiers.js.map +1 -1
  24. package/dist/cascade-context.d.ts +28 -28
  25. package/dist/client.d.ts +162 -0
  26. package/dist/client.d.ts.map +1 -0
  27. package/dist/client.js +64 -0
  28. package/dist/client.js.map +1 -0
  29. package/dist/decide.d.ts +42 -6
  30. package/dist/decide.d.ts.map +1 -1
  31. package/dist/decide.js +54 -11
  32. package/dist/decide.js.map +1 -1
  33. package/dist/do.d.ts +36 -7
  34. package/dist/do.d.ts.map +1 -1
  35. package/dist/do.js +82 -39
  36. package/dist/do.js.map +1 -1
  37. package/dist/error-escalation.d.ts.map +1 -1
  38. package/dist/error-escalation.js +38 -38
  39. package/dist/error-escalation.js.map +1 -1
  40. package/dist/generate.d.ts +48 -7
  41. package/dist/generate.d.ts.map +1 -1
  42. package/dist/generate.js +49 -8
  43. package/dist/generate.js.map +1 -1
  44. package/dist/goals.d.ts +10 -9
  45. package/dist/goals.d.ts.map +1 -1
  46. package/dist/goals.js +30 -24
  47. package/dist/goals.js.map +1 -1
  48. package/dist/image.d.ts +189 -0
  49. package/dist/image.d.ts.map +1 -0
  50. package/dist/image.js +528 -0
  51. package/dist/image.js.map +1 -0
  52. package/dist/index.d.ts +49 -2
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +58 -2
  55. package/dist/index.js.map +1 -1
  56. package/dist/is.d.ts +45 -10
  57. package/dist/is.d.ts.map +1 -1
  58. package/dist/is.js +56 -21
  59. package/dist/is.js.map +1 -1
  60. package/dist/kpis.d.ts +24 -15
  61. package/dist/kpis.d.ts.map +1 -1
  62. package/dist/kpis.js +16 -14
  63. package/dist/kpis.js.map +1 -1
  64. package/dist/load-balancing.d.ts.map +1 -1
  65. package/dist/load-balancing.js +124 -38
  66. package/dist/load-balancing.js.map +1 -1
  67. package/dist/logger.d.ts +76 -0
  68. package/dist/logger.d.ts.map +1 -0
  69. package/dist/logger.js +39 -0
  70. package/dist/logger.js.map +1 -0
  71. package/dist/notify.d.ts +38 -9
  72. package/dist/notify.d.ts.map +1 -1
  73. package/dist/notify.js +72 -17
  74. package/dist/notify.js.map +1 -1
  75. package/dist/role.d.ts +5 -4
  76. package/dist/role.d.ts.map +1 -1
  77. package/dist/role.js +13 -10
  78. package/dist/role.js.map +1 -1
  79. package/dist/runtime.d.ts +310 -0
  80. package/dist/runtime.d.ts.map +1 -0
  81. package/dist/runtime.js +510 -0
  82. package/dist/runtime.js.map +1 -0
  83. package/dist/team.d.ts +11 -6
  84. package/dist/team.d.ts.map +1 -1
  85. package/dist/team.js +22 -15
  86. package/dist/team.js.map +1 -1
  87. package/dist/transports/email.d.ts +318 -0
  88. package/dist/transports/email.d.ts.map +1 -0
  89. package/dist/transports/email.js +779 -0
  90. package/dist/transports/email.js.map +1 -0
  91. package/dist/transports/slack.d.ts +515 -0
  92. package/dist/transports/slack.d.ts.map +1 -0
  93. package/dist/transports/slack.js +844 -0
  94. package/dist/transports/slack.js.map +1 -0
  95. package/dist/transports.d.ts.map +1 -1
  96. package/dist/transports.js +44 -25
  97. package/dist/transports.js.map +1 -1
  98. package/dist/types.d.ts +141 -19
  99. package/dist/types.d.ts.map +1 -1
  100. package/dist/types.js +5 -0
  101. package/dist/types.js.map +1 -1
  102. package/dist/utils/id.d.ts +19 -0
  103. package/dist/utils/id.d.ts.map +1 -0
  104. package/dist/utils/id.js +21 -0
  105. package/dist/utils/id.js.map +1 -0
  106. package/dist/video.d.ts +203 -0
  107. package/dist/video.d.ts.map +1 -0
  108. package/dist/video.js +528 -0
  109. package/dist/video.js.map +1 -0
  110. package/dist/worker.d.ts +343 -0
  111. package/dist/worker.d.ts.map +1 -0
  112. package/dist/worker.js +698 -0
  113. package/dist/worker.js.map +1 -0
  114. package/package.json +32 -14
  115. package/src/actions.ts +39 -30
  116. package/src/agent-comms.ts +54 -92
  117. package/src/approve.ts +91 -20
  118. package/src/ask.ts +99 -25
  119. package/src/browse.ts +627 -0
  120. package/src/capability-tiers.ts +5 -5
  121. package/src/client.ts +221 -0
  122. package/src/decide.ts +81 -35
  123. package/src/do.ts +98 -52
  124. package/src/error-escalation.ts +55 -67
  125. package/src/generate.ts +52 -18
  126. package/src/goals.ts +36 -27
  127. package/src/image.ts +816 -0
  128. package/src/index.ts +187 -2
  129. package/src/is.ts +59 -25
  130. package/src/kpis.ts +41 -36
  131. package/src/load-balancing.ts +132 -46
  132. package/src/logger.ts +93 -0
  133. package/src/notify.ts +78 -17
  134. package/src/role.ts +30 -20
  135. package/src/runtime.ts +796 -0
  136. package/src/team.ts +24 -19
  137. package/src/transports/email.ts +1160 -0
  138. package/src/transports/slack.ts +1320 -0
  139. package/src/transports.ts +58 -43
  140. package/src/types.ts +174 -46
  141. package/src/utils/id.ts +21 -0
  142. package/src/video.ts +906 -0
  143. package/src/worker.ts +1007 -0
  144. package/test/approve.test.ts +305 -0
  145. package/test/ask.test.ts +274 -0
  146. package/test/browse.test.ts +361 -0
  147. package/test/decide.test.ts +252 -0
  148. package/test/do.test.ts +144 -0
  149. package/test/error-logging.test.ts +357 -0
  150. package/test/generate.test.ts +319 -0
  151. package/test/image.test.ts +398 -0
  152. package/test/is.test.ts +287 -0
  153. package/test/load-balancing-safety.test.ts +404 -0
  154. package/test/notify.test.ts +434 -0
  155. package/test/primitives.test.ts +320 -0
  156. package/test/runtime-integration.test.ts +892 -0
  157. package/test/transports/crypto.test.ts +230 -0
  158. package/test/transports/email.test.ts +866 -0
  159. package/test/transports/id-generation.test.ts +91 -0
  160. package/test/transports/slack.test.ts +760 -0
  161. package/test/type-safety.test.ts +834 -0
  162. package/test/types.test.ts +60 -2
  163. package/test/video.test.ts +530 -0
  164. package/test/worker.test.ts +1433 -0
  165. package/tsconfig.json +4 -1
  166. package/vitest.config.ts +42 -0
  167. package/wrangler.jsonc +36 -0
  168. package/LICENSE +0 -21
  169. package/src/actions.js +0 -436
  170. package/src/approve.js +0 -234
  171. package/src/ask.js +0 -226
  172. package/src/decide.js +0 -244
  173. package/src/do.js +0 -227
  174. package/src/generate.js +0 -298
  175. package/src/goals.js +0 -205
  176. package/src/index.js +0 -68
  177. package/src/is.js +0 -317
  178. package/src/kpis.js +0 -270
  179. package/src/notify.js +0 -219
  180. package/src/role.js +0 -110
  181. package/src/team.js +0 -130
  182. package/src/transports.js +0 -357
  183. package/src/types.js +0 -71
package/src/goals.js DELETED
@@ -1,205 +0,0 @@
1
- /**
2
- * Goals definition for digital workers
3
- */
4
- /**
5
- * Define worker goals
6
- *
7
- * Goals provide direction and metrics for workers and teams.
8
- * Supports short-term, long-term, and strategic objectives with KPIs.
9
- *
10
- * @param definition - Goals definition
11
- * @returns The defined goals
12
- *
13
- * @example
14
- * ```ts
15
- * const engineeringGoals = Goals({
16
- * shortTerm: [
17
- * 'Complete Q1 roadmap features',
18
- * 'Reduce bug backlog by 30%',
19
- * 'Improve test coverage to 80%',
20
- * ],
21
- * longTerm: [
22
- * 'Migrate to microservices architecture',
23
- * 'Achieve 99.9% uptime',
24
- * 'Build scalable platform for 1M users',
25
- * ],
26
- * strategic: [
27
- * 'Become industry leader in performance',
28
- * 'Enable product innovation through technology',
29
- * ],
30
- * metrics: [
31
- * {
32
- * name: 'Deployment Frequency',
33
- * description: 'Number of deployments per week',
34
- * current: 5,
35
- * target: 10,
36
- * unit: 'deploys/week',
37
- * trend: 'up',
38
- * period: 'weekly',
39
- * },
40
- * {
41
- * name: 'Mean Time to Recovery',
42
- * description: 'Average time to recover from incidents',
43
- * current: 45,
44
- * target: 30,
45
- * unit: 'minutes',
46
- * trend: 'down',
47
- * period: 'monthly',
48
- * },
49
- * ],
50
- * })
51
- * ```
52
- *
53
- * @example
54
- * ```ts
55
- * const supportGoals = Goals({
56
- * shortTerm: [
57
- * 'Achieve 95% customer satisfaction',
58
- * 'Reduce average response time to < 5 min',
59
- * ],
60
- * longTerm: [
61
- * 'Build comprehensive knowledge base',
62
- * 'Implement AI-first support workflow',
63
- * ],
64
- * metrics: [
65
- * {
66
- * name: 'Customer Satisfaction',
67
- * description: 'CSAT score from surveys',
68
- * current: 92,
69
- * target: 95,
70
- * unit: '%',
71
- * trend: 'up',
72
- * period: 'monthly',
73
- * },
74
- * ],
75
- * })
76
- * ```
77
- */
78
- export function Goals(definition) {
79
- return definition;
80
- }
81
- /**
82
- * Add a short-term goal
83
- *
84
- * @param goals - The goals object
85
- * @param goal - Goal to add
86
- * @returns Updated goals
87
- *
88
- * @example
89
- * ```ts
90
- * const updated = Goals.addShortTerm(engineeringGoals, 'Complete security audit')
91
- * ```
92
- */
93
- Goals.addShortTerm = (goals, goal) => ({
94
- ...goals,
95
- shortTerm: [...goals.shortTerm, goal],
96
- });
97
- /**
98
- * Add a long-term goal
99
- *
100
- * @param goals - The goals object
101
- * @param goal - Goal to add
102
- * @returns Updated goals
103
- *
104
- * @example
105
- * ```ts
106
- * const updated = Goals.addLongTerm(engineeringGoals, 'Build ML platform')
107
- * ```
108
- */
109
- Goals.addLongTerm = (goals, goal) => ({
110
- ...goals,
111
- longTerm: [...goals.longTerm, goal],
112
- });
113
- /**
114
- * Add a strategic goal
115
- *
116
- * @param goals - The goals object
117
- * @param goal - Goal to add
118
- * @returns Updated goals
119
- *
120
- * @example
121
- * ```ts
122
- * const updated = Goals.addStrategic(engineeringGoals, 'Become carbon neutral')
123
- * ```
124
- */
125
- Goals.addStrategic = (goals, goal) => ({
126
- ...goals,
127
- strategic: [...(goals.strategic || []), goal],
128
- });
129
- /**
130
- * Add a KPI metric
131
- *
132
- * @param goals - The goals object
133
- * @param kpi - KPI to add
134
- * @returns Updated goals
135
- *
136
- * @example
137
- * ```ts
138
- * const updated = Goals.addMetric(engineeringGoals, {
139
- * name: 'Code Quality',
140
- * description: 'Code quality score from SonarQube',
141
- * current: 85,
142
- * target: 90,
143
- * unit: 'score',
144
- * trend: 'up',
145
- * period: 'weekly',
146
- * })
147
- * ```
148
- */
149
- Goals.addMetric = (goals, kpi) => ({
150
- ...goals,
151
- metrics: [...(goals.metrics || []), kpi],
152
- });
153
- /**
154
- * Update a KPI metric
155
- *
156
- * @param goals - The goals object
157
- * @param name - Name of KPI to update
158
- * @param updates - Fields to update
159
- * @returns Updated goals
160
- *
161
- * @example
162
- * ```ts
163
- * const updated = Goals.updateMetric(engineeringGoals, 'Deployment Frequency', {
164
- * current: 8,
165
- * trend: 'up',
166
- * })
167
- * ```
168
- */
169
- Goals.updateMetric = (goals, name, updates) => ({
170
- ...goals,
171
- metrics: goals.metrics?.map((kpi) => kpi.name === name ? { ...kpi, ...updates } : kpi),
172
- });
173
- /**
174
- * Get progress for a KPI (0-1)
175
- *
176
- * @param kpi - The KPI
177
- * @returns Progress value between 0 and 1
178
- *
179
- * @example
180
- * ```ts
181
- * const kpi = { current: 75, target: 100 }
182
- * const progress = Goals.progress(kpi) // 0.75
183
- * ```
184
- */
185
- Goals.progress = (kpi) => {
186
- if (kpi.target === 0)
187
- return 0;
188
- return Math.min(1, Math.max(0, kpi.current / kpi.target));
189
- };
190
- /**
191
- * Check if a KPI is on track
192
- *
193
- * @param kpi - The KPI
194
- * @param threshold - Minimum progress to be considered "on track" (default: 0.8)
195
- * @returns Whether the KPI is on track
196
- *
197
- * @example
198
- * ```ts
199
- * const kpi = { current: 85, target: 100 }
200
- * const onTrack = Goals.onTrack(kpi) // true (85% >= 80% threshold)
201
- * ```
202
- */
203
- Goals.onTrack = (kpi, threshold = 0.8) => {
204
- return Goals.progress(kpi) >= threshold;
205
- };
package/src/index.js DELETED
@@ -1,68 +0,0 @@
1
- /**
2
- * digital-workers - Abstract interface for organizing digital work
3
- *
4
- * This package provides the foundational abstraction for structuring work
5
- * independent of whether AI agents or humans perform individual tasks. It
6
- * defines a unified Worker interface that enables workflows to be designed
7
- * once and executed by any combination of AI and human workers.
8
- *
9
- * Package relationships:
10
- * - `autonomous-agents` - Implements Worker for AI agents
11
- * - `human-in-the-loop` - Implements Worker for humans
12
- * - `ai-workflows` - Uses digital-workers to orchestrate execution
13
- *
14
- * The key insight: define WHAT work needs to happen, not WHO does it.
15
- *
16
- * ## Worker Actions
17
- *
18
- * Worker actions (notify, ask, approve, decide, do) are durable workflow actions
19
- * that integrate with ai-workflows. They can be invoked via:
20
- *
21
- * 1. `$.do('Worker.notify', data)` - Durable action
22
- * 2. `$.send('Worker.notify', data)` - Fire and forget
23
- * 3. `$.notify(target, message)` - Convenience method (when using withWorkers)
24
- *
25
- * @example
26
- * ```ts
27
- * import { Workflow } from 'ai-workflows'
28
- * import { registerWorkerActions, withWorkers } from 'digital-workers'
29
- *
30
- * const workflow = Workflow($ => {
31
- * registerWorkerActions($)
32
- * const worker$ = withWorkers($)
33
- *
34
- * $.on.Expense.submitted(async (expense) => {
35
- * await worker$.notify(finance, `New expense: ${expense.amount}`)
36
- *
37
- * const approval = await worker$.approve(
38
- * `Expense: $${expense.amount}`,
39
- * manager,
40
- * { via: 'slack' }
41
- * )
42
- *
43
- * if (approval.approved) {
44
- * await worker$.notify(expense.submitter, 'Expense approved!')
45
- * }
46
- * })
47
- * })
48
- * ```
49
- *
50
- * @packageDocumentation
51
- */
52
- // Export workflow integration
53
- export { registerWorkerActions, withWorkers, handleNotify, handleAsk, handleApprove, handleDecide, handleDo, notify as notifyAction, ask as askAction, approve as approveAction, decide as decideAction, } from './actions.js';
54
- // Export core functions
55
- export { Role } from './role.js';
56
- export { Team } from './team.js';
57
- export { Goals } from './goals.js';
58
- export { approve } from './approve.js';
59
- export { ask } from './ask.js';
60
- export { do } from './do.js';
61
- export { decide } from './decide.js';
62
- export { generate } from './generate.js';
63
- export { is } from './is.js';
64
- export { notify } from './notify.js';
65
- export { kpis, okrs } from './kpis.js';
66
- // Export verb definitions
67
- export { WorkerVerbs } from './types.js';
68
- export { channelToTransport, getWorkerTransports, getTeamTransports, resolveAddress, resolveWorkerAddresses, getPrimaryAddress, registerTransport, getTransportHandler, hasTransport, listTransports, sendViaTransport, sendToMultipleTransports, buildNotifyPayload, buildAskPayload, buildApprovePayload, toDigitalToolsMessage, fromDigitalToolsMessage, MessageTypeMapping, CallTypeMapping, } from './transports.js';
package/src/is.js DELETED
@@ -1,317 +0,0 @@
1
- /**
2
- * Type validation and checking functionality for digital workers
3
- */
4
- import { generateObject } from 'ai-functions';
5
- import { schema as convertSchema } from 'ai-functions';
6
- /**
7
- * Check if a value matches an expected type or schema
8
- *
9
- * Uses AI-powered validation for complex types and schemas.
10
- * Can also perform type coercion when enabled.
11
- *
12
- * @param value - The value to check
13
- * @param type - Type name or schema to validate against
14
- * @param options - Validation options
15
- * @returns Promise resolving to validation result
16
- *
17
- * @example
18
- * ```ts
19
- * // Simple type checking
20
- * const result = await is('hello@example.com', 'email')
21
- * console.log(result.valid) // true
22
- * ```
23
- *
24
- * @example
25
- * ```ts
26
- * // Schema validation
27
- * const result = await is(
28
- * { name: 'John', age: 30 },
29
- * {
30
- * name: 'Full name',
31
- * age: 'Age in years (number)',
32
- * email: 'Email address',
33
- * }
34
- * )
35
- * console.log(result.valid) // false - missing email
36
- * console.log(result.errors) // ['Missing required field: email']
37
- * ```
38
- *
39
- * @example
40
- * ```ts
41
- * // With coercion
42
- * const result = await is('123', 'number', { coerce: true })
43
- * console.log(result.valid) // true
44
- * console.log(result.value) // 123 (as number)
45
- * ```
46
- */
47
- export async function is(value, type, options = {}) {
48
- const { coerce = false, strict = false } = options;
49
- // Handle simple type strings
50
- if (typeof type === 'string') {
51
- return validateSimpleType(value, type, { coerce, strict });
52
- }
53
- // Handle schema validation
54
- return validateSchema(value, type, { coerce, strict });
55
- }
56
- /**
57
- * Validate against a simple type name
58
- */
59
- async function validateSimpleType(value, type, options) {
60
- const { coerce, strict } = options;
61
- // Built-in JavaScript types
62
- const builtInTypes = {
63
- string: (v) => typeof v === 'string',
64
- number: (v) => typeof v === 'number' && !isNaN(v),
65
- boolean: (v) => typeof v === 'boolean',
66
- object: (v) => typeof v === 'object' && v !== null && !Array.isArray(v),
67
- array: (v) => Array.isArray(v),
68
- null: (v) => v === null,
69
- undefined: (v) => v === undefined,
70
- function: (v) => typeof v === 'function',
71
- };
72
- // Check built-in types first
73
- if (type in builtInTypes) {
74
- const isValid = builtInTypes[type](value);
75
- if (!isValid && coerce) {
76
- // Try to coerce the value
77
- const coerced = coerceValue(value, type);
78
- if (coerced.success) {
79
- return {
80
- valid: true,
81
- value: coerced.value,
82
- };
83
- }
84
- }
85
- return {
86
- valid: isValid,
87
- value: isValid ? value : undefined,
88
- errors: isValid ? undefined : [`Value is not a valid ${type}`],
89
- };
90
- }
91
- // Use AI for complex type validation
92
- const result = await generateObject({
93
- model: 'sonnet',
94
- schema: {
95
- valid: 'Whether the value matches the expected type (boolean)',
96
- errors: ['List of validation errors if invalid'],
97
- coercedValue: coerce ? 'The value coerced to the expected type' : undefined,
98
- },
99
- system: `You are a type validation expert. Determine if a value matches an expected type.
100
-
101
- ${coerce ? 'If the value can be coerced to the expected type, provide the coerced value.' : ''}
102
- ${strict ? 'Be strict in your validation - require exact type matches.' : 'Be flexible - allow reasonable type conversions.'}`,
103
- prompt: `Validate if this value matches the expected type:
104
-
105
- Value: ${JSON.stringify(value)}
106
- Type: ${type}
107
-
108
- Determine if the value is valid for this type.`,
109
- });
110
- const validation = result.object;
111
- return {
112
- valid: validation.valid,
113
- value: coerce && validation.coercedValue !== undefined ? validation.coercedValue : value,
114
- errors: validation.valid ? undefined : validation.errors,
115
- };
116
- }
117
- /**
118
- * Validate against a schema
119
- */
120
- async function validateSchema(value, schema, options) {
121
- const { coerce, strict } = options;
122
- try {
123
- // Convert SimpleSchema to Zod schema
124
- const zodSchema = convertSchema(schema);
125
- // Parse the value
126
- const parsed = zodSchema.parse(value);
127
- return {
128
- valid: true,
129
- value: parsed,
130
- };
131
- }
132
- catch (error) {
133
- if (strict) {
134
- return {
135
- valid: false,
136
- errors: [error.message],
137
- };
138
- }
139
- // Use AI for more flexible validation
140
- const result = await generateObject({
141
- model: 'sonnet',
142
- schema: {
143
- valid: 'Whether the value matches the schema (boolean)',
144
- errors: ['List of validation errors'],
145
- coercedValue: coerce ? 'The value with corrections/coercions applied' : undefined,
146
- },
147
- system: `You are a schema validation expert. Validate a value against a schema.
148
-
149
- ${coerce ? 'Try to coerce the value to match the schema where reasonable.' : ''}
150
- Be helpful - provide clear error messages.`,
151
- prompt: `Validate this value against the schema:
152
-
153
- Value:
154
- ${JSON.stringify(value, null, 2)}
155
-
156
- Schema:
157
- ${JSON.stringify(schema, null, 2)}
158
-
159
- Check if the value matches the schema structure and types.`,
160
- });
161
- const validation = result.object;
162
- return {
163
- valid: validation.valid,
164
- value: coerce && validation.coercedValue !== undefined ? validation.coercedValue : value,
165
- errors: validation.valid ? undefined : validation.errors,
166
- };
167
- }
168
- }
169
- /**
170
- * Try to coerce a value to a specific type
171
- */
172
- function coerceValue(value, type) {
173
- try {
174
- switch (type) {
175
- case 'string':
176
- return { success: true, value: String(value) };
177
- case 'number':
178
- const num = Number(value);
179
- return { success: !isNaN(num), value: num };
180
- case 'boolean':
181
- if (typeof value === 'string') {
182
- const lower = value.toLowerCase();
183
- if (lower === 'true' || lower === '1') {
184
- return { success: true, value: true };
185
- }
186
- if (lower === 'false' || lower === '0') {
187
- return { success: true, value: false };
188
- }
189
- }
190
- return { success: true, value: Boolean(value) };
191
- case 'array':
192
- if (Array.isArray(value)) {
193
- return { success: true, value };
194
- }
195
- return { success: true, value: [value] };
196
- default:
197
- return { success: false };
198
- }
199
- }
200
- catch {
201
- return { success: false };
202
- }
203
- }
204
- /**
205
- * Check if a value is valid email
206
- *
207
- * @param value - Value to check
208
- * @returns Promise resolving to validation result
209
- *
210
- * @example
211
- * ```ts
212
- * const result = await is.email('test@example.com')
213
- * console.log(result.valid) // true
214
- * ```
215
- */
216
- is.email = async (value) => {
217
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
218
- const valid = typeof value === 'string' && emailRegex.test(value);
219
- return {
220
- valid,
221
- value: valid ? value : undefined,
222
- errors: valid ? undefined : ['Invalid email format'],
223
- };
224
- };
225
- /**
226
- * Check if a value is a valid URL
227
- *
228
- * @param value - Value to check
229
- * @returns Promise resolving to validation result
230
- */
231
- is.url = async (value) => {
232
- try {
233
- if (typeof value !== 'string') {
234
- return {
235
- valid: false,
236
- errors: ['Value must be a string'],
237
- };
238
- }
239
- new URL(value);
240
- return {
241
- valid: true,
242
- value,
243
- };
244
- }
245
- catch {
246
- return {
247
- valid: false,
248
- errors: ['Invalid URL format'],
249
- };
250
- }
251
- };
252
- /**
253
- * Check if a value is a valid date
254
- *
255
- * @param value - Value to check
256
- * @param options - Validation options
257
- * @returns Promise resolving to validation result
258
- */
259
- is.date = async (value, options = {}) => {
260
- const { coerce } = options;
261
- if (value instanceof Date) {
262
- return {
263
- valid: !isNaN(value.getTime()),
264
- value,
265
- errors: isNaN(value.getTime()) ? ['Invalid date'] : undefined,
266
- };
267
- }
268
- if (coerce) {
269
- try {
270
- const date = new Date(value);
271
- if (!isNaN(date.getTime())) {
272
- return {
273
- valid: true,
274
- value: date,
275
- };
276
- }
277
- }
278
- catch {
279
- // Fall through to invalid
280
- }
281
- }
282
- return {
283
- valid: false,
284
- errors: ['Invalid date'],
285
- };
286
- };
287
- /**
288
- * Check if a value matches a custom validation function
289
- *
290
- * @param value - Value to check
291
- * @param validator - Validation function
292
- * @returns Promise resolving to validation result
293
- *
294
- * @example
295
- * ```ts
296
- * const result = await is.custom(
297
- * 42,
298
- * (v) => typeof v === 'number' && v > 0 && v < 100
299
- * )
300
- * ```
301
- */
302
- is.custom = async (value, validator) => {
303
- try {
304
- const valid = await validator(value);
305
- return {
306
- valid,
307
- value: valid ? value : undefined,
308
- errors: valid ? undefined : ['Custom validation failed'],
309
- };
310
- }
311
- catch (error) {
312
- return {
313
- valid: false,
314
- errors: [error.message],
315
- };
316
- }
317
- };