amqplib 0.10.8 → 1.0.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 (85) hide show
  1. package/.claude/commands/lint-disable.md +9 -0
  2. package/.claude/commands/lint-enable.md +12 -0
  3. package/.claude/settings.local.json +16 -0
  4. package/.github/workflows/publish.yml +1 -1
  5. package/.github/workflows/test.yml +1 -1
  6. package/CHANGELOG.md +34 -0
  7. package/CLAUDE.md +12 -0
  8. package/Makefile +5 -12
  9. package/bin/generate-defs.js +382 -369
  10. package/biome.json +51 -0
  11. package/callback_api.js +12 -8
  12. package/channel_api.js +5 -10
  13. package/examples/direct_reply_to_client.js +9 -5
  14. package/examples/direct_reply_to_server.js +8 -6
  15. package/examples/headers.js +13 -10
  16. package/examples/receive_generator.js +13 -20
  17. package/examples/send_generators.js +2 -9
  18. package/examples/ssl.js +2 -3
  19. package/examples/stream_queues/receive_stream.js +39 -36
  20. package/examples/stream_queues/send_stream.js +26 -29
  21. package/examples/tutorials/callback_api/emit_log.js +4 -3
  22. package/examples/tutorials/callback_api/emit_log_direct.js +5 -4
  23. package/examples/tutorials/callback_api/emit_log_topic.js +5 -4
  24. package/examples/tutorials/callback_api/new_task.js +5 -4
  25. package/examples/tutorials/callback_api/receive.js +16 -10
  26. package/examples/tutorials/callback_api/receive_logs.js +17 -11
  27. package/examples/tutorials/callback_api/receive_logs_direct.js +19 -13
  28. package/examples/tutorials/callback_api/receive_logs_topic.js +19 -14
  29. package/examples/tutorials/callback_api/rpc_client.js +20 -16
  30. package/examples/tutorials/callback_api/rpc_server.js +27 -21
  31. package/examples/tutorials/callback_api/send.js +4 -3
  32. package/examples/tutorials/callback_api/worker.js +18 -13
  33. package/examples/tutorials/emit_log.js +4 -6
  34. package/examples/tutorials/emit_log_direct.js +5 -7
  35. package/examples/tutorials/emit_log_topic.js +5 -7
  36. package/examples/tutorials/new_task.js +4 -6
  37. package/examples/tutorials/receive.js +8 -4
  38. package/examples/tutorials/receive_logs.js +10 -6
  39. package/examples/tutorials/receive_logs_direct.js +16 -10
  40. package/examples/tutorials/receive_logs_topic.js +16 -11
  41. package/examples/tutorials/rpc_client.js +17 -15
  42. package/examples/tutorials/rpc_server.js +9 -8
  43. package/examples/tutorials/send.js +4 -6
  44. package/examples/tutorials/worker.js +17 -14
  45. package/examples/waitForConfirms.js +2 -2
  46. package/lefthook.yml +14 -0
  47. package/lib/api_args.js +124 -149
  48. package/lib/bitset.js +28 -18
  49. package/lib/callback_model.js +134 -190
  50. package/lib/channel.js +175 -213
  51. package/lib/channel_model.js +41 -85
  52. package/lib/codec.js +257 -228
  53. package/lib/connect.js +74 -82
  54. package/lib/connection.js +204 -240
  55. package/lib/credentials.js +21 -29
  56. package/lib/defs.js +2559 -1927
  57. package/lib/error.js +5 -6
  58. package/lib/format.js +15 -33
  59. package/lib/frame.js +66 -66
  60. package/lib/heartbeat.js +17 -24
  61. package/lib/mux.js +32 -41
  62. package/package.json +8 -5
  63. package/test/bitset.test.js +65 -0
  64. package/test/callback_api.test.js +438 -0
  65. package/test/channel.test.js +592 -0
  66. package/test/channel_api.test.js +537 -0
  67. package/test/codec.test.js +172 -0
  68. package/test/connect.test.js +196 -0
  69. package/test/connection.test.js +330 -0
  70. package/test/data.test.js +33 -0
  71. package/test/frame.test.js +180 -0
  72. package/test/lib/data.js +249 -0
  73. package/test/lib/util.js +223 -0
  74. package/test/mux.test.js +215 -0
  75. package/test/bitset.js +0 -69
  76. package/test/callback_api.js +0 -379
  77. package/test/channel.js +0 -621
  78. package/test/channel_api.js +0 -606
  79. package/test/codec.js +0 -237
  80. package/test/connect.js +0 -197
  81. package/test/connection.js +0 -390
  82. package/test/data.js +0 -269
  83. package/test/frame.js +0 -191
  84. package/test/mux.js +0 -203
  85. package/test/util.js +0 -217
