@dooboostore/simple-boot-http-server 1.0.27 → 1.0.28

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.
Files changed (49) hide show
  1. package/README.md +44 -9
  2. package/dist/cjs/SimpleBootHttpServer.js +15 -2
  3. package/dist/cjs/SimpleBootHttpServer.js.map +2 -2
  4. package/dist/cjs/decorators/MethodMapping.js.map +2 -2
  5. package/dist/cjs/models/RequestResponse.js +52 -0
  6. package/dist/cjs/models/RequestResponse.js.map +3 -3
  7. package/dist/cjs/proxy/RequestResponseInjectProxy.js +35 -0
  8. package/dist/cjs/proxy/RequestResponseInjectProxy.js.map +7 -0
  9. package/dist/cjs/proxy/SymbolIntentApiServiceProxy.js +1 -1
  10. package/dist/cjs/proxy/SymbolIntentApiServiceProxy.js.map +2 -2
  11. package/dist/cjs/proxy/index.js +3 -1
  12. package/dist/cjs/proxy/index.js.map +2 -2
  13. package/dist/cjs/resolvers/Resolver.js.map +1 -1
  14. package/dist/esm/SimpleBootHttpServer.js +16 -3
  15. package/dist/esm/SimpleBootHttpServer.js.map +2 -2
  16. package/dist/esm/decorators/MethodMapping.js.map +2 -2
  17. package/dist/esm/models/RequestResponse.js +52 -0
  18. package/dist/esm/models/RequestResponse.js.map +2 -2
  19. package/dist/esm/proxy/RequestResponseInjectProxy.js +12 -0
  20. package/dist/esm/proxy/RequestResponseInjectProxy.js.map +7 -0
  21. package/dist/esm/proxy/SymbolIntentApiServiceProxy.js +1 -1
  22. package/dist/esm/proxy/SymbolIntentApiServiceProxy.js.map +2 -2
  23. package/dist/esm/proxy/index.js +1 -0
  24. package/dist/esm/proxy/index.js.map +2 -2
  25. package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js +295 -252
  26. package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js.map +4 -4
  27. package/dist/types/SimpleBootHttpServer.d.ts.map +1 -1
  28. package/dist/types/decorators/MethodMapping.d.ts +13 -16
  29. package/dist/types/decorators/MethodMapping.d.ts.map +1 -1
  30. package/dist/types/models/RequestResponse.d.ts +9 -0
  31. package/dist/types/models/RequestResponse.d.ts.map +1 -1
  32. package/dist/types/proxy/RequestResponseInjectProxy.d.ts +22 -0
  33. package/dist/types/proxy/RequestResponseInjectProxy.d.ts.map +1 -0
  34. package/dist/types/proxy/index.d.ts +1 -0
  35. package/dist/types/proxy/index.d.ts.map +1 -1
  36. package/dist/types/resolvers/Resolver.d.ts +2 -1
  37. package/dist/types/resolvers/Resolver.d.ts.map +1 -1
  38. package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js +295 -252
  39. package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js.map +4 -4
  40. package/dist/umd-bundle/websocket-client.umd.js +106 -140
  41. package/dist/umd-bundle/websocket-client.umd.js.map +2 -2
  42. package/package.json +7 -7
  43. package/src/SimpleBootHttpServer.ts +19 -3
  44. package/src/decorators/MethodMapping.ts +151 -159
  45. package/src/models/RequestResponse.ts +50 -0
  46. package/src/proxy/RequestResponseInjectProxy.ts +30 -0
  47. package/src/proxy/SymbolIntentApiServiceProxy.ts +1 -1
  48. package/src/proxy/index.ts +1 -0
  49. package/src/resolvers/Resolver.ts +2 -1
