@nlabs/lex 1.49.5 → 1.50.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/.swcrc +35 -0
- package/README.md +43 -59
- package/config.json +32 -8
- package/examples/lex.config.js +110 -10
- package/lex.config.js +34 -7
- package/lib/Button.stories.js +99 -0
- package/lib/LexConfig.d.ts +60 -22
- package/lib/LexConfig.js +285 -244
- package/lib/commands/ai/ai.js +287 -288
- package/lib/commands/ai/index.js +8 -7
- package/lib/commands/build/build.d.ts +2 -2
- package/lib/commands/build/build.js +349 -458
- package/lib/commands/clean/clean.js +45 -33
- package/lib/commands/compile/compile.js +214 -228
- package/lib/commands/config/config.js +46 -42
- package/lib/commands/copy/copy.js +36 -35
- package/lib/commands/create/create.js +200 -121
- package/lib/commands/dev/dev.d.ts +1 -0
- package/lib/commands/dev/dev.js +261 -259
- package/lib/commands/init/init.js +108 -88
- package/lib/commands/link/link.js +18 -14
- package/lib/commands/lint/lint.js +735 -742
- package/lib/commands/migrate/migrate.js +49 -36
- package/lib/commands/publish/publish.js +116 -96
- package/lib/commands/serverless/serverless.js +611 -585
- package/lib/commands/storybook/storybook.js +242 -238
- package/lib/commands/test/test.js +381 -409
- package/lib/commands/update/update.js +141 -120
- package/lib/commands/upgrade/upgrade.js +51 -44
- package/lib/commands/versions/versions.d.ts +1 -1
- package/lib/commands/versions/versions.js +36 -38
- package/lib/create/changelog.js +136 -125
- package/lib/index.js +40 -38
- package/lib/lex.js +95 -68
- package/lib/storybook/index.js +6 -1
- package/lib/test-react/index.js +7 -84
- package/lib/types.d.ts +1 -1
- package/lib/types.js +7 -1
- package/lib/utils/aiService.js +240 -227
- package/lib/utils/app.js +274 -273
- package/lib/utils/deepMerge.js +37 -23
- package/lib/utils/file.js +218 -215
- package/lib/utils/log.js +29 -27
- package/lib/utils/reactShim.js +7 -85
- package/lib/utils/translations.js +92 -82
- package/package.json +59 -60
- package/templates/typescript/DataLayer.js.txt +218 -0
- package/templates/typescript/DataLayer.test.js.txt +268 -0
- package/templates/typescript/DataLayer.test.ts.txt +269 -0
- package/templates/typescript/DataLayer.ts.txt +227 -0
- package/webpack.config.js +38 -28
- package/lib/commands/lint/autofix.d.ts +0 -2
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018-Present, Nitrogen Labs, Inc.
|
|
3
|
+
* Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
|
|
4
|
+
*/
|
|
5
|
+
import {APIGatewayProxyEvent, Context} from 'aws-lambda';
|
|
6
|
+
|
|
7
|
+
import {DataLayer, handler} from './DataLayer.js';
|
|
8
|
+
|
|
9
|
+
describe('DataLayer', () => {
|
|
10
|
+
let dataLayer: DataLayer;
|
|
11
|
+
let mockContext: Context;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
dataLayer = new DataLayer({
|
|
15
|
+
tableName: 'test-table',
|
|
16
|
+
region: 'us-east-1'
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
mockContext = {
|
|
20
|
+
awsRequestId: 'test-request-id',
|
|
21
|
+
functionName: 'test-function',
|
|
22
|
+
functionVersion: '$LATEST',
|
|
23
|
+
getRemainingTimeInMillis: () => 30000,
|
|
24
|
+
invokedFunctionArn: 'arn:aws:lambda:us-east-1:123456789012:function:test-function',
|
|
25
|
+
logGroupName: '/aws/lambda/test-function',
|
|
26
|
+
logStreamName: 'test-log-stream',
|
|
27
|
+
memoryLimitInMB: '128'
|
|
28
|
+
} as Context;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('getItem', () => {
|
|
32
|
+
it('should get an item by ID', async () => {
|
|
33
|
+
const result = await dataLayer.getItem('test-id');
|
|
34
|
+
|
|
35
|
+
expect(result).toEqual({
|
|
36
|
+
id: 'test-id',
|
|
37
|
+
data: 'sample data',
|
|
38
|
+
timestamp: expect.any(String)
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('createItem', () => {
|
|
44
|
+
it('should create a new item', async () => {
|
|
45
|
+
const itemData = {
|
|
46
|
+
name: 'Test Item',
|
|
47
|
+
description: 'A test item'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const result = await dataLayer.createItem(itemData);
|
|
51
|
+
|
|
52
|
+
expect(result).toEqual({
|
|
53
|
+
id: expect.stringMatching(/^item-\d+$/),
|
|
54
|
+
name: 'Test Item',
|
|
55
|
+
description: 'A test item',
|
|
56
|
+
createdAt: expect.any(String),
|
|
57
|
+
updatedAt: expect.any(String)
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should create an item with custom ID', async () => {
|
|
62
|
+
const itemData = {
|
|
63
|
+
id: 'custom-id',
|
|
64
|
+
name: 'Test Item'
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const result = await dataLayer.createItem(itemData);
|
|
68
|
+
|
|
69
|
+
expect(result.id).toBe('custom-id');
|
|
70
|
+
expect(result.name).toBe('Test Item');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('updateItem', () => {
|
|
75
|
+
it('should update an existing item', async () => {
|
|
76
|
+
const updateData = {
|
|
77
|
+
name: 'Updated Item',
|
|
78
|
+
description: 'Updated description'
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const result = await dataLayer.updateItem('test-id', updateData);
|
|
82
|
+
|
|
83
|
+
expect(result).toEqual({
|
|
84
|
+
id: 'test-id',
|
|
85
|
+
name: 'Updated Item',
|
|
86
|
+
description: 'Updated description',
|
|
87
|
+
updatedAt: expect.any(String)
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('deleteItem', () => {
|
|
93
|
+
it('should delete an item by ID', async () => {
|
|
94
|
+
const result = await dataLayer.deleteItem('test-id');
|
|
95
|
+
|
|
96
|
+
expect(result).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('listItems', () => {
|
|
101
|
+
it('should list items without filters', async () => {
|
|
102
|
+
const result = await dataLayer.listItems();
|
|
103
|
+
|
|
104
|
+
expect(Array.isArray(result)).toBe(true);
|
|
105
|
+
expect(result.length).toBeGreaterThan(0);
|
|
106
|
+
expect(result[0]).toHaveProperty('id');
|
|
107
|
+
expect(result[0]).toHaveProperty('data');
|
|
108
|
+
expect(result[0]).toHaveProperty('timestamp');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should list items with filters', async () => {
|
|
112
|
+
const filters = {
|
|
113
|
+
status: 'active'
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const result = await dataLayer.listItems(filters);
|
|
117
|
+
|
|
118
|
+
expect(Array.isArray(result)).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('handleRequest', () => {
|
|
123
|
+
it('should handle GET request for single item', async () => {
|
|
124
|
+
const event: APIGatewayProxyEvent = {
|
|
125
|
+
httpMethod: 'GET',
|
|
126
|
+
pathParameters: {id: 'test-id'},
|
|
127
|
+
body: null,
|
|
128
|
+
queryStringParameters: null
|
|
129
|
+
} as APIGatewayProxyEvent;
|
|
130
|
+
|
|
131
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
132
|
+
|
|
133
|
+
expect(result.statusCode).toBe(200);
|
|
134
|
+
expect(result.headers['Content-Type']).toBe('application/json');
|
|
135
|
+
expect(result.headers['Access-Control-Allow-Origin']).toBe('*');
|
|
136
|
+
|
|
137
|
+
const body = JSON.parse(result.body);
|
|
138
|
+
expect(body.id).toBe('test-id');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should handle GET request for list items', async () => {
|
|
142
|
+
const event: APIGatewayProxyEvent = {
|
|
143
|
+
httpMethod: 'GET',
|
|
144
|
+
pathParameters: null,
|
|
145
|
+
body: null,
|
|
146
|
+
queryStringParameters: {status: 'active'}
|
|
147
|
+
} as APIGatewayProxyEvent;
|
|
148
|
+
|
|
149
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
150
|
+
|
|
151
|
+
expect(result.statusCode).toBe(200);
|
|
152
|
+
const body = JSON.parse(result.body);
|
|
153
|
+
expect(Array.isArray(body)).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should handle POST request', async () => {
|
|
157
|
+
const event: APIGatewayProxyEvent = {
|
|
158
|
+
httpMethod: 'POST',
|
|
159
|
+
pathParameters: null,
|
|
160
|
+
body: JSON.stringify({
|
|
161
|
+
name: 'New Item',
|
|
162
|
+
description: 'A new item'
|
|
163
|
+
}),
|
|
164
|
+
queryStringParameters: null
|
|
165
|
+
} as APIGatewayProxyEvent;
|
|
166
|
+
|
|
167
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
168
|
+
|
|
169
|
+
expect(result.statusCode).toBe(200);
|
|
170
|
+
const body = JSON.parse(result.body);
|
|
171
|
+
expect(body.name).toBe('New Item');
|
|
172
|
+
expect(body.description).toBe('A new item');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should handle PUT request', async () => {
|
|
176
|
+
const event: APIGatewayProxyEvent = {
|
|
177
|
+
httpMethod: 'PUT',
|
|
178
|
+
pathParameters: {id: 'test-id'},
|
|
179
|
+
body: JSON.stringify({
|
|
180
|
+
name: 'Updated Item'
|
|
181
|
+
}),
|
|
182
|
+
queryStringParameters: null
|
|
183
|
+
} as APIGatewayProxyEvent;
|
|
184
|
+
|
|
185
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
186
|
+
|
|
187
|
+
expect(result.statusCode).toBe(200);
|
|
188
|
+
const body = JSON.parse(result.body);
|
|
189
|
+
expect(body.id).toBe('test-id');
|
|
190
|
+
expect(body.name).toBe('Updated Item');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should handle DELETE request', async () => {
|
|
194
|
+
const event: APIGatewayProxyEvent = {
|
|
195
|
+
httpMethod: 'DELETE',
|
|
196
|
+
pathParameters: {id: 'test-id'},
|
|
197
|
+
body: null,
|
|
198
|
+
queryStringParameters: null
|
|
199
|
+
} as APIGatewayProxyEvent;
|
|
200
|
+
|
|
201
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
202
|
+
|
|
203
|
+
expect(result.statusCode).toBe(200);
|
|
204
|
+
const body = JSON.parse(result.body);
|
|
205
|
+
expect(body.message).toBe('Item deleted successfully');
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should return 400 for PUT without ID', async () => {
|
|
209
|
+
const event: APIGatewayProxyEvent = {
|
|
210
|
+
httpMethod: 'PUT',
|
|
211
|
+
pathParameters: null,
|
|
212
|
+
body: JSON.stringify({name: 'Updated Item'}),
|
|
213
|
+
queryStringParameters: null
|
|
214
|
+
} as APIGatewayProxyEvent;
|
|
215
|
+
|
|
216
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
217
|
+
|
|
218
|
+
expect(result.statusCode).toBe(400);
|
|
219
|
+
const body = JSON.parse(result.body);
|
|
220
|
+
expect(body.error).toBe('ID is required for update operations');
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should return 400 for DELETE without ID', async () => {
|
|
224
|
+
const event: APIGatewayProxyEvent = {
|
|
225
|
+
httpMethod: 'DELETE',
|
|
226
|
+
pathParameters: null,
|
|
227
|
+
body: null,
|
|
228
|
+
queryStringParameters: null
|
|
229
|
+
} as APIGatewayProxyEvent;
|
|
230
|
+
|
|
231
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
232
|
+
|
|
233
|
+
expect(result.statusCode).toBe(400);
|
|
234
|
+
const body = JSON.parse(result.body);
|
|
235
|
+
expect(body.error).toBe('ID is required for delete operations');
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('should return 405 for unsupported method', async () => {
|
|
239
|
+
const event: APIGatewayProxyEvent = {
|
|
240
|
+
httpMethod: 'OPTIONS',
|
|
241
|
+
pathParameters: null,
|
|
242
|
+
body: null,
|
|
243
|
+
queryStringParameters: null
|
|
244
|
+
} as APIGatewayProxyEvent;
|
|
245
|
+
|
|
246
|
+
const result = await dataLayer.handleRequest(event, mockContext);
|
|
247
|
+
|
|
248
|
+
expect(result.statusCode).toBe(405);
|
|
249
|
+
const body = JSON.parse(result.body);
|
|
250
|
+
expect(body.error).toBe('Method not allowed');
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
describe('handler function', () => {
|
|
255
|
+
it('should work as Lambda handler', async () => {
|
|
256
|
+
const event: APIGatewayProxyEvent = {
|
|
257
|
+
httpMethod: 'GET',
|
|
258
|
+
pathParameters: {id: 'test-id'},
|
|
259
|
+
body: null,
|
|
260
|
+
queryStringParameters: null
|
|
261
|
+
} as APIGatewayProxyEvent;
|
|
262
|
+
|
|
263
|
+
const result = await handler(event, mockContext);
|
|
264
|
+
|
|
265
|
+
expect(result.statusCode).toBe(200);
|
|
266
|
+
expect(result.headers['Content-Type']).toBe('application/json');
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
});
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2018-Present, Nitrogen Labs, Inc.
|
|
3
|
+
* Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
|
|
4
|
+
*/
|
|
5
|
+
import {APIGatewayProxyEvent, APIGatewayProxyResult, Context} from 'aws-lambda';
|
|
6
|
+
|
|
7
|
+
export interface DataLayerOptions {
|
|
8
|
+
readonly tableName?: string;
|
|
9
|
+
readonly region?: string;
|
|
10
|
+
readonly endpoint?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class DataLayer {
|
|
14
|
+
private readonly options: DataLayerOptions;
|
|
15
|
+
|
|
16
|
+
constructor(options: DataLayerOptions = {}) {
|
|
17
|
+
this.options = {
|
|
18
|
+
tableName: process.env.TABLE_NAME || 'default-table',
|
|
19
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
20
|
+
endpoint: process.env.DYNAMODB_ENDPOINT,
|
|
21
|
+
...options
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get a single item by ID
|
|
27
|
+
*/
|
|
28
|
+
async getItem(id: string): Promise<any> {
|
|
29
|
+
try {
|
|
30
|
+
// TODO: Implement DynamoDB getItem logic
|
|
31
|
+
console.log(`Getting item with ID: ${id}`);
|
|
32
|
+
|
|
33
|
+
// Example response structure
|
|
34
|
+
return {
|
|
35
|
+
id,
|
|
36
|
+
data: 'sample data',
|
|
37
|
+
timestamp: new Date().toISOString()
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('Error getting item:', error);
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create a new item
|
|
47
|
+
*/
|
|
48
|
+
async createItem(data: any): Promise<any> {
|
|
49
|
+
try {
|
|
50
|
+
// TODO: Implement DynamoDB putItem logic
|
|
51
|
+
console.log('Creating new item:', data);
|
|
52
|
+
|
|
53
|
+
const newItem = {
|
|
54
|
+
id: data.id || `item-${Date.now()}`,
|
|
55
|
+
...data,
|
|
56
|
+
createdAt: new Date().toISOString(),
|
|
57
|
+
updatedAt: new Date().toISOString()
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return newItem;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error('Error creating item:', error);
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Update an existing item
|
|
69
|
+
*/
|
|
70
|
+
async updateItem(id: string, data: any): Promise<any> {
|
|
71
|
+
try {
|
|
72
|
+
// TODO: Implement DynamoDB updateItem logic
|
|
73
|
+
console.log(`Updating item ${id}:`, data);
|
|
74
|
+
|
|
75
|
+
const updatedItem = {
|
|
76
|
+
id,
|
|
77
|
+
...data,
|
|
78
|
+
updatedAt: new Date().toISOString()
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return updatedItem;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error('Error updating item:', error);
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Delete an item by ID
|
|
90
|
+
*/
|
|
91
|
+
async deleteItem(id: string): Promise<boolean> {
|
|
92
|
+
try {
|
|
93
|
+
// TODO: Implement DynamoDB deleteItem logic
|
|
94
|
+
console.log(`Deleting item with ID: ${id}`);
|
|
95
|
+
|
|
96
|
+
return true;
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error('Error deleting item:', error);
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* List items with optional filtering
|
|
105
|
+
*/
|
|
106
|
+
async listItems(filters?: any): Promise<any[]> {
|
|
107
|
+
try {
|
|
108
|
+
// TODO: Implement DynamoDB scan/query logic
|
|
109
|
+
console.log('Listing items with filters:', filters);
|
|
110
|
+
|
|
111
|
+
// Example response
|
|
112
|
+
return [
|
|
113
|
+
{
|
|
114
|
+
id: 'item-1',
|
|
115
|
+
data: 'sample data 1',
|
|
116
|
+
timestamp: new Date().toISOString()
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: 'item-2',
|
|
120
|
+
data: 'sample data 2',
|
|
121
|
+
timestamp: new Date().toISOString()
|
|
122
|
+
}
|
|
123
|
+
];
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error('Error listing items:', error);
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Lambda handler for HTTP requests
|
|
132
|
+
*/
|
|
133
|
+
async handleRequest(event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> {
|
|
134
|
+
try {
|
|
135
|
+
const {httpMethod, pathParameters, body, queryStringParameters} = event;
|
|
136
|
+
const id = pathParameters?.id;
|
|
137
|
+
|
|
138
|
+
let result: any;
|
|
139
|
+
|
|
140
|
+
switch (httpMethod) {
|
|
141
|
+
case 'GET':
|
|
142
|
+
if (id) {
|
|
143
|
+
result = await this.getItem(id);
|
|
144
|
+
} else {
|
|
145
|
+
result = await this.listItems(queryStringParameters);
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
|
|
149
|
+
case 'POST':
|
|
150
|
+
const createData = body ? JSON.parse(body) : {};
|
|
151
|
+
result = await this.createItem(createData);
|
|
152
|
+
break;
|
|
153
|
+
|
|
154
|
+
case 'PUT':
|
|
155
|
+
case 'PATCH':
|
|
156
|
+
if (!id) {
|
|
157
|
+
return {
|
|
158
|
+
statusCode: 400,
|
|
159
|
+
headers: {
|
|
160
|
+
'Content-Type': 'application/json',
|
|
161
|
+
'Access-Control-Allow-Origin': '*'
|
|
162
|
+
},
|
|
163
|
+
body: JSON.stringify({error: 'ID is required for update operations'})
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const updateData = body ? JSON.parse(body) : {};
|
|
167
|
+
result = await this.updateItem(id, updateData);
|
|
168
|
+
break;
|
|
169
|
+
|
|
170
|
+
case 'DELETE':
|
|
171
|
+
if (!id) {
|
|
172
|
+
return {
|
|
173
|
+
statusCode: 400,
|
|
174
|
+
headers: {
|
|
175
|
+
'Content-Type': 'application/json',
|
|
176
|
+
'Access-Control-Allow-Origin': '*'
|
|
177
|
+
},
|
|
178
|
+
body: JSON.stringify({error: 'ID is required for delete operations'})
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
await this.deleteItem(id);
|
|
182
|
+
result = {message: 'Item deleted successfully'};
|
|
183
|
+
break;
|
|
184
|
+
|
|
185
|
+
default:
|
|
186
|
+
return {
|
|
187
|
+
statusCode: 405,
|
|
188
|
+
headers: {
|
|
189
|
+
'Content-Type': 'application/json',
|
|
190
|
+
'Access-Control-Allow-Origin': '*'
|
|
191
|
+
},
|
|
192
|
+
body: JSON.stringify({error: 'Method not allowed'})
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
statusCode: 200,
|
|
198
|
+
headers: {
|
|
199
|
+
'Content-Type': 'application/json',
|
|
200
|
+
'Access-Control-Allow-Origin': '*'
|
|
201
|
+
},
|
|
202
|
+
body: JSON.stringify(result)
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.error('Handler error:', error);
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
statusCode: 500,
|
|
210
|
+
headers: {
|
|
211
|
+
'Content-Type': 'application/json',
|
|
212
|
+
'Access-Control-Allow-Origin': '*'
|
|
213
|
+
},
|
|
214
|
+
body: JSON.stringify({
|
|
215
|
+
error: 'Internal server error',
|
|
216
|
+
message: error instanceof Error ? error.message : 'Unknown error'
|
|
217
|
+
})
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Export the handler function for Lambda
|
|
224
|
+
export const handler = async (event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> => {
|
|
225
|
+
const dataLayer = new DataLayer();
|
|
226
|
+
return dataLayer.handleRequest(event, context);
|
|
227
|
+
};
|
package/webpack.config.js
CHANGED
|
@@ -9,7 +9,7 @@ import CompressionWebpackPlugin from 'compression-webpack-plugin';
|
|
|
9
9
|
import CopyWebpackPlugin from 'copy-webpack-plugin';
|
|
10
10
|
import cssnano from 'cssnano';
|
|
11
11
|
import DotenvPlugin from 'dotenv-webpack';
|
|
12
|
-
import
|
|
12
|
+
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
|
|
13
13
|
import FaviconsWebpackPlugin from 'favicons-webpack-plugin';
|
|
14
14
|
import {existsSync} from 'fs';
|
|
15
15
|
import {sync as globSync} from 'glob';
|
|
@@ -34,6 +34,7 @@ import {merge} from 'webpack-merge';
|
|
|
34
34
|
import {WebpackPluginServe} from 'webpack-plugin-serve';
|
|
35
35
|
|
|
36
36
|
import {relativeFilePath, relativeNodePath} from './lib/utils/file.js';
|
|
37
|
+
import {LexConfig} from './lib/LexConfig.js';
|
|
37
38
|
|
|
38
39
|
const {ProgressPlugin, ProvidePlugin} = webpack;
|
|
39
40
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
@@ -53,7 +54,7 @@ const {
|
|
|
53
54
|
webpack: webpackCustom
|
|
54
55
|
} = lexConfig;
|
|
55
56
|
|
|
56
|
-
const
|
|
57
|
+
const webpackStaticPath = webpackCustom?.staticPath || './src/static';
|
|
57
58
|
|
|
58
59
|
const { publicPath: _, ...webpackConfigFiltered } = webpackCustom || {};
|
|
59
60
|
|
|
@@ -153,13 +154,13 @@ const imagePath = `${sourceFullPath}/images/`;
|
|
|
153
154
|
const fontPath = `${sourceFullPath}/fonts/`;
|
|
154
155
|
const docPath = `${sourceFullPath}/docs/`;
|
|
155
156
|
|
|
156
|
-
const
|
|
157
|
-
if(existsSync(
|
|
157
|
+
const staticPathFull = pathResolve(process.cwd(), webpackStaticPath);
|
|
158
|
+
if(existsSync(staticPathFull)) {
|
|
158
159
|
staticPaths.push({
|
|
159
|
-
from:
|
|
160
|
+
from: staticPathFull,
|
|
160
161
|
to: './'
|
|
161
162
|
});
|
|
162
|
-
watchIgnorePaths.push(
|
|
163
|
+
watchIgnorePaths.push(staticPathFull);
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
if(existsSync(imagePath)) {
|
|
@@ -233,7 +234,7 @@ if(existsSync(`${sourceFullPath}/tsconfig.json`)) {
|
|
|
233
234
|
}));
|
|
234
235
|
}
|
|
235
236
|
|
|
236
|
-
const
|
|
237
|
+
const swcLoaderPath = relativeNodePath('swc-loader', dirName);
|
|
237
238
|
const cssLoaderPath = relativeNodePath('css-loader', dirName);
|
|
238
239
|
const graphqlLoaderPath = relativeNodePath('graphql-tag/loader', dirName);
|
|
239
240
|
const htmlLoaderPath = relativeNodePath('html-loader', dirName);
|
|
@@ -263,7 +264,7 @@ const alias = aliasKeys.reduce((aliases, key) => {
|
|
|
263
264
|
}, {});
|
|
264
265
|
|
|
265
266
|
export default (webpackEnv, webpackOptions) => {
|
|
266
|
-
const {bundleAnalyzer, watch, entry: cliEntry, mode: cliMode} = webpackOptions;
|
|
267
|
+
const {bundleAnalyzer, watch, entry: cliEntry, mode: cliMode, port} = webpackOptions;
|
|
267
268
|
const entryValue = Array.isArray(cliEntry) ? cliEntry[0] : cliEntry;
|
|
268
269
|
|
|
269
270
|
// Debug printout for environment and mode
|
|
@@ -322,10 +323,16 @@ export default (webpackEnv, webpackOptions) => {
|
|
|
322
323
|
`${sourceFullPath}/**/*.test.ts*`
|
|
323
324
|
],
|
|
324
325
|
include: sourceFullPath,
|
|
325
|
-
loader:
|
|
326
|
+
loader: swcLoaderPath,
|
|
326
327
|
options: {
|
|
327
|
-
|
|
328
|
-
|
|
328
|
+
...LexConfig.config.swc,
|
|
329
|
+
jsc: {
|
|
330
|
+
...LexConfig.config.swc?.jsc,
|
|
331
|
+
parser: {
|
|
332
|
+
...LexConfig.config.swc?.jsc?.parser,
|
|
333
|
+
tsx: false
|
|
334
|
+
}
|
|
335
|
+
}
|
|
329
336
|
},
|
|
330
337
|
resolve: {
|
|
331
338
|
symlinks: true
|
|
@@ -339,10 +346,23 @@ export default (webpackEnv, webpackOptions) => {
|
|
|
339
346
|
`${sourceFullPath}/**/*.test.ts*`
|
|
340
347
|
],
|
|
341
348
|
include: sourceFullPath,
|
|
342
|
-
loader:
|
|
349
|
+
loader: swcLoaderPath,
|
|
343
350
|
options: {
|
|
344
|
-
|
|
345
|
-
|
|
351
|
+
...LexConfig.config.swc,
|
|
352
|
+
jsc: {
|
|
353
|
+
...LexConfig.config.swc?.jsc,
|
|
354
|
+
parser: {
|
|
355
|
+
...LexConfig.config.swc?.jsc?.parser,
|
|
356
|
+
tsx: true
|
|
357
|
+
},
|
|
358
|
+
transform: {
|
|
359
|
+
...LexConfig.config.swc?.jsc?.transform,
|
|
360
|
+
react: {
|
|
361
|
+
...LexConfig.config.swc?.jsc?.transform?.react,
|
|
362
|
+
runtime: 'automatic'
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
346
366
|
},
|
|
347
367
|
resolve: {
|
|
348
368
|
symlinks: true
|
|
@@ -433,13 +453,6 @@ export default (webpackEnv, webpackOptions) => {
|
|
|
433
453
|
]
|
|
434
454
|
}
|
|
435
455
|
}
|
|
436
|
-
},
|
|
437
|
-
{
|
|
438
|
-
loader: esbuildLoaderPath,
|
|
439
|
-
options: {
|
|
440
|
-
loader: 'css',
|
|
441
|
-
minify: isProduction
|
|
442
|
-
}
|
|
443
456
|
}
|
|
444
457
|
]
|
|
445
458
|
},
|
|
@@ -451,7 +464,7 @@ export default (webpackEnv, webpackOptions) => {
|
|
|
451
464
|
},
|
|
452
465
|
{
|
|
453
466
|
test: /\.(jpg|jpeg|png|gif|webp|svg|mp4|webm|ogg|mp3|wav|flac|aac)$/,
|
|
454
|
-
include:
|
|
467
|
+
include: staticPathFull,
|
|
455
468
|
type: 'asset/resource',
|
|
456
469
|
generator: {
|
|
457
470
|
filename: '[name].[hash][ext]'
|
|
@@ -504,10 +517,7 @@ export default (webpackEnv, webpackOptions) => {
|
|
|
504
517
|
isProduction && isWeb
|
|
505
518
|
? {
|
|
506
519
|
minimizer: [
|
|
507
|
-
new
|
|
508
|
-
css: true,
|
|
509
|
-
target: targetEnvironment
|
|
510
|
-
})
|
|
520
|
+
new CssMinimizerPlugin()
|
|
511
521
|
],
|
|
512
522
|
runtimeChunk: 'single',
|
|
513
523
|
splitChunks: {
|
|
@@ -605,7 +615,7 @@ export default (webpackEnv, webpackOptions) => {
|
|
|
605
615
|
}
|
|
606
616
|
},
|
|
607
617
|
{
|
|
608
|
-
from:
|
|
618
|
+
from: /\\.(css|gif|ico|jpg|json|png|svg)$/,
|
|
609
619
|
to: ({parsedUrl: {pathname}}) => pathname
|
|
610
620
|
}
|
|
611
621
|
],
|
|
@@ -623,7 +633,7 @@ export default (webpackEnv, webpackOptions) => {
|
|
|
623
633
|
await next();
|
|
624
634
|
}),
|
|
625
635
|
open: process.env.WEBPACK_DEV_OPEN === 'true',
|
|
626
|
-
port:
|
|
636
|
+
port: port || 3000,
|
|
627
637
|
progress: 'minimal',
|
|
628
638
|
static: existsSync(outputFullPath) ? [outputFullPath] : [],
|
|
629
639
|
status: true
|