@rakomi/react-native 0.4.0 → 0.6.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 +1 -0
- package/THIRD-PARTY-NOTICES +1 -1
- package/dist/index.cjs +46 -11
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +47 -12
- package/package.json +4 -4
- package/sbom.cdx.json +6 -6
package/README.md
CHANGED
|
@@ -211,6 +211,7 @@ have to branch:
|
|
|
211
211
|
| What happened | Code your UI handles |
|
|
212
212
|
|---|---|
|
|
213
213
|
| The user dismissed the sheet | `PASSKEY_CEREMONY_CANCELLED` |
|
|
214
|
+
| Nobody finished the sheet in time | `PASSKEY_CEREMONY_TIMED_OUT` — retryable; the SDK asked your module to cancel the request |
|
|
214
215
|
| The device cannot do passkeys, or no adapter is wired | `PASSKEY_NOT_SUPPORTED` |
|
|
215
216
|
| The credential is already registered for this user | `PASSKEY_ALREADY_REGISTERED` |
|
|
216
217
|
| The action needs a fresh re-authentication first | `PASSKEY_STEP_UP_REQUIRED` |
|
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.6.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
|
@@ -299,8 +299,19 @@ function deriveDefaultJwksUri(tokenEndpoint) {
|
|
|
299
299
|
}
|
|
300
300
|
var RAKOMI_PLATFORM_ISSUER_DEFAULT = "https://api.rakomi.com";
|
|
301
301
|
var RAKOMI_PLATFORM_AUDIENCE_DEFAULT = "https://api.rakomi.com";
|
|
302
|
-
function deriveDefaultIssuer(
|
|
303
|
-
|
|
302
|
+
function deriveDefaultIssuer(options) {
|
|
303
|
+
if (options.baseUrl) {
|
|
304
|
+
try {
|
|
305
|
+
new URL(options.baseUrl);
|
|
306
|
+
return sdkCore.resolveExpectedIssuer(options.baseUrl);
|
|
307
|
+
} catch {
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
return new URL(options.tokenEndpoint).origin;
|
|
312
|
+
} catch {
|
|
313
|
+
return RAKOMI_PLATFORM_ISSUER_DEFAULT;
|
|
314
|
+
}
|
|
304
315
|
}
|
|
305
316
|
var REFRESH_TOKEN_PREFIX = "v1:";
|
|
306
317
|
var REFRESH_BUFFER_SECONDS = 60;
|
|
@@ -360,7 +371,7 @@ var TokenRuntime = class _TokenRuntime {
|
|
|
360
371
|
this.clearTimeoutFn = options.clearTimeout ?? globalThis.clearTimeout.bind(globalThis);
|
|
361
372
|
this.jwksUri = options.jwksUri ?? deriveDefaultJwksUri(options.tokenEndpoint);
|
|
362
373
|
this.jwksTtlMs = options.jwksTtlMs ?? 24 * 60 * 60 * 1e3;
|
|
363
|
-
this.expectedIssuer = options.expectedIssuer ?? deriveDefaultIssuer(options.tokenEndpoint);
|
|
374
|
+
this.expectedIssuer = options.expectedIssuer ?? deriveDefaultIssuer({ baseUrl: options.baseUrl, tokenEndpoint: options.tokenEndpoint });
|
|
364
375
|
this.expectedAudience = options.expectedAudience ?? RAKOMI_PLATFORM_AUDIENCE_DEFAULT;
|
|
365
376
|
}
|
|
366
377
|
/**
|
|
@@ -515,18 +526,20 @@ var TokenRuntime = class _TokenRuntime {
|
|
|
515
526
|
*
|
|
516
527
|
* uses `jose.createLocalJWKSet` so verification is purely local once
|
|
517
528
|
* the JWKS document has been fetched and cached. The cache is preloaded from `KeyValueStore`
|
|
518
|
-
* on cold-start (slot `jwks_cache`) and refreshed on TTL miss
|
|
529
|
+
* on cold-start (slot `jwks_cache`) and refreshed on TTL miss, or once when the token's `kid` is not in
|
|
530
|
+
* the cached set (a rotated key; rate-limited by a cooldown); on persistent network failure
|
|
519
531
|
* the stale-while-error fallback keeps verification working until the cached doc itself expires.
|
|
520
532
|
*/
|
|
521
533
|
async verifyAccessToken(token) {
|
|
522
534
|
try {
|
|
523
535
|
const cache = await this.getOrCreateJwksCache();
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
536
|
+
const result = await cache.withKeyRotationRetry(
|
|
537
|
+
(keySet) => jose.jwtVerify(token, keySet, {
|
|
538
|
+
issuer: this.expectedIssuer,
|
|
539
|
+
audience: this.expectedAudience,
|
|
540
|
+
algorithms: ["RS256"]
|
|
541
|
+
})
|
|
542
|
+
);
|
|
530
543
|
return { ok: true, payload: result.payload };
|
|
531
544
|
} catch (err2) {
|
|
532
545
|
return { ok: false, reason: err2 instanceof Error ? err2.message : "verify failed" };
|
|
@@ -545,11 +558,32 @@ var TokenRuntime = class _TokenRuntime {
|
|
|
545
558
|
this.storageKeyResolved = await sdkCore.deriveTenantStorageKey(this.crypto, this.tenantId, "refresh_token");
|
|
546
559
|
return this.storageKeyResolved;
|
|
547
560
|
}
|
|
561
|
+
/**
|
|
562
|
+
* The persisted JWKS-cache slot, scoped per-host in addition to per-tenant.
|
|
563
|
+
*
|
|
564
|
+
* `deriveTenantStorageKey`'s own domain separation is tenant-only, which was correct while every
|
|
565
|
+
* tenant verified against ONE platform-wide JWKS document. Now that a tenant's issuer host can
|
|
566
|
+
* change across the app's lifetime (a custom domain bound after this SDK version first shipped, or
|
|
567
|
+
* simply a dev pointed at a different host between builds), a slot keyed by tenant alone would
|
|
568
|
+
* silently reuse a PREVIOUS host's persisted document as this instance's "fresh" cache on cold
|
|
569
|
+
* start — cross-host reuse this offline-verification path must never do. The host segment is not
|
|
570
|
+
* secret (it is the caller's own `jwksUri` configuration), so a plain suffix is enough; this only
|
|
571
|
+
* needs to be a stable, DIFFERENT key per host, not a cryptographically-opaque one.
|
|
572
|
+
*/
|
|
548
573
|
async resolveJwksKey() {
|
|
549
574
|
if (this.jwksKeyResolved) return this.jwksKeyResolved;
|
|
550
|
-
|
|
575
|
+
const base = await sdkCore.deriveTenantStorageKey(this.crypto, this.tenantId, "jwks_cache");
|
|
576
|
+
const host = this.jwksHost();
|
|
577
|
+
this.jwksKeyResolved = host ? `${base}.h.${host}` : base;
|
|
551
578
|
return this.jwksKeyResolved;
|
|
552
579
|
}
|
|
580
|
+
jwksHost() {
|
|
581
|
+
try {
|
|
582
|
+
return new URL(this.jwksUri).hostname;
|
|
583
|
+
} catch {
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
553
587
|
async getOrCreateJwksCache() {
|
|
554
588
|
if (this.jwksCache) return this.jwksCache;
|
|
555
589
|
const key = await this.resolveJwksKey();
|
|
@@ -1051,6 +1085,7 @@ function RakomiProvider(props) {
|
|
|
1051
1085
|
clientId: props.publishableKey,
|
|
1052
1086
|
tenantId: props.tenantId ?? props.publishableKey,
|
|
1053
1087
|
tokenEndpoint,
|
|
1088
|
+
baseUrl: props.baseUrl,
|
|
1054
1089
|
storage: adapter.storage,
|
|
1055
1090
|
http,
|
|
1056
1091
|
crypto: adapter.crypto,
|
package/dist/index.d.cts
CHANGED
|
@@ -495,7 +495,7 @@ declare const MAX_WEBHOOK_TOLERANCE = 600;
|
|
|
495
495
|
/** Portable webhook-verify error class — the value IS the cross-SDK conformance `error_class`. */
|
|
496
496
|
type WebhookVerifyErrorClass = 'invalid_signature' | 'invalid_secret' | 'missing_header' | 'timestamp_too_old' | 'timestamp_too_new' | 'invalid_body';
|
|
497
497
|
/** Open-set publisher event type (the known catalog widened with the base string for forward-compat). */
|
|
498
|
-
type PublisherEventType = 'app.installed' | 'app.uninstalled' | 'app.install.scope_bump' | 'app.install.receipts_revoked' | 'publisher.created' | 'publisher.domain_verified' | 'publisher.dpa_accepted' | 'app.created' | 'app.version_published' | 'app.state_changed' | 'publisher.review_requested' | 'publisher.review_denied' | 'publisher.review_stale' | 'publisher.verified' | 'publisher.deverified' | 'publisher.subscription_activated' | 'publisher.subscription_lapsed';
|
|
498
|
+
type PublisherEventType = 'app.installed' | 'app.uninstalled' | 'app.install.scope_bump' | 'app.install.receipts_revoked' | 'publisher.created' | 'publisher.domain_verified' | 'publisher.dpa_accepted' | 'app.created' | 'app.version_published' | 'app.state_changed' | 'publisher.review_requested' | 'publisher.review_denied' | 'publisher.review_stale' | 'publisher.verified' | 'publisher.deverified' | 'publisher.subscription_activated' | 'publisher.subscription_lapsed' | 'app.version_pending_review' | 'app.pending_version_approved' | 'app.pending_version_rejected';
|
|
499
499
|
type PublisherWebhookEventType = PublisherEventType | (string & {});
|
|
500
500
|
/** The flat publisher-webhook delivery body. Unknown fields tolerated (forward-compat). No end-user PII. */
|
|
501
501
|
interface PublisherWebhookEvent {
|
package/dist/index.d.ts
CHANGED
|
@@ -495,7 +495,7 @@ declare const MAX_WEBHOOK_TOLERANCE = 600;
|
|
|
495
495
|
/** Portable webhook-verify error class — the value IS the cross-SDK conformance `error_class`. */
|
|
496
496
|
type WebhookVerifyErrorClass = 'invalid_signature' | 'invalid_secret' | 'missing_header' | 'timestamp_too_old' | 'timestamp_too_new' | 'invalid_body';
|
|
497
497
|
/** Open-set publisher event type (the known catalog widened with the base string for forward-compat). */
|
|
498
|
-
type PublisherEventType = 'app.installed' | 'app.uninstalled' | 'app.install.scope_bump' | 'app.install.receipts_revoked' | 'publisher.created' | 'publisher.domain_verified' | 'publisher.dpa_accepted' | 'app.created' | 'app.version_published' | 'app.state_changed' | 'publisher.review_requested' | 'publisher.review_denied' | 'publisher.review_stale' | 'publisher.verified' | 'publisher.deverified' | 'publisher.subscription_activated' | 'publisher.subscription_lapsed';
|
|
498
|
+
type PublisherEventType = 'app.installed' | 'app.uninstalled' | 'app.install.scope_bump' | 'app.install.receipts_revoked' | 'publisher.created' | 'publisher.domain_verified' | 'publisher.dpa_accepted' | 'app.created' | 'app.version_published' | 'app.state_changed' | 'publisher.review_requested' | 'publisher.review_denied' | 'publisher.review_stale' | 'publisher.verified' | 'publisher.deverified' | 'publisher.subscription_activated' | 'publisher.subscription_lapsed' | 'app.version_pending_review' | 'app.pending_version_approved' | 'app.pending_version_rejected';
|
|
499
499
|
type PublisherWebhookEventType = PublisherEventType | (string & {});
|
|
500
500
|
/** The flat publisher-webhook delivery body. Unknown fields tolerated (forward-compat). No end-user PII. */
|
|
501
501
|
interface PublisherWebhookEvent {
|
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, extractRequestId, 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, resolveExpectedIssuer } 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';
|
|
@@ -298,8 +298,19 @@ function deriveDefaultJwksUri(tokenEndpoint) {
|
|
|
298
298
|
}
|
|
299
299
|
var RAKOMI_PLATFORM_ISSUER_DEFAULT = "https://api.rakomi.com";
|
|
300
300
|
var RAKOMI_PLATFORM_AUDIENCE_DEFAULT = "https://api.rakomi.com";
|
|
301
|
-
function deriveDefaultIssuer(
|
|
302
|
-
|
|
301
|
+
function deriveDefaultIssuer(options) {
|
|
302
|
+
if (options.baseUrl) {
|
|
303
|
+
try {
|
|
304
|
+
new URL(options.baseUrl);
|
|
305
|
+
return resolveExpectedIssuer(options.baseUrl);
|
|
306
|
+
} catch {
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
return new URL(options.tokenEndpoint).origin;
|
|
311
|
+
} catch {
|
|
312
|
+
return RAKOMI_PLATFORM_ISSUER_DEFAULT;
|
|
313
|
+
}
|
|
303
314
|
}
|
|
304
315
|
var REFRESH_TOKEN_PREFIX = "v1:";
|
|
305
316
|
var REFRESH_BUFFER_SECONDS = 60;
|
|
@@ -359,7 +370,7 @@ var TokenRuntime = class _TokenRuntime {
|
|
|
359
370
|
this.clearTimeoutFn = options.clearTimeout ?? globalThis.clearTimeout.bind(globalThis);
|
|
360
371
|
this.jwksUri = options.jwksUri ?? deriveDefaultJwksUri(options.tokenEndpoint);
|
|
361
372
|
this.jwksTtlMs = options.jwksTtlMs ?? 24 * 60 * 60 * 1e3;
|
|
362
|
-
this.expectedIssuer = options.expectedIssuer ?? deriveDefaultIssuer(options.tokenEndpoint);
|
|
373
|
+
this.expectedIssuer = options.expectedIssuer ?? deriveDefaultIssuer({ baseUrl: options.baseUrl, tokenEndpoint: options.tokenEndpoint });
|
|
363
374
|
this.expectedAudience = options.expectedAudience ?? RAKOMI_PLATFORM_AUDIENCE_DEFAULT;
|
|
364
375
|
}
|
|
365
376
|
/**
|
|
@@ -514,18 +525,20 @@ var TokenRuntime = class _TokenRuntime {
|
|
|
514
525
|
*
|
|
515
526
|
* uses `jose.createLocalJWKSet` so verification is purely local once
|
|
516
527
|
* the JWKS document has been fetched and cached. The cache is preloaded from `KeyValueStore`
|
|
517
|
-
* on cold-start (slot `jwks_cache`) and refreshed on TTL miss
|
|
528
|
+
* on cold-start (slot `jwks_cache`) and refreshed on TTL miss, or once when the token's `kid` is not in
|
|
529
|
+
* the cached set (a rotated key; rate-limited by a cooldown); on persistent network failure
|
|
518
530
|
* the stale-while-error fallback keeps verification working until the cached doc itself expires.
|
|
519
531
|
*/
|
|
520
532
|
async verifyAccessToken(token) {
|
|
521
533
|
try {
|
|
522
534
|
const cache = await this.getOrCreateJwksCache();
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
535
|
+
const result = await cache.withKeyRotationRetry(
|
|
536
|
+
(keySet) => jwtVerify(token, keySet, {
|
|
537
|
+
issuer: this.expectedIssuer,
|
|
538
|
+
audience: this.expectedAudience,
|
|
539
|
+
algorithms: ["RS256"]
|
|
540
|
+
})
|
|
541
|
+
);
|
|
529
542
|
return { ok: true, payload: result.payload };
|
|
530
543
|
} catch (err2) {
|
|
531
544
|
return { ok: false, reason: err2 instanceof Error ? err2.message : "verify failed" };
|
|
@@ -544,11 +557,32 @@ var TokenRuntime = class _TokenRuntime {
|
|
|
544
557
|
this.storageKeyResolved = await deriveTenantStorageKey(this.crypto, this.tenantId, "refresh_token");
|
|
545
558
|
return this.storageKeyResolved;
|
|
546
559
|
}
|
|
560
|
+
/**
|
|
561
|
+
* The persisted JWKS-cache slot, scoped per-host in addition to per-tenant.
|
|
562
|
+
*
|
|
563
|
+
* `deriveTenantStorageKey`'s own domain separation is tenant-only, which was correct while every
|
|
564
|
+
* tenant verified against ONE platform-wide JWKS document. Now that a tenant's issuer host can
|
|
565
|
+
* change across the app's lifetime (a custom domain bound after this SDK version first shipped, or
|
|
566
|
+
* simply a dev pointed at a different host between builds), a slot keyed by tenant alone would
|
|
567
|
+
* silently reuse a PREVIOUS host's persisted document as this instance's "fresh" cache on cold
|
|
568
|
+
* start — cross-host reuse this offline-verification path must never do. The host segment is not
|
|
569
|
+
* secret (it is the caller's own `jwksUri` configuration), so a plain suffix is enough; this only
|
|
570
|
+
* needs to be a stable, DIFFERENT key per host, not a cryptographically-opaque one.
|
|
571
|
+
*/
|
|
547
572
|
async resolveJwksKey() {
|
|
548
573
|
if (this.jwksKeyResolved) return this.jwksKeyResolved;
|
|
549
|
-
|
|
574
|
+
const base = await deriveTenantStorageKey(this.crypto, this.tenantId, "jwks_cache");
|
|
575
|
+
const host = this.jwksHost();
|
|
576
|
+
this.jwksKeyResolved = host ? `${base}.h.${host}` : base;
|
|
550
577
|
return this.jwksKeyResolved;
|
|
551
578
|
}
|
|
579
|
+
jwksHost() {
|
|
580
|
+
try {
|
|
581
|
+
return new URL(this.jwksUri).hostname;
|
|
582
|
+
} catch {
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
552
586
|
async getOrCreateJwksCache() {
|
|
553
587
|
if (this.jwksCache) return this.jwksCache;
|
|
554
588
|
const key = await this.resolveJwksKey();
|
|
@@ -1050,6 +1084,7 @@ function RakomiProvider(props) {
|
|
|
1050
1084
|
clientId: props.publishableKey,
|
|
1051
1085
|
tenantId: props.tenantId ?? props.publishableKey,
|
|
1052
1086
|
tokenEndpoint,
|
|
1087
|
+
baseUrl: props.baseUrl,
|
|
1053
1088
|
storage: adapter.storage,
|
|
1054
1089
|
http,
|
|
1055
1090
|
crypto: adapter.crypto,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rakomi/react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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.6.0"
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"jose": "^6.2.3",
|
|
90
|
-
"@rakomi/sdk-core": "^0.
|
|
90
|
+
"@rakomi/sdk-core": "^0.6.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": "node ../../scripts/ci/vitest-fork-crash-retry.mjs --results ./test-results.json -- vitest run"
|
|
96
|
+
"test": "node ../../scripts/assert-not-story-agent-worktree.mjs 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.6.0",
|
|
30
30
|
"name": "@rakomi/react-native",
|
|
31
|
-
"version": "0.
|
|
32
|
-
"purl": "pkg:npm/%40rakomi%2Freact-native@0.
|
|
31
|
+
"version": "0.6.0",
|
|
32
|
+
"purl": "pkg:npm/%40rakomi%2Freact-native@0.6.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.6.0",
|
|
46
46
|
"name": "@rakomi/sdk-core",
|
|
47
|
-
"version": "0.
|
|
48
|
-
"purl": "pkg:npm/@rakomi/sdk-core@0.
|
|
47
|
+
"version": "0.6.0",
|
|
48
|
+
"purl": "pkg:npm/@rakomi/sdk-core@0.6.0",
|
|
49
49
|
"licenses": [
|
|
50
50
|
{
|
|
51
51
|
"license": {
|