@mindstudio-ai/agent 0.1.81 → 0.1.83

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/dist/index.js CHANGED
@@ -1924,6 +1924,173 @@ function resolveTable(databases, tableName, databaseHint) {
1924
1924
  );
1925
1925
  }
1926
1926
 
1927
+ // src/files/store.ts
1928
+ import { createHash, randomUUID } from "crypto";
1929
+ function toBase64(content) {
1930
+ return Buffer.from(
1931
+ typeof content === "string" ? Buffer.from(content) : content
1932
+ ).toString("base64");
1933
+ }
1934
+ function extensionFor(filename) {
1935
+ if (!filename) {
1936
+ return "";
1937
+ }
1938
+ const dot = filename.lastIndexOf(".");
1939
+ return dot > 0 ? filename.slice(dot) : "";
1940
+ }
1941
+ var Store = class {
1942
+ constructor(_store, _access, _call, _policy = {}) {
1943
+ this._store = _store;
1944
+ this._access = _access;
1945
+ this._call = _call;
1946
+ this._policy = _policy;
1947
+ }
1948
+ /** The store's access level. */
1949
+ get access() {
1950
+ return this._access;
1951
+ }
1952
+ /** Store bytes. Returns a {@link StoredFile} with a ready-to-use `url`. */
1953
+ async put(content, options) {
1954
+ const ext = extensionFor(options?.filename);
1955
+ const key = options?.key ?? (options?.contentAddressed ? `${createHash("sha256").update(content).digest("hex")}${ext}` : `${randomUUID()}${ext}`);
1956
+ const meta = await this._call("put", {
1957
+ store: this._store,
1958
+ access: this._access,
1959
+ key,
1960
+ body: toBase64(content),
1961
+ ...options?.contentType ? { contentType: options.contentType } : {}
1962
+ });
1963
+ return this._toFile(key, meta);
1964
+ }
1965
+ /** Read an object's bytes (backend / trusted context). */
1966
+ async get(key) {
1967
+ const res = await this._call("get", {
1968
+ store: this._store,
1969
+ access: this._access,
1970
+ key
1971
+ });
1972
+ return Buffer.from(res.body, "base64");
1973
+ }
1974
+ /** Metadata without downloading. Rejects if the object doesn't exist. */
1975
+ async head(key) {
1976
+ const meta = await this._call("head", {
1977
+ store: this._store,
1978
+ access: this._access,
1979
+ key
1980
+ });
1981
+ return this._toFile(key, meta);
1982
+ }
1983
+ /** Whether an object exists. */
1984
+ async exists(key) {
1985
+ try {
1986
+ await this.head(key);
1987
+ return true;
1988
+ } catch {
1989
+ return false;
1990
+ }
1991
+ }
1992
+ /** List objects in the store (optionally under `prefix`), one page at a time. */
1993
+ async list(options) {
1994
+ const res = await this._call("list", {
1995
+ store: this._store,
1996
+ access: this._access,
1997
+ ...options?.prefix ? { prefix: options.prefix } : {},
1998
+ ...options?.cursor ? { cursor: options.cursor } : {},
1999
+ ...options?.limit ? { limit: options.limit } : {}
2000
+ });
2001
+ return {
2002
+ files: (res.files ?? []).map((f) => this._toFile(f.key, f)),
2003
+ ...res.cursor ? { cursor: res.cursor } : {}
2004
+ };
2005
+ }
2006
+ /** Delete an object. No-op if it doesn't exist. */
2007
+ async delete(key) {
2008
+ await this._call("delete", {
2009
+ store: this._store,
2010
+ access: this._access,
2011
+ key
2012
+ });
2013
+ }
2014
+ /**
2015
+ * Mint an {@link UploadToken} for a **client-direct** upload — the browser
2016
+ * POSTs the file straight to storage, so the bytes never pass through the
2017
+ * platform. Return the token from a backend method and hand it to the
2018
+ * frontend's `platform.upload(token, file)`. Works for private + public stores.
2019
+ *
2020
+ * Enforced at upload time by the presigned POST: a max size (this call's
2021
+ * `maxSize`, else the store's, else the platform default) and — when
2022
+ * `contentType` is set — an exact content-type match. When the store declares
2023
+ * `contentTypes`, `contentType` must be one of them.
2024
+ *
2025
+ * @example
2026
+ * ```ts
2027
+ * // backend method
2028
+ * export async function getUploadSlot(input: { contentType: string }) {
2029
+ * return Uploads.createUploadToken({ contentType: input.contentType, maxSize: 50 * 1024 * 1024 });
2030
+ * }
2031
+ * ```
2032
+ */
2033
+ async createUploadToken(options) {
2034
+ if (options?.contentType && this._policy.contentTypes && !this._policy.contentTypes.includes(options.contentType)) {
2035
+ throw new MindStudioError(
2036
+ `contentType "${options.contentType}" is not allowed by store "${this._store}".`,
2037
+ "content_type_not_allowed",
2038
+ 400
2039
+ );
2040
+ }
2041
+ const key = options?.key ?? `${randomUUID()}${extensionFor(options?.filename)}`;
2042
+ const maxSize = options?.maxSize ?? this._policy.maxSize;
2043
+ const res = await this._call("create-upload", {
2044
+ store: this._store,
2045
+ access: this._access,
2046
+ key,
2047
+ ...options?.contentType ? { contentType: options.contentType } : {},
2048
+ ...maxSize ? { maxSize } : {},
2049
+ ...options?.expiresIn ? { expiresIn: options.expiresIn } : {}
2050
+ });
2051
+ return {
2052
+ key,
2053
+ url: `/_/files/${this._access}/${this._store}/${key}`,
2054
+ upload: { url: res.uploadUrl, fields: res.uploadFields }
2055
+ };
2056
+ }
2057
+ _toFile(key, meta) {
2058
+ const store = this._store;
2059
+ const access = this._access;
2060
+ const call = this._call;
2061
+ return {
2062
+ store,
2063
+ key,
2064
+ access,
2065
+ url: `/_/files/${access}/${store}/${key}`,
2066
+ ...typeof meta?.size === "number" ? { size: meta.size } : {},
2067
+ ...meta?.contentType ? { contentType: meta.contentType } : {},
2068
+ ...meta?.updatedAt ? { updatedAt: meta.updatedAt } : {},
2069
+ async shareUrl(options) {
2070
+ const res = await call("sign", {
2071
+ store,
2072
+ access,
2073
+ key,
2074
+ ...options?.expiresIn ? { expiresIn: options.expiresIn } : {}
2075
+ });
2076
+ return res.url;
2077
+ }
2078
+ };
2079
+ }
2080
+ };
2081
+
2082
+ // src/files/index.ts
2083
+ function createFiles(call) {
2084
+ return {
2085
+ defineStore(name, options) {
2086
+ return new Store(name, options?.access ?? "private", call, {
2087
+ ...options?.maxSize !== void 0 ? { maxSize: options.maxSize } : {},
2088
+ ...options?.contentTypes ? { contentTypes: options.contentTypes } : {}
2089
+ });
2090
+ }
2091
+ };
2092
+ }
2093
+
1927
2094
  // src/generated/metadata.ts
