@basmilius/http-client 3.29.0 → 3.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +1012 -1
- package/dist/index.mjs.map +1 -1
- package/dist/vite.d.mts +11 -0
- package/dist/vite.d.mts.map +1 -0
- package/dist/vite.mjs +56 -0
- package/dist/vite.mjs.map +1 -0
- package/package.json +13 -2
- package/src/vite/dtoNames.ts +84 -0
- package/src/vite.ts +1 -0
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,1013 @@
|
|
|
1
|
-
import{DateTime as e}from"luxon";import{debounce as t,getPrototypeChain as n,setObjectMethod as r,setObjectValue as i}from"@basmilius/utils";import{customRef as a,markRaw as o,toRaw as s}from"vue";function c(e){return class extends e{constructor(...e){throw Error(`@adapter: cannot create instance of class.`)}}}function ee(){return(e,t)=>{e[t]=e[t].bind(e)}}function te(e){return(n,r,i)=>{i.value=t(i.value,e,n)}}function ne(e,t){return e===t?!0:e===t}const l=Symbol(),u=Symbol(),d=Symbol(),f=Symbol(),p=Symbol(),m=Symbol(),h=Symbol(),g=Symbol(),_=Symbol(),re=Symbol(),ie=Symbol();function v(e){return e&&typeof e==`object`&&!!e[p]}function y(e){if(!v(e))throw Error(`@dto assert given object is not a class decorated with @Dto.`)}const ae=Symbol();function b(e,t=0,n){return function(...r){let i=e[ae]??=new WeakMap,a=r[t],o=n===void 0?`self`:r[n];if(typeof a!=`object`||!a)return e.call(this,...r);i.has(a)||i.set(a,[]);let s=i.get(a);if(!s.includes(o)){s.push(o);try{return e.call(this,...r)}finally{let e=s.lastIndexOf(o);e!==-1&&s.splice(e,1),s.length===0&&i.delete(a)}}}}function oe(e){return y(e),e.clone()}function x(e){return y(e),e[f]}const S=b(function(e,t,n,r){let i=e[ie];i(e,t,n,r),e[m]&&S(e[m],e[h],e[m][e[h]])},0,1),C=b(function(e){y(e),e[f]&&(e[f]=!1,S(e,f,!1,!0)),!(!e[u]||e[u].length===0)&&e[u].filter(x).forEach(C)});async function se(e,t){!v(e)||!x(e)||(await t(e),C(e))}function ce(e){return y(e),!e[f]}const w=b(function(e,t){y(e),e[f]||(e[f]=!0,S(e,f,!0,!1)),e[m]&&w(e[m],e[h])});function T(e,t,n){t[u]??=[],!t[u].includes(e)&&t[u].push(e),e[m]!==t&&(e[m]=t),e[h]!==n&&(e[h]=n)}function E(e,t,n){if(v(n))T(n,e,t);else if(Array.isArray(n)){for(let r of n)v(r)&&T(r,e,t);n[m]=e,n[h]=t}}function le(e,t){let n=e[re];n(e,t)}function D(e,t){if(u in t){let n=t[u].indexOf(e);n!==-1&&t[u].splice(n,1)}e[m]=void 0,e[h]=void 0}function ue(e,t){if(v(t))D(t,e);else if(Array.isArray(t)){for(let n of t)v(n)&&D(n,e);t[m]=void 0,t[h]=void 0}}const O={};var k={deleteProperty(e,t){if(Reflect.deleteProperty(e,t),A(e,t))return!0;let n=e[m];return n&&S(n,e[h],n[e[h]]),n&&w(n,e[h]),!0},get(e,t,n){if(t===_)return!0;if(A(e,t))return Reflect.get(e,t,n);let r=e[m];return r&&le(r,e[h]),Reflect.get(e,t)},set(e,t,n,r){if(A(e,t))return Reflect.set(e,t,n,r);let i=e[m];return i&&S(i,e[h],i[e[h]]),i&&w(i,e[h]),Reflect.set(e,t,n)}};function A(e,t){return typeof t==`symbol`||typeof e[t]==`function`||t===`length`}var de={get(e,t,n){if(t===_)return!0;if(typeof t==`symbol`)return Reflect.get(e,t,n);let r=e[d][t];if(!r||!r.get)return Reflect.get(e,t,n);let i=r.get.call(e);return le(e,t),E(e,t,i),i},getOwnPropertyDescriptor(e,t){return e[d][t]},ownKeys(e){return e[g]},set(e,t,n,r){if(typeof t==`symbol`)return Reflect.set(e,t,n,r);let i=e[d][t];if(!i||!i.set)return Reflect.set(e,t,n,r);let a=i.get?.call(e)??void 0;return ne(n,a)?!0:(ue(e,a),Array.isArray(n)&&!n[_]&&(n=new Proxy(n,k)),i.set.call(e,n),E(e,t,n),w(e,t),S(e,t,n,a),!0)}},fe={get(e,t,n){return t===`__v_isRef`?!1:t===_?!0:t in e?Reflect.get(e,t,n):Reflect.get(e.value,t)},getOwnPropertyDescriptor(e,t){return Reflect.getOwnPropertyDescriptor(e.value,t)},ownKeys(e){return Reflect.ownKeys(e.value)},set(e,t,n,r){return t in e?Reflect.set(e,t,n,r):Reflect.set(e.value,t,n)}},pe={construct(e,t,n){t=t.map(e=>Array.isArray(e)?new Proxy(e,k):e);let r=a((r,i)=>{let a=o(Reflect.construct(e,t,n));a[l]=t,a[f]=!1,a[re]=r,a[ie]=i;let s=new Proxy(a,de);return{get:()=>(r(),s),set:()=>void 0}});return new Proxy(r,fe)}};function me(){let e=this;y(e);let t=O[e[p]],n=new t(...e[l]);for(let[e,t]of Object.entries(this[d]))t.set&&(n[e]=v(this[e])?this[e].clone():this[e]);return n}function he(e){for(let t in e){let n=this[d][t];v(this[t])&&typeof e[t]==`object`?this[t].fill(e[t]):n&&n.set&&(this[t]=e[t])}}function ge(){let e={};for(let t of this[g]){let n=this[t];v(n)&&(n=n.toJSON()),e[t]=n}return e}function j(e){ve(e);let t=Object.freeze(n(e)),a=Object.keys(t);return i(e.prototype,d,t),i(e.prototype,p,e.name),i(e.prototype,g,a),i(e,Symbol.hasInstance,t=>typeof t==`object`&&t?.[p]===e.name),r(e,`clone`,me),r(e,`fill`,he),r(e,`toJSON`,ge),_e(e)}function _e(e){let t=new Proxy(e,pe);return O[e.name]=t,t}function ve(e){let t=Object.getPrototypeOf(e.prototype);if(p in t)throw Error(`⛔️ @dto ${e.name} cannot extend parent class which is also decorated with @dto ${t[p]}.`)}function M(e){return e.map(F)}function ye([,t]){return e.fromISO(t)}function N(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,F(t)]).filter(([,e])=>e!==void 0))}const P={};function be([,e,t,n,r]){if(!(t in O))throw Error(`Cannot restore @dto. Dto ${t} was not found.`);if(e in P)return P[e];let i=O[t],a=new i(...M(r));return a.fill(N(n)),P[e]=a,a}function xe(e){return Array.isArray(e)&&e[0]===3058}function Se(e){return Array.isArray(e)&&e[0]===3057}function F(e){switch(!0){case e===null:return null;case Array.isArray(e):switch(!0){case xe(e):return ye(e);case Se(e):return be(e);default:return M(e)}case typeof e==`object`:return N(e);default:return e}}function Ce(e){return F(JSON.parse(e))}function we(e){return[3058,e.toISO({extendedZone:!0,includeOffset:!0})]}function I(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,z(t)]).filter(([,e])=>e!==void 0))}function Te(){return`10000000-1000-4000-8000-100000000000`.replace(/[018]/g,e=>(e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>e/4).toString(16))}function L(e){e=s(e);let t=e.toJSON();return[3057,Te(),e[p],I(t),R(e[l])]}function R(t){switch(!0){case t.every(v):return t.map(L);case t.every(e.isDateTime):return t.map(we);default:return t.map(z)}}function z(t){switch(!0){case t===null:return null;case Array.isArray(t):return R(t);case v(t):return L(t);case e.isDateTime(t):return we(t);case typeof t==`object`:return I(t);case typeof t==`boolean`:case typeof t==`number`:case typeof t==`string`:return t;default:return}}function Ee(e){return JSON.stringify(z(e))}function B(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}let V=class{get blob(){return this.#e}get name(){return this.#t}#e;#t;constructor(e,t){this.#e=e,this.#t=t}};V=B([j],V);var H=V;let U=class{get items(){return this.#e}get page(){return this.#t}get pageSize(){return this.#n}get pages(){return this.#r}get total(){return this.#i}#e;#t;#n;#r;#i;constructor(e,t,n,r,i){this.#e=e,this.#t=t,this.#n=n,this.#r=r,this.#i=i}};U=B([j],U);var W=U;let G=class{get code(){return this.#e}get error(){return this.#t}get errorDescription(){return this.#n}get statusCode(){return this.#r}#e;#t;#n;#r;constructor(e,t,n,r){this.#e=e,this.#t=t,this.#n=n,this.#r=r}};G=B([j],G);var K=G;let q=class{get code(){return this.#e}get error(){return this.#t}get errorDescription(){return this.#n}get errors(){return this.#r}get params(){return this.#i}#e;#t;#n;#r;#i;constructor(e,t,n,r,i){this.#e=e,this.#t=t,this.#n=n,this.#r=r,this.#i=i}};q=B([j],q);var J=q,Y;let X=Y=class{static parsePaginatedAdapter(e,t){return new W(e.items.map(t),e.page,e.page_size,e.pages,e.total)}static parseFileNameFromContentDispositionHeader(t){let n=`download-${e.now().toFormat(`yyyy-MM-dd HH-mm-ss`)}`;if(!t.startsWith(`attachment`))return n;let r=/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(t);return(r?.length||0)<2?n:r[1].replaceAll(`'`,``).replaceAll(`"`,``).replaceAll(`/`,`-`).replaceAll(`:`,`-`)}static parseRequestError(e,t){return new K(e.code,e.error,e.error_description,t)}static parseValidationError(e){let t;return e.errors&&(t={},Object.entries(e.errors).forEach(([e,n])=>{t[e]=Y.parseValidationError(n)})),new J(e.code,e.error,e.error_description,t,e.params)}};X=Y=B([c],X);var Z=class{get data(){return this.#e}get headers(){return this.#t.headers}get ok(){return this.statusCode>=200&&this.statusCode<300}get response(){return this.#t}get statusCode(){return this.#t.status}#e;#t;constructor(e,t){this.#e=e,this.#t=t}},De=class e{get authToken(){return this.#e}set authToken(e){this.#e=e}get baseUrl(){return this.#t}get dataField(){return this.#n}#e;#t;#n;constructor(e,t,n=!1){this.#e=e,this.#t=t,this.#n=n}static get instance(){if(e.#r===null)throw Error(`There is currently no HttpClient instance registered. Register one using the HttpClient.register() function.`);return e.#r}static#r=null;static register(t){e.#r=t}},Q=class extends Error{};const $={};var Oe=class t{get client(){return this.#e}get options(){return this.#r}get path(){return this.#n}set path(e){this.#n=e}get query(){return this.#i}set query(e){this.#i=e}#e;#t=null;#n;#r={};#i=null;constructor(e,t){this.#e=t??De.instance,this.#r.cache=`no-cache`,this.#r.method=`GET`,this.#n=e}autoCancel(e){return this.#t=e,this}bearerToken(e){return e??=this.#e.authToken,e?this.header(`Authorization`,`Bearer ${e}`):(this.#r.headers&&`Authorization`in this.#r.headers&&delete this.#r.headers.Authorization,this)}body(e,t=`application/octet-stream`){return e instanceof FormData?t=null:(Array.isArray(e)||typeof e==`object`)&&(e=JSON.stringify(e),t=`application/json`),this.#r.body=e,t===null?this:this.header(`Content-Type`,t)}header(e,t){return this.#r.headers=this.#r.headers||{},this.#r.headers[e]=t,this}method(e){return this.#r.method=e.toUpperCase(),this}queryString(e){return this.#i=e,this}signal(e=null){return this.#r.signal=e,this}async fetch(){return this.#a().then(e=>e.json())}async fetchBlob(){let t=await this.#a();if(t.status!==200){let e=await t.json();throw`code`in e&&`error`in e&&`error_description`in e?new K(e.code,e.error,e.error_description,t.status):new K(-1,`failed_without_info`,`Request failed without any information from the backend.`,t.status)}let n=t.headers.has(`content-disposition`)?X.parseFileNameFromContentDispositionHeader(t.headers.get(`content-disposition`)??``):`download-${e.now().toFormat(`yyyy-MM-dd HH-mm-ss`)}`;return new H(await t.blob(),n)}async run(){let{data:e,response:t}=await this.#o();return new Z(e,t)}async runAdapter(e){let{data:t,response:n}=await this.#o();return new Z(e(t),n)}async runArrayAdapter(e){return this.runAdapter(t=>t.map(e))}async runEmpty(){return await this.#o()}async runPaginatedAdapter(e){return this.runAdapter(t=>X.parsePaginatedAdapter(t,e))}async runData(){return await this.#o()}async runDataKey(e){let{data:t,response:n}=await this.#o();return new Z(t[e],n)}async runStatusCode(){return(await this.#o()).statusCode}async#a(){if(this.#t!==null){this.#t in $&&$[this.#t].abort(new Q);let e=new AbortController;$[this.#t]=e,this.signal(e.signal)}let e=this.path;this.query!==null&&(e+=`?${this.query.build()}`);let t=await fetch(this.client.baseUrl+e,this.options);return this.#t!==null&&delete $[this.#t],t}async#o(){return await this.#a().then(e=>t.#s(e,this.client.dataField))}static async#s(e,t){if(e.status===204)return new Z(null,e);if(e.headers.has(`content-type`)&&e.headers.get(`content-type`)?.startsWith(`application/json`)){let n=await e.json();if(n&&typeof n==`object`&&`code`in n&&`error`in n&&`error_description`in n)throw`errors`in n?X.parseValidationError(n):X.parseRequestError(n,e.status);return t&&`data`in n?new Z(n.data,e):new Z(n,e)}if(e.status===401||e.status===403||(await e.text()).length===0&&e.status>=200&&e.status<300)return new Z(null,e);throw new K(-1,`not_a_json_response`,`The response was not a JSON response.`,e.status)}},ke=class{request(e,t){return new Oe(e,t)}},Ae=class e{#e;constructor(){this.#e=new URLSearchParams}build(){return this.#e.toString()}append(e,t){return this.#t(this.#e.append.bind(this.#e),e,t)}appendArray(e,t){return t?.forEach(t=>this.append(e,t)),this}delete(e){return this.#e.delete(e),this}get(e){return this.#e.get(e)}getAll(e){return this.#e.getAll(e)}has(e){return this.#e.has(e)}set(e,t){return this.#t(this.#e.set.bind(this.#e),e,t)}#t(e,t,n){if(!n&&n!==!1)return this;switch(typeof n){case`boolean`:e(t,n?`true`:`false`);break;case`number`:e(t,n.toString(10));break;case`string`:e(t,n);break}return this}static builder(){return new e}};function je(e){return e instanceof Q}function Me(e){return e instanceof K}function Ne(e){return e instanceof K&&(e=e.statusCode),e===403||e===401}function Pe(e){return e instanceof J}export{Z as BaseResponse,ke as BaseService,H as BlobResponse,X as HttpAdapter,De as HttpClient,W as Paginated,Ae as QueryString,Q as RequestAbortedError,Oe as RequestBuilder,K as RequestError,J as ValidationError,c as adapter,y as assertDto,ee as bound,oe as cloneDto,te as debounce,Ce as deserialize,j as dto,se as executeIfDtoDirtyAndMarkClean,v as isDto,ce as isDtoClean,x as isDtoDirty,je as isRequestAborted,Me as isRequestError,Ne as isUnsanctionedRequest,Pe as isValidationError,C as markDtoClean,w as markDtoDirty,Ee as serialize};
|
|
1
|
+
import { DateTime } from "luxon";
|
|
2
|
+
import { debounce, getPrototypeChain, setObjectMethod, setObjectValue } from "@basmilius/utils";
|
|
3
|
+
import { customRef, markRaw, toRaw } from "vue";
|
|
4
|
+
//#region src/decorator/adapter.ts
|
|
5
|
+
function adapter_default(Parent) {
|
|
6
|
+
return class extends Parent {
|
|
7
|
+
constructor(...args) {
|
|
8
|
+
throw new Error("@adapter: cannot create instance of class.");
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/decorator/bound.ts
|
|
14
|
+
function bound_default() {
|
|
15
|
+
return (target, method) => {
|
|
16
|
+
target[method] = target[method].bind(target);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/decorator/debounce.ts
|
|
21
|
+
function debounce_default(interval) {
|
|
22
|
+
return (target, _, descriptor) => {
|
|
23
|
+
descriptor.value = debounce(descriptor.value, interval, target);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/decorator/dto/const.ts
|
|
28
|
+
const SERIALIZED_DATETIME = 3058;
|
|
29
|
+
const SERIALIZED_DTO = 3057;
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/decorator/dto/helper/areEqual.ts
|
|
32
|
+
/**
|
|
33
|
+
* Checks if the two given values are equal. When both values are a
|
|
34
|
+
* dto, the check is done by firstly converthing them to JSON.
|
|
35
|
+
*/
|
|
36
|
+
function areEqual_default(a, b) {
|
|
37
|
+
if (a === b) return true;
|
|
38
|
+
return a === b;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/decorator/dto/symbols.ts
|
|
42
|
+
const ARGS = Symbol();
|
|
43
|
+
const CHILDREN = Symbol();
|
|
44
|
+
const DESCRIPTORS = Symbol();
|
|
45
|
+
const DIRTY = Symbol();
|
|
46
|
+
const NAME = Symbol();
|
|
47
|
+
const PARENT = Symbol();
|
|
48
|
+
const PARENT_KEY = Symbol();
|
|
49
|
+
const PROPERTIES = Symbol();
|
|
50
|
+
const PROXY = Symbol();
|
|
51
|
+
const TRACK = Symbol();
|
|
52
|
+
const TRIGGER = Symbol();
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/decorator/dto/helper/isDto.ts
|
|
55
|
+
/**
|
|
56
|
+
* Checks if the given object is a dto.
|
|
57
|
+
*/
|
|
58
|
+
function isDto_default(obj) {
|
|
59
|
+
return obj && typeof obj === "object" && !!obj[NAME];
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/decorator/dto/helper/assertDto.ts
|
|
63
|
+
/**
|
|
64
|
+
* Asserts that the given object is a dto.
|
|
65
|
+
*/
|
|
66
|
+
function assertDto_default(obj) {
|
|
67
|
+
if (!isDto_default(obj)) throw new Error("@dto assert given object is not a class decorated with @Dto.");
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/decorator/dto/helper/circularProtect.ts
|
|
71
|
+
const CIRCULAR_MAP = Symbol();
|
|
72
|
+
function circularProtect_default(fn, arg1 = 0, arg2) {
|
|
73
|
+
return function(...args) {
|
|
74
|
+
const map = fn[CIRCULAR_MAP] ??= /* @__PURE__ */ new WeakMap();
|
|
75
|
+
const primary = args[arg1];
|
|
76
|
+
const secondary = arg2 !== void 0 ? args[arg2] : "self";
|
|
77
|
+
if (typeof primary !== "object" || primary === null) return fn.call(this, ...args);
|
|
78
|
+
if (!map.has(primary)) map.set(primary, []);
|
|
79
|
+
const visited = map.get(primary);
|
|
80
|
+
if (visited.includes(secondary)) return;
|
|
81
|
+
visited.push(secondary);
|
|
82
|
+
try {
|
|
83
|
+
return fn.call(this, ...args);
|
|
84
|
+
} finally {
|
|
85
|
+
const index = visited.lastIndexOf(secondary);
|
|
86
|
+
if (index !== -1) visited.splice(index, 1);
|
|
87
|
+
if (visited.length === 0) map.delete(primary);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/decorator/dto/helper/cloneDto.ts
|
|
93
|
+
/**
|
|
94
|
+
* Clones the given dto.
|
|
95
|
+
*/
|
|
96
|
+
function cloneDto_default(obj) {
|
|
97
|
+
assertDto_default(obj);
|
|
98
|
+
return obj.clone();
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/decorator/dto/helper/isDtoDirty.ts
|
|
102
|
+
/**
|
|
103
|
+
* Checks if the given dto is dirty.
|
|
104
|
+
*/
|
|
105
|
+
function isDtoDirty_default(obj) {
|
|
106
|
+
assertDto_default(obj);
|
|
107
|
+
return obj[DIRTY];
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/decorator/dto/helper/triggerDto.ts
|
|
111
|
+
/**
|
|
112
|
+
* Trigger for when a dto property is being updated.
|
|
113
|
+
*/
|
|
114
|
+
const triggerDto = circularProtect_default(function(dto, key, value, oldValue) {
|
|
115
|
+
const trigger = dto[TRIGGER];
|
|
116
|
+
trigger(dto, key, value, oldValue);
|
|
117
|
+
dto[PARENT] && triggerDto(dto[PARENT], dto[PARENT_KEY], dto[PARENT][dto[PARENT_KEY]]);
|
|
118
|
+
}, 0, 1);
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region src/decorator/dto/helper/markDtoClean.ts
|
|
121
|
+
/**
|
|
122
|
+
* Marks the given dto clean.
|
|
123
|
+
*/
|
|
124
|
+
const markDtoClean = circularProtect_default(function(obj) {
|
|
125
|
+
assertDto_default(obj);
|
|
126
|
+
if (obj[DIRTY]) {
|
|
127
|
+
obj[DIRTY] = false;
|
|
128
|
+
triggerDto(obj, DIRTY, false, true);
|
|
129
|
+
}
|
|
130
|
+
if (!obj[CHILDREN] || obj[CHILDREN].length === 0) return;
|
|
131
|
+
obj[CHILDREN].filter(isDtoDirty_default).forEach(markDtoClean);
|
|
132
|
+
});
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/decorator/dto/helper/executeIfDtoDirtyAndMarkClean.ts
|
|
135
|
+
/**
|
|
136
|
+
* Executes the given function if the given dto is marked dirty.
|
|
137
|
+
*/
|
|
138
|
+
async function executeIfDtoDirtyAndMarkClean_default(obj, fn) {
|
|
139
|
+
if (!isDto_default(obj) || !isDtoDirty_default(obj)) return;
|
|
140
|
+
await fn(obj);
|
|
141
|
+
markDtoClean(obj);
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region src/decorator/dto/helper/isDtoClean.ts
|
|
145
|
+
/**
|
|
146
|
+
* Checks if the given dto is clean.
|
|
147
|
+
*/
|
|
148
|
+
function isDtoClean_default(obj) {
|
|
149
|
+
assertDto_default(obj);
|
|
150
|
+
return !obj[DIRTY];
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region src/decorator/dto/helper/markDtoDirty.ts
|
|
154
|
+
/**
|
|
155
|
+
* Marks the given dto dirty.
|
|
156
|
+
*/
|
|
157
|
+
const markDtoDirty = circularProtect_default(function(obj, key) {
|
|
158
|
+
assertDto_default(obj);
|
|
159
|
+
if (!obj[DIRTY]) {
|
|
160
|
+
obj[DIRTY] = true;
|
|
161
|
+
triggerDto(obj, DIRTY, true, false);
|
|
162
|
+
}
|
|
163
|
+
if (!obj[PARENT]) return;
|
|
164
|
+
markDtoDirty(obj[PARENT], obj[PARENT_KEY]);
|
|
165
|
+
});
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/decorator/dto/helper/relateDtoTo.ts
|
|
168
|
+
/**
|
|
169
|
+
* Creates a parent-child relationship between the given two dtos.
|
|
170
|
+
*/
|
|
171
|
+
function relateDtoTo_default(dto, parent, key) {
|
|
172
|
+
parent[CHILDREN] ??= [];
|
|
173
|
+
!parent[CHILDREN].includes(dto) && parent[CHILDREN].push(dto);
|
|
174
|
+
dto[PARENT] !== parent && (dto[PARENT] = parent);
|
|
175
|
+
dto[PARENT_KEY] !== key && (dto[PARENT_KEY] = key);
|
|
176
|
+
}
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region src/decorator/dto/helper/relateValueTo.ts
|
|
179
|
+
/**
|
|
180
|
+
* Creates relationships between the given value and dto.
|
|
181
|
+
*/
|
|
182
|
+
function relateValueTo_default(dto, key, value) {
|
|
183
|
+
if (isDto_default(value)) relateDtoTo_default(value, dto, key);
|
|
184
|
+
else if (Array.isArray(value)) {
|
|
185
|
+
for (const item of value) {
|
|
186
|
+
if (!isDto_default(item)) continue;
|
|
187
|
+
relateDtoTo_default(item, dto, key);
|
|
188
|
+
}
|
|
189
|
+
value[PARENT] = dto;
|
|
190
|
+
value[PARENT_KEY] = key;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/decorator/dto/helper/trackDto.ts
|
|
195
|
+
/**
|
|
196
|
+
* Tracking for when a dto property is being accessed.
|
|
197
|
+
*/
|
|
198
|
+
function trackDto(dto, key) {
|
|
199
|
+
const track = dto[TRACK];
|
|
200
|
+
track(dto, key);
|
|
201
|
+
}
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region src/decorator/dto/helper/unrelateDtoFrom.ts
|
|
204
|
+
/**
|
|
205
|
+
* Removes a parent-child relationship between the given two dtos.
|
|
206
|
+
*/
|
|
207
|
+
function unrelateDtoFrom_default(dto, parent) {
|
|
208
|
+
if (CHILDREN in parent) {
|
|
209
|
+
const index = parent[CHILDREN].indexOf(dto);
|
|
210
|
+
if (index !== -1) parent[CHILDREN].splice(index, 1);
|
|
211
|
+
}
|
|
212
|
+
dto[PARENT] = void 0;
|
|
213
|
+
dto[PARENT_KEY] = void 0;
|
|
214
|
+
}
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/decorator/dto/helper/unrelateValueFrom.ts
|
|
217
|
+
/**
|
|
218
|
+
* Removes relationships between the given value and dto.
|
|
219
|
+
*/
|
|
220
|
+
function unrelateValueFrom_default(dto, value) {
|
|
221
|
+
if (isDto_default(value)) unrelateDtoFrom_default(value, dto);
|
|
222
|
+
else if (Array.isArray(value)) {
|
|
223
|
+
for (const item of value) if (isDto_default(item)) unrelateDtoFrom_default(item, dto);
|
|
224
|
+
value[PARENT] = void 0;
|
|
225
|
+
value[PARENT_KEY] = void 0;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//#endregion
|
|
229
|
+
//#region src/decorator/dto/map.ts
|
|
230
|
+
const DTO_CLASS_MAP = {};
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/decorator/dto/arrayProxy.ts
|
|
233
|
+
var arrayProxy_default = {
|
|
234
|
+
/**
|
|
235
|
+
* Trap for when a property is deleted from the target. This
|
|
236
|
+
* will mark the parent dto as dirty and trigger an update.
|
|
237
|
+
*/
|
|
238
|
+
deleteProperty(target, key) {
|
|
239
|
+
Reflect.deleteProperty(target, key);
|
|
240
|
+
if (ignored(target, key)) return true;
|
|
241
|
+
const dto = target[PARENT];
|
|
242
|
+
dto && triggerDto(dto, target[PARENT_KEY], dto[target[PARENT_KEY]]);
|
|
243
|
+
dto && markDtoDirty(dto, target[PARENT_KEY]);
|
|
244
|
+
return true;
|
|
245
|
+
},
|
|
246
|
+
/**
|
|
247
|
+
* Trap for when a property of the target is being accessed. The
|
|
248
|
+
* property access is being tracked for further updates.
|
|
249
|
+
*/
|
|
250
|
+
get(target, key, receiver) {
|
|
251
|
+
if (key === PROXY) return true;
|
|
252
|
+
if (ignored(target, key)) return Reflect.get(target, key, receiver);
|
|
253
|
+
const dto = target[PARENT];
|
|
254
|
+
dto && trackDto(dto, target[PARENT_KEY]);
|
|
255
|
+
return Reflect.get(target, key);
|
|
256
|
+
},
|
|
257
|
+
/**
|
|
258
|
+
* Trap for when a property of the target is being updated. This
|
|
259
|
+
* will mark the parent dto as dirty and trigger an update.
|
|
260
|
+
*/
|
|
261
|
+
set(target, key, value, receiver) {
|
|
262
|
+
if (ignored(target, key)) return Reflect.set(target, key, value, receiver);
|
|
263
|
+
const dto = target[PARENT];
|
|
264
|
+
dto && triggerDto(dto, target[PARENT_KEY], dto[target[PARENT_KEY]]);
|
|
265
|
+
dto && markDtoDirty(dto, target[PARENT_KEY]);
|
|
266
|
+
return Reflect.set(target, key, value);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
/**
|
|
270
|
+
* Checks if the given key should be ignored by the proxy.
|
|
271
|
+
*/
|
|
272
|
+
function ignored(target, key) {
|
|
273
|
+
return typeof key === "symbol" || typeof target[key] === "function" || key === "length";
|
|
274
|
+
}
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region src/decorator/dto/instanceProxy.ts
|
|
277
|
+
var instanceProxy_default = {
|
|
278
|
+
/**
|
|
279
|
+
* Trap for when a dto property is being accessed. The property
|
|
280
|
+
* access is being tracked for further updates. If the dto has
|
|
281
|
+
* any child dtos, a relationship will be added between them.
|
|
282
|
+
*/
|
|
283
|
+
get(target, key, receiver) {
|
|
284
|
+
if (key === PROXY) return true;
|
|
285
|
+
if (typeof key === "symbol") return Reflect.get(target, key, receiver);
|
|
286
|
+
const descriptor = target[DESCRIPTORS][key];
|
|
287
|
+
if (!descriptor || !descriptor.get) return Reflect.get(target, key, receiver);
|
|
288
|
+
const value = descriptor.get.call(target);
|
|
289
|
+
trackDto(target, key);
|
|
290
|
+
relateValueTo_default(target, key, value);
|
|
291
|
+
return value;
|
|
292
|
+
},
|
|
293
|
+
/**
|
|
294
|
+
* Trap for when a descriptor of a dto property is requested.
|
|
295
|
+
*/
|
|
296
|
+
getOwnPropertyDescriptor(target, key) {
|
|
297
|
+
return target[DESCRIPTORS][key];
|
|
298
|
+
},
|
|
299
|
+
/**
|
|
300
|
+
* Trap for when the keys of a dto are requested.
|
|
301
|
+
*/
|
|
302
|
+
ownKeys(target) {
|
|
303
|
+
return target[PROPERTIES];
|
|
304
|
+
},
|
|
305
|
+
/**
|
|
306
|
+
* Trap for when a dto property is being updated. This will
|
|
307
|
+
* mark the dto dirty and trigger an update. If an array is
|
|
308
|
+
* passed, that array will be made reactive as well.
|
|
309
|
+
*/
|
|
310
|
+
set(target, key, value, receiver) {
|
|
311
|
+
if (typeof key === "symbol") return Reflect.set(target, key, value, receiver);
|
|
312
|
+
const descriptor = target[DESCRIPTORS][key];
|
|
313
|
+
if (!descriptor || !descriptor.set) return Reflect.set(target, key, value, receiver);
|
|
314
|
+
const oldValue = descriptor.get?.call(target) ?? void 0;
|
|
315
|
+
if (areEqual_default(value, oldValue)) return true;
|
|
316
|
+
unrelateValueFrom_default(target, oldValue);
|
|
317
|
+
if (Array.isArray(value) && !value[PROXY]) value = new Proxy(value, arrayProxy_default);
|
|
318
|
+
descriptor.set.call(target, value);
|
|
319
|
+
relateValueTo_default(target, key, value);
|
|
320
|
+
markDtoDirty(target, key);
|
|
321
|
+
triggerDto(target, key, value, oldValue);
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
//#endregion
|
|
326
|
+
//#region src/decorator/dto/refProxy.ts
|
|
327
|
+
var refProxy_default = {
|
|
328
|
+
/**
|
|
329
|
+
* Trap for when a ref property is being accessed. The property
|
|
330
|
+
* access is being tracked for further updates. If the requested
|
|
331
|
+
* property is not a part of {Ref}, the get is proxied to the
|
|
332
|
+
* underlying dto instance.
|
|
333
|
+
*
|
|
334
|
+
* A little trick with __v_isRef is done here, all the features
|
|
335
|
+
* of refs are used by our dto, but we don't want Vue to treat
|
|
336
|
+
* it as a ref. We return false here to trick Vue.
|
|
337
|
+
*/
|
|
338
|
+
get(target, key, receiver) {
|
|
339
|
+
if (key === "__v_isRef") return false;
|
|
340
|
+
if (key === PROXY) return true;
|
|
341
|
+
if (key in target) return Reflect.get(target, key, receiver);
|
|
342
|
+
return Reflect.get(target.value, key);
|
|
343
|
+
},
|
|
344
|
+
/**
|
|
345
|
+
* Trap for when a descriptor of a property is requested, that
|
|
346
|
+
* request is proxied to the underlying dto.
|
|
347
|
+
*/
|
|
348
|
+
getOwnPropertyDescriptor(target, key) {
|
|
349
|
+
return Reflect.getOwnPropertyDescriptor(target.value, key);
|
|
350
|
+
},
|
|
351
|
+
/**
|
|
352
|
+
* Trap for when the keys of the ref are requested, that request
|
|
353
|
+
* is proxied to the underlying dto.
|
|
354
|
+
*/
|
|
355
|
+
ownKeys(target) {
|
|
356
|
+
return Reflect.ownKeys(target.value);
|
|
357
|
+
},
|
|
358
|
+
/**
|
|
359
|
+
* Trap for when a ref property is being updated. If the property
|
|
360
|
+
* is not part of {Ref}, the set is proxied to the underlying dto
|
|
361
|
+
* instance. In that proxy, the dto will be marked dirty and an
|
|
362
|
+
* update is triggered.
|
|
363
|
+
*/
|
|
364
|
+
set(target, key, value, receiver) {
|
|
365
|
+
if (key in target) return Reflect.set(target, key, value, receiver);
|
|
366
|
+
return Reflect.set(target.value, key, value);
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/decorator/dto/classProxy.ts
|
|
371
|
+
var classProxy_default = {
|
|
372
|
+
/**
|
|
373
|
+
* Trap for when a dto is being constructed. Reactivity is provided
|
|
374
|
+
* to all arguments and a proxied custom ref is returned that references
|
|
375
|
+
* the actual dto instance.
|
|
376
|
+
*/
|
|
377
|
+
construct(target, argsArray, newTarget) {
|
|
378
|
+
argsArray = argsArray.map((arg) => {
|
|
379
|
+
if (!Array.isArray(arg)) return arg;
|
|
380
|
+
return new Proxy(arg, arrayProxy_default);
|
|
381
|
+
});
|
|
382
|
+
const ref = customRef((track, trigger) => {
|
|
383
|
+
const instance = markRaw(Reflect.construct(target, argsArray, newTarget));
|
|
384
|
+
instance[ARGS] = argsArray;
|
|
385
|
+
instance[DIRTY] = false;
|
|
386
|
+
instance[TRACK] = track;
|
|
387
|
+
instance[TRIGGER] = trigger;
|
|
388
|
+
const proxied = new Proxy(instance, instanceProxy_default);
|
|
389
|
+
return {
|
|
390
|
+
get: () => {
|
|
391
|
+
track();
|
|
392
|
+
return proxied;
|
|
393
|
+
},
|
|
394
|
+
set: () => void 0
|
|
395
|
+
};
|
|
396
|
+
});
|
|
397
|
+
return new Proxy(ref, refProxy_default);
|
|
398
|
+
} };
|
|
399
|
+
//#endregion
|
|
400
|
+
//#region src/decorator/dto/clone.ts
|
|
401
|
+
/**
|
|
402
|
+
* Returns a clone of the dto.
|
|
403
|
+
*/
|
|
404
|
+
function clone_default() {
|
|
405
|
+
const instance = this;
|
|
406
|
+
assertDto_default(instance);
|
|
407
|
+
const clazz = DTO_CLASS_MAP[instance[NAME]];
|
|
408
|
+
const clone = new clazz(...instance[ARGS]);
|
|
409
|
+
for (const [key, descriptor] of Object.entries(this[DESCRIPTORS])) {
|
|
410
|
+
if (!descriptor.set) continue;
|
|
411
|
+
clone[key] = isDto_default(this[key]) ? this[key].clone() : this[key];
|
|
412
|
+
}
|
|
413
|
+
return clone;
|
|
414
|
+
}
|
|
415
|
+
//#endregion
|
|
416
|
+
//#region src/decorator/dto/fill.ts
|
|
417
|
+
/**
|
|
418
|
+
* Fills the dto with the given data.
|
|
419
|
+
*/
|
|
420
|
+
function fill_default(data) {
|
|
421
|
+
for (let key in data) {
|
|
422
|
+
const descriptor = this[DESCRIPTORS][key];
|
|
423
|
+
if (isDto_default(this[key]) && typeof data[key] === "object") this[key].fill(data[key]);
|
|
424
|
+
else if (descriptor && descriptor.set) this[key] = data[key];
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
//#endregion
|
|
428
|
+
//#region src/decorator/dto/toJSON.ts
|
|
429
|
+
/**
|
|
430
|
+
* Returns the json object representation of the dto.
|
|
431
|
+
*/
|
|
432
|
+
function toJSON_default() {
|
|
433
|
+
const result = {};
|
|
434
|
+
for (const property of this[PROPERTIES]) {
|
|
435
|
+
let value = this[property];
|
|
436
|
+
if (isDto_default(value)) value = value.toJSON();
|
|
437
|
+
result[property] = value;
|
|
438
|
+
}
|
|
439
|
+
return result;
|
|
440
|
+
}
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/decorator/dto/index.ts
|
|
443
|
+
/**
|
|
444
|
+
* Provides reactivity to the decorated class.
|
|
445
|
+
*/
|
|
446
|
+
function dto_default(clazz) {
|
|
447
|
+
validate(clazz);
|
|
448
|
+
const descriptors = Object.freeze(getPrototypeChain(clazz));
|
|
449
|
+
const properties = Object.keys(descriptors);
|
|
450
|
+
setObjectValue(clazz.prototype, DESCRIPTORS, descriptors);
|
|
451
|
+
setObjectValue(clazz.prototype, NAME, clazz.name);
|
|
452
|
+
setObjectValue(clazz.prototype, PROPERTIES, properties);
|
|
453
|
+
setObjectValue(clazz, Symbol.hasInstance, (instance) => typeof instance === "object" && instance?.[NAME] === clazz.name);
|
|
454
|
+
setObjectMethod(clazz, "clone", clone_default);
|
|
455
|
+
setObjectMethod(clazz, "fill", fill_default);
|
|
456
|
+
setObjectMethod(clazz, "toJSON", toJSON_default);
|
|
457
|
+
return proxy(clazz);
|
|
458
|
+
}
|
|
459
|
+
function proxy(clazz) {
|
|
460
|
+
const proxied = new Proxy(clazz, classProxy_default);
|
|
461
|
+
DTO_CLASS_MAP[clazz.name] = proxied;
|
|
462
|
+
return proxied;
|
|
463
|
+
}
|
|
464
|
+
function validate(clazz) {
|
|
465
|
+
const parent = Object.getPrototypeOf(clazz.prototype);
|
|
466
|
+
if (NAME in parent) throw new Error(`⛔️ @dto ${clazz.name} cannot extend parent class which is also decorated with @dto ${parent[NAME]}.`);
|
|
467
|
+
}
|
|
468
|
+
//#endregion
|
|
469
|
+
//#region src/decorator/dto/serialize/deserializeArray.ts
|
|
470
|
+
function deserializeArray_default(obj) {
|
|
471
|
+
return obj.map(deserializeUnknown_default);
|
|
472
|
+
}
|
|
473
|
+
//#endregion
|
|
474
|
+
//#region src/decorator/dto/serialize/deserializeDateTime.ts
|
|
475
|
+
function deserializeDateTime_default([, iso]) {
|
|
476
|
+
return DateTime.fromISO(iso);
|
|
477
|
+
}
|
|
478
|
+
//#endregion
|
|
479
|
+
//#region src/decorator/dto/serialize/deserializeObject.ts
|
|
480
|
+
function deserializeObject_default(obj) {
|
|
481
|
+
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, deserializeUnknown_default(value)]).filter(([, value]) => value !== void 0));
|
|
482
|
+
}
|
|
483
|
+
//#endregion
|
|
484
|
+
//#region src/decorator/dto/serialize/deserializeDto.ts
|
|
485
|
+
const CACHE = {};
|
|
486
|
+
function deserializeDto_default([, id, name, state, args]) {
|
|
487
|
+
if (!(name in DTO_CLASS_MAP)) throw new Error(`Cannot restore @dto. Dto ${name} was not found.`);
|
|
488
|
+
if (id in CACHE) return CACHE[id];
|
|
489
|
+
const Dto = DTO_CLASS_MAP[name];
|
|
490
|
+
const instance = new Dto(...deserializeArray_default(args));
|
|
491
|
+
instance.fill(deserializeObject_default(state));
|
|
492
|
+
CACHE[id] = instance;
|
|
493
|
+
return instance;
|
|
494
|
+
}
|
|
495
|
+
//#endregion
|
|
496
|
+
//#region src/decorator/dto/serialize/isSerializedDateTime.ts
|
|
497
|
+
function isSerializedDateTime_default(obj) {
|
|
498
|
+
return Array.isArray(obj) && obj[0] === 3058;
|
|
499
|
+
}
|
|
500
|
+
//#endregion
|
|
501
|
+
//#region src/decorator/dto/serialize/isSerializedDto.ts
|
|
502
|
+
function isSerializedDto_default(obj) {
|
|
503
|
+
return Array.isArray(obj) && obj[0] === 3057;
|
|
504
|
+
}
|
|
505
|
+
//#endregion
|
|
506
|
+
//#region src/decorator/dto/serialize/deserializeUnknown.ts
|
|
507
|
+
function deserializeUnknown_default(obj) {
|
|
508
|
+
switch (true) {
|
|
509
|
+
case obj === null: return null;
|
|
510
|
+
case Array.isArray(obj): switch (true) {
|
|
511
|
+
case isSerializedDateTime_default(obj): return deserializeDateTime_default(obj);
|
|
512
|
+
case isSerializedDto_default(obj): return deserializeDto_default(obj);
|
|
513
|
+
default: return deserializeArray_default(obj);
|
|
514
|
+
}
|
|
515
|
+
case typeof obj === "object": return deserializeObject_default(obj);
|
|
516
|
+
default: return obj;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
//#endregion
|
|
520
|
+
//#region src/decorator/dto/serialize/deserialize.ts
|
|
521
|
+
function deserialize_default(serialized) {
|
|
522
|
+
return deserializeUnknown_default(JSON.parse(serialized));
|
|
523
|
+
}
|
|
524
|
+
//#endregion
|
|
525
|
+
//#region src/decorator/dto/serialize/serializeDateTime.ts
|
|
526
|
+
function serializeDateTime_default(obj) {
|
|
527
|
+
return [SERIALIZED_DATETIME, obj.toISO({
|
|
528
|
+
extendedZone: true,
|
|
529
|
+
includeOffset: true
|
|
530
|
+
})];
|
|
531
|
+
}
|
|
532
|
+
//#endregion
|
|
533
|
+
//#region src/decorator/dto/serialize/serializeObject.ts
|
|
534
|
+
function serializeObject_default(obj) {
|
|
535
|
+
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, serializeUnknown_default(value)]).filter(([, value]) => value !== void 0));
|
|
536
|
+
}
|
|
537
|
+
//#endregion
|
|
538
|
+
//#region src/decorator/dto/serialize/uuid.ts
|
|
539
|
+
function uuid_default() {
|
|
540
|
+
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => (+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16));
|
|
541
|
+
}
|
|
542
|
+
//#endregion
|
|
543
|
+
//#region src/decorator/dto/serialize/serializeDto.ts
|
|
544
|
+
function serializeDto_default(obj) {
|
|
545
|
+
obj = toRaw(obj);
|
|
546
|
+
const json = obj.toJSON();
|
|
547
|
+
return [
|
|
548
|
+
SERIALIZED_DTO,
|
|
549
|
+
uuid_default(),
|
|
550
|
+
obj[NAME],
|
|
551
|
+
serializeObject_default(json),
|
|
552
|
+
serializeArray_default(obj[ARGS])
|
|
553
|
+
];
|
|
554
|
+
}
|
|
555
|
+
//#endregion
|
|
556
|
+
//#region src/decorator/dto/serialize/serializeArray.ts
|
|
557
|
+
function serializeArray_default(obj) {
|
|
558
|
+
switch (true) {
|
|
559
|
+
case obj.every(isDto_default): return obj.map(serializeDto_default);
|
|
560
|
+
case obj.every(DateTime.isDateTime): return obj.map(serializeDateTime_default);
|
|
561
|
+
default: return obj.map(serializeUnknown_default);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
//#endregion
|
|
565
|
+
//#region src/decorator/dto/serialize/serializeUnknown.ts
|
|
566
|
+
function serializeUnknown_default(obj) {
|
|
567
|
+
switch (true) {
|
|
568
|
+
case obj === null: return null;
|
|
569
|
+
case Array.isArray(obj): return serializeArray_default(obj);
|
|
570
|
+
case isDto_default(obj): return serializeDto_default(obj);
|
|
571
|
+
case DateTime.isDateTime(obj): return serializeDateTime_default(obj);
|
|
572
|
+
case typeof obj === "object": return serializeObject_default(obj);
|
|
573
|
+
case typeof obj === "boolean":
|
|
574
|
+
case typeof obj === "number":
|
|
575
|
+
case typeof obj === "string": return obj;
|
|
576
|
+
default: return;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
//#endregion
|
|
580
|
+
//#region src/decorator/dto/serialize/serialize.ts
|
|
581
|
+
function serialize_default(obj) {
|
|
582
|
+
return JSON.stringify(serializeUnknown_default(obj));
|
|
583
|
+
}
|
|
584
|
+
//#endregion
|
|
585
|
+
//#region \0@oxc-project+runtime@0.129.0/helpers/decorate.js
|
|
586
|
+
function __decorate(decorators, target, key, desc) {
|
|
587
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
588
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
589
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
590
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
591
|
+
}
|
|
592
|
+
//#endregion
|
|
593
|
+
//#region src/dto/BlobResponse.ts
|
|
594
|
+
let BlobResponse = class BlobResponse {
|
|
595
|
+
get blob() {
|
|
596
|
+
return this.#blob;
|
|
597
|
+
}
|
|
598
|
+
get name() {
|
|
599
|
+
return this.#name;
|
|
600
|
+
}
|
|
601
|
+
#blob;
|
|
602
|
+
#name;
|
|
603
|
+
constructor(blob, name) {
|
|
604
|
+
this.#blob = blob;
|
|
605
|
+
this.#name = name;
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
BlobResponse = __decorate([dto_default], BlobResponse);
|
|
609
|
+
var BlobResponse_default = BlobResponse;
|
|
610
|
+
//#endregion
|
|
611
|
+
//#region src/dto/Paginated.ts
|
|
612
|
+
let Paginated = class Paginated {
|
|
613
|
+
get items() {
|
|
614
|
+
return this.#items;
|
|
615
|
+
}
|
|
616
|
+
get page() {
|
|
617
|
+
return this.#page;
|
|
618
|
+
}
|
|
619
|
+
get pageSize() {
|
|
620
|
+
return this.#pageSize;
|
|
621
|
+
}
|
|
622
|
+
get pages() {
|
|
623
|
+
return this.#pages;
|
|
624
|
+
}
|
|
625
|
+
get total() {
|
|
626
|
+
return this.#total;
|
|
627
|
+
}
|
|
628
|
+
#items;
|
|
629
|
+
#page;
|
|
630
|
+
#pageSize;
|
|
631
|
+
#pages;
|
|
632
|
+
#total;
|
|
633
|
+
constructor(items, page, pageSize, pages, total) {
|
|
634
|
+
this.#items = items;
|
|
635
|
+
this.#page = page;
|
|
636
|
+
this.#pageSize = pageSize;
|
|
637
|
+
this.#pages = pages;
|
|
638
|
+
this.#total = total;
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
Paginated = __decorate([dto_default], Paginated);
|
|
642
|
+
var Paginated_default = Paginated;
|
|
643
|
+
//#endregion
|
|
644
|
+
//#region src/dto/RequestError.ts
|
|
645
|
+
let RequestError = class RequestError {
|
|
646
|
+
get code() {
|
|
647
|
+
return this.#code;
|
|
648
|
+
}
|
|
649
|
+
get error() {
|
|
650
|
+
return this.#error;
|
|
651
|
+
}
|
|
652
|
+
get errorDescription() {
|
|
653
|
+
return this.#errorDescription;
|
|
654
|
+
}
|
|
655
|
+
get statusCode() {
|
|
656
|
+
return this.#statusCode;
|
|
657
|
+
}
|
|
658
|
+
#code;
|
|
659
|
+
#error;
|
|
660
|
+
#errorDescription;
|
|
661
|
+
#statusCode;
|
|
662
|
+
constructor(code, error, errorDescription, statusCode) {
|
|
663
|
+
this.#code = code;
|
|
664
|
+
this.#error = error;
|
|
665
|
+
this.#errorDescription = errorDescription;
|
|
666
|
+
this.#statusCode = statusCode;
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
RequestError = __decorate([dto_default], RequestError);
|
|
670
|
+
var RequestError_default = RequestError;
|
|
671
|
+
//#endregion
|
|
672
|
+
//#region src/dto/ValidationError.ts
|
|
673
|
+
let ValidationError = class ValidationError {
|
|
674
|
+
get code() {
|
|
675
|
+
return this.#code;
|
|
676
|
+
}
|
|
677
|
+
get error() {
|
|
678
|
+
return this.#error;
|
|
679
|
+
}
|
|
680
|
+
get errorDescription() {
|
|
681
|
+
return this.#errorDescription;
|
|
682
|
+
}
|
|
683
|
+
get errors() {
|
|
684
|
+
return this.#errors;
|
|
685
|
+
}
|
|
686
|
+
get params() {
|
|
687
|
+
return this.#params;
|
|
688
|
+
}
|
|
689
|
+
#code;
|
|
690
|
+
#error;
|
|
691
|
+
#errorDescription;
|
|
692
|
+
#errors;
|
|
693
|
+
#params;
|
|
694
|
+
constructor(code, error, errorDescription, errors, params) {
|
|
695
|
+
this.#code = code;
|
|
696
|
+
this.#error = error;
|
|
697
|
+
this.#errorDescription = errorDescription;
|
|
698
|
+
this.#errors = errors;
|
|
699
|
+
this.#params = params;
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
ValidationError = __decorate([dto_default], ValidationError);
|
|
703
|
+
var ValidationError_default = ValidationError;
|
|
704
|
+
//#endregion
|
|
705
|
+
//#region src/adapter/HttpAdapter.ts
|
|
706
|
+
var _HttpAdapter;
|
|
707
|
+
let HttpAdapter = _HttpAdapter = class HttpAdapter {
|
|
708
|
+
static parsePaginatedAdapter(data, adapterMethod) {
|
|
709
|
+
return new Paginated_default(data.items.map(adapterMethod), data.page, data.page_size, data.pages, data.total);
|
|
710
|
+
}
|
|
711
|
+
static parseFileNameFromContentDispositionHeader(header) {
|
|
712
|
+
const defaultFilename = `download-${DateTime.now().toFormat("yyyy-MM-dd HH-mm-ss")}`;
|
|
713
|
+
if (!header.startsWith("attachment")) return defaultFilename;
|
|
714
|
+
const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(header);
|
|
715
|
+
if ((matches?.length || 0) < 2) return defaultFilename;
|
|
716
|
+
return matches[1].replaceAll("'", "").replaceAll("\"", "").replaceAll("/", "-").replaceAll(":", "-");
|
|
717
|
+
}
|
|
718
|
+
static parseRequestError(data, statusCode) {
|
|
719
|
+
return new RequestError_default(data.code, data.error, data.error_description, statusCode);
|
|
720
|
+
}
|
|
721
|
+
static parseValidationError(data) {
|
|
722
|
+
let errors;
|
|
723
|
+
if (data.errors) {
|
|
724
|
+
errors = {};
|
|
725
|
+
Object.entries(data.errors).forEach(([key, value]) => {
|
|
726
|
+
errors[key] = _HttpAdapter.parseValidationError(value);
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
return new ValidationError_default(data.code, data.error, data.error_description, errors, data.params);
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
HttpAdapter = _HttpAdapter = __decorate([adapter_default], HttpAdapter);
|
|
733
|
+
//#endregion
|
|
734
|
+
//#region src/http/BaseResponse.ts
|
|
735
|
+
var BaseResponse = class {
|
|
736
|
+
get data() {
|
|
737
|
+
return this.#data;
|
|
738
|
+
}
|
|
739
|
+
get headers() {
|
|
740
|
+
return this.#response.headers;
|
|
741
|
+
}
|
|
742
|
+
get ok() {
|
|
743
|
+
return this.statusCode >= 200 && this.statusCode < 300;
|
|
744
|
+
}
|
|
745
|
+
get response() {
|
|
746
|
+
return this.#response;
|
|
747
|
+
}
|
|
748
|
+
get statusCode() {
|
|
749
|
+
return this.#response.status;
|
|
750
|
+
}
|
|
751
|
+
#data;
|
|
752
|
+
#response;
|
|
753
|
+
constructor(data, response) {
|
|
754
|
+
this.#data = data;
|
|
755
|
+
this.#response = response;
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
//#endregion
|
|
759
|
+
//#region src/http/HttpClient.ts
|
|
760
|
+
var HttpClient = class HttpClient {
|
|
761
|
+
get authToken() {
|
|
762
|
+
return this.#authToken;
|
|
763
|
+
}
|
|
764
|
+
set authToken(value) {
|
|
765
|
+
this.#authToken = value;
|
|
766
|
+
}
|
|
767
|
+
get baseUrl() {
|
|
768
|
+
return this.#baseUrl;
|
|
769
|
+
}
|
|
770
|
+
get dataField() {
|
|
771
|
+
return this.#dataField;
|
|
772
|
+
}
|
|
773
|
+
#authToken;
|
|
774
|
+
#baseUrl;
|
|
775
|
+
#dataField;
|
|
776
|
+
constructor(authToken, baseUrl, dataField = false) {
|
|
777
|
+
this.#authToken = authToken;
|
|
778
|
+
this.#baseUrl = baseUrl;
|
|
779
|
+
this.#dataField = dataField;
|
|
780
|
+
}
|
|
781
|
+
static get instance() {
|
|
782
|
+
if (HttpClient.#instance === null) throw new Error("There is currently no HttpClient instance registered. Register one using the HttpClient.register() function.");
|
|
783
|
+
return HttpClient.#instance;
|
|
784
|
+
}
|
|
785
|
+
static #instance = null;
|
|
786
|
+
static register(client) {
|
|
787
|
+
HttpClient.#instance = client;
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
//#endregion
|
|
791
|
+
//#region src/http/RequestAbortedError.ts
|
|
792
|
+
var RequestAbortedError_default = class extends Error {};
|
|
793
|
+
//#endregion
|
|
794
|
+
//#region src/http/RequestBuilder.ts
|
|
795
|
+
const abortControllers = {};
|
|
796
|
+
var RequestBuilder = class RequestBuilder {
|
|
797
|
+
get client() {
|
|
798
|
+
return this.#client;
|
|
799
|
+
}
|
|
800
|
+
get options() {
|
|
801
|
+
return this.#options;
|
|
802
|
+
}
|
|
803
|
+
get path() {
|
|
804
|
+
return this.#path;
|
|
805
|
+
}
|
|
806
|
+
set path(value) {
|
|
807
|
+
this.#path = value;
|
|
808
|
+
}
|
|
809
|
+
get query() {
|
|
810
|
+
return this.#query;
|
|
811
|
+
}
|
|
812
|
+
set query(value) {
|
|
813
|
+
this.#query = value;
|
|
814
|
+
}
|
|
815
|
+
#client;
|
|
816
|
+
#autoCancelIdentifier = null;
|
|
817
|
+
#path;
|
|
818
|
+
#options = {};
|
|
819
|
+
#query = null;
|
|
820
|
+
constructor(path, client) {
|
|
821
|
+
this.#client = client ?? HttpClient.instance;
|
|
822
|
+
this.#options.cache = "no-cache";
|
|
823
|
+
this.#options.method = "GET";
|
|
824
|
+
this.#path = path;
|
|
825
|
+
}
|
|
826
|
+
autoCancel(identifier) {
|
|
827
|
+
this.#autoCancelIdentifier = identifier;
|
|
828
|
+
return this;
|
|
829
|
+
}
|
|
830
|
+
bearerToken(token) {
|
|
831
|
+
token = token ?? this.#client.authToken;
|
|
832
|
+
if (token) return this.header("Authorization", `Bearer ${token}`);
|
|
833
|
+
if (this.#options.headers && "Authorization" in this.#options.headers) delete this.#options.headers["Authorization"];
|
|
834
|
+
return this;
|
|
835
|
+
}
|
|
836
|
+
body(body, contentType = "application/octet-stream") {
|
|
837
|
+
if (body instanceof FormData) contentType = null;
|
|
838
|
+
else if (Array.isArray(body) || typeof body === "object") {
|
|
839
|
+
body = JSON.stringify(body);
|
|
840
|
+
contentType = "application/json";
|
|
841
|
+
}
|
|
842
|
+
this.#options.body = body;
|
|
843
|
+
if (contentType !== null) return this.header("Content-Type", contentType);
|
|
844
|
+
return this;
|
|
845
|
+
}
|
|
846
|
+
header(name, value) {
|
|
847
|
+
this.#options.headers = this.#options.headers || {};
|
|
848
|
+
this.#options.headers[name] = value;
|
|
849
|
+
return this;
|
|
850
|
+
}
|
|
851
|
+
method(method) {
|
|
852
|
+
this.#options.method = method.toUpperCase();
|
|
853
|
+
return this;
|
|
854
|
+
}
|
|
855
|
+
queryString(queryString) {
|
|
856
|
+
this.#query = queryString;
|
|
857
|
+
return this;
|
|
858
|
+
}
|
|
859
|
+
signal(signal = null) {
|
|
860
|
+
this.#options.signal = signal;
|
|
861
|
+
return this;
|
|
862
|
+
}
|
|
863
|
+
async fetch() {
|
|
864
|
+
return this.#execute().then((r) => r.json());
|
|
865
|
+
}
|
|
866
|
+
async fetchBlob() {
|
|
867
|
+
let response = await this.#execute();
|
|
868
|
+
if (response.status !== 200) {
|
|
869
|
+
const data = await response.json();
|
|
870
|
+
if ("code" in data && "error" in data && "error_description" in data) throw new RequestError_default(data.code, data.error, data.error_description, response.status);
|
|
871
|
+
throw new RequestError_default(-1, "failed_without_info", "Request failed without any information from the backend.", response.status);
|
|
872
|
+
}
|
|
873
|
+
let filename = response.headers.has("content-disposition") ? HttpAdapter.parseFileNameFromContentDispositionHeader(response.headers.get("content-disposition") ?? "") : `download-${DateTime.now().toFormat("yyyy-MM-dd HH-mm-ss")}`;
|
|
874
|
+
return new BlobResponse_default(await response.blob(), filename);
|
|
875
|
+
}
|
|
876
|
+
async run() {
|
|
877
|
+
const { data, response } = await this.#executeSafe();
|
|
878
|
+
return new BaseResponse(data, response);
|
|
879
|
+
}
|
|
880
|
+
async runAdapter(adapterMethod) {
|
|
881
|
+
const { data, response } = await this.#executeSafe();
|
|
882
|
+
return new BaseResponse(adapterMethod(data), response);
|
|
883
|
+
}
|
|
884
|
+
async runArrayAdapter(adapterMethod) {
|
|
885
|
+
return this.runAdapter((data) => data.map(adapterMethod));
|
|
886
|
+
}
|
|
887
|
+
async runEmpty() {
|
|
888
|
+
return await this.#executeSafe();
|
|
889
|
+
}
|
|
890
|
+
async runPaginatedAdapter(adapterMethod) {
|
|
891
|
+
return this.runAdapter((response) => HttpAdapter.parsePaginatedAdapter(response, adapterMethod));
|
|
892
|
+
}
|
|
893
|
+
async runData() {
|
|
894
|
+
return await this.#executeSafe();
|
|
895
|
+
}
|
|
896
|
+
async runDataKey(key) {
|
|
897
|
+
const { data, response } = await this.#executeSafe();
|
|
898
|
+
return new BaseResponse(data[key], response);
|
|
899
|
+
}
|
|
900
|
+
async runStatusCode() {
|
|
901
|
+
return (await this.#executeSafe()).statusCode;
|
|
902
|
+
}
|
|
903
|
+
async #execute() {
|
|
904
|
+
if (this.#autoCancelIdentifier !== null) {
|
|
905
|
+
if (this.#autoCancelIdentifier in abortControllers) abortControllers[this.#autoCancelIdentifier].abort(new RequestAbortedError_default());
|
|
906
|
+
const controller = new AbortController();
|
|
907
|
+
abortControllers[this.#autoCancelIdentifier] = controller;
|
|
908
|
+
this.signal(controller.signal);
|
|
909
|
+
}
|
|
910
|
+
let path = this.path;
|
|
911
|
+
if (this.query !== null) path += `?${this.query.build()}`;
|
|
912
|
+
const response = await fetch(this.client.baseUrl + path, this.options);
|
|
913
|
+
if (this.#autoCancelIdentifier !== null) delete abortControllers[this.#autoCancelIdentifier];
|
|
914
|
+
return response;
|
|
915
|
+
}
|
|
916
|
+
async #executeSafe() {
|
|
917
|
+
return await this.#execute().then((response) => RequestBuilder.#handleResponse(response, this.client.dataField));
|
|
918
|
+
}
|
|
919
|
+
static async #handleResponse(response, dataField) {
|
|
920
|
+
if (response.status === 204) return new BaseResponse(null, response);
|
|
921
|
+
if (response.headers.has("content-type") && response.headers.get("content-type")?.startsWith("application/json")) {
|
|
922
|
+
const data = await response.json();
|
|
923
|
+
if (data && typeof data === "object" && "code" in data && "error" in data && "error_description" in data) {
|
|
924
|
+
if ("errors" in data) throw HttpAdapter.parseValidationError(data);
|
|
925
|
+
throw HttpAdapter.parseRequestError(data, response.status);
|
|
926
|
+
}
|
|
927
|
+
if (dataField && "data" in data) return new BaseResponse(data.data, response);
|
|
928
|
+
return new BaseResponse(data, response);
|
|
929
|
+
}
|
|
930
|
+
if (response.status === 401 || response.status === 403) return new BaseResponse(null, response);
|
|
931
|
+
if ((await response.text()).length === 0 && response.status >= 200 && response.status < 300) return new BaseResponse(null, response);
|
|
932
|
+
throw new RequestError_default(-1, "not_a_json_response", "The response was not a JSON response.", response.status);
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
//#endregion
|
|
936
|
+
//#region src/http/BaseService.ts
|
|
937
|
+
var BaseService = class {
|
|
938
|
+
request(path, client) {
|
|
939
|
+
return new RequestBuilder(path, client);
|
|
940
|
+
}
|
|
941
|
+
};
|
|
942
|
+
//#endregion
|
|
943
|
+
//#region src/http/QueryString.ts
|
|
944
|
+
var QueryString = class QueryString {
|
|
945
|
+
#builder;
|
|
946
|
+
constructor() {
|
|
947
|
+
this.#builder = new URLSearchParams();
|
|
948
|
+
}
|
|
949
|
+
build() {
|
|
950
|
+
return this.#builder.toString();
|
|
951
|
+
}
|
|
952
|
+
append(name, value) {
|
|
953
|
+
return this.#add(this.#builder.append.bind(this.#builder), name, value);
|
|
954
|
+
}
|
|
955
|
+
appendArray(name, values) {
|
|
956
|
+
if (values === void 0 || values === null) return this;
|
|
957
|
+
values.forEach((value) => this.append(name, value));
|
|
958
|
+
return this;
|
|
959
|
+
}
|
|
960
|
+
delete(name) {
|
|
961
|
+
this.#builder.delete(name);
|
|
962
|
+
return this;
|
|
963
|
+
}
|
|
964
|
+
get(name) {
|
|
965
|
+
return this.#builder.get(name);
|
|
966
|
+
}
|
|
967
|
+
getAll(name) {
|
|
968
|
+
return this.#builder.getAll(name);
|
|
969
|
+
}
|
|
970
|
+
has(name) {
|
|
971
|
+
return this.#builder.has(name);
|
|
972
|
+
}
|
|
973
|
+
set(name, value) {
|
|
974
|
+
return this.#add(this.#builder.set.bind(this.#builder), name, value);
|
|
975
|
+
}
|
|
976
|
+
#add(fn, name, value) {
|
|
977
|
+
if (!value && value !== false) return this;
|
|
978
|
+
switch (typeof value) {
|
|
979
|
+
case "boolean":
|
|
980
|
+
fn(name, value ? "true" : "false");
|
|
981
|
+
break;
|
|
982
|
+
case "number":
|
|
983
|
+
fn(name, value.toString(10));
|
|
984
|
+
break;
|
|
985
|
+
case "string":
|
|
986
|
+
fn(name, value);
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
return this;
|
|
990
|
+
}
|
|
991
|
+
static builder() {
|
|
992
|
+
return new QueryString();
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
//#endregion
|
|
996
|
+
//#region src/http/helpers.ts
|
|
997
|
+
function isRequestAborted(obj) {
|
|
998
|
+
return obj instanceof RequestAbortedError_default;
|
|
999
|
+
}
|
|
1000
|
+
function isRequestError(obj) {
|
|
1001
|
+
return obj instanceof RequestError_default;
|
|
1002
|
+
}
|
|
1003
|
+
function isUnsanctionedRequest(statusCode) {
|
|
1004
|
+
if (statusCode instanceof RequestError_default) statusCode = statusCode.statusCode;
|
|
1005
|
+
return statusCode === 403 || statusCode === 401;
|
|
1006
|
+
}
|
|
1007
|
+
function isValidationError(obj) {
|
|
1008
|
+
return obj instanceof ValidationError_default;
|
|
1009
|
+
}
|
|
1010
|
+
//#endregion
|
|
1011
|
+
export { BaseResponse, BaseService, BlobResponse_default as BlobResponse, HttpAdapter, HttpClient, Paginated_default as Paginated, QueryString, RequestAbortedError_default as RequestAbortedError, RequestBuilder, RequestError_default as RequestError, ValidationError_default as ValidationError, adapter_default as adapter, assertDto_default as assertDto, bound_default as bound, cloneDto_default as cloneDto, debounce_default as debounce, deserialize_default as deserialize, dto_default as dto, executeIfDtoDirtyAndMarkClean_default as executeIfDtoDirtyAndMarkClean, isDto_default as isDto, isDtoClean_default as isDtoClean, isDtoDirty_default as isDtoDirty, isRequestAborted, isRequestError, isUnsanctionedRequest, isValidationError, markDtoClean, markDtoDirty, serialize_default as serialize };
|
|
1012
|
+
|
|
2
1013
|
//# sourceMappingURL=index.mjs.map
|