@stack0/sdk 0.4.0 → 0.5.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/dist/index.mjs CHANGED
@@ -599,6 +599,273 @@ var CDN = class {
599
599
  }
600
600
  return job;
601
601
  }
602
+ // ============================================================================
603
+ // Private Files Methods
604
+ // ============================================================================
605
+ /**
606
+ * Generate a presigned URL for uploading a private file
607
+ *
608
+ * Private files are stored securely and can only be accessed through
609
+ * authorized download links with configurable expiration.
610
+ *
611
+ * @example
612
+ * ```typescript
613
+ * const { uploadUrl, fileId } = await cdn.getPrivateUploadUrl({
614
+ * projectSlug: 'my-project',
615
+ * filename: 'confidential.pdf',
616
+ * mimeType: 'application/pdf',
617
+ * size: 1024 * 1024,
618
+ * });
619
+ *
620
+ * // Upload file to the presigned URL
621
+ * await fetch(uploadUrl, {
622
+ * method: 'PUT',
623
+ * body: file,
624
+ * headers: { 'Content-Type': 'application/pdf' },
625
+ * });
626
+ *
627
+ * // Confirm the upload
628
+ * const privateFile = await cdn.confirmPrivateUpload(fileId);
629
+ * ```
630
+ */
631
+ async getPrivateUploadUrl(request) {
632
+ const response = await this.http.post("/cdn/private/upload", request);
633
+ if (typeof response.expiresAt === "string") {
634
+ response.expiresAt = new Date(response.expiresAt);
635
+ }
636
+ return response;
637
+ }
638
+ /**
639
+ * Confirm that a private file upload has completed
640
+ */
641
+ async confirmPrivateUpload(fileId) {
642
+ const response = await this.http.post(`/cdn/private/upload/${fileId}/confirm`, {});
643
+ return this.convertPrivateFileDates(response);
644
+ }
645
+ /**
646
+ * Upload a private file directly (handles presigned URL flow automatically)
647
+ *
648
+ * @example
649
+ * ```typescript
650
+ * const privateFile = await cdn.uploadPrivate({
651
+ * projectSlug: 'my-project',
652
+ * file: fileBuffer,
653
+ * filename: 'confidential.pdf',
654
+ * mimeType: 'application/pdf',
655
+ * });
656
+ * ```
657
+ */
658
+ async uploadPrivate(options) {
659
+ const { projectSlug, file, filename, mimeType, folder, description, metadata } = options;
660
+ let size;
661
+ if (file instanceof Blob) {
662
+ size = file.size;
663
+ } else if (file instanceof ArrayBuffer) {
664
+ size = file.byteLength;
665
+ } else {
666
+ size = file.length;
667
+ }
668
+ const { uploadUrl, fileId } = await this.getPrivateUploadUrl({
669
+ projectSlug,
670
+ filename,
671
+ mimeType,
672
+ size,
673
+ folder,
674
+ description,
675
+ metadata
676
+ });
677
+ const uploadResponse = await fetch(uploadUrl, {
678
+ method: "PUT",
679
+ body: file,
680
+ headers: {
681
+ "Content-Type": mimeType
682
+ }
683
+ });
684
+ if (!uploadResponse.ok) {
685
+ throw new Error(`Upload failed: ${uploadResponse.statusText}`);
686
+ }
687
+ return this.confirmPrivateUpload(fileId);
688
+ }
689
+ /**
690
+ * Generate a presigned download URL for a private file
691
+ *
692
+ * @example
693
+ * ```typescript
694
+ * const { downloadUrl, expiresAt } = await cdn.getPrivateDownloadUrl({
695
+ * fileId: 'file-id',
696
+ * expiresIn: 86400, // 24 hours
697
+ * });
698
+ * ```
699
+ */
700
+ async getPrivateDownloadUrl(request) {
701
+ const response = await this.http.post(
702
+ `/cdn/private/${request.fileId}/download`,
703
+ { expiresIn: request.expiresIn }
704
+ );
705
+ if (typeof response.expiresAt === "string") {
706
+ response.expiresAt = new Date(response.expiresAt);
707
+ }
708
+ return response;
709
+ }
710
+ /**
711
+ * Get a private file by ID
712
+ */
713
+ async getPrivateFile(fileId) {
714
+ const response = await this.http.get(`/cdn/private/${fileId}`);
715
+ return this.convertPrivateFileDates(response);
716
+ }
717
+ /**
718
+ * Update a private file's metadata
719
+ */
720
+ async updatePrivateFile(request) {
721
+ const { fileId, ...data } = request;
722
+ const response = await this.http.patch(`/cdn/private/${fileId}`, data);
723
+ return this.convertPrivateFileDates(response);
724
+ }
725
+ /**
726
+ * Delete a private file
727
+ */
728
+ async deletePrivateFile(fileId) {
729
+ return this.http.deleteWithBody(`/cdn/private/${fileId}`, { fileId });
730
+ }
731
+ /**
732
+ * Delete multiple private files
733
+ */
734
+ async deletePrivateFiles(fileIds) {
735
+ return this.http.post("/cdn/private/delete", { fileIds });
736
+ }
737
+ /**
738
+ * List private files with filters and pagination
739
+ *
740
+ * @example
741
+ * ```typescript
742
+ * const { files, total, hasMore } = await cdn.listPrivateFiles({
743
+ * projectSlug: 'my-project',
744
+ * limit: 20,
745
+ * });
746
+ * ```
747
+ */
748
+ async listPrivateFiles(request) {
749
+ const params = new URLSearchParams();
750
+ params.set("projectSlug", request.projectSlug);
751
+ if (request.folder !== void 0) params.set("folder", request.folder ?? "");
752
+ if (request.status) params.set("status", request.status);
753
+ if (request.search) params.set("search", request.search);
754
+ if (request.sortBy) params.set("sortBy", request.sortBy);
755
+ if (request.sortOrder) params.set("sortOrder", request.sortOrder);
756
+ if (request.limit) params.set("limit", request.limit.toString());
757
+ if (request.offset) params.set("offset", request.offset.toString());
758
+ const response = await this.http.get(`/cdn/private?${params.toString()}`);
759
+ return {
760
+ ...response,
761
+ files: response.files.map((file) => this.convertPrivateFileDates(file))
762
+ };
763
+ }
764
+ convertPrivateFileDates(file) {
765
+ if (typeof file.createdAt === "string") {
766
+ file.createdAt = new Date(file.createdAt);
767
+ }
768
+ if (file.updatedAt && typeof file.updatedAt === "string") {
769
+ file.updatedAt = new Date(file.updatedAt);
770
+ }
771
+ return file;
772
+ }
773
+ // ============================================================================
774
+ // Download Bundle Methods
775
+ // ============================================================================
776
+ /**
777
+ * Create a download bundle from assets and/or private files
778
+ *
779
+ * The bundle will be created asynchronously. Check the status using getBundle().
780
+ *
781
+ * @example
782
+ * ```typescript
783
+ * const { bundle } = await cdn.createBundle({
784
+ * projectSlug: 'my-project',
785
+ * name: 'Project Assets - Dec 2024',
786
+ * assetIds: ['asset-1', 'asset-2'],
787
+ * privateFileIds: ['file-1', 'file-2'],
788
+ * expiresIn: 86400, // 24 hours
789
+ * });
790
+ * console.log(`Bundle ${bundle.id} status: ${bundle.status}`);
791
+ * ```
792
+ */
793
+ async createBundle(request) {
794
+ const response = await this.http.post("/cdn/bundles", request);
795
+ return {
796
+ bundle: this.convertBundleDates(response.bundle)
797
+ };
798
+ }
799
+ /**
800
+ * Get a download bundle by ID
801
+ */
802
+ async getBundle(bundleId) {
803
+ const response = await this.http.get(`/cdn/bundles/${bundleId}`);
804
+ return this.convertBundleDates(response);
805
+ }
806
+ /**
807
+ * List download bundles with filters and pagination
808
+ *
809
+ * @example
810
+ * ```typescript
811
+ * const { bundles, total } = await cdn.listBundles({
812
+ * projectSlug: 'my-project',
813
+ * status: 'ready',
814
+ * });
815
+ * ```
816
+ */
817
+ async listBundles(request) {
818
+ const params = new URLSearchParams();
819
+ params.set("projectSlug", request.projectSlug);
820
+ if (request.status) params.set("status", request.status);
821
+ if (request.search) params.set("search", request.search);
822
+ if (request.limit) params.set("limit", request.limit.toString());
823
+ if (request.offset) params.set("offset", request.offset.toString());
824
+ const response = await this.http.get(`/cdn/bundles?${params.toString()}`);
825
+ return {
826
+ ...response,
827
+ bundles: response.bundles.map((bundle) => this.convertBundleDates(bundle))
828
+ };
829
+ }
830
+ /**
831
+ * Generate a presigned download URL for a bundle
832
+ *
833
+ * @example
834
+ * ```typescript
835
+ * const { downloadUrl, expiresAt } = await cdn.getBundleDownloadUrl({
836
+ * bundleId: 'bundle-id',
837
+ * expiresIn: 3600, // 1 hour
838
+ * });
839
+ * ```
840
+ */
841
+ async getBundleDownloadUrl(request) {
842
+ const response = await this.http.post(
843
+ `/cdn/bundles/${request.bundleId}/download`,
844
+ { expiresIn: request.expiresIn }
845
+ );
846
+ if (typeof response.expiresAt === "string") {
847
+ response.expiresAt = new Date(response.expiresAt);
848
+ }
849
+ return response;
850
+ }
851
+ /**
852
+ * Delete a download bundle
853
+ */
854
+ async deleteBundle(bundleId) {
855
+ return this.http.deleteWithBody(`/cdn/bundles/${bundleId}`, { bundleId });
856
+ }
857
+ convertBundleDates(bundle) {
858
+ if (typeof bundle.createdAt === "string") {
859
+ bundle.createdAt = new Date(bundle.createdAt);
860
+ }
861
+ if (bundle.completedAt && typeof bundle.completedAt === "string") {
862
+ bundle.completedAt = new Date(bundle.completedAt);
863
+ }
864
+ if (bundle.expiresAt && typeof bundle.expiresAt === "string") {
865
+ bundle.expiresAt = new Date(bundle.expiresAt);
866
+ }
867
+ return bundle;
868
+ }
602
869
  };
603
870
 
604
871
  // src/screenshots/client.ts