@mdxui/do 2.1.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/README.md +412 -0
- package/dist/__test-utils__/index.d.ts +399 -0
- package/dist/__test-utils__/index.js +34641 -0
- package/dist/__test-utils__/index.js.map +1 -0
- package/dist/agents-xcIn2dUB.d.ts +832 -0
- package/dist/chunk-EEDMN7UF.js +1351 -0
- package/dist/chunk-EEDMN7UF.js.map +1 -0
- package/dist/chunk-G3PMV62Z.js +33 -0
- package/dist/chunk-G3PMV62Z.js.map +1 -0
- package/dist/chunk-GGO5GW72.js +695 -0
- package/dist/chunk-GGO5GW72.js.map +1 -0
- package/dist/chunk-GKSP5RIA.js +3 -0
- package/dist/chunk-GKSP5RIA.js.map +1 -0
- package/dist/chunk-NXPXL5NA.js +3789 -0
- package/dist/chunk-NXPXL5NA.js.map +1 -0
- package/dist/chunk-PC5FJY6M.js +20 -0
- package/dist/chunk-PC5FJY6M.js.map +1 -0
- package/dist/chunk-XF6LKY2M.js +445 -0
- package/dist/chunk-XF6LKY2M.js.map +1 -0
- package/dist/components/index.d.ts +813 -0
- package/dist/components/index.js +8 -0
- package/dist/components/index.js.map +1 -0
- package/dist/do-CaQVueZw.d.ts +195 -0
- package/dist/hooks/index.d.ts +801 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +1012 -0
- package/dist/index.js +843 -0
- package/dist/index.js.map +1 -0
- package/dist/magic-string.es-J7BYFTTJ.js +1307 -0
- package/dist/magic-string.es-J7BYFTTJ.js.map +1 -0
- package/dist/providers/index.d.ts +90 -0
- package/dist/providers/index.js +5 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/schemas/index.d.ts +206 -0
- package/dist/schemas/index.js +262 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/thing-DtI25yZh.d.ts +902 -0
- package/dist/types/index.d.ts +7681 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +94 -0
package/README.md
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
# @mdxui/do
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@mdxui/do)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Admin interface for the .do platform - manage Durable Objects, Things, Relationships, Workflows, Agents, and Integrations.
|
|
7
|
+
|
|
8
|
+
## What is @mdxui/do?
|
|
9
|
+
|
|
10
|
+
`@mdxui/do` provides a React-based admin interface for the [.do platform](https://do.md). It enables you to manage semantic entities (Things), graph relationships, business process workflows, and autonomous AI agents. Built on TanStack Query, the library supports two operational modes: traditional REST API fetching or local-first reactive data with TanStack DB and WebSocket sync.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @mdxui/do
|
|
16
|
+
# or
|
|
17
|
+
pnpm add @mdxui/do
|
|
18
|
+
# or
|
|
19
|
+
yarn add @mdxui/do
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Peer Dependencies
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install react react-dom
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
Wrap your application with `DOProvider` and start using hooks to fetch and mutate data:
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { DOProvider, useThings, useCreateThing } from '@mdxui/do'
|
|
34
|
+
|
|
35
|
+
function App() {
|
|
36
|
+
return (
|
|
37
|
+
<DOProvider
|
|
38
|
+
config={{
|
|
39
|
+
apiEndpoint: 'https://api.example.do/admin',
|
|
40
|
+
doUrl: 'wss://api.example.do/do/workspace',
|
|
41
|
+
authMethod: 'jwt',
|
|
42
|
+
authToken: 'your-token',
|
|
43
|
+
bindings: [],
|
|
44
|
+
realTimeUpdates: true,
|
|
45
|
+
collections: ['Task', 'User', 'Project'],
|
|
46
|
+
}}
|
|
47
|
+
initialNamespace="default"
|
|
48
|
+
>
|
|
49
|
+
<TaskList />
|
|
50
|
+
</DOProvider>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function TaskList() {
|
|
55
|
+
const { data, isLoading, error } = useThings({ type: 'Task' })
|
|
56
|
+
const createThing = useCreateThing()
|
|
57
|
+
|
|
58
|
+
if (isLoading) return <div>Loading...</div>
|
|
59
|
+
if (error) return <div>Error: {error.message}</div>
|
|
60
|
+
|
|
61
|
+
const handleCreate = () => {
|
|
62
|
+
createThing.mutate({
|
|
63
|
+
ns: 'default',
|
|
64
|
+
type: 'Task',
|
|
65
|
+
name: 'New Task',
|
|
66
|
+
data: { status: 'todo', priority: 'medium' },
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<div>
|
|
72
|
+
<button onClick={handleCreate} disabled={createThing.isLoading}>
|
|
73
|
+
Add Task
|
|
74
|
+
</button>
|
|
75
|
+
<ul>
|
|
76
|
+
{data?.data.map((task) => (
|
|
77
|
+
<li key={task.id}>{task.name}</li>
|
|
78
|
+
))}
|
|
79
|
+
</ul>
|
|
80
|
+
</div>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Core Concepts
|
|
86
|
+
|
|
87
|
+
### Things
|
|
88
|
+
|
|
89
|
+
Things are semantic entities (nouns) that form the foundation of your data model. Each Thing has:
|
|
90
|
+
|
|
91
|
+
- **Namespace (`ns`)**: Tenant or domain isolation (e.g., `"default"`, `"production"`)
|
|
92
|
+
- **Type**: Entity classification (e.g., `"Task"`, `"User"`, `"Project"`)
|
|
93
|
+
- **ID**: Unique identifier within namespace/type
|
|
94
|
+
- **Data**: JSON-LD compatible payload with flexible schema
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
const { data } = useThings({ type: 'Task', nameSearch: 'urgent' })
|
|
98
|
+
const { data: task } = useThing('default', 'Task', 'task-123')
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Relationships
|
|
102
|
+
|
|
103
|
+
Relationships form a semantic knowledge graph connecting Things using 64+ built-in predicates across temporal, spatial, directional, relational, and causal categories.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
// Fetch relationships for an entity
|
|
107
|
+
const { data } = useEntityRelationships(
|
|
108
|
+
{ ns: 'default', type: 'Task', id: 'task-1', semanticId: 'default/Task/task-1' },
|
|
109
|
+
'both'
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
// Create a relationship
|
|
113
|
+
const createRelationship = useCreateRelationship()
|
|
114
|
+
createRelationship.mutate({
|
|
115
|
+
relationshipType: 'dependsOn',
|
|
116
|
+
from: { ns: 'default', type: 'Task', id: 'task-2', semanticId: 'default/Task/task-2' },
|
|
117
|
+
to: { ns: 'default', type: 'Task', id: 'task-1', semanticId: 'default/Task/task-1' },
|
|
118
|
+
})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Workflows
|
|
122
|
+
|
|
123
|
+
Workflows orchestrate multi-step business processes with support for:
|
|
124
|
+
|
|
125
|
+
- Event, schedule, manual, or webhook triggers
|
|
126
|
+
- Function steps (Code, Generative, Agentic, Human)
|
|
127
|
+
- Conditional branching and parallel execution
|
|
128
|
+
- Saga pattern for compensation/rollback
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
const { data: workflows } = useWorkflows({ status: ['active'] })
|
|
132
|
+
const triggerWorkflow = useTriggerWorkflow('workflow-id')
|
|
133
|
+
|
|
134
|
+
// Trigger with input
|
|
135
|
+
triggerWorkflow.mutate({ customerId: 'cust-123' })
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Agents
|
|
139
|
+
|
|
140
|
+
Agents are autonomous AI workers derived from O*NET occupations and NAICS industries, creating 40,000+ potential agent types. They include:
|
|
141
|
+
|
|
142
|
+
- System prompts and character bibles for persona
|
|
143
|
+
- Tool access and guardrails for safety
|
|
144
|
+
- Handoff rules for multi-agent coordination
|
|
145
|
+
- Performance metrics and feedback collection
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
const { data: agents } = useAgents({ roleCategory: ['engineer'], status: ['active'] })
|
|
149
|
+
const executeAgent = useExecuteAgent('agent-id')
|
|
150
|
+
|
|
151
|
+
executeAgent.mutate({
|
|
152
|
+
task: 'Review this pull request for security issues',
|
|
153
|
+
context: { prUrl: 'https://github.com/...' },
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Dual Mode Operation
|
|
158
|
+
|
|
159
|
+
`@mdxui/do` supports two operational modes depending on your configuration:
|
|
160
|
+
|
|
161
|
+
| Mode | Configuration | Use Case | Features |
|
|
162
|
+
|------|---------------|----------|----------|
|
|
163
|
+
| **REST API** | `apiEndpoint` only | Traditional server-rendered apps | Standard fetch, server-side caching |
|
|
164
|
+
| **TanStack DB** | `apiEndpoint` + `doUrl` | Real-time collaborative apps | Local-first, WebSocket sync, offline support |
|
|
165
|
+
|
|
166
|
+
### REST API Mode
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
<DOProvider
|
|
170
|
+
config={{
|
|
171
|
+
apiEndpoint: 'https://api.example.do/admin',
|
|
172
|
+
authMethod: 'jwt',
|
|
173
|
+
authToken: 'your-token',
|
|
174
|
+
bindings: [],
|
|
175
|
+
realTimeUpdates: false,
|
|
176
|
+
}}
|
|
177
|
+
>
|
|
178
|
+
{children}
|
|
179
|
+
</DOProvider>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### TanStack DB Mode (Recommended)
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
<DOProvider
|
|
186
|
+
config={{
|
|
187
|
+
apiEndpoint: 'https://api.example.do/admin',
|
|
188
|
+
doUrl: 'wss://api.example.do/do/workspace',
|
|
189
|
+
authMethod: 'jwt',
|
|
190
|
+
authToken: 'your-token',
|
|
191
|
+
bindings: [],
|
|
192
|
+
realTimeUpdates: true,
|
|
193
|
+
collections: ['Task', 'User', 'Project'],
|
|
194
|
+
conflictStrategy: 'last-write-wins',
|
|
195
|
+
offline: { enabled: true, dbName: 'my-app-cache' },
|
|
196
|
+
}}
|
|
197
|
+
>
|
|
198
|
+
{children}
|
|
199
|
+
</DOProvider>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Configuration
|
|
203
|
+
|
|
204
|
+
### DOAdminConfig
|
|
205
|
+
|
|
206
|
+
| Property | Type | Required | Default | Description |
|
|
207
|
+
|----------|------|----------|---------|-------------|
|
|
208
|
+
| `apiEndpoint` | `string` | Yes | - | Base URL for REST API calls |
|
|
209
|
+
| `doUrl` | `string` | No | - | WebSocket URL for Durable Object sync (enables TanStack DB mode) |
|
|
210
|
+
| `authMethod` | `'jwt' \| 'api-key' \| 'oauth'` | Yes | - | Authentication method |
|
|
211
|
+
| `authToken` | `string` | No | - | JWT token or API key |
|
|
212
|
+
| `bindings` | `DOBinding[]` | Yes | - | Available Durable Object bindings |
|
|
213
|
+
| `realTimeUpdates` | `boolean` | Yes | - | Enable real-time data updates |
|
|
214
|
+
| `wsEndpoint` | `string` | No | - | Legacy WebSocket endpoint (prefer `doUrl`) |
|
|
215
|
+
| `conflictStrategy` | `'last-write-wins' \| 'merge' \| ConflictResolver` | No | `'last-write-wins'` | How to resolve sync conflicts |
|
|
216
|
+
| `offline` | `OfflineConfig` | No | - | Offline persistence settings |
|
|
217
|
+
| `collections` | `string[]` | No | - | Entity types to auto-sync |
|
|
218
|
+
|
|
219
|
+
### DOProviderProps
|
|
220
|
+
|
|
221
|
+
| Property | Type | Required | Default | Description |
|
|
222
|
+
|----------|------|----------|---------|-------------|
|
|
223
|
+
| `config` | `DOAdminConfig` | Yes | - | Admin configuration |
|
|
224
|
+
| `initialNamespace` | `string` | No | `'default'` | Starting namespace |
|
|
225
|
+
| `userId` | `string` | No | - | Current user ID |
|
|
226
|
+
| `children` | `ReactNode` | Yes | - | Child components |
|
|
227
|
+
| `queryClient` | `QueryClient` | No | - | Custom TanStack Query client |
|
|
228
|
+
|
|
229
|
+
## Available Hooks
|
|
230
|
+
|
|
231
|
+
### Context Hooks
|
|
232
|
+
|
|
233
|
+
| Hook | Description |
|
|
234
|
+
|------|-------------|
|
|
235
|
+
| `useDO()` | Access the DO context (config, namespace, connection status) |
|
|
236
|
+
| `useDOUrls()` | Get derived URLs (rpcUrl, syncUrl, apiEndpoint) |
|
|
237
|
+
| `useSyncStatus()` | Get current sync status (`'disconnected'`, `'connecting'`, `'syncing'`, `'synced'`, `'error'`) |
|
|
238
|
+
|
|
239
|
+
### Things Hooks
|
|
240
|
+
|
|
241
|
+
| Hook | Description |
|
|
242
|
+
|------|-------------|
|
|
243
|
+
| `useThings(filter?, sort?, pagination?)` | Fetch a paginated list of Things |
|
|
244
|
+
| `useThing(ns, type, id)` | Fetch a single Thing by semantic ID |
|
|
245
|
+
| `useThingVersions(ns, type, id)` | Fetch version history for a Thing |
|
|
246
|
+
| `useTypeStats(ns, type)` | Fetch statistics for a Thing type |
|
|
247
|
+
| `useCreateThing()` | Create a new Thing |
|
|
248
|
+
| `useUpdateThing(ns, type, id)` | Update an existing Thing |
|
|
249
|
+
| `useDeleteThing(ns, type, id)` | Soft or hard delete a Thing |
|
|
250
|
+
|
|
251
|
+
### Relationships Hooks
|
|
252
|
+
|
|
253
|
+
| Hook | Description |
|
|
254
|
+
|------|-------------|
|
|
255
|
+
| `useRelationships(filter?)` | Fetch relationships with optional filters |
|
|
256
|
+
| `useEntityRelationships(entity, direction?)` | Fetch relationships for a specific entity |
|
|
257
|
+
| `useGraphTraversal(entity, pattern)` | Traverse the graph from a starting entity |
|
|
258
|
+
| `useGraphStats()` | Fetch graph statistics |
|
|
259
|
+
| `useCreateRelationship()` | Create a new relationship |
|
|
260
|
+
| `useDeleteRelationship()` | Delete a relationship |
|
|
261
|
+
|
|
262
|
+
### Workflows Hooks
|
|
263
|
+
|
|
264
|
+
| Hook | Description |
|
|
265
|
+
|------|-------------|
|
|
266
|
+
| `useWorkflows(filter?)` | Fetch workflows with optional filters |
|
|
267
|
+
| `useWorkflow(id)` | Fetch a single workflow |
|
|
268
|
+
| `useWorkflowExecutions(filter?)` | Fetch workflow executions |
|
|
269
|
+
| `useWorkflowExecution(id)` | Fetch a single execution (auto-refetch while running) |
|
|
270
|
+
| `useCreateWorkflow()` | Create a new workflow |
|
|
271
|
+
| `useUpdateWorkflow(id)` | Update an existing workflow |
|
|
272
|
+
| `useTriggerWorkflow(id)` | Manually trigger a workflow |
|
|
273
|
+
| `useCancelExecution()` | Cancel a running execution |
|
|
274
|
+
| `useDeleteWorkflow()` | Delete a workflow |
|
|
275
|
+
|
|
276
|
+
### Agents Hooks
|
|
277
|
+
|
|
278
|
+
| Hook | Description |
|
|
279
|
+
|------|-------------|
|
|
280
|
+
| `useAgents(filter?)` | Fetch agents with optional filters |
|
|
281
|
+
| `useAgent(id)` | Fetch a single agent |
|
|
282
|
+
| `useAgentMetrics(id, periodDays?)` | Fetch performance metrics for an agent |
|
|
283
|
+
| `useAgentExecutions(filter?)` | Fetch agent executions |
|
|
284
|
+
| `useAgentExecution(id)` | Fetch a single execution (auto-refetch while running) |
|
|
285
|
+
| `useCreateAgent()` | Create a new agent |
|
|
286
|
+
| `useUpdateAgent(id)` | Update an existing agent |
|
|
287
|
+
| `useExecuteAgent(id)` | Execute an agent with a task |
|
|
288
|
+
| `useSubmitAgentFeedback(executionId)` | Submit feedback for an execution |
|
|
289
|
+
| `useDeleteAgent()` | Delete an agent |
|
|
290
|
+
|
|
291
|
+
## Query Keys
|
|
292
|
+
|
|
293
|
+
Each hook module exports query key factories for cache management:
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
import { thingsKeys, relationshipsKeys, workflowsKeys, agentsKeys } from '@mdxui/do/hooks'
|
|
297
|
+
import { useQueryClient } from '@tanstack/react-query'
|
|
298
|
+
|
|
299
|
+
const queryClient = useQueryClient()
|
|
300
|
+
|
|
301
|
+
// Invalidate all things queries
|
|
302
|
+
queryClient.invalidateQueries({ queryKey: thingsKeys.all })
|
|
303
|
+
|
|
304
|
+
// Invalidate a specific thing
|
|
305
|
+
queryClient.invalidateQueries({ queryKey: thingsKeys.detail('default', 'Task', 'task-1') })
|
|
306
|
+
|
|
307
|
+
// Invalidate all workflow executions
|
|
308
|
+
queryClient.invalidateQueries({ queryKey: workflowsKeys.executions() })
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Components
|
|
312
|
+
|
|
313
|
+
The package includes pre-built UI components:
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
import { DOShell, DOSidebar, DOHeader, ThingsList, StatsCards, ErrorBoundary } from '@mdxui/do/components'
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
| Component | Description |
|
|
320
|
+
|-----------|-------------|
|
|
321
|
+
| `DOShell` | Main application shell with sidebar and header |
|
|
322
|
+
| `DOSidebar` | Navigation sidebar with customizable items |
|
|
323
|
+
| `DOHeader` | Application header with namespace selector |
|
|
324
|
+
| `ThingsList` | Data table for displaying Things |
|
|
325
|
+
| `StatsCards` | Dashboard statistics cards |
|
|
326
|
+
| `ErrorBoundary` | Error boundary with fallback UI |
|
|
327
|
+
|
|
328
|
+
## Types
|
|
329
|
+
|
|
330
|
+
Import types for TypeScript projects:
|
|
331
|
+
|
|
332
|
+
```tsx
|
|
333
|
+
import type {
|
|
334
|
+
// Things
|
|
335
|
+
Thing,
|
|
336
|
+
ThingFilter,
|
|
337
|
+
ThingCreateInput,
|
|
338
|
+
ThingUpdateInput,
|
|
339
|
+
ThingQueryResult,
|
|
340
|
+
|
|
341
|
+
// Relationships
|
|
342
|
+
Relationship,
|
|
343
|
+
SemanticPredicate,
|
|
344
|
+
EntityReference,
|
|
345
|
+
GraphTraversalResult,
|
|
346
|
+
|
|
347
|
+
// Workflows
|
|
348
|
+
Workflow,
|
|
349
|
+
WorkflowExecution,
|
|
350
|
+
WorkflowStep,
|
|
351
|
+
|
|
352
|
+
// Agents
|
|
353
|
+
Agent,
|
|
354
|
+
AgentExecution,
|
|
355
|
+
AgentMetrics,
|
|
356
|
+
|
|
357
|
+
// Config
|
|
358
|
+
DOAdminConfig,
|
|
359
|
+
DOBinding,
|
|
360
|
+
SyncStatus,
|
|
361
|
+
} from '@mdxui/do/types'
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Subpath Exports
|
|
365
|
+
|
|
366
|
+
The package provides granular imports for tree-shaking:
|
|
367
|
+
|
|
368
|
+
```tsx
|
|
369
|
+
// Full package
|
|
370
|
+
import { DOProvider, useThings, Thing } from '@mdxui/do'
|
|
371
|
+
|
|
372
|
+
// Just providers
|
|
373
|
+
import { DOProvider, useDO } from '@mdxui/do/providers'
|
|
374
|
+
|
|
375
|
+
// Just hooks
|
|
376
|
+
import { useThings, useAgents } from '@mdxui/do/hooks'
|
|
377
|
+
|
|
378
|
+
// Just components
|
|
379
|
+
import { DOShell, ThingsList } from '@mdxui/do/components'
|
|
380
|
+
|
|
381
|
+
// Just types
|
|
382
|
+
import type { Thing, Agent } from '@mdxui/do/types'
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Error Handling
|
|
386
|
+
|
|
387
|
+
The package provides type guards for handling API errors:
|
|
388
|
+
|
|
389
|
+
```tsx
|
|
390
|
+
import { isValidationErrorData, isNotFoundError, isRateLimitError, isAppError } from '@mdxui/do/types'
|
|
391
|
+
|
|
392
|
+
try {
|
|
393
|
+
await createThing.mutateAsync({ /* ... */ })
|
|
394
|
+
} catch (error) {
|
|
395
|
+
if (isAppError(error)) {
|
|
396
|
+
if (isValidationErrorData(error)) {
|
|
397
|
+
// Handle validation errors (API response data)
|
|
398
|
+
error.errors.forEach(e => console.log(e.field, e.message))
|
|
399
|
+
} else if (isNotFoundError(error)) {
|
|
400
|
+
// Handle not found
|
|
401
|
+
console.log(`${error.resourceType}/${error.resourceId} not found`)
|
|
402
|
+
} else if (isRateLimitError(error)) {
|
|
403
|
+
// Handle rate limiting
|
|
404
|
+
console.log(`Retry after ${error.retryAfter}ms`)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## License
|
|
411
|
+
|
|
412
|
+
MIT
|