lemon-model 1.2.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/dist/esm/index.js +1 -0
  2. package/dist/esm/index.js.map +1 -1
  3. package/dist/esm/socket/decorators.js +266 -0
  4. package/dist/esm/socket/decorators.js.map +1 -0
  5. package/dist/esm/socket/index.js +2 -0
  6. package/dist/esm/socket/index.js.map +1 -1
  7. package/dist/esm/socket/multi.js +94 -0
  8. package/dist/esm/socket/multi.js.map +1 -0
  9. package/dist/esm/socket/socket.js +82 -22
  10. package/dist/esm/socket/socket.js.map +1 -1
  11. package/dist/esm/socket/transport.js +385 -3
  12. package/dist/esm/socket/transport.js.map +1 -1
  13. package/dist/esm/sync/client.js +166 -0
  14. package/dist/esm/sync/client.js.map +1 -0
  15. package/dist/esm/sync/index.js +14 -0
  16. package/dist/esm/sync/index.js.map +1 -0
  17. package/dist/esm/sync/machine.js +181 -0
  18. package/dist/esm/sync/machine.js.map +1 -0
  19. package/dist/esm/sync/network.js +273 -0
  20. package/dist/esm/sync/network.js.map +1 -0
  21. package/dist/esm/sync/testing.js +44 -0
  22. package/dist/esm/sync/testing.js.map +1 -0
  23. package/dist/esm/sync/ticker.js +53 -0
  24. package/dist/esm/sync/ticker.js.map +1 -0
  25. package/dist/esm/sync/types.js +2 -0
  26. package/dist/{proxy → esm/sync}/types.js.map +1 -1
  27. package/dist/esm/upload/engine/engine.js +166 -0
  28. package/dist/esm/upload/engine/engine.js.map +1 -0
  29. package/dist/esm/upload/engine/executors.js +57 -0
  30. package/dist/esm/upload/engine/executors.js.map +1 -0
  31. package/dist/esm/upload/engine/index.js +13 -0
  32. package/dist/esm/upload/engine/index.js.map +1 -0
  33. package/dist/esm/upload/engine/progress.js +52 -0
  34. package/dist/esm/upload/engine/progress.js.map +1 -0
  35. package/dist/esm/upload/index.js +11 -0
  36. package/dist/esm/upload/index.js.map +1 -0
  37. package/dist/esm/upload/testing.js +73 -0
  38. package/dist/esm/upload/testing.js.map +1 -0
  39. package/dist/esm/upload/types.js +69 -0
  40. package/dist/esm/upload/types.js.map +1 -0
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.js +1 -0
  43. package/dist/index.js.map +1 -1
  44. package/dist/socket/client/index.d.ts +9 -0
  45. package/dist/socket/client/index.js +26 -0
  46. package/dist/socket/client/index.js.map +1 -0
  47. package/dist/socket/client/keep-alive-controller.d.ts +35 -0
  48. package/dist/socket/client/keep-alive-controller.js +101 -0
  49. package/dist/socket/client/keep-alive-controller.js.map +1 -0
  50. package/dist/socket/client/message-router.d.ts +15 -0
  51. package/dist/socket/client/message-router.js +52 -0
  52. package/dist/socket/client/message-router.js.map +1 -0
  53. package/dist/socket/client/pending-request-store.d.ts +24 -0
  54. package/dist/socket/client/pending-request-store.js +78 -0
  55. package/dist/socket/client/pending-request-store.js.map +1 -0
  56. package/dist/socket/client/reconnect-controller.d.ts +56 -0
  57. package/dist/socket/client/reconnect-controller.js +177 -0
  58. package/dist/socket/client/reconnect-controller.js.map +1 -0
  59. package/dist/socket/client/rotation-controller.d.ts +32 -0
  60. package/dist/socket/client/rotation-controller.js +76 -0
  61. package/dist/socket/client/rotation-controller.js.map +1 -0
  62. package/dist/socket/client/shared-timer-scheduler.d.ts +17 -0
  63. package/dist/socket/client/shared-timer-scheduler.js +77 -0
  64. package/dist/socket/client/shared-timer-scheduler.js.map +1 -0
  65. package/dist/socket/client/socket-client.d.ts +2 -0
  66. package/dist/socket/client/socket-client.js +219 -0
  67. package/dist/socket/client/socket-client.js.map +1 -0
  68. package/dist/socket/client/types.d.ts +101 -0
  69. package/dist/socket/client/types.js +3 -0
  70. package/dist/socket/client/types.js.map +1 -0
  71. package/dist/socket/client/websocket-client-transport.d.ts +23 -0
  72. package/dist/socket/client/websocket-client-transport.js +152 -0
  73. package/dist/socket/client/websocket-client-transport.js.map +1 -0
  74. package/dist/socket/decorators.d.ts +38 -0
  75. package/dist/socket/decorators.js +271 -0
  76. package/dist/socket/decorators.js.map +1 -0
  77. package/dist/socket/index.d.ts +2 -0
  78. package/dist/socket/index.js +2 -0
  79. package/dist/socket/index.js.map +1 -1
  80. package/dist/socket/multi.d.ts +33 -0
  81. package/dist/socket/multi.js +98 -0
  82. package/dist/socket/multi.js.map +1 -0
  83. package/dist/socket/socket.d.ts +22 -4
  84. package/dist/socket/socket.js +82 -22
  85. package/dist/socket/socket.js.map +1 -1
  86. package/dist/socket/transport.d.ts +124 -6
  87. package/dist/socket/transport.js +389 -4
  88. package/dist/socket/transport.js.map +1 -1
  89. package/dist/sync/client.d.ts +16 -0
  90. package/dist/sync/client.js +171 -0
  91. package/dist/sync/client.js.map +1 -0
  92. package/dist/sync/index.d.ts +10 -0
  93. package/dist/sync/index.js +30 -0
  94. package/dist/sync/index.js.map +1 -0
  95. package/dist/sync/machine.d.ts +3 -0
  96. package/dist/sync/machine.js +185 -0
  97. package/dist/sync/machine.js.map +1 -0
  98. package/dist/sync/network.d.ts +38 -0
  99. package/dist/sync/network.js +278 -0
  100. package/dist/sync/network.js.map +1 -0
  101. package/dist/sync/testing.d.ts +38 -0
  102. package/dist/sync/testing.js +48 -0
  103. package/dist/sync/testing.js.map +1 -0
  104. package/dist/sync/ticker.d.ts +21 -0
  105. package/dist/sync/ticker.js +57 -0
  106. package/dist/sync/ticker.js.map +1 -0
  107. package/dist/sync/types.d.ts +115 -0
  108. package/dist/sync/types.js +3 -0
  109. package/dist/sync/types.js.map +1 -0
  110. package/dist/upload/engine/engine.d.ts +52 -0
  111. package/dist/upload/engine/engine.js +172 -0
  112. package/dist/upload/engine/engine.js.map +1 -0
  113. package/dist/upload/engine/executors.d.ts +44 -0
  114. package/dist/upload/engine/executors.js +62 -0
  115. package/dist/upload/engine/executors.js.map +1 -0
  116. package/dist/upload/engine/index.d.ts +12 -0
  117. package/dist/upload/engine/index.js +29 -0
  118. package/dist/upload/engine/index.js.map +1 -0
  119. package/dist/upload/engine/progress.d.ts +48 -0
  120. package/dist/upload/engine/progress.js +57 -0
  121. package/dist/upload/engine/progress.js.map +1 -0
  122. package/dist/upload/index.d.ts +10 -0
  123. package/dist/{proxy → upload}/index.js +6 -8
  124. package/dist/upload/index.js.map +1 -0
  125. package/dist/upload/testing.d.ts +21 -0
  126. package/dist/upload/testing.js +76 -0
  127. package/dist/upload/testing.js.map +1 -0
  128. package/dist/upload/types.d.ts +230 -0
  129. package/dist/upload/types.js +74 -0
  130. package/dist/upload/types.js.map +1 -0
  131. package/package.json +26 -1
  132. package/dist/proxy/index.d.ts +0 -12
  133. package/dist/proxy/index.js.map +0 -1
  134. package/dist/proxy/proxy.d.ts +0 -75
  135. package/dist/proxy/proxy.js +0 -198
  136. package/dist/proxy/proxy.js.map +0 -1
  137. package/dist/proxy/transport.d.ts +0 -123
  138. package/dist/proxy/transport.js +0 -401
  139. package/dist/proxy/transport.js.map +0 -1
  140. package/dist/proxy/types.d.ts +0 -89
  141. package/dist/proxy/types.js +0 -12
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `upload/engine/index.ts`
3
+ * - isolated entry for the client upload engine: `import { ... } from 'lemon-model/upload/engine'`.
4
+ * - kept OUT of both the package root barrel and `lemon-model/upload`: a server consumer needs the
5
+ * contract only, and must not pull the engine in with it.
6
+ * - shell adapters (XHR, RN bridge, Electron fs) are NOT here — they belong to the consuming app.
7
+ *
8
+ * @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
9
+ */
10
+ export * from './progress.js';
11
+ export * from './engine.js';
12
+ export * from './executors.js';
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/upload/engine/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * `upload/engine/progress.ts`
3
+ * - progress is a CLIENT-LOCAL signal: nothing here travels on the wire and no server ever sees it.
4
+ * the server's knowledge of progress differs per transfer kind (a presigned PUT it cannot see at all),
5
+ * so the contract deliberately carries none of it.
6
+ * - scope A: per-file percent + one batch percent. everything is measured in bytes of the ORIGINAL
7
+ * content, never in wire bytes, so the bar means the same thing whichever executor runs.
8
+ *
9
+ * @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
10
+ */
11
+ /** scale request-body progress (base64 JSON or raw bytes) to original-send bytes */
12
+ export const asContentBytes = (loaded, total, contentSize) => total > 0 ? Math.min(contentSize, Math.round((loaded / total) * contentSize)) : 0;
13
+ /** byte-weighted aggregation; one immutable snapshot per change so a UI store can replace state as-is */
14
+ export class UploadProgressTracker {
15
+ constructor(totals, emit) {
16
+ this.emit = emit;
17
+ this.files = totals.map((total, index) => ({ index, total: Math.max(0, total), settled: false }));
18
+ this.totalBytes = this.files.reduce((sum, file) => sum + file.total, 0);
19
+ }
20
+ /** the per-file sink handed to an executor: clamps to [previous, total], ignores reports after settle */
21
+ sink(index) {
22
+ return sent => {
23
+ var _a;
24
+ const file = this.files[index];
25
+ if (!file || file.settled)
26
+ return;
27
+ const next = Math.min(file.total, Math.max(sent, (_a = file.sent) !== null && _a !== void 0 ? _a : 0));
28
+ if (next === file.sent)
29
+ return;
30
+ this.files = this.files.map(item => (item.index === index ? Object.assign(Object.assign({}, item), { sent: next }) : item));
31
+ this.publish();
32
+ };
33
+ }
34
+ settle(index) {
35
+ const file = this.files[index];
36
+ if (!file || file.settled)
37
+ return;
38
+ this.files = this.files.map(item => (item.index === index ? Object.assign(Object.assign({}, item), { settled: true }) : item));
39
+ this.publish();
40
+ }
41
+ snapshot() {
42
+ const sentBytes = this.files.reduce((sum, file) => { var _a; return sum + (file.settled ? file.total : (_a = file.sent) !== null && _a !== void 0 ? _a : 0); }, 0);
43
+ const settled = this.files.filter(file => file.settled).length;
44
+ const ratio = this.totalBytes > 0 ? sentBytes / this.totalBytes : this.files.length > 0 ? settled / this.files.length : 1;
45
+ return { files: this.files, totalBytes: this.totalBytes, sentBytes, ratio };
46
+ }
47
+ publish() {
48
+ if (this.emit)
49
+ this.emit(this.snapshot());
50
+ }
51
+ }
52
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../../../src/upload/engine/progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,oFAAoF;AACpF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAc,EAAE,KAAa,EAAE,WAAmB,EAAU,EAAE,CACzF,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAyBtF,yGAAyG;AACzG,MAAM,OAAO,qBAAqB;IAI9B,YAAmB,MAA6B,EAAmB,IAA8B;QAA9B,SAAI,GAAJ,IAAI,CAA0B;QAC7F,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAClG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,yGAAyG;IAClG,IAAI,CAAC,KAAa;QACrB,OAAO,IAAI,CAAC,EAAE;;YACV,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO;gBAAE,OAAO;YAClC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,MAAA,IAAI,CAAC,IAAI,mCAAI,CAAC,CAAC,CAAC,CAAC;YAClE,IAAI,IAAI,KAAK,IAAI,CAAC,IAAI;gBAAE,OAAO;YAC/B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,iCAAM,IAAI,KAAE,IAAI,EAAE,IAAI,IAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC7F,IAAI,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC,CAAC;IACN,CAAC;IAEM,MAAM,CAAC,KAAa;QACvB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAClC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,iCAAM,IAAI,KAAE,OAAO,EAAE,IAAI,IAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAChG,IAAI,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAEM,QAAQ;QACX,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,WAAC,OAAA,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAA,IAAI,CAAC,IAAI,mCAAI,CAAC,CAAC,CAAA,EAAA,EAAE,CAAC,CAAC,CAAC;QAC1G,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;QAC/D,MAAM,KAAK,GACP,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChH,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAChF,CAAC;IAEM,OAAO;QACV,IAAI,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9C,CAAC;CACJ"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `upload/index.ts`
3
+ * - isolated entry for the upload contract: `import { ... } from 'lemon-model/upload'`.
4
+ * - kept OUT of the package root barrel: a consumer that only needs this contract must not pull
5
+ * the socket/genai runtime, and a subpath can be promoted to the root later without a breaking
6
+ * change (the reverse is not true).
7
+ *
8
+ * @copyright (C) 2026 LemonCloud Co Ltd. - All Rights Reserved.
9
+ */
10
+ export * from './types.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/upload/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,SAAS,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { UPLOAD_STATUS, UPLOAD_STEREO, UPLOAD_TRANSFER_KIND } from './types.js';
2
+ /** a settled image as the server returns it after `complete` */
3
+ export const SAMPLE_UPLOAD_STORED = {
4
+ id: 'up-001',
5
+ status: UPLOAD_STATUS.stored,
6
+ stereo: UPLOAD_STEREO.image,
7
+ name: 'photo.png',
8
+ contentType: 'image/png',
9
+ contentSize: 123456,
10
+ url: 'https://cdn.example.com/up-001.png',
11
+ width: 1024,
12
+ height: 768,
13
+ createdAt: 1757894400000,
14
+ updatedAt: 1757894401000,
15
+ };
16
+ /** the head a message embeds under `upload$$` for the same upload */
17
+ export const SAMPLE_UPLOAD_HEAD = {
18
+ id: 'up-001',
19
+ stereo: UPLOAD_STEREO.image,
20
+ name: 'photo.png',
21
+ contentType: 'image/png',
22
+ contentSize: 123456,
23
+ url: 'https://cdn.example.com/up-001.png',
24
+ width: 1024,
25
+ height: 768,
26
+ };
27
+ /** what a message view carries: both halves of the pair, never one */
28
+ export const SAMPLE_UPLOAD_REFS = {
29
+ uploadIds: ['up-001'],
30
+ upload$$: [SAMPLE_UPLOAD_HEAD],
31
+ };
32
+ /** start slot: inline ticket (roadmap 1) */
33
+ export const SAMPLE_UPLOAD_TICKET_INLINE = {
34
+ upload: {
35
+ id: 'up-002',
36
+ status: UPLOAD_STATUS.pending,
37
+ stereo: UPLOAD_STEREO.image,
38
+ name: 'photo.png',
39
+ contentType: 'image/png',
40
+ contentSize: 123456,
41
+ },
42
+ transfer: { kind: UPLOAD_TRANSFER_KIND.inline, maxBytes: 4000000 },
43
+ };
44
+ /** start slot: presigned ticket (roadmap 2) */
45
+ export const SAMPLE_UPLOAD_TICKET_PRESIGNED = {
46
+ upload: {
47
+ id: 'up-003',
48
+ status: UPLOAD_STATUS.pending,
49
+ stereo: UPLOAD_STEREO.image,
50
+ name: 'photo.png',
51
+ contentType: 'image/png',
52
+ contentSize: 123456,
53
+ },
54
+ transfer: {
55
+ kind: UPLOAD_TRANSFER_KIND.presignedPut,
56
+ method: 'PUT',
57
+ url: 'https://storage.example.com/up-003?X-Amz-Signature=masked',
58
+ headers: { 'content-type': 'image/png', 'content-length': '123456' },
59
+ maxBytes: 50000000,
60
+ expiresAt: 1757895300000,
61
+ },
62
+ };
63
+ /** start slot rejected at validation: no id, nothing to transfer or complete */
64
+ export const SAMPLE_UPLOAD_REJECTED = {
65
+ upload: {
66
+ status: UPLOAD_STATUS.failed,
67
+ name: 'big.png',
68
+ contentType: 'image/png',
69
+ contentSize: 6291456,
70
+ error: '413 TOO LARGE - 6291456 > 4000000',
71
+ },
72
+ };
73
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.js","sourceRoot":"","sources":["../../../src/upload/testing.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE7E,gEAAgE;AAChE,MAAM,CAAC,MAAM,oBAAoB,GAAe;IAC5C,EAAE,EAAE,QAAQ;IACZ,MAAM,EAAE,aAAa,CAAC,MAAM;IAC5B,MAAM,EAAE,aAAa,CAAC,KAAK;IAC3B,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,WAAW;IACxB,WAAW,EAAE,MAAM;IACnB,GAAG,EAAE,oCAAoC;IACzC,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,GAAG;IACX,SAAS,EAAE,aAAa;IACxB,SAAS,EAAE,aAAa;CAC3B,CAAC;AAEF,qEAAqE;AACrE,MAAM,CAAC,MAAM,kBAAkB,GAAe;IAC1C,EAAE,EAAE,QAAQ;IACZ,MAAM,EAAE,aAAa,CAAC,KAAK;IAC3B,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,WAAW;IACxB,WAAW,EAAE,MAAM;IACnB,GAAG,EAAE,oCAAoC;IACzC,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,GAAG;CACd,CAAC;AAEF,sEAAsE;AACtE,MAAM,CAAC,MAAM,kBAAkB,GAAe;IAC1C,SAAS,EAAE,CAAC,QAAQ,CAAC;IACrB,QAAQ,EAAE,CAAC,kBAAkB,CAAC;CACjC,CAAC;AAEF,4CAA4C;AAC5C,MAAM,CAAC,MAAM,2BAA2B,GAAiB;IACrD,MAAM,EAAE;QACJ,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,aAAa,CAAC,OAAO;QAC7B,MAAM,EAAE,aAAa,CAAC,KAAK;QAC3B,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,MAAM;KACtB;IACD,QAAQ,EAAE,EAAE,IAAI,EAAE,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE;CACrE,CAAC;AAEF,+CAA+C;AAC/C,MAAM,CAAC,MAAM,8BAA8B,GAAiB;IACxD,MAAM,EAAE;QACJ,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,aAAa,CAAC,OAAO;QAC7B,MAAM,EAAE,aAAa,CAAC,KAAK;QAC3B,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,MAAM;KACtB;IACD,QAAQ,EAAE;QACN,IAAI,EAAE,oBAAoB,CAAC,YAAY;QACvC,MAAM,EAAE,KAAK;QACb,GAAG,EAAE,2DAA2D;QAChE,OAAO,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,gBAAgB,EAAE,QAAQ,EAAE;QACpE,QAAQ,EAAE,QAAQ;QAClB,SAAS,EAAE,aAAa;KAC3B;CACJ,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,sBAAsB,GAAiB;IAChD,MAAM,EAAE;QACJ,MAAM,EAAE,aAAa,CAAC,MAAM;QAC5B,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,WAAW;QACxB,WAAW,EAAE,OAAO;QACpB,KAAK,EAAE,mCAAmC;KAC7C;CACJ,CAAC"}
@@ -0,0 +1,69 @@
1
+ /** kind of stored content. same vocabulary as lemon-uploads-api `MediaStereo` minus its internal markers */
2
+ export const UPLOAD_STEREO = {
3
+ image: 'image',
4
+ video: 'video',
5
+ sound: 'sound',
6
+ docs: 'docs',
7
+ };
8
+ /** lifecycle of one upload as the client sees it. `url` is meaningful only when `stored` */
9
+ export const UPLOAD_STATUS = {
10
+ /** ticket issued; bytes not confirmed by the server yet */
11
+ pending: 'pending',
12
+ /** bytes durable and `url` valid */
13
+ stored: 'stored',
14
+ /** terminal; `error` carries "<status> <LABEL> - <detail>" */
15
+ failed: 'failed',
16
+ };
17
+ /** how bytes travel. the only axis that changes across the roadmap */
18
+ export const UPLOAD_TRANSFER_KIND = {
19
+ /** base64 JSON to the API via the `send` operation (roadmap 1) */
20
+ inline: 'inline',
21
+ /** HTTP PUT straight to storage with a server-issued url + headers (roadmap 2) */
22
+ presignedPut: 'presigned-put',
23
+ };
24
+ /** who produced a failure */
25
+ export const UPLOAD_FAILURE_SOURCE = {
26
+ /** our API answered with an error */
27
+ api: 'api',
28
+ /** the storage endpoint (presigned PUT) answered with an error */
29
+ storage: 'storage',
30
+ /** the client gave up before or without a response */
31
+ client: 'client',
32
+ };
33
+ /** normalized failure codes; the app branches on these, never on raw HTTP status */
34
+ export const UPLOAD_FAILURE_CODE = {
35
+ invalid: 'invalid',
36
+ tooLarge: 'too-large',
37
+ unsupported: 'unsupported',
38
+ notAcceptable: 'not-acceptable',
39
+ notFound: 'not-found',
40
+ conflict: 'conflict',
41
+ expired: 'expired',
42
+ signature: 'signature',
43
+ checksum: 'checksum',
44
+ network: 'network',
45
+ aborted: 'aborted',
46
+ unknown: 'unknown',
47
+ };
48
+ /** HTTP binding relative to the server's upload base path (lemon-core `/{type}/{id}/{cmd}` shape) */
49
+ export const UPLOAD_ROUTES = {
50
+ start: { method: 'POST', path: '/start' },
51
+ send: { method: 'POST', path: '/{id}/send' },
52
+ complete: { method: 'POST', path: '/complete' },
53
+ read: { method: 'GET', path: '/{id}' },
54
+ };
55
+ export const isUploadStored = (view) => view.status === UPLOAD_STATUS.stored && typeof view.id === 'string' && typeof view.url === 'string';
56
+ /** shared stereo derivation so an optimistic client tile and the server agree */
57
+ export const uploadStereoOf = (contentType) => {
58
+ const type = contentType.toLowerCase().split(';')[0].trim();
59
+ if (type.startsWith('image/'))
60
+ return UPLOAD_STEREO.image;
61
+ if (type.startsWith('video/'))
62
+ return UPLOAD_STEREO.video;
63
+ if (type.startsWith('audio/'))
64
+ return UPLOAD_STEREO.sound;
65
+ if (type === 'application/pdf')
66
+ return UPLOAD_STEREO.docs;
67
+ return undefined;
68
+ };
69
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/upload/types.ts"],"names":[],"mappings":"AAaA,4GAA4G;AAC5G,MAAM,CAAC,MAAM,aAAa,GAAG;IACzB,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;CACN,CAAC;AAGX,4FAA4F;AAC5F,MAAM,CAAC,MAAM,aAAa,GAAG;IACzB,2DAA2D;IAC3D,OAAO,EAAE,SAAS;IAClB,oCAAoC;IACpC,MAAM,EAAE,QAAQ;IAChB,8DAA8D;IAC9D,MAAM,EAAE,QAAQ;CACV,CAAC;AAGX,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAChC,kEAAkE;IAClE,MAAM,EAAE,QAAQ;IAChB,kFAAkF;IAClF,YAAY,EAAE,eAAe;CACvB,CAAC;AAoHX,6BAA6B;AAC7B,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACjC,qCAAqC;IACrC,GAAG,EAAE,KAAK;IACV,kEAAkE;IAClE,OAAO,EAAE,SAAS;IAClB,sDAAsD;IACtD,MAAM,EAAE,QAAQ;CACV,CAAC;AAGX,oFAAoF;AACpF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IAC/B,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,aAAa;IAC1B,aAAa,EAAE,gBAAgB;IAC/B,QAAQ,EAAE,WAAW;IACrB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACZ,CAAC;AA8CX,qGAAqG;AACrG,MAAM,CAAC,MAAM,aAAa,GAAG;IACzB,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE;IAC5C,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE;IAC/C,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE;CAChC,CAAC;AAKX,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAgB,EAA4B,EAAE,CACzE,IAAI,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC;AAExG,iFAAiF;AACjF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,WAAmB,EAA4B,EAAE;IAC5E,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5D,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,aAAa,CAAC,KAAK,CAAC;IAC1D,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,aAAa,CAAC,KAAK,CAAC;IAC1D,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,aAAa,CAAC,KAAK,CAAC;IAC1D,IAAI,IAAI,KAAK,iBAAiB;QAAE,OAAO,aAAa,CAAC,IAAI,CAAC;IAC1D,OAAO,SAAS,CAAC;AACrB,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -13,5 +13,6 @@ export * from './cores';
13
13
  export * from './socket';
