@jaypie/express 1.2.4 → 1.2.5

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.
@@ -8,6 +8,7 @@ interface LambdaRequestOptions {
8
8
  lambdaEvent: LambdaEvent;
9
9
  method: string;
10
10
  protocol: string;
11
+ query?: Record<string, string | string[]>;
11
12
  remoteAddress: string;
12
13
  url: string;
13
14
  }
package/dist/esm/index.js CHANGED
@@ -32,13 +32,15 @@ class LambdaRequest extends Readable {
32
32
  this.path = options.url.split("?")[0];
33
33
  this.headers = this.normalizeHeaders(options.headers);
34
34
  this.bodyBuffer = options.body ?? null;
35
- // Parse query string from URL
36
- const queryIndex = options.url.indexOf("?");
37
- if (queryIndex !== -1) {
38
- const queryString = options.url.slice(queryIndex + 1);
39
- const params = new URLSearchParams(queryString);
40
- for (const [key, value] of params) {
41
- this.query[key] = value;
35
+ // Use pre-parsed query if provided, otherwise parse from URL
36
+ if (options.query) {
37
+ this.query = options.query;
38
+ }
39
+ else {
40
+ const queryIndex = options.url.indexOf("?");
41
+ if (queryIndex !== -1) {
42
+ const queryString = options.url.slice(queryIndex + 1);
43
+ this.query = parseQueryString(queryString);
42
44
  }
43
45
  }
44
46
  // Store Lambda context
@@ -101,6 +103,66 @@ class LambdaRequest extends Readable {
101
103
  }
102
104
  //
103
105
  //
106
+ // Helper Functions
107
+ //
108
+ /**
109
+ * Normalize bracket notation in query parameter key.
110
+ * Removes trailing `[]` from keys (e.g., `filterByStatus[]` → `filterByStatus`).
111
+ */
112
+ function normalizeQueryKey(key) {
113
+ return key.endsWith("[]") ? key.slice(0, -2) : key;
114
+ }
115
+ /**
116
+ * Parse a query string into a record with proper array handling.
117
+ * Handles bracket notation (e.g., `param[]`) and multi-value parameters.
118
+ */
119
+ function parseQueryString(queryString) {
120
+ const result = {};
121
+ const params = new URLSearchParams(queryString);
122
+ for (const [rawKey, value] of params) {
123
+ const key = normalizeQueryKey(rawKey);
124
+ const existing = result[key];
125
+ if (existing === undefined) {
126
+ // First occurrence - check if it's bracket notation to determine if it should be an array
127
+ result[key] = rawKey.endsWith("[]") ? [value] : value;
128
+ }
129
+ else if (Array.isArray(existing)) {
130
+ existing.push(value);
131
+ }
132
+ else {
133
+ // Convert to array when we encounter a second value
134
+ result[key] = [existing, value];
135
+ }
136
+ }
137
+ return result;
138
+ }
139
+ /**
140
+ * Build query object from API Gateway v1 multiValueQueryStringParameters.
141
+ * Normalizes bracket notation and preserves array values.
142
+ */
143
+ function buildQueryFromMultiValue(multiValueParams) {
144
+ const result = {};
145
+ if (!multiValueParams)
146
+ return result;
147
+ for (const [rawKey, values] of Object.entries(multiValueParams)) {
148
+ const key = normalizeQueryKey(rawKey);
149
+ const existingValues = result[key];
150
+ if (existingValues === undefined) {
151
+ // First occurrence - use array if multiple values or bracket notation
152
+ result[key] = values.length === 1 && !rawKey.endsWith("[]") ? values[0] : values;
153
+ }
154
+ else if (Array.isArray(existingValues)) {
155
+ existingValues.push(...values);
156
+ }
157
+ else {
158
+ // Convert to array and merge
159
+ result[key] = [existingValues, ...values];
160
+ }
161
+ }
162
+ return result;
163
+ }
164
+ //
165
+ //
104
166
  // Type Guards
105
167
  //
106
168
  /**
@@ -126,6 +188,7 @@ function createLambdaRequest(event, context) {
126
188
  let url;
127
189
  let method;
128
190
  let protocol;
191
+ let query;
129
192
  let remoteAddress;
130
193
  const headers = { ...event.headers };
131
194
  if (isFunctionUrlEvent(event)) {
@@ -136,6 +199,10 @@ function createLambdaRequest(event, context) {
136
199
  method = event.requestContext.http.method;
137
200
  protocol = event.requestContext.http.protocol.split("/")[0].toLowerCase();
138
201
  remoteAddress = event.requestContext.http.sourceIp;
202
+ // Parse query string with proper multi-value and bracket notation support
203
+ if (event.rawQueryString) {
204
+ query = parseQueryString(event.rawQueryString);
205
+ }
139
206
  // Normalize cookies into Cookie header if not already present
140
207
  if (event.cookies && event.cookies.length > 0 && !headers.cookie) {
141
208
  headers.cookie = event.cookies.join("; ");
@@ -143,7 +210,13 @@ function createLambdaRequest(event, context) {
143
210
  }
144
211
  else if (isApiGatewayV1Event(event)) {
145
212
  // API Gateway REST API v1 format
213
+ // Use multiValueQueryStringParameters for proper array support
214
+ const multiValueParams = event.multiValueQueryStringParameters;
146
215
  const queryParams = event.queryStringParameters;
216
+ if (multiValueParams && Object.keys(multiValueParams).length > 0) {
217
+ query = buildQueryFromMultiValue(multiValueParams);
218
+ }
219
+ // Build URL with query string
147
220
  if (queryParams && Object.keys(queryParams).length > 0) {
148
221
  const queryString = new URLSearchParams(queryParams).toString();
149
222
  url = `${event.path}?${queryString}`;
@@ -177,6 +250,7 @@ function createLambdaRequest(event, context) {
177
250
  lambdaEvent: event,
178
251
  method,
179
252
  protocol,
253
+ query,
180
254
  remoteAddress,
181
255
  url,
182
256
  });