How to sign requests using opensearch-js? - node.js

I need to sign requests to Opensearch. I'm attempting to use opensearch-js and aws-es-connection to do that.
import {
createAWSConnection,
awsGetCredentials,
} from '#acuris/aws-es-connection';
import { Client } from "#opensearch-project/opensearch";
import { esConfig } from "./config";
export const getClient = async () => {
const awsCredentials = await awsGetCredentials();
const AWSConnection = createAWSConnection(awsCredentials);
const client = new Client({
...AWSConnection,
node: esConfig.uri
});
return client;
};
However, this code complains about the types not being compatible with the destructure ... syntax.
S2345: Argument of type '{ node: string; nodes?: string | string[] | NodeOptions | NodeOptions[]; Connection?: typeof Connection; ConnectionPool?: typeof ConnectionPool; ... 26 more ...; caFingerprint?: string; }' is not assignable to parameter of type 'ClientOptions'.   Types of property 'ConnectionPool' are incompatible.     Type 'typeof import("/packages/api/node_modules/#elastic/elasticsearch/lib/pool/index").ConnectionPool' is not assignable to type 'typeof import("/packages/api/node_modules/#opensearch-project/opensearch/lib/pool/index").ConnectionPool'.       Types of parameters 'opts' and 'opts' are incompatible.
...
Perhaps I'm making a dumb mistake with the destructuring? Is there another way of signing requests for opensearch-js?

Related

Write openpgp.encrypt stream to S3 not working

I'm trying to push the stream from openpgp.encrypt to an S3 bucket.
Typescript reports const encrypted: openpgp.WebStream<Uint8Array> though it should probably be NodeStream as I'm using nodejs v18 within an AWS Lambda. I'm using openpgpjs v5.5.0.
const publicKeyArmored = settings.publicKey
const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored })
const cleartextStream = getS3InputStream({ bucket, objectKey })
const message = await openpgp.createMessage({
text: cleartextStream,
format: 'binary'
})
const encrypted = await openpgp.encrypt({
message,
format: 'binary',
encryptionKeys: publicKey,
config: {
preferredCompressionAlgorithm: openpgp.enums.compression.uncompressed
}
})
const { s3Outstream: ws, s3Promise } = createS3OutputStream(bucket, outKey)
await pipeline(
encrypted,
ws
)
await s3Promise // wait for upload to finish
Typescript errors
No overload matches this call.
Overload 1 of 7, '(source: PipelineSource<any>, destination: PassThrough, options?: PipelineOptions | undefined): Promise<void>', gave the following error.
Argument of type 'WebStream<Uint8Array>' is not assignable to parameter of type 'PipelineSource<any>'.
Overload 2 of 7, '(streams: readonly (WritableStream | ReadableStream | ReadWriteStream)[], options?: PipelineOptions | undefined): Promise<...>', gave the following error.
Argument of type 'WebStream<Uint8Array>' is not assignable to parameter of type 'readonly (WritableStream | ReadableStream | ReadWriteStream)[]'.
Type 'WebStream<Uint8Array>' is missing the following properties from type 'readonly (WritableStream | ReadableStream | ReadWriteStream)[]': length, concat, join, slice, and 18 more.
Overload 3 of 7, '(stream1: ReadableStream, stream2: WritableStream | ReadWriteStream, ...streams: (WritableStream | ReadWriteStream | PipelineOptions)[]): Promise<...>', gave the following error.
Argument of type 'WebStream<Uint8Array>' is not assignable to parameter of type 'ReadableStream'.
Type 'WebStream<Uint8Array>' is missing the following properties from type 'ReadableStream': readable, read, setEncoding, pause, and 22 more.ts(2769)

How to separately type Fastify decorators in different plugins?

