gracefulerrors 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -2
- package/dist/vue.cjs +85 -0
- package/dist/vue.cjs.map +1 -0
- package/dist/vue.d.cts +32 -0
- package/dist/vue.d.ts +32 -0
- package/dist/vue.js +78 -0
- package/dist/vue.js.map +1 -0
- package/package.json +14 -3
package/README.md
CHANGED
|
@@ -17,12 +17,18 @@ gracefulerrors is a TypeScript library for turning technical errors into consist
|
|
|
17
17
|
npm install gracefulerrors
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
If you use the React SDK or the Sonner adapter, install the matching peer dependencies
|
|
20
|
+
If you use the React SDK or the Sonner adapter, install the matching peer dependencies:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
npm install react react-dom sonner
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
If you use the Vue SDK:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install vue
|
|
30
|
+
```
|
|
31
|
+
|
|
26
32
|
## Quick Start
|
|
27
33
|
|
|
28
34
|
```ts
|
|
@@ -120,6 +126,44 @@ export function App() {
|
|
|
120
126
|
- `useFieldError(field)` for inline error state
|
|
121
127
|
- `ErrorBoundaryWithEngine` for catching runtime errors and forwarding them to the engine
|
|
122
128
|
|
|
129
|
+
## Vue Integration
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { createErrorEngine } from 'gracefulerrors'
|
|
133
|
+
import { createErrorEnginePlugin, useErrorEngine } from 'gracefulerrors/vue'
|
|
134
|
+
import { createApp } from 'vue'
|
|
135
|
+
import App from './App.vue'
|
|
136
|
+
|
|
137
|
+
const engine = createErrorEngine({
|
|
138
|
+
registry: {
|
|
139
|
+
NETWORK_ERROR: { ui: 'toast', message: 'Network error' },
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
const app = createApp(App)
|
|
144
|
+
app.use(createErrorEnginePlugin(engine))
|
|
145
|
+
app.mount('#app')
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Inside any component:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { useErrorEngine, useFieldError } from 'gracefulerrors/vue'
|
|
152
|
+
|
|
153
|
+
// Access the engine
|
|
154
|
+
const engine = useErrorEngine()
|
|
155
|
+
engine?.handle({ code: 'NETWORK_ERROR' })
|
|
156
|
+
|
|
157
|
+
// Bind inline field errors
|
|
158
|
+
const { error } = useFieldError('email')
|
|
159
|
+
// error is a Ref<AppError | null> that updates reactively
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`gracefulerrors/vue` also exports:
|
|
163
|
+
|
|
164
|
+
- `provideErrorEngine(engine)` for local subtree injection (alternative to the global plugin)
|
|
165
|
+
- `ErrorBoundaryWithEngine` component for catching runtime errors and forwarding them to the engine
|
|
166
|
+
|
|
123
167
|
## Sonner Adapter
|
|
124
168
|
|
|
125
169
|
```tsx
|
|
@@ -161,6 +205,7 @@ Type exports are available from the root package as well.
|
|
|
161
205
|
Additional entry points:
|
|
162
206
|
|
|
163
207
|
- `gracefulerrors/react`
|
|
208
|
+
- `gracefulerrors/vue`
|
|
164
209
|
- `gracefulerrors/sonner`
|
|
165
210
|
- `gracefulerrors/internal` for internal testing and low-level integration only
|
|
166
211
|
|
|
@@ -183,7 +228,7 @@ Common engine options include:
|
|
|
183
228
|
## Package Notes
|
|
184
229
|
|
|
185
230
|
- Package format: ESM and CJS via conditional exports
|
|
186
|
-
- Runtime peers: `react`, `react-dom`, and `
|
|
231
|
+
- Runtime peers: `react`, `react-dom`, `sonner`, and `vue` are optional peer dependencies
|
|
187
232
|
- Current version: `0.1.0`
|
|
188
233
|
|
|
189
234
|
## Development
|
package/dist/vue.cjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var vue = require('vue');
|
|
4
|
+
|
|
5
|
+
// src/vue.ts
|
|
6
|
+
var ErrorEngineKey = /* @__PURE__ */ Symbol("ErrorEngine");
|
|
7
|
+
function createErrorEnginePlugin(engine) {
|
|
8
|
+
return {
|
|
9
|
+
install(app) {
|
|
10
|
+
app.provide(ErrorEngineKey, engine);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function provideErrorEngine(engine) {
|
|
15
|
+
vue.provide(ErrorEngineKey, engine);
|
|
16
|
+
}
|
|
17
|
+
function useErrorEngine() {
|
|
18
|
+
const engine = vue.inject(ErrorEngineKey, null);
|
|
19
|
+
if (!engine && process.env["NODE_ENV"] === "development") {
|
|
20
|
+
console.error("[gracefulerrors] useErrorEngine called outside of a provider (ErrorEngineKey not found).");
|
|
21
|
+
}
|
|
22
|
+
return engine;
|
|
23
|
+
}
|
|
24
|
+
function useFieldError(field) {
|
|
25
|
+
const engine = useErrorEngine();
|
|
26
|
+
const error = vue.ref(null);
|
|
27
|
+
let unsubscribe = null;
|
|
28
|
+
vue.onMounted(() => {
|
|
29
|
+
if (!engine) return;
|
|
30
|
+
unsubscribe = engine.subscribe((event) => {
|
|
31
|
+
if (event.type === "ERROR_ADDED" && event.action === "inline") {
|
|
32
|
+
if (event.error.context?.field === field) {
|
|
33
|
+
error.value = event.error;
|
|
34
|
+
}
|
|
35
|
+
} else if (event.type === "ERROR_CLEARED") {
|
|
36
|
+
if (error.value?.code === event.code) {
|
|
37
|
+
error.value = null;
|
|
38
|
+
}
|
|
39
|
+
} else if (event.type === "ALL_CLEARED") {
|
|
40
|
+
error.value = null;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
vue.onUnmounted(() => {
|
|
45
|
+
unsubscribe?.();
|
|
46
|
+
});
|
|
47
|
+
return { error };
|
|
48
|
+
}
|
|
49
|
+
var ErrorBoundaryWithEngine = vue.defineComponent({
|
|
50
|
+
name: "ErrorBoundaryWithEngine",
|
|
51
|
+
props: {
|
|
52
|
+
fallback: {
|
|
53
|
+
type: [String, Object],
|
|
54
|
+
default: null
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
setup(props, { slots }) {
|
|
58
|
+
const engine = useErrorEngine();
|
|
59
|
+
const hasError = vue.ref(false);
|
|
60
|
+
vue.onErrorCaptured((err) => {
|
|
61
|
+
engine?.handle(err);
|
|
62
|
+
hasError.value = true;
|
|
63
|
+
return false;
|
|
64
|
+
});
|
|
65
|
+
return () => {
|
|
66
|
+
if (hasError.value) {
|
|
67
|
+
if (slots.fallback) return slots.fallback();
|
|
68
|
+
if (props.fallback) {
|
|
69
|
+
return typeof props.fallback === "string" ? vue.h("span", props.fallback) : props.fallback;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return slots.default?.();
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
exports.ErrorBoundaryWithEngine = ErrorBoundaryWithEngine;
|
|
79
|
+
exports.ErrorEngineKey = ErrorEngineKey;
|
|
80
|
+
exports.createErrorEnginePlugin = createErrorEnginePlugin;
|
|
81
|
+
exports.provideErrorEngine = provideErrorEngine;
|
|
82
|
+
exports.useErrorEngine = useErrorEngine;
|
|
83
|
+
exports.useFieldError = useFieldError;
|
|
84
|
+
//# sourceMappingURL=vue.cjs.map
|
|
85
|
+
//# sourceMappingURL=vue.cjs.map
|
package/dist/vue.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vue.ts"],"names":["provide","inject","ref","onMounted","onUnmounted","defineComponent","onErrorCaptured","h"],"mappings":"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","file":"vue.cjs","sourcesContent":["import {\n inject,\n provide,\n ref,\n onMounted,\n onUnmounted,\n defineComponent,\n h,\n onErrorCaptured,\n} from 'vue'\nimport type { InjectionKey, Plugin, Ref, VNode } from 'vue'\nimport type { ErrorEngine, AppError, StateListener } from './types'\n\nexport const ErrorEngineKey: InjectionKey<ErrorEngine> = Symbol('ErrorEngine')\n\nexport function createErrorEnginePlugin<TCode extends string = string>(\n engine: ErrorEngine<TCode>\n): Plugin {\n return {\n install(app) {\n app.provide(ErrorEngineKey, engine)\n },\n }\n}\n\nexport function provideErrorEngine<TCode extends string = string>(\n engine: ErrorEngine<TCode>\n): void {\n provide(ErrorEngineKey, engine)\n}\n\nexport function useErrorEngine<TCode extends string = string>(): ErrorEngine<TCode> | null {\n const engine = inject(ErrorEngineKey, null)\n if (!engine && process.env['NODE_ENV'] === 'development') {\n console.error('[gracefulerrors] useErrorEngine called outside of a provider (ErrorEngineKey not found).')\n }\n return engine as ErrorEngine<TCode> | null\n}\n\nexport function useFieldError<TField extends string = string>(\n field: TField\n): { error: Ref<AppError<string, TField> | null> } {\n const engine = useErrorEngine()\n const error = ref<AppError<string, TField> | null>(null) as Ref<AppError<string, TField> | null>\n let unsubscribe: (() => void) | null = null\n\n onMounted(() => {\n if (!engine) return\n unsubscribe = engine.subscribe((event: Parameters<StateListener>[0]) => {\n if (event.type === 'ERROR_ADDED' && event.action === 'inline') {\n if (event.error.context?.field === field) {\n error.value = event.error as AppError<string, TField>\n }\n } else if (event.type === 'ERROR_CLEARED') {\n if (error.value?.code === event.code) {\n error.value = null\n }\n } else if (event.type === 'ALL_CLEARED') {\n error.value = null\n }\n })\n })\n\n onUnmounted(() => {\n unsubscribe?.()\n })\n\n return { error }\n}\n\nexport const ErrorBoundaryWithEngine = defineComponent({\n name: 'ErrorBoundaryWithEngine',\n props: {\n fallback: {\n type: [String, Object] as unknown as () => string | VNode,\n default: null,\n },\n },\n setup(props, { slots }) {\n const engine = useErrorEngine()\n const hasError = ref(false)\n\n onErrorCaptured((err: unknown) => {\n engine?.handle(err)\n hasError.value = true\n return false\n })\n\n return () => {\n if (hasError.value) {\n if (slots.fallback) return slots.fallback()\n if (props.fallback) {\n return typeof props.fallback === 'string'\n ? h('span', props.fallback)\n : (props.fallback as VNode)\n }\n return null\n }\n return slots.default?.()\n }\n },\n})\n"]}
|
package/dist/vue.d.cts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as vue from 'vue';
|
|
2
|
+
import { VNode, InjectionKey, Plugin, Ref } from 'vue';
|
|
3
|
+
import { a as ErrorEngine, A as AppError } from './types-CsPmpcbL.cjs';
|
|
4
|
+
|
|
5
|
+
declare const ErrorEngineKey: InjectionKey<ErrorEngine>;
|
|
6
|
+
declare function createErrorEnginePlugin<TCode extends string = string>(engine: ErrorEngine<TCode>): Plugin;
|
|
7
|
+
declare function provideErrorEngine<TCode extends string = string>(engine: ErrorEngine<TCode>): void;
|
|
8
|
+
declare function useErrorEngine<TCode extends string = string>(): ErrorEngine<TCode> | null;
|
|
9
|
+
declare function useFieldError<TField extends string = string>(field: TField): {
|
|
10
|
+
error: Ref<AppError<string, TField> | null>;
|
|
11
|
+
};
|
|
12
|
+
declare const ErrorBoundaryWithEngine: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
13
|
+
fallback: {
|
|
14
|
+
type: () => string | VNode;
|
|
15
|
+
default: null;
|
|
16
|
+
};
|
|
17
|
+
}>, () => VNode<vue.RendererNode, vue.RendererElement, {
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}> | VNode<vue.RendererNode, vue.RendererElement, {
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}>[] | null | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
22
|
+
fallback: {
|
|
23
|
+
type: () => string | VNode;
|
|
24
|
+
default: null;
|
|
25
|
+
};
|
|
26
|
+
}>> & Readonly<{}>, {
|
|
27
|
+
fallback: string | VNode<vue.RendererNode, vue.RendererElement, {
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
}>;
|
|
30
|
+
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
31
|
+
|
|
32
|
+
export { ErrorBoundaryWithEngine, ErrorEngineKey, createErrorEnginePlugin, provideErrorEngine, useErrorEngine, useFieldError };
|
package/dist/vue.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as vue from 'vue';
|
|
2
|
+
import { VNode, InjectionKey, Plugin, Ref } from 'vue';
|
|
3
|
+
import { a as ErrorEngine, A as AppError } from './types-CsPmpcbL.js';
|
|
4
|
+
|
|
5
|
+
declare const ErrorEngineKey: InjectionKey<ErrorEngine>;
|
|
6
|
+
declare function createErrorEnginePlugin<TCode extends string = string>(engine: ErrorEngine<TCode>): Plugin;
|
|
7
|
+
declare function provideErrorEngine<TCode extends string = string>(engine: ErrorEngine<TCode>): void;
|
|
8
|
+
declare function useErrorEngine<TCode extends string = string>(): ErrorEngine<TCode> | null;
|
|
9
|
+
declare function useFieldError<TField extends string = string>(field: TField): {
|
|
10
|
+
error: Ref<AppError<string, TField> | null>;
|
|
11
|
+
};
|
|
12
|
+
declare const ErrorBoundaryWithEngine: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
13
|
+
fallback: {
|
|
14
|
+
type: () => string | VNode;
|
|
15
|
+
default: null;
|
|
16
|
+
};
|
|
17
|
+
}>, () => VNode<vue.RendererNode, vue.RendererElement, {
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}> | VNode<vue.RendererNode, vue.RendererElement, {
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}>[] | null | undefined, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
22
|
+
fallback: {
|
|
23
|
+
type: () => string | VNode;
|
|
24
|
+
default: null;
|
|
25
|
+
};
|
|
26
|
+
}>> & Readonly<{}>, {
|
|
27
|
+
fallback: string | VNode<vue.RendererNode, vue.RendererElement, {
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
}>;
|
|
30
|
+
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
31
|
+
|
|
32
|
+
export { ErrorBoundaryWithEngine, ErrorEngineKey, createErrorEnginePlugin, provideErrorEngine, useErrorEngine, useFieldError };
|
package/dist/vue.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { defineComponent, ref, onErrorCaptured, h, inject, provide, onMounted, onUnmounted } from 'vue';
|
|
2
|
+
|
|
3
|
+
// src/vue.ts
|
|
4
|
+
var ErrorEngineKey = /* @__PURE__ */ Symbol("ErrorEngine");
|
|
5
|
+
function createErrorEnginePlugin(engine) {
|
|
6
|
+
return {
|
|
7
|
+
install(app) {
|
|
8
|
+
app.provide(ErrorEngineKey, engine);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function provideErrorEngine(engine) {
|
|
13
|
+
provide(ErrorEngineKey, engine);
|
|
14
|
+
}
|
|
15
|
+
function useErrorEngine() {
|
|
16
|
+
const engine = inject(ErrorEngineKey, null);
|
|
17
|
+
if (!engine && process.env["NODE_ENV"] === "development") {
|
|
18
|
+
console.error("[gracefulerrors] useErrorEngine called outside of a provider (ErrorEngineKey not found).");
|
|
19
|
+
}
|
|
20
|
+
return engine;
|
|
21
|
+
}
|
|
22
|
+
function useFieldError(field) {
|
|
23
|
+
const engine = useErrorEngine();
|
|
24
|
+
const error = ref(null);
|
|
25
|
+
let unsubscribe = null;
|
|
26
|
+
onMounted(() => {
|
|
27
|
+
if (!engine) return;
|
|
28
|
+
unsubscribe = engine.subscribe((event) => {
|
|
29
|
+
if (event.type === "ERROR_ADDED" && event.action === "inline") {
|
|
30
|
+
if (event.error.context?.field === field) {
|
|
31
|
+
error.value = event.error;
|
|
32
|
+
}
|
|
33
|
+
} else if (event.type === "ERROR_CLEARED") {
|
|
34
|
+
if (error.value?.code === event.code) {
|
|
35
|
+
error.value = null;
|
|
36
|
+
}
|
|
37
|
+
} else if (event.type === "ALL_CLEARED") {
|
|
38
|
+
error.value = null;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
onUnmounted(() => {
|
|
43
|
+
unsubscribe?.();
|
|
44
|
+
});
|
|
45
|
+
return { error };
|
|
46
|
+
}
|
|
47
|
+
var ErrorBoundaryWithEngine = defineComponent({
|
|
48
|
+
name: "ErrorBoundaryWithEngine",
|
|
49
|
+
props: {
|
|
50
|
+
fallback: {
|
|
51
|
+
type: [String, Object],
|
|
52
|
+
default: null
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
setup(props, { slots }) {
|
|
56
|
+
const engine = useErrorEngine();
|
|
57
|
+
const hasError = ref(false);
|
|
58
|
+
onErrorCaptured((err) => {
|
|
59
|
+
engine?.handle(err);
|
|
60
|
+
hasError.value = true;
|
|
61
|
+
return false;
|
|
62
|
+
});
|
|
63
|
+
return () => {
|
|
64
|
+
if (hasError.value) {
|
|
65
|
+
if (slots.fallback) return slots.fallback();
|
|
66
|
+
if (props.fallback) {
|
|
67
|
+
return typeof props.fallback === "string" ? h("span", props.fallback) : props.fallback;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return slots.default?.();
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
export { ErrorBoundaryWithEngine, ErrorEngineKey, createErrorEnginePlugin, provideErrorEngine, useErrorEngine, useFieldError };
|
|
77
|
+
//# sourceMappingURL=vue.js.map
|
|
78
|
+
//# sourceMappingURL=vue.js.map
|
package/dist/vue.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vue.ts"],"names":[],"mappings":"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","file":"vue.js","sourcesContent":["import {\n inject,\n provide,\n ref,\n onMounted,\n onUnmounted,\n defineComponent,\n h,\n onErrorCaptured,\n} from 'vue'\nimport type { InjectionKey, Plugin, Ref, VNode } from 'vue'\nimport type { ErrorEngine, AppError, StateListener } from './types'\n\nexport const ErrorEngineKey: InjectionKey<ErrorEngine> = Symbol('ErrorEngine')\n\nexport function createErrorEnginePlugin<TCode extends string = string>(\n engine: ErrorEngine<TCode>\n): Plugin {\n return {\n install(app) {\n app.provide(ErrorEngineKey, engine)\n },\n }\n}\n\nexport function provideErrorEngine<TCode extends string = string>(\n engine: ErrorEngine<TCode>\n): void {\n provide(ErrorEngineKey, engine)\n}\n\nexport function useErrorEngine<TCode extends string = string>(): ErrorEngine<TCode> | null {\n const engine = inject(ErrorEngineKey, null)\n if (!engine && process.env['NODE_ENV'] === 'development') {\n console.error('[gracefulerrors] useErrorEngine called outside of a provider (ErrorEngineKey not found).')\n }\n return engine as ErrorEngine<TCode> | null\n}\n\nexport function useFieldError<TField extends string = string>(\n field: TField\n): { error: Ref<AppError<string, TField> | null> } {\n const engine = useErrorEngine()\n const error = ref<AppError<string, TField> | null>(null) as Ref<AppError<string, TField> | null>\n let unsubscribe: (() => void) | null = null\n\n onMounted(() => {\n if (!engine) return\n unsubscribe = engine.subscribe((event: Parameters<StateListener>[0]) => {\n if (event.type === 'ERROR_ADDED' && event.action === 'inline') {\n if (event.error.context?.field === field) {\n error.value = event.error as AppError<string, TField>\n }\n } else if (event.type === 'ERROR_CLEARED') {\n if (error.value?.code === event.code) {\n error.value = null\n }\n } else if (event.type === 'ALL_CLEARED') {\n error.value = null\n }\n })\n })\n\n onUnmounted(() => {\n unsubscribe?.()\n })\n\n return { error }\n}\n\nexport const ErrorBoundaryWithEngine = defineComponent({\n name: 'ErrorBoundaryWithEngine',\n props: {\n fallback: {\n type: [String, Object] as unknown as () => string | VNode,\n default: null,\n },\n },\n setup(props, { slots }) {\n const engine = useErrorEngine()\n const hasError = ref(false)\n\n onErrorCaptured((err: unknown) => {\n engine?.handle(err)\n hasError.value = true\n return false\n })\n\n return () => {\n if (hasError.value) {\n if (slots.fallback) return slots.fallback()\n if (props.fallback) {\n return typeof props.fallback === 'string'\n ? h('span', props.fallback)\n : (props.fallback as VNode)\n }\n return null\n }\n return slots.default?.()\n }\n },\n})\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gracefulerrors",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Transform technical errors into consistent, user-friendly experiences",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,6 +24,11 @@
|
|
|
24
24
|
"types": "./dist/internal.d.ts",
|
|
25
25
|
"import": "./dist/internal.mjs",
|
|
26
26
|
"require": "./dist/internal.cjs"
|
|
27
|
+
},
|
|
28
|
+
"./vue": {
|
|
29
|
+
"types": "./dist/vue.d.ts",
|
|
30
|
+
"import": "./dist/vue.mjs",
|
|
31
|
+
"require": "./dist/vue.cjs"
|
|
27
32
|
}
|
|
28
33
|
},
|
|
29
34
|
"main": "./dist/index.cjs",
|
|
@@ -45,7 +50,8 @@
|
|
|
45
50
|
"peerDependencies": {
|
|
46
51
|
"react": ">=18",
|
|
47
52
|
"react-dom": ">=18",
|
|
48
|
-
"sonner": ">=1"
|
|
53
|
+
"sonner": ">=1",
|
|
54
|
+
"vue": ">=3"
|
|
49
55
|
},
|
|
50
56
|
"peerDependenciesMeta": {
|
|
51
57
|
"sonner": {
|
|
@@ -56,6 +62,9 @@
|
|
|
56
62
|
},
|
|
57
63
|
"react-dom": {
|
|
58
64
|
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"vue": {
|
|
67
|
+
"optional": true
|
|
59
68
|
}
|
|
60
69
|
},
|
|
61
70
|
"tsd": {
|
|
@@ -68,6 +77,7 @@
|
|
|
68
77
|
"@types/react": "^18.0.0",
|
|
69
78
|
"@types/react-dom": "^18.0.0",
|
|
70
79
|
"@vitest/coverage-v8": "^1.0.0",
|
|
80
|
+
"@vue/test-utils": "^2.4.6",
|
|
71
81
|
"jsdom": "^24.0.0",
|
|
72
82
|
"react": "^18.0.0",
|
|
73
83
|
"react-dom": "^18.0.0",
|
|
@@ -75,6 +85,7 @@
|
|
|
75
85
|
"tsd": "^0.31.0",
|
|
76
86
|
"tsup": "^8.0.0",
|
|
77
87
|
"typescript": "^5.0.0",
|
|
78
|
-
"vitest": "^1.0.0"
|
|
88
|
+
"vitest": "^1.0.0",
|
|
89
|
+
"vue": "^3.5.32"
|
|
79
90
|
}
|
|
80
91
|
}
|