@userflow-tech/react-native 0.1.0 → 0.1.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.
- package/README.md +24 -14
- package/app.plugin.js +3 -0
- package/babel-plugin/index.d.ts +43 -0
- package/babel-plugin/index.d.ts.map +1 -0
- package/babel-plugin/index.js +854 -0
- package/babel-plugin/index.js.map +1 -0
- package/docs/deep-linking.md +2 -2
- package/docs/troubleshooting.md +2 -2
- package/expo-plugin/withUserflow.d.ts +17 -0
- package/expo-plugin/withUserflow.d.ts.map +1 -0
- package/expo-plugin/withUserflow.js +99 -0
- package/expo-plugin/withUserflow.js.map +1 -0
- package/lib/commonjs/anchors/AutoAnchorRegistry.js +1 -1
- package/lib/commonjs/anchors/autoAnchor.js +1 -1
- package/lib/commonjs/anchors/hintsCodec.js +1 -1
- package/lib/commonjs/pairing/diagnostics.js +2 -2
- package/lib/commonjs/pairing/diagnostics.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/anchors/AutoAnchorRegistry.js +1 -1
- package/lib/module/anchors/autoAnchor.js +1 -1
- package/lib/module/anchors/hintsCodec.js +1 -1
- package/lib/module/pairing/diagnostics.js +2 -2
- package/lib/module/pairing/diagnostics.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/commonjs/src/anchors/AutoAnchorRegistry.d.ts +1 -1
- package/lib/typescript/commonjs/src/anchors/AutoAnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/autoAnchor.d.ts +1 -1
- package/lib/typescript/commonjs/src/anchors/hintsCodec.d.ts +1 -1
- package/lib/typescript/commonjs/src/version.d.ts +1 -1
- package/lib/typescript/module/src/anchors/AutoAnchorRegistry.d.ts +1 -1
- package/lib/typescript/module/src/anchors/AutoAnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/autoAnchor.d.ts +1 -1
- package/lib/typescript/module/src/anchors/hintsCodec.d.ts +1 -1
- package/lib/typescript/module/src/version.d.ts +1 -1
- package/package.json +15 -7
- package/src/anchors/AutoAnchorRegistry.ts +1 -1
- package/src/anchors/autoAnchor.ts +1 -1
- package/src/anchors/hintsCodec.ts +1 -1
- package/src/pairing/diagnostics.ts +2 -2
- package/src/version.ts +1 -1
- package/vendor/core/LICENSE +76 -0
- package/vendor/core/README.md +9 -0
- package/vendor/core/dist/attributes.d.ts +16 -0
- package/vendor/core/dist/attributes.d.ts.map +1 -0
- package/vendor/core/dist/attributes.js +55 -0
- package/vendor/core/dist/attributes.js.map +1 -0
- package/vendor/core/dist/constants.d.ts +21 -0
- package/vendor/core/dist/constants.d.ts.map +1 -0
- package/vendor/core/dist/constants.js +21 -0
- package/vendor/core/dist/constants.js.map +1 -0
- package/vendor/core/dist/engine/ClientConditionEngine.d.ts +68 -0
- package/vendor/core/dist/engine/ClientConditionEngine.d.ts.map +1 -0
- package/vendor/core/dist/engine/ClientConditionEngine.js +197 -0
- package/vendor/core/dist/engine/ClientConditionEngine.js.map +1 -0
- package/vendor/core/dist/engine/FlowSessionEngine.d.ts +92 -0
- package/vendor/core/dist/engine/FlowSessionEngine.d.ts.map +1 -0
- package/vendor/core/dist/engine/FlowSessionEngine.js +310 -0
- package/vendor/core/dist/engine/FlowSessionEngine.js.map +1 -0
- package/vendor/core/dist/engine/PairingEngine.d.ts +92 -0
- package/vendor/core/dist/engine/PairingEngine.d.ts.map +1 -0
- package/vendor/core/dist/engine/PairingEngine.js +302 -0
- package/vendor/core/dist/engine/PairingEngine.js.map +1 -0
- package/vendor/core/dist/engine/UserflowCore.d.ts +126 -0
- package/vendor/core/dist/engine/UserflowCore.d.ts.map +1 -0
- package/vendor/core/dist/engine/UserflowCore.js +266 -0
- package/vendor/core/dist/engine/UserflowCore.js.map +1 -0
- package/vendor/core/dist/engine/handleActions.d.ts +19 -0
- package/vendor/core/dist/engine/handleActions.d.ts.map +1 -0
- package/vendor/core/dist/engine/handleActions.js +71 -0
- package/vendor/core/dist/engine/handleActions.js.map +1 -0
- package/vendor/core/dist/engine/interpolateSessionData.d.ts +7 -0
- package/vendor/core/dist/engine/interpolateSessionData.d.ts.map +1 -0
- package/vendor/core/dist/engine/interpolateSessionData.js +29 -0
- package/vendor/core/dist/engine/interpolateSessionData.js.map +1 -0
- package/vendor/core/dist/errors.d.ts +9 -0
- package/vendor/core/dist/errors.d.ts.map +1 -0
- package/vendor/core/dist/errors.js +15 -0
- package/vendor/core/dist/errors.js.map +1 -0
- package/vendor/core/dist/eventAttributes.d.ts +7 -0
- package/vendor/core/dist/eventAttributes.d.ts.map +1 -0
- package/vendor/core/dist/eventAttributes.js +31 -0
- package/vendor/core/dist/eventAttributes.js.map +1 -0
- package/vendor/core/dist/index.d.ts +30 -0
- package/vendor/core/dist/index.d.ts.map +1 -0
- package/vendor/core/dist/index.js +21 -0
- package/vendor/core/dist/index.js.map +1 -0
- package/vendor/core/dist/transport/backoff.d.ts +11 -0
- package/vendor/core/dist/transport/backoff.d.ts.map +1 -0
- package/vendor/core/dist/transport/backoff.js +17 -0
- package/vendor/core/dist/transport/backoff.js.map +1 -0
- package/vendor/core/dist/transport/pairing.d.ts +121 -0
- package/vendor/core/dist/transport/pairing.d.ts.map +1 -0
- package/vendor/core/dist/transport/pairing.js +551 -0
- package/vendor/core/dist/transport/pairing.js.map +1 -0
- package/vendor/core/dist/transport/phoenix.d.ts +223 -0
- package/vendor/core/dist/transport/phoenix.d.ts.map +1 -0
- package/vendor/core/dist/transport/phoenix.js +757 -0
- package/vendor/core/dist/transport/phoenix.js.map +1 -0
- package/vendor/core/dist/transport/rateLimiter.d.ts +17 -0
- package/vendor/core/dist/transport/rateLimiter.d.ts.map +1 -0
- package/vendor/core/dist/transport/rateLimiter.js +30 -0
- package/vendor/core/dist/transport/rateLimiter.js.map +1 -0
- package/vendor/core/dist/transport/scheduler.d.ts +12 -0
- package/vendor/core/dist/transport/scheduler.d.ts.map +1 -0
- package/vendor/core/dist/transport/scheduler.js +11 -0
- package/vendor/core/dist/transport/scheduler.js.map +1 -0
- package/vendor/core/dist/types.d.ts +35 -0
- package/vendor/core/dist/types.d.ts.map +1 -0
- package/vendor/core/dist/types.js +2 -0
- package/vendor/core/dist/types.js.map +1 -0
- package/vendor/core/dist/version.d.ts +3 -0
- package/vendor/core/dist/version.d.ts.map +1 -0
- package/vendor/core/dist/version.js +3 -0
- package/vendor/core/dist/version.js.map +1 -0
- package/vendor/core/package.json +20 -0
- package/vendor/protocol/LICENSE +76 -0
- package/vendor/protocol/README.md +8 -0
- package/vendor/protocol/dist/autoData.d.ts +232 -0
- package/vendor/protocol/dist/autoData.d.ts.map +1 -0
- package/vendor/protocol/dist/autoData.js +78 -0
- package/vendor/protocol/dist/autoData.js.map +1 -0
- package/vendor/protocol/dist/events.d.ts +16 -0
- package/vendor/protocol/dist/events.d.ts.map +1 -0
- package/vendor/protocol/dist/events.js +8 -0
- package/vendor/protocol/dist/events.js.map +1 -0
- package/vendor/protocol/dist/flows.d.ts +298 -0
- package/vendor/protocol/dist/flows.d.ts.map +1 -0
- package/vendor/protocol/dist/flows.js +154 -0
- package/vendor/protocol/dist/flows.js.map +1 -0
- package/vendor/protocol/dist/index.d.ts +24 -0
- package/vendor/protocol/dist/index.d.ts.map +1 -0
- package/vendor/protocol/dist/index.js +16 -0
- package/vendor/protocol/dist/index.js.map +1 -0
- package/vendor/protocol/dist/messages.d.ts +166 -0
- package/vendor/protocol/dist/messages.d.ts.map +1 -0
- package/vendor/protocol/dist/messages.js +57 -0
- package/vendor/protocol/dist/messages.js.map +1 -0
- package/vendor/protocol/dist/pairing.d.ts +56 -0
- package/vendor/protocol/dist/pairing.d.ts.map +1 -0
- package/vendor/protocol/dist/pairing.js +146 -0
- package/vendor/protocol/dist/pairing.js.map +1 -0
- package/vendor/protocol/package.json +17 -0
|
@@ -85,7 +85,7 @@ export function pairingForeignSchemeMessage(url: string): string {
|
|
|
85
85
|
`link, but it was opened with a scheme Userflow does not own. Use your ` +
|
|
86
86
|
`environment's scheme_id ("userflow-" followed by digits) exactly as the ` +
|
|
87
87
|
`pairing QR code provides it — do not substitute your app's own scheme. ` +
|
|
88
|
-
`Register it via the @userflow-tech/
|
|
88
|
+
`Register it via the @userflow-tech/react-native plugin ({ schemeId: 'userflow-…' }) and ` +
|
|
89
89
|
`rebuild the native app; a Metro reload is not enough.`
|
|
90
90
|
);
|
|
91
91
|
}
|
|
@@ -130,6 +130,6 @@ export function pairingSchemeShapeMessage(url: string): string {
|
|
|
130
130
|
return (
|
|
131
131
|
`${PREFIX} Ignoring Builder pairing link "${redactPairingToken(url)}": the scheme must be your ` +
|
|
132
132
|
`environment's scheme_id — "userflow-" followed by digits (e.g. userflow-257587). ` +
|
|
133
|
-
`Check the schemeId passed to the @userflow-tech/
|
|
133
|
+
`Check the schemeId passed to the @userflow-tech/react-native plugin.`
|
|
134
134
|
);
|
|
135
135
|
}
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Generated by scripts/write-version.mjs — do not edit. */
|
|
2
|
-
export const SDK_VERSION = '0.1.
|
|
2
|
+
export const SDK_VERSION = '0.1.1';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Userflow React Native SDK
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Userflow Inc. All rights reserved.
|
|
4
|
+
|
|
5
|
+
PROPRIETARY AND CONFIDENTIAL
|
|
6
|
+
|
|
7
|
+
This software and its source code (the "Software") are the proprietary and
|
|
8
|
+
confidential property of Userflow Inc. ("Userflow"). The Software is licensed,
|
|
9
|
+
not sold.
|
|
10
|
+
|
|
11
|
+
1. Grant of License
|
|
12
|
+
|
|
13
|
+
Use of the Software is permitted only by parties who have entered into a
|
|
14
|
+
written agreement with Userflow that expressly covers the Software (the
|
|
15
|
+
"Agreement"), and only for the duration, purposes, and scope set out in
|
|
16
|
+
that Agreement. Where the Software is provided for evaluation or as part
|
|
17
|
+
of an early-access or design-partner program, use is limited to internal
|
|
18
|
+
evaluation and integration testing unless the Agreement states otherwise.
|
|
19
|
+
|
|
20
|
+
If you have not entered into such an Agreement with Userflow, you are
|
|
21
|
+
granted no rights to use, copy, modify, or distribute the Software.
|
|
22
|
+
|
|
23
|
+
2. Restrictions
|
|
24
|
+
|
|
25
|
+
Except as expressly permitted by the Agreement or by applicable law, you
|
|
26
|
+
may not:
|
|
27
|
+
|
|
28
|
+
(a) redistribute, sublicense, sell, rent, lease, or otherwise transfer the
|
|
29
|
+
Software or any portion of it to any third party, except that you may
|
|
30
|
+
ship the Software in compiled or bundled form as an integral part of
|
|
31
|
+
your own applications distributed to your end users, provided you do
|
|
32
|
+
not redistribute the Software as a standalone library or SDK;
|
|
33
|
+
(b) modify or create derivative works of the Software, except for
|
|
34
|
+
automated transformations performed by ordinary build tooling
|
|
35
|
+
(including transpilation, bundling, minification, tree-shaking, and
|
|
36
|
+
source-map generation) and other modifications reasonably necessary
|
|
37
|
+
to integrate the Software into your applications, provided that any
|
|
38
|
+
such modifications remain subject to this notice;
|
|
39
|
+
(c) remove or obscure any copyright, trademark, or other proprietary
|
|
40
|
+
notices contained in the Software;
|
|
41
|
+
(d) disclose the Software's source code to any third party, except to your
|
|
42
|
+
employees and contractors who need access for a purpose permitted by
|
|
43
|
+
the Agreement and who are bound by written confidentiality
|
|
44
|
+
obligations no less protective than those in the Agreement.
|
|
45
|
+
|
|
46
|
+
3. Pre-Release Software
|
|
47
|
+
|
|
48
|
+
The Software may be provided prior to general availability. It may be
|
|
49
|
+
incomplete, may change without notice, and may not be backward compatible
|
|
50
|
+
between versions. Userflow is under no obligation to provide maintenance,
|
|
51
|
+
support, updates, or future releases except as set out in the Agreement.
|
|
52
|
+
|
|
53
|
+
4. No Warranty
|
|
54
|
+
|
|
55
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
56
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
57
|
+
FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
|
|
58
|
+
|
|
59
|
+
5. Limitation of Liability
|
|
60
|
+
|
|
61
|
+
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
|
|
62
|
+
USERFLOW BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN
|
|
63
|
+
AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN
|
|
64
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
65
|
+
|
|
66
|
+
6. Precedence
|
|
67
|
+
|
|
68
|
+
In the event of a conflict between this notice and the Agreement, the
|
|
69
|
+
Agreement governs.
|
|
70
|
+
|
|
71
|
+
For licensing enquiries, contact:
|
|
72
|
+
|
|
73
|
+
Userflow Inc.
|
|
74
|
+
548 Market St PMB 69598
|
|
75
|
+
San Francisco, CA 94104-5401
|
|
76
|
+
United States
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# `@userflow-tech/core`
|
|
2
|
+
|
|
3
|
+
Platform-agnostic engine for the Userflow React Native SDK (transport, identity,
|
|
4
|
+
flow session, client conditions).
|
|
5
|
+
|
|
6
|
+
**This package is an implementation detail and is not published.** It is
|
|
7
|
+
vendored into `@userflow-tech/react-native` at pack time. Host apps should
|
|
8
|
+
depend on that package only. Do not import `@userflow-tech/core` from
|
|
9
|
+
application code.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { UserflowAttributes } from '@userflow-tech/protocol';
|
|
2
|
+
/** Attribute scope used when validating names. Matches backend scopes. */
|
|
3
|
+
export type AttributeScope = 'user' | 'group' | 'group_membership' | 'event';
|
|
4
|
+
/** Keep in sync with `Flows.validate_attribute_name` / `validateAttributeDefinitionName`. */
|
|
5
|
+
export declare const MAX_ATTRIBUTE_NAME_LENGTH = 100;
|
|
6
|
+
/** Keep in sync with `Flows.validate_event_name` max length. */
|
|
7
|
+
export declare const MAX_EVENT_NAME_LENGTH = 255;
|
|
8
|
+
/** Returns true when `name` only contains supported attribute name characters. */
|
|
9
|
+
export declare function isAttributeNameSoftValid(name: string): boolean;
|
|
10
|
+
/** Returns an error message when invalid, or `null` when the name is allowed. */
|
|
11
|
+
export declare function validateAttributeName(scope: AttributeScope, name: string): string | null;
|
|
12
|
+
/** Throws when any attribute name is invalid for the given scope. */
|
|
13
|
+
export declare function assertValidAttributeNames(scope: AttributeScope, attributes: UserflowAttributes): void;
|
|
14
|
+
/** Throws when the custom event name is invalid. */
|
|
15
|
+
export declare function assertValidEventName(name: string): void;
|
|
16
|
+
//# sourceMappingURL=attributes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAIlE,0EAA0E;AAC1E,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,kBAAkB,GAAG,OAAO,CAAC;AAE7E,6FAA6F;AAC7F,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,gEAAgE;AAChE,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAczC,kFAAkF;AAClF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAcxF;AAED,qEAAqE;AACrE,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,cAAc,EACrB,UAAU,EAAE,kBAAkB,GAC7B,IAAI,CAQN;AAED,oDAAoD;AACpD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAcvD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { UserflowAuthError } from './errors.js';
|
|
2
|
+
/** Keep in sync with `Flows.validate_attribute_name` / `validateAttributeDefinitionName`. */
|
|
3
|
+
export const MAX_ATTRIBUTE_NAME_LENGTH = 100;
|
|
4
|
+
/** Keep in sync with `Flows.validate_event_name` max length. */
|
|
5
|
+
export const MAX_EVENT_NAME_LENGTH = 255;
|
|
6
|
+
const ATTRIBUTE_NAME_PATTERN = /^[a-z0-9_ :|#()-]+$/i;
|
|
7
|
+
/** Matches Userflow docs / web SDK event naming rules (subset of backend validator). */
|
|
8
|
+
const EVENT_NAME_PATTERN = /^[a-z0-9_ \-.()]+$/i;
|
|
9
|
+
const RESERVED_ATTRIBUTE_NAMES = {
|
|
10
|
+
user: ['id', 'groups', 'traits'],
|
|
11
|
+
event: [],
|
|
12
|
+
group: [],
|
|
13
|
+
group_membership: [],
|
|
14
|
+
};
|
|
15
|
+
/** Returns true when `name` only contains supported attribute name characters. */
|
|
16
|
+
export function isAttributeNameSoftValid(name) {
|
|
17
|
+
return typeof name === 'string' && ATTRIBUTE_NAME_PATTERN.test(name);
|
|
18
|
+
}
|
|
19
|
+
/** Returns an error message when invalid, or `null` when the name is allowed. */
|
|
20
|
+
export function validateAttributeName(scope, name) {
|
|
21
|
+
if (!isAttributeNameSoftValid(name)) {
|
|
22
|
+
return `${name}: Invalid attribute name. Attribute names must consist of only a-z, A-Z, 0-9, underscores, dashes, colons, vertical lines (|), hash signs (#), parentheses and spaces.`;
|
|
23
|
+
}
|
|
24
|
+
if (name.length > MAX_ATTRIBUTE_NAME_LENGTH) {
|
|
25
|
+
return `${name}: Attribute names must not be longer than ${MAX_ATTRIBUTE_NAME_LENGTH} characters.`;
|
|
26
|
+
}
|
|
27
|
+
if (RESERVED_ATTRIBUTE_NAMES[scope].includes(name)) {
|
|
28
|
+
return `${name}: Is a reserved name and cannot be used for attributes.`;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
/** Throws when any attribute name is invalid for the given scope. */
|
|
33
|
+
export function assertValidAttributeNames(scope, attributes) {
|
|
34
|
+
for (const name of Object.keys(attributes)) {
|
|
35
|
+
if (!Object.prototype.hasOwnProperty.call(attributes, name))
|
|
36
|
+
continue;
|
|
37
|
+
const error = validateAttributeName(scope, name);
|
|
38
|
+
if (error) {
|
|
39
|
+
throw new UserflowAuthError(error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Throws when the custom event name is invalid. */
|
|
44
|
+
export function assertValidEventName(name) {
|
|
45
|
+
if (!name) {
|
|
46
|
+
throw new UserflowAuthError('Missing name');
|
|
47
|
+
}
|
|
48
|
+
if (!EVENT_NAME_PATTERN.test(name)) {
|
|
49
|
+
throw new UserflowAuthError('Invalid event name. Event names must consist of only a-z, A-Z, 0-9, underscores, dashes, periods(.), parentheses and spaces.');
|
|
50
|
+
}
|
|
51
|
+
if (name.length > MAX_EVENT_NAME_LENGTH) {
|
|
52
|
+
throw new UserflowAuthError(`Event names must not be longer than ${MAX_EVENT_NAME_LENGTH} characters.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=attributes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attributes.js","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKhD,6FAA6F;AAC7F,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAE7C,gEAAgE;AAChE,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC,MAAM,sBAAsB,GAAG,sBAAsB,CAAC;AAEtD,wFAAwF;AACxF,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AAEjD,MAAM,wBAAwB,GAAwD;IACpF,IAAI,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC;IAChC,KAAK,EAAE,EAAE;IACT,KAAK,EAAE,EAAE;IACT,gBAAgB,EAAE,EAAE;CACrB,CAAC;AAEF,kFAAkF;AAClF,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvE,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,qBAAqB,CAAC,KAAqB,EAAE,IAAY;IACvE,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,OAAO,GAAG,IAAI,wKAAwK,CAAC;IACzL,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,GAAG,yBAAyB,EAAE,CAAC;QAC5C,OAAO,GAAG,IAAI,6CAA6C,yBAAyB,cAAc,CAAC;IACrG,CAAC;IAED,IAAI,wBAAwB,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,GAAG,IAAI,yDAAyD,CAAC;IAC1E,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,yBAAyB,CACvC,KAAqB,EACrB,UAA8B;IAE9B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC;YAAE,SAAS;QACtE,MAAM,KAAK,GAAG,qBAAqB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACjD,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;AACH,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,iBAAiB,CACzB,8HAA8H,CAC/H,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,GAAG,qBAAqB,EAAE,CAAC;QACxC,MAAM,IAAI,iBAAiB,CACzB,uCAAuC,qBAAqB,cAAc,CAC3E,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default backend endpoint used when a host app does not pass an explicit
|
|
3
|
+
* `serverEndpoint` to `init()`. Points at Userflow production.
|
|
4
|
+
*
|
|
5
|
+
* For local development against the Userflow dev stack, pass the local endpoint
|
|
6
|
+
* explicitly, e.g. `init({ ..., serverEndpoint: 'http://localhost:40401' })`.
|
|
7
|
+
*
|
|
8
|
+
* TODO(publish): production server-driven `Publish` delivery for mobile is not
|
|
9
|
+
* wired yet (only the Preview/dev-device path is validated). Revisit this
|
|
10
|
+
* default and the transport once Publish lands.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_SERVER_ENDPOINT = "https://e.userflow.com";
|
|
13
|
+
/**
|
|
14
|
+
* US-pinned host for the Builder pairing websocket (`/socket/pairing`).
|
|
15
|
+
* The builder dashboard and pairing PubSub are US-only; do not use a regional
|
|
16
|
+
* `serverEndpoint` for pairing.
|
|
17
|
+
*
|
|
18
|
+
* Override via {@link PairingConnection} options for local/staging stacks.
|
|
19
|
+
*/
|
|
20
|
+
export declare const DEFAULT_PAIRING_ENDPOINT = "https://e.userflow.com";
|
|
21
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,2BAA2B,CAAC;AAEhE;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default backend endpoint used when a host app does not pass an explicit
|
|
3
|
+
* `serverEndpoint` to `init()`. Points at Userflow production.
|
|
4
|
+
*
|
|
5
|
+
* For local development against the Userflow dev stack, pass the local endpoint
|
|
6
|
+
* explicitly, e.g. `init({ ..., serverEndpoint: 'http://localhost:40401' })`.
|
|
7
|
+
*
|
|
8
|
+
* TODO(publish): production server-driven `Publish` delivery for mobile is not
|
|
9
|
+
* wired yet (only the Preview/dev-device path is validated). Revisit this
|
|
10
|
+
* default and the transport once Publish lands.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_SERVER_ENDPOINT = 'https://e.userflow.com';
|
|
13
|
+
/**
|
|
14
|
+
* US-pinned host for the Builder pairing websocket (`/socket/pairing`).
|
|
15
|
+
* The builder dashboard and pairing PubSub are US-only; do not use a regional
|
|
16
|
+
* `serverEndpoint` for pairing.
|
|
17
|
+
*
|
|
18
|
+
* Override via {@link PairingConnection} options for local/staging stacks.
|
|
19
|
+
*/
|
|
20
|
+
export const DEFAULT_PAIRING_ENDPOINT = 'https://e.userflow.com';
|
|
21
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,wBAAwB,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ClientMessage, FlowConditionFragment, FlowConditionType, JoinPayloadClientCondition, ServerMessage } from '@userflow-tech/protocol';
|
|
2
|
+
import { type Scheduler } from '../transport/scheduler.js';
|
|
3
|
+
/** Narrow transport surface the client-condition engine depends on. */
|
|
4
|
+
export interface ClientConditionTransport {
|
|
5
|
+
send(message: ClientMessage): Promise<void>;
|
|
6
|
+
onServerMessage(handler: (message: ServerMessage) => void): () => void;
|
|
7
|
+
setClientConditions(clientConditions: JoinPayloadClientCondition[]): void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Platform-specific evaluator for one condition type. Calls `report` whenever
|
|
11
|
+
* truthiness changes (including the initial evaluation). Returns an untrack
|
|
12
|
+
* function that tears down listeners. `null` means "unknown / cannot evaluate".
|
|
13
|
+
*/
|
|
14
|
+
export type ConditionEvaluator = (condition: FlowConditionFragment, report: (isTrue: boolean | null) => void) => () => void;
|
|
15
|
+
export interface ClientConditionEngineDeps {
|
|
16
|
+
transport: ClientConditionTransport;
|
|
17
|
+
/** Per-type evaluators. Types without an entry stay unknown and warn once. */
|
|
18
|
+
evaluators?: Partial<Record<FlowConditionType, ConditionEvaluator>>;
|
|
19
|
+
warn?: (message: string) => void;
|
|
20
|
+
scheduler?: Scheduler;
|
|
21
|
+
/** Override the ToggleClientCondition debounce window (tests). */
|
|
22
|
+
reportDebounceMs?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Framework-agnostic client-condition state machine.
|
|
26
|
+
*
|
|
27
|
+
* Mirrors web `userflow-client` TrackClientCondition / UntrackClientCondition /
|
|
28
|
+
* ToggleClientCondition semantics: starts each condition at `isTrue: null`
|
|
29
|
+
* (unknown), reports transitions via ToggleClientCondition, and seeds the
|
|
30
|
+
* join payload snapshot so reconnects do not lose tracked state.
|
|
31
|
+
*
|
|
32
|
+
* Call {@link attach} after identify. Re-attach rebinds evaluators for any
|
|
33
|
+
* conditions still in the map (so identify → identify does not freeze tracking).
|
|
34
|
+
*/
|
|
35
|
+
export declare class ClientConditionEngine {
|
|
36
|
+
private readonly transport;
|
|
37
|
+
private readonly evaluators;
|
|
38
|
+
private readonly warn;
|
|
39
|
+
private readonly scheduler;
|
|
40
|
+
private readonly reportDebounceMs;
|
|
41
|
+
private readonly conditions;
|
|
42
|
+
private unsubscribeServerMessages;
|
|
43
|
+
constructor(deps: ClientConditionEngineDeps);
|
|
44
|
+
/**
|
|
45
|
+
* Subscribe to inbound server messages and (re)bind evaluators for any
|
|
46
|
+
* conditions still in the map. Must be called after identify.
|
|
47
|
+
*/
|
|
48
|
+
attach(): () => void;
|
|
49
|
+
/**
|
|
50
|
+
* Unsubscribe from server messages and stop evaluators, but keep the
|
|
51
|
+
* condition map so a later attach can resume (rebind evaluators + snapshot).
|
|
52
|
+
*/
|
|
53
|
+
detach(): void;
|
|
54
|
+
/** Tear down all tracked conditions and clear the join snapshot. */
|
|
55
|
+
reset(): void;
|
|
56
|
+
/** Current join-payload snapshot (including `isTrue: null` unknowns). */
|
|
57
|
+
getSnapshot(): JoinPayloadClientCondition[];
|
|
58
|
+
private handleServerMessage;
|
|
59
|
+
private trackClientCondition;
|
|
60
|
+
private untrackClientCondition;
|
|
61
|
+
private rebindEvaluators;
|
|
62
|
+
private bindEvaluator;
|
|
63
|
+
private report;
|
|
64
|
+
private sendToggle;
|
|
65
|
+
private pushSnapshot;
|
|
66
|
+
private clearDebounce;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=ClientConditionEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClientConditionEngine.d.ts","sourceRoot":"","sources":["../../src/engine/ClientConditionEngine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,0BAA0B,EAC1B,aAAa,EACd,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAoB,KAAK,SAAS,EAAoB,MAAM,2BAA2B,CAAC;AAK/F,uEAAuE;AACvE,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,eAAe,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACvE,mBAAmB,CAAC,gBAAgB,EAAE,0BAA0B,EAAE,GAAG,IAAI,CAAC;CAC3E;AAED;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,SAAS,EAAE,qBAAqB,EAChC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,KACrC,MAAM,IAAI,CAAC;AAEhB,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,wBAAwB,CAAC;IACpC,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAWD;;;;;;;;;;GAUG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IACrD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyD;IACpF,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4B;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAE1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0C;IACrE,OAAO,CAAC,yBAAyB,CAA6B;gBAElD,IAAI,EAAE,yBAAyB;IAQ3C;;;OAGG;IACH,MAAM,IAAI,MAAM,IAAI;IAapB;;;OAGG;IACH,MAAM,IAAI,IAAI;IAWd,oEAAoE;IACpE,KAAK,IAAI,IAAI;IASb,yEAAyE;IACzE,WAAW,IAAI,0BAA0B,EAAE;IAO3C,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,sBAAsB;IAS9B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,aAAa;IAqBrB,OAAO,CAAC,MAAM;IA+Cd,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,aAAa;CAMtB"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { defaultScheduler } from '../transport/scheduler.js';
|
|
2
|
+
/** Cap for coalescing rapid truthiness flips before sending ToggleClientCondition. */
|
|
3
|
+
const REPORT_DEBOUNCE_MS = 250;
|
|
4
|
+
/**
|
|
5
|
+
* Framework-agnostic client-condition state machine.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors web `userflow-client` TrackClientCondition / UntrackClientCondition /
|
|
8
|
+
* ToggleClientCondition semantics: starts each condition at `isTrue: null`
|
|
9
|
+
* (unknown), reports transitions via ToggleClientCondition, and seeds the
|
|
10
|
+
* join payload snapshot so reconnects do not lose tracked state.
|
|
11
|
+
*
|
|
12
|
+
* Call {@link attach} after identify. Re-attach rebinds evaluators for any
|
|
13
|
+
* conditions still in the map (so identify → identify does not freeze tracking).
|
|
14
|
+
*/
|
|
15
|
+
export class ClientConditionEngine {
|
|
16
|
+
constructor(deps) {
|
|
17
|
+
this.conditions = new Map();
|
|
18
|
+
this.unsubscribeServerMessages = null;
|
|
19
|
+
this.transport = deps.transport;
|
|
20
|
+
this.evaluators = deps.evaluators ?? {};
|
|
21
|
+
this.warn = deps.warn ?? ((message) => console.warn(message));
|
|
22
|
+
this.scheduler = deps.scheduler ?? defaultScheduler;
|
|
23
|
+
this.reportDebounceMs = deps.reportDebounceMs ?? REPORT_DEBOUNCE_MS;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Subscribe to inbound server messages and (re)bind evaluators for any
|
|
27
|
+
* conditions still in the map. Must be called after identify.
|
|
28
|
+
*/
|
|
29
|
+
attach() {
|
|
30
|
+
this.detach();
|
|
31
|
+
this.unsubscribeServerMessages = this.transport.onServerMessage((message) => {
|
|
32
|
+
this.handleServerMessage(message);
|
|
33
|
+
});
|
|
34
|
+
// Rebind after detach so a second identify/attach keeps live evaluation
|
|
35
|
+
// even when the server skips TrackClientCondition (join snapshot already
|
|
36
|
+
// lists these IDs as tracked).
|
|
37
|
+
this.rebindEvaluators();
|
|
38
|
+
this.pushSnapshot();
|
|
39
|
+
return () => this.detach();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Unsubscribe from server messages and stop evaluators, but keep the
|
|
43
|
+
* condition map so a later attach can resume (rebind evaluators + snapshot).
|
|
44
|
+
*/
|
|
45
|
+
detach() {
|
|
46
|
+
this.unsubscribeServerMessages?.();
|
|
47
|
+
this.unsubscribeServerMessages = null;
|
|
48
|
+
for (const meta of this.conditions.values()) {
|
|
49
|
+
this.clearDebounce(meta);
|
|
50
|
+
meta.pendingReport = undefined;
|
|
51
|
+
meta.untrack?.();
|
|
52
|
+
delete meta.untrack;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Tear down all tracked conditions and clear the join snapshot. */
|
|
56
|
+
reset() {
|
|
57
|
+
const ids = [...this.conditions.keys()];
|
|
58
|
+
for (const id of ids) {
|
|
59
|
+
this.untrackClientCondition(id);
|
|
60
|
+
}
|
|
61
|
+
this.detach();
|
|
62
|
+
this.pushSnapshot();
|
|
63
|
+
}
|
|
64
|
+
/** Current join-payload snapshot (including `isTrue: null` unknowns). */
|
|
65
|
+
getSnapshot() {
|
|
66
|
+
return Array.from(this.conditions.values()).map((meta) => ({
|
|
67
|
+
conditionId: meta.condition.id,
|
|
68
|
+
isTrue: meta.isTrue,
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
handleServerMessage(message) {
|
|
72
|
+
switch (message.kind) {
|
|
73
|
+
case 'TrackClientCondition':
|
|
74
|
+
this.trackClientCondition(message.condition, message.flowId);
|
|
75
|
+
return;
|
|
76
|
+
case 'UntrackClientCondition':
|
|
77
|
+
this.untrackClientCondition(message.conditionId);
|
|
78
|
+
return;
|
|
79
|
+
default:
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
trackClientCondition(condition, flowId) {
|
|
84
|
+
if (this.conditions.has(condition.id)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const meta = {
|
|
88
|
+
condition,
|
|
89
|
+
flowId,
|
|
90
|
+
isTrue: null,
|
|
91
|
+
pendingReport: undefined,
|
|
92
|
+
debounceHandle: null,
|
|
93
|
+
};
|
|
94
|
+
this.conditions.set(condition.id, meta);
|
|
95
|
+
this.pushSnapshot();
|
|
96
|
+
this.bindEvaluator(meta, { warnIfMissing: true });
|
|
97
|
+
}
|
|
98
|
+
untrackClientCondition(conditionId) {
|
|
99
|
+
const meta = this.conditions.get(conditionId);
|
|
100
|
+
if (!meta)
|
|
101
|
+
return;
|
|
102
|
+
this.clearDebounce(meta);
|
|
103
|
+
meta.untrack?.();
|
|
104
|
+
this.conditions.delete(conditionId);
|
|
105
|
+
this.pushSnapshot();
|
|
106
|
+
}
|
|
107
|
+
rebindEvaluators() {
|
|
108
|
+
for (const meta of this.conditions.values()) {
|
|
109
|
+
this.bindEvaluator(meta, { warnIfMissing: false });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
bindEvaluator(meta, options) {
|
|
113
|
+
meta.untrack?.();
|
|
114
|
+
delete meta.untrack;
|
|
115
|
+
const evaluator = this.evaluators[meta.condition.type];
|
|
116
|
+
if (!evaluator) {
|
|
117
|
+
if (options.warnIfMissing) {
|
|
118
|
+
this.warn(`Userflow: cannot evaluate client condition type "${meta.condition.type}" ` +
|
|
119
|
+
`for flow "${meta.flowId}" (condition ${meta.condition.id}); leaving unknown so ` +
|
|
120
|
+
'the gated flow will not start until this type is supported');
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
meta.untrack = evaluator(meta.condition, (isTrue) => {
|
|
125
|
+
this.report(meta.condition.id, isTrue);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
report(conditionId, isTrue) {
|
|
129
|
+
const meta = this.conditions.get(conditionId);
|
|
130
|
+
if (!meta)
|
|
131
|
+
return;
|
|
132
|
+
if (isTrue === null) {
|
|
133
|
+
// Evaluator cannot decide — stay unknown and never send Toggle.
|
|
134
|
+
// (Specific why-warnings belong to the evaluator; missing-evaluator
|
|
135
|
+
// warnings are emitted at track time.)
|
|
136
|
+
this.clearDebounce(meta);
|
|
137
|
+
meta.pendingReport = undefined;
|
|
138
|
+
if (meta.isTrue !== null) {
|
|
139
|
+
meta.isTrue = null;
|
|
140
|
+
this.pushSnapshot();
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (meta.isTrue === isTrue && meta.pendingReport === undefined) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
// First resolution from unknown: send immediately so gated flows are not
|
|
148
|
+
// delayed by the remount-churn debounce.
|
|
149
|
+
if (meta.isTrue === null) {
|
|
150
|
+
this.clearDebounce(meta);
|
|
151
|
+
meta.pendingReport = undefined;
|
|
152
|
+
meta.isTrue = isTrue;
|
|
153
|
+
this.pushSnapshot();
|
|
154
|
+
this.sendToggle(conditionId, isTrue);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// Subsequent flips: trailing debounce to absorb anchor remount churn.
|
|
158
|
+
meta.pendingReport = isTrue;
|
|
159
|
+
this.clearDebounce(meta);
|
|
160
|
+
meta.debounceHandle = this.scheduler.setTimeout(() => {
|
|
161
|
+
meta.debounceHandle = null;
|
|
162
|
+
const next = meta.pendingReport;
|
|
163
|
+
meta.pendingReport = undefined;
|
|
164
|
+
if (next === undefined)
|
|
165
|
+
return;
|
|
166
|
+
if (meta.isTrue === next)
|
|
167
|
+
return;
|
|
168
|
+
meta.isTrue = next;
|
|
169
|
+
this.pushSnapshot();
|
|
170
|
+
this.sendToggle(conditionId, next);
|
|
171
|
+
}, this.reportDebounceMs);
|
|
172
|
+
}
|
|
173
|
+
sendToggle(conditionId, isTrue) {
|
|
174
|
+
// Swallow send failures (e.g. not joined). The value is already in the
|
|
175
|
+
// join-payload snapshot, so reconnect will re-seed the server without loss.
|
|
176
|
+
// ToggleClientCondition is rate-limit-exempt on the transport (web parity).
|
|
177
|
+
void this.transport
|
|
178
|
+
.send({
|
|
179
|
+
kind: 'ToggleClientCondition',
|
|
180
|
+
conditionId,
|
|
181
|
+
isTrue,
|
|
182
|
+
})
|
|
183
|
+
.catch(() => {
|
|
184
|
+
// Intentionally empty — see comment above.
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
pushSnapshot() {
|
|
188
|
+
this.transport.setClientConditions(this.getSnapshot());
|
|
189
|
+
}
|
|
190
|
+
clearDebounce(meta) {
|
|
191
|
+
if (meta.debounceHandle !== null) {
|
|
192
|
+
this.scheduler.clearTimeout(meta.debounceHandle);
|
|
193
|
+
meta.debounceHandle = null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=ClientConditionEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClientConditionEngine.js","sourceRoot":"","sources":["../../src/engine/ClientConditionEngine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ClientMessage, FlowActionFragment, FlowSessionFragment, FlowStepFragment, ServerMessage } from '@userflow-tech/protocol';
|
|
2
|
+
import { EndFlowReasonInput } from '@userflow-tech/protocol';
|
|
3
|
+
import { type Scheduler } from '../transport/scheduler.js';
|
|
4
|
+
/** Narrow transport surface the flow session engine depends on. */
|
|
5
|
+
export interface FlowTransport {
|
|
6
|
+
send(message: ClientMessage): Promise<void>;
|
|
7
|
+
onServerMessage(handler: (message: ServerMessage) => void): () => void;
|
|
8
|
+
setFlowSessionId(flowSessionId: string | null): void;
|
|
9
|
+
}
|
|
10
|
+
export type FlowSessionEngineEvent = {
|
|
11
|
+
type: 'sessionChange';
|
|
12
|
+
session: FlowSessionFragment | null;
|
|
13
|
+
} | {
|
|
14
|
+
type: 'goToStep';
|
|
15
|
+
sessionId: string;
|
|
16
|
+
stepId: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'flowEnded';
|
|
19
|
+
flowId: string;
|
|
20
|
+
endReason: EndFlowReasonInput;
|
|
21
|
+
};
|
|
22
|
+
export type FlowSessionEngineListener = (event: FlowSessionEngineEvent) => void;
|
|
23
|
+
export interface FlowSessionEngineDeps {
|
|
24
|
+
transport: FlowTransport;
|
|
25
|
+
/** Open a URL for NAVIGATE actions (both SAME_TAB and NEW_TAB on mobile). */
|
|
26
|
+
onOpenExternalUrl?: (url: string) => void;
|
|
27
|
+
warn?: (message: string) => void;
|
|
28
|
+
scheduler?: Scheduler;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Framework-agnostic flow session state machine (Phase 3 WS2).
|
|
32
|
+
*
|
|
33
|
+
* Ports web `userflow-client` session/clock/wait-timer semantics onto the
|
|
34
|
+
* Phoenix transport seam. Call {@link attach} after identify.
|
|
35
|
+
*/
|
|
36
|
+
export declare class FlowSessionEngine {
|
|
37
|
+
private readonly transport;
|
|
38
|
+
private readonly onOpenExternalUrl;
|
|
39
|
+
private readonly warn;
|
|
40
|
+
private readonly scheduler;
|
|
41
|
+
private clientClock;
|
|
42
|
+
private serverClock;
|
|
43
|
+
private flowSessionClock;
|
|
44
|
+
private flowSession;
|
|
45
|
+
private readonly listeners;
|
|
46
|
+
private readonly conditionWaitTimers;
|
|
47
|
+
private readonly pendingSends;
|
|
48
|
+
private flushingPending;
|
|
49
|
+
private unsubscribeServerMessages;
|
|
50
|
+
constructor(deps: FlowSessionEngineDeps);
|
|
51
|
+
/** Subscribe to inbound server messages. Must be called after identify. */
|
|
52
|
+
attach(): () => void;
|
|
53
|
+
/**
|
|
54
|
+
* Unsubscribe from server messages and clear wait timers (keeps session state).
|
|
55
|
+
* Note: in-flight condition wait timers are dropped and not restarted on
|
|
56
|
+
* re-attach; the server must send StartConditionWaitTimer again if needed.
|
|
57
|
+
*/
|
|
58
|
+
detach(): void;
|
|
59
|
+
on(listener: FlowSessionEngineListener): () => void;
|
|
60
|
+
getFlowSession(): FlowSessionFragment | null;
|
|
61
|
+
getCurrentStep(): FlowStepFragment | null;
|
|
62
|
+
/** Visible for tests / advanced callers; prefer {@link attach}. */
|
|
63
|
+
handleServerMessage(message: ServerMessage): void;
|
|
64
|
+
goToStep(step: FlowStepFragment): Promise<void>;
|
|
65
|
+
endFlow(endReason: EndFlowReasonInput): Promise<void>;
|
|
66
|
+
reportTooltipTargetMissing(stepId: string): Promise<void>;
|
|
67
|
+
handleActions(actions: FlowActionFragment[]): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Clear the local flow session and join resume id without detaching from
|
|
70
|
+
* server messages. Used when a long background makes mid-flow resume stale.
|
|
71
|
+
*/
|
|
72
|
+
clearLocalSession(): void;
|
|
73
|
+
/** Clear session, clocks, timers, pending sends, and join resume id; detach from transport. */
|
|
74
|
+
reset(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Flush client messages queued after transport failure.
|
|
77
|
+
* Call after reconnect / lifecycle resume (`ensureConnected` path).
|
|
78
|
+
*/
|
|
79
|
+
flushPendingSends(): Promise<void>;
|
|
80
|
+
/** @internal Test helper. */
|
|
81
|
+
getPendingSendCountForTests(): number;
|
|
82
|
+
private setFlowSession;
|
|
83
|
+
private optimisticClockUIUpdate;
|
|
84
|
+
private enqueuePendingSend;
|
|
85
|
+
private sendTracked;
|
|
86
|
+
private startConditionWaitTimer;
|
|
87
|
+
private cancelConditionWaitTimer;
|
|
88
|
+
private clearConditionWaitTimers;
|
|
89
|
+
private requireFlowSession;
|
|
90
|
+
private emit;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=FlowSessionEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FlowSessionEngine.d.ts","sourceRoot":"","sources":["../../src/engine/FlowSessionEngine.ts"],"names":[],"mappings":"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"}
|