@lafken/common 0.10.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.
Files changed (61) hide show
  1. package/LICENCE +21 -0
  2. package/README.md +414 -0
  3. package/lib/constants/env.constants.d.ts +2 -0
  4. package/lib/constants/env.constants.js +5 -0
  5. package/lib/constants/index.d.ts +1 -0
  6. package/lib/constants/index.js +17 -0
  7. package/lib/decorators/field/field.d.ts +9 -0
  8. package/lib/decorators/field/field.js +138 -0
  9. package/lib/decorators/field/field.types.d.ts +71 -0
  10. package/lib/decorators/field/field.types.js +8 -0
  11. package/lib/decorators/field/index.d.ts +2 -0
  12. package/lib/decorators/field/index.js +18 -0
  13. package/lib/decorators/index.d.ts +4 -0
  14. package/lib/decorators/index.js +20 -0
  15. package/lib/decorators/lambda/index.d.ts +2 -0
  16. package/lib/decorators/lambda/index.js +18 -0
  17. package/lib/decorators/lambda/lambda.d.ts +7 -0
  18. package/lib/decorators/lambda/lambda.js +58 -0
  19. package/lib/decorators/lambda/lambda.types.d.ts +204 -0
  20. package/lib/decorators/lambda/lambda.types.js +14 -0
  21. package/lib/decorators/payload/index.d.ts +2 -0
  22. package/lib/decorators/payload/index.js +18 -0
  23. package/lib/decorators/payload/payload.d.ts +2 -0
  24. package/lib/decorators/payload/payload.js +32 -0
  25. package/lib/decorators/payload/payload.types.d.ts +18 -0
  26. package/lib/decorators/payload/payload.types.js +2 -0
  27. package/lib/decorators/resource/index.d.ts +2 -0
  28. package/lib/decorators/resource/index.js +18 -0
  29. package/lib/decorators/resource/resource.d.ts +2 -0
  30. package/lib/decorators/resource/resource.js +25 -0
  31. package/lib/decorators/resource/resource.types.d.ts +31 -0
  32. package/lib/decorators/resource/resource.types.js +7 -0
  33. package/lib/index.d.ts +4 -0
  34. package/lib/index.js +20 -0
  35. package/lib/types/env.types.d.ts +4 -0
  36. package/lib/types/env.types.js +2 -0
  37. package/lib/types/index.d.ts +7 -0
  38. package/lib/types/index.js +23 -0
  39. package/lib/types/output.types.d.ts +55 -0
  40. package/lib/types/output.types.js +2 -0
  41. package/lib/types/override-resources.types.d.ts +35 -0
  42. package/lib/types/override-resources.types.js +2 -0
  43. package/lib/types/resource.types.d.ts +52 -0
  44. package/lib/types/resource.types.js +2 -0
  45. package/lib/types/services.types.d.ts +22 -0
  46. package/lib/types/services.types.js +2 -0
  47. package/lib/types/time.types.d.ts +8 -0
  48. package/lib/types/time.types.js +2 -0
  49. package/lib/types/utilities.types.d.ts +37 -0
  50. package/lib/types/utilities.types.js +2 -0
  51. package/lib/utils/build-env.utils.d.ts +2 -0
  52. package/lib/utils/build-env.utils.js +12 -0
  53. package/lib/utils/index.d.ts +4 -0
  54. package/lib/utils/index.js +20 -0
  55. package/lib/utils/path.utils.d.ts +1 -0
  56. package/lib/utils/path.utils.js +16 -0
  57. package/lib/utils/resource.utils.d.ts +6 -0
  58. package/lib/utils/resource.utils.js +20 -0
  59. package/lib/utils/string.utils.d.ts +5 -0
  60. package/lib/utils/string.utils.js +36 -0
  61. package/package.json +55 -0
