openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
161 lines (160 loc) • 7.21 kB
JavaScript
import { t as createDeferredCore } from "./deferred-D0La5CRk.mjs";
import { a as resolveGlobalSingleton } from "./global-singleton-0m-JziJW.mjs";
import { r as getAsyncWorkSignal, t as AsyncWorkScope } from "./async-work-scope-BYeX3gh6.mjs";
import { i as hasRetainedPluginRuntimeCloseError } from "./runtime-close-error-DPmgR5gM.mjs";
import { r as getCanonicalGatewayContextResolver } from "./gateway-context-binding-VqB7gkMe.mjs";
import { a as getPluginRuntimeGatewayRequestScope } from "./gateway-request-scope-BSmCVVpP.mjs";
import { AsyncLocalStorage } from "node:async_hooks";
import { types } from "node:util";
//#region src/plugins/plugin-return-value.ts
const promiseThen = Object.getOwnPropertyDescriptor(Promise.prototype, "then");
const promiseSpecies = Object.getOwnPropertyDescriptor(Promise, Symbol.species);
/** Preserve foreign then/species results while identifying native host continuations. */
function mapPluginReturnPromise(completion, fulfilled, rejected) {
const then = completion.then;
const constructor = types.isPromise(completion) && Object.getPrototypeOf(completion) === Promise.prototype ? Object.getOwnPropertyDescriptor(completion, "constructor") ?? Object.getOwnPropertyDescriptor(Promise.prototype, "constructor") : void 0;
const host = then === promiseThen?.value && constructor?.value === Promise && Object.getOwnPropertyDescriptor(Promise, Symbol.species)?.get === promiseSpecies?.get;
return {
value: Reflect.apply(then, completion, rejected ? [fulfilled, rejected] : [fulfilled]),
host
};
}
/** Capture a returned then method once without turning synchronous values into async work. */
function resolvePluginReturnPromise(value) {
if (types.isPromise(value)) return Promise.resolve(value);
if (value === null || typeof value !== "object" && typeof value !== "function") return;
let then;
try {
then = Reflect.get(value, "then");
} catch (error) {
return Promise.reject(error);
}
if (typeof then !== "function") return;
return Promise.resolve({ then(resolve, reject) {
Reflect.apply(then, value, [resolve, reject]);
} });
}
//#endregion
//#region src/plugins/legacy-sdk-resource-host.ts
/** Owns resources borrowed by shipped SDK results that have no release method. */
var LegacyPluginSdkResourceHost = class {
constructor() {
this.work = new AsyncWorkScope();
this.claims = /* @__PURE__ */ new Map();
this.providerProjections = /* @__PURE__ */ new WeakMap();
this.pending = /* @__PURE__ */ new Set();
this.failures = [];
}
get scheduler() {
this.assertOpen();
if (!this.gatewayScheduler) throw new Error("Plugin SDK resource host has no Gateway scheduler");
this.gatewayScheduler.signal.throwIfAborted();
return this.gatewayScheduler;
}
bindScheduler(scheduler) {
this.assertOpen();
scheduler.signal.throwIfAborted();
if (this.gatewayScheduler && this.gatewayScheduler !== scheduler) throw new Error("Plugin SDK resource host already belongs to another Gateway scheduler");
this.gatewayScheduler = scheduler;
}
assertOpen() {
if (this.closing || this.work.isClosing) throw new Error("Plugin SDK resource host is closed");
}
run(run) {
return hostContext.run(this, run);
}
track(run) {
this.assertOpen();
return this.work.track(() => this.run(run));
}
/** Preserve synchronous SDK hooks while joining their asynchronous results and descendants. */
invoke(run) {
if (getAsyncWorkSignal() !== this.work.signal) this.assertOpen();
return this.work.run(() => this.run(() => {
const result = run();
const completion = resolvePluginReturnPromise(result);
return completion ? this.work.track(() => completion) : result;
}));
}
adopt(source, claim) {
this.assertOpen();
if (this.claims.has(source)) this.releaseClaim(claim);
else this.claims.set(source, claim);
}
/** View lookup shares identity; only adopted or temporary claims own disposal. */
getProviderProjection(source, create) {
this.assertOpen();
let projection = this.providerProjections.get(source);
if (!projection) {
projection = create();
this.providerProjections.set(source, projection);
}
return projection;
}
forgetProviderProjection(source, projection) {
if (this.providerProjections.get(source) === projection) this.providerProjections.delete(source);
}
/** Projection failures still own their asynchronous release until it settles. */
releaseClaim(claim) {
const operation = createDeferredCore();
const completion = operation.promise.then(() => {
this.pending.delete(completion);
}, (error) => {
this.failures.push(error);
this.pending.delete(completion);
});
this.pending.add(completion);
try {
operation.resolve(this.work.hasPendingWork ? AsyncWorkScope.runWhenAllIdle(() => [this.work], () => claim.release()) : claim.release());
} catch (error) {
operation.reject(error);
}
}
/** Fence new SDK work and join its tails before prepared resources can retire. */
async drainWork() {
await this.work.drain();
await this.drainPendingReleases();
if (this.failures.some(hasRetainedPluginRuntimeCloseError)) throw new AggregateError(this.failures, "Plugin SDK resources could not all be disposed");
}
async drainPendingReleases() {
while (this.pending.size > 0) await Promise.all(this.pending);
}
close() {
if (!this.closing) this.closing = Promise.resolve().then(async () => {
await this.drainWork();
const claims = [...this.claims.values()];
this.claims.clear();
for (const claim of claims) this.releaseClaim(claim);
await this.drainPendingReleases();
if (this.failures.length > 0) throw new AggregateError(this.failures, "Plugin SDK resources could not all be disposed");
});
return this.closing;
}
};
const { hostContext, gatewayHosts } = resolveGlobalSingleton(Symbol.for("openclaw.legacyPluginSdkResourceHosts"), () => ({
hostContext: new AsyncLocalStorage(),
gatewayHosts: /* @__PURE__ */ new WeakMap()
}));
const STANDALONE_HOST_KEY = Symbol.for("openclaw.legacyPluginSdkStandaloneResourceHost");
/** Associate exact host resolvers without calling them after their authority closes. */
function bindLegacyPluginSdkResourceHost(resolver, host) {
gatewayHosts.set(resolver, host);
}
function getBoundLegacyPluginSdkResourceHost() {
const scope = getPluginRuntimeGatewayRequestScope();
const resolver = scope?.resolveGatewayContext ?? scope?.context?.resolveGatewayContext;
if (resolver) {
const owner = getCanonicalGatewayContextResolver(resolver);
const host = owner ? gatewayHosts.get(owner) : void 0;
if (!host) throw new Error("Gateway SDK resource host is not bound");
return host;
}
const host = hostContext.getStore();
return host === globalThis[STANDALONE_HOST_KEY] ? void 0 : host;
}
/** Standalone callers of the shipped bare-result SDK retain their process lifetime. */
function getLegacyPluginSdkResourceHost() {
return getBoundLegacyPluginSdkResourceHost() ?? resolveGlobalSingleton(STANDALONE_HOST_KEY, () => new LegacyPluginSdkResourceHost());
}
//#endregion
export { mapPluginReturnPromise as a, getLegacyPluginSdkResourceHost as i, bindLegacyPluginSdkResourceHost as n, resolvePluginReturnPromise as o, getBoundLegacyPluginSdkResourceHost as r, LegacyPluginSdkResourceHost as t };