@aws/aurora-dsql-postgresjs-connector 0.1.3 → 0.2.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.
package/README.md CHANGED
@@ -118,7 +118,7 @@ const sql = AuroraDSQLPostgres({
118
118
  });
119
119
  ```
120
120
 
121
- ## Configuration Options
121
+ ### Configuration Options
122
122
 
123
123
  | Option | Type | Required | Description |
124
124
  |-----------------------------|----------------------------------|----------|----------------------------------------------------------|
@@ -131,6 +131,63 @@ const sql = AuroraDSQLPostgres({
131
131
 
132
132
  All standard [Postgres.js options](https://github.com/porsager/postgres?tab=readme-ov-file#connection-details) are also supported.
133
133
 
134
+ ## Websocket Connector
135
+ The websocket connector provides an alternative connection method to Aurora DSQL using WebSockets instead of standard TCP sockets. This approach is designed to work in use cases where TCP sockets are not provided by the platform. For Node.js server applications, use the standard TCP socket connector shown above.
136
+
137
+ ### Use cases
138
+ - Browser Compatibility - Web browsers don't support raw TCP sockets (Node.js net module). WebSockets are a common way to establish persistent database connections from browser-based applications.
139
+
140
+ - Simplified Architecture - Eliminates the need for a separate backend API layer when building prototypes or internal tools, allowing direct browser-to-database connections.
141
+
142
+ ### AWS Credentials
143
+ - DSQL access tokens are not secrets and can be accessed by the user in the browser
144
+ - Access tokens should be time limited, and use a role with access permissions that are scoped to data accessible by that user
145
+
146
+ ### Basic Usage
147
+
148
+ ```typescript
149
+ import type { AwsCredentialIdentity } from '@aws-sdk/types';
150
+ import { auroraDSQLWsPostgres, AuroraDSQLWsConfig } from '@aws/aurora-dsql-postgresjs-connector';
151
+
152
+ // For testing only, DO NOT USE in a production environment
153
+ const simulateSecureGetCredentialsAPI = (): Promise<AwsCredentialIdentity> => {
154
+ // Users must retrieve the AwsCredentialIdentity through a secure API
155
+ // DO NOT store the IAM accessKeyId and secretAccessKey inside the JavaScript source code
156
+ // for more details, refer to the example in the folder "example/src/alternative/websocket"
157
+ };
158
+
159
+ const config: AuroraDSQLWsConfig<{}> = {
160
+ host: 'your-cluster.dsql.us-east-1.on.aws',
161
+ database: "postgres",
162
+ user: "admin",
163
+ customCredentialsProvider: simulateSecureGetCredentialsAPI,
164
+ };
165
+
166
+ const sql = auroraDSQLWsPostgres(config);
167
+
168
+ const result = await sql`SELECT version()`;
169
+ console.log(result);
170
+ await sql.end();
171
+ ```
172
+
173
+ ### Configuration Options
174
+
175
+ | Option | Type | Required | Description |
176
+ |-----------------------------|----------------------------------|----------|----------------------------------------------------------|
177
+ | `host` | `string` | Yes | DSQL cluster hostname or cluster ID |
178
+ | `database` | `string?` | No | Database name |
179
+ | `username` | `string?` | No | Database username (uses admin if not provided) |
180
+ | `region` | `string?` | No | AWS region (auto-detected from hostname if not provided) |
181
+ | `customCredentialsProvider` | `AwsCredentialIdentityProvider?` | No | Custom AWS credentials provider |
182
+ | `tokenDurationSecs` | `number?` | No | Token expiration time in seconds |
183
+ | `connectionCheck` | `boolean?` | No | Perform a heart beat connectivity check with`Select 1` before every query (Default: false)
184
+ | `connectionId` | `string?` | No | An optional connection identifier to be used in the `onReservedConnectionClose` callback
185
+ | `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.
186
+
187
+ 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.
188
+
189
+
190
+
134
191
  ## Authentication
135
192
 
136
193
  The connector automatically handles DSQL authentication by generating tokens using the DSQL client token generator. If the
package/dist/index.cjs CHANGED
@@ -28,55 +28,294 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  let postgres = require("postgres");
29
29
  postgres = __toESM(postgres);
30
30
  let _aws_sdk_dsql_signer = require("@aws-sdk/dsql-signer");
31
+ let events = require("events");
32
+ let async_mutex = require("async-mutex");
31
33
 
