@lafken/common 0.6.4 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +379 -31
- package/lib/decorators/field/field.js +5 -2
- package/lib/decorators/lambda/lambda.d.ts +0 -1
- package/lib/decorators/lambda/lambda.js +3 -8
- package/lib/decorators/lambda/lambda.types.d.ts +1 -3
- package/lib/decorators/lambda/lambda.types.js +0 -1
- package/lib/types/utilities.types.d.ts +4 -0
- package/lib/utils/string.utils.d.ts +1 -0
- package/lib/utils/string.utils.js +8 -1
- package/package.json +25 -9
package/README.md
CHANGED
|
@@ -1,66 +1,414 @@
|
|
|
1
1
|
# @lafken/common
|
|
2
2
|
|
|
3
|
-
`@lafken/common` is the core utility package for the Lafken framework. It provides the
|
|
3
|
+
`@lafken/common` is the core utility package for the Lafken framework. It provides the decorator factory functions, metadata reflection utilities, and shared types that power every `@lafken/*` package. If a Lafken package defines a decorator or reads infrastructure metadata, it depends on `@lafken/common`.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @lafken/common
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
Lafken uses TypeScript decorators to declare infrastructure. This package provides the factories that create those decorators and the utilities that read the metadata they produce:
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
| Factory | Level | Purpose |
|
|
16
|
+
| -------------------------- | ------ | -------------------------------------------- |
|
|
17
|
+
| `createResourceDecorator` | Class | Mark a class as a deployable resource |
|
|
18
|
+
| `createLambdaDecorator` | Method | Mark a method as a Lambda handler |
|
|
19
|
+
| `createEventDecorator` | Param | Bind a method parameter to the Lambda event |
|
|
20
|
+
| `createFieldDecorator` | Prop | Describe a typed field inside a payload class |
|
|
21
|
+
| `createPayloadDecorator` | Class | Define a named payload schema |
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
## Decorator Factories
|
|
14
24
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- The file path and folder
|
|
18
|
-
- Custom metadata defined in your props.
|
|
25
|
+
### `createResourceDecorator`
|
|
26
|
+
|
|
27
|
+
Creates a **class-level** decorator that marks a class as an infrastructure resource. The factory automatically captures the resource name, the file path and folder (used for Lambda bundling), and any custom metadata you define.
|
|
19
28
|
|
|
20
29
|
```typescript
|
|
21
30
|
import { createResourceDecorator } from '@lafken/common';
|
|
22
31
|
|
|
23
|
-
export const
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
export const RESOURCE_TYPE = 'MY_SERVICE' as const;
|
|
33
|
+
|
|
34
|
+
export interface MyServiceProps {
|
|
35
|
+
name?: string;
|
|
36
|
+
retryCount?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const MyService = createResourceDecorator<MyServiceProps>({
|
|
40
|
+
type: RESOURCE_TYPE,
|
|
41
|
+
callerFileIndex: 5, // Stack-trace index to resolve caller file
|
|
42
|
+
getMetadata: (props) => ({ // Optional — transform props before storing
|
|
43
|
+
...props,
|
|
44
|
+
retryCount: props.retryCount ?? 3,
|
|
45
|
+
}),
|
|
26
46
|
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Usage:
|
|
27
50
|
|
|
28
|
-
|
|
29
|
-
@
|
|
30
|
-
export class
|
|
51
|
+
```typescript
|
|
52
|
+
@MyService({ name: 'notifications', retryCount: 5 })
|
|
53
|
+
export class NotificationService { ... }
|
|
31
54
|
```
|
|
32
55
|
|
|
33
|
-
|
|
56
|
+
**Captured metadata** (`ResourceMetadata`):
|
|
57
|
+
|
|
58
|
+
| Field | Description |
|
|
59
|
+
| -------------- | ---------------------------------------- |
|
|
60
|
+
| `type` | Resolver identifier (`MY_SERVICE`) |
|
|
61
|
+
| `name` | Explicit name or the class name |
|
|
62
|
+
| `foldername` | Directory of the decorated file |
|
|
63
|
+
| `filename` | File name (without `.js` extension) |
|
|
64
|
+
| `originalName` | Original class name (for asset naming) |
|
|
65
|
+
| `minify` | Whether to minify the bundle (`true`) |
|
|
66
|
+
|
|
67
|
+
### `createLambdaDecorator`
|
|
34
68
|
|
|
35
|
-
|
|
36
|
-
- Method metadata reflection.
|
|
37
|
-
- Argument injection (Event, Context, Callback).
|
|
69
|
+
Creates a **method-level** decorator that registers a method as a Lambda handler. It stores handler metadata and rewrites the method descriptor so the framework can inject arguments (`@Event`, `@Context`) at runtime.
|
|
38
70
|
|
|
39
71
|
```typescript
|
|
40
72
|
import { createLambdaDecorator } from '@lafken/common';
|
|
73
|
+
import type { LambdaMetadata } from '@lafken/common';
|
|
74
|
+
|
|
75
|
+
export interface PublishProps {
|
|
76
|
+
name: string;
|
|
77
|
+
lambda?: LambdaProps;
|
|
78
|
+
}
|
|
41
79
|
|
|
42
|
-
export
|
|
43
|
-
|
|
80
|
+
export interface PublishMetadata extends PublishProps {
|
|
81
|
+
name: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const Publish = (props: PublishProps) =>
|
|
85
|
+
createLambdaDecorator<PublishProps, PublishMetadata>({
|
|
44
86
|
getLambdaMetadata: (props, methodName) => ({
|
|
45
87
|
...props,
|
|
46
88
|
name: methodName,
|
|
47
89
|
}),
|
|
48
90
|
})(props);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Usage:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
class NotificationService {
|
|
97
|
+
@Publish({ name: 'send-email' })
|
|
98
|
+
sendEmail(@Event() event: EmailPayload) {
|
|
99
|
+
// handler logic
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**`LambdaProps`** — Optional Lambda-level configuration available through the `lambda` property:
|
|
105
|
+
|
|
106
|
+
| Property | Type | Description |
|
|
107
|
+
| ------------- | ------------------- | --------------------------------------------- |
|
|
108
|
+
| `timeout` | `number` | Execution timeout in seconds |
|
|
109
|
+
| `memory` | `number` | Memory allocation in MB |
|
|
110
|
+
| `runtime` | `24 \| 22 \| 20` | Node.js runtime version |
|
|
111
|
+
| `services` | `ServicesValues` | IAM service permissions |
|
|
112
|
+
| `env` | `EnvironmentValue` | Environment variables (static or dynamic) |
|
|
113
|
+
| `tags` | `Record<string, string>` | Resource tags |
|
|
114
|
+
| `enableTrace` | `boolean` | Enable AWS X-Ray tracing |
|
|
115
|
+
|
|
116
|
+
### `createEventDecorator`
|
|
117
|
+
|
|
118
|
+
Creates a **parameter-level** decorator that binds a method parameter to the incoming Lambda event. It works with `createFieldDecorator` to map typed payload classes onto the raw event.
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { createEventDecorator } from '@lafken/common';
|
|
122
|
+
|
|
123
|
+
export const Event = createEventDecorator({
|
|
124
|
+
prefix: 'my-service',
|
|
125
|
+
enableInLambdaInvocation: false, // Only capture metadata during build
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Usage:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
class NotificationService {
|
|
133
|
+
@Publish({ name: 'send-email' })
|
|
134
|
+
sendEmail(@Event(EmailPayload) event: EmailPayload) { ... }
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### `Context`
|
|
139
|
+
|
|
140
|
+
A built-in parameter decorator that injects the Lambda execution context:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import { Context } from '@lafken/common';
|
|
49
144
|
|
|
50
|
-
// Usage
|
|
51
145
|
class MyService {
|
|
52
|
-
@
|
|
53
|
-
|
|
146
|
+
@Handler()
|
|
147
|
+
process(@Event(Input) event: Input, @Context() ctx: any) {
|
|
148
|
+
console.log(ctx.functionName);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### `createFieldDecorator`
|
|
154
|
+
|
|
155
|
+
Creates a **property-level** decorator that describes a typed field inside a payload class. The field metadata is collected by resolvers to build event schemas (e.g., Step Functions input/output, API request bodies).
|
|
156
|
+
|
|
157
|
+
Supported types: `String`, `Number`, `Boolean`, nested classes, and arrays.
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { createFieldDecorator } from '@lafken/common';
|
|
161
|
+
|
|
162
|
+
export const Field = createFieldDecorator({
|
|
163
|
+
prefix: 'my-service',
|
|
164
|
+
getMetadata: () => ({}),
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Usage:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
class Address {
|
|
172
|
+
@Field()
|
|
173
|
+
street: string;
|
|
174
|
+
|
|
175
|
+
@Field()
|
|
176
|
+
city: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
class UserPayload {
|
|
180
|
+
@Field({ name: 'user_name' }) // Rename the field in the schema
|
|
181
|
+
name: string;
|
|
182
|
+
|
|
183
|
+
@Field()
|
|
184
|
+
age: number;
|
|
185
|
+
|
|
186
|
+
@Field({ type: Address }) // Nested object
|
|
187
|
+
address: Address;
|
|
188
|
+
|
|
189
|
+
@Field({ type: [String] }) // Array of primitives
|
|
190
|
+
tags: string[];
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### `createPayloadDecorator`
|
|
195
|
+
|
|
196
|
+
Creates a **class-level** decorator that gives a payload class a name and optional metadata. This identity is used when resolvers reference the payload in generated infrastructure.
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { createPayloadDecorator } from '@lafken/common';
|
|
200
|
+
|
|
201
|
+
export const Payload = createPayloadDecorator({
|
|
202
|
+
prefix: 'my-service',
|
|
203
|
+
createUniqueId: true, // Append a counter if names collide
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Usage:
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
@Payload({ name: 'CreateUserInput' })
|
|
211
|
+
class CreateUserInput {
|
|
212
|
+
@Field()
|
|
213
|
+
email: string;
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Metadata Utilities
|
|
218
|
+
|
|
219
|
+
Resolvers use these functions to read the metadata produced by the decorators above.
|
|
220
|
+
|
|
221
|
+
### `getResourceMetadata`
|
|
222
|
+
|
|
223
|
+
Returns the `ResourceMetadata` stored on a class by `createResourceDecorator`:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
import { getResourceMetadata } from '@lafken/common';
|
|
227
|
+
|
|
228
|
+
const metadata = getResourceMetadata(NotificationService);
|
|
229
|
+
// { type: 'MY_SERVICE', name: 'notifications', foldername: '...', ... }
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### `getResourceHandlerMetadata`
|
|
233
|
+
|
|
234
|
+
Returns an array of handler metadata stored by `createLambdaDecorator`:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { getResourceHandlerMetadata } from '@lafken/common';
|
|
238
|
+
|
|
239
|
+
const handlers = getResourceHandlerMetadata<PublishMetadata>(NotificationService);
|
|
240
|
+
// [{ name: 'sendEmail', ... }]
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### `getMetadataByKey` / `getMetadataPrototypeByKey`
|
|
244
|
+
|
|
245
|
+
Low-level helpers to read any Reflect metadata by key from a class or its prototype:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { getMetadataByKey, getMetadataPrototypeByKey } from '@lafken/common';
|
|
249
|
+
|
|
250
|
+
const payload = getMetadataByKey<PayloadMetadata>(MyClass, 'my-service:lafken:payload');
|
|
251
|
+
const fields = getMetadataPrototypeByKey<FieldMetadata[]>(MyClass, 'my-service:lafken:field');
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Build Environment
|
|
255
|
+
|
|
256
|
+
Decorators only capture metadata when the build environment flag is set. This prevents metadata side-effects during normal runtime execution.
|
|
257
|
+
|
|
258
|
+
- **`isBuildEnvironment()`** — Returns `true` when the `LAFKEN_CONTEXT` environment variable equals `BUILD`.
|
|
259
|
+
- **`enableBuildEnvVariable()`** — Sets the flag. **Required in tests** before declaring any decorated class.
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import { enableBuildEnvVariable } from '@lafken/common';
|
|
263
|
+
|
|
264
|
+
describe('My resolver', () => {
|
|
265
|
+
enableBuildEnvVariable();
|
|
266
|
+
|
|
267
|
+
@MyService({ name: 'test' })
|
|
268
|
+
class TestResource { ... }
|
|
269
|
+
|
|
270
|
+
it('should capture metadata', () => {
|
|
271
|
+
const meta = getResourceMetadata(TestResource);
|
|
272
|
+
expect(meta.name).toBe('test');
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## String Utilities
|
|
278
|
+
|
|
279
|
+
General-purpose string helpers used throughout the framework:
|
|
280
|
+
|
|
281
|
+
| Function | Description | Example |
|
|
282
|
+
| ---------------------- | ---------------------------------------------------- | -------------------------------- |
|
|
283
|
+
| `capitalize(str)` | Uppercase first letter | `'hello'` → `'Hello'` |
|
|
284
|
+
| `kebabCase(str)` | Convert to kebab-case | `'MyService'` → `'my-service'` |
|
|
285
|
+
| `cleanString(str)` | Remove non-alphanumeric characters | `'a-b_c'` → `'abc'` |
|
|
286
|
+
| `cleanAndCapitalize(str)` | Clean + capitalize each word | `'my-service'` → `'MyService'` |
|
|
287
|
+
| `cleanTemplateString(str)` | Trim + collapse multiline strings into one line | — |
|
|
288
|
+
|
|
289
|
+
## Shared Types
|
|
290
|
+
|
|
291
|
+
### Services & Permissions
|
|
292
|
+
|
|
293
|
+
The `Services` type provides typed IAM permission declarations for Lambda handlers:
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
import type { Services } from '@lafken/common';
|
|
297
|
+
|
|
298
|
+
// Shorthand — grants full service access
|
|
299
|
+
const services: Services[] = ['dynamodb', 's3'];
|
|
300
|
+
|
|
301
|
+
// Fine-grained — specific actions and resources
|
|
302
|
+
const services: Services[] = [
|
|
303
|
+
{ type: 'dynamodb', permissions: ['GetItem', 'PutItem'] },
|
|
304
|
+
{ type: 's3', permissions: ['GetObject'], resources: ['arn:aws:s3:::my-bucket/*'] },
|
|
305
|
+
{ type: 'custom', serviceName: 'ses', permissions: ['SendEmail'] },
|
|
306
|
+
];
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Supported service types: `dynamodb`, `s3`, `lambda`, `cloudwatch`, `sqs`, `state_machine`, `kms`, `ssm`, `event`, and `custom`.
|
|
310
|
+
|
|
311
|
+
### Environment Variables
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
import type { EnvironmentValue } from '@lafken/common';
|
|
315
|
+
|
|
316
|
+
// Static values
|
|
317
|
+
const env: EnvironmentValue = { TABLE_NAME: 'users' };
|
|
318
|
+
|
|
319
|
+
// Dynamic values — resolved at deploy time via resource references
|
|
320
|
+
const env: EnvironmentValue = ({ getResourceValue }) => ({
|
|
321
|
+
TABLE_ARN: getResourceValue('dynamo::users-table', 'arn'),
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Duration
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
import type { Duration } from '@lafken/common';
|
|
329
|
+
|
|
330
|
+
const timeout: Duration = 30; // seconds
|
|
331
|
+
const ttl: Duration = { type: 'days', duration: 7 }; // 7 days
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Type-Safe Resource References
|
|
335
|
+
|
|
336
|
+
The package provides augmentable interfaces that enable type-safe resource names across modules. Packages extend these interfaces so that `getResourceValue` calls are validated at compile time:
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
// In your lafken-types.d.ts
|
|
340
|
+
declare module '@lafken/common' {
|
|
341
|
+
interface ModulesAvailable {
|
|
342
|
+
core: {
|
|
343
|
+
Queue: { 'email-queue': string };
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
interface DynamoTableAvailable {
|
|
347
|
+
'users-table': string;
|
|
348
|
+
}
|
|
54
349
|
}
|
|
55
350
|
```
|
|
56
351
|
|
|
57
|
-
|
|
352
|
+
## API Reference
|
|
353
|
+
|
|
354
|
+
### Decorator Factories
|
|
355
|
+
|
|
356
|
+
| Export | Description |
|
|
357
|
+
| -------------------------- | ------------------------------------------ |
|
|
358
|
+
| `createResourceDecorator` | Factory for class-level resource decorators |
|
|
359
|
+
| `createLambdaDecorator` | Factory for method-level handler decorators |
|
|
360
|
+
| `createEventDecorator` | Factory for parameter-level event binding |
|
|
361
|
+
| `createFieldDecorator` | Factory for property-level field metadata |
|
|
362
|
+
| `createPayloadDecorator` | Factory for class-level payload naming |
|
|
363
|
+
| `Context` | Parameter decorator for Lambda context |
|
|
364
|
+
|
|
365
|
+
### Metadata Readers
|
|
366
|
+
|
|
367
|
+
| Export | Description |
|
|
368
|
+
| ---------------------------- | ------------------------------------------ |
|
|
369
|
+
| `getResourceMetadata` | Read class resource metadata |
|
|
370
|
+
| `getResourceHandlerMetadata` | Read method handler metadata |
|
|
371
|
+
| `getMetadataByKey` | Read metadata by key from a class |
|
|
372
|
+
| `getMetadataPrototypeByKey` | Read metadata by key from a prototype |
|
|
373
|
+
|
|
374
|
+
### Utilities
|
|
375
|
+
|
|
376
|
+
| Export | Description |
|
|
377
|
+
| ------------------------- | ---------------------------------------- |
|
|
378
|
+
| `enableBuildEnvVariable` | Enable build mode for decorator capture |
|
|
379
|
+
| `isBuildEnvironment` | Check if build mode is active |
|
|
380
|
+
| `getCallerFileName` | Resolve the caller file from the stack |
|
|
381
|
+
| `capitalize` | Capitalize a string |
|
|
382
|
+
| `kebabCase` | Convert to kebab-case |
|
|
383
|
+
| `cleanString` | Strip non-alphanumeric characters |
|
|
384
|
+
| `cleanAndCapitalize` | Clean and capitalize each word |
|
|
385
|
+
| `cleanTemplateString` | Collapse multiline string to one line |
|
|
386
|
+
|
|
387
|
+
### Constants
|
|
388
|
+
|
|
389
|
+
| Export | Description |
|
|
390
|
+
| ---------------------- | ------------------------------------ |
|
|
391
|
+
| `LAFKEN_CONTEXT` | Environment variable name |
|
|
392
|
+
| `LAFKEN_CONTEXT_VALUE` | Expected value for build mode |
|
|
58
393
|
|
|
59
|
-
|
|
394
|
+
### Key Types
|
|
60
395
|
|
|
61
|
-
|
|
62
|
-
|
|
396
|
+
| Export | Description |
|
|
397
|
+
| -------------------- | --------------------------------------------------- |
|
|
398
|
+
| `ResourceProps` | Base props for resource decorators |
|
|
399
|
+
| `ResourceMetadata` | Metadata shape stored by resource decorators |
|
|
400
|
+
| `LambdaProps` | Lambda configuration (timeout, memory, runtime, ...) |
|
|
401
|
+
| `LambdaMetadata` | Metadata shape for handler methods |
|
|
402
|
+
| `FieldMetadata` | Discriminated union of field types |
|
|
403
|
+
| `PayloadMetadata` | Metadata shape for payload classes |
|
|
404
|
+
| `Services` | IAM permission declaration type |
|
|
405
|
+
| `ServicesValues` | Array or function returning `Services[]` |
|
|
406
|
+
| `EnvironmentValue` | Static or dynamic environment variables |
|
|
407
|
+
| `Duration` | Seconds or `{ type, duration }` object |
|
|
408
|
+
| `ClassResource` | Generic class constructor type |
|
|
409
|
+
| `GetResourceValue` | Callback type for cross-resource references |
|
|
410
|
+
| `DeepPartial<T>` | Recursive partial type utility |
|
|
63
411
|
|
|
64
|
-
##
|
|
412
|
+
## License
|
|
65
413
|
|
|
66
|
-
|
|
414
|
+
MIT
|
|
@@ -61,10 +61,13 @@ const getFieldMetadata = (props) => {
|
|
|
61
61
|
destinationName,
|
|
62
62
|
name: fieldProps?.name || destinationName,
|
|
63
63
|
};
|
|
64
|
-
|
|
64
|
+
let primitiveType = (0, exports.getPrimitiveType)(type);
|
|
65
|
+
if (!primitiveType && fieldProps?.type) {
|
|
66
|
+
primitiveType = (0, exports.getPrimitiveType)(fieldProps.type);
|
|
67
|
+
}
|
|
65
68
|
const typeHasValue = exports.mapTypeofValueToPrimitiveType[typeof fieldProps?.type];
|
|
66
69
|
if (fieldProps?.type !== undefined) {
|
|
67
|
-
if (typeof fieldProps.type === 'function') {
|
|
70
|
+
if (typeof fieldProps.type === 'function' && !primitiveType) {
|
|
68
71
|
return getObjectMetadata(metadata, fieldProps.type, prefix);
|
|
69
72
|
}
|
|
70
73
|
if (Array.isArray(fieldProps.type)) {
|
|
@@ -4,5 +4,4 @@ import { type CreateEventDecoratorProps, type CreateLambdaDecoratorProps, Lambda
|
|
|
4
4
|
export declare const reflectArgumentMethod: (target: Function, methodName: string, type: LambdaArgumentTypes) => void;
|
|
5
5
|
export declare const createLambdaDecorator: <T, M>({ getLambdaMetadata, descriptorValue, argumentParser, }: CreateLambdaDecoratorProps<T, M>) => (props?: T) => (target: any, methodName: string, descriptor: PropertyDescriptor) => any;
|
|
6
6
|
export declare const createEventDecorator: ({ enableInLambdaInvocation, prefix }: CreateEventDecoratorProps) => (eventField: AllowedTypes) => (target: any, methodName: string, _number: number) => void;
|
|
7
|
-
export declare const Callback: () => (target: any, methodName: string, _number: number) => void;
|
|
8
7
|
export declare const Context: () => (target: any, methodName: string, _number: number) => void;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Context = exports.
|
|
3
|
+
exports.Context = exports.createEventDecorator = exports.createLambdaDecorator = exports.reflectArgumentMethod = void 0;
|
|
4
4
|
require("reflect-metadata");
|
|
5
5
|
const utils_1 = require("../../utils");
|
|
6
6
|
const field_1 = require("../field");
|
|
7
7
|
const lambda_types_1 = require("./lambda.types");
|
|
8
8
|
const argumentsByType = {
|
|
9
9
|
[lambda_types_1.LambdaArgumentTypes.event]: ({ event }) => event,
|
|
10
|
-
[lambda_types_1.LambdaArgumentTypes.callback]: ({ callback }) => callback,
|
|
11
10
|
[lambda_types_1.LambdaArgumentTypes.context]: ({ context }) => context,
|
|
12
11
|
};
|
|
13
12
|
const reflectArgumentMethod = (target, methodName, type) => {
|
|
@@ -30,8 +29,8 @@ const createLambdaDecorator = ({ getLambdaMetadata, descriptorValue, argumentPar
|
|
|
30
29
|
...argumentsByType,
|
|
31
30
|
...argumentParser,
|
|
32
31
|
};
|
|
33
|
-
descriptor.value = async (event, context
|
|
34
|
-
const methodArguments = (lambdaArguments?.[methodName] || []).map((argumentType) => mapArgumentMethod[argumentType]({ event, context, methodName, target
|
|
32
|
+
descriptor.value = async (event, context) => {
|
|
33
|
+
const methodArguments = (lambdaArguments?.[methodName] || []).map((argumentType) => mapArgumentMethod[argumentType]({ event, context, methodName, target }));
|
|
35
34
|
const response = await originalValue.apply(this, methodArguments);
|
|
36
35
|
return response;
|
|
37
36
|
};
|
|
@@ -53,10 +52,6 @@ const createEventDecorator = ({ enableInLambdaInvocation = false, prefix }) => (
|
|
|
53
52
|
reflectEventMetadata(target, methodName, lambda_types_1.LambdaReflectKeys.event_param, field);
|
|
54
53
|
};
|
|
55
54
|
exports.createEventDecorator = createEventDecorator;
|
|
56
|
-
const Callback = () => (target, methodName, _number) => {
|
|
57
|
-
(0, exports.reflectArgumentMethod)(target, methodName, lambda_types_1.LambdaArgumentTypes.callback);
|
|
58
|
-
};
|
|
59
|
-
exports.Callback = Callback;
|
|
60
55
|
const Context = () => (target, methodName, _number) => {
|
|
61
56
|
(0, exports.reflectArgumentMethod)(target, methodName, lambda_types_1.LambdaArgumentTypes.context);
|
|
62
57
|
};
|
|
@@ -103,17 +103,15 @@ export declare enum LambdaReflectKeys {
|
|
|
103
103
|
}
|
|
104
104
|
export declare enum LambdaArgumentTypes {
|
|
105
105
|
event = "event",
|
|
106
|
-
callback = "callback",
|
|
107
106
|
context = "context"
|
|
108
107
|
}
|
|
109
108
|
export type CallbackParam = (error: boolean | null, response?: any) => void;
|
|
110
109
|
export type LambdaArguments = Record<string, LambdaArgumentTypes[]>;
|
|
111
|
-
export type LambdaArgumentsType = Record<LambdaArgumentTypes, ({ event, context,
|
|
110
|
+
export type LambdaArgumentsType = Record<LambdaArgumentTypes, ({ event, context, }: {
|
|
112
111
|
event: any;
|
|
113
112
|
context: any;
|
|
114
113
|
methodName: string;
|
|
115
114
|
target: any;
|
|
116
|
-
callback: CallbackParam;
|
|
117
115
|
}) => any>;
|
|
118
116
|
export interface CreateLambdaDecoratorProps<T, M> {
|
|
119
117
|
getLambdaMetadata: (params: T, methodName: string) => M;
|
|
@@ -10,6 +10,5 @@ var LambdaReflectKeys;
|
|
|
10
10
|
var LambdaArgumentTypes;
|
|
11
11
|
(function (LambdaArgumentTypes) {
|
|
12
12
|
LambdaArgumentTypes["event"] = "event";
|
|
13
|
-
LambdaArgumentTypes["callback"] = "callback";
|
|
14
13
|
LambdaArgumentTypes["context"] = "context";
|
|
15
14
|
})(LambdaArgumentTypes || (exports.LambdaArgumentTypes = LambdaArgumentTypes = {}));
|
|
@@ -31,3 +31,7 @@ export type OnlyOneKey<T> = {
|
|
|
31
31
|
export type StripReadonly<T> = {
|
|
32
32
|
-readonly [P in keyof T]: StripReadonly<T[P]>;
|
|
33
33
|
};
|
|
34
|
+
export type Primitive = string | number | boolean[];
|
|
35
|
+
export type OnlyTypeKeys<T, V> = {
|
|
36
|
+
[K in keyof T]: T[K] extends V ? K : never;
|
|
37
|
+
}[keyof T];
|
|
@@ -2,3 +2,4 @@ export declare const capitalize: (str: string) => string;
|
|
|
2
2
|
export declare const kebabCase: (str: string) => string;
|
|
3
3
|
export declare const cleanString: (str: string) => string;
|
|
4
4
|
export declare const cleanTemplateString: (str: string) => string;
|
|
5
|
+
export declare const cleanAndCapitalize: (str: string) => string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.cleanTemplateString = exports.cleanString = exports.kebabCase = exports.capitalize = void 0;
|
|
3
|
+
exports.cleanAndCapitalize = exports.cleanTemplateString = exports.cleanString = exports.kebabCase = exports.capitalize = void 0;
|
|
4
4
|
const capitalize = (str) => {
|
|
5
5
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
6
6
|
};
|
|
@@ -27,3 +27,10 @@ const cleanTemplateString = (str) => {
|
|
|
27
27
|
.join(' ');
|
|
28
28
|
};
|
|
29
29
|
exports.cleanTemplateString = cleanTemplateString;
|
|
30
|
+
const cleanAndCapitalize = (str) => {
|
|
31
|
+
return str
|
|
32
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
33
|
+
.map((word) => (0, exports.capitalize)(word))
|
|
34
|
+
.join('');
|
|
35
|
+
};
|
|
36
|
+
exports.cleanAndCapitalize = cleanAndCapitalize;
|
package/package.json
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lafken/common",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Lafken utilities - TypeScript decorator factories and metadata reflection for infrastructure-as-code decorators",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"aws",
|
|
8
8
|
"serverless",
|
|
9
9
|
"lafken",
|
|
10
|
-
"
|
|
10
|
+
"decorators",
|
|
11
|
+
"metadata",
|
|
12
|
+
"reflection",
|
|
13
|
+
"typescript",
|
|
11
14
|
"utility"
|
|
12
15
|
],
|
|
16
|
+
"homepage": "https://github.com/Hero64/lafken#readme",
|
|
17
|
+
"bugs": "https://github.com/Hero64/lafken/issues",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/Hero64/lafken",
|
|
21
|
+
"directory": "packages/common"
|
|
22
|
+
},
|
|
13
23
|
"license": "MIT",
|
|
24
|
+
"author": "Aníbal Jorquera",
|
|
14
25
|
"main": "lib/index.js",
|
|
15
26
|
"types": "lib/index.d.ts",
|
|
16
27
|
"files": [
|
|
@@ -20,19 +31,24 @@
|
|
|
20
31
|
"reflect-metadata": "0.2.2"
|
|
21
32
|
},
|
|
22
33
|
"devDependencies": {
|
|
23
|
-
"@
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
34
|
+
"@swc/core": "^1.15.11",
|
|
35
|
+
"@swc/helpers": "^0.5.18",
|
|
36
|
+
"@vitest/runner": "^4.0.18",
|
|
37
|
+
"cdktn-vitest": "^1.0.0",
|
|
38
|
+
"unplugin-swc": "^1.5.9",
|
|
39
|
+
"vitest": "^4.0.18"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20.19"
|
|
27
43
|
},
|
|
28
44
|
"publishConfig": {
|
|
29
45
|
"access": "public"
|
|
30
46
|
},
|
|
31
47
|
"scripts": {
|
|
32
48
|
"build": "pnpm clean && tsc -p ./tsconfig.build.json",
|
|
49
|
+
"check-types": "tsc --noEmit -p ./tsconfig.build.json",
|
|
33
50
|
"clean": "rm -rf ./lib",
|
|
34
51
|
"dev": "tsc -w",
|
|
35
|
-
"test": "
|
|
36
|
-
"test:coverage": "jest --coverage"
|
|
52
|
+
"test": "vitest"
|
|
37
53
|
}
|
|
38
54
|
}
|