From c757247858938894e73fc2272edc0fb7f865585e Mon Sep 17 00:00:00 2001 From: Tat Dat Duong Date: Mon, 7 Apr 2025 20:29:14 +0200 Subject: [PATCH 1/5] feat(sdk-js): add auth types --- libs/sdk-js/langchain.config.js | 1 + libs/sdk-js/src/auth/error.ts | 74 +++++++++ libs/sdk-js/src/auth/index.ts | 267 ++++++++++++++++++++++++++++++++ libs/sdk-js/tsconfig.json | 24 +-- 4 files changed, 347 insertions(+), 19 deletions(-) create mode 100644 libs/sdk-js/src/auth/error.ts create mode 100644 libs/sdk-js/src/auth/index.ts diff --git a/libs/sdk-js/langchain.config.js b/libs/sdk-js/langchain.config.js index 21d796c87..0c8a691cd 100644 --- a/libs/sdk-js/langchain.config.js +++ b/libs/sdk-js/langchain.config.js @@ -14,6 +14,7 @@ export const config = { entrypoints: { index: "index", client: "client", + auth: "auth/index", react: "react/index", "react-ui": "react-ui/index", "react-ui/server": "react-ui/server/index", diff --git a/libs/sdk-js/src/auth/error.ts b/libs/sdk-js/src/auth/error.ts new file mode 100644 index 000000000..bd26c8912 --- /dev/null +++ b/libs/sdk-js/src/auth/error.ts @@ -0,0 +1,74 @@ +const HTTP_STATUS_MAPPING: { [key: number]: string } = { + 100: "Continue", + 101: "Switching Protocols", + 102: "Processing", + 103: "Early Hints", + 200: "OK", + 201: "Created", + 202: "Accepted", + 203: "Non-Authoritative Information", + 204: "No Content", + 205: "Reset Content", + 206: "Partial Content", + 207: "Multi-Status", + 208: "Already Reported", + 226: "IM Used", + 300: "Multiple Choices", + 301: "Moved Permanently", + 302: "Found", + 303: "See Other", + 304: "Not Modified", + 305: "Use Proxy", + 307: "Temporary Redirect", + 308: "Permanent Redirect", + 400: "Bad Request", + 401: "Unauthorized", + 402: "Payment Required", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Not Acceptable", + 407: "Proxy Authentication Required", + 408: "Request Timeout", + 409: "Conflict", + 410: "Gone", + 411: "Length Required", + 412: "Precondition Failed", + 413: "Request Entity Too Large", + 414: "Request-URI Too Long", + 415: "Unsupported Media Type", + 416: "Requested Range Not Satisfiable", + 417: "Expectation Failed", + 418: "I'm a Teapot", + 421: "Misdirected Request", + 422: "Unprocessable Entity", + 423: "Locked", + 424: "Failed Dependency", + 425: "Too Early", + 426: "Upgrade Required", + 428: "Precondition Required", + 429: "Too Many Requests", + 431: "Request Header Fields Too Large", + 451: "Unavailable For Legal Reasons", + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + 505: "HTTP Version Not Supported", + 506: "Variant Also Negotiates", + 507: "Insufficient Storage", + 508: "Loop Detected", + 510: "Not Extended", + 511: "Network Authentication Required", +}; + +export class HTTPException extends Error { + status: number; + constructor(status: number, options?: { message?: string; cause?: Error }) { + super(options?.message ?? HTTP_STATUS_MAPPING[status] ?? "Unknown error", { + cause: options?.cause, + }); + this.status = status; + } +} diff --git a/libs/sdk-js/src/auth/index.ts b/libs/sdk-js/src/auth/index.ts new file mode 100644 index 000000000..900a3adbb --- /dev/null +++ b/libs/sdk-js/src/auth/index.ts @@ -0,0 +1,267 @@ +type Maybe = T | null | undefined; + +interface AssistantConfig { + tags?: Maybe; + recursion_limit?: Maybe; + configurable?: Maybe<{ + thread_id?: Maybe; + thread_ts?: Maybe; + [key: string]: unknown; + }>; + [key: string]: unknown; +} + +interface AssistantCreate { + assistant_id?: Maybe; + metadata?: Maybe>; + config?: Maybe; + if_exists?: Maybe<"raise" | "do_nothing">; + name?: Maybe; + graph_id: string; +} + +interface AssistantRead { + assistant_id: string; + metadata?: Maybe>; +} + +interface AssistantUpdate { + assistant_id: string; + metadata?: Maybe>; + config?: Maybe; + graph_id?: Maybe; + name?: Maybe; + version?: Maybe; +} + +interface AssistantDelete { + assistant_id: string; +} + +interface AssistantSearch { + graph_id?: Maybe; + metadata?: Maybe>; + limit?: Maybe; + offset?: Maybe; +} + +// TODO: add missing types +interface ThreadCreate {} +interface ThreadRead {} +interface ThreadUpdate {} +interface ThreadDelete {} +interface ThreadSearch {} + +interface CronCreate {} +interface CronRead {} +interface CronUpdate {} +interface CronDelete {} +interface CronSearch {} + +interface StorePut {} +interface StoreGet {} +interface StoreSearch {} +interface StoreListNamespaces {} +interface StoreDelete {} + +interface RunsCreate {} + +interface ResourceActionType { + ["threads:create"]: ThreadCreate; + ["threads:read"]: ThreadRead; + ["threads:update"]: ThreadUpdate; + ["threads:delete"]: ThreadDelete; + ["threads:search"]: ThreadSearch; + ["threads:create_run"]: RunsCreate; + + ["assistants:create"]: AssistantCreate; + ["assistants:read"]: AssistantRead; + ["assistants:update"]: AssistantUpdate; + ["assistants:delete"]: AssistantDelete; + ["assistants:search"]: AssistantSearch; + + ["crons:create"]: CronCreate; + ["crons:read"]: CronRead; + ["crons:update"]: CronUpdate; + ["crons:delete"]: CronDelete; + ["crons:search"]: CronSearch; + + ["store:put"]: StorePut; + ["store:get"]: StoreGet; + ["store:search"]: StoreSearch; + ["store:list_namespaces"]: StoreListNamespaces; + ["store:delete"]: StoreDelete; +} + +interface ResourceType { + threads: + | "threads:create" + | "threads:read" + | "threads:update" + | "threads:delete" + | "threads:search" + | "threads:create_run"; + + assistants: + | "assistants:create" + | "assistants:read" + | "assistants:update" + | "assistants:delete" + | "assistants:search"; + crons: + | "crons:create" + | "crons:read" + | "crons:update" + | "crons:delete" + | "crons:search"; + + store: + | "store:put" + | "store:get" + | "store:search" + | "store:list_namespaces" + | "store:delete"; +} + +interface ActionType { + "*:create": "threads:create" | "assistants:create" | "crons:create"; + + "*:read": "threads:read" | "assistants:read" | "crons:read"; + + "*:update": "threads:update" | "assistants:update" | "crons:update"; + + "*:delete": + | "threads:delete" + | "assistants:delete" + | "crons:delete" + | "store:delete"; + + "*:search": + | "threads:search" + | "assistants:search" + | "crons:search" + | "store:search"; + + "*:create_run": "threads:create_run"; + + "*:put": "store:put"; + + "*:get": "store:get"; + + "*:list_namespaces": "store:list_namespaces"; +} + +interface BaseAuthContext { + permissions?: string[]; + user?: { + is_authenticated: boolean; + display_name: string; + identity: string; + permissions: string[]; + }; +} + +type ContextMap = { + [ActionType in keyof ResourceActionType]: { + resource: ActionType extends `${infer Resource}:${string}` + ? Resource + : never; + action: ActionType; + data: ResourceActionType[ActionType]; + context: BaseAuthContext; + }; +}; + +type ActionCallbackParameter< + T extends keyof ActionType, + AuthContext = {}, +> = ContextMap[ActionType[T]] & { context: AuthContext }; + +type AuthCallbackParameter< + T extends keyof ResourceActionType, + AuthContext = {}, +> = ContextMap[T] & { context: AuthContext }; + +type ResourceCallbackParameter< + T extends keyof ResourceType, + AuthContext = {}, +> = ContextMap[ResourceType[T]] & { context: AuthContext }; + +type Filters = { + [key in TKey]: string | { [op in "$contains" | "$eq"]?: string }; +}; + +interface AuthenticateCallback> { + (request: Request): AuthContext; +} + +export class Auth< + Metadata extends Record = {}, + AuthContext extends Record = {}, +> { + protected __lg_type = Symbol.for("lg:auth"); + + "~handlerCache": { + authenticate?: AuthenticateCallback; + callbacks?: Record< + string, + (request: any) => void | boolean | Filters + >; + } = {}; + + authenticate(cb: AuthenticateCallback): this { + this["~handlerCache"].authenticate = cb; + return this; + } + + /** + * Global handler for all requests + */ + on( + event: "*", + callback: ( + data: AuthCallbackParameter, + ) => void | boolean | Filters, + ): this; + + /** + * Resource-specific handler + */ + on( + event: T, + callback: ( + data: ResourceCallbackParameter, + ) => void | boolean | Filters, + ): this; + + /** + * Action-specific handler + */ + on( + event: T, + callback: ( + data: ActionCallbackParameter, + ) => void | boolean | Filters, + ): this; + + /** + * Resource-action specific handler + */ + on( + event: T, + callback: ( + data: AuthCallbackParameter, + ) => void | boolean | Filters, + ): this; + + on( + event: string, + callback: ( + data: AuthCallbackParameter, + ) => void | boolean | Filters, + ): this { + this["~handlerCache"].callbacks ??= {}; + this["~handlerCache"].callbacks[event] = callback; + return this; + } +} diff --git a/libs/sdk-js/tsconfig.json b/libs/sdk-js/tsconfig.json index 9c6561a09..d5c1626ab 100644 --- a/libs/sdk-js/tsconfig.json +++ b/libs/sdk-js/tsconfig.json @@ -2,11 +2,7 @@ "extends": "@tsconfig/recommended", "compilerOptions": { "target": "ES2021", - "lib": [ - "ES2021", - "ES2022.Object", - "DOM" - ], + "lib": ["ES2021", "ES2022.Object", "ES2022.Error", "DOM"], "module": "NodeNext", "moduleResolution": "nodenext", "esModuleInterop": true, @@ -22,24 +18,14 @@ "jsx": "react-jsx", "outDir": "dist" }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "dist", - "coverage" - ], + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "coverage"], "includeVersion": true, "typedocOptions": { - "entryPoints": [ - "src/client.ts" - ], + "entryPoints": ["src/client.ts"], "readme": "none", "out": "docs", - "plugin": [ - "typedoc-plugin-markdown" - ], + "plugin": ["typedoc-plugin-markdown"], "excludePrivate": true, "excludeProtected": true, "excludeExternals": false From aee39605e096a2d19f76a3fa3e618f3da5a3061a Mon Sep 17 00:00:00 2001 From: Tat Dat Duong Date: Tue, 8 Apr 2025 14:13:59 +0200 Subject: [PATCH 2/5] Add missing types --- libs/sdk-js/.gitignore | 4 + libs/sdk-js/package.json | 13 +++ libs/sdk-js/src/auth/index.ts | 187 ++++++++++++++++++++++++++-------- 3 files changed, 163 insertions(+), 41 deletions(-) diff --git a/libs/sdk-js/.gitignore b/libs/sdk-js/.gitignore index 128c6dc98..db1a582d0 100644 --- a/libs/sdk-js/.gitignore +++ b/libs/sdk-js/.gitignore @@ -6,6 +6,10 @@ client.cjs client.js client.d.ts client.d.cts +auth.cjs +auth.js +auth.d.ts +auth.d.cts react.cjs react.js react.d.ts diff --git a/libs/sdk-js/package.json b/libs/sdk-js/package.json index 3be321092..2ff1c8282 100644 --- a/libs/sdk-js/package.json +++ b/libs/sdk-js/package.json @@ -72,6 +72,15 @@ "import": "./client.js", "require": "./client.cjs" }, + "./auth": { + "types": { + "import": "./auth.d.ts", + "require": "./auth.d.cts", + "default": "./auth.d.ts" + }, + "import": "./auth.js", + "require": "./auth.cjs" + }, "./react": { "types": { "import": "./react.d.ts", @@ -111,6 +120,10 @@ "client.js", "client.d.ts", "client.d.cts", + "auth.cjs", + "auth.js", + "auth.d.ts", + "auth.d.cts", "react.cjs", "react.js", "react.d.ts", diff --git a/libs/sdk-js/src/auth/index.ts b/libs/sdk-js/src/auth/index.ts index 900a3adbb..04a84d06b 100644 --- a/libs/sdk-js/src/auth/index.ts +++ b/libs/sdk-js/src/auth/index.ts @@ -5,10 +5,9 @@ interface AssistantConfig { recursion_limit?: Maybe; configurable?: Maybe<{ thread_id?: Maybe; - thread_ts?: Maybe; + thread_ts?: Maybe; [key: string]: unknown; }>; - [key: string]: unknown; } interface AssistantCreate { @@ -24,7 +23,6 @@ interface AssistantRead { assistant_id: string; metadata?: Maybe>; } - interface AssistantUpdate { assistant_id: string; metadata?: Maybe>; @@ -33,11 +31,9 @@ interface AssistantUpdate { name?: Maybe; version?: Maybe; } - interface AssistantDelete { assistant_id: string; } - interface AssistantSearch { graph_id?: Maybe; metadata?: Maybe>; @@ -45,28 +41,114 @@ interface AssistantSearch { offset?: Maybe; } -// TODO: add missing types -interface ThreadCreate {} -interface ThreadRead {} -interface ThreadUpdate {} -interface ThreadDelete {} -interface ThreadSearch {} +interface ThreadCreate { + thread_id?: Maybe; + metadata?: Maybe>; + if_exists?: Maybe<"raise" | "do_nothing">; +} -interface CronCreate {} -interface CronRead {} -interface CronUpdate {} -interface CronDelete {} -interface CronSearch {} +interface ThreadRead { + thread_id?: Maybe; +} -interface StorePut {} -interface StoreGet {} -interface StoreSearch {} -interface StoreListNamespaces {} -interface StoreDelete {} +interface ThreadUpdate { + thread_id?: Maybe; + metadata?: Maybe>; + action?: Maybe<"interrupt" | "rollback">; +} -interface RunsCreate {} +interface ThreadDelete { + thread_id?: Maybe; + run_id?: Maybe; +} -interface ResourceActionType { +interface ThreadSearch { + thread_id?: Maybe; + status?: Maybe<"idle" | "busy" | "interrupted" | "error" | (string & {})>; + metadata?: Maybe>; + values?: Maybe>; + limit?: Maybe; + offset?: Maybe; +} + +interface CronCreate { + payload?: Maybe>; + schedule: string; + cron_id?: Maybe; + thread_id?: Maybe; + user_id?: Maybe; + end_time?: Maybe; +} + +interface CronRead { + cron_id: string; +} + +interface CronUpdate { + cron_id: string; + payload?: Maybe>; + schedule?: Maybe; +} + +interface CronDelete { + cron_id: string; +} + +interface CronSearch { + assistant_id?: Maybe; + thread_id?: Maybe; + limit?: Maybe; + offset?: Maybe; +} + +interface StorePut { + namespace: string[]; + key: string; + value: Record; +} + +interface StoreGet { + namespace: Maybe; + key: string; +} + +interface StoreSearch { + namespace?: Maybe; + filter?: Maybe>; + limit?: Maybe; + offset?: Maybe; + query?: Maybe; +} + +interface StoreListNamespaces { + namespace?: Maybe; + suffix?: Maybe; + max_depth?: Maybe; + limit?: Maybe; + offset?: Maybe; +} + +interface StoreDelete { + namespace?: Maybe; + key: string; +} + +interface RunsCreate { + thread_id?: Maybe; + assistant_id: string; + run_id: string; + status: Maybe< + "pending" | "running" | "error" | "success" | "timeout" | "interrupted" + >; + metadata?: Maybe>; + prevent_insert_if_inflight?: Maybe; + multitask_strategy?: Maybe<"interrupt" | "rollback" | "reject" | "enqueue">; + if_not_exists?: Maybe<"reject" | "create">; + after_seconds?: Maybe; + kwargs: Record; +} + +export interface ResourceActionType { ["threads:create"]: ThreadCreate; ["threads:read"]: ThreadRead; ["threads:update"]: ThreadUpdate; @@ -187,7 +269,7 @@ type ResourceCallbackParameter< AuthContext = {}, > = ContextMap[ResourceType[T]] & { context: AuthContext }; -type Filters = { +export type Filters = { [key in TKey]: string | { [op in "$contains" | "$eq"]?: string }; }; @@ -195,12 +277,46 @@ interface AuthenticateCallback> { (request: Request): AuthContext; } +interface GlobalCallback< + Metadata extends Record = {}, + AuthContext extends Record = {}, +> { + ( + data: AuthCallbackParameter, + ): void | boolean | Filters; +} + +interface ResourceCallback< + Metadata extends Record = {}, + AuthContext extends Record = {}, +> { + ( + data: ResourceCallbackParameter, + ): void | boolean | Filters; +} + +interface ActionCallback< + Metadata extends Record = {}, + AuthContext extends Record = {}, +> { + ( + data: ActionCallbackParameter, + ): void | boolean | Filters; +} + +interface ResourceActionCallback< + Metadata extends Record = {}, + AuthContext extends Record = {}, +> { + ( + data: AuthCallbackParameter, + ): void | boolean | Filters; +} + export class Auth< Metadata extends Record = {}, AuthContext extends Record = {}, > { - protected __lg_type = Symbol.for("lg:auth"); - "~handlerCache": { authenticate?: AuthenticateCallback; callbacks?: Record< @@ -217,21 +333,14 @@ export class Auth< /** * Global handler for all requests */ - on( - event: "*", - callback: ( - data: AuthCallbackParameter, - ) => void | boolean | Filters, - ): this; + on(event: "*", callback: GlobalCallback): this; /** * Resource-specific handler */ on( event: T, - callback: ( - data: ResourceCallbackParameter, - ) => void | boolean | Filters, + callback: ResourceCallback, ): this; /** @@ -239,9 +348,7 @@ export class Auth< */ on( event: T, - callback: ( - data: ActionCallbackParameter, - ) => void | boolean | Filters, + callback: ActionCallback, ): this; /** @@ -249,9 +356,7 @@ export class Auth< */ on( event: T, - callback: ( - data: AuthCallbackParameter, - ) => void | boolean | Filters, + callback: ResourceActionCallback, ): this; on( From a98f9542fa3d2cb864017cfa5c5e82c885f2bd44 Mon Sep 17 00:00:00 2001 From: Tat Dat Duong Date: Tue, 8 Apr 2025 17:06:51 +0200 Subject: [PATCH 3/5] Add unused extra generic for future typing of metadata --- libs/sdk-js/src/auth/error.ts | 8 +- libs/sdk-js/src/auth/index.ts | 384 +++------------------------------- libs/sdk-js/src/auth/types.ts | 345 ++++++++++++++++++++++++++++++ 3 files changed, 377 insertions(+), 360 deletions(-) create mode 100644 libs/sdk-js/src/auth/types.ts diff --git a/libs/sdk-js/src/auth/error.ts b/libs/sdk-js/src/auth/error.ts index bd26c8912..ace6df54c 100644 --- a/libs/sdk-js/src/auth/error.ts +++ b/libs/sdk-js/src/auth/error.ts @@ -65,10 +65,16 @@ const HTTP_STATUS_MAPPING: { [key: number]: string } = { export class HTTPException extends Error { status: number; - constructor(status: number, options?: { message?: string; cause?: Error }) { + headers: HeadersInit; + + constructor( + status: number, + options?: { message?: string; headers?: HeadersInit; cause?: unknown }, + ) { super(options?.message ?? HTTP_STATUS_MAPPING[status] ?? "Unknown error", { cause: options?.cause, }); this.status = status; + this.headers = options?.headers ?? {}; } } diff --git a/libs/sdk-js/src/auth/index.ts b/libs/sdk-js/src/auth/index.ts index 04a84d06b..726e638d4 100644 --- a/libs/sdk-js/src/auth/index.ts +++ b/libs/sdk-js/src/auth/index.ts @@ -1,372 +1,38 @@ -type Maybe = T | null | undefined; - -interface AssistantConfig { - tags?: Maybe; - recursion_limit?: Maybe; - configurable?: Maybe<{ - thread_id?: Maybe; - thread_ts?: Maybe; - [key: string]: unknown; - }>; -} - -interface AssistantCreate { - assistant_id?: Maybe; - metadata?: Maybe>; - config?: Maybe; - if_exists?: Maybe<"raise" | "do_nothing">; - name?: Maybe; - graph_id: string; -} - -interface AssistantRead { - assistant_id: string; - metadata?: Maybe>; -} -interface AssistantUpdate { - assistant_id: string; - metadata?: Maybe>; - config?: Maybe; - graph_id?: Maybe; - name?: Maybe; - version?: Maybe; -} -interface AssistantDelete { - assistant_id: string; -} -interface AssistantSearch { - graph_id?: Maybe; - metadata?: Maybe>; - limit?: Maybe; - offset?: Maybe; -} - -interface ThreadCreate { - thread_id?: Maybe; - metadata?: Maybe>; - if_exists?: Maybe<"raise" | "do_nothing">; -} - -interface ThreadRead { - thread_id?: Maybe; -} - -interface ThreadUpdate { - thread_id?: Maybe; - metadata?: Maybe>; - action?: Maybe<"interrupt" | "rollback">; -} - -interface ThreadDelete { - thread_id?: Maybe; - run_id?: Maybe; -} - -interface ThreadSearch { - thread_id?: Maybe; - status?: Maybe<"idle" | "busy" | "interrupted" | "error" | (string & {})>; - metadata?: Maybe>; - values?: Maybe>; - limit?: Maybe; - offset?: Maybe; -} - -interface CronCreate { - payload?: Maybe>; - schedule: string; - cron_id?: Maybe; - thread_id?: Maybe; - user_id?: Maybe; - end_time?: Maybe; -} - -interface CronRead { - cron_id: string; -} - -interface CronUpdate { - cron_id: string; - payload?: Maybe>; - schedule?: Maybe; -} - -interface CronDelete { - cron_id: string; -} - -interface CronSearch { - assistant_id?: Maybe; - thread_id?: Maybe; - limit?: Maybe; - offset?: Maybe; -} - -interface StorePut { - namespace: string[]; - key: string; - value: Record; -} - -interface StoreGet { - namespace: Maybe; - key: string; -} - -interface StoreSearch { - namespace?: Maybe; - filter?: Maybe>; - limit?: Maybe; - offset?: Maybe; - query?: Maybe; -} - -interface StoreListNamespaces { - namespace?: Maybe; - suffix?: Maybe; - max_depth?: Maybe; - limit?: Maybe; - offset?: Maybe; -} - -interface StoreDelete { - namespace?: Maybe; - key: string; -} - -interface RunsCreate { - thread_id?: Maybe; - assistant_id: string; - run_id: string; - status: Maybe< - "pending" | "running" | "error" | "success" | "timeout" | "interrupted" - >; - metadata?: Maybe>; - prevent_insert_if_inflight?: Maybe; - multitask_strategy?: Maybe<"interrupt" | "rollback" | "reject" | "enqueue">; - if_not_exists?: Maybe<"reject" | "create">; - after_seconds?: Maybe; - kwargs: Record; -} - -export interface ResourceActionType { - ["threads:create"]: ThreadCreate; - ["threads:read"]: ThreadRead; - ["threads:update"]: ThreadUpdate; - ["threads:delete"]: ThreadDelete; - ["threads:search"]: ThreadSearch; - ["threads:create_run"]: RunsCreate; - - ["assistants:create"]: AssistantCreate; - ["assistants:read"]: AssistantRead; - ["assistants:update"]: AssistantUpdate; - ["assistants:delete"]: AssistantDelete; - ["assistants:search"]: AssistantSearch; - - ["crons:create"]: CronCreate; - ["crons:read"]: CronRead; - ["crons:update"]: CronUpdate; - ["crons:delete"]: CronDelete; - ["crons:search"]: CronSearch; - - ["store:put"]: StorePut; - ["store:get"]: StoreGet; - ["store:search"]: StoreSearch; - ["store:list_namespaces"]: StoreListNamespaces; - ["store:delete"]: StoreDelete; -} - -interface ResourceType { - threads: - | "threads:create" - | "threads:read" - | "threads:update" - | "threads:delete" - | "threads:search" - | "threads:create_run"; - - assistants: - | "assistants:create" - | "assistants:read" - | "assistants:update" - | "assistants:delete" - | "assistants:search"; - crons: - | "crons:create" - | "crons:read" - | "crons:update" - | "crons:delete" - | "crons:search"; - - store: - | "store:put" - | "store:get" - | "store:search" - | "store:list_namespaces" - | "store:delete"; -} - -interface ActionType { - "*:create": "threads:create" | "assistants:create" | "crons:create"; - - "*:read": "threads:read" | "assistants:read" | "crons:read"; - - "*:update": "threads:update" | "assistants:update" | "crons:update"; - - "*:delete": - | "threads:delete" - | "assistants:delete" - | "crons:delete" - | "store:delete"; - - "*:search": - | "threads:search" - | "assistants:search" - | "crons:search" - | "store:search"; - - "*:create_run": "threads:create_run"; - - "*:put": "store:put"; - - "*:get": "store:get"; - - "*:list_namespaces": "store:list_namespaces"; -} - -interface BaseAuthContext { - permissions?: string[]; - user?: { - is_authenticated: boolean; - display_name: string; - identity: string; - permissions: string[]; - }; -} - -type ContextMap = { - [ActionType in keyof ResourceActionType]: { - resource: ActionType extends `${infer Resource}:${string}` - ? Resource - : never; - action: ActionType; - data: ResourceActionType[ActionType]; - context: BaseAuthContext; - }; -}; - -type ActionCallbackParameter< - T extends keyof ActionType, - AuthContext = {}, -> = ContextMap[ActionType[T]] & { context: AuthContext }; - -type AuthCallbackParameter< - T extends keyof ResourceActionType, - AuthContext = {}, -> = ContextMap[T] & { context: AuthContext }; - -type ResourceCallbackParameter< - T extends keyof ResourceType, - AuthContext = {}, -> = ContextMap[ResourceType[T]] & { context: AuthContext }; - -export type Filters = { - [key in TKey]: string | { [op in "$contains" | "$eq"]?: string }; -}; - -interface AuthenticateCallback> { - (request: Request): AuthContext; -} - -interface GlobalCallback< - Metadata extends Record = {}, - AuthContext extends Record = {}, -> { - ( - data: AuthCallbackParameter, - ): void | boolean | Filters; -} - -interface ResourceCallback< - Metadata extends Record = {}, - AuthContext extends Record = {}, -> { - ( - data: ResourceCallbackParameter, - ): void | boolean | Filters; -} - -interface ActionCallback< - Metadata extends Record = {}, - AuthContext extends Record = {}, -> { - ( - data: ActionCallbackParameter, - ): void | boolean | Filters; -} - -interface ResourceActionCallback< - Metadata extends Record = {}, - AuthContext extends Record = {}, -> { - ( - data: AuthCallbackParameter, - ): void | boolean | Filters; -} +import type { + AuthenticateCallback, + AnyCallback, + CallbackEvent, + OnCallback, + BaseAuthReturn, + ToUserLike, + BaseUser, +} from "./types.js"; export class Auth< - Metadata extends Record = {}, - AuthContext extends Record = {}, + TExtra, + TAuthReturn extends BaseAuthReturn = BaseAuthReturn, + TUser extends BaseUser = ToUserLike, > { + extra: TExtra; + "~handlerCache": { - authenticate?: AuthenticateCallback; - callbacks?: Record< - string, - (request: any) => void | boolean | Filters - >; + authenticate?: AuthenticateCallback; + callbacks?: Record; } = {}; - authenticate(cb: AuthenticateCallback): this { + authenticate( + cb: AuthenticateCallback, + ): Auth { this["~handlerCache"].authenticate = cb; - return this; + return this as unknown as Auth; } - /** - * Global handler for all requests - */ - on(event: "*", callback: GlobalCallback): this; - - /** - * Resource-specific handler - */ - on( - event: T, - callback: ResourceCallback, - ): this; - - /** - * Action-specific handler - */ - on( - event: T, - callback: ActionCallback, - ): this; - - /** - * Resource-action specific handler - */ - on( - event: T, - callback: ResourceActionCallback, - ): this; - - on( - event: string, - callback: ( - data: AuthCallbackParameter, - ) => void | boolean | Filters, - ): this { + on(event: T, callback: OnCallback): this { this["~handlerCache"].callbacks ??= {}; - this["~handlerCache"].callbacks[event] = callback; + this["~handlerCache"].callbacks[event as string] = callback as AnyCallback; return this; } } + +export type { Filters, ResourceActionType } from "./types.js"; +export { HTTPException } from "./error.js"; diff --git a/libs/sdk-js/src/auth/types.ts b/libs/sdk-js/src/auth/types.ts new file mode 100644 index 000000000..d2a39e05b --- /dev/null +++ b/libs/sdk-js/src/auth/types.ts @@ -0,0 +1,345 @@ +type Maybe = T | null | undefined; +type PromiseMaybe = Promise | T; + +interface AssistantConfig { + tags?: Maybe; + recursion_limit?: Maybe; + configurable?: Maybe<{ + thread_id?: Maybe; + thread_ts?: Maybe; + [key: string]: unknown; + }>; +} + +interface AssistantCreate { + assistant_id?: Maybe; + metadata?: Maybe>; + config?: Maybe; + if_exists?: Maybe<"raise" | "do_nothing">; + name?: Maybe; + graph_id: string; +} + +interface AssistantRead { + assistant_id: string; + metadata?: Maybe>; +} + +interface AssistantUpdate { + assistant_id: string; + metadata?: Maybe>; + config?: Maybe; + graph_id?: Maybe; + name?: Maybe; + version?: Maybe; +} + +interface AssistantDelete { + assistant_id: string; +} + +interface AssistantSearch { + graph_id?: Maybe; + metadata?: Maybe>; + limit?: Maybe; + offset?: Maybe; +} + +interface ThreadCreate { + thread_id?: Maybe; + metadata?: Maybe>; + if_exists?: Maybe<"raise" | "do_nothing">; +} + +interface ThreadRead { + thread_id?: Maybe; +} + +interface ThreadUpdate { + thread_id?: Maybe; + metadata?: Maybe>; + action?: Maybe<"interrupt" | "rollback">; +} + +interface ThreadDelete { + thread_id?: Maybe; + run_id?: Maybe; +} + +interface ThreadSearch { + thread_id?: Maybe; + status?: Maybe<"idle" | "busy" | "interrupted" | "error" | (string & {})>; + metadata?: Maybe>; + values?: Maybe>; + limit?: Maybe; + offset?: Maybe; +} + +interface CronCreate { + payload?: Maybe>; + schedule: string; + cron_id?: Maybe; + thread_id?: Maybe; + user_id?: Maybe; + end_time?: Maybe; +} + +interface CronRead { + cron_id: string; +} + +interface CronUpdate { + cron_id: string; + payload?: Maybe>; + schedule?: Maybe; +} + +interface CronDelete { + cron_id: string; +} + +interface CronSearch { + assistant_id?: Maybe; + thread_id?: Maybe; + limit?: Maybe; + offset?: Maybe; +} + +interface StorePut { + namespace: string[]; + key: string; + value: Record; +} + +interface StoreGet { + namespace: Maybe; + key: string; +} + +interface StoreSearch { + namespace?: Maybe; + filter?: Maybe>; + limit?: Maybe; + offset?: Maybe; + query?: Maybe; +} + +interface StoreListNamespaces { + namespace?: Maybe; + suffix?: Maybe; + max_depth?: Maybe; + limit?: Maybe; + offset?: Maybe; +} + +interface StoreDelete { + namespace?: Maybe; + key: string; +} + +interface RunsCreate { + thread_id?: Maybe; + assistant_id: string; + run_id: string; + status: Maybe< + "pending" | "running" | "error" | "success" | "timeout" | "interrupted" + >; + metadata?: Maybe>; + prevent_insert_if_inflight?: Maybe; + multitask_strategy?: Maybe<"interrupt" | "rollback" | "reject" | "enqueue">; + if_not_exists?: Maybe<"reject" | "create">; + after_seconds?: Maybe; + kwargs: Record; +} + +export interface ResourceActionType { + ["threads:create"]: ThreadCreate; + ["threads:read"]: ThreadRead; + ["threads:update"]: ThreadUpdate; + ["threads:delete"]: ThreadDelete; + ["threads:search"]: ThreadSearch; + ["threads:create_run"]: RunsCreate; + + ["assistants:create"]: AssistantCreate; + ["assistants:read"]: AssistantRead; + ["assistants:update"]: AssistantUpdate; + ["assistants:delete"]: AssistantDelete; + ["assistants:search"]: AssistantSearch; + + ["crons:create"]: CronCreate; + ["crons:read"]: CronRead; + ["crons:update"]: CronUpdate; + ["crons:delete"]: CronDelete; + ["crons:search"]: CronSearch; + + ["store:put"]: StorePut; + ["store:get"]: StoreGet; + ["store:search"]: StoreSearch; + ["store:list_namespaces"]: StoreListNamespaces; + ["store:delete"]: StoreDelete; +} +interface ResourceType { + threads: + | "threads:create" + | "threads:read" + | "threads:update" + | "threads:delete" + | "threads:search" + | "threads:create_run"; + + assistants: + | "assistants:create" + | "assistants:read" + | "assistants:update" + | "assistants:delete" + | "assistants:search"; + crons: + | "crons:create" + | "crons:read" + | "crons:update" + | "crons:delete" + | "crons:search"; + + store: + | "store:put" + | "store:get" + | "store:search" + | "store:list_namespaces" + | "store:delete"; +} +interface ActionType { + "*:create": "threads:create" | "assistants:create" | "crons:create"; + + "*:read": "threads:read" | "assistants:read" | "crons:read"; + + "*:update": "threads:update" | "assistants:update" | "crons:update"; + + "*:delete": + | "threads:delete" + | "assistants:delete" + | "crons:delete" + | "store:delete"; + + "*:search": + | "threads:search" + | "assistants:search" + | "crons:search" + | "store:search"; + + "*:create_run": "threads:create_run"; + + "*:put": "store:put"; + + "*:get": "store:get"; + + "*:list_namespaces": "store:list_namespaces"; +} + +export type BaseAuthReturn = + | { + is_authenticated?: boolean; + display_name?: string; + identity: string; + permissions: string[]; + } + | string; + +export interface BaseUser { + is_authenticated: boolean; + display_name: string; + identity: string; + permissions: string[]; +} + +export type ToUserLike = T extends string + ? { + is_authenticated: boolean; + display_name: string; + identity: string; + permissions: string[]; + } + : Omit & { + is_authenticated: boolean; + display_name: string; + }; + +type CallbackParameter< + Resource extends string = string, + Action extends string = string, + Value extends unknown = unknown, + TUser extends BaseUser = BaseUser, +> = { + resource: Resource; + action: Action; + value: Value; + user: TUser; + permissions: string[]; +}; + +type ContextMap = { + [ActionType in keyof ResourceActionType]: CallbackParameter< + ActionType extends `${infer Resource}:${string}` ? Resource : never, + ActionType, + ResourceActionType[ActionType], + BaseUser + >; +}; + +type ActionCallbackParameter< + T extends keyof ActionType, + TUser extends BaseUser = BaseUser, +> = ContextMap[ActionType[T]] & { user: TUser }; +type AuthCallbackParameter< + T extends keyof ResourceActionType, + TUser extends BaseUser = BaseUser, +> = ContextMap[T] & { user: TUser }; +type ResourceCallbackParameter< + T extends keyof ResourceType, + TUser extends BaseUser = BaseUser, +> = ContextMap[ResourceType[T]] & { user: TUser }; + +export type Filters = { + [key in TKey]: string | { [op in "$contains" | "$eq"]?: string }; +}; + +export interface AuthenticateCallback { + (request: Request): PromiseMaybe; +} + +type OnKey = keyof ResourceType | keyof ActionType | keyof ResourceActionType; + +type OnSingleParameter< + T extends OnKey, + TUser extends BaseUser = BaseUser, +> = T extends keyof ResourceType + ? ResourceCallbackParameter + : T extends keyof ActionType + ? ActionCallbackParameter + : T extends keyof ResourceActionType + ? AuthCallbackParameter + : never; + +type OnParameter< + T extends "*" | OnKey | OnKey[], + TUser extends BaseUser = BaseUser, +> = T extends OnKey[] + ? OnSingleParameter + : T extends "*" + ? AuthCallbackParameter + : T extends OnKey + ? OnSingleParameter + : never; + +export type AnyCallback = ( + request: CallbackParameter, +) => void | boolean | Filters; + +export type CallbackEvent = "*" | OnKey | OnKey[]; + +export type OnCallback< + T extends CallbackEvent, + TUser extends BaseUser = BaseUser, + TMetadata extends Record = Record, +> = ( + request: OnParameter, +) => void | boolean | Filters; From 5f1213a1c72316c0a6443d3da9d1872179cc4208 Mon Sep 17 00:00:00 2001 From: Tat Dat Duong Date: Tue, 8 Apr 2025 17:07:04 +0200 Subject: [PATCH 4/5] Remove extra --- libs/sdk-js/src/auth/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/libs/sdk-js/src/auth/index.ts b/libs/sdk-js/src/auth/index.ts index 726e638d4..5229b43df 100644 --- a/libs/sdk-js/src/auth/index.ts +++ b/libs/sdk-js/src/auth/index.ts @@ -13,8 +13,6 @@ export class Auth< TAuthReturn extends BaseAuthReturn = BaseAuthReturn, TUser extends BaseUser = ToUserLike, > { - extra: TExtra; - "~handlerCache": { authenticate?: AuthenticateCallback; callbacks?: Record; From 7d5621a84fb803066f93762d642eff33e8ec08da Mon Sep 17 00:00:00 2001 From: Tat Dat Duong Date: Tue, 8 Apr 2025 17:10:43 +0200 Subject: [PATCH 5/5] Default type for TExtra --- libs/sdk-js/src/auth/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/sdk-js/src/auth/index.ts b/libs/sdk-js/src/auth/index.ts index 5229b43df..c736f5cbb 100644 --- a/libs/sdk-js/src/auth/index.ts +++ b/libs/sdk-js/src/auth/index.ts @@ -9,7 +9,7 @@ import type { } from "./types.js"; export class Auth< - TExtra, + TExtra = {}, TAuthReturn extends BaseAuthReturn = BaseAuthReturn, TUser extends BaseUser = ToUserLike, > {