autotel-cloudflare 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +432 -0
  3. package/dist/actors.d.ts +248 -0
  4. package/dist/actors.js +1030 -0
  5. package/dist/actors.js.map +1 -0
  6. package/dist/agents.d.ts +219 -0
  7. package/dist/agents.js +276 -0
  8. package/dist/agents.js.map +1 -0
  9. package/dist/bindings.d.ts +40 -0
  10. package/dist/bindings.js +4 -0
  11. package/dist/bindings.js.map +1 -0
  12. package/dist/chunk-JDPN3HND.js +520 -0
  13. package/dist/chunk-JDPN3HND.js.map +1 -0
  14. package/dist/chunk-QXFYTHQF.js +298 -0
  15. package/dist/chunk-QXFYTHQF.js.map +1 -0
  16. package/dist/chunk-SKKRPS5K.js +50 -0
  17. package/dist/chunk-SKKRPS5K.js.map +1 -0
  18. package/dist/events.d.ts +1 -0
  19. package/dist/events.js +3 -0
  20. package/dist/events.js.map +1 -0
  21. package/dist/handlers.d.ts +121 -0
  22. package/dist/handlers.js +4 -0
  23. package/dist/handlers.js.map +1 -0
  24. package/dist/index.d.ts +144 -0
  25. package/dist/index.js +576 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/logger.d.ts +1 -0
  28. package/dist/logger.js +3 -0
  29. package/dist/logger.js.map +1 -0
  30. package/dist/sampling.d.ts +4 -0
  31. package/dist/sampling.js +3 -0
  32. package/dist/sampling.js.map +1 -0
  33. package/dist/testing.d.ts +1 -0
  34. package/dist/testing.js +3 -0
  35. package/dist/testing.js.map +1 -0
  36. package/package.json +107 -0
  37. package/src/actors/alarms.ts +225 -0
  38. package/src/actors/index.ts +36 -0
  39. package/src/actors/instrument-actor.test.ts +179 -0
  40. package/src/actors/instrument-actor.ts +574 -0
  41. package/src/actors/sockets.ts +217 -0
  42. package/src/actors/storage.ts +263 -0
  43. package/src/actors/traced-handler.ts +300 -0
  44. package/src/actors/types.ts +98 -0
  45. package/src/actors.ts +50 -0
  46. package/src/agents/index.ts +42 -0
  47. package/src/agents/otel-observability.test.ts +329 -0
  48. package/src/agents/otel-observability.ts +465 -0
  49. package/src/agents/types.ts +167 -0
  50. package/src/agents.ts +76 -0
  51. package/src/bindings/bindings.ts +621 -0
  52. package/src/bindings/common.ts +75 -0
  53. package/src/bindings/index.ts +12 -0
  54. package/src/bindings.ts +6 -0
  55. package/src/events.ts +6 -0
  56. package/src/global/cache.test.ts +292 -0
  57. package/src/global/cache.ts +164 -0
  58. package/src/global/fetch.test.ts +344 -0
  59. package/src/global/fetch.ts +134 -0
  60. package/src/global/index.ts +7 -0
  61. package/src/handlers/durable-objects.test.ts +524 -0
  62. package/src/handlers/durable-objects.ts +250 -0
  63. package/src/handlers/index.ts +6 -0
  64. package/src/handlers/workflows.ts +318 -0
  65. package/src/handlers.ts +6 -0
  66. package/src/index.ts +57 -0
  67. package/src/logger.ts +6 -0
  68. package/src/sampling.ts +6 -0
  69. package/src/testing.ts +6 -0
  70. package/src/wrappers/index.ts +8 -0
  71. package/src/wrappers/instrument.integration.test.ts +468 -0
  72. package/src/wrappers/instrument.ts +643 -0
  73. package/src/wrappers/wrap-do.ts +34 -0
  74. package/src/wrappers/wrap-module.ts +37 -0
