diff --git a/.github/workflows/test-and-release.yaml b/.github/workflows/test-and-release.yaml index a41ef640b..0333bb4bd 100644 --- a/.github/workflows/test-and-release.yaml +++ b/.github/workflows/test-and-release.yaml @@ -79,8 +79,7 @@ jobs: - run: echo "VERSION=${{ github.sha }}" >> $GITHUB_ENV - name: Set up stack for End-to-End tests run: | - npx cdk -a 'node --loader tsx --unhandled-rejections=strict cdk/cloudformation-sourcecode.ts' bootstrap aws://`aws sts get-caller-identity | jq -r '.Account' | tr -d '\n'`/${{ env.AWS_REGION }} - npx cdk -a 'node --loader tsx --unhandled-rejections=strict cdk/cloudformation-sourcecode.ts' deploy + npx cdk -a 'node --loader tsx --unhandled-rejections=strict cdk/cloudformation-test.ts' bootstrap aws://`aws sts get-caller-identity | jq -r '.Account' | tr -d '\n'`/${{ env.AWS_REGION }} npx cdk -a 'node --loader tsx --unhandled-rejections=strict cdk/cloudformation-http-api-mock.ts' deploy '*' --require-approval never ./cli.sh configure thirdParty nrfcloud teamId `uuidgen` openssl ecparam -name prime256v1 -genkey | ./cli.sh configure thirdParty nrfcloud agpsLocationServiceKey @@ -112,11 +111,6 @@ jobs: ./cli.sh purge-buckets npx cdk -a 'node --loader tsx --unhandled-rejections=strict cdk/cloudformation-test.ts' destroy -f '*' npx cdk -a 'node --loader tsx --unhandled-rejections=strict cdk/cloudformation-http-api-mock.ts' destroy -f '*' - # Delete sourcecode bucket - SOURCE_CODE_BUCKET=`aws cloudformation describe-stacks --stack-name $STACK_NAME-sourcecode | jq -r '.Stacks[0].Outputs[] | select(.OutputKey == "bucketName") | .OutputValue'` - aws s3 rb s3://$SOURCE_CODE_BUCKET --force - # Delete the sourceode stack - npx cdk -a 'node --loader tsx --unhandled-rejections=strict cdk/cloudformation-sourcecode.ts' destroy -f '*' - uses: actions/upload-artifact@v3 if: always() with: diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index 4dda6599b..000000000 --- a/.prettierrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - ...require('@nordicsemiconductor/asset-tracker-cloud-code-style/.prettierrc'), -} diff --git a/agps/cacheKey.spec.ts b/agps/cacheKey.spec.ts index f3159e56a..f2e8d517c 100644 --- a/agps/cacheKey.spec.ts +++ b/agps/cacheKey.spec.ts @@ -1,4 +1,4 @@ -import { cacheKey } from './cacheKey' +import { cacheKey } from './cacheKey.js' describe('cacheKey', () => { it('should create a cache key', () => diff --git a/agps/cacheKey.ts b/agps/cacheKey.ts index 00bd18ce7..4f1b398b4 100644 --- a/agps/cacheKey.ts +++ b/agps/cacheKey.ts @@ -1,5 +1,5 @@ -import { Static } from '@sinclair/typebox' -import { agpsRequestSchema } from './types' +import type { Static } from '@sinclair/typebox' +import type { agpsRequestSchema } from './types.js' export const cacheKey = ({ request, diff --git a/agps/deviceRequestHandler.ts b/agps/deviceRequestHandler.ts index ed7ab8822..1f452d2ec 100644 --- a/agps/deviceRequestHandler.ts +++ b/agps/deviceRequestHandler.ts @@ -9,14 +9,13 @@ import { SendMessageBatchRequestEntry, SQSClient, } from '@aws-sdk/client-sqs' -import { Static } from '@sinclair/typebox' -import { SQSEvent, SQSMessageAttributes } from 'aws-lambda' -import { isRight } from 'fp-ts/lib/These' +import type { Static } from '@sinclair/typebox' +import type { SQSEvent, SQSMessageAttributes } from 'aws-lambda' import { randomUUID } from 'node:crypto' -import { fromEnv } from '../util/fromEnv' -import { cacheKey } from './cacheKey' -import { AGPSDataCache, getCache } from './getCache' -import { agpsRequestSchema } from './types' +import { fromEnv } from '../util/fromEnv.js' +import { cacheKey } from './cacheKey.js' +import { AGPSDataCache, getCache } from './getCache.js' +import type { agpsRequestSchema } from './types.js' const { binHoursString, @@ -84,7 +83,7 @@ export const handler = async (event: SQSEvent): Promise => { if (grouped[k] === undefined) { grouped[k] = [deviceRequest] } else { - grouped[k].push(deviceRequest) + grouped[k]?.push(deviceRequest) } return grouped }, @@ -104,19 +103,10 @@ export const handler = async (event: SQSEvent): Promise => { if (resolvedRequests[cacheKey] === undefined) { console.debug(cacheKey, 'Load from DB') const d = await c(cacheKey) - if (isRight(d)) { - if (d.right?.unresolved !== undefined) { - console.debug(cacheKey, 'Processing of the request is finished') - resolvedRequests[cacheKey] = d.right - if (d.right.unresolved === true) { - console.error(cacheKey, `A-GPS request is unresolved.`) - return - } - } - } else { + if ('error' in d) { console.debug(cacheKey, 'cache does not exist') - console.warn({ getCache: d.left }) - const r = deviceRequests[0].request + console.warn({ getCache: d }) + const r = deviceRequests[0]?.request await Promise.all([ // Create DB entry await dynamodb @@ -128,25 +118,25 @@ export const handler = async (event: SQSEvent): Promise => { S: cacheKey, }, mcc: { - N: `${r.mcc}`, + N: `${r?.mcc}`, }, mnc: { - N: `${r.mnc}`, + N: `${r?.mnc}`, }, cell: { - N: `${r.cell}`, + N: `${r?.cell}`, }, area: { - N: `${r.area}`, + N: `${r?.area}`, }, phycell: - r.phycell !== undefined + r?.phycell !== undefined ? { N: `${r.phycell}`, } : { NULL: true }, types: { - NS: r.types.map((t) => `${t}`), + NS: r?.types.map((t) => `${t}`) ?? [], }, updatedAt: { S: new Date().toISOString(), @@ -189,13 +179,22 @@ export const handler = async (event: SQSEvent): Promise => { ) }), ]) + } else { + if (d.unresolved !== undefined) { + console.debug(cacheKey, 'Processing of the request is finished') + resolvedRequests[cacheKey] = d + if (d.unresolved === true) { + console.error(cacheKey, `A-GPS request is unresolved.`) + return + } + } } } // The data for these requests is available if ( resolvedRequests[cacheKey]?.unresolved !== undefined && - resolvedRequests[cacheKey].unresolved === false + resolvedRequests[cacheKey]?.unresolved === false ) { console.debug(cacheKey, 'data for these requests is available') console.debug( diff --git a/agps/getCache.ts b/agps/getCache.ts index 9dff114d6..73e7849d1 100644 --- a/agps/getCache.ts +++ b/agps/getCache.ts @@ -1,9 +1,8 @@ import { DynamoDBClient, GetItemCommand } from '@aws-sdk/client-dynamodb' import { unmarshall } from '@aws-sdk/util-dynamodb' -import { Static } from '@sinclair/typebox' -import { Either, left, right } from 'fp-ts/lib/Either' -import { ErrorInfo, ErrorType } from '../api/ErrorInfo' -import { agpsRequestSchema } from './types' +import type { Static } from '@sinclair/typebox' +import { ErrorInfo, ErrorType } from '../api/ErrorInfo.js' +import type { agpsRequestSchema } from './types.js' export type AGPSDataCache = Static & { source: string @@ -14,7 +13,7 @@ export type AGPSDataCache = Static & { export const getCache = ({ dynamodb, TableName }: { dynamodb: DynamoDBClient; TableName: string }) => - async (cacheKey: string): Promise> => { + async (cacheKey: string): Promise<{ error: ErrorInfo } | AGPSDataCache> => { try { const { Item } = await dynamodb.send( new GetItemCommand({ @@ -30,7 +29,7 @@ export const getCache = if (Item === undefined) throw new Error('NOT_FOUND') const entry = unmarshall(Item) - const i = { + return { ...entry, updatedAt: new Date(entry.updatedAt as string), types: [...(entry.types as Set)], @@ -39,17 +38,17 @@ export const getCache = ? [...(entry.dataHex as Set)] : undefined, } as AGPSDataCache - - return right(i) } catch (err) { if ( (err as Error).message === 'NOT_FOUND' || (err as Error).name === 'ResourceNotFoundException' ) - return left({ - type: ErrorType.EntityNotFound, - message: `Report ${cacheKey} not found!`, - }) + return { + error: { + type: ErrorType.EntityNotFound, + message: `Report ${cacheKey} not found!`, + }, + } console.error( JSON.stringify({ getCache: { @@ -60,9 +59,11 @@ export const getCache = }, }), ) - return left({ - type: ErrorType.InternalError, - message: (err as Error).message, - }) + return { + error: { + type: ErrorType.InternalError, + message: (err as Error).message, + }, + } } } diff --git a/agps/types.ts b/agps/types.ts index 9bf855052..ba3c52042 100644 --- a/agps/types.ts +++ b/agps/types.ts @@ -13,6 +13,9 @@ export enum AGPSType { const PositiveInteger = Type.Integer({ minimum: 1, title: 'positive integer' }) +/** + * @see https://api.nrfcloud.com/v1#tag/Assisted-GPS/operation/GetAssistanceData + */ export const agpsRequestSchema = Type.Object({ mcc: Type.Integer({ minimum: 100, maximum: 999 }), mnc: Type.Integer({ minimum: 0, maximum: 999 }), diff --git a/api/res.ts b/api/res.ts index a2962c6c7..f19e39151 100644 --- a/api/res.ts +++ b/api/res.ts @@ -1,4 +1,4 @@ -import { APIGatewayProxyResultV2 } from 'aws-lambda' +import type { APIGatewayProxyResultV2 } from 'aws-lambda' export const res = (statusCode: number, options?: { expires: number }) => diff --git a/api/resFP.ts b/api/resFP.ts deleted file mode 100644 index a66e3171d..000000000 --- a/api/resFP.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { APIGatewayProxyResult } from 'aws-lambda' -import * as T from 'fp-ts/lib/Task' - -/** - * @deprecated use res() because fp-ts is getting gradually phased out from this code-base - */ -export const resFP = - (statusCode: number, options?: { expires: number }) => - (body: unknown): T.Task => - T.of({ - statusCode, - headers: { - 'Access-Control-Allow-Origin': '*', - 'Content-Type': 'application/json', - ...(options?.expires !== undefined && { - 'Cache-Control': `public, max-age=${options.expires}`, - Expires: new Date( - new Date().getTime() + options.expires * 1000, - ).toUTCString(), - }), - 'X-asset-tracker-Version': process.env.VERSION ?? 'unknown', - }, - body: JSON.stringify(body), - }) diff --git a/api/validateWithJSONSchema.spec.ts b/api/validateWithJSONSchema.spec.ts deleted file mode 100644 index 5027812ac..000000000 --- a/api/validateWithJSONSchema.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Static, Type } from '@sinclair/typebox' -import { validateWithJSONSchema } from './validateWithJSONSchema' - -const typedInputSchema = Type.Object( - { - cell: Type.Number({ - minimum: 1, - }), - }, - { additionalProperties: false }, -) - -describe('validateWithJSONSchema', () => { - describe('it should validate', () => { - const v = validateWithJSONSchema(typedInputSchema) - it('valid input', () => { - const isValid = v({ cell: 42 }) - expect('error' in isValid).toEqual(false) - expect((isValid as Static).cell).toEqual(42) - }) - it('invalid input', () => { - const isInvalid = v({ cell: -42 }) - expect('error' in isInvalid).toEqual(true) - }) - }) -}) diff --git a/api/validateWithJSONSchema.ts b/api/validateWithJSONSchema.ts deleted file mode 100644 index 46715218b..000000000 --- a/api/validateWithJSONSchema.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Static, TSchema } from '@sinclair/typebox' -import Ajv from 'ajv' -import { ErrorInfo, ErrorType } from './ErrorInfo' - -export const validateWithJSONSchema = ( - schema: T, -): ((value: unknown) => { error: ErrorInfo } | Static) => { - const ajv = new Ajv() - // see @https://github.com/sinclairzx81/typebox/issues/51 - ajv.addKeyword('kind') - ajv.addKeyword('modifier') - const v = ajv.compile(schema) - return (value: unknown) => { - const valid = v(value) - if (valid !== true) { - return { - error: { - type: ErrorType.BadRequest, - message: 'Validation failed!', - detail: { - errors: v.errors, - input: value, - }, - }, - } - } - return value as Static - } -} diff --git a/api/validateWithJSONSchemaFP.spec.ts b/api/validateWithJSONSchemaFP.spec.ts deleted file mode 100644 index 4b437af2c..000000000 --- a/api/validateWithJSONSchemaFP.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Static, Type } from '@sinclair/typebox' -import { isRight, Right } from 'fp-ts/lib/Either' -import { isLeft } from 'fp-ts/lib/These' -import { validateWithJSONSchemaFP } from './validateWithJSONSchemaFP' - -const typedInputSchema = Type.Object( - { - cell: Type.Number({ - minimum: 1, - }), - }, - { additionalProperties: false }, -) - -describe('validateWithJSONSchemaFP', () => { - describe('it should validate', () => { - const v = validateWithJSONSchemaFP(typedInputSchema) - it('valid input', () => { - const isValid = v({ cell: 42 }) - expect(isRight(isValid)).toEqual(true) - expect( - (isValid as Right>).right.cell, - ).toEqual(42) - }) - it('invalid input', () => { - const isInvalid = v({ cell: -42 }) - expect(isLeft(isInvalid)).toEqual(true) - }) - }) -}) diff --git a/api/validateWithJSONSchemaFP.ts b/api/validateWithJSONSchemaFP.ts deleted file mode 100644 index 9b51e28e9..000000000 --- a/api/validateWithJSONSchemaFP.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Static, TSchema } from '@sinclair/typebox' -import Ajv from 'ajv' -import * as E from 'fp-ts/lib/Either' -import { ErrorInfo, ErrorType } from './ErrorInfo' - -/** - * @deprecated use validateWithJSONSchema() because fp-ts is getting gradually phased out from this code-base - */ -export const validateWithJSONSchemaFP = ( - schema: T, -): ((value: unknown) => E.Either>) => { - const ajv = new Ajv() - // see @https://github.com/sinclairzx81/typebox/issues/51 - ajv.addKeyword('kind') - ajv.addKeyword('modifier') - const v = ajv.compile(schema) - return (value: unknown) => { - const valid = v(value) - if (valid !== true) { - return E.left({ - type: ErrorType.BadRequest, - message: 'Validation failed!', - detail: { - errors: v.errors, - input: value, - }, - }) - } - return E.right(value as Static) - } -} diff --git a/cdk/apps/AssetTracker.ts b/cdk/apps/AssetTracker.ts index f527f9c34..186bc6f5c 100644 --- a/cdk/apps/AssetTracker.ts +++ b/cdk/apps/AssetTracker.ts @@ -1,21 +1,22 @@ import { App } from 'aws-cdk-lib' import { readFileSync } from 'fs' -import * as path from 'path' -import { enabledInContext } from '../helper/enabledInContext' -import { extractRepoAndOwner } from '../helper/extract-repo-and-owner' -import { PackedLambdas } from '../helper/lambdas/PackedLambdas' -import { AssetTrackerLambdas, CDKLambdas } from '../stacks/AssetTracker/lambdas' -import { AssetTrackerStack } from '../stacks/AssetTracker/stack' -import { ContinuousDeploymentStack } from '../stacks/ContinuousDeployment' -import { FirmwareCIStack } from '../stacks/FirmwareCI' -import { WebAppStack } from '../stacks/WebApp' -import { WebAppCIStack } from '../stacks/WebAppCI' +import path from 'path' +import { enabledInContext } from '../helper/enabledInContext.js' +import { extractRepoAndOwner } from '../helper/extract-repo-and-owner.js' +import type { + AssetTrackerLambdas, + CDKLambdas, +} from '../stacks/AssetTracker/lambdas.js' +import { AssetTrackerStack } from '../stacks/AssetTracker/stack.js' +import { ContinuousDeploymentStack } from '../stacks/ContinuousDeployment.js' +import { FirmwareCIStack } from '../stacks/FirmwareCI.js' +import { WebAppStack } from '../stacks/WebApp.js' +import { WebAppCIStack } from '../stacks/WebAppCI.js' export class AssetTrackerApp extends App { public constructor(args: { - sourceCodeBucketName: string - packedLambdas: PackedLambdas - packedCDKLambdas: PackedLambdas + packedLambdas: AssetTrackerLambdas + packedCDKLambdas: CDKLambdas context?: Record }) { super({ context: args.context }) diff --git a/cdk/apps/HTTPAPIMock.ts b/cdk/apps/HTTPAPIMock.ts index 8d996ef3f..843a3d889 100644 --- a/cdk/apps/HTTPAPIMock.ts +++ b/cdk/apps/HTTPAPIMock.ts @@ -1,7 +1,6 @@ import { App } from 'aws-cdk-lib' -import { PackedLambdas } from '../helper/lambdas/PackedLambdas' -import { HttpApiMockStack } from '../test-resources/HttpApiMockStack' -import { HTTPAPIMockLambdas } from '../test-resources/prepare-test-resources' +import { HttpApiMockStack } from '../test-resources/HttpApiMockStack.js' +import type { HTTPAPIMockLambdas } from '../test-resources/prepare-test-resources.js' /** * This sets up the parts of the app needed for the end-to-end tests @@ -9,10 +8,8 @@ import { HTTPAPIMockLambdas } from '../test-resources/prepare-test-resources' export class HTTPAPIMockApp extends App { public constructor({ packedHTTPAPIMockLambdas, - sourceCodeBucketName, }: { - sourceCodeBucketName: string - packedHTTPAPIMockLambdas: PackedLambdas + packedHTTPAPIMockLambdas: HTTPAPIMockLambdas }) { super({ context: { @@ -21,7 +18,6 @@ export class HTTPAPIMockApp extends App { }) new HttpApiMockStack(this, { packedHTTPAPIMockLambdas, - sourceCodeBucketName, }) } } diff --git a/cdk/apps/LambdaSourceCodeStorage.ts b/cdk/apps/LambdaSourceCodeStorage.ts deleted file mode 100644 index 5702354c3..000000000 --- a/cdk/apps/LambdaSourceCodeStorage.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { App } from 'aws-cdk-lib' -import { LambdaSourceCodeStorageStack } from '../stacks/LambdaSourceCodeStorage' - -/** - * In order to deploy lambda functions written in TypeScript we need to publish - * the compiled source code to an S3 bucket. - * This app provides the bucket and run before the main app. - */ -export class LambdaSourceCodeStorageApp extends App { - public constructor() { - super() - - new LambdaSourceCodeStorageStack(this) - } -} diff --git a/cdk/apps/Test.ts b/cdk/apps/Test.ts index 93dc4f30f..62e516d76 100644 --- a/cdk/apps/Test.ts +++ b/cdk/apps/Test.ts @@ -1,17 +1,18 @@ import { App } from 'aws-cdk-lib' -import { PackedLambdas } from '../helper/lambdas/PackedLambdas' -import { AssetTrackerLambdas, CDKLambdas } from '../stacks/AssetTracker/lambdas' -import { AssetTrackerStack } from '../stacks/AssetTracker/stack' -import { FirmwareCIStack } from '../stacks/FirmwareCI' +import type { + AssetTrackerLambdas, + CDKLambdas, +} from '../stacks/AssetTracker/lambdas.js' +import { AssetTrackerStack } from '../stacks/AssetTracker/stack.js' +import { FirmwareCIStack } from '../stacks/FirmwareCI.js' /** * This sets up the parts of the app needed for the end-to-end tests */ export class TestApp extends App { public constructor(args: { - sourceCodeBucketName: string - packedLambdas: PackedLambdas - packedCDKLambdas: PackedLambdas + packedLambdas: AssetTrackerLambdas + packedCDKLambdas: CDKLambdas context?: Record }) { super({ context: args.context }) diff --git a/cdk/cloudformation-http-api-mock.ts b/cdk/cloudformation-http-api-mock.ts index 8c3eb2793..9447bcff9 100644 --- a/cdk/cloudformation-http-api-mock.ts +++ b/cdk/cloudformation-http-api-mock.ts @@ -1,30 +1,6 @@ -import { HTTPAPIMockApp } from './apps/HTTPAPIMock' -import { getLambdaSourceCodeBucketName } from './helper/getLambdaSourceCodeBucketName' -import { preparePackagedLambdaStorageDir } from './helper/lambdas/outDir' -import { prepareHTTPAPIMockLambdas } from './test-resources/prepare-test-resources' +import { HTTPAPIMockApp } from './apps/HTTPAPIMock.js' +import { prepareHTTPAPIMockLambdas } from './test-resources/prepare-test-resources.js' -const rootDir = process.cwd() - -Promise.all([ - preparePackagedLambdaStorageDir({ - rootDir, - }), - getLambdaSourceCodeBucketName(), -]) - .then(async ([outDir, sourceCodeBucketName]) => ({ - sourceCodeBucketName, - packedHTTPAPIMockLambdas: await prepareHTTPAPIMockLambdas({ - outDir, - rootDir, - sourceCodeBucketName, - }), - })) - .then((args) => - new HTTPAPIMockApp({ - ...args, - }).synth(), - ) - .catch((err) => { - console.error(err) - process.exit(1) - }) +new HTTPAPIMockApp({ + packedHTTPAPIMockLambdas: await prepareHTTPAPIMockLambdas(), +}).synth() diff --git a/cdk/cloudformation-sourcecode.ts b/cdk/cloudformation-sourcecode.ts deleted file mode 100644 index 0712bee0b..000000000 --- a/cdk/cloudformation-sourcecode.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { LambdaSourceCodeStorageApp } from './apps/LambdaSourceCodeStorage' - -new LambdaSourceCodeStorageApp().synth() diff --git a/cdk/cloudformation-test.ts b/cdk/cloudformation-test.ts index d49b85a7f..842c57d95 100644 --- a/cdk/cloudformation-test.ts +++ b/cdk/cloudformation-test.ts @@ -1,45 +1,17 @@ -import { TestApp } from './apps/Test' -import { getLambdaSourceCodeBucketName } from './helper/getLambdaSourceCodeBucketName' -import { preparePackagedLambdaStorageDir } from './helper/lambdas/outDir' +import { TestApp } from './apps/Test.js' import { prepareAssetTrackerLambdas, prepareCDKLambdas, -} from './stacks/AssetTracker/lambdas' +} from './stacks/AssetTracker/lambdas.js' -const rootDir = process.cwd() - -Promise.all([ - preparePackagedLambdaStorageDir({ - rootDir, - }), - getLambdaSourceCodeBucketName(), -]) - .then(async ([outDir, sourceCodeBucketName]) => ({ - sourceCodeBucketName, - packedLambdas: await prepareAssetTrackerLambdas({ - sourceCodeBucketName, - rootDir, - outDir, - }), - packedCDKLambdas: await prepareCDKLambdas({ - sourceCodeBucketName, - rootDir, - outDir, - }), - })) - .then((lambdaResources) => - new TestApp({ - ...lambdaResources, - context: { - version: process.env.VERSION ?? '0.0.0-development', - isTest: true, - nrfcloudAGPS: '1', - nrfcloudPGPS: '1', - nrfcloudGroundFix: '1', - }, - }).synth(), - ) - .catch((err) => { - console.error(err) - process.exit(1) - }) +new TestApp({ + packedLambdas: await prepareAssetTrackerLambdas(), + packedCDKLambdas: await prepareCDKLambdas(), + context: { + version: process.env.VERSION ?? '0.0.0-development', + isTest: true, + nrfcloudAGPS: '1', + nrfcloudPGPS: '1', + nrfcloudGroundFix: '1', + }, +}).synth() diff --git a/cdk/cloudformation.ts b/cdk/cloudformation.ts index ba66ed869..023a7910d 100644 --- a/cdk/cloudformation.ts +++ b/cdk/cloudformation.ts @@ -5,18 +5,16 @@ import { getGroundFixApiSettings, getPGPSLocationApiSettings, serviceKeyProperty, -} from '../third-party/nrfcloud.com/settings' -import { getSettings } from '../util/settings' -import { AssetTrackerApp } from './apps/AssetTracker' -import { getLambdaSourceCodeBucketName } from './helper/getLambdaSourceCodeBucketName' -import { getStackContexts } from './helper/getStackContexts' -import { preparePackagedLambdaStorageDir } from './helper/lambdas/outDir' -import { warn } from './helper/note' +} from '../third-party/nrfcloud.com/settings.js' +import { getSettings } from '../util/settings.js' +import { AssetTrackerApp } from './apps/AssetTracker.js' +import { getStackContexts } from './helper/getStackContexts.js' +import { warn } from './helper/note.js' import { prepareAssetTrackerLambdas, prepareCDKLambdas, -} from './stacks/AssetTracker/lambdas' -import { CORE_STACK_NAME } from './stacks/stackName' +} from './stacks/AssetTracker/lambdas.js' +import { CORE_STACK_NAME } from './stacks/stackName.js' const ssm = new SSMClient({}) const fetchNrfCloudAGPSLocationApiSettings = getAGPSLocationApiSettings({ @@ -36,27 +34,13 @@ const fetchStackContexts = getStackContexts({ stackName: CORE_STACK_NAME, }) -const rootDir = process.cwd() - -Promise.all([ - Promise.all([ - preparePackagedLambdaStorageDir({ - rootDir, - }), - getLambdaSourceCodeBucketName(), - ]).then(async ([outDir, sourceCodeBucketName]) => ({ - sourceCodeBucketName, - packedLambdas: await prepareAssetTrackerLambdas({ - rootDir, - outDir, - sourceCodeBucketName, - }), - packedCDKLambdas: await prepareCDKLambdas({ - rootDir, - outDir, - sourceCodeBucketName, - }), - })), +const [ + nrfCloudAGPSLocationApiSettings, + nrfCloudPGPSLocationApiSettings, + nrfCloudGroundFixApiSettings, + codebuildSettings, + context, +] = await Promise.all([ fetchNrfCloudAGPSLocationApiSettings().catch(() => ({})), fetchNrfCloudPGPSLocationApiSettings().catch(() => ({})), fetchNrfCloudGroundFixApiSettings().catch(() => ({})), @@ -68,77 +52,64 @@ Promise.all([ })().catch(() => ({})), fetchStackContexts(), ]) - .then( - ([ - lambdaResources, - nrfCloudAGPSLocationApiSettings, - nrfCloudPGPSLocationApiSettings, - nrfCloudGroundFixApiSettings, - codebuildSettings, - context, - ]) => { - const ctx = { - version: process.env.VERSION ?? '0.0.0-development', - ...context, - } as Record - for (const { name, context, configProperty, settings } of [ - { - name: 'Assisted GPS', - context: 'nrfcloudAGPS', - configProperty: serviceKeyProperty('agpsLocation'), - settings: nrfCloudAGPSLocationApiSettings, - }, - { - name: 'Predicted GPS', - context: 'nrfcloudPGPS', - configProperty: serviceKeyProperty('pgpsLocation'), - settings: nrfCloudPGPSLocationApiSettings, - }, - { - name: 'Ground Fix', - context: 'nrfcloudGroundFix', - configProperty: serviceKeyProperty('groundFix'), - settings: nrfCloudGroundFixApiSettings, - }, - ]) { - if (!('serviceKey' in settings)) { - warn( - 'Location Services', - `No nRF Cloud ${name} Location Service service key configured. Feature will be disabled.`, - ) - warn( - 'Location Services', - `Use ${chalk.greenBright( - `./cli.sh configure thirdParty nrfcloud ${configProperty} `, - )} to set the service key`, - ) - ctx[context] = '0' - } - } +const ctx = { + version: process.env.VERSION ?? '0.0.0-development', + ...context, +} as Record - const enableCD = 'token' in codebuildSettings - if (!enableCD) { - warn( - 'Continuous Deployment', - 'No GitHub API key configured. Continuous deployment will be disabled.', - ) - warn( - 'Continuous Deployment', - `Use ${chalk.greenBright( - `./cli.sh configure codebuild github token `, - )} to set the token`, - ) - ctx.cd = '0' - } +for (const { name, context, configProperty, settings } of [ + { + name: 'Assisted GPS', + context: 'nrfcloudAGPS', + configProperty: serviceKeyProperty('agpsLocation'), + settings: nrfCloudAGPSLocationApiSettings, + }, + { + name: 'Predicted GPS', + context: 'nrfcloudPGPS', + configProperty: serviceKeyProperty('pgpsLocation'), + settings: nrfCloudPGPSLocationApiSettings, + }, + { + name: 'Ground Fix', + context: 'nrfcloudGroundFix', + configProperty: serviceKeyProperty('groundFix'), + settings: nrfCloudGroundFixApiSettings, + }, +]) { + if (!('serviceKey' in settings)) { + warn( + 'Location Services', + `No nRF Cloud ${name} Location Service service key configured. Feature will be disabled.`, + ) + warn( + 'Location Services', + `Use ${chalk.greenBright( + `./cli.sh configure thirdParty nrfcloud ${configProperty} `, + )} to set the service key`, + ) + ctx[context] = '0' + } +} - return new AssetTrackerApp({ - ...lambdaResources, - context: ctx, - }).synth() - }, +const enableCD = 'token' in codebuildSettings +if (!enableCD) { + warn( + 'Continuous Deployment', + 'No GitHub API key configured. Continuous deployment will be disabled.', + ) + warn( + 'Continuous Deployment', + `Use ${chalk.greenBright( + `./cli.sh configure codebuild github token `, + )} to set the token`, ) - .catch((err) => { - console.error(err) - process.exit(1) - }) + ctx.cd = '0' +} + +new AssetTrackerApp({ + packedLambdas: await prepareAssetTrackerLambdas(), + packedCDKLambdas: await prepareCDKLambdas(), + context: ctx, +}).synth() diff --git a/cdk/createThingGroup.ts b/cdk/createThingGroup.ts index f3dd85c43..19c850858 100644 --- a/cdk/createThingGroup.ts +++ b/cdk/createThingGroup.ts @@ -15,8 +15,8 @@ import { cfnResponse, ResponseStatus, } from '@nordicsemiconductor/cloudformation-helpers' -import { CloudFormationCustomResourceEvent } from 'aws-lambda' -import { paginate } from '../util/paginate' +import type { CloudFormationCustomResourceEvent } from 'aws-lambda' +import { paginate } from '../util/paginate.js' const iot = new IoTClient({}) diff --git a/cdk/helper/checkRegion.ts b/cdk/helper/checkRegion.ts index d17ff84b7..68a992835 100644 --- a/cdk/helper/checkRegion.ts +++ b/cdk/helper/checkRegion.ts @@ -1,5 +1,5 @@ import chalk from 'chalk' -import { supportedRegions } from '../regions' +import { supportedRegions } from '../regions.js' export const checkRegion = (): void => { if (!supportedRegions.includes(process.env.AWS_REGION ?? 'us-east-1')) { diff --git a/cdk/helper/enabledInContext.ts b/cdk/helper/enabledInContext.ts index 0cbd8d20f..b08d784e4 100644 --- a/cdk/helper/enabledInContext.ts +++ b/cdk/helper/enabledInContext.ts @@ -1,5 +1,5 @@ import chalk from 'chalk' -import { Node } from 'constructs' +import type { Node } from 'constructs' const ENABLED = 'enabled' const DISABLED = 'disabled' diff --git a/cdk/helper/extract-repo-and-owner.spec.ts b/cdk/helper/extract-repo-and-owner.spec.ts index 9344ff741..c54f4e27c 100644 --- a/cdk/helper/extract-repo-and-owner.spec.ts +++ b/cdk/helper/extract-repo-and-owner.spec.ts @@ -1,4 +1,4 @@ -import { extractRepoAndOwner } from './extract-repo-and-owner' +import { extractRepoAndOwner } from './extract-repo-and-owner.js' describe('extractRepoAndOwner()', () => { it('should parse a git repo', () => { diff --git a/cdk/helper/extract-repo-and-owner.ts b/cdk/helper/extract-repo-and-owner.ts index af59e6b41..111bd7b9e 100644 --- a/cdk/helper/extract-repo-and-owner.ts +++ b/cdk/helper/extract-repo-and-owner.ts @@ -5,7 +5,7 @@ export const extractRepoAndOwner = ( ): { repo: string; owner: string } => { const repoUrl = new URL(repositoryUrl) const owner = repoUrl?.pathname?.split('/')[1] - const repo = repoUrl?.pathname?.split('/')[2].replace(/\..+$/, '') + const repo = repoUrl?.pathname?.split('/')[2]?.replace(/\..+$/, '') if (owner === undefined || repo === undefined) { throw new Error(`Could not determine owner and repo from repository.url!`) } diff --git a/cdk/helper/getLambdaSourceCodeBucketName.ts b/cdk/helper/getLambdaSourceCodeBucketName.ts deleted file mode 100644 index 936977dd9..000000000 --- a/cdk/helper/getLambdaSourceCodeBucketName.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { - CloudFormationClient, - DescribeStacksCommand, -} from '@aws-sdk/client-cloudformation' -import { SOURCECODE_STACK_NAME } from '../stacks/stackName' - -const cf = new CloudFormationClient({}) - -export const getLambdaSourceCodeBucketName = async (): Promise => { - const StackName = SOURCECODE_STACK_NAME - return cf - .send( - new DescribeStacksCommand({ - StackName: StackName, - }), - ) - .then(({ Stacks }) => { - if (Stacks === null || Stacks === undefined || !Stacks.length) { - throw new Error(`${StackName} stack is not available.`) - } else { - const stack = Stacks[0] - const BucketOutput = stack.Outputs?.find( - ({ OutputKey }) => OutputKey === 'bucketName', - ) - if (BucketOutput?.OutputValue === undefined) { - throw new Error(`${StackName} bucket not found.`) - } - return BucketOutput.OutputValue - } - }) -} diff --git a/cdk/helper/getStackContexts.ts b/cdk/helper/getStackContexts.ts index 3cf743c8d..f8f22e85b 100644 --- a/cdk/helper/getStackContexts.ts +++ b/cdk/helper/getStackContexts.ts @@ -1,5 +1,5 @@ -import { SSMClient } from '@aws-sdk/client-ssm' -import { getSettings } from '../../util/settings' +import type { SSMClient } from '@aws-sdk/client-ssm' +import { getSettings } from '../../util/settings.js' type StackContexts = { nrfcloudAGPS: '0' | '1' diff --git a/cdk/helper/iotRuleSqlCheckIfDefinedAndNotZero.spec.ts b/cdk/helper/iotRuleSqlCheckIfDefinedAndNotZero.spec.ts index 1c5cad2af..fc0d40493 100644 --- a/cdk/helper/iotRuleSqlCheckIfDefinedAndNotZero.spec.ts +++ b/cdk/helper/iotRuleSqlCheckIfDefinedAndNotZero.spec.ts @@ -1,4 +1,4 @@ -import { iotRuleSqlCheckIfDefinedAndNotZero } from './iotRuleSqlCheckIfDefinedAndNotZero' +import { iotRuleSqlCheckIfDefinedAndNotZero } from './iotRuleSqlCheckIfDefinedAndNotZero.js' describe('iotRuleSqlCheckIfDefinedAndNotZero', () => { it('should check for undefined for the given values', () => diff --git a/cdk/helper/iotRuleSqlCheckUndefined.spec.ts b/cdk/helper/iotRuleSqlCheckUndefined.spec.ts index 6d9c93ac8..3f726c532 100644 --- a/cdk/helper/iotRuleSqlCheckUndefined.spec.ts +++ b/cdk/helper/iotRuleSqlCheckUndefined.spec.ts @@ -1,4 +1,4 @@ -import { iotRuleSqlCheckUndefined } from './iotRuleSqlCheckUndefined' +import { iotRuleSqlCheckUndefined } from './iotRuleSqlCheckUndefined.js' describe('iotRuleSqlCheckUndefined', () => { it('should check for undefined for the given values', () => diff --git a/cdk/helper/lambdas/PackedLambdas.ts b/cdk/helper/lambdas/PackedLambdas.ts deleted file mode 100644 index 1e373d941..000000000 --- a/cdk/helper/lambdas/PackedLambdas.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { LayeredLambdas } from '@nordicsemiconductor/package-layered-lambdas' - -export type PackedLambdas< - A extends { - [key: string]: string - }, -> = { - lambdas: LayeredLambdas - layerZipFileName: string -} diff --git a/cdk/helper/lambdas/commonParent.spec.ts b/cdk/helper/lambdas/commonParent.spec.ts new file mode 100644 index 000000000..722c1cb92 --- /dev/null +++ b/cdk/helper/lambdas/commonParent.spec.ts @@ -0,0 +1,24 @@ +import { commonParent } from './commonParent' + +describe('commonParent()', () => { + it('should return the common parent directory', () => + expect( + commonParent([ + '/some/dir/lambda/onMessage.ts', + '/some/dir/lambda/notifyClients.ts', + '/some/dir/lambda/wirepasPublish.ts', + '/some/dir/wirepas-5g-mesh-gateway/protobuf/ts/data_message.ts', + ]), + ).toEqual('/some/dir/')) + it('should return the entire parent tree for a single file', () => + expect(commonParent(['/some/dir/lambda/onMessage.ts'])).toEqual( + '/some/dir/lambda/', + )) + it('should return "/" if files have no common directory', () => + expect( + commonParent([ + '/some/dir/lambda/onMessage.ts', + '/other/dir/lambda/onMessage.ts', + ]), + ).toEqual('/')) +}) diff --git a/cdk/helper/lambdas/commonParent.ts b/cdk/helper/lambdas/commonParent.ts new file mode 100644 index 000000000..ff62c0a69 --- /dev/null +++ b/cdk/helper/lambdas/commonParent.ts @@ -0,0 +1,16 @@ +import { parse, sep } from 'node:path' + +/** + * Returns the common ancestor directory from a list of files + */ +export const commonParent = (files: string[]): string => { + if (files.length === 1) return parse(files[0] ?? '').dir + sep + let index = 0 + let prefix = '/' + + while (files.filter((f) => f.startsWith(prefix)).length === files.length) { + prefix = files[0]?.slice(0, ++index) ?? '' + } + + return prefix.slice(0, prefix.length - 1) +} diff --git a/cdk/helper/lambdas/findDependencies.ts b/cdk/helper/lambdas/findDependencies.ts new file mode 100644 index 000000000..9137a2e48 --- /dev/null +++ b/cdk/helper/lambdas/findDependencies.ts @@ -0,0 +1,53 @@ +import { readFileSync, statSync } from 'node:fs' +import path from 'node:path' +import ts, { ImportDeclaration, StringLiteral } from 'typescript' + +/** + * Resolve project-level dependencies for the given file using TypeScript compiler API + */ +export const findDependencies = ( + sourceFile: string, + imports: string[] = [], + visited: string[] = [], +): string[] => { + if (visited.includes(sourceFile)) return imports + + const fileNode = ts.createSourceFile( + sourceFile, + readFileSync(sourceFile, 'utf-8').toString(), + ts.ScriptTarget.ES2022, + /*setParentNodes */ true, + ) + + const parseChild = (node: ts.Node) => { + if (node.kind !== ts.SyntaxKind.ImportDeclaration) return + const moduleSpecifier = ( + (node as ImportDeclaration).moduleSpecifier as StringLiteral + ).text + const file = moduleSpecifier.startsWith('.') + ? path + .resolve(path.parse(sourceFile).dir, moduleSpecifier) + // In ECMA Script modules, all imports from local files must have an extension. + // See https://nodejs.org/api/esm.html#mandatory-file-extensions + // So we need to replace the `.js` in the import specification to find the TypeScript source for the file. + // Example: import { Network, notifyClients } from './notifyClients.js' + // The source file for that is actually in './notifyClients.ts' + .replace(/\.js$/, '.ts') + : moduleSpecifier + try { + const s = statSync(file) + if (!s.isDirectory()) imports.push(file) + } catch { + // Module or file not found + visited.push(file) + } + } + ts.forEachChild(fileNode, parseChild) + visited.push(sourceFile) + + for (const file of imports) { + findDependencies(file, imports, visited) + } + + return imports +} diff --git a/cdk/helper/lambdas/outDir.ts b/cdk/helper/lambdas/outDir.ts deleted file mode 100644 index a57c84c32..000000000 --- a/cdk/helper/lambdas/outDir.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { promises as fs } from 'fs' -import * as path from 'path' - -// Prepares the storage director for packed lambdas -export const preparePackagedLambdaStorageDir = async ({ - rootDir, -}: { - rootDir: string -}): Promise => { - const outDir = path.resolve(rootDir, 'dist', 'lambdas') - try { - await fs.stat(outDir) - } catch (_) { - await fs.mkdir(outDir, { recursive: true }) - } - return outDir -} diff --git a/cdk/helper/lambdas/packLambda.ts b/cdk/helper/lambdas/packLambda.ts new file mode 100644 index 000000000..ef67a08d1 --- /dev/null +++ b/cdk/helper/lambdas/packLambda.ts @@ -0,0 +1,80 @@ +import swc from '@swc/core' +import { createWriteStream } from 'node:fs' +import { parse } from 'path' +import yazl from 'yazl' +import { commonParent } from './commonParent' +import { findDependencies } from './findDependencies' + +export type PackedLambda = { zipFile: string; handler: string } + +const removeCommonAncestor = + (parentDir: string) => + (file: string): string => { + const p = parse(file) + const jsFileName = [ + p.dir.replace(parentDir.slice(0, parentDir.length - 1), ''), + `${p.name}.js`, + ] + .join('/') + // Replace leading slash + .replace(/^\//, '') + + return jsFileName + } + +/** + * In the bundle we only include code that's not in the layer. + */ +export const packLambda = async ({ + sourceFile, + zipFile, + debug, + progress, +}: { + sourceFile: string + zipFile: string + debug?: (label: string, info: string) => void + progress?: (label: string, info: string) => void +}): Promise<{ handler: string }> => { + const lambdaFiles = [sourceFile, ...findDependencies(sourceFile)] + + const zipfile = new yazl.ZipFile() + + const stripCommon = removeCommonAncestor(commonParent(lambdaFiles)) + + for (const file of lambdaFiles) { + const compiled = ( + await swc.transformFile(file, { + jsc: { + target: 'es2022', + }, + }) + ).code + debug?.(`compiled`, compiled) + const jsFileName = stripCommon(file) + zipfile.addBuffer(Buffer.from(compiled, 'utf-8'), jsFileName) + progress?.(`added`, jsFileName) + } + + // Mark it as ES module + zipfile.addBuffer( + Buffer.from( + JSON.stringify({ + type: 'module', + }), + 'utf-8', + ), + 'package.json', + ) + progress?.(`added`, 'package.json') + + await new Promise((resolve) => { + zipfile.outputStream.pipe(createWriteStream(zipFile)).on('close', () => { + resolve() + }) + zipfile.end() + }) + progress?.(`written`, zipFile) + + return { handler: stripCommon(sourceFile) } +} diff --git a/cdk/helper/lambdas/packLambdaFromPath.ts b/cdk/helper/lambdas/packLambdaFromPath.ts new file mode 100644 index 000000000..b10b54273 --- /dev/null +++ b/cdk/helper/lambdas/packLambdaFromPath.ts @@ -0,0 +1,28 @@ +import { mkdir } from 'node:fs/promises' +import path from 'node:path' +import { packLambda } from './packLambda.js' +export type PackedLambda = { zipFile: string; handler: string } + +export const packLambdaFromPath = async ( + id: string, + sourceFile: string, + handlerFunction = 'handler', + baseDir = process.cwd(), +): Promise => { + try { + await mkdir(path.join(process.cwd(), 'dist', 'lambdas'), { + recursive: true, + }) + } catch { + // Directory exists + } + const zipFile = path.join(process.cwd(), 'dist', 'lambdas', `${id}.zip`) + const { handler } = await packLambda({ + sourceFile: path.join(baseDir, sourceFile), + zipFile, + }) + return { + zipFile: zipFile, + handler: handler.replace('.js', `.${handlerFunction}`), + } +} diff --git a/cdk/helper/lambdas/packLayer.ts b/cdk/helper/lambdas/packLayer.ts new file mode 100644 index 000000000..a82d9f448 --- /dev/null +++ b/cdk/helper/lambdas/packLayer.ts @@ -0,0 +1,99 @@ +import { spawn } from 'child_process' +import { createWriteStream } from 'fs' +import { copyFile, mkdir, readFile, rm, writeFile } from 'fs/promises' +import glob from 'glob' +import path from 'path' +import { ZipFile } from 'yazl' + +export type PackedLayer = { layerZipFile: string } + +export const packLayer = async ({ + id, + dependencies, +}: { + id: string + dependencies: string[] +}): Promise => { + const packageJsonFile = path.join(process.cwd(), 'package.json') + const packageLockJsonFile = path.join(process.cwd(), 'package-lock.json') + const { dependencies: deps, devDependencies: devDeps } = JSON.parse( + await readFile(packageJsonFile, 'utf-8'), + ) + + const layerDir = path.join(process.cwd(), 'dist', 'layers', id) + const nodejsDir = path.join(layerDir, 'nodejs', 'node18') + + try { + await rm(layerDir, { recursive: true }) + } catch { + // Folder does not exist. + } + + await mkdir(nodejsDir, { recursive: true }) + + const depsToBeInstalled = dependencies.reduce((resolved, dep) => { + const resolvedDependency = deps[dep] ?? devDeps[dep] + if (resolvedDependency === undefined) + throw new Error( + `Could not resolve dependency "${dep}" in ${packageJsonFile}!`, + ) + return { + ...resolved, + [dep]: resolvedDependency, + } + }, {} as Record) + + await writeFile( + path.join(nodejsDir, 'package.json'), + JSON.stringify({ + dependencies: depsToBeInstalled, + }), + 'utf-8', + ) + await copyFile(packageLockJsonFile, path.join(nodejsDir, 'package-lock.json')) + + await new Promise((resolve, reject) => { + const [cmd, ...args] = [ + 'npm', + 'ci', + '--ignore-scripts', + '--only=prod', + '--no-audit', + ] + const p = spawn(cmd, args, { + cwd: nodejsDir, + }) + p.on('close', (code) => { + if (code !== 0) { + const msg = `${cmd} ${args.join( + ' ', + )} in ${nodejsDir} exited with code ${code}.` + return reject(new Error(msg)) + } + return resolve() + }) + }) + + const filesToAdd = await glob(`**`, { + cwd: layerDir, + nodir: true, + }) + const zipfile = new ZipFile() + filesToAdd.forEach((f) => { + zipfile.addFile(path.join(layerDir, f), f) + }) + + const zipFileName = await new Promise((resolve) => { + const zipFileName = path.join(process.cwd(), 'dist', 'layers', `${id}.zip`) + zipfile.outputStream + .pipe(createWriteStream(zipFileName)) + .on('close', () => { + resolve(zipFileName) + }) + zipfile.end() + }) + + return { + layerZipFile: zipFileName, + } +} diff --git a/cdk/resources/AGPSDeviceRequestHandler.ts b/cdk/resources/AGPSDeviceRequestHandler.ts index 57e39720d..e9cf939e2 100644 --- a/cdk/resources/AGPSDeviceRequestHandler.ts +++ b/cdk/resources/AGPSDeviceRequestHandler.ts @@ -1,15 +1,14 @@ -import * as CloudFormation from 'aws-cdk-lib' -import { Duration } from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as IoT from 'aws-cdk-lib/aws-iot' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as SQS from 'aws-cdk-lib/aws-sqs' -import { iotRuleSqlCheckUndefined } from '../helper/iotRuleSqlCheckUndefined' -import { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas' -import { AGPSResolver } from './AGPSResolver' -import { AGPSStorage } from './AGPSStorage' -import { LambdaLogGroup } from './LambdaLogGroup' -import { LambdasWithLayer } from './LambdasWithLayer' +import CloudFormation, { Duration } from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import IoT from 'aws-cdk-lib/aws-iot' +import Lambda from 'aws-cdk-lib/aws-lambda' +import SQS from 'aws-cdk-lib/aws-sqs' +import { iotRuleSqlCheckUndefined } from '../helper/iotRuleSqlCheckUndefined.js' +import type { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas.js' +import type { AGPSResolver } from './AGPSResolver.js' +import type { AGPSStorage } from './AGPSStorage.js' +import { LambdaLogGroup } from './LambdaLogGroup.js' +import type { LambdasWithLayer } from './LambdasWithLayer.js' export const MAX_RESOLUTION_TIME_IN_MINUTES = 10 @@ -39,7 +38,7 @@ export class AGPSDeviceRequestHandler extends CloudFormation.Resource { storage, resolver, }: { - lambdas: LambdasWithLayer + lambdas: LambdasWithLayer storage: AGPSStorage resolver: AGPSResolver }, @@ -104,12 +103,14 @@ export class AGPSDeviceRequestHandler extends CloudFormation.Resource { 'deviceRequestHandler', { layers: lambdas.layers, - handler: 'index.handler', + handler: lambdas.lambdas.agpsDeviceRequestHandler.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.minutes(1), memorySize: 1792, - code: lambdas.lambdas.agpsDeviceRequestHandler, + code: Lambda.Code.fromAsset( + lambdas.lambdas.agpsDeviceRequestHandler.zipFile, + ), description: 'Handles A-GPS requests which have been queued, either by fullfilling them by using the resolved data, or by starting a new resolution', environment: { diff --git a/cdk/resources/AGPSResolver.ts b/cdk/resources/AGPSResolver.ts index e3aa7c6c7..9286b5b1a 100644 --- a/cdk/resources/AGPSResolver.ts +++ b/cdk/resources/AGPSResolver.ts @@ -1,15 +1,15 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as StepFunctions from 'aws-cdk-lib/aws-stepfunctions' -import * as StepFunctionTasks from 'aws-cdk-lib/aws-stepfunctions-tasks' -import { enabledInContext } from '../helper/enabledInContext' -import { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas' -import { CORE_STACK_NAME } from '../stacks/stackName' -import { AGPSStorage } from './AGPSStorage' -import { LambdaLogGroup } from './LambdaLogGroup' -import { LambdasWithLayer } from './LambdasWithLayer' -import { logToCloudWatch } from './logToCloudWatch' +import CloudFormation from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import Lambda from 'aws-cdk-lib/aws-lambda' +import StepFunctions from 'aws-cdk-lib/aws-stepfunctions' +import StepFunctionTasks from 'aws-cdk-lib/aws-stepfunctions-tasks' +import { enabledInContext } from '../helper/enabledInContext.js' +import type { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas.js' +import { CORE_STACK_NAME } from '../stacks/stackName.js' +import type { AGPSStorage } from './AGPSStorage.js' +import { LambdaLogGroup } from './LambdaLogGroup.js' +import type { LambdasWithLayer } from './LambdasWithLayer.js' +import { logToCloudWatch } from './logToCloudWatch.js' /** * Provides a state machine that can resolve A-GPS requests @@ -23,7 +23,7 @@ export class AGPSResolver extends CloudFormation.Resource { lambdas, storage, }: { - lambdas: LambdasWithLayer + lambdas: LambdasWithLayer storage: AGPSStorage }, ) { @@ -40,12 +40,14 @@ export class AGPSResolver extends CloudFormation.Resource { onEnabled: () => { fromNrfCloud = new Lambda.Function(this, 'fromNrfCloud', { layers: lambdas.layers, - handler: 'index.handler', + handler: lambdas.lambdas.agpsNrfCloudStepFunction.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.seconds(10), memorySize: 1792, - code: lambdas.lambdas.agpsNrfCloudStepFunction, + code: Lambda.Code.fromAsset( + lambdas.lambdas.agpsNrfCloudStepFunction.zipFile, + ), description: 'Use the nRF Cloud API to provide A-GPS data for devices', initialPolicy: [ diff --git a/cdk/resources/AGPSStorage.ts b/cdk/resources/AGPSStorage.ts index 7b1e49d68..4b21b66d1 100644 --- a/cdk/resources/AGPSStorage.ts +++ b/cdk/resources/AGPSStorage.ts @@ -1,5 +1,5 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as DynamoDB from 'aws-cdk-lib/aws-dynamodb' +import CloudFormation from 'aws-cdk-lib' +import DynamoDB from 'aws-cdk-lib/aws-dynamodb' /** * Provides storage for A-GPS requests diff --git a/cdk/resources/CellGeolocation.ts b/cdk/resources/CellGeolocation.ts index 4ba99e423..639595483 100644 --- a/cdk/resources/CellGeolocation.ts +++ b/cdk/resources/CellGeolocation.ts @@ -1,16 +1,16 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as DynamoDB from 'aws-cdk-lib/aws-dynamodb' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as StepFunctions from 'aws-cdk-lib/aws-stepfunctions' -import * as StepFunctionTasks from 'aws-cdk-lib/aws-stepfunctions-tasks' -import { enabledInContext } from '../helper/enabledInContext' -import { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas' -import { CORE_STACK_NAME } from '../stacks/stackName' -import { DeviceCellGeolocations } from './DeviceCellGeolocations' -import { LambdaLogGroup } from './LambdaLogGroup' -import { LambdasWithLayer } from './LambdasWithLayer' -import { logToCloudWatch } from './logToCloudWatch' +import CloudFormation from 'aws-cdk-lib' +import DynamoDB from 'aws-cdk-lib/aws-dynamodb' +import IAM from 'aws-cdk-lib/aws-iam' +import Lambda from 'aws-cdk-lib/aws-lambda' +import StepFunctions from 'aws-cdk-lib/aws-stepfunctions' +import StepFunctionTasks from 'aws-cdk-lib/aws-stepfunctions-tasks' +import { enabledInContext } from '../helper/enabledInContext.js' +import type { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas.js' +import { CORE_STACK_NAME } from '../stacks/stackName.js' +import type { DeviceCellGeolocations } from './DeviceCellGeolocations.js' +import { LambdaLogGroup } from './LambdaLogGroup.js' +import type { LambdasWithLayer } from './LambdasWithLayer.js' +import { logToCloudWatch } from './logToCloudWatch.js' /** * Describes the step functions which resolves the geolocation of LTE/NB-IoT network cells using third-party location providers @@ -26,7 +26,7 @@ export class CellGeolocation extends CloudFormation.Resource { lambdas, deviceCellGeo, }: { - lambdas: LambdasWithLayer + lambdas: LambdasWithLayer deviceCellGeo: DeviceCellGeolocations }, ) { @@ -49,12 +49,14 @@ export class CellGeolocation extends CloudFormation.Resource { const fromCache = new Lambda.Function(this, 'fromCache', { layers: lambdas.layers, - handler: 'index.handler', + handler: lambdas.lambdas.geolocateFromCacheStepFunction.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.seconds(10), memorySize: 1792, - code: lambdas.lambdas.geolocateFromCacheStepFunction, + code: Lambda.Code.fromAsset( + lambdas.lambdas.geolocateFromCacheStepFunction.zipFile, + ), description: 'Geolocate cells from cache', initialPolicy: [ logToCloudWatch, @@ -74,12 +76,15 @@ export class CellGeolocation extends CloudFormation.Resource { const fromDevices = new Lambda.Function(this, 'fromDevices', { layers: lambdas.layers, - handler: 'index.handler', + handler: + lambdas.lambdas.geolocateCellFromDeviceLocationsStepFunction.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.seconds(10), memorySize: 1792, - code: lambdas.lambdas.geolocateCellFromDeviceLocationsStepFunction, + code: Lambda.Code.fromAsset( + lambdas.lambdas.geolocateCellFromDeviceLocationsStepFunction.zipFile, + ), description: 'Geolocate cells from device locations', initialPolicy: [ logToCloudWatch, @@ -104,12 +109,14 @@ export class CellGeolocation extends CloudFormation.Resource { const addToCache = new Lambda.Function(this, 'addToCache', { layers: lambdas.layers, - handler: 'index.handler', + handler: lambdas.lambdas.cacheCellGeolocationStepFunction.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.minutes(1), memorySize: 1792, - code: lambdas.lambdas.cacheCellGeolocationStepFunction, + code: Lambda.Code.fromAsset( + lambdas.lambdas.cacheCellGeolocationStepFunction.zipFile, + ), description: 'Caches cell geolocations', initialPolicy: [ logToCloudWatch, @@ -138,12 +145,15 @@ export class CellGeolocation extends CloudFormation.Resource { onEnabled: () => { fromNrfCloud = new Lambda.Function(this, 'fromNrfCloud', { layers: lambdas.layers, - handler: 'index.handler', + handler: + lambdas.lambdas.geolocateCellFromNrfCloudStepFunction.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.seconds(10), memorySize: 1792, - code: lambdas.lambdas.geolocateCellFromNrfCloudStepFunction, + code: Lambda.Code.fromAsset( + lambdas.lambdas.geolocateCellFromNrfCloudStepFunction.zipFile, + ), description: 'Resolve cell geolocation using the nRF Cloud API', initialPolicy: [ logToCloudWatch, diff --git a/cdk/resources/CellGeolocationApi.ts b/cdk/resources/CellGeolocationApi.ts index aaf12f25f..77c72a241 100644 --- a/cdk/resources/CellGeolocationApi.ts +++ b/cdk/resources/CellGeolocationApi.ts @@ -1,14 +1,14 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as HttpApi from 'aws-cdk-lib/aws-apigatewayv2' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as CloudWatchLogs from 'aws-cdk-lib/aws-logs' -import * as SQS from 'aws-cdk-lib/aws-sqs' -import { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas' -import { CellGeolocation } from './CellGeolocation' -import { LambdaLogGroup } from './LambdaLogGroup' -import { LambdasWithLayer } from './LambdasWithLayer' -import { logToCloudWatch } from './logToCloudWatch' +import CloudFormation from 'aws-cdk-lib' +import HttpApi from 'aws-cdk-lib/aws-apigatewayv2' +import IAM from 'aws-cdk-lib/aws-iam' +import Lambda from 'aws-cdk-lib/aws-lambda' +import CloudWatchLogs from 'aws-cdk-lib/aws-logs' +import SQS from 'aws-cdk-lib/aws-sqs' +import type { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas.js' +import type { CellGeolocation } from './CellGeolocation.js' +import { LambdaLogGroup } from './LambdaLogGroup.js' +import type { LambdasWithLayer } from './LambdasWithLayer.js' +import { logToCloudWatch } from './logToCloudWatch.js' /** * Allows to resolve cell geolocations using a HTTP API @@ -28,7 +28,7 @@ export class CellGeolocationApi extends CloudFormation.Resource { lambdas, }: { cellgeo: CellGeolocation - lambdas: LambdasWithLayer + lambdas: LambdasWithLayer }, ) { super(parent, id) @@ -39,12 +39,14 @@ export class CellGeolocationApi extends CloudFormation.Resource { }) const fromSQS = new Lambda.Function(this, 'fromSQS', { - handler: 'index.handler', + handler: lambdas.lambdas.invokeStepFunctionFromSQS.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.seconds(10), memorySize: 1792, - code: lambdas.lambdas.invokeStepFunctionFromSQS, + code: Lambda.Code.fromAsset( + lambdas.lambdas.invokeStepFunctionFromSQS.zipFile, + ), layers: lambdas.layers, description: 'Invoke the cell geolocation resolution step function for SQS messages', @@ -75,12 +77,12 @@ export class CellGeolocationApi extends CloudFormation.Resource { const getCell = new Lambda.Function(this, 'getCell', { layers: lambdas.layers, - handler: 'index.handler', + handler: lambdas.lambdas.geolocateCellHttpApi.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.seconds(10), memorySize: 1792, - code: lambdas.lambdas.geolocateCellHttpApi, + code: Lambda.Code.fromAsset(lambdas.lambdas.geolocateCellHttpApi.zipFile), description: 'Geolocate cells', initialPolicy: [ logToCloudWatch, diff --git a/cdk/resources/DeviceCellGeolocations.ts b/cdk/resources/DeviceCellGeolocations.ts index 4e5b7e6a6..e4f07b96a 100644 --- a/cdk/resources/DeviceCellGeolocations.ts +++ b/cdk/resources/DeviceCellGeolocations.ts @@ -1,7 +1,7 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as DynamoDB from 'aws-cdk-lib/aws-dynamodb' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as IoT from 'aws-cdk-lib/aws-iot' +import CloudFormation from 'aws-cdk-lib' +import DynamoDB from 'aws-cdk-lib/aws-dynamodb' +import IAM from 'aws-cdk-lib/aws-iam' +import IoT from 'aws-cdk-lib/aws-iot' /** * Store Cell Geolocation from Devices. diff --git a/cdk/resources/FOTAStorage.ts b/cdk/resources/FOTAStorage.ts index d709d02a6..708851174 100644 --- a/cdk/resources/FOTAStorage.ts +++ b/cdk/resources/FOTAStorage.ts @@ -1,6 +1,6 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as S3 from 'aws-cdk-lib/aws-s3' +import CloudFormation from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import S3 from 'aws-cdk-lib/aws-s3' /** * Storage firmware files diff --git a/cdk/resources/FirmwareCI.ts b/cdk/resources/FirmwareCI.ts index 453b354b7..995d333c4 100644 --- a/cdk/resources/FirmwareCI.ts +++ b/cdk/resources/FirmwareCI.ts @@ -1,7 +1,7 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as S3 from 'aws-cdk-lib/aws-s3' -import { CORE_STACK_NAME, FIRMWARE_CI_STACK_NAME } from '../stacks/stackName' +import CloudFormation from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import S3 from 'aws-cdk-lib/aws-s3' +import { CORE_STACK_NAME, FIRMWARE_CI_STACK_NAME } from '../stacks/stackName.js' export class FirmwareCI extends CloudFormation.Resource { public readonly bucket diff --git a/cdk/resources/HistoricalData.ts b/cdk/resources/HistoricalData.ts index 5d4b3bd6c..ddfc4278e 100644 --- a/cdk/resources/HistoricalData.ts +++ b/cdk/resources/HistoricalData.ts @@ -1,12 +1,12 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as IoT from 'aws-cdk-lib/aws-iot' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as Timestream from 'aws-cdk-lib/aws-timestream' -import { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas' -import { LambdaLogGroup } from './LambdaLogGroup' -import { LambdasWithLayer } from './LambdasWithLayer' -import { logToCloudWatch } from './logToCloudWatch' +import CloudFormation from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import IoT from 'aws-cdk-lib/aws-iot' +import Lambda from 'aws-cdk-lib/aws-lambda' +import Timestream from 'aws-cdk-lib/aws-timestream' +import type { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas.js' +import { LambdaLogGroup } from './LambdaLogGroup.js' +import type { LambdasWithLayer } from './LambdasWithLayer.js' +import { logToCloudWatch } from './logToCloudWatch.js' /** * Provides resources for historical data @@ -21,7 +21,7 @@ export class HistoricalData extends CloudFormation.Resource { lambdas, userRole, }: { - lambdas: LambdasWithLayer + lambdas: LambdasWithLayer userRole: IAM.IRole }, ) { @@ -63,12 +63,14 @@ export class HistoricalData extends CloudFormation.Resource { const storeMessagesInTimestream = new Lambda.Function(this, 'lambda', { layers: lambdas.layers, - handler: 'index.handler', + handler: lambdas.lambdas.storeMessagesInTimestream.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.minutes(2), memorySize: 1792, - code: lambdas.lambdas.storeMessagesInTimestream, + code: Lambda.Code.fromAsset( + lambdas.lambdas.storeMessagesInTimestream.zipFile, + ), description: 'Processes devices messages and updates and stores them in Timestream', initialPolicy: [ diff --git a/cdk/resources/LambdaLogGroup.ts b/cdk/resources/LambdaLogGroup.ts index 91ca4457d..fd08d9625 100644 --- a/cdk/resources/LambdaLogGroup.ts +++ b/cdk/resources/LambdaLogGroup.ts @@ -1,7 +1,7 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as CloudWatchLogs from 'aws-cdk-lib/aws-logs' -import { Construct } from 'constructs' +import CloudFormation from 'aws-cdk-lib' +import type * as Lambda from 'aws-cdk-lib/aws-lambda' +import CloudWatchLogs from 'aws-cdk-lib/aws-logs' +import type { Construct } from 'constructs' export class LambdaLogGroup extends CloudFormation.Resource { public constructor(parent: Construct, id: string, lambda: Lambda.IFunction) { diff --git a/cdk/resources/LambdasWithLayer.ts b/cdk/resources/LambdasWithLayer.ts index 93fde05c0..8622be61c 100644 --- a/cdk/resources/LambdasWithLayer.ts +++ b/cdk/resources/LambdasWithLayer.ts @@ -1,12 +1,13 @@ -import * as Lambda from 'aws-cdk-lib/aws-lambda' +import type * as Lambda from 'aws-cdk-lib/aws-lambda' +import type { PackedLambda } from '../helper/lambdas/packLambda' export type LambdasWithLayer< A extends { - [key: string]: string + [key: string]: PackedLambda }, > = { lambdas: { - [P in keyof A]: Lambda.S3Code + [P in keyof A]: PackedLambda } layers: Lambda.ILayerVersion[] } diff --git a/cdk/resources/NetworkSurveyGeolocation.ts b/cdk/resources/NetworkSurveyGeolocation.ts index e1155b285..90ad6254e 100644 --- a/cdk/resources/NetworkSurveyGeolocation.ts +++ b/cdk/resources/NetworkSurveyGeolocation.ts @@ -1,14 +1,14 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as StepFunctions from 'aws-cdk-lib/aws-stepfunctions' -import * as StepFunctionTasks from 'aws-cdk-lib/aws-stepfunctions-tasks' -import { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas' -import { CORE_STACK_NAME } from '../stacks/stackName' -import { LambdaLogGroup } from './LambdaLogGroup' -import { LambdasWithLayer } from './LambdasWithLayer' -import { logToCloudWatch } from './logToCloudWatch' -import { NetworkSurveysStorage } from './NetworkSurveysStorage' +import CloudFormation from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import Lambda from 'aws-cdk-lib/aws-lambda' +import StepFunctions from 'aws-cdk-lib/aws-stepfunctions' +import StepFunctionTasks from 'aws-cdk-lib/aws-stepfunctions-tasks' +import type { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas.js' +import { CORE_STACK_NAME } from '../stacks/stackName.js' +import { LambdaLogGroup } from './LambdaLogGroup.js' +import type { LambdasWithLayer } from './LambdasWithLayer.js' +import { logToCloudWatch } from './logToCloudWatch.js' +import type { NetworkSurveysStorage } from './NetworkSurveysStorage.js' /** * Describes the step functions which resolves the geolocation of network survey using nRF Cloud Location Services @@ -22,7 +22,7 @@ export class NetworkSurveyGeolocation extends CloudFormation.Resource { lambdas, storage, }: { - lambdas: LambdasWithLayer + lambdas: LambdasWithLayer storage: NetworkSurveysStorage }, ) { @@ -30,12 +30,15 @@ export class NetworkSurveyGeolocation extends CloudFormation.Resource { const fromNrfCloud = new Lambda.Function(this, 'fromNrfCloud', { layers: lambdas.layers, - handler: 'index.handler', + handler: + lambdas.lambdas.networkSurveyGeolocateFromNrfCloudStepFunction.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.seconds(10), memorySize: 1792, - code: lambdas.lambdas.networkSurveyGeolocateFromNrfCloudStepFunction, + code: Lambda.Code.fromAsset( + lambdas.lambdas.networkSurveyGeolocateFromNrfCloudStepFunction.zipFile, + ), description: 'Resolve device geolocation from network survey using the nRF Cloud API', initialPolicy: [ diff --git a/cdk/resources/NetworkSurveyGeolocationApi.ts b/cdk/resources/NetworkSurveyGeolocationApi.ts index 489a93879..ed654822d 100644 --- a/cdk/resources/NetworkSurveyGeolocationApi.ts +++ b/cdk/resources/NetworkSurveyGeolocationApi.ts @@ -1,10 +1,10 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas' -import { LambdaLogGroup } from './LambdaLogGroup' -import { LambdasWithLayer } from './LambdasWithLayer' -import { NetworkSurveyGeolocation } from './NetworkSurveyGeolocation' -import { NetworkSurveysStorage } from './NetworkSurveysStorage' +import CloudFormation from 'aws-cdk-lib' +import Lambda from 'aws-cdk-lib/aws-lambda' +import type { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas.js' +import { LambdaLogGroup } from './LambdaLogGroup.js' +import type { LambdasWithLayer } from './LambdasWithLayer.js' +import type { NetworkSurveyGeolocation } from './NetworkSurveyGeolocation.js' +import type { NetworkSurveysStorage } from './NetworkSurveysStorage.js' /** * Provides geo-location for Network surveys from devices through a HTTP API @@ -24,7 +24,7 @@ export class NetworkSurveyGeolocationApi extends CloudFormation.Resource { geolocation, }: { storage: NetworkSurveysStorage - lambdas: LambdasWithLayer + lambdas: LambdasWithLayer geolocation: NetworkSurveyGeolocation }, ) { @@ -32,12 +32,14 @@ export class NetworkSurveyGeolocationApi extends CloudFormation.Resource { const getSurveyLocation = new Lambda.Function(this, 'lambda', { layers: lambdas.layers, - handler: 'index.handler', + handler: lambdas.lambdas.geolocateNetworkSurveyHttpApi.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.seconds(60), memorySize: 1792, - code: lambdas.lambdas.geolocateNetworkSurveyHttpApi, + code: Lambda.Code.fromAsset( + lambdas.lambdas.geolocateNetworkSurveyHttpApi.zipFile, + ), description: 'Geolocate Network survey', environment: { SURVEYS_TABLE: storage.surveysTable.tableName, diff --git a/cdk/resources/NetworkSurveysStorage.ts b/cdk/resources/NetworkSurveysStorage.ts index e64757597..1112f1b5f 100644 --- a/cdk/resources/NetworkSurveysStorage.ts +++ b/cdk/resources/NetworkSurveysStorage.ts @@ -1,7 +1,7 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as DynamoDB from 'aws-cdk-lib/aws-dynamodb' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as IoT from 'aws-cdk-lib/aws-iot' +import CloudFormation from 'aws-cdk-lib' +import DynamoDB from 'aws-cdk-lib/aws-dynamodb' +import IAM from 'aws-cdk-lib/aws-iam' +import IoT from 'aws-cdk-lib/aws-iot' /** * Provides storage for Network surveys diff --git a/cdk/resources/PGPSDeviceRequestHandler.ts b/cdk/resources/PGPSDeviceRequestHandler.ts index 9960a6b3a..8278efa8e 100644 --- a/cdk/resources/PGPSDeviceRequestHandler.ts +++ b/cdk/resources/PGPSDeviceRequestHandler.ts @@ -1,15 +1,14 @@ -import * as CloudFormation from 'aws-cdk-lib' -import { Duration } from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as IoT from 'aws-cdk-lib/aws-iot' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as SQS from 'aws-cdk-lib/aws-sqs' -import { iotRuleSqlCheckIfDefinedAndNotZero } from '../helper/iotRuleSqlCheckIfDefinedAndNotZero' -import { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas' -import { LambdaLogGroup } from './LambdaLogGroup' -import { LambdasWithLayer } from './LambdasWithLayer' -import { PGPSResolver } from './PGPSResolver' -import { PGPSStorage } from './PGPSStorage' +import CloudFormation, { Duration } from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import IoT from 'aws-cdk-lib/aws-iot' +import Lambda from 'aws-cdk-lib/aws-lambda' +import SQS from 'aws-cdk-lib/aws-sqs' +import { iotRuleSqlCheckIfDefinedAndNotZero } from '../helper/iotRuleSqlCheckIfDefinedAndNotZero.js' +import type { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas.js' +import { LambdaLogGroup } from './LambdaLogGroup.js' +import type { LambdasWithLayer } from './LambdasWithLayer.js' +import type { PGPSResolver } from './PGPSResolver.js' +import type { PGPSStorage } from './PGPSStorage.js' export const MAX_RESOLUTION_TIME_IN_MINUTES = 10 @@ -39,7 +38,7 @@ export class PGPSDeviceRequestHandler extends CloudFormation.Resource { storage, resolver, }: { - lambdas: LambdasWithLayer + lambdas: LambdasWithLayer storage: PGPSStorage resolver: PGPSResolver }, @@ -100,12 +99,14 @@ export class PGPSDeviceRequestHandler extends CloudFormation.Resource { 'deviceRequestHandler', { layers: lambdas.layers, - handler: 'index.handler', + handler: lambdas.lambdas.pgpsDeviceRequestHandler.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.minutes(1), memorySize: 1792, - code: lambdas.lambdas.pgpsDeviceRequestHandler, + code: Lambda.Code.fromAsset( + lambdas.lambdas.pgpsDeviceRequestHandler.zipFile, + ), description: 'Handles P-GPS requests which have been queued, either by fullfilling them by using the resolved data, or by starting a new resolution', environment: { diff --git a/cdk/resources/PGPSResolver.ts b/cdk/resources/PGPSResolver.ts index 13931e595..e4790255a 100644 --- a/cdk/resources/PGPSResolver.ts +++ b/cdk/resources/PGPSResolver.ts @@ -1,15 +1,15 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as StepFunctions from 'aws-cdk-lib/aws-stepfunctions' -import * as StepFunctionTasks from 'aws-cdk-lib/aws-stepfunctions-tasks' -import { enabledInContext } from '../helper/enabledInContext' -import { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas' -import { CORE_STACK_NAME } from '../stacks/stackName' -import { LambdaLogGroup } from './LambdaLogGroup' -import { LambdasWithLayer } from './LambdasWithLayer' -import { logToCloudWatch } from './logToCloudWatch' -import { PGPSStorage } from './PGPSStorage' +import CloudFormation from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import Lambda from 'aws-cdk-lib/aws-lambda' +import StepFunctions from 'aws-cdk-lib/aws-stepfunctions' +import StepFunctionTasks from 'aws-cdk-lib/aws-stepfunctions-tasks' +import { enabledInContext } from '../helper/enabledInContext.js' +import type { AssetTrackerLambdas } from '../stacks/AssetTracker/lambdas.js' +import { CORE_STACK_NAME } from '../stacks/stackName.js' +import { LambdaLogGroup } from './LambdaLogGroup.js' +import type { LambdasWithLayer } from './LambdasWithLayer.js' +import { logToCloudWatch } from './logToCloudWatch.js' +import type { PGPSStorage } from './PGPSStorage.js' /** * Provides a state machine that can resolve P-GPS requests @@ -23,7 +23,7 @@ export class PGPSResolver extends CloudFormation.Resource { lambdas, storage, }: { - lambdas: LambdasWithLayer + lambdas: LambdasWithLayer storage: PGPSStorage }, ) { @@ -40,12 +40,14 @@ export class PGPSResolver extends CloudFormation.Resource { onEnabled: () => { fromNrfCloud = new Lambda.Function(this, 'fromNrfCloud', { layers: lambdas.layers, - handler: 'index.handler', + handler: lambdas.lambdas.pgpsNrfCloudStepFunction.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.seconds(10), memorySize: 1792, - code: lambdas.lambdas.pgpsNrfCloudStepFunction, + code: Lambda.Code.fromAsset( + lambdas.lambdas.pgpsNrfCloudStepFunction.zipFile, + ), description: 'Use the nRF Cloud API to provide P-GPS data for devices', initialPolicy: [ diff --git a/cdk/resources/PGPSStorage.ts b/cdk/resources/PGPSStorage.ts index ae82e5291..12a0a1c9a 100644 --- a/cdk/resources/PGPSStorage.ts +++ b/cdk/resources/PGPSStorage.ts @@ -1,5 +1,5 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as DynamoDB from 'aws-cdk-lib/aws-dynamodb' +import CloudFormation from 'aws-cdk-lib' +import DynamoDB from 'aws-cdk-lib/aws-dynamodb' /** * Provides storage for P-GPS requests diff --git a/cdk/resources/RepublishDesiredConfig.ts b/cdk/resources/RepublishDesiredConfig.ts index 5afe2235e..0c8b299ed 100644 --- a/cdk/resources/RepublishDesiredConfig.ts +++ b/cdk/resources/RepublishDesiredConfig.ts @@ -1,6 +1,6 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as IoT from 'aws-cdk-lib/aws-iot' +import CloudFormation from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import IoT from 'aws-cdk-lib/aws-iot' /** * This sets up the rules to republish the desired config diff --git a/cdk/resources/ThingGroup.ts b/cdk/resources/ThingGroup.ts index 592588903..632643fc6 100644 --- a/cdk/resources/ThingGroup.ts +++ b/cdk/resources/ThingGroup.ts @@ -1,6 +1,6 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import { Construct } from 'constructs' +import CloudFormation from 'aws-cdk-lib' +import type * as Lambda from 'aws-cdk-lib/aws-lambda' +import type { Construct } from 'constructs' export class ThingGroup extends CloudFormation.Resource { public constructor( diff --git a/cdk/resources/ThingGroupLambda.ts b/cdk/resources/ThingGroupLambda.ts index 60256ae59..24b4f3030 100644 --- a/cdk/resources/ThingGroupLambda.ts +++ b/cdk/resources/ThingGroupLambda.ts @@ -1,10 +1,10 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import { CDKLambdas } from '../stacks/AssetTracker/lambdas' -import { LambdaLogGroup } from './LambdaLogGroup' -import { LambdasWithLayer } from './LambdasWithLayer' -import { logToCloudWatch } from './logToCloudWatch' +import CloudFormation from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import Lambda from 'aws-cdk-lib/aws-lambda' +import type { CDKLambdas } from '../stacks/AssetTracker/lambdas.js' +import { LambdaLogGroup } from './LambdaLogGroup.js' +import type { LambdasWithLayer } from './LambdasWithLayer.js' +import { logToCloudWatch } from './logToCloudWatch.js' export class ThingGroupLambda extends CloudFormation.Resource { public readonly function: Lambda.IFunction @@ -14,17 +14,17 @@ export class ThingGroupLambda extends CloudFormation.Resource { { cdkLambdas, }: { - cdkLambdas: LambdasWithLayer + cdkLambdas: LambdasWithLayer }, ) { super(parent, id) this.function = new Lambda.Function(this, 'createThingGroup', { - code: cdkLambdas.lambdas.createThingGroup, + code: Lambda.Code.fromAsset(cdkLambdas.lambdas.createThingGroup.zipFile), layers: cdkLambdas.layers, description: 'Used in CloudFormation to create the thing group for the devices', - handler: 'index.handler', + handler: cdkLambdas.lambdas.createThingGroup.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CloudFormation.Duration.minutes(1), diff --git a/cdk/resources/WebAppCD.ts b/cdk/resources/WebAppCD.ts index 30806ee0a..49d18fa84 100644 --- a/cdk/resources/WebAppCD.ts +++ b/cdk/resources/WebAppCD.ts @@ -1,11 +1,11 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as CodeBuild from 'aws-cdk-lib/aws-codebuild' -import * as CodePipeline from 'aws-cdk-lib/aws-codepipeline' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as S3 from 'aws-cdk-lib/aws-s3' -import * as SSM from 'aws-cdk-lib/aws-ssm' +import CloudFormation from 'aws-cdk-lib' +import CodeBuild from 'aws-cdk-lib/aws-codebuild' +import CodePipeline from 'aws-cdk-lib/aws-codepipeline' +import IAM from 'aws-cdk-lib/aws-iam' +import S3 from 'aws-cdk-lib/aws-s3' +import type * as SSM from 'aws-cdk-lib/aws-ssm' import { Construct } from 'constructs' -import { CORE_STACK_NAME } from '../stacks/stackName' +import { CORE_STACK_NAME } from '../stacks/stackName.js' export const BuildActionCodeBuild = { category: 'Build', diff --git a/cdk/resources/WebAppCI.ts b/cdk/resources/WebAppCI.ts index 032526d05..267082b7d 100644 --- a/cdk/resources/WebAppCI.ts +++ b/cdk/resources/WebAppCI.ts @@ -1,8 +1,8 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as Cognito from 'aws-cdk-lib/aws-cognito' -import * as DynamoDB from 'aws-cdk-lib/aws-dynamodb' -import * as IAM from 'aws-cdk-lib/aws-iam' -import { CORE_STACK_NAME, WEBAPP_STACK_NAME } from '../stacks/stackName' +import CloudFormation from 'aws-cdk-lib' +import type * as Cognito from 'aws-cdk-lib/aws-cognito' +import type * as DynamoDB from 'aws-cdk-lib/aws-dynamodb' +import IAM from 'aws-cdk-lib/aws-iam' +import { CORE_STACK_NAME, WEBAPP_STACK_NAME } from '../stacks/stackName.js' export class WebAppCI extends CloudFormation.Resource { public readonly userAccessKey diff --git a/cdk/resources/WebAppHosting.ts b/cdk/resources/WebAppHosting.ts index 01b473a71..431201a22 100644 --- a/cdk/resources/WebAppHosting.ts +++ b/cdk/resources/WebAppHosting.ts @@ -1,6 +1,6 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as CloudFront from 'aws-cdk-lib/aws-cloudfront' -import * as S3 from 'aws-cdk-lib/aws-s3' +import CloudFormation from 'aws-cdk-lib' +import CloudFront from 'aws-cdk-lib/aws-cloudfront' +import S3 from 'aws-cdk-lib/aws-s3' /** * This sets up the web hosting for a web app diff --git a/cdk/resources/lambdasOnS3.ts b/cdk/resources/lambdasOnS3.ts deleted file mode 100644 index 02cef0b03..000000000 --- a/cdk/resources/lambdasOnS3.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as S3 from 'aws-cdk-lib/aws-s3' -import { PackedLambdas } from '../helper/lambdas/PackedLambdas' - -export const lambdasOnS3 = - (sourceCodeBucket: S3.IBucket) => - < - A extends { - [key: string]: string - }, - >( - packedLambdas: PackedLambdas, - ): { - [P in keyof A]: Lambda.S3Code - } => - Object.entries(packedLambdas.lambdas.lambdaZipFileNames).reduce( - (o, [lambdaName, zipFileName]) => ({ - ...o, - [lambdaName]: Lambda.Code.fromBucket(sourceCodeBucket, zipFileName), - }), - {} as { - [P in keyof A]: Lambda.S3Code - }, - ) diff --git a/cdk/resources/logToCloudWatch.ts b/cdk/resources/logToCloudWatch.ts index 7f2895880..3e295c106 100644 --- a/cdk/resources/logToCloudWatch.ts +++ b/cdk/resources/logToCloudWatch.ts @@ -1,4 +1,4 @@ -import * as IAM from 'aws-cdk-lib/aws-iam' +import IAM from 'aws-cdk-lib/aws-iam' export const logToCloudWatch = new IAM.PolicyStatement({ resources: ['*'], diff --git a/cdk/stacks/AssetTracker/lambdas.ts b/cdk/stacks/AssetTracker/lambdas.ts index 59e87c8a6..d7610cd35 100644 --- a/cdk/stacks/AssetTracker/lambdas.ts +++ b/cdk/stacks/AssetTracker/lambdas.ts @@ -1,182 +1,114 @@ -import { - ConsoleProgressReporter, - makeLayerFromPackageJSON, - packBaseLayer, - packLayeredLambdas, -} from '@nordicsemiconductor/package-layered-lambdas' -import * as path from 'path' -import { PackedLambdas } from '../../helper/lambdas/PackedLambdas' +import pjson from '../../../package.json' +import type { PackedLambda } from '../../helper/lambdas/packLambda.js' +import { packLambdaFromPath } from '../../helper/lambdas/packLambdaFromPath.js' +import { packLayer } from '../../helper/lambdas/packLayer.js' export type AssetTrackerLambdas = { - storeMessagesInTimestream: string - geolocateCellHttpApi: string - invokeStepFunctionFromSQS: string - geolocateFromCacheStepFunction: string - geolocateCellFromDeviceLocationsStepFunction: string - geolocateCellFromNrfCloudStepFunction: string - cacheCellGeolocationStepFunction: string - agpsDeviceRequestHandler: string - agpsNrfCloudStepFunction: string - pgpsDeviceRequestHandler: string - pgpsNrfCloudStepFunction: string - geolocateNetworkSurveyHttpApi: string - networkSurveyGeolocateFromNrfCloudStepFunction: string + layerZipFileName: string + lambdas: { + storeMessagesInTimestream: PackedLambda + geolocateCellHttpApi: PackedLambda + invokeStepFunctionFromSQS: PackedLambda + geolocateFromCacheStepFunction: PackedLambda + geolocateCellFromDeviceLocationsStepFunction: PackedLambda + geolocateCellFromNrfCloudStepFunction: PackedLambda + cacheCellGeolocationStepFunction: PackedLambda + agpsDeviceRequestHandler: PackedLambda + agpsNrfCloudStepFunction: PackedLambda + pgpsDeviceRequestHandler: PackedLambda + pgpsNrfCloudStepFunction: PackedLambda + geolocateNetworkSurveyHttpApi: PackedLambda + networkSurveyGeolocateFromNrfCloudStepFunction: PackedLambda + } } export type CDKLambdas = { - createThingGroup: string -} - -export const prepareAssetTrackerLambdas = async ({ - rootDir, - outDir, - sourceCodeBucketName, -}: { - rootDir: string - outDir: string - sourceCodeBucketName: string -}): Promise> => { - const reporter = ConsoleProgressReporter('nRF Asset Tracker Lambdas') - return { - layerZipFileName: await packBaseLayer({ - layerName: 'asset-tracker-layer', - reporter, - srcDir: rootDir, - outDir, - Bucket: sourceCodeBucketName, - }), - lambdas: await packLayeredLambdas({ - reporter, - id: 'asset-tracker', - srcDir: rootDir, - outDir, - Bucket: sourceCodeBucketName, - lambdas: { - storeMessagesInTimestream: path.resolve( - rootDir, - 'historicalData', - 'storeMessagesInTimestream.ts', - ), - invokeStepFunctionFromSQS: path.resolve( - rootDir, - 'cellGeolocation', - 'lambda', - 'invokeStepFunctionFromSQS.ts', - ), - geolocateFromCacheStepFunction: path.resolve( - rootDir, - 'cellGeolocation', - 'stepFunction', - 'fromCache.ts', - ), - geolocateCellFromDeviceLocationsStepFunction: path.resolve( - rootDir, - 'cellGeolocation', - 'stepFunction', - 'fromDeviceLocations.ts', - ), - geolocateCellFromNrfCloudStepFunction: path.resolve( - rootDir, - 'third-party', - 'nrfcloud.com', - 'cellgeolocation.ts', - ), - cacheCellGeolocationStepFunction: path.resolve( - rootDir, - 'cellGeolocation', - 'stepFunction', - 'updateCache.ts', - ), - geolocateCellHttpApi: path.resolve( - rootDir, - 'cellGeolocation', - 'httpApi', - 'cell.ts', - ), - agpsDeviceRequestHandler: path.resolve( - rootDir, - 'agps', - 'deviceRequestHandler.ts', - ), - agpsNrfCloudStepFunction: path.resolve( - rootDir, - 'third-party', - 'nrfcloud.com', - 'agps.ts', - ), - pgpsDeviceRequestHandler: path.resolve( - rootDir, - 'pgps', - 'deviceRequestHandler.ts', - ), - pgpsNrfCloudStepFunction: path.resolve( - rootDir, - 'third-party', - 'nrfcloud.com', - 'pgps.ts', - ), - geolocateNetworkSurveyHttpApi: path.resolve( - rootDir, - 'networkSurveyGeolocation', - 'httpApi', - 'locateSurvey.ts', - ), - networkSurveyGeolocateFromNrfCloudStepFunction: path.resolve( - rootDir, - 'third-party', - 'nrfcloud.com', - 'networksurveygeolocation.ts', - ), - }, - tsConfig: path.resolve(rootDir, 'tsconfig.json'), - }), + layerZipFileName: string + lambdas: { + createThingGroup: PackedLambda } } -export const prepareCDKLambdas = async ({ - rootDir, - outDir, - sourceCodeBucketName, -}: { - rootDir: string - outDir: string - sourceCodeBucketName: string -}): Promise> => { - const reporter = ConsoleProgressReporter('CDK Lambdas') - return { - layerZipFileName: await (async () => { - const cloudFormationLayerDir = path.resolve( - rootDir, - 'dist', - 'lambdas', - 'cloudFormationLayer', - ) - return makeLayerFromPackageJSON({ - layerName: 'cdk-layer', - packageJsonFile: path.resolve(rootDir, 'package.json'), - packageLockJsonFile: path.resolve(rootDir, 'package-lock.json'), - requiredDependencies: [ - '@nordicsemiconductor/cloudformation-helpers', - 'fast-xml-parser', - // uuid is still needed for the ThingGroup Custom Resource lambda - 'uuid', - ], - dir: cloudFormationLayerDir, - reporter, - sourceCodeBucketName, - outDir, +export const prepareAssetTrackerLambdas = + async (): Promise => ({ + layerZipFileName: ( + await packLayer({ + id: 'asset-tracker-layer', + dependencies: Object.keys(pjson.dependencies), }) - })(), - lambdas: await packLayeredLambdas({ - reporter, - id: 'CDK', - srcDir: rootDir, - outDir, - Bucket: sourceCodeBucketName, - lambdas: { - createThingGroup: path.resolve(rootDir, 'cdk', 'createThingGroup.ts'), - }, - tsConfig: path.resolve(rootDir, 'tsconfig.json'), - }), - } -} + ).layerZipFile, + lambdas: { + storeMessagesInTimestream: await packLambdaFromPath( + 'storeMessagesInTimestream', + 'historicalData/storeMessagesInTimestream.ts', + ), + invokeStepFunctionFromSQS: await packLambdaFromPath( + 'invokeStepFunctionFromSQS', + 'cellGeolocation/lambda/invokeStepFunctionFromSQS.ts', + ), + geolocateFromCacheStepFunction: await packLambdaFromPath( + 'geolocateFromCacheStepFunction', + 'cellGeolocation/stepFunction/fromCache.ts', + ), + geolocateCellFromDeviceLocationsStepFunction: await packLambdaFromPath( + 'geolocateCellFromDeviceLocationsStepFunction', + 'cellGeolocation/stepFunction/fromDeviceLocations.ts', + ), + geolocateCellFromNrfCloudStepFunction: await packLambdaFromPath( + 'geolocateCellFromNrfCloudStepFunction', + 'third-party/nrfcloud.com/cellgeolocation.ts', + ), + cacheCellGeolocationStepFunction: await packLambdaFromPath( + 'cacheCellGeolocationStepFunction', + 'cellGeolocation/stepFunction/updateCache.ts', + ), + geolocateCellHttpApi: await packLambdaFromPath( + 'geolocateCellHttpApi', + 'cellGeolocation/httpApi/cell.ts', + ), + agpsDeviceRequestHandler: await packLambdaFromPath( + 'agpsDeviceRequestHandler', + 'agps/deviceRequestHandler.ts', + ), + agpsNrfCloudStepFunction: await packLambdaFromPath( + 'agpsNrfCloudStepFunction', + 'third-party/nrfcloud.com/agps.ts', + ), + pgpsDeviceRequestHandler: await packLambdaFromPath( + 'pgpsDeviceRequestHandler', + 'pgps/deviceRequestHandler.ts', + ), + pgpsNrfCloudStepFunction: await packLambdaFromPath( + 'pgpsNrfCloudStepFunction', + 'third-party/nrfcloud.com/pgps.ts', + ), + geolocateNetworkSurveyHttpApi: await packLambdaFromPath( + 'geolocateNetworkSurveyHttpApi', + 'networkSurveyGeolocation/httpApi/locateSurvey.ts', + ), + networkSurveyGeolocateFromNrfCloudStepFunction: await packLambdaFromPath( + 'networkSurveyGeolocateFromNrfCloudStepFunction', + 'third-party/nrfcloud.com/networksurveygeolocation.ts', + ), + }, + }) + +export const prepareCDKLambdas = async (): Promise => ({ + layerZipFileName: ( + await packLayer({ + dependencies: [ + '@nordicsemiconductor/cloudformation-helpers', + 'fast-xml-parser', + // uuid is still needed for the ThingGroup Custom Resource lambda + 'uuid', + ], + id: 'cdk-layer', + }) + ).layerZipFile, + lambdas: { + createThingGroup: await packLambdaFromPath( + 'createThingGroup', + 'cdk/createThingGroup.ts', + ), + }, +}) diff --git a/cdk/stacks/AssetTracker/stack.ts b/cdk/stacks/AssetTracker/stack.ts index 53cced092..6a0694b8e 100644 --- a/cdk/stacks/AssetTracker/stack.ts +++ b/cdk/stacks/AssetTracker/stack.ts @@ -1,33 +1,30 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as Cognito from 'aws-cdk-lib/aws-cognito' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as Iot from 'aws-cdk-lib/aws-iot' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as S3 from 'aws-cdk-lib/aws-s3' -import { enabledInContext } from '../../helper/enabledInContext' -import { PackedLambdas } from '../../helper/lambdas/PackedLambdas' -import { warn } from '../../helper/note' -import { AGPSDeviceRequestHandler } from '../../resources/AGPSDeviceRequestHandler' -import { AGPSResolver } from '../../resources/AGPSResolver' -import { AGPSStorage } from '../../resources/AGPSStorage' -import { CellGeolocation } from '../../resources/CellGeolocation' -import { CellGeolocationApi } from '../../resources/CellGeolocationApi' -import { DeviceCellGeolocations } from '../../resources/DeviceCellGeolocations' -import { FOTAStorage } from '../../resources/FOTAStorage' -import { HistoricalData } from '../../resources/HistoricalData' -import { lambdasOnS3 } from '../../resources/lambdasOnS3' -import { LambdasWithLayer } from '../../resources/LambdasWithLayer' -import { NetworkSurveyGeolocation } from '../../resources/NetworkSurveyGeolocation' -import { NetworkSurveyGeolocationApi } from '../../resources/NetworkSurveyGeolocationApi' -import { NetworkSurveysStorage } from '../../resources/NetworkSurveysStorage' -import { PGPSDeviceRequestHandler } from '../../resources/PGPSDeviceRequestHandler' -import { PGPSResolver } from '../../resources/PGPSResolver' -import { PGPSStorage } from '../../resources/PGPSStorage' -import { RepublishDesiredConfig } from '../../resources/RepublishDesiredConfig' -import { ThingGroup } from '../../resources/ThingGroup' -import { ThingGroupLambda } from '../../resources/ThingGroupLambda' -import { CORE_STACK_NAME } from '../stackName' -import { AssetTrackerLambdas, CDKLambdas } from './lambdas' +import CloudFormation from 'aws-cdk-lib' +import Cognito from 'aws-cdk-lib/aws-cognito' +import IAM from 'aws-cdk-lib/aws-iam' +import Iot from 'aws-cdk-lib/aws-iot' +import Lambda from 'aws-cdk-lib/aws-lambda' +import { enabledInContext } from '../../helper/enabledInContext.js' +import { warn } from '../../helper/note.js' +import { AGPSDeviceRequestHandler } from '../../resources/AGPSDeviceRequestHandler.js' +import { AGPSResolver } from '../../resources/AGPSResolver.js' +import { AGPSStorage } from '../../resources/AGPSStorage.js' +import { CellGeolocation } from '../../resources/CellGeolocation.js' +import { CellGeolocationApi } from '../../resources/CellGeolocationApi.js' +import { DeviceCellGeolocations } from '../../resources/DeviceCellGeolocations.js' +import { FOTAStorage } from '../../resources/FOTAStorage.js' +import { HistoricalData } from '../../resources/HistoricalData.js' +import type { LambdasWithLayer } from '../../resources/LambdasWithLayer.js' +import { NetworkSurveyGeolocation } from '../../resources/NetworkSurveyGeolocation.js' +import { NetworkSurveyGeolocationApi } from '../../resources/NetworkSurveyGeolocationApi.js' +import { NetworkSurveysStorage } from '../../resources/NetworkSurveysStorage.js' +import { PGPSDeviceRequestHandler } from '../../resources/PGPSDeviceRequestHandler.js' +import { PGPSResolver } from '../../resources/PGPSResolver.js' +import { PGPSStorage } from '../../resources/PGPSStorage.js' +import { RepublishDesiredConfig } from '../../resources/RepublishDesiredConfig.js' +import { ThingGroup } from '../../resources/ThingGroup.js' +import { ThingGroupLambda } from '../../resources/ThingGroupLambda.js' +import { CORE_STACK_NAME } from '../stackName.js' +import type { AssetTrackerLambdas, CDKLambdas } from './lambdas.js' /** * Defines the names use for stack outputs, which are used below to ensure @@ -55,7 +52,6 @@ export const StackOutputs = { networkSurveyStorageTableName: `${CORE_STACK_NAME}:networkSurveyStorageTableName`, networkSurveyStorageTableArn: `${CORE_STACK_NAME}:networkSurveyStorageTableArn`, networkSurveyStorageTableStreamArn: `${CORE_STACK_NAME}:networkSurveyStorageTableStreamArn`, - cloudformationLayerVersionArn: `${CORE_STACK_NAME}:cloudformationLayerVersionArn`, networkSurveyGeolocationApiUrl: `${CORE_STACK_NAME}:networkSurveyGeolocationApiUrl`, } as const @@ -63,55 +59,15 @@ export class AssetTrackerStack extends CloudFormation.Stack { public constructor( parent: CloudFormation.App, { - sourceCodeBucketName, packedLambdas, packedCDKLambdas, }: { - sourceCodeBucketName: string - packedLambdas: PackedLambdas - packedCDKLambdas: PackedLambdas + packedLambdas: AssetTrackerLambdas + packedCDKLambdas: CDKLambdas }, ) { super(parent, CORE_STACK_NAME) - const sourceCodeBucket = S3.Bucket.fromBucketAttributes( - this, - 'SourceCodeBucket', - { - bucketName: sourceCodeBucketName, - }, - ) - const lambasOnBucket = lambdasOnS3(sourceCodeBucket) - - const baseLayer = new Lambda.LayerVersion( - this, - `${CORE_STACK_NAME}-layer`, - { - code: Lambda.Code.fromBucket( - sourceCodeBucket, - packedLambdas.layerZipFileName, - ), - compatibleRuntimes: [Lambda.Runtime.NODEJS_18_X], - }, - ) - - const cloudFormationLayer = new Lambda.LayerVersion( - this, - `${CORE_STACK_NAME}-cloudformation-layer`, - { - code: Lambda.Code.fromBucket( - sourceCodeBucket, - packedCDKLambdas.layerZipFileName, - ), - compatibleRuntimes: [Lambda.Runtime.NODEJS_18_X], - }, - ) - - new CloudFormation.CfnOutput(this, 'cloudformationLayerVersionArn', { - value: cloudFormationLayer.layerVersionArn, - exportName: StackOutputs.cloudformationLayerVersionArn, - }) - const isTest = this.node.tryGetContext('isTest') === true if (isTest) { @@ -394,13 +350,20 @@ export class AssetTrackerStack extends CloudFormation.Stack { exportName: StackOutputs.thingPolicyArn, }) - const cdkLambdas = { - lambdas: lambasOnBucket(packedCDKLambdas), - layers: [cloudFormationLayer], - } - const thingGroupLambda = new ThingGroupLambda(this, 'thingGroupLambda', { - cdkLambdas, + cdkLambdas: { + lambdas: packedCDKLambdas.lambdas, + layers: [ + new Lambda.LayerVersion( + this, + `${CORE_STACK_NAME}-cloudformation-layer`, + { + code: Lambda.Code.fromAsset(packedCDKLambdas.layerZipFileName), + compatibleRuntimes: [Lambda.Runtime.NODEJS_18_X], + }, + ), + ], + }, }) new CloudFormation.CfnOutput(this, 'thingGroupLambdaArn', { @@ -423,9 +386,14 @@ export class AssetTrackerStack extends CloudFormation.Stack { new RepublishDesiredConfig(this, 'republishDesiredConfig') - const lambdas: LambdasWithLayer = { - lambdas: lambasOnBucket(packedLambdas), - layers: [baseLayer], + const lambdas: LambdasWithLayer = { + lambdas: packedLambdas.lambdas, + layers: [ + new Lambda.LayerVersion(this, `${CORE_STACK_NAME}-layer`, { + code: Lambda.Code.fromAsset(packedLambdas.layerZipFileName), + compatibleRuntimes: [Lambda.Runtime.NODEJS_18_X], + }), + ], } const hd = new HistoricalData(this, 'historicalData', { diff --git a/cdk/stacks/ContinuousDeployment.ts b/cdk/stacks/ContinuousDeployment.ts index f7ebbff7f..5da2d2df1 100644 --- a/cdk/stacks/ContinuousDeployment.ts +++ b/cdk/stacks/ContinuousDeployment.ts @@ -1,14 +1,17 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as CodeBuild from 'aws-cdk-lib/aws-codebuild' -import * as CodePipeline from 'aws-cdk-lib/aws-codepipeline' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as S3 from 'aws-cdk-lib/aws-s3' -import * as SSM from 'aws-cdk-lib/aws-ssm' +import CloudFormation from 'aws-cdk-lib' +import CodeBuild from 'aws-cdk-lib/aws-codebuild' +import CodePipeline from 'aws-cdk-lib/aws-codepipeline' +import IAM from 'aws-cdk-lib/aws-iam' +import S3 from 'aws-cdk-lib/aws-s3' +import SSM from 'aws-cdk-lib/aws-ssm' import chalk from 'chalk' -import { enabledInContext } from '../helper/enabledInContext' -import { info } from '../helper/note' -import { BuildActionCodeBuild, WebAppCD } from '../resources/WebAppCD' -import { CONTINUOUS_DEPLOYMENT_STACK_NAME, CORE_STACK_NAME } from './stackName' +import { enabledInContext } from '../helper/enabledInContext.js' +import { info } from '../helper/note.js' +import { BuildActionCodeBuild, WebAppCD } from '../resources/WebAppCD.js' +import { + CONTINUOUS_DEPLOYMENT_STACK_NAME, + CORE_STACK_NAME, +} from './stackName.js' /** * This is the CloudFormation stack sets up the continuous deployment of the project. diff --git a/cdk/stacks/FirmwareCI.ts b/cdk/stacks/FirmwareCI.ts index 8f68ef15a..dfb1b8ba5 100644 --- a/cdk/stacks/FirmwareCI.ts +++ b/cdk/stacks/FirmwareCI.ts @@ -1,9 +1,8 @@ -import * as CloudFormation from 'aws-cdk-lib' -import { Fn } from 'aws-cdk-lib' -import * as IAM from 'aws-cdk-lib/aws-iam' -import { FirmwareCI } from '../resources/FirmwareCI' -import { StackOutputs } from './AssetTracker/stack' -import { FIRMWARE_CI_STACK_NAME } from './stackName' +import CloudFormation, { Fn } from 'aws-cdk-lib' +import IAM from 'aws-cdk-lib/aws-iam' +import { FirmwareCI } from '../resources/FirmwareCI.js' +import { StackOutputs } from './AssetTracker/stack.js' +import { FIRMWARE_CI_STACK_NAME } from './stackName.js' export class FirmwareCIStack extends CloudFormation.Stack { public constructor(parent: CloudFormation.App) { super(parent, FIRMWARE_CI_STACK_NAME) diff --git a/cdk/stacks/LambdaSourceCodeStorage.ts b/cdk/stacks/LambdaSourceCodeStorage.ts deleted file mode 100644 index cb158fa0a..000000000 --- a/cdk/stacks/LambdaSourceCodeStorage.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { App, CfnOutput, RemovalPolicy, Stack } from 'aws-cdk-lib' -import * as S3 from 'aws-cdk-lib/aws-s3' -import { SOURCECODE_STACK_NAME } from './stackName' - -/** - * This stack provides a bucket to store the source code for the lambda functions - */ -export class LambdaSourceCodeStorageStack extends Stack { - public readonly bucket: S3.Bucket - - public constructor(parent: App) { - super(parent, SOURCECODE_STACK_NAME) - this.bucket = new S3.Bucket(this, 'cf-sourcecode', { - removalPolicy: RemovalPolicy.DESTROY, - }) - - new CfnOutput(this, 'bucketName', { - value: this.bucket.bucketName, - exportName: `${this.stackName}:bucketName`, - }) - } -} diff --git a/cdk/stacks/WebApp.ts b/cdk/stacks/WebApp.ts index b58d12626..98394b9b0 100644 --- a/cdk/stacks/WebApp.ts +++ b/cdk/stacks/WebApp.ts @@ -1,9 +1,9 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as SSM from 'aws-cdk-lib/aws-ssm' -import { settingsPath } from '../../util/settings' -import { WebAppHosting } from '../resources/WebAppHosting' -import { StackOutputs as CoreStackOutputs } from './AssetTracker/stack' -import { WEBAPP_STACK_NAME } from './stackName' +import CloudFormation from 'aws-cdk-lib' +import SSM from 'aws-cdk-lib/aws-ssm' +import { settingsPath } from '../../util/settings.js' +import { WebAppHosting } from '../resources/WebAppHosting.js' +import { StackOutputs as CoreStackOutputs } from './AssetTracker/stack.js' +import { WEBAPP_STACK_NAME } from './stackName.js' /** * Defines the names use for stack outputs, which are used below to ensure @@ -87,7 +87,7 @@ export class WebAppStack extends CloudFormation.Stack { for (const k of Object.keys(SSMParameters)) { new SSM.StringParameter(this, `${k}SSMParameter`, { - stringValue: SSMParameters[k], + stringValue: SSMParameters[k] as string, parameterName: `${ssmPrefix}/${k}`, }) } diff --git a/cdk/stacks/WebAppCI.ts b/cdk/stacks/WebAppCI.ts index 2c79491ff..1a598a716 100644 --- a/cdk/stacks/WebAppCI.ts +++ b/cdk/stacks/WebAppCI.ts @@ -1,9 +1,9 @@ -import * as CloudFormation from 'aws-cdk-lib' -import * as Cognito from 'aws-cdk-lib/aws-cognito' -import * as DynamoDB from 'aws-cdk-lib/aws-dynamodb' -import { WebAppCI } from '../resources/WebAppCI' -import { StackOutputs } from './AssetTracker/stack' -import { WEBAPP_CI_STACK_NAME } from './stackName' +import CloudFormation from 'aws-cdk-lib' +import Cognito from 'aws-cdk-lib/aws-cognito' +import DynamoDB from 'aws-cdk-lib/aws-dynamodb' +import { WebAppCI } from '../resources/WebAppCI.js' +import { StackOutputs } from './AssetTracker/stack.js' +import { WEBAPP_CI_STACK_NAME } from './stackName.js' export class WebAppCIStack extends CloudFormation.Stack { public constructor(parent: CloudFormation.App) { diff --git a/cdk/stacks/stackName.ts b/cdk/stacks/stackName.ts index ce48ca7c9..6663be1e4 100644 --- a/cdk/stacks/stackName.ts +++ b/cdk/stacks/stackName.ts @@ -1,7 +1,6 @@ const STACK_NAME = process.env.STACK_NAME ?? 'nrf-asset-tracker' export const CORE_STACK_NAME = STACK_NAME export const WEBAPP_STACK_NAME = `${STACK_NAME}-webapp` -export const SOURCECODE_STACK_NAME = `${STACK_NAME}-sourcecode` export const CONTINUOUS_DEPLOYMENT_STACK_NAME = `${STACK_NAME}-continuous-deployment` export const FIRMWARE_CI_STACK_NAME = `${STACK_NAME}-firmware-ci` export const WEBAPP_CI_STACK_NAME = `${STACK_NAME}-web-app-ci` diff --git a/cdk/test-resources/HttpApiMockStack.ts b/cdk/test-resources/HttpApiMockStack.ts index 4345cbb3d..110e599ac 100644 --- a/cdk/test-resources/HttpApiMockStack.ts +++ b/cdk/test-resources/HttpApiMockStack.ts @@ -1,15 +1,12 @@ -import * as CDK from 'aws-cdk-lib' -import * as ApiGateway from 'aws-cdk-lib/aws-apigateway' -import * as DynamoDB from 'aws-cdk-lib/aws-dynamodb' -import * as IAM from 'aws-cdk-lib/aws-iam' -import * as Lambda from 'aws-cdk-lib/aws-lambda' -import * as S3 from 'aws-cdk-lib/aws-s3' -import { PackedLambdas } from '../helper/lambdas/PackedLambdas' -import { LambdaLogGroup } from '../resources/LambdaLogGroup' -import { lambdasOnS3 } from '../resources/lambdasOnS3' -import { logToCloudWatch } from '../resources/logToCloudWatch' -import { HTTP_MOCK_HTTP_API_STACK_NAME } from '../stacks/stackName' -import { HTTPAPIMockLambdas } from './prepare-test-resources' +import CDK from 'aws-cdk-lib' +import ApiGateway from 'aws-cdk-lib/aws-apigateway' +import DynamoDB from 'aws-cdk-lib/aws-dynamodb' +import IAM from 'aws-cdk-lib/aws-iam' +import Lambda from 'aws-cdk-lib/aws-lambda' +import { LambdaLogGroup } from '../resources/LambdaLogGroup.js' +import { logToCloudWatch } from '../resources/logToCloudWatch.js' +import { HTTP_MOCK_HTTP_API_STACK_NAME } from '../stacks/stackName.js' +import type { HTTPAPIMockLambdas } from './prepare-test-resources.js' /** * This is CloudFormation stack sets up a dummy HTTP API which stores all requests in SQS for inspection @@ -19,10 +16,8 @@ export class HttpApiMockStack extends CDK.Stack { parent: CDK.App, { packedHTTPAPIMockLambdas, - sourceCodeBucketName, }: { - sourceCodeBucketName: string - packedHTTPAPIMockLambdas: PackedLambdas + packedHTTPAPIMockLambdas: HTTPAPIMockLambdas }, ) { super(parent, HTTP_MOCK_HTTP_API_STACK_NAME) @@ -55,39 +50,24 @@ export class HttpApiMockStack extends CDK.Stack { timeToLiveAttribute: 'ttl', }) - const sourceCodeBucket = S3.Bucket.fromBucketAttributes( - this, - 'SourceCodeBucket', - { - bucketName: sourceCodeBucketName, - }, - ) - const lambasOnBucket = lambdasOnS3(sourceCodeBucket) - const httpAPIMockLambdaLayer = new Lambda.LayerVersion( this, `${HTTP_MOCK_HTTP_API_STACK_NAME}-cloudformation-layer`, { - code: Lambda.Code.fromBucket( - sourceCodeBucket, - packedHTTPAPIMockLambdas.layerZipFileName, - ), + code: Lambda.Code.fromAsset(packedHTTPAPIMockLambdas.layerZipFileName), compatibleRuntimes: [Lambda.Runtime.NODEJS_18_X], }, ) - const httpAPIMockLambdas = { - lambdas: lambasOnBucket(packedHTTPAPIMockLambdas), - layers: [httpAPIMockLambdaLayer], - } - // This lambda will publish all requests made to the API Gateway in the queue const lambda = new Lambda.Function(this, 'Lambda', { description: 'Mocks a HTTP API and stores all requests in SQS for inspection, and optionally replies with enqued responses', - code: httpAPIMockLambdas.lambdas.httpApiMock, - layers: httpAPIMockLambdas.layers, - handler: 'index.handler', + code: Lambda.Code.fromAsset( + packedHTTPAPIMockLambdas.lambdas.httpApiMock.zipFile, + ), + layers: [httpAPIMockLambdaLayer], + handler: packedHTTPAPIMockLambdas.lambdas.httpApiMock.handler, architecture: Lambda.Architecture.ARM_64, runtime: Lambda.Runtime.NODEJS_18_X, timeout: CDK.Duration.seconds(5), diff --git a/cdk/test-resources/api-mock-lambda.ts b/cdk/test-resources/api-mock-lambda.ts index 953fd8cd6..1a6e99dae 100644 --- a/cdk/test-resources/api-mock-lambda.ts +++ b/cdk/test-resources/api-mock-lambda.ts @@ -4,10 +4,10 @@ import { GetItemCommand, PutItemCommand, } from '@aws-sdk/client-dynamodb' -import { APIGatewayEvent, APIGatewayProxyResult } from 'aws-lambda' +import type { APIGatewayEvent, APIGatewayProxyResult } from 'aws-lambda' import { randomUUID } from 'node:crypto' -import * as querystring from 'querystring' -import { splitMockResponse } from './splitMockResponse' +import querystring from 'querystring' +import { splitMockResponse } from './splitMockResponse.js' const db = new DynamoDBClient({}) @@ -79,12 +79,12 @@ export const handler = async ( }), ) - const { body, headers } = splitMockResponse(Item.body.S ?? '') + const { body, headers } = splitMockResponse(Item.body?.S ?? '') // Send as binary, if mock response is HEX encoded. See https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings.html const isBinary = /^[0-9a-f]+$/.test(body) const res = { - statusCode: parseInt(Item.statusCode.N ?? '200', 10), + statusCode: parseInt(Item.statusCode?.N ?? '200', 10), headers: isBinary ? { ...headers, diff --git a/cdk/test-resources/prepare-test-resources.ts b/cdk/test-resources/prepare-test-resources.ts index 2228e85c4..cf9fff54d 100644 --- a/cdk/test-resources/prepare-test-resources.ts +++ b/cdk/test-resources/prepare-test-resources.ts @@ -1,64 +1,31 @@ -import { - ConsoleProgressReporter, - makeLayerFromPackageJSON, - packLayeredLambdas, -} from '@nordicsemiconductor/package-layered-lambdas' -import * as path from 'path' -import { PackedLambdas } from '../helper/lambdas/PackedLambdas' +import type { PackedLambda } from '../helper/lambdas/packLambda' +import { packLambdaFromPath } from '../helper/lambdas/packLambdaFromPath.js' +import { packLayer } from '../helper/lambdas/packLayer.js' export type HTTPAPIMockLambdas = { - httpApiMock: string + layerZipFileName: string + lambdas: { + httpApiMock: PackedLambda + } } -export const prepareHTTPAPIMockLambdas = async ({ - rootDir, - outDir, - sourceCodeBucketName, -}: { - rootDir: string - outDir: string - sourceCodeBucketName: string -}): Promise> => { - const reporter = ConsoleProgressReporter('HTTP API Mock Lambdas') - return { - layerZipFileName: await (async () => { - const httpApiMockLayerDir = path.resolve( - rootDir, - 'dist', - 'lambdas', - 'httpApiMockLayer', - ) - return makeLayerFromPackageJSON({ - layerName: 'httpApiMock-layer', - packageJsonFile: path.resolve(rootDir, 'package.json'), - packageLockJsonFile: path.resolve(rootDir, 'package-lock.json'), - requiredDependencies: [ +export const prepareHTTPAPIMockLambdas = + async (): Promise => ({ + layerZipFileName: ( + await packLayer({ + dependencies: [ '@aws-sdk/client-dynamodb', 'fast-xml-parser', // Needed by old AWS SDK 'uuid', ], - dir: httpApiMockLayerDir, - reporter, - sourceCodeBucketName, - outDir, + id: 'httpApiMock-layer', }) - })(), - lambdas: await packLayeredLambdas({ - reporter, - id: 'HTTPAPIMock', - srcDir: rootDir, - outDir, - Bucket: sourceCodeBucketName, - lambdas: { - httpApiMock: path.resolve( - rootDir, - 'cdk', - 'test-resources', - 'api-mock-lambda.ts', - ), - }, - tsConfig: path.resolve(rootDir, 'tsconfig.json'), - }), - } -} + ).layerZipFile, + lambdas: { + httpApiMock: await packLambdaFromPath( + 'httpApiMock', + 'cdk/test-resources/api-mock-lambda.ts', + ), + }, + }) diff --git a/cdk/test-resources/splitMockResponse.spec.ts b/cdk/test-resources/splitMockResponse.spec.ts index ba3c369bf..54ea6bca6 100644 --- a/cdk/test-resources/splitMockResponse.spec.ts +++ b/cdk/test-resources/splitMockResponse.spec.ts @@ -1,4 +1,4 @@ -import { splitMockResponse } from './splitMockResponse' +import { splitMockResponse } from './splitMockResponse.js' describe('split mock response', () => { it('should parse headers and body', () => diff --git a/cdk/test-resources/splitMockResponse.ts b/cdk/test-resources/splitMockResponse.ts index 361b573ea..b0c0daa98 100644 --- a/cdk/test-resources/splitMockResponse.ts +++ b/cdk/test-resources/splitMockResponse.ts @@ -12,7 +12,7 @@ export const splitMockResponse = ( .slice(0, blankLineLocation) .split('\n') .map((s) => s.split(':', 2)) - .reduce((headers, [k, v]) => ({ ...headers, [k]: v.trim() }), {}), + .reduce((headers, [k, v]) => ({ ...headers, [k ?? '']: v?.trim() }), {}), body: r.slice(blankLineLocation + 2), } } diff --git a/cellGeolocation/addCellToCacheIfNotExists.ts b/cellGeolocation/addCellToCacheIfNotExists.ts index e56684079..04159db7a 100644 --- a/cellGeolocation/addCellToCacheIfNotExists.ts +++ b/cellGeolocation/addCellToCacheIfNotExists.ts @@ -1,84 +1,73 @@ import { DynamoDBClient, PutItemCommand } from '@aws-sdk/client-dynamodb' import { cellId } from '@nordicsemiconductor/cell-geolocation-helpers' -import { pipe } from 'fp-ts/lib/function' -import * as TE from 'fp-ts/lib/TaskEither' -import { ErrorInfo, ErrorType } from '../api/ErrorInfo' -import { Cell } from '../geolocation/Cell' -import { Location } from '../geolocation/Location' -import { fromDeviceLocations } from './cellGeolocationFromDeviceLocations' +import { ErrorInfo, ErrorType } from '../api/ErrorInfo.js' +import type { Cell } from '../geolocation/Cell.js' +import type { Location } from '../geolocation/Location.js' +import { fromDeviceLocations } from './cellGeolocationFromDeviceLocations.js' export const addCellToCacheIfNotExists = ({ dynamodb, TableName }: { dynamodb: DynamoDBClient; TableName: string }) => - ({ + async ({ nw, area, mccmnc, cell, lat, lng, - }: Cell & Location): TE.TaskEither => - pipe( - TE.tryCatch( - async () => { - const cellGeolocation = fromDeviceLocations([ - { - lat, - lng, - }, - ]) - if (cellGeolocation === undefined) { - throw new Error( - `Failed to determine cell location from ${JSON.stringify({ - lat, - lng, - })}`, - ) - } - const query = { - TableName, - Item: { - cellId: { - S: cellId({ nw, area, mccmnc, cell }), - }, - lat: { - N: `${cellGeolocation.lat}`, - }, - lng: { - N: `${cellGeolocation.lng}`, - }, - accuracy: { - N: `${cellGeolocation.accuracy}`, - }, - ttl: { - N: `${Math.round(Date.now() / 1000) + 24 * 60 * 60}`, - }, - }, - ConditionExpression: 'attribute_not_exists(cellId)', - } - const res = await dynamodb.send(new PutItemCommand(query)) - console.log(JSON.stringify({ query, res })) + }: Cell & Location): Promise<{ error: ErrorInfo } | null> => { + try { + const cellGeolocation = fromDeviceLocations([ + { + lat, + lng, }, - (err) => { - if ((err as Error).name === 'ConditionalCheckFailedException') { - return { - type: ErrorType.Conflict, - message: (err as Error).message, - } - } - console.error( - JSON.stringify({ - addCellToCacheIfNotExists: { error: err, TableName }, - }), - ) - return { - type: ErrorType.InternalError, - message: (err as Error).message, - } + ]) + if (cellGeolocation === undefined) { + throw new Error( + `Failed to determine cell location from ${JSON.stringify({ + lat, + lng, + })}`, + ) + } + const query = { + TableName, + Item: { + cellId: { + S: cellId({ nw, area, mccmnc, cell }), + }, + lat: { + N: `${cellGeolocation.lat}`, + }, + lng: { + N: `${cellGeolocation.lng}`, + }, + accuracy: { + N: `${cellGeolocation.accuracy}`, + }, + ttl: { + N: `${Math.round(Date.now() / 1000) + 24 * 60 * 60}`, + }, }, - ), - TE.fold( - (e) => - e.type === ErrorType.Conflict ? TE.right(undefined) : TE.left(e), - () => TE.right(undefined), - ), - ) + ConditionExpression: 'attribute_not_exists(cellId)', + } + const res = await dynamodb.send(new PutItemCommand(query)) + console.log(JSON.stringify({ query, res })) + return null + } catch (err) { + if ((err as Error).name === 'ConditionalCheckFailedException') { + return null + } + console.error( + JSON.stringify({ + addCellToCacheIfNotExists: { error: err, TableName }, + }), + ) + return { + error: { + type: ErrorType.InternalError, + message: (err as Error).message, + }, + } + } + } diff --git a/cellGeolocation/addDeviceCellGeolocation.ts b/cellGeolocation/addDeviceCellGeolocation.ts index 8945bb972..affe01099 100644 --- a/cellGeolocation/addDeviceCellGeolocation.ts +++ b/cellGeolocation/addDeviceCellGeolocation.ts @@ -1,71 +1,55 @@ import { DynamoDBClient, PutItemCommand } from '@aws-sdk/client-dynamodb' import { cellId } from '@nordicsemiconductor/cell-geolocation-helpers' -import * as TE from 'fp-ts/lib/TaskEither' import { randomUUID } from 'node:crypto' -import { ErrorInfo, ErrorType } from '../api/ErrorInfo' -import { Cell } from '../geolocation/Cell' -import { Location } from '../geolocation/Location' +import type { Cell } from '../geolocation/Cell.js' +import type { Location } from '../geolocation/Location.js' export const addDeviceCellGeolocation = ({ dynamodb, TableName }: { dynamodb: DynamoDBClient; TableName: string }) => - ({ + async ({ cellgeolocation, source, }: { cellgeolocation: Cell & Location source: string - }): TE.TaskEither => - TE.tryCatch( - async () => { - const id = randomUUID() - await dynamodb.send( - new PutItemCommand({ - TableName, - Item: { - uuid: { - S: id, - }, - cellId: { - S: cellId(cellgeolocation), - }, - nw: { - S: `${cellgeolocation.nw}`, - }, - cell: { - N: `${cellgeolocation.cell}`, - }, - mccmnc: { - N: `${cellgeolocation.mccmnc}`, - }, - area: { - N: `${cellgeolocation.area}`, - }, - lat: { - N: `${cellgeolocation.lat}`, - }, - lng: { - N: `${cellgeolocation.lng}`, - }, - source: { - S: source, - }, - timestamp: { - S: new Date().toISOString(), - }, - }, - }), - ) - return id - }, - (err) => { - console.error( - JSON.stringify({ - addDeviceCellGeolocation: { error: err, TableName }, - }), - ) - return { - type: ErrorType.InternalError, - message: (err as Error).message, - } - }, + }): Promise => { + const id = randomUUID() + await dynamodb.send( + new PutItemCommand({ + TableName, + Item: { + uuid: { + S: id, + }, + cellId: { + S: cellId(cellgeolocation), + }, + nw: { + S: `${cellgeolocation.nw}`, + }, + cell: { + N: `${cellgeolocation.cell}`, + }, + mccmnc: { + N: `${cellgeolocation.mccmnc}`, + }, + area: { + N: `${cellgeolocation.area}`, + }, + lat: { + N: `${cellgeolocation.lat}`, + }, + lng: { + N: `${cellgeolocation.lng}`, + }, + source: { + S: source, + }, + timestamp: { + S: new Date().toISOString(), + }, + }, + }), ) + return id + } diff --git a/cellGeolocation/geolocateFromCache.ts b/cellGeolocation/geolocateFromCache.ts index 4854aca46..1fef3a887 100644 --- a/cellGeolocation/geolocateFromCache.ts +++ b/cellGeolocation/geolocateFromCache.ts @@ -1,74 +1,72 @@ import { DynamoDBClient, GetItemCommand } from '@aws-sdk/client-dynamodb' import { cellId } from '@nordicsemiconductor/cell-geolocation-helpers' -import { none, Option, some } from 'fp-ts/lib/Option' -import * as TE from 'fp-ts/lib/TaskEither' -import { ErrorInfo, ErrorType } from '../api/ErrorInfo' -import { Cell } from '../geolocation/Cell' -import { Location } from '../geolocation/Location' +import { ErrorInfo, ErrorType } from '../api/ErrorInfo.js' +import type { Cell } from '../geolocation/Cell.js' +import type { Location } from '../geolocation/Location.js' export const geolocateFromCache = ({ dynamodb, TableName }: { dynamodb: DynamoDBClient; TableName: string }) => - ( + async ( cell: Cell, - ): TE.TaskEither< - ErrorInfo, - Option<{ unresolved: boolean } & Partial> - > => - TE.tryCatch( - async () => { - const { Item } = await dynamodb.send( - new GetItemCommand({ - TableName, - Key: { - cellId: { - S: cellId(cell), - }, + ): Promise< + { error: ErrorInfo } | ({ unresolved: boolean } & Partial) + > => { + try { + const { Item } = await dynamodb.send( + new GetItemCommand({ + TableName, + Key: { + cellId: { + S: cellId(cell), }, - ProjectionExpression: 'nw,lat,lng,accuracy,unresolved', - }), - ) - if (Item) { - const unresolved = Item.unresolved?.BOOL ?? false - if (unresolved) { - return some({ - unresolved, - }) - } else { - return some({ - unresolved, - lat: parseFloat(Item.lat.N as string), - lng: parseFloat(Item.lng.N as string), - accuracy: - Item?.accuracy?.N !== undefined - ? parseFloat(Item.accuracy.N) - : 5000, - }) + }, + ProjectionExpression: 'nw,lat,lng,accuracy,unresolved', + }), + ) + if (Item) { + const unresolved = Item.unresolved?.BOOL ?? false + if (unresolved) { + return { + unresolved, } - } - - return none - }, - (err) => { - if ( - (err as Error).message === 'NOT_FOUND' || - (err as Error).name === 'ResourceNotFoundException' - ) + } else { return { - type: ErrorType.EntityNotFound, - message: `Cell ${cellId(cell)} not found!`, + unresolved, + lat: parseFloat(Item?.lat?.N as string), + lng: parseFloat(Item?.lng?.N as string), + accuracy: + Item?.accuracy?.N !== undefined + ? parseFloat(Item.accuracy.N) + : 5000, } - console.error( - JSON.stringify({ - geolocateFromCache: { - err, - cell, - TableName, - }, - }), - ) + } + } + throw new Error('NOT_FOUND') + } catch (err) { + if ( + (err as Error).message === 'NOT_FOUND' || + (err as Error).name === 'ResourceNotFoundException' + ) return { + error: { + type: ErrorType.EntityNotFound, + message: `Cell ${cellId(cell)} not found!`, + }, + } + console.error( + JSON.stringify({ + geolocateFromCache: { + err, + cell, + TableName, + }, + }), + ) + return { + error: { type: ErrorType.InternalError, message: (err as Error).message, - } - }, - ) + }, + } + } + } diff --git a/cellGeolocation/httpApi/addCellGeolocation.ts b/cellGeolocation/httpApi/addCellGeolocation.ts index 499a96528..d46a2cf27 100644 --- a/cellGeolocation/httpApi/addCellGeolocation.ts +++ b/cellGeolocation/httpApi/addCellGeolocation.ts @@ -1,20 +1,17 @@ import { DynamoDBClient } from '@aws-sdk/client-dynamodb' +import { validateWithType } from '@nordicsemiconductor/asset-tracker-cloud-docs/protocol' import { NetworkMode } from '@nordicsemiconductor/cell-geolocation-helpers' import { Type } from '@sinclair/typebox' -import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda' -import { sequenceT } from 'fp-ts/lib/Apply' -import * as E from 'fp-ts/lib/Either' -import { pipe } from 'fp-ts/lib/function' -import * as JSON from 'fp-ts/lib/Json' -import * as TE from 'fp-ts/lib/TaskEither' -import { ErrorInfo, ErrorType, toStatusCode } from '../../api/ErrorInfo' -import { resFP } from '../../api/resFP' -import { validateWithJSONSchemaFP } from '../../api/validateWithJSONSchemaFP' -import { Cell } from '../../geolocation/Cell' -import { Location } from '../../geolocation/Location' -import { fromEnv } from '../../util/fromEnv' -import { addCellToCacheIfNotExists } from '../addCellToCacheIfNotExists' -import { addDeviceCellGeolocation } from '../addDeviceCellGeolocation' +import type { + APIGatewayProxyEventV2, + APIGatewayProxyResultV2, +} from 'aws-lambda' +import { ErrorType, toStatusCode } from '../../api/ErrorInfo.js' +import { res } from '../../api/res.js' +import { fromEnv } from '../../util/fromEnv.js' +import { parseJSON } from '../../util/parseJSON.js' +import { addCellToCacheIfNotExists } from '../addCellToCacheIfNotExists.js' +import { addDeviceCellGeolocation } from '../addDeviceCellGeolocation.js' const { deviceCellGeolocationTable, cacheTable } = fromEnv({ deviceCellGeolocationTable: 'DEVICE_CELL_GEOLOCATION_TABLE', @@ -61,60 +58,52 @@ const cellGeolocationInputSchema = Type.Object( { additionalProperties: false }, ) -const validateInput = validateWithJSONSchemaFP(cellGeolocationInputSchema) +const validateInput = validateWithType(cellGeolocationInputSchema) const toIntOr0 = (v?: any) => parseInt(v ?? '0', 10) const toFloatOr0 = (v?: any) => parseFloat(v ?? '0') export const handler = async ( - event: APIGatewayProxyEvent, -): Promise => { + event: APIGatewayProxyEventV2, +): Promise => { console.log(JSON.stringify(event)) - return pipe( - JSON.parse(event?.body ?? ''), - E.mapLeft(() => ({ - message: `Failed to parse body "${event.body}"!`, + + const maybeJSON = parseJSON(event?.body ?? '') + if ('error' in maybeJSON) + return res(toStatusCode[ErrorType.BadRequest])(maybeJSON.error) + + const b = maybeJSON.json + + const maybeCellGeolocation = validateInput({ + cell: toIntOr0(b.cell), + area: toIntOr0(b.area), + mccmnc: toIntOr0(b.mccmnc), + lat: toFloatOr0(b.lat), + lng: toFloatOr0(b.lng), + accuracy: toFloatOr0(b.accuracy), + nw: b.nw, + }) + if ('errors' in maybeCellGeolocation) { + return res(toStatusCode[ErrorType.BadRequest])(maybeCellGeolocation.errors) + } + const cellgeolocation = maybeCellGeolocation + + if (cellgeolocation.lat === 0 && cellgeolocation.lng === 0) + return res(toStatusCode[ErrorType.BadRequest])({ + message: `Both lat and lng are 0, ignoring. This is probably bogus test data.`, type: ErrorType.BadRequest, - })), - E.map((body) => { - const b = body as any - return validateInput({ - cell: toIntOr0(b.cell), - area: toIntOr0(b.area), - mccmnc: toIntOr0(b.mccmnc), - lat: toFloatOr0(b.lat), - lng: toFloatOr0(b.lng), - accuracy: toFloatOr0(b.accuracy), - nw: b.nw, - }) - }), - E.flatten, - E.map((cellgeolocation) => { - if (cellgeolocation.lat === 0 && cellgeolocation.lng === 0) - return E.left({ - message: `Both lat and lng are 0, ignoring. This is probably bogus test data.`, - type: ErrorType.BadRequest, - }) - return E.right(cellgeolocation) - }), - E.flatten, - TE.fromEither, - TE.map((cellgeolocation) => - sequenceT(TE.taskEither)( - // Persist cell geo locations - persistDeviceCellGeolocation({ - cellgeolocation, - source: `api:${event.requestContext.identity.sourceIp}:${event.requestContext.identity.userAgent}`, - }), - // If this is the first time we see this cell, make it available in the cache - addToCellGeolocation(cellgeolocation), - ), - ), - TE.flatten, - TE.map(([id]) => id), - TE.fold( - (error) => resFP(toStatusCode[(error as ErrorInfo).type])(error), - resFP(202), - ), - )() + }) + + // Persist cell geo locations + const id = await persistDeviceCellGeolocation({ + cellgeolocation, + source: `api:${event.requestContext.http.sourceIp}:${event.requestContext.http.userAgent}`, + }) + // If this is the first time we see this cell, make it available in the cache + const maybeAdded = await addToCellGeolocation(cellgeolocation) + if (maybeAdded !== null && 'error' in maybeAdded) { + return res(toStatusCode[maybeAdded.error.type])(maybeAdded.error) + } + + return res(202)(id) } diff --git a/cellGeolocation/httpApi/cell.ts b/cellGeolocation/httpApi/cell.ts index 9e2be59a9..43cf51542 100644 --- a/cellGeolocation/httpApi/cell.ts +++ b/cellGeolocation/httpApi/cell.ts @@ -1,20 +1,20 @@ import { DynamoDBClient } from '@aws-sdk/client-dynamodb' import { SQSClient } from '@aws-sdk/client-sqs' +import { validateWithType } from '@nordicsemiconductor/asset-tracker-cloud-docs/protocol' import { cellId, NetworkMode, } from '@nordicsemiconductor/cell-geolocation-helpers' import { Type } from '@sinclair/typebox' -import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda' -import { pipe } from 'fp-ts/lib/pipeable' -import * as TE from 'fp-ts/lib/TaskEither' -import { ErrorType, toStatusCode } from '../../api/ErrorInfo' -import { resFP } from '../../api/resFP' -import { validateWithJSONSchemaFP } from '../../api/validateWithJSONSchemaFP' -import { queueJobFP } from '../../geolocation/queueJobFP' -import { getOrElse } from '../../util/fp-ts' -import { fromEnv } from '../../util/fromEnv' -import { geolocateFromCache } from '../geolocateFromCache' +import type { + APIGatewayProxyEventV2, + APIGatewayProxyResultV2, +} from 'aws-lambda' +import { ErrorType, toStatusCode } from '../../api/ErrorInfo.js' +import { res } from '../../api/res.js' +import { queueJob } from '../../geolocation/queueJob.js' +import { fromEnv } from '../../util/fromEnv.js' +import { geolocateFromCache } from '../geolocateFromCache.js' const { cellGeolocationResolutionJobsQueue, cacheTable } = fromEnv({ cellGeolocationResolutionJobsQueue: 'CELL_GEOLOCATION_RESOLUTION_JOBS_QUEUE', @@ -26,7 +26,7 @@ const locator = geolocateFromCache({ TableName: cacheTable, }) -const q = queueJobFP({ +const q = queueJob({ QueueUrl: cellGeolocationResolutionJobsQueue, sqs: new SQSClient({}), }) @@ -55,7 +55,7 @@ const cellInputSchema = Type.Object( console.log(JSON.stringify(cellInputSchema, null, 2)) -const validateInput = validateWithJSONSchemaFP(cellInputSchema) +const validateInput = validateWithType(cellInputSchema) const allMembersToInt = (o: Record): Record => Object.entries(o).reduce( @@ -64,56 +64,49 @@ const allMembersToInt = (o: Record): Record => ) export const handler = async ( - event: APIGatewayProxyEvent, -): Promise => { + event: APIGatewayProxyEventV2, +): Promise => { console.log(JSON.stringify(event)) - return pipe( - validateInput({ - ...allMembersToInt(event.queryStringParameters ?? {}), - nw: event?.queryStringParameters?.nw ?? '', - }), - TE.fromEither, - TE.chain((cell) => - pipe( - locator(cell), - getOrElse.TE(() => - pipe( - q({ payload: cell, deduplicationId: cellId(cell) }), - TE.fold( - (err) => TE.left(err), - () => - TE.left({ - type: ErrorType.Conflict, - message: 'Calculation for cell geolocation in process', - }), - ), - ), - ), - ), - ), - TE.fold( - (error) => - resFP(toStatusCode[error.type], { - expires: 60, - })(error), - (cell) => { - if (cell.unresolved) { - return resFP(toStatusCode[ErrorType.EntityNotFound], { - expires: 86400, - })({ - type: ErrorType.EntityNotFound, - message: `cell geolocation not found!`, - }) - } - return resFP(200, { - expires: 86400, - })({ - lat: cell.lat, - lng: cell.lng, - accuracy: cell.accuracy, - }) - }, - ), - )() + const maybeValidInput = validateInput({ + ...allMembersToInt(event.queryStringParameters ?? {}), + nw: event?.queryStringParameters?.nw ?? '', + }) + if ('errors' in maybeValidInput) { + return res(toStatusCode[ErrorType.BadRequest])(maybeValidInput.errors) + } + const cell = await locator(maybeValidInput) + + if ('error' in cell) { + const scheduled = await q({ + payload: maybeValidInput, + deduplicationId: cellId(maybeValidInput), + }) + if (scheduled !== undefined && 'error' in scheduled) { + return res(toStatusCode[scheduled.error.type], { + expires: 60, + })(scheduled.error) + } + return res(toStatusCode[ErrorType.Conflict], { + expires: 60, + })({ + type: ErrorType.Conflict, + message: 'Calculation for cell geolocation in process', + }) + } + if (cell.unresolved) { + return res(toStatusCode[ErrorType.EntityNotFound], { + expires: 86400, + })({ + type: ErrorType.EntityNotFound, + message: `cell geolocation not found!`, + }) + } + return res(200, { + expires: 86400, + })({ + lat: cell.lat, + lng: cell.lng, + accuracy: cell.accuracy, + }) } diff --git a/cellGeolocation/lambda/invokeStepFunctionFromSQS.ts b/cellGeolocation/lambda/invokeStepFunctionFromSQS.ts index 42e5de23c..dcb3c00fc 100644 --- a/cellGeolocation/lambda/invokeStepFunctionFromSQS.ts +++ b/cellGeolocation/lambda/invokeStepFunctionFromSQS.ts @@ -1,6 +1,6 @@ import { SFNClient, StartExecutionCommand } from '@aws-sdk/client-sfn' -import { SQSEvent } from 'aws-lambda' -import { fromEnv } from '../../util/fromEnv' +import type { SQSEvent } from 'aws-lambda' +import { fromEnv } from '../../util/fromEnv.js' const sf = new SFNClient({}) const { stateMachineArn } = fromEnv({ diff --git a/cellGeolocation/stepFunction/fromCache.ts b/cellGeolocation/stepFunction/fromCache.ts index 2bbc1c06e..b734f70f2 100644 --- a/cellGeolocation/stepFunction/fromCache.ts +++ b/cellGeolocation/stepFunction/fromCache.ts @@ -1,12 +1,8 @@ import { DynamoDBClient } from '@aws-sdk/client-dynamodb' -import { isSome } from 'fp-ts/lib/Option' -import { pipe } from 'fp-ts/lib/pipeable' -import * as T from 'fp-ts/lib/Task' -import * as TE from 'fp-ts/lib/TaskEither' -import { Cell } from '../../geolocation/Cell' -import { fromEnv } from '../../util/fromEnv' -import { geolocateFromCache } from '../geolocateFromCache' -import { MaybeCellGeoLocation } from './types' +import type { Cell } from '../../geolocation/Cell.js' +import { fromEnv } from '../../util/fromEnv.js' +import { geolocateFromCache } from '../geolocateFromCache.js' +import type { MaybeCellGeoLocation } from './types.js' const { cacheTable } = fromEnv({ cacheTable: 'CACHE_TABLE', @@ -17,21 +13,11 @@ const locator = geolocateFromCache({ TableName: cacheTable, }) -export const handler = async (input: Cell): Promise => - pipe( - locator(input), - TE.map((optionalLocation) => { - if (isSome(optionalLocation)) { - return { - located: true, - ...optionalLocation.value, - } - } - return { located: false } - }), - TE.getOrElse(() => - T.of({ - located: false, - }), - ), - )() +export const handler = async (input: Cell): Promise => { + const optionalLocation = await locator(input) + if ('error' in optionalLocation) return { located: false } + return { + located: true, + ...optionalLocation, + } +} diff --git a/cellGeolocation/stepFunction/fromDeviceLocations.ts b/cellGeolocation/stepFunction/fromDeviceLocations.ts index 25e5cb567..a2ff60b4a 100644 --- a/cellGeolocation/stepFunction/fromDeviceLocations.ts +++ b/cellGeolocation/stepFunction/fromDeviceLocations.ts @@ -1,9 +1,9 @@ import { DynamoDBClient, QueryCommand } from '@aws-sdk/client-dynamodb' import { cellId } from '@nordicsemiconductor/cell-geolocation-helpers' -import { Cell } from '../../geolocation/Cell' -import { fromEnv } from '../../util/fromEnv' -import { fromDeviceLocations } from '../cellGeolocationFromDeviceLocations' -import { MaybeCellGeoLocation } from './types' +import type { Cell } from '../../geolocation/Cell.js' +import { fromEnv } from '../../util/fromEnv.js' +import { fromDeviceLocations } from '../cellGeolocationFromDeviceLocations.js' +import type { MaybeCellGeoLocation } from './types.js' const { TableName, IndexName } = fromEnv({ TableName: 'LOCATIONS_TABLE', @@ -29,8 +29,8 @@ export const handler = async (cell: Cell): Promise => { if (Items !== undefined && (Items?.length ?? 0) > 0) { const location = fromDeviceLocations( Items.map(({ lat, lng }) => ({ - lat: parseFloat(lat.N as string), - lng: parseFloat(lng.N as string), + lat: parseFloat(lat?.N as string), + lng: parseFloat(lng?.N as string), })), ) diff --git a/cellGeolocation/stepFunction/types.ts b/cellGeolocation/stepFunction/types.ts index 7ef263040..686a0b839 100644 --- a/cellGeolocation/stepFunction/types.ts +++ b/cellGeolocation/stepFunction/types.ts @@ -1,4 +1,4 @@ -import { Location } from '../../geolocation/Location' +import type { Location } from '../../geolocation/Location.js' export type MaybeCellGeoLocation = { located: boolean diff --git a/cellGeolocation/stepFunction/updateCache.ts b/cellGeolocation/stepFunction/updateCache.ts index 41bd79f1f..ef84f2d25 100644 --- a/cellGeolocation/stepFunction/updateCache.ts +++ b/cellGeolocation/stepFunction/updateCache.ts @@ -1,8 +1,8 @@ import { DynamoDBClient, PutItemCommand } from '@aws-sdk/client-dynamodb' import { cellId } from '@nordicsemiconductor/cell-geolocation-helpers' -import { Cell } from '../../geolocation/Cell' -import { fromEnv } from '../../util/fromEnv' -import { MaybeCellGeoLocation } from './types' +import type { Cell } from '../../geolocation/Cell.js' +import { fromEnv } from '../../util/fromEnv.js' +import type { MaybeCellGeoLocation } from './types.js' const { TableName } = fromEnv({ TableName: 'CACHE_TABLE', diff --git a/cli/cd/listPipelines.ts b/cli/cd/listPipelines.ts index ea3477f28..41a5c191e 100644 --- a/cli/cd/listPipelines.ts +++ b/cli/cd/listPipelines.ts @@ -1,10 +1,10 @@ import { CloudFormationClient } from '@aws-sdk/client-cloudformation' import { stackOutput } from '@nordicsemiconductor/cloudformation-helpers' -import { StackOutputs } from '../../cdk/stacks/ContinuousDeployment' +import type { StackOutputs } from '../../cdk/stacks/ContinuousDeployment.js' import { CONTINUOUS_DEPLOYMENT_STACK_NAME, CORE_STACK_NAME, -} from '../../cdk/stacks/stackName' +} from '../../cdk/stacks/stackName.js' /** * Returns the active pipelines of the CD stack diff --git a/cli/cli.ts b/cli/cli.ts index d9146aa33..ba2e366b7 100644 --- a/cli/cli.ts +++ b/cli/cli.ts @@ -2,30 +2,30 @@ import { IoTClient } from '@aws-sdk/client-iot' import { GetCallerIdentityCommand, STSClient } from '@aws-sdk/client-sts' import chalk from 'chalk' import { program } from 'commander' -import * as fs from 'fs' -import * as path from 'path' +import fs from 'fs' +import path from 'path' import { createInterface } from 'readline' -import { getIotEndpoint } from '../cdk/helper/getIotEndpoint' -import { cdCommand } from './commands/cd' -import { cdUpdateTokenCommand } from './commands/cd-update-token' -import { CommandDefinition } from './commands/CommandDefinition' -import { configureCommand } from './commands/configure' -import { createAndProvisionDeviceCertCommand } from './commands/create-and-provision-device-cert' -import { createCACommand } from './commands/create-ca' -import { createSimulatorCertCommand } from './commands/create-simulator-cert' -import { firmwareCICommand } from './commands/firmware-ci' -import { flashFirmwareCommand } from './commands/flash-firmware' -import { imeiCommand } from './commands/imei' -import { infoCommand } from './commands/info' -import { logsCommand } from './commands/logs' -import { purgeBucketsCommand } from './commands/purge-buckets' -import { purgeCAsCommand } from './commands/purge-cas' -import { purgeIotUserPolicyPrincipals } from './commands/purge-iot-user-policy-principals' -import { registerCACommand } from './commands/register-ca' -import { showAPIConfigurationCommand } from './commands/show-api-configuration' -import { webappCICommand } from './commands/web-app-ci' -import { webAppConfigCommand } from './commands/web-app-config' -import { certsDir as provideCertsDir } from './jitp/certsDir' +import { getIotEndpoint } from '../cdk/helper/getIotEndpoint.js' +import { cdUpdateTokenCommand } from './commands/cd-update-token.js' +import { cdCommand } from './commands/cd.js' +import type { CommandDefinition } from './commands/CommandDefinition.js' +import { configureCommand } from './commands/configure.js' +import { createAndProvisionDeviceCertCommand } from './commands/create-and-provision-device-cert.js' +import { createCACommand } from './commands/create-ca.js' +import { createSimulatorCertCommand } from './commands/create-simulator-cert.js' +import { firmwareCICommand } from './commands/firmware-ci.js' +import { flashFirmwareCommand } from './commands/flash-firmware.js' +import { imeiCommand } from './commands/imei.js' +import { infoCommand } from './commands/info.js' +import { logsCommand } from './commands/logs.js' +import { purgeBucketsCommand } from './commands/purge-buckets.js' +import { purgeCAsCommand } from './commands/purge-cas.js' +import { purgeIotUserPolicyPrincipals } from './commands/purge-iot-user-policy-principals.js' +import { registerCACommand } from './commands/register-ca.js' +import { showAPIConfigurationCommand } from './commands/show-api-configuration.js' +import { webappCICommand } from './commands/web-app-ci.js' +import { webAppConfigCommand } from './commands/web-app-config.js' +import { certsDir as provideCertsDir } from './jitp/certsDir.js' const die = (err: Error, origin: any) => { console.error(`An unhandled exception occured!`) diff --git a/cli/commands/cd-update-token.ts b/cli/commands/cd-update-token.ts index 3a29ad835..8db72bd10 100644 --- a/cli/commands/cd-update-token.ts +++ b/cli/commands/cd-update-token.ts @@ -5,10 +5,10 @@ import { } from '@aws-sdk/client-codepipeline' import { SSMClient } from '@aws-sdk/client-ssm' import chalk from 'chalk' -import { CORE_STACK_NAME } from '../../cdk/stacks/stackName' -import { putSettings } from '../../util/settings' -import { listPipelines } from '../cd/listPipelines' -import { CommandDefinition } from './CommandDefinition' +import { CORE_STACK_NAME } from '../../cdk/stacks/stackName.js' +import { putSettings } from '../../util/settings.js' +import { listPipelines } from '../cd/listPipelines.js' +import type { CommandDefinition } from './CommandDefinition.js' export const cdUpdateTokenCommand = (): CommandDefinition => ({ command: 'cd-update-token ', diff --git a/cli/commands/cd.ts b/cli/commands/cd.ts index 33c7370a5..a5b250e74 100644 --- a/cli/commands/cd.ts +++ b/cli/commands/cd.ts @@ -4,8 +4,8 @@ import { } from '@aws-sdk/client-codepipeline' import chalk from 'chalk' import { formatDistanceToNow } from 'date-fns' -import { listPipelines } from '../cd/listPipelines' -import { CommandDefinition } from './CommandDefinition' +import { listPipelines } from '../cd/listPipelines.js' +import type { CommandDefinition } from './CommandDefinition.js' export const cdCommand = (): CommandDefinition => ({ command: 'cd', diff --git a/cli/commands/configure.ts b/cli/commands/configure.ts index 4cb5b148a..d274f45c3 100644 --- a/cli/commands/configure.ts +++ b/cli/commands/configure.ts @@ -1,9 +1,9 @@ import { SSMClient } from '@aws-sdk/client-ssm' import chalk from 'chalk' -import * as fs from 'fs' -import { CORE_STACK_NAME } from '../../cdk/stacks/stackName' -import { deleteSettings, putSettings } from '../../util/settings' -import { CommandDefinition } from './CommandDefinition' +import fs from 'fs' +import { CORE_STACK_NAME } from '../../cdk/stacks/stackName.js' +import { deleteSettings, putSettings } from '../../util/settings.js' +import type { CommandDefinition } from './CommandDefinition.js' export const configureCommand = (): CommandDefinition => ({ command: 'configure [value]', diff --git a/cli/commands/create-and-provision-device-cert.ts b/cli/commands/create-and-provision-device-cert.ts index 79561ce35..0f94d6689 100644 --- a/cli/commands/create-and-provision-device-cert.ts +++ b/cli/commands/create-and-provision-device-cert.ts @@ -8,17 +8,17 @@ import { } from '@nordicsemiconductor/firmware-ci-device-helpers' import chalk from 'chalk' import { promises as fs } from 'fs' -import * as os from 'os' -import * as path from 'path' +import os from 'os' +import path from 'path' import { createDeviceCertificate, defaultDeviceCertificateValidityInDays, -} from '../jitp/createDeviceCertificate' -import { getCurrentCA } from '../jitp/currentCA' -import { deviceFileLocations } from '../jitp/deviceFileLocations' -import { readlineDevice } from '../jitp/readlineDevice' -import { run } from '../process/run' -import { CommandDefinition } from './CommandDefinition' +} from '../jitp/createDeviceCertificate.js' +import { getCurrentCA } from '../jitp/currentCA.js' +import { deviceFileLocations } from '../jitp/deviceFileLocations.js' +import { readlineDevice } from '../jitp/readlineDevice.js' +import { run } from '../process/run.js' +import type { CommandDefinition } from './CommandDefinition.js' export const defaultPort = '/dev/ttyACM0' export const defaultSecTag = 42 diff --git a/cli/commands/create-ca.ts b/cli/commands/create-ca.ts index 710b2ee15..d3c4fc52f 100644 --- a/cli/commands/create-ca.ts +++ b/cli/commands/create-ca.ts @@ -1,10 +1,10 @@ import { CloudFormationClient } from '@aws-sdk/client-cloudformation' import { IoTClient } from '@aws-sdk/client-iot' import chalk from 'chalk' -import { CORE_STACK_NAME } from '../../cdk/stacks/stackName' -import { createCA, defaultCAValidityInDays } from '../jitp/createCA' -import { setCurrentCA } from '../jitp/currentCA' -import { CommandDefinition } from './CommandDefinition' +import { CORE_STACK_NAME } from '../../cdk/stacks/stackName.js' +import { createCA, defaultCAValidityInDays } from '../jitp/createCA.js' +import { setCurrentCA } from '../jitp/currentCA.js' +import type { CommandDefinition } from './CommandDefinition.js' export const createCACommand = ({ certsDir, @@ -49,7 +49,7 @@ export const createCACommand = ({ ) console.log( chalk.green('You can now generate device certificates.'), - chalk.greenBright('./cli.sh create-and-provision-device-cert'), + chalk.greenBright('./cli.sh create-and-provision-device-cert.js'), ) setCurrentCA({ certsDir, caId: certificateId }) }, diff --git a/cli/commands/create-simulator-cert.ts b/cli/commands/create-simulator-cert.ts index 4818c120f..c0cd4088f 100644 --- a/cli/commands/create-simulator-cert.ts +++ b/cli/commands/create-simulator-cert.ts @@ -1,15 +1,15 @@ import { randomWords } from '@nordicsemiconductor/random-words' import chalk from 'chalk' import { promises as fs } from 'fs' -import * as path from 'path' +import path from 'path' import { createDeviceCertificate, defaultDeviceCertificateValidityInDays, -} from '../jitp/createDeviceCertificate' -import { createSimulatorKeyAndCSR } from '../jitp/createSimulatorKeyAndCSR' -import { getCurrentCA } from '../jitp/currentCA' -import { deviceFileLocations } from '../jitp/deviceFileLocations' -import { CommandDefinition } from './CommandDefinition' +} from '../jitp/createDeviceCertificate.js' +import { createSimulatorKeyAndCSR } from '../jitp/createSimulatorKeyAndCSR.js' +import { getCurrentCA } from '../jitp/currentCA.js' +import { deviceFileLocations } from '../jitp/deviceFileLocations.js' +import type { CommandDefinition } from './CommandDefinition.js' export const createSimulatorCertCommand = ({ endpoint, diff --git a/cli/commands/firmware-ci.ts b/cli/commands/firmware-ci.ts index 5a5b9e98b..89f105534 100644 --- a/cli/commands/firmware-ci.ts +++ b/cli/commands/firmware-ci.ts @@ -1,9 +1,9 @@ import { CloudFormationClient } from '@aws-sdk/client-cloudformation' import { stackOutput } from '@nordicsemiconductor/cloudformation-helpers' import chalk from 'chalk' -import { StackOutputs as FirmwareCIStackOutputs } from '../../cdk/stacks/FirmwareCI' -import { FIRMWARE_CI_STACK_NAME } from '../../cdk/stacks/stackName' -import { CommandDefinition } from './CommandDefinition' +import type { StackOutputs as FirmwareCIStackOutputs } from '../../cdk/stacks/FirmwareCI.js' +import { FIRMWARE_CI_STACK_NAME } from '../../cdk/stacks/stackName.js' +import type { CommandDefinition } from './CommandDefinition.js' export const firmwareCICommand = ({ endpoint, diff --git a/cli/commands/flash-firmware.ts b/cli/commands/flash-firmware.ts index 1c51d7b94..f3a802b1b 100644 --- a/cli/commands/flash-firmware.ts +++ b/cli/commands/flash-firmware.ts @@ -1,17 +1,17 @@ import { flash } from '@nordicsemiconductor/firmware-ci-device-helpers' import { Octokit } from '@octokit/rest' import chalk from 'chalk' -import * as fs from 'fs' -import * as https from 'https' +import fs from 'fs' +import https from 'https' import { randomUUID } from 'node:crypto' -import * as os from 'os' -import * as path from 'path' -import { extractRepoAndOwner } from '../../cdk/helper/extract-repo-and-owner' -import { CommandDefinition } from './CommandDefinition' +import os from 'os' +import path from 'path' +import { extractRepoAndOwner } from '../../cdk/helper/extract-repo-and-owner.js' +import type { CommandDefinition } from './CommandDefinition.js' export const defaultFirmwareRepository = 'https://github.com/NordicSemiconductor/asset-tracker-cloud-firmware-aws' -const netrclocation = path.resolve(os.homedir(), '.netrc') +const netrclocation = path.resolve(os.homedir(), '.netrc.js') type FWVariant = 'memfault' | 'debug' | 'nodebug' @@ -41,12 +41,12 @@ const getLatestFirmware = async ({ await octokit.repos.listReleaseAssets({ owner, repo, - release_id: latestRelease.id, + release_id: latestRelease?.id as number, }) ).data const hexfile = assets.find(({ name }) => { - if (!name.includes('.hex')) return false + if (!name.includes('.hex.js')) return false if (name.includes('-signed')) return false if (!name.includes(dk ? 'nRF9160DK' : 'Thingy91')) return false switch (variant) { diff --git a/cli/commands/imei.ts b/cli/commands/imei.ts index 7e06ea772..5d2ea7ac9 100644 --- a/cli/commands/imei.ts +++ b/cli/commands/imei.ts @@ -4,8 +4,8 @@ import { getIMEI, } from '@nordicsemiconductor/firmware-ci-device-helpers' import chalk from 'chalk' -import { CommandDefinition } from './CommandDefinition' -import { defaultPort } from './create-and-provision-device-cert' +import type { CommandDefinition } from './CommandDefinition.js' +import { defaultPort } from './create-and-provision-device-cert.js' export const imeiCommand = (): CommandDefinition => ({ command: 'imei', diff --git a/cli/commands/info.ts b/cli/commands/info.ts index 3db05c3bc..6d23960e1 100644 --- a/cli/commands/info.ts +++ b/cli/commands/info.ts @@ -2,9 +2,9 @@ import { CloudFormationClient } from '@aws-sdk/client-cloudformation' import { IoTClient } from '@aws-sdk/client-iot' import { stackOutput } from '@nordicsemiconductor/cloudformation-helpers' import chalk from 'chalk' -import { getIotEndpoint } from '../../cdk/helper/getIotEndpoint' -import { CORE_STACK_NAME } from '../../cdk/stacks/stackName' -import { CommandDefinition } from './CommandDefinition' +import { getIotEndpoint } from '../../cdk/helper/getIotEndpoint.js' +import { CORE_STACK_NAME } from '../../cdk/stacks/stackName.js' +import type { CommandDefinition } from './CommandDefinition.js' export const infoCommand = (): CommandDefinition => ({ command: 'info', @@ -23,7 +23,7 @@ export const infoCommand = (): CommandDefinition => ({ if (outputs[output] === undefined) { throw new Error(`${output} is not defined.`) } - process.stdout.write(outputs[output]) + process.stdout.write(outputs[output] ?? '') return } Object.entries(outputs).forEach(([k, v]) => { diff --git a/cli/commands/logs.ts b/cli/commands/logs.ts index 7f643ee4d..b32ef5300 100644 --- a/cli/commands/logs.ts +++ b/cli/commands/logs.ts @@ -8,8 +8,8 @@ import { GetLogEventsCommand, } from '@aws-sdk/client-cloudwatch-logs' import chalk from 'chalk' -import { CORE_STACK_NAME } from '../../cdk/stacks/stackName' -import { CommandDefinition } from './CommandDefinition' +import { CORE_STACK_NAME } from '../../cdk/stacks/stackName.js' +import type { CommandDefinition } from './CommandDefinition.js' export const logsCommand = (): CommandDefinition => ({ command: 'logs', diff --git a/cli/commands/purge-buckets.ts b/cli/commands/purge-buckets.ts index 007f01350..05027025b 100644 --- a/cli/commands/purge-buckets.ts +++ b/cli/commands/purge-buckets.ts @@ -14,10 +14,10 @@ import { CORE_STACK_NAME, FIRMWARE_CI_STACK_NAME, WEBAPP_STACK_NAME, -} from '../../cdk/stacks/stackName' -import { paginate } from '../../util/paginate' -import { CommandDefinition } from './CommandDefinition' -import { retry } from './retry' +} from '../../cdk/stacks/stackName.js' +import { paginate } from '../../util/paginate.js' +import type { CommandDefinition } from './CommandDefinition.js' +import { retry } from './retry.js' const cf = new CloudFormationClient({}) diff --git a/cli/commands/purge-cas.ts b/cli/commands/purge-cas.ts index 93af7b841..c205ceaa6 100644 --- a/cli/commands/purge-cas.ts +++ b/cli/commands/purge-cas.ts @@ -7,10 +7,10 @@ import { } from '@aws-sdk/client-iot' import { stackOutput } from '@nordicsemiconductor/cloudformation-helpers' import chalk from 'chalk' -import { CORE_STACK_NAME } from '../../cdk/stacks/stackName' -import { getCurrentCA } from '../jitp/currentCA' -import { listRegisteredCAs } from '../jitp/listRegisteredCAs' -import { CommandDefinition } from './CommandDefinition' +import { CORE_STACK_NAME } from '../../cdk/stacks/stackName.js' +import { getCurrentCA } from '../jitp/currentCA.js' +import { listRegisteredCAs } from '../jitp/listRegisteredCAs.js' +import type { CommandDefinition } from './CommandDefinition.js' const purgeCACertificate = ({ iot, thingGroupName }: { iot: IoTClient; thingGroupName: string }) => @@ -70,7 +70,10 @@ export const purgeCAsCommand = ({ ...(await stackOutput(new CloudFormationClient({}))(CORE_STACK_NAME)), } as { [key: string]: string } - const purge = purgeCACertificate({ iot, thingGroupName }) + const purge = purgeCACertificate({ + iot, + thingGroupName: thingGroupName as string, + }) if (caId !== undefined) return purge(caId) if (current === true) return purge(getCurrentCA({ certsDir })) diff --git a/cli/commands/purge-iot-user-policy-principals.ts b/cli/commands/purge-iot-user-policy-principals.ts index cd9514c8b..b3a6ca24e 100644 --- a/cli/commands/purge-iot-user-policy-principals.ts +++ b/cli/commands/purge-iot-user-policy-principals.ts @@ -5,9 +5,9 @@ import { ListTargetsForPolicyCommand, } from '@aws-sdk/client-iot' import { stackOutput } from '@nordicsemiconductor/cloudformation-helpers' -import { CORE_STACK_NAME } from '../../cdk/stacks/stackName' -import { paginate } from '../../util/paginate' -import { CommandDefinition } from './CommandDefinition' +import { CORE_STACK_NAME } from '../../cdk/stacks/stackName.js' +import { paginate } from '../../util/paginate.js' +import type { CommandDefinition } from './CommandDefinition.js' export const purgeIotUserPolicyPrincipals = (): CommandDefinition => ({ command: 'purge-iot-user-policy-principals', diff --git a/cli/commands/register-ca.ts b/cli/commands/register-ca.ts index 4a5d8b744..619d06db0 100644 --- a/cli/commands/register-ca.ts +++ b/cli/commands/register-ca.ts @@ -1,10 +1,10 @@ import { CloudFormationClient } from '@aws-sdk/client-cloudformation' import { IoTClient } from '@aws-sdk/client-iot' import chalk from 'chalk' -import { CORE_STACK_NAME } from '../../cdk/stacks/stackName' -import { setCurrentCA } from '../jitp/currentCA' -import { registerCA } from '../jitp/registerCA' -import { CommandDefinition } from './CommandDefinition' +import { CORE_STACK_NAME } from '../../cdk/stacks/stackName.js' +import { setCurrentCA } from '../jitp/currentCA.js' +import { registerCA } from '../jitp/registerCA.js' +import type { CommandDefinition } from './CommandDefinition.js' export const registerCACommand = ({ certsDir, @@ -47,7 +47,7 @@ export const registerCACommand = ({ ) console.log( chalk.green('You can now generate device certificates.'), - chalk.greenBright('./cli.sh create-and-provision-device-cert'), + chalk.greenBright('./cli.sh create-and-provision-device-cert.js'), ) setCurrentCA({ certsDir, caId: certificateId }) }, diff --git a/cli/commands/retry.spec.ts b/cli/commands/retry.spec.ts index eeae18ec4..86fba94ed 100644 --- a/cli/commands/retry.spec.ts +++ b/cli/commands/retry.spec.ts @@ -1,4 +1,4 @@ -import { retry } from './retry' +import { retry } from './retry.js' describe('retry()', () => { it('should run a passed function and return the resolved promise', async () => { diff --git a/cli/commands/show-api-configuration.ts b/cli/commands/show-api-configuration.ts index 9641704cd..220456ef1 100644 --- a/cli/commands/show-api-configuration.ts +++ b/cli/commands/show-api-configuration.ts @@ -1,8 +1,8 @@ import { SSMClient } from '@aws-sdk/client-ssm' -import { setting } from '../../cdk/helper/note' -import { CORE_STACK_NAME } from '../../cdk/stacks/stackName' -import { getSettings } from '../../util/settings' -import { CommandDefinition } from './CommandDefinition' +import { setting } from '../../cdk/helper/note.js' +import { CORE_STACK_NAME } from '../../cdk/stacks/stackName.js' +import { getSettings } from '../../util/settings.js' +import type { CommandDefinition } from './CommandDefinition.js' export const showAPIConfigurationCommand = (): CommandDefinition => ({ command: 'show-api-configuration ', diff --git a/cli/commands/web-app-ci.ts b/cli/commands/web-app-ci.ts index 42199bdf5..581f6836c 100644 --- a/cli/commands/web-app-ci.ts +++ b/cli/commands/web-app-ci.ts @@ -4,10 +4,10 @@ import chalk from 'chalk' import { WEBAPP_CI_STACK_NAME, WEBAPP_STACK_NAME, -} from '../../cdk/stacks/stackName' -import { StackOutputs as WebAppCIStackOutputs } from '../../cdk/stacks/WebAppCI' -import { fromEnv } from '../../util/fromEnv' -import { CommandDefinition } from './CommandDefinition' +} from '../../cdk/stacks/stackName.js' +import type { StackOutputs as WebAppCIStackOutputs } from '../../cdk/stacks/WebAppCI.js' +import { fromEnv } from '../../util/fromEnv.js' +import type { CommandDefinition } from './CommandDefinition.js' const { region } = fromEnv({ region: 'AWS_REGION' })(process.env) diff --git a/cli/commands/web-app-config.ts b/cli/commands/web-app-config.ts index 5a6f93b1d..de9f0979a 100644 --- a/cli/commands/web-app-config.ts +++ b/cli/commands/web-app-config.ts @@ -1,10 +1,13 @@ import { IoTClient } from '@aws-sdk/client-iot' import { SSMClient } from '@aws-sdk/client-ssm' import { objectToEnv } from '@nordicsemiconductor/object-to-env' -import { getIotEndpoint } from '../../cdk/helper/getIotEndpoint' -import { CORE_STACK_NAME, WEBAPP_STACK_NAME } from '../../cdk/stacks/stackName' -import { getSettings } from '../../util/settings' -import { CommandDefinition } from './CommandDefinition' +import { getIotEndpoint } from '../../cdk/helper/getIotEndpoint.js' +import { + CORE_STACK_NAME, + WEBAPP_STACK_NAME, +} from '../../cdk/stacks/stackName.js' +import { getSettings } from '../../util/settings.js' +import type { CommandDefinition } from './CommandDefinition.js' const ssm = new SSMClient({}) diff --git a/cli/jitp/caFileLocations.ts b/cli/jitp/caFileLocations.ts index 38d3d851e..eba0cf8ff 100644 --- a/cli/jitp/caFileLocations.ts +++ b/cli/jitp/caFileLocations.ts @@ -1,4 +1,4 @@ -import * as path from 'path' +import path from 'path' export const caFileLocations = ({ id, diff --git a/cli/jitp/certsDir.ts b/cli/jitp/certsDir.ts index 90f620f1f..91cc867dc 100644 --- a/cli/jitp/certsDir.ts +++ b/cli/jitp/certsDir.ts @@ -1,6 +1,6 @@ import chalk from 'chalk' import { promises as fs } from 'fs' -import * as path from 'path' +import path from 'path' /** * Ensures the directory for storing certificates is available diff --git a/cli/jitp/createCA.ts b/cli/jitp/createCA.ts index 0ad1200ae..8583a4f77 100644 --- a/cli/jitp/createCA.ts +++ b/cli/jitp/createCA.ts @@ -1,10 +1,10 @@ -import { CloudFormationClient } from '@aws-sdk/client-cloudformation' -import { IoTClient, Tag } from '@aws-sdk/client-iot' +import type { CloudFormationClient } from '@aws-sdk/client-cloudformation' +import type { IoTClient, Tag } from '@aws-sdk/client-iot' import { randomUUID } from 'crypto' import { mkdir, stat, unlink } from 'fs/promises' -import { run } from '../process/run' -import { caFileLocations } from './caFileLocations' -import { registerCA } from './registerCA' +import { run } from '../process/run.js' +import { caFileLocations } from './caFileLocations.js' +import { registerCA } from './registerCA.js' export const defaultCAValidityInDays = 356 diff --git a/cli/jitp/createDeviceCertificate.ts b/cli/jitp/createDeviceCertificate.ts index faed14709..6584cd46e 100644 --- a/cli/jitp/createDeviceCertificate.ts +++ b/cli/jitp/createDeviceCertificate.ts @@ -1,8 +1,8 @@ import { promises as fs } from 'fs' -import * as os from 'os' -import { run } from '../process/run' -import { caFileLocations } from './caFileLocations' -import { deviceFileLocations } from './deviceFileLocations' +import os from 'os' +import { run } from '../process/run.js' +import { caFileLocations } from './caFileLocations.js' +import { deviceFileLocations } from './deviceFileLocations.js' export const defaultDeviceCertificateValidityInDays = 10950 diff --git a/cli/jitp/createSimulatorKeyAndCSR.ts b/cli/jitp/createSimulatorKeyAndCSR.ts index 9c3da99f3..b3e629bd0 100644 --- a/cli/jitp/createSimulatorKeyAndCSR.ts +++ b/cli/jitp/createSimulatorKeyAndCSR.ts @@ -1,6 +1,6 @@ import { promises as fs } from 'fs' -import { run } from '../process/run' -import { deviceFileLocations } from './deviceFileLocations' +import { run } from '../process/run.js' +import { deviceFileLocations } from './deviceFileLocations.js' /** * Creates a private key and a CSR for a simulated device diff --git a/cli/jitp/deviceFileLocations.ts b/cli/jitp/deviceFileLocations.ts index cbe9be406..68924dfbb 100644 --- a/cli/jitp/deviceFileLocations.ts +++ b/cli/jitp/deviceFileLocations.ts @@ -1,4 +1,4 @@ -import * as path from 'path' +import path from 'path' export const deviceFileLocations = ({ certsDir, diff --git a/cli/jitp/listLocalCAs.ts b/cli/jitp/listLocalCAs.ts index bd861ab85..d331c5669 100644 --- a/cli/jitp/listLocalCAs.ts +++ b/cli/jitp/listLocalCAs.ts @@ -1,6 +1,6 @@ import { readdir, readFile } from 'fs/promises' import path from 'path' -import { fingerprint } from './fingerprint' +import { fingerprint } from './fingerprint.js' export const listLocalCAs = async ({ certsDir, diff --git a/cli/jitp/listRegisteredCAs.ts b/cli/jitp/listRegisteredCAs.ts index 66d90dcc3..0936cff72 100644 --- a/cli/jitp/listRegisteredCAs.ts +++ b/cli/jitp/listRegisteredCAs.ts @@ -3,8 +3,8 @@ import { IoTClient, ListCACertificatesCommand, } from '@aws-sdk/client-iot' -import { paginate } from '../../util/paginate' -import { fingerprint } from './fingerprint' +import { paginate } from '../../util/paginate.js' +import { fingerprint } from './fingerprint.js' /** * Returns a map of the registered CA IDs and their fingerprints diff --git a/cli/jitp/readlineDevice.ts b/cli/jitp/readlineDevice.ts index def666d12..ca75245f0 100644 --- a/cli/jitp/readlineDevice.ts +++ b/cli/jitp/readlineDevice.ts @@ -1,7 +1,7 @@ -import { Connection } from '@nordicsemiconductor/firmware-ci-device-helpers' +import type { Connection } from '@nordicsemiconductor/firmware-ci-device-helpers' import chalk from 'chalk' -import * as readline from 'readline' -import { defaultFirmwareRepository } from '../commands/flash-firmware' +import readline from 'readline' +import { defaultFirmwareRepository } from '../commands/flash-firmware.js' /** * Provides a device that uses readline as the UART interface and requires a human to provide the input. diff --git a/cli/jitp/registerCA.ts b/cli/jitp/registerCA.ts index bc152e251..47053b109 100644 --- a/cli/jitp/registerCA.ts +++ b/cli/jitp/registerCA.ts @@ -13,8 +13,8 @@ import { toObject } from '@nordicsemiconductor/cloudformation-helpers' import { randomUUID } from 'crypto' import { copyFile, readFile, unlink } from 'fs/promises' import path from 'path' -import { run } from '../process/run' -import { caFileLocations } from './caFileLocations' +import { run } from '../process/run.js' +import { caFileLocations } from './caFileLocations.js' export const registerCA = async ({ iot, @@ -43,7 +43,7 @@ export const registerCA = async ({ const stackOutput = await cf .send(new DescribeStacksCommand({ StackName: stack })) .then(async ({ Stacks }) => { - if (Stacks?.length === 0 || Stacks?.[0].Outputs === undefined) { + if (Stacks?.length === 0 || Stacks?.[0]?.Outputs === undefined) { throw new Error(`Stack ${stack} not found.`) } return toObject(Stacks[0].Outputs) diff --git a/cli/process/run.ts b/cli/process/run.ts index a8109aa88..d50770ed8 100644 --- a/cli/process/run.ts +++ b/cli/process/run.ts @@ -1,5 +1,5 @@ import { spawn } from 'child_process' -import * as os from 'os' +import os from 'os' export const run = async (args: { command: string diff --git a/commitlint.config.js b/commitlint.config.cjs similarity index 100% rename from commitlint.config.js rename to commitlint.config.cjs diff --git a/export.d.ts b/export.d.ts new file mode 100644 index 000000000..7de6f7c13 --- /dev/null +++ b/export.d.ts @@ -0,0 +1,6 @@ +export * from './cli/jitp/caFileLocations.js' +export * from './cli/jitp/certsDir.js' +export * from './cli/jitp/createCA.js' +export * from './cli/jitp/createDeviceCertificate.js' +export * from './cli/jitp/deviceFileLocations.js' +export * from './feature-runner/steps.js' diff --git a/export.js b/export.js new file mode 100644 index 000000000..0ce1e31d5 --- /dev/null +++ b/export.js @@ -0,0 +1,6 @@ +export * from './dist/cli/jitp/caFileLocations' +export * from './dist/cli/jitp/certsDir' +export * from './dist/cli/jitp/createCA' +export * from './dist/cli/jitp/createDeviceCertificate' +export * from './dist/cli/jitp/deviceFileLocations' +export * from './dist/feature-runner/steps' diff --git a/export.ts b/export.ts deleted file mode 100644 index 3af422a0b..000000000 --- a/export.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './cli/jitp/caFileLocations' -export * from './cli/jitp/certsDir' -export * from './cli/jitp/createCA' -export * from './cli/jitp/createDeviceCertificate' -export * from './cli/jitp/deviceFileLocations' -export * from './feature-runner/steps' diff --git a/feature-runner/run-features.ts b/feature-runner/run-features.ts index 79b29afcf..0c93cffac 100644 --- a/feature-runner/run-features.ts +++ b/feature-runner/run-features.ts @@ -18,21 +18,21 @@ import chalk from 'chalk' import { program } from 'commander' import { promises as fs } from 'fs' import { randomUUID } from 'node:crypto' -import * as path from 'path' -import { getIotEndpoint } from '../cdk/helper/getIotEndpoint' -import { StackOutputs } from '../cdk/stacks/AssetTracker/stack' -import { StackOutputs as FirmwareCIStackOutputs } from '../cdk/stacks/FirmwareCI' +import path from 'path' +import { getIotEndpoint } from '../cdk/helper/getIotEndpoint.js' +import type { StackOutputs } from '../cdk/stacks/AssetTracker/stack.js' +import type { StackOutputs as FirmwareCIStackOutputs } from '../cdk/stacks/FirmwareCI.js' import { CORE_STACK_NAME, FIRMWARE_CI_STACK_NAME, HTTP_MOCK_HTTP_API_STACK_NAME, -} from '../cdk/stacks/stackName' -import { StackOutputs as HttpApiMockStackOutputs } from '../cdk/test-resources/HttpApiMockStack' -import { certsDir } from '../cli/jitp/certsDir' -import { gpsDay } from '../pgps/gpsTime' -import { assetTrackerStepRunners } from './steps/asset-tracker' -import { httpApiMockStepRunners } from './steps/httpApiMock' -import { timestreamStepRunners } from './steps/timestream' +} from '../cdk/stacks/stackName.js' +import type { StackOutputs as HttpApiMockStackOutputs } from '../cdk/test-resources/HttpApiMockStack.js' +import { certsDir } from '../cli/jitp/certsDir.js' +import { gpsDay } from '../pgps/gpsTime.js' +import { assetTrackerStepRunners } from './steps/asset-tracker.js' +import { httpApiMockStepRunners } from './steps/httpApiMock.js' +import { timestreamStepRunners } from './steps/timestream.js' let ran = false @@ -100,7 +100,7 @@ program ) const [historicaldataDatabaseName, historicaldataTableName] = - stackConfig.historicaldataTableInfo.split('|') + stackConfig.historicaldataTableInfo.split('|') as [string, string] const world: AssetTrackerWorld = { ...stackConfig, @@ -126,7 +126,7 @@ program 'httpApiMock:responsesTableName': httpApiMockStackConfig.responsesTableName, 'httpApiMock:apiURL': httpApiMockStackConfig.apiURL, - region: mqttEndpoint.split('.')[2], + region: mqttEndpoint.split('.')[2] as string, currentGpsDay: gpsDay(), } @@ -172,7 +172,7 @@ program email: () => `${randomUUID()}@example.com`, password: () => ((pw) => - `${pw[0].toUpperCase()}${pw.slice(1)}${Math.round( + `${pw[0]?.toUpperCase()}${pw.slice(1)}${Math.round( Math.random() * 1000, )}`)( Math.random() @@ -238,7 +238,6 @@ program .run() if (!success) { process.exit(1) - return } process.exit() } catch (error) { diff --git a/feature-runner/steps/asset-tracker.ts b/feature-runner/steps/asset-tracker.ts index d5de06154..a132a8fc1 100644 --- a/feature-runner/steps/asset-tracker.ts +++ b/feature-runner/steps/asset-tracker.ts @@ -7,14 +7,14 @@ import { import { randomWords } from '@nordicsemiconductor/random-words' import { expect } from 'chai' import { promises as fs } from 'fs' -import { createDeviceCertificate } from '../../cli/jitp/createDeviceCertificate' -import { createSimulatorKeyAndCSR } from '../../cli/jitp/createSimulatorKeyAndCSR' -import { getCurrentCA } from '../../cli/jitp/currentCA' -import { deviceFileLocations } from '../../cli/jitp/deviceFileLocations' +import { createDeviceCertificate } from '../../cli/jitp/createDeviceCertificate.js' +import { createSimulatorKeyAndCSR } from '../../cli/jitp/createSimulatorKeyAndCSR.js' +import { getCurrentCA } from '../../cli/jitp/currentCA.js' +import { deviceFileLocations } from '../../cli/jitp/deviceFileLocations.js' import { awsIotDeviceConnection, ListenerWithPayload, -} from './awsIotDeviceConnection' +} from './awsIotDeviceConnection.js' type World = { accountId: string @@ -155,7 +155,7 @@ export const assetTrackerStepRunners = ({ const publishPromise = new Promise((resolve, reject) => { const timeout = setTimeout(reject, 10 * 1000) connection - .publish(topic, JSON.stringify(message)) + .publish(topic as string, JSON.stringify(message)) .then(resolve) .catch(reject) .finally(() => { @@ -172,7 +172,7 @@ export const assetTrackerStepRunners = ({ const isRaw = raw !== undefined const expectedMessageCount = - messageCount === 'a' ? 1 : parseInt(messageCount, 10) + messageCount === 'a' ? 1 : parseInt(messageCount as string, 10) const messages: (Record | string)[] = [] return new Promise((resolve, reject) => { @@ -223,9 +223,9 @@ export const assetTrackerStepRunners = ({ return resolve(result) } - connection.onMessageOnce(topic, listener).catch(catchError) + connection.onMessageOnce(topic as string, listener).catch(catchError) } - connection.onMessageOnce(topic, listener).catch(catchError) + connection.onMessageOnce(topic as string, listener).catch(catchError) }) }), regexGroupMatcher( @@ -250,8 +250,10 @@ export const assetTrackerStepRunners = ({ connection .onMessageOnce(successTopic, (message) => { clearTimeout(timeout) - runner.store[storeName] = JSON.parse(message.toString()).execution - resolve(runner.store[storeName]) + runner.store[storeName as string] = JSON.parse( + message.toString(), + ).execution + resolve(runner.store[storeName as string]) }) .catch(catchError) @@ -264,7 +266,7 @@ export const assetTrackerStepRunners = ({ const catId = deviceId ?? runner.store['tracker:id'] const connection = await connectToBroker(catId) - const job = runner.store[storeName] + const job = runner.store[storeName as string] expect(job).to.not.be.an('undefined') const updateJobTopic = `$aws/things/${catId}/jobs/${job.jobId}/update` @@ -283,7 +285,7 @@ export const assetTrackerStepRunners = ({ connection .onMessageOnce(successTopic, (message) => { clearTimeout(timeout) - runner.store[storeName] = JSON.parse(message.toString()) + runner.store[storeName as string] = JSON.parse(message.toString()) resolve(JSON.parse(message.toString())) }) .then(async () => diff --git a/feature-runner/steps/awsIotDeviceConnection.ts b/feature-runner/steps/awsIotDeviceConnection.ts index 3cab65cb3..0ecd5be9d 100644 --- a/feature-runner/steps/awsIotDeviceConnection.ts +++ b/feature-runner/steps/awsIotDeviceConnection.ts @@ -1,7 +1,7 @@ import { device } from 'aws-iot-device-sdk' import { promises as fs } from 'fs' -import { deviceFileLocations } from '../../cli/jitp/deviceFileLocations' -import { isNullOrUndefined } from '../../util/isNullOrUndefined' +import { deviceFileLocations } from '../../cli/jitp/deviceFileLocations.js' +import { isNullOrUndefined } from '../../util/isNullOrUndefined.js' export type Listener = () => unknown export type ListenerWithPayload = (payload: Buffer) => unknown @@ -39,7 +39,10 @@ export const awsIotDeviceConnection = ({ fs.readFile(deviceFiles.certWithCA, 'utf-8'), ]) } - const [privateKey, clientCert] = await credentials[clientId] + const [privateKey, clientCert] = (await credentials[clientId]) as [ + string, + string, + ] const d = new device({ privateKey: Buffer.from(privateKey), clientCert: Buffer.from(clientCert), @@ -100,6 +103,6 @@ export const awsIotDeviceConnection = ({ }), } } - return connections[clientId] + return connections[clientId] as Connection } } diff --git a/feature-runner/steps/httpApiMock.ts b/feature-runner/steps/httpApiMock.ts index ff73c9861..0c612baca 100644 --- a/feature-runner/steps/httpApiMock.ts +++ b/feature-runner/steps/httpApiMock.ts @@ -1,4 +1,5 @@ import { + AttributeValue, DeleteItemCommand, DynamoDBClient, PutItemCommand, @@ -11,8 +12,8 @@ import { } from '@nordicsemiconductor/e2e-bdd-test-runner' import chai, { expect } from 'chai' import chaiSubset from 'chai-subset' -import { splitMockResponse } from '../../cdk/test-resources/splitMockResponse' -import { AssetTrackerWorld } from '../run-features' +import { splitMockResponse } from '../../cdk/test-resources/splitMockResponse.js' +import type { AssetTrackerWorld } from '../run-features.js' chai.use(chaiSubset) export const httpApiMockStepRunners = ({ @@ -37,7 +38,7 @@ export const httpApiMockStepRunners = ({ S: `${method} ${path}`, }, statusCode: { - N: statusCode, + N: statusCode as string, }, body: { S: step.interpolatedArgument, @@ -89,8 +90,8 @@ export const httpApiMockStepRunners = ({ new DeleteItemCommand({ TableName: runner.world['httpApiMock:requestsTableName'], Key: { - methodPathQuery: request.methodPathQuery, - requestId: request.requestId, + methodPathQuery: request.methodPathQuery as AttributeValue, + requestId: request.requestId as AttributeValue, }, }), ) diff --git a/feature-runner/steps/index.ts b/feature-runner/steps/index.ts index 381d03eaa..4f27f91e5 100644 --- a/feature-runner/steps/index.ts +++ b/feature-runner/steps/index.ts @@ -1 +1 @@ -export * from './asset-tracker' +export * from './asset-tracker.js' diff --git a/feature-runner/steps/timestream.ts b/feature-runner/steps/timestream.ts index 7b3a84810..406d9224b 100644 --- a/feature-runner/steps/timestream.ts +++ b/feature-runner/steps/timestream.ts @@ -8,7 +8,7 @@ import { StepRunnerFunc, } from '@nordicsemiconductor/e2e-bdd-test-runner' import { parseResult } from '@nordicsemiconductor/timestream-helpers' -import { AssetTrackerWorld } from '../run-features' +import type { AssetTrackerWorld } from '../run-features.js' export const timestreamStepRunners = ({ timestream, diff --git a/geolocation/Cell.ts b/geolocation/Cell.ts index f1709c6b7..efcf22eb7 100644 --- a/geolocation/Cell.ts +++ b/geolocation/Cell.ts @@ -1,3 +1,3 @@ -import { cellId } from '@nordicsemiconductor/cell-geolocation-helpers' +import type { cellId } from '@nordicsemiconductor/cell-geolocation-helpers' export type Cell = Parameters[0] diff --git a/geolocation/parseMCCMNC.spec.ts b/geolocation/parseMCCMNC.spec.ts index bf6ec75be..804ac269d 100644 --- a/geolocation/parseMCCMNC.spec.ts +++ b/geolocation/parseMCCMNC.spec.ts @@ -1,4 +1,4 @@ -import { parseMCCMNC } from './parseMCCMNC' +import { parseMCCMNC } from './parseMCCMNC.js' describe('parseMCCMNC()', () => { it.each([ diff --git a/geolocation/queueJob.ts b/geolocation/queueJob.ts index f03d0082d..cbdf84120 100644 --- a/geolocation/queueJob.ts +++ b/geolocation/queueJob.ts @@ -1,5 +1,5 @@ import { SendMessageCommand, SQSClient } from '@aws-sdk/client-sqs' -import { ErrorInfo, ErrorType } from '../api/ErrorInfo' +import { ErrorInfo, ErrorType } from '../api/ErrorInfo.js' export const queueJob = ({ sqs, QueueUrl }: { sqs: SQSClient; QueueUrl: string }) => diff --git a/geolocation/queueJobFP.ts b/geolocation/queueJobFP.ts deleted file mode 100644 index d0ebeb0dc..000000000 --- a/geolocation/queueJobFP.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { SendMessageCommand, SQSClient } from '@aws-sdk/client-sqs' -import * as TE from 'fp-ts/lib/TaskEither' -import { ErrorInfo, ErrorType } from '../api/ErrorInfo' - -/** - * @deprecated use queueJob() because fp-ts is getting gradually phased out from this code-base - */ -export const queueJobFP = - ({ sqs, QueueUrl }: { sqs: SQSClient; QueueUrl: string }) => - ({ - payload, - deduplicationId, - }: { - payload: unknown - deduplicationId: string - }): TE.TaskEither => - TE.tryCatch( - async () => { - console.debug( - JSON.stringify({ - queueJob: { - payload, - }, - }), - ) - const { MessageId, SequenceNumber } = await sqs.send( - new SendMessageCommand({ - QueueUrl, - MessageBody: JSON.stringify(payload), - MessageGroupId: deduplicationId, - MessageDeduplicationId: deduplicationId, - }), - ) - console.debug( - JSON.stringify({ - queueJob: { - QueueUrl, - MessageId, - SequenceNumber, - }, - }), - ) - }, - (err) => { - console.error( - JSON.stringify({ - queueJob: { - error: (err as Error).message, - cell: payload, - QueueUrl, - }, - }), - ) - return { - type: ErrorType.InternalError, - message: (err as Error).message, - } - }, - ) diff --git a/geolocation/types.ts b/geolocation/types.ts index 5561cf03d..3457ca28c 100644 --- a/geolocation/types.ts +++ b/geolocation/types.ts @@ -1,4 +1,4 @@ -import { Location } from './Location' +import type { Location } from './Location.js' export type MaybeLocation = { located: boolean diff --git a/historicalData/batchToTimestreamRecords.spec.ts b/historicalData/batchToTimestreamRecords.spec.ts index 4520cca09..d484fd6e1 100644 --- a/historicalData/batchToTimestreamRecords.spec.ts +++ b/historicalData/batchToTimestreamRecords.spec.ts @@ -1,4 +1,4 @@ -import { batchToTimestreamRecords } from './batchToTimestreamRecords' +import { batchToTimestreamRecords } from './batchToTimestreamRecords.js' describe('batchToTimestreamRecords', () => { it('should convert a message to Timestream records', () => { @@ -74,10 +74,18 @@ describe('batchToTimestreamRecords', () => { }, ]) - const g1lng = r[0].Dimensions?.find(({ Name }) => Name === 'measureGroup') - const g1lat = r[1].Dimensions?.find(({ Name }) => Name === 'measureGroup') - const g2lng = r[2].Dimensions?.find(({ Name }) => Name === 'measureGroup') - const g2lat = r[3].Dimensions?.find(({ Name }) => Name === 'measureGroup') + const g1lng = r?.[0]?.Dimensions?.find( + ({ Name }) => Name === 'measureGroup', + ) + const g1lat = r?.[1]?.Dimensions?.find( + ({ Name }) => Name === 'measureGroup', + ) + const g2lng = r?.[2]?.Dimensions?.find( + ({ Name }) => Name === 'measureGroup', + ) + const g2lat = r?.[3]?.Dimensions?.find( + ({ Name }) => Name === 'measureGroup', + ) // measureGroups should be equal for measures from the same object expect(g1lng?.Value).toEqual(g1lat?.Value) expect(g2lng?.Value).toEqual(g2lat?.Value) diff --git a/historicalData/batchToTimestreamRecords.ts b/historicalData/batchToTimestreamRecords.ts index 8a4b46495..0baebbb47 100644 --- a/historicalData/batchToTimestreamRecords.ts +++ b/historicalData/batchToTimestreamRecords.ts @@ -1,7 +1,7 @@ -import { _Record } from '@aws-sdk/client-timestream-write' +import type { _Record } from '@aws-sdk/client-timestream-write' import { toRecord } from '@nordicsemiconductor/timestream-helpers' import { randomUUID } from 'node:crypto' -import { isNotNullOrUndefined } from '../util/isNullOrUndefined' +import { isNotNullOrUndefined } from '../util/isNullOrUndefined.js' export const batchToTimestreamRecords = (event: BatchMessage): _Record[] => { const Records: (_Record | undefined)[] = Object.entries(event.batch) diff --git a/historicalData/messageToTimestreamRecords.spec.ts b/historicalData/messageToTimestreamRecords.spec.ts index 114764080..e1b100bf2 100644 --- a/historicalData/messageToTimestreamRecords.spec.ts +++ b/historicalData/messageToTimestreamRecords.spec.ts @@ -1,4 +1,4 @@ -import { messageToTimestreamRecords } from './messageToTimestreamRecords' +import { messageToTimestreamRecords } from './messageToTimestreamRecords.js' describe('messageToTimestreamRecords', () => { it('should convert a message to Timestream records', () => { diff --git a/historicalData/messageToTimestreamRecords.ts b/historicalData/messageToTimestreamRecords.ts index d8ac82353..aadd74089 100644 --- a/historicalData/messageToTimestreamRecords.ts +++ b/historicalData/messageToTimestreamRecords.ts @@ -1,7 +1,7 @@ -import { _Record } from '@aws-sdk/client-timestream-write' +import type { _Record } from '@aws-sdk/client-timestream-write' import { toRecord } from '@nordicsemiconductor/timestream-helpers' import { randomUUID } from 'node:crypto' -import { isNotNullOrUndefined } from '../util/isNullOrUndefined' +import { isNotNullOrUndefined } from '../util/isNullOrUndefined.js' export const messageToTimestreamRecords = (event: DeviceMessage): _Record[] => { const Records: (_Record | undefined)[] = [] diff --git a/historicalData/shadowUpdateToTimestreamRecords.spec.ts b/historicalData/shadowUpdateToTimestreamRecords.spec.ts index 850c15b86..5a6c1e4df 100644 --- a/historicalData/shadowUpdateToTimestreamRecords.spec.ts +++ b/historicalData/shadowUpdateToTimestreamRecords.spec.ts @@ -1,4 +1,4 @@ -import { shadowUpdateToTimestreamRecords } from './shadowUpdateToTimestreamRecords' +import { shadowUpdateToTimestreamRecords } from './shadowUpdateToTimestreamRecords.js' describe('shadowUpdateToTimestreamRecords', () => { it('should convert a shadow update to Timestream records', () => { @@ -145,8 +145,10 @@ describe('shadowUpdateToTimestreamRecords', () => { TimeUnit: 'MILLISECONDS', }, ]) - const first = r[0].Dimensions?.find(({ Name }) => Name === 'measureGroup') - const last = r[r.length - 1].Dimensions?.find( + const first = r?.[0]?.Dimensions?.find( + ({ Name }) => Name === 'measureGroup', + ) + const last = r?.[r.length - 1]?.Dimensions?.find( ({ Name }) => Name === 'measureGroup', ) // measureGroups should be equal for measures diff --git a/historicalData/shadowUpdateToTimestreamRecords.ts b/historicalData/shadowUpdateToTimestreamRecords.ts index 4eb25874b..39029f23f 100644 --- a/historicalData/shadowUpdateToTimestreamRecords.ts +++ b/historicalData/shadowUpdateToTimestreamRecords.ts @@ -1,7 +1,7 @@ -import { _Record } from '@aws-sdk/client-timestream-write' +import type { _Record } from '@aws-sdk/client-timestream-write' import { toRecord } from '@nordicsemiconductor/timestream-helpers' import { randomUUID } from 'node:crypto' -import { isNotNullOrUndefined } from '../util/isNullOrUndefined' +import { isNotNullOrUndefined } from '../util/isNullOrUndefined.js' export const shadowUpdateToTimestreamRecords = ( event: UpdatedDeviceState, diff --git a/historicalData/storeMessagesInTimestream.ts b/historicalData/storeMessagesInTimestream.ts index 617fed1cb..6467a6835 100644 --- a/historicalData/storeMessagesInTimestream.ts +++ b/historicalData/storeMessagesInTimestream.ts @@ -1,16 +1,16 @@ -import { Dimension, _Record } from '@aws-sdk/client-timestream-write' +import type { Dimension, _Record } from '@aws-sdk/client-timestream-write' import { writeClient } from '@nordicsemiconductor/timestream-helpers' -import { fromEnv } from '../util/fromEnv' -import { batchToTimestreamRecords } from './batchToTimestreamRecords' -import { messageToTimestreamRecords } from './messageToTimestreamRecords' -import { shadowUpdateToTimestreamRecords } from './shadowUpdateToTimestreamRecords' -import { storeRecordsInTimeseries } from './storeRecordsInTimeseries' +import { fromEnv } from '../util/fromEnv.js' +import { batchToTimestreamRecords } from './batchToTimestreamRecords.js' +import { messageToTimestreamRecords } from './messageToTimestreamRecords.js' +import { shadowUpdateToTimestreamRecords } from './shadowUpdateToTimestreamRecords.js' +import { storeRecordsInTimeseries } from './storeRecordsInTimeseries.js' const { tableInfo } = fromEnv({ tableInfo: 'TABLE_INFO', })(process.env) -const [DatabaseName, TableName] = tableInfo.split('|') +const [DatabaseName, TableName] = tableInfo.split('|') as [string, string] const store = (async () => storeRecordsInTimeseries({ timestream: await writeClient(), diff --git a/networkSurveyGeolocation/expandMac.spec.ts b/networkSurveyGeolocation/expandMac.spec.ts index ae08970b3..513c1e11f 100644 --- a/networkSurveyGeolocation/expandMac.spec.ts +++ b/networkSurveyGeolocation/expandMac.spec.ts @@ -1,4 +1,4 @@ -import { expandMac } from './expandMac' +import { expandMac } from './expandMac.js' describe('expandMac()', () => { it.each([ diff --git a/networkSurveyGeolocation/geolocateSurvey.ts b/networkSurveyGeolocation/geolocateSurvey.ts index 0685b7da5..e84629dac 100644 --- a/networkSurveyGeolocation/geolocateSurvey.ts +++ b/networkSurveyGeolocation/geolocateSurvey.ts @@ -1,7 +1,7 @@ import { DynamoDBClient, GetItemCommand } from '@aws-sdk/client-dynamodb' import { unmarshall } from '@aws-sdk/util-dynamodb' -import { ErrorInfo, ErrorType } from '../api/ErrorInfo' -import { Location } from '../geolocation/Location' +import { ErrorInfo, ErrorType } from '../api/ErrorInfo.js' +import type { Location } from '../geolocation/Location.js' export type Survey = { deviceId: string diff --git a/networkSurveyGeolocation/httpApi/locateSurvey.ts b/networkSurveyGeolocation/httpApi/locateSurvey.ts index 82ff0fd11..06c68458b 100644 --- a/networkSurveyGeolocation/httpApi/locateSurvey.ts +++ b/networkSurveyGeolocation/httpApi/locateSurvey.ts @@ -1,15 +1,15 @@ import { DynamoDBClient } from '@aws-sdk/client-dynamodb' import { SFNClient, StartExecutionCommand } from '@aws-sdk/client-sfn' +import { validateWithType } from '@nordicsemiconductor/asset-tracker-cloud-docs/protocol' import { Type } from '@sinclair/typebox' import type { APIGatewayProxyEventV2, APIGatewayProxyResultV2, } from 'aws-lambda' -import { ErrorType, toStatusCode } from '../../api/ErrorInfo' -import { res } from '../../api/res' -import { validateWithJSONSchema } from '../../api/validateWithJSONSchema' -import { fromEnv } from '../../util/fromEnv' -import { geolocateSurvey, Survey } from '../geolocateSurvey' +import { ErrorType, toStatusCode } from '../../api/ErrorInfo.js' +import { res } from '../../api/res.js' +import { fromEnv } from '../../util/fromEnv.js' +import { geolocateSurvey, Survey } from '../geolocateSurvey.js' const inputSchema = Type.Object( { @@ -18,7 +18,7 @@ const inputSchema = Type.Object( { additionalProperties: false }, ) -const validateInput = validateWithJSONSchema(inputSchema) +const validateInput = validateWithType(inputSchema) const { surveysTable, stateMachineArn } = fromEnv({ surveysTable: 'SURVEYS_TABLE', @@ -66,8 +66,8 @@ export const handler = async ( const id = event.requestContext.http.path.slice(1) // path: /3bf67b25-acd9-474c-b97a-3cb6083b7c44 const maybeValidRequest = validateInput({ id }) - if ('error' in maybeValidRequest) { - return res(toStatusCode[ErrorType.BadRequest])(maybeValidRequest.error) + if ('errors' in maybeValidRequest) { + return res(toStatusCode[ErrorType.BadRequest])(maybeValidRequest.errors) } const maybeSurvey = await locator(maybeValidRequest.id) diff --git a/package-lock.json b/package-lock.json index 6ae52921b..174c9011d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0-development", "license": "BSD-3-Clause", "dependencies": { + "@nordicsemiconductor/asset-tracker-cloud-docs": "28.1.3", "@nordicsemiconductor/cell-geolocation-helpers": "6.0.0", "@nordicsemiconductor/nrfcloud-location-services-tests": "4.0.1", "@nordicsemiconductor/timestream-helpers": "5.0.0", @@ -16,7 +17,6 @@ "ajv": "8.12.0", "entities": "4.4.0", "fast-xml-parser": "4.1.3", - "fp-ts": "2.13.1", "jsonwebtoken": "9.0.0", "uuid": "9.0.0" }, @@ -39,9 +39,8 @@ "@nordicsemiconductor/asset-tracker-cloud-code-style": "12.0.5", "@nordicsemiconductor/cloudformation-helpers": "8.0.0", "@nordicsemiconductor/e2e-bdd-test-runner": "16.0.12", - "@nordicsemiconductor/firmware-ci-device-helpers": "14.0.11", + "@nordicsemiconductor/firmware-ci-device-helpers": "14.0.12", "@nordicsemiconductor/object-to-env": "5.0.0", - "@nordicsemiconductor/package-layered-lambdas": "12.0.10", "@nordicsemiconductor/random-words": "7.0.0", "@octokit/rest": "19.0.7", "@swc/cli": "0.1.62", @@ -55,6 +54,7 @@ "@types/jest": "29.5.0", "@types/jsonwebtoken": "9.0.1", "@types/node": "18.15.3", + "@types/yazl": "2.4.2", "aws-cdk-lib": "2.69.0", "aws-iot-device-sdk": "2.2.12", "backoff": "2.5.0", @@ -65,10 +65,12 @@ "commander": "10.0.0", "constructs": "10.1.283", "date-fns": "2.29.3", + "glob": "9.3.0", "jest": "29.5.0", "nock": "13.3.0", "octokit-auth-netrc": "2.1.0", - "tsx": "3.12.5" + "tsx": "3.12.5", + "yazl": "2.5.1" }, "engines": { "node": ">=18", @@ -740,53 +742,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/@aws-sdk/client-lambda": { - "version": "3.294.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.294.0.tgz", - "integrity": "sha512-zqkRsODF7R/4d597mjPExqyrRqwut+PCffQvLsfmxCnRHQPWVmMRBVl9xAvmsPM0mWlvrqcwa/GGOJplG3z/vQ==", - "dev": true, - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.294.0", - "@aws-sdk/config-resolver": "3.292.0", - "@aws-sdk/credential-provider-node": "3.294.0", - "@aws-sdk/fetch-http-handler": "3.292.0", - "@aws-sdk/hash-node": "3.292.0", - "@aws-sdk/invalid-dependency": "3.292.0", - "@aws-sdk/middleware-content-length": "3.292.0", - "@aws-sdk/middleware-endpoint": "3.292.0", - "@aws-sdk/middleware-host-header": "3.292.0", - "@aws-sdk/middleware-logger": "3.292.0", - "@aws-sdk/middleware-recursion-detection": "3.292.0", - "@aws-sdk/middleware-retry": "3.293.0", - "@aws-sdk/middleware-serde": "3.292.0", - "@aws-sdk/middleware-signing": "3.292.0", - "@aws-sdk/middleware-stack": "3.292.0", - "@aws-sdk/middleware-user-agent": "3.293.0", - "@aws-sdk/node-config-provider": "3.292.0", - "@aws-sdk/node-http-handler": "3.292.0", - "@aws-sdk/protocol-http": "3.292.0", - "@aws-sdk/smithy-client": "3.292.0", - "@aws-sdk/types": "3.292.0", - "@aws-sdk/url-parser": "3.292.0", - "@aws-sdk/util-base64": "3.292.0", - "@aws-sdk/util-body-length-browser": "3.292.0", - "@aws-sdk/util-body-length-node": "3.292.0", - "@aws-sdk/util-defaults-mode-browser": "3.292.0", - "@aws-sdk/util-defaults-mode-node": "3.292.0", - "@aws-sdk/util-endpoints": "3.293.0", - "@aws-sdk/util-retry": "3.292.0", - "@aws-sdk/util-user-agent-browser": "3.292.0", - "@aws-sdk/util-user-agent-node": "3.292.0", - "@aws-sdk/util-utf8": "3.292.0", - "@aws-sdk/util-waiter": "3.292.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@aws-sdk/client-s3": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.294.0.tgz", @@ -4616,6 +4571,18 @@ "node": ">=12.20" } }, + "node_modules/@nordicsemiconductor/asset-tracker-cloud-docs": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@nordicsemiconductor/asset-tracker-cloud-docs/-/asset-tracker-cloud-docs-28.1.3.tgz", + "integrity": "sha512-4K031jjsQMoBQ2/LsnkxkM6qHMSgLZRP3kNt2gei+uffgIsd7nmphYvx1sbEM+YtLlLPHH5B2/eaOfyK3mFumg==", + "dependencies": { + "@sinclair/typebox": "0.25.24" + }, + "engines": { + "node": ">=18", + "npm": ">=9" + } + }, "node_modules/@nordicsemiconductor/cell-geolocation-helpers": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@nordicsemiconductor/cell-geolocation-helpers/-/cell-geolocation-helpers-6.0.0.tgz", @@ -4675,6 +4642,15 @@ "npm": ">=9" } }, + "node_modules/@nordicsemiconductor/e2e-bdd-test-runner/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/@nordicsemiconductor/e2e-bdd-test-runner/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -4691,6 +4667,37 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@nordicsemiconductor/e2e-bdd-test-runner/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@nordicsemiconductor/e2e-bdd-test-runner/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@nordicsemiconductor/eslint-config-asset-tracker-cloud-typescript": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/@nordicsemiconductor/eslint-config-asset-tracker-cloud-typescript/-/eslint-config-asset-tracker-cloud-typescript-12.0.1.tgz", @@ -4707,9 +4714,9 @@ } }, "node_modules/@nordicsemiconductor/firmware-ci-device-helpers": { - "version": "14.0.11", - "resolved": "https://registry.npmjs.org/@nordicsemiconductor/firmware-ci-device-helpers/-/firmware-ci-device-helpers-14.0.11.tgz", - "integrity": "sha512-0SaMJgs8VC4gPi8UPyO9BPXmMA3LBH1iP6i7xfjnP2UN/q5RSxMyJPqZsJB5kRAt4SAOr3ulwzS4qHYgPDqKrQ==", + "version": "14.0.12", + "resolved": "https://registry.npmjs.org/@nordicsemiconductor/firmware-ci-device-helpers/-/firmware-ci-device-helpers-14.0.12.tgz", + "integrity": "sha512-/EKJO/7IjPxwjnk4EwHD2JZLNpQ1ScRhgKKNBTPm/lwyZYWVEsB/oF552ki2GEYopPO+XKt0dh7xY48goTO1WQ==", "dev": true, "dependencies": { "@serialport/parser-readline": "10.5.0", @@ -4748,47 +4755,6 @@ "npm": ">=9" } }, - "node_modules/@nordicsemiconductor/package-layered-lambdas": { - "version": "12.0.10", - "resolved": "https://registry.npmjs.org/@nordicsemiconductor/package-layered-lambdas/-/package-layered-lambdas-12.0.10.tgz", - "integrity": "sha512-tj5doUhgaK2PvT63Le5I3lBMpLaTZsZLBMTPhB1MXrFX7wVS5nnSe6PWdZ2KuVSz1jKQscoi8a0/jYimrB9Zgg==", - "dev": true, - "dependencies": { - "@aws-sdk/client-cloudformation": "3.294.0", - "@aws-sdk/client-lambda": "3.294.0", - "@aws-sdk/client-s3": "3.294.0", - "ansi-escapes": "4.3.2", - "aws-lambda": "1.0.7", - "chalk": "4.1.2", - "dependency-tree": "9.0.0", - "glob": "8.1.0", - "table": "6.8.1", - "tmp": "0.2.1", - "ts-loader": "9.4.2", - "webpack": "5.76.2", - "yazl": "2.5.1" - }, - "engines": { - "node": ">=18", - "npm": ">=9" - } - }, - "node_modules/@nordicsemiconductor/package-layered-lambdas/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/@nordicsemiconductor/random-words": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@nordicsemiconductor/random-words/-/random-words-7.0.0.tgz", @@ -5747,29 +5713,6 @@ "@types/chai": "*" } }, - "node_modules/@types/eslint": { - "version": "8.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.51", - "dev": true, - "license": "MIT" - }, "node_modules/@types/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", @@ -5831,11 +5774,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/json5": { - "version": "0.0.29", - "dev": true, - "license": "MIT" - }, "node_modules/@types/jsonwebtoken": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", @@ -5937,6 +5875,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/yazl": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/yazl/-/yazl-2.4.2.tgz", + "integrity": "sha512-T+9JH8O2guEjXNxqmybzQ92mJUh2oCwDDMSSimZSe1P+pceZiFROZLYmcbqkzV5EUwz6VwcKXCO2S2yUpra6XQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.55.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz", @@ -6126,147 +6073,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/acorn": { "version": "8.8.0", "dev": true, @@ -6278,14 +6084,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^8" - } - }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -6380,11 +6178,6 @@ "node": ">= 8" } }, - "node_modules/app-module-path": { - "version": "2.2.0", - "dev": true, - "license": "BSD-2-Clause" - }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -6449,14 +6242,6 @@ "node": "*" } }, - "node_modules/ast-module-types": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "dev": true, @@ -6745,25 +6530,6 @@ "node": ">=10.0.0" } }, - "node_modules/aws-lambda": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "aws-sdk": "^2.814.0", - "commander": "^3.0.2", - "js-yaml": "^3.14.1", - "watchpack": "^2.0.0-beta.10" - }, - "bin": { - "lambda": "bin/lambda" - } - }, - "node_modules/aws-lambda/node_modules/commander": { - "version": "3.0.2", - "dev": true, - "license": "MIT" - }, "node_modules/aws-sdk": { "version": "2.1338.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1338.0.tgz", @@ -7180,8 +6946,9 @@ }, "node_modules/buffer-crc32": { "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, - "license": "MIT", "engines": { "node": "*" } @@ -7433,14 +7200,6 @@ "semver": "bin/semver.js" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0" - } - }, "node_modules/ci-info": { "version": "3.6.1", "dev": true, @@ -7979,30 +7738,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dependency-tree": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/dependency-tree/-/dependency-tree-9.0.0.tgz", - "integrity": "sha512-osYHZJ1fBSon3lNLw70amAXsQ+RGzXsPvk9HbBgTLbp/bQBmpH5mOmsUvqXU+YEWVU0ZLewsmzOET/8jWswjDQ==", - "dev": true, - "dependencies": { - "commander": "^2.20.3", - "debug": "^4.3.1", - "filing-cabinet": "^3.0.1", - "precinct": "^9.0.0", - "typescript": "^4.0.0" - }, - "bin": { - "dependency-tree": "bin/cli.js" - }, - "engines": { - "node": "^10.13 || ^12 || >=14" - } - }, - "node_modules/dependency-tree/node_modules/commander": { - "version": "2.20.3", - "dev": true, - "license": "MIT" - }, "node_modules/deprecation": { "version": "2.3.1", "dev": true, @@ -8017,199 +7752,6 @@ "node": ">=8" } }, - "node_modules/detective-amd": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/detective-amd/-/detective-amd-4.0.1.tgz", - "integrity": "sha512-bDo22IYbJ8yzALB0Ow5CQLtyhU1BpDksLB9dsWHI9Eh0N3OQR6aQqhjPsNDd69ncYwRfL1sTo7OA9T3VRVSe2Q==", - "dev": true, - "dependencies": { - "ast-module-types": "^3.0.0", - "escodegen": "^2.0.0", - "get-amd-module-type": "^4.0.0", - "node-source-walk": "^5.0.0" - }, - "bin": { - "detective-amd": "bin/cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/detective-amd/node_modules/node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/detective-cjs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detective-cjs/-/detective-cjs-4.0.0.tgz", - "integrity": "sha512-VsD6Yo1+1xgxJWoeDRyut7eqZ8EWaJI70C5eanSAPcBHzenHZx0uhjxaaEfIm0cHII7dBiwU98Orh44bwXN2jg==", - "dev": true, - "dependencies": { - "ast-module-types": "^3.0.0", - "node-source-walk": "^5.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/detective-cjs/node_modules/node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/detective-es6": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/detective-es6/-/detective-es6-3.0.0.tgz", - "integrity": "sha512-Uv2b5Uih7vorYlqGzCX+nTPUb4CMzUAn3VPHTV5p5lBkAN4cAApLGgUz4mZE2sXlBfv4/LMmeP7qzxHV/ZcfWA==", - "dev": true, - "dependencies": { - "node-source-walk": "^5.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/detective-es6/node_modules/node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/detective-less": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/detective-less/-/detective-less-1.0.2.tgz", - "integrity": "sha512-Rps1xDkEEBSq3kLdsdnHZL1x2S4NGDcbrjmd4q+PykK5aJwDdP5MBgrJw1Xo+kyUHuv3JEzPqxr+Dj9ryeDRTA==", - "dev": true, - "dependencies": { - "debug": "^4.0.0", - "gonzales-pe": "^4.2.3", - "node-source-walk": "^4.0.0" - }, - "engines": { - "node": ">= 6.0" - } - }, - "node_modules/detective-postcss": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detective-postcss/-/detective-postcss-6.1.0.tgz", - "integrity": "sha512-ZFZnEmUrL2XHAC0j/4D1fdwZbo/anAcK84soJh7qc7xfx2Kc8gFO5Bk5I9jU7NLC/OAF1Yho1GLxEDnmQnRH2A==", - "dev": true, - "dependencies": { - "is-url": "^1.2.4", - "postcss": "^8.4.12", - "postcss-values-parser": "^6.0.2" - }, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/detective-sass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/detective-sass/-/detective-sass-4.0.1.tgz", - "integrity": "sha512-80zfpxux1krOrkxCHbtwvIs2gNHUBScnSqlGl0FvUuHVz8HD6vD2ov66OroMctyvzhM67fxhuEeVjIk18s6yTQ==", - "dev": true, - "dependencies": { - "gonzales-pe": "^4.3.0", - "node-source-walk": "^5.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/detective-sass/node_modules/node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/detective-scss": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/detective-scss/-/detective-scss-3.0.0.tgz", - "integrity": "sha512-37MB/mhJyS45ngqfzd6eTbuLMoDgdZnH03ZOMW2m9WqJ/Rlbuc8kZAr0Ypovaf1DJiTRzy5mmxzOTja85jbzlA==", - "dev": true, - "dependencies": { - "gonzales-pe": "^4.3.0", - "node-source-walk": "^5.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/detective-scss/node_modules/node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/detective-stylus": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detective-stylus/-/detective-stylus-2.0.1.tgz", - "integrity": "sha512-/Tvs1pWLg8eYwwV6kZQY5IslGaYqc/GACxjcaGudiNtN5nKCH6o2WnJK3j0gA3huCnoQcbv8X7oz/c1lnvE3zQ==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/detective-typescript": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-9.0.0.tgz", - "integrity": "sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "^5.13.0", - "ast-module-types": "^3.0.0", - "node-source-walk": "^5.0.0", - "typescript": "^4.5.5" - }, - "engines": { - "node": "^12.20.0 || ^14.14.0 || >=16.0.0" - } - }, - "node_modules/detective-typescript/node_modules/node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/diff": { "version": "4.0.2", "dev": true, @@ -8323,18 +7865,6 @@ "once": "^1.4.0" } }, - "node_modules/enhanced-resolve": { - "version": "5.10.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/entities": { "version": "4.4.0", "license": "BSD-2-Clause", @@ -8389,11 +7919,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-module-lexer": { - "version": "0.9.3", - "dev": true, - "license": "MIT" - }, "node_modules/es-to-primitive": { "version": "1.2.1", "dev": true, @@ -8480,88 +8005,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/eslint": { "version": "8.36.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", @@ -9088,49 +8531,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/filing-cabinet": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "app-module-path": "^2.2.0", - "commander": "^2.20.3", - "debug": "^4.3.3", - "enhanced-resolve": "^5.8.3", - "is-relative-path": "^1.0.2", - "module-definition": "^3.3.1", - "module-lookup-amd": "^7.0.1", - "resolve": "^1.21.0", - "resolve-dependency-path": "^2.0.0", - "sass-lookup": "^3.0.0", - "stylus-lookup": "^3.0.1", - "tsconfig-paths": "^3.10.1", - "typescript": "^3.9.7" - }, - "bin": { - "filing-cabinet": "bin/cli.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/filing-cabinet/node_modules/commander": { - "version": "2.20.3", - "dev": true, - "license": "MIT" - }, - "node_modules/filing-cabinet/node_modules/typescript": { - "version": "3.9.10", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, "node_modules/fill-range": { "version": "7.0.1", "dev": true, @@ -9193,10 +8593,6 @@ "node": ">=12.20.0" } }, - "node_modules/fp-ts": { - "version": "2.13.1", - "license": "MIT" - }, "node_modules/fs-extra": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", @@ -9269,31 +8665,6 @@ "node": ">=6.9.0" } }, - "node_modules/get-amd-module-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/get-amd-module-type/-/get-amd-module-type-4.0.0.tgz", - "integrity": "sha512-GbBawUCuA2tY8ztiMiVo3e3P95gc2TVrfYFfpUHdHQA8WyxMCckK29bQsVKhYX8SUf+w6JLhL2LG8tSC0ANt9Q==", - "dev": true, - "dependencies": { - "ast-module-types": "^3.0.0", - "node-source-walk": "^5.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/get-amd-module-type/node_modules/node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "dev": true, @@ -9323,11 +8694,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "dev": true, - "license": "ISC" - }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -9413,19 +8779,18 @@ } }, "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.0.tgz", + "integrity": "sha512-EAZejC7JvnQINayvB/7BJbpZpNOJ8Lrw2OZNEvQxe0vaLn1SuwMcfV7/MNaX8L/T0wmptBFI4YMtDvSBxYDc7w==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -9442,28 +8807,28 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "dev": true, - "license": "BSD-2-Clause" - }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/glob/node_modules/minimatch": { - "version": "5.0.1", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.2.tgz", + "integrity": "sha512-xy4q7wou3vUoC9k1xGTXc+awNdGaGVHtFUaey8tiX4H1QRc04DZ/rmDFwNm2EBsuYEhAZ6SgMmYf3InGY6OauA==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/global-dirs": { @@ -9524,21 +8889,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/gonzales-pe": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz", - "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "gonzales": "bin/gonzales.js" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/graceful-fs": { "version": "4.2.10", "dev": true, @@ -10066,21 +9416,8 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-regexp": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-relative-path": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", "dev": true, "license": "MIT", "dependencies": { @@ -10159,24 +9496,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true - }, - "node_modules/is-url-superb": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-url-superb/-/is-url-superb-4.0.0.tgz", - "integrity": "sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-weakref": { "version": "1.0.2", "dev": true, @@ -11992,14 +11311,6 @@ "node": ">=8" } }, - "node_modules/loader-runner": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.11.5" - } - }, "node_modules/locate-path": { "version": "6.0.0", "dev": true, @@ -12058,22 +11369,12 @@ "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", "dev": true }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.startcase": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", "dev": true }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -12320,17 +11621,6 @@ "node": ">= 0.6" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mimic-fn": { "version": "2.1.0", "dev": true, @@ -12386,6 +11676,15 @@ "node": ">= 6" } }, + "node_modules/minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/mnemonist": { "version": "0.38.3", "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", @@ -12394,63 +11693,6 @@ "obliterator": "^1.6.1" } }, - "node_modules/module-definition": { - "version": "3.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ast-module-types": "^3.0.0", - "node-source-walk": "^4.0.0" - }, - "bin": { - "module-definition": "bin/cli.js" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/module-lookup-amd": { - "version": "7.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^2.8.1", - "debug": "^4.1.0", - "glob": "^7.1.6", - "requirejs": "^2.3.5", - "requirejs-config-file": "^4.0.0" - }, - "bin": { - "lookup-amd": "bin/cli.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/module-lookup-amd/node_modules/commander": { - "version": "2.20.3", - "dev": true, - "license": "MIT" - }, - "node_modules/module-lookup-amd/node_modules/glob": { - "version": "7.2.0", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/mqtt": { "version": "4.3.7", "dev": true, @@ -12497,18 +11739,6 @@ "version": "2.1.2", "license": "MIT" }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "dev": true, @@ -12520,11 +11750,6 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, - "node_modules/neo-async": { - "version": "2.6.2", - "dev": true, - "license": "MIT" - }, "node_modules/netrc": { "version": "0.1.4", "dev": true, @@ -12616,17 +11841,6 @@ "dev": true, "license": "MIT" }, - "node_modules/node-source-walk": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.0.0" - }, - "engines": { - "node": ">=6.0" - } - }, "node_modules/nofilter": { "version": "3.1.0", "dev": true, @@ -12929,6 +12143,31 @@ "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.1.tgz", + "integrity": "sha512-OW+5s+7cw6253Q4E+8qQ/u1fVvcJQCJo/VFD8pje+dbJCF1n5ZRMV2AEHbGp+5Q7jxQIYJxkHopnj6nzdGeZLA==", + "dev": true, + "dependencies": { + "lru-cache": "^7.14.1", + "minipass": "^4.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/path-type": { "version": "4.0.0", "dev": true, @@ -13073,110 +12312,6 @@ "node": ">=4" } }, - "node_modules/postcss": { - "version": "8.4.20", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", - "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-values-parser": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-6.0.2.tgz", - "integrity": "sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==", - "dev": true, - "dependencies": { - "color-name": "^1.1.4", - "is-url-superb": "^4.0.0", - "quote-unquote": "^1.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "postcss": "^8.2.9" - } - }, - "node_modules/precinct": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/precinct/-/precinct-9.0.1.tgz", - "integrity": "sha512-hVNS6JvfvlZ64B3ezKeGAcVhIuOvuAiSVzagHX/+KjVPkYWoCNkfyMgCl1bjDtAFQSlzi95NcS9ykUWrl1L1vA==", - "dev": true, - "dependencies": { - "commander": "^9.1.0", - "detective-amd": "^4.0.1", - "detective-cjs": "^4.0.0", - "detective-es6": "^3.0.0", - "detective-less": "^1.0.2", - "detective-postcss": "^6.0.1", - "detective-sass": "^4.0.1", - "detective-scss": "^3.0.0", - "detective-stylus": "^2.0.0", - "detective-typescript": "^9.0.0", - "module-definition": "^4.0.0", - "node-source-walk": "^5.0.0" - }, - "bin": { - "precinct": "bin/cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.14.0 || >=16.0.0" - } - }, - "node_modules/precinct/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, - "node_modules/precinct/node_modules/module-definition": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-4.0.0.tgz", - "integrity": "sha512-wntiAHV4lDn24BQn2kX6LKq0y85phHLHiv3aOPDF+lIs06kVjEMTe/ZTdrbVLnQV5FQsjik21taknvMhKY1Cug==", - "dev": true, - "dependencies": { - "ast-module-types": "^3.0.0", - "node-source-walk": "^5.0.0" - }, - "bin": { - "module-definition": "bin/cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/precinct/node_modules/node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/precond": { "version": "0.2.3", "dev": true, @@ -13385,12 +12520,6 @@ "node": ">=8" } }, - "node_modules/quote-unquote": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/quote-unquote/-/quote-unquote-1.0.0.tgz", - "integrity": "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==", - "dev": true - }, "node_modules/random-number-csprng": { "version": "1.0.2", "dev": true, @@ -13400,14 +12529,6 @@ "create-error": "^0.3.1" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/react-is": { "version": "18.2.0", "dev": true, @@ -13639,30 +12760,6 @@ "node": ">=0.10.0" } }, - "node_modules/requirejs": { - "version": "2.3.6", - "dev": true, - "license": "MIT", - "bin": { - "r_js": "bin/r.js", - "r.js": "bin/r.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/requirejs-config-file": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "esprima": "^4.0.0", - "stringify-object": "^3.2.1" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/resolve": { "version": "1.22.0", "dev": true, @@ -13696,14 +12793,6 @@ "node": ">=8" } }, - "node_modules/resolve-dependency-path": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/resolve-from": { "version": "5.0.0", "dev": true, @@ -13837,109 +12926,37 @@ "regexp-tree": "~0.1.1" } }, - "node_modules/sass-lookup": { - "version": "3.0.0", + "node_modules/sax": { + "version": "1.2.1", "dev": true, - "license": "MIT", + "license": "ISC" + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dependencies": { - "commander": "^2.16.0" + "lru-cache": "^6.0.0" }, "bin": { - "sass-lookup": "bin/cli.js" + "semver": "bin/semver.js" }, "engines": { - "node": ">=6.0.0" + "node": ">=10" } }, - "node_modules/sass-lookup/node_modules/commander": { - "version": "2.20.3", - "dev": true, - "license": "MIT" - }, - "node_modules/sax": { - "version": "1.2.1", - "dev": true, - "license": "ISC" - }, - "node_modules/schema-utils": { - "version": "3.1.1", + "node_modules/sentence-case": { + "version": "3.0.4", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" } }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "6.12.6", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/schema-utils/node_modules/ajv-keywords": { - "version": "3.5.2", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sentence-case": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3", - "upper-case-first": "^2.0.2" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serialport": { - "version": "10.5.0", + "node_modules/serialport": { + "version": "10.5.0", "dev": true, "license": "MIT", "dependencies": { @@ -14091,15 +13108,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-support": { "version": "0.5.21", "dev": true, @@ -14289,27 +13297,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stringify-object": { - "version": "3.3.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/stringify-object/node_modules/is-obj": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "dev": true, @@ -14390,26 +13377,6 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/stylus-lookup": { - "version": "3.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^2.8.1", - "debug": "^4.1.0" - }, - "bin": { - "stylus-lookup": "bin/cli.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/stylus-lookup/node_modules/commander": { - "version": "2.20.3", - "dev": true, - "license": "MIT" - }, "node_modules/supports-color": { "version": "7.2.0", "dev": true, @@ -14432,187 +13399,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/table": { - "version": "6.8.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/slice-ansi": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/table/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.13.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map": "~0.8.0-beta.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker": { - "version": "27.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "dev": true, - "license": "MIT" - }, - "node_modules/terser/node_modules/source-map": { - "version": "0.8.0-beta.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/terser/node_modules/tr46": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/terser/node_modules/webidl-conversions": { - "version": "4.0.2", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/terser/node_modules/whatwg-url": { - "version": "7.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -14675,17 +13461,6 @@ "readable-stream": "3" } }, - "node_modules/tmp": { - "version": "0.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -14768,40 +13543,6 @@ "node": ">=8" } }, - "node_modules/ts-loader": { - "version": "9.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-loader/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/ts-node": { "version": "10.8.1", "dev": true, @@ -14844,36 +13585,6 @@ } } }, - "node_modules/tsconfig-paths": { - "version": "3.14.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/tslib": { "version": "2.4.0", "license": "0BSD" @@ -15126,18 +13837,6 @@ "makeerror": "1.0.12" } }, - "node_modules/watchpack": { - "version": "2.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/web-streams-polyfill": { "version": "3.2.1", "dev": true, @@ -15151,69 +13850,6 @@ "dev": true, "license": "BSD-2-Clause" }, - "node_modules/webpack": { - "version": "5.76.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz", - "integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/events": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, "node_modules/websocket-stream": { "version": "5.5.2", "dev": true, @@ -15523,8 +14159,9 @@ }, "node_modules/yazl": { "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", "dev": true, - "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3" } @@ -16185,50 +14822,6 @@ "tslib": "^2.3.1" } }, - "@aws-sdk/client-lambda": { - "version": "3.294.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.294.0.tgz", - "integrity": "sha512-zqkRsODF7R/4d597mjPExqyrRqwut+PCffQvLsfmxCnRHQPWVmMRBVl9xAvmsPM0mWlvrqcwa/GGOJplG3z/vQ==", - "dev": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.294.0", - "@aws-sdk/config-resolver": "3.292.0", - "@aws-sdk/credential-provider-node": "3.294.0", - "@aws-sdk/fetch-http-handler": "3.292.0", - "@aws-sdk/hash-node": "3.292.0", - "@aws-sdk/invalid-dependency": "3.292.0", - "@aws-sdk/middleware-content-length": "3.292.0", - "@aws-sdk/middleware-endpoint": "3.292.0", - "@aws-sdk/middleware-host-header": "3.292.0", - "@aws-sdk/middleware-logger": "3.292.0", - "@aws-sdk/middleware-recursion-detection": "3.292.0", - "@aws-sdk/middleware-retry": "3.293.0", - "@aws-sdk/middleware-serde": "3.292.0", - "@aws-sdk/middleware-signing": "3.292.0", - "@aws-sdk/middleware-stack": "3.292.0", - "@aws-sdk/middleware-user-agent": "3.293.0", - "@aws-sdk/node-config-provider": "3.292.0", - "@aws-sdk/node-http-handler": "3.292.0", - "@aws-sdk/protocol-http": "3.292.0", - "@aws-sdk/smithy-client": "3.292.0", - "@aws-sdk/types": "3.292.0", - "@aws-sdk/url-parser": "3.292.0", - "@aws-sdk/util-base64": "3.292.0", - "@aws-sdk/util-body-length-browser": "3.292.0", - "@aws-sdk/util-body-length-node": "3.292.0", - "@aws-sdk/util-defaults-mode-browser": "3.292.0", - "@aws-sdk/util-defaults-mode-node": "3.292.0", - "@aws-sdk/util-endpoints": "3.293.0", - "@aws-sdk/util-retry": "3.292.0", - "@aws-sdk/util-user-agent-browser": "3.292.0", - "@aws-sdk/util-user-agent-node": "3.292.0", - "@aws-sdk/util-utf8": "3.292.0", - "@aws-sdk/util-waiter": "3.292.0", - "tslib": "^2.3.1" - } - }, "@aws-sdk/client-s3": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.294.0.tgz", @@ -19237,6 +17830,14 @@ } } }, + "@nordicsemiconductor/asset-tracker-cloud-docs": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@nordicsemiconductor/asset-tracker-cloud-docs/-/asset-tracker-cloud-docs-28.1.3.tgz", + "integrity": "sha512-4K031jjsQMoBQ2/LsnkxkM6qHMSgLZRP3kNt2gei+uffgIsd7nmphYvx1sbEM+YtLlLPHH5B2/eaOfyK3mFumg==", + "requires": { + "@sinclair/typebox": "0.25.24" + } + }, "@nordicsemiconductor/cell-geolocation-helpers": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@nordicsemiconductor/cell-geolocation-helpers/-/cell-geolocation-helpers-6.0.0.tgz", @@ -19282,6 +17883,15 @@ "toposort": "2.0.2" }, "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -19291,6 +17901,28 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } } } }, @@ -19306,9 +17938,9 @@ } }, "@nordicsemiconductor/firmware-ci-device-helpers": { - "version": "14.0.11", - "resolved": "https://registry.npmjs.org/@nordicsemiconductor/firmware-ci-device-helpers/-/firmware-ci-device-helpers-14.0.11.tgz", - "integrity": "sha512-0SaMJgs8VC4gPi8UPyO9BPXmMA3LBH1iP6i7xfjnP2UN/q5RSxMyJPqZsJB5kRAt4SAOr3ulwzS4qHYgPDqKrQ==", + "version": "14.0.12", + "resolved": "https://registry.npmjs.org/@nordicsemiconductor/firmware-ci-device-helpers/-/firmware-ci-device-helpers-14.0.12.tgz", + "integrity": "sha512-/EKJO/7IjPxwjnk4EwHD2JZLNpQ1ScRhgKKNBTPm/lwyZYWVEsB/oF552ki2GEYopPO+XKt0dh7xY48goTO1WQ==", "dev": true, "requires": { "@serialport/parser-readline": "10.5.0", @@ -19335,39 +17967,6 @@ "change-case": "4.1.2" } }, - "@nordicsemiconductor/package-layered-lambdas": { - "version": "12.0.10", - "resolved": "https://registry.npmjs.org/@nordicsemiconductor/package-layered-lambdas/-/package-layered-lambdas-12.0.10.tgz", - "integrity": "sha512-tj5doUhgaK2PvT63Le5I3lBMpLaTZsZLBMTPhB1MXrFX7wVS5nnSe6PWdZ2KuVSz1jKQscoi8a0/jYimrB9Zgg==", - "dev": true, - "requires": { - "@aws-sdk/client-cloudformation": "3.294.0", - "@aws-sdk/client-lambda": "3.294.0", - "@aws-sdk/client-s3": "3.294.0", - "ansi-escapes": "4.3.2", - "aws-lambda": "1.0.7", - "chalk": "4.1.2", - "dependency-tree": "9.0.0", - "glob": "8.1.0", - "table": "6.8.1", - "tmp": "0.2.1", - "ts-loader": "9.4.2", - "webpack": "5.76.2", - "yazl": "2.5.1" - }, - "dependencies": { - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - } - } - }, "@nordicsemiconductor/random-words": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@nordicsemiconductor/random-words/-/random-words-7.0.0.tgz", @@ -20006,26 +18605,6 @@ "@types/chai": "*" } }, - "@types/eslint": { - "version": "8.4.1", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.3", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "0.0.51", - "dev": true - }, "@types/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", @@ -20083,10 +18662,6 @@ "version": "7.0.11", "dev": true }, - "@types/json5": { - "version": "0.0.29", - "dev": true - }, "@types/jsonwebtoken": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", @@ -20181,6 +18756,15 @@ "version": "21.0.0", "dev": true }, + "@types/yazl": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/yazl/-/yazl-2.4.2.tgz", + "integrity": "sha512-T+9JH8O2guEjXNxqmybzQ92mJUh2oCwDDMSSimZSe1P+pceZiFROZLYmcbqkzV5EUwz6VwcKXCO2S2yUpra6XQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@typescript-eslint/eslint-plugin": { "version": "5.55.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz", @@ -20281,138 +18865,9 @@ "eslint-visitor-keys": "^3.3.0" } }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "dev": true - }, - "acorn": { - "version": "8.8.0", - "dev": true - }, - "acorn-import-assertions": { - "version": "1.8.0", - "dev": true, - "requires": {} + "acorn": { + "version": "8.8.0", + "dev": true }, "acorn-jsx": { "version": "5.3.2", @@ -20474,10 +18929,6 @@ "picomatch": "^2.0.4" } }, - "app-module-path": { - "version": "2.2.0", - "dev": true - }, "arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -20515,10 +18966,6 @@ "version": "1.1.0", "dev": true }, - "ast-module-types": { - "version": "3.0.0", - "dev": true - }, "astral-regex": { "version": "2.0.0", "dev": true @@ -20707,22 +19154,6 @@ } } }, - "aws-lambda": { - "version": "1.0.7", - "dev": true, - "requires": { - "aws-sdk": "^2.814.0", - "commander": "^3.0.2", - "js-yaml": "^3.14.1", - "watchpack": "^2.0.0-beta.10" - }, - "dependencies": { - "commander": { - "version": "3.0.2", - "dev": true - } - } - }, "aws-sdk": { "version": "2.1338.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1338.0.tgz", @@ -21024,6 +19455,8 @@ }, "buffer-crc32": { "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, "buffer-equal-constant-time": { @@ -21186,10 +19619,6 @@ } } }, - "chrome-trace-event": { - "version": "1.0.3", - "dev": true - }, "ci-info": { "version": "3.6.1", "dev": true @@ -21574,25 +20003,6 @@ "object-keys": "^1.1.1" } }, - "dependency-tree": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/dependency-tree/-/dependency-tree-9.0.0.tgz", - "integrity": "sha512-osYHZJ1fBSon3lNLw70amAXsQ+RGzXsPvk9HbBgTLbp/bQBmpH5mOmsUvqXU+YEWVU0ZLewsmzOET/8jWswjDQ==", - "dev": true, - "requires": { - "commander": "^2.20.3", - "debug": "^4.3.1", - "filing-cabinet": "^3.0.1", - "precinct": "^9.0.0", - "typescript": "^4.0.0" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "dev": true - } - } - }, "deprecation": { "version": "2.3.1", "dev": true @@ -21603,163 +20013,6 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, - "detective-amd": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/detective-amd/-/detective-amd-4.0.1.tgz", - "integrity": "sha512-bDo22IYbJ8yzALB0Ow5CQLtyhU1BpDksLB9dsWHI9Eh0N3OQR6aQqhjPsNDd69ncYwRfL1sTo7OA9T3VRVSe2Q==", - "dev": true, - "requires": { - "ast-module-types": "^3.0.0", - "escodegen": "^2.0.0", - "get-amd-module-type": "^4.0.0", - "node-source-walk": "^5.0.0" - }, - "dependencies": { - "node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "requires": { - "@babel/parser": "^7.0.0" - } - } - } - }, - "detective-cjs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detective-cjs/-/detective-cjs-4.0.0.tgz", - "integrity": "sha512-VsD6Yo1+1xgxJWoeDRyut7eqZ8EWaJI70C5eanSAPcBHzenHZx0uhjxaaEfIm0cHII7dBiwU98Orh44bwXN2jg==", - "dev": true, - "requires": { - "ast-module-types": "^3.0.0", - "node-source-walk": "^5.0.0" - }, - "dependencies": { - "node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "requires": { - "@babel/parser": "^7.0.0" - } - } - } - }, - "detective-es6": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/detective-es6/-/detective-es6-3.0.0.tgz", - "integrity": "sha512-Uv2b5Uih7vorYlqGzCX+nTPUb4CMzUAn3VPHTV5p5lBkAN4cAApLGgUz4mZE2sXlBfv4/LMmeP7qzxHV/ZcfWA==", - "dev": true, - "requires": { - "node-source-walk": "^5.0.0" - }, - "dependencies": { - "node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "requires": { - "@babel/parser": "^7.0.0" - } - } - } - }, - "detective-less": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/detective-less/-/detective-less-1.0.2.tgz", - "integrity": "sha512-Rps1xDkEEBSq3kLdsdnHZL1x2S4NGDcbrjmd4q+PykK5aJwDdP5MBgrJw1Xo+kyUHuv3JEzPqxr+Dj9ryeDRTA==", - "dev": true, - "requires": { - "debug": "^4.0.0", - "gonzales-pe": "^4.2.3", - "node-source-walk": "^4.0.0" - } - }, - "detective-postcss": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detective-postcss/-/detective-postcss-6.1.0.tgz", - "integrity": "sha512-ZFZnEmUrL2XHAC0j/4D1fdwZbo/anAcK84soJh7qc7xfx2Kc8gFO5Bk5I9jU7NLC/OAF1Yho1GLxEDnmQnRH2A==", - "dev": true, - "requires": { - "is-url": "^1.2.4", - "postcss": "^8.4.12", - "postcss-values-parser": "^6.0.2" - } - }, - "detective-sass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/detective-sass/-/detective-sass-4.0.1.tgz", - "integrity": "sha512-80zfpxux1krOrkxCHbtwvIs2gNHUBScnSqlGl0FvUuHVz8HD6vD2ov66OroMctyvzhM67fxhuEeVjIk18s6yTQ==", - "dev": true, - "requires": { - "gonzales-pe": "^4.3.0", - "node-source-walk": "^5.0.0" - }, - "dependencies": { - "node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "requires": { - "@babel/parser": "^7.0.0" - } - } - } - }, - "detective-scss": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/detective-scss/-/detective-scss-3.0.0.tgz", - "integrity": "sha512-37MB/mhJyS45ngqfzd6eTbuLMoDgdZnH03ZOMW2m9WqJ/Rlbuc8kZAr0Ypovaf1DJiTRzy5mmxzOTja85jbzlA==", - "dev": true, - "requires": { - "gonzales-pe": "^4.3.0", - "node-source-walk": "^5.0.0" - }, - "dependencies": { - "node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "requires": { - "@babel/parser": "^7.0.0" - } - } - } - }, - "detective-stylus": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detective-stylus/-/detective-stylus-2.0.1.tgz", - "integrity": "sha512-/Tvs1pWLg8eYwwV6kZQY5IslGaYqc/GACxjcaGudiNtN5nKCH6o2WnJK3j0gA3huCnoQcbv8X7oz/c1lnvE3zQ==", - "dev": true - }, - "detective-typescript": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/detective-typescript/-/detective-typescript-9.0.0.tgz", - "integrity": "sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "^5.13.0", - "ast-module-types": "^3.0.0", - "node-source-walk": "^5.0.0", - "typescript": "^4.5.5" - }, - "dependencies": { - "node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "requires": { - "@babel/parser": "^7.0.0" - } - } - } - }, "diff": { "version": "4.0.2", "dev": true @@ -21842,14 +20095,6 @@ "once": "^1.4.0" } }, - "enhanced-resolve": { - "version": "5.10.0", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, "entities": { "version": "4.4.0" }, @@ -21889,10 +20134,6 @@ "unbox-primitive": "^1.0.2" } }, - "es-module-lexer": { - "version": "0.9.3", - "dev": true - }, "es-to-primitive": { "version": "1.2.1", "dev": true, @@ -21943,66 +20184,6 @@ "version": "4.0.0", "dev": true }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, "eslint": { "version": "8.36.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", @@ -22364,35 +20545,6 @@ "flat-cache": "^3.0.4" } }, - "filing-cabinet": { - "version": "3.3.0", - "dev": true, - "requires": { - "app-module-path": "^2.2.0", - "commander": "^2.20.3", - "debug": "^4.3.3", - "enhanced-resolve": "^5.8.3", - "is-relative-path": "^1.0.2", - "module-definition": "^3.3.1", - "module-lookup-amd": "^7.0.1", - "resolve": "^1.21.0", - "resolve-dependency-path": "^2.0.0", - "sass-lookup": "^3.0.0", - "stylus-lookup": "^3.0.1", - "tsconfig-paths": "^3.10.1", - "typescript": "^3.9.7" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "dev": true - }, - "typescript": { - "version": "3.9.10", - "dev": true - } - } - }, "fill-range": { "version": "7.0.1", "dev": true, @@ -22434,9 +20586,6 @@ "fetch-blob": "^3.1.2" } }, - "fp-ts": { - "version": "2.13.1" - }, "fs-extra": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", @@ -22483,27 +20632,6 @@ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true }, - "get-amd-module-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/get-amd-module-type/-/get-amd-module-type-4.0.0.tgz", - "integrity": "sha512-GbBawUCuA2tY8ztiMiVo3e3P95gc2TVrfYFfpUHdHQA8WyxMCckK29bQsVKhYX8SUf+w6JLhL2LG8tSC0ANt9Q==", - "dev": true, - "requires": { - "ast-module-types": "^3.0.0", - "node-source-walk": "^5.0.0" - }, - "dependencies": { - "node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "requires": { - "@babel/parser": "^7.0.0" - } - } - } - }, "get-caller-file": { "version": "2.0.5", "dev": true @@ -22521,10 +20649,6 @@ "has-symbols": "^1.0.3" } }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "dev": true - }, "get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -22578,27 +20702,30 @@ } }, "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.0.tgz", + "integrity": "sha512-EAZejC7JvnQINayvB/7BJbpZpNOJ8Lrw2OZNEvQxe0vaLn1SuwMcfV7/MNaX8L/T0wmptBFI4YMtDvSBxYDc7w==", "dev": true, "requires": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "dependencies": { "brace-expansion": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { "balanced-match": "^1.0.0" } }, "minimatch": { - "version": "5.0.1", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.2.tgz", + "integrity": "sha512-xy4q7wou3vUoC9k1xGTXc+awNdGaGVHtFUaey8tiX4H1QRc04DZ/rmDFwNm2EBsuYEhAZ6SgMmYf3InGY6OauA==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -22613,10 +20740,6 @@ "is-glob": "^4.0.3" } }, - "glob-to-regexp": { - "version": "0.4.1", - "dev": true - }, "global-dirs": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", @@ -22655,15 +20778,6 @@ "slash": "^3.0.0" } }, - "gonzales-pe": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz", - "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, "graceful-fs": { "version": "4.2.10", "dev": true @@ -22976,14 +21090,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-regexp": { - "version": "1.0.0", - "dev": true - }, - "is-relative-path": { - "version": "1.0.2", - "dev": true - }, "is-shared-array-buffer": { "version": "1.0.2", "dev": true, @@ -23029,18 +21135,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true - }, - "is-url-superb": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-url-superb/-/is-url-superb-4.0.0.tgz", - "integrity": "sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==", - "dev": true - }, "is-weakref": { "version": "1.0.2", "dev": true, @@ -24432,10 +22526,6 @@ } } }, - "loader-runner": { - "version": "4.3.0", - "dev": true - }, "locate-path": { "version": "6.0.0", "dev": true, @@ -24484,20 +22574,12 @@ "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", "dev": true }, - "lodash.sortby": { - "version": "4.7.0", - "dev": true - }, "lodash.startcase": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", "dev": true }, - "lodash.truncate": { - "version": "4.4.2", - "dev": true - }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -24680,13 +22762,6 @@ "version": "1.52.0", "dev": true }, - "mime-types": { - "version": "2.1.35", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, "mimic-fn": { "version": "2.1.0", "dev": true @@ -24723,6 +22798,12 @@ "kind-of": "^6.0.3" } }, + "minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "dev": true + }, "mnemonist": { "version": "0.38.3", "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", @@ -24731,43 +22812,6 @@ "obliterator": "^1.6.1" } }, - "module-definition": { - "version": "3.4.0", - "dev": true, - "requires": { - "ast-module-types": "^3.0.0", - "node-source-walk": "^4.0.0" - } - }, - "module-lookup-amd": { - "version": "7.0.1", - "dev": true, - "requires": { - "commander": "^2.8.1", - "debug": "^4.1.0", - "glob": "^7.1.6", - "requirejs": "^2.3.5", - "requirejs-config-file": "^4.0.0" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "dev": true - }, - "glob": { - "version": "7.2.0", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, "mqtt": { "version": "4.3.7", "dev": true, @@ -24803,12 +22847,6 @@ "ms": { "version": "2.1.2" }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "dev": true @@ -24816,11 +22854,7 @@ "natural-compare-lite": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "neo-async": { - "version": "2.6.2", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, "netrc": { @@ -24880,13 +22914,6 @@ "version": "2.0.6", "dev": true }, - "node-source-walk": { - "version": "4.3.0", - "dev": true, - "requires": { - "@babel/parser": "^7.0.0" - } - }, "nofilter": { "version": "3.1.0", "dev": true @@ -25086,6 +23113,24 @@ "version": "1.0.7", "dev": true }, + "path-scurry": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.1.tgz", + "integrity": "sha512-OW+5s+7cw6253Q4E+8qQ/u1fVvcJQCJo/VFD8pje+dbJCF1n5ZRMV2AEHbGp+5Q7jxQIYJxkHopnj6nzdGeZLA==", + "dev": true, + "requires": { + "lru-cache": "^7.14.1", + "minipass": "^4.0.2" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + } + } + }, "path-type": { "version": "4.0.0", "dev": true @@ -25166,75 +23211,6 @@ "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true }, - "postcss": { - "version": "8.4.20", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", - "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", - "dev": true, - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-values-parser": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-6.0.2.tgz", - "integrity": "sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==", - "dev": true, - "requires": { - "color-name": "^1.1.4", - "is-url-superb": "^4.0.0", - "quote-unquote": "^1.0.0" - } - }, - "precinct": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/precinct/-/precinct-9.0.1.tgz", - "integrity": "sha512-hVNS6JvfvlZ64B3ezKeGAcVhIuOvuAiSVzagHX/+KjVPkYWoCNkfyMgCl1bjDtAFQSlzi95NcS9ykUWrl1L1vA==", - "dev": true, - "requires": { - "commander": "^9.1.0", - "detective-amd": "^4.0.1", - "detective-cjs": "^4.0.0", - "detective-es6": "^3.0.0", - "detective-less": "^1.0.2", - "detective-postcss": "^6.0.1", - "detective-sass": "^4.0.1", - "detective-scss": "^3.0.0", - "detective-stylus": "^2.0.0", - "detective-typescript": "^9.0.0", - "module-definition": "^4.0.0", - "node-source-walk": "^5.0.0" - }, - "dependencies": { - "commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true - }, - "module-definition": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-4.0.0.tgz", - "integrity": "sha512-wntiAHV4lDn24BQn2kX6LKq0y85phHLHiv3aOPDF+lIs06kVjEMTe/ZTdrbVLnQV5FQsjik21taknvMhKY1Cug==", - "dev": true, - "requires": { - "ast-module-types": "^3.0.0", - "node-source-walk": "^5.0.0" - } - }, - "node-source-walk": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-5.0.0.tgz", - "integrity": "sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==", - "dev": true, - "requires": { - "@babel/parser": "^7.0.0" - } - } - } - }, "precond": { "version": "0.2.3", "dev": true @@ -25351,12 +23327,6 @@ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, - "quote-unquote": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/quote-unquote/-/quote-unquote-1.0.0.tgz", - "integrity": "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==", - "dev": true - }, "random-number-csprng": { "version": "1.0.2", "dev": true, @@ -25365,13 +23335,6 @@ "create-error": "^0.3.1" } }, - "randombytes": { - "version": "2.1.0", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, "react-is": { "version": "18.2.0", "dev": true @@ -25525,18 +23488,6 @@ "require-from-string": { "version": "2.0.2" }, - "requirejs": { - "version": "2.3.6", - "dev": true - }, - "requirejs-config-file": { - "version": "4.0.0", - "dev": true, - "requires": { - "esprima": "^4.0.0", - "stringify-object": "^3.2.1" - } - }, "resolve": { "version": "1.22.0", "dev": true, @@ -25559,10 +23510,6 @@ "resolve-from": "^5.0.0" } }, - "resolve-dependency-path": { - "version": "2.0.0", - "dev": true - }, "resolve-from": { "version": "5.0.0", "dev": true @@ -25649,53 +23596,10 @@ "regexp-tree": "~0.1.1" } }, - "sass-lookup": { - "version": "3.0.0", - "dev": true, - "requires": { - "commander": "^2.16.0" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "dev": true - } - } - }, "sax": { "version": "1.2.1", "dev": true }, - "schema-utils": { - "version": "3.1.1", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "3.5.2", - "dev": true, - "requires": {} - }, - "json-schema-traverse": { - "version": "0.4.1", - "dev": true - } - } - }, "semver": { "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", @@ -25713,13 +23617,6 @@ "upper-case-first": "^2.0.2" } }, - "serialize-javascript": { - "version": "6.0.0", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, "serialport": { "version": "10.5.0", "dev": true, @@ -25824,12 +23721,6 @@ "version": "0.6.1", "dev": true }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, "source-map-support": { "version": "0.5.21", "dev": true, @@ -25957,21 +23848,6 @@ "es-abstract": "^1.19.5" } }, - "stringify-object": { - "version": "3.3.0", - "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "dependencies": { - "is-obj": { - "version": "1.0.1", - "dev": true - } - } - }, "strip-ansi": { "version": "6.0.1", "dev": true, @@ -26019,20 +23895,6 @@ "peek-readable": "^5.0.0" } }, - "stylus-lookup": { - "version": "3.0.2", - "dev": true, - "requires": { - "commander": "^2.8.1", - "debug": "^4.1.0" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "dev": true - } - } - }, "supports-color": { "version": "7.2.0", "dev": true, @@ -26044,121 +23906,6 @@ "version": "1.0.0", "dev": true }, - "table": { - "version": "6.8.1", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - } - } - }, - "tapable": { - "version": "2.2.1", - "dev": true - }, - "terser": { - "version": "5.13.1", - "dev": true, - "requires": { - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map": "~0.8.0-beta.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "dev": true - }, - "source-map": { - "version": "0.8.0-beta.0", - "dev": true, - "requires": { - "whatwg-url": "^7.0.0" - } - }, - "tr46": { - "version": "1.0.1", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "dev": true - }, - "whatwg-url": { - "version": "7.1.0", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "terser-webpack-plugin": { - "version": "5.3.1", - "dev": true, - "requires": { - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - }, - "dependencies": { - "jest-worker": { - "version": "27.5.1", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -26209,13 +23956,6 @@ "readable-stream": "3" } }, - "tmp": { - "version": "0.2.1", - "dev": true, - "requires": { - "rimraf": "^3.0.0" - } - }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -26267,28 +24007,6 @@ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, - "ts-loader": { - "version": "9.4.2", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4" - }, - "dependencies": { - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - } - } - }, "ts-node": { "version": "10.8.1", "dev": true, @@ -26308,29 +24026,6 @@ "yn": "3.1.1" } }, - "tsconfig-paths": { - "version": "3.14.1", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "dev": true - } - } - }, "tslib": { "version": "2.4.0" }, @@ -26511,14 +24206,6 @@ "makeerror": "1.0.12" } }, - "watchpack": { - "version": "2.4.0", - "dev": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, "web-streams-polyfill": { "version": "3.2.1", "dev": true @@ -26527,48 +24214,6 @@ "version": "3.0.1", "dev": true }, - "webpack": { - "version": "5.76.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz", - "integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "dependencies": { - "events": { - "version": "3.3.0", - "dev": true - } - } - }, - "webpack-sources": { - "version": "3.2.3", - "dev": true - }, "websocket-stream": { "version": "5.5.2", "dev": true, @@ -26784,6 +24429,8 @@ }, "yazl": { "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", "dev": true, "requires": { "buffer-crc32": "~0.2.3" diff --git a/package.json b/package.json index 8ddea785b..afd12ccff 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,19 @@ "name": "@nordicsemiconductor/asset-tracker-cloud-aws", "version": "0.0.0-development", "description": "A reference implementation of a serverless backend for an IoT product developed using AWS CDK in TypeScript.", - "main": "./dist/export.js", + "types": "./export.d.ts", + "exports": { + ".": { + "import": "./export.js", + "node": "./export.js" + } + }, + "type": "module", "scripts": { "test": "jest --detectOpenHandles --forceExit", "test:e2e": "node --unhandled-rejections=strict --loader tsx feature-runner/run-features.ts ./features --print-results --progress", "prepare": "husky install && check-node-version --package", - "prepublishOnly": "npx tsc --noEmit false --outDir ./dist" + "prepublish": "npx swc -d dist ./cli npx swc -d dist ./features" }, "repository": { "type": "git", @@ -24,6 +31,7 @@ "author": "Nordic Semiconductor ASA | nordicsemi.no", "license": "BSD-3-Clause", "dependencies": { + "@nordicsemiconductor/asset-tracker-cloud-docs": "28.1.3", "@nordicsemiconductor/cell-geolocation-helpers": "6.0.0", "@nordicsemiconductor/nrfcloud-location-services-tests": "4.0.1", "@nordicsemiconductor/timestream-helpers": "5.0.0", @@ -31,7 +39,6 @@ "ajv": "8.12.0", "entities": "4.4.0", "fast-xml-parser": "4.1.3", - "fp-ts": "2.13.1", "jsonwebtoken": "9.0.0", "uuid": "9.0.0" }, @@ -54,9 +61,8 @@ "@nordicsemiconductor/asset-tracker-cloud-code-style": "12.0.5", "@nordicsemiconductor/cloudformation-helpers": "8.0.0", "@nordicsemiconductor/e2e-bdd-test-runner": "16.0.12", - "@nordicsemiconductor/firmware-ci-device-helpers": "14.0.11", + "@nordicsemiconductor/firmware-ci-device-helpers": "14.0.12", "@nordicsemiconductor/object-to-env": "5.0.0", - "@nordicsemiconductor/package-layered-lambdas": "12.0.10", "@nordicsemiconductor/random-words": "7.0.0", "@octokit/rest": "19.0.7", "@swc/cli": "0.1.62", @@ -70,6 +76,7 @@ "@types/jest": "29.5.0", "@types/jsonwebtoken": "9.0.1", "@types/node": "18.15.3", + "@types/yazl": "2.4.2", "aws-cdk-lib": "2.69.0", "aws-iot-device-sdk": "2.2.12", "backoff": "2.5.0", @@ -80,10 +87,12 @@ "commander": "10.0.0", "constructs": "10.1.283", "date-fns": "2.29.3", + "glob": "9.3.0", "jest": "29.5.0", "nock": "13.3.0", "octokit-auth-netrc": "2.1.0", - "tsx": "3.12.5" + "tsx": "3.12.5", + "yazl": "2.5.1" }, "lint-staged": { "*.{md,json,yaml,yml}": [ @@ -137,6 +146,10 @@ "@swc/jest" ] }, - "testRegex": ".+\\.spec\\.ts$" - } + "testRegex": ".+\\.spec\\.ts$", + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + } + }, + "prettier": "@nordicsemiconductor/asset-tracker-cloud-code-style/.prettierrc" } diff --git a/pgps/cacheKey.spec.ts b/pgps/cacheKey.spec.ts index 0c01956ba..77fd8a215 100644 --- a/pgps/cacheKey.spec.ts +++ b/pgps/cacheKey.spec.ts @@ -1,5 +1,5 @@ -import { cacheKey } from './cacheKey' -import { gpsDay } from './gpsTime' +import { cacheKey } from './cacheKey.js' +import { gpsDay } from './gpsTime.js' describe('cacheKey', () => { it('should create a cache key', () => diff --git a/pgps/cacheKey.ts b/pgps/cacheKey.ts index 158b44338..ed0af4bfc 100644 --- a/pgps/cacheKey.ts +++ b/pgps/cacheKey.ts @@ -1,6 +1,6 @@ -import { Static } from '@sinclair/typebox' -import { gpsDay } from './gpsTime' -import { pgpsRequestSchema } from './types' +import type { Static } from '@sinclair/typebox' +import { gpsDay } from './gpsTime.js' +import type { pgpsRequestSchema } from './types.js' // Default values, all properties for requests are optional export const defaultNumberOfPredictions = 42 diff --git a/pgps/deviceRequestHandler.ts b/pgps/deviceRequestHandler.ts index 065140b96..3f9e58175 100644 --- a/pgps/deviceRequestHandler.ts +++ b/pgps/deviceRequestHandler.ts @@ -9,22 +9,21 @@ import { SendMessageBatchRequestEntry, SQSClient, } from '@aws-sdk/client-sqs' -import { Static } from '@sinclair/typebox' -import { SQSEvent, SQSMessageAttributes } from 'aws-lambda' -import { isRight } from 'fp-ts/lib/These' +import type { Static } from '@sinclair/typebox' +import type { SQSEvent, SQSMessageAttributes } from 'aws-lambda' import { randomUUID } from 'node:crypto' -import { URL } from 'url' +import type { URL } from 'url' import { TextEncoder } from 'util' -import { fromEnv } from '../util/fromEnv' +import { fromEnv } from '../util/fromEnv.js' import { cacheKey, defaultInterval, defaultNumberOfPredictions, defaultTimeOfDay, -} from './cacheKey' -import { getCache, PGPSDataCache } from './getCache' -import { gpsDay } from './gpsTime' -import { pgpsRequestSchema } from './types' +} from './cacheKey.js' +import { getCache, PGPSDataCache } from './getCache.js' +import { gpsDay } from './gpsTime.js' +import type { pgpsRequestSchema } from './types.js' const { binHoursString, @@ -95,7 +94,7 @@ export const handler = async (event: SQSEvent): Promise => { if (grouped[k] === undefined) { grouped[k] = [deviceRequest] } else { - grouped[k].push(deviceRequest) + grouped[k]?.push(deviceRequest) } return grouped }, @@ -115,19 +114,10 @@ export const handler = async (event: SQSEvent): Promise => { if (resolvedRequests[cacheKey] === undefined) { console.debug(cacheKey, 'Load from DB') const d = await c(cacheKey) - if (isRight(d)) { - if (d.right?.unresolved !== undefined) { - console.debug(cacheKey, 'Processing of the request is finished') - resolvedRequests[cacheKey] = d.right - if (d.right.unresolved === true) { - console.error(cacheKey, `P-GPS request is unresolved.`) - return - } - } - } else { + if ('error' in d) { console.debug(cacheKey, 'cache does not exist') - console.warn({ getCache: d.left }) - const r = deviceRequests[0].request + console.warn({ getCache: d }) + const r = deviceRequests[0]?.request await Promise.all([ // Create DB entry await dynamodb @@ -139,16 +129,16 @@ export const handler = async (event: SQSEvent): Promise => { S: cacheKey, }, numPredictions: { - N: `${r.n ?? defaultNumberOfPredictions}`, + N: `${r?.n ?? defaultNumberOfPredictions}`, }, interval: { - N: `${r.int ?? defaultInterval}`, + N: `${r?.int ?? defaultInterval}`, }, gpsDay: { - N: `${r.day ?? gpsDay()}`, + N: `${r?.day ?? gpsDay()}`, }, timeOfDay: { - N: `${r.time ?? defaultTimeOfDay}`, + N: `${r?.time ?? defaultTimeOfDay}`, }, updatedAt: { S: new Date().toISOString(), @@ -191,13 +181,22 @@ export const handler = async (event: SQSEvent): Promise => { ) }), ]) + } else { + if (d.unresolved !== undefined) { + console.debug(cacheKey, 'Processing of the request is finished') + resolvedRequests[cacheKey] = d + if (d.unresolved === true) { + console.error(cacheKey, `P-GPS request is unresolved.`) + return + } + } } } // The data for these requests is available if ( resolvedRequests[cacheKey]?.unresolved !== undefined && - resolvedRequests[cacheKey].unresolved === false + resolvedRequests[cacheKey]?.unresolved === false ) { console.debug(cacheKey, 'data for these requests is available') console.debug( @@ -206,7 +205,7 @@ export const handler = async (event: SQSEvent): Promise => { resolvedRequests, }), ) - const url = resolvedRequests[cacheKey].url as URL + const url = resolvedRequests[cacheKey]?.url as URL await Promise.all( deviceRequests.map(async (deviceRequest) => iotData.send( diff --git a/pgps/getCache.ts b/pgps/getCache.ts index bb97d3908..f30c29f8f 100644 --- a/pgps/getCache.ts +++ b/pgps/getCache.ts @@ -1,10 +1,9 @@ import { DynamoDBClient, GetItemCommand } from '@aws-sdk/client-dynamodb' import { unmarshall } from '@aws-sdk/util-dynamodb' -import { Static } from '@sinclair/typebox' -import { Either, left, right } from 'fp-ts/lib/Either' +import type { Static } from '@sinclair/typebox' import { URL } from 'url' -import { ErrorInfo, ErrorType } from '../api/ErrorInfo' -import { pgpsRequestSchema } from './types' +import { ErrorInfo, ErrorType } from '../api/ErrorInfo.js' +import type { pgpsRequestSchema } from './types.js' export type PGPSDataCache = Static & { source: string @@ -15,7 +14,7 @@ export type PGPSDataCache = Static & { export const getCache = ({ dynamodb, TableName }: { dynamodb: DynamoDBClient; TableName: string }) => - async (cacheKey: string): Promise> => { + async (cacheKey: string): Promise<{ error: ErrorInfo } | PGPSDataCache> => { try { const { Item } = await dynamodb.send( new GetItemCommand({ @@ -42,16 +41,18 @@ export const getCache = getCache: { entry: i }, }), ) - return right(i) + return i } catch (err) { if ( (err as Error).message === 'NOT_FOUND' || (err as Error).name === 'ResourceNotFoundException' ) - return left({ - type: ErrorType.EntityNotFound, - message: `Report ${cacheKey} not found!`, - }) + return { + error: { + type: ErrorType.EntityNotFound, + message: `Report ${cacheKey} not found!`, + }, + } console.error( JSON.stringify({ getCache: { @@ -62,9 +63,11 @@ export const getCache = }, }), ) - return left({ - type: ErrorType.InternalError, - message: (err as Error).message, - }) + return { + error: { + type: ErrorType.InternalError, + message: (err as Error).message, + }, + } } } diff --git a/pgps/gpsTime.spec.ts b/pgps/gpsTime.spec.ts index 948d9f304..fbb8e8c2c 100644 --- a/pgps/gpsTime.spec.ts +++ b/pgps/gpsTime.spec.ts @@ -1,4 +1,4 @@ -import { gpsDay } from './gpsTime' +import { gpsDay } from './gpsTime.js' describe('GPS epoch time functions', () => { it('should calculate the GPS epoch day', () => { diff --git a/pgps/types.ts b/pgps/types.ts index b6e96b72f..92022295b 100644 --- a/pgps/types.ts +++ b/pgps/types.ts @@ -1,6 +1,9 @@ import { Type } from '@sinclair/typebox' -import { minimumGpsDay } from './gpsTime' +import { minimumGpsDay } from './gpsTime.js' +/** + * @see https://api.nrfcloud.com/v1#tag/Predicted-GPS/operation/GetPredictedAssistanceData + */ export const pgpsRequestSchema = Type.Object({ n: Type.Optional( Type.Integer({ minimum: 1, title: 'number of predictions' }), diff --git a/third-party/nrfcloud.com/agps.ts b/third-party/nrfcloud.com/agps.ts index 0f6a16bd9..440b4aa21 100644 --- a/third-party/nrfcloud.com/agps.ts +++ b/third-party/nrfcloud.com/agps.ts @@ -1,13 +1,13 @@ import { SSMClient } from '@aws-sdk/client-ssm' +import { validateWithType } from '@nordicsemiconductor/asset-tracker-cloud-docs/protocol' import { verify } from '@nordicsemiconductor/nrfcloud-location-services-tests' import { Static, Type } from '@sinclair/typebox' import { URL } from 'url' -import { agpsRequestSchema, AGPSType } from '../../agps/types' -import { ErrorInfo } from '../../api/ErrorInfo' -import { validateWithJSONSchema } from '../../api/validateWithJSONSchema' -import { fromEnv } from '../../util/fromEnv' -import { apiClient } from './apiclient' -import { getAGPSLocationApiSettings } from './settings' +import { agpsRequestSchema, AGPSType } from '../../agps/types.js' +import type { ErrorInfo } from '../../api/ErrorInfo.js' +import { fromEnv } from '../../util/fromEnv.js' +import { apiClient } from './apiclient.js' +import { getAGPSLocationApiSettings } from './settings.js' const { stackName } = fromEnv({ stackName: 'STACK_NAME', @@ -20,6 +20,9 @@ const settingsPromise = getAGPSLocationApiSettings({ const PositiveInteger = Type.Integer({ minimum: 1, title: 'positive integer' }) +/** + * @see https://api.nrfcloud.com/v1#tag/Assisted-GPS/operation/GetAssistanceData + */ const apiRequestSchema = Type.Object( { eci: PositiveInteger, @@ -32,14 +35,14 @@ const apiRequestSchema = Type.Object( { additionalProperties: false }, ) -const validateInput = validateWithJSONSchema(agpsRequestSchema) +const validateInput = validateWithType(agpsRequestSchema) export const handler = async ( agps: Static, ): Promise<{ resolved: boolean; dataHex?: readonly string[] }> => { console.log(JSON.stringify({ event: agps })) const maybeValidInput = validateInput(agps) - if ('error' in maybeValidInput) { + if ('errors' in maybeValidInput) { console.error(JSON.stringify(maybeValidInput)) return { resolved: false, diff --git a/third-party/nrfcloud.com/apiclient.spec.ts b/third-party/nrfcloud.com/apiclient.spec.ts index bf40c5613..b97df0789 100644 --- a/third-party/nrfcloud.com/apiclient.spec.ts +++ b/third-party/nrfcloud.com/apiclient.spec.ts @@ -1,4 +1,4 @@ -import { toQueryString } from './apiclient' +import { toQueryString } from './apiclient.js' describe('nRF Cloud API client', () => { it('should encode query strings', () => diff --git a/third-party/nrfcloud.com/apiclient.ts b/third-party/nrfcloud.com/apiclient.ts index dea815251..ecbbb4e73 100644 --- a/third-party/nrfcloud.com/apiclient.ts +++ b/third-party/nrfcloud.com/apiclient.ts @@ -1,10 +1,10 @@ -import { Static, TObject, TProperties } from '@sinclair/typebox' +import type { Static, TObject, TProperties } from '@sinclair/typebox' import Ajv from 'ajv' -import { IncomingHttpHeaders, OutgoingHttpHeaders } from 'http' +import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'http' import { request as nodeRequest, RequestOptions } from 'https' -import { URL } from 'url' -import { ErrorInfo, ErrorType } from '../../api/ErrorInfo' -import { createToken } from './createToken' +import type { URL } from 'url' +import { ErrorInfo, ErrorType } from '../../api/ErrorInfo.js' +import { createToken } from './createToken.js' const ajv = new Ajv() // see @https://github.com/sinclairzx81/typebox/issues/51 @@ -86,7 +86,7 @@ const doRequest = }) console.debug( - JSON.stringify({ doRequest: { options, payload } }, null, 2), + JSON.stringify({ doRequest: { request: { options, payload } } }), ) const req = nodeRequest(options, (res) => { diff --git a/third-party/nrfcloud.com/cellgeolocation.ts b/third-party/nrfcloud.com/cellgeolocation.ts index 430264cb3..dd8506291 100644 --- a/third-party/nrfcloud.com/cellgeolocation.ts +++ b/third-party/nrfcloud.com/cellgeolocation.ts @@ -1,15 +1,15 @@ import { SSMClient } from '@aws-sdk/client-ssm' import { NetworkMode } from '@nordicsemiconductor/cell-geolocation-helpers' -import { TObject, TProperties } from '@sinclair/typebox' +import type { TObject, TProperties } from '@sinclair/typebox' import { URL } from 'url' -import { MaybeCellGeoLocation } from '../../cellGeolocation/stepFunction/types' -import { Cell } from '../../geolocation/Cell' -import { parseMCCMNC } from '../../geolocation/parseMCCMNC' -import { fromEnv } from '../../util/fromEnv' -import { apiClient } from './apiclient' -import { groundFixRequestSchema } from './groundFixRequestSchema' -import { locateResultSchema } from './locate' -import { getGroundFixApiSettings } from './settings' +import type { MaybeCellGeoLocation } from '../../cellGeolocation/stepFunction/types.js' +import type { Cell } from '../../geolocation/Cell.js' +import { parseMCCMNC } from '../../geolocation/parseMCCMNC.js' +import { fromEnv } from '../../util/fromEnv.js' +import { apiClient } from './apiclient.js' +import { groundFixRequestSchema } from './groundFixRequestSchema.js' +import { locateResultSchema } from './locate.js' +import { getGroundFixApiSettings } from './settings.js' const { stackName } = fromEnv({ stackName: 'STACK_NAME' })(process.env) diff --git a/third-party/nrfcloud.com/createToken.spec.ts b/third-party/nrfcloud.com/createToken.spec.ts index 29ef0551f..83e73e0dc 100644 --- a/third-party/nrfcloud.com/createToken.spec.ts +++ b/third-party/nrfcloud.com/createToken.spec.ts @@ -1,7 +1,7 @@ import { execSync } from 'child_process' import { randomUUID } from 'crypto' -import * as jwt from 'jsonwebtoken' -import { createToken } from './createToken' +import jwt from 'jsonwebtoken' +import { createToken } from './createToken.js' describe('createToken', () => { it('should create a token', () => { diff --git a/third-party/nrfcloud.com/createToken.ts b/third-party/nrfcloud.com/createToken.ts index 88d9016fa..36c045c3d 100644 --- a/third-party/nrfcloud.com/createToken.ts +++ b/third-party/nrfcloud.com/createToken.ts @@ -1,4 +1,4 @@ -import * as jwt from 'jsonwebtoken' +import jwt from 'jsonwebtoken' export const createToken = (teamId: string, serviceKey: string): string => jwt.sign({ aud: teamId }, serviceKey, { diff --git a/third-party/nrfcloud.com/groundFixRequestSchema.spec.ts b/third-party/nrfcloud.com/groundFixRequestSchema.spec.ts index 77adc188d..79e691b8a 100644 --- a/third-party/nrfcloud.com/groundFixRequestSchema.spec.ts +++ b/third-party/nrfcloud.com/groundFixRequestSchema.spec.ts @@ -1,6 +1,6 @@ -import { Static } from '@sinclair/typebox' +import type { Static } from '@sinclair/typebox' import Ajv from 'ajv' -import { groundFixRequestSchema } from './groundFixRequestSchema' +import { groundFixRequestSchema } from './groundFixRequestSchema.js' const ajv = new Ajv() // see @https://github.com/sinclairzx81/typebox/issues/51 diff --git a/third-party/nrfcloud.com/groundFixRequestSchema.ts b/third-party/nrfcloud.com/groundFixRequestSchema.ts index 74651c614..9d652cfa0 100644 --- a/third-party/nrfcloud.com/groundFixRequestSchema.ts +++ b/third-party/nrfcloud.com/groundFixRequestSchema.ts @@ -1,30 +1,30 @@ import { Type } from '@sinclair/typebox' -export const RSRP = Type.Integer({ +const RSRP = Type.Integer({ minimum: -157, maximum: -44, title: 'RSRP: Reference Signal Received Power. Measured in dBm. See this page for more details. Range -157..-44', }) -export const RSRQ = Type.Number({ +const RSRQ = Type.Number({ minimum: -34.5, maximum: 3.5, title: 'RSRQ: Reference Signal Received Quality. Measured in dB. See this page for more details. Range -34.5..3.5', }) -export const TimingAdvance = Type.Integer({ +const TimingAdvance = Type.Integer({ minimum: -34.5, maximum: 20512, title: 'TimingAdvance: The length of time a signal takes to reach the base station from a mobile phone (half of rtt=round trip time). The units are symbols (Ts) as specified in 3GPP TS 36.211 (LTE). The expected resolution for nRF Cloud API is 1 Ts. Range 0..20512. ', }) -export const EARFCN = Type.Integer({ +const EARFCN = Type.Integer({ description: 'Evolved Absolute Radio Frequency Channel (E-ARFCN). Range: 0..262143', minimum: 0, maximum: 262143, }) -export const PCI = Type.Integer({ +const PCI = Type.Integer({ description: 'Physical Cell Identity (PCI). Range: 0..503', minimum: 0, maximum: 504, @@ -83,6 +83,9 @@ const wifiSiteSurvey = Type.Object({ ), }) +/** + * @see https://api.nrfcloud.com/v1#tag/Ground-Fix/operation/GetLocationFromCellTowersOrWifiNetworks + */ export const groundFixRequestSchema = Type.Object( { lte: Type.Optional(neighboringCellsSurvey), diff --git a/third-party/nrfcloud.com/locate.ts b/third-party/nrfcloud.com/locate.ts index 2d0454a98..e810c11fc 100644 --- a/third-party/nrfcloud.com/locate.ts +++ b/third-party/nrfcloud.com/locate.ts @@ -1,5 +1,8 @@ import { Type } from '@sinclair/typebox' +/** + * @see https://api.nrfcloud.com/v1#tag/Ground-Fix/operation/GetLocationFromCellTowersOrWifiNetworks + */ export const locateResultSchema = Type.Object({ lat: Type.Number({ minimum: -90, maximum: 90 }), lon: Type.Number({ minimum: -180, maximum: 180 }), diff --git a/third-party/nrfcloud.com/networksurveygeolocation.ts b/third-party/nrfcloud.com/networksurveygeolocation.ts index 11bca247b..ec5707f84 100644 --- a/third-party/nrfcloud.com/networksurveygeolocation.ts +++ b/third-party/nrfcloud.com/networksurveygeolocation.ts @@ -1,20 +1,18 @@ import { SSMClient } from '@aws-sdk/client-ssm' +import { + NeighboringCellMeasurements, + validateWithType, + WiFiSiteSurvey, +} from '@nordicsemiconductor/asset-tracker-cloud-docs/protocol' import { Static, TObject, TProperties, Type } from '@sinclair/typebox' import { URL } from 'url' -import { validateWithJSONSchema } from '../../api/validateWithJSONSchema' -import { MaybeLocation } from '../../geolocation/types' -import { expandMac } from '../../networkSurveyGeolocation/expandMac' -import { fromEnv } from '../../util/fromEnv' -import { apiClient } from './apiclient' -import { - EARFCN, - groundFixRequestSchema, - RSRP, - RSRQ, - TimingAdvance, -} from './groundFixRequestSchema' -import { locateResultSchema } from './locate' -import { getGroundFixApiSettings } from './settings' +import type { MaybeLocation } from '../../geolocation/types.js' +import { expandMac } from '../../networkSurveyGeolocation/expandMac.js' +import { fromEnv } from '../../util/fromEnv.js' +import { apiClient } from './apiclient.js' +import { groundFixRequestSchema } from './groundFixRequestSchema.js' +import { locateResultSchema } from './locate.js' +import { getGroundFixApiSettings } from './settings.js' const { stackName } = fromEnv({ stackName: 'STACK_NAME', @@ -30,42 +28,11 @@ const networkSurveyLocateInputSchema = Type.Object({ deviceId: Type.String(), timestamp: Type.String(), nw: Type.String({ minLength: 1 }), - lte: Type.Optional( - Type.Object({ - mcc: Type.Integer({ minimum: 100, maximum: 999 }), - mnc: Type.Integer({ minimum: 0, maximum: 999 }), - cell: Type.Integer({ minimum: 1 }), - area: Type.Integer({ minimum: 1 }), - earfcn: Type.Optional(EARFCN), - adv: Type.Optional(TimingAdvance), - rsrp: Type.Optional(RSRP), - rsrq: Type.Optional(RSRQ), - nmr: Type.Optional( - Type.Array( - Type.Object( - { - cell: Type.Integer({ minimum: 1 }), - earfcn: Type.Integer({ minimum: 1 }), - rsrp: RSRP, - rsrq: RSRQ, - }, - { additionalProperties: false }, - ), - { minItems: 1 }, - ), - ), - ts: Type.Integer({ minimum: 1 }), - }), - ), - wifi: Type.Optional( - Type.Object({ - ts: Type.Integer({ minimum: 1 }), - aps: Type.Array(Type.String()), - }), - ), + lte: Type.Optional(NeighboringCellMeasurements), + wifi: Type.Optional(WiFiSiteSurvey), }) -const validateInput = validateWithJSONSchema(networkSurveyLocateInputSchema) +const validateInput = validateWithType(networkSurveyLocateInputSchema) export const handler = async ( event: Static, @@ -76,7 +43,7 @@ export const handler = async ( const c = apiClient({ endpoint: new URL(endpoint), serviceKey, teamId }) const maybeValidInput = validateInput(event) - if ('error' in maybeValidInput) { + if ('errors' in maybeValidInput) { console.error(JSON.stringify(maybeValidInput)) return { located: false, diff --git a/third-party/nrfcloud.com/pgps.ts b/third-party/nrfcloud.com/pgps.ts index 169d6933a..9e8bd130a 100644 --- a/third-party/nrfcloud.com/pgps.ts +++ b/third-party/nrfcloud.com/pgps.ts @@ -1,17 +1,17 @@ import { SSMClient } from '@aws-sdk/client-ssm' +import { validateWithType } from '@nordicsemiconductor/asset-tracker-cloud-docs/protocol' import { Static, Type } from '@sinclair/typebox' import { URL } from 'url' -import { validateWithJSONSchema } from '../../api/validateWithJSONSchema' import { defaultInterval, defaultNumberOfPredictions, defaultTimeOfDay, -} from '../../pgps/cacheKey' -import { gpsDay, minimumGpsDay } from '../../pgps/gpsTime' -import { pgpsRequestSchema } from '../../pgps/types' -import { fromEnv } from '../../util/fromEnv' -import { apiClient } from './apiclient' -import { getPGPSLocationApiSettings } from './settings' +} from '../../pgps/cacheKey.js' +import { gpsDay, minimumGpsDay } from '../../pgps/gpsTime.js' +import { pgpsRequestSchema } from '../../pgps/types.js' +import { fromEnv } from '../../util/fromEnv.js' +import { apiClient } from './apiclient.js' +import { getPGPSLocationApiSettings } from './settings.js' const { stackName } = fromEnv({ stackName: 'STACK_NAME' })(process.env) @@ -26,6 +26,10 @@ enum Interval { sixHours = 360, eightHours = 480, } + +/** + * @see https://api.nrfcloud.com/v1#tag/Predicted-GPS/operation/GetPredictedAssistanceData + */ const apiRequestSchema = Type.Object( { predictionCount: Type.Optional( @@ -56,6 +60,9 @@ const apiRequestSchema = Type.Object( { additionalProperties: false }, ) +/** + * @see https://api.nrfcloud.com/v1#tag/Predicted-GPS/operation/GetPredictedAssistanceData + */ const apiResponseSchema = Type.Object( { path: Type.String({ minLength: 1 }), @@ -64,14 +71,14 @@ const apiResponseSchema = Type.Object( { additionalProperties: false }, ) -const validateInput = validateWithJSONSchema(pgpsRequestSchema) +const validateInput = validateWithType(pgpsRequestSchema) export const handler = async ( pgps: Static, ): Promise<{ resolved: boolean; url?: URL }> => { console.log(JSON.stringify(pgps)) const maybeValidInput = validateInput(pgps) - if ('error' in maybeValidInput) { + if ('errors' in maybeValidInput) { console.error(JSON.stringify(maybeValidInput)) return { resolved: false, diff --git a/third-party/nrfcloud.com/settings.ts b/third-party/nrfcloud.com/settings.ts index 6a5491398..3d36aa479 100644 --- a/third-party/nrfcloud.com/settings.ts +++ b/third-party/nrfcloud.com/settings.ts @@ -1,5 +1,5 @@ -import { SSMClient } from '@aws-sdk/client-ssm' -import { getSettings } from '../../util/settings' +import type { SSMClient } from '@aws-sdk/client-ssm' +import { getSettings } from '../../util/settings.js' type nRFCloudLocationService = 'agpsLocation' | 'pgpsLocation' | 'groundFix' @@ -33,7 +33,7 @@ const getApiSettings = if (p[serviceKeyProperty(service)] === undefined) throw new Error(`No nRF Cloud service key configured for ${service}!`) return { - serviceKey: p[serviceKeyProperty(service)], + serviceKey: p[serviceKeyProperty(service)] as nRFCloudLocationService, endpoint: endpoint ?? 'https://api.nrfcloud.com/', teamId, } diff --git a/tsconfig.json b/tsconfig.json index ac81102b4..eb1e29fdc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,21 @@ { - "extends": "@nordicsemiconductor/asset-tracker-cloud-code-style/tsconfig.json", - "include": ["**/*.ts"], "compilerOptions": { + "target": "esnext", + "module": "ESNext", + "moduleResolution": "node", + "resolveJsonModule": true, + "esModuleInterop": true, + "strict": true, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, "noEmit": true, - "esModuleInterop": true + "importsNotUsedAsValues": "error", + "skipLibCheck": true } } diff --git a/util/fp-ts.ts b/util/fp-ts.ts deleted file mode 100644 index eb61e05f8..000000000 --- a/util/fp-ts.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Option } from 'fp-ts/lib/Option' -import { getOptionM } from 'fp-ts/lib/OptionT' -import { TaskEither, taskEither } from 'fp-ts/lib/TaskEither' - -const MTE = getOptionM(taskEither) -export const TE = - ( - onNone: () => TaskEither, - ): ((ma: TaskEither>) => TaskEither) => - (ma) => - MTE.getOrElse(ma, onNone) - -export const getOrElse = { - TE, -} diff --git a/util/paginate.ts b/util/paginate.ts index 38400fdd9..1bf4b9587 100644 --- a/util/paginate.ts +++ b/util/paginate.ts @@ -1,5 +1,5 @@ -import { isEmpty } from './isNotEmpty' -import { isNullOrUndefined } from './isNullOrUndefined' +import { isEmpty } from './isNotEmpty.js' +import { isNullOrUndefined } from './isNullOrUndefined.js' /** * Iteratively follows paginated results. diff --git a/util/parseJSON.ts b/util/parseJSON.ts new file mode 100644 index 000000000..bb70bc484 --- /dev/null +++ b/util/parseJSON.ts @@ -0,0 +1,9 @@ +export const parseJSON = ( + json: string, +): { error: Error } | { json: Record } => { + try { + return JSON.parse(json) + } catch (error) { + return { error: error as Error } + } +} diff --git a/util/settings.ts b/util/settings.ts index a190d515d..887df9478 100644 --- a/util/settings.ts +++ b/util/settings.ts @@ -5,7 +5,7 @@ import { PutParameterCommand, SSMClient, } from '@aws-sdk/client-ssm' -import { paginate } from './paginate' +import { paginate } from './paginate.js' type Scopes = 'context' | 'config' | 'thirdParty' | 'codebuild' type Systems = 'stack' | 'github' | 'nrfcloud' | 'sentry'