@humeai/voice-embed-react 0.0.0-beta.20 → 0.0.0-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,7 +57,6 @@ function App() {
57
57
  <button onClick={() => setIsEmbedOpen(true)}>Open Widget</button>
58
58
  <EmbeddedVoice
59
59
  auth={{ type: 'apiKey', value: apiKey }}
60
- systemPrompt={'Your system prompt goes here.'}
61
60
  onMessage={(msg) => console.log('Message received: ', msg)}
62
61
  onClose={() => setIsEmbedOpen(false)}
63
62
  isEmbedOpen={isEmbedOpen}
@@ -84,7 +83,6 @@ The table below outlines the props accepted by the EmbeddedVoice component:
84
83
  | tts | no | Text-To-Speech service. If not provided this value will default to `"hume_ai"`, specifying Hume's text-to-speech service. Other options include: `"eleven_labs"` and `"play_ht"`. |
85
84
  | reconnectAttempts | no | Number of times to attempt to reconnect to the API. If not provided this value will default to `30`. |
86
85
  | debug | no | Enable debug mode. If not provided this value will default to `false`. |
87
- | systemPrompt | no | System prompt to use for the Voice. The system prompt has a character limit of 100,000 characters. If not provided, this value will default to the default Hume system prompt. |
88
86
  | onMessage | no | Callback function to invoke upon receiving a message through the web socket. |
89
87
  | onClose | no | Callback function to invoke upon the web socket connection being closed. |
90
88
 
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { EmbeddedVoiceConfig, TranscriptMessageHandler, CloseHandler } from '@humeai/voice-embed';
2
- export { AssistantTranscriptMessage, COLLAPSE_WIDGET_ACTION, Config, EXPAND_WIDGET_ACTION, EmotionScores, FrameToClientAction, JSONMessage, LanguageModelOption, MINIMIZE_WIDGET_ACTION, RESIZE_FRAME_ACTION, TRANSCRIPT_MESSAGE_ACTION, UserTranscriptMessage, WIDGET_IFRAME_IS_READY_ACTION, WindowDimensions, parseClientToFrameAction } from '@humeai/voice-embed';
2
+ export { AssistantTranscriptMessage, COLLAPSE_WIDGET_ACTION, EXPAND_WIDGET_ACTION, EmotionScores, FrameToClientAction, JSONMessage, LanguageModelOption, MINIMIZE_WIDGET_ACTION, RESIZE_FRAME_ACTION, SocketConfig, TRANSCRIPT_MESSAGE_ACTION, UserTranscriptMessage, WIDGET_IFRAME_IS_READY_ACTION, WindowDimensions, parseClientToFrameAction } from '@humeai/voice-embed';
3
3
 
4
4
  type EmbeddedVoiceProps = Partial<EmbeddedVoiceConfig> & NonNullable<Pick<EmbeddedVoiceConfig, 'auth'>> & {
5
5
  onMessage?: TranscriptMessageHandler;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { EmbeddedVoiceConfig, TranscriptMessageHandler, CloseHandler } from '@humeai/voice-embed';
2
- export { AssistantTranscriptMessage, COLLAPSE_WIDGET_ACTION, Config, EXPAND_WIDGET_ACTION, EmotionScores, FrameToClientAction, JSONMessage, LanguageModelOption, MINIMIZE_WIDGET_ACTION, RESIZE_FRAME_ACTION, TRANSCRIPT_MESSAGE_ACTION, UserTranscriptMessage, WIDGET_IFRAME_IS_READY_ACTION, WindowDimensions, parseClientToFrameAction } from '@humeai/voice-embed';
2
+ export { AssistantTranscriptMessage, COLLAPSE_WIDGET_ACTION, EXPAND_WIDGET_ACTION, EmotionScores, FrameToClientAction, JSONMessage, LanguageModelOption, MINIMIZE_WIDGET_ACTION, RESIZE_FRAME_ACTION, SocketConfig, TRANSCRIPT_MESSAGE_ACTION, UserTranscriptMessage, WIDGET_IFRAME_IS_READY_ACTION, WindowDimensions, parseClientToFrameAction } from '@humeai/voice-embed';
3
3
 
4
4
  type EmbeddedVoiceProps = Partial<EmbeddedVoiceConfig> & NonNullable<Pick<EmbeddedVoiceConfig, 'auth'>> & {
5
5
  onMessage?: TranscriptMessageHandler;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/lib/EmbeddedVoice.ts"],"sourcesContent":["export * from './lib/EmbeddedVoice';\n\nexport {\n COLLAPSE_WIDGET_ACTION,\n EXPAND_WIDGET_ACTION,\n MINIMIZE_WIDGET_ACTION,\n RESIZE_FRAME_ACTION,\n TRANSCRIPT_MESSAGE_ACTION,\n WIDGET_IFRAME_IS_READY_ACTION,\n parseClientToFrameAction,\n LanguageModelOption,\n} from '@humeai/voice-embed';\n\nexport type {\n AssistantTranscriptMessage,\n Config,\n FrameToClientAction,\n JSONMessage,\n UserTranscriptMessage,\n WindowDimensions,\n EmotionScores,\n} from '@humeai/voice-embed';\n","import {\n type CloseHandler,\n EmbeddedVoice as EA,\n type EmbeddedVoiceConfig,\n type TranscriptMessageHandler,\n} from '@humeai/voice-embed';\nimport { useEffect, useRef } from 'react';\n\ntype EmbeddedVoiceProps = Partial<EmbeddedVoiceConfig> &\n NonNullable<Pick<EmbeddedVoiceConfig, 'auth'>> & {\n onMessage?: TranscriptMessageHandler;\n onClose?: CloseHandler;\n isEmbedOpen: boolean;\n openOnMount?: boolean;\n };\n\nexport const EmbeddedVoice = (props: EmbeddedVoiceProps) => {\n const {\n onMessage,\n isEmbedOpen,\n onClose,\n openOnMount = false,\n ...config\n } = props;\n const embeddedVoice = useRef<EA | null>(null);\n const onMessageHandler = useRef<TranscriptMessageHandler | undefined>();\n onMessageHandler.current = onMessage;\n\n const onCloseHandler = useRef<CloseHandler | undefined>();\n onCloseHandler.current = onClose;\n\n const stableConfig = useRef<\n Partial<EmbeddedVoiceConfig> &\n NonNullable<Pick<EmbeddedVoiceConfig, 'auth'>>\n >();\n stableConfig.current = config;\n\n useEffect(() => {\n let unmount: () => void;\n if (!embeddedVoice.current && stableConfig.current) {\n embeddedVoice.current = EA.create({\n onMessage: onMessageHandler.current,\n onClose: onCloseHandler.current,\n openOnMount: openOnMount,\n ...stableConfig.current,\n });\n unmount = embeddedVoice.current.mount();\n }\n\n return () => {\n unmount?.();\n embeddedVoice.current = null;\n };\n }, [openOnMount]);\n\n useEffect(() => {\n if (isEmbedOpen) {\n embeddedVoice.current?.openEmbed();\n }\n }, [isEmbedOpen]);\n\n return null;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,yBAKO;AACP,mBAAkC;AAU3B,IAAM,gBAAgB,CAAC,UAA8B;AAC1D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,oBAAgB,qBAAkB,IAAI;AAC5C,QAAM,uBAAmB,qBAA6C;AACtE,mBAAiB,UAAU;AAE3B,QAAM,qBAAiB,qBAAiC;AACxD,iBAAe,UAAU;AAEzB,QAAM,mBAAe,qBAGnB;AACF,eAAa,UAAU;AAEvB,8BAAU,MAAM;AACd,QAAI;AACJ,QAAI,CAAC,cAAc,WAAW,aAAa,SAAS;AAClD,oBAAc,UAAU,mBAAAA,cAAG,OAAO;AAAA,QAChC,WAAW,iBAAiB;AAAA,QAC5B,SAAS,eAAe;AAAA,QACxB;AAAA,QACA,GAAG,aAAa;AAAA,MAClB,CAAC;AACD,gBAAU,cAAc,QAAQ,MAAM;AAAA,IACxC;AAEA,WAAO,MAAM;AACX,gBAAU;AACV,oBAAc,UAAU;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,8BAAU,MAAM;AACd,QAAI,aAAa;AACf,oBAAc,SAAS,UAAU;AAAA,IACnC;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,SAAO;AACT;;;AD5DA,IAAAC,sBASO;","names":["EA","import_voice_embed"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/lib/EmbeddedVoice.ts"],"sourcesContent":["export * from './lib/EmbeddedVoice';\n\nexport {\n COLLAPSE_WIDGET_ACTION,\n EXPAND_WIDGET_ACTION,\n MINIMIZE_WIDGET_ACTION,\n RESIZE_FRAME_ACTION,\n TRANSCRIPT_MESSAGE_ACTION,\n WIDGET_IFRAME_IS_READY_ACTION,\n parseClientToFrameAction,\n LanguageModelOption,\n} from '@humeai/voice-embed';\n\nexport type {\n AssistantTranscriptMessage,\n SocketConfig,\n FrameToClientAction,\n JSONMessage,\n UserTranscriptMessage,\n WindowDimensions,\n EmotionScores,\n} from '@humeai/voice-embed';\n","import {\n type CloseHandler,\n EmbeddedVoice as EA,\n type EmbeddedVoiceConfig,\n type TranscriptMessageHandler,\n} from '@humeai/voice-embed';\nimport { useEffect, useRef } from 'react';\n\ntype EmbeddedVoiceProps = Partial<EmbeddedVoiceConfig> &\n NonNullable<Pick<EmbeddedVoiceConfig, 'auth'>> & {\n onMessage?: TranscriptMessageHandler;\n onClose?: CloseHandler;\n isEmbedOpen: boolean;\n openOnMount?: boolean;\n };\n\nexport const EmbeddedVoice = (props: EmbeddedVoiceProps) => {\n const {\n onMessage,\n isEmbedOpen,\n onClose,\n openOnMount = false,\n ...config\n } = props;\n const embeddedVoice = useRef<EA | null>(null);\n const onMessageHandler = useRef<TranscriptMessageHandler | undefined>();\n onMessageHandler.current = onMessage;\n\n const onCloseHandler = useRef<CloseHandler | undefined>();\n onCloseHandler.current = onClose;\n\n const stableConfig = useRef<\n Partial<EmbeddedVoiceConfig> &\n NonNullable<Pick<EmbeddedVoiceConfig, 'auth'>>\n >();\n stableConfig.current = config;\n\n useEffect(() => {\n let unmount: () => void;\n if (!embeddedVoice.current && stableConfig.current) {\n embeddedVoice.current = EA.create({\n onMessage: onMessageHandler.current,\n onClose: onCloseHandler.current,\n openOnMount: openOnMount,\n ...stableConfig.current,\n });\n unmount = embeddedVoice.current.mount();\n }\n\n return () => {\n unmount?.();\n embeddedVoice.current = null;\n };\n }, [openOnMount]);\n\n useEffect(() => {\n if (isEmbedOpen) {\n embeddedVoice.current?.openEmbed();\n }\n }, [isEmbedOpen]);\n\n return null;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,yBAKO;AACP,mBAAkC;AAU3B,IAAM,gBAAgB,CAAC,UAA8B;AAC1D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,oBAAgB,qBAAkB,IAAI;AAC5C,QAAM,uBAAmB,qBAA6C;AACtE,mBAAiB,UAAU;AAE3B,QAAM,qBAAiB,qBAAiC;AACxD,iBAAe,UAAU;AAEzB,QAAM,mBAAe,qBAGnB;AACF,eAAa,UAAU;AAEvB,8BAAU,MAAM;AACd,QAAI;AACJ,QAAI,CAAC,cAAc,WAAW,aAAa,SAAS;AAClD,oBAAc,UAAU,mBAAAA,cAAG,OAAO;AAAA,QAChC,WAAW,iBAAiB;AAAA,QAC5B,SAAS,eAAe;AAAA,QACxB;AAAA,QACA,GAAG,aAAa;AAAA,MAClB,CAAC;AACD,gBAAU,cAAc,QAAQ,MAAM;AAAA,IACxC;AAEA,WAAO,MAAM;AACX,gBAAU;AACV,oBAAc,UAAU;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,8BAAU,MAAM;AACd,QAAI,aAAa;AACf,oBAAc,SAAS,UAAU;AAAA,IACnC;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,SAAO;AACT;;;AD5DA,IAAAC,sBASO;","names":["EA","import_voice_embed"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/EmbeddedVoice.ts","../src/index.ts"],"sourcesContent":["import {\n type CloseHandler,\n EmbeddedVoice as EA,\n type EmbeddedVoiceConfig,\n type TranscriptMessageHandler,\n} from '@humeai/voice-embed';\nimport { useEffect, useRef } from 'react';\n\ntype EmbeddedVoiceProps = Partial<EmbeddedVoiceConfig> &\n NonNullable<Pick<EmbeddedVoiceConfig, 'auth'>> & {\n onMessage?: TranscriptMessageHandler;\n onClose?: CloseHandler;\n isEmbedOpen: boolean;\n openOnMount?: boolean;\n };\n\nexport const EmbeddedVoice = (props: EmbeddedVoiceProps) => {\n const {\n onMessage,\n isEmbedOpen,\n onClose,\n openOnMount = false,\n ...config\n } = props;\n const embeddedVoice = useRef<EA | null>(null);\n const onMessageHandler = useRef<TranscriptMessageHandler | undefined>();\n onMessageHandler.current = onMessage;\n\n const onCloseHandler = useRef<CloseHandler | undefined>();\n onCloseHandler.current = onClose;\n\n const stableConfig = useRef<\n Partial<EmbeddedVoiceConfig> &\n NonNullable<Pick<EmbeddedVoiceConfig, 'auth'>>\n >();\n stableConfig.current = config;\n\n useEffect(() => {\n let unmount: () => void;\n if (!embeddedVoice.current && stableConfig.current) {\n embeddedVoice.current = EA.create({\n onMessage: onMessageHandler.current,\n onClose: onCloseHandler.current,\n openOnMount: openOnMount,\n ...stableConfig.current,\n });\n unmount = embeddedVoice.current.mount();\n }\n\n return () => {\n unmount?.();\n embeddedVoice.current = null;\n };\n }, [openOnMount]);\n\n useEffect(() => {\n if (isEmbedOpen) {\n embeddedVoice.current?.openEmbed();\n }\n }, [isEmbedOpen]);\n\n return null;\n};\n","export * from './lib/EmbeddedVoice';\n\nexport {\n COLLAPSE_WIDGET_ACTION,\n EXPAND_WIDGET_ACTION,\n MINIMIZE_WIDGET_ACTION,\n RESIZE_FRAME_ACTION,\n TRANSCRIPT_MESSAGE_ACTION,\n WIDGET_IFRAME_IS_READY_ACTION,\n parseClientToFrameAction,\n LanguageModelOption,\n} from '@humeai/voice-embed';\n\nexport type {\n AssistantTranscriptMessage,\n Config,\n FrameToClientAction,\n JSONMessage,\n UserTranscriptMessage,\n WindowDimensions,\n EmotionScores,\n} from '@humeai/voice-embed';\n"],"mappings":";;;AAAA;AAAA,EAEE,iBAAiB;AAAA,OAGZ;AACP,SAAS,WAAW,cAAc;AAU3B,IAAM,gBAAgB,CAAC,UAA8B;AAC1D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,gBAAgB,OAAkB,IAAI;AAC5C,QAAM,mBAAmB,OAA6C;AACtE,mBAAiB,UAAU;AAE3B,QAAM,iBAAiB,OAAiC;AACxD,iBAAe,UAAU;AAEzB,QAAM,eAAe,OAGnB;AACF,eAAa,UAAU;AAEvB,YAAU,MAAM;AACd,QAAI;AACJ,QAAI,CAAC,cAAc,WAAW,aAAa,SAAS;AAClD,oBAAc,UAAU,GAAG,OAAO;AAAA,QAChC,WAAW,iBAAiB;AAAA,QAC5B,SAAS,eAAe;AAAA,QACxB;AAAA,QACA,GAAG,aAAa;AAAA,MAClB,CAAC;AACD,gBAAU,cAAc,QAAQ,MAAM;AAAA,IACxC;AAEA,WAAO,MAAM;AACX,gBAAU;AACV,oBAAc,UAAU;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,YAAU,MAAM;AACd,QAAI,aAAa;AACf,oBAAc,SAAS,UAAU;AAAA,IACnC;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,SAAO;AACT;;;AC5DA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
1
+ {"version":3,"sources":["../src/lib/EmbeddedVoice.ts","../src/index.ts"],"sourcesContent":["import {\n type CloseHandler,\n EmbeddedVoice as EA,\n type EmbeddedVoiceConfig,\n type TranscriptMessageHandler,\n} from '@humeai/voice-embed';\nimport { useEffect, useRef } from 'react';\n\ntype EmbeddedVoiceProps = Partial<EmbeddedVoiceConfig> &\n NonNullable<Pick<EmbeddedVoiceConfig, 'auth'>> & {\n onMessage?: TranscriptMessageHandler;\n onClose?: CloseHandler;\n isEmbedOpen: boolean;\n openOnMount?: boolean;\n };\n\nexport const EmbeddedVoice = (props: EmbeddedVoiceProps) => {\n const {\n onMessage,\n isEmbedOpen,\n onClose,\n openOnMount = false,\n ...config\n } = props;\n const embeddedVoice = useRef<EA | null>(null);\n const onMessageHandler = useRef<TranscriptMessageHandler | undefined>();\n onMessageHandler.current = onMessage;\n\n const onCloseHandler = useRef<CloseHandler | undefined>();\n onCloseHandler.current = onClose;\n\n const stableConfig = useRef<\n Partial<EmbeddedVoiceConfig> &\n NonNullable<Pick<EmbeddedVoiceConfig, 'auth'>>\n >();\n stableConfig.current = config;\n\n useEffect(() => {\n let unmount: () => void;\n if (!embeddedVoice.current && stableConfig.current) {\n embeddedVoice.current = EA.create({\n onMessage: onMessageHandler.current,\n onClose: onCloseHandler.current,\n openOnMount: openOnMount,\n ...stableConfig.current,\n });\n unmount = embeddedVoice.current.mount();\n }\n\n return () => {\n unmount?.();\n embeddedVoice.current = null;\n };\n }, [openOnMount]);\n\n useEffect(() => {\n if (isEmbedOpen) {\n embeddedVoice.current?.openEmbed();\n }\n }, [isEmbedOpen]);\n\n return null;\n};\n","export * from './lib/EmbeddedVoice';\n\nexport {\n COLLAPSE_WIDGET_ACTION,\n EXPAND_WIDGET_ACTION,\n MINIMIZE_WIDGET_ACTION,\n RESIZE_FRAME_ACTION,\n TRANSCRIPT_MESSAGE_ACTION,\n WIDGET_IFRAME_IS_READY_ACTION,\n parseClientToFrameAction,\n LanguageModelOption,\n} from '@humeai/voice-embed';\n\nexport type {\n AssistantTranscriptMessage,\n SocketConfig,\n FrameToClientAction,\n JSONMessage,\n UserTranscriptMessage,\n WindowDimensions,\n EmotionScores,\n} from '@humeai/voice-embed';\n"],"mappings":";;;AAAA;AAAA,EAEE,iBAAiB;AAAA,OAGZ;AACP,SAAS,WAAW,cAAc;AAU3B,IAAM,gBAAgB,CAAC,UAA8B;AAC1D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,gBAAgB,OAAkB,IAAI;AAC5C,QAAM,mBAAmB,OAA6C;AACtE,mBAAiB,UAAU;AAE3B,QAAM,iBAAiB,OAAiC;AACxD,iBAAe,UAAU;AAEzB,QAAM,eAAe,OAGnB;AACF,eAAa,UAAU;AAEvB,YAAU,MAAM;AACd,QAAI;AACJ,QAAI,CAAC,cAAc,WAAW,aAAa,SAAS;AAClD,oBAAc,UAAU,GAAG,OAAO;AAAA,QAChC,WAAW,iBAAiB;AAAA,QAC5B,SAAS,eAAe;AAAA,QACxB;AAAA,QACA,GAAG,aAAa;AAAA,MAClB,CAAC;AACD,gBAAU,cAAc,QAAQ,MAAM;AAAA,IACxC;AAEA,WAAO,MAAM;AACX,gBAAU;AACV,oBAAc,UAAU;AAAA,IAC1B;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,YAAU,MAAM;AACd,QAAI,aAAa;AACf,oBAAc,SAAS,UAAU;AAAA,IACnC;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,SAAO;AACT;;;AC5DA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humeai/voice-embed-react",
3
- "version": "0.0.0-beta.20",
3
+ "version": "0.0.0-beta.22",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "react": "^18.2.0",
22
22
  "react-dom": "^18.2.0",
23
- "@humeai/voice-embed": "0.0.0-beta.20"
23
+ "@humeai/voice-embed": "0.0.0-beta.22"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@testing-library/react": "^14.2.2",
@@ -38,8 +38,8 @@
38
38
  "tsup": "^8.0.2",
39
39
  "typescript": "^5.4.3",
40
40
  "vitest": "^1.4.0",
41
- "@humeai/typescript-config": "0.0.0",
42
- "@humeai/eslint-config": "0.0.1"
41
+ "@humeai/eslint-config": "0.0.1",
42
+ "@humeai/typescript-config": "0.0.0"
43
43
  },
44
44
  "browserslist": [
45
45
  "last 2 Chrome versions, last 2 iOS major versions, Firefox ESR, not dead"