@spytecgps/lambda-utils 3.0.6-rc.0 → 3.0.8
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/dist/index.d.ts +1 -0
- package/dist/index.js +12 -0
- package/dist/middleware/contextualLogger.js +0 -1
- package/dist/middleware/middleware.test.d.ts +0 -1
- package/dist/middleware/warmup.js +0 -1
- package/dist/testing/eventFactories.d.ts +46 -0
- package/dist/testing/eventFactories.js +176 -0
- package/dist/testing/handlerInvoker.d.ts +15 -0
- package/dist/testing/handlerInvoker.js +22 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/types.d.ts +1 -1
- package/dist/validation/custom.d.ts +1 -1
- package/dist/validation/custom.js +10 -11
- package/dist/validation/requestContext.d.ts +1 -1
- package/dist/validation/requestContext.js +19 -38
- package/package.json +18 -26
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ var HttpError = require('./errors/HttpError.js');
|
|
|
10
10
|
var NotFoundError = require('./errors/NotFoundError.js');
|
|
11
11
|
var UnauthorizedError = require('./errors/UnauthorizedError.js');
|
|
12
12
|
var index$1 = require('./middleware/index.js');
|
|
13
|
+
var eventFactories = require('./testing/eventFactories.js');
|
|
14
|
+
var handlerInvoker = require('./testing/handlerInvoker.js');
|
|
13
15
|
var merge = require('deepmerge');
|
|
14
16
|
var cache = require('./utils/cache.js');
|
|
15
17
|
var cacheWrapper = require('./utils/cacheWrapper.js');
|
|
@@ -48,6 +50,16 @@ exports.NotFoundError = NotFoundError.default;
|
|
|
48
50
|
exports.UnauthorizedError = UnauthorizedError.default;
|
|
49
51
|
exports.getApiGatewayMiddlewares = index$1.getApiGatewayMiddlewares;
|
|
50
52
|
exports.getBaseMiddlewares = index$1.getBaseMiddlewares;
|
|
53
|
+
exports.createDynamoDbStreamEvent = eventFactories.createDynamoDbStreamEvent;
|
|
54
|
+
exports.createDynamoDbStreamRecord = eventFactories.createDynamoDbStreamRecord;
|
|
55
|
+
exports.createHttpEvent = eventFactories.createHttpEvent;
|
|
56
|
+
exports.createKinesisEvent = eventFactories.createKinesisEvent;
|
|
57
|
+
exports.createKinesisEventWithRawData = eventFactories.createKinesisEventWithRawData;
|
|
58
|
+
exports.createSqsEvent = eventFactories.createSqsEvent;
|
|
59
|
+
exports.encodeKinesisData = eventFactories.encodeKinesisData;
|
|
60
|
+
exports.invokeHttpHandler = handlerInvoker.invokeHttpHandler;
|
|
61
|
+
exports.invokeSqsHandler = handlerInvoker.invokeSqsHandler;
|
|
62
|
+
exports.mockContext = handlerInvoker.mockContext;
|
|
51
63
|
exports.merge = merge;
|
|
52
64
|
exports.LambdaCache = cache.LambdaCache;
|
|
53
65
|
exports.promiseWithCache = cacheWrapper.promiseWithCache;
|
|
@@ -18,7 +18,6 @@ const contextualLogger = ({ logger }) => {
|
|
|
18
18
|
if (event.headers) {
|
|
19
19
|
Object.keys(event.headers).forEach((header) => {
|
|
20
20
|
if (header.toLowerCase().startsWith(CORRELATION_HEADER)) {
|
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
22
21
|
ctx[header] = event.headers[header];
|
|
23
22
|
}
|
|
24
23
|
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { DynamoDBRecord, DynamoDBStreamEvent, KinesisStreamEvent, SQSEvent } from 'aws-lambda';
|
|
2
|
+
import type { SpytecAuthContext } from '../types';
|
|
3
|
+
/** Creates an SQS event. Body is JSON.stringified automatically. */
|
|
4
|
+
export declare function createSqsEvent<T extends object>(body: T): SQSEvent;
|
|
5
|
+
export declare function createSqsEvent<T extends object>(bodies: T[]): SQSEvent;
|
|
6
|
+
export interface CreateHttpEventOptions {
|
|
7
|
+
/** Authorizer context fields (merged into requestContext.authorizer). */
|
|
8
|
+
authorizer?: Partial<SpytecAuthContext> | Record<string, unknown>;
|
|
9
|
+
pathParameters?: Record<string, string | number>;
|
|
10
|
+
queryStringParameters?: Record<string, string>;
|
|
11
|
+
/** Body payload — auto-stringified via JSON.stringify. */
|
|
12
|
+
body?: unknown;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
httpMethod?: string;
|
|
15
|
+
path?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates an API Gateway proxy event for HTTP handler tests.
|
|
19
|
+
* Body is JSON.stringified automatically. Authorizer fields are placed into
|
|
20
|
+
* requestContext.authorizer for you.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createHttpEvent<T = unknown>(options?: CreateHttpEventOptions): T;
|
|
23
|
+
export interface CreateDynamoDbStreamRecordOptions<T = object> {
|
|
24
|
+
newImage?: T;
|
|
25
|
+
oldImage?: T;
|
|
26
|
+
/** Explicit key attributes for the record. */
|
|
27
|
+
keys?: Record<string, unknown>;
|
|
28
|
+
/** Field names to extract as keys from newImage/oldImage when keys not provided. */
|
|
29
|
+
keyFields?: string[];
|
|
30
|
+
}
|
|
31
|
+
/** Creates a DynamoDB Stream record. Uses marshall from @aws-sdk/util-dynamodb for attribute conversion. */
|
|
32
|
+
export declare function createDynamoDbStreamRecord<T extends object>(eventName: 'INSERT' | 'MODIFY' | 'REMOVE', optionsOrNewImage?: CreateDynamoDbStreamRecordOptions<T> | T, oldImageParam?: T): DynamoDBRecord;
|
|
33
|
+
/** Creates a DynamoDB Stream event from records. */
|
|
34
|
+
export declare function createDynamoDbStreamEvent(records: DynamoDBRecord[]): DynamoDBStreamEvent;
|
|
35
|
+
/** Encodes a value as base64 for Kinesis record data. */
|
|
36
|
+
export declare function encodeKinesisData<T>(value: T): string;
|
|
37
|
+
export interface CreateKinesisEventOptions {
|
|
38
|
+
/** Extract partition key from each record. Defaults to index-based. */
|
|
39
|
+
partitionKey?: (record: unknown, index: number) => string;
|
|
40
|
+
/** Minimal record structure (just kinesis.data) vs full record. */
|
|
41
|
+
minimal?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** Creates a Kinesis event with raw base64 record data (e.g. for malformed payload tests). */
|
|
44
|
+
export declare function createKinesisEventWithRawData(dataBase64: string[]): KinesisStreamEvent;
|
|
45
|
+
/** Creates a Kinesis stream event from record payloads. */
|
|
46
|
+
export declare function createKinesisEvent<T>(records: T[], options?: CreateKinesisEventOptions): KinesisStreamEvent;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utilDynamodb = require('@aws-sdk/util-dynamodb');
|
|
4
|
+
|
|
5
|
+
function createSqsEvent(bodyOrBodies) {
|
|
6
|
+
const bodies = Array.isArray(bodyOrBodies) ? bodyOrBodies : [bodyOrBodies];
|
|
7
|
+
return {
|
|
8
|
+
Records: bodies.map((body) => ({
|
|
9
|
+
messageId: `msg-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
10
|
+
receiptHandle: 'receipt-handle',
|
|
11
|
+
body: JSON.stringify(body),
|
|
12
|
+
attributes: {
|
|
13
|
+
ApproximateReceiveCount: '1',
|
|
14
|
+
SentTimestamp: Date.now().toString(),
|
|
15
|
+
SenderId: 'AIDAIT2UOQQY3AUEKVGXU',
|
|
16
|
+
ApproximateFirstReceiveTimestamp: Date.now().toString(),
|
|
17
|
+
},
|
|
18
|
+
messageAttributes: {},
|
|
19
|
+
md5OfBody: 'md5',
|
|
20
|
+
eventSource: 'aws:sqs',
|
|
21
|
+
eventSourceARN: 'arn:aws:sqs:us-east-1:123456789012:test-queue',
|
|
22
|
+
awsRegion: 'us-east-1',
|
|
23
|
+
})),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Creates an API Gateway proxy event for HTTP handler tests.
|
|
28
|
+
* Body is JSON.stringified automatically. Authorizer fields are placed into
|
|
29
|
+
* requestContext.authorizer for you.
|
|
30
|
+
*/
|
|
31
|
+
function createHttpEvent(options = {}) {
|
|
32
|
+
const { authorizer, pathParameters, queryStringParameters, body, headers, httpMethod = 'GET', path = '/' } = options;
|
|
33
|
+
const event = {
|
|
34
|
+
httpMethod,
|
|
35
|
+
path,
|
|
36
|
+
headers: headers ?? {},
|
|
37
|
+
multiValueHeaders: {},
|
|
38
|
+
pathParameters: pathParameters
|
|
39
|
+
? Object.fromEntries(Object.entries(pathParameters).map(([k, v]) => [k, String(v)]))
|
|
40
|
+
: null,
|
|
41
|
+
queryStringParameters: queryStringParameters ?? null,
|
|
42
|
+
multiValueQueryStringParameters: null,
|
|
43
|
+
body: body !== undefined && body !== null ? JSON.stringify(body) : null,
|
|
44
|
+
isBase64Encoded: false,
|
|
45
|
+
resource: path,
|
|
46
|
+
stageVariables: null,
|
|
47
|
+
requestContext: {
|
|
48
|
+
authorizer: authorizer ?? {},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
return event;
|
|
52
|
+
}
|
|
53
|
+
function pickKeys(image, keyFields) {
|
|
54
|
+
return keyFields.reduce((acc, k) => {
|
|
55
|
+
if (k in image)
|
|
56
|
+
acc[k] = image[k];
|
|
57
|
+
return acc;
|
|
58
|
+
}, {});
|
|
59
|
+
}
|
|
60
|
+
/** Creates a DynamoDB Stream record. Uses marshall from @aws-sdk/util-dynamodb for attribute conversion. */
|
|
61
|
+
function createDynamoDbStreamRecord(eventName, optionsOrNewImage, oldImageParam) {
|
|
62
|
+
let newImage;
|
|
63
|
+
let oldImage;
|
|
64
|
+
let keys;
|
|
65
|
+
let keyFields;
|
|
66
|
+
const isOptions = (o) => o != null && typeof o === 'object' && ('newImage' in o || 'oldImage' in o || 'keys' in o || 'keyFields' in o);
|
|
67
|
+
if (isOptions(optionsOrNewImage)) {
|
|
68
|
+
const opts = optionsOrNewImage;
|
|
69
|
+
newImage = opts.newImage;
|
|
70
|
+
oldImage = opts.oldImage;
|
|
71
|
+
keys = opts.keys;
|
|
72
|
+
keyFields = opts.keyFields;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
newImage = optionsOrNewImage;
|
|
76
|
+
oldImage = oldImageParam;
|
|
77
|
+
}
|
|
78
|
+
const image = newImage ?? oldImage;
|
|
79
|
+
const resolvedKeys = keys ??
|
|
80
|
+
(keyFields && image ? pickKeys(image, keyFields) : undefined) ??
|
|
81
|
+
(image ? { id: 'unknown' } : { id: 'unknown' });
|
|
82
|
+
return {
|
|
83
|
+
eventID: `event-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
84
|
+
eventName,
|
|
85
|
+
eventVersion: '1.1',
|
|
86
|
+
eventSource: 'aws:dynamodb',
|
|
87
|
+
awsRegion: 'us-east-1',
|
|
88
|
+
dynamodb: {
|
|
89
|
+
Keys: utilDynamodb.marshall(resolvedKeys),
|
|
90
|
+
NewImage: newImage ? utilDynamodb.marshall(newImage) : undefined,
|
|
91
|
+
OldImage: oldImage ? utilDynamodb.marshall(oldImage) : undefined,
|
|
92
|
+
SequenceNumber: '123456789',
|
|
93
|
+
SizeBytes: 100,
|
|
94
|
+
StreamViewType: 'NEW_AND_OLD_IMAGES',
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/** Creates a DynamoDB Stream event from records. */
|
|
99
|
+
function createDynamoDbStreamEvent(records) {
|
|
100
|
+
return { Records: records };
|
|
101
|
+
}
|
|
102
|
+
// ── Kinesis ─────────────────────────────────────────────────────────────────
|
|
103
|
+
const DEFAULT_KINESIS_STREAM_ARN = 'arn:aws:kinesis:us-east-1:123456789012:stream/test-stream';
|
|
104
|
+
/** Encodes a value as base64 for Kinesis record data. */
|
|
105
|
+
function encodeKinesisData(value) {
|
|
106
|
+
return Buffer.from(JSON.stringify(value)).toString('base64');
|
|
107
|
+
}
|
|
108
|
+
/** Creates a Kinesis event with raw base64 record data (e.g. for malformed payload tests). */
|
|
109
|
+
function createKinesisEventWithRawData(dataBase64) {
|
|
110
|
+
return {
|
|
111
|
+
Records: dataBase64.map((data, index) => ({
|
|
112
|
+
eventSource: 'aws:kinesis',
|
|
113
|
+
eventVersion: '1.0',
|
|
114
|
+
eventID: String(index),
|
|
115
|
+
eventName: 'aws:kinesis:record',
|
|
116
|
+
invokeIdentityArn: 'arn:aws:iam::123456789012:role/lambda-role',
|
|
117
|
+
eventSourceARN: DEFAULT_KINESIS_STREAM_ARN,
|
|
118
|
+
awsRegion: 'us-east-1',
|
|
119
|
+
kinesis: {
|
|
120
|
+
partitionKey: String(index),
|
|
121
|
+
data: data,
|
|
122
|
+
kinesisSchemaVersion: '1.0',
|
|
123
|
+
sequenceNumber: String(index),
|
|
124
|
+
approximateArrivalTimestamp: Date.now() / 1000,
|
|
125
|
+
},
|
|
126
|
+
})),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** Creates a Kinesis stream event from record payloads. */
|
|
130
|
+
function createKinesisEvent(records, options = {}) {
|
|
131
|
+
const { partitionKey, minimal = false } = options;
|
|
132
|
+
return {
|
|
133
|
+
Records: records.map((record, index) => {
|
|
134
|
+
const data = encodeKinesisData(record);
|
|
135
|
+
const pk = partitionKey?.(record, index) ??
|
|
136
|
+
(typeof record === 'object' && record !== null && 'imei' in record
|
|
137
|
+
? String(record.imei)
|
|
138
|
+
: String(index));
|
|
139
|
+
if (minimal) {
|
|
140
|
+
return {
|
|
141
|
+
kinesis: {
|
|
142
|
+
data,
|
|
143
|
+
partitionKey: pk,
|
|
144
|
+
kinesisSchemaVersion: '1.0',
|
|
145
|
+
sequenceNumber: String(index),
|
|
146
|
+
approximateArrivalTimestamp: Date.now() / 1000,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
eventSource: 'aws:kinesis',
|
|
152
|
+
eventVersion: '1.0',
|
|
153
|
+
eventID: String(index),
|
|
154
|
+
eventName: 'aws:kinesis:record',
|
|
155
|
+
invokeIdentityArn: 'arn:aws:iam::123456789012:role/lambda-role',
|
|
156
|
+
eventSourceARN: DEFAULT_KINESIS_STREAM_ARN,
|
|
157
|
+
awsRegion: 'us-east-1',
|
|
158
|
+
kinesis: {
|
|
159
|
+
partitionKey: pk,
|
|
160
|
+
data,
|
|
161
|
+
kinesisSchemaVersion: '1.0',
|
|
162
|
+
sequenceNumber: String(index),
|
|
163
|
+
approximateArrivalTimestamp: Date.now() / 1000,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
exports.createDynamoDbStreamEvent = createDynamoDbStreamEvent;
|
|
171
|
+
exports.createDynamoDbStreamRecord = createDynamoDbStreamRecord;
|
|
172
|
+
exports.createHttpEvent = createHttpEvent;
|
|
173
|
+
exports.createKinesisEvent = createKinesisEvent;
|
|
174
|
+
exports.createKinesisEventWithRawData = createKinesisEventWithRawData;
|
|
175
|
+
exports.createSqsEvent = createSqsEvent;
|
|
176
|
+
exports.encodeKinesisData = encodeKinesisData;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { APIGatewayProxyResult, Context, SQSBatchResponse, SQSEvent } from 'aws-lambda';
|
|
2
|
+
/** Minimal Lambda context for testing. */
|
|
3
|
+
export declare const mockContext: Context;
|
|
4
|
+
type AnyHandler = (event: any, context: any, ...rest: any[]) => any;
|
|
5
|
+
/**
|
|
6
|
+
* Invoke an HTTP/API Gateway handler and return a typed response.
|
|
7
|
+
* Eliminates the `const response: any = await handler(event, mockContext)` pattern.
|
|
8
|
+
*/
|
|
9
|
+
export declare function invokeHttpHandler(handler: AnyHandler, event: unknown, context?: Context): Promise<APIGatewayProxyResult>;
|
|
10
|
+
/**
|
|
11
|
+
* Invoke an SQS handler and return the result.
|
|
12
|
+
* Handles both 2-arg (event, context) and 3-arg (event, context, callback) signatures.
|
|
13
|
+
*/
|
|
14
|
+
export declare function invokeSqsHandler(handler: AnyHandler, event: SQSEvent, context?: Context): Promise<SQSBatchResponse | void>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** Minimal Lambda context for testing. */
|
|
4
|
+
const mockContext = {};
|
|
5
|
+
/**
|
|
6
|
+
* Invoke an HTTP/API Gateway handler and return a typed response.
|
|
7
|
+
* Eliminates the `const response: any = await handler(event, mockContext)` pattern.
|
|
8
|
+
*/
|
|
9
|
+
async function invokeHttpHandler(handler, event, context = mockContext) {
|
|
10
|
+
return (await handler(event, context));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Invoke an SQS handler and return the result.
|
|
14
|
+
* Handles both 2-arg (event, context) and 3-arg (event, context, callback) signatures.
|
|
15
|
+
*/
|
|
16
|
+
async function invokeSqsHandler(handler, event, context = mockContext) {
|
|
17
|
+
return (await handler(event, context, () => { }));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
exports.invokeHttpHandler = invokeHttpHandler;
|
|
21
|
+
exports.invokeSqsHandler = invokeSqsHandler;
|
|
22
|
+
exports.mockContext = mockContext;
|
package/dist/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { APIGatewayEventRequestContext, APIGatewayProxyEvent, APIGatewayProxyWit
|
|
|
2
2
|
import { Callback } from 'aws-lambda/handler';
|
|
3
3
|
import { APIGatewayProxyEventBase } from 'aws-lambda/trigger/api-gateway-proxy';
|
|
4
4
|
import { ObjectSchema } from 'joi';
|
|
5
|
-
import
|
|
5
|
+
import Joi from 'joi';
|
|
6
6
|
export interface SpytecAuthorizedResources {
|
|
7
7
|
devices: string[];
|
|
8
8
|
boundaries: number[];
|
|
@@ -23,12 +23,11 @@ function _interopNamespaceDefault(e) {
|
|
|
23
23
|
return Object.freeze(n);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
var Joi__namespace = /*#__PURE__*/_interopNamespaceDefault(Joi);
|
|
27
26
|
var qs__namespace = /*#__PURE__*/_interopNamespaceDefault(qs);
|
|
28
27
|
|
|
29
28
|
dayjs.extend(utc);
|
|
30
29
|
dayjs.extend(timezone);
|
|
31
|
-
const json =
|
|
30
|
+
const json = Joi.extend((joi) => {
|
|
32
31
|
return {
|
|
33
32
|
type: 'object',
|
|
34
33
|
base: joi.object(),
|
|
@@ -39,7 +38,7 @@ const json = Joi__namespace.extend((joi) => {
|
|
|
39
38
|
try {
|
|
40
39
|
return { value: JSON.parse(value) };
|
|
41
40
|
}
|
|
42
|
-
catch (
|
|
41
|
+
catch (_err) {
|
|
43
42
|
return null;
|
|
44
43
|
}
|
|
45
44
|
},
|
|
@@ -51,7 +50,7 @@ const json = Joi__namespace.extend((joi) => {
|
|
|
51
50
|
},
|
|
52
51
|
};
|
|
53
52
|
});
|
|
54
|
-
const urlEncoded =
|
|
53
|
+
const urlEncoded = Joi.extend((joi) => {
|
|
55
54
|
return {
|
|
56
55
|
type: 'object',
|
|
57
56
|
base: joi.object(),
|
|
@@ -60,13 +59,13 @@ const urlEncoded = Joi__namespace.extend((joi) => {
|
|
|
60
59
|
},
|
|
61
60
|
};
|
|
62
61
|
});
|
|
63
|
-
const imeiSchema =
|
|
62
|
+
const imeiSchema = Joi.string()
|
|
64
63
|
.regex(/^\d{15,16}$/)
|
|
65
64
|
.message('Invalid IMEI');
|
|
66
|
-
const iccidSchema =
|
|
65
|
+
const iccidSchema = Joi.string()
|
|
67
66
|
.regex(/^[0-9A-Za-z]{18,22}$/)
|
|
68
67
|
.message('Invalid ICCID');
|
|
69
|
-
const SpytecJoi =
|
|
68
|
+
const SpytecJoi = Joi.extend((joi) => ({
|
|
70
69
|
type: 'imei',
|
|
71
70
|
messages: 'Invalid IMEI',
|
|
72
71
|
base: joi.string().regex(/^\d{15,16}$/),
|
|
@@ -87,7 +86,7 @@ const SpytecJoi = Joi__namespace.extend((joi) => ({
|
|
|
87
86
|
try {
|
|
88
87
|
return { value: JSON.parse(value) };
|
|
89
88
|
}
|
|
90
|
-
catch (
|
|
89
|
+
catch (_err) {
|
|
91
90
|
return null;
|
|
92
91
|
}
|
|
93
92
|
},
|
|
@@ -117,7 +116,7 @@ const SpytecJoi = Joi__namespace.extend((joi) => ({
|
|
|
117
116
|
return { value: dayjsDate.toDate() };
|
|
118
117
|
}
|
|
119
118
|
}
|
|
120
|
-
catch (
|
|
119
|
+
catch (_error) {
|
|
121
120
|
return helpers.error('any.invalid');
|
|
122
121
|
}
|
|
123
122
|
},
|
|
@@ -128,7 +127,7 @@ const SpytecJoi = Joi__namespace.extend((joi) => ({
|
|
|
128
127
|
try {
|
|
129
128
|
return { value: JSON.parse(value) };
|
|
130
129
|
}
|
|
131
|
-
catch (
|
|
130
|
+
catch (_err) {
|
|
132
131
|
return { value: null };
|
|
133
132
|
}
|
|
134
133
|
},
|
|
@@ -146,7 +145,7 @@ const SpytecJoi = Joi__namespace.extend((joi) => ({
|
|
|
146
145
|
const decodedValue = decodeURIComponent(Buffer.from(value, 'base64').toString());
|
|
147
146
|
return { value: JSON.parse(decodedValue) };
|
|
148
147
|
}
|
|
149
|
-
catch (
|
|
148
|
+
catch (_err) {
|
|
150
149
|
return null;
|
|
151
150
|
}
|
|
152
151
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { APIGatewayEventRequestContextWithAuthorizer } from 'aws-lambda/common/api-gateway';
|
|
2
|
-
import
|
|
2
|
+
import Joi from 'joi';
|
|
3
3
|
import { SpytecAuthContext, SpytecAuthContextV4 } from '../types';
|
|
4
4
|
type GetAuthorizerValidatorParams = Partial<Record<keyof SpytecAuthContext, Joi.AnySchema>>;
|
|
5
5
|
type GetAuthorizerValidatorParamsV4 = Partial<Record<keyof SpytecAuthContextV4, Joi.AnySchema>>;
|
|
@@ -3,65 +3,46 @@
|
|
|
3
3
|
var Joi = require('joi');
|
|
4
4
|
var custom = require('./custom.js');
|
|
5
5
|
|
|
6
|
-
function _interopNamespaceDefault(e) {
|
|
7
|
-
var n = Object.create(null);
|
|
8
|
-
if (e) {
|
|
9
|
-
Object.keys(e).forEach(function (k) {
|
|
10
|
-
if (k !== 'default') {
|
|
11
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
12
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
get: function () { return e[k]; }
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
n.default = e;
|
|
20
|
-
return Object.freeze(n);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
var Joi__namespace = /*#__PURE__*/_interopNamespaceDefault(Joi);
|
|
24
|
-
|
|
25
6
|
const getAuthorizerValidator = (params = {}) => {
|
|
26
|
-
return
|
|
27
|
-
clientId:
|
|
28
|
-
userId:
|
|
7
|
+
return Joi.object({
|
|
8
|
+
clientId: Joi.number().greater(0).required(),
|
|
9
|
+
userId: Joi.string().guid( /*{ version: 'uuidv4' }*/).required(),
|
|
29
10
|
resources: custom.json.object({}),
|
|
30
|
-
scope:
|
|
11
|
+
scope: Joi.string().optional(),
|
|
31
12
|
// .error(() => new UnauthorizedError(`missing scope ${scope}`))
|
|
32
|
-
type:
|
|
13
|
+
type: Joi.string().optional(),
|
|
33
14
|
// .error(() => new UnauthorizedError(`missing user type ${type}`))
|
|
34
|
-
enterprise:
|
|
35
|
-
maintenanceModule:
|
|
36
|
-
billingMethod:
|
|
37
|
-
customerSegment:
|
|
38
|
-
securityGroupTagId:
|
|
39
|
-
securityRole:
|
|
15
|
+
enterprise: Joi.boolean().default(false),
|
|
16
|
+
maintenanceModule: Joi.boolean().default(false),
|
|
17
|
+
billingMethod: Joi.string().optional(),
|
|
18
|
+
customerSegment: Joi.string().optional(),
|
|
19
|
+
securityGroupTagId: Joi.number().optional().allow(null),
|
|
20
|
+
securityRole: Joi.string().optional().allow(null),
|
|
40
21
|
...params,
|
|
41
22
|
});
|
|
42
23
|
};
|
|
43
24
|
const getAuthorizerValidatorV4 = (params = {}) => {
|
|
44
|
-
return
|
|
45
|
-
clientId:
|
|
46
|
-
userId:
|
|
47
|
-
scope:
|
|
48
|
-
type:
|
|
25
|
+
return Joi.object({
|
|
26
|
+
clientId: Joi.number().greater(0).required(),
|
|
27
|
+
userId: Joi.string().guid( /*{ version: 'uuidv4' }*/).required(),
|
|
28
|
+
scope: Joi.string().optional(),
|
|
29
|
+
type: Joi.string().optional(),
|
|
49
30
|
...params,
|
|
50
31
|
});
|
|
51
32
|
};
|
|
52
33
|
/**
|
|
53
34
|
* @deprecated
|
|
54
35
|
*/
|
|
55
|
-
const requestContextValidator =
|
|
36
|
+
const requestContextValidator = Joi.object({
|
|
56
37
|
authorizer: getAuthorizerValidator(),
|
|
57
38
|
});
|
|
58
39
|
const getRequestContextValidator = (params = {}) => {
|
|
59
|
-
return
|
|
40
|
+
return Joi.object({
|
|
60
41
|
authorizer: getAuthorizerValidator(params),
|
|
61
42
|
});
|
|
62
43
|
};
|
|
63
44
|
const getRequestContextValidatorV4 = (params = {}) => {
|
|
64
|
-
return
|
|
45
|
+
return Joi.object({
|
|
65
46
|
authorizer: getAuthorizerValidatorV4(params),
|
|
66
47
|
});
|
|
67
48
|
};
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spytecgps/lambda-utils",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.8",
|
|
4
4
|
"description": "Lambda Utils",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"lint": "eslint
|
|
9
|
-
"lint
|
|
10
|
-
"test": "
|
|
8
|
+
"lint": "eslint --cache --cache-strategy content .",
|
|
9
|
+
"lint:fix": "eslint --cache --cache-strategy content . --fix",
|
|
10
|
+
"test": "vitest run --reporter=default --coverage",
|
|
11
|
+
"type-check": "tsc --noEmit",
|
|
11
12
|
"version": "npm run format && git add -A src",
|
|
12
13
|
"postversion": "git push && git push --tags",
|
|
13
14
|
"prepublishOnly": "npm run lint",
|
|
@@ -28,6 +29,7 @@
|
|
|
28
29
|
},
|
|
29
30
|
"homepage": "https://github.com/spytecgps/lambda-utils#readme",
|
|
30
31
|
"dependencies": {
|
|
32
|
+
"@aws-sdk/util-dynamodb": "^3.731.1",
|
|
31
33
|
"@middy/core": "^2.5.7",
|
|
32
34
|
"@middy/http-error-handler": "^2.5.7",
|
|
33
35
|
"@middy/http-response-serializer": "^2.5.7",
|
|
@@ -43,33 +45,23 @@
|
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
45
47
|
"@aws-sdk/client-lambda": "^3.731.1",
|
|
46
|
-
"@
|
|
47
|
-
"@rollup/plugin-json": "^6.1.0",
|
|
48
|
-
"@rollup/plugin-node-resolve": "^16.0.0",
|
|
49
|
-
"@rollup/plugin-terser": "^0.4.4",
|
|
48
|
+
"@eslint/js": "^9.18.0",
|
|
50
49
|
"@rollup/plugin-typescript": "^12.1.2",
|
|
51
50
|
"@spytecgps/sdk-logger": "^2.0.18",
|
|
52
51
|
"@types/aws-lambda": "^8.10.76",
|
|
53
|
-
"@types/
|
|
54
|
-
"@
|
|
55
|
-
"@
|
|
56
|
-
"@
|
|
57
|
-
"@typescript-eslint/parser": "^5.42.1",
|
|
52
|
+
"@types/node": "^22",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^8.21.0",
|
|
54
|
+
"@typescript-eslint/parser": "^8.21.0",
|
|
55
|
+
"@vitest/coverage-v8": "^3.0.5",
|
|
58
56
|
"aws-sdk-client-mock": "^4.1.0",
|
|
59
|
-
"
|
|
60
|
-
"eslint": "^
|
|
61
|
-
"eslint-
|
|
62
|
-
"eslint-plugin-import": "^
|
|
63
|
-
"
|
|
64
|
-
"eslint-plugin-simple-import-sort": "^8.0.0",
|
|
65
|
-
"jest": "^29.7.0",
|
|
66
|
-
"jest-junit": "^16",
|
|
67
|
-
"prettier": "^2.8.8",
|
|
68
|
-
"prettier-eslint": "^16.3.0",
|
|
57
|
+
"eslint": "^9.18.0",
|
|
58
|
+
"eslint-config-prettier": "^10.0.1",
|
|
59
|
+
"eslint-plugin-prettier": "^5.2.3",
|
|
60
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
61
|
+
"prettier": "^3.4.2",
|
|
69
62
|
"rollup": "^4.24.0",
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"typescript": "^5.6.3"
|
|
63
|
+
"typescript": "^5.6.3",
|
|
64
|
+
"vitest": "^3.0.5"
|
|
73
65
|
},
|
|
74
66
|
"files": [
|
|
75
67
|
"dist/**/*"
|