jazz-tools 0.9.23 → 0.10.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/.turbo/turbo-build.log +11 -11
- package/CHANGELOG.md +19 -0
- package/dist/{chunk-OJIEP4WE.js → chunk-UBD75Z27.js} +566 -118
- package/dist/chunk-UBD75Z27.js.map +1 -0
- package/dist/index.native.js +17 -5
- package/dist/index.native.js.map +1 -1
- package/dist/index.web.js +17 -5
- package/dist/index.web.js.map +1 -1
- package/dist/testing.js +124 -33
- package/dist/testing.js.map +1 -1
- package/package.json +5 -3
- package/src/auth/AuthSecretStorage.ts +109 -0
- package/src/auth/DemoAuth.ts +188 -0
- package/src/auth/InMemoryKVStore.ts +25 -0
- package/src/auth/KvStoreContext.ts +39 -0
- package/src/auth/PassphraseAuth.ts +113 -0
- package/src/coValues/account.ts +8 -3
- package/src/coValues/coFeed.ts +1 -1
- package/src/coValues/coList.ts +1 -1
- package/src/coValues/coMap.ts +1 -1
- package/src/coValues/group.ts +9 -8
- package/src/coValues/interfaces.ts +14 -5
- package/src/exports.ts +17 -3
- package/src/implementation/ContextManager.ts +178 -0
- package/src/implementation/activeAccountContext.ts +6 -1
- package/src/implementation/createContext.ts +173 -149
- package/src/testing.ts +171 -33
- package/src/tests/AuthSecretStorage.test.ts +275 -0
- package/src/tests/ContextManager.test.ts +256 -0
- package/src/tests/DemoAuth.test.ts +269 -0
- package/src/tests/PassphraseAuth.test.ts +152 -0
- package/src/tests/coFeed.test.ts +44 -39
- package/src/tests/coList.test.ts +21 -20
- package/src/tests/coMap.test.ts +21 -20
- package/src/tests/coPlainText.test.ts +21 -20
- package/src/tests/coRichText.test.ts +21 -20
- package/src/tests/createContext.test.ts +339 -0
- package/src/tests/deepLoading.test.ts +41 -42
- package/src/tests/fixtures.ts +2050 -0
- package/src/tests/groupsAndAccounts.test.ts +2 -2
- package/src/tests/subscribe.test.ts +42 -9
- package/src/tests/testing.test.ts +56 -0
- package/src/tests/utils.ts +11 -11
- package/src/types.ts +54 -0
- package/dist/chunk-OJIEP4WE.js.map +0 -1
package/dist/index.native.js
CHANGED
@@ -1,19 +1,25 @@
|
|
1
1
|
import {
|
2
2
|
Account,
|
3
3
|
AnonymousJazzAgent,
|
4
|
+
AuthSecretStorage,
|
4
5
|
CoFeed,
|
5
6
|
CoList,
|
6
7
|
CoMap,
|
7
8
|
CoPlainText,
|
8
9
|
CoRichText,
|
9
10
|
CoValueBase,
|
11
|
+
DemoAuth,
|
10
12
|
Encoders,
|
11
13
|
FileStream,
|
12
14
|
Group,
|
13
15
|
ImageDefinition,
|
16
|
+
InMemoryKVStore,
|
14
17
|
Inbox,
|
15
18
|
InboxSender,
|
19
|
+
JazzContextManager,
|
20
|
+
KvStoreContext,
|
16
21
|
Marks,
|
22
|
+
PassphraseAuth,
|
17
23
|
Profile,
|
18
24
|
SchemaUnion,
|
19
25
|
co,
|
@@ -22,14 +28,14 @@ import {
|
|
22
28
|
createCoValueObservable,
|
23
29
|
createInviteLink,
|
24
30
|
createJazzContext,
|
25
|
-
|
26
|
-
|
31
|
+
createJazzContextForNewAccount,
|
32
|
+
createJazzContextFromExistingCredentials,
|
27
33
|
isControlledAccount,
|
28
34
|
loadCoValue,
|
29
35
|
parseInviteLink,
|
30
36
|
randomSessionProvider,
|
31
37
|
subscribeToCoValue
|
32
|
-
} from "./chunk-
|
38
|
+
} from "./chunk-UBD75Z27.js";
|
33
39
|
|
34
40
|
// src/index.native.ts
|
35
41
|
import {
|
@@ -39,6 +45,7 @@ import {
|
|
39
45
|
export {
|
40
46
|
Account,
|
41
47
|
AnonymousJazzAgent,
|
48
|
+
AuthSecretStorage,
|
42
49
|
FileStream as BinaryCoStream,
|
43
50
|
CoFeed,
|
44
51
|
CoList,
|
@@ -47,14 +54,19 @@ export {
|
|
47
54
|
CoRichText,
|
48
55
|
CoFeed as CoStream,
|
49
56
|
CoValueBase,
|
57
|
+
DemoAuth,
|
50
58
|
Encoders,
|
51
59
|
FileStream,
|
52
60
|
Group,
|
53
61
|
ImageDefinition,
|
62
|
+
InMemoryKVStore,
|
54
63
|
Inbox,
|
55
64
|
InboxSender,
|
65
|
+
JazzContextManager,
|
66
|
+
KvStoreContext,
|
56
67
|
MAX_RECOMMENDED_TX_SIZE,
|
57
68
|
Marks,
|
69
|
+
PassphraseAuth,
|
58
70
|
Profile,
|
59
71
|
SchemaUnion,
|
60
72
|
co,
|
@@ -64,8 +76,8 @@ export {
|
|
64
76
|
createCoValueObservable,
|
65
77
|
createInviteLink,
|
66
78
|
createJazzContext,
|
67
|
-
|
68
|
-
|
79
|
+
createJazzContextForNewAccount,
|
80
|
+
createJazzContextFromExistingCredentials,
|
69
81
|
isControlledAccount,
|
70
82
|
loadCoValue,
|
71
83
|
parseInviteLink,
|
package/dist/index.native.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/index.native.ts"],"sourcesContent":["export * from \"./exports.js\";\n\nexport {\n MAX_RECOMMENDED_TX_SIZE,\n cojsonInternals,\n} from \"cojson/native\";\n"],"mappings":"
|
1
|
+
{"version":3,"sources":["../src/index.native.ts"],"sourcesContent":["export * from \"./exports.js\";\n\nexport {\n MAX_RECOMMENDED_TX_SIZE,\n cojsonInternals,\n} from \"cojson/native\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA;AAAA,EACE;AAAA,EACA;AAAA,OACK;","names":[]}
|
package/dist/index.web.js
CHANGED
@@ -1,19 +1,25 @@
|
|
1
1
|
import {
|
2
2
|
Account,
|
3
3
|
AnonymousJazzAgent,
|
4
|
+
AuthSecretStorage,
|
4
5
|
CoFeed,
|
5
6
|
CoList,
|
6
7
|
CoMap,
|
7
8
|
CoPlainText,
|
8
9
|
CoRichText,
|
9
10
|
CoValueBase,
|
11
|
+
DemoAuth,
|
10
12
|
Encoders,
|
11
13
|
FileStream,
|
12
14
|
Group,
|
13
15
|
ImageDefinition,
|
16
|
+
InMemoryKVStore,
|
14
17
|
Inbox,
|
15
18
|
InboxSender,
|
19
|
+
JazzContextManager,
|
20
|
+
KvStoreContext,
|
16
21
|
Marks,
|
22
|
+
PassphraseAuth,
|
17
23
|
Profile,
|
18
24
|
SchemaUnion,
|
19
25
|
co,
|
@@ -22,20 +28,21 @@ import {
|
|
22
28
|
createCoValueObservable,
|
23
29
|
createInviteLink,
|
24
30
|
createJazzContext,
|
25
|
-
|
26
|
-
|
31
|
+
createJazzContextForNewAccount,
|
32
|
+
createJazzContextFromExistingCredentials,
|
27
33
|
isControlledAccount,
|
28
34
|
loadCoValue,
|
29
35
|
parseInviteLink,
|
30
36
|
randomSessionProvider,
|
31
37
|
subscribeToCoValue
|
32
|
-
} from "./chunk-
|
38
|
+
} from "./chunk-UBD75Z27.js";
|
33
39
|
|
34
40
|
// src/index.web.ts
|
35
41
|
import { cojsonInternals, MAX_RECOMMENDED_TX_SIZE, WasmCrypto } from "cojson";
|
36
42
|
export {
|
37
43
|
Account,
|
38
44
|
AnonymousJazzAgent,
|
45
|
+
AuthSecretStorage,
|
39
46
|
FileStream as BinaryCoStream,
|
40
47
|
CoFeed,
|
41
48
|
CoList,
|
@@ -44,14 +51,19 @@ export {
|
|
44
51
|
CoRichText,
|
45
52
|
CoFeed as CoStream,
|
46
53
|
CoValueBase,
|
54
|
+
DemoAuth,
|
47
55
|
Encoders,
|
48
56
|
FileStream,
|
49
57
|
Group,
|
50
58
|
ImageDefinition,
|
59
|
+
InMemoryKVStore,
|
51
60
|
Inbox,
|
52
61
|
InboxSender,
|
62
|
+
JazzContextManager,
|
63
|
+
KvStoreContext,
|
53
64
|
MAX_RECOMMENDED_TX_SIZE,
|
54
65
|
Marks,
|
66
|
+
PassphraseAuth,
|
55
67
|
Profile,
|
56
68
|
SchemaUnion,
|
57
69
|
WasmCrypto,
|
@@ -62,8 +74,8 @@ export {
|
|
62
74
|
createCoValueObservable,
|
63
75
|
createInviteLink,
|
64
76
|
createJazzContext,
|
65
|
-
|
66
|
-
|
77
|
+
createJazzContextForNewAccount,
|
78
|
+
createJazzContextFromExistingCredentials,
|
67
79
|
isControlledAccount,
|
68
80
|
loadCoValue,
|
69
81
|
parseInviteLink,
|
package/dist/index.web.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/index.web.ts"],"sourcesContent":["export * from \"./exports.js\";\n\nexport { cojsonInternals, MAX_RECOMMENDED_TX_SIZE, WasmCrypto } from \"cojson\";\n"],"mappings":"
|
1
|
+
{"version":3,"sources":["../src/index.web.ts"],"sourcesContent":["export * from \"./exports.js\";\n\nexport { cojsonInternals, MAX_RECOMMENDED_TX_SIZE, WasmCrypto } from \"cojson\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,SAAS,iBAAiB,yBAAyB,kBAAkB;","names":[]}
|
package/dist/testing.js
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
import {
|
2
2
|
Account,
|
3
|
+
JazzContextManager,
|
3
4
|
activeAccountContext,
|
4
|
-
createAnonymousJazzContext
|
5
|
-
|
5
|
+
createAnonymousJazzContext,
|
6
|
+
createJazzContext,
|
7
|
+
randomSessionProvider
|
8
|
+
} from "./chunk-UBD75Z27.js";
|
6
9
|
|
7
10
|
// src/testing.ts
|
8
11
|
import { LocalNode } from "cojson";
|
@@ -11,7 +14,7 @@ import { PureJSCrypto } from "cojson/crypto";
|
|
11
14
|
var syncServer = { current: null };
|
12
15
|
var TestJSCrypto = class extends PureJSCrypto {
|
13
16
|
static async create() {
|
14
|
-
if ("navigator" in globalThis && navigator.userAgent
|
17
|
+
if ("navigator" in globalThis && navigator.userAgent?.includes("jsdom")) {
|
15
18
|
const crypto = new PureJSCrypto();
|
16
19
|
crypto.seal = (options) => `sealed_U${cojsonInternals.stableStringify(options.message)}`;
|
17
20
|
crypto.unseal = (sealed) => JSON.parse(sealed.substring("sealed_U".length));
|
@@ -22,39 +25,60 @@ var TestJSCrypto = class extends PureJSCrypto {
|
|
22
25
|
return new PureJSCrypto();
|
23
26
|
}
|
24
27
|
};
|
28
|
+
function getPeerConnectedToTestSyncServer() {
|
29
|
+
if (!syncServer.current) {
|
30
|
+
throw new Error("Sync server not initialized");
|
31
|
+
}
|
32
|
+
const [aPeer, bPeer] = cojsonInternals.connectedPeers(
|
33
|
+
Math.random().toString(),
|
34
|
+
Math.random().toString(),
|
35
|
+
{
|
36
|
+
peer1role: "server",
|
37
|
+
peer2role: "server"
|
38
|
+
}
|
39
|
+
);
|
40
|
+
syncServer.current.syncManager.addPeer(aPeer);
|
41
|
+
return bPeer;
|
42
|
+
}
|
43
|
+
var SecretSeedMap = /* @__PURE__ */ new Map();
|
44
|
+
var isMigrationActive = false;
|
25
45
|
async function createJazzTestAccount(options) {
|
26
46
|
const AccountSchema = options?.AccountSchema ?? Account;
|
27
47
|
const peers = [];
|
28
48
|
if (syncServer.current) {
|
29
|
-
|
30
|
-
Math.random().toString(),
|
31
|
-
Math.random().toString(),
|
32
|
-
{
|
33
|
-
peer1role: "server",
|
34
|
-
peer2role: "server"
|
35
|
-
}
|
36
|
-
);
|
37
|
-
syncServer.current.syncManager.addPeer(aPeer);
|
38
|
-
peers.push(bPeer);
|
49
|
+
peers.push(getPeerConnectedToTestSyncServer());
|
39
50
|
}
|
51
|
+
const crypto = await TestJSCrypto.create();
|
52
|
+
const secretSeed = crypto.newRandomSecretSeed();
|
40
53
|
const { node } = await LocalNode.withNewlyCreatedAccount({
|
41
54
|
creationProps: {
|
42
55
|
name: "Test Account",
|
43
56
|
...options?.creationProps
|
44
57
|
},
|
45
|
-
|
58
|
+
initialAgentSecret: crypto.agentSecretFromSecretSeed(secretSeed),
|
59
|
+
crypto,
|
46
60
|
peersToLoadFrom: peers,
|
47
61
|
migration: async (rawAccount, _node, creationProps) => {
|
62
|
+
if (isMigrationActive) {
|
63
|
+
throw new Error(
|
64
|
+
"It is not possible to create multiple accounts in parallel inside the test environment."
|
65
|
+
);
|
66
|
+
}
|
67
|
+
isMigrationActive = true;
|
48
68
|
const account2 = new AccountSchema({
|
49
69
|
fromRaw: rawAccount
|
50
70
|
});
|
51
|
-
|
52
|
-
|
53
|
-
}
|
71
|
+
const prevActiveAccount = activeAccountContext.maybeGet();
|
72
|
+
activeAccountContext.set(account2);
|
54
73
|
await account2.applyMigration?.(creationProps);
|
74
|
+
if (!options?.isCurrentActiveAccount) {
|
75
|
+
activeAccountContext.set(prevActiveAccount);
|
76
|
+
}
|
77
|
+
isMigrationActive = false;
|
55
78
|
}
|
56
79
|
});
|
57
80
|
const account = AccountSchema.fromNode(node);
|
81
|
+
SecretSeedMap.set(account.id, secretSeed);
|
58
82
|
if (options?.isCurrentActiveAccount) {
|
59
83
|
activeAccountContext.set(account);
|
60
84
|
}
|
@@ -72,22 +96,87 @@ async function createJazzTestGuest() {
|
|
72
96
|
guest: ctx.agent
|
73
97
|
};
|
74
98
|
}
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
done: () => account.guest.node.gracefulShutdown()
|
82
|
-
};
|
99
|
+
var TestJazzContextManager = class _TestJazzContextManager extends JazzContextManager {
|
100
|
+
static fromAccountOrGuest(account, props) {
|
101
|
+
if (account && "guest" in account) {
|
102
|
+
return this.fromGuest(account, props);
|
103
|
+
}
|
104
|
+
return this.fromAccount(account ?? Account.getMe(), props);
|
83
105
|
}
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
106
|
+
static fromAccount(account, props) {
|
107
|
+
const context = new _TestJazzContextManager();
|
108
|
+
const provider = props?.isAuthenticated ? "testProvider" : "anonymous";
|
109
|
+
const storage = context.getAuthSecretStorage();
|
110
|
+
const node = account._raw.core.node;
|
111
|
+
storage.set({
|
112
|
+
accountID: account.id,
|
113
|
+
accountSecret: node.account.agentSecret,
|
114
|
+
secretSeed: SecretSeedMap.get(account.id),
|
115
|
+
provider
|
116
|
+
});
|
117
|
+
storage.isAuthenticated = Boolean(props?.isAuthenticated);
|
118
|
+
context.updateContext(
|
119
|
+
{
|
120
|
+
AccountSchema: account.constructor,
|
121
|
+
...props
|
122
|
+
},
|
123
|
+
{
|
124
|
+
me: account,
|
125
|
+
node,
|
126
|
+
done: () => {
|
127
|
+
node.gracefulShutdown();
|
128
|
+
},
|
129
|
+
logOut: async () => {
|
130
|
+
node.gracefulShutdown();
|
131
|
+
}
|
132
|
+
}
|
133
|
+
);
|
134
|
+
return context;
|
135
|
+
}
|
136
|
+
static fromGuest({ guest }, props = {}) {
|
137
|
+
const context = new _TestJazzContextManager();
|
138
|
+
const node = guest.node;
|
139
|
+
context.updateContext(props, {
|
140
|
+
guest,
|
141
|
+
node,
|
142
|
+
done: () => {
|
143
|
+
node.gracefulShutdown();
|
144
|
+
},
|
145
|
+
logOut: async () => {
|
146
|
+
node.gracefulShutdown();
|
147
|
+
}
|
148
|
+
});
|
149
|
+
return context;
|
150
|
+
}
|
151
|
+
async createContext(props, authProps) {
|
152
|
+
this.props = props;
|
153
|
+
if (!syncServer.current) {
|
154
|
+
throw new Error(
|
155
|
+
"You need to setup a test sync server with setupJazzTestSync to use the Auth functions"
|
156
|
+
);
|
157
|
+
}
|
158
|
+
const context = await createJazzContext({
|
159
|
+
credentials: authProps?.credentials,
|
160
|
+
defaultProfileName: props.defaultProfileName,
|
161
|
+
newAccountProps: authProps?.newAccountProps,
|
162
|
+
peersToLoadFrom: [getPeerConnectedToTestSyncServer()],
|
163
|
+
crypto: await TestJSCrypto.create(),
|
164
|
+
sessionProvider: randomSessionProvider,
|
165
|
+
authSecretStorage: this.getAuthSecretStorage(),
|
166
|
+
AccountSchema: props.AccountSchema
|
167
|
+
});
|
168
|
+
this.updateContext(props, {
|
169
|
+
me: context.account,
|
170
|
+
node: context.node,
|
171
|
+
done: () => {
|
172
|
+
context.done();
|
173
|
+
},
|
174
|
+
logOut: () => {
|
175
|
+
return context.logOut();
|
176
|
+
}
|
177
|
+
});
|
178
|
+
}
|
179
|
+
};
|
91
180
|
function linkAccounts(a, b, aRole = "server", bRole = "server") {
|
92
181
|
const [aPeer, bPeer] = cojsonInternals.connectedPeers(b.id, a.id, {
|
93
182
|
peer1role: aRole,
|
@@ -110,9 +199,11 @@ async function setupJazzTestSync() {
|
|
110
199
|
return account;
|
111
200
|
}
|
112
201
|
export {
|
202
|
+
TestJSCrypto,
|
203
|
+
TestJazzContextManager,
|
113
204
|
createJazzTestAccount,
|
114
205
|
createJazzTestGuest,
|
115
|
-
|
206
|
+
getPeerConnectedToTestSyncServer,
|
116
207
|
linkAccounts,
|
117
208
|
setActiveAccount,
|
118
209
|
setupJazzTestSync
|
package/dist/testing.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/testing.ts"],"sourcesContent":["import { AgentSecret, CryptoProvider, LocalNode, Peer } from \"cojson\";\nimport { cojsonInternals } from \"cojson\";\nimport { PureJSCrypto } from \"cojson/crypto\";\nimport { Account, type AccountClass } from \"./exports.js\";\nimport { activeAccountContext } from \"./implementation/activeAccountContext.js\";\nimport {\n type AnonymousJazzAgent,\n type CoValueClass,\n createAnonymousJazzContext,\n} from \"./internal.js\";\n\nconst syncServer: { current: LocalNode | null } = { current: null };\n\ntype TestAccountSchema<Acc extends Account> = CoValueClass<Acc> & {\n fromNode: (typeof Account)[\"fromNode\"];\n create: (options: {\n creationProps: { name: string };\n initialAgentSecret?: AgentSecret;\n peersToLoadFrom?: Peer[];\n crypto: CryptoProvider;\n }) => Promise<Acc>;\n};\n\nclass TestJSCrypto extends PureJSCrypto {\n static async create() {\n if (\"navigator\" in globalThis && navigator.userAgent.includes(\"jsdom\")) {\n // Mocking crypto seal & encrypt to make it work with JSDom. Getting \"Error: Uint8Array expected\" there\n const crypto = new PureJSCrypto();\n\n crypto.seal = (options) =>\n `sealed_U${cojsonInternals.stableStringify(options.message)}` as any;\n crypto.unseal = (sealed) =>\n JSON.parse(sealed.substring(\"sealed_U\".length));\n crypto.encrypt = (message) =>\n `encrypted_U${cojsonInternals.stableStringify(message)}` as any;\n crypto.decryptRaw = (encrypted) =>\n encrypted.substring(\"encrypted_U\".length) as any;\n\n return crypto;\n }\n\n // For non-jsdom environments, we use the real crypto\n return new PureJSCrypto();\n }\n}\n\nexport async function createJazzTestAccount<Acc extends Account>(options?: {\n isCurrentActiveAccount?: boolean;\n AccountSchema?: CoValueClass<Acc>;\n creationProps?: Record<string, unknown>;\n}): Promise<Acc> {\n const AccountSchema = (options?.AccountSchema ??\n Account) as unknown as TestAccountSchema<Acc>;\n const peers = [];\n if (syncServer.current) {\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(\n Math.random().toString(),\n Math.random().toString(),\n {\n peer1role: \"server\",\n peer2role: \"server\",\n },\n );\n syncServer.current.syncManager.addPeer(aPeer);\n peers.push(bPeer);\n }\n\n const { node } = await LocalNode.withNewlyCreatedAccount({\n creationProps: {\n name: \"Test Account\",\n ...options?.creationProps,\n },\n crypto: await TestJSCrypto.create(),\n peersToLoadFrom: peers,\n migration: async (rawAccount, _node, creationProps) => {\n const account = new AccountSchema({\n fromRaw: rawAccount,\n });\n\n if (options?.isCurrentActiveAccount) {\n activeAccountContext.set(account);\n }\n\n await account.applyMigration?.(creationProps);\n },\n });\n\n const account = AccountSchema.fromNode(node);\n\n if (options?.isCurrentActiveAccount) {\n activeAccountContext.set(account);\n }\n\n return account;\n}\n\nexport function setActiveAccount(account: Account) {\n activeAccountContext.set(account);\n}\n\nexport async function createJazzTestGuest() {\n const ctx = await createAnonymousJazzContext({\n crypto: await PureJSCrypto.create(),\n peersToLoadFrom: [],\n });\n\n return {\n guest: ctx.agent,\n };\n}\n\nexport function getJazzContextShape<Acc extends Account>(\n account: Acc | { guest: AnonymousJazzAgent },\n) {\n if (\"guest\" in account) {\n return {\n guest: account.guest,\n AccountSchema: Account,\n logOut: () => account.guest.node.gracefulShutdown(),\n done: () => account.guest.node.gracefulShutdown(),\n };\n }\n\n return {\n me: account,\n AccountSchema: account.constructor as AccountClass<Acc>,\n logOut: () => account._raw.core.node.gracefulShutdown(),\n done: () => account._raw.core.node.gracefulShutdown(),\n };\n}\n\nexport function linkAccounts(\n a: Account,\n b: Account,\n aRole: \"server\" | \"client\" = \"server\",\n bRole: \"server\" | \"client\" = \"server\",\n) {\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(b.id, a.id, {\n peer1role: aRole,\n peer2role: bRole,\n });\n\n a._raw.core.node.syncManager.addPeer(aPeer);\n b._raw.core.node.syncManager.addPeer(bPeer);\n}\n\nexport async function setupJazzTestSync() {\n if (syncServer.current) {\n syncServer.current.gracefulShutdown();\n }\n\n const account = await Account.create({\n creationProps: {\n name: \"Test Account\",\n },\n crypto: await TestJSCrypto.create(),\n });\n\n syncServer.current = account._raw.core.node;\n\n return account;\n}\n"],"mappings":"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","names":["account"]}
|
1
|
+
{"version":3,"sources":["../src/testing.ts"],"sourcesContent":["import { AgentSecret, CryptoProvider, LocalNode, Peer } from \"cojson\";\nimport { cojsonInternals } from \"cojson\";\nimport { PureJSCrypto } from \"cojson/crypto\";\nimport {\n Account,\n AccountClass,\n JazzContextManagerAuthProps,\n} from \"./exports.js\";\nimport {\n JazzContextManager,\n JazzContextManagerBaseProps,\n} from \"./implementation/ContextManager.js\";\nimport { activeAccountContext } from \"./implementation/activeAccountContext.js\";\nimport {\n type AnonymousJazzAgent,\n type CoValueClass,\n createAnonymousJazzContext,\n createJazzContext,\n randomSessionProvider,\n} from \"./internal.js\";\n\nconst syncServer: { current: LocalNode | null } = { current: null };\n\ntype TestAccountSchema<Acc extends Account> = CoValueClass<Acc> & {\n fromNode: (typeof Account)[\"fromNode\"];\n create: (options: {\n creationProps: { name: string };\n initialAgentSecret?: AgentSecret;\n peersToLoadFrom?: Peer[];\n crypto: CryptoProvider;\n }) => Promise<Acc>;\n};\n\nexport class TestJSCrypto extends PureJSCrypto {\n static async create() {\n if (\"navigator\" in globalThis && navigator.userAgent?.includes(\"jsdom\")) {\n // Mocking crypto seal & encrypt to make it work with JSDom. Getting \"Error: Uint8Array expected\" there\n const crypto = new PureJSCrypto();\n\n crypto.seal = (options) =>\n `sealed_U${cojsonInternals.stableStringify(options.message)}` as any;\n crypto.unseal = (sealed) =>\n JSON.parse(sealed.substring(\"sealed_U\".length));\n crypto.encrypt = (message) =>\n `encrypted_U${cojsonInternals.stableStringify(message)}` as any;\n crypto.decryptRaw = (encrypted) =>\n encrypted.substring(\"encrypted_U\".length) as any;\n\n return crypto;\n }\n\n // For non-jsdom environments, we use the real crypto\n return new PureJSCrypto();\n }\n}\n\nexport function getPeerConnectedToTestSyncServer() {\n if (!syncServer.current) {\n throw new Error(\"Sync server not initialized\");\n }\n\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(\n Math.random().toString(),\n Math.random().toString(),\n {\n peer1role: \"server\",\n peer2role: \"server\",\n },\n );\n syncServer.current.syncManager.addPeer(aPeer);\n\n return bPeer;\n}\n\nconst SecretSeedMap = new Map<string, Uint8Array>();\nlet isMigrationActive = false;\n\nexport async function createJazzTestAccount<Acc extends Account>(options?: {\n isCurrentActiveAccount?: boolean;\n AccountSchema?: CoValueClass<Acc>;\n creationProps?: Record<string, unknown>;\n}): Promise<Acc> {\n const AccountSchema = (options?.AccountSchema ??\n Account) as unknown as TestAccountSchema<Acc>;\n const peers = [];\n if (syncServer.current) {\n peers.push(getPeerConnectedToTestSyncServer());\n }\n\n const crypto = await TestJSCrypto.create();\n const secretSeed = crypto.newRandomSecretSeed();\n\n const { node } = await LocalNode.withNewlyCreatedAccount({\n creationProps: {\n name: \"Test Account\",\n ...options?.creationProps,\n },\n initialAgentSecret: crypto.agentSecretFromSecretSeed(secretSeed),\n crypto,\n peersToLoadFrom: peers,\n migration: async (rawAccount, _node, creationProps) => {\n if (isMigrationActive) {\n throw new Error(\n \"It is not possible to create multiple accounts in parallel inside the test environment.\",\n );\n }\n\n isMigrationActive = true;\n\n const account = new AccountSchema({\n fromRaw: rawAccount,\n });\n\n // We need to set the account as current because the migration\n // will probably rely on the global me\n const prevActiveAccount = activeAccountContext.maybeGet();\n activeAccountContext.set(account);\n\n await account.applyMigration?.(creationProps);\n\n if (!options?.isCurrentActiveAccount) {\n activeAccountContext.set(prevActiveAccount);\n }\n\n isMigrationActive = false;\n },\n });\n\n const account = AccountSchema.fromNode(node);\n SecretSeedMap.set(account.id, secretSeed);\n\n if (options?.isCurrentActiveAccount) {\n activeAccountContext.set(account);\n }\n\n return account;\n}\n\nexport function setActiveAccount(account: Account) {\n activeAccountContext.set(account);\n}\n\nexport async function createJazzTestGuest() {\n const ctx = await createAnonymousJazzContext({\n crypto: await PureJSCrypto.create(),\n peersToLoadFrom: [],\n });\n\n return {\n guest: ctx.agent,\n };\n}\n\nexport type TestJazzContextManagerProps<Acc extends Account> =\n JazzContextManagerBaseProps<Acc> & {\n defaultProfileName?: string;\n AccountSchema?: AccountClass<Acc>;\n isAuthenticated?: boolean;\n };\n\nexport class TestJazzContextManager<\n Acc extends Account,\n> extends JazzContextManager<Acc, TestJazzContextManagerProps<Acc>> {\n static fromAccountOrGuest<Acc extends Account>(\n account?: Acc | { guest: AnonymousJazzAgent },\n props?: TestJazzContextManagerProps<Acc>,\n ) {\n if (account && \"guest\" in account) {\n return this.fromGuest<Acc>(account, props);\n }\n\n return this.fromAccount<Acc>(account ?? (Account.getMe() as Acc), props);\n }\n\n static fromAccount<Acc extends Account>(\n account: Acc,\n props?: TestJazzContextManagerProps<Acc>,\n ) {\n const context = new TestJazzContextManager<Acc>();\n\n const provider = props?.isAuthenticated ? \"testProvider\" : \"anonymous\";\n const storage = context.getAuthSecretStorage();\n const node = account._raw.core.node;\n\n storage.set({\n accountID: account.id,\n accountSecret: node.account.agentSecret,\n secretSeed: SecretSeedMap.get(account.id),\n provider,\n });\n storage.isAuthenticated = Boolean(props?.isAuthenticated);\n\n context.updateContext(\n {\n AccountSchema: account.constructor as AccountClass<Acc>,\n ...props,\n },\n {\n me: account,\n node,\n done: () => {\n node.gracefulShutdown();\n },\n logOut: async () => {\n node.gracefulShutdown();\n },\n },\n );\n\n return context;\n }\n\n static fromGuest<Acc extends Account>(\n { guest }: { guest: AnonymousJazzAgent },\n props: TestJazzContextManagerProps<Acc> = {},\n ) {\n const context = new TestJazzContextManager<Acc>();\n const node = guest.node;\n\n context.updateContext(props, {\n guest,\n node,\n done: () => {\n node.gracefulShutdown();\n },\n logOut: async () => {\n node.gracefulShutdown();\n },\n });\n\n return context;\n }\n\n async createContext(\n props: TestJazzContextManagerProps<Acc>,\n authProps?: JazzContextManagerAuthProps,\n ) {\n this.props = props;\n\n if (!syncServer.current) {\n throw new Error(\n \"You need to setup a test sync server with setupJazzTestSync to use the Auth functions\",\n );\n }\n\n const context = await createJazzContext<Acc>({\n credentials: authProps?.credentials,\n defaultProfileName: props.defaultProfileName,\n newAccountProps: authProps?.newAccountProps,\n peersToLoadFrom: [getPeerConnectedToTestSyncServer()],\n crypto: await TestJSCrypto.create(),\n sessionProvider: randomSessionProvider,\n authSecretStorage: this.getAuthSecretStorage(),\n AccountSchema: props.AccountSchema,\n });\n\n this.updateContext(props, {\n me: context.account,\n node: context.node,\n done: () => {\n context.done();\n },\n logOut: () => {\n return context.logOut();\n },\n });\n }\n}\n\nexport function linkAccounts(\n a: Account,\n b: Account,\n aRole: \"server\" | \"client\" = \"server\",\n bRole: \"server\" | \"client\" = \"server\",\n) {\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(b.id, a.id, {\n peer1role: aRole,\n peer2role: bRole,\n });\n\n a._raw.core.node.syncManager.addPeer(aPeer);\n b._raw.core.node.syncManager.addPeer(bPeer);\n}\n\nexport async function setupJazzTestSync() {\n if (syncServer.current) {\n syncServer.current.gracefulShutdown();\n }\n\n const account = await Account.create({\n creationProps: {\n name: \"Test Account\",\n },\n crypto: await TestJSCrypto.create(),\n });\n\n syncServer.current = account._raw.core.node;\n\n return account;\n}\n"],"mappings":"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","names":["account"]}
|
package/package.json
CHANGED
@@ -23,14 +23,16 @@
|
|
23
23
|
},
|
24
24
|
"type": "module",
|
25
25
|
"license": "MIT",
|
26
|
-
"version": "0.
|
26
|
+
"version": "0.10.0",
|
27
27
|
"dependencies": {
|
28
|
-
"
|
28
|
+
"@scure/bip39": "^1.3.0",
|
29
|
+
"cojson": "0.10.0"
|
29
30
|
},
|
30
31
|
"devDependencies": {
|
31
32
|
"tsup": "8.3.5",
|
32
33
|
"typescript": "~5.6.2",
|
33
|
-
"vitest": "
|
34
|
+
"vitest": "3.0.5",
|
35
|
+
"ws": "^8.14.2"
|
34
36
|
},
|
35
37
|
"madge": {
|
36
38
|
"detectiveOptions": {
|
@@ -0,0 +1,109 @@
|
|
1
|
+
import { AgentSecret } from "cojson";
|
2
|
+
import type { Account } from "../coValues/account.js";
|
3
|
+
import type { ID } from "../internal.js";
|
4
|
+
import { AuthCredentials } from "../types.js";
|
5
|
+
import KvStoreContext from "./KvStoreContext.js";
|
6
|
+
|
7
|
+
const STORAGE_KEY = "jazz-logged-in-secret";
|
8
|
+
|
9
|
+
export type AuthSetPayload = {
|
10
|
+
accountID: ID<Account>;
|
11
|
+
secretSeed?: Uint8Array;
|
12
|
+
accountSecret: AgentSecret;
|
13
|
+
provider: "anonymous" | "clerk" | "demo" | "passkey" | "passphrase" | string;
|
14
|
+
};
|
15
|
+
|
16
|
+
export class AuthSecretStorage {
|
17
|
+
private listeners: Set<(isAuthenticated: boolean) => void>;
|
18
|
+
public isAuthenticated: boolean;
|
19
|
+
|
20
|
+
constructor() {
|
21
|
+
this.listeners = new Set();
|
22
|
+
this.isAuthenticated = false;
|
23
|
+
}
|
24
|
+
|
25
|
+
async migrate() {
|
26
|
+
const kvStore = KvStoreContext.getInstance().getStorage();
|
27
|
+
|
28
|
+
if (!(await kvStore.get(STORAGE_KEY))) {
|
29
|
+
const demoAuthSecret = await kvStore.get("demo-auth-logged-in-secret");
|
30
|
+
if (demoAuthSecret) {
|
31
|
+
await kvStore.set(STORAGE_KEY, demoAuthSecret);
|
32
|
+
await kvStore.delete("demo-auth-logged-in-secret");
|
33
|
+
}
|
34
|
+
|
35
|
+
const clerkAuthSecret = await kvStore.get("jazz-clerk-auth");
|
36
|
+
if (clerkAuthSecret) {
|
37
|
+
await kvStore.set(STORAGE_KEY, clerkAuthSecret);
|
38
|
+
await kvStore.delete("jazz-clerk-auth");
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
async get(): Promise<AuthCredentials | null> {
|
44
|
+
const kvStore = KvStoreContext.getInstance().getStorage();
|
45
|
+
const data = await kvStore.get(STORAGE_KEY);
|
46
|
+
|
47
|
+
if (!data) return null;
|
48
|
+
|
49
|
+
const parsed = JSON.parse(data);
|
50
|
+
|
51
|
+
if (!parsed.accountID || !parsed.accountSecret) {
|
52
|
+
throw new Error("Invalid auth secret storage data");
|
53
|
+
}
|
54
|
+
|
55
|
+
return {
|
56
|
+
accountID: parsed.accountID,
|
57
|
+
secretSeed: parsed.secretSeed
|
58
|
+
? new Uint8Array(parsed.secretSeed)
|
59
|
+
: undefined,
|
60
|
+
accountSecret: parsed.accountSecret,
|
61
|
+
provider: parsed.provider,
|
62
|
+
};
|
63
|
+
}
|
64
|
+
|
65
|
+
async set(payload: AuthSetPayload) {
|
66
|
+
const kvStore = KvStoreContext.getInstance().getStorage();
|
67
|
+
await kvStore.set(
|
68
|
+
STORAGE_KEY,
|
69
|
+
JSON.stringify({
|
70
|
+
accountID: payload.accountID,
|
71
|
+
secretSeed: payload.secretSeed
|
72
|
+
? Array.from(payload.secretSeed)
|
73
|
+
: undefined,
|
74
|
+
accountSecret: payload.accountSecret,
|
75
|
+
provider: payload.provider,
|
76
|
+
}),
|
77
|
+
);
|
78
|
+
this.emitUpdate(payload);
|
79
|
+
}
|
80
|
+
|
81
|
+
getIsAuthenticated(data: AuthCredentials | null): boolean {
|
82
|
+
if (!data) return false;
|
83
|
+
return data.provider !== "anonymous";
|
84
|
+
}
|
85
|
+
|
86
|
+
onUpdate(handler: (isAuthenticated: boolean) => void) {
|
87
|
+
this.listeners.add(handler);
|
88
|
+
return () => {
|
89
|
+
this.listeners.delete(handler);
|
90
|
+
};
|
91
|
+
}
|
92
|
+
|
93
|
+
emitUpdate(data: AuthCredentials | null) {
|
94
|
+
const isAuthenticated = this.getIsAuthenticated(data);
|
95
|
+
|
96
|
+
if (this.isAuthenticated === isAuthenticated) return;
|
97
|
+
|
98
|
+
this.isAuthenticated = isAuthenticated;
|
99
|
+
for (const listener of this.listeners) {
|
100
|
+
listener(this.isAuthenticated);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
async clear() {
|
105
|
+
const kvStore = KvStoreContext.getInstance().getStorage();
|
106
|
+
await kvStore.delete(STORAGE_KEY);
|
107
|
+
this.emitUpdate(null);
|
108
|
+
}
|
109
|
+
}
|