@cloudwerk/service 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Squirrelsoft Dev Tools
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,574 @@
1
+ /**
2
+ * @cloudwerk/service - Type Definitions
3
+ *
4
+ * Core types for service extraction and RPC.
5
+ */
6
+ /**
7
+ * Type that can be either a value or a Promise of that value.
8
+ */
9
+ type Awaitable<T> = T | Promise<T>;
10
+ /**
11
+ * Extracts the method signatures from a service methods object.
12
+ */
13
+ type ServiceMethods = Record<string, (...args: unknown[]) => Awaitable<unknown>>;
14
+ /**
15
+ * Context provided to service method calls.
16
+ */
17
+ interface ServiceMethodContext {
18
+ /** Cloudflare environment bindings */
19
+ env: Record<string, unknown>;
20
+ }
21
+ /**
22
+ * Lifecycle hooks for service methods.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * export default defineService({
27
+ * methods: { ... },
28
+ * hooks: {
29
+ * onInit: async () => {
30
+ * console.log('Service initialized')
31
+ * },
32
+ * onBefore: async (method, args) => {
33
+ * console.log(`Calling ${method}`)
34
+ * },
35
+ * onAfter: async (method, result) => {
36
+ * console.log(`${method} returned`, result)
37
+ * },
38
+ * onError: async (method, error) => {
39
+ * console.error(`${method} failed`, error)
40
+ * },
41
+ * },
42
+ * })
43
+ * ```
44
+ */
45
+ interface ServiceHooks {
46
+ /**
47
+ * Called once when the service is initialized.
48
+ * Runs before any method calls.
49
+ */
50
+ onInit?: () => Awaitable<void>;
51
+ /**
52
+ * Called before each method invocation.
53
+ *
54
+ * @param method - The name of the method being called
55
+ * @param args - Arguments passed to the method
56
+ */
57
+ onBefore?: (method: string, args: unknown[]) => Awaitable<void>;
58
+ /**
59
+ * Called after each successful method invocation.
60
+ *
61
+ * @param method - The name of the method that was called
62
+ * @param result - The return value of the method
63
+ */
64
+ onAfter?: (method: string, result: unknown) => Awaitable<void>;
65
+ /**
66
+ * Called when a method throws an error.
67
+ *
68
+ * @param method - The name of the method that threw
69
+ * @param error - The error that was thrown
70
+ */
71
+ onError?: (method: string, error: Error) => Awaitable<void>;
72
+ }
73
+ /**
74
+ * Configuration for service extraction to a separate Worker.
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * export default defineService({
79
+ * methods: { ... },
80
+ * config: {
81
+ * extraction: {
82
+ * workerName: 'email-service',
83
+ * bindings: ['DB', 'EMAIL_API_KEY'],
84
+ * }
85
+ * }
86
+ * })
87
+ * ```
88
+ */
89
+ interface ServiceExtractionConfig {
90
+ /**
91
+ * Name of the extracted Worker.
92
+ * Used as the service name in wrangler.toml.
93
+ *
94
+ * @default Derived from directory name (e.g., 'email' -> 'email-service')
95
+ */
96
+ workerName?: string;
97
+ /**
98
+ * List of binding names this service needs.
99
+ * These will be copied to the extracted Worker's wrangler.toml.
100
+ *
101
+ * @example ['DB', 'EMAIL_API_KEY', 'STRIPE_SECRET']
102
+ */
103
+ bindings?: string[];
104
+ }
105
+ /**
106
+ * Full service configuration.
107
+ */
108
+ interface ServiceProcessingConfig {
109
+ /**
110
+ * Extraction configuration for when the service is deployed
111
+ * as a separate Worker.
112
+ */
113
+ extraction?: ServiceExtractionConfig;
114
+ }
115
+ /**
116
+ * Configuration for defining a service.
117
+ *
118
+ * @typeParam T - The methods object type
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * // app/services/email/service.ts
123
+ * import { defineService } from '@cloudwerk/service'
124
+ *
125
+ * export default defineService({
126
+ * methods: {
127
+ * async send({ to, subject, body }) {
128
+ * await sendEmail(to, subject, body)
129
+ * return { success: true, messageId: crypto.randomUUID() }
130
+ * },
131
+ * async sendBatch(emails) {
132
+ * return Promise.all(emails.map(e => this.send(e)))
133
+ * }
134
+ * },
135
+ *
136
+ * hooks: {
137
+ * onBefore: async (method, args) => {
138
+ * console.log(`[email] ${method} called`)
139
+ * }
140
+ * },
141
+ *
142
+ * config: {
143
+ * extraction: {
144
+ * workerName: 'email-service',
145
+ * bindings: ['RESEND_API_KEY'],
146
+ * }
147
+ * }
148
+ * })
149
+ * ```
150
+ */
151
+ interface ServiceConfig<T extends ServiceMethods = ServiceMethods> {
152
+ /**
153
+ * Optional service name override.
154
+ * By default, the service name is derived from the directory name.
155
+ * - `app/services/email/service.ts` -> `email`
156
+ * - `app/services/user-management/service.ts` -> `userManagement`
157
+ */
158
+ name?: string;
159
+ /**
160
+ * The methods exposed by this service.
161
+ * Each method receives arguments and returns a value or Promise.
162
+ *
163
+ * Methods can access `this.env` for Cloudflare bindings when running
164
+ * in extracted mode.
165
+ */
166
+ methods: T;
167
+ /**
168
+ * Lifecycle hooks for observability and side effects.
169
+ */
170
+ hooks?: ServiceHooks;
171
+ /**
172
+ * Service configuration including extraction settings.
173
+ */
174
+ config?: ServiceProcessingConfig;
175
+ }
176
+ /**
177
+ * A defined service, returned by defineService().
178
+ *
179
+ * @typeParam T - The methods object type
180
+ */
181
+ interface ServiceDefinition<T extends ServiceMethods = ServiceMethods> {
182
+ /** Internal marker identifying this as a service definition */
183
+ readonly __brand: 'cloudwerk-service';
184
+ /** Service name (derived from directory or explicitly set) */
185
+ readonly name: string | undefined;
186
+ /** The service methods */
187
+ readonly methods: T;
188
+ /** Lifecycle hooks */
189
+ readonly hooks: ServiceHooks | undefined;
190
+ /** Processing configuration */
191
+ readonly config: ServiceProcessingConfig;
192
+ }
193
+ /**
194
+ * A scanned service from the app/services/ directory.
195
+ */
196
+ interface ScannedService {
197
+ /** Service name derived from directory (e.g., 'email', 'userManagement') */
198
+ name: string;
199
+ /** Relative path from app/services/ (e.g., 'email/service.ts') */
200
+ relativePath: string;
201
+ /** Absolute filesystem path */
202
+ absolutePath: string;
203
+ /** Directory name (e.g., 'email') */
204
+ directoryName: string;
205
+ /** File extension (e.g., '.ts') */
206
+ extension: string;
207
+ }
208
+ /**
209
+ * Result of scanning the app/services/ directory.
210
+ */
211
+ interface ServiceScanResult {
212
+ /** All discovered service files */
213
+ services: ScannedService[];
214
+ }
215
+ /**
216
+ * Extraction mode for a service.
217
+ */
218
+ type ServiceMode = 'local' | 'extracted';
219
+ /**
220
+ * A compiled service entry in the manifest.
221
+ */
222
+ interface ServiceEntry {
223
+ /** Service name derived from directory (e.g., 'email', 'userManagement') */
224
+ name: string;
225
+ /** Binding name for wrangler.toml (e.g., 'EMAIL_SERVICE') */
226
+ bindingName: string;
227
+ /** Worker name when extracted (e.g., 'email-service') */
228
+ workerName: string;
229
+ /** Entrypoint class name for WorkerEntrypoint (e.g., 'EmailService') */
230
+ entrypointClass: string;
231
+ /** Relative path to the service definition file */
232
+ filePath: string;
233
+ /** Absolute path to the service definition file */
234
+ absolutePath: string;
235
+ /** Current extraction mode */
236
+ mode: ServiceMode;
237
+ /** List of method names exposed by this service */
238
+ methodNames: string[];
239
+ /** Bindings required by this service */
240
+ requiredBindings: string[];
241
+ /** Whether hooks are defined */
242
+ hasHooks: boolean;
243
+ }
244
+ /**
245
+ * Validation error for a service definition.
246
+ */
247
+ interface ServiceValidationError {
248
+ /** Service file path */
249
+ file: string;
250
+ /** Error message */
251
+ message: string;
252
+ /** Error code for programmatic handling */
253
+ code: 'NO_METHODS' | 'INVALID_CONFIG' | 'DUPLICATE_NAME' | 'INVALID_NAME' | 'INVALID_METHOD';
254
+ }
255
+ /**
256
+ * Validation warning for a service definition.
257
+ */
258
+ interface ServiceValidationWarning {
259
+ /** Service file path */
260
+ file: string;
261
+ /** Warning message */
262
+ message: string;
263
+ /** Warning code */
264
+ code: 'NO_HOOKS' | 'MISSING_BINDINGS' | 'EMPTY_METHODS';
265
+ }
266
+ /**
267
+ * Complete service manifest generated during build.
268
+ */
269
+ interface ServiceManifest {
270
+ /** All compiled service entries */
271
+ services: ServiceEntry[];
272
+ /** Validation errors (service won't be registered) */
273
+ errors: ServiceValidationError[];
274
+ /** Validation warnings (service will be registered with warning) */
275
+ warnings: ServiceValidationWarning[];
276
+ /** When the manifest was generated */
277
+ generatedAt: Date;
278
+ /** Root directory of the app */
279
+ rootDir: string;
280
+ }
281
+ /**
282
+ * Service mode configuration in cloudwerk.config.ts.
283
+ */
284
+ interface ServicesConfigEntry {
285
+ /** Extraction mode for this specific service */
286
+ mode: ServiceMode;
287
+ }
288
+ /**
289
+ * Top-level services configuration.
290
+ *
291
+ * @example
292
+ * ```typescript
293
+ * // cloudwerk.config.ts
294
+ * export default defineConfig({
295
+ * services: {
296
+ * mode: 'hybrid',
297
+ * email: { mode: 'extracted' },
298
+ * payments: { mode: 'extracted' },
299
+ * users: { mode: 'local' },
300
+ * }
301
+ * })
302
+ * ```
303
+ */
304
+ interface ServicesConfig {
305
+ /**
306
+ * Default mode for all services.
307
+ * - 'local': All services run in the main Worker (direct calls)
308
+ * - 'extracted': All services run as separate Workers (RPC via service bindings)
309
+ * - 'hybrid': Use per-service configuration
310
+ *
311
+ * @default 'local'
312
+ */
313
+ mode?: 'local' | 'extracted' | 'hybrid';
314
+ /**
315
+ * Per-service mode overrides.
316
+ * Keys are service names (e.g., 'email', 'userManagement').
317
+ */
318
+ [serviceName: string]: ServicesConfigEntry | string | undefined;
319
+ }
320
+
321
+ /**
322
+ * @cloudwerk/service - Error Classes
323
+ *
324
+ * Custom error classes for service operations.
325
+ */
326
+ /**
327
+ * Base error class for service-related errors.
328
+ */
329
+ declare class ServiceError extends Error {
330
+ /** Error code for programmatic handling */
331
+ readonly code: string;
332
+ constructor(code: string, message: string, options?: ErrorOptions);
333
+ }
334
+ /**
335
+ * Error thrown when a service has no methods defined.
336
+ */
337
+ declare class ServiceNoMethodsError extends ServiceError {
338
+ constructor(serviceName: string);
339
+ }
340
+ /**
341
+ * Error thrown when a service method is invalid.
342
+ */
343
+ declare class ServiceInvalidMethodError extends ServiceError {
344
+ /** The method name that is invalid */
345
+ readonly methodName: string;
346
+ constructor(serviceName: string, methodName: string, reason: string);
347
+ }
348
+ /**
349
+ * Error thrown when service configuration is invalid.
350
+ */
351
+ declare class ServiceConfigError extends ServiceError {
352
+ /** The configuration field that is invalid */
353
+ readonly field?: string;
354
+ constructor(message: string, field?: string);
355
+ }
356
+ /**
357
+ * Error thrown when accessing a service outside of request context.
358
+ */
359
+ declare class ServiceContextError extends ServiceError {
360
+ constructor();
361
+ }
362
+ /**
363
+ * Error thrown when a service binding is not found.
364
+ */
365
+ declare class ServiceNotFoundError extends ServiceError {
366
+ /** The service name that was not found */
367
+ readonly serviceName: string;
368
+ /** Available service names */
369
+ readonly availableServices: string[];
370
+ constructor(serviceName: string, availableServices: string[]);
371
+ }
372
+ /**
373
+ * Error thrown when a service method call fails.
374
+ */
375
+ declare class ServiceMethodError extends ServiceError {
376
+ /** The service name */
377
+ readonly serviceName: string;
378
+ /** The method name that failed */
379
+ readonly methodName: string;
380
+ constructor(serviceName: string, methodName: string, message: string, options?: ErrorOptions);
381
+ }
382
+ /**
383
+ * Error thrown when service initialization fails.
384
+ */
385
+ declare class ServiceInitError extends ServiceError {
386
+ /** The service name */
387
+ readonly serviceName: string;
388
+ constructor(serviceName: string, message: string, options?: ErrorOptions);
389
+ }
390
+
391
+ /**
392
+ * @cloudwerk/service - defineService()
393
+ *
394
+ * Factory function for creating service definitions.
395
+ */
396
+
397
+ /**
398
+ * Define a service with methods that can be called locally or via RPC.
399
+ *
400
+ * This function creates a service definition that will be automatically
401
+ * discovered and registered by Cloudwerk during build. Services can run
402
+ * locally (direct function calls) or be extracted to separate Workers
403
+ * (using Cloudflare's service binding RPC).
404
+ *
405
+ * @typeParam T - The methods object type
406
+ * @param config - Service configuration
407
+ * @returns Service definition
408
+ *
409
+ * @example
410
+ * ```typescript
411
+ * // app/services/email/service.ts
412
+ * import { defineService } from '@cloudwerk/service'
413
+ *
414
+ * export default defineService({
415
+ * methods: {
416
+ * async send({ to, subject, body }) {
417
+ * // Send email via API
418
+ * const response = await fetch('https://api.resend.com/emails', {
419
+ * method: 'POST',
420
+ * headers: { 'Authorization': `Bearer ${this.env.RESEND_API_KEY}` },
421
+ * body: JSON.stringify({ to, subject, html: body }),
422
+ * })
423
+ * const data = await response.json()
424
+ * return { success: true, messageId: data.id }
425
+ * },
426
+ *
427
+ * async sendBatch(emails) {
428
+ * return Promise.all(emails.map(e => this.send(e)))
429
+ * }
430
+ * }
431
+ * })
432
+ * ```
433
+ *
434
+ * @example
435
+ * ```typescript
436
+ * // With hooks and extraction config
437
+ * import { defineService } from '@cloudwerk/service'
438
+ *
439
+ * export default defineService({
440
+ * methods: {
441
+ * async processPayment({ amount, currency, customerId }) {
442
+ * // Process payment with Stripe
443
+ * return { chargeId: '...' }
444
+ * }
445
+ * },
446
+ *
447
+ * hooks: {
448
+ * onInit: async () => {
449
+ * console.log('Payment service initialized')
450
+ * },
451
+ * onBefore: async (method, args) => {
452
+ * console.log(`[payment] ${method} called with`, args)
453
+ * },
454
+ * onError: async (method, error) => {
455
+ * // Report to error tracking
456
+ * await reportError('payment', method, error)
457
+ * }
458
+ * },
459
+ *
460
+ * config: {
461
+ * extraction: {
462
+ * workerName: 'payment-service',
463
+ * bindings: ['STRIPE_SECRET_KEY', 'DB'],
464
+ * }
465
+ * }
466
+ * })
467
+ * ```
468
+ */
469
+ declare function defineService<T extends ServiceMethods>(config: ServiceConfig<T>): ServiceDefinition<T>;
470
+ /**
471
+ * Check if a value is a service definition created by defineService().
472
+ *
473
+ * @param value - Value to check
474
+ * @returns true if value is a ServiceDefinition
475
+ */
476
+ declare function isServiceDefinition(value: unknown): value is ServiceDefinition;
477
+
478
+ /**
479
+ * @cloudwerk/service - Hooks Manager
480
+ *
481
+ * Manages lifecycle hook execution for services.
482
+ */
483
+
484
+ /**
485
+ * Manages lifecycle hook execution for a service.
486
+ *
487
+ * Provides methods to safely execute hooks with error handling,
488
+ * and tracks initialization state.
489
+ *
490
+ * @example
491
+ * ```typescript
492
+ * const manager = createHooksManager(service.hooks)
493
+ *
494
+ * // Initialize once
495
+ * await manager.runInit()
496
+ *
497
+ * // Wrap method calls
498
+ * await manager.runBefore('send', [{ to: 'user@example.com' }])
499
+ * const result = await service.methods.send({ to: 'user@example.com' })
500
+ * await manager.runAfter('send', result)
501
+ * ```
502
+ */
503
+ declare class HooksManager {
504
+ private readonly hooks;
505
+ private initialized;
506
+ constructor(hooks: ServiceHooks | undefined);
507
+ /**
508
+ * Whether hooks are defined for this manager.
509
+ */
510
+ get hasHooks(): boolean;
511
+ /**
512
+ * Whether the service has been initialized.
513
+ */
514
+ get isInitialized(): boolean;
515
+ /**
516
+ * Run the onInit hook if defined.
517
+ * Only runs once per manager instance.
518
+ *
519
+ * @returns true if hook ran successfully or wasn't defined, false if already initialized
520
+ */
521
+ runInit(): Promise<boolean>;
522
+ /**
523
+ * Run the onBefore hook if defined.
524
+ *
525
+ * @param method - The method name being called
526
+ * @param args - Arguments passed to the method
527
+ */
528
+ runBefore(method: string, args: unknown[]): Promise<void>;
529
+ /**
530
+ * Run the onAfter hook if defined.
531
+ *
532
+ * @param method - The method name that was called
533
+ * @param result - The return value of the method
534
+ */
535
+ runAfter(method: string, result: unknown): Promise<void>;
536
+ /**
537
+ * Run the onError hook if defined.
538
+ *
539
+ * @param method - The method name that threw
540
+ * @param error - The error that was thrown
541
+ */
542
+ runError(method: string, error: Error): Promise<void>;
543
+ /**
544
+ * Execute a method with full hook lifecycle.
545
+ *
546
+ * Runs onBefore, executes the method, then runs either onAfter (success)
547
+ * or onError (failure).
548
+ *
549
+ * @param method - The method name
550
+ * @param args - Arguments for the method
551
+ * @param fn - The method function to execute
552
+ * @returns The method's return value
553
+ * @throws Re-throws any error from the method after running onError
554
+ *
555
+ * @example
556
+ * ```typescript
557
+ * const result = await manager.executeWithHooks(
558
+ * 'send',
559
+ * [{ to: 'user@example.com' }],
560
+ * async () => service.methods.send({ to: 'user@example.com' })
561
+ * )
562
+ * ```
563
+ */
564
+ executeWithHooks<T>(method: string, args: unknown[], fn: () => Promise<T>): Promise<T>;
565
+ }
566
+ /**
567
+ * Create a new hooks manager for a service.
568
+ *
569
+ * @param hooks - The service hooks configuration
570
+ * @returns A new HooksManager instance
571
+ */
572
+ declare function createHooksManager(hooks: ServiceHooks | undefined): HooksManager;
573
+
574
+ export { type Awaitable, HooksManager, type ScannedService, type ServiceConfig, ServiceConfigError, ServiceContextError, type ServiceDefinition, type ServiceEntry, ServiceError, type ServiceExtractionConfig, type ServiceHooks, ServiceInitError, ServiceInvalidMethodError, type ServiceManifest, type ServiceMethodContext, ServiceMethodError, type ServiceMethods, type ServiceMode, ServiceNoMethodsError, ServiceNotFoundError, type ServiceProcessingConfig, type ServiceScanResult, type ServiceValidationError, type ServiceValidationWarning, type ServicesConfig, type ServicesConfigEntry, createHooksManager, defineService, isServiceDefinition };
package/dist/index.js ADDED
@@ -0,0 +1,334 @@
1
+ // src/errors.ts
2
+ var ServiceError = class extends Error {
3
+ /** Error code for programmatic handling */
4
+ code;
5
+ constructor(code, message, options) {
6
+ super(message, options);
7
+ this.name = "ServiceError";
8
+ this.code = code;
9
+ }
10
+ };
11
+ var ServiceNoMethodsError = class extends ServiceError {
12
+ constructor(serviceName) {
13
+ super(
14
+ "NO_METHODS",
15
+ `Service '${serviceName}' must define at least one method`
16
+ );
17
+ this.name = "ServiceNoMethodsError";
18
+ }
19
+ };
20
+ var ServiceInvalidMethodError = class extends ServiceError {
21
+ /** The method name that is invalid */
22
+ methodName;
23
+ constructor(serviceName, methodName, reason) {
24
+ super(
25
+ "INVALID_METHOD",
26
+ `Service '${serviceName}' method '${methodName}' is invalid: ${reason}`
27
+ );
28
+ this.name = "ServiceInvalidMethodError";
29
+ this.methodName = methodName;
30
+ }
31
+ };
32
+ var ServiceConfigError = class extends ServiceError {
33
+ /** The configuration field that is invalid */
34
+ field;
35
+ constructor(message, field) {
36
+ super("CONFIG_ERROR", message);
37
+ this.name = "ServiceConfigError";
38
+ this.field = field;
39
+ }
40
+ };
41
+ var ServiceContextError = class extends ServiceError {
42
+ constructor() {
43
+ super(
44
+ "CONTEXT_ERROR",
45
+ "Service accessed outside of request handler. Services can only be accessed during request handling."
46
+ );
47
+ this.name = "ServiceContextError";
48
+ }
49
+ };
50
+ var ServiceNotFoundError = class extends ServiceError {
51
+ /** The service name that was not found */
52
+ serviceName;
53
+ /** Available service names */
54
+ availableServices;
55
+ constructor(serviceName, availableServices) {
56
+ const available = availableServices.length > 0 ? `Available services: ${availableServices.join(", ")}` : "No services are configured";
57
+ super(
58
+ "SERVICE_NOT_FOUND",
59
+ `Service '${serviceName}' not found in environment. ${available}`
60
+ );
61
+ this.name = "ServiceNotFoundError";
62
+ this.serviceName = serviceName;
63
+ this.availableServices = availableServices;
64
+ }
65
+ };
66
+ var ServiceMethodError = class extends ServiceError {
67
+ /** The service name */
68
+ serviceName;
69
+ /** The method name that failed */
70
+ methodName;
71
+ constructor(serviceName, methodName, message, options) {
72
+ super(
73
+ "METHOD_ERROR",
74
+ `Service '${serviceName}.${methodName}' failed: ${message}`,
75
+ options
76
+ );
77
+ this.name = "ServiceMethodError";
78
+ this.serviceName = serviceName;
79
+ this.methodName = methodName;
80
+ }
81
+ };
82
+ var ServiceInitError = class extends ServiceError {
83
+ /** The service name */
84
+ serviceName;
85
+ constructor(serviceName, message, options) {
86
+ super(
87
+ "INIT_ERROR",
88
+ `Service '${serviceName}' failed to initialize: ${message}`,
89
+ options
90
+ );
91
+ this.name = "ServiceInitError";
92
+ this.serviceName = serviceName;
93
+ }
94
+ };
95
+
96
+ // src/define-service.ts
97
+ var DEFAULT_CONFIG = {
98
+ extraction: void 0
99
+ };
100
+ function validateConfig(config) {
101
+ if (!config.methods || typeof config.methods !== "object") {
102
+ throw new ServiceNoMethodsError(config.name || "unknown");
103
+ }
104
+ const methodNames = Object.keys(config.methods);
105
+ if (methodNames.length === 0) {
106
+ throw new ServiceNoMethodsError(config.name || "unknown");
107
+ }
108
+ for (const name of methodNames) {
109
+ const method = config.methods[name];
110
+ if (typeof method !== "function") {
111
+ throw new ServiceInvalidMethodError(
112
+ config.name || "unknown",
113
+ name,
114
+ "must be a function"
115
+ );
116
+ }
117
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
118
+ throw new ServiceInvalidMethodError(
119
+ config.name || "unknown",
120
+ name,
121
+ "must be a valid JavaScript identifier"
122
+ );
123
+ }
124
+ const reserved = ["constructor", "prototype", "__proto__", "fetch"];
125
+ if (reserved.includes(name)) {
126
+ throw new ServiceInvalidMethodError(
127
+ config.name || "unknown",
128
+ name,
129
+ `'${name}' is a reserved name`
130
+ );
131
+ }
132
+ }
133
+ if (config.name !== void 0) {
134
+ if (typeof config.name !== "string" || config.name.length === 0) {
135
+ throw new ServiceConfigError("name must be a non-empty string", "name");
136
+ }
137
+ if (!/^[a-z][a-zA-Z0-9-]*$/.test(config.name)) {
138
+ throw new ServiceConfigError(
139
+ "name must start with a lowercase letter and contain only letters, numbers, and hyphens",
140
+ "name"
141
+ );
142
+ }
143
+ }
144
+ if (config.config?.extraction) {
145
+ const { workerName, bindings } = config.config.extraction;
146
+ if (workerName !== void 0) {
147
+ if (typeof workerName !== "string" || workerName.length === 0) {
148
+ throw new ServiceConfigError(
149
+ "extraction.workerName must be a non-empty string",
150
+ "extraction.workerName"
151
+ );
152
+ }
153
+ if (!/^[a-z][a-z0-9-]*$/.test(workerName)) {
154
+ throw new ServiceConfigError(
155
+ "extraction.workerName must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens",
156
+ "extraction.workerName"
157
+ );
158
+ }
159
+ }
160
+ if (bindings !== void 0) {
161
+ if (!Array.isArray(bindings)) {
162
+ throw new ServiceConfigError(
163
+ "extraction.bindings must be an array",
164
+ "extraction.bindings"
165
+ );
166
+ }
167
+ for (const binding of bindings) {
168
+ if (typeof binding !== "string" || binding.length === 0) {
169
+ throw new ServiceConfigError(
170
+ "extraction.bindings must contain non-empty strings",
171
+ "extraction.bindings"
172
+ );
173
+ }
174
+ if (!/^[A-Z][A-Z0-9_]*$|^[a-z][a-zA-Z0-9]*$/.test(binding)) {
175
+ throw new ServiceConfigError(
176
+ `Invalid binding name '${binding}'. Must be SCREAMING_SNAKE_CASE or camelCase`,
177
+ "extraction.bindings"
178
+ );
179
+ }
180
+ }
181
+ }
182
+ }
183
+ if (config.hooks) {
184
+ const hookNames = ["onInit", "onBefore", "onAfter", "onError"];
185
+ for (const hookName of hookNames) {
186
+ const hook = config.hooks[hookName];
187
+ if (hook !== void 0 && typeof hook !== "function") {
188
+ throw new ServiceConfigError(
189
+ `hooks.${hookName} must be a function`,
190
+ `hooks.${hookName}`
191
+ );
192
+ }
193
+ }
194
+ }
195
+ }
196
+ function defineService(config) {
197
+ validateConfig(config);
198
+ const mergedConfig = {
199
+ ...DEFAULT_CONFIG,
200
+ ...config.config
201
+ };
202
+ const definition = {
203
+ __brand: "cloudwerk-service",
204
+ name: config.name,
205
+ methods: config.methods,
206
+ hooks: config.hooks,
207
+ config: mergedConfig
208
+ };
209
+ return definition;
210
+ }
211
+ function isServiceDefinition(value) {
212
+ return typeof value === "object" && value !== null && "__brand" in value && value.__brand === "cloudwerk-service";
213
+ }
214
+
215
+ // src/hooks/manager.ts
216
+ var HooksManager = class {
217
+ hooks;
218
+ initialized = false;
219
+ constructor(hooks) {
220
+ this.hooks = hooks;
221
+ }
222
+ /**
223
+ * Whether hooks are defined for this manager.
224
+ */
225
+ get hasHooks() {
226
+ return this.hooks !== void 0;
227
+ }
228
+ /**
229
+ * Whether the service has been initialized.
230
+ */
231
+ get isInitialized() {
232
+ return this.initialized;
233
+ }
234
+ /**
235
+ * Run the onInit hook if defined.
236
+ * Only runs once per manager instance.
237
+ *
238
+ * @returns true if hook ran successfully or wasn't defined, false if already initialized
239
+ */
240
+ async runInit() {
241
+ if (this.initialized) {
242
+ return false;
243
+ }
244
+ this.initialized = true;
245
+ if (this.hooks?.onInit) {
246
+ await this.hooks.onInit();
247
+ }
248
+ return true;
249
+ }
250
+ /**
251
+ * Run the onBefore hook if defined.
252
+ *
253
+ * @param method - The method name being called
254
+ * @param args - Arguments passed to the method
255
+ */
256
+ async runBefore(method, args) {
257
+ if (this.hooks?.onBefore) {
258
+ await this.hooks.onBefore(method, args);
259
+ }
260
+ }
261
+ /**
262
+ * Run the onAfter hook if defined.
263
+ *
264
+ * @param method - The method name that was called
265
+ * @param result - The return value of the method
266
+ */
267
+ async runAfter(method, result) {
268
+ if (this.hooks?.onAfter) {
269
+ await this.hooks.onAfter(method, result);
270
+ }
271
+ }
272
+ /**
273
+ * Run the onError hook if defined.
274
+ *
275
+ * @param method - The method name that threw
276
+ * @param error - The error that was thrown
277
+ */
278
+ async runError(method, error) {
279
+ if (this.hooks?.onError) {
280
+ await this.hooks.onError(method, error);
281
+ }
282
+ }
283
+ /**
284
+ * Execute a method with full hook lifecycle.
285
+ *
286
+ * Runs onBefore, executes the method, then runs either onAfter (success)
287
+ * or onError (failure).
288
+ *
289
+ * @param method - The method name
290
+ * @param args - Arguments for the method
291
+ * @param fn - The method function to execute
292
+ * @returns The method's return value
293
+ * @throws Re-throws any error from the method after running onError
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * const result = await manager.executeWithHooks(
298
+ * 'send',
299
+ * [{ to: 'user@example.com' }],
300
+ * async () => service.methods.send({ to: 'user@example.com' })
301
+ * )
302
+ * ```
303
+ */
304
+ async executeWithHooks(method, args, fn) {
305
+ await this.runBefore(method, args);
306
+ try {
307
+ const result = await fn();
308
+ await this.runAfter(method, result);
309
+ return result;
310
+ } catch (err) {
311
+ const error = err instanceof Error ? err : new Error(String(err));
312
+ await this.runError(method, error);
313
+ throw error;
314
+ }
315
+ }
316
+ };
317
+ function createHooksManager(hooks) {
318
+ return new HooksManager(hooks);
319
+ }
320
+ export {
321
+ HooksManager,
322
+ ServiceConfigError,
323
+ ServiceContextError,
324
+ ServiceError,
325
+ ServiceInitError,
326
+ ServiceInvalidMethodError,
327
+ ServiceMethodError,
328
+ ServiceNoMethodsError,
329
+ ServiceNotFoundError,
330
+ createHooksManager,
331
+ defineService,
332
+ isServiceDefinition
333
+ };
334
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/define-service.ts","../src/hooks/manager.ts"],"sourcesContent":["/**\n * @cloudwerk/service - Error Classes\n *\n * Custom error classes for service operations.\n */\n\n// ============================================================================\n// Base Error\n// ============================================================================\n\n/**\n * Base error class for service-related errors.\n */\nexport class ServiceError extends Error {\n /** Error code for programmatic handling */\n readonly code: string\n\n constructor(code: string, message: string, options?: ErrorOptions) {\n super(message, options)\n this.name = 'ServiceError'\n this.code = code\n }\n}\n\n// ============================================================================\n// Definition Errors\n// ============================================================================\n\n/**\n * Error thrown when a service has no methods defined.\n */\nexport class ServiceNoMethodsError extends ServiceError {\n constructor(serviceName: string) {\n super(\n 'NO_METHODS',\n `Service '${serviceName}' must define at least one method`\n )\n this.name = 'ServiceNoMethodsError'\n }\n}\n\n/**\n * Error thrown when a service method is invalid.\n */\nexport class ServiceInvalidMethodError extends ServiceError {\n /** The method name that is invalid */\n readonly methodName: string\n\n constructor(serviceName: string, methodName: string, reason: string) {\n super(\n 'INVALID_METHOD',\n `Service '${serviceName}' method '${methodName}' is invalid: ${reason}`\n )\n this.name = 'ServiceInvalidMethodError'\n this.methodName = methodName\n }\n}\n\n// ============================================================================\n// Configuration Errors\n// ============================================================================\n\n/**\n * Error thrown when service configuration is invalid.\n */\nexport class ServiceConfigError extends ServiceError {\n /** The configuration field that is invalid */\n readonly field?: string\n\n constructor(message: string, field?: string) {\n super('CONFIG_ERROR', message)\n this.name = 'ServiceConfigError'\n this.field = field\n }\n}\n\n// ============================================================================\n// Runtime Errors\n// ============================================================================\n\n/**\n * Error thrown when accessing a service outside of request context.\n */\nexport class ServiceContextError extends ServiceError {\n constructor() {\n super(\n 'CONTEXT_ERROR',\n 'Service accessed outside of request handler. Services can only be accessed during request handling.'\n )\n this.name = 'ServiceContextError'\n }\n}\n\n/**\n * Error thrown when a service binding is not found.\n */\nexport class ServiceNotFoundError extends ServiceError {\n /** The service name that was not found */\n readonly serviceName: string\n\n /** Available service names */\n readonly availableServices: string[]\n\n constructor(serviceName: string, availableServices: string[]) {\n const available =\n availableServices.length > 0\n ? `Available services: ${availableServices.join(', ')}`\n : 'No services are configured'\n\n super(\n 'SERVICE_NOT_FOUND',\n `Service '${serviceName}' not found in environment. ${available}`\n )\n this.name = 'ServiceNotFoundError'\n this.serviceName = serviceName\n this.availableServices = availableServices\n }\n}\n\n/**\n * Error thrown when a service method call fails.\n */\nexport class ServiceMethodError extends ServiceError {\n /** The service name */\n readonly serviceName: string\n\n /** The method name that failed */\n readonly methodName: string\n\n constructor(\n serviceName: string,\n methodName: string,\n message: string,\n options?: ErrorOptions\n ) {\n super(\n 'METHOD_ERROR',\n `Service '${serviceName}.${methodName}' failed: ${message}`,\n options\n )\n this.name = 'ServiceMethodError'\n this.serviceName = serviceName\n this.methodName = methodName\n }\n}\n\n/**\n * Error thrown when service initialization fails.\n */\nexport class ServiceInitError extends ServiceError {\n /** The service name */\n readonly serviceName: string\n\n constructor(serviceName: string, message: string, options?: ErrorOptions) {\n super(\n 'INIT_ERROR',\n `Service '${serviceName}' failed to initialize: ${message}`,\n options\n )\n this.name = 'ServiceInitError'\n this.serviceName = serviceName\n }\n}\n","/**\n * @cloudwerk/service - defineService()\n *\n * Factory function for creating service definitions.\n */\n\nimport type {\n ServiceConfig,\n ServiceDefinition,\n ServiceMethods,\n ServiceProcessingConfig,\n} from './types.js'\nimport {\n ServiceConfigError,\n ServiceNoMethodsError,\n ServiceInvalidMethodError,\n} from './errors.js'\n\n// ============================================================================\n// Default Configuration\n// ============================================================================\n\nconst DEFAULT_CONFIG: ServiceProcessingConfig = {\n extraction: undefined,\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\n/**\n * Validate service configuration.\n *\n * @param config - Service configuration to validate\n * @throws ServiceConfigError if configuration is invalid\n * @throws ServiceNoMethodsError if no methods are defined\n */\nfunction validateConfig<T extends ServiceMethods>(config: ServiceConfig<T>): void {\n // Must have methods defined\n if (!config.methods || typeof config.methods !== 'object') {\n throw new ServiceNoMethodsError(config.name || 'unknown')\n }\n\n const methodNames = Object.keys(config.methods)\n\n // Must have at least one method\n if (methodNames.length === 0) {\n throw new ServiceNoMethodsError(config.name || 'unknown')\n }\n\n // Validate each method is a function\n for (const name of methodNames) {\n const method = config.methods[name]\n if (typeof method !== 'function') {\n throw new ServiceInvalidMethodError(\n config.name || 'unknown',\n name,\n 'must be a function'\n )\n }\n\n // Method names should be valid identifiers\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n throw new ServiceInvalidMethodError(\n config.name || 'unknown',\n name,\n 'must be a valid JavaScript identifier'\n )\n }\n\n // Reserved method names\n const reserved = ['constructor', 'prototype', '__proto__', 'fetch']\n if (reserved.includes(name)) {\n throw new ServiceInvalidMethodError(\n config.name || 'unknown',\n name,\n `'${name}' is a reserved name`\n )\n }\n }\n\n // Validate name if provided\n if (config.name !== undefined) {\n if (typeof config.name !== 'string' || config.name.length === 0) {\n throw new ServiceConfigError('name must be a non-empty string', 'name')\n }\n\n // Service names should be camelCase or lowercase with hyphens\n if (!/^[a-z][a-zA-Z0-9-]*$/.test(config.name)) {\n throw new ServiceConfigError(\n 'name must start with a lowercase letter and contain only letters, numbers, and hyphens',\n 'name'\n )\n }\n }\n\n // Validate extraction config\n if (config.config?.extraction) {\n const { workerName, bindings } = config.config.extraction\n\n if (workerName !== undefined) {\n if (typeof workerName !== 'string' || workerName.length === 0) {\n throw new ServiceConfigError(\n 'extraction.workerName must be a non-empty string',\n 'extraction.workerName'\n )\n }\n\n // Worker names should be lowercase with hyphens\n if (!/^[a-z][a-z0-9-]*$/.test(workerName)) {\n throw new ServiceConfigError(\n 'extraction.workerName must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens',\n 'extraction.workerName'\n )\n }\n }\n\n if (bindings !== undefined) {\n if (!Array.isArray(bindings)) {\n throw new ServiceConfigError(\n 'extraction.bindings must be an array',\n 'extraction.bindings'\n )\n }\n\n for (const binding of bindings) {\n if (typeof binding !== 'string' || binding.length === 0) {\n throw new ServiceConfigError(\n 'extraction.bindings must contain non-empty strings',\n 'extraction.bindings'\n )\n }\n\n // Binding names should be SCREAMING_SNAKE_CASE or camelCase\n if (!/^[A-Z][A-Z0-9_]*$|^[a-z][a-zA-Z0-9]*$/.test(binding)) {\n throw new ServiceConfigError(\n `Invalid binding name '${binding}'. Must be SCREAMING_SNAKE_CASE or camelCase`,\n 'extraction.bindings'\n )\n }\n }\n }\n }\n\n // Validate hooks if provided\n if (config.hooks) {\n const hookNames = ['onInit', 'onBefore', 'onAfter', 'onError'] as const\n\n for (const hookName of hookNames) {\n const hook = config.hooks[hookName]\n if (hook !== undefined && typeof hook !== 'function') {\n throw new ServiceConfigError(\n `hooks.${hookName} must be a function`,\n `hooks.${hookName}`\n )\n }\n }\n }\n}\n\n// ============================================================================\n// defineService()\n// ============================================================================\n\n/**\n * Define a service with methods that can be called locally or via RPC.\n *\n * This function creates a service definition that will be automatically\n * discovered and registered by Cloudwerk during build. Services can run\n * locally (direct function calls) or be extracted to separate Workers\n * (using Cloudflare's service binding RPC).\n *\n * @typeParam T - The methods object type\n * @param config - Service configuration\n * @returns Service definition\n *\n * @example\n * ```typescript\n * // app/services/email/service.ts\n * import { defineService } from '@cloudwerk/service'\n *\n * export default defineService({\n * methods: {\n * async send({ to, subject, body }) {\n * // Send email via API\n * const response = await fetch('https://api.resend.com/emails', {\n * method: 'POST',\n * headers: { 'Authorization': `Bearer ${this.env.RESEND_API_KEY}` },\n * body: JSON.stringify({ to, subject, html: body }),\n * })\n * const data = await response.json()\n * return { success: true, messageId: data.id }\n * },\n *\n * async sendBatch(emails) {\n * return Promise.all(emails.map(e => this.send(e)))\n * }\n * }\n * })\n * ```\n *\n * @example\n * ```typescript\n * // With hooks and extraction config\n * import { defineService } from '@cloudwerk/service'\n *\n * export default defineService({\n * methods: {\n * async processPayment({ amount, currency, customerId }) {\n * // Process payment with Stripe\n * return { chargeId: '...' }\n * }\n * },\n *\n * hooks: {\n * onInit: async () => {\n * console.log('Payment service initialized')\n * },\n * onBefore: async (method, args) => {\n * console.log(`[payment] ${method} called with`, args)\n * },\n * onError: async (method, error) => {\n * // Report to error tracking\n * await reportError('payment', method, error)\n * }\n * },\n *\n * config: {\n * extraction: {\n * workerName: 'payment-service',\n * bindings: ['STRIPE_SECRET_KEY', 'DB'],\n * }\n * }\n * })\n * ```\n */\nexport function defineService<T extends ServiceMethods>(\n config: ServiceConfig<T>\n): ServiceDefinition<T> {\n // Validate configuration\n validateConfig(config)\n\n // Merge with defaults\n const mergedConfig: ServiceProcessingConfig = {\n ...DEFAULT_CONFIG,\n ...config.config,\n }\n\n // Create the definition object\n const definition: ServiceDefinition<T> = {\n __brand: 'cloudwerk-service',\n name: config.name,\n methods: config.methods,\n hooks: config.hooks,\n config: mergedConfig,\n }\n\n return definition\n}\n\n/**\n * Check if a value is a service definition created by defineService().\n *\n * @param value - Value to check\n * @returns true if value is a ServiceDefinition\n */\nexport function isServiceDefinition(\n value: unknown\n): value is ServiceDefinition {\n return (\n typeof value === 'object' &&\n value !== null &&\n '__brand' in value &&\n (value as ServiceDefinition).__brand === 'cloudwerk-service'\n )\n}\n","/**\n * @cloudwerk/service - Hooks Manager\n *\n * Manages lifecycle hook execution for services.\n */\n\nimport type { ServiceHooks } from '../types.js'\n\n/**\n * Manages lifecycle hook execution for a service.\n *\n * Provides methods to safely execute hooks with error handling,\n * and tracks initialization state.\n *\n * @example\n * ```typescript\n * const manager = createHooksManager(service.hooks)\n *\n * // Initialize once\n * await manager.runInit()\n *\n * // Wrap method calls\n * await manager.runBefore('send', [{ to: 'user@example.com' }])\n * const result = await service.methods.send({ to: 'user@example.com' })\n * await manager.runAfter('send', result)\n * ```\n */\nexport class HooksManager {\n private readonly hooks: ServiceHooks | undefined\n private initialized = false\n\n constructor(hooks: ServiceHooks | undefined) {\n this.hooks = hooks\n }\n\n /**\n * Whether hooks are defined for this manager.\n */\n get hasHooks(): boolean {\n return this.hooks !== undefined\n }\n\n /**\n * Whether the service has been initialized.\n */\n get isInitialized(): boolean {\n return this.initialized\n }\n\n /**\n * Run the onInit hook if defined.\n * Only runs once per manager instance.\n *\n * @returns true if hook ran successfully or wasn't defined, false if already initialized\n */\n async runInit(): Promise<boolean> {\n if (this.initialized) {\n return false\n }\n\n this.initialized = true\n\n if (this.hooks?.onInit) {\n await this.hooks.onInit()\n }\n\n return true\n }\n\n /**\n * Run the onBefore hook if defined.\n *\n * @param method - The method name being called\n * @param args - Arguments passed to the method\n */\n async runBefore(method: string, args: unknown[]): Promise<void> {\n if (this.hooks?.onBefore) {\n await this.hooks.onBefore(method, args)\n }\n }\n\n /**\n * Run the onAfter hook if defined.\n *\n * @param method - The method name that was called\n * @param result - The return value of the method\n */\n async runAfter(method: string, result: unknown): Promise<void> {\n if (this.hooks?.onAfter) {\n await this.hooks.onAfter(method, result)\n }\n }\n\n /**\n * Run the onError hook if defined.\n *\n * @param method - The method name that threw\n * @param error - The error that was thrown\n */\n async runError(method: string, error: Error): Promise<void> {\n if (this.hooks?.onError) {\n await this.hooks.onError(method, error)\n }\n }\n\n /**\n * Execute a method with full hook lifecycle.\n *\n * Runs onBefore, executes the method, then runs either onAfter (success)\n * or onError (failure).\n *\n * @param method - The method name\n * @param args - Arguments for the method\n * @param fn - The method function to execute\n * @returns The method's return value\n * @throws Re-throws any error from the method after running onError\n *\n * @example\n * ```typescript\n * const result = await manager.executeWithHooks(\n * 'send',\n * [{ to: 'user@example.com' }],\n * async () => service.methods.send({ to: 'user@example.com' })\n * )\n * ```\n */\n async executeWithHooks<T>(\n method: string,\n args: unknown[],\n fn: () => Promise<T>\n ): Promise<T> {\n await this.runBefore(method, args)\n\n try {\n const result = await fn()\n await this.runAfter(method, result)\n return result\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n await this.runError(method, error)\n throw error\n }\n }\n}\n\n/**\n * Create a new hooks manager for a service.\n *\n * @param hooks - The service hooks configuration\n * @returns A new HooksManager instance\n */\nexport function createHooksManager(\n hooks: ServiceHooks | undefined\n): HooksManager {\n return new HooksManager(hooks)\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@cloudwerk/service",
3
+ "version": "0.0.1",
4
+ "description": "Service extraction and RPC for Cloudwerk",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/squirrelsoft-dev/cloudwerk.git",
8
+ "directory": "packages/service"
9
+ },
10
+ "type": "module",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {
21
+ "@cloudwerk/core": "0.12.0"
22
+ },
23
+ "devDependencies": {
24
+ "typescript": "^5.4.0",
25
+ "vitest": "^1.0.0",
26
+ "tsup": "^8.0.0"
27
+ },
28
+ "peerDependencies": {
29
+ "typescript": "^5.0.0"
30
+ },
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "test": "vitest --run",
34
+ "test:watch": "vitest"
35
+ }
36
+ }