I'm having trouble typing decorators in two plugins (scopes):
import Fastify, { FastifyInstance } from 'fastify'
const fastify = Fastify()
// scope A
fastify.register((instance) => {
instance.decorate('utilA', 'AAA')
instance.get('/', (req, reply) => {
const data = instance.utilA // Property 'utilA' does not exist on type 'FastifyInstance<...>'
reply.send(data)
})
}, { prefix: '/A/' })
// scope B
fastify.register((instance) => {
instance.decorate('utilB', () => 'BBB')
instance.get('/', (req, reply) => {
const data = instance.utilB() // Property 'utilB' does not exist on type 'FastifyInstance<...>'
reply.send(data)
})
}, { prefix: '/B/' })
I can define types globally:
declare module 'fastify' {
interface FastifyInstance {
utilA: string
utilB: () => string
}
}
And it solves the compiler errors. But since utilA and utilB are defined globally compiler allows me to use utilB in the scope A and vice versa.
Is there a way to do the same but independently per scope?
No I do not think this is possible with the declare module '' syntax due to the way that TypeScript works (although someone smarter than me might be able to figure out how).
One thing you can do is create a sub type of the FastifyInstance with your new properties (they will need to be optional or TypeScript might get mad at you depending on your tsconfig settings) and type your plugins fastify instance with that type. For example:
// Scope A
import { FastifyInstance } from 'fastify';
type MyPluginsFastifyInstance = FastifyInstance & { myThing?: MyType; }
export default async (fastify: MyPluginFastifyInstance) => {
... // Implementation.
fastify.myThing // TypeScript is happy :)
}
// Scope B
export default async (fastify) => {
fastify.myThing // TypeScript is mad at you >:(
}

type 'typeof globalThis' has no index signature

i get this error whenever i try to add a function to the global nodejs global namsepace in a TypeScript environment.
Element implicitly has an 'any' type because type 'typeof globalThis'
has no index signature
declaring the global namespace
declare global {
namespace NodeJS {
interface Global {
signin(): string[]
}
}
}
so if i try this
global.signin = () => {}
it returns a
Element implicitly has an 'any' type because type 'typeof globalThis'
has no index signature
I was having a similar issue and I found that node's global typings were changed recently-ish; you can now override them by doing:
// global.d.ts
declare global {
function someFunction(): string;
var someVariable: string;
}
Note: this will not work with let or const you must use var.
// index.ts
global.someFunction = () => "some value";
global.someVariable = "some value";
Below is an example for Node v16
// globals.d.ts
declare module globalThis {
var signin: () => string[];
}
You should declare a global declared as interface in global.d.ts like this:
export interface global {}
declare global {
var signin: ()=>string[]
}
The vscode gives correct code hints
You have to use the var keyword in declare global, and remove namespace NodeJS {.
Like this:
//globals.d.ts
import type { EventEmitter } from "events";
declare global {
var myGlobal: EventEmitter;
}
/// <reference path="globals.d.ts" />
//index.ts
// reference needs to be at top of file
import { EventEmitter } from "events";
global.myGlobal = new EventEmitter();
global.myGlobal // EventEmitter type: EventEmitter
window.myGlobal // EventEmitter type: EventEmitter
Or if you don't have any imports in the .d.ts file:
//namedoesntmatter.d.ts
declare var a: string;
//index.ts
global.a = "Hello"
global.a //Hello type: string
window.a //Hello type: string
I had the same problem with a svelte.kit app. my database module use a global variable to store the dbClient as a promise. VSCode stop complain when the global.d.ts file had this content.
import type { MongoClient } from 'mongodb'
declare global {
namespace globalThis {
var _mongoClientPromise: Promise<MongoClient>
}
}
This is how I solved with Node.js V16+
// global.d.ts
export declare global {
declare module globalThis {
var MyVar: object;
}
}
I too had the same issue. Fixed it by the below code.
declare global {
function signin(): Promise<string[]>
}
in my own case i didn't quite realize until later that the global namespace i declared was case sensitive.
instead of this. before my question was edited it was namespace NODEJS
declare global {
namespace NODEJS {
interface Global {
signin(): string[]
}
}
}
it was supposed to be this
declare global {
namespace NodeJS {
interface Global {
signin(): string[]
}
}
}
pay attention to NODEJS and NodeJS. After i made these changes, typescript was cool with it and it work the way i expected it to.
I tried everything I found here, but nothing worked.Even stranger, VSCode showed NO TypeScript errors, but running tsc still threw:
TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.
After hours, I realised I forgot an "include": [ "src/app.ts" ] line in my tsconfig.json file.
Note to future self and for those who may have made the same mistake:
If you have explicitly provided one or more files in TypeScript's config with include, and that does not include the *.d.ts file, where you declared your globals, the build will fail with this error, even if VSCode shows no error (because it sees the global declaration, but TypeScript won't).
just declare variable by var keyword. like this:
// eslint-disable-next-line no-var
var hello = () => { console.log("hello world"); };
// eslint-disable-next-line no-var
var hi: () => number;
globalThis.hello();
globalThis.hi = () => 143;
You can declare variables in .d.ts files, too.

