UNPKG

@atlassian/atlassian-connect-express

Version:

Library for building Atlassian Add-ons on top of Express

299 lines (258 loc) 10.3 kB
import * as events from "node:events"; import * as fs from "node:fs"; import * as querystring from "node:querystring"; import * as express from "express"; import * as request from "request"; import * as sequelize from "sequelize"; type Console = typeof console; declare namespace AddOnFactory { // Actual exports of lib/index.js export interface Descriptor { key: string; name: string; description: string; vendor: { name: string; url: string; }; baseUrl: string; links: { self: string; homepage: string; }; authentication: { type: string; }; scopes: string[]; } export interface Options { config: { descriptorTransformer?: (descriptor: Partial<Descriptor>, config: Config) => Descriptor development?: Partial<ConfigOptions>; production?: Partial<ConfigOptions>; } } export interface ConfigOptions { environment: string; port: string; store: { adapter?: string, type?: string, url?: string, storage?: string }; expressErrorHandling: boolean; errorTemplate: boolean; errorTemplateName: string; errorTemplateObject: Record<string, unknown>; validateDescriptor: boolean; localBaseUrl: string; jwt: { validityInMinutes: number; }; product: string; hosts: string[]; maxTokenAge: number; userAgent: string; watch: boolean; } export interface Config { port(): string environment(): string; store(): { adapter: string, type: string }; expressErrorHandling(): boolean; errorTemplate(): boolean; getErrorTemplateName(): string; getErrorTemplateObject(): Record<string, unknown>; validateDescriptor(): boolean; localBaseUrl(): string; jwt(): { validityInMinutes: number; }; product(): string; hosts(): string[]; maxTokenAge(): number; userAgent(): string; } export interface KVStore { del(key: string): Promise<void>; get<T = unknown>(key: string): Promise<T>; set<T = unknown>(key: string, value: T | string): Promise<T>; } export interface StoreAdapter { del(key: string, clientKey: string): Promise<void>; get<T = unknown>(key: string, clientKey: string): Promise<T>; /** * Used to set data under `key` for a given client. * Do not use this to save clientInfo, use `saveInstallation` instead, as it handles associating Forge installations. */ set<T = unknown>(key: string, value: T | string, clientKey: string): Promise<T>; getAllClientInfos(): Promise<ClientInfo[]>; saveInstallation(value: ClientInfo, clientKey: string): Promise<ClientInfo>; getClientSettingsForForgeInstallation(forgeInstallationId: string): Promise<ForgeInstallationClientSettings>; deleteAssociation(forgeInstallationId: string): Promise<void>; forForgeInstallation(installationId: string): KVStore; } export type ForgeInstallationClientSettings = { clientKey: string; installationId: string; } | null; export const DESCRIPTOR_FILENAME: "atlassian-connect.json"; export const store: { register( adapterKey: string, factory: (logger: Console, opts: unknown) => StoreAdapter ): void; } export type JiraPermissionsQuery = { project?: string[] global?: string[] }; export type ConfluencePermissionsQuery = { application?: string[] content?: string }; export type ModifyRequestArgsOptions = Omit<request.Options, 'form' | 'qs'> & { /** @deprecated Use multipartFormData instead */ form?: request.Options['form']; multipartFormData?: Record<string, unknown | unknown[]>; urlEncodedFormData?: Record<string, unknown>; qs?: querystring.ParsedUrlQueryInput; }|URL|string; export type ModifyArgsOutput< TOptions extends ModifyRequestArgsOptions, TCallback extends request.RequestCallback > = TCallback extends request.RequestCallback ? [TOptions, TCallback] : [TCallback]; export type HostClientArgs< TOptions extends ModifyRequestArgsOptions, TCallback extends request.RequestCallback > = [ TOptions, request.Headers, TCallback, string ]; export type BearerToken = { access_token: string; token_type: string; expires_in: number; }; export type RequestOptions = ModifyRequestArgsOptions & { /** don't authenticate the request */ anonymous?: boolean; } export type ForgeAppToken = { appToken: string; apiBaseUrl: string; } // This is a class that isn't exported, so we don't want to export a class that's not importable at runtime // We declare it as an interface so consumers can do module augmentation though, instead of `declare class X` and exporting `InstanceType<typeof X>. export interface HostClient { addon: AddOn; context: boolean; clientKey: string; oauth2: unknown; userKey?: string; // for impersonatingClient asUser(userKey: string): HostClient; asUserByAccountId: (userAccountId: string|number) => HostClient; createJwtPayload: (req: request.Request) => string; getUserBearerToken: (scopes: string[], clientSettings: ClientInfo) => Promise<BearerToken>; getBearerToken: (clientSettings: ClientInfo) => Promise<BearerToken>; defaults(): request.Request; cookie(): request.Cookie; jar(): request.CookieJar; modifyArgs<TOptions extends ModifyRequestArgsOptions = ModifyRequestArgsOptions, TCallback extends request.RequestCallback = request.RequestCallback>(...args: HostClientArgs<TOptions, TCallback>): ModifyArgsOutput<TOptions, TCallback>; get: <T = unknown, TOptions extends RequestOptions = RequestOptions>(options: TOptions, callback?: request.RequestCallback) => Promise<T>; post: <T = unknown, TOptions extends RequestOptions = RequestOptions>(options: TOptions, callback?: request.RequestCallback) => Promise<T>; put: <T = unknown, TOptions extends RequestOptions = RequestOptions>(options: TOptions, callback?: request.RequestCallback) => Promise<T>; del: <T = unknown, TOptions extends RequestOptions = RequestOptions>(options: TOptions, callback?: request.RequestCallback) => Promise<T>; head: <T = unknown, TOptions extends RequestOptions = RequestOptions>(options: TOptions, callback?: request.RequestCallback) => Promise<T>; patch: <T = unknown, TOptions extends RequestOptions = RequestOptions>(options: TOptions, callback?: request.RequestCallback) => Promise<T>; } // This is a class that isn't exported, so we don't want to export a class that's not importable at runtime // We declare it as an interface so consumers can do module augmentation though, instead of `declare class X` and exporting `InstanceType<typeof X>. export interface AddOn extends events.EventEmitter { verifyInstallation(): express.RequestHandler; authenticateInstall(): express.RequestHandler; postInstallation(): (request: express.Request, response: express.Response) => void; middleware(): express.RequestHandler; authenticateForge(): express.RequestHandler; getForgeAppToken(): Promise<ForgeAppToken>; associateConnect(): express.RequestHandler; authenticate(skipQshVerification?: boolean): express.RequestHandler; authorizeJira(permissions: JiraPermissionsQuery): express.RequestHandler; authorizeConfluence(permissions: ConfluencePermissionsQuery): express.RequestHandler; loadClientInfo(clientKey: string): Promise<ClientInfo>; checkValidToken(): express.RequestHandler; register() : Promise<void>; key: string; name: string; config: Config; app: express.Application; deregister(): Promise<void>; descriptor: Descriptor; descriptorExists: boolean; schema: sequelize.Sequelize; settings: StoreAdapter; shouldDeregister(): boolean; shouldRegister(): boolean; validateDescriptor(): { type: string; message: string; validationResults: { module: string; description: string; value?: unknown; validValues?: string[]; }[] }[]; watcher: fs.FSWatcher; /** * Reloads AddOn descriptor file */ reloadDescriptor(): void; /* eslint-disable @typescript-eslint/unified-signatures */ /** * @param opts a clientKey, and optionally a userKey * @deprecated to call with userKey, pass userAccountId instead. */ httpClient(opts: { clientKey: string, userKey?: string }): HostClient; /** * @param reqOrOpts either an expressRequest object or an object containing a clientKey, and optionally a userAccountId * @returns HostClient a httpClient */ httpClient( reqOrOpts: express.Request | { clientKey: string; userAccountId?: string } ): HostClient; /* eslint-enable @typescript-eslint/unified-signatures */ } export interface FileNames { descriptorFilename?: string; configFileName?: string; } export interface ClientInfo { key: string, clientKey: string, publicKey: string sharedSecret: string, serverVersion: string, pluginsVersion: string, baseUrl: string, displayUrl?: string; productType: string, description: string, eventType: string, oauthClientId?: string } export type AddOnFactory = typeof AddOnFactory; } // End namespace AddOnFactory // Declaring the function then a namespace is how to support the CJS export pattern we use in lib/index.js without using `export default` and requiring TS consumers to use `esModuleInterop: true` // It also means that any types we want to expose to consumers have to be exported // https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html#common-commonjs-patterns // https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-function-d-ts.html export = AddOnFactory; // Overload definition to properly type how fileNames can be omitted. declare function AddOnFactory(app: express.Application, opts?: AddOnFactory.Options, logger?: Console, callback?: () => void): AddOnFactory.AddOn; declare function AddOnFactory(app: express.Application, opts?: AddOnFactory.Options, logger?: Console, fileNames?: AddOnFactory.FileNames, callback?: () => void): AddOnFactory.AddOn;