@arkstack/common 0.14.14 → 0.14.16

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.d.ts CHANGED
@@ -324,6 +324,31 @@ declare const nodeEnv: () => "prod" | "dev";
324
324
  * @returns
325
325
  */
326
326
  declare const outputDir: (cwd?: string) => string;
327
+ /**
328
+ * Map an application source path to its build-output counterpart.
329
+ *
330
+ * Application code is authored under `src/` and compiled into {@link outputDir},
331
+ * which strips the leading `src/` segment (e.g. `src/app/models/User.ts` ->
332
+ * `dist/app/models/User.js`). Absolute or root-relative paths outside the app
333
+ * root are returned unchanged.
334
+ *
335
+ * @param sourcePath Absolute or root-relative source path.
336
+ */
337
+ declare const toOutputPath: (sourcePath: string) => string;
338
+ /**
339
+ * Resolve an application module's source path to a file that can be imported at
340
+ * runtime.
341
+ *
342
+ * In development the TypeScript source is loaded directly (jiti compiles on the
343
+ * fly); in production only the build output ships, so the path is remapped into
344
+ * {@link outputDir} with a compiled extension. The first existing candidate
345
+ * wins — production prefers the build output, development prefers source — so a
346
+ * deploy that ships only `dist` never reaches for `src`.
347
+ *
348
+ * @param sourcePath Absolute or root-relative source path, with or without extension.
349
+ * @returns An existing importable path, or `sourcePath` unchanged when none exists.
350
+ */
351
+ declare const resolveRuntimeModule: (sourcePath: string) => string;
327
352
  /**
328
353
  * Rebuild the application output (tsdown) into {@link outputDir}, wiping it first
329
354
  * so no stale emitted modules survive a source change. Standalone — it does NOT
@@ -545,4 +570,4 @@ declare class Hook {
545
570
  static clear: () => void;
546
571
  }
547
572
  //#endregion
548
- export { AbstractModelConstructor, AppException, ArkstackErrorPayload, ArkstackErrorShape, CONFIG_KEY, ConfigRegistry, ConfigShape, DotPath, DotPathValue, Encryption, EnvRegistry, 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, createErrorPayload, discoverCommands, env, getErrorLogger, getModel, getPrimaryError, getValidationErrors, importFile, initializeGlobalContext, interopDefault, isClass, isModelNotFoundError, isValidationError, loadPrototypes, logUnhandledError, nodeEnv, normalizeStatusCode, outputDir, perPage, rebuildOutput, renderError, serializeError, shouldHideStack, shouldLogError, toErrorShape };
573
+ export { AbstractModelConstructor, AppException, ArkstackErrorPayload, ArkstackErrorShape, CONFIG_KEY, ConfigRegistry, ConfigShape, DotPath, DotPathValue, Encryption, EnvRegistry, 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, createErrorPayload, discoverCommands, env, getErrorLogger, getModel, getPrimaryError, getValidationErrors, importFile, initializeGlobalContext, interopDefault, isClass, isModelNotFoundError, isValidationError, loadPrototypes, logUnhandledError, nodeEnv, normalizeStatusCode, outputDir, perPage, rebuildOutput, renderError, resolveRuntimeModule, serializeError, shouldHideStack, shouldLogError, toErrorShape, toOutputPath };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as discoverCommands, D as nodeEnv, E as interopDefault, O as outputDir, S as config, T as importFile, _ as Hash, b as appKey, c as abortIf, d as initializeGlobalContext, f as isClass, g as Exception, h as AppException, k as rebuildOutput, l as assertFound, m as RequestException, p as perPage, s as abort, u as getModel, v as Encryption, w as env, x as appUrl, y as CONFIG_KEY } from "./utils-CL_FD72V.js";
1
+ import { A as resolveRuntimeModule, C as discoverCommands, D as nodeEnv, E as interopDefault, O as outputDir, S as config, T as importFile, _ as Hash, b as appKey, c as abortIf, d as initializeGlobalContext, f as isClass, g as Exception, h as AppException, j as toOutputPath, k as rebuildOutput, l as assertFound, m as RequestException, p as perPage, s as abort, u as getModel, v as Encryption, w as env, x as appUrl, y as CONFIG_KEY } from "./utils-B_zH08ji.js";
2
2
  import { Hook as Hook$1 } from "@arkstack/foundry";
3
3
  import { str } from "@h3ravel/support";
4
4
  import { Arkstack } from "@arkstack/contract";
@@ -529,4 +529,4 @@ var Hook = class {
529
529
  };
530
530
  };
531
531
  //#endregion
532
- export { AppException, CONFIG_KEY, Encryption, ErrorHandler, Exception, Hash, Hook, Logger, Publisher, RequestException, abort, abortIf, appKey, appUrl, assertFound, bindGracefulShutdown, bootWithDetectedPort, config, createErrorPayload, discoverCommands, env, getErrorLogger, getModel, getPrimaryError, getValidationErrors, importFile, initializeGlobalContext, interopDefault, isClass, isModelNotFoundError, isValidationError, loadPrototypes, logUnhandledError, nodeEnv, normalizeStatusCode, outputDir, perPage, rebuildOutput, renderError, serializeError, shouldHideStack, shouldLogError, toErrorShape };
532
+ export { AppException, CONFIG_KEY, Encryption, ErrorHandler, Exception, Hash, Hook, Logger, Publisher, RequestException, abort, abortIf, appKey, appUrl, assertFound, bindGracefulShutdown, bootWithDetectedPort, config, createErrorPayload, discoverCommands, env, getErrorLogger, getModel, getPrimaryError, getValidationErrors, importFile, initializeGlobalContext, interopDefault, isClass, isModelNotFoundError, isValidationError, loadPrototypes, logUnhandledError, nodeEnv, normalizeStatusCode, outputDir, perPage, rebuildOutput, renderError, resolveRuntimeModule, serializeError, shouldHideStack, shouldLogError, toErrorShape, toOutputPath };
@@ -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-CL_FD72V.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-B_zH08ji.js";
2
2
  export { Encryption, Hash, abort, abortIf, assertFound, callTraitMethods, crc32, getModel, getTraitMethods, initializeGlobalContext, isClass, perPage, trait, use, uses };
@@ -1,11 +1,11 @@
1
1
  import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:crypto";
2
2
  import { Arr, Obj, undot } from "@h3ravel/support";
3
3
  import { createJiti } from "jiti";
4
+ import { existsSync, readdirSync } from "fs";
4
5
  import { Arkstack } from "@arkstack/contract";
5
6
  import { createRequire } from "module";
6
7
  import path, { resolve } from "node:path";
7
8
  import { pathToFileURL } from "node:url";
8
- import { readdirSync } from "fs";
9
9
  import { rm } from "node:fs/promises";
10
10
  import { spawn } from "node:child_process";
11
11
  import { Secret, TOTP } from "otpauth";
@@ -147,6 +147,79 @@ const outputDir = (cwd) => {
147
147
  };
148
148
  return path.isAbsolute(output[NODE_ENV] ?? output.dev) ? output[NODE_ENV] ?? output.dev : path.join(cwd, output[NODE_ENV] ?? output.dev);
149
149
  };
150
+ const SOURCE_DIR = "src";
151
+ const SOURCE_EXTENSIONS = [
152
+ ".ts",
153
+ ".tsx",
154
+ ".mts",
155
+ ".cts",
156
+ ".js",
157
+ ".mjs",
158
+ ".cjs"
159
+ ];
160
+ const OUTPUT_EXTENSIONS = [
161
+ ".js",
162
+ ".mjs",
163
+ ".cjs",
164
+ ".ts"
165
+ ];
166
+ /**
167
+ * Strip a trailing known source/compiled extension from a path.
168
+ *
169
+ * @param value
170
+ * @returns
171
+ */
172
+ const stripKnownExtension = (value) => value.replace(/\.(ts|tsx|mts|cts|js|mjs|cjs)$/i, "");
173
+ /**
174
+ * Build the list of concrete file candidates for a base path. Any existing
175
+ * source/compiled extension is dropped first so the correct runtime extension
176
+ * can be tried (e.g. a `.ts` source maps to a `.js` candidate under `dist`).
177
+ *
178
+ * @param base
179
+ * @param extensions
180
+ * @returns
181
+ */
182
+ const moduleCandidates = (base, extensions) => {
183
+ const bare = stripKnownExtension(base);
184
+ return extensions.map((ext) => bare + ext);
185
+ };
186
+ /**
187
+ * Map an application source path to its build-output counterpart.
188
+ *
189
+ * Application code is authored under `src/` and compiled into {@link outputDir},
190
+ * which strips the leading `src/` segment (e.g. `src/app/models/User.ts` ->
191
+ * `dist/app/models/User.js`). Absolute or root-relative paths outside the app
192
+ * root are returned unchanged.
193
+ *
194
+ * @param sourcePath Absolute or root-relative source path.
195
+ */
196
+ const toOutputPath = (sourcePath) => {
197
+ const root = Arkstack.rootDir();
198
+ const abs = path.isAbsolute(sourcePath) ? sourcePath : path.join(root, sourcePath);
199
+ const rel = path.relative(root, abs);
200
+ if (!rel || rel.startsWith("..")) return abs;
201
+ return path.join(outputDir(), rel.replace(new RegExp(`^${SOURCE_DIR}[\\\\/]`), ""));
202
+ };
203
+ /**
204
+ * Resolve an application module's source path to a file that can be imported at
205
+ * runtime.
206
+ *
207
+ * In development the TypeScript source is loaded directly (jiti compiles on the
208
+ * fly); in production only the build output ships, so the path is remapped into
209
+ * {@link outputDir} with a compiled extension. The first existing candidate
210
+ * wins — production prefers the build output, development prefers source — so a
211
+ * deploy that ships only `dist` never reaches for `src`.
212
+ *
213
+ * @param sourcePath Absolute or root-relative source path, with or without extension.
214
+ * @returns An existing importable path, or `sourcePath` unchanged when none exists.
215
+ */
216
+ const resolveRuntimeModule = (sourcePath) => {
217
+ const root = Arkstack.rootDir();
218
+ const abs = path.isAbsolute(sourcePath) ? sourcePath : path.join(root, sourcePath);
219
+ const sourceCandidates = moduleCandidates(abs, SOURCE_EXTENSIONS);
220
+ const outputCandidates = moduleCandidates(toOutputPath(abs), OUTPUT_EXTENSIONS);
221
+ return (nodeEnv() === "prod" ? [...outputCandidates, ...sourceCandidates] : [...sourceCandidates, ...outputCandidates]).find((candidate) => existsSync(candidate)) ?? abs;
222
+ };
150
223
  /**
151
224
  * Rebuild the application output (tsdown) into {@link outputDir}, wiping it first
152
225
  * so no stale emitted modules survive a source change. Standalone — it does NOT
@@ -232,8 +305,9 @@ const resolveCommandExport = (mod, basename) => {
232
305
  */
