@wabot-dev/framework 0.1.0-beta.11 → 0.1.0-beta.13

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.
Files changed (61) hide show
  1. package/dist/src/ai/claude/ClaudeChatBotAdapter.js +115 -0
  2. package/dist/src/channels/whatsapp/WhatsApp.js +2 -2
  3. package/dist/src/channels/whatsapp/WhatsAppSender.js +10 -1
  4. package/dist/src/channels/whatsapp/WhatsAppSenderByCloudApi.js +3 -9
  5. package/dist/src/channels/whatsapp/WhatsAppSenderByDevConnection.js +6 -11
  6. package/dist/src/core/{Persistent.js → Entity.js} +24 -9
  7. package/dist/src/core/Storable.js +8 -0
  8. package/dist/src/core/chat/Chat.js +2 -2
  9. package/dist/src/core/chat/ChatItem.js +2 -2
  10. package/dist/src/core/user/User.js +2 -2
  11. package/dist/src/error/CustomError.js +1 -0
  12. package/dist/src/index.d.ts +250 -181
  13. package/dist/src/index.js +13 -9
  14. package/dist/src/node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.js +221 -0
  15. package/dist/src/node_modules/@anthropic-ai/sdk/client.js +540 -0
  16. package/dist/src/node_modules/@anthropic-ai/sdk/core/api-promise.js +74 -0
  17. package/dist/src/node_modules/@anthropic-ai/sdk/core/error.js +100 -0
  18. package/dist/src/node_modules/@anthropic-ai/sdk/core/pagination.js +119 -0
  19. package/dist/src/node_modules/@anthropic-ai/sdk/core/resource.js +8 -0
  20. package/dist/src/node_modules/@anthropic-ai/sdk/core/streaming.js +283 -0
  21. package/dist/src/node_modules/@anthropic-ai/sdk/internal/constants.js +16 -0
  22. package/dist/src/node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.js +37 -0
  23. package/dist/src/node_modules/@anthropic-ai/sdk/internal/decoders/line.js +110 -0
  24. package/dist/src/node_modules/@anthropic-ai/sdk/internal/detect-platform.js +159 -0
  25. package/dist/src/node_modules/@anthropic-ai/sdk/internal/errors.js +37 -0
  26. package/dist/src/node_modules/@anthropic-ai/sdk/internal/headers.js +71 -0
  27. package/dist/src/node_modules/@anthropic-ai/sdk/internal/parse.js +53 -0
  28. package/dist/src/node_modules/@anthropic-ai/sdk/internal/request-options.js +11 -0
  29. package/dist/src/node_modules/@anthropic-ai/sdk/internal/shims.js +86 -0
  30. package/dist/src/node_modules/@anthropic-ai/sdk/internal/to-file.js +94 -0
  31. package/dist/src/node_modules/@anthropic-ai/sdk/internal/tslib.js +14 -0
  32. package/dist/src/node_modules/@anthropic-ai/sdk/internal/uploads.js +113 -0
  33. package/dist/src/node_modules/@anthropic-ai/sdk/internal/utils/bytes.js +27 -0
  34. package/dist/src/node_modules/@anthropic-ai/sdk/internal/utils/env.js +19 -0
  35. package/dist/src/node_modules/@anthropic-ai/sdk/internal/utils/log.js +82 -0
  36. package/dist/src/node_modules/@anthropic-ai/sdk/internal/utils/path.js +76 -0
  37. package/dist/src/node_modules/@anthropic-ai/sdk/internal/utils/sleep.js +4 -0
  38. package/dist/src/node_modules/@anthropic-ai/sdk/internal/utils/uuid.js +16 -0
  39. package/dist/src/node_modules/@anthropic-ai/sdk/internal/utils/values.js +48 -0
  40. package/dist/src/node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.js +588 -0
  41. package/dist/src/node_modules/@anthropic-ai/sdk/lib/MessageStream.js +582 -0
  42. package/dist/src/node_modules/@anthropic-ai/sdk/resources/beta/beta.js +19 -0
  43. package/dist/src/node_modules/@anthropic-ai/sdk/resources/beta/files.js +120 -0
  44. package/dist/src/node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.js +202 -0
  45. package/dist/src/node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.js +85 -0
  46. package/dist/src/node_modules/@anthropic-ai/sdk/resources/beta/models.js +58 -0
  47. package/dist/src/node_modules/@anthropic-ai/sdk/resources/completions.js +21 -0
  48. package/dist/src/node_modules/@anthropic-ai/sdk/resources/messages/batches.js +151 -0
  49. package/dist/src/node_modules/@anthropic-ai/sdk/resources/messages/messages.js +71 -0
  50. package/dist/src/node_modules/@anthropic-ai/sdk/resources/models.js +43 -0
  51. package/dist/src/node_modules/@anthropic-ai/sdk/version.js +3 -0
  52. package/dist/src/pre-made/repository/chat/ram/RamChatRepository.js +1 -1
  53. package/dist/src/repository/pg/PgCrudRepository.js +2 -2
  54. package/dist/src/repository/pg/PgRepositoryBase.js +2 -2
  55. package/dist/src/rest-controller/metadata/@middleware.js +16 -0
  56. package/dist/src/rest-controller/metadata/RestControllerMetadataStore.js +13 -0
  57. package/dist/src/rest-controller/runRestControllers.js +30 -22
  58. package/dist/src/server/prepareChatContainer.js +2 -2
  59. package/dist/src/validation/metadata/@isModel.js +18 -0
  60. package/dist/src/validation/validators/validateModel.js +2 -6
  61. package/package.json +2 -1
