@aigne/afs-mapping 1.11.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +26 -0
- package/README.md +286 -0
- package/dist/index.d.mts +3186 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +828 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +57 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2025 ArcBlock, Inc. All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are proprietary
|
|
6
|
+
and confidential. Unauthorized copying, modification, distribution, or use of
|
|
7
|
+
this Software, via any medium, is strictly prohibited.
|
|
8
|
+
|
|
9
|
+
The Software is provided for internal use only within ArcBlock, Inc. and its
|
|
10
|
+
authorized affiliates.
|
|
11
|
+
|
|
12
|
+
## No License Granted
|
|
13
|
+
|
|
14
|
+
No license, express or implied, is granted to any party for any purpose.
|
|
15
|
+
All rights are reserved by ArcBlock, Inc.
|
|
16
|
+
|
|
17
|
+
## Public Artifact Distribution
|
|
18
|
+
|
|
19
|
+
Portions of this Software may be released publicly under separate open-source
|
|
20
|
+
licenses (such as MIT License) through designated public repositories. Such
|
|
21
|
+
public releases are governed by their respective licenses and do not affect
|
|
22
|
+
the proprietary nature of this repository.
|
|
23
|
+
|
|
24
|
+
## Contact
|
|
25
|
+
|
|
26
|
+
For licensing inquiries, contact: legal@arcblock.io
|
package/README.md
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# @aigne/afs-mapping
|
|
2
|
+
|
|
3
|
+
**@aigne/afs-mapping** is a DSL compiler for declarative path-to-API mapping. It converts YAML DSL definitions into compiled route matchers, enabling AFS providers to map virtual paths to external API calls.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
AFS Mapping provides the infrastructure for building AFS providers that interact with external APIs. It allows you to declaratively define how AFS paths map to API endpoints, how parameters are extracted and bound, and how API responses are transformed into AFS entries.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **YAML DSL**: Declarative mapping configuration in YAML format
|
|
12
|
+
- **Path Resolution**: Pattern-based route matching with parameter extraction
|
|
13
|
+
- **Expression Binding**: Flexible parameter binding with Jinja-like expressions
|
|
14
|
+
- **Response Projection**: Transform API responses into AFS entries
|
|
15
|
+
- **Multi-Operation Support**: Define list, read, write, create, and delete operations
|
|
16
|
+
- **Modular Configuration**: Split mappings across multiple files with includes
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @aigne/afs-mapping
|
|
22
|
+
# or
|
|
23
|
+
yarn add @aigne/afs-mapping
|
|
24
|
+
# or
|
|
25
|
+
pnpm add @aigne/afs-mapping
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { MappingCompiler } from "@aigne/afs-mapping";
|
|
32
|
+
|
|
33
|
+
// Compile a mapping configuration
|
|
34
|
+
const compiler = new MappingCompiler();
|
|
35
|
+
const compiled = await compiler.compileDirectory("/path/to/mapping/");
|
|
36
|
+
|
|
37
|
+
// Resolve a path to route information
|
|
38
|
+
const resolved = compiled.resolve("/aigne/afs/issues/123");
|
|
39
|
+
// => { template: "/{owner}/{repo}/issues/{number}", params: { owner: "aigne", repo: "afs", number: "123" }, ... }
|
|
40
|
+
|
|
41
|
+
// Build an HTTP request
|
|
42
|
+
const request = compiled.buildRequest("/aigne/afs/issues", "list", {
|
|
43
|
+
query: { state: "open" },
|
|
44
|
+
});
|
|
45
|
+
// => { method: "GET", path: "/repos/aigne/afs/issues", params: { state: "open", per_page: 30 }, ... }
|
|
46
|
+
|
|
47
|
+
// Project API response to AFS entries
|
|
48
|
+
const entries = compiled.projectResponse("/aigne/afs/issues", "list", apiResponse);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Mapping DSL
|
|
52
|
+
|
|
53
|
+
### Configuration Structure
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
# mapping.yml
|
|
57
|
+
name: github
|
|
58
|
+
version: "1.0"
|
|
59
|
+
description: GitHub API mapping
|
|
60
|
+
|
|
61
|
+
defaults:
|
|
62
|
+
baseUrl: https://api.github.com
|
|
63
|
+
headers:
|
|
64
|
+
Accept: application/vnd.github+json
|
|
65
|
+
|
|
66
|
+
routes:
|
|
67
|
+
"/{owner}/{repo}/issues":
|
|
68
|
+
list:
|
|
69
|
+
method: GET
|
|
70
|
+
path: /repos/{owner}/{repo}/issues
|
|
71
|
+
params:
|
|
72
|
+
owner: path.owner
|
|
73
|
+
repo: path.repo
|
|
74
|
+
state: query.state | default("open")
|
|
75
|
+
per_page: query.limit | default(30)
|
|
76
|
+
transform:
|
|
77
|
+
items: "$"
|
|
78
|
+
entry:
|
|
79
|
+
id: "$.number | string"
|
|
80
|
+
path: "/{owner}/{repo}/issues/{$.number}"
|
|
81
|
+
summary: "$.title"
|
|
82
|
+
content: "$.body"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Route Definition
|
|
86
|
+
|
|
87
|
+
Each route defines operations for a path pattern:
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
routes:
|
|
91
|
+
"/{owner}/{repo}/issues/{number}":
|
|
92
|
+
read:
|
|
93
|
+
method: GET
|
|
94
|
+
path: /repos/{owner}/{repo}/issues/{number}
|
|
95
|
+
params:
|
|
96
|
+
owner: path.owner
|
|
97
|
+
repo: path.repo
|
|
98
|
+
number: path.number
|
|
99
|
+
transform:
|
|
100
|
+
entry:
|
|
101
|
+
id: "$.number | string"
|
|
102
|
+
path: "/{owner}/{repo}/issues/{$.number}"
|
|
103
|
+
summary: "$.title"
|
|
104
|
+
content: "$.body"
|
|
105
|
+
metadata:
|
|
106
|
+
type: issue
|
|
107
|
+
state: "$.state"
|
|
108
|
+
author: "$.user.login"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Operations
|
|
112
|
+
|
|
113
|
+
Each route can define these operations:
|
|
114
|
+
|
|
115
|
+
- **list**: Returns multiple entries (GET)
|
|
116
|
+
- **read**: Returns a single entry (GET)
|
|
117
|
+
- **write**: Updates an existing entry (PUT/PATCH)
|
|
118
|
+
- **create**: Creates a new entry (POST)
|
|
119
|
+
- **delete**: Removes an entry (DELETE)
|
|
120
|
+
|
|
121
|
+
### Parameter Binding
|
|
122
|
+
|
|
123
|
+
Parameters can be bound from various sources:
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
params:
|
|
127
|
+
# From path parameters
|
|
128
|
+
owner: path.owner
|
|
129
|
+
|
|
130
|
+
# From query parameters with default
|
|
131
|
+
state: query.state | default("open")
|
|
132
|
+
|
|
133
|
+
# From request input
|
|
134
|
+
title: input.title
|
|
135
|
+
|
|
136
|
+
# Static values
|
|
137
|
+
per_page: "30"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Response Transform
|
|
141
|
+
|
|
142
|
+
Transform API responses into AFS entries:
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
transform:
|
|
146
|
+
# JSONPath to items array (for list operations)
|
|
147
|
+
items: "$.data"
|
|
148
|
+
|
|
149
|
+
# Entry mapping
|
|
150
|
+
entry:
|
|
151
|
+
id: "$.id | string"
|
|
152
|
+
path: "/items/{$.id}"
|
|
153
|
+
summary: "$.title"
|
|
154
|
+
content: "$.body"
|
|
155
|
+
description: "$.description"
|
|
156
|
+
metadata:
|
|
157
|
+
type: "$.type"
|
|
158
|
+
status: "$.status"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## API Reference
|
|
162
|
+
|
|
163
|
+
### MappingCompiler
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
const compiler = new MappingCompiler();
|
|
167
|
+
|
|
168
|
+
// Compile from a single file
|
|
169
|
+
const compiled = await compiler.compileFile("/path/to/mapping.yml");
|
|
170
|
+
|
|
171
|
+
// Compile from a directory (with includes)
|
|
172
|
+
const compiled = await compiler.compileDirectory("/path/to/mapping/");
|
|
173
|
+
|
|
174
|
+
// Compile from a config object (for testing)
|
|
175
|
+
const compiled = compiler.compileConfig(configObject);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### CompiledMapping
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
// Get mapping info
|
|
182
|
+
compiled.name; // Mapping name
|
|
183
|
+
compiled.version; // Version string
|
|
184
|
+
compiled.routeCount; // Number of routes
|
|
185
|
+
compiled.operationCount; // Total operations
|
|
186
|
+
|
|
187
|
+
// Resolve a path
|
|
188
|
+
const resolved = compiled.resolve("/owner/repo/issues/123");
|
|
189
|
+
// Returns: { template, params, operations }
|
|
190
|
+
|
|
191
|
+
// Build HTTP request
|
|
192
|
+
const request = compiled.buildRequest(path, operationType, { query, input });
|
|
193
|
+
// Returns: { method, path, params, headers, body }
|
|
194
|
+
|
|
195
|
+
// Project API response
|
|
196
|
+
const entries = compiled.projectResponse(path, operationType, apiResponse);
|
|
197
|
+
// Returns: AFSEntry[]
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### ResolvedRoute
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
interface ResolvedRoute {
|
|
204
|
+
template: string; // Original template
|
|
205
|
+
params: Record<string, string>; // Extracted parameters
|
|
206
|
+
operations: { // Available operations
|
|
207
|
+
list?: Operation;
|
|
208
|
+
read?: Operation;
|
|
209
|
+
write?: Operation;
|
|
210
|
+
create?: Operation;
|
|
211
|
+
delete?: Operation;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### HttpRequest
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
interface HttpRequest {
|
|
220
|
+
method: string; // HTTP method
|
|
221
|
+
path: string; // Request path (interpolated)
|
|
222
|
+
params: Record<string, unknown>; // Query/path parameters
|
|
223
|
+
headers?: Record<string, string>; // Request headers
|
|
224
|
+
body?: Record<string, unknown>; // Request body
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Creating a Provider with Mapping
|
|
229
|
+
|
|
230
|
+
Here's how to use AFS Mapping in a custom provider:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
import { AFSModule, AFSEntry } from "@aigne/afs";
|
|
234
|
+
import { MappingCompiler, CompiledMapping } from "@aigne/afs-mapping";
|
|
235
|
+
|
|
236
|
+
class MyAPIProvider implements AFSModule {
|
|
237
|
+
readonly name = "my-api";
|
|
238
|
+
private compiled: CompiledMapping;
|
|
239
|
+
|
|
240
|
+
constructor() {
|
|
241
|
+
const compiler = new MappingCompiler();
|
|
242
|
+
this.compiled = compiler.compileConfig({
|
|
243
|
+
name: "my-api",
|
|
244
|
+
version: "1.0",
|
|
245
|
+
routes: {
|
|
246
|
+
"/items": {
|
|
247
|
+
list: {
|
|
248
|
+
method: "GET",
|
|
249
|
+
path: "/api/items",
|
|
250
|
+
transform: {
|
|
251
|
+
items: "$",
|
|
252
|
+
entry: {
|
|
253
|
+
id: "$.id",
|
|
254
|
+
path: "/items/{$.id}",
|
|
255
|
+
summary: "$.name",
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async list(path: string): Promise<{ data: AFSEntry[] }> {
|
|
265
|
+
const request = this.compiled.buildRequest(path, "list", {});
|
|
266
|
+
if (!request) return { data: [] };
|
|
267
|
+
|
|
268
|
+
// Make API call
|
|
269
|
+
const response = await fetch(`https://api.example.com${request.path}`);
|
|
270
|
+
const data = await response.json();
|
|
271
|
+
|
|
272
|
+
// Transform response
|
|
273
|
+
const entries = this.compiled.projectResponse(path, "list", data);
|
|
274
|
+
return { data: entries };
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Related Packages
|
|
280
|
+
|
|
281
|
+
- [@aigne/afs](../core/README.md) - AFS core package
|
|
282
|
+
- [@aigne/afs-github](../../providers/github/README.md) - GitHub provider (uses AFS Mapping)
|
|
283
|
+
|
|
284
|
+
## TypeScript Support
|
|
285
|
+
|
|
286
|
+
This package includes full TypeScript type definitions.
|