simplex-chat 7.0.2 → 7.1.0-beta.4

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.
Files changed (56) hide show
  1. package/binding.gyp +2 -0
  2. package/cpp/simplex.cc +265 -29
  3. package/cpp/simplex.h +2 -0
  4. package/dist/api.d.ts +3 -64
  5. package/dist/api.js +8 -106
  6. package/dist/api.js.map +1 -1
  7. package/dist/bot.d.ts +4 -2
  8. package/dist/bot.js +1 -1
  9. package/dist/bot.js.map +1 -1
  10. package/dist/util.js +1 -1
  11. package/dist/util.js.map +1 -1
  12. package/docs/Namespace.bot.md +1 -0
  13. package/docs/api.Class.ChatApi.md +122 -78
  14. package/docs/bot.Function.run.md +1 -1
  15. package/docs/bot.Function.subscribeChatItems.md +27 -0
  16. package/docs/bot.Interface.BotConfig.md +7 -7
  17. package/docs/bot.Interface.BotOptions.md +10 -10
  18. package/docs/bot.TypeAlias.BotDbOpts.md +4 -0
  19. package/docs/core.Class.ChatAPIError.md +4 -4
  20. package/docs/core.Class.ChatInitError.md +4 -4
  21. package/docs/core.DBMigrationError.Interface.ErrorMigration.md +4 -4
  22. package/docs/core.DBMigrationError.Interface.ErrorNotADatabase.md +3 -3
  23. package/docs/core.DBMigrationError.Interface.ErrorSQL.md +4 -4
  24. package/docs/core.DBMigrationError.Interface.InvalidConfirmation.md +2 -2
  25. package/docs/core.DBMigrationError.Interface.InvalidQueueSize.md +25 -0
  26. package/docs/core.DBMigrationError.TypeAlias.Tag.md +2 -2
  27. package/docs/core.Enumeration.MigrationConfirmation.md +5 -5
  28. package/docs/core.Function.chatCloseStore.md +1 -1
  29. package/docs/core.Function.chatDecryptFile.md +1 -1
  30. package/docs/core.Function.chatEncryptFile.md +1 -1
  31. package/docs/core.Function.chatMigrateInit.md +8 -2
  32. package/docs/core.Function.chatReadFile.md +3 -3
  33. package/docs/core.Function.chatRecvMsgWait.md +1 -1
  34. package/docs/core.Function.chatSendCmd.md +1 -1
  35. package/docs/core.Function.chatWriteFile.md +2 -2
  36. package/docs/core.Interface.APIResult.md +3 -3
  37. package/docs/core.Interface.CryptoArgs.md +3 -3
  38. package/docs/core.Interface.UpMigration.md +3 -3
  39. package/docs/core.MTRError.Interface.MTREDifferent.md +3 -3
  40. package/docs/core.MTRError.Interface.MTRENoDown.md +10 -10
  41. package/docs/core.MTRError.TypeAlias.Tag.md +1 -1
  42. package/docs/core.MigrationError.Interface.MEDowngrade.md +3 -3
  43. package/docs/core.MigrationError.Interface.MEUpgrade.md +4 -4
  44. package/docs/core.MigrationError.Interface.MigrationError.md +3 -3
  45. package/docs/core.MigrationError.TypeAlias.Tag.md +1 -1
  46. package/docs/core.Namespace.DBMigrationError.md +1 -0
  47. package/docs/core.TypeAlias.DBMigrationError.md +2 -2
  48. package/docs/core.TypeAlias.MTRError.md +1 -1
  49. package/docs/core.TypeAlias.MigrationError.md +1 -1
  50. package/package.json +2 -2
  51. package/src/api.ts +40 -22
  52. package/src/bot.ts +17 -30
  53. package/src/core.ts +15 -7
  54. package/src/download-libs.js +28 -1
  55. package/src/simplex.d.ts +3 -2
  56. package/src/util.ts +1 -1
@@ -6,7 +6,7 @@
6
6
 
7
7
  # Interface: MTRENoDown
8
8
 