@@ -0,0 +1,159 @@
1
+ import { VERSION } from '../version.js';
2
+
3
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
4
+ const isRunningInBrowser = () => {
5
+ return (
6
+ // @ts-ignore
7
+ typeof window !== 'undefined' &&
8
+ // @ts-ignore
9
+ typeof window.document !== 'undefined' &&
10
+ // @ts-ignore
11
+ typeof navigator !== 'undefined');
12
+ };
13
+ /**
14
+ * Note this does not detect 'browser'; for that, use getBrowserInfo().
15
+ */
16
+ function getDetectedPlatform() {
17
+ if (typeof Deno !== 'undefined' && Deno.build != null) {
18
+ return 'deno';
19
+ }
20
+ if (typeof EdgeRuntime !== 'undefined') {
21
+ return 'edge';
22
+ }
23
+ if (Object.prototype.toString.call(typeof globalThis.process !== 'undefined' ? globalThis.process : 0) === '[object process]') {
24
+ return 'node';
25
+ }
26
+ return 'unknown';
27
+ }
28
+ const getPlatformProperties = () => {
29
+ const detectedPlatform = getDetectedPlatform();
30
+ if (detectedPlatform === 'deno') {
31
+ return {
32
+ 'X-Stainless-Lang': 'js',
33
+ 'X-Stainless-Package-Version': VERSION,
34
+ 'X-Stainless-OS': normalizePlatform(Deno.build.os),
35
+ 'X-Stainless-Arch': normalizeArch(Deno.build.arch),
36
+ 'X-Stainless-Runtime': 'deno',
37
+ 'X-Stainless-Runtime-Version': typeof Deno.version === 'string' ? Deno.version : Deno.version?.deno ?? 'unknown',
38
+ };
39
+ }
40
+ if (typeof EdgeRuntime !== 'undefined') {
41
+ return {
42
+ 'X-Stainless-Lang': 'js',
43
+ 'X-Stainless-Package-Version': VERSION,
44
+ 'X-Stainless-OS': 'Unknown',
45
+ 'X-Stainless-Arch': `other:${EdgeRuntime}`,
46
+ 'X-Stainless-Runtime': 'edge',
47
+ 'X-Stainless-Runtime-Version': globalThis.process.version,
48
+ };
49
+ }
50
+ // Check if Node.js
51
+ if (detectedPlatform === 'node') {
52
+ return {
53
+ 'X-Stainless-Lang': 'js',
54
+ 'X-Stainless-Package-Version': VERSION,
55
+ 'X-Stainless-OS': normalizePlatform(globalThis.process.platform ?? 'unknown'),
56
+ 'X-Stainless-Arch': normalizeArch(globalThis.process.arch ?? 'unknown'),
57
+ 'X-Stainless-Runtime': 'node',
58
+ 'X-Stainless-Runtime-Version': globalThis.process.version ?? 'unknown',
59
+ };
60
+ }
61
+ const browserInfo = getBrowserInfo();
62
+ if (browserInfo) {
63
+ return {
64
+ 'X-Stainless-Lang': 'js',
65
+ 'X-Stainless-Package-Version': VERSION,
66
+ 'X-Stainless-OS': 'Unknown',
67
+ 'X-Stainless-Arch': 'unknown',
68
+ 'X-Stainless-Runtime': `browser:${browserInfo.browser}`,
69
+ 'X-Stainless-Runtime-Version': browserInfo.version,
70
+ };
71
+ }
72
+ // TODO add support for Cloudflare workers, etc.
73
+ return {
74
+ 'X-Stainless-Lang': 'js',
75
+ 'X-Stainless-Package-Version': VERSION,
76
+ 'X-Stainless-OS': 'Unknown',
77
+ 'X-Stainless-Arch': 'unknown',
78
+ 'X-Stainless-Runtime': 'unknown',
79
+ 'X-Stainless-Runtime-Version': 'unknown',
80
+ };
81
+ };
82
+ // Note: modified from https://github.com/JS-DevTools/host-environment/blob/b1ab79ecde37db5d6e163c050e54fe7d287d7c92/src/isomorphic.browser.ts
83
+ function getBrowserInfo() {
84
+ if (typeof navigator === 'undefined' || !navigator) {
85
+ return null;
86
+ }
87
+ // NOTE: The order matters here!
88
+ const browserPatterns = [
89
+ { key: 'edge', pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
90
+ { key: 'ie', pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
91
+ { key: 'ie', pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ },
92
+ { key: 'chrome', pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
93
+ { key: 'firefox', pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
94
+ { key: 'safari', pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ },
95
+ ];
96
+ // Find the FIRST matching browser
97
+ for (const { key, pattern } of browserPatterns) {
98
+ const match = pattern.exec(navigator.userAgent);
99
+ if (match) {
100
+ const major = match[1] || 0;
101
+ const minor = match[2] || 0;
102
+ const patch = match[3] || 0;
103
+ return { browser: key, version: `${major}.${minor}.${patch}` };
104
+ }
105
+ }
106
+ return null;
107
+ }
108
+ const normalizeArch = (arch) => {
109
+ // Node docs:
110
+ // - https://nodejs.org/api/process.html#processarch
111
+ // Deno docs:
112
+ // - https://doc.deno.land/deno/stable/~/Deno.build
113
+ if (arch === 'x32')
114
+ return 'x32';
115
+ if (arch === 'x86_64' || arch === 'x64')
116
+ return 'x64';
117
+ if (arch === 'arm')
118
+ return 'arm';
119
+ if (arch === 'aarch64' || arch === 'arm64')
120
+ return 'arm64';
121
+ if (arch)
122
+ return `other:${arch}`;
123
+ return 'unknown';
124
+ };
125
+ const normalizePlatform = (platform) => {
126
+ // Node platforms:
127
+ // - https://nodejs.org/api/process.html#processplatform
128
+ // Deno platforms:
129
+ // - https://doc.deno.land/deno/stable/~/Deno.build
130
+ // - https://github.com/denoland/deno/issues/14799
131
+ platform = platform.toLowerCase();
132
+ // NOTE: this iOS check is untested and may not work
133
+ // Node does not work natively on IOS, there is a fork at
134
+ // https://github.com/nodejs-mobile/nodejs-mobile
135
+ // however it is unknown at the time of writing how to detect if it is running
136
+ if (platform.includes('ios'))
137
+ return 'iOS';
138
+ if (platform === 'android')
139
+ return 'Android';
140
+ if (platform === 'darwin')
141
+ return 'MacOS';
142
+ if (platform === 'win32')
143
+ return 'Windows';
144
+ if (platform === 'freebsd')
145
+ return 'FreeBSD';
146
+ if (platform === 'openbsd')
147
+ return 'OpenBSD';
148
+ if (platform === 'linux')
149
+ return 'Linux';
150
+ if (platform)
151
+ return `Other:${platform}`;
152
+ return 'Unknown';
153
+ };
154
+ let _platformHeaders;
155
+ const getPlatformHeaders = () => {
156
+ return (_platformHeaders ?? (_platformHeaders = getPlatformProperties()));
157
+ };
158
+
159
+ export { getPlatformHeaders, isRunningInBrowser };
@@ -0,0 +1,37 @@
1
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+ function isAbortError(err) {
3
+ return (typeof err === 'object' &&
4
+ err !== null &&
5
+ // Spec-compliant fetch implementations
6
+ (('name' in err && err.name === 'AbortError') ||
7
+ // Expo fetch
8
+ ('message' in err && String(err.message).includes('FetchRequestCanceledException'))));
9
+ }
10
+ const castToError = (err) => {
11
+ if (err instanceof Error)
12
+ return err;
13
+ if (typeof err === 'object' && err !== null) {
14
+ try {
15
+ if (Object.prototype.toString.call(err) === '[object Error]') {
16
+ // @ts-ignore - not all envs have native support for cause yet
17
+ const error = new Error(err.message, err.cause ? { cause: err.cause } : {});
18
+ if (err.stack)
19
+ error.stack = err.stack;
20
+ // @ts-ignore - not all envs have native support for cause yet
21
+ if (err.cause && !error.cause)
22
+ error.cause = err.cause;
23
+ if (err.name)
24
+ error.name = err.name;
25
+ return error;
26
+ }
27
+ }
28
+ catch { }
29
+ try {
30
+ return new Error(JSON.stringify(err));
31
+ }
32
+ catch { }
33
+ }
34
+ return new Error(err);
35
+ };
36
+
37
+ export { castToError, isAbortError };
@@ -0,0 +1,71 @@
1
+ import { isReadonlyArray } from './utils/values.js';
2
+
3
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
4
+ const brand_privateNullableHeaders = Symbol.for('brand.privateNullableHeaders');
5
+ function* iterateHeaders(headers) {
6
+ if (!headers)
7
+ return;
8
+ if (brand_privateNullableHeaders in headers) {
9
+ const { values, nulls } = headers;
10
+ yield* values.entries();
11
+ for (const name of nulls) {
12
+ yield [name, null];
13
+ }
14
+ return;
15
+ }
16
+ let shouldClear = false;
17
+ let iter;
18
+ if (headers instanceof Headers) {
19
+ iter = headers.entries();
20
+ }
21
+ else if (isReadonlyArray(headers)) {
22
+ iter = headers;
23
+ }
24
+ else {
25
+ shouldClear = true;
26
+ iter = Object.entries(headers ?? {});
27
+ }
28
+ for (let row of iter) {
29
+ const name = row[0];
30
+ if (typeof name !== 'string')
31
+ throw new TypeError('expected header name to be a string');
32
+ const values = isReadonlyArray(row[1]) ? row[1] : [row[1]];
33
+ let didClear = false;
34
+ for (const value of values) {
35
+ if (value === undefined)
36
+ continue;
37
+ // Objects keys always overwrite older headers, they never append.
38
+ // Yield a null to clear the header before adding the new values.
39
+ if (shouldClear && !didClear) {
40
+ didClear = true;
41
+ yield [name, null];
42
+ }
43
+ yield [name, value];
44
+ }
45
+ }
46
+ }
47
+ const buildHeaders = (newHeaders) => {
48
+ const targetHeaders = new Headers();
49
+ const nullHeaders = new Set();
50
+ for (const headers of newHeaders) {
51
+ const seenHeaders = new Set();
52
+ for (const [name, value] of iterateHeaders(headers)) {
53
+ const lowerName = name.toLowerCase();
54
+ if (!seenHeaders.has(lowerName)) {
55
+ targetHeaders.delete(name);
56
+ seenHeaders.add(lowerName);
57
+ }
58
+ if (value === null) {
59
+ targetHeaders.delete(name);
60
+ nullHeaders.add(lowerName);
61
+ }
62
+ else {
63
+ targetHeaders.append(name, value);
64
+ nullHeaders.delete(lowerName);
65
+ }
66
+ }
67
+ }
68
+ return { [brand_privateNullableHeaders]: true, values: targetHeaders, nulls: nullHeaders };
69
+ };
70
+
71
+ export { buildHeaders };
@@ -0,0 +1,53 @@
1
+ import { Stream } from '../core/streaming.js';
2
+ import { loggerFor, formatRequestDetails } from './utils/log.js';
3
+
4
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
5
+ async function defaultParseResponse(client, props) {
6
+ const { response, requestLogID, retryOfRequestLogID, startTime } = props;
7
+ const body = await (async () => {
8
+ if (props.options.stream) {
9
+ loggerFor(client).debug('response', response.status, response.url, response.headers, response.body);
10
+ // Note: there is an invariant here that isn't represented in the type system
11
+ // that if you set `stream: true` the response type must also be `Stream<T>`
12
+ if (props.options.__streamClass) {
13
+ return props.options.__streamClass.fromSSEResponse(response, props.controller);
14
+ }
15
+ return Stream.fromSSEResponse(response, props.controller);
16
+ }
17
+ // fetch refuses to read the body when the status code is 204.
18
+ if (response.status === 204) {
19
+ return null;
20
+ }
21
+ if (props.options.__binaryResponse) {
22
+ return response;
23
+ }
24
+ const contentType = response.headers.get('content-type');
25
+ const mediaType = contentType?.split(';')[0]?.trim();
26
+ const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+json');
27
+ if (isJSON) {
28
+ const json = await response.json();
29
+ return addRequestID(json, response);
30
+ }
31
+ const text = await response.text();
32
+ return text;
33
+ })();
34
+ loggerFor(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails({
35
+ retryOfRequestLogID,
36
+ url: response.url,
37
+ status: response.status,
38
+ body,
39
+ durationMs: Date.now() - startTime,
40
+ }));
41
+ return body;
42
+ }
43
+ function addRequestID(value, response) {
44
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
45
+ return value;
46
+ }
47
+ return Object.defineProperty(value, '_request_id', {
48
+ value: response.headers.get('request-id'),
49
+ enumerable: false,
50
+ });
51
+ }
52
+
53
+ export { addRequestID, defaultParseResponse };
@@ -0,0 +1,11 @@
1
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+ const FallbackEncoder = ({ headers, body }) => {
3
+ return {
4
+ bodyHeaders: {
5
+ 'content-type': 'application/json',
6
+ },
7
+ body: JSON.stringify(body),
8
+ };
9
+ };
10
+
11
+ export { FallbackEncoder };
@@ -0,0 +1,86 @@
1
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+ function getDefaultFetch() {
3
+ if (typeof fetch !== 'undefined') {
4
+ return fetch;
5
+ }
6
+ throw new Error('`fetch` is not defined as a global; Either pass `fetch` to the client, `new Anthropic({ fetch })` or polyfill the global, `globalThis.fetch = fetch`');
7
+ }
8
+ function makeReadableStream(...args) {
9
+ const ReadableStream = globalThis.ReadableStream;
10
+ if (typeof ReadableStream === 'undefined') {
11
+ // Note: All of the platforms / runtimes we officially support already define
12
+ // `ReadableStream` as a global, so this should only ever be hit on unsupported runtimes.
13
+ throw new Error('`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`');
14
+ }
15
+ return new ReadableStream(...args);
16
+ }
17
+ function ReadableStreamFrom(iterable) {
18
+ let iter = Symbol.asyncIterator in iterable ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
19
+ return makeReadableStream({
20
+ start() { },
21
+ async pull(controller) {
22
+ const { done, value } = await iter.next();
23
+ if (done) {
24
+ controller.close();
25
+ }
26
+ else {
27
+ controller.enqueue(value);
28
+ }
29
+ },
30
+ async cancel() {
31
+ await iter.return?.();
32
+ },
33
+ });
34
+ }
35
+ /**
36
+ * Most browsers don't yet have async iterable support for ReadableStream,
37
+ * and Node has a very different way of reading bytes from its "ReadableStream".
38
+ *
39
+ * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490
40
+ */
41
+ function ReadableStreamToAsyncIterable(stream) {
42
+ if (stream[Symbol.asyncIterator])
43
+ return stream;
44
+ const reader = stream.getReader();
45
+ return {
46
+ async next() {
47
+ try {
48
+ const result = await reader.read();
49
+ if (result?.done)
50
+ reader.releaseLock(); // release lock when stream becomes closed
51
+ return result;
52
+ }
53
+ catch (e) {
54
+ reader.releaseLock(); // release lock when stream becomes errored
55
+ throw e;
56
+ }
57
+ },
58
+ async return() {
59
+ const cancelPromise = reader.cancel();
60
+ reader.releaseLock();
61
+ await cancelPromise;
62
+ return { done: true, value: undefined };
63
+ },
64
+ [Symbol.asyncIterator]() {
65
+ return this;
66
+ },
67
+ };
68
+ }
69
+ /**
70
+ * Cancels a ReadableStream we don't need to consume.
71
+ * See https://undici.nodejs.org/#/?id=garbage-collection
72
+ */
73
+ async function CancelReadableStream(stream) {
74
+ if (stream === null || typeof stream !== 'object')
75
+ return;
76
+ if (stream[Symbol.asyncIterator]) {
77
+ await stream[Symbol.asyncIterator]().return?.();
78
+ return;
79
+ }
80
+ const reader = stream.getReader();
81
+ const cancelPromise = reader.cancel();
82
+ reader.releaseLock();
83
+ await cancelPromise;
84
+ }
85
+
86
+ export { CancelReadableStream, ReadableStreamFrom, ReadableStreamToAsyncIterable, getDefaultFetch, makeReadableStream };
@@ -0,0 +1,94 @@
1
+ import { checkFileSupport, getName, makeFile, isAsyncIterable } from './uploads.js';
2
+
3
+ /**
4
+ * This check adds the arrayBuffer() method type because it is available and used at runtime
5
+ */
6
+ const isBlobLike = (value) => value != null &&
7
+ typeof value === 'object' &&
8
+ typeof value.size === 'number' &&
9
+ typeof value.type === 'string' &&
10
+ typeof value.text === 'function' &&
11
+ typeof value.slice === 'function' &&
12
+ typeof value.arrayBuffer === 'function';
13
+ /**
14
+ * This check adds the arrayBuffer() method type because it is available and used at runtime
15
+ */
16
+ const isFileLike = (value) => value != null &&
17
+ typeof value === 'object' &&
18
+ typeof value.name === 'string' &&
19
+ typeof value.lastModified === 'number' &&
20
+ isBlobLike(value);
21
+ const isResponseLike = (value) => value != null &&
22
+ typeof value === 'object' &&
23
+ typeof value.url === 'string' &&
24
+ typeof value.blob === 'function';
25
+ /**
26
+ * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats
27
+ * @param value the raw content of the file. Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s
28
+ * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible
29
+ * @param {Object=} options additional properties
30
+ * @param {string=} options.type the MIME type of the content
31
+ * @param {number=} options.lastModified the last modified timestamp
32
+ * @returns a {@link File} with the given properties
33
+ */
34
+ async function toFile(value, name, options) {
35
+ checkFileSupport();
36
+ // If it's a promise, resolve it.
37
+ value = await value;
38
+ name || (name = getName(value));
39
+ // If we've been given a `File` we don't need to do anything if the name / options
40
+ // have not been customised.
41
+ if (isFileLike(value)) {
42
+ if (value instanceof File && name == null && options == null) {
43
+ return value;
44
+ }
45
+ return makeFile([await value.arrayBuffer()], name ?? value.name, {
46
+ type: value.type,
47
+ lastModified: value.lastModified,
48
+ ...options,
49
+ });
50
+ }
51
+ if (isResponseLike(value)) {
52
+ const blob = await value.blob();
53
+ name || (name = new URL(value.url).pathname.split(/[\\/]/).pop());
54
+ return makeFile(await getBytes(blob), name, options);
55
+ }
56
+ const parts = await getBytes(value);
57
+ if (!options?.type) {
58
+ const type = parts.find((part) => typeof part === 'object' && 'type' in part && part.type);
59
+ if (typeof type === 'string') {
60
+ options = { ...options, type };
61
+ }
62
+ }
63
+ return makeFile(parts, name, options);
64
+ }
65
+ async function getBytes(value) {
66
+ let parts = [];
67
+ if (typeof value === 'string' ||
68
+ ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.
69
+ value instanceof ArrayBuffer) {
70
+ parts.push(value);
71
+ }
72
+ else if (isBlobLike(value)) {
73
+ parts.push(value instanceof Blob ? value : await value.arrayBuffer());
74
+ }
75
+ else if (isAsyncIterable(value) // includes Readable, ReadableStream, etc.
76
+ ) {
77
+ for await (const chunk of value) {
78
+ parts.push(...(await getBytes(chunk))); // TODO, consider validating?
79
+ }
80
+ }
81
+ else {
82
+ const constructor = value?.constructor?.name;
83
+ throw new Error(`Unexpected data type: ${typeof value}${constructor ? `; constructor: ${constructor}` : ''}${propsForError(value)}`);
84
+ }
85
+ return parts;
86
+ }
87
+ function propsForError(value) {
88
+ if (typeof value !== 'object' || value === null)
89
+ return '';
90
+ const props = Object.getOwnPropertyNames(value);
91
+ return `; props: [${props.map((p) => `"${p}"`).join(', ')}]`;
92
+ }
93
+
94
+ export { toFile };
@@ -0,0 +1,14 @@
1
+ function __classPrivateFieldSet(receiver, state, value, kind, f) {
2
+ if (typeof state === "function" ? receiver !== state || true : !state.has(receiver))
3
+ throw new TypeError("Cannot write private member to an object whose class did not declare it");
4
+ return state.set(receiver, value), value;
5
+ }
6
+ function __classPrivateFieldGet(receiver, state, kind, f) {
7
+ if (kind === "a" && !f)
8
+ throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
10
+ throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ }
13
+
14
+ export { __classPrivateFieldGet, __classPrivateFieldSet };
@@ -0,0 +1,113 @@
1
+ import { ReadableStreamFrom } from './shims.js';
2
+
3
+ const checkFileSupport = () => {
4
+ if (typeof File === 'undefined') {
5
+ const { process } = globalThis;
6
+ const isOldNode = typeof process?.versions?.node === 'string' && parseInt(process.versions.node.split('.')) < 20;
7
+ throw new Error('`File` is not defined as a global, which is required for file uploads.' +
8
+ (isOldNode ?
9
+ " Update to Node 20 LTS or newer, or set `globalThis.File` to `import('node:buffer').File`."
10
+ : ''));
11
+ }
12
+ };
13
+ /**
14
+ * Construct a `File` instance. This is used to ensure a helpful error is thrown
15
+ * for environments that don't define a global `File` yet.
16
+ */
17
+ function makeFile(fileBits, fileName, options) {
18
+ checkFileSupport();
19
+ return new File(fileBits, fileName ?? 'unknown_file', options);
20
+ }
21
+ function getName(value) {
22
+ return (((typeof value === 'object' &&
23
+ value !== null &&
24
+ (('name' in value && value.name && String(value.name)) ||
25
+ ('url' in value && value.url && String(value.url)) ||
26
+ ('filename' in value && value.filename && String(value.filename)) ||
27
+ ('path' in value && value.path && String(value.path)))) ||
28
+ '')
29
+ .split(/[\\/]/)
30
+ .pop() || undefined);
31
+ }
32
+ const isAsyncIterable = (value) => value != null && typeof value === 'object' && typeof value[Symbol.asyncIterator] === 'function';
33
+ const multipartFormRequestOptions = async (opts, fetch) => {
34
+ return { ...opts, body: await createForm(opts.body, fetch) };
35
+ };
36
+ const supportsFormDataMap = /* @__PURE__ */ new WeakMap();
37
+ /**
38
+ * node-fetch doesn't support the global FormData object in recent node versions. Instead of sending
39
+ * properly-encoded form data, it just stringifies the object, resulting in a request body of "[object FormData]".
40
+ * This function detects if the fetch function provided supports the global FormData object to avoid
41
+ * confusing error messages later on.
42
+ */
43
+ function supportsFormData(fetchObject) {
44
+ const fetch = typeof fetchObject === 'function' ? fetchObject : fetchObject.fetch;
45
+ const cached = supportsFormDataMap.get(fetch);
46
+ if (cached)
47
+ return cached;
48
+ const promise = (async () => {
49
+ try {
50
+ const FetchResponse = ('Response' in fetch ?
51
+ fetch.Response
52
+ : (await fetch('data:,')).constructor);
53
+ const data = new FormData();
54
+ if (data.toString() === (await new FetchResponse(data).text())) {
55
+ return false;
56
+ }
57
+ return true;
58
+ }
59
+ catch {
60
+ // avoid false negatives
61
+ return true;
62
+ }
63
+ })();
64
+ supportsFormDataMap.set(fetch, promise);
65
+ return promise;
66
+ }
67
+ const createForm = async (body, fetch) => {
68
+ if (!(await supportsFormData(fetch))) {
69
+ throw new TypeError('The provided fetch function does not support file uploads with the current global FormData class.');
70
+ }
71
+ const form = new FormData();
72
+ await Promise.all(Object.entries(body || {}).map(([key, value]) => addFormValue(form, key, value)));
73
+ return form;
74
+ };
75
+ // We check for Blob not File because Bun.File doesn't inherit from File,
76
+ // but they both inherit from Blob and have a `name` property at runtime.
77
+ const isNamedBlob = (value) => value instanceof Blob && 'name' in value;
78
+ const addFormValue = async (form, key, value) => {
79
+ if (value === undefined)
80
+ return;
81
+ if (value == null) {
82
+ throw new TypeError(`Received null for "${key}"; to pass null in FormData, you must use the string 'null'`);
83
+ }
84
+ // TODO: make nested formats configurable
85
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
86
+ form.append(key, String(value));
87
+ }
88
+ else if (value instanceof Response) {
89
+ let options = {};
90
+ const contentType = value.headers.get('Content-Type');
91
+ if (contentType) {
92
+ options = { type: contentType };
93
+ }
94
+ form.append(key, makeFile([await value.blob()], getName(value), options));
95
+ }
96
+ else if (isAsyncIterable(value)) {
97
+ form.append(key, makeFile([await new Response(ReadableStreamFrom(value)).blob()], getName(value)));
98
+ }
99
+ else if (isNamedBlob(value)) {
100
+ form.append(key, makeFile([value], getName(value), { type: value.type }));
101
+ }
102
+ else if (Array.isArray(value)) {
103
+ await Promise.all(value.map((entry) => addFormValue(form, key + '[]', entry)));
104
+ }
105
+ else if (typeof value === 'object') {
106
+ await Promise.all(Object.entries(value).map(([name, prop]) => addFormValue(form, `${key}[${name}]`, prop)));
107
+ }
108
+ else {
109
+ throw new TypeError(`Invalid value given to form, expected a string, number, boolean, object, Array, File or Blob but got ${value} instead`);
110
+ }
111
+ };
112
+
113
+ export { checkFileSupport, createForm, getName, isAsyncIterable, makeFile, multipartFormRequestOptions };
@@ -0,0 +1,27 @@
1
+ function concatBytes(buffers) {
2
+ let length = 0;
3
+ for (const buffer of buffers) {
4
+ length += buffer.length;
5
+ }
6
+ const output = new Uint8Array(length);
7
+ let index = 0;
8
+ for (const buffer of buffers) {
9
+ output.set(buffer, index);
10
+ index += buffer.length;
11
+ }
12
+ return output;
13
+ }
14
+ let encodeUTF8_;
15
+ function encodeUTF8(str) {
16
+ let encoder;
17
+ return (encodeUTF8_ ??
18
+ ((encoder = new globalThis.TextEncoder()), (encodeUTF8_ = encoder.encode.bind(encoder))))(str);
19
+ }
20
+ let decodeUTF8_;
21
+ function decodeUTF8(bytes) {
22
+ let decoder;
23
+ return (decodeUTF8_ ??
24
+ ((decoder = new globalThis.TextDecoder()), (decodeUTF8_ = decoder.decode.bind(decoder))))(bytes);
25
+ }
26
+
27
+ export { concatBytes, decodeUTF8, encodeUTF8 };