@arkstack/common 0.14.19 → 0.14.21

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.
@@ -0,0 +1,9 @@
1
+ import { Faker, ImageModule } from "@faker-js/faker";
2
+ import { PictwoFakerImage } from "@pictwo/faker";
3
+
4
+ //#region src/faker.d.ts
5
+ declare const faker: Faker & {
6
+ image: ImageModule & PictwoFakerImage;
7
+ };
8
+ //#endregion
9
+ export { faker };
package/dist/faker.js ADDED
@@ -0,0 +1,20 @@
1
+ import { v as configLoader } from "./system-DUaI4u99.js";
2
+ import * as fakerLocales from "@faker-js/faker";
3
+ import { Faker } from "@faker-js/faker";
4
+ import { pictwoImage } from "@pictwo/faker";
5
+ //#region src/faker.ts
6
+ const config = globalThis.config ?? ((key, def) => configLoader.resolve(key, def));
7
+ const fallbackLocale = "en";
8
+ const resolveLocale = () => {
9
+ const locale = config("app.locale", fallbackLocale);
10
+ if (typeof locale === "string" && locale in fakerLocales && typeof fakerLocales[locale] === "object") return fakerLocales[locale];
11
+ return fakerLocales[fallbackLocale];
12
+ };
13
+ const fakerInstance = new Faker({ locale: [resolveLocale()].filter(Boolean) });
14
+ const { faker: _, ...image } = fakerInstance.image;
15
+ const faker = {
16
+ ...fakerInstance,
17
+ image: Object.assign({}, image, pictwoImage())
18
+ };
19
+ //#endregion
20
+ export { faker };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /// <reference path="./app.d.ts" />
2
- import { a as abortIf, c as initializeGlobalContext, d as Hash, f as Encryption, i as abort, l as isClass, n as ModelConstructor, o as assertFound, r as ModelRegistry, s as getModel, t as AbstractModelConstructor, u as perPage } from "./helpers-CfQxt_q2.js";
2
+ import { a as abortIf, c as initializeGlobalContext, d as Hash, f as Encryption, i as abort, l as isClass, n as ModelConstructor, o as assertFound, r as ModelRegistry, s as getModel, t as AbstractModelConstructor, u as perPage } from "./helpers-BrQ0B-EX.js";
3
3
  import { JitiOptions, JitiResolveOptions } from "jiti";
4
4
  import { Arkstack } from "@arkstack/contract";
5
5
  import pino from "pino";
@@ -170,6 +170,9 @@ declare class Logger {
170
170
  static console(): typeof Console;
171
171
  }
172
172
  //#endregion
173
+ //#region src/locales.d.ts
174
+ declare const locales: readonly ["af_ZA", "ar", "az", "bn_BD", "cs_CZ", "cy", "da", "de", "de_AT", "de_CH", "dv", "el", "en", "en_AU", "en_AU_ocker", "en_BORK", "en_CA", "en_GB", "en_GH", "en_HK", "en_IE", "en_IN", "en_NG", "en_US", "en_ZA", "eo", "es", "es_MX", "fa", "fi", "fr", "fr_BE", "fr_CA", "fr_CH", "fr_LU", "fr_SN", "he", "hr", "hu", "hy", "id_ID", "it", "ja", "ka_GE", "ko", "ku_ckb", "ku_kmr_latin", "lv", "mk", "mn_MN_cyrl", "nb_NO", "ne", "nl", "nl_BE", "pl", "pt_BR", "pt_PT", "ro", "ro_MD", "ru", "sk", "sl_SI", "sr_RS_latin", "sv", "ta_IN", "th", "tr", "uk", "ur", "uz_UZ_latin", "vi", "yo_NG", "zh_CN", "zh_TW", "zu_ZA"];
175
+ //#endregion
173
176
  //#region src/types.d.ts
174
177
  interface ConfigRegistry {}
175
178
  /**
@@ -192,6 +195,11 @@ interface EnvRegistry {
192
195
  APP_URL: string;
193
196
  APP_HOST: string;
194
197
  APP_PORT: number;
198
+ APP_DEBUG: boolean;
199
+ APP_TIMEZONE: string;
200
+ APP_LOCALE: typeof locales[number];
201
+ APP_FALLBACK_LOCALE: typeof locales[number];
202
+ APP_FAKER_LOCALE: typeof locales[number];
195
203
  NODE_ENV: 'development' | 'production' | 'test';
196
204
  PORT: number;
197
205
  HOST: string;
@@ -200,6 +208,8 @@ interface EnvRegistry {
200
208
  OUTPUT_DIR_DEV: string;
201
209
  CONFIG_PATH: string;
202
210
  TUNNEL: boolean;
211
+ NGROK_AUTHTOKEN: string;
212
+ NGROK_DOMAIN: string;
203
213
  FILESYSTEM_DISK: string;
204
214
  CACHE_STORE: string;
205
215
  CACHE_PREFIX: string;
@@ -237,7 +247,26 @@ interface EnvRegistry {
237
247
  AWS_URL: string;
238
248
  AWS_ENDPOINT: string;
239
249
  }
240
- /** Known environment variable names. */
250
+ /**
251
+ * App Confifuration
252
+ */
253
+ interface AppConfig {
254
+ [key: string]: any;
255
+ env: string;
256
+ key: string;
257
+ url: string;
258
+ host: string;
259
+ name: string;
260
+ frontend_url: string;
261
+ debug: boolean;
262
+ timezone: string;
263
+ locale: typeof locales[number];
264
+ fallback_locale: typeof locales[number];
265
+ faker_locale: typeof locales[number];
266
+ }
267
+ /**
268
+ * Known environment variable names.
269
+ */
241
270
  type EnvKey = keyof EnvRegistry & string;
242
271
  /** The registered type for a known key, or `string` for an unknown one. */
243
272
  type EnvLookup<K extends string> = [K] extends [EnvKey] ? EnvRegistry[K] : string;
