veryfront 0.1.1071 → 0.1.1072
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/esm/_dnt.polyfills.d.ts +13 -13
- package/esm/_dnt.polyfills.d.ts.map +1 -1
- package/esm/_dnt.polyfills.js +11 -11
- package/esm/deno.js +1 -1
- package/esm/src/registry/project-scoped-registry-manager.d.ts +18 -5
- package/esm/src/registry/project-scoped-registry-manager.d.ts.map +1 -1
- package/esm/src/registry/project-scoped-registry-manager.js +169 -48
- package/esm/src/tool/registry.d.ts.map +1 -1
- package/esm/src/tool/registry.js +14 -9
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +5 -5
package/esm/_dnt.polyfills.d.ts
CHANGED
|
@@ -109,6 +109,19 @@ interface ImportMetaPonyfill extends ImportMetaPonyfillCommonjs, ImportMetaPonyf
|
|
|
109
109
|
export declare let import_meta_ponyfill_commonjs: ImportMetaPonyfillCommonjs;
|
|
110
110
|
export declare let import_meta_ponyfill_esmodule: ImportMetaPonyfillEsmodule;
|
|
111
111
|
export declare let import_meta_ponyfill: ImportMetaPonyfill;
|
|
112
|
+
declare global {
|
|
113
|
+
interface PromiseConstructor {
|
|
114
|
+
/**
|
|
115
|
+
* Creates a Promise that can be resolved or rejected using provided functions.
|
|
116
|
+
* @returns An object containing `promise` promise object, `resolve` and `reject` functions.
|
|
117
|
+
*/
|
|
118
|
+
withResolvers<T>(): {
|
|
119
|
+
promise: Promise<T>;
|
|
120
|
+
resolve: (value: T | PromiseLike<T>) => void;
|
|
121
|
+
reject: (reason?: any) => void;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
112
125
|
declare global {
|
|
113
126
|
interface Object {
|
|
114
127
|
/**
|
|
@@ -169,17 +182,4 @@ declare global {
|
|
|
169
182
|
}
|
|
170
183
|
}
|
|
171
184
|
export {};
|
|
172
|
-
declare global {
|
|
173
|
-
interface PromiseConstructor {
|
|
174
|
-
/**
|
|
175
|
-
* Creates a Promise that can be resolved or rejected using provided functions.
|
|
176
|
-
* @returns An object containing `promise` promise object, `resolve` and `reject` functions.
|
|
177
|
-
*/
|
|
178
|
-
withResolvers<T>(): {
|
|
179
|
-
promise: Promise<T>;
|
|
180
|
-
resolve: (value: T | PromiseLike<T>) => void;
|
|
181
|
-
reject: (reason?: any) => void;
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
185
|
//# sourceMappingURL=_dnt.polyfills.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_dnt.polyfills.d.ts","sourceRoot":"","sources":["../src/_dnt.polyfills.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,KAAK;QACb,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB;CACF;AAED,OAAO,EAAE,CAAC;AAEV,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,gBAAgB;QACxB,SAAS,CAAC,CAAC,EACP,mBAAmB,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,GAC7F,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;QAEhB,SAAS,CAAC,CAAC,EAAE,CAAC,EACV,mBAAmB,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,EAClE,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,EAC/B,OAAO,CAAC,EAAE,GAAG,GACd,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;KAC1B;CACF;AAoID,OAAO,EAAE,CAAC,CAAA;;;;;;;;;;;GAWP;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAgC,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAGlE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,UAAU;QAClB;;;;;;;;;;;;;;WAcG;QACH,GAAG,EAAE,MAAM,CAAC;QACZ;;;;;;;;;;;;WAYG;QACH,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,GAAG,MAAM,CAAC;QACtE;;;;;;;;WAQG;QACH,IAAI,EAAE,OAAO,CAAC;QAEd;;;;;;;;;;;;WAYG;QACH,QAAQ,EAAE,MAAM,CAAC;QAEjB;;;;;;;;;;;;WAYG;QACH,OAAO,EAAE,MAAM,CAAC;KACjB;CACF;AAED,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACpD,KAAK,UAAU,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;AACnD,UAAU,0BAA0B;IAClC,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,GAAG,UAAU,CAAC;CACxD;AACD,UAAU,0BAA0B;IAClC,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,CAAC;CACtC;AACD,UAAU,kBACR,SAAQ,0BAA0B,EAAE,0BAA0B;CAC/D;AAiBD,eAAO,IAAI,6BAA6B,EA2BnC,0BAA0B,CAAC;AAMhC,eAAO,IAAI,6BAA6B,EA4DnC,0BAA0B,CAAC;AAMhC,eAAO,IAAI,oBAAoB,EAoB1B,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"_dnt.polyfills.d.ts","sourceRoot":"","sources":["../src/_dnt.polyfills.ts"],"names":[],"mappings":"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"}
|
package/esm/_dnt.polyfills.js
CHANGED
|
@@ -222,6 +222,17 @@ export let import_meta_ponyfill = ((...args) => {
|
|
|
222
222
|
//@ts-ignore
|
|
223
223
|
return import_meta_ponyfill(...args);
|
|
224
224
|
});
|
|
225
|
+
// https://github.com/tc39/proposal-promise-with-resolvers/blob/3a78801e073e99217dbeb2c43ba7212f3bdc8b83/polyfills.js#L1C1-L9C2
|
|
226
|
+
if (Promise.withResolvers === undefined) {
|
|
227
|
+
Promise.withResolvers = () => {
|
|
228
|
+
const out = {};
|
|
229
|
+
out.promise = new Promise((resolve_, reject_) => {
|
|
230
|
+
out.resolve = resolve_;
|
|
231
|
+
out.reject = reject_;
|
|
232
|
+
});
|
|
233
|
+
return out;
|
|
234
|
+
};
|
|
235
|
+
}
|
|
225
236
|
// https://github.com/tc39/proposal-accessible-object-hasownproperty/blob/main/polyfill.js
|
|
226
237
|
if (!Object.hasOwn) {
|
|
227
238
|
Object.defineProperty(Object, "hasOwn", {
|
|
@@ -272,14 +283,3 @@ if (!Uint8Array.prototype.findLast) {
|
|
|
272
283
|
return findLast(this, callbackfn, that);
|
|
273
284
|
};
|
|
274
285
|
}
|
|
275
|
-
// https://github.com/tc39/proposal-promise-with-resolvers/blob/3a78801e073e99217dbeb2c43ba7212f3bdc8b83/polyfills.js#L1C1-L9C2
|
|
276
|
-
if (Promise.withResolvers === undefined) {
|
|
277
|
-
Promise.withResolvers = () => {
|
|
278
|
-
const out = {};
|
|
279
|
-
out.promise = new Promise((resolve_, reject_) => {
|
|
280
|
-
out.resolve = resolve_;
|
|
281
|
-
out.reject = reject_;
|
|
282
|
-
});
|
|
283
|
-
return out;
|
|
284
|
-
};
|
|
285
|
-
}
|
package/esm/deno.js
CHANGED
|
@@ -22,12 +22,18 @@
|
|
|
22
22
|
*
|
|
23
23
|
* @module
|
|
24
24
|
*/
|
|
25
|
+
interface ProjectScopedRegistryManagerOptions<T> {
|
|
26
|
+
/** Must be side-effect free; transaction preparation may invoke it again. */
|
|
27
|
+
validateRegistration?(id: string, existing: T, incoming: T): void;
|
|
28
|
+
}
|
|
25
29
|
/**
|
|
26
30
|
* Stage project-scoped registry mutations and publish them as one synchronous
|
|
27
31
|
* commit after the callback succeeds. Reads inside the callback see staged
|
|
28
32
|
* state; concurrent requests keep seeing the previous live state.
|
|
29
|
-
*
|
|
30
|
-
*
|
|
33
|
+
* Transactions for the same scope are serialized. Live writes made outside
|
|
34
|
+
* the transaction while discovery is in flight are journaled alongside staged
|
|
35
|
+
* mutations and replayed in call order, preserving the previous immediate-
|
|
36
|
+
* mutation semantics without exposing a partially discovered generation.
|
|
31
37
|
* Use this for complete discovery generations, not incremental updates.
|
|
32
38
|
*
|
|
33
39
|
* Nested calls participate in the existing transaction. If a nested tenant
|
|
@@ -42,16 +48,22 @@ export declare function runWithRegistryTransaction<T>(fn: () => Promise<T>): Pro
|
|
|
42
48
|
*/
|
|
43
49
|
export declare class ProjectScopedRegistryManager<T> {
|
|
44
50
|
private registryName;
|
|
51
|
+
private options;
|
|
45
52
|
private registriesByScope;
|
|
46
53
|
private sharedRegistry;
|
|
47
|
-
|
|
54
|
+
private activeStagesByScope;
|
|
55
|
+
constructor(registryName: string, options?: ProjectScopedRegistryManagerOptions<T>);
|
|
56
|
+
private validateRegistration;
|
|
57
|
+
private applyMutation;
|
|
48
58
|
/**
|
|
49
59
|
* Get the current project ID from AsyncLocalStorage context.
|
|
50
60
|
* Falls back to default for CLI/test scenarios.
|
|
51
61
|
*/
|
|
52
62
|
private getCurrentScopeId;
|
|
53
|
-
/** Return
|
|
54
|
-
private
|
|
63
|
+
/** Return the transaction-local stage for this manager and scope. */
|
|
64
|
+
private getTransactionStage;
|
|
65
|
+
/** Record a live mutation in any in-flight transaction for this scope. */
|
|
66
|
+
private recordLiveMutation;
|
|
55
67
|
/** Read the active registry, routing transaction access to its staged copy. */
|
|
56
68
|
private getActiveScopeRegistry;
|
|
57
69
|
/**
|
|
@@ -117,4 +129,5 @@ export declare class ProjectScopedRegistryManager<T> {
|
|
|
117
129
|
currentProjectItems: number;
|
|
118
130
|
};
|
|
119
131
|
}
|
|
132
|
+
export {};
|
|
120
133
|
//# sourceMappingURL=project-scoped-registry-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-scoped-registry-manager.d.ts","sourceRoot":"","sources":["../../../src/src/registry/project-scoped-registry-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;
|
|
1
|
+
{"version":3,"file":"project-scoped-registry-manager.d.ts","sourceRoot":"","sources":["../../../src/src/registry/project-scoped-registry-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA4BH,UAAU,mCAAmC,CAAC,CAAC;IAC7C,6EAA6E;IAC7E,oBAAoB,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC;CACnE;AAsCD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,0BAA0B,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAyCpF;AAED;;;;GAIG;AACH,qBAAa,4BAA4B,CAAC,CAAC;IAMvC,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,OAAO;IANjB,OAAO,CAAC,iBAAiB,CAAqC;IAC9D,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,mBAAmB,CAA8D;gBAG/E,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,mCAAmC,CAAC,CAAC,CAAM;IAG9D,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,aAAa;IAqBrB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB,qEAAqE;IACrE,OAAO,CAAC,mBAAmB;IA0E3B,0EAA0E;IAC1E,OAAO,CAAC,kBAAkB;IAM1B,+EAA+E;IAC/E,OAAO,CAAC,sBAAsB;IAI9B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IASxB;;OAEG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAoBnC;;;OAGG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAYzC;;;OAGG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAK9B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAKjC;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAMxB;;OAEG;IACH,SAAS,IAAI,MAAM,EAAE;IAOrB;;OAEG;IACH,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAUxB;;OAEG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAe3B;;OAEG;IACH,KAAK,IAAI,IAAI;IAWb;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAyBrC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAoBhB;;OAEG;IACH,QAAQ,IAAI;QACV,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,mBAAmB,EAAE,MAAM,CAAC;KAC7B;CAeF"}
|
|
@@ -27,6 +27,24 @@ import { agentLogger } from "../utils/logger/logger.js";
|
|
|
27
27
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
28
28
|
const DEFAULT_SCOPE_ID = "__default__";
|
|
29
29
|
const registryTransactionStorage = new AsyncLocalStorage();
|
|
30
|
+
const registryTransactionLocks = new Map();
|
|
31
|
+
async function acquireRegistryTransactionLock(scopeId) {
|
|
32
|
+
const previous = registryTransactionLocks.get(scopeId) ?? Promise.resolve();
|
|
33
|
+
const gate = Promise.withResolvers();
|
|
34
|
+
const current = previous.then(() => gate.promise);
|
|
35
|
+
registryTransactionLocks.set(scopeId, current);
|
|
36
|
+
await previous;
|
|
37
|
+
let released = false;
|
|
38
|
+
return () => {
|
|
39
|
+
if (released)
|
|
40
|
+
return;
|
|
41
|
+
released = true;
|
|
42
|
+
gate.resolve();
|
|
43
|
+
if (registryTransactionLocks.get(scopeId) === current) {
|
|
44
|
+
registryTransactionLocks.delete(scopeId);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
30
48
|
function buildRegistryScopeId() {
|
|
31
49
|
// tryGetRegistryScopeId() returns a project-isolated key even when
|
|
32
50
|
// tryGetCacheKeyContext() would return null (e.g. control-plane runs for an
|
|
@@ -39,8 +57,10 @@ function buildRegistryScopeId() {
|
|
|
39
57
|
* Stage project-scoped registry mutations and publish them as one synchronous
|
|
40
58
|
* commit after the callback succeeds. Reads inside the callback see staged
|
|
41
59
|
* state; concurrent requests keep seeing the previous live state.
|
|
42
|
-
*
|
|
43
|
-
*
|
|
60
|
+
* Transactions for the same scope are serialized. Live writes made outside
|
|
61
|
+
* the transaction while discovery is in flight are journaled alongside staged
|
|
62
|
+
* mutations and replayed in call order, preserving the previous immediate-
|
|
63
|
+
* mutation semantics without exposing a partially discovered generation.
|
|
44
64
|
* Use this for complete discovery generations, not incremental updates.
|
|
45
65
|
*
|
|
46
66
|
* Nested calls participate in the existing transaction. If a nested tenant
|
|
@@ -51,29 +71,40 @@ export async function runWithRegistryTransaction(fn) {
|
|
|
51
71
|
const existing = registryTransactionStorage.getStore();
|
|
52
72
|
if (existing?.state === "active")
|
|
53
73
|
return await fn();
|
|
74
|
+
const targetScopeId = buildRegistryScopeId();
|
|
75
|
+
const releaseLock = await acquireRegistryTransactionLock(targetScopeId);
|
|
54
76
|
const transaction = {
|
|
55
|
-
targetScopeId
|
|
77
|
+
targetScopeId,
|
|
56
78
|
stages: new Map(),
|
|
57
79
|
state: "active",
|
|
58
80
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
stage.
|
|
81
|
+
try {
|
|
82
|
+
return await registryTransactionStorage.run(transaction, async () => {
|
|
83
|
+
try {
|
|
84
|
+
const result = await fn();
|
|
85
|
+
// Prepare every manager before publishing any of them. Publication is
|
|
86
|
+
// synchronous, so no request can observe a partial generation.
|
|
87
|
+
const publications = Array.from(transaction.stages.values(), (stage) => stage.prepare());
|
|
88
|
+
for (const publication of publications) {
|
|
89
|
+
publication.publish();
|
|
90
|
+
}
|
|
91
|
+
transaction.state = "committed";
|
|
92
|
+
transaction.stages.clear();
|
|
93
|
+
return result;
|
|
66
94
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
transaction.state = "aborted";
|
|
97
|
+
for (const stage of transaction.stages.values()) {
|
|
98
|
+
stage.abort();
|
|
99
|
+
}
|
|
100
|
+
transaction.stages.clear();
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
releaseLock();
|
|
107
|
+
}
|
|
77
108
|
}
|
|
78
109
|
/**
|
|
79
110
|
* Base class for project-scoped registries.
|
|
@@ -82,10 +113,34 @@ export async function runWithRegistryTransaction(fn) {
|
|
|
82
113
|
*/
|
|
83
114
|
export class ProjectScopedRegistryManager {
|
|
84
115
|
registryName;
|
|
116
|
+
options;
|
|
85
117
|
registriesByScope = new Map();
|
|
86
118
|
sharedRegistry = new Map();
|
|
87
|
-
|
|
119
|
+
activeStagesByScope = new Map();
|
|
120
|
+
constructor(registryName, options = {}) {
|
|
88
121
|
this.registryName = registryName;
|
|
122
|
+
this.options = options;
|
|
123
|
+
}
|
|
124
|
+
validateRegistration(registry, id, incoming) {
|
|
125
|
+
if (!registry.has(id))
|
|
126
|
+
return;
|
|
127
|
+
this.options.validateRegistration?.(id, registry.get(id), incoming);
|
|
128
|
+
}
|
|
129
|
+
applyMutation(registry, mutation, validateRegistration = false) {
|
|
130
|
+
switch (mutation.type) {
|
|
131
|
+
case "clear":
|
|
132
|
+
registry.clear();
|
|
133
|
+
break;
|
|
134
|
+
case "delete":
|
|
135
|
+
registry.delete(mutation.id);
|
|
136
|
+
break;
|
|
137
|
+
case "set":
|
|
138
|
+
if (validateRegistration) {
|
|
139
|
+
this.validateRegistration(registry, mutation.id, mutation.item);
|
|
140
|
+
}
|
|
141
|
+
registry.set(mutation.id, mutation.item);
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
89
144
|
}
|
|
90
145
|
/**
|
|
91
146
|
* Get the current project ID from AsyncLocalStorage context.
|
|
@@ -94,8 +149,8 @@ export class ProjectScopedRegistryManager {
|
|
|
94
149
|
getCurrentScopeId() {
|
|
95
150
|
return buildRegistryScopeId();
|
|
96
151
|
}
|
|
97
|
-
/** Return
|
|
98
|
-
|
|
152
|
+
/** Return the transaction-local stage for this manager and scope. */
|
|
153
|
+
getTransactionStage(scopeId) {
|
|
99
154
|
const transaction = registryTransactionStorage.getStore();
|
|
100
155
|
if (!transaction)
|
|
101
156
|
return undefined;
|
|
@@ -111,33 +166,69 @@ export class ProjectScopedRegistryManager {
|
|
|
111
166
|
}
|
|
112
167
|
const existing = transaction.stages.get(this);
|
|
113
168
|
if (existing)
|
|
114
|
-
return existing
|
|
115
|
-
const
|
|
169
|
+
return existing;
|
|
170
|
+
const baseRegistry = new Map(this.registriesByScope.get(scopeId));
|
|
171
|
+
const registry = new Map(baseRegistry);
|
|
172
|
+
const validationRegistry = new Map(baseRegistry);
|
|
173
|
+
const mutations = [];
|
|
174
|
+
let closed = false;
|
|
175
|
+
const close = () => {
|
|
176
|
+
if (closed)
|
|
177
|
+
return;
|
|
178
|
+
closed = true;
|
|
179
|
+
const activeStages = this.activeStagesByScope.get(scopeId);
|
|
180
|
+
activeStages?.delete(stage);
|
|
181
|
+
if (activeStages?.size === 0)
|
|
182
|
+
this.activeStagesByScope.delete(scopeId);
|
|
183
|
+
};
|
|
116
184
|
const stage = {
|
|
117
185
|
registry,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
186
|
+
validateRegistration: (id, incoming) => {
|
|
187
|
+
this.validateRegistration(validationRegistry, id, incoming);
|
|
188
|
+
},
|
|
189
|
+
record: (mutation) => {
|
|
190
|
+
mutations.push(mutation);
|
|
191
|
+
this.applyMutation(validationRegistry, mutation);
|
|
192
|
+
},
|
|
193
|
+
prepare: () => {
|
|
194
|
+
const replacement = new Map(baseRegistry);
|
|
195
|
+
for (const mutation of mutations) {
|
|
196
|
+
this.applyMutation(replacement, mutation, true);
|
|
124
197
|
}
|
|
198
|
+
return {
|
|
199
|
+
publish: () => {
|
|
200
|
+
close();
|
|
201
|
+
if (replacement.size === 0) {
|
|
202
|
+
this.registriesByScope.delete(scopeId);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
this.registriesByScope.set(scopeId, replacement);
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
};
|
|
125
209
|
},
|
|
210
|
+
abort: close,
|
|
126
211
|
};
|
|
127
212
|
transaction.stages.set(this, stage);
|
|
128
|
-
|
|
213
|
+
const activeStages = this.activeStagesByScope.get(scopeId) ?? new Set();
|
|
214
|
+
activeStages.add(stage);
|
|
215
|
+
this.activeStagesByScope.set(scopeId, activeStages);
|
|
216
|
+
return stage;
|
|
217
|
+
}
|
|
218
|
+
/** Record a live mutation in any in-flight transaction for this scope. */
|
|
219
|
+
recordLiveMutation(scopeId, mutation) {
|
|
220
|
+
for (const stage of this.activeStagesByScope.get(scopeId) ?? []) {
|
|
221
|
+
stage.record(mutation);
|
|
222
|
+
}
|
|
129
223
|
}
|
|
130
224
|
/** Read the active registry, routing transaction access to its staged copy. */
|
|
131
225
|
getActiveScopeRegistry(scopeId) {
|
|
132
|
-
return this.
|
|
226
|
+
return this.getTransactionStage(scopeId)?.registry ?? this.registriesByScope.get(scopeId);
|
|
133
227
|
}
|
|
134
228
|
/**
|
|
135
229
|
* Get or create registry for a specific project.
|
|
136
230
|
*/
|
|
137
231
|
getScopeRegistry(scopeId) {
|
|
138
|
-
const staged = this.getTransactionRegistry(scopeId);
|
|
139
|
-
if (staged)
|
|
140
|
-
return staged;
|
|
141
232
|
const existing = this.registriesByScope.get(scopeId);
|
|
142
233
|
if (existing)
|
|
143
234
|
return existing;
|
|
@@ -150,11 +241,21 @@ export class ProjectScopedRegistryManager {
|
|
|
150
241
|
*/
|
|
151
242
|
register(id, item) {
|
|
152
243
|
const scopeId = this.getCurrentScopeId();
|
|
153
|
-
const
|
|
244
|
+
const stage = this.getTransactionStage(scopeId);
|
|
245
|
+
const registry = stage?.registry ?? this.getScopeRegistry(scopeId);
|
|
246
|
+
if (stage)
|
|
247
|
+
stage.validateRegistration(id, item);
|
|
248
|
+
else
|
|
249
|
+
this.validateRegistration(registry, id, item);
|
|
154
250
|
if (registry.has(id)) {
|
|
155
251
|
agentLogger.debug(`[${this.registryName}] "${id}" already registered for scope ${scopeId}. Overwriting.`);
|
|
156
252
|
}
|
|
157
253
|
registry.set(id, item);
|
|
254
|
+
const mutation = { type: "set", id, item };
|
|
255
|
+
if (stage)
|
|
256
|
+
stage.record(mutation);
|
|
257
|
+
else
|
|
258
|
+
this.recordLiveMutation(scopeId, mutation);
|
|
158
259
|
agentLogger.debug(`[${this.registryName}] Registered "${id}" for scope ${scopeId}`);
|
|
159
260
|
}
|
|
160
261
|
/**
|
|
@@ -224,23 +325,32 @@ export class ProjectScopedRegistryManager {
|
|
|
224
325
|
*/
|
|
225
326
|
delete(id) {
|
|
226
327
|
const scopeId = this.getCurrentScopeId();
|
|
227
|
-
const
|
|
228
|
-
|
|
328
|
+
const stage = this.getTransactionStage(scopeId);
|
|
329
|
+
const registry = stage?.registry ?? this.registriesByScope.get(scopeId);
|
|
330
|
+
const existed = registry?.has(id) ?? false;
|
|
331
|
+
if (!existed && !stage && !this.activeStagesByScope.has(scopeId))
|
|
229
332
|
return false;
|
|
230
|
-
registry
|
|
333
|
+
registry?.delete(id);
|
|
334
|
+
const mutation = { type: "delete", id };
|
|
335
|
+
if (stage)
|
|
336
|
+
stage.record(mutation);
|
|
337
|
+
else
|
|
338
|
+
this.recordLiveMutation(scopeId, mutation);
|
|
231
339
|
agentLogger.debug(`[${this.registryName}] Deleted "${id}" from scope ${scopeId}`);
|
|
232
|
-
return
|
|
340
|
+
return existed;
|
|
233
341
|
}
|
|
234
342
|
/**
|
|
235
343
|
* Clear all items for the current project.
|
|
236
344
|
*/
|
|
237
345
|
clear() {
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
346
|
+
const scopeId = this.getCurrentScopeId();
|
|
347
|
+
const stage = this.getTransactionStage(scopeId);
|
|
348
|
+
if (stage) {
|
|
349
|
+
stage.registry.clear();
|
|
350
|
+
stage.record({ type: "clear" });
|
|
241
351
|
return;
|
|
242
352
|
}
|
|
243
|
-
this.clearProject(
|
|
353
|
+
this.clearProject(scopeId);
|
|
244
354
|
}
|
|
245
355
|
/**
|
|
246
356
|
* Clear a specific project's registry.
|
|
@@ -251,10 +361,14 @@ export class ProjectScopedRegistryManager {
|
|
|
251
361
|
throw new Error(`[${this.registryName}] clearProject() is not supported during a registry transaction`);
|
|
252
362
|
}
|
|
253
363
|
let cleared = false;
|
|
254
|
-
|
|
364
|
+
const scopeIds = new Set([
|
|
365
|
+
...this.registriesByScope.keys(),
|
|
366
|
+
...this.activeStagesByScope.keys(),
|
|
367
|
+
]);
|
|
368
|
+
for (const scopeId of scopeIds) {
|
|
255
369
|
if (scopeId === projectId || scopeId.startsWith(`${projectId}:`)) {
|
|
256
|
-
this.registriesByScope.delete(scopeId);
|
|
257
|
-
|
|
370
|
+
cleared = this.registriesByScope.delete(scopeId) || cleared;
|
|
371
|
+
this.recordLiveMutation(scopeId, { type: "clear" });
|
|
258
372
|
}
|
|
259
373
|
}
|
|
260
374
|
if (cleared) {
|
|
@@ -269,6 +383,13 @@ export class ProjectScopedRegistryManager {
|
|
|
269
383
|
if (transaction && transaction.state !== "committed") {
|
|
270
384
|
throw new Error(`[${this.registryName}] clearAll() is not supported during a registry transaction`);
|
|
271
385
|
}
|
|
386
|
+
const scopeIds = new Set([
|
|
387
|
+
...this.registriesByScope.keys(),
|
|
388
|
+
...this.activeStagesByScope.keys(),
|
|
389
|
+
]);
|
|
390
|
+
for (const scopeId of scopeIds) {
|
|
391
|
+
this.recordLiveMutation(scopeId, { type: "clear" });
|
|
392
|
+
}
|
|
272
393
|
this.registriesByScope.clear();
|
|
273
394
|
this.sharedRegistry.clear();
|
|
274
395
|
agentLogger.debug(`[${this.registryName}] Cleared all registries`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/src/tool/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/src/tool/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AA2B7E,cAAM,iBAAkB,SAAQ,oBAAoB,CAAC,IAAI,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI;IAW/C,mBAAmB,IAAI,cAAc,EAAE;CAGxC;AAED,kCAAkC;AAClC,eAAO,MAAM,YAAY,mBAAqC,CAAC;AAE/D,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,IAAI,GAAG,cAAc,CAenE"}
|
package/esm/src/tool/registry.js
CHANGED
|
@@ -3,7 +3,6 @@ import { agentLogger } from "../utils/logger/logger.js";
|
|
|
3
3
|
import { ScopedRegistryFacade } from "../registry/scoped-registry-facade.js";
|
|
4
4
|
import { ProjectScopedRegistryManager } from "../registry/project-scoped-registry-manager.js";
|
|
5
5
|
import { TOOL_ID_CONFLICT } from "../errors/error-registry/agent.js";
|
|
6
|
-
const toolManager = new ProjectScopedRegistryManager("tool");
|
|
7
6
|
/**
|
|
8
7
|
* Returns true when `incoming` is considered the same definition as `existing`:
|
|
9
8
|
* same object reference, or matching id + description. Equivalent definitions
|
|
@@ -14,17 +13,23 @@ function isSameToolDefinition(existing, incoming) {
|
|
|
14
13
|
return existing === incoming ||
|
|
15
14
|
(existing.id === incoming.id && existing.description === incoming.description);
|
|
16
15
|
}
|
|
16
|
+
function validateToolRegistration(id, existing, incoming) {
|
|
17
|
+
if (isSameToolDefinition(existing, incoming))
|
|
18
|
+
return;
|
|
19
|
+
throw TOOL_ID_CONFLICT.create({
|
|
20
|
+
detail: `Tool "${id}" is already registered with a different definition. Use a unique tool ID or rename one of the conflicting tools.`,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const toolManager = new ProjectScopedRegistryManager("tool", {
|
|
24
|
+
validateRegistration: validateToolRegistration,
|
|
25
|
+
});
|
|
17
26
|
class ToolRegistryClass extends ScopedRegistryFacade {
|
|
18
27
|
register(id, item) {
|
|
19
|
-
//
|
|
20
|
-
//
|
|
28
|
+
// Equivalent-registration diagnostics inspect the project scope only;
|
|
29
|
+
// the manager enforces conflicts here and again against journaled order.
|
|
30
|
+
// Shared/framework tools remain intentionally shadowable.
|
|
21
31
|
const existing = this.getOwn(id);
|
|
22
|
-
if (existing !== undefined &&
|
|
23
|
-
throw TOOL_ID_CONFLICT.create({
|
|
24
|
-
detail: `Tool "${id}" is already registered with a different definition. Use a unique tool ID or rename one of the conflicting tools.`,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
if (existing !== undefined && existing !== item) {
|
|
32
|
+
if (existing !== undefined && existing !== item && isSameToolDefinition(existing, item)) {
|
|
28
33
|
agentLogger.debug(`[tool] "${id}" re-registered with equivalent definition; replacing.`);
|
|
29
34
|
}
|
|
30
35
|
super.register(id, item);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "veryfront",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1072",
|
|
4
4
|
"description": "The simplest way to build AI-powered apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -328,10 +328,10 @@
|
|
|
328
328
|
"@types/react": "19.2.14",
|
|
329
329
|
"@types/react-dom": "19.2.3",
|
|
330
330
|
"ws": "8.21.0",
|
|
331
|
-
"@veryfront/ext-bundler-esbuild": "0.1.
|
|
332
|
-
"@veryfront/ext-content-mdx": "0.1.
|
|
333
|
-
"@veryfront/ext-css-tailwind": "0.1.
|
|
334
|
-
"@veryfront/ext-parser-babel": "0.1.
|
|
331
|
+
"@veryfront/ext-bundler-esbuild": "0.1.1072",
|
|
332
|
+
"@veryfront/ext-content-mdx": "0.1.1072",
|
|
333
|
+
"@veryfront/ext-css-tailwind": "0.1.1072",
|
|
334
|
+
"@veryfront/ext-parser-babel": "0.1.1072"
|
|
335
335
|
},
|
|
336
336
|
"devDependencies": {
|
|
337
337
|
"@types/node": "20.9.0"
|