node-firebird 2.3.3 → 2.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 (109) hide show
  1. package/README.md +544 -6
  2. package/lib/callback.d.ts +20 -0
  3. package/lib/callback.js +6 -16
  4. package/lib/firebird.msg.json +1370 -1370
  5. package/lib/gdscodes.d.ts +1519 -1520
  6. package/lib/gdscodes.js +5 -5
  7. package/lib/ieee754-decimal.d.ts +38 -0
  8. package/lib/ieee754-decimal.js +71 -118
  9. package/lib/index.d.ts +37 -338
  10. package/lib/index.js +97 -86
  11. package/lib/messages.d.ts +6 -0
  12. package/lib/messages.js +135 -162
  13. package/lib/pool.d.ts +23 -0
  14. package/lib/pool.js +34 -47
  15. package/lib/srp.d.ts +51 -0
  16. package/lib/srp.js +62 -72
  17. package/lib/types.d.ts +375 -0
  18. package/lib/types.js +22 -0
  19. package/lib/unix-crypt.d.ts +1 -0
  20. package/lib/unix-crypt.js +126 -152
  21. package/lib/utils.d.ts +16 -0
  22. package/lib/utils.js +24 -48
  23. package/lib/wire/connection.d.ts +100 -0
  24. package/lib/wire/connection.js +1029 -1009
  25. package/lib/wire/const.d.ts +567 -0
  26. package/lib/wire/const.js +620 -599
  27. package/lib/wire/database.d.ts +57 -0
  28. package/lib/wire/database.js +111 -108
  29. package/lib/wire/eventConnection.d.ts +16 -0
  30. package/lib/wire/eventConnection.js +29 -31
  31. package/lib/wire/fbEventManager.d.ts +45 -0
  32. package/lib/wire/fbEventManager.js +38 -57
  33. package/lib/wire/serialize.d.ts +97 -0
  34. package/lib/wire/serialize.js +42 -141
  35. package/lib/wire/service.d.ts +66 -0
  36. package/lib/wire/service.js +374 -401
  37. package/lib/wire/socket.d.ts +59 -0
  38. package/lib/wire/socket.js +79 -40
  39. package/lib/wire/statement.d.ts +25 -0
  40. package/lib/wire/statement.js +13 -9
  41. package/lib/wire/transaction.d.ts +21 -0
  42. package/lib/wire/transaction.js +33 -61
  43. package/lib/wire/xsqlvar.d.ts +175 -0
  44. package/lib/wire/xsqlvar.js +169 -269
  45. package/package.json +12 -4
  46. package/src/callback.ts +55 -0
  47. package/{poc/node_modules/node-firebird/lib/gdscodes.js → src/gdscodes.ts} +3 -3
  48. package/{poc/node_modules/node-firebird/lib/ieee754-decimal.js → src/ieee754-decimal.ts} +7 -14
  49. package/src/index.ts +157 -0
  50. package/{poc/node_modules/node-firebird/lib/messages.js → src/messages.ts} +163 -162
  51. package/src/pool.ts +209 -0
  52. package/{poc/node_modules/node-firebird/lib/srp.js → src/srp.ts} +74 -33
  53. package/src/types.ts +419 -0
  54. package/{poc/node_modules/node-firebird/lib/unix-crypt.js → src/unix-crypt.ts} +6 -12
  55. package/{poc/node_modules/node-firebird/lib/utils.js → src/utils.ts} +11 -20
  56. package/{poc/node_modules/node-firebird/lib/wire/connection.js → src/wire/connection.ts} +611 -129
  57. package/{poc/node_modules/node-firebird/lib/wire/const.js → src/wire/const.ts} +96 -9
  58. package/{poc/node_modules/node-firebird/lib/wire/database.js → src/wire/database.ts} +110 -44
  59. package/{poc/node_modules/node-firebird/lib/wire/eventConnection.js → src/wire/eventConnection.ts} +29 -14
  60. package/{poc/node_modules/node-firebird/lib/wire/fbEventManager.js → src/wire/fbEventManager.ts} +39 -30
  61. package/{poc/node_modules/node-firebird/lib/wire/serialize.js → src/wire/serialize.ts} +78 -59
  62. package/{poc/node_modules/node-firebird/lib/wire/service.js → src/wire/service.ts} +90 -88
  63. package/src/wire/socket.ts +262 -0
  64. package/src/wire/statement.ts +71 -0
  65. package/{poc/node_modules/node-firebird/lib/wire/transaction.js → src/wire/transaction.ts} +25 -19
  66. package/{poc/node_modules/node-firebird/lib/wire/xsqlvar.js → src/wire/xsqlvar.ts} +244 -143
  67. package/.eslintrc.json +0 -12
  68. package/.github/workflows/codeql.yml +0 -76
  69. package/.github/workflows/node.js.yml +0 -95
  70. package/BIGINT_MIGRATION.md +0 -374
  71. package/CI_DEBUGGING_GUIDE.md +0 -148
  72. package/ENCRYPTION_CALLBACK.md +0 -152
  73. package/FIREBIRD_LOG_FEATURE.md +0 -145
  74. package/MINIMAL_CHANGES_SUMMARY.md +0 -136
  75. package/PR_SUMMARY.md +0 -96
  76. package/ROADMAP.md +0 -223
  77. package/SRP_PROTOCOL.md +0 -482
  78. package/poc/README.md +0 -160
  79. package/poc/helpers.js +0 -59
  80. package/poc/node_modules/.package-lock.json +0 -14
  81. package/poc/node_modules/node-firebird/.eslintrc.json +0 -12
  82. package/poc/node_modules/node-firebird/.github/workflows/codeql.yml +0 -76
  83. package/poc/node_modules/node-firebird/.github/workflows/node.js.yml +0 -95
  84. package/poc/node_modules/node-firebird/BIGINT_MIGRATION.md +0 -374
  85. package/poc/node_modules/node-firebird/CI_DEBUGGING_GUIDE.md +0 -148
  86. package/poc/node_modules/node-firebird/ENCRYPTION_CALLBACK.md +0 -152
  87. package/poc/node_modules/node-firebird/FIREBIRD_LOG_FEATURE.md +0 -145
  88. package/poc/node_modules/node-firebird/LICENSE +0 -373
  89. package/poc/node_modules/node-firebird/MINIMAL_CHANGES_SUMMARY.md +0 -136
  90. package/poc/node_modules/node-firebird/PR_SUMMARY.md +0 -96
  91. package/poc/node_modules/node-firebird/README.md +0 -794
  92. package/poc/node_modules/node-firebird/ROADMAP.md +0 -223
  93. package/poc/node_modules/node-firebird/SRP_PROTOCOL.md +0 -482
  94. package/poc/node_modules/node-firebird/lib/callback.js +0 -38
  95. package/poc/node_modules/node-firebird/lib/gdscodes.d.ts +0 -1524
  96. package/poc/node_modules/node-firebird/lib/index.d.ts +0 -316
  97. package/poc/node_modules/node-firebird/lib/index.js +0 -128
  98. package/poc/node_modules/node-firebird/lib/pool.js +0 -108
  99. package/poc/node_modules/node-firebird/lib/wire/socket.js +0 -175
  100. package/poc/node_modules/node-firebird/lib/wire/statement.js +0 -48
  101. package/poc/node_modules/node-firebird/package.json +0 -38
  102. package/poc/node_modules/node-firebird/vitest.config.js +0 -24
  103. package/poc/package-lock.json +0 -21
  104. package/poc/package.json +0 -12
  105. package/poc/reproduce-fixed.js +0 -150
  106. package/poc/reproduce.js +0 -133
  107. package/vitest.config.js +0 -27
  108. /package/{poc/node_modules/node-firebird/lib → src}/firebird.msg +0 -0
  109. /package/{poc/node_modules/node-firebird/lib → src}/firebird.msg.json +0 -0
