@aws/aurora-dsql-postgresjs-connector 0.1.3 → 0.2.1

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.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Aurora DSQL Connector for Postgres.js
2
2
 
3
- [![GitHub](https://img.shields.io/badge/github-awslabs/aurora--dsql--postgres--js--connector-blue?logo=github)](https://github.com/awslabs/aurora-dsql-nodejs-connector/tree/main/packages/postgres-js)
4
- [![License](https://img.shields.io/badge/license-Apache--2.0-brightgreen)](https://github.com/awslabs/aurora-dsql-nodejs-connector/blob/main/LICENSE)
3
+ [![GitHub](https://img.shields.io/badge/github-awslabs/aurora--dsql--connectors-blue?logo=github)](https://github.com/awslabs/aurora-dsql-connectors/tree/main/node/postgres-js)
4
+ [![License](https://img.shields.io/badge/license-Apache--2.0-brightgreen)](https://github.com/awslabs/aurora-dsql-connectors/blob/main/LICENSE)
5
5
  [![NPM Version](https://img.shields.io/npm/v/@aws/aurora-dsql-postgresjs-connector)](https://www.npmjs.com/package/@aws/aurora-dsql-postgresjs-connector)
6
6
  [![Discord chat](https://img.shields.io/discord/1435027294837276802.svg?logo=discord)](https://discord.com/invite/nEF6ksFWru)
7
7
 
@@ -52,6 +52,15 @@ The Aurora DSQL Connector for Postgres.js is designed to understand these requir
52
52
  - Set up appropriate IAM permissions to allow your application to connect to Aurora DSQL.
53
53
  - AWS credentials configured (via AWS CLI, environment variables, or IAM roles)
54
54
 
55
+ ## ⚠️ Important
56
+
57
+ * Running this code might result in charges to your AWS account.
58
+ * We recommend that you grant your code least privilege. At most, grant only the
59
+ minimum permissions required to perform the task. For more information, see
60
+ [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege).
61
+ * This code is not tested in every AWS Region. For more information, see
62
+ [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services).
63
+
55
64
  ### Installation
56
65
 
57
66
  ```bash
@@ -118,7 +127,7 @@ const sql = AuroraDSQLPostgres({
118
127
  });
119
128
  ```
120
129
 
121
- ## Configuration Options
130
+ ### Configuration Options
122
131
 
123
132
  | Option | Type | Required | Description |
124
133
  |-----------------------------|----------------------------------|----------|----------------------------------------------------------|
@@ -131,6 +140,76 @@ const sql = AuroraDSQLPostgres({
131
140
 
132
141
  All standard [Postgres.js options](https://github.com/porsager/postgres?tab=readme-ov-file#connection-details) are also supported.
133
142
 
143
+ ## Websocket Connector
144
+ The websocket connector provides an alternative connection method to Aurora DSQL using WebSockets instead of standard TCP sockets. This is designed for environments where TCP sockets are unavailable. For Node.js server applications, use the standard TCP socket connector shown above.
145
+
146
+ ### Use Case - Environments Without TCP Sockets
147
+
148
+ Some JavaScript runtimes don't provide TCP socket support. The WebSocket connector enables DSQL connections from these environments. If credentials remain server-controlled, the security model is similar to traditional server-side applications and credentials can be configured using your platform's secrets management (e.g., environment variables, secrets store).
149
+
150
+ ### Use Case - Browser Applications
151
+
152
+ Web browsers don't support TCP sockets. The WebSocket connector enables direct browser-to-database connections for use cases like internal tools, prototypes, or applications where users can safely have direct database access.
153
+
154
+ #### ⚠️ Security Considerations for Browser Usage
155
+
156
+ When using the WebSocket connector from a browser, the database connection runs in an environment controlled by the end user. This has important security implications:
157
+
158
+ - **Users can execute any query their database role permits.** There is no server-side layer to validate, filter, or restrict queries. The browser's JavaScript can be inspected and modified.
159
+
160
+ - **Database role permissions are your access control boundary.** The IAM role grants connection ability, but the PostgreSQL database role determines what data the user can access. Configure database roles with minimal necessary permissions.
161
+
162
+ This approach is appropriate when users should have direct database access such as internal admin tools, single-user applications, or scenarios with properly scoped database roles. It is not a substitute for a backend API when you need to control what queries users can run.
163
+
164
+ For guidance on configuring IAM roles and database permissions, see:
165
+ - [Authentication and authorization for Aurora DSQL](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/authentication-authorization.html)
166
+ - [Using database roles and IAM authentication](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/using-database-and-iam-roles.html)
167
+
168
+ ### Basic Usage
169
+
170
+ ```typescript
171
+ import type { AwsCredentialIdentity } from '@aws-sdk/types';
172
+ import { auroraDSQLWsPostgres, AuroraDSQLWsConfig } from '@aws/aurora-dsql-postgresjs-connector';
173
+
174
+ // For testing only, DO NOT USE in a production environment
175
+ const simulateSecureGetCredentialsAPI = (): Promise<AwsCredentialIdentity> => {
176
+ // Users must retrieve the AwsCredentialIdentity through a secure API
177
+ // DO NOT store the IAM accessKeyId and secretAccessKey inside the JavaScript source code
178
+ // for more details, refer to the example in the folder "example/src/alternative/websocket"
179
+ };
180
+
181
+ const config: AuroraDSQLWsConfig<{}> = {
182
+ host: 'your-cluster.dsql.us-east-1.on.aws',
183
+ database: "postgres",
184
+ user: "admin",
185
+ customCredentialsProvider: simulateSecureGetCredentialsAPI,
186
+ };
187
+
188
+ const sql = auroraDSQLWsPostgres(config);
189
+
190
+ const result = await sql`SELECT version()`;
191
+ console.log(result);
192
+ await sql.end();
193
+ ```
194
+
195
+ ### Configuration Options
196
+
197
+ | Option | Type | Required | Description |
198
+ |-----------------------------|----------------------------------|----------|----------------------------------------------------------|
199
+ | `host` | `string` | Yes | DSQL cluster hostname or cluster ID |
200
+ | `database` | `string?` | No | Database name |
201
+ | `username` | `string?` | No | Database username (uses admin if not provided) |
202
+ | `region` | `string?` | No | AWS region (auto-detected from hostname if not provided) |
203
+ | `customCredentialsProvider` | `AwsCredentialIdentityProvider?` | No | Custom AWS credentials provider |
204
+ | `tokenDurationSecs` | `number?` | No | Token expiration time in seconds |
205
+ | `connectionCheck` | `boolean?` | No | Perform a heart beat connectivity check with`Select 1` before every query (Default: false)
206
+ | `connectionId` | `string?` | No | An optional connection identifier to be used in the `onReservedConnectionClose` callback
207
+ | `onReservedConnectionClose` | `(connectionId?: string) => void?` | No | A callback that is executed upon unexpected closure of a reserved connection, such as a heartbeat failure. The connectionId is passed to the callback when available.
208
+
209
+ Other standard [Postgres.js options](https://github.com/porsager/postgres?tab=readme-ov-file#connection-details) are also supported, except for `socket`, `port`, and `ssl`, which have default values.
210
+
211
+
212
+
134
213
  ## Authentication
135
214
 
136
215
  The connector automatically handles DSQL authentication by generating tokens using the DSQL client token generator. If the
package/dist/index.cjs CHANGED
@@ -1,4 +1,5 @@
1
- //#region rolldown:runtime
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -28,55 +29,294 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
29
  let postgres = require("postgres");
29
30
  postgres = __toESM(postgres);
30
31
  let _aws_sdk_dsql_signer = require("@aws-sdk/dsql-signer");
32
+ let events = require("events");
33
+ let async_mutex = require("async-mutex");
31
34
 
35
+ //#region src/postgres-web-socket.ts
36
+ const HEARTBEAT_TIMEOUT = 5e3;
37
+ const MESSAGE_CODE_SIMPLE_QUERY = "Q".charCodeAt(0);
38
+ const MESSAGE_CODE_SYNC = "S".charCodeAt(0);
39
+ const MESSAGE_CODE_RFQ = "Z".charCodeAt(0);
40
+ var ReadyState = /* @__PURE__ */ function(ReadyState) {
41
+ ReadyState["Closed"] = "closed";
42
+ ReadyState["Querying"] = "querying";
43
+ ReadyState["Open"] = "open";
44
+ return ReadyState;
45
+ }(ReadyState || {});
46
+ var PostgresWs = class extends events.EventEmitter {
47
+ constructor(config) {
48
+ super();
49
+ this.mutex = new async_mutex.Mutex();
50
+ this.mutexRelease = null;
51
+ this.ws = null;
52
+ this.connected = false;
53
+ this.disableHeartBeat = false;
54
+ this.heartBeatTimeout = null;
55
+ this.pendingQueries = [];
56
+ this.readyState = ReadyState.Closed;
57
+ this.port = 443;
58
+ this.config = config;
59
+ this.host = config.host || "";
60
+ }
61
+ onReadyForQuery() {
62
+ if (this.pendingQueries.length > 0) {
63
+ if (this.pendingQueries[0].numOfQueries > 0) this.pendingQueries[0].numOfQueries--;
64
+ if (this.pendingQueries[0].numOfQueries <= 0) {
65
+ this.pendingQueries.shift();
66
+ this.readyState = ReadyState.Open;
67
+ this.disableHeartBeat = false;
68
+ this.releaseMutex();
69
+ this.processQueue();
70
+ }
71
+ }
72
+ }
73
+ handleHeartBeatResponse(data) {
74
+ if (this.pendingQueries.length === 0 || !this.pendingQueries[0].isHeartBeat) return false;
75
+ const messageType = String.fromCharCode(data[0]);
76
+ if (messageType === "D") {
77
+ if (new TextDecoder().decode(data.slice(5)).includes("1")) {
78
+ clearTimeout(this.heartBeatTimeout);
79
+ this.heartBeatTimeout = null;
80
+ }
81
+ } else if (messageType === "Z") this.onReadyForQuery();
82
+ return true;
83
+ }
84
+ async connect() {
85
+ const url = `wss://${this.config.host}:${this.port}`;
86
+ this.ws = new WebSocket(url);
87
+ this.ws.binaryType = "arraybuffer";
88
+ return new Promise((resolve, reject) => {
89
+ if (this.ws != null) {
90
+ this.ws.onopen = () => {
91
+ this.connected = true;
92
+ this.readyState = ReadyState.Open;
93
+ resolve(this);
94
+ };
95
+ this.ws.onmessage = (event) => {
96
+ const data = new Uint8Array(event.data);
97
+ if (this.config.connectionCheck) {
98
+ if (this.handleHeartBeatResponse(data)) return;
99
+ if (data.length > 0 && data[0] === MESSAGE_CODE_RFQ) {
100
+ if (data.length > 5) if (String.fromCharCode(data[5]) === "E") {
101
+ this.disableHeartBeat = true;
102
+ this.cleanUpTxErrorState();
103
+ } else this.onReadyForQuery();
104
+ }
105
+ }
106
+ this.emit("data", Buffer.from(data));
107
+ };
108
+ this.ws.onerror = (event) => {
109
+ const msg = event.message || "WebSocket error";
110
+ const error = /* @__PURE__ */ new Error(`${msg} ${this.host}:${this.port}`);
111
+ this.emit("error", error);
112
+ reject(error);
113
+ };
114
+ this.ws.onclose = () => {
115
+ if (this.heartBeatTimeout) {
116
+ clearTimeout(this.heartBeatTimeout);
117
+ this.heartBeatTimeout = null;
118
+ }
119
+ this.releaseMutex();
120
+ this.connected = false;
121
+ this.readyState = ReadyState.Closed;
122
+ this.ws = null;
123
+ this.emit("close");
124
+ if (this.config.onReservedConnectionClose) this.config.onReservedConnectionClose(this.config.connectionId);
125
+ };
126
+ }
127
+ });
128
+ }
129
+ createQueryBuffer(sql) {
130
+ const sqlBytes = new TextEncoder().encode(sql + "\0");
131
+ const length = 4 + sqlBytes.length;
132
+ const buf = new Uint8Array(1 + length);
133
+ const view = new DataView(buf.buffer);
134
+ buf[0] = MESSAGE_CODE_SIMPLE_QUERY;
135
+ view.setInt32(1, length, false);
136
+ buf.set(sqlBytes, 5);
137
+ return buf;
138
+ }
139
+ write(data, encodingOrCallback, callback) {
140
+ let callbackFn;
141
+ if (typeof encodingOrCallback === "function") callbackFn = encodingOrCallback;
142
+ else callbackFn = callback;
143
+ let sendData;
144
+ if (typeof data === "string") sendData = new TextEncoder().encode(data);
145
+ else if (data instanceof Buffer) sendData = new Uint8Array(data);
146
+ else sendData = data;
147
+ if (!this.ws || !this.connected) {
148
+ if (callbackFn) callbackFn(/* @__PURE__ */ new Error("websocket is not connected"));
149
+ return false;
150
+ }
151
+ let offset = 0;
152
+ let queryCount = 0;
153
+ let hasSync = false;
154
+ while (offset < sendData.length) {
155
+ if (sendData[offset] === MESSAGE_CODE_SIMPLE_QUERY) queryCount++;
156
+ if (sendData[offset] === MESSAGE_CODE_SYNC) hasSync = true;
157
+ if (offset + 5 <= sendData.length) {
158
+ const length = new DataView(sendData.buffer, sendData.byteOffset + offset + 1, 4).getInt32(0, false);
159
+ offset += 1 + length;
160
+ } else break;
161
+ }
162
+ if (!this.config.connectionCheck || queryCount == 0 && hasSync === false) try {
163
+ this.ws.send(sendData);
164
+ if (callbackFn) callbackFn();
165
+ return true;
166
+ } catch (err) {
167
+ if (callbackFn) callbackFn(err);
168
+ return false;
169
+ }
170
+ if (queryCount > 0 && this.config.connectionCheck && this.heartBeatTimeout === null && !this.disableHeartBeat) {
171
+ const buf = this.createQueryBuffer("select 1;");
172
+ this.pendingQueries.push({
173
+ buffer: buf,
174
+ numOfQueries: 1,
175
+ isHeartBeat: true
176
+ });
177
+ }
178
+ this.pendingQueries.push({
179
+ buffer: sendData,
180
+ numOfQueries: queryCount,
181
+ isHeartBeat: false
182
+ });
183
+ this.processQueue();
184
+ if (callbackFn) callbackFn();
185
+ return true;
186
+ }
187
+ releaseMutex() {
188
+ if (this.mutexRelease) {
189
+ this.mutexRelease();
190
+ this.mutexRelease = null;
191
+ }
192
+ }
193
+ cleanUpTxErrorState() {
194
+ if (this.pendingQueries.length > 0) this.pendingQueries.shift();
195
+ while (this.pendingQueries.length > 0 && this.pendingQueries[0].isHeartBeat) this.pendingQueries.shift();
196
+ this.readyState = ReadyState.Open;
197
+ this.releaseMutex();
198
+ if (this.pendingQueries.length > 0) this.processQueue();
199
+ }
200
+ async processQueue() {
201
+ if (this.mutexRelease || this.readyState !== ReadyState.Open || this.pendingQueries.length === 0) return;
202
+ this.mutexRelease = await this.mutex.acquire();
203
+ if (this.pendingQueries.length == 0) {
204
+ this.releaseMutex();
205
+ return;
206
+ }
207
+ const data = this.pendingQueries[0];
208
+ if (data.buffer.length > 0 && data.buffer[0] === MESSAGE_CODE_SIMPLE_QUERY) this.readyState = ReadyState.Querying;
209
+ if (data.isHeartBeat) this.heartBeatTimeout = setTimeout(() => {
210
+ console.log("Heart beat timed out");
211
+ if (this.ws) this.ws.close(1e3, "Heart beat timeout");
212
+ }, HEARTBEAT_TIMEOUT);
213
+ if (this.ws) this.ws.send(data.buffer);
214
+ else throw Error("Websocket is not initialized");
215
+ }
216
+ end() {
217
+ if (this.ws && this.readyState !== ReadyState.Closed) this.ws.close();
218
+ }
219
+ destroy() {
220
+ if (this.ws) this.ws.close();
221
+ }
222
+ setKeepAlive() {
223
+ return this;
224
+ }
225
+ resume() {
226
+ return this;
227
+ }
228
+ pause() {
229
+ return this;
230
+ }
231
+ cork() {
232
+ return this;
233
+ }
234
+ uncork() {
235
+ return this;
236
+ }
237
+ };
238
+ function createPostgresWs(config) {
239
+ return async () => {
240
+ const socket = new PostgresWs(config);
241
+ await socket.connect();
242
+ return socket;
243
+ };
244
+ }
245
+
246
+ //#endregion
32
247
  //#region src/client.ts
248
+ const version = "0.2.1";
33
249
  const ADMIN = "admin";
34
250
  const DEFAULT_DATABASE = "postgres";
35
251
  const DEFAULT_EXPIRY = 30;
36
252
  const PRE_REGION_HOST_PATTERN = ".dsql.";
37
253
  const POST_REGION_HOST_PATTERN = ".on.aws";
38
- function auroraDSQLPostgres(urlOrOptions, options) {
254
+ const APPLICATION_NAME = `aurora-dsql-nodejs-postgresjs/${version}`;
255
+ function parseConnectionParams(urlOrOptions, options) {
39
256
  let opts;
40
257
  let host;
41
258
  let username;
42
259
  let database;
43
- let ssl;
44
260
  if (typeof urlOrOptions === "string") {
45
261
  let parsedOptions = parseConnectionString(urlOrOptions);
46
262
  host = options?.hostname || options?.host || parsedOptions.host || process.env.PGHOST;
47
263
  username = options?.username || options?.user || parsedOptions.username || process.env.PGUSERNAME || process.env.USER || ADMIN;
48
264
  database = options?.database || options?.db || parsedOptions.database || process.env.PGDATABASE;
49
- ssl = options?.ssl || parsedOptions.ssl;
50
- opts = { ...options };
265
+ opts = {
266
+ ...options,
267
+ ssl: options?.ssl || parsedOptions.ssl
268
+ };
51
269
  } else {
52
270
  host = urlOrOptions?.hostname || urlOrOptions?.host || process.env.PGHOST;
53
271
  username = urlOrOptions?.username || urlOrOptions?.user || process.env.PGUSERNAME || process.env.USER || ADMIN;
54
272
  database = urlOrOptions?.database || urlOrOptions?.db || process.env.PGDATABASE;
55
- ssl = urlOrOptions?.ssl;
56
273
  opts = { ...urlOrOptions };
57
274
  }
58
275
  if (Array.isArray(host)) throw new Error("Multi-host configurations are not supported for Aurora DSQL");
59
- let region = opts.region || parseRegionFromHost(host);
60
- if (isClusterID(host)) {
61
- host = buildHostnameFromIdAndRegion(host, region);
62
- opts.host = host;
63
- }
276
+ if (!opts.region) opts.region = parseRegionFromHost(host);
277
+ if (isClusterID(host)) host = buildHostnameFromIdAndRegion(host, opts.region);
278
+ if (!database) opts.database = DEFAULT_DATABASE;
279
+ opts.host = host;
280
+ opts.username = username;
281
+ opts.connection = {
282
+ ...opts.connection,
283
+ application_name: buildApplicationName(opts.connection?.application_name)
284
+ };
285
+ return { opts };
286
+ }
287
+ function setupDsqlSigner(opts) {
64
288
  let signerConfig = {
65
- hostname: host,
66
- region: opts.region || parseRegionFromHost(host),
289
+ hostname: opts.host,
290
+ region: opts.region,
67
291
  expiresIn: opts.tokenDurationSecs ?? opts.connect_timeout ?? (process.env.PGCONNECT_TIMEOUT ? parseInt(process.env.PGCONNECT_TIMEOUT) : void 0) ?? DEFAULT_EXPIRY,
68
292
  profile: opts.profile || process.env.AWS_PROFILE || "default"
69
293
  };
70
294
  if (opts.customCredentialsProvider) signerConfig.credentials = opts.customCredentialsProvider;
295
+ return { signerConfig };
296
+ }
297
+ function auroraDSQLPostgres(urlOrOptions, options) {
298
+ let { opts } = parseConnectionParams(urlOrOptions, options);
299
+ const { signerConfig } = setupDsqlSigner(opts);
71
300
  let signer = new _aws_sdk_dsql_signer.DsqlSigner(signerConfig);
72
- if (!database) opts.database = DEFAULT_DATABASE;
73
- if (!ssl) opts.ssl = true;
301
+ if (!opts.ssl) opts.ssl = true;
74
302
  const postgresOpts = {
75
303
  ...opts,
76
- pass: () => getToken(signer, username)
304
+ pass: () => getToken(signer, opts.username)
77
305
  };
78
306
  return typeof urlOrOptions === "string" ? (0, postgres.default)(urlOrOptions, postgresOpts) : (0, postgres.default)(postgresOpts);
79
307
  }
308
+ function auroraDSQLWsPostgres(urlOrOptions, options) {
309
+ let { opts } = parseConnectionParams(urlOrOptions, options);
310
+ const { signerConfig } = setupDsqlSigner(opts);
311
+ if (!opts.pass) opts.pass = async () => {
312
+ return await getToken(new _aws_sdk_dsql_signer.DsqlSigner(signerConfig), opts.username);
313
+ };
314
+ opts.socket = createPostgresWs(opts);
315
+ opts.ssl = false;
316
+ if (opts.connectionCheck == void 0) opts.connectionCheck = false;
317
+ opts.port = 443;
318
+ return typeof urlOrOptions === "string" ? (0, postgres.default)(urlOrOptions, opts) : (0, postgres.default)(opts);
319
+ }
80
320
  function parseConnectionString(url) {
81
321
  let decodedUrl = decodeURI(url);
82
322
  const parsed = new URL(decodedUrl);
@@ -104,6 +344,27 @@ async function getToken(signer, username) {
104
344
  if (username === ADMIN) return await signer.getDbConnectAdminAuthToken();
105
345
  else return await signer.getDbConnectAuthToken();
106
346
  }
347
+ /**
348
+ * Build the application_name with optional ORM prefix.
349
+ *
350
+ * If ormPrefix is provided and non-empty after trimming, prepends it to
351
+ * the connector identifier. Otherwise, returns the connector's application_name.
352
+ *
353
+ * PostgreSQL limits application_name to 64 characters. After accounting for
354
+ * the connector identifier and separator, 27 characters are available for
355
+ * the ORM name.
356
+ *
357
+ * @param ormPrefix Optional ORM name to prepend (e.g., "prisma")
358
+ * @returns Formatted application_name string
359
+ */
360
+ function buildApplicationName(ormPrefix) {
361
+ if (ormPrefix) {
362
+ const trimmed = ormPrefix.trim();
363
+ if (trimmed) return `${trimmed}:${APPLICATION_NAME}`;
364
+ }
365
+ return APPLICATION_NAME;
366
+ }
107
367
 
108
368
  //#endregion
109
- exports.auroraDSQLPostgres = auroraDSQLPostgres;
369
+ exports.auroraDSQLPostgres = auroraDSQLPostgres;
370
+ exports.auroraDSQLWsPostgres = auroraDSQLWsPostgres;
package/dist/index.d.cts CHANGED
@@ -10,12 +10,28 @@ declare function auroraDSQLPostgres<T extends Record<string, postgres.PostgresTy
10
10
  serialize: (value: infer R) => any;
11
11
  parse: (raw: any) => infer R;
12
12
  } ? R : never }>;
13
+ declare function auroraDSQLWsPostgres<T extends Record<string, postgres.PostgresType> = {}>(url: string, options?: AuroraDSQLWsConfig<T>): postgres.Sql<Record<string, postgres.PostgresType> extends T ? {} : { [type in keyof T]: T[type] extends {
14
+ serialize: (value: infer R) => any;
15
+ parse: (raw: any) => infer R;
16
+ } ? R : never }>;
17
+ declare function auroraDSQLWsPostgres<T extends Record<string, postgres.PostgresType> = {}>(options: AuroraDSQLWsConfig<T>): postgres.Sql<Record<string, postgres.PostgresType> extends T ? {} : { [type in keyof T]: T[type] extends {
18
+ serialize: (value: infer R) => any;
19
+ parse: (raw: any) => infer R;
20
+ } ? R : never }>;
13
21
  interface AuroraDSQLConfig<T extends Record<string, PostgresType<T>>> extends Omit<postgres.Options<T>, 'password' | 'pass'> {
14
22
  region?: string;
15
23
  profile?: string;
16
24
  tokenDurationSecs?: number;
17
25
  customCredentialsProvider?: AwsCredentialIdentity | AwsCredentialIdentityProvider;
18
26
  }
27
+ interface AuroraDSQLWsConfig<T extends Record<string, PostgresType<T>>> extends Omit<postgres.Options<T>, "socket" | "ssl" | "port"> {
28
+ region?: string;
29
+ tokenDurationSecs?: number;
30
+ customCredentialsProvider?: AwsCredentialIdentity | AwsCredentialIdentityProvider;
31
+ connectionCheck?: boolean;
32
+ connectionId?: string;
33
+ onReservedConnectionClose?: (connectionId?: string) => void;
34
+ }
19
35
  //#endregion
20
- export { type AuroraDSQLConfig, auroraDSQLPostgres };
36
+ export { type AuroraDSQLConfig, type AuroraDSQLWsConfig, auroraDSQLPostgres, auroraDSQLWsPostgres };
21
37
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/client.ts"],"sourcesContent":[],"mappings":";;;;iBAgBgB,6BAA6B,eAAe,QAAA,CAAS,2CAEvD,iBAAiB,KAC5B,QAAA,CAAS,IAAI,eAAe,QAAA,CAAS,sBAAsB,0BAC3C,IAAI,EAAE;EAJT,SAAA,EAAA,CAAA,KAAkB,EAAA,KAAA,EAAA,EAAA,GAAA,GAAA;EAA0B,KAAS,EAAA,CAAA,GAAA,EAAA,GAAA,EAAA,GAAA,KAAA,EAAA;AAAxB,CAAA,GAAA,CAAA,GAAA,KAAA,EAEd,CAAA;AAAjB,iBAQE,kBARF,CAAA,UAQ+B,MAR/B,CAAA,MAAA,EAQ8C,QAAA,CAAS,YARvD,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,OAAA,EASD,gBATC,CASgB,CAThB,CAAA,CAAA,EAUX,QAAA,CAAS,GAVE,CAUE,MAVF,CAAA,MAAA,EAUiB,QAAA,CAAS,YAV1B,CAAA,SAUgD,CAVhD,GAAA,CAAA,CAAA,GAAA,WAC0B,MAUrB,CAVqB,GAUjB,CAViB,CAUf,IAVe,CAAA,SAAA;EAAxB,SAAA,EAAA,CAAA,KAAA,EAAA,KAAA,EAAA,EAAA,GAAA,GAAA;EAA8C,KAAA,EAAA,CAAA,GAAA,EAAA,GAAA,EAAA,GAAA,KAAA,EAAA;AAC3C,CAAA,GAAA,CAAA,GAAA,KAAA,EAAI,CAAA;AAAE,UA2HR,gBA3HQ,CAAA,UA2HmB,MA3HnB,CAAA,MAAA,EA2HkC,YA3HlC,CA2H+C,CA3H/C,CAAA,CAAA,CAAA,SA2H4D,IA3H5D,CA2HiE,QAAA,CAAS,OA3H1E,CA2HkF,CA3HlF,CAAA,EAAA,UAAA,GAAA,MAAA,CAAA,CAAA;EADtB,MAAS,CAAA,EAAA,MAAA;EAAG,OAAA,CAAA,EAAA,MAAA;EAOC,iBAAA,CAAA,EAAA,MAAkB;EAA0B,yBAAS,CAAA,EA6HrC,qBA7HqC,GA6Hb,6BA7Ha"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/client.ts"],"mappings":";;;;iBAgGgB,kBAAA,WACJ,MAAA,SAAe,QAAA,CAAS,YAAA,OAAA,CAElC,GAAA,UACA,OAAA,GAAU,gBAAA,CAAiB,CAAA,IAC1B,QAAA,CAAS,GAAA,CACV,MAAA,SAAe,QAAA,CAAS,YAAA,UAAsB,CAAA,yBAG7B,CAAA,GAAI,CAAA,CAAE,IAAA;EACnB,SAAA,GAAY,KAAA;EACZ,KAAA,GAAQ,GAAA;AAAA,IAER,CAAA;AAAA,iBAKU,kBAAA,WACJ,MAAA,SAAe,QAAA,CAAS,YAAA,OAAA,CAElC,OAAA,EAAS,gBAAA,CAAiB,CAAA,IACzB,QAAA,CAAS,GAAA,CACV,MAAA,SAAe,QAAA,CAAS,YAAA,UAAsB,CAAA,yBAG7B,CAAA,GAAI,CAAA,CAAE,IAAA;EACnB,SAAA,GAAY,KAAA;EACZ,KAAA,GAAQ,GAAA;AAAA,IAER,CAAA;AAAA,iBAqCU,oBAAA,WACJ,MAAA,SAAe,QAAA,CAAS,YAAA,OAAA,CAElC,GAAA,UACA,OAAA,GAAU,kBAAA,CAAmB,CAAA,IAC5B,QAAA,CAAS,GAAA,CACV,MAAA,SAAe,QAAA,CAAS,YAAA,UAAsB,CAAA,yBAG7B,CAAA,GAAI,CAAA,CAAE,IAAA;EACnB,SAAA,GAAY,KAAA;EACZ,KAAA,GAAQ,GAAA;AAAA,IAER,CAAA;AAAA,iBAKU,oBAAA,WACJ,MAAA,SAAe,QAAA,CAAS,YAAA,OAAA,CAElC,OAAA,EAAS,kBAAA,CAAmB,CAAA,IAC3B,QAAA,CAAS,GAAA,CACV,MAAA,SAAe,QAAA,CAAS,YAAA,UAAsB,CAAA,yBAG7B,CAAA,GAAI,CAAA,CAAE,IAAA;EACnB,SAAA,GAAY,KAAA;EACZ,KAAA,GAAQ,GAAA;AAAA,IAER,CAAA;AAAA,UAwIW,gBAAA,WAA2B,MAAA,SAAe,YAAA,CAAa,CAAA,YAAa,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,CAAA;EAEzG,MAAA;EAEA,OAAA;EAEA,iBAAA;EAEA,yBAAA,GAA4B,qBAAA,GAAwB,6BAAA;AAAA;AAAA,UAGrC,kBAAA,WAA6B,MAAA,SAAe,YAAA,CAAa,CAAA,YAChE,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,CAAA;EAC9B,MAAA;EACA,iBAAA;EACA,yBAAA,GACE,qBAAA,GACA,6BAAA;EACF,eAAA;EACA,YAAA;EACA,yBAAA,IAA6B,YAAA;AAAA"}
package/dist/index.d.mts CHANGED
@@ -10,12 +10,28 @@ declare function auroraDSQLPostgres<T extends Record<string, postgres.PostgresTy
10
10
  serialize: (value: infer R) => any;
11
11
  parse: (raw: any) => infer R;
12
12
  } ? R : never }>;
13
+ declare function auroraDSQLWsPostgres<T extends Record<string, postgres.PostgresType> = {}>(url: string, options?: AuroraDSQLWsConfig<T>): postgres.Sql<Record<string, postgres.PostgresType> extends T ? {} : { [type in keyof T]: T[type] extends {
14
+ serialize: (value: infer R) => any;
15
+ parse: (raw: any) => infer R;
16
+ } ? R : never }>;
17
+ declare function auroraDSQLWsPostgres<T extends Record<string, postgres.PostgresType> = {}>(options: AuroraDSQLWsConfig<T>): postgres.Sql<Record<string, postgres.PostgresType> extends T ? {} : { [type in keyof T]: T[type] extends {
18
+ serialize: (value: infer R) => any;
19
+ parse: (raw: any) => infer R;
20
+ } ? R : never }>;
13
21
  interface AuroraDSQLConfig<T extends Record<string, PostgresType<T>>> extends Omit<postgres.Options<T>, 'password' | 'pass'> {
14
22
  region?: string;
15
23
  profile?: string;
16
24
  tokenDurationSecs?: number;
17
25
  customCredentialsProvider?: AwsCredentialIdentity | AwsCredentialIdentityProvider;
18
26
  }
27
+ interface AuroraDSQLWsConfig<T extends Record<string, PostgresType<T>>> extends Omit<postgres.Options<T>, "socket" | "ssl" | "port"> {
28
+ region?: string;
29
+ tokenDurationSecs?: number;
30
+ customCredentialsProvider?: AwsCredentialIdentity | AwsCredentialIdentityProvider;
31
+ connectionCheck?: boolean;
32
+ connectionId?: string;
33
+ onReservedConnectionClose?: (connectionId?: string) => void;
34
+ }
19
35
  //#endregion
20
- export { type AuroraDSQLConfig, auroraDSQLPostgres };
36
+ export { type AuroraDSQLConfig, type AuroraDSQLWsConfig, auroraDSQLPostgres, auroraDSQLWsPostgres };
21
37
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/client.ts"],"sourcesContent":[],"mappings":";;;;iBAgBgB,6BAA6B,eAAe,QAAA,CAAS,2CAEvD,iBAAiB,KAC5B,QAAA,CAAS,IAAI,eAAe,QAAA,CAAS,sBAAsB,0BAC3C,IAAI,EAAE;EAJT,SAAA,EAAA,CAAA,KAAkB,EAAA,KAAA,EAAA,EAAA,GAAA,GAAA;EAA0B,KAAS,EAAA,CAAA,GAAA,EAAA,GAAA,EAAA,GAAA,KAAA,EAAA;AAAxB,CAAA,GAAA,CAAA,GAAA,KAAA,EAEd,CAAA;AAAjB,iBAQE,kBARF,CAAA,UAQ+B,MAR/B,CAAA,MAAA,EAQ8C,QAAA,CAAS,YARvD,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,OAAA,EASD,gBATC,CASgB,CAThB,CAAA,CAAA,EAUX,QAAA,CAAS,GAVE,CAUE,MAVF,CAAA,MAAA,EAUiB,QAAA,CAAS,YAV1B,CAAA,SAUgD,CAVhD,GAAA,CAAA,CAAA,GAAA,WAC0B,MAUrB,CAVqB,GAUjB,CAViB,CAUf,IAVe,CAAA,SAAA;EAAxB,SAAA,EAAA,CAAA,KAAA,EAAA,KAAA,EAAA,EAAA,GAAA,GAAA;EAA8C,KAAA,EAAA,CAAA,GAAA,EAAA,GAAA,EAAA,GAAA,KAAA,EAAA;AAC3C,CAAA,GAAA,CAAA,GAAA,KAAA,EAAI,CAAA;AAAE,UA2HR,gBA3HQ,CAAA,UA2HmB,MA3HnB,CAAA,MAAA,EA2HkC,YA3HlC,CA2H+C,CA3H/C,CAAA,CAAA,CAAA,SA2H4D,IA3H5D,CA2HiE,QAAA,CAAS,OA3H1E,CA2HkF,CA3HlF,CAAA,EAAA,UAAA,GAAA,MAAA,CAAA,CAAA;EADtB,MAAS,CAAA,EAAA,MAAA;EAAG,OAAA,CAAA,EAAA,MAAA;EAOC,iBAAA,CAAA,EAAA,MAAkB;EAA0B,yBAAS,CAAA,EA6HrC,qBA7HqC,GA6Hb,6BA7Ha"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/client.ts"],"mappings":";;;;iBAgGgB,kBAAA,WACJ,MAAA,SAAe,QAAA,CAAS,YAAA,OAAA,CAElC,GAAA,UACA,OAAA,GAAU,gBAAA,CAAiB,CAAA,IAC1B,QAAA,CAAS,GAAA,CACV,MAAA,SAAe,QAAA,CAAS,YAAA,UAAsB,CAAA,yBAG7B,CAAA,GAAI,CAAA,CAAE,IAAA;EACnB,SAAA,GAAY,KAAA;EACZ,KAAA,GAAQ,GAAA;AAAA,IAER,CAAA;AAAA,iBAKU,kBAAA,WACJ,MAAA,SAAe,QAAA,CAAS,YAAA,OAAA,CAElC,OAAA,EAAS,gBAAA,CAAiB,CAAA,IACzB,QAAA,CAAS,GAAA,CACV,MAAA,SAAe,QAAA,CAAS,YAAA,UAAsB,CAAA,yBAG7B,CAAA,GAAI,CAAA,CAAE,IAAA;EACnB,SAAA,GAAY,KAAA;EACZ,KAAA,GAAQ,GAAA;AAAA,IAER,CAAA;AAAA,iBAqCU,oBAAA,WACJ,MAAA,SAAe,QAAA,CAAS,YAAA,OAAA,CAElC,GAAA,UACA,OAAA,GAAU,kBAAA,CAAmB,CAAA,IAC5B,QAAA,CAAS,GAAA,CACV,MAAA,SAAe,QAAA,CAAS,YAAA,UAAsB,CAAA,yBAG7B,CAAA,GAAI,CAAA,CAAE,IAAA;EACnB,SAAA,GAAY,KAAA;EACZ,KAAA,GAAQ,GAAA;AAAA,IAER,CAAA;AAAA,iBAKU,oBAAA,WACJ,MAAA,SAAe,QAAA,CAAS,YAAA,OAAA,CAElC,OAAA,EAAS,kBAAA,CAAmB,CAAA,IAC3B,QAAA,CAAS,GAAA,CACV,MAAA,SAAe,QAAA,CAAS,YAAA,UAAsB,CAAA,yBAG7B,CAAA,GAAI,CAAA,CAAE,IAAA;EACnB,SAAA,GAAY,KAAA;EACZ,KAAA,GAAQ,GAAA;AAAA,IAER,CAAA;AAAA,UAwIW,gBAAA,WAA2B,MAAA,SAAe,YAAA,CAAa,CAAA,YAAa,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,CAAA;EAEzG,MAAA;EAEA,OAAA;EAEA,iBAAA;EAEA,yBAAA,GAA4B,qBAAA,GAAwB,6BAAA;AAAA;AAAA,UAGrC,kBAAA,WAA6B,MAAA,SAAe,YAAA,CAAa,CAAA,YAChE,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,CAAA;EAC9B,MAAA;EACA,iBAAA;EACA,yBAAA,GACE,qBAAA,GACA,6BAAA;EACF,eAAA;EACA,YAAA;EACA,yBAAA,IAA6B,YAAA;AAAA"}
package/dist/index.mjs CHANGED
@@ -1,54 +1,293 @@
1
1
  import postgres from "postgres";
2
2
  import { DsqlSigner } from "@aws-sdk/dsql-signer";
3
+ import { EventEmitter } from "events";
4
+ import { Mutex } from "async-mutex";
3
5
 
6
+ //#region src/postgres-web-socket.ts
7
+ const HEARTBEAT_TIMEOUT = 5e3;
8
+ const MESSAGE_CODE_SIMPLE_QUERY = "Q".charCodeAt(0);
9
+ const MESSAGE_CODE_SYNC = "S".charCodeAt(0);
10
+ const MESSAGE_CODE_RFQ = "Z".charCodeAt(0);
11
+ var ReadyState = /* @__PURE__ */ function(ReadyState) {
12
+ ReadyState["Closed"] = "closed";
13
+ ReadyState["Querying"] = "querying";
14
+ ReadyState["Open"] = "open";
15
+ return ReadyState;
16
+ }(ReadyState || {});
17
+ var PostgresWs = class extends EventEmitter {
18
+ constructor(config) {
19
+ super();
20
+ this.mutex = new Mutex();
21
+ this.mutexRelease = null;
22
+ this.ws = null;
23
+ this.connected = false;
24
+ this.disableHeartBeat = false;
25
+ this.heartBeatTimeout = null;
26
+ this.pendingQueries = [];
27
+ this.readyState = ReadyState.Closed;
28
+ this.port = 443;
29
+ this.config = config;
30
+ this.host = config.host || "";
31
+ }
32
+ onReadyForQuery() {
33
+ if (this.pendingQueries.length > 0) {
34
+ if (this.pendingQueries[0].numOfQueries > 0) this.pendingQueries[0].numOfQueries--;
35
+ if (this.pendingQueries[0].numOfQueries <= 0) {
36
+ this.pendingQueries.shift();
37
+ this.readyState = ReadyState.Open;
38
+ this.disableHeartBeat = false;
39
+ this.releaseMutex();
40
+ this.processQueue();
41
+ }
42
+ }
43
+ }
44
+ handleHeartBeatResponse(data) {
45
+ if (this.pendingQueries.length === 0 || !this.pendingQueries[0].isHeartBeat) return false;
46
+ const messageType = String.fromCharCode(data[0]);
47
+ if (messageType === "D") {
48
+ if (new TextDecoder().decode(data.slice(5)).includes("1")) {
49
+ clearTimeout(this.heartBeatTimeout);
50
+ this.heartBeatTimeout = null;
51
+ }
52
+ } else if (messageType === "Z") this.onReadyForQuery();
53
+ return true;
54
+ }
55
+ async connect() {
56
+ const url = `wss://${this.config.host}:${this.port}`;
57
+ this.ws = new WebSocket(url);
58
+ this.ws.binaryType = "arraybuffer";
59
+ return new Promise((resolve, reject) => {
60
+ if (this.ws != null) {
61
+ this.ws.onopen = () => {
62
+ this.connected = true;
63
+ this.readyState = ReadyState.Open;
64
+ resolve(this);
65
+ };
66
+ this.ws.onmessage = (event) => {
67
+ const data = new Uint8Array(event.data);
68
+ if (this.config.connectionCheck) {
69
+ if (this.handleHeartBeatResponse(data)) return;
70
+ if (data.length > 0 && data[0] === MESSAGE_CODE_RFQ) {
71
+ if (data.length > 5) if (String.fromCharCode(data[5]) === "E") {
72
+ this.disableHeartBeat = true;
73
+ this.cleanUpTxErrorState();
74
+ } else this.onReadyForQuery();
75
+ }
76
+ }
77
+ this.emit("data", Buffer.from(data));
78
+ };
79
+ this.ws.onerror = (event) => {
80
+ const msg = event.message || "WebSocket error";
81
+ const error = /* @__PURE__ */ new Error(`${msg} ${this.host}:${this.port}`);
82
+ this.emit("error", error);
83
+ reject(error);
84
+ };
85
+ this.ws.onclose = () => {
86
+ if (this.heartBeatTimeout) {
87
+ clearTimeout(this.heartBeatTimeout);
88
+ this.heartBeatTimeout = null;
89
+ }
90
+ this.releaseMutex();
91
+ this.connected = false;
92
+ this.readyState = ReadyState.Closed;
93
+ this.ws = null;
94
+ this.emit("close");
95
+ if (this.config.onReservedConnectionClose) this.config.onReservedConnectionClose(this.config.connectionId);
96
+ };
97
+ }
98
+ });
99
+ }
100
+ createQueryBuffer(sql) {
101
+ const sqlBytes = new TextEncoder().encode(sql + "\0");
102
+ const length = 4 + sqlBytes.length;
103
+ const buf = new Uint8Array(1 + length);
104
+ const view = new DataView(buf.buffer);
105
+ buf[0] = MESSAGE_CODE_SIMPLE_QUERY;
106
+ view.setInt32(1, length, false);
107
+ buf.set(sqlBytes, 5);
108
+ return buf;
109
+ }
110
+ write(data, encodingOrCallback, callback) {
111
+ let callbackFn;
112
+ if (typeof encodingOrCallback === "function") callbackFn = encodingOrCallback;
113
+ else callbackFn = callback;
114
+ let sendData;
115
+ if (typeof data === "string") sendData = new TextEncoder().encode(data);
116
+ else if (data instanceof Buffer) sendData = new Uint8Array(data);
117
+ else sendData = data;
118
+ if (!this.ws || !this.connected) {
119
+ if (callbackFn) callbackFn(/* @__PURE__ */ new Error("websocket is not connected"));
120
+ return false;
121
+ }
122
+ let offset = 0;
123
+ let queryCount = 0;
124
+ let hasSync = false;
125
+ while (offset < sendData.length) {
126
+ if (sendData[offset] === MESSAGE_CODE_SIMPLE_QUERY) queryCount++;
127
+ if (sendData[offset] === MESSAGE_CODE_SYNC) hasSync = true;
128
+ if (offset + 5 <= sendData.length) {
129
+ const length = new DataView(sendData.buffer, sendData.byteOffset + offset + 1, 4).getInt32(0, false);
130
+ offset += 1 + length;
131
+ } else break;
132
+ }
133
+ if (!this.config.connectionCheck || queryCount == 0 && hasSync === false) try {
134
+ this.ws.send(sendData);
135
+ if (callbackFn) callbackFn();
136
+ return true;
137
+ } catch (err) {
138
+ if (callbackFn) callbackFn(err);
139
+ return false;
140
+ }
141
+ if (queryCount > 0 && this.config.connectionCheck && this.heartBeatTimeout === null && !this.disableHeartBeat) {
142
+ const buf = this.createQueryBuffer("select 1;");
143
+ this.pendingQueries.push({
144
+ buffer: buf,
145
+ numOfQueries: 1,
146
+ isHeartBeat: true
147
+ });
148
+ }
149
+ this.pendingQueries.push({
150
+ buffer: sendData,
151
+ numOfQueries: queryCount,
152
+ isHeartBeat: false
153
+ });
154
+ this.processQueue();
155
+ if (callbackFn) callbackFn();
156
+ return true;
157
+ }
158
+ releaseMutex() {
159
+ if (this.mutexRelease) {
160
+ this.mutexRelease();
161
+ this.mutexRelease = null;
162
+ }
163
+ }
164
+ cleanUpTxErrorState() {
165
+ if (this.pendingQueries.length > 0) this.pendingQueries.shift();
166
+ while (this.pendingQueries.length > 0 && this.pendingQueries[0].isHeartBeat) this.pendingQueries.shift();
167
+ this.readyState = ReadyState.Open;
168
+ this.releaseMutex();
169
+ if (this.pendingQueries.length > 0) this.processQueue();
170
+ }
171
+ async processQueue() {
172
+ if (this.mutexRelease || this.readyState !== ReadyState.Open || this.pendingQueries.length === 0) return;
173
+ this.mutexRelease = await this.mutex.acquire();
174
+ if (this.pendingQueries.length == 0) {
175
+ this.releaseMutex();
176
+ return;
177
+ }
178
+ const data = this.pendingQueries[0];
179
+ if (data.buffer.length > 0 && data.buffer[0] === MESSAGE_CODE_SIMPLE_QUERY) this.readyState = ReadyState.Querying;
180
+ if (data.isHeartBeat) this.heartBeatTimeout = setTimeout(() => {
181
+ console.log("Heart beat timed out");
182
+ if (this.ws) this.ws.close(1e3, "Heart beat timeout");
183
+ }, HEARTBEAT_TIMEOUT);
184
+ if (this.ws) this.ws.send(data.buffer);
185
+ else throw Error("Websocket is not initialized");
186
+ }
187
+ end() {
188
+ if (this.ws && this.readyState !== ReadyState.Closed) this.ws.close();
189
+ }
190
+ destroy() {
191
+ if (this.ws) this.ws.close();
192
+ }
193
+ setKeepAlive() {
194
+ return this;
195
+ }
196
+ resume() {
197
+ return this;
198
+ }
199
+ pause() {
200
+ return this;
201
+ }
202
+ cork() {
203
+ return this;
204
+ }
205
+ uncork() {
206
+ return this;
207
+ }
208
+ };
209
+ function createPostgresWs(config) {
210
+ return async () => {
211
+ const socket = new PostgresWs(config);
212
+ await socket.connect();
213
+ return socket;
214
+ };
215
+ }
216
+
217
+ //#endregion
4
218
  //#region src/client.ts
219
+ const version = "0.2.1";
5
220
  const ADMIN = "admin";
6
221
  const DEFAULT_DATABASE = "postgres";
7
222
  const DEFAULT_EXPIRY = 30;
8
223
  const PRE_REGION_HOST_PATTERN = ".dsql.";
9
224
  const POST_REGION_HOST_PATTERN = ".on.aws";
10
- function auroraDSQLPostgres(urlOrOptions, options) {
225
+ const APPLICATION_NAME = `aurora-dsql-nodejs-postgresjs/${version}`;
226
+ function parseConnectionParams(urlOrOptions, options) {
11
227
  let opts;
12
228
  let host;
13
229
  let username;
14
230
  let database;
15
- let ssl;
16
231
  if (typeof urlOrOptions === "string") {
17
232
  let parsedOptions = parseConnectionString(urlOrOptions);
18
233
  host = options?.hostname || options?.host || parsedOptions.host || process.env.PGHOST;
19
234
  username = options?.username || options?.user || parsedOptions.username || process.env.PGUSERNAME || process.env.USER || ADMIN;
20
235
  database = options?.database || options?.db || parsedOptions.database || process.env.PGDATABASE;
21
- ssl = options?.ssl || parsedOptions.ssl;
22
- opts = { ...options };
236
+ opts = {
237
+ ...options,
238
+ ssl: options?.ssl || parsedOptions.ssl
239
+ };
23
240
  } else {
24
241
  host = urlOrOptions?.hostname || urlOrOptions?.host || process.env.PGHOST;
25
242
  username = urlOrOptions?.username || urlOrOptions?.user || process.env.PGUSERNAME || process.env.USER || ADMIN;
26
243
  database = urlOrOptions?.database || urlOrOptions?.db || process.env.PGDATABASE;
27
- ssl = urlOrOptions?.ssl;
28
244
  opts = { ...urlOrOptions };
29
245
  }
30
246
  if (Array.isArray(host)) throw new Error("Multi-host configurations are not supported for Aurora DSQL");
31
- let region = opts.region || parseRegionFromHost(host);
32
- if (isClusterID(host)) {
33
- host = buildHostnameFromIdAndRegion(host, region);
34
- opts.host = host;
35
- }
247
+ if (!opts.region) opts.region = parseRegionFromHost(host);
248
+ if (isClusterID(host)) host = buildHostnameFromIdAndRegion(host, opts.region);
249
+ if (!database) opts.database = DEFAULT_DATABASE;
250
+ opts.host = host;
251
+ opts.username = username;
252
+ opts.connection = {
253
+ ...opts.connection,
254
+ application_name: buildApplicationName(opts.connection?.application_name)
255
+ };
256
+ return { opts };
257
+ }
258
+ function setupDsqlSigner(opts) {
36
259
  let signerConfig = {
37
- hostname: host,
38
- region: opts.region || parseRegionFromHost(host),
260
+ hostname: opts.host,
261
+ region: opts.region,
39
262
  expiresIn: opts.tokenDurationSecs ?? opts.connect_timeout ?? (process.env.PGCONNECT_TIMEOUT ? parseInt(process.env.PGCONNECT_TIMEOUT) : void 0) ?? DEFAULT_EXPIRY,
40
263
  profile: opts.profile || process.env.AWS_PROFILE || "default"
41
264
  };
42
265
  if (opts.customCredentialsProvider) signerConfig.credentials = opts.customCredentialsProvider;
266
+ return { signerConfig };
267
+ }
268
+ function auroraDSQLPostgres(urlOrOptions, options) {
269
+ let { opts } = parseConnectionParams(urlOrOptions, options);
270
+ const { signerConfig } = setupDsqlSigner(opts);
43
271
  let signer = new DsqlSigner(signerConfig);
44
- if (!database) opts.database = DEFAULT_DATABASE;
45
- if (!ssl) opts.ssl = true;
272
+ if (!opts.ssl) opts.ssl = true;
46
273
  const postgresOpts = {
47
274
  ...opts,
48
- pass: () => getToken(signer, username)
275
+ pass: () => getToken(signer, opts.username)
49
276
  };
50
277
  return typeof urlOrOptions === "string" ? postgres(urlOrOptions, postgresOpts) : postgres(postgresOpts);
51
278
  }
279
+ function auroraDSQLWsPostgres(urlOrOptions, options) {
280
+ let { opts } = parseConnectionParams(urlOrOptions, options);
281
+ const { signerConfig } = setupDsqlSigner(opts);
282
+ if (!opts.pass) opts.pass = async () => {
283
+ return await getToken(new DsqlSigner(signerConfig), opts.username);
284
+ };
285
+ opts.socket = createPostgresWs(opts);
286
+ opts.ssl = false;
287
+ if (opts.connectionCheck == void 0) opts.connectionCheck = false;
288
+ opts.port = 443;
289
+ return typeof urlOrOptions === "string" ? postgres(urlOrOptions, opts) : postgres(opts);
290
+ }
52
291
  function parseConnectionString(url) {
53
292
  let decodedUrl = decodeURI(url);
54
293
  const parsed = new URL(decodedUrl);
@@ -76,7 +315,27 @@ async function getToken(signer, username) {
76
315
  if (username === ADMIN) return await signer.getDbConnectAdminAuthToken();
77
316
  else return await signer.getDbConnectAuthToken();
78
317
  }
318
+ /**
319
+ * Build the application_name with optional ORM prefix.
320
+ *
321
+ * If ormPrefix is provided and non-empty after trimming, prepends it to
322
+ * the connector identifier. Otherwise, returns the connector's application_name.
323
+ *
324
+ * PostgreSQL limits application_name to 64 characters. After accounting for
325
+ * the connector identifier and separator, 27 characters are available for
326
+ * the ORM name.
327
+ *
328
+ * @param ormPrefix Optional ORM name to prepend (e.g., "prisma")
329
+ * @returns Formatted application_name string
330
+ */
331
+ function buildApplicationName(ormPrefix) {
332
+ if (ormPrefix) {
333
+ const trimmed = ormPrefix.trim();
334
+ if (trimmed) return `${trimmed}:${APPLICATION_NAME}`;
335
+ }
336
+ return APPLICATION_NAME;
337
+ }
79
338
 
80
339
  //#endregion
81
- export { auroraDSQLPostgres };
340
+ export { auroraDSQLPostgres, auroraDSQLWsPostgres };
82
341
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["opts: AuroraDSQLConfig<T>","host: string","username: string","database: string | undefined","ssl: object | boolean | string | undefined","signerConfig: DsqlSignerConfig","postgresOpts: postgres.Options<T>"],"sources":["../src/client.ts"],"sourcesContent":["/*\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport postgres, {PostgresType} from \"postgres\";\nimport {AwsCredentialIdentity, AwsCredentialIdentityProvider} from \"@aws-sdk/types\";\nimport {DsqlSigner, DsqlSignerConfig} from \"@aws-sdk/dsql-signer\";\n\nconst ADMIN = \"admin\";\nconst DEFAULT_DATABASE = \"postgres\";\nconst DEFAULT_EXPIRY = 30; // Based on default Postgres.js connect_timeout\n// String components of a DSQL hostname, <Cluster ID>.dsql.<region>.on.aws\nconst PRE_REGION_HOST_PATTERN = \".dsql.\";\nconst POST_REGION_HOST_PATTERN = \".on.aws\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport function auroraDSQLPostgres<T extends Record<string, postgres.PostgresType> = {}>(\n url: string,\n options?: AuroraDSQLConfig<T>\n): postgres.Sql<Record<string, postgres.PostgresType> extends T ? {} : {\n [type in keyof T]: T[type] extends {\n serialize: (value: infer R) => any,\n parse: (raw: any) => infer R\n } ? R : never\n}>;\n\nexport function auroraDSQLPostgres<T extends Record<string, postgres.PostgresType> = {}>(\n options: AuroraDSQLConfig<T>\n): postgres.Sql<Record<string, postgres.PostgresType> extends T ? {} : {\n [type in keyof T]: T[type] extends {\n serialize: (value: infer R) => any,\n parse: (raw: any) => infer R\n } ? R : never\n}>;\n\nexport function auroraDSQLPostgres<T extends Record<string, postgres.PostgresType> = {}>(\n urlOrOptions: string | AuroraDSQLConfig<T>,\n options?: AuroraDSQLConfig<T>\n): postgres.Sql<Record<string, postgres.PostgresType> extends T ? {} : {\n [type in keyof T]: T[type] extends {\n serialize: (value: infer R) => any,\n parse: (raw: any) => infer R\n } ? R : never\n}> {\n/* eslint-enable @typescript-eslint/no-explicit-any */\n let opts: AuroraDSQLConfig<T>;\n let host: string;\n let username: string;\n let database: string | undefined;\n let ssl: object | boolean | string | undefined;\n if (typeof urlOrOptions === 'string') {\n // Called with (url, options)\n let parsedOptions = parseConnectionString(urlOrOptions);\n host = options?.hostname || options?.host || parsedOptions.host || process.env.PGHOST!;\n username = options?.username || options?.user || parsedOptions.username! || process.env.PGUSERNAME || process.env.USER || ADMIN;\n database = options?.database || options?.db || parsedOptions.database || process.env.PGDATABASE;\n ssl = options?.ssl || parsedOptions.ssl;\n opts = {...options!};\n } else {\n // Called with (options) only\n host = urlOrOptions?.hostname || urlOrOptions?.host || process.env.PGHOST!;\n username = urlOrOptions?.username || urlOrOptions?.user || process.env.PGUSERNAME || process.env.USER || ADMIN;\n database = urlOrOptions?.database || urlOrOptions?.db || process.env.PGDATABASE;\n ssl = urlOrOptions?.ssl;\n opts = {...urlOrOptions!};\n }\n if (Array.isArray(host)) {\n throw new Error('Multi-host configurations are not supported for Aurora DSQL');\n }\n let region = opts.region || parseRegionFromHost(host);\n if (isClusterID(host)) {\n host = buildHostnameFromIdAndRegion(host, region);\n opts.host = host;\n }\n let signerConfig: DsqlSignerConfig = {\n hostname: host,\n region: opts.region || parseRegionFromHost(host),\n expiresIn: opts.tokenDurationSecs ?? opts.connect_timeout ?? (process.env.PGCONNECT_TIMEOUT ? parseInt(process.env.PGCONNECT_TIMEOUT) : undefined) ?? DEFAULT_EXPIRY,\n profile: opts.profile || process.env.AWS_PROFILE || \"default\",\n };\n if (opts.customCredentialsProvider) {\n signerConfig.credentials = opts.customCredentialsProvider;\n }\n let signer = new DsqlSigner(signerConfig);\n if (!database) opts.database = DEFAULT_DATABASE;\n if (!ssl) opts.ssl = true;\n const postgresOpts: postgres.Options<T> = {\n ...opts,\n pass: () => getToken(signer, username),\n };\n return typeof urlOrOptions === 'string' ? postgres(urlOrOptions, postgresOpts) : postgres(postgresOpts);\n}\n\nfunction parseConnectionString(url: string): {\n database?: string;\n host?: string;\n username?: string;\n ssl?: string;\n} {\n let decodedUrl = decodeURI(url);\n const parsed = new URL(decodedUrl);\n\n // Check for multi-host\n if (parsed.hostname?.includes(',')) {\n throw new Error('Multi-host connection strings are not supported for Aurora DSQL');\n }\n\n return {\n username: parsed.username,\n host: parsed.hostname,\n database: parsed.pathname?.slice(1),\n ssl: parsed.searchParams.get(\"ssl\") || parsed.searchParams.get(\"sslmode\") || undefined,\n };\n}\n\nfunction parseRegionFromHost(host: string): string | undefined {\n if (!host) {\n throw new Error(\"Hostname is required to parse region\");\n }\n\n const match = host.match(/^(?<instance>[^.]+)\\.(?<dns>dsql(?:-[^.]+)?)\\.(?<domain>(?<region>[a-zA-Z0-9-]+)\\.on\\.aws\\.?)$/i);\n if (match?.groups) {\n return match.groups.region;\n }\n throw new Error(`Unable to parse region from hostname: ${host}`);\n}\n\nfunction isClusterID(host: string) {\n return !host.includes(\".\");\n}\n\nfunction buildHostnameFromIdAndRegion(host: string, region: string | undefined) {\n return host + PRE_REGION_HOST_PATTERN + region + POST_REGION_HOST_PATTERN;\n}\n\nasync function getToken(signer: DsqlSigner, username: string): Promise<string> {\n if (username === ADMIN) {\n return await signer.getDbConnectAdminAuthToken();\n } else {\n return await signer.getDbConnectAuthToken();\n }\n}\n\nexport interface AuroraDSQLConfig<T extends Record<string, PostgresType<T>>> extends Omit<postgres.Options<T>, 'password' | 'pass'> {\n\n region?: string;\n\n profile?: string;\n\n tokenDurationSecs?: number;\n\n customCredentialsProvider?: AwsCredentialIdentity | AwsCredentialIdentityProvider;\n\n}"],"mappings":";;;;AAQA,MAAM,QAAQ;AACd,MAAM,mBAAmB;AACzB,MAAM,iBAAiB;AAEvB,MAAM,0BAA0B;AAChC,MAAM,2BAA2B;AAsBjC,SAAgB,mBACZ,cACA,SAMD;CAEC,IAAIA;CACJ,IAAIC;CACJ,IAAIC;CACJ,IAAIC;CACJ,IAAIC;AACJ,KAAI,OAAO,iBAAiB,UAAU;EAElC,IAAI,gBAAgB,sBAAsB,aAAa;AACvD,SAAO,SAAS,YAAY,SAAS,QAAQ,cAAc,QAAQ,QAAQ,IAAI;AAC/E,aAAW,SAAS,YAAY,SAAS,QAAQ,cAAc,YAAa,QAAQ,IAAI,cAAc,QAAQ,IAAI,QAAQ;AAC1H,aAAW,SAAS,YAAY,SAAS,MAAM,cAAc,YAAY,QAAQ,IAAI;AACrF,QAAM,SAAS,OAAO,cAAc;AACpC,SAAO,EAAC,GAAG,SAAS;QACjB;AAEH,SAAO,cAAc,YAAY,cAAc,QAAQ,QAAQ,IAAI;AACnE,aAAW,cAAc,YAAY,cAAc,QAAQ,QAAQ,IAAI,cAAc,QAAQ,IAAI,QAAQ;AACzG,aAAW,cAAc,YAAY,cAAc,MAAM,QAAQ,IAAI;AACrE,QAAM,cAAc;AACpB,SAAO,EAAC,GAAG,cAAc;;AAE7B,KAAI,MAAM,QAAQ,KAAK,CACnB,OAAM,IAAI,MAAM,8DAA8D;CAElF,IAAI,SAAS,KAAK,UAAU,oBAAoB,KAAK;AACrD,KAAI,YAAY,KAAK,EAAE;AACnB,SAAO,6BAA6B,MAAM,OAAO;AACjD,OAAK,OAAO;;CAEhB,IAAIC,eAAiC;EACjC,UAAU;EACV,QAAQ,KAAK,UAAU,oBAAoB,KAAK;EAChD,WAAW,KAAK,qBAAqB,KAAK,oBAAoB,QAAQ,IAAI,oBAAoB,SAAS,QAAQ,IAAI,kBAAkB,GAAG,WAAc;EACtJ,SAAS,KAAK,WAAW,QAAQ,IAAI,eAAe;EACvD;AACD,KAAI,KAAK,0BACL,cAAa,cAAc,KAAK;CAEpC,IAAI,SAAS,IAAI,WAAW,aAAa;AACzC,KAAI,CAAC,SAAU,MAAK,WAAW;AAC/B,KAAI,CAAC,IAAK,MAAK,MAAM;CACrB,MAAMC,eAAoC;EACtC,GAAG;EACH,YAAY,SAAS,QAAQ,SAAS;EACzC;AACD,QAAO,OAAO,iBAAiB,WAAW,SAAS,cAAc,aAAa,GAAG,SAAS,aAAa;;AAG3G,SAAS,sBAAsB,KAK7B;CACE,IAAI,aAAa,UAAU,IAAI;CAC/B,MAAM,SAAS,IAAI,IAAI,WAAW;AAGlC,KAAI,OAAO,UAAU,SAAS,IAAI,CAC9B,OAAM,IAAI,MAAM,kEAAkE;AAGtF,QAAO;EACH,UAAU,OAAO;EACjB,MAAM,OAAO;EACb,UAAU,OAAO,UAAU,MAAM,EAAE;EACnC,KAAK,OAAO,aAAa,IAAI,MAAM,IAAI,OAAO,aAAa,IAAI,UAAU,IAAI;EAChF;;AAGL,SAAS,oBAAoB,MAAkC;AAC3D,KAAI,CAAC,KACD,OAAM,IAAI,MAAM,uCAAuC;CAG3D,MAAM,QAAQ,KAAK,MAAM,kGAAkG;AAC3H,KAAI,OAAO,OACP,QAAO,MAAM,OAAO;AAExB,OAAM,IAAI,MAAM,yCAAyC,OAAO;;AAGpE,SAAS,YAAY,MAAc;AAC/B,QAAO,CAAC,KAAK,SAAS,IAAI;;AAG9B,SAAS,6BAA6B,MAAc,QAA4B;AAC5E,QAAO,OAAO,0BAA0B,SAAS;;AAGrD,eAAe,SAAS,QAAoB,UAAmC;AAC3E,KAAI,aAAa,MACb,QAAO,MAAM,OAAO,4BAA4B;KAEhD,QAAO,MAAM,OAAO,uBAAuB"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/postgres-web-socket.ts","../src/client.ts"],"sourcesContent":["/*\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { EventEmitter } from \"events\";\nimport { AuroraDSQLWsConfig } from \"./client\";\nimport { Mutex } from \"async-mutex\";\n\nconst HEARTBEAT_TIMEOUT = 5_000; // 5 seconds\n\nconst MESSAGE_CODE_SIMPLE_QUERY = \"Q\".charCodeAt(0);\nconst MESSAGE_CODE_SYNC = \"S\".charCodeAt(0);\nconst MESSAGE_CODE_RFQ = \"Z\".charCodeAt(0);\n\ninterface Query {\n buffer: Buffer | Uint8Array;\n numOfQueries: number;\n isHeartBeat: boolean;\n}\n\nenum ReadyState {\n Closed = 'closed',\n Querying = 'querying',\n Open = 'open'\n}\n\nexport class PostgresWs extends EventEmitter {\n private mutex = new Mutex();\n private mutexRelease: (() => void) | null = null;\n\n private config: AuroraDSQLWsConfig<{}>;\n private ws: WebSocket | null = null;\n private connected: boolean = false;\n\n private disableHeartBeat: boolean = false;\n private heartBeatTimeout: NodeJS.Timeout | null = null;\n private pendingQueries: Query[] = [];\n\n public readyState: ReadyState = ReadyState.Closed;\n\n\n // these parameters are referenced when an Error is thrown\n private host: string;\n private port: number = 443;\n\n constructor(config: AuroraDSQLWsConfig<{}>) {\n super();\n this.config = config;\n this.host = config.host || '';\n }\n\n\n onReadyForQuery() {\n if (this.pendingQueries.length > 0) {\n if (this.pendingQueries[0].numOfQueries > 0) {\n this.pendingQueries[0].numOfQueries--;\n }\n\n // remove the pendingQueries now that we received the reply only if the querycount is at 0\n if (this.pendingQueries[0].numOfQueries <= 0) {\n this.pendingQueries.shift();\n this.readyState = ReadyState.Open;\n this.disableHeartBeat = false;\n this.releaseMutex();\n this.processQueue();\n }\n }\n }\n\n handleHeartBeatResponse(data: Uint8Array): boolean {\n if (this.pendingQueries.length === 0 || !this.pendingQueries[0].isHeartBeat) return false;\n\n const messageType = String.fromCharCode(data[0]);\n\n if (messageType === \"D\") {\n const dataStr = new TextDecoder().decode(data.slice(5));\n // verify that it is from heartbeat\n if (dataStr.includes(\"1\")) {\n clearTimeout(this.heartBeatTimeout!);\n this.heartBeatTimeout = null;\n }\n } else if (messageType === \"Z\") {\n this.onReadyForQuery();\n }\n\n return true;\n }\n\n async connect(): Promise<this> {\n const url = `wss://${this.config.host}:${this.port}`;\n this.ws = new WebSocket(url);\n this.ws.binaryType = \"arraybuffer\";\n\n return new Promise((resolve, reject) => {\n if (this.ws != null) {\n this.ws.onopen = () => {\n this.connected = true;\n this.readyState = ReadyState.Open;\n resolve(this);\n };\n\n this.ws.onmessage = (event: MessageEvent) => {\n const data = new Uint8Array(event.data);\n\n if (this.config.connectionCheck) {\n if (this.handleHeartBeatResponse(data)) return;\n\n if (data.length > 0 && data[0] === MESSAGE_CODE_RFQ) {\n\n if (data.length > 5) {\n const status = String.fromCharCode(data[5]);\n\n if (status === \"E\") {\n // temporarily disable heart beat when the connection has a transaction error\n this.disableHeartBeat = true;\n this.cleanUpTxErrorState();\n } else {\n // I (IDLE) or T (Transaction) \n this.onReadyForQuery();\n }\n }\n }\n }\n\n this.emit(\"data\", Buffer.from(data));\n };\n\n this.ws.onerror = (event: Event) => {\n const msg = (event as ErrorEvent).message || \"WebSocket error\";\n const error = new Error(`${msg} ${this.host}:${this.port}`);\n this.emit(\"error\", error);\n reject(error);\n };\n\n this.ws.onclose = () => {\n if (this.heartBeatTimeout) {\n clearTimeout(this.heartBeatTimeout);\n this.heartBeatTimeout = null;\n }\n\n this.releaseMutex();\n\n this.connected = false;\n this.readyState = ReadyState.Closed;\n this.ws = null;\n this.emit(\"close\");\n\n if (this.config.onReservedConnectionClose) {\n this.config.onReservedConnectionClose(this.config.connectionId);\n }\n };\n }\n });\n }\n\n createQueryBuffer(sql: string): Uint8Array {\n const sqlBytes = new TextEncoder().encode(sql + \"\\0\");\n const length = 4 + sqlBytes.length;\n const buf = new Uint8Array(1 + length);\n const view = new DataView(buf.buffer);\n\n buf[0] = MESSAGE_CODE_SIMPLE_QUERY;\n view.setInt32(1, length, false);\n buf.set(sqlBytes, 5);\n\n return buf;\n }\n\n // future proofing in case postgres.js starts using the write function with 3 parameters\n // currently the library uses the write function with 2 parameters\n // callback is needed for copy related operations \n write(data: Buffer | Uint8Array, callback?: (err?: Error) => void): boolean;\n write(data: string, encoding?: string, callback?: (err?: Error) => void): boolean;\n\n write(\n data: Buffer | Uint8Array | string,\n encodingOrCallback?: string | ((err?: Error) => void),\n callback?: (err?: Error) => void\n ): boolean {\n\n let callbackFn: ((err?: Error) => void) | undefined;\n\n if (typeof encodingOrCallback === 'function') {\n callbackFn = encodingOrCallback;\n } else {\n callbackFn = callback;\n }\n\n let sendData: Uint8Array;\n if (typeof data === 'string') {\n const encoder = new TextEncoder();\n sendData = encoder.encode(data); // Always UTF-8\n } else if (data instanceof Buffer) {\n sendData = new Uint8Array(data);\n } else {\n sendData = data;\n }\n\n if (!this.ws || !this.connected) {\n if (callbackFn) {\n callbackFn(new Error(\"websocket is not connected\"));\n }\n return false;\n }\n\n let offset = 0;\n\n let queryCount = 0; // simple query \n let hasSync = false; // extended query protocol \n\n while (offset < sendData.length) {\n if (sendData[offset] === MESSAGE_CODE_SIMPLE_QUERY) {\n queryCount++;\n }\n\n if (sendData[offset] === MESSAGE_CODE_SYNC) {\n hasSync = true;\n }\n\n // Read message length to skip to next message\n if (offset + 5 <= sendData.length) {\n const length = new DataView(sendData.buffer, sendData.byteOffset + offset + 1, 4).getInt32(0, false);\n offset += 1 + length;\n } else {\n break;\n }\n }\n\n // directly send message to websocket when \n // * connection check (heart beat) is disabled \n // * Z (ReadyForQuery) message is not expected to be returned\n if (!this.config.connectionCheck || (queryCount == 0 && hasSync === false)) {\n try {\n this.ws.send(sendData);\n if (callbackFn) {\n callbackFn();\n }\n return true;\n } catch (err) {\n if (callbackFn) {\n callbackFn(err as Error);\n }\n return false;\n }\n }\n\n // if the buffer contains a query, send a heart beat first\n if (\n queryCount > 0 &&\n this.config.connectionCheck &&\n this.heartBeatTimeout === null && // make sure no existing heart beat time out is overwritten\n !this.disableHeartBeat\n ) {\n const buf = this.createQueryBuffer(\"select 1;\");\n this.pendingQueries.push({ buffer: buf, numOfQueries: 1, isHeartBeat: true });\n }\n this.pendingQueries.push({ buffer: sendData, numOfQueries: queryCount, isHeartBeat: false });\n this.processQueue();\n\n if (callbackFn) {\n callbackFn();\n }\n\n return true;\n }\n\n private releaseMutex() {\n if (this.mutexRelease) {\n this.mutexRelease();\n this.mutexRelease = null;\n }\n }\n\n // cleans up the error state during a transaction error \n private cleanUpTxErrorState() {\n // throw away last query as the result set has a transaction error and no more result set should return \n if (this.pendingQueries.length > 0) {\n this.pendingQueries.shift();\n }\n\n // since heart beat cant be performed during a transaction error, discard heart beat queries which are already in pending queries\n while (this.pendingQueries.length > 0 && this.pendingQueries[0].isHeartBeat) {\n this.pendingQueries.shift();\n }\n this.readyState = ReadyState.Open;\n this.releaseMutex();\n\n if (this.pendingQueries.length > 0) {\n this.processQueue();\n }\n }\n\n private async processQueue(): Promise<void> {\n if (\n this.mutexRelease ||\n this.readyState !== ReadyState.Open ||\n this.pendingQueries.length === 0\n ) {\n return;\n }\n\n this.mutexRelease = await this.mutex.acquire();\n\n // it is possible that the pendingQueries is now empty \n if (this.pendingQueries.length == 0) {\n this.releaseMutex();\n return;\n }\n\n const data = this.pendingQueries[0];\n\n if (data.buffer.length > 0 && data.buffer[0] === MESSAGE_CODE_SIMPLE_QUERY) {\n this.readyState = ReadyState.Querying;\n }\n\n if (data.isHeartBeat) {\n this.heartBeatTimeout = setTimeout(() => {\n console.log(\"Heart beat timed out\");\n if (this.ws) {\n this.ws.close(1000, \"Heart beat timeout\");\n }\n }, HEARTBEAT_TIMEOUT);\n }\n\n if (this.ws) {\n this.ws.send(data.buffer);\n } else {\n throw Error(\"Websocket is not initialized\");\n }\n }\n\n end(): void {\n if (this.ws && this.readyState !== ReadyState.Closed) {\n this.ws.close();\n }\n }\n\n destroy(): void {\n if (this.ws) {\n this.ws.close();\n }\n }\n\n // Following functions needs to be defined as connection.js \n // in postgres.js can call these functions but they will be no-op\n setKeepAlive(): this {\n return this;\n }\n\n resume(): this {\n return this;\n }\n\n pause(): this {\n return this;\n }\n\n cork(): this {\n return this;\n }\n\n uncork(): this {\n return this;\n }\n}\n\nexport function createPostgresWs(\n config: AuroraDSQLWsConfig<{}>\n): () => Promise<PostgresWs> {\n return async () => {\n\n const socket = new PostgresWs(config);\n await socket.connect();\n return socket;\n };\n}\n","/*\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport postgres, { PostgresType } from \"postgres\";\nimport {\n AwsCredentialIdentity,\n AwsCredentialIdentityProvider,\n} from \"@aws-sdk/types\";\nimport { DsqlSigner, DsqlSignerConfig } from \"@aws-sdk/dsql-signer\";\nimport { createPostgresWs } from \"./postgres-web-socket\";\n\n// Version is injected at build time via tsdown\ndeclare const __VERSION__: string;\nconst version = typeof __VERSION__ !== \"undefined\" ? __VERSION__ : \"0.0.0\";\n\nconst ADMIN = \"admin\";\nconst DEFAULT_DATABASE = \"postgres\";\nconst DEFAULT_EXPIRY = 30; // Based on default Postgres.js connect_timeout\n// String components of a DSQL hostname, <Cluster ID>.dsql.<region>.on.aws\nconst PRE_REGION_HOST_PATTERN = \".dsql.\";\nconst POST_REGION_HOST_PATTERN = \".on.aws\";\nconst APPLICATION_NAME = `aurora-dsql-nodejs-postgresjs/${version}`;\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nfunction parseConnectionParams(\n urlOrOptions: string | any,\n options?: any\n): { opts: any; } {\n let opts: any;\n let host: string;\n let username: string;\n let database: string | undefined;\n\n if (typeof urlOrOptions === \"string\") {\n let parsedOptions = parseConnectionString(urlOrOptions);\n host = options?.hostname || options?.host || parsedOptions.host || process.env.PGHOST!;\n username = options?.username || options?.user || parsedOptions.username! ||\n process.env.PGUSERNAME || process.env.USER || ADMIN;\n database = options?.database || options?.db || parsedOptions.database || process.env.PGDATABASE;\n opts = {\n ...options,\n ssl: options?.ssl || parsedOptions.ssl\n };\n } else {\n host = urlOrOptions?.hostname || urlOrOptions?.host || process.env.PGHOST!;\n username = urlOrOptions?.username || urlOrOptions?.user ||\n process.env.PGUSERNAME || process.env.USER || ADMIN;\n database = urlOrOptions?.database || urlOrOptions?.db || process.env.PGDATABASE;\n opts = { ...urlOrOptions };\n }\n\n if (Array.isArray(host)) {\n throw new Error(\"Multi-host configurations are not supported for Aurora DSQL\");\n }\n\n if (!opts.region) {\n opts.region = parseRegionFromHost(host);\n }\n\n if (isClusterID(host)) {\n host = buildHostnameFromIdAndRegion(host, opts.region);\n }\n\n if (!database) {\n opts.database = DEFAULT_DATABASE;\n }\n\n opts.host = host;\n opts.username = username;\n opts.connection = {\n ...opts.connection,\n application_name: buildApplicationName(opts.connection?.application_name),\n };\n\n return { opts };\n}\n\nfunction setupDsqlSigner(opts: any): { signerConfig: DsqlSignerConfig; } {\n\n let signerConfig: DsqlSignerConfig = {\n hostname: opts.host,\n region: opts.region,\n expiresIn: opts.tokenDurationSecs ?? opts.connect_timeout ??\n (process.env.PGCONNECT_TIMEOUT ? parseInt(process.env.PGCONNECT_TIMEOUT) : undefined) ??\n DEFAULT_EXPIRY,\n profile: opts.profile || process.env.AWS_PROFILE || \"default\",\n };\n\n if (opts.customCredentialsProvider) {\n signerConfig.credentials = opts.customCredentialsProvider;\n }\n\n return { signerConfig };\n}\n\nexport function auroraDSQLPostgres<\n T extends Record<string, postgres.PostgresType> = {}\n>(\n url: string,\n options?: AuroraDSQLConfig<T>\n): postgres.Sql<\n Record<string, postgres.PostgresType> extends T\n ? {}\n : {\n [type in keyof T]: T[type] extends {\n serialize: (value: infer R) => any;\n parse: (raw: any) => infer R;\n }\n ? R\n : never;\n }\n>;\n\nexport function auroraDSQLPostgres<\n T extends Record<string, postgres.PostgresType> = {}\n>(\n options: AuroraDSQLConfig<T>\n): postgres.Sql<\n Record<string, postgres.PostgresType> extends T\n ? {}\n : {\n [type in keyof T]: T[type] extends {\n serialize: (value: infer R) => any;\n parse: (raw: any) => infer R;\n }\n ? R\n : never;\n }\n>;\n\nexport function auroraDSQLPostgres<\n T extends Record<string, postgres.PostgresType> = {}\n>(\n urlOrOptions: string | AuroraDSQLConfig<T>,\n options?: AuroraDSQLConfig<T>\n): postgres.Sql<\n Record<string, postgres.PostgresType> extends T\n ? {}\n : {\n [type in keyof T]: T[type] extends {\n serialize: (value: infer R) => any;\n parse: (raw: any) => infer R;\n }\n ? R\n : never;\n }\n> {\n\n let { opts } = parseConnectionParams(urlOrOptions, options);\n const { signerConfig } = setupDsqlSigner(opts);\n let signer = new DsqlSigner(signerConfig);\n\n if (!opts.ssl) opts.ssl = true;\n const postgresOpts: postgres.Options<T> = {\n ...opts,\n pass: () => getToken(signer, opts.username),\n };\n return typeof urlOrOptions === \"string\"\n ? postgres(urlOrOptions, postgresOpts)\n : postgres(postgresOpts);\n}\n\nexport function auroraDSQLWsPostgres<\n T extends Record<string, postgres.PostgresType> = {}\n>(\n url: string,\n options?: AuroraDSQLWsConfig<T>\n): postgres.Sql<\n Record<string, postgres.PostgresType> extends T\n ? {}\n : {\n [type in keyof T]: T[type] extends {\n serialize: (value: infer R) => any;\n parse: (raw: any) => infer R;\n }\n ? R\n : never;\n }\n>;\n\nexport function auroraDSQLWsPostgres<\n T extends Record<string, postgres.PostgresType> = {}\n>(\n options: AuroraDSQLWsConfig<T>\n): postgres.Sql<\n Record<string, postgres.PostgresType> extends T\n ? {}\n : {\n [type in keyof T]: T[type] extends {\n serialize: (value: infer R) => any;\n parse: (raw: any) => infer R;\n }\n ? R\n : never;\n }\n>;\n\nexport function auroraDSQLWsPostgres<\n T extends Record<string, postgres.PostgresType> = {}\n>(\n urlOrOptions: string | AuroraDSQLWsConfig<T>,\n options?: AuroraDSQLWsConfig<T>\n): postgres.Sql<\n Record<string, postgres.PostgresType> extends T\n ? {}\n : {\n [type in keyof T]: T[type] extends {\n serialize: (value: infer R) => any;\n parse: (raw: any) => infer R;\n }\n ? R\n : never;\n }\n> {\n\n let { opts } = parseConnectionParams(urlOrOptions, options);\n const { signerConfig } = setupDsqlSigner(opts);\n\n if (!opts.pass) {\n opts.pass = async () => {\n let signer = new DsqlSigner(signerConfig);\n return await getToken(signer, opts.username);\n };\n }\n\n // swap out socket to use websocket\n opts.socket = createPostgresWs(opts);\n\n // ssl must be false otherwise postgres.js will try to use the net.socket \n opts.ssl = false;\n\n if (opts.connectionCheck == undefined) {\n // disable connection check by default \n // connection check sends a 'select 1' before every query\n opts.connectionCheck = false;\n }\n\n opts.port = 443;\n\n return typeof urlOrOptions === \"string\"\n ? postgres(urlOrOptions, opts)\n : postgres(opts);\n}\n\n\nfunction parseConnectionString(url: string): {\n database?: string;\n host?: string;\n username?: string;\n ssl?: string;\n} {\n let decodedUrl = decodeURI(url);\n const parsed = new URL(decodedUrl);\n\n // Check for multi-host\n if (parsed.hostname?.includes(\",\")) {\n throw new Error(\n \"Multi-host connection strings are not supported for Aurora DSQL\"\n );\n }\n\n return {\n username: parsed.username,\n host: parsed.hostname,\n database: parsed.pathname?.slice(1),\n ssl:\n parsed.searchParams.get(\"ssl\") ||\n parsed.searchParams.get(\"sslmode\") ||\n undefined,\n };\n}\n\nfunction parseRegionFromHost(host: string): string | undefined {\n if (!host) {\n throw new Error(\"Hostname is required to parse region\");\n }\n\n const match = host.match(\n /^(?<instance>[^.]+)\\.(?<dns>dsql(?:-[^.]+)?)\\.(?<domain>(?<region>[a-zA-Z0-9-]+)\\.on\\.aws\\.?)$/i\n );\n if (match?.groups) {\n return match.groups.region;\n }\n throw new Error(`Unable to parse region from hostname: ${host}`);\n}\n\nfunction isClusterID(host: string) {\n return !host.includes(\".\");\n}\n\nfunction buildHostnameFromIdAndRegion(\n host: string,\n region: string | undefined\n) {\n return host + PRE_REGION_HOST_PATTERN + region + POST_REGION_HOST_PATTERN;\n}\n\nasync function getToken(signer: DsqlSigner, username: string): Promise<string> {\n if (username === ADMIN) {\n return await signer.getDbConnectAdminAuthToken();\n } else {\n return await signer.getDbConnectAuthToken();\n }\n}\n\n/**\n * Build the application_name with optional ORM prefix.\n *\n * If ormPrefix is provided and non-empty after trimming, prepends it to\n * the connector identifier. Otherwise, returns the connector's application_name.\n *\n * PostgreSQL limits application_name to 64 characters. After accounting for\n * the connector identifier and separator, 27 characters are available for\n * the ORM name.\n *\n * @param ormPrefix Optional ORM name to prepend (e.g., \"prisma\")\n * @returns Formatted application_name string\n */\nfunction buildApplicationName(ormPrefix?: string): string {\n if (ormPrefix) {\n const trimmed = ormPrefix.trim();\n if (trimmed) {\n return `${trimmed}:${APPLICATION_NAME}`;\n }\n }\n return APPLICATION_NAME;\n}\n\nexport interface AuroraDSQLConfig<T extends Record<string, PostgresType<T>>> extends Omit<postgres.Options<T>, 'password' | 'pass'> {\n\n region?: string;\n\n profile?: string;\n\n tokenDurationSecs?: number;\n\n customCredentialsProvider?: AwsCredentialIdentity | AwsCredentialIdentityProvider;\n\n}\nexport interface AuroraDSQLWsConfig<T extends Record<string, PostgresType<T>>>\n extends Omit<postgres.Options<T>, \"socket\" | \"ssl\" | \"port\"> {\n region?: string;\n tokenDurationSecs?: number;\n customCredentialsProvider?:\n | AwsCredentialIdentity\n | AwsCredentialIdentityProvider;\n connectionCheck?: boolean;\n connectionId?: string;\n onReservedConnectionClose?: (connectionId?: string) => void;\n}\n"],"mappings":";;;;;;AASA,MAAM,oBAAoB;AAE1B,MAAM,4BAA4B,IAAI,WAAW,EAAE;AACnD,MAAM,oBAAoB,IAAI,WAAW,EAAE;AAC3C,MAAM,mBAAmB,IAAI,WAAW,EAAE;AAQ1C,IAAK,kDAAL;AACE;AACA;AACA;;EAHG;AAML,IAAa,aAAb,cAAgC,aAAa;CAmB3C,YAAY,QAAgC;AAC1C,SAAO;eAnBO,IAAI,OAAO;sBACiB;YAGb;mBACF;0BAEO;0BACc;wBAChB,EAAE;oBAEJ,WAAW;cAKpB;AAIrB,OAAK,SAAS;AACd,OAAK,OAAO,OAAO,QAAQ;;CAI7B,kBAAkB;AAChB,MAAI,KAAK,eAAe,SAAS,GAAG;AAClC,OAAI,KAAK,eAAe,GAAG,eAAe,EACxC,MAAK,eAAe,GAAG;AAIzB,OAAI,KAAK,eAAe,GAAG,gBAAgB,GAAG;AAC5C,SAAK,eAAe,OAAO;AAC3B,SAAK,aAAa,WAAW;AAC7B,SAAK,mBAAmB;AACxB,SAAK,cAAc;AACnB,SAAK,cAAc;;;;CAKzB,wBAAwB,MAA2B;AACjD,MAAI,KAAK,eAAe,WAAW,KAAK,CAAC,KAAK,eAAe,GAAG,YAAa,QAAO;EAEpF,MAAM,cAAc,OAAO,aAAa,KAAK,GAAG;AAEhD,MAAI,gBAAgB,KAGlB;OAFgB,IAAI,aAAa,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC,CAE3C,SAAS,IAAI,EAAE;AACzB,iBAAa,KAAK,iBAAkB;AACpC,SAAK,mBAAmB;;aAEjB,gBAAgB,IACzB,MAAK,iBAAiB;AAGxB,SAAO;;CAGT,MAAM,UAAyB;EAC7B,MAAM,MAAM,SAAS,KAAK,OAAO,KAAK,GAAG,KAAK;AAC9C,OAAK,KAAK,IAAI,UAAU,IAAI;AAC5B,OAAK,GAAG,aAAa;AAErB,SAAO,IAAI,SAAS,SAAS,WAAW;AACtC,OAAI,KAAK,MAAM,MAAM;AACnB,SAAK,GAAG,eAAe;AACrB,UAAK,YAAY;AACjB,UAAK,aAAa,WAAW;AAC7B,aAAQ,KAAK;;AAGf,SAAK,GAAG,aAAa,UAAwB;KAC3C,MAAM,OAAO,IAAI,WAAW,MAAM,KAAK;AAEvC,SAAI,KAAK,OAAO,iBAAiB;AAC/B,UAAI,KAAK,wBAAwB,KAAK,CAAE;AAExC,UAAI,KAAK,SAAS,KAAK,KAAK,OAAO,kBAEjC;WAAI,KAAK,SAAS,EAGhB,KAFe,OAAO,aAAa,KAAK,GAAG,KAE5B,KAAK;AAElB,aAAK,mBAAmB;AACxB,aAAK,qBAAqB;aAG1B,MAAK,iBAAiB;;;AAM9B,UAAK,KAAK,QAAQ,OAAO,KAAK,KAAK,CAAC;;AAGtC,SAAK,GAAG,WAAW,UAAiB;KAClC,MAAM,MAAO,MAAqB,WAAW;KAC7C,MAAM,wBAAQ,IAAI,MAAM,GAAG,IAAI,GAAG,KAAK,KAAK,GAAG,KAAK,OAAO;AAC3D,UAAK,KAAK,SAAS,MAAM;AACzB,YAAO,MAAM;;AAGf,SAAK,GAAG,gBAAgB;AACtB,SAAI,KAAK,kBAAkB;AACzB,mBAAa,KAAK,iBAAiB;AACnC,WAAK,mBAAmB;;AAG1B,UAAK,cAAc;AAEnB,UAAK,YAAY;AACjB,UAAK,aAAa,WAAW;AAC7B,UAAK,KAAK;AACV,UAAK,KAAK,QAAQ;AAElB,SAAI,KAAK,OAAO,0BACd,MAAK,OAAO,0BAA0B,KAAK,OAAO,aAAa;;;IAIrE;;CAGJ,kBAAkB,KAAyB;EACzC,MAAM,WAAW,IAAI,aAAa,CAAC,OAAO,MAAM,KAAK;EACrD,MAAM,SAAS,IAAI,SAAS;EAC5B,MAAM,MAAM,IAAI,WAAW,IAAI,OAAO;EACtC,MAAM,OAAO,IAAI,SAAS,IAAI,OAAO;AAErC,MAAI,KAAK;AACT,OAAK,SAAS,GAAG,QAAQ,MAAM;AAC/B,MAAI,IAAI,UAAU,EAAE;AAEpB,SAAO;;CAST,MACE,MACA,oBACA,UACS;EAET,IAAI;AAEJ,MAAI,OAAO,uBAAuB,WAChC,cAAa;MAEb,cAAa;EAGf,IAAI;AACJ,MAAI,OAAO,SAAS,SAElB,YADgB,IAAI,aAAa,CACd,OAAO,KAAK;WACtB,gBAAgB,OACzB,YAAW,IAAI,WAAW,KAAK;MAE/B,YAAW;AAGb,MAAI,CAAC,KAAK,MAAM,CAAC,KAAK,WAAW;AAC/B,OAAI,WACF,4BAAW,IAAI,MAAM,6BAA6B,CAAC;AAErD,UAAO;;EAGT,IAAI,SAAS;EAEb,IAAI,aAAa;EACjB,IAAI,UAAU;AAEd,SAAO,SAAS,SAAS,QAAQ;AAC/B,OAAI,SAAS,YAAY,0BACvB;AAGF,OAAI,SAAS,YAAY,kBACvB,WAAU;AAIZ,OAAI,SAAS,KAAK,SAAS,QAAQ;IACjC,MAAM,SAAS,IAAI,SAAS,SAAS,QAAQ,SAAS,aAAa,SAAS,GAAG,EAAE,CAAC,SAAS,GAAG,MAAM;AACpG,cAAU,IAAI;SAEd;;AAOJ,MAAI,CAAC,KAAK,OAAO,mBAAoB,cAAc,KAAK,YAAY,MAClE,KAAI;AACF,QAAK,GAAG,KAAK,SAAS;AACtB,OAAI,WACF,aAAY;AAEd,UAAO;WACA,KAAK;AACZ,OAAI,WACF,YAAW,IAAa;AAE1B,UAAO;;AAKX,MACE,aAAa,KACb,KAAK,OAAO,mBACZ,KAAK,qBAAqB,QAC1B,CAAC,KAAK,kBACN;GACA,MAAM,MAAM,KAAK,kBAAkB,YAAY;AAC/C,QAAK,eAAe,KAAK;IAAE,QAAQ;IAAK,cAAc;IAAG,aAAa;IAAM,CAAC;;AAE/E,OAAK,eAAe,KAAK;GAAE,QAAQ;GAAU,cAAc;GAAY,aAAa;GAAO,CAAC;AAC5F,OAAK,cAAc;AAEnB,MAAI,WACF,aAAY;AAGd,SAAO;;CAGT,AAAQ,eAAe;AACrB,MAAI,KAAK,cAAc;AACrB,QAAK,cAAc;AACnB,QAAK,eAAe;;;CAKxB,AAAQ,sBAAsB;AAE5B,MAAI,KAAK,eAAe,SAAS,EAC/B,MAAK,eAAe,OAAO;AAI7B,SAAO,KAAK,eAAe,SAAS,KAAK,KAAK,eAAe,GAAG,YAC9D,MAAK,eAAe,OAAO;AAE7B,OAAK,aAAa,WAAW;AAC7B,OAAK,cAAc;AAEnB,MAAI,KAAK,eAAe,SAAS,EAC/B,MAAK,cAAc;;CAIvB,MAAc,eAA8B;AAC1C,MACE,KAAK,gBACL,KAAK,eAAe,WAAW,QAC/B,KAAK,eAAe,WAAW,EAE/B;AAGF,OAAK,eAAe,MAAM,KAAK,MAAM,SAAS;AAG9C,MAAI,KAAK,eAAe,UAAU,GAAG;AACnC,QAAK,cAAc;AACnB;;EAGF,MAAM,OAAO,KAAK,eAAe;AAEjC,MAAI,KAAK,OAAO,SAAS,KAAK,KAAK,OAAO,OAAO,0BAC/C,MAAK,aAAa,WAAW;AAG/B,MAAI,KAAK,YACP,MAAK,mBAAmB,iBAAiB;AACvC,WAAQ,IAAI,uBAAuB;AACnC,OAAI,KAAK,GACP,MAAK,GAAG,MAAM,KAAM,qBAAqB;KAE1C,kBAAkB;AAGvB,MAAI,KAAK,GACP,MAAK,GAAG,KAAK,KAAK,OAAO;MAEzB,OAAM,MAAM,+BAA+B;;CAI/C,MAAY;AACV,MAAI,KAAK,MAAM,KAAK,eAAe,WAAW,OAC5C,MAAK,GAAG,OAAO;;CAInB,UAAgB;AACd,MAAI,KAAK,GACP,MAAK,GAAG,OAAO;;CAMnB,eAAqB;AACnB,SAAO;;CAGT,SAAe;AACb,SAAO;;CAGT,QAAc;AACZ,SAAO;;CAGT,OAAa;AACX,SAAO;;CAGT,SAAe;AACb,SAAO;;;AAIX,SAAgB,iBACd,QAC2B;AAC3B,QAAO,YAAY;EAEjB,MAAM,SAAS,IAAI,WAAW,OAAO;AACrC,QAAM,OAAO,SAAS;AACtB,SAAO;;;;;;ACxWX,MAAM;AAEN,MAAM,QAAQ;AACd,MAAM,mBAAmB;AACzB,MAAM,iBAAiB;AAEvB,MAAM,0BAA0B;AAChC,MAAM,2BAA2B;AACjC,MAAM,mBAAmB,iCAAiC;AAG1D,SAAS,sBACP,cACA,SACgB;CAChB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AAEJ,KAAI,OAAO,iBAAiB,UAAU;EACpC,IAAI,gBAAgB,sBAAsB,aAAa;AACvD,SAAO,SAAS,YAAY,SAAS,QAAQ,cAAc,QAAQ,QAAQ,IAAI;AAC/E,aAAW,SAAS,YAAY,SAAS,QAAQ,cAAc,YAC7D,QAAQ,IAAI,cAAc,QAAQ,IAAI,QAAQ;AAChD,aAAW,SAAS,YAAY,SAAS,MAAM,cAAc,YAAY,QAAQ,IAAI;AACrF,SAAO;GACL,GAAG;GACH,KAAK,SAAS,OAAO,cAAc;GACpC;QACI;AACL,SAAO,cAAc,YAAY,cAAc,QAAQ,QAAQ,IAAI;AACnE,aAAW,cAAc,YAAY,cAAc,QACjD,QAAQ,IAAI,cAAc,QAAQ,IAAI,QAAQ;AAChD,aAAW,cAAc,YAAY,cAAc,MAAM,QAAQ,IAAI;AACrE,SAAO,EAAE,GAAG,cAAc;;AAG5B,KAAI,MAAM,QAAQ,KAAK,CACrB,OAAM,IAAI,MAAM,8DAA8D;AAGhF,KAAI,CAAC,KAAK,OACR,MAAK,SAAS,oBAAoB,KAAK;AAGzC,KAAI,YAAY,KAAK,CACnB,QAAO,6BAA6B,MAAM,KAAK,OAAO;AAGxD,KAAI,CAAC,SACH,MAAK,WAAW;AAGlB,MAAK,OAAO;AACZ,MAAK,WAAW;AAChB,MAAK,aAAa;EAChB,GAAG,KAAK;EACR,kBAAkB,qBAAqB,KAAK,YAAY,iBAAiB;EAC1E;AAED,QAAO,EAAE,MAAM;;AAGjB,SAAS,gBAAgB,MAAgD;CAEvE,IAAI,eAAiC;EACnC,UAAU,KAAK;EACf,QAAQ,KAAK;EACb,WAAW,KAAK,qBAAqB,KAAK,oBACvC,QAAQ,IAAI,oBAAoB,SAAS,QAAQ,IAAI,kBAAkB,GAAG,WAC3E;EACF,SAAS,KAAK,WAAW,QAAQ,IAAI,eAAe;EACrD;AAED,KAAI,KAAK,0BACP,cAAa,cAAc,KAAK;AAGlC,QAAO,EAAE,cAAc;;AAsCzB,SAAgB,mBAGd,cACA,SAYA;CAEA,IAAI,EAAE,SAAS,sBAAsB,cAAc,QAAQ;CAC3D,MAAM,EAAE,iBAAiB,gBAAgB,KAAK;CAC9C,IAAI,SAAS,IAAI,WAAW,aAAa;AAEzC,KAAI,CAAC,KAAK,IAAK,MAAK,MAAM;CAC1B,MAAM,eAAoC;EACxC,GAAG;EACH,YAAY,SAAS,QAAQ,KAAK,SAAS;EAC5C;AACD,QAAO,OAAO,iBAAiB,WAC3B,SAAS,cAAc,aAAa,GACpC,SAAS,aAAa;;AAsC5B,SAAgB,qBAGd,cACA,SAYA;CAEA,IAAI,EAAE,SAAS,sBAAsB,cAAc,QAAQ;CAC3D,MAAM,EAAE,iBAAiB,gBAAgB,KAAK;AAE9C,KAAI,CAAC,KAAK,KACR,MAAK,OAAO,YAAY;AAEtB,SAAO,MAAM,SADA,IAAI,WAAW,aAAa,EACX,KAAK,SAAS;;AAKhD,MAAK,SAAS,iBAAiB,KAAK;AAGpC,MAAK,MAAM;AAEX,KAAI,KAAK,mBAAmB,OAG1B,MAAK,kBAAkB;AAGzB,MAAK,OAAO;AAEZ,QAAO,OAAO,iBAAiB,WAC3B,SAAS,cAAc,KAAK,GAC5B,SAAS,KAAK;;AAIpB,SAAS,sBAAsB,KAK7B;CACA,IAAI,aAAa,UAAU,IAAI;CAC/B,MAAM,SAAS,IAAI,IAAI,WAAW;AAGlC,KAAI,OAAO,UAAU,SAAS,IAAI,CAChC,OAAM,IAAI,MACR,kEACD;AAGH,QAAO;EACL,UAAU,OAAO;EACjB,MAAM,OAAO;EACb,UAAU,OAAO,UAAU,MAAM,EAAE;EACnC,KACE,OAAO,aAAa,IAAI,MAAM,IAC9B,OAAO,aAAa,IAAI,UAAU,IAClC;EACH;;AAGH,SAAS,oBAAoB,MAAkC;AAC7D,KAAI,CAAC,KACH,OAAM,IAAI,MAAM,uCAAuC;CAGzD,MAAM,QAAQ,KAAK,MACjB,kGACD;AACD,KAAI,OAAO,OACT,QAAO,MAAM,OAAO;AAEtB,OAAM,IAAI,MAAM,yCAAyC,OAAO;;AAGlE,SAAS,YAAY,MAAc;AACjC,QAAO,CAAC,KAAK,SAAS,IAAI;;AAG5B,SAAS,6BACP,MACA,QACA;AACA,QAAO,OAAO,0BAA0B,SAAS;;AAGnD,eAAe,SAAS,QAAoB,UAAmC;AAC7E,KAAI,aAAa,MACf,QAAO,MAAM,OAAO,4BAA4B;KAEhD,QAAO,MAAM,OAAO,uBAAuB;;;;;;;;;;;;;;;AAiB/C,SAAS,qBAAqB,WAA4B;AACxD,KAAI,WAAW;EACb,MAAM,UAAU,UAAU,MAAM;AAChC,MAAI,QACF,QAAO,GAAG,QAAQ,GAAG;;AAGzB,QAAO"}
package/package.json CHANGED
@@ -1,14 +1,23 @@
1
1
  {
2
2
  "name": "@aws/aurora-dsql-postgresjs-connector",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "description": "An AWS Aurora DSQL connector with IAM authentication for Postgres.js",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git+https://github.com/awslabs/aurora-dsql-nodejs-connector.git"
8
+ "url": "git+https://github.com/awslabs/aurora-dsql-connectors.git",
9
+ "directory": "node/postgres-js"
9
10
  },
10
- "homepage": "https://github.com/awslabs/aurora-dsql-nodejs-connector",
11
- "keywords": ["aws", "aurora", "dsql", "postgres", "database", "iam", "authentication"],
11
+ "homepage": "https://github.com/awslabs/aurora-dsql-connectors/tree/main/node/postgres-js",
12
+ "keywords": [
13
+ "aws",
14
+ "aurora",
15
+ "dsql",
16
+ "postgres",
17
+ "database",
18
+ "iam",
19
+ "authentication"
20
+ ],
12
21
  "publishConfig": {
13
22
  "access": "public"
14
23
  },
@@ -50,7 +59,8 @@
50
59
  "dependencies": {
51
60
  "@aws-sdk/credential-providers": "^3.901.0",
52
61
  "@aws-sdk/dsql-signer": "^3.940.0",
53
- "@aws-sdk/types": "^3.901.0"
62
+ "@aws-sdk/types": "^3.901.0",
63
+ "async-mutex": "^0.5.0"
54
64
  },
55
65
  "peerDependencies": {
56
66
  "postgres": "^3.4.7"
@@ -71,7 +81,7 @@
71
81
  "postgres": "^3.4.7",
72
82
  "publint": "^0.3.16",
73
83
  "ts-jest": "^29.4.5",
74
- "tsdown": "^0.18.0",
84
+ "tsdown": "^0.20.2",
75
85
  "typescript": "^5.9.3"
76
86
  }
77
87
  }