@sentry/nitro 10.53.1 → 10.54.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.
- package/build/esm/config.js +1 -15
- package/build/esm/config.js.map +1 -1
- package/build/esm/instruments/instrumentServer.js +1 -5
- package/build/esm/instruments/instrumentServer.js.map +1 -1
- package/build/esm/module.js +3 -6
- package/build/esm/module.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/runtime/hooks/captureErrorHook.js +5 -29
- package/build/esm/runtime/hooks/captureErrorHook.js.map +1 -1
- package/build/esm/runtime/hooks/captureStorageEvents.js +34 -69
- package/build/esm/runtime/hooks/captureStorageEvents.js.map +1 -1
- package/build/esm/runtime/hooks/captureTracingEvents.js +50 -115
- package/build/esm/runtime/hooks/captureTracingEvents.js.map +1 -1
- package/build/esm/runtime/hooks/setServerTimingHeaders.js +3 -10
- package/build/esm/runtime/hooks/setServerTimingHeaders.js.map +1 -1
- package/build/esm/runtime/plugins/server.js +2 -3
- package/build/esm/runtime/plugins/server.js.map +1 -1
- package/build/esm/sdk.js +3 -16
- package/build/esm/sdk.js.map +1 -1
- package/build/esm/sourceMaps.js +26 -107
- package/build/esm/sourceMaps.js.map +1 -1
- package/build/esm/utils/plugin.js +0 -3
- package/build/esm/utils/plugin.js.map +1 -1
- package/build/esm/utils/resolver.js +2 -11
- package/build/esm/utils/resolver.js.map +1 -1
- package/package.json +5 -5
package/build/esm/config.js
CHANGED
|
@@ -1,30 +1,16 @@
|
|
|
1
1
|
import { createNitroModule } from './module.js';
|
|
2
2
|
import { configureSourcemapSettings } from './sourceMaps.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Modifies the passed in Nitro configuration with automatic build-time instrumentation.
|
|
6
|
-
*/
|
|
7
4
|
function withSentryConfig(config, sentryOptions) {
|
|
8
5
|
return setupSentryNitroModule(config, sentryOptions);
|
|
9
6
|
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Sets up the Sentry Nitro module, useful for meta framework integrations.
|
|
13
|
-
*/
|
|
14
|
-
function setupSentryNitroModule(
|
|
15
|
-
config,
|
|
16
|
-
moduleOptions,
|
|
17
|
-
_serverConfigFile,
|
|
18
|
-
) {
|
|
7
|
+
function setupSentryNitroModule(config, moduleOptions, _serverConfigFile) {
|
|
19
8
|
if (!config.tracingChannel) {
|
|
20
9
|
config.tracingChannel = true;
|
|
21
10
|
}
|
|
22
|
-
|
|
23
11
|
const { sentryEnabledSourcemaps } = configureSourcemapSettings(config, moduleOptions);
|
|
24
|
-
|
|
25
12
|
config.modules = config.modules || [];
|
|
26
13
|
config.modules.push(createNitroModule(moduleOptions, sentryEnabledSourcemaps));
|
|
27
|
-
|
|
28
14
|
return config;
|
|
29
15
|
}
|
|
30
16
|
|
package/build/esm/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sources":["../../src/config.ts"],"sourcesContent":["import type { BuildTimeOptionsBase } from '@sentry/core';\nimport type { NitroConfig } from 'nitro/types';\nimport { createNitroModule } from './module';\nimport { configureSourcemapSettings } from './sourceMaps';\n\nexport type SentryNitroOptions = BuildTimeOptionsBase;\n\n/**\n * Modifies the passed in Nitro configuration with automatic build-time instrumentation.\n */\nexport function withSentryConfig(config: NitroConfig, sentryOptions?: SentryNitroOptions): NitroConfig {\n return setupSentryNitroModule(config, sentryOptions);\n}\n\n/**\n * Sets up the Sentry Nitro module, useful for meta framework integrations.\n */\nexport function setupSentryNitroModule(\n config: NitroConfig,\n moduleOptions?: SentryNitroOptions,\n _serverConfigFile?: string,\n): NitroConfig {\n if (!config.tracingChannel) {\n config.tracingChannel = true;\n }\n\n const { sentryEnabledSourcemaps } = configureSourcemapSettings(config, moduleOptions);\n\n config.modules = config.modules || [];\n config.modules.push(createNitroModule(moduleOptions, sentryEnabledSourcemaps));\n\n return config;\n}\n"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"config.js","sources":["../../src/config.ts"],"sourcesContent":["import type { BuildTimeOptionsBase } from '@sentry/core';\nimport type { NitroConfig } from 'nitro/types';\nimport { createNitroModule } from './module';\nimport { configureSourcemapSettings } from './sourceMaps';\n\nexport type SentryNitroOptions = BuildTimeOptionsBase;\n\n/**\n * Modifies the passed in Nitro configuration with automatic build-time instrumentation.\n */\nexport function withSentryConfig(config: NitroConfig, sentryOptions?: SentryNitroOptions): NitroConfig {\n return setupSentryNitroModule(config, sentryOptions);\n}\n\n/**\n * Sets up the Sentry Nitro module, useful for meta framework integrations.\n */\nexport function setupSentryNitroModule(\n config: NitroConfig,\n moduleOptions?: SentryNitroOptions,\n _serverConfigFile?: string,\n): NitroConfig {\n if (!config.tracingChannel) {\n config.tracingChannel = true;\n }\n\n const { sentryEnabledSourcemaps } = configureSourcemapSettings(config, moduleOptions);\n\n config.modules = config.modules || [];\n config.modules.push(createNitroModule(moduleOptions, sentryEnabledSourcemaps));\n\n return config;\n}\n"],"names":[],"mappings":";;;AAUO,SAAS,gBAAA,CAAiB,QAAqB,aAAA,EAAiD;AACrG,EAAA,OAAO,sBAAA,CAAuB,QAAQ,aAAa,CAAA;AACrD;AAKO,SAAS,sBAAA,CACd,MAAA,EACA,aAAA,EACA,iBAAA,EACa;AACb,EAAA,IAAI,CAAC,OAAO,cAAA,EAAgB;AAC1B,IAAA,MAAA,CAAO,cAAA,GAAiB,IAAA;AAAA,EAC1B;AAEA,EAAA,MAAM,EAAE,uBAAA,EAAwB,GAAI,0BAAA,CAA2B,QAAQ,aAAa,CAAA;AAEpF,EAAA,MAAA,CAAO,OAAA,GAAU,MAAA,CAAO,OAAA,IAAW,EAAC;AACpC,EAAA,MAAA,CAAO,OAAA,CAAQ,IAAA,CAAK,iBAAA,CAAkB,aAAA,EAAe,uBAAuB,CAAC,CAAA;AAE7E,EAAA,OAAO,MAAA;AACT;;;;"}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { addPlugin } from '../utils/plugin.js';
|
|
2
2
|
import { createResolver } from '../utils/resolver.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Sets up the Nitro server instrumentation plugin
|
|
6
|
-
* @param nitro - The Nitro instance.
|
|
7
|
-
*/
|
|
8
4
|
function instrumentServer(nitro) {
|
|
9
5
|
const moduleResolver = createResolver(import.meta.url);
|
|
10
|
-
addPlugin(nitro, moduleResolver.resolve(
|
|
6
|
+
addPlugin(nitro, moduleResolver.resolve("../runtime/plugins/server"));
|
|
11
7
|
}
|
|
12
8
|
|
|
13
9
|
export { instrumentServer };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentServer.js","sources":["../../../src/instruments/instrumentServer.ts"],"sourcesContent":["import type { Nitro } from 'nitro/types';\nimport { addPlugin } from '../utils/plugin';\nimport { createResolver } from '../utils/resolver';\n\n/**\n * Sets up the Nitro server instrumentation plugin\n * @param nitro - The Nitro instance.\n */\nexport function instrumentServer(nitro: Nitro): void {\n const moduleResolver = createResolver(import.meta.url);\n addPlugin(nitro, moduleResolver.resolve('../runtime/plugins/server'));\n}\n"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"instrumentServer.js","sources":["../../../src/instruments/instrumentServer.ts"],"sourcesContent":["import type { Nitro } from 'nitro/types';\nimport { addPlugin } from '../utils/plugin';\nimport { createResolver } from '../utils/resolver';\n\n/**\n * Sets up the Nitro server instrumentation plugin\n * @param nitro - The Nitro instance.\n */\nexport function instrumentServer(nitro: Nitro): void {\n const moduleResolver = createResolver(import.meta.url);\n addPlugin(nitro, moduleResolver.resolve('../runtime/plugins/server'));\n}\n"],"names":[],"mappings":";;;AAQO,SAAS,iBAAiB,KAAA,EAAoB;AACnD,EAAA,MAAM,cAAA,GAAiB,cAAA,CAAe,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AACrD,EAAA,SAAA,CAAU,KAAA,EAAO,cAAA,CAAe,OAAA,CAAQ,2BAA2B,CAAC,CAAA;AACtE;;;;"}
|
package/build/esm/module.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { instrumentServer } from './instruments/instrumentServer.js';
|
|
2
2
|
import { setupSourceMaps } from './sourceMaps.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Creates a Nitro module to setup the Sentry SDK.
|
|
6
|
-
*/
|
|
7
4
|
function createNitroModule(sentryOptions, sentryEnabledSourcemaps) {
|
|
8
5
|
return {
|
|
9
|
-
name:
|
|
10
|
-
setup: nitro => {
|
|
6
|
+
name: "sentry",
|
|
7
|
+
setup: (nitro) => {
|
|
11
8
|
instrumentServer(nitro);
|
|
12
9
|
setupSourceMaps(nitro, sentryOptions, sentryEnabledSourcemaps);
|
|
13
|
-
}
|
|
10
|
+
}
|
|
14
11
|
};
|
|
15
12
|
}
|
|
16
13
|
|
package/build/esm/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.js","sources":["../../src/module.ts"],"sourcesContent":["import type { NitroModule } from 'nitro/types';\nimport type { SentryNitroOptions } from './config';\nimport { instrumentServer } from './instruments/instrumentServer';\nimport { setupSourceMaps } from './sourceMaps';\n\n/**\n * Creates a Nitro module to setup the Sentry SDK.\n */\nexport function createNitroModule(sentryOptions?: SentryNitroOptions, sentryEnabledSourcemaps?: boolean): NitroModule {\n return {\n name: 'sentry',\n setup: nitro => {\n instrumentServer(nitro);\n setupSourceMaps(nitro, sentryOptions, sentryEnabledSourcemaps);\n },\n };\n}\n"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"module.js","sources":["../../src/module.ts"],"sourcesContent":["import type { NitroModule } from 'nitro/types';\nimport type { SentryNitroOptions } from './config';\nimport { instrumentServer } from './instruments/instrumentServer';\nimport { setupSourceMaps } from './sourceMaps';\n\n/**\n * Creates a Nitro module to setup the Sentry SDK.\n */\nexport function createNitroModule(sentryOptions?: SentryNitroOptions, sentryEnabledSourcemaps?: boolean): NitroModule {\n return {\n name: 'sentry',\n setup: nitro => {\n instrumentServer(nitro);\n setupSourceMaps(nitro, sentryOptions, sentryEnabledSourcemaps);\n },\n };\n}\n"],"names":[],"mappings":";;;AAQO,SAAS,iBAAA,CAAkB,eAAoC,uBAAA,EAAgD;AACpH,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IACN,OAAO,CAAA,KAAA,KAAS;AACd,MAAA,gBAAA,CAAiB,KAAK,CAAA;AACtB,MAAA,eAAA,CAAgB,KAAA,EAAO,eAAe,uBAAuB,CAAA;AAAA,IAC/D;AAAA,GACF;AACF;;;;"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"10.
|
|
1
|
+
{"type":"module","version":"10.54.0","sideEffects":false}
|
|
@@ -1,67 +1,43 @@
|
|
|
1
1
|
import { getClient, parseUrl, getCurrentScope, getActiveSpan, getRootSpan, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, captureException, flushIfServerless } from '@sentry/core';
|
|
2
2
|
import { HTTPError } from 'h3';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Extracts the relevant context information from the error context (HTTPEvent in Nitro Error)
|
|
6
|
-
* and creates a structured context object.
|
|
7
|
-
*/
|
|
8
4
|
function extractErrorContext(errorContext) {
|
|
9
5
|
const ctx = {};
|
|
10
|
-
|
|
11
6
|
if (!errorContext) {
|
|
12
7
|
return ctx;
|
|
13
8
|
}
|
|
14
|
-
|
|
15
9
|
if (errorContext.event) {
|
|
16
10
|
ctx.method = errorContext.event.req.method;
|
|
17
11
|
ctx.path = parseUrl(errorContext.event.req.url).path;
|
|
18
12
|
}
|
|
19
|
-
|
|
20
13
|
if (Array.isArray(errorContext.tags)) {
|
|
21
14
|
ctx.tags = errorContext.tags;
|
|
22
15
|
}
|
|
23
|
-
|
|
24
16
|
return ctx;
|
|
25
17
|
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Hook that can be added in a Nitro plugin. It captures an error and sends it to Sentry.
|
|
29
|
-
*/
|
|
30
18
|
async function captureErrorHook(error, errorContext) {
|
|
31
19
|
const sentryClient = getClient();
|
|
32
20
|
const sentryClientOptions = sentryClient?.getOptions();
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
sentryClientOptions &&
|
|
36
|
-
'enableNitroErrorHandler' in sentryClientOptions &&
|
|
37
|
-
sentryClientOptions.enableNitroErrorHandler === false
|
|
38
|
-
) {
|
|
21
|
+
if (sentryClientOptions && "enableNitroErrorHandler" in sentryClientOptions && sentryClientOptions.enableNitroErrorHandler === false) {
|
|
39
22
|
return;
|
|
40
23
|
}
|
|
41
|
-
|
|
42
|
-
// Do not report HTTPErrors with 3xx or 4xx status codes
|
|
43
24
|
if (HTTPError.isError(error) && error.status >= 300 && error.status < 500) {
|
|
44
25
|
return;
|
|
45
26
|
}
|
|
46
|
-
|
|
47
|
-
const method = errorContext.event?.req.method ?? '';
|
|
27
|
+
const method = errorContext.event?.req.method ?? "";
|
|
48
28
|
const path = errorContext.event?.req.url ? parseUrl(errorContext.event.req.url).path : null;
|
|
49
|
-
|
|
50
29
|
if (path) {
|
|
51
30
|
getCurrentScope().setTransactionName(`${method} ${path}`);
|
|
52
31
|
const activeSpan = getActiveSpan();
|
|
53
|
-
const activeRootSpan = activeSpan ? getRootSpan(activeSpan) :
|
|
32
|
+
const activeRootSpan = activeSpan ? getRootSpan(activeSpan) : void 0;
|
|
54
33
|
activeRootSpan?.updateName(`${method} ${path}`);
|
|
55
|
-
activeRootSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
|
|
34
|
+
activeRootSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, "route");
|
|
56
35
|
}
|
|
57
|
-
|
|
58
36
|
const structuredContext = extractErrorContext(errorContext);
|
|
59
|
-
|
|
60
37
|
captureException(error, {
|
|
61
38
|
captureContext: { contexts: { nitro: structuredContext } },
|
|
62
|
-
mechanism: { handled: false, type:
|
|
39
|
+
mechanism: { handled: false, type: "auto.function.nitro.captureErrorHook" }
|
|
63
40
|
});
|
|
64
|
-
|
|
65
41
|
await flushIfServerless();
|
|
66
42
|
}
|
|
67
43
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"captureErrorHook.js","sources":["../../../../src/runtime/hooks/captureErrorHook.ts"],"sourcesContent":["import {\n captureException,\n flushIfServerless,\n getActiveSpan,\n getClient,\n getCurrentScope,\n getRootSpan,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n} from '@sentry/core';\nimport { HTTPError } from 'h3';\nimport type { CapturedErrorContext } from 'nitro/types';\n\n/**\n * Extracts the relevant context information from the error context (HTTPEvent in Nitro Error)\n * and creates a structured context object.\n */\nfunction extractErrorContext(errorContext: CapturedErrorContext | undefined): Record<string, unknown> {\n const ctx: Record<string, unknown> = {};\n\n if (!errorContext) {\n return ctx;\n }\n\n if (errorContext.event) {\n ctx.method = errorContext.event.req.method;\n ctx.path = parseUrl(errorContext.event.req.url).path;\n }\n\n if (Array.isArray(errorContext.tags)) {\n ctx.tags = errorContext.tags;\n }\n\n return ctx;\n}\n\n/**\n * Hook that can be added in a Nitro plugin. It captures an error and sends it to Sentry.\n */\nexport async function captureErrorHook(error: Error, errorContext: CapturedErrorContext): Promise<void> {\n const sentryClient = getClient();\n const sentryClientOptions = sentryClient?.getOptions();\n\n if (\n sentryClientOptions &&\n 'enableNitroErrorHandler' in sentryClientOptions &&\n sentryClientOptions.enableNitroErrorHandler === false\n ) {\n return;\n }\n\n // Do not report HTTPErrors with 3xx or 4xx status codes\n if (HTTPError.isError(error) && error.status >= 300 && error.status < 500) {\n return;\n }\n\n const method = errorContext.event?.req.method ?? '';\n const path = errorContext.event?.req.url ? parseUrl(errorContext.event.req.url).path : null;\n\n if (path) {\n getCurrentScope().setTransactionName(`${method} ${path}`);\n const activeSpan = getActiveSpan();\n const activeRootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n activeRootSpan?.updateName(`${method} ${path}`);\n activeRootSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n }\n\n const structuredContext = extractErrorContext(errorContext);\n\n captureException(error, {\n captureContext: { contexts: { nitro: structuredContext } },\n mechanism: { handled: false, type: 'auto.function.nitro.captureErrorHook' },\n });\n\n await flushIfServerless();\n}\n"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"captureErrorHook.js","sources":["../../../../src/runtime/hooks/captureErrorHook.ts"],"sourcesContent":["import {\n captureException,\n flushIfServerless,\n getActiveSpan,\n getClient,\n getCurrentScope,\n getRootSpan,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n} from '@sentry/core';\nimport { HTTPError } from 'h3';\nimport type { CapturedErrorContext } from 'nitro/types';\n\n/**\n * Extracts the relevant context information from the error context (HTTPEvent in Nitro Error)\n * and creates a structured context object.\n */\nfunction extractErrorContext(errorContext: CapturedErrorContext | undefined): Record<string, unknown> {\n const ctx: Record<string, unknown> = {};\n\n if (!errorContext) {\n return ctx;\n }\n\n if (errorContext.event) {\n ctx.method = errorContext.event.req.method;\n ctx.path = parseUrl(errorContext.event.req.url).path;\n }\n\n if (Array.isArray(errorContext.tags)) {\n ctx.tags = errorContext.tags;\n }\n\n return ctx;\n}\n\n/**\n * Hook that can be added in a Nitro plugin. It captures an error and sends it to Sentry.\n */\nexport async function captureErrorHook(error: Error, errorContext: CapturedErrorContext): Promise<void> {\n const sentryClient = getClient();\n const sentryClientOptions = sentryClient?.getOptions();\n\n if (\n sentryClientOptions &&\n 'enableNitroErrorHandler' in sentryClientOptions &&\n sentryClientOptions.enableNitroErrorHandler === false\n ) {\n return;\n }\n\n // Do not report HTTPErrors with 3xx or 4xx status codes\n if (HTTPError.isError(error) && error.status >= 300 && error.status < 500) {\n return;\n }\n\n const method = errorContext.event?.req.method ?? '';\n const path = errorContext.event?.req.url ? parseUrl(errorContext.event.req.url).path : null;\n\n if (path) {\n getCurrentScope().setTransactionName(`${method} ${path}`);\n const activeSpan = getActiveSpan();\n const activeRootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n activeRootSpan?.updateName(`${method} ${path}`);\n activeRootSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n }\n\n const structuredContext = extractErrorContext(errorContext);\n\n captureException(error, {\n captureContext: { contexts: { nitro: structuredContext } },\n mechanism: { handled: false, type: 'auto.function.nitro.captureErrorHook' },\n });\n\n await flushIfServerless();\n}\n"],"names":[],"mappings":";;;AAiBA,SAAS,oBAAoB,YAAA,EAAyE;AACpG,EAAA,MAAM,MAA+B,EAAC;AAEtC,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,IAAI,aAAa,KAAA,EAAO;AACtB,IAAA,GAAA,CAAI,MAAA,GAAS,YAAA,CAAa,KAAA,CAAM,GAAA,CAAI,MAAA;AACpC,IAAA,GAAA,CAAI,OAAO,QAAA,CAAS,YAAA,CAAa,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,CAAE,IAAA;AAAA,EAClD;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,YAAA,CAAa,IAAI,CAAA,EAAG;AACpC,IAAA,GAAA,CAAI,OAAO,YAAA,CAAa,IAAA;AAAA,EAC1B;AAEA,EAAA,OAAO,GAAA;AACT;AAKA,eAAsB,gBAAA,CAAiB,OAAc,YAAA,EAAmD;AACtG,EAAA,MAAM,eAAe,SAAA,EAAU;AAC/B,EAAA,MAAM,mBAAA,GAAsB,cAAc,UAAA,EAAW;AAErD,EAAA,IACE,mBAAA,IACA,yBAAA,IAA6B,mBAAA,IAC7B,mBAAA,CAAoB,4BAA4B,KAAA,EAChD;AACA,IAAA;AAAA,EACF;AAGA,EAAA,IAAI,SAAA,CAAU,QAAQ,KAAK,CAAA,IAAK,MAAM,MAAA,IAAU,GAAA,IAAO,KAAA,CAAM,MAAA,GAAS,GAAA,EAAK;AACzE,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,KAAA,EAAO,GAAA,CAAI,MAAA,IAAU,EAAA;AACjD,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,KAAA,EAAO,GAAA,CAAI,GAAA,GAAM,QAAA,CAAS,YAAA,CAAa,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,CAAE,IAAA,GAAO,IAAA;AAEvF,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,eAAA,GAAkB,kBAAA,CAAmB,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA;AACxD,IAAA,MAAM,aAAa,aAAA,EAAc;AACjC,IAAA,MAAM,cAAA,GAAiB,UAAA,GAAa,WAAA,CAAY,UAAU,CAAA,GAAI,MAAA;AAC9D,IAAA,cAAA,EAAgB,UAAA,CAAW,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA;AAC9C,IAAA,cAAA,EAAgB,YAAA,CAAa,kCAAkC,OAAO,CAAA;AAAA,EACxE;AAEA,EAAA,MAAM,iBAAA,GAAoB,oBAAoB,YAAY,CAAA;AAE1D,EAAA,gBAAA,CAAiB,KAAA,EAAO;AAAA,IACtB,gBAAgB,EAAE,QAAA,EAAU,EAAE,KAAA,EAAO,mBAAkB,EAAE;AAAA,IACzD,SAAA,EAAW,EAAE,OAAA,EAAS,KAAA,EAAO,MAAM,sCAAA;AAAuC,GAC3E,CAAA;AAED,EAAA,MAAM,iBAAA,EAAkB;AAC1B;;;;"}
|
|
@@ -1,146 +1,111 @@
|
|
|
1
1
|
import { GLOBAL_OBJ, startSpanManual, SEMANTIC_ATTRIBUTE_CACHE_KEY, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_OP, captureException, SPAN_STATUS_ERROR, flushIfServerless, SEMANTIC_ATTRIBUTE_CACHE_HIT, SPAN_STATUS_OK } from '@sentry/core';
|
|
2
2
|
import { tracingChannel } from '@sentry/opentelemetry/tracing-channel';
|
|
3
3
|
|
|
4
|
-
const ORIGIN =
|
|
5
|
-
|
|
6
|
-
const globalWithStorageChannels = GLOBAL_OBJ
|
|
7
|
-
|
|
8
|
-
;
|
|
9
|
-
|
|
4
|
+
const ORIGIN = "auto.cache.nitro";
|
|
5
|
+
const globalWithStorageChannels = GLOBAL_OBJ;
|
|
10
6
|
const TRACED_OPERATIONS = [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
]
|
|
22
|
-
|
|
23
|
-
const CACHE_HIT_OPERATIONS = new Set(['hasItem', 'getItem', 'getItemRaw']);
|
|
24
|
-
|
|
7
|
+
"hasItem",
|
|
8
|
+
"getItem",
|
|
9
|
+
"getItemRaw",
|
|
10
|
+
"getItems",
|
|
11
|
+
"setItem",
|
|
12
|
+
"setItemRaw",
|
|
13
|
+
"setItems",
|
|
14
|
+
"removeItem",
|
|
15
|
+
"getKeys",
|
|
16
|
+
"clear"
|
|
17
|
+
];
|
|
18
|
+
const CACHE_HIT_OPERATIONS = /* @__PURE__ */ new Set(["hasItem", "getItem", "getItemRaw"]);
|
|
25
19
|
const CACHED_FN_HANDLERS_RE = /^nitro:(functions|handlers):/i;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Subscribes to unstorage tracing channels and creates Sentry spans for storage operations.
|
|
29
|
-
*/
|
|
30
20
|
function captureStorageEvents() {
|
|
31
21
|
if (globalWithStorageChannels.__SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__) {
|
|
32
22
|
return;
|
|
33
23
|
}
|
|
34
|
-
|
|
35
24
|
for (const operation of TRACED_OPERATIONS) {
|
|
36
25
|
setupStorageTracingChannel(operation);
|
|
37
26
|
}
|
|
38
|
-
|
|
39
27
|
globalWithStorageChannels.__SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__ = true;
|
|
40
28
|
}
|
|
41
|
-
|
|
42
29
|
function setupStorageTracingChannel(operation) {
|
|
43
30
|
const keys = (data) => data.keys ?? [];
|
|
44
|
-
const mountBase = (data) => (data.base ??
|
|
45
|
-
|
|
46
|
-
const channel = tracingChannel(`unstorage.${operation}`, data => {
|
|
31
|
+
const mountBase = (data) => (data.base ?? "").replace(/:$/, "");
|
|
32
|
+
const channel = tracingChannel(`unstorage.${operation}`, (data) => {
|
|
47
33
|
const cacheKeys = keys(data);
|
|
48
|
-
|
|
49
34
|
return startSpanManual(
|
|
50
35
|
{
|
|
51
|
-
name: cacheKeys.join(
|
|
36
|
+
name: cacheKeys.join(", ") || operation,
|
|
52
37
|
attributes: {
|
|
53
38
|
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: `cache.${normalizeMethodName(operation)}`,
|
|
54
39
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
|
|
55
40
|
[SEMANTIC_ATTRIBUTE_CACHE_KEY]: cacheKeys.length > 1 ? cacheKeys : cacheKeys[0],
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
41
|
+
"db.operation.name": operation,
|
|
42
|
+
"db.collection.name": mountBase(data),
|
|
43
|
+
"db.system.name": data.driver?.name ?? "unknown"
|
|
44
|
+
}
|
|
60
45
|
},
|
|
61
|
-
span => span
|
|
46
|
+
(span) => span
|
|
62
47
|
);
|
|
63
48
|
});
|
|
64
|
-
|
|
65
49
|
channel.subscribe({
|
|
66
50
|
asyncEnd(data) {
|
|
67
51
|
if (data._sentrySpan && CACHE_HIT_OPERATIONS.has(operation)) {
|
|
68
|
-
const hit = operation ===
|
|
52
|
+
const hit = operation === "hasItem" ? Boolean(data.result) : isCacheHit(data.keys?.[0], data.result);
|
|
69
53
|
data._sentrySpan.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_HIT, hit);
|
|
70
54
|
}
|
|
71
|
-
|
|
72
55
|
data._sentrySpan?.setStatus({ code: SPAN_STATUS_OK });
|
|
73
56
|
data._sentrySpan?.end();
|
|
74
|
-
|
|
75
57
|
void flushIfServerless();
|
|
76
58
|
},
|
|
77
59
|
error(data) {
|
|
78
60
|
captureException(data.error, {
|
|
79
|
-
mechanism: { handled: false, type: ORIGIN }
|
|
61
|
+
mechanism: { handled: false, type: ORIGIN }
|
|
80
62
|
});
|
|
81
|
-
|
|
82
|
-
data._sentrySpan?.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
|
|
63
|
+
data._sentrySpan?.setStatus({ code: SPAN_STATUS_ERROR, message: "internal_error" });
|
|
83
64
|
data._sentrySpan?.end();
|
|
84
|
-
|
|
85
65
|
void flushIfServerless();
|
|
86
|
-
}
|
|
66
|
+
}
|
|
87
67
|
});
|
|
88
68
|
}
|
|
89
|
-
|
|
90
69
|
function normalizeMethodName(methodName) {
|
|
91
|
-
return methodName.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
|
|
70
|
+
return methodName.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
92
71
|
}
|
|
93
|
-
|
|
94
72
|
function isEmptyValue(value) {
|
|
95
|
-
return value === null || value ===
|
|
73
|
+
return value === null || value === void 0;
|
|
96
74
|
}
|
|
97
|
-
|
|
98
75
|
function isCacheHit(key, value) {
|
|
99
76
|
try {
|
|
100
77
|
const isEmpty = isEmptyValue(value);
|
|
101
|
-
if (isEmpty || typeof key !==
|
|
78
|
+
if (isEmpty || typeof key !== "string" || !CACHED_FN_HANDLERS_RE.test(key)) {
|
|
102
79
|
return !isEmpty;
|
|
103
80
|
}
|
|
104
|
-
|
|
105
|
-
const entry = typeof value === 'string' ? (JSON.parse(value) ) : (value );
|
|
106
|
-
|
|
81
|
+
const entry = typeof value === "string" ? JSON.parse(value) : value;
|
|
107
82
|
return validateCacheEntry(key, entry);
|
|
108
83
|
} catch {
|
|
109
84
|
return false;
|
|
110
85
|
}
|
|
111
86
|
}
|
|
112
|
-
|
|
113
|
-
function validateCacheEntry(
|
|
114
|
-
key,
|
|
115
|
-
entry,
|
|
116
|
-
) {
|
|
87
|
+
function validateCacheEntry(key, entry) {
|
|
117
88
|
if (isEmptyValue(entry.value)) {
|
|
118
89
|
return false;
|
|
119
90
|
}
|
|
120
|
-
|
|
121
91
|
if (Date.now() > (entry.expires || 0)) {
|
|
122
92
|
return false;
|
|
123
93
|
}
|
|
124
|
-
|
|
125
94
|
if (isResponseCacheEntry(key)) {
|
|
126
95
|
if ((entry.value.status ?? 0) >= 400) {
|
|
127
96
|
return false;
|
|
128
97
|
}
|
|
129
|
-
|
|
130
|
-
if (entry.value.body === undefined) {
|
|
98
|
+
if (entry.value.body === void 0) {
|
|
131
99
|
return false;
|
|
132
100
|
}
|
|
133
|
-
|
|
134
|
-
if (entry.value.headers?.etag === 'undefined' || entry.value.headers?.['last-modified'] === 'undefined') {
|
|
101
|
+
if (entry.value.headers?.etag === "undefined" || entry.value.headers?.["last-modified"] === "undefined") {
|
|
135
102
|
return false;
|
|
136
103
|
}
|
|
137
104
|
}
|
|
138
|
-
|
|
139
105
|
return true;
|
|
140
106
|
}
|
|
141
|
-
|
|
142
107
|
function isResponseCacheEntry(key, _) {
|
|
143
|
-
return key.startsWith(
|
|
108
|
+
return key.startsWith("nitro:handlers:");
|
|
144
109
|
}
|
|
145
110
|
|
|
146
111
|
export { captureStorageEvents };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"captureStorageEvents.js","sources":["../../../../src/runtime/hooks/captureStorageEvents.ts"],"sourcesContent":["import {\n captureException,\n flushIfServerless,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_CACHE_HIT,\n SEMANTIC_ATTRIBUTE_CACHE_KEY,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n SPAN_STATUS_OK,\n startSpanManual,\n} from '@sentry/core';\nimport { tracingChannel, type TracingChannelContextWithSpan } from '@sentry/opentelemetry/tracing-channel';\nimport type { TraceContext } from 'unstorage/tracing';\n\nconst ORIGIN = 'auto.cache.nitro';\n\nconst globalWithStorageChannels = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__: boolean;\n};\n\nconst TRACED_OPERATIONS = [\n 'hasItem',\n 'getItem',\n 'getItemRaw',\n 'getItems',\n 'setItem',\n 'setItemRaw',\n 'setItems',\n 'removeItem',\n 'getKeys',\n 'clear',\n] as const;\n\ntype TracedOperation = (typeof TRACED_OPERATIONS)[number];\n\nconst CACHE_HIT_OPERATIONS = new Set<TracedOperation>(['hasItem', 'getItem', 'getItemRaw']);\n\nconst CACHED_FN_HANDLERS_RE = /^nitro:(functions|handlers):/i;\n\n/**\n * Subscribes to unstorage tracing channels and creates Sentry spans for storage operations.\n */\nexport function captureStorageEvents(): void {\n if (globalWithStorageChannels.__SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__) {\n return;\n }\n\n for (const operation of TRACED_OPERATIONS) {\n setupStorageTracingChannel(operation);\n }\n\n globalWithStorageChannels.__SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__ = true;\n}\n\nfunction setupStorageTracingChannel(operation: TracedOperation): void {\n const keys = (data: TraceContext): string[] => data.keys ?? [];\n const mountBase = (data: TraceContext): string => (data.base ?? '').replace(/:$/, '');\n\n const channel = tracingChannel<TraceContext>(`unstorage.${operation}`, data => {\n const cacheKeys = keys(data);\n\n return startSpanManual(\n {\n name: cacheKeys.join(', ') || operation,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `cache.${normalizeMethodName(operation)}`,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_CACHE_KEY]: cacheKeys.length > 1 ? cacheKeys : cacheKeys[0],\n 'db.operation.name': operation,\n 'db.collection.name': mountBase(data),\n 'db.system.name': data.driver?.name ?? 'unknown',\n },\n },\n span => span,\n );\n });\n\n channel.subscribe({\n asyncEnd(data: TracingChannelContextWithSpan<TraceContext & { result?: unknown }>) {\n if (data._sentrySpan && CACHE_HIT_OPERATIONS.has(operation)) {\n const hit = operation === 'hasItem' ? Boolean(data.result) : isCacheHit(data.keys?.[0], data.result);\n data._sentrySpan.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_HIT, hit);\n }\n\n data._sentrySpan?.setStatus({ code: SPAN_STATUS_OK });\n data._sentrySpan?.end();\n\n void flushIfServerless();\n },\n error(data: TracingChannelContextWithSpan<TraceContext & { error?: unknown }>) {\n captureException(data.error, {\n mechanism: { handled: false, type: ORIGIN },\n });\n\n data._sentrySpan?.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n data._sentrySpan?.end();\n\n void flushIfServerless();\n },\n });\n}\n\nfunction normalizeMethodName(methodName: string): string {\n return methodName.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n}\n\nfunction isEmptyValue(value: unknown): value is null | undefined {\n return value === null || value === undefined;\n}\n\ninterface CacheEntry<T = unknown> {\n value?: T;\n expires?: number;\n}\n\ninterface ResponseCacheEntry {\n status?: number;\n body?: unknown;\n headers?: Record<string, string | undefined>;\n}\n\nfunction isCacheHit(key: unknown, value: unknown): boolean {\n try {\n const isEmpty = isEmptyValue(value);\n if (isEmpty || typeof key !== 'string' || !CACHED_FN_HANDLERS_RE.test(key)) {\n return !isEmpty;\n }\n\n const entry = typeof value === 'string' ? (JSON.parse(value) as CacheEntry) : (value as CacheEntry);\n\n return validateCacheEntry(key, entry);\n } catch {\n return false;\n }\n}\n\nfunction validateCacheEntry(\n key: string,\n entry: CacheEntry | CacheEntry<ResponseCacheEntry & { status: number }>,\n): boolean {\n if (isEmptyValue(entry.value)) {\n return false;\n }\n\n if (Date.now() > (entry.expires || 0)) {\n return false;\n }\n\n if (isResponseCacheEntry(key, entry)) {\n if ((entry.value.status ?? 0) >= 400) {\n return false;\n }\n\n if (entry.value.body === undefined) {\n return false;\n }\n\n if (entry.value.headers?.etag === 'undefined' || entry.value.headers?.['last-modified'] === 'undefined') {\n return false;\n }\n }\n\n return true;\n}\n\nfunction isResponseCacheEntry(key: string, _: CacheEntry): _ is CacheEntry<ResponseCacheEntry & { status: number }> {\n return key.startsWith('nitro:handlers:');\n}\n"],"names":[],"mappings":";;;AAeA,MAAM,MAAA,GAAS,
|
|
1
|
+
{"version":3,"file":"captureStorageEvents.js","sources":["../../../../src/runtime/hooks/captureStorageEvents.ts"],"sourcesContent":["import {\n captureException,\n flushIfServerless,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_CACHE_HIT,\n SEMANTIC_ATTRIBUTE_CACHE_KEY,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n SPAN_STATUS_OK,\n startSpanManual,\n} from '@sentry/core';\nimport { tracingChannel, type TracingChannelContextWithSpan } from '@sentry/opentelemetry/tracing-channel';\nimport type { TraceContext } from 'unstorage/tracing';\n\nconst ORIGIN = 'auto.cache.nitro';\n\nconst globalWithStorageChannels = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__: boolean;\n};\n\nconst TRACED_OPERATIONS = [\n 'hasItem',\n 'getItem',\n 'getItemRaw',\n 'getItems',\n 'setItem',\n 'setItemRaw',\n 'setItems',\n 'removeItem',\n 'getKeys',\n 'clear',\n] as const;\n\ntype TracedOperation = (typeof TRACED_OPERATIONS)[number];\n\nconst CACHE_HIT_OPERATIONS = new Set<TracedOperation>(['hasItem', 'getItem', 'getItemRaw']);\n\nconst CACHED_FN_HANDLERS_RE = /^nitro:(functions|handlers):/i;\n\n/**\n * Subscribes to unstorage tracing channels and creates Sentry spans for storage operations.\n */\nexport function captureStorageEvents(): void {\n if (globalWithStorageChannels.__SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__) {\n return;\n }\n\n for (const operation of TRACED_OPERATIONS) {\n setupStorageTracingChannel(operation);\n }\n\n globalWithStorageChannels.__SENTRY_NITRO_STORAGE_CHANNELS_INSTRUMENTED__ = true;\n}\n\nfunction setupStorageTracingChannel(operation: TracedOperation): void {\n const keys = (data: TraceContext): string[] => data.keys ?? [];\n const mountBase = (data: TraceContext): string => (data.base ?? '').replace(/:$/, '');\n\n const channel = tracingChannel<TraceContext>(`unstorage.${operation}`, data => {\n const cacheKeys = keys(data);\n\n return startSpanManual(\n {\n name: cacheKeys.join(', ') || operation,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `cache.${normalizeMethodName(operation)}`,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_CACHE_KEY]: cacheKeys.length > 1 ? cacheKeys : cacheKeys[0],\n 'db.operation.name': operation,\n 'db.collection.name': mountBase(data),\n 'db.system.name': data.driver?.name ?? 'unknown',\n },\n },\n span => span,\n );\n });\n\n channel.subscribe({\n asyncEnd(data: TracingChannelContextWithSpan<TraceContext & { result?: unknown }>) {\n if (data._sentrySpan && CACHE_HIT_OPERATIONS.has(operation)) {\n const hit = operation === 'hasItem' ? Boolean(data.result) : isCacheHit(data.keys?.[0], data.result);\n data._sentrySpan.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_HIT, hit);\n }\n\n data._sentrySpan?.setStatus({ code: SPAN_STATUS_OK });\n data._sentrySpan?.end();\n\n void flushIfServerless();\n },\n error(data: TracingChannelContextWithSpan<TraceContext & { error?: unknown }>) {\n captureException(data.error, {\n mechanism: { handled: false, type: ORIGIN },\n });\n\n data._sentrySpan?.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n data._sentrySpan?.end();\n\n void flushIfServerless();\n },\n });\n}\n\nfunction normalizeMethodName(methodName: string): string {\n return methodName.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n}\n\nfunction isEmptyValue(value: unknown): value is null | undefined {\n return value === null || value === undefined;\n}\n\ninterface CacheEntry<T = unknown> {\n value?: T;\n expires?: number;\n}\n\ninterface ResponseCacheEntry {\n status?: number;\n body?: unknown;\n headers?: Record<string, string | undefined>;\n}\n\nfunction isCacheHit(key: unknown, value: unknown): boolean {\n try {\n const isEmpty = isEmptyValue(value);\n if (isEmpty || typeof key !== 'string' || !CACHED_FN_HANDLERS_RE.test(key)) {\n return !isEmpty;\n }\n\n const entry = typeof value === 'string' ? (JSON.parse(value) as CacheEntry) : (value as CacheEntry);\n\n return validateCacheEntry(key, entry);\n } catch {\n return false;\n }\n}\n\nfunction validateCacheEntry(\n key: string,\n entry: CacheEntry | CacheEntry<ResponseCacheEntry & { status: number }>,\n): boolean {\n if (isEmptyValue(entry.value)) {\n return false;\n }\n\n if (Date.now() > (entry.expires || 0)) {\n return false;\n }\n\n if (isResponseCacheEntry(key, entry)) {\n if ((entry.value.status ?? 0) >= 400) {\n return false;\n }\n\n if (entry.value.body === undefined) {\n return false;\n }\n\n if (entry.value.headers?.etag === 'undefined' || entry.value.headers?.['last-modified'] === 'undefined') {\n return false;\n }\n }\n\n return true;\n}\n\nfunction isResponseCacheEntry(key: string, _: CacheEntry): _ is CacheEntry<ResponseCacheEntry & { status: number }> {\n return key.startsWith('nitro:handlers:');\n}\n"],"names":[],"mappings":";;;AAeA,MAAM,MAAA,GAAS,kBAAA;AAEf,MAAM,yBAAA,GAA4B,UAAA;AAIlC,MAAM,iBAAA,GAAoB;AAAA,EACxB,SAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAIA,MAAM,uCAAuB,IAAI,GAAA,CAAqB,CAAC,SAAA,EAAW,SAAA,EAAW,YAAY,CAAC,CAAA;AAE1F,MAAM,qBAAA,GAAwB,+BAAA;AAKvB,SAAS,oBAAA,GAA6B;AAC3C,EAAA,IAAI,0BAA0B,8CAAA,EAAgD;AAC5E,IAAA;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,aAAa,iBAAA,EAAmB;AACzC,IAAA,0BAAA,CAA2B,SAAS,CAAA;AAAA,EACtC;AAEA,EAAA,yBAAA,CAA0B,8CAAA,GAAiD,IAAA;AAC7E;AAEA,SAAS,2BAA2B,SAAA,EAAkC;AACpE,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,KAAiC,IAAA,CAAK,QAAQ,EAAC;AAC7D,EAAA,MAAM,SAAA,GAAY,CAAC,IAAA,KAAA,CAAgC,IAAA,CAAK,QAAQ,EAAA,EAAI,OAAA,CAAQ,MAAM,EAAE,CAAA;AAEpF,EAAA,MAAM,OAAA,GAAU,cAAA,CAA6B,CAAA,UAAA,EAAa,SAAS,IAAI,CAAA,IAAA,KAAQ;AAC7E,IAAA,MAAM,SAAA,GAAY,KAAK,IAAI,CAAA;AAE3B,IAAA,OAAO,eAAA;AAAA,MACL;AAAA,QACE,IAAA,EAAM,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA,IAAK,SAAA;AAAA,QAC9B,UAAA,EAAY;AAAA,UACV,CAAC,4BAA4B,GAAG,CAAA,MAAA,EAAS,mBAAA,CAAoB,SAAS,CAAC,CAAA,CAAA;AAAA,UACvE,CAAC,gCAAgC,GAAG,MAAA;AAAA,UACpC,CAAC,4BAA4B,GAAG,SAAA,CAAU,SAAS,CAAA,GAAI,SAAA,GAAY,UAAU,CAAC,CAAA;AAAA,UAC9E,mBAAA,EAAqB,SAAA;AAAA,UACrB,oBAAA,EAAsB,UAAU,IAAI,CAAA;AAAA,UACpC,gBAAA,EAAkB,IAAA,CAAK,MAAA,EAAQ,IAAA,IAAQ;AAAA;AACzC,OACF;AAAA,MACA,CAAA,IAAA,KAAQ;AAAA,KACV;AAAA,EACF,CAAC,CAAA;AAED,EAAA,OAAA,CAAQ,SAAA,CAAU;AAAA,IAChB,SAAS,IAAA,EAA0E;AACjF,MAAA,IAAI,IAAA,CAAK,WAAA,IAAe,oBAAA,CAAqB,GAAA,CAAI,SAAS,CAAA,EAAG;AAC3D,QAAA,MAAM,GAAA,GAAM,SAAA,KAAc,SAAA,GAAY,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,GAAI,UAAA,CAAW,IAAA,CAAK,IAAA,GAAO,CAAC,CAAA,EAAG,KAAK,MAAM,CAAA;AACnG,QAAA,IAAA,CAAK,WAAA,CAAY,YAAA,CAAa,4BAAA,EAA8B,GAAG,CAAA;AAAA,MACjE;AAEA,MAAA,IAAA,CAAK,WAAA,EAAa,SAAA,CAAU,EAAE,IAAA,EAAM,gBAAgB,CAAA;AACpD,MAAA,IAAA,CAAK,aAAa,GAAA,EAAI;AAEtB,MAAA,KAAK,iBAAA,EAAkB;AAAA,IACzB,CAAA;AAAA,IACA,MAAM,IAAA,EAAyE;AAC7E,MAAA,gBAAA,CAAiB,KAAK,KAAA,EAAO;AAAA,QAC3B,SAAA,EAAW,EAAE,OAAA,EAAS,KAAA,EAAO,MAAM,MAAA;AAAO,OAC3C,CAAA;AAED,MAAA,IAAA,CAAK,aAAa,SAAA,CAAU,EAAE,MAAM,iBAAA,EAAmB,OAAA,EAAS,kBAAkB,CAAA;AAClF,MAAA,IAAA,CAAK,aAAa,GAAA,EAAI;AAEtB,MAAA,KAAK,iBAAA,EAAkB;AAAA,IACzB;AAAA,GACD,CAAA;AACH;AAEA,SAAS,oBAAoB,UAAA,EAA4B;AACvD,EAAA,OAAO,UAAA,CAAW,QAAQ,QAAA,EAAU,CAAA,MAAA,KAAU,IAAI,MAAA,CAAO,WAAA,EAAa,CAAA,CAAE,CAAA;AAC1E;AAEA,SAAS,aAAa,KAAA,EAA2C;AAC/D,EAAA,OAAO,KAAA,KAAU,QAAQ,KAAA,KAAU,MAAA;AACrC;AAaA,SAAS,UAAA,CAAW,KAAc,KAAA,EAAyB;AACzD,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,aAAa,KAAK,CAAA;AAClC,IAAA,IAAI,OAAA,IAAW,OAAO,GAAA,KAAQ,QAAA,IAAY,CAAC,qBAAA,CAAsB,IAAA,CAAK,GAAG,CAAA,EAAG;AAC1E,MAAA,OAAO,CAAC,OAAA;AAAA,IACV;AAEA,IAAA,MAAM,QAAQ,OAAO,KAAA,KAAU,WAAY,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,GAAoB,KAAA;AAE/E,IAAA,OAAO,kBAAA,CAAmB,KAAK,KAAK,CAAA;AAAA,EACtC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAAS,kBAAA,CACP,KACA,KAAA,EACS;AACT,EAAA,IAAI,YAAA,CAAa,KAAA,CAAM,KAAK,CAAA,EAAG;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,IAAA,CAAK,GAAA,EAAI,IAAK,KAAA,CAAM,WAAW,CAAA,CAAA,EAAI;AACrC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,oBAAA,CAAqB,GAAU,CAAA,EAAG;AACpC,IAAA,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,MAAA,IAAU,CAAA,KAAM,GAAA,EAAK;AACpC,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,KAAA,CAAM,KAAA,CAAM,IAAA,KAAS,MAAA,EAAW;AAClC,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,KAAA,CAAM,KAAA,CAAM,OAAA,EAAS,IAAA,KAAS,WAAA,IAAe,MAAM,KAAA,CAAM,OAAA,GAAU,eAAe,CAAA,KAAM,WAAA,EAAa;AACvG,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,oBAAA,CAAqB,KAAa,CAAA,EAAyE;AAClH,EAAA,OAAO,GAAA,CAAI,WAAW,iBAAiB,CAAA;AACzC;;;;"}
|