@atrim/instrument-node 0.5.0-c05e3a1-20251119131235 → 0.5.1-3a86b84-20260105170223

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.
@@ -1,13 +1,15 @@
1
- import { Data, Context, Effect, Layer, FiberSet as FiberSet$1, Tracer } from 'effect';
1
+ import { Data, Context, Effect, Layer, FiberSet as FiberSet$1, Fiber, Option, FiberId, Tracer as Tracer$1 } from 'effect';
2
+ import * as Tracer from '@effect/opentelemetry/Tracer';
3
+ import * as Resource from '@effect/opentelemetry/Resource';
2
4
  import * as Otlp from '@effect/opentelemetry/Otlp';
3
5
  import { FetchHttpClient } from '@effect/platform';
4
6
  import { TraceFlags, trace, context } from '@opentelemetry/api';
7
+ import { TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS, ATTR_TELEMETRY_SDK_NAME, ATTR_TELEMETRY_SDK_LANGUAGE } from '@opentelemetry/semantic-conventions';
5
8
  import { FileSystem } from '@effect/platform/FileSystem';
6
9
  import * as HttpClient from '@effect/platform/HttpClient';
7
10
  import * as HttpClientRequest from '@effect/platform/HttpClientRequest';
8
11
  import { parse } from 'yaml';
9
12
  import { z } from 'zod';
10
- import { NodeContext } from '@effect/platform-node';
11
13
 
12
14
  // src/integrations/effect/effect-tracer.ts
13
15
  var __defProp = Object.defineProperty;
@@ -71,11 +73,50 @@ var InstrumentationConfigSchema = z.object({
71
73
  ignore_patterns: z.array(PatternConfigSchema)
72
74
  }),
73
75
  effect: z.object({
76
+ // Enable/disable Effect tracing entirely
77
+ // When false, EffectInstrumentationLive returns Layer.empty
78
+ enabled: z.boolean().default(true),
79
+ // Exporter mode:
80
+ // - "unified": Use global TracerProvider from Node SDK (recommended, enables filtering)
81
+ // - "standalone": Use Effect's own OTLP exporter (bypasses Node SDK filtering)
82
+ exporter: z.enum(["unified", "standalone"]).default("unified"),
74
83
  auto_extract_metadata: z.boolean(),
75
84
  auto_isolation: AutoIsolationConfigSchema.optional()
76
85
  }).optional(),
77
86
  http: HttpFilteringConfigSchema.optional()
78
87
  });
