@capxul/sdk 0.1.0-alpha.6 → 0.1.0-alpha.9
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/CHANGELOG.md +15 -8
- package/README.md +86 -4
- package/dist/{client-ChfXWMzO.d.ts → client-ChZrdf3R.d.ts} +209 -15
- package/dist/{client-DW_fW9DC.d.cts → client-DG6ODWu6.d.cts} +209 -15
- package/dist/client.cjs +634 -36
- package/dist/client.d.cts +2 -3
- package/dist/client.d.ts +2 -3
- package/dist/client.js +634 -36
- package/dist/index.cjs +635 -36
- package/dist/index.d.cts +11 -33
- package/dist/index.d.ts +11 -33
- package/dist/index.js +635 -37
- package/dist/types-PM4AQRLP.d.ts +1136 -0
- package/dist/types-hfcOE7Oi.d.cts +1136 -0
- package/dist/webhooks.d.cts +1 -2
- package/dist/webhooks.d.ts +1 -2
- package/package.json +7 -7
- package/dist/types-CYvLP5pP.d.ts +0 -213
- package/dist/types-X02RbQ2u.d.cts +0 -213
package/dist/index.cjs
CHANGED
|
@@ -679,7 +679,12 @@ var Errors = {
|
|
|
679
679
|
"Idempotency key was already used for a different request",
|
|
680
680
|
{ details }
|
|
681
681
|
),
|
|
682
|
-
emailDeliveryFailed: (detail) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}
|
|
682
|
+
emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
683
|
+
details
|
|
684
|
+
}),
|
|
685
|
+
rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
|
|
686
|
+
details: { ...details }
|
|
687
|
+
}),
|
|
683
688
|
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
684
689
|
/**
|
|
685
690
|
* Verification gate. Surfaced when a request hits a verification
|
|
@@ -752,13 +757,13 @@ function createLifecycle(initial) {
|
|
|
752
757
|
}
|
|
753
758
|
function makeBuildTimeUrlsTransport(config) {
|
|
754
759
|
if (!config.authBaseUrl || config.authBaseUrl.trim().length === 0) {
|
|
755
|
-
throw
|
|
760
|
+
throw invalidConfigError(
|
|
756
761
|
"authBaseUrl",
|
|
757
762
|
"build-time-urls transport requires a non-empty authBaseUrl."
|
|
758
763
|
);
|
|
759
764
|
}
|
|
760
765
|
if (!config.convexUrl || config.convexUrl.trim().length === 0) {
|
|
761
|
-
throw
|
|
766
|
+
throw invalidConfigError(
|
|
762
767
|
"convexUrl",
|
|
763
768
|
"build-time-urls transport requires a non-empty convexUrl."
|
|
764
769
|
);
|
|
@@ -772,6 +777,7 @@ function makeBuildTimeUrlsTransport(config) {
|
|
|
772
777
|
return {
|
|
773
778
|
authBaseUrl,
|
|
774
779
|
convexUrl,
|
|
780
|
+
ensureRuntime: async () => runtime,
|
|
775
781
|
fetch: (path, init) => fetchImpl(resolveUrl(authBaseUrl, path), init),
|
|
776
782
|
getState: lifecycle.getState,
|
|
777
783
|
subscribe: lifecycle.subscribe,
|
|
@@ -787,14 +793,15 @@ function makeBuildTimeUrlsTransport(config) {
|
|
|
787
793
|
};
|
|
788
794
|
}
|
|
789
795
|
function makePublishableKeyTransport(config) {
|
|
790
|
-
|
|
791
|
-
|
|
796
|
+
const publishableKey = config.publishableKey?.trim();
|
|
797
|
+
if (!publishableKey) {
|
|
798
|
+
throw invalidConfigError(
|
|
792
799
|
"publishableKey",
|
|
793
800
|
"publishable-key transport requires a non-empty publishableKey."
|
|
794
801
|
);
|
|
795
802
|
}
|
|
796
803
|
const fetchImpl = config.fetchImpl ?? globalThis.fetch;
|
|
797
|
-
const bootstrapUrl =
|
|
804
|
+
const bootstrapUrl = normalizeBootstrapUrl(
|
|
798
805
|
config.bootstrapUrl ?? `${CAPXUL_API_BASE_URL}/v1/client/bootstrap`
|
|
799
806
|
);
|
|
800
807
|
let authBaseUrl = "";
|
|
@@ -809,23 +816,20 @@ function makePublishableKeyTransport(config) {
|
|
|
809
816
|
const response = await fetchImpl(bootstrapUrl, {
|
|
810
817
|
method: "POST",
|
|
811
818
|
headers: { "content-type": "application/json" },
|
|
812
|
-
body: JSON.stringify({ publishableKey
|
|
819
|
+
body: JSON.stringify({ publishableKey })
|
|
813
820
|
});
|
|
814
821
|
if (!response.ok) {
|
|
815
|
-
throw
|
|
816
|
-
"publishableKey",
|
|
817
|
-
`${bootstrapUrl} failed with HTTP ${response.status}.`
|
|
818
|
-
);
|
|
822
|
+
throw await bootstrapResponseError(response, bootstrapUrl);
|
|
819
823
|
}
|
|
820
|
-
const body = await response
|
|
824
|
+
const body = await readBootstrapSuccessBody(response);
|
|
821
825
|
if (typeof body.authBaseUrl !== "string" || body.authBaseUrl.trim().length === 0) {
|
|
822
|
-
throw
|
|
826
|
+
throw bootstrapContractError(
|
|
823
827
|
"authBaseUrl",
|
|
824
828
|
"/v1/client/bootstrap returned no authBaseUrl."
|
|
825
829
|
);
|
|
826
830
|
}
|
|
827
831
|
if (typeof body.convexUrl !== "string" || body.convexUrl.trim().length === 0) {
|
|
828
|
-
throw
|
|
832
|
+
throw bootstrapContractError(
|
|
829
833
|
"convexUrl",
|
|
830
834
|
"/v1/client/bootstrap returned no convexUrl."
|
|
831
835
|
);
|
|
@@ -837,16 +841,13 @@ function makePublishableKeyTransport(config) {
|
|
|
837
841
|
return runtime;
|
|
838
842
|
})();
|
|
839
843
|
bootstrapPromise = attempt.catch((err) => {
|
|
844
|
+
const error = normalizeBootstrapThrownError(err);
|
|
840
845
|
bootstrapPromise = null;
|
|
841
846
|
lifecycle.setState({
|
|
842
847
|
status: "error",
|
|
843
|
-
error
|
|
844
|
-
code: "UNKNOWN",
|
|
845
|
-
message: "Bootstrap failed without a typed CapxulError.",
|
|
846
|
-
cause: err
|
|
847
|
-
})
|
|
848
|
+
error
|
|
848
849
|
});
|
|
849
|
-
throw
|
|
850
|
+
throw error;
|
|
850
851
|
});
|
|
851
852
|
return await bootstrapPromise;
|
|
852
853
|
}
|
|
@@ -857,6 +858,7 @@ function makePublishableKeyTransport(config) {
|
|
|
857
858
|
get convexUrl() {
|
|
858
859
|
return convexUrl;
|
|
859
860
|
},
|
|
861
|
+
ensureRuntime: ensureBootstrap,
|
|
860
862
|
fetch: async (path, init) => {
|
|
861
863
|
const resolved = await ensureBootstrap();
|
|
862
864
|
return await fetchImpl(resolveUrl(resolved.authBaseUrl, path), init);
|
|
@@ -867,7 +869,7 @@ function makePublishableKeyTransport(config) {
|
|
|
867
869
|
markAuthenticated: ({ dataClient: nextDataClient }) => {
|
|
868
870
|
const current = lifecycle.getState();
|
|
869
871
|
if (current.status !== "ready" && current.status !== "authenticated") {
|
|
870
|
-
throw
|
|
872
|
+
throw internalTransportError(
|
|
871
873
|
`markAuthenticated() called from status="${current.status}". Expected "ready" or "authenticated".`
|
|
872
874
|
);
|
|
873
875
|
}
|
|
@@ -889,6 +891,24 @@ function makePublishableKeyTransport(config) {
|
|
|
889
891
|
function stripTrailingSlash(url) {
|
|
890
892
|
return url.replace(/\/+$/, "");
|
|
891
893
|
}
|
|
894
|
+
function normalizeBootstrapUrl(url) {
|
|
895
|
+
const normalized = stripTrailingSlash(url.trim());
|
|
896
|
+
if (!isAbsoluteHttpUrl(normalized)) {
|
|
897
|
+
throw invalidConfigError(
|
|
898
|
+
"bootstrapUrl",
|
|
899
|
+
"publishable-key transport requires an absolute http(s) bootstrapUrl."
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
return normalized;
|
|
903
|
+
}
|
|
904
|
+
function isAbsoluteHttpUrl(url) {
|
|
905
|
+
try {
|
|
906
|
+
const parsed = new URL(url);
|
|
907
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
908
|
+
} catch {
|
|
909
|
+
return false;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
892
912
|
function resolveUrl(authBaseUrl, path) {
|
|
893
913
|
if (path.startsWith("http://") || path.startsWith("https://")) {
|
|
894
914
|
return path;
|
|
@@ -896,10 +916,142 @@ function resolveUrl(authBaseUrl, path) {
|
|
|
896
916
|
return `${authBaseUrl}${path}`;
|
|
897
917
|
}
|
|
898
918
|
function assertNever(value) {
|
|
899
|
-
throw
|
|
919
|
+
throw internalTransportError(
|
|
900
920
|
`Unhandled BrowserCapxulConfig.mode: ${String(value.mode)}.`
|
|
901
921
|
);
|
|
902
922
|
}
|
|
923
|
+
function invalidConfigError(field, reason) {
|
|
924
|
+
return new CapxulError({
|
|
925
|
+
code: "INVALID_INPUT",
|
|
926
|
+
message: `Invalid ${field}: ${reason}`,
|
|
927
|
+
details: { source: "sdk-config", field, reason }
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
function bootstrapContractError(field, message) {
|
|
931
|
+
return new CapxulError({
|
|
932
|
+
code: "INVALID_INPUT",
|
|
933
|
+
message,
|
|
934
|
+
details: {
|
|
935
|
+
source: "backend-bootstrap",
|
|
936
|
+
phase: "publishable-key-bootstrap",
|
|
937
|
+
field,
|
|
938
|
+
reason: message
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
function internalTransportError(reason) {
|
|
943
|
+
return new CapxulError({
|
|
944
|
+
code: "INTERNAL_ERROR",
|
|
945
|
+
message: `Internal error: ${reason}`,
|
|
946
|
+
details: { source: "sdk-transport", reason }
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
async function bootstrapResponseError(response, bootstrapUrl) {
|
|
950
|
+
const envelope = await readBootstrapErrorEnvelope(response);
|
|
951
|
+
const wireCode = readNonEmptyString(envelope?.error?.code);
|
|
952
|
+
const normalized = normalizeBootstrapErrorCode(wireCode);
|
|
953
|
+
const message = readNonEmptyString(envelope?.error?.message) ?? `${bootstrapUrl} failed with HTTP ${response.status}.`;
|
|
954
|
+
const backendDetails = readRecord(envelope?.error?.details);
|
|
955
|
+
return new CapxulError({
|
|
956
|
+
code: normalized.code,
|
|
957
|
+
message,
|
|
958
|
+
details: {
|
|
959
|
+
...backendDetails,
|
|
960
|
+
source: "backend-bootstrap",
|
|
961
|
+
phase: "publishable-key-bootstrap",
|
|
962
|
+
httpStatus: response.status,
|
|
963
|
+
...normalized.wireCode ? { wireCode: normalized.wireCode } : {}
|
|
964
|
+
},
|
|
965
|
+
operationId: readNonEmptyString(envelope?.error?.operationId),
|
|
966
|
+
correlationId: readNonEmptyString(envelope?.error?.correlationId),
|
|
967
|
+
retryable: typeof envelope?.error?.retryable === "boolean" ? envelope.error.retryable : void 0
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
async function readBootstrapErrorEnvelope(response) {
|
|
971
|
+
try {
|
|
972
|
+
const parsed = await response.json();
|
|
973
|
+
return typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
974
|
+
} catch {
|
|
975
|
+
return null;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
async function readBootstrapSuccessBody(response) {
|
|
979
|
+
try {
|
|
980
|
+
const parsed = await response.json();
|
|
981
|
+
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
982
|
+
} catch {
|
|
983
|
+
throw bootstrapContractError(
|
|
984
|
+
"body",
|
|
985
|
+
"/v1/client/bootstrap returned invalid JSON."
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
function normalizeBootstrapThrownError(error) {
|
|
990
|
+
if (error instanceof CapxulError) return error;
|
|
991
|
+
return new CapxulError({
|
|
992
|
+
code: "NETWORK_ERROR",
|
|
993
|
+
message: "Publishable-key bootstrap network failure.",
|
|
994
|
+
cause: error,
|
|
995
|
+
details: {
|
|
996
|
+
source: "bootstrap-network",
|
|
997
|
+
phase: "publishable-key-bootstrap"
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
function normalizeBootstrapErrorCode(wireCode) {
|
|
1002
|
+
if (wireCode === "INTERNAL_SERVER_ERROR") {
|
|
1003
|
+
return { code: "INTERNAL_ERROR", wireCode };
|
|
1004
|
+
}
|
|
1005
|
+
if (wireCode && isCapxulErrorCode(wireCode)) {
|
|
1006
|
+
return { code: wireCode };
|
|
1007
|
+
}
|
|
1008
|
+
return wireCode ? { code: "UNKNOWN", wireCode } : { code: "UNKNOWN" };
|
|
1009
|
+
}
|
|
1010
|
+
var CAPXUL_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
1011
|
+
"NOT_AUTHENTICATED",
|
|
1012
|
+
"EMAIL_DELIVERY_FAILED",
|
|
1013
|
+
"PROFILE_NOT_FOUND",
|
|
1014
|
+
"SMART_ACCOUNT_MISSING",
|
|
1015
|
+
"PLAYER_NOT_FOUND",
|
|
1016
|
+
"ACCOUNT_NOT_FOUND",
|
|
1017
|
+
"PROVIDER_ERROR",
|
|
1018
|
+
"INVALID_INPUT",
|
|
1019
|
+
"ENV_MISSING",
|
|
1020
|
+
"NOT_IMPLEMENTED",
|
|
1021
|
+
"VERIFICATION_REQUIRED",
|
|
1022
|
+
"INSUFFICIENT_BALANCE",
|
|
1023
|
+
"INVALID_RECIPIENT",
|
|
1024
|
+
"TRANSACTION_FAILED",
|
|
1025
|
+
"RATE_LIMITED",
|
|
1026
|
+
"NETWORK_ERROR",
|
|
1027
|
+
"UNKNOWN",
|
|
1028
|
+
"PERMISSION_DENIED",
|
|
1029
|
+
"API_KEY_INVALID",
|
|
1030
|
+
"API_KEY_EXPIRED",
|
|
1031
|
+
"IDEMPOTENCY_CONFLICT",
|
|
1032
|
+
"NOT_FOUND",
|
|
1033
|
+
"OPERATION_CANCELED",
|
|
1034
|
+
"OPERATION_TIMEOUT",
|
|
1035
|
+
"ACTION_REQUIRED",
|
|
1036
|
+
"KYC_REQUIRED",
|
|
1037
|
+
"POLICY_DENIED",
|
|
1038
|
+
"SAFE_NOT_READY",
|
|
1039
|
+
"PROVIDER_UNAVAILABLE",
|
|
1040
|
+
"PROVIDER_REJECTED",
|
|
1041
|
+
"RECONCILIATION_FAILED",
|
|
1042
|
+
"INTERNAL_ERROR",
|
|
1043
|
+
"QUOTE_EXPIRED",
|
|
1044
|
+
"QUOTE_NOT_FOUND"
|
|
1045
|
+
]);
|
|
1046
|
+
function isCapxulErrorCode(value) {
|
|
1047
|
+
return CAPXUL_ERROR_CODES.has(value);
|
|
1048
|
+
}
|
|
1049
|
+
function readRecord(value) {
|
|
1050
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
1051
|
+
}
|
|
1052
|
+
function readNonEmptyString(value) {
|
|
1053
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
1054
|
+
}
|
|
903
1055
|
|
|
904
1056
|
// src/core/auth.ts
|
|
905
1057
|
function createAuthClient(config = {}) {
|
|
@@ -954,13 +1106,16 @@ function createAuthClient(config = {}) {
|
|
|
954
1106
|
email: signIn.user.email,
|
|
955
1107
|
token: signIn.token,
|
|
956
1108
|
convexJwt,
|
|
957
|
-
expiresAt: new Date(
|
|
1109
|
+
expiresAt: new Date(
|
|
1110
|
+
Date.now() + 30 * 24 * 60 * 60 * 1e3
|
|
1111
|
+
).toISOString()
|
|
958
1112
|
};
|
|
959
1113
|
sessionStore.set(session);
|
|
960
1114
|
if (config.auth?.createDataClient) {
|
|
961
1115
|
try {
|
|
962
1116
|
dataClient = await config.auth.createDataClient(session);
|
|
963
1117
|
mutableConfig(config).data = dataClient;
|
|
1118
|
+
transport.markAuthenticated({ dataClient });
|
|
964
1119
|
} catch (cause) {
|
|
965
1120
|
return [
|
|
966
1121
|
new CapxulError({
|
|
@@ -972,13 +1127,76 @@ function createAuthClient(config = {}) {
|
|
|
972
1127
|
];
|
|
973
1128
|
}
|
|
974
1129
|
}
|
|
975
|
-
|
|
1130
|
+
if (!dataClient) {
|
|
1131
|
+
return [
|
|
1132
|
+
new CapxulError({
|
|
1133
|
+
code: "NOT_AUTHENTICATED",
|
|
1134
|
+
message: "Auth bootstrap requires an authenticated Convex data client."
|
|
1135
|
+
}),
|
|
1136
|
+
null
|
|
1137
|
+
];
|
|
1138
|
+
}
|
|
1139
|
+
try {
|
|
1140
|
+
const resolution = await dataClient.mutation(
|
|
1141
|
+
api.authBootstrap.resolveAfterOtp,
|
|
1142
|
+
{
|
|
1143
|
+
email: session.email,
|
|
1144
|
+
sessionToken: session.token
|
|
1145
|
+
}
|
|
1146
|
+
);
|
|
1147
|
+
if (resolution.kind === "existing_member") {
|
|
1148
|
+
return [null, { ...resolution, session }];
|
|
1149
|
+
}
|
|
1150
|
+
return [null, { ...resolution, session }];
|
|
1151
|
+
} catch (cause) {
|
|
1152
|
+
return [fromConvexError(cause), null];
|
|
1153
|
+
}
|
|
1154
|
+
},
|
|
1155
|
+
completeBootstrap: async (input) => {
|
|
1156
|
+
const session = sessionStore.get();
|
|
1157
|
+
const data = dataClient ?? config.data;
|
|
1158
|
+
if (!session || !data) {
|
|
1159
|
+
return [
|
|
1160
|
+
new CapxulError({
|
|
1161
|
+
code: "INVALID_INPUT",
|
|
1162
|
+
message: "completeBootstrap requires the OTP-verified session that issued the bootstrap token."
|
|
1163
|
+
}),
|
|
1164
|
+
null
|
|
1165
|
+
];
|
|
1166
|
+
}
|
|
1167
|
+
if (input.signerProvider.kind !== "local-private-key") {
|
|
1168
|
+
return [
|
|
1169
|
+
new CapxulError({
|
|
1170
|
+
code: "INVALID_INPUT",
|
|
1171
|
+
message: "completeBootstrap currently supports local-private-key signer providers only."
|
|
1172
|
+
}),
|
|
1173
|
+
null
|
|
1174
|
+
];
|
|
1175
|
+
}
|
|
1176
|
+
try {
|
|
1177
|
+
const result = await data.mutation(api.authBootstrap.completeBootstrap, {
|
|
1178
|
+
bootstrapToken: input.bootstrapToken,
|
|
1179
|
+
sessionToken: session.token,
|
|
1180
|
+
username: input.username,
|
|
1181
|
+
displayName: input.displayName,
|
|
1182
|
+
countryCode: input.countryCode,
|
|
1183
|
+
signerProvider: input.signerProvider
|
|
1184
|
+
});
|
|
1185
|
+
return [null, { kind: "authenticated", session, ...result }];
|
|
1186
|
+
} catch (cause) {
|
|
1187
|
+
return [
|
|
1188
|
+
fromConvexError(cause),
|
|
1189
|
+
null
|
|
1190
|
+
];
|
|
1191
|
+
}
|
|
976
1192
|
},
|
|
977
1193
|
getSession: async () => [null, sessionStore.get()],
|
|
978
1194
|
signOut: async () => {
|
|
979
1195
|
sessionStore.clear();
|
|
980
1196
|
dataClient = null;
|
|
981
1197
|
mutableConfig(config).data = void 0;
|
|
1198
|
+
const transport = getTransport();
|
|
1199
|
+
transport?.clearAuth();
|
|
982
1200
|
return [null, void 0];
|
|
983
1201
|
},
|
|
984
1202
|
serviceTokenMint: async () => stub("auth.serviceTokenMint"),
|
|
@@ -1032,16 +1250,19 @@ async function postBetterAuth(transport, path, body, code, signal) {
|
|
|
1032
1250
|
body: JSON.stringify(body),
|
|
1033
1251
|
signal
|
|
1034
1252
|
});
|
|
1253
|
+
const text = await response.text();
|
|
1035
1254
|
if (!response.ok) {
|
|
1255
|
+
const parsedError = parseBetterAuthError(text);
|
|
1036
1256
|
return [
|
|
1037
1257
|
new CapxulError({
|
|
1038
|
-
code,
|
|
1039
|
-
message: `BetterAuth ${path} failed with HTTP ${response.status}
|
|
1258
|
+
code: parsedError.code ?? code,
|
|
1259
|
+
message: parsedError.message ?? `BetterAuth ${path} failed with HTTP ${response.status}.`,
|
|
1260
|
+
details: parsedError.details,
|
|
1261
|
+
retryable: parsedError.retryable
|
|
1040
1262
|
}),
|
|
1041
1263
|
null
|
|
1042
1264
|
];
|
|
1043
1265
|
}
|
|
1044
|
-
const text = await response.text();
|
|
1045
1266
|
return [null, text ? JSON.parse(text) : void 0];
|
|
1046
1267
|
} catch (cause) {
|
|
1047
1268
|
return [
|
|
@@ -1054,6 +1275,36 @@ async function postBetterAuth(transport, path, body, code, signal) {
|
|
|
1054
1275
|
];
|
|
1055
1276
|
}
|
|
1056
1277
|
}
|
|
1278
|
+
function parseBetterAuthError(text) {
|
|
1279
|
+
if (!text.trim()) {
|
|
1280
|
+
return {};
|
|
1281
|
+
}
|
|
1282
|
+
try {
|
|
1283
|
+
const body = JSON.parse(text);
|
|
1284
|
+
if (!body || typeof body !== "object") {
|
|
1285
|
+
return {};
|
|
1286
|
+
}
|
|
1287
|
+
const record = body;
|
|
1288
|
+
const nested = record.error && typeof record.error === "object" ? record.error : record;
|
|
1289
|
+
const code = typeof nested.code === "string" ? nested.code : void 0;
|
|
1290
|
+
const message = typeof nested.message === "string" ? nested.message : void 0;
|
|
1291
|
+
const details = nested.details && typeof nested.details === "object" ? nested.details : void 0;
|
|
1292
|
+
const correlationId = typeof nested.correlationId === "string" ? nested.correlationId : void 0;
|
|
1293
|
+
const retryable = typeof nested.retryable === "boolean" ? nested.retryable : void 0;
|
|
1294
|
+
return {
|
|
1295
|
+
code: isCapxulErrorCode2(code) ? code : void 0,
|
|
1296
|
+
message,
|
|
1297
|
+
details,
|
|
1298
|
+
correlationId,
|
|
1299
|
+
retryable
|
|
1300
|
+
};
|
|
1301
|
+
} catch {
|
|
1302
|
+
return {};
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
function isCapxulErrorCode2(code) {
|
|
1306
|
+
return code === "NOT_AUTHENTICATED" || code === "EMAIL_DELIVERY_FAILED" || code === "INVALID_INPUT" || code === "RATE_LIMITED" || code === "NETWORK_ERROR" || code === "API_KEY_INVALID" || code === "API_KEY_EXPIRED";
|
|
1307
|
+
}
|
|
1057
1308
|
async function exchangeConvexToken(transport, config, token, signal) {
|
|
1058
1309
|
const path = config.auth?.convexTokenUrl ?? "/convex/token";
|
|
1059
1310
|
try {
|
|
@@ -2296,7 +2547,7 @@ function createAuthFlowMachine(client) {
|
|
|
2296
2547
|
}),
|
|
2297
2548
|
verifyOtp: xstate.fromPromise(
|
|
2298
2549
|
async ({ input, signal }) => {
|
|
2299
|
-
const [error,
|
|
2550
|
+
const [error, result] = await client.auth.verifyOtp(
|
|
2300
2551
|
{
|
|
2301
2552
|
email: input.email,
|
|
2302
2553
|
otp: input.code
|
|
@@ -2304,7 +2555,14 @@ function createAuthFlowMachine(client) {
|
|
|
2304
2555
|
{ signal }
|
|
2305
2556
|
);
|
|
2306
2557
|
if (error) throw error;
|
|
2307
|
-
|
|
2558
|
+
if (result.kind === "bootstrap_required") {
|
|
2559
|
+
throw new CapxulError({
|
|
2560
|
+
code: "ACTION_REQUIRED",
|
|
2561
|
+
message: "OTP verified but auth bootstrap is required. Use createAuthBootstrapFlowMachine for product sign-up.",
|
|
2562
|
+
details: { reason: result.reason }
|
|
2563
|
+
});
|
|
2564
|
+
}
|
|
2565
|
+
return result.session;
|
|
2308
2566
|
}
|
|
2309
2567
|
),
|
|
2310
2568
|
signOut: xstate.fromPromise(async () => {
|
|
@@ -2552,6 +2810,345 @@ function emailDomain(email) {
|
|
|
2552
2810
|
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
2553
2811
|
return domain || "unknown";
|
|
2554
2812
|
}
|
|
2813
|
+
var initialContext = {
|
|
2814
|
+
email: null,
|
|
2815
|
+
code: null,
|
|
2816
|
+
username: null,
|
|
2817
|
+
signerProvider: null,
|
|
2818
|
+
bootstrapToken: null,
|
|
2819
|
+
bootstrapReason: null,
|
|
2820
|
+
session: null,
|
|
2821
|
+
account: null,
|
|
2822
|
+
safe: null,
|
|
2823
|
+
error: null
|
|
2824
|
+
};
|
|
2825
|
+
function createAuthBootstrapFlowMachine(client) {
|
|
2826
|
+
return xstate.setup({
|
|
2827
|
+
types: {},
|
|
2828
|
+
actors: {
|
|
2829
|
+
sendOtp: xstate.fromPromise(async ({ input, signal }) => {
|
|
2830
|
+
const [error] = await client.auth.sendOtp(
|
|
2831
|
+
{ email: input.email },
|
|
2832
|
+
{ signal }
|
|
2833
|
+
);
|
|
2834
|
+
if (error) throw error;
|
|
2835
|
+
}),
|
|
2836
|
+
verifyOtp: xstate.fromPromise(
|
|
2837
|
+
async ({ input, signal }) => {
|
|
2838
|
+
const [error, result] = await client.auth.verifyOtp(
|
|
2839
|
+
{ email: input.email, otp: input.code },
|
|
2840
|
+
{ signal }
|
|
2841
|
+
);
|
|
2842
|
+
if (error) throw error;
|
|
2843
|
+
return result;
|
|
2844
|
+
}
|
|
2845
|
+
),
|
|
2846
|
+
completeBootstrap: xstate.fromPromise(async ({ input }) => {
|
|
2847
|
+
const [error, result] = await client.auth.completeBootstrap(input);
|
|
2848
|
+
if (error) throw error;
|
|
2849
|
+
return result;
|
|
2850
|
+
}),
|
|
2851
|
+
signOut: xstate.fromPromise(async () => {
|
|
2852
|
+
const [error] = await client.auth.signOut();
|
|
2853
|
+
if (error) throw error;
|
|
2854
|
+
})
|
|
2855
|
+
},
|
|
2856
|
+
actions: {
|
|
2857
|
+
trackOtpRequested: ({ context }) => {
|
|
2858
|
+
if (!context.email) return;
|
|
2859
|
+
track("auth_otp_requested", {
|
|
2860
|
+
email_domain: emailDomain2(context.email)
|
|
2861
|
+
});
|
|
2862
|
+
},
|
|
2863
|
+
trackFailed: ({ event }) => {
|
|
2864
|
+
track("auth_failed", {
|
|
2865
|
+
auth_type: "email_otp",
|
|
2866
|
+
reason: errorFromEvent2(event).code
|
|
2867
|
+
});
|
|
2868
|
+
},
|
|
2869
|
+
trackTimeoutFailed: () => {
|
|
2870
|
+
track("auth_failed", {
|
|
2871
|
+
auth_type: "email_otp",
|
|
2872
|
+
reason: "timeout"
|
|
2873
|
+
});
|
|
2874
|
+
},
|
|
2875
|
+
trackVerified: () => {
|
|
2876
|
+
track("auth_verified", { auth_type: "email_otp" });
|
|
2877
|
+
},
|
|
2878
|
+
trackBootstrapRequired: ({ context }) => {
|
|
2879
|
+
track("auth_verified", {
|
|
2880
|
+
auth_type: "email_otp",
|
|
2881
|
+
auth_mode: context.bootstrapReason ?? "bootstrap_required"
|
|
2882
|
+
});
|
|
2883
|
+
},
|
|
2884
|
+
identifyAndTrack: ({ context }) => {
|
|
2885
|
+
if (!context.session) return;
|
|
2886
|
+
identify(context.session.authUserId, {
|
|
2887
|
+
email_domain: emailDomain2(context.session.email)
|
|
2888
|
+
});
|
|
2889
|
+
track("auth_identified", {
|
|
2890
|
+
email_domain: emailDomain2(context.session.email)
|
|
2891
|
+
});
|
|
2892
|
+
},
|
|
2893
|
+
trackSignedOut: () => {
|
|
2894
|
+
track("auth_signed_out");
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
}).createMachine({
|
|
2898
|
+
id: "authBootstrap",
|
|
2899
|
+
initial: "email",
|
|
2900
|
+
context: initialContext,
|
|
2901
|
+
states: {
|
|
2902
|
+
email: {
|
|
2903
|
+
on: {
|
|
2904
|
+
ENTER_EMAIL: {
|
|
2905
|
+
actions: xstate.assign({
|
|
2906
|
+
email: ({ event }) => event.email,
|
|
2907
|
+
error: () => null
|
|
2908
|
+
})
|
|
2909
|
+
},
|
|
2910
|
+
REQUEST_OTP: { target: "sending_otp" }
|
|
2911
|
+
}
|
|
2912
|
+
},
|
|
2913
|
+
sending_otp: {
|
|
2914
|
+
invoke: {
|
|
2915
|
+
src: "sendOtp",
|
|
2916
|
+
input: ({ context }) => ({ email: requireEmail2(context) }),
|
|
2917
|
+
onDone: { target: "otp_requested", actions: "trackOtpRequested" },
|
|
2918
|
+
onError: {
|
|
2919
|
+
target: "otp_requested",
|
|
2920
|
+
actions: [
|
|
2921
|
+
xstate.assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
2922
|
+
"trackFailed"
|
|
2923
|
+
]
|
|
2924
|
+
}
|
|
2925
|
+
},
|
|
2926
|
+
after: {
|
|
2927
|
+
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2928
|
+
target: "otp_requested",
|
|
2929
|
+
actions: [
|
|
2930
|
+
xstate.assign({ error: () => timeoutError2("sending_otp") }),
|
|
2931
|
+
"trackTimeoutFailed"
|
|
2932
|
+
]
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
},
|
|
2936
|
+
otp_requested: {
|
|
2937
|
+
on: {
|
|
2938
|
+
ENTER_OTP: {
|
|
2939
|
+
actions: xstate.assign({
|
|
2940
|
+
code: ({ event }) => event.code,
|
|
2941
|
+
error: () => null
|
|
2942
|
+
})
|
|
2943
|
+
},
|
|
2944
|
+
VERIFY_OTP: { target: "verifying_otp" },
|
|
2945
|
+
BACK: { target: "email" },
|
|
2946
|
+
RESET: { target: "email", actions: xstate.assign(() => initialContext) }
|
|
2947
|
+
}
|
|
2948
|
+
},
|
|
2949
|
+
verifying_otp: {
|
|
2950
|
+
invoke: {
|
|
2951
|
+
src: "verifyOtp",
|
|
2952
|
+
input: ({ context }) => ({
|
|
2953
|
+
email: requireEmail2(context),
|
|
2954
|
+
code: requireCode(context)
|
|
2955
|
+
}),
|
|
2956
|
+
onDone: [
|
|
2957
|
+
{
|
|
2958
|
+
guard: ({ event }) => event.output.kind === "existing_member",
|
|
2959
|
+
target: "authenticated",
|
|
2960
|
+
actions: [
|
|
2961
|
+
xstate.assign({
|
|
2962
|
+
session: ({ event }) => event.output.session,
|
|
2963
|
+
account: ({ event }) => event.output.kind === "existing_member" ? event.output.account : null,
|
|
2964
|
+
username: ({ event }) => event.output.kind === "existing_member" ? event.output.username : null,
|
|
2965
|
+
safe: ({ event }) => event.output.kind === "existing_member" ? event.output.safe : null,
|
|
2966
|
+
email: () => null,
|
|
2967
|
+
error: () => null
|
|
2968
|
+
}),
|
|
2969
|
+
"trackVerified",
|
|
2970
|
+
"identifyAndTrack"
|
|
2971
|
+
]
|
|
2972
|
+
},
|
|
2973
|
+
{
|
|
2974
|
+
target: "bootstrap_required",
|
|
2975
|
+
actions: [
|
|
2976
|
+
xstate.assign({
|
|
2977
|
+
session: ({ event }) => event.output.session,
|
|
2978
|
+
bootstrapToken: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.bootstrapToken : null,
|
|
2979
|
+
bootstrapReason: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.reason : null,
|
|
2980
|
+
username: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.username ?? null : null,
|
|
2981
|
+
email: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.email : null,
|
|
2982
|
+
error: () => null
|
|
2983
|
+
}),
|
|
2984
|
+
"trackVerified",
|
|
2985
|
+
"trackBootstrapRequired"
|
|
2986
|
+
]
|
|
2987
|
+
}
|
|
2988
|
+
],
|
|
2989
|
+
onError: {
|
|
2990
|
+
target: "otp_requested",
|
|
2991
|
+
actions: [
|
|
2992
|
+
xstate.assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
2993
|
+
"trackFailed"
|
|
2994
|
+
]
|
|
2995
|
+
}
|
|
2996
|
+
},
|
|
2997
|
+
after: {
|
|
2998
|
+
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2999
|
+
target: "otp_requested",
|
|
3000
|
+
actions: [
|
|
3001
|
+
xstate.assign({ error: () => timeoutError2("verifying_otp") }),
|
|
3002
|
+
"trackTimeoutFailed"
|
|
3003
|
+
]
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
},
|
|
3007
|
+
bootstrap_required: {
|
|
3008
|
+
on: {
|
|
3009
|
+
ENTER_USERNAME: {
|
|
3010
|
+
actions: xstate.assign({
|
|
3011
|
+
username: ({ event }) => event.username,
|
|
3012
|
+
error: () => null
|
|
3013
|
+
})
|
|
3014
|
+
},
|
|
3015
|
+
ENTER_SIGNER_PROVIDER: {
|
|
3016
|
+
actions: xstate.assign({
|
|
3017
|
+
signerProvider: ({ event }) => event.signerProvider,
|
|
3018
|
+
error: () => null
|
|
3019
|
+
})
|
|
3020
|
+
},
|
|
3021
|
+
COMPLETE_BOOTSTRAP: { target: "completing_bootstrap" },
|
|
3022
|
+
BACK: { target: "otp_requested" },
|
|
3023
|
+
RESET: { target: "email", actions: xstate.assign(() => initialContext) }
|
|
3024
|
+
}
|
|
3025
|
+
},
|
|
3026
|
+
completing_bootstrap: {
|
|
3027
|
+
invoke: {
|
|
3028
|
+
src: "completeBootstrap",
|
|
3029
|
+
input: ({ context }) => ({
|
|
3030
|
+
bootstrapToken: requireBootstrapToken(context),
|
|
3031
|
+
username: requireUsername(context),
|
|
3032
|
+
signerProvider: requireSignerProvider(context)
|
|
3033
|
+
}),
|
|
3034
|
+
onDone: {
|
|
3035
|
+
target: "authenticated",
|
|
3036
|
+
actions: [
|
|
3037
|
+
xstate.assign({
|
|
3038
|
+
session: ({ event }) => event.output.session,
|
|
3039
|
+
account: ({ event }) => event.output.account,
|
|
3040
|
+
username: ({ event }) => event.output.username,
|
|
3041
|
+
safe: ({ event }) => event.output.safe,
|
|
3042
|
+
bootstrapToken: () => null,
|
|
3043
|
+
bootstrapReason: () => null,
|
|
3044
|
+
signerProvider: () => null,
|
|
3045
|
+
email: () => null,
|
|
3046
|
+
error: () => null
|
|
3047
|
+
}),
|
|
3048
|
+
"identifyAndTrack"
|
|
3049
|
+
]
|
|
3050
|
+
},
|
|
3051
|
+
onError: {
|
|
3052
|
+
target: "bootstrap_required",
|
|
3053
|
+
actions: [
|
|
3054
|
+
xstate.assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3055
|
+
"trackFailed"
|
|
3056
|
+
]
|
|
3057
|
+
}
|
|
3058
|
+
},
|
|
3059
|
+
after: {
|
|
3060
|
+
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3061
|
+
target: "bootstrap_required",
|
|
3062
|
+
actions: [
|
|
3063
|
+
xstate.assign({ error: () => timeoutError2("completing_bootstrap") }),
|
|
3064
|
+
"trackTimeoutFailed"
|
|
3065
|
+
]
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
},
|
|
3069
|
+
authenticated: {
|
|
3070
|
+
on: {
|
|
3071
|
+
SIGN_OUT: { target: "signing_out" }
|
|
3072
|
+
}
|
|
3073
|
+
},
|
|
3074
|
+
signing_out: {
|
|
3075
|
+
invoke: {
|
|
3076
|
+
src: "signOut",
|
|
3077
|
+
onDone: {
|
|
3078
|
+
target: "email",
|
|
3079
|
+
actions: [
|
|
3080
|
+
xstate.assign(() => initialContext),
|
|
3081
|
+
"trackSignedOut"
|
|
3082
|
+
]
|
|
3083
|
+
},
|
|
3084
|
+
onError: {
|
|
3085
|
+
target: "error",
|
|
3086
|
+
actions: xstate.assign({ error: ({ event }) => errorFromEvent2(event) })
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
},
|
|
3090
|
+
error: {
|
|
3091
|
+
on: {
|
|
3092
|
+
RESET: { target: "email", actions: xstate.assign(() => initialContext) }
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
});
|
|
3097
|
+
}
|
|
3098
|
+
function requireEmail2(context) {
|
|
3099
|
+
if (!context.email) {
|
|
3100
|
+
throw Errors.invalidInput("email", "Auth bootstrap requires an email.");
|
|
3101
|
+
}
|
|
3102
|
+
return context.email;
|
|
3103
|
+
}
|
|
3104
|
+
function requireCode(context) {
|
|
3105
|
+
if (!context.code) {
|
|
3106
|
+
throw Errors.invalidInput("code", "Auth bootstrap requires an OTP code.");
|
|
3107
|
+
}
|
|
3108
|
+
return context.code;
|
|
3109
|
+
}
|
|
3110
|
+
function requireBootstrapToken(context) {
|
|
3111
|
+
if (!context.bootstrapToken) {
|
|
3112
|
+
throw Errors.invalidInput(
|
|
3113
|
+
"bootstrapToken",
|
|
3114
|
+
"Auth bootstrap requires a continuation token."
|
|
3115
|
+
);
|
|
3116
|
+
}
|
|
3117
|
+
return context.bootstrapToken;
|
|
3118
|
+
}
|
|
3119
|
+
function requireUsername(context) {
|
|
3120
|
+
if (!context.username) {
|
|
3121
|
+
throw Errors.invalidInput("username", "Auth bootstrap requires a username.");
|
|
3122
|
+
}
|
|
3123
|
+
return context.username;
|
|
3124
|
+
}
|
|
3125
|
+
function requireSignerProvider(context) {
|
|
3126
|
+
if (!context.signerProvider) {
|
|
3127
|
+
throw Errors.invalidInput(
|
|
3128
|
+
"signerProvider",
|
|
3129
|
+
"Auth bootstrap requires a signer provider."
|
|
3130
|
+
);
|
|
3131
|
+
}
|
|
3132
|
+
return context.signerProvider;
|
|
3133
|
+
}
|
|
3134
|
+
function errorFromEvent2(event) {
|
|
3135
|
+
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3136
|
+
if (cause instanceof CapxulError || cause instanceof CapxulError2) {
|
|
3137
|
+
return cause;
|
|
3138
|
+
}
|
|
3139
|
+
return Errors.providerError("auth", "bootstrap", cause);
|
|
3140
|
+
}
|
|
3141
|
+
function timeoutError2(state) {
|
|
3142
|
+
return Errors.providerError(
|
|
3143
|
+
"auth",
|
|
3144
|
+
"bootstrap",
|
|
3145
|
+
new Error(`timeout: ${state} exceeded ${FLOW_INVOKE_TIMEOUT_MS}ms`)
|
|
3146
|
+
);
|
|
3147
|
+
}
|
|
3148
|
+
function emailDomain2(email) {
|
|
3149
|
+
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
3150
|
+
return domain || "unknown";
|
|
3151
|
+
}
|
|
2555
3152
|
function createProvisioningMachine(client) {
|
|
2556
3153
|
return xstate.setup({
|
|
2557
3154
|
types: {},
|
|
@@ -2624,13 +3221,13 @@ function createProvisioningMachine(client) {
|
|
|
2624
3221
|
},
|
|
2625
3222
|
onError: {
|
|
2626
3223
|
target: "error",
|
|
2627
|
-
actions: xstate.assign({ error: ({ event }) =>
|
|
3224
|
+
actions: xstate.assign({ error: ({ event }) => errorFromEvent3(event) })
|
|
2628
3225
|
}
|
|
2629
3226
|
},
|
|
2630
3227
|
after: {
|
|
2631
3228
|
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2632
3229
|
target: "error",
|
|
2633
|
-
actions: xstate.assign({ error: () =>
|
|
3230
|
+
actions: xstate.assign({ error: () => timeoutError3() })
|
|
2634
3231
|
}
|
|
2635
3232
|
}
|
|
2636
3233
|
},
|
|
@@ -2648,7 +3245,7 @@ function createProvisioningMachine(client) {
|
|
|
2648
3245
|
* this payload on its `onDone` transition and branches via guards
|
|
2649
3246
|
* on `event.output.error`.
|
|
2650
3247
|
*/
|
|
2651
|
-
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error:
|
|
3248
|
+
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error: timeoutError3() }
|
|
2652
3249
|
});
|
|
2653
3250
|
}
|
|
2654
3251
|
function requireProvisionInput(context) {
|
|
@@ -2660,13 +3257,13 @@ function requireProvisionInput(context) {
|
|
|
2660
3257
|
}
|
|
2661
3258
|
return context.input;
|
|
2662
3259
|
}
|
|
2663
|
-
function
|
|
3260
|
+
function errorFromEvent3(event) {
|
|
2664
3261
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
2665
3262
|
if (cause instanceof CapxulError) return cause;
|
|
2666
3263
|
if (cause instanceof CapxulError2) return cause;
|
|
2667
3264
|
return Errors.providerError("provisioning", "flow", cause);
|
|
2668
3265
|
}
|
|
2669
|
-
function
|
|
3266
|
+
function timeoutError3() {
|
|
2670
3267
|
return Errors.providerError(
|
|
2671
3268
|
"provisioning",
|
|
2672
3269
|
"flow",
|
|
@@ -2759,7 +3356,7 @@ function createOnboardingFlowMachine(client) {
|
|
|
2759
3356
|
error: ({ event }) => extractChildErrorOrFallback(event)
|
|
2760
3357
|
}),
|
|
2761
3358
|
assignChildThrown: xstate.assign({
|
|
2762
|
-
error: ({ event }) =>
|
|
3359
|
+
error: ({ event }) => errorFromEvent4(event)
|
|
2763
3360
|
}),
|
|
2764
3361
|
assignAccountFromChild: xstate.assign({
|
|
2765
3362
|
account: ({ event }) => extractChildAccountOrNull(event)
|
|
@@ -2921,7 +3518,7 @@ function extractChildAccountOrNull(event) {
|
|
|
2921
3518
|
if (output && "account" in output && output.account) return output.account;
|
|
2922
3519
|
return null;
|
|
2923
3520
|
}
|
|
2924
|
-
function
|
|
3521
|
+
function errorFromEvent4(event) {
|
|
2925
3522
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
2926
3523
|
if (cause instanceof CapxulError) return cause;
|
|
2927
3524
|
if (cause instanceof CapxulError2) return cause;
|
|
@@ -2953,6 +3550,7 @@ function createCapxulClient(config = {}) {
|
|
|
2953
3550
|
const client = clientWithoutFlows;
|
|
2954
3551
|
client.flows = {
|
|
2955
3552
|
auth: () => createAuthFlowMachine(client),
|
|
3553
|
+
authBootstrap: () => createAuthBootstrapFlowMachine(client),
|
|
2956
3554
|
onboarding: () => createOnboardingFlowMachine(client),
|
|
2957
3555
|
provisioning: () => createProvisioningMachine(client)
|
|
2958
3556
|
};
|
|
@@ -3058,6 +3656,7 @@ function isWebhookEvent(value) {
|
|
|
3058
3656
|
}
|
|
3059
3657
|
|
|
3060
3658
|
exports.CapxulError = CapxulError;
|
|
3659
|
+
exports.createAuthBootstrapFlowMachine = createAuthBootstrapFlowMachine;
|
|
3061
3660
|
exports.createAuthFlowMachine = createAuthFlowMachine;
|
|
3062
3661
|
exports.createCapxulClient = createCapxulClient;
|
|
3063
3662
|
exports.createLocalSigner = createLocalSigner;
|