shield360 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +29 -1
  2. package/dist/__tests__/build-info.test.d.ts +1 -0
  3. package/dist/__tests__/build-info.test.js +189 -0
  4. package/dist/__tests__/build-info.test.js.map +1 -0
  5. package/dist/__tests__/code-location.test.d.ts +1 -0
  6. package/dist/__tests__/code-location.test.js +180 -0
  7. package/dist/__tests__/code-location.test.js.map +1 -0
  8. package/dist/__tests__/destination.test.d.ts +1 -0
  9. package/dist/__tests__/destination.test.js +76 -0
  10. package/dist/__tests__/destination.test.js.map +1 -0
  11. package/dist/__tests__/pricing-claude-5.test.d.ts +1 -0
  12. package/dist/__tests__/pricing-claude-5.test.js +56 -0
  13. package/dist/__tests__/pricing-claude-5.test.js.map +1 -0
  14. package/dist/config.js +1 -1
  15. package/dist/config.js.map +1 -1
  16. package/dist/destination.d.ts +37 -0
  17. package/dist/destination.js +64 -0
  18. package/dist/destination.js.map +1 -0
  19. package/dist/guard/__tests__/findings.test.js +27 -8
  20. package/dist/guard/__tests__/findings.test.js.map +1 -1
  21. package/dist/guard/base.d.ts +2 -0
  22. package/dist/guard/base.js +4 -0
  23. package/dist/guard/base.js.map +1 -1
  24. package/dist/guard/findings.d.ts +12 -2
  25. package/dist/guard/findings.js +19 -49
  26. package/dist/guard/findings.js.map +1 -1
  27. package/dist/guard/integration.d.ts +24 -3
  28. package/dist/guard/integration.js +102 -30
  29. package/dist/guard/integration.js.map +1 -1
  30. package/dist/guard/pipeline.d.ts +10 -1
  31. package/dist/guard/pipeline.js +14 -0
  32. package/dist/guard/pipeline.js.map +1 -1
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.js +47 -17
  35. package/dist/index.js.map +1 -1
  36. package/dist/instrumentation/__tests__/anthropic-api-promise.test.d.ts +1 -0
  37. package/dist/instrumentation/__tests__/anthropic-api-promise.test.js +99 -0
  38. package/dist/instrumentation/__tests__/anthropic-api-promise.test.js.map +1 -0
  39. package/dist/instrumentation/__tests__/anthropic-instrumentation.test.d.ts +1 -0
  40. package/dist/instrumentation/__tests__/anthropic-instrumentation.test.js +86 -0
  41. package/dist/instrumentation/__tests__/anthropic-instrumentation.test.js.map +1 -0
  42. package/dist/instrumentation/anthropic/index.d.ts +6 -0
  43. package/dist/instrumentation/anthropic/index.js +41 -4
  44. package/dist/instrumentation/anthropic/index.js.map +1 -1
  45. package/dist/instrumentation/anthropic/wrapper.d.ts +9 -1
  46. package/dist/instrumentation/anthropic/wrapper.js +51 -20
  47. package/dist/instrumentation/anthropic/wrapper.js.map +1 -1
  48. package/dist/instrumentation/mcp/wrapper.js +7 -1
  49. package/dist/instrumentation/mcp/wrapper.js.map +1 -1
  50. package/dist/otel/build-info.d.ts +22 -0
  51. package/dist/otel/build-info.js +175 -0
  52. package/dist/otel/build-info.js.map +1 -0
  53. package/dist/otel/code-location.d.ts +49 -0
  54. package/dist/otel/code-location.js +233 -0
  55. package/dist/otel/code-location.js.map +1 -0
  56. package/dist/otel/tracing.js +7 -0
  57. package/dist/otel/tracing.js.map +1 -1
  58. package/dist/pricing.json +130 -36
  59. package/dist/protect/__tests__/protect.test.d.ts +1 -0
  60. package/dist/protect/__tests__/protect.test.js +206 -0
  61. package/dist/protect/__tests__/protect.test.js.map +1 -0
  62. package/dist/protect/index.d.ts +103 -0
  63. package/dist/protect/index.js +191 -0
  64. package/dist/protect/index.js.map +1 -0
  65. package/dist/protect/mcp.d.ts +13 -0
  66. package/dist/protect/mcp.js +49 -0
  67. package/dist/protect/mcp.js.map +1 -0
  68. package/dist/protect/mode.d.ts +89 -0
  69. package/dist/protect/mode.js +134 -0
  70. package/dist/protect/mode.js.map +1 -0
  71. package/dist/types.d.ts +22 -0
  72. package/package.json +1 -1
package/README.md CHANGED
@@ -195,11 +195,39 @@ Below is a detailed overview of the configuration options available, allowing yo
195
195
  | `otlpEndpoint` | Specifies the OTLP endpoint for transmitting telemetry data. | `undefined` | No |
196
196
  | `otlpHeaders` | Defines headers for the OTLP exporter, useful for backends requiring authentication. | `undefined` | No |
197
197
  | `disableBatch` | A flag to disable batch span processing, favoring immediate dispatch. | `true` | No |
198
- | `traceContent` | Enables tracing of content for deeper insights. | `true` | No |
198
+ | `captureMessageContent` | Records prompt and completion text. Off unless set here or with `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true`. | `false` | No |
199
199
  | `disabledInstrumentations` | List of instrumentations to disable. | `undefined` | No |
200
200
  | `instrumentations` | Object of instrumentation modules for manual patching | `undefined` | No |
201
201
  | `pricingJson` | URL or file path of the pricing JSON file. | Bundled `pricing.json` | No |
