@rakomi/react-native 0.3.0 → 0.4.0
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 +10 -0
- package/SECURITY.md +2 -2
- package/THIRD-PARTY-NOTICES +1 -1
- package/dist/index.cjs +21 -7
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +22 -8
- package/package.json +4 -4
- package/sbom.cdx.json +9 -9
package/README.md
CHANGED
|
@@ -24,6 +24,16 @@ React Native / Expo SDK for [Rakomi](https://rakomi.com) — EU-native auth-as-a
|
|
|
24
24
|
> Token-manager runtime, JWKS verification, social-provider deep-link auto-handler, a bare-RN adapter
|
|
25
25
|
> example, and a demo app land in subsequent 0.x releases.
|
|
26
26
|
|
|
27
|
+
## Ask your agent
|
|
28
|
+
|
|
29
|
+
Add the Rakomi MCP server to your coding agent, then ask it directly:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
claude mcp add --transport http rakomi https://mcp.rakomi.com/mcp
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
"List the AI agents connected to my Rakomi tenant."
|
|
36
|
+
|
|
27
37
|
## Install
|
|
28
38
|
|
|
29
39
|
```sh
|
package/SECURITY.md
CHANGED
|
@@ -9,8 +9,8 @@ While these packages remain pre-1.0 (`0.x`), they carry **no stability or suppor
|
|
|
9
9
|
(SemVer 2.0.0 §4); the latest `0.x` line receives security updates on a best-effort basis.
|
|
10
10
|
|
|
11
11
|
From version **1.0** onward, Rakomi maintains the current (N) and previous (N-1) MAJOR in parallel, with N-1 receiving
|
|
12
|
-
security-only fixes.
|
|
13
|
-
**
|
|
12
|
+
security-only fixes. For each MAJOR version of the Rakomi SDKs, CRE8EVE commits to a CRA support period of
|
|
13
|
+
**at least five years (60 months)**, meeting the support-period requirement of **CRA Art. 13(8)**. The authoritative, machine-readable support windows are published at
|
|
14
14
|
[`https://api.rakomi.com/.well-known/sdk-support.json`](https://api.rakomi.com/.well-known/sdk-support.json)
|
|
15
15
|
and rendered for humans on the [SDK Support & Lifecycle page](https://rakomi.com/sdk-support). This
|
|
16
16
|
document points at that single source rather than re-typing dated rows.
|
package/THIRD-PARTY-NOTICES
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
|
|
2
2
|
|
|
3
|
-
For the npm package: @rakomi/react-native@0.
|
|
3
|
+
For the npm package: @rakomi/react-native@0.4.0
|
|
4
4
|
|
|
5
5
|
This package's published bundle (`dist/`) INLINES the third-party components listed below.
|
|
6
6
|
Their copyright and permission notices are reproduced verbatim, as required by their licenses
|
package/dist/index.cjs
CHANGED
|
@@ -1075,8 +1075,12 @@ function RakomiProvider(props) {
|
|
|
1075
1075
|
}
|
|
1076
1076
|
});
|
|
1077
1077
|
}, [adapter, http, props.publishableKey, props.tenantId, props.baseUrl, props.tokenEndpoint, props.biometric, props.biometricStrict, props.biometricPrompt, events, dpopSession]);
|
|
1078
|
+
const restoreStarted = react.useRef(false);
|
|
1078
1079
|
react.useEffect(() => {
|
|
1079
|
-
|
|
1080
|
+
if (!restoreStarted.current) {
|
|
1081
|
+
restoreStarted.current = true;
|
|
1082
|
+
void runtime.restore();
|
|
1083
|
+
}
|
|
1080
1084
|
return () => runtime.destroy();
|
|
1081
1085
|
}, [runtime]);
|
|
1082
1086
|
const debounceTimer = react.useRef(null);
|
|
@@ -1636,8 +1640,8 @@ function SignIn(props) {
|
|
|
1636
1640
|
const [step, setStep] = react.useState({ kind: "methods" });
|
|
1637
1641
|
const [code, setCode] = react.useState("");
|
|
1638
1642
|
const [busy, setBusy] = react.useState(false);
|
|
1639
|
-
const tokenEndpoint = props.tokenEndpoint ?? "/
|
|
1640
|
-
const totpVerifyEndpoint = props.totpVerifyEndpoint ?? "/v1/auth/mfa/
|
|
1643
|
+
const tokenEndpoint = props.tokenEndpoint ?? "/oauth/token";
|
|
1644
|
+
const totpVerifyEndpoint = props.totpVerifyEndpoint ?? "/v1/auth/mfa/verify-login";
|
|
1641
1645
|
const providers = props.providers ?? ["google"];
|
|
1642
1646
|
async function onProviderPress(provider) {
|
|
1643
1647
|
if (busy) return;
|
|
@@ -1679,6 +1683,7 @@ function SignIn(props) {
|
|
|
1679
1683
|
const result = await sdkCore.verifyTotp({
|
|
1680
1684
|
http: ctx.http,
|
|
1681
1685
|
endpoint: totpVerifyEndpoint,
|
|
1686
|
+
apiKey: ctx.publishableKey,
|
|
1682
1687
|
challengeToken: step.challengeToken,
|
|
1683
1688
|
code
|
|
1684
1689
|
});
|
|
@@ -1760,11 +1765,20 @@ function SignUp(props) {
|
|
|
1760
1765
|
try {
|
|
1761
1766
|
const response = await ctx.http.fetch(props.registerEndpoint ?? "/v1/auth/register", {
|
|
1762
1767
|
method: "POST",
|
|
1763
|
-
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
1768
|
+
headers: { "Content-Type": "application/json", Accept: "application/json", "X-API-Key": ctx.publishableKey },
|
|
1764
1769
|
body: JSON.stringify({ email, password, returnTo })
|
|
1765
1770
|
});
|
|
1766
1771
|
if (!response.ok) {
|
|
1767
|
-
|
|
1772
|
+
let parsed = {};
|
|
1773
|
+
try {
|
|
1774
|
+
parsed = await response.json();
|
|
1775
|
+
} catch {
|
|
1776
|
+
}
|
|
1777
|
+
const requestId = sdkCore.extractRequestId(parsed);
|
|
1778
|
+
setStep({
|
|
1779
|
+
kind: "error",
|
|
1780
|
+
error: { code: "SIGN_IN_FAILED", message: parsed.detail ?? `Register failed (${response.status})`, ...requestId && { requestId } }
|
|
1781
|
+
});
|
|
1768
1782
|
} else {
|
|
1769
1783
|
setStep({ kind: "verification_required" });
|
|
1770
1784
|
}
|
|
@@ -2686,8 +2700,8 @@ function useMfa() {
|
|
|
2686
2700
|
const ctx = useRakomiContext();
|
|
2687
2701
|
return {
|
|
2688
2702
|
verifyTotp: async (challengeToken, code, endpoint) => {
|
|
2689
|
-
const url = endpoint ?? `${ctx.baseUrl}/v1/auth/mfa/
|
|
2690
|
-
const result = await sdkCore.verifyTotp({ http: ctx.http, endpoint: url, challengeToken, code });
|
|
2703
|
+
const url = endpoint ?? `${ctx.baseUrl}/v1/auth/mfa/verify-login`;
|
|
2704
|
+
const result = await sdkCore.verifyTotp({ http: ctx.http, endpoint: url, apiKey: ctx.publishableKey, challengeToken, code });
|
|
2691
2705
|
if (result.ok) {
|
|
2692
2706
|
const nonce = await ctx.beginAuthFlow();
|
|
2693
2707
|
await ctx.submitOAuthTokens({
|
package/dist/index.d.cts
CHANGED
|
@@ -394,9 +394,9 @@ interface SignInProps {
|
|
|
394
394
|
* path on the API host returns JSON, not the hosted login UI.
|
|
395
395
|
*/
|
|
396
396
|
authorizationEndpoint?: string;
|
|
397
|
-
/**
|
|
397
|
+
/** RFC 6749 §3.2 token endpoint used for the PKCE code→token exchange, default `${baseUrl}/oauth/token`. */
|
|
398
398
|
tokenEndpoint?: string;
|
|
399
|
-
/** MFA TOTP verify endpoint, default `${baseUrl}/v1/auth/mfa/
|
|
399
|
+
/** MFA TOTP verify endpoint, default `${baseUrl}/v1/auth/mfa/verify-login`. */
|
|
400
400
|
totpVerifyEndpoint?: string;
|
|
401
401
|
/** Social providers to render. Default: ['google']. */
|
|
402
402
|
providers?: string[];
|
package/dist/index.d.ts
CHANGED
|
@@ -394,9 +394,9 @@ interface SignInProps {
|
|
|
394
394
|
* path on the API host returns JSON, not the hosted login UI.
|
|
395
395
|
*/
|
|
396
396
|
authorizationEndpoint?: string;
|
|
397
|
-
/**
|
|
397
|
+
/** RFC 6749 §3.2 token endpoint used for the PKCE code→token exchange, default `${baseUrl}/oauth/token`. */
|
|
398
398
|
tokenEndpoint?: string;
|
|
399
|
-
/** MFA TOTP verify endpoint, default `${baseUrl}/v1/auth/mfa/
|
|
399
|
+
/** MFA TOTP verify endpoint, default `${baseUrl}/v1/auth/mfa/verify-login`. */
|
|
400
400
|
totpVerifyEndpoint?: string;
|
|
401
401
|
/** Social providers to render. Default: ['google']. */
|
|
402
402
|
providers?: string[];
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, useMemo, useReducer, useRef, useEffect, useState, useCallback, useContext } from 'react';
|
|
2
|
-
import { createAuthorizationEndpointCache, EventLog, reduce, INITIAL_SNAPSHOT, createTranslator, isSignedIn, hasPermission, hasRole, extractOrgClaims, parseAuthConfigResponse, generatePkce, issueState, buildAuthorizationUrl, consumeState, exchangeAuthCode, parseOAuthCallbackError, scorePassword, isSafeUrl, passkeyError, decodeUser, assertPasskey, stepUpWithPasskey, registerPasskey, listPasskeys, renamePasskey, deletePasskey, verifyMagicLink, requestMagicLink, verifyEmailOtp, requestEmailOtp, register, verifyTotp, MfaStepUpUnavailableError, decodeSession, deriveTenantStorageKey, createJwksCache, refreshAccessToken, decodeJwtPayload, PasskeyCeremonyError } from '@rakomi/sdk-core';
|
|
2
|
+
import { createAuthorizationEndpointCache, EventLog, reduce, INITIAL_SNAPSHOT, createTranslator, isSignedIn, hasPermission, hasRole, extractOrgClaims, parseAuthConfigResponse, generatePkce, issueState, buildAuthorizationUrl, consumeState, exchangeAuthCode, parseOAuthCallbackError, scorePassword, isSafeUrl, passkeyError, decodeUser, assertPasskey, stepUpWithPasskey, registerPasskey, listPasskeys, renamePasskey, deletePasskey, verifyMagicLink, requestMagicLink, verifyEmailOtp, requestEmailOtp, register, verifyTotp, MfaStepUpUnavailableError, extractRequestId, decodeSession, deriveTenantStorageKey, createJwksCache, refreshAccessToken, decodeJwtPayload, PasskeyCeremonyError } from '@rakomi/sdk-core';
|
|
3
3
|
export { MfaStepUpRequiredError, MfaStepUpUnavailableError, base64url, createAuthorizationEndpointCache, createTranslator, decodeJwtPayload, decodeSession, decodeUser, deriveAuthorizationEndpointFallback, generatePkce, getErrorMessage, hasPermission, hasRole, isSafeUrl, networkError, parseOAuthCallbackError, parseTokenEndpointError, scorePassword, selectPluralForm } from '@rakomi/sdk-core';
|
|
4
4
|
import { jwtVerify } from 'jose';
|
|
5
5
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
@@ -1074,8 +1074,12 @@ function RakomiProvider(props) {
|
|
|
1074
1074
|
}
|
|
1075
1075
|
});
|
|
1076
1076
|
}, [adapter, http, props.publishableKey, props.tenantId, props.baseUrl, props.tokenEndpoint, props.biometric, props.biometricStrict, props.biometricPrompt, events, dpopSession]);
|
|
1077
|
+
const restoreStarted = useRef(false);
|
|
1077
1078
|
useEffect(() => {
|
|
1078
|
-
|
|
1079
|
+
if (!restoreStarted.current) {
|
|
1080
|
+
restoreStarted.current = true;
|
|
1081
|
+
void runtime.restore();
|
|
1082
|
+
}
|
|
1079
1083
|
return () => runtime.destroy();
|
|
1080
1084
|
}, [runtime]);
|
|
1081
1085
|
const debounceTimer = useRef(null);
|
|
@@ -1635,8 +1639,8 @@ function SignIn(props) {
|
|
|
1635
1639
|
const [step, setStep] = useState({ kind: "methods" });
|
|
1636
1640
|
const [code, setCode] = useState("");
|
|
1637
1641
|
const [busy, setBusy] = useState(false);
|
|
1638
|
-
const tokenEndpoint = props.tokenEndpoint ?? "/
|
|
1639
|
-
const totpVerifyEndpoint = props.totpVerifyEndpoint ?? "/v1/auth/mfa/
|
|
1642
|
+
const tokenEndpoint = props.tokenEndpoint ?? "/oauth/token";
|
|
1643
|
+
const totpVerifyEndpoint = props.totpVerifyEndpoint ?? "/v1/auth/mfa/verify-login";
|
|
1640
1644
|
const providers = props.providers ?? ["google"];
|
|
1641
1645
|
async function onProviderPress(provider) {
|
|
1642
1646
|
if (busy) return;
|
|
@@ -1678,6 +1682,7 @@ function SignIn(props) {
|
|
|
1678
1682
|
const result = await verifyTotp({
|
|
1679
1683
|
http: ctx.http,
|
|
1680
1684
|
endpoint: totpVerifyEndpoint,
|
|
1685
|
+
apiKey: ctx.publishableKey,
|
|
1681
1686
|
challengeToken: step.challengeToken,
|
|
1682
1687
|
code
|
|
1683
1688
|
});
|
|
@@ -1759,11 +1764,20 @@ function SignUp(props) {
|
|
|
1759
1764
|
try {
|
|
1760
1765
|
const response = await ctx.http.fetch(props.registerEndpoint ?? "/v1/auth/register", {
|
|
1761
1766
|
method: "POST",
|
|
1762
|
-
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
1767
|
+
headers: { "Content-Type": "application/json", Accept: "application/json", "X-API-Key": ctx.publishableKey },
|
|
1763
1768
|
body: JSON.stringify({ email, password, returnTo })
|
|
1764
1769
|
});
|
|
1765
1770
|
if (!response.ok) {
|
|
1766
|
-
|
|
1771
|
+
let parsed = {};
|
|
1772
|
+
try {
|
|
1773
|
+
parsed = await response.json();
|
|
1774
|
+
} catch {
|
|
1775
|
+
}
|
|
1776
|
+
const requestId = extractRequestId(parsed);
|
|
1777
|
+
setStep({
|
|
1778
|
+
kind: "error",
|
|
1779
|
+
error: { code: "SIGN_IN_FAILED", message: parsed.detail ?? `Register failed (${response.status})`, ...requestId && { requestId } }
|
|
1780
|
+
});
|
|
1767
1781
|
} else {
|
|
1768
1782
|
setStep({ kind: "verification_required" });
|
|
1769
1783
|
}
|
|
@@ -2685,8 +2699,8 @@ function useMfa() {
|
|
|
2685
2699
|
const ctx = useRakomiContext();
|
|
2686
2700
|
return {
|
|
2687
2701
|
verifyTotp: async (challengeToken, code, endpoint) => {
|
|
2688
|
-
const url = endpoint ?? `${ctx.baseUrl}/v1/auth/mfa/
|
|
2689
|
-
const result = await verifyTotp({ http: ctx.http, endpoint: url, challengeToken, code });
|
|
2702
|
+
const url = endpoint ?? `${ctx.baseUrl}/v1/auth/mfa/verify-login`;
|
|
2703
|
+
const result = await verifyTotp({ http: ctx.http, endpoint: url, apiKey: ctx.publishableKey, challengeToken, code });
|
|
2690
2704
|
if (result.ok) {
|
|
2691
2705
|
const nonce = await ctx.beginAuthFlow();
|
|
2692
2706
|
await ctx.submitOAuthTokens({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rakomi/react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "React Native / Expo SDK for Rakomi authentication.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rakomi",
|
|
@@ -83,16 +83,16 @@
|
|
|
83
83
|
}
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@rakomi/react": "0.
|
|
86
|
+
"@rakomi/react": "0.4.0"
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"jose": "^6.2.3",
|
|
90
|
-
"@rakomi/sdk-core": "^0.
|
|
90
|
+
"@rakomi/sdk-core": "^0.4.0"
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
93
|
"build": "NODE_OPTIONS=--max-old-space-size=4096 tsup",
|
|
94
94
|
"typecheck": "tsc --noEmit && tsc -p tsconfig.typetest.json",
|
|
95
95
|
"lint": "eslint src/ test/ --max-warnings=0",
|
|
96
|
-
"test": "vitest run"
|
|
96
|
+
"test": "node ../../scripts/ci/vitest-fork-crash-retry.mjs --results ./test-results.json -- vitest run"
|
|
97
97
|
}
|
|
98
98
|
}
|
package/sbom.cdx.json
CHANGED
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
},
|
|
27
27
|
"component": {
|
|
28
28
|
"type": "library",
|
|
29
|
-
"bom-ref": "pkg:npm/%40rakomi%2Freact-native@0.
|
|
29
|
+
"bom-ref": "pkg:npm/%40rakomi%2Freact-native@0.4.0",
|
|
30
30
|
"name": "@rakomi/react-native",
|
|
31
|
-
"version": "0.
|
|
32
|
-
"purl": "pkg:npm/%40rakomi%2Freact-native@0.
|
|
31
|
+
"version": "0.4.0",
|
|
32
|
+
"purl": "pkg:npm/%40rakomi%2Freact-native@0.4.0",
|
|
33
33
|
"licenses": [
|
|
34
34
|
{
|
|
35
35
|
"license": {
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"components": [
|
|
43
43
|
{
|
|
44
44
|
"type": "library",
|
|
45
|
-
"bom-ref": "pkg:npm/@rakomi/sdk-core@0.
|
|
45
|
+
"bom-ref": "pkg:npm/@rakomi/sdk-core@0.4.0",
|
|
46
46
|
"name": "@rakomi/sdk-core",
|
|
47
|
-
"version": "0.
|
|
48
|
-
"purl": "pkg:npm/@rakomi/sdk-core@0.
|
|
47
|
+
"version": "0.4.0",
|
|
48
|
+
"purl": "pkg:npm/@rakomi/sdk-core@0.4.0",
|
|
49
49
|
"licenses": [
|
|
50
50
|
{
|
|
51
51
|
"license": {
|
|
@@ -56,10 +56,10 @@
|
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
"type": "library",
|
|
59
|
-
"bom-ref": "pkg:npm/jose@6.2.
|
|
59
|
+
"bom-ref": "pkg:npm/jose@6.2.12",
|
|
60
60
|
"name": "jose",
|
|
61
|
-
"version": "6.2.
|
|
62
|
-
"purl": "pkg:npm/jose@6.2.
|
|
61
|
+
"version": "6.2.12",
|
|
62
|
+
"purl": "pkg:npm/jose@6.2.12",
|
|
63
63
|
"licenses": [
|
|
64
64
|
{
|
|
65
65
|
"license": {
|