1928
2095
  var stepMetadata = {
1929
2096
  "activeCampaignAddNote": {
@@ -2785,21 +2952,21 @@ var stepMetadata = {
2785
2952
  description: "Extract text, HTML, or structured content from one or more web pages.",
2786
2953
  usageNotes: '- Accepts a single URL or multiple URLs (as a JSON array, comma-separated, or newline-separated).\n- Output format controls the result shape: "text" returns markdown, "html" returns raw HTML, "json" returns structured scraper data.\n- Can optionally capture a screenshot of each page.',
2787
2954
  inputSchema: { "type": "object", "properties": { "url": { "type": "string", "description": "URL(s) to scrape. Accepts a single URL, JSON array, or comma/newline-separated list" }, "service": { "enum": ["default", "firecrawl"], "type": "string", "description": "Scraping service to use" }, "autoEnhance": { "type": "boolean", "description": "Whether to enable enhanced scraping for social media URLs (e.g. Twitter, LinkedIn)" }, "outputFormat": { "enum": ["text", "json", "html"], "type": "string", "description": "Output format: text returns markdown, html returns raw HTML, json returns structured scraper data" }, "pageOptions": { "type": "object", "properties": { "onlyMainContent": { "type": "boolean", "description": "Whether to extract only the main content of the page, excluding navigation, footers, etc." }, "screenshot": { "type": "boolean", "description": "Whether to capture a screenshot of the page" }, "waitFor": { "type": "number", "description": "Milliseconds to wait before scraping (0 for immediate)" }, "replaceAllPathsWithAbsolutePaths": { "type": "boolean", "description": "Whether to convert relative URLs to absolute URLs in the result" }, "headers": { "type": "object", "properties": {}, "required": [], "description": "Custom HTTP request headers as key-value pairs" }, "removeTags": { "type": "array", "items": { "type": "string" }, "description": "HTML tags to remove from the scraped result" }, "mobile": { "type": "boolean", "description": "Whether to scrape using a mobile user-agent" } }, "required": ["onlyMainContent", "screenshot", "waitFor", "replaceAllPathsWithAbsolutePaths", "headers", "removeTags", "mobile"], "description": "Page-level scraping options (content filtering, screenshots, headers, etc.)" } }, "required": ["url"] },
2788
- outputSchema: { "type": "object", "properties": { "content": { "anyOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }, { "type": "object", "properties": { "text": { "type": "string", "description": "Markdown/plain-text content of the scraped page" }, "html": { "type": "string", "description": "Raw HTML content of the scraped page" }, "json": { "type": "object", "properties": {}, "required": [], "description": "Structured data extracted from the page" }, "screenshotUrl": { "type": "string", "description": "Screenshot URL of the page (if requested)" }, "metadata": { "type": "object", "properties": { "title": { "type": "string", "description": "Page title" }, "description": { "type": "string", "description": "Page meta description" }, "url": { "type": "string", "description": "Canonical URL" }, "image": { "type": "string", "description": "Open Graph image URL" } }, "required": ["title", "description", "url", "image"], "description": "Page metadata (Open Graph / meta tags)" } }, "required": ["text", "html"] }, { "type": "array", "items": { "type": "object", "properties": { "text": { "type": "string", "description": "Markdown/plain-text content of the scraped page" }, "html": { "type": "string", "description": "Raw HTML content of the scraped page" }, "json": { "type": "object", "properties": {}, "required": [], "description": "Structured data extracted from the page" }, "screenshotUrl": { "type": "string", "description": "Screenshot URL of the page (if requested)" }, "metadata": { "type": "object", "properties": { "title": { "type": "string", "description": "Page title" }, "description": { "type": "string", "description": "Page meta description" }, "url": { "type": "string", "description": "Canonical URL" }, "image": { "type": "string", "description": "Open Graph image URL" } }, "required": ["title", "description", "url", "image"], "description": "Page metadata (Open Graph / meta tags)" } }, "required": ["text", "html"] } }] }, "screenshot": { "type": "string", "description": "Screenshot URL, only present when screenshot was requested via pageOptions" } }, "required": ["content"] }
2955
+ outputSchema: { "type": "object", "properties": { "content": { "anyOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }, { "type": "object", "properties": { "text": { "type": "string", "description": "Markdown/plain-text content of the scraped page" }, "html": { "type": "string", "description": "Raw HTML content of the scraped page" }, "json": { "type": "object", "properties": {}, "required": [], "description": "Structured data extracted from the page" }, "screenshotUrl": { "type": "string", "description": "Screenshot URL of the page (if requested)" }, "metadata": { "type": "object", "properties": { "title": { "type": "string", "description": "Page title" }, "description": { "type": "string", "description": "Page meta description" }, "url": { "type": "string", "description": "Canonical URL" }, "image": { "type": "string", "description": "Open Graph image URL" } }, "required": ["title", "description", "url", "image"], "description": "Page metadata (Open Graph / meta tags)" }, "error": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } }, "required": ["code", "message"], "description": "Set when the scrape failed. `text`/`html` still carry the human-readable error so existing callers behave as before, but callers that care \u2014 billing, in particular \u2014 can tell a failure from real page content." } }, "required": ["text", "html"] }, { "type": "array", "items": { "type": "object", "properties": { "text": { "type": "string", "description": "Markdown/plain-text content of the scraped page" }, "html": { "type": "string", "description": "Raw HTML content of the scraped page" }, "json": { "type": "object", "properties": {}, "required": [], "description": "Structured data extracted from the page" }, "screenshotUrl": { "type": "string", "description": "Screenshot URL of the page (if requested)" }, "metadata": { "type": "object", "properties": { "title": { "type": "string", "description": "Page title" }, "description": { "type": "string", "description": "Page meta description" }, "url": { "type": "string", "description": "Canonical URL" }, "image": { "type": "string", "description": "Open Graph image URL" } }, "required": ["title", "description", "url", "image"], "description": "Page metadata (Open Graph / meta tags)" }, "error": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } }, "required": ["code", "message"], "description": "Set when the scrape failed. `text`/`html` still carry the human-readable error so existing callers behave as before, but callers that care \u2014 billing, in particular \u2014 can tell a failure from real page content." } }, "required": ["text", "html"] } }] }, "screenshot": { "anyOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }] } }, "required": ["content"] }
2789
2956
  },
2790
2957
  "scrapeXPost": {
2791
2958
  stepType: "scrapeXPost",
2792
2959
  description: "Scrape data from a single X (Twitter) post by URL.",
2793
2960
  usageNotes: "- Returns structured post data (text, html, optional json/screenshot/metadata).\n- Optionally saves the text content to a variable.",
2794
2961
  inputSchema: { "type": "object", "properties": { "url": { "type": "string", "description": "Full URL to the X post (e.g. https://x.com/elonmusk/status/1655608985058267139)" } }, "required": ["url"] },
2795
- outputSchema: { "type": "object", "properties": { "post": { "type": "object", "properties": { "text": { "type": "string", "description": "Markdown/plain-text content of the scraped page" }, "html": { "type": "string", "description": "Raw HTML content of the scraped page" }, "json": { "type": "object", "properties": {}, "required": [], "description": "Structured data extracted from the page" }, "screenshotUrl": { "type": "string", "description": "Screenshot URL of the page (if requested)" }, "metadata": { "type": "object", "properties": { "title": { "type": "string", "description": "Page title" }, "description": { "type": "string", "description": "Page meta description" }, "url": { "type": "string", "description": "Canonical URL" }, "image": { "type": "string", "description": "Open Graph image URL" } }, "required": ["title", "description", "url", "image"], "description": "Page metadata (Open Graph / meta tags)" } }, "required": ["text", "html"], "description": "Scraped post data including text, HTML, and optional structured JSON" } }, "required": ["post"] }
2962
+ outputSchema: { "type": "object", "properties": { "post": { "type": "object", "properties": { "text": { "type": "string", "description": "Markdown/plain-text content of the scraped page" }, "html": { "type": "string", "description": "Raw HTML content of the scraped page" }, "json": { "type": "object", "properties": {}, "required": [], "description": "Structured data extracted from the page" }, "screenshotUrl": { "type": "string", "description": "Screenshot URL of the page (if requested)" }, "metadata": { "type": "object", "properties": { "title": { "type": "string", "description": "Page title" }, "description": { "type": "string", "description": "Page meta description" }, "url": { "type": "string", "description": "Canonical URL" }, "image": { "type": "string", "description": "Open Graph image URL" } }, "required": ["title", "description", "url", "image"], "description": "Page metadata (Open Graph / meta tags)" }, "error": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } }, "required": ["code", "message"], "description": "Set when the scrape failed. `text`/`html` still carry the human-readable error so existing callers behave as before, but callers that care \u2014 billing, in particular \u2014 can tell a failure from real page content." } }, "required": ["text", "html"], "description": "Scraped post data including text, HTML, and optional structured JSON" } }, "required": ["post"] }
2796
2963
  },
