@multiplatform.one/keycloak 1.0.36 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/dist/cjs/Authenticated.js +9 -4
  2. package/dist/cjs/Authenticated.js.map +1 -1
  3. package/dist/cjs/Authenticated.native.js +7 -22
  4. package/dist/cjs/Authenticated.native.js.map +2 -2
  5. package/dist/cjs/Loading.js +25 -0
  6. package/dist/cjs/Loading.js.map +6 -0
  7. package/dist/cjs/Loading.native.js +31 -0
  8. package/dist/cjs/Loading.native.js.map +6 -0
  9. package/dist/cjs/hooks/useTokensFromState.js +5 -4
  10. package/dist/cjs/hooks/useTokensFromState.js.map +1 -1
  11. package/dist/cjs/hooks/useTokensFromState.native.js +6 -5
  12. package/dist/cjs/hooks/useTokensFromState.native.js.map +2 -2
  13. package/dist/cjs/keycloak/context.js.map +1 -1
  14. package/dist/cjs/keycloak/context.native.js.map +1 -1
  15. package/dist/cjs/keycloak/keycloak.js +10 -7
  16. package/dist/cjs/keycloak/keycloak.js.map +1 -1
  17. package/dist/cjs/keycloak/keycloak.native.js +27 -209
  18. package/dist/cjs/keycloak/keycloak.native.js.map +2 -2
  19. package/dist/cjs/provider/AfterAuth.js +12 -7
  20. package/dist/cjs/provider/AfterAuth.js.map +1 -1
  21. package/dist/cjs/provider/AfterAuth.native.js +6 -4
  22. package/dist/cjs/provider/AfterAuth.native.js.map +2 -2
  23. package/dist/cjs/provider/AuthProvider/AuthProvider.js +59 -23
  24. package/dist/cjs/provider/AuthProvider/AuthProvider.js.map +1 -1
  25. package/dist/cjs/provider/AuthProvider/AuthProvider.native.js +80 -321
  26. package/dist/cjs/provider/AuthProvider/AuthProvider.native.js.map +2 -2
  27. package/dist/cjs/provider/KeycloakProvider.js +4 -1
  28. package/dist/cjs/provider/KeycloakProvider.js.map +1 -1
  29. package/dist/cjs/provider/KeycloakProvider.native.js +1 -1
  30. package/dist/cjs/provider/KeycloakProvider.native.js.map +1 -1
  31. package/dist/cjs/routes.js +11 -10
  32. package/dist/cjs/routes.js.map +1 -1
  33. package/dist/cjs/routes.native.js +89 -333
  34. package/dist/cjs/routes.native.js.map +2 -2
  35. package/dist/cjs/session/session.js.map +1 -1
  36. package/dist/cjs/session/session.native.js +2 -122
  37. package/dist/cjs/session/session.native.js.map +1 -1
  38. package/dist/cjs/state.js +10 -14
  39. package/dist/cjs/state.js.map +1 -1
  40. package/dist/cjs/state.native.js +20 -11
  41. package/dist/cjs/state.native.js.map +2 -2
  42. package/dist/cjs/token.js.map +1 -1
  43. package/dist/cjs/token.native.js +1 -1
  44. package/dist/cjs/token.native.js.map +1 -1
  45. package/dist/esm/Authenticated.js +11 -4
  46. package/dist/esm/Authenticated.js.map +1 -1
  47. package/dist/esm/Authenticated.mjs +7 -5
  48. package/dist/esm/Authenticated.mjs.map +1 -0
  49. package/dist/esm/Authenticated.native.js +26 -37
  50. package/dist/esm/Authenticated.native.js.map +1 -6
  51. package/dist/esm/Loading.js +11 -0
  52. package/dist/esm/Loading.js.map +6 -0
  53. package/dist/esm/Loading.mjs +16 -0
  54. package/dist/esm/Loading.mjs.map +1 -0
  55. package/dist/esm/Loading.native.js +17 -0
  56. package/dist/esm/Loading.native.js.map +1 -0
  57. package/dist/esm/authConfig.mjs +2 -1
  58. package/dist/esm/authConfig.mjs.map +1 -0
  59. package/dist/esm/authConfig.native.js +5 -6
  60. package/dist/esm/authConfig.native.js.map +1 -6
  61. package/dist/esm/hooks/index.mjs +3 -2
  62. package/dist/esm/hooks/index.mjs.map +1 -0
  63. package/dist/esm/hooks/index.native.js +3 -3
  64. package/dist/esm/hooks/index.native.js.map +1 -6
  65. package/dist/esm/hooks/useAuthConfig.mjs +2 -1
  66. package/dist/esm/hooks/useAuthConfig.mjs.map +1 -0
  67. package/dist/esm/hooks/useAuthConfig.native.js +3 -5
  68. package/dist/esm/hooks/useAuthConfig.native.js.map +1 -6
  69. package/dist/esm/hooks/useTokensFromQuery/index.mjs +2 -1
  70. package/dist/esm/hooks/useTokensFromQuery/index.mjs.map +1 -0
  71. package/dist/esm/hooks/useTokensFromQuery/index.native.js +2 -4
  72. package/dist/esm/hooks/useTokensFromQuery/index.native.js.map +1 -6
  73. package/dist/esm/hooks/useTokensFromState.js +6 -5
  74. package/dist/esm/hooks/useTokensFromState.js.map +1 -1
  75. package/dist/esm/hooks/useTokensFromState.mjs +6 -5
  76. package/dist/esm/hooks/useTokensFromState.mjs.map +1 -0
  77. package/dist/esm/hooks/useTokensFromState.native.js +7 -9
  78. package/dist/esm/hooks/useTokensFromState.native.js.map +1 -6
  79. package/dist/esm/index.mjs +6 -5
  80. package/dist/esm/index.mjs.map +1 -0
  81. package/dist/esm/index.native.js +4 -4
  82. package/dist/esm/index.native.js.map +1 -6
  83. package/dist/esm/keycloak/config.mjs +2 -1
  84. package/dist/esm/keycloak/config.mjs.map +1 -0
  85. package/dist/esm/keycloak/config.native.js +3 -4
  86. package/dist/esm/keycloak/config.native.js.map +1 -6
  87. package/dist/esm/keycloak/context.js.map +1 -1
  88. package/dist/esm/keycloak/context.mjs +2 -1
  89. package/dist/esm/keycloak/context.mjs.map +1 -0
  90. package/dist/esm/keycloak/context.native.js +3 -4
  91. package/dist/esm/keycloak/context.native.js.map +1 -6
  92. package/dist/esm/keycloak/index.mjs +2 -1
  93. package/dist/esm/keycloak/index.mjs.map +1 -0
  94. package/dist/esm/keycloak/index.native.js +3 -3
  95. package/dist/esm/keycloak/index.native.js.map +1 -6
  96. package/dist/esm/keycloak/keycloak.js +14 -11
  97. package/dist/esm/keycloak/keycloak.js.map +1 -1
  98. package/dist/esm/keycloak/keycloak.mjs +8 -7
  99. package/dist/esm/keycloak/keycloak.mjs.map +1 -0
  100. package/dist/esm/keycloak/keycloak.native.js +112 -317
  101. package/dist/esm/keycloak/keycloak.native.js.map +1 -6
  102. package/dist/esm/provider/AfterAuth.js +16 -8
  103. package/dist/esm/provider/AfterAuth.js.map +1 -1
  104. package/dist/esm/provider/AfterAuth.mjs +13 -8
  105. package/dist/esm/provider/AfterAuth.mjs.map +1 -0
  106. package/dist/esm/provider/AfterAuth.native.js +25 -30
  107. package/dist/esm/provider/AfterAuth.native.js.map +1 -6
  108. package/dist/esm/provider/AuthProvider/AuthProvider.js +56 -19
  109. package/dist/esm/provider/AuthProvider/AuthProvider.js.map +1 -1
  110. package/dist/esm/provider/AuthProvider/AuthProvider.mjs +21 -14
  111. package/dist/esm/provider/AuthProvider/AuthProvider.mjs.map +1 -0
  112. package/dist/esm/provider/AuthProvider/AuthProvider.native.js +104 -364
  113. package/dist/esm/provider/AuthProvider/AuthProvider.native.js.map +1 -6
  114. package/dist/esm/provider/AuthProvider/index.mjs +2 -1
  115. package/dist/esm/provider/AuthProvider/index.mjs.map +1 -0
  116. package/dist/esm/provider/AuthProvider/index.native.js +2 -2
  117. package/dist/esm/provider/AuthProvider/index.native.js.map +1 -6
  118. package/dist/esm/provider/KeycloakProvider.js +4 -1
  119. package/dist/esm/provider/KeycloakProvider.js.map +1 -1
  120. package/dist/esm/provider/KeycloakProvider.mjs +3 -2
  121. package/dist/esm/provider/KeycloakProvider.mjs.map +1 -0
  122. package/dist/esm/provider/KeycloakProvider.native.js +22 -17
  123. package/dist/esm/provider/KeycloakProvider.native.js.map +1 -6
  124. package/dist/esm/provider/index.mjs +3 -2
  125. package/dist/esm/provider/index.mjs.map +1 -0
  126. package/dist/esm/provider/index.native.js +3 -3
  127. package/dist/esm/provider/index.native.js.map +1 -6
  128. package/dist/esm/routes.js +11 -10
  129. package/dist/esm/routes.js.map +1 -1
  130. package/dist/esm/routes.mjs +12 -12
  131. package/dist/esm/routes.mjs.map +1 -0
  132. package/dist/esm/routes.native.js +98 -342
  133. package/dist/esm/routes.native.js.map +1 -6
  134. package/dist/esm/session/index.mjs +2 -1
  135. package/dist/esm/session/index.mjs.map +1 -0
  136. package/dist/esm/session/index.native.js +2 -2
  137. package/dist/esm/session/index.native.js.map +1 -6
  138. package/dist/esm/session/session.js.map +1 -1
  139. package/dist/esm/session/session.mjs +2 -1
  140. package/dist/esm/session/session.mjs.map +1 -0
  141. package/dist/esm/session/session.native.js +3 -126
  142. package/dist/esm/session/session.native.js.map +1 -6
  143. package/dist/esm/state.js +10 -14
  144. package/dist/esm/state.js.map +1 -1
  145. package/dist/esm/state.mjs +11 -14
  146. package/dist/esm/state.mjs.map +1 -0
  147. package/dist/esm/state.native.js +22 -15
  148. package/dist/esm/state.native.js.map +1 -6
  149. package/dist/esm/token.js.map +1 -1
  150. package/dist/esm/token.mjs +2 -1
  151. package/dist/esm/token.mjs.map +1 -0
  152. package/dist/esm/token.native.js +6 -8
  153. package/dist/esm/token.native.js.map +1 -6
  154. package/dist/esm/types.mjs +2 -0
  155. package/dist/esm/types.mjs.map +1 -0
  156. package/dist/esm/types.native.js +2 -1
  157. package/dist/esm/types.native.js.map +1 -6
  158. package/dist/jsx/Authenticated.js +11 -4
  159. package/dist/jsx/Authenticated.js.map +1 -1
  160. package/dist/jsx/Authenticated.mjs +7 -5
  161. package/dist/jsx/Authenticated.mjs.map +1 -0
  162. package/dist/jsx/Authenticated.native.js +7 -22
  163. package/dist/jsx/Authenticated.native.js.map +2 -2
  164. package/dist/jsx/Loading.js +11 -0
  165. package/dist/jsx/Loading.js.map +6 -0
  166. package/dist/jsx/Loading.mjs +16 -0
  167. package/dist/jsx/Loading.mjs.map +1 -0
  168. package/dist/jsx/Loading.native.js +13 -0
  169. package/dist/jsx/Loading.native.js.map +6 -0
  170. package/dist/jsx/authConfig.mjs +2 -1
  171. package/dist/jsx/authConfig.mjs.map +1 -0
  172. package/dist/jsx/hooks/index.mjs +3 -2
  173. package/dist/jsx/hooks/index.mjs.map +1 -0
  174. package/dist/jsx/hooks/useAuthConfig.mjs +2 -1
  175. package/dist/jsx/hooks/useAuthConfig.mjs.map +1 -0
  176. package/dist/jsx/hooks/useTokensFromQuery/index.mjs +2 -1
  177. package/dist/jsx/hooks/useTokensFromQuery/index.mjs.map +1 -0
  178. package/dist/jsx/hooks/useTokensFromState.js +6 -5
  179. package/dist/jsx/hooks/useTokensFromState.js.map +1 -1
  180. package/dist/jsx/hooks/useTokensFromState.mjs +6 -5
  181. package/dist/jsx/hooks/useTokensFromState.mjs.map +1 -0
  182. package/dist/jsx/hooks/useTokensFromState.native.js +6 -5
  183. package/dist/jsx/hooks/useTokensFromState.native.js.map +2 -2
  184. package/dist/jsx/index.mjs +6 -5
  185. package/dist/jsx/index.mjs.map +1 -0
  186. package/dist/jsx/keycloak/config.mjs +2 -1
  187. package/dist/jsx/keycloak/config.mjs.map +1 -0
  188. package/dist/jsx/keycloak/context.js.map +1 -1
  189. package/dist/jsx/keycloak/context.mjs +2 -1
  190. package/dist/jsx/keycloak/context.mjs.map +1 -0
  191. package/dist/jsx/keycloak/context.native.js.map +1 -1
  192. package/dist/jsx/keycloak/index.mjs +2 -1
  193. package/dist/jsx/keycloak/index.mjs.map +1 -0
  194. package/dist/jsx/keycloak/keycloak.js +14 -11
  195. package/dist/jsx/keycloak/keycloak.js.map +1 -1
  196. package/dist/jsx/keycloak/keycloak.mjs +8 -7
  197. package/dist/jsx/keycloak/keycloak.mjs.map +1 -0
  198. package/dist/jsx/keycloak/keycloak.native.js +29 -211
  199. package/dist/jsx/keycloak/keycloak.native.js.map +2 -2
  200. package/dist/jsx/provider/AfterAuth.js +16 -8
  201. package/dist/jsx/provider/AfterAuth.js.map +1 -1
  202. package/dist/jsx/provider/AfterAuth.mjs +13 -8
  203. package/dist/jsx/provider/AfterAuth.mjs.map +1 -0
  204. package/dist/jsx/provider/AfterAuth.native.js +7 -4
  205. package/dist/jsx/provider/AfterAuth.native.js.map +2 -2
  206. package/dist/jsx/provider/AuthProvider/AuthProvider.js +56 -19
  207. package/dist/jsx/provider/AuthProvider/AuthProvider.js.map +1 -1
  208. package/dist/jsx/provider/AuthProvider/AuthProvider.mjs +21 -14
  209. package/dist/jsx/provider/AuthProvider/AuthProvider.mjs.map +1 -0
  210. package/dist/jsx/provider/AuthProvider/AuthProvider.native.js +84 -323
  211. package/dist/jsx/provider/AuthProvider/AuthProvider.native.js.map +2 -2
  212. package/dist/jsx/provider/AuthProvider/index.mjs +2 -1
  213. package/dist/jsx/provider/AuthProvider/index.mjs.map +1 -0
  214. package/dist/jsx/provider/KeycloakProvider.js +4 -1
  215. package/dist/jsx/provider/KeycloakProvider.js.map +1 -1
  216. package/dist/jsx/provider/KeycloakProvider.mjs +3 -2
  217. package/dist/jsx/provider/KeycloakProvider.mjs.map +1 -0
  218. package/dist/jsx/provider/KeycloakProvider.native.js +1 -1
  219. package/dist/jsx/provider/KeycloakProvider.native.js.map +1 -1
  220. package/dist/jsx/provider/index.mjs +3 -2
  221. package/dist/jsx/provider/index.mjs.map +1 -0
  222. package/dist/jsx/routes.js +11 -10
  223. package/dist/jsx/routes.js.map +1 -1
  224. package/dist/jsx/routes.mjs +12 -12
  225. package/dist/jsx/routes.mjs.map +1 -0
  226. package/dist/jsx/routes.native.js +89 -332
  227. package/dist/jsx/routes.native.js.map +2 -2
  228. package/dist/jsx/session/index.mjs +2 -1
  229. package/dist/jsx/session/index.mjs.map +1 -0
  230. package/dist/jsx/session/session.js.map +1 -1
  231. package/dist/jsx/session/session.mjs +2 -1
  232. package/dist/jsx/session/session.mjs.map +1 -0
  233. package/dist/jsx/session/session.native.js +2 -122
  234. package/dist/jsx/session/session.native.js.map +1 -1
  235. package/dist/jsx/state.js +10 -14
  236. package/dist/jsx/state.js.map +1 -1
  237. package/dist/jsx/state.mjs +11 -14
  238. package/dist/jsx/state.mjs.map +1 -0
  239. package/dist/jsx/state.native.js +19 -11
  240. package/dist/jsx/state.native.js.map +2 -2
  241. package/dist/jsx/token.js.map +1 -1
  242. package/dist/jsx/token.mjs +2 -1
  243. package/dist/jsx/token.mjs.map +1 -0
  244. package/dist/jsx/token.native.js +1 -1
  245. package/dist/jsx/token.native.js.map +1 -1
  246. package/dist/jsx/types.mjs +2 -0
  247. package/dist/jsx/types.mjs.map +1 -0
  248. package/package.json +12 -15
  249. package/routes/index.d.ts +1 -1
  250. package/routes/index.js +1 -1
  251. package/src/@types/expoKeycloakAuth.d.ts +1 -1
  252. package/src/Authenticated.tsx +41 -15
  253. package/src/Loading.tsx +37 -0
  254. package/src/authConfig.ts +2 -2
  255. package/src/hooks/index.ts +3 -3
  256. package/src/hooks/useAuthConfig.ts +2 -2
  257. package/src/hooks/useTokensFromQuery/index.ts +4 -4
  258. package/src/hooks/useTokensFromState.ts +6 -5
  259. package/src/index.ts +7 -7
  260. package/src/keycloak/config.ts +6 -6
  261. package/src/keycloak/context.ts +3 -3
  262. package/src/keycloak/index.ts +2 -2
  263. package/src/keycloak/keycloak.native.ts +35 -27
  264. package/src/keycloak/keycloak.ts +48 -37
  265. package/src/provider/AfterAuth.tsx +33 -17
  266. package/src/provider/AuthProvider/AuthProvider.native.tsx +78 -29
  267. package/src/provider/AuthProvider/AuthProvider.tsx +143 -81
  268. package/src/provider/AuthProvider/index.ts +1 -1
  269. package/src/provider/KeycloakProvider.tsx +12 -9
  270. package/src/provider/index.ts +3 -3
  271. package/src/routes.ts +45 -35
  272. package/src/session/index.ts +1 -1
  273. package/src/session/session.native.ts +5 -3
  274. package/src/session/session.ts +14 -7
  275. package/src/state.ts +12 -16
  276. package/src/token.ts +9 -6
  277. package/types/Authenticated.d.ts +3 -3
  278. package/types/Authenticated.d.ts.map +1 -1
  279. package/types/Loading.d.ts +6 -0
  280. package/types/Loading.d.ts.map +1 -0
  281. package/types/hooks/index.d.ts +3 -3
  282. package/types/hooks/useTokensFromState.d.ts +1 -1
  283. package/types/hooks/useTokensFromState.d.ts.map +1 -1
  284. package/types/index.d.ts +7 -7
  285. package/types/keycloak/config.d.ts +1 -1
  286. package/types/keycloak/context.d.ts +1 -1
  287. package/types/keycloak/context.d.ts.map +1 -1
  288. package/types/keycloak/index.d.ts +2 -2
  289. package/types/keycloak/keycloak.d.ts +7 -7
  290. package/types/keycloak/keycloak.d.ts.map +1 -1
  291. package/types/keycloak/keycloak.native.d.ts +5 -5
  292. package/types/keycloak/keycloak.native.d.ts.map +1 -1
  293. package/types/provider/AfterAuth.d.ts +3 -3
  294. package/types/provider/AfterAuth.d.ts.map +1 -1
  295. package/types/provider/AuthProvider/AuthProvider.d.ts +8 -7
  296. package/types/provider/AuthProvider/AuthProvider.d.ts.map +1 -1
  297. package/types/provider/AuthProvider/AuthProvider.native.d.ts +3 -3
  298. package/types/provider/AuthProvider/AuthProvider.native.d.ts.map +1 -1
  299. package/types/provider/AuthProvider/index.d.ts +1 -1
  300. package/types/provider/KeycloakProvider.d.ts +4 -4
  301. package/types/provider/KeycloakProvider.d.ts.map +1 -1
  302. package/types/provider/index.d.ts +3 -3
  303. package/types/routes.d.ts +4 -4
  304. package/types/routes.d.ts.map +1 -1
  305. package/types/session/index.d.ts +1 -1
  306. package/types/session/session.d.ts +3 -3
  307. package/types/session/session.d.ts.map +1 -1
  308. package/types/session/session.native.d.ts +2 -2
  309. package/types/session/session.native.d.ts.map +1 -1
  310. package/types/state.d.ts +4 -6
  311. package/types/state.d.ts.map +1 -1
  312. package/types/token.d.ts +2 -2
  313. package/types/token.d.ts.map +1 -1