package/lib/codec.js CHANGED
@@ -1,9 +1,4 @@
1
- //
2
- //
3
- //
4
-
5
1
  /*
6
-
7
2
  The AMQP 0-9-1 is a mess when it comes to the types that can be
8
3
  encoded on the wire.
9
4
 
@@ -48,12 +43,9 @@ except that they appear in content header frames, which include a
48
43
  content size, and they carry a set of flags indicating which
49
44
  properties are present. This scheme can save ones of bytes per message
50
45
  (messages which take a minimum of three frames each to send).
51
-
52
46
  */
53
47
 
54
- 'use strict';
55
-
56
- var ints = require('buffer-more-ints');
48
+ const ints = require('buffer-more-ints');
57
49
 
58
50
  // JavaScript uses only doubles so what I'm testing for is whether
59
51
  // it's *better* to encode a number as a float or double. This really
@@ -69,276 +61,313 @@ var ints = require('buffer-more-ints');
69
61
  // as a 64-bit integer. Except that only signed integers are supported
70
62
  // by RabbitMQ, so anything above 2^63 - 1 must be a double.
71
63
  function isFloatingPoint(n) {
72
- return n >= 0x8000000000000000 ||
73
- (Math.abs(n) < 0x4000000000000
74
- && Math.floor(n) !== n);
64
+ return n >= 0x8000000000000000 || (Math.abs(n) < 0x4000000000000 && Math.floor(n) !== n);
75
65
  }
76
66
 