@@ -274,7 +303,7 @@ interface LoggerLog {
274
303
  */
275
304
  type EnvReturn<X, K extends string, D> = [X] extends [never] ? [D] extends [undefined] ? EnvLookup<K> : EnvLookup<K> | D : [D] extends [undefined] ? X : X | D;
276
305
  interface GlobalEnv {
277
- <X = never, D = undefined, K extends string = string>(env: K, defaultValue?: D): EnvReturn<X, K, D>;
306
+ <X = never, D = undefined, K extends (keyof EnvRegistry | (string & {})) = keyof EnvRegistry>(env: K, defaultValue?: D): EnvReturn<X, K, D>;
278
307
  }
279
308
  type ConfigShape = keyof ConfigRegistry extends never ? Record<string, any> : ConfigRegistry;
280
309
  interface GlobalConfig {
@@ -742,4 +771,4 @@ declare class ConfigLoader {
742
771
  */
743
772
  declare const configLoader: ConfigLoader;
744
773
  //#endregion
745
- export { AbstractModelConstructor, AppException, ArkstackErrorPayload, ArkstackErrorShape, CONFIG_KEY, ConfigLoader, ConfigRegistry, ConfigShape, DotPath, DotPathValue, Encryption, EnvKey, EnvLoader, EnvLookup, EnvRegistry, EnvReturn, ErrorHandler, Exception, FileImporter, GlobalConfig, GlobalEnv, Hash, Hook, HookArgs, HookFor, HookName, HookPos, HookPositions, HookRegistry, IHook, Logger, LoggerChalk, LoggerLog, LoggerParseSignature, MergedConfig, ModelConstructor, ModelRegistry, Primitive, PublishEntry, PublishFilter, PublishGroup, Publisher, RequestException, UnionToIntersection, abort, abortIf, appKey, appUrl, assertFound, bindGracefulShutdown, bootWithDetectedPort, config, configLoader, createErrorPayload, discoverCommands, env, envLoader, getErrorLogger, getModel, getPrimaryError, getValidationErrors, importFile, initializeGlobalContext, interopDefault, isClass, isModelNotFoundError, isValidationError, loadPrototypes, logUnhandledError, nodeEnv, normalizeStatusCode, outputDir, perPage, rebuildOutput, renderError, resolveRuntimeDir, resolveRuntimeModule, serializeError, shouldHideStack, shouldLogError, toErrorShape, toOutputPath };
774
+ export { AbstractModelConstructor, AppConfig, AppException, ArkstackErrorPayload, ArkstackErrorShape, CONFIG_KEY, ConfigLoader, ConfigRegistry, ConfigShape, DotPath, DotPathValue, Encryption, EnvKey, EnvLoader, EnvLookup, EnvRegistry, EnvReturn, ErrorHandler, Exception, FileImporter, GlobalConfig, GlobalEnv, Hash, Hook, HookArgs, HookFor, HookName, HookPos, HookPositions, HookRegistry, IHook, Logger, LoggerChalk, LoggerLog, LoggerParseSignature, MergedConfig, ModelConstructor, ModelRegistry, Primitive, PublishEntry, PublishFilter, PublishGroup, Publisher, RequestException, UnionToIntersection, abort, abortIf, appKey, appUrl, assertFound, bindGracefulShutdown, bootWithDetectedPort, config, configLoader, createErrorPayload, discoverCommands, env, envLoader, getErrorLogger, getModel, getPrimaryError, getValidationErrors, importFile, initializeGlobalContext, interopDefault, isClass, isModelNotFoundError, isValidationError, loadPrototypes, logUnhandledError, nodeEnv, normalizeStatusCode, outputDir, perPage, rebuildOutput, renderError, resolveRuntimeDir, resolveRuntimeModule, serializeError, shouldHideStack, shouldLogError, toErrorShape, toOutputPath };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- import { A as resolveRuntimeModule, C as env, D as outputDir, E as nodeEnv, F as ConfigLoader, I as configLoader, M as EnvLoader, N as envLoader, O as rebuildOutput, P as CONFIG_KEY, S as discoverCommands, T as interopDefault, _ as Hash, b as appUrl, c as abortIf, d as initializeGlobalContext, f as isClass, g as Exception, h as AppException, j as toOutputPath, k as resolveRuntimeDir, l as assertFound, m as RequestException, p as perPage, s as abort, u as getModel, v as Encryption, w as importFile, x as config, y as appKey } from "./utils-DEflBOXp.js";
1
+ import { _ as ConfigLoader, a as env, c as nodeEnv, d as resolveRuntimeDir, f as resolveRuntimeModule, g as CONFIG_KEY, h as envLoader, i as discoverCommands, l as outputDir, m as EnvLoader, n as appUrl, o as importFile, p as toOutputPath, r as config, s as interopDefault, t as appKey, u as rebuildOutput, v as configLoader } from "./system-DUaI4u99.js";
2
+ import { _ as Hash, c as abortIf, d as initializeGlobalContext, f as isClass, g as Exception, h as AppException, l as assertFound, m as RequestException, p as perPage, s as abort, u as getModel, v as Encryption } from "./utils-Df3nH1sG.js";
2
3
  import { Hook as Hook$1 } from "@arkstack/foundry";
3
4
  import { Arkstack } from "@arkstack/contract";
4
5
  import { str } from "@h3ravel/support";
@@ -1,4 +1,3 @@
1
- import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:crypto";
2
1
  import { createJiti } from "jiti";
3
2
  import { existsSync, readdirSync } from "fs";
4
3
  import { Arkstack } from "@arkstack/contract";
@@ -10,9 +9,6 @@ import { config } from "dotenv";
10
9
  import { pathToFileURL } from "node:url";
11
10
  import { rm } from "node:fs/promises";
12
11
  import { spawn } from "node:child_process";
13
- import { Secret, TOTP } from "otpauth";
14
- import { compare, genSalt, hash } from "bcryptjs";
15
- import { getUserConfig } from "arkormx";
16
12
  //#region src/ConfigLoader.ts
17
13
  const CONFIG_KEY = Symbol("globalConfig");
18
14
  globalThis[CONFIG_KEY] = {};
@@ -476,433 +472,4 @@ const interopDefault = (imp) => {
476
472
  return typeof imp === "function" ? imp : imp.default;
477
473
  };
478
474
  //#endregion
479
- //#region src/utils/encryption.ts
480
- var Encryption = class {
481
- static algorithm = "aes-256-gcm";
482
- static getKey() {
483
- const secret = appKey("TWO_FACTOR_ENCRYPTION_KEY");
484
- if (!secret) throw new Error("APP_KEY is required to use two-factor authentication. Run `ark key:generate`.");
485
- return createHash("sha256").update(secret).digest();
486
- }
487
- static encrypt(value) {
488
- const iv = randomBytes(12);
489
- const cipher = createCipheriv(this.algorithm, this.getKey(), iv);
490
- const ciphertext = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
491
- return [
492
- iv,
493
- cipher.getAuthTag(),
494
- ciphertext
495
- ].map((part) => part.toString("base64url")).join(":");
496
- }
497
- static decrypt(payload) {
498
- const [iv, authTag, ciphertext] = payload.split(":");
499
- if (!iv || !authTag || !ciphertext) throw new Error("Invalid encrypted payload format");
500
- const decipher = createDecipheriv(this.algorithm, this.getKey(), Buffer.from(iv, "base64url"));
501
- decipher.setAuthTag(Buffer.from(authTag, "base64url"));
502
- return Buffer.concat([decipher.update(Buffer.from(ciphertext, "base64url")), decipher.final()]).toString("utf8");
503
- }
504
- };
505
- //#endregion
506
- //#region src/utils/hash.ts
507
- var Hash = class {
508
- /**
509
- * Hash a value using bcrypt
510
- *
511
- * @param value
512
- * @returns
513
- */
514
- static async make(value) {
515
- return await hash(value, await genSalt(10));
516
- }
517
- /**
518
- * Verify a value against a hashed value
519
- *
520
- * @param value
521
- * @param hashedValue
522
- * @returns
523
- */
524
- static async verify(value, hashedValue) {
525
- return await compare(value, hashedValue);
526
- }
527
- /**
528
- * Generate a one-time password (OTP) using TOTP algorithm
529
- *
530
- * @param digits The number of digits for the OTP, default is 6.
531
- * @param label A label to identify the OTP, can be an email or phone number.
532
- * @param period Interval of time for which a token is valid, in seconds.
533
- * @returns
534
- */
535
- static otp(digits = 6, label = "Alice", period = 30) {
536
- return new TOTP({
537
- label,
538
- digits,
539
- issuer: env$1("APP_NAME", "Roseed"),
540
- algorithm: "SHA1",
541
- period,
542
- secret: "US3WHSG7X5KAPV27VANWKQHF3SH3HULL"
543
- });
544
- }
545
- static totp(secret, label, issuer = env$1("APP_NAME", "Roseed"), period = 30) {
546
- return new TOTP({
547
- issuer,
548
- label,
549
- algorithm: "SHA1",
550
- digits: 6,
551
- period,
552
- secret: Secret.fromBase32(secret)
553
- });
554
- }
555
- };
556
- //#endregion
557
- //#region src/Exceptions/Exception.ts
558
- var Exception = class extends Error {
559
- name;
560
- constructor(message, options) {
561
- super(message, options);
562
- this.name = "Exception";
563
- }
564
- };
565
- //#endregion
566
- //#region src/Exceptions/AppException.ts
567
- var AppException = class extends Exception {
568
- errors = void 0;
569
- statusCode;
570
- constructor(message, statusCode = 400, options) {
571
- super(message, options);
572
- this.statusCode = statusCode;
573
- }
574
- };
575
- //#endregion
576
- //#region src/Exceptions/RequestException.ts
577
- var RequestException = class RequestException extends AppException {
578
- statusCode;
579
- constructor(message, statusCode = 400, options) {
580
- super(message, statusCode, options);
581
- this.statusCode = statusCode;
582
- }
583
- /**
584
- * Asserts that a value is not null or undefined.
585
- *
586
- * @param value
587
- * @param message
588
- * @param code
589
- * @throws {RequestException} Throws if the value is null or undefined.
590
- */
591
- static assertFound(value, message, code = 404) {
592
- if (!value) throw new RequestException(message, code);
593
- }
594
- /**
595
- * Asserts that a value is not null or undefined.
596
- *
597
- * @param value
598
- * @param message
599
- * @param code
600
- * @throws {RequestException} Throws if the value is null or undefined.
601
- * @deprecated Use assertFound instead
602
- */
603
- static assertNotEmpty(value, message, code = 404) {
604
- return this.assertFound(value, message, code);
605
- }
606
- /**
607
- * Asserts that a boolean condition is true.
608
- *
609
- * @param boolean
610
- * @param message
611
- * @param code
612
- * @throws {RequestException} Throws if the boolean condition is true.
613
- */
614
- static abortIf(boolean, message, code) {
615
- if (boolean) throw new RequestException(message, code);
616
- }
617
- };
618
- //#endregion
619
- //#region src/utils/helpers.ts
620
- /**
621
- * Checks and asserts if target is a class
622
- *
623
- * @param target
624
- * @returns
625
- */
626
- const isClass = (target) => {
627
- return typeof target === "function" && /^class\s/.test(Function.prototype.toString.call(target));
628
- };
629
- /**
630
- * Determine the number of items to return per page based on the provided query parameters.
631
- *
632
- * @param query
633
- * @returns
634
- */
635
- const perPage = (query) => {
636
- const requestedPerPage = Number(query.limit ?? query.perPage ?? 15);
637
- return Number.isFinite(requestedPerPage) && requestedPerPage > 0 ? Math.min(requestedPerPage, 50) : 15;
638
- };
639
- async function getModel(modelName) {
640
- const resolveModelExport = (module, modelName) => {
641
- if (!isModelModule(module)) return module;
642
- return module.default ?? module[modelName] ?? module;
643
- };
644
- const isModelModule = (value) => typeof value === "object" && value !== null;
645
- const modelPath = getUserConfig().paths?.models || "./src/models";
646
- const model = resolveModelExport(await importFile(resolveRuntimeModule(path.join(path.isAbsolute(modelPath) ? modelPath : path.join(Arkstack.rootDir(), modelPath), modelName))), path.basename(modelName, path.extname(modelName)));
647
- if (typeof model !== "function") throw new Error(`Model "${modelName}" not found`);
648
- return model;
649
- }
650
- const initializeGlobalContext = async ({ Request, Response, Session } = {}) => {
651
- try {
652
- const { Request: Req, Response: Res, Session: Ses } = await import("@arkstack/http");
653
- Session ??= new Ses();
654
- Request ??= new Req();
655
- Response ??= new Res();
656
- } catch {
657
- Session ??= new class {}();
658
- Request ??= new class {}();
659
- Response ??= new class {}();
660
- }
661
- globalThis.session ??= () => Session;
662
- globalThis.request ??= () => Request;
663
- globalThis.response ??= () => Response;
664
- };
665
- /**
666
- * Thows to abort the current request
667
- *
668
- * @param message
669
- * @param code
670
- * @throws {RequestException}
671
- */
672
- const abort = (message = "Request Aborted", code = 404) => {
673
- RequestException.abortIf(true, message, code);
674
- };
675
- /**
676
- * Asserts that a boolean condition is true.
677
- *
678
- * @param boolean
679
- * @param message
680
- * @param code
681
- * @throws {RequestException} Throws if the boolean condition is true.
682
- */
683
- const abortIf = (boolean, message = "Request Aborted", code = 404) => {
684
- RequestException.abortIf(boolean, message, code);
685
- };
686
- /**
687
- * Asserts that a value is not null or undefined.
688
- *
689
- * @param value
690
- * @param message
691
- * @param code
692
- * @throws {RequestException} Throws if the value is null or undefined.
693
- */
694
- const assertFound = (value, message, code = 404) => {
695
- if (!value) throw new RequestException(message, code);
696
- };
697
- //#endregion
698
- //#region src/utils/traits.ts
699
- /**
700
- * CRC32 implementation in TypeScript, adapted from https://stackoverflow.com/a/18639999
701
- * Note: This implementation is not cryptographically secure and is only used for generating
702
- * unique identifiers for traits based on their factory function's string representation.
703
- */
704
- const crcTable = [];
705
- for (let n = 0; n < 256; n++) {
706
- let c = n;
707
- for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
708
- crcTable[n] = c;
709
- }
710
- const crc32 = (str) => {
711
- let crc = -1;
712
- for (let i = 0; i < str.length; i++) crc = crc >>> 8 ^ crcTable[(crc ^ str.charCodeAt(i)) & 255];
713
- return (crc ^ -1) >>> 0;
714
- };
715
- const isCons = (fn) => typeof fn === "function" && !!fn.prototype && !!fn.prototype.constructor;
716
- const isArkormModelInstance = (value) => typeof value === "object" && value !== null && typeof value.constructor === "function" && typeof value.getAttribute === "function" && typeof value.setAttribute === "function";
717
- const isTypeFactory = (fn) => typeof fn === "function" && !fn.prototype && fn.length === 0;
718
- /**
719
- * API: generate trait (technical implementation)
720
- *
721
- * @param args
722
- */
723
- function trait(...args) {
724
- const factory = args.length === 2 ? args[1] : args[0];
725
- const superTraits = args.length === 2 ? args[0] : void 0;
726
- return {
727
- id: crc32(factory.toString()),
728
- symbol: Symbol("trait"),
729
- factory,
730
- superTraits
731
- };
732
- }
733
- /**
734
- * utility function: add an additional invisible property to an object
735
- *
736
- * @param cons
737
- * @param field
738
- * @param value
739
- * @returns
740
- */
741
- const extendProperties = (cons, field, value) => Object.defineProperty(cons, field, {
742
- value,
743
- enumerable: false,
744
- writable: false
745
- });
746
- const traitMethodRegistry = Symbol("trait-method-registry");
747
- const cloneMethodRegistry = (target) => {
748
- const registry = target[traitMethodRegistry];
749
- return new Map([...registry?.entries() ?? []].map(([name, methods]) => [name, [...methods]]));
750
- };
751
- const registerMethodScope = (target, base, ignored) => {
752
- const registry = cloneMethodRegistry(base);
753
- for (const name of Reflect.ownKeys(target)) {
754
- if (ignored.has(name)) continue;
755
- const method = Object.getOwnPropertyDescriptor(target, name)?.value;
756
- if (typeof method !== "function") continue;
757
- const methods = registry.get(name);
758
- const previous = base?.[name];
759
- if (methods) {
760
- if (methods.at(-1) !== method) methods.push(method);
761
- registry.set(name, methods);
762
- } else if (typeof previous === "function" && previous !== method) registry.set(name, [previous, method]);
763
- }
764
- Object.defineProperty(target, traitMethodRegistry, {
765
- configurable: false,
766
- enumerable: false,
767
- value: registry,
768
- writable: false
769
- });
770
- };
771
- /**
772
- * Registers conflicting trait methods
773
- *
774
- * @param classInstance
775
- * @param baseClass
776
- */
777
- const registerTraitMethods = (classInstance, baseClass) => {
778
- registerMethodScope(classInstance.prototype, baseClass.prototype, new Set(["constructor"]));
779
- registerMethodScope(classInstance, baseClass, new Set([
780
- "length",
781
- "name",
782
- "prototype",
783
- "arguments",
784
- "caller"
785
- ]));
786
- };
787
- /**
788
- * Return every trait implementation for a method, bound to the supplied
789
- * instance or class. Methods are ordered from the base implementation to the
790
- * currently active trait implementation.
791
- *
792
- * @param target
793
- * @param name
794
- * @returns
795
- */
796
- const getTraitMethods = (target, name) => {
797
- return (((typeof target === "function" ? target : Object.getPrototypeOf(target))?.[traitMethodRegistry])?.get(name) ?? []).map((method) => method.bind(target));
798
- };
799
- /**
800
- * Invoke every trait implementation for a method in registration order.
801
- *
802
- * @param target
803
- * @param name
804
- * @param args
805
- * @returns
806
- */
807
- const callTraitMethods = (target, name, ...args) => {
808
- const methods = getTraitMethods(target, name);
809
- if (methods.length === 0) {
810
- console.warn(`No conflicting trait methods found for "${String(name)}".`);
811
- return [];
812
- }
813
- return methods.map((method) => method(...args));
814
- };
815
- /**
816
- * utility function: get raw trait
817
- *
818
- * @param x
819
- * @returns
820
- */
821
- const rawTrait = (x) => isTypeFactory(x) ? x() : x;
822
- /**
823
- * utility function: derive a trait
824
- *
825
- * @param trait$
826
- * @param baseClass
827
- * @param derived
828
- * @returns
829
- */
830
- const deriveTrait = (trait$, baseClass, derived) => {
831
- const trait = rawTrait(trait$);
832
- if (trait === void 0 || trait === null || typeof trait.id !== "number") throw new Error("use(): received an undefined or invalid trait. This usually means a circular import — the trait module had not finished initializing when use() ran. Avoid importing models at the top level of trait modules, or break the import cycle.");
833
- let classInstance = baseClass;
834
- if (!derived.has(trait.id)) {
835
- derived.set(trait.id, true);
836
- if (trait.superTraits !== void 0) for (const superTrait of reverseTraitList(trait.superTraits)) classInstance = deriveTrait(superTrait, classInstance, derived);
837
- const base = classInstance;
838
- classInstance = trait.factory(classInstance);
839
- registerTraitMethods(classInstance, base);
840
- extendProperties(classInstance, "id", crc32(trait.factory.toString()));
841
- extendProperties(classInstance, trait.symbol, true);
842
- }
843
- return classInstance;
844
- };
845
- /**
846
- * utility function: get reversed trait list
847
- *
848
- * @param traits
849
- * @returns
850
- */
851
- const reverseTraitList = (traits) => traits.slice().reverse();
852
- function use(...args) {
853
- const withMethodHelpers = args[0] === true;
854
- const traits = withMethodHelpers ? args.slice(1) : args;
855
- if (traits.length === 0) throw new Error("invalid number of parameters (expected one or more traits)");
856
- let classInstance;
857
- let lot;
858
- const last = traits[traits.length - 1];
859
- if (isCons(last) && !isTypeFactory(last)) {
860
- classInstance = last;
861
- lot = traits.slice(0, -1);
862
- } else if (isArkormModelInstance(last)) {
863
- classInstance = last.constructor;
864
- lot = traits.slice(0, -1);
865
- } else {
866
- classInstance = class ROOT {};
867
- lot = traits;
868
- }
869
- const derived = /* @__PURE__ */ new Map();
870
- for (const trait of reverseTraitList(lot)) classInstance = deriveTrait(trait, classInstance, derived);
871
- if (withMethodHelpers) classInstance = class TraitMethodEnabled extends classInstance {
872
- getTraitMethods(name) {
873
- return getTraitMethods(this, name);
874
- }
875
- callTraitMethods(name, ...args) {
876
- return callTraitMethods(this, name, ...args);
877
- }
878
- static getTraitMethods(name) {
879
- return getTraitMethods(this, name);
880
- }
881
- static callTraitMethods(name, ...args) {
882
- return callTraitMethods(this, name, ...args);
883
- }
884
- };
885
- return classInstance;
886
- }
887
- /**
888
- * API: type guard for checking whether class instance is derived from a trait
889
- *
890
- * @param instance
891
- * @param trait
892
- * @returns
893
- */
894
- function uses(instance, trait) {
895
- if (typeof instance !== "object" || instance === null) return false;
896
- let obj = instance;
897
- if (isCons(trait) && !isTypeFactory(trait)) return instance instanceof trait;
898
- const idTrait = (isTypeFactory(trait) ? trait() : trait)["id"];
899
- while (obj) {
900
- if (Object.hasOwn(obj, "constructor")) {
901
- if ((obj.constructor["id"] ?? 0) === idTrait) return true;
902
- }
903
- obj = Object.getPrototypeOf(obj);
904
- }
905
- return false;
906
- }
907
- //#endregion
908
- export { resolveRuntimeModule as A, env$1 as C, outputDir as D, nodeEnv as E, ConfigLoader as F, configLoader as I, EnvLoader as M, envLoader as N, rebuildOutput as O, CONFIG_KEY as P, discoverCommands as S, interopDefault as T, Hash as _, use as a, appUrl as b, abortIf as c, initializeGlobalContext as d, isClass as f, Exception as g, AppException as h, trait as i, toOutputPath as j, resolveRuntimeDir as k, assertFound as l, RequestException as m, crc32 as n, uses as o, perPage as p, getTraitMethods as r, abort as s, callTraitMethods as t, getModel as u, Encryption as v, importFile as w, config$1 as x, appKey as y };
475
+ export { ConfigLoader as _, env$1 as a, nodeEnv as c, resolveRuntimeDir as d, resolveRuntimeModule as f, CONFIG_KEY as g, envLoader as h, discoverCommands as i, outputDir as l, EnvLoader as m, appUrl as n, importFile as o, toOutputPath as p, config$1 as r, interopDefault as s, appKey as t, rebuildOutput as u, configLoader as v };
@@ -1,4 +1,4 @@
1
- import { a as abortIf, c as initializeGlobalContext, d as Hash, f as Encryption, i as abort, l as isClass, n as ModelConstructor, o as assertFound, r as ModelRegistry, s as getModel, t as AbstractModelConstructor, u as perPage } from "../helpers-CfQxt_q2.js";
1
+ import { a as abortIf, c as initializeGlobalContext, d as Hash, f as Encryption, i as abort, l as isClass, n as ModelConstructor, o as assertFound, r as ModelRegistry, s as getModel, t as AbstractModelConstructor, u as perPage } from "../helpers-BrQ0B-EX.js";
2
2
  import { Model } from "arkormx";
3
3
 
4
4
  //#region src/utils/traits.d.ts
@@ -1,2 +1,2 @@
1
- import { _ as Hash, a as use, c as abortIf, d as initializeGlobalContext, f as isClass, i as trait, l as assertFound, n as crc32, o as uses, p as perPage, r as getTraitMethods, s as abort, t as callTraitMethods, u as getModel, v as Encryption } from "../utils-DEflBOXp.js";
1
+ import { _ as Hash, a as use, c as abortIf, d as initializeGlobalContext, f as isClass, i as trait, l as assertFound, n as crc32, o as uses, p as perPage, r as getTraitMethods, s as abort, t as callTraitMethods, u as getModel, v as Encryption } from "../utils-Df3nH1sG.js";
2
2
  export { Encryption, Hash, abort, abortIf, assertFound, callTraitMethods, crc32, getModel, getTraitMethods, initializeGlobalContext, isClass, perPage, trait, use, uses };
@@ -0,0 +1,437 @@
1
+ import { a as env, f as resolveRuntimeModule, o as importFile, t as appKey } from "./system-DUaI4u99.js";
2
+ import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:crypto";
3
+ import { Arkstack } from "@arkstack/contract";
4
+ import path from "node:path";
5
+ import { Secret, TOTP } from "otpauth";
6
+ import { compare, genSalt, hash } from "bcryptjs";
7
+ import { getUserConfig } from "arkormx";
8
+ //#region src/utils/encryption.ts
9
+ var Encryption = class {
10
+ static algorithm = "aes-256-gcm";
11
+ static getKey() {
12
+ const secret = appKey("TWO_FACTOR_ENCRYPTION_KEY");
13
+ if (!secret) throw new Error("APP_KEY is required to use two-factor authentication. Run `ark key:generate`.");
14
+ return createHash("sha256").update(secret).digest();
15
+ }
16
+ static encrypt(value) {
17
+ const iv = randomBytes(12);
18
+ const cipher = createCipheriv(this.algorithm, this.getKey(), iv);
19
+ const ciphertext = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
20
+ return [
21
+ iv,
22
+ cipher.getAuthTag(),
23
+ ciphertext
24
+ ].map((part) => part.toString("base64url")).join(":");
25
+ }
26
+ static decrypt(payload) {
27
+ const [iv, authTag, ciphertext] = payload.split(":");
28
+ if (!iv || !authTag || !ciphertext) throw new Error("Invalid encrypted payload format");
29
+ const decipher = createDecipheriv(this.algorithm, this.getKey(), Buffer.from(iv, "base64url"));
30
+ decipher.setAuthTag(Buffer.from(authTag, "base64url"));
31
+ return Buffer.concat([decipher.update(Buffer.from(ciphertext, "base64url")), decipher.final()]).toString("utf8");
32
+ }
33
+ };
34
+ //#endregion
35
+ //#region src/utils/hash.ts
36
+ var Hash = class {
37
+ /**
38
+ * Hash a value using bcrypt
39
+ *
40
+ * @param value
41
+ * @returns
42
+ */
43
+ static async make(value) {
44
+ return await hash(value, await genSalt(10));
45
+ }
46
+ /**
47
+ * Verify a value against a hashed value
48
+ *
49
+ * @param value
50
+ * @param hashedValue
51
+ * @returns
52
+ */
53
+ static async verify(value, hashedValue) {
54
+ return await compare(value, hashedValue);
55
+ }
56
+ /**
57
+ * Generate a one-time password (OTP) using TOTP algorithm
58
+ *
59
+ * @param digits The number of digits for the OTP, default is 6.
60
+ * @param label A label to identify the OTP, can be an email or phone number.
61
+ * @param period Interval of time for which a token is valid, in seconds.
62
+ * @returns
63
+ */
64
+ static otp(digits = 6, label = "Alice", period = 30) {
65
+ return new TOTP({
66
+ label,
67
+ digits,
68
+ issuer: env("APP_NAME", "Roseed"),
69
+ algorithm: "SHA1",
70
+ period,
71
+ secret: "US3WHSG7X5KAPV27VANWKQHF3SH3HULL"
72
+ });
73
+ }
74
+ static totp(secret, label, issuer = env("APP_NAME", "Roseed"), period = 30) {
75
+ return new TOTP({
76
+ issuer,
77
+ label,
78
+ algorithm: "SHA1",
79
+ digits: 6,
80
+ period,
81
+ secret: Secret.fromBase32(secret)
82
+ });
83
+ }
84
+ };
85
+ //#endregion
86
+ //#region src/Exceptions/Exception.ts
87
+ var Exception = class extends Error {
88
+ name;
89
+ constructor(message, options) {
90
+ super(message, options);
91
+ this.name = "Exception";
92
+ }
93
+ };
94
+ //#endregion
95
+ //#region src/Exceptions/AppException.ts
96
+ var AppException = class extends Exception {
97
+ errors = void 0;
98
+ statusCode;
99
+ constructor(message, statusCode = 400, options) {
100
+ super(message, options);
101
+ this.statusCode = statusCode;
102
+ }
103
+ };
104
+ //#endregion
105
+ //#region src/Exceptions/RequestException.ts
106
+ var RequestException = class RequestException extends AppException {
107
+ statusCode;
108
+ constructor(message, statusCode = 400, options) {
109
+ super(message, statusCode, options);
110
+ this.statusCode = statusCode;
111
+ }
112
+ /**
113
+ * Asserts that a value is not null or undefined.
114
+ *
115
+ * @param value
116
+ * @param message
117
+ * @param code
118
+ * @throws {RequestException} Throws if the value is null or undefined.
119
+ */
120
+ static assertFound(value, message, code = 404) {
121
+ if (!value) throw new RequestException(message, code);
122
+ }
123
+ /**
124
+ * Asserts that a value is not null or undefined.
125
+ *
126
+ * @param value
127
+ * @param message
128
+ * @param code
129
+ * @throws {RequestException} Throws if the value is null or undefined.
130
+ * @deprecated Use assertFound instead
131
+ */
132
+ static assertNotEmpty(value, message, code = 404) {
133
+ return this.assertFound(value, message, code);
134
+ }
135
+ /**
136
+ * Asserts that a boolean condition is true.
137
+ *
138
+ * @param boolean
139
+ * @param message
140
+ * @param code
141
+ * @throws {RequestException} Throws if the boolean condition is true.
142
+ */
143
+ static abortIf(boolean, message, code) {
144
+ if (boolean) throw new RequestException(message, code);
145
+ }
146
+ };
147
+ //#endregion
148
+ //#region src/utils/helpers.ts
149
+ /**
150
+ * Checks and asserts if target is a class
151
+ *
152
+ * @param target
153
+ * @returns
154
+ */
155
+ const isClass = (target) => {
156
+ return typeof target === "function" && /^class\s/.test(Function.prototype.toString.call(target));
157
+ };
158
+ /**
159
+ * Determine the number of items to return per page based on the provided query parameters.
160
+ *
161
+ * @param query
162
+ * @returns
163
+ */
164
+ const perPage = (query) => {
165
+ const requestedPerPage = Number(query.limit ?? query.perPage ?? 15);
166
+ return Number.isFinite(requestedPerPage) && requestedPerPage > 0 ? Math.min(requestedPerPage, 50) : 15;
167
+ };
168
+ async function getModel(modelName) {
169
+ const resolveModelExport = (module, modelName) => {
170
+ if (!isModelModule(module)) return module;
171
+ return module.default ?? module[modelName] ?? module;
172
+ };
173
+ const isModelModule = (value) => typeof value === "object" && value !== null;
174
+ const modelPath = getUserConfig().paths?.models || "./src/models";
175
+ const model = resolveModelExport(await importFile(resolveRuntimeModule(path.join(path.isAbsolute(modelPath) ? modelPath : path.join(Arkstack.rootDir(), modelPath), modelName))), path.basename(modelName, path.extname(modelName)));
176
+ if (typeof model !== "function") throw new Error(`Model "${modelName}" not found`);
177
+ return model;
178
+ }
179
+ const initializeGlobalContext = async ({ Request, Response, Session } = {}) => {
180
+ try {
181
+ const { Request: Req, Response: Res, Session: Ses } = await import("@arkstack/http");
182
+ Session ??= new Ses();
183
+ Request ??= new Req();
184
+ Response ??= new Res();
185
+ } catch {
186
+ Session ??= new class {}();
187
+ Request ??= new class {}();
188
+ Response ??= new class {}();
189
+ }
190
+ globalThis.session ??= () => Session;
191
+ globalThis.request ??= () => Request;
192
+ globalThis.response ??= () => Response;
193
+ };
194
+ /**
195
+ * Thows to abort the current request
196
+ *
197
+ * @param message
198
+ * @param code
199
+ * @throws {RequestException}
200
+ */
201
+ const abort = (message = "Request Aborted", code = 404) => {
202
+ RequestException.abortIf(true, message, code);
203
+ };
204
+ /**
205
+ * Asserts that a boolean condition is true.
206
+ *
207
+ * @param boolean
208
+ * @param message
209
+ * @param code
210
+ * @throws {RequestException} Throws if the boolean condition is true.
211
+ */
212
+ const abortIf = (boolean, message = "Request Aborted", code = 404) => {
213
+ RequestException.abortIf(boolean, message, code);
214
+ };
215
+ /**
216
+ * Asserts that a value is not null or undefined.
217
+ *
218
+ * @param value
219
+ * @param message
220
+ * @param code
221
+ * @throws {RequestException} Throws if the value is null or undefined.
222
+ */
223
+ const assertFound = (value, message, code = 404) => {
224
+ if (!value) throw new RequestException(message, code);
225
+ };
226
+ //#endregion
227
+ //#region src/utils/traits.ts
228
+ /**
229
+ * CRC32 implementation in TypeScript, adapted from https://stackoverflow.com/a/18639999
230
+ * Note: This implementation is not cryptographically secure and is only used for generating
231
+ * unique identifiers for traits based on their factory function's string representation.
232
+ */
233
+ const crcTable = [];
234
+ for (let n = 0; n < 256; n++) {
235
+ let c = n;
236
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
237
+ crcTable[n] = c;
238
+ }
239
+ const crc32 = (str) => {
240
+ let crc = -1;
241
+ for (let i = 0; i < str.length; i++) crc = crc >>> 8 ^ crcTable[(crc ^ str.charCodeAt(i)) & 255];
242
+ return (crc ^ -1) >>> 0;
243
+ };
244
+ const isCons = (fn) => typeof fn === "function" && !!fn.prototype && !!fn.prototype.constructor;
245
+ const isArkormModelInstance = (value) => typeof value === "object" && value !== null && typeof value.constructor === "function" && typeof value.getAttribute === "function" && typeof value.setAttribute === "function";
246
+ const isTypeFactory = (fn) => typeof fn === "function" && !fn.prototype && fn.length === 0;
247
+ /**
248
+ * API: generate trait (technical implementation)
249
+ *
250
+ * @param args
251
+ */
252
+ function trait(...args) {
253
+ const factory = args.length === 2 ? args[1] : args[0];
254
+ const superTraits = args.length === 2 ? args[0] : void 0;
255
+ return {
256
+ id: crc32(factory.toString()),
257
+ symbol: Symbol("trait"),
258
+ factory,
259
+ superTraits
260
+ };
261
+ }
262
+ /**
263
+ * utility function: add an additional invisible property to an object
264
+ *
265
+ * @param cons
266
+ * @param field
267
+ * @param value
268
+ * @returns
269
+ */
270
+ const extendProperties = (cons, field, value) => Object.defineProperty(cons, field, {
271
+ value,
272
+ enumerable: false,
273
+ writable: false
274
+ });
275
+ const traitMethodRegistry = Symbol("trait-method-registry");
276
+ const cloneMethodRegistry = (target) => {
277
+ const registry = target[traitMethodRegistry];
278
+ return new Map([...registry?.entries() ?? []].map(([name, methods]) => [name, [...methods]]));
279
+ };
280
+ const registerMethodScope = (target, base, ignored) => {
281
+ const registry = cloneMethodRegistry(base);
282
+ for (const name of Reflect.ownKeys(target)) {
283
+ if (ignored.has(name)) continue;
284
+ const method = Object.getOwnPropertyDescriptor(target, name)?.value;
285
+ if (typeof method !== "function") continue;
286
+ const methods = registry.get(name);
287
+ const previous = base?.[name];
288
+ if (methods) {
289
+ if (methods.at(-1) !== method) methods.push(method);
290
+ registry.set(name, methods);
291
+ } else if (typeof previous === "function" && previous !== method) registry.set(name, [previous, method]);
292
+ }
293
+ Object.defineProperty(target, traitMethodRegistry, {
294
+ configurable: false,
295
+ enumerable: false,
296
+ value: registry,
297
+ writable: false
298
+ });
299
+ };
300
+ /**
301
+ * Registers conflicting trait methods
302
+ *
303
+ * @param classInstance
304
+ * @param baseClass
305
+ */
306
+ const registerTraitMethods = (classInstance, baseClass) => {
307
+ registerMethodScope(classInstance.prototype, baseClass.prototype, new Set(["constructor"]));
308
+ registerMethodScope(classInstance, baseClass, new Set([
309
+ "length",
310
+ "name",
311
+ "prototype",
312
+ "arguments",
313
+ "caller"
314
+ ]));
315
+ };
316
+ /**
317
+ * Return every trait implementation for a method, bound to the supplied
318
+ * instance or class. Methods are ordered from the base implementation to the
319
+ * currently active trait implementation.
320
+ *
321
+ * @param target
322
+ * @param name
323
+ * @returns
324
+ */
325
+ const getTraitMethods = (target, name) => {
326
+ return (((typeof target === "function" ? target : Object.getPrototypeOf(target))?.[traitMethodRegistry])?.get(name) ?? []).map((method) => method.bind(target));
327
+ };
328
+ /**
329
+ * Invoke every trait implementation for a method in registration order.
330
+ *
331
+ * @param target
332
+ * @param name
333
+ * @param args
334
+ * @returns
335
+ */
336
+ const callTraitMethods = (target, name, ...args) => {
337
+ const methods = getTraitMethods(target, name);
338
+ if (methods.length === 0) {
339
+ console.warn(`No conflicting trait methods found for "${String(name)}".`);
340
+ return [];
341
+ }
342
+ return methods.map((method) => method(...args));
343
+ };
344
+ /**
345
+ * utility function: get raw trait
346
+ *
347
+ * @param x
348
+ * @returns
349
+ */
350
+ const rawTrait = (x) => isTypeFactory(x) ? x() : x;
351
+ /**
352
+ * utility function: derive a trait
353
+ *
354
+ * @param trait$
355
+ * @param baseClass
356
+ * @param derived
357
+ * @returns
358
+ */
359
+ const deriveTrait = (trait$, baseClass, derived) => {
360
+ const trait = rawTrait(trait$);
361
+ if (trait === void 0 || trait === null || typeof trait.id !== "number") throw new Error("use(): received an undefined or invalid trait. This usually means a circular import — the trait module had not finished initializing when use() ran. Avoid importing models at the top level of trait modules, or break the import cycle.");
362
+ let classInstance = baseClass;
363
+ if (!derived.has(trait.id)) {
364
+ derived.set(trait.id, true);
365
+ if (trait.superTraits !== void 0) for (const superTrait of reverseTraitList(trait.superTraits)) classInstance = deriveTrait(superTrait, classInstance, derived);
366
+ const base = classInstance;
367
+ classInstance = trait.factory(classInstance);
368
+ registerTraitMethods(classInstance, base);
369
+ extendProperties(classInstance, "id", crc32(trait.factory.toString()));
370
+ extendProperties(classInstance, trait.symbol, true);
371
+ }
372
+ return classInstance;
373
+ };
374
+ /**
375
+ * utility function: get reversed trait list
376
+ *
377
+ * @param traits
378
+ * @returns
379
+ */
380
+ const reverseTraitList = (traits) => traits.slice().reverse();
381
+ function use(...args) {
382
+ const withMethodHelpers = args[0] === true;
383
+ const traits = withMethodHelpers ? args.slice(1) : args;
384
+ if (traits.length === 0) throw new Error("invalid number of parameters (expected one or more traits)");
385
+ let classInstance;
386
+ let lot;
387
+ const last = traits[traits.length - 1];
388
+ if (isCons(last) && !isTypeFactory(last)) {
389
+ classInstance = last;
390
+ lot = traits.slice(0, -1);
391
+ } else if (isArkormModelInstance(last)) {
392
+ classInstance = last.constructor;
393
+ lot = traits.slice(0, -1);
394
+ } else {
395
+ classInstance = class ROOT {};
396
+ lot = traits;
397
+ }
398
+ const derived = /* @__PURE__ */ new Map();
399
+ for (const trait of reverseTraitList(lot)) classInstance = deriveTrait(trait, classInstance, derived);
400
+ if (withMethodHelpers) classInstance = class TraitMethodEnabled extends classInstance {
401
+ getTraitMethods(name) {
402
+ return getTraitMethods(this, name);
403
+ }
404
+ callTraitMethods(name, ...args) {
405
+ return callTraitMethods(this, name, ...args);
406
+ }
407
+ static getTraitMethods(name) {
408
+ return getTraitMethods(this, name);
409
+ }
410
+ static callTraitMethods(name, ...args) {
411
+ return callTraitMethods(this, name, ...args);
412
+ }
413
+ };
414
+ return classInstance;
415
+ }
416
+ /**
417
+ * API: type guard for checking whether class instance is derived from a trait
418
+ *
419
+ * @param instance
420
+ * @param trait
421
+ * @returns
422
+ */
423
+ function uses(instance, trait) {
424
+ if (typeof instance !== "object" || instance === null) return false;
425
+ let obj = instance;
426
+ if (isCons(trait) && !isTypeFactory(trait)) return instance instanceof trait;
427
+ const idTrait = (isTypeFactory(trait) ? trait() : trait)["id"];
428
+ while (obj) {
429
+ if (Object.hasOwn(obj, "constructor")) {
430
+ if ((obj.constructor["id"] ?? 0) === idTrait) return true;
431
+ }
432
+ obj = Object.getPrototypeOf(obj);
433
+ }
434
+ return false;
435
+ }
436
+ //#endregion
437
+ export { Hash as _, use as a, abortIf as c, initializeGlobalContext as d, isClass as f, Exception as g, AppException as h, trait as i, assertFound as l, RequestException as m, crc32 as n, uses as o, perPage as p, getTraitMethods as r, abort as s, callTraitMethods as t, getModel as u, Encryption as v };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkstack/common",
3
- "version": "0.14.19",
3
+ "version": "0.14.21",
4
4
  "type": "module",
5
5
  "description": "Core utilities, primitives, and shared infrastructure for the Arkstack ecosystem.",
6
6
  "homepage": "https://arkstack.toneflix.net",
@@ -28,23 +28,28 @@
28
28
  },
29
29
  "exports": {
30
30
  ".": "./dist/index.js",
31
+ "./faker": "./dist/faker.js",
31
32
  "./utils": "./dist/utils/index.js",
32
33
  "./package.json": "./package.json"
33
34
  },
34
35
  "dependencies": {
35
- "jiti": "^2.7.0",
36
+ "@pictwo/faker": "^1.1.0",
36
37
  "bcryptjs": "^3.0.3",
37
38
  "chalk": "^5.6.2",
38
39
  "detect-port": "^2.1.0",
39
40
  "dotenv": "^17.4.2",
41
+ "jiti": "^2.7.0",
40
42
  "otpauth": "^9.5.1",
41
43
  "pino": "^10.3.1"
42
44
  },
43
45
  "peerDependencies": {
44
46
  "@h3ravel/support": "^2.2.0",
45
47
  "arkormx": "^2.10.1",
46
- "@arkstack/foundry": "^0.14.19",
47
- "@arkstack/contract": "^0.14.19"
48
+ "@arkstack/contract": "^0.14.21",
49
+ "@arkstack/foundry": "^0.14.21"
50
+ },
51
+ "optionalDependencies": {
52
+ "@faker-js/faker": "^10.4.0"
48
53
  },
49
54
  "scripts": {
50
55
  "build": "tsdown --config-loader unrun",