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