77
67
  function encodeTable(buffer, val, offset) {
78
- var start = offset;
79
- offset += 4; // leave room for the table length
80
- for (var key in val) {
81
- if (val[key] !== undefined) {
82
- var len = Buffer.byteLength(key);
83
- buffer.writeUInt8(len, offset); offset++;
84
- buffer.write(key, offset, 'utf8'); offset += len;
85
- offset += encodeFieldValue(buffer, val[key], offset);
86
- }
68
+ const start = offset;
69
+ offset += 4; // leave room for the table length
70
+ for (const key in val) {
71
+ if (val[key] !== undefined) {
72
+ const len = Buffer.byteLength(key);
73
+ buffer.writeUInt8(len, offset);
74
+ offset++;
75
+ buffer.write(key, offset, 'utf8');
76
+ offset += len;
77
+ offset += encodeFieldValue(buffer, val[key], offset);
87
78
  }
88
- var size = offset - start;
89
- buffer.writeUInt32BE(size - 4, start);
90
- return size;
79
+ }
80
+ const size = offset - start;
81
+ buffer.writeUInt32BE(size - 4, start);
82
+ return size;
91
83
  }
92
84
 
93
85
  function encodeArray(buffer, val, offset) {
94
- var start = offset;
95
- offset += 4;
96
- for (var i=0, num=val.length; i < num; i++) {
97
- offset += encodeFieldValue(buffer, val[i], offset);
98
- }
99
- var size = offset - start;
100
- buffer.writeUInt32BE(size - 4, start);
101
- return size;
86
+ const start = offset;
87
+ offset += 4;
88
+ for (let i = 0, num = val.length; i < num; i++) {
89
+ offset += encodeFieldValue(buffer, val[i], offset);
90
+ }
91
+ const size = offset - start;
92
+ buffer.writeUInt32BE(size - 4, start);
93
+ return size;
102
94
  }
103
95
 
104
96
  function encodeFieldValue(buffer, value, offset) {
105
- var start = offset;
106
- var type = typeof value, val = value;
107
- // A trapdoor for specifying a type, e.g., timestamp
108
- if (value && type === 'object' && value.hasOwnProperty('!')) {
109
- val = value.value;
110
- type = value['!'];
111
- }
97
+ const start = offset;
98
+ let type = typeof value;
99
+ let val = value;
100
+ // A trapdoor for specifying a type, e.g., timestamp
101
+ if (value && type === 'object' && Object.hasOwn(value, '!')) {
102
+ val = value.value;
103
+ type = value['!'];
104
+ }
112
105
 
113
- // If it's a JS number, we'll have to guess what type to encode it
114
- // as.
115
- if (type == 'number') {
116
- // Making assumptions about the kind of number (floating point
117
- // v integer, signed, unsigned, size) desired is dangerous in
118
- // general; however, in practice RabbitMQ uses only
119
- // longstrings and unsigned integers in its arguments, and
120
- // other clients generally conflate number types anyway. So
121
- // the only distinction we care about is floating point vs
122
- // integers, preferring integers since those can be promoted
123
- // if necessary. If floating point is required, we may as well
124
- // use double precision.
125
- if (isFloatingPoint(val)) {
126
- type = 'double';
127
- }
128
- else { // only signed values are used in tables by
129
- // RabbitMQ. It *used* to (< v3.3.0) treat the byte 'b'
130
- // type as unsigned, but most clients (and the spec)
131
- // think it's signed, and now RabbitMQ does too.
132
- if (val < 128 && val >= -128) {
133
- type = 'byte';
134
- }
135
- else if (val >= -0x8000 && val < 0x8000) {
136
- type = 'short'
137
- }
138
- else if (val >= -0x80000000 && val < 0x80000000) {
139
- type = 'int';
140
- }
141
- else {
142
- type = 'long';
143
- }
144
- }
106
+ // If it's a JS number, we'll have to guess what type to encode it
107
+ // as.
108
+ if (type === 'number') {
109
+ // Making assumptions about the kind of number (floating point
110
+ // v integer, signed, unsigned, size) desired is dangerous in
111
+ // general; however, in practice RabbitMQ uses only
112
+ // longstrings and unsigned integers in its arguments, and
113
+ // other clients generally conflate number types anyway. So
114
+ // the only distinction we care about is floating point vs
115
+ // integers, preferring integers since those can be promoted
116
+ // if necessary. If floating point is required, we may as well
117
+ // use double precision.
118
+ if (isFloatingPoint(val)) {
119
+ type = 'double';
120
+ } else {
121
+ // only signed values are used in tables by
122
+ // RabbitMQ. It *used* to (< v3.3.0) treat the byte 'b'
123
+ // type as unsigned, but most clients (and the spec)
124
+ // think it's signed, and now RabbitMQ does too.
125
+ if (val < 128 && val >= -128) {
126
+ type = 'byte';
127
+ } else if (val >= -0x8000 && val < 0x8000) {
128
+ type = 'short';
129
+ } else if (val >= -0x80000000 && val < 0x80000000) {
130
+ type = 'int';
131
+ } else {
132
+ type = 'long';
133
+ }
145
134
  }
135
+ }
146
136
 
147
- function tag(t) { buffer.write(t, offset); offset++; }
137
+ function tag(t) {
138
+ buffer.write(t, offset);
139
+ offset++;
140
+ }
148
141
 
149
- switch (type) {
150
- case 'string': // no shortstr in field tables
151
- var len = Buffer.byteLength(val, 'utf8');
152
- tag('S');
153
- buffer.writeUInt32BE(len, offset); offset += 4;
154
- buffer.write(val, offset, 'utf8'); offset += len;
155
- break;
142
+ switch (type) {
143
+ case 'string': {
144
+ // no shortstr in field tables
145
+ const len = Buffer.byteLength(val, 'utf8');
146
+ tag('S');
147
+ buffer.writeUInt32BE(len, offset);
148
+ offset += 4;
149
+ buffer.write(val, offset, 'utf8');
150
+ offset += len;
151
+ break;
152
+ }
156
153
  case 'object':
157
- if (val === null) {
158
- tag('V');
159
- }
160
- else if (Array.isArray(val)) {
161
- tag('A');
162
- offset += encodeArray(buffer, val, offset);
163
- }
164
- else if (Buffer.isBuffer(val)) {
165
- tag('x');
166
- buffer.writeUInt32BE(val.length, offset); offset += 4;
167
- val.copy(buffer, offset); offset += val.length;
168
- }
169
- else {
170
- tag('F');
171
- offset += encodeTable(buffer, val, offset);
172
- }
173
- break;
154
+ if (val === null) {
155
+ tag('V');
156
+ } else if (Array.isArray(val)) {
157
+ tag('A');
158
+ offset += encodeArray(buffer, val, offset);
159
+ } else if (Buffer.isBuffer(val)) {
160
+ tag('x');
161
+ buffer.writeUInt32BE(val.length, offset);
162
+ offset += 4;
163
+ val.copy(buffer, offset);
164
+ offset += val.length;
165
+ } else {
166
+ tag('F');
167
+ offset += encodeTable(buffer, val, offset);
168
+ }
169
+ break;
174
170
  case 'boolean':
175
- tag('t');
176
- buffer.writeUInt8((val) ? 1 : 0, offset); offset++;
177
- break;
171
+ tag('t');
172
+ buffer.writeUInt8(val ? 1 : 0, offset);
173
+ offset++;
174
+ break;
178
175
  // These are the types that are either guessed above, or
179
176
  // explicitly given using the {'!': type} notation.
180
177
  case 'double':
181
178
  case 'float64':
182
- tag('d');
183
- buffer.writeDoubleBE(val, offset);
184
- offset += 8;
185
- break;
179
+ tag('d');
180
+ buffer.writeDoubleBE(val, offset);
181
+ offset += 8;
182
+ break;
186
183
  case 'byte':
187
184
  case 'int8':
188
- tag('b');
189
- buffer.writeInt8(val, offset); offset++;
190
- break;
185
+ tag('b');
186
+ buffer.writeInt8(val, offset);
187
+ offset++;
188
+ break;
191
189
  case 'unsignedbyte':
192
190
  case 'uint8':
193
- tag('B');
194
- buffer.writeUInt8(val, offset); offset++;
195
- break;
191
+ tag('B');
192
+ buffer.writeUInt8(val, offset);
193
+ offset++;
194
+ break;
196
195
  case 'short':
197
196
  case 'int16':
198
- tag('s');
199
- buffer.writeInt16BE(val, offset); offset += 2;
200
- break;
197
+ tag('s');
198
+ buffer.writeInt16BE(val, offset);
199
+ offset += 2;
200
+ break;
201
201
  case 'unsignedshort':
202
202
  case 'uint16':
203
- tag('u');
204
- buffer.writeUInt16BE(val, offset); offset += 2;
205
- break;
203
+ tag('u');
204
+ buffer.writeUInt16BE(val, offset);
205
+ offset += 2;
206
+ break;
206
207
  case 'int':
207
208
  case 'int32':
208
- tag('I');
209
- buffer.writeInt32BE(val, offset); offset += 4;
210
- break;
209
+ tag('I');
210
+ buffer.writeInt32BE(val, offset);
211
+ offset += 4;
212
+ break;
211
213
  case 'unsignedint':
212
214
  case 'uint32':
213
- tag('i');
214
- buffer.writeUInt32BE(val, offset); offset += 4;
215
- break;
215
+ tag('i');
216
+ buffer.writeUInt32BE(val, offset);
217
+ offset += 4;
218
+ break;
216
219
  case 'long':
217
220
  case 'int64':
218
- tag('l');
219
- ints.writeInt64BE(buffer, val, offset); offset += 8;
220
- break;
221
+ tag('l');
222
+ ints.writeInt64BE(buffer, val, offset);
223
+ offset += 8;
224
+ break;
221
225
 
222
226
  // Now for exotic types, those can _only_ be denoted by using
223
227
  // `{'!': type, value: val}
224
228
  case 'timestamp':
225
- tag('T');
226
- ints.writeUInt64BE(buffer, val, offset); offset += 8;
227
- break;
229
+ tag('T');
230
+ ints.writeUInt64BE(buffer, val, offset);
231
+ offset += 8;
232
+ break;
228
233
  case 'float':
229
- tag('f');
230
- buffer.writeFloatBE(val, offset); offset += 4;
231
- break;
234
+ tag('f');
235
+ buffer.writeFloatBE(val, offset);
236
+ offset += 4;
237
+ break;
232
238
  case 'decimal':
233
- tag('D');
234
- if (val.hasOwnProperty('places') && val.hasOwnProperty('digits')
235
- && val.places >= 0 && val.places < 256) {
236
- buffer[offset] = val.places; offset++;
237
- buffer.writeUInt32BE(val.digits, offset); offset += 4;
238
- }
239
- else throw new TypeError(
240
- "Decimal value must be {'places': 0..255, 'digits': uint32}, " +
241
- "got " + JSON.stringify(val));
242
- break;
239
+ tag('D');
240
+ if (Object.hasOwn(val, 'places') && Object.hasOwn(val, 'digits') && val.places >= 0 && val.places < 256) {
241
+ buffer[offset] = val.places;
242
+ offset++;
243
+ buffer.writeUInt32BE(val.digits, offset);
244
+ offset += 4;
245
+ } else throw new TypeError(`Decimal value must be {'places': 0..255, 'digits': uint32}, got ${JSON.stringify(val)}`);
246
+ break;
243
247
  default:
244
- throw new TypeError('Unknown type to encode: ' + type);
245
- }
246
- return offset - start;
248
+ throw new TypeError(`Unknown type to encode: ${type}`);
249
+ }
250
+ return offset - start;
247
251
  }
248
252
 
249
253
  // Assume we're given a slice of the buffer that contains just the
250
254
  // fields.
251
255
  function decodeFields(slice) {
252
- var fields = {}, offset = 0, size = slice.length;
253
- var len, key, val;
256
+ const fields = {};
257
+ let offset = 0;
258
+ const size = slice.length;
259
+ let len;
260
+ let key;
261
+ let val;
254
262
 
255
- function decodeFieldValue() {
256
- var tag = String.fromCharCode(slice[offset]); offset++;
257
- switch (tag) {
258
- case 'b':
259
- val = slice.readInt8(offset); offset++;
260
- break;
261
- case 'B':
262
- val = slice.readUInt8(offset); offset++;
263
- break;
264
- case 'S':
265
- len = slice.readUInt32BE(offset); offset += 4;
266
- val = slice.toString('utf8', offset, offset + len);
267
- offset += len;
268
- break;
269
- case 'I':
270
- val = slice.readInt32BE(offset); offset += 4;
271
- break;
272
- case 'i':
273
- val = slice.readUInt32BE(offset); offset += 4;
274
- break;
275
- case 'D': // only positive decimals, apparently.
276
- var places = slice[offset]; offset++;
277
- var digits = slice.readUInt32BE(offset); offset += 4;
278
- val = {'!': 'decimal', value: {places: places, digits: digits}};
279
- break;
280
- case 'T':
281
- val = ints.readUInt64BE(slice, offset); offset += 8;
282
- val = {'!': 'timestamp', value: val};
283
- break;
284
- case 'F':
285
- len = slice.readUInt32BE(offset); offset += 4;
286
- val = decodeFields(slice.subarray(offset, offset + len));
287
- offset += len;
288
- break;
289
- case 'A':
290
- len = slice.readUInt32BE(offset); offset += 4;
291
- decodeArray(offset + len);
292
- // NB decodeArray will itself update offset and val
293
- break;
294
- case 'd':
295
- val = slice.readDoubleBE(offset); offset += 8;
296
- break;
297
- case 'f':
298
- val = slice.readFloatBE(offset); offset += 4;
299
- break;
300
- case 'l':
301
- val = ints.readInt64BE(slice, offset); offset += 8;
302
- break;
303
- case 's':
304
- val = slice.readInt16BE(offset); offset += 2;
305
- break;
306
- case 'u':
307
- val = slice.readUInt16BE(offset); offset += 2;
308
- break;
309
- case 't':
310
- val = slice[offset] != 0; offset++;
311
- break;
312
- case 'V':
313
- val = null;
314
- break;
315
- case 'x':
316
- len = slice.readUInt32BE(offset); offset += 4;
317
- val = slice.subarray(offset, offset + len);
318
- offset += len;
319
- break;
320
- default:
321
- throw new TypeError('Unexpected type tag "' + tag +'"');
322
- }
263
+ function decodeFieldValue() {
264
+ const tag = String.fromCharCode(slice[offset]);
265
+ offset++;
266
+ switch (tag) {
267
+ case 'b':
268
+ val = slice.readInt8(offset);
269
+ offset++;
270
+ break;
271
+ case 'B':
272
+ val = slice.readUInt8(offset);
273
+ offset++;
274
+ break;
275
+ case 'S':
276
+ len = slice.readUInt32BE(offset);
277
+ offset += 4;
278
+ val = slice.toString('utf8', offset, offset + len);
279
+ offset += len;
280
+ break;
281
+ case 'I':
282
+ val = slice.readInt32BE(offset);
283
+ offset += 4;
284
+ break;
285
+ case 'i':
286
+ val = slice.readUInt32BE(offset);
287
+ offset += 4;
288
+ break;
289
+ case 'D': {
290
+ // only positive decimals, apparently.
291
+ const places = slice[offset];
292
+ offset++;
293
+ const digits = slice.readUInt32BE(offset);
294
+ offset += 4;
295
+ val = { '!': 'decimal', value: { places: places, digits: digits } };
296
+ break;
297
+ }
298
+ case 'T':
299
+ val = ints.readUInt64BE(slice, offset);
300
+ offset += 8;
301
+ val = { '!': 'timestamp', value: val };
302
+ break;
303
+ case 'F':
304
+ len = slice.readUInt32BE(offset);
305
+ offset += 4;
306
+ val = decodeFields(slice.subarray(offset, offset + len));
307
+ offset += len;
308
+ break;
309
+ case 'A':
310
+ len = slice.readUInt32BE(offset);
311
+ offset += 4;
312
+ decodeArray(offset + len);
313
+ // NB decodeArray will itself update offset and val
314
+ break;
315
+ case 'd':
316
+ val = slice.readDoubleBE(offset);
317
+ offset += 8;
318
+ break;
319
+ case 'f':
320
+ val = slice.readFloatBE(offset);
321
+ offset += 4;
322
+ break;
323
+ case 'l':
324
+ val = ints.readInt64BE(slice, offset);
325
+ offset += 8;
326
+ break;
327
+ case 's':
328
+ val = slice.readInt16BE(offset);
329
+ offset += 2;
330
+ break;
331
+ case 'u':
332
+ val = slice.readUInt16BE(offset);
333
+ offset += 2;
334
+ break;
335
+ case 't':
336
+ val = slice[offset] !== 0;
337
+ offset++;
338
+ break;
339
+ case 'V':
340
+ val = null;
341
+ break;
342
+ case 'x':
343
+ len = slice.readUInt32BE(offset);
344
+ offset += 4;
345
+ val = slice.subarray(offset, offset + len);
346
+ offset += len;
347
+ break;
348
+ default:
349
+ throw new TypeError(`Unexpected type tag "${tag}"`);
323
350
  }
351
+ }
324
352
 
325
- function decodeArray(until) {
326
- var vals = [];
327
- while (offset < until) {
328
- decodeFieldValue();
329
- vals.push(val);
330
- }
331
- val = vals;
353
+ function decodeArray(until) {
354
+ const vals = [];
355
+ while (offset < until) {
356
+ decodeFieldValue();
357
+ vals.push(val);
332
358
  }
359
+ val = vals;
360
+ }
333
361
 
334
- while (offset < size) {
335
- len = slice.readUInt8(offset); offset++;
336
- key = slice.toString('utf8', offset, offset + len);
337
- offset += len;
338
- decodeFieldValue();
339
- fields[key] = val;
340
- }
341
- return fields;
362
+ while (offset < size) {
363
+ len = slice.readUInt8(offset);
364
+ offset++;
365
+ key = slice.toString('utf8', offset, offset + len);
366
+ offset += len;
367
+ decodeFieldValue();
368
+ fields[key] = val;
369
+ }
370
+ return fields;
342
371
  }
343
372
 
344
373
  module.exports.encodeTable = encodeTable;