@@ -19,28 +19,31 @@
19
19
  * limitations under the License.
20
20
  */
21
21
 
22
- 'use client';
22
+ "use client";
23
23
 
24
- import KeycloakClient from 'keycloak-js';
25
- import React, { useEffect, useMemo, useState } from 'react';
26
- import type { KeycloakInitOptions } from 'keycloak-js';
27
- import type { KeycloakConfig } from '../../keycloak';
28
- import type { PropsWithChildren } from 'react';
29
- import type { SessionProviderProps } from 'next-auth/react';
30
- import { AfterAuth } from '../AfterAuth';
31
- import { Keycloak, KeycloakConfigContext } from '../../keycloak';
32
- import { KeycloakContext } from '../../keycloak/context';
33
- import { MultiPlatform } from 'multiplatform.one';
34
- import { SessionProvider } from 'next-auth/react';
35
- import { persist, useAuthState } from '../../state';
36
- import { useAuthConfig } from '../../hooks';
37
- import { useRouter } from 'next/router';
38
- import { validOrRefreshableToken } from '../../token';
24
+ import KeycloakClient from "keycloak-js";
25
+ import type { KeycloakInitOptions } from "keycloak-js";
26
+ import { MultiPlatform } from "multiplatform.one";
27
+ import type { SessionProviderProps } from "next-auth/react";
28
+ import { SessionProvider } from "next-auth/react";
29
+ import { useRouter } from "next/router";
30
+ import type { PropsWithChildren } from "react";
31
+ import { type ComponentType, useEffect, useMemo, useState } from "react";
32
+ import { Text } from "tamagui";
33
+ import { Loading } from "../../Loading";
34
+ import { useAuthConfig } from "../../hooks";
35
+ import type { KeycloakConfig } from "../../keycloak";
36
+ import { Keycloak, KeycloakConfigContext } from "../../keycloak";
37
+ import { KeycloakContext } from "../../keycloak/context";
38
+ import { persist, useAuthStore } from "../../state";
39
+ import { validOrRefreshableToken } from "../../token";
40
+ import { AfterAuth } from "../AfterAuth";
39
41
 
