Dynamoose: The Model object doesn't allow config as a parameter - dynamoose

I have created a model that was working when I had my backend functions running on my local machine, but when it uses AWS I get and authentication problem when the table is being queried:
2022-02-18T08:54:58.149Z 31785a81-ea8c-434b-832f-6dcff583c01c ERROR Unhandled Promise Rejection
{
"errorType": "Runtime.UnhandledPromiseRejection",
"errorMessage": "AccessDeniedException: User: arn:aws:sts::xxxxxxxxx:assumed-role/dev-production-history-role/ppc-backend-functions-dev-queryProductionHistoryItems is not authorized to perform: dynamodb:CreateTable on resource: arn:aws:dynamodb:eu-west-1:xxxxxxxxxxxx:table/dev-production-history-table",
"trace": [
"Runtime.UnhandledPromiseRejection: AccessDeniedException: User: arn:aws:sts::xxxxxxxxx:assumed-role/dev-production-history-role/ppc-backend-functions-dev-queryProductionHistoryItems is not authorized to perform: dynamodb:CreateTable on resource: arn:aws:dynamodb:eu-west-1:xxxxxxxxx:table/dev-production-history-table",
" at process.<anonymous> (/var/runtime/index.js:35:15)",
" at process.emit (events.js:400:28)",
" at processPromiseRejections (internal/process/promises.js:245:33)",
" at processTicksAndRejections (internal/process/task_queues.js:96:32)"
]
}
This is how my model is defined:
const model = dynamoose.model<ProductionHistory>(DatabaseTableNames.productionHistoryTable, {schema});
From looking at possible solutions, it seems that adding {“create”: false} to the parameters might solve the issue, but in version 3 of Dynamoose you cannot add three parameters, so this will not work:
const model = dynamoose.model<ProductionHistory>(DatabaseTableNames.productionHistoryTable,
schema, {“create”: false});
Does anyone know how to overcome this problem so that it works with Dynamoose version 3?
I have made the changes that Charlie Fish suggested and I am now getting the following error:
2022-02-18T16:39:39.211Z b00a36b8-c612-4886-b9fc-da7084527bf0 INFO AccessDeniedException: User: arn:aws:sts::874124979428:assumed-role/dev-production-history-role/ppc-backend-functions-dev-queryProductionHistoryItems is not authorized to perform: dynamodb:Query on resource: arn:aws:dynamodb:eu-west-1:874124979428:table/dev-production-history-table
at deserializeAws_json1_0QueryCommandError (/var/task/node_modules/dynamoose/node_modules/#aws-sdk/client-dynamodb/dist-cjs/protocols/Aws_json1_0.js:2984:41)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async /var/task/node_modules/dynamoose/node_modules/#aws-sdk/middleware-serde/dist-cjs/deserializerMiddleware.js:7:24
at async /var/task/node_modules/dynamoose/node_modules/#aws-sdk/middleware-signing/dist-cjs/middleware.js:11:20
at async StandardRetryStrategy.retry (/var/task/node_modules/dynamoose/node_modules/#aws-sdk/middleware-retry/dist-cjs/StandardRetryStrategy.js:51:46)
at async /var/task/node_modules/dynamoose/node_modules/#aws-sdk/middleware-logger/dist-cjs/loggerMiddleware.js:6:22
at async main (/var/task/node_modules/dynamoose/dist/aws/ddb/internal.js:6:20)
at async /var/task/node_modules/dynamoose/dist/ItemRetriever.js:105:32
at async Object.queryByDate (/var/task/functions/production-history/query.js:1:1723)
at async Runtime.l [as handler] (/var/task/functions/production-history/query.js:1:1974) {
__type: 'com.amazon.coral.service#AccessDeniedException',
'$fault': 'client',
'$metadata': {
httpStatusCode: 400,
requestId: 'DCB6SNOH9O2NTRAS9LL3OJGEU7VV4KQNSO5AEMVJF66Q9ASUAAJG',
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
},
'$response': HttpResponse {
statusCode: 400,
headers: {
server: 'Server',
date: 'Fri, 18 Feb 2022 16:39:39 GMT',
'content-type': 'application/x-amz-json-1.0',
'content-length': '331',
connection: 'keep-alive',
'x-amzn-requestid': 'DCB6SNOH9O2NTRAS9LL3OJGEU7VV4KQNSO5AEMVJF66Q9ASUAAJG',
'x-amz-crc32': '2950006190'
},
body: IncomingMessage {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
socket: null,
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
headers: [Object],
rawHeaders: [Array],
trailers: {},
rawTrailers: [],
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 400,
statusMessage: 'Bad Request',
client: [TLSSocket],
_consuming: false,
_dumped: false,
req: [ClientRequest],
[Symbol(kCapture)]: false,
[Symbol(RequestTimeout)]: undefined
}
}
}
This is my code now:
const model = dynamoose.model<ProductionHistory>(DatabaseTableNames.productionHistoryTable, schema);
const Table = new dynamoose.Table(DatabaseTableNames.productionHistoryTable, [model], {"create": false, "waitForActive": false});
Any ideas?

Disclaimer: this answer is based on Dynamoose v3.0.0 beta 1. Answers based on beta versions can become outdated quickly, so be sure to check for any updated details for your version of Dynamoose.
In Dynamoose v3, a new class was introduced called Table. This represents a single DynamoDB Table. In previous versions of Dynamoose, a Model represented a single DynamoDB Table, but based on the API also kinda represented a specific entity or model in your data structure (ex. Movie, Order, User, etc). This lead to complications and confusion when it comes to single table design structures especially.
In terms of code, what this means is the following.
// If you have the following code in v2:
const User = dynamoose.model("User", {"id": String});
// It will be converted to this in v3:
const User = dynamoose.model("User", {"id": String});
const DBTable = new dynamoose.Table("DBTable", [User]);
So basically you create a new Table instance based on your Model. In v3 if you try to use your Model without created a Table instance based on it, it will throw an error.
Once you do that, the 3rd parameter of your Table constructor, you can pass in settings. Once of which being create. So you can set that to false as that parameter.
Your code specifically would look something like:
const model = dynamoose.model<ProductionHistory(DatabaseTableNames.productionHistoryTable, schema);
const DBTable = new dynamoose.Table(DatabaseTableNames.productionHistoryTable, [model], {"create": false});

Related

What is the best practice to bypass my specific dynamic code evaluation in next.js middleware?

I use next.js middleware to retrieve a data stored inside a cookie, and to check in a db (using strapi) if this specific user exists, or if he needs to register before going further.
// middleware.js
import { getToken } from 'next-auth/jwt';
import qs from 'qs';
import { MY_DB } from './constants';
export async function middleware(request) {
const token = await getToken({
req: request,
secret: process.env.SECRET,
});
const params = qs.stringify({
filters: {
address: {
$eq: token.sub,
},
},
});
const url = MY_DB + '/api/users/?' + params;
const result = await fetch(url, {
method: 'GET',
headers: { accept: 'application/json' },
});
// remaining code checks if the request is empty or not and returns the appropriate page
(...)
building my project returns the following error :
Failed to compile.
./node_modules/.pnpm/function-bind#1.1.1/node_modules/function-bind/implementation.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation
Import trace for requested module:
./node_modules/.pnpm/function-bind#1.1.1/node_modules/function-bind/implementation.js
./node_modules/.pnpm/function-bind#1.1.1/node_modules/function-bind/index.js
./node_modules/.pnpm/get-intrinsic#1.1.3/node_modules/get-intrinsic/index.js
./node_modules/.pnpm/side-channel#1.0.4/node_modules/side-channel/index.js
./node_modules/.pnpm/qs#6.11.0/node_modules/qs/lib/stringify.js
./node_modules/.pnpm/qs#6.11.0/node_modules/qs/lib/index.js
> Build failed because of webpack errors
 ELIFECYCLE  Command failed with exit code 1.
I highly suspect the qs.stringify call given the stacktrace, but how can I overcome this in an elegant way ?

Post multiple logs to DataDog with 1 HTTP request

I want to post multiple logs to DataDog from a JS function, using a single HTTP request. Looking at the v2 docs for DataDog's 'send logs' POST endpoint, it sounds like this is possible:
For a single log request, the API ... For a multi-logs request, the API ...
But it's not clear to me from the docs how to actually send a 'multi-logs' request. I've tried the following:
const dataDogEndpoint = 'https://http-intake.logs.datadoghq.com/api/v2/logs';
const body = {
ddtags: 'env:production,status:info',
hostname: 'my-host',
message: ['My first production log.', 'My second production log.'],
service: 'my-service'
};
const response = await fetch(dataDogEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'DD-API-KEY': apiKey
},
body: JSON.stringify(body)
});
Perhaps unsurprisingly, this appears in DataDog as a single log with the following content:
[My first production log., My second production log.]
How can I achieve this?
Got it - this can be achieved by adding multiple log objects to the body like so:
const dataDogEndpoint = 'https://http-intake.logs.datadoghq.com/api/v2/logs';
const body = [{
ddtags: 'env:production,status:info',
hostname: 'my-host',
message: 'My first production log.',
service: 'my-service'
},{
ddtags: 'env:production,status:info',
hostname: 'my-host',
message: 'My second production log.',
service: 'my-service'
}];
const response = await fetch(dataDogEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'DD-API-KEY': apiKey
},
body: JSON.stringify(body)
});
(You'll probably want a loop instead of instantiating each log object separately.)

Next-auth JWT user missing values after logging in

I ran into some issues regarding the JWT user being null after a succesfull login.
Did some debugging in the callbacks and saw the following:
2 {
token: {
token: {
name: null,
email: null,
picture: null,
sub: 'e1d4c887-0257-4543-be37-c9b297e2cce6'
},
user: {
id: 'e1d4c887-0257-4543-be37-c9b297e2cce6',
emailVerified: '2022-09-06T09:54:24.163Z',
name: null,
email: null,
image: null
},
account: {
providerAccountId: 'test#test.com',
type: 'email',
provider: 'email'
},
isNewUser: false,
iat: 1662458064,
exp: 1665050064,
jti: '521054a5-7ead-43fc-94f4-f5eb7fffde43'
}
}
I read through the docs and noticed that the correct callback flow would be: signin -> JWT -> Session.
It is possible to return the user object found within the signIn callback, but this is not getting passed into the JWT callback.
Due to the fact that some properties like isNewUser are filled in correctly, could the missing user info be related to a DB issue?
What are some things I could further check in the hopes of solving this issue?

openstack npm pkgcloud createImage() function not working

I am trying to create an image of an instance in openstack using npm pkgcloud.
For this I am using the code as below:
var openstack_client_compute = null;
openstack_client_compute = pkgcloud.compute.createClient({
provider: PROVIDER, // required
username: USERNAME, // required
password: PASSWORD, // required
region: REGION,
authUrl: AUTH_URL // required
});
options = {
name: 'image1', // required
server: '0e4d56a2-173a-425d-befd-cec366605522' // required
};
openstack_client_compute.createImage(options, function(err, image){
if(err){
console.log(err);
}
console.log(image);
});
I am getting the following error :
name: 'Error',
provider: 'openstack',
failCode: 'Service Unavailable',
statusCode: 503,
href: 'http://controller:8774/v2.1/6af81940df89199f088beba7d93/servers/0e4d56a2-173a-425d-befd-cec366605522/action',method: 'POST',
headers:
{ server: 'squid',
'mime-version': '1.0',
date: 'Mon, 09 Apr 2018 07:21:15 GMT',
'content-type': 'text/html;charset=utf-8',
'content-length': '3012',
'x-squid-error': 'ERR_DNS_FAIL 0',
'x-cache': 'MISS from lproxy',
'x-cache-lookup': 'MISS from proxy:8080',
connection: 'close' },
Note : other functions such as createStack deleteStack getStack etc are functioning properly
It is showing the error that unable to resolve host name (controller is not getting resolved to IP) the code is failing due to that.
Any possibility that a change in openstack configuration may resolve it.
If yes what changes are needed?

Issue with sending LiveChat messages via DDP in RocketChat

I am trying to use the DDP Realtime API to initiate a LiveChat conversation but I am facing issues.
https://rocket.chat/docs/developer-guides/realtime-api/livechat-api
I am doing all the steps as per the documentation. In the first API outcome, you can see that it saus numAgents: 2 and online: true. However when I try to send a message to the same department, it says: "Sorry, no online agents".
Is there a way to find out the problem?
Result of livechat:getInitialData
{ enabled: true,
title: 'xyz.com',
color: '#C1272D',
registrationForm: false,
room: null,
triggers: [],
departments:
[ { _id: 'CxCTgXL4csw3TcW6S',
enabled: true,
name: 'Support',
description: '',
numAgents: 2,
showOnRegistration: true,
_updatedAt: 2017-09-24T06:46:39.657Z } ],
allowSwitchingDepartments: true,
online: true,
offlineColor: '#666666',
offlineMessage: 'We are not online right now. Please leave us a message:',
offlineSuccessMessage: '',
offlineUnavailableMessage: '',
displayOfflineForm: true,
videoCall: true,
offlineTitle: 'Leave a message',
language: '',
transcript: false,
transcriptMessage: 'Would you like a copy of this chat emailed?' }
Result of livechat:registerGuest
{ userId: 'j65Cp5peeLJLYhWQi',
token: 'J8IpnpB1yN1AYtO0e0EzLhuaRhe0zaZkjHBAamsehSO' }
Result of Login
{ id: 'j65Cp5peeLJLYhWQi',
token: 'J8IpnpB1yN1AYtO0e0EzLhuaRhe0zaZkjHBAamsehSO',
tokenExpires: 2017-12-23T07:45:01.928Z }
Result of sendMessageLivechat
{ isClientSafe: true,
error: 'no-agent-online',
reason: 'Sorry, no online agents',
message: 'Sorry, no online agents [no-agent-online]',
errorType: 'Meteor.Error' }
These are the parameters I am sending to sendMessageLiveChat.
"_id" : "j65Cp5peeLJLYhWQi"
"rid" : "a_random_string"
"msg": "Hello"
"token" : "J8IpnpB1yN1AYtO0e0EzLhuaRhe0zaZkjHBAamsehSO"
Could someone help me?
This is how I called registerGuest.
ddpClient.call("livechat:registerGuest",[{"token":authToken,"name":"test1","email":"test2#gmail.com","department":department._id},25],function(err, info){
});
the token passed by me here is the admin's authToken
The ddpClient object is obtained using the DDP npm package.
I solved this by a combination of
setting the bot as livechat agent & manager at the same time (I've read that tip somewhere it might be nonsense)
in Admin -> Omnichannel -> routing I've set 'accept even when no agents are online' (since my bot was never online, bould it was replying when DMessaged) + 'assign bot agents to new conversations'
I've setup myself a livechat-manager + livechat-agent role, but stayed in a different department, that way I can takeover
The rocket chat live api docs are quite out of date, just got stream-room-messages working because of a random forum post. Generally, registerGuest works with very minimal parameters as well, namely a random, self generated token + a name.
Here's my code for the complete setup
async subscribeToLiveRoom(message){
var _self = this
// let initial = await this.api
// .call("livechat:getInitialData",[token])
// register
const token = this.randomString()
var guestUser = await this.api
.call(
'livechat:registerGuest',
[{
token: token,
name: _self.$auth.user.name
}]
)
.catch(console.error)
console.log('guest', guestUser.visitor.token)
this.setActiveGuest(guestUser)
var roomId = this.randomString()
this.setActiveRoom(roomId)
let msg = await this.api
.call(
'sendMessageLivechat',
[{
_id: _self.randomString(),
rid: roomId,
msg: message,
token: guestUser.visitor.token
}])
.catch(console.error)
try {
let liveStream = await this.$subscribe("stream-livechat-room",[
roomId,
{
"useCollection": true,
"args":[
{
"visitorToken": guestUser.visitor.token
}
]
}
])
this.msgLive = await this.find('stream-livechat-room')
} catch (e) {
console.log(e)
}
//
try {
var roomStream = await this.$subscribe("stream-room-messages",[
roomId,
{
"useCollection": true,
"args":[
{
"visitorToken": guestUser.visitor.token
}
]
}
])
console.log('roomstream')
var update = this.find('stream-room-messages')
} catch (e) {
console.log('an error occured', e)
}
console.log( this.msg)
},
async sendToLiveRoom(message, rId){
var _self = this
// let initial = await this.api
// .call("livechat:getInitialData",[token])
// register
let msg = await this.api
.call(
'sendMessageLivechat',
[{
_id: _self.randomString(),
rid: rId,
msg: message,
token: _self.guest.visitor.token
}])
.catch(console.error)
},
By the way, since it's not well documented, you will get room-messages in livechat rooms via subscribing to stream-room-messages while you get room status changes (like switched to another agent) by subscribing to stream-livechat-room

Resources