9
- Defined in: [src/core.ts:201](../src/core.ts#L201)
9
+ Defined in: [src/core.ts:209](../src/core.ts#L209)
10
10
 
11
11
  ## Extends
12
12
 
@@ -14,20 +14,20 @@ Defined in: [src/core.ts:201](../src/core.ts#L201)
14
14
 
15
15
  ## Properties
16
16
 
17
- ### type
17
+ ### dbMigrations
18
18
 
19
- > **type**: `"noDown"`
19
+ > **dbMigrations**: `string`[]
20
20
 
21
- Defined in: [src/core.ts:202](../src/core.ts#L202)
21
+ Defined in: [src/core.ts:211](../src/core.ts#L211)
22
22
 
23
- #### Overrides
23
+ ***
24
24
 
25
- `Interface.type`
25
+ ### type
26
26
 
27
- ***
27
+ > **type**: `"noDown"`
28
28
 
29
- ### upMigrations
29
+ Defined in: [src/core.ts:210](../src/core.ts#L210)
30
30
 
31
- > **upMigrations**: [`UpMigration`](core.Interface.UpMigration.md)
31
+ #### Overrides
32
32
 
33
- Defined in: [src/core.ts:203](../src/core.ts#L203)
33
+ `Interface.type`
@@ -8,4 +8,4 @@
8
8
 
9
9
  > **Tag** = `"noDown"` \| `"different"`
10
10
 
11
- Defined in: [src/core.ts:195](../src/core.ts#L195)
11
+ Defined in: [src/core.ts:203](../src/core.ts#L203)
@@ -6,7 +6,7 @@
6
6
 
7
7
  # Interface: MEDowngrade
8
8
 
9
- Defined in: [src/core.ts:174](../src/core.ts#L174)
9
+ Defined in: [src/core.ts:182](../src/core.ts#L182)
10
10
 
11
11
  ## Extends
12
12
 
@@ -18,7 +18,7 @@ Defined in: [src/core.ts:174](../src/core.ts#L174)
18
18
 
19
19
  > **downMigrations**: `string`[]
20
20
 
21
- Defined in: [src/core.ts:176](../src/core.ts#L176)
21
+ Defined in: [src/core.ts:184](../src/core.ts#L184)
22
22
 
23
23
  ***
24
24
 
@@ -26,7 +26,7 @@ Defined in: [src/core.ts:176](../src/core.ts#L176)
26
26
 
27
27
  > **type**: `"downgrade"`
28
28
 
29
- Defined in: [src/core.ts:175](../src/core.ts#L175)
29
+ Defined in: [src/core.ts:183](../src/core.ts#L183)
30
30
 
31
31
  #### Overrides
32
32
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  # Interface: MEUpgrade
8
8
 
9
- Defined in: [src/core.ts:169](../src/core.ts#L169)
9
+ Defined in: [src/core.ts:177](../src/core.ts#L177)
10
10
 
11
11
  ## Extends
12
12
 
@@ -18,7 +18,7 @@ Defined in: [src/core.ts:169](../src/core.ts#L169)
18
18
 
19
19
  > **type**: `"upgrade"`
20
20
 
21
- Defined in: [src/core.ts:170](../src/core.ts#L170)
21
+ Defined in: [src/core.ts:178](../src/core.ts#L178)
22
22
 
23
23
  #### Overrides
24
24
 
@@ -28,6 +28,6 @@ Defined in: [src/core.ts:170](../src/core.ts#L170)
28
28
 
29
29
  ### upMigrations
30
30
 
31
- > **upMigrations**: [`UpMigration`](core.Interface.UpMigration.md)
31
+ > **upMigrations**: [`UpMigration`](core.Interface.UpMigration.md)[]
32
32
 
33
- Defined in: [src/core.ts:171](../src/core.ts#L171)
33
+ Defined in: [src/core.ts:179](../src/core.ts#L179)
@@ -6,7 +6,7 @@
6
6
 
7
7
  # Interface: MigrationError
8
8
 
9
- Defined in: [src/core.ts:179](../src/core.ts#L179)
9
+ Defined in: [src/core.ts:187](../src/core.ts#L187)
10
10
 
11
11
  ## Extends
12
12
 
@@ -18,7 +18,7 @@ Defined in: [src/core.ts:179](../src/core.ts#L179)
18
18
 
19
19
  > **mtrError**: [`MTRError`](core.TypeAlias.MTRError.md)
20
20
 
21
- Defined in: [src/core.ts:181](../src/core.ts#L181)
21
+ Defined in: [src/core.ts:189](../src/core.ts#L189)
22
22
 
23
23
  ***
24
24
 
@@ -26,7 +26,7 @@ Defined in: [src/core.ts:181](../src/core.ts#L181)
26
26
 
27
27
  > **type**: `"migrationError"`
28
28
 
29
- Defined in: [src/core.ts:180](../src/core.ts#L180)
29
+ Defined in: [src/core.ts:188](../src/core.ts#L188)
30
30
 
31
31
  #### Overrides
32
32
 
@@ -8,4 +8,4 @@
8
8
 
9
9
  > **Tag** = `"upgrade"` \| `"downgrade"` \| `"migrationError"`
10
10
 
11
- Defined in: [src/core.ts:163](../src/core.ts#L163)
11
+ Defined in: [src/core.ts:171](../src/core.ts#L171)
@@ -12,6 +12,7 @@
12
12
  - [ErrorNotADatabase](core.DBMigrationError.Interface.ErrorNotADatabase.md)
13
13
  - [ErrorSQL](core.DBMigrationError.Interface.ErrorSQL.md)
14
14
  - [InvalidConfirmation](core.DBMigrationError.Interface.InvalidConfirmation.md)
15
+ - [InvalidQueueSize](core.DBMigrationError.Interface.InvalidQueueSize.md)
15
16
 
16
17
  ## Type Aliases
17
18
 
@@ -6,6 +6,6 @@
6
6
 
7
7
  # Type Alias: DBMigrationError
8
8
 
9
- > **DBMigrationError** = [`InvalidConfirmation`](core.DBMigrationError.Interface.InvalidConfirmation.md) \| [`ErrorNotADatabase`](core.DBMigrationError.Interface.ErrorNotADatabase.md) \| [`ErrorMigration`](core.DBMigrationError.Interface.ErrorMigration.md) \| [`ErrorSQL`](core.DBMigrationError.Interface.ErrorSQL.md)
9
+ > **DBMigrationError** = [`InvalidConfirmation`](core.DBMigrationError.Interface.InvalidConfirmation.md) \| [`InvalidQueueSize`](core.DBMigrationError.Interface.InvalidQueueSize.md) \| [`ErrorNotADatabase`](core.DBMigrationError.Interface.ErrorNotADatabase.md) \| [`ErrorMigration`](core.DBMigrationError.Interface.ErrorMigration.md) \| [`ErrorSQL`](core.DBMigrationError.Interface.ErrorSQL.md)
10
10
 
11
- Defined in: [src/core.ts:122](../src/core.ts#L122)
11
+ Defined in: [src/core.ts:125](../src/core.ts#L125)
@@ -8,4 +8,4 @@
8
8
 
9
9
  > **MTRError** = [`MTRENoDown`](core.MTRError.Interface.MTRENoDown.md) \| [`MTREDifferent`](core.MTRError.Interface.MTREDifferent.md)
10
10
 
11
- Defined in: [src/core.ts:190](../src/core.ts#L190)
11
+ Defined in: [src/core.ts:198](../src/core.ts#L198)
@@ -8,4 +8,4 @@
8
8
 
9
9
  > **MigrationError** = [`MEUpgrade`](core.MigrationError.Interface.MEUpgrade.md) \| [`MEDowngrade`](core.MigrationError.Interface.MEDowngrade.md) \| [`MigrationError`](core.MigrationError.Interface.MigrationError.md)
10
10
 
11
- Defined in: [src/core.ts:157](../src/core.ts#L157)
11
+ Defined in: [src/core.ts:165](../src/core.ts#L165)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simplex-chat",
3
- "version": "7.0.2",
3
+ "version": "7.1.0-beta.4",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -24,7 +24,7 @@
24
24
  "docs": "typedoc"
25
25
  },
26
26
  "dependencies": {
27
- "@simplex-chat/types": "^0.10.3",
27
+ "@simplex-chat/types": "^0.11.4",
28
28
  "extract-zip": "^2.0.1",
29
29
  "fast-deep-equal": "^3.1.3",
30
30
  "node-addon-api": "^8.5.0"
package/src/api.ts CHANGED
@@ -106,13 +106,15 @@ export class ChatApi {
106
106
  * Initializes the ChatApi.
107
107
  * @param {DbConfig} db - Database configuration (sqlite or postgres).
108
108
  * @param {core.MigrationConfirmation} [confirm=core.MigrationConfirmation.YesUp] - Migration confirmation mode.
109
+ * @param {number} [queueSize] - Size of internal queues, the core default is used when omitted.
109
110
  */
110
111
  static async init(
111
112
  db: DbConfig,
112
- confirm = core.MigrationConfirmation.YesUp
113
+ confirm = core.MigrationConfirmation.YesUp,
114
+ queueSize?: number
113
115
  ): Promise<ChatApi> {
114
116
  const [path, key] = dbConfigToMigrateArgs(db)
115
- const ctrl = await core.chatMigrateInit(path, key, confirm)
117
+ const ctrl = await core.chatMigrateInit(path, key, confirm, queueSize)
116
118
  return new ChatApi(ctrl)
117
119
  }
118
120
 
@@ -120,39 +122,52 @@ export class ChatApi {
120
122
  * Start chat controller. Must be called with the existing user profile.
121
123
  */
122
124
  async startChat(): Promise<void> {
125
+ if (this.eventsLoop) throw new Error("chat already started")
126
+ const ctrl = this.ctrl
123
127
  this.receiveEvents = true
124
128
  this.eventsLoop = this.runEventsLoop()
125
- const r = await this.sendChatCmd(CC.StartChat.cmdString({mainApp: true, enableSndFiles: true}))
129
+ let r: ChatResponse
130
+ try {
131
+ r = await core.chatSendCmd(ctrl, CC.StartChat.cmdString({mainApp: true, enableSndFiles: true, serviceRequests: false}))
132
+ } catch (e) {
133
+ await this.stopEventsLoop()
134
+ throw e
135
+ }
126
136
  if (r.type !== "chatStarted" && r.type !== "chatRunning") {
137
+ await this.stopEventsLoop()
127
138
  throw new ChatCommandError("error starting chat", r)
128
139
  }
129
140
  }
130
-
141
+
131
142
  /**
132
143
  * Stop chat controller.
133
- * Must be called before closing the database.
144
+ * `close` calls it before closing the database.
134
145
  * Usually doesn't need to be called in chat bots.
135
146
  */
136
147
  async stopChat(): Promise<void> {
137
148
  const r = await this.sendChatCmd("/_stop")
138
- if (r.type !== "chatStopped") throw new ChatCommandError("error starting chat", r)
139
- this.receiveEvents = false
140
- if (this.eventsLoop) await this.eventsLoop
141
- this.eventsLoop = undefined
149
+ if (r.type !== "chatStopped") throw new ChatCommandError("error stopping chat", r)
150
+ await this.stopEventsLoop()
142
151
  }
143
152
 
144
153
  /**
145
- * Close chat database.
154
+ * Stop chat controller and close chat database.
155
+ * The database is not closed if stopping fails.
146
156
  * Usually doesn't need to be called in chat bots.
147
157
  */
148
158
  async close(): Promise<void> {
149
- this.receiveEvents = false
150
- if (this.eventsLoop) await this.eventsLoop
151
- this.eventsLoop = undefined
159
+ // a running controller keeps using the database connections that closing frees
160
+ await this.stopChat()
152
161
  await core.chatCloseStore(this.ctrl)
153
162
  this.ctrl_ = undefined
154
163
  }
155
-
164
+
165
+ private async stopEventsLoop(): Promise<void> {
166
+ this.receiveEvents = false
167
+ if (this.eventsLoop) await this.eventsLoop
168
+ this.eventsLoop = undefined
169
+ }
170
+
156
171
  private async runEventsLoop(): Promise<void> {
157
172
  while (this.receiveEvents) {
158
173
  try {
@@ -335,7 +350,7 @@ export class ChatApi {
335
350
  return await core.chatSendCmd(this.ctrl, cmd)
336
351
  }
337
352
 
338
- async recvChatEvent(wait: number = 5_000_000): Promise<ChatEvent | undefined> {
353
+ async recvChatEvent(wait: number = 500_000): Promise<ChatEvent | undefined> {
339
354
  return await core.chatRecvMsgWait(this.ctrl, wait)
340
355
  }
341
356
 
@@ -386,8 +401,10 @@ export class ChatApi {
386
401
  switch (r.type) {
387
402
  case "userProfileUpdated":
388
403
  return r.updateSummary
404
+ case "userProfileNoChange":
405
+ return {updateSuccesses: 0, updateFailures: 0, changedContacts: []}
389
406
  default:
390
- throw new ChatCommandError("error loading user address", r)
407
+ throw new ChatCommandError("error setting profile address", r)
391
408
  }
392
409
  }
393
410
 
@@ -460,7 +477,7 @@ export class ChatApi {
460
477
  updatedMessage: {msgContent, mentions: {}},
461
478
  })
462
479
  )
463
- if (r.type === "chatItemUpdated") return r.chatItem.chatItem
480
+ if (r.type === "chatItemUpdated" || r.type === "chatItemNotChanged") return r.chatItem.chatItem
464
481
  throw new ChatCommandError("error updating chat item", r)
465
482
  }
466
483
 
@@ -499,10 +516,10 @@ export class ChatApi {
499
516
  chatItemId: number,
500
517
  add: boolean,
501
518
  reaction: T.MsgReaction
502
- ) {
519
+ ): Promise<T.ACIReaction> {
503
520
  const r = await this.sendChatCmd(CC.APIChatItemReaction.cmdString({chatRef: {chatType, chatId}, chatItemId, add, reaction}))
504
- if (r.type === "chatItemsDeleted") return r.chatItemDeletions
505
- throw new ChatCommandError("error setting item reaction", r)
521
+ if (r.type === "chatItemReaction") return r.reaction
522
+ throw new ChatCommandError("error setting item reaction", r)
506
523
  }
507
524
 
508
525
  /**
@@ -512,6 +529,7 @@ export class ChatApi {
512
529
  async apiReceiveFile(fileId: number): Promise<T.AChatItem> {
513
530
  const r = await this.sendChatCmd(CC.ReceiveFile.cmdString({fileId, userApprovedRelays: true}))
514
531
  if (r.type === "rcvFileAccepted") return r.chatItem
532
+ if (r.type === "rcvFileAcceptedSndCancelled") throw new ChatCommandError("file cancelled by sender", r)
515
533
  throw new ChatCommandError("error receiving file", r)
516
534
  }
517
535
 
@@ -698,7 +716,7 @@ export class ChatApi {
698
716
  * Connect via prepared SimpleX link. The link can be 1-time invitation link, contact address or group link
699
717
  * Network usage: interactive.
700
718
  */
701
- async apiConnect(userId: number, incognito: boolean, preparedLink?: T.CreatedConnLink): Promise<ConnReqType> {
719
+ async apiConnect(userId: number, incognito: boolean, preparedLink: T.CreatedConnLink): Promise<ConnReqType> {
702
720
  const r = await this.sendChatCmd(CC.APIConnect.cmdString({userId, incognito, preparedLink_: preparedLink}))
703
721
  return this.handleConnectResult(r)
704
722
  }
@@ -740,7 +758,7 @@ export class ChatApi {
740
758
  * Network usage: no.
741
759
  */
742
760
  async apiRejectContactRequest(contactReqId: number): Promise<void> {
743
- const r = await this.sendChatCmd(CC.APIRejectContact.cmdString({contactReqId}))
761
+ const r = await this.sendChatCmd(CC.APIRejectContact.cmdString({contactReqId, notify: false}))
744
762
  if (r.type === "contactRequestRejected") return
745
763
  throw new ChatCommandError("error rejecting contact request", r)
746
764
  }
package/src/bot.ts CHANGED
@@ -6,6 +6,7 @@ import equal = require("fast-deep-equal")
6
6
 
7
7
  export type BotDbOpts = api.DbConfig & {
8
8
  confirmMigrations?: core.MigrationConfirmation
9
+ queueSize?: number
9
10
  }
10
11
 
11
12
  export interface BotOptions {
@@ -45,10 +46,9 @@ export interface BotConfig {
45
46
  }
46
47
 
47
48
  export async function run({profile, dbOpts, options = defaultOpts, onMessage, onCommands = {}, events = {}}: BotConfig): Promise<[api.ChatApi, T.User, T.UserContactLink | undefined]> {
48
- const bot = await api.ChatApi.init(dbOpts, dbOpts.confirmMigrations || core.MigrationConfirmation.YesUp)
49
+ const bot = await api.ChatApi.init(dbOpts, dbOpts.confirmMigrations || core.MigrationConfirmation.YesUp, dbOpts.queueSize)
49
50
  const opts = fullOptions(options)
50
- if (onMessage) subscribeMessages(bot, onMessage)
51
- if (Object.keys(onCommands).length > 0) subscribeCommands(bot, onCommands)
51
+ if (onMessage || Object.keys(onCommands).length > 0) subscribeChatItems(bot, onMessage, onCommands)
52
52
  if (Object.keys(events).length > 0) bot.on(events)
53
53
  subscribeLogEvents(bot, opts)
54
54
  const botProfile = mkBotProfile(profile, opts)
@@ -105,38 +105,25 @@ function mkBotProfile(profile: T.Profile, opts: Required<BotOptions>): T.Profile
105
105
  return profile
106
106
  }
107
107
 
108
- function subscribeMessages(bot: api.ChatApi, onMessage: (chatItem: T.AChatItem, content: T.MsgContent) => void | Promise<void>) {
108
+ export function subscribeChatItems(
109
+ bot: api.ChatApi,
110
+ onMessage: ((chatItem: T.AChatItem, content: T.MsgContent) => void | Promise<void>) | undefined,
111
+ commands: {[K in string]?: ((chatItem: T.AChatItem, command: util.BotCommand) => void | Promise<void>)}
112
+ ) {
109
113
  bot.on("newChatItems", async ({chatItems}) => {
110
114
  for (const ci of chatItems) {
111
- if (ci.chatItem.content.type === "rcvMsgContent") {
112
- try {
113
- const p = onMessage(ci, ci.chatItem.content.msgContent)
114
- if (p instanceof Promise) await p
115
- } catch (e) {
116
- console.log("message processing error", e)
117
- }
118
- }
119
- }
120
- })
121
- }
122
-
123
- function subscribeCommands(bot: api.ChatApi, commands: {[K in string]?: ((chatItem: T.AChatItem, command: util.BotCommand) => void | Promise<void>)}) {
124
- bot.on("newChatItems", async (evt) => {
125
- for (const ci of evt.chatItems) {
115
+ const content = ci.chatItem.content
116
+ if (content.type !== "rcvMsgContent") continue
126
117
  const cmd = util.ciBotCommand(ci.chatItem)
127
- if (cmd) {
128
- const cmdFunc = commands[cmd.keyword] || commands[""]
129
- if (cmdFunc) {
130
- try {
131
- const p = cmdFunc(ci, cmd)
132
- if (p instanceof Promise) await p
133
- } catch(e) {
134
- console.log(`${cmd} command processing error`, e)
135
- }
136
- }
118
+ const cmdFunc = cmd && (commands[cmd.keyword] || commands[""])
119
+ try {
120
+ if (cmd && cmdFunc) await cmdFunc(ci, cmd)
121
+ else if (onMessage) await onMessage(ci, content.msgContent)
122
+ } catch (e) {
123
+ console.log(cmd && cmdFunc ? `${cmd.keyword} command processing error` : "message processing error", e)
137
124
  }
138
125
  }
139
- })
126
+ })
140
127
  }
141
128
 
142
129
  function subscribeLogEvents(bot: api.ChatApi, opts: Required<BotOptions>) {
package/src/core.ts CHANGED
@@ -3,9 +3,12 @@ import * as simplex from "./simplex"
3
3
 
4
4
  /**
5
5
  * Initialize chat controller
6
+ * @param {number} [queueSize] - Size of internal queues, the core default is used when omitted.
6
7
  */
7
- export async function chatMigrateInit(dbPath: string, dbKey: string, confirm: MigrationConfirmation): Promise<bigint> {
8
- const [ctrl, res] = await simplex.chat_migrate_init(dbPath, dbKey, confirm)
8
+ export async function chatMigrateInit(dbPath: string, dbKey: string, confirm: MigrationConfirmation, queueSize?: number): Promise<bigint> {
9
+ const [ctrl, res] = queueSize === undefined
10
+ ? await simplex.chat_migrate_init(dbPath, dbKey, confirm)
11
+ : await simplex.chat_migrate_init_queue(dbPath, dbKey, confirm, queueSize)
9
12
  const json = JSON.parse(res)
10
13
  if (json.type === 'ok') return ctrl
11
14
  throw new ChatInitError("Database or migration error (see dbMigrationError property)", json as DBMigrationError)
@@ -47,7 +50,7 @@ export async function chatRecvMsgWait(ctrl: bigint, wait: number): Promise<ChatE
47
50
  /**
48
51
  * Write buffer to encrypted file
49
52
  */
50
- export async function chatWriteFile(ctrl: bigint, path: string, buffer: ArrayBuffer): Promise<CryptoArgs> {
53
+ export async function chatWriteFile(ctrl: bigint, path: string, buffer: ArrayBuffer | Uint8Array): Promise<CryptoArgs> {
51
54
  const res = await simplex.chat_write_file(ctrl, path, buffer)
52
55
  return cryptoArgsResult(res)
53
56
  }
@@ -55,7 +58,7 @@ export async function chatWriteFile(ctrl: bigint, path: string, buffer: ArrayBuf
55
58
  /**
56
59
  * Read buffer from encrypted file
57
60
  */
58
- export async function chatReadFile(path: string, {fileKey, fileNonce}: CryptoArgs): Promise<ArrayBuffer> {
61
+ export async function chatReadFile(path: string, {fileKey, fileNonce}: CryptoArgs): Promise<Buffer> {
59
62
  return await simplex.chat_read_file(path, fileKey, fileNonce)
60
63
  }
61
64
 
@@ -121,12 +124,13 @@ export class ChatInitError extends Error {
121
124
 
122
125
  export type DBMigrationError =
123
126
  | DBMigrationError.InvalidConfirmation
127
+ | DBMigrationError.InvalidQueueSize
124
128
  | DBMigrationError.ErrorNotADatabase // invalid/corrupt database file or incorrect encryption key
125
129
  | DBMigrationError.ErrorMigration
126
130
  | DBMigrationError.ErrorSQL
127
131
 
128
132
  export namespace DBMigrationError {
129
- export type Tag = "invalidConfirmation" | "errorNotADatabase" | "errorMigration" | "errorSQL"
133
+ export type Tag = "invalidConfirmation" | "invalidQueueSize" | "errorNotADatabase" | "errorMigration" | "errorSQL"
130
134
 
131
135
  interface Interface {
132
136
  type: Tag
@@ -136,6 +140,10 @@ export namespace DBMigrationError {
136
140
  type: "invalidConfirmation"
137
141
  }
138
142
 
143
+ export interface InvalidQueueSize extends Interface {
144
+ type: "invalidQueueSize"
145
+ }
146
+
139
147
  export interface ErrorNotADatabase extends Interface {
140
148
  type: "errorNotADatabase"
141
149
  dbFile: string
@@ -168,7 +176,7 @@ export namespace MigrationError {
168
176
 
169
177
  export interface MEUpgrade extends Interface {
170
178
  type: "upgrade"
171
- upMigrations: UpMigration
179
+ upMigrations: UpMigration[]
172
180
  }
173
181
 
174
182
  export interface MEDowngrade extends Interface {
@@ -200,7 +208,7 @@ export namespace MTRError {
200
208
 
201
209
  export interface MTRENoDown extends Interface {
202
210
  type: "noDown"
203
- upMigrations: UpMigration
211
+ dbMigrations: string[]
204
212
  }
205
213
 
206
214
  export interface MTREDifferent extends Interface {
@@ -4,8 +4,12 @@ const path = require('path');
4
4
  const extract = require('extract-zip');
5
5
 
6
6
  const GITHUB_REPO = 'simplex-chat/simplex-chat-libs';
7
- const RELEASE_TAG = 'v7.0.2';
7
+ const RELEASE_TAG = 'v7.1.0-beta.4';
8
8
  const BACKEND = (process.env.SIMPLEX_BACKEND || process.env.npm_config_simplex_backend || 'sqlite').toLowerCase();
9
+ // A locally built libsimplex, copied into libs/ rather than loaded in place:
10
+ // the addon's RUNPATH is $ORIGIN/../../libs.
11
+ const LIBS_DIR_OVERRIDE = process.env.SIMPLEX_LIBS_DIR || process.env.npm_config_simplex_libs_dir;
12
+ const LIB_NAMES = ['libsimplex.so', 'libsimplex.dylib', 'libsimplex.dll'];
9
13
 
10
14
  if (BACKEND !== 'sqlite' && BACKEND !== 'postgres') {
11
15
  console.error(`✗ Invalid SIMPLEX_BACKEND: "${BACKEND}". Must be "sqlite" or "postgres".`);
@@ -83,8 +87,31 @@ function isAlreadyInstalled() {
83
87
  }
84
88
  }
85
89
 
90
+ // No version check: the files behind SIMPLEX_LIBS_DIR change on every rebuild.
91
+ function installFromOverride() {
92
+ if (!fs.existsSync(LIBS_DIR_OVERRIDE)) {
93
+ throw new Error(`SIMPLEX_LIBS_DIR does not exist: ${LIBS_DIR_OVERRIDE}`);
94
+ }
95
+ const lib = LIB_NAMES.find((name) => fs.existsSync(path.join(LIBS_DIR_OVERRIDE, name)));
96
+ if (!lib) {
97
+ throw new Error(`No ${LIB_NAMES.join(' / ')} in SIMPLEX_LIBS_DIR: ${LIBS_DIR_OVERRIDE}`);
98
+ }
99
+ console.log(`Using libraries from SIMPLEX_LIBS_DIR: ${LIBS_DIR_OVERRIDE}`);
100
+ cleanLibsDirectory();
101
+ copyDirSync(LIBS_DIR_OVERRIDE, LIBS_DIR);
102
+ // Not a release tag: a later install without the variable sees a mismatch
103
+ // and replaces these files with the released ones.
104
+ fs.writeFileSync(INSTALLED_FILE, `${LIBS_DIR_OVERRIDE}:${BACKEND}`, 'utf-8');
105
+ console.log(`✓ Installed ${lib} and its runtime libraries from ${LIBS_DIR_OVERRIDE}`);
106
+ }
107
+
86
108
  async function install() {
87
109
  try {
110
+ if (LIBS_DIR_OVERRIDE) {
111
+ installFromOverride();
112
+ return;
113
+ }
114
+
88
115
  // Check if already installed
89
116
  if (isAlreadyInstalled()) {
90
117
  return;
package/src/simplex.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  // These functions are defined in CPP add-on ../cpp/simplex.cc
2
2
 
3
3
  export function chat_migrate_init(dbPath: string, dbKey: string, confirm: string): Promise<[bigint, string]>
4
+ export function chat_migrate_init_queue(dbPath: string, dbKey: string, confirm: string, queueSize: number): Promise<[bigint, string]>
4
5
  export function chat_close_store(ctrl: bigint): Promise<string>
5
6
  export function chat_send_cmd(ctrl: bigint, cmd: string): Promise<string>
6
7
  export function chat_recv_msg_wait(ctrl: bigint, wait: number): Promise<string>
7
- export function chat_write_file(ctrl: bigint, path: string, buffer: ArrayBuffer): Promise<string>
8
- export function chat_read_file(path: string, key: string, nonce: string): Promise<ArrayBuffer>
8
+ export function chat_write_file(ctrl: bigint, path: string, buffer: ArrayBuffer | Uint8Array): Promise<string>
9
+ export function chat_read_file(path: string, key: string, nonce: string): Promise<Buffer>
9
10
  export function chat_encrypt_file(ctrl: bigint, fromPath: string, toPath: string): Promise<string>
10
11
  export function chat_decrypt_file(fromPath: string, key: string, nonce: string, toPath: string): Promise<string>
package/src/util.ts CHANGED
@@ -78,7 +78,7 @@ export interface BotCommand {
78
78
  export function ciBotCommand(chatItem: T.ChatItem): BotCommand | undefined {
79
79
  const msg = ciContentText(chatItem)?.trim()
80
80
  if (msg) {
81
- const r = msg.match(/^\/([^\s]+)(.*)/)
81
+ const r = msg.match(/^\/([^\s]+)([\s\S]*)/)
82
82
  if (r && r.length >= 3) {
83
83
  return {keyword: r[1], params: r[2].trim()}
84
84
  }