@clerk/expo-native-components 0.0.0-stage → 0.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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -2
  3. package/android/build.gradle +152 -0
  4. package/android/src/main/AndroidManifest.xml +4 -0
  5. package/android/src/main/java/expo/modules/clerk/ClerkAuthViewModule.kt +241 -0
  6. package/android/src/main/java/expo/modules/clerk/ClerkComposeNativeViewHost.kt +148 -0
  7. package/android/src/main/java/expo/modules/clerk/ClerkExpoModule.kt +1077 -0
  8. package/android/src/main/java/expo/modules/clerk/ClerkUserButtonViewModule.kt +156 -0
  9. package/android/src/main/java/expo/modules/clerk/ClerkUserProfileCustomPageState.kt +120 -0
  10. package/android/src/main/java/expo/modules/clerk/ClerkUserProfileViewModule.kt +315 -0
  11. package/android/src/test/java/expo/modules/clerk/BiometricCredentialBridgeTest.kt +326 -0
  12. package/android/src/test/java/expo/modules/clerk/ClerkUserProfileCustomPageStateTest.kt +163 -0
  13. package/app.plugin.d.ts +5 -0
  14. package/app.plugin.js +333 -0
  15. package/dist/AuthView.d.ts +35 -0
  16. package/dist/AuthView.d.ts.map +1 -0
  17. package/dist/AuthView.js +79 -0
  18. package/dist/AuthView.js.map +1 -0
  19. package/dist/AuthView.types.d.ts +62 -0
  20. package/dist/AuthView.types.d.ts.map +1 -0
  21. package/dist/AuthView.types.js +0 -0
  22. package/dist/EmbeddedNavigation.types.d.ts +24 -0
  23. package/dist/EmbeddedNavigation.types.d.ts.map +1 -0
  24. package/dist/EmbeddedNavigation.types.js +0 -0
  25. package/dist/UserButton.d.ts +38 -0
  26. package/dist/UserButton.d.ts.map +1 -0
  27. package/dist/UserButton.js +68 -0
  28. package/dist/UserButton.js.map +1 -0
  29. package/dist/UserProfileCustomPages.d.ts +81 -0
  30. package/dist/UserProfileCustomPages.d.ts.map +1 -0
  31. package/dist/UserProfileCustomPages.js +140 -0
  32. package/dist/UserProfileCustomPages.js.map +1 -0
  33. package/dist/UserProfileView.d.ts +76 -0
  34. package/dist/UserProfileView.d.ts.map +1 -0
  35. package/dist/UserProfileView.js +101 -0
  36. package/dist/UserProfileView.js.map +1 -0
  37. package/dist/_virtual/_rolldown/runtime.js +29 -0
  38. package/dist/index.d.ts +41 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +37 -0
  41. package/dist/specs/NativeClerkAuthView.android.d.ts +15 -0
  42. package/dist/specs/NativeClerkAuthView.android.d.ts.map +1 -0
  43. package/dist/specs/NativeClerkAuthView.android.js +8 -0
  44. package/dist/specs/NativeClerkAuthView.android.js.map +1 -0
  45. package/dist/specs/NativeClerkAuthView.d.ts +15 -0
  46. package/dist/specs/NativeClerkAuthView.d.ts.map +1 -0
  47. package/dist/specs/NativeClerkAuthView.js +9 -0
  48. package/dist/specs/NativeClerkAuthView.js.map +1 -0
  49. package/dist/specs/NativeClerkModule.d.ts +4 -0
  50. package/dist/specs/NativeClerkModule.d.ts.map +1 -0
  51. package/dist/specs/NativeClerkModule.js +8 -0
  52. package/dist/specs/NativeClerkModule.js.map +1 -0
  53. package/dist/specs/NativeClerkModule.types.d.ts +11 -0
  54. package/dist/specs/NativeClerkModule.types.d.ts.map +1 -0
  55. package/dist/specs/NativeClerkModule.types.js +0 -0
  56. package/dist/specs/NativeClerkModule.web.d.ts +4 -0
  57. package/dist/specs/NativeClerkModule.web.d.ts.map +1 -0
  58. package/dist/specs/NativeClerkModule.web.js +7 -0
  59. package/dist/specs/NativeClerkModule.web.js.map +1 -0
  60. package/dist/specs/NativeClerkUserButtonView.android.d.ts +6 -0
  61. package/dist/specs/NativeClerkUserButtonView.android.d.ts.map +1 -0
  62. package/dist/specs/NativeClerkUserButtonView.android.js +8 -0
  63. package/dist/specs/NativeClerkUserButtonView.android.js.map +1 -0
  64. package/dist/specs/NativeClerkUserButtonView.d.ts +6 -0
  65. package/dist/specs/NativeClerkUserButtonView.d.ts.map +1 -0
  66. package/dist/specs/NativeClerkUserButtonView.js +9 -0
  67. package/dist/specs/NativeClerkUserButtonView.js.map +1 -0
  68. package/dist/specs/NativeClerkUserProfileView.android.d.ts +13 -0
  69. package/dist/specs/NativeClerkUserProfileView.android.d.ts.map +1 -0
  70. package/dist/specs/NativeClerkUserProfileView.android.js +8 -0
  71. package/dist/specs/NativeClerkUserProfileView.android.js.map +1 -0
  72. package/dist/specs/NativeClerkUserProfileView.d.ts +13 -0
  73. package/dist/specs/NativeClerkUserProfileView.d.ts.map +1 -0
  74. package/dist/specs/NativeClerkUserProfileView.js +9 -0
  75. package/dist/specs/NativeClerkUserProfileView.js.map +1 -0
  76. package/dist/useAuthViewState.d.ts +12 -0
  77. package/dist/useAuthViewState.d.ts.map +1 -0
  78. package/dist/useAuthViewState.js +76 -0
  79. package/dist/useAuthViewState.js.map +1 -0
  80. package/dist/utils/native-module.d.ts +3 -0
  81. package/dist/utils/native-module.d.ts.map +1 -0
  82. package/dist/utils/native-module.js +14 -0
  83. package/dist/utils/native-module.js.map +1 -0
  84. package/expo-module.config.json +15 -0
  85. package/ios/ClerkAppDelegateSubscriber.swift +16 -0
  86. package/ios/ClerkAuthNativeView.swift +157 -0
  87. package/ios/ClerkExpo.podspec +67 -0
  88. package/ios/ClerkExpoModule.swift +315 -0
  89. package/ios/ClerkNativeBridge.swift +1575 -0
  90. package/ios/ClerkNativeViewHost.swift +204 -0
  91. package/ios/ClerkUserButtonNativeView.swift +34 -0
  92. package/ios/ClerkUserProfileNativeView.swift +92 -0
  93. package/ios/Tests/ClerkAuthNativeViewPaperTests.swift +30 -0
  94. package/ios/Tests/ClerkNativeBridgeTests.swift +185 -0
  95. package/ios/Tests/ClerkNativeViewHostTests.swift +66 -0
  96. package/ios/Tests/ClerkUserProfileCustomPageStateTests.swift +311 -0
  97. package/package.json +79 -3
  98. package/react-native.config.js +8 -0
  99. package/src/specs/NativeClerkAuthView.android.ts +15 -0
  100. package/src/specs/NativeClerkAuthView.ts +19 -0
  101. package/src/specs/NativeClerkModule.ts +6 -0
  102. package/src/specs/NativeClerkModule.types.ts +9 -0
  103. package/src/specs/NativeClerkModule.web.ts +3 -0
  104. package/src/specs/NativeClerkUserButtonView.android.ts +9 -0
  105. package/src/specs/NativeClerkUserButtonView.ts +11 -0
  106. package/src/specs/NativeClerkUserProfileView.android.ts +13 -0
  107. package/src/specs/NativeClerkUserProfileView.ts +17 -0
  108. package/src/specs/__tests__/native-view.web.test.ts +43 -0
