Merge pull request #32743 from overleaf/ar-new-v1-api
[web] new v1 api client GitOrigin-RevId: 7ba0deef0d10526198a2a6ba997c2dcff7b7e5a5
This commit is contained in:
@@ -4,6 +4,7 @@ import settings from '@overleaf/settings'
|
||||
import Errors from '../Errors/Errors.js'
|
||||
import { promisifyMultiResult } from '@overleaf/promise-utils'
|
||||
import OError from '@overleaf/o-error'
|
||||
import Modules from '../../infrastructure/Modules.mjs'
|
||||
|
||||
// TODO: check what happens when these settings aren't defined
|
||||
const DEFAULT_V1_PARAMS = {
|
||||
@@ -16,6 +17,14 @@ const DEFAULT_V1_PARAMS = {
|
||||
timeout: settings.apis.v1.timeout,
|
||||
}
|
||||
|
||||
export async function makeV1Request(options) {
|
||||
const results = await Modules.promises.hooks.fire('makeV1Request', options)
|
||||
if (!Array.isArray(results) || results.length === 0) {
|
||||
throw new Error('No module provides a makeV1Request implementation')
|
||||
}
|
||||
return results[0]
|
||||
}
|
||||
|
||||
const v1Request = request.defaults(DEFAULT_V1_PARAMS)
|
||||
|
||||
function makeRequest(options, callback) {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { RequestInit, Response } from 'node-fetch'
|
||||
|
||||
export type V1RequestOptions = Omit<RequestInit, 'method'> & {
|
||||
uri: string
|
||||
qs?: Record<string, string | undefined>
|
||||
expectJson?: boolean
|
||||
expectedStatusCodes?: number[]
|
||||
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
|
||||
}
|
||||
|
||||
export interface KnownHookSignatures {
|
||||
makeV1Request: (
|
||||
options: V1RequestOptions
|
||||
) => Promise<{ body: unknown; response: Response }>
|
||||
}
|
||||
|
||||
export type HookName = keyof KnownHookSignatures | string
|
||||
|
||||
export type HookParameters<K extends HookName> =
|
||||
K extends keyof KnownHookSignatures
|
||||
? Parameters<KnownHookSignatures[K]>
|
||||
: any[]
|
||||
|
||||
export type HookReturnType<K extends HookName> =
|
||||
K extends keyof KnownHookSignatures
|
||||
? Awaited<ReturnType<KnownHookSignatures[K]>>
|
||||
: any
|
||||
@@ -12,12 +12,16 @@ import Metrics from '@overleaf/metrics'
|
||||
/** @import { WebModule } from "../../../types/web-module" */
|
||||
/** @import { RequestHandler } from "express" */
|
||||
|
||||
/**
|
||||
* @import { HookName, HookParameters, HookReturnType } from './Modules'
|
||||
*/
|
||||
|
||||
const MODULE_BASE_PATH = Path.join(import.meta.dirname, '/../../../modules')
|
||||
|
||||
/** @type {WebModule[]} */
|
||||
const _modules = []
|
||||
let _modulesLoaded = false
|
||||
/** @type {Record<string, any>} */
|
||||
/** @type {Partial<Record<HookName, Function[]>>} */
|
||||
const _hooks = {}
|
||||
|
||||
/** @type {Record<string, RequestHandler[]>} */
|
||||
@@ -46,9 +50,20 @@ async function loadModulesImpl() {
|
||||
await import(settingsCheckModule)
|
||||
}
|
||||
for (const moduleName of Settings.moduleImportSequence || []) {
|
||||
const module = await import(
|
||||
Path.join(MODULE_BASE_PATH, moduleName, 'index.mjs')
|
||||
const typescriptModule = Path.join(
|
||||
MODULE_BASE_PATH,
|
||||
moduleName,
|
||||
'index.mts'
|
||||
)
|
||||
let module
|
||||
if (fs.existsSync(typescriptModule)) {
|
||||
module = await import(typescriptModule)
|
||||
} else {
|
||||
module = await import(
|
||||
Path.join(MODULE_BASE_PATH, moduleName, 'index.mjs')
|
||||
)
|
||||
}
|
||||
|
||||
/** @type {WebModule & {name: string}} */
|
||||
const loadedModule = module.default || module
|
||||
|
||||
@@ -194,8 +209,9 @@ async function attachHooks() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} name
|
||||
* @param {any} method
|
||||
* @template {HookName} K
|
||||
* @param {K} name
|
||||
* @param {(...args: HookParameters<K>) => HookReturnType<K>| Promise<HookReturnType<K>>} method
|
||||
*/
|
||||
function attachHook(name, method) {
|
||||
if (_hooks[name] == null) {
|
||||
@@ -221,8 +237,10 @@ async function attachMiddleware() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} name
|
||||
* @param {...any} args
|
||||
* @template {HookName} K
|
||||
* @param {K} name
|
||||
* @param {HookParameters<K>} args
|
||||
* @returns {Promise<HookReturnType<K>[]>}
|
||||
*/
|
||||
async function fireHook(name, ...args) {
|
||||
// ensure that modules are loaded if we need to fire a hook
|
||||
@@ -250,6 +268,10 @@ async function getMiddleware(name) {
|
||||
return _middleware[name] || []
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {<K extends HookName>(name: K, ...args: [...HookParameters<K>, (err: any, results?: HookReturnType<K>[]) => void]) => void} CallbackFireHook
|
||||
*/
|
||||
|
||||
export default {
|
||||
applyNonCsrfRouter,
|
||||
applyRouter,
|
||||
@@ -261,7 +283,9 @@ export default {
|
||||
start,
|
||||
hooks: {
|
||||
attach: attachHook,
|
||||
fire: callbackify(fireHook),
|
||||
fire: /** @type {CallbackFireHook} */ (
|
||||
/** @type {unknown} */ (callbackify(/** @type {any} */ (fireHook)))
|
||||
),
|
||||
},
|
||||
middleware: getMiddleware,
|
||||
promises: {
|
||||
|
||||
Reference in New Issue
Block a user