@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 +82 -3
- package/dist/index.cjs +278 -17
- package/dist/index.d.cts +17 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +17 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +275 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -6
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Aurora DSQL Connector for Postgres.js
|
|
2
2
|
|
|
3
|
-
[](https://github.com/awslabs/aurora-dsql-
|
|
3
|
+
[](https://github.com/awslabs/aurora-dsql-connectors/tree/main/node/postgres-js)
|
|
4
|
+
[](https://github.com/awslabs/aurora-dsql-connectors/blob/main/LICENSE)
|
|
5
5
|
[](https://www.npmjs.com/package/@aws/aurora-dsql-postgresjs-connector)
|
|
6
6
|
[](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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50
|
-
|
|
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
|
-
|
|
60
|
-
if (isClusterID(host))
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
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 (!
|
|
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
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/client.ts"],"
|
|
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
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/client.ts"],"
|
|
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
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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
|
-
|
|
32
|
-
if (isClusterID(host))
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
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 (!
|
|
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
|
package/dist/index.mjs.map
CHANGED
|
@@ -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":"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"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aws/aurora-dsql-postgresjs-connector",
|
|
3
|
-
"version": "0.1
|
|
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-
|
|
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-
|
|
11
|
-
"keywords": [
|
|
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.
|
|
84
|
+
"tsdown": "^0.20.2",
|
|
75
85
|
"typescript": "^5.9.3"
|
|
76
86
|
}
|
|
77
87
|
}
|