2797
2964
  "scrapeXProfile": {
2798
2965
  stepType: "scrapeXProfile",
2799
2966
  description: "Scrape public profile data from an X (Twitter) account by URL.",
2800
2967
  usageNotes: "- Returns structured profile data.\n- Optionally saves the result to a variable.",
2801
2968
  inputSchema: { "type": "object", "properties": { "url": { "type": "string", "description": "Full URL or username for the X profile (e.g. https://x.com/elonmusk)" } }, "required": ["url"] },
2802
- outputSchema: { "type": "object", "properties": { "profile": { "type": "object", "properties": { "text": { "type": "string", "description": "Markdown/plain-text content of the scraped page" }, "html": { "type": "string", "description": "Raw HTML content of the scraped page" }, "json": { "type": "object", "properties": {}, "required": [], "description": "Structured data extracted from the page" }, "screenshotUrl": { "type": "string", "description": "Screenshot URL of the page (if requested)" }, "metadata": { "type": "object", "properties": { "title": { "type": "string", "description": "Page title" }, "description": { "type": "string", "description": "Page meta description" }, "url": { "type": "string", "description": "Canonical URL" }, "image": { "type": "string", "description": "Open Graph image URL" } }, "required": ["title", "description", "url", "image"], "description": "Page metadata (Open Graph / meta tags)" } }, "required": ["text", "html"], "description": "Scraped profile data including text, HTML, and optional structured JSON" } }, "required": ["profile"] }
2969
+ outputSchema: { "type": "object", "properties": { "profile": { "type": "object", "properties": { "text": { "type": "string", "description": "Markdown/plain-text content of the scraped page" }, "html": { "type": "string", "description": "Raw HTML content of the scraped page" }, "json": { "type": "object", "properties": {}, "required": [], "description": "Structured data extracted from the page" }, "screenshotUrl": { "type": "string", "description": "Screenshot URL of the page (if requested)" }, "metadata": { "type": "object", "properties": { "title": { "type": "string", "description": "Page title" }, "description": { "type": "string", "description": "Page meta description" }, "url": { "type": "string", "description": "Canonical URL" }, "image": { "type": "string", "description": "Open Graph image URL" } }, "required": ["title", "description", "url", "image"], "description": "Page metadata (Open Graph / meta tags)" }, "error": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } }, "required": ["code", "message"], "description": "Set when the scrape failed. `text`/`html` still carry the human-readable error so existing callers behave as before, but callers that care \u2014 billing, in particular \u2014 can tell a failure from real page content." } }, "required": ["text", "html"], "description": "Scraped profile data including text, HTML, and optional structured JSON" } }, "required": ["profile"] }
2803
2970
  },
