@usewind/node 0.1.0 → 0.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/DESIGN.md +1 -1
- package/README.md +1 -1
- package/dist/index.cjs +56 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -3
- package/dist/index.d.ts +37 -3
- package/dist/index.js +56 -7
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/DESIGN.md
CHANGED
|
@@ -270,7 +270,7 @@ const event = wind.verify(req) // throws WindSignatureError on mismatch
|
|
|
270
270
|
```
|
|
271
271
|
|
|
272
272
|
- HMAC-SHA256 over the raw body with `webhookSecret`, constant-time compare,
|
|
273
|
-
`
|
|
273
|
+
`Wind-Signature: t=<unix>,v1=<hex>` header, 5-minute timestamp tolerance
|
|
274
274
|
(replay guard). Requires the raw (unparsed) body — documented loudly.
|
|
275
275
|
|
|
276
276
|
### Escape hatch
|
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ const res = await wind.connection(userId).model('gpt-4o').chat({
|
|
|
44
44
|
const res2 = await wind.connection(userId).feature('chat').chat({ messages })
|
|
45
45
|
|
|
46
46
|
// 3. webhooks
|
|
47
|
-
const event = wind.verify({ payload: rawBody, signature: req.headers['
|
|
47
|
+
const event = wind.verify({ payload: rawBody, signature: req.headers['wind-signature'] })
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
Credentials come from `wind.configure({ … })` or the env vars `WIND_CLIENT_ID`,
|
package/dist/index.cjs
CHANGED
|
@@ -236,6 +236,9 @@ var RawClient = class {
|
|
|
236
236
|
signal: req.signal
|
|
237
237
|
});
|
|
238
238
|
const requestId = res.headers.get("x-request-id");
|
|
239
|
+
if (req.stream && res.ok && res.body && (res.headers.get("content-type") ?? "").includes("text/event-stream")) {
|
|
240
|
+
return { status: res.status, headers: res.headers, body: res.body, requestId };
|
|
241
|
+
}
|
|
239
242
|
let parsed = void 0;
|
|
240
243
|
const text = await res.text();
|
|
241
244
|
if (text) {
|
|
@@ -290,7 +293,8 @@ var RawClient = class {
|
|
|
290
293
|
bearer: args.accessToken,
|
|
291
294
|
headers,
|
|
292
295
|
body: args.body,
|
|
293
|
-
signal: args.signal
|
|
296
|
+
signal: args.signal,
|
|
297
|
+
stream: isStreamBody(args.body)
|
|
294
298
|
});
|
|
295
299
|
}
|
|
296
300
|
/** `POST /v1/ai/features/{slug}`. */
|
|
@@ -301,7 +305,8 @@ var RawClient = class {
|
|
|
301
305
|
bearer: args.accessToken,
|
|
302
306
|
headers: { "Idempotency-Key": args.idempotencyKey },
|
|
303
307
|
body: args.body,
|
|
304
|
-
signal: args.signal
|
|
308
|
+
signal: args.signal,
|
|
309
|
+
stream: isStreamBody(args.body)
|
|
305
310
|
});
|
|
306
311
|
}
|
|
307
312
|
// ── Management (client-credentials) ────────────────────────────────────────
|
|
@@ -364,6 +369,9 @@ var RawClient = class {
|
|
|
364
369
|
return this.request({ method: "POST", path, ...init });
|
|
365
370
|
}
|
|
366
371
|
};
|
|
372
|
+
function isStreamBody(body) {
|
|
373
|
+
return typeof body === "object" && body !== null && body.stream === true;
|
|
374
|
+
}
|
|
367
375
|
|
|
368
376
|
// src/tokens.ts
|
|
369
377
|
var ACCESS_TOKEN_SKEW_MS = 6e4;
|
|
@@ -622,6 +630,9 @@ function requestBody(params) {
|
|
|
622
630
|
messages: params.messages,
|
|
623
631
|
...params.max_tokens !== void 0 && { max_tokens: params.max_tokens },
|
|
624
632
|
...params.temperature !== void 0 && { temperature: params.temperature },
|
|
633
|
+
...params.tools !== void 0 && { tools: params.tools },
|
|
634
|
+
...params.tool_choice !== void 0 && { tool_choice: params.tool_choice },
|
|
635
|
+
...params.parallel_tool_calls !== void 0 && { parallel_tool_calls: params.parallel_tool_calls },
|
|
625
636
|
...params.stream !== void 0 && { stream: params.stream }
|
|
626
637
|
};
|
|
627
638
|
}
|
|
@@ -668,13 +679,51 @@ async function* billedStream(ctx, userId, params, call) {
|
|
|
668
679
|
if (res.status < 200 || res.status >= 300) {
|
|
669
680
|
throw WindError.fromResponse(res.status, res.body, { requestId: res.requestId });
|
|
670
681
|
}
|
|
671
|
-
|
|
672
|
-
if (!contentType.includes("text/event-stream")) {
|
|
682
|
+
if (!(res.body instanceof ReadableStream)) {
|
|
673
683
|
const result = res.body;
|
|
674
|
-
yield { delta: result, wind: result.wind };
|
|
684
|
+
yield { delta: result, wind: result.wind ?? null, usage: result.usage };
|
|
675
685
|
return;
|
|
676
686
|
}
|
|
677
|
-
|
|
687
|
+
for await (const event of sseEvents(res.body)) {
|
|
688
|
+
if (event === "[DONE]") return;
|
|
689
|
+
let data;
|
|
690
|
+
try {
|
|
691
|
+
data = JSON.parse(event);
|
|
692
|
+
} catch {
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
if (data?.wind_final) {
|
|
696
|
+
yield { delta: null, wind: data.wind_final.wind ?? null, usage: data.wind_final.usage };
|
|
697
|
+
} else if (data?.error) {
|
|
698
|
+
const err = data.error.error ?? data.error;
|
|
699
|
+
const status = err.code === "provider_error" ? 502 : 403;
|
|
700
|
+
throw WindError.fromResponse(status, { error: err }, { requestId: res.requestId });
|
|
701
|
+
} else if (data?.streamed && data.wind) {
|
|
702
|
+
yield { delta: null, wind: data.wind, usage: data.usage };
|
|
703
|
+
} else {
|
|
704
|
+
yield { delta: data, wind: null };
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
async function* sseEvents(stream) {
|
|
709
|
+
const reader = stream.getReader();
|
|
710
|
+
const decoder = new TextDecoder();
|
|
711
|
+
let buffer = "";
|
|
712
|
+
try {
|
|
713
|
+
while (true) {
|
|
714
|
+
const { done, value } = await reader.read();
|
|
715
|
+
if (done) break;
|
|
716
|
+
buffer += decoder.decode(value, { stream: true });
|
|
717
|
+
const lines = buffer.split("\n");
|
|
718
|
+
buffer = lines.pop() ?? "";
|
|
719
|
+
for (const line of lines) {
|
|
720
|
+
if (line.startsWith("data:")) yield line.slice(5).trim();
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
if (buffer.startsWith("data:")) yield buffer.slice(5).trim();
|
|
724
|
+
} finally {
|
|
725
|
+
reader.releaseLock();
|
|
726
|
+
}
|
|
678
727
|
}
|
|
679
728
|
var TOLERANCE_S = 300;
|
|
680
729
|
var WebhookVerifier = class {
|
|
@@ -997,7 +1046,7 @@ var Wind = class {
|
|
|
997
1046
|
update: (appId, slug, patch) => this.raw.updateFeature(appId, slug, patch)
|
|
998
1047
|
};
|
|
999
1048
|
// ── webhooks ─────────────────────────────────────────────────────────────
|
|
1000
|
-
/** Verify a webhook's `
|
|
1049
|
+
/** Verify a webhook's `Wind-Signature` and return the typed event. Needs the raw body. */
|
|
1001
1050
|
verify(input) {
|
|
1002
1051
|
return this.#verifier.verify(input);
|
|
1003
1052
|
}
|