@snail-js/api 0.1.2 → 0.1.4

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/snail-api.js CHANGED
@@ -3682,6 +3682,13 @@ var CacheType = /* @__PURE__ */ ((CacheType2) => {
3682
3682
  })(CacheType || {});
3683
3683
  class Strategy {
3684
3684
  }
3685
+ class RegisterSseEvent {
3686
+ constructor() {
3687
+ __publicField(this, "eventName");
3688
+ __publicField(this, "emit");
3689
+ __publicField(this, "options");
3690
+ }
3691
+ }
3685
3692
  function createCache(type, ttl) {
3686
3693
  if (type === CacheType.Memory) {
3687
3694
  return new MemoryCache(ttl);
@@ -3741,8 +3748,8 @@ function applyVersioning(version, versioning) {
3741
3748
  versioning
3742
3749
  );
3743
3750
  }
3744
- const METHOD_KEY = "SNAIL_METHOD_KEY";
3745
- const API_CONFIG_KEY = "SNAIL_API_CONFIG_KEY";
3751
+ const METHOD_KEY = Symbol("SNAIL_METHOD_KEY");
3752
+ const API_CONFIG_KEY = Symbol("SNAIL_API_CONFIG_KEY");
3746
3753
  const Api = (url = "", config) => {
3747
3754
  return (target) => {
3748
3755
  Reflect.defineMetadata(API_CONFIG_KEY, { url, ...config }, target);
@@ -3766,7 +3773,7 @@ const Delete = createMethodDecorator(RequestMethod.DELETE);
3766
3773
  const Patch = createMethodDecorator(RequestMethod.PATCH);
3767
3774
  const Options = createMethodDecorator(RequestMethod.OPTIONS);
3768
3775
  const Head = createMethodDecorator(RequestMethod.HEAD);
3769
- const SERVER_CONFIG_KEY = "SANIL_SERVER_CONFIG_KEY";
3776
+ const SERVER_CONFIG_KEY = Symbol("SANIL_SERVER_CONFIG_KEY");
3770
3777
  const Server = (config) => {
3771
3778
  return (target) => {
3772
3779
  Reflect.defineMetadata(SERVER_CONFIG_KEY, config, target);
@@ -3781,7 +3788,7 @@ const UseStrategy = (...strategies) => {
3781
3788
  };
3782
3789
  const REQUEST_ARGS_KEY = Symbol("SNAIL_REQUEST_ARGS_KEY");
3783
3790
  const Params = (key) => createArgsDecorator("params", key);
3784
- const Data = () => createArgsDecorator("data");
3791
+ const Data = (key) => createArgsDecorator("data", key);
3785
3792
  const createArgsDecorator = (type, key) => {
3786
3793
  return (target, propertyKey, parameterIndex) => {
3787
3794
  const args = Reflect.getMetadata(REQUEST_ARGS_KEY, target, propertyKey) || [];
@@ -3801,11 +3808,50 @@ const Version = (version) => {
3801
3808
  Reflect.defineMetadata(VERSION_KEY, version, target, propertyKey);
3802
3809
  };
3803
3810
  };
3804
- const CACHE_KEY = "SNALI_CACHE_KEY";
3805
- const Cache = (options) => {
3811
+ const CACHE_OPTIONS_KEY = Symbol("SNALI_CACHE_OPTIONS_KEY");
3812
+ const Cache = (hitSource) => {
3813
+ return (target, propertyKey) => {
3814
+ const key = propertyKey ? `${CACHE_OPTIONS_KEY.toString()}_${propertyKey}` : CACHE_OPTIONS_KEY;
3815
+ Reflect.defineMetadata(key, hitSource, target);
3816
+ };
3817
+ };
3818
+ const UPLOAD_PROGRESS_KEY = Symbol("SNAIL_UPLOAD_PROGRESS_KEY");
3819
+ const EVENT_SOURCE_OPTION_KEY = Symbol("SNAIL_EVENT_SOURCE_OPTION_KEY");
3820
+ const Sse = (path, options) => {
3806
3821
  return (target, propertyKey) => {
3807
- const key = propertyKey ? `${CACHE_KEY}_${propertyKey}` : CACHE_KEY;
3808
- Reflect.defineMetadata(key, options, target);
3822
+ Reflect.defineMetadata(
3823
+ EVENT_SOURCE_OPTION_KEY,
3824
+ {
3825
+ path,
3826
+ withCredentials: options == null ? void 0 : options.withCredentials
3827
+ },
3828
+ target,
3829
+ propertyKey
3830
+ );
3831
+ };
3832
+ };
3833
+ const EVENT_SOURCE_EVENTS_KEY = Symbol("EVENT_SOURCE_EVENTS_KEY");
3834
+ const SseEvent = (eventName, options) => {
3835
+ return (target, propertyKey) => {
3836
+ const events = Reflect.getMetadata(EVENT_SOURCE_EVENTS_KEY, target) || [];
3837
+ events.push({
3838
+ eventName: eventName ? eventName : "message",
3839
+ emit: target[propertyKey],
3840
+ options
3841
+ });
3842
+ Reflect.defineMetadata(EVENT_SOURCE_EVENTS_KEY, events, target);
3843
+ };
3844
+ };
3845
+ const EVENT_SOURCE_OPEN_KEY = Symbol("EVENT_SOURCE_OPEN_KEY");
3846
+ const OnSseOpen = () => {
3847
+ return (target, propertyKey) => {
3848
+ Reflect.defineMetadata(EVENT_SOURCE_OPEN_KEY, target[propertyKey], target);
3849
+ };
3850
+ };
3851
+ const EVENT_SOURCE_ERROR_KEY = Symbol("EVENT_SOURCE_ERROR_KEY");
3852
+ const OnSseError = () => {
3853
+ return (target, propertyKey) => {
3854
+ Reflect.defineMetadata(EVENT_SOURCE_ERROR_KEY, target[propertyKey], target);
3809
3855
  };
3810
3856
  };
3811
3857
  class Snail {
@@ -3815,39 +3861,26 @@ class Snail {
3815
3861
  __publicField(this, "strategies", []);
3816
3862
  __publicField(this, "cacheStorage");
3817
3863
  __publicField(this, "version");
3864
+ __publicField(this, "sourceMap", /* @__PURE__ */ new Map());
3865
+ __publicField(this, "eventSource");
3818
3866
  }
3819
3867
  registerStrategy(strategy) {
3820
3868
  this.strategies.push(strategy);
3821
3869
  }
3822
3870
  createApi(constructor) {
3823
3871
  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);
3872
+ const serverConfig = this.getServerConfig();
3873
+ const { baseURL, timeout, CacheManage, enableLog } = serverConfig;
3874
+ enableLog && console.log("serverConfig:", serverConfig);
3875
+ this.initAxios({ baseURL, timeout });
3876
+ enableLog && console.log("CacheManage:", CacheManage);
3877
+ this.initCacheManage(CacheManage);
3878
+ const apiConfig = this.getApiConfig(constructor);
3879
+ enableLog && console.log("ApiConfig:", apiConfig);
3847
3880
  this.version = apiConfig.version;
3848
3881
  return new Proxy(instance, {
3849
3882
  get: (target, propertyKey) => {
3850
- console.log("proxy:", target, "|", propertyKey);
3883
+ enableLog && console.log("proxy:", target, "|", propertyKey);
3851
3884
  if (typeof propertyKey !== "string") return;
3852
3885
  const methodConfig = Reflect.getMetadata(
3853
3886
  METHOD_KEY,
@@ -3857,7 +3890,7 @@ class Snail {
3857
3890
  if (!methodConfig) return target[propertyKey];
3858
3891
  return async (...args) => {
3859
3892
  const url = methodConfig.path == "" ? apiConfig.url : apiConfig.url + `/${methodConfig.path}`;
3860
- console.log("url:", url);
3893
+ enableLog && console.log("url:", url);
3861
3894
  let request = {
3862
3895
  // baseURL: serverConfig.baseURL,
3863
3896
  url,
@@ -3868,35 +3901,11 @@ class Snail {
3868
3901
  ...request,
3869
3902
  ...this.applyVersion(request, target, propertyKey)
3870
3903
  };
3871
- console.log("版本管理参数:", request);
3904
+ enableLog && console.log("版本管理参数:", request);
3872
3905
  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
3906
  const params = this.buildRequestArgs(target, propertyKey, args);
3898
3907
  request = { ...request, ...params };
3899
- console.log("构建请求参数:", request);
3908
+ enableLog && console.log("构建请求参数:", request);
3900
3909
  const requestStrategies = strategies.filter(
3901
3910
  (strategy) => strategy.applyRequest
3902
3911
  );
@@ -3905,10 +3914,32 @@ class Snail {
3905
3914
  requestStrategies,
3906
3915
  "request"
3907
3916
  );
3917
+ const hitSource = this.getHitSource(target, propertyKey);
3918
+ enableLog && console.log("hitSource:", hitSource);
3919
+ if (typeof hitSource == "string") {
3920
+ this.setHitSource(request, hitSource);
3921
+ }
3922
+ if (hitSource !== null) {
3923
+ const cachedResponse = await this.getCache(request, strategies);
3924
+ if (cachedResponse) {
3925
+ enableLog && console.warn("数据从缓存获取");
3926
+ return this.handleResponse(cachedResponse, true);
3927
+ }
3928
+ }
3929
+ const onUploadProgress = Reflect.getMetadata(
3930
+ UPLOAD_PROGRESS_KEY,
3931
+ target,
3932
+ propertyKey
3933
+ );
3908
3934
  try {
3909
- console.log("send request:", request);
3910
- const response = await this.axiosInstance(request);
3911
- return this.handleResponse(response);
3935
+ enableLog && console.log("send request:", request);
3936
+ const response = await this.axiosInstance({
3937
+ ...request,
3938
+ onUploadProgress
3939
+ });
3940
+ hitSource !== null && this.setCache(request, response);
3941
+ this.expireCache(propertyKey);
3942
+ return this.handleResponse(response, false);
3912
3943
  } catch (error) {
3913
3944
  return this.handleError(error);
3914
3945
  }
@@ -3919,7 +3950,6 @@ class Snail {
3919
3950
  buildRequestArgs(target, propertyKey, args) {
3920
3951
  const requestArgs = { params: {}, data: {} };
3921
3952
  const paramConfigs = Reflect.getMetadata(REQUEST_ARGS_KEY, target, propertyKey) || [];
3922
- console.log("请求参数:", paramConfigs);
3923
3953
  paramConfigs.forEach(({ index, type, key }) => {
3924
3954
  const value = args[index];
3925
3955
  if (type === "params" && !key && typeof value === "object") {
@@ -3939,14 +3969,11 @@ class Snail {
3939
3969
  }
3940
3970
  getStrategies(target, propertyKey) {
3941
3971
  const serverStrategies = Reflect.getMetadata(STRATEGY_KEY, this.constructor) || [];
3942
- console.log("serverStrategies:", serverStrategies);
3943
3972
  const classStrategies = Reflect.getMetadata(STRATEGY_KEY, target.constructor) || [];
3944
- console.log("classStrategies:", classStrategies);
3945
3973
  const methodStrategies = Reflect.getMetadata(
3946
3974
  `${STRATEGY_KEY.toString()}_${propertyKey}`,
3947
3975
  target
3948
3976
  ) || [];
3949
- console.log("methodStrategies:", methodStrategies);
3950
3977
  const allStrategies = [
3951
3978
  ...this.strategies,
3952
3979
  ...serverStrategies,
@@ -3967,7 +3994,6 @@ class Snail {
3967
3994
  VERSIONING_KEY,
3968
3995
  this.constructor
3969
3996
  );
3970
- console.log("版本管理器:", versioning);
3971
3997
  if (!versioning) return request;
3972
3998
  const version = Reflect.getMetadata(VERSION_KEY, target, propertyKey);
3973
3999
  const currentVersion = version || this.version || versioning.defaultVersion;
@@ -3978,24 +4004,104 @@ class Snail {
3978
4004
  const versionUrl = url ? `${url}/${request.url}` : request.url;
3979
4005
  return { ...request, url: versionUrl, headers, params };
3980
4006
  }
3981
- async applyCache(request, options) {
4007
+ async getCache(request, strategies) {
3982
4008
  var _a;
4009
+ if (!this.cacheStorage) return void 0;
3983
4010
  const cacheKey = apiKey(request);
3984
- if (this.cacheStorage) {
3985
- return await ((_a = this.cacheStorage) == null ? void 0 : _a.get(cacheKey));
4011
+ const cached = await ((_a = this.cacheStorage) == null ? void 0 : _a.get(cacheKey));
4012
+ if (cached && cached.error === null) {
4013
+ let cacheResponse = {
4014
+ data: cached.data,
4015
+ status: 304,
4016
+ headers: {},
4017
+ statusText: "get response data from cache",
4018
+ config: { headers: new AxiosHeaders2() }
4019
+ };
4020
+ const responseStrategies = strategies.filter(
4021
+ (strategy) => strategy.applyResponse
4022
+ );
4023
+ const strategyResponse = await this.applyStrategies(
4024
+ cacheResponse,
4025
+ responseStrategies,
4026
+ "response"
4027
+ );
4028
+ return strategyResponse;
3986
4029
  }
3987
- return void 0;
3988
4030
  }
3989
- getCacheConfig(target, propertyKey) {
3990
- return Reflect.getMetadata(`${CACHE_KEY.toString()}_${propertyKey}`, target) || // 方法级
3991
- Reflect.getMetadata(CACHE_KEY, target.constructor);
4031
+ initCacheManage(options) {
4032
+ if (!this.cacheStorage && options !== void 0) {
4033
+ this.cacheStorage = createCache(options.type, options.ttl || 300);
4034
+ }
3992
4035
  }
3993
- handleResponse(response) {
3994
- console.log("Response:", response);
4036
+ getHitSource(target, propertyKey) {
4037
+ const methodHitSource = Reflect.getMetadata(
4038
+ `${CACHE_OPTIONS_KEY.toString()}_${propertyKey}`,
4039
+ target
4040
+ );
4041
+ if (methodHitSource !== void 0) return methodHitSource;
4042
+ const apiHitSource = Reflect.getMetadata(
4043
+ CACHE_OPTIONS_KEY,
4044
+ target.constructor
4045
+ );
4046
+ return apiHitSource;
4047
+ }
4048
+ setHitSource(request, hitSource) {
4049
+ const cacheKeys = this.sourceMap.get(hitSource);
4050
+ const currentCacheKey = apiKey(request);
4051
+ if (cacheKeys) {
4052
+ cacheKeys.push(currentCacheKey);
4053
+ this.sourceMap.set(hitSource, cacheKeys);
4054
+ } else {
4055
+ this.sourceMap.set(hitSource, [currentCacheKey]);
4056
+ }
4057
+ }
4058
+ async setCache(request, response) {
4059
+ var _a;
4060
+ const cacheKey = apiKey(request);
4061
+ await ((_a = this.cacheStorage) == null ? void 0 : _a.set(cacheKey, response.data));
4062
+ }
4063
+ async expireCache(hitSource) {
4064
+ const keys = this.sourceMap.get(hitSource);
4065
+ if (keys) {
4066
+ Promise.all(
4067
+ keys.map(async (key) => {
4068
+ var _a;
4069
+ await ((_a = this.cacheStorage) == null ? void 0 : _a.delete(key));
4070
+ })
4071
+ );
4072
+ }
4073
+ }
4074
+ getServerConfig() {
4075
+ return Reflect.getMetadata(
4076
+ SERVER_CONFIG_KEY,
4077
+ this.constructor
4078
+ );
4079
+ }
4080
+ getApiConfig(constructor) {
4081
+ return Reflect.getMetadata(API_CONFIG_KEY, constructor);
4082
+ }
4083
+ initAxios(config) {
4084
+ if (!this.axiosInstance) {
4085
+ this.axiosInstance = axios.create({
4086
+ baseURL: config.baseURL,
4087
+ timeout: config.timeout
4088
+ });
4089
+ }
4090
+ }
4091
+ generateSseUrl(baseURL, url) {
4092
+ if (!baseURL && !url) {
4093
+ return "/";
4094
+ }
4095
+ if (!baseURL && url) {
4096
+ return `/${url}`;
4097
+ }
4098
+ return `${baseURL}/${url}`;
4099
+ }
4100
+ handleResponse(response, hitCache) {
3995
4101
  return {
3996
4102
  data: response.data,
3997
4103
  error: null,
3998
- hitCache: false
4104
+ hitCache
3999
4105
  };
4000
4106
  }
4001
4107
  handleError(error) {
@@ -4004,33 +4110,99 @@ class Snail {
4004
4110
  error
4005
4111
  };
4006
4112
  }
4113
+ createSse(constructor) {
4114
+ const instance = new constructor();
4115
+ const serverConfig = this.getServerConfig();
4116
+ const { baseURL, enableLog } = serverConfig;
4117
+ const apiConfig = this.getApiConfig(constructor);
4118
+ enableLog && console.log("ApiConfig:", apiConfig);
4119
+ this.version = apiConfig.version;
4120
+ return new Proxy(instance, {
4121
+ get: (target, propertyKey) => {
4122
+ enableLog && console.log("proxy:", target, "|", propertyKey);
4123
+ if (typeof propertyKey !== "string") return;
4124
+ const sseOption = Reflect.getMetadata(
4125
+ EVENT_SOURCE_OPTION_KEY,
4126
+ target,
4127
+ propertyKey
4128
+ );
4129
+ if (sseOption) {
4130
+ const url = sseOption.path == "" ? apiConfig.url : apiConfig.url + `/${sseOption.path}`;
4131
+ const { url: versionUrl } = this.applyVersion(
4132
+ { url },
4133
+ target,
4134
+ propertyKey
4135
+ );
4136
+ const sseUrl = this.generateSseUrl(baseURL, versionUrl || url);
4137
+ enableLog && console.log("sse-url:", sseUrl);
4138
+ const { eventSource, close } = this.initSse(sseUrl, sseOption);
4139
+ this.eventSource = eventSource;
4140
+ this.setSse(target);
4141
+ this.registerSseEvent(target);
4142
+ return () => {
4143
+ return { eventSource, close };
4144
+ };
4145
+ }
4146
+ }
4147
+ });
4148
+ }
4149
+ initSse(url, options) {
4150
+ const eventSource = new EventSource(url, {
4151
+ withCredentials: options.withCredentials ? options.withCredentials : false
4152
+ });
4153
+ console.log("EventSource:", eventSource);
4154
+ return {
4155
+ eventSource,
4156
+ close: eventSource.close
4157
+ };
4158
+ }
4159
+ setSse(target) {
4160
+ const onOpenFunc = Reflect.getMetadata(EVENT_SOURCE_OPEN_KEY, target);
4161
+ console.log("sse-proxy[open]:", onOpenFunc);
4162
+ if (typeof onOpenFunc == "function") {
4163
+ this.eventSource && (this.eventSource.onopen = onOpenFunc);
4164
+ }
4165
+ const onErrorFunc = Reflect.getMetadata(EVENT_SOURCE_ERROR_KEY, target);
4166
+ console.log("sse-proxy[error]:", onErrorFunc);
4167
+ if (typeof onErrorFunc == "function") {
4168
+ this.eventSource && (this.eventSource.onerror = onErrorFunc);
4169
+ }
4170
+ }
4171
+ registerSseEvent(target) {
4172
+ const eventSource = this.eventSource;
4173
+ if (!eventSource) return;
4174
+ const events = Reflect.getMetadata(
4175
+ EVENT_SOURCE_EVENTS_KEY,
4176
+ target
4177
+ );
4178
+ events.map((event) => {
4179
+ eventSource.addEventListener(event.eventName, event.emit, event.options);
4180
+ });
4181
+ }
4007
4182
  }
4008
4183
  export {
4009
- API_CONFIG_KEY,
4010
4184
  Api,
4011
- CACHE_KEY,
4012
4185
  Cache,
4013
4186
  CacheType,
4014
4187
  Data,
4015
4188
  Delete,
4016
4189
  Get,
4017
4190
  Head,
4018
- METHOD_KEY,
4191
+ OnSseError,
4192
+ OnSseOpen,
4019
4193
  Options,
4020
4194
  Params,
4021
4195
  Patch,
4022
4196
  Post,
4023
4197
  Put,
4024
- REQUEST_ARGS_KEY,
4198
+ RegisterSseEvent,
4025
4199
  RequestMethod,
4026
- SERVER_CONFIG_KEY,
4027
- STRATEGY_KEY,
4028
4200
  Server,
4029
4201
  Snail,
4202
+ Sse,
4203
+ SseEvent,
4030
4204
  Strategy,
4031
4205
  UseStrategy,
4032
- VERSIONING_KEY,
4033
- VERSION_KEY,
4034
4206
  Version,
4035
4207
  Versioning,
4036
4208
  VersioningType,