@seam-rpc/client 4.3.21 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { RpcError, type Result } from "@seam-rpc/core";
2
- export { RpcError };
1
+ import { ApiError, type Result } from "@seam-rpc/core";
2
+ export { ApiError as RpcError };
3
3
  export type { Result };
4
4
  export type SeamRequestMiddleware = (context: SeamRequestMiddlewareContext) => void | Promise<void>;
5
5
  export type SeamResponseMiddleware = (context: SeamResponseMiddlewareContext) => void | Promise<void>;
@@ -19,23 +19,24 @@ export interface SeamClientOptions {
19
19
  response?: SeamResponseMiddleware[];
20
20
  };
21
21
  }
22
- export declare class SeamClient {
22
+ export declare class SeamClient<ApiType> {
23
23
  readonly baseUrl: string;
24
- static _instance: SeamClient;
25
24
  options: SeamClientOptions;
25
+ readonly api: ApiType;
26
26
  constructor(baseUrl: string, options?: SeamClientOptions);
27
27
  preRequest(middleware: SeamRequestMiddleware): void;
28
28
  postRequest(middleware: SeamResponseMiddleware): void;
29
29
  }
30
- export declare class SeamError extends RpcError {
30
+ export declare class SeamError extends ApiError {
31
31
  constructor(code: string);
32
32
  }
33
- type SeamClientErrorType = "REQUEST_FAILED" | "TIMEOUT" | "PARSE_ERROR" | "INVALID_RESPONSE";
33
+ type SeamClientErrorType = "REQUEST_FAILED" | "INVALID_CONTENT_TYPE";
34
34
  export declare class SeamClientError extends Error {
35
35
  readonly type: SeamClientErrorType;
36
+ readonly url: string;
36
37
  readonly request: RequestInit;
37
38
  readonly cause: unknown;
38
- constructor(type: SeamClientErrorType, message: string, request: RequestInit, cause: unknown);
39
+ constructor(type: SeamClientErrorType, message: string, url: string, request: RequestInit, cause: unknown);
39
40
  }
40
- export declare function createSeamClient(baseUrl: string, options?: SeamClientOptions): SeamClient;
41
- export declare function callApi(routerName: string, funcName: string, input?: Record<string, any>): Promise<any>;
41
+ export declare function createSeamClient<ApiType>(baseUrl: string, options?: SeamClientOptions): SeamClient<ApiType>;
42
+ export declare function callApi(seamClient: SeamClient<any>, routerName: string, funcName: string, input?: Record<string, any>): Promise<any>;
package/dist/index.js CHANGED
@@ -1,15 +1,26 @@
1
- import { extractFiles, injectFiles, RpcError } from "@seam-rpc/core";
2
- export { RpcError };
1
+ import { extractFiles, injectFiles, ApiError } from "@seam-rpc/core";
2
+ export { ApiError as RpcError };
3
3
  export class SeamClient {
4
4
  constructor(baseUrl, options) {
5
5
  this.baseUrl = baseUrl;
6
- SeamClient._instance = this;
7
6
  this.options = {
8
7
  middleware: {
9
8
  request: options?.middleware?.request || [],
10
9
  response: options?.middleware?.response || [],
11
10
  }
12
11
  };
12
+ const client = this;
13
+ this.api = new Proxy({}, {
14
+ get(_target, routerName) {
15
+ return new Proxy({}, {
16
+ get(_subTarget, procName) {
17
+ return async (input) => {
18
+ return callApi(client, String(routerName), String(procName), input);
19
+ };
20
+ },
21
+ });
22
+ },
23
+ });
13
24
  }
14
25
  preRequest(middleware) {
15
26
  this.options?.middleware?.request?.push(middleware);
@@ -18,15 +29,16 @@ export class SeamClient {
18
29
  this.options?.middleware?.response?.push(middleware);
19
30
  }
20
31
  }
21
- export class SeamError extends RpcError {
32
+ export class SeamError extends ApiError {
22
33
  constructor(code) {
23
34
  super(code, undefined);
24
35
  }
25
36
  }
26
37
  export class SeamClientError extends Error {
27
- constructor(type, message, request, cause) {
38
+ constructor(type, message, url, request, cause) {
28
39
  super(message);
29
40
  this.type = type;
41
+ this.url = url;
30
42
  this.request = request;
31
43
  this.cause = cause;
32
44
  this.name = "SeamClientError";
@@ -35,10 +47,7 @@ export class SeamClientError extends Error {
35
47
  export function createSeamClient(baseUrl, options) {
36
48
  return new SeamClient(baseUrl, options);
37
49
  }
38
- export async function callApi(routerName, funcName, input) {
39
- if (!SeamClient._instance)
40
- throw new Error("Seam Client not instantiated.");
41
- const seamClient = SeamClient._instance;
50
+ export async function callApi(seamClient, routerName, funcName, input) {
42
51
  const req = buildRequest(input);
43
52
  const url = `${seamClient.baseUrl}/${routerName}/${funcName}`;
44
53
  if (seamClient.options?.middleware?.request) {
@@ -56,30 +65,27 @@ export async function callApi(routerName, funcName, input) {
56
65
  res = await fetch(url, req);
57
66
  }
58
67
  catch (err) {
59
- throw new SeamClientError("REQUEST_FAILED", "Failed to send request.", req, err);
68
+ throw new SeamClientError("REQUEST_FAILED", "Failed to send request.", url, req, err);
60
69
  }
61
70
  if (!res.ok) {
62
71
  if (res.status == 400) {
63
72
  const resError = await res.json();
64
- if (resError.rpcError) {
73
+ if (resError.isApiError) {
65
74
  return {
66
75
  ok: false,
67
- error: RpcError.fromJSON(resError.error),
76
+ error: ApiError.fromJSON(resError.error),
68
77
  };
69
78
  }
70
- else {
71
- return { ok: false, error: null };
72
- }
79
+ throw new SeamClientError("REQUEST_FAILED", `Request failed with status ${res.status} ${res.statusText} and non-api error.`, url, req, null);
73
80
  }
74
- // throw new Error(`Request failed at router ${routerName} at function ${funcName}, with status ${res.status} ${res.statusText}.`);
75
- return { ok: false, error: null };
81
+ throw new SeamClientError("REQUEST_FAILED", `Request failed with status ${res.status} ${res.statusText}.`, url, req, null);
76
82
  }
77
83
  const contentType = res.headers.get("content-type") || "";
78
84
  if (contentType.startsWith("application/json")) {
79
85
  const data = await res.json();
80
86
  return data.result;
81
87
  }
82
- else if (contentType.startsWith("multipart/form-data")) {
88
+ if (contentType.startsWith("multipart/form-data")) {
83
89
  const formData = await res.formData();
84
90
  const jsonPart = JSON.parse(formData.get("json")?.toString() || "[]");
85
91
  const pathsPart = JSON.parse(formData.get("paths")?.toString() || "[]");
@@ -109,9 +115,7 @@ export async function callApi(routerName, funcName, input) {
109
115
  }
110
116
  return jsonPart.result;
111
117
  }
112
- else {
113
- return { ok: false, error: null };
114
- }
118
+ throw new SeamClientError("INVALID_CONTENT_TYPE", `Response has invalid content type ${contentType}.`, url, req, null);
115
119
  }
116
120
  function buildRequest(input = {}) {
117
121
  let req;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seam-rpc/client",
3
- "version": "4.3.21",
3
+ "version": "5.0.0",
4
4
  "main": "./dist/index.js",
5
5
  "type": "module",
6
6
  "files": [