@sendoracloud/sdk-react-native 0.10.0 → 0.10.2
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/dist/index.cjs +30 -7
- package/dist/index.d.cts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +30 -7
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -200,11 +200,14 @@ function isAuthApiResponse(v) {
|
|
|
200
200
|
const user = r.user;
|
|
201
201
|
const tokens = r.tokens;
|
|
202
202
|
if (!user || typeof user.id !== "string" || user.id.length === 0) return false;
|
|
203
|
-
if (typeof user.isAnonymous !== "boolean") return false;
|
|
204
203
|
if (!tokens) return false;
|
|
205
204
|
if (typeof tokens.accessToken !== "string" || tokens.accessToken.length === 0) return false;
|
|
206
205
|
if (typeof tokens.refreshToken !== "string" || tokens.refreshToken.length === 0) return false;
|
|
207
206
|
if (typeof tokens.expiresIn !== "number" || tokens.expiresIn <= 0) return false;
|
|
207
|
+
if (user.isAnonymous !== void 0 && typeof user.isAnonymous !== "boolean") return false;
|
|
208
|
+
if (user.email !== void 0 && user.email !== null && typeof user.email !== "string") return false;
|
|
209
|
+
if (user.emailVerified !== void 0 && typeof user.emailVerified !== "boolean") return false;
|
|
210
|
+
if (user.name !== void 0 && user.name !== null && typeof user.name !== "string") return false;
|
|
208
211
|
return true;
|
|
209
212
|
}
|
|
210
213
|
var EmailAlreadyTakenError = class extends Error {
|
|
@@ -280,11 +283,29 @@ var Auth = class {
|
|
|
280
283
|
return data.user;
|
|
281
284
|
});
|
|
282
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Create an email/password account.
|
|
288
|
+
*
|
|
289
|
+
* Industry-standard upgrade-first flow (matches Firebase
|
|
290
|
+
* `linkWithCredential`, Auth0 anonymous-merge, Supabase
|
|
291
|
+
* `linkIdentity`): when a refresh token is present in storage we
|
|
292
|
+
* try `/auth-service/upgrade` first — backend validates the
|
|
293
|
+
* refresh, checks the bound user is anonymous, and promotes in
|
|
294
|
+
* place preserving `user.id`. If the bound user is NOT anonymous
|
|
295
|
+
* (already identified, expired refresh, etc.), backend rejects
|
|
296
|
+
* with FORBIDDEN_NON_ANONYMOUS / INVALID_REFRESH and we fall back
|
|
297
|
+
* to a fresh /signup.
|
|
298
|
+
*
|
|
299
|
+
* Why we don't gate on the cached `this.user.isAnonymous`
|
|
300
|
+
* boolean: the in-memory user can be stale during cold start or
|
|
301
|
+
* fast-refresh races. The refresh token in storage is the
|
|
302
|
+
* authoritative signal — if it's there, the upgrade path is
|
|
303
|
+
* worth attempting; backend has the source of truth.
|
|
304
|
+
*/
|
|
283
305
|
signUp(email, password, opts) {
|
|
284
306
|
return this.serialize(async () => {
|
|
285
307
|
const refresh = this.hooks.storage.get(REFRESH_KEY);
|
|
286
|
-
|
|
287
|
-
if (isAnonymous && refresh) {
|
|
308
|
+
if (refresh) {
|
|
288
309
|
try {
|
|
289
310
|
const data = await this.callAuth("/api/v1/auth-service/upgrade", {
|
|
290
311
|
refreshToken: refresh,
|
|
@@ -298,11 +319,13 @@ var Auth = class {
|
|
|
298
319
|
if (err instanceof AuthError && (err.code === "CONFLICT" || err.code === "EMAIL_ALREADY_TAKEN")) {
|
|
299
320
|
throw new EmailAlreadyTakenError(err.message);
|
|
300
321
|
}
|
|
301
|
-
|
|
322
|
+
if (err instanceof AuthError && (err.code === "FORBIDDEN_NON_ANONYMOUS" || err.code === "INVALID_REFRESH" || err.code === "UNAUTHORIZED" || err.code === "REFRESH_EXPIRED")) {
|
|
323
|
+
await this.wipeLocalIdentity();
|
|
324
|
+
} else {
|
|
325
|
+
throw err;
|
|
326
|
+
}
|
|
302
327
|
}
|
|
303
328
|
}
|
|
304
|
-
const wasIdentified = this.user !== null && this.user.isAnonymous === false;
|
|
305
|
-
if (wasIdentified) await this.wipeLocalIdentity();
|
|
306
329
|
try {
|
|
307
330
|
const data = await this.callAuth("/api/v1/auth-service/signup", {
|
|
308
331
|
email,
|
|
@@ -767,7 +790,7 @@ function decodeJwtPayload(token) {
|
|
|
767
790
|
}
|
|
768
791
|
|
|
769
792
|
// src/index.ts
|
|
770
|
-
var SDK_VERSION = "0.10.
|
|
793
|
+
var SDK_VERSION = "0.10.2";
|
|
771
794
|
var DEFAULT_API_URL = "https://api.sendoracloud.com";
|
|
772
795
|
var ANON_KEY = "anon_id";
|
|
773
796
|
var USER_ID_KEY = "user_id";
|
package/dist/index.d.cts
CHANGED
|
@@ -123,6 +123,25 @@ declare class Auth {
|
|
|
123
123
|
name?: string;
|
|
124
124
|
metadata?: Record<string, unknown>;
|
|
125
125
|
}): Promise<AuthUser>;
|
|
126
|
+
/**
|
|
127
|
+
* Create an email/password account.
|
|
128
|
+
*
|
|
129
|
+
* Industry-standard upgrade-first flow (matches Firebase
|
|
130
|
+
* `linkWithCredential`, Auth0 anonymous-merge, Supabase
|
|
131
|
+
* `linkIdentity`): when a refresh token is present in storage we
|
|
132
|
+
* try `/auth-service/upgrade` first — backend validates the
|
|
133
|
+
* refresh, checks the bound user is anonymous, and promotes in
|
|
134
|
+
* place preserving `user.id`. If the bound user is NOT anonymous
|
|
135
|
+
* (already identified, expired refresh, etc.), backend rejects
|
|
136
|
+
* with FORBIDDEN_NON_ANONYMOUS / INVALID_REFRESH and we fall back
|
|
137
|
+
* to a fresh /signup.
|
|
138
|
+
*
|
|
139
|
+
* Why we don't gate on the cached `this.user.isAnonymous`
|
|
140
|
+
* boolean: the in-memory user can be stale during cold start or
|
|
141
|
+
* fast-refresh races. The refresh token in storage is the
|
|
142
|
+
* authoritative signal — if it's there, the upgrade path is
|
|
143
|
+
* worth attempting; backend has the source of truth.
|
|
144
|
+
*/
|
|
126
145
|
signUp(email: string, password: string, opts?: {
|
|
127
146
|
name?: string;
|
|
128
147
|
metadata?: Record<string, unknown>;
|
package/dist/index.d.ts
CHANGED
|
@@ -123,6 +123,25 @@ declare class Auth {
|
|
|
123
123
|
name?: string;
|
|
124
124
|
metadata?: Record<string, unknown>;
|
|
125
125
|
}): Promise<AuthUser>;
|
|
126
|
+
/**
|
|
127
|
+
* Create an email/password account.
|
|
128
|
+
*
|
|
129
|
+
* Industry-standard upgrade-first flow (matches Firebase
|
|
130
|
+
* `linkWithCredential`, Auth0 anonymous-merge, Supabase
|
|
131
|
+
* `linkIdentity`): when a refresh token is present in storage we
|
|
132
|
+
* try `/auth-service/upgrade` first — backend validates the
|
|
133
|
+
* refresh, checks the bound user is anonymous, and promotes in
|
|
134
|
+
* place preserving `user.id`. If the bound user is NOT anonymous
|
|
135
|
+
* (already identified, expired refresh, etc.), backend rejects
|
|
136
|
+
* with FORBIDDEN_NON_ANONYMOUS / INVALID_REFRESH and we fall back
|
|
137
|
+
* to a fresh /signup.
|
|
138
|
+
*
|
|
139
|
+
* Why we don't gate on the cached `this.user.isAnonymous`
|
|
140
|
+
* boolean: the in-memory user can be stale during cold start or
|
|
141
|
+
* fast-refresh races. The refresh token in storage is the
|
|
142
|
+
* authoritative signal — if it's there, the upgrade path is
|
|
143
|
+
* worth attempting; backend has the source of truth.
|
|
144
|
+
*/
|
|
126
145
|
signUp(email: string, password: string, opts?: {
|
|
127
146
|
name?: string;
|
|
128
147
|
metadata?: Record<string, unknown>;
|
package/dist/index.js
CHANGED
|
@@ -160,11 +160,14 @@ function isAuthApiResponse(v) {
|
|
|
160
160
|
const user = r.user;
|
|
161
161
|
const tokens = r.tokens;
|
|
162
162
|
if (!user || typeof user.id !== "string" || user.id.length === 0) return false;
|
|
163
|
-
if (typeof user.isAnonymous !== "boolean") return false;
|
|
164
163
|
if (!tokens) return false;
|
|
165
164
|
if (typeof tokens.accessToken !== "string" || tokens.accessToken.length === 0) return false;
|
|
166
165
|
if (typeof tokens.refreshToken !== "string" || tokens.refreshToken.length === 0) return false;
|
|
167
166
|
if (typeof tokens.expiresIn !== "number" || tokens.expiresIn <= 0) return false;
|
|
167
|
+
if (user.isAnonymous !== void 0 && typeof user.isAnonymous !== "boolean") return false;
|
|
168
|
+
if (user.email !== void 0 && user.email !== null && typeof user.email !== "string") return false;
|
|
169
|
+
if (user.emailVerified !== void 0 && typeof user.emailVerified !== "boolean") return false;
|
|
170
|
+
if (user.name !== void 0 && user.name !== null && typeof user.name !== "string") return false;
|
|
168
171
|
return true;
|
|
169
172
|
}
|
|
170
173
|
var EmailAlreadyTakenError = class extends Error {
|
|
@@ -240,11 +243,29 @@ var Auth = class {
|
|
|
240
243
|
return data.user;
|
|
241
244
|
});
|
|
242
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* Create an email/password account.
|
|
248
|
+
*
|
|
249
|
+
* Industry-standard upgrade-first flow (matches Firebase
|
|
250
|
+
* `linkWithCredential`, Auth0 anonymous-merge, Supabase
|
|
251
|
+
* `linkIdentity`): when a refresh token is present in storage we
|
|
252
|
+
* try `/auth-service/upgrade` first — backend validates the
|
|
253
|
+
* refresh, checks the bound user is anonymous, and promotes in
|
|
254
|
+
* place preserving `user.id`. If the bound user is NOT anonymous
|
|
255
|
+
* (already identified, expired refresh, etc.), backend rejects
|
|
256
|
+
* with FORBIDDEN_NON_ANONYMOUS / INVALID_REFRESH and we fall back
|
|
257
|
+
* to a fresh /signup.
|
|
258
|
+
*
|
|
259
|
+
* Why we don't gate on the cached `this.user.isAnonymous`
|
|
260
|
+
* boolean: the in-memory user can be stale during cold start or
|
|
261
|
+
* fast-refresh races. The refresh token in storage is the
|
|
262
|
+
* authoritative signal — if it's there, the upgrade path is
|
|
263
|
+
* worth attempting; backend has the source of truth.
|
|
264
|
+
*/
|
|
243
265
|
signUp(email, password, opts) {
|
|
244
266
|
return this.serialize(async () => {
|
|
245
267
|
const refresh = this.hooks.storage.get(REFRESH_KEY);
|
|
246
|
-
|
|
247
|
-
if (isAnonymous && refresh) {
|
|
268
|
+
if (refresh) {
|
|
248
269
|
try {
|
|
249
270
|
const data = await this.callAuth("/api/v1/auth-service/upgrade", {
|
|
250
271
|
refreshToken: refresh,
|
|
@@ -258,11 +279,13 @@ var Auth = class {
|
|
|
258
279
|
if (err instanceof AuthError && (err.code === "CONFLICT" || err.code === "EMAIL_ALREADY_TAKEN")) {
|
|
259
280
|
throw new EmailAlreadyTakenError(err.message);
|
|
260
281
|
}
|
|
261
|
-
|
|
282
|
+
if (err instanceof AuthError && (err.code === "FORBIDDEN_NON_ANONYMOUS" || err.code === "INVALID_REFRESH" || err.code === "UNAUTHORIZED" || err.code === "REFRESH_EXPIRED")) {
|
|
283
|
+
await this.wipeLocalIdentity();
|
|
284
|
+
} else {
|
|
285
|
+
throw err;
|
|
286
|
+
}
|
|
262
287
|
}
|
|
263
288
|
}
|
|
264
|
-
const wasIdentified = this.user !== null && this.user.isAnonymous === false;
|
|
265
|
-
if (wasIdentified) await this.wipeLocalIdentity();
|
|
266
289
|
try {
|
|
267
290
|
const data = await this.callAuth("/api/v1/auth-service/signup", {
|
|
268
291
|
email,
|
|
@@ -727,7 +750,7 @@ function decodeJwtPayload(token) {
|
|
|
727
750
|
}
|
|
728
751
|
|
|
729
752
|
// src/index.ts
|
|
730
|
-
var SDK_VERSION = "0.10.
|
|
753
|
+
var SDK_VERSION = "0.10.2";
|
|
731
754
|
var DEFAULT_API_URL = "https://api.sendoracloud.com";
|
|
732
755
|
var ANON_KEY = "anon_id";
|
|
733
756
|
var USER_ID_KEY = "user_id";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sendoracloud/sdk-react-native",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "Sendora Cloud React Native + Expo SDK — analytics, identity, push-token registration, auth. Expo Go compatible, no native modules beyond AsyncStorage.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|