2804
2971
  "screenshotUrl": {
2805
2972
  stepType: "screenshotUrl",
@@ -2891,6 +3058,9 @@ var stepMetadata = {
2891
3058
  usageNotes: `- Use the "to" field to send to one or more specific recipient email addresses directly. Allowed recipients depend on the sender: when the app sends from a domain it owns (a verified custom domain or its <slug>.madewithremy.com subdomain) any recipient is allowed; when it falls back to the shared Remy address, recipients must be verified app users or members of the app's organization. (v1 apps cannot use a direct "to" \u2014 they must resolve recipients via a connection.)
2892
3059
  - Alternatively, recipient email addresses can be resolved from OAuth connections configured by the app creator via connectionId. The user running the workflow does not specify the recipient directly.
2893
3060
  - Use "cc" and "bcc" to add visible / hidden recipients (a string or an array). They are subject to the same recipient rules as "to".
3061
+ - "to" is optional only in the sense that recipients can come from elsewhere \u2014 omit it and supply "cc"/"bcc" for a hidden-list send, or omit all three and recipients are resolved from an OAuth connection. Naming nobody at all is an error.
3062
+ - Bcc-only sends are supported: with no "to" or "cc", the To: header is addressed to the app's own sender address (the standard "undisclosed recipients" pattern) so recipients can't see each other. The returned "recipients" reflects that auto-filled address.
3063
+ - Every recipient counts toward the app's daily outbound cap, including cc and bcc.
2894
3064
  - The sender defaults automatically: v2 apps send from the app's own identity \u2014 its verified custom domain if set, else its platform subdomain (noreply@<slug>.madewithremy.com), else the default Remy address.
2895
3065
  - Optionally set "from" to a custom handle, but ONLY if the app has a custom domain or subdomain: a bare handle ("support" \u2192 support@<app-domain>), a full "support@your-domain.com", or "Name <support@your-domain.com>". The domain must be one the app owns, or the step fails.
2896
3066
  - If the body is a URL to a hosted HTML file on the CDN, the HTML is fetched and used as the email body.
@@ -3178,6 +3348,13 @@ function resolveStepType(name) {
3178
3348
  }
3179
3349
  function mapTools(tools) {
3180
3350
  return tools.map((t) => {
3351
+ if (typeof t === "object" && "appMethod" in t) {
3352
+ return {
3353
+ appMethod: t.appMethod,
3354
+ ...t.description ? { description: t.description } : {},
3355
+ ...t.defaults ? { defaults: t.defaults } : {}
3356
+ };
3357
+ }
3181
3358
  const method = typeof t === "string" ? t : t.method;
3182
3359
  const stepType = resolveStepType(method);
3183
3360
  const defaults = typeof t === "object" ? t.defaults : void 0;
@@ -3926,6 +4103,8 @@ var MindStudioAgent = class {
3926
4103
  _auth;
3927
4104
  /** @internal Cached Db namespace instance, created during context hydration. */
3928
4105
  _db;
4106
+ /** @internal Cached Files namespace instance (lazy; no context hydration needed). */
4107
+ _files;
3929
4108
  /** @internal Auth type — 'internal' for CALLBACK_TOKEN (managed mode), 'apiKey' otherwise. */
3930
4109
  _authType;
3931
4110
  /** @internal Usage source sent on step executions (from MINDSTUDIO_REQUEST_SOURCE).
@@ -4383,11 +4562,18 @@ var MindStudioAgent = class {
4383
4562
  * to produce structured output. The model receives the prompt and tools,
4384
4563
  * calls actions as needed, and returns JSON matching the output example.
4385
4564
  *
4565
+ * Tools can be SDK actions, your own app's methods, or both. App methods run
4566
+ * as the user who invoked the method that started the task, with their roles.
4567
+ *
4386
4568
  * ```ts
4387
4569
  * const result = await agent.runTask<{ name: string; url: string }>({
4388
- * prompt: 'Find canonical info for this restaurant.',
4570
+ * prompt: 'Find canonical info for this restaurant, then save it.',
4389
4571
  * input: { restaurantName: 'Tartine Bakery SF' },
4390
- * tools: ['searchGoogle', 'fetchUrl'],
4572
+ * tools: [
4573
+ * 'searchGoogle',
4574
+ * 'fetchUrl',
4575
+ * { appMethod: 'saveRestaurant', description: 'Persist the researched restaurant.' },
4576
+ * ],
4391
4577
  * structuredOutputExample: JSON.stringify({ name: 'Tartine Bakery', url: 'https://tartinebakery.com' }),
4392
4578
  * model: 'claude-4-6-sonnet',
4393
4579
  * });
@@ -4795,6 +4981,54 @@ var MindStudioAgent = class {
4795
4981
  });
4796
4982
  }
