@snail-js/api 0.1.2 → 0.1.3

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 CHANGED
@@ -2,14 +2,13 @@
2
2
  <img src="https://img.shields.io/badge/TypeScript-1e80ff"></img>
3
3
  <img src="https://img.shields.io/npm/v/axios?label=axios&labelColor=1e80ff&color=67C23A"></img>
4
4
  </p>
5
- ## 项目介绍
6
5
 
6
+ ## 项目介绍
7
7
  - 基于 Axios 二次封装
8
8
  - 使用`reflect-metadata`创建和处理元数据
9
9
  - 提供装饰器方式定义请求,基本实例`Snail`,请求实例`Api`
10
10
 
11
11
  ## 安装
12
-
13
12
  `npm install @snail-js/api`
14
13
 
15
14
  ## 使用
@@ -48,6 +47,7 @@ import { Snail, Server } from "@snail-js/api";
48
47
  timeout: 5000,
49
48
  })
50
49
  class BackEnd extends Snail {}
50
+
51
51
  export const Service = new BackEnd();
52
52
  ```
53
53
 
@@ -61,6 +61,7 @@ import { Service } from "./service";
61
61
 
62
62
  @Api("user")
63
63
  class UserApi {
64
+
64
65
  @Get()
65
66
  get(@Params("id") id: string) {}
66
67
 
@@ -88,12 +89,13 @@ if (error !== null) {
88
89
  - `baseUrl`:同`Axios`,使用`vite.proxy`时,请使用`\`开头,直接跨域请求请填写完整地址
89
90
  - `Versioning`:版本管理器
90
91
  - type:管理器类型,enum:Uri,Head,Query,Custom
91
- - prifix:前缀
92
+ - prifix:前缀,字符串;添加在版本号前面的字符,默认为`v`
92
93
  - defaultVersion:全局默认版本
93
94
  - timenout:全局超时时间,会被 Api 的 timeout 值覆盖
94
95
  - CacheManage:缓存管理器
95
- - type:缓存管理器类型,CacheType,enum:localStorage,IndexDB,Memory
96
+ - type:缓存管理器类型,CacheType,`enum:localStorage,IndexDB,Memory`
96
97
  - ttl: 缓存过期时间
98
+ - enableLog: 是否打印日志
97
99
 
98
100
  ## Api 配置
99
101
 
@@ -117,6 +119,7 @@ if (error !== null) {
117
119
  ```typescript
118
120
  @Api("user")
119
121
  class UserApi {
122
+
120
123
  @Get()
121
124
  get(@Params("id") id: string, @Params("sign") sign: string) {}
122
125
  }
