@knocklabs/react-core 0.12.2 → 0.12.4

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 (55) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/index.js +1 -1
  3. package/dist/cjs/modules/core/hooks/useAuthPolling.js +2 -0
  4. package/dist/cjs/modules/core/hooks/useAuthPolling.js.map +1 -0
  5. package/dist/cjs/modules/core/hooks/useAuthPostMessageListener.js +2 -0
  6. package/dist/cjs/modules/core/hooks/useAuthPostMessageListener.js.map +1 -0
  7. package/dist/cjs/modules/ms-teams/context/KnockMsTeamsProvider.js +1 -1
  8. package/dist/cjs/modules/ms-teams/context/KnockMsTeamsProvider.js.map +1 -1
  9. package/dist/cjs/modules/ms-teams/hooks/useMsTeamsConnectionStatus.js.map +1 -1
  10. package/dist/cjs/modules/slack/context/KnockSlackProvider.js +1 -1
  11. package/dist/cjs/modules/slack/context/KnockSlackProvider.js.map +1 -1
  12. package/dist/cjs/modules/slack/hooks/useSlackConnectionStatus.js.map +1 -1
  13. package/dist/esm/index.mjs +70 -66
  14. package/dist/esm/index.mjs.map +1 -1
  15. package/dist/esm/modules/core/hooks/useAuthPolling.mjs +50 -0
  16. package/dist/esm/modules/core/hooks/useAuthPolling.mjs.map +1 -0
  17. package/dist/esm/modules/core/hooks/useAuthPostMessageListener.mjs +19 -0
  18. package/dist/esm/modules/core/hooks/useAuthPostMessageListener.mjs.map +1 -0
  19. package/dist/esm/modules/ms-teams/context/KnockMsTeamsProvider.mjs +28 -26
  20. package/dist/esm/modules/ms-teams/context/KnockMsTeamsProvider.mjs.map +1 -1
  21. package/dist/esm/modules/ms-teams/hooks/useMsTeamsConnectionStatus.mjs.map +1 -1
  22. package/dist/esm/modules/slack/context/KnockSlackProvider.mjs +24 -22
  23. package/dist/esm/modules/slack/context/KnockSlackProvider.mjs.map +1 -1
  24. package/dist/esm/modules/slack/hooks/useSlackConnectionStatus.mjs.map +1 -1
  25. package/dist/types/index.d.ts +1 -1
  26. package/dist/types/index.d.ts.map +1 -1
  27. package/dist/types/modules/core/hooks/index.d.ts +2 -0
  28. package/dist/types/modules/core/hooks/index.d.ts.map +1 -1
  29. package/dist/types/modules/core/hooks/useAuthPolling.d.ts +34 -0
  30. package/dist/types/modules/core/hooks/useAuthPolling.d.ts.map +1 -0
  31. package/dist/types/modules/core/hooks/useAuthPostMessageListener.d.ts +27 -0
  32. package/dist/types/modules/core/hooks/useAuthPostMessageListener.d.ts.map +1 -0
  33. package/dist/types/modules/core/index.d.ts +2 -1
  34. package/dist/types/modules/core/index.d.ts.map +1 -1
  35. package/dist/types/modules/core/types.d.ts +20 -0
  36. package/dist/types/modules/core/types.d.ts.map +1 -0
  37. package/dist/types/modules/ms-teams/context/KnockMsTeamsProvider.d.ts +2 -1
  38. package/dist/types/modules/ms-teams/context/KnockMsTeamsProvider.d.ts.map +1 -1
  39. package/dist/types/modules/ms-teams/hooks/useMsTeamsConnectionStatus.d.ts +1 -1
  40. package/dist/types/modules/ms-teams/hooks/useMsTeamsConnectionStatus.d.ts.map +1 -1
  41. package/dist/types/modules/slack/context/KnockSlackProvider.d.ts +2 -1
  42. package/dist/types/modules/slack/context/KnockSlackProvider.d.ts.map +1 -1
  43. package/dist/types/modules/slack/hooks/useSlackConnectionStatus.d.ts +1 -1
  44. package/dist/types/modules/slack/hooks/useSlackConnectionStatus.d.ts.map +1 -1
  45. package/package.json +2 -2
  46. package/src/index.ts +4 -0
  47. package/src/modules/core/hooks/index.ts +2 -0
  48. package/src/modules/core/hooks/useAuthPolling.ts +115 -0
  49. package/src/modules/core/hooks/useAuthPostMessageListener.ts +70 -0
  50. package/src/modules/core/index.ts +7 -1
  51. package/src/modules/core/types.ts +25 -0
  52. package/src/modules/ms-teams/context/KnockMsTeamsProvider.tsx +5 -3
  53. package/src/modules/ms-teams/hooks/useMsTeamsConnectionStatus.ts +1 -7
  54. package/src/modules/slack/context/KnockSlackProvider.tsx +5 -3
  55. package/src/modules/slack/hooks/useSlackConnectionStatus.ts +1 -7
@@ -1,49 +1,51 @@
1
- import d from "../hooks/useSlackConnectionStatus.mjs";
1
+ import S from "../hooks/useSlackConnectionStatus.mjs";
2
2
  import * as o from "react";
3
+ import { useRef as C } from "react";
3
4
  import "swr/infinite";
4
- import { useKnockClient as S } from "../../core/context/KnockProvider.mjs";
5
+ import { useKnockClient as f } from "../../core/context/KnockProvider.mjs";
5
6
  import "@knocklabs/client";
6
7
  import "fast-deep-equal";
7
- import { slackProviderKey as C } from "../../core/utils.mjs";
8
+ import { slackProviderKey as p } from "../../core/utils.mjs";
8
9
  import "swr";
9
10
  import "../../i18n/context/KnockI18nProvider.mjs";