@@ -0,0 +1,45 @@
1
+ import Events from 'events';
2
+ declare class FbEventManager extends Events.EventEmitter {
3
+ db: any;
4
+ eventconnection: any;
5
+ events: Record<string, number>;
6
+ eventid: number;
7
+ _subscriptionVersion: number;
8
+ _hasActiveSubscription: boolean;
9
+ constructor(db: any, eventconnection: any, eventid: number, callback: (err: any, ret?: any) => void);
10
+ /**
11
+ * Returns a snapshot of the current state for debugging.
12
+ * Useful for tracing the state machine during development.
13
+ *
14
+ * Stable states: 'IDLE', 'SUBSCRIBED', 'CLOSED'.
15
+ * Transient states (SUBSCRIBING, CANCELLING, CLOSING) occur while waiting
16
+ * for op_response on the main connection or for the socket to close; they
17
+ * are not tracked with dedicated flags to keep the implementation simple,
18
+ * but they can be inferred: if the socket is open and _hasActiveSubscription
19
+ * disagrees with what the caller expects, a transitional operation is in
20
+ * progress.
21
+ *
22
+ * @returns {{
23
+ * state: string,
24
+ * hasActiveSubscription: boolean,
25
+ * registeredEvents: Object,
26
+ * eventId: number,
27
+ * isEventConnectionOpen: boolean,
28
+ * isDatabaseConnectionClosed: boolean
29
+ * }}
30
+ */
31
+ getState(): {
32
+ state: string;
33
+ hasActiveSubscription: boolean;
34
+ registeredEvents: Record<string, number>;
35
+ eventId: number;
36
+ isEventConnectionOpen: boolean;
37
+ isDatabaseConnectionClosed: boolean;
38
+ };
39
+ _createEventLoop(callback: (err: any, ret?: any) => void): void;
40
+ _changeEvent(callback: (err: any, ret?: any) => void): void;
41
+ registerEvent(events: string[], callback: (err: any, ret?: any) => void): any;
42
+ unregisterEvent(events: string[], callback: (err: any, ret?: any) => void): any;
43
+ close(callback?: (err?: any) => void): void;
44
+ }
45
+ export = FbEventManager;
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  // FbEventManager – Firebird POST_EVENT subscription manager
2
3
  //