@@ -134,6 +137,7 @@ class QueryParams {
134
137
 
135
138
  @Api("user")
136
139
  class UserApi {
140
+
137
141
  @Get()
138
142
  get(@Params() params: QueryParams) {}
139
143
  }
@@ -151,6 +155,7 @@ class QueryParams {
151
155
 
152
156
  @Api("user")
153
157
  class UserApi {
158
+
154
159
  @Get()
155
160
  get(@Params() params: QueryParams, @Params("a") a: number) {}
156
161
  }
@@ -286,10 +291,11 @@ export type VersioningOption =
286
291
  ```
287
292
 
288
293
  ### 临时版本修改器`@Version`
289
-
294
+ - 临时改变方法请求的版本
290
295
  ```typescript
291
296
  @Api("test")
292
297
  class Test {
298
+
293
299
  @Get("HelloWorld")
294
300
  @Version("0.2.0")
295
301
  test() {}
@@ -299,7 +305,35 @@ class Test {
299
305
  > 临时改变 api 版本,便于测试
300
306
 
301
307
  ### 缓存装饰器`@Cache`
302
- - 待测试,测试后发布文档
308
+ - `@Cache(string | null)`
309
+ - 当设置为null时,此方法不应用缓存
310
+ - 当设置为string时,应为此Api类下的方法名称,当设置的此名称方法被调用且正常响应时,被装饰的方法缓存失效
311
+
312
+ ```typescript
313
+
314
+ @Api("test")
315
+ class Test {
316
+
317
+ @Get("HelloWorld")
318
+ @Cache("test2")
319
+ test1() {}
320
+
321
+ @Post()
322
+ test2() {}
323
+
324
+ @Get()
325
+ @Cache(null)
326
+ test3() {}
327
+ }
328
+ ```
329
+
330
+ > 当请求`[Post]test`成功时,`[Get]test/HelloWorld`的缓存失效
331
+ > 注意:`test2`方法请求成功的前提是需要设置`@Cache(null)`,否则仅第一次请求会发送,后续请求需等待缓存管理设置的ttl时间到期才会发送请求
332
+ > 因此,若未设置`test2`方法的`@Cache(null)`,仅第一次请求会使`[Get]test/HelloWorld`的缓存失效,后续需等待ttl时间到期,才会继续失效
333
+
334
+ > `test3`方法请求成功时,不缓存
335
+
336
+ > 注意:要使用缓存,请配置`@Server({CacheManage})`缓存管理器
303
337
 
304
338
  ### 代码仓库
305
339
 
@@ -7,14 +7,22 @@ export declare class Snail<R extends {
7
7
  private strategies;
8
8
  private cacheStorage?;
9
9
  private version?;
10
+ private sourceMap;
10
11
  registerStrategy(strategy: Strategy): void;
11
12
  createApi<T extends object>(constructor: new () => T): ApiProxy<T, R>;
12
13
  private buildRequestArgs;
13
14
  private getStrategies;
14
15
  private applyStrategies;
15
16
  private applyVersion;
16
- private applyCache;
17
- private getCacheConfig;
17
+ private getCache;
18
+ private initCacheManage;
19
+ private getHitSource;
20
+ private setHitSource;
21
+ private setCache;
22
+ private expireCache;
23
+ private getServerConfig;
24
+ private getApiConfig;
25
+ private initAxios;
18
26
  private handleResponse;
19
27
  private handleError;
20
28
  }
@@ -1,7 +1,7 @@
1
1
  import "reflect-metadata";
2
2
  import { ApiConfig } from "../typings";
3
- export declare const METHOD_KEY = "SNAIL_METHOD_KEY";
4
- export declare const API_CONFIG_KEY = "SNAIL_API_CONFIG_KEY";
3
+ export declare const METHOD_KEY: unique symbol;
4
+ export declare const API_CONFIG_KEY: unique symbol;
5
5
  export declare const Api: (url?: string, config?: ApiConfig) => ClassDecorator;
6
6
  export declare const Get: (path?: string) => (target: any, propertyKey: string | symbol) => void;
7
7
  export declare const Post: (path?: string) => (target: any, propertyKey: string | symbol) => void;
@@ -1,4 +1,3 @@
1
1
  import "reflect-metadata";
2
- import { CacheManagementOption } from '../typings';
3
- export declare const CACHE_KEY = "SNALI_CACHE_KEY";
4
- export declare const Cache: (options: CacheManagementOption) => (target: any, propertyKey?: string) => void;
2
+ export declare const CACHE_OPTIONS_KEY: unique symbol;
3
+ export declare const Cache: (hitSource: string | null) => (target: any, propertyKey?: string) => void;
@@ -1,4 +1,4 @@
1
1
  import "reflect-metadata";
2
2
  import { SnailOption } from "../typings";
3
- export declare const SERVER_CONFIG_KEY = "SANIL_SERVER_CONFIG_KEY";
3
+ export declare const SERVER_CONFIG_KEY: unique symbol;
4
4
  export declare const Server: (config: SnailOption) => (target: any) => void;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  export * from "./core";
2
- export * from "./decorators/server";
3
- export * from "./decorators/api";
4
- export * from "./decorators/cache";
5
- export * from "./decorators/param";
6
- export * from "./decorators/strategy";
7
- export * from "./decorators/versioning";
2
+ export { Server } from "./decorators/server";
3
+ export { Api, Get, Put, Post, Patch, Options, Head, Delete, } from "./decorators/api";
4
+ export { Cache } from "./decorators/cache";
5
+ export { Params, Data } from "./decorators/param";
6
+ export { UseStrategy } from "./decorators/strategy";
7
+ export { Versioning, Version } from "./decorators/versioning";
8
8
  export * from "./typings";
9
9
  export * from "./utils";
package/dist/snail-api.js CHANGED
@@ -3741,8 +3741,8 @@ function applyVersioning(version, versioning) {
3741
3741
  versioning
3742
3742
  );
3743
3743
  }
3744
- const METHOD_KEY = "SNAIL_METHOD_KEY";
3745
- const API_CONFIG_KEY = "SNAIL_API_CONFIG_KEY";
3744
+ const METHOD_KEY = Symbol("SNAIL_METHOD_KEY");
3745
+ const API_CONFIG_KEY = Symbol("SNAIL_API_CONFIG_KEY");
3746
3746
  const Api = (url = "", config) => {
3747
3747
  return (target) => {
3748
3748
  Reflect.defineMetadata(API_CONFIG_KEY, { url, ...config }, target);
@@ -3766,7 +3766,7 @@ const Delete = createMethodDecorator(RequestMethod.DELETE);
3766
3766
  const Patch = createMethodDecorator(RequestMethod.PATCH);
3767
3767
  const Options = createMethodDecorator(RequestMethod.OPTIONS);
3768
3768
  const Head = createMethodDecorator(RequestMethod.HEAD);
3769
- const SERVER_CONFIG_KEY = "SANIL_SERVER_CONFIG_KEY";
3769
+ const SERVER_CONFIG_KEY = Symbol("SANIL_SERVER_CONFIG_KEY");
3770
3770
  const Server = (config) => {
3771
3771
  return (target) => {
3772
3772
  Reflect.defineMetadata(SERVER_CONFIG_KEY, config, target);
@@ -3801,11 +3801,11 @@ const Version = (version) => {
3801
3801
  Reflect.defineMetadata(VERSION_KEY, version, target, propertyKey);
3802
3802
  };
3803
3803
  };
3804
- const CACHE_KEY = "SNALI_CACHE_KEY";
3805
- const Cache = (options) => {
3804
+ const CACHE_OPTIONS_KEY = Symbol("SNALI_CACHE_OPTIONS_KEY");
3805
+ const Cache = (hitSource) => {
3806
3806
  return (target, propertyKey) => {
3807
- const key = propertyKey ? `${CACHE_KEY}_${propertyKey}` : CACHE_KEY;
3808
- Reflect.defineMetadata(key, options, target);
3807
+ const key = propertyKey ? `${CACHE_OPTIONS_KEY.toString()}_${propertyKey}` : CACHE_OPTIONS_KEY;
3808
+ Reflect.defineMetadata(key, hitSource, target);
3809
3809
  };
3810
3810
  };
3811
3811
  class Snail {
@@ -3815,39 +3815,25 @@ class Snail {
3815
3815
  __publicField(this, "strategies", []);
3816
3816
  __publicField(this, "cacheStorage");
3817
3817
  __publicField(this, "version");
3818
+ __publicField(this, "sourceMap", /* @__PURE__ */ new Map());
3818
3819
  }
3819
3820
  registerStrategy(strategy) {
3820
3821
  this.strategies.push(strategy);
3821
3822
  }
3822
3823
  createApi(constructor) {
3823
3824
  const instance = new constructor();
3824
- const serverConfig = Reflect.getMetadata(
3825
- SERVER_CONFIG_KEY,
3826
- this.constructor
3827
- );
3828
- console.log("serverConfig:", serverConfig);
3829
- if (!this.axiosInstance) {
3830
- this.axiosInstance = axios.create({
3831
- baseURL: serverConfig.baseURL,
3832
- timeout: serverConfig.timeout
3833
- });
3834
- }
3835
- const cacheManage = Reflect.getMetadata(
3836
- CACHE_KEY,
3837
- this
3838
- );
3839
- if (!this.cacheStorage && cacheManage !== void 0) {
3840
- this.cacheStorage = createCache(cacheManage.type, cacheManage.ttl || 300);
3841
- }
3842
- const apiConfig = Reflect.getMetadata(
3843
- API_CONFIG_KEY,
3844
- constructor
3845
- );
3846
- console.log("ApiConfig:", apiConfig);
3825
+ const serverConfig = this.getServerConfig();
3826
+ const { baseURL, timeout, CacheManage, enableLog } = serverConfig;
3827
+ enableLog && console.log("serverConfig:", serverConfig);
3828
+ this.initAxios({ baseURL, timeout });
3829
+ enableLog && console.log("CacheManage:", CacheManage);
3830
+ this.initCacheManage(CacheManage);
3831
+ const apiConfig = this.getApiConfig(constructor);
3832
+ enableLog && console.log("ApiConfig:", apiConfig);
3847
3833
  this.version = apiConfig.version;
3848
3834
  return new Proxy(instance, {
3849
3835
  get: (target, propertyKey) => {
3850
- console.log("proxy:", target, "|", propertyKey);
3836
+ enableLog && console.log("proxy:", target, "|", propertyKey);
3851
3837
  if (typeof propertyKey !== "string") return;
3852
3838
  const methodConfig = Reflect.getMetadata(
3853
3839
  METHOD_KEY,
@@ -3857,7 +3843,7 @@ class Snail {
3857
3843
  if (!methodConfig) return target[propertyKey];
3858
3844
  return async (...args) => {
3859
3845
  const url = methodConfig.path == "" ? apiConfig.url : apiConfig.url + `/${methodConfig.path}`;
3860
- console.log("url:", url);
3846
+ enableLog && console.log("url:", url);
3861
3847
  let request = {
3862
3848
  // baseURL: serverConfig.baseURL,
3863
3849
  url,
@@ -3868,35 +3854,11 @@ class Snail {
3868
3854
  ...request,
3869
3855
  ...this.applyVersion(request, target, propertyKey)
3870
3856
  };
3871
- console.log("版本管理参数:", request);
3857
+ enableLog && console.log("版本管理参数:", request);
3872
3858
  const strategies = this.getStrategies(target, propertyKey);
3873
- const methodCache = this.getCacheConfig(target, propertyKey) || void 0;
3874
- if (methodCache == void 0) {
3875
- const cached = await this.applyCache(request, cacheManage);
3876
- if (cached && cached.error === null) {
3877
- let cacheResponse = {
3878
- data: cached.data,
3879
- status: 304,
3880
- headers: {
3881
- hitCache: true
3882
- },
3883
- statusText: "get response data from cache",
3884
- config: { headers: new AxiosHeaders2() }
3885
- };
3886
- const responseStrategies = strategies.filter(
3887
- (strategy) => strategy.applyResponse
3888
- );
3889
- const strategyResponse = await this.applyStrategies(
3890
- cacheResponse,
3891
- responseStrategies,
3892
- "response"
3893
- );
3894
- return strategyResponse;
3895
- }
3896
- }
3897
3859
  const params = this.buildRequestArgs(target, propertyKey, args);
3898
3860
  request = { ...request, ...params };
3899
- console.log("构建请求参数:", request);
3861
+ enableLog && console.log("构建请求参数:", request);
3900
3862
  const requestStrategies = strategies.filter(
3901
3863
  (strategy) => strategy.applyRequest
3902
3864
  );
@@ -3905,10 +3867,24 @@ class Snail {
3905
3867
  requestStrategies,
3906
3868
  "request"
3907
3869
  );
3870
+ const hitSource = this.getHitSource(target, propertyKey);
3871
+ enableLog && console.log("hitSource:", hitSource);
3872
+ if (typeof hitSource == "string") {
3873
+ this.setHitSource(request, hitSource);
3874
+ }
3875
+ if (hitSource !== null) {
3876
+ const cachedResponse = await this.getCache(request, strategies);
3877
+ if (cachedResponse) {
3878
+ enableLog && console.warn("数据从缓存获取");
3879
+ return this.handleResponse(cachedResponse, true);
3880
+ }
3881
+ }
3908
3882
  try {
3909
- console.log("send request:", request);
3883
+ enableLog && console.log("send request:", request);
3910
3884
  const response = await this.axiosInstance(request);
3911
- return this.handleResponse(response);
3885
+ hitSource !== null && this.setCache(request, response);
3886
+ this.expireCache(propertyKey);
3887
+ return this.handleResponse(response, false);
3912
3888
  } catch (error) {
3913
3889
  return this.handleError(error);
3914
3890
  }
@@ -3919,7 +3895,6 @@ class Snail {
3919
3895
  buildRequestArgs(target, propertyKey, args) {
3920
3896
  const requestArgs = { params: {}, data: {} };
3921
3897
  const paramConfigs = Reflect.getMetadata(REQUEST_ARGS_KEY, target, propertyKey) || [];
3922
- console.log("请求参数:", paramConfigs);
3923
3898
  paramConfigs.forEach(({ index, type, key }) => {
3924
3899
  const value = args[index];
3925
3900
  if (type === "params" && !key && typeof value === "object") {
@@ -3939,14 +3914,11 @@ class Snail {
3939
3914
  }
3940
3915
  getStrategies(target, propertyKey) {
3941
3916
  const serverStrategies = Reflect.getMetadata(STRATEGY_KEY, this.constructor) || [];
3942
- console.log("serverStrategies:", serverStrategies);
3943
3917
  const classStrategies = Reflect.getMetadata(STRATEGY_KEY, target.constructor) || [];
3944
- console.log("classStrategies:", classStrategies);
3945
3918
  const methodStrategies = Reflect.getMetadata(
3946
3919
  `${STRATEGY_KEY.toString()}_${propertyKey}`,
3947
3920
  target
3948
3921
  ) || [];
3949
- console.log("methodStrategies:", methodStrategies);
3950
3922
  const allStrategies = [
3951
3923
  ...this.strategies,
3952
3924
  ...serverStrategies,
@@ -3967,7 +3939,6 @@ class Snail {
3967
3939
  VERSIONING_KEY,
3968
3940
  this.constructor
3969
3941
  );
3970
- console.log("版本管理器:", versioning);
3971
3942
  if (!versioning) return request;
3972
3943
  const version = Reflect.getMetadata(VERSION_KEY, target, propertyKey);
3973
3944
  const currentVersion = version || this.version || versioning.defaultVersion;
@@ -3978,24 +3949,95 @@ class Snail {
3978
3949
  const versionUrl = url ? `${url}/${request.url}` : request.url;
3979
3950
  return { ...request, url: versionUrl, headers, params };
3980
3951
  }
3981
- async applyCache(request, options) {
3952
+ async getCache(request, strategies) {
3953
+ var _a;
3954
+ if (!this.cacheStorage) return void 0;
3955
+ const cacheKey = apiKey(request);
3956
+ const cached = await ((_a = this.cacheStorage) == null ? void 0 : _a.get(cacheKey));
3957
+ if (cached && cached.error === null) {
3958
+ let cacheResponse = {
3959
+ data: cached.data,
3960
+ status: 304,
3961
+ headers: {},
3962
+ statusText: "get response data from cache",
3963
+ config: { headers: new AxiosHeaders2() }
3964
+ };
3965
+ const responseStrategies = strategies.filter(
3966
+ (strategy) => strategy.applyResponse
3967
+ );
3968
+ const strategyResponse = await this.applyStrategies(
3969
+ cacheResponse,
3970
+ responseStrategies,
3971
+ "response"
3972
+ );
3973
+ return strategyResponse;
3974
+ }
3975
+ }
3976
+ initCacheManage(options) {
3977
+ if (!this.cacheStorage && options !== void 0) {
3978
+ this.cacheStorage = createCache(options.type, options.ttl || 300);
3979
+ }
3980
+ }
3981
+ getHitSource(target, propertyKey) {
3982
+ const methodHitSource = Reflect.getMetadata(
3983
+ `${CACHE_OPTIONS_KEY.toString()}_${propertyKey}`,
3984
+ target
3985
+ );
3986
+ if (methodHitSource !== void 0) return methodHitSource;
3987
+ const apiHitSource = Reflect.getMetadata(
3988
+ CACHE_OPTIONS_KEY,
3989
+ target.constructor
3990
+ );
3991
+ return apiHitSource;
3992
+ }
3993
+ setHitSource(request, hitSource) {
3994
+ const cacheKeys = this.sourceMap.get(hitSource);
3995
+ const currentCacheKey = apiKey(request);
3996
+ if (cacheKeys) {
3997
+ cacheKeys.push(currentCacheKey);
3998
+ this.sourceMap.set(hitSource, cacheKeys);
3999
+ } else {
4000
+ this.sourceMap.set(hitSource, [currentCacheKey]);
4001
+ }
4002
+ }
4003
+ async setCache(request, response) {
3982
4004
  var _a;
3983
4005
  const cacheKey = apiKey(request);
3984
- if (this.cacheStorage) {
3985
- return await ((_a = this.cacheStorage) == null ? void 0 : _a.get(cacheKey));
4006
+ await ((_a = this.cacheStorage) == null ? void 0 : _a.set(cacheKey, response.data));
4007
+ }
4008
+ async expireCache(hitSource) {
4009
+ const keys = this.sourceMap.get(hitSource);
4010
+ if (keys) {
4011
+ Promise.all(
4012
+ keys.map(async (key) => {
4013
+ var _a;
4014
+ await ((_a = this.cacheStorage) == null ? void 0 : _a.delete(key));
4015
+ })
4016
+ );
3986
4017
  }
3987
- return void 0;
3988
4018
  }
3989
- getCacheConfig(target, propertyKey) {
3990
- return Reflect.getMetadata(`${CACHE_KEY.toString()}_${propertyKey}`, target) || // 方法级
3991
- Reflect.getMetadata(CACHE_KEY, target.constructor);
4019
+ getServerConfig() {
4020
+ return Reflect.getMetadata(
4021
+ SERVER_CONFIG_KEY,
4022
+ this.constructor
4023
+ );
4024
+ }
4025
+ getApiConfig(constructor) {
4026
+ return Reflect.getMetadata(API_CONFIG_KEY, constructor);
4027
+ }
4028
+ initAxios(config) {
4029
+ if (!this.axiosInstance) {
4030
+ this.axiosInstance = axios.create({
4031
+ baseURL: config.baseURL,
4032
+ timeout: config.timeout
4033
+ });
4034
+ }
3992
4035
  }
3993
- handleResponse(response) {
3994
- console.log("Response:", response);
4036
+ handleResponse(response, hitCache) {
3995
4037
  return {
3996
4038
  data: response.data,
3997
4039
  error: null,
3998
- hitCache: false
4040
+ hitCache
3999
4041
  };
4000
4042
  }
4001
4043
  handleError(error) {
@@ -4006,31 +4048,23 @@ class Snail {
4006
4048
  }
4007
4049
  }
4008
4050
  export {
4009
- API_CONFIG_KEY,
4010
4051
  Api,
4011
- CACHE_KEY,
4012
4052
  Cache,
4013
4053
  CacheType,
4014
4054
  Data,
4015
4055
  Delete,
4016
4056
  Get,
4017
4057
  Head,
4018
- METHOD_KEY,
4019
4058
  Options,
4020
4059
  Params,
4021
4060
  Patch,
4022
4061
  Post,
4023
4062
  Put,
4024
- REQUEST_ARGS_KEY,
4025
4063
  RequestMethod,
4026
- SERVER_CONFIG_KEY,
4027
- STRATEGY_KEY,
4028
4064
  Server,
4029
4065
  Snail,
4030
4066
  Strategy,
4031
4067
  UseStrategy,
4032
- VERSIONING_KEY,
4033
- VERSION_KEY,
4034
4068
  Version,
4035
4069
  Versioning,
4036
4070
  VersioningType,
@@ -3745,8 +3745,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3745
3745
  versioning
3746
3746
  );
3747
3747
  }
3748
- const METHOD_KEY = "SNAIL_METHOD_KEY";
3749
- const API_CONFIG_KEY = "SNAIL_API_CONFIG_KEY";
3748
+ const METHOD_KEY = Symbol("SNAIL_METHOD_KEY");
3749
+ const API_CONFIG_KEY = Symbol("SNAIL_API_CONFIG_KEY");
3750
3750
  const Api = (url = "", config) => {
3751
3751
  return (target) => {
3752
3752
  Reflect.defineMetadata(API_CONFIG_KEY, { url, ...config }, target);
@@ -3770,7 +3770,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3770
3770
  const Patch = createMethodDecorator(RequestMethod.PATCH);
3771
3771
  const Options = createMethodDecorator(RequestMethod.OPTIONS);
3772
3772
  const Head = createMethodDecorator(RequestMethod.HEAD);
3773
- const SERVER_CONFIG_KEY = "SANIL_SERVER_CONFIG_KEY";
3773
+ const SERVER_CONFIG_KEY = Symbol("SANIL_SERVER_CONFIG_KEY");
3774
3774
  const Server = (config) => {
3775
3775
  return (target) => {
3776
3776
  Reflect.defineMetadata(SERVER_CONFIG_KEY, config, target);
@@ -3805,11 +3805,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3805
3805
  Reflect.defineMetadata(VERSION_KEY, version, target, propertyKey);
3806
3806
  };
3807
3807
  };
3808
- const CACHE_KEY = "SNALI_CACHE_KEY";
3809
- const Cache = (options) => {
3808
+ const CACHE_OPTIONS_KEY = Symbol("SNALI_CACHE_OPTIONS_KEY");
3809
+ const Cache = (hitSource) => {
3810
3810
  return (target, propertyKey) => {
3811
- const key = propertyKey ? `${CACHE_KEY}_${propertyKey}` : CACHE_KEY;
3812
- Reflect.defineMetadata(key, options, target);
3811
+ const key = propertyKey ? `${CACHE_OPTIONS_KEY.toString()}_${propertyKey}` : CACHE_OPTIONS_KEY;
3812
+ Reflect.defineMetadata(key, hitSource, target);
3813
3813
  };
3814
3814
  };
3815
3815
  class Snail {
@@ -3819,39 +3819,25 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3819
3819
  __publicField(this, "strategies", []);
3820
3820
  __publicField(this, "cacheStorage");
3821
3821
  __publicField(this, "version");
3822
+ __publicField(this, "sourceMap", /* @__PURE__ */ new Map());
3822
3823
  }
3823
3824
  registerStrategy(strategy) {
3824
3825
  this.strategies.push(strategy);
3825
3826
  }
3826
3827
  createApi(constructor) {
3827
3828
  const instance = new constructor();
3828
- const serverConfig = Reflect.getMetadata(
3829
- SERVER_CONFIG_KEY,
3830
- this.constructor
3831
- );
3832
- console.log("serverConfig:", serverConfig);
3833
- if (!this.axiosInstance) {
3834
- this.axiosInstance = axios.create({
3835
- baseURL: serverConfig.baseURL,
3836
- timeout: serverConfig.timeout
3837
- });
3838
- }
3839
- const cacheManage = Reflect.getMetadata(
3840
- CACHE_KEY,
3841
- this
3842
- );
3843
- if (!this.cacheStorage && cacheManage !== void 0) {
3844
- this.cacheStorage = createCache(cacheManage.type, cacheManage.ttl || 300);
3845
- }
3846
- const apiConfig = Reflect.getMetadata(
3847
- API_CONFIG_KEY,
3848
- constructor
3849
- );
3850
- console.log("ApiConfig:", apiConfig);
3829
+ const serverConfig = this.getServerConfig();
3830
+ const { baseURL, timeout, CacheManage, enableLog } = serverConfig;
3831
+ enableLog && console.log("serverConfig:", serverConfig);
3832
+ this.initAxios({ baseURL, timeout });
3833
+ enableLog && console.log("CacheManage:", CacheManage);
3834
+ this.initCacheManage(CacheManage);
3835
+ const apiConfig = this.getApiConfig(constructor);
3836
+ enableLog && console.log("ApiConfig:", apiConfig);
3851
3837
  this.version = apiConfig.version;
3852
3838
  return new Proxy(instance, {
3853
3839
  get: (target, propertyKey) => {
3854
- console.log("proxy:", target, "|", propertyKey);
3840
+ enableLog && console.log("proxy:", target, "|", propertyKey);
3855
3841
  if (typeof propertyKey !== "string") return;
3856
3842
  const methodConfig = Reflect.getMetadata(
3857
3843
  METHOD_KEY,
@@ -3861,7 +3847,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3861
3847
  if (!methodConfig) return target[propertyKey];
3862
3848
  return async (...args) => {
3863
3849
  const url = methodConfig.path == "" ? apiConfig.url : apiConfig.url + `/${methodConfig.path}`;
3864
- console.log("url:", url);
3850
+ enableLog && console.log("url:", url);
3865
3851
  let request = {
3866
3852
  // baseURL: serverConfig.baseURL,
3867
3853
  url,
@@ -3872,35 +3858,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3872
3858
  ...request,
3873
3859
  ...this.applyVersion(request, target, propertyKey)
3874
3860
  };
3875
- console.log("版本管理参数:", request);
3861
+ enableLog && console.log("版本管理参数:", request);
3876
3862
  const strategies = this.getStrategies(target, propertyKey);
3877
- const methodCache = this.getCacheConfig(target, propertyKey) || void 0;
3878
- if (methodCache == void 0) {
3879
- const cached = await this.applyCache(request, cacheManage);
3880
- if (cached && cached.error === null) {
3881
- let cacheResponse = {
3882
- data: cached.data,
3883
- status: 304,
3884
- headers: {
3885
- hitCache: true
3886
- },
3887
- statusText: "get response data from cache",
3888
- config: { headers: new AxiosHeaders() }
3889
- };
3890
- const responseStrategies = strategies.filter(
3891
- (strategy) => strategy.applyResponse
3892
- );
3893
- const strategyResponse = await this.applyStrategies(
3894
- cacheResponse,
3895
- responseStrategies,
3896
- "response"
3897
- );
3898
- return strategyResponse;
3899
- }
3900
- }
3901
3863
  const params = this.buildRequestArgs(target, propertyKey, args);
3902
3864
  request = { ...request, ...params };
3903
- console.log("构建请求参数:", request);
3865
+ enableLog && console.log("构建请求参数:", request);
3904
3866
  const requestStrategies = strategies.filter(
3905
3867
  (strategy) => strategy.applyRequest
3906
3868
  );
@@ -3909,10 +3871,24 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3909
3871
  requestStrategies,
3910
3872
  "request"
3911
3873
  );
3874
+ const hitSource = this.getHitSource(target, propertyKey);
3875
+ enableLog && console.log("hitSource:", hitSource);
3876
+ if (typeof hitSource == "string") {
3877
+ this.setHitSource(request, hitSource);
3878
+ }
3879
+ if (hitSource !== null) {
3880
+ const cachedResponse = await this.getCache(request, strategies);
3881
+ if (cachedResponse) {
3882
+ enableLog && console.warn("数据从缓存获取");
3883
+ return this.handleResponse(cachedResponse, true);
3884
+ }
3885
+ }
3912
3886
  try {
3913
- console.log("send request:", request);
3887
+ enableLog && console.log("send request:", request);
3914
3888
  const response = await this.axiosInstance(request);
3915
- return this.handleResponse(response);
3889
+ hitSource !== null && this.setCache(request, response);
3890
+ this.expireCache(propertyKey);
3891
+ return this.handleResponse(response, false);
3916
3892
  } catch (error) {
3917
3893
  return this.handleError(error);
3918
3894
  }
@@ -3923,7 +3899,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3923
3899
  buildRequestArgs(target, propertyKey, args) {
3924
3900
  const requestArgs = { params: {}, data: {} };
3925
3901
  const paramConfigs = Reflect.getMetadata(REQUEST_ARGS_KEY, target, propertyKey) || [];
3926
- console.log("请求参数:", paramConfigs);
3927
3902
  paramConfigs.forEach(({ index, type, key }) => {
3928
3903
  const value = args[index];
3929
3904
  if (type === "params" && !key && typeof value === "object") {
@@ -3943,14 +3918,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3943
3918
  }
3944
3919
  getStrategies(target, propertyKey) {
3945
3920
  const serverStrategies = Reflect.getMetadata(STRATEGY_KEY, this.constructor) || [];
3946
- console.log("serverStrategies:", serverStrategies);
3947
3921
  const classStrategies = Reflect.getMetadata(STRATEGY_KEY, target.constructor) || [];
3948
- console.log("classStrategies:", classStrategies);
3949
3922
  const methodStrategies = Reflect.getMetadata(
3950
3923
  `${STRATEGY_KEY.toString()}_${propertyKey}`,
3951
3924
  target
3952
3925
  ) || [];
3953
- console.log("methodStrategies:", methodStrategies);
3954
3926
  const allStrategies = [
3955
3927
  ...this.strategies,
3956
3928
  ...serverStrategies,
@@ -3971,7 +3943,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3971
3943
  VERSIONING_KEY,
3972
3944
  this.constructor
3973
3945
  );
3974
- console.log("版本管理器:", versioning);
3975
3946
  if (!versioning) return request;
3976
3947
  const version = Reflect.getMetadata(VERSION_KEY, target, propertyKey);
3977
3948
  const currentVersion = version || this.version || versioning.defaultVersion;
@@ -3982,24 +3953,95 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3982
3953
  const versionUrl = url ? `${url}/${request.url}` : request.url;
3983
3954
  return { ...request, url: versionUrl, headers, params };
3984
3955
  }
3985
- async applyCache(request, options) {
3956
+ async getCache(request, strategies) {
3957
+ var _a;
3958
+ if (!this.cacheStorage) return void 0;
3959
+ const cacheKey = apiKey(request);
3960
+ const cached = await ((_a = this.cacheStorage) == null ? void 0 : _a.get(cacheKey));
3961
+ if (cached && cached.error === null) {
3962
+ let cacheResponse = {
3963
+ data: cached.data,
3964
+ status: 304,
3965
+ headers: {},
3966
+ statusText: "get response data from cache",
3967
+ config: { headers: new AxiosHeaders() }
3968
+ };
3969
+ const responseStrategies = strategies.filter(
3970
+ (strategy) => strategy.applyResponse
3971
+ );
3972
+ const strategyResponse = await this.applyStrategies(
3973
+ cacheResponse,
3974
+ responseStrategies,
3975
+ "response"
3976
+ );
3977
+ return strategyResponse;
3978
+ }
3979
+ }
3980
+ initCacheManage(options) {
3981
+ if (!this.cacheStorage && options !== void 0) {
3982
+ this.cacheStorage = createCache(options.type, options.ttl || 300);
3983
+ }
3984
+ }
3985
+ getHitSource(target, propertyKey) {
3986
+ const methodHitSource = Reflect.getMetadata(
3987
+ `${CACHE_OPTIONS_KEY.toString()}_${propertyKey}`,
3988
+ target
3989
+ );
3990
+ if (methodHitSource !== void 0) return methodHitSource;
3991
+ const apiHitSource = Reflect.getMetadata(
3992
+ CACHE_OPTIONS_KEY,
3993
+ target.constructor
3994
+ );
3995
+ return apiHitSource;
3996
+ }
3997
+ setHitSource(request, hitSource) {
3998
+ const cacheKeys = this.sourceMap.get(hitSource);
3999
+ const currentCacheKey = apiKey(request);
4000
+ if (cacheKeys) {
4001
+ cacheKeys.push(currentCacheKey);
4002
+ this.sourceMap.set(hitSource, cacheKeys);
4003
+ } else {
4004
+ this.sourceMap.set(hitSource, [currentCacheKey]);
4005
+ }
4006
+ }
4007
+ async setCache(request, response) {
3986
4008
  var _a;
3987
4009
  const cacheKey = apiKey(request);
3988
- if (this.cacheStorage) {
3989
- return await ((_a = this.cacheStorage) == null ? void 0 : _a.get(cacheKey));
4010
+ await ((_a = this.cacheStorage) == null ? void 0 : _a.set(cacheKey, response.data));
4011
+ }
4012
+ async expireCache(hitSource) {
4013
+ const keys = this.sourceMap.get(hitSource);
4014
+ if (keys) {
4015
+ Promise.all(
4016
+ keys.map(async (key) => {
4017
+ var _a;
4018
+ await ((_a = this.cacheStorage) == null ? void 0 : _a.delete(key));
4019
+ })
4020
+ );
3990
4021
  }
3991
- return void 0;
3992
4022
  }
3993
- getCacheConfig(target, propertyKey) {
3994
- return Reflect.getMetadata(`${CACHE_KEY.toString()}_${propertyKey}`, target) || // 方法级
3995
- Reflect.getMetadata(CACHE_KEY, target.constructor);
4023
+ getServerConfig() {
4024
+ return Reflect.getMetadata(
4025
+ SERVER_CONFIG_KEY,
4026
+ this.constructor
4027
+ );
4028
+ }
4029
+ getApiConfig(constructor) {
4030
+ return Reflect.getMetadata(API_CONFIG_KEY, constructor);
4031
+ }
4032
+ initAxios(config) {
4033
+ if (!this.axiosInstance) {
4034
+ this.axiosInstance = axios.create({
4035
+ baseURL: config.baseURL,
4036
+ timeout: config.timeout
4037
+ });
4038
+ }
3996
4039
  }
3997
- handleResponse(response) {
3998
- console.log("Response:", response);
4040
+ handleResponse(response, hitCache) {
3999
4041
  return {
4000
4042
  data: response.data,
4001
4043
  error: null,
4002
- hitCache: false
4044
+ hitCache
4003
4045
  };
4004
4046
  }
4005
4047
  handleError(error) {
@@ -4009,31 +4051,23 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4009
4051
  };
4010
4052
  }
4011
4053
  }
4012
- exports2.API_CONFIG_KEY = API_CONFIG_KEY;
4013
4054
  exports2.Api = Api;
4014
- exports2.CACHE_KEY = CACHE_KEY;
4015
4055
  exports2.Cache = Cache;
4016
4056
  exports2.CacheType = CacheType;
4017
4057
  exports2.Data = Data;
4018
4058
  exports2.Delete = Delete;
4019
4059
  exports2.Get = Get;
4020
4060
  exports2.Head = Head;
4021
- exports2.METHOD_KEY = METHOD_KEY;
4022
4061
  exports2.Options = Options;
4023
4062
  exports2.Params = Params;
4024
4063
  exports2.Patch = Patch;
4025
4064
  exports2.Post = Post;
4026
4065
  exports2.Put = Put;
4027
- exports2.REQUEST_ARGS_KEY = REQUEST_ARGS_KEY;
4028
4066
  exports2.RequestMethod = RequestMethod;
4029
- exports2.SERVER_CONFIG_KEY = SERVER_CONFIG_KEY;
4030
- exports2.STRATEGY_KEY = STRATEGY_KEY;
4031
4067
  exports2.Server = Server;
4032
4068
  exports2.Snail = Snail;
4033
4069
  exports2.Strategy = Strategy;
4034
4070
  exports2.UseStrategy = UseStrategy;
4035
- exports2.VERSIONING_KEY = VERSIONING_KEY;
4036
- exports2.VERSION_KEY = VERSION_KEY;
4037
4071
  exports2.Version = Version;
4038
4072
  exports2.Versioning = Versioning;
4039
4073
  exports2.VersioningType = VersioningType;
@@ -1,8 +1,6 @@
1
1
  import { CacheManagementOption } from "./cache.management.option";
2
- import { VersioningOption } from "./versioning.option";
3
2
  export interface SnailOption {
4
3
  baseURL?: string;
5
- Versioning?: VersioningOption;
6
4
  CacheManage?: CacheManagementOption;
7
5
  enableLog?: boolean;
8
6
  timeout?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snail-js/api",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Http Request with Decorators Api, build on axios",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",