@loutrejs/loutre 0.6.0 → 0.8.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 (71) hide show
  1. package/dist/adapters/bun.d.ts +2 -4
  2. package/dist/adapters/bun.js +36 -28
  3. package/dist/adapters/cloudflare-workers.d.ts +2 -4
  4. package/dist/adapters/cloudflare-workers.js +6 -11
  5. package/dist/adapters/server-transports.d.ts +4 -0
  6. package/dist/adapters/server-transports.js +18 -0
  7. package/dist/adapters/websocket-native.d.ts +24 -0
  8. package/dist/adapters/websocket-native.js +150 -0
  9. package/dist/application/kernel.d.ts +2 -1
  10. package/dist/core/extension.d.ts +26 -3
  11. package/dist/core/extension.js +19 -0
  12. package/dist/core/index.d.ts +2 -1
  13. package/dist/core/instrumentation.d.ts +36 -0
  14. package/dist/core/instrumentation.js +1 -0
  15. package/dist/core/model/modules.js +13 -17
  16. package/dist/core/model.js +14 -4
  17. package/dist/core/module.d.ts +3 -3
  18. package/dist/devtools/capsule.d.ts +51 -0
  19. package/dist/devtools/capsule.js +247 -0
  20. package/dist/devtools/index.d.ts +11 -0
  21. package/dist/devtools/index.js +6 -0
  22. package/dist/devtools/inspector.d.ts +57 -0
  23. package/dist/devtools/inspector.js +1 -0
  24. package/dist/devtools/module.d.ts +18 -0
  25. package/dist/devtools/module.js +26 -0
  26. package/dist/devtools/observer.d.ts +77 -0
  27. package/dist/devtools/observer.js +10 -0
  28. package/dist/devtools/protocol.d.ts +1 -0
  29. package/dist/devtools/protocol.js +1 -0
  30. package/dist/devtools/provider-instrumentation.d.ts +14 -0
  31. package/dist/devtools/provider-instrumentation.js +117 -0
  32. package/dist/devtools/runtime.d.ts +20 -0
  33. package/dist/devtools/runtime.js +519 -0
  34. package/dist/devtools/values.d.ts +35 -0
  35. package/dist/devtools/values.js +172 -0
  36. package/dist/generated/version.d.ts +1 -1
  37. package/dist/generated/version.js +1 -1
  38. package/dist/graph/model.js +37 -40
  39. package/dist/http/auth.d.ts +2 -2
  40. package/dist/http/auth.js +9 -0
  41. package/dist/http/client.js +5 -5
  42. package/dist/http/extension.d.ts +37 -10
  43. package/dist/http/extension.js +249 -57
  44. package/dist/http/index.d.ts +3 -2
  45. package/dist/http/index.js +1 -1
  46. package/dist/http/openapi.d.ts +3 -4
  47. package/dist/http/openapi.js +45 -26
  48. package/dist/http/request-head.d.ts +6 -0
  49. package/dist/http/request-head.js +1 -0
  50. package/dist/http/route-validation.d.ts +9 -0
  51. package/dist/http/route-validation.js +18 -0
  52. package/dist/http/runtime/response.js +10 -10
  53. package/dist/message-port/extension.js +20 -4
  54. package/dist/runtime/di.d.ts +4 -0
  55. package/dist/runtime/di.js +42 -31
  56. package/dist/runtime/engine.d.ts +1 -1
  57. package/dist/runtime/engine.js +1 -2
  58. package/dist/runtime/kernel.d.ts +4 -2
  59. package/dist/runtime/kernel.js +96 -3
  60. package/dist/runtime/node-capabilities.d.ts +1 -1
  61. package/dist/runtime/node-capabilities.js +2 -1
  62. package/dist/tasks/extension.js +133 -118
  63. package/dist/websocket/driver.d.ts +30 -0
  64. package/dist/websocket/driver.js +96 -0
  65. package/dist/websocket/extension.d.ts +33 -12
  66. package/dist/websocket/extension.js +72 -47
  67. package/dist/websocket/index.d.ts +3 -1
  68. package/dist/websocket/index.js +1 -0
  69. package/package.json +7 -6
  70. package/dist/adapters/deno.d.ts +0 -35
  71. package/dist/adapters/deno.js +0 -231
