Skip to content

Commit d0b2f7d

Browse files
authored
Merge pull request #15578 from getsentry/lms/fix-sveltekit-type-assertion
fix(sveltekit): Correctly parse angle bracket type assertions for auto instrumentation
2 parents c27a09a + 62f3b09 commit d0b2f7d

File tree

7 files changed

+169
-63
lines changed

7 files changed

+169
-63
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script lang="ts">
2+
export let data
3+
</script>
4+
5+
<h1>Type Assertion</h1>
6+
7+
<p>
8+
This route only exists to ensure we don't emit a build error because of the angle bracket type assertion in +page.ts
9+
see https://github.com/getsentry/sentry-javascript/issues/9318
10+
</p>
11+
12+
<p>
13+
Message: {data.msg}
14+
</p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export async function load() {
2+
let x: unknown = 'foo';
3+
return {
4+
// this angle bracket type assertion threw an auto instrumentation error
5+
// see: https://github.com/getsentry/sentry-javascript/issues/9318
6+
msg: <string>x,
7+
};
8+
}

packages/sveltekit/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,15 @@
4444
}
4545
},
4646
"dependencies": {
47+
"@babel/parser": "7.26.9",
4748
"@sentry/cloudflare": "9.5.0",
4849
"@sentry/core": "9.5.0",
4950
"@sentry/node": "9.5.0",
5051
"@sentry/opentelemetry": "9.5.0",
5152
"@sentry/svelte": "9.5.0",
5253
"@sentry/vite-plugin": "3.2.0",
5354
"magic-string": "0.30.7",
54-
"magicast": "0.2.8",
55+
"recast": "0.23.11",
5556
"sorcery": "1.0.0"
5657
},
5758
"devDependencies": {

packages/sveltekit/src/vite/autoInstrument.ts

+20-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
3-
import type { ExportNamedDeclaration } from '@babel/types';
4-
import { parseModule } from 'magicast';
3+
import * as recast from 'recast';
4+
import t = recast.types.namedTypes;
55
import type { Plugin } from 'vite';
66
import { WRAPPED_MODULE_SUFFIX } from '../common/utils';
7+
import { parser } from './recastTypescriptParser';
78

89
export type AutoInstrumentSelection = {
910
/**
@@ -101,22 +102,30 @@ export async function canWrapLoad(id: string, debug: boolean): Promise<boolean>
101102

102103
const code = (await fs.promises.readFile(id, 'utf8')).toString();
103104

104-
const mod = parseModule(code);
105+
const ast = recast.parse(code, {
106+
parser,
107+
});
108+
109+
const program = (ast as { program?: t.Program }).program;
105110

106-
const program = mod.$ast.type === 'Program' && mod.$ast;
107111
if (!program) {
108112
// eslint-disable-next-line no-console
109113
debug && console.log(`Skipping wrapping ${id} because it doesn't contain valid JavaScript or TypeScript`);
110114
return false;
111115
}
112116

113117
const hasLoadDeclaration = program.body
114-
.filter((statement): statement is ExportNamedDeclaration => statement.type === 'ExportNamedDeclaration')
118+
.filter(
119+
(statement): statement is recast.types.namedTypes.ExportNamedDeclaration =>
120+
statement.type === 'ExportNamedDeclaration',
121+
)
115122
.find(exportDecl => {
116123
// find `export const load = ...`
117124
if (exportDecl.declaration?.type === 'VariableDeclaration') {
118125
const variableDeclarations = exportDecl.declaration.declarations;
119-
return variableDeclarations.find(decl => decl.id.type === 'Identifier' && decl.id.name === 'load');
126+
return variableDeclarations.find(
127+
decl => decl.type === 'VariableDeclarator' && decl.id.type === 'Identifier' && decl.id.name === 'load',
128+
);
120129
}
121130

122131
// find `export function load = ...`
@@ -130,7 +139,11 @@ export async function canWrapLoad(id: string, debug: boolean): Promise<boolean>
130139
return exportDecl.specifiers.find(specifier => {
131140
return (
132141
(specifier.exported.type === 'Identifier' && specifier.exported.name === 'load') ||
133-
(specifier.exported.type === 'StringLiteral' && specifier.exported.value === 'load')
142+
// Type casting here because somehow the 'exportExtensions' plugin isn't reflected in the possible types
143+
// This plugin adds support for exporting something as a string literal (see comment above)
144+
// Doing this to avoid adding another babel plugin dependency
145+
((specifier.exported.type as 'StringLiteral' | '') === 'StringLiteral' &&
146+
(specifier.exported as unknown as t.StringLiteral).value === 'load')
134147
);
135148
});
136149
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// This babel parser config is taken from recast's typescript parser config, specifically from these two files:
2+
// see: https://github.com/benjamn/recast/blob/master/parsers/_babel_options.ts
3+
// see: https://github.com/benjamn/recast/blob/master/parsers/babel-ts.ts
4+
//
5+
// Changes:
6+
// - we don't add the 'jsx' plugin, to correctly parse TypeScript angle bracket type assertions
7+
// (see https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions)
8+
// - minor import and export changes
9+
// - merged the two files linked above into one for simplicity
10+
11+
// Date of access: 2025-03-04
12+
// Commit: https://github.com/benjamn/recast/commit/ba5132174894b496285da9d001f1f2524ceaed3a
13+
14+
// Recast license:
15+
16+
// Copyright (c) 2012 Ben Newman <bn@cs.stanford.edu>
17+
18+
// Permission is hereby granted, free of charge, to any person obtaining
19+
// a copy of this software and associated documentation files (the
20+
// "Software"), to deal in the Software without restriction, including
21+
// without limitation the rights to use, copy, modify, merge, publish,
22+
// distribute, sublicense, and/or sell copies of the Software, and to
23+
// permit persons to whom the Software is furnished to do so, subject to
24+
// the following conditions:
25+
26+
// The above copyright notice and this permission notice shall be
27+
// included in all copies or substantial portions of the Software.
28+
29+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32+
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
33+
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
34+
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
35+
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36+
37+
import type { ParserPlugin } from '@babel/parser';
38+
import { parse as babelParse } from '@babel/parser';
39+
import type { Options } from 'recast';
40+
41+
export const parser: Options['parser'] = {
42+
parse: (source: string) =>
43+
babelParse(source, {
44+
strictMode: false,
45+
allowImportExportEverywhere: true,
46+
allowReturnOutsideFunction: true,
47+
startLine: 1,
48+
tokens: true,
49+
plugins: [
50+
'typescript',
51+
'asyncGenerators',
52+
'bigInt',
53+
'classPrivateMethods',
54+
'classPrivateProperties',
55+
'classProperties',
56+
'classStaticBlock',
57+
'decimal',
58+
'decorators-legacy',
59+
'doExpressions',
60+
'dynamicImport',
61+
'exportDefaultFrom',
62+
'exportNamespaceFrom',
63+
'functionBind',
64+
'functionSent',
65+
'importAssertions',
66+
'exportExtensions' as ParserPlugin,
67+
'importMeta',
68+
'nullishCoalescingOperator',
69+
'numericSeparator',
70+
'objectRestSpread',
71+
'optionalCatchBinding',
72+
'optionalChaining',
73+
[
74+
'pipelineOperator',
75+
{
76+
proposal: 'minimal',
77+
},
78+
],
79+
[
80+
'recordAndTuple',
81+
{
82+
syntaxType: 'hash',
83+
},
84+
],
85+
'throwExpressions',
86+
'topLevelAwait',
87+
'v8intrinsic',
88+
],
89+
sourceType: 'module',
90+
}),
91+
};

packages/sveltekit/test/vite/autoInstrument.test.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,15 @@ describe('canWrapLoad', () => {
140140
return { props: { msg: res.toString() } }
141141
}`,
142142
],
143-
143+
[
144+
'export function declaration - with angle bracket type assertion',
145+
`export async function load() {
146+
let x: unknown = 'foo';
147+
return {
148+
msg: <string>x,
149+
};
150+
}`,
151+
],
144152
[
145153
'variable declaration (let)',
146154
`import {something} from 'somewhere';

yarn.lock

+25-54
Original file line numberDiff line numberDiff line change
@@ -1695,20 +1695,20 @@
16951695
js-tokens "^4.0.0"
16961696
picocolors "^1.0.0"
16971697

1698-
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.4", "@babel/parser@^7.18.10", "@babel/parser@^7.20.7", "@babel/parser@^7.21.8", "@babel/parser@^7.21.9", "@babel/parser@^7.22.10", "@babel/parser@^7.22.16", "@babel/parser@^7.23.5", "@babel/parser@^7.23.9", "@babel/parser@^7.25.3", "@babel/parser@^7.25.4", "@babel/parser@^7.25.6", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3", "@babel/parser@^7.4.5", "@babel/parser@^7.7.0":
1699-
version "7.26.3"
1700-
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234"
1701-
integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==
1702-
dependencies:
1703-
"@babel/types" "^7.26.3"
1704-
1705-
"@babel/parser@^7.23.6", "@babel/parser@^7.26.9":
1698+
"@babel/parser@7.26.9", "@babel/parser@^7.23.6", "@babel/parser@^7.26.9":
17061699
version "7.26.9"
17071700
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.9.tgz#d9e78bee6dc80f9efd8f2349dcfbbcdace280fd5"
17081701
integrity sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==
17091702
dependencies:
17101703
"@babel/types" "^7.26.9"
17111704

1705+
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.4", "@babel/parser@^7.18.10", "@babel/parser@^7.20.7", "@babel/parser@^7.21.8", "@babel/parser@^7.22.10", "@babel/parser@^7.22.16", "@babel/parser@^7.23.5", "@babel/parser@^7.23.9", "@babel/parser@^7.25.3", "@babel/parser@^7.25.4", "@babel/parser@^7.25.6", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3", "@babel/parser@^7.4.5", "@babel/parser@^7.7.0":
1706+
version "7.26.3"
1707+
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234"
1708+
integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==
1709+
dependencies:
1710+
"@babel/types" "^7.26.3"
1711+
17121712
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.4":
17131713
version "7.24.4"
17141714
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz#6125f0158543fb4edf1c22f322f3db67f21cb3e1"
@@ -2829,7 +2829,7 @@
28292829
debug "^4.3.1"
28302830
globals "^11.1.0"
28312831

2832-
"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.21.5", "@babel/types@^7.22.10", "@babel/types@^7.22.15", "@babel/types@^7.22.17", "@babel/types@^7.22.19", "@babel/types@^7.23.6", "@babel/types@^7.23.9", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.4", "@babel/types@^7.25.6", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.3", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.7.2":
2832+
"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.22.10", "@babel/types@^7.22.15", "@babel/types@^7.22.17", "@babel/types@^7.22.19", "@babel/types@^7.23.6", "@babel/types@^7.23.9", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.4", "@babel/types@^7.25.6", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.3", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.7.2":
28332833
version "7.26.3"
28342834
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0"
28352835
integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==
@@ -8509,12 +8509,7 @@
85098509
dependencies:
85108510
"@types/unist" "*"
85118511

8512-
"@types/history-4@npm:@types/history@4.7.8":
8513-
version "4.7.8"
8514-
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934"
8515-
integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA==
8516-
8517-
"@types/history-5@npm:@types/history@4.7.8":
8512+
"@types/history-4@npm:@types/history@4.7.8", "@types/history-5@npm:@types/history@4.7.8":
85188513
version "4.7.8"
85198514
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934"
85208515
integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA==
@@ -21326,15 +21321,6 @@ magic-string@^0.30.0, magic-string@^0.30.10, magic-string@^0.30.11, magic-string
2132621321
dependencies:
2132721322
"@jridgewell/sourcemap-codec" "^1.5.0"
2132821323

21329-
magicast@0.2.8:
21330-
version "0.2.8"
21331-
resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.2.8.tgz#02b298c65fbc5b7d1fce52ef779c59caf68cc9cf"
21332-
integrity sha512-zEnqeb3E6TfMKYXGyHv3utbuHNixr04o3/gVGviSzVQkbFiU46VZUd+Ea/1npKfvEsEWxBYuIksKzoztTDPg0A==
21333-
dependencies:
21334-
"@babel/parser" "^7.21.9"
21335-
"@babel/types" "^7.21.5"
21336-
recast "^0.23.2"
21337-
2133821324
magicast@^0.2.10:
2133921325
version "0.2.11"
2134021326
resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.2.11.tgz#d5d9339ec59e5322cf331460d8e3db2f6585f5d5"
@@ -26237,6 +26223,17 @@ realistic-structured-clone@^3.0.0:
2623726223
typeson "^6.1.0"
2623826224
typeson-registry "^1.0.0-alpha.20"
2623926225

26226+
recast@0.23.11:
26227+
version "0.23.11"
26228+
resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.11.tgz#8885570bb28cf773ba1dc600da7f502f7883f73f"
26229+
integrity sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==
26230+
dependencies:
26231+
ast-types "^0.16.1"
26232+
esprima "~4.0.0"
26233+
source-map "~0.6.1"
26234+
tiny-invariant "^1.3.3"
26235+
tslib "^2.0.1"
26236+
2624026237
recast@^0.18.1:
2624126238
version "0.18.10"
2624226239
resolved "https://registry.yarnpkg.com/recast/-/recast-0.18.10.tgz#605ebbe621511eb89b6356a7e224bff66ed91478"
@@ -26257,7 +26254,7 @@ recast@^0.20.5:
2625726254
source-map "~0.6.1"
2625826255
tslib "^2.0.1"
2625926256

26260-
recast@^0.23.2, recast@^0.23.4:
26257+
recast@^0.23.4:
2626126258
version "0.23.9"
2626226259
resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.9.tgz#587c5d3a77c2cfcb0c18ccce6da4361528c2587b"
2626326260
integrity sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==
@@ -28346,16 +28343,7 @@ string-template@~0.2.1:
2834628343
resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add"
2834728344
integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=
2834828345

28349-
"string-width-cjs@npm:string-width@^4.2.0":
28350-
version "4.2.3"
28351-
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
28352-
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
28353-
dependencies:
28354-
emoji-regex "^8.0.0"
28355-
is-fullwidth-code-point "^3.0.0"
28356-
strip-ansi "^6.0.1"
28357-
28358-
string-width@4.2.3, "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
28346+
"string-width-cjs@npm:string-width@^4.2.0", string-width@4.2.3, "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
2835928347
version "4.2.3"
2836028348
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
2836128349
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -28458,14 +28446,7 @@ stringify-object@^3.2.1:
2845828446
is-obj "^1.0.1"
2845928447
is-regexp "^1.0.0"
2846028448

28461-
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
28462-
version "6.0.1"
28463-
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
28464-
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
28465-
dependencies:
28466-
ansi-regex "^5.0.1"
28467-
28468-
strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
28449+
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
2846928450
version "6.0.1"
2847028451
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
2847128452
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -28630,7 +28611,6 @@ stylus@0.59.0, stylus@^0.59.0:
2863028611

2863128612
sucrase@^3.27.0, sucrase@^3.35.0, sucrase@getsentry/sucrase#es2020-polyfills:
2863228613
version "3.36.0"
28633-
uid fd682f6129e507c00bb4e6319cc5d6b767e36061
2863428614
resolved "https://codeload.github.com/getsentry/sucrase/tar.gz/fd682f6129e507c00bb4e6319cc5d6b767e36061"
2863528615
dependencies:
2863628616
"@jridgewell/gen-mapping" "^0.3.2"
@@ -31303,16 +31283,7 @@ wrangler@^3.67.1:
3130331283
optionalDependencies:
3130431284
fsevents "~2.3.2"
3130531285

31306-
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
31307-
version "7.0.0"
31308-
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
31309-
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
31310-
dependencies:
31311-
ansi-styles "^4.0.0"
31312-
string-width "^4.1.0"
31313-
strip-ansi "^6.0.0"
31314-
31315-
wrap-ansi@7.0.0, wrap-ansi@^7.0.0:
31286+
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@7.0.0, wrap-ansi@^7.0.0:
3131631287
version "7.0.0"
3131731288
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
3131831289
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==

0 commit comments

Comments
 (0)