@decaf-ts/core 0.8.51 → 0.8.53

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 (100) hide show
  1. package/README.md +206 -93
  2. package/dist/core.cjs +1 -1
  3. package/dist/core.cjs.map +1 -1
  4. package/dist/core.js +1 -1
  5. package/dist/core.js.map +1 -1
  6. package/lib/esm/fs/FilesystemAdapter.d.ts +67 -0
  7. package/lib/esm/fs/FilesystemAdapter.js +430 -0
  8. package/lib/esm/fs/FilesystemAdapter.js.map +1 -0
  9. package/lib/esm/fs/FsDispatch.d.ts +7 -0
  10. package/lib/esm/fs/FsDispatch.js +20 -0
  11. package/lib/esm/fs/FsDispatch.js.map +1 -0
  12. package/lib/esm/fs/helpers.d.ts +17 -0
  13. package/lib/esm/fs/helpers.js +64 -0
  14. package/lib/esm/fs/helpers.js.map +1 -0
  15. package/lib/esm/fs/index.d.ts +4 -0
  16. package/lib/esm/fs/index.js +5 -0
  17. package/lib/esm/fs/index.js.map +1 -0
  18. package/lib/esm/fs/indexStore.d.ts +28 -0
  19. package/lib/esm/fs/indexStore.js +173 -0
  20. package/lib/esm/fs/indexStore.js.map +1 -0
  21. package/lib/esm/fs/locks/FilesystemLock.d.ts +13 -0
  22. package/lib/esm/fs/locks/FilesystemLock.js +49 -0
  23. package/lib/esm/fs/locks/FilesystemLock.js.map +1 -0
  24. package/lib/esm/fs/locks/FilesystemMultiLock.d.ts +8 -0
  25. package/lib/esm/fs/locks/FilesystemMultiLock.js +23 -0
  26. package/lib/esm/fs/locks/FilesystemMultiLock.js.map +1 -0
  27. package/lib/esm/fs/types.d.ts +34 -0
  28. package/lib/esm/fs/types.js +2 -0
  29. package/lib/esm/fs/types.js.map +1 -0
  30. package/lib/esm/index.d.ts +1 -1
  31. package/lib/esm/index.js +1 -1
  32. package/lib/esm/ram/RamAdapter.d.ts +1 -1
  33. package/lib/esm/ram/types.d.ts +2 -1
  34. package/lib/esm/tasks/TaskEngine.d.ts +30 -1
  35. package/lib/esm/tasks/TaskEngine.js +361 -16
  36. package/lib/esm/tasks/TaskEngine.js.map +1 -1
  37. package/lib/esm/tasks/TaskService.js +3 -0
  38. package/lib/esm/tasks/TaskService.js.map +1 -1
  39. package/lib/esm/tasks/builder.js +1 -1
  40. package/lib/esm/tasks/builder.js.map +1 -1
  41. package/lib/esm/tasks/constants.js +1 -0
  42. package/lib/esm/tasks/constants.js.map +1 -1
  43. package/lib/esm/tasks/types.d.ts +12 -0
  44. package/lib/esm/tasks/workers/WorkThreadEnvironment.d.ts +32 -0
  45. package/lib/esm/tasks/workers/WorkThreadEnvironment.js +28 -0
  46. package/lib/esm/tasks/workers/WorkThreadEnvironment.js.map +1 -0
  47. package/lib/esm/tasks/workers/messages.d.ts +69 -0
  48. package/lib/esm/tasks/workers/messages.js +2 -0
  49. package/lib/esm/tasks/workers/messages.js.map +1 -0
  50. package/lib/esm/tasks/workers/workerThread.d.ts +1 -0
  51. package/lib/esm/tasks/workers/workerThread.js +185 -0
  52. package/lib/esm/tasks/workers/workerThread.js.map +1 -0
  53. package/lib/fs/FilesystemAdapter.cjs +437 -0
  54. package/lib/fs/FilesystemAdapter.d.ts +67 -0
  55. package/lib/fs/FilesystemAdapter.js.map +1 -0
  56. package/lib/fs/FsDispatch.cjs +24 -0
  57. package/lib/fs/FsDispatch.d.ts +7 -0
  58. package/lib/fs/FsDispatch.js.map +1 -0
  59. package/lib/fs/helpers.cjs +76 -0
  60. package/lib/fs/helpers.d.ts +17 -0
  61. package/lib/fs/helpers.js.map +1 -0
  62. package/lib/fs/index.cjs +21 -0
  63. package/lib/fs/index.d.ts +4 -0
  64. package/lib/fs/index.js.map +1 -0
  65. package/lib/fs/indexStore.cjs +181 -0
  66. package/lib/fs/indexStore.d.ts +28 -0
  67. package/lib/fs/indexStore.js.map +1 -0
  68. package/lib/fs/locks/FilesystemLock.cjs +56 -0
  69. package/lib/fs/locks/FilesystemLock.d.ts +13 -0
  70. package/lib/fs/locks/FilesystemLock.js.map +1 -0
  71. package/lib/fs/locks/FilesystemMultiLock.cjs +30 -0
  72. package/lib/fs/locks/FilesystemMultiLock.d.ts +8 -0
  73. package/lib/fs/locks/FilesystemMultiLock.js.map +1 -0
  74. package/lib/fs/types.cjs +3 -0
  75. package/lib/fs/types.d.ts +34 -0
  76. package/lib/fs/types.js.map +1 -0
  77. package/lib/index.cjs +1 -1
  78. package/lib/index.d.ts +1 -1
  79. package/lib/ram/RamAdapter.d.ts +1 -1
  80. package/lib/ram/types.d.ts +2 -1
  81. package/lib/tasks/TaskEngine.cjs +360 -15
  82. package/lib/tasks/TaskEngine.d.ts +30 -1
  83. package/lib/tasks/TaskEngine.js.map +1 -1
  84. package/lib/tasks/TaskService.cjs +3 -0
  85. package/lib/tasks/TaskService.js.map +1 -1
  86. package/lib/tasks/builder.cjs +1 -1
  87. package/lib/tasks/builder.js.map +1 -1
  88. package/lib/tasks/constants.cjs +1 -0
  89. package/lib/tasks/constants.js.map +1 -1
  90. package/lib/tasks/types.d.ts +12 -0
  91. package/lib/tasks/workers/WorkThreadEnvironment.cjs +31 -0
  92. package/lib/tasks/workers/WorkThreadEnvironment.d.ts +32 -0
  93. package/lib/tasks/workers/WorkThreadEnvironment.js.map +1 -0
  94. package/lib/tasks/workers/messages.cjs +3 -0
  95. package/lib/tasks/workers/messages.d.ts +69 -0
  96. package/lib/tasks/workers/messages.js.map +1 -0
  97. package/lib/tasks/workers/workerThread.cjs +220 -0
  98. package/lib/tasks/workers/workerThread.d.ts +1 -0
  99. package/lib/tasks/workers/workerThread.js.map +1 -0
  100. package/package.json +19 -8
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/fs/index.ts"],"names":[],"mappings":"AAAA,uCAAoC;AACpC,2BAAwB;AACxB,6BAA0B;AAC1B,gCAA6B"}
@@ -0,0 +1,28 @@
1
+ import type { promises as FsPromises } from "node:fs";
2
+ import { PrimaryKeyType } from "@decaf-ts/db-decorators";
3
+ import { OrderDirection } from "../repository/constants";
4
+ import { JsonSpacing } from "./helpers";
5
+ export type IndexDescriptor = {
6
+ name: string;
7
+ fileName: string;
8
+ columns: string[];
9
+ directions?: OrderDirection[2];
10
+ };
11
+ export declare function toIndexFileName(indexName: string): string;
12
+ export declare class FsIndexStore {
13
+ private readonly fs;
14
+ private readonly indexDirResolver;
15
+ private readonly spacing?;
16
+ private readonly cache;
17
+ constructor(fs: typeof FsPromises, indexDirResolver: (tableName: string) => string, spacing?: JsonSpacing);
18
+ ensure(tableName: string, descriptors: IndexDescriptor[]): Promise<void>;
19
+ upsert(tableName: string, descriptors: IndexDescriptor[], id: PrimaryKeyType, record: Record<string, any>, previous?: Record<string, any>): Promise<void>;
20
+ remove(tableName: string, descriptors: IndexDescriptor[], id: PrimaryKeyType, record?: Record<string, any>): Promise<void>;
21
+ private removeFromEntries;
22
+ private removeFromAll;
23
+ private keyForRecord;
24
+ private normalizeValue;
25
+ private indexPath;
26
+ private persist;
27
+ refresh(tableName: string, descriptors: IndexDescriptor[]): Promise<void>;
28
+ }
@@ -0,0 +1,173 @@
1
+ import path from "node:path";
2
+ import { ensureDir, readJsonFile, serializeId, writeJsonAtomic, } from "./helpers.js";
3
+ const KEY_SEPARATOR = "::";
4
+ export function toIndexFileName(indexName) {
5
+ return encodeURIComponent(indexName).replace(/%/g, "_");
6
+ }
7
+ export class FsIndexStore {
8
+ constructor(fs, indexDirResolver, spacing) {
9
+ this.fs = fs;
10
+ this.indexDirResolver = indexDirResolver;
11
+ this.spacing = spacing;
12
+ this.cache = new Map();
13
+ }
14
+ async ensure(tableName, descriptors) {
15
+ if (!descriptors.length)
16
+ return;
17
+ await ensureDir(this.fs, this.indexDirResolver(tableName));
18
+ if (!this.cache.has(tableName))
19
+ this.cache.set(tableName, new Map());
20
+ const tableCache = this.cache.get(tableName);
21
+ await Promise.all(descriptors.map(async (descriptor) => {
22
+ if (tableCache.has(descriptor.fileName))
23
+ return;
24
+ const filePath = this.indexPath(tableName, descriptor.fileName);
25
+ const existing = await readJsonFile(this.fs, filePath);
26
+ const payload = existing && existing.columns?.length
27
+ ? {
28
+ ...descriptor,
29
+ entries: existing.entries ?? {},
30
+ directions: existing.directions ?? descriptor.directions,
31
+ columns: existing.columns,
32
+ }
33
+ : {
34
+ ...descriptor,
35
+ entries: {},
36
+ };
37
+ tableCache.set(descriptor.fileName, payload);
38
+ }));
39
+ }
40
+ async upsert(tableName, descriptors, id, record, previous) {
41
+ if (!descriptors.length)
42
+ return;
43
+ await this.ensure(tableName, descriptors);
44
+ const tableCache = this.cache.get(tableName);
45
+ if (!tableCache)
46
+ return;
47
+ const serializedId = serializeId(id);
48
+ await Promise.all(descriptors.map(async (descriptor) => {
49
+ const payload = tableCache.get(descriptor.fileName);
50
+ if (!payload)
51
+ return;
52
+ if (previous) {
53
+ const prevKey = this.keyForRecord(previous, descriptor.columns);
54
+ if (prevKey) {
55
+ this.removeFromEntries(payload.entries, prevKey, serializedId);
56
+ }
57
+ }
58
+ const nextKey = this.keyForRecord(record, descriptor.columns);
59
+ if (!nextKey)
60
+ return;
61
+ const bucket = payload.entries[nextKey] ?? [];
62
+ if (!bucket.find((entry) => entry.type === serializedId.type && entry.value === serializedId.value)) {
63
+ bucket.push(serializedId);
64
+ payload.entries[nextKey] = bucket;
65
+ }
66
+ await this.persist(tableName, payload);
67
+ }));
68
+ }
69
+ async remove(tableName, descriptors, id, record) {
70
+ if (!descriptors.length)
71
+ return;
72
+ await this.ensure(tableName, descriptors);
73
+ const tableCache = this.cache.get(tableName);
74
+ if (!tableCache)
75
+ return;
76
+ const serializedId = serializeId(id);
77
+ await Promise.all(descriptors.map(async (descriptor) => {
78
+ const payload = tableCache.get(descriptor.fileName);
79
+ if (!payload)
80
+ return;
81
+ let removed = false;
82
+ if (record) {
83
+ const key = this.keyForRecord(record, descriptor.columns);
84
+ if (key) {
85
+ removed = this.removeFromEntries(payload.entries, key, serializedId);
86
+ }
87
+ }
88
+ if (!removed) {
89
+ removed = this.removeFromAll(payload.entries, serializedId);
90
+ }
91
+ if (removed) {
92
+ await this.persist(tableName, payload);
93
+ }
94
+ }));
95
+ }
96
+ removeFromEntries(entries, key, id) {
97
+ const bucket = entries[key];
98
+ if (!bucket)
99
+ return false;
100
+ const filtered = bucket.filter((entry) => entry.value !== id.value || entry.type !== id.type);
101
+ if (filtered.length) {
102
+ entries[key] = filtered;
103
+ }
104
+ else {
105
+ delete entries[key];
106
+ }
107
+ return filtered.length !== bucket.length;
108
+ }
109
+ removeFromAll(entries, id) {
110
+ let removed = false;
111
+ for (const key of Object.keys(entries)) {
112
+ removed = this.removeFromEntries(entries, key, id) || removed;
113
+ }
114
+ return removed;
115
+ }
116
+ keyForRecord(record, columns) {
117
+ if (!record)
118
+ return undefined;
119
+ const values = [];
120
+ for (const column of columns) {
121
+ if (!(column in record) || typeof record[column] === "undefined") {
122
+ return undefined;
123
+ }
124
+ values.push(record[column]);
125
+ }
126
+ return values.map(this.normalizeValue).join(KEY_SEPARATOR);
127
+ }
128
+ normalizeValue(value) {
129
+ if (value === null)
130
+ return "__null__";
131
+ if (value === undefined)
132
+ return "__undefined__";
133
+ if (typeof value === "object") {
134
+ try {
135
+ return JSON.stringify(value);
136
+ }
137
+ catch {
138
+ return String(value);
139
+ }
140
+ }
141
+ return String(value);
142
+ }
143
+ indexPath(tableName, fileName) {
144
+ return path.join(this.indexDirResolver(tableName), `${fileName}.json`);
145
+ }
146
+ async persist(tableName, payload) {
147
+ const filePath = this.indexPath(tableName, payload.fileName);
148
+ await writeJsonAtomic(this.fs, filePath, payload, this.spacing);
149
+ }
150
+ async refresh(tableName, descriptors) {
151
+ if (!descriptors.length)
152
+ return;
153
+ await this.ensure(tableName, descriptors);
154
+ const tableCache = this.cache.get(tableName);
155
+ if (!tableCache)
156
+ return;
157
+ await Promise.all(descriptors.map(async (descriptor) => {
158
+ const filePath = this.indexPath(tableName, descriptor.fileName);
159
+ const payload = await readJsonFile(this.fs, filePath);
160
+ if (!payload) {
161
+ tableCache.delete(descriptor.fileName);
162
+ return;
163
+ }
164
+ const refreshed = {
165
+ ...descriptor,
166
+ entries: payload.entries ?? {},
167
+ directions: payload.directions ?? descriptor.directions,
168
+ };
169
+ tableCache.set(descriptor.fileName, refreshed);
170
+ }));
171
+ }
172
+ }
173
+ //# sourceMappingURL=indexStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexStore.js","sourceRoot":"","sources":["../../../src/fs/indexStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { promises as defaultFs } from "node:fs";
2
+ import { Lock } from "@decaf-ts/transactional-decorators";
3
+ export declare class FilesystemLock extends Lock {
4
+ private readonly lockPath;
5
+ private readonly fs;
6
+ private readonly waitMs;
7
+ private handle?;
8
+ constructor(lockPath: string, fs?: typeof defaultFs, waitMs?: number);
9
+ private takeLock;
10
+ private releaseLockFile;
11
+ acquire(...args: any[]): Promise<void>;
12
+ release(...args: any[]): void;
13
+ }
@@ -0,0 +1,49 @@
1
+ import { promises as defaultFs, constants as fsConstants } from "node:fs";
2
+ import path from "node:path";
3
+ import { Lock } from "@decaf-ts/transactional-decorators";
4
+ import { ensureDir } from "./../helpers.js";
5
+ const DEFAULT_WAIT_MS = 50;
6
+ export class FilesystemLock extends Lock {
7
+ constructor(lockPath, fs = defaultFs, waitMs = DEFAULT_WAIT_MS) {
8
+ super();
9
+ this.lockPath = lockPath;
10
+ this.fs = fs;
11
+ this.waitMs = waitMs;
12
+ }
13
+ async takeLock() {
14
+ await ensureDir(this.fs, path.dirname(this.lockPath));
15
+ while (true) {
16
+ try {
17
+ this.handle = await this.fs.open(this.lockPath, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_RDWR);
18
+ return;
19
+ }
20
+ catch (err) {
21
+ if (err?.code === "EEXIST") {
22
+ await new Promise((resolve) => setTimeout(resolve, this.waitMs));
23
+ continue;
24
+ }
25
+ throw err;
26
+ }
27
+ }
28
+ }
29
+ async releaseLockFile() {
30
+ if (!this.handle)
31
+ return;
32
+ try {
33
+ await this.handle.close();
34
+ }
35
+ catch {
36
+ // ignore errors while closing
37
+ }
38
+ await this.fs.rm(this.lockPath, { force: true });
39
+ this.handle = undefined;
40
+ }
41
+ async acquire(...args) {
42
+ await super.acquire(...args);
43
+ await this.takeLock();
44
+ }
45
+ release(...args) {
46
+ void this.releaseLockFile().then(() => super.release(...args));
47
+ }
48
+ }
49
+ //# sourceMappingURL=FilesystemLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilesystemLock.js","sourceRoot":"","sources":["../../../../src/fs/locks/FilesystemLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,SAAS,EAAE,SAAS,IAAI,WAAW,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,wBAAmB;AAEvC,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,MAAM,OAAO,cAAe,SAAQ,IAAI;IAGtC,YACmB,QAAgB,EAChB,KAAuB,SAAS,EAChC,SAAiB,eAAe;QAEjD,KAAK,EAAE,CAAC;QAJS,aAAQ,GAAR,QAAQ,CAAQ;QAChB,OAAE,GAAF,EAAE,CAA8B;QAChC,WAAM,GAAN,MAAM,CAA0B;IAGnD,CAAC;IAEO,KAAK,CAAC,QAAQ;QACpB,MAAM,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtD,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,IAAI,CAC9B,IAAI,CAAC,QAAQ,EACb,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAC9D,CAAC;gBACF,OAAO;YACT,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,IAAI,GAAG,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC3B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;oBACjE,SAAS;gBACX,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,eAAe;QAC3B,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QACzB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,8BAA8B;QAChC,CAAC;QACD,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAC1B,CAAC;IAEQ,KAAK,CAAC,OAAO,CAAC,GAAG,IAAW;QACnC,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7B,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAEQ,OAAO,CAAC,GAAG,IAAW;QAC7B,KAAK,IAAI,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACjE,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import { promises as defaultFs } from "node:fs";
2
+ import { MultiLock, Lock } from "@decaf-ts/transactional-decorators";
3
+ export declare class FilesystemMultiLock extends MultiLock {
4
+ private readonly lockDir;
5
+ private readonly fs;
6
+ constructor(lockDir: string, fs?: typeof defaultFs);
7
+ protected lockFor(name: string): Promise<Lock>;
8
+ }
@@ -0,0 +1,23 @@
1
+ import { promises as defaultFs } from "node:fs";
2
+ import path from "node:path";
3
+ import { MultiLock } from "@decaf-ts/transactional-decorators";
4
+ import { ensureDir } from "./../helpers.js";
5
+ import { FilesystemLock } from "./FilesystemLock.js";
6
+ export class FilesystemMultiLock extends MultiLock {
7
+ constructor(lockDir, fs = defaultFs) {
8
+ super();
9
+ this.lockDir = lockDir;
10
+ this.fs = fs;
11
+ }
12
+ async lockFor(name) {
13
+ await this.lock.acquire();
14
+ if (!this.locks[name]) {
15
+ const lockPath = path.join(this.lockDir, `${encodeURIComponent(name)}.lock`);
16
+ await ensureDir(this.fs, path.dirname(lockPath));
17
+ this.locks[name] = new FilesystemLock(lockPath, this.fs);
18
+ }
19
+ this.lock.release();
20
+ return this.locks[name];
21
+ }
22
+ }
23
+ //# sourceMappingURL=FilesystemMultiLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilesystemMultiLock.js","sourceRoot":"","sources":["../../../../src/fs/locks/FilesystemMultiLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAQ,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,wBAAmB;AACvC,OAAO,EAAE,cAAc,EAAE,4BAAyB;AAElD,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IAChD,YACmB,OAAe,EACf,KAAuB,SAAS;QAEjD,KAAK,EAAE,CAAC;QAHS,YAAO,GAAP,OAAO,CAAQ;QACf,OAAE,GAAF,EAAE,CAA8B;IAGnD,CAAC;IAEkB,KAAK,CAAC,OAAO,CAAC,IAAY;QAC3C,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CACxB,IAAI,CAAC,OAAO,EACZ,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,CACnC,CAAC;YACF,MAAM,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YACjD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,34 @@
1
+ import type { promises as FsPromises } from "node:fs";
2
+ import type { RamConfig } from "../ram/types";
3
+ import type { JsonSpacing } from "./helpers";
4
+ export type FilesystemHydrationInfo = {
5
+ table: string;
6
+ records: number;
7
+ };
8
+ export type FilesystemConfig = RamConfig & {
9
+ /**
10
+ * Base directory where adapter data is persisted.
11
+ * A sub-directory using the adapter alias will be created automatically.
12
+ */
13
+ rootDir?: string;
14
+ /**
15
+ * Optional fs/promises implementation (for testing/mocking).
16
+ */
17
+ fs?: typeof FsPromises;
18
+ /**
19
+ * Whether JSON files should use pretty formatting.
20
+ */
21
+ jsonSpacing?: JsonSpacing;
22
+ /**
23
+ * Optional callback invoked after a table has been hydrated from disk.
24
+ */
25
+ onHydrated?: (info: FilesystemHydrationInfo) => void;
26
+ /**
27
+ * Directory used to store lockfiles when filesystem locking is enabled.
28
+ */
29
+ lockDir?: string;
30
+ /**
31
+ * Minimum debounce window (in milliseconds) used by watchers before notifying observers.
32
+ */
33
+ watchDebounceMs?: number;
34
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/fs/types.ts"],"names":[],"mappings":""}
@@ -22,7 +22,7 @@ export * from "./persistence";
22
22
  * @const VERSION
23
23
  * @memberOf module:core
24
24
  */
25
- export declare const VERSION = "0.8.50";
25
+ export declare const VERSION = "0.8.52";
26
26
  /**
27
27
  * @description Stores the current package version
28
28
  * @summary A constant representing the version of the core package
package/lib/esm/index.js CHANGED
@@ -32,7 +32,7 @@ export * from "./persistence/index.js";
32
32
  * @const VERSION
33
33
  * @memberOf module:core
34
34
  */
35
- export const VERSION = "0.8.50";
35
+ export const VERSION = "0.8.52";
36
36
  /**
37
37
  * @description Stores the current package version
38
38
  * @summary A constant representing the version of the core package
@@ -235,7 +235,7 @@ export declare class RamAdapter extends Adapter<RamConfig, RamStorage, RawRamQue
235
235
  * @param {Constructor<M>} from - The model class
236
236
  * @return {Map<string | number, any> | undefined} The table Map or undefined
237
237
  */
238
- protected tableFor<M extends Model>(from: Constructor<M>): Map<string | number, any> | undefined;
238
+ protected tableFor<M extends Model>(from: Constructor<M>): Map<PrimaryKeyType, any> | undefined;
239
239
  /**
240
240
  * @description Executes a raw query against the in-memory storage
241
241
  * @summary Performs a query operation on the in-memory data store using the provided query specification.
@@ -4,6 +4,7 @@ import { Constructor } from "@decaf-ts/decoration";
4
4
  import { Adapter, AdapterFlags } from "../persistence";
5
5
  import { Context } from "../persistence/Context";
6
6
  import { MultiLock } from "@decaf-ts/transactional-decorators";
7
+ import { PrimaryKeyType } from "@decaf-ts/db-decorators";
7
8
  /**
8
9
  * @description In-memory storage structure for the RAM adapter
9
10
  * @summary A nested Map structure that stores all entities by their table name and primary key.
@@ -12,7 +13,7 @@ import { MultiLock } from "@decaf-ts/transactional-decorators";
12
13
  * @memberOf module:core
13
14
  * @category Ram
14
15
  */
15
- export type RamStorage = Map<string, Map<string | number, any>>;
16
+ export type RamStorage = Map<string, Map<PrimaryKeyType, any>>;
16
17
  export type RawRamQuery<M extends Model = any> = {
17
18
  select: undefined | (keyof M)[];
18
19
  from: Constructor<M>;
@@ -4,17 +4,25 @@ import { TaskEventModel } from "./models/TaskEventModel";
4
4
  import { TaskHandlerRegistry } from "./TaskHandlerRegistry";
5
5
  import { TaskEventBus } from "./TaskEventBus";
6
6
  import { Adapter } from "../persistence/Adapter";
7
+ import { Context } from "../persistence/Context";
7
8
  import { ContextOf, FlagsOf } from "../persistence/types";
8
9
  import { AbsContextual, MaybeContextualArg } from "../utils/ContextualLoggedClass";
9
10
  import { OperationKeys } from "@decaf-ts/db-decorators";
11
+ import { TaskContext } from "./TaskContext";
10
12
  import { DateTarget } from "@decaf-ts/decorator-validation";
11
13
  import { Constructor } from "@decaf-ts/decoration";
12
- import { TaskEngineConfig } from "./types";
14
+ import { TaskEngineConfig, TaskFlags } from "./types";
13
15
  import { TaskTracker } from "./TaskTracker";
14
16
  export declare class TaskEngine<A extends Adapter<any, any, any, any>> extends AbsContextual<ContextOf<A>> {
15
17
  private config;
16
18
  private _tasks?;
17
19
  private _events?;
20
+ private workerPoolConfig?;
21
+ private workerThreads;
22
+ private workerJobQueue;
23
+ private workerJobs;
24
+ private workerCounter;
25
+ private workerThreadCapacity;
18
26
  private lock;
19
27
  protected get Context(): Constructor<ContextOf<A>>;
20
28
  protected get adapter(): A;
@@ -23,7 +31,15 @@ export declare class TaskEngine<A extends Adapter<any, any, any, any>> extends A
23
31
  protected get tasks(): Repo<TaskModel>;
24
32
  protected get events(): Repo<TaskEventModel>;
25
33
  protected running: boolean;
34
+ static createTaskContext(base?: Context<any>, overrides?: Partial<TaskFlags>): TaskContext;
26
35
  constructor(config: TaskEngineConfig<A>);
36
+ private normalizeWorkerPoolConfig;
37
+ private hasWorkerPool;
38
+ private getWorkerCount;
39
+ private getWorkerExecutionSlots;
40
+ private canDispatchToWorkers;
41
+ private getExecutionConcurrency;
42
+ private computeWorkerModules;
27
43
  push<I, O>(task: TaskModel<I, O>, ...args: MaybeContextualArg<any>): Promise<TaskModel<I, O>>;
28
44
  push<I, O>(task: TaskModel<I, O>, track: false, ...args: MaybeContextualArg<any>): Promise<TaskModel<I, O>>;
29
45
  push<I, O>(task: TaskModel<I, O>, track: true, ...args: MaybeContextualArg<any>): Promise<{
@@ -51,9 +67,22 @@ export declare class TaskEngine<A extends Adapter<any, any, any, any>> extends A
51
67
  isRunning(): Promise<boolean>;
52
68
  start(...args: MaybeContextualArg<any>): Promise<void>;
53
69
  stop(...args: MaybeContextualArg<any>): Promise<void>;
70
+ private spawnWorkers;
71
+ private createWorker;
72
+ private shutdownWorkers;
73
+ private handleWorkerError;
74
+ private handleWorkerExit;
75
+ private handleWorkerMessage;
76
+ private applyWorkerCache;
77
+ private processWorkerQueue;
78
+ private assignWorker;
79
+ private enqueueWorkerJob;
54
80
  private loop;
55
81
  private claimBatch;
56
82
  private tryClaim;
83
+ private runHandlerInline;
84
+ private dispatchToWorker;
85
+ private invokeHandler;
57
86
  private executeClaimed;
58
87
  private handleTaskStateChange;
59
88
  private runComposite;