@inference-net/otel-cf-workers 2.0.5 → 2.1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"console-Cy5QdByD.js","sources":["../src/logs/console.ts"],"sourcesContent":["import { getLogger } from './provider.js'\nimport { SEVERITY_NUMBERS } from '../constants.js'\n\nconst severityMap = {\n\tdebug: SEVERITY_NUMBERS.DEBUG,\n\tlog: SEVERITY_NUMBERS.INFO,\n\tinfo: SEVERITY_NUMBERS.INFO,\n\twarn: SEVERITY_NUMBERS.WARN,\n\terror: SEVERITY_NUMBERS.ERROR,\n} as const\n\ntype ConsoleMethod = keyof typeof severityMap\n\n/**\n * Instrument console methods to emit OpenTelemetry log records\n * This is OPT-IN and must be explicitly enabled in configuration\n */\nexport function instrumentConsole() {\n\tconst logger = getLogger('console')\n\n\tfor (const [method, severityNumber] of Object.entries(severityMap)) {\n\t\tconst consoleMethod = method as ConsoleMethod\n\t\tconst original = console[consoleMethod]\n\n\t\tif (typeof original !== 'function') {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Replace console method with instrumented version\n\t\t;(console as any)[consoleMethod] = function (...args: any[]) {\n\t\t\ttry {\n\t\t\t\t// Emit log record\n\t\t\t\tlogger.emit({\n\t\t\t\t\tseverityNumber,\n\t\t\t\t\tseverityText: method.toUpperCase(),\n\t\t\t\t\tbody: args.length === 1 ? String(args[0]) : args.map(String).join(' '),\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\t'log.source': 'console',\n\t\t\t\t\t\t'log.method': method,\n\t\t\t\t\t\t'log.args_count': args.length,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t} catch (error) {\n\t\t\t\t// Don't break console if logging fails - but can't use console.error here!\n\t\t\t}\n\n\t\t\t// Always call original console method\n\t\t\treturn original.apply(console, args)\n\t\t}\n\t}\n}\n"],"names":[],"mappings":";;AAGA,MAAM,WAAA,GAAc;AAAA,EACnB,OAAO,gBAAA,CAAiB,KAAA;AAAA,EACxB,KAAK,gBAAA,CAAiB,IAAA;AAAA,EACtB,MAAM,gBAAA,CAAiB,IAAA;AAAA,EACvB,MAAM,gBAAA,CAAiB,IAAA;AAAA,EACvB,OAAO,gBAAA,CAAiB;AACzB,CAAA;AAQO,SAAS,iBAAA,GAAoB;AACnC,EAAA,MAAM,MAAA,GAAS,UAAU,SAAS,CAAA;AAElC,EAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,cAAc,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AACnE,IAAA,MAAM,aAAA,GAAgB,MAAA;AACtB,IAAA,MAAM,QAAA,GAAW,QAAQ,aAAa,CAAA;AAEtC,IAAA,IAAI,OAAO,aAAa,UAAA,EAAY;AACnC,MAAA;AAAA,IACD;AAGC,IAAC,OAAA,CAAgB,aAAa,CAAA,GAAI,SAAA,GAAa,IAAA,EAAa;AAC5D,MAAA,IAAI;AAEH,QAAA,MAAA,CAAO,IAAA,CAAK;AAAA,UACX,cAAA;AAAA,UACA,YAAA,EAAc,OAAO,WAAA,EAAY;AAAA,UACjC,IAAA,EAAM,IAAA,CAAK,MAAA,KAAW,CAAA,GAAI,OAAO,IAAA,CAAK,CAAC,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,UACrE,UAAA,EAAY;AAAA,YACX,YAAA,EAAc,SAAA;AAAA,YACd,YAAA,EAAc,MAAA;AAAA,YACd,kBAAkB,IAAA,CAAK;AAAA;AACxB,SACA,CAAA;AAAA,MACF,SAAS,KAAA,EAAO;AAAA,MAEhB;AAGA,MAAA,OAAO,QAAA,CAAS,KAAA,CAAM,OAAA,EAAS,IAAI,CAAA;AAAA,IACpC,CAAA;AAAA,EACD;AACD;;;;"}
1
+ {"version":3,"file":"console-Cy5QdByD.js","sources":["../src/logs/console.ts"],"sourcesContent":["import { getLogger } from './provider'\nimport { SEVERITY_NUMBERS } from '../constants'\n\nconst severityMap = {\n\tdebug: SEVERITY_NUMBERS.DEBUG,\n\tlog: SEVERITY_NUMBERS.INFO,\n\tinfo: SEVERITY_NUMBERS.INFO,\n\twarn: SEVERITY_NUMBERS.WARN,\n\terror: SEVERITY_NUMBERS.ERROR,\n} as const\n\ntype ConsoleMethod = keyof typeof severityMap\n\n/**\n * Instrument console methods to emit OpenTelemetry log records\n * This is OPT-IN and must be explicitly enabled in configuration\n */\nexport function instrumentConsole() {\n\tconst logger = getLogger('console')\n\n\tfor (const [method, severityNumber] of Object.entries(severityMap)) {\n\t\tconst consoleMethod = method as ConsoleMethod\n\t\tconst original = console[consoleMethod]\n\n\t\tif (typeof original !== 'function') {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Replace console method with instrumented version\n\t\t;(console as any)[consoleMethod] = function (...args: any[]) {\n\t\t\ttry {\n\t\t\t\t// Emit log record\n\t\t\t\tlogger.emit({\n\t\t\t\t\tseverityNumber,\n\t\t\t\t\tseverityText: method.toUpperCase(),\n\t\t\t\t\tbody: args.length === 1 ? String(args[0]) : args.map(String).join(' '),\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\t'log.source': 'console',\n\t\t\t\t\t\t'log.method': method,\n\t\t\t\t\t\t'log.args_count': args.length,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t} catch (error) {\n\t\t\t\t// Don't break console if logging fails - but can't use console.error here!\n\t\t\t}\n\n\t\t\t// Always call original console method\n\t\t\treturn original.apply(console, args)\n\t\t}\n\t}\n}\n"],"names":[],"mappings":";;AAGA,MAAM,WAAA,GAAc;AAAA,EACnB,OAAO,gBAAA,CAAiB,KAAA;AAAA,EACxB,KAAK,gBAAA,CAAiB,IAAA;AAAA,EACtB,MAAM,gBAAA,CAAiB,IAAA;AAAA,EACvB,MAAM,gBAAA,CAAiB,IAAA;AAAA,EACvB,OAAO,gBAAA,CAAiB;AACzB,CAAA;AAQO,SAAS,iBAAA,GAAoB;AACnC,EAAA,MAAM,MAAA,GAAS,UAAU,SAAS,CAAA;AAElC,EAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,cAAc,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AACnE,IAAA,MAAM,aAAA,GAAgB,MAAA;AACtB,IAAA,MAAM,QAAA,GAAW,QAAQ,aAAa,CAAA;AAEtC,IAAA,IAAI,OAAO,aAAa,UAAA,EAAY;AACnC,MAAA;AAAA,IACD;AAGC,IAAC,OAAA,CAAgB,aAAa,CAAA,GAAI,SAAA,GAAa,IAAA,EAAa;AAC5D,MAAA,IAAI;AAEH,QAAA,MAAA,CAAO,IAAA,CAAK;AAAA,UACX,cAAA;AAAA,UACA,YAAA,EAAc,OAAO,WAAA,EAAY;AAAA,UACjC,IAAA,EAAM,IAAA,CAAK,MAAA,KAAW,CAAA,GAAI,OAAO,IAAA,CAAK,CAAC,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,UACrE,UAAA,EAAY;AAAA,YACX,YAAA,EAAc,SAAA;AAAA,YACd,YAAA,EAAc,MAAA;AAAA,YACd,kBAAkB,IAAA,CAAK;AAAA;AACxB,SACA,CAAA;AAAA,MACF,SAAS,KAAA,EAAO;AAAA,MAEhB;AAGA,MAAA,OAAO,QAAA,CAAS,KAAA,CAAM,OAAA,EAAS,IAAI,CAAA;AAAA,IACpC,CAAA;AAAA,EACD;AACD;;;;"}
package/dist/index.d.ts CHANGED
@@ -105,7 +105,7 @@ export declare interface DOConstructorTrigger {
105
105
  name?: string;
106
106
  }