3
4
  // State machine overview
@@ -63,24 +64,27 @@
63
64
  // Asynchronous notifications on the AUX (EventConnection) socket
64
65
  // ───────────────────────────────────────────────────────────────
65
66
  // Server → Client : op_event (fired by Firebird POST_EVENT trigger)
66
-
67
- const Events = require('events');
68
- const { doError } = require('../callback');
69
-
70
- class FbEventManager extends Events.EventEmitter {
67
+ var __importDefault = (this && this.__importDefault) || function (mod) {
68
+ return (mod && mod.__esModule) ? mod : { "default": mod };
69
+ };
70
+ const events_1 = __importDefault(require("events"));
71
+ const callback_1 = require("../callback");
72
+ class FbEventManager extends events_1.default.EventEmitter {
71
73
  constructor(db, eventconnection, eventid, callback) {
72
74
  super();
73
75
  this.db = db;
74
76
  this.eventconnection = eventconnection;
75
77
  this.events = {};
76
78
  this.eventid = eventid;
79
+ // Guards _hasActiveSubscription against late callbacks from an older
80
+ // register/unregister cycle after a newer subscription change started.
81
+ this._subscriptionVersion = 0;
77
82
  // True when an op_que_events subscription is currently active on the
78
83
  // main connection (so close() and _changeEvent know whether to send
79
84
  // op_cancel_events before tearing down or re-subscribing).
80
85
  this._hasActiveSubscription = false;
81
86
  this._createEventLoop(callback);
82
87
  }
83
-
84
88
  /**
85
89
  * Returns a snapshot of the current state for debugging.
86
90
  * Useful for tracing the state machine during development.
@@ -109,7 +113,6 @@ class FbEventManager extends Events.EventEmitter {
109
113
  const dbConnClosed = this.db.connection
110
114
  ? this.db.connection._isClosed
111
115
  : true;
112
-
113
116
  // Derive a human-readable stable-state label.
114
117
  // Transitional states (SUBSCRIBING / CANCELLING / CLOSING) are not
115
118
  // individually flagged; callers that need finer granularity can
@@ -117,12 +120,13 @@ class FbEventManager extends Events.EventEmitter {
117
120
  let state;
118
121
  if (dbConnClosed || !evtConnOpen) {
119
122
  state = 'CLOSED';
120
- } else if (this._hasActiveSubscription) {
123
+ }
124
+ else if (this._hasActiveSubscription) {
121
125
  state = 'SUBSCRIBED';
122
- } else {
126
+ }
127
+ else {
123
128
  state = 'IDLE';
124
129
  }
125
-
126
130
  return {
127
131
  state,
128
132
  hasActiveSubscription: this._hasActiveSubscription,
@@ -132,16 +136,13 @@ class FbEventManager extends Events.EventEmitter {
132
136
  isDatabaseConnectionClosed: dbConnClosed,
133
137
  };
134
138
  }
135
-
136
139
  _createEventLoop(callback) {
137
140
  var self = this;
138
141
  var cnx = this.db.connection;
139
142
  this.eventconnection.emgr = this;
140
-
141
143
  if (process.env.FIREBIRD_DEBUG) {
142
144
  console.log('[fb-debug] FbEventManager._createEventLoop: eventid=%d', self.eventid);
143
145
  }
144
-
145
146
  // Re-subscribe after each op_event notification so that further
146
147
  // trigger fires continue to be delivered.
147
148
  function loop() {
@@ -156,42 +157,31 @@ class FbEventManager extends Events.EventEmitter {
156
157
  }
157
158
  cnx.queEvents(self.events, self.eventid, function (err) {
158
159
  if (err) {
159
- doError(err, callback);
160
+ (0, callback_1.doError)(err, callback);
160
161
  return;
161
162
  }
162
163
  // subscription renewed, nothing else to do
163
164
  });
164
165
  }
165
-
166
166
  this.eventconnection.eventcallback = function (err, ret) {
167
167
  if (err || (self.eventid !== ret.eventid)) {
168
- doError(err || new Error('Bad eventid'), callback);
168
+ (0, callback_1.doError)(err || new Error('Bad eventid'), callback);
169
169
  return;
170
170
  }
171
-
172
171
  ret.events.forEach(function (event) {
173
172
  self.emit('post_event', event.name, event.count);
174
173
  });
175
-
176
174
  loop();
177
175
  };
178
-
179
176
  // Resolve attachEvent on the next tick – no subscription is needed
180
177
  // until the caller registers at least one event name via registerEvent().
181
178
  // process.nextTick ensures the outer `const evt = new FbEventManager(...)`
182
179
  // assignment in database.js completes before this callback fires.
183
- process.nextTick(function() { callback(null); });
180
+ process.nextTick(function () { callback(null); });
184
181
  }
185
-
186
182
  _changeEvent(callback) {
187
183
  var self = this;
188
-
189
- // Temporarily suppress the event loop to prevent stale op_event
190
- // notifications from pushing spurious queEvents onto the main
191
- // connection queue while we're reconfiguring the subscription.
192
- var savedCallback = self.eventconnection.eventcallback;
193
- self.eventconnection.eventcallback = null;
194
-
184
+ const changeVersion = ++self._subscriptionVersion;
195
185
  function subscribe() {
196
186
  // If no events remain, mark subscription as inactive and return.
197
187
  // Sending queEvents with an empty EPB after op_cancel_events does
@@ -199,71 +189,64 @@ class FbEventManager extends Events.EventEmitter {
199
189
  // permanently block the main connection queue.
200
190
  if (Object.keys(self.events).length === 0) {
201
191
  self._hasActiveSubscription = false;
202
- self.eventconnection.eventcallback = savedCallback;
203
192
  callback(null);
204
193
  return;
205
194
  }
206
-
195
+ // Firebird can deliver the initial op_event baseline before the
196
+ // matching op_response reaches the main connection. Mark the
197
+ // subscription active before sending queEvents so that this early
198
+ // op_event can re-queue the next one-shot request.
199
+ self._hasActiveSubscription = true;
207
200
  self.db.connection.queEvents(self.events, self.eventid, function (err, ret) {
208
- self.eventconnection.eventcallback = savedCallback;
209
201
  if (err) {
210
- doError(err, callback);
202
+ if (self._subscriptionVersion === changeVersion) {
203
+ self._hasActiveSubscription = false;
204
+ }
205
+ (0, callback_1.doError)(err, callback);
211
206
  return;
212
207
  }
213
- self._hasActiveSubscription = true;
214
208
  callback(null, ret);
215
209
  });
216
210
  }
217
-
218
211
  if (self._hasActiveSubscription) {
219
212
  // Cancel the current subscription before setting up a new one.
220
213
  self.db.connection.closeEvents(this.eventid, function (err) {
221
214
  if (err) {
222
- self.eventconnection.eventcallback = savedCallback;
223
- doError(err, callback);
215
+ (0, callback_1.doError)(err, callback);
224
216
  return;
225
217
  }
226
218
  self._hasActiveSubscription = false;
227
219
  subscribe();
228
220
  });
229
- } else {
221
+ }
222
+ else {
230
223
  // No active subscription yet (first registerEvent call, or after
231
224
  // all events were unregistered) – go straight to subscribing.
232
225
  subscribe();
233
226
  }
234
227
  }
235
-
236
228
  registerEvent(events, callback) {
237
229
  var self = this;
238
-
239
230
  if (self.db.connection._isClosed || self.eventconnection._isClosed)
240
231
  return self.eventconnection.throwClosed(callback);
241
-
242
232
  events.forEach((event) => self.events[event] = self.events[event] || 0);
243
233
  self._changeEvent(callback);
244
234
  }
245
-
246
235
  unregisterEvent(events, callback) {
247
236
  var self = this;
248
-
249
237
  if (self.db.connection._isClosed || self.eventconnection._isClosed)
250
238
  return self.eventconnection.throwClosed(callback);
251
-
252
- events.forEach(function (event) { delete self.events[event] });
239
+ events.forEach(function (event) { delete self.events[event]; });
253
240
  self._changeEvent(callback);
254
241
  }
255
-
256
242
  close(callback) {
257
243
  var self = this;
258
-
259
244
  if (process.env.FIREBIRD_DEBUG) {
260
245
  console.log('[fb-debug] FbEventManager.close() called, _hasActiveSubscription=%s eventid=%d', self._hasActiveSubscription, self.eventid);
261
246
  }
262
-
263
247
  // Prevent the event loop from re-queuing on stale op_event notifications
264
248
  // that may arrive between closeEvents and socket.end()
265
249
  self.eventconnection.eventcallback = null;
266
-
267
250
  // Gracefully close the event socket using a FIN (end()) rather than a RST
268
251
  // (destroy()), then wait for the 'close' event which confirms both sides have
269
252
  // exchanged FINs. This gives Firebird (all versions 3/4/5) time to fully
@@ -279,7 +262,8 @@ class FbEventManager extends Events.EventEmitter {
279
262
  if (process.env.FIREBIRD_DEBUG) {
280
263
  console.log('[fb-debug] endAndWaitForClose: socket already destroyed, calling back immediately');
281
264
  }
282
- if (cb) cb();
265
+ if (cb)
266
+ cb();
283
267
  return;
284
268
  }
285
269
  var fired = false;
@@ -291,36 +275,33 @@ class FbEventManager extends Events.EventEmitter {
291
275
  if (process.env.FIREBIRD_DEBUG) {
292
276
  console.log('[fb-debug] endAndWaitForClose done() via %s, eventid=%d', source, self.eventid);
293
277
  }
294
- if (cb) cb();
278
+ if (cb)
279
+ cb();
295
280
  }
296
281
  }
297
- sock.once('close', function() { done('close-event'); });
282
+ sock.once('close', function () { done('close-event'); });
298
283
  if (process.env.FIREBIRD_DEBUG) {
299
284
  console.log('[fb-debug] endAndWaitForClose: calling sock.end(), eventid=%d sock.destroyed=%s', self.eventid, sock.destroyed);
300
285
  }
301
286
  sock.end();
302
287
  // Safety fallback: if Firebird never sends its FIN (e.g. an error
303
288
  // occurs on the server side), resolve after 200 ms so tests don't hang.
304
- timer = setTimeout(function() { done('200ms-timer'); }, 200);
289
+ timer = setTimeout(function () { done('200ms-timer'); }, 200);
305
290
  }
306
-
307
291
  if (!self._hasActiveSubscription) {
308
292
  // No active subscription (attachEvent without registerEvent, or
309
293
  // all events were unregistered) – nothing to cancel.
310
294
  endAndWaitForClose(callback);
311
295
  return;
312
296
  }
313
-
314
297
  self.db.connection.closeEvents(this.eventid, function (err) {
315
298
  if (err) {
316
- doError(err, callback);
299
+ (0, callback_1.doError)(err, callback);
317
300
  return;
318
301
  }
319
-
320
302
  self._hasActiveSubscription = false;
321
303
  endAndWaitForClose(callback);
322
304
  });
323
305
  }
324
306
  }
325
-
326
307
  module.exports = FbEventManager;
@@ -0,0 +1,97 @@
1
+ export declare class BlrWriter {
2
+ buffer: Buffer;
3
+ pos: number;
4
+ constructor(size?: number);
5
+ ensure(len: number): void;
6
+ addByte(b: number): void;
7
+ addShort(b: number): void;
8
+ addSmall(b: number): void;
9
+ addWord(b: number): void;
10
+ addInt32(b: number): void;
11
+ addByteInt32(c: number, b: number): void;
12
+ addNumeric(c: number, v: number): void;
13
+ addBytes(b: number[] | Buffer): void;
14
+ addString(c: number, s: string, encoding: BufferEncoding): void;
15
+ addBuffer(b: Buffer): void;
16
+ addString2(c: number, s: string, encoding: BufferEncoding): void;
17
+ addMultiblockPart(c: number, s: string, encoding: BufferEncoding): void;
18
+ }
19
+ /***************************************
20
+ *
21
+ * BLR Reader
22
+ *
23
+ ***************************************/
24
+ export declare class BlrReader {
25
+ buffer: Buffer;
26
+ pos: number;
27
+ constructor(buffer: Buffer);
28
+ readByteCode(): number;
29
+ readInt32(): number;
30
+ readInt(): any;
31
+ readString(encoding?: BufferEncoding): string;
32
+ readSegment(): Buffer;
33
+ }
34
+ /***************************************
35
+ *
36
+ * XDR Writer
37
+ *
38
+ ***************************************/
39
+ export declare class XdrWriter {
40
+ buffer: Buffer;
41
+ pos: number;
42
+ constructor(size?: number);
43
+ ensure(len: number): void;
44
+ addInt(value: number): void;
45
+ addInt64(value: number): void;
46
+ addInt128(value: number | bigint | string): void;
47
+ addDecFloat16(value: number | string | bigint): void;
48
+ addDecFloat34(value: number | string | bigint): void;
49
+ addUInt(value: number): void;
50
+ addString(s: string, encoding: BufferEncoding): void;
51
+ addText(s: string, encoding: BufferEncoding): void;
52
+ addParamBuffer(b: Buffer): void;
53
+ addBlr(blr: BlrWriter): void;
54
+ getData(): Buffer;
55
+ addDouble(value: number): void;
56
+ addQuad(quad: {
57
+ low: number;
58
+ high: number;
59
+ }): void;
60
+ addBuffer(buffer: Buffer): void;
61
+ addAlignment(len: number): void;
62
+ }
63
+ /***************************************
64
+ *
65
+ * XDR Reader
66
+ *
67
+ ***************************************/
68
+ export declare class XdrReader {
69
+ buffer: Buffer;
70
+ pos: number;
71
+ constructor(buffer: Buffer);
72
+ readInt(): number;
73
+ readUInt(): number;
74
+ readInt64(): number;
75
+ readInt128(): bigint;
76
+ readDecFloat16(): string | number;
77
+ readDecFloat34(): string | number;
78
+ readShort(): number;
79
+ readQuad(): {
80
+ low: number;
81
+ high: number;
82
+ };
83
+ readFloat(): number;
84
+ readDouble(): number;
85
+ readArray(): Buffer<ArrayBuffer>;
86
+ readBuffer(len?: number, toAlign?: boolean): Buffer | undefined;
87
+ readString(encoding: BufferEncoding): string;
88
+ readText(len: number, encoding: BufferEncoding): string;
89
+ }
90
+ export declare class BitSet {
91
+ data: number[];
92
+ constructor(buffer?: Buffer);
93
+ scale(index: number): void;
94
+ set(index: number, value?: boolean | number): void;
95
+ get(index: number): number;
96
+ toBuffer(): Buffer;
97
+ }