New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@agentuity/server

Package Overview
Dependencies
Maintainers
4
Versions
235
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@agentuity/server - npm Package Compare versions

Comparing version
2.0.11
to
3.0.0-alpha.0
+1
-1
dist/index.d.ts

@@ -0,4 +1,4 @@

export { createServerFetchAdapter, buildClientHeaders, type BuildClientHeadersOptions, type ServiceAdapterConfig, redact, } from '@agentuity/adapter';
export * from '@agentuity/core';
export { type ColorScheme, ConsoleLogger, createLogger } from './logger.ts';
export { createServerFetchAdapter, buildClientHeaders, type BuildClientHeadersOptions, } from './server.ts';
export { toJSONSchema } from './schema.ts';

@@ -5,0 +5,0 @@ export { getContentType, mimeTypes } from './util/mime.ts';

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAC;AAGhC,OAAO,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EACN,wBAAwB,EACxB,kBAAkB,EAClB,KAAK,yBAAyB,GAC9B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EACN,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAC3F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACN,wBAAwB,EACxB,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,MAAM,GACN,MAAM,oBAAoB,CAAC;AAK5B,cAAc,iBAAiB,CAAC;AAGhC,OAAO,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EACN,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAC3F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC"}

@@ -1,6 +0,9 @@

// Re-export ALL API modules from core (moved there for browser compatibility)
// Re-export adapter functions (backward compatibility - prefer @agentuity/adapter)
export { createServerFetchAdapter, buildClientHeaders, redact, } from '@agentuity/adapter';
// Re-export commonly used types from core
// Note: Full re-export maintained for backward compatibility with CLI and other packages
// TODO: Phase 2 - Migrate CLI imports to @agentuity/core directly, then remove this re-export
export * from '@agentuity/core';
// Server-specific exports (these remain in @agentuity/server only)
export { ConsoleLogger, createLogger } from "./logger.js";
export { createServerFetchAdapter, buildClientHeaders, } from "./server.js";
export { toJSONSchema } from "./schema.js";

@@ -7,0 +10,0 @@ export { getContentType, mimeTypes } from "./util/mime.js";

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,cAAc,iBAAiB,CAAC;AAEhC,mEAAmE;AACnE,OAAO,EAAoB,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EACN,wBAAwB,EACxB,kBAAkB,GAElB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EACN,eAAe,EACf,kBAAkB,EAClB,iBAAiB,GAIjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAgC,MAAM,wBAAwB,CAAC;AAC3F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,OAAO,EACN,wBAAwB,EACxB,kBAAkB,EAGlB,MAAM,GACN,MAAM,oBAAoB,CAAC;AAE5B,0CAA0C;AAC1C,yFAAyF;AACzF,8FAA8F;AAC9F,cAAc,iBAAiB,CAAC;AAEhC,mEAAmE;AACnE,OAAO,EAAoB,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EACN,eAAe,EACf,kBAAkB,EAClB,iBAAiB,GAIjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAgC,MAAM,wBAAwB,CAAC;AAC3F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC"}

@@ -29,3 +29,3 @@ /**

*
* Call this BEFORE createApp() in your app.ts:
* Call this early in your app entry point:
*

@@ -35,9 +35,5 @@ * @example

* import { bootstrapRuntimeEnv } from '@agentuity/server';
* import { createApp } from '@agentuity/runtime';
*
* // Set up service URLs
* // Set up service URLs before initializing your app
* bootstrapRuntimeEnv();
*
* // Now createApp() will use the correct env vars
* const app = await createApp();
* ```

@@ -44,0 +40,0 @@ */

@@ -1,1 +0,1 @@

