Files
rudder-js-sdk/src/domains/ModulesDomain.ts
T

60 lines
2.0 KiB
TypeScript
Raw Normal View History

import type { RudderContext } from '../core/context.js';
import { uuidv4 } from '../core/uuid.js';
import { RudderHttpError, RudderModuleError } from '../client/RudderError.js';
import type {
CallModuleFunctionClientResponse,
CallModuleFunctionRequest,
ModuleErrorResponse,
} from '../generated/modules.js';
export interface ModuleCallOptions {
/** Version the caller was built against; sent as `X-Rudder-Module-Version: <module>@<version>`. */
moduleVersion?: string;
}
/**
* ModulesDomain — calls module functions. Usually reached through a client
* generated by `rudder client generate`, not directly.
*/
export class ModulesDomain {
constructor(private readonly ctx: RudderContext) {}
/**
* Calls `module.fn` and returns its `result`. Each call gets one
* Idempotency-Key reused across retries (network errors, 5xx, 409 `conflict`).
* Rejects with {@link RudderModuleError} on 422.
*/
async call<T = unknown>(
module: string,
fn: string,
args?: unknown,
options?: ModuleCallOptions,
): Promise<T> {
const headers: Record<string, string> = { 'Idempotency-Key': uuidv4() };
if (options?.moduleVersion) {
headers['X-Rudder-Module-Version'] = `${module}@${options.moduleVersion}`;
}
const path = `/sdk/v1/modules/${encodeURIComponent(module)}/${encodeURIComponent(fn)}`;
try {
const response = await this.ctx.request<CallModuleFunctionClientResponse>(
'POST',
path,
{ args: args ?? {} } satisfies CallModuleFunctionRequest,
{ headers, retry: true },
);
return response?.result as T;
} catch (err) {
if (err instanceof RudderHttpError && err.status === 422 && err.code) {
let payload: Partial<ModuleErrorResponse> = {};
try {
payload = JSON.parse(err.body);
} catch {
// err.code came from this body, so it is JSON; keep the fallback anyway.
}
throw new RudderModuleError(err.statusText, err.body, { ...payload, code: err.code });
}
throw err;
}
}
}