Skip to content

Commit 7ace30b

Browse files
committed
Merge pull request #14135 from getsentry/master
meta(changelog): Merge changelog from master to develop
2 parents 472c228 + a9cedf9 commit 7ace30b

File tree

10 files changed

+277
-3
lines changed

10 files changed

+277
-3
lines changed

CHANGELOG.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,73 @@
1010

1111
- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott
1212

13+
- **feat(nuxt): Add Sentry Pinia plugin ([#14138](https://github.com/getsentry/sentry-javascript/pull/14138))**
14+
15+
The Nuxt SDK now allows you to track Pinia state for captured errors. To enable the Pinia plugin, add the `piniaIntegration` to your client config:
16+
17+
```ts
18+
// sentry.client.config.ts
19+
import { usePinia } from '#imports';
20+
21+
Sentry.init({
22+
integrations: [
23+
Sentry.piniaIntegration(usePinia(), {
24+
/* optinal Pinia plugin options */
25+
}),
26+
],
27+
});
28+
```
29+
30+
## 8.36.0
31+
32+
### Important Changes
33+
34+
- **feat(nuxt): Add Sentry Pinia plugin ([#14047](https://github.com/getsentry/sentry-javascript/pull/14047))**
35+
36+
The Nuxt SDK now allows you to track Pinia state for captured errors. To enable the Pinia plugin, set the `trackPinia` option to `true` in your client config:
37+
38+
```ts
39+
// sentry.client.config.ts
40+
41+
Sentry.init({
42+
trackPinia: true,
43+
});
44+
```
45+
46+
Read more about the Pinia plugin in the [Sentry Pinia Documentation](https://docs.sentry.io/platforms/javascript/guides/nuxt/features/pinia/).
47+
48+
- **feat(nextjs/vercel-edge/cloudflare): Switch to OTEL for performance monitoring ([#13889](https://github.com/getsentry/sentry-javascript/pull/13889))**
49+
50+
With this release, the Sentry Next.js, and Cloudflare SDKs will now capture performance data based on OpenTelemetry.
51+
Some exceptions apply in cases where Next.js captures inaccurate data itself.
52+
53+
NOTE: You may experience minor differences in transaction names in Sentry.
54+
Most importantly transactions for serverside pages router invocations will now be named `GET /[param]/my/route` instead of `/[param]/my/route`.
55+
This means that those transactions are now better aligned with the OpenTelemetry semantic conventions.
56+
57+
### Other Changes
58+
59+
- deps: Bump bundler plugins and CLI to 2.22.6 and 2.37.0 respectively ([#14050](https://github.com/getsentry/sentry-javascript/pull/14050))
60+
- feat(deps): bump @opentelemetry/instrumentation-aws-sdk from 0.44.0 to 0.45.0 ([#14099](https://github.com/getsentry/sentry-javascript/pull/14099))
61+
- feat(deps): bump @opentelemetry/instrumentation-connect from 0.39.0 to 0.40.0 ([#14101](https://github.com/getsentry/sentry-javascript/pull/14101))
62+
- feat(deps): bump @opentelemetry/instrumentation-express from 0.43.0 to 0.44.0 ([#14102](https://github.com/getsentry/sentry-javascript/pull/14102))
63+
- feat(deps): bump @opentelemetry/instrumentation-fs from 0.15.0 to 0.16.0 ([#14098](https://github.com/getsentry/sentry-javascript/pull/14098))
64+
- feat(deps): bump @opentelemetry/instrumentation-kafkajs from 0.3.0 to 0.4.0 ([#14100](https://github.com/getsentry/sentry-javascript/pull/14100))
65+
- feat(nextjs): Add method and url to route handler request data ([#14084](https://github.com/getsentry/sentry-javascript/pull/14084))
66+
- feat(node): Add breadcrumbs for `child_process` and `worker_thread` ([#13896](https://github.com/getsentry/sentry-javascript/pull/13896))
67+
- fix(core): Ensure standalone spans are not sent if SDK is disabled ([#14088](https://github.com/getsentry/sentry-javascript/pull/14088))
68+
- fix(nextjs): Await flush in api handlers ([#14023](https://github.com/getsentry/sentry-javascript/pull/14023))
69+
- fix(nextjs): Don't leak webpack types into exports ([#14116](https://github.com/getsentry/sentry-javascript/pull/14116))
70+
- fix(nextjs): Fix matching logic for file convention type for root level components ([#14038](https://github.com/getsentry/sentry-javascript/pull/14038))
71+
- fix(nextjs): Respect directives in value injection loader ([#14083](https://github.com/getsentry/sentry-javascript/pull/14083))
72+
- fix(nuxt): Only wrap `.mjs` entry files in rollup ([#14060](https://github.com/getsentry/sentry-javascript/pull/14060))
73+
- fix(nuxt): Re-export all exported bindings ([#14086](https://github.com/getsentry/sentry-javascript/pull/14086))
74+
- fix(nuxt): Server-side setup in readme ([#14049](https://github.com/getsentry/sentry-javascript/pull/14049))
75+
- fix(profiling-node): Always warn when running on incompatible major version of Node.js ([#14043](https://github.com/getsentry/sentry-javascript/pull/14043))
76+
- fix(replay): Fix `onError` callback ([#14002](https://github.com/getsentry/sentry-javascript/pull/14002))
77+
- perf(otel): Only calculate current timestamp once ([#14094](https://github.com/getsentry/sentry-javascript/pull/14094))
78+
- test(browser-integration): Add sentry DSN route handler by default ([#14095](https://github.com/getsentry/sentry-javascript/pull/14095))
79+
1380
## 8.35.0
1481

1582
### Beta release of the official Nuxt Sentry SDK
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<script setup lang="ts">
2+
import { ref } from '#imports'
3+
import { useCartStore } from '~~/stores/cart'
4+
5+
const cart = useCartStore()
6+
7+
const itemName = ref('')
8+
9+
function addItemToCart() {
10+
if (!itemName.value) return
11+
cart.addItem(itemName.value)
12+
itemName.value = ''
13+
}
14+
15+
function throwError() {
16+
throw new Error('This is an error')
17+
}
18+
19+
function clearCart() {
20+
if (window.confirm('Are you sure you want to clear the cart?')) {
21+
cart.rawItems = []
22+
}
23+
}
24+
</script>
25+
26+
<template>
27+
<Layout>
28+
<div>
29+
<div style="margin: 1rem 0;">
30+
<PiniaLogo />
31+
</div>
32+
33+
<form @submit.prevent="addItemToCart" data-testid="add-items">
34+
<input id="item-input" type="text" v-model="itemName" />
35+
<button id="item-add">Add</button>
36+
<button id="throw-error" @click="throwError">Throw error</button>
37+
</form>
38+
39+
<form>
40+
<ul data-testid="items">
41+
<li v-for="item in cart.items" :key="item.name">
42+
{{ item.name }} ({{ item.amount }})
43+
<button
44+
@click="cart.removeItem(item.name)"
45+
type="button"
46+
>X</button>
47+
</li>
48+
</ul>
49+
50+
<button
51+
:disabled="!cart.items.length"
52+
@click="clearCart"
53+
type="button"
54+
data-testid="clear"
55+
>Clear the cart</button>
56+
</form>
57+
</div>
58+
</Layout>
59+
</template>
60+
61+
62+
63+
<style scoped>
64+
img {
65+
width: 200px;
66+
}
67+
68+
button,
69+
input {
70+
margin-right: 0.5rem;
71+
margin-bottom: 0.5rem;
72+
}
73+
</style>

dev-packages/e2e-tests/test-applications/nuxt-4/nuxt.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export default defineNuxtConfig({
44
compatibilityDate: '2024-04-03',
55
imports: { autoImport: false },
66

7-
modules: ['@sentry/nuxt/module'],
7+
modules: ['@pinia/nuxt', '@sentry/nuxt/module'],
88

99
runtimeConfig: {
1010
public: {

dev-packages/e2e-tests/test-applications/nuxt-4/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"test:assert": "pnpm test"
1515
},
1616
"dependencies": {
17+
"@pinia/nuxt": "^0.5.5",
1718
"@sentry/nuxt": "latest || *",
1819
"nuxt": "^3.13.2"
1920
},
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
import * as Sentry from '@sentry/nuxt';
2-
import { useRuntimeConfig } from '#imports';
2+
import { usePinia, useRuntimeConfig } from '#imports';
33

44
Sentry.init({
55
environment: 'qa', // dynamic sampling bias to keep transactions
66
dsn: useRuntimeConfig().public.sentry.dsn,
77
tunnel: `http://localhost:3031/`, // proxy server
88
tracesSampleRate: 1.0,
99
trackComponents: true,
10+
integrations: [
11+
Sentry.piniaIntegration(usePinia(), {
12+
actionTransformer: action => `Transformed: ${action}`,
13+
stateTransformer: state => ({
14+
transformed: true,
15+
...state,
16+
}),
17+
}),
18+
],
1019
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { acceptHMRUpdate, defineStore } from '#imports';
2+
3+
export const useCartStore = defineStore({
4+
id: 'cart',
5+
state: () => ({
6+
rawItems: [] as string[],
7+
}),
8+
getters: {
9+
items: (state): Array<{ name: string; amount: number }> =>
10+
state.rawItems.reduce(
11+
(items: any, item: any) => {
12+
const existingItem = items.find((it: any) => it.name === item);
13+
14+
if (!existingItem) {
15+
items.push({ name: item, amount: 1 });
16+
} else {
17+
existingItem.amount++;
18+
}
19+
20+
return items;
21+
},
22+
[] as Array<{ name: string; amount: number }>,
23+
),
24+
},
25+
actions: {
26+
addItem(name: string) {
27+
this.rawItems.push(name);
28+
},
29+
30+
removeItem(name: string) {
31+
const i = this.rawItems.lastIndexOf(name);
32+
if (i > -1) this.rawItems.splice(i, 1);
33+
},
34+
35+
throwError() {
36+
throw new Error('error');
37+
},
38+
},
39+
});
40+
41+
if (import.meta.hot) {
42+
import.meta.hot.accept(acceptHMRUpdate(useCartStore, import.meta.hot));
43+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForError } from '@sentry-internal/test-utils';
3+
4+
test('sends pinia action breadcrumbs and state context', async ({ page }) => {
5+
await page.goto('/pinia-cart');
6+
7+
await page.locator('#item-input').fill('item');
8+
await page.locator('#item-add').click();
9+
10+
const errorPromise = waitForError('nuxt-4', async errorEvent => {
11+
return errorEvent?.exception?.values?.[0].value === 'This is an error';
12+
});
13+
14+
await page.locator('#throw-error').click();
15+
16+
const error = await errorPromise;
17+
18+
expect(error).toBeTruthy();
19+
expect(error.breadcrumbs?.length).toBeGreaterThan(0);
20+
21+
const actionBreadcrumb = error.breadcrumbs?.find(breadcrumb => breadcrumb.category === 'action');
22+
23+
expect(actionBreadcrumb).toBeDefined();
24+
expect(actionBreadcrumb?.message).toBe('Transformed: addItem');
25+
expect(actionBreadcrumb?.level).toBe('info');
26+
27+
const stateContext = error.contexts?.state?.state;
28+
29+
expect(stateContext).toBeDefined();
30+
expect(stateContext?.type).toBe('pinia');
31+
expect(stateContext?.value).toEqual({
32+
transformed: true,
33+
rawItems: ['item'],
34+
});
35+
});

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@
153153
"printWidth": 120,
154154
"proseWrap": "always",
155155
"singleQuote": true,
156-
"trailingComma": "all"
156+
"trailingComma": "all",
157+
"overrides": [{
158+
"files": "CHANGELOG.md",
159+
"options": {
160+
"proseWrap": "preserve"
161+
}
162+
}]
157163
}
158164
}

packages/nuxt/src/client/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from '@sentry/vue';
22

33
export { init } from './sdk';
4+
export { piniaIntegration } from './piniaIntegration';
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { defineIntegration } from '@sentry/core';
2+
import type { IntegrationFn } from '@sentry/types';
3+
4+
import { consoleSandbox } from '@sentry/utils';
5+
import { createSentryPiniaPlugin } from '@sentry/vue';
6+
7+
const INTEGRATION_NAME = 'LinkedErrors';
8+
9+
type Pinia = { use: (plugin: ReturnType<typeof createSentryPiniaPlugin>) => void };
10+
11+
const _piniaIntegration = ((
12+
// `unknown` here as well because usePinia declares this type: `export declare const usePinia: () => unknown;`
13+
pinia: unknown | Pinia,
14+
options: Parameters<typeof createSentryPiniaPlugin>[0] = {},
15+
) => {
16+
return {
17+
name: INTEGRATION_NAME,
18+
setup() {
19+
if (!pinia || (typeof pinia === 'object' && !('use' in pinia))) {
20+
consoleSandbox(() => {
21+
// eslint-disable-next-line no-console
22+
console.warn(
23+
'[Sentry] You added the Pinia integration, but the passed parameter `pinia` has the wrong value. Make sure to enable Pinia by adding `"@pinia/nuxt"` to your Nuxt modules array and pass pinia to Sentry with `piniaIntegration(usePinia())`. Current value of `pinia`: ',
24+
pinia,
25+
);
26+
});
27+
} else {
28+
(pinia as Pinia).use(createSentryPiniaPlugin(options));
29+
}
30+
},
31+
};
32+
}) satisfies IntegrationFn;
33+
34+
/**
35+
* Monitor an existing Pinia store.
36+
*
37+
* This only works if "@pinia/nuxt" is added to the `modules` array.
38+
*/
39+
export const piniaIntegration = defineIntegration(_piniaIntegration);

0 commit comments

Comments
 (0)