@naisys/common 3.0.0-beta.4 → 3.0.0-beta.6

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/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "name": "@naisys/common",
3
- "version": "3.0.0-beta.4",
3
+ "version": "3.0.0-beta.6",
4
4
  "type": "module",
5
5
  "description": "[internal] Common utilities and constants for NAISYS",
6
6
  "files": [
7
7
  "dist",
8
8
  "assets",
9
- "!dist/**/*.map"
9
+ "!dist/**/*.map",
10
+ "!dist/**/*.d.ts",
11
+ "!dist/**/*.d.ts.map"
10
12
  ],
11
13
  "scripts": {
12
14
  "clean": "rimraf dist",
@@ -1,62 +0,0 @@
1
- import { z } from "zod";
2
- export declare const commandProtectionValues: readonly ["none", "manual", "semi-auto", "auto"];
3
- export declare const AgentConfigFileSchema: z.ZodObject<{
4
- username: z.ZodString;
5
- title: z.ZodString;
6
- agentPrompt: z.ZodString;
7
- spendLimitDollars: z.ZodOptional<z.ZodNumber>;
8
- spendLimitHours: z.ZodOptional<z.ZodNumber>;
9
- tokenMax: z.ZodNumber;
10
- shellModel: z.ZodString;
11
- imageModel: z.ZodOptional<z.ZodString>;
12
- mailEnabled: z.ZodOptional<z.ZodBoolean>;
13
- chatEnabled: z.ZodOptional<z.ZodBoolean>;
14
- webEnabled: z.ZodOptional<z.ZodBoolean>;
15
- completeSessionEnabled: z.ZodOptional<z.ZodBoolean>;
16
- debugPauseSeconds: z.ZodOptional<z.ZodNumber>;
17
- wakeOnMessage: z.ZodOptional<z.ZodBoolean>;
18
- commandProtection: z.ZodOptional<z.ZodEnum<{
19
- none: "none";
20
- manual: "manual";
21
- "semi-auto": "semi-auto";
22
- auto: "auto";
23
- }>>;
24
- initialCommands: z.ZodOptional<z.ZodArray<z.ZodString>>;
25
- multipleCommandsEnabled: z.ZodOptional<z.ZodBoolean>;
26
- workspacesEnabled: z.ZodOptional<z.ZodBoolean>;
27
- controlDesktop: z.ZodOptional<z.ZodBoolean>;
28
- }, z.core.$strip>;
29
- export type AgentConfigFile = z.infer<typeof AgentConfigFileSchema>;
30
- /**
31
- * Thoughts on the admin user:
32
- * 1. We need an admin user as a placeholder when no agents are running
33
- * Especially when a hub client starts up and the hub has assigned no agents to the host
34
- * 2. We want to be able to start agents and send mail from the placeholder so it needs to be an official user
35
- * It is registered in the hub db as well so we don't need tons of special case code everywhere like `if (userId === adminUserId)` ...
36
- * 3. The admin is also a source of ns-talk commands, gives the LLM someone to reply to
37
- * 4. Calling it a debug user would be confusing with debug input mode, also considered calling it operator, but admin seems more intuitive
38
- * 5. The hub supports agents running simultaneously across hosts, so each client can run an admin fine
39
- * 6. Having it as an official user means mail will be logged by the hub as well which is helpful for debugging and monitoring
40
- */
41
- export declare function buildDefaultAgentConfig(username: string): AgentConfigFile;
42
- export declare const adminAgentConfig: {
43
- username: string;
44
- title: string;
45
- shellModel: string;
46
- agentPrompt: string;
47
- tokenMax: number;
48
- mailEnabled: true;
49
- chatEnabled: true;
50
- wakeOnMessage: true;
51
- webEnabled: true;
52
- spendLimitDollars: number;
53
- };
54
- export interface UserEntry {
55
- userId: number;
56
- username: string;
57
- enabled: boolean;
58
- leadUserId?: number;
59
- assignedHostIds?: number[];
60
- apiKey?: string;
61
- config: AgentConfigFile;
62
- }
@@ -1,9 +0,0 @@
1
- export type AgentStatus = "active" | "available" | "disabled" | "offline" | "suspended";
2
- export declare function determineAgentStatus(opts: {
3
- isActive: boolean;
4
- isEnabled: boolean;
5
- isSuspended: boolean;
6
- assignedHostIds: number[] | undefined;
7
- isHostOnline: (hostId: number) => boolean;
8
- hasNonRestrictedOnlineHost: boolean;
9
- }): AgentStatus;
@@ -1,23 +0,0 @@
1
- export interface AuthCacheOptions {
2
- /** TTL in ms for valid (authenticated) entries. Default: 60_000 */
3
- ttlMs?: number;
4
- /** TTL in ms for negative (unauthenticated) entries. Default: 10_000 */
5
- negativeTtlMs?: number;
6
- /** Maximum number of cached entries. Default: 1_000 */
7
- maxSize?: number;
8
- }
9
- export declare class AuthCache<TUser> {
10
- private cache;
11
- private ttlMs;
12
- private negativeTtlMs;
13
- private maxSize;
14
- constructor(options?: AuthCacheOptions);
15
- /** Returns the cached user, `null` for a negative hit, or `undefined` on cache miss. */
16
- get(key: string): TUser | null | undefined;
17
- /** Cache a lookup result. Pass `null` to cache a negative (invalid token) result. */
18
- set(key: string, user: TUser | null): void;
19
- /** Remove a specific key from the cache (e.g. on logout). */
20
- invalidate(key: string): void;
21
- /** Clear the entire cache. */
22
- clear(): void;
23
- }
@@ -1,3 +0,0 @@
1
- import { type ImageModel, type LlmModel } from "./modelTypes.js";
2
- export declare const builtInLlmModels: LlmModel[];
3
- export declare const builtInImageModels: ImageModel[];
@@ -1 +0,0 @@
1
- export declare function sanitizeSpendLimit(num: any): number | undefined;
@@ -1,4 +0,0 @@
1
- export declare const SUPER_ADMIN_USERNAME = "superadmin";
2
- export declare const NAV_HEADER_ROW_HEIGHT = 48;
3
- /** Target megapixels for screenshots sent to LLMs during computer use */
4
- export declare const TARGET_MEGAPIXELS = 1.1;
@@ -1,10 +0,0 @@
1
- /**
2
- * Calculate the current period boundaries based on a given number of hours.
3
- * Periods are fixed multiples of hours from midnight (server local time).
4
- * The reason we don't slide the window is that we don't want to the llm to get stuck sending off a query
5
- * only for the window to close again, and the llm cache to *expire* creating a cycle of constant cache misses
6
- */
7
- export declare function calculatePeriodBoundaries(hours: number): {
8
- periodStart: Date;
9
- periodEnd: Date;
10
- };
@@ -1,28 +0,0 @@
1
- /**
2
- * Shared Fastify error handler that bypasses route-level Zod response
3
- * serializers by sending a pre-stringified JSON payload. Without this,
4
- * an error whose shape doesn't match the route's response schema causes a
5
- * cascading "Failed to serialize an error" from fastify-type-provider-zod.
6
- *
7
- * Interfaces are duck-typed so @naisys/common doesn't need a Fastify dependency.
8
- */
9
- interface HandlerError {
10
- statusCode?: number;
11
- message: string;
12
- name?: string;
13
- code?: string;
14
- }
15
- interface HandlerRequest {
16
- url: string;
17
- method: string;
18
- log: {
19
- error: (obj: Record<string, unknown>, msg: string) => void;
20
- };
21
- }
22
- interface HandlerReply {
23
- status: (code: number) => HandlerReply;
24
- header: (key: string, value: string) => HandlerReply;
25
- send: (payload: string) => void;
26
- }
27
- export declare function commonErrorHandler(error: HandlerError, request: HandlerRequest, reply: HandlerReply): void;
28
- export {};
@@ -1,4 +0,0 @@
1
- /** Maximum allowed file size for attachments (10 MB) */
2
- export declare const MAX_ATTACHMENT_SIZE: number;
3
- /** Format a byte count into a human-readable size string (e.g. "1.2 KB") */
4
- export declare function formatFileSize(bytes: number): string;
@@ -1,25 +0,0 @@
1
- export interface ClientConfig {
2
- shellCommand: {
3
- outputTokenMax: number;
4
- timeoutSeconds: number;
5
- maxTimeoutSeconds: number;
6
- };
7
- retrySecondsMax: number;
8
- webTokenMax: number;
9
- compactSessionEnabled: boolean;
10
- preemptiveCompactEnabled: boolean;
11
- googleSearchEngineId?: string;
12
- spendLimitDollars?: number;
13
- spendLimitHours?: number;
14
- variableMap: Record<string, string>;
15
- shellVariableMap: Record<string, string>;
16
- useToolsForLlmConsoleResponses: boolean;
17
- autoStartAgentsOnMessage: boolean;
18
- }
19
- /**
20
- * Builds hub-distributable config from the provided env vars.
21
- * @param variables - Env var source: process.env (ephemeral) or DB-sourced map (hub).
22
- * @param shellExportKeys - Set of variable keys that should be exported to the shell.
23
- * When undefined (e.g. .env fallback), all variables are exported for backwards compat.
24
- */
25
- export declare function buildClientConfig(variables: Record<string, string | undefined>, shellExportKeys?: Set<string>): ClientConfig;
@@ -1,76 +0,0 @@
1
- import { z } from "zod/v4";
2
- export declare const HateoasLinkSchema: z.ZodObject<{
3
- rel: z.ZodString;
4
- href: z.ZodString;
5
- method: z.ZodOptional<z.ZodString>;
6
- title: z.ZodOptional<z.ZodString>;
7
- schema: z.ZodOptional<z.ZodString>;
8
- }, z.core.$strip>;
9
- export type HateoasLink = z.infer<typeof HateoasLinkSchema>;
10
- export declare const AlternateEncodingSchema: z.ZodObject<{
11
- contentType: z.ZodString;
12
- description: z.ZodOptional<z.ZodString>;
13
- fileFields: z.ZodArray<z.ZodString>;
14
- }, z.core.$strip>;
15
- export type AlternateEncoding = z.infer<typeof AlternateEncodingSchema>;
16
- export declare const HateoasActionSchema: z.ZodObject<{
17
- rel: z.ZodString;
18
- href: z.ZodString;
19
- method: z.ZodString;
20
- title: z.ZodOptional<z.ZodString>;
21
- schema: z.ZodOptional<z.ZodString>;
22
- body: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
23
- alternateEncoding: z.ZodOptional<z.ZodObject<{
24
- contentType: z.ZodString;
25
- description: z.ZodOptional<z.ZodString>;
26
- fileFields: z.ZodArray<z.ZodString>;
27
- }, z.core.$strip>>;
28
- disabled: z.ZodOptional<z.ZodBoolean>;
29
- disabledReason: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
30
- }, z.core.$strip>;
31
- export type HateoasAction = z.infer<typeof HateoasActionSchema>;
32
- export declare const HateoasActionTemplateSchema: z.ZodObject<{
33
- rel: z.ZodString;
34
- hrefTemplate: z.ZodString;
35
- method: z.ZodString;
36
- title: z.ZodOptional<z.ZodString>;
37
- schema: z.ZodOptional<z.ZodString>;
38
- body: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
39
- alternateEncoding: z.ZodOptional<z.ZodObject<{
40
- contentType: z.ZodString;
41
- description: z.ZodOptional<z.ZodString>;
42
- fileFields: z.ZodArray<z.ZodString>;
43
- }, z.core.$strip>>;
44
- }, z.core.$strip>;
45
- export type HateoasActionTemplate = z.infer<typeof HateoasActionTemplateSchema>;
46
- export declare const HateoasLinkTemplateSchema: z.ZodObject<{
47
- rel: z.ZodString;
48
- hrefTemplate: z.ZodString;
49
- title: z.ZodOptional<z.ZodString>;
50
- }, z.core.$strip>;
51
- export type HateoasLinkTemplate = z.infer<typeof HateoasLinkTemplateSchema>;
52
- export declare const HateoasLinksSchema: z.ZodObject<{
53
- _links: z.ZodArray<z.ZodObject<{
54
- rel: z.ZodString;
55
- href: z.ZodString;
56
- method: z.ZodOptional<z.ZodString>;
57
- title: z.ZodOptional<z.ZodString>;
58
- schema: z.ZodOptional<z.ZodString>;
59
- }, z.core.$strip>>;
60
- _actions: z.ZodOptional<z.ZodArray<z.ZodObject<{
61
- rel: z.ZodString;
62
- href: z.ZodString;
63
- method: z.ZodString;
64
- title: z.ZodOptional<z.ZodString>;
65
- schema: z.ZodOptional<z.ZodString>;
66
- body: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
67
- alternateEncoding: z.ZodOptional<z.ZodObject<{
68
- contentType: z.ZodString;
69
- description: z.ZodOptional<z.ZodString>;
70
- fileFields: z.ZodArray<z.ZodString>;
71
- }, z.core.$strip>>;
72
- disabled: z.ZodOptional<z.ZodBoolean>;
73
- disabledReason: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
74
- }, z.core.$strip>>>;
75
- }, z.core.$strip>;
76
- export type HateoasLinks = z.infer<typeof HateoasLinksSchema>;
package/dist/hateoas.d.ts DELETED
@@ -1,35 +0,0 @@
1
- import type { HateoasAction, HateoasActionTemplate, HateoasLinkTemplate } from "./hateoas-types.js";
2
- /**
3
- * Returns the action if it exists and is enabled.
4
- * Pass `{ includeDisabled: true }` to also return disabled actions
5
- * (e.g. when rendering a disabled button with a tooltip).
6
- */
7
- export declare function hasAction(actions: HateoasAction[] | undefined, rel: string, opts?: {
8
- includeDisabled: boolean;
9
- }): HateoasAction | undefined;
10
- export declare function hasActionTemplate(templates: HateoasActionTemplate[] | undefined, rel: string): HateoasActionTemplate | undefined;
11
- export declare function hasLinkTemplate(templates: HateoasLinkTemplate[] | undefined, rel: string): HateoasLinkTemplate | undefined;
12
- export interface ActionDef<T> {
13
- rel: string;
14
- path?: string;
15
- href?: string;
16
- method: string;
17
- title: string;
18
- schema?: string;
19
- body?: Record<string, unknown>;
20
- permission?: string;
21
- statuses?: string[];
22
- visibleWhen?: (ctx: T) => boolean;
23
- hideWithoutPermission?: boolean;
24
- disabledWhen?: (ctx: T) => string | string[] | null;
25
- }
26
- export declare function resolveActions<T>(defs: ActionDef<T>[], baseHref: string, ctx: T, checkPermission: (permission: string) => boolean): HateoasAction[];
27
- export declare function permGate(hasPerm: boolean, permission: string): {
28
- disabled?: undefined;
29
- disabledReason?: undefined;
30
- } | {
31
- disabled: true;
32
- disabledReason: string;
33
- };
34
- /** Normalize a `disabledReason` (string | string[] | undefined) to a single display string. */
35
- export declare function formatDisabledReason(reason: string | string[] | undefined): string | undefined;
@@ -1,14 +0,0 @@
1
- /**
2
- * Interfaces for services that can be dynamically loaded in "hosted" mode
3
- * (running in the same process space to save memory).
4
- *
5
- * These are defined in @naisys/common so that both the caller and implementer
6
- * share the same type without a compile-time dependency between them.
7
- */
8
- /** Starts the Hub server. Exported by @naisys/hub */
9
- export type StartHub = (startupType: "standalone" | "hosted", startSupervisor?: boolean, plugins?: "erp"[], startupAgentPath?: string) => Promise<{
10
- hubPort: number;
11
- supervisorPort?: number;
12
- }>;
13
- /** Starts the Supervisor web server. Exported by @naisys/supervisor */
14
- export type StartServer = (startupType: "standalone" | "hosted", plugins?: "erp"[], hubPort?: number) => Promise<number>;
package/dist/index.d.ts DELETED
@@ -1,19 +0,0 @@
1
- export * from "./agentConfigFile.js";
2
- export * from "./agentStatus.js";
3
- export * from "./authCache.js";
4
- export * from "./builtInModels.js";
5
- export * from "./configUtils.js";
6
- export * from "./constants.js";
7
- export * from "./costUtils.js";
8
- export * from "./errorHandler.js";
9
- export * from "./formatFileSize.js";
10
- export * from "./globalConfigLoader.js";
11
- export * from "./hateoas.js";
12
- export * from "./hateoas-types.js";
13
- export * from "./hostedServices.js";
14
- export * from "./lenientJsonParser.js";
15
- export * from "./mimeTypes.js";
16
- export * from "./modelTypes.js";
17
- export * from "./securityHeaders.js";
18
- export * from "./sleep.js";
19
- export * from "./urlSafeKey.js";
@@ -1,15 +0,0 @@
1
- /**
2
- * Custom JSON content-type parser that accepts empty bodies on POST endpoints.
3
- * Without this, sending Content-Type: application/json with no body (common
4
- * with HTTP clients calling bodiless state-transition actions like /start,
5
- * /complete) causes a JSON parse error.
6
- *
7
- * Interface is duck-typed so @naisys/common doesn't need a Fastify dependency.
8
- */
9
- interface FastifyLike {
10
- addContentTypeParser(contentType: string, opts: {
11
- parseAs: "string";
12
- }, parser: (req: unknown, body: string, done: (err: Error | null, body?: unknown) => void) => void): void;
13
- }
14
- export declare function registerLenientJsonParser(fastify: FastifyLike): void;
15
- export {};
@@ -1 +0,0 @@
1
- export declare function mimeFromFilename(filename: string): string;
@@ -1,107 +0,0 @@
1
- import { z } from "zod";
2
- export declare enum LlmApiType {
3
- OpenAI = "openai",
4
- Google = "google",
5
- Anthropic = "anthropic",
6
- Mock = "mock",
7
- None = "none"
8
- }
9
- export declare const LlmModelSchema: z.ZodObject<{
10
- key: z.ZodString;
11
- label: z.ZodString;
12
- versionName: z.ZodString;
13
- apiType: z.ZodEnum<typeof LlmApiType>;
14
- maxTokens: z.ZodNumber;
15
- baseUrl: z.ZodOptional<z.ZodString>;
16
- apiKeyVar: z.ZodString;
17
- inputCost: z.ZodDefault<z.ZodNumber>;
18
- outputCost: z.ZodDefault<z.ZodNumber>;
19
- cacheWriteCost: z.ZodOptional<z.ZodNumber>;
20
- cacheReadCost: z.ZodOptional<z.ZodNumber>;
21
- cacheTtlSeconds: z.ZodOptional<z.ZodNumber>;
22
- supportsVision: z.ZodOptional<z.ZodBoolean>;
23
- supportsHearing: z.ZodOptional<z.ZodBoolean>;
24
- supportsComputerUse: z.ZodOptional<z.ZodBoolean>;
25
- }, z.core.$strip>;
26
- export type LlmModel = z.infer<typeof LlmModelSchema>;
27
- export declare const ImageModelSchema: z.ZodObject<{
28
- key: z.ZodString;
29
- label: z.ZodString;
30
- versionName: z.ZodString;
31
- size: z.ZodString;
32
- baseUrl: z.ZodOptional<z.ZodString>;
33
- apiKeyVar: z.ZodString;
34
- cost: z.ZodNumber;
35
- quality: z.ZodOptional<z.ZodEnum<{
36
- standard: "standard";
37
- hd: "hd";
38
- high: "high";
39
- medium: "medium";
40
- low: "low";
41
- }>>;
42
- }, z.core.$strip>;
43
- export type ImageModel = z.infer<typeof ImageModelSchema>;
44
- export declare const CustomModelsFileSchema: z.ZodObject<{
45
- llmModels: z.ZodOptional<z.ZodArray<z.ZodObject<{
46
- key: z.ZodString;
47
- label: z.ZodString;
48
- versionName: z.ZodString;
49
- apiType: z.ZodEnum<typeof LlmApiType>;
50
- maxTokens: z.ZodNumber;
51
- baseUrl: z.ZodOptional<z.ZodString>;
52
- apiKeyVar: z.ZodString;
53
- inputCost: z.ZodDefault<z.ZodNumber>;
54
- outputCost: z.ZodDefault<z.ZodNumber>;
55
- cacheWriteCost: z.ZodOptional<z.ZodNumber>;
56
- cacheReadCost: z.ZodOptional<z.ZodNumber>;
57
- cacheTtlSeconds: z.ZodOptional<z.ZodNumber>;
58
- supportsVision: z.ZodOptional<z.ZodBoolean>;
59
- supportsHearing: z.ZodOptional<z.ZodBoolean>;
60
- supportsComputerUse: z.ZodOptional<z.ZodBoolean>;
61
- }, z.core.$strip>>>;
62
- imageModels: z.ZodOptional<z.ZodArray<z.ZodObject<{
63
- key: z.ZodString;
64
- label: z.ZodString;
65
- versionName: z.ZodString;
66
- size: z.ZodString;
67
- baseUrl: z.ZodOptional<z.ZodString>;
68
- apiKeyVar: z.ZodString;
69
- cost: z.ZodNumber;
70
- quality: z.ZodOptional<z.ZodEnum<{
71
- standard: "standard";
72
- hd: "hd";
73
- high: "high";
74
- medium: "medium";
75
- low: "low";
76
- }>>;
77
- }, z.core.$strip>>>;
78
- }, z.core.$strip>;
79
- export type CustomModelsFile = z.infer<typeof CustomModelsFileSchema>;
80
- export type ModelDbType = "llm" | "image";
81
- /** Row shape returned from prisma models table */
82
- export interface ModelDbRow {
83
- id: number;
84
- key: string;
85
- type: ModelDbType;
86
- label: string;
87
- version_name: string;
88
- is_builtin: boolean;
89
- is_custom: boolean;
90
- meta: string;
91
- }
92
- /** Fields for prisma models.createMany / update (without id, created_at, updated_at) */
93
- export interface ModelDbFields {
94
- key: string;
95
- type: ModelDbType;
96
- label: string;
97
- version_name: string;
98
- is_builtin: boolean;
99
- is_custom: boolean;
100
- meta: string;
101
- }
102
- export declare function llmModelToDbFields(model: LlmModel, isBuiltin: boolean, isCustom: boolean): ModelDbFields;
103
- export declare function imageModelToDbFields(model: ImageModel, isBuiltin: boolean, isCustom: boolean): ModelDbFields;
104
- export declare function dbFieldsToLlmModel(row: ModelDbRow): LlmModel;
105
- export declare function dbFieldsToImageModel(row: ModelDbRow): ImageModel;
106
- export declare function getAllLlmModels(customLlmModels?: LlmModel[]): LlmModel[];
107
- export declare function getAllImageModels(customImageModels?: ImageModel[]): ImageModel[];
@@ -1,14 +0,0 @@
1
- /**
2
- * Shared security-header hook for Fastify servers.
3
- *
4
- * Interfaces are duck-typed so @naisys/common doesn't need a Fastify dependency.
5
- */
6
- interface HeaderReply {
7
- header: (key: string, value: string) => HeaderReply;
8
- }
9
- export declare function registerSecurityHeaders(fastify: {
10
- addHook: (name: string, fn: (request: unknown, reply: HeaderReply, payload: unknown, done: () => void) => void) => void;
11
- }, options: {
12
- enforceHsts: boolean;
13
- }): void;
14
- export {};
package/dist/sleep.d.ts DELETED
@@ -1,2 +0,0 @@
1
- /** Async sleep utility. Usage: `await sleep(1000)` */
2
- export declare function sleep(ms: number): Promise<void>;
@@ -1,7 +0,0 @@
1
- /** Characters allowed in URL path segments used as database keys (usernames, hostnames). */
2
- export declare const URL_SAFE_KEY_REGEX: RegExp;
3
- export declare const URL_SAFE_KEY_MESSAGE = "Must contain only letters, numbers, hyphens, and underscores";
4
- /** Sanitize a string into a URL-safe key (replace spaces/special chars with hyphens). */
5
- export declare function toUrlSafeKey(input: string): string;
6
- /** Throws if the value is not a valid URL-safe key. */
7
- export declare function assertUrlSafeKey(value: string, label: string): void;