@puku-ai/sdk 4.0.2 → 4.0.4
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 +24 -7
- package/dist/index.cjs +85 -0
- package/dist/vendor/_vendor/partial-json-parser/parser.cjs +225 -0
- package/dist/vendor/api-promise.cjs +18 -0
- package/dist/vendor/client.cjs +1013 -0
- package/dist/vendor/core/api-promise.cjs +80 -0
- package/dist/vendor/core/api.cjs +2 -0
- package/dist/vendor/core/credentials.cjs +313 -0
- package/dist/vendor/core/error.cjs +156 -0
- package/dist/vendor/core/middleware.cjs +173 -0
- package/dist/vendor/core/pagination.cjs +215 -0
- package/dist/vendor/core/resource.cjs +11 -0
- package/dist/vendor/core/streaming.cjs +346 -0
- package/dist/vendor/core/uploads.cjs +5 -0
- package/dist/vendor/error.cjs +18 -0
- package/dist/vendor/helpers/beta/environments.cjs +30 -0
- package/dist/vendor/helpers/beta/json-schema.cjs +56 -0
- package/dist/vendor/helpers/beta/mcp.cjs +418 -0
- package/dist/vendor/helpers/beta/memory.cjs +17 -0
- package/dist/vendor/helpers/beta/standard-schema.cjs +57 -0
- package/dist/vendor/helpers/beta/zod.cjs +88 -0
- package/dist/vendor/helpers/index.cjs +7 -0
- package/dist/vendor/helpers/json-schema.cjs +36 -0
- package/dist/vendor/helpers/zod.cjs +77 -0
- package/dist/vendor/index.cjs +54 -0
- package/dist/vendor/internal/builtin-types.cjs +3 -0
- package/dist/vendor/internal/constants.cjs +12 -0
- package/dist/vendor/internal/decoders/jsonl.cjs +40 -0
- package/dist/vendor/internal/decoders/line.cjs +109 -0
- package/dist/vendor/internal/detect-platform.cjs +159 -0
- package/dist/vendor/internal/errors.cjs +42 -0
- package/dist/vendor/internal/file-store.cjs +535 -0
- package/dist/vendor/internal/headers.cjs +119 -0
- package/dist/vendor/internal/message-stream-utils.cjs +33 -0
- package/dist/vendor/internal/node.browser.cjs +21 -0
- package/dist/vendor/internal/node.cjs +55 -0
- package/dist/vendor/internal/parse.cjs +65 -0
- package/dist/vendor/internal/qs/formats.cjs +12 -0
- package/dist/vendor/internal/qs/index.cjs +13 -0
- package/dist/vendor/internal/qs/stringify.cjs +276 -0
- package/dist/vendor/internal/qs/types.cjs +2 -0
- package/dist/vendor/internal/qs/utils.cjs +229 -0
- package/dist/vendor/internal/request-options.cjs +31 -0
- package/dist/vendor/internal/request-signal.cjs +49 -0
- package/dist/vendor/internal/shim-types.cjs +3 -0
- package/dist/vendor/internal/shims.cjs +91 -0
- package/dist/vendor/internal/stainless-helper-header.cjs +90 -0
- package/dist/vendor/internal/stream-utils.cjs +37 -0
- package/dist/vendor/internal/to-file.cjs +95 -0
- package/dist/vendor/internal/types.cjs +3 -0
- package/dist/vendor/internal/uploads.cjs +148 -0
- package/dist/vendor/internal/utils/abort.cjs +24 -0
- package/dist/vendor/internal/utils/async-queue.cjs +69 -0
- package/dist/vendor/internal/utils/backoff.cjs +43 -0
- package/dist/vendor/internal/utils/base64.cjs +37 -0
- package/dist/vendor/internal/utils/bytes.cjs +30 -0
- package/dist/vendor/internal/utils/env.cjs +21 -0
- package/dist/vendor/internal/utils/log.cjs +111 -0
- package/dist/vendor/internal/utils/path.cjs +78 -0
- package/dist/vendor/internal/utils/promise.cjs +17 -0
- package/dist/vendor/internal/utils/query.cjs +41 -0
- package/dist/vendor/internal/utils/sleep.cjs +27 -0
- package/dist/vendor/internal/utils/time.cjs +7 -0
- package/dist/vendor/internal/utils/uuid.cjs +18 -0
- package/dist/vendor/internal/utils/values.cjs +125 -0
- package/dist/vendor/internal/utils.cjs +24 -0
- package/dist/vendor/lib/BetaMessageStream.cjs +665 -0
- package/dist/vendor/lib/MessageStream.cjs +612 -0
- package/dist/vendor/lib/beta-parser.cjs +78 -0
- package/dist/vendor/lib/credentials/credential-chain.cjs +244 -0
- package/dist/vendor/lib/credentials/identity-token.cjs +71 -0
- package/dist/vendor/lib/credentials/oidc-federation.cjs +81 -0
- package/dist/vendor/lib/credentials/token-cache.cjs +113 -0
- package/dist/vendor/lib/credentials/types.cjs +267 -0
- package/dist/vendor/lib/credentials/user-oauth.cjs +129 -0
- package/dist/vendor/lib/credentials.cjs +7 -0
- package/dist/vendor/lib/environments/index.cjs +17 -0
- package/dist/vendor/lib/environments/poller.cjs +226 -0
- package/dist/vendor/lib/environments/worker.cjs +609 -0
- package/dist/vendor/lib/helper-client.cjs +57 -0
- package/dist/vendor/lib/middleware.cjs +779 -0
- package/dist/vendor/lib/parser.cjs +65 -0
- package/dist/vendor/lib/sessions/accumulate.cjs +44 -0
- package/dist/vendor/lib/standard-schema.cjs +44 -0
- package/dist/vendor/lib/tools/BetaRunnableTool.cjs +30 -0
- package/dist/vendor/lib/tools/BetaToolRunner.cjs +500 -0
- package/dist/vendor/lib/tools/BetaToolRunner.d.ts +1 -1
- package/dist/vendor/lib/tools/CompactionControl.cjs +27 -0
- package/dist/vendor/lib/tools/SessionToolRunner.cjs +740 -0
- package/dist/vendor/lib/tools/ToolError.cjs +46 -0
- package/dist/vendor/lib/transform-json-schema.cjs +113 -0
- package/dist/vendor/pagination.cjs +18 -0
- package/dist/vendor/resource.cjs +18 -0
- package/dist/vendor/resources/beta/agents/agents.cjs +159 -0
- package/dist/vendor/resources/beta/agents/agents.d.ts +3 -3
- package/dist/vendor/resources/beta/agents/agents.js +1 -1
- package/dist/vendor/resources/beta/agents/index.cjs +8 -0
- package/dist/vendor/resources/beta/agents/versions.cjs +35 -0
- package/dist/vendor/resources/beta/agents.cjs +18 -0
- package/dist/vendor/resources/beta/beta.cjs +105 -0
- package/dist/vendor/resources/beta/deployment-runs.cjs +54 -0
- package/dist/vendor/resources/beta/deployments.cjs +195 -0
- package/dist/vendor/resources/beta/dreams.cjs +115 -0
- package/dist/vendor/resources/beta/dreams.d.ts +2 -2
- package/dist/vendor/resources/beta/environments/environments.cjs +178 -0
- package/dist/vendor/resources/beta/environments/index.cjs +8 -0
- package/dist/vendor/resources/beta/environments/work.cjs +256 -0
- package/dist/vendor/resources/beta/environments.cjs +18 -0
- package/dist/vendor/resources/beta/files.cjs +123 -0
- package/dist/vendor/resources/beta/index.cjs +38 -0
- package/dist/vendor/resources/beta/memory-stores/index.cjs +10 -0
- package/dist/vendor/resources/beta/memory-stores/memories.cjs +129 -0
- package/dist/vendor/resources/beta/memory-stores/memory-stores.cjs +173 -0
- package/dist/vendor/resources/beta/memory-stores/memory-versions.cjs +80 -0
- package/dist/vendor/resources/beta/memory-stores.cjs +18 -0
- package/dist/vendor/resources/beta/messages/batches.cjs +206 -0
- package/dist/vendor/resources/beta/messages/batches.d.ts +3 -3
- package/dist/vendor/resources/beta/messages/index.cjs +11 -0
- package/dist/vendor/resources/beta/messages/messages.cjs +189 -0
- package/dist/vendor/resources/beta/messages/messages.d.ts +5 -5
- package/dist/vendor/resources/beta/messages/messages.js +4 -11
- package/dist/vendor/resources/beta/messages/messages.js.map +1 -1
- package/dist/vendor/resources/beta/messages.cjs +18 -0
- package/dist/vendor/resources/beta/models.cjs +59 -0
- package/dist/vendor/resources/beta/organization/api-keys.cjs +55 -0
- package/dist/vendor/resources/beta/organization/compliance-settings.cjs +51 -0
- package/dist/vendor/resources/beta/organization/external-keys.cjs +118 -0
- package/dist/vendor/resources/beta/organization/federation/federation.cjs +49 -0
- package/dist/vendor/resources/beta/organization/federation/index.cjs +10 -0
- package/dist/vendor/resources/beta/organization/federation/issuers.cjs +168 -0
- package/dist/vendor/resources/beta/organization/federation/rules/index.cjs +8 -0
- package/dist/vendor/resources/beta/organization/federation/rules/rules.cjs +226 -0
- package/dist/vendor/resources/beta/organization/federation/rules/workspaces.cjs +113 -0
- package/dist/vendor/resources/beta/organization/federation/rules.cjs +18 -0
- package/dist/vendor/resources/beta/organization/federation.cjs +18 -0
- package/dist/vendor/resources/beta/organization/index.cjs +24 -0
- package/dist/vendor/resources/beta/organization/invites.cjs +75 -0
- package/dist/vendor/resources/beta/organization/organization.cjs +90 -0
- package/dist/vendor/resources/beta/organization/rate-limits.cjs +30 -0
- package/dist/vendor/resources/beta/organization/service-accounts/index.cjs +8 -0
- package/dist/vendor/resources/beta/organization/service-accounts/service-accounts.cjs +202 -0
- package/dist/vendor/resources/beta/organization/service-accounts/workspaces.cjs +124 -0
- package/dist/vendor/resources/beta/organization/service-accounts.cjs +18 -0
- package/dist/vendor/resources/beta/organization/users.cjs +66 -0
- package/dist/vendor/resources/beta/organization/workspaces/index.cjs +12 -0
- package/dist/vendor/resources/beta/organization/workspaces/members.cjs +101 -0
- package/dist/vendor/resources/beta/organization/workspaces/rate-limits.cjs +33 -0
- package/dist/vendor/resources/beta/organization/workspaces/service-accounts.cjs +188 -0
- package/dist/vendor/resources/beta/organization/workspaces/workspaces.cjs +140 -0
- package/dist/vendor/resources/beta/organization/workspaces.cjs +18 -0
- package/dist/vendor/resources/beta/organization.cjs +18 -0
- package/dist/vendor/resources/beta/sessions/events.cjs +119 -0
- package/dist/vendor/resources/beta/sessions/index.cjs +12 -0
- package/dist/vendor/resources/beta/sessions/resources.cjs +131 -0
- package/dist/vendor/resources/beta/sessions/sessions.cjs +186 -0
- package/dist/vendor/resources/beta/sessions/sessions.d.ts +1 -1
- package/dist/vendor/resources/beta/sessions/threads/events.cjs +60 -0
- package/dist/vendor/resources/beta/sessions/threads/index.cjs +8 -0
- package/dist/vendor/resources/beta/sessions/threads/threads.cjs +116 -0
- package/dist/vendor/resources/beta/sessions/threads.cjs +18 -0
- package/dist/vendor/resources/beta/sessions.cjs +18 -0
- package/dist/vendor/resources/beta/skills/index.cjs +8 -0
- package/dist/vendor/resources/beta/skills/skills.cjs +132 -0
- package/dist/vendor/resources/beta/skills/versions.cjs +128 -0
- package/dist/vendor/resources/beta/skills.cjs +18 -0
- package/dist/vendor/resources/beta/tunnels/certificates.cjs +128 -0
- package/dist/vendor/resources/beta/tunnels/index.cjs +8 -0
- package/dist/vendor/resources/beta/tunnels/tunnels.cjs +209 -0
- package/dist/vendor/resources/beta/tunnels.cjs +18 -0
- package/dist/vendor/resources/beta/user-profiles.cjs +117 -0
- package/dist/vendor/resources/beta/vaults/credentials.cjs +176 -0
- package/dist/vendor/resources/beta/vaults/index.cjs +8 -0
- package/dist/vendor/resources/beta/vaults/vaults.cjs +177 -0
- package/dist/vendor/resources/beta/vaults.cjs +18 -0
- package/dist/vendor/resources/beta/webhooks.cjs +32 -0
- package/dist/vendor/resources/beta.cjs +18 -0
- package/dist/vendor/resources/completions.cjs +22 -0
- package/dist/vendor/resources/completions.d.ts +3 -3
- package/dist/vendor/resources/files.cjs +51 -0
- package/dist/vendor/resources/index.cjs +31 -0
- package/dist/vendor/resources/messages/batches.cjs +160 -0
- package/dist/vendor/resources/messages/batches.d.ts +1 -1
- package/dist/vendor/resources/messages/batches.js +1 -1
- package/dist/vendor/resources/messages/index.cjs +8 -0
- package/dist/vendor/resources/messages/messages.cjs +159 -0
- package/dist/vendor/resources/messages/messages.d.ts +7 -7
- package/dist/vendor/resources/messages/messages.js +6 -13
- package/dist/vendor/resources/messages/messages.js.map +1 -1
- package/dist/vendor/resources/messages.cjs +18 -0
- package/dist/vendor/resources/models.cjs +44 -0
- package/dist/vendor/resources/shared.cjs +3 -0
- package/dist/vendor/resources/skills/index.cjs +8 -0
- package/dist/vendor/resources/skills/skills.cjs +72 -0
- package/dist/vendor/resources/skills/versions.cjs +40 -0
- package/dist/vendor/resources/skills.cjs +18 -0
- package/dist/vendor/resources/top-level.cjs +3 -0
- package/dist/vendor/resources.cjs +17 -0
- package/dist/vendor/streaming.cjs +18 -0
- package/dist/vendor/tools/agent-toolset/fs-util.cjs +193 -0
- package/dist/vendor/tools/agent-toolset/memories.cjs +916 -0
- package/dist/vendor/tools/agent-toolset/node.browser.cjs +147 -0
- package/dist/vendor/tools/agent-toolset/node.cjs +939 -0
- package/dist/vendor/tools/agent-toolset/skills.cjs +325 -0
- package/dist/vendor/tools/agent-toolset/sync-interval.cjs +28 -0
- package/dist/vendor/tools/memory/node.browser.cjs +48 -0
- package/dist/vendor/tools/memory/node.cjs +364 -0
- package/dist/vendor/uploads.cjs +18 -0
- package/dist/vendor/version.cjs +4 -0
- package/package.json +12 -13
- package/sdk.cjs +0 -14293
- package/sdk.cjs.map +0 -149
- package/sdk.d.ts +0 -10866
- package/sdk.mjs +0 -68
- package/sdk.mjs.map +0 -149
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.FallbackEncoder = exports.BetaFallbackState = void 0;
|
|
5
|
+
/**
|
|
6
|
+
* Tracks which fallback a sequence of requests is pinned to.
|
|
7
|
+
*
|
|
8
|
+
* Create one (`new BetaFallbackState()`) and pass it via the `fallbackState`
|
|
9
|
+
* request option on every request that should share the pin — the turns of one
|
|
10
|
+
* conversation, or any wider scope the stickiness should apply to;
|
|
11
|
+
* `betaRefusalFallbackMiddleware` mutates it in place when a model refuses.
|
|
12
|
+
*/
|
|
13
|
+
class BetaFallbackState {
|
|
14
|
+
/**
|
|
15
|
+
* Index into the fallback chain the requests are pinned to.
|
|
16
|
+
*
|
|
17
|
+
* `undefined` (or -1) targets the original request params; the middleware
|
|
18
|
+
* sets it to the index of the fallback that accepted the request.
|
|
19
|
+
*/
|
|
20
|
+
index;
|
|
21
|
+
}
|
|
22
|
+
exports.BetaFallbackState = BetaFallbackState;
|
|
23
|
+
const FallbackEncoder = ({ headers, body }) => {
|
|
24
|
+
return {
|
|
25
|
+
bodyHeaders: {
|
|
26
|
+
'content-type': 'application/json',
|
|
27
|
+
},
|
|
28
|
+
body: JSON.stringify(body),
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
exports.FallbackEncoder = FallbackEncoder;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerRequestSignalCleanup = registerRequestSignalCleanup;
|
|
4
|
+
exports.armAbandonmentBackstop = armAbandonmentBackstop;
|
|
5
|
+
exports.releaseRequestSignal = releaseRequestSignal;
|
|
6
|
+
/**
|
|
7
|
+
* Tracks the removal of the per-request abort listener that
|
|
8
|
+
* `fetchWithTimeout` attaches to a caller-provided signal, so the listener's
|
|
9
|
+
* lifetime matches the request instead of the signal.
|
|
10
|
+
*
|
|
11
|
+
* Without removal, a long-lived signal (e.g. one AbortController reused for
|
|
12
|
+
* a whole session) accumulates one `{ once: true }` listener plus its bound
|
|
13
|
+
* AbortController per HTTP attempt until the signal fires or is collected,
|
|
14
|
+
* and Node warns at the 11th listener. The listener must survive until the
|
|
15
|
+
* response body is settled - removing it when fetch resolves (headers) would
|
|
16
|
+
* break aborting an in-flight body read - so the code that finishes the body
|
|
17
|
+
* (response parsing, stream teardown, retry/error handling) calls
|
|
18
|
+
* `releaseRequestSignal` with the request's controller.
|
|
19
|
+
*/
|
|
20
|
+
const cleanups = new WeakMap();
|
|
21
|
+
const registry = typeof globalThis.FinalizationRegistry === 'function' ?
|
|
22
|
+
new globalThis.FinalizationRegistry((controller) => releaseRequestSignal(controller))
|
|
23
|
+
: null;
|
|
24
|
+
// Module-scope factory so the cleanup closure captures exactly the signal and
|
|
25
|
+
// the listener - built at the `fetchWithTimeout` call site it would share that
|
|
26
|
+
// scope's context and retain the request body for as long as the cleanup is
|
|
27
|
+
// held (same reason `_makeAbort` exists in client.ts).
|
|
28
|
+
function makeCleanup(signal, listener) {
|
|
29
|
+
return () => signal.removeEventListener('abort', listener);
|
|
30
|
+
}
|
|
31
|
+
function registerRequestSignalCleanup(controller, signal, listener) {
|
|
32
|
+
cleanups.set(controller, makeCleanup(signal, listener));
|
|
33
|
+
}
|
|
34
|
+
// The registered target is the response BODY, not the Response: a caller can
|
|
35
|
+
// keep a reader on the body and drop the Response wrapper (`.asResponse()`),
|
|
36
|
+
// and the listener must survive for as long as anything can still read - the
|
|
37
|
+
// body is what a live read keeps alive.
|
|
38
|
+
function armAbandonmentBackstop(body, controller) {
|
|
39
|
+
if (cleanups.has(controller))
|
|
40
|
+
registry?.register(body, controller, controller);
|
|
41
|
+
}
|
|
42
|
+
function releaseRequestSignal(controller) {
|
|
43
|
+
const cleanup = cleanups.get(controller);
|
|
44
|
+
if (cleanup) {
|
|
45
|
+
cleanups.delete(controller);
|
|
46
|
+
registry?.unregister(controller);
|
|
47
|
+
cleanup();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.getDefaultFetch = getDefaultFetch;
|
|
5
|
+
exports.makeReadableStream = makeReadableStream;
|
|
6
|
+
exports.ReadableStreamFrom = ReadableStreamFrom;
|
|
7
|
+
exports.ReadableStreamToAsyncIterable = ReadableStreamToAsyncIterable;
|
|
8
|
+
exports.CancelReadableStream = CancelReadableStream;
|
|
9
|
+
function getDefaultFetch() {
|
|
10
|
+
if (typeof fetch !== 'undefined') {
|
|
11
|
+
return fetch;
|
|
12
|
+
}
|
|
13
|
+
throw new Error('`fetch` is not defined as a global; Either pass `fetch` to the client, `new PukuAI({ fetch })` or polyfill the global, `globalThis.fetch = fetch`');
|
|
14
|
+
}
|
|
15
|
+
function makeReadableStream(...args) {
|
|
16
|
+
const ReadableStream = globalThis.ReadableStream;
|
|
17
|
+
if (typeof ReadableStream === 'undefined') {
|
|
18
|
+
// Note: All of the platforms / runtimes we officially support already define
|
|
19
|
+
// `ReadableStream` as a global, so this should only ever be hit on unsupported runtimes.
|
|
20
|
+
throw new Error('`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`');
|
|
21
|
+
}
|
|
22
|
+
return new ReadableStream(...args);
|
|
23
|
+
}
|
|
24
|
+
function ReadableStreamFrom(iterable) {
|
|
25
|
+
let iter = Symbol.asyncIterator in iterable ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
|
|
26
|
+
return makeReadableStream({
|
|
27
|
+
start() { },
|
|
28
|
+
async pull(controller) {
|
|
29
|
+
const { done, value } = await iter.next();
|
|
30
|
+
if (done) {
|
|
31
|
+
controller.close();
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
controller.enqueue(value);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
async cancel() {
|
|
38
|
+
await iter.return?.();
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Most browsers don't yet have async iterable support for ReadableStream,
|
|
44
|
+
* and Node has a very different way of reading bytes from its "ReadableStream".
|
|
45
|
+
*
|
|
46
|
+
* This polyfill was pulled from
|
|
47
|
+
*/
|
|
48
|
+
function ReadableStreamToAsyncIterable(stream) {
|
|
49
|
+
if (stream[Symbol.asyncIterator])
|
|
50
|
+
return stream;
|
|
51
|
+
const reader = stream.getReader();
|
|
52
|
+
return {
|
|
53
|
+
async next() {
|
|
54
|
+
try {
|
|
55
|
+
const result = await reader.read();
|
|
56
|
+
if (result?.done)
|
|
57
|
+
reader.releaseLock(); // release lock when stream becomes closed
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
reader.releaseLock(); // release lock when stream becomes errored
|
|
62
|
+
throw e;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
async return() {
|
|
66
|
+
const cancelPromise = reader.cancel();
|
|
67
|
+
reader.releaseLock();
|
|
68
|
+
await cancelPromise;
|
|
69
|
+
return { done: true, value: undefined };
|
|
70
|
+
},
|
|
71
|
+
[Symbol.asyncIterator]() {
|
|
72
|
+
return this;
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Cancels a ReadableStream we don't need to consume.
|
|
78
|
+
* See https://undici.nodejs.org/#/?id=garbage-collection
|
|
79
|
+
*/
|
|
80
|
+
async function CancelReadableStream(stream) {
|
|
81
|
+
if (stream === null || typeof stream !== 'object')
|
|
82
|
+
return;
|
|
83
|
+
if (stream[Symbol.asyncIterator]) {
|
|
84
|
+
await stream[Symbol.asyncIterator]().return?.();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const reader = stream.getReader();
|
|
88
|
+
const cancelPromise = reader.cancel();
|
|
89
|
+
reader.releaseLock();
|
|
90
|
+
await cancelPromise;
|
|
91
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Single source of truth for the `x-stainless-helper` telemetry header — the
|
|
4
|
+
* key, the closed value vocabulary, and per-object helper tagging. The
|
|
5
|
+
* append-don't-clobber merge for the header itself lives in
|
|
6
|
+
* {@link import('../internal/headers').buildHeaders} via `APPEND_HEADERS`.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.SDK_HELPER_SYMBOL = exports.STAINLESS_HELPER_METHOD_HEADER = exports.STAINLESS_HELPER_HEADER = void 0;
|
|
10
|
+
exports.helperHeader = helperHeader;
|
|
11
|
+
exports.wasCreatedByStainlessHelper = wasCreatedByStainlessHelper;
|
|
12
|
+
exports.collectStainlessHelpers = collectStainlessHelpers;
|
|
13
|
+
exports.stainlessHelperHeader = stainlessHelperHeader;
|
|
14
|
+
exports.stainlessHelperHeaderFromFile = stainlessHelperHeaderFromFile;
|
|
15
|
+
/**
|
|
16
|
+
* Telemetry header naming the SDK helper(s) a request came from. Always this
|
|
17
|
+
* lowercase form; `buildHeaders` matches it case-insensitively for its append
|
|
18
|
+
* semantics, but a single canonical casing keeps every call site greppable.
|
|
19
|
+
*/
|
|
20
|
+
exports.STAINLESS_HELPER_HEADER = 'x-stainless-helper';
|
|
21
|
+
/** Telemetry header naming the SDK method (e.g. `stream`) in use. */
|
|
22
|
+
exports.STAINLESS_HELPER_METHOD_HEADER = 'x-stainless-helper-method';
|
|
23
|
+
/**
|
|
24
|
+
* The `{ 'x-stainless-helper': value }` header dict, for passing into
|
|
25
|
+
* `buildHeaders` (which comma-appends `x-stainless-helper` across sources)
|
|
26
|
+
* or as `defaultHeaders`/per-request `headers`.
|
|
27
|
+
*/
|
|
28
|
+
function helperHeader(value) {
|
|
29
|
+
return { [exports.STAINLESS_HELPER_HEADER]: value };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Symbol used to mark objects created by SDK helpers for tracking.
|
|
33
|
+
* The value is the helper name (e.g., 'mcpTool', 'betaZodTool').
|
|
34
|
+
*/
|
|
35
|
+
exports.SDK_HELPER_SYMBOL = Symbol('puku.sdk.stainlessHelper');
|
|
36
|
+
function wasCreatedByStainlessHelper(value) {
|
|
37
|
+
return typeof value === 'object' && value !== null && exports.SDK_HELPER_SYMBOL in value;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Collects helper names from tools and messages arrays.
|
|
41
|
+
* Returns a deduplicated array of helper names found.
|
|
42
|
+
*/
|
|
43
|
+
function collectStainlessHelpers(tools, messages) {
|
|
44
|
+
const helpers = new Set();
|
|
45
|
+
// Collect from tools
|
|
46
|
+
if (tools) {
|
|
47
|
+
for (const tool of tools) {
|
|
48
|
+
if (wasCreatedByStainlessHelper(tool)) {
|
|
49
|
+
helpers.add(tool[exports.SDK_HELPER_SYMBOL]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Collect from messages and their content blocks
|
|
54
|
+
if (messages) {
|
|
55
|
+
for (const message of messages) {
|
|
56
|
+
if (wasCreatedByStainlessHelper(message)) {
|
|
57
|
+
helpers.add(message[exports.SDK_HELPER_SYMBOL]);
|
|
58
|
+
}
|
|
59
|
+
const content = message.content;
|
|
60
|
+
if (Array.isArray(content)) {
|
|
61
|
+
for (const block of content) {
|
|
62
|
+
if (wasCreatedByStainlessHelper(block)) {
|
|
63
|
+
helpers.add(block[exports.SDK_HELPER_SYMBOL]);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return Array.from(helpers);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Builds x-stainless-helper header value from tools and messages.
|
|
73
|
+
* Returns an empty object if no helpers are found.
|
|
74
|
+
*/
|
|
75
|
+
function stainlessHelperHeader(tools, messages) {
|
|
76
|
+
const helpers = collectStainlessHelpers(tools, messages);
|
|
77
|
+
if (helpers.length === 0)
|
|
78
|
+
return {};
|
|
79
|
+
return { [exports.STAINLESS_HELPER_HEADER]: helpers.join(', ') };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Builds x-stainless-helper header value from a file object.
|
|
83
|
+
* Returns an empty object if the file is not marked with a helper.
|
|
84
|
+
*/
|
|
85
|
+
function stainlessHelperHeaderFromFile(file) {
|
|
86
|
+
if (wasCreatedByStainlessHelper(file)) {
|
|
87
|
+
return { [exports.STAINLESS_HELPER_HEADER]: file[exports.SDK_HELPER_SYMBOL] };
|
|
88
|
+
}
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReadableStreamToAsyncIterable = ReadableStreamToAsyncIterable;
|
|
4
|
+
/**
|
|
5
|
+
* Most browsers don't yet have async iterable support for ReadableStream,
|
|
6
|
+
* and Node has a very different way of reading bytes from its "ReadableStream".
|
|
7
|
+
*
|
|
8
|
+
* This polyfill was pulled from
|
|
9
|
+
*/
|
|
10
|
+
function ReadableStreamToAsyncIterable(stream) {
|
|
11
|
+
if (stream[Symbol.asyncIterator])
|
|
12
|
+
return stream;
|
|
13
|
+
const reader = stream.getReader();
|
|
14
|
+
return {
|
|
15
|
+
async next() {
|
|
16
|
+
try {
|
|
17
|
+
const result = await reader.read();
|
|
18
|
+
if (result?.done)
|
|
19
|
+
reader.releaseLock(); // release lock when stream becomes closed
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
reader.releaseLock(); // release lock when stream becomes errored
|
|
24
|
+
throw e;
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
async return() {
|
|
28
|
+
const cancelPromise = reader.cancel();
|
|
29
|
+
reader.releaseLock();
|
|
30
|
+
await cancelPromise;
|
|
31
|
+
return { done: true, value: undefined };
|
|
32
|
+
},
|
|
33
|
+
[Symbol.asyncIterator]() {
|
|
34
|
+
return this;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toFile = toFile;
|
|
4
|
+
const uploads_1 = require("./uploads");
|
|
5
|
+
const uploads_2 = require("./uploads");
|
|
6
|
+
/**
|
|
7
|
+
* This check adds the arrayBuffer() method type because it is available and used at runtime
|
|
8
|
+
*/
|
|
9
|
+
const isBlobLike = (value) => value != null &&
|
|
10
|
+
typeof value === 'object' &&
|
|
11
|
+
typeof value.size === 'number' &&
|
|
12
|
+
typeof value.type === 'string' &&
|
|
13
|
+
typeof value.text === 'function' &&
|
|
14
|
+
typeof value.slice === 'function' &&
|
|
15
|
+
typeof value.arrayBuffer === 'function';
|
|
16
|
+
/**
|
|
17
|
+
* This check adds the arrayBuffer() method type because it is available and used at runtime
|
|
18
|
+
*/
|
|
19
|
+
const isFileLike = (value) => value != null &&
|
|
20
|
+
typeof value === 'object' &&
|
|
21
|
+
typeof value.name === 'string' &&
|
|
22
|
+
typeof value.lastModified === 'number' &&
|
|
23
|
+
isBlobLike(value);
|
|
24
|
+
const isResponseLike = (value) => value != null &&
|
|
25
|
+
typeof value === 'object' &&
|
|
26
|
+
typeof value.url === 'string' &&
|
|
27
|
+
typeof value.blob === 'function';
|
|
28
|
+
/**
|
|
29
|
+
* Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats
|
|
30
|
+
* @param value the raw content of the file. Can be an {@link Uploadable}, BlobLikePart, or AsyncIterable of BlobLikeParts
|
|
31
|
+
* @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible
|
|
32
|
+
* @param {Object=} options additional properties
|
|
33
|
+
* @param {string=} options.type the MIME type of the content
|
|
34
|
+
* @param {number=} options.lastModified the last modified timestamp
|
|
35
|
+
* @returns a {@link File} with the given properties
|
|
36
|
+
*/
|
|
37
|
+
async function toFile(value, name, options) {
|
|
38
|
+
(0, uploads_2.checkFileSupport)();
|
|
39
|
+
// If it's a promise, resolve it.
|
|
40
|
+
value = await value;
|
|
41
|
+
name ||= (0, uploads_1.getName)(value, true);
|
|
42
|
+
// If we've been given a `File` we don't need to do anything if the name / options
|
|
43
|
+
// have not been customised.
|
|
44
|
+
if (isFileLike(value)) {
|
|
45
|
+
if (value instanceof File && name == null && options == null) {
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
return (0, uploads_1.makeFile)([await value.arrayBuffer()], name ?? value.name, {
|
|
49
|
+
type: value.type,
|
|
50
|
+
lastModified: value.lastModified,
|
|
51
|
+
...options,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (isResponseLike(value)) {
|
|
55
|
+
const blob = await value.blob();
|
|
56
|
+
name ||= new URL(value.url).pathname.split(/[\\/]/).pop();
|
|
57
|
+
return (0, uploads_1.makeFile)(await getBytes(blob), name, options);
|
|
58
|
+
}
|
|
59
|
+
const parts = await getBytes(value);
|
|
60
|
+
if (!options?.type) {
|
|
61
|
+
const type = parts.find((part) => typeof part === 'object' && 'type' in part && part.type);
|
|
62
|
+
if (typeof type === 'string') {
|
|
63
|
+
options = { ...options, type };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return (0, uploads_1.makeFile)(parts, name, options);
|
|
67
|
+
}
|
|
68
|
+
async function getBytes(value) {
|
|
69
|
+
let parts = [];
|
|
70
|
+
if (typeof value === 'string' ||
|
|
71
|
+
ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.
|
|
72
|
+
value instanceof ArrayBuffer) {
|
|
73
|
+
parts.push(value);
|
|
74
|
+
}
|
|
75
|
+
else if (isBlobLike(value)) {
|
|
76
|
+
parts.push(value instanceof Blob ? value : await value.arrayBuffer());
|
|
77
|
+
}
|
|
78
|
+
else if ((0, uploads_1.isAsyncIterable)(value) // includes Readable, ReadableStream, etc.
|
|
79
|
+
) {
|
|
80
|
+
for await (const chunk of value) {
|
|
81
|
+
parts.push(...(await getBytes(chunk))); // TODO, consider validating?
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const constructor = value?.constructor?.name;
|
|
86
|
+
throw new Error(`Unexpected data type: ${typeof value}${constructor ? `; constructor: ${constructor}` : ''}${propsForError(value)}`);
|
|
87
|
+
}
|
|
88
|
+
return parts;
|
|
89
|
+
}
|
|
90
|
+
function propsForError(value) {
|
|
91
|
+
if (typeof value !== 'object' || value === null)
|
|
92
|
+
return '';
|
|
93
|
+
const props = Object.getOwnPropertyNames(value);
|
|
94
|
+
return `; props: [${props.map((p) => `"${p}"`).join(', ')}]`;
|
|
95
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createForm = exports.multipartFormRequestOptions = exports.maybeMultipartFormRequestOptions = exports.isAsyncIterable = exports.checkFileSupport = void 0;
|
|
4
|
+
exports.makeFile = makeFile;
|
|
5
|
+
exports.getName = getName;
|
|
6
|
+
const shims_1 = require("./shims");
|
|
7
|
+
const checkFileSupport = () => {
|
|
8
|
+
if (typeof File === 'undefined') {
|
|
9
|
+
const { process } = globalThis;
|
|
10
|
+
const isOldNode = typeof process?.versions?.node === 'string' && parseInt(process.versions.node.split('.')) < 20;
|
|
11
|
+
throw new Error('`File` is not defined as a global, which is required for file uploads.' +
|
|
12
|
+
(isOldNode ?
|
|
13
|
+
" Update to Node 20 LTS or newer, or set `globalThis.File` to `import('node:buffer').File`."
|
|
14
|
+
: ''));
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
exports.checkFileSupport = checkFileSupport;
|
|
18
|
+
/**
|
|
19
|
+
* Construct a `File` instance. This is used to ensure a helpful error is thrown
|
|
20
|
+
* for environments that don't define a global `File` yet.
|
|
21
|
+
*/
|
|
22
|
+
function makeFile(fileBits, fileName, options) {
|
|
23
|
+
(0, exports.checkFileSupport)();
|
|
24
|
+
return new File(fileBits, fileName ?? 'unknown_file', options);
|
|
25
|
+
}
|
|
26
|
+
function getName(value, stripPath) {
|
|
27
|
+
const val = (typeof value === 'object' &&
|
|
28
|
+
value !== null &&
|
|
29
|
+
(('name' in value && value.name && String(value.name)) ||
|
|
30
|
+
('url' in value && value.url && String(value.url)) ||
|
|
31
|
+
('filename' in value && value.filename && String(value.filename)) ||
|
|
32
|
+
('path' in value && value.path && String(value.path)))) ||
|
|
33
|
+
'';
|
|
34
|
+
return stripPath ? val.split(/[\\/]/).pop() || undefined : val;
|
|
35
|
+
}
|
|
36
|
+
const isAsyncIterable = (value) => value != null && typeof value === 'object' && typeof value[Symbol.asyncIterator] === 'function';
|
|
37
|
+
exports.isAsyncIterable = isAsyncIterable;
|
|
38
|
+
/**
|
|
39
|
+
* Returns a multipart/form-data request if any part of the given request body contains a File / Blob value.
|
|
40
|
+
* Otherwise returns the request as is.
|
|
41
|
+
*/
|
|
42
|
+
const maybeMultipartFormRequestOptions = async (opts, fetch) => {
|
|
43
|
+
if (!hasUploadableValue(opts.body))
|
|
44
|
+
return opts;
|
|
45
|
+
return { ...opts, body: await (0, exports.createForm)(opts.body, fetch) };
|
|
46
|
+
};
|
|
47
|
+
exports.maybeMultipartFormRequestOptions = maybeMultipartFormRequestOptions;
|
|
48
|
+
const multipartFormRequestOptions = async (opts, fetch, stripFilenames = true) => {
|
|
49
|
+
return { ...opts, body: await (0, exports.createForm)(opts.body, fetch, stripFilenames) };
|
|
50
|
+
};
|
|
51
|
+
exports.multipartFormRequestOptions = multipartFormRequestOptions;
|
|
52
|
+
const supportsFormDataMap = /* @__PURE__ */ new WeakMap();
|
|
53
|
+
/**
|
|
54
|
+
* node-fetch doesn't support the global FormData object in recent node versions. Instead of sending
|
|
55
|
+
* properly-encoded form data, it just stringifies the object, resulting in a request body of "[object FormData]".
|
|
56
|
+
* This function detects if the fetch function provided supports the global FormData object to avoid
|
|
57
|
+
* confusing error messages later on.
|
|
58
|
+
*/
|
|
59
|
+
function supportsFormData(fetchObject) {
|
|
60
|
+
const fetch = typeof fetchObject === 'function' ? fetchObject : fetchObject.fetch;
|
|
61
|
+
const cached = supportsFormDataMap.get(fetch);
|
|
62
|
+
if (cached)
|
|
63
|
+
return cached;
|
|
64
|
+
const promise = (async () => {
|
|
65
|
+
try {
|
|
66
|
+
const FetchResponse = ('Response' in fetch ?
|
|
67
|
+
fetch.Response
|
|
68
|
+
: (await fetch('data:,')).constructor);
|
|
69
|
+
const data = new FormData();
|
|
70
|
+
if (data.toString() === (await new FetchResponse(data).text())) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// avoid false negatives
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
})();
|
|
80
|
+
supportsFormDataMap.set(fetch, promise);
|
|
81
|
+
return promise;
|
|
82
|
+
}
|
|
83
|
+
const createForm = async (body, fetch, stripFilenames = true) => {
|
|
84
|
+
if (!(await supportsFormData(fetch))) {
|
|
85
|
+
throw new TypeError('The provided fetch function does not support file uploads with the current global FormData class.');
|
|
86
|
+
}
|
|
87
|
+
const form = new FormData();
|
|
88
|
+
await Promise.all(Object.entries(body || {}).map(([key, value]) => addFormValue(form, key, value, stripFilenames)));
|
|
89
|
+
return form;
|
|
90
|
+
};
|
|
91
|
+
exports.createForm = createForm;
|
|
92
|
+
// Blob, not File: bare Blobs and Bun.file() results don't inherit from File.
|
|
93
|
+
const isUploadable = (value) => typeof value === 'object' &&
|
|
94
|
+
value !== null &&
|
|
95
|
+
(value instanceof Response || (0, exports.isAsyncIterable)(value) || value instanceof Blob);
|
|
96
|
+
const hasUploadableValue = (value) => {
|
|
97
|
+
if (isUploadable(value))
|
|
98
|
+
return true;
|
|
99
|
+
if (Array.isArray(value))
|
|
100
|
+
return value.some(hasUploadableValue);
|
|
101
|
+
if (value && typeof value === 'object') {
|
|
102
|
+
for (const k in value) {
|
|
103
|
+
if (hasUploadableValue(value[k]))
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
};
|
|
109
|
+
const addFormValue = async (form, key, value, stripFilenames) => {
|
|
110
|
+
if (value === undefined)
|
|
111
|
+
return;
|
|
112
|
+
if (value == null) {
|
|
113
|
+
throw new TypeError(`Received null for "${key}"; to pass null in FormData, you must use the string 'null'`);
|
|
114
|
+
}
|
|
115
|
+
// TODO: make nested formats configurable
|
|
116
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
117
|
+
form.append(key, String(value));
|
|
118
|
+
}
|
|
119
|
+
else if (value instanceof Response) {
|
|
120
|
+
let options = {};
|
|
121
|
+
const contentType = value.headers.get('Content-Type');
|
|
122
|
+
if (contentType) {
|
|
123
|
+
options = { type: contentType };
|
|
124
|
+
}
|
|
125
|
+
form.append(key, makeFile([await value.blob()], getName(value, stripFilenames), options));
|
|
126
|
+
}
|
|
127
|
+
else if ((0, exports.isAsyncIterable)(value)) {
|
|
128
|
+
form.append(key, makeFile([await new Response((0, shims_1.ReadableStreamFrom)(value)).blob()], getName(value, stripFilenames)));
|
|
129
|
+
}
|
|
130
|
+
else if (value instanceof Blob) {
|
|
131
|
+
form.append(key, makeFile([value], getName(value, stripFilenames) || undefined, { type: value.type }));
|
|
132
|
+
}
|
|
133
|
+
else if (Array.isArray(value)) {
|
|
134
|
+
await Promise.all(value.map((entry) => addFormValue(form, key + '[]', entry, stripFilenames)));
|
|
135
|
+
}
|
|
136
|
+
else if (typeof value.then === 'function') {
|
|
137
|
+
throw new TypeError(`Received a Promise for "${key}"; await it first, e.g. \`await toFile(...)\``);
|
|
138
|
+
}
|
|
139
|
+
else if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
|
|
140
|
+
throw new TypeError(`Received ${value.constructor.name} for "${key}"; to upload raw bytes, wrap them with \`await toFile(bytes, 'filename')\``);
|
|
141
|
+
}
|
|
142
|
+
else if (typeof value === 'object') {
|
|
143
|
+
await Promise.all(Object.entries(value).map(([name, prop]) => addFormValue(form, `${key}[${name}]`, prop, stripFilenames)));
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
throw new TypeError(`Invalid value given to form, expected a string, number, boolean, object, Array, File or Blob but got ${value} instead`);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.linkAbort = linkAbort;
|
|
4
|
+
/**
|
|
5
|
+
* Chain an external {@link AbortSignal} into a local {@link AbortController}:
|
|
6
|
+
* the controller aborts whenever `external` aborts (synchronously if it is
|
|
7
|
+
* already aborted).
|
|
8
|
+
*
|
|
9
|
+
* Returns a cleanup function that detaches the listener. Callers MUST invoke it
|
|
10
|
+
* on their normal teardown path — `{ once: true }` only removes the listener if
|
|
11
|
+
* abort actually fires, so a long-lived `external` signal would otherwise leak one
|
|
12
|
+
* listener per controller.
|
|
13
|
+
*/
|
|
14
|
+
function linkAbort(external, controller) {
|
|
15
|
+
if (!external)
|
|
16
|
+
return () => { };
|
|
17
|
+
if (external.aborted) {
|
|
18
|
+
controller.abort();
|
|
19
|
+
return () => { };
|
|
20
|
+
}
|
|
21
|
+
const onAbort = () => controller.abort();
|
|
22
|
+
external.addEventListener('abort', onAbort);
|
|
23
|
+
return () => external.removeEventListener('abort', onAbort);
|
|
24
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AsyncQueue = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Single-consumer async queue that bridges background producers to an
|
|
6
|
+
* `AsyncIterator`-style reader. Producers `push()` items; the consumer awaits
|
|
7
|
+
* `next()`. `close()` is idempotent and wakes any pending `next()` with
|
|
8
|
+
* `done: true`. `tryShift()` synchronously drains remaining items after
|
|
9
|
+
* iteration has been signalled to stop.
|
|
10
|
+
*/
|
|
11
|
+
class AsyncQueue {
|
|
12
|
+
#items = [];
|
|
13
|
+
#waiters = [];
|
|
14
|
+
#closed = false;
|
|
15
|
+
/** Enqueue an item, or hand it directly to a waiting reader. Returns `false` once closed. */
|
|
16
|
+
push(item) {
|
|
17
|
+
if (this.#closed)
|
|
18
|
+
return false;
|
|
19
|
+
const w = this.#waiters.shift();
|
|
20
|
+
if (w)
|
|
21
|
+
w({ done: false, value: item });
|
|
22
|
+
else
|
|
23
|
+
this.#items.push(item);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
/** Mark the queue done. Idempotent; wakes every pending reader with `done: true`. */
|
|
27
|
+
close() {
|
|
28
|
+
if (this.#closed)
|
|
29
|
+
return;
|
|
30
|
+
this.#closed = true;
|
|
31
|
+
while (this.#waiters.length > 0) {
|
|
32
|
+
const w = this.#waiters.shift();
|
|
33
|
+
w({ done: true, value: undefined });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resolve with the next item, or `done: true` once the queue is closed and
|
|
38
|
+
* drained. When `signal` is supplied, aborting it resolves a pending read
|
|
39
|
+
* with `done: true` (cancellation is pushed down here rather than handled by
|
|
40
|
+
* an outer `Promise.race`).
|
|
41
|
+
*/
|
|
42
|
+
next(signal) {
|
|
43
|
+
if (this.#items.length > 0) {
|
|
44
|
+
return Promise.resolve({ done: false, value: this.#items.shift() });
|
|
45
|
+
}
|
|
46
|
+
if (this.#closed || signal?.aborted) {
|
|
47
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
48
|
+
}
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
const waiter = (r) => {
|
|
51
|
+
signal?.removeEventListener('abort', onAbort);
|
|
52
|
+
resolve(r);
|
|
53
|
+
};
|
|
54
|
+
const onAbort = () => {
|
|
55
|
+
const idx = this.#waiters.indexOf(waiter);
|
|
56
|
+
if (idx >= 0)
|
|
57
|
+
this.#waiters.splice(idx, 1);
|
|
58
|
+
resolve({ done: true, value: undefined });
|
|
59
|
+
};
|
|
60
|
+
this.#waiters.push(waiter);
|
|
61
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** Synchronously remove and return the next buffered item, or `undefined` if empty. */
|
|
65
|
+
tryShift() {
|
|
66
|
+
return this.#items.shift();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.AsyncQueue = AsyncQueue;
|