jazz-react-native 0.8.41 → 0.8.46
Sign up to get free protection for your applications and to get access to all the features.
- package/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +29 -0
- package/dist/auth/DemoAuthMethod.js +58 -23
- package/dist/auth/DemoAuthMethod.js.map +1 -1
- package/dist/crypto/RNQuickCrypto.d.ts +12 -0
- package/dist/crypto/RNQuickCrypto.js +31 -0
- package/dist/crypto/RNQuickCrypto.js.map +1 -0
- package/dist/crypto/index.d.ts +1 -0
- package/dist/crypto/index.js +2 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +52 -21
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +5 -5
- package/dist/provider.js +3 -1
- package/dist/provider.js.map +1 -1
- package/dist/tests/DemoAuthMethod.test.d.ts +1 -0
- package/dist/tests/DemoAuthMethod.test.js +186 -0
- package/dist/tests/DemoAuthMethod.test.js.map +1 -0
- package/package.json +11 -6
- package/src/auth/DemoAuthMethod.ts +77 -41
- package/src/crypto/RNQuickCrypto.ts +58 -0
- package/src/crypto/index.ts +1 -0
- package/src/index.ts +60 -25
- package/src/provider.tsx +8 -0
- package/src/tests/DemoAuthMethod.test.ts +282 -0
@@ -0,0 +1,186 @@
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
2
|
+
import { RNDemoAuth } from "../auth/DemoAuthMethod";
|
3
|
+
import { KvStoreContext } from "../storage/kv-store-context";
|
4
|
+
// Initialize mock storage
|
5
|
+
const mockStorage = {};
|
6
|
+
// Mock KvStore implementation
|
7
|
+
const mockKvStore = {
|
8
|
+
get: vi.fn(async (key) => mockStorage[key] || null),
|
9
|
+
set: vi.fn(async (key, value) => {
|
10
|
+
mockStorage[key] = value;
|
11
|
+
}),
|
12
|
+
delete: vi.fn(async (key) => {
|
13
|
+
delete mockStorage[key];
|
14
|
+
}),
|
15
|
+
clearAll: vi.fn(async () => {
|
16
|
+
Object.keys(mockStorage).forEach((key) => delete mockStorage[key]);
|
17
|
+
}),
|
18
|
+
};
|
19
|
+
KvStoreContext.getInstance().initialize(mockKvStore);
|
20
|
+
beforeEach(() => {
|
21
|
+
mockKvStore.clearAll();
|
22
|
+
vi.clearAllMocks();
|
23
|
+
});
|
24
|
+
function setup() {
|
25
|
+
const mockDriver = {
|
26
|
+
onReady: vi.fn(),
|
27
|
+
onSignedIn: vi.fn(),
|
28
|
+
onError: vi.fn(),
|
29
|
+
};
|
30
|
+
return {
|
31
|
+
mockStorage,
|
32
|
+
mockKvStore,
|
33
|
+
mockDriver,
|
34
|
+
};
|
35
|
+
}
|
36
|
+
describe("RNDemoAuth", () => {
|
37
|
+
describe("initialization", () => {
|
38
|
+
it("should initialize with seed accounts", async () => {
|
39
|
+
const { mockKvStore, mockDriver } = setup();
|
40
|
+
const seedAccounts = {
|
41
|
+
testUser: {
|
42
|
+
accountID: "test-account-id",
|
43
|
+
accountSecret: "test-secret",
|
44
|
+
},
|
45
|
+
};
|
46
|
+
await RNDemoAuth.init(mockDriver, seedAccounts);
|
47
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users", "testUser");
|
48
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users-" + btoa("testUser"), expect.any(String));
|
49
|
+
});
|
50
|
+
});
|
51
|
+
describe("authentication", () => {
|
52
|
+
it("should handle new user signup", async () => {
|
53
|
+
const { mockDriver } = setup();
|
54
|
+
mockDriver.onReady = vi.fn(({ signUp }) => {
|
55
|
+
signUp("testUser");
|
56
|
+
});
|
57
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
58
|
+
const result = await auth.start();
|
59
|
+
expect(mockDriver.onReady).toHaveBeenCalled();
|
60
|
+
expect(result.type).toBe("new");
|
61
|
+
expect(result.saveCredentials).toBeDefined();
|
62
|
+
});
|
63
|
+
it("should handle existing user login", async () => {
|
64
|
+
const { mockStorage, mockDriver } = setup();
|
65
|
+
// Set up existing user in storage
|
66
|
+
const existingUser = {
|
67
|
+
accountID: "test-account-id",
|
68
|
+
accountSecret: "test-secret",
|
69
|
+
};
|
70
|
+
mockStorage["demo-auth-logged-in-secret"] = JSON.stringify(existingUser);
|
71
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
72
|
+
const result = await auth.start();
|
73
|
+
if (result.type !== "existing") {
|
74
|
+
throw new Error("Result is not a existing user");
|
75
|
+
}
|
76
|
+
expect(result.type).toBe("existing");
|
77
|
+
expect(result.credentials).toEqual({
|
78
|
+
accountID: existingUser.accountID,
|
79
|
+
secret: existingUser.accountSecret,
|
80
|
+
});
|
81
|
+
});
|
82
|
+
it("should handle logout", async () => {
|
83
|
+
const { mockKvStore, mockDriver } = setup();
|
84
|
+
mockDriver.onReady = vi.fn(({ signUp }) => {
|
85
|
+
signUp("testUser");
|
86
|
+
});
|
87
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
88
|
+
const result = await auth.start();
|
89
|
+
await result.logOut();
|
90
|
+
expect(mockKvStore.delete).toHaveBeenCalledWith("demo-auth-logged-in-secret");
|
91
|
+
});
|
92
|
+
});
|
93
|
+
describe("user management", () => {
|
94
|
+
it("should signup a new user", async () => {
|
95
|
+
const { mockKvStore, mockDriver } = setup();
|
96
|
+
mockDriver.onReady = vi.fn(({ signUp }) => {
|
97
|
+
return signUp("testUser");
|
98
|
+
});
|
99
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
100
|
+
const result = await auth.start();
|
101
|
+
if (result.type !== "new") {
|
102
|
+
throw new Error("Result is not a new user");
|
103
|
+
}
|
104
|
+
await result.saveCredentials({
|
105
|
+
accountID: "test-account-id",
|
106
|
+
secret: "test-secret",
|
107
|
+
});
|
108
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users-" + btoa("testUser"), expect.any(String));
|
109
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users", "testUser");
|
110
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-logged-in-secret", expect.any(String));
|
111
|
+
});
|
112
|
+
it("should login an existing user", async () => {
|
113
|
+
const { mockStorage, mockKvStore, mockDriver } = setup();
|
114
|
+
const credentials = {
|
115
|
+
accountID: "test-account-id",
|
116
|
+
accountSecret: "test-secret",
|
117
|
+
};
|
118
|
+
mockStorage["demo-auth-existing-users-" + btoa("testUser")] =
|
119
|
+
JSON.stringify(credentials);
|
120
|
+
mockDriver.onReady = vi.fn(({ logInAs }) => {
|
121
|
+
return logInAs("testUser");
|
122
|
+
});
|
123
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
124
|
+
const result = await auth.start();
|
125
|
+
if (result.type !== "existing") {
|
126
|
+
throw new Error("Result is not a existing user");
|
127
|
+
}
|
128
|
+
expect(result.credentials).toEqual({
|
129
|
+
accountID: credentials.accountID,
|
130
|
+
secret: credentials.accountSecret,
|
131
|
+
});
|
132
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-logged-in-secret", JSON.stringify(credentials));
|
133
|
+
});
|
134
|
+
it("should handle duplicate usernames by adding suffix", async () => {
|
135
|
+
const { mockStorage, mockKvStore, mockDriver } = setup();
|
136
|
+
mockDriver.onReady = vi.fn(({ signUp }) => {
|
137
|
+
return signUp("testUser");
|
138
|
+
});
|
139
|
+
mockStorage["demo-auth-existing-users"] = "testUser";
|
140
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
141
|
+
const result = await auth.start();
|
142
|
+
if (result.type !== "new") {
|
143
|
+
throw new Error("Result is not a new user");
|
144
|
+
}
|
145
|
+
await result.saveCredentials({
|
146
|
+
accountID: "test-account-id",
|
147
|
+
secret: "test-secret",
|
148
|
+
});
|
149
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users-" + btoa("testUser-2"), expect.any(String));
|
150
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users", "testUser,testUser-2");
|
151
|
+
});
|
152
|
+
it("should retrieve existing users", async () => {
|
153
|
+
const { mockStorage, mockDriver } = setup();
|
154
|
+
mockDriver.onReady = vi.fn(({ signUp }) => {
|
155
|
+
return signUp("testUser");
|
156
|
+
});
|
157
|
+
mockStorage["demo-auth-existing-users"] = "user1,user2,user3";
|
158
|
+
const auth = await RNDemoAuth.init(mockDriver);
|
159
|
+
const result = await auth.start();
|
160
|
+
if (result.type !== "new") {
|
161
|
+
throw new Error("Result is not a new user");
|
162
|
+
}
|
163
|
+
await result.saveCredentials({
|
164
|
+
accountID: "test-account-id",
|
165
|
+
secret: "test-secret",
|
166
|
+
});
|
167
|
+
const onReadyCall = vi.mocked(mockDriver.onReady).mock.calls[0][0];
|
168
|
+
const existingUsers = await onReadyCall.getExistingUsers();
|
169
|
+
expect(existingUsers).toEqual(["user1", "user2", "user3", "testUser"]);
|
170
|
+
});
|
171
|
+
it("should migrate legacy user keys to the new format", async () => {
|
172
|
+
const { mockStorage, mockKvStore, mockDriver } = setup();
|
173
|
+
const value = JSON.stringify({
|
174
|
+
accountID: "test-account-id",
|
175
|
+
accountSecret: "test-secret",
|
176
|
+
});
|
177
|
+
mockStorage["demo-auth-existing-users"] = "testUser";
|
178
|
+
mockStorage["demo-auth-existing-users-testUser"] = value;
|
179
|
+
await RNDemoAuth.init(mockDriver);
|
180
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-existing-users-" + btoa("testUser"), value);
|
181
|
+
expect(mockKvStore.set).toHaveBeenCalledWith("demo-auth-storage-version", "2");
|
182
|
+
expect(mockKvStore.delete).toHaveBeenCalledWith("demo-auth-existing-users-testUser");
|
183
|
+
});
|
184
|
+
});
|
185
|
+
});
|
186
|
+
//# sourceMappingURL=DemoAuthMethod.test.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"DemoAuthMethod.test.js","sourceRoot":"","sources":["../../src/tests/DemoAuthMethod.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "jazz-react-native",
|
3
|
-
"version": "0.8.
|
3
|
+
"version": "0.8.46",
|
4
4
|
"type": "module",
|
5
5
|
"main": "./dist/index.js",
|
6
6
|
"module": "./dist/index.js",
|
@@ -11,24 +11,29 @@
|
|
11
11
|
"react-native": "./dist/index.js",
|
12
12
|
"types": "./dist/index.d.ts",
|
13
13
|
"default": "./dist/index.js"
|
14
|
+
},
|
15
|
+
"./crypto": {
|
16
|
+
"react-native": "./dist/crypto/index.js",
|
17
|
+
"types": "./dist/crypto/index.d.ts",
|
18
|
+
"default": "./dist/crypto/index.js"
|
14
19
|
}
|
15
20
|
},
|
16
21
|
"license": "MIT",
|
17
22
|
"dependencies": {
|
23
|
+
"@scure/base": "1.2.1",
|
18
24
|
"@scure/bip39": "^1.3.0",
|
19
|
-
"
|
20
|
-
"cojson
|
21
|
-
"
|
25
|
+
"react-native-quick-crypto": "1.0.0-beta.9",
|
26
|
+
"cojson": "0.8.45",
|
27
|
+
"cojson-transport-ws": "0.8.45",
|
28
|
+
"jazz-tools": "0.8.45"
|
22
29
|
},
|
23
30
|
"peerDependencies": {
|
24
31
|
"@react-native-community/netinfo": "*",
|
25
|
-
"expo-linking": "*",
|
26
32
|
"expo-secure-store": "*",
|
27
33
|
"react-native": "*"
|
28
34
|
},
|
29
35
|
"devDependencies": {
|
30
36
|
"@react-native-community/netinfo": "^11.4.1",
|
31
|
-
"expo-linking": "~7.0.3",
|
32
37
|
"expo-secure-store": "~14.0.0",
|
33
38
|
"react-native": "~0.76.3",
|
34
39
|
"typescript": "~5.6.2"
|
@@ -23,6 +23,69 @@ export namespace RNDemoAuth {
|
|
23
23
|
|
24
24
|
const localStorageKey = "demo-auth-logged-in-secret";
|
25
25
|
|
26
|
+
function getUserStorageKey(username: string) {
|
27
|
+
return `demo-auth-existing-users-${btoa(username)}`;
|
28
|
+
}
|
29
|
+
|
30
|
+
function getLegacyUserStorageKey(username: string) {
|
31
|
+
return `demo-auth-existing-users-${username}`;
|
32
|
+
}
|
33
|
+
|
34
|
+
async function getStorageVersion(kvStore: KvStore) {
|
35
|
+
try {
|
36
|
+
const version = await kvStore.get("demo-auth-storage-version");
|
37
|
+
return version ? parseInt(version) : 1;
|
38
|
+
} catch (error) {
|
39
|
+
return 1;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
async function setStorageVersion(kvStore: KvStore, version: number) {
|
44
|
+
await kvStore.set("demo-auth-storage-version", version.toString());
|
45
|
+
}
|
46
|
+
|
47
|
+
async function getExistingUsers(kvStore: KvStore) {
|
48
|
+
const existingUsers = await kvStore.get("demo-auth-existing-users");
|
49
|
+
return existingUsers ? existingUsers.split(",") : [];
|
50
|
+
}
|
51
|
+
|
52
|
+
async function addUserToExistingUsers(username: string, kvStore: KvStore) {
|
53
|
+
const existingUsers = await getExistingUsers(kvStore);
|
54
|
+
|
55
|
+
if (existingUsers.includes(username)) {
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
|
59
|
+
await kvStore.set(
|
60
|
+
"demo-auth-existing-users",
|
61
|
+
existingUsers.concat(username).join(","),
|
62
|
+
);
|
63
|
+
}
|
64
|
+
|
65
|
+
/**
|
66
|
+
* Migrates existing users keys to use a base64 encoded username.
|
67
|
+
*
|
68
|
+
* This is done to avoid issues with special characters in the username.
|
69
|
+
*/
|
70
|
+
async function migrateExistingUsersKeys(kvStore: KvStore) {
|
71
|
+
if ((await getStorageVersion(kvStore)) >= 2) {
|
72
|
+
return;
|
73
|
+
}
|
74
|
+
|
75
|
+
await setStorageVersion(kvStore, 2);
|
76
|
+
|
77
|
+
const existingUsers = await getExistingUsers(kvStore);
|
78
|
+
|
79
|
+
for (const existingUsername of existingUsers) {
|
80
|
+
const legacyKey = getLegacyUserStorageKey(existingUsername);
|
81
|
+
const storageData = await kvStore.get(legacyKey);
|
82
|
+
if (storageData) {
|
83
|
+
await kvStore.set(getUserStorageKey(existingUsername), storageData);
|
84
|
+
await kvStore.delete(legacyKey);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
26
89
|
export class RNDemoAuth implements AuthMethod {
|
27
90
|
private constructor(
|
28
91
|
private driver: RNDemoAuth.Driver,
|
@@ -39,27 +102,16 @@ export class RNDemoAuth implements AuthMethod {
|
|
39
102
|
},
|
40
103
|
) {
|
41
104
|
const kvStore = KvStoreContext.getInstance().getStorage();
|
105
|
+
|
106
|
+
await migrateExistingUsersKeys(kvStore);
|
107
|
+
|
42
108
|
for (const [name, credentials] of Object.entries(seedAccounts || {})) {
|
43
109
|
const storageData = JSON.stringify(credentials satisfies StorageData);
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
| string[]
|
48
|
-
| undefined
|
49
|
-
)?.includes(name)
|
50
|
-
) {
|
51
|
-
const existingUsers = await kvStore.get("demo-auth-existing-users");
|
52
|
-
if (existingUsers) {
|
53
|
-
await kvStore.set(
|
54
|
-
"demo-auth-existing-users",
|
55
|
-
existingUsers + "," + name,
|
56
|
-
);
|
57
|
-
} else {
|
58
|
-
await kvStore.set("demo-auth-existing-users", name);
|
59
|
-
}
|
60
|
-
}
|
61
|
-
await kvStore.set("demo-auth-existing-users-" + name, storageData);
|
110
|
+
|
111
|
+
await addUserToExistingUsers(name, kvStore);
|
112
|
+
await kvStore.set(getUserStorageKey(name), storageData);
|
62
113
|
}
|
114
|
+
|
63
115
|
return new RNDemoAuth(driver, kvStore);
|
64
116
|
}
|
65
117
|
|
@@ -103,13 +155,9 @@ export class RNDemoAuth implements AuthMethod {
|
|
103
155
|
accountSecret: credentials.secret,
|
104
156
|
} satisfies StorageData);
|
105
157
|
|
106
|
-
|
107
|
-
|
108
|
-
"demo-auth-existing-users",
|
158
|
+
const existingUsernames = await getExistingUsers(
|
159
|
+
this.kvStore,
|
109
160
|
);
|
110
|
-
const existingUsernames = existingUsers
|
111
|
-
? existingUsers.split(",")
|
112
|
-
: [];
|
113
161
|
|
114
162
|
// Determine if the username already exists and generate a unique username
|
115
163
|
let uniqueUsername = username;
|
@@ -122,18 +170,11 @@ export class RNDemoAuth implements AuthMethod {
|
|
122
170
|
// Save credentials using the unique username
|
123
171
|
await this.kvStore.set(localStorageKey, storageData);
|
124
172
|
await this.kvStore.set(
|
125
|
-
|
173
|
+
getUserStorageKey(uniqueUsername),
|
126
174
|
storageData,
|
127
175
|
);
|
128
176
|
|
129
|
-
|
130
|
-
const updatedUsers = existingUsers
|
131
|
-
? `${existingUsers},${uniqueUsername}`
|
132
|
-
: uniqueUsername;
|
133
|
-
await this.kvStore.set(
|
134
|
-
"demo-auth-existing-users",
|
135
|
-
updatedUsers,
|
136
|
-
);
|
177
|
+
await addUserToExistingUsers(uniqueUsername, this.kvStore);
|
137
178
|
},
|
138
179
|
onSuccess: () => {
|
139
180
|
this.driver.onSignedIn({ logOut });
|
@@ -149,17 +190,12 @@ export class RNDemoAuth implements AuthMethod {
|
|
149
190
|
});
|
150
191
|
},
|
151
192
|
getExistingUsers: async () => {
|
152
|
-
return (
|
153
|
-
(await this.kvStore.get("demo-auth-existing-users"))?.split(
|
154
|
-
",",
|
155
|
-
) ?? []
|
156
|
-
);
|
193
|
+
return await getExistingUsers(this.kvStore);
|
157
194
|
},
|
158
195
|
logInAs: async (existingUser) => {
|
159
196
|
const storageData = JSON.parse(
|
160
|
-
(await this.kvStore.get(
|
161
|
-
"
|
162
|
-
)) ?? "{}",
|
197
|
+
(await this.kvStore.get(getUserStorageKey(existingUser))) ??
|
198
|
+
"{}",
|
163
199
|
) as StorageData;
|
164
200
|
|
165
201
|
await this.kvStore.set(
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import { base58 } from "@scure/base";
|
2
|
+
import { JsonValue, PureJSCrypto } from "cojson/native";
|
3
|
+
import { CojsonInternalTypes, cojsonInternals } from "cojson/native";
|
4
|
+
import { Ed } from "react-native-quick-crypto";
|
5
|
+
const { stableStringify } = cojsonInternals;
|
6
|
+
|
7
|
+
const textEncoder = new TextEncoder();
|
8
|
+
|
9
|
+
export class RNQuickCrypto extends PureJSCrypto {
|
10
|
+
ed: Ed;
|
11
|
+
|
12
|
+
constructor() {
|
13
|
+
super();
|
14
|
+
this.ed = new Ed("ed25519", {});
|
15
|
+
}
|
16
|
+
|
17
|
+
static async create(): Promise<RNQuickCrypto> {
|
18
|
+
return new RNQuickCrypto();
|
19
|
+
}
|
20
|
+
|
21
|
+
newEd25519SigningKey(): Uint8Array {
|
22
|
+
this.ed.generateKeyPairSync();
|
23
|
+
return new Uint8Array(this.ed.getPrivateKey());
|
24
|
+
}
|
25
|
+
|
26
|
+
getSignerID(
|
27
|
+
secret: CojsonInternalTypes.SignerSecret,
|
28
|
+
): CojsonInternalTypes.SignerID {
|
29
|
+
return `signer_z${base58.encode(
|
30
|
+
base58.decode(secret.substring("signerSecret_z".length)),
|
31
|
+
)}`;
|
32
|
+
}
|
33
|
+
|
34
|
+
sign(
|
35
|
+
secret: CojsonInternalTypes.SignerSecret,
|
36
|
+
message: JsonValue,
|
37
|
+
): CojsonInternalTypes.Signature {
|
38
|
+
const signature = new Uint8Array(
|
39
|
+
this.ed.signSync(
|
40
|
+
textEncoder.encode(stableStringify(message)),
|
41
|
+
base58.decode(secret.substring("signerSecret_z".length)),
|
42
|
+
),
|
43
|
+
);
|
44
|
+
return `signature_z${base58.encode(signature)}`;
|
45
|
+
}
|
46
|
+
|
47
|
+
verify(
|
48
|
+
signature: CojsonInternalTypes.Signature,
|
49
|
+
message: JsonValue,
|
50
|
+
id: CojsonInternalTypes.SignerID,
|
51
|
+
): boolean {
|
52
|
+
return this.ed.verifySync(
|
53
|
+
base58.decode(signature.substring("signature_z".length)),
|
54
|
+
textEncoder.encode(stableStringify(message)),
|
55
|
+
base58.decode(id.substring("signer_z".length)),
|
56
|
+
);
|
57
|
+
}
|
58
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export { RNQuickCrypto } from "./RNQuickCrypto.js";
|
package/src/index.ts
CHANGED
@@ -15,15 +15,13 @@ import {
|
|
15
15
|
createJazzContext,
|
16
16
|
} from "jazz-tools";
|
17
17
|
|
18
|
-
import NetInfo from "@react-native-community/netinfo";
|
19
18
|
import { RawAccountID } from "cojson";
|
20
|
-
import { createWebSocketPeer } from "cojson-transport-ws";
|
21
|
-
import * as Linking from "expo-linking";
|
22
|
-
import { PureJSCrypto } from "jazz-tools/native";
|
23
19
|
|
24
20
|
export { RNDemoAuth } from "./auth/DemoAuthMethod.js";
|
25
21
|
|
22
|
+
import { PureJSCrypto } from "cojson/native";
|
26
23
|
import { createWebSocketPeerWithReconnection } from "./createWebSocketPeerWithReconnection.js";
|
24
|
+
import type { RNQuickCrypto } from "./crypto/RNQuickCrypto.js";
|
27
25
|
import { KvStoreContext } from "./storage/kv-store-context.js";
|
28
26
|
|
29
27
|
/** @category Context Creation */
|
@@ -51,7 +49,7 @@ export type BaseReactNativeContextOptions = {
|
|
51
49
|
peer: `wss://${string}` | `ws://${string}`;
|
52
50
|
reconnectionTimeout?: number;
|
53
51
|
storage?: "indexedDB" | "singleTabOPFS";
|
54
|
-
|
52
|
+
CryptoProvider?: typeof PureJSCrypto | typeof RNQuickCrypto;
|
55
53
|
};
|
56
54
|
|
57
55
|
/** @category Context Creation */
|
@@ -75,17 +73,19 @@ export async function createJazzRNContext<Acc extends Account>(
|
|
75
73
|
},
|
76
74
|
);
|
77
75
|
|
76
|
+
const CryptoProvider = options.CryptoProvider || PureJSCrypto;
|
77
|
+
|
78
78
|
const context =
|
79
79
|
"auth" in options
|
80
80
|
? await createJazzContext({
|
81
81
|
AccountSchema: options.AccountSchema,
|
82
82
|
auth: options.auth,
|
83
|
-
crypto: await
|
83
|
+
crypto: await CryptoProvider.create(),
|
84
84
|
peersToLoadFrom: [websocketPeer.peer],
|
85
85
|
sessionProvider: provideLockSession,
|
86
86
|
})
|
87
87
|
: await createJazzContext({
|
88
|
-
crypto: await
|
88
|
+
crypto: await CryptoProvider.create(),
|
89
89
|
peersToLoadFrom: [websocketPeer.peer],
|
90
90
|
});
|
91
91
|
|
@@ -165,6 +165,7 @@ export function createInviteLink<C extends CoValue>(
|
|
165
165
|
}
|
166
166
|
|
167
167
|
/** @category Invite Links */
|
168
|
+
// TODO: copied from jazz-browser, should be shared
|
168
169
|
export function parseInviteLink<C extends CoValue>(
|
169
170
|
inviteURL: string,
|
170
171
|
):
|
@@ -174,33 +175,67 @@ export function parseInviteLink<C extends CoValue>(
|
|
174
175
|
inviteSecret: InviteSecret;
|
175
176
|
}
|
176
177
|
| undefined {
|
177
|
-
const url =
|
178
|
-
const parts = url.
|
179
|
-
|
180
|
-
if (!parts || parts[0] !== "invite") {
|
181
|
-
return undefined;
|
182
|
-
}
|
178
|
+
const url = new URL(inviteURL);
|
179
|
+
const parts = url.hash.split("/");
|
183
180
|
|
184
181
|
let valueHint: string | undefined;
|
185
182
|
let valueID: ID<C> | undefined;
|
186
183
|
let inviteSecret: InviteSecret | undefined;
|
187
184
|
|
188
|
-
if (parts
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
185
|
+
if (parts[0] === "#" && parts[1] === "invite") {
|
186
|
+
if (parts.length === 5) {
|
187
|
+
valueHint = parts[2];
|
188
|
+
valueID = parts[3] as ID<C>;
|
189
|
+
inviteSecret = parts[4] as InviteSecret;
|
190
|
+
} else if (parts.length === 4) {
|
191
|
+
valueID = parts[2] as ID<C>;
|
192
|
+
inviteSecret = parts[3] as InviteSecret;
|
193
|
+
}
|
196
194
|
|
197
|
-
|
198
|
-
|
195
|
+
if (!valueID || !inviteSecret) {
|
196
|
+
return undefined;
|
197
|
+
}
|
198
|
+
return { valueID, inviteSecret, valueHint };
|
199
199
|
}
|
200
|
-
|
201
|
-
return { valueID, inviteSecret, valueHint };
|
202
200
|
}
|
203
201
|
|
202
|
+
// getting out of the `expo` business 🤞
|
203
|
+
// export function parseInviteLink<C extends CoValue>(
|
204
|
+
// inviteURL: string,
|
205
|
+
// ):
|
206
|
+
// | {
|
207
|
+
// valueID: ID<C>;
|
208
|
+
// valueHint?: string;
|
209
|
+
// inviteSecret: InviteSecret;
|
210
|
+
// }
|
211
|
+
// | undefined {
|
212
|
+
// const url = Linking.parse(inviteURL);
|
213
|
+
// const parts = url.path?.split("/");
|
214
|
+
|
215
|
+
// if (!parts || parts[0] !== "invite") {
|
216
|
+
// return undefined;
|
217
|
+
// }
|
218
|
+
|
219
|
+
// let valueHint: string | undefined;
|
220
|
+
// let valueID: ID<C> | undefined;
|
221
|
+
// let inviteSecret: InviteSecret | undefined;
|
222
|
+
|
223
|
+
// if (parts.length === 4) {
|
224
|
+
// valueHint = parts[1];
|
225
|
+
// valueID = parts[2] as ID<C>;
|
226
|
+
// inviteSecret = parts[3] as InviteSecret;
|
227
|
+
// } else if (parts.length === 3) {
|
228
|
+
// valueID = parts[1] as ID<C>;
|
229
|
+
// inviteSecret = parts[2] as InviteSecret;
|
230
|
+
// }
|
231
|
+
|
232
|
+
// if (!valueID || !inviteSecret) {
|
233
|
+
// return undefined;
|
234
|
+
// }
|
235
|
+
|
236
|
+
// return { valueID, inviteSecret, valueHint };
|
237
|
+
// }
|
238
|
+
|
204
239
|
/////////
|
205
240
|
|
206
241
|
export * from "./provider.js";
|
package/src/provider.tsx
CHANGED
@@ -14,6 +14,7 @@ import {
|
|
14
14
|
} from "jazz-tools";
|
15
15
|
import { Linking } from "react-native";
|
16
16
|
import {
|
17
|
+
BaseReactNativeContextOptions,
|
17
18
|
KvStore,
|
18
19
|
KvStoreContext,
|
19
20
|
ReactNativeContext,
|
@@ -27,6 +28,11 @@ import { ExpoSecureStoreAdapter } from "./storage/expo-secure-store-adapter.js";
|
|
27
28
|
export function createJazzRNApp<Acc extends Account>({
|
28
29
|
kvStore = new ExpoSecureStoreAdapter(),
|
29
30
|
AccountSchema = Account as unknown as AccountClass<Acc>,
|
31
|
+
CryptoProvider,
|
32
|
+
}: {
|
33
|
+
kvStore?: KvStore;
|
34
|
+
AccountSchema?: AccountClass<Acc>;
|
35
|
+
CryptoProvider?: BaseReactNativeContextOptions["CryptoProvider"];
|
30
36
|
} = {}): JazzReactApp<Acc> {
|
31
37
|
const JazzContext = React.createContext<
|
32
38
|
ReactNativeContext<Acc> | ReactNativeGuestContext | undefined
|
@@ -61,12 +67,14 @@ export function createJazzRNApp<Acc extends Account>({
|
|
61
67
|
? {
|
62
68
|
peer,
|
63
69
|
storage,
|
70
|
+
CryptoProvider,
|
64
71
|
}
|
65
72
|
: {
|
66
73
|
AccountSchema,
|
67
74
|
auth: auth,
|
68
75
|
peer,
|
69
76
|
storage,
|
77
|
+
CryptoProvider,
|
70
78
|
},
|
71
79
|
).then((context) => {
|
72
80
|
setCtx({
|