segmind 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The official JavaScript SDK for [Segmind](https://www.segmind.com): image, video, audio and LLM models through one API. It works in Node 22+, and in browsers and React Native through your own backend.
4
4
 
5
- > **Pre-release.** The API below is the 0.1 surface and may change before 1.0.
5
+ > **Pre-release.** The API below is the 0.2 surface and may change before 1.0.
6
6
 
7
7
  ## Install
8
8
 
@@ -90,6 +90,50 @@ const described = await segmind.chat('gpt-5.5', {
90
90
 
91
91
  `reply.text` reads the assistant text from OpenAI, Anthropic and Gemini replies alike; `reply.raw` is the provider's own JSON. `chatSync` makes one blocking call, and `submitChat` returns a job.
92
92
 
93
+ ## Files
94
+
95
+ ```ts
96
+ const { url } = await segmind.files.upload('portrait.jpg'); // a path (Node), a Blob/File, or bytes
97
+ const result = await segmind.run('some-image-to-image-model', { image: url });
98
+ ```
99
+
100
+ Each file goes straight to storage on a presigned URL, so large videos never travel as base64 JSON. The URLs are public and temporary (kept for at least two days): they are for passing files to models, not for keeping them. Pass an array to upload several, in order. Bytes without a name need `{ filename: 'clip.mp4' }` unless their type can be read from the first bytes.
101
+
102
+ ## Generations
103
+
104
+ ```ts
105
+ const page = await segmind.generations.list({ modelName: 'flux-schnell' });
106
+ const history = await segmind.generations.history({ status: 'FAILED', perPage: 50 }); // failures included
107
+ const one = await segmind.generations.get(requestId);
108
+ const latest = await segmind.generations.recent('flux-schnell');
109
+ ```
110
+
111
+ `history` lists one row per output, each with the request's full cost: de-duplicate on `request_id` before summing `credits_deduction`.
112
+
113
+ ## Webhooks
114
+
115
+ ```ts
116
+ const hook = await segmind.webhooks.add('https://example.com/hooks/segmind', ['PIXELFLOW']);
117
+ const hooks = await segmind.webhooks.get(); // each with its signing_secret
118
+ await segmind.webhooks.update(hook.id, 'https://example.com/hooks/v2', ['PIXELFLOW']);
119
+ await segmind.webhooks.logs(hook.id);
120
+ await segmind.webhooks.delete(hook.id);
121
+ ```
122
+
123
+ Event types are subscription types: `PIXELFLOW` for PixelFlow runs, plus `WORKFLOW`, `INFERENCE` and `FINETUNE`.
124
+
125
+ ## PixelFlow workflows
126
+
127
+ ```ts
128
+ const result = await segmind.pixelflows.run('your-workflow-slug', { Text_Prompt: 'An infographic about tea' });
129
+ console.log(result.outputs); // { image_out: 'https://…' }
130
+
131
+ const job = await segmind.pixelflows.submit('your-workflow-slug', { Text_Prompt: '…' });
132
+ const done = await job.wait({ timeout: 20 * 60_000, interval: 5_000 });
133
+ ```
134
+
135
+ The slug is the workflow's API slug from its API tab, and inputs are keyed by each input's keyname. Runs use the current workflow engine; pass `{ engine: 'v1' }` for the legacy one. A failed run throws `InferenceFailed` whose `detail` names the node that failed. A submit is never retried, because a run bills.
136
+
93
137
  ## Errors
94
138
 
95
139
  | Error | When |
package/dist/index.cjs CHANGED
@@ -38,22 +38,31 @@ __export(index_exports, {
38
38
  DEFAULT_SPOT_URL: () => DEFAULT_SPOT_URL,
39
39
  DEFAULT_WAIT_INTERVAL_MS: () => DEFAULT_WAIT_INTERVAL_MS,
40
40
  DEFAULT_WAIT_TIMEOUT_MS: () => DEFAULT_WAIT_TIMEOUT_MS,
41
+ Files: () => Files,
42
+ Generations: () => Generations,
41
43
  InferenceFailed: () => InferenceFailed,
42
44
  InferenceTimeout: () => InferenceTimeout,
43
45
  Job: () => Job,
44
46
  Models: () => Models,
47
+ PixelFlows: () => PixelFlows,
48
+ PixelflowJob: () => PixelflowJob,
45
49
  Segmind: () => Segmind,
46
50
  SegmindError: () => SegmindError,
47
51
  VERSION: () => VERSION,
52
+ Webhooks: () => Webhooks,
48
53
  accounts: () => accounts,
49
54
  chat: () => chat,
50
55
  chatSync: () => chatSync,
56
+ files: () => files,
57
+ generations: () => generations,
51
58
  imageUrl: () => imageUrl,
52
59
  models: () => models,
60
+ pixelflows: () => pixelflows,
53
61
  run: () => run,
54
62
  runSync: () => runSync,
55
63
  submit: () => submit,
56
- submitChat: () => submitChat
64
+ submitChat: () => submitChat,
65
+ webhooks: () => webhooks
57
66
  });
58
67
  module.exports = __toCommonJS(index_exports);
59
68
 
@@ -93,8 +102,8 @@ var APIConnectionError = class extends SegmindError {
93
102
  var InferenceFailed = class extends SegmindError {
94
103
  /** The status body that reported the failure. */
95
104
  statusBody;
96
- constructor(requestId, statusBody) {
97
- const detail = typeof statusBody.error === "string" ? statusBody.error : void 0;
105
+ constructor(requestId, statusBody, detail) {
106
+ detail ??= typeof statusBody.error === "string" ? statusBody.error : void 0;
98
107
  super(detail ? `request ${requestId} failed: ${detail}` : `request ${requestId} failed`, {
99
108
  detail,
100
109
  requestId,
@@ -331,14 +340,15 @@ var HttpClient = class {
331
340
  }, timeout);
332
341
  const onAbort = () => controller.abort(signal.reason);
333
342
  signal?.addEventListener("abort", onAbort, { once: true });
334
- const headers = { ...this.config.headers, ...req.headers };
335
- if (this.config.apiKey) headers["x-api-key"] = this.config.apiKey;
343
+ const headers = req.bare ? { ...req.headers } : { ...this.config.headers, ...req.headers };
344
+ if (this.config.apiKey && !req.bare) headers["x-api-key"] = this.config.apiKey;
336
345
  if (req.body !== void 0) headers["content-type"] = "application/json";
346
+ const body = req.rawBody ?? (req.body === void 0 ? void 0 : JSON.stringify(req.body));
337
347
  try {
338
- return await this.config.fetch(req.url, {
348
+ return await this.config.fetch(withQuery(req.url, req.query), {
339
349
  method: req.method,
340
350
  headers,
341
- body: req.body === void 0 ? void 0 : JSON.stringify(req.body),
351
+ body,
342
352
  signal: controller.signal
343
353
  });
344
354
  } catch (err) {
@@ -363,6 +373,15 @@ async function readJson(response) {
363
373
  });
364
374
  }
365
375
  }
376
+ function withQuery(url, query) {
377
+ if (!query) return url;
378
+ const params = new URLSearchParams();
379
+ for (const [key, value] of Object.entries(query)) {
380
+ if (value !== void 0) params.set(key, String(value));
381
+ }
382
+ const qs = params.toString();
383
+ return qs ? `${url}${url.includes("?") ? "&" : "?"}${qs}` : url;
384
+ }
366
385
  function describe(err) {
367
386
  if (err instanceof Error) {
368
387
  const cause = err.cause;
@@ -371,6 +390,182 @@ function describe(err) {
371
390
  return String(err);
372
391
  }
373
392
 
393
+ // src/core/input.ts
394
+ var MIME_BY_EXTENSION = {
395
+ png: "image/png",
396
+ jpg: "image/jpeg",
397
+ jpeg: "image/jpeg",
398
+ gif: "image/gif",
399
+ webp: "image/webp",
400
+ bmp: "image/bmp",
401
+ svg: "image/svg+xml",
402
+ heic: "image/heic",
403
+ heif: "image/heif",
404
+ tif: "image/tiff",
405
+ tiff: "image/tiff",
406
+ avif: "image/avif",
407
+ mp4: "video/mp4",
408
+ mov: "video/quicktime",
409
+ webm: "video/webm",
410
+ mkv: "video/x-matroska",
411
+ avi: "video/x-msvideo",
412
+ mp3: "audio/mpeg",
413
+ wav: "audio/wav",
414
+ m4a: "audio/mp4",
415
+ ogg: "audio/ogg",
416
+ flac: "audio/flac",
417
+ aac: "audio/aac",
418
+ pdf: "application/pdf",
419
+ txt: "text/plain",
420
+ json: "application/json",
421
+ glb: "model/gltf-binary"
422
+ };
423
+ var EXTENSION_BY_MIME = Object.fromEntries(
424
+ Object.entries(MIME_BY_EXTENSION).map(([ext, mime]) => [mime, ext])
425
+ );
426
+ EXTENSION_BY_MIME["image/jpeg"] = "jpg";
427
+ function mimeFromName(name) {
428
+ const extension = name.includes(".") ? name.split(".").pop().toLowerCase() : "";
429
+ return MIME_BY_EXTENSION[extension];
430
+ }
431
+ async function readFileInput(input, options) {
432
+ let bytes;
433
+ let name = options.filename;
434
+ let mimeType = options.mimeType;
435
+ if (typeof input === "string") {
436
+ if (detectRuntime() !== "node") {
437
+ throw new SegmindError(`${options.caller}: file paths work in Node only; pass a Blob or bytes`);
438
+ }
439
+ const { readFile } = await import("node:fs/promises");
440
+ try {
441
+ bytes = new Uint8Array(await readFile(input));
442
+ } catch (err) {
443
+ throw new SegmindError(`${options.caller}: cannot read ${JSON.stringify(input)}: ${err.message}`, {
444
+ cause: err
445
+ });
446
+ }
447
+ name ??= input.split(/[\\/]/).pop();
448
+ } else if (typeof Blob !== "undefined" && input instanceof Blob) {
449
+ bytes = new Uint8Array(await input.arrayBuffer());
450
+ name ??= input.name || void 0;
451
+ mimeType ??= input.type || void 0;
452
+ } else {
453
+ bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
454
+ }
455
+ mimeType ??= name && mimeFromName(name) || sniff(bytes);
456
+ if (!name || !name.includes(".")) {
457
+ const extension = mimeType ? EXTENSION_BY_MIME[mimeType] : void 0;
458
+ if (!extension) {
459
+ throw new SegmindError(`${options.caller}: cannot tell the file type; pass { filename: 'name.ext' } or { mimeType }`);
460
+ }
461
+ name = `${name || "upload"}.${extension}`;
462
+ }
463
+ return { bytes, filename: name, mimeType };
464
+ }
465
+ function sniff(bytes) {
466
+ const at = (offset, signature) => signature.every((b, i) => bytes[offset + i] === b);
467
+ if (at(0, [137, 80, 78, 71])) return "image/png";
468
+ if (at(0, [255, 216, 255])) return "image/jpeg";
469
+ if (at(0, [71, 73, 70, 56])) return "image/gif";
470
+ if (at(0, [82, 73, 70, 70]) && at(8, [87, 69, 66, 80])) return "image/webp";
471
+ if (at(0, [82, 73, 70, 70]) && at(8, [87, 65, 86, 69])) return "audio/wav";
472
+ if (at(4, [102, 116, 121, 112])) return "video/mp4";
473
+ if (at(0, [73, 68, 51]) || at(0, [255, 251])) return "audio/mpeg";
474
+ if (at(0, [37, 80, 68, 70])) return "application/pdf";
475
+ return void 0;
476
+ }
477
+
478
+ // src/files.ts
479
+ var Files = class {
480
+ constructor(client2) {
481
+ this.client = client2;
482
+ }
483
+ client;
484
+ async upload(input, options = {}) {
485
+ if (Array.isArray(input)) {
486
+ const uploaded = [];
487
+ for (const file of input) uploaded.push(await this.uploadOne(file, { ...options, filename: void 0 }));
488
+ return uploaded;
489
+ }
490
+ return this.uploadOne(input, options);
491
+ }
492
+ async uploadOne(input, options) {
493
+ const file = await readFileInput(input, { ...options, caller: "files.upload" });
494
+ const { http } = this.client;
495
+ const ticket = await http.json({
496
+ method: "POST",
497
+ url: `${this.client.spotURL}/inference-request/input-presign`,
498
+ body: { filename: file.filename, size: file.bytes.byteLength },
499
+ signal: options.signal,
500
+ retry: true
501
+ });
502
+ if (!ticket.upload_url || !ticket.url) {
503
+ throw new SegmindError("files.upload: the presign response had no upload_url or url", { body: ticket });
504
+ }
505
+ const headers = { ...ticket.required_headers };
506
+ delete headers["Content-Length"];
507
+ delete headers["content-length"];
508
+ await http.request({
509
+ method: "PUT",
510
+ url: ticket.upload_url,
511
+ rawBody: file.bytes,
512
+ headers,
513
+ bare: true,
514
+ signal: options.signal,
515
+ retry: true
516
+ });
517
+ return { url: ticket.url, filename: file.filename, size: file.bytes.byteLength };
518
+ }
519
+ };
520
+
521
+ // src/generations.ts
522
+ var Generations = class {
523
+ constructor(client2) {
524
+ this.client = client2;
525
+ }
526
+ client;
527
+ /** Generated outputs, newest first. */
528
+ async list(options = {}) {
529
+ return this.read("/inference-request/generations", options.signal, {
530
+ page: options.page ?? 1,
531
+ model_name: options.modelName,
532
+ start_date: options.startDate,
533
+ end_date: options.endDate,
534
+ user_id: options.userId
535
+ });
536
+ }
537
+ /** The newest generations for one model. */
538
+ async recent(modelName, options = {}) {
539
+ return this.read("/inference-request/recent-generations", options.signal, { model_name: modelName });
540
+ }
541
+ /**
542
+ * Requests with their cost, inputs and outcome, failures included. A request
543
+ * with several outputs appears once per output, each carrying its full cost:
544
+ * de-duplicate on `request_id` before summing.
545
+ */
546
+ async history(options = {}) {
547
+ return this.read("/inference-request/request-history", options.signal, {
548
+ page: options.page ?? 1,
549
+ per_page: options.perPage ?? 20,
550
+ from_date: options.fromDate,
551
+ to_date: options.toDate,
552
+ model_name: options.modelName,
553
+ status: options.status,
554
+ user_id: options.userId,
555
+ user_email: options.userEmail,
556
+ sort_by: options.sortBy,
557
+ sort_order: options.sortOrder
558
+ });
559
+ }
560
+ /** One of your own requests, of any age. A teammate's request id is not found. */
561
+ async get(requestId, options = {}) {
562
+ return this.read(`/inference-request/request-history/${encodeURIComponent(requestId)}`, options.signal);
563
+ }
564
+ read(path2, signal, query) {
565
+ return this.client.http.json({ method: "GET", url: `${this.client.spotURL}${path2}`, query, signal, retry: true });
566
+ }
567
+ };
568
+
374
569
  // src/job.ts
375
570
  var DEFAULT_WAIT_TIMEOUT_MS = 6e5;
376
571
  var DEFAULT_WAIT_INTERVAL_MS = 1e3;
@@ -440,8 +635,167 @@ var Job = class {
440
635
  }
441
636
  };
442
637
 
638
+ // src/pixelflows.ts
639
+ var DONE = /* @__PURE__ */ new Set(["COMPLETED", "SUCCESS", "SUCCEEDED"]);
640
+ var FAILED = /* @__PURE__ */ new Set(["FAILED", "ERROR"]);
641
+ var DEFAULT_TIMEOUT_MS = 6e5;
642
+ var DEFAULT_INTERVAL_MS = 2e3;
643
+ var PixelFlows = class {
644
+ constructor(client2) {
645
+ this.client = client2;
646
+ }
647
+ client;
648
+ /** Runs a workflow and waits for its outputs. */
649
+ async run(slug, inputs = {}, options = {}) {
650
+ const job = await this.submit(slug, inputs, options);
651
+ return job.wait(options);
652
+ }
653
+ /** Starts a workflow and returns a job to wait on. Never retried: a run bills. */
654
+ async submit(slug, inputs = {}, options = {}) {
655
+ const clean = slug.trim().replace(/^\/+/, "");
656
+ if (!clean) throw new SegmindError("pixelflows: a workflow slug is required");
657
+ const route = options.engine === "v1" ? "/workflows/" : "/workflows/v2/";
658
+ const body = await this.client.http.json({
659
+ method: "POST",
660
+ url: `${this.client.baseURL}${route}${clean}`,
661
+ body: inputs,
662
+ signal: options.signal
663
+ });
664
+ const requestId = body.request_id;
665
+ if (typeof requestId !== "string" || !requestId) {
666
+ throw new SegmindError("pixelflows: the submit response had no request_id", { body });
667
+ }
668
+ return new PixelflowJob(this, requestId);
669
+ }
670
+ /** A run's current state, without waiting. */
671
+ async getStatus(requestId, options = {}) {
672
+ const raw = await this.client.http.json({
673
+ method: "GET",
674
+ url: `${this.client.baseURL}/workflows/request/${encodeURIComponent(requestId)}`,
675
+ signal: options.signal,
676
+ retry: true
677
+ });
678
+ return toStatus(raw);
679
+ }
680
+ /** Waits for a run started earlier, by its request id. */
681
+ async poll(requestId, options = {}) {
682
+ return new PixelflowJob(this, requestId).wait(options);
683
+ }
684
+ };
685
+ var PixelflowJob = class {
686
+ constructor(pixelflows2, requestId) {
687
+ this.pixelflows = pixelflows2;
688
+ this.requestId = requestId;
689
+ }
690
+ pixelflows;
691
+ requestId;
692
+ status(options = {}) {
693
+ return this.pixelflows.getStatus(this.requestId, options);
694
+ }
695
+ /**
696
+ * Polls until the run finishes. Throws `InferenceFailed` (its `detail` names
697
+ * the failing node) or `InferenceTimeout`; the run may still finish after a
698
+ * timeout, so `wait()` can be called again.
699
+ */
700
+ async wait(options = {}) {
701
+ const timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
702
+ const interval = options.interval ?? DEFAULT_INTERVAL_MS;
703
+ const started = Date.now();
704
+ for (; ; ) {
705
+ const state = await this.status({ signal: options.signal });
706
+ if (DONE.has(state.status)) return state;
707
+ if (FAILED.has(state.status)) throw new InferenceFailed(this.requestId, state.raw, failureDetail(state.raw));
708
+ const elapsed = Date.now() - started;
709
+ if (elapsed + interval > timeout) throw new InferenceTimeout(this.requestId, elapsed);
710
+ await sleep(interval, options.signal);
711
+ }
712
+ }
713
+ };
714
+ function toStatus(body) {
715
+ const raw = { ...body };
716
+ if (typeof raw.output === "string") {
717
+ try {
718
+ raw.output = JSON.parse(raw.output);
719
+ } catch {
720
+ }
721
+ }
722
+ const status = String(raw.status ?? "UNKNOWN").toUpperCase();
723
+ return { status, outputs: DONE.has(status) ? flattenOutputs(raw.output) : {}, raw };
724
+ }
725
+ function flattenOutputs(output) {
726
+ const outputs = {};
727
+ if (Array.isArray(output)) {
728
+ for (const item of output) {
729
+ if (item && typeof item === "object" && typeof item.keyname === "string") {
730
+ const { keyname, value } = item;
731
+ outputs[keyname] = unwrap(value);
732
+ }
733
+ }
734
+ } else if (output && typeof output === "object") {
735
+ for (const [key, value] of Object.entries(output)) outputs[key] = unwrap(value);
736
+ }
737
+ return outputs;
738
+ }
739
+ function unwrap(value) {
740
+ if (value && typeof value === "object" && "data" in value) return value.data;
741
+ return value;
742
+ }
743
+ function failureDetail(body) {
744
+ const error = body.error_message ?? body.error;
745
+ if (typeof error === "string") return error;
746
+ if (error && typeof error === "object") {
747
+ const e = error;
748
+ const text = e.details ?? e.error_message ?? e.error;
749
+ if (typeof text === "string") return text;
750
+ }
751
+ return void 0;
752
+ }
753
+
443
754
  // src/version.ts
444
- var VERSION = "0.1.0";
755
+ var VERSION = "0.2.1";
756
+
757
+ // src/webhooks.ts
758
+ var Webhooks = class {
759
+ constructor(client2) {
760
+ this.client = client2;
761
+ }
762
+ client;
763
+ /** Every registration; `[]` when you have none. */
764
+ async get(options = {}) {
765
+ return this.call("GET", "/get", { signal: options.signal, retry: true });
766
+ }
767
+ /** Registers an endpoint for the given event types. A second active registration for the same types is refused (409). */
768
+ async add(webhookUrl, eventTypes, options = {}) {
769
+ return this.call("POST", "/add", {
770
+ body: { webhook_url: webhookUrl, event: { types: requireTypes(eventTypes) } },
771
+ signal: options.signal
772
+ });
773
+ }
774
+ /** Changes a registration's URL and event types. */
775
+ async update(webhookId, webhookUrl, eventTypes, options = {}) {
776
+ return this.call("POST", "/update", {
777
+ body: { webhook_id: webhookId, webhook_url: webhookUrl, event: { types: requireTypes(eventTypes) } },
778
+ signal: options.signal
779
+ });
780
+ }
781
+ /** Deactivates a registration. */
782
+ async delete(webhookId, options = {}) {
783
+ return this.call("GET", "/inactive", { query: { webhook_id: webhookId }, signal: options.signal, retry: true });
784
+ }
785
+ /** Delivery history for one registration. */
786
+ async logs(webhookId, options = {}) {
787
+ return this.call("GET", "/dispatch-logs", { query: { webhook_id: webhookId }, signal: options.signal, retry: true });
788
+ }
789
+ call(method, path2, req) {
790
+ return this.client.http.json({ method, url: `${this.client.spotURL}/webhook${path2}`, ...req });
791
+ }
792
+ };
793
+ function requireTypes(eventTypes) {
794
+ if (!Array.isArray(eventTypes) || eventTypes.length === 0) {
795
+ throw new SegmindError('webhooks: pass at least one event type, e.g. ["PIXELFLOW"]');
796
+ }
797
+ return eventTypes;
798
+ }
445
799
 
446
800
  // src/client.ts
447
801
  var DEFAULT_BASE_URL = "https://api.segmind.com";
@@ -453,6 +807,14 @@ var Segmind = class {
453
807
  consoleURL;
454
808
  models;
455
809
  accounts;
810
+ /** Upload files to pass as model inputs. */
811
+ files;
812
+ /** Your generations and request history. */
813
+ generations;
814
+ /** Your webhook registrations. */
815
+ webhooks;
816
+ /** Run published PixelFlow workflows. */
817
+ pixelflows;
456
818
  /** @internal */
457
819
  http;
458
820
  constructor(options = {}) {
@@ -483,6 +845,10 @@ var Segmind = class {
483
845
  });
484
846
  this.models = new Models(this);
485
847
  this.accounts = new Accounts(this);
848
+ this.files = new Files(this);
849
+ this.generations = new Generations(this);
850
+ this.webhooks = new Webhooks(this);
851
+ this.pixelflows = new PixelFlows(this);
486
852
  }
487
853
  /**
488
854
  * Runs a model and returns its result: submits to the v2 queue, then polls
@@ -628,62 +994,12 @@ function trimBase(url) {
628
994
  }
629
995
 
630
996
  // src/image-url.ts
631
- var MIME_BY_EXTENSION = {
632
- png: "image/png",
633
- jpg: "image/jpeg",
634
- jpeg: "image/jpeg",
635
- gif: "image/gif",
636
- webp: "image/webp",
637
- bmp: "image/bmp",
638
- svg: "image/svg+xml",
639
- heic: "image/heic",
640
- heif: "image/heif",
641
- tif: "image/tiff",
642
- tiff: "image/tiff",
643
- avif: "image/avif"
644
- };
645
997
  async function imageUrl(input, options = {}) {
646
- return { type: "image_url", image_url: { url: await toDataUri(input, options.mimeType) } };
647
- }
648
- async function toDataUri(input, mimeType) {
649
- if (typeof input === "string") {
650
- if (/^(https?:|data:)/i.test(input)) return input;
651
- if (detectRuntime() !== "node") {
652
- throw new SegmindError(`imageUrl: ${JSON.stringify(input)} is not an http(s) or data: URL (file paths work in Node only)`);
653
- }
654
- return fileToDataUri(input, mimeType);
998
+ if (typeof input === "string" && /^(https?:|data:)/i.test(input)) {
999
+ return { type: "image_url", image_url: { url: input } };
655
1000
  }
656
- if (typeof Blob !== "undefined" && input instanceof Blob) {
657
- const bytes2 = new Uint8Array(await input.arrayBuffer());
658
- return dataUri(bytes2, mimeType ?? (input.type || sniff(bytes2)));
659
- }
660
- const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
661
- return dataUri(bytes, mimeType ?? sniff(bytes));
662
- }
663
- async function fileToDataUri(path2, mimeType) {
664
- const { readFile } = await import("node:fs/promises");
665
- let bytes;
666
- try {
667
- bytes = new Uint8Array(await readFile(path2));
668
- } catch (err) {
669
- throw new SegmindError(`imageUrl: cannot read ${JSON.stringify(path2)}: ${err.message}`, { cause: err });
670
- }
671
- const extension = path2.split(".").pop()?.toLowerCase() ?? "";
672
- return dataUri(bytes, mimeType ?? MIME_BY_EXTENSION[extension] ?? sniff(bytes));
673
- }
674
- function dataUri(bytes, mimeType) {
675
- if (!mimeType) {
676
- throw new SegmindError("imageUrl: cannot tell the image type; pass { mimeType }");
677
- }
678
- return `data:${mimeType};base64,${toBase64(bytes)}`;
679
- }
680
- function sniff(bytes) {
681
- const at = (offset, signature) => signature.every((b, i) => bytes[offset + i] === b);
682
- if (at(0, [137, 80, 78, 71])) return "image/png";
683
- if (at(0, [255, 216, 255])) return "image/jpeg";
684
- if (at(0, [71, 73, 70, 56])) return "image/gif";
685
- if (at(0, [82, 73, 70, 70]) && at(8, [87, 69, 66, 80])) return "image/webp";
686
- return void 0;
1001
+ const file = await readFileInput(input, { mimeType: options.mimeType, caller: "imageUrl" });
1002
+ return { type: "image_url", image_url: { url: `data:${file.mimeType};base64,${toBase64(file.bytes)}` } };
687
1003
  }
688
1004
 
689
1005
  // src/index.ts
@@ -704,4 +1020,26 @@ var models = {
704
1020
  var accounts = {
705
1021
  current: (options) => client().accounts.current(options)
706
1022
  };
1023
+ var files = {
1024
+ upload: ((input, options) => client().files.upload(input, options))
1025
+ };
1026
+ var generations = {
1027
+ list: (options) => client().generations.list(options),
1028
+ recent: (modelName, options) => client().generations.recent(modelName, options),
1029
+ history: (options) => client().generations.history(options),
1030
+ get: (requestId, options) => client().generations.get(requestId, options)
1031
+ };
1032
+ var webhooks = {
1033
+ get: (options) => client().webhooks.get(options),
1034
+ add: (webhookUrl, eventTypes, options) => client().webhooks.add(webhookUrl, eventTypes, options),
1035
+ update: (webhookId, webhookUrl, eventTypes, options) => client().webhooks.update(webhookId, webhookUrl, eventTypes, options),
1036
+ delete: (webhookId, options) => client().webhooks.delete(webhookId, options),
1037
+ logs: (webhookId, options) => client().webhooks.logs(webhookId, options)
1038
+ };
1039
+ var pixelflows = {
1040
+ run: (slug, inputs, options) => client().pixelflows.run(slug, inputs, options),
1041
+ submit: (slug, inputs, options) => client().pixelflows.submit(slug, inputs, options),
1042
+ getStatus: (requestId, options) => client().pixelflows.getStatus(requestId, options),
1043
+ poll: (requestId, options) => client().pixelflows.poll(requestId, options)
1044
+ };
707
1045
  //# sourceMappingURL=index.cjs.map