{"version":3,"file":"runtime-bootstrap.d.ts","sourceRoot":"","sources":["../src/runtime-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,uBAAuB;IACvC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,uBAA4B,GAAG,IAAI,CA6C/E"}
{"version":3,"file":"runtime-bootstrap.d.ts","sourceRoot":"","sources":["../src/runtime-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,uBAAuB;IACvC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,uBAA4B,GAAG,IAAI,CA6C/E"}

@@ -19,3 +19,3 @@ /**

*
* Call this BEFORE createApp() in your app.ts:
* Call this early in your app entry point:
*

@@ -25,9 +25,5 @@ * @example

* import { bootstrapRuntimeEnv } from '@agentuity/server';
* import { createApp } from '@agentuity/runtime';
*
* // Set up service URLs
* // Set up service URLs before initializing your app
* bootstrapRuntimeEnv();
*
* // Now createApp() will use the correct env vars
* const app = await createApp();
* ```

@@ -34,0 +30,0 @@ */

@@ -1,1 +0,1 @@

{"version":3,"file":"runtime-bootstrap.js","sourceRoot":"","sources":["../src/runtime-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAe7C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAmC,EAAE;IACxE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC;IAE5E,6DAA6D;IAC7D,IACC,CAAC,OAAO,KAAK,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC;QAC/D,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAC5B,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,OAAO,CAAC;IACxC,CAAC;IAED,kDAAkD;IAClD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,OAAO,CAAC;IACzC,CAAC;IAED,mCAAmC;IACnC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC5C,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAE3C,2EAA2E;IAC3E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,qBAAqB,GAAG,WAAW,CAAC,OAAO,CAAC;IACzD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,WAAW,CAAC,IAAI,CAAC;IACnD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,WAAW,CAAC,KAAK,CAAC;IACrD,CAAC;AACF,CAAC"}
{"version":3,"file":"runtime-bootstrap.js","sourceRoot":"","sources":["../src/runtime-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAe7C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAmC,EAAE;IACxE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC;IAE5E,6DAA6D;IAC7D,IACC,CAAC,OAAO,KAAK,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC;QAC/D,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAC5B,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,OAAO,CAAC;IACxC,CAAC;IAED,kDAAkD;IAClD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,OAAO,CAAC;IACzC,CAAC;IAED,mCAAmC;IACnC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC5C,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAE3C,2EAA2E;IAC3E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,qBAAqB,GAAG,WAAW,CAAC,OAAO,CAAC;IACzD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,sBAAsB,GAAG,WAAW,CAAC,QAAQ,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,WAAW,CAAC,IAAI,CAAC;IACnD,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,WAAW,CAAC,KAAK,CAAC;IACrD,CAAC;AACF,CAAC"}
{
"name": "@agentuity/server",
"version": "2.0.11",
"version": "3.0.0-alpha.0",
"license": "Apache-2.0",

@@ -23,17 +23,18 @@ "author": "Agentuity employees and contributors",

"clean": "rm -rf dist tsconfig.tsbuildinfo",
"build": "bunx tsc --build --force",
"typecheck": "bunx tsc --noEmit",
"build": "tsgo --build --force",
"typecheck": "tsgo --noEmit",
"prepublishOnly": "bun run clean && bun run build"
},
"dependencies": {
"@agentuity/core": "2.0.11",
"@agentuity/schema": "2.0.11",
"@agentuity/adapter": "3.0.0-alpha.0",
"@agentuity/core": "3.0.0-alpha.0",
"@agentuity/schema": "3.0.0-alpha.0",
"zod": "^4.3.5"
},
"devDependencies": {
"@agentuity/test-utils": "2.0.11",
"@agentuity/test-utils": "3.0.0-alpha.0",
"@types/bun": "latest",
"@types/node": "^22.0.0",
"bun-types": "latest",
"typescript": "^5.9.0"
"typescript": "^6.0.2"
},

@@ -43,3 +44,8 @@ "publishConfig": {

},
"sideEffects": false
"sideEffects": false,
"repository": {
"type": "git",
"url": "https://github.com/agentuity/sdk.git",
"directory": "packages/server"
}
}

@@ -1,2 +0,13 @@

// Re-export ALL API modules from core (moved there for browser compatibility)
// Re-export adapter functions (backward compatibility - prefer @agentuity/adapter)
export {
createServerFetchAdapter,
buildClientHeaders,
type BuildClientHeadersOptions,
type ServiceAdapterConfig,
redact,
} from '@agentuity/adapter';
// Re-export commonly used types from core
// Note: Full re-export maintained for backward compatibility with CLI and other packages
// TODO: Phase 2 - Migrate CLI imports to @agentuity/core directly, then remove this re-export
export * from '@agentuity/core';

@@ -6,7 +17,2 @@

export { type ColorScheme, ConsoleLogger, createLogger } from './logger.ts';
export {
createServerFetchAdapter,
buildClientHeaders,
type BuildClientHeadersOptions,
} from './server.ts';
export { toJSONSchema } from './schema.ts';

@@ -13,0 +19,0 @@ export { getContentType, mimeTypes } from './util/mime.ts';

@@ -34,3 +34,3 @@ /**

*
* Call this BEFORE createApp() in your app.ts:
* Call this early in your app entry point:
*

@@ -40,9 +40,5 @@ * @example

* import { bootstrapRuntimeEnv } from '@agentuity/server';
* import { createApp } from '@agentuity/runtime';
*
* // Set up service URLs
* // Set up service URLs before initializing your app
* bootstrapRuntimeEnv();
*
* // Now createApp() will use the correct env vars
* const app = await createApp();
* ```

@@ -49,0 +45,0 @@ */

import type { FetchRequest, FetchResponse, FetchAdapter, Logger } from '@agentuity/core';
import { ServiceException } from '@agentuity/core';
interface ServiceAdapterConfig {
headers: Record<string, string>;
queryParams?: Record<string, string>;
onBefore?: (url: string, options: FetchRequest, invoke: () => Promise<void>) => Promise<void>;
onAfter?: <T>(url: string, options: FetchRequest, response: FetchResponse<T>, err?: InstanceType<typeof ServiceException>) => Promise<void>;
}
/**
* Options for building client request headers.
*/
export interface BuildClientHeadersOptions {
/** API key for authentication (Bearer token) */
apiKey?: string;
/** Organization ID for multi-tenant requests */
orgId?: string;
}
/**
* Builds standard headers for Agentuity service clients.
*
* This helper creates the header object needed by `createServerFetchAdapter`,
* handling authentication and multi-tenant scoping consistently across all clients.
*
* @param options - Options containing apiKey and/or orgId
* @returns Headers object ready to pass to createServerFetchAdapter
*
* @example
* ```typescript
* import { buildClientHeaders, createServerFetchAdapter } from '@agentuity/server';
*
* const headers = buildClientHeaders({ apiKey: 'sk_xxx', orgId: 'org_xxx' });
* const adapter = createServerFetchAdapter({ headers }, logger);
* ```
*/
export declare function buildClientHeaders(options: BuildClientHeadersOptions): Record<string, string>;
/**
* Redacts the middle of a string while keeping a prefix and suffix visible.
* Ensures that if the string is too short, everything is redacted.
*
* @param input The string to redact
* @param prefix Number of chars to keep at the start
* @param suffix Number of chars to keep at the end
* @param mask Character used for redaction
*/
export declare function redact(input: string, prefix?: number, suffix?: number, mask?: string): string;
declare class ServerFetchAdapter implements FetchAdapter {
#private;
constructor(config: ServiceAdapterConfig, logger: Logger);
private _invoke;
invoke<T>(url: string, options?: FetchRequest): Promise<FetchResponse<T>>;
}
/**
* Create a Server Side Fetch Adapter to allow the server to add headers and track outgoing requests
*
* @param config the service config
* @returns
*/
export declare function createServerFetchAdapter(config: ServiceAdapterConfig, logger: Logger): ServerFetchAdapter;
export {};
//# sourceMappingURL=server.d.ts.map
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,YAAY,EAEZ,aAAa,EACb,YAAY,EACZ,MAAM,EAEN,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAoC,MAAM,iBAAiB,CAAC;AAGrF,UAAU,oBAAoB;IAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9F,OAAO,CAAC,EAAE,CAAC,CAAC,EACX,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAC1B,GAAG,CAAC,EAAE,YAAY,CAAC,OAAO,gBAAgB,CAAC,KACvC,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAa7F;AAqKD;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CACrB,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,MAAU,EAClB,MAAM,GAAE,MAAU,EAClB,IAAI,GAAE,MAAY,GAChB,MAAM,CAaR;AAmBD,cAAM,kBAAmB,YAAW,YAAY;;gBAInC,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM;YAoB1C,OAAO;IA0Ef,MAAM,CAAC,CAAC,EACb,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,YAAiC,GACxC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;CAsC5B;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,sBAEpF"}
import { ServiceException, toServiceException, fromResponse } from '@agentuity/core';
import { appendFileSync } from 'node:fs';
/**
* Builds standard headers for Agentuity service clients.
*
* This helper creates the header object needed by `createServerFetchAdapter`,
* handling authentication and multi-tenant scoping consistently across all clients.
*
* @param options - Options containing apiKey and/or orgId
* @returns Headers object ready to pass to createServerFetchAdapter
*
* @example
* ```typescript
* import { buildClientHeaders, createServerFetchAdapter } from '@agentuity/server';
*
* const headers = buildClientHeaders({ apiKey: 'sk_xxx', orgId: 'org_xxx' });
* const adapter = createServerFetchAdapter({ headers }, logger);
* ```
*/
export function buildClientHeaders(options) {
const headers = options.apiKey
? {
Authorization: `Bearer ${options.apiKey}`,
'Content-Type': 'application/json',
}
: { 'Content-Type': 'application/json' };
if (options.orgId) {
headers['x-agentuity-orgid'] = options.orgId;
}
return headers;
}
/**
* Headers that contain sensitive information and should be redacted in debug logs.
* Includes authentication tokens, API keys, cookies, and proxy credentials.
*/
const sensitiveHeaders = new Set([
'authorization',
'x-api-key',
'cookie',
'set-cookie',
'proxy-authorization',
]);
/**
* Check if API debug logging is enabled and return the output destination.
* Returns:
* - 'console' if CI=1/true or AGENTUITY_API_DEBUG=1/true
* - file path string if AGENTUITY_API_DEBUG is set to a path
* - null if debug logging is disabled (including AGENTUITY_API_DEBUG=0/false)
*/
function getDebugOutput() {
const apiDebug = process.env.AGENTUITY_API_DEBUG?.trim();
if (apiDebug) {
const normalized = apiDebug.toLowerCase();
// Check if explicitly disabled
if (normalized === '0' || normalized === 'false') {
return null;
}
// Check if it's a truthy value (console output)
if (normalized === '1' || normalized === 'true') {
return 'console';
}
// Treat any other non-empty value as a file path
return apiDebug;
}
// Fall back to CI environment check
if (process.env.CI === '1' || process.env.CI === 'true') {
return 'console';
}
return null;
}
/**
* Format request body for CI debug logging
*/
function formatRequestBody(body) {
if (body === undefined || body === null) {
return '[no body]';
}
if (typeof body === 'string') {
return body;
}
if (body instanceof Uint8Array) {
return `[binary data: ${body.length} bytes]`;
}
if (body instanceof ArrayBuffer) {
return `[binary data: ${body.byteLength} bytes]`;
}
if (body instanceof ReadableStream) {
return '[stream]';
}
return String(body);
}
/**
* Format a sensitive header value, preserving Bearer prefix if present.
*/
function redactSensitiveHeader(key, value) {
const _k = key.toLowerCase();
// Handle Bearer tokens in authorization and proxy-authorization headers
if ((_k === 'authorization' || _k === 'proxy-authorization') && value.startsWith('Bearer ')) {
return `Bearer ${redact(value.substring(7))}`;
}
return redact(value);
}
/**
* Format headers as a readable string for debug logging.
* Sensitive headers (auth tokens, cookies, API keys) are redacted.
*/
function formatHeaders(headers) {
const entries = [];
if (headers instanceof Headers) {
headers.forEach((value, key) => {
const _k = key.toLowerCase();
if (sensitiveHeaders.has(_k)) {
entries.push(` ${key}: ${redactSensitiveHeader(key, value)}`);
}
else {
entries.push(` ${key}: ${value}`);
}
});
}
else {
for (const [key, value] of Object.entries(headers)) {
const _k = key.toLowerCase();
if (sensitiveHeaders.has(_k)) {
entries.push(` ${key}: ${redactSensitiveHeader(key, value)}`);
}
else {
entries.push(` ${key}: ${value}`);
}
}
}
return entries.join('\n');
}
/**
* Log detailed debug information when API requests fail.
* Output destination is determined by AGENTUITY_API_DEBUG or CI environment variables.
*/
function logAPIDebug(url, method, requestHeaders, requestBody, response, responseBody) {
const output = getDebugOutput();
if (!output) {
return;
}
const separator = '='.repeat(60);
const timestamp = new Date().toISOString();
const lines = [
'',
separator,
`API DEBUG: Request Failed [${timestamp}]`,
separator,
'',
'>>> REQUEST',
`URL: ${url}`,
`Method: ${method}`,
'Headers:',
formatHeaders(requestHeaders),
'Body:',
` ${formatRequestBody(requestBody)}`,
'',
'<<< RESPONSE',
`Status: ${response.status} ${response.statusText}`,
'Headers:',
formatHeaders(response.headers),
'Body:',
` ${responseBody || '[empty]'}`,
'',
separator,
'',
];
const content = lines.join('\n');
if (output === 'console') {
console.error(content);
}
else {
// Append to file
try {
appendFileSync(output, content + '\n');
}
catch {
// If file write fails, fall back to console.error
console.error(`[API DEBUG] Failed to write to ${output}, falling back to console`);
console.error(content);
}
}
}
/**
* Redacts the middle of a string while keeping a prefix and suffix visible.
* Ensures that if the string is too short, everything is redacted.
*
* @param input The string to redact
* @param prefix Number of chars to keep at the start
* @param suffix Number of chars to keep at the end
* @param mask Character used for redaction
*/
export function redact(input, prefix = 4, suffix = 4, mask = '*') {
if (!input)
return '';
// If revealing prefix+suffix would leak too much, fully mask
if (input.length <= prefix + suffix) {
return mask.repeat(input.length);
}
const start = input.slice(0, prefix);
const end = input.slice(-suffix);
const hiddenLength = input.length - prefix - suffix;
return start + mask.repeat(hiddenLength) + end;
}
const redactHeaders = (kv) => {
const values = [];
for (const k of Object.keys(kv)) {
const _k = k.toLowerCase();
const v = kv[k];
if (v === undefined) {
continue;
}
if (sensitiveHeaders.has(_k)) {
values.push(`${_k}=${redactSensitiveHeader(k, v)}`);
}
else {
values.push(`${_k}=${v}`);
}
}
return '[' + values.join(',') + ']';
};
class ServerFetchAdapter {
#config;
#logger;
constructor(config, logger) {
this.#config = config;
this.#logger = logger;
}
/**
* Build the final URL with query params appended.
* This is extracted so both invoke() and _invoke() use the same URL.
*/
#buildUrl(url) {
if (this.#config.queryParams && Object.keys(this.#config.queryParams).length > 0) {
const urlObj = new URL(url);
for (const [key, value] of Object.entries(this.#config.queryParams)) {
urlObj.searchParams.set(key, value);
}
return urlObj.toString();
}
return url;
}
async _invoke(url, options) {
// URL already has query params appended by invoke() or direct caller
const headers = {
...options.headers,
...this.#config.headers,
};
if (options.contentType) {
headers['Content-Type'] = options.contentType;
}
else if (typeof options.body === 'string' ||
options.body instanceof Uint8Array ||
options.body instanceof ArrayBuffer) {
headers['Content-Type'] = 'application/octet-stream';
}
// Ensure we request JSON responses for proper error handling
if (!headers['Accept'] && !headers['accept']) {
headers['Accept'] = 'application/json';
}
const method = options.method ?? 'POST';
this.#logger.trace('sending %s to %s with headers: %s', method, url, redactHeaders(headers));
const res = await fetch(url, {
method,
body: options.body,
headers,
signal: options.signal,
...(options.duplex ? { duplex: options.duplex } : {}),
});
if (res.ok) {
switch (res.status) {
case 100:
case 101:
case 102:
case 204:
case 304:
return {
ok: true,
data: undefined,
response: res,
};
default:
break;
}
if (options?.binary) {
return {
ok: true,
data: undefined,
response: res,
};
}
const data = await fromResponse(res);
return {
ok: true,
data,
response: res,
};
}
if (res.status === 404) {
// Log debug info for 404 errors if debugging is enabled
if (getDebugOutput()) {
const responseBody = await res.clone().text();
logAPIDebug(url, method, headers, options.body, res, responseBody);
}
return {
ok: false,
response: res,
};
}
// Clone response to read body for debug logging before toServiceException consumes it
const responseBody = getDebugOutput() ? await res.clone().text() : '';
logAPIDebug(url, method, headers, options.body, res, responseBody);
const err = await toServiceException(method, url, res);
throw err;
}
async invoke(url, options = { method: 'POST' }) {
// Build final URL with query params BEFORE hooks, so hooks receive the actual URL
const finalUrl = this.#buildUrl(url);
if (this.#config.onBefore) {
let result = undefined;
let err = undefined;
await this.#config.onBefore(finalUrl, options, async () => {
try {
result = await this._invoke(finalUrl, options);
if (this.#config.onAfter) {
await this.#config.onAfter(finalUrl, options, result);
}
}
catch (ex) {
err = ex;
if (this.#config.onAfter && err instanceof ServiceException) {
await this.#config.onAfter(finalUrl, options, {
ok: false,
response: new Response(err.message, {
status: err.statusCode,
}),
}, err);
}
}
});
if (err) {
throw err;
}
return result;
}
else {
return await this._invoke(finalUrl, options);
}
}
}
/**
* Create a Server Side Fetch Adapter to allow the server to add headers and track outgoing requests
*
* @param config the service config
* @returns
*/
export function createServerFetchAdapter(config, logger) {
return new ServerFetchAdapter(config, logger);
}
//# sourceMappingURL=server.js.map
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
import type {
FetchRequest,
FetchErrorResponse,
FetchResponse,
FetchAdapter,
Logger,
HttpMethod,
} from '@agentuity/core';
import { ServiceException, toServiceException, fromResponse } from '@agentuity/core';
import { appendFileSync } from 'node:fs';
interface ServiceAdapterConfig {
headers: Record<string, string>;
queryParams?: Record<string, string>;
onBefore?: (url: string, options: FetchRequest, invoke: () => Promise<void>) => Promise<void>;
onAfter?: <T>(
url: string,
options: FetchRequest,
response: FetchResponse<T>,
err?: InstanceType<typeof ServiceException>
) => Promise<void>;
}
/**
* Options for building client request headers.
*/
export interface BuildClientHeadersOptions {
/** API key for authentication (Bearer token) */
apiKey?: string;
/** Organization ID for multi-tenant requests */
orgId?: string;
}
/**
* Builds standard headers for Agentuity service clients.
*
* This helper creates the header object needed by `createServerFetchAdapter`,
* handling authentication and multi-tenant scoping consistently across all clients.
*
* @param options - Options containing apiKey and/or orgId
* @returns Headers object ready to pass to createServerFetchAdapter
*
* @example
* ```typescript
* import { buildClientHeaders, createServerFetchAdapter } from '@agentuity/server';
*
* const headers = buildClientHeaders({ apiKey: 'sk_xxx', orgId: 'org_xxx' });
* const adapter = createServerFetchAdapter({ headers }, logger);
* ```
*/
export function buildClientHeaders(options: BuildClientHeadersOptions): Record<string, string> {
const headers: Record<string, string> = options.apiKey
? {
Authorization: `Bearer ${options.apiKey}`,
'Content-Type': 'application/json',
}
: { 'Content-Type': 'application/json' };
if (options.orgId) {
headers['x-agentuity-orgid'] = options.orgId;
}
return headers;
}
/**
* Headers that contain sensitive information and should be redacted in debug logs.
* Includes authentication tokens, API keys, cookies, and proxy credentials.
*/
const sensitiveHeaders = new Set([
'authorization',
'x-api-key',
'cookie',
'set-cookie',
'proxy-authorization',
]);
/**
* Check if API debug logging is enabled and return the output destination.
* Returns:
* - 'console' if CI=1/true or AGENTUITY_API_DEBUG=1/true
* - file path string if AGENTUITY_API_DEBUG is set to a path
* - null if debug logging is disabled (including AGENTUITY_API_DEBUG=0/false)
*/
function getDebugOutput(): 'console' | string | null {
const apiDebug = process.env.AGENTUITY_API_DEBUG?.trim();
if (apiDebug) {
const normalized = apiDebug.toLowerCase();
// Check if explicitly disabled
if (normalized === '0' || normalized === 'false') {
return null;
}
// Check if it's a truthy value (console output)
if (normalized === '1' || normalized === 'true') {
return 'console';
}
// Treat any other non-empty value as a file path
return apiDebug;
}
// Fall back to CI environment check
if (process.env.CI === '1' || process.env.CI === 'true') {
return 'console';
}
return null;
}
/**
* Format request body for CI debug logging
*/
function formatRequestBody(body: unknown): string {
if (body === undefined || body === null) {
return '[no body]';
}
if (typeof body === 'string') {
return body;
}
if (body instanceof Uint8Array) {
return `[binary data: ${body.length} bytes]`;
}
if (body instanceof ArrayBuffer) {
return `[binary data: ${body.byteLength} bytes]`;
}
if (body instanceof ReadableStream) {
return '[stream]';
}
return String(body);
}
/**
* Format a sensitive header value, preserving Bearer prefix if present.
*/
function redactSensitiveHeader(key: string, value: string): string {
const _k = key.toLowerCase();
// Handle Bearer tokens in authorization and proxy-authorization headers
if ((_k === 'authorization' || _k === 'proxy-authorization') && value.startsWith('Bearer ')) {
return `Bearer ${redact(value.substring(7))}`;
}
return redact(value);
}
/**
* Format headers as a readable string for debug logging.
* Sensitive headers (auth tokens, cookies, API keys) are redacted.
*/
function formatHeaders(headers: Headers | Record<string, string>): string {
const entries: string[] = [];
if (headers instanceof Headers) {
headers.forEach((value, key) => {
const _k = key.toLowerCase();
if (sensitiveHeaders.has(_k)) {
entries.push(` ${key}: ${redactSensitiveHeader(key, value)}`);
} else {
entries.push(` ${key}: ${value}`);
}
});
} else {
for (const [key, value] of Object.entries(headers)) {
const _k = key.toLowerCase();
if (sensitiveHeaders.has(_k)) {
entries.push(` ${key}: ${redactSensitiveHeader(key, value)}`);
} else {
entries.push(` ${key}: ${value}`);
}
}
}
return entries.join('\n');
}
/**
* Log detailed debug information when API requests fail.
* Output destination is determined by AGENTUITY_API_DEBUG or CI environment variables.
*/
function logAPIDebug(
url: string,
method: string,
requestHeaders: Record<string, string>,
requestBody: unknown,
response: Response,
responseBody: string
): void {
const output = getDebugOutput();
if (!output) {
return;
}
const separator = '='.repeat(60);
const timestamp = new Date().toISOString();
const lines = [
'',
separator,
`API DEBUG: Request Failed [${timestamp}]`,
separator,
'',
'>>> REQUEST',
`URL: ${url}`,
`Method: ${method}`,
'Headers:',
formatHeaders(requestHeaders),
'Body:',
` ${formatRequestBody(requestBody)}`,
'',
'<<< RESPONSE',
`Status: ${response.status} ${response.statusText}`,
'Headers:',
formatHeaders(response.headers),
'Body:',
` ${responseBody || '[empty]'}`,
'',
separator,
'',
];
const content = lines.join('\n');
if (output === 'console') {
console.error(content);
} else {
// Append to file
try {
appendFileSync(output, content + '\n');
} catch {
// If file write fails, fall back to console.error
console.error(`[API DEBUG] Failed to write to ${output}, falling back to console`);
console.error(content);
}
}
}
/**
* Redacts the middle of a string while keeping a prefix and suffix visible.
* Ensures that if the string is too short, everything is redacted.
*
* @param input The string to redact
* @param prefix Number of chars to keep at the start
* @param suffix Number of chars to keep at the end
* @param mask Character used for redaction
*/
export function redact(
input: string,
prefix: number = 4,
suffix: number = 4,
mask: string = '*'
): string {
if (!input) return '';
// If revealing prefix+suffix would leak too much, fully mask
if (input.length <= prefix + suffix) {
return mask.repeat(input.length);
}
const start = input.slice(0, prefix);
const end = input.slice(-suffix);
const hiddenLength = input.length - prefix - suffix;
return start + mask.repeat(hiddenLength) + end;
}
const redactHeaders = (kv: Record<string, string>): string => {
const values: string[] = [];
for (const k of Object.keys(kv)) {
const _k = k.toLowerCase();
const v = kv[k];
if (v === undefined) {
continue;
}
if (sensitiveHeaders.has(_k)) {
values.push(`${_k}=${redactSensitiveHeader(k, v)}`);
} else {
values.push(`${_k}=${v}`);
}
}
return '[' + values.join(',') + ']';
};
class ServerFetchAdapter implements FetchAdapter {
#config: ServiceAdapterConfig;
#logger: Logger;
constructor(config: ServiceAdapterConfig, logger: Logger) {
this.#config = config;
this.#logger = logger;
}
/**
* Build the final URL with query params appended.
* This is extracted so both invoke() and _invoke() use the same URL.
*/
#buildUrl(url: string): string {
if (this.#config.queryParams && Object.keys(this.#config.queryParams).length > 0) {
const urlObj = new URL(url);
for (const [key, value] of Object.entries(this.#config.queryParams)) {
urlObj.searchParams.set(key, value);
}
return urlObj.toString();
}
return url;
}
private async _invoke<T>(url: string, options: FetchRequest): Promise<FetchResponse<T>> {
// URL already has query params appended by invoke() or direct caller
const headers: Record<string, string> = {
...options.headers,
...this.#config.headers,
};
if (options.contentType) {
headers['Content-Type'] = options.contentType;
} else if (
typeof options.body === 'string' ||
options.body instanceof Uint8Array ||
options.body instanceof ArrayBuffer
) {
headers['Content-Type'] = 'application/octet-stream';
}
// Ensure we request JSON responses for proper error handling
if (!headers['Accept'] && !headers['accept']) {
headers['Accept'] = 'application/json';
}
const method: HttpMethod = options.method ?? 'POST';
this.#logger.trace('sending %s to %s with headers: %s', method, url, redactHeaders(headers));
const res = await fetch(url, {
method,
body: options.body,
headers,
signal: options.signal,
...(options.duplex ? { duplex: options.duplex } : {}),
});
if (res.ok) {
switch (res.status) {
case 100:
case 101:
case 102:
case 204:
case 304:
return {
ok: true,
data: undefined as T,
response: res,
};
default:
break;
}
if (options?.binary) {
return {
ok: true,
data: undefined as T,
response: res,
};
}
const data = await fromResponse<T>(res);
return {
ok: true,
data,
response: res,
};
}
if (res.status === 404) {
// Log debug info for 404 errors if debugging is enabled
if (getDebugOutput()) {
const responseBody = await res.clone().text();
logAPIDebug(url, method, headers, options.body, res, responseBody);
}
return {
ok: false,
response: res,
} as FetchErrorResponse;
}
// Clone response to read body for debug logging before toServiceException consumes it
const responseBody = getDebugOutput() ? await res.clone().text() : '';
logAPIDebug(url, method, headers, options.body, res, responseBody);
const err = await toServiceException(method, url, res);
throw err;
}
async invoke<T>(
url: string,
options: FetchRequest = { method: 'POST' }
): Promise<FetchResponse<T>> {
// Build final URL with query params BEFORE hooks, so hooks receive the actual URL
const finalUrl = this.#buildUrl(url);
if (this.#config.onBefore) {
let result: FetchResponse<T> | undefined = undefined;
let err: Error | undefined = undefined;
await this.#config.onBefore(finalUrl, options, async () => {
try {
result = await this._invoke(finalUrl, options);
if (this.#config.onAfter) {
await this.#config.onAfter(finalUrl, options, result);
}
} catch (ex) {
err = ex as Error;
if (this.#config.onAfter && err instanceof ServiceException) {
await this.#config.onAfter(
finalUrl,
options,
{
ok: false,
response: new Response(err.message, {
status: err.statusCode,
}),
} as FetchErrorResponse,
err
);
}
}
});
if (err) {
throw err;
}
return result as unknown as FetchResponse<T>;
} else {
return await this._invoke(finalUrl, options);
}
}
}
/**
* Create a Server Side Fetch Adapter to allow the server to add headers and track outgoing requests
*
* @param config the service config
* @returns
*/
export function createServerFetchAdapter(config: ServiceAdapterConfig, logger: Logger) {
return new ServerFetchAdapter(config, logger);
}