@n8n/composables 1.23.0 → 1.24.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 (39) hide show
  1. package/dist/notification.d.cts +24 -0
  2. package/dist/notification.d.mts +24 -0
  3. package/dist/registries/telemetryRegistry.cjs +5 -0
  4. package/dist/registries/telemetryRegistry.d.cts +2 -0
  5. package/dist/registries/telemetryRegistry.d.mts +2 -0
  6. package/dist/registries/telemetryRegistry.mjs +3 -0
  7. package/dist/telemetryRegistry.cjs +42 -0
  8. package/dist/telemetryRegistry.cjs.map +1 -0
  9. package/dist/telemetryRegistry.d.cts +42 -0
  10. package/dist/telemetryRegistry.d.mts +42 -0
  11. package/dist/telemetryRegistry.mjs +24 -0
  12. package/dist/telemetryRegistry.mjs.map +1 -0
  13. package/dist/types/notification.cjs +0 -0
  14. package/dist/types/notification.d.cts +2 -0
  15. package/dist/types/notification.d.mts +2 -0
  16. package/dist/types/notification.mjs +1 -0
  17. package/dist/useDeviceSupport.d.cts +2 -2
  18. package/dist/useDeviceSupport.d.mts +2 -2
  19. package/dist/useStorage.cjs +13 -0
  20. package/dist/useStorage.cjs.map +1 -0
  21. package/dist/useStorage.d.cts +7 -0
  22. package/dist/useStorage.d.mts +7 -0
  23. package/dist/useStorage.mjs +12 -0
  24. package/dist/useStorage.mjs.map +1 -0
  25. package/dist/useTelemetry.cjs +1 -2
  26. package/dist/useTelemetry.d.cts +2 -37
  27. package/dist/useTelemetry.d.mts +2 -37
  28. package/dist/useTelemetry.mjs +3 -2
  29. package/dist/useTelemetry2.cjs +5 -31
  30. package/dist/useTelemetry2.cjs.map +1 -1
  31. package/dist/useTelemetry2.mjs +6 -20
  32. package/dist/useTelemetry2.mjs.map +1 -1
  33. package/dist/useToast.cjs +20 -25
  34. package/dist/useToast.cjs.map +1 -1
  35. package/dist/useToast.d.cts +3 -6
  36. package/dist/useToast.d.mts +3 -6
  37. package/dist/useToast.mjs +21 -26
  38. package/dist/useToast.mjs.map +1 -1
  39. package/package.json +9 -10
