jopi-toolkit 3.1.32 → 3.1.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/jk_app/common.d.ts +1 -0
  2. package/dist/jk_app/common.js +9 -2
  3. package/dist/jk_app/common.js.map +1 -1
  4. package/dist/jk_data/browserActions.d.ts +8 -0
  5. package/dist/jk_data/browserActions.js +9 -0
  6. package/dist/jk_data/browserActions.js.map +1 -0
  7. package/dist/jk_data/bundler_ifServer.d.ts +2 -0
  8. package/dist/jk_data/bundler_ifServer.js +2 -0
  9. package/dist/jk_data/bundler_ifServer.js.map +1 -0
  10. package/dist/jk_data/common.d.ts +8 -0
  11. package/dist/jk_data/common.js +2 -0
  12. package/dist/jk_data/common.js.map +1 -0
  13. package/dist/jk_data/core.d.ts +13 -0
  14. package/dist/jk_data/core.js +85 -0
  15. package/dist/jk_data/core.js.map +1 -0
  16. package/dist/jk_data/dataTableProxy.d.ts +21 -0
  17. package/dist/jk_data/dataTableProxy.js +49 -0
  18. package/dist/jk_data/dataTableProxy.js.map +1 -0
  19. package/dist/jk_data/ifServerSide.d.ts +0 -0
  20. package/dist/jk_data/ifServerSide.js +2 -0
  21. package/dist/jk_data/ifServerSide.js.map +1 -0
  22. package/dist/jk_data/index.d.ts +3 -55
  23. package/dist/jk_data/index.js +3 -105
  24. package/dist/jk_data/index.js.map +1 -1
  25. package/dist/jk_data/interfaces.d.ts +107 -0
  26. package/dist/jk_data/interfaces.js +2 -0
  27. package/dist/jk_data/interfaces.js.map +1 -0
  28. package/dist/jk_data/jBundler_common.d.ts +12 -0
  29. package/dist/jk_data/jBundler_common.js +2 -0
  30. package/dist/jk_data/jBundler_common.js.map +1 -0
  31. package/dist/jk_data/jBundler_ifBrowser.d.ts +2 -0
  32. package/dist/jk_data/jBundler_ifBrowser.js +2 -0
  33. package/dist/jk_data/jBundler_ifBrowser.js.map +1 -0
  34. package/dist/jk_data/jBundler_ifServer.1.d.ts +2 -0
  35. package/dist/jk_data/jBundler_ifServer.1.js +2 -0
  36. package/dist/jk_data/jBundler_ifServer.1.js.map +1 -0
  37. package/dist/jk_data/jBundler_ifServer.d.ts +2 -0
  38. package/dist/jk_data/jBundler_ifServer.js +2 -0
  39. package/dist/jk_data/jBundler_ifServer.js.map +1 -0
  40. package/dist/jk_data/proxy.d.ts +24 -0
  41. package/dist/jk_data/proxy.js +82 -0
  42. package/dist/jk_data/proxy.js.map +1 -0
  43. package/dist/jk_dates/index.d.ts +4 -0
  44. package/dist/jk_dates/index.js +11 -0
  45. package/dist/jk_dates/index.js.map +1 -0
  46. package/dist/jk_fs/jBundler_ifServer.d.ts +2 -0
  47. package/dist/jk_fs/jBundler_ifServer.js +11 -1
  48. package/dist/jk_fs/jBundler_ifServer.js.map +1 -1
  49. package/dist/jk_memcache/index.d.ts +1 -0
  50. package/dist/jk_memcache/index.js +1 -5
  51. package/dist/jk_memcache/index.js.map +1 -1
  52. package/dist/jk_schemas/index.d.ts +20 -16
  53. package/dist/jk_schemas/index.js +13 -15
  54. package/dist/jk_schemas/index.js.map +1 -1
  55. package/dist/jk_tools/index.d.ts +1 -0
  56. package/package.json +8 -3
  57. package/src/jk_app/common.ts +12 -2
  58. package/src/jk_data/core.ts +92 -0
  59. package/src/jk_data/index.ts +3 -166
  60. package/src/jk_data/interfaces.ts +140 -0
  61. package/src/jk_data/proxy.ts +102 -0
  62. package/src/jk_dates/index.ts +12 -0
  63. package/src/jk_fs/jBundler_ifServer.ts +11 -1
  64. package/src/jk_memcache/index.ts +4 -8
  65. package/src/jk_schemas/index.ts +29 -27
  66. package/src/jk_tools/index.ts +3 -1
  67. package/src/jk_compress/index.js +0 -1
  68. package/src/jk_compress/jBundler_ifServer.js +0 -10
  69. package/src/jk_data/index.js +0 -155
  70. package/src/jk_schemas/index.js +0 -330