34
+ //#region src/postgres-web-socket.ts
35
+ const HEARTBEAT_TIMEOUT = 5e3;
36
+ const MESSAGE_CODE_SIMPLE_QUERY = "Q".charCodeAt(0);
37
+ const MESSAGE_CODE_SYNC = "S".charCodeAt(0);
38
+ const MESSAGE_CODE_RFQ = "Z".charCodeAt(0);
39
+ var ReadyState = /* @__PURE__ */ function(ReadyState$1) {
40
+ ReadyState$1["Closed"] = "closed";
41
+ ReadyState$1["Querying"] = "querying";
42
+ ReadyState$1["Open"] = "open";
43
+ return ReadyState$1;
44
+ }(ReadyState || {});
45
+ var PostgresWs = class extends events.EventEmitter {
46
+ constructor(config) {
47
+ super();
48
+ this.mutex = new async_mutex.Mutex();
49
+ this.mutexRelease = null;
50
+ this.ws = null;
51
+ this.connected = false;
52
+ this.disableHeartBeat = false;
53
+ this.heartBeatTimeout = null;
54
+ this.pendingQueries = [];
55
+ this.readyState = ReadyState.Closed;
56
+ this.port = 443;
57
+ this.config = config;
58
+ this.host = config.host || "";
59
+ }
60
+ onReadyForQuery() {
61
+ if (this.pendingQueries.length > 0) {
62
+ if (this.pendingQueries[0].numOfQueries > 0) this.pendingQueries[0].numOfQueries--;
63
+ if (this.pendingQueries[0].numOfQueries <= 0) {
64
+ this.pendingQueries.shift();
65
+ this.readyState = ReadyState.Open;
66
+ this.disableHeartBeat = false;
67
+ this.releaseMutex();
68
+ this.processQueue();
69
+ }
70
+ }
71
+ }
72
+ handleHeartBeatResponse(data) {
73
+ if (this.pendingQueries.length === 0 || !this.pendingQueries[0].isHeartBeat) return false;
74
+ const messageType = String.fromCharCode(data[0]);
75
+ if (messageType === "D") {
76
+ if (new TextDecoder().decode(data.slice(5)).includes("1")) {
77
+ clearTimeout(this.heartBeatTimeout);
78
+ this.heartBeatTimeout = null;
79
+ }
80
+ } else if (messageType === "Z") this.onReadyForQuery();
81
+ return true;
82
+ }
83
+ async connect() {
84
+ const url = `wss://${this.config.host}:${this.port}`;
85
+ this.ws = new WebSocket(url);
86
+ this.ws.binaryType = "arraybuffer";
87
+ return new Promise((resolve, reject) => {
88
+ if (this.ws != null) {
89
+ this.ws.onopen = () => {
90
+ this.connected = true;
91
+ this.readyState = ReadyState.Open;
92
+ resolve(this);
93
+ };
94
+ this.ws.onmessage = (event) => {
95
+ const data = new Uint8Array(event.data);
96
+ if (this.config.connectionCheck) {
97
+ if (this.handleHeartBeatResponse(data)) return;
98
+ if (data.length > 0 && data[0] === MESSAGE_CODE_RFQ) {
99
+ if (data.length > 5) if (String.fromCharCode(data[5]) === "E") {
100
+ this.disableHeartBeat = true;
101
+ this.cleanUpTxErrorState();
102
+ } else this.onReadyForQuery();
103
+ }
104
+ }
105
+ this.emit("data", Buffer.from(data));
106
+ };
107
+ this.ws.onerror = (event) => {
108
+ const msg = event.message || "WebSocket error";
109
+ const error = /* @__PURE__ */ new Error(`${msg} ${this.host}:${this.port}`);
110
+ this.emit("error", error);
111
+ reject(error);
112
+ };
113
+ this.ws.onclose = () => {
114
+ if (this.heartBeatTimeout) {
115
+ clearTimeout(this.heartBeatTimeout);
116
+ this.heartBeatTimeout = null;
117
+ }
118
+ this.releaseMutex();
119
+ this.connected = false;
120
+ this.readyState = ReadyState.Closed;
121
+ this.ws = null;
122
+ this.emit("close");
123
+ if (this.config.onReservedConnectionClose) this.config.onReservedConnectionClose(this.config.connectionId);
124
+ };
125
+ }
126
+ });
127
+ }
128
+ createQueryBuffer(sql) {
129
+ const sqlBytes = new TextEncoder().encode(sql + "\0");
130
+ const length = 4 + sqlBytes.length;
131
+ const buf = new Uint8Array(1 + length);
132
+ const view = new DataView(buf.buffer);
133
+ buf[0] = MESSAGE_CODE_SIMPLE_QUERY;
134
+ view.setInt32(1, length, false);
135
+ buf.set(sqlBytes, 5);
136
+ return buf;
137
+ }
138
+ write(data, encodingOrCallback, callback) {
139
+ let callbackFn;
140
+ if (typeof encodingOrCallback === "function") callbackFn = encodingOrCallback;
141
+ else callbackFn = callback;
142
+ let sendData;
143
+ if (typeof data === "string") sendData = new TextEncoder().encode(data);
144
+ else if (data instanceof Buffer) sendData = new Uint8Array(data);
145
+ else sendData = data;
146
+ if (!this.ws || !this.connected) {
147
+ if (callbackFn) callbackFn(/* @__PURE__ */ new Error("websocket is not connected"));
148
+ return false;
149
+ }
150
+ let offset = 0;
151
+ let queryCount = 0;
152
+ let hasSync = false;
153
+ while (offset < sendData.length) {
154
+ if (sendData[offset] === MESSAGE_CODE_SIMPLE_QUERY) queryCount++;
155
+ if (sendData[offset] === MESSAGE_CODE_SYNC) hasSync = true;
156
+ if (offset + 5 <= sendData.length) {
157
+ const length = new DataView(sendData.buffer, sendData.byteOffset + offset + 1, 4).getInt32(0, false);
158
+ offset += 1 + length;
159
+ } else break;
160
+ }
161
+ if (!this.config.connectionCheck || queryCount == 0 && hasSync === false) try {
162
+ this.ws.send(sendData);
163
+ if (callbackFn) callbackFn();
164
+ return true;
165
+ } catch (err) {
166
+ if (callbackFn) callbackFn(err);
167
+ return false;
168
+ }
169
+ if (queryCount > 0 && this.config.connectionCheck && this.heartBeatTimeout === null && !this.disableHeartBeat) {
170
+ const buf = this.createQueryBuffer("select 1;");
171
+ this.pendingQueries.push({
172
+ buffer: buf,
173
+ numOfQueries: 1,
174
+ isHeartBeat: true
175
+ });
176
+ }
177
+ this.pendingQueries.push({
178
+ buffer: sendData,
179
+ numOfQueries: queryCount,
180
+ isHeartBeat: false
181
+ });
182
+ this.processQueue();
183
+ if (callbackFn) callbackFn();
184
+ return true;
185
+ }
186
+ releaseMutex() {
187
+ if (this.mutexRelease) {
188
+ this.mutexRelease();
189
+ this.mutexRelease = null;
190
+ }
191
+ }
192
+ cleanUpTxErrorState() {
193
+ if (this.pendingQueries.length > 0) this.pendingQueries.shift();
194
+ while (this.pendingQueries.length > 0 && this.pendingQueries[0].isHeartBeat) this.pendingQueries.shift();
195
+ this.readyState = ReadyState.Open;
196
+ this.releaseMutex();
197
+ if (this.pendingQueries.length > 0) this.processQueue();
198
+ }
199
+ async processQueue() {
200
+ if (this.mutexRelease || this.readyState !== ReadyState.Open || this.pendingQueries.length === 0) return;
201
+ this.mutexRelease = await this.mutex.acquire();
202
+ if (this.pendingQueries.length == 0) {
203
+ this.releaseMutex();
204
+ return;
205
+ }
206
+ const data = this.pendingQueries[0];
207
+ if (data.buffer.length > 0 && data.buffer[0] === MESSAGE_CODE_SIMPLE_QUERY) this.readyState = ReadyState.Querying;
208
+ if (data.isHeartBeat) this.heartBeatTimeout = setTimeout(() => {
209
+ console.log("Heart beat timed out");
210
+ if (this.ws) this.ws.close(1e3, "Heart beat timeout");
211
+ }, HEARTBEAT_TIMEOUT);
212
+ if (this.ws) this.ws.send(data.buffer);
213
+ else throw Error("Websocket is not initialized");
214
+ }
215
+ end() {
216
+ if (this.ws && this.readyState !== ReadyState.Closed) this.ws.close();
217
+ }
218
+ destroy() {
219
+ if (this.ws) this.ws.close();
220
+ }
221
+ setKeepAlive() {
222
+ return this;
223
+ }
224
+ resume() {
225
+ return this;
226
+ }
227
+ pause() {
228
+ return this;
229
+ }
230
+ cork() {
231
+ return this;
232
+ }
233
+ uncork() {
234
+ return this;
235
+ }
236
+ };
237
+ function createPostgresWs(config) {
238
+ return async () => {
239
+ const socket = new PostgresWs(config);
240
+ await socket.connect();
241
+ return socket;
242
+ };
243
+ }
244
+
245
+ //#endregion
32
246
  //#region src/client.ts