4797
4983
  }
4984
+ /**
4985
+ * The `files` namespace — typed, private-by-default file storage (the twin of
4986
+ * `db`). No context hydration needed: the hook token identifies the app
4987
+ * server-side and stores are code-defined (access travels per call).
4988
+ *
4989
+ * @example
4990
+ * ```ts
4991
+ * const Uploads = agent.files.defineStore('uploads');
4992
+ * const f = await Uploads.put(buffer, { contentType: 'image/png' });
4993
+ * return { url: f.url };
4994
+ * ```
4995
+ */
4996
+ get files() {
4997
+ return this._files ??= createFiles(this._filesRequest.bind(this));
4998
+ }
4999
+ /**
5000
+ * @internal Transport for the `files` namespace — POST /_internal/v2/files/<op>
5001
+ * with the raw hook token (mirrors `_executeDbBatch`).
5002
+ */
5003
+ async _filesRequest(op, body) {
5004
+ const url = `${this._currentHttpConfig.baseUrl}/_internal/v2/files/${op}`;
5005
+ const res = await fetch(url, {
5006
+ method: "POST",
5007
+ headers: {
5008
+ "Content-Type": "application/json",
5009
+ Authorization: this._token
5010
+ },
5011
+ body: JSON.stringify(body)
5012
+ });
5013
+ if (res.status === 204) {
5014
+ return void 0;
5015
+ }
5016
+ const text = await res.text();
5017
+ let json;
5018
+ if (text) {
5019
+ try {
5020
+ json = JSON.parse(text);
5021
+ } catch {
5022
+ }
5023
+ }
5024
+ if (!res.ok) {
5025
+ const rawMsg = json?.errorMessage ?? (typeof json?.error === "string" ? json.error : json?.error?.message);
5026
+ const message = typeof rawMsg === "string" ? rawMsg : `File operation failed: ${res.status} ${res.statusText}`;
5027
+ const code = json?.errorString ?? json?.code ?? "file_error";
5028
+ throw new MindStudioError(message, code, res.status);
5029
+ }
5030
+ return json;
5031
+ }
4798
5032
  /**
4799
5033
  * @internal Execute a batch of SQL queries against a managed database.
4800
5034
  * Used as the `executeBatch` callback for Table/Query instances.
@@ -5461,6 +5695,16 @@ var db = new Proxy(
5461
5695
  }
5462
5696
  }
5463
5697
  );
5698
+ var files = new Proxy(
5699
+ {},
5700
+ {
5701
+ get(_, prop) {
5702
+ const target = mindstudio.files;
5703
+ const value = Reflect.get(target, prop, target);
5704
+ return typeof value === "function" ? value.bind(target) : value;
5705
+ }
5706
+ }
5707
+ );
5464
5708
  var stream = (data) => mindstudio.stream(data);
5465
5709
  var resolveUser = (userId) => mindstudio.resolveUser(userId);
5466
5710
  var reportIssue = (input) => mindstudio.reportIssue(input);
@@ -5476,6 +5720,7 @@ export {
5476
5720
  blockTypeAliases,
5477
5721
  db,
5478
5722
  index_default as default,
5723
+ files,
5479
5724
  getRequestContext,
5480
5725
  mindstudio,
5481
5726
  monacoSnippets,