@@ -0,0 +1,20 @@
1
+ import type { RuntimeExecutionMetadata, RuntimeInstrumentation, RuntimeInstrumentationScope, RuntimeInvocationRegistration, RuntimeProviderMetadata, RuntimeOperationMetadata } from '../core/instrumentation.js';
2
+ import type { ProviderMethodInvocationRequest, ProviderPlaygroundDescriptor, ProviderPlaygroundRequest, ReplayCapsuleRequest, RuntimeDevtoolsContextStorage, RuntimeInspector, RuntimeInvocationResult } from './inspector.js';
3
+ import type { DevtoolsModuleOptions } from './module.js';
4
+ import { type RuntimeObserver } from './observer.js';
5
+ export interface RuntimeDevtoolsInstrumentationOptions {
6
+ readonly options: Readonly<DevtoolsModuleOptions>;
7
+ readonly observer: RuntimeObserver;
8
+ readonly context: RuntimeDevtoolsContextStorage;
9
+ }
10
+ export declare class RuntimeDevtoolsInstrumentation implements RuntimeInstrumentation, RuntimeInspector {
11
+ #private;
12
+ constructor(options: RuntimeDevtoolsInstrumentationOptions);
13
+ beginExecution(metadata: RuntimeExecutionMetadata, invocation?: RuntimeInvocationRegistration): RuntimeInstrumentationScope;
14
+ beginOperation(metadata: RuntimeOperationMetadata, invocation?: RuntimeInvocationRegistration): RuntimeInstrumentationScope | undefined;
15
+ providerCreated(metadata: RuntimeProviderMetadata, value: unknown): void;
16
+ providerPlayground(request: ProviderPlaygroundRequest): Promise<ProviderPlaygroundDescriptor>;
17
+ invokeProviderMethod(request: ProviderMethodInvocationRequest): Promise<RuntimeInvocationResult>;
18
+ replayCapsule(request: ReplayCapsuleRequest): Promise<RuntimeInvocationResult>;
19
+ close(): void;
20
+ }
@@ -0,0 +1,519 @@
1
+ import { ReplayCapsuleStore } from './capsule.js';
2
+ import { serializeDevtoolsError, } from './observer.js';
3
+ import { discoverProviderMethods, instrumentProviderMethods, } from './provider-instrumentation.js';
4
+ import { previewDevtoolsValue } from './values.js';
5
+ export class RuntimeDevtoolsInstrumentation {
6
+ #options;
7
+ #observer;
8
+ #context;
9
+ #captureProviderMethods;
10
+ #captureResults;
11
+ #runId;
12
+ #capsules;
13
+ #providers = new Map();
14
+ #providerMethods = new WeakMap();
15
+ #instrumentedProviderIds = new WeakMap();
16
+ #externalProviderValues = new WeakSet();
17
+ #ambiguousProviders = new WeakSet();
18
+ #providerRestorers = new WeakMap();
19
+ #applicationProviderRestorers = new Map();
20
+ #seq = 0;
21
+ constructor(options) {
22
+ this.#options = options.options;
23
+ this.#observer = options.observer;
24
+ this.#context = options.context;
25
+ this.#captureProviderMethods =
26
+ options.options.capture?.providerMethods !== false;
27
+ const captureResults = options.options.capture?.results;
28
+ this.#captureResults =
29
+ captureResults !== false && captureResults !== 'errors';
30
+ this.#runId = options.observer.runId ?? `run_${crypto.randomUUID()}`;
31
+ const replay = options.options.replay;
32
+ this.#capsules =
33
+ replay?.enabled === false
34
+ ? undefined
35
+ : new ReplayCapsuleStore(this.#runId, {
36
+ ...(replay?.capsuleTtlMs === undefined
37
+ ? {}
38
+ : { ttlMs: replay.capsuleTtlMs }),
39
+ ...(replay?.maxCapsules === undefined
40
+ ? {}
41
+ : { maxCapsules: replay.maxCapsules }),
42
+ ...(options.options.capture === undefined
43
+ ? {}
44
+ : { capture: options.options.capture }),
45
+ ...(options.options.redact === undefined
46
+ ? {}
47
+ : { redact: options.options.redact }),
48
+ });
49
+ }
50
+ beginExecution(metadata, invocation) {
51
+ const traceId = `trace_${crypto.randomUUID()}`;
52
+ const spanId = `span_${crypto.randomUUID()}`;
53
+ const startedAt = performance.now();
54
+ const startedTimestamp = performance.timeOrigin + startedAt;
55
+ const name = metadata.name ?? metadata.executionId;
56
+ const replaySource = this.#context.current()?.replay;
57
+ const capsule = invocation && this.#capsules
58
+ ? this.#capsules.createExecution(traceId, spanId, metadata, {
59
+ input: invocation.input,
60
+ replay: (input, context) => this.#runReplayContext(context, () => invocation.invoke(input)),
61
+ })
62
+ : undefined;
63
+ let completed = false;
64
+ let failed = false;
65
+ let failureReason;
66
+ let cancelled = false;
67
+ const attributes = {};
68
+ this.#notify('executionStarted', {
69
+ type: 'execution.started',
70
+ ...this.#identity(startedTimestamp, traceId, spanId, metadata.graphNodeId),
71
+ executionId: metadata.executionId,
72
+ executionKind: metadata.executionKind,
73
+ name,
74
+ ...(capsule === undefined
75
+ ? {}
76
+ : {
77
+ input: capsule.input,
78
+ capsuleId: capsule.id,
79
+ replayable: true,
80
+ replayModes: capsule.replayModes,
81
+ }),
82
+ ...(replaySource === undefined
83
+ ? {}
84
+ : {
85
+ replayedFromTraceId: replaySource.sourceTraceId,
86
+ replayedFromCapsuleId: replaySource.sourceCapsuleId,
87
+ }),
88
+ });
89
+ this.#notify('spanStarted', {
90
+ type: 'span.started',
91
+ ...this.#identity(startedTimestamp, traceId, spanId, metadata.graphNodeId),
92
+ kind: 'execution',
93
+ name,
94
+ attributes: { executionKind: metadata.executionKind },
95
+ });
96
+ return {
97
+ run: (operation) => this.#context.run({
98
+ trace: { traceId, spanId },
99
+ ...(replaySource === undefined ? {} : { replay: replaySource }),
100
+ }, operation),
101
+ abort() {
102
+ cancelled = true;
103
+ },
104
+ fail(reason) {
105
+ failed = true;
106
+ failureReason = reason;
107
+ },
108
+ annotate(nextAttributes) {
109
+ Object.assign(attributes, nextAttributes);
110
+ },
111
+ complete: (...resultValues) => {
112
+ if (completed)
113
+ return;
114
+ completed = true;
115
+ const status = failed ? 'error' : cancelled ? 'cancelled' : 'ok';
116
+ const error = failed ? serializeDevtoolsError(failureReason) : undefined;
117
+ const result = resultValues.length === 0
118
+ ? undefined
119
+ : this.#previewResult(resultValues[0]);
120
+ const endedAt = performance.now();
121
+ const timestamp = performance.timeOrigin + endedAt;
122
+ this.#notify('spanEnded', {
123
+ type: 'span.ended',
124
+ ...this.#identity(timestamp, traceId, spanId, metadata.graphNodeId),
125
+ durationMs: endedAt - startedAt,
126
+ status,
127
+ ...(Object.keys(attributes).length === 0 ? {} : { attributes }),
128
+ ...(result === undefined ? {} : { result }),
129
+ ...(error === undefined ? {} : { error }),
130
+ });
131
+ this.#notify('executionEnded', {
132
+ type: 'execution.ended',
133
+ ...this.#identity(timestamp, traceId, spanId, metadata.graphNodeId),
134
+ executionId: metadata.executionId,
135
+ durationMs: endedAt - startedAt,
136
+ status,
137
+ ...(Object.keys(attributes).length === 0 ? {} : { attributes }),
138
+ ...(result === undefined ? {} : { result }),
139
+ ...(error === undefined ? {} : { error }),
140
+ });
141
+ },
142
+ };
143
+ }
144
+ beginOperation(metadata, invocation) {
145
+ const current = this.#context.current();
146
+ if (!current?.trace)
147
+ return undefined;
148
+ const spanId = `span_${crypto.randomUUID()}`;
149
+ const startedAt = performance.now();
150
+ const capsule = invocation && this.#capsules
151
+ ? this.#capsules.createExecution(current.trace.traceId, spanId, {
152
+ executionId: `span:${metadata.name}`,
153
+ executionKind: metadata.kind,
154
+ name: metadata.name,
155
+ ...(metadata.graphNodeId === undefined
156
+ ? {}
157
+ : { graphNodeId: metadata.graphNodeId }),
158
+ }, {
159
+ input: invocation.input,
160
+ replay: (input, context) => this.#runReplayContext(context, () => invocation.invoke(input)),
161
+ })
162
+ : undefined;
163
+ let completed = false;
164
+ let failed = false;
165
+ let failureReason;
166
+ const attributes = {};
167
+ this.#notify('spanStarted', {
168
+ type: 'span.started',
169
+ runId: this.#runId,
170
+ seq: ++this.#seq,
171
+ timestamp: performance.timeOrigin + startedAt,
172
+ traceId: current.trace.traceId,
173
+ spanId,
174
+ parentSpanId: current.trace.spanId,
175
+ ...(metadata.graphNodeId === undefined
176
+ ? {}
177
+ : { graphNodeId: metadata.graphNodeId }),
178
+ kind: metadata.kind,
179
+ name: metadata.name,
180
+ ...(capsule === undefined
181
+ ? {}
182
+ : {
183
+ input: capsule.input,
184
+ capsuleId: capsule.id,
185
+ replayable: true,
186
+ replayModes: capsule.replayModes,
187
+ }),
188
+ });
189
+ return {
190
+ run: (operation) => this.#context.run({
191
+ trace: { traceId: current.trace.traceId, spanId },
192
+ ...(current.replay === undefined ? {} : { replay: current.replay }),
193
+ }, operation),
194
+ fail(reason) {
195
+ failed = true;
196
+ failureReason = reason;
197
+ },
198
+ annotate(nextAttributes) {
199
+ Object.assign(attributes, nextAttributes);
200
+ },
201
+ complete: (...resultValues) => {
202
+ if (completed)
203
+ return;
204
+ completed = true;
205
+ const result = resultValues.length === 0
206
+ ? undefined
207
+ : this.#previewResult(resultValues[0]);
208
+ const error = failed ? serializeDevtoolsError(failureReason) : undefined;
209
+ const endedAt = performance.now();
210
+ this.#notify('spanEnded', {
211
+ type: 'span.ended',
212
+ runId: this.#runId,
213
+ seq: ++this.#seq,
214
+ timestamp: performance.timeOrigin + endedAt,
215
+ traceId: current.trace.traceId,
216
+ spanId,
217
+ parentSpanId: current.trace.spanId,
218
+ ...(metadata.graphNodeId === undefined
219
+ ? {}
220
+ : { graphNodeId: metadata.graphNodeId }),
221
+ durationMs: endedAt - startedAt,
222
+ status: failed ? 'error' : 'ok',
223
+ ...(Object.keys(attributes).length === 0 ? {} : { attributes }),
224
+ ...(result === undefined ? {} : { result }),
225
+ ...(error === undefined ? {} : { error }),
226
+ });
227
+ },
228
+ };
229
+ }
230
+ providerCreated(metadata, value) {
231
+ if (typeof value !== 'object' || value === null)
232
+ return;
233
+ let methods = this.#providerMethods.get(value);
234
+ if (!methods) {
235
+ methods = discoverProviderMethods(value);
236
+ this.#providerMethods.set(value, methods);
237
+ }
238
+ if (metadata.scope === 'application') {
239
+ this.#providers.set(metadata.graphNodeId, {
240
+ metadata,
241
+ instance: value,
242
+ methods: new Map(methods.flatMap((method) => typeof method.key === 'string' ? [[method.name, method]] : [])),
243
+ });
244
+ }
245
+ if (!this.#captureProviderMethods)
246
+ return;
247
+ if (metadata.providerKind === 'value' ||
248
+ metadata.providerKind === 'factory') {
249
+ this.#providerRestorers.get(value)?.();
250
+ this.#providerRestorers.delete(value);
251
+ this.#applicationProviderRestorers.delete(value);
252
+ this.#externalProviderValues.add(value);
253
+ return;
254
+ }
255
+ if (this.#externalProviderValues.has(value) ||
256
+ this.#ambiguousProviders.has(value)) {
257
+ return;
258
+ }
259
+ const instrumentedProviderId = this.#instrumentedProviderIds.get(value);
260
+ if (instrumentedProviderId !== undefined) {
261
+ if (instrumentedProviderId !== metadata.graphNodeId) {
262
+ this.#providerRestorers.get(value)?.();
263
+ this.#providerRestorers.delete(value);
264
+ this.#applicationProviderRestorers.delete(value);
265
+ this.#ambiguousProviders.add(value);
266
+ }
267
+ return;
268
+ }
269
+ const restore = instrumentProviderMethods(value, (invocation) => this.#invokeProviderMethod(metadata, value, invocation));
270
+ this.#instrumentedProviderIds.set(value, metadata.graphNodeId);
271
+ this.#providerRestorers.set(value, restore);
272
+ if (metadata.scope === 'application') {
273
+ this.#applicationProviderRestorers.set(value, restore);
274
+ }
275
+ }
276
+ async providerPlayground(request) {
277
+ const provider = this.#providers.get(request.graphNodeId);
278
+ if (!provider) {
279
+ throw new Error(`LUTRE_DEVTOOLS_PROVIDER_UNAVAILABLE: ${request.graphNodeId}`);
280
+ }
281
+ return {
282
+ requestId: request.requestId,
283
+ graphNodeId: request.graphNodeId,
284
+ providerName: provider.metadata.name,
285
+ methods: [...provider.methods.values()]
286
+ .map((method) => ({ name: method.name, arity: method.original.length }))
287
+ .toSorted((left, right) => left.name.localeCompare(right.name)),
288
+ };
289
+ }
290
+ async invokeProviderMethod(request) {
291
+ const provider = this.#providers.get(request.graphNodeId);
292
+ if (!provider) {
293
+ return {
294
+ requestId: request.requestId,
295
+ status: 'error',
296
+ error: {
297
+ name: 'ProviderUnavailableError',
298
+ message: `LUTRE_DEVTOOLS_PROVIDER_UNAVAILABLE: ${request.graphNodeId}`,
299
+ },
300
+ };
301
+ }
302
+ const method = provider.methods.get(request.method);
303
+ if (!method) {
304
+ return {
305
+ requestId: request.requestId,
306
+ status: 'error',
307
+ error: {
308
+ name: 'ProviderMethodUnavailableError',
309
+ message: `LUTRE_DEVTOOLS_PROVIDER_METHOD_UNAVAILABLE: ${request.method}`,
310
+ },
311
+ };
312
+ }
313
+ let traceId;
314
+ try {
315
+ const result = await this.#runProviderMethodExecution(provider.metadata, provider.instance, method.original, method.name, request.args, (nextTraceId) => {
316
+ traceId = nextTraceId;
317
+ });
318
+ return {
319
+ requestId: request.requestId,
320
+ status: 'ok',
321
+ ...(traceId === undefined ? {} : { traceId }),
322
+ result: this.#previewValue(result),
323
+ };
324
+ }
325
+ catch (error) {
326
+ return {
327
+ requestId: request.requestId,
328
+ status: 'error',
329
+ ...(traceId === undefined ? {} : { traceId }),
330
+ error: serializeDevtoolsError(error),
331
+ };
332
+ }
333
+ }
334
+ async replayCapsule(request) {
335
+ if (!this.#capsules) {
336
+ return {
337
+ requestId: request.requestId,
338
+ status: 'error',
339
+ error: {
340
+ name: 'ReplayDisabledError',
341
+ message: 'LUTRE_DEVTOOLS_REPLAY_DISABLED: Replay is not enabled.',
342
+ },
343
+ };
344
+ }
345
+ return this.#capsules.replay(request);
346
+ }
347
+ close() {
348
+ this.#capsules?.clear();
349
+ this.#providers.clear();
350
+ for (const restore of this.#applicationProviderRestorers.values())
351
+ restore();
352
+ this.#applicationProviderRestorers.clear();
353
+ }
354
+ #invokeProviderMethod(metadata, instance, invocation) {
355
+ const current = this.#context.current();
356
+ if (!current?.trace) {
357
+ return Reflect.apply(invocation.original, invocation.receiver, invocation.args);
358
+ }
359
+ const spanId = `span_${crypto.randomUUID()}`;
360
+ const startedAt = performance.now();
361
+ const name = `${metadata.name}.${invocation.name}`;
362
+ const capsule = metadata.scope === 'transient'
363
+ ? undefined
364
+ : this.#capsules?.createExecution(current.trace.traceId, spanId, {
365
+ executionId: `${metadata.providerId}.${invocation.name}`,
366
+ executionKind: 'provider.method',
367
+ graphNodeId: metadata.graphNodeId,
368
+ name,
369
+ }, {
370
+ input: invocation.args,
371
+ replay: (input, context) => this.#runReplayContext(context, () => this.#replayProviderMethod(metadata, instance, invocation.original, invocation.name, input)),
372
+ });
373
+ let result;
374
+ try {
375
+ result = Reflect.apply(invocation.original, invocation.receiver, invocation.args);
376
+ }
377
+ catch (error) {
378
+ this.#recordProviderMethodSpan(metadata, invocation, current.trace, spanId, startedAt, capsule, { status: 'error', error });
379
+ throw error;
380
+ }
381
+ // Promiseのsettlementを観測するとrejection handlerが追加され、Applicationの
382
+ // unhandled-rejection semanticsを変え得る。自動Traceは同期的に完結する呼び出しへ
383
+ // 限定し、明示実行であるPlaygroundとReplayだけがPromiseをawaitする。
384
+ if (result instanceof Promise) {
385
+ if (capsule)
386
+ this.#capsules?.discard(capsule.id);
387
+ return result;
388
+ }
389
+ this.#recordProviderMethodSpan(metadata, invocation, current.trace, spanId, startedAt, capsule, { status: 'ok', result });
390
+ return result;
391
+ }
392
+ #recordProviderMethodSpan(metadata, invocation, parent, spanId, startedAt, capsule, outcome) {
393
+ const name = `${metadata.name}.${invocation.name}`;
394
+ this.#notify('spanStarted', {
395
+ type: 'span.started',
396
+ runId: this.#runId,
397
+ seq: ++this.#seq,
398
+ timestamp: performance.timeOrigin + startedAt,
399
+ traceId: parent.traceId,
400
+ spanId,
401
+ parentSpanId: parent.spanId,
402
+ graphNodeId: metadata.graphNodeId,
403
+ kind: 'provider.method',
404
+ name,
405
+ ...(capsule === undefined
406
+ ? {}
407
+ : {
408
+ input: capsule.input,
409
+ capsuleId: capsule.id,
410
+ replayable: true,
411
+ replayModes: capsule.replayModes,
412
+ }),
413
+ });
414
+ const endedAt = performance.now();
415
+ const result = outcome.status === 'ok' ? this.#previewResult(outcome.result) : undefined;
416
+ this.#notify('spanEnded', {
417
+ type: 'span.ended',
418
+ runId: this.#runId,
419
+ seq: ++this.#seq,
420
+ timestamp: performance.timeOrigin + endedAt,
421
+ traceId: parent.traceId,
422
+ spanId,
423
+ parentSpanId: parent.spanId,
424
+ graphNodeId: metadata.graphNodeId,
425
+ durationMs: endedAt - startedAt,
426
+ status: outcome.status,
427
+ ...(result === undefined ? {} : { result }),
428
+ ...(outcome.status === 'error'
429
+ ? { error: serializeDevtoolsError(outcome.error) }
430
+ : {}),
431
+ });
432
+ }
433
+ async #replayProviderMethod(metadata, instance, original, method, input) {
434
+ return this.#runProviderMethodExecution(metadata, instance, original, method, input);
435
+ }
436
+ async #runProviderMethodExecution(metadata, instance, original, method, input, onTraceId) {
437
+ if (!Array.isArray(input)) {
438
+ throw new TypeError('LUTRE_DEVTOOLS_PROVIDER_ARGS_REQUIRED');
439
+ }
440
+ const scope = this.beginExecution({
441
+ executionId: `${metadata.providerId}.${method}`,
442
+ executionKind: 'provider.method',
443
+ graphNodeId: metadata.graphNodeId,
444
+ name: `${metadata.name}.${method}`,
445
+ }, {
446
+ input,
447
+ invoke: (nextInput) => this.#runProviderMethodExecution(metadata, instance, original, method, nextInput),
448
+ });
449
+ let result;
450
+ let hasResult = false;
451
+ try {
452
+ const invoke = () => {
453
+ const traceId = this.#context.current()?.trace?.traceId;
454
+ if (traceId)
455
+ onTraceId?.(traceId);
456
+ return Reflect.apply(original, instance, input);
457
+ };
458
+ result = await (scope.run ? scope.run(invoke) : invoke());
459
+ hasResult = true;
460
+ return result;
461
+ }
462
+ catch (error) {
463
+ scope.fail?.(error);
464
+ throw error;
465
+ }
466
+ finally {
467
+ if (hasResult)
468
+ scope.complete(result);
469
+ else
470
+ scope.complete();
471
+ }
472
+ }
473
+ #runReplayContext(context, operation) {
474
+ const current = this.#context.current();
475
+ const next = {
476
+ ...(current?.trace === undefined ? {} : { trace: current.trace }),
477
+ replay: context,
478
+ };
479
+ return this.#context.run(next, operation);
480
+ }
481
+ #previewResult(value) {
482
+ if (!this.#captureResults)
483
+ return undefined;
484
+ return this.#previewValue(value);
485
+ }
486
+ #previewValue(value) {
487
+ const capture = this.#options.capture;
488
+ return previewDevtoolsValue(value, {
489
+ ...(capture?.maxValueBytes === undefined
490
+ ? {}
491
+ : { maxValueBytes: capture.maxValueBytes }),
492
+ ...(capture?.maxDepth === undefined
493
+ ? {}
494
+ : { maxDepth: capture.maxDepth }),
495
+ ...(this.#options.redact === undefined
496
+ ? {}
497
+ : { redact: this.#options.redact }),
498
+ });
499
+ }
500
+ #identity(timestamp, traceId, spanId, graphNodeId) {
501
+ return {
502
+ runId: this.#runId,
503
+ seq: ++this.#seq,
504
+ timestamp,
505
+ traceId,
506
+ spanId,
507
+ ...(graphNodeId === undefined ? {} : { graphNodeId }),
508
+ };
509
+ }
510
+ #notify(key, event) {
511
+ try {
512
+ const callback = this.#observer[key];
513
+ callback?.(event);
514
+ }
515
+ catch {
516
+ // observerの失敗をApplicationの挙動へ伝播させてはならない。
517
+ }
518
+ }
519
+ }
@@ -0,0 +1,35 @@
1
+ export type DevtoolsValue = null | boolean | number | string | {
2
+ readonly $type: 'undefined';
3
+ } | {
4
+ readonly $type: 'bigint';
5
+ readonly value: string;
6
+ } | {
7
+ readonly $type: 'date';
8
+ readonly value: string;
9
+ } | {
10
+ readonly $type: 'bytes';
11
+ readonly base64: string;
12
+ } | {
13
+ readonly $type: 'map';
14
+ readonly entries: readonly [DevtoolsValue, DevtoolsValue][];
15
+ } | {
16
+ readonly $type: 'set';
17
+ readonly values: readonly DevtoolsValue[];
18
+ } | {
19
+ readonly $type: 'redacted';
20
+ } | readonly DevtoolsValue[] | {
21
+ readonly [key: string]: DevtoolsValue;
22
+ };
23
+ export interface DevtoolsValuePreview {
24
+ readonly value?: DevtoolsValue;
25
+ readonly preview: string;
26
+ readonly truncated?: boolean;
27
+ readonly redacted?: boolean;
28
+ readonly type?: string;
29
+ }
30
+ export interface DevtoolsValuePreviewOptions {
31
+ readonly maxValueBytes?: number;
32
+ readonly maxDepth?: number;
33
+ readonly redact?: readonly string[];
34
+ }
35
+ export declare function previewDevtoolsValue(value: unknown, options?: DevtoolsValuePreviewOptions): DevtoolsValuePreview;