jazz-tools 0.15.7 → 0.15.9
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 +42 -42
- package/CHANGELOG.md +21 -0
- package/dist/browser/createBrowserContext.d.ts.map +1 -1
- package/dist/browser/index.js +9 -7
- package/dist/browser/index.js.map +1 -1
- package/dist/{chunk-AV3MKD64.js → chunk-5PFEKHX5.js} +30 -5
- package/dist/chunk-5PFEKHX5.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/inspector/{custom-element-I7Q6H5E5.js → custom-element-TUXKXSZU.js} +18791 -18806
- package/dist/inspector/custom-element-TUXKXSZU.js.map +1 -0
- package/dist/inspector/register-custom-element.js +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/testing.js +1 -1
- package/dist/react/testing.js.map +1 -1
- package/dist/react-native-core/index.d.ts +1 -1
- package/dist/react-native-core/index.d.ts.map +1 -1
- package/dist/react-native-core/index.js +15 -31
- package/dist/react-native-core/index.js.map +1 -1
- package/dist/react-native-core/platform.d.ts +1 -1
- package/dist/react-native-core/platform.d.ts.map +1 -1
- package/dist/testing.js +22 -3
- package/dist/testing.js.map +1 -1
- package/dist/tools/exports.d.ts +1 -1
- package/dist/tools/exports.d.ts.map +1 -1
- package/dist/tools/implementation/createContext.d.ts +8 -4
- package/dist/tools/implementation/createContext.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +12 -13
- package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
- package/dist/tools/implementation/zodSchema/zodCo.d.ts +39 -9
- package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
- package/dist/tools/subscribe/SubscriptionScope.d.ts +2 -0
- package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
- package/dist/tools/testing.d.ts +3 -1
- package/dist/tools/testing.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/browser/createBrowserContext.ts +8 -6
- package/src/react-core/tests/useCoState.test.ts +0 -12
- package/src/react-native-core/index.ts +1 -1
- package/src/react-native-core/platform.ts +13 -12
- package/src/tools/exports.ts +2 -0
- package/src/tools/implementation/createContext.ts +16 -0
- package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +17 -15
- package/src/tools/implementation/zodSchema/zodCo.ts +54 -32
- package/src/tools/subscribe/SubscriptionScope.ts +20 -0
- package/src/tools/testing.ts +25 -2
- package/src/tools/tests/coFeed.test.ts +190 -239
- package/src/tools/tests/coMap.test.ts +0 -8
- package/src/tools/tests/coPlainText.test.ts +2 -1
- package/src/tools/tests/load.test.ts +65 -30
- package/src/tools/tests/subscribe.test.ts +92 -0
- package/dist/chunk-AV3MKD64.js.map +0 -1
- package/dist/inspector/custom-element-I7Q6H5E5.js.map +0 -1
- package/dist/react-native-core/storage/sqlite-react-native.d.ts +0 -9
- package/dist/react-native-core/storage/sqlite-react-native.d.ts.map +0 -1
- package/src/react-native-core/storage/sqlite-react-native.ts +0 -19
@@ -8,6 +8,7 @@ import {
|
|
8
8
|
RawAccount,
|
9
9
|
RawAccountID,
|
10
10
|
SessionID,
|
11
|
+
StorageAPI,
|
11
12
|
} from "cojson";
|
12
13
|
import { AuthSecretStorage } from "../auth/AuthSecretStorage.js";
|
13
14
|
import { type Account, type AccountClass } from "../coValues/account.js";
|
@@ -93,6 +94,7 @@ export async function createJazzContextFromExistingCredentials<
|
|
93
94
|
credentials,
|
94
95
|
peersToLoadFrom,
|
95
96
|
crypto,
|
97
|
+
storage,
|
96
98
|
AccountSchema: PropsAccountSchema,
|
97
99
|
sessionProvider,
|
98
100
|
onLogOut,
|
@@ -103,6 +105,7 @@ export async function createJazzContextFromExistingCredentials<
|
|
103
105
|
AccountSchema?: S;
|
104
106
|
sessionProvider: SessionProvider;
|
105
107
|
onLogOut?: () => void;
|
108
|
+
storage?: StorageAPI;
|
106
109
|
}): Promise<JazzContextWithAccount<InstanceOfSchema<S>>> {
|
107
110
|
const { sessionID, sessionDone } = await sessionProvider(
|
108
111
|
credentials.accountID,
|
@@ -120,6 +123,7 @@ export async function createJazzContextFromExistingCredentials<
|
|
120
123
|
sessionID: sessionID,
|
121
124
|
peersToLoadFrom: peersToLoadFrom,
|
122
125
|
crypto: crypto,
|
126
|
+
storage,
|
123
127
|
migration: async (rawAccount, _node, creationProps) => {
|
124
128
|
const account = AccountClass.fromRaw(rawAccount) as InstanceOfSchema<S>;
|
125
129
|
activeAccountContext.set(account);
|
@@ -157,6 +161,7 @@ export async function createJazzContextForNewAccount<
|
|
157
161
|
crypto,
|
158
162
|
AccountSchema: PropsAccountSchema,
|
159
163
|
onLogOut,
|
164
|
+
storage,
|
160
165
|
}: {
|
161
166
|
creationProps: { name: string };
|
162
167
|
initialAgentSecret?: AgentSecret;
|
@@ -164,6 +169,7 @@ export async function createJazzContextForNewAccount<
|
|
164
169
|
crypto: CryptoProvider;
|
165
170
|
AccountSchema?: S;
|
166
171
|
onLogOut?: () => Promise<void>;
|
172
|
+
storage?: StorageAPI;
|
167
173
|
}): Promise<JazzContextWithAccount<InstanceOfSchema<S>>> {
|
168
174
|
const CurrentAccountSchema =
|
169
175
|
PropsAccountSchema ?? (RegisteredSchemas["Account"] as unknown as S);
|
@@ -175,6 +181,7 @@ export async function createJazzContextForNewAccount<
|
|
175
181
|
peersToLoadFrom,
|
176
182
|
crypto,
|
177
183
|
initialAgentSecret,
|
184
|
+
storage,
|
178
185
|
migration: async (rawAccount, _node, creationProps) => {
|
179
186
|
const account = AccountClass.fromRaw(rawAccount) as InstanceOfSchema<S>;
|
180
187
|
activeAccountContext.set(account);
|
@@ -212,6 +219,7 @@ export async function createJazzContext<
|
|
212
219
|
AccountSchema?: S;
|
213
220
|
sessionProvider: SessionProvider;
|
214
221
|
authSecretStorage: AuthSecretStorage;
|
222
|
+
storage?: StorageAPI;
|
215
223
|
}) {
|
216
224
|
const crypto = options.crypto;
|
217
225
|
|
@@ -236,6 +244,7 @@ export async function createJazzContext<
|
|
236
244
|
onLogOut: () => {
|
237
245
|
authSecretStorage.clearWithoutNotify();
|
238
246
|
},
|
247
|
+
storage: options.storage,
|
239
248
|
});
|
240
249
|
} else {
|
241
250
|
const secretSeed = options.crypto.newRandomSecretSeed();
|
@@ -257,6 +266,7 @@ export async function createJazzContext<
|
|
257
266
|
onLogOut: async () => {
|
258
267
|
await authSecretStorage.clearWithoutNotify();
|
259
268
|
},
|
269
|
+
storage: options.storage,
|
260
270
|
});
|
261
271
|
|
262
272
|
if (!options.newAccountProps) {
|
@@ -278,9 +288,11 @@ export async function createJazzContext<
|
|
278
288
|
export function createAnonymousJazzContext({
|
279
289
|
peersToLoadFrom,
|
280
290
|
crypto,
|
291
|
+
storage,
|
281
292
|
}: {
|
282
293
|
peersToLoadFrom: Peer[];
|
283
294
|
crypto: CryptoProvider;
|
295
|
+
storage?: StorageAPI;
|
284
296
|
}): JazzContextWithAgent {
|
285
297
|
const agentSecret = crypto.newRandomAgentSecret();
|
286
298
|
|
@@ -294,6 +306,10 @@ export function createAnonymousJazzContext({
|
|
294
306
|
node.syncManager.addPeer(peer);
|
295
307
|
}
|
296
308
|
|
309
|
+
if (storage) {
|
310
|
+
node.setStorage(storage);
|
311
|
+
}
|
312
|
+
|
297
313
|
activeAccountContext.setGuestMode();
|
298
314
|
|
299
315
|
return {
|
@@ -7,22 +7,24 @@ import { z } from "../zodReExport.js";
|
|
7
7
|
import { Loaded, ResolveQuery } from "../zodSchema.js";
|
8
8
|
import { AnyCoMapSchema, CoMapSchema } from "./CoMapSchema.js";
|
9
9
|
|
10
|
+
export type BaseProfileShape = {
|
11
|
+
name: z.core.$ZodString<string>;
|
12
|
+
inbox?: z.core.$ZodOptional<z.core.$ZodString>;
|
13
|
+
inboxInvite?: z.core.$ZodOptional<z.core.$ZodString>;
|
14
|
+
};
|
15
|
+
|
16
|
+
export type BaseAccountShape = {
|
17
|
+
profile: AnyCoMapSchema<BaseProfileShape>;
|
18
|
+
root: AnyCoMapSchema;
|
19
|
+
};
|
20
|
+
|
21
|
+
export type DefaultAccountShape = {
|
22
|
+
profile: CoMapSchema<BaseProfileShape>;
|
23
|
+
root: CoMapSchema<{}>;
|
24
|
+
};
|
25
|
+
|
10
26
|
export type AccountSchema<
|
11
|
-
Shape extends
|
12
|
-
profile: AnyCoMapSchema<{
|
13
|
-
name: z.core.$ZodString<string>;
|
14
|
-
inbox?: z.core.$ZodOptional<z.core.$ZodString>;
|
15
|
-
inboxInvite?: z.core.$ZodOptional<z.core.$ZodString>;
|
16
|
-
}>;
|
17
|
-
root: AnyCoMapSchema;
|
18
|
-
} = {
|
19
|
-
profile: CoMapSchema<{
|
20
|
-
name: z.core.$ZodString<string>;
|
21
|
-
inbox?: z.core.$ZodOptional<z.core.$ZodString>;
|
22
|
-
inboxInvite?: z.core.$ZodOptional<z.core.$ZodString>;
|
23
|
-
}>;
|
24
|
-
root: CoMapSchema<{}>;
|
25
|
-
},
|
27
|
+
Shape extends BaseAccountShape = DefaultAccountShape,
|
26
28
|
> = Omit<CoMapSchema<Shape>, "create" | "load" | "withMigration"> & {
|
27
29
|
builtin: "Account";
|
28
30
|
|
@@ -1,22 +1,23 @@
|
|
1
1
|
import {
|
2
2
|
type Account,
|
3
|
-
AccountCreationProps,
|
4
|
-
AccountSchema,
|
5
|
-
AnyCoMapSchema,
|
3
|
+
type AccountCreationProps,
|
4
|
+
type AccountSchema,
|
5
|
+
type AnyCoMapSchema,
|
6
|
+
BaseAccountShape,
|
6
7
|
CoFeed,
|
7
|
-
CoFeedSchema,
|
8
|
-
CoListSchema,
|
9
|
-
CoMapSchema,
|
8
|
+
type CoFeedSchema,
|
9
|
+
type CoListSchema,
|
10
|
+
type CoMapSchema,
|
10
11
|
CoPlainText,
|
11
|
-
CoProfileSchema,
|
12
|
-
CoRecordSchema,
|
12
|
+
type CoProfileSchema,
|
13
|
+
type CoRecordSchema,
|
13
14
|
CoRichText,
|
14
|
-
DefaultProfileShape,
|
15
|
+
type DefaultProfileShape,
|
15
16
|
FileStream,
|
16
|
-
FileStreamSchema,
|
17
|
+
type FileStreamSchema,
|
17
18
|
ImageDefinition,
|
18
|
-
PlainTextSchema,
|
19
|
-
Simplify,
|
19
|
+
type PlainTextSchema,
|
20
|
+
type Simplify,
|
20
21
|
zodSchemaToCoSchema,
|
21
22
|
} from "../../internal.js";
|
22
23
|
import { RichTextSchema } from "./schemaTypes/RichTextSchema.js";
|
@@ -82,16 +83,9 @@ export const coMapDefiner = <Shape extends z.core.$ZodLooseShape>(
|
|
82
83
|
return enrichCoMapSchema(objectSchema);
|
83
84
|
};
|
84
85
|
|
85
|
-
function enrichAccountSchema<
|
86
|
-
Shape
|
87
|
-
|
88
|
-
name: z.core.$ZodString<string>;
|
89
|
-
inbox?: z.core.$ZodOptional<z.core.$ZodString>;
|
90
|
-
inboxInvite?: z.core.$ZodOptional<z.core.$ZodString>;
|
91
|
-
}>;
|
92
|
-
root: AnyCoMapSchema;
|
93
|
-
},
|
94
|
-
>(schema: z.ZodObject<Shape, z.core.$strip>) {
|
86
|
+
function enrichAccountSchema<Shape extends BaseAccountShape>(
|
87
|
+
schema: z.ZodObject<Shape, z.core.$strip>,
|
88
|
+
) {
|
95
89
|
const enrichedSchema = Object.assign(schema, {
|
96
90
|
collaborative: true,
|
97
91
|
builtin: "Account",
|
@@ -142,16 +136,44 @@ function enrichAccountSchema<
|
|
142
136
|
return enrichedSchema;
|
143
137
|
}
|
144
138
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
139
|
+
/**
|
140
|
+
* Defines a collaborative account schema for Jazz applications.
|
141
|
+
*
|
142
|
+
* Creates an account schema that represents a user account with profile and root data.
|
143
|
+
* Accounts are the primary way to identify and manage users in Jazz applications.
|
144
|
+
*
|
145
|
+
* @template Shape - The shape of the account schema extending BaseAccountShape
|
146
|
+
* @param shape - The account schema shape. Defaults to a basic profile with name, inbox, and inboxInvite fields, plus an empty root object.
|
147
|
+
*
|
148
|
+
* @example
|
149
|
+
* ```typescript
|
150
|
+
* // Basic account with default profile
|
151
|
+
* const BasicAccount = co.account();
|
152
|
+
*
|
153
|
+
* // Custom account with specific profile and root structure
|
154
|
+
* const JazzAccount = co.account({
|
155
|
+
* profile: co.profile({
|
156
|
+
* name: z.string(),
|
157
|
+
* avatar: z.optional(z.string()),
|
158
|
+
* }),
|
159
|
+
* root: co.map({
|
160
|
+
* organizations: co.list(Organization),
|
161
|
+
* draftOrganization: DraftOrganization,
|
162
|
+
* }),
|
163
|
+
* }).withMigration(async (account) => {
|
164
|
+
* // Migration logic for existing accounts
|
165
|
+
* if (account.profile === undefined) {
|
166
|
+
* const group = Group.create();
|
167
|
+
* account.profile = co.profile().create(
|
168
|
+
* { name: getRandomUsername() },
|
169
|
+
* group
|
170
|
+
* );
|
171
|
+
* group.addMember("everyone", "reader");
|
172
|
+
* }
|
173
|
+
* });
|
174
|
+
* ```
|
175
|
+
*/
|
176
|
+
export const coAccountDefiner = <Shape extends BaseAccountShape>(
|
155
177
|
shape: Shape = {
|
156
178
|
profile: coMapDefiner({
|
157
179
|
name: z.string(),
|
@@ -249,6 +249,10 @@ export class SubscriptionScope<D extends CoValue> {
|
|
249
249
|
// If the value is in error, we send the update regardless of the children statuses
|
250
250
|
if (this.value.type !== "loaded") return true;
|
251
251
|
|
252
|
+
if (this.isStreaming() && !this.isFileStream()) {
|
253
|
+
return false;
|
254
|
+
}
|
255
|
+
|
252
256
|
for (const value of this.childValues.values()) {
|
253
257
|
// We don't wait for autoloaded values to be loaded, in order to stream updates
|
254
258
|
// on autoloaded lists or records
|
@@ -285,6 +289,22 @@ export class SubscriptionScope<D extends CoValue> {
|
|
285
289
|
return undefined;
|
286
290
|
}
|
287
291
|
|
292
|
+
isStreaming() {
|
293
|
+
if (this.value.type !== "loaded") {
|
294
|
+
return false;
|
295
|
+
}
|
296
|
+
|
297
|
+
return this.value.value._raw.core.verified.isStreaming();
|
298
|
+
}
|
299
|
+
|
300
|
+
isFileStream() {
|
301
|
+
if (this.value.type !== "loaded") {
|
302
|
+
return false;
|
303
|
+
}
|
304
|
+
|
305
|
+
return this.value.value._raw.core.verified.header.meta?.type === "binary";
|
306
|
+
}
|
307
|
+
|
288
308
|
triggerUpdate() {
|
289
309
|
if (!this.shouldSendUpdates()) return;
|
290
310
|
if (!this.dirty) return;
|
package/src/tools/testing.ts
CHANGED
@@ -19,7 +19,10 @@ import {
|
|
19
19
|
randomSessionProvider,
|
20
20
|
} from "./internal.js";
|
21
21
|
|
22
|
-
const syncServer: { current: LocalNode | null } = {
|
22
|
+
const syncServer: { current: LocalNode | null; asyncPeers: boolean } = {
|
23
|
+
current: null,
|
24
|
+
asyncPeers: false,
|
25
|
+
};
|
23
26
|
|
24
27
|
export class TestJSCrypto extends PureJSCrypto {
|
25
28
|
static async create() {
|
@@ -57,6 +60,23 @@ export function getPeerConnectedToTestSyncServer() {
|
|
57
60
|
peer2role: "server",
|
58
61
|
},
|
59
62
|
);
|
63
|
+
|
64
|
+
if (syncServer.asyncPeers) {
|
65
|
+
const push = aPeer.outgoing.push;
|
66
|
+
|
67
|
+
aPeer.outgoing.push = (message) => {
|
68
|
+
setTimeout(() => {
|
69
|
+
push.call(aPeer.outgoing, message);
|
70
|
+
});
|
71
|
+
};
|
72
|
+
|
73
|
+
bPeer.outgoing.push = (message) => {
|
74
|
+
setTimeout(() => {
|
75
|
+
push.call(bPeer.outgoing, message);
|
76
|
+
});
|
77
|
+
};
|
78
|
+
}
|
79
|
+
|
60
80
|
syncServer.current.syncManager.addPeer(aPeer);
|
61
81
|
|
62
82
|
return bPeer;
|
@@ -283,7 +303,9 @@ export async function linkAccounts(
|
|
283
303
|
await b.waitForAllCoValuesSync();
|
284
304
|
}
|
285
305
|
|
286
|
-
export async function setupJazzTestSync(
|
306
|
+
export async function setupJazzTestSync({
|
307
|
+
asyncPeers = false,
|
308
|
+
}: { asyncPeers?: boolean } = {}) {
|
287
309
|
if (syncServer.current) {
|
288
310
|
syncServer.current.gracefulShutdown();
|
289
311
|
}
|
@@ -296,6 +318,7 @@ export async function setupJazzTestSync() {
|
|
296
318
|
});
|
297
319
|
|
298
320
|
syncServer.current = account._raw.core.node;
|
321
|
+
syncServer.asyncPeers = asyncPeers;
|
299
322
|
|
300
323
|
return account;
|
301
324
|
}
|