From 43310611209306bee910f623cb9bbcc92c439e6c Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Wed, 25 Oct 2023 17:29:44 +0100 Subject: [PATCH] chore: appease linter --- .eslintignore | 3 +- billing/functions/space-billing-queue.js | 1 - billing/functions/ucan-stream.js | 1 - billing/functions/usage-table.js | 61 +++++++---------------- billing/lib/billing-cron.js | 1 + billing/lib/customer-billing-queue.js | 1 + billing/lib/space-billing-queue.js | 1 + billing/lib/usage-table.js | 7 --- filecoin/test/helpers/resources.js | 10 ++-- stacks/billing-db-stack.js | 5 +- stacks/billing-stack.js | 3 +- tsconfig.json | 3 +- ucan-invocation/test/helpers/resources.js | 3 +- upload-api/test/helpers/resources.js | 3 +- 14 files changed, 39 insertions(+), 64 deletions(-) delete mode 100644 billing/lib/usage-table.js diff --git a/.eslintignore b/.eslintignore index 763301fc..2d0c0644 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ dist/ -node_modules/ \ No newline at end of file +node_modules/ +coverage/ diff --git a/billing/functions/space-billing-queue.js b/billing/functions/space-billing-queue.js index d91a9e8d..36384569 100644 --- a/billing/functions/space-billing-queue.js +++ b/billing/functions/space-billing-queue.js @@ -17,7 +17,6 @@ Sentry.AWSLambda.init({ * spaceDiffTable?: string * spaceSnapshotTable?: string * usageTable?: string - * dbEndpoint?: URL * region?: 'us-west-2'|'us-east-2' * }} CustomHandlerContext */ diff --git a/billing/functions/ucan-stream.js b/billing/functions/ucan-stream.js index 3a6a5dc8..9acff409 100644 --- a/billing/functions/ucan-stream.js +++ b/billing/functions/ucan-stream.js @@ -18,7 +18,6 @@ Sentry.AWSLambda.init({ * spaceDiffTable?: string * subscriptionTable?: string * consumerTable?: string - * dbEndpoint?: URL * region?: 'us-west-2'|'us-east-2' * }} CustomHandlerContext */ diff --git a/billing/functions/usage-table.js b/billing/functions/usage-table.js index f996d93f..26596bbf 100644 --- a/billing/functions/usage-table.js +++ b/billing/functions/usage-table.js @@ -1,11 +1,6 @@ import * as Sentry from '@sentry/serverless' -import { toString, fromString } from 'uint8arrays' -import * as Link from 'multiformats/link' -import { createSpaceDiffStore } from '../tables/space-diff.js' -import { createSubscriptionStore } from '../tables/subscription.js' -import { createConsumerStore } from '../tables/consumer.js' -import { notNully } from './lib.js' -import { handleUsageInsert } from '../lib/usage-table.js' +import { unmarshall } from '@aws-sdk/util-dynamodb' +import * as Usage from '../data/usage.js' Sentry.AWSLambda.init({ environment: process.env.SST_STAGE, @@ -14,13 +9,7 @@ Sentry.AWSLambda.init({ }) /** - * @typedef {{ - * spaceDiffTable?: string - * subscriptionTable?: string - * consumerTable?: string - * dbEndpoint?: URL - * region?: 'us-west-2'|'us-east-2' - * }} CustomHandlerContext + * @typedef {{}} CustomHandlerContext */ export const handler = Sentry.AWSLambda.wrapHandler( @@ -29,47 +18,33 @@ export const handler = Sentry.AWSLambda.wrapHandler( * @param {import('aws-lambda').Context} context */ async (event, context) => { - /** @type {CustomHandlerContext|undefined} */ - const customContext = context?.clientContext?.Custom - const spaceDiffTable = customContext?.spaceDiffTable ?? notNully(process.env, 'SPACE_DIFF_TABLE_NAME') - const subscriptionTable = customContext?.subscriptionTable ?? notNully(process.env, 'SUBSCRIPTION_TABLE_NAME') - const consumerTable = customContext?.consumerTable ?? notNully(process.env, 'CONSUMER_TABLE_NAME') - const dbEndpoint = new URL(customContext?.dbEndpoint ?? notNully(process.env, 'DB_ENDPOINT')) - const region = customContext?.region ?? notNully(process.env, 'AWS_REGION') + // /** @type {CustomHandlerContext|undefined} */ + // const customContext = context?.clientContext?.Custom + // TODO: stripe publishable key or something? - const records = parseUsageInsertEvent(event) - if (!records.length) return + const usages = parseUsageInsertEvent(event) + if (!usages.length) return - const storeOptions = { endpoint: dbEndpoint } - const ctx = { - spaceDiffStore: createSpaceDiffStore(region, spaceDiffTable, storeOptions), - subscriptionStore: createSubscriptionStore(region, subscriptionTable, storeOptions), - consumerStore: createConsumerStore(region, consumerTable, storeOptions) + for (const u of usages) { + // TODO: send request to stripe + console.log(u) } - const results = await Promise.all(records.map(m => handleUsageInsert(m, ctx))) - for (const r of results) if (r.error) throw r.error } ) /** * @param {import('aws-lambda').DynamoDBStreamEvent} event - * @returns {import('../lib/api').Usage[]} */ const parseUsageInsertEvent = event => { const usages = [] for (const r of event.Records) { if (r.eventName !== 'INSERT') continue - usages.push(r.dynamodb) + if (!r.dynamodb) continue + if (!r.dynamodb.NewImage) throw new Error('missing "NEW_IMAGE" in stream event') + // @ts-expect-error IDK why this is not Record + const { ok: usage, error } = Usage.decode(unmarshall(r.dynamodb.NewImage)) + if (error) throw error + usages.push(usage) } - - const batch = event.Records.map(r => fromString(r.kinesis.data, 'base64')) - return batch.map(b => { - const json = JSON.parse(toString(b, 'utf8')) - return { - ...json, - carCid: Link.parse(json.carCid), - invocationCid: Link.parse(json.invocationCid), - ts: new Date(json.ts) - } - }) + return usages } diff --git a/billing/lib/billing-cron.js b/billing/lib/billing-cron.js index 95343707..a5128326 100644 --- a/billing/lib/billing-cron.js +++ b/billing/lib/billing-cron.js @@ -11,6 +11,7 @@ export const handleCronTick = async ctx => { const from = startOfLastMonth() const to = startOfMonth() + /** @type {string|undefined} */ let cursor while (true) { const customerList = await ctx.customerStore.list({}, { cursor, size: 1000 }) diff --git a/billing/lib/customer-billing-queue.js b/billing/lib/customer-billing-queue.js index 45c1084c..6d10c983 100644 --- a/billing/lib/customer-billing-queue.js +++ b/billing/lib/customer-billing-queue.js @@ -11,6 +11,7 @@ export const handleCustomerBillingInstruction = async (instruction, ctx) => { console.log(`Processing customer billing instruction for: ${instruction.customer}`) console.log(`Period: ${instruction.from.toISOString()} - ${instruction.to.toISOString()}`) + /** @type {string|undefined} */ let cursor while (true) { const subsList = await ctx.subscriptionStore.list({ customer: instruction.customer }, { cursor }) diff --git a/billing/lib/space-billing-queue.js b/billing/lib/space-billing-queue.js index 21d7aa93..e3de7066 100644 --- a/billing/lib/space-billing-queue.js +++ b/billing/lib/space-billing-queue.js @@ -27,6 +27,7 @@ export const handleSpaceBillingInstruction = async (instruction, ctx) => { let size = snap.size let usage = size * BigInt(instruction.to.getTime() - instruction.from.getTime()) + /** @type {string|undefined} */ let cursor while (true) { const spaceDiffList = await ctx.spaceDiffStore.listBetween( diff --git a/billing/lib/usage-table.js b/billing/lib/usage-table.js deleted file mode 100644 index 1d89f4ee..00000000 --- a/billing/lib/usage-table.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @param {import('./api').Usage} record - * @param {*} ctx - */ -export const handleUsageInsert = (record, ctx) => { - -} \ No newline at end of file diff --git a/filecoin/test/helpers/resources.js b/filecoin/test/helpers/resources.js index 67165a3e..0153fce6 100644 --- a/filecoin/test/helpers/resources.js +++ b/filecoin/test/helpers/resources.js @@ -30,7 +30,6 @@ export async function createDynamodDb(opts = {}) { * * @typedef {import('@aws-sdk/client-dynamodb').CreateTableCommandInput} CreateTableCommandInput * @typedef {import('@serverless-stack/resources').TableProps} TableProps - * * @param {TableProps} props * @returns {Pick} */ @@ -47,11 +46,11 @@ export function dynamoDBTableConfig ({ fields, primaryIndex, globalIndexes = {} .filter(([k]) => attributes.includes(k)) // 'The number of attributes in key schema must match the number of attributes defined in attribute definitions' .map(([k, v]) => ({ AttributeName: k, - AttributeType: v[0].toUpperCase() + AttributeType: /** @type {import('@aws-sdk/client-dynamodb').ScalarAttributeType} */ (v[0].toUpperCase()) })) const KeySchema = toKeySchema(primaryIndex) const GlobalSecondaryIndexes = Object.entries(globalIndexes) - .map(([IndexName, val]) => ({ + .map(([IndexName, val]) => /** @type {import('@aws-sdk/client-dynamodb').GlobalSecondaryIndex} */ ({ IndexName, KeySchema: toKeySchema(val), Projection: { ProjectionType: 'ALL' }, @@ -74,9 +73,8 @@ export function dynamoDBTableConfig ({ fields, primaryIndex, globalIndexes = {} * @param {string} [index.sortKey] */ function toKeySchema ({partitionKey, sortKey}) { - const KeySchema = [ - { AttributeName: partitionKey, KeyType: 'HASH' } - ] + /** @type {import('@aws-sdk/client-dynamodb').KeySchemaElement[]} */ + const KeySchema = [{ AttributeName: partitionKey, KeyType: 'HASH' }] if (sortKey) { KeySchema.push( { AttributeName: sortKey, KeyType: 'RANGE' } diff --git a/stacks/billing-db-stack.js b/stacks/billing-db-stack.js index ef4d6bbe..1173db62 100644 --- a/stacks/billing-db-stack.js +++ b/stacks/billing-db-stack.js @@ -11,6 +11,9 @@ export const BillingDbStack = ({ stack }) => { const customerTable = new Table(stack, 'customer', customerTableProps) const spaceSnapshotTable = new Table(stack, 'space-snapshot', spaceSnapshotTableProps) const spaceDiffTable = new Table(stack, 'space-diff', spaceDiffTableProps) - const usageTable = new Table(stack, 'usage', usageTableProps) + const usageTable = new Table(stack, 'usage', { + ...usageTableProps, + stream: 'new_image' + }) return { customerTable, spaceSnapshotTable, spaceDiffTable, usageTable } } diff --git a/stacks/billing-stack.js b/stacks/billing-stack.js index b612d2ba..5f844f37 100644 --- a/stacks/billing-stack.js +++ b/stacks/billing-stack.js @@ -94,7 +94,8 @@ export function BillingStack ({ stack, app }) { batchSize: 1, startingPosition: StartingPosition.LATEST } - } + }, + filters: [{ eventName: ['INSERT'] }] } }) diff --git a/tsconfig.json b/tsconfig.json index 1982cf8a..1ec45a5b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -35,5 +35,6 @@ "stripInternal": true, "resolveJsonModule": true, }, - "include": [ "billing", "upload-api", "stacks", "carpark", "replicator", "satnav", "ucan-invocation", "filecoin", "tools" ] + "include": [ "billing", "upload-api", "stacks", "carpark", "replicator", "satnav", "ucan-invocation", "filecoin", "tools" ], + "exclude": [ "billing/coverage" ] } \ No newline at end of file diff --git a/ucan-invocation/test/helpers/resources.js b/ucan-invocation/test/helpers/resources.js index ba66c848..92ea8178 100644 --- a/ucan-invocation/test/helpers/resources.js +++ b/ucan-invocation/test/helpers/resources.js @@ -41,8 +41,9 @@ export function dynamoDBTableConfig ({ fields, primaryIndex }) { .filter(([k]) => attributes.includes(k)) // 'The number of attributes in key schema must match the number of attributes defined in attribute definitions' .map(([k, v]) => ({ AttributeName: k, - AttributeType: v[0].toUpperCase() + AttributeType: /** @type {import('@aws-sdk/client-dynamodb').ScalarAttributeType} */ (v[0].toUpperCase()) })) + /** @type {import('@aws-sdk/client-dynamodb').KeySchemaElement[]} */ const KeySchema = [ { AttributeName: primaryIndex.partitionKey, KeyType: 'HASH' } ] diff --git a/upload-api/test/helpers/resources.js b/upload-api/test/helpers/resources.js index 1cc53754..9c6ce245 100644 --- a/upload-api/test/helpers/resources.js +++ b/upload-api/test/helpers/resources.js @@ -110,8 +110,9 @@ export function dynamoDBTableConfig ({ fields, primaryIndex, globalIndexes }) { .filter(([k]) => attributes.includes(k)) // 'The number of attributes in key schema must match the number of attributes defined in attribute definitions' .map(([k, v]) => ({ AttributeName: k, - AttributeType: v[0].toUpperCase(), + AttributeType: /** @type {import('@aws-sdk/client-dynamodb').ScalarAttributeType} */ (v[0].toUpperCase()), })) + /** @type {import('@aws-sdk/client-dynamodb').KeySchemaElement[]} */ const KeySchema = [ { AttributeName: primaryIndex.partitionKey, KeyType: 'HASH' }, ]