@scalemule/nextjs 0.1.7 → 0.1.8

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.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ApiError, RealtimeService, StorageService, PhotoService, VideoService, FileStatus } from '@scalemule/sdk';
2
+ import { ApiError, RealtimeService, StorageService, PhotoService, VideoService, AudioService, FileStatus } from '@scalemule/sdk';
3
3
  import * as React from 'react';
4
4
  import { ReactNode, ReactElement } from 'react';
5
5
  import { MoneyClient } from '@scalemule/money';
@@ -164,6 +164,8 @@ interface ScaleMuleContextValue {
164
164
  photo: PhotoService;
165
165
  /** Base SDK video service — exposed for `useMedia()` and `video.uploadViaStorage()` */
166
166
  video: VideoService;
167
+ /** Base SDK audio service — exposed for `useMedia()` and `audio.uploadViaStorage()` */
168
+ audio: AudioService;
167
169
  /**
168
170
  * Default media policy for `useMedia()` calls. Set via
169
171
  * `<ScaleMuleProvider mediaPolicy="…">`; per-call overrides win.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ApiError, RealtimeService, StorageService, PhotoService, VideoService, FileStatus } from '@scalemule/sdk';
2
+ import { ApiError, RealtimeService, StorageService, PhotoService, VideoService, AudioService, FileStatus } from '@scalemule/sdk';
3
3
  import * as React from 'react';
4
4
  import { ReactNode, ReactElement } from 'react';
5
5
  import { MoneyClient } from '@scalemule/money';
@@ -164,6 +164,8 @@ interface ScaleMuleContextValue {
164
164
  photo: PhotoService;
165
165
  /** Base SDK video service — exposed for `useMedia()` and `video.uploadViaStorage()` */
166
166
  video: VideoService;
167
+ /** Base SDK audio service — exposed for `useMedia()` and `audio.uploadViaStorage()` */
168
+ audio: AudioService;
167
169
  /**
168
170
  * Default media policy for `useMedia()` calls. Set via
169
171
  * `<ScaleMuleProvider mediaPolicy="…">`; per-call overrides win.
package/dist/index.js CHANGED
@@ -2727,6 +2727,25 @@ var StorageService = class extends ServiceModule {
2727
2727
  async getInfo(fileId, options) {
2728
2728
  return this._get(`/files/${fileId}/info`, options);
2729
2729
  }
2730
+ /**
2731
+ * Get the calling app's storage + media settings — content policy,
2732
+ * retention, max upload size, and the per-app `media_policy`.
2733
+ *
2734
+ * `media_policy` drives release-gating in the SDK upload helpers:
2735
+ * `fast_trusted` / `safe_visible` resolve immediately on upload; the
2736
+ * `safe_public` / `moderated` / `compliance` modes await pipeline
2737
+ * completion before resolving the upload promise.
2738
+ */
2739
+ async getSettings(options) {
2740
+ return this._get("/settings", options);
2741
+ }
2742
+ /**
2743
+ * Update the calling app's storage + media settings. Admin-only on the
2744
+ * platform side (callers without the right role get 403).
2745
+ */
2746
+ async updateSettings(settings, options) {
2747
+ return this.put("/settings", settings, options);
2748
+ }
2730
2749
  /**
2731
2750
  * Aggregate status for a file — single call returns scan + reserved
2732
2751
  * optimize/transcode slots + the canonical view URL paths for image
@@ -5678,6 +5697,72 @@ var PhotoService = class extends ServiceModule {
5678
5697
  return this.get(id);
5679
5698
  }
5680
5699
  };
5700
+ var AudioService = class extends ServiceModule {
5701
+ /**
5702
+ * @param storage Required for {@link uploadViaStorage}. Wired up by the
5703
+ * top-level {@link ScaleMule} constructor — most call sites should not
5704
+ * instantiate `AudioService` directly.
5705
+ */
5706
+ constructor(client, storage) {
5707
+ super(client);
5708
+ this.storage = storage;
5709
+ this.basePath = "/v1/audios";
5710
+ }
5711
+ /**
5712
+ * Register a storage-uploaded audio asset with the audio service.
5713
+ * Idempotent — re-calling with the same `file_id` returns the existing
5714
+ * record.
5715
+ */
5716
+ async register(args, options) {
5717
+ return this.post("/register", { file_id: args.fileId, sm_user_id: args.userId }, options);
5718
+ }
5719
+ /**
5720
+ * Upload a file to storage (browser → S3 direct, private, uncompressed)
5721
+ * and register it with the audio service.
5722
+ *
5723
+ * Mirrors `photo.uploadViaStorage()` / `video.uploadViaStorage()`. If
5724
+ * `register()` fails after a successful storage upload, the file is *not*
5725
+ * lost — the returned `file_id` is still valid as a generic private storage
5726
+ * file. The SDK logs a warning and returns `audio_id: null`.
5727
+ */
5728
+ async uploadViaStorage(file, uploadOptions, requestOptions) {
5729
+ const uploadResult = await this.storage.uploadPrivate(file, {
5730
+ filename: uploadOptions?.filename,
5731
+ metadata: uploadOptions?.metadata,
5732
+ onProgress: uploadOptions?.onProgress,
5733
+ signal: uploadOptions?.signal
5734
+ });
5735
+ if (uploadResult.error || !uploadResult.data) {
5736
+ return { data: null, error: uploadResult.error };
5737
+ }
5738
+ const fileInfo = uploadResult.data;
5739
+ const fileId = fileInfo.id;
5740
+ const originalViewUrl = fileInfo.url ?? null;
5741
+ const registerResult = await this.register({ fileId, userId: uploadOptions?.userId }, requestOptions);
5742
+ if (registerResult.error || !registerResult.data) {
5743
+ console.warn(
5744
+ "[scalemule-sdk] audio.register() failed after storage upload; typed audio metadata unavailable.",
5745
+ registerResult.error
5746
+ );
5747
+ return {
5748
+ data: {
5749
+ file_id: fileId,
5750
+ audio_id: null,
5751
+ original_view_url: originalViewUrl
5752
+ },
5753
+ error: null
5754
+ };
5755
+ }
5756
+ return {
5757
+ data: {
5758
+ file_id: fileId,
5759
+ audio_id: registerResult.data.audio_id,
5760
+ original_view_url: originalViewUrl
5761
+ },
5762
+ error: null
5763
+ };
5764
+ }
5765
+ };
5681
5766
  var DeadLetterApi = class extends ServiceModule {
5682
5767
  constructor() {
5683
5768
  super(...arguments);
@@ -6497,6 +6582,7 @@ var ScaleMule = class {
6497
6582
  this.graph = new GraphService(this._client);
6498
6583
  this.functions = new FunctionsService(this._client);
6499
6584
  this.photo = new PhotoService(this._client, this.storage);
6585
+ this.audio = new AudioService(this._client, this.storage);
6500
6586
  this.flagContent = new FlagContentService(this._client);
6501
6587
  this.creatorMaker = new CreatorMakerService(this._client);
6502
6588
  this.compliance = new ComplianceService(this._client);
@@ -7585,6 +7671,7 @@ function ScaleMuleProvider({
7585
7671
  storage: baseClient.storage,
7586
7672
  photo: baseClient.photo,
7587
7673
  video: baseClient.video,
7674
+ audio: baseClient.audio,
7588
7675
  mediaPolicy,
7589
7676
  user,
7590
7677
  setUser: handleSetUser,
@@ -8899,7 +8986,7 @@ function useContent(options = {}) {
8899
8986
  );
8900
8987
  }
8901
8988
  function useMedia() {
8902
- const { storage, photo, video, mediaPolicy: providerDefaultPolicy } = useScaleMule();
8989
+ const { storage, photo, video, audio, mediaPolicy: providerDefaultPolicy } = useScaleMule();
8903
8990
  const [uploading, setUploading] = React.useState(false);
8904
8991
  const [error, setError] = React.useState(null);
8905
8992
  const upload = React.useCallback(
@@ -8953,6 +9040,21 @@ function useMedia() {
8953
9040
  is_public: false
8954
9041
  };
8955
9042
  }
9043
+ if (mimeType.startsWith("audio/") && !isPublic) {
9044
+ const r2 = await audio.uploadViaStorage(file, sharedOpts);
9045
+ if (r2.error || !r2.data) {
9046
+ throw r2.error ?? { code: "upload_error", message: "Upload failed", status: 0 };
9047
+ }
9048
+ return {
9049
+ file_id: r2.data.file_id,
9050
+ photo_id: null,
9051
+ original_view_url: r2.data.original_view_url,
9052
+ optimized_url_promise: Promise.resolve(null),
9053
+ hls_url_promise: Promise.resolve(null),
9054
+ mime_type: mimeType,
9055
+ is_public: false
9056
+ };
9057
+ }
8956
9058
  if (mimeType.startsWith("image/") && isPublic) {
8957
9059
  const r2 = await storage.upload(file, {
8958
9060
  ...sharedOpts,
@@ -8995,7 +9097,7 @@ function useMedia() {
8995
9097
  setUploading(false);
8996
9098
  }
8997
9099
  },
8998
- [storage, photo, video, providerDefaultPolicy]
9100
+ [storage, photo, video, audio, providerDefaultPolicy]
8999
9101
  );
9000
9102
  const cancelUpload = React.useCallback(
9001
9103
  async (fileId) => {
package/dist/index.mjs CHANGED
@@ -2707,6 +2707,25 @@ var StorageService = class extends ServiceModule {
2707
2707
  async getInfo(fileId, options) {
2708
2708
  return this._get(`/files/${fileId}/info`, options);
2709
2709
  }
2710
+ /**
2711
+ * Get the calling app's storage + media settings — content policy,
2712
+ * retention, max upload size, and the per-app `media_policy`.
2713
+ *
2714
+ * `media_policy` drives release-gating in the SDK upload helpers:
2715
+ * `fast_trusted` / `safe_visible` resolve immediately on upload; the
2716
+ * `safe_public` / `moderated` / `compliance` modes await pipeline
2717
+ * completion before resolving the upload promise.
2718
+ */
2719
+ async getSettings(options) {
2720
+ return this._get("/settings", options);
2721
+ }
2722
+ /**
2723
+ * Update the calling app's storage + media settings. Admin-only on the
2724
+ * platform side (callers without the right role get 403).
2725
+ */
2726
+ async updateSettings(settings, options) {
2727
+ return this.put("/settings", settings, options);
2728
+ }
2710
2729
  /**
2711
2730
  * Aggregate status for a file — single call returns scan + reserved
2712
2731
  * optimize/transcode slots + the canonical view URL paths for image
@@ -5658,6 +5677,72 @@ var PhotoService = class extends ServiceModule {
5658
5677
  return this.get(id);
5659
5678
  }
5660
5679
  };
5680
+ var AudioService = class extends ServiceModule {
5681
+ /**
5682
+ * @param storage Required for {@link uploadViaStorage}. Wired up by the
5683
+ * top-level {@link ScaleMule} constructor — most call sites should not
5684
+ * instantiate `AudioService` directly.
5685
+ */
5686
+ constructor(client, storage) {
5687
+ super(client);
5688
+ this.storage = storage;
5689
+ this.basePath = "/v1/audios";
5690
+ }
5691
+ /**
5692
+ * Register a storage-uploaded audio asset with the audio service.
5693
+ * Idempotent — re-calling with the same `file_id` returns the existing
5694
+ * record.
5695
+ */
5696
+ async register(args, options) {
5697
+ return this.post("/register", { file_id: args.fileId, sm_user_id: args.userId }, options);
5698
+ }
5699
+ /**
5700
+ * Upload a file to storage (browser → S3 direct, private, uncompressed)
5701
+ * and register it with the audio service.
5702
+ *
5703
+ * Mirrors `photo.uploadViaStorage()` / `video.uploadViaStorage()`. If
5704
+ * `register()` fails after a successful storage upload, the file is *not*
5705
+ * lost — the returned `file_id` is still valid as a generic private storage
5706
+ * file. The SDK logs a warning and returns `audio_id: null`.
5707
+ */
5708
+ async uploadViaStorage(file, uploadOptions, requestOptions) {
5709
+ const uploadResult = await this.storage.uploadPrivate(file, {
5710
+ filename: uploadOptions?.filename,
5711
+ metadata: uploadOptions?.metadata,
5712
+ onProgress: uploadOptions?.onProgress,
5713
+ signal: uploadOptions?.signal
5714
+ });
5715
+ if (uploadResult.error || !uploadResult.data) {
5716
+ return { data: null, error: uploadResult.error };
5717
+ }
5718
+ const fileInfo = uploadResult.data;
5719
+ const fileId = fileInfo.id;
5720
+ const originalViewUrl = fileInfo.url ?? null;
5721
+ const registerResult = await this.register({ fileId, userId: uploadOptions?.userId }, requestOptions);
5722
+ if (registerResult.error || !registerResult.data) {
5723
+ console.warn(
5724
+ "[scalemule-sdk] audio.register() failed after storage upload; typed audio metadata unavailable.",
5725
+ registerResult.error
5726
+ );
5727
+ return {
5728
+ data: {
5729
+ file_id: fileId,
5730
+ audio_id: null,
5731
+ original_view_url: originalViewUrl
5732
+ },
5733
+ error: null
5734
+ };
5735
+ }
5736
+ return {
5737
+ data: {
5738
+ file_id: fileId,
5739
+ audio_id: registerResult.data.audio_id,
5740
+ original_view_url: originalViewUrl
5741
+ },
5742
+ error: null
5743
+ };
5744
+ }
5745
+ };
5661
5746
  var DeadLetterApi = class extends ServiceModule {
5662
5747
  constructor() {
5663
5748
  super(...arguments);
@@ -6477,6 +6562,7 @@ var ScaleMule = class {
6477
6562
  this.graph = new GraphService(this._client);
6478
6563
  this.functions = new FunctionsService(this._client);
6479
6564
  this.photo = new PhotoService(this._client, this.storage);
6565
+ this.audio = new AudioService(this._client, this.storage);
6480
6566
  this.flagContent = new FlagContentService(this._client);
6481
6567
  this.creatorMaker = new CreatorMakerService(this._client);
6482
6568
  this.compliance = new ComplianceService(this._client);
@@ -7565,6 +7651,7 @@ function ScaleMuleProvider({
7565
7651
  storage: baseClient.storage,
7566
7652
  photo: baseClient.photo,
7567
7653
  video: baseClient.video,
7654
+ audio: baseClient.audio,
7568
7655
  mediaPolicy,
7569
7656
  user,
7570
7657
  setUser: handleSetUser,
@@ -8879,7 +8966,7 @@ function useContent(options = {}) {
8879
8966
  );
8880
8967
  }
8881
8968
  function useMedia() {
8882
- const { storage, photo, video, mediaPolicy: providerDefaultPolicy } = useScaleMule();
8969
+ const { storage, photo, video, audio, mediaPolicy: providerDefaultPolicy } = useScaleMule();
8883
8970
  const [uploading, setUploading] = useState(false);
8884
8971
  const [error, setError] = useState(null);
8885
8972
  const upload = useCallback(
@@ -8933,6 +9020,21 @@ function useMedia() {
8933
9020
  is_public: false
8934
9021
  };
8935
9022
  }
9023
+ if (mimeType.startsWith("audio/") && !isPublic) {
9024
+ const r2 = await audio.uploadViaStorage(file, sharedOpts);
9025
+ if (r2.error || !r2.data) {
9026
+ throw r2.error ?? { code: "upload_error", message: "Upload failed", status: 0 };
9027
+ }
9028
+ return {
9029
+ file_id: r2.data.file_id,
9030
+ photo_id: null,
9031
+ original_view_url: r2.data.original_view_url,
9032
+ optimized_url_promise: Promise.resolve(null),
9033
+ hls_url_promise: Promise.resolve(null),
9034
+ mime_type: mimeType,
9035
+ is_public: false
9036
+ };
9037
+ }
8936
9038
  if (mimeType.startsWith("image/") && isPublic) {
8937
9039
  const r2 = await storage.upload(file, {
8938
9040
  ...sharedOpts,
@@ -8975,7 +9077,7 @@ function useMedia() {
8975
9077
  setUploading(false);
8976
9078
  }
8977
9079
  },
8978
- [storage, photo, video, providerDefaultPolicy]
9080
+ [storage, photo, video, audio, providerDefaultPolicy]
8979
9081
  );
8980
9082
  const cancelUpload = useCallback(
8981
9083
  async (fileId) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalemule/nextjs",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "ScaleMule SDK for Next.js applications - authentication, storage, and user management",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -54,7 +54,7 @@
54
54
  },
55
55
  "dependencies": {
56
56
  "@scalemule/money": "^0.0.1",
57
- "@scalemule/sdk": "^0.0.41"
57
+ "@scalemule/sdk": "^0.0.43"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "next": ">=14.0.0",