apollo-server-testing: how to type createTestClient() return? (eslint unbound-method error)

I am trying to setup testing for a node.js / typescript / apollo-server / typegrapql / typeorm project using jest, ts-jest and apollo-server-testing. My test server and client are setup like this:
import 'dotenv/config';
import { ApolloServer } from 'apollo-server-express';
import connectToDatabase from '../database/createConnection';
import buildApolloSchema from './buildApolloSchema';
import { createTestClient } from 'apollo-server-testing';
let server: ApolloServer;
let query: any; // <- Type here??
let mutate: any; // <- Type here??
export { server, query, mutate };
const setupTestEnvironment = async () => {
await connectToDatabase();
const schema = await buildApolloSchema();
if (schema) {
const server = new ApolloServer({
schema,
context: ({ req, res }) => ({
req,
res,
}),
});
const testClient = createTestClient(server);
query = testClient.query; // <- Error here: Avoid referencing unbound methods...
mutate = testClient.mutate; // <- Error here: Avoid referencing unbound methods...
}
};
Any idea of how can I type variables query and mutate to avoid implicit any errors? There seems to be some type inference but I don't seem to be able to import types from the apollo-server-testing package and so far I have left them as any (quickfix suggests never).
Right now the assignments at the end are also throwing the error Avoid referencing unbound methods which may cause unintentional scoping of this.
I have tried all sorts of destructuring assignments (including const {query, mutate} = createTestClient(server) as it appears in the docs) and I get the same error.
Any clues?
You should be able to type query and mutate with the types from apollo-server-testing like this:
import {
ApolloServerTestClient,
createTestClient,
} from "apollo-server-testing";
let server: ApolloServer;
let query: ApolloServerTestClient["query"];
let mutate: ApolloServerTestClient["mutate"];
The Avoid referencing unbound methods which may cause unintentional scoping of this. error is related to the way the types of createTestClient are defined. Since that's apollo-server-testing code, that's hard for you to resolve. Consider disabling the rule for these lines:
const testClient = createTestClient(server);
// eslint-disable-next-line #typescript-eslint/unbound-method
query = testClient.query;
// eslint-disable-next-line #typescript-eslint/unbound-method
mutate = testClient.mutate;
The root of the issue seems to be this definition in apollo-server-testing:
export interface ApolloServerTestClient {
query<TData = any, TVariables = Record<string, any>>(query: Query<TVariables>): Promise<GraphQLResponse<TData>>;
mutate<TData = any, TVariables = Record<string, any>>(mutation: Mutation<TVariables>): Promise<GraphQLResponse<TData>>;
}
If the definition would be like this, the rule shouldn't trigger:
export interface ApolloServerTestClient {
query: <TData = any, TVariables = Record<string, any>>(query: Query<TVariables>) => Promise<GraphQLResponse<TData>>;
mutate: <TData = any, TVariables = Record<string, any>>(mutation: Mutation<TVariables>) => Promise<GraphQLResponse<TData>>;
}
Edit: Related to issue 4724 in apollo-server-testing

RxJS Http Server with typescript compile errors

I'm pretty newbie with rxjs, can you please tell what's wrong with below?
interface IHTTP {
req: IncomingMessage;
res: ServerResponse;
handler?: Promise<any>;
}
server = http.createServer();
let request$: Observable<any>;
request$ = fromEvent(server, 'request').pipe(
map(([req, res]: [IncomingMessage, ServerResponse]): IHTTP => {
return { req, res } as IHTTP;
}
)
);
Compile error:
TS2345: Argument of type 'OperatorFunction<[IncomingMessage, ServerResponse], IHTTP>' is not assignable to parameter of type 'OperatorFunction<unknown, IHTTP>'.   Type 'unknown' is not assignable to type '[IncomingMessage, ServerResponse]'.
I found the problem I had to define fromEvent's first argument as:
server as FromEventTarget<[http.IncomingMessage, http.ServerResponse]>
Otherwise Typescript thinks it's FromEventTarget<unknown>

Resources