@mantyx/sdk 0.9.1 → 0.10.1
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/CHANGELOG.md +9 -2
- package/README.md +81 -2
- package/dist/a2a-server.cjs.map +1 -1
- package/dist/a2a-server.d.cts +1 -1
- package/dist/a2a-server.d.ts +1 -1
- package/dist/a2a-server.js +1 -1
- package/dist/{chunk-AE7ZSLBH.js → chunk-XMUCELMH.js} +126 -24
- package/dist/chunk-XMUCELMH.js.map +1 -0
- package/dist/{client-BB6cjfsz.d.cts → client-CZUVldDx.d.cts} +401 -3
- package/dist/{client-BB6cjfsz.d.ts → client-CZUVldDx.d.ts} +401 -3
- package/dist/index.cjs +354 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -93
- package/dist/index.d.ts +3 -93
- package/dist/index.js +227 -2
- package/dist/index.js.map +1 -1
- package/docs/agent-runs-protocol.md +123 -113
- package/docs/oauth.md +356 -0
- package/docs/wire-protocol.md +1102 -0
- package/package.json +1 -1
- package/dist/chunk-AE7ZSLBH.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,96 +1,6 @@
|
|
|
1
|
-
export { A as A2AToolRef, a as AgentSession, b as AgentSpecBase, c as AssistantDeltaEvent, d as AssistantMessageEvent, C as CancelledEvent, D as DEFAULT_BASE_URL, e as
|
|
1
|
+
export { A as A2AToolRef, a as AgentSession, b as AgentSpecBase, c as AssistantDeltaEvent, d as AssistantMessageEvent, C as CancelledEvent, D as DEFAULT_BASE_URL, e as DEFAULT_OAUTH_BASE_URL, f as DEFAULT_REFRESH_SKEW_MS, g as DefineLocalA2AOptions, h as DefineLocalMcpOptions, i as DefineLocalToolOptions, E as ErrorEvent, L as LocalA2ATool, j as LocalHandlers, k as LocalMcpHttpTransport, l as LocalMcpServer, m as LocalMcpStdioTransport, n as LocalTool, o as LocalToolCallEvent, p as LocalToolResultInEvent, q as LoopDetectedEvent, r as LoopDetection, s as MantyxA2AOptions, t as MantyxAuthError, M as MantyxClient, u as MantyxClientOptions, v as MantyxError, w as MantyxMcpOptions, x as MantyxNetworkError, y as MantyxOAuthClient, z as MantyxOAuthClientOptions, B as MantyxOAuthError, F as MantyxParseError, G as MantyxPluginToolRef, H as MantyxRunError, I as MantyxRunErrorInit, J as MantyxScopeError, K as MantyxToolError, N as MantyxToolRef, O as McpToolRef, P as ModelCatalog, Q as ModelInfo, S as OAuthToken, U as OutputSchema, R as ReasoningLevel, V as RefreshOptions, W as RefreshTokenSourceOptions, X as ResultEvent, Y as RevokeOptions, Z as RunEvent, _ as RunEventBase, $ as RunResult, a0 as RunSpec, a1 as ServerToolResultEvent, a2 as SessionInfo, a3 as SessionSpec, a4 as ThinkingDeltaEvent, a5 as TokenRequestReason, a6 as TokenSource, a7 as ToolBudget, a8 as ToolBudgetExceededEvent, a9 as ToolBudgets, T as ToolRef, aa as ZodLikeObject, ab as defineLocalA2A, ac as defineLocalMcp, ad as defineLocalTool, ae as isLocalA2ATool, af as isLocalMcpServer, ag as isLocalTool, ah as mantyxA2A, ai as mantyxMcp, aj as mantyxPluginTool, ak as mantyxTool, al as parseRunOutput } from './client-CZUVldDx.cjs';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Error types raised by the MANTYX SDK.
|
|
6
|
-
*/
|
|
7
|
-
declare class MantyxError extends Error {
|
|
8
|
-
readonly code: string;
|
|
9
|
-
readonly status: number | undefined;
|
|
10
|
-
readonly hint: string | undefined;
|
|
11
|
-
constructor(message: string, opts?: {
|
|
12
|
-
code?: string;
|
|
13
|
-
status?: number;
|
|
14
|
-
hint?: string;
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
declare class MantyxNetworkError extends MantyxError {
|
|
18
|
-
constructor(message: string, opts?: {
|
|
19
|
-
cause?: unknown;
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
declare class MantyxAuthError extends MantyxError {
|
|
23
|
-
constructor(message?: string);
|
|
24
|
-
}
|
|
25
|
-
declare class MantyxToolError extends MantyxError {
|
|
26
|
-
readonly toolName: string;
|
|
27
|
-
constructor(toolName: string, message: string);
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Optional triage attributes the runner attaches to terminal `error`
|
|
31
|
-
* events. Mirrors the wire fields described in
|
|
32
|
-
* `docs/agent-runs-protocol.md` §7 ("error event payload fields") so SDK
|
|
33
|
-
* callers can render structured UI status notes ("model truncated — JSON
|
|
34
|
-
* likely incomplete") and drive retry policy without re-parsing the
|
|
35
|
-
* human-readable `message`.
|
|
36
|
-
*/
|
|
37
|
-
interface MantyxRunErrorInit {
|
|
38
|
-
/**
|
|
39
|
-
* Canonical category of failure. One of `"rate_limit"`, `"overloaded"`,
|
|
40
|
-
* `"server"`, `"context_window"`, `"truncation"`, `"invalid_request"`,
|
|
41
|
-
* `"auth"`, `"timeout"`, `"local_timeout"`, `"upstream_deadline"`,
|
|
42
|
-
* `"unknown"`. New categories may land additively — callers should
|
|
43
|
-
* default-branch to `"unknown"` for unrecognized values.
|
|
44
|
-
*/
|
|
45
|
-
errorClass?: string;
|
|
46
|
-
/**
|
|
47
|
-
* Canonical lowercase stop reason normalized across providers
|
|
48
|
-
* (`"max_tokens"`, `"refusal"`, `"malformed_function_call"`, …). When
|
|
49
|
-
* present, mirrors the value carried on the last `assistant_message`
|
|
50
|
-
* event preceding the failure.
|
|
51
|
-
*/
|
|
52
|
-
finishReason?: string | null;
|
|
53
|
-
/**
|
|
54
|
-
* **Best-effort raw bytes** the model emitted before the failure. For
|
|
55
|
-
* `outputSchema` runs this is likely **incomplete JSON** that will
|
|
56
|
-
* fail `JSON.parse` — treat it as diagnostic data, never as a
|
|
57
|
-
* schema-conformant reply.
|
|
58
|
-
*/
|
|
59
|
-
partialText?: string;
|
|
60
|
-
/**
|
|
61
|
-
* Coarse retry hint inherited from the pipeline's error classifier.
|
|
62
|
-
* Informational; the SDK still owns the actual retry decision.
|
|
63
|
-
*/
|
|
64
|
-
retryable?: boolean;
|
|
65
|
-
}
|
|
66
|
-
declare class MantyxRunError extends MantyxError {
|
|
67
|
-
readonly runId: string;
|
|
68
|
-
readonly subtype: string;
|
|
69
|
-
/** See {@link MantyxRunErrorInit.errorClass}. */
|
|
70
|
-
readonly errorClass: string | undefined;
|
|
71
|
-
/** See {@link MantyxRunErrorInit.finishReason}. */
|
|
72
|
-
readonly finishReason: string | null | undefined;
|
|
73
|
-
/** See {@link MantyxRunErrorInit.partialText}. */
|
|
74
|
-
readonly partialText: string | undefined;
|
|
75
|
-
/** See {@link MantyxRunErrorInit.retryable}. */
|
|
76
|
-
readonly retryable: boolean | undefined;
|
|
77
|
-
constructor(runId: string, subtype: string, message: string, init?: MantyxRunErrorInit);
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Thrown by {@link parseRunOutput} when the run's terminal text was supposed
|
|
81
|
-
* to be a JSON document (because `outputSchema` was set on the spec) but
|
|
82
|
-
* either failed to JSON.parse or failed the user-supplied validator.
|
|
83
|
-
*
|
|
84
|
-
* The original `text` is preserved on the `text` field so callers can log
|
|
85
|
-
* the raw model output for debugging.
|
|
86
|
-
*/
|
|
87
|
-
declare class MantyxParseError extends MantyxError {
|
|
88
|
-
readonly text: string;
|
|
89
|
-
constructor(message: string, text: string, opts?: {
|
|
90
|
-
cause?: unknown;
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
4
|
/**
|
|
95
5
|
* Lightweight Zod → JSON Schema converter for tool parameter definitions.
|
|
96
6
|
*
|
|
@@ -142,6 +52,6 @@ declare function readSseStream(body: ReadableStream<Uint8Array> | null, opts?: S
|
|
|
142
52
|
/**
|
|
143
53
|
* Release version — synced from repo root VERSION (`npm run sync-version`).
|
|
144
54
|
*/
|
|
145
|
-
declare const SDK_VERSION = "0.
|
|
55
|
+
declare const SDK_VERSION = "0.10.1";
|
|
146
56
|
|
|
147
|
-
export {
|
|
57
|
+
export { SDK_VERSION, type SseEvent, type SseStreamOptions, readSseStream, toToolParametersWire, zodToJsonSchema };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,96 +1,6 @@
|
|
|
1
|
-
export { A as A2AToolRef, a as AgentSession, b as AgentSpecBase, c as AssistantDeltaEvent, d as AssistantMessageEvent, C as CancelledEvent, D as DEFAULT_BASE_URL, e as
|
|
1
|
+
export { A as A2AToolRef, a as AgentSession, b as AgentSpecBase, c as AssistantDeltaEvent, d as AssistantMessageEvent, C as CancelledEvent, D as DEFAULT_BASE_URL, e as DEFAULT_OAUTH_BASE_URL, f as DEFAULT_REFRESH_SKEW_MS, g as DefineLocalA2AOptions, h as DefineLocalMcpOptions, i as DefineLocalToolOptions, E as ErrorEvent, L as LocalA2ATool, j as LocalHandlers, k as LocalMcpHttpTransport, l as LocalMcpServer, m as LocalMcpStdioTransport, n as LocalTool, o as LocalToolCallEvent, p as LocalToolResultInEvent, q as LoopDetectedEvent, r as LoopDetection, s as MantyxA2AOptions, t as MantyxAuthError, M as MantyxClient, u as MantyxClientOptions, v as MantyxError, w as MantyxMcpOptions, x as MantyxNetworkError, y as MantyxOAuthClient, z as MantyxOAuthClientOptions, B as MantyxOAuthError, F as MantyxParseError, G as MantyxPluginToolRef, H as MantyxRunError, I as MantyxRunErrorInit, J as MantyxScopeError, K as MantyxToolError, N as MantyxToolRef, O as McpToolRef, P as ModelCatalog, Q as ModelInfo, S as OAuthToken, U as OutputSchema, R as ReasoningLevel, V as RefreshOptions, W as RefreshTokenSourceOptions, X as ResultEvent, Y as RevokeOptions, Z as RunEvent, _ as RunEventBase, $ as RunResult, a0 as RunSpec, a1 as ServerToolResultEvent, a2 as SessionInfo, a3 as SessionSpec, a4 as ThinkingDeltaEvent, a5 as TokenRequestReason, a6 as TokenSource, a7 as ToolBudget, a8 as ToolBudgetExceededEvent, a9 as ToolBudgets, T as ToolRef, aa as ZodLikeObject, ab as defineLocalA2A, ac as defineLocalMcp, ad as defineLocalTool, ae as isLocalA2ATool, af as isLocalMcpServer, ag as isLocalTool, ah as mantyxA2A, ai as mantyxMcp, aj as mantyxPluginTool, ak as mantyxTool, al as parseRunOutput } from './client-CZUVldDx.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Error types raised by the MANTYX SDK.
|
|
6
|
-
*/
|
|
7
|
-
declare class MantyxError extends Error {
|
|
8
|
-
readonly code: string;
|
|
9
|
-
readonly status: number | undefined;
|
|
10
|
-
readonly hint: string | undefined;
|
|
11
|
-
constructor(message: string, opts?: {
|
|
12
|
-
code?: string;
|
|
13
|
-
status?: number;
|
|
14
|
-
hint?: string;
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
declare class MantyxNetworkError extends MantyxError {
|
|
18
|
-
constructor(message: string, opts?: {
|
|
19
|
-
cause?: unknown;
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
declare class MantyxAuthError extends MantyxError {
|
|
23
|
-
constructor(message?: string);
|
|
24
|
-
}
|
|
25
|
-
declare class MantyxToolError extends MantyxError {
|
|
26
|
-
readonly toolName: string;
|
|
27
|
-
constructor(toolName: string, message: string);
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Optional triage attributes the runner attaches to terminal `error`
|
|
31
|
-
* events. Mirrors the wire fields described in
|
|
32
|
-
* `docs/agent-runs-protocol.md` §7 ("error event payload fields") so SDK
|
|
33
|
-
* callers can render structured UI status notes ("model truncated — JSON
|
|
34
|
-
* likely incomplete") and drive retry policy without re-parsing the
|
|
35
|
-
* human-readable `message`.
|
|
36
|
-
*/
|
|
37
|
-
interface MantyxRunErrorInit {
|
|
38
|
-
/**
|
|
39
|
-
* Canonical category of failure. One of `"rate_limit"`, `"overloaded"`,
|
|
40
|
-
* `"server"`, `"context_window"`, `"truncation"`, `"invalid_request"`,
|
|
41
|
-
* `"auth"`, `"timeout"`, `"local_timeout"`, `"upstream_deadline"`,
|
|
42
|
-
* `"unknown"`. New categories may land additively — callers should
|
|
43
|
-
* default-branch to `"unknown"` for unrecognized values.
|
|
44
|
-
*/
|
|
45
|
-
errorClass?: string;
|
|
46
|
-
/**
|
|
47
|
-
* Canonical lowercase stop reason normalized across providers
|
|
48
|
-
* (`"max_tokens"`, `"refusal"`, `"malformed_function_call"`, …). When
|
|
49
|
-
* present, mirrors the value carried on the last `assistant_message`
|
|
50
|
-
* event preceding the failure.
|
|
51
|
-
*/
|
|
52
|
-
finishReason?: string | null;
|
|
53
|
-
/**
|
|
54
|
-
* **Best-effort raw bytes** the model emitted before the failure. For
|
|
55
|
-
* `outputSchema` runs this is likely **incomplete JSON** that will
|
|
56
|
-
* fail `JSON.parse` — treat it as diagnostic data, never as a
|
|
57
|
-
* schema-conformant reply.
|
|
58
|
-
*/
|
|
59
|
-
partialText?: string;
|
|
60
|
-
/**
|
|
61
|
-
* Coarse retry hint inherited from the pipeline's error classifier.
|
|
62
|
-
* Informational; the SDK still owns the actual retry decision.
|
|
63
|
-
*/
|
|
64
|
-
retryable?: boolean;
|
|
65
|
-
}
|
|
66
|
-
declare class MantyxRunError extends MantyxError {
|
|
67
|
-
readonly runId: string;
|
|
68
|
-
readonly subtype: string;
|
|
69
|
-
/** See {@link MantyxRunErrorInit.errorClass}. */
|
|
70
|
-
readonly errorClass: string | undefined;
|
|
71
|
-
/** See {@link MantyxRunErrorInit.finishReason}. */
|
|
72
|
-
readonly finishReason: string | null | undefined;
|
|
73
|
-
/** See {@link MantyxRunErrorInit.partialText}. */
|
|
74
|
-
readonly partialText: string | undefined;
|
|
75
|
-
/** See {@link MantyxRunErrorInit.retryable}. */
|
|
76
|
-
readonly retryable: boolean | undefined;
|
|
77
|
-
constructor(runId: string, subtype: string, message: string, init?: MantyxRunErrorInit);
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Thrown by {@link parseRunOutput} when the run's terminal text was supposed
|
|
81
|
-
* to be a JSON document (because `outputSchema` was set on the spec) but
|
|
82
|
-
* either failed to JSON.parse or failed the user-supplied validator.
|
|
83
|
-
*
|
|
84
|
-
* The original `text` is preserved on the `text` field so callers can log
|
|
85
|
-
* the raw model output for debugging.
|
|
86
|
-
*/
|
|
87
|
-
declare class MantyxParseError extends MantyxError {
|
|
88
|
-
readonly text: string;
|
|
89
|
-
constructor(message: string, text: string, opts?: {
|
|
90
|
-
cause?: unknown;
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
4
|
/**
|
|
95
5
|
* Lightweight Zod → JSON Schema converter for tool parameter definitions.
|
|
96
6
|
*
|
|
@@ -142,6 +52,6 @@ declare function readSseStream(body: ReadableStream<Uint8Array> | null, opts?: S
|
|
|
142
52
|
/**
|
|
143
53
|
* Release version — synced from repo root VERSION (`npm run sync-version`).
|
|
144
54
|
*/
|
|
145
|
-
declare const SDK_VERSION = "0.
|
|
55
|
+
declare const SDK_VERSION = "0.10.1";
|
|
146
56
|
|
|
147
|
-
export {
|
|
57
|
+
export { SDK_VERSION, type SseEvent, type SseStreamOptions, readSseStream, toToolParametersWire, zodToJsonSchema };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
MantyxNetworkError,
|
|
8
8
|
MantyxParseError,
|
|
9
9
|
MantyxRunError,
|
|
10
|
+
MantyxScopeError,
|
|
10
11
|
MantyxToolError,
|
|
11
12
|
defineLocalA2A,
|
|
12
13
|
defineLocalMcp,
|
|
@@ -22,19 +23,243 @@ import {
|
|
|
22
23
|
readSseStream,
|
|
23
24
|
toToolParametersWire,
|
|
24
25
|
zodToJsonSchema
|
|
25
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-XMUCELMH.js";
|
|
27
|
+
|
|
28
|
+
// src/oauth.ts
|
|
29
|
+
var DEFAULT_OAUTH_BASE_URL = "https://app.mantyx.io";
|
|
30
|
+
var DEFAULT_REFRESH_SKEW_MS = 6e4;
|
|
31
|
+
var MantyxOAuthError = class extends MantyxError {
|
|
32
|
+
oauthError;
|
|
33
|
+
oauthErrorDescription;
|
|
34
|
+
constructor(oauthError, oauthErrorDescription, status) {
|
|
35
|
+
const message = oauthErrorDescription ? `OAuth ${oauthError}: ${oauthErrorDescription}` : `OAuth ${oauthError}`;
|
|
36
|
+
super(message, { code: oauthError, status });
|
|
37
|
+
this.name = "MantyxOAuthError";
|
|
38
|
+
this.oauthError = oauthError;
|
|
39
|
+
this.oauthErrorDescription = oauthErrorDescription;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var MantyxOAuthClient = class {
|
|
43
|
+
clientId;
|
|
44
|
+
baseUrl;
|
|
45
|
+
clientSecret;
|
|
46
|
+
fetchImpl;
|
|
47
|
+
timeoutMs;
|
|
48
|
+
constructor(opts) {
|
|
49
|
+
if (!opts.clientId) {
|
|
50
|
+
throw new MantyxError("`clientId` is required for MantyxOAuthClient");
|
|
51
|
+
}
|
|
52
|
+
if (!opts.clientSecret) {
|
|
53
|
+
throw new MantyxError("`clientSecret` is required for MantyxOAuthClient");
|
|
54
|
+
}
|
|
55
|
+
const f = opts.fetch ?? globalThis.fetch;
|
|
56
|
+
if (typeof f !== "function") {
|
|
57
|
+
throw new MantyxError(
|
|
58
|
+
"Global fetch is not available; pass a custom `fetch` implementation in MantyxOAuthClientOptions."
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
this.clientId = opts.clientId;
|
|
62
|
+
this.clientSecret = opts.clientSecret;
|
|
63
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_OAUTH_BASE_URL).replace(/\/+$/, "");
|
|
64
|
+
this.fetchImpl = f;
|
|
65
|
+
this.timeoutMs = opts.timeoutMs ?? 3e4;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Mint a fresh access token from a stored refresh token. The
|
|
69
|
+
* returned `refreshToken` is identical to the input — refresh
|
|
70
|
+
* tokens are persistent and non-rotating, so the field is
|
|
71
|
+
* surfaced only for symmetry with the response shape.
|
|
72
|
+
*
|
|
73
|
+
* On `400 invalid_grant` the refresh token has been revoked (or its
|
|
74
|
+
* grant / app was deleted); the SDK surfaces a
|
|
75
|
+
* {@link MantyxOAuthError} and callers must drive a fresh sign-in.
|
|
76
|
+
*/
|
|
77
|
+
async refresh(opts) {
|
|
78
|
+
if (!opts.refreshToken) {
|
|
79
|
+
throw new MantyxError("`refreshToken` is required for MantyxOAuthClient.refresh");
|
|
80
|
+
}
|
|
81
|
+
const body = {
|
|
82
|
+
grant_type: "refresh_token",
|
|
83
|
+
refresh_token: opts.refreshToken
|
|
84
|
+
};
|
|
85
|
+
const scope = normalizeScope(opts.scope);
|
|
86
|
+
if (scope !== void 0) body.scope = scope;
|
|
87
|
+
return this.token(body);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Revoke an access or refresh token (RFC 7009). The server always
|
|
91
|
+
* returns 200, even for unknown tokens. Revoking a **refresh**
|
|
92
|
+
* token kills the refresh and every live access token tied to its
|
|
93
|
+
* grant; revoking an **access** token kills only that one.
|
|
94
|
+
*/
|
|
95
|
+
async revoke(opts) {
|
|
96
|
+
if (!opts.token) {
|
|
97
|
+
throw new MantyxError("`token` is required for MantyxOAuthClient.revoke");
|
|
98
|
+
}
|
|
99
|
+
await this.formPost("/api/oauth/revoke", {
|
|
100
|
+
token: opts.token
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Build a long-lived {@link TokenSource} that re-mints access
|
|
105
|
+
* tokens from the supplied refresh token. Pass the returned source
|
|
106
|
+
* to `new MantyxClient({ tokenSource, workspaceSlug, ... })`. The
|
|
107
|
+
* source caches the access token in-memory and refreshes
|
|
108
|
+
* proactively when the cached value is within `refreshSkewMs` of
|
|
109
|
+
* `expiresAt`, or eagerly when `MantyxClient` reports a 401.
|
|
110
|
+
*
|
|
111
|
+
* Pass `initialToken` if the calling app already has a non-expired
|
|
112
|
+
* access token in hand (e.g. straight out of the sign-in flow) to
|
|
113
|
+
* avoid an extra round-trip on the first request.
|
|
114
|
+
*/
|
|
115
|
+
refreshTokenSource(opts) {
|
|
116
|
+
if (!opts.refreshToken) {
|
|
117
|
+
throw new MantyxError("`refreshToken` is required for MantyxOAuthClient.refreshTokenSource");
|
|
118
|
+
}
|
|
119
|
+
const skew = opts.refreshSkewMs ?? DEFAULT_REFRESH_SKEW_MS;
|
|
120
|
+
const cache = { token: opts.initialToken, inflight: null };
|
|
121
|
+
const refreshToken = opts.refreshToken;
|
|
122
|
+
return makeTokenSource(cache, skew, async () => {
|
|
123
|
+
return this.refresh({ refreshToken, scope: opts.scope });
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// -------------------------------------------------------------- internals
|
|
127
|
+
/**
|
|
128
|
+
* POST `application/x-www-form-urlencoded` to `/api/oauth/token` and
|
|
129
|
+
* decode the {@link OAuthToken} response. Always injects `client_id`
|
|
130
|
+
* + `client_secret` from the constructor.
|
|
131
|
+
*/
|
|
132
|
+
async token(body) {
|
|
133
|
+
const res = await this.formPost("/api/oauth/token", body);
|
|
134
|
+
let parsed = {};
|
|
135
|
+
try {
|
|
136
|
+
parsed = await res.json();
|
|
137
|
+
} catch {
|
|
138
|
+
throw new MantyxOAuthError(
|
|
139
|
+
"invalid_response",
|
|
140
|
+
"Token endpoint returned a non-JSON response",
|
|
141
|
+
res.status
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
const accessToken = typeof parsed.access_token === "string" ? parsed.access_token : "";
|
|
145
|
+
if (!accessToken) {
|
|
146
|
+
throw new MantyxOAuthError(
|
|
147
|
+
"invalid_response",
|
|
148
|
+
"Token endpoint response is missing `access_token`",
|
|
149
|
+
res.status
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
const expiresIn = typeof parsed.expires_in === "number" ? parsed.expires_in : 3600;
|
|
153
|
+
return {
|
|
154
|
+
accessToken,
|
|
155
|
+
refreshToken: typeof parsed.refresh_token === "string" ? parsed.refresh_token : void 0,
|
|
156
|
+
tokenType: typeof parsed.token_type === "string" ? parsed.token_type : "Bearer",
|
|
157
|
+
expiresIn,
|
|
158
|
+
expiresAt: Date.now() + expiresIn * 1e3,
|
|
159
|
+
scope: typeof parsed.scope === "string" ? parsed.scope : void 0
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
async formPost(path, body) {
|
|
163
|
+
const url = `${this.baseUrl}${path}`;
|
|
164
|
+
const params = new URLSearchParams({
|
|
165
|
+
...body,
|
|
166
|
+
client_id: this.clientId,
|
|
167
|
+
client_secret: this.clientSecret
|
|
168
|
+
});
|
|
169
|
+
const ctrl = new AbortController();
|
|
170
|
+
const t = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
171
|
+
let res;
|
|
172
|
+
try {
|
|
173
|
+
res = await this.fetchImpl(url, {
|
|
174
|
+
method: "POST",
|
|
175
|
+
headers: {
|
|
176
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
177
|
+
Accept: "application/json"
|
|
178
|
+
},
|
|
179
|
+
body: params.toString(),
|
|
180
|
+
signal: ctrl.signal
|
|
181
|
+
});
|
|
182
|
+
} catch (err) {
|
|
183
|
+
if (ctrl.signal.aborted) {
|
|
184
|
+
throw new MantyxNetworkError(`OAuth request timed out after ${this.timeoutMs}ms`);
|
|
185
|
+
}
|
|
186
|
+
throw new MantyxNetworkError(`OAuth network error: ${err.message}`, {
|
|
187
|
+
cause: err
|
|
188
|
+
});
|
|
189
|
+
} finally {
|
|
190
|
+
clearTimeout(t);
|
|
191
|
+
}
|
|
192
|
+
if (!res.ok) {
|
|
193
|
+
let errBody = {};
|
|
194
|
+
try {
|
|
195
|
+
errBody = await res.json();
|
|
196
|
+
} catch {
|
|
197
|
+
}
|
|
198
|
+
const oauthError = typeof errBody.error === "string" ? errBody.error : `http_${res.status}`;
|
|
199
|
+
const desc = typeof errBody.error_description === "string" ? errBody.error_description : void 0;
|
|
200
|
+
throw new MantyxOAuthError(oauthError, desc, res.status);
|
|
201
|
+
}
|
|
202
|
+
return res;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
function makeTokenSource(cache, skewMs, mint) {
|
|
206
|
+
return async (reason = "initial") => {
|
|
207
|
+
if (reason !== "unauthorized" && cache.token && !isExpiring(cache.token, skewMs)) {
|
|
208
|
+
return cache.token.accessToken;
|
|
209
|
+
}
|
|
210
|
+
if (cache.inflight) {
|
|
211
|
+
const t = await cache.inflight;
|
|
212
|
+
if (reason === "unauthorized" && t === cache.token) {
|
|
213
|
+
} else {
|
|
214
|
+
return t.accessToken;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
cache.inflight = mint().then(
|
|
218
|
+
(t) => {
|
|
219
|
+
cache.token = t;
|
|
220
|
+
return t;
|
|
221
|
+
},
|
|
222
|
+
(err) => {
|
|
223
|
+
throw err;
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
try {
|
|
227
|
+
const t = await cache.inflight;
|
|
228
|
+
return t.accessToken;
|
|
229
|
+
} finally {
|
|
230
|
+
cache.inflight = null;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function isExpiring(token, skewMs) {
|
|
235
|
+
return token.expiresAt - Date.now() <= skewMs;
|
|
236
|
+
}
|
|
237
|
+
function normalizeScope(scope) {
|
|
238
|
+
if (scope === void 0) return void 0;
|
|
239
|
+
if (typeof scope === "string") {
|
|
240
|
+
const trimmed = scope.trim();
|
|
241
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
242
|
+
}
|
|
243
|
+
const joined = scope.filter((s) => typeof s === "string" && s.length > 0).join(" ");
|
|
244
|
+
return joined.length > 0 ? joined : void 0;
|
|
245
|
+
}
|
|
26
246
|
|
|
27
247
|
// src/version.ts
|
|
28
|
-
var SDK_VERSION = "0.
|
|
248
|
+
var SDK_VERSION = "0.10.1";
|
|
29
249
|
export {
|
|
30
250
|
AgentSession,
|
|
31
251
|
DEFAULT_BASE_URL,
|
|
252
|
+
DEFAULT_OAUTH_BASE_URL,
|
|
253
|
+
DEFAULT_REFRESH_SKEW_MS,
|
|
32
254
|
MantyxAuthError,
|
|
33
255
|
MantyxClient,
|
|
34
256
|
MantyxError,
|
|
35
257
|
MantyxNetworkError,
|
|
258
|
+
MantyxOAuthClient,
|
|
259
|
+
MantyxOAuthError,
|
|
36
260
|
MantyxParseError,
|
|
37
261
|
MantyxRunError,
|
|
262
|
+
MantyxScopeError,
|
|
38
263
|
MantyxToolError,
|
|
39
264
|
SDK_VERSION,
|
|
40
265
|
defineLocalA2A,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["/**\n * Release version — synced from repo root VERSION (`npm run sync-version`).\n */\nexport const SDK_VERSION = \"0.9.1\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAGO,IAAM,cAAc;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/oauth.ts","../src/version.ts"],"sourcesContent":["/**\n * MANTYX OAuth 2.0 refresh client: trade a stored refresh token for\n * short-lived access tokens, revoke tokens at sign-out, and expose\n * a {@link TokenSource} the {@link MantyxClient} HTTP layer calls\n * before every request (and again on 401).\n *\n * The library is intentionally **refresh-only**. It assumes the caller\n * already obtained the refresh token through their own sign-in flow\n * (Authorization Code + PKCE in a browser, native redirect, server-\n * side exchange — whatever fits the host application). The SDK does\n * not drive consent, does not initiate auth-code exchanges, and does\n * not bundle PKCE helpers.\n *\n * Wire contract (`docs/oauth.md`):\n *\n * - Token endpoint: `POST <baseUrl>/api/oauth/token`, form-encoded,\n * `grant_type=refresh_token`. Echoes back the same `refresh_token`\n * the client sent (refresh tokens are persistent and non-rotating).\n * - Revoke endpoint: `POST <baseUrl>/api/oauth/revoke`, form-encoded.\n * - Access tokens (`mantyx_at_…`) live 1 hour (`expires_in: 3600`).\n * - Refresh tokens (`mantyx_rt_…`) are long-lived; the caller persists\n * them once at first sign-in (encrypted at rest) and the SDK re-mints\n * access tokens from the same value on demand.\n */\n\nimport { MantyxError, MantyxNetworkError } from \"./errors.js\";\n\nexport const DEFAULT_OAUTH_BASE_URL = \"https://app.mantyx.io\";\n\n/** Skew (ms) before `expiresAt` at which a TokenSource will pre-emptively refresh. Default 60s. */\nexport const DEFAULT_REFRESH_SKEW_MS = 60_000;\n\n/**\n * Raised on a non-2xx response from `POST /api/oauth/token` or\n * `POST /api/oauth/revoke`. Carries the RFC 6749 `error` discriminator\n * (`\"invalid_grant\"`, `\"invalid_client\"`, `\"unsupported_grant_type\"`,\n * …) and the optional `error_description` so callers can branch on\n * machine-readable values without parsing the human message.\n *\n * `invalid_grant` from the refresh path specifically signals that the\n * refresh token has been revoked (or the OAuth grant / application\n * was deleted). The SDK never loops on this — callers should route\n * the user back to a fresh sign-in.\n */\nexport class MantyxOAuthError extends MantyxError {\n readonly oauthError: string;\n readonly oauthErrorDescription: string | undefined;\n\n constructor(\n oauthError: string,\n oauthErrorDescription: string | undefined,\n status: number,\n ) {\n const message = oauthErrorDescription\n ? `OAuth ${oauthError}: ${oauthErrorDescription}`\n : `OAuth ${oauthError}`;\n super(message, { code: oauthError, status });\n this.name = \"MantyxOAuthError\";\n this.oauthError = oauthError;\n this.oauthErrorDescription = oauthErrorDescription;\n }\n}\n\n/**\n * Decoded `POST /api/oauth/token` response, augmented with an absolute\n * `expiresAt` timestamp the SDK uses to decide when to refresh.\n *\n * On the refresh grant the response's `refreshToken` is identical to\n * the value the client just sent (refresh tokens never rotate). The\n * field is surfaced for symmetry with whatever the calling app's\n * sign-in flow already does.\n */\nexport interface OAuthToken {\n readonly accessToken: string;\n readonly refreshToken: string | undefined;\n readonly tokenType: string;\n readonly expiresIn: number;\n /** Absolute Unix-ms timestamp set when the SDK parsed the response. */\n readonly expiresAt: number;\n readonly scope: string | undefined;\n}\n\n/** Why the SDK asked the {@link TokenSource} for the current access token. */\nexport type TokenRequestReason = \"initial\" | \"expired\" | \"unauthorized\";\n\n/**\n * A `TokenSource` produces the current access token on demand. The\n * {@link MantyxClient} HTTP layer calls it before every request. When\n * called with `reason: \"unauthorized\"` the source MUST force a refresh\n * (do not return a cached value); this is how the SDK recovers from\n * 401s caused by a token that the server already invalidated.\n *\n * Implementations should be safe to call from many concurrent requests.\n */\nexport type TokenSource = (reason?: TokenRequestReason) => Promise<string>;\n\n/** Caller-supplied options for `MantyxOAuthClient`. */\nexport interface MantyxOAuthClientOptions {\n /**\n * OAuth `client_id` issued at app registration (token prefix\n * `mantyx_oa_`).\n */\n clientId: string;\n /**\n * OAuth `client_secret` issued at app registration (token prefix\n * `mantyx_oas_`). Every MANTYX OAuth app is a confidential client,\n * so this is always required for token + revoke calls. Treat as a\n * deployment secret — do not bundle into browser builds.\n */\n clientSecret: string;\n /**\n * Origin of the MANTYX deployment. Defaults to `https://app.mantyx.io`.\n * The OAuth endpoints are mounted at `<baseUrl>/api/oauth/...`.\n */\n baseUrl?: string;\n /** Optional `fetch` override (e.g. node-fetch wrapper). Default: global `fetch`. */\n fetch?: typeof fetch;\n /** Default per-request timeout in milliseconds. Default: 30s. */\n timeoutMs?: number;\n}\n\nexport interface RefreshOptions {\n refreshToken: string;\n /**\n * Optional scope narrowing. Must be a subset of the scopes already\n * granted to the refresh token (server enforces this). Useful when\n * an SDK consumer wants a short-scope access token for a specific\n * sub-operation.\n */\n scope?: string | readonly string[];\n}\n\nexport interface RevokeOptions {\n token: string;\n}\n\nexport interface RefreshTokenSourceOptions {\n refreshToken: string;\n /** Optional scope narrowing applied on every refresh. */\n scope?: string | readonly string[];\n /**\n * How many ms before `expiresAt` the source proactively refreshes.\n * Defaults to {@link DEFAULT_REFRESH_SKEW_MS} (60s).\n */\n refreshSkewMs?: number;\n /**\n * Optional initial access token + expiry to seed the source's cache\n * with (e.g. the token already in hand from the host application's\n * sign-in flow). When omitted, the source mints one on the first\n * call.\n */\n initialToken?: OAuthToken;\n}\n\n/**\n * Refresh-only wrapper around the MANTYX OAuth 2.0 authorization-server\n * endpoints. App-scoped (one per `{clientId, clientSecret}` pair);\n * construct independently of {@link MantyxClient}, then either call\n * {@link refresh} / {@link revoke} directly or hand a `TokenSource`\n * produced by {@link refreshTokenSource} to `MantyxClient` for fully\n * transparent refresh on every request.\n *\n * The client deliberately does **not** drive the authorization-code\n * exchange or any other \"initiate sign-in\" grant. The caller is\n * expected to obtain the refresh token through their own consent flow\n * and persist it before constructing this client.\n */\nexport class MantyxOAuthClient {\n readonly clientId: string;\n readonly baseUrl: string;\n private readonly clientSecret: string;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(opts: MantyxOAuthClientOptions) {\n if (!opts.clientId) {\n throw new MantyxError(\"`clientId` is required for MantyxOAuthClient\");\n }\n if (!opts.clientSecret) {\n throw new MantyxError(\"`clientSecret` is required for MantyxOAuthClient\");\n }\n const f = opts.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new MantyxError(\n \"Global fetch is not available; pass a custom `fetch` implementation in MantyxOAuthClientOptions.\",\n );\n }\n this.clientId = opts.clientId;\n this.clientSecret = opts.clientSecret;\n this.baseUrl = (opts.baseUrl ?? DEFAULT_OAUTH_BASE_URL).replace(/\\/+$/, \"\");\n this.fetchImpl = f;\n this.timeoutMs = opts.timeoutMs ?? 30_000;\n }\n\n /**\n * Mint a fresh access token from a stored refresh token. The\n * returned `refreshToken` is identical to the input — refresh\n * tokens are persistent and non-rotating, so the field is\n * surfaced only for symmetry with the response shape.\n *\n * On `400 invalid_grant` the refresh token has been revoked (or its\n * grant / app was deleted); the SDK surfaces a\n * {@link MantyxOAuthError} and callers must drive a fresh sign-in.\n */\n async refresh(opts: RefreshOptions): Promise<OAuthToken> {\n if (!opts.refreshToken) {\n throw new MantyxError(\"`refreshToken` is required for MantyxOAuthClient.refresh\");\n }\n const body: Record<string, string> = {\n grant_type: \"refresh_token\",\n refresh_token: opts.refreshToken,\n };\n const scope = normalizeScope(opts.scope);\n if (scope !== undefined) body.scope = scope;\n return this.token(body);\n }\n\n /**\n * Revoke an access or refresh token (RFC 7009). The server always\n * returns 200, even for unknown tokens. Revoking a **refresh**\n * token kills the refresh and every live access token tied to its\n * grant; revoking an **access** token kills only that one.\n */\n async revoke(opts: RevokeOptions): Promise<void> {\n if (!opts.token) {\n throw new MantyxError(\"`token` is required for MantyxOAuthClient.revoke\");\n }\n await this.formPost(\"/api/oauth/revoke\", {\n token: opts.token,\n });\n }\n\n /**\n * Build a long-lived {@link TokenSource} that re-mints access\n * tokens from the supplied refresh token. Pass the returned source\n * to `new MantyxClient({ tokenSource, workspaceSlug, ... })`. The\n * source caches the access token in-memory and refreshes\n * proactively when the cached value is within `refreshSkewMs` of\n * `expiresAt`, or eagerly when `MantyxClient` reports a 401.\n *\n * Pass `initialToken` if the calling app already has a non-expired\n * access token in hand (e.g. straight out of the sign-in flow) to\n * avoid an extra round-trip on the first request.\n */\n refreshTokenSource(opts: RefreshTokenSourceOptions): TokenSource {\n if (!opts.refreshToken) {\n throw new MantyxError(\"`refreshToken` is required for MantyxOAuthClient.refreshTokenSource\");\n }\n const skew = opts.refreshSkewMs ?? DEFAULT_REFRESH_SKEW_MS;\n const cache: TokenCache = { token: opts.initialToken, inflight: null };\n const refreshToken = opts.refreshToken;\n return makeTokenSource(cache, skew, async () => {\n return this.refresh({ refreshToken, scope: opts.scope });\n });\n }\n\n // -------------------------------------------------------------- internals\n\n /**\n * POST `application/x-www-form-urlencoded` to `/api/oauth/token` and\n * decode the {@link OAuthToken} response. Always injects `client_id`\n * + `client_secret` from the constructor.\n */\n private async token(body: Record<string, string>): Promise<OAuthToken> {\n const res = await this.formPost(\"/api/oauth/token\", body);\n let parsed: Record<string, unknown> = {};\n try {\n parsed = (await res.json()) as Record<string, unknown>;\n } catch {\n throw new MantyxOAuthError(\n \"invalid_response\",\n \"Token endpoint returned a non-JSON response\",\n res.status,\n );\n }\n const accessToken = typeof parsed.access_token === \"string\" ? parsed.access_token : \"\";\n if (!accessToken) {\n throw new MantyxOAuthError(\n \"invalid_response\",\n \"Token endpoint response is missing `access_token`\",\n res.status,\n );\n }\n const expiresIn = typeof parsed.expires_in === \"number\" ? parsed.expires_in : 3600;\n return {\n accessToken,\n refreshToken: typeof parsed.refresh_token === \"string\" ? parsed.refresh_token : undefined,\n tokenType: typeof parsed.token_type === \"string\" ? parsed.token_type : \"Bearer\",\n expiresIn,\n expiresAt: Date.now() + expiresIn * 1000,\n scope: typeof parsed.scope === \"string\" ? parsed.scope : undefined,\n };\n }\n\n private async formPost(path: string, body: Record<string, string>): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n const params = new URLSearchParams({\n ...body,\n client_id: this.clientId,\n client_secret: this.clientSecret,\n });\n const ctrl = new AbortController();\n const t = setTimeout(() => ctrl.abort(), this.timeoutMs);\n let res: Response;\n try {\n res = await this.fetchImpl(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body: params.toString(),\n signal: ctrl.signal,\n });\n } catch (err) {\n if (ctrl.signal.aborted) {\n throw new MantyxNetworkError(`OAuth request timed out after ${this.timeoutMs}ms`);\n }\n throw new MantyxNetworkError(`OAuth network error: ${(err as Error).message}`, {\n cause: err,\n });\n } finally {\n clearTimeout(t);\n }\n if (!res.ok) {\n let errBody: { error?: unknown; error_description?: unknown } = {};\n try {\n errBody = (await res.json()) as typeof errBody;\n } catch {\n // ignore\n }\n const oauthError = typeof errBody.error === \"string\" ? errBody.error : `http_${res.status}`;\n const desc =\n typeof errBody.error_description === \"string\" ? errBody.error_description : undefined;\n throw new MantyxOAuthError(oauthError, desc, res.status);\n }\n return res;\n }\n}\n\n// -------------------------------------------------------------- internals\n\ninterface TokenCache {\n token: OAuthToken | undefined;\n inflight: Promise<OAuthToken> | null;\n}\n\n/**\n * Wrap a `mintToken` thunk into a single-flight {@link TokenSource}\n * with a cache + proactive-refresh skew. The cache is overwritten\n * atomically on every successful mint; the in-flight promise\n * collapses N concurrent expired-token observers into one mint call.\n *\n * Single-flight is an efficiency, not a correctness requirement —\n * `docs/oauth.md` explicitly allows multiple concurrent refreshes\n * against the same refresh token — but it keeps the token-endpoint\n * QPS reasonable when an SDK consumer fans out work in parallel.\n */\nfunction makeTokenSource(\n cache: TokenCache,\n skewMs: number,\n mint: () => Promise<OAuthToken>,\n): TokenSource {\n return async (reason: TokenRequestReason = \"initial\"): Promise<string> => {\n if (reason !== \"unauthorized\" && cache.token && !isExpiring(cache.token, skewMs)) {\n return cache.token.accessToken;\n }\n if (cache.inflight) {\n const t = await cache.inflight;\n if (reason === \"unauthorized\" && t === cache.token) {\n // If the inflight refresh was triggered by a benign cache miss\n // and we observed an unauthorized hint after it started, fall\n // through and mint again so the caller never gets a stale token.\n } else {\n return t.accessToken;\n }\n }\n cache.inflight = mint().then(\n (t) => {\n cache.token = t;\n return t;\n },\n (err: unknown) => {\n throw err;\n },\n );\n try {\n const t = await cache.inflight;\n return t.accessToken;\n } finally {\n cache.inflight = null;\n }\n };\n}\n\nfunction isExpiring(token: OAuthToken, skewMs: number): boolean {\n return token.expiresAt - Date.now() <= skewMs;\n}\n\nfunction normalizeScope(scope: string | readonly string[] | undefined): string | undefined {\n if (scope === undefined) return undefined;\n if (typeof scope === \"string\") {\n const trimmed = scope.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n const joined = scope.filter((s) => typeof s === \"string\" && s.length > 0).join(\" \");\n return joined.length > 0 ? joined : undefined;\n}\n","/**\n * Release version — synced from repo root VERSION (`npm run sync-version`).\n */\nexport const SDK_VERSION = \"0.10.1\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BO,IAAM,yBAAyB;AAG/B,IAAM,0BAA0B;AAchC,IAAM,mBAAN,cAA+B,YAAY;AAAA,EACvC;AAAA,EACA;AAAA,EAET,YACE,YACA,uBACA,QACA;AACA,UAAM,UAAU,wBACZ,SAAS,UAAU,KAAK,qBAAqB,KAC7C,SAAS,UAAU;AACvB,UAAM,SAAS,EAAE,MAAM,YAAY,OAAO,CAAC;AAC3C,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,wBAAwB;AAAA,EAC/B;AACF;AA0GO,IAAM,oBAAN,MAAwB;AAAA,EACpB;AAAA,EACA;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,MAAgC;AAC1C,QAAI,CAAC,KAAK,UAAU;AAClB,YAAM,IAAI,YAAY,8CAA8C;AAAA,IACtE;AACA,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,IAAI,YAAY,kDAAkD;AAAA,IAC1E;AACA,UAAM,IAAI,KAAK,SAAS,WAAW;AACnC,QAAI,OAAO,MAAM,YAAY;AAC3B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,SAAK,WAAW,KAAK;AACrB,SAAK,eAAe,KAAK;AACzB,SAAK,WAAW,KAAK,WAAW,wBAAwB,QAAQ,QAAQ,EAAE;AAC1E,SAAK,YAAY;AACjB,SAAK,YAAY,KAAK,aAAa;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,QAAQ,MAA2C;AACvD,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,IAAI,YAAY,0DAA0D;AAAA,IAClF;AACA,UAAM,OAA+B;AAAA,MACnC,YAAY;AAAA,MACZ,eAAe,KAAK;AAAA,IACtB;AACA,UAAM,QAAQ,eAAe,KAAK,KAAK;AACvC,QAAI,UAAU,OAAW,MAAK,QAAQ;AACtC,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAO,MAAoC;AAC/C,QAAI,CAAC,KAAK,OAAO;AACf,YAAM,IAAI,YAAY,kDAAkD;AAAA,IAC1E;AACA,UAAM,KAAK,SAAS,qBAAqB;AAAA,MACvC,OAAO,KAAK;AAAA,IACd,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,mBAAmB,MAA8C;AAC/D,QAAI,CAAC,KAAK,cAAc;AACtB,YAAM,IAAI,YAAY,qEAAqE;AAAA,IAC7F;AACA,UAAM,OAAO,KAAK,iBAAiB;AACnC,UAAM,QAAoB,EAAE,OAAO,KAAK,cAAc,UAAU,KAAK;AACrE,UAAM,eAAe,KAAK;AAC1B,WAAO,gBAAgB,OAAO,MAAM,YAAY;AAC9C,aAAO,KAAK,QAAQ,EAAE,cAAc,OAAO,KAAK,MAAM,CAAC;AAAA,IACzD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,MAAM,MAAmD;AACrE,UAAM,MAAM,MAAM,KAAK,SAAS,oBAAoB,IAAI;AACxD,QAAI,SAAkC,CAAC;AACvC,QAAI;AACF,eAAU,MAAM,IAAI,KAAK;AAAA,IAC3B,QAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA,IAAI;AAAA,MACN;AAAA,IACF;AACA,UAAM,cAAc,OAAO,OAAO,iBAAiB,WAAW,OAAO,eAAe;AACpF,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA,IAAI;AAAA,MACN;AAAA,IACF;AACA,UAAM,YAAY,OAAO,OAAO,eAAe,WAAW,OAAO,aAAa;AAC9E,WAAO;AAAA,MACL;AAAA,MACA,cAAc,OAAO,OAAO,kBAAkB,WAAW,OAAO,gBAAgB;AAAA,MAChF,WAAW,OAAO,OAAO,eAAe,WAAW,OAAO,aAAa;AAAA,MACvE;AAAA,MACA,WAAW,KAAK,IAAI,IAAI,YAAY;AAAA,MACpC,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAc,SAAS,MAAc,MAAiD;AACpF,UAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI;AAClC,UAAM,SAAS,IAAI,gBAAgB;AAAA,MACjC,GAAG;AAAA,MACH,WAAW,KAAK;AAAA,MAChB,eAAe,KAAK;AAAA,IACtB,CAAC;AACD,UAAM,OAAO,IAAI,gBAAgB;AACjC,UAAM,IAAI,WAAW,MAAM,KAAK,MAAM,GAAG,KAAK,SAAS;AACvD,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,KAAK,UAAU,KAAK;AAAA,QAC9B,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,QACV;AAAA,QACA,MAAM,OAAO,SAAS;AAAA,QACtB,QAAQ,KAAK;AAAA,MACf,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,UAAI,KAAK,OAAO,SAAS;AACvB,cAAM,IAAI,mBAAmB,iCAAiC,KAAK,SAAS,IAAI;AAAA,MAClF;AACA,YAAM,IAAI,mBAAmB,wBAAyB,IAAc,OAAO,IAAI;AAAA,QAC7E,OAAO;AAAA,MACT,CAAC;AAAA,IACH,UAAE;AACA,mBAAa,CAAC;AAAA,IAChB;AACA,QAAI,CAAC,IAAI,IAAI;AACX,UAAI,UAA4D,CAAC;AACjE,UAAI;AACF,kBAAW,MAAM,IAAI,KAAK;AAAA,MAC5B,QAAQ;AAAA,MAER;AACA,YAAM,aAAa,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,QAAQ,IAAI,MAAM;AACzF,YAAM,OACJ,OAAO,QAAQ,sBAAsB,WAAW,QAAQ,oBAAoB;AAC9E,YAAM,IAAI,iBAAiB,YAAY,MAAM,IAAI,MAAM;AAAA,IACzD;AACA,WAAO;AAAA,EACT;AACF;AAoBA,SAAS,gBACP,OACA,QACA,MACa;AACb,SAAO,OAAO,SAA6B,cAA+B;AACxE,QAAI,WAAW,kBAAkB,MAAM,SAAS,CAAC,WAAW,MAAM,OAAO,MAAM,GAAG;AAChF,aAAO,MAAM,MAAM;AAAA,IACrB;AACA,QAAI,MAAM,UAAU;AAClB,YAAM,IAAI,MAAM,MAAM;AACtB,UAAI,WAAW,kBAAkB,MAAM,MAAM,OAAO;AAAA,MAIpD,OAAO;AACL,eAAO,EAAE;AAAA,MACX;AAAA,IACF;AACA,UAAM,WAAW,KAAK,EAAE;AAAA,MACtB,CAAC,MAAM;AACL,cAAM,QAAQ;AACd,eAAO;AAAA,MACT;AAAA,MACA,CAAC,QAAiB;AAChB,cAAM;AAAA,MACR;AAAA,IACF;AACA,QAAI;AACF,YAAM,IAAI,MAAM,MAAM;AACtB,aAAO,EAAE;AAAA,IACX,UAAE;AACA,YAAM,WAAW;AAAA,IACnB;AAAA,EACF;AACF;AAEA,SAAS,WAAW,OAAmB,QAAyB;AAC9D,SAAO,MAAM,YAAY,KAAK,IAAI,KAAK;AACzC;AAEA,SAAS,eAAe,OAAmE;AACzF,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,MAAM,KAAK;AAC3B,WAAO,QAAQ,SAAS,IAAI,UAAU;AAAA,EACxC;AACA,QAAM,SAAS,MAAM,OAAO,CAAC,MAAM,OAAO,MAAM,YAAY,EAAE,SAAS,CAAC,EAAE,KAAK,GAAG;AAClF,SAAO,OAAO,SAAS,IAAI,SAAS;AACtC;;;ACpZO,IAAM,cAAc;","names":[]}
|