10
- const a = o.createContext(null), I = (t) => {
11
+ const i = o.createContext(null), E = (t) => {
11
12
  const {
12
13
  knockSlackChannelId: e,
13
- children: i
14
- } = t, n = "tenantId" in t ? t.tenantId : t.tenant, l = S(), {
14
+ children: a
15
+ } = t, n = "tenantId" in t ? t.tenantId : t.tenant, l = f(), s = C(null), {
15
16
  connectionStatus: r,
16
- setConnectionStatus: s,
17
+ setConnectionStatus: k,
17
18
  errorLabel: c,
18
- setErrorLabel: k,
19
- actionLabel: m,
20
- setActionLabel: u
21
- } = d(l, e, n);
22
- return /* @__PURE__ */ o.createElement(a.Provider, { key: C({
19
+ setErrorLabel: m,
20
+ actionLabel: u,
21
+ setActionLabel: d
22
+ } = S(l, e, n);
23
+ return /* @__PURE__ */ o.createElement(i.Provider, { key: p({
23
24
  knockSlackChannelId: e,
24
25
  tenantId: n,
25
26
  connectionStatus: r,
26
27
  errorLabel: c
27
28
  }), value: {
28
29
  connectionStatus: r,
29
- setConnectionStatus: s,
30
+ setConnectionStatus: k,
30
31
  errorLabel: c,
31
- setErrorLabel: k,
32
- actionLabel: m,
33
- setActionLabel: u,
32
+ setErrorLabel: m,
33
+ actionLabel: u,
34
+ setActionLabel: d,
34
35
  knockSlackChannelId: e,
35
36
  // Assign the same value to both tenant and tenantId for backwards compatibility
36
37
  tenant: n,
37
- tenantId: n
38
- } }, i);
39
- }, L = () => {
40
- const t = o.useContext(a);
38
+ tenantId: n,
39
+ popupWindowRef: s
40
+ } }, a);
41
+ }, R = () => {
42
+ const t = o.useContext(i);
41
43
  if (t === void 0)
42
44
  throw new Error("useKnockSlackClient must be used within a KnockSlackProvider");
43
45
  return t;
44
46
  };
45
47
  export {
46
- I as KnockSlackProvider,
47
- L as useKnockSlackClient
48
+ E as KnockSlackProvider,
49
+ R as useKnockSlackClient
48
50
  };
49
51
  //# sourceMappingURL=KnockSlackProvider.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"KnockSlackProvider.mjs","sources":["../../../../../src/modules/slack/context/KnockSlackProvider.tsx"],"sourcesContent":["import { useSlackConnectionStatus } from \"..\";\nimport * as React from \"react\";\nimport { PropsWithChildren } from \"react\";\n\nimport { slackProviderKey } from \"../../core\";\nimport { useKnockClient } from \"../../core\";\nimport { ConnectionStatus } from \"../hooks/useSlackConnectionStatus\";\n\nexport interface KnockSlackProviderState {\n knockSlackChannelId: string;\n tenantId: string;\n /**\n * @deprecated Use `tenantId` instead. This field will be removed in a future release.\n */\n tenant: string;\n connectionStatus: ConnectionStatus;\n setConnectionStatus: (connectionStatus: ConnectionStatus) => void;\n errorLabel: string | null;\n setErrorLabel: (label: string) => void;\n actionLabel: string | null;\n setActionLabel: (label: string | null) => void;\n}\n\nconst SlackProviderStateContext =\n React.createContext<KnockSlackProviderState | null>(null);\n\nexport type KnockSlackProviderProps =\n | {\n knockSlackChannelId: string;\n /**\n * @deprecated Use `tenantId` instead. This field will be removed in a future release.\n */\n tenant: string;\n }\n | {\n knockSlackChannelId: string;\n tenantId: string;\n };\n\nexport const KnockSlackProvider: React.FC<\n PropsWithChildren<KnockSlackProviderProps>\n> = (props) => {\n const { knockSlackChannelId, children } = props;\n const tenantId = \"tenantId\" in props ? props.tenantId : props.tenant;\n\n const knock = useKnockClient();\n\n const {\n connectionStatus,\n setConnectionStatus,\n errorLabel,\n setErrorLabel,\n actionLabel,\n setActionLabel,\n } = useSlackConnectionStatus(knock, knockSlackChannelId, tenantId);\n\n return (\n <SlackProviderStateContext.Provider\n key={slackProviderKey({\n knockSlackChannelId,\n tenantId,\n connectionStatus,\n errorLabel,\n })}\n value={{\n connectionStatus,\n setConnectionStatus,\n errorLabel,\n setErrorLabel,\n actionLabel,\n setActionLabel,\n knockSlackChannelId,\n // Assign the same value to both tenant and tenantId for backwards compatibility\n tenant: tenantId,\n tenantId,\n }}\n >\n {children}\n </SlackProviderStateContext.Provider>\n );\n};\n\nexport const useKnockSlackClient = (): KnockSlackProviderState => {\n const context = React.useContext(\n SlackProviderStateContext,\n ) as KnockSlackProviderState;\n if (context === undefined) {\n throw new Error(\n \"useKnockSlackClient must be used within a KnockSlackProvider\",\n );\n }\n return context as KnockSlackProviderState;\n};\n"],"names":["SlackProviderStateContext","React","createContext","KnockSlackProvider","props","knockSlackChannelId","children","tenantId","tenant","knock","useKnockClient","connectionStatus","setConnectionStatus","errorLabel","setErrorLabel","actionLabel","setActionLabel","useSlackConnectionStatus","slackProviderKey","useKnockSlackClient","context","useContext","undefined","Error"],"mappings":";;;;;;;;;AAuBA,MAAMA,IACJC,EAAMC,cAA8C,IAAI,GAe7CC,IAERC,CAAUA,MAAA;AACP,QAAA;AAAA,IAAEC,qBAAAA;AAAAA,IAAqBC,UAAAA;AAAAA,EAAAA,IAAaF,GACpCG,IAAW,cAAcH,IAAQA,EAAMG,WAAWH,EAAMI,QAExDC,IAAQC,EAAe,GAEvB;AAAA,IACJC,kBAAAA;AAAAA,IACAC,qBAAAA;AAAAA,IACAC,YAAAA;AAAAA,IACAC,eAAAA;AAAAA,IACAC,aAAAA;AAAAA,IACAC,gBAAAA;AAAAA,EACEC,IAAAA,EAAyBR,GAAOJ,GAAqBE,CAAQ;AAEjE,SACG,gBAAAN,EAAA,cAAAD,EAA0B,UAA1B,EACC,KAAKkB,EAAiB;AAAA,IACpBb,qBAAAA;AAAAA,IACAE,UAAAA;AAAAA,IACAI,kBAAAA;AAAAA,IACAE,YAAAA;AAAAA,EACD,CAAA,GACD,OAAO;AAAA,IACLF,kBAAAA;AAAAA,IACAC,qBAAAA;AAAAA,IACAC,YAAAA;AAAAA,IACAC,eAAAA;AAAAA,IACAC,aAAAA;AAAAA,IACAC,gBAAAA;AAAAA,IACAX,qBAAAA;AAAAA;AAAAA,IAEAG,QAAQD;AAAAA,IACRA,UAAAA;AAAAA,OAGDD,CACH;AAEJ,GAEaa,IAAsBA,MAA+B;AAC1DC,QAAAA,IAAUnB,EAAMoB,WACpBrB,CACF;AACA,MAAIoB,MAAYE;AACR,UAAA,IAAIC,MACR,8DACF;AAEKH,SAAAA;AACT;"}
1
+ {"version":3,"file":"KnockSlackProvider.mjs","sources":["../../../../../src/modules/slack/context/KnockSlackProvider.tsx"],"sourcesContent":["import { useSlackConnectionStatus } from \"..\";\nimport * as React from \"react\";\nimport { PropsWithChildren, useRef } from \"react\";\n\nimport { type ConnectionStatus, slackProviderKey } from \"../../core\";\nimport { useKnockClient } from \"../../core\";\n\nexport interface KnockSlackProviderState {\n knockSlackChannelId: string;\n tenantId: string;\n /**\n * @deprecated Use `tenantId` instead. This field will be removed in a future release.\n */\n tenant: string;\n connectionStatus: ConnectionStatus;\n setConnectionStatus: (connectionStatus: ConnectionStatus) => void;\n errorLabel: string | null;\n setErrorLabel: (label: string) => void;\n actionLabel: string | null;\n setActionLabel: (label: string | null) => void;\n popupWindowRef: React.MutableRefObject<Window | null>;\n}\n\nconst SlackProviderStateContext =\n React.createContext<KnockSlackProviderState | null>(null);\n\nexport type KnockSlackProviderProps =\n | {\n knockSlackChannelId: string;\n /**\n * @deprecated Use `tenantId` instead. This field will be removed in a future release.\n */\n tenant: string;\n }\n | {\n knockSlackChannelId: string;\n tenantId: string;\n };\n\nexport const KnockSlackProvider: React.FC<\n PropsWithChildren<KnockSlackProviderProps>\n> = (props) => {\n const { knockSlackChannelId, children } = props;\n const tenantId = \"tenantId\" in props ? props.tenantId : props.tenant;\n\n const knock = useKnockClient();\n const popupWindowRef = useRef<Window | null>(null);\n\n const {\n connectionStatus,\n setConnectionStatus,\n errorLabel,\n setErrorLabel,\n actionLabel,\n setActionLabel,\n } = useSlackConnectionStatus(knock, knockSlackChannelId, tenantId);\n\n return (\n <SlackProviderStateContext.Provider\n key={slackProviderKey({\n knockSlackChannelId,\n tenantId,\n connectionStatus,\n errorLabel,\n })}\n value={{\n connectionStatus,\n setConnectionStatus,\n errorLabel,\n setErrorLabel,\n actionLabel,\n setActionLabel,\n knockSlackChannelId,\n // Assign the same value to both tenant and tenantId for backwards compatibility\n tenant: tenantId,\n tenantId,\n popupWindowRef,\n }}\n >\n {children}\n </SlackProviderStateContext.Provider>\n );\n};\n\nexport const useKnockSlackClient = (): KnockSlackProviderState => {\n const context = React.useContext(\n SlackProviderStateContext,\n ) as KnockSlackProviderState;\n if (context === undefined) {\n throw new Error(\n \"useKnockSlackClient must be used within a KnockSlackProvider\",\n );\n }\n return context as KnockSlackProviderState;\n};\n"],"names":["SlackProviderStateContext","React","createContext","KnockSlackProvider","props","knockSlackChannelId","children","tenantId","tenant","knock","useKnockClient","popupWindowRef","useRef","connectionStatus","setConnectionStatus","errorLabel","setErrorLabel","actionLabel","setActionLabel","useSlackConnectionStatus","slackProviderKey","useKnockSlackClient","context","useContext","undefined","Error"],"mappings":";;;;;;;;;;AAuBA,MAAMA,IACJC,EAAMC,cAA8C,IAAI,GAe7CC,IAERC,CAAUA,MAAA;AACP,QAAA;AAAA,IAAEC,qBAAAA;AAAAA,IAAqBC,UAAAA;AAAAA,EAAAA,IAAaF,GACpCG,IAAW,cAAcH,IAAQA,EAAMG,WAAWH,EAAMI,QAExDC,IAAQC,EAAe,GACvBC,IAAiBC,EAAsB,IAAI,GAE3C;AAAA,IACJC,kBAAAA;AAAAA,IACAC,qBAAAA;AAAAA,IACAC,YAAAA;AAAAA,IACAC,eAAAA;AAAAA,IACAC,aAAAA;AAAAA,IACAC,gBAAAA;AAAAA,EACEC,IAAAA,EAAyBV,GAAOJ,GAAqBE,CAAQ;AAEjE,SACG,gBAAAN,EAAA,cAAAD,EAA0B,UAA1B,EACC,KAAKoB,EAAiB;AAAA,IACpBf,qBAAAA;AAAAA,IACAE,UAAAA;AAAAA,IACAM,kBAAAA;AAAAA,IACAE,YAAAA;AAAAA,EACD,CAAA,GACD,OAAO;AAAA,IACLF,kBAAAA;AAAAA,IACAC,qBAAAA;AAAAA,IACAC,YAAAA;AAAAA,IACAC,eAAAA;AAAAA,IACAC,aAAAA;AAAAA,IACAC,gBAAAA;AAAAA,IACAb,qBAAAA;AAAAA;AAAAA,IAEAG,QAAQD;AAAAA,IACRA,UAAAA;AAAAA,IACAI,gBAAAA;AAAAA,OAGDL,CACH;AAEJ,GAEae,IAAsBA,MAA+B;AAC1DC,QAAAA,IAAUrB,EAAMsB,WACpBvB,CACF;AACA,MAAIsB,MAAYE;AACR,UAAA,IAAIC,MACR,8DACF;AAEKH,SAAAA;AACT;"}
@@ -1 +1 @@
1
- {"version":3,"file":"useSlackConnectionStatus.mjs","sources":["../../../../../src/modules/slack/hooks/useSlackConnectionStatus.ts"],"sourcesContent":["import Knock from \"@knocklabs/client\";\nimport { useEffect, useState } from \"react\";\n\nimport { useTranslations } from \"../../i18n\";\n\nexport type ConnectionStatus =\n | \"connecting\"\n | \"connected\"\n | \"disconnected\"\n | \"error\"\n | \"disconnecting\";\n\ntype UseSlackConnectionStatusOutput = {\n connectionStatus: ConnectionStatus;\n setConnectionStatus: (status: ConnectionStatus) => void;\n errorLabel: string | null;\n setErrorLabel: (errorLabel: string) => void;\n actionLabel: string | null;\n setActionLabel: (actionLabel: string | null) => void;\n};\n\n/**\n * Transforms a slack error message into\n * a formatted one. Slack error messages: https://api.slack.com/methods/auth.test#errors\n *\n * Ex.: \"account_inactive\" -> \"Account inactive\"\n */\nconst formatSlackErrorMessage = (errorMessage: string) => {\n const firstLetter = errorMessage.substring(0, 1).toUpperCase();\n const rest = errorMessage.substring(1);\n return firstLetter?.concat(rest).replace(\"_\", \" \");\n};\n\nfunction useSlackConnectionStatus(\n knock: Knock,\n knockSlackChannelId: string,\n tenantId: string,\n): UseSlackConnectionStatusOutput {\n const { t } = useTranslations();\n const [connectionStatus, setConnectionStatus] =\n useState<ConnectionStatus>(\"connecting\");\n const [errorLabel, setErrorLabel] = useState<string | null>(null);\n const [actionLabel, setActionLabel] = useState<string | null>(null);\n\n useEffect(() => {\n const checkAuthStatus = async () => {\n if (connectionStatus !== \"connecting\") return;\n\n try {\n const authRes = await knock.slack.authCheck({\n tenant: tenantId,\n knockChannelId: knockSlackChannelId,\n });\n\n if (authRes.connection?.ok) {\n return setConnectionStatus(\"connected\");\n }\n\n // This is a normal response for a tenant that doesn't have an access\n // token set on it, meaning it's not connected to Slack, so we\n // give it a \"disconnected\" status instead of an error status.\n if (\n authRes.code === \"ERR_BAD_REQUEST\" &&\n authRes.response?.data?.message === t(\"slackAccessTokenNotSet\")\n ) {\n return setConnectionStatus(\"disconnected\");\n }\n\n // This is for an error coming directly from Slack.\n if (authRes.connection && authRes.connection.error) {\n const errorLabel = formatSlackErrorMessage(authRes.connection.error);\n setErrorLabel(errorLabel);\n setConnectionStatus(\"error\");\n return;\n }\n\n if (authRes.connection) {\n return setConnectionStatus(\"disconnected\");\n }\n\n setConnectionStatus(\"error\");\n } catch (_error) {\n setConnectionStatus(\"error\");\n }\n };\n\n checkAuthStatus();\n }, [connectionStatus, tenantId, knockSlackChannelId, knock.slack, t]);\n\n return {\n connectionStatus,\n setConnectionStatus,\n errorLabel,\n setErrorLabel,\n actionLabel,\n setActionLabel,\n };\n}\n\nexport default useSlackConnectionStatus;\n"],"names":["formatSlackErrorMessage","errorMessage","firstLetter","substring","toUpperCase","rest","concat","replace","useSlackConnectionStatus","knock","knockSlackChannelId","tenantId","t","useTranslations","connectionStatus","setConnectionStatus","useState","errorLabel","setErrorLabel","actionLabel","setActionLabel","useEffect","authRes","slack","authCheck","tenant","knockChannelId","connection","ok","code","response","data","message","error"],"mappings":";;;AA2BA,MAAMA,IAA0BA,CAACC,MAAyB;AACxD,QAAMC,IAAcD,EAAaE,UAAU,GAAG,CAAC,EAAEC,YAAY,GACvDC,IAAOJ,EAAaE,UAAU,CAAC;AACrC,SAAOD,KAAAA,gBAAAA,EAAaI,OAAOD,GAAME,QAAQ,KAAK;AAChD;AAEA,SAASC,EACPC,GACAC,GACAC,GACgC;AAC1B,QAAA;AAAA,IAAEC,GAAAA;AAAAA,MAAMC,EAAgB,GACxB,CAACC,GAAkBC,CAAmB,IAC1CC,EAA2B,YAAY,GACnC,CAACC,GAAYC,CAAa,IAAIF,EAAwB,IAAI,GAC1D,CAACG,GAAaC,CAAc,IAAIJ,EAAwB,IAAI;AAElEK,SAAAA,EAAU,MAAM;AA0CE,KAzCQ,YAAY;;AAClC,UAAIP,MAAqB;AAErB,YAAA;AACF,gBAAMQ,IAAU,MAAMb,EAAMc,MAAMC,UAAU;AAAA,YAC1CC,QAAQd;AAAAA,YACRe,gBAAgBhB;AAAAA,UAAAA,CACjB;AAEGY,eAAAA,IAAAA,EAAQK,eAARL,QAAAA,EAAoBM;AACtB,mBAAOb,EAAoB,WAAW;AAOtCO,cAAAA,EAAQO,SAAS,uBACjBP,KAAAA,IAAAA,EAAQQ,aAARR,gBAAAA,EAAkBS,SAAlBT,gBAAAA,EAAwBU,aAAYpB,EAAE,wBAAwB;AAE9D,mBAAOG,EAAoB,cAAc;AAI3C,cAAIO,EAAQK,cAAcL,EAAQK,WAAWM,OAAO;AAClD,kBAAMhB,IAAajB,EAAwBsB,EAAQK,WAAWM,KAAK;AACnEf,YAAAA,EAAcD,CAAU,GACxBF,EAAoB,OAAO;AAC3B;AAAA,UAAA;AAGF,cAAIO,EAAQK;AACV,mBAAOZ,EAAoB,cAAc;AAG3CA,UAAAA,EAAoB,OAAO;AAAA,gBACZ;AACfA,UAAAA,EAAoB,OAAO;AAAA,QAAA;AAAA,IAE/B,GAEgB;AAAA,EAAA,GACf,CAACD,GAAkBH,GAAUD,GAAqBD,EAAMc,OAAOX,CAAC,CAAC,GAE7D;AAAA,IACLE,kBAAAA;AAAAA,IACAC,qBAAAA;AAAAA,IACAE,YAAAA;AAAAA,IACAC,eAAAA;AAAAA,IACAC,aAAAA;AAAAA,IACAC,gBAAAA;AAAAA,EACF;AACF;"}
1
+ {"version":3,"file":"useSlackConnectionStatus.mjs","sources":["../../../../../src/modules/slack/hooks/useSlackConnectionStatus.ts"],"sourcesContent":["import Knock from \"@knocklabs/client\";\nimport { useEffect, useState } from \"react\";\n\nimport { type ConnectionStatus } from \"../../core/types\";\nimport { useTranslations } from \"../../i18n\";\n\ntype UseSlackConnectionStatusOutput = {\n connectionStatus: ConnectionStatus;\n setConnectionStatus: (status: ConnectionStatus) => void;\n errorLabel: string | null;\n setErrorLabel: (errorLabel: string) => void;\n actionLabel: string | null;\n setActionLabel: (actionLabel: string | null) => void;\n};\n\n/**\n * Transforms a slack error message into\n * a formatted one. Slack error messages: https://api.slack.com/methods/auth.test#errors\n *\n * Ex.: \"account_inactive\" -> \"Account inactive\"\n */\nconst formatSlackErrorMessage = (errorMessage: string) => {\n const firstLetter = errorMessage.substring(0, 1).toUpperCase();\n const rest = errorMessage.substring(1);\n return firstLetter?.concat(rest).replace(\"_\", \" \");\n};\n\nfunction useSlackConnectionStatus(\n knock: Knock,\n knockSlackChannelId: string,\n tenantId: string,\n): UseSlackConnectionStatusOutput {\n const { t } = useTranslations();\n const [connectionStatus, setConnectionStatus] =\n useState<ConnectionStatus>(\"connecting\");\n const [errorLabel, setErrorLabel] = useState<string | null>(null);\n const [actionLabel, setActionLabel] = useState<string | null>(null);\n\n useEffect(() => {\n const checkAuthStatus = async () => {\n if (connectionStatus !== \"connecting\") return;\n\n try {\n const authRes = await knock.slack.authCheck({\n tenant: tenantId,\n knockChannelId: knockSlackChannelId,\n });\n\n if (authRes.connection?.ok) {\n return setConnectionStatus(\"connected\");\n }\n\n // This is a normal response for a tenant that doesn't have an access\n // token set on it, meaning it's not connected to Slack, so we\n // give it a \"disconnected\" status instead of an error status.\n if (\n authRes.code === \"ERR_BAD_REQUEST\" &&\n authRes.response?.data?.message === t(\"slackAccessTokenNotSet\")\n ) {\n return setConnectionStatus(\"disconnected\");\n }\n\n // This is for an error coming directly from Slack.\n if (authRes.connection && authRes.connection.error) {\n const errorLabel = formatSlackErrorMessage(authRes.connection.error);\n setErrorLabel(errorLabel);\n setConnectionStatus(\"error\");\n return;\n }\n\n if (authRes.connection) {\n return setConnectionStatus(\"disconnected\");\n }\n\n setConnectionStatus(\"error\");\n } catch (_error) {\n setConnectionStatus(\"error\");\n }\n };\n\n checkAuthStatus();\n }, [connectionStatus, tenantId, knockSlackChannelId, knock.slack, t]);\n\n return {\n connectionStatus,\n setConnectionStatus,\n errorLabel,\n setErrorLabel,\n actionLabel,\n setActionLabel,\n };\n}\n\nexport default useSlackConnectionStatus;\n"],"names":["formatSlackErrorMessage","errorMessage","firstLetter","substring","toUpperCase","rest","concat","replace","useSlackConnectionStatus","knock","knockSlackChannelId","tenantId","t","useTranslations","connectionStatus","setConnectionStatus","useState","errorLabel","setErrorLabel","actionLabel","setActionLabel","useEffect","authRes","slack","authCheck","tenant","knockChannelId","connection","ok","code","response","data","message","error"],"mappings":";;;AAqBA,MAAMA,IAA0BA,CAACC,MAAyB;AACxD,QAAMC,IAAcD,EAAaE,UAAU,GAAG,CAAC,EAAEC,YAAY,GACvDC,IAAOJ,EAAaE,UAAU,CAAC;AACrC,SAAOD,KAAAA,gBAAAA,EAAaI,OAAOD,GAAME,QAAQ,KAAK;AAChD;AAEA,SAASC,EACPC,GACAC,GACAC,GACgC;AAC1B,QAAA;AAAA,IAAEC,GAAAA;AAAAA,MAAMC,EAAgB,GACxB,CAACC,GAAkBC,CAAmB,IAC1CC,EAA2B,YAAY,GACnC,CAACC,GAAYC,CAAa,IAAIF,EAAwB,IAAI,GAC1D,CAACG,GAAaC,CAAc,IAAIJ,EAAwB,IAAI;AAElEK,SAAAA,EAAU,MAAM;AA0CE,KAzCQ,YAAY;;AAClC,UAAIP,MAAqB;AAErB,YAAA;AACF,gBAAMQ,IAAU,MAAMb,EAAMc,MAAMC,UAAU;AAAA,YAC1CC,QAAQd;AAAAA,YACRe,gBAAgBhB;AAAAA,UAAAA,CACjB;AAEGY,eAAAA,IAAAA,EAAQK,eAARL,QAAAA,EAAoBM;AACtB,mBAAOb,EAAoB,WAAW;AAOtCO,cAAAA,EAAQO,SAAS,uBACjBP,KAAAA,IAAAA,EAAQQ,aAARR,gBAAAA,EAAkBS,SAAlBT,gBAAAA,EAAwBU,aAAYpB,EAAE,wBAAwB;AAE9D,mBAAOG,EAAoB,cAAc;AAI3C,cAAIO,EAAQK,cAAcL,EAAQK,WAAWM,OAAO;AAClD,kBAAMhB,IAAajB,EAAwBsB,EAAQK,WAAWM,KAAK;AACnEf,YAAAA,EAAcD,CAAU,GACxBF,EAAoB,OAAO;AAC3B;AAAA,UAAA;AAGF,cAAIO,EAAQK;AACV,mBAAOZ,EAAoB,cAAc;AAG3CA,UAAAA,EAAoB,OAAO;AAAA,gBACZ;AACfA,UAAAA,EAAoB,OAAO;AAAA,QAAA;AAAA,IAE/B,GAEgB;AAAA,EAAA,GACf,CAACD,GAAkBH,GAAUD,GAAqBD,EAAMc,OAAOX,CAAC,CAAC,GAE7D;AAAA,IACLE,kBAAAA;AAAAA,IACAC,qBAAAA;AAAAA,IACAE,YAAAA;AAAAA,IACAC,eAAAA;AAAAA,IACAC,aAAAA;AAAAA,IACAC,gBAAAA;AAAAA,EACF;AACF;"}
@@ -1,4 +1,4 @@
1
- export { FilterStatus, KnockProvider, feedProviderKey, formatBadgeCount, formatTimestamp, msTeamsProviderKey, renderNodeOrFallback, slackProviderKey, toSentenceCase, type ColorMode, type KnockProviderProps, type KnockProviderState, useAuthenticatedKnockClient, useKnockClient, useStableOptions, } from './modules/core';
1
+ export { FilterStatus, KnockProvider, feedProviderKey, formatBadgeCount, formatTimestamp, msTeamsProviderKey, renderNodeOrFallback, slackProviderKey, toSentenceCase, type AuthCheckResult, type ColorMode, type ConnectionStatus, type KnockProviderProps, type KnockProviderState, useAuthenticatedKnockClient, useAuthPolling, useAuthPostMessageListener, useKnockClient, useStableOptions, } from './modules/core';
2
2
  export { KnockFeedProvider, type KnockFeedProviderProps, type KnockFeedProviderState, type Selector, useCreateNotificationStore, useFeedSettings, useKnockFeed, useNotificationStore, useNotifications, } from './modules/feed';
3
3
  export { KnockGuideProvider, KnockGuideContext, type KnockGuideProviderProps, useGuide, useGuides, useGuideContext, } from './modules/guide';
4
4
  export { type MsTeamsChannelQueryOptions, type MsTeamsTeamQueryOptions, KnockMsTeamsProvider, type KnockMsTeamsProviderProps, type KnockMsTeamsProviderState, useConnectedMsTeamsChannels, useKnockMsTeamsClient, useMsTeamsAuth, useMsTeamsChannels, useMsTeamsConnectionStatus, useMsTeamsTeams, } from './modules/ms-teams';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,2BAA2B,EAC3B,cAAc,EACd,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,QAAQ,EACb,0BAA0B,EAC1B,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,QAAQ,EACR,SAAS,EACT,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,oBAAoB,EACpB,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,EAC9B,2BAA2B,EAC3B,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,0BAA0B,EAC1B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,EAC7B,yBAAyB,EACzB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,KAAK,YAAY,EACjB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMvD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,2BAA2B,EAC3B,cAAc,EACd,0BAA0B,EAC1B,cAAc,EACd,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,QAAQ,EACb,0BAA0B,EAC1B,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,QAAQ,EACR,SAAS,EACT,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,oBAAoB,EACpB,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,EAC9B,2BAA2B,EAC3B,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,0BAA0B,EAC1B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,EAC7B,yBAAyB,EACzB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,KAAK,YAAY,EACjB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMvD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC"}
@@ -1,3 +1,5 @@
1
1
  export { default as useAuthenticatedKnockClient } from './useAuthenticatedKnockClient';
2
2
  export { default as useStableOptions } from './useStableOptions';
3
+ export { useAuthPostMessageListener } from './useAuthPostMessageListener';
4
+ export { useAuthPolling } from './useAuthPolling';
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/modules/core/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/modules/core/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACvF,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { AuthCheckResult, ConnectionStatus } from '../types';
2
+ export interface UseAuthPollingOptions {
3
+ popupWindowRef: React.MutableRefObject<Window | null>;
4
+ setConnectionStatus: (status: ConnectionStatus) => void;
5
+ authCheckFn: () => Promise<AuthCheckResult>;
6
+ onAuthenticationComplete?: (authenticationResp: string) => void;
7
+ }
8
+ /**
9
+ * Hook that polls an authentication check endpoint until success or timeout.
10
+ *
11
+ * Polls every 2 seconds for up to 3 minutes (90 iterations). Has three stop conditions:
12
+ * 1. Max timeout reached → sets error status
13
+ * 2. Popup closed + 10s grace period → stops silently
14
+ * 3. Success detected via authCheckFn → updates status and closes popup
15
+ *
16
+ * @param options - Configuration options for the polling mechanism
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * useAuthPolling({
21
+ * popupWindowRef,
22
+ * setConnectionStatus,
23
+ * onAuthenticationComplete,
24
+ * authCheckFn: useCallback(async () => {
25
+ * return knock.slack.authCheck({
26
+ * tenant: tenantId,
27
+ * knockChannelId: knockSlackChannelId,
28
+ * });
29
+ * }, [knock.slack, tenantId, knockSlackChannelId]),
30
+ * });
31
+ * ```
32
+ */
33
+ export declare function useAuthPolling(options: UseAuthPollingOptions): void;
34
+ //# sourceMappingURL=useAuthPolling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuthPolling.d.ts","sourceRoot":"","sources":["../../../../../src/modules/core/hooks/useAuthPolling.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE7D,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACtD,mBAAmB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxD,WAAW,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5C,wBAAwB,CAAC,EAAE,CAAC,kBAAkB,EAAE,MAAM,KAAK,IAAI,CAAC;CACjE;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CA8EnE"}
@@ -0,0 +1,27 @@
1
+ import { ConnectionStatus } from '../types';
2
+ export interface UseAuthPostMessageListenerOptions {
3
+ knockHost: string;
4
+ popupWindowRef: React.MutableRefObject<Window | null>;
5
+ setConnectionStatus: (status: ConnectionStatus) => void;
6
+ onAuthenticationComplete?: (authenticationResp: string) => void;
7
+ }
8
+ /**
9
+ * Hook that listens for postMessage events from OAuth popup windows.
10
+ *
11
+ * Handles "authComplete" and "authFailed" messages sent from the OAuth flow popup,
12
+ * validates the message origin, updates connection status, and closes the popup.
13
+ *
14
+ * @param options - Configuration options for the postMessage listener
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * useAuthPostMessageListener({
19
+ * knockHost: knock.host,
20
+ * popupWindowRef,
21
+ * setConnectionStatus,
22
+ * onAuthenticationComplete,
23
+ * });
24
+ * ```
25
+ */
26
+ export declare function useAuthPostMessageListener(options: UseAuthPostMessageListenerOptions): void;
27
+ //# sourceMappingURL=useAuthPostMessageListener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuthPostMessageListener.d.ts","sourceRoot":"","sources":["../../../../../src/modules/core/hooks/useAuthPostMessageListener.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,MAAM,WAAW,iCAAiC;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACtD,mBAAmB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxD,wBAAwB,CAAC,EAAE,CAAC,kBAAkB,EAAE,MAAM,KAAK,IAAI,CAAC;CACjE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,iCAAiC,GACzC,IAAI,CAsCN"}
@@ -1,5 +1,6 @@
1
1
  export { KnockProvider, useKnockClient, type KnockProviderProps, type KnockProviderState, } from './context';
2
- export { useAuthenticatedKnockClient, useStableOptions } from './hooks';
2
+ export { useAuthenticatedKnockClient, useStableOptions, useAuthPostMessageListener, useAuthPolling, } from './hooks';
3
3
  export { FilterStatus, type ColorMode } from './constants';
4
4
  export { formatBadgeCount, formatTimestamp, toSentenceCase, renderNodeOrFallback, feedProviderKey, slackProviderKey, msTeamsProviderKey, } from './utils';
5
+ export { type ConnectionStatus, type AuthCheckResult } from './types';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,2BAA2B,EAC3B,gBAAgB,EAChB,0BAA0B,EAC1B,cAAc,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Represents the connection status for OAuth-based integrations (Slack, MS Teams, etc.)
3
+ */
4
+ export type ConnectionStatus = "connecting" | "connected" | "disconnected" | "error" | "disconnecting";
5
+ /**
6
+ * Result returned by authentication check API calls
7
+ */
8
+ export interface AuthCheckResult {
9
+ connection?: {
10
+ ok?: boolean;
11
+ error?: string;
12
+ };
13
+ code?: string;
14
+ response?: {
15
+ data?: {
16
+ message?: string;
17
+ };
18
+ };
19
+ }
20
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/modules/core/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,WAAW,GACX,cAAc,GACd,OAAO,GACP,eAAe,CAAC;AAEpB;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE;QACX,EAAE,CAAC,EAAE,OAAO,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE;YACL,OAAO,CAAC,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC;CACH"}
@@ -1,5 +1,5 @@
1
1
  import { PropsWithChildren } from 'react';
2
- import { ConnectionStatus } from '../hooks/useMsTeamsConnectionStatus';
2
+ import { ConnectionStatus } from '../../core';
3
3
  import * as React from "react";
4
4
  export interface KnockMsTeamsProviderState {
5
5
  knockMsTeamsChannelId: string;
@@ -10,6 +10,7 @@ export interface KnockMsTeamsProviderState {
10
10
  setErrorLabel: (label: string) => void;
11
11
  actionLabel: string | null;
12
12
  setActionLabel: (label: string | null) => void;
13
+ popupWindowRef: React.MutableRefObject<Window | null>;
13
14
  }
14
15
  export interface KnockMsTeamsProviderProps {
15
16
  knockMsTeamsChannelId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"KnockMsTeamsProvider.d.ts","sourceRoot":"","sources":["../../../../../src/modules/ms-teams/context/KnockMsTeamsProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAK1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAEvE,MAAM,WAAW,yBAAyB;IACxC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,mBAAmB,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAChD;AAKD,MAAM,WAAW,yBAAyB;IACxC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CACzC,iBAAiB,CAAC,yBAAyB,CAAC,CAmC7C,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAO,yBAQxC,CAAC"}
1
+ {"version":3,"file":"KnockMsTeamsProvider.d.ts","sourceRoot":"","sources":["../../../../../src/modules/ms-teams/context/KnockMsTeamsProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAU,MAAM,OAAO,CAAC;AAElD,OAAO,EAAE,KAAK,gBAAgB,EAAkB,MAAM,YAAY,CAAC;AAInE,MAAM,WAAW,yBAAyB;IACxC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,mBAAmB,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACvD;AAKD,MAAM,WAAW,yBAAyB;IACxC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CACzC,iBAAiB,CAAC,yBAAyB,CAAC,CAqC7C,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAO,yBAQxC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { default as Knock } from '@knocklabs/client';
2
- export type ConnectionStatus = "connecting" | "connected" | "disconnected" | "error" | "disconnecting";
2
+ import { ConnectionStatus } from '../../core/types';
3
3
  type UseMsTeamsConnectionStatusOutput = {
4
4
  connectionStatus: ConnectionStatus;
5
5
  setConnectionStatus: (status: ConnectionStatus) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useMsTeamsConnectionStatus.d.ts","sourceRoot":"","sources":["../../../../../src/modules/ms-teams/hooks/useMsTeamsConnectionStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,mBAAmB,CAAC;AAKtC,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,WAAW,GACX,cAAc,GACd,OAAO,GACP,eAAe,CAAC;AAEpB,KAAK,gCAAgC,GAAG;IACtC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,mBAAmB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACtD,CAAC;AAEF,iBAAS,0BAA0B,CACjC,KAAK,EAAE,KAAK,EACZ,qBAAqB,EAAE,MAAM,EAC7B,QAAQ,EAAE,MAAM,GACf,gCAAgC,CAsDlC;AAED,eAAe,0BAA0B,CAAC"}
1
+ {"version":3,"file":"useMsTeamsConnectionStatus.d.ts","sourceRoot":"","sources":["../../../../../src/modules/ms-teams/hooks/useMsTeamsConnectionStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,mBAAmB,CAAC;AAGtC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGzD,KAAK,gCAAgC,GAAG;IACtC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,mBAAmB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACtD,CAAC;AAEF,iBAAS,0BAA0B,CACjC,KAAK,EAAE,KAAK,EACZ,qBAAqB,EAAE,MAAM,EAC7B,QAAQ,EAAE,MAAM,GACf,gCAAgC,CAsDlC;AAED,eAAe,0BAA0B,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { PropsWithChildren } from 'react';
2
- import { ConnectionStatus } from '../hooks/useSlackConnectionStatus';
2
+ import { ConnectionStatus } from '../../core';
3
3
  import * as React from "react";
4
4
  export interface KnockSlackProviderState {
5
5
  knockSlackChannelId: string;
@@ -14,6 +14,7 @@ export interface KnockSlackProviderState {
14
14
  setErrorLabel: (label: string) => void;
15
15
  actionLabel: string | null;
16
16
  setActionLabel: (label: string | null) => void;
17
+ popupWindowRef: React.MutableRefObject<Window | null>;
17
18
  }
18
19
  export type KnockSlackProviderProps = {
19
20
  knockSlackChannelId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"KnockSlackProvider.d.ts","sourceRoot":"","sources":["../../../../../src/modules/slack/context/KnockSlackProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAI1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAErE,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,mBAAmB,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAChD;AAKD,MAAM,MAAM,uBAAuB,GAC/B;IACE,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEN,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CACvC,iBAAiB,CAAC,uBAAuB,CAAC,CAwC3C,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAO,uBAUtC,CAAC"}
1
+ {"version":3,"file":"KnockSlackProvider.d.ts","sourceRoot":"","sources":["../../../../../src/modules/slack/context/KnockSlackProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAU,MAAM,OAAO,CAAC;AAElD,OAAO,EAAE,KAAK,gBAAgB,EAAoB,MAAM,YAAY,CAAC;AAGrE,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,mBAAmB,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACvD;AAKD,MAAM,MAAM,uBAAuB,GAC/B;IACE,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEN,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CACvC,iBAAiB,CAAC,uBAAuB,CAAC,CA0C3C,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAO,uBAUtC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { default as Knock } from '@knocklabs/client';
2
- export type ConnectionStatus = "connecting" | "connected" | "disconnected" | "error" | "disconnecting";
2
+ import { ConnectionStatus } from '../../core/types';
3
3
  type UseSlackConnectionStatusOutput = {
4
4
  connectionStatus: ConnectionStatus;
5
5
  setConnectionStatus: (status: ConnectionStatus) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useSlackConnectionStatus.d.ts","sourceRoot":"","sources":["../../../../../src/modules/slack/hooks/useSlackConnectionStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,mBAAmB,CAAC;AAKtC,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,WAAW,GACX,cAAc,GACd,OAAO,GACP,eAAe,CAAC;AAEpB,KAAK,8BAA8B,GAAG;IACpC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,mBAAmB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACtD,CAAC;AAcF,iBAAS,wBAAwB,CAC/B,KAAK,EAAE,KAAK,EACZ,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,GACf,8BAA8B,CA4DhC;AAED,eAAe,wBAAwB,CAAC"}
1
+ {"version":3,"file":"useSlackConnectionStatus.d.ts","sourceRoot":"","sources":["../../../../../src/modules/slack/hooks/useSlackConnectionStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,mBAAmB,CAAC;AAGtC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGzD,KAAK,8BAA8B,GAAG;IACpC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,mBAAmB,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACxD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACtD,CAAC;AAcF,iBAAS,wBAAwB,CAC/B,KAAK,EAAE,KAAK,EACZ,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,GACf,8BAA8B,CA4DhC;AAED,eAAe,wBAAwB,CAAC"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@knocklabs/react-core",
3
3
  "description": "A set of React components to build notification experiences powered by Knock",
4
4
  "author": "@knocklabs",
5
- "version": "0.12.2",
5
+ "version": "0.12.4",
6
6
  "license": "MIT",
7
7
  "main": "dist/cjs/index.js",
8
8
  "module": "dist/esm/index.mjs",
@@ -47,7 +47,7 @@
47
47
  "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
48
48
  },
49
49
  "dependencies": {
50
- "@knocklabs/client": "^0.20.2",
50
+ "@knocklabs/client": "^0.20.3",
51
51
  "@tanstack/react-store": "^0.7.3",
52
52
  "date-fns": "^4.0.0",
53
53
  "fast-deep-equal": "^3.1.3",
package/src/index.ts CHANGED
@@ -8,10 +8,14 @@ export {
8
8
  renderNodeOrFallback,
9
9
  slackProviderKey,
10
10
  toSentenceCase,
11
+ type AuthCheckResult,
11
12
  type ColorMode,
13
+ type ConnectionStatus,
12
14
  type KnockProviderProps,
13
15
  type KnockProviderState,
14
16
  useAuthenticatedKnockClient,
17
+ useAuthPolling,
18
+ useAuthPostMessageListener,
15
19
  useKnockClient,
16
20
  useStableOptions,
17
21
  } from "./modules/core";
@@ -1,2 +1,4 @@
1
1
  export { default as useAuthenticatedKnockClient } from "./useAuthenticatedKnockClient";
2
2
  export { default as useStableOptions } from "./useStableOptions";
3
+ export { useAuthPostMessageListener } from "./useAuthPostMessageListener";
4
+ export { useAuthPolling } from "./useAuthPolling";
@@ -0,0 +1,115 @@
1
+ import { useEffect } from "react";
2
+
3
+ import { AuthCheckResult, ConnectionStatus } from "../types";
4
+
5
+ export interface UseAuthPollingOptions {
6
+ popupWindowRef: React.MutableRefObject<Window | null>;
7
+ setConnectionStatus: (status: ConnectionStatus) => void;
8
+ authCheckFn: () => Promise<AuthCheckResult>;
9
+ onAuthenticationComplete?: (authenticationResp: string) => void;
10
+ }
11
+
12
+ /**
13
+ * Hook that polls an authentication check endpoint until success or timeout.
14
+ *
15
+ * Polls every 2 seconds for up to 3 minutes (90 iterations). Has three stop conditions:
16
+ * 1. Max timeout reached → sets error status
17
+ * 2. Popup closed + 10s grace period → stops silently
18
+ * 3. Success detected via authCheckFn → updates status and closes popup
19
+ *
20
+ * @param options - Configuration options for the polling mechanism
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * useAuthPolling({
25
+ * popupWindowRef,
26
+ * setConnectionStatus,
27
+ * onAuthenticationComplete,
28
+ * authCheckFn: useCallback(async () => {
29
+ * return knock.slack.authCheck({
30
+ * tenant: tenantId,
31
+ * knockChannelId: knockSlackChannelId,
32
+ * });
33
+ * }, [knock.slack, tenantId, knockSlackChannelId]),
34
+ * });
35
+ * ```
36
+ */
37
+ export function useAuthPolling(options: UseAuthPollingOptions): void {
38
+ const {
39
+ popupWindowRef,
40
+ setConnectionStatus,
41
+ onAuthenticationComplete,
42
+ authCheckFn,
43
+ } = options;
44
+
45
+ useEffect(
46
+ () => {
47
+ let pollCount = 0;
48
+ const maxPolls = 90;
49
+ let popupClosedAt: number | null = null;
50
+ let isActive = true;
51
+
52
+ const pollInterval = setInterval(async () => {
53
+ if (!isActive) {
54
+ clearInterval(pollInterval);
55
+ return;
56
+ }
57
+
58
+ const popupWindow = popupWindowRef.current;
59
+ if (!popupWindow) {
60
+ return;
61
+ }
62
+
63
+ pollCount++;
64
+
65
+ const isPopupClosed = popupWindow.closed;
66
+ if (isPopupClosed && !popupClosedAt) {
67
+ popupClosedAt = Date.now();
68
+ }
69
+
70
+ // Stop condition 1: Max timeout reached
71
+ if (pollCount >= maxPolls) {
72
+ clearInterval(pollInterval);
73
+ setConnectionStatus("error");
74
+ return;
75
+ }
76
+
77
+ // Stop condition 2: Popup closed + grace period expired
78
+ if (popupClosedAt && Date.now() - popupClosedAt > 10000) {
79
+ clearInterval(pollInterval);
80
+ popupWindowRef.current = null;
81
+ return;
82
+ }
83
+
84
+ try {
85
+ const authRes = await authCheckFn();
86
+
87
+ // Stop condition 3: Success detected
88
+ if (authRes.connection?.ok) {
89
+ clearInterval(pollInterval);
90
+ setConnectionStatus("connected");
91
+ if (onAuthenticationComplete) {
92
+ onAuthenticationComplete("authComplete");
93
+ }
94
+ if (popupWindow && !popupWindow.closed) {
95
+ popupWindow.close();
96
+ }
97
+ popupWindowRef.current = null;
98
+ }
99
+ } catch (_error) {
100
+ // Continue polling on error
101
+ }
102
+ }, 2000);
103
+
104
+ return () => {
105
+ isActive = false;
106
+ clearInterval(pollInterval);
107
+ };
108
+ },
109
+ // eslint-disable-next-line react-hooks/exhaustive-deps
110
+ [
111
+ // Empty deps - run once on mount and keep polling
112
+ // This is intentionally simple/brute force
113
+ ],
114
+ );
115
+ }
@@ -0,0 +1,70 @@
1
+ import { useEffect } from "react";
2
+
3
+ import { ConnectionStatus } from "../types";
4
+
5
+ export interface UseAuthPostMessageListenerOptions {
6
+ knockHost: string;
7
+ popupWindowRef: React.MutableRefObject<Window | null>;
8
+ setConnectionStatus: (status: ConnectionStatus) => void;
9
+ onAuthenticationComplete?: (authenticationResp: string) => void;
10
+ }
11
+
12
+ /**
13
+ * Hook that listens for postMessage events from OAuth popup windows.
14
+ *
15
+ * Handles "authComplete" and "authFailed" messages sent from the OAuth flow popup,
16
+ * validates the message origin, updates connection status, and closes the popup.
17
+ *
18
+ * @param options - Configuration options for the postMessage listener
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * useAuthPostMessageListener({
23
+ * knockHost: knock.host,
24
+ * popupWindowRef,
25
+ * setConnectionStatus,
26
+ * onAuthenticationComplete,
27
+ * });
28
+ * ```
29
+ */
30
+ export function useAuthPostMessageListener(
31
+ options: UseAuthPostMessageListenerOptions,
32
+ ): void {
33
+ const {
34
+ knockHost,
35
+ popupWindowRef,
36
+ setConnectionStatus,
37
+ onAuthenticationComplete,
38
+ } = options;
39
+
40
+ useEffect(() => {
41
+ const receiveMessage = (event: MessageEvent) => {
42
+ // Validate message origin for security
43
+ if (event.origin !== knockHost) {
44
+ return;
45
+ }
46
+
47
+ if (event.data === "authComplete") {
48
+ setConnectionStatus("connected");
49
+ onAuthenticationComplete?.(event.data);
50
+ // Clear popup ref so polling stops and doesn't trigger callback again
51
+ if (popupWindowRef.current && !popupWindowRef.current.closed) {
52
+ popupWindowRef.current.close();
53
+ }
54
+ popupWindowRef.current = null;
55
+ } else if (event.data === "authFailed") {
56
+ setConnectionStatus("error");
57
+ onAuthenticationComplete?.(event.data);
58
+ popupWindowRef.current = null;
59
+ }
60
+ };
61
+
62
+ window.addEventListener("message", receiveMessage, false);
63
+ return () => window.removeEventListener("message", receiveMessage);
64
+ }, [
65
+ knockHost,
66
+ onAuthenticationComplete,
67
+ setConnectionStatus,
68
+ popupWindowRef,
69
+ ]);
70
+ }
@@ -4,7 +4,12 @@ export {
4
4
  type KnockProviderProps,
5
5
  type KnockProviderState,
6
6
  } from "./context";
7
- export { useAuthenticatedKnockClient, useStableOptions } from "./hooks";
7
+ export {
8
+ useAuthenticatedKnockClient,
9
+ useStableOptions,
10
+ useAuthPostMessageListener,
11
+ useAuthPolling,
12
+ } from "./hooks";
8
13
  export { FilterStatus, type ColorMode } from "./constants";
9
14
  export {
10
15
  formatBadgeCount,
@@ -15,3 +20,4 @@ export {
15
20
  slackProviderKey,
16
21
  msTeamsProviderKey,
17
22
  } from "./utils";
23
+ export { type ConnectionStatus, type AuthCheckResult } from "./types";
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Represents the connection status for OAuth-based integrations (Slack, MS Teams, etc.)
3
+ */
4
+ export type ConnectionStatus =
5
+ | "connecting"
6
+ | "connected"
7
+ | "disconnected"
8
+ | "error"
9
+ | "disconnecting";
10
+
11
+ /**
12
+ * Result returned by authentication check API calls
13
+ */
14
+ export interface AuthCheckResult {
15
+ connection?: {
16
+ ok?: boolean;
17
+ error?: string;
18
+ };
19
+ code?: string;
20
+ response?: {
21
+ data?: {
22
+ message?: string;
23
+ };
24
+ };
25
+ }