202
202
  | `collectGpuStats` | Flag to enable or disable GPU metrics collection (NVIDIA via `nvidia-smi`, AMD via `rocm-smi`). | `false` | No |
203
+ | `captureCodeLocation` | Adds the calling function, file and line to GenAI spans. Also `SHIELD360_CAPTURE_CODE_LOCATION=false`. | `true` | No |
204
+ | `codeRoot` | Directory stripped from reported file paths. Also `SHIELD360_CODE_ROOT`. | git root, then working directory | No |
205
+ | `serviceVersion` | Release recorded as the `service.version` resource attribute. Also `SHIELD360_SERVICE_VERSION`. | `undefined` | No |
206
+
207
+ > **Message content is off by default.** Prompt and completion text is recorded only when you pass `captureMessageContent: true` (or set `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true`). Even then, Shield360 stores it only if your organisation's [Data retention](https://shield360.ai) setting allows it. Before this release the default was on.
208
+
209
+ ### Code location and build attributes
210
+
211
+ Every GenAI span (one with `gen_ai.operation.name`) records where your code made the call:
212
+
213
+ | Attribute | Value |
214
+ | --- | --- |
215
+ | `code.function.name` | Calling function, such as `BillingService.summarise`. Left out for anonymous functions. |
216
+ | `code.file.path` | File path relative to `codeRoot`, the git root or the working directory. No home directory (yours or another user's) or CI workspace prefix is sent. |
217
+ | `code.line.number` | Line of the call. |
218
+
219
+ Frames inside Shield360, OpenTelemetry, `node_modules` and Node internals are skipped. Only names, paths and line numbers are recorded, never argument values or source text. Turn it off with `captureCodeLocation: false` or `SHIELD360_CAPTURE_CODE_LOCATION=false` (`0`, `no` and `off` also work); the init option wins over the environment variable.
220
+
221
+ At startup Shield360 also adds these resource attributes, so costs and traces can be tied to a release:
222
+
223
+ | Attribute | Sources, first match wins |
224
+ | --- | --- |
225
+ | `service.version` | `serviceVersion`, `SHIELD360_SERVICE_VERSION`, `OTEL_SERVICE_VERSION`, `OTEL_RESOURCE_ATTRIBUTES` |
226
+ | `vcs.ref.head.revision` | `SHIELD360_GIT_COMMIT`, `OTEL_RESOURCE_ATTRIBUTES`, CI variables |
227
+ | `vcs.repository.url.full` | `SHIELD360_GIT_REPOSITORY_URL`, `OTEL_RESOURCE_ATTRIBUTES`, CI variables |
228
+ | `vcs.ref.head.name` | `SHIELD360_GIT_BRANCH`, `OTEL_RESOURCE_ATTRIBUTES`, CI variables |
229
+
230
+ CI variables are read from GitHub Actions, GitLab CI, Vercel, Netlify, Render, Railway, Heroku, AWS CodeBuild, Buildkite, CircleCI, Bitbucket Pipelines, Azure Pipelines and Jenkins. An explicit `OTEL_RESOURCE_ATTRIBUTES` value beats CI auto-detection. Values from different providers are never mixed. Commit SHAs that are not 7 to 64 hex characters are dropped, and repository URLs are reduced to `https://host/owner/repo` with any credentials removed.
203
231
 
204
232
  ### Shield360 Prompt Hub - `Shield360.getPrompt()`
205
233
 
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const build_info_1 = require("../otel/build-info");
4
+ const SHA = 'ABCDEF1234567890abcdef1234567890abcdef12';
5
+ const sha = SHA.toLowerCase();
6
+ describe('resolveBuildAttributes', () => {
7
+ it('returns nothing when nothing is configured', () => {
8
+ expect((0, build_info_1.resolveBuildAttributes)({}, {})).toEqual({});
9
+ });
10
+ it('prefers the init option, then SHIELD360_* env', () => {
11
+ const env = {
12
+ SHIELD360_SERVICE_VERSION: '2.0.0',
13
+ SHIELD360_GIT_COMMIT: SHA,
14
+ SHIELD360_GIT_REPOSITORY_URL: 'git@github.com:acme/api.git',
15
+ SHIELD360_GIT_BRANCH: 'release',
16
+ GITHUB_SHA: '1111111111111111111111111111111111111111',
17
+ GITHUB_REPOSITORY: 'other/repo',
18
+ GITHUB_REF_NAME: 'main',
19
+ OTEL_SERVICE_VERSION: '9.9.9',
20
+ };
21
+ expect((0, build_info_1.resolveBuildAttributes)({ serviceVersion: '3.1.0' }, env)).toEqual({
22
+ [build_info_1.ATTR_SERVICE_VERSION]: '3.1.0',
23
+ [build_info_1.ATTR_VCS_REVISION]: sha,
24
+ [build_info_1.ATTR_VCS_REPOSITORY_URL]: 'https://github.com/acme/api',
25
+ [build_info_1.ATTR_VCS_REF_NAME]: 'release',
26
+ });
27
+ expect((0, build_info_1.resolveBuildAttributes)({}, env)[build_info_1.ATTR_SERVICE_VERSION]).toBe('2.0.0');
28
+ });
29
+ it('reads CI provider env and never takes service.version from CI', () => {
30
+ expect((0, build_info_1.resolveBuildAttributes)({}, {
31
+ GITHUB_SHA: SHA,
32
+ GITHUB_REPOSITORY: 'acme/api',
33
+ GITHUB_HEAD_REF: 'feature/x',
34
+ GITHUB_REF_NAME: '12/merge',
35
+ })).toEqual({
36
+ [build_info_1.ATTR_VCS_REVISION]: sha,
37
+ [build_info_1.ATTR_VCS_REPOSITORY_URL]: 'https://github.com/acme/api',
38
+ [build_info_1.ATTR_VCS_REF_NAME]: 'feature/x',
39
+ });
40
+ });
41
+ it('never mixes providers', () => {
42
+ const attrs = (0, build_info_1.resolveBuildAttributes)({}, {
43
+ RENDER_GIT_COMMIT: SHA,
44
+ RENDER_GIT_BRANCH: 'main',
45
+ // Lower-priority provider with a repo URL must not leak in.
46
+ GIT_COMMIT: '2222222',
47
+ GIT_URL: 'https://github.com/acme/jenkins',
48
+ GIT_BRANCH: 'origin/dev',
49
+ // Higher-priority provider without a revision is skipped entirely.
50
+ CI_PROJECT_URL: 'https://gitlab.com/acme/gitlab',
51
+ });
52
+ expect(attrs).toEqual({ [build_info_1.ATTR_VCS_REVISION]: sha, [build_info_1.ATTR_VCS_REF_NAME]: 'main' });
53
+ });
54
+ it.each([
55
+ [
56
+ 'Vercel',
57
+ {
58
+ VERCEL_GIT_COMMIT_SHA: SHA,
59
+ VERCEL_GIT_PROVIDER: 'gitlab',
60
+ VERCEL_GIT_REPO_OWNER: 'acme',
61
+ VERCEL_GIT_REPO_SLUG: 'api',
62
+ VERCEL_GIT_COMMIT_REF: 'main',
63
+ },
64
+ 'https://gitlab.com/acme/api',
65
+ 'main',
66
+ ],
67
+ [
68
+ 'CodeBuild',
69
+ {
70
+ CODEBUILD_RESOLVED_SOURCE_VERSION: SHA,
71
+ CODEBUILD_SOURCE_REPO_URL: 'https://github.com/acme/api.git',
72
+ CODEBUILD_WEBHOOK_HEAD_REF: 'refs/heads/main',
73
+ },
74
+ 'https://github.com/acme/api',
75
+ 'main',
76
+ ],
77
+ [
78
+ 'Jenkins',
79
+ { GIT_COMMIT: SHA, GIT_URL: 'ssh://git@github.com:22/acme/api.git', GIT_BRANCH: 'origin/dev' },
80
+ 'https://github.com/acme/api',
81
+ 'dev',
82
+ ],
83
+ ])('maps %s variables', (_name, env, repo, ref) => {
84
+ const attrs = (0, build_info_1.resolveBuildAttributes)({}, env);
85
+ expect(attrs[build_info_1.ATTR_VCS_REVISION]).toBe(sha);
86
+ expect(attrs[build_info_1.ATTR_VCS_REPOSITORY_URL]).toBe(repo);
87
+ expect(attrs[build_info_1.ATTR_VCS_REF_NAME]).toBe(ref);
88
+ });
89
+ it('uses Heroku SOURCE_VERSION when HEROKU_SLUG_COMMIT is unset', () => {
90
+ expect((0, build_info_1.resolveBuildAttributes)({}, { SOURCE_VERSION: SHA })).toEqual({
91
+ [build_info_1.ATTR_VCS_REVISION]: sha,
92
+ });
93
+ });
94
+ it('lets explicit OTel env beat CI auto-detection, per attribute', () => {
95
+ const env = {
96
+ GITHUB_SHA: '1111111111111111111111111111111111111111',
97
+ GITHUB_REPOSITORY: 'acme/ci',
98
+ GITHUB_REF_NAME: 'ci-branch',
99
+ OTEL_RESOURCE_ATTRIBUTES: `vcs.ref.head.revision=${SHA},vcs.ref.head.name=otel-branch`,
100
+ };
101
+ expect((0, build_info_1.resolveBuildAttributes)({}, env)).toEqual({
102
+ [build_info_1.ATTR_VCS_REVISION]: sha,
103
+ [build_info_1.ATTR_VCS_REF_NAME]: 'otel-branch',
104
+ // OTel set no repository, so the CI provider fills it.
105
+ [build_info_1.ATTR_VCS_REPOSITORY_URL]: 'https://github.com/acme/ci',
106
+ });
107
+ // An invalid OTel revision falls through to CI.
108
+ expect((0, build_info_1.resolveBuildAttributes)({}, { GITHUB_SHA: SHA, OTEL_RESOURCE_ATTRIBUTES: 'vcs.ref.head.revision=HEAD' })[build_info_1.ATTR_VCS_REVISION]).toBe(sha);
109
+ });
110
+ it('uses OTel env when nothing explicit is set', () => {
111
+ const env = {
112
+ OTEL_SERVICE_VERSION: '1.2.3',
113
+ OTEL_RESOURCE_ATTRIBUTES: 'service.version=0.0.1,vcs.ref.head.revision=' +
114
+ SHA +
115
+ ',vcs.repository.url.full=https%3A%2F%2Fgithub.com%2Facme%2Fapi,vcs.ref.head.name=feat%2Fa',
116
+ };
117
+ expect((0, build_info_1.resolveBuildAttributes)({}, env)).toEqual({
118
+ [build_info_1.ATTR_SERVICE_VERSION]: '1.2.3',
119
+ [build_info_1.ATTR_VCS_REVISION]: sha,
120
+ [build_info_1.ATTR_VCS_REPOSITORY_URL]: 'https://github.com/acme/api',
121
+ [build_info_1.ATTR_VCS_REF_NAME]: 'feat/a',
122
+ });
123
+ expect((0, build_info_1.resolveBuildAttributes)({ serviceVersion: '5' }, env)[build_info_1.ATTR_SERVICE_VERSION]).toBe('5');
124
+ });
125
+ it('drops an invalid revision and falls through to the next source', () => {
126
+ expect((0, build_info_1.resolveBuildAttributes)({}, { SHIELD360_GIT_COMMIT: 'not-a-sha', CIRCLE_SHA1: SHA })[build_info_1.ATTR_VCS_REVISION]).toBe(sha);
127
+ expect((0, build_info_1.resolveBuildAttributes)({}, { SHIELD360_GIT_COMMIT: 'abc' })).toEqual({});
128
+ });
129
+ });
130
+ describe('sanitisers', () => {
131
+ it.each([
132
+ ['https://x-access-token:ghp_abc@github.com/acme/api.git', 'https://github.com/acme/api'],
133
+ ['git@github.com:acme/api.git', 'https://github.com/acme/api'],
134
+ ['ssh://git@gitlab.example.com:2222/group/sub/repo.git/', 'https://gitlab.example.com/group/sub/repo'],
135
+ ['git://github.com/acme/api', 'https://github.com/acme/api'],
136
+ ['http://git.local:8080/acme/api/?q=1#x', 'http://git.local:8080/acme/api'],
137
+ ['HTTPS://GitHub.com/acme/api/', 'https://github.com/acme/api'],
138
+ ])('normalises repository URL %p', (input, expected) => {
139
+ expect((0, build_info_1.sanitiseRepositoryUrl)(input)).toBe(expected);
140
+ });
141
+ it.each(['/home/bob/repo', 'file:///repo', 'ftp://host/repo', 'not a url', 'https://github.com/', ''])('drops repository URL %p', (input) => {
142
+ expect((0, build_info_1.sanitiseRepositoryUrl)(input)).toBeUndefined();
143
+ });
144
+ it('validates revisions', () => {
145
+ expect((0, build_info_1.sanitiseRevision)(` ${SHA} `)).toBe(sha);
146
+ expect((0, build_info_1.sanitiseRevision)('abc123')).toBeUndefined();
147
+ expect((0, build_info_1.sanitiseRevision)('zzzzzzzz')).toBeUndefined();
148
+ });
149
+ it('cleans text values', () => {
150
+ expect((0, build_info_1.sanitiseText)(' main\u0000\n ')).toBe('main');
151
+ expect((0, build_info_1.sanitiseText)('x'.repeat(300))).toHaveLength(256);
152
+ expect((0, build_info_1.sanitiseText)(' \t ')).toBeUndefined();
153
+ });
154
+ it('parses OTEL_RESOURCE_ATTRIBUTES', () => {
155
+ expect((0, build_info_1.parseOtelResourceAttributes)('a=1, b = x%2Cy ,bad,c=%E0%A4%A')).toEqual({ a: '1', b: 'x,y' });
156
+ });
157
+ });
158
+ describe('Shield360.init resource', () => {
159
+ const savedEnv = process.env;
160
+ afterEach(() => {
161
+ process.env = savedEnv;
162
+ jest.resetModules();
163
+ });
164
+ it('carries the resolved build attributes', () => {
165
+ process.env = {
166
+ ...savedEnv,
167
+ OTEL_TRACES_EXPORTER: 'none',
168
+ SHIELD360_GIT_COMMIT: SHA,
169
+ GITHUB_SHA: '',
170
+ OTEL_RESOURCE_ATTRIBUTES: 'vcs.ref.head.name=main',
171
+ };
172
+ jest.isolateModules(() => {
173
+ const Shield360 = require('../index').default;
174
+ Shield360.init({
175
+ serviceVersion: '4.0.0',
176
+ captureCodeLocation: false,
177
+ disableMetrics: true,
178
+ disableEvents: true,
179
+ });
180
+ expect(Shield360.options.captureCodeLocation).toBe(false);
181
+ expect(Shield360.resource.attributes).toMatchObject({
182
+ [build_info_1.ATTR_SERVICE_VERSION]: '4.0.0',
183
+ [build_info_1.ATTR_VCS_REVISION]: sha,
184
+ [build_info_1.ATTR_VCS_REF_NAME]: 'main',
185
+ });
186
+ });
187
+ });
188
+ });
189
+ //# sourceMappingURL=build-info.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-info.test.js","sourceRoot":"","sources":["../../src/__tests__/build-info.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const path_1 = require("path");
4
+ const fs_1 = require("fs");
5
+ const url_1 = require("url");
6
+ const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
7
+ const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
8
+ const code_location_1 = require("../otel/code-location");
9
+ const GEN_AI = { 'gen_ai.operation.name': 'chat' };
10
+ /** This file as the processor reports it: relative to the repository root, which is the monorepo here and the SDK's own root in its public mirror. */
11
+ function gitRoot(from) {
12
+ let dir = from;
13
+ while (!(0, fs_1.existsSync)((0, path_1.resolve)(dir, '.git'))) {
14
+ const parent = (0, path_1.dirname)(dir);
15
+ if (parent === dir)
16
+ return from;
17
+ dir = parent;
18
+ }
19
+ return dir;
20
+ }
21
+ const THIS_FILE = (0, path_1.relative)(gitRoot(__dirname), __filename).split('\\').join('/');
22
+ /** Line number of the caller's line, read the same way V8 reports it. */
23
+ function callerLine() {
24
+ const frame = new Error().stack.split('\n')[2];
25
+ return Number(/:(\d+):\d+\)?$/.exec(frame)[1]);
26
+ }
27
+ describe('CodeLocationSpanProcessor', () => {
28
+ let exporter;
29
+ let processor;
30
+ let provider;
31
+ beforeEach(() => {
32
+ exporter = new sdk_trace_base_1.InMemorySpanExporter();
33
+ processor = new code_location_1.CodeLocationSpanProcessor();
34
+ provider = new sdk_trace_node_1.NodeTracerProvider({
35
+ spanProcessors: [processor, new sdk_trace_base_1.SimpleSpanProcessor(exporter)],
36
+ });
37
+ });
38
+ afterEach(async () => {
39
+ await provider.shutdown();
40
+ });
41
+ function startChat(attributes = GEN_AI) {
42
+ const [span, line] = [provider.getTracer('test').startSpan('chat', { attributes }), callerLine()];
43
+ span.end();
44
+ return { attrs: exporter.getFinishedSpans()[0].attributes, line };
45
+ }
46
+ it('adds the application call site to GenAI spans', () => {
47
+ const { attrs, line } = startChat();
48
+ expect(attrs[code_location_1.ATTR_CODE_FUNCTION_NAME]).toBe('startChat');
49
+ expect(attrs[code_location_1.ATTR_CODE_FILE_PATH]).toBe(THIS_FILE);
50
+ expect(attrs[code_location_1.ATTR_CODE_LINE_NUMBER]).toBe(line);
51
+ });
52
+ it('leaves non-GenAI spans alone', () => {
53
+ const { attrs } = startChat({ 'db.system': 'postgresql' });
54
+ expect(attrs[code_location_1.ATTR_CODE_FILE_PATH]).toBeUndefined();
55
+ expect(attrs[code_location_1.ATTR_CODE_FUNCTION_NAME]).toBeUndefined();
56
+ expect(attrs[code_location_1.ATTR_CODE_LINE_NUMBER]).toBeUndefined();
57
+ });
58
+ it('recognises instrumentations that set the operation after creation', () => {
59
+ provider.getTracer('@shield360/instrumentation-langchain').startSpan('chain').end();
60
+ const attrs = exporter.getFinishedSpans()[0].attributes;
61
+ expect(attrs[code_location_1.ATTR_CODE_FILE_PATH]).toBe(THIS_FILE);
62
+ });
63
+ it('never overwrites an existing code.* attribute', () => {
64
+ const { attrs } = startChat({ ...GEN_AI, [code_location_1.ATTR_CODE_FILE_PATH]: 'given.ts' });
65
+ expect(attrs[code_location_1.ATTR_CODE_FILE_PATH]).toBe('given.ts');
66
+ expect(attrs[code_location_1.ATTR_CODE_LINE_NUMBER]).toBeUndefined();
67
+ });
68
+ it('reuses cached frames for a repeated call site', () => {
69
+ const lines = [];
70
+ for (let i = 0; i < 3; i++)
71
+ lines.push(startChat().attrs[code_location_1.ATTR_CODE_LINE_NUMBER]);
72
+ const size = processor.cacheSize;
73
+ startChat();
74
+ expect(processor.cacheSize).toBe(size);
75
+ expect(new Set(lines).size).toBe(1);
76
+ });
77
+ it('restores Error.stackTraceLimit', () => {
78
+ const before = Error.stackTraceLimit;
79
+ startChat();
80
+ expect(Error.stackTraceLimit).toBe(before);
81
+ });
82
+ it('skips SDK, node_modules and node internal frames', () => {
83
+ const sdkFile = (0, path_1.resolve)(__dirname, '../instrumentation/openai/wrapper.ts');
84
+ const appFile = (0, path_1.resolve)(process.cwd(), 'app/billing.ts');
85
+ const stack = [
86
+ 'Error',
87
+ ` at CodeLocationSpanProcessor.onStart (${(0, path_1.resolve)(__dirname, '../otel/code-location.ts')}:1:1)`,
88
+ ` at Span (${process.cwd()}/node_modules/@opentelemetry/sdk-trace/build/src/Span.js:75:29)`,
89
+ ` at Completions.create [as create] (${sdkFile}:84:20)`,
90
+ ' at process.processTicksAndRejections (node:internal/process/task_queues:95:5)',
91
+ ` at async Billing.summarise (${appFile}:42:7)`,
92
+ ].join('\n');
93
+ expect(processor.findApplicationFrame(stack)).toEqual({
94
+ functionName: 'Billing.summarise',
95
+ filePath: (0, path_1.relative)(gitRoot(process.cwd()), appFile).split('\\').join('/'),
96
+ lineNumber: 42,
97
+ });
98
+ });
99
+ it('omits the function name for anonymous frames', () => {
100
+ const file = (0, path_1.resolve)(process.cwd(), 'app/main.ts');
101
+ const frame = processor.findApplicationFrame(`Error\n at Object.<anonymous> (${file}:3:9)`);
102
+ expect(frame?.functionName).toBeUndefined();
103
+ expect(frame?.lineNumber).toBe(3);
104
+ });
105
+ });
106
+ describe('PathNormaliser', () => {
107
+ it('strips an explicit code root first', () => {
108
+ const n = new code_location_1.PathNormaliser({ codeRoot: '/srv/app', cwd: '/elsewhere', home: '/home/bob' });
109
+ expect(n.normalise('/srv/app/src/x.ts')).toBe('src/x.ts');
110
+ });
111
+ it('strips the git root', () => {
112
+ const n = new code_location_1.PathNormaliser({ cwd: '/elsewhere', home: '/nobody' });
113
+ expect(n.normalise(__filename)).toBe(THIS_FILE);
114
+ });
115
+ it('strips the working directory when there is no git root', () => {
116
+ const n = new code_location_1.PathNormaliser({ cwd: '/app', home: '/home/bob' });
117
+ expect(n.normalise('/app/src/server.js')).toBe('src/server.js');
118
+ });
119
+ it('never emits the home directory', () => {
120
+ const n = new code_location_1.PathNormaliser({ cwd: '/srv', home: '/home/bob' });
121
+ expect(n.normalise('/home/bob/proj/x.ts')).toBe('proj/x.ts');
122
+ expect(n.normalise('/opt/lib/y.ts')).toBe('/opt/lib/y.ts');
123
+ });
124
+ it.each([
125
+ ['/home/runner/work/api/api/src/x.ts', 'src/x.ts'],
126
+ ['/github/workspace/src/x.ts', 'src/x.ts'],
127
+ ['/builds/acme/api/src/x.ts', 'src/x.ts'],
128
+ ['/Users/alice/dev/api/x.ts', 'dev/api/x.ts'],
129
+ ['/home/alice/dev/api/x.ts', 'dev/api/x.ts'],
130
+ ['C:/Users/alice/dev/api/x.ts', 'dev/api/x.ts'],
131
+ ['/root/api/x.ts', 'api/x.ts'],
132
+ ['/srv/app/x.ts', '/srv/app/x.ts'],
133
+ ])('drops a home or CI workspace prefix from %s', (input, expected) => {
134
+ expect((0, code_location_1.anonymiseAbsolutePath)(input)).toBe(expected);
135
+ const n = new code_location_1.PathNormaliser({ cwd: '/elsewhere', home: '/home/app' });
136
+ expect(n.normalise(input)).toBe(expected);
137
+ });
138
+ it('converts file:// URLs and drops query and hash', () => {
139
+ const n = new code_location_1.PathNormaliser({ cwd: '/app', home: '/home/bob' });
140
+ expect(n.normalise('file:///app/src/esm.mjs?v=2#top')).toBe('src/esm.mjs');
141
+ expect(n.normalise((0, url_1.pathToFileURL)(__filename).href)).toBe(THIS_FILE);
142
+ });
143
+ it('reads SHIELD360_CODE_ROOT', () => {
144
+ const saved = process.env.SHIELD360_CODE_ROOT;
145
+ process.env.SHIELD360_CODE_ROOT = '/srv/app';
146
+ try {
147
+ expect(new code_location_1.PathNormaliser({ cwd: '/x', home: '/y' }).normalise('/srv/app/a.ts')).toBe('a.ts');
148
+ }
149
+ finally {
150
+ if (saved === undefined)
151
+ delete process.env.SHIELD360_CODE_ROOT;
152
+ else
153
+ process.env.SHIELD360_CODE_ROOT = saved;
154
+ }
155
+ });
156
+ });
157
+ describe('resolveCaptureCodeLocation', () => {
158
+ const saved = process.env.SHIELD360_CAPTURE_CODE_LOCATION;
159
+ afterEach(() => {
160
+ if (saved === undefined)
161
+ delete process.env.SHIELD360_CAPTURE_CODE_LOCATION;
162
+ else
163
+ process.env.SHIELD360_CAPTURE_CODE_LOCATION = saved;
164
+ });
165
+ it('is on by default', () => {
166
+ delete process.env.SHIELD360_CAPTURE_CODE_LOCATION;
167
+ expect((0, code_location_1.resolveCaptureCodeLocation)()).toBe(true);
168
+ });
169
+ it.each(['false', '0', 'NO', ' Off '])('is turned off by env %p', (value) => {
170
+ process.env.SHIELD360_CAPTURE_CODE_LOCATION = value;
171
+ expect((0, code_location_1.resolveCaptureCodeLocation)()).toBe(false);
172
+ });
173
+ it('lets the init option win over env', () => {
174
+ process.env.SHIELD360_CAPTURE_CODE_LOCATION = 'false';
175
+ expect((0, code_location_1.resolveCaptureCodeLocation)(true)).toBe(true);
176
+ process.env.SHIELD360_CAPTURE_CODE_LOCATION = 'true';
177
+ expect((0, code_location_1.resolveCaptureCodeLocation)(false)).toBe(false);
178
+ });
179
+ });
180
+ //# sourceMappingURL=code-location.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-location.test.js","sourceRoot":"","sources":["../../src/__tests__/code-location.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const destination_1 = require("../destination");
4
+ /**
5
+ * A Shield360 URL and API key are enough to send telemetry.
6
+ *
7
+ * Before this, they configured prompt management, the vault and evaluations,
8
+ * and telemetry silently went to the console unless somebody also set the
9
+ * OTLP variables — which every customer has to discover by finding nothing
10
+ * in their dashboard.
11
+ */
12
+ describe('resolveDestination', () => {
13
+ it('points at the platform ingest route with the key as bearer', () => {
14
+ const d = (0, destination_1.resolveDestination)({
15
+ shield360Url: 'https://app.shield360.ai',
16
+ shield360ApiKey: 'k-1',
17
+ });
18
+ expect(d.otlpEndpoint).toBe(`https://app.shield360.ai${destination_1.INGEST_PATH}`);
19
+ expect(d.otlpHeaders).toEqual({ Authorization: 'Bearer k-1' });
20
+ });
21
+ it('tolerates a trailing slash on the URL', () => {
22
+ const d = (0, destination_1.resolveDestination)({ shield360Url: 'https://app.shield360.ai/', shield360ApiKey: 'k' });
23
+ expect(d.otlpEndpoint).toBe(`https://app.shield360.ai${destination_1.INGEST_PATH}`);
24
+ });
25
+ it('lets an explicit OTLP endpoint win, untouched', () => {
26
+ const d = (0, destination_1.resolveDestination)({
27
+ otlpEndpoint: 'http://collector:4318',
28
+ otlpHeaders: { 'X-Team': 'ai' },
29
+ shield360Url: 'https://app.shield360.ai',
30
+ shield360ApiKey: 'k',
31
+ });
32
+ expect(d.otlpEndpoint).toBe('http://collector:4318');
33
+ // No bearer is added to somebody else's collector.
34
+ expect(d.otlpHeaders).toEqual({ 'X-Team': 'ai' });
35
+ });
36
+ it('strips a pasted /v1/traces from an explicit endpoint, as before', () => {
37
+ const d = (0, destination_1.resolveDestination)({ otlpEndpoint: 'http://collector:4318/v1/traces' });
38
+ expect(d.otlpEndpoint).toBe('http://collector:4318');
39
+ });
40
+ it('never overwrites an Authorization header the caller set', () => {
41
+ const d = (0, destination_1.resolveDestination)({
42
+ otlpHeaders: { authorization: 'Basic abc' },
43
+ shield360Url: 'https://app.shield360.ai',
44
+ shield360ApiKey: 'k',
45
+ });
46
+ expect(d.otlpHeaders).toEqual({ authorization: 'Basic abc' });
47
+ });
48
+ it('resolves to nowhere with only one of the two, so the console fallback stays', () => {
49
+ expect((0, destination_1.resolveDestination)({ shield360Url: 'https://app.shield360.ai' }).otlpEndpoint).toBeUndefined();
50
+ expect((0, destination_1.resolveDestination)({ shield360ApiKey: 'k' }).otlpEndpoint).toBeUndefined();
51
+ expect((0, destination_1.resolveDestination)({}).otlpEndpoint).toBeUndefined();
52
+ });
53
+ });
54
+ /**
55
+ * A Shield360 key ends in `=`. The old reader split each pair on every `=`
56
+ * and sent the key one character short — every span refused as invalid, and
57
+ * nothing in the SDK to say why.
58
+ */
59
+ describe('parseOtlpHeaders', () => {
60
+ it('keeps a value that itself contains "="', () => {
61
+ expect((0, destination_1.parseOtlpHeaders)('Authorization=Bearer shield360-abc/DEF==')).toEqual({
62
+ Authorization: 'Bearer shield360-abc/DEF==',
63
+ });
64
+ });
65
+ it('reads several pairs and trims the spaces around them', () => {
66
+ expect((0, destination_1.parseOtlpHeaders)(' Authorization=Bearer k= , x-team = ai ')).toEqual({
67
+ Authorization: 'Bearer k=',
68
+ 'x-team': 'ai',
69
+ });
70
+ });
71
+ it('ignores what is not a pair', () => {
72
+ expect((0, destination_1.parseOtlpHeaders)('=nothing,justaname,,')).toEqual({});
73
+ expect((0, destination_1.parseOtlpHeaders)(undefined)).toEqual({});
74
+ });
75
+ });
76
+ //# sourceMappingURL=destination.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destination.test.js","sourceRoot":"","sources":["../../src/__tests__/destination.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const helpers_1 = __importDefault(require("../helpers"));
7
+ const pricing_json_1 = __importDefault(require("../pricing.json"));
8
+ /**
9
+ * The bundled price table knows the current Claude models.
10
+ *
11
+ * `getChatModelCost` returns 0 for a model it has no entry for, and 0 is
12
+ * indistinguishable from "this call was free". When the table fell behind the
13
+ * model line-up, every request to the newest — and dearest — models was
14
+ * reported as costing nothing, which is the one direction a cost tracker must
15
+ * never be wrong in. These pin the entries and the arithmetic against the
16
+ * published per-million prices.
17
+ */
18
+ const MILLION = 1000000;
19
+ /** Cost of a million input and a million output tokens, in dollars. */
20
+ function perMillion(model) {
21
+ return {
22
+ input: helpers_1.default.getChatModelCost(model, pricing_json_1.default, MILLION, 0),
23
+ output: helpers_1.default.getChatModelCost(model, pricing_json_1.default, 0, MILLION),
24
+ };
25
+ }
26
+ describe('pricing for the Claude 5 family', () => {
27
+ it.each([
28
+ ['claude-opus-5', 5, 25],
29
+ ['claude-opus-5-5', 4, 20],
30
+ ['claude-opus-4-8', 5, 25],
31
+ ['claude-sonnet-5', 2, 10],
32
+ ['claude-sonnet-5-5', 2, 10],
33
+ ['gpt-5.6-sol', 4, 20],
34
+ ['gpt-5.6-terra', 2, 12],
35
+ ['claude-fable-5', 10, 50],
36
+ ['claude-fable-5-1', 10, 50],
37
+ ['claude-haiku-4-5-20251001', 1, 5],
38
+ ])('%s costs $%d in and $%d out per million tokens', (model, input, output) => {
39
+ expect(perMillion(model)).toEqual({ input, output });
40
+ });
41
+ it('prices a cache read at a tenth of input, and a quarter of that on Fable 5.1', () => {
42
+ const opusRead = helpers_1.default.getChatModelCost('claude-opus-5', pricing_json_1.default, 0, 0, MILLION);
43
+ expect(opusRead).toBeCloseTo(0.5, 6);
44
+ const fableRead = helpers_1.default.getChatModelCost('claude-fable-5-1', pricing_json_1.default, 0, 0, MILLION);
45
+ expect(fableRead).toBeCloseTo(0.25, 6);
46
+ });
47
+ it('prices a cache write at one and a quarter times input', () => {
48
+ const write = helpers_1.default.getChatModelCost('claude-sonnet-5', pricing_json_1.default, 0, 0, 0, MILLION);
49
+ expect(write).toBeCloseTo(2.5, 6);
50
+ });
51
+ it('is not silently free for a model the table does know', () => {
52
+ // The failure mode this file exists for: an unknown model costs 0.
53
+ expect(helpers_1.default.getChatModelCost('claude-opus-5', pricing_json_1.default, 1000, 1000)).toBeGreaterThan(0);
54
+ });
55
+ });
56
+ //# sourceMappingURL=pricing-claude-5.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing-claude-5.test.js","sourceRoot":"","sources":["../../src/__tests__/pricing-claude-5.test.ts"],"names":[],"mappings":";;;;;AAAA,yDAAyC;AACzC,mEAAsC;AAEtC;;;;;;;;;GASG;AAEH,MAAM,OAAO,GAAG,OAAS,CAAC;AAE1B,uEAAuE;AACvE,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO;QACL,KAAK,EAAE,iBAAe,CAAC,gBAAgB,CAAC,KAAK,EAAE,sBAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACnE,MAAM,EAAE,iBAAe,CAAC,gBAAgB,CAAC,KAAK,EAAE,sBAAO,EAAE,CAAC,EAAE,OAAO,CAAC;KACrE,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;QACxB,CAAC,iBAAiB,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1B,CAAC,iBAAiB,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1B,CAAC,iBAAiB,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1B,CAAC,mBAAmB,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,CAAC,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;QACtB,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,CAAC;QACxB,CAAC,gBAAgB,EAAE,EAAE,EAAE,EAAE,CAAC;QAC1B,CAAC,kBAAkB,EAAE,EAAE,EAAE,EAAE,CAAC;QAC5B,CAAC,2BAA2B,EAAE,CAAC,EAAE,CAAC,CAAC;KACpC,CAAC,CAAC,gDAAgD,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAC5E,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6EAA6E,EAAE,GAAG,EAAE;QACrF,MAAM,QAAQ,GAAG,iBAAe,CAAC,gBAAgB,CAAC,eAAe,EAAE,sBAAO,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;QAC3F,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAErC,MAAM,SAAS,GAAG,iBAAe,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,sBAAO,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;QAC/F,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,KAAK,GAAG,iBAAe,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,sBAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;QAC7F,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,mEAAmE;QACnE,MAAM,CAAC,iBAAe,CAAC,gBAAgB,CAAC,eAAe,EAAE,sBAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACpG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/dist/config.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  class Shield360Config {
4
- static updateConfig({ environment = 'default', applicationName = 'default', tracer, otlpEndpoint, otlpHeaders, disableBatch = false, captureMessageContent = true, pricingJson, disableMetrics = false, disableEvents = false, maxContentLength = null, customSpanAttributes = null, shield360ApiKey, shield360Url, }) {
4
+ static updateConfig({ environment = 'default', applicationName = 'default', tracer, otlpEndpoint, otlpHeaders, disableBatch = false, captureMessageContent = false, pricingJson, disableMetrics = false, disableEvents = false, maxContentLength = null, customSpanAttributes = null, shield360ApiKey, shield360Url, }) {
5
5
  this.environment = environment;
6
6
  this.applicationName = applicationName;
7
7
  this.tracer = tracer;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;AAGA,MAAqB,eAAe;IAkBlC,MAAM,CAAC,YAAY,CAAC,EAClB,WAAW,GAAG,SAAS,EACvB,eAAe,GAAG,SAAS,EAC3B,MAAM,EACN,YAAY,EACZ,WAAW,EACX,YAAY,GAAG,KAAK,EACpB,qBAAqB,GAAG,IAAI,EAC5B,WAAW,EACX,cAAc,GAAG,KAAK,EACtB,aAAa,GAAG,KAAK,EACrB,gBAAgB,GAAG,IAAI,EACvB,oBAAoB,GAAG,IAAI,EAC3B,eAAe,EACf,YAAY,GAQb;QACC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,MAA4C,CAAC;QAC3D,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,qBAAqB,GAAG,qBAAqB,CAAC;QACnD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,oBAAoB,GAAG,oBAAoB,CAAC;QACjD,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;CACF;AAxDD,kCAwDC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;AAGA,MAAqB,eAAe;IAkBlC,MAAM,CAAC,YAAY,CAAC,EAClB,WAAW,GAAG,SAAS,EACvB,eAAe,GAAG,SAAS,EAC3B,MAAM,EACN,YAAY,EACZ,WAAW,EACX,YAAY,GAAG,KAAK,EACpB,qBAAqB,GAAG,KAAK,EAC7B,WAAW,EACX,cAAc,GAAG,KAAK,EACtB,aAAa,GAAG,KAAK,EACrB,gBAAgB,GAAG,IAAI,EACvB,oBAAoB,GAAG,IAAI,EAC3B,eAAe,EACf,YAAY,GAQb;QACC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,MAA4C,CAAC;QAC3D,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,qBAAqB,GAAG,qBAAqB,CAAC;QACnD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,oBAAoB,GAAG,oBAAoB,CAAC;QACjD,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;CACF;AAxDD,kCAwDC"}