88
+ var defaultConfig = {
89
+ version: "1.0",
90
+ instrumentation: {
91
+ enabled: true,
92
+ logging: "on",
93
+ description: "Default instrumentation configuration",
94
+ instrument_patterns: [
95
+ { pattern: "^app\\.", enabled: true, description: "Application operations" },
96
+ { pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
97
+ { pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
98
+ ],
99
+ ignore_patterns: [
100
+ { pattern: "^test\\.", description: "Test utilities" },
101
+ { pattern: "^internal\\.", description: "Internal operations" },
102
+ { pattern: "^health\\.", description: "Health checks" }
103
+ ]
104
+ },
105
+ effect: {
106
+ enabled: true,
107
+ exporter: "unified",
108
+ auto_extract_metadata: true
109
+ }
110
+ };
111
+ function parseAndValidateConfig(content) {
112
+ let parsed;
113
+ if (typeof content === "string") {
114
+ parsed = parse(content);
115
+ } else {
116
+ parsed = content;
117
+ }
118
+ return InstrumentationConfigSchema.parse(parsed);
119
+ }
79
120
  (class extends Data.TaggedError("ConfigError") {
80
121
  get message() {
81
122
  return this.reason;
@@ -253,7 +294,7 @@ var makeConfigLoader = Effect.gen(function* () {
253
294
  })
254
295
  });
255
296
  });
256
- var ConfigLoaderLive = Layer.effect(ConfigLoader, makeConfigLoader);
297
+ Layer.effect(ConfigLoader, makeConfigLoader);
257
298
  var PatternMatcher = class {
258
299
  constructor(config) {
259
300
  __publicField(this, "ignorePatterns", []);
@@ -401,83 +442,58 @@ var Logger = class {
401
442
  }
402
443
  };
403
444
  var logger = new Logger();
404
- var NodeConfigLoaderLive = ConfigLoaderLive.pipe(
405
- Layer.provide(Layer.mergeAll(NodeContext.layer, FetchHttpClient.layer))
406
- );
407
- var cachedLoaderPromise = null;
408
- function getCachedLoader() {
409
- if (!cachedLoaderPromise) {
410
- cachedLoaderPromise = Effect.runPromise(
411
- Effect.gen(function* () {
412
- return yield* ConfigLoader;
413
- }).pipe(Effect.provide(NodeConfigLoaderLive))
414
- );
445
+ async function loadFromFile(filePath) {
446
+ const { readFile } = await import('fs/promises');
447
+ const content = await readFile(filePath, "utf-8");
448
+ return parseAndValidateConfig(content);
449
+ }
450
+ async function loadFromUrl(url) {
451
+ const response = await fetch(url);
452
+ if (!response.ok) {
453
+ throw new Error(`Failed to fetch config from ${url}: ${response.statusText}`);
415
454
  }
416
- return cachedLoaderPromise;
455
+ const content = await response.text();
456
+ return parseAndValidateConfig(content);
417
457
  }
418
- async function loadConfig(uri, options) {
419
- if (options?.cacheTimeout === 0) {
420
- const program = Effect.gen(function* () {
421
- const loader2 = yield* ConfigLoader;
422
- return yield* loader2.loadFromUri(uri);
423
- });
424
- return Effect.runPromise(program.pipe(Effect.provide(NodeConfigLoaderLive)));
425
- }
426
- const loader = await getCachedLoader();
427
- return Effect.runPromise(loader.loadFromUri(uri));
458
+ async function loadConfig(uri, _options) {
459
+ if (uri.startsWith("http://") || uri.startsWith("https://")) {
460
+ return loadFromUrl(uri);
461
+ }
462
+ if (uri.startsWith("file://")) {
463
+ const filePath = uri.slice(7);
464
+ return loadFromFile(filePath);
465
+ }
466
+ return loadFromFile(uri);
428
467
  }
429
468
  async function loadConfigFromInline(content) {
430
- const loader = await getCachedLoader();
431
- return Effect.runPromise(loader.loadFromInline(content));
432
- }
433
- function getDefaultConfig() {
434
- return {
435
- version: "1.0",
436
- instrumentation: {
437
- enabled: true,
438
- logging: "on",
439
- description: "Default instrumentation configuration",
440
- instrument_patterns: [
441
- { pattern: "^app\\.", enabled: true, description: "Application operations" },
442
- { pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
443
- { pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
444
- ],
445
- ignore_patterns: [
446
- { pattern: "^test\\.", description: "Test utilities" },
447
- { pattern: "^internal\\.", description: "Internal operations" },
448
- { pattern: "^health\\.", description: "Health checks" }
449
- ]
450
- },
451
- effect: {
452
- auto_extract_metadata: true
453
- }
454
- };
469
+ return parseAndValidateConfig(content);
455
470
  }
456
471
  async function loadConfigWithOptions(options = {}) {
457
- const loadOptions = options.cacheTimeout !== void 0 ? { cacheTimeout: options.cacheTimeout } : void 0;
458
472
  if (options.config) {
459
473
  return loadConfigFromInline(options.config);
460
474
  }
461
475
  const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
462
476
  if (envConfigPath) {
463
- return loadConfig(envConfigPath, loadOptions);
477
+ return loadConfig(envConfigPath);
464
478
  }
465
479
  if (options.configUrl) {
466
- return loadConfig(options.configUrl, loadOptions);
480
+ return loadConfig(options.configUrl);
467
481
  }
468
482
  if (options.configPath) {
469
- return loadConfig(options.configPath, loadOptions);
483
+ return loadConfig(options.configPath);
470
484
  }
471
485
  const { existsSync } = await import('fs');
472
486
  const { join } = await import('path');
473
487
  const defaultPath = join(process.cwd(), "instrumentation.yaml");
474
488
  if (existsSync(defaultPath)) {
475
- return loadConfig(defaultPath, loadOptions);
489
+ return loadConfig(defaultPath);
476
490
  }
477
- return getDefaultConfig();
491
+ return defaultConfig;
478
492
  }
479
493
 
480
494
  // src/integrations/effect/effect-tracer.ts
495
+ var SDK_NAME = "@effect/opentelemetry";
496
+ var ATTR_TELEMETRY_EXPORTER_MODE = "telemetry.exporter.mode";
481
497
  function createEffectInstrumentation(options = {}) {
482
498
  return Layer.unwrapEffect(
483
499
  Effect.gen(function* () {
@@ -488,106 +504,228 @@ function createEffectInstrumentation(options = {}) {
488
504
  message: error instanceof Error ? error.message : String(error)
489
505
  })
490
506
  });
507
+ const effectEnabled = process.env.OTEL_EFFECT_ENABLED !== "false" && (config.effect?.enabled ?? true);
508
+ if (!effectEnabled) {
509
+ logger.log("@atrim/instrumentation/effect: Effect tracing disabled via config");
510
+ return Layer.empty;
511
+ }
491
512
  yield* Effect.sync(() => {
492
513
  const loggingLevel = config.instrumentation.logging || "on";
493
514
  logger.setLevel(loggingLevel);
494
515
  });
495
516
  yield* Effect.sync(() => initializePatternMatcher(config));
496
- const otlpEndpoint = options.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
497
517
  const serviceName = options.serviceName || process.env.OTEL_SERVICE_NAME || "effect-service";
498
518
  const serviceVersion = options.serviceVersion || process.env.npm_package_version || "1.0.0";
499
- const autoExtractMetadata = options.autoExtractMetadata ?? config.effect?.auto_extract_metadata ?? true;
500
- const continueExistingTraces = options.continueExistingTraces ?? true;
501
- logger.log("\u{1F50D} Effect OpenTelemetry instrumentation");
502
- logger.log(` \u{1F4E1} Endpoint: ${otlpEndpoint}`);
503
- logger.log(` \u{1F3F7}\uFE0F Service: ${serviceName}`);
504
- logger.log(` \u2705 Auto metadata extraction: ${autoExtractMetadata}`);
505
- logger.log(` \u2705 Continue existing traces: ${continueExistingTraces}`);
506
- const otlpLayer = Otlp.layer({
507
- baseUrl: otlpEndpoint,
508
- resource: {
509
- serviceName,
510
- serviceVersion,
511
- attributes: {
512
- "platform.component": "effect",
513
- "effect.auto_metadata": autoExtractMetadata,
514
- "effect.context_propagation": continueExistingTraces
515
- }
516
- },
517
- // Bridge Effect context to OpenTelemetry global context
518
- // This is essential for context propagation to work properly
519
- tracerContext: (f, span) => {
520
- if (span._tag !== "Span") {
521
- return f();
519
+ const exporterMode = options.exporterMode ?? config.effect?.exporter ?? "unified";
520
+ const resourceAttributes = {
521
+ "platform.component": "effect",
522
+ [ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
523
+ [ATTR_TELEMETRY_SDK_NAME]: SDK_NAME,
524
+ [ATTR_TELEMETRY_EXPORTER_MODE]: exporterMode
525
+ };
526
+ if (exporterMode === "standalone") {
527
+ const otlpEndpoint = options.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
528
+ logger.log("Effect OpenTelemetry instrumentation (standalone)");
529
+ logger.log(` Service: ${serviceName}`);
530
+ logger.log(` Endpoint: ${otlpEndpoint}`);
531
+ logger.log(" WARNING: Standalone mode bypasses Node SDK filtering");
532
+ return Otlp.layer({
533
+ baseUrl: otlpEndpoint,
534
+ resource: {
535
+ serviceName,
536
+ serviceVersion,
537
+ attributes: resourceAttributes
538
+ },
539
+ // Bridge Effect context to OpenTelemetry global context
540
+ tracerContext: (f, span) => {
541
+ if (span._tag !== "Span") {
542
+ return f();
543
+ }
544
+ const spanContext = {
545
+ traceId: span.traceId,
546
+ spanId: span.spanId,
547
+ traceFlags: span.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE
548
+ };
549
+ const otelSpan = trace.wrapSpanContext(spanContext);
550
+ return context.with(trace.setSpan(context.active(), otelSpan), f);
522
551
  }
523
- const spanContext = {
524
- traceId: span.traceId,
525
- spanId: span.spanId,
526
- traceFlags: span.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE
527
- };
528
- const otelSpan = trace.wrapSpanContext(spanContext);
529
- return context.with(trace.setSpan(context.active(), otelSpan), f);
530
- }
531
- }).pipe(Layer.provide(FetchHttpClient.layer));
532
- if (autoExtractMetadata) {
533
- return otlpLayer;
552
+ }).pipe(Layer.provide(FetchHttpClient.layer));
553
+ } else {
554
+ logger.log("Effect OpenTelemetry instrumentation (unified)");
555
+ logger.log(` Service: ${serviceName}`);
556
+ logger.log(" Using global TracerProvider for span export");
557
+ return Tracer.layerGlobal.pipe(
558
+ Layer.provide(
559
+ Resource.layer({
560
+ serviceName,
561
+ serviceVersion,
562
+ attributes: resourceAttributes
563
+ })
564
+ )
565
+ );
534
566
  }
535
- return otlpLayer;
536
567
  })
537
568
  ).pipe(Layer.orDie);
538
569
  }
539
570
  var EffectInstrumentationLive = Effect.sync(() => {
540
- const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318";
541
571
  const serviceName = process.env.OTEL_SERVICE_NAME || "effect-service";
542
572
  const serviceVersion = process.env.npm_package_version || "1.0.0";
543
573
  logger.minimal(`@atrim/instrumentation/effect: Effect tracing enabled (${serviceName})`);
544
- logger.log("\u{1F50D} Effect OpenTelemetry tracer");
545
- logger.log(` \u{1F4E1} Endpoint: ${endpoint}`);
546
- logger.log(` \u{1F3F7}\uFE0F Service: ${serviceName}`);
547
- return Otlp.layer({
548
- baseUrl: endpoint,
549
- resource: {
550
- serviceName,
551
- serviceVersion,
552
- attributes: {
553
- "platform.component": "effect"
554
- }
555
- },
556
- // CRITICAL: Bridge Effect context to OpenTelemetry global context
557
- // This allows NodeSDK auto-instrumentation to see Effect spans as parent spans
558
- tracerContext: (f, span) => {
559
- if (span._tag !== "Span") {
560
- return f();
561
- }
562
- const spanContext = {
563
- traceId: span.traceId,
564
- spanId: span.spanId,
565
- traceFlags: span.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE
566
- };
567
- const otelSpan = trace.wrapSpanContext(spanContext);
568
- return context.with(trace.setSpan(context.active(), otelSpan), f);
569
- }
570
- }).pipe(Layer.provide(FetchHttpClient.layer));
574
+ logger.log("Effect OpenTelemetry tracer (unified)");
575
+ logger.log(` Service: ${serviceName}`);
576
+ return Tracer.layerGlobal.pipe(
577
+ Layer.provide(
578
+ Resource.layer({
579
+ serviceName,
580
+ serviceVersion,
581
+ attributes: {
582
+ "platform.component": "effect",
583
+ [ATTR_TELEMETRY_SDK_LANGUAGE]: TELEMETRY_SDK_LANGUAGE_VALUE_NODEJS,
584
+ [ATTR_TELEMETRY_SDK_NAME]: SDK_NAME,
585
+ [ATTR_TELEMETRY_EXPORTER_MODE]: "unified"
586
+ }
587
+ })
588
+ )
589
+ );
571
590
  }).pipe(Layer.unwrapEffect);
572
-
573
- // src/integrations/effect/effect-helpers.ts
574
- function annotateUser(_userId, _email) {
591
+ function annotateUser(userId, email, username) {
592
+ const attributes = {
593
+ "user.id": userId
594
+ };
595
+ if (email) attributes["user.email"] = email;
596
+ if (username) attributes["user.name"] = username;
597
+ return Effect.annotateCurrentSpan(attributes);
575
598
  }
576
- function annotateDataSize(_bytes, _count) {
599
+ function annotateDataSize(bytes, items, compressionRatio) {
600
+ const attributes = {
601
+ "data.size.bytes": bytes,
602
+ "data.size.items": items
603
+ };
604
+ if (compressionRatio !== void 0) {
605
+ attributes["data.compression.ratio"] = compressionRatio;
606
+ }
607
+ return Effect.annotateCurrentSpan(attributes);
608
+ }
609
+ function annotateBatch(totalItems, batchSize, successCount, failureCount) {
610
+ const attributes = {
611
+ "batch.size": batchSize,
612
+ "batch.total_items": totalItems,
613
+ "batch.count": Math.ceil(totalItems / batchSize)
614
+ };
615
+ if (successCount !== void 0) {
616
+ attributes["batch.success_count"] = successCount;
617
+ }
618
+ if (failureCount !== void 0) {
619
+ attributes["batch.failure_count"] = failureCount;
620
+ }
621
+ return Effect.annotateCurrentSpan(attributes);
622
+ }
623
+ function annotateLLM(model, provider, tokens) {
624
+ const attributes = {
625
+ "llm.model": model,
626
+ "llm.provider": provider
627
+ };
628
+ if (tokens) {
629
+ if (tokens.prompt !== void 0) attributes["llm.tokens.prompt"] = tokens.prompt;
630
+ if (tokens.completion !== void 0) attributes["llm.tokens.completion"] = tokens.completion;
631
+ if (tokens.total !== void 0) attributes["llm.tokens.total"] = tokens.total;
632
+ }
633
+ return Effect.annotateCurrentSpan(attributes);
577
634
  }
578
- function annotateBatch(_size, _batchSize) {
635
+ function annotateQuery(query, duration, rowCount, database) {
636
+ const attributes = {
637
+ "db.statement": query.length > 1e3 ? query.substring(0, 1e3) + "..." : query
638
+ };
639
+ if (duration !== void 0) attributes["db.duration.ms"] = duration;
640
+ if (rowCount !== void 0) attributes["db.row_count"] = rowCount;
641
+ if (database) attributes["db.name"] = database;
642
+ return Effect.annotateCurrentSpan(attributes);
579
643
  }
580
- function annotateLLM(_model, _operation, _inputTokens, _outputTokens) {
644
+ function annotateHttpRequest(method, url, statusCode, contentLength) {
645
+ const attributes = {
646
+ "http.method": method,
647
+ "http.url": url
648
+ };
649
+ if (statusCode !== void 0) attributes["http.status_code"] = statusCode;
650
+ if (contentLength !== void 0) attributes["http.response.content_length"] = contentLength;
651
+ return Effect.annotateCurrentSpan(attributes);
581
652
  }
582
- function annotateQuery(_query, _database) {
653
+ function annotateError(error, recoverable, errorType) {
654
+ const errorMessage = typeof error === "string" ? error : error.message;
655
+ const errorStack = typeof error === "string" ? void 0 : error.stack;
656
+ const attributes = {
657
+ "error.message": errorMessage,
658
+ "error.recoverable": recoverable
659
+ };
660
+ if (errorType) attributes["error.type"] = errorType;
661
+ if (errorStack) attributes["error.stack"] = errorStack;
662
+ return Effect.annotateCurrentSpan(attributes);
663
+ }
664
+ function annotatePriority(priority, reason) {
665
+ const attributes = {
666
+ "operation.priority": priority
667
+ };
668
+ if (reason) attributes["operation.priority.reason"] = reason;
669
+ return Effect.annotateCurrentSpan(attributes);
583
670
  }
584
- function annotateHttpRequest(_method, _url, _statusCode) {
671
+ function annotateCache(hit, key, ttl) {
672
+ const attributes = {
673
+ "cache.hit": hit,
674
+ "cache.key": key
675
+ };
676
+ if (ttl !== void 0) attributes["cache.ttl.seconds"] = ttl;
677
+ return Effect.annotateCurrentSpan(attributes);
585
678
  }
586
- function annotateError(_error, _context) {
679
+ function extractEffectMetadata() {
680
+ return Effect.gen(function* () {
681
+ const metadata = {};
682
+ const currentFiber = Fiber.getCurrentFiber();
683
+ if (Option.isSome(currentFiber)) {
684
+ const fiber = currentFiber.value;
685
+ const fiberId = fiber.id();
686
+ metadata["effect.fiber.id"] = FiberId.threadName(fiberId);
687
+ const status = yield* Fiber.status(fiber);
688
+ if (status._tag) {
689
+ metadata["effect.fiber.status"] = status._tag;
690
+ }
691
+ }
692
+ const parentSpanResult = yield* Effect.currentSpan.pipe(
693
+ Effect.option
694
+ // Convert NoSuchElementException to Option
695
+ );
696
+ if (Option.isSome(parentSpanResult)) {
697
+ const parentSpan = parentSpanResult.value;
698
+ metadata["effect.operation.nested"] = true;
699
+ metadata["effect.operation.root"] = false;
700
+ if (parentSpan.spanId) {
701
+ metadata["effect.parent.span.id"] = parentSpan.spanId;
702
+ }
703
+ if (parentSpan.name) {
704
+ metadata["effect.parent.span.name"] = parentSpan.name;
705
+ }
706
+ if (parentSpan.traceId) {
707
+ metadata["effect.parent.trace.id"] = parentSpan.traceId;
708
+ }
709
+ } else {
710
+ metadata["effect.operation.nested"] = false;
711
+ metadata["effect.operation.root"] = true;
712
+ }
713
+ return metadata;
714
+ });
587
715
  }
588
- function annotatePriority(_priority) {
716
+ function autoEnrichSpan() {
717
+ return Effect.gen(function* () {
718
+ const metadata = yield* extractEffectMetadata();
719
+ yield* Effect.annotateCurrentSpan(metadata);
720
+ });
589
721
  }
590
- function annotateCache(_operation, _hit) {
722
+ function withAutoEnrichedSpan(spanName, options) {
723
+ return (self) => {
724
+ return Effect.gen(function* () {
725
+ yield* autoEnrichSpan();
726
+ return yield* self;
727
+ }).pipe(Effect.withSpan(spanName, options));
728
+ };
591
729
  }
592
730
  var createLogicalParentLink = (parentSpan, useSpanLinks) => {
593
731
  if (!useSpanLinks) {
@@ -637,7 +775,7 @@ var runIsolated = (set, effect, name, options) => {
637
775
  return FiberSet$1.run(set, effect, { propagateInterruption });
638
776
  }
639
777
  return Effect.gen(function* () {
640
- const maybeParent = yield* Effect.serviceOption(Tracer.ParentSpan);
778
+ const maybeParent = yield* Effect.serviceOption(Tracer$1.ParentSpan);
641
779
  if (maybeParent._tag === "None" || !captureLogicalParent) {
642
780
  const isolated2 = effect.pipe(
643
781
  Effect.withSpan(name, {
@@ -714,6 +852,6 @@ var FiberSet = {
714
852
  runWithSpan
715
853
  };
716
854
 
717
- export { EffectInstrumentationLive, FiberSet, annotateBatch, annotateCache, annotateDataSize, annotateError, annotateHttpRequest, annotateLLM, annotatePriority, annotateQuery, annotateSpawnedTasks, annotateUser, createEffectInstrumentation, runIsolated, runWithSpan };
855
+ export { EffectInstrumentationLive, FiberSet, annotateBatch, annotateCache, annotateDataSize, annotateError, annotateHttpRequest, annotateLLM, annotatePriority, annotateQuery, annotateSpawnedTasks, annotateUser, autoEnrichSpan, createEffectInstrumentation, extractEffectMetadata, runIsolated, runWithSpan, withAutoEnrichedSpan };
718
856
  //# sourceMappingURL=index.js.map
719
857
  //# sourceMappingURL=index.js.map