flowstudio-rn 0.0.1-alpha

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 (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -0
  3. package/android/build.gradle +41 -0
  4. package/android/src/main/AndroidManifest.xml +2 -0
  5. package/android/src/main/java/id/bureau/flowstudio/rn/FlowStudioReactNativeModule.kt +173 -0
  6. package/app.plugin.js +2 -0
  7. package/build/FlowStudio.d.ts +21 -0
  8. package/build/FlowStudio.d.ts.map +1 -0
  9. package/build/FlowStudio.js +58 -0
  10. package/build/FlowStudio.js.map +1 -0
  11. package/build/FlowStudioReactNative.types.d.ts +48 -0
  12. package/build/FlowStudioReactNative.types.d.ts.map +1 -0
  13. package/build/FlowStudioReactNative.types.js +2 -0
  14. package/build/FlowStudioReactNative.types.js.map +1 -0
  15. package/build/FlowStudioReactNativeModule.d.ts +15 -0
  16. package/build/FlowStudioReactNativeModule.d.ts.map +1 -0
  17. package/build/FlowStudioReactNativeModule.js +3 -0
  18. package/build/FlowStudioReactNativeModule.js.map +1 -0
  19. package/build/FlowStudioReactNativeModule.web.d.ts +6 -0
  20. package/build/FlowStudioReactNativeModule.web.d.ts.map +1 -0
  21. package/build/FlowStudioReactNativeModule.web.js +6 -0
  22. package/build/FlowStudioReactNativeModule.web.js.map +1 -0
  23. package/build/index.d.ts +4 -0
  24. package/build/index.d.ts.map +1 -0
  25. package/build/index.js +4 -0
  26. package/build/index.js.map +1 -0
  27. package/expo-module.config.json +9 -0
  28. package/ios/FlowStudioReactNative.podspec +23 -0
  29. package/ios/FlowStudioReactNativeModule.swift +7 -0
  30. package/package.json +86 -0
  31. package/plugin/build/index.d.ts +3 -0
  32. package/plugin/build/index.js +29 -0
  33. package/src/FlowStudio.ts +77 -0
  34. package/src/FlowStudioReactNative.types.ts +45 -0
  35. package/src/FlowStudioReactNativeModule.ts +16 -0
  36. package/src/FlowStudioReactNativeModule.web.ts +6 -0
  37. package/src/index.ts +10 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # flowstudio-rn
2
+
3
+ React Native SDK for Bureau Flow Studio. It runs Flow Studio identity and verification journeys inside React Native and Expo apps, on top of Bureau's native FlowStudio SDK.
4
+
5
+ > **Alpha:** Android only for now. iOS support is coming. On iOS, `initialize()` and `start()` throw `FlowStudio: ios is not supported yet`, and `isInitialized()` returns `false`.
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ npm install flowstudio-rn@alpha
11
+ ```
12
+
13
+ Expo projects can use `npx expo install flowstudio-rn@alpha`.
14
+
15
+ ### Android setup
16
+
17
+ The native FlowStudio SDK is downloaded from Bureau's Maven repository (`https://packages.bureau.id/api/packages/Bureau/maven`). The SDK registers this repository for your app automatically:
18
+
19
+ - **Expo (prebuild / CNG):** add the config plugin to `app.json`, then run `npx expo prebuild` (or `npx expo run:android`):
20
+
21
+ ```json
22
+ {
23
+ "expo": {
24
+ "plugins": ["flowstudio-rn"]
25
+ }
26
+ }
27
+ ```
28
+
29
+ - **Bare React Native:** nothing to add. The library's Gradle file registers the repository for all projects.
30
+
31
+ If your `settings.gradle` sets `repositoriesMode` to `FAIL_ON_PROJECT_REPOS`, add the repository yourself under `dependencyResolutionManagement { repositories { ... } }`:
32
+
33
+ ```groovy
34
+ maven { url "https://packages.bureau.id/api/packages/Bureau/maven" }
35
+ ```
36
+
37
+ **Requirements:** `minSdkVersion` 24 or higher. The SDK declares the `CAMERA` permission, which it uses for document capture and liveness.
38
+
39
+ ## API Reference
40
+
41
+ ```typescript
42
+ import { FlowStudio } from 'flowstudio-rn';
43
+ ```
44
+
45
+ ### `FlowStudio.initialize(config)`
46
+
47
+ Initializes the SDK. Call it before `start()`, for example once you have created the execution on your backend.
48
+
49
+ **Parameters (`FlowStudioConfig`):**
50
+
51
+ - `credentialId` (string): your Bureau credential ID
52
+ - `deviceCredentialId` (string): credential ID used for device intelligence
53
+ - `executionId` (string): ID of the Flow Studio execution to run
54
+ - `environment` (string, optional): `'PROD'`, `'STAGING'` or `'DEV'` (default: `'PROD'`)
55
+ - `enableLogging` (boolean, optional): enables SDK logs (default: `false`)
56
+
57
+ It throws an `Error` if a required field is missing or `environment` is invalid.
58
+
59
+ ### `FlowStudio.start()`
60
+
61
+ Opens the Flow Studio journey. The promise resolves when the journey ends.
62
+
63
+ **Returns:** `Promise<FlowStudioResult>`
64
+
65
+ ```typescript
66
+ type FlowStudioResult =
67
+ | { type: 'result'; response: ExecutionResponse } // journey finished
68
+ | { type: 'exit' }; // user left the journey without a result
69
+
70
+ interface ExecutionResponse {
71
+ executionId: string;
72
+ merchantId: string;
73
+ requestId: string;
74
+ executionStatus: string; // 'PROCESSING' | 'AWAITING' | 'COMPLETED' | 'TIMEOUT' | 'ERROR'
75
+ currentState: Record<string, unknown>;
76
+ createdAt: number; // epoch timestamp
77
+ updatedAt: number; // epoch timestamp
78
+ }
79
+ ```
80
+
81
+ Only one journey can run at a time. `start()` can be called again once the previous call has resolved.
82
+
83
+ ### `FlowStudio.isInitialized()`
84
+
85
+ **Returns:** `boolean`, which is `true` once `initialize()` has succeeded.
86
+
87
+ ## Usage Example
88
+
89
+ ```typescript
90
+ import { FlowStudio } from 'flowstudio-rn';
91
+
92
+ async function runVerification(executionId: string) {
93
+ FlowStudio.initialize({
94
+ credentialId: 'your-credential-id',
95
+ deviceCredentialId: 'your-device-credential-id',
96
+ executionId,
97
+ environment: 'STAGING', // 'PROD' for live
98
+ });
99
+
100
+ try {
101
+ const result = await FlowStudio.start();
102
+
103
+ if (result.type === 'result') {
104
+ console.log('Status:', result.response.executionStatus);
105
+ } else {
106
+ console.log('User exited the journey');
107
+ }
108
+ } catch (error) {
109
+ console.error('FlowStudio failed:', error);
110
+ }
111
+ }
112
+ ```
113
+
114
+ ## Errors
115
+
116
+ `initialize()` and `start()` throw or reject with an `Error`. Errors that come from the native side carry a `code`:
117
+
118
+ | Code | Meaning |
119
+ |---|---|
120
+ | `ERR_ALREADY_STARTED` | `start()` was called while a journey is already running |
121
+ | `ERR_NO_CONTEXT` | No Activity was available to open the journey |
122
+ | `ERR_START_FAILED` | The native SDK failed to start the journey (see `message`) |
123
+ | `ERR_INVALID_ENVIRONMENT` | Unknown `environment` value |
124
+ | `ERR_MODULE_DESTROYED` | The app reloaded or the React context was torn down during a journey |
125
+
126
+ ## Notes
127
+
128
+ - **Execution ID:** create a new execution for each journey. Execution IDs are single use.
129
+ - **Environment:** use `'STAGING'` for testing and `'PROD'` for live traffic. Credentials are environment specific.
130
+ - **Exit handling:** a `{ type: 'exit' }` result is not an error. It means the user closed the journey.
131
+
132
+ ## Example App
133
+
134
+ The `example/` directory contains an Expo app that initializes the SDK and starts a journey. To run it on a connected Android device:
135
+
136
+ ```sh
137
+ npm install
138
+ cd example && npm install && npx expo run:android
139
+ ```
140
+
141
+ ## Releasing (maintainers)
142
+
143
+ Releases are published from GitHub Actions ([`.github/workflows/release.yml`](.github/workflows/release.yml)) when a version tag (`1.2.3`, `1.2.3-alpha`, or the same with a leading `v`) is pushed to a commit on `main`:
144
+
145
+ ```sh
146
+ git tag 0.0.1-alpha
147
+ git push origin 0.0.1-alpha
148
+ ```
149
+
150
+ You can also create the tag from the GitHub UI under **Releases → Draft a new release**.
151
+
152
+ - The tag sets the published version. Keep `package.json` in sync through a PR before tagging.
153
+ - Prerelease tags (`-alpha`, `-beta`, `-rc`, ...) publish to the matching npm dist-tag. They never become `latest`.
154
+ - The workflow publishes to npm and creates a GitHub Release with generated notes and the package tarball.
155
+ - **Actions → Release → Run workflow** does a dry run: the same checks and build, with nothing published.
156
+ - The workflow needs an `NPM_TOKEN` repository secret: an npm automation token for the publishing account.
157
+
158
+ ## License
159
+
160
+ MIT
@@ -0,0 +1,41 @@
1
+ plugins {
2
+ id 'com.android.library'
3
+ id 'expo-module-gradle-plugin'
4
+ }
5
+
6
+ def bureauMavenUrl = "https://packages.bureau.id/api/packages/Bureau/maven"
7
+
8
+ // Make the Bureau Maven repository available to the host app and all its subprojects, so
9
+ // clients (Expo or bare React Native) do not need to add it to their android/build.gradle.
10
+ // The Expo config plugin (app.plugin.js) adds it too, for apps that regenerate android/.
11
+ rootProject.allprojects {
12
+ repositories {
13
+ maven { url bureauMavenUrl }
14
+ }
15
+ }
16
+
17
+ def packageJson = new groovy.json.JsonSlurper().parse(file("../package.json"))
18
+
19
+ group = 'id.bureau.flowstudio.rn'
20
+ version = packageJson.version
21
+
22
+ repositories {
23
+ google()
24
+ mavenCentral()
25
+ maven { url bureauMavenUrl }
26
+ }
27
+
28
+ android {
29
+ namespace "id.bureau.flowstudio.rn"
30
+ defaultConfig {
31
+ versionCode 1
32
+ versionName packageJson.version
33
+ }
34
+ lintOptions {
35
+ abortOnError false
36
+ }
37
+ }
38
+
39
+ dependencies {
40
+ implementation 'id.bureau:flowstudio:0.0.3-alpha'
41
+ }
@@ -0,0 +1,2 @@
1
+ <manifest>
2
+ </manifest>
@@ -0,0 +1,173 @@
1
+ package id.bureau.flowstudio.rn
2
+
3
+ import android.app.Activity
4
+ import android.app.Application
5
+ import android.os.Bundle
6
+ import android.os.Handler
7
+ import android.os.Looper
8
+ import com.bureau.flowstudio.FlowStudio
9
+ import com.bureau.flowstudio.FlowStudioCallback
10
+ import com.bureau.flowstudio.FlowStudioConfig
11
+ import com.bureau.flowstudio.FlowStudioEnvironment
12
+ import com.bureau.flowstudio.ui.FlowStudioActivity
13
+ import com.bureau.network.data.model.network.ExecutionResponse
14
+ import expo.modules.kotlin.Promise
15
+ import expo.modules.kotlin.exception.CodedException
16
+ import expo.modules.kotlin.exception.Exceptions
17
+ import expo.modules.kotlin.functions.Queues
18
+ import expo.modules.kotlin.modules.Module
19
+ import expo.modules.kotlin.modules.ModuleDefinition
20
+ import expo.modules.kotlin.records.Field
21
+ import expo.modules.kotlin.records.Record
22
+ import java.util.concurrent.atomic.AtomicReference
23
+
24
+ /**
25
+ * Config received from JS. Mirrors `Required<FlowStudioConfig>` in `src/FlowStudio.ts`;
26
+ * defaults are already applied on the JS side.
27
+ */
28
+ class FlowStudioConfigRecord : Record {
29
+ @Field val credentialId: String = ""
30
+ @Field val deviceCredentialId: String = ""
31
+ @Field val executionId: String = ""
32
+ @Field val environment: String = "PROD"
33
+ @Field val enableLogging: Boolean = false
34
+ }
35
+
36
+ /**
37
+ * Android implementation of the bridge contract defined in `src/FlowStudio.ts`
38
+ * (`FlowStudioNativeContract`). Function names must match it exactly.
39
+ */
40
+ class FlowStudioReactNativeModule : Module() {
41
+ // Promise of the flow currently running, if any. Resolved exactly once.
42
+ private val pendingStart = AtomicReference<Promise?>(null)
43
+ private val mainHandler = Handler(Looper.getMainLooper())
44
+ private var flowActivityWatcher: Application.ActivityLifecycleCallbacks? = null
45
+
46
+ private fun settle(block: (Promise) -> Unit) {
47
+ pendingStart.getAndSet(null)?.let { promise ->
48
+ stopWatchingFlowActivity()
49
+ block(promise)
50
+ }
51
+ }
52
+
53
+ /**
54
+ * The SDK does not invoke FlowStudioCallback when the user backs out of the flow.
55
+ * Resolve as `exit` once FlowStudioActivity is finished for good, unless the SDK
56
+ * reports a result first (the delay gives its callback time to arrive).
57
+ */
58
+ private fun watchFlowActivity(application: Application) {
59
+ stopWatchingFlowActivity()
60
+ val watcher = object : Application.ActivityLifecycleCallbacks {
61
+ override fun onActivityDestroyed(activity: Activity) {
62
+ if (activity is FlowStudioActivity && activity.isFinishing) {
63
+ mainHandler.postDelayed({ settle { it.resolve(mapOf("type" to "exit")) } }, EXIT_FALLBACK_DELAY_MS)
64
+ }
65
+ }
66
+
67
+ override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = Unit
68
+ override fun onActivityStarted(activity: Activity) = Unit
69
+ override fun onActivityResumed(activity: Activity) = Unit
70
+ override fun onActivityPaused(activity: Activity) = Unit
71
+ override fun onActivityStopped(activity: Activity) = Unit
72
+ override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
73
+ }
74
+ application.registerActivityLifecycleCallbacks(watcher)
75
+ flowActivityWatcher = watcher
76
+ }
77
+
78
+ private fun stopWatchingFlowActivity() {
79
+ val watcher = flowActivityWatcher ?: return
80
+ flowActivityWatcher = null
81
+ (appContext.reactContext?.applicationContext as? Application)
82
+ ?.unregisterActivityLifecycleCallbacks(watcher)
83
+ }
84
+
85
+ override fun definition() = ModuleDefinition {
86
+ Name("FlowStudioReactNative")
87
+
88
+ // initialize(config: Required<FlowStudioConfig>): void
89
+ Function("initialize") { config: FlowStudioConfigRecord ->
90
+ val application = appContext.reactContext?.applicationContext as? Application
91
+ ?: throw Exceptions.ReactContextLost()
92
+
93
+ val environment = FlowStudioEnvironment.entries.find { it.name == config.environment }
94
+ ?: throw CodedException("ERR_INVALID_ENVIRONMENT", "Unknown environment: ${config.environment}", null)
95
+
96
+ FlowStudio.initialize(
97
+ application,
98
+ FlowStudioConfig(
99
+ config.enableLogging,
100
+ config.credentialId,
101
+ environment,
102
+ config.deviceCredentialId,
103
+ config.executionId,
104
+ ),
105
+ )
106
+ }
107
+
108
+ // start(): Promise<FlowStudioResult>
109
+ // FlowStudio.start() must be called on the main thread.
110
+ AsyncFunction("start") { promise: Promise ->
111
+ if (!FlowStudio.isInitialized()) {
112
+ promise.reject("ERR_NOT_INITIALIZED", "Call initialize() before start()", null)
113
+ return@AsyncFunction
114
+ }
115
+ if (!pendingStart.compareAndSet(null, promise)) {
116
+ promise.reject("ERR_ALREADY_STARTED", "A FlowStudio flow is already in progress", null)
117
+ return@AsyncFunction
118
+ }
119
+
120
+ val context = appContext.currentActivity ?: appContext.reactContext
121
+ if (context == null) {
122
+ pendingStart.set(null)
123
+ promise.reject("ERR_NO_CONTEXT", "No Activity or React context available to start FlowStudio", null)
124
+ return@AsyncFunction
125
+ }
126
+
127
+ (context.applicationContext as? Application)?.let(::watchFlowActivity)
128
+
129
+ try {
130
+ FlowStudio.start(context, object : FlowStudioCallback {
131
+ override fun onResult(response: ExecutionResponse) {
132
+ settle { it.resolve(mapOf("type" to "result", "response" to response.toMap())) }
133
+ }
134
+
135
+ override fun onExit() {
136
+ settle { it.resolve(mapOf("type" to "exit")) }
137
+ }
138
+ })
139
+ } catch (e: Exception) {
140
+ settle { it.reject("ERR_START_FAILED", e.message ?: "Failed to start FlowStudio", e) }
141
+ }
142
+ }.runOnQueue(Queues.MAIN)
143
+
144
+ // isInitialized(): boolean
145
+ Function("isInitialized") {
146
+ FlowStudio.isInitialized()
147
+ }
148
+
149
+ OnDestroy {
150
+ mainHandler.removeCallbacksAndMessages(null)
151
+ settle { it.reject("ERR_MODULE_DESTROYED", "FlowStudio module was destroyed before the flow finished", null) }
152
+ }
153
+ }
154
+
155
+ private companion object {
156
+ const val EXIT_FALLBACK_DELAY_MS = 500L
157
+ }
158
+ }
159
+
160
+ private fun ExecutionResponse.toMap(): Map<String, Any> = mapOf(
161
+ "executionId" to executionId,
162
+ "merchantId" to merchantId,
163
+ "requestId" to requestId,
164
+ "executionStatus" to executionStatus.name,
165
+ "currentState" to mapOf(
166
+ "type" to currentState.type.name,
167
+ "popCurrent" to currentState.popCurrent,
168
+ "screenType" to currentState.screenType.name,
169
+ "screenId" to currentState.screenId,
170
+ ),
171
+ "createdAt" to createdAt,
172
+ "updatedAt" to updatedAt,
173
+ )
package/app.plugin.js ADDED
@@ -0,0 +1,2 @@
1
+ // Expo config plugin entry point, resolved when an app lists "flowstudio-rn" in `plugins`.
2
+ module.exports = require('./plugin/build');
@@ -0,0 +1,21 @@
1
+ import { FlowStudioConfig, FlowStudioResult } from './FlowStudioReactNative.types';
2
+ /**
3
+ * Initializes the Flow Studio SDK. Must be called before `start()`.
4
+ */
5
+ declare function initialize(config: FlowStudioConfig): void;
6
+ /**
7
+ * Launches the Flow Studio flow. Resolves when the flow finishes
8
+ * (`type: 'result'`) or the user exits it (`type: 'exit'`).
9
+ */
10
+ declare function start(): Promise<FlowStudioResult>;
11
+ /**
12
+ * Returns whether `initialize()` has completed successfully.
13
+ */
14
+ declare function isInitialized(): boolean;
15
+ export declare const FlowStudio: {
16
+ initialize: typeof initialize;
17
+ start: typeof start;
18
+ isInitialized: typeof isInitialized;
19
+ };
20
+ export {};
21
+ //# sourceMappingURL=FlowStudio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowStudio.d.ts","sourceRoot":"","sources":["../src/FlowStudio.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAEhB,gBAAgB,EACjB,MAAM,+BAA+B,CAAC;AAsBvC;;GAEG;AACH,iBAAS,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAoBlD;AAED;;;GAGG;AACH,iBAAe,KAAK,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAMhD;AAED;;GAEG;AACH,iBAAS,aAAa,IAAI,OAAO,CAEhC;AAED,eAAO,MAAM,UAAU;;;;CAItB,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { Platform } from 'react-native';
2
+ import native from './FlowStudioReactNativeModule';
3
+ const ENVIRONMENTS = ['PROD', 'STAGING', 'DEV'];
4
+ // Only the Android native module is implemented so far.
5
+ const isSupportedPlatform = Platform.OS === 'android';
6
+ function requireSupportedPlatform() {
7
+ if (!isSupportedPlatform) {
8
+ throw new Error(`FlowStudio: ${Platform.OS} is not supported yet (Android only in this release)`);
9
+ }
10
+ }
11
+ function requireNonEmpty(value, name) {
12
+ if (typeof value !== 'string' || value.trim() === '') {
13
+ throw new Error(`FlowStudio: \`${name}\` is required and must be a non-empty string`);
14
+ }
15
+ }
16
+ /**
17
+ * Initializes the Flow Studio SDK. Must be called before `start()`.
18
+ */
19
+ function initialize(config) {
20
+ requireSupportedPlatform();
21
+ requireNonEmpty(config?.credentialId, 'credentialId');
22
+ requireNonEmpty(config.deviceCredentialId, 'deviceCredentialId');
23
+ requireNonEmpty(config.executionId, 'executionId');
24
+ const environment = config.environment ?? 'PROD';
25
+ if (!ENVIRONMENTS.includes(environment)) {
26
+ throw new Error(`FlowStudio: \`environment\` must be one of ${ENVIRONMENTS.join(', ')}, got "${environment}"`);
27
+ }
28
+ native.initialize({
29
+ credentialId: config.credentialId,
30
+ deviceCredentialId: config.deviceCredentialId,
31
+ executionId: config.executionId,
32
+ environment,
33
+ enableLogging: config.enableLogging ?? false,
34
+ });
35
+ }
36
+ /**
37
+ * Launches the Flow Studio flow. Resolves when the flow finishes
38
+ * (`type: 'result'`) or the user exits it (`type: 'exit'`).
39
+ */
40
+ async function start() {
41
+ requireSupportedPlatform();
42
+ if (!native.isInitialized()) {
43
+ throw new Error('FlowStudio: call `initialize()` before `start()`');
44
+ }
45
+ return native.start();
46
+ }
47
+ /**
48
+ * Returns whether `initialize()` has completed successfully.
49
+ */
50
+ function isInitialized() {
51
+ return isSupportedPlatform && native.isInitialized();
52
+ }
53
+ export const FlowStudio = {
54
+ initialize,
55
+ start,
56
+ isInitialized,
57
+ };
58
+ //# sourceMappingURL=FlowStudio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowStudio.js","sourceRoot":"","sources":["../src/FlowStudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAOxC,OAAO,MAAM,MAAM,+BAA+B,CAAC;AAEnD,MAAM,YAAY,GAAqC,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAElF,wDAAwD;AACxD,MAAM,mBAAmB,GAAG,QAAQ,CAAC,EAAE,KAAK,SAAS,CAAC;AAEtD,SAAS,wBAAwB;IAC/B,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,eAAe,QAAQ,CAAC,EAAE,sDAAsD,CACjF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAc,EAAE,IAAY;IACnD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,+CAA+C,CAAC,CAAC;IACxF,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,MAAwB;IAC1C,wBAAwB,EAAE,CAAC;IAC3B,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC;IACtD,eAAe,CAAC,MAAM,CAAC,kBAAkB,EAAE,oBAAoB,CAAC,CAAC;IACjE,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAEnD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC;IACjD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,8CAA8C,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,WAAW,GAAG,CAC9F,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,UAAU,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,WAAW;QACX,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,KAAK;KAC7C,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,KAAK;IAClB,wBAAwB,EAAE,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,EAAE,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,SAAS,aAAa;IACpB,OAAO,mBAAmB,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,UAAU;IACV,KAAK;IACL,aAAa;CACd,CAAC","sourcesContent":["import { Platform } from 'react-native';\n\nimport {\n FlowStudioConfig,\n FlowStudioEnvironment,\n FlowStudioResult,\n} from './FlowStudioReactNative.types';\nimport native from './FlowStudioReactNativeModule';\n\nconst ENVIRONMENTS: readonly FlowStudioEnvironment[] = ['PROD', 'STAGING', 'DEV'];\n\n// Only the Android native module is implemented so far.\nconst isSupportedPlatform = Platform.OS === 'android';\n\nfunction requireSupportedPlatform(): void {\n if (!isSupportedPlatform) {\n throw new Error(\n `FlowStudio: ${Platform.OS} is not supported yet (Android only in this release)`\n );\n }\n}\n\nfunction requireNonEmpty(value: unknown, name: string): void {\n if (typeof value !== 'string' || value.trim() === '') {\n throw new Error(`FlowStudio: \\`${name}\\` is required and must be a non-empty string`);\n }\n}\n\n/**\n * Initializes the Flow Studio SDK. Must be called before `start()`.\n */\nfunction initialize(config: FlowStudioConfig): void {\n requireSupportedPlatform();\n requireNonEmpty(config?.credentialId, 'credentialId');\n requireNonEmpty(config.deviceCredentialId, 'deviceCredentialId');\n requireNonEmpty(config.executionId, 'executionId');\n\n const environment = config.environment ?? 'PROD';\n if (!ENVIRONMENTS.includes(environment)) {\n throw new Error(\n `FlowStudio: \\`environment\\` must be one of ${ENVIRONMENTS.join(', ')}, got \"${environment}\"`\n );\n }\n\n native.initialize({\n credentialId: config.credentialId,\n deviceCredentialId: config.deviceCredentialId,\n executionId: config.executionId,\n environment,\n enableLogging: config.enableLogging ?? false,\n });\n}\n\n/**\n * Launches the Flow Studio flow. Resolves when the flow finishes\n * (`type: 'result'`) or the user exits it (`type: 'exit'`).\n */\nasync function start(): Promise<FlowStudioResult> {\n requireSupportedPlatform();\n if (!native.isInitialized()) {\n throw new Error('FlowStudio: call `initialize()` before `start()`');\n }\n return native.start();\n}\n\n/**\n * Returns whether `initialize()` has completed successfully.\n */\nfunction isInitialized(): boolean {\n return isSupportedPlatform && native.isInitialized();\n}\n\nexport const FlowStudio = {\n initialize,\n start,\n isInitialized,\n};\n"]}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Backend environment the Flow Studio SDK connects to.
3
+ * Mirrors native `FlowStudioEnvironment` (PROD | STAGING | DEV).
4
+ */
5
+ export type FlowStudioEnvironment = 'PROD' | 'STAGING' | 'DEV';
6
+ /**
7
+ * Configuration passed to `FlowStudio.initialize()`.
8
+ * Mirrors native `FlowStudioConfig`.
9
+ */
10
+ export interface FlowStudioConfig {
11
+ /** Credential ID issued by Bureau. */
12
+ credentialId: string;
13
+ /** Credential ID used for device intelligence. */
14
+ deviceCredentialId: string;
15
+ /** ID of the flow execution to run. */
16
+ executionId: string;
17
+ /** Defaults to `'PROD'`. */
18
+ environment?: FlowStudioEnvironment;
19
+ /** Enables SDK logging. Defaults to `false`. */
20
+ enableLogging?: boolean;
21
+ }
22
+ /**
23
+ * Result of a completed flow execution.
24
+ * Mirrors native `ExecutionResponse`.
25
+ */
26
+ export interface ExecutionResponse {
27
+ executionId: string;
28
+ merchantId: string;
29
+ requestId: string;
30
+ executionStatus: string;
31
+ currentState: Record<string, unknown>;
32
+ /** Epoch timestamp. */
33
+ createdAt: number;
34
+ /** Epoch timestamp. */
35
+ updatedAt: number;
36
+ }
37
+ /**
38
+ * Outcome of `FlowStudio.start()`. Mirrors native `FlowStudioCallback`:
39
+ * - `result` → `onResult(response)`
40
+ * - `exit` → `onExit()` (user left the flow without a result)
41
+ */
42
+ export type FlowStudioResult = {
43
+ type: 'result';
44
+ response: ExecutionResponse;
45
+ } | {
46
+ type: 'exit';
47
+ };
48
+ //# sourceMappingURL=FlowStudioReactNative.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowStudioReactNative.types.d.ts","sourceRoot":"","sources":["../src/FlowStudioReactNative.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC;AAE/D;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,gDAAgD;IAChD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,iBAAiB,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=FlowStudioReactNative.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowStudioReactNative.types.js","sourceRoot":"","sources":["../src/FlowStudioReactNative.types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Backend environment the Flow Studio SDK connects to.\n * Mirrors native `FlowStudioEnvironment` (PROD | STAGING | DEV).\n */\nexport type FlowStudioEnvironment = 'PROD' | 'STAGING' | 'DEV';\n\n/**\n * Configuration passed to `FlowStudio.initialize()`.\n * Mirrors native `FlowStudioConfig`.\n */\nexport interface FlowStudioConfig {\n /** Credential ID issued by Bureau. */\n credentialId: string;\n /** Credential ID used for device intelligence. */\n deviceCredentialId: string;\n /** ID of the flow execution to run. */\n executionId: string;\n /** Defaults to `'PROD'`. */\n environment?: FlowStudioEnvironment;\n /** Enables SDK logging. Defaults to `false`. */\n enableLogging?: boolean;\n}\n\n/**\n * Result of a completed flow execution.\n * Mirrors native `ExecutionResponse`.\n */\nexport interface ExecutionResponse {\n executionId: string;\n merchantId: string;\n requestId: string;\n executionStatus: string;\n currentState: Record<string, unknown>;\n /** Epoch timestamp. */\n createdAt: number;\n /** Epoch timestamp. */\n updatedAt: number;\n}\n\n/**\n * Outcome of `FlowStudio.start()`. Mirrors native `FlowStudioCallback`:\n * - `result` → `onResult(response)`\n * - `exit` → `onExit()` (user left the flow without a result)\n */\nexport type FlowStudioResult = { type: 'result'; response: ExecutionResponse } | { type: 'exit' };\n"]}
@@ -0,0 +1,15 @@
1
+ import { NativeModule } from 'expo';
2
+ import { FlowStudioConfig, FlowStudioResult } from './FlowStudioReactNative.types';
3
+ /**
4
+ * Contract the native modules (Kotlin on Android, Swift on iOS) must implement.
5
+ * Names must match `Function(...)` / `AsyncFunction(...)` in the native modules exactly.
6
+ * Only plain data crosses the bridge, so config is passed fully resolved.
7
+ */
8
+ declare class FlowStudioReactNativeModule extends NativeModule<{}> {
9
+ initialize(config: Required<FlowStudioConfig>): void;
10
+ start(): Promise<FlowStudioResult>;
11
+ isInitialized(): boolean;
12
+ }
13
+ declare const _default: FlowStudioReactNativeModule;
14
+ export default _default;
15
+ //# sourceMappingURL=FlowStudioReactNativeModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowStudioReactNativeModule.d.ts","sourceRoot":"","sources":["../src/FlowStudioReactNativeModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEnF;;;;GAIG;AACH,OAAO,OAAO,2BAA4B,SAAQ,YAAY,CAAC,EAAE,CAAC;IAChE,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,IAAI;IACpD,KAAK,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAClC,aAAa,IAAI,OAAO;CACzB;;AAED,wBAAyF"}
@@ -0,0 +1,3 @@
1
+ import { requireNativeModule } from 'expo';
2
+ export default requireNativeModule('FlowStudioReactNative');
3
+ //# sourceMappingURL=FlowStudioReactNativeModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowStudioReactNativeModule.js","sourceRoot":"","sources":["../src/FlowStudioReactNativeModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAezD,eAAe,mBAAmB,CAA8B,uBAAuB,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport { FlowStudioConfig, FlowStudioResult } from './FlowStudioReactNative.types';\n\n/**\n * Contract the native modules (Kotlin on Android, Swift on iOS) must implement.\n * Names must match `Function(...)` / `AsyncFunction(...)` in the native modules exactly.\n * Only plain data crosses the bridge, so config is passed fully resolved.\n */\ndeclare class FlowStudioReactNativeModule extends NativeModule<{}> {\n initialize(config: Required<FlowStudioConfig>): void;\n start(): Promise<FlowStudioResult>;\n isInitialized(): boolean;\n}\n\nexport default requireNativeModule<FlowStudioReactNativeModule>('FlowStudioReactNative');\n"]}
@@ -0,0 +1,6 @@
1
+ import { NativeModule } from 'expo';
2
+ declare class FlowStudioReactNativeModule extends NativeModule<{}> {
3
+ }
4
+ declare const _default: typeof FlowStudioReactNativeModule;
5
+ export default _default;
6
+ //# sourceMappingURL=FlowStudioReactNativeModule.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowStudioReactNativeModule.web.d.ts","sourceRoot":"","sources":["../src/FlowStudioReactNativeModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,YAAY,EAAE,MAAM,MAAM,CAAC;AAGvD,cAAM,2BAA4B,SAAQ,YAAY,CAAC,EAAE,CAAC;CAAG;;AAE7D,wBAA6F"}
@@ -0,0 +1,6 @@
1
+ import { registerWebModule, NativeModule } from 'expo';
2
+ // FlowStudioReactNativeModule is not available on the web platform.
3
+ class FlowStudioReactNativeModule extends NativeModule {
4
+ }
5
+ export default registerWebModule(FlowStudioReactNativeModule, 'FlowStudioReactNativeModule');
6
+ //# sourceMappingURL=FlowStudioReactNativeModule.web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowStudioReactNativeModule.web.js","sourceRoot":"","sources":["../src/FlowStudioReactNativeModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAEvD,oEAAoE;AACpE,MAAM,2BAA4B,SAAQ,YAAgB;CAAG;AAE7D,eAAe,iBAAiB,CAAC,2BAA2B,EAAE,6BAA6B,CAAC,CAAC","sourcesContent":["import { registerWebModule, NativeModule } from 'expo';\n\n// FlowStudioReactNativeModule is not available on the web platform.\nclass FlowStudioReactNativeModule extends NativeModule<{}> {}\n\nexport default registerWebModule(FlowStudioReactNativeModule, 'FlowStudioReactNativeModule');\n"]}
@@ -0,0 +1,4 @@
1
+ export { FlowStudio } from './FlowStudio';
2
+ export { FlowStudio as default } from './FlowStudio';
3
+ export type { ExecutionResponse, FlowStudioConfig, FlowStudioEnvironment, FlowStudioResult, } from './FlowStudioReactNative.types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAErD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,+BAA+B,CAAC"}
package/build/index.js ADDED
@@ -0,0 +1,4 @@
1
+ // Public API of flowstudio-rn. Only what is exported here is available to clients.
2
+ export { FlowStudio } from './FlowStudio';
3
+ export { FlowStudio as default } from './FlowStudio';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC","sourcesContent":["// Public API of flowstudio-rn. Only what is exported here is available to clients.\nexport { FlowStudio } from './FlowStudio';\nexport { FlowStudio as default } from './FlowStudio';\n\nexport type {\n ExecutionResponse,\n FlowStudioConfig,\n FlowStudioEnvironment,\n FlowStudioResult,\n} from './FlowStudioReactNative.types';\n"]}
@@ -0,0 +1,9 @@
1
+ {
2
+ "platforms": ["apple", "android"],
3
+ "apple": {
4
+ "modules": ["FlowStudioReactNativeModule"]
5
+ },
6
+ "android": {
7
+ "modules": ["id.bureau.flowstudio.rn.FlowStudioReactNativeModule"]
8
+ }
9
+ }
@@ -0,0 +1,23 @@
1
+ Pod::Spec.new do |s|
2
+ s.name = 'FlowStudioReactNative'
3
+ s.version = '1.0.0'
4
+ s.summary = 'A sample project summary'
5
+ s.description = 'A sample project description'
6
+ s.author = ''
7
+ s.homepage = 'https://docs.expo.dev/modules/'
8
+ s.platforms = {
9
+ :ios => '16.4',
10
+ :tvos => '16.4'
11
+ }
12
+ s.source = { git: '' }
13
+ s.static_framework = true
14
+
15
+ s.dependency 'ExpoModulesCore'
16
+
17
+ # Swift/Objective-C compatibility
18
+ s.pod_target_xcconfig = {
19
+ 'DEFINES_MODULE' => 'YES',
20
+ }
21
+
22
+ s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
23
+ end
@@ -0,0 +1,7 @@
1
+ import ExpoModulesCore
2
+
3
+ public class FlowStudioReactNativeModule: Module {
4
+ public func definition() -> ModuleDefinition {
5
+ Name("FlowStudioReactNative")
6
+ }
7
+ }
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "flowstudio-rn",
3
+ "version": "0.0.1-alpha",
4
+ "description": "React Native SDK for Bureau Flow Studio: run Flow Studio identity and verification journeys in React Native / Expo apps.",
5
+ "main": "build/index.js",
6
+ "types": "build/index.d.ts",
7
+ "files": [
8
+ "build",
9
+ "src",
10
+ "android",
11
+ "!android/build",
12
+ "!android/.gradle",
13
+ "!android/.gitignore",
14
+ "!android/src/test",
15
+ "!android/src/androidTest",
16
+ "ios",
17
+ "plugin/build",
18
+ "app.plugin.js",
19
+ "expo-module.config.json",
20
+ "!**/__tests__",
21
+ "!**/__mocks__"
22
+ ],
23
+ "scripts": {
24
+ "build": "node internal/module_scripts/build.js",
25
+ "clean": "node internal/module_scripts/clean.js",
26
+ "lint": "eslint src/ plugin/src/",
27
+ "test": "node internal/module_scripts/test.js",
28
+ "prepare": "node internal/module_scripts/prepare.js",
29
+ "open:ios": "node internal/module_scripts/open-ios.js",
30
+ "open:android": "node internal/module_scripts/open-android.js",
31
+ "typecheck": "tsc --noEmit && tsc --noEmit -p plugin"
32
+ },
33
+ "keywords": [
34
+ "react-native",
35
+ "expo",
36
+ "bureau",
37
+ "flowstudio",
38
+ "identity-verification",
39
+ "kyc"
40
+ ],
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/deepak-bureau/flowstudio-react-native-sdk.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/deepak-bureau/flowstudio-react-native-sdk/issues"
47
+ },
48
+ "author": "Bureau <techops@bureau.id> (https://bureau.id)",
49
+ "license": "MIT",
50
+ "homepage": "https://github.com/deepak-bureau/flowstudio-react-native-sdk#readme",
51
+ "publishConfig": {
52
+ "registry": "https://registry.npmjs.org/",
53
+ "access": "public"
54
+ },
55
+ "engines": {
56
+ "node": "^20.19.4 || ^22.13.0 || >=24.3.0"
57
+ },
58
+ "devDependencies": {
59
+ "@babel/core": "^7.26.0",
60
+ "@react-native/jest-preset": "^0.86.3",
61
+ "@types/jest": "^29.2.1",
62
+ "@types/react": "~19.2.2",
63
+ "babel-preset-expo": "~57.0.12",
64
+ "eslint": "~9.39.4",
65
+ "eslint-config-universe": "^15.0.3",
66
+ "expo": "~57.0.24",
67
+ "expo-modules-core": "~57.0.18",
68
+ "jest": "^29.7.0",
69
+ "jest-expo": "~57.0.5",
70
+ "prettier": "^3.0.0",
71
+ "react": "19.2.3",
72
+ "react-native": "0.86.3",
73
+ "typescript": "^5.9.2"
74
+ },
75
+ "jest": {
76
+ "preset": "jest-expo",
77
+ "roots": [
78
+ "<rootDir>/src"
79
+ ]
80
+ },
81
+ "peerDependencies": {
82
+ "expo": "*",
83
+ "react": "*",
84
+ "react-native": "*"
85
+ }
86
+ }
@@ -0,0 +1,3 @@
1
+ import { ConfigPlugin } from 'expo/config-plugins';
2
+ declare const withFlowStudio: ConfigPlugin;
3
+ export default withFlowStudio;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config_plugins_1 = require("expo/config-plugins");
4
+ // Maven repository hosting the native FlowStudio SDK (id.bureau:flowstudio).
5
+ const BUREAU_MAVEN_URL = 'https://packages.bureau.id/api/packages/Bureau/maven';
6
+ /**
7
+ * Adds the Bureau Maven repository to the app's android/build.gradle
8
+ * (`allprojects { repositories { ... } }`) so the native FlowStudio SDK can be resolved.
9
+ */
10
+ const withBureauMavenRepo = (config) => (0, config_plugins_1.withProjectBuildGradle)(config, (config) => {
11
+ const { contents, language } = config.modResults;
12
+ // Already added (by us on a previous run, or by hand).
13
+ if (contents.includes(BUREAU_MAVEN_URL)) {
14
+ return config;
15
+ }
16
+ const repoLine = language === 'kt'
17
+ ? `maven { url = uri("${BUREAU_MAVEN_URL}") }`
18
+ : `maven { url '${BUREAU_MAVEN_URL}' }`;
19
+ const anchor = /allprojects\s*\{\s*repositories\s*\{/;
20
+ if (!anchor.test(contents)) {
21
+ config_plugins_1.WarningAggregator.addWarningAndroid('flowstudio-rn', `Could not find "allprojects { repositories { ... } }" in android/build.gradle. ` +
22
+ `Add the FlowStudio Maven repository manually: ${repoLine}`);
23
+ return config;
24
+ }
25
+ config.modResults.contents = contents.replace(anchor, (match) => `${match}\n ${repoLine}`);
26
+ return config;
27
+ });
28
+ const withFlowStudio = (config) => withBureauMavenRepo(config);
29
+ exports.default = withFlowStudio;
@@ -0,0 +1,77 @@
1
+ import { Platform } from 'react-native';
2
+
3
+ import {
4
+ FlowStudioConfig,
5
+ FlowStudioEnvironment,
6
+ FlowStudioResult,
7
+ } from './FlowStudioReactNative.types';
8
+ import native from './FlowStudioReactNativeModule';
9
+
10
+ const ENVIRONMENTS: readonly FlowStudioEnvironment[] = ['PROD', 'STAGING', 'DEV'];
11
+
12
+ // Only the Android native module is implemented so far.
13
+ const isSupportedPlatform = Platform.OS === 'android';
14
+
15
+ function requireSupportedPlatform(): void {
16
+ if (!isSupportedPlatform) {
17
+ throw new Error(
18
+ `FlowStudio: ${Platform.OS} is not supported yet (Android only in this release)`
19
+ );
20
+ }
21
+ }
22
+
23
+ function requireNonEmpty(value: unknown, name: string): void {
24
+ if (typeof value !== 'string' || value.trim() === '') {
25
+ throw new Error(`FlowStudio: \`${name}\` is required and must be a non-empty string`);
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Initializes the Flow Studio SDK. Must be called before `start()`.
31
+ */
32
+ function initialize(config: FlowStudioConfig): void {
33
+ requireSupportedPlatform();
34
+ requireNonEmpty(config?.credentialId, 'credentialId');
35
+ requireNonEmpty(config.deviceCredentialId, 'deviceCredentialId');
36
+ requireNonEmpty(config.executionId, 'executionId');
37
+
38
+ const environment = config.environment ?? 'PROD';
39
+ if (!ENVIRONMENTS.includes(environment)) {
40
+ throw new Error(
41
+ `FlowStudio: \`environment\` must be one of ${ENVIRONMENTS.join(', ')}, got "${environment}"`
42
+ );
43
+ }
44
+
45
+ native.initialize({
46
+ credentialId: config.credentialId,
47
+ deviceCredentialId: config.deviceCredentialId,
48
+ executionId: config.executionId,
49
+ environment,
50
+ enableLogging: config.enableLogging ?? false,
51
+ });
52
+ }
53
+
54
+ /**
55
+ * Launches the Flow Studio flow. Resolves when the flow finishes
56
+ * (`type: 'result'`) or the user exits it (`type: 'exit'`).
57
+ */
58
+ async function start(): Promise<FlowStudioResult> {
59
+ requireSupportedPlatform();
60
+ if (!native.isInitialized()) {
61
+ throw new Error('FlowStudio: call `initialize()` before `start()`');
62
+ }
63
+ return native.start();
64
+ }
65
+
66
+ /**
67
+ * Returns whether `initialize()` has completed successfully.
68
+ */
69
+ function isInitialized(): boolean {
70
+ return isSupportedPlatform && native.isInitialized();
71
+ }
72
+
73
+ export const FlowStudio = {
74
+ initialize,
75
+ start,
76
+ isInitialized,
77
+ };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Backend environment the Flow Studio SDK connects to.
3
+ * Mirrors native `FlowStudioEnvironment` (PROD | STAGING | DEV).
4
+ */
5
+ export type FlowStudioEnvironment = 'PROD' | 'STAGING' | 'DEV';
6
+
7
+ /**
8
+ * Configuration passed to `FlowStudio.initialize()`.
9
+ * Mirrors native `FlowStudioConfig`.
10
+ */
11
+ export interface FlowStudioConfig {
12
+ /** Credential ID issued by Bureau. */
13
+ credentialId: string;
14
+ /** Credential ID used for device intelligence. */
15
+ deviceCredentialId: string;
16
+ /** ID of the flow execution to run. */
17
+ executionId: string;
18
+ /** Defaults to `'PROD'`. */
19
+ environment?: FlowStudioEnvironment;
20
+ /** Enables SDK logging. Defaults to `false`. */
21
+ enableLogging?: boolean;
22
+ }
23
+
24
+ /**
25
+ * Result of a completed flow execution.
26
+ * Mirrors native `ExecutionResponse`.
27
+ */
28
+ export interface ExecutionResponse {
29
+ executionId: string;
30
+ merchantId: string;
31
+ requestId: string;
32
+ executionStatus: string;
33
+ currentState: Record<string, unknown>;
34
+ /** Epoch timestamp. */
35
+ createdAt: number;
36
+ /** Epoch timestamp. */
37
+ updatedAt: number;
38
+ }
39
+
40
+ /**
41
+ * Outcome of `FlowStudio.start()`. Mirrors native `FlowStudioCallback`:
42
+ * - `result` → `onResult(response)`
43
+ * - `exit` → `onExit()` (user left the flow without a result)
44
+ */
45
+ export type FlowStudioResult = { type: 'result'; response: ExecutionResponse } | { type: 'exit' };
@@ -0,0 +1,16 @@
1
+ import { NativeModule, requireNativeModule } from 'expo';
2
+
3
+ import { FlowStudioConfig, FlowStudioResult } from './FlowStudioReactNative.types';
4
+
5
+ /**
6
+ * Contract the native modules (Kotlin on Android, Swift on iOS) must implement.
7
+ * Names must match `Function(...)` / `AsyncFunction(...)` in the native modules exactly.
8
+ * Only plain data crosses the bridge, so config is passed fully resolved.
9
+ */
10
+ declare class FlowStudioReactNativeModule extends NativeModule<{}> {
11
+ initialize(config: Required<FlowStudioConfig>): void;
12
+ start(): Promise<FlowStudioResult>;
13
+ isInitialized(): boolean;
14
+ }
15
+
16
+ export default requireNativeModule<FlowStudioReactNativeModule>('FlowStudioReactNative');
@@ -0,0 +1,6 @@
1
+ import { registerWebModule, NativeModule } from 'expo';
2
+
3
+ // FlowStudioReactNativeModule is not available on the web platform.
4
+ class FlowStudioReactNativeModule extends NativeModule<{}> {}
5
+
6
+ export default registerWebModule(FlowStudioReactNativeModule, 'FlowStudioReactNativeModule');
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ // Public API of flowstudio-rn. Only what is exported here is available to clients.
2
+ export { FlowStudio } from './FlowStudio';
3
+ export { FlowStudio as default } from './FlowStudio';
4
+
5
+ export type {
6
+ ExecutionResponse,
7
+ FlowStudioConfig,
8
+ FlowStudioEnvironment,
9
+ FlowStudioResult,
10
+ } from './FlowStudioReactNative.types';