@eeplatform/core 1.4.3 → 1.4.5

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 CHANGED
@@ -10389,7 +10389,7 @@ var require_ms = __commonJS({
10389
10389
  options = options || {};
10390
10390
  var type = typeof val;
10391
10391
  if (type === "string" && val.length > 0) {
10392
- return parse(val);
10392
+ return parse3(val);
10393
10393
  } else if (type === "number" && isNaN(val) === false) {
10394
10394
  return options.long ? fmtLong(val) : fmtShort(val);
10395
10395
  }
@@ -10397,7 +10397,7 @@ var require_ms = __commonJS({
10397
10397
  "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
10398
10398
  );
10399
10399
  };
10400
- function parse(str) {
10400
+ function parse3(str) {
10401
10401
  str = String(str);
10402
10402
  if (str.length > 100) {
10403
10403
  return;
@@ -10844,7 +10844,7 @@ var require_follow_redirects = __commonJS({
10844
10844
  (function detectUnsupportedEnvironment() {
10845
10845
  var looksLikeNode = typeof process !== "undefined";
10846
10846
  var looksLikeBrowser = typeof window !== "undefined" && typeof document !== "undefined";
10847
- var looksLikeV8 = isFunction2(Error.captureStackTrace);
10847
+ var looksLikeV8 = isFunction3(Error.captureStackTrace);
10848
10848
  if (!looksLikeNode && (looksLikeBrowser || !looksLikeV8)) {
10849
10849
  console.warn("The follow-redirects package should be excluded from browser builds.");
10850
10850
  }
@@ -10939,7 +10939,7 @@ var require_follow_redirects = __commonJS({
10939
10939
  if (!isString2(data) && !isBuffer2(data)) {
10940
10940
  throw new TypeError("data should be a string, Buffer or Uint8Array");
10941
10941
  }
10942
- if (isFunction2(encoding)) {
10942
+ if (isFunction3(encoding)) {
10943
10943
  callback = encoding;
10944
10944
  encoding = null;
10945
10945
  }
@@ -10959,10 +10959,10 @@ var require_follow_redirects = __commonJS({
10959
10959
  }
10960
10960
  };
10961
10961
  RedirectableRequest.prototype.end = function(data, encoding, callback) {
10962
- if (isFunction2(data)) {
10962
+ if (isFunction3(data)) {
10963
10963
  callback = data;
10964
10964
  data = encoding = null;
10965
- } else if (isFunction2(encoding)) {
10965
+ } else if (isFunction3(encoding)) {
10966
10966
  callback = encoding;
10967
10967
  encoding = null;
10968
10968
  }
@@ -11163,7 +11163,7 @@ var require_follow_redirects = __commonJS({
11163
11163
  if (redirectUrl.protocol !== currentUrlParts.protocol && redirectUrl.protocol !== "https:" || redirectUrl.host !== currentHost && !isSubdomain(redirectUrl.host, currentHost)) {
11164
11164
  removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this._options.headers);
11165
11165
  }
11166
- if (isFunction2(beforeRedirect)) {
11166
+ if (isFunction3(beforeRedirect)) {
11167
11167
  var responseDetails = {
11168
11168
  headers: response.headers,
11169
11169
  statusCode
@@ -11198,7 +11198,7 @@ var require_follow_redirects = __commonJS({
11198
11198
  options = validateUrl(input);
11199
11199
  input = { protocol };
11200
11200
  }
11201
- if (isFunction2(options)) {
11201
+ if (isFunction3(options)) {
11202
11202
  callback = options;
11203
11203
  options = null;
11204
11204
  }
@@ -11278,7 +11278,7 @@ var require_follow_redirects = __commonJS({
11278
11278
  }
11279
11279
  function createErrorType(code, message, baseClass) {
11280
11280
  function CustomError(properties) {
11281
- if (isFunction2(Error.captureStackTrace)) {
11281
+ if (isFunction3(Error.captureStackTrace)) {
11282
11282
  Error.captureStackTrace(this, this.constructor);
11283
11283
  }
11284
11284
  Object.assign(this, properties || {});
@@ -11313,7 +11313,7 @@ var require_follow_redirects = __commonJS({
11313
11313
  function isString2(value) {
11314
11314
  return typeof value === "string" || value instanceof String;
11315
11315
  }
11316
- function isFunction2(value) {
11316
+ function isFunction3(value) {
11317
11317
  return typeof value === "function";
11318
11318
  }
11319
11319
  function isBuffer2(value) {
@@ -13569,7 +13569,7 @@ var _global = (() => {
13569
13569
  })();
13570
13570
  var isContextDefined = (context) => !isUndefined(context) && context !== _global;
13571
13571
  function merge() {
13572
- const { caseless } = isContextDefined(this) && this || {};
13572
+ const { caseless, skipUndefined } = isContextDefined(this) && this || {};
13573
13573
  const result = {};
13574
13574
  const assignValue = (val, key) => {
13575
13575
  const targetKey = caseless && findKey(result, key) || key;
@@ -13579,7 +13579,7 @@ function merge() {
13579
13579
  result[targetKey] = merge({}, val);
13580
13580
  } else if (isArray(val)) {
13581
13581
  result[targetKey] = val.slice();
13582
- } else {
13582
+ } else if (!skipUndefined || !isUndefined(val)) {
13583
13583
  result[targetKey] = val;
13584
13584
  }
13585
13585
  };
@@ -13915,9 +13915,13 @@ AxiosError.from = (error, code, config2, request, response, customProps) => {
13915
13915
  }, (prop) => {
13916
13916
  return prop !== "isAxiosError";
13917
13917
  });
13918
- AxiosError.call(axiosError, error.message, code, config2, request, response);
13919
- axiosError.cause = error;
13920
- axiosError.name = error.name;
13918
+ const msg = error && error.message ? error.message : "Error";
13919
+ const errCode = code == null && error ? error.code : code;
13920
+ AxiosError.call(axiosError, msg, errCode, config2, request, response);
13921
+ if (error && axiosError.cause == null) {
13922
+ Object.defineProperty(axiosError, "cause", { value: error, configurable: true });
13923
+ }
13924
+ axiosError.name = error && error.name || "Error";
13921
13925
  customProps && Object.assign(axiosError, customProps);
13922
13926
  return axiosError;
13923
13927
  };
@@ -14080,7 +14084,7 @@ var AxiosURLSearchParams_default = AxiosURLSearchParams;
14080
14084
 
14081
14085
  // node_modules/axios/lib/helpers/buildURL.js
14082
14086
  function encode2(val) {
14083
- return encodeURIComponent(val).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+").replace(/%5B/gi, "[").replace(/%5D/gi, "]");
14087
+ return encodeURIComponent(val).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+");
14084
14088
  }
14085
14089
  function buildURL(url2, params, options) {
14086
14090
  if (!params) {
@@ -14378,7 +14382,7 @@ var defaults = {
14378
14382
  const silentJSONParsing = transitional2 && transitional2.silentJSONParsing;
14379
14383
  const strictJSONParsing = !silentJSONParsing && JSONRequested;
14380
14384
  try {
14381
- return JSON.parse(data);
14385
+ return JSON.parse(data, this.parseReviver);
14382
14386
  } catch (e) {
14383
14387
  if (strictJSONParsing) {
14384
14388
  if (e.name === "SyntaxError") {
@@ -14765,7 +14769,7 @@ import util2 from "util";
14765
14769
  import zlib from "zlib";
14766
14770
 
14767
14771
  // node_modules/axios/lib/env/data.js
14768
- var VERSION = "1.11.0";
14772
+ var VERSION = "1.12.2";
14769
14773
 
14770
14774
  // node_modules/axios/lib/helpers/parseProtocol.js
14771
14775
  function parseProtocol(url2) {
@@ -15164,6 +15168,60 @@ var progressEventDecorator = (total, throttled) => {
15164
15168
  };
15165
15169
  var asyncDecorator = (fn) => (...args) => utils_default.asap(() => fn(...args));
15166
15170
 
15171
+ // node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js
15172
+ function estimateDataURLDecodedBytes(url2) {
15173
+ if (!url2 || typeof url2 !== "string")
15174
+ return 0;
15175
+ if (!url2.startsWith("data:"))
15176
+ return 0;
15177
+ const comma = url2.indexOf(",");
15178
+ if (comma < 0)
15179
+ return 0;
15180
+ const meta = url2.slice(5, comma);
15181
+ const body = url2.slice(comma + 1);
15182
+ const isBase64 = /;base64/i.test(meta);
15183
+ if (isBase64) {
15184
+ let effectiveLen = body.length;
15185
+ const len = body.length;
15186
+ for (let i = 0; i < len; i++) {
15187
+ if (body.charCodeAt(i) === 37 && i + 2 < len) {
15188
+ const a = body.charCodeAt(i + 1);
15189
+ const b = body.charCodeAt(i + 2);
15190
+ const isHex = (a >= 48 && a <= 57 || a >= 65 && a <= 70 || a >= 97 && a <= 102) && (b >= 48 && b <= 57 || b >= 65 && b <= 70 || b >= 97 && b <= 102);
15191
+ if (isHex) {
15192
+ effectiveLen -= 2;
15193
+ i += 2;
15194
+ }
15195
+ }
15196
+ }
15197
+ let pad = 0;
15198
+ let idx = len - 1;
15199
+ const tailIsPct3D = (j) => j >= 2 && body.charCodeAt(j - 2) === 37 && // '%'
15200
+ body.charCodeAt(j - 1) === 51 && // '3'
15201
+ (body.charCodeAt(j) === 68 || body.charCodeAt(j) === 100);
15202
+ if (idx >= 0) {
15203
+ if (body.charCodeAt(idx) === 61) {
15204
+ pad++;
15205
+ idx--;
15206
+ } else if (tailIsPct3D(idx)) {
15207
+ pad++;
15208
+ idx -= 3;
15209
+ }
15210
+ }
15211
+ if (pad === 1 && idx >= 0) {
15212
+ if (body.charCodeAt(idx) === 61) {
15213
+ pad++;
15214
+ } else if (tailIsPct3D(idx)) {
15215
+ pad++;
15216
+ }
15217
+ }
15218
+ const groups = Math.floor(effectiveLen / 4);
15219
+ const bytes = groups * 3 - (pad || 0);
15220
+ return bytes > 0 ? bytes : 0;
15221
+ }
15222
+ return Buffer.byteLength(body, "utf8");
15223
+ }
15224
+
15167
15225
  // node_modules/axios/lib/adapters/http.js
15168
15226
  var zlibOptions = {
15169
15227
  flush: zlib.constants.Z_SYNC_FLUSH,
@@ -15307,6 +15365,17 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config2) {
15307
15365
  const parsed = new URL(fullPath, platform_default.hasBrowserEnv ? platform_default.origin : void 0);
15308
15366
  const protocol = parsed.protocol || supportedProtocols[0];
15309
15367
  if (protocol === "data:") {
15368
+ if (config2.maxContentLength > -1) {
15369
+ const dataUrl = String(config2.url || fullPath || "");
15370
+ const estimated = estimateDataURLDecodedBytes(dataUrl);
15371
+ if (estimated > config2.maxContentLength) {
15372
+ return reject(new AxiosError_default(
15373
+ "maxContentLength size of " + config2.maxContentLength + " exceeded",
15374
+ AxiosError_default.ERR_BAD_RESPONSE,
15375
+ config2
15376
+ ));
15377
+ }
15378
+ }
15310
15379
  let convertedData;
15311
15380
  if (method !== "GET") {
15312
15381
  return settle(resolve, reject, {
@@ -15802,13 +15871,17 @@ var resolveConfig_default = (config2) => {
15802
15871
  "Basic " + btoa((auth.username || "") + ":" + (auth.password ? unescape(encodeURIComponent(auth.password)) : ""))
15803
15872
  );
15804
15873
  }
15805
- let contentType;
15806
15874
  if (utils_default.isFormData(data)) {
15807
15875
  if (platform_default.hasStandardBrowserEnv || platform_default.hasStandardBrowserWebWorkerEnv) {
15808
15876
  headers.setContentType(void 0);
15809
- } else if ((contentType = headers.getContentType()) !== false) {
15810
- const [type, ...tokens] = contentType ? contentType.split(";").map((token) => token.trim()).filter(Boolean) : [];
15811
- headers.setContentType([type || "multipart/form-data", ...tokens].join("; "));
15877
+ } else if (utils_default.isFunction(data.getHeaders)) {
15878
+ const formHeaders = data.getHeaders();
15879
+ const allowedHeaders = ["content-type", "content-length"];
15880
+ Object.entries(formHeaders).forEach(([key, val]) => {
15881
+ if (allowedHeaders.includes(key.toLowerCase())) {
15882
+ headers.set(key, val);
15883
+ }
15884
+ });
15812
15885
  }
15813
15886
  }
15814
15887
  if (platform_default.hasStandardBrowserEnv) {
@@ -15888,8 +15961,11 @@ var xhr_default = isXHRAdapterSupported && function(config2) {
15888
15961
  reject(new AxiosError_default("Request aborted", AxiosError_default.ECONNABORTED, config2, request));
15889
15962
  request = null;
15890
15963
  };
15891
- request.onerror = function handleError() {
15892
- reject(new AxiosError_default("Network Error", AxiosError_default.ERR_NETWORK, config2, request));
15964
+ request.onerror = function handleError(event) {
15965
+ const msg = event && event.message ? event.message : "Network Error";
15966
+ const err = new AxiosError_default(msg, AxiosError_default.ERR_NETWORK, config2, request);
15967
+ err.event = event || null;
15968
+ reject(err);
15893
15969
  request = null;
15894
15970
  };
15895
15971
  request.ontimeout = function handleTimeout() {
@@ -16064,9 +16140,16 @@ var trackStream = (stream4, chunkSize, onProgress, onFinish) => {
16064
16140
  };
16065
16141
 
16066
16142
  // node_modules/axios/lib/adapters/fetch.js
16067
- var isFetchSupported = typeof fetch === "function" && typeof Request === "function" && typeof Response === "function";
16068
- var isReadableStreamSupported = isFetchSupported && typeof ReadableStream === "function";
16069
- var encodeText = isFetchSupported && (typeof TextEncoder === "function" ? ((encoder) => (str) => encoder.encode(str))(new TextEncoder()) : async (str) => new Uint8Array(await new Response(str).arrayBuffer()));
16143
+ var DEFAULT_CHUNK_SIZE = 64 * 1024;
16144
+ var { isFunction: isFunction2 } = utils_default;
16145
+ var globalFetchAPI = (({ Request, Response }) => ({
16146
+ Request,
16147
+ Response
16148
+ }))(utils_default.global);
16149
+ var {
16150
+ ReadableStream: ReadableStream2,
16151
+ TextEncoder: TextEncoder2
16152
+ } = utils_default.global;
16070
16153
  var test = (fn, ...args) => {
16071
16154
  try {
16072
16155
  return !!fn(...args);
@@ -16074,164 +16157,204 @@ var test = (fn, ...args) => {
16074
16157
  return false;
16075
16158
  }
16076
16159
  };
16077
- var supportsRequestStream = isReadableStreamSupported && test(() => {
16078
- let duplexAccessed = false;
16079
- const hasContentType = new Request(platform_default.origin, {
16080
- body: new ReadableStream(),
16081
- method: "POST",
16082
- get duplex() {
16083
- duplexAccessed = true;
16084
- return "half";
16085
- }
16086
- }).headers.has("Content-Type");
16087
- return duplexAccessed && !hasContentType;
16088
- });
16089
- var DEFAULT_CHUNK_SIZE = 64 * 1024;
16090
- var supportsResponseStream = isReadableStreamSupported && test(() => utils_default.isReadableStream(new Response("").body));
16091
- var resolvers = {
16092
- stream: supportsResponseStream && ((res) => res.body)
16093
- };
16094
- isFetchSupported && ((res) => {
16095
- ["text", "arrayBuffer", "blob", "formData", "stream"].forEach((type) => {
16096
- !resolvers[type] && (resolvers[type] = utils_default.isFunction(res[type]) ? (res2) => res2[type]() : (_, config2) => {
16097
- throw new AxiosError_default(`Response type '${type}' is not supported`, AxiosError_default.ERR_NOT_SUPPORT, config2);
16098
- });
16099
- });
16100
- })(new Response());
16101
- var getBodyLength = async (body) => {
16102
- if (body == null) {
16103
- return 0;
16104
- }
16105
- if (utils_default.isBlob(body)) {
16106
- return body.size;
16160
+ var factory = (env) => {
16161
+ env = utils_default.merge.call({
16162
+ skipUndefined: true
16163
+ }, globalFetchAPI, env);
16164
+ const { fetch: envFetch, Request, Response } = env;
16165
+ const isFetchSupported = envFetch ? isFunction2(envFetch) : typeof fetch === "function";
16166
+ const isRequestSupported = isFunction2(Request);
16167
+ const isResponseSupported = isFunction2(Response);
16168
+ if (!isFetchSupported) {
16169
+ return false;
16107
16170
  }
16108
- if (utils_default.isSpecCompliantForm(body)) {
16109
- const _request = new Request(platform_default.origin, {
16171
+ const isReadableStreamSupported = isFetchSupported && isFunction2(ReadableStream2);
16172
+ const encodeText = isFetchSupported && (typeof TextEncoder2 === "function" ? ((encoder) => (str) => encoder.encode(str))(new TextEncoder2()) : async (str) => new Uint8Array(await new Request(str).arrayBuffer()));
16173
+ const supportsRequestStream = isRequestSupported && isReadableStreamSupported && test(() => {
16174
+ let duplexAccessed = false;
16175
+ const hasContentType = new Request(platform_default.origin, {
16176
+ body: new ReadableStream2(),
16110
16177
  method: "POST",
16111
- body
16112
- });
16113
- return (await _request.arrayBuffer()).byteLength;
16114
- }
16115
- if (utils_default.isArrayBufferView(body) || utils_default.isArrayBuffer(body)) {
16116
- return body.byteLength;
16117
- }
16118
- if (utils_default.isURLSearchParams(body)) {
16119
- body = body + "";
16120
- }
16121
- if (utils_default.isString(body)) {
16122
- return (await encodeText(body)).byteLength;
16123
- }
16124
- };
16125
- var resolveBodyLength = async (headers, body) => {
16126
- const length = utils_default.toFiniteNumber(headers.getContentLength());
16127
- return length == null ? getBodyLength(body) : length;
16128
- };
16129
- var fetch_default = isFetchSupported && (async (config2) => {
16130
- let {
16131
- url: url2,
16132
- method,
16133
- data,
16134
- signal,
16135
- cancelToken,
16136
- timeout,
16137
- onDownloadProgress,
16138
- onUploadProgress,
16139
- responseType,
16140
- headers,
16141
- withCredentials = "same-origin",
16142
- fetchOptions
16143
- } = resolveConfig_default(config2);
16144
- responseType = responseType ? (responseType + "").toLowerCase() : "text";
16145
- let composedSignal = composeSignals_default([signal, cancelToken && cancelToken.toAbortSignal()], timeout);
16146
- let request;
16147
- const unsubscribe = composedSignal && composedSignal.unsubscribe && (() => {
16148
- composedSignal.unsubscribe();
16178
+ get duplex() {
16179
+ duplexAccessed = true;
16180
+ return "half";
16181
+ }
16182
+ }).headers.has("Content-Type");
16183
+ return duplexAccessed && !hasContentType;
16149
16184
  });
16150
- let requestContentLength;
16151
- try {
16152
- if (onUploadProgress && supportsRequestStream && method !== "get" && method !== "head" && (requestContentLength = await resolveBodyLength(headers, data)) !== 0) {
16153
- let _request = new Request(url2, {
16154
- method: "POST",
16155
- body: data,
16156
- duplex: "half"
16185
+ const supportsResponseStream = isResponseSupported && isReadableStreamSupported && test(() => utils_default.isReadableStream(new Response("").body));
16186
+ const resolvers = {
16187
+ stream: supportsResponseStream && ((res) => res.body)
16188
+ };
16189
+ isFetchSupported && (() => {
16190
+ ["text", "arrayBuffer", "blob", "formData", "stream"].forEach((type) => {
16191
+ !resolvers[type] && (resolvers[type] = (res, config2) => {
16192
+ let method = res && res[type];
16193
+ if (method) {
16194
+ return method.call(res);
16195
+ }
16196
+ throw new AxiosError_default(`Response type '${type}' is not supported`, AxiosError_default.ERR_NOT_SUPPORT, config2);
16157
16197
  });
16158
- let contentTypeHeader;
16159
- if (utils_default.isFormData(data) && (contentTypeHeader = _request.headers.get("content-type"))) {
16160
- headers.setContentType(contentTypeHeader);
16161
- }
16162
- if (_request.body) {
16163
- const [onProgress, flush] = progressEventDecorator(
16164
- requestContentLength,
16165
- progressEventReducer(asyncDecorator(onUploadProgress))
16166
- );
16167
- data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush);
16168
- }
16198
+ });
16199
+ })();
16200
+ const getBodyLength = async (body) => {
16201
+ if (body == null) {
16202
+ return 0;
16169
16203
  }
16170
- if (!utils_default.isString(withCredentials)) {
16171
- withCredentials = withCredentials ? "include" : "omit";
16204
+ if (utils_default.isBlob(body)) {
16205
+ return body.size;
16172
16206
  }
16173
- const isCredentialsSupported = "credentials" in Request.prototype;
16174
- request = new Request(url2, {
16175
- ...fetchOptions,
16176
- signal: composedSignal,
16177
- method: method.toUpperCase(),
16178
- headers: headers.normalize().toJSON(),
16179
- body: data,
16180
- duplex: "half",
16181
- credentials: isCredentialsSupported ? withCredentials : void 0
16182
- });
16183
- let response = await fetch(request, fetchOptions);
16184
- const isStreamResponse = supportsResponseStream && (responseType === "stream" || responseType === "response");
16185
- if (supportsResponseStream && (onDownloadProgress || isStreamResponse && unsubscribe)) {
16186
- const options = {};
16187
- ["status", "statusText", "headers"].forEach((prop) => {
16188
- options[prop] = response[prop];
16207
+ if (utils_default.isSpecCompliantForm(body)) {
16208
+ const _request = new Request(platform_default.origin, {
16209
+ method: "POST",
16210
+ body
16189
16211
  });
16190
- const responseContentLength = utils_default.toFiniteNumber(response.headers.get("content-length"));
16191
- const [onProgress, flush] = onDownloadProgress && progressEventDecorator(
16192
- responseContentLength,
16193
- progressEventReducer(asyncDecorator(onDownloadProgress), true)
16194
- ) || [];
16195
- response = new Response(
16196
- trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {
16197
- flush && flush();
16198
- unsubscribe && unsubscribe();
16199
- }),
16200
- options
16201
- );
16212
+ return (await _request.arrayBuffer()).byteLength;
16202
16213
  }
16203
- responseType = responseType || "text";
16204
- let responseData = await resolvers[utils_default.findKey(resolvers, responseType) || "text"](response, config2);
16205
- !isStreamResponse && unsubscribe && unsubscribe();
16206
- return await new Promise((resolve, reject) => {
16207
- settle(resolve, reject, {
16208
- data: responseData,
16209
- headers: AxiosHeaders_default.from(response.headers),
16210
- status: response.status,
16211
- statusText: response.statusText,
16212
- config: config2,
16213
- request
16214
- });
16214
+ if (utils_default.isArrayBufferView(body) || utils_default.isArrayBuffer(body)) {
16215
+ return body.byteLength;
16216
+ }
16217
+ if (utils_default.isURLSearchParams(body)) {
16218
+ body = body + "";
16219
+ }
16220
+ if (utils_default.isString(body)) {
16221
+ return (await encodeText(body)).byteLength;
16222
+ }
16223
+ };
16224
+ const resolveBodyLength = async (headers, body) => {
16225
+ const length = utils_default.toFiniteNumber(headers.getContentLength());
16226
+ return length == null ? getBodyLength(body) : length;
16227
+ };
16228
+ return async (config2) => {
16229
+ let {
16230
+ url: url2,
16231
+ method,
16232
+ data,
16233
+ signal,
16234
+ cancelToken,
16235
+ timeout,
16236
+ onDownloadProgress,
16237
+ onUploadProgress,
16238
+ responseType,
16239
+ headers,
16240
+ withCredentials = "same-origin",
16241
+ fetchOptions
16242
+ } = resolveConfig_default(config2);
16243
+ let _fetch = envFetch || fetch;
16244
+ responseType = responseType ? (responseType + "").toLowerCase() : "text";
16245
+ let composedSignal = composeSignals_default([signal, cancelToken && cancelToken.toAbortSignal()], timeout);
16246
+ let request = null;
16247
+ const unsubscribe = composedSignal && composedSignal.unsubscribe && (() => {
16248
+ composedSignal.unsubscribe();
16215
16249
  });
16216
- } catch (err) {
16217
- unsubscribe && unsubscribe();
16218
- if (err && err.name === "TypeError" && /Load failed|fetch/i.test(err.message)) {
16219
- throw Object.assign(
16220
- new AxiosError_default("Network Error", AxiosError_default.ERR_NETWORK, config2, request),
16221
- {
16222
- cause: err.cause || err
16250
+ let requestContentLength;
16251
+ try {
16252
+ if (onUploadProgress && supportsRequestStream && method !== "get" && method !== "head" && (requestContentLength = await resolveBodyLength(headers, data)) !== 0) {
16253
+ let _request = new Request(url2, {
16254
+ method: "POST",
16255
+ body: data,
16256
+ duplex: "half"
16257
+ });
16258
+ let contentTypeHeader;
16259
+ if (utils_default.isFormData(data) && (contentTypeHeader = _request.headers.get("content-type"))) {
16260
+ headers.setContentType(contentTypeHeader);
16223
16261
  }
16224
- );
16262
+ if (_request.body) {
16263
+ const [onProgress, flush] = progressEventDecorator(
16264
+ requestContentLength,
16265
+ progressEventReducer(asyncDecorator(onUploadProgress))
16266
+ );
16267
+ data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush);
16268
+ }
16269
+ }
16270
+ if (!utils_default.isString(withCredentials)) {
16271
+ withCredentials = withCredentials ? "include" : "omit";
16272
+ }
16273
+ const isCredentialsSupported = isRequestSupported && "credentials" in Request.prototype;
16274
+ const resolvedOptions = {
16275
+ ...fetchOptions,
16276
+ signal: composedSignal,
16277
+ method: method.toUpperCase(),
16278
+ headers: headers.normalize().toJSON(),
16279
+ body: data,
16280
+ duplex: "half",
16281
+ credentials: isCredentialsSupported ? withCredentials : void 0
16282
+ };
16283
+ request = isRequestSupported && new Request(url2, resolvedOptions);
16284
+ let response = await (isRequestSupported ? _fetch(request, fetchOptions) : _fetch(url2, resolvedOptions));
16285
+ const isStreamResponse = supportsResponseStream && (responseType === "stream" || responseType === "response");
16286
+ if (supportsResponseStream && (onDownloadProgress || isStreamResponse && unsubscribe)) {
16287
+ const options = {};
16288
+ ["status", "statusText", "headers"].forEach((prop) => {
16289
+ options[prop] = response[prop];
16290
+ });
16291
+ const responseContentLength = utils_default.toFiniteNumber(response.headers.get("content-length"));
16292
+ const [onProgress, flush] = onDownloadProgress && progressEventDecorator(
16293
+ responseContentLength,
16294
+ progressEventReducer(asyncDecorator(onDownloadProgress), true)
16295
+ ) || [];
16296
+ response = new Response(
16297
+ trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {
16298
+ flush && flush();
16299
+ unsubscribe && unsubscribe();
16300
+ }),
16301
+ options
16302
+ );
16303
+ }
16304
+ responseType = responseType || "text";
16305
+ let responseData = await resolvers[utils_default.findKey(resolvers, responseType) || "text"](response, config2);
16306
+ !isStreamResponse && unsubscribe && unsubscribe();
16307
+ return await new Promise((resolve, reject) => {
16308
+ settle(resolve, reject, {
16309
+ data: responseData,
16310
+ headers: AxiosHeaders_default.from(response.headers),
16311
+ status: response.status,
16312
+ statusText: response.statusText,
16313
+ config: config2,
16314
+ request
16315
+ });
16316
+ });
16317
+ } catch (err) {
16318
+ unsubscribe && unsubscribe();
16319
+ if (err && err.name === "TypeError" && /Load failed|fetch/i.test(err.message)) {
16320
+ throw Object.assign(
16321
+ new AxiosError_default("Network Error", AxiosError_default.ERR_NETWORK, config2, request),
16322
+ {
16323
+ cause: err.cause || err
16324
+ }
16325
+ );
16326
+ }
16327
+ throw AxiosError_default.from(err, err && err.code, config2, request);
16225
16328
  }
16226
- throw AxiosError_default.from(err, err && err.code, config2, request);
16227
- }
16228
- });
16329
+ };
16330
+ };
16331
+ var seedCache = /* @__PURE__ */ new Map();
16332
+ var getFetch = (config2) => {
16333
+ let env = config2 ? config2.env : {};
16334
+ const { fetch: fetch2, Request, Response } = env;
16335
+ const seeds = [
16336
+ Request,
16337
+ Response,
16338
+ fetch2
16339
+ ];
16340
+ let len = seeds.length, i = len, seed, target, map = seedCache;
16341
+ while (i--) {
16342
+ seed = seeds[i];
16343
+ target = map.get(seed);
16344
+ target === void 0 && map.set(seed, target = i ? /* @__PURE__ */ new Map() : factory(env));
16345
+ map = target;
16346
+ }
16347
+ return target;
16348
+ };
16349
+ var adapter = getFetch();
16229
16350
 
16230
16351
  // node_modules/axios/lib/adapters/adapters.js
16231
16352
  var knownAdapters = {
16232
16353
  http: http_default,
16233
16354
  xhr: xhr_default,
16234
- fetch: fetch_default
16355
+ fetch: {
16356
+ get: getFetch
16357
+ }
16235
16358
  };
16236
16359
  utils_default.forEach(knownAdapters, (fn, value) => {
16237
16360
  if (fn) {
@@ -16243,30 +16366,30 @@ utils_default.forEach(knownAdapters, (fn, value) => {
16243
16366
  }
16244
16367
  });
16245
16368
  var renderReason = (reason) => `- ${reason}`;
16246
- var isResolvedHandle = (adapter) => utils_default.isFunction(adapter) || adapter === null || adapter === false;
16369
+ var isResolvedHandle = (adapter2) => utils_default.isFunction(adapter2) || adapter2 === null || adapter2 === false;
16247
16370
  var adapters_default = {
16248
- getAdapter: (adapters) => {
16371
+ getAdapter: (adapters, config2) => {
16249
16372
  adapters = utils_default.isArray(adapters) ? adapters : [adapters];
16250
16373
  const { length } = adapters;
16251
16374
  let nameOrAdapter;
16252
- let adapter;
16375
+ let adapter2;
16253
16376
  const rejectedReasons = {};
16254
16377
  for (let i = 0; i < length; i++) {
16255
16378
  nameOrAdapter = adapters[i];
16256
16379
  let id;
16257
- adapter = nameOrAdapter;
16380
+ adapter2 = nameOrAdapter;
16258
16381
  if (!isResolvedHandle(nameOrAdapter)) {
16259
- adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];
16260
- if (adapter === void 0) {
16382
+ adapter2 = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];
16383
+ if (adapter2 === void 0) {
16261
16384
  throw new AxiosError_default(`Unknown adapter '${id}'`);
16262
16385
  }
16263
16386
  }
16264
- if (adapter) {
16387
+ if (adapter2 && (utils_default.isFunction(adapter2) || (adapter2 = adapter2.get(config2)))) {
16265
16388
  break;
16266
16389
  }
16267
- rejectedReasons[id || "#" + i] = adapter;
16390
+ rejectedReasons[id || "#" + i] = adapter2;
16268
16391
  }
16269
- if (!adapter) {
16392
+ if (!adapter2) {
16270
16393
  const reasons = Object.entries(rejectedReasons).map(
16271
16394
  ([id, state]) => `adapter ${id} ` + (state === false ? "is not supported by the environment" : "is not available in the build")
16272
16395
  );
@@ -16276,7 +16399,7 @@ var adapters_default = {
16276
16399
  "ERR_NOT_SUPPORT"
16277
16400
  );
16278
16401
  }
16279
- return adapter;
16402
+ return adapter2;
16280
16403
  },
16281
16404
  adapters: knownAdapters
16282
16405
  };
@@ -16300,8 +16423,8 @@ function dispatchRequest(config2) {
16300
16423
  if (["post", "put", "patch"].indexOf(config2.method) !== -1) {
16301
16424
  config2.headers.setContentType("application/x-www-form-urlencoded", false);
16302
16425
  }
16303
- const adapter = adapters_default.getAdapter(config2.adapter || defaults_default.adapter);
16304
- return adapter(config2).then(function onAdapterResolution(response) {
16426
+ const adapter2 = adapters_default.getAdapter(config2.adapter || defaults_default.adapter, config2);
16427
+ return adapter2(config2).then(function onAdapterResolution(response) {
16305
16428
  throwIfCancellationRequested(config2);
16306
16429
  response.data = transformData.call(
16307
16430
  config2,
@@ -16507,7 +16630,6 @@ var Axios = class {
16507
16630
  }
16508
16631
  len = requestInterceptorChain.length;
16509
16632
  let newConfig = config2;
16510
- i = 0;
16511
16633
  while (i < len) {
16512
16634
  const onFulfilled = requestInterceptorChain[i++];
16513
16635
  const onRejected = requestInterceptorChain[i++];
@@ -25700,7 +25822,7 @@ function useRegionService() {
25700
25822
  {
25701
25823
  id: region.toString(),
25702
25824
  name: "Admin",
25703
- type: "region",
25825
+ type: "basic-edu-ro",
25704
25826
  permissions: ["*"],
25705
25827
  status: "active",
25706
25828
  default: true
@@ -26261,7 +26383,7 @@ function useDivisionService() {
26261
26383
  {
26262
26384
  id: division.toString(),
26263
26385
  name: "Admin",
26264
- type: "division",
26386
+ type: "basic-edu-sdo",
26265
26387
  permissions: ["*"],
26266
26388
  status: "active",
26267
26389
  default: true
@@ -26365,11 +26487,8 @@ function useDivisionController() {
26365
26487
  return;
26366
26488
  }
26367
26489
  try {
26368
- const division = await _getById(id);
26369
- res.json({
26370
- message: "Successfully retrieved division.",
26371
- data: { division }
26372
- });
26490
+ const data = await _getById(id);
26491
+ res.json(data);
26373
26492
  return;
26374
26493
  } catch (error2) {
26375
26494
  next(error2);
@@ -26456,16 +26575,17 @@ import Joi31 from "joi";
26456
26575
  import { ObjectId as ObjectId37 } from "mongodb";
26457
26576
  var schemaSchool = Joi31.object({
26458
26577
  _id: Joi31.string().hex().optional().allow("", null),
26459
- id: Joi31.string().required(),
26460
- name: Joi31.string().required(),
26461
- country: Joi31.string().required(),
26462
- address: Joi31.string().required(),
26578
+ id: Joi31.string().optional().allow("", null),
26579
+ name: Joi31.string().optional().allow("", null),
26580
+ country: Joi31.string().optional().allow("", null),
26581
+ address: Joi31.string().optional().allow("", null),
26463
26582
  continuedAddress: Joi31.string().optional().allow("", null),
26464
- city: Joi31.string().required(),
26465
- province: Joi31.string().required(),
26466
- postalCode: Joi31.string().required(),
26467
- courses: Joi31.array().items(Joi31.string()).required(),
26468
- principalName: Joi31.string().required(),
26583
+ city: Joi31.string().required().allow("", null),
26584
+ province: Joi31.string().required().allow("", null),
26585
+ district: Joi31.string().optional().allow("", null),
26586
+ postalCode: Joi31.string().required().allow("", null),
26587
+ courses: Joi31.array().items(Joi31.string()).optional(),
26588
+ principalName: Joi31.string().required().allow("", null),
26469
26589
  principalEmail: Joi31.string().email().optional().allow("", null),
26470
26590
  principalNumber: Joi31.string().optional().allow("", null),
26471
26591
  region: Joi31.string().hex().required(),
@@ -26475,7 +26595,7 @@ var schemaSchool = Joi31.object({
26475
26595
  status: Joi31.string().optional().allow(null, ""),
26476
26596
  createdAt: Joi31.date().optional().allow("", null),
26477
26597
  updatedAt: Joi31.date().optional().allow("", null),
26478
- createdBy: Joi31.string().hex().required()
26598
+ createdBy: Joi31.string().hex().optional().allow("", null)
26479
26599
  });
26480
26600
  function MSchool(value) {
26481
26601
  const { error } = schemaSchool.validate(value);
@@ -26514,15 +26634,15 @@ function MSchool(value) {
26514
26634
  _id: value._id ? value._id : new ObjectId37(),
26515
26635
  id: value.id,
26516
26636
  name: value.name,
26517
- country: value.country,
26518
- address: value.address,
26637
+ country: value.country ?? "",
26638
+ address: value.address ?? "",
26519
26639
  continuedAddress: value.continuedAddress ?? "",
26520
- city: value.city,
26521
- province: value.province,
26522
- postalCode: value.postalCode,
26640
+ city: value.city ?? "",
26641
+ province: value.province ?? "",
26642
+ postalCode: value.postalCode ?? "",
26523
26643
  courses: value.courses || [],
26524
- principalName: value.principalName,
26525
- principalEmail: value.principalEmail,
26644
+ principalName: value.principalName ?? "",
26645
+ principalEmail: value.principalEmail ?? "",
26526
26646
  principalNumber: value.principalNumber ?? "",
26527
26647
  region: value.region,
26528
26648
  regionName: value.regionName ?? "",
@@ -26531,7 +26651,7 @@ function MSchool(value) {
26531
26651
  createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
26532
26652
  updatedAt: value.updatedAt ?? "",
26533
26653
  status: value.status ?? "pending",
26534
- createdBy: value.createdBy
26654
+ createdBy: value.createdBy ?? ""
26535
26655
  };
26536
26656
  }
26537
26657
 
@@ -26806,8 +26926,16 @@ function useSchoolRepo() {
26806
26926
 
26807
26927
  // src/services/school.service.ts
26808
26928
  import { BadRequestError as BadRequestError57, useAtlas as useAtlas30, logger as logger28 } from "@eeplatform/nodejs-utils";
26929
+ import * as XLSX from "xlsx";
26930
+ import * as Papa from "papaparse";
26931
+ import * as BSON from "bson";
26809
26932
  function useSchoolService() {
26810
- const { add, getPendingByCreatedBy, updateStatusById, getPendingById } = useSchoolRepo();
26933
+ const {
26934
+ add: addSchool,
26935
+ getPendingByCreatedBy,
26936
+ updateStatusById,
26937
+ getPendingById
26938
+ } = useSchoolRepo();
26811
26939
  const { addRole } = useRoleRepo();
26812
26940
  const { getUserById } = useUserRepo();
26813
26941
  const { add: addMember } = useMemberRepo();
@@ -26824,7 +26952,7 @@ function useSchoolService() {
26824
26952
  }
26825
26953
  try {
26826
26954
  value.status = "pending";
26827
- await add(value);
26955
+ await addSchool(value);
26828
26956
  return "Request to register school has been sent successfully. Please wait for approval.";
26829
26957
  } catch (error2) {
26830
26958
  throw error2;
@@ -26843,7 +26971,7 @@ function useSchoolService() {
26843
26971
  session.startTransaction();
26844
26972
  school.status = "approved";
26845
26973
  await updateStatusById(id, "active", session);
26846
- const roleType = "school";
26974
+ const roleType = "basic-edu-school";
26847
26975
  const roleName = "Admin";
26848
26976
  const roleId = await addRole(
26849
26977
  {
@@ -26888,9 +27016,245 @@ function useSchoolService() {
26888
27016
  await session.endSession();
26889
27017
  }
26890
27018
  }
27019
+ async function add(value) {
27020
+ const { error } = schemaSchool.validate(value);
27021
+ if (error) {
27022
+ throw new BadRequestError57(error.message);
27023
+ }
27024
+ const session = useAtlas30.getClient()?.startSession();
27025
+ if (!session) {
27026
+ throw new Error("Unable to start session for school service.");
27027
+ }
27028
+ try {
27029
+ session.startTransaction();
27030
+ value.status = "active";
27031
+ const schoolId = await addSchool(value, session);
27032
+ const roleType = "basic-edu-school";
27033
+ const roleName = "Admin";
27034
+ const roleId = await addRole(
27035
+ {
27036
+ id: schoolId.toString(),
27037
+ type: roleType,
27038
+ name: roleName,
27039
+ permissions: ["*"],
27040
+ status: "active",
27041
+ default: true
27042
+ },
27043
+ session
27044
+ );
27045
+ if (!value.createdBy) {
27046
+ throw new BadRequestError57("School must have a creator.");
27047
+ }
27048
+ const user = await getUserById(value.createdBy ?? "");
27049
+ if (!user) {
27050
+ throw new BadRequestError57("User not found for the school creator.");
27051
+ }
27052
+ await addMember(
27053
+ {
27054
+ org: schoolId.toString(),
27055
+ orgName: value.name,
27056
+ user: value.createdBy.toString(),
27057
+ name: `${user.firstName} ${user.lastName}`,
27058
+ role: roleId.toString(),
27059
+ roleName,
27060
+ type: roleType
27061
+ },
27062
+ session
27063
+ );
27064
+ await session.commitTransaction();
27065
+ return "School has been added and activated successfully.";
27066
+ } catch (error2) {
27067
+ logger28.log({
27068
+ level: "error",
27069
+ message: `Error adding school: ${error2.message}`
27070
+ });
27071
+ await session.abortTransaction();
27072
+ throw error2;
27073
+ } finally {
27074
+ await session.endSession();
27075
+ }
27076
+ }
27077
+ async function addBulk(file, region, division) {
27078
+ const MAX_SIZE = 16 * 1024 * 1024;
27079
+ if (file.size > MAX_SIZE) {
27080
+ throw new BadRequestError57(
27081
+ "File size exceeds 16MB limit. Please use a smaller file to ensure transaction compatibility."
27082
+ );
27083
+ }
27084
+ let schools = [];
27085
+ const validatedSchools = [];
27086
+ const totalSize = validatedSchools.reduce(
27087
+ (sum, school) => sum + BSON.calculateObjectSize(school),
27088
+ 0
27089
+ );
27090
+ try {
27091
+ if (file.mimetype.includes("sheet") || file.originalname.endsWith(".xlsx") || file.originalname.endsWith(".xls")) {
27092
+ const workbook = XLSX.read(file.buffer);
27093
+ const sheetName = workbook.SheetNames[0];
27094
+ const worksheet = workbook.Sheets[sheetName];
27095
+ schools = XLSX.utils.sheet_to_json(worksheet);
27096
+ } else if (file.mimetype.includes("csv") || file.originalname.endsWith(".csv")) {
27097
+ const csvText = file.buffer.toString("utf8");
27098
+ const parseResult = Papa.parse(csvText, {
27099
+ header: true,
27100
+ skipEmptyLines: true,
27101
+ transformHeader: (header) => header.trim()
27102
+ });
27103
+ if (parseResult.errors.length > 0) {
27104
+ throw new BadRequestError57(
27105
+ `CSV parsing error: ${parseResult.errors[0].message}`
27106
+ );
27107
+ }
27108
+ schools = parseResult.data;
27109
+ } else {
27110
+ throw new BadRequestError57(
27111
+ "Unsupported file type. Please upload an Excel (.xlsx, .xls) or CSV (.csv) file."
27112
+ );
27113
+ }
27114
+ if (!schools || schools.length === 0) {
27115
+ throw new BadRequestError57("No data found in the uploaded file.");
27116
+ }
27117
+ const errors = [];
27118
+ for (let i = 0; i < schools.length; i++) {
27119
+ const schoolData = schools[i];
27120
+ const rowNumber = i + 1;
27121
+ try {
27122
+ const schoolName = schoolData.schoolName || schoolData.name || "";
27123
+ const schoolId = schoolData.schoolId || schoolData.id || "";
27124
+ const district = schoolData.district || "";
27125
+ if (!schoolName.trim()) {
27126
+ errors.push(`Row ${rowNumber}: School name is required`);
27127
+ continue;
27128
+ }
27129
+ if (!schoolId.trim()) {
27130
+ errors.push(`Row ${rowNumber}: School ID is required`);
27131
+ continue;
27132
+ }
27133
+ if (!district.trim()) {
27134
+ errors.push(`Row ${rowNumber}: District is required`);
27135
+ continue;
27136
+ }
27137
+ const school = {
27138
+ id: schoolId.trim(),
27139
+ name: schoolName.trim(),
27140
+ country: "Philippines",
27141
+ // Default country
27142
+ address: district.trim(),
27143
+ // Use district as address
27144
+ continuedAddress: "",
27145
+ city: district.trim(),
27146
+ // Use district as city
27147
+ province: "",
27148
+ // Will need to be set based on region/division
27149
+ postalCode: "",
27150
+ courses: [],
27151
+ // Empty array for courses
27152
+ principalName: "",
27153
+ principalEmail: "",
27154
+ principalNumber: "",
27155
+ region,
27156
+ regionName: "",
27157
+ // Will be populated from region lookup
27158
+ division,
27159
+ divisionName: "",
27160
+ // Will be populated from division lookup
27161
+ status: "active"
27162
+ };
27163
+ const { error } = schemaSchool.validate(school);
27164
+ if (error) {
27165
+ errors.push(`Row ${rowNumber}: ${error.message}`);
27166
+ continue;
27167
+ }
27168
+ validatedSchools.push(school);
27169
+ } catch (error) {
27170
+ errors.push(
27171
+ `Row ${rowNumber}: ${error.message || "Invalid data format"}`
27172
+ );
27173
+ }
27174
+ }
27175
+ if (errors.length > 0) {
27176
+ throw new BadRequestError57(
27177
+ `Validation errors found:
27178
+ ${errors.slice(0, 10).join("\n")}${errors.length > 10 ? `
27179
+ ... and ${errors.length - 10} more errors` : ""}`
27180
+ );
27181
+ }
27182
+ if (validatedSchools.length === 0) {
27183
+ throw new BadRequestError57(
27184
+ "No valid school records found after validation."
27185
+ );
27186
+ }
27187
+ if (totalSize > MAX_SIZE) {
27188
+ throw new BadRequestError57(
27189
+ `Data payload (${Math.round(
27190
+ totalSize / 1024 / 1024
27191
+ )}MB) exceeds MongoDB transaction limit of 16MB. Please reduce the number of records or split into smaller files.`
27192
+ );
27193
+ }
27194
+ } catch (error) {
27195
+ if (error instanceof BadRequestError57) {
27196
+ throw error;
27197
+ }
27198
+ throw new BadRequestError57(`File processing error: ${error.message}`);
27199
+ }
27200
+ const session = useAtlas30.getClient()?.startSession();
27201
+ if (!session) {
27202
+ throw new Error("Unable to start session for bulk school upload.");
27203
+ }
27204
+ try {
27205
+ session.startTransaction();
27206
+ const results = {
27207
+ successful: 0,
27208
+ failed: 0,
27209
+ errors: []
27210
+ };
27211
+ for (const school of validatedSchools) {
27212
+ try {
27213
+ const schoolId = await addSchool(school, session);
27214
+ await addRole(
27215
+ {
27216
+ id: schoolId.toString(),
27217
+ type: "basic-edu-school",
27218
+ name: "Admin",
27219
+ permissions: ["*"],
27220
+ status: "active",
27221
+ default: true
27222
+ },
27223
+ session
27224
+ );
27225
+ results.successful++;
27226
+ } catch (error) {
27227
+ results.failed++;
27228
+ results.errors.push(`School "${school.name}": ${error.message}`);
27229
+ }
27230
+ }
27231
+ await session.commitTransaction();
27232
+ return {
27233
+ message: `Bulk upload completed. ${results.successful} schools added successfully.`,
27234
+ details: {
27235
+ successful: results.successful,
27236
+ failed: results.failed,
27237
+ total: validatedSchools.length,
27238
+ totalSizeMB: Math.round(totalSize / 1024 / 1024 * 100) / 100,
27239
+ errors: results.errors
27240
+ }
27241
+ };
27242
+ } catch (error) {
27243
+ logger28.log({
27244
+ level: "error",
27245
+ message: `Error in bulk school upload: ${error.message}`
27246
+ });
27247
+ await session.abortTransaction();
27248
+ throw error;
27249
+ } finally {
27250
+ await session.endSession();
27251
+ }
27252
+ }
26891
27253
  return {
26892
27254
  register,
26893
- approve
27255
+ approve,
27256
+ add,
27257
+ addBulk
26894
27258
  };
26895
27259
  }
26896
27260
 
@@ -26899,11 +27263,16 @@ import { BadRequestError as BadRequestError58 } from "@eeplatform/nodejs-utils";
26899
27263
  import Joi32 from "joi";
26900
27264
  function useSchoolController() {
26901
27265
  const {
26902
- add: _add,
26903
27266
  getAll: _getAll,
26904
27267
  getPendingByCreatedBy: _getPendingByCreatedBy,
26905
27268
  updateStatusById: _updateStatusById
26906
27269
  } = useSchoolRepo();
27270
+ const {
27271
+ add: _addSchool,
27272
+ register: _registerSchool,
27273
+ approve,
27274
+ addBulk: _addBulk
27275
+ } = useSchoolService();
26907
27276
  async function add(req, res, next) {
26908
27277
  const payload = req.body;
26909
27278
  const { error } = schemaSchool.validate(payload);
@@ -26912,8 +27281,8 @@ function useSchoolController() {
26912
27281
  return;
26913
27282
  }
26914
27283
  try {
26915
- const school = await _add(payload);
26916
- res.status(201).json(school);
27284
+ const result = await _addSchool(payload);
27285
+ res.status(201).json({ message: result });
26917
27286
  return;
26918
27287
  } catch (error2) {
26919
27288
  next(error2);
@@ -27003,7 +27372,6 @@ function useSchoolController() {
27003
27372
  next(error2);
27004
27373
  }
27005
27374
  }
27006
- const { register: _registerSchool, approve } = useSchoolService();
27007
27375
  async function registerSchool(req, res, next) {
27008
27376
  const payload = req.body;
27009
27377
  const { error } = schemaSchool.validate(payload);
@@ -27038,13 +27406,38 @@ function useSchoolController() {
27038
27406
  next(error2);
27039
27407
  }
27040
27408
  }
27409
+ async function addBulk(req, res, next) {
27410
+ if (!req.file) {
27411
+ res.status(400).send("File is required!");
27412
+ return;
27413
+ }
27414
+ const { region, division } = req.body;
27415
+ const validation = Joi32.object({
27416
+ region: Joi32.string().hex().required(),
27417
+ division: Joi32.string().hex().required()
27418
+ });
27419
+ const { error } = validation.validate({ region, division });
27420
+ if (error) {
27421
+ next(new BadRequestError58(`Validation error: ${error.message}`));
27422
+ return;
27423
+ }
27424
+ try {
27425
+ const result = await _addBulk(req.file, region, division);
27426
+ res.status(201).json(result);
27427
+ return;
27428
+ } catch (error2) {
27429
+ next(error2);
27430
+ return;
27431
+ }
27432
+ }
27041
27433
  return {
27042
27434
  add,
27043
27435
  getAll,
27044
27436
  getByCreatedBy,
27045
27437
  updateStatusById,
27046
27438
  registerSchool,
27047
- approveSchool
27439
+ approveSchool,
27440
+ addBulk
27048
27441
  };
27049
27442
  }
27050
27443
 
@@ -29272,6 +29665,956 @@ function useStockCardController() {
29272
29665
  getSuppliers
29273
29666
  };
29274
29667
  }
29668
+
29669
+ // src/services/github.service.ts
29670
+ import { AppError as AppError16, BadRequestError as BadRequestError72 } from "@eeplatform/nodejs-utils";
29671
+ import { Octokit } from "@octokit/rest";
29672
+ import _sodium from "libsodium-wrappers";
29673
+ function useGitHubService() {
29674
+ function parseRepoUrl(url2) {
29675
+ const match = url2.match(/github\.com[:\/]([^\/]+)\/(.+)\.git$/);
29676
+ if (!match)
29677
+ throw new Error("Invalid GitHub repo URL");
29678
+ return { owner: match[1], repo: match[2] };
29679
+ }
29680
+ async function checkAdminPermission(owner, repo, octokit) {
29681
+ try {
29682
+ const { data: repoData } = await octokit.repos.get({ owner, repo });
29683
+ if (!repoData.permissions?.admin) {
29684
+ throw new BadRequestError72(
29685
+ "You do not have admin access to this repository."
29686
+ );
29687
+ }
29688
+ } catch (error) {
29689
+ if (error.status === 404) {
29690
+ throw new BadRequestError72(
29691
+ "Repository not found or you don't have access to it."
29692
+ );
29693
+ } else if (error.status === 401) {
29694
+ throw new BadRequestError72(
29695
+ "Invalid GitHub token or insufficient permissions."
29696
+ );
29697
+ } else if (error.message.includes("admin access")) {
29698
+ throw error;
29699
+ } else {
29700
+ throw new BadRequestError72(
29701
+ `Failed to check repository permissions: ${error.message}`
29702
+ );
29703
+ }
29704
+ }
29705
+ }
29706
+ async function setVariables(params) {
29707
+ try {
29708
+ const { githubToken, repoUrl, environment, type, keyValues } = params;
29709
+ const octokit = new Octokit({ auth: githubToken });
29710
+ const { owner, repo } = parseRepoUrl(repoUrl);
29711
+ await checkAdminPermission(owner, repo, octokit);
29712
+ const lines = keyValues.split(/[\n\r\s\t]+/).map((l) => l.trim()).filter(Boolean);
29713
+ for (const line of lines) {
29714
+ const equalIndex = line.indexOf("=");
29715
+ if (equalIndex === -1)
29716
+ continue;
29717
+ const key = line.substring(0, equalIndex).trim();
29718
+ const value = line.substring(equalIndex + 1).trim();
29719
+ if (!key || !value)
29720
+ continue;
29721
+ if (type === "secret") {
29722
+ const { data: publicKeyRes } = await octokit.actions.getEnvironmentPublicKey({
29723
+ owner,
29724
+ repo,
29725
+ environment_name: environment
29726
+ });
29727
+ try {
29728
+ await _sodium.ready;
29729
+ const sodium = _sodium;
29730
+ const publicKeyBase64 = publicKeyRes.key;
29731
+ if (!publicKeyBase64) {
29732
+ throw new Error("No public key received from GitHub");
29733
+ }
29734
+ const keyBytes = new Uint8Array(
29735
+ Buffer.from(publicKeyBase64, "base64")
29736
+ );
29737
+ const valueBytes = new Uint8Array(Buffer.from(value, "utf8"));
29738
+ const encryptedBytes = sodium.crypto_box_seal(valueBytes, keyBytes);
29739
+ const encryptedValue = Buffer.from(encryptedBytes).toString("base64");
29740
+ await octokit.actions.createOrUpdateEnvironmentSecret({
29741
+ owner,
29742
+ repo,
29743
+ environment_name: environment,
29744
+ secret_name: key,
29745
+ encrypted_value: encryptedValue,
29746
+ key_id: publicKeyRes.key_id
29747
+ });
29748
+ } catch (encryptionError) {
29749
+ throw new BadRequestError72(
29750
+ `Failed to encrypt secret '${key}': ${encryptionError.message}`
29751
+ );
29752
+ }
29753
+ } else if (type === "env") {
29754
+ await octokit.actions.createEnvironmentVariable({
29755
+ owner,
29756
+ repo,
29757
+ environment_name: environment,
29758
+ name: key,
29759
+ value
29760
+ });
29761
+ }
29762
+ }
29763
+ return `Successfully set ${lines.length} ${type} variables/secrets in environment '${environment}'`;
29764
+ } catch (error) {
29765
+ if (error instanceof AppError16)
29766
+ throw error;
29767
+ if (error.status === 422) {
29768
+ throw new BadRequestError72(
29769
+ `GitHub API validation error: ${error.message}`
29770
+ );
29771
+ } else if (error.status === 404) {
29772
+ throw new BadRequestError72("Environment or repository not found.");
29773
+ } else if (error.status === 403) {
29774
+ throw new BadRequestError72(
29775
+ "Forbidden: Insufficient permissions or rate limit exceeded."
29776
+ );
29777
+ } else if (error.message.includes("admin access") || error.message.includes("permissions")) {
29778
+ throw error;
29779
+ } else {
29780
+ throw new BadRequestError72(
29781
+ `Failed to set GitHub variables: ${error.message}`
29782
+ );
29783
+ }
29784
+ }
29785
+ }
29786
+ return {
29787
+ setVariables
29788
+ };
29789
+ }
29790
+
29791
+ // src/controllers/util.controller.ts
29792
+ import Joi40 from "joi";
29793
+ import {
29794
+ AppError as AppError17,
29795
+ BadRequestError as BadRequestError73,
29796
+ InternalServerError as InternalServerError27,
29797
+ logger as logger35
29798
+ } from "@eeplatform/nodejs-utils";
29799
+ function useUtilController() {
29800
+ async function healthCheck(req, res, next) {
29801
+ try {
29802
+ res.status(200).json({
29803
+ success: true,
29804
+ message: "Util service is healthy",
29805
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
29806
+ data: {
29807
+ availableEndpoints: [
29808
+ "POST /github/variables - Set GitHub environment variables or secrets"
29809
+ ],
29810
+ keyValueFormat: "KEY=value pairs separated by newlines, spaces, or tabs"
29811
+ }
29812
+ });
29813
+ } catch (error) {
29814
+ logger35.error("Health check failed", { error: error.message });
29815
+ next(new InternalServerError27("Health check failed"));
29816
+ }
29817
+ }
29818
+ async function setGitHubVariables(req, res, next) {
29819
+ try {
29820
+ const { githubToken, repoUrl, environment, type, keyValues } = req.body;
29821
+ const validation = Joi40.object({
29822
+ githubToken: Joi40.string().required().messages({
29823
+ "string.empty": "GitHub token is required",
29824
+ "any.required": "GitHub token is required"
29825
+ }),
29826
+ repoUrl: Joi40.string().uri().required().messages({
29827
+ "string.empty": "Repository URL is required",
29828
+ "string.uri": "Repository URL must be a valid URL",
29829
+ "any.required": "Repository URL is required"
29830
+ }),
29831
+ environment: Joi40.string().required().messages({
29832
+ "string.empty": "Environment name is required",
29833
+ "any.required": "Environment name is required"
29834
+ }),
29835
+ type: Joi40.string().valid("env", "secret").required().messages({
29836
+ "any.only": 'Type must be either "env" or "secret"',
29837
+ "any.required": "Type is required"
29838
+ }),
29839
+ keyValues: Joi40.string().required().messages({
29840
+ "string.empty": "Key-value pairs are required",
29841
+ "any.required": "Key-value pairs are required"
29842
+ })
29843
+ });
29844
+ const { error } = validation.validate({
29845
+ githubToken,
29846
+ repoUrl,
29847
+ environment,
29848
+ type,
29849
+ keyValues
29850
+ });
29851
+ if (error) {
29852
+ next(new BadRequestError73(error.message));
29853
+ return;
29854
+ }
29855
+ const repoUrlPattern = /github\.com[:\/]([^\/]+)\/(.+)\.git$/;
29856
+ if (!repoUrlPattern.test(repoUrl)) {
29857
+ next(
29858
+ new BadRequestError73(
29859
+ "Invalid GitHub repository URL format. Expected format: https://github.com/owner/repo.git"
29860
+ )
29861
+ );
29862
+ return;
29863
+ }
29864
+ const lines = keyValues.split(/[\n\r\s\t]+/).map((l) => l.trim()).filter(Boolean);
29865
+ const invalidLines = lines.filter(
29866
+ (line) => !line.includes("=") || line.indexOf("=") === -1
29867
+ );
29868
+ if (invalidLines.length > 0) {
29869
+ next(
29870
+ new BadRequestError73(
29871
+ "Invalid key-value format. Each pair should be in format: KEY=value. Pairs can be separated by newlines, spaces, or tabs."
29872
+ )
29873
+ );
29874
+ return;
29875
+ }
29876
+ const githubService = useGitHubService();
29877
+ const result = await githubService.setVariables({
29878
+ githubToken,
29879
+ repoUrl,
29880
+ environment,
29881
+ type,
29882
+ keyValues
29883
+ });
29884
+ logger35.info(`GitHub variables set successfully`, {
29885
+ repoUrl,
29886
+ environment,
29887
+ type,
29888
+ count: lines.length
29889
+ });
29890
+ res.status(200).json({
29891
+ success: true,
29892
+ message: result,
29893
+ data: {
29894
+ repoUrl,
29895
+ environment,
29896
+ type,
29897
+ variablesSet: lines.length
29898
+ }
29899
+ });
29900
+ } catch (error) {
29901
+ logger35.error("Failed to set GitHub variables", {
29902
+ error: error.message,
29903
+ stack: error.stack
29904
+ });
29905
+ if (error instanceof AppError17) {
29906
+ next(error);
29907
+ } else {
29908
+ next(
29909
+ new InternalServerError27(
29910
+ `Failed to set GitHub variables: ${error.message}`
29911
+ )
29912
+ );
29913
+ }
29914
+ }
29915
+ }
29916
+ return {
29917
+ healthCheck,
29918
+ setGitHubVariables
29919
+ };
29920
+ }
29921
+
29922
+ // src/models/plantilla.model.ts
29923
+ import { BadRequestError as BadRequestError74 } from "@eeplatform/nodejs-utils";
29924
+ import Joi41 from "joi";
29925
+ import { ObjectId as ObjectId46 } from "mongodb";
29926
+ var schemaPlantilla = Joi41.object({
29927
+ _id: Joi41.string().hex().optional().allow(null, ""),
29928
+ itemNumber: Joi41.string().required(),
29929
+ positionTitle: Joi41.string().required(),
29930
+ positionCategory: Joi41.string().required(),
29931
+ region: Joi41.string().hex().optional().allow(null, ""),
29932
+ regionName: Joi41.string().optional().allow(null, ""),
29933
+ division: Joi41.string().hex().optional().allow(null, ""),
29934
+ divisionName: Joi41.string().optional().allow(null, ""),
29935
+ salaryGrade: Joi41.number().required(),
29936
+ step: Joi41.number().optional().allow(null, 0),
29937
+ incumbent: Joi41.string().optional().allow(null, ""),
29938
+ annualSalary: Joi41.number().optional().allow(null, 0),
29939
+ monthlySalary: Joi41.number().optional().allow(null, 0),
29940
+ status: Joi41.string().required(),
29941
+ employee: Joi41.string().hex().optional().allow(null, ""),
29942
+ createdAt: Joi41.date().iso().optional().allow(null, ""),
29943
+ updatedAt: Joi41.date().iso().optional().allow(null, ""),
29944
+ deletedAt: Joi41.date().iso().optional().allow(null, "")
29945
+ });
29946
+ function MPlantilla(data) {
29947
+ const { error } = schemaPlantilla.validate(data);
29948
+ if (error) {
29949
+ throw new BadRequestError74(error.message);
29950
+ }
29951
+ if (data._id && typeof data._id === "string") {
29952
+ try {
29953
+ data._id = new ObjectId46(data._id);
29954
+ } catch (error2) {
29955
+ throw new BadRequestError74("Invalid _id.");
29956
+ }
29957
+ }
29958
+ return {
29959
+ _id: data._id,
29960
+ itemNumber: data.itemNumber ?? "",
29961
+ positionTitle: data.positionTitle ?? "",
29962
+ positionCategory: data.positionCategory ?? "",
29963
+ status: data.status ?? "active",
29964
+ salaryGrade: data.salaryGrade ?? 0,
29965
+ step: data.step ?? 0,
29966
+ monthlySalary: data.monthlySalary ?? 0,
29967
+ annualSalary: data.annualSalary ?? 0,
29968
+ region: data.region ?? "",
29969
+ regionName: data.regionName ?? "",
29970
+ division: data.division ?? "",
29971
+ divisionName: data.divisionName ?? "",
29972
+ incumbent: data.incumbent ?? "",
29973
+ createdAt: data.createdAt ? new Date(data.createdAt) : /* @__PURE__ */ new Date(),
29974
+ updatedAt: data.updatedAt ? new Date(data.updatedAt) : "",
29975
+ deletedAt: data.deletedAt ? new Date(data.deletedAt) : ""
29976
+ };
29977
+ }
29978
+
29979
+ // src/repositories/plantilla.repository.ts
29980
+ import {
29981
+ AppError as AppError18,
29982
+ BadRequestError as BadRequestError75,
29983
+ InternalServerError as InternalServerError28,
29984
+ logger as logger36,
29985
+ makeCacheKey as makeCacheKey23,
29986
+ paginate as paginate19,
29987
+ useAtlas as useAtlas38,
29988
+ useCache as useCache24
29989
+ } from "@eeplatform/nodejs-utils";
29990
+ import { ObjectId as ObjectId47 } from "mongodb";
29991
+ function usePlantillaRepo() {
29992
+ const db = useAtlas38.getDb();
29993
+ if (!db) {
29994
+ throw new Error("Unable to connect to server.");
29995
+ }
29996
+ const namespace_collection = "plantillas";
29997
+ const collection = db.collection(namespace_collection);
29998
+ const { getCache, setCache, delNamespace } = useCache24(namespace_collection);
29999
+ async function createIndexes() {
30000
+ try {
30001
+ await collection.createIndexes([
30002
+ { key: { name: 1 }, unique: true, name: "unique_name_index" },
30003
+ { key: { school: 1 } },
30004
+ { key: { status: 1 } }
30005
+ ]);
30006
+ } catch (error) {
30007
+ throw new Error("Failed to create index on plantillas.");
30008
+ }
30009
+ }
30010
+ async function add(value, session, clearCache = true) {
30011
+ console.log(value);
30012
+ try {
30013
+ value = MPlantilla(value);
30014
+ const res = await collection.insertOne(value, { session });
30015
+ if (clearCache) {
30016
+ delCachedData();
30017
+ }
30018
+ return res.insertedId;
30019
+ } catch (error) {
30020
+ logger36.log({
30021
+ level: "error",
30022
+ message: error.message
30023
+ });
30024
+ if (error instanceof AppError18) {
30025
+ throw error;
30026
+ } else {
30027
+ const isDuplicated = error.message.includes("duplicate");
30028
+ if (isDuplicated) {
30029
+ throw new BadRequestError75("Plantilla already exists.");
30030
+ }
30031
+ throw new Error("Failed to create plantilla.");
30032
+ }
30033
+ }
30034
+ }
30035
+ async function updateById(_id, value, session) {
30036
+ try {
30037
+ _id = new ObjectId47(_id);
30038
+ } catch (error) {
30039
+ throw new BadRequestError75("Invalid ID.");
30040
+ }
30041
+ value.updatedAt = /* @__PURE__ */ new Date();
30042
+ try {
30043
+ const res = await collection.updateOne(
30044
+ { _id },
30045
+ { $set: value },
30046
+ { session }
30047
+ );
30048
+ delCachedData();
30049
+ return res;
30050
+ } catch (error) {
30051
+ logger36.log({
30052
+ level: "error",
30053
+ message: error.message
30054
+ });
30055
+ if (error instanceof AppError18) {
30056
+ throw error;
30057
+ } else {
30058
+ throw new Error("Failed to update plantilla.");
30059
+ }
30060
+ }
30061
+ }
30062
+ async function getAll({
30063
+ search = "",
30064
+ page = 1,
30065
+ limit = 10,
30066
+ sort = {},
30067
+ org = "",
30068
+ status = "active"
30069
+ } = {}) {
30070
+ page = page > 0 ? page - 1 : 0;
30071
+ const query = {
30072
+ status
30073
+ };
30074
+ sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
30075
+ if (search) {
30076
+ query.$text = { $search: search };
30077
+ }
30078
+ if (org) {
30079
+ try {
30080
+ query.org = new ObjectId47(org);
30081
+ } catch (error) {
30082
+ throw new BadRequestError75("Invalid org ID.");
30083
+ }
30084
+ }
30085
+ const cacheParams = {
30086
+ page,
30087
+ limit,
30088
+ sort: JSON.stringify(sort)
30089
+ };
30090
+ if (search)
30091
+ cacheParams.search = search;
30092
+ if (org)
30093
+ cacheParams.org = org;
30094
+ if (status !== "active")
30095
+ cacheParams.status = status;
30096
+ const cacheKey = makeCacheKey23(namespace_collection, cacheParams);
30097
+ logger36.log({
30098
+ level: "info",
30099
+ message: `Cache key for getAll plantillas: ${cacheKey}`
30100
+ });
30101
+ try {
30102
+ const cached = await getCache(cacheKey);
30103
+ if (cached) {
30104
+ logger36.log({
30105
+ level: "info",
30106
+ message: `Cache hit for getAll plantillas: ${cacheKey}`
30107
+ });
30108
+ return cached;
30109
+ }
30110
+ const items = await collection.aggregate([
30111
+ { $match: query },
30112
+ { $sort: sort },
30113
+ { $skip: page * limit },
30114
+ { $limit: limit }
30115
+ ]).toArray();
30116
+ const length = await collection.countDocuments(query);
30117
+ const data = paginate19(items, page, limit, length);
30118
+ setCache(cacheKey, data, 600).then(() => {
30119
+ logger36.log({
30120
+ level: "info",
30121
+ message: `Cache set for getAll plantillas: ${cacheKey}`
30122
+ });
30123
+ }).catch((err) => {
30124
+ logger36.log({
30125
+ level: "error",
30126
+ message: `Failed to set cache for getAll plantillas: ${err.message}`
30127
+ });
30128
+ });
30129
+ return data;
30130
+ } catch (error) {
30131
+ logger36.log({ level: "error", message: `${error}` });
30132
+ throw error;
30133
+ }
30134
+ }
30135
+ async function getById(_id) {
30136
+ try {
30137
+ _id = new ObjectId47(_id);
30138
+ } catch (error) {
30139
+ throw new BadRequestError75("Invalid ID.");
30140
+ }
30141
+ const cacheKey = makeCacheKey23(namespace_collection, { _id: String(_id) });
30142
+ try {
30143
+ const cached = await getCache(cacheKey);
30144
+ if (cached) {
30145
+ logger36.log({
30146
+ level: "info",
30147
+ message: `Cache hit for getById plantilla: ${cacheKey}`
30148
+ });
30149
+ return cached;
30150
+ }
30151
+ const result = await collection.findOne({
30152
+ _id
30153
+ });
30154
+ setCache(cacheKey, result, 300).then(() => {
30155
+ logger36.log({
30156
+ level: "info",
30157
+ message: `Cache set for plantilla by id: ${cacheKey}`
30158
+ });
30159
+ }).catch((err) => {
30160
+ logger36.log({
30161
+ level: "error",
30162
+ message: `Failed to set cache for plantilla by id: ${err.message}`
30163
+ });
30164
+ });
30165
+ return result;
30166
+ } catch (error) {
30167
+ if (error instanceof AppError18) {
30168
+ throw error;
30169
+ } else {
30170
+ throw new InternalServerError28("Failed to get plantilla.");
30171
+ }
30172
+ }
30173
+ }
30174
+ async function deleteById(_id, session) {
30175
+ try {
30176
+ _id = new ObjectId47(_id);
30177
+ } catch (error) {
30178
+ throw new BadRequestError75("Invalid ID.");
30179
+ }
30180
+ try {
30181
+ const res = await collection.updateOne(
30182
+ { _id },
30183
+ { $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
30184
+ );
30185
+ delCachedData();
30186
+ return res;
30187
+ } catch (error) {
30188
+ logger36.log({
30189
+ level: "error",
30190
+ message: error.message
30191
+ });
30192
+ if (error instanceof AppError18) {
30193
+ throw error;
30194
+ } else {
30195
+ throw new InternalServerError28("Failed to delete plantilla.");
30196
+ }
30197
+ }
30198
+ }
30199
+ function delCachedData() {
30200
+ delNamespace().then(() => {
30201
+ logger36.log({
30202
+ level: "info",
30203
+ message: `Cache namespace cleared for ${namespace_collection}`
30204
+ });
30205
+ }).catch((err) => {
30206
+ logger36.log({
30207
+ level: "error",
30208
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
30209
+ });
30210
+ });
30211
+ }
30212
+ return {
30213
+ createIndexes,
30214
+ add,
30215
+ getAll,
30216
+ getById,
30217
+ updateById,
30218
+ deleteById,
30219
+ delCachedData
30220
+ };
30221
+ }
30222
+
30223
+ // src/controllers/plantilla.controller.ts
30224
+ import { BadRequestError as BadRequestError77 } from "@eeplatform/nodejs-utils";
30225
+ import Joi42 from "joi";
30226
+
30227
+ // src/services/plantilla.service.ts
30228
+ import { BadRequestError as BadRequestError76, useAtlas as useAtlas39, logger as logger37 } from "@eeplatform/nodejs-utils";
30229
+ import * as XLSX2 from "xlsx";
30230
+ import * as Papa2 from "papaparse";
30231
+ function usePlantillaService() {
30232
+ const { add: addPlantilla, delCachedData } = usePlantillaRepo();
30233
+ async function addBulk(file, region, division) {
30234
+ logger37.log({
30235
+ level: "info",
30236
+ message: `Starting plantilla bulk upload. File: ${file.originalname}, Size: ${file.size} bytes`
30237
+ });
30238
+ const MAX_SIZE = 16 * 1024 * 1024;
30239
+ let plantillas = [];
30240
+ let totalSize = 0;
30241
+ let validatedPlantillas = [];
30242
+ if (!file.buffer) {
30243
+ throw new BadRequestError76("File buffer is empty or corrupted");
30244
+ }
30245
+ try {
30246
+ const fileExtension = file.originalname.split(".").pop()?.toLowerCase();
30247
+ if (fileExtension === "csv") {
30248
+ const csvData = file.buffer.toString("utf-8");
30249
+ totalSize = Buffer.byteLength(csvData, "utf8");
30250
+ const parseResult = Papa2.parse(csvData, {
30251
+ header: true,
30252
+ skipEmptyLines: true,
30253
+ transformHeader: (header) => {
30254
+ return header.toLowerCase().replace(/\s+/g, "").replace(/[^\w]/g, "");
30255
+ }
30256
+ });
30257
+ if (parseResult.errors.length > 0) {
30258
+ throw new BadRequestError76(
30259
+ `CSV parsing errors: ${parseResult.errors.map((e) => e.message).join(", ")}`
30260
+ );
30261
+ }
30262
+ plantillas = parseResult.data;
30263
+ } else if (fileExtension === "xlsx" || fileExtension === "xls") {
30264
+ totalSize = file.buffer.length;
30265
+ const workbook = XLSX2.read(file.buffer, { type: "buffer" });
30266
+ const sheetName = workbook.SheetNames[0];
30267
+ const worksheet = workbook.Sheets[sheetName];
30268
+ plantillas = XLSX2.utils.sheet_to_json(worksheet, {
30269
+ header: 1,
30270
+ defval: ""
30271
+ });
30272
+ if (plantillas.length === 0) {
30273
+ throw new BadRequestError76("Excel file is empty.");
30274
+ }
30275
+ const headers = plantillas[0];
30276
+ const normalizedHeaders = headers.map(
30277
+ (header) => header.toLowerCase().replace(/\s+/g, "").replace(/[^\w]/g, "")
30278
+ );
30279
+ plantillas = plantillas.slice(1).map((row) => {
30280
+ const obj = {};
30281
+ normalizedHeaders.forEach((header, index) => {
30282
+ obj[header] = row[index] || "";
30283
+ });
30284
+ return obj;
30285
+ });
30286
+ } else {
30287
+ throw new BadRequestError76(
30288
+ "Unsupported file type. Please upload an Excel (.xlsx, .xls) or CSV (.csv) file."
30289
+ );
30290
+ }
30291
+ if (!plantillas || plantillas.length === 0) {
30292
+ throw new BadRequestError76("No data found in the uploaded file.");
30293
+ }
30294
+ const errors = [];
30295
+ for (let i = 0; i < plantillas.length; i++) {
30296
+ const plantillaData = plantillas[i];
30297
+ const rowNumber = i + 1;
30298
+ try {
30299
+ const itemNumber = plantillaData.itemnumber || plantillaData.item_number || "";
30300
+ const positionTitle = plantillaData.positiontitle || plantillaData.position_title || plantillaData.title || "";
30301
+ const positionCategory = plantillaData.positioncategory || plantillaData.position_category || "";
30302
+ const status = plantillaData.status || "active";
30303
+ if (!itemNumber.trim()) {
30304
+ errors.push(`Row ${rowNumber}: Item Number is required`);
30305
+ continue;
30306
+ }
30307
+ if (!positionTitle.trim()) {
30308
+ errors.push(`Row ${rowNumber}: Position Title is required`);
30309
+ continue;
30310
+ }
30311
+ if (!positionCategory.trim()) {
30312
+ errors.push(`Row ${rowNumber}: Position Category is required`);
30313
+ continue;
30314
+ }
30315
+ const plantilla = {
30316
+ itemNumber: itemNumber.trim(),
30317
+ positionTitle: positionTitle.trim(),
30318
+ positionCategory: positionCategory.trim(),
30319
+ salaryGrade: parseInt(
30320
+ plantillaData.salarygrade || plantillaData.salary_grade || "1"
30321
+ ) || 1,
30322
+ step: parseInt(plantillaData.step || "1") || 1,
30323
+ status: status.trim() || "active"
30324
+ };
30325
+ if (region)
30326
+ plantilla.region = region;
30327
+ if (division)
30328
+ plantilla.division = division;
30329
+ if (plantillaData.regionname || plantillaData.region_name) {
30330
+ plantilla.regionName = plantillaData.regionname || plantillaData.region_name;
30331
+ }
30332
+ if (plantillaData.divisionname || plantillaData.division_name) {
30333
+ plantilla.divisionName = plantillaData.divisionname || plantillaData.division_name;
30334
+ }
30335
+ if (plantillaData.incumbent) {
30336
+ plantilla.incumbent = plantillaData.incumbent;
30337
+ }
30338
+ if (plantillaData.employee) {
30339
+ plantilla.employee = plantillaData.employee;
30340
+ }
30341
+ if (plantillaData.annualsalary || plantillaData.annual_salary) {
30342
+ plantilla.annualSalary = parseFloat(
30343
+ plantillaData.annualsalary || plantillaData.annual_salary
30344
+ ) || void 0;
30345
+ }
30346
+ if (plantillaData.monthlysalary || plantillaData.monthly_salary) {
30347
+ plantilla.monthlySalary = parseFloat(
30348
+ plantillaData.monthlysalary || plantillaData.monthly_salary
30349
+ ) || void 0;
30350
+ }
30351
+ if (!plantilla.itemNumber || !plantilla.positionTitle || !plantilla.positionCategory) {
30352
+ errors.push(`Row ${rowNumber}: Missing required fields`);
30353
+ continue;
30354
+ }
30355
+ validatedPlantillas.push(plantilla);
30356
+ } catch (error) {
30357
+ errors.push(
30358
+ `Row ${rowNumber}: ${error.message || "Invalid data format"}`
30359
+ );
30360
+ }
30361
+ }
30362
+ if (errors.length > 0) {
30363
+ throw new BadRequestError76(
30364
+ `Validation errors found:
30365
+ ${errors.slice(0, 10).join("\n")}${errors.length > 10 ? `
30366
+ ... and ${errors.length - 10} more errors` : ""}`
30367
+ );
30368
+ }
30369
+ if (validatedPlantillas.length === 0) {
30370
+ throw new BadRequestError76(
30371
+ "No valid plantilla records found after validation."
30372
+ );
30373
+ }
30374
+ if (totalSize > MAX_SIZE) {
30375
+ throw new BadRequestError76(
30376
+ `Data payload (${Math.round(
30377
+ totalSize / 1024 / 1024
30378
+ )}MB) exceeds MongoDB transaction limit of 16MB. Please reduce the number of records or split into smaller files.`
30379
+ );
30380
+ }
30381
+ } catch (error) {
30382
+ if (error instanceof BadRequestError76) {
30383
+ throw error;
30384
+ }
30385
+ throw new BadRequestError76(`File processing error: ${error.message}`);
30386
+ }
30387
+ const session = useAtlas39.getClient()?.startSession();
30388
+ if (!session) {
30389
+ throw new Error("Unable to start session for bulk plantilla upload.");
30390
+ }
30391
+ logger37.log({
30392
+ level: "info",
30393
+ message: `Starting bulk plantilla upload with ${validatedPlantillas.length} records`
30394
+ });
30395
+ try {
30396
+ session.startTransaction();
30397
+ const results = {
30398
+ successful: 0,
30399
+ failed: 0,
30400
+ errors: []
30401
+ };
30402
+ const promises = [];
30403
+ for (let i = 0; i < validatedPlantillas.length; i++) {
30404
+ const plantilla = validatedPlantillas[i];
30405
+ promises.push(addPlantilla(plantilla, session, false));
30406
+ }
30407
+ await Promise.all(promises);
30408
+ await delCachedData();
30409
+ await session.commitTransaction();
30410
+ return {
30411
+ message: `Bulk upload completed. ${results.successful} plantillas added successfully.`,
30412
+ details: {
30413
+ successful: results.successful,
30414
+ failed: results.failed,
30415
+ total: validatedPlantillas.length,
30416
+ totalSizeMB: Math.round(totalSize / 1024 / 1024 * 100) / 100,
30417
+ errors: results.errors
30418
+ }
30419
+ };
30420
+ } catch (error) {
30421
+ logger37.log({
30422
+ level: "error",
30423
+ message: `Error in bulk plantilla upload: ${error.message}`
30424
+ });
30425
+ await session.abortTransaction();
30426
+ throw error;
30427
+ } finally {
30428
+ await session.endSession();
30429
+ }
30430
+ }
30431
+ return {
30432
+ addBulk
30433
+ };
30434
+ }
30435
+
30436
+ // src/controllers/plantilla.controller.ts
30437
+ function usePlantillaController() {
30438
+ const {
30439
+ add: _addPlantilla,
30440
+ getAll: _getAllPlantillas,
30441
+ getById: _getPlantillaById,
30442
+ updateById: _updatePlantillaById,
30443
+ deleteById: _deletePlantillaById
30444
+ } = usePlantillaRepo();
30445
+ const { addBulk: _addBulk } = usePlantillaService();
30446
+ async function createPlantilla(req, res, next) {
30447
+ const value = req.body;
30448
+ const validation = Joi42.object({
30449
+ itemNumber: Joi42.string().required(),
30450
+ positionTitle: Joi42.string().required(),
30451
+ positionCategory: Joi42.string().required(),
30452
+ status: Joi42.string().required()
30453
+ });
30454
+ const { error } = validation.validate(value);
30455
+ if (error) {
30456
+ next(new BadRequestError77(error.message));
30457
+ return;
30458
+ }
30459
+ try {
30460
+ const id = await _addPlantilla(value);
30461
+ res.json({ message: "Plantilla created successfully", id });
30462
+ return;
30463
+ } catch (error2) {
30464
+ next(error2);
30465
+ }
30466
+ }
30467
+ async function getAllPlantillas(req, res, next) {
30468
+ const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
30469
+ const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
30470
+ const search = req.query.search ?? "";
30471
+ const org = req.query.org ?? "";
30472
+ const isPageNumber = isFinite(page);
30473
+ if (!isPageNumber) {
30474
+ next(new BadRequestError77("Invalid page number."));
30475
+ return;
30476
+ }
30477
+ const isLimitNumber = isFinite(limit);
30478
+ if (!isLimitNumber) {
30479
+ next(new BadRequestError77("Invalid limit number."));
30480
+ return;
30481
+ }
30482
+ const validation = Joi42.object({
30483
+ page: Joi42.number().min(1).optional().allow("", null),
30484
+ limit: Joi42.number().min(1).optional().allow("", null),
30485
+ search: Joi42.string().optional().allow("", null),
30486
+ org: Joi42.string().optional().allow("", null)
30487
+ });
30488
+ const { error } = validation.validate({ page, limit, search, org });
30489
+ if (error) {
30490
+ next(new BadRequestError77(error.message));
30491
+ return;
30492
+ }
30493
+ try {
30494
+ const plantillas = await _getAllPlantillas({
30495
+ search,
30496
+ page,
30497
+ limit,
30498
+ org
30499
+ });
30500
+ res.json(plantillas);
30501
+ return;
30502
+ } catch (error2) {
30503
+ next(error2);
30504
+ }
30505
+ }
30506
+ async function getPlantillaById(req, res, next) {
30507
+ const id = req.params.id;
30508
+ const validation = Joi42.object({
30509
+ id: Joi42.string().hex().required()
30510
+ });
30511
+ const { error } = validation.validate({ id });
30512
+ if (error) {
30513
+ next(new BadRequestError77(error.message));
30514
+ return;
30515
+ }
30516
+ try {
30517
+ const plantilla = await _getPlantillaById(id);
30518
+ if (!plantilla) {
30519
+ next(new BadRequestError77("Plantilla not found."));
30520
+ return;
30521
+ }
30522
+ res.json(plantilla);
30523
+ return;
30524
+ } catch (error2) {
30525
+ next(error2);
30526
+ }
30527
+ }
30528
+ async function updatePlantilla(req, res, next) {
30529
+ const id = req.params.id;
30530
+ const value = req.body;
30531
+ const validation = Joi42.object({
30532
+ id: Joi42.string().hex().required(),
30533
+ employee: Joi42.string().hex().optional().allow(null, ""),
30534
+ status: Joi42.string().optional(),
30535
+ positionTitle: Joi42.string().optional(),
30536
+ positionCategory: Joi42.string().optional()
30537
+ });
30538
+ const { error } = validation.validate({ id, ...value });
30539
+ if (error) {
30540
+ next(new BadRequestError77(error.message));
30541
+ return;
30542
+ }
30543
+ try {
30544
+ const result = await _updatePlantillaById(id, value);
30545
+ if (result.matchedCount === 0) {
30546
+ next(new BadRequestError77("Plantilla not found."));
30547
+ return;
30548
+ }
30549
+ res.json({ message: "Plantilla updated successfully" });
30550
+ return;
30551
+ } catch (error2) {
30552
+ next(error2);
30553
+ }
30554
+ }
30555
+ async function deletePlantilla(req, res, next) {
30556
+ const id = req.params.id;
30557
+ const validation = Joi42.object({
30558
+ id: Joi42.string().hex().required()
30559
+ });
30560
+ const { error } = validation.validate({ id });
30561
+ if (error) {
30562
+ next(new BadRequestError77(error.message));
30563
+ return;
30564
+ }
30565
+ try {
30566
+ const result = await _deletePlantillaById(id);
30567
+ if (result.matchedCount === 0) {
30568
+ next(new BadRequestError77("Plantilla not found."));
30569
+ return;
30570
+ }
30571
+ res.json({ message: "Plantilla deleted successfully" });
30572
+ return;
30573
+ } catch (error2) {
30574
+ next(error2);
30575
+ }
30576
+ }
30577
+ async function bulkAddPlantillas(req, res, next) {
30578
+ if (!req.file) {
30579
+ res.status(400).send("File is required!");
30580
+ return;
30581
+ }
30582
+ const { region, division } = req.body;
30583
+ const validation = Joi42.object({
30584
+ region: Joi42.string().hex().optional(),
30585
+ division: Joi42.string().hex().optional()
30586
+ });
30587
+ const { error } = validation.validate({ region, division });
30588
+ if (error) {
30589
+ next(new BadRequestError77(`Validation error: ${error.message}`));
30590
+ return;
30591
+ }
30592
+ if (!region && !division) {
30593
+ next(
30594
+ new BadRequestError77(
30595
+ "At least one of region or division must be provided"
30596
+ )
30597
+ );
30598
+ return;
30599
+ }
30600
+ try {
30601
+ const result = await _addBulk(req.file, region, division);
30602
+ res.status(201).json(result);
30603
+ return;
30604
+ } catch (error2) {
30605
+ next(error2);
30606
+ return;
30607
+ }
30608
+ }
30609
+ return {
30610
+ createPlantilla,
30611
+ getAllPlantillas,
30612
+ getPlantillaById,
30613
+ updatePlantilla,
30614
+ deletePlantilla,
30615
+ bulkAddPlantillas
30616
+ };
30617
+ }
29275
30618
  export {
29276
30619
  ACCESS_TOKEN_EXPIRY,
29277
30620
  ACCESS_TOKEN_SECRET,
@@ -29302,6 +30645,7 @@ export {
29302
30645
  MOrder,
29303
30646
  MOrg,
29304
30647
  MPaymentMethod,
30648
+ MPlantilla,
29305
30649
  MPromoCode,
29306
30650
  MRegion,
29307
30651
  MRole,
@@ -29339,6 +30683,7 @@ export {
29339
30683
  schemaBuilding,
29340
30684
  schemaBuildingUnit,
29341
30685
  schemaDivision,
30686
+ schemaPlantilla,
29342
30687
  schemaRegion,
29343
30688
  schemaSchool,
29344
30689
  schemaStockCard,
@@ -29363,6 +30708,7 @@ export {
29363
30708
  useFileController,
29364
30709
  useFileRepo,
29365
30710
  useFileService,
30711
+ useGitHubService,
29366
30712
  useInvoiceController,
29367
30713
  useInvoiceModel,
29368
30714
  useInvoiceRepo,
@@ -29381,6 +30727,8 @@ export {
29381
30727
  usePaymentModel,
29382
30728
  usePaymentRepo,
29383
30729
  usePaypalService,
30730
+ usePlantillaController,
30731
+ usePlantillaRepo,
29384
30732
  usePriceController,
29385
30733
  usePriceModel,
29386
30734
  usePriceRepo,
@@ -29403,6 +30751,7 @@ export {
29403
30751
  useUserController,
29404
30752
  useUserRepo,
29405
30753
  useUserService,
30754
+ useUtilController,
29406
30755
  useVerificationController,
29407
30756
  useVerificationRepo,
29408
30757
  useVerificationService,