40
42
  export interface AuthProviderProps extends PropsWithChildren {
41
43
  keycloakConfig: KeycloakConfig;
42
44
  keycloakInitOptions?: KeycloakInitOptions;
43
- sessionProvider?: Omit<SessionProviderProps, 'children'>;
45
+ sessionProvider?: Omit<SessionProviderProps, "children">;
46
+ loadingComponent?: ComponentType;
44
47
  }
45
48
 
46
49
  const logger = console;
@@ -51,17 +54,27 @@ export interface Tokens<B = boolean> {
51
54
  token?: string | B;
52
55
  }
53
56
 
54
- export function AuthProvider({ children, sessionProvider, keycloakInitOptions, keycloakConfig }: AuthProviderProps) {
57
+ export function AuthProvider({
58
+ children,
59
+ keycloakConfig,
60
+ keycloakInitOptions,
61
+ loadingComponent,
62
+ sessionProvider,
63
+ }: AuthProviderProps) {
55
64
  const { debug, messageHandlerKeys } = useAuthConfig();
56
65
  const { query } = MultiPlatform.isNext ? useRouter() : { query: {} };
57
- const authState = useAuthState();
66
+ const authStore = useAuthStore();
67
+ if (typeof authStore === "undefined") {
68
+ return <Loading loadingComponent={loadingComponent} />;
69
+ }
58
70
  const [keycloak, setKeycloak] = useState<Keycloak>();
59
71
  const initialRefreshToken = useMemo(
60
72
  () =>
61
73
  validOrRefreshableToken(
62
74
  MultiPlatform.isIframe
63
- ? ('refreshToken' in query && (query.refreshToken?.toString() || true)) ||
64
- (persist && authState.refreshToken) ||
75
+ ? ("refreshToken" in query &&
76
+ (query.refreshToken?.toString() || true)) ||
77
+ (persist && authStore.refreshToken) ||
65
78
  undefined
66
79
  : undefined,
67
80
  ),
@@ -71,58 +84,72 @@ export function AuthProvider({ children, sessionProvider, keycloakInitOptions, k
71
84
  refreshToken: initialRefreshToken,
72
85
  token: validOrRefreshableToken(
73
86
  MultiPlatform.isIframe
74
- ? ('token' in query && (query.token?.toString() || true)) || (persist && authState.token) || undefined
87
+ ? ("token" in query && (query.token?.toString() || true)) ||
88
+ (persist && authStore.token) ||
89
+ undefined
75
90
  : undefined,
76
91
  initialRefreshToken,
77
92
  ),
78
93
  idToken: validOrRefreshableToken(
79
94
  MultiPlatform.isIframe
80
- ? ('idToken' in query && (query.idToken?.toString() || true)) || (persist && authState.idToken) || undefined
95
+ ? ("idToken" in query && (query.idToken?.toString() || true)) ||
96
+ (persist && authStore.idToken) ||
97
+ undefined
81
98
  : undefined,
82
99
  initialRefreshToken,
83
100
  ),
84
101
  });
85
102
 
86
103
  useEffect(() => {
87
- if (tokens.token !== true && tokens.refreshToken !== true && tokens.idToken !== true) return;
88
- if (debug) logger.debug('post message', JSON.stringify({ type: 'LOADED' }));
104
+ if (
105
+ tokens.token !== true &&
106
+ tokens.refreshToken !== true &&
107
+ tokens.idToken !== true
108
+ )
109
+ return;
110
+ if (debug) logger.debug("post message", JSON.stringify({ type: "LOADED" }));
89
111
  (messageHandlerKeys || []).forEach((key: string) => {
90
- window?.webkit?.messageHandlers?.[key]?.postMessage(JSON.stringify({ type: 'LOADED' }));
112
+ window?.webkit?.messageHandlers?.[key]?.postMessage(
113
+ JSON.stringify({ type: "LOADED" }),
114
+ );
91
115
  });
92
- window?.ReactNativeWebView?.postMessage(JSON.stringify({ type: 'LOADED' }));
93
- window?.parent?.postMessage(JSON.stringify({ type: 'LOADED' }));
116
+ window?.ReactNativeWebView?.postMessage(JSON.stringify({ type: "LOADED" }));
117
+ window?.parent?.postMessage(JSON.stringify({ type: "LOADED" }));
94
118
  }, []);
95
119
 
96
120
  useEffect(() => {
97
121
  if (tokens.refreshToken !== true) return;
98
122
  const messageCallback = (e: MessageEvent<any>) => {
99
123
  let data = e?.data || null;
100
- if (typeof data === 'string') {
124
+ if (typeof data === "string") {
101
125
  try {
102
126
  data = JSON.parse(data);
103
127
  } catch (err) {}
104
128
  }
105
- if (debug) logger.debug('received message', JSON.stringify(data));
129
+ if (debug) logger.debug("received message", JSON.stringify(data));
106
130
  const message: MessageSchema = data;
107
131
  if (!message.type) return;
108
- if (message.type.toUpperCase() === 'REFRESH_TOKEN' && message.payload) {
109
- if (debug) logger.debug('setting refresh token', message.payload);
110
- setTokens((tokens) => ({ ...tokens, refreshToken: validOrRefreshableToken(message.payload) }));
111
- window.removeEventListener('message', messageCallback);
132
+ if (message.type.toUpperCase() === "REFRESH_TOKEN" && message.payload) {
133
+ if (debug) logger.debug("setting refresh token", message.payload);
134
+ setTokens((tokens) => ({
135
+ ...tokens,
136
+ refreshToken: validOrRefreshableToken(message.payload),
137
+ }));
138
+ window.removeEventListener("message", messageCallback);
112
139
  }
113
140
  };
114
141
  if (debug) {
115
142
  logger.debug(
116
- 'listening for message',
143
+ "listening for message",
117
144
  JSON.stringify({
118
- type: 'REFRESH_TOKEN',
119
- payload: '<some_refresh_token>',
145
+ type: "REFRESH_TOKEN",
146
+ payload: "<some_refresh_token>",
120
147
  }),
121
148
  );
122
149
  }
123
- window.addEventListener('message', messageCallback);
150
+ window.addEventListener("message", messageCallback);
124
151
  return () => {
125
- window.removeEventListener('message', messageCallback);
152
+ window.removeEventListener("message", messageCallback);
126
153
  };
127
154
  }, []);
128
155
 
@@ -130,32 +157,35 @@ export function AuthProvider({ children, sessionProvider, keycloakInitOptions, k
130
157
  if (tokens.token !== true) return;
131
158
  const messageCallback = (e: MessageEvent<any>) => {
132
159
  let data = e?.data || null;
133
- if (typeof data === 'string') {
160
+ if (typeof data === "string") {
134
161
  try {
135
162
  data = JSON.parse(data);
136
163
  } catch (err) {}
137
164
  }
138
- if (debug) logger.debug('received message', JSON.stringify(data));
165
+ if (debug) logger.debug("received message", JSON.stringify(data));
139
166
  const message: MessageSchema = data;
140
167
  if (!message.type) return;
141
- if (message.type.toUpperCase() === 'TOKEN' && message.payload) {
142
- if (debug) logger.debug('setting token', message.payload);
143
- setTokens((tokens) => ({ ...tokens, token: validOrRefreshableToken(message.payload, tokens.refreshToken) }));
144
- window.removeEventListener('message', messageCallback);
168
+ if (message.type.toUpperCase() === "TOKEN" && message.payload) {
169
+ if (debug) logger.debug("setting token", message.payload);
170
+ setTokens((tokens) => ({
171
+ ...tokens,
172
+ token: validOrRefreshableToken(message.payload, tokens.refreshToken),
173
+ }));
174
+ window.removeEventListener("message", messageCallback);
145
175
  }
146
176
  };
147
177
  if (debug) {
148
178
  logger.debug(
149
- 'listening for message',
179
+ "listening for message",
150
180
  JSON.stringify({
151
- type: 'TOKEN',
152
- payload: '<some_token>',
181
+ type: "TOKEN",
182
+ payload: "<some_token>",
153
183
  }),
154
184
  );
155
185
  }
156
- window.addEventListener('message', messageCallback);
186
+ window.addEventListener("message", messageCallback);
157
187
  return () => {
158
- window.removeEventListener('message', messageCallback);
188
+ window.removeEventListener("message", messageCallback);
159
189
  };
160
190
  }, []);
161
191
 
@@ -163,85 +193,117 @@ export function AuthProvider({ children, sessionProvider, keycloakInitOptions, k
163
193
  if (tokens.idToken !== true) return;
164
194
  const messageCallback = (e: MessageEvent<any>) => {
165
195
  let data = e?.data || null;
166
- if (typeof data === 'string') {
196
+ if (typeof data === "string") {
167
197
  try {
168
198
  data = JSON.parse(data);
169
199
  } catch (err) {}
170
200
  }
171
- if (debug) logger.debug('received message', JSON.stringify(data));
201
+ if (debug) logger.debug("received message", JSON.stringify(data));
172
202
  const message: MessageSchema = data;
173
203
  if (!message.type) return;
174
- if (message.type.toUpperCase() === 'ID_TOKEN' && message.payload) {
175
- if (debug) logger.debug('setting id token', message.payload);
176
- setTokens((tokens) => ({ ...tokens, idToken: validOrRefreshableToken(message.payload, tokens.refreshToken) }));
177
- window.removeEventListener('message', messageCallback);
204
+ if (message.type.toUpperCase() === "ID_TOKEN" && message.payload) {
205
+ if (debug) logger.debug("setting id token", message.payload);
206
+ setTokens((tokens) => ({
207
+ ...tokens,
208
+ idToken: validOrRefreshableToken(
209
+ message.payload,
210
+ tokens.refreshToken,
211
+ ),
212
+ }));
213
+ window.removeEventListener("message", messageCallback);
178
214
  }
179
215
  };
180
216
  if (debug) {
181
217
  logger.debug(
182
- 'listening for message',
218
+ "listening for message",
183
219
  JSON.stringify({
184
- type: 'ID_TOKEN',
185
- payload: '<some_id_token>',
220
+ type: "ID_TOKEN",
221
+ payload: "<some_id_token>",
186
222
  }),
187
223
  );
188
224
  }
189
- window.addEventListener('message', messageCallback);
225
+ window.addEventListener("message", messageCallback);
190
226
  return () => {
191
- window.removeEventListener('message', messageCallback);
227
+ window.removeEventListener("message", messageCallback);
192
228
  };
193
229
  }, []);
194
230
 
195
231
  const keycloakClient = useMemo(
196
232
  () =>
197
- (!MultiPlatform.isNext || MultiPlatform.isElectron || MultiPlatform.isIframe) && keycloakConfig
233
+ (!MultiPlatform.isNext ||
234
+ MultiPlatform.isElectron ||
235
+ MultiPlatform.isIframe) &&
236
+ keycloakConfig
198
237
  ? new KeycloakClient({
199
238
  url: keycloakConfig.url,
200
239
  realm: keycloakConfig.realm,
201
240
  clientId: keycloakConfig.publicClientId || keycloakConfig.clientId,
202
241
  })
203
242
  : undefined,
204
- [keycloakInitOptions, keycloakConfig, tokens.token, tokens.refreshToken, tokens.idToken],
243
+ [
244
+ keycloakInitOptions,
245
+ keycloakConfig,
246
+ tokens.token,
247
+ tokens.refreshToken,
248
+ tokens.idToken,
249
+ ],
205
250
  );
206
251
 
207
252
  const initOptions = useMemo(() => {
208
- if (MultiPlatform.isNext && !MultiPlatform.isElectron && !MultiPlatform.isIframe) return;
253
+ if (
254
+ MultiPlatform.isNext &&
255
+ !MultiPlatform.isElectron &&
256
+ !MultiPlatform.isIframe
257
+ )
258
+ return;
209
259
  const initOptions: KeycloakInitOptions = {
210
260
  ...defaultKeycloakInitOptions,
211
261
  ...keycloakInitOptions,
212
262
  scope: [
213
263
  ...new Set([
214
- 'email',
215
- 'openid',
216
- 'profile',
217
- ...(defaultKeycloakInitOptions.scope?.split(' ') || []),
218
- ...(keycloakInitOptions?.scope?.split(' ') || []),
264
+ "email",
265
+ "openid",
266
+ "profile",
267
+ ...(defaultKeycloakInitOptions.scope?.split(" ") || []),
268
+ ...(keycloakInitOptions?.scope?.split(" ") || []),
219
269
  ...(keycloakConfig.scopes || []),
220
270
  ]),
221
- ].join(' '),
271
+ ].join(" "),
222
272
  };
223
273
  if (debug) initOptions.enableLogging = true;
224
- if (tokens.token && typeof tokens.token === 'string') {
274
+ if (tokens.token && typeof tokens.token === "string") {
225
275
  initOptions.token = tokens.token;
226
276
  initOptions.timeSkew = 0;
227
- if (tokens.idToken && typeof tokens.idToken === 'string') initOptions.idToken = tokens.idToken;
228
- if (tokens.refreshToken && typeof tokens.refreshToken === 'string')
277
+ if (tokens.idToken && typeof tokens.idToken === "string")
278
+ initOptions.idToken = tokens.idToken;
279
+ if (tokens.refreshToken && typeof tokens.refreshToken === "string")
229
280
  initOptions.refreshToken = tokens.refreshToken;
230
281
  }
231
- if ((typeof window !== 'undefined' && window.self !== window.top) || (tokens.token && !tokens.refreshToken)) {
282
+ if (
283
+ (typeof window !== "undefined" && window.self !== window.top) ||
284
+ (tokens.token && !tokens.refreshToken)
285
+ ) {
232
286
  initOptions.checkLoginIframe = false;
233
- initOptions.flow = 'implicit';
287
+ initOptions.flow = "implicit";
234
288
  initOptions.onLoad = undefined;
235
289
  }
236
290
  return initOptions;
237
- }, [keycloakInitOptions, keycloakConfig.scopes, tokens.token, tokens.idToken, tokens.refreshToken]);
291
+ }, [
292
+ keycloakInitOptions,
293
+ keycloakConfig.scopes,
294
+ tokens.token,
295
+ tokens.idToken,
296
+ tokens.refreshToken,
297
+ ]);
238
298
 
239
299
  useEffect(() => {
240
300
  function onError() {
241
- if (keycloakClient && initOptions) setKeycloak(new Keycloak(keycloakConfig, keycloakClient));
301
+ if (keycloakClient && initOptions)
302
+ setKeycloak(new Keycloak(keycloakConfig, keycloakClient));
242
303
  }
243
304
  function onUpdate() {
244
- if (keycloakClient && initOptions) setKeycloak(new Keycloak(keycloakConfig, keycloakClient));
305
+ if (keycloakClient && initOptions)
306
+ setKeycloak(new Keycloak(keycloakConfig, keycloakClient));
245
307
  }
246
308
  if (keycloakClient && initOptions) {
247
309
  (async () => {
@@ -268,7 +330,7 @@ export function AuthProvider({ children, sessionProvider, keycloakInitOptions, k
268
330
  return (
269
331
  <KeycloakConfigContext.Provider value={keycloakConfig}>
270
332
  <KeycloakContext.Provider value={keycloak}>
271
- <AfterAuth>{children}</AfterAuth>
333
+ <AfterAuth loadingComponent={loadingComponent}>{children}</AfterAuth>
272
334
  </KeycloakContext.Provider>
273
335
  </KeycloakConfigContext.Provider>
274
336
  );
@@ -284,8 +346,8 @@ const defaultKeycloakInitOptions: KeycloakInitOptions = {
284
346
  checkLoginIframe: true,
285
347
  checkLoginIframeInterval: 5,
286
348
  enableLogging: false,
287
- onLoad: 'check-sso',
288
- pkceMethod: 'S256',
349
+ onLoad: "check-sso",
350
+ pkceMethod: "S256",
289
351
  };
290
352
 
291
353
  export interface MessageSchema {
@@ -19,4 +19,4 @@
19
19
  * limitations under the License.
20
20
  */
21
21
 
22
- export * from './AuthProvider';
22
+ export * from "./AuthProvider";
@@ -19,12 +19,12 @@
19
19
  * limitations under the License.
20
20
  */
21
21
 
22
- import React, { useMemo } from 'react';
23
- import type { AuthConfig } from '../authConfig';
24
- import type { PropsWithChildren } from 'react';
25
- import type { Session } from 'next-auth';
26
- import { AuthConfigContext } from '../authConfig';
27
- import { AuthProvider } from './AuthProvider';
22
+ import type { Session } from "next-auth";
23
+ import React, { useMemo } from "react";
24
+ import type { PropsWithChildren } from "react";
25
+ import type { AuthConfig } from "../authConfig";
26
+ import { AuthConfigContext } from "../authConfig";
27
+ import { AuthProvider } from "./AuthProvider";
28
28
 
29
29
  export interface KeycloakProviderProps extends PropsWithChildren, AuthConfig {
30
30
  baseUrl?: string;
@@ -45,7 +45,10 @@ export function KeycloakProvider({
45
45
  realm,
46
46
  session,
47
47
  }: KeycloakProviderProps) {
48
- const authConfig = useMemo(() => ({ debug, disabled, loginRedirectUri }), [debug, disabled, loginRedirectUri]);
48
+ const authConfig = useMemo(
49
+ () => ({ debug, disabled, loginRedirectUri }),
50
+ [debug, disabled, loginRedirectUri],
51
+ );
49
52
  return (
50
53
  <AuthConfigContext.Provider value={authConfig}>
51
54
  {disabled ? (
@@ -54,9 +57,9 @@ export function KeycloakProvider({
54
57
  <AuthProvider
55
58
  sessionProvider={{ session }}
56
59
  keycloakConfig={{
57
- clientId: clientId || 'app',
60
+ clientId: clientId || "app",
58
61
  publicClientId,
59
- realm: realm || 'main',
62
+ realm: realm || "main",
60
63
  url: baseUrl,
61
64
  }}
62
65
  >
@@ -19,6 +19,6 @@
19
19
  * limitations under the License.
20
20
  */
21
21
 
22
- export * from './AfterAuth';
23
- export * from './AuthProvider';
24
- export * from './KeycloakProvider';
22
+ export * from "./AfterAuth";
23
+ export * from "./AuthProvider";
24
+ export * from "./KeycloakProvider";
package/src/routes.ts CHANGED
@@ -19,20 +19,22 @@
19
19
  * limitations under the License.
20
20
  */
21
21
 
22
- import type { AccessTokenParsed } from './token';
23
- import type { AuthOptions, CallbacksOptions } from 'next-auth';
24
- import type { JWT } from 'next-auth/jwt';
25
- import type { OAuthUserConfig } from 'next-auth/providers';
26
- import type { Session } from './session';
27
- import { getServerSession } from 'next-auth';
28
- import { jwtDecode } from 'jwt-decode';
22
+ import { jwtDecode } from "jwt-decode";
23
+ import type { AuthOptions, CallbacksOptions } from "next-auth";
24
+ import { getServerSession } from "next-auth";
25
+ import type { JWT } from "next-auth/jwt";
26
+ import type { OAuthUserConfig } from "next-auth/providers";
27
+ import type { Session } from "./session";
28
+ import type { AccessTokenParsed } from "./token";
29
29
 
30
- const NextAuth = require('next-auth').default as typeof import('next-auth').default;
31
- const NextResponse = require('next/server').NextResponse as typeof import('next/server').NextResponse;
30
+ const NextAuth = require("next-auth")
31
+ .default as typeof import("next-auth").default;
32
+ const NextResponse = require("next/server")
33
+ .NextResponse as typeof import("next/server").NextResponse;
32
34
  const logger = console;
33
35
  let _nextAuth: AuthOptions | undefined;
34
- const KeycloakProvider = require('next-auth/providers/keycloak')
35
- .default as typeof import('next-auth/providers/keycloak').default;
36
+ const KeycloakProvider = require("next-auth/providers/keycloak")
37
+ .default as typeof import("next-auth/providers/keycloak").default;
36
38
 
37
39
  export function createAuthHandler(options: AuthHandlerOptions) {
38
40
  return NextAuth(createNextAuthOptions(options));
@@ -40,15 +42,17 @@ export function createAuthHandler(options: AuthHandlerOptions) {
40
42
 
41
43
  const defaults = {
42
44
  keycloak: {
43
- baseUrl: 'http://localhost:8080',
44
- realm: 'master',
45
+ baseUrl: "http://localhost:8080",
46
+ realm: "master",
45
47
  },
46
48
  };
47
49
 
48
50
  export function createLogoutHandler(options: AuthHandlerOptions) {
49
51
  return {
50
52
  async GET() {
51
- const idToken = ((await getServerSession(createNextAuthOptions(options))) as Session)?.idToken;
53
+ const idToken = (
54
+ (await getServerSession(createNextAuthOptions(options))) as Session
55
+ )?.idToken;
52
56
  if (idToken) {
53
57
  try {
54
58
  await fetch(
@@ -57,7 +61,7 @@ export function createLogoutHandler(options: AuthHandlerOptions) {
57
61
  }/protocol/openid-connect/logout?id_token_hint=${idToken}&post_logout_redirect_uri=${encodeURIComponent(
58
62
  options.baseUrl,
59
63
  )}`,
60
- { method: 'GET' },
64
+ { method: "GET" },
61
65
  );
62
66
  } catch (err) {
63
67
  logger.error(err);
@@ -72,7 +76,8 @@ export function createLogoutHandler(options: AuthHandlerOptions) {
72
76
  export function createNextAuthOptions(options: AuthHandlerOptions) {
73
77
  if (_nextAuth) return _nextAuth;
74
78
  const authorization =
75
- options.keycloak.authorization && typeof options.keycloak.authorization === 'object'
79
+ options.keycloak.authorization &&
80
+ typeof options.keycloak.authorization === "object"
76
81
  ? options.keycloak.authorization
77
82
  : {};
78
83
  _nextAuth = {
@@ -85,13 +90,13 @@ export function createNextAuthOptions(options: AuthHandlerOptions) {
85
90
  params: {
86
91
  scope: [
87
92
  ...new Set([
88
- 'email',
89
- 'openid',
90
- 'profile',
91
- ...(authorization.params?.scope?.split(' ') || []),
93
+ "email",
94
+ "openid",
95
+ "profile",
96
+ ...(authorization.params?.scope?.split(" ") || []),
92
97
  ...(options.scopes || []),
93
98
  ]),
94
- ].join(' '),
99
+ ].join(" "),
95
100
  },
96
101
  },
97
102
  ...options.keycloak,
@@ -101,12 +106,14 @@ export function createNextAuthOptions(options: AuthHandlerOptions) {
101
106
  callbacks: {
102
107
  ...options.nextAuth?.callbacks,
103
108
  async jwt(params) {
104
- if (typeof options.nextAuth?.callbacks?.jwt === 'function') {
109
+ if (typeof options.nextAuth?.callbacks?.jwt === "function") {
105
110
  return options.nextAuth?.callbacks.jwt(params);
106
111
  }
107
112
  const { token, account } = params;
108
113
  if (account) {
109
- const decoded = jwtDecode(account.access_token || '') as AccessTokenParsed;
114
+ const decoded = jwtDecode(
115
+ account.access_token || "",
116
+ ) as AccessTokenParsed;
110
117
  token.decoded = decoded;
111
118
  token.accessToken = account.access_token;
112
119
  token.idToken = account.id_token;
@@ -114,18 +121,18 @@ export function createNextAuthOptions(options: AuthHandlerOptions) {
114
121
  token.refreshToken = account.refresh_token;
115
122
  token.roles = decoded.realm_access?.roles;
116
123
  return token;
117
- } else if (Math.floor(Date.now() / 1000) < Number(token.expiresAt)) {
124
+ }
125
+ if (Math.floor(Date.now() / 1000) < Number(token.expiresAt)) {
118
126
  return token;
119
- } else {
120
- try {
121
- return refreshAccessToken(options, token as NextToken);
122
- } catch (err) {
123
- return { ...token, err };
124
- }
127
+ }
128
+ try {
129
+ return refreshAccessToken(options, token as NextToken);
130
+ } catch (err) {
131
+ return { ...token, err };
125
132
  }
126
133
  },
127
134
  async session(params) {
128
- if (typeof options.nextAuth?.callbacks?.session === 'function') {
135
+ if (typeof options.nextAuth?.callbacks?.session === "function") {
129
136
  return options.nextAuth.callbacks.session(params);
130
137
  }
131
138
  const { session: nextSession, token: nextToken } = params;
@@ -165,20 +172,23 @@ export interface NextToken extends JWT {
165
172
  roles: string[];
166
173
  }
167
174
 
168
- async function refreshAccessToken(options: AuthHandlerOptions, nextToken: NextToken) {
175
+ async function refreshAccessToken(
176
+ options: AuthHandlerOptions,
177
+ nextToken: NextToken,
178
+ ) {
169
179
  const res = await fetch(
170
180
  `${options.keycloak?.baseUrl || defaults.keycloak.baseUrl}/realms/${
171
181
  options.keycloak?.realm || defaults.keycloak.realm
172
182
  }/protocol/openid-connect/token`,
173
183
  {
174
- method: 'POST',
184
+ method: "POST",
175
185
  headers: {
176
- 'Content-Type': 'application/x-www-form-urlencoded',
186
+ "Content-Type": "application/x-www-form-urlencoded",
177
187
  },
178
188
  body: new URLSearchParams({
179
189
  client_id: options.keycloak.clientId,
180
190
  client_secret: options.keycloak.clientSecret,
181
- grant_type: 'refresh_token',
191
+ grant_type: "refresh_token",
182
192
  refresh_token: nextToken.refreshToken,
183
193
  }),
184
194
  },
@@ -19,4 +19,4 @@
19
19
  * limitations under the License.
20
20
  */
21
21
 
22
- export * from './session';
22
+ export * from "./session";
@@ -19,13 +19,15 @@
19
19
  * limitations under the License.
20
20
  */
21
21
 
22
- import type { SessionContextValue } from './session';
23
- import type { UseSessionOptions } from 'next-auth/react';
22
+ import type { UseSessionOptions } from "next-auth/react";
23
+ import type { SessionContextValue } from "./session";
24
24
 
25
25
  export async function getSession() {
26
26
  return null;
27
27
  }
28
28
 
29
- export function useSession<R extends boolean>(_options?: UseSessionOptions<R>): SessionContextValue<R> {
29
+ export function useSession<R extends boolean>(
30
+ _options?: UseSessionOptions<R>,
31
+ ): SessionContextValue<R> {
30
32
  return {};
31
33
  }