@mappa-ai/mappa-node 2.0.9 → 2.0.11
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 +164 -167
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -1,239 +1,236 @@
|
|
|
1
1
|
# @mappa-ai/mappa-node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@mappa-ai/mappa-node)
|
|
4
|
+
[](https://www.typescriptlang.org/)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
Behavioral intelligence for your app. Type-safe. Async-first. Production-ready.
|
|
6
7
|
|
|
7
|
-
##
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# npm
|
|
12
|
+
npm install @mappa-ai/mappa-node
|
|
13
|
+
|
|
14
|
+
# yarn
|
|
15
|
+
yarn add @mappa-ai/mappa-node
|
|
8
16
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
# pnpm
|
|
18
|
+
pnpm add @mappa-ai/mappa-node
|
|
19
|
+
|
|
20
|
+
# bun
|
|
21
|
+
bun add @mappa-ai/mappa-node
|
|
22
|
+
```
|
|
14
23
|
|
|
15
24
|
## Runtime support
|
|
16
25
|
|
|
17
|
-
|
|
18
|
-
- Compatible: Deno, Cloudflare Workers, other fetch-compatible server/edge runtimes
|
|
19
|
-
- Browser: blocked by default to protect secret API keys
|
|
26
|
+
Runs anywhere fetch runs. Node, Bun, Deno, Cloudflare Workers. Browser blocked by default — your API key stays secret.
|
|
20
27
|
|
|
21
|
-
## Security
|
|
28
|
+
## Security
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
Your API key is secret. We enforce it.
|
|
24
31
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
32
|
+
- Keep `MAPPA_API_KEY` server-side.
|
|
33
|
+
- Proxy requests through your backend.
|
|
34
|
+
- Browser calls throw unless you set `dangerouslyAllowBrowser: true`.
|
|
28
35
|
|
|
29
|
-
##
|
|
36
|
+
## Choose a workflow
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
Three paths. Pick yours.
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
| Method | When to use |
|
|
41
|
+
| --- | --- |
|
|
42
|
+
| `generateFromFile` / `generateFromUrl` | One call. Done. |
|
|
43
|
+
| `createJob` + `webhook` | Fire and forget. We call you. |
|
|
44
|
+
| `createJob` + `wait()` / `stream()` | Stay in control. |
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
## Webhooks — the production path
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
// app/api/mappa/report/route.ts
|
|
41
|
-
import { NextResponse } from "next/server";
|
|
42
|
-
import { Mappa, isMappaError } from "@mappa-ai/mappa-node";
|
|
43
|
-
|
|
44
|
-
const mappa = new Mappa({ apiKey: process.env.MAPPA_API_KEY! });
|
|
45
|
-
|
|
46
|
-
export async function POST(req: Request) {
|
|
47
|
-
try {
|
|
48
|
-
const form = await req.formData();
|
|
49
|
-
const file = form.get("file");
|
|
50
|
-
|
|
51
|
-
if (!(file instanceof File)) {
|
|
52
|
-
return NextResponse.json({ error: "file is required" }, { status: 400 });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const report = await mappa.reports.generateFromFile({
|
|
56
|
-
file,
|
|
57
|
-
output: { template: "general_report" },
|
|
58
|
-
target: { strategy: "dominant" },
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
return NextResponse.json({
|
|
62
|
-
id: report.id,
|
|
63
|
-
template: report.output.template,
|
|
64
|
-
summary: report.summary ?? null,
|
|
65
|
-
});
|
|
66
|
-
} catch (err) {
|
|
67
|
-
if (isMappaError(err)) {
|
|
68
|
-
return NextResponse.json(
|
|
69
|
-
{ error: err.message, requestId: err.requestId ?? null },
|
|
70
|
-
{ status: 502 },
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
return NextResponse.json({ error: "Unexpected error" }, { status: 500 });
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
48
|
+
Submit jobs. Move on. Mappa calls your endpoint when it's done. Signatures included.
|
|
77
49
|
|
|
78
|
-
|
|
50
|
+
### Publish
|
|
79
51
|
|
|
80
|
-
|
|
52
|
+
One field. That's it.
|
|
81
53
|
|
|
82
54
|
```ts
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
55
|
+
import { Mappa } from "@mappa-ai/mappa-node"
|
|
56
|
+
|
|
57
|
+
const mappa = new Mappa({ apiKey: process.env.MAPPA_API_KEY! })
|
|
58
|
+
|
|
59
|
+
const receipt = await mappa.reports.createJobFromFile({
|
|
60
|
+
file: audioBlob,
|
|
61
|
+
output: { template: "general_report" },
|
|
62
|
+
target: { strategy: "dominant" },
|
|
63
|
+
webhook: {
|
|
64
|
+
url: "https://your-app.com/api/webhooks/mappa",
|
|
65
|
+
headers: { "x-tenant-id": "tenant_123" },
|
|
66
|
+
},
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
console.log(receipt.jobId)
|
|
87
70
|
```
|
|
88
71
|
|
|
72
|
+
Already have media uploaded? Same idea.
|
|
73
|
+
|
|
89
74
|
```ts
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
})
|
|
96
|
-
return { id: report.id, summary: report.summary };
|
|
75
|
+
await mappa.reports.createJob({
|
|
76
|
+
media: { mediaId: "media_abc123" },
|
|
77
|
+
output: { template: "general_report" },
|
|
78
|
+
target: { strategy: "dominant" },
|
|
79
|
+
webhook: { url: "https://your-app.com/api/webhooks/mappa" },
|
|
80
|
+
})
|
|
97
81
|
```
|
|
98
82
|
|
|
99
|
-
###
|
|
83
|
+
### Consume
|
|
100
84
|
|
|
101
|
-
|
|
102
|
-
- Require auth for proxy endpoints
|
|
103
|
-
- Validate input size and type before SDK calls
|
|
104
|
-
- Add rate limits on proxy endpoints
|
|
105
|
-
- Log `requestId` values from SDK errors for traceability
|
|
85
|
+
Verify. Parse. React.
|
|
106
86
|
|
|
107
|
-
|
|
87
|
+
```ts
|
|
88
|
+
import { Mappa } from "@mappa-ai/mappa-node"
|
|
108
89
|
|
|
109
|
-
|
|
110
|
-
npm install @mappa-ai/mappa-node
|
|
111
|
-
```
|
|
90
|
+
const mappa = new Mappa({ apiKey: process.env.MAPPA_API_KEY! })
|
|
112
91
|
|
|
113
|
-
|
|
92
|
+
export async function POST(req: Request): Promise<Response> {
|
|
93
|
+
const payload = await req.text()
|
|
114
94
|
|
|
115
|
-
|
|
116
|
-
|
|
95
|
+
await mappa.webhooks.verifySignature({
|
|
96
|
+
payload,
|
|
97
|
+
headers: Object.fromEntries(req.headers),
|
|
98
|
+
secret: process.env.MAPPA_WEBHOOK_SECRET!,
|
|
99
|
+
})
|
|
117
100
|
|
|
118
|
-
const
|
|
119
|
-
apiKey: process.env.MAPPA_API_KEY!,
|
|
120
|
-
});
|
|
101
|
+
const event = mappa.webhooks.parseEvent(payload)
|
|
121
102
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
103
|
+
if (event.type === "report.completed") {
|
|
104
|
+
const report = await mappa.reports.get(event.data.reportId)
|
|
105
|
+
console.log("done", report.id)
|
|
106
|
+
return new Response("ok", { status: 200 })
|
|
107
|
+
}
|
|
125
108
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
});
|
|
109
|
+
if (event.type === "report.failed") {
|
|
110
|
+
console.error("failed", event.data.jobId, event.data.error.code)
|
|
111
|
+
return new Response("ok", { status: 200 })
|
|
112
|
+
}
|
|
131
113
|
|
|
132
|
-
|
|
133
|
-
|
|
114
|
+
return new Response("ignored", { status: 200 })
|
|
115
|
+
}
|
|
134
116
|
```
|
|
135
117
|
|
|
136
|
-
##
|
|
118
|
+
## Polling — when you want to wait
|
|
137
119
|
|
|
138
|
-
|
|
120
|
+
Sometimes you need the answer now.
|
|
121
|
+
|
|
122
|
+
### `wait()`
|
|
139
123
|
|
|
140
124
|
```ts
|
|
141
|
-
import { Mappa } from "@mappa-ai/mappa-node"
|
|
142
|
-
import { uploadFromPath, generateReportFromPath } from "@mappa-ai/mappa-node/node";
|
|
125
|
+
import { Mappa } from "@mappa-ai/mappa-node"
|
|
143
126
|
|
|
144
|
-
const mappa = new Mappa({ apiKey: process.env.MAPPA_API_KEY! })
|
|
127
|
+
const mappa = new Mappa({ apiKey: process.env.MAPPA_API_KEY! })
|
|
145
128
|
|
|
146
|
-
const media = await
|
|
147
|
-
path: "./recording.wav",
|
|
148
|
-
});
|
|
129
|
+
const media = await mappa.files.upload({ file: audioBlob })
|
|
149
130
|
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
})
|
|
131
|
+
const job = await mappa.reports.createJob({
|
|
132
|
+
media: { mediaId: media.mediaId },
|
|
133
|
+
output: { template: "general_report" },
|
|
134
|
+
target: { strategy: "dominant" },
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
const report = await job.handle?.wait()
|
|
138
|
+
console.log(report?.id)
|
|
155
139
|
```
|
|
156
140
|
|
|
157
|
-
|
|
141
|
+
### `stream()`
|
|
158
142
|
|
|
159
143
|
```ts
|
|
160
|
-
const job
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
const analysis = await job.handle?.wait();
|
|
168
|
-
console.log(analysis?.id);
|
|
144
|
+
for await (const event of job.handle?.stream() ?? []) {
|
|
145
|
+
if (event.type === "stage") {
|
|
146
|
+
console.log(event.stage, event.progress)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
169
149
|
```
|
|
170
150
|
|
|
171
|
-
##
|
|
151
|
+
## Helpers
|
|
152
|
+
|
|
153
|
+
### `generateFromFile`
|
|
154
|
+
|
|
155
|
+
Upload, process, return. One call.
|
|
172
156
|
|
|
173
157
|
```ts
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
onError: (ctx) => console.error("err", ctx.requestId, ctx.error),
|
|
182
|
-
},
|
|
183
|
-
});
|
|
158
|
+
const report = await mappa.reports.generateFromFile({
|
|
159
|
+
file: audioBlob,
|
|
160
|
+
output: { template: "general_report" },
|
|
161
|
+
target: { strategy: "dominant" },
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
console.log(report.id)
|
|
184
165
|
```
|
|
185
166
|
|
|
186
|
-
|
|
167
|
+
### `generateFromUrl`
|
|
168
|
+
|
|
169
|
+
Got a URL? We fetch it.
|
|
187
170
|
|
|
188
171
|
```ts
|
|
189
|
-
const
|
|
172
|
+
const report = await mappa.reports.generateFromUrl({
|
|
173
|
+
url: "https://example.com/recording.wav",
|
|
174
|
+
output: { template: "general_report" },
|
|
175
|
+
target: { strategy: "dominant" },
|
|
176
|
+
})
|
|
190
177
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
headers: req.headers,
|
|
194
|
-
secret: process.env.MAPPA_WEBHOOK_SECRET!,
|
|
195
|
-
});
|
|
178
|
+
console.log(report.id)
|
|
179
|
+
```
|
|
196
180
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
181
|
+
## Node/Bun file paths
|
|
182
|
+
|
|
183
|
+
Working with file paths? Use the `/node` subpath.
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { Mappa } from "@mappa-ai/mappa-node"
|
|
187
|
+
import { generateReportFromPath, uploadFromPath } from "@mappa-ai/mappa-node/node"
|
|
188
|
+
|
|
189
|
+
const mappa = new Mappa({ apiKey: process.env.MAPPA_API_KEY! })
|
|
190
|
+
|
|
191
|
+
const media = await uploadFromPath(mappa, { path: "./recording.wav" })
|
|
192
|
+
|
|
193
|
+
const report = await generateReportFromPath(mappa, {
|
|
194
|
+
path: "./recording.wav",
|
|
195
|
+
output: { template: "general_report" },
|
|
196
|
+
target: { strategy: "dominant" },
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
console.log(media.mediaId, report.id)
|
|
201
200
|
```
|
|
202
201
|
|
|
203
202
|
## Error handling
|
|
204
203
|
|
|
204
|
+
Things break. We tell you why.
|
|
205
|
+
|
|
205
206
|
```ts
|
|
206
|
-
import {
|
|
207
|
-
isInsufficientCreditsError,
|
|
208
|
-
isMappaError,
|
|
209
|
-
isStreamError,
|
|
210
|
-
} from "@mappa-ai/mappa-node";
|
|
207
|
+
import { isInsufficientCreditsError, isMappaError, isStreamError } from "@mappa-ai/mappa-node"
|
|
211
208
|
|
|
212
209
|
try {
|
|
213
|
-
|
|
210
|
+
// ...
|
|
214
211
|
} catch (err) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
212
|
+
if (isInsufficientCreditsError(err)) {
|
|
213
|
+
console.error(err.required, err.available)
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (isStreamError(err)) {
|
|
218
|
+
console.error(err.jobId, err.retryCount)
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (isMappaError(err)) {
|
|
223
|
+
console.error(err.requestId, err.code, err.message)
|
|
224
|
+
}
|
|
222
225
|
}
|
|
223
226
|
```
|
|
224
227
|
|
|
225
228
|
## Scope
|
|
226
229
|
|
|
227
|
-
|
|
228
|
-
- Includes: health, files, jobs, reports, matching-analysis, feedback, entities, webhooks
|
|
229
|
-
- Excludes: billing and user-session console endpoints
|
|
230
|
+
API-key workflows. Reports, files, jobs, webhooks, feedback, entities. Billing lives in the dashboard.
|
|
230
231
|
|
|
231
|
-
|
|
232
|
+
---
|
|
232
233
|
|
|
233
|
-
|
|
234
|
-
bun run build
|
|
235
|
-
bun run check
|
|
236
|
-
bun run type-check
|
|
237
|
-
bun test
|
|
238
|
-
```
|
|
234
|
+
Questions? [api-docs.mappa.ai](https://api-docs.mappa.ai)
|
|
239
235
|
|
|
236
|
+
For SDK maintenance, see `README_INTERNAL.md`.
|
package/dist/index.cjs
CHANGED
|
@@ -4904,7 +4904,7 @@ const reportTemplates = _enum([
|
|
|
4904
4904
|
* - `markdown`: Human-readable formatted text
|
|
4905
4905
|
* - `json`: Structured data for programmatic use
|
|
4906
4906
|
* - `pdf`: Rendered PDF document (via external service)
|
|
4907
|
-
* - `url`: Hosted web report at
|
|
4907
|
+
* - `url`: Hosted web report at conduit.mappa.ai/reports/[id]
|
|
4908
4908
|
*/
|
|
4909
4909
|
const reportOutput = object({
|
|
4910
4910
|
template: reportTemplates,
|