@neonwilderness/ecjsonstorage 1.0.3 → 1.0.5

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/CHANGELOG.md CHANGED
@@ -18,3 +18,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
18
18
  ## [1.0.3] - 2026-09-30
19
19
  - Change package name to @neonwilderness/ecjsonstorage
20
20
  - Adapt installation
21
+
22
+ ## [1.0.4] - 2026-10-01
23
+ - Throw when param "bin" is missing (getBin, updateBin, patchBin and deleteBin)
package/README.md CHANGED
@@ -1,18 +1,18 @@
1
1
  # About ECJsonStorage
2
2
  ECJsonStorage is a TS/JS wrapper to the [ExtendsClass JSON Storage API](https://extendsclass.com/json-storage.html) offering of Cyril Bois.
3
3
 
4
- For API usage, you need a (free) API-Key for which you can apply [here](https://extendsclass.com/create-account-form).
4
+ For API usage, you need a (free) API-Key for which you can apply on the [ExtendsClass site](https://extendsclass.com/create-account-form).
5
5
 
6
- ECJsonStorage enables you to create, update, patch and delete Bins, which store JSON data. There is a usage limit of
6
+ ECJsonStorage enables you to create, update, patch and delete "Bins" to store JSON data. There is a usage limit of
7
7
  - 10.000 calls per month
8
8
  - Bin size limit of 100kb
9
9
  - total account limit of 10mb.
10
10
 
11
11
  # Installation
12
12
 
13
- - `npm i @neonwilderness/ecjsonstorage -S` to install the module, which is then both available as CommonJs and ESM version.
13
+ - `npm i @neonwilderness/ecjsonstorage -S` to install the package (available as CommonJs and ESM).
14
14
 
15
- - Create an .env file in your project directory root and add the following keys:
15
+ - Copy the `.env.template` to your project folder and create a related `.env` file by adding at least the following keys:
16
16
 
17
17
  `JSONAPI=your ExtendsClass Api-key`
18
18
 
@@ -24,26 +24,176 @@
24
24
 
25
25
  # Usage
26
26
 
27
- ## Constructor
27
+ ## Constructor
28
28
 
29
- ```
30
- import { ECJsonStorage } from '@neonwilderness/ecjsonstorage';
31
- import { config } from 'dotenv-safe';
32
- config();
29
+ ### constructor(apiKey: string, securityKey?: string, url?: string)
33
30
 
34
- const json = new ECJsonStorage(process.env.JSONAPI, process.env.JSONSEC);
35
- ...
36
- ```
31
+ ```
32
+ import { ECJsonStorage } from '@neonwilderness/ecjsonstorage';
33
+ import { config } from 'dotenv-safe';
34
+ config();
37
35
 
38
- ## Create a new bin
36
+ const json = new ECJsonStorage(process.env.JSONAPI, process.env.JSONSEC);
37
+ ...
38
+ ```
39
39
 
40
- `createBin(payload: object, keepPrivate: boolean)`
40
+ > Param `url` will only be needed once the main API address changes. To protect your bins from unauthorized access, you should use a Security-key and pass it as the second parameter.
41
41
 
42
- ```
43
- const json = new ECJsonStorage(process.env.JSONAPI, process.env.JSONSEC);
44
- const payload = { name: 'Neon', profession: 'IT-Consultant' };
45
- const res = await json.createBin(payload, true);
46
- console.log(res);
47
- ```
42
+ ## Create a new bin
48
43
 
49
- Further Documentation/Usage details will follow swiftly; for now you may wanna consult the [TS types file](dist/index.d.ts).
44
+ ### createBin(payload: object, keepPrivate: boolean): Promise<resCreateBin | resError>
45
+
46
+ Param | Type | Text
47
+ --- | --- | ---
48
+ payload | object | JSON object
49
+ keepPrivate | boolean | TRUE=Bin is kept private | Security-key needed for access
50
+
51
+ resCreateBin Property | Type | Text
52
+ --- | --- | ---
53
+ status | string | 'ok'
54
+ uri | string | full URI of the created bin
55
+ bin | string | bin ID
56
+
57
+ <u>or</u>
58
+
59
+ resError Property | Type | Text
60
+ --- | --- | ---
61
+ status | string | 'error'
62
+ statusText | string | error text
63
+
64
+ > If an error occurs, the returned object is always `<resError>`.
65
+
66
+ > Best practice is to always check `res.status` first. If it's not 'ok' (lowercase), then the class function did not run successfully.
67
+
68
+ ```
69
+ const json = new ECJsonStorage(process.env.JSONAPI, process.env.JSONSEC);
70
+ const payload = { name: 'Neon', profession: 'IT-Consultant' };
71
+ const res = await json.createBin(payload, true);
72
+ console.log(res);
73
+ ```
74
+
75
+ ## Get all bin IDs
76
+
77
+ ### getBins(): Promise<resGetBins | resError>
78
+
79
+ This function returns all bins that have been created (and still exist) for the given Api-key. It also returns the current quota limit, i.e. number of calls made and number of ramaining calls (Limit is 10.000 calls per month).
80
+
81
+ resGetBins Property | Type | Text
82
+ --- | --- | ---
83
+ status | string | 'ok'
84
+ callsDone | number | number of API calls made this month
85
+ callsRemaining | number | number of API calls remaining before the limit kicks in
86
+ bins | string[] | array of strings (bin ID)
87
+
88
+ ```
89
+ const json = new ECJsonStorage(process.env.JSONAPI, process.env.JSONSEC);
90
+ const res = await json.getBins();
91
+ console.log(`I have ${res.bins.length} bins and the IDs are: ${res.bins}`);
92
+ ```
93
+
94
+ ## Get statistics (Quota limit)
95
+
96
+ ### getStats(): Promise<resGetStats | resError>
97
+
98
+ This function is a syntactic sugar function for getBins and only returns the current quota limit, i.e. number of calls made and number of ramaining calls.
99
+
100
+ resGetStats Property | Type | Text
101
+ --- | --- | ---
102
+ status | string | 'ok'
103
+ callsDone | number | number of API calls made this month
104
+ callsRemaining | number | number of API calls remaining before the limit kicks in
105
+
106
+ ```
107
+ const json = new ECJsonStorage(process.env.JSONAPI, process.env.JSONSEC);
108
+ const res = await json.getStats();
109
+ console.log(`Used calls: ${res.callsDone}, calls remaining: ${res.callsRemaining}`);
110
+ ```
111
+
112
+ ## Get a bin's content
113
+
114
+ ### getBin(bin: string): Promise<resGetBin | resError>
115
+
116
+ This function reads the bin and returns its content.
117
+
118
+ Param | Type | Text
119
+ --- | --- | ---
120
+ bin | string | Bin ID to read
121
+
122
+ resGetBin Property | Type | Text
123
+ --- | --- | ---
124
+ status | string | 'ok'
125
+ data | object | JSON object (Content of bin)
126
+
127
+ ```
128
+ const json = new ECJsonStorage(process.env.JSONAPI, process.env.JSONSEC);
129
+ const res = await json.getBin('c8ba8b1da99c');
130
+ console.log(res.data);
131
+ ```
132
+
133
+ ## Update a bin
134
+
135
+ ### updateBin(payload: object, bin: string): Promise<resUpdateBin | resError>
136
+
137
+ Param | Type | Text
138
+ --- | --- | ---
139
+ payload | object | JSON object
140
+ bin | string | Bin ID to be updated
141
+
142
+ resUpdateBin Property | Type | Text
143
+ --- | --- | ---
144
+ status | string | 'ok'
145
+ data | string | Stringified JSON object (Content of updated bin)
146
+
147
+ ```
148
+ const json = new ECJsonStorage(process.env.JSONAPI, process.env.JSONSEC);
149
+ const newPayload = { name: 'Wilderness', profession: 'Web Ninja' };
150
+ const res = await json.updateBin(newPayload, 'c8ba8b1da99c');
151
+ console.log(res);
152
+ ```
153
+
154
+ ## Patch a bin
155
+
156
+ ### patchBin(payload: object, bin: string): Promise<resPatchBin | resError>
157
+
158
+ Param | Type | Text
159
+ --- | --- | ---
160
+ payload | object | JSON object
161
+ bin | string | Bin ID to be patched
162
+
163
+ resUpdateBin Property | Type | Text
164
+ --- | --- | ---
165
+ status | string | 'ok'
166
+ data | string | Stringified JSON object (Content of patched bin)
167
+
168
+ ```
169
+ const json = new ECJsonStorage(process.env.JSONAPI, process.env.JSONSEC);
170
+ //current bin = { name: 'Wilderness', profession: 'Web Ninja' }
171
+ const addPayload = { song: 'In a NeonWilderness he was restless', state: 'Germany' };
172
+ const res = await json.patchBin(addPayload, 'c8ba8b1da99c');
173
+ console.log(res);
174
+ //patched bin = { name: 'Wilderness', profession: 'Web Ninja', song: 'In a NeonWilderness he was restless', state: 'Germany' }
175
+ ```
176
+
177
+ > For more information regarding PATCH, please refer to the [ExtendsClass site - "Partially update JSON"](https://extendsclass.com/json-storage.html#apiDocumentation).
178
+
179
+ ## Delete a bin
180
+
181
+ ### deleteBin(bin: string): Promise<resDeleteBin | resError>
182
+
183
+ Param | Type | Text
184
+ --- | --- | ---
185
+ bin | string | Bin ID to be deleted
186
+
187
+ resDeleteBin Property | Type | Text
188
+ --- | --- | ---
189
+ status | string | 'ok'
190
+
191
+ ```
192
+ const json = new ECJsonStorage(process.env.JSONAPI, process.env.JSONSEC);
193
+ const bin = 'c8ba8b1da99c';
194
+ const res = await json.deleteBin(bin);
195
+ if (res.status !== 'ok')
196
+ console.error(`Could not delete bin ${bin}, error=${<resError>statusText}.`);
197
+ ```
198
+
199
+ In addition, you also may wanna consult the [TS types file](dist/index.d.ts).
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var a=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var y=(i,t)=>{for(var e in t)a(i,e,{get:t[e],enumerable:!0})},l=(i,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of u(t))!h.call(i,s)&&s!==e&&a(i,s,{get:()=>t[s],enumerable:!(r=p(t,s))||r.enumerable});return i};var d=i=>l(a({},"__esModule",{value:!0}),i);var g={};y(g,{ECJsonStorage:()=>o});module.exports=d(g);var o=class{url;apiKey;securityKey;monthlyLimit=1e4;constructor(t,e,r){if(this.url=r||"https://json.extendsclass.com/bin",this.apiKey=t||"",this.securityKey=e||"",!this.url||!this.apiKey)throw new Error("Invalid constructor params!");for(;this.url.endsWith("/");)this.url=this.url.slice(0,-1)}validateResponse=async t=>{if(!t.ok)throw new Error(`HTTP error! Status: ${t.status}`);if((t.headers.get("content-type")||"").startsWith("text/html"))throw new Error(`Expected JSON but server returned HTML: "${(await t.text()).slice(0,100)}..."`)};getBins=async()=>{try{let t=await fetch(`${this.url}s`,{method:"GET",headers:{"Api-key":this.apiKey,Accept:"application/json"}});await this.validateResponse(t);let e=Number(t.headers.get("x-counter")),r=await t.json();return{status:"ok",callsDone:e,callsRemaining:this.monthlyLimit-e,bins:r}}catch(t){return console.error("getBins error:",t),{status:"error",statusText:t}}};getStats=async()=>{try{let t=await this.getBins();if(t.status==="error")throw new Error(`HTTP error! Status: ${t.statusText}`);return delete t.bins,t}catch(t){return console.error("getStats error:",t),{status:"error",statusText:t}}};getBin=async t=>{try{if(!t)throw new Error("Bin ID missing!");let e=await fetch(`${this.url}/${t}`,{method:"GET",headers:{"Security-key":this.securityKey,Accept:"application/json"}});return await this.validateResponse(e),{status:"ok",data:await e.json()}}catch(e){return console.error("getBin error:",e),{status:"error",statusText:e}}};createBin=async(t,e)=>{let r=new Headers({"Api-key":this.apiKey,"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"});r.append("Private",e.toString());try{let s=await fetch(this.url,{method:"POST",headers:r,body:JSON.stringify(t)});await this.validateResponse(s);let{uri:c,bin:n}=await s.json();return n||(n=c.split("/").pop()),{status:"ok",uri:c,bin:n}}catch(s){return console.error("createBin error:",s),{status:"error",statusText:s}}};updateBin=async(t,e)=>{try{let r=await fetch(`${this.url}/${e}`,{method:"PUT",headers:{"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t)});await this.validateResponse(r);let{data:s}=await r.json();return{status:"ok",data:s}}catch(r){return console.error("updateBin error:",r),{status:"error",statusText:r}}};patchBin=async(t,e)=>{try{let r=await fetch(`${this.url}/${e}`,{method:"PATCH",headers:{"Security-key":this.securityKey,"Content-Type":"application/merge-patch+json",Accept:"application/json"},body:JSON.stringify(t)});await this.validateResponse(r);let{data:s}=await r.json();return{status:"ok",data:s}}catch(r){return console.error("patchBin error:",r),{status:"error",statusText:r}}};deleteBin=async t=>{try{let e=await fetch(`${this.url}/${t}`,{method:"DELETE",headers:{"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"}});await this.validateResponse(e);let{status:r}=await e.json();if(r!==0)throw new Error(`Bin delete failed with error: ${r.message}`);return{status:"ok"}}catch(e){return console.error("deleteBin error:",e),{status:"error",statusText:e}}}};0&&(module.exports={ECJsonStorage});
1
+ "use strict";var o=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var y=(i,t)=>{for(var r in t)o(i,r,{get:t[r],enumerable:!0})},l=(i,t,r,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of u(t))!h.call(i,s)&&s!==r&&o(i,s,{get:()=>t[s],enumerable:!(e=p(t,s))||e.enumerable});return i};var d=i=>l(o({},"__esModule",{value:!0}),i);var g={};y(g,{ECJsonStorage:()=>a});module.exports=d(g);var a=class{url;apiKey;securityKey;monthlyLimit=1e4;constructor(t,r,e){if(this.url=e||"https://json.extendsclass.com/bin",this.apiKey=t||"",this.securityKey=r||"",!this.url||!this.apiKey)throw new Error("Invalid constructor params!");for(;this.url.endsWith("/");)this.url=this.url.slice(0,-1)}validateResponse=async t=>{if(!t.ok)throw new Error(`HTTP error! Status: ${t.status}`);if((t.headers.get("content-type")||"").startsWith("text/html"))throw new Error(`Expected JSON but server returned HTML: "${(await t.text()).slice(0,100)}..."`)};getBins=async()=>{try{let t=await fetch(`${this.url}s`,{method:"GET",headers:{"Api-key":this.apiKey,Accept:"application/json"}});await this.validateResponse(t);let r=Number(t.headers.get("x-counter")),e=await t.json();return{status:"ok",callsDone:r,callsRemaining:this.monthlyLimit-r,bins:e}}catch(t){return console.error("getBins error:",t),{status:"error",statusText:t}}};getStats=async()=>{try{let t=await this.getBins();if(t.status==="error")throw new Error(`HTTP error! Status: ${t.statusText}`);return delete t.bins,t}catch(t){return console.error("getStats error:",t),{status:"error",statusText:t}}};getBin=async t=>{try{if(!t)throw new Error("Bin ID missing!");let r=await fetch(`${this.url}/${t}`,{method:"GET",headers:{"Security-key":this.securityKey,Accept:"application/json"}});return await this.validateResponse(r),{status:"ok",data:await r.json()}}catch(r){return console.error("getBin error:",r),{status:"error",statusText:r}}};createBin=async(t,r)=>{let e=new Headers({"Api-key":this.apiKey,"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"});e.append("Private",r.toString());try{let s=await fetch(this.url,{method:"POST",headers:e,body:JSON.stringify(t)});await this.validateResponse(s);let{uri:c,bin:n}=await s.json();return n||(n=c.split("/").pop()),{status:"ok",uri:c,bin:n}}catch(s){return console.error("createBin error:",s),{status:"error",statusText:s}}};updateBin=async(t,r)=>{try{if(!r)throw new Error("Bin ID missing!");let e=await fetch(`${this.url}/${r}`,{method:"PUT",headers:{"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t)});await this.validateResponse(e);let{data:s}=await e.json();return{status:"ok",data:s}}catch(e){return console.error("updateBin error:",e),{status:"error",statusText:e}}};patchBin=async(t,r)=>{try{if(!r)throw new Error("Bin ID missing!");let e=await fetch(`${this.url}/${r}`,{method:"PATCH",headers:{"Security-key":this.securityKey,"Content-Type":"application/merge-patch+json",Accept:"application/json"},body:JSON.stringify(t)});await this.validateResponse(e);let{data:s}=await e.json();return{status:"ok",data:s}}catch(e){return console.error("patchBin error:",e),{status:"error",statusText:e}}};deleteBin=async t=>{try{if(!t)throw new Error("Bin ID missing!");let r=await fetch(`${this.url}/${t}`,{method:"DELETE",headers:{"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"}});await this.validateResponse(r);let{status:e}=await r.json();if(e!==0)throw new Error(`Bin delete failed with error: ${e.message}`);return{status:"ok"}}catch(r){return console.error("deleteBin error:",r),{status:"error",statusText:r}}}};0&&(module.exports={ECJsonStorage});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * ESJsonStorage class is a wrapper to the ExtendsClass JSON-Storage API\r\n */\r\nexport type resGetBins = {\r\n status: 'ok';\r\n callsDone: number;\r\n callsRemaining: number;\r\n bins?: string[];\r\n};\r\nexport type resGetStats = Omit<resGetBins, 'bins'>;\r\n\r\nexport type resGetBin = {\r\n status: 'ok';\r\n data: object;\r\n};\r\n\r\nexport type resUpdateBin = {\r\n status: 'ok';\r\n data: string;\r\n};\r\nexport type resPatchBin = resUpdateBin;\r\n\r\nexport type resCreateBin = {\r\n status: 'ok';\r\n uri: string;\r\n bin: string;\r\n};\r\n\r\nexport type resDeleteBin = Omit<resGetBin, 'data'>;\r\n\r\nexport type resError = {\r\n status: 'error';\r\n statusText: string;\r\n};\r\n\r\nexport class ECJsonStorage {\r\n url: string;\r\n apiKey: string;\r\n securityKey: string;\r\n monthlyLimit: number = 10000;\r\n\r\n constructor(apiKey: string, securityKey?: string, url?: string) {\r\n this.url = url || 'https://json.extendsclass.com/bin';\r\n this.apiKey = apiKey || '';\r\n this.securityKey = securityKey || '';\r\n\r\n if (!this.url || !this.apiKey) throw new Error('Invalid constructor params!');\r\n while (this.url.endsWith('/')) {\r\n this.url = this.url.slice(0, -1);\r\n }\r\n }\r\n\r\n /**\r\n * Utility function to validate the response after the class function call\r\n * @param response\r\n */\r\n validateResponse = async (response: Response) => {\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! Status: ${response.status}`);\r\n }\r\n\r\n const contentType = response.headers.get('content-type') || '';\r\n if (contentType.startsWith('text/html')) {\r\n throw new Error(`Expected JSON but server returned HTML: \"${(await response.text()).slice(0, 100)}...\"`);\r\n }\r\n };\r\n\r\n /**\r\n * Get all bin IDs for a certain Api-key\r\n * @returns {object} <resGetBins | resError>\r\n */\r\n getBins = async (): Promise<resGetBins | resError> => {\r\n try {\r\n const response = await fetch(`${this.url}s`, {\r\n method: 'GET',\r\n headers: {\r\n 'Api-key': this.apiKey,\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const counter = Number(response.headers.get('x-counter'));\r\n const data = await response.json();\r\n return {\r\n status: 'ok',\r\n callsDone: counter,\r\n callsRemaining: this.monthlyLimit - counter,\r\n bins: data\r\n };\r\n } catch (error) {\r\n console.error('getBins error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Syntactic sugar function for getBins to only return limit counter\r\n * @returns {object} <resGetStats | resError>\r\n */\r\n getStats = async (): Promise<resGetStats | resError> => {\r\n try {\r\n const res = await this.getBins();\r\n if (res.status === 'error') {\r\n throw new Error(`HTTP error! Status: ${(<resError>res).statusText}`);\r\n }\r\n\r\n delete (<resGetBins>res).bins;\r\n return <resGetStats>res;\r\n } catch (error) {\r\n console.error('getStats error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Reads the content of a certain bin ID\r\n * @param bin string Bin ID to read\r\n * @returns {object} <resGetBin | resError>\r\n */\r\n getBin = async (bin: string): Promise<resGetBin | resError> => {\r\n try {\r\n if (!bin) throw new Error('Bin ID missing!');\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'GET',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const data = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('getBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Creates a new bin and saves the given JSON payload to it\r\n * @param payload {object} JSON object to create the bin with\r\n * @param keepPrivate {boolean} TRUE=bin shall be kept private\r\n * @returns {object} <resCreateBin | resError>\r\n */\r\n createBin = async (payload: object, keepPrivate: boolean): Promise<resCreateBin | resError> => {\r\n const headers = new Headers({\r\n 'Api-key': this.apiKey,\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n });\r\n headers.append('Private', keepPrivate.toString());\r\n try {\r\n const response = await fetch(this.url, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n let { uri, bin } = await response.json();\r\n if (!bin) bin = uri.split('/').pop();\r\n\r\n return {\r\n status: 'ok',\r\n uri,\r\n bin\r\n };\r\n } catch (error) {\r\n console.error('createBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Updates a certain bin with the given JSON object\r\n * @param payload {object} JSON object to update the bin with\r\n * @param bin string Bin ID to be updated\r\n * @returns {object} <resUpdateBin | resError>\r\n */\r\n updateBin = async (payload: object, bin: string): Promise<resUpdateBin | resError> => {\r\n try {\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'PUT',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n },\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { data } = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('updateBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Patches/inserts/changes a certain bin with the given JSON payload\r\n * ref: \"Partially update JSON\" at https://extendsclass.com/json-storage.html#apiDocumentation\r\n * @param payload {object} JSON object to patch the bin with\r\n * @param bin string Bin ID to be patched\r\n * @returns {object} <resPatchBin | resError>\r\n */\r\n patchBin = async (payload: object, bin: string): Promise<resPatchBin | resError> => {\r\n try {\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'PATCH',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/merge-patch+json',\r\n Accept: 'application/json'\r\n },\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { data } = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('patchBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Deletes a certain bin\r\n * @param bin string Bin ID to be deleted\r\n * @returns {object} <resDeleteBin | resError>\r\n */\r\n deleteBin = async (bin: string): Promise<resDeleteBin | resError> => {\r\n try {\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'DELETE',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { status } = await response.json();\r\n if (status !== 0) throw new Error(`Bin delete failed with error: ${status.message}`);\r\n\r\n return {\r\n status: 'ok'\r\n };\r\n } catch (error) {\r\n console.error('deleteBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n}\r\n"],"mappings":"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","names":["index_exports","__export","ECJsonStorage","__toCommonJS","apiKey","securityKey","url","response","counter","data","error","res","bin","payload","keepPrivate","headers","uri","status"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * ESJsonStorage class is a wrapper to the ExtendsClass JSON-Storage API\r\n */\r\nexport type resGetBins = {\r\n status: 'ok';\r\n callsDone: number;\r\n callsRemaining: number;\r\n bins?: string[];\r\n};\r\nexport type resGetStats = Omit<resGetBins, 'bins'>;\r\n\r\nexport type resGetBin = {\r\n status: 'ok';\r\n data: object;\r\n};\r\n\r\nexport type resUpdateBin = {\r\n status: 'ok';\r\n data: string;\r\n};\r\nexport type resPatchBin = resUpdateBin;\r\n\r\nexport type resCreateBin = {\r\n status: 'ok';\r\n uri: string;\r\n bin: string;\r\n};\r\n\r\nexport type resDeleteBin = Omit<resGetBin, 'data'>;\r\n\r\nexport type resError = {\r\n status: 'error';\r\n statusText: string;\r\n};\r\n\r\nexport class ECJsonStorage {\r\n url: string;\r\n apiKey: string;\r\n securityKey: string;\r\n monthlyLimit: number = 10000;\r\n\r\n constructor(apiKey: string, securityKey?: string, url?: string) {\r\n this.url = url || 'https://json.extendsclass.com/bin';\r\n this.apiKey = apiKey || '';\r\n this.securityKey = securityKey || '';\r\n\r\n if (!this.url || !this.apiKey) throw new Error('Invalid constructor params!');\r\n while (this.url.endsWith('/')) {\r\n this.url = this.url.slice(0, -1);\r\n }\r\n }\r\n\r\n /**\r\n * Utility function to validate the response after the class function call\r\n * @param response\r\n */\r\n validateResponse = async (response: Response) => {\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! Status: ${response.status}`);\r\n }\r\n\r\n const contentType = response.headers.get('content-type') || '';\r\n if (contentType.startsWith('text/html')) {\r\n throw new Error(`Expected JSON but server returned HTML: \"${(await response.text()).slice(0, 100)}...\"`);\r\n }\r\n };\r\n\r\n /**\r\n * Get all bin IDs for a certain Api-key\r\n * @returns {object} <resGetBins | resError>\r\n */\r\n getBins = async (): Promise<resGetBins | resError> => {\r\n try {\r\n const response = await fetch(`${this.url}s`, {\r\n method: 'GET',\r\n headers: {\r\n 'Api-key': this.apiKey,\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const counter = Number(response.headers.get('x-counter'));\r\n const data = await response.json();\r\n return {\r\n status: 'ok',\r\n callsDone: counter,\r\n callsRemaining: this.monthlyLimit - counter,\r\n bins: data\r\n };\r\n } catch (error) {\r\n console.error('getBins error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Syntactic sugar function for getBins to only return limit counter\r\n * @returns {object} <resGetStats | resError>\r\n */\r\n getStats = async (): Promise<resGetStats | resError> => {\r\n try {\r\n const res = await this.getBins();\r\n if (res.status === 'error') {\r\n throw new Error(`HTTP error! Status: ${(<resError>res).statusText}`);\r\n }\r\n\r\n delete (<resGetBins>res).bins;\r\n return <resGetStats>res;\r\n } catch (error) {\r\n console.error('getStats error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Reads the content of a certain bin ID\r\n * @param bin string Bin ID to read\r\n * @returns {object} <resGetBin | resError>\r\n */\r\n getBin = async (bin: string): Promise<resGetBin | resError> => {\r\n try {\r\n if (!bin) throw new Error('Bin ID missing!');\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'GET',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const data = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('getBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Creates a new bin and saves the given JSON payload to it\r\n * @param payload {object} JSON object to create the bin with\r\n * @param keepPrivate {boolean} TRUE=bin shall be kept private\r\n * @returns {object} <resCreateBin | resError>\r\n */\r\n createBin = async (payload: object, keepPrivate: boolean): Promise<resCreateBin | resError> => {\r\n const headers = new Headers({\r\n 'Api-key': this.apiKey,\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n });\r\n headers.append('Private', keepPrivate.toString());\r\n try {\r\n const response = await fetch(this.url, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n let { uri, bin } = await response.json();\r\n if (!bin) bin = uri.split('/').pop();\r\n\r\n return {\r\n status: 'ok',\r\n uri,\r\n bin\r\n };\r\n } catch (error) {\r\n console.error('createBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Updates a certain bin with the given JSON object\r\n * @param payload {object} JSON object to update the bin with\r\n * @param bin string Bin ID to be updated\r\n * @returns {object} <resUpdateBin | resError>\r\n */\r\n updateBin = async (payload: object, bin: string): Promise<resUpdateBin | resError> => {\r\n try {\r\n if (!bin) throw new Error('Bin ID missing!');\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'PUT',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n },\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { data } = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('updateBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Patches/inserts/changes a certain bin with the given JSON payload\r\n * ref: \"Partially update JSON\" at https://extendsclass.com/json-storage.html#apiDocumentation\r\n * @param payload {object} JSON object to patch the bin with\r\n * @param bin string Bin ID to be patched\r\n * @returns {object} <resPatchBin | resError>\r\n */\r\n patchBin = async (payload: object, bin: string): Promise<resPatchBin | resError> => {\r\n try {\r\n if (!bin) throw new Error('Bin ID missing!');\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'PATCH',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/merge-patch+json',\r\n Accept: 'application/json'\r\n },\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { data } = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('patchBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Deletes a certain bin\r\n * @param bin string Bin ID to be deleted\r\n * @returns {object} <resDeleteBin | resError>\r\n */\r\n deleteBin = async (bin: string): Promise<resDeleteBin | resError> => {\r\n try {\r\n if (!bin) throw new Error('Bin ID missing!');\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'DELETE',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { status } = await response.json();\r\n if (status !== 0) throw new Error(`Bin delete failed with error: ${status.message}`);\r\n\r\n return {\r\n status: 'ok'\r\n };\r\n } catch (error) {\r\n console.error('deleteBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n}\r\n"],"mappings":"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","names":["index_exports","__export","ECJsonStorage","__toCommonJS","apiKey","securityKey","url","response","counter","data","error","res","bin","payload","keepPrivate","headers","uri","status"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var a=class{url;apiKey;securityKey;monthlyLimit=1e4;constructor(t,e,r){if(this.url=r||"https://json.extendsclass.com/bin",this.apiKey=t||"",this.securityKey=e||"",!this.url||!this.apiKey)throw new Error("Invalid constructor params!");for(;this.url.endsWith("/");)this.url=this.url.slice(0,-1)}validateResponse=async t=>{if(!t.ok)throw new Error(`HTTP error! Status: ${t.status}`);if((t.headers.get("content-type")||"").startsWith("text/html"))throw new Error(`Expected JSON but server returned HTML: "${(await t.text()).slice(0,100)}..."`)};getBins=async()=>{try{let t=await fetch(`${this.url}s`,{method:"GET",headers:{"Api-key":this.apiKey,Accept:"application/json"}});await this.validateResponse(t);let e=Number(t.headers.get("x-counter")),r=await t.json();return{status:"ok",callsDone:e,callsRemaining:this.monthlyLimit-e,bins:r}}catch(t){return console.error("getBins error:",t),{status:"error",statusText:t}}};getStats=async()=>{try{let t=await this.getBins();if(t.status==="error")throw new Error(`HTTP error! Status: ${t.statusText}`);return delete t.bins,t}catch(t){return console.error("getStats error:",t),{status:"error",statusText:t}}};getBin=async t=>{try{if(!t)throw new Error("Bin ID missing!");let e=await fetch(`${this.url}/${t}`,{method:"GET",headers:{"Security-key":this.securityKey,Accept:"application/json"}});return await this.validateResponse(e),{status:"ok",data:await e.json()}}catch(e){return console.error("getBin error:",e),{status:"error",statusText:e}}};createBin=async(t,e)=>{let r=new Headers({"Api-key":this.apiKey,"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"});r.append("Private",e.toString());try{let s=await fetch(this.url,{method:"POST",headers:r,body:JSON.stringify(t)});await this.validateResponse(s);let{uri:n,bin:i}=await s.json();return i||(i=n.split("/").pop()),{status:"ok",uri:n,bin:i}}catch(s){return console.error("createBin error:",s),{status:"error",statusText:s}}};updateBin=async(t,e)=>{try{let r=await fetch(`${this.url}/${e}`,{method:"PUT",headers:{"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t)});await this.validateResponse(r);let{data:s}=await r.json();return{status:"ok",data:s}}catch(r){return console.error("updateBin error:",r),{status:"error",statusText:r}}};patchBin=async(t,e)=>{try{let r=await fetch(`${this.url}/${e}`,{method:"PATCH",headers:{"Security-key":this.securityKey,"Content-Type":"application/merge-patch+json",Accept:"application/json"},body:JSON.stringify(t)});await this.validateResponse(r);let{data:s}=await r.json();return{status:"ok",data:s}}catch(r){return console.error("patchBin error:",r),{status:"error",statusText:r}}};deleteBin=async t=>{try{let e=await fetch(`${this.url}/${t}`,{method:"DELETE",headers:{"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"}});await this.validateResponse(e);let{status:r}=await e.json();if(r!==0)throw new Error(`Bin delete failed with error: ${r.message}`);return{status:"ok"}}catch(e){return console.error("deleteBin error:",e),{status:"error",statusText:e}}}};export{a as ECJsonStorage};
1
+ var o=class{url;apiKey;securityKey;monthlyLimit=1e4;constructor(t,r,e){if(this.url=e||"https://json.extendsclass.com/bin",this.apiKey=t||"",this.securityKey=r||"",!this.url||!this.apiKey)throw new Error("Invalid constructor params!");for(;this.url.endsWith("/");)this.url=this.url.slice(0,-1)}validateResponse=async t=>{if(!t.ok)throw new Error(`HTTP error! Status: ${t.status}`);if((t.headers.get("content-type")||"").startsWith("text/html"))throw new Error(`Expected JSON but server returned HTML: "${(await t.text()).slice(0,100)}..."`)};getBins=async()=>{try{let t=await fetch(`${this.url}s`,{method:"GET",headers:{"Api-key":this.apiKey,Accept:"application/json"}});await this.validateResponse(t);let r=Number(t.headers.get("x-counter")),e=await t.json();return{status:"ok",callsDone:r,callsRemaining:this.monthlyLimit-r,bins:e}}catch(t){return console.error("getBins error:",t),{status:"error",statusText:t}}};getStats=async()=>{try{let t=await this.getBins();if(t.status==="error")throw new Error(`HTTP error! Status: ${t.statusText}`);return delete t.bins,t}catch(t){return console.error("getStats error:",t),{status:"error",statusText:t}}};getBin=async t=>{try{if(!t)throw new Error("Bin ID missing!");let r=await fetch(`${this.url}/${t}`,{method:"GET",headers:{"Security-key":this.securityKey,Accept:"application/json"}});return await this.validateResponse(r),{status:"ok",data:await r.json()}}catch(r){return console.error("getBin error:",r),{status:"error",statusText:r}}};createBin=async(t,r)=>{let e=new Headers({"Api-key":this.apiKey,"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"});e.append("Private",r.toString());try{let s=await fetch(this.url,{method:"POST",headers:e,body:JSON.stringify(t)});await this.validateResponse(s);let{uri:n,bin:i}=await s.json();return i||(i=n.split("/").pop()),{status:"ok",uri:n,bin:i}}catch(s){return console.error("createBin error:",s),{status:"error",statusText:s}}};updateBin=async(t,r)=>{try{if(!r)throw new Error("Bin ID missing!");let e=await fetch(`${this.url}/${r}`,{method:"PUT",headers:{"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t)});await this.validateResponse(e);let{data:s}=await e.json();return{status:"ok",data:s}}catch(e){return console.error("updateBin error:",e),{status:"error",statusText:e}}};patchBin=async(t,r)=>{try{if(!r)throw new Error("Bin ID missing!");let e=await fetch(`${this.url}/${r}`,{method:"PATCH",headers:{"Security-key":this.securityKey,"Content-Type":"application/merge-patch+json",Accept:"application/json"},body:JSON.stringify(t)});await this.validateResponse(e);let{data:s}=await e.json();return{status:"ok",data:s}}catch(e){return console.error("patchBin error:",e),{status:"error",statusText:e}}};deleteBin=async t=>{try{if(!t)throw new Error("Bin ID missing!");let r=await fetch(`${this.url}/${t}`,{method:"DELETE",headers:{"Security-key":this.securityKey,"Content-Type":"application/json",Accept:"application/json"}});await this.validateResponse(r);let{status:e}=await r.json();if(e!==0)throw new Error(`Bin delete failed with error: ${e.message}`);return{status:"ok"}}catch(r){return console.error("deleteBin error:",r),{status:"error",statusText:r}}}};export{o as ECJsonStorage};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * ESJsonStorage class is a wrapper to the ExtendsClass JSON-Storage API\r\n */\r\nexport type resGetBins = {\r\n status: 'ok';\r\n callsDone: number;\r\n callsRemaining: number;\r\n bins?: string[];\r\n};\r\nexport type resGetStats = Omit<resGetBins, 'bins'>;\r\n\r\nexport type resGetBin = {\r\n status: 'ok';\r\n data: object;\r\n};\r\n\r\nexport type resUpdateBin = {\r\n status: 'ok';\r\n data: string;\r\n};\r\nexport type resPatchBin = resUpdateBin;\r\n\r\nexport type resCreateBin = {\r\n status: 'ok';\r\n uri: string;\r\n bin: string;\r\n};\r\n\r\nexport type resDeleteBin = Omit<resGetBin, 'data'>;\r\n\r\nexport type resError = {\r\n status: 'error';\r\n statusText: string;\r\n};\r\n\r\nexport class ECJsonStorage {\r\n url: string;\r\n apiKey: string;\r\n securityKey: string;\r\n monthlyLimit: number = 10000;\r\n\r\n constructor(apiKey: string, securityKey?: string, url?: string) {\r\n this.url = url || 'https://json.extendsclass.com/bin';\r\n this.apiKey = apiKey || '';\r\n this.securityKey = securityKey || '';\r\n\r\n if (!this.url || !this.apiKey) throw new Error('Invalid constructor params!');\r\n while (this.url.endsWith('/')) {\r\n this.url = this.url.slice(0, -1);\r\n }\r\n }\r\n\r\n /**\r\n * Utility function to validate the response after the class function call\r\n * @param response\r\n */\r\n validateResponse = async (response: Response) => {\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! Status: ${response.status}`);\r\n }\r\n\r\n const contentType = response.headers.get('content-type') || '';\r\n if (contentType.startsWith('text/html')) {\r\n throw new Error(`Expected JSON but server returned HTML: \"${(await response.text()).slice(0, 100)}...\"`);\r\n }\r\n };\r\n\r\n /**\r\n * Get all bin IDs for a certain Api-key\r\n * @returns {object} <resGetBins | resError>\r\n */\r\n getBins = async (): Promise<resGetBins | resError> => {\r\n try {\r\n const response = await fetch(`${this.url}s`, {\r\n method: 'GET',\r\n headers: {\r\n 'Api-key': this.apiKey,\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const counter = Number(response.headers.get('x-counter'));\r\n const data = await response.json();\r\n return {\r\n status: 'ok',\r\n callsDone: counter,\r\n callsRemaining: this.monthlyLimit - counter,\r\n bins: data\r\n };\r\n } catch (error) {\r\n console.error('getBins error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Syntactic sugar function for getBins to only return limit counter\r\n * @returns {object} <resGetStats | resError>\r\n */\r\n getStats = async (): Promise<resGetStats | resError> => {\r\n try {\r\n const res = await this.getBins();\r\n if (res.status === 'error') {\r\n throw new Error(`HTTP error! Status: ${(<resError>res).statusText}`);\r\n }\r\n\r\n delete (<resGetBins>res).bins;\r\n return <resGetStats>res;\r\n } catch (error) {\r\n console.error('getStats error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Reads the content of a certain bin ID\r\n * @param bin string Bin ID to read\r\n * @returns {object} <resGetBin | resError>\r\n */\r\n getBin = async (bin: string): Promise<resGetBin | resError> => {\r\n try {\r\n if (!bin) throw new Error('Bin ID missing!');\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'GET',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const data = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('getBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Creates a new bin and saves the given JSON payload to it\r\n * @param payload {object} JSON object to create the bin with\r\n * @param keepPrivate {boolean} TRUE=bin shall be kept private\r\n * @returns {object} <resCreateBin | resError>\r\n */\r\n createBin = async (payload: object, keepPrivate: boolean): Promise<resCreateBin | resError> => {\r\n const headers = new Headers({\r\n 'Api-key': this.apiKey,\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n });\r\n headers.append('Private', keepPrivate.toString());\r\n try {\r\n const response = await fetch(this.url, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n let { uri, bin } = await response.json();\r\n if (!bin) bin = uri.split('/').pop();\r\n\r\n return {\r\n status: 'ok',\r\n uri,\r\n bin\r\n };\r\n } catch (error) {\r\n console.error('createBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Updates a certain bin with the given JSON object\r\n * @param payload {object} JSON object to update the bin with\r\n * @param bin string Bin ID to be updated\r\n * @returns {object} <resUpdateBin | resError>\r\n */\r\n updateBin = async (payload: object, bin: string): Promise<resUpdateBin | resError> => {\r\n try {\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'PUT',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n },\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { data } = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('updateBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Patches/inserts/changes a certain bin with the given JSON payload\r\n * ref: \"Partially update JSON\" at https://extendsclass.com/json-storage.html#apiDocumentation\r\n * @param payload {object} JSON object to patch the bin with\r\n * @param bin string Bin ID to be patched\r\n * @returns {object} <resPatchBin | resError>\r\n */\r\n patchBin = async (payload: object, bin: string): Promise<resPatchBin | resError> => {\r\n try {\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'PATCH',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/merge-patch+json',\r\n Accept: 'application/json'\r\n },\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { data } = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('patchBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Deletes a certain bin\r\n * @param bin string Bin ID to be deleted\r\n * @returns {object} <resDeleteBin | resError>\r\n */\r\n deleteBin = async (bin: string): Promise<resDeleteBin | resError> => {\r\n try {\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'DELETE',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { status } = await response.json();\r\n if (status !== 0) throw new Error(`Bin delete failed with error: ${status.message}`);\r\n\r\n return {\r\n status: 'ok'\r\n };\r\n } catch (error) {\r\n console.error('deleteBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n}\r\n"],"mappings":"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","names":["ECJsonStorage","apiKey","securityKey","url","response","counter","data","error","res","bin","payload","keepPrivate","headers","uri","status"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * ESJsonStorage class is a wrapper to the ExtendsClass JSON-Storage API\r\n */\r\nexport type resGetBins = {\r\n status: 'ok';\r\n callsDone: number;\r\n callsRemaining: number;\r\n bins?: string[];\r\n};\r\nexport type resGetStats = Omit<resGetBins, 'bins'>;\r\n\r\nexport type resGetBin = {\r\n status: 'ok';\r\n data: object;\r\n};\r\n\r\nexport type resUpdateBin = {\r\n status: 'ok';\r\n data: string;\r\n};\r\nexport type resPatchBin = resUpdateBin;\r\n\r\nexport type resCreateBin = {\r\n status: 'ok';\r\n uri: string;\r\n bin: string;\r\n};\r\n\r\nexport type resDeleteBin = Omit<resGetBin, 'data'>;\r\n\r\nexport type resError = {\r\n status: 'error';\r\n statusText: string;\r\n};\r\n\r\nexport class ECJsonStorage {\r\n url: string;\r\n apiKey: string;\r\n securityKey: string;\r\n monthlyLimit: number = 10000;\r\n\r\n constructor(apiKey: string, securityKey?: string, url?: string) {\r\n this.url = url || 'https://json.extendsclass.com/bin';\r\n this.apiKey = apiKey || '';\r\n this.securityKey = securityKey || '';\r\n\r\n if (!this.url || !this.apiKey) throw new Error('Invalid constructor params!');\r\n while (this.url.endsWith('/')) {\r\n this.url = this.url.slice(0, -1);\r\n }\r\n }\r\n\r\n /**\r\n * Utility function to validate the response after the class function call\r\n * @param response\r\n */\r\n validateResponse = async (response: Response) => {\r\n if (!response.ok) {\r\n throw new Error(`HTTP error! Status: ${response.status}`);\r\n }\r\n\r\n const contentType = response.headers.get('content-type') || '';\r\n if (contentType.startsWith('text/html')) {\r\n throw new Error(`Expected JSON but server returned HTML: \"${(await response.text()).slice(0, 100)}...\"`);\r\n }\r\n };\r\n\r\n /**\r\n * Get all bin IDs for a certain Api-key\r\n * @returns {object} <resGetBins | resError>\r\n */\r\n getBins = async (): Promise<resGetBins | resError> => {\r\n try {\r\n const response = await fetch(`${this.url}s`, {\r\n method: 'GET',\r\n headers: {\r\n 'Api-key': this.apiKey,\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const counter = Number(response.headers.get('x-counter'));\r\n const data = await response.json();\r\n return {\r\n status: 'ok',\r\n callsDone: counter,\r\n callsRemaining: this.monthlyLimit - counter,\r\n bins: data\r\n };\r\n } catch (error) {\r\n console.error('getBins error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Syntactic sugar function for getBins to only return limit counter\r\n * @returns {object} <resGetStats | resError>\r\n */\r\n getStats = async (): Promise<resGetStats | resError> => {\r\n try {\r\n const res = await this.getBins();\r\n if (res.status === 'error') {\r\n throw new Error(`HTTP error! Status: ${(<resError>res).statusText}`);\r\n }\r\n\r\n delete (<resGetBins>res).bins;\r\n return <resGetStats>res;\r\n } catch (error) {\r\n console.error('getStats error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Reads the content of a certain bin ID\r\n * @param bin string Bin ID to read\r\n * @returns {object} <resGetBin | resError>\r\n */\r\n getBin = async (bin: string): Promise<resGetBin | resError> => {\r\n try {\r\n if (!bin) throw new Error('Bin ID missing!');\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'GET',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const data = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('getBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Creates a new bin and saves the given JSON payload to it\r\n * @param payload {object} JSON object to create the bin with\r\n * @param keepPrivate {boolean} TRUE=bin shall be kept private\r\n * @returns {object} <resCreateBin | resError>\r\n */\r\n createBin = async (payload: object, keepPrivate: boolean): Promise<resCreateBin | resError> => {\r\n const headers = new Headers({\r\n 'Api-key': this.apiKey,\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n });\r\n headers.append('Private', keepPrivate.toString());\r\n try {\r\n const response = await fetch(this.url, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n let { uri, bin } = await response.json();\r\n if (!bin) bin = uri.split('/').pop();\r\n\r\n return {\r\n status: 'ok',\r\n uri,\r\n bin\r\n };\r\n } catch (error) {\r\n console.error('createBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Updates a certain bin with the given JSON object\r\n * @param payload {object} JSON object to update the bin with\r\n * @param bin string Bin ID to be updated\r\n * @returns {object} <resUpdateBin | resError>\r\n */\r\n updateBin = async (payload: object, bin: string): Promise<resUpdateBin | resError> => {\r\n try {\r\n if (!bin) throw new Error('Bin ID missing!');\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'PUT',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n },\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { data } = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('updateBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Patches/inserts/changes a certain bin with the given JSON payload\r\n * ref: \"Partially update JSON\" at https://extendsclass.com/json-storage.html#apiDocumentation\r\n * @param payload {object} JSON object to patch the bin with\r\n * @param bin string Bin ID to be patched\r\n * @returns {object} <resPatchBin | resError>\r\n */\r\n patchBin = async (payload: object, bin: string): Promise<resPatchBin | resError> => {\r\n try {\r\n if (!bin) throw new Error('Bin ID missing!');\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'PATCH',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/merge-patch+json',\r\n Accept: 'application/json'\r\n },\r\n body: JSON.stringify(payload)\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { data } = await response.json();\r\n return {\r\n status: 'ok',\r\n data\r\n };\r\n } catch (error) {\r\n console.error('patchBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n\r\n /**\r\n * Deletes a certain bin\r\n * @param bin string Bin ID to be deleted\r\n * @returns {object} <resDeleteBin | resError>\r\n */\r\n deleteBin = async (bin: string): Promise<resDeleteBin | resError> => {\r\n try {\r\n if (!bin) throw new Error('Bin ID missing!');\r\n const response = await fetch(`${this.url}/${bin}`, {\r\n method: 'DELETE',\r\n headers: {\r\n 'Security-key': this.securityKey,\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json'\r\n }\r\n });\r\n\r\n await this.validateResponse(response);\r\n\r\n const { status } = await response.json();\r\n if (status !== 0) throw new Error(`Bin delete failed with error: ${status.message}`);\r\n\r\n return {\r\n status: 'ok'\r\n };\r\n } catch (error) {\r\n console.error('deleteBin error:', error);\r\n return {\r\n status: 'error',\r\n statusText: <string>error\r\n };\r\n }\r\n };\r\n}\r\n"],"mappings":"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","names":["ECJsonStorage","apiKey","securityKey","url","response","counter","data","error","res","bin","payload","keepPrivate","headers","uri","status"]}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@neonwilderness/ecjsonstorage",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.cts",
8
- "exports": {
8
+ "exports": {
9
9
  "import": {
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.js"
@@ -39,14 +39,15 @@
39
39
  "type": "module",
40
40
  "devDependencies": {
41
41
  "@types/dotenv-safe": "^9.1.0",
42
- "@types/node": "^26.6.3",
43
- "dotenv": "^18.0.4",
42
+ "@types/node": "^26.6.4",
43
+ "dotenv": "^18.0.5",
44
44
  "dotenv-safe": "^9.1.0",
45
45
  "tsup": "^8.5.1",
46
46
  "typescript": "^6.0.3",
47
47
  "vitest": "^5.0.3"
48
48
  },
49
49
  "allowScripts": {
50
- "esbuild@0.28.2": true
50
+ "esbuild@0.28.2": true,
51
+ "esbuild@0.27.2": true
51
52
  }
52
53
  }
package/src/index.ts CHANGED
@@ -200,6 +200,7 @@ export class ECJsonStorage {
200
200
  */
201
201
  updateBin = async (payload: object, bin: string): Promise<resUpdateBin | resError> => {
202
202
  try {
203
+ if (!bin) throw new Error('Bin ID missing!');
203
204
  const response = await fetch(`${this.url}/${bin}`, {
204
205
  method: 'PUT',
205
206
  headers: {
@@ -235,6 +236,7 @@ export class ECJsonStorage {
235
236
  */
236
237
  patchBin = async (payload: object, bin: string): Promise<resPatchBin | resError> => {
237
238
  try {
239
+ if (!bin) throw new Error('Bin ID missing!');
238
240
  const response = await fetch(`${this.url}/${bin}`, {
239
241
  method: 'PATCH',
240
242
  headers: {
@@ -268,6 +270,7 @@ export class ECJsonStorage {
268
270
  */
269
271
  deleteBin = async (bin: string): Promise<resDeleteBin | resError> => {
270
272
  try {
273
+ if (!bin) throw new Error('Bin ID missing!');
271
274
  const response = await fetch(`${this.url}/${bin}`, {
272
275
  method: 'DELETE',
273
276
  headers: {