107
107
 
108
- declare type Env_2 = Record<string, any>;
108
+ declare type Env = Record<string, any>;
109
109
 
110
110
  export declare type ExporterConfig = OTLPExporterConfig | SpanExporter;
111
111
 
@@ -168,7 +168,7 @@ export declare interface InitialSpanInfo {
168
168
  context?: Context;
169
169
  }
170
170
 
171
- export declare function instrument<E extends Env_2, Q, C>(handler: ExportedHandler<E, Q, C>, config: ConfigurationOption): ExportedHandler<E, Q, C>;
171
+ export declare function instrument<E extends Env, Q, C>(handler: ExportedHandler<E, Q, C>, config: ConfigurationOption): ExportedHandler<E, Q, C>;
172
172
 
173
173
  export declare interface InstrumentationOptions {
174
174
  instrumentGlobalFetch?: boolean;
package/dist/index.js CHANGED
@@ -96,7 +96,7 @@ function passthroughGet(target, prop, thisArg) {
96
96
  }
97
97
  }
98
98
 
99
- const PACKAGE_VERSION = "2.0.5";
99
+ const PACKAGE_VERSION = "2.1.1";
100
100
  const PACKAGE_NAME = "@inference-net/otel-cf-workers";
101
101
  const ATTR_CLOUDFLARE_COLO = "cloudflare.colo";