@@ -14158,6 +14158,7 @@ var dooboostoreSimpleBootHttpServer = (() => {
14158
14158
  getUrlMapping: () => getUrlMapping,
14159
14159
  getUrlMappings: () => getUrlMappings,
14160
14160
  headMethod: () => headMethod,
14161
+ injectRequestResponse: () => injectRequestResponse,
14161
14162
  isDataDist: () => isDataDist,
14162
14163
  isPathDist: () => isPathDist,
14163
14164
  makeIntentHeaderBySymbolFor: () => makeIntentHeaderBySymbolFor,
@@ -14458,6 +14459,12 @@ var dooboostoreSimpleBootHttpServer = (() => {
14458
14459
  return false;
14459
14460
  }
14460
14461
  };
14462
+ ValidUtils22.isGenerator = (value) => {
14463
+ return value !== null && typeof value === "object" && typeof value.next === "function" && typeof value[Symbol.iterator] === "function";
14464
+ };
14465
+ ValidUtils22.isAsyncGenerator = (value) => {
14466
+ return value !== null && typeof value === "object" && typeof value.next === "function" && typeof value[Symbol.asyncIterator] === "function";
14467
+ };
14461
14468
  ValidUtils22.isFrozen = (obj) => {
14462
14469
  return Object.isFrozen(obj);
14463
14470
  };
@@ -18902,87 +18909,64 @@ var dooboostoreSimpleBootHttpServer = (() => {
18902
18909
  // ../core/dist/esm/promise/AbortablePromise.js
18903
18910
  var AbortablePromise = class _AbortablePromise {
18904
18911
  constructor(executor, signal) {
18905
- this.steps = [];
18906
- this.initialExecutor = executor;
18907
18912
  this.signal = signal;
18913
+ if (typeof executor !== "function") {
18914
+ this.source = Promise.resolve(executor);
18915
+ } else if (signal?.aborted) {
18916
+ this.source = Promise.reject(signal.reason);
18917
+ } else {
18918
+ this.source = Promise.resolve().then(executor);
18919
+ }
18920
+ }
18921
+ /**
18922
+ * source 를 abort 와 경쟁시킨 promise. 실제로 소비될 때(then/toPromise) 한 번만 만든다 —
18923
+ * await 는 then() 이 돌려준 새 인스턴스를 버리므로, 미리 만들면 아무도 안 받는 reject 가 unhandled 로 남는다.
18924
+ */
18925
+ get promise() {
18926
+ if (this.guarded) return this.guarded;
18927
+ const signal = this.signal;
18928
+ if (!signal) return this.guarded = this.source;
18929
+ if (signal.aborted) {
18930
+ this.source.catch(() => {
18931
+ });
18932
+ return this.guarded = Promise.reject(signal.reason);
18933
+ }
18934
+ return this.guarded = new Promise((resolve2, reject) => {
18935
+ const cleanup = () => signal.removeEventListener("abort", onAbort);
18936
+ const onAbort = () => reject(signal.reason);
18937
+ signal.addEventListener("abort", onAbort, { once: true });
18938
+ this.source.then(
18939
+ (value) => {
18940
+ cleanup();
18941
+ resolve2(value);
18942
+ },
18943
+ (reason) => {
18944
+ cleanup();
18945
+ reject(reason);
18946
+ }
18947
+ );
18948
+ });
18908
18949
  }
18909
18950
  then(onfulfilled, onrejected) {
18910
- const newPromise = new _AbortablePromise(
18911
- this.initialExecutor,
18912
- this.signal
18951
+ const signal = this.signal;
18952
+ const next = this.promise.then(
18953
+ onfulfilled ? (value) => {
18954
+ if (signal?.aborted) throw signal.reason;
18955
+ return onfulfilled(value);
18956
+ } : void 0,
18957
+ onrejected
18913
18958
  );
18914
- newPromise.steps = [...this.steps];
18915
- if (onfulfilled) {
18916
- newPromise.steps.push(onfulfilled);
18917
- }
18918
- if (onrejected) {
18919
- newPromise.errorHandler = onrejected;
18920
- } else if (this.errorHandler) {
18921
- newPromise.errorHandler = this.errorHandler;
18922
- }
18923
- return newPromise;
18959
+ return new _AbortablePromise(next, signal);
18924
18960
  }
18925
18961
  catch(onrejected) {
18926
18962
  return this.then(void 0, onrejected);
18927
18963
  }
18928
18964
  finally(onfinally) {
18929
- return this.then(
18930
- (value) => {
18931
- onfinally?.();
18932
- return value;
18933
- },
18934
- (reason) => {
18935
- onfinally?.();
18936
- throw reason;
18937
- }
18938
- );
18965
+ return new _AbortablePromise(this.promise.finally(onfinally), this.signal);
18939
18966
  }
18940
- async execute() {
18941
- try {
18942
- if (this.signal?.aborted) {
18943
- throw new Error(this.signal.reason || "Aborted");
18944
- }
18945
- const abortPromise = new Promise((_, reject) => {
18946
- if (this.signal?.aborted) {
18947
- return reject(new Error(this.signal.reason || "Aborted"));
18948
- }
18949
- const callback = (e) => {
18950
- const target = e.target;
18951
- this.signal?.removeEventListener("abort", callback);
18952
- reject(new Error(target.reason || "Aborted"));
18953
- };
18954
- this.signal?.addEventListener("abort", callback, { once: true });
18955
- });
18956
- const pipelineRunner = async () => {
18957
- let lastResult;
18958
- if (typeof this.initialExecutor === "function") {
18959
- if (this.signal?.aborted) {
18960
- throw new Error(this.signal.reason || "Aborted");
18961
- }
18962
- lastResult = await this.initialExecutor();
18963
- } else {
18964
- lastResult = await this.initialExecutor;
18965
- }
18966
- for (let i = 0; i < this.steps.length; i++) {
18967
- if (this.signal?.aborted) {
18968
- throw new Error(this.signal.reason || "Aborted");
18969
- }
18970
- const step = this.steps[i];
18971
- lastResult = await step(lastResult);
18972
- }
18973
- return lastResult;
18974
- };
18975
- return await Promise.race([pipelineRunner(), abortPromise]);
18976
- } catch (error) {
18977
- if (this.errorHandler) {
18978
- return await this.errorHandler(error);
18979
- }
18980
- throw error;
18981
- }
18982
- }
18983
- // Convert to native Promise
18967
+ // 네이티브 Promise 로 변환 (그냥 await 해도 된다)
18984
18968
  toPromise() {
18985
- return this.execute();
18969
+ return this.promise;
18986
18970
  }
18987
18971
  };
18988
18972
 
@@ -19855,11 +19839,15 @@ var dooboostoreSimpleBootHttpServer = (() => {
19855
19839
  resolve2(gdata);
19856
19840
  }).catch(async (e) => {
19857
19841
  this.error(config, pipe, e);
19858
- config?.error?.();
19842
+ config?.error?.(e);
19859
19843
  if (config?.errorTransform) {
19860
19844
  e = await config.errorTransform(e);
19861
19845
  }
19862
- e = await this.errorTransform(e);
19846
+ try {
19847
+ e = await this.errorTransform(e);
19848
+ } catch (ee) {
19849
+ e = ee;
19850
+ }
19863
19851
  reject(e);
19864
19852
  }).finally(() => {
19865
19853
  this.finally(config, pipe);
@@ -19876,41 +19864,30 @@ var dooboostoreSimpleBootHttpServer = (() => {
19876
19864
  return data instanceof HttpResponseError;
19877
19865
  };
19878
19866
  var HttpFetcher = class extends Fetcher {
19867
+ // get/post/put/patch/head/delete가 전부 config.config.fetch.method를 세팅하려고 caller가
19868
+ // 넘긴 config(.fetch) 객체를 직접 mutate했다 - 같은 config 객체를 여러 호출이 공유하면
19869
+ // (예: Promise.all로 동시에 get/post) 서로의 method를 덮어쓰는 레이스가 생겼다. caller의
19870
+ // 객체는 절대 건드리지 않고, 얕은 복사본 위에 method만 얹어서 반환한다.
19871
+ withMethod(config, method) {
19872
+ return { ...config, config: { ...config.config, fetch: { ...config.config?.fetch, method } } };
19873
+ }
19879
19874
  get(config) {
19880
- config.config ?? (config.config = {});
19881
- config.config.fetch = config.config?.fetch ?? {};
19882
- config.config.fetch.method = "GET";
19883
- return this.fetch(config);
19875
+ return this.fetch(this.withMethod(config, "GET"));
19884
19876
  }
19885
19877
  post(config) {
19886
- config.config ?? (config.config = {});
19887
- config.config.fetch = config.config?.fetch ?? {};
19888
- config.config.fetch.method = "POST";
19889
- return this.fetch(config);
19878
+ return this.fetch(this.withMethod(config, "POST"));
19890
19879
  }
19891
19880
  patch(config) {
19892
- config.config ?? (config.config = {});
19893
- config.config.fetch = config.config?.fetch ?? {};
19894
- config.config.fetch.method = "PATCH";
19895
- return this.fetch(config);
19881
+ return this.fetch(this.withMethod(config, "PATCH"));
19896
19882
  }
19897
19883
  put(config) {
19898
- config.config ?? (config.config = {});
19899
- config.config.fetch = config.config?.fetch ?? {};
19900
- config.config.fetch.method = "PUT";
19901
- return this.fetch(config);
19884
+ return this.fetch(this.withMethod(config, "PUT"));
19902
19885
  }
19903
19886
  head(config) {
19904
- config.config ?? (config.config = {});
19905
- config.config.fetch = config.config?.fetch ?? {};
19906
- config.config.fetch.method = "HEAD";
19907
- return this.fetch(config);
19887
+ return this.fetch(this.withMethod(config, "HEAD"));
19908
19888
  }
19909
19889
  delete(config) {
19910
- config.config ?? (config.config = {});
19911
- config.config.fetch = config.config?.fetch ?? {};
19912
- config.config.fetch.method = "DELETE";
19913
- return this.fetch(config);
19890
+ return this.fetch(this.withMethod(config, "DELETE"));
19914
19891
  }
19915
19892
  async beforeProxyFetch(config) {
19916
19893
  return config;
@@ -19947,7 +19924,7 @@ var dooboostoreSimpleBootHttpServer = (() => {
19947
19924
  }
19948
19925
  } else {
19949
19926
  httpResponseError.body = e;
19950
- httpResponseError.message = e.message;
19927
+ httpResponseError.message = e?.message;
19951
19928
  }
19952
19929
  return httpResponseError;
19953
19930
  }
@@ -19957,7 +19934,7 @@ var dooboostoreSimpleBootHttpServer = (() => {
19957
19934
  if (!(target instanceof URL) && typeof target !== "string") {
19958
19935
  const searchParams = ConvertUtils.toURLSearchParams(target.searchParams ?? {});
19959
19936
  try {
19960
- const url = typeof target.url === "string" ? new URL(target.url) : target.url;
19937
+ const url = new URL(target.url);
19961
19938
  searchParams.forEach((value, key) => {
19962
19939
  url.searchParams.append(key, value);
19963
19940
  });
@@ -19972,43 +19949,30 @@ var dooboostoreSimpleBootHttpServer = (() => {
19972
19949
  }
19973
19950
  }
19974
19951
  const beforeProxyData = { requestInfo: target, init: config?.fetch };
19975
- let beforeData = config?.beforeProxyFetch ? await config?.beforeProxyFetch(config) : beforeProxyData.requestInfo;
19976
- beforeData = config?.skipGlobalBeforeProxyFetch ? beforeProxyData : await this.beforeProxyFetch(beforeProxyData);
19952
+ let beforeData = config?.beforeProxyFetch ? await config?.beforeProxyFetch(beforeProxyData) : beforeProxyData;
19953
+ beforeData = config?.skipGlobalBeforeProxyFetch ? beforeData : await this.beforeProxyFetch(beforeData);
19977
19954
  target = beforeData.requestInfo;
19978
19955
  if (beforeData.init) {
19979
19956
  config ?? (config = {});
19980
19957
  config.fetch = beforeData.init;
19981
19958
  }
19982
- let abortedTimeout;
19959
+ let requestInit = config?.fetch;
19983
19960
  if (config?.fetch && "timeout" in config.fetch) {
19984
- const abortController = new AbortController();
19985
- abortedTimeout = setTimeout(() => {
19986
- if (config?.fetch?.signal) {
19987
- const inputSignal = config.fetch.signal;
19988
- const listener = () => {
19989
- if (!abortController.signal.aborted) {
19990
- abortController.abort();
19991
- }
19992
- inputSignal.removeEventListener("abort", listener);
19993
- };
19994
- inputSignal.addEventListener("abort", listener);
19995
- }
19996
- if (!abortController.signal.aborted) {
19997
- abortController.abort();
19998
- }
19999
- }, config.fetch.timeout);
20000
- config.fetch.signal = abortController.signal;
19961
+ const timeoutSignal = AbortSignal.timeout(config.fetch.timeout);
19962
+ const signal = config.fetch.signal ? AbortSignal.any([timeoutSignal, config.fetch.signal]) : timeoutSignal;
19963
+ requestInit = { ...config.fetch, signal };
20001
19964
  }
20002
- this.beforeFetch({ target, requestInit: config?.fetch });
20003
- return (config.fetcher ?? fetch)(target, config?.fetch).then(async (it) => {
20004
- this.afterFetch({ target, requestInit: config?.fetch }, it);
19965
+ this.beforeFetch({ target, requestInit });
19966
+ return (config.fetcher ?? fetch)(target, requestInit).then(async (it) => {
19967
+ this.afterFetch({ target, requestInit }, it);
20005
19968
  const afterProxyData = {
20006
- fetch: { target, requestInit: config.fetch },
19969
+ fetch: { target, requestInit },
20007
19970
  config: beforeData,
20008
19971
  response: it
20009
19972
  };
20010
- it = config?.afterProxyFetch ? await config.afterProxyFetch(afterProxyData) : it;
20011
- it = config?.skipGlobalAfterProxyFetch ? it : await this.afterProxyFetch(afterProxyData);
19973
+ afterProxyData.response = config?.afterProxyFetch ? await config.afterProxyFetch(afterProxyData) : it;
19974
+ afterProxyData.response = config?.skipGlobalAfterProxyFetch ? afterProxyData.response : await this.afterProxyFetch(afterProxyData);
19975
+ it = afterProxyData.response;
20012
19976
  config?.fetchResponseAfterCallBack?.(it, config);
20013
19977
  if (!config?.allowedResponseNotOk && !it.ok) {
20014
19978
  throw it;
@@ -20018,30 +19982,31 @@ var dooboostoreSimpleBootHttpServer = (() => {
20018
19982
  throw data;
20019
19983
  }
20020
19984
  return it;
20021
- }).finally(() => {
20022
- if (abortedTimeout) {
20023
- clearTimeout(abortedTimeout);
20024
- }
20025
19985
  });
20026
19986
  }
20027
19987
  };
20028
19988
 
20029
19989
  // ../core/dist/esm/fetch/HttpJsonFetcher.js
20030
19990
  var HttpJsonFetcher = class extends HttpFetcher {
19991
+ // config.config/config.config.fetch를 직접 mutate하면(예전처럼) 같은 config 객체를 여러
19992
+ // postJson/patchJson/putJson 호출이 동시에 공유할 때 서로의 headers/body를 덮어쓰는 레이스가
19993
+ // 생긴다(HttpFetcher.get/post의 method 레이스랑 같은 문제). caller의 객체는 안 건드리고,
19994
+ // 얕은 복사본을 만들어서 새 config 객체를 리턴한다.
20031
19995
  updateJsonFetchConfigAndData(config) {
20032
- var _a4, _b3;
20033
19996
  const headers = {
20034
19997
  "Content-Type": "application/json",
20035
19998
  Accept: "application/json, text/plain, */*"
20036
19999
  };
20037
- config.config ?? (config.config = {});
20038
- (_a4 = config.config).fetch ?? (_a4.fetch = {});
20039
- (_b3 = config.config.fetch).headers ?? (_b3.headers = {});
20040
- config.config.fetch.headers = { ...headers, ...config.config.fetch?.headers };
20041
- if (config.config?.fetch?.body && typeof config.config?.fetch?.body !== "string") {
20042
- config.config.fetch.body = JSON.stringify(config.config.fetch.body);
20000
+ const fetchInit = { ...config.config?.fetch };
20001
+ const merged = new Headers(headers);
20002
+ if (fetchInit.headers) {
20003
+ new Headers(fetchInit.headers).forEach((value, key) => merged.set(key, value));
20043
20004
  }
20044
- return config;
20005
+ fetchInit.headers = merged;
20006
+ if (fetchInit.body && typeof fetchInit.body !== "string") {
20007
+ fetchInit.body = JSON.stringify(fetchInit.body);
20008
+ }
20009
+ return { ...config, config: { ...config.config, fetch: fetchInit } };
20045
20010
  }
20046
20011
  get(config) {
20047
20012
  return super.get(config);
@@ -21865,12 +21830,13 @@ var dooboostoreSimpleBootHttpServer = (() => {
21865
21830
  ReflectUtils2.findMetadata = (metadataKey, target, propertyKey) => {
21866
21831
  if (target == null) return void 0;
21867
21832
  let searchTarget = typeof target === "object" && typeof target !== "function" ? target.constructor : target;
21868
- while (searchTarget && searchTarget !== Object) {
21833
+ const seen = /* @__PURE__ */ new Set();
21834
+ while (searchTarget && searchTarget !== Object && !seen.has(searchTarget)) {
21835
+ seen.add(searchTarget);
21869
21836
  const data = propertyKey ? Reflect.getOwnMetadata(metadataKey, searchTarget, propertyKey) : Reflect.getOwnMetadata(metadataKey, searchTarget);
21870
21837
  if (data !== void 0) return data;
21871
21838
  const proto = Object.getPrototypeOf(searchTarget);
21872
21839
  searchTarget = proto && typeof proto === "function" ? proto : proto?.constructor || null;
21873
- if (searchTarget === target) break;
21874
21840
  }
21875
21841
  return void 0;
21876
21842
  };
@@ -21878,12 +21844,13 @@ var dooboostoreSimpleBootHttpServer = (() => {
21878
21844
  const results = [];
21879
21845
  if (target == null) return results;
21880
21846
  let searchTarget = typeof target === "object" && typeof target !== "function" ? target.constructor : target;
21881
- while (searchTarget && searchTarget !== Object) {
21847
+ const seen = /* @__PURE__ */ new Set();
21848
+ while (searchTarget && searchTarget !== Object && !seen.has(searchTarget)) {
21849
+ seen.add(searchTarget);
21882
21850
  const data = propertyKey ? Reflect.getOwnMetadata(metadataKey, searchTarget, propertyKey) : Reflect.getOwnMetadata(metadataKey, searchTarget);
21883
21851
  if (data !== void 0) results.unshift(data);
21884
21852
  const proto = Object.getPrototypeOf(searchTarget);
21885
21853
  searchTarget = proto && typeof proto === "function" ? proto : proto?.constructor || null;
21886
- if (searchTarget === target) break;
21887
21854
  }
21888
21855
  return results;
21889
21856
  };
@@ -25130,7 +25097,16 @@ ${indentStr}}`;
25130
25097
  }
25131
25098
  if (!this.value) {
25132
25099
  if (typeof this.type.targetKeyType === "symbol") {
25133
- this.value = this.simstanceManager.findFirstSim(this.type.targetKeyType)?.getValue();
25100
+ const stored = this.simstanceManager.getStoreSet(this.type.targetKeyType);
25101
+ if (ValidUtils.isArrowFunction(stored?.instance)) {
25102
+ const fresh = stored.instance();
25103
+ if (this.getConfig()?.scope === Lifecycle.Singleton) {
25104
+ this.simstanceManager.setStoreSet(this.type.targetKeyType, fresh, stored.type);
25105
+ this.value = fresh;
25106
+ }
25107
+ return fresh;
25108
+ }
25109
+ this.value = stored?.instance;
25134
25110
  } else {
25135
25111
  this.value = this.simstanceManager.getOrNewSim({ target: this.type.targetKeyType, originTypeTarget: this.type.originalType, newInstanceCarrier: config?.newInstanceCarrier });
25136
25112
  }
@@ -25685,7 +25661,7 @@ ${indentStr}}`;
25685
25661
  registerStore(targetKey, regTyps) {
25686
25662
  const itemMap = this.storage.get(targetKey) ?? /* @__PURE__ */ new Map();
25687
25663
  regTyps.forEach((it) => {
25688
- const { type, value } = typeof it === "object" ? { type: it.constructor, value: it } : { type: it, value: void 0 };
25664
+ const { type, value } = ValidUtils.isArrowFunction(it) ? { type: it, value: it } : typeof it === "object" ? { type: it.constructor, value: it } : { type: it, value: void 0 };
25689
25665
  if (!itemMap.has(type) || value !== void 0 && itemMap.get(type) === void 0) {
25690
25666
  itemMap.set(type, value);
25691
25667
  }
@@ -25938,9 +25914,16 @@ ${indentStr}}`;
25938
25914
  }
25939
25915
  run(otherInstanceSim = /* @__PURE__ */ new Map()) {
25940
25916
  for (const [k, v] of Array.from(otherInstanceSim.entries())) {
25941
- const storageKey = typeof k === "object" && k !== null && "type" in k ? k.type : k;
25942
- this.registerStore(storageKey, /* @__PURE__ */ new Set([v]));
25943
- if (typeof k === "object" && k !== null && "symbol" in k && k.symbol) {
25917
+ const hasType = typeof k === "object" && k !== null && "type" in k;
25918
+ const hasSymbol = typeof k === "object" && k !== null && !!k.symbol;
25919
+ const storageKey = hasType ? k.type : k;
25920
+ if (hasType || !hasSymbol) {
25921
+ this.registerStore(storageKey, /* @__PURE__ */ new Set([v]));
25922
+ }
25923
+ if (hasSymbol) {
25924
+ if (!ReflectUtils.getMetadata(SimMetadataKey, v)) {
25925
+ ReflectUtils.defineMetadata(SimMetadataKey, { ...k, scope: k.scope ?? Lifecycle.Singleton }, v);
25926
+ }
25944
25927
  this.registerStore(k.symbol, /* @__PURE__ */ new Set([v]));
25945
25928
  }
25946
25929
  }
@@ -28069,7 +28052,7 @@ ${indentStr}}`;
28069
28052
  fetch: {
28070
28053
  credentials: "include",
28071
28054
  headers,
28072
- body: ConvertUtils.toFormData(userConfig?.body)
28055
+ body: userConfig?.body ? ConvertUtils.toFormData(userConfig.body) : void 0
28073
28056
  }
28074
28057
  }
28075
28058
  });
@@ -28382,6 +28365,16 @@ ${indentStr}}`;
28382
28365
  };
28383
28366
  };
28384
28367
 
28368
+ // src/proxy/RequestResponseInjectProxy.ts
28369
+ var injectRequestResponse = (sim2, rr) => new Proxy(sim2, {
28370
+ get(target, prop) {
28371
+ const value = target[prop];
28372
+ if (prop === "constructor" || typeof value !== "function") return value;
28373
+ if (!rr) return value.bind(target);
28374
+ return (...args) => value.apply(target, [...args, rr]);
28375
+ }
28376
+ });
28377
+
28385
28378
  // src/inject/InjectSituationType.ts
28386
28379
  var InjectSituationType2;
28387
28380
  ((InjectSituationType3) => {
@@ -28406,6 +28399,7 @@ ${indentStr}}`;
28406
28399
 
28407
28400
  // src/models/RequestResponse.ts
28408
28401
  var import_node_gzip = __toESM(require_dist(), 1);
28402
+ var import_zlib = __require("zlib");
28409
28403
  var import_node_buffer2 = __require("node:buffer");
28410
28404
  var RequestResponse = class _RequestResponse {
28411
28405
  constructor(req, res, config) {
@@ -28844,6 +28838,57 @@ ${indentStr}}`;
28844
28838
  this.createRequestResponseChain(this.res.writeHead(statusCode, headers));
28845
28839
  this.res.end();
28846
28840
  }
28841
+ /**
28842
+ * 헤더를 즉시 보내고, source 가 내놓는 값을 하나씩 바로 body 에 쓴 뒤 end.
28843
+ * (SSE / 스트리밍 응답용. resWrite 는 버퍼링 후 resEnd 에서 한 번에 보내므로 스트리밍 불가)
28844
+ * - 문자열/Buffer 는 그대로, 그 외는 JSON.stringify
28845
+ * - Accept-Encoding 에 gzip 이 있으면 gzip 스트림으로 압축하고, 청크마다 Z_SYNC_FLUSH 로 바로 내보낸다
28846
+ * (flush 없이 쓰면 zlib 내부 버퍼에 모였다가 늦게 나가서 SSE 실시간성이 깨짐)
28847
+ * - 클라이언트가 끊으면 source.return() 으로 제너레이터를 종료시켜 finally 가 돌게 한다
28848
+ */
28849
+ async resStream(source) {
28850
+ const res = this.res;
28851
+ const gz = this.reqHeaderFirst(HttpHeaders.AcceptEncoding)?.includes("gzip") ? (0, import_zlib.createGzip)() : void 0;
28852
+ if (gz) {
28853
+ res.setHeader(HttpHeaders.ContentEncoding, "gzip");
28854
+ res.removeHeader(HttpHeaders.ContentLength);
28855
+ gz.pipe(res);
28856
+ }
28857
+ const out = gz ?? res;
28858
+ res.flushHeaders();
28859
+ let closed = false;
28860
+ const onClose = () => {
28861
+ closed = true;
28862
+ source.return?.();
28863
+ };
28864
+ res.once("close", onClose);
28865
+ try {
28866
+ for await (const chunk of source) {
28867
+ if (closed) break;
28868
+ const data = typeof chunk === "string" || import_buffer.Buffer.isBuffer(chunk) ? chunk : JSON.stringify(chunk);
28869
+ const ok = out.write(data);
28870
+ gz?.flush(import_zlib.constants.Z_SYNC_FLUSH);
28871
+ if (!ok) await new Promise((resolve2) => {
28872
+ out.once("drain", resolve2);
28873
+ res.once("close", resolve2);
28874
+ });
28875
+ }
28876
+ } catch (e) {
28877
+ if (!closed) throw e;
28878
+ } finally {
28879
+ res.off("close", onClose);
28880
+ if (closed) {
28881
+ gz?.destroy();
28882
+ } else if (!res.writableEnded) {
28883
+ const finished = new Promise((resolve2) => {
28884
+ res.once("finish", resolve2);
28885
+ res.once("close", resolve2);
28886
+ });
28887
+ out.end();
28888
+ await finished;
28889
+ }
28890
+ }
28891
+ }
28847
28892
  resIsDone() {
28848
28893
  return this.res.finished || this.res.writableEnded || this.res.headersSent;
28849
28894
  }
@@ -29191,6 +29236,11 @@ ${indentStr}}`;
29191
29236
  otherStorage.set(RequestResponse, rr);
29192
29237
  otherStorage.set(import_http.IncomingMessage, req);
29193
29238
  otherStorage.set(import_http.ServerResponse, res);
29239
+ const abortController = new AbortController();
29240
+ res.once("close", () => {
29241
+ if (!res.writableFinished) abortController.abort();
29242
+ });
29243
+ otherStorage.set(AbortSignal, abortController.signal);
29194
29244
  try {
29195
29245
  transactionManager?.try();
29196
29246
  if (this.option.requestEndPoints) {
@@ -29348,11 +29398,19 @@ ${indentStr}}`;
29348
29398
  targetKey: it.propertyKey
29349
29399
  }, otherStorage);
29350
29400
  const resConfig = it.config?.res;
29351
- if (resConfig?.manual === true) {
29401
+ if (resConfig === "manual") {
29402
+ } else if (ValidUtils.isGenerator(data) || ValidUtils.isAsyncGenerator(data)) {
29403
+ const headers = resConfig?.header ?? {};
29404
+ if (resConfig?.contentType) {
29405
+ headers[HttpHeaders.ContentType] = resConfig.contentType;
29406
+ }
29407
+ rr.resSetHeaders(headers);
29408
+ rr.resSetStatusCode(resConfig?.status ?? 200 /* Ok */);
29409
+ await rr.resStream(data);
29352
29410
  } else {
29353
29411
  if (it.config?.resolver) {
29354
29412
  const execute = typeof it.config.resolver === "function" ? this.simstanceManager.getOrNewSim({ target: it.config.resolver }) : it.config.resolver;
29355
- data = await execute?.resolve?.(data, rr);
29413
+ data = await execute?.resolve?.(data, rr, resConfig);
29356
29414
  }
29357
29415
  const status = resConfig?.status ?? 200 /* Ok */;
29358
29416
  const headers = resConfig?.header ?? {};
@@ -29664,7 +29722,7 @@ ${indentStr}}`;
29664
29722
  var ElementApply = class _ElementApply {
29665
29723
  constructor(el, config) {
29666
29724
  this.el = el;
29667
- this.window = this.el.ownerDocument.defaultView;
29725
+ this.window = this.el.ownerDocument.defaultView ?? globalThis;
29668
29726
  this.document = this.el.ownerDocument;
29669
29727
  this.id = config?.id ?? el.id;
29670
29728
  this.variableWrap = config?.variableWrap ?? { start: "@", end: "@" };
@@ -29687,6 +29745,8 @@ ${indentStr}}`;
29687
29745
  let match;
29688
29746
  while ((match = regex.exec(script)) !== null) {
29689
29747
  variables.push(match[1]);
29748
+ const root = match[1].split(/[.[(]/)[0].trim();
29749
+ if (root && root !== match[1]) variables.push(root);
29690
29750
  }
29691
29751
  return variables;
29692
29752
  }
@@ -29791,10 +29851,15 @@ ${indentStr}}`;
29791
29851
  type.variables.forEach((v) => variables.add(v));
29792
29852
  });
29793
29853
  }
29854
+ const bind = config?.bind;
29855
+ const fromBind = (key) => bind != null && typeof key === "string" && !(key in (config?.context ?? {})) && _ElementApply.isUserMember(bind, key);
29794
29856
  const context = new Proxy(config?.context ?? {}, {
29857
+ has(target, key) {
29858
+ return key in target || fromBind(key);
29859
+ },
29795
29860
  get(target, key) {
29796
- const value = target[key];
29797
- return typeof value === "function" ? value.bind(config?.bind ?? target) : value;
29861
+ const value = key in target ? target[key] : fromBind(key) ? bind[key] : void 0;
29862
+ return typeof value === "function" ? value.bind(bind ?? target) : value;
29798
29863
  }
29799
29864
  });
29800
29865
  if (!config?.targetVariableName || config?.targetVariableName && variables.has(config?.targetVariableName)) {
@@ -29819,7 +29884,6 @@ ${indentStr}}`;
29819
29884
  }
29820
29885
  }
29821
29886
  `)(context).bind(it.node);
29822
- console.log("------------------->", it, tit);
29823
29887
  if (tit.type === "attribute" && !config?.exclude?.attribute) {
29824
29888
  it.node.setAttribute(tit.name, data());
29825
29889
  } else if (tit.type === "property" && !config?.exclude?.property) {
@@ -29839,6 +29903,15 @@ ${indentStr}}`;
29839
29903
  }
29840
29904
  }
29841
29905
  }
29906
+ /** key 가 네이티브(DOM/내장) prototype 이 아니라 사용자 클래스나 인스턴스에 정의돼 있으면 true */
29907
+ static isUserMember(obj, key) {
29908
+ for (let p = obj; p; p = Object.getPrototypeOf(p)) {
29909
+ if (!Object.prototype.hasOwnProperty.call(p, key)) continue;
29910
+ const ctor = p === obj ? null : p.constructor;
29911
+ return !(typeof ctor === "function" && /\[native code\]/.test(Function.prototype.toString.call(ctor)));
29912
+ }
29913
+ return false;
29914
+ }
29842
29915
  removeAllEventListener() {
29843
29916
  const m = this.findAllTarget().filter((it) => it.nodeType === "element").flatMap((it) => it.types.map((sit) => ({ ...sit, node: it.node })).filter((it2) => it2.type === "event"));
29844
29917
  m.forEach((tit) => {
@@ -30216,15 +30289,21 @@ ${indentStr}}`;
30216
30289
  const slots = this.findSlots();
30217
30290
  return slots.map((s) => s.nodes());
30218
30291
  }
30219
- append(...args) {
30220
- let targetId;
30221
- let items = [];
30222
- if (typeof args[0] === "string" && args.length > 1) {
30223
- targetId = args[0];
30224
- items = args.slice(1);
30225
- } else {
30226
- items = args;
30292
+ /**
30293
+ * Shared disambiguation for the `(...items)` / `(targetId, ...items)` overload pair.
30294
+ * Items are always Node instances (or strings meant as literal content) coming from
30295
+ * callers; a leading string is therefore always treated as `targetId`, even when no
30296
+ * items follow — this avoids misclassifying `targetId` itself as content when the
30297
+ * caller has zero items to insert (e.g. a decorated method returning undefined).
30298
+ */
30299
+ static parseTargetArgs(args) {
30300
+ if (typeof args[0] === "string") {
30301
+ return { targetId: args[0], items: args.slice(1) };
30227
30302
  }
30303
+ return { targetId: void 0, items: args };
30304
+ }
30305
+ append(...args) {
30306
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30228
30307
  if (!items || items.length === 0) return;
30229
30308
  const slots = this.findSlots(targetId);
30230
30309
  if (!slots || slots.length === 0) return;
@@ -30233,38 +30312,17 @@ ${indentStr}}`;
30233
30312
  }
30234
30313
  }
30235
30314
  appendHtml(...args) {
30236
- let targetId;
30237
- let items = [];
30238
- if (typeof args[0] === "string" && args.length > 1) {
30239
- targetId = args[0];
30240
- items = args.slice(1);
30241
- } else {
30242
- items = args;
30243
- }
30315
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30244
30316
  const slots = this.findSlots(targetId);
30245
30317
  for (const s of slots) s.appendHtml(...items);
30246
30318
  }
30247
30319
  appendText(...args) {
30248
- let targetId;
30249
- let items = [];
30250
- if (typeof args[0] === "string" && args.length > 1) {
30251
- targetId = args[0];
30252
- items = args.slice(1);
30253
- } else {
30254
- items = args;
30255
- }
30320
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30256
30321
  const slots = this.findSlots(targetId);
30257
30322
  for (const s of slots) s.appendText(...items);
30258
30323
  }
30259
30324
  appendCopy(...args) {
30260
- let targetId;
30261
- let items = [];
30262
- if (typeof args[0] === "string" && args.length > 1) {
30263
- targetId = args[0];
30264
- items = args.slice(1);
30265
- } else {
30266
- items = args;
30267
- }
30325
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30268
30326
  if (!items || items.length === 0) return;
30269
30327
  const slots = this.findSlots(targetId);
30270
30328
  if (!slots || slots.length === 0) return;
@@ -30273,14 +30331,7 @@ ${indentStr}}`;
30273
30331
  }
30274
30332
  }
30275
30333
  prepend(...args) {
30276
- let targetId;
30277
- let items = [];
30278
- if (typeof args[0] === "string" && args.length > 1) {
30279
- targetId = args[0];
30280
- items = args.slice(1);
30281
- } else {
30282
- items = args;
30283
- }
30334
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30284
30335
  if (!items || items.length === 0) return;
30285
30336
  const slots = this.findSlots(targetId);
30286
30337
  if (!slots || slots.length === 0) return;
@@ -30289,38 +30340,17 @@ ${indentStr}}`;
30289
30340
  }
30290
30341
  }
30291
30342
  prependHtml(...args) {
30292
- let targetId;
30293
- let items = [];
30294
- if (typeof args[0] === "string" && args.length > 1) {
30295
- targetId = args[0];
30296
- items = args.slice(1);
30297
- } else {
30298
- items = args;
30299
- }
30343
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30300
30344
  const slots = this.findSlots(targetId);
30301
30345
  for (const s of slots) s.prependHtml(...items);
30302
30346
  }
30303
30347
  prependText(...args) {
30304
- let targetId;
30305
- let items = [];
30306
- if (typeof args[0] === "string" && args.length > 1) {
30307
- targetId = args[0];
30308
- items = args.slice(1);
30309
- } else {
30310
- items = args;
30311
- }
30348
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30312
30349
  const slots = this.findSlots(targetId);
30313
30350
  for (const s of slots) s.prependText(...items);
30314
30351
  }
30315
30352
  prependCopy(...args) {
30316
- let targetId;
30317
- let items = [];
30318
- if (typeof args[0] === "string" && args.length > 1) {
30319
- targetId = args[0];
30320
- items = args.slice(1);
30321
- } else {
30322
- items = args;
30323
- }
30353
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30324
30354
  if (!items || items.length === 0) return;
30325
30355
  const slots = this.findSlots(targetId);
30326
30356
  if (!slots || slots.length === 0) return;
@@ -30340,14 +30370,7 @@ ${indentStr}}`;
30340
30370
  }
30341
30371
  }
30342
30372
  replaceChildren(...args) {
30343
- let targetId;
30344
- let items = [];
30345
- if (typeof args[0] === "string" && args.length > 1) {
30346
- targetId = args[0];
30347
- items = args.slice(1);
30348
- } else {
30349
- items = args;
30350
- }
30373
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30351
30374
  const slots = this.findSlots(targetId);
30352
30375
  if (!slots || slots.length === 0) return;
30353
30376
  for (const s of slots) {
@@ -30355,14 +30378,7 @@ ${indentStr}}`;
30355
30378
  }
30356
30379
  }
30357
30380
  replaceChildrenHtml(...args) {
30358
- let targetId;
30359
- let items = [];
30360
- if (typeof args[0] === "string" && args.length > 1) {
30361
- targetId = args[0];
30362
- items = args.slice(1);
30363
- } else {
30364
- items = args;
30365
- }
30381
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30366
30382
  const slots = this.findSlots(targetId);
30367
30383
  if (!slots || slots.length === 0) return;
30368
30384
  for (const s of slots) {
@@ -30370,14 +30386,7 @@ ${indentStr}}`;
30370
30386
  }
30371
30387
  }
30372
30388
  replaceChildrenText(...args) {
30373
- let targetId;
30374
- let items = [];
30375
- if (typeof args[0] === "string" && args.length > 1) {
30376
- targetId = args[0];
30377
- items = args.slice(1);
30378
- } else {
30379
- items = args;
30380
- }
30389
+ const { targetId, items } = _NodeSlot.parseTargetArgs(args);
30381
30390
  const slots = this.findSlots(targetId);
30382
30391
  if (!slots || slots.length === 0) return;
30383
30392
  for (const s of slots) {
@@ -31068,6 +31077,7 @@ ${indentStr}}`;
31068
31077
  var ROUTER_NO_EVENT_MARKER = "__ROUTER_NO_EVENT__";
31069
31078
  var Router2 = class {
31070
31079
  constructor(config) {
31080
+ this.leaveGuards = /* @__PURE__ */ new Set();
31071
31081
  this._config = config;
31072
31082
  let routeData;
31073
31083
  if (config?.firstUrl) {
@@ -31088,13 +31098,39 @@ ${indentStr}}`;
31088
31098
  this.behaviorSubject = new BehaviorSubject(routeData);
31089
31099
  }
31090
31100
  this.config.window.addEventListener("popstate", (event) => {
31091
- const routeData2 = { ...this.getRouteData(), triggerPoint: "end" };
31092
- this.behaviorSubject.next(routeData2);
31101
+ const publish = () => this.behaviorSubject.next({ ...this.getRouteData(), triggerPoint: "end" });
31102
+ if (!this.leaveGuards.size) return publish();
31103
+ const from = this.value;
31104
+ void this.canLeave(this.getRouteData(), from).then((ok) => {
31105
+ if (ok) publish();
31106
+ else this.config.window.history?.pushState(from.data ?? null, "", from.url);
31107
+ });
31093
31108
  });
31094
31109
  }
31095
31110
  get value() {
31096
31111
  return this.behaviorSubject.getValue();
31097
31112
  }
31113
+ /**
31114
+ * 이동 전 가드 등록. go() 와 뒤로/앞으로 가기(popstate)에 적용된다 (pushState/replaceState 직접 호출은 제외).
31115
+ * 리턴한 함수를 부르면 해제된다.
31116
+ */
31117
+ addLeaveGuard(guard) {
31118
+ this.leaveGuards.add(guard);
31119
+ return () => {
31120
+ this.leaveGuards.delete(guard);
31121
+ };
31122
+ }
31123
+ /** 가드가 하나라도 있는지 (없으면 호출자가 동기로 진행해도 된다) */
31124
+ get hasLeaveGuards() {
31125
+ return this.leaveGuards.size > 0;
31126
+ }
31127
+ /** 등록된 가드를 순서대로 평가. 하나라도 false 면 false */
31128
+ async canLeave(to, from) {
31129
+ for (const guard of [...this.leaveGuards]) {
31130
+ if (await guard(to, from) === false) return false;
31131
+ }
31132
+ return true;
31133
+ }
31098
31134
  get observable() {
31099
31135
  return this.behaviorSubject.asObservable();
31100
31136
  }
@@ -31225,17 +31261,24 @@ ${indentStr}}`;
31225
31261
  if (typeof config === "string") {
31226
31262
  config = { path: config };
31227
31263
  }
31228
- if (config?.replace) {
31229
- this.replace(config.path, config.state);
31230
- } else {
31231
- this.push(config.path, config.state);
31232
- }
31233
- if (config.scrollToTop !== false) {
31234
- try {
31235
- this._config.window?.scrollTo?.(0, 0);
31236
- } catch (e) {
31264
+ const target = config;
31265
+ const navigate = () => {
31266
+ if (target?.replace) {
31267
+ this.replace(target.path, target.state);
31268
+ } else {
31269
+ this.push(target.path, target.state);
31237
31270
  }
31238
- }
31271
+ if (target.scrollToTop !== false) {
31272
+ try {
31273
+ this._config.window?.scrollTo?.(0, 0);
31274
+ } catch (e) {
31275
+ }
31276
+ }
31277
+ };
31278
+ if (!this.leaveGuards.size) return navigate();
31279
+ return this.canLeave(this.getRouteData({ pathOrUrl: this.toUrl(target.path) }), this.value).then((ok) => {
31280
+ if (ok) navigate();
31281
+ });
31239
31282
  }
31240
31283
  toUrl(data) {
31241
31284
  let targetPath;