@major-tech/resource-client
v0.2.9
Published
TypeScript client library for invoking Major resources (PostgreSQL, Custom APIs, HubSpot, S3)
Downloads
705
Readme
@major-tech/resource-client
TS client: PostgreSQL/CustomAPI/HubSpot/S3. Type-safe, 0-dep, universal (Node/browser/edge), ESM+CJS.
Install
pnpm add @major-tech/resource-clientConfig (All Clients)
{ baseUrl: string; applicationId: string; resourceId: string; majorJwtToken?: string; fetch?: typeof fetch }Response Format
{ ok: true; requestId: string; result: T } | { ok: false; requestId: string; error: { message: string; httpStatus?: number } }PostgresResourceClient
Constructor: new PostgresResourceClient(config: BaseClientConfig)
Method: invoke(sql: string, params: DbParamPrimitive[] | undefined, invocationKey: string, timeoutMs?: number): Promise<DatabaseInvokeResponse>
Params:
sql: SQL query stringparams:(string | number | boolean | null)[]- positional params ($1, $2, etc)invocationKey: unique operation ID (regex:[a-zA-Z0-9][a-zA-Z0-9._:-]*)timeoutMs: optional timeout
Result (ok=true):
{ kind: "database"; rows: Record<string, unknown>[]; rowsAffected?: number }Example:
import { PostgresResourceClient } from "@major-tech/resource-client";
const c = new PostgresResourceClient({
baseUrl,
applicationId,
resourceId,
majorJwtToken,
});
const r = await c.invoke(
"SELECT * FROM users WHERE id = $1",
[123],
"fetch-user"
);
// r.ok ? r.result.rows : r.error.messageDynamoDBResourceClient
Constructor: new DynamoDBResourceClient(config: BaseClientConfig)
Method: invoke(command: DbDynamoDBPayload["command"], params: Record<string, unknown>, invocationKey: string, timeoutMs?: number): Promise<DatabaseInvokeResponse>
Params:
command:"GetItem" | "PutItem" | "UpdateItem" | "DeleteItem" | "Query" | "Scan" | ...params: Command parameters (e.g.,{ TableName: 'users', Key: { id: { S: '123' } } })invocationKey: unique operation IDtimeoutMs: optional timeout
Result (ok=true):
{
kind: "database";
command: string;
data: unknown;
}Example:
import { DynamoDBResourceClient } from "@major-tech/resource-client";
const c = new DynamoDBResourceClient({ baseUrl, applicationId, resourceId });
const r = await c.invoke(
"GetItem",
{ TableName: "users", Key: { id: { S: "123" } } },
"get-user"
);
// r.ok ? r.result.data : r.errorCustomApiResourceClient
Constructor: new CustomApiResourceClient(config: BaseClientConfig)
Method: invoke(method: HttpMethod, path: string, invocationKey: string, options?: { query?: QueryParams; headers?: Record<string, string>; body?: BodyPayload; timeoutMs?: number }): Promise<ApiInvokeResponse>
Params:
method:"GET" | "POST" | "PUT" | "PATCH" | "DELETE"path: URL path (appended to resource baseUrl)invocationKey: unique operation IDoptions.query:Record<string, string | string[]>- query paramsoptions.headers:Record<string, string>- additional headersoptions.body:{ type: "json"; value: unknown } | { type: "text"; value: string } | { type: "bytes"; base64: string; contentType: string }options.timeoutMs: timeout (default: 30000)
Result (ok=true):
{ kind: "api"; status: number; body: { kind: "json"; value: unknown } | { kind: "text"; value: string } | { kind: "bytes"; base64: string; contentType: string } }Example:
import { CustomApiResourceClient } from "@major-tech/resource-client";
const c = new CustomApiResourceClient({ baseUrl, applicationId, resourceId });
const r = await c.invoke("POST", "/v1/pay", "create-pay", {
query: { currency: "USD" },
headers: { "X-Key": "val" },
body: { type: "json", value: { amt: 100 } },
timeoutMs: 5000,
});
// r.ok ? r.result.status : r.errorHubSpotResourceClient
Constructor: new HubSpotResourceClient(config: BaseClientConfig)
Method: invoke(method: HttpMethod, path: string, invocationKey: string, options?: { query?: QueryParams; body?: { type: "json"; value: unknown }; timeoutMs?: number }): Promise<ApiInvokeResponse>
Params:
method:"GET" | "POST" | "PUT" | "PATCH" | "DELETE"path: HubSpot API pathinvocationKey: unique operation IDoptions.query:Record<string, string | string[]>options.body:{ type: "json"; value: unknown }- JSON onlyoptions.timeoutMs: timeout (default: 30000)
Result: Same as CustomApiResourceClient
Example:
import { HubSpotResourceClient } from "@major-tech/resource-client";
const c = new HubSpotResourceClient({ baseUrl, applicationId, resourceId });
const r = await c.invoke("GET", "/crm/v3/objects/contacts", "fetch-contacts", {
query: { limit: "10" },
});
// r.ok && r.result.body.kind === 'json' ? r.result.body.value : r.errorS3ResourceClient
Constructor: new S3ResourceClient(config: BaseClientConfig)
Method: invoke(command: S3Command, params: Record<string, unknown>, invocationKey: string, options?: { timeoutMs?: number }): Promise<StorageInvokeResponse>
Params:
command:"ListObjectsV2" | "HeadObject" | "GetObjectTagging" | "PutObjectTagging" | "DeleteObject" | "DeleteObjects" | "CopyObject" | "ListBuckets" | "GetBucketLocation" | "GeneratePresignedUrl"params: Command-specific params (e.g.,{ Bucket, Prefix, Key, expiresIn })invocationKey: unique operation IDoptions.timeoutMs: optional timeout
Result (ok=true):
{ kind: "storage"; command: string; data: unknown } | { kind: "storage"; presignedUrl: string; expiresAt: string }- Standard commands return
{ kind: "storage"; command; data } GeneratePresignedUrlreturns{ kind: "storage"; presignedUrl; expiresAt }
Example:
import { S3ResourceClient } from "@major-tech/resource-client";
const c = new S3ResourceClient({ baseUrl, applicationId, resourceId });
const r = await c.invoke(
"ListObjectsV2",
{ Bucket: "my-bucket", Prefix: "uploads/" },
"list-uploads"
);
// r.ok ? r.result.data : r.error
const u = await c.invoke(
"GeneratePresignedUrl",
{ Bucket: "my-bucket", Key: "file.pdf", expiresIn: 3600 },
"presigned"
);
// u.ok && 'presignedUrl' in u.result ? u.result.presignedUrl : u.errorError Handling
import { ResourceInvokeError } from '@major-tech/resource-client';
try { await client.invoke(...); }
catch (e) { if (e instanceof ResourceInvokeError) { e.message, e.httpStatus, e.requestId } }CLI - Singleton Generator
Commands:
npx major-client add <resourceId> <name> <type> <desc> <appId>- Add resource, generate singletonnpx major-client list- List all resourcesnpx major-client remove <name>- Remove resourcenpx major-client regenerate- Regenerate all clients
Types: database-postgresql | database-dynamodb | api-custom | api-hubspot | storage-s3
Generated Files:
resources.json- Resource registrysrc/clients/<name>.ts- Singleton clientsrc/clients/index.ts- Exports
Env Vars: MAJOR_API_BASE_URL, MAJOR_JWT_TOKEN
Example:
npx major-client add "res_123" "orders-db" "database-postgresql" "Orders DB" "app_456"import { ordersDbClient } from "./clients";
const r = await ordersDbClient.invoke(
"SELECT * FROM orders",
[],
"list-orders"
);MIT License