package/LICENCE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Aníbal Emilio Jorquera Cornejo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,414 @@
1
+ # @lafken/common
2
+
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
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @lafken/common
9
+ ```
10
+
11
+ ## Overview
12
+
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:
14
+
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 |
22
+
23
+ ## Decorator Factories
24
+
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.
28
+
29
+ ```typescript
30
+ import { createResourceDecorator } from '@lafken/common';
31
+
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
+ }),
46
+ });
47
+ ```
48
+
49
+ Usage:
50
+
51
+ ```typescript
52
+ @MyService({ name: 'notifications', retryCount: 5 })
53
+ export class NotificationService { ... }
54
+ ```
55
+
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`
68
+
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.
70
+
71
+ ```typescript
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
+ }
79
+
80
+ export interface PublishMetadata extends PublishProps {
81
+ name: string;
82
+ }
83
+
84
+ export const Publish = (props: PublishProps) =>
85
+ createLambdaDecorator<PublishProps, PublishMetadata>({
86
+ getLambdaMetadata: (props, methodName) => ({
87
+ ...props,
88
+ name: methodName,
89
+ }),
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';
144
+
145
+ class MyService {
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
+ }
349
+ }
350
+ ```
351
+
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 |
393
+
394
+ ### Key Types
395
+
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 |
411
+
412
+ ## License
413
+
414
+ MIT
@@ -0,0 +1,2 @@
1
+ export declare const LAFKEN_CONTEXT = "LAFKEN_CONTEXT";
2
+ export declare const LAFKEN_CONTEXT_VALUE = "BUILD";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LAFKEN_CONTEXT_VALUE = exports.LAFKEN_CONTEXT = void 0;
4
+ exports.LAFKEN_CONTEXT = 'LAFKEN_CONTEXT';
5
+ exports.LAFKEN_CONTEXT_VALUE = 'BUILD';
@@ -0,0 +1 @@
1
+ export * from './env.constants';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./env.constants"), exports);
@@ -0,0 +1,9 @@
1
+ import 'reflect-metadata';
2
+ import { type AllowedTypes, type BaseFieldMetadata, type CreateFieldDecoratorProps, FieldProperties, type FieldProps, type PrimitiveTypes } from './field.types';
3
+ export declare const primitiveTypeValues: Set<PrimitiveTypes>;
4
+ export declare const primitiveTypeofValues: Set<string>;
5
+ export declare const mapTypeofValueToPrimitiveType: Record<string, PrimitiveTypes>;
6
+ export declare const getPrimitiveType: (type: AllowedTypes) => PrimitiveTypes | undefined;
7
+ export declare const getEventFields: (prefix: string, target?: AllowedTypes, name?: string) => BaseFieldMetadata | undefined;
8
+ export declare const createFieldDecorator: <T extends FieldProps, M>({ prefix, enableInLambdaInvocation, getMetadata, }: CreateFieldDecoratorProps<T, M>) => (props?: T) => (target: any, destinationName: string) => void;
9
+ export declare const createFieldName: (prefix: string, type: FieldProperties) => string;
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createFieldName = exports.createFieldDecorator = exports.getEventFields = exports.getPrimitiveType = exports.mapTypeofValueToPrimitiveType = exports.primitiveTypeofValues = exports.primitiveTypeValues = void 0;
4
+ require("reflect-metadata");
5
+ const utils_1 = require("../../utils");
6
+ const build_env_utils_1 = require("../../utils/build-env.utils");
7
+ const field_types_1 = require("./field.types");
8
+ exports.primitiveTypeValues = new Set([
9
+ 'Boolean',
10
+ 'Number',
11
+ 'String',
12
+ ]);
13
+ exports.primitiveTypeofValues = new Set(['boolean', 'number', 'string']);
14
+ exports.mapTypeofValueToPrimitiveType = {
15
+ boolean: 'Boolean',
16
+ number: 'Number',
17
+ string: 'String',
18
+ };
19
+ const getPrimitiveType = (type) => {
20
+ if (type === String)
21
+ return 'String';
22
+ if (type === Number)
23
+ return 'Number';
24
+ if (type === Boolean)
25
+ return 'Boolean';
26
+ };
27
+ exports.getPrimitiveType = getPrimitiveType;
28
+ const getEventFields = (prefix, target, name = 'event') => {
29
+ if (!target) {
30
+ return undefined;
31
+ }
32
+ return getFieldMetadata({
33
+ destinationName: name,
34
+ type: `${name}_type`,
35
+ fieldProps: {
36
+ type: target,
37
+ },
38
+ prefix,
39
+ });
40
+ };
41
+ exports.getEventFields = getEventFields;
42
+ const getObjectMetadata = (metadata, payloadClass, prefix) => {
43
+ const payloadMetadata = (0, utils_1.getMetadataByKey)(payloadClass, (0, exports.createFieldName)(prefix, field_types_1.FieldProperties.payload)) || {
44
+ name: payloadClass.name,
45
+ id: payloadClass.name,
46
+ };
47
+ const properties = (0, utils_1.getMetadataPrototypeByKey)(payloadClass, (0, exports.createFieldName)(prefix, field_types_1.FieldProperties.field));
48
+ if (!properties?.length) {
49
+ throw new Error(`should include Field properties in ${payloadClass.name} class`);
50
+ }
51
+ return {
52
+ ...metadata,
53
+ properties,
54
+ type: 'Object',
55
+ payload: payloadMetadata,
56
+ };
57
+ };
58
+ const getFieldMetadata = (props) => {
59
+ const { fieldProps, destinationName, type, prefix } = props;
60
+ const metadata = {
61
+ destinationName,
62
+ name: fieldProps?.name || destinationName,
63
+ };
64
+ let primitiveType = (0, exports.getPrimitiveType)(type);
65
+ if (!primitiveType && fieldProps?.type) {
66
+ primitiveType = (0, exports.getPrimitiveType)(fieldProps.type);
67
+ }
68
+ const typeHasValue = exports.mapTypeofValueToPrimitiveType[typeof fieldProps?.type];
69
+ if (fieldProps?.type !== undefined) {
70
+ if (typeof fieldProps.type === 'function' && !primitiveType) {
71
+ return getObjectMetadata(metadata, fieldProps.type, prefix);
72
+ }
73
+ if (Array.isArray(fieldProps.type)) {
74
+ const arrayPrimitiveType = (0, exports.getPrimitiveType)(fieldProps.type[0]);
75
+ let items;
76
+ if (arrayPrimitiveType) {
77
+ items = {
78
+ type: arrayPrimitiveType,
79
+ name: arrayPrimitiveType,
80
+ destinationName: arrayPrimitiveType,
81
+ };
82
+ }
83
+ else {
84
+ if (typeof fieldProps.type[0] === 'function') {
85
+ items = getObjectMetadata({
86
+ name: 'Object',
87
+ destinationName: 'Object',
88
+ }, fieldProps.type[0], prefix);
89
+ }
90
+ }
91
+ return {
92
+ ...metadata,
93
+ type: 'Array',
94
+ items,
95
+ };
96
+ }
97
+ }
98
+ if (exports.primitiveTypeValues.has(type) ||
99
+ exports.primitiveTypeValues.has(primitiveType) ||
100
+ typeHasValue) {
101
+ return {
102
+ type: primitiveType || typeHasValue || type,
103
+ initialValue: typeHasValue ? fieldProps?.type : undefined,
104
+ ...metadata,
105
+ };
106
+ }
107
+ throw new Error(`unidentified type ${type} in ${destinationName} field`);
108
+ };
109
+ const createFieldDecorator = ({ prefix, enableInLambdaInvocation, getMetadata, }) => (props) => (target, destinationName) => {
110
+ if (!(0, build_env_utils_1.isBuildEnvironment)() && !enableInLambdaInvocation) {
111
+ return;
112
+ }
113
+ const filedKey = (0, exports.createFieldName)(prefix, field_types_1.FieldProperties.field);
114
+ const fields = (0, utils_1.getMetadataByKey)(target, filedKey) || [];
115
+ const propertyType = Reflect.getMetadata('design:type', target, destinationName).name;
116
+ const parentMetadata = getMetadata(props);
117
+ const metadata = [
118
+ ...fields,
119
+ {
120
+ ...parentMetadata,
121
+ ...getFieldMetadata({
122
+ destinationName,
123
+ type: propertyType,
124
+ fieldProps: {
125
+ ...props,
126
+ type: parentMetadata.forceType ?? props?.type,
127
+ },
128
+ prefix,
129
+ }),
130
+ },
131
+ ];
132
+ Reflect.defineMetadata(filedKey, metadata, target);
133
+ };
134
+ exports.createFieldDecorator = createFieldDecorator;
135
+ const createFieldName = (prefix, type) => {
136
+ return `${prefix}:${type}`;
137
+ };
138
+ exports.createFieldName = createFieldName;
@@ -0,0 +1,71 @@
1
+ import type { PayloadMetadata } from '../payload';
2
+ export type BasicTypes = StringConstructor | NumberConstructor | BooleanConstructor;
3
+ export type AllowedTypes = String | Number | Boolean | Function | [String | Number | Boolean | Function];
4
+ export type AllowedTypesWithoutFunction = BasicTypes | [BasicTypes];
5
+ export type EnumValue = (string | number)[];
6
+ export interface FieldProps {
7
+ /**
8
+ * Original field name.
9
+ *
10
+ * Specifies the original name of the field as it is expected
11
+ * in the input or payload. This is used to map incoming data
12
+ * to the corresponding property in the system.
13
+ */
14
+ name?: string;
15
+ /**
16
+ * Field data type.
17
+ *
18
+ * Specifies the type of the field. By default, the type is inferred
19
+ * from the property that decorates the field. However, it can be
20
+ * explicitly set to a primitive type such as `String`, `Number`,
21
+ * `Boolean`, or to another payload type.
22
+ *
23
+ * This ensures correct parsing, validation, and serialization of the field's value.
24
+ */
25
+ type?: AllowedTypes;
26
+ }
27
+ export interface BaseFieldMetadata {
28
+ name: string;
29
+ destinationName: string;
30
+ }
31
+ export interface StringField extends BaseFieldMetadata {
32
+ type: 'String';
33
+ initialValue?: string;
34
+ }
35
+ export interface NumberField extends BaseFieldMetadata {
36
+ type: 'Number';
37
+ initialValue?: number;
38
+ }
39
+ export interface BooleanField extends BaseFieldMetadata {
40
+ type: 'Boolean';
41
+ initialValue?: boolean;
42
+ }
43
+ export interface ObjectField extends BaseFieldMetadata {
44
+ type: 'Object';
45
+ properties: FieldMetadata[];
46
+ payload: PayloadMetadata;
47
+ }
48
+ export interface ArrayField extends BaseFieldMetadata {
49
+ type: 'Array';
50
+ items: FieldMetadata;
51
+ }
52
+ export type FieldMetadata = StringField | NumberField | BooleanField | ObjectField | ArrayField;
53
+ export type FieldTypes = FieldMetadata['type'];
54
+ export type PrimitiveTypes = Extract<FieldTypes, 'String' | 'Number' | 'Boolean'>;
55
+ export declare enum FieldProperties {
56
+ field = "lafken:field",
57
+ payload = "lafken:payload"
58
+ }
59
+ export interface CreateFieldDecoratorProps<P extends FieldProps, M> {
60
+ prefix: string;
61
+ enableInLambdaInvocation?: boolean;
62
+ getMetadata: (props?: P) => Omit<M, keyof FieldMetadata> & {
63
+ forceType?: any;
64
+ };
65
+ }
66
+ export interface GetFieldMetadataProps {
67
+ type: string;
68
+ prefix: string;
69
+ destinationName: string;
70
+ fieldProps?: FieldProps;
71
+ }