247
+ const version = "0.2.0";
33
248
  const ADMIN = "admin";
34
249
  const DEFAULT_DATABASE = "postgres";
35
250
  const DEFAULT_EXPIRY = 30;
36
251
  const PRE_REGION_HOST_PATTERN = ".dsql.";
37
252
  const POST_REGION_HOST_PATTERN = ".on.aws";
38
- function auroraDSQLPostgres(urlOrOptions, options) {
253
+ const APPLICATION_NAME = `aurora-dsql-nodejs-postgresjs/${version}`;
254
+ function parseConnectionParams(urlOrOptions, options) {
39
255
  let opts;
40
256
  let host;
41
257
  let username;
42
258
  let database;
43
- let ssl;
44
259
  if (typeof urlOrOptions === "string") {
45
260
  let parsedOptions = parseConnectionString(urlOrOptions);
46
261
  host = options?.hostname || options?.host || parsedOptions.host || process.env.PGHOST;
47
262
  username = options?.username || options?.user || parsedOptions.username || process.env.PGUSERNAME || process.env.USER || ADMIN;
48
263
  database = options?.database || options?.db || parsedOptions.database || process.env.PGDATABASE;
49
- ssl = options?.ssl || parsedOptions.ssl;
50
- opts = { ...options };
264
+ opts = {
265
+ ...options,
266
+ ssl: options?.ssl || parsedOptions.ssl
267
+ };
51
268
  } else {
52
269
  host = urlOrOptions?.hostname || urlOrOptions?.host || process.env.PGHOST;
53
270
  username = urlOrOptions?.username || urlOrOptions?.user || process.env.PGUSERNAME || process.env.USER || ADMIN;
54
271
  database = urlOrOptions?.database || urlOrOptions?.db || process.env.PGDATABASE;
55
- ssl = urlOrOptions?.ssl;
56
272
  opts = { ...urlOrOptions };
57
273
  }
58
274
  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
- }
275
+ if (!opts.region) opts.region = parseRegionFromHost(host);
276
+ if (isClusterID(host)) host = buildHostnameFromIdAndRegion(host, opts.region);
277
+ if (!database) opts.database = DEFAULT_DATABASE;
278
+ opts.host = host;
279
+ opts.username = username;
280
+ opts.connection = {
281
+ ...opts.connection,
282
+ application_name: buildApplicationName(opts.connection?.application_name)
283
+ };
284
+ return { opts };
285
+ }
286
+ function setupDsqlSigner(opts) {
64
287
  let signerConfig = {
65
- hostname: host,
66
- region: opts.region || parseRegionFromHost(host),
288
+ hostname: opts.host,
289
+ region: opts.region,
67
290
  expiresIn: opts.tokenDurationSecs ?? opts.connect_timeout ?? (process.env.PGCONNECT_TIMEOUT ? parseInt(process.env.PGCONNECT_TIMEOUT) : void 0) ?? DEFAULT_EXPIRY,
68
291
  profile: opts.profile || process.env.AWS_PROFILE || "default"
69
292
  };
70
293
  if (opts.customCredentialsProvider) signerConfig.credentials = opts.customCredentialsProvider;
294
+ return { signerConfig };
295
+ }
296
+ function auroraDSQLPostgres(urlOrOptions, options) {
297
+ let { opts } = parseConnectionParams(urlOrOptions, options);
298
+ const { signerConfig } = setupDsqlSigner(opts);
71
299
  let signer = new _aws_sdk_dsql_signer.DsqlSigner(signerConfig);
72
- if (!database) opts.database = DEFAULT_DATABASE;
73
- if (!ssl) opts.ssl = true;
300
+ if (!opts.ssl) opts.ssl = true;
74
301
  const postgresOpts = {
75
302
  ...opts,
76
- pass: () => getToken(signer, username)
303
+ pass: () => getToken(signer, opts.username)
77
304
  };
78
305
  return typeof urlOrOptions === "string" ? (0, postgres.default)(urlOrOptions, postgresOpts) : (0, postgres.default)(postgresOpts);
79
306
  }
