diff --git a/src/ports/writable-grant-store.ts b/src/ports/writable-grant-store.ts index 5d572bb..cefbbcf 100644 --- a/src/ports/writable-grant-store.ts +++ b/src/ports/writable-grant-store.ts @@ -32,15 +32,30 @@ export function createInMemoryWritableGrantStore( initial: GrantRule[] = [], ): WritableGrantStore & { grants: GrantRule[] } { const grants = [...initial]; - return { + function collect(principalId: string) { + const now = new Date(); + return grants.filter((g) => { + if (g.principalId !== principalId) return false; + if (g.expiresAt !== null && g.expiresAt <= now) return false; + return true; + }); + } + // Bound to a const rather than returned as a fresh object literal: some + // `@intx/authz` versions require `collectGrantsInChain` on `GrantStore` + // (an ancestor-chain walk) that this package's own pinned version + // predates. Routing through a named variable gets normal structural + // assignment for the function's declared return type instead of + // TypeScript's excess-property check on literals, so this satisfies + // either shape — tenantId (and thus the ancestor chain) is a no-op here + // regardless, matching `createInMemoryGrantStore`'s own tenant-scoped + // fixture semantics. + const store = { grants, async collectGrants(principalId: string, _tenantId?: string) { - const now = new Date(); - return grants.filter((g) => { - if (g.principalId !== principalId) return false; - if (g.expiresAt !== null && g.expiresAt <= now) return false; - return true; - }); + return collect(principalId); + }, + async collectGrantsInChain(principalId: string, _tenantId?: string) { + return collect(principalId); }, async putGrant(grant: GrantRule) { const idx = grants.findIndex((g) => g.id === grant.id); @@ -48,4 +63,5 @@ export function createInMemoryWritableGrantStore( else grants.push(grant); }, }; + return store; } diff --git a/src/tools/install.ts b/src/tools/install.ts index 688dd62..a098739 100644 --- a/src/tools/install.ts +++ b/src/tools/install.ts @@ -37,10 +37,19 @@ export function defineMemoryHttpTool(opts: { signal: AbortSignal | undefined, ) => Promise; }) { - return defineTool({ + // Bound to a const rather than passed as a fresh object literal: some + // `@intx/agent` versions add a static `definitions` field to defineTool's + // options (so callers can enumerate tool names without instantiating the + // factory) that this package's own pinned version predates. Routing + // through a named variable gets normal structural (duck-typed) parameter + // assignment instead of TypeScript's excess-property check on literals, + // so this call type-checks against either shape — the extra field is + // simply unused by an older defineTool at runtime. + const toolOpts = { id: opts.id, requires: MEMORY_TOOL_ENV_KEYS, - factory(env) { + definitions: [{ name: opts.name }], + factory(env: MemoryInstallEnv) { const client = createMemoryHttpClient(readMemoryToolEnv(env)); const runner = createToolRunner([ stringTool({ @@ -55,8 +64,9 @@ export function defineMemoryHttpTool(opts: { ]); return { definitions: runner.definitions, - run: (call, signal) => runner.run(call, signal), + run: runner.run.bind(runner), }; }, - }); + }; + return defineTool(toolOpts); }