@@ -0,0 +1,574 @@
1
+ /**
2
+ * Actor class instrumentation for @cloudflare/actors
3
+ *
4
+ * Wraps Actor lifecycle methods with OpenTelemetry tracing:
5
+ * - onInit: Traced as 'actor.lifecycle': 'init'
6
+ * - onRequest: Traced with full HTTP semantics
7
+ * - onAlarm: Traced as 'actor.lifecycle': 'alarm'
8
+ * - onPersist: Traced as 'actor.lifecycle': 'persist'
9
+ * - WebSocket methods: Traced with socket semantics
10
+ */
11
+
12
+ import {
13
+ trace,
14
+ context as api_context,
15
+ propagation,
16
+ SpanStatusCode,
17
+ SpanKind,
18
+ } from '@opentelemetry/api';
19
+ import type { ConfigurationOption } from 'autotel-edge';
20
+ import { createInitialiser, setConfig, WorkerTracer } from 'autotel-edge';
21
+ import { wrap } from '../bindings/common';
22
+ import type {
23
+ ActorConfig,
24
+ ActorConstructor,
25
+ ActorLike,
26
+ ActorLifecycle,
27
+ ActorInstrumentationOptions,
28
+ } from './types';
29
+ import { instrumentActorStorage } from './storage';
30
+ import { instrumentActorAlarms } from './alarms';
31
+ import { instrumentActorSockets } from './sockets';
32
+
33
+ /**
34
+ * Track cold starts per Actor class
35
+ */
36
+ const coldStarts = new WeakMap<object, boolean>();
37
+
38
+ function isColdStart(actorClass: object): boolean {
39
+ if (!coldStarts.has(actorClass)) {
40
+ coldStarts.set(actorClass, true);
41
+ return true;
42
+ }
43
+ return false;
44
+ }
45
+
46
+ /**
47
+ * Get the tracer instance
48
+ */
49
+ function getTracer(): WorkerTracer {
50
+ return trace.getTracer('autotel-cloudflare-actors') as WorkerTracer;
51
+ }
52
+
53
+ /**
54
+ * Default span name formatter
55
+ */
56
+ function defaultSpanNameFormatter(
57
+ actorName: string,
58
+ actorClass: string,
59
+ lifecycle: ActorLifecycle,
60
+ ): string {
61
+ const displayName = actorName || actorClass;
62
+ return `Actor ${displayName}: ${lifecycle}`;
63
+ }
64
+
65
+ /**
66
+ * Create base Actor span attributes
67
+ */
68
+ function createActorAttributes(
69
+ actorInstance: ActorLike,
70
+ actorClass: object,
71
+ lifecycle: ActorLifecycle,
72
+ ): Record<string, string | boolean | number> {
73
+ return {
74
+ 'actor.name': actorInstance.name || 'unknown',
75
+ 'actor.class': (actorClass as { name?: string }).name || 'Actor',
76
+ 'actor.lifecycle': lifecycle,
77
+ 'actor.coldstart': isColdStart(actorClass),
78
+ ...(actorInstance.identifier && { 'actor.identifier': actorInstance.identifier }),
79
+ };
80
+ }
81
+
82
+ /**
83
+ * Instrument the onInit lifecycle method
84
+ */
85
+ function instrumentOnInit(
86
+ originalMethod: () => Promise<void>,
87
+ actorInstance: ActorLike,
88
+ actorClass: object,
89
+ options: ActorInstrumentationOptions,
90
+ ): () => Promise<void> {
91
+ return async function instrumentedOnInit(): Promise<void> {
92
+ const tracer = getTracer();
93
+ const actorClassName = (actorClass as { name?: string }).name || 'Actor';
94
+ const spanName = options.spanNameFormatter
95
+ ? options.spanNameFormatter(actorInstance.name || '', 'init')
96
+ : defaultSpanNameFormatter(actorInstance.name || '', actorClassName, 'init');
97
+
98
+ return tracer.startActiveSpan(
99
+ spanName,
100
+ {
101
+ kind: SpanKind.INTERNAL,
102
+ attributes: createActorAttributes(actorInstance, actorClass, 'init'),
103
+ },
104
+ async (span) => {
105
+ try {
106
+ await originalMethod.call(actorInstance);
107
+ span.setStatus({ code: SpanStatusCode.OK });
108
+ } catch (error) {
109
+ span.recordException(error as Error);
110
+ span.setStatus({
111
+ code: SpanStatusCode.ERROR,
112
+ message: error instanceof Error ? error.message : String(error),
113
+ });
114
+ throw error;
115
+ } finally {
116
+ span.end();
117
+ }
118
+ },
119
+ );
120
+ };
121
+ }
122
+
123
+ /**
124
+ * Instrument the onRequest lifecycle method
125
+ */
126
+ function instrumentOnRequest(
127
+ originalMethod: (request: Request) => Promise<Response>,
128
+ actorInstance: ActorLike,
129
+ actorClass: object,
130
+ options: ActorInstrumentationOptions,
131
+ ): (request: Request) => Promise<Response> {
132
+ return async function instrumentedOnRequest(request: Request): Promise<Response> {
133
+ const tracer = getTracer();
134
+
135
+ // Extract parent context from request headers
136
+ const parentContext = propagation.extract(api_context.active(), request.headers);
137
+
138
+ const url = new URL(request.url);
139
+ const actorClassName = (actorClass as { name?: string }).name || 'Actor';
140
+ const spanName = options.spanNameFormatter
141
+ ? options.spanNameFormatter(actorInstance.name || '', 'request')
142
+ : `Actor ${actorInstance.name || actorClassName}: ${request.method} ${url.pathname}`;
143
+
144
+ return tracer.startActiveSpan(
145
+ spanName,
146
+ {
147
+ kind: SpanKind.SERVER,
148
+ attributes: {
149
+ ...createActorAttributes(actorInstance, actorClass, 'request'),
150
+ 'http.request.method': request.method,
151
+ 'url.full': request.url,
152
+ 'url.path': url.pathname,
153
+ 'url.query': url.search,
154
+ },
155
+ },
156
+ parentContext,
157
+ async (span) => {
158
+ try {
159
+ const response = await originalMethod.call(actorInstance, request);
160
+
161
+ span.setAttributes({
162
+ 'http.response.status_code': response.status,
163
+ });
164
+
165
+ if (response.ok) {
166
+ span.setStatus({ code: SpanStatusCode.OK });
167
+ } else {
168
+ span.setStatus({ code: SpanStatusCode.ERROR });
169
+ }
170
+
171
+ return response;
172
+ } catch (error) {
173
+ span.recordException(error as Error);
174
+ span.setStatus({
175
+ code: SpanStatusCode.ERROR,
176
+ message: error instanceof Error ? error.message : String(error),
177
+ });
178
+ throw error;
179
+ } finally {
180
+ span.end();
181
+ }
182
+ },
183
+ );
184
+ };
185
+ }
186
+
187
+ /**
188
+ * Instrument the onAlarm lifecycle method
189
+ */
190
+ function instrumentOnAlarm(
191
+ originalMethod: (alarmInfo?: unknown) => Promise<void>,
192
+ actorInstance: ActorLike,
193
+ actorClass: object,
194
+ options: ActorInstrumentationOptions,
195
+ ): (alarmInfo?: unknown) => Promise<void> {
196
+ return async function instrumentedOnAlarm(alarmInfo?: unknown): Promise<void> {
197
+ const tracer = getTracer();
198
+ const actorClassName = (actorClass as { name?: string }).name || 'Actor';
199
+ const spanName = options.spanNameFormatter
200
+ ? options.spanNameFormatter(actorInstance.name || '', 'alarm')
201
+ : defaultSpanNameFormatter(actorInstance.name || '', actorClassName, 'alarm');
202
+
203
+ return tracer.startActiveSpan(
204
+ spanName,
205
+ {
206
+ kind: SpanKind.INTERNAL,
207
+ attributes: {
208
+ ...createActorAttributes(actorInstance, actorClass, 'alarm'),
209
+ 'faas.trigger': 'timer',
210
+ },
211
+ },
212
+ async (span) => {
213
+ try {
214
+ await originalMethod.call(actorInstance, alarmInfo);
215
+ span.setStatus({ code: SpanStatusCode.OK });
216
+ } catch (error) {
217
+ span.recordException(error as Error);
218
+ span.setStatus({
219
+ code: SpanStatusCode.ERROR,
220
+ message: error instanceof Error ? error.message : String(error),
221
+ });
222
+ throw error;
223
+ } finally {
224
+ span.end();
225
+ }
226
+ },
227
+ );
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Instrument the onPersist lifecycle method
233
+ */
234
+ function instrumentOnPersist(
235
+ originalMethod: (key: string, value: unknown) => void,
236
+ actorInstance: ActorLike,
237
+ actorClass: object,
238
+ options: ActorInstrumentationOptions,
239
+ ): (key: string, value: unknown) => void {
240
+ if (!options.capturePersistEvents) {
241
+ return originalMethod;
242
+ }
243
+
244
+ return function instrumentedOnPersist(key: string, value: unknown): void {
245
+ const tracer = getTracer();
246
+ const actorClassName = (actorClass as { name?: string }).name || 'Actor';
247
+ const spanName = options.spanNameFormatter
248
+ ? options.spanNameFormatter(actorInstance.name || '', 'persist')
249
+ : `Actor ${actorInstance.name || actorClassName}: persist ${key}`;
250
+
251
+ tracer.startActiveSpan(
252
+ spanName,
253
+ {
254
+ kind: SpanKind.INTERNAL,
255
+ attributes: {
256
+ ...createActorAttributes(actorInstance, actorClass, 'persist'),
257
+ 'actor.persist.key': key,
258
+ 'actor.persist.value_type': typeof value,
259
+ },
260
+ },
261
+ (span) => {
262
+ try {
263
+ originalMethod.call(actorInstance, key, value);
264
+ span.setStatus({ code: SpanStatusCode.OK });
265
+ } catch (error) {
266
+ span.recordException(error as Error);
267
+ span.setStatus({
268
+ code: SpanStatusCode.ERROR,
269
+ message: error instanceof Error ? error.message : String(error),
270
+ });
271
+ throw error;
272
+ } finally {
273
+ span.end();
274
+ }
275
+ },
276
+ );
277
+ };
278
+ }
279
+
280
+ /**
281
+ * Instrument WebSocket lifecycle methods
282
+ */
283
+ function instrumentWebSocketConnect(
284
+ originalMethod: (ws: WebSocket, request: Request) => void,
285
+ actorInstance: ActorLike,
286
+ actorClass: object,
287
+ options: ActorInstrumentationOptions,
288
+ ): (ws: WebSocket, request: Request) => void {
289
+ return function instrumentedWebSocketConnect(ws: WebSocket, request: Request): void {
290
+ const tracer = getTracer();
291
+ const actorClassName = (actorClass as { name?: string }).name || 'Actor';
292
+ const spanName = options.spanNameFormatter
293
+ ? options.spanNameFormatter(actorInstance.name || '', 'websocket.connect')
294
+ : defaultSpanNameFormatter(actorInstance.name || '', actorClassName, 'websocket.connect');
295
+
296
+ tracer.startActiveSpan(
297
+ spanName,
298
+ {
299
+ kind: SpanKind.SERVER,
300
+ attributes: {
301
+ ...createActorAttributes(actorInstance, actorClass, 'websocket.connect'),
302
+ 'url.full': request.url,
303
+ },
304
+ },
305
+ (span) => {
306
+ try {
307
+ originalMethod.call(actorInstance, ws, request);
308
+ span.setStatus({ code: SpanStatusCode.OK });
309
+ } catch (error) {
310
+ span.recordException(error as Error);
311
+ span.setStatus({
312
+ code: SpanStatusCode.ERROR,
313
+ message: error instanceof Error ? error.message : String(error),
314
+ });
315
+ throw error;
316
+ } finally {
317
+ span.end();
318
+ }
319
+ },
320
+ );
321
+ };
322
+ }
323
+
324
+ function instrumentWebSocketMessage(
325
+ originalMethod: (ws: WebSocket, message: unknown) => void,
326
+ actorInstance: ActorLike,
327
+ actorClass: object,
328
+ options: ActorInstrumentationOptions,
329
+ ): (ws: WebSocket, message: unknown) => void {
330
+ return function instrumentedWebSocketMessage(ws: WebSocket, message: unknown): void {
331
+ const tracer = getTracer();
332
+ const actorClassName = (actorClass as { name?: string }).name || 'Actor';
333
+ const spanName = options.spanNameFormatter
334
+ ? options.spanNameFormatter(actorInstance.name || '', 'websocket.message')
335
+ : defaultSpanNameFormatter(actorInstance.name || '', actorClassName, 'websocket.message');
336
+
337
+ tracer.startActiveSpan(
338
+ spanName,
339
+ {
340
+ kind: SpanKind.SERVER,
341
+ attributes: {
342
+ ...createActorAttributes(actorInstance, actorClass, 'websocket.message'),
343
+ 'websocket.message.type': typeof message,
344
+ 'websocket.message.size':
345
+ typeof message === 'string'
346
+ ? message.length
347
+ : message instanceof ArrayBuffer
348
+ ? message.byteLength
349
+ : 0,
350
+ },
351
+ },
352
+ (span) => {
353
+ try {
354
+ originalMethod.call(actorInstance, ws, message);
355
+ span.setStatus({ code: SpanStatusCode.OK });
356
+ } catch (error) {
357
+ span.recordException(error as Error);
358
+ span.setStatus({
359
+ code: SpanStatusCode.ERROR,
360
+ message: error instanceof Error ? error.message : String(error),
361
+ });
362
+ throw error;
363
+ } finally {
364
+ span.end();
365
+ }
366
+ },
367
+ );
368
+ };
369
+ }
370
+
371
+ function instrumentWebSocketDisconnect(
372
+ originalMethod: (ws: WebSocket) => void,
373
+ actorInstance: ActorLike,
374
+ actorClass: object,
375
+ options: ActorInstrumentationOptions,
376
+ ): (ws: WebSocket) => void {
377
+ return function instrumentedWebSocketDisconnect(ws: WebSocket): void {
378
+ const tracer = getTracer();
379
+ const actorClassName = (actorClass as { name?: string }).name || 'Actor';
380
+ const spanName = options.spanNameFormatter
381
+ ? options.spanNameFormatter(actorInstance.name || '', 'websocket.disconnect')
382
+ : defaultSpanNameFormatter(actorInstance.name || '', actorClassName, 'websocket.disconnect');
383
+
384
+ tracer.startActiveSpan(
385
+ spanName,
386
+ {
387
+ kind: SpanKind.SERVER,
388
+ attributes: createActorAttributes(actorInstance, actorClass, 'websocket.disconnect'),
389
+ },
390
+ (span) => {
391
+ try {
392
+ originalMethod.call(actorInstance, ws);
393
+ span.setStatus({ code: SpanStatusCode.OK });
394
+ } catch (error) {
395
+ span.recordException(error as Error);
396
+ span.setStatus({
397
+ code: SpanStatusCode.ERROR,
398
+ message: error instanceof Error ? error.message : String(error),
399
+ });
400
+ throw error;
401
+ } finally {
402
+ span.end();
403
+ }
404
+ },
405
+ );
406
+ };
407
+ }
408
+
409
+ /**
410
+ * Instrument an Actor instance by wrapping all lifecycle methods
411
+ */
412
+ function instrumentActorInstance(
413
+ actorInstance: ActorLike,
414
+ _state: DurableObjectState,
415
+ _env: unknown,
416
+ actorClass: object,
417
+ options: ActorInstrumentationOptions,
418
+ ): ActorLike {
419
+ const instanceHandler: ProxyHandler<ActorLike> = {
420
+ get(target, prop) {
421
+ const value = Reflect.get(target, prop);
422
+
423
+ // Lifecycle methods that need instrumentation
424
+ if (prop === 'onInit' && typeof value === 'function') {
425
+ return instrumentOnInit(value.bind(target), target, actorClass, options);
426
+ }
427
+
428
+ if (prop === 'onRequest' && typeof value === 'function') {
429
+ return instrumentOnRequest(value.bind(target), target, actorClass, options);
430
+ }
431
+
432
+ if (prop === 'onAlarm' && typeof value === 'function') {
433
+ return instrumentOnAlarm(value.bind(target), target, actorClass, options);
434
+ }
435
+
436
+ if (prop === 'onPersist' && typeof value === 'function') {
437
+ return instrumentOnPersist(value.bind(target), target, actorClass, options);
438
+ }
439
+
440
+ if (prop === 'onWebSocketConnect' && typeof value === 'function') {
441
+ return instrumentWebSocketConnect(value.bind(target), target, actorClass, options);
442
+ }
443
+
444
+ if (prop === 'onWebSocketMessage' && typeof value === 'function') {
445
+ return instrumentWebSocketMessage(value.bind(target), target, actorClass, options);
446
+ }
447
+
448
+ if (prop === 'onWebSocketDisconnect' && typeof value === 'function') {
449
+ return instrumentWebSocketDisconnect(value.bind(target), target, actorClass, options);
450
+ }
451
+
452
+ // Instrument sub-components if enabled
453
+ if (prop === 'storage' && value && options.instrumentStorage !== false) {
454
+ return instrumentActorStorage(value, target, actorClass);
455
+ }
456
+
457
+ if (prop === 'alarms' && value && options.instrumentAlarms !== false) {
458
+ return instrumentActorAlarms(value, target, actorClass);
459
+ }
460
+
461
+ if (prop === 'sockets' && value && options.instrumentSockets !== false) {
462
+ return instrumentActorSockets(value, target, actorClass);
463
+ }
464
+
465
+ // Bind other methods to the target
466
+ if (typeof value === 'function') {
467
+ return value.bind(target);
468
+ }
469
+
470
+ return value;
471
+ },
472
+ };
473
+
474
+ return wrap(actorInstance, instanceHandler);
475
+ }
476
+
477
+ /**
478
+ * Instrument an Actor class for comprehensive OpenTelemetry tracing
479
+ *
480
+ * This wraps the Actor class to automatically trace all lifecycle methods:
481
+ * - onInit: Actor initialization
482
+ * - onRequest: HTTP request handling
483
+ * - onAlarm: Alarm triggers
484
+ * - onPersist: Property persistence events
485
+ * - WebSocket methods: Connection, message, disconnect
486
+ *
487
+ * It also optionally instruments:
488
+ * - actor.storage: SQL queries and storage operations
489
+ * - actor.alarms: Alarm scheduling operations
490
+ * - actor.sockets: WebSocket operations
491
+ *
492
+ * @example
493
+ * ```typescript
494
+ * import { Actor } from '@cloudflare/actors'
495
+ * import { instrumentActor } from 'autotel-cloudflare/actors'
496
+ *
497
+ * class Counter extends Actor<Env> {
498
+ * protected onInit() {
499
+ * console.log('Counter initialized')
500
+ * }
501
+ *
502
+ * protected onRequest(request: Request) {
503
+ * return new Response('count: 42')
504
+ * }
505
+ * }
506
+ *
507
+ * // Wrap the class
508
+ * export const InstrumentedCounter = instrumentActor(Counter, (env: Env) => ({
509
+ * service: { name: 'counter-actor' },
510
+ * exporter: { url: env.OTLP_ENDPOINT },
511
+ * actors: {
512
+ * instrumentStorage: true,
513
+ * capturePersistEvents: true
514
+ * }
515
+ * }))
516
+ * ```
517
+ *
518
+ * @param actorClass - The Actor class to instrument
519
+ * @param config - Configuration (static object or function)
520
+ * @returns Instrumented Actor class
521
+ */
522
+ export function instrumentActor<C extends ActorConstructor>(
523
+ actorClass: C,
524
+ config: ActorConfig | ((env: unknown, trigger?: unknown) => ActorConfig),
525
+ ): C {
526
+ const initialiser = createInitialiser(config as ConfigurationOption);
527
+
528
+ // Default options
529
+ const defaultOptions: ActorInstrumentationOptions = {
530
+ instrumentStorage: true,
531
+ instrumentAlarms: true,
532
+ instrumentSockets: true,
533
+ capturePersistEvents: true,
534
+ };
535
+
536
+ const classHandler: ProxyHandler<C> = {
537
+ construct(target, [state, env]: [DurableObjectState, unknown]) {
538
+ // Get config (either static or from function)
539
+ const resolvedConfig =
540
+ typeof config === 'function'
541
+ ? config(env, { id: state.id.toString(), name: state.id.name })
542
+ : config;
543
+
544
+ // Merge options with defaults
545
+ // Handle the case where config might not have actors property
546
+ const actorOptions =
547
+ resolvedConfig && typeof resolvedConfig === 'object' && 'actors' in resolvedConfig
548
+ ? (resolvedConfig as { actors?: ActorInstrumentationOptions }).actors
549
+ : undefined;
550
+ const options: ActorInstrumentationOptions = {
551
+ ...defaultOptions,
552
+ ...actorOptions,
553
+ };
554
+
555
+ // Initialize telemetry config
556
+ const trigger = {
557
+ id: state.id.toString(),
558
+ name: state.id.name,
559
+ };
560
+ const telemetryConfig = initialiser(env, trigger);
561
+ const context = setConfig(telemetryConfig);
562
+
563
+ // Create the Actor instance within the config context
564
+ const actorInstance = api_context.with(context, () => {
565
+ return new target(state, env);
566
+ }) as ActorLike;
567
+
568
+ // Instrument the instance
569
+ return instrumentActorInstance(actorInstance, state, env, actorClass, options);
570
+ },
571
+ };
572
+
573
+ return wrap(actorClass, classHandler);
574
+ }