102
102
  const ATTR_CLOUDFLARE_RAY_ID = "cloudflare.ray_id";
@@ -1284,14 +1284,6 @@ function getLogger(name, version, options) {
1284
1284
  return getGlobalLoggerProvider().getLogger(name, version, options);
1285
1285
  }
1286
1286
 
1287
- const provider = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
1288
- __proto__: null,
1289
- WorkerLoggerProvider,
1290
- getGlobalLoggerProvider,
1291
- getLogger,
1292
- setGlobalLoggerProvider
1293
- }, Symbol.toStringTag, { value: 'Module' }));
1294
-
1295
1287
  function isValidAttributeValue(value) {
1296
1288
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
1297
1289
  }
@@ -1449,11 +1441,22 @@ function getParentContextFromRequest(request) {
1449
1441
  const acceptTraceContext = typeof workerConfig.handlers.fetch.acceptTraceContext === "function" ? workerConfig.handlers.fetch.acceptTraceContext(request) : workerConfig.handlers.fetch.acceptTraceContext ?? true;
1450
1442
  return acceptTraceContext ? getParentContextFromHeaders(request.headers) : context.active();
1451
1443
  }
1452
- function updateSpanNameOnRoute(span, request) {
1444
+ function updateSpanNameOnRoute(span, request, result) {
1453
1445
  const readable = span;
1454
- if (readable.attributes["http.route"]) {
1446
+ const route = readable.attributes?.["http.route"];
1447
+ if (route) {
1455
1448
  const method = request.method.toUpperCase();
1456
- span.updateName(`${method} ${readable.attributes["http.route"]}`);
1449
+ span.updateName(`${method} ${route}`);
1450
+ }
1451
+ if (result) {
1452
+ if (result.status >= 400) {
1453
+ span.setStatus({
1454
+ code: SpanStatusCode.ERROR,
1455
+ message: `HTTP ${result.status}: ${result.statusText}`
1456
+ });
1457
+ } else {
1458
+ span.setStatus({ code: SpanStatusCode.OK });
1459
+ }
1457
1460
  }
1458
1461
  }
1459
1462
  const fetchInstrumentation = {
@@ -1468,8 +1471,10 @@ const fetchInstrumentation = {
1468
1471
  Object.assign(attributes, gatherRootSpanAttributes(request, "fetch"));
1469
1472
  Object.assign(attributes, gatherUserAgentAttributes(request));
1470
1473
  const method = request.method.toUpperCase();
1474
+ const url = new URL(request.url);
1475
+ const route = url.pathname;
1471
1476
  return {
1472
- name: `fetchHandler ${method}`,
1477
+ name: `${method} ${route}`,
1473
1478
  options: {
1474
1479
  attributes,
1475
1480
  kind: SpanKind.SERVER
@@ -1478,7 +1483,10 @@ const fetchInstrumentation = {
1478
1483
  };
1479
1484
  },
1480
1485
  getAttributesFromResult: (response) => {
1481
- return gatherResponseAttributes(response);
1486
+ const attrs = gatherResponseAttributes(response);
1487
+ attrs["http.status_code"] = response.status;
1488
+ attrs["http.status_text"] = response.statusText;
1489
+ return attrs;
1482
1490
  },
1483
1491
  executionSucces: updateSpanNameOnRoute,
1484
1492
  executionFailed: updateSpanNameOnRoute
@@ -1512,6 +1520,18 @@ function instrumentClientFetch(fetchFn, configFn, attrs) {
1512
1520
  if (request.cf) span.setAttributes(gatherOutgoingCfAttributes(request.cf));
1513
1521
  const response = await Reflect.apply(target, thisArg, [request]);
1514
1522
  span.setAttributes(gatherResponseAttributes(response));
1523
+ span.setAttributes({
1524
+ "http.status_code": response.status,
1525
+ "http.status_text": response.statusText
1526
+ });
1527
+ if (response.status >= 400) {
1528
+ span.setStatus({
1529
+ code: SpanStatusCode.ERROR,
1530
+ message: `HTTP ${response.status}: ${response.statusText}`
1531
+ });
1532
+ } else {
1533
+ span.setStatus({ code: SpanStatusCode.OK });
1534
+ }
1515
1535
  return response;
1516
1536
  } catch (error) {
1517
1537
  span.recordException(error);
@@ -2870,7 +2890,7 @@ function instrumentSQLStorageExec(fn, operation) {
2870
2890
  const fnHandler = {
2871
2891
  apply: (target, thisArg, argArray) => {
2872
2892
  const query = argArray[0];
2873
- const bindings = argArray[1];
2893
+ const bindings = argArray.slice(1);
2874
2894
  const attributes = {
2875
2895
  [ATTR_DB_SYSTEM_NAME]: dbSystem,
2876
2896
  [ATTR_DB_OPERATION_NAME]: operation,
@@ -2883,58 +2903,74 @@ function instrumentSQLStorageExec(fn, operation) {
2883
2903
  kind: SpanKind.CLIENT,
2884
2904
  attributes
2885
2905
  };
2886
- return tracer.startActiveSpan(`Durable Object SQL ${operation}`, options, async (span) => {
2887
- const result = await Reflect.apply(target, thisArg, argArray);
2888
- if (result && typeof result === "object") {
2889
- if ("rowsRead" in result) {
2890
- span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_READ, result.rowsRead);
2906
+ return tracer.startActiveSpan(`Durable Object SQL ${operation}`, options, (span) => {
2907
+ const cursor = Reflect.apply(target, thisArg, argArray);
2908
+ let spanEnded = false;
2909
+ const endSpanWithMetrics = () => {
2910
+ if (spanEnded) return;
2911
+ spanEnded = true;
2912
+ if (typeof cursor.rowsRead === "number") {
2913
+ span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_READ, cursor.rowsRead);
2891
2914
  }
2892
- if ("rowsWritten" in result) {
2893
- span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_WRITTEN, result.rowsWritten);
2915
+ if (typeof cursor.rowsWritten === "number") {
2916
+ span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_WRITTEN, cursor.rowsWritten);
2894
2917
  }
2895
- }
2896
- span.end();
2897
- return result;
2898
- });
2899
- }
2900
- };
2901
- return wrap(fn, fnHandler);
2902
- }
2903
- function instrumentSQLStorageExecBatch(fn, operation) {
2904
- const tracer = trace.getTracer("do_sql_storage");
2905
- const fnHandler = {
2906
- apply: (target, thisArg, argArray) => {
2907
- const statements = argArray[0];
2908
- const attributes = {
2909
- [ATTR_DB_SYSTEM_NAME]: dbSystem,
2910
- [ATTR_DB_OPERATION_NAME]: operation,
2911
- [ATTR_DB_OPERATION_BATCH_SIZE]: statements.length
2912
- };
2913
- if (statements.length > 0 && statements[0]) {
2914
- attributes[ATTR_DB_QUERY_TEXT] = statements[0].query;
2915
- }
2916
- const options = {
2917
- kind: SpanKind.CLIENT,
2918
- attributes
2919
- };
2920
- return tracer.startActiveSpan(`Durable Object SQL ${operation}`, options, async (span) => {
2921
- const results = await Reflect.apply(target, thisArg, argArray);
2922
- let totalRowsRead = 0;
2923
- let totalRowsWritten = 0;
2924
- for (const result of results) {
2925
- if (result && typeof result === "object") {
2926
- if ("rowsRead" in result) {
2927
- totalRowsRead += result.rowsRead;
2918
+ span.end();
2919
+ };
2920
+ Promise.resolve().then(() => {
2921
+ if (!spanEnded) {
2922
+ endSpanWithMetrics();
2923
+ }
2924
+ });
2925
+ const wrappedCursor = new Proxy(cursor, {
2926
+ get(target2, prop, receiver) {
2927
+ const value = Reflect.get(target2, prop, receiver);
2928
+ if (prop === "toArray") {
2929
+ return function(...args) {
2930
+ const result = typeof value === "function" ? value.apply(target2, args) : value;
2931
+ endSpanWithMetrics();
2932
+ return result;
2933
+ };
2928
2934
  }
2929
- if ("rowsWritten" in result) {
2930
- totalRowsWritten += result.rowsWritten;
2935
+ if (prop === "one") {
2936
+ return function(...args) {
2937
+ const result = typeof value === "function" ? value.apply(target2, args) : value;
2938
+ endSpanWithMetrics();
2939
+ return result;
2940
+ };
2931
2941
  }
2942
+ if (prop === Symbol.iterator) {
2943
+ return function() {
2944
+ const iterator = typeof value === "function" ? value.apply(target2) : value;
2945
+ let iterationComplete = false;
2946
+ return {
2947
+ next() {
2948
+ const result = iterator.next();
2949
+ if (result.done && !iterationComplete) {
2950
+ iterationComplete = true;
2951
+ endSpanWithMetrics();
2952
+ }
2953
+ return result;
2954
+ },
2955
+ [Symbol.iterator]() {
2956
+ return this;
2957
+ }
2958
+ };
2959
+ };
2960
+ }
2961
+ if (prop === "next") {
2962
+ return function(...args) {
2963
+ const result = typeof value === "function" ? value.apply(target2, args) : value;
2964
+ if (result && result.done) {
2965
+ endSpanWithMetrics();
2966
+ }
2967
+ return result;
2968
+ };
2969
+ }
2970
+ return typeof value === "function" ? value.bind(target2) : value;
2932
2971
  }
2933
- }
2934
- span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_READ, totalRowsRead);
2935
- span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_WRITTEN, totalRowsWritten);
2936
- span.end();
2937
- return results;
2972
+ });
2973
+ return wrappedCursor;
2938
2974
  });
2939
2975
  }
2940
2976
  };
@@ -2950,8 +2986,6 @@ function instrumentSQLStorage(sql) {
2950
2986
  switch (prop) {
2951
2987
  case "exec":
2952
2988
  return instrumentSQLStorageExec(fn, "exec");
2953
- case "execBatch":
2954
- return instrumentSQLStorageExecBatch(fn, "execBatch");
2955
2989
  default:
2956
2990
  return fn;
2957
2991
  }
@@ -3016,7 +3050,8 @@ function instrumentRpcMethod(method, methodName, nsName, stubId) {
3016
3050
  kind: SpanKind.CLIENT,
3017
3051
  attributes
3018
3052
  };
3019
- const spanName = `RPC ${nsName}.${methodName}`;
3053
+ const serviceName = stubId.name || nsName;
3054
+ const spanName = `RPC ${serviceName}.${methodName}`;
3020
3055
  return tracer.startActiveSpan(spanName, options, async (span) => {
3021
3056
  try {
3022
3057
  const contextCarrier = injectRpcContext(context.active(), stubId.name);
@@ -3203,17 +3238,6 @@ function instrumentRpcHandlerMethod(fn, methodName, initialiser, env, id) {
3203
3238
  const [extractedContext, cleanedArgs] = extractAndRemoveRpcContext(argArray);
3204
3239
  const carrierDoName = argArray.length > 0 && extractedContext ? argArray[0].doName : void 0;
3205
3240
  const doName = carrierDoName || id.name || void 0;
3206
- const carrier = argArray.length > 0 ? argArray[0] : void 0;
3207
- console.log("[DO RPC Server]", {
3208
- methodName,
3209
- hasExtractedContext: !!extractedContext,
3210
- carrierDoName,
3211
- idName: id.name,
3212
- finalDoName: doName,
3213
- argArrayLength: argArray.length,
3214
- cleanedArgsLength: cleanedArgs.length,
3215
- carrierHeaders: carrier ? carrier.headers : void 0
3216
- });
3217
3241
  let context$1 = extractedContext || context.active();
3218
3242
  context$1 = setConfig(config, context$1);
3219
3243
  const tracer = trace.getTracer("do_rpc_handler");
@@ -3488,7 +3512,6 @@ function createInitialiser(config) {
3488
3512
  }
3489
3513
  async function exportTelemetry(traceId, tracker) {
3490
3514
  const tracer = trace.getTracer("export");
3491
- const { getLogger } = await Promise.resolve().then(() => provider);
3492
3515
  const logger = getLogger("export");
3493
3516
  if (tracer instanceof WorkerTracer) {
3494
3517
  await scheduler.wait(1);
@@ -3518,12 +3541,19 @@ function createHandlerFlowFn(instrumentation) {
3518
3541
  const result = tracer.startActiveSpan(name, options, parentContext, async (span) => {
3519
3542
  try {
3520
3543
  const result2 = await handlerFn(instrumentedTrigger, proxiedEnv, proxiedCtx);
3521
- if (instrumentation.getAttributesFromResult) {
3522
- const attributes = instrumentation.getAttributesFromResult(result2);
3523
- span.setAttributes(attributes);
3524
- }
3525
- if (instrumentation.executionSucces) {
3526
- instrumentation.executionSucces(span, trigger, result2);
3544
+ const isWebSocketUpgrade = isRequest(trigger) && trigger.headers.get("upgrade")?.toLowerCase() === "websocket" && trigger.headers.has("sec-websocket-key");
3545
+ if (isWebSocketUpgrade) {
3546
+ const logger = getLogger("handler");
3547
+ logger.trace("WebSocket upgrade detected, closing span without reading response");
3548
+ span.setStatus({ code: SpanStatusCode.OK });
3549
+ } else {
3550
+ if (instrumentation.getAttributesFromResult) {
3551
+ const attributes = instrumentation.getAttributesFromResult(result2);
3552
+ span.setAttributes(attributes);
3553
+ }
3554
+ if (instrumentation.executionSucces) {
3555
+ instrumentation.executionSucces(span, trigger, result2);
3556
+ }
3527
3557
  }
3528
3558
  return result2;
3529
3559
  } catch (error) {