233
306
  const discoverCommands = async (subPath = path.join("app", "console", "commands")) => {
234
307
  const root = Arkstack.rootDir();
235
- const dist = path.relative(root, outputDir());
236
- const candidateDirs = [path.join(root, "src", subPath), path.join(root, dist, subPath)];
308
+ const sourceDir = path.join(root, SOURCE_DIR, subPath);
309
+ const outputCommandDir = path.join(outputDir(), subPath);
310
+ const candidateDirs = nodeEnv() === "prod" ? [outputCommandDir, sourceDir] : [sourceDir, outputCommandDir];
237
311
  let commandsDir;
238
312
  let files = [];
239
313
  for (const dir of candidateDirs) try {
@@ -440,7 +514,7 @@ async function getModel(modelName) {
440
514
  };
441
515
  const isModelModule = (value) => typeof value === "object" && value !== null;
442
516
  const modelPath = getUserConfig().paths?.models || "./src/models";
443
- const model = resolveModelExport(await importFile(path.join(path.isAbsolute(modelPath) ? modelPath : path.join(Arkstack.rootDir(), modelPath), modelName)), path.basename(modelName, path.extname(modelName)));
517
+ const model = resolveModelExport(await importFile(resolveRuntimeModule(path.join(path.isAbsolute(modelPath) ? modelPath : path.join(Arkstack.rootDir(), modelPath), modelName))), path.basename(modelName, path.extname(modelName)));
444
518
  if (typeof model !== "function") throw new Error(`Model "${modelName}" not found`);
445
519
  return model;
446
520
  }
@@ -702,4 +776,4 @@ function uses(instance, trait) {
702
776
  return false;
703
777
  }
704
778
  //#endregion
705
- export { discoverCommands as C, nodeEnv as D, interopDefault as E, outputDir as O, config as S, importFile as T, Hash as _, use as a, appKey as b, abortIf as c, initializeGlobalContext as d, isClass as f, Exception as g, AppException as h, trait as i, rebuildOutput 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, env as w, appUrl as x, CONFIG_KEY as y };
779
+ export { resolveRuntimeModule as A, discoverCommands as C, nodeEnv as D, interopDefault as E, outputDir as O, config as S, importFile as T, Hash as _, use as a, appKey as b, abortIf as c, initializeGlobalContext as d, isClass as f, Exception as g, AppException as h, trait as i, toOutputPath as j, rebuildOutput 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, env as w, appUrl as x, CONFIG_KEY as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkstack/common",
3
- "version": "0.14.14",
3
+ "version": "0.14.16",
4
4
  "type": "module",
5
5
  "description": "Core utilities, primitives, and shared infrastructure for the Arkstack ecosystem.",
6
6
  "homepage": "https://arkstack.toneflix.net",
@@ -42,8 +42,8 @@
42
42
  "peerDependencies": {
43
43
  "@h3ravel/support": "^2.1.4",
44
44
  "arkormx": "^2.9.3",
45
- "@arkstack/foundry": "^0.14.14",
46
- "@arkstack/contract": "^0.14.14"
45
+ "@arkstack/foundry": "^0.14.16",
46
+ "@arkstack/contract": "^0.14.16"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "tsdown --config-loader unrun",