@@ -0,0 +1,9 @@
1
+ let react_native = require("react-native");
2
+ let expo = require("expo");
3
+
4
+ //#region src/specs/NativeClerkAuthView.ts
5
+ const NativeClerkAuthView = react_native.Platform.OS === "ios" || react_native.Platform.OS === "android" ? (0, expo.requireNativeView)("ClerkAuthView") : null;
6
+
7
+ //#endregion
8
+ module.exports = NativeClerkAuthView;
9
+ //# sourceMappingURL=NativeClerkAuthView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkAuthView.js","names":["Platform"],"sources":["../../src/specs/NativeClerkAuthView.ts"],"sourcesContent":["import { requireNativeView } from 'expo';\nimport type { NativeSyntheticEvent, ViewProps } from 'react-native';\nimport { Platform } from 'react-native';\n\ntype AuthEvent = Readonly<{ type: string }>;\n\ninterface NativeProps extends ViewProps {\n mode?: string;\n isDismissible?: boolean;\n logoMaxHeight?: number;\n hostBackButton?: boolean;\n onAuthEvent?: (event: NativeSyntheticEvent<AuthEvent>) => void;\n onHostBack?: (event: NativeSyntheticEvent<object>) => void;\n}\n\nconst NativeClerkAuthView =\n Platform.OS === 'ios' || Platform.OS === 'android' ? requireNativeView<NativeProps>('ClerkAuthView') : null;\n\nexport default NativeClerkAuthView;\n"],"mappings":";;;;AAeA,MAAM,sBACJA,sBAAS,OAAO,SAASA,sBAAS,OAAO,wCAA2C,eAAe,IAAI"}
@@ -0,0 +1,4 @@
1
+ import type { Spec } from './NativeClerkModule.types';
2
+ declare const _default: Spec | null;
3
+ export default _default;
4
+ //# sourceMappingURL=NativeClerkModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkModule.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkModule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;;AAGtD,wBAA8D"}
@@ -0,0 +1,8 @@
1
+ let expo = require("expo");
2
+
3
+ //#region src/specs/NativeClerkModule.ts
4
+ var NativeClerkModule_default = (0, expo.requireOptionalNativeModule)("ClerkExpo");
5
+
6
+ //#endregion
7
+ module.exports = NativeClerkModule_default;
8
+ //# sourceMappingURL=NativeClerkModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkModule.js","names":[],"sources":["../../src/specs/NativeClerkModule.ts"],"sourcesContent":["import { requireOptionalNativeModule } from 'expo';\n\nimport type { Spec } from './NativeClerkModule.types';\n\n// Optional so it resolves to null in Expo Go instead of throwing at import time.\nexport default requireOptionalNativeModule<Spec>('ClerkExpo');\n"],"mappings":";;;AAKA,sEAAiD,WAAW"}
@@ -0,0 +1,11 @@
1
+ export type NativeAuthFlowState = {
2
+ isLoaded: boolean;
3
+ isAuthFlowComplete: boolean;
4
+ };
5
+ export interface Spec {
6
+ addListener?(eventName: string, listener?: (...args: unknown[]) => void): {
7
+ remove: () => void;
8
+ };
9
+ getAuthFlowState?(): Promise<NativeAuthFlowState>;
10
+ }
11
+ //# sourceMappingURL=NativeClerkModule.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkModule.types.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkModule.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,IAAI;IACnB,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG;QAAE,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IACjG,gBAAgB,CAAC,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACnD"}
File without changes
@@ -0,0 +1,4 @@
1
+ import type { Spec } from './NativeClerkModule.types';
2
+ declare const _default: Spec | null;
3
+ export default _default;
4
+ //# sourceMappingURL=NativeClerkModule.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkModule.web.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;wBAE/B,IAAI,GAAG,IAAI;AAAlC,wBAAmC"}
@@ -0,0 +1,7 @@
1
+
2
+ //#region src/specs/NativeClerkModule.web.ts
3
+ var NativeClerkModule_web_default = null;
4
+
5
+ //#endregion
6
+ module.exports = NativeClerkModule_web_default;
7
+ //# sourceMappingURL=NativeClerkModule.web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkModule.web.js","names":[],"sources":["../../src/specs/NativeClerkModule.web.ts"],"sourcesContent":["import type { Spec } from './NativeClerkModule.types';\n\nexport default null as Spec | null;\n"],"mappings":";;AAEA,oCAAe"}
@@ -0,0 +1,6 @@
1
+ import type { ViewProps } from 'react-native';
2
+ interface NativeProps extends ViewProps {
3
+ }
4
+ declare const _default: import("react").ComponentType<NativeProps>;
5
+ export default _default;
6
+ //# sourceMappingURL=NativeClerkUserButtonView.android.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkUserButtonView.android.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkUserButtonView.android.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAK9C,UAAU,WAAY,SAAQ,SAAS;CAAG;;AAE1C,wBAAqE"}
@@ -0,0 +1,8 @@
1
+ let expo = require("expo");
2
+
3
+ //#region src/specs/NativeClerkUserButtonView.android.ts
4
+ var NativeClerkUserButtonView_android_default = (0, expo.requireNativeView)("ClerkUserButtonView");
5
+
6
+ //#endregion
7
+ module.exports = NativeClerkUserButtonView_android_default;
8
+ //# sourceMappingURL=NativeClerkUserButtonView.android.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkUserButtonView.android.js","names":[],"sources":["../../src/specs/NativeClerkUserButtonView.android.ts"],"sourcesContent":["import { requireNativeView } from 'expo';\nimport type { ViewProps } from 'react-native';\n\n// Codegen requires an interface declaration in the iOS spec; keep the Android\n// view prop shape identical for the shared React wrapper.\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\ninterface NativeProps extends ViewProps {}\n\nexport default requireNativeView<NativeProps>('ClerkUserButtonView');\n"],"mappings":";;;AAQA,4EAA8C,qBAAqB"}
@@ -0,0 +1,6 @@
1
+ import type { ViewProps } from 'react-native';
2
+ interface NativeProps extends ViewProps {
3
+ }
4
+ declare const NativeClerkUserButtonView: import("react").ComponentType<NativeProps> | null;
5
+ export default NativeClerkUserButtonView;
6
+ //# sourceMappingURL=NativeClerkUserButtonView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkUserButtonView.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkUserButtonView.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAI9C,UAAU,WAAY,SAAQ,SAAS;CAAG;AAE1C,QAAA,MAAM,yBAAyB,mDACoF,CAAC;AAEpH,eAAe,yBAAyB,CAAC"}
@@ -0,0 +1,9 @@
1
+ let react_native = require("react-native");
2
+ let expo = require("expo");
3
+
4
+ //#region src/specs/NativeClerkUserButtonView.ts
5
+ const NativeClerkUserButtonView = react_native.Platform.OS === "ios" || react_native.Platform.OS === "android" ? (0, expo.requireNativeView)("ClerkUserButtonView") : null;
6
+
7
+ //#endregion
8
+ module.exports = NativeClerkUserButtonView;
9
+ //# sourceMappingURL=NativeClerkUserButtonView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkUserButtonView.js","names":["Platform"],"sources":["../../src/specs/NativeClerkUserButtonView.ts"],"sourcesContent":["import { requireNativeView } from 'expo';\nimport type { ViewProps } from 'react-native';\nimport { Platform } from 'react-native';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\ninterface NativeProps extends ViewProps {}\n\nconst NativeClerkUserButtonView =\n Platform.OS === 'ios' || Platform.OS === 'android' ? requireNativeView<NativeProps>('ClerkUserButtonView') : null;\n\nexport default NativeClerkUserButtonView;\n"],"mappings":";;;;AAOA,MAAM,4BACJA,sBAAS,OAAO,SAASA,sBAAS,OAAO,wCAA2C,qBAAqB,IAAI"}
@@ -0,0 +1,13 @@
1
+ import type { NativeSyntheticEvent, ViewProps } from 'react-native';
2
+ type ProfileEvent = Readonly<{
3
+ type: string;
4
+ }>;
5
+ interface NativeProps extends ViewProps {
6
+ isDismissible?: boolean;
7
+ hostBackButton?: boolean;
8
+ onProfileEvent?: (event: NativeSyntheticEvent<ProfileEvent>) => void;
9
+ onHostBack?: (event: NativeSyntheticEvent<object>) => void;
10
+ }
11
+ declare const _default: import("react").ComponentType<NativeProps>;
12
+ export default _default;
13
+ //# sourceMappingURL=NativeClerkUserProfileView.android.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkUserProfileView.android.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkUserProfileView.android.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpE,KAAK,YAAY,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE/C,UAAU,WAAY,SAAQ,SAAS;IACrC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACrE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;CAC5D;;AAED,wBAAsE"}
@@ -0,0 +1,8 @@
1
+ let expo = require("expo");
2
+
3
+ //#region src/specs/NativeClerkUserProfileView.android.ts
4
+ var NativeClerkUserProfileView_android_default = (0, expo.requireNativeView)("ClerkUserProfileView");
5
+
6
+ //#endregion
7
+ module.exports = NativeClerkUserProfileView_android_default;
8
+ //# sourceMappingURL=NativeClerkUserProfileView.android.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkUserProfileView.android.js","names":[],"sources":["../../src/specs/NativeClerkUserProfileView.android.ts"],"sourcesContent":["import { requireNativeView } from 'expo';\nimport type { NativeSyntheticEvent, ViewProps } from 'react-native';\n\ntype ProfileEvent = Readonly<{ type: string }>;\n\ninterface NativeProps extends ViewProps {\n isDismissible?: boolean;\n hostBackButton?: boolean;\n onProfileEvent?: (event: NativeSyntheticEvent<ProfileEvent>) => void;\n onHostBack?: (event: NativeSyntheticEvent<object>) => void;\n}\n\nexport default requireNativeView<NativeProps>('ClerkUserProfileView');\n"],"mappings":";;;AAYA,6EAA8C,sBAAsB"}
@@ -0,0 +1,13 @@
1
+ import type { NativeSyntheticEvent, ViewProps } from 'react-native';
2
+ type ProfileEvent = Readonly<{
3
+ type: string;
4
+ }>;
5
+ interface NativeProps extends ViewProps {
6
+ isDismissible?: boolean;
7
+ hostBackButton?: boolean;
8
+ onProfileEvent?: (event: NativeSyntheticEvent<ProfileEvent>) => void;
9
+ onHostBack?: (event: NativeSyntheticEvent<object>) => void;
10
+ }
11
+ declare const NativeClerkUserProfileView: import("react").ComponentType<NativeProps> | null;
12
+ export default NativeClerkUserProfileView;
13
+ //# sourceMappingURL=NativeClerkUserProfileView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkUserProfileView.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkUserProfileView.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGpE,KAAK,YAAY,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE/C,UAAU,WAAY,SAAQ,SAAS;IACrC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACrE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;CAC5D;AAED,QAAA,MAAM,0BAA0B,mDACoF,CAAC;AAErH,eAAe,0BAA0B,CAAC"}
@@ -0,0 +1,9 @@
1
+ let react_native = require("react-native");
2
+ let expo = require("expo");
3
+
4
+ //#region src/specs/NativeClerkUserProfileView.ts
5
+ const NativeClerkUserProfileView = react_native.Platform.OS === "ios" || react_native.Platform.OS === "android" ? (0, expo.requireNativeView)("ClerkUserProfileView") : null;
6
+
7
+ //#endregion
8
+ module.exports = NativeClerkUserProfileView;
9
+ //# sourceMappingURL=NativeClerkUserProfileView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeClerkUserProfileView.js","names":["Platform"],"sources":["../../src/specs/NativeClerkUserProfileView.ts"],"sourcesContent":["import { requireNativeView } from 'expo';\nimport type { NativeSyntheticEvent, ViewProps } from 'react-native';\nimport { Platform } from 'react-native';\n\ntype ProfileEvent = Readonly<{ type: string }>;\n\ninterface NativeProps extends ViewProps {\n isDismissible?: boolean;\n hostBackButton?: boolean;\n onProfileEvent?: (event: NativeSyntheticEvent<ProfileEvent>) => void;\n onHostBack?: (event: NativeSyntheticEvent<object>) => void;\n}\n\nconst NativeClerkUserProfileView =\n Platform.OS === 'ios' || Platform.OS === 'android' ? requireNativeView<NativeProps>('ClerkUserProfileView') : null;\n\nexport default NativeClerkUserProfileView;\n"],"mappings":";;;;AAaA,MAAM,6BACJA,sBAAS,OAAO,SAASA,sBAAS,OAAO,wCAA2C,sBAAsB,IAAI"}
@@ -0,0 +1,12 @@
1
+ import type { NativeAuthFlowState } from './specs/NativeClerkModule.types';
2
+ export type UseAuthViewStateReturn = NativeAuthFlowState;
3
+ /**
4
+ * Reports when authentication and an optional biometric-credential enrollment prompt are complete.
5
+ *
6
+ * Use this hook when biometric-credential enrollment prompts are enabled and a
7
+ * non-dismissible root `AuthView` must remain mounted until the prompt finishes.
8
+ * On platforms without native auth-flow completion state, it falls back to the
9
+ * JS session state.
10
+ */
11
+ export declare function useAuthViewState(): UseAuthViewStateReturn;
12
+ //# sourceMappingURL=useAuthViewState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuthViewState.d.ts","sourceRoot":"","sources":["../src/useAuthViewState.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAK3E,MAAM,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AA2BzD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,IAAI,sBAAsB,CA4EzD"}
@@ -0,0 +1,76 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let react = require("react");
3
+ let src_utils_native_module = require("./utils/native-module");
4
+ let _clerk_react = require("@clerk/react");
5
+
6
+ //#region src/useAuthViewState.ts
7
+ const nativeAuthFlowChangedEvent = "clerkNativeAuthFlowChanged";
8
+ const initialNativeState = {
9
+ isLoaded: false,
10
+ isAuthFlowComplete: false
11
+ };
12
+ function getNativeAuthFlowModule() {
13
+ if (src_utils_native_module.ClerkExpoModule && typeof src_utils_native_module.ClerkExpoModule.addListener === "function" && typeof src_utils_native_module.ClerkExpoModule.getAuthFlowState === "function") return src_utils_native_module.ClerkExpoModule;
14
+ return null;
15
+ }
16
+ function isNativeAuthFlowState(state) {
17
+ return typeof state?.isLoaded === "boolean" && typeof state.isAuthFlowComplete === "boolean";
18
+ }
19
+ /**
20
+ * Reports when authentication and an optional biometric-credential enrollment prompt are complete.
21
+ *
22
+ * Use this hook when biometric-credential enrollment prompts are enabled and a
23
+ * non-dismissible root `AuthView` must remain mounted until the prompt finishes.
24
+ * On platforms without native auth-flow completion state, it falls back to the
25
+ * JS session state.
26
+ */
27
+ function useAuthViewState() {
28
+ const { isLoaded: isJsLoaded, isSignedIn } = (0, _clerk_react.useAuth)({ treatPendingAsSignedOut: false });
29
+ const [nativeState, setNativeState] = (0, react.useState)(initialNativeState);
30
+ const [useJsFallback, setUseJsFallback] = (0, react.useState)(false);
31
+ const nativeModule = getNativeAuthFlowModule();
32
+ (0, react.useEffect)(() => {
33
+ if (!nativeModule) {
34
+ setUseJsFallback(true);
35
+ return;
36
+ }
37
+ let isMounted = true;
38
+ let didReceiveEvent = false;
39
+ let subscription;
40
+ setUseJsFallback(false);
41
+ try {
42
+ subscription = nativeModule.addListener(nativeAuthFlowChangedEvent, (state) => {
43
+ if (!isNativeAuthFlowState(state)) return;
44
+ didReceiveEvent = true;
45
+ setNativeState(state);
46
+ setUseJsFallback(false);
47
+ });
48
+ nativeModule.getAuthFlowState().then((state) => {
49
+ if (!isMounted || didReceiveEvent) return;
50
+ if (isNativeAuthFlowState(state)) setNativeState(state);
51
+ else setUseJsFallback(true);
52
+ }).catch((error) => {
53
+ if (!isMounted || didReceiveEvent) return;
54
+ setUseJsFallback(true);
55
+ });
56
+ } catch (error) {
57
+ setUseJsFallback(true);
58
+ }
59
+ return () => {
60
+ isMounted = false;
61
+ subscription?.remove();
62
+ };
63
+ }, [nativeModule]);
64
+ if (!nativeModule || useJsFallback) return {
65
+ isLoaded: isJsLoaded,
66
+ isAuthFlowComplete: Boolean(isJsLoaded && isSignedIn)
67
+ };
68
+ return {
69
+ isLoaded: Boolean(isJsLoaded && nativeState.isLoaded),
70
+ isAuthFlowComplete: Boolean(isJsLoaded && isSignedIn && nativeState.isAuthFlowComplete)
71
+ };
72
+ }
73
+
74
+ //#endregion
75
+ exports.useAuthViewState = useAuthViewState;
76
+ //# sourceMappingURL=useAuthViewState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuthViewState.js","names":["ClerkExpo"],"sources":["../src/useAuthViewState.ts"],"sourcesContent":["import { useAuth } from '@clerk/react';\nimport { useEffect, useState } from 'react';\n\nimport type { NativeAuthFlowState } from './specs/NativeClerkModule.types';\nimport { ClerkExpoModule as ClerkExpo } from './utils/native-module';\n\nconst nativeAuthFlowChangedEvent = 'clerkNativeAuthFlowChanged';\n\nexport type UseAuthViewStateReturn = NativeAuthFlowState;\n\ntype NativeAuthFlowEventEmitter = {\n addListener(\n eventName: typeof nativeAuthFlowChangedEvent,\n listener: (state?: NativeAuthFlowState) => void,\n ): { remove: () => void };\n getAuthFlowState(): Promise<NativeAuthFlowState>;\n};\n\nconst initialNativeState: NativeAuthFlowState = {\n isLoaded: false,\n isAuthFlowComplete: false,\n};\n\nfunction getNativeAuthFlowModule(): NativeAuthFlowEventEmitter | null {\n if (ClerkExpo && typeof ClerkExpo.addListener === 'function' && typeof ClerkExpo.getAuthFlowState === 'function') {\n return ClerkExpo as NativeAuthFlowEventEmitter;\n }\n\n return null;\n}\n\nfunction isNativeAuthFlowState(state: NativeAuthFlowState | undefined): state is NativeAuthFlowState {\n return typeof state?.isLoaded === 'boolean' && typeof state.isAuthFlowComplete === 'boolean';\n}\n\n/**\n * Reports when authentication and an optional biometric-credential enrollment prompt are complete.\n *\n * Use this hook when biometric-credential enrollment prompts are enabled and a\n * non-dismissible root `AuthView` must remain mounted until the prompt finishes.\n * On platforms without native auth-flow completion state, it falls back to the\n * JS session state.\n */\nexport function useAuthViewState(): UseAuthViewStateReturn {\n const { isLoaded: isJsLoaded, isSignedIn } = useAuth({ treatPendingAsSignedOut: false });\n const [nativeState, setNativeState] = useState(initialNativeState);\n const [useJsFallback, setUseJsFallback] = useState(false);\n const nativeModule = getNativeAuthFlowModule();\n\n useEffect(() => {\n if (!nativeModule) {\n setUseJsFallback(true);\n return;\n }\n\n let isMounted = true;\n let didReceiveEvent = false;\n let subscription: { remove: () => void } | undefined;\n\n setUseJsFallback(false);\n\n try {\n subscription = nativeModule.addListener(nativeAuthFlowChangedEvent, state => {\n if (!isNativeAuthFlowState(state)) {\n return;\n }\n\n didReceiveEvent = true;\n setNativeState(state);\n setUseJsFallback(false);\n });\n\n void nativeModule\n .getAuthFlowState()\n .then(state => {\n if (!isMounted || didReceiveEvent) {\n return;\n }\n\n if (isNativeAuthFlowState(state)) {\n setNativeState(state);\n } else {\n setUseJsFallback(true);\n }\n })\n .catch(error => {\n if (!isMounted || didReceiveEvent) {\n return;\n }\n\n setUseJsFallback(true);\n if (__DEV__) {\n console.error('[useAuthViewState] Failed to get native auth-flow state:', error);\n }\n });\n } catch (error) {\n setUseJsFallback(true);\n if (__DEV__) {\n console.error('[useAuthViewState] Failed to observe native auth-flow state:', error);\n }\n }\n\n return () => {\n isMounted = false;\n subscription?.remove();\n };\n }, [nativeModule]);\n\n if (!nativeModule || useJsFallback) {\n return {\n isLoaded: isJsLoaded,\n isAuthFlowComplete: Boolean(isJsLoaded && isSignedIn),\n };\n }\n\n return {\n isLoaded: Boolean(isJsLoaded && nativeState.isLoaded),\n isAuthFlowComplete: Boolean(isJsLoaded && isSignedIn && nativeState.isAuthFlowComplete),\n };\n}\n"],"mappings":";;;;;;AAMA,MAAM,6BAA6B;AAYnC,MAAM,qBAA0C;CAC9C,UAAU;CACV,oBAAoB;AACtB;AAEA,SAAS,0BAA6D;CACpE,IAAIA,2CAAa,OAAOA,wCAAU,gBAAgB,cAAc,OAAOA,wCAAU,qBAAqB,YACpG,OAAOA;CAGT,OAAO;AACT;AAEA,SAAS,sBAAsB,OAAsE;CACnG,OAAO,OAAO,OAAO,aAAa,aAAa,OAAO,MAAM,uBAAuB;AACrF;;;;;;;;;AAUA,SAAgB,mBAA2C;CACzD,MAAM,EAAE,UAAU,YAAY,yCAAuB,EAAE,yBAAyB,MAAM,CAAC;CACvF,MAAM,CAAC,aAAa,sCAA2B,kBAAkB;CACjE,MAAM,CAAC,eAAe,wCAA6B,KAAK;CACxD,MAAM,eAAe,wBAAwB;CAE7C,2BAAgB;EACd,IAAI,CAAC,cAAc;GACjB,iBAAiB,IAAI;GACrB;EACF;EAEA,IAAI,YAAY;EAChB,IAAI,kBAAkB;EACtB,IAAI;EAEJ,iBAAiB,KAAK;EAEtB,IAAI;GACF,eAAe,aAAa,YAAY,6BAA4B,UAAS;IAC3E,IAAI,CAAC,sBAAsB,KAAK,GAC9B;IAGF,kBAAkB;IAClB,eAAe,KAAK;IACpB,iBAAiB,KAAK;GACxB,CAAC;GAED,AAAK,aACF,iBAAiB,CAAC,CAClB,MAAK,UAAS;IACb,IAAI,CAAC,aAAa,iBAChB;IAGF,IAAI,sBAAsB,KAAK,GAC7B,eAAe,KAAK;SAEpB,iBAAiB,IAAI;GAEzB,CAAC,CAAC,CACD,OAAM,UAAS;IACd,IAAI,CAAC,aAAa,iBAChB;IAGF,iBAAiB,IAAI;GAIvB,CAAC;EACL,SAAS,OAAO;GACd,iBAAiB,IAAI;EAIvB;EAEA,aAAa;GACX,YAAY;GACZ,cAAc,OAAO;EACvB;CACF,GAAG,CAAC,YAAY,CAAC;CAEjB,IAAI,CAAC,gBAAgB,eACnB,OAAO;EACL,UAAU;EACV,oBAAoB,QAAQ,cAAc,UAAU;CACtD;CAGF,OAAO;EACL,UAAU,QAAQ,cAAc,YAAY,QAAQ;EACpD,oBAAoB,QAAQ,cAAc,cAAc,YAAY,kBAAkB;CACxF;AACF"}
@@ -0,0 +1,3 @@
1
+ export declare const isNativeSupported: boolean;
2
+ export declare const ClerkExpoModule: import("../specs/NativeClerkModule.types").Spec | null;
3
+ //# sourceMappingURL=native-module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-module.d.ts","sourceRoot":"","sources":["../../src/utils/native-module.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,iBAAiB,SAAqD,CAAC;AAEpF,eAAO,MAAM,eAAe,wDAA+C,CAAC"}
@@ -0,0 +1,14 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_runtime = require('../_virtual/_rolldown/runtime.js');
3
+ let react_native = require("react-native");
4
+ let src_specs_NativeClerkModule = require("../specs/NativeClerkModule");
5
+ src_specs_NativeClerkModule = require_runtime.__toESM(src_specs_NativeClerkModule);
6
+
7
+ //#region src/utils/native-module.ts
8
+ const isNativeSupported = react_native.Platform.OS === "ios" || react_native.Platform.OS === "android";
9
+ const ClerkExpoModule = isNativeSupported ? src_specs_NativeClerkModule.default : null;
10
+
11
+ //#endregion
12
+ exports.ClerkExpoModule = ClerkExpoModule;
13
+ exports.isNativeSupported = isNativeSupported;
14
+ //# sourceMappingURL=native-module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-module.js","names":["Platform","NativeClerkModule"],"sources":["../../src/utils/native-module.ts"],"sourcesContent":["import { Platform } from 'react-native';\n\nimport NativeClerkModule from '../specs/NativeClerkModule';\n\nexport const isNativeSupported = Platform.OS === 'ios' || Platform.OS === 'android';\n\nexport const ClerkExpoModule = isNativeSupported ? NativeClerkModule : null;\n"],"mappings":";;;;;;;AAIA,MAAa,oBAAoBA,sBAAS,OAAO,SAASA,sBAAS,OAAO;AAE1E,MAAa,kBAAkB,oBAAoBC,sCAAoB"}
@@ -0,0 +1,15 @@
1
+ {
2
+ "platforms": ["apple", "android"],
3
+ "apple": {
4
+ "modules": ["ClerkExpoModule", "ClerkAuthViewModule", "ClerkUserProfileViewModule", "ClerkUserButtonViewModule"],
5
+ "appDelegateSubscribers": ["ClerkAppDelegateSubscriber"]
6
+ },
7
+ "android": {
8
+ "modules": [
9
+ "expo.modules.clerk.ClerkExpoModule",
10
+ "expo.modules.clerk.ClerkAuthViewModule",
11
+ "expo.modules.clerk.ClerkUserProfileViewModule",
12
+ "expo.modules.clerk.ClerkUserButtonViewModule"
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1,16 @@
1
+ // ClerkAppDelegateSubscriber - Forwards inbound URLs to the native Clerk SDK.
2
+
3
+ import ExpoModulesCore
4
+ import UIKit
5
+
6
+ public class ClerkAppDelegateSubscriber: ExpoAppDelegateSubscriber {
7
+ public func application(
8
+ _ app: UIApplication,
9
+ open url: URL,
10
+ options: [UIApplication.OpenURLOptionsKey: Any] = [:]
11
+ ) -> Bool {
12
+ ClerkNativeBridge.shared.handle(url: url)
13
+ // Returning false leaves the URL available to React Native's Linking.
14
+ return false
15
+ }
16
+ }
@@ -0,0 +1,157 @@
1
+ import ExpoModulesCore
2
+ import UIKit
3
+
4
+ public class ClerkAuthNativeView: ClerkNativeViewHost {
5
+ private var currentMode: String = "signInOrUp"
6
+ private var currentDismissible: Bool = true
7
+ private var currentLogoMaxHeight: CGFloat?
8
+ private let logoState = ClerkInlineAuthLogoState()
9
+ private var logoBoundsObservation: NSKeyValueObservation?
10
+ private var currentHostBackButton: Bool = false
11
+ private var didSendDismiss = false
12
+
13
+ let onAuthEvent = EventDispatcher()
14
+ let onHostBack = EventDispatcher()
15
+
16
+ func setMode(_ mode: String?) {
17
+ let newMode = mode ?? "signInOrUp"
18
+ guard newMode != currentMode else { return }
19
+ currentMode = newMode
20
+ setNeedsHostedViewUpdate()
21
+ }
22
+
23
+ func setDismissible(_ isDismissible: Bool?) {
24
+ let newDismissible = isDismissible ?? true
25
+ guard newDismissible != currentDismissible else { return }
26
+ currentDismissible = newDismissible
27
+ setNeedsHostedViewUpdate()
28
+ }
29
+
30
+ func setLogoMaxHeight(_ logoMaxHeight: CGFloat?) {
31
+ guard logoMaxHeight != currentLogoMaxHeight else { return }
32
+ currentLogoMaxHeight = logoMaxHeight
33
+ setNeedsHostedViewUpdate()
34
+ }
35
+
36
+ func setHostBackButton(_ hostBackButton: Bool?) {
37
+ let newHostBackButton = hostBackButton ?? false
38
+ guard newHostBackButton != currentHostBackButton else { return }
39
+ currentHostBackButton = newHostBackButton
40
+ setNeedsHostedViewUpdate()
41
+ }
42
+
43
+ private func sendAuthEvent(type: ClerkNativeViewEvent) {
44
+ onAuthEvent(["type": type.rawValue])
45
+ }
46
+
47
+ private func sendDismiss() {
48
+ guard !didSendDismiss else { return }
49
+ didSendDismiss = true
50
+ sendAuthEvent(type: .dismissed)
51
+ }
52
+
53
+ override func hostedViewDidAttachToWindow() {
54
+ didSendDismiss = false
55
+ }
56
+
57
+ override func hostedViewDidDetachFromWindow() {
58
+ // SwiftUI dismissals detach the hosted view without calling UIKit dismiss().
59
+ // A non-dismissible view never self-dismisses, so a detach there is the host
60
+ // tearing the view down rather than a dismissal to report.
61
+ guard currentDismissible else { return }
62
+ sendDismiss()
63
+ }
64
+
65
+ override public func layoutSubviews() {
66
+ super.layoutSubviews()
67
+ guard let logoView = logoState.content?.view else { return }
68
+ logoState.updateSize(for: logoView)
69
+ }
70
+
71
+ #if RCT_NEW_ARCH_ENABLED
72
+ override public func mountChildComponentView(_ childComponentView: UIView, index: Int) {
73
+ setLogoView(childComponentView)
74
+ }
75
+
76
+ override public func unmountChildComponentView(_ childComponentView: UIView, index: Int) {
77
+ removeLogoView(childComponentView)
78
+ }
79
+ #else
80
+ override public func insertReactSubview(_ subview: UIView!, at atIndex: Int) {
81
+ super.insertReactSubview(subview, at: atIndex)
82
+ setLogoView(subview)
83
+ }
84
+
85
+ override public func removeReactSubview(_ subview: UIView!) {
86
+ removeLogoView(subview)
87
+ super.removeReactSubview(subview)
88
+ }
89
+
90
+ override public func didUpdateReactSubviews() {}
91
+ #endif
92
+
93
+ private func setLogoView(_ view: UIView) {
94
+ guard logoState.content?.view !== view else { return }
95
+ logoBoundsObservation = nil
96
+ logoState.setView(view)
97
+ logoBoundsObservation = view.observe(\.bounds, options: [.new]) { [weak self, weak view] _, _ in
98
+ DispatchQueue.main.async { [weak self, weak view] in
99
+ guard let self, let view, self.logoState.content?.view === view else { return }
100
+ self.logoState.updateSize(for: view)
101
+ }
102
+ }
103
+ }
104
+
105
+ private func removeLogoView(_ view: UIView) {
106
+ guard logoState.content?.view === view else { return }
107
+ logoBoundsObservation = nil
108
+ view.removeFromSuperview()
109
+ logoState.removeView(view)
110
+ }
111
+
112
+ override func makeHostedController() -> UIViewController? {
113
+ let hostBackAction: (() -> Void)? = currentHostBackButton
114
+ ? { [weak self] in self?.onHostBack([:]) }
115
+ : nil
116
+
117
+ return ClerkNativeBridge.shared.makeAuthViewController(
118
+ mode: currentMode,
119
+ dismissible: currentDismissible,
120
+ logoState: logoState,
121
+ logoMaxHeight: currentLogoMaxHeight,
122
+ hostBackAction: hostBackAction,
123
+ onEvent: { [weak self] event, _ in
124
+ if event == .dismissed {
125
+ self?.sendDismiss()
126
+ }
127
+ }
128
+ )
129
+ }
130
+ }
131
+
132
+ public class ClerkAuthViewModule: Module {
133
+ public func definition() -> ModuleDefinition {
134
+ Name("ClerkAuthView")
135
+
136
+ View(ClerkAuthNativeView.self) {
137
+ Events("onAuthEvent", "onHostBack")
138
+
139
+ Prop("mode") { (view: ClerkAuthNativeView, mode: String?) in
140
+ view.setMode(mode)
141
+ }
142
+
143
+ Prop("isDismissible") { (view: ClerkAuthNativeView, isDismissible: Bool?) in
144
+ view.setDismissible(isDismissible)
145
+ }
146
+
147
+ Prop("logoMaxHeight") { (view: ClerkAuthNativeView, logoMaxHeight: CGFloat?) in
148
+ view.setLogoMaxHeight(logoMaxHeight)
149
+ }
150
+
151
+ Prop("hostBackButton") { (view: ClerkAuthNativeView, hostBackButton: Bool?) in
152
+ view.setHostBackButton(hostBackButton)
153
+ }
154
+
155
+ }
156
+ }
157
+ }
@@ -0,0 +1,67 @@
1
+ require 'json'
2
+
3
+ # Find package.json by following symlinks if necessary
4
+ package_json_path = File.join(__dir__, '..', 'package.json')
5
+ package_json_path = File.join(File.readlink(__dir__), '..', 'package.json') if File.symlink?(__dir__)
6
+
7
+ # Fallback to hardcoded values if package.json is not found
8
+ if File.exist?(package_json_path)
9
+ package = JSON.parse(File.read(package_json_path))
10
+ else
11
+ package = {
12
+ 'version' => '0.0.0-FALLBACK',
13
+ 'description' => 'Clerk React Native/Expo library',
14
+ 'license' => 'MIT',
15
+ 'author' => 'Clerk',
16
+ 'homepage' => 'https://clerk.com/'
17
+ }
18
+ end
19
+
20
+ clerk_ios_repo = 'https://github.com/clerk/clerk-ios.git'
21
+ clerk_ios_version = '1.6.1'
22
+
23
+ Pod::Spec.new do |s|
24
+ s.name = 'ClerkExpo'
25
+ s.version = package['version']
26
+ s.summary = package['description']
27
+ s.license = package['license']
28
+ s.author = package['author']
29
+ s.homepage = package['homepage']
30
+ # NOTE: Must match CLERK_MIN_IOS_VERSION in app.plugin.js
31
+ s.platforms = { :ios => '17.0' } # Clerk iOS SDK requires iOS 17
32
+ s.swift_version = '5.10'
33
+ s.source = { git: 'https://github.com/clerk/javascript' }
34
+ s.static_framework = true
35
+
36
+ s.dependency 'ExpoModulesCore'
37
+
38
+ s.pod_target_xcconfig = {
39
+ 'DEFINES_MODULE' => 'YES',
40
+ 'SWIFT_COMPILATION_MODE' => 'wholemodule'
41
+ }
42
+
43
+ if defined?(spm_dependency)
44
+ spm_dependency(
45
+ s,
46
+ url: clerk_ios_repo,
47
+ requirement: { :kind => 'exactVersion', :version => clerk_ios_version },
48
+ products: ['ClerkKit', 'ClerkKitUI']
49
+ )
50
+ else
51
+ raise 'ClerkExpo requires React Native 0.75 or newer for iOS Swift Package Manager dependencies.'
52
+ end
53
+
54
+ s.source_files = "ClerkNativeBridge.swift",
55
+ "ClerkAppDelegateSubscriber.swift",
56
+ "ClerkExpoModule.swift",
57
+ "ClerkNativeViewHost.swift",
58
+ "ClerkAuthNativeView.swift",
59
+ "ClerkUserProfileNativeView.swift",
60
+ "ClerkUserButtonNativeView.swift"
61
+
62
+ s.test_spec 'Tests' do |test_spec|
63
+ test_spec.source_files = 'Tests/**/*.swift'
64
+ end
65
+
66
+ install_modules_dependencies(s)
67
+ end