@@ -291,12 +291,22 @@ export function getCompiledCodeDir(): string {
291
291
  return rootDir;
292
292
  }
293
293
 
294
+ export function toSourceCodeDir(itemPath: string): string {
295
+ const compiledDir = getCompiledCodeDir();
296
+
297
+ if (itemPath.startsWith(compiledDir)) {
298
+ return getSourceCodeDir() + itemPath.substring(compiledDir.length);
299
+ }
300
+
301
+ return itemPath;
302
+ }
303
+
294
304
  export function getCompiledFilePathFor(sourceFilePath: string, replaceExtension = true): string {
295
305
  const compiledCodeDir = getCompiledCodeDir();
296
306
  const sourceCodeDir = getSourceCodeDir();
297
307
 
298
308
  if (!sourceFilePath.startsWith(sourceCodeDir)) {
299
- throw new Error("jopi-loader - The source file must be in the source code directory: " + sourceFilePath);
309
+ return sourceFilePath;
300
310
  }
301
311
 
302
312
  let filePath = sourceFilePath.substring(sourceCodeDir.length);
@@ -321,7 +331,7 @@ export function getSourcesCodePathFor(compiledFilePath: string): string {
321
331
  const sourceCodeDir = getSourceCodeDir();
322
332
 
323
333
  if (!compiledFilePath.startsWith(compiledCodeDir)) {
324
- throw new Error("jopi-loader - The compiled file must be in the compiled code directory: " + compiledFilePath);
334
+ return compiledCodeDir;
325
335
  }
326
336
 
327
337
  let filePath = jk_fs.join(sourceCodeDir, compiledFilePath.substring(compiledCodeDir.length));
@@ -0,0 +1,92 @@
1
+ import {type Schema} from "jopi-toolkit/jk_schema";
2
+ import type { JopiDataTable, JDataReadParams, JDataReadResult, JRowArrayFilter } from "./interfaces.ts";
3
+ export * from "./interfaces.ts";
4
+
5
+ //region Rows Arrays
6
+
7
+ /**
8
+ * Filter the row content according to rules.
9
+ */
10
+ export function simpleRowArrayFilter(rows: any[], params: JRowArrayFilter): JDataReadResult {
11
+ // > Apply filter.
12
+
13
+ if (params.filter) {
14
+ const f = params.filter;
15
+
16
+ rows = rows.filter(r => {
17
+ if (f.field) {
18
+ let v = r[f.field];
19
+ if (v===undefined) return false;
20
+ return String(v).includes(f.value);
21
+ } else {
22
+ for (let v of Object.values(r)) {
23
+ if (v===undefined) continue;
24
+ if (String(v).includes(f.value)) return true;
25
+ }
26
+
27
+ return false;
28
+ }
29
+ });
30
+ }
31
+
32
+ // > Apply sorting.
33
+
34
+ if (params.sorting && params.sorting.length) {
35
+ const sorting = params.sorting[0];
36
+ const sortField = sorting.id;
37
+ const sortDesc = sorting.desc;
38
+
39
+ rows = rows.sort((a, b) => {
40
+ let av = a[sortField];
41
+ let bv = b[sortField];
42
+
43
+ if (av === undefined) av = "";
44
+ if (bv === undefined) bv = "";
45
+
46
+ const avIsNumber = typeof av === "number";
47
+ const bvIsNumber = typeof bv === "number";
48
+
49
+ if (avIsNumber && bvIsNumber) {
50
+ if (sortDesc) {
51
+ return bv - av;
52
+ } else {
53
+ return av - bv;
54
+ }
55
+ } else {
56
+ const avStr = String(av);
57
+ const bvStr = String(bv);
58
+
59
+ if (sortDesc) {
60
+ return bvStr.localeCompare(avStr);
61
+ } else {
62
+ return avStr.localeCompare(bvStr);
63
+ }
64
+ }
65
+ });
66
+ }
67
+
68
+ const totalWithoutPagination = rows.length;
69
+ let offset = 0;
70
+
71
+ if (params.page) {
72
+ offset = params.page.pageIndex * params.page.pageSize;
73
+ rows = rows.slice(offset, offset + params.page.pageSize);
74
+ }
75
+
76
+ return {rows, total: totalWithoutPagination, offset};
77
+ }
78
+
79
+ //endregion
80
+
81
+ //region JDataBinding
82
+
83
+ export class JDataBinding_UseArray implements JopiDataTable {
84
+ public constructor(public readonly schema: Schema, private readonly rows: any[]) {
85
+ }
86
+
87
+ async read(params: JDataReadParams): Promise<JDataReadResult> {
88
+ return simpleRowArrayFilter(this.rows, params);
89
+ }
90
+ }
91
+
92
+ //endregion
@@ -1,166 +1,3 @@
1
- import {type Schema} from "jopi-toolkit/jk_schema";
2
-
3
- //region Rows Arrays
4
-
5
- export interface JFieldSorting {
6
- id: string;
7
- desc: boolean;
8
- }
9
-
10
- export interface JFieldFilter {
11
- value?: string | number | boolean;
12
- constraint: JFieldConstraintType;
13
- caseSensitive?: boolean;
14
- }
15
-
16
- export type JFieldConstraintType =
17
- | "$eq" // Equals
18
- | "$ne" // Not equals
19
- | "$gt" // Greater than
20
- | "$gte" // Greater than or equals
21
- | "$lt" // Less than
22
- | "$lte" // Less than or equals
23
- | "$in" // In an array of values
24
- | "$nin" // Not in an array of values
25
- | "$like" // Like search %endsWith or startsWith%
26
-
27
- export interface JRowsFilter {
28
- field?: string;
29
- value: string;
30
- }
31
-
32
- export interface JPageExtraction {
33
- pageIndex: number;
34
- pageSize: number;
35
- }
36
-
37
- export interface JRowArrayFilter {
38
- page?: JPageExtraction;
39
- filter?: JRowsFilter;
40
- sorting?: JFieldSorting[];
41
- fieldFilters?: Record<string, JFieldFilter[]>;
42
- }
43
-
44
- /**
45
- * Filter the row content according to rules.
46
- */
47
- export function simpleRowArrayFilter(rows: any[], params: JRowArrayFilter): JTableDs_ReadResult {
48
- // > Apply filter.
49
-
50
- if (params.filter) {
51
- const f = params.filter;
52
-
53
- rows = rows.filter(r => {
54
- if (f.field) {
55
- let v = r[f.field];
56
- if (v===undefined) return false;
57
- return String(v).includes(f.value);
58
- } else {
59
- for (let v of Object.values(r)) {
60
- if (v===undefined) continue;
61
- if (String(v).includes(f.value)) return true;
62
- }
63
-
64
- return false;
65
- }
66
- });
67
- }
68
-
69
- // > Apply sorting.
70
-
71
- if (params.sorting && params.sorting.length) {
72
- const sorting = params.sorting[0];
73
- const sortField = sorting.id;
74
- const sortDesc = sorting.desc;
75
-
76
- rows = rows.sort((a, b) => {
77
- let av = a[sortField];
78
- let bv = b[sortField];
79
-
80
- if (av === undefined) av = "";
81
- if (bv === undefined) bv = "";
82
-
83
- const avIsNumber = typeof av === "number";
84
- const bvIsNumber = typeof bv === "number";
85
-
86
- if (avIsNumber && bvIsNumber) {
87
- if (sortDesc) {
88
- return bv - av;
89
- } else {
90
- return av - bv;
91
- }
92
- } else {
93
- const avStr = String(av);
94
- const bvStr = String(bv);
95
-
96
- if (sortDesc) {
97
- return bvStr.localeCompare(avStr);
98
- } else {
99
- return avStr.localeCompare(bvStr);
100
- }
101
- }
102
- });
103
- }
104
-
105
- const totalWithoutPagination = rows.length;
106
- let offset = 0;
107
-
108
- if (params.page) {
109
- offset = params.page.pageIndex * params.page.pageSize;
110
- rows = rows.slice(offset, offset + params.page.pageSize);
111
- }
112
-
113
- return {rows, total: totalWithoutPagination, offset};
114
- }
115
-
116
- //endregion
117
-
118
- //region JTableDs
119
-
120
- export interface JTableDs_ReadParams extends JRowArrayFilter {
121
- }
122
-
123
- export interface JTableDs_ReadResult {
124
- rows: any[];
125
- total?: number;
126
- offset?: number;
127
- }
128
-
129
- export interface JTableDs {
130
- get name(): string;
131
- get schema(): Schema;
132
- read(params: JTableDs_ReadParams): Promise<JTableDs_ReadResult>;
133
- }
134
-
135
- export class JTableDs_UseArray implements JTableDs {
136
- public constructor(public readonly name: string, public readonly schema: Schema, private readonly rows: any[]) {
137
- }
138
-
139
- async read(params: JTableDs_ReadParams): Promise<JTableDs_ReadResult> {
140
- return simpleRowArrayFilter(this.rows, params);
141
- }
142
- }
143
-
144
- export class JTableDs_HttpProxy implements JTableDs {
145
- public constructor(public readonly name: string, private readonly url: string, public readonly schema: Schema) {
146
- }
147
-
148
- async read(params: JTableDs_ReadParams): Promise<JTableDs_ReadResult> {
149
- let toSend = {dsName: this.name, read: params};
150
-
151
- let res = await fetch(this.url, {
152
- method: "POST",
153
- headers: {"Content-Type": "application/json"},
154
- body: JSON.stringify(toSend)
155
- });
156
-
157
- if (res.status !== 200) {
158
- throw new Error(`Error while reading data source "${this.name}"`);
159
- }
160
-
161
- let asJson = await res.json();
162
- return asJson as JTableDs_ReadResult;
163
- }
164
- }
165
-
166
- //endregion
1
+ export * from "./core.ts";
2
+ export * from "./proxy.ts";
3
+ export * from "./interfaces.ts";
@@ -0,0 +1,140 @@
1
+ import { type Schema } from "jopi-toolkit/jk_schema";
2
+ import type {Translatable} from "../jk_tools";
3
+
4
+ export interface JFieldSorting {
5
+ id: string;
6
+ desc: boolean;
7
+ }
8
+
9
+ export interface IActionContext {
10
+ refresh: () => void;
11
+ }
12
+
13
+ export interface JFieldFilter {
14
+ value?: string | number | boolean;
15
+ constraint: JFieldConstraintType;
16
+ caseSensitive?: boolean;
17
+ }
18
+
19
+ export type JFieldConstraintType =
20
+ | "$eq" // Equals
21
+ | "$ne" // Not equals
22
+ | "$gt" // Greater than
23
+ | "$gte" // Greater than or equals
24
+ | "$lt" // Less than
25
+ | "$lte" // Less than or equals
26
+ | "$in" // In an array of values
27
+ | "$nin" // Not in an array of values
28
+ | "$like" // Like search %endsWith or startsWith%
29
+ ;
30
+
31
+ export interface JGlobalFilter {
32
+ field?: string;
33
+ value: string;
34
+ }
35
+
36
+ export interface JPageExtraction {
37
+ pageIndex: number;
38
+ pageSize: number;
39
+ }
40
+
41
+ export interface JRowArrayFilter {
42
+ page?: JPageExtraction;
43
+ filter?: JGlobalFilter;
44
+ sorting?: JFieldSorting[];
45
+ fieldFilters?: Record<string, JFieldFilter[]>;
46
+ }
47
+
48
+ export interface JDataReadParams extends JRowArrayFilter {
49
+ }
50
+
51
+ export interface JDataReadResult {
52
+ rows: any[];
53
+ total?: number;
54
+ offset?: number;
55
+ }
56
+
57
+ export interface JActionDef {
58
+ id: string;
59
+ title?: Translatable;
60
+ separator?: boolean;
61
+ }
62
+
63
+ export interface JopiDataTable {
64
+ readonly schema: Schema;
65
+ readonly actions?: JActionDef[];
66
+ read(params: JDataReadParams): Promise<JDataReadResult>;
67
+ }
68
+
69
+ export interface JDataTable extends JopiDataTable {
70
+ readonly name: string;
71
+ executeAction?: (rows: any[], actionName: string, context?: IActionContext) => Promise<JActionResult | void>
72
+ isActionEnabled?: (actionName: string, rows: any[], context?: IActionContext) => boolean;
73
+ }
74
+
75
+ export interface JActionPreProcessParams {
76
+ rows: any[];
77
+ context?: IActionContext;
78
+ }
79
+
80
+ export interface JActionResult {
81
+ isOk?: boolean;
82
+ errorCode?: string;
83
+ errorMessage?: string;
84
+ userMessage?: string;
85
+ data?: any;
86
+ }
87
+
88
+ export interface JActionPreProcessResult extends JActionResult {
89
+ rows?: any[];
90
+ }
91
+
92
+ export interface JActionPostProcessParams {
93
+ rows: any[];
94
+ context?: IActionContext;
95
+
96
+ data?: any[];
97
+ userMessage?: string;
98
+ }
99
+
100
+ /**
101
+ * Defines the behavior of a custom action in the browser for a Jopi table.
102
+ * allowing to hook into the action lifecycle (pre-process, server call, post-process).
103
+ */
104
+ export interface JopiTableBrowserActionItem {
105
+ /**
106
+ * Callback invoked when an error occurs during the action execution.
107
+ * This can be triggered by a failure in the `action` handler or a server-side error.
108
+ */
109
+ onError?: (params: JActionResult) => Promise<void>,
110
+
111
+ /**
112
+ * The main client-side action handler.
113
+ * - Can be used to perform checks or data transformation before sending to the server.
114
+ * - Can be used as a standalone action if `disableServerCall` is true.
115
+ * - Return `void` to proceed with the default flow.
116
+ * - Return a `JActionPreProcessResult` to control flow (e.g., stop execution if `isOk` is false) or modify data sent to server.
117
+ */
118
+ action?: (params: JActionPreProcessParams) => Promise<JActionPreProcessResult|void>,
119
+
120
+ /**
121
+ * Callback invoked after the server-side action has successfully completed.
122
+ * Useful for showing notifications, refreshing data, or triggering other UI updates.
123
+ */
124
+ afterServerCall?: (params: JActionPostProcessParams) => Promise<void>;
125
+
126
+ /**
127
+ * Function to determine if the action should be enabled/clickable.
128
+ * Based on the currently selected rows and the current action context.
129
+ * If not provided, the action is assumed to be always enabled.
130
+ */
131
+ canEnable?: (rows: any[], context?: IActionContext) => boolean;
132
+
133
+ /**
134
+ * If set to true, the framework will NOT assume there is a corresponding server-side action to call.
135
+ * Use this for actions that are purely client-side (e.g., "Copy to clipboard").
136
+ */
137
+ disableServerCall?: boolean;
138
+ }
139
+
140
+ export type JopiTableBrowserActions = Record<string, JopiTableBrowserActionItem>
@@ -0,0 +1,102 @@
1
+ import type { IActionContext, JopiTableBrowserActions, JDataReadParams, JDataReadResult, JDataTable, JActionDef, JActionResult } from "./interfaces.ts";
2
+ import { schema, type Schema } from "jopi-toolkit/jk_schema";
3
+
4
+ export interface ProxyParams {
5
+ name: string;
6
+ apiUrl: string;
7
+ actions?: JActionDef[];
8
+ schema: { meta: any; desc: any; };
9
+ }
10
+
11
+ export class Proxy implements JDataTable {
12
+ readonly name: string;
13
+ readonly schema: Schema;
14
+ readonly actions?: JActionDef[];
15
+ private readonly url: string;
16
+
17
+ readonly browserActions: JopiTableBrowserActions;
18
+
19
+ constructor(params: ProxyParams, browserActions: JopiTableBrowserActions) {
20
+ this.name = params.name;
21
+ this.url = params.apiUrl;
22
+ this.actions = params.actions;
23
+ this.schema = schema(params.schema.desc, params.schema.meta);
24
+ this.browserActions = browserActions;
25
+ }
26
+
27
+ async read(params: JDataReadParams): Promise<JDataReadResult> {
28
+ const asJson = await this.callServer({ dsName: this.name, read: params });
29
+ return asJson as JDataReadResult;
30
+ }
31
+
32
+ isActionEnabled(actionName: string, rows: any[], context?: IActionContext): boolean {
33
+ let actionEntry = this.browserActions[actionName];
34
+ if (!actionEntry) return false;
35
+ if (!actionEntry.canEnable) return true;
36
+ return actionEntry.canEnable(rows, context);
37
+ }
38
+
39
+ async executeAction(rows: any[], actionName: string, context?: IActionContext): Promise<JActionResult|void> {
40
+ async function processError(res: JActionResult | undefined) {
41
+ if (!res) return true;
42
+
43
+ if (res.isOk===false||res.errorCode||res.errorMessage) {
44
+ if (actionEntry.onError) {
45
+ await actionEntry.onError(res);
46
+ return false;
47
+ }
48
+ }
49
+
50
+ return true;
51
+ }
52
+
53
+ let actionEntry = this.browserActions[actionName];
54
+ if (!actionEntry) return;
55
+
56
+ if (actionEntry.action) {
57
+ let res = await actionEntry.action({ rows, context });
58
+
59
+ if (res) {
60
+ if (!processError(res)) return;
61
+
62
+ if (res.rows !== undefined) {
63
+ rows = res.rows;
64
+ }
65
+ }
66
+ }
67
+
68
+ if (actionEntry.disableServerCall === true) {
69
+ return;
70
+ }
71
+
72
+ let serverRes = await this.callServer({ action: actionName, rows });
73
+ if (!processError(serverRes)) return;
74
+
75
+ if (actionEntry.afterServerCall) {
76
+ await actionEntry.afterServerCall({
77
+ rows,
78
+ context,
79
+ data: serverRes?.data,
80
+ userMessage: serverRes?.userMessage
81
+ });
82
+ }
83
+ }
84
+
85
+ async callServer(data: any): Promise<any> {
86
+ let res = await fetch(this.url, {
87
+ method: "POST",
88
+ headers: {"Content-Type": "application/json"},
89
+ body: JSON.stringify(data)
90
+ });
91
+
92
+ if (res.status !== 200) {
93
+ throw new Error(`Error while calling data source "${this.name}"`);
94
+ }
95
+
96
+ return await res.json();
97
+ }
98
+ }
99
+
100
+ export function toDataTableProxy(params: ProxyParams, browserActions?: JopiTableBrowserActions): JDataTable {
101
+ return new Proxy(params, browserActions || {});
102
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Calculate week-number from a date.
3
+ */
4
+ export function calcWeekNumber(year: number, month: number, day: number): number {
5
+ const date = new Date(Date.UTC(year, month - 1, day));
6
+ const dayNum = date.getUTCDay() || 7;
7
+
8
+ date.setUTCDate(date.getUTCDate() + (4 - dayNum));
9
+ const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
10
+
11
+ return Math.ceil((((date.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
12
+ }
@@ -1,7 +1,7 @@
1
1
  // noinspection JSUnusedGlobalSymbols
2
2
 
3
3
  import fs from "node:fs/promises";
4
- import fss, {createReadStream, createWriteStream} from "node:fs";
4
+ import fss, {createReadStream} from "node:fs";
5
5
  import {fileURLToPath as n_fileURLToPath, pathToFileURL as n_pathToFileURL } from "node:url";
6
6
  import {lookup} from "mime-types";
7
7
  import {Readable} from "node:stream";
@@ -172,6 +172,15 @@ export async function writeTextToFile(filePath: string, text: string, createDir:
172
172
  await fs.writeFile(filePath, text, {encoding: 'utf8', flag: 'w'});
173
173
  }
174
174
 
175
+ export async function appendTextToFile(filePath: string, text: string): Promise<void> {
176
+ try {
177
+ await fs.appendFile(filePath, text, {encoding: 'utf8'});
178
+ } catch {
179
+ await mkDir(path.dirname(filePath));
180
+ await fs.appendFile(filePath, text, {encoding: 'utf8'});
181
+ }
182
+ }
183
+
175
184
  export function writeTextToFileSync(filePath: string, text: string, createDir: boolean = true): void {
176
185
  if (createDir) {
177
186
  try {
@@ -516,6 +525,7 @@ export const join = path.join;
516
525
  export const resolve = path.resolve;
517
526
  export const dirname = path.dirname;
518
527
  export const extname = path.extname;
528
+ export const relative = path.relative;
519
529
 
520
530
  export const sep = path.sep;
521
531
  export const isAbsolute = path.isAbsolute;
@@ -202,18 +202,14 @@ export class JkMemCache {
202
202
  /**
203
203
  * Retrieve an item from the cache with its metadata.
204
204
  */
205
- public getWithMeta<T = any>(key: string, peek = false): { value: T; meta: any } | null {
205
+ public getWithMeta<T = any>(key: string, peek = false): { value: T; meta: any; size: number } | null {
206
206
  const entry = this._storage.get(key);
207
+
207
208
  if (!entry) return null;
208
-
209
- if (entry.expiresAt && entry.expiresAt < Date.now()) {
210
- this.delete(key);
211
- return null;
212
- }
213
-
214
209
  if (!peek) entry.accessCount++;
215
210
 
216
211
  let value: T;
212
+
217
213
  if (entry.type === 'buffer') {
218
214
  value = entry.value as T;
219
215
  } else if (entry.type === 'json') {
@@ -222,7 +218,7 @@ export class JkMemCache {
222
218
  value = entry.value as T;
223
219
  }
224
220
 
225
- return { value, meta: entry.meta };
221
+ return { value, meta: entry.meta, size: entry.size };
226
222
  }
227
223
 
228
224
  /**