14
14
  export * from './genai';
15
15
  export * from './buffer';
16
+ export * from './sync';
16
17
  export * from './progress';
17
18
  export * from './logtrace';
package/dist/index.js CHANGED
@@ -29,6 +29,7 @@ __exportStar(require("./cores"), exports);
29
29
  __exportStar(require("./socket"), exports);
30
30
  __exportStar(require("./genai"), exports);
31
31
  __exportStar(require("./buffer"), exports);
32
+ __exportStar(require("./sync"), exports);
32
33
  __exportStar(require("./progress"), exports);
33
34
  __exportStar(require("./logtrace"), exports);
34
35
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;;;;;;GASG;AACH,0CAAwB;AACxB,0CAAwB;AACxB,2CAAyB;AACzB,0CAAwB;AACxB,2CAAyB;AACzB,6CAA2B;AAC3B,6CAA2B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;;;;;;GASG;AACH,0CAAwB;AACxB,0CAAwB;AACxB,2CAAyB;AACzB,0CAAwB;AACxB,2CAAyB;AACzB,yCAAuB;AACvB,6CAA2B;AAC3B,6CAA2B"}
@@ -0,0 +1,9 @@
1
+ export * from './types';
2
+ export * from './shared-timer-scheduler';
3
+ export * from './message-router';
4
+ export * from './pending-request-store';
5
+ export * from './socket-client';
6
+ export * from './websocket-client-transport';
7
+ export * from './keep-alive-controller';
8
+ export * from './reconnect-controller';
9
+ export * from './rotation-controller';
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./shared-timer-scheduler"), exports);
19
+ __exportStar(require("./message-router"), exports);
20
+ __exportStar(require("./pending-request-store"), exports);
21
+ __exportStar(require("./socket-client"), exports);
22
+ __exportStar(require("./websocket-client-transport"), exports);
23
+ __exportStar(require("./keep-alive-controller"), exports);
24
+ __exportStar(require("./reconnect-controller"), exports);
25
+ __exportStar(require("./rotation-controller"), exports);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/socket/client/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,2DAAyC;AACzC,mDAAiC;AACjC,0DAAwC;AACxC,kDAAgC;AAChC,+DAA6C;AAC7C,0DAAwC;AACxC,yDAAuC;AACvC,wDAAsC"}
@@ -0,0 +1,35 @@
1
+ import type { SharedTimerScheduler, SocketRuntimePort } from './types';
2
+ export interface KeepAliveControllerOptions<TMessage> {
3
+ client: SocketRuntimePort<TMessage>;
4
+ buildMessage: () => TMessage;
5
+ intervalMs?: number;
6
+ timeoutMs?: number;
7
+ maxMissedPongs?: number;
8
+ mode?: 'send' | 'request';
9
+ timerScheduler?: SharedTimerScheduler;
10
+ timerKey?: string;
11
+ onPongTimeout?: () => unknown | Promise<unknown>;
12
+ }
13
+ export declare class KeepAliveController<TMessage> {
14
+ private readonly client;
15
+ private readonly buildMessage;
16
+ private readonly intervalMs;
17
+ private readonly timeoutMs;
18
+ private readonly maxMissedPongs;
19
+ private readonly mode;
20
+ private readonly timerScheduler;
21
+ private readonly timerKey;
22
+ private readonly onPongTimeout;
23
+ private readonly unsubs;
24
+ private running;
25
+ private inFlight;
26
+ private missedPongs;
27
+ constructor(options: KeepAliveControllerOptions<TMessage>);
28
+ start(): void;
29
+ stop(): void;
30
+ destroy(): void;
31
+ private scheduleNow;
32
+ private scheduleNext;
33
+ private clearTimer;
34
+ private tick;
35
+ }
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.KeepAliveController = void 0;
13
+ const shared_timer_scheduler_1 = require("./shared-timer-scheduler");
14
+ class KeepAliveController {
15
+ constructor(options) {
16
+ var _a, _b, _c, _d, _e, _f;
17
+ this.unsubs = [];
18
+ this.running = false;
19
+ this.inFlight = false;
20
+ this.missedPongs = 0;
21
+ this.client = options.client;
22
+ this.buildMessage = options.buildMessage;
23
+ this.intervalMs = (_a = options.intervalMs) !== null && _a !== void 0 ? _a : 30000;
24
+ this.timeoutMs = (_b = options.timeoutMs) !== null && _b !== void 0 ? _b : 10000;
25
+ this.maxMissedPongs = Math.max(1, (_c = options.maxMissedPongs) !== null && _c !== void 0 ? _c : 2);
26
+ this.mode = (_d = options.mode) !== null && _d !== void 0 ? _d : 'request';
27
+ this.timerScheduler = (_e = options.timerScheduler) !== null && _e !== void 0 ? _e : new shared_timer_scheduler_1.InMemorySharedTimerScheduler();
28
+ this.timerKey = (_f = options.timerKey) !== null && _f !== void 0 ? _f : 'keepalive';
29
+ this.onPongTimeout = options.onPongTimeout;
30
+ this.unsubs.push(options.client.onState(event => {
31
+ if (event.next === 'connected' && this.running) {
32
+ this.missedPongs = 0;
33
+ this.scheduleNow();
34
+ }
35
+ if (event.next === 'closing' || event.next === 'closed') {
36
+ this.missedPongs = 0;
37
+ this.clearTimer();
38
+ }
39
+ }));
40
+ }
41
+ start() {
42
+ this.running = true;
43
+ if (this.client.state === 'connected')
44
+ this.scheduleNow();
45
+ }
46
+ stop() {
47
+ this.running = false;
48
+ this.clearTimer();
49
+ }
50
+ destroy() {
51
+ this.stop();
52
+ this.unsubs.splice(0).forEach(unsub => unsub());
53
+ }
54
+ scheduleNow() {
55
+ this.clearTimer();
56
+ this.timerScheduler.schedule(this.timerKey, 0, () => this.tick());
57
+ }
58
+ scheduleNext() {
59
+ this.clearTimer();
60
+ if (!this.running || this.client.state !== 'connected')
61
+ return;
62
+ this.timerScheduler.schedule(this.timerKey, this.intervalMs, () => this.tick());
63
+ }
64
+ clearTimer() {
65
+ this.timerScheduler.cancel(this.timerKey);
66
+ }
67
+ tick() {
68
+ return __awaiter(this, void 0, void 0, function* () {
69
+ if (!this.running || this.client.state !== 'connected' || this.inFlight)
70
+ return;
71
+ this.inFlight = true;
72
+ try {
73
+ const message = this.buildMessage();
74
+ if (this.mode === 'send') {
75
+ this.client.send(message);
76
+ return;
77
+ }
78
+ yield this.client.request(message, { timeoutMs: this.timeoutMs });
79
+ this.missedPongs = 0;
80
+ }
81
+ catch (_a) {
82
+ if (this.mode === 'request') {
83
+ this.missedPongs += 1;
84
+ if (this.missedPongs >= this.maxMissedPongs) {
85
+ this.missedPongs = 0;
86
+ if (this.onPongTimeout)
87
+ yield Promise.resolve(this.onPongTimeout()).catch(() => undefined);
88
+ else
89
+ yield this.client.disconnect(1001, 'pong-timeout').catch(() => undefined);
90
+ }
91
+ }
92
+ }
93
+ finally {
94
+ this.inFlight = false;
95
+ this.scheduleNext();
96
+ }
97
+ });
98
+ }
99
+ }
100
+ exports.KeepAliveController = KeepAliveController;
101
+ //# sourceMappingURL=keep-alive-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keep-alive-controller.js","sourceRoot":"","sources":["../../../src/socket/client/keep-alive-controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { SocketUnsubscribe } from '../types';
2
+ export declare type MessageListener<TMessage = unknown> = (message: TMessage) => void;
3
+ export interface MessageRouterOptions<TMessage> {
4
+ getMessageType?: (message: TMessage) => string | undefined;
5
+ }
6
+ export declare class MessageRouter<TMessage = any> {
7
+ private readonly anyListeners;
8
+ private readonly typeListeners;
9
+ private readonly getMessageType;
10
+ constructor(options?: MessageRouterOptions<TMessage>);
11
+ onAny(listener: MessageListener<TMessage>): SocketUnsubscribe;
12
+ onType(type: string, listener: MessageListener<TMessage>): SocketUnsubscribe;
13
+ clear(): void;
14
+ route(message: TMessage): number;
15
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MessageRouter = void 0;
4
+ class MessageRouter {
5
+ constructor(options = {}) {
6
+ var _a;
7
+ this.anyListeners = new Set();
8
+ this.typeListeners = new Map();
9
+ this.getMessageType = (_a = options.getMessageType) !== null && _a !== void 0 ? _a : (message => { var _a; return `${(_a = message === null || message === void 0 ? void 0 : message.type) !== null && _a !== void 0 ? _a : ''}`; });
10
+ }
11
+ onAny(listener) {
12
+ this.anyListeners.add(listener);
13
+ return () => this.anyListeners.delete(listener);
14
+ }
15
+ onType(type, listener) {
16
+ var _a;
17
+ const key = `${type !== null && type !== void 0 ? type : ''}`.trim();
18
+ if (!key)
19
+ throw new Error(`@type (string) is required - MessageRouter.onType()`);
20
+ const bucket = (_a = this.typeListeners.get(key)) !== null && _a !== void 0 ? _a : new Set();
21
+ bucket.add(listener);
22
+ this.typeListeners.set(key, bucket);
23
+ return () => {
24
+ bucket.delete(listener);
25
+ if (!bucket.size)
26
+ this.typeListeners.delete(key);
27
+ };
28
+ }
29
+ clear() {
30
+ this.anyListeners.clear();
31
+ this.typeListeners.clear();
32
+ }
33
+ route(message) {
34
+ var _a;
35
+ const key = `${(_a = this.getMessageType(message)) !== null && _a !== void 0 ? _a : ''}`.trim();
36
+ let count = 0;
37
+ this.anyListeners.forEach(listener => {
38
+ listener(message);
39
+ count += 1;
40
+ });
41
+ if (!key)
42
+ return count;
43
+ const bucket = this.typeListeners.get(key);
44
+ bucket === null || bucket === void 0 ? void 0 : bucket.forEach(listener => {
45
+ listener(message);
46
+ count += 1;
47
+ });
48
+ return count;
49
+ }
50
+ }
51
+ exports.MessageRouter = MessageRouter;
52
+ //# sourceMappingURL=message-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-router.js","sourceRoot":"","sources":["../../../src/socket/client/message-router.ts"],"names":[],"mappings":";;;AAQA,MAAa,aAAa;IAKtB,YAAmB,UAA0C,EAAE;;QAJ9C,iBAAY,GAAG,IAAI,GAAG,EAA6B,CAAC;QACpD,kBAAa,GAAG,IAAI,GAAG,EAA0C,CAAC;QAI/E,IAAI,CAAC,cAAc,GAAG,MAAA,OAAO,CAAC,cAAc,mCAAI,CAAC,OAAO,CAAC,EAAE,WAAC,OAAA,GAAG,MAAC,OAAe,aAAf,OAAO,uBAAP,OAAO,CAAU,IAAI,mCAAI,EAAE,EAAE,CAAA,EAAA,CAAC,CAAC;IACnG,CAAC;IAEM,KAAK,CAAC,QAAmC;QAC5C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpD,CAAC;IAEM,MAAM,CAAC,IAAY,EAAE,QAAmC;;QAC3D,MAAM,GAAG,GAAG,GAAG,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACjF,MAAM,MAAM,GAAG,MAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,mCAAI,IAAI,GAAG,EAA6B,CAAC;QACnF,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACpC,OAAO,GAAG,EAAE;YACR,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,IAAI;gBAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrD,CAAC,CAAC;IACN,CAAC;IAEM,KAAK;QACR,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;IAEM,KAAK,CAAC,OAAiB;;QAC1B,MAAM,GAAG,GAAG,GAAG,MAAA,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,mCAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;QAC3D,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;YACjC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAClB,KAAK,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YACvB,QAAQ,CAAC,OAAO,CAAC,CAAC;YAClB,KAAK,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ;AA9CD,sCA8CC"}
@@ -0,0 +1,24 @@
1
+ import type { SharedTimerScheduler } from './types';
2
+ export interface PendingRequestStoreOptions {
3
+ timerScheduler?: SharedTimerScheduler;
4
+ timerPrefix?: string;
5
+ }
6
+ export interface PendingRequestCreateOptions {
7
+ timeoutMs?: number;
8
+ onTimeout?: (mid: string) => Error;
9
+ }
10
+ export declare class PendingRequestStore {
11
+ private readonly items;
12
+ private readonly timerScheduler;
13
+ private readonly timerPrefix;
14
+ constructor(options?: PendingRequestStoreOptions);
15
+ size(): number;
16
+ has(mid: string): boolean;
17
+ create<T = unknown>(mid: string, options?: PendingRequestCreateOptions): Promise<T>;
18
+ resolve<T = unknown>(mid: string, value: T): boolean;
19
+ reject(mid: string, error: unknown): boolean;
20
+ clear(reason?: unknown): number;
21
+ private timeout;
22
+ private remove;
23
+ private toTimerKey;
24
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PendingRequestStore = void 0;
4
+ class PendingRequestStore {
5
+ constructor(options = {}) {
6
+ var _a;
7
+ this.items = new Map();
8
+ this.timerScheduler = options.timerScheduler;
9
+ this.timerPrefix = (_a = options.timerPrefix) !== null && _a !== void 0 ? _a : 'pending:';
10
+ }
11
+ size() {
12
+ return this.items.size;
13
+ }
14
+ has(mid) {
15
+ return this.items.has(mid);
16
+ }
17
+ create(mid, options = {}) {
18
+ if (!mid)
19
+ throw new Error(`@mid (string) is required - PendingRequestStore.create()`);
20
+ if (this.items.has(mid))
21
+ throw new Error(`409 CONFLICT - pending request[${mid}] already exists`);
22
+ return new Promise((resolve, reject) => {
23
+ const item = {
24
+ resolve,
25
+ reject,
26
+ timer: options.timeoutMs && options.timeoutMs > 0 && !this.timerScheduler
27
+ ? setTimeout(() => this.timeout(mid, options), options.timeoutMs)
28
+ : undefined,
29
+ };
30
+ this.items.set(mid, item);
31
+ if (options.timeoutMs && options.timeoutMs > 0 && this.timerScheduler) {
32
+ this.timerScheduler.schedule(this.toTimerKey(mid), options.timeoutMs, () => this.timeout(mid, options));
33
+ }
34
+ });
35
+ }
36
+ resolve(mid, value) {
37
+ const item = this.items.get(mid);
38
+ if (!item)
39
+ return false;
40
+ this.remove(mid, item);
41
+ item.resolve(value);
42
+ return true;
43
+ }
44
+ reject(mid, error) {
45
+ const item = this.items.get(mid);
46
+ if (!item)
47
+ return false;
48
+ this.remove(mid, item);
49
+ item.reject(error);
50
+ return true;
51
+ }
52
+ clear(reason = new Error(`499 CLIENT CLOSED REQUEST`)) {
53
+ const mids = [...this.items.keys()];
54
+ mids.forEach(mid => this.reject(mid, reason));
55
+ return mids.length;
56
+ }
57
+ timeout(mid, options) {
58
+ var _a, _b;
59
+ const item = this.items.get(mid);
60
+ if (!item)
61
+ return;
62
+ this.items.delete(mid);
63
+ const error = (_b = (_a = options.onTimeout) === null || _a === void 0 ? void 0 : _a.call(options, mid)) !== null && _b !== void 0 ? _b : new Error(`408 REQUEST TIMEOUT - pending[${mid}]`);
64
+ item.reject(error);
65
+ }
66
+ remove(mid, item) {
67
+ var _a;
68
+ this.items.delete(mid);
69
+ (_a = this.timerScheduler) === null || _a === void 0 ? void 0 : _a.cancel(this.toTimerKey(mid));
70
+ if (item.timer)
71
+ clearTimeout(item.timer);
72
+ }
73
+ toTimerKey(mid) {
74
+ return `${this.timerPrefix}${mid}`;
75
+ }
76
+ }
77
+ exports.PendingRequestStore = PendingRequestStore;
78
+ //# sourceMappingURL=pending-request-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-request-store.js","sourceRoot":"","sources":["../../../src/socket/client/pending-request-store.ts"],"names":[],"mappings":"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"}