@nocloud/sdk 0.1.0
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/LICENSE +21 -0
- package/README.md +146 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +185 -0
- package/dist/index.js +1 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NoneM
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://assets.nonefivem.com/logo/dark-bg.png" alt="NoneM Logo" width="200" />
|
|
3
|
+
|
|
4
|
+
# @nocloud/sdk
|
|
5
|
+
|
|
6
|
+
**Official SDK for NoCloud services**
|
|
7
|
+
|
|
8
|
+
[](https://www.npmjs.com/package/@nocloud/sdk)
|
|
9
|
+
[](https://www.typescriptlang.org/)
|
|
10
|
+
[](https://opensource.org/licenses/MIT)
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 🚀 Getting Started
|
|
17
|
+
|
|
18
|
+
### Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @nocloud/sdk
|
|
22
|
+
# or
|
|
23
|
+
bun add @nocloud/sdk
|
|
24
|
+
# or
|
|
25
|
+
pnpm add @nocloud/sdk
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Quick Start
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { NoCloud } from "@nocloud/sdk";
|
|
32
|
+
|
|
33
|
+
const cloud = new NoCloud("your-api-key");
|
|
34
|
+
|
|
35
|
+
// Upload a file
|
|
36
|
+
const file = new File(["hello"], "hello.txt", { type: "text/plain" });
|
|
37
|
+
const { id, url } = await cloud.storage.upload(file);
|
|
38
|
+
|
|
39
|
+
console.log(`Uploaded: ${url}`);
|
|
40
|
+
|
|
41
|
+
// Delete a file
|
|
42
|
+
await cloud.storage.delete(id);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 📖 Usage
|
|
48
|
+
|
|
49
|
+
### Initialize
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { NoCloud } from "@nocloud/sdk";
|
|
53
|
+
|
|
54
|
+
// Simple
|
|
55
|
+
const cloud = new NoCloud("your-api-key");
|
|
56
|
+
|
|
57
|
+
// With options
|
|
58
|
+
const cloud = new NoCloud({
|
|
59
|
+
apiKey: "your-api-key",
|
|
60
|
+
baseUrl: "https://api.nonefivem.com", // optional
|
|
61
|
+
retries: 3, // optional
|
|
62
|
+
retryDelayMs: 1000, // optional
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 📦 Storage
|
|
67
|
+
|
|
68
|
+
#### Upload a File
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// From File/Blob
|
|
72
|
+
const file = new File(["content"], "file.txt", { type: "text/plain" });
|
|
73
|
+
const { id, url } = await cloud.storage.upload(file);
|
|
74
|
+
|
|
75
|
+
// From ArrayBuffer
|
|
76
|
+
const buffer = new ArrayBuffer(8);
|
|
77
|
+
const { id, url } = await cloud.storage.upload(buffer);
|
|
78
|
+
|
|
79
|
+
// From base64 string (auto-detects mime type)
|
|
80
|
+
const base64 = "iVBORw0KGgo..."; // PNG base64
|
|
81
|
+
const { id, url } = await cloud.storage.upload(base64);
|
|
82
|
+
|
|
83
|
+
// With metadata
|
|
84
|
+
const { id, url } = await cloud.storage.upload(file, {
|
|
85
|
+
userId: "123",
|
|
86
|
+
category: "avatars",
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### Upload a Stream
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const stream = getReadableStream();
|
|
94
|
+
const { id, url } = await cloud.storage.uploadStream(
|
|
95
|
+
stream,
|
|
96
|
+
"video/mp4",
|
|
97
|
+
fileSize,
|
|
98
|
+
);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### Delete a File
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
await cloud.storage.delete(mediaId);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 📋 Supported Body Types
|
|
110
|
+
|
|
111
|
+
| Type | Description |
|
|
112
|
+
| ------------- | -------------------- |
|
|
113
|
+
| `File` | Browser File object |
|
|
114
|
+
| `Blob` | Binary data |
|
|
115
|
+
| `ArrayBuffer` | Raw binary buffer |
|
|
116
|
+
| `string` | Base64 or plain text |
|
|
117
|
+
|
|
118
|
+
Base64 strings with data URLs (`data:image/png;base64,...`) or raw base64 are automatically detected and the mime type is inferred.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## ⚠️ Error Handling
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { NoCloud, NoCloudAPIError } from "@nocloud/sdk";
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
await cloud.storage.upload(file);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
if (error instanceof NoCloudAPIError) {
|
|
131
|
+
console.error(`API Error: ${error.message} (${error.status})`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 🔧 Compatibility
|
|
139
|
+
|
|
140
|
+
Works in both Node.js (>=18) and browser environments. No Node-specific APIs are used.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 📄 License
|
|
145
|
+
|
|
146
|
+
[MIT](LICENSE) © [NoneM](https://nonefivem.com)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var{defineProperty:u,getOwnPropertyNames:j,getOwnPropertyDescriptor:v}=Object,G=Object.prototype.hasOwnProperty;var U=new WeakMap,M=(r)=>{var x=U.get(r),F;if(x)return x;if(x=u({},"__esModule",{value:!0}),r&&typeof r==="object"||typeof r==="function")j(r).map((f)=>!G.call(x,f)&&u(x,f,{get:()=>r[f],enumerable:!(F=v(r,f))||F.enumerable}));return U.set(r,x),x};var P=(r,x)=>{for(var F in x)u(r,F,{get:x[F],enumerable:!0,configurable:!0,set:(f)=>x[F]=()=>f})};var C={};P(C,{default:()=>w,NoCloudAPIError:()=>h,NoCloud:()=>_});module.exports=M(C);var V="https://api.nonefivem.com";class h extends Error{status;constructor(r,x){super(r);this.status=x;this.name="NoCloudAPIError"}}function k(r){return new Promise((x)=>setTimeout(x,r))}async function W(r,x=3,F=1000){let f;for(let K=0;K<=x;K++)try{return await r()}catch(c){if(f=c,K<x)await k(F)}throw f}var A={iVBORw0KGgo:"image/png","/9j/":"image/jpeg",R0lGOD:"image/gif",UklGR:"image/webp",AAAA:"video/mp4",JVBERi0:"application/pdf",UEsDB:"application/zip",PD94bWw:"application/xml",PHN2Zw:"image/svg+xml"};function X(r){let x=r.match(/^data:([^;,]+)/);if(x?.[1])return x[1];for(let[F,f]of Object.entries(A))if(r.startsWith(F))return f;return null}function Y(r){let x=r.match(/^data:[^;,]+;base64,(.+)$/);if(x?.[1])return x[1];return r}function Z(r){let x=(r.match(/=+$/)||[""])[0].length;return Math.floor(r.length*3/4)-x}class D{baseUrl;apiKey;retryCount;retryDelayMs;constructor(r){if(this.apiKey=r.apiKey,this.baseUrl=r.baseUrl||V,this.retryCount=r.retries??3,this.retryDelayMs=r.retryDelayMs??1000,!this.apiKey)throw Error("API key is required")}buildUrl(r){return`${this.baseUrl}/cloud/${r}`}fetch(r,x={}){let F=this.buildUrl(r);return W(()=>fetch(F,{...x,headers:{Authorization:`Bearer ${this.apiKey}`,...x.headers||{}}}),x.retries??this.retryCount,x.retryDelayMs??this.retryDelayMs)}}async function B(r){if(!r.ok)try{let x=await r.json();throw new h(x.message||"API Error",r.status)}catch(x){throw new h("Unknown error",r.status)}return await r.json()}class H{fetcher;constructor(r){this.fetcher=r}fetch(r,x){return this.fetcher.fetch(r,x)}}class Q extends H{async generateSignedUrl(r,x,F){let f=await this.fetch("storage/signed-url",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentType:r,size:x,metadata:F})});return B(f)}getBodyInfo(r){if(typeof Blob<"u"&&r instanceof Blob)return{contentType:r.type||"application/octet-stream",size:r.size};if(typeof ArrayBuffer<"u"&&r instanceof ArrayBuffer)return{contentType:"application/octet-stream",size:r.byteLength};if(typeof r==="string"){let x=X(r);if(x){let F=Y(r),f=Z(F);return{contentType:x,size:f}}return{contentType:"text/plain",size:new TextEncoder().encode(r).length}}throw new h("Unsupported body type",400)}async upload(r,x){let{contentType:F,size:f}=this.getBodyInfo(r),{url:K,mediaUrl:c,mediaId:$}=await this.generateSignedUrl(F,f,x),O=await fetch(K,{method:"PUT",headers:{"Content-Type":F,"Content-Length":f.toString()},body:r});if(!O.ok){let q=await O.text().catch(()=>O.statusText);throw new h(`Failed to upload file to R2: ${q}`,O.status)}return{id:$,url:c}}async uploadStream(r,x,F,f){let{url:K,mediaUrl:c,mediaId:$}=await this.generateSignedUrl(x,F,f),O=await fetch(K,{method:"PUT",headers:{"Content-Type":x,"Content-Length":F.toString()},body:r,duplex:"half"});if(!O.ok){let q=await O.text().catch(()=>O.statusText);throw new h(`Failed to upload stream to R2: ${q}`,O.status)}return{id:$,url:c}}async delete(r){let x=await this.fetch(`storage/${r}`,{method:"DELETE"});return B(x)}}class _{fetcher;constructor(r){if(typeof r==="string")r={apiKey:r};this.fetcher=new D({apiKey:r.apiKey,baseUrl:r.baseUrl,retries:r.retries,retryDelayMs:r.retryDelayMs})}_storage;get storage(){return this._storage??=new Q(this.fetcher)}}var w=_;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// Generated by dts-bundle-generator v9.5.1
|
|
2
|
+
|
|
3
|
+
export interface FetchOptionsBase {
|
|
4
|
+
retries?: number;
|
|
5
|
+
retryDelayMs?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface FetcherOptions extends FetchOptionsBase {
|
|
8
|
+
apiKey: string;
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
}
|
|
11
|
+
export type FetchOptions = RequestInit & FetchOptionsBase;
|
|
12
|
+
declare class Fetcher {
|
|
13
|
+
private readonly baseUrl;
|
|
14
|
+
private readonly apiKey;
|
|
15
|
+
private readonly retryCount;
|
|
16
|
+
private readonly retryDelayMs;
|
|
17
|
+
constructor(options: FetcherOptions);
|
|
18
|
+
private buildUrl;
|
|
19
|
+
fetch(endpoint: string, options?: FetchOptions): Promise<Response>;
|
|
20
|
+
}
|
|
21
|
+
declare class SDKModule {
|
|
22
|
+
private readonly fetcher;
|
|
23
|
+
constructor(fetcher: Fetcher);
|
|
24
|
+
protected fetch(endpoint: string, options: FetchOptions): Promise<Response>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Upload body types.
|
|
28
|
+
*
|
|
29
|
+
* `File` and `Blob` are streamed.
|
|
30
|
+
* `ArrayBuffer` and `string` are buffered in memory.
|
|
31
|
+
*
|
|
32
|
+
* `string` values (e.g. Base64) are uploaded as-is.
|
|
33
|
+
*/
|
|
34
|
+
export type FileBody = File | Blob | ArrayBuffer | string;
|
|
35
|
+
/**
|
|
36
|
+
* Metadata associated with a file.
|
|
37
|
+
*/
|
|
38
|
+
export type FileMetadata = Record<string, string | number | boolean>;
|
|
39
|
+
/**
|
|
40
|
+
* Response returned after a successful file upload.
|
|
41
|
+
*/
|
|
42
|
+
export interface UploadResponse {
|
|
43
|
+
/**
|
|
44
|
+
* The unique identifier for the uploaded file.
|
|
45
|
+
*/
|
|
46
|
+
id: string;
|
|
47
|
+
/**
|
|
48
|
+
* The public URL where the uploaded file can be accessed.
|
|
49
|
+
*/
|
|
50
|
+
url: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Response returned when requesting a signed URL for uploading media.
|
|
54
|
+
*/
|
|
55
|
+
export interface SignedUrlResponse {
|
|
56
|
+
/**
|
|
57
|
+
* The signed URL for uploading the file.
|
|
58
|
+
*/
|
|
59
|
+
url: string;
|
|
60
|
+
/**
|
|
61
|
+
* The expiration time of the signed URL in ISO 8601 format.
|
|
62
|
+
*/
|
|
63
|
+
expiresAt: string;
|
|
64
|
+
/**
|
|
65
|
+
* The unique identifier for the media after upload.
|
|
66
|
+
*/
|
|
67
|
+
mediaId: string;
|
|
68
|
+
/**
|
|
69
|
+
* The public URL to access the media after upload.
|
|
70
|
+
*/
|
|
71
|
+
mediaUrl: string;
|
|
72
|
+
}
|
|
73
|
+
declare class Storage$1 extends SDKModule {
|
|
74
|
+
/**
|
|
75
|
+
* Generates a signed URL for uploading a file.
|
|
76
|
+
* @param contentType - The MIME type of the file.
|
|
77
|
+
* @param size - The size of the file in bytes.
|
|
78
|
+
* @param metadata - Optional metadata associated with the file.
|
|
79
|
+
* @returns {Promise<SignedUrlResponse>} An object containing the signed URL and its expiration time.
|
|
80
|
+
* @throws {NoCloudAPIError} If the API request fails.
|
|
81
|
+
*/
|
|
82
|
+
generateSignedUrl(contentType: string, size: number, metadata?: FileMetadata): Promise<SignedUrlResponse>;
|
|
83
|
+
/**
|
|
84
|
+
* Extracts content type and size from the body.
|
|
85
|
+
*/
|
|
86
|
+
private getBodyInfo;
|
|
87
|
+
/**
|
|
88
|
+
* Uploads a file to R2 storage using S3-compatible API.
|
|
89
|
+
* @param body The file body to upload. Supports File, Blob, ArrayBuffer, or string.
|
|
90
|
+
* @param metadata Optional metadata associated with the file.
|
|
91
|
+
* @returns {Promise<UploadResponse>} An object containing the upload ID and URL.
|
|
92
|
+
* @throws {NoCloudAPIError} If the upload fails.
|
|
93
|
+
*/
|
|
94
|
+
upload(body: FileBody, metadata?: FileMetadata): Promise<UploadResponse>;
|
|
95
|
+
/**
|
|
96
|
+
* Uploads a ReadableStream to R2 storage using S3-compatible API.
|
|
97
|
+
* @param stream The ReadableStream to upload.
|
|
98
|
+
* @param contentType The MIME type of the content.
|
|
99
|
+
* @param contentLength The size of the content in bytes.
|
|
100
|
+
* @param metadata Optional metadata associated with the file.
|
|
101
|
+
* @returns {Promise<UploadResponse>} An object containing the upload ID and URL.
|
|
102
|
+
* @throws {NoCloudAPIError} If the upload fails.
|
|
103
|
+
*/
|
|
104
|
+
uploadStream(stream: ReadableStream, contentType: string, contentLength: number, metadata?: FileMetadata): Promise<UploadResponse>;
|
|
105
|
+
/**
|
|
106
|
+
* Deletes a media file from the storage.
|
|
107
|
+
* @param mediaId The ID of the media file to be deleted.
|
|
108
|
+
* @returns {Promise<void>} A promise that resolves when the deletion is complete.
|
|
109
|
+
* @throws {NoCloudAPIError} If the deletion fails.
|
|
110
|
+
*/
|
|
111
|
+
delete(mediaId: string): Promise<void>;
|
|
112
|
+
}
|
|
113
|
+
export interface NoCloudOptions {
|
|
114
|
+
/**
|
|
115
|
+
* Your API key for authenticating requests.
|
|
116
|
+
*/
|
|
117
|
+
apiKey: string;
|
|
118
|
+
/**
|
|
119
|
+
* Optional base URL for the API.
|
|
120
|
+
* @default "https://api.nonefivem.com"
|
|
121
|
+
*/
|
|
122
|
+
baseUrl?: string;
|
|
123
|
+
/**
|
|
124
|
+
* Number of retry attempts for failed requests.
|
|
125
|
+
* @default 3
|
|
126
|
+
*/
|
|
127
|
+
retries?: number;
|
|
128
|
+
/**
|
|
129
|
+
* Delay in milliseconds between retry attempts.
|
|
130
|
+
* @default 1000
|
|
131
|
+
*/
|
|
132
|
+
retryDelayMs?: number;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Main SDK class for interacting with NoCloud services.
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* // Using a string API key
|
|
139
|
+
* const cloud = new NoCloud("your-api-key");
|
|
140
|
+
*
|
|
141
|
+
* // Using an options object
|
|
142
|
+
* const cloud = new NoCloud({
|
|
143
|
+
* apiKey: "your-api-key",
|
|
144
|
+
* baseUrl: "https://api.nonefivem.com",
|
|
145
|
+
* retries: 5,
|
|
146
|
+
* retryDelayMs: 2000,
|
|
147
|
+
* });
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
export declare class NoCloud {
|
|
151
|
+
private readonly fetcher;
|
|
152
|
+
/**
|
|
153
|
+
* Creates an instance of the NoCloud SDK.
|
|
154
|
+
* @param options - Your API key or an options object.
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* // Using a string API key
|
|
158
|
+
* const cloud = new NoCloud("your-api-key");
|
|
159
|
+
*
|
|
160
|
+
* // Using an options object
|
|
161
|
+
* const cloud = new NoCloud({
|
|
162
|
+
* apiKey: "your-api-key",
|
|
163
|
+
* baseUrl: "https://api.nonefivem.com",
|
|
164
|
+
* retries: 5,
|
|
165
|
+
* retryDelayMs: 1000,
|
|
166
|
+
* });
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
constructor(options: string | NoCloudOptions);
|
|
170
|
+
private _storage?;
|
|
171
|
+
/**
|
|
172
|
+
* Storage module for handling file storage operations.
|
|
173
|
+
*/
|
|
174
|
+
get storage(): Storage$1;
|
|
175
|
+
}
|
|
176
|
+
export declare class NoCloudAPIError extends Error {
|
|
177
|
+
readonly status: number;
|
|
178
|
+
constructor(message: string, status: number);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export {
|
|
182
|
+
NoCloud as default,
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var Q="https://api.nonefivem.com";class h extends Error{status;constructor(r,x){super(r);this.status=x;this.name="NoCloudAPIError"}}function Y(r){return new Promise((x)=>setTimeout(x,r))}async function U(r,x=3,F=1000){let f;for(let K=0;K<=x;K++)try{return await r()}catch(c){if(f=c,K<x)await Y(F)}throw f}var Z={iVBORw0KGgo:"image/png","/9j/":"image/jpeg",R0lGOD:"image/gif",UklGR:"image/webp",AAAA:"video/mp4",JVBERi0:"application/pdf",UEsDB:"application/zip",PD94bWw:"application/xml",PHN2Zw:"image/svg+xml"};function V(r){let x=r.match(/^data:([^;,]+)/);if(x?.[1])return x[1];for(let[F,f]of Object.entries(Z))if(r.startsWith(F))return f;return null}function W(r){let x=r.match(/^data:[^;,]+;base64,(.+)$/);if(x?.[1])return x[1];return r}function X(r){let x=(r.match(/=+$/)||[""])[0].length;return Math.floor(r.length*3/4)-x}class q{baseUrl;apiKey;retryCount;retryDelayMs;constructor(r){if(this.apiKey=r.apiKey,this.baseUrl=r.baseUrl||Q,this.retryCount=r.retries??3,this.retryDelayMs=r.retryDelayMs??1000,!this.apiKey)throw Error("API key is required")}buildUrl(r){return`${this.baseUrl}/cloud/${r}`}fetch(r,x={}){let F=this.buildUrl(r);return U(()=>fetch(F,{...x,headers:{Authorization:`Bearer ${this.apiKey}`,...x.headers||{}}}),x.retries??this.retryCount,x.retryDelayMs??this.retryDelayMs)}}async function u(r){if(!r.ok)try{let x=await r.json();throw new h(x.message||"API Error",r.status)}catch(x){throw new h("Unknown error",r.status)}return await r.json()}class D{fetcher;constructor(r){this.fetcher=r}fetch(r,x){return this.fetcher.fetch(r,x)}}class B extends D{async generateSignedUrl(r,x,F){let f=await this.fetch("storage/signed-url",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentType:r,size:x,metadata:F})});return u(f)}getBodyInfo(r){if(typeof Blob<"u"&&r instanceof Blob)return{contentType:r.type||"application/octet-stream",size:r.size};if(typeof ArrayBuffer<"u"&&r instanceof ArrayBuffer)return{contentType:"application/octet-stream",size:r.byteLength};if(typeof r==="string"){let x=V(r);if(x){let F=W(r),f=X(F);return{contentType:x,size:f}}return{contentType:"text/plain",size:new TextEncoder().encode(r).length}}throw new h("Unsupported body type",400)}async upload(r,x){let{contentType:F,size:f}=this.getBodyInfo(r),{url:K,mediaUrl:c,mediaId:_}=await this.generateSignedUrl(F,f,x),O=await fetch(K,{method:"PUT",headers:{"Content-Type":F,"Content-Length":f.toString()},body:r});if(!O.ok){let $=await O.text().catch(()=>O.statusText);throw new h(`Failed to upload file to R2: ${$}`,O.status)}return{id:_,url:c}}async uploadStream(r,x,F,f){let{url:K,mediaUrl:c,mediaId:_}=await this.generateSignedUrl(x,F,f),O=await fetch(K,{method:"PUT",headers:{"Content-Type":x,"Content-Length":F.toString()},body:r,duplex:"half"});if(!O.ok){let $=await O.text().catch(()=>O.statusText);throw new h(`Failed to upload stream to R2: ${$}`,O.status)}return{id:_,url:c}}async delete(r){let x=await this.fetch(`storage/${r}`,{method:"DELETE"});return u(x)}}class H{fetcher;constructor(r){if(typeof r==="string")r={apiKey:r};this.fetcher=new q({apiKey:r.apiKey,baseUrl:r.baseUrl,retries:r.retries,retryDelayMs:r.retryDelayMs})}_storage;get storage(){return this._storage??=new B(this.fetcher)}}var s=H;export{s as default,h as NoCloudAPIError,H as NoCloud};
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nocloud/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official SDK for NoCloud services - file storage and more",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "sinanovicanes",
|
|
7
|
+
"email": "anes@nonefivem.com",
|
|
8
|
+
"url": "https://nonefivem.com"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/nonefivem/no-cloud-sdk.git"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/nonefivem/no-cloud-sdk#readme",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/nonefivem/no-cloud-sdk/issues"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"nocloud",
|
|
21
|
+
"no-cloud",
|
|
22
|
+
"nonem",
|
|
23
|
+
"nonefivem",
|
|
24
|
+
"sdk",
|
|
25
|
+
"storage",
|
|
26
|
+
"r2",
|
|
27
|
+
"s3",
|
|
28
|
+
"file-upload",
|
|
29
|
+
"api"
|
|
30
|
+
],
|
|
31
|
+
"type": "module",
|
|
32
|
+
"main": "./dist/index.js",
|
|
33
|
+
"module": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"default": "./dist/index.js"
|
|
40
|
+
},
|
|
41
|
+
"require": {
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"default": "./dist/index.cjs"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"dist",
|
|
49
|
+
"README.md",
|
|
50
|
+
"LICENSE"
|
|
51
|
+
],
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "bun run clean && bun run build:js && bun run build:types",
|
|
54
|
+
"build:js": "bun build ./src/index.ts --outfile ./dist/index.js --target browser --format esm --minify && bun build ./src/index.ts --outfile ./dist/index.cjs --target browser --format cjs --minify",
|
|
55
|
+
"build:types": "bun x dts-bundle-generator -o ./dist/index.d.ts ./src/index.ts --project ./tsconfig.build.json --no-check",
|
|
56
|
+
"clean": "rm -rf dist",
|
|
57
|
+
"prepublishOnly": "bun run build",
|
|
58
|
+
"typecheck": "tsc --noEmit"
|
|
59
|
+
},
|
|
60
|
+
"private": false,
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@types/node": "^22.0.0",
|
|
63
|
+
"typescript": "^5.7.0"
|
|
64
|
+
},
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=18.0.0"
|
|
67
|
+
}
|
|
68
|
+
}
|