@inlang/sdk 0.35.3 → 0.35.5
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.
|
@@ -174,7 +174,7 @@ describe("messages", () => {
|
|
|
174
174
|
project.setSettings({ ...project.settings(), languageTags: ["en"] });
|
|
175
175
|
// TODO: how can we await `setConfig` correctly
|
|
176
176
|
await new Promise((resolve) => setTimeout(resolve, 510));
|
|
177
|
-
expect(effectOnMessagesCounter).toBe(
|
|
177
|
+
expect(effectOnMessagesCounter).toBe(2); // 2 = setSetting (clearing the message index), subsequencial loadMessage call
|
|
178
178
|
expect(Object.values(project.query.messages.getAll()).length).toBe(2);
|
|
179
179
|
});
|
|
180
180
|
it("should react to message udpate", async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createMessagesQuery.d.ts","sourceRoot":"","sources":["../src/createMessagesQuery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAyC,MAAM,UAAU,CAAA;AAEpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAEzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAInD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"createMessagesQuery.d.ts","sourceRoot":"","sources":["../src/createMessagesQuery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAyC,MAAM,UAAU,CAAA;AAEpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAEzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAInD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAwB/D,KAAK,6BAA6B,GAAG;IACpC,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,iBAAiB,CAAA;IAC5B,QAAQ,EAAE,MAAM,eAAe,GAAG,SAAS,CAAA;IAC3C,eAAe,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,GAAG,SAAS,CAAA;IAC7E,0BAA0B,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;IAC/C,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;IACxC,mBAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAA;CACxC,CAAA;AACD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EACnC,WAAW,EACX,SAAS,EACT,QAAQ,EACR,eAAe,EACf,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,GACnB,EAAE,6BAA6B,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAmNpE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactiveMap } from "./reactivity/map.js";
|
|
2
|
-
import { createEffect, onCleanup } from "./reactivity/solid.js";
|
|
2
|
+
import { createEffect, onCleanup, batch } from "./reactivity/solid.js";
|
|
3
3
|
import { createSubscribable } from "./loadProject.js";
|
|
4
4
|
import { createNodeishFsWithWatcher } from "./createNodeishFsWithWatcher.js";
|
|
5
5
|
import { stringifyMessage } from "./storage/helper.js";
|
|
@@ -9,9 +9,6 @@ import { releaseLock } from "./persistence/filelock/releaseLock.js";
|
|
|
9
9
|
import { PluginLoadMessagesError, PluginSaveMessagesError } from "./errors.js";
|
|
10
10
|
import { humanIdHash } from "./storage/human-id/human-readable-id.js";
|
|
11
11
|
const debug = _debug("sdk:messages");
|
|
12
|
-
function sleep(ms) {
|
|
13
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
14
|
-
}
|
|
15
12
|
/**
|
|
16
13
|
* Creates a reactive query API for messages.
|
|
17
14
|
*/
|
|
@@ -194,7 +191,6 @@ export function createMessagesQuery({ projectPath, nodeishFs, settings, resolved
|
|
|
194
191
|
// - json plugin exports into separate file per language.
|
|
195
192
|
// - saving a message in two different languages would lead to a write in de.json first
|
|
196
193
|
// - This will leads to a load of the messages and since en.json has not been saved yet the english variant in the message would get overritten with the old state again
|
|
197
|
-
const maxMessagesPerTick = 500;
|
|
198
194
|
/**
|
|
199
195
|
* Messsage that loads messages from a plugin - this method synchronizes with the saveMessage funciton.
|
|
200
196
|
* If a save is in progress loading will wait until saving is done. If another load kicks in during this load it will queue the
|
|
@@ -227,89 +223,79 @@ async function loadMessagesViaPlugin(fs, lockDirPath, messageState, messages, de
|
|
|
227
223
|
settings: settingsValue,
|
|
228
224
|
nodeishFs: fs,
|
|
229
225
|
}));
|
|
230
|
-
let loadedMessageCount = 0;
|
|
231
226
|
const deletedMessages = new Set(messages.keys());
|
|
232
|
-
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
deletedMessages.delete(currentMessages[0].id);
|
|
245
|
-
// update message in place - leave message id and alias untouched
|
|
246
|
-
loadedMessageClone.alias = {};
|
|
247
|
-
// TODO #1585 we have to map the id of the importedMessage to the alias and fill the id property with the id of the existing message - change when import mesage provides importedMessage.alias
|
|
248
|
-
if (experimentalAliases) {
|
|
249
|
-
loadedMessageClone.alias["default"] = loadedMessageClone.id;
|
|
227
|
+
batch(() => {
|
|
228
|
+
for (const loadedMessage of loadedMessages) {
|
|
229
|
+
const loadedMessageClone = structuredClone(loadedMessage);
|
|
230
|
+
const currentMessages = [...messages.values()]
|
|
231
|
+
// TODO #1585 here we match using the id to support legacy load message plugins - after we introduced import / export methods we will use importedMessage.alias
|
|
232
|
+
.filter((message) => (experimentalAliases ? message.alias["default"] : message.id) === loadedMessage.id);
|
|
233
|
+
if (currentMessages.length > 1) {
|
|
234
|
+
// NOTE: if we happen to find two messages witht the sam alias we throw for now
|
|
235
|
+
// - this could be the case if one edits the aliase manualy
|
|
236
|
+
throw new Error("more than one message with the same id or alias found ");
|
|
237
|
+
}
|
|
238
|
+
else if (currentMessages.length === 1) {
|
|
250
239
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length has checked beforhand
|
|
251
|
-
|
|
240
|
+
deletedMessages.delete(currentMessages[0].id);
|
|
241
|
+
// update message in place - leave message id and alias untouched
|
|
242
|
+
loadedMessageClone.alias = {};
|
|
243
|
+
// TODO #1585 we have to map the id of the importedMessage to the alias and fill the id property with the id of the existing message - change when import mesage provides importedMessage.alias
|
|
244
|
+
if (experimentalAliases) {
|
|
245
|
+
loadedMessageClone.alias["default"] = loadedMessageClone.id;
|
|
246
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length has checked beforhand
|
|
247
|
+
loadedMessageClone.id = currentMessages[0].id;
|
|
248
|
+
}
|
|
249
|
+
// NOTE stringifyMessage encodes messages independent from key order!
|
|
250
|
+
const importedEnecoded = stringifyMessage(loadedMessageClone);
|
|
251
|
+
// NOTE could use hash instead of the whole object JSON to save memory...
|
|
252
|
+
if (messageState.messageLoadHash[loadedMessageClone.id] === importedEnecoded) {
|
|
253
|
+
// debug("skipping upsert!")
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
// This logic is preventing cycles - could also be handled if update api had a parameter for who triggered update
|
|
257
|
+
// e.g. when FS was updated, we don't need to write back to FS
|
|
258
|
+
// update is synchronous, so update effect will be triggered immediately
|
|
259
|
+
// NOTE: this might trigger a save before we have the chance to delete - but since save is async and waits for the lock acquired by this method - its save to set the flags afterwards
|
|
260
|
+
messages.set(loadedMessageClone.id, loadedMessageClone);
|
|
261
|
+
// NOTE could use hash instead of the whole object JSON to save memory...
|
|
262
|
+
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded;
|
|
263
|
+
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone, [
|
|
264
|
+
...messages.values(),
|
|
265
|
+
]);
|
|
252
266
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
267
|
+
else {
|
|
268
|
+
// message with the given alias does not exist so far
|
|
269
|
+
loadedMessageClone.alias = {};
|
|
270
|
+
// TODO #1585 we have to map the id of the importedMessage to the alias - change when import mesage provides importedMessage.alias
|
|
271
|
+
if (experimentalAliases) {
|
|
272
|
+
loadedMessageClone.alias["default"] = loadedMessageClone.id;
|
|
273
|
+
let currentOffset = 0;
|
|
274
|
+
let messsageId;
|
|
275
|
+
do {
|
|
276
|
+
messsageId = humanIdHash(loadedMessageClone.id, currentOffset);
|
|
277
|
+
if (messages.get(messsageId)) {
|
|
278
|
+
currentOffset += 1;
|
|
279
|
+
messsageId = undefined;
|
|
280
|
+
}
|
|
281
|
+
} while (messsageId === undefined);
|
|
282
|
+
// create a humanId based on a hash of the alias
|
|
283
|
+
loadedMessageClone.id = messsageId;
|
|
284
|
+
}
|
|
285
|
+
const importedEnecoded = stringifyMessage(loadedMessageClone);
|
|
286
|
+
// we don't have to check - done before hand if (messages.has(loadedMessageClone.id)) return false
|
|
287
|
+
messages.set(loadedMessageClone.id, loadedMessageClone);
|
|
288
|
+
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded;
|
|
289
|
+
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone, [
|
|
290
|
+
...messages.values(),
|
|
291
|
+
]);
|
|
259
292
|
}
|
|
260
|
-
// This logic is preventing cycles - could also be handled if update api had a parameter for who triggered update
|
|
261
|
-
// e.g. when FS was updated, we don't need to write back to FS
|
|
262
|
-
// update is synchronous, so update effect will be triggered immediately
|
|
263
|
-
// NOTE: this might trigger a save before we have the chance to delete - but since save is async and waits for the lock acquired by this method - its save to set the flags afterwards
|
|
264
|
-
messages.set(loadedMessageClone.id, loadedMessageClone);
|
|
265
|
-
// NOTE could use hash instead of the whole object JSON to save memory...
|
|
266
|
-
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded;
|
|
267
|
-
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone, [...messages.values()]);
|
|
268
|
-
loadedMessageCount++;
|
|
269
293
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
// TODO #1585 we have to map the id of the importedMessage to the alias - change when import mesage provides importedMessage.alias
|
|
274
|
-
if (experimentalAliases) {
|
|
275
|
-
loadedMessageClone.alias["default"] = loadedMessageClone.id;
|
|
276
|
-
let currentOffset = 0;
|
|
277
|
-
let messsageId;
|
|
278
|
-
do {
|
|
279
|
-
messsageId = humanIdHash(loadedMessageClone.id, currentOffset);
|
|
280
|
-
if (messages.get(messsageId)) {
|
|
281
|
-
currentOffset += 1;
|
|
282
|
-
messsageId = undefined;
|
|
283
|
-
}
|
|
284
|
-
} while (messsageId === undefined);
|
|
285
|
-
// create a humanId based on a hash of the alias
|
|
286
|
-
loadedMessageClone.id = messsageId;
|
|
287
|
-
}
|
|
288
|
-
const importedEnecoded = stringifyMessage(loadedMessageClone);
|
|
289
|
-
// we don't have to check - done before hand if (messages.has(loadedMessageClone.id)) return false
|
|
290
|
-
messages.set(loadedMessageClone.id, loadedMessageClone);
|
|
291
|
-
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded;
|
|
292
|
-
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone, [...messages.values()]);
|
|
293
|
-
loadedMessageCount++;
|
|
294
|
+
for (const deletedMessageId of deletedMessages) {
|
|
295
|
+
messages.delete(deletedMessageId);
|
|
296
|
+
delegate?.onMessageDelete(deletedMessageId, [...messages.values()]);
|
|
294
297
|
}
|
|
295
|
-
|
|
296
|
-
// move loading of the next messages to the next ticks to allow solid to cleanup resources
|
|
297
|
-
// solid needs some time to settle and clean up
|
|
298
|
-
// https://github.com/solidjs-community/solid-primitives/blob/9ca76a47ffa2172770e075a90695cf933da0ff48/packages/trigger/src/index.ts#L64
|
|
299
|
-
await sleep(0);
|
|
300
|
-
loadedMessageCount = 0;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
loadedMessageCount = 0;
|
|
304
|
-
for (const deletedMessageId of deletedMessages) {
|
|
305
|
-
messages.delete(deletedMessageId);
|
|
306
|
-
delegate?.onMessageDelete(deletedMessageId, [...messages.values()]);
|
|
307
|
-
loadedMessageCount++;
|
|
308
|
-
if (loadedMessageCount > maxMessagesPerTick) {
|
|
309
|
-
await sleep(0);
|
|
310
|
-
loadedMessageCount = 0;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
298
|
+
});
|
|
313
299
|
await releaseLock(fs, lockDirPath, "loadMessage", lockTime);
|
|
314
300
|
lockTime = undefined;
|
|
315
301
|
debug("loadMessagesViaPlugin: " + loadedMessages.length + " Messages processed ");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inlang/sdk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.35.
|
|
4
|
+
"version": "0.35.5",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -34,15 +34,15 @@
|
|
|
34
34
|
"solid-js": "1.6.12",
|
|
35
35
|
"throttle-debounce": "^5.0.0",
|
|
36
36
|
"@inlang/json-types": "1.1.0",
|
|
37
|
-
"@inlang/language-tag": "1.5.1",
|
|
38
37
|
"@inlang/message": "2.1.0",
|
|
38
|
+
"@inlang/language-tag": "1.5.1",
|
|
39
39
|
"@inlang/message-lint-rule": "1.4.7",
|
|
40
40
|
"@inlang/module": "1.2.13",
|
|
41
|
-
"@inlang/project-settings": "2.4.2",
|
|
42
41
|
"@inlang/plugin": "2.4.13",
|
|
43
|
-
"@inlang/
|
|
42
|
+
"@inlang/project-settings": "2.4.2",
|
|
44
43
|
"@inlang/translatable": "1.3.1",
|
|
45
|
-
"@
|
|
44
|
+
"@inlang/result": "1.1.0",
|
|
45
|
+
"@lix-js/client": "2.2.0",
|
|
46
46
|
"@lix-js/fs": "2.1.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
@@ -222,7 +222,7 @@ describe("messages", () => {
|
|
|
222
222
|
// TODO: how can we await `setConfig` correctly
|
|
223
223
|
await new Promise((resolve) => setTimeout(resolve, 510))
|
|
224
224
|
|
|
225
|
-
expect(effectOnMessagesCounter).toBe(
|
|
225
|
+
expect(effectOnMessagesCounter).toBe(2) // 2 = setSetting (clearing the message index), subsequencial loadMessage call
|
|
226
226
|
expect(Object.values(project.query.messages.getAll()).length).toBe(2)
|
|
227
227
|
})
|
|
228
228
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Message } from "@inlang/message"
|
|
2
2
|
import { ReactiveMap } from "./reactivity/map.js"
|
|
3
|
-
import { createEffect, onCleanup } from "./reactivity/solid.js"
|
|
3
|
+
import { createEffect, onCleanup, batch } from "./reactivity/solid.js"
|
|
4
4
|
import { createSubscribable } from "./loadProject.js"
|
|
5
5
|
import type { InlangProject, MessageQueryApi, MessageQueryDelegate } from "./api.js"
|
|
6
6
|
import type { ResolvedPluginApi } from "./resolve-modules/plugins/types.js"
|
|
@@ -16,10 +16,6 @@ import { PluginLoadMessagesError, PluginSaveMessagesError } from "./errors.js"
|
|
|
16
16
|
import { humanIdHash } from "./storage/human-id/human-readable-id.js"
|
|
17
17
|
const debug = _debug("sdk:messages")
|
|
18
18
|
|
|
19
|
-
function sleep(ms: number) {
|
|
20
|
-
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
21
|
-
}
|
|
22
|
-
|
|
23
19
|
type MessageState = {
|
|
24
20
|
messageDirtyFlags: {
|
|
25
21
|
[messageId: string]: boolean
|
|
@@ -278,8 +274,6 @@ export function createMessagesQuery({
|
|
|
278
274
|
// - saving a message in two different languages would lead to a write in de.json first
|
|
279
275
|
// - This will leads to a load of the messages and since en.json has not been saved yet the english variant in the message would get overritten with the old state again
|
|
280
276
|
|
|
281
|
-
const maxMessagesPerTick = 500
|
|
282
|
-
|
|
283
277
|
/**
|
|
284
278
|
* Messsage that loads messages from a plugin - this method synchronizes with the saveMessage funciton.
|
|
285
279
|
* If a save is in progress loading will wait until saving is done. If another load kicks in during this load it will queue the
|
|
@@ -326,104 +320,91 @@ async function loadMessagesViaPlugin(
|
|
|
326
320
|
})
|
|
327
321
|
)
|
|
328
322
|
|
|
329
|
-
let loadedMessageCount = 0
|
|
330
|
-
|
|
331
323
|
const deletedMessages = new Set(messages.keys())
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length has checked beforhand
|
|
349
|
-
deletedMessages.delete(currentMessages[0]!.id)
|
|
350
|
-
// update message in place - leave message id and alias untouched
|
|
351
|
-
loadedMessageClone.alias = {} as any
|
|
352
|
-
|
|
353
|
-
// TODO #1585 we have to map the id of the importedMessage to the alias and fill the id property with the id of the existing message - change when import mesage provides importedMessage.alias
|
|
354
|
-
if (experimentalAliases) {
|
|
355
|
-
loadedMessageClone.alias["default"] = loadedMessageClone.id
|
|
324
|
+
batch(() => {
|
|
325
|
+
for (const loadedMessage of loadedMessages) {
|
|
326
|
+
const loadedMessageClone = structuredClone(loadedMessage)
|
|
327
|
+
|
|
328
|
+
const currentMessages = [...messages.values()]
|
|
329
|
+
// TODO #1585 here we match using the id to support legacy load message plugins - after we introduced import / export methods we will use importedMessage.alias
|
|
330
|
+
.filter(
|
|
331
|
+
(message: any) =>
|
|
332
|
+
(experimentalAliases ? message.alias["default"] : message.id) === loadedMessage.id
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
if (currentMessages.length > 1) {
|
|
336
|
+
// NOTE: if we happen to find two messages witht the sam alias we throw for now
|
|
337
|
+
// - this could be the case if one edits the aliase manualy
|
|
338
|
+
throw new Error("more than one message with the same id or alias found ")
|
|
339
|
+
} else if (currentMessages.length === 1) {
|
|
356
340
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length has checked beforhand
|
|
357
|
-
|
|
341
|
+
deletedMessages.delete(currentMessages[0]!.id)
|
|
342
|
+
// update message in place - leave message id and alias untouched
|
|
343
|
+
loadedMessageClone.alias = {} as any
|
|
344
|
+
|
|
345
|
+
// TODO #1585 we have to map the id of the importedMessage to the alias and fill the id property with the id of the existing message - change when import mesage provides importedMessage.alias
|
|
346
|
+
if (experimentalAliases) {
|
|
347
|
+
loadedMessageClone.alias["default"] = loadedMessageClone.id
|
|
348
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length has checked beforhand
|
|
349
|
+
loadedMessageClone.id = currentMessages[0]!.id
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// NOTE stringifyMessage encodes messages independent from key order!
|
|
353
|
+
const importedEnecoded = stringifyMessage(loadedMessageClone)
|
|
354
|
+
|
|
355
|
+
// NOTE could use hash instead of the whole object JSON to save memory...
|
|
356
|
+
if (messageState.messageLoadHash[loadedMessageClone.id] === importedEnecoded) {
|
|
357
|
+
// debug("skipping upsert!")
|
|
358
|
+
continue
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// This logic is preventing cycles - could also be handled if update api had a parameter for who triggered update
|
|
362
|
+
// e.g. when FS was updated, we don't need to write back to FS
|
|
363
|
+
// update is synchronous, so update effect will be triggered immediately
|
|
364
|
+
// NOTE: this might trigger a save before we have the chance to delete - but since save is async and waits for the lock acquired by this method - its save to set the flags afterwards
|
|
365
|
+
messages.set(loadedMessageClone.id, loadedMessageClone)
|
|
366
|
+
// NOTE could use hash instead of the whole object JSON to save memory...
|
|
367
|
+
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded
|
|
368
|
+
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone, [
|
|
369
|
+
...messages.values(),
|
|
370
|
+
])
|
|
371
|
+
} else {
|
|
372
|
+
// message with the given alias does not exist so far
|
|
373
|
+
loadedMessageClone.alias = {} as any
|
|
374
|
+
// TODO #1585 we have to map the id of the importedMessage to the alias - change when import mesage provides importedMessage.alias
|
|
375
|
+
if (experimentalAliases) {
|
|
376
|
+
loadedMessageClone.alias["default"] = loadedMessageClone.id
|
|
377
|
+
|
|
378
|
+
let currentOffset = 0
|
|
379
|
+
let messsageId: string | undefined
|
|
380
|
+
do {
|
|
381
|
+
messsageId = humanIdHash(loadedMessageClone.id, currentOffset)
|
|
382
|
+
if (messages.get(messsageId)) {
|
|
383
|
+
currentOffset += 1
|
|
384
|
+
messsageId = undefined
|
|
385
|
+
}
|
|
386
|
+
} while (messsageId === undefined)
|
|
387
|
+
|
|
388
|
+
// create a humanId based on a hash of the alias
|
|
389
|
+
loadedMessageClone.id = messsageId
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const importedEnecoded = stringifyMessage(loadedMessageClone)
|
|
393
|
+
|
|
394
|
+
// we don't have to check - done before hand if (messages.has(loadedMessageClone.id)) return false
|
|
395
|
+
messages.set(loadedMessageClone.id, loadedMessageClone)
|
|
396
|
+
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded
|
|
397
|
+
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone, [
|
|
398
|
+
...messages.values(),
|
|
399
|
+
])
|
|
358
400
|
}
|
|
359
|
-
|
|
360
|
-
// NOTE stringifyMessage encodes messages independent from key order!
|
|
361
|
-
const importedEnecoded = stringifyMessage(loadedMessageClone)
|
|
362
|
-
|
|
363
|
-
// NOTE could use hash instead of the whole object JSON to save memory...
|
|
364
|
-
if (messageState.messageLoadHash[loadedMessageClone.id] === importedEnecoded) {
|
|
365
|
-
// debug("skipping upsert!")
|
|
366
|
-
continue
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// This logic is preventing cycles - could also be handled if update api had a parameter for who triggered update
|
|
370
|
-
// e.g. when FS was updated, we don't need to write back to FS
|
|
371
|
-
// update is synchronous, so update effect will be triggered immediately
|
|
372
|
-
// NOTE: this might trigger a save before we have the chance to delete - but since save is async and waits for the lock acquired by this method - its save to set the flags afterwards
|
|
373
|
-
messages.set(loadedMessageClone.id, loadedMessageClone)
|
|
374
|
-
// NOTE could use hash instead of the whole object JSON to save memory...
|
|
375
|
-
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded
|
|
376
|
-
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone, [...messages.values()])
|
|
377
|
-
loadedMessageCount++
|
|
378
|
-
} else {
|
|
379
|
-
// message with the given alias does not exist so far
|
|
380
|
-
loadedMessageClone.alias = {} as any
|
|
381
|
-
// TODO #1585 we have to map the id of the importedMessage to the alias - change when import mesage provides importedMessage.alias
|
|
382
|
-
if (experimentalAliases) {
|
|
383
|
-
loadedMessageClone.alias["default"] = loadedMessageClone.id
|
|
384
|
-
|
|
385
|
-
let currentOffset = 0
|
|
386
|
-
let messsageId: string | undefined
|
|
387
|
-
do {
|
|
388
|
-
messsageId = humanIdHash(loadedMessageClone.id, currentOffset)
|
|
389
|
-
if (messages.get(messsageId)) {
|
|
390
|
-
currentOffset += 1
|
|
391
|
-
messsageId = undefined
|
|
392
|
-
}
|
|
393
|
-
} while (messsageId === undefined)
|
|
394
|
-
|
|
395
|
-
// create a humanId based on a hash of the alias
|
|
396
|
-
loadedMessageClone.id = messsageId
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
const importedEnecoded = stringifyMessage(loadedMessageClone)
|
|
400
|
-
|
|
401
|
-
// we don't have to check - done before hand if (messages.has(loadedMessageClone.id)) return false
|
|
402
|
-
messages.set(loadedMessageClone.id, loadedMessageClone)
|
|
403
|
-
messageState.messageLoadHash[loadedMessageClone.id] = importedEnecoded
|
|
404
|
-
delegate?.onMessageUpdate(loadedMessageClone.id, loadedMessageClone, [...messages.values()])
|
|
405
|
-
loadedMessageCount++
|
|
406
401
|
}
|
|
407
|
-
if (loadedMessageCount > maxMessagesPerTick) {
|
|
408
|
-
// move loading of the next messages to the next ticks to allow solid to cleanup resources
|
|
409
|
-
// solid needs some time to settle and clean up
|
|
410
|
-
// https://github.com/solidjs-community/solid-primitives/blob/9ca76a47ffa2172770e075a90695cf933da0ff48/packages/trigger/src/index.ts#L64
|
|
411
|
-
await sleep(0)
|
|
412
|
-
loadedMessageCount = 0
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
402
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
delegate?.onMessageDelete(deletedMessageId, [...messages.values()])
|
|
420
|
-
loadedMessageCount++
|
|
421
|
-
if (loadedMessageCount > maxMessagesPerTick) {
|
|
422
|
-
await sleep(0)
|
|
423
|
-
loadedMessageCount = 0
|
|
403
|
+
for (const deletedMessageId of deletedMessages) {
|
|
404
|
+
messages.delete(deletedMessageId)
|
|
405
|
+
delegate?.onMessageDelete(deletedMessageId, [...messages.values()])
|
|
424
406
|
}
|
|
425
|
-
}
|
|
426
|
-
|
|
407
|
+
})
|
|
427
408
|
await releaseLock(fs as NodeishFilesystem, lockDirPath, "loadMessage", lockTime)
|
|
428
409
|
lockTime = undefined
|
|
429
410
|
|