@sparqjs/api-client 0.1.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/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @sparqjs/api-client
2
+
3
+ `@sparqjs/api-client` 是 Sparq 前端共享的 HTTP 传输层。它封装 Axios、请求配置、响应 envelope 解包和统一错误,不承载 Admin、Schema、Storage、Settings 或插件业务协议。
4
+
5
+ ## 负责范围
6
+
7
+ - 配置 `baseURL`、Cookie、Header、Token、CSRF、超时和参数序列化。
8
+ - 解包后端 `code/data/message` 响应。
9
+ - 将 HTTP、网络和业务 envelope 错误归一化为 `SparqApiError`。
10
+ - 提供 response、error、unauthorized 和 forbidden hooks。
11
+ - 透传 Axios 支持的 `AbortSignal`、上传进度等单次请求配置。
12
+
13
+ ## 不负责范围
14
+
15
+ - 不增加 `schema`、`storage`、`settings`、`admin` 等领域 namespace。
16
+ - 不依赖 Vue、Router、Pinia、schema core 或 schema protocol。
17
+ - 不定义业务 DTO、页面反馈、登录状态或 `DataAdapter`。
18
+ - 不向插件暴露宿主 Admin 已配置 Cookie 和 CSRF 的 transport 实例。
19
+
20
+ 领域 HTTP adapter 应放在真实消费者中。Admin 的正式实现位于 `apps/admin/src/client/api`,Stage 的验证实现位于 `apps/stage/src/api`;两者分别满足自身运行场景,不为表面复用提前拆成新包。
21
+
22
+ ## 使用方式
23
+
24
+ ```ts
25
+ import { createSparqApiClient } from '@sparqjs/api-client'
26
+
27
+ const transport = createSparqApiClient({
28
+ baseURL: '/api',
29
+ withCredentials: true,
30
+ })
31
+
32
+ const result = await transport.request<{ id: string }>({
33
+ method: 'GET',
34
+ url: '/records/1',
35
+ })
36
+ ```
37
+
38
+ 宿主应用应按认证边界创建 transport。Admin 当前只创建一个 authority-scoped 实例,认证、管理和 schema 领域 adapter 共同复用该实例。
@@ -0,0 +1,6 @@
1
+ import type { CreateSparqApiClientOptions, SparqApiClient } from './types';
2
+ /**
3
+ * 创建 Sparq API client。
4
+ */
5
+ export declare function createSparqApiClient(options?: CreateSparqApiClientOptions): SparqApiClient;
6
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE1E;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,2BAAgC,GAAG,cAAc,CAE9F"}
package/dist/client.js ADDED
@@ -0,0 +1,8 @@
1
+ import { createRequestExecutor } from './request';
2
+ /**
3
+ * 创建 Sparq API client。
4
+ */
5
+ export function createSparqApiClient(options = {}) {
6
+ return createRequestExecutor(options);
7
+ }
8
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAA;AAGjD;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAuC,EAAE;IAC1E,OAAO,qBAAqB,CAAC,OAAO,CAAC,CAAA;AACzC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { SparqApiError } from './types';
2
+ /**
3
+ * 创建标准 API 错误。
4
+ */
5
+ export declare function createSparqApiError(input: {
6
+ status?: number;
7
+ code?: string;
8
+ message?: string;
9
+ details?: unknown;
10
+ requestId?: string;
11
+ raw?: unknown;
12
+ }): SparqApiError;
13
+ /**
14
+ * 把 axios 或未知错误归一化为 SparqApiError。
15
+ */
16
+ export declare function normalizeApiError(error: unknown): SparqApiError;
17
+ /**
18
+ * 判断是否已经是标准 API 错误。
19
+ */
20
+ export declare function isSparqApiError(error: unknown): error is SparqApiError;
21
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,OAAO,CAAA;CAChB,GAAG,aAAa,CA+BhB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CAiC/D;AAcD;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAEtE"}
package/dist/error.js ADDED
@@ -0,0 +1,119 @@
1
+ import axios from 'axios';
2
+ /**
3
+ * 创建标准 API 错误。
4
+ */
5
+ export function createSparqApiError(input) {
6
+ const error = new Error(input.message || '请求失败');
7
+ Object.defineProperties(error, {
8
+ name: {
9
+ value: 'SparqApiError',
10
+ enumerable: true,
11
+ },
12
+ status: {
13
+ value: input.status ?? 0,
14
+ enumerable: true,
15
+ },
16
+ code: {
17
+ value: input.code || 'API_ERROR',
18
+ enumerable: true,
19
+ },
20
+ details: {
21
+ value: input.details,
22
+ enumerable: true,
23
+ },
24
+ requestId: {
25
+ value: input.requestId,
26
+ enumerable: true,
27
+ },
28
+ raw: {
29
+ value: input.raw,
30
+ enumerable: false,
31
+ },
32
+ });
33
+ return error;
34
+ }
35
+ /**
36
+ * 把 axios 或未知错误归一化为 SparqApiError。
37
+ */
38
+ export function normalizeApiError(error) {
39
+ if (isSparqApiError(error)) {
40
+ return error;
41
+ }
42
+ if (axios.isAxiosError(error)) {
43
+ const response = error.response;
44
+ const data = response?.data;
45
+ const body = isRecord(data) ? data : undefined;
46
+ const status = response?.status ?? 0;
47
+ const requestId = readRequestId(response?.headers);
48
+ return createSparqApiError({
49
+ status,
50
+ code: readCode(body) || readString(body, 'error') || readAxiosErrorCode(error) || fallbackCode(status),
51
+ message: readString(body, 'message') || error.message || fallbackMessage(status),
52
+ details: body?.details ?? body?.errors ?? body?.data,
53
+ requestId,
54
+ raw: error,
55
+ });
56
+ }
57
+ if (error instanceof Error) {
58
+ return createSparqApiError({
59
+ message: error.message,
60
+ raw: error,
61
+ });
62
+ }
63
+ return createSparqApiError({
64
+ message: String(error || '请求失败'),
65
+ raw: error,
66
+ });
67
+ }
68
+ function readAxiosErrorCode(error) {
69
+ return typeof error.code === 'string' && error.code.trim() !== '' ? error.code : undefined;
70
+ }
71
+ function readCode(record) {
72
+ const value = record?.code;
73
+ if (typeof value === 'number') {
74
+ return String(value);
75
+ }
76
+ return typeof value === 'string' && value.trim() !== '' ? value : undefined;
77
+ }
78
+ /**
79
+ * 判断是否已经是标准 API 错误。
80
+ */
81
+ export function isSparqApiError(error) {
82
+ return isRecord(error) && error.name === 'SparqApiError';
83
+ }
84
+ function fallbackCode(status) {
85
+ if (status === 401) {
86
+ return 'UNAUTHORIZED';
87
+ }
88
+ if (status === 403) {
89
+ return 'FORBIDDEN';
90
+ }
91
+ if (status >= 500) {
92
+ return 'SERVER_ERROR';
93
+ }
94
+ return 'API_ERROR';
95
+ }
96
+ function fallbackMessage(status) {
97
+ if (status === 401) {
98
+ return '登录状态已失效';
99
+ }
100
+ if (status === 403) {
101
+ return '没有权限执行该操作';
102
+ }
103
+ return '请求失败';
104
+ }
105
+ function readString(record, key) {
106
+ const value = record?.[key];
107
+ return typeof value === 'string' && value.trim() !== '' ? value : undefined;
108
+ }
109
+ function readRequestId(headers) {
110
+ if (!isRecord(headers)) {
111
+ return undefined;
112
+ }
113
+ const value = headers['x-request-id'] ?? headers['X-Request-Id'];
114
+ return typeof value === 'string' && value.trim() !== '' ? value : undefined;
115
+ }
116
+ function isRecord(value) {
117
+ return typeof value === 'object' && value !== null;
118
+ }
119
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { createSparqApiClient } from './client';
2
+ export { createSparqApiError, isSparqApiError, normalizeApiError } from './error';
3
+ export type { CreateSparqApiClientOptions, SparqApiClient, SparqApiClientHooks, SparqApiError, SparqRequestConfig, } from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAC/C,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AACjF,YAAY,EACR,2BAA2B,EAC3B,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,kBAAkB,GACrB,MAAM,SAAS,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { createSparqApiClient } from './client';
2
+ export { createSparqApiError, isSparqApiError, normalizeApiError } from './error';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAC/C,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { CreateSparqApiClientOptions, SparqApiClient } from './types';
2
+ /**
3
+ * 创建底层请求执行器。
4
+ */
5
+ export declare function createRequestExecutor(options: CreateSparqApiClientOptions): Pick<SparqApiClient, 'http' | 'request'>;
6
+ //# sourceMappingURL=request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,cAAc,EAAsB,MAAM,SAAS,CAAA;AAE9F;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,2BAA2B,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC,CAuEpH"}
@@ -0,0 +1,106 @@
1
+ import axios from 'axios';
2
+ import { createSparqApiError, normalizeApiError } from './error';
3
+ /**
4
+ * 创建底层请求执行器。
5
+ */
6
+ export function createRequestExecutor(options) {
7
+ const http = options.axios ??
8
+ axios.create({
9
+ baseURL: options.baseURL,
10
+ timeout: options.timeout,
11
+ withCredentials: options.withCredentials,
12
+ paramsSerializer: {
13
+ serialize: serializeParams,
14
+ },
15
+ });
16
+ http.interceptors.request.use((config) => {
17
+ const token = options.getToken?.();
18
+ const dynamicHeaders = options.getHeaders?.();
19
+ if (token) {
20
+ config.headers = config.headers ?? {};
21
+ config.headers.Authorization = `Bearer ${token}`;
22
+ }
23
+ if (dynamicHeaders) {
24
+ for (const [key, value] of Object.entries(dynamicHeaders)) {
25
+ if (value !== undefined && value !== null) {
26
+ config.headers = config.headers ?? {};
27
+ config.headers[key] = value;
28
+ }
29
+ }
30
+ }
31
+ return config;
32
+ });
33
+ http.interceptors.response.use((response) => {
34
+ options.onResponse?.(response);
35
+ return response;
36
+ }, (error) => {
37
+ if (axios.isAxiosError(error) && error.response) {
38
+ options.onResponse?.(error.response);
39
+ }
40
+ return Promise.reject(error);
41
+ });
42
+ async function request(config) {
43
+ const silent = config.silent ?? options.silent ?? false;
44
+ try {
45
+ const response = await http.request(config);
46
+ return unwrapResponseData(response.data);
47
+ }
48
+ catch (caught) {
49
+ const error = normalizeApiError(caught);
50
+ if (!silent) {
51
+ if (error.status === 401) {
52
+ options.onUnauthorized?.(error);
53
+ }
54
+ else if (error.status === 403) {
55
+ options.onForbidden?.(error);
56
+ }
57
+ options.onError?.(error);
58
+ }
59
+ throw error;
60
+ }
61
+ }
62
+ return {
63
+ http,
64
+ request,
65
+ };
66
+ }
67
+ function serializeParams(params) {
68
+ if (!isRecord(params)) {
69
+ return '';
70
+ }
71
+ const values = new URLSearchParams();
72
+ for (const [key, value] of Object.entries(params)) {
73
+ if (value === undefined || value === null || value === '') {
74
+ continue;
75
+ }
76
+ if (typeof value === 'object') {
77
+ values.set(key, JSON.stringify(value));
78
+ continue;
79
+ }
80
+ values.set(key, String(value));
81
+ }
82
+ return values.toString();
83
+ }
84
+ function unwrapResponseData(data) {
85
+ if (!isRecord(data)) {
86
+ return data;
87
+ }
88
+ if (typeof data.code === 'number' && 'data' in data) {
89
+ if (data.code === 0) {
90
+ return data.data;
91
+ }
92
+ const details = data.data;
93
+ throw createSparqApiError({
94
+ status: 200,
95
+ code: isRecord(details) && typeof details.code === 'string' ? details.code : String(data.code),
96
+ message: typeof data.message === 'string' ? data.message : '请求失败',
97
+ details,
98
+ raw: data,
99
+ });
100
+ }
101
+ return data;
102
+ }
103
+ function isRecord(value) {
104
+ return typeof value === 'object' && value !== null;
105
+ }
106
+ //# sourceMappingURL=request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
2
+ /**
3
+ * 请求生命周期钩子。
4
+ *
5
+ * api-client 只负责触发钩子,不直接绑定任何 UI 提示组件。
6
+ */
7
+ export interface SparqApiClientHooks {
8
+ /** 收到 HTTP 响应时触发,包括非 2xx 响应。 */
9
+ onResponse?: (response: AxiosResponse) => void;
10
+ /** 请求失败时触发。silent 请求不会触发该钩子。 */
11
+ onError?: (error: SparqApiError) => void;
12
+ /** HTTP 401 时触发。 */
13
+ onUnauthorized?: (error: SparqApiError) => void;
14
+ /** HTTP 403 时触发。 */
15
+ onForbidden?: (error: SparqApiError) => void;
16
+ }
17
+ /**
18
+ * 创建 Sparq API client 的配置。
19
+ */
20
+ export interface CreateSparqApiClientOptions extends SparqApiClientHooks {
21
+ /** API 根地址,例如 /api。 */
22
+ baseURL?: string;
23
+ /** 请求超时时间。 */
24
+ timeout?: number;
25
+ /** 是否携带 cookie。 */
26
+ withCredentials?: boolean;
27
+ /** 动态读取认证 token。 */
28
+ getToken?: () => string | undefined | null;
29
+ /** 动态读取附加请求头,例如租户、应用或插件上下文。 */
30
+ getHeaders?: () => Record<string, string | undefined | null>;
31
+ /** 自定义 axios 实例,测试或高级接入时使用。 */
32
+ axios?: AxiosInstance;
33
+ /** 默认是否静默错误。 */
34
+ silent?: boolean;
35
+ }
36
+ /**
37
+ * 单次请求配置。
38
+ */
39
+ export interface SparqRequestConfig<TData = unknown> extends AxiosRequestConfig<TData> {
40
+ /** 静默请求不会触发 onError/onUnauthorized/onForbidden。 */
41
+ silent?: boolean;
42
+ }
43
+ /**
44
+ * Sparq API client 实例。
45
+ */
46
+ export interface SparqApiClient {
47
+ /** 底层 axios 实例。 */
48
+ readonly http: AxiosInstance;
49
+ /** 执行请求并返回响应业务数据。 */
50
+ request<T = unknown, TData = unknown>(config: SparqRequestConfig<TData>): Promise<T>;
51
+ }
52
+ /**
53
+ * 归一化后的 API 错误。
54
+ */
55
+ export interface SparqApiError extends Error {
56
+ readonly name: 'SparqApiError';
57
+ readonly status: number;
58
+ readonly code: string;
59
+ readonly details?: unknown;
60
+ readonly requestId?: string;
61
+ readonly raw?: unknown;
62
+ }
63
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE7E;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAChC,gCAAgC;IAChC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAA;IAC9C,gCAAgC;IAChC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IACxC,oBAAoB;IACpB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAC/C,oBAAoB;IACpB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,2BAA4B,SAAQ,mBAAmB;IACpE,uBAAuB;IACvB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mBAAmB;IACnB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,CAAA;IAC1C,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,CAAA;IAC5D,+BAA+B;IAC/B,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,gBAAgB;IAChB,MAAM,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,KAAK,GAAG,OAAO,CAAE,SAAQ,kBAAkB,CAAC,KAAK,CAAC;IAClF,mDAAmD;IACnD,MAAM,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,mBAAmB;IACnB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;IAC5B,qBAAqB;IACrB,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,GAAG,OAAO,EAAE,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;CACvF;AAED;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CACzB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@sparqjs/api-client",
3
+ "version": "0.1.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "type": "module",
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {
21
+ "axios": "^1.7.0"
22
+ }
23
+ }