307
+ function auroraDSQLWsPostgres(urlOrOptions, options) {
308
+ let { opts } = parseConnectionParams(urlOrOptions, options);
309
+ const { signerConfig } = setupDsqlSigner(opts);
310
+ if (!opts.pass) opts.pass = async () => {
311
+ return await getToken(new _aws_sdk_dsql_signer.DsqlSigner(signerConfig), opts.username);
312
+ };
313
+ opts.socket = createPostgresWs(opts);
314
+ opts.ssl = false;
315
+ if (opts.connectionCheck == void 0) opts.connectionCheck = false;
316
+ opts.port = 443;
317
+ return typeof urlOrOptions === "string" ? (0, postgres.default)(urlOrOptions, opts) : (0, postgres.default)(opts);
318
+ }
80
319
  function parseConnectionString(url) {
81
320
  let decodedUrl = decodeURI(url);
82
321
  const parsed = new URL(decodedUrl);
@@ -104,6 +343,27 @@ async function getToken(signer, username) {
104
343
  if (username === ADMIN) return await signer.getDbConnectAdminAuthToken();
105
344
  else return await signer.getDbConnectAuthToken();
106
345
  }
346
+ /**
347
+ * Build the application_name with optional ORM prefix.
348
+ *
349
+ * If ormPrefix is provided and non-empty after trimming, prepends it to
350
+ * the connector identifier. Otherwise, returns the connector's application_name.
351
+ *
352
+ * PostgreSQL limits application_name to 64 characters. After accounting for
353
+ * the connector identifier and separator, 27 characters are available for
354
+ * the ORM name.
355
+ *
356
+ * @param ormPrefix Optional ORM name to prepend (e.g., "prisma")
357
+ * @returns Formatted application_name string
358
+ */
359
+ function buildApplicationName(ormPrefix) {
360
+ if (ormPrefix) {
361
+ const trimmed = ormPrefix.trim();
362
+ if (trimmed) return `${trimmed}:${APPLICATION_NAME}`;
363
+ }
364
+ return APPLICATION_NAME;
365
+ }
107
366
 
108
367
  //#endregion
109
- exports.auroraDSQLPostgres = auroraDSQLPostgres;
368
+ exports.auroraDSQLPostgres = auroraDSQLPostgres;
369
+ 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"],"sourcesContent":[],"mappings":"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"}
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"],"sourcesContent":[],"mappings":"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"}
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$1) {
12
+ ReadyState$1["Closed"] = "closed";
13
+ ReadyState$1["Querying"] = "querying";
14
+ ReadyState$1["Open"] = "open";
15
+ return ReadyState$1;
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.0";
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":["callbackFn: ((err?: Error) => void) | undefined","sendData: Uint8Array","opts: any","host: string","username: string","database: string | undefined","signerConfig: DsqlSignerConfig","postgresOpts: postgres.Options<T>"],"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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws/aurora-dsql-postgresjs-connector",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "An AWS Aurora DSQL connector with IAM authentication for Postgres.js",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -8,7 +8,15 @@
8
8
  "url": "git+https://github.com/awslabs/aurora-dsql-nodejs-connector.git"
9
9
  },
10
10
  "homepage": "https://github.com/awslabs/aurora-dsql-nodejs-connector",
11
- "keywords": ["aws", "aurora", "dsql", "postgres", "database", "iam", "authentication"],
11
+ "keywords": [
12
+ "aws",
13
+ "aurora",
14
+ "dsql",
15
+ "postgres",
16
+ "database",
17
+ "iam",
18
+ "authentication"
19
+ ],
12
20
  "publishConfig": {
13
21
  "access": "public"
14
22
  },
@@ -50,7 +58,8 @@
50
58
  "dependencies": {
51
59
  "@aws-sdk/credential-providers": "^3.901.0",
52
60
  "@aws-sdk/dsql-signer": "^3.940.0",
53
- "@aws-sdk/types": "^3.901.0"
61
+ "@aws-sdk/types": "^3.901.0",
62
+ "async-mutex": "^0.5.0"
54
63
  },
55
64
  "peerDependencies": {
56
65
  "postgres": "^3.4.7"