@@ -0,0 +1,24 @@
1
+ import { Component, VNode } from "vue";
2
+
3
+ //#region src/types/notification.d.ts
4
+ type NotificationType = '' | 'success' | 'warning' | 'error' | 'info';
5
+ type NotificationPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
6
+ interface NotificationOptions {
7
+ message: string | VNode;
8
+ title?: string;
9
+ type?: NotificationType;
10
+ icon?: string | Component;
11
+ customClass?: string;
12
+ duration?: number;
13
+ position?: NotificationPosition;
14
+ showClose?: boolean;
15
+ dangerouslyUseHTMLString?: boolean;
16
+ offset?: number;
17
+ appendTo?: HTMLElement | string;
18
+ zIndex?: number;
19
+ onClick?: () => void;
20
+ onClose?: () => void;
21
+ }
22
+ //#endregion
23
+ export { NotificationPosition as n, NotificationType as r, NotificationOptions as t };
24
+ //# sourceMappingURL=notification.d.cts.map
@@ -0,0 +1,24 @@
1
+ import { Component, VNode } from "vue";
2
+
3
+ //#region src/types/notification.d.ts
4
+ type NotificationType = '' | 'success' | 'warning' | 'error' | 'info';
5
+ type NotificationPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
6
+ interface NotificationOptions {
7
+ message: string | VNode;
8
+ title?: string;
9
+ type?: NotificationType;
10
+ icon?: string | Component;
11
+ customClass?: string;
12
+ duration?: number;
13
+ position?: NotificationPosition;
14
+ showClose?: boolean;
15
+ dangerouslyUseHTMLString?: boolean;
16
+ offset?: number;
17
+ appendTo?: HTMLElement | string;
18
+ zIndex?: number;
19
+ onClick?: () => void;
20
+ onClose?: () => void;
21
+ }
22
+ //#endregion
23
+ export { NotificationPosition as n, NotificationType as r, NotificationOptions as t };
24
+ //# sourceMappingURL=notification.d.mts.map
@@ -0,0 +1,5 @@
1
+ const require_telemetryRegistry = require('../telemetryRegistry.cjs');
2
+
3
+ exports.TelemetryKey = require_telemetryRegistry.TelemetryKey;
4
+ exports.getRegisteredTelemetry = require_telemetryRegistry.getRegisteredTelemetry;
5
+ exports.setTelemetry = require_telemetryRegistry.setTelemetry;
@@ -0,0 +1,2 @@
1
+ import { a as getRegisteredTelemetry, i as TelemetryNodeParameterChange, n as TelemetryIdentifyOptions, o as setTelemetry, r as TelemetryKey, t as Telemetry } from "../telemetryRegistry.cjs";
2
+ export { Telemetry, TelemetryIdentifyOptions, TelemetryKey, TelemetryNodeParameterChange, getRegisteredTelemetry, setTelemetry };
@@ -0,0 +1,2 @@
1
+ import { a as getRegisteredTelemetry, i as TelemetryNodeParameterChange, n as TelemetryIdentifyOptions, o as setTelemetry, r as TelemetryKey, t as Telemetry } from "../telemetryRegistry.mjs";
2
+ export { Telemetry, TelemetryIdentifyOptions, TelemetryKey, TelemetryNodeParameterChange, getRegisteredTelemetry, setTelemetry };
@@ -0,0 +1,3 @@
1
+ import { n as getRegisteredTelemetry, r as setTelemetry, t as TelemetryKey } from "../telemetryRegistry.mjs";
2
+
3
+ export { TelemetryKey, getRegisteredTelemetry, setTelemetry };
@@ -0,0 +1,42 @@
1
+
2
+ //#region src/registries/telemetryRegistry.ts
3
+ /**
4
+ * Injection key for the telemetry instance. The application provides it at
5
+ * bootstrap; components may override it (e.g. a pop-out window with its own
6
+ * instance). `useTelemetry` reads it when called inside an injection context.
7
+ */
8
+ const TelemetryKey = Symbol("Telemetry");
9
+ let registeredTelemetry;
10
+ /**
11
+ * Register the application's telemetry instance. Called once at bootstrap by
12
+ * the editor-ui telemetry plugin so package-side `useTelemetry` can return it
13
+ * from any context, including outside of component setup.
14
+ */
15
+ function setTelemetry(instance) {
16
+ registeredTelemetry = instance;
17
+ }
18
+ /** The instance registered via {@link setTelemetry}, if bootstrap has run. */
19
+ function getRegisteredTelemetry() {
20
+ return registeredTelemetry;
21
+ }
22
+
23
+ //#endregion
24
+ Object.defineProperty(exports, 'TelemetryKey', {
25
+ enumerable: true,
26
+ get: function () {
27
+ return TelemetryKey;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, 'getRegisteredTelemetry', {
31
+ enumerable: true,
32
+ get: function () {
33
+ return getRegisteredTelemetry;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, 'setTelemetry', {
37
+ enumerable: true,
38
+ get: function () {
39
+ return setTelemetry;
40
+ }
41
+ });
42
+ //# sourceMappingURL=telemetryRegistry.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetryRegistry.cjs","names":["TelemetryKey: InjectionKey<Telemetry>","registeredTelemetry: Telemetry | undefined"],"sources":["../src/registries/telemetryRegistry.ts"],"sourcesContent":["import type { ITelemetrySettings } from '@n8n/api-types';\nimport type { InferTelemetryProps, TelemetryEventDef } from '@n8n/telemetry';\nimport type { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from 'n8n-workflow';\nimport type { InjectionKey } from 'vue';\nimport type { RouteLocation } from 'vue-router';\n\nexport type TelemetryIdentifyOptions = {\n\tinstanceId: string;\n\tuserId?: string;\n\tprojectId?: string;\n\tversionCli?: string;\n\tuserRole?: string;\n};\n\n/**\n * Shape of a node-parameter change tracked by telemetry. Structurally mirrors\n * editor-ui's `IUpdateInformation`; declared here so the telemetry contract\n * carries no dependency back into the application package.\n */\nexport interface TelemetryNodeParameterChange {\n\tname: string;\n\tkey?: string;\n\tvalue: NodeParameterValueType;\n\tnode?: string;\n\toldValue?: string | number;\n\ttype?: 'optionsOrderChanged';\n}\n\n/**\n * The telemetry contract consumed across the frontend.\n *\n * This package owns the *type* only; the concrete implementation lives in the\n * application (`editor-ui`'s telemetry plugin) and is registered at bootstrap\n * via {@link setTelemetry} / provided through {@link TelemetryKey}. Keeping the\n * contract here lets `useTelemetry` return a fully-typed instance without the\n * package importing application code.\n */\nexport interface Telemetry {\n\tinit(\n\t\ttelemetrySettings: ITelemetrySettings,\n\t\toptions: TelemetryIdentifyOptions & { versionCli: string },\n\t): void;\n\tidentify(options: TelemetryIdentifyOptions): void;\n\ttrack<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;\n\ttrack(event: string, properties?: ITelemetryTrackProperties): void;\n\tpage(route: RouteLocation): void;\n\treset(): void;\n\tflushPageEvents(): void;\n\ttrackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;\n}\n\n/**\n * Injection key for the telemetry instance. The application provides it at\n * bootstrap; components may override it (e.g. a pop-out window with its own\n * instance). `useTelemetry` reads it when called inside an injection context.\n */\nexport const TelemetryKey: InjectionKey<Telemetry> = Symbol('Telemetry');\n\nlet registeredTelemetry: Telemetry | undefined;\n\n/**\n * Register the application's telemetry instance. Called once at bootstrap by\n * the editor-ui telemetry plugin so package-side `useTelemetry` can return it\n * from any context, including outside of component setup.\n */\nexport function setTelemetry(instance: Telemetry | undefined): void {\n\tregisteredTelemetry = instance;\n}\n\n/** The instance registered via {@link setTelemetry}, if bootstrap has run. */\nexport function getRegisteredTelemetry(): Telemetry | undefined {\n\treturn registeredTelemetry;\n}\n"],"mappings":";;;;;;;AA0DA,MAAaA,eAAwC,OAAO,YAAY;AAExE,IAAIC;;;;;;AAOJ,SAAgB,aAAa,UAAuC;AACnE,uBAAsB;;;AAIvB,SAAgB,yBAAgD;AAC/D,QAAO"}
@@ -0,0 +1,42 @@
1
+ import { InjectionKey } from "vue";
2
+ import { ITelemetrySettings } from "@n8n/api-types";
3
+ import { InferTelemetryProps, TelemetryEventDef } from "@n8n/telemetry";
4
+ import { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from "n8n-workflow";
5
+ import { RouteLocation } from "vue-router";
6
+
7
+ //#region src/registries/telemetryRegistry.d.ts
8
+ type TelemetryIdentifyOptions = {
9
+ instanceId: string;
10
+ userId?: string;
11
+ projectId?: string;
12
+ versionCli?: string;
13
+ userRole?: string;
14
+ };
15
+ interface TelemetryNodeParameterChange {
16
+ name: string;
17
+ key?: string;
18
+ value: NodeParameterValueType;
19
+ node?: string;
20
+ oldValue?: string | number;
21
+ type?: 'optionsOrderChanged';
22
+ }
23
+ interface Telemetry {
24
+ init(telemetrySettings: ITelemetrySettings, options: TelemetryIdentifyOptions & {
25
+ versionCli: string;
26
+ }): void;
27
+ identify(options: TelemetryIdentifyOptions): void;
28
+ track<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;
29
+ track(event: string, properties?: ITelemetryTrackProperties): void;
30
+ page(route: RouteLocation): void;
31
+ reset(): void;
32
+ flushPageEvents(): void;
33
+ trackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;
34
+ trackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;
35
+ trackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;
36
+ }
37
+ declare const TelemetryKey: InjectionKey<Telemetry>;
38
+ declare function setTelemetry(instance: Telemetry | undefined): void;
39
+ declare function getRegisteredTelemetry(): Telemetry | undefined;
40
+ //#endregion
41
+ export { getRegisteredTelemetry as a, TelemetryNodeParameterChange as i, TelemetryIdentifyOptions as n, setTelemetry as o, TelemetryKey as r, Telemetry as t };
42
+ //# sourceMappingURL=telemetryRegistry.d.cts.map
@@ -0,0 +1,42 @@
1
+ import { InjectionKey } from "vue";
2
+ import { RouteLocation } from "vue-router";
3
+ import { ITelemetrySettings } from "@n8n/api-types";
4
+ import { InferTelemetryProps, TelemetryEventDef } from "@n8n/telemetry";
5
+ import { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from "n8n-workflow";
6
+
7
+ //#region src/registries/telemetryRegistry.d.ts
8
+ type TelemetryIdentifyOptions = {
9
+ instanceId: string;
10
+ userId?: string;
11
+ projectId?: string;
12
+ versionCli?: string;
13
+ userRole?: string;
14
+ };
15
+ interface TelemetryNodeParameterChange {
16
+ name: string;
17
+ key?: string;
18
+ value: NodeParameterValueType;
19
+ node?: string;
20
+ oldValue?: string | number;
21
+ type?: 'optionsOrderChanged';
22
+ }
23
+ interface Telemetry {
24
+ init(telemetrySettings: ITelemetrySettings, options: TelemetryIdentifyOptions & {
25
+ versionCli: string;
26
+ }): void;
27
+ identify(options: TelemetryIdentifyOptions): void;
28
+ track<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;
29
+ track(event: string, properties?: ITelemetryTrackProperties): void;
30
+ page(route: RouteLocation): void;
31
+ reset(): void;
32
+ flushPageEvents(): void;
33
+ trackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;
34
+ trackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;
35
+ trackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;
36
+ }
37
+ declare const TelemetryKey: InjectionKey<Telemetry>;
38
+ declare function setTelemetry(instance: Telemetry | undefined): void;
39
+ declare function getRegisteredTelemetry(): Telemetry | undefined;
40
+ //#endregion
41
+ export { getRegisteredTelemetry as a, TelemetryNodeParameterChange as i, TelemetryIdentifyOptions as n, setTelemetry as o, TelemetryKey as r, Telemetry as t };
42
+ //# sourceMappingURL=telemetryRegistry.d.mts.map
@@ -0,0 +1,24 @@
1
+ //#region src/registries/telemetryRegistry.ts
2
+ /**
3
+ * Injection key for the telemetry instance. The application provides it at
4
+ * bootstrap; components may override it (e.g. a pop-out window with its own
5
+ * instance). `useTelemetry` reads it when called inside an injection context.
6
+ */
7
+ const TelemetryKey = Symbol("Telemetry");
8
+ let registeredTelemetry;
9
+ /**
10
+ * Register the application's telemetry instance. Called once at bootstrap by
11
+ * the editor-ui telemetry plugin so package-side `useTelemetry` can return it
12
+ * from any context, including outside of component setup.
13
+ */
14
+ function setTelemetry(instance) {
15
+ registeredTelemetry = instance;
16
+ }
17
+ /** The instance registered via {@link setTelemetry}, if bootstrap has run. */
18
+ function getRegisteredTelemetry() {
19
+ return registeredTelemetry;
20
+ }
21
+
22
+ //#endregion
23
+ export { getRegisteredTelemetry as n, setTelemetry as r, TelemetryKey as t };
24
+ //# sourceMappingURL=telemetryRegistry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetryRegistry.mjs","names":["TelemetryKey: InjectionKey<Telemetry>","registeredTelemetry: Telemetry | undefined"],"sources":["../src/registries/telemetryRegistry.ts"],"sourcesContent":["import type { ITelemetrySettings } from '@n8n/api-types';\nimport type { InferTelemetryProps, TelemetryEventDef } from '@n8n/telemetry';\nimport type { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from 'n8n-workflow';\nimport type { InjectionKey } from 'vue';\nimport type { RouteLocation } from 'vue-router';\n\nexport type TelemetryIdentifyOptions = {\n\tinstanceId: string;\n\tuserId?: string;\n\tprojectId?: string;\n\tversionCli?: string;\n\tuserRole?: string;\n};\n\n/**\n * Shape of a node-parameter change tracked by telemetry. Structurally mirrors\n * editor-ui's `IUpdateInformation`; declared here so the telemetry contract\n * carries no dependency back into the application package.\n */\nexport interface TelemetryNodeParameterChange {\n\tname: string;\n\tkey?: string;\n\tvalue: NodeParameterValueType;\n\tnode?: string;\n\toldValue?: string | number;\n\ttype?: 'optionsOrderChanged';\n}\n\n/**\n * The telemetry contract consumed across the frontend.\n *\n * This package owns the *type* only; the concrete implementation lives in the\n * application (`editor-ui`'s telemetry plugin) and is registered at bootstrap\n * via {@link setTelemetry} / provided through {@link TelemetryKey}. Keeping the\n * contract here lets `useTelemetry` return a fully-typed instance without the\n * package importing application code.\n */\nexport interface Telemetry {\n\tinit(\n\t\ttelemetrySettings: ITelemetrySettings,\n\t\toptions: TelemetryIdentifyOptions & { versionCli: string },\n\t): void;\n\tidentify(options: TelemetryIdentifyOptions): void;\n\ttrack<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;\n\ttrack(event: string, properties?: ITelemetryTrackProperties): void;\n\tpage(route: RouteLocation): void;\n\treset(): void;\n\tflushPageEvents(): void;\n\ttrackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;\n}\n\n/**\n * Injection key for the telemetry instance. The application provides it at\n * bootstrap; components may override it (e.g. a pop-out window with its own\n * instance). `useTelemetry` reads it when called inside an injection context.\n */\nexport const TelemetryKey: InjectionKey<Telemetry> = Symbol('Telemetry');\n\nlet registeredTelemetry: Telemetry | undefined;\n\n/**\n * Register the application's telemetry instance. Called once at bootstrap by\n * the editor-ui telemetry plugin so package-side `useTelemetry` can return it\n * from any context, including outside of component setup.\n */\nexport function setTelemetry(instance: Telemetry | undefined): void {\n\tregisteredTelemetry = instance;\n}\n\n/** The instance registered via {@link setTelemetry}, if bootstrap has run. */\nexport function getRegisteredTelemetry(): Telemetry | undefined {\n\treturn registeredTelemetry;\n}\n"],"mappings":";;;;;;AA0DA,MAAaA,eAAwC,OAAO,YAAY;AAExE,IAAIC;;;;;;AAOJ,SAAgB,aAAa,UAAuC;AACnE,uBAAsB;;;AAIvB,SAAgB,yBAAgD;AAC/D,QAAO"}
File without changes
@@ -0,0 +1,2 @@
1
+ import { n as NotificationPosition, r as NotificationType, t as NotificationOptions } from "../notification.cjs";
2
+ export { NotificationOptions, NotificationPosition, NotificationType };
@@ -0,0 +1,2 @@
1
+ import { n as NotificationPosition, r as NotificationType, t as NotificationOptions } from "../notification.mjs";
2
+ export { NotificationOptions, NotificationPosition, NotificationType };
@@ -0,0 +1 @@
1
+ export { };
@@ -1,4 +1,4 @@
1
- import * as vue3 from "vue";
1
+ import * as vue0 from "vue";
2
2
 
3
3
  //#region src/useDeviceSupport.d.ts
4
4
  declare function useDeviceSupport(): {
@@ -9,7 +9,7 @@ declare function useDeviceSupport(): {
9
9
  isMacOs: boolean;
10
10
  isMobileDevice: boolean;
11
11
  controlKeyCode: string;
12
- controlKeyText: vue3.ComputedRef<"⌘" | "Ctrl">;
12
+ controlKeyText: vue0.ComputedRef<"⌘" | "Ctrl">;
13
13
  isCtrlKeyPressed: (e: MouseEvent | KeyboardEvent) => boolean;
14
14
  };
15
15
  //#endregion
@@ -1,4 +1,4 @@
1
- import * as vue0 from "vue";
1
+ import * as vue3 from "vue";
2
2
 
3
3
  //#region src/useDeviceSupport.d.ts
4
4
  declare function useDeviceSupport(): {
@@ -9,7 +9,7 @@ declare function useDeviceSupport(): {
9
9
  isMacOs: boolean;
10
10
  isMobileDevice: boolean;
11
11
  controlKeyCode: string;
12
- controlKeyText: vue0.ComputedRef<"⌘" | "Ctrl">;
12
+ controlKeyText: vue3.ComputedRef<"⌘" | "Ctrl">;
13
13
  isCtrlKeyPressed: (e: MouseEvent | KeyboardEvent) => boolean;
14
14
  };
15
15
  //#endregion
@@ -0,0 +1,13 @@
1
+ const require_useDebounce = require('./useDebounce.cjs');
2
+ let __vueuse_core = require("@vueuse/core");
3
+
4
+ //#region src/useStorage.ts
5
+ function useStorage(key) {
6
+ const data = (0, __vueuse_core.useStorage)(key, null, void 0, { writeDefaults: false });
7
+ if (data.value === "undefined") data.value = null;
8
+ return data;
9
+ }
10
+
11
+ //#endregion
12
+ exports.useStorage = useStorage;
13
+ //# sourceMappingURL=useStorage.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStorage.cjs","names":[],"sources":["../src/useStorage.ts"],"sourcesContent":["import { useStorage as useStorageComposable } from '@vueuse/core';\nimport type { Ref } from 'vue';\n\nexport function useStorage(key: string): Ref<string | null> {\n\tconst data = useStorageComposable(key, null, undefined, { writeDefaults: false });\n\n\t// bug in 1.15.1\n\tif (data.value === 'undefined') {\n\t\tdata.value = null;\n\t}\n\n\treturn data;\n}\n"],"mappings":";;;;AAGA,SAAgB,WAAW,KAAiC;CAC3D,MAAM,qCAA4B,KAAK,MAAM,QAAW,EAAE,eAAe,OAAO,CAAC;AAGjF,KAAI,KAAK,UAAU,YAClB,MAAK,QAAQ;AAGd,QAAO"}
@@ -0,0 +1,7 @@
1
+ import { Ref } from "vue";
2
+
3
+ //#region src/useStorage.d.ts
4
+ declare function useStorage(key: string): Ref<string | null>;
5
+ //#endregion
6
+ export { useStorage };
7
+ //# sourceMappingURL=useStorage.d.cts.map
@@ -0,0 +1,7 @@
1
+ import { Ref } from "vue";
2
+
3
+ //#region src/useStorage.d.ts
4
+ declare function useStorage(key: string): Ref<string | null>;
5
+ //#endregion
6
+ export { useStorage };
7
+ //# sourceMappingURL=useStorage.d.mts.map
@@ -0,0 +1,12 @@
1
+ import { useStorage as useStorage$1 } from "@vueuse/core";
2
+
3
+ //#region src/useStorage.ts
4
+ function useStorage(key) {
5
+ const data = useStorage$1(key, null, void 0, { writeDefaults: false });
6
+ if (data.value === "undefined") data.value = null;
7
+ return data;
8
+ }
9
+
10
+ //#endregion
11
+ export { useStorage };
12
+ //# sourceMappingURL=useStorage.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStorage.mjs","names":["useStorageComposable"],"sources":["../src/useStorage.ts"],"sourcesContent":["import { useStorage as useStorageComposable } from '@vueuse/core';\nimport type { Ref } from 'vue';\n\nexport function useStorage(key: string): Ref<string | null> {\n\tconst data = useStorageComposable(key, null, undefined, { writeDefaults: false });\n\n\t// bug in 1.15.1\n\tif (data.value === 'undefined') {\n\t\tdata.value = null;\n\t}\n\n\treturn data;\n}\n"],"mappings":";;;AAGA,SAAgB,WAAW,KAAiC;CAC3D,MAAM,OAAOA,aAAqB,KAAK,MAAM,QAAW,EAAE,eAAe,OAAO,CAAC;AAGjF,KAAI,KAAK,UAAU,YAClB,MAAK,QAAQ;AAGd,QAAO"}
@@ -1,5 +1,4 @@
1
+ require('./telemetryRegistry.cjs');
1
2
  const require_useTelemetry = require('./useTelemetry2.cjs');
2
3
 
3
- exports.TelemetryKey = require_useTelemetry.TelemetryKey;
4
- exports.setTelemetry = require_useTelemetry.setTelemetry;
5
4
  exports.useTelemetry = require_useTelemetry.useTelemetry;
@@ -1,42 +1,7 @@
1
- import { InjectionKey } from "vue";
2
- import { ITelemetrySettings } from "@n8n/api-types";
3
- import { InferTelemetryProps, TelemetryEventDef } from "@n8n/telemetry";
4
- import { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from "n8n-workflow";
5
- import { RouteLocation } from "vue-router";
1
+ import { i as TelemetryNodeParameterChange, n as TelemetryIdentifyOptions, t as Telemetry } from "./telemetryRegistry.cjs";
6
2
 
7
3
  //#region src/useTelemetry.d.ts
8
- type TelemetryIdentifyOptions = {
9
- instanceId: string;
10
- userId?: string;
11
- projectId?: string;
12
- versionCli?: string;
13
- userRole?: string;
14
- };
15
- interface TelemetryNodeParameterChange {
16
- name: string;
17
- key?: string;
18
- value: NodeParameterValueType;
19
- node?: string;
20
- oldValue?: string | number;
21
- type?: 'optionsOrderChanged';
22
- }
23
- interface Telemetry {
24
- init(telemetrySettings: ITelemetrySettings, options: TelemetryIdentifyOptions & {
25
- versionCli: string;
26
- }): void;
27
- identify(options: TelemetryIdentifyOptions): void;
28
- track<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;
29
- track(event: string, properties?: ITelemetryTrackProperties): void;
30
- page(route: RouteLocation): void;
31
- reset(): void;
32
- flushPageEvents(): void;
33
- trackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;
34
- trackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;
35
- trackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;
36
- }
37
- declare const TelemetryKey: InjectionKey<Telemetry>;
38
- declare function setTelemetry(instance: Telemetry | undefined): void;
39
4
  declare function useTelemetry(): Telemetry;
40
5
  //#endregion
41
- export { Telemetry, TelemetryIdentifyOptions, TelemetryKey, TelemetryNodeParameterChange, setTelemetry, useTelemetry };
6
+ export { type Telemetry, type TelemetryIdentifyOptions, type TelemetryNodeParameterChange, useTelemetry };
42
7
  //# sourceMappingURL=useTelemetry.d.cts.map
@@ -1,42 +1,7 @@
1
- import { InjectionKey } from "vue";
2
- import { RouteLocation } from "vue-router";
3
- import { ITelemetrySettings } from "@n8n/api-types";
4
- import { InferTelemetryProps, TelemetryEventDef } from "@n8n/telemetry";
5
- import { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from "n8n-workflow";
1
+ import { i as TelemetryNodeParameterChange, n as TelemetryIdentifyOptions, t as Telemetry } from "./telemetryRegistry.mjs";
6
2
 
7
3
  //#region src/useTelemetry.d.ts
8
- type TelemetryIdentifyOptions = {
9
- instanceId: string;
10
- userId?: string;
11
- projectId?: string;
12
- versionCli?: string;
13
- userRole?: string;
14
- };
15
- interface TelemetryNodeParameterChange {
16
- name: string;
17
- key?: string;
18
- value: NodeParameterValueType;
19
- node?: string;
20
- oldValue?: string | number;
21
- type?: 'optionsOrderChanged';
22
- }
23
- interface Telemetry {
24
- init(telemetrySettings: ITelemetrySettings, options: TelemetryIdentifyOptions & {
25
- versionCli: string;
26
- }): void;
27
- identify(options: TelemetryIdentifyOptions): void;
28
- track<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;
29
- track(event: string, properties?: ITelemetryTrackProperties): void;
30
- page(route: RouteLocation): void;
31
- reset(): void;
32
- flushPageEvents(): void;
33
- trackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;
34
- trackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;
35
- trackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;
36
- }
37
- declare const TelemetryKey: InjectionKey<Telemetry>;
38
- declare function setTelemetry(instance: Telemetry | undefined): void;
39
4
  declare function useTelemetry(): Telemetry;
40
5
  //#endregion
41
- export { Telemetry, TelemetryIdentifyOptions, TelemetryKey, TelemetryNodeParameterChange, setTelemetry, useTelemetry };
6
+ export { type Telemetry, type TelemetryIdentifyOptions, type TelemetryNodeParameterChange, useTelemetry };
42
7
  //# sourceMappingURL=useTelemetry.d.mts.map
@@ -1,3 +1,4 @@
1
- import { n as setTelemetry, r as useTelemetry, t as TelemetryKey } from "./useTelemetry2.mjs";
1
+ import "./telemetryRegistry.mjs";
2
+ import { t as useTelemetry } from "./useTelemetry2.mjs";
2
3
 
3
- export { TelemetryKey, setTelemetry, useTelemetry };
4
+ export { useTelemetry };
@@ -1,18 +1,13 @@
1
1
  const require_useDebounce = require('./useDebounce.cjs');
2
+ const require_telemetryRegistry = require('./telemetryRegistry.cjs');
2
3
  let vue = require("vue");
3
4
 
4
5
  //#region src/useTelemetry.ts
5
6
  /**
6
- * Injection key for the telemetry instance. The application provides it at
7
- * bootstrap; components may override it (e.g. a pop-out window with its own
8
- * instance). `useTelemetry` reads it when called inside an injection context.
9
- */
10
- const TelemetryKey = Symbol("Telemetry");
11
- /**
12
7
  * Null-object telemetry used when no instance has been registered (e.g. in
13
8
  * tests that never install the plugin). Telemetry is best-effort and must never
14
9
  * throw or break the UI, so every method is a no-op. Any registered instance
15
- * (via {@link setTelemetry} or {@link TelemetryKey}) takes precedence.
10
+ * (via `setTelemetry` or `TelemetryKey`) takes precedence.
16
11
  *
17
12
  * A plain object literal (not a `Proxy`) so method identity is stable, spies
18
13
  * attach, `'track' in noopTelemetry` holds, and there is no accidental `then`
@@ -29,23 +24,14 @@ const noopTelemetry = {
29
24
  trackAiTransform() {},
30
25
  trackNodeParametersValuesChange() {}
31
26
  };
32
- let registeredTelemetry;
33
27
  let warnedAboutMissingTelemetry = false;
34
28
  /**
35
- * Register the application's telemetry instance. Called once at bootstrap by
36
- * the editor-ui telemetry plugin so package-side `useTelemetry` can return it
37
- * from any context, including outside of component setup.
38
- */
39
- function setTelemetry(instance) {
40
- registeredTelemetry = instance;
41
- }
42
- /**
43
29
  * Returns the active telemetry instance. Resolution order: a component-provided
44
- * instance (via {@link TelemetryKey}), then the app-registered singleton (via
45
- * {@link setTelemetry}), then a no-op fallback.
30
+ * instance (via `TelemetryKey`), then the app-registered singleton (via
31
+ * `setTelemetry`), then a no-op fallback.
46
32
  */
47
33
  function useTelemetry() {
48
- const instance = ((0, vue.hasInjectionContext)() ? (0, vue.inject)(TelemetryKey, null) : null) ?? registeredTelemetry;
34
+ const instance = ((0, vue.hasInjectionContext)() ? (0, vue.inject)(require_telemetryRegistry.TelemetryKey, null) : null) ?? require_telemetryRegistry.getRegisteredTelemetry();
49
35
  if (instance) return instance;
50
36
  if ({}.env.DEV && !warnedAboutMissingTelemetry) {
51
37
  warnedAboutMissingTelemetry = true;
@@ -55,18 +41,6 @@ function useTelemetry() {
55
41
  }
56
42
 
57
43
  //#endregion
58
- Object.defineProperty(exports, 'TelemetryKey', {
59
- enumerable: true,
60
- get: function () {
61
- return TelemetryKey;
62
- }
63
- });
64
- Object.defineProperty(exports, 'setTelemetry', {
65
- enumerable: true,
66
- get: function () {
67
- return setTelemetry;
68
- }
69
- });
70
44
  Object.defineProperty(exports, 'useTelemetry', {
71
45
  enumerable: true,
72
46
  get: function () {
@@ -1 +1 @@
1
- {"version":3,"file":"useTelemetry2.cjs","names":["TelemetryKey: InjectionKey<Telemetry>","noopTelemetry: Telemetry","registeredTelemetry: Telemetry | undefined"],"sources":["../src/useTelemetry.ts"],"sourcesContent":["import type { ITelemetrySettings } from '@n8n/api-types';\nimport type { InferTelemetryProps, TelemetryEventDef } from '@n8n/telemetry';\nimport type { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from 'n8n-workflow';\nimport { hasInjectionContext, inject, type InjectionKey } from 'vue';\nimport type { RouteLocation } from 'vue-router';\n\nexport type TelemetryIdentifyOptions = {\n\tinstanceId: string;\n\tuserId?: string;\n\tprojectId?: string;\n\tversionCli?: string;\n\tuserRole?: string;\n};\n\n/**\n * Shape of a node-parameter change tracked by telemetry. Structurally mirrors\n * editor-ui's `IUpdateInformation`; declared here so the telemetry contract\n * carries no dependency back into the application package.\n */\nexport interface TelemetryNodeParameterChange {\n\tname: string;\n\tkey?: string;\n\tvalue: NodeParameterValueType;\n\tnode?: string;\n\toldValue?: string | number;\n\ttype?: 'optionsOrderChanged';\n}\n\n/**\n * The telemetry contract consumed across the frontend.\n *\n * This package owns the *type* only; the concrete implementation lives in the\n * application (`editor-ui`'s telemetry plugin) and is registered at bootstrap\n * via {@link setTelemetry} / provided through {@link TelemetryKey}. Keeping the\n * contract here lets `useTelemetry` return a fully-typed instance without the\n * package importing application code.\n */\nexport interface Telemetry {\n\tinit(\n\t\ttelemetrySettings: ITelemetrySettings,\n\t\toptions: TelemetryIdentifyOptions & { versionCli: string },\n\t): void;\n\tidentify(options: TelemetryIdentifyOptions): void;\n\ttrack<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;\n\ttrack(event: string, properties?: ITelemetryTrackProperties): void;\n\tpage(route: RouteLocation): void;\n\treset(): void;\n\tflushPageEvents(): void;\n\ttrackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;\n}\n\n/**\n * Injection key for the telemetry instance. The application provides it at\n * bootstrap; components may override it (e.g. a pop-out window with its own\n * instance). `useTelemetry` reads it when called inside an injection context.\n */\nexport const TelemetryKey: InjectionKey<Telemetry> = Symbol('Telemetry');\n\n/**\n * Null-object telemetry used when no instance has been registered (e.g. in\n * tests that never install the plugin). Telemetry is best-effort and must never\n * throw or break the UI, so every method is a no-op. Any registered instance\n * (via {@link setTelemetry} or {@link TelemetryKey}) takes precedence.\n *\n * A plain object literal (not a `Proxy`) so method identity is stable, spies\n * attach, `'track' in noopTelemetry` holds, and there is no accidental `then`\n * that would make `await useTelemetry()` hang.\n */\nconst noopTelemetry: Telemetry = {\n\tinit() {},\n\tidentify() {},\n\ttrack() {},\n\tpage() {},\n\treset() {},\n\tflushPageEvents() {},\n\ttrackAskAI() {},\n\ttrackAiTransform() {},\n\ttrackNodeParametersValuesChange() {},\n};\n\nlet registeredTelemetry: Telemetry | undefined;\nlet warnedAboutMissingTelemetry = false;\n\n/**\n * Register the application's telemetry instance. Called once at bootstrap by\n * the editor-ui telemetry plugin so package-side `useTelemetry` can return it\n * from any context, including outside of component setup.\n */\nexport function setTelemetry(instance: Telemetry | undefined): void {\n\tregisteredTelemetry = instance;\n}\n\n/**\n * Returns the active telemetry instance. Resolution order: a component-provided\n * instance (via {@link TelemetryKey}), then the app-registered singleton (via\n * {@link setTelemetry}), then a no-op fallback.\n */\nexport function useTelemetry(): Telemetry {\n\tconst injected = hasInjectionContext() ? inject(TelemetryKey, null) : null;\n\tconst instance = injected ?? registeredTelemetry;\n\tif (instance) return instance;\n\n\t// Falling back to the no-op means the plugin has not registered an instance\n\t// yet. That should never happen in the app (bootstrap registers before any\n\t// consumer runs); warn once in dev so an ordering regression stays visible.\n\tif (import.meta.env.DEV && !warnedAboutMissingTelemetry) {\n\t\twarnedAboutMissingTelemetry = true;\n\t\tconsole.warn(\n\t\t\t'[useTelemetry] No telemetry instance registered; using a no-op. Ensure the telemetry plugin is installed at bootstrap.',\n\t\t);\n\t}\n\treturn noopTelemetry;\n}\n"],"mappings":";;;;;;;;;AA0DA,MAAaA,eAAwC,OAAO,YAAY;;;;;;;;;;;AAYxE,MAAMC,gBAA2B;CAChC,OAAO;CACP,WAAW;CACX,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,kBAAkB;CAClB,aAAa;CACb,mBAAmB;CACnB,kCAAkC;CAClC;AAED,IAAIC;AACJ,IAAI,8BAA8B;;;;;;AAOlC,SAAgB,aAAa,UAAuC;AACnE,uBAAsB;;;;;;;AAQvB,SAAgB,eAA0B;CAEzC,MAAM,0CADgC,mBAAU,cAAc,KAAK,GAAG,SACzC;AAC7B,KAAI,SAAU,QAAO;AAKrB,QAAgB,IAAI,OAAO,CAAC,6BAA6B;AACxD,gCAA8B;AAC9B,UAAQ,KACP,yHACA;;AAEF,QAAO"}
1
+ {"version":3,"file":"useTelemetry2.cjs","names":["noopTelemetry: Telemetry","TelemetryKey","getRegisteredTelemetry"],"sources":["../src/useTelemetry.ts"],"sourcesContent":["import { hasInjectionContext, inject } from 'vue';\n\nimport {\n\tgetRegisteredTelemetry,\n\tTelemetryKey,\n\ttype Telemetry,\n} from './registries/telemetryRegistry';\n\n// The telemetry *contract* and the *registration* surface deliberately live in\n// `./registries/telemetryRegistry`: this module is `vi.mock`ed in ~100 test\n// files, and a mock factory replaces the whole module. While `setTelemetry`\n// lived here, any partial factory (the common `{ useTelemetry: () => ... }`\n// shape) also starved the telemetry plugin's own bootstrap import of it.\n// Separate modules make that unreachable the plugin never imports this one.\nexport type {\n\tTelemetry,\n\tTelemetryIdentifyOptions,\n\tTelemetryNodeParameterChange,\n} from './registries/telemetryRegistry';\n\n/**\n * Null-object telemetry used when no instance has been registered (e.g. in\n * tests that never install the plugin). Telemetry is best-effort and must never\n * throw or break the UI, so every method is a no-op. Any registered instance\n * (via `setTelemetry` or `TelemetryKey`) takes precedence.\n *\n * A plain object literal (not a `Proxy`) so method identity is stable, spies\n * attach, `'track' in noopTelemetry` holds, and there is no accidental `then`\n * that would make `await useTelemetry()` hang.\n */\nconst noopTelemetry: Telemetry = {\n\tinit() {},\n\tidentify() {},\n\ttrack() {},\n\tpage() {},\n\treset() {},\n\tflushPageEvents() {},\n\ttrackAskAI() {},\n\ttrackAiTransform() {},\n\ttrackNodeParametersValuesChange() {},\n};\n\nlet warnedAboutMissingTelemetry = false;\n\n/**\n * Returns the active telemetry instance. Resolution order: a component-provided\n * instance (via `TelemetryKey`), then the app-registered singleton (via\n * `setTelemetry`), then a no-op fallback.\n */\nexport function useTelemetry(): Telemetry {\n\tconst injected = hasInjectionContext() ? inject(TelemetryKey, null) : null;\n\tconst instance = injected ?? getRegisteredTelemetry();\n\tif (instance) return instance;\n\n\t// Falling back to the no-op means the plugin has not registered an instance\n\t// yet. That should never happen in the app (bootstrap registers before any\n\t// consumer runs); warn once in dev so an ordering regression stays visible.\n\tif (import.meta.env.DEV && !warnedAboutMissingTelemetry) {\n\t\twarnedAboutMissingTelemetry = true;\n\t\tconsole.warn(\n\t\t\t'[useTelemetry] No telemetry instance registered; using a no-op. Ensure the telemetry plugin is installed at bootstrap.',\n\t\t);\n\t}\n\treturn noopTelemetry;\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8BA,MAAMA,gBAA2B;CAChC,OAAO;CACP,WAAW;CACX,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,kBAAkB;CAClB,aAAa;CACb,mBAAmB;CACnB,kCAAkC;CAClC;AAED,IAAI,8BAA8B;;;;;;AAOlC,SAAgB,eAA0B;CAEzC,MAAM,0CADgC,mBAAUC,wCAAc,KAAK,GAAG,SACzCC,kDAAwB;AACrD,KAAI,SAAU,QAAO;AAKrB,QAAgB,IAAI,OAAO,CAAC,6BAA6B;AACxD,gCAA8B;AAC9B,UAAQ,KACP,yHACA;;AAEF,QAAO"}
@@ -1,17 +1,12 @@
1
+ import { n as getRegisteredTelemetry, t as TelemetryKey } from "./telemetryRegistry.mjs";
1
2
  import { hasInjectionContext, inject } from "vue";
2
3
 
3
4
  //#region src/useTelemetry.ts
4
5
  /**
5
- * Injection key for the telemetry instance. The application provides it at
6
- * bootstrap; components may override it (e.g. a pop-out window with its own
7
- * instance). `useTelemetry` reads it when called inside an injection context.
8
- */
9
- const TelemetryKey = Symbol("Telemetry");
10
- /**
11
6
  * Null-object telemetry used when no instance has been registered (e.g. in
12
7
  * tests that never install the plugin). Telemetry is best-effort and must never
13
8
  * throw or break the UI, so every method is a no-op. Any registered instance
14
- * (via {@link setTelemetry} or {@link TelemetryKey}) takes precedence.
9
+ * (via `setTelemetry` or `TelemetryKey`) takes precedence.
15
10
  *
16
11
  * A plain object literal (not a `Proxy`) so method identity is stable, spies
17
12
  * attach, `'track' in noopTelemetry` holds, and there is no accidental `then`
@@ -28,23 +23,14 @@ const noopTelemetry = {
28
23
  trackAiTransform() {},
29
24
  trackNodeParametersValuesChange() {}
30
25
  };
31
- let registeredTelemetry;
32
26
  let warnedAboutMissingTelemetry = false;
33
27
  /**
34
- * Register the application's telemetry instance. Called once at bootstrap by
35
- * the editor-ui telemetry plugin so package-side `useTelemetry` can return it
36
- * from any context, including outside of component setup.
37
- */
38
- function setTelemetry(instance) {
39
- registeredTelemetry = instance;
40
- }
41
- /**
42
28
  * Returns the active telemetry instance. Resolution order: a component-provided
43
- * instance (via {@link TelemetryKey}), then the app-registered singleton (via
44
- * {@link setTelemetry}), then a no-op fallback.
29
+ * instance (via `TelemetryKey`), then the app-registered singleton (via
30
+ * `setTelemetry`), then a no-op fallback.
45
31
  */
46
32
  function useTelemetry() {
47
- const instance = (hasInjectionContext() ? inject(TelemetryKey, null) : null) ?? registeredTelemetry;
33
+ const instance = (hasInjectionContext() ? inject(TelemetryKey, null) : null) ?? getRegisteredTelemetry();
48
34
  if (instance) return instance;
49
35
  if (import.meta.env.DEV && !warnedAboutMissingTelemetry) {
50
36
  warnedAboutMissingTelemetry = true;
@@ -54,5 +40,5 @@ function useTelemetry() {
54
40
  }
55
41
 
56
42
  //#endregion
57
- export { setTelemetry as n, useTelemetry as r, TelemetryKey as t };
43
+ export { useTelemetry as t };
58
44
  //# sourceMappingURL=useTelemetry2.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useTelemetry2.mjs","names":["TelemetryKey: InjectionKey<Telemetry>","noopTelemetry: Telemetry","registeredTelemetry: Telemetry | undefined"],"sources":["../src/useTelemetry.ts"],"sourcesContent":["import type { ITelemetrySettings } from '@n8n/api-types';\nimport type { InferTelemetryProps, TelemetryEventDef } from '@n8n/telemetry';\nimport type { IDataObject, ITelemetryTrackProperties, NodeParameterValueType } from 'n8n-workflow';\nimport { hasInjectionContext, inject, type InjectionKey } from 'vue';\nimport type { RouteLocation } from 'vue-router';\n\nexport type TelemetryIdentifyOptions = {\n\tinstanceId: string;\n\tuserId?: string;\n\tprojectId?: string;\n\tversionCli?: string;\n\tuserRole?: string;\n};\n\n/**\n * Shape of a node-parameter change tracked by telemetry. Structurally mirrors\n * editor-ui's `IUpdateInformation`; declared here so the telemetry contract\n * carries no dependency back into the application package.\n */\nexport interface TelemetryNodeParameterChange {\n\tname: string;\n\tkey?: string;\n\tvalue: NodeParameterValueType;\n\tnode?: string;\n\toldValue?: string | number;\n\ttype?: 'optionsOrderChanged';\n}\n\n/**\n * The telemetry contract consumed across the frontend.\n *\n * This package owns the *type* only; the concrete implementation lives in the\n * application (`editor-ui`'s telemetry plugin) and is registered at bootstrap\n * via {@link setTelemetry} / provided through {@link TelemetryKey}. Keeping the\n * contract here lets `useTelemetry` return a fully-typed instance without the\n * package importing application code.\n */\nexport interface Telemetry {\n\tinit(\n\t\ttelemetrySettings: ITelemetrySettings,\n\t\toptions: TelemetryIdentifyOptions & { versionCli: string },\n\t): void;\n\tidentify(options: TelemetryIdentifyOptions): void;\n\ttrack<T extends TelemetryEventDef>(event: T, properties: InferTelemetryProps<T>): void;\n\ttrack(event: string, properties?: ITelemetryTrackProperties): void;\n\tpage(route: RouteLocation): void;\n\treset(): void;\n\tflushPageEvents(): void;\n\ttrackAskAI(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackAiTransform(event: string, ndvPushRef: string, properties?: IDataObject): void;\n\ttrackNodeParametersValuesChange(nodeType: string, change: TelemetryNodeParameterChange): void;\n}\n\n/**\n * Injection key for the telemetry instance. The application provides it at\n * bootstrap; components may override it (e.g. a pop-out window with its own\n * instance). `useTelemetry` reads it when called inside an injection context.\n */\nexport const TelemetryKey: InjectionKey<Telemetry> = Symbol('Telemetry');\n\n/**\n * Null-object telemetry used when no instance has been registered (e.g. in\n * tests that never install the plugin). Telemetry is best-effort and must never\n * throw or break the UI, so every method is a no-op. Any registered instance\n * (via {@link setTelemetry} or {@link TelemetryKey}) takes precedence.\n *\n * A plain object literal (not a `Proxy`) so method identity is stable, spies\n * attach, `'track' in noopTelemetry` holds, and there is no accidental `then`\n * that would make `await useTelemetry()` hang.\n */\nconst noopTelemetry: Telemetry = {\n\tinit() {},\n\tidentify() {},\n\ttrack() {},\n\tpage() {},\n\treset() {},\n\tflushPageEvents() {},\n\ttrackAskAI() {},\n\ttrackAiTransform() {},\n\ttrackNodeParametersValuesChange() {},\n};\n\nlet registeredTelemetry: Telemetry | undefined;\nlet warnedAboutMissingTelemetry = false;\n\n/**\n * Register the application's telemetry instance. Called once at bootstrap by\n * the editor-ui telemetry plugin so package-side `useTelemetry` can return it\n * from any context, including outside of component setup.\n */\nexport function setTelemetry(instance: Telemetry | undefined): void {\n\tregisteredTelemetry = instance;\n}\n\n/**\n * Returns the active telemetry instance. Resolution order: a component-provided\n * instance (via {@link TelemetryKey}), then the app-registered singleton (via\n * {@link setTelemetry}), then a no-op fallback.\n */\nexport function useTelemetry(): Telemetry {\n\tconst injected = hasInjectionContext() ? inject(TelemetryKey, null) : null;\n\tconst instance = injected ?? registeredTelemetry;\n\tif (instance) return instance;\n\n\t// Falling back to the no-op means the plugin has not registered an instance\n\t// yet. That should never happen in the app (bootstrap registers before any\n\t// consumer runs); warn once in dev so an ordering regression stays visible.\n\tif (import.meta.env.DEV && !warnedAboutMissingTelemetry) {\n\t\twarnedAboutMissingTelemetry = true;\n\t\tconsole.warn(\n\t\t\t'[useTelemetry] No telemetry instance registered; using a no-op. Ensure the telemetry plugin is installed at bootstrap.',\n\t\t);\n\t}\n\treturn noopTelemetry;\n}\n"],"mappings":";;;;;;;;AA0DA,MAAaA,eAAwC,OAAO,YAAY;;;;;;;;;;;AAYxE,MAAMC,gBAA2B;CAChC,OAAO;CACP,WAAW;CACX,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,kBAAkB;CAClB,aAAa;CACb,mBAAmB;CACnB,kCAAkC;CAClC;AAED,IAAIC;AACJ,IAAI,8BAA8B;;;;;;AAOlC,SAAgB,aAAa,UAAuC;AACnE,uBAAsB;;;;;;;AAQvB,SAAgB,eAA0B;CAEzC,MAAM,YADW,qBAAqB,GAAG,OAAO,cAAc,KAAK,GAAG,SACzC;AAC7B,KAAI,SAAU,QAAO;AAKrB,KAAI,OAAO,KAAK,IAAI,OAAO,CAAC,6BAA6B;AACxD,gCAA8B;AAC9B,UAAQ,KACP,yHACA;;AAEF,QAAO"}
1
+ {"version":3,"file":"useTelemetry2.mjs","names":["noopTelemetry: Telemetry"],"sources":["../src/useTelemetry.ts"],"sourcesContent":["import { hasInjectionContext, inject } from 'vue';\n\nimport {\n\tgetRegisteredTelemetry,\n\tTelemetryKey,\n\ttype Telemetry,\n} from './registries/telemetryRegistry';\n\n// The telemetry *contract* and the *registration* surface deliberately live in\n// `./registries/telemetryRegistry`: this module is `vi.mock`ed in ~100 test\n// files, and a mock factory replaces the whole module. While `setTelemetry`\n// lived here, any partial factory (the common `{ useTelemetry: () => ... }`\n// shape) also starved the telemetry plugin's own bootstrap import of it.\n// Separate modules make that unreachable the plugin never imports this one.\nexport type {\n\tTelemetry,\n\tTelemetryIdentifyOptions,\n\tTelemetryNodeParameterChange,\n} from './registries/telemetryRegistry';\n\n/**\n * Null-object telemetry used when no instance has been registered (e.g. in\n * tests that never install the plugin). Telemetry is best-effort and must never\n * throw or break the UI, so every method is a no-op. Any registered instance\n * (via `setTelemetry` or `TelemetryKey`) takes precedence.\n *\n * A plain object literal (not a `Proxy`) so method identity is stable, spies\n * attach, `'track' in noopTelemetry` holds, and there is no accidental `then`\n * that would make `await useTelemetry()` hang.\n */\nconst noopTelemetry: Telemetry = {\n\tinit() {},\n\tidentify() {},\n\ttrack() {},\n\tpage() {},\n\treset() {},\n\tflushPageEvents() {},\n\ttrackAskAI() {},\n\ttrackAiTransform() {},\n\ttrackNodeParametersValuesChange() {},\n};\n\nlet warnedAboutMissingTelemetry = false;\n\n/**\n * Returns the active telemetry instance. Resolution order: a component-provided\n * instance (via `TelemetryKey`), then the app-registered singleton (via\n * `setTelemetry`), then a no-op fallback.\n */\nexport function useTelemetry(): Telemetry {\n\tconst injected = hasInjectionContext() ? inject(TelemetryKey, null) : null;\n\tconst instance = injected ?? getRegisteredTelemetry();\n\tif (instance) return instance;\n\n\t// Falling back to the no-op means the plugin has not registered an instance\n\t// yet. That should never happen in the app (bootstrap registers before any\n\t// consumer runs); warn once in dev so an ordering regression stays visible.\n\tif (import.meta.env.DEV && !warnedAboutMissingTelemetry) {\n\t\twarnedAboutMissingTelemetry = true;\n\t\tconsole.warn(\n\t\t\t'[useTelemetry] No telemetry instance registered; using a no-op. Ensure the telemetry plugin is installed at bootstrap.',\n\t\t);\n\t}\n\treturn noopTelemetry;\n}\n"],"mappings":";;;;;;;;;;;;;;AA8BA,MAAMA,gBAA2B;CAChC,OAAO;CACP,WAAW;CACX,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,kBAAkB;CAClB,aAAa;CACb,mBAAmB;CACnB,kCAAkC;CAClC;AAED,IAAI,8BAA8B;;;;;;AAOlC,SAAgB,eAA0B;CAEzC,MAAM,YADW,qBAAqB,GAAG,OAAO,cAAc,KAAK,GAAG,SACzC,wBAAwB;AACrD,KAAI,SAAU,QAAO;AAKrB,KAAI,OAAO,KAAK,IAAI,OAAO,CAAC,6BAA6B;AACxD,gCAA8B;AAC9B,UAAQ,KACP,yHACA;;AAEF,QAAO"}
package/dist/useToast.cjs CHANGED
@@ -1,30 +1,42 @@
1
1
  const require_useDebounce = require('./useDebounce.cjs');
2
2
  const require_useExternalHooks = require('./useExternalHooks2.cjs');
3
+ require('./telemetryRegistry.cjs');
3
4
  const require_useTelemetry = require('./useTelemetry2.cjs');
4
5
  let vue = require("vue");
5
6
  let __n8n_frontend_constants_z_indexes = require("@n8n/frontend-constants/z-indexes");
6
7
  let __n8n_frontend_constants_views = require("@n8n/frontend-constants/views");
7
8
  let __n8n_frontend_utils_htmlUtils = require("@n8n/frontend-utils/htmlUtils");
8
9
  let __n8n_i18n = require("@n8n/i18n");
9
- let __n8n_stores_notifications_store = require("@n8n/stores/notifications.store");
10
10
  let vue_router = require("vue-router");
11
11
 
12
12
  //#region src/useToast.ts
13
13
  let registeredNotify;
14
14
  /**
15
15
  * Register the notification function. Called once at bootstrap by
16
- * `editor-ui` (passing `ElNotification` from element-plus) so `useToast`
17
- * can issue notifications without importing element-plus directly — keeping
18
- * the DTS build lightweight.
16
+ * `editor-ui` (passing a suppression-aware wrapper around `ElNotification`) so
17
+ * `useToast` can issue notifications without importing element-plus directly —
18
+ * keeping the DTS build lightweight.
19
+ *
20
+ * This is the *only* toast dependency the app registers. Whether a notification
21
+ * is actually shown is the notifier's decision, so if you are chasing a toast
22
+ * that never appeared, look at the registration site, not here.
19
23
  */
20
24
  function setNotify(fn) {
21
25
  registeredNotify = fn;
22
26
  }
23
27
  const noopHandle = { close() {} };
24
28
  const noopNotify = () => noopHandle;
29
+ let warnedAboutMissingNotify = false;
30
+ function resolveNotify() {
31
+ if (registeredNotify) return registeredNotify;
32
+ if ({}.env.DEV && !warnedAboutMissingNotify) {
33
+ warnedAboutMissingNotify = true;
34
+ console.warn("[useToast] No notification function registered; toasts will not render. Call setNotify() at app bootstrap.");
35
+ }
36
+ return noopNotify;
37
+ }
25
38
  const stickyNotificationQueue = [];
26
39
  function useToast() {
27
- const notify = registeredNotify ?? noopNotify;
28
40
  const telemetry = require_useTelemetry.useTelemetry();
29
41
  const route = (0, vue_router.useRoute)();
30
42
  const workflowId = (0, vue.computed)(() => {
@@ -32,7 +44,6 @@ function useToast() {
32
44
  const id = route?.params?.workflowId;
33
45
  return (Array.isArray(id) ? id[0] : id) ?? "";
34
46
  });
35
- const notificationsStore = (0, __n8n_stores_notifications_store.useNotificationsStore)();
36
47
  const externalHooks = require_useExternalHooks.useExternalHooks();
37
48
  const i18n = (0, __n8n_i18n.useI18n)();
38
49
  function causedByCredential(message) {
@@ -40,9 +51,7 @@ function useToast() {
40
51
  return message.includes("Credentials for") && message.includes("are not set");
41
52
  }
42
53
  function showMessage(messageData, track = true) {
43
- const suppressed = notificationsStore.areNotificationsSuppressed;
44
- const allowErrors = notificationsStore.allowErrorNotificationsWhenSuppressed;
45
- if (suppressed && !(allowErrors && messageData.type === "error")) return { close: () => {} };
54
+ const notify = resolveNotify();
46
55
  const messageDefaults = {
47
56
  dangerouslyUseHTMLString: true,
48
57
  position: "bottom-right",
@@ -58,6 +67,7 @@ function useToast() {
58
67
  if (typeof message === "string") params.message = (0, __n8n_frontend_utils_htmlUtils.sanitizeHtml)(message);
59
68
  if (typeof title === "string") params.title = (0, __n8n_frontend_utils_htmlUtils.sanitizeHtml)(title);
60
69
  const notification = notify(params);
70
+ if (!notification) return noopHandle;
61
71
  if (params.duration === 0) stickyNotificationQueue.push(notification);
62
72
  if (params.type === "error" && track) {
63
73
  let messageForTelemetry;
@@ -146,26 +156,11 @@ function useToast() {
146
156
  });
147
157
  stickyNotificationQueue.length = 0;
148
158
  }
149
- function showNotificationForViews(views) {
150
- const notifications = [];
151
- views.forEach((view) => {
152
- notifications.push(...notificationsStore.pendingNotificationsForViews[view] ?? []);
153
- });
154
- if (notifications.length) {
155
- notifications.forEach((notification) => {
156
- setTimeout(() => {
157
- showMessage(notification);
158
- }, 5);
159
- });
160
- notificationsStore.setNotificationsForView(__n8n_frontend_constants_views.VIEWS.WORKFLOW, []);
161
- }
162
- }
163
159
  return {
164
160
  showMessage,
165
161
  showToast,
166
162
  showError,
167
- clearAllStickyNotifications,
168
- showNotificationForViews
163
+ clearAllStickyNotifications
169
164
  };
170
165
  }
171
166
 
@@ -1 +1 @@
1
- {"version":3,"file":"useToast.cjs","names":["registeredNotify: NotifyFn | undefined","noopHandle: NotificationHandle","noopNotify: NotifyFn","stickyNotificationQueue: NotificationHandle[]","useTelemetry","VIEWS","useExternalHooks","messageDefaults: Partial<Omit<NotificationOptions, 'message'>>","APP_Z_INDEXES","messageForTelemetry: string","notification: NotificationHandle","notifications: NotificationOptions[]"],"sources":["../src/useToast.ts"],"sourcesContent":["import { VIEWS } from '@n8n/frontend-constants/views';\nimport { APP_Z_INDEXES } from '@n8n/frontend-constants/z-indexes';\nimport { sanitizeHtml } from '@n8n/frontend-utils/htmlUtils';\nimport { useI18n } from '@n8n/i18n';\nimport type { NotificationOptions } from '@n8n/stores/notifications.store';\nimport { useNotificationsStore } from '@n8n/stores/notifications.store';\nimport { computed } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { useExternalHooks } from './useExternalHooks';\nimport { useTelemetry } from './useTelemetry';\n\n/**\n * Handle returned by the notification function. Declared locally so the DTS\n * build stays free of the full element-plus type graph.\n */\nexport interface NotificationHandle {\n\tclose: () => void;\n}\n\n/** Notification severity — mirrors `MessageBoxState['type']` from element-plus. */\nexport type NotificationType = '' | 'success' | 'warning' | 'info' | 'error';\n\n/**\n * Notification function contract — matches `ElNotification` from element-plus.\n * The application registers the concrete implementation at bootstrap via\n * {@link setNotify}; this package owns only the contract.\n */\ntype NotifyFn = (options: Record<string, unknown>) => NotificationHandle;\n\nlet registeredNotify: NotifyFn | undefined;\n\n/**\n * Register the notification function. Called once at bootstrap by\n * `editor-ui` (passing `ElNotification` from element-plus) so `useToast`\n * can issue notifications without importing element-plus directly — keeping\n * the DTS build lightweight.\n */\nexport function setNotify(fn: NotifyFn): void {\n\tregisteredNotify = fn;\n}\n\nconst noopHandle: NotificationHandle = { close() {} };\nconst noopNotify: NotifyFn = () => noopHandle;\n\nconst stickyNotificationQueue: NotificationHandle[] = [];\n\nexport function useToast() {\n\tconst notify = registeredNotify ?? noopNotify;\n\tconst telemetry = useTelemetry();\n\tconst route = useRoute();\n\tconst workflowId = computed(() => {\n\t\tif (route?.name === VIEWS.DEMO || route?.name === VIEWS.DEMO_DIFF) return 'demo';\n\t\tconst id = route?.params?.workflowId;\n\t\treturn (Array.isArray(id) ? id[0] : id) ?? '';\n\t});\n\tconst notificationsStore = useNotificationsStore();\n\tconst externalHooks = useExternalHooks();\n\tconst i18n = useI18n();\n\n\tfunction causedByCredential(message: string | undefined) {\n\t\tif (!message || typeof message !== 'string') return false;\n\n\t\treturn message.includes('Credentials for') && message.includes('are not set');\n\t}\n\n\tfunction showMessage(messageData: Partial<NotificationOptions>, track = true) {\n\t\tconst suppressed = notificationsStore.areNotificationsSuppressed;\n\t\tconst allowErrors = notificationsStore.allowErrorNotificationsWhenSuppressed;\n\t\tif (suppressed && !(allowErrors && messageData.type === 'error')) {\n\t\t\treturn { close: () => {} } as NotificationHandle;\n\t\t}\n\n\t\tconst messageDefaults: Partial<Omit<NotificationOptions, 'message'>> = {\n\t\t\tdangerouslyUseHTMLString: true,\n\t\t\tposition: 'bottom-right',\n\t\t\t// Layer above NDV and modal overlays, sourced from the shared scale.\n\t\t\tzIndex: APP_Z_INDEXES.TOASTS,\n\t\t\tappendTo: '#n8n-app',\n\t\t\tcustomClass: 'content-toast',\n\t\t};\n\t\tconst { message, title } = messageData;\n\t\tconst params = { ...messageDefaults, ...messageData };\n\n\t\tif (typeof message === 'string') {\n\t\t\tparams.message = sanitizeHtml(message);\n\t\t}\n\n\t\tif (typeof title === 'string') {\n\t\t\tparams.title = sanitizeHtml(title);\n\t\t}\n\n\t\tconst notification = notify(params as unknown as Record<string, unknown>);\n\n\t\tif (params.duration === 0) {\n\t\t\tstickyNotificationQueue.push(notification);\n\t\t}\n\n\t\tif (params.type === 'error' && track) {\n\t\t\t// Extract string message for telemetry - don't send VNode objects as they have circular refs\n\t\t\tlet messageForTelemetry: string;\n\t\t\tif (typeof params.message === 'string') {\n\t\t\t\tmessageForTelemetry = params.message;\n\t\t\t} else if (\n\t\t\t\tparams.message &&\n\t\t\t\ttypeof params.message === 'object' &&\n\t\t\t\t'props' in params.message &&\n\t\t\t\tparams.message.props\n\t\t\t) {\n\t\t\t\t// Extract error message from VNode props (e.g., NodeExecutionErrorMessage component)\n\t\t\t\tconst props = params.message.props;\n\t\t\t\tconst hasErrorMessage =\n\t\t\t\t\ttypeof props === 'object' && props !== null && 'errorMessage' in props;\n\t\t\t\tconst hasMessage = typeof props === 'object' && props !== null && 'message' in props;\n\n\t\t\t\tif (hasErrorMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.errorMessage);\n\t\t\t\t} else if (hasMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.message);\n\t\t\t\t} else {\n\t\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t}\n\n\t\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\t\terror_title: params.title,\n\t\t\t\terror_message: messageForTelemetry,\n\t\t\t\tcaused_by_credential: causedByCredential(messageForTelemetry),\n\t\t\t\tworkflow_id: workflowId.value,\n\t\t\t});\n\t\t}\n\n\t\treturn notification;\n\t}\n\n\tfunction showToast(config: {\n\t\ttitle: string;\n\t\tmessage: NotificationOptions['message'];\n\t\tonClick?: (event?: MouseEvent) => void;\n\t\tonClose?: () => void;\n\t\tduration?: number;\n\t\tcustomClass?: string;\n\t\tcloseOnClick?: boolean;\n\t\ttype?: NotificationType;\n\t}) {\n\t\t// eslint-disable-next-line prefer-const\n\t\tlet notification: NotificationHandle;\n\t\tif (config.closeOnClick) {\n\t\t\tconst originalOnClick = config.onClick;\n\t\t\tconfig.onClick = () => {\n\t\t\t\tif (notification) {\n\t\t\t\t\tnotification.close();\n\t\t\t\t}\n\n\t\t\t\tif (originalOnClick) {\n\t\t\t\t\toriginalOnClick();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tnotification = showMessage({\n\t\t\ttitle: config.title,\n\t\t\tmessage: config.message,\n\t\t\tonClick: config.onClick,\n\t\t\tonClose: config.onClose,\n\t\t\tduration: config.duration,\n\t\t\tcustomClass: config.customClass,\n\t\t\ttype: config.type,\n\t\t});\n\n\t\treturn notification;\n\t}\n\n\tfunction collapsableDetails(description: string) {\n\t\tconst errorDescription =\n\t\t\tdescription.length > 500 ? `${description.slice(0, 500)}...` : description;\n\n\t\treturn `\n\t\t\t\t<br>\n\t\t\t\t<br>\n\t\t\t\t<details>\n\t\t\t\t\t<summary\n\t\t\t\t\t\tstyle=\"color: #ff6d5a; font-weight: bold; cursor: pointer;\"\n\t\t\t\t\t>\n\t\t\t\t\t\t${i18n.baseText('showMessage.showDetails')}\n\t\t\t\t\t</summary>\n\t\t\t\t\t<p>${errorDescription}</p>\n\t\t\t\t</details>\n\t\t\t`;\n\t}\n\n\tfunction showError(\n\t\te: unknown,\n\t\ttitle: string,\n\t\toptions?: { message?: string; description?: string },\n\t) {\n\t\tconst error = e as Error & { description?: string };\n\t\tconst message = options?.message;\n\t\tconst description = options?.description ?? error.description;\n\t\tconst messageLine = message ? `${message}<br/>` : '';\n\t\tshowMessage(\n\t\t\t{\n\t\t\t\ttitle,\n\t\t\t\tmessage: `\n\t\t\t\t\t${messageLine}\n\t\t\t\t\t<i>${error.message}</i>\n\t\t\t\t\t${description ? collapsableDetails(description) : ''}`,\n\t\t\t\ttype: 'error',\n\t\t\t\tduration: 0,\n\t\t\t},\n\t\t\tfalse,\n\t\t);\n\n\t\tvoid externalHooks.run('showMessage.showError', {\n\t\t\ttitle,\n\t\t\tmessage,\n\t\t\terrorMessage: error.message,\n\t\t});\n\n\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\terror_title: title,\n\t\t\terror_description: message,\n\t\t\terror_message: error.message,\n\t\t\tcaused_by_credential: causedByCredential(error.message),\n\t\t\tworkflow_id: workflowId.value,\n\t\t});\n\t}\n\n\tfunction clearAllStickyNotifications() {\n\t\tstickyNotificationQueue.forEach((notification) => {\n\t\t\tif (notification) {\n\t\t\t\tnotification.close();\n\t\t\t}\n\t\t});\n\n\t\tstickyNotificationQueue.length = 0;\n\t}\n\n\t// Pick up and display notifications for the given list of views\n\tfunction showNotificationForViews(views: VIEWS[]) {\n\t\tconst notifications: NotificationOptions[] = [];\n\t\tviews.forEach((view) => {\n\t\t\tnotifications.push(...(notificationsStore.pendingNotificationsForViews[view] ?? []));\n\t\t});\n\t\tif (notifications.length) {\n\t\t\tnotifications.forEach((notification) => {\n\t\t\t\t// Notifications show on top of each other without this timeout\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tshowMessage(notification);\n\t\t\t\t}, 5);\n\t\t\t});\n\t\t\t// Clear the queue once all notifications are shown\n\t\t\tnotificationsStore.setNotificationsForView(VIEWS.WORKFLOW, []);\n\t\t}\n\t}\n\n\treturn {\n\t\tshowMessage,\n\t\tshowToast,\n\t\tshowError,\n\t\tclearAllStickyNotifications,\n\t\tshowNotificationForViews,\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useToast.cjs","names":["registeredNotify: NotifyFn | undefined","noopHandle: NotificationHandle","noopNotify: NotifyFn","stickyNotificationQueue: NotificationHandle[]","useTelemetry","VIEWS","useExternalHooks","messageDefaults: Partial<Omit<NotificationOptions, 'message'>>","APP_Z_INDEXES","messageForTelemetry: string","notification: NotificationHandle"],"sources":["../src/useToast.ts"],"sourcesContent":["import { VIEWS } from '@n8n/frontend-constants/views';\nimport { APP_Z_INDEXES } from '@n8n/frontend-constants/z-indexes';\nimport { sanitizeHtml } from '@n8n/frontend-utils/htmlUtils';\nimport { useI18n } from '@n8n/i18n';\nimport { computed } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport type { NotificationOptions, NotificationType } from './types/notification';\nimport { useExternalHooks } from './useExternalHooks';\nimport { useTelemetry } from './useTelemetry';\n\nexport type {\n\tNotificationOptions,\n\tNotificationPosition,\n\tNotificationType,\n} from './types/notification';\n\n/**\n * Handle returned by the notification function. Declared locally so the DTS\n * build stays free of the full element-plus type graph.\n */\nexport interface NotificationHandle {\n\tclose: () => void;\n}\n\n/**\n * Notification function contract — the app's wrapper around `ElNotification`.\n * Registered at bootstrap via {@link setNotify}; this package owns only the\n * contract.\n *\n * Returning `undefined` means the app declined to show this notification — today\n * that is notification suppression, which lives at the registration site rather\n * than here. `showMessage` treats it as \"dropped\": no sticky-queue\n * entry, no error telemetry, and a no-op handle to the caller.\n */\ntype NotifyFn = (options: Record<string, unknown>) => NotificationHandle | undefined;\n\nlet registeredNotify: NotifyFn | undefined;\n\n/**\n * Register the notification function. Called once at bootstrap by\n * `editor-ui` (passing a suppression-aware wrapper around `ElNotification`) so\n * `useToast` can issue notifications without importing element-plus directly —\n * keeping the DTS build lightweight.\n *\n * This is the *only* toast dependency the app registers. Whether a notification\n * is actually shown is the notifier's decision, so if you are chasing a toast\n * that never appeared, look at the registration site, not here.\n */\nexport function setNotify(fn: NotifyFn): void {\n\tregisteredNotify = fn;\n}\n\nconst noopHandle: NotificationHandle = { close() {} };\nconst noopNotify: NotifyFn = () => noopHandle;\n\nlet warnedAboutMissingNotify = false;\n\nfunction resolveNotify(): NotifyFn {\n\tif (registeredNotify) return registeredNotify;\n\n\t// Falling back means bootstrap never registered. The toast is dropped rather\n\t// than shown, so warn once in dev instead of failing silent.\n\tif (import.meta.env.DEV && !warnedAboutMissingNotify) {\n\t\twarnedAboutMissingNotify = true;\n\t\tconsole.warn(\n\t\t\t'[useToast] No notification function registered; toasts will not render. Call setNotify() at app bootstrap.',\n\t\t);\n\t}\n\treturn noopNotify;\n}\n\nconst stickyNotificationQueue: NotificationHandle[] = [];\n\nexport function useToast() {\n\tconst telemetry = useTelemetry();\n\tconst route = useRoute();\n\tconst workflowId = computed(() => {\n\t\tif (route?.name === VIEWS.DEMO || route?.name === VIEWS.DEMO_DIFF) return 'demo';\n\t\tconst id = route?.params?.workflowId;\n\t\treturn (Array.isArray(id) ? id[0] : id) ?? '';\n\t});\n\tconst externalHooks = useExternalHooks();\n\tconst i18n = useI18n();\n\n\tfunction causedByCredential(message: string | undefined) {\n\t\tif (!message || typeof message !== 'string') return false;\n\n\t\treturn message.includes('Credentials for') && message.includes('are not set');\n\t}\n\n\tfunction showMessage(messageData: Partial<NotificationOptions>, track = true) {\n\t\t// Resolved per call, not once per `useToast()`: a composable captured before\n\t\t// bootstrap registers would otherwise stay bound to the no-op for its whole\n\t\t// lifetime, silently dropping toasts.\n\t\tconst notify = resolveNotify();\n\n\t\tconst messageDefaults: Partial<Omit<NotificationOptions, 'message'>> = {\n\t\t\tdangerouslyUseHTMLString: true,\n\t\t\tposition: 'bottom-right',\n\t\t\t// Layer above NDV and modal overlays, sourced from the shared scale.\n\t\t\tzIndex: APP_Z_INDEXES.TOASTS,\n\t\t\tappendTo: '#n8n-app',\n\t\t\tcustomClass: 'content-toast',\n\t\t};\n\t\tconst { message, title } = messageData;\n\t\tconst params = { ...messageDefaults, ...messageData };\n\n\t\tif (typeof message === 'string') {\n\t\t\tparams.message = sanitizeHtml(message);\n\t\t}\n\n\t\tif (typeof title === 'string') {\n\t\t\tparams.title = sanitizeHtml(title);\n\t\t}\n\n\t\tconst notification = notify(params as unknown as Record<string, unknown>);\n\n\t\t// The app declined to show it (suppression). Return before the sticky queue\n\t\t// and before error telemetry, so a dropped toast leaves no trace — exactly\n\t\t// what the removed in-package suppression branch did.\n\t\tif (!notification) return noopHandle;\n\n\t\tif (params.duration === 0) {\n\t\t\tstickyNotificationQueue.push(notification);\n\t\t}\n\n\t\tif (params.type === 'error' && track) {\n\t\t\t// Extract string message for telemetry - don't send VNode objects as they have circular refs\n\t\t\tlet messageForTelemetry: string;\n\t\t\tif (typeof params.message === 'string') {\n\t\t\t\tmessageForTelemetry = params.message;\n\t\t\t} else if (\n\t\t\t\tparams.message &&\n\t\t\t\ttypeof params.message === 'object' &&\n\t\t\t\t'props' in params.message &&\n\t\t\t\tparams.message.props\n\t\t\t) {\n\t\t\t\t// Extract error message from VNode props (e.g., NodeExecutionErrorMessage component)\n\t\t\t\tconst props = params.message.props;\n\t\t\t\tconst hasErrorMessage =\n\t\t\t\t\ttypeof props === 'object' && props !== null && 'errorMessage' in props;\n\t\t\t\tconst hasMessage = typeof props === 'object' && props !== null && 'message' in props;\n\n\t\t\t\tif (hasErrorMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.errorMessage);\n\t\t\t\t} else if (hasMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.message);\n\t\t\t\t} else {\n\t\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t}\n\n\t\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\t\terror_title: params.title,\n\t\t\t\terror_message: messageForTelemetry,\n\t\t\t\tcaused_by_credential: causedByCredential(messageForTelemetry),\n\t\t\t\tworkflow_id: workflowId.value,\n\t\t\t});\n\t\t}\n\n\t\treturn notification;\n\t}\n\n\tfunction showToast(config: {\n\t\ttitle: string;\n\t\tmessage: NotificationOptions['message'];\n\t\tonClick?: (event?: MouseEvent) => void;\n\t\tonClose?: () => void;\n\t\tduration?: number;\n\t\tcustomClass?: string;\n\t\tcloseOnClick?: boolean;\n\t\ttype?: NotificationType;\n\t}) {\n\t\t// eslint-disable-next-line prefer-const\n\t\tlet notification: NotificationHandle;\n\t\tif (config.closeOnClick) {\n\t\t\tconst originalOnClick = config.onClick;\n\t\t\tconfig.onClick = () => {\n\t\t\t\tif (notification) {\n\t\t\t\t\tnotification.close();\n\t\t\t\t}\n\n\t\t\t\tif (originalOnClick) {\n\t\t\t\t\toriginalOnClick();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tnotification = showMessage({\n\t\t\ttitle: config.title,\n\t\t\tmessage: config.message,\n\t\t\tonClick: config.onClick,\n\t\t\tonClose: config.onClose,\n\t\t\tduration: config.duration,\n\t\t\tcustomClass: config.customClass,\n\t\t\ttype: config.type,\n\t\t});\n\n\t\treturn notification;\n\t}\n\n\tfunction collapsableDetails(description: string) {\n\t\tconst errorDescription =\n\t\t\tdescription.length > 500 ? `${description.slice(0, 500)}...` : description;\n\n\t\treturn `\n\t\t\t\t<br>\n\t\t\t\t<br>\n\t\t\t\t<details>\n\t\t\t\t\t<summary\n\t\t\t\t\t\tstyle=\"color: #ff6d5a; font-weight: bold; cursor: pointer;\"\n\t\t\t\t\t>\n\t\t\t\t\t\t${i18n.baseText('showMessage.showDetails')}\n\t\t\t\t\t</summary>\n\t\t\t\t\t<p>${errorDescription}</p>\n\t\t\t\t</details>\n\t\t\t`;\n\t}\n\n\tfunction showError(\n\t\te: unknown,\n\t\ttitle: string,\n\t\toptions?: { message?: string; description?: string },\n\t) {\n\t\tconst error = e as Error & { description?: string };\n\t\tconst message = options?.message;\n\t\tconst description = options?.description ?? error.description;\n\t\tconst messageLine = message ? `${message}<br/>` : '';\n\t\tshowMessage(\n\t\t\t{\n\t\t\t\ttitle,\n\t\t\t\tmessage: `\n\t\t\t\t\t${messageLine}\n\t\t\t\t\t<i>${error.message}</i>\n\t\t\t\t\t${description ? collapsableDetails(description) : ''}`,\n\t\t\t\ttype: 'error',\n\t\t\t\tduration: 0,\n\t\t\t},\n\t\t\tfalse,\n\t\t);\n\n\t\tvoid externalHooks.run('showMessage.showError', {\n\t\t\ttitle,\n\t\t\tmessage,\n\t\t\terrorMessage: error.message,\n\t\t});\n\n\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\terror_title: title,\n\t\t\terror_description: message,\n\t\t\terror_message: error.message,\n\t\t\tcaused_by_credential: causedByCredential(error.message),\n\t\t\tworkflow_id: workflowId.value,\n\t\t});\n\t}\n\n\tfunction clearAllStickyNotifications() {\n\t\tstickyNotificationQueue.forEach((notification) => {\n\t\t\tif (notification) {\n\t\t\t\tnotification.close();\n\t\t\t}\n\t\t});\n\n\t\tstickyNotificationQueue.length = 0;\n\t}\n\n\treturn {\n\t\tshowMessage,\n\t\tshowToast,\n\t\tshowError,\n\t\tclearAllStickyNotifications,\n\t};\n}\n"],"mappings":"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"}
@@ -1,12 +1,10 @@
1
- import { VIEWS } from "@n8n/frontend-constants/views";
2
- import { NotificationOptions } from "@n8n/stores/notifications.store";
1
+ import { n as NotificationPosition, r as NotificationType, t as NotificationOptions } from "./notification.cjs";
3
2
 
4
3
  //#region src/useToast.d.ts
5
4
  interface NotificationHandle {
6
5
  close: () => void;
7
6
  }
8
- type NotificationType = '' | 'success' | 'warning' | 'info' | 'error';
9
- type NotifyFn = (options: Record<string, unknown>) => NotificationHandle;
7
+ type NotifyFn = (options: Record<string, unknown>) => NotificationHandle | undefined;
10
8
  declare function setNotify(fn: NotifyFn): void;
11
9
  declare function useToast(): {
12
10
  showMessage: (messageData: Partial<NotificationOptions>, track?: boolean) => NotificationHandle;
@@ -25,8 +23,7 @@ declare function useToast(): {
25
23
  description?: string;
26
24
  }) => void;
27
25
  clearAllStickyNotifications: () => void;
28
- showNotificationForViews: (views: VIEWS[]) => void;
29
26
  };
30
27
  //#endregion
31
- export { NotificationHandle, NotificationType, setNotify, useToast };
28
+ export { NotificationHandle, type NotificationOptions, type NotificationPosition, type NotificationType, setNotify, useToast };
32
29
  //# sourceMappingURL=useToast.d.cts.map
@@ -1,12 +1,10 @@
1
- import { VIEWS } from "@n8n/frontend-constants/views";
2
- import { NotificationOptions } from "@n8n/stores/notifications.store";
1
+ import { n as NotificationPosition, r as NotificationType, t as NotificationOptions } from "./notification.mjs";
3
2
 
4
3
  //#region src/useToast.d.ts
5
4
  interface NotificationHandle {
6
5
  close: () => void;
7
6
  }
8
- type NotificationType = '' | 'success' | 'warning' | 'info' | 'error';
9
- type NotifyFn = (options: Record<string, unknown>) => NotificationHandle;
7
+ type NotifyFn = (options: Record<string, unknown>) => NotificationHandle | undefined;
10
8
  declare function setNotify(fn: NotifyFn): void;
11
9
  declare function useToast(): {
12
10
  showMessage: (messageData: Partial<NotificationOptions>, track?: boolean) => NotificationHandle;
@@ -25,8 +23,7 @@ declare function useToast(): {
25
23
  description?: string;
26
24
  }) => void;
27
25
  clearAllStickyNotifications: () => void;
28
- showNotificationForViews: (views: VIEWS[]) => void;
29
26
  };
30
27
  //#endregion
31
- export { NotificationHandle, NotificationType, setNotify, useToast };
28
+ export { NotificationHandle, type NotificationOptions, type NotificationPosition, type NotificationType, setNotify, useToast };
32
29
  //# sourceMappingURL=useToast.d.mts.map
package/dist/useToast.mjs CHANGED
@@ -1,29 +1,41 @@
1
1
  import { r as useExternalHooks } from "./useExternalHooks2.mjs";
2
- import { r as useTelemetry } from "./useTelemetry2.mjs";
2
+ import "./telemetryRegistry.mjs";
3
+ import { t as useTelemetry } from "./useTelemetry2.mjs";
3
4
  import { computed } from "vue";
4
5
  import { APP_Z_INDEXES } from "@n8n/frontend-constants/z-indexes";
5
6
  import { VIEWS } from "@n8n/frontend-constants/views";
6
7
  import { sanitizeHtml } from "@n8n/frontend-utils/htmlUtils";
7
8
  import { useI18n } from "@n8n/i18n";
8
- import { useNotificationsStore } from "@n8n/stores/notifications.store";
9
9
  import { useRoute } from "vue-router";
10
10
 
11
11
  //#region src/useToast.ts
12
12
  let registeredNotify;
13
13
  /**
14
14
  * Register the notification function. Called once at bootstrap by
15
- * `editor-ui` (passing `ElNotification` from element-plus) so `useToast`
16
- * can issue notifications without importing element-plus directly — keeping
17
- * the DTS build lightweight.
15
+ * `editor-ui` (passing a suppression-aware wrapper around `ElNotification`) so
16
+ * `useToast` can issue notifications without importing element-plus directly —
17
+ * keeping the DTS build lightweight.
18
+ *
19
+ * This is the *only* toast dependency the app registers. Whether a notification
20
+ * is actually shown is the notifier's decision, so if you are chasing a toast
21
+ * that never appeared, look at the registration site, not here.
18
22
  */
19
23
  function setNotify(fn) {
20
24
  registeredNotify = fn;
21
25
  }
22
26
  const noopHandle = { close() {} };
23
27
  const noopNotify = () => noopHandle;
28
+ let warnedAboutMissingNotify = false;
29
+ function resolveNotify() {
30
+ if (registeredNotify) return registeredNotify;
31
+ if (import.meta.env.DEV && !warnedAboutMissingNotify) {
32
+ warnedAboutMissingNotify = true;
33
+ console.warn("[useToast] No notification function registered; toasts will not render. Call setNotify() at app bootstrap.");
34
+ }
35
+ return noopNotify;
36
+ }
24
37
  const stickyNotificationQueue = [];
25
38
  function useToast() {
26
- const notify = registeredNotify ?? noopNotify;
27
39
  const telemetry = useTelemetry();
28
40
  const route = useRoute();
29
41
  const workflowId = computed(() => {
@@ -31,7 +43,6 @@ function useToast() {
31
43
  const id = route?.params?.workflowId;
32
44
  return (Array.isArray(id) ? id[0] : id) ?? "";
33
45
  });
34
- const notificationsStore = useNotificationsStore();
35
46
  const externalHooks = useExternalHooks();
36
47
  const i18n = useI18n();
37
48
  function causedByCredential(message) {
@@ -39,9 +50,7 @@ function useToast() {
39
50
  return message.includes("Credentials for") && message.includes("are not set");
40
51
  }
41
52
  function showMessage(messageData, track = true) {
42
- const suppressed = notificationsStore.areNotificationsSuppressed;
43
- const allowErrors = notificationsStore.allowErrorNotificationsWhenSuppressed;
44
- if (suppressed && !(allowErrors && messageData.type === "error")) return { close: () => {} };
53
+ const notify = resolveNotify();
45
54
  const messageDefaults = {
46
55
  dangerouslyUseHTMLString: true,
47
56
  position: "bottom-right",
@@ -57,6 +66,7 @@ function useToast() {
57
66
  if (typeof message === "string") params.message = sanitizeHtml(message);
58
67
  if (typeof title === "string") params.title = sanitizeHtml(title);
59
68
  const notification = notify(params);
69
+ if (!notification) return noopHandle;
60
70
  if (params.duration === 0) stickyNotificationQueue.push(notification);
61
71
  if (params.type === "error" && track) {
62
72
  let messageForTelemetry;
@@ -145,26 +155,11 @@ function useToast() {
145
155
  });
146
156
  stickyNotificationQueue.length = 0;
147
157
  }
148
- function showNotificationForViews(views) {
149
- const notifications = [];
150
- views.forEach((view) => {
151
- notifications.push(...notificationsStore.pendingNotificationsForViews[view] ?? []);
152
- });
153
- if (notifications.length) {
154
- notifications.forEach((notification) => {
155
- setTimeout(() => {
156
- showMessage(notification);
157
- }, 5);
158
- });
159
- notificationsStore.setNotificationsForView(VIEWS.WORKFLOW, []);
160
- }
161
- }
162
158
  return {
163
159
  showMessage,
164
160
  showToast,
165
161
  showError,
166
- clearAllStickyNotifications,
167
- showNotificationForViews
162
+ clearAllStickyNotifications
168
163
  };
169
164
  }
170
165
 
@@ -1 +1 @@
1
- {"version":3,"file":"useToast.mjs","names":["registeredNotify: NotifyFn | undefined","noopHandle: NotificationHandle","noopNotify: NotifyFn","stickyNotificationQueue: NotificationHandle[]","messageDefaults: Partial<Omit<NotificationOptions, 'message'>>","messageForTelemetry: string","notification: NotificationHandle","notifications: NotificationOptions[]"],"sources":["../src/useToast.ts"],"sourcesContent":["import { VIEWS } from '@n8n/frontend-constants/views';\nimport { APP_Z_INDEXES } from '@n8n/frontend-constants/z-indexes';\nimport { sanitizeHtml } from '@n8n/frontend-utils/htmlUtils';\nimport { useI18n } from '@n8n/i18n';\nimport type { NotificationOptions } from '@n8n/stores/notifications.store';\nimport { useNotificationsStore } from '@n8n/stores/notifications.store';\nimport { computed } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport { useExternalHooks } from './useExternalHooks';\nimport { useTelemetry } from './useTelemetry';\n\n/**\n * Handle returned by the notification function. Declared locally so the DTS\n * build stays free of the full element-plus type graph.\n */\nexport interface NotificationHandle {\n\tclose: () => void;\n}\n\n/** Notification severity — mirrors `MessageBoxState['type']` from element-plus. */\nexport type NotificationType = '' | 'success' | 'warning' | 'info' | 'error';\n\n/**\n * Notification function contract — matches `ElNotification` from element-plus.\n * The application registers the concrete implementation at bootstrap via\n * {@link setNotify}; this package owns only the contract.\n */\ntype NotifyFn = (options: Record<string, unknown>) => NotificationHandle;\n\nlet registeredNotify: NotifyFn | undefined;\n\n/**\n * Register the notification function. Called once at bootstrap by\n * `editor-ui` (passing `ElNotification` from element-plus) so `useToast`\n * can issue notifications without importing element-plus directly — keeping\n * the DTS build lightweight.\n */\nexport function setNotify(fn: NotifyFn): void {\n\tregisteredNotify = fn;\n}\n\nconst noopHandle: NotificationHandle = { close() {} };\nconst noopNotify: NotifyFn = () => noopHandle;\n\nconst stickyNotificationQueue: NotificationHandle[] = [];\n\nexport function useToast() {\n\tconst notify = registeredNotify ?? noopNotify;\n\tconst telemetry = useTelemetry();\n\tconst route = useRoute();\n\tconst workflowId = computed(() => {\n\t\tif (route?.name === VIEWS.DEMO || route?.name === VIEWS.DEMO_DIFF) return 'demo';\n\t\tconst id = route?.params?.workflowId;\n\t\treturn (Array.isArray(id) ? id[0] : id) ?? '';\n\t});\n\tconst notificationsStore = useNotificationsStore();\n\tconst externalHooks = useExternalHooks();\n\tconst i18n = useI18n();\n\n\tfunction causedByCredential(message: string | undefined) {\n\t\tif (!message || typeof message !== 'string') return false;\n\n\t\treturn message.includes('Credentials for') && message.includes('are not set');\n\t}\n\n\tfunction showMessage(messageData: Partial<NotificationOptions>, track = true) {\n\t\tconst suppressed = notificationsStore.areNotificationsSuppressed;\n\t\tconst allowErrors = notificationsStore.allowErrorNotificationsWhenSuppressed;\n\t\tif (suppressed && !(allowErrors && messageData.type === 'error')) {\n\t\t\treturn { close: () => {} } as NotificationHandle;\n\t\t}\n\n\t\tconst messageDefaults: Partial<Omit<NotificationOptions, 'message'>> = {\n\t\t\tdangerouslyUseHTMLString: true,\n\t\t\tposition: 'bottom-right',\n\t\t\t// Layer above NDV and modal overlays, sourced from the shared scale.\n\t\t\tzIndex: APP_Z_INDEXES.TOASTS,\n\t\t\tappendTo: '#n8n-app',\n\t\t\tcustomClass: 'content-toast',\n\t\t};\n\t\tconst { message, title } = messageData;\n\t\tconst params = { ...messageDefaults, ...messageData };\n\n\t\tif (typeof message === 'string') {\n\t\t\tparams.message = sanitizeHtml(message);\n\t\t}\n\n\t\tif (typeof title === 'string') {\n\t\t\tparams.title = sanitizeHtml(title);\n\t\t}\n\n\t\tconst notification = notify(params as unknown as Record<string, unknown>);\n\n\t\tif (params.duration === 0) {\n\t\t\tstickyNotificationQueue.push(notification);\n\t\t}\n\n\t\tif (params.type === 'error' && track) {\n\t\t\t// Extract string message for telemetry - don't send VNode objects as they have circular refs\n\t\t\tlet messageForTelemetry: string;\n\t\t\tif (typeof params.message === 'string') {\n\t\t\t\tmessageForTelemetry = params.message;\n\t\t\t} else if (\n\t\t\t\tparams.message &&\n\t\t\t\ttypeof params.message === 'object' &&\n\t\t\t\t'props' in params.message &&\n\t\t\t\tparams.message.props\n\t\t\t) {\n\t\t\t\t// Extract error message from VNode props (e.g., NodeExecutionErrorMessage component)\n\t\t\t\tconst props = params.message.props;\n\t\t\t\tconst hasErrorMessage =\n\t\t\t\t\ttypeof props === 'object' && props !== null && 'errorMessage' in props;\n\t\t\t\tconst hasMessage = typeof props === 'object' && props !== null && 'message' in props;\n\n\t\t\t\tif (hasErrorMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.errorMessage);\n\t\t\t\t} else if (hasMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.message);\n\t\t\t\t} else {\n\t\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t}\n\n\t\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\t\terror_title: params.title,\n\t\t\t\terror_message: messageForTelemetry,\n\t\t\t\tcaused_by_credential: causedByCredential(messageForTelemetry),\n\t\t\t\tworkflow_id: workflowId.value,\n\t\t\t});\n\t\t}\n\n\t\treturn notification;\n\t}\n\n\tfunction showToast(config: {\n\t\ttitle: string;\n\t\tmessage: NotificationOptions['message'];\n\t\tonClick?: (event?: MouseEvent) => void;\n\t\tonClose?: () => void;\n\t\tduration?: number;\n\t\tcustomClass?: string;\n\t\tcloseOnClick?: boolean;\n\t\ttype?: NotificationType;\n\t}) {\n\t\t// eslint-disable-next-line prefer-const\n\t\tlet notification: NotificationHandle;\n\t\tif (config.closeOnClick) {\n\t\t\tconst originalOnClick = config.onClick;\n\t\t\tconfig.onClick = () => {\n\t\t\t\tif (notification) {\n\t\t\t\t\tnotification.close();\n\t\t\t\t}\n\n\t\t\t\tif (originalOnClick) {\n\t\t\t\t\toriginalOnClick();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tnotification = showMessage({\n\t\t\ttitle: config.title,\n\t\t\tmessage: config.message,\n\t\t\tonClick: config.onClick,\n\t\t\tonClose: config.onClose,\n\t\t\tduration: config.duration,\n\t\t\tcustomClass: config.customClass,\n\t\t\ttype: config.type,\n\t\t});\n\n\t\treturn notification;\n\t}\n\n\tfunction collapsableDetails(description: string) {\n\t\tconst errorDescription =\n\t\t\tdescription.length > 500 ? `${description.slice(0, 500)}...` : description;\n\n\t\treturn `\n\t\t\t\t<br>\n\t\t\t\t<br>\n\t\t\t\t<details>\n\t\t\t\t\t<summary\n\t\t\t\t\t\tstyle=\"color: #ff6d5a; font-weight: bold; cursor: pointer;\"\n\t\t\t\t\t>\n\t\t\t\t\t\t${i18n.baseText('showMessage.showDetails')}\n\t\t\t\t\t</summary>\n\t\t\t\t\t<p>${errorDescription}</p>\n\t\t\t\t</details>\n\t\t\t`;\n\t}\n\n\tfunction showError(\n\t\te: unknown,\n\t\ttitle: string,\n\t\toptions?: { message?: string; description?: string },\n\t) {\n\t\tconst error = e as Error & { description?: string };\n\t\tconst message = options?.message;\n\t\tconst description = options?.description ?? error.description;\n\t\tconst messageLine = message ? `${message}<br/>` : '';\n\t\tshowMessage(\n\t\t\t{\n\t\t\t\ttitle,\n\t\t\t\tmessage: `\n\t\t\t\t\t${messageLine}\n\t\t\t\t\t<i>${error.message}</i>\n\t\t\t\t\t${description ? collapsableDetails(description) : ''}`,\n\t\t\t\ttype: 'error',\n\t\t\t\tduration: 0,\n\t\t\t},\n\t\t\tfalse,\n\t\t);\n\n\t\tvoid externalHooks.run('showMessage.showError', {\n\t\t\ttitle,\n\t\t\tmessage,\n\t\t\terrorMessage: error.message,\n\t\t});\n\n\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\terror_title: title,\n\t\t\terror_description: message,\n\t\t\terror_message: error.message,\n\t\t\tcaused_by_credential: causedByCredential(error.message),\n\t\t\tworkflow_id: workflowId.value,\n\t\t});\n\t}\n\n\tfunction clearAllStickyNotifications() {\n\t\tstickyNotificationQueue.forEach((notification) => {\n\t\t\tif (notification) {\n\t\t\t\tnotification.close();\n\t\t\t}\n\t\t});\n\n\t\tstickyNotificationQueue.length = 0;\n\t}\n\n\t// Pick up and display notifications for the given list of views\n\tfunction showNotificationForViews(views: VIEWS[]) {\n\t\tconst notifications: NotificationOptions[] = [];\n\t\tviews.forEach((view) => {\n\t\t\tnotifications.push(...(notificationsStore.pendingNotificationsForViews[view] ?? []));\n\t\t});\n\t\tif (notifications.length) {\n\t\t\tnotifications.forEach((notification) => {\n\t\t\t\t// Notifications show on top of each other without this timeout\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tshowMessage(notification);\n\t\t\t\t}, 5);\n\t\t\t});\n\t\t\t// Clear the queue once all notifications are shown\n\t\t\tnotificationsStore.setNotificationsForView(VIEWS.WORKFLOW, []);\n\t\t}\n\t}\n\n\treturn {\n\t\tshowMessage,\n\t\tshowToast,\n\t\tshowError,\n\t\tclearAllStickyNotifications,\n\t\tshowNotificationForViews,\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useToast.mjs","names":["registeredNotify: NotifyFn | undefined","noopHandle: NotificationHandle","noopNotify: NotifyFn","stickyNotificationQueue: NotificationHandle[]","messageDefaults: Partial<Omit<NotificationOptions, 'message'>>","messageForTelemetry: string","notification: NotificationHandle"],"sources":["../src/useToast.ts"],"sourcesContent":["import { VIEWS } from '@n8n/frontend-constants/views';\nimport { APP_Z_INDEXES } from '@n8n/frontend-constants/z-indexes';\nimport { sanitizeHtml } from '@n8n/frontend-utils/htmlUtils';\nimport { useI18n } from '@n8n/i18n';\nimport { computed } from 'vue';\nimport { useRoute } from 'vue-router';\n\nimport type { NotificationOptions, NotificationType } from './types/notification';\nimport { useExternalHooks } from './useExternalHooks';\nimport { useTelemetry } from './useTelemetry';\n\nexport type {\n\tNotificationOptions,\n\tNotificationPosition,\n\tNotificationType,\n} from './types/notification';\n\n/**\n * Handle returned by the notification function. Declared locally so the DTS\n * build stays free of the full element-plus type graph.\n */\nexport interface NotificationHandle {\n\tclose: () => void;\n}\n\n/**\n * Notification function contract — the app's wrapper around `ElNotification`.\n * Registered at bootstrap via {@link setNotify}; this package owns only the\n * contract.\n *\n * Returning `undefined` means the app declined to show this notification — today\n * that is notification suppression, which lives at the registration site rather\n * than here. `showMessage` treats it as \"dropped\": no sticky-queue\n * entry, no error telemetry, and a no-op handle to the caller.\n */\ntype NotifyFn = (options: Record<string, unknown>) => NotificationHandle | undefined;\n\nlet registeredNotify: NotifyFn | undefined;\n\n/**\n * Register the notification function. Called once at bootstrap by\n * `editor-ui` (passing a suppression-aware wrapper around `ElNotification`) so\n * `useToast` can issue notifications without importing element-plus directly —\n * keeping the DTS build lightweight.\n *\n * This is the *only* toast dependency the app registers. Whether a notification\n * is actually shown is the notifier's decision, so if you are chasing a toast\n * that never appeared, look at the registration site, not here.\n */\nexport function setNotify(fn: NotifyFn): void {\n\tregisteredNotify = fn;\n}\n\nconst noopHandle: NotificationHandle = { close() {} };\nconst noopNotify: NotifyFn = () => noopHandle;\n\nlet warnedAboutMissingNotify = false;\n\nfunction resolveNotify(): NotifyFn {\n\tif (registeredNotify) return registeredNotify;\n\n\t// Falling back means bootstrap never registered. The toast is dropped rather\n\t// than shown, so warn once in dev instead of failing silent.\n\tif (import.meta.env.DEV && !warnedAboutMissingNotify) {\n\t\twarnedAboutMissingNotify = true;\n\t\tconsole.warn(\n\t\t\t'[useToast] No notification function registered; toasts will not render. Call setNotify() at app bootstrap.',\n\t\t);\n\t}\n\treturn noopNotify;\n}\n\nconst stickyNotificationQueue: NotificationHandle[] = [];\n\nexport function useToast() {\n\tconst telemetry = useTelemetry();\n\tconst route = useRoute();\n\tconst workflowId = computed(() => {\n\t\tif (route?.name === VIEWS.DEMO || route?.name === VIEWS.DEMO_DIFF) return 'demo';\n\t\tconst id = route?.params?.workflowId;\n\t\treturn (Array.isArray(id) ? id[0] : id) ?? '';\n\t});\n\tconst externalHooks = useExternalHooks();\n\tconst i18n = useI18n();\n\n\tfunction causedByCredential(message: string | undefined) {\n\t\tif (!message || typeof message !== 'string') return false;\n\n\t\treturn message.includes('Credentials for') && message.includes('are not set');\n\t}\n\n\tfunction showMessage(messageData: Partial<NotificationOptions>, track = true) {\n\t\t// Resolved per call, not once per `useToast()`: a composable captured before\n\t\t// bootstrap registers would otherwise stay bound to the no-op for its whole\n\t\t// lifetime, silently dropping toasts.\n\t\tconst notify = resolveNotify();\n\n\t\tconst messageDefaults: Partial<Omit<NotificationOptions, 'message'>> = {\n\t\t\tdangerouslyUseHTMLString: true,\n\t\t\tposition: 'bottom-right',\n\t\t\t// Layer above NDV and modal overlays, sourced from the shared scale.\n\t\t\tzIndex: APP_Z_INDEXES.TOASTS,\n\t\t\tappendTo: '#n8n-app',\n\t\t\tcustomClass: 'content-toast',\n\t\t};\n\t\tconst { message, title } = messageData;\n\t\tconst params = { ...messageDefaults, ...messageData };\n\n\t\tif (typeof message === 'string') {\n\t\t\tparams.message = sanitizeHtml(message);\n\t\t}\n\n\t\tif (typeof title === 'string') {\n\t\t\tparams.title = sanitizeHtml(title);\n\t\t}\n\n\t\tconst notification = notify(params as unknown as Record<string, unknown>);\n\n\t\t// The app declined to show it (suppression). Return before the sticky queue\n\t\t// and before error telemetry, so a dropped toast leaves no trace — exactly\n\t\t// what the removed in-package suppression branch did.\n\t\tif (!notification) return noopHandle;\n\n\t\tif (params.duration === 0) {\n\t\t\tstickyNotificationQueue.push(notification);\n\t\t}\n\n\t\tif (params.type === 'error' && track) {\n\t\t\t// Extract string message for telemetry - don't send VNode objects as they have circular refs\n\t\t\tlet messageForTelemetry: string;\n\t\t\tif (typeof params.message === 'string') {\n\t\t\t\tmessageForTelemetry = params.message;\n\t\t\t} else if (\n\t\t\t\tparams.message &&\n\t\t\t\ttypeof params.message === 'object' &&\n\t\t\t\t'props' in params.message &&\n\t\t\t\tparams.message.props\n\t\t\t) {\n\t\t\t\t// Extract error message from VNode props (e.g., NodeExecutionErrorMessage component)\n\t\t\t\tconst props = params.message.props;\n\t\t\t\tconst hasErrorMessage =\n\t\t\t\t\ttypeof props === 'object' && props !== null && 'errorMessage' in props;\n\t\t\t\tconst hasMessage = typeof props === 'object' && props !== null && 'message' in props;\n\n\t\t\t\tif (hasErrorMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.errorMessage);\n\t\t\t\t} else if (hasMessage) {\n\t\t\t\t\tmessageForTelemetry = String(props.message);\n\t\t\t\t} else {\n\t\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmessageForTelemetry = 'Unknown error';\n\t\t\t}\n\n\t\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\t\terror_title: params.title,\n\t\t\t\terror_message: messageForTelemetry,\n\t\t\t\tcaused_by_credential: causedByCredential(messageForTelemetry),\n\t\t\t\tworkflow_id: workflowId.value,\n\t\t\t});\n\t\t}\n\n\t\treturn notification;\n\t}\n\n\tfunction showToast(config: {\n\t\ttitle: string;\n\t\tmessage: NotificationOptions['message'];\n\t\tonClick?: (event?: MouseEvent) => void;\n\t\tonClose?: () => void;\n\t\tduration?: number;\n\t\tcustomClass?: string;\n\t\tcloseOnClick?: boolean;\n\t\ttype?: NotificationType;\n\t}) {\n\t\t// eslint-disable-next-line prefer-const\n\t\tlet notification: NotificationHandle;\n\t\tif (config.closeOnClick) {\n\t\t\tconst originalOnClick = config.onClick;\n\t\t\tconfig.onClick = () => {\n\t\t\t\tif (notification) {\n\t\t\t\t\tnotification.close();\n\t\t\t\t}\n\n\t\t\t\tif (originalOnClick) {\n\t\t\t\t\toriginalOnClick();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tnotification = showMessage({\n\t\t\ttitle: config.title,\n\t\t\tmessage: config.message,\n\t\t\tonClick: config.onClick,\n\t\t\tonClose: config.onClose,\n\t\t\tduration: config.duration,\n\t\t\tcustomClass: config.customClass,\n\t\t\ttype: config.type,\n\t\t});\n\n\t\treturn notification;\n\t}\n\n\tfunction collapsableDetails(description: string) {\n\t\tconst errorDescription =\n\t\t\tdescription.length > 500 ? `${description.slice(0, 500)}...` : description;\n\n\t\treturn `\n\t\t\t\t<br>\n\t\t\t\t<br>\n\t\t\t\t<details>\n\t\t\t\t\t<summary\n\t\t\t\t\t\tstyle=\"color: #ff6d5a; font-weight: bold; cursor: pointer;\"\n\t\t\t\t\t>\n\t\t\t\t\t\t${i18n.baseText('showMessage.showDetails')}\n\t\t\t\t\t</summary>\n\t\t\t\t\t<p>${errorDescription}</p>\n\t\t\t\t</details>\n\t\t\t`;\n\t}\n\n\tfunction showError(\n\t\te: unknown,\n\t\ttitle: string,\n\t\toptions?: { message?: string; description?: string },\n\t) {\n\t\tconst error = e as Error & { description?: string };\n\t\tconst message = options?.message;\n\t\tconst description = options?.description ?? error.description;\n\t\tconst messageLine = message ? `${message}<br/>` : '';\n\t\tshowMessage(\n\t\t\t{\n\t\t\t\ttitle,\n\t\t\t\tmessage: `\n\t\t\t\t\t${messageLine}\n\t\t\t\t\t<i>${error.message}</i>\n\t\t\t\t\t${description ? collapsableDetails(description) : ''}`,\n\t\t\t\ttype: 'error',\n\t\t\t\tduration: 0,\n\t\t\t},\n\t\t\tfalse,\n\t\t);\n\n\t\tvoid externalHooks.run('showMessage.showError', {\n\t\t\ttitle,\n\t\t\tmessage,\n\t\t\terrorMessage: error.message,\n\t\t});\n\n\t\ttelemetry.track('Instance FE emitted error', {\n\t\t\terror_title: title,\n\t\t\terror_description: message,\n\t\t\terror_message: error.message,\n\t\t\tcaused_by_credential: causedByCredential(error.message),\n\t\t\tworkflow_id: workflowId.value,\n\t\t});\n\t}\n\n\tfunction clearAllStickyNotifications() {\n\t\tstickyNotificationQueue.forEach((notification) => {\n\t\t\tif (notification) {\n\t\t\t\tnotification.close();\n\t\t\t}\n\t\t});\n\n\t\tstickyNotificationQueue.length = 0;\n\t}\n\n\treturn {\n\t\tshowMessage,\n\t\tshowToast,\n\t\tshowError,\n\t\tclearAllStickyNotifications,\n\t};\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@n8n/composables",
3
3
  "type": "module",
4
- "version": "1.23.0",
4
+ "version": "1.24.0",
5
5
  "files": [
6
6
  "dist",
7
- "LICENSE_EE.md",
8
- "LICENSE.md"
7
+ "LICENSE.md",
8
+ "LICENSE_EE.md"
9
9
  ],
10
10
  "exports": {
11
11
  "./*": {
@@ -19,12 +19,11 @@
19
19
  "lodash": "4.18.1",
20
20
  "vue": "^3.5.13",
21
21
  "vue-router": "^4.5.0",
22
- "@n8n/frontend-constants": "0.2.0",
22
+ "@n8n/api-types": "1.34.0",
23
+ "@n8n/frontend-constants": "0.3.0",
23
24
  "@n8n/frontend-utils": "0.2.0",
24
- "@n8n/api-types": "1.33.0",
25
- "@n8n/i18n": "2.33.0",
26
- "@n8n/stores": "2.33.0",
27
- "n8n-workflow": "2.33.0"
25
+ "@n8n/i18n": "2.34.0",
26
+ "n8n-workflow": "2.34.0"
28
27
  },
29
28
  "devDependencies": {
30
29
  "@pinia/testing": "^0.1.6",
@@ -42,9 +41,9 @@
42
41
  "vitest": "^4.1.9",
43
42
  "vue-tsc": "^2.2.8",
44
43
  "@n8n/eslint-config": "0.0.1",
45
- "@n8n/telemetry": "1.1.0",
46
- "@n8n/vitest-config": "1.19.0",
47
44
  "@n8n/playwright-janitor": "0.1.0",
45
+ "@n8n/telemetry": "1.2.0",
46
+ "@n8n/vitest-config": "1.19.0",
48
47
  "@n8n/typescript-config": "1.9.0"
49
48
  },
50
49
  "license": "SEE LICENSE IN LICENSE.md",