jazz-tools 0.8.44 → 0.8.48
Sign up to get free protection for your applications and to get access to all the features.
- package/.turbo/turbo-build.log +16 -10
- package/CHANGELOG.md +21 -0
- package/dist/chunk-6OHBW32Q.js +2853 -0
- package/dist/chunk-6OHBW32Q.js.map +1 -0
- package/dist/index.native.js +63 -0
- package/dist/index.native.js.map +1 -0
- package/dist/index.web.js +61 -0
- package/dist/index.web.js.map +1 -0
- package/package.json +9 -12
- package/src/coValues/account.ts +29 -10
- package/src/coValues/coFeed.ts +4 -3
- package/src/coValues/coList.ts +8 -5
- package/src/coValues/coMap.ts +14 -5
- package/src/coValues/deepLoading.ts +6 -12
- package/src/coValues/extensions/imageDef.ts +3 -1
- package/src/coValues/group.ts +8 -11
- package/src/coValues/inbox.ts +377 -0
- package/src/coValues/interfaces.ts +9 -6
- package/src/coValues/profile.ts +11 -0
- package/src/coValues/registeredSchemas.ts +12 -0
- package/src/exports.ts +21 -15
- package/src/implementation/anonymousJazzAgent.ts +6 -0
- package/src/implementation/createContext.ts +8 -9
- package/src/implementation/refs.ts +1 -1
- package/src/implementation/subscriptionScope.ts +1 -1
- package/src/index.native.ts +0 -1
- package/src/internal.ts +1 -9
- package/src/tests/account.test.ts +2 -2
- package/src/tests/coFeed.test.ts +0 -9
- package/src/tests/coMap.test.ts +11 -8
- package/src/tests/groupsAndAccounts.test.ts +1 -63
- package/src/tests/inbox.test.ts +299 -0
- package/src/tests/schemaUnion.test.ts +1 -1
- package/src/tests/utils.ts +14 -0
- package/tsup.config.ts +13 -0
- package/dist/native/coValues/account.js +0 -221
- package/dist/native/coValues/account.js.map +0 -1
- package/dist/native/coValues/coFeed.js +0 -571
- package/dist/native/coValues/coFeed.js.map +0 -1
- package/dist/native/coValues/coList.js +0 -404
- package/dist/native/coValues/coList.js.map +0 -1
- package/dist/native/coValues/coMap.js +0 -537
- package/dist/native/coValues/coMap.js.map +0 -1
- package/dist/native/coValues/deepLoading.js +0 -63
- package/dist/native/coValues/deepLoading.js.map +0 -1
- package/dist/native/coValues/extensions/imageDef.js +0 -42
- package/dist/native/coValues/extensions/imageDef.js.map +0 -1
- package/dist/native/coValues/group.js +0 -136
- package/dist/native/coValues/group.js.map +0 -1
- package/dist/native/coValues/interfaces.js +0 -135
- package/dist/native/coValues/interfaces.js.map +0 -1
- package/dist/native/coValues/schemaUnion.js +0 -89
- package/dist/native/coValues/schemaUnion.js.map +0 -1
- package/dist/native/exports.js +0 -5
- package/dist/native/exports.js.map +0 -1
- package/dist/native/implementation/createContext.js +0 -157
- package/dist/native/implementation/createContext.js.map +0 -1
- package/dist/native/implementation/devtoolsFormatters.js +0 -95
- package/dist/native/implementation/devtoolsFormatters.js.map +0 -1
- package/dist/native/implementation/errors.js +0 -2
- package/dist/native/implementation/errors.js.map +0 -1
- package/dist/native/implementation/inspect.js +0 -2
- package/dist/native/implementation/inspect.js.map +0 -1
- package/dist/native/implementation/refs.js +0 -115
- package/dist/native/implementation/refs.js.map +0 -1
- package/dist/native/implementation/schema.js +0 -96
- package/dist/native/implementation/schema.js.map +0 -1
- package/dist/native/implementation/subscriptionScope.js +0 -91
- package/dist/native/implementation/subscriptionScope.js.map +0 -1
- package/dist/native/implementation/symbols.js +0 -4
- package/dist/native/implementation/symbols.js.map +0 -1
- package/dist/native/index.native.js +0 -3
- package/dist/native/index.native.js.map +0 -1
- package/dist/native/internal.js +0 -18
- package/dist/native/internal.js.map +0 -1
- package/dist/native/lib/cache.js +0 -13
- package/dist/native/lib/cache.js.map +0 -1
- package/dist/native/lib/cache.test.js +0 -52
- package/dist/native/lib/cache.test.js.map +0 -1
- package/dist/web/coValues/account.js +0 -221
- package/dist/web/coValues/account.js.map +0 -1
- package/dist/web/coValues/coFeed.js +0 -571
- package/dist/web/coValues/coFeed.js.map +0 -1
- package/dist/web/coValues/coList.js +0 -404
- package/dist/web/coValues/coList.js.map +0 -1
- package/dist/web/coValues/coMap.js +0 -537
- package/dist/web/coValues/coMap.js.map +0 -1
- package/dist/web/coValues/deepLoading.js +0 -63
- package/dist/web/coValues/deepLoading.js.map +0 -1
- package/dist/web/coValues/extensions/imageDef.js +0 -42
- package/dist/web/coValues/extensions/imageDef.js.map +0 -1
- package/dist/web/coValues/group.js +0 -136
- package/dist/web/coValues/group.js.map +0 -1
- package/dist/web/coValues/interfaces.js +0 -135
- package/dist/web/coValues/interfaces.js.map +0 -1
- package/dist/web/coValues/schemaUnion.js +0 -89
- package/dist/web/coValues/schemaUnion.js.map +0 -1
- package/dist/web/exports.js +0 -5
- package/dist/web/exports.js.map +0 -1
- package/dist/web/implementation/createContext.js +0 -157
- package/dist/web/implementation/createContext.js.map +0 -1
- package/dist/web/implementation/devtoolsFormatters.js +0 -95
- package/dist/web/implementation/devtoolsFormatters.js.map +0 -1
- package/dist/web/implementation/errors.js +0 -2
- package/dist/web/implementation/errors.js.map +0 -1
- package/dist/web/implementation/inspect.js +0 -2
- package/dist/web/implementation/inspect.js.map +0 -1
- package/dist/web/implementation/refs.js +0 -115
- package/dist/web/implementation/refs.js.map +0 -1
- package/dist/web/implementation/schema.js +0 -96
- package/dist/web/implementation/schema.js.map +0 -1
- package/dist/web/implementation/subscriptionScope.js +0 -91
- package/dist/web/implementation/subscriptionScope.js.map +0 -1
- package/dist/web/implementation/symbols.js +0 -4
- package/dist/web/implementation/symbols.js.map +0 -1
- package/dist/web/index.web.js +0 -3
- package/dist/web/index.web.js.map +0 -1
- package/dist/web/internal.js +0 -18
- package/dist/web/internal.js.map +0 -1
- package/dist/web/lib/cache.js +0 -13
- package/dist/web/lib/cache.js.map +0 -1
- package/dist/web/lib/cache.test.js +0 -52
- package/dist/web/lib/cache.test.js.map +0 -1
@@ -0,0 +1,377 @@
|
|
1
|
+
import {
|
2
|
+
CoID,
|
3
|
+
InviteSecret,
|
4
|
+
RawAccount,
|
5
|
+
RawCoMap,
|
6
|
+
RawControlledAccount,
|
7
|
+
SessionID,
|
8
|
+
} from "cojson";
|
9
|
+
import { CoStreamItem, RawCoStream } from "cojson";
|
10
|
+
import { type Account } from "./account.js";
|
11
|
+
import { CoValue, CoValueClass, ID, loadCoValue } from "./interfaces.js";
|
12
|
+
|
13
|
+
export type InboxInvite = `${CoID<MessagesStream>}/${InviteSecret}`;
|
14
|
+
type TxKey = `${SessionID}/${number}`;
|
15
|
+
|
16
|
+
type MessagesStream = RawCoStream<CoID<InboxMessage<CoValue, any>>>;
|
17
|
+
type FailedMessagesStream = RawCoStream<{
|
18
|
+
errors: string[];
|
19
|
+
value: CoID<InboxMessage<CoValue, any>>;
|
20
|
+
}>;
|
21
|
+
type TxKeyStream = RawCoStream<TxKey>;
|
22
|
+
export type InboxRoot = RawCoMap<{
|
23
|
+
messages: CoID<MessagesStream>;
|
24
|
+
processed: CoID<TxKeyStream>;
|
25
|
+
failed: CoID<FailedMessagesStream>;
|
26
|
+
inviteLink: InboxInvite;
|
27
|
+
}>;
|
28
|
+
|
29
|
+
export function createInboxRoot(account: Account) {
|
30
|
+
if (!account.isMe) {
|
31
|
+
throw new Error("Account is not controlled");
|
32
|
+
}
|
33
|
+
|
34
|
+
const rawAccount = account._raw as RawControlledAccount;
|
35
|
+
|
36
|
+
const group = rawAccount.createGroup();
|
37
|
+
const messagesFeed = group.createStream<MessagesStream>();
|
38
|
+
|
39
|
+
const inboxRoot = rawAccount.createMap<InboxRoot>();
|
40
|
+
const processedFeed = rawAccount.createStream<TxKeyStream>();
|
41
|
+
const failedFeed = rawAccount.createStream<FailedMessagesStream>();
|
42
|
+
|
43
|
+
const inviteLink =
|
44
|
+
`${messagesFeed.id}/${group.createInvite("writeOnly")}` as const;
|
45
|
+
|
46
|
+
inboxRoot.set("messages", messagesFeed.id);
|
47
|
+
inboxRoot.set("processed", processedFeed.id);
|
48
|
+
inboxRoot.set("failed", failedFeed.id);
|
49
|
+
|
50
|
+
return {
|
51
|
+
id: inboxRoot.id,
|
52
|
+
inviteLink,
|
53
|
+
};
|
54
|
+
}
|
55
|
+
|
56
|
+
type InboxMessage<I extends CoValue, O extends CoValue | undefined> = RawCoMap<{
|
57
|
+
payload: ID<I>;
|
58
|
+
result: ID<O> | undefined;
|
59
|
+
processed: boolean;
|
60
|
+
error: string | undefined;
|
61
|
+
}>;
|
62
|
+
|
63
|
+
function createInboxMessage<I extends CoValue, O extends CoValue | undefined>(
|
64
|
+
payload: I,
|
65
|
+
inboxOwner: RawAccount,
|
66
|
+
) {
|
67
|
+
const group = payload._raw.group;
|
68
|
+
|
69
|
+
if (group instanceof RawAccount) {
|
70
|
+
throw new Error("Inbox messages should be owned by a group");
|
71
|
+
}
|
72
|
+
|
73
|
+
group.addMember(inboxOwner, "writer");
|
74
|
+
|
75
|
+
const message = group.createMap<InboxMessage<I, O>>({
|
76
|
+
payload: payload.id,
|
77
|
+
result: undefined,
|
78
|
+
processed: false,
|
79
|
+
error: undefined,
|
80
|
+
});
|
81
|
+
|
82
|
+
return message;
|
83
|
+
}
|
84
|
+
|
85
|
+
export class Inbox {
|
86
|
+
account: Account;
|
87
|
+
messages: MessagesStream;
|
88
|
+
processed: TxKeyStream;
|
89
|
+
failed: FailedMessagesStream;
|
90
|
+
root: InboxRoot;
|
91
|
+
processing = new Set<`${SessionID}/${number}`>();
|
92
|
+
|
93
|
+
private constructor(
|
94
|
+
account: Account,
|
95
|
+
root: InboxRoot,
|
96
|
+
messages: MessagesStream,
|
97
|
+
processed: TxKeyStream,
|
98
|
+
failed: FailedMessagesStream,
|
99
|
+
) {
|
100
|
+
this.account = account;
|
101
|
+
this.root = root;
|
102
|
+
this.messages = messages;
|
103
|
+
this.processed = processed;
|
104
|
+
this.failed = failed;
|
105
|
+
}
|
106
|
+
|
107
|
+
subscribe<I extends CoValue, O extends CoValue | undefined>(
|
108
|
+
Schema: CoValueClass<I>,
|
109
|
+
callback: (
|
110
|
+
message: I,
|
111
|
+
senderAccountID: ID<Account>,
|
112
|
+
) => Promise<O | undefined | void>,
|
113
|
+
options: { retries?: number } = {},
|
114
|
+
) {
|
115
|
+
const processed = new Set<`${SessionID}/${number}`>();
|
116
|
+
const failed = new Map<`${SessionID}/${number}`, string[]>();
|
117
|
+
const node = this.account._raw.core.node;
|
118
|
+
|
119
|
+
this.processed.subscribe((stream) => {
|
120
|
+
for (const items of Object.values(stream.items)) {
|
121
|
+
for (const item of items) {
|
122
|
+
processed.add(item.value as TxKey);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
});
|
126
|
+
|
127
|
+
const { account } = this;
|
128
|
+
const { retries = 3 } = options;
|
129
|
+
|
130
|
+
let failTimer: ReturnType<typeof setTimeout> | number | undefined =
|
131
|
+
undefined;
|
132
|
+
|
133
|
+
const clearFailTimer = () => {
|
134
|
+
clearTimeout(failTimer);
|
135
|
+
failTimer = undefined;
|
136
|
+
};
|
137
|
+
|
138
|
+
const handleNewMessages = (stream: MessagesStream) => {
|
139
|
+
clearFailTimer(); // Stop the failure timers, we're going to process the failed entries anyway
|
140
|
+
|
141
|
+
for (const [sessionID, items] of Object.entries(stream.items) as [
|
142
|
+
SessionID,
|
143
|
+
CoStreamItem<CoID<InboxMessage<I, O>>>[],
|
144
|
+
][]) {
|
145
|
+
const accountID = getAccountIDfromSessionID(sessionID);
|
146
|
+
|
147
|
+
if (!accountID) {
|
148
|
+
console.warn("Received message from unknown account", sessionID);
|
149
|
+
continue;
|
150
|
+
}
|
151
|
+
|
152
|
+
for (const item of items) {
|
153
|
+
const txKey = `${sessionID}/${item.tx.txIndex}` as const;
|
154
|
+
|
155
|
+
if (!processed.has(txKey) && !this.processing.has(txKey)) {
|
156
|
+
this.processing.add(txKey);
|
157
|
+
|
158
|
+
const id = item.value;
|
159
|
+
|
160
|
+
node
|
161
|
+
.load(id)
|
162
|
+
.then((message) => {
|
163
|
+
if (message === "unavailable") {
|
164
|
+
return Promise.reject(
|
165
|
+
new Error("Unable to load inbox message " + id),
|
166
|
+
);
|
167
|
+
}
|
168
|
+
|
169
|
+
return loadCoValue(
|
170
|
+
Schema,
|
171
|
+
message.get("payload") as ID<I>,
|
172
|
+
account,
|
173
|
+
[],
|
174
|
+
);
|
175
|
+
})
|
176
|
+
.then((value) => {
|
177
|
+
if (!value) {
|
178
|
+
return Promise.reject(
|
179
|
+
new Error("Unable to load inbox message " + id),
|
180
|
+
);
|
181
|
+
}
|
182
|
+
|
183
|
+
return callback(value, accountID);
|
184
|
+
})
|
185
|
+
.then((result) => {
|
186
|
+
const inboxMessage = node
|
187
|
+
.expectCoValueLoaded(item.value)
|
188
|
+
.getCurrentContent() as RawCoMap;
|
189
|
+
|
190
|
+
if (result) {
|
191
|
+
inboxMessage.set("result", result.id);
|
192
|
+
}
|
193
|
+
|
194
|
+
inboxMessage.set("processed", true);
|
195
|
+
|
196
|
+
this.processed.push(txKey);
|
197
|
+
this.processing.delete(txKey);
|
198
|
+
})
|
199
|
+
.catch((error) => {
|
200
|
+
console.error("Error processing inbox message", error);
|
201
|
+
this.processing.delete(txKey);
|
202
|
+
const errors = failed.get(txKey) ?? [];
|
203
|
+
|
204
|
+
const stringifiedError = String(error);
|
205
|
+
errors.push(stringifiedError);
|
206
|
+
|
207
|
+
const inboxMessage = node
|
208
|
+
.expectCoValueLoaded(item.value)
|
209
|
+
.getCurrentContent() as RawCoMap;
|
210
|
+
|
211
|
+
inboxMessage.set("error", stringifiedError);
|
212
|
+
|
213
|
+
if (errors.length > retries) {
|
214
|
+
inboxMessage.set("processed", true);
|
215
|
+
this.processed.push(txKey);
|
216
|
+
this.failed.push({ errors, value: item.value });
|
217
|
+
} else {
|
218
|
+
failed.set(txKey, errors);
|
219
|
+
if (!failTimer) {
|
220
|
+
failTimer = setTimeout(
|
221
|
+
() => handleNewMessages(stream),
|
222
|
+
100,
|
223
|
+
);
|
224
|
+
}
|
225
|
+
}
|
226
|
+
});
|
227
|
+
}
|
228
|
+
}
|
229
|
+
}
|
230
|
+
};
|
231
|
+
|
232
|
+
return this.messages.subscribe(handleNewMessages);
|
233
|
+
}
|
234
|
+
|
235
|
+
static async load(account: Account) {
|
236
|
+
const profile = account.profile;
|
237
|
+
|
238
|
+
if (!profile) {
|
239
|
+
throw new Error("Account profile should already be loaded");
|
240
|
+
}
|
241
|
+
|
242
|
+
if (!profile.inbox) {
|
243
|
+
throw new Error("The account has not set up their inbox");
|
244
|
+
}
|
245
|
+
|
246
|
+
const node = account._raw.core.node;
|
247
|
+
|
248
|
+
const root = await node.load(profile.inbox as CoID<InboxRoot>);
|
249
|
+
|
250
|
+
if (root === "unavailable") {
|
251
|
+
throw new Error("Inbox not found");
|
252
|
+
}
|
253
|
+
|
254
|
+
const [messages, processed, failed] = await Promise.all([
|
255
|
+
node.load(root.get("messages")!),
|
256
|
+
node.load(root.get("processed")!),
|
257
|
+
node.load(root.get("failed")!),
|
258
|
+
]);
|
259
|
+
|
260
|
+
if (
|
261
|
+
messages === "unavailable" ||
|
262
|
+
processed === "unavailable" ||
|
263
|
+
failed === "unavailable"
|
264
|
+
) {
|
265
|
+
throw new Error("Inbox not found");
|
266
|
+
}
|
267
|
+
|
268
|
+
return new Inbox(account, root, messages, processed, failed);
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
272
|
+
export class InboxSender<I extends CoValue, O extends CoValue | undefined> {
|
273
|
+
currentAccount: Account;
|
274
|
+
owner: RawAccount;
|
275
|
+
messages: MessagesStream;
|
276
|
+
|
277
|
+
private constructor(
|
278
|
+
currentAccount: Account,
|
279
|
+
owner: RawAccount,
|
280
|
+
messages: MessagesStream,
|
281
|
+
) {
|
282
|
+
this.currentAccount = currentAccount;
|
283
|
+
this.owner = owner;
|
284
|
+
this.messages = messages;
|
285
|
+
}
|
286
|
+
|
287
|
+
getOwnerAccount() {
|
288
|
+
return this.owner;
|
289
|
+
}
|
290
|
+
|
291
|
+
sendMessage(message: I): Promise<O extends CoValue ? ID<O> : undefined> {
|
292
|
+
const inboxMessage = createInboxMessage<I, O>(message, this.owner);
|
293
|
+
|
294
|
+
this.messages.push(inboxMessage.id);
|
295
|
+
|
296
|
+
return new Promise((resolve, reject) => {
|
297
|
+
inboxMessage.subscribe((message) => {
|
298
|
+
if (message.get("processed")) {
|
299
|
+
const error = message.get("error");
|
300
|
+
if (error) {
|
301
|
+
reject(new Error(error));
|
302
|
+
} else {
|
303
|
+
resolve(
|
304
|
+
message.get("result") as O extends CoValue ? ID<O> : undefined,
|
305
|
+
);
|
306
|
+
}
|
307
|
+
}
|
308
|
+
});
|
309
|
+
});
|
310
|
+
}
|
311
|
+
|
312
|
+
static async load<
|
313
|
+
I extends CoValue,
|
314
|
+
O extends CoValue | undefined = undefined,
|
315
|
+
>(inboxOwnerID: ID<Account>, currentAccount: Account) {
|
316
|
+
const node = currentAccount._raw.core.node;
|
317
|
+
|
318
|
+
const inboxOwnerRaw = await node.load(
|
319
|
+
inboxOwnerID as unknown as CoID<RawAccount>,
|
320
|
+
);
|
321
|
+
|
322
|
+
if (inboxOwnerRaw === "unavailable") {
|
323
|
+
throw new Error("Failed to load the inbox owner");
|
324
|
+
}
|
325
|
+
|
326
|
+
const inboxOwnerProfileRaw = await node.load(inboxOwnerRaw.get("profile")!);
|
327
|
+
|
328
|
+
if (inboxOwnerProfileRaw === "unavailable") {
|
329
|
+
throw new Error("Failed to load the inbox owner profile");
|
330
|
+
}
|
331
|
+
|
332
|
+
const inboxInvite = inboxOwnerProfileRaw.get("inboxInvite");
|
333
|
+
|
334
|
+
if (!inboxInvite) {
|
335
|
+
throw new Error("The user has not set up their inbox");
|
336
|
+
}
|
337
|
+
|
338
|
+
const id = await acceptInvite(inboxInvite as InboxInvite, currentAccount);
|
339
|
+
|
340
|
+
const messages = await node.load(id);
|
341
|
+
|
342
|
+
if (messages === "unavailable") {
|
343
|
+
throw new Error("Inbox not found");
|
344
|
+
}
|
345
|
+
|
346
|
+
return new InboxSender<I, O>(currentAccount, inboxOwnerRaw, messages);
|
347
|
+
}
|
348
|
+
}
|
349
|
+
|
350
|
+
async function acceptInvite(invite: string, account: Account) {
|
351
|
+
const id = invite.slice(0, invite.indexOf("/")) as CoID<MessagesStream>;
|
352
|
+
|
353
|
+
const inviteSecret = invite.slice(invite.indexOf("/") + 1) as InviteSecret;
|
354
|
+
|
355
|
+
if (!id?.startsWith("co_z") || !inviteSecret.startsWith("inviteSecret_")) {
|
356
|
+
throw new Error("Invalid inbox ticket");
|
357
|
+
}
|
358
|
+
|
359
|
+
if (!account.isMe) {
|
360
|
+
throw new Error("Account is not controlled");
|
361
|
+
}
|
362
|
+
|
363
|
+
await (account._raw as RawControlledAccount).acceptInvite(id, inviteSecret);
|
364
|
+
|
365
|
+
return id;
|
366
|
+
}
|
367
|
+
|
368
|
+
function getAccountIDfromSessionID(sessionID: SessionID) {
|
369
|
+
const until = sessionID.indexOf("_session");
|
370
|
+
const accountID = sessionID.slice(0, until);
|
371
|
+
|
372
|
+
if (accountID.startsWith("co_z")) {
|
373
|
+
return accountID as ID<Account>;
|
374
|
+
}
|
375
|
+
|
376
|
+
return;
|
377
|
+
}
|
@@ -1,17 +1,18 @@
|
|
1
1
|
import type { CojsonInternalTypes, RawCoValue } from "cojson";
|
2
2
|
import { RawAccount } from "cojson";
|
3
|
+
import { AnonymousJazzAgent } from "../implementation/anonymousJazzAgent.js";
|
3
4
|
import type { DeeplyLoaded, DepthsIn } from "../internal.js";
|
4
5
|
import {
|
5
|
-
Account,
|
6
|
-
AnonymousJazzAgent,
|
7
|
-
Group,
|
8
6
|
Ref,
|
9
7
|
SubscriptionScope,
|
10
8
|
inspect,
|
11
9
|
subscriptionsScopes,
|
12
10
|
} from "../internal.js";
|
13
11
|
import { coValuesCache } from "../lib/cache.js";
|
12
|
+
import { type Account } from "./account.js";
|
14
13
|
import { fulfillsDepth } from "./deepLoading.js";
|
14
|
+
import { type Group } from "./group.js";
|
15
|
+
import { RegisteredSchemas } from "./registeredSchemas.js";
|
15
16
|
|
16
17
|
/** @category Abstract interfaces */
|
17
18
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
@@ -85,8 +86,8 @@ export class CoValueBase implements CoValue {
|
|
85
86
|
get _owner(): Account | Group {
|
86
87
|
const owner =
|
87
88
|
this._raw.group instanceof RawAccount
|
88
|
-
? Account.fromRaw(this._raw.group)
|
89
|
-
: Group.fromRaw(this._raw.group);
|
89
|
+
? RegisteredSchemas["Account"].fromRaw(this._raw.group)
|
90
|
+
: RegisteredSchemas["Group"].fromRaw(this._raw.group);
|
90
91
|
|
91
92
|
const subScope = subscriptionsScopes.get(this);
|
92
93
|
if (subScope) {
|
@@ -102,7 +103,9 @@ export class CoValueBase implements CoValue {
|
|
102
103
|
const rawAccount = this._raw.core.node.account;
|
103
104
|
|
104
105
|
if (rawAccount instanceof RawAccount) {
|
105
|
-
return coValuesCache.get(rawAccount, () =>
|
106
|
+
return coValuesCache.get(rawAccount, () =>
|
107
|
+
RegisteredSchemas["Account"].fromRaw(rawAccount),
|
108
|
+
);
|
106
109
|
}
|
107
110
|
|
108
111
|
return new AnonymousJazzAgent(this._raw.core.node);
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { CoID } from "cojson";
|
2
|
+
import { co } from "../internal.js";
|
3
|
+
import { CoMap } from "./coMap.js";
|
4
|
+
import { InboxInvite, InboxRoot } from "./inbox.js";
|
5
|
+
|
6
|
+
/** @category Identity & Permissions */
|
7
|
+
export class Profile extends CoMap {
|
8
|
+
name = co.string;
|
9
|
+
inbox = co.optional.json<CoID<InboxRoot>>();
|
10
|
+
inboxInvite = co.optional.json<InboxInvite>();
|
11
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import type { Account } from "./account.js";
|
2
|
+
import type { CoMap } from "./coMap.js";
|
3
|
+
import type { Group } from "./group.js";
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Regisering schemas into this Record to avoid circular dependencies.
|
7
|
+
*/
|
8
|
+
export const RegisteredSchemas = {} as {
|
9
|
+
Account: typeof Account;
|
10
|
+
Group: typeof Group;
|
11
|
+
CoMap: typeof CoMap;
|
12
|
+
};
|
package/src/exports.ts
CHANGED
@@ -12,25 +12,31 @@ export type { CoValue, ID } from "./internal.js";
|
|
12
12
|
|
13
13
|
export { Encoders, co } from "./internal.js";
|
14
14
|
|
15
|
+
export {
|
16
|
+
Inbox,
|
17
|
+
InboxSender,
|
18
|
+
} from "./coValues/inbox.js";
|
19
|
+
|
15
20
|
export {
|
16
21
|
Account,
|
17
|
-
FileStream,
|
18
|
-
BinaryCoStream,
|
19
|
-
CoList,
|
20
|
-
CoMap,
|
21
|
-
CoFeed,
|
22
|
-
CoStream,
|
23
|
-
CoValueBase,
|
24
|
-
Group,
|
25
|
-
ImageDefinition,
|
26
|
-
Profile,
|
27
22
|
isControlledAccount,
|
28
|
-
SchemaUnion,
|
29
23
|
type AccountClass,
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
} from "./coValues/account.js";
|
25
|
+
export { Group } from "./coValues/group.js";
|
26
|
+
export {
|
27
|
+
CoStream,
|
28
|
+
CoFeed,
|
29
|
+
FileStream,
|
30
|
+
BinaryCoStream,
|
31
|
+
} from "./coValues/coFeed.js";
|
32
|
+
export { CoList } from "./coValues/coList.js";
|
33
|
+
export { CoMap, type CoMapInit } from "./coValues/coMap.js";
|
34
|
+
export { CoValueBase } from "./coValues/interfaces.js";
|
35
|
+
export { ImageDefinition } from "./coValues/extensions/imageDef.js";
|
36
|
+
export { Profile } from "./coValues/profile.js";
|
37
|
+
export { SchemaUnion } from "./coValues/schemaUnion.js";
|
38
|
+
|
39
|
+
export type { CoValueClass, DeeplyLoaded, DepthsIn } from "./internal.js";
|
34
40
|
|
35
41
|
export {
|
36
42
|
createCoValueObservable,
|
@@ -9,7 +9,10 @@ import {
|
|
9
9
|
RawAccountID,
|
10
10
|
SessionID,
|
11
11
|
} from "cojson";
|
12
|
-
import { Account, AccountClass
|
12
|
+
import { type Account, type AccountClass } from "../coValues/account.js";
|
13
|
+
import { RegisteredSchemas } from "../coValues/registeredSchemas.js";
|
14
|
+
import type { ID } from "../internal.js";
|
15
|
+
import { AnonymousJazzAgent } from "./anonymousJazzAgent.js";
|
13
16
|
|
14
17
|
export type Credentials = {
|
15
18
|
accountID: ID<Account>;
|
@@ -136,7 +139,8 @@ export async function createJazzContext<Acc extends Account>(
|
|
136
139
|
|
137
140
|
const { auth, sessionProvider, peersToLoadFrom, crypto } = options;
|
138
141
|
const AccountSchema =
|
139
|
-
options.AccountSchema ??
|
142
|
+
options.AccountSchema ??
|
143
|
+
(RegisteredSchemas["Account"] as unknown as AccountClass<Acc>);
|
140
144
|
let authResult: AuthResult;
|
141
145
|
try {
|
142
146
|
authResult = await auth.start(crypto);
|
@@ -165,7 +169,7 @@ export async function createJazzContext<Acc extends Account>(
|
|
165
169
|
fromRaw: rawAccount,
|
166
170
|
}) as Acc;
|
167
171
|
|
168
|
-
await account.
|
172
|
+
await account.applyMigration(creationProps);
|
169
173
|
},
|
170
174
|
});
|
171
175
|
|
@@ -214,7 +218,7 @@ export async function createJazzContext<Acc extends Account>(
|
|
214
218
|
fromRaw: rawAccount,
|
215
219
|
}) as Acc;
|
216
220
|
|
217
|
-
await account.
|
221
|
+
await account.applyMigration(creationProps);
|
218
222
|
},
|
219
223
|
});
|
220
224
|
|
@@ -243,11 +247,6 @@ export async function createJazzContext<Acc extends Account>(
|
|
243
247
|
}
|
244
248
|
}
|
245
249
|
|
246
|
-
export class AnonymousJazzAgent {
|
247
|
-
_type = "Anonymous" as const;
|
248
|
-
constructor(public node: LocalNode) {}
|
249
|
-
}
|
250
|
-
|
251
250
|
export async function createAnonymousJazzContext({
|
252
251
|
peersToLoadFrom,
|
253
252
|
crypto,
|
package/src/index.native.ts
CHANGED
package/src/internal.ts
CHANGED
@@ -2,21 +2,13 @@ export * from "./implementation/symbols.js";
|
|
2
2
|
export * from "./implementation/inspect.js";
|
3
3
|
export * from "./coValues/interfaces.js";
|
4
4
|
|
5
|
-
export * from "./coValues/coMap.js";
|
6
|
-
export * from "./coValues/account.js";
|
7
|
-
export * from "./coValues/coList.js";
|
8
|
-
export * from "./coValues/coFeed.js";
|
9
|
-
export * from "./coValues/schemaUnion.js";
|
10
|
-
export * from "./coValues/group.js";
|
11
|
-
|
12
5
|
export * from "./implementation/errors.js";
|
6
|
+
export * from "./implementation/anonymousJazzAgent.js";
|
13
7
|
export * from "./implementation/refs.js";
|
14
8
|
export * from "./implementation/schema.js";
|
15
9
|
export * from "./implementation/subscriptionScope.js";
|
16
10
|
export * from "./coValues/deepLoading.js";
|
17
11
|
|
18
|
-
export * from "./coValues/extensions/imageDef.js";
|
19
|
-
|
20
12
|
export * from "./implementation/createContext.js";
|
21
13
|
|
22
14
|
import "./implementation/devtoolsFormatters.js";
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { expect, test } from "vitest";
|
2
|
-
import { CoMap, co } from "../
|
3
|
-
import { setupTwoNodes } from "./utils";
|
2
|
+
import { CoMap, co } from "../exports.js";
|
3
|
+
import { setupTwoNodes } from "./utils.js";
|
4
4
|
|
5
5
|
test("waitForAllCoValuesSync should resolve when all the values are synced", async () => {
|
6
6
|
class TestMap extends CoMap {
|
package/src/tests/coFeed.test.ts
CHANGED
@@ -192,15 +192,6 @@ describe("CoFeed resolution", async () => {
|
|
192
192
|
const queue = new cojsonInternals.Channel();
|
193
193
|
|
194
194
|
TestStream.subscribe(stream.id, meOnSecondPeer, [], (subscribedStream) => {
|
195
|
-
console.log("subscribedStream[me.id]", subscribedStream[me.id]);
|
196
|
-
console.log(
|
197
|
-
"subscribedStream[me.id]?.value?.[me.id]?.value",
|
198
|
-
subscribedStream[me.id]?.value?.[me.id]?.value,
|
199
|
-
);
|
200
|
-
console.log(
|
201
|
-
"subscribedStream[me.id]?.value?.[me.id]?.value?.[me.id]?.value",
|
202
|
-
subscribedStream[me.id]?.value?.[me.id]?.value?.[me.id]?.value,
|
203
|
-
);
|
204
195
|
void queue.push(subscribedStream);
|
205
196
|
});
|
206
197
|
|
package/src/tests/coMap.test.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import { connectedPeers } from "cojson/src/streamUtils.ts";
|
2
2
|
import { describe, expect, expectTypeOf, test } from "vitest";
|
3
|
+
import { Group, randomSessionProvider } from "../exports.js";
|
3
4
|
import {
|
4
5
|
Account,
|
5
6
|
CoMap,
|
@@ -11,8 +12,7 @@ import {
|
|
11
12
|
fixedCredentialsAuth,
|
12
13
|
isControlledAccount,
|
13
14
|
} from "../index.web.js";
|
14
|
-
import {
|
15
|
-
import { loadCoValueOrFail, setupTwoNodes } from "./utils.js";
|
15
|
+
import { setupTwoNodes } from "./utils.js";
|
16
16
|
|
17
17
|
const Crypto = await WasmCrypto.create();
|
18
18
|
|
@@ -38,8 +38,6 @@ describe("Simple CoMap operations", async () => {
|
|
38
38
|
crypto: Crypto,
|
39
39
|
});
|
40
40
|
|
41
|
-
console.log("TestMap schema", TestMap.prototype._schema);
|
42
|
-
|
43
41
|
const birthday = new Date();
|
44
42
|
|
45
43
|
const map = TestMap.create(
|
@@ -82,6 +80,13 @@ describe("Simple CoMap operations", async () => {
|
|
82
80
|
expect(mapWithExtra.color).toEqual("red");
|
83
81
|
});
|
84
82
|
|
83
|
+
test("Empty schema", () => {
|
84
|
+
const emptyMap = CoMap.create({}, { owner: me });
|
85
|
+
|
86
|
+
// @ts-expect-error
|
87
|
+
expect(emptyMap.color).toEqual(undefined);
|
88
|
+
});
|
89
|
+
|
85
90
|
describe("Mutation", () => {
|
86
91
|
test("assignment & deletion", () => {
|
87
92
|
map.color = "blue";
|
@@ -468,10 +473,8 @@ describe("CoMap resolution", async () => {
|
|
468
473
|
const queue = new cojsonInternals.Channel<TestMap>();
|
469
474
|
|
470
475
|
TestMap.subscribe(map.id, meOnSecondPeer, {}, (subscribedMap) => {
|
471
|
-
|
472
|
-
|
473
|
-
subscribedMap.nested?.twiceNested?.taste,
|
474
|
-
);
|
476
|
+
// Read to property to trigger loading
|
477
|
+
subscribedMap.nested?.twiceNested?.taste;
|
475
478
|
void queue.push(subscribedMap);
|
476
479
|
});
|
477
480
|
|