@karpeleslab/klbfw 0.2.10 → 0.2.12

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/fw-wrapper.js CHANGED
@@ -111,6 +111,24 @@ const setContext = (key, value) => {
111
111
  */
112
112
  const getToken = () => getFWProperty('token', undefined);
113
113
 
114
+ /**
115
+ * Gets the current token expiration time
116
+ * @returns {number|undefined} Token expiration time in milliseconds
117
+ */
118
+ const getTokenExp = () => getFWProperty('token_exp', undefined);
119
+
120
+ /**
121
+ * Sets the authentication token and its expiration time
122
+ * @param {string} token - New token value
123
+ * @param {number|undefined} tokenExp - Token expiration time in milliseconds
124
+ */
125
+ const setToken = (token, tokenExp) => {
126
+ if (typeof FW !== 'undefined') {
127
+ FW.token = token;
128
+ FW.token_exp = tokenExp;
129
+ }
130
+ };
131
+
114
132
  /**
115
133
  * Gets the registry
116
134
  * @returns {Object|undefined} Registry object
@@ -251,6 +269,8 @@ module.exports.getCurrency = getCurrency;
251
269
  module.exports.getContext = getContext;
252
270
  module.exports.setContext = setContext;
253
271
  module.exports.getToken = getToken;
272
+ module.exports.getTokenExp = getTokenExp;
273
+ module.exports.setToken = setToken;
254
274
  module.exports.getRegistry = getRegistry;
255
275
  module.exports.getUrl = getUrl;
256
276
  module.exports.getSiteStatic = getSiteStatic;
package/internal.js CHANGED
@@ -104,7 +104,7 @@ const buildRestUrl = (path, withToken, context) => {
104
104
  */
105
105
  const checkSupport = () => {
106
106
  const missingFeatures = [];
107
-
107
+
108
108
  if (typeof fetch === "undefined") {
109
109
  missingFeatures.push("fetch API");
110
110
  }
@@ -112,15 +112,79 @@ const checkSupport = () => {
112
112
  if (!fwWrapper.supported()) {
113
113
  missingFeatures.push("Framework wrapper");
114
114
  }
115
-
115
+
116
116
  if (missingFeatures.length > 0) {
117
117
  console.error("Missing required features: " + missingFeatures.join(", "));
118
118
  return false;
119
119
  }
120
-
120
+
121
121
  return true;
122
122
  };
123
123
 
124
+ /**
125
+ * Checks if token needs refresh and refreshes if necessary
126
+ * @returns {Promise<void>} Resolves when check/refresh is complete
127
+ */
128
+ const checkAndRefreshToken = () => {
129
+ const tokenExp = fwWrapper.getTokenExp();
130
+
131
+ // If token_exp is not defined, no refresh needed
132
+ if (tokenExp === undefined) {
133
+ return Promise.resolve();
134
+ }
135
+
136
+ const now = Date.now();
137
+ const fiveMinutes = 5 * 60 * 1000; // 5 minutes in milliseconds
138
+
139
+ // Check if token expires within 5 minutes
140
+ if (tokenExp - now <= fiveMinutes) {
141
+ // Need to refresh token
142
+ const callUrl = buildRestUrl('_special/token.json', true);
143
+ const headers = {};
144
+
145
+ if (fwWrapper.getToken() !== '') {
146
+ headers['Authorization'] = 'Session ' + fwWrapper.getToken();
147
+ }
148
+
149
+ return fetch(callUrl, {
150
+ method: 'GET',
151
+ credentials: 'include',
152
+ headers: headers
153
+ })
154
+ .then(response => {
155
+ if (!response.ok) {
156
+ // API returned an error, give up by setting token_exp to undefined
157
+ fwWrapper.setToken(fwWrapper.getToken(), undefined);
158
+ return;
159
+ }
160
+
161
+ const contentType = response.headers.get('content-type');
162
+ if (!contentType || contentType.indexOf('application/json') === -1) {
163
+ // Not JSON response, give up
164
+ fwWrapper.setToken(fwWrapper.getToken(), undefined);
165
+ return;
166
+ }
167
+
168
+ return response.json();
169
+ })
170
+ .then(json => {
171
+ if (json && json.token && json.token_exp) {
172
+ // Update token and token_exp
173
+ fwWrapper.setToken(json.token, json.token_exp);
174
+ } else {
175
+ // Invalid response, give up
176
+ fwWrapper.setToken(fwWrapper.getToken(), undefined);
177
+ }
178
+ })
179
+ .catch(() => {
180
+ // Error occurred, give up by setting token_exp to undefined
181
+ fwWrapper.setToken(fwWrapper.getToken(), undefined);
182
+ });
183
+ }
184
+
185
+ return Promise.resolve();
186
+ };
187
+
124
188
  /**
125
189
  * Makes an internal REST API call
126
190
  * @param {string} name - API endpoint name
@@ -137,58 +201,61 @@ const internalRest = (name, verb, params, context) => {
137
201
  if (typeof window !== "undefined") {
138
202
  context['t'] = getTimezoneData();
139
203
  }
140
-
141
- const callUrl = buildRestUrl(name, true, context);
142
- const headers = {};
143
-
144
- if (fwWrapper.getToken() !== '') {
145
- headers['Authorization'] = 'Session ' + fwWrapper.getToken();
146
- }
147
204
 
148
- // Handle GET requests
149
- if (verb === "GET") {
150
- if (params) {
151
- // Check if params is a JSON string, or if it needs encoding
152
- if (typeof params === "string") {
153
- return fetch(callUrl + "&_=" + encodeURIComponent(params), {
154
- method: verb,
155
- credentials: 'include',
156
- headers: headers
157
- });
158
- } else {
159
- return fetch(callUrl + "&_=" + encodeURIComponent(JSON.stringify(params)), {
160
- method: verb,
161
- credentials: 'include',
162
- headers: headers
163
- });
205
+ // Check and refresh token if needed before making the request
206
+ return checkAndRefreshToken().then(() => {
207
+ const callUrl = buildRestUrl(name, true, context);
208
+ const headers = {};
209
+
210
+ if (fwWrapper.getToken() !== '') {
211
+ headers['Authorization'] = 'Session ' + fwWrapper.getToken();
212
+ }
213
+
214
+ // Handle GET requests
215
+ if (verb === "GET") {
216
+ if (params) {
217
+ // Check if params is a JSON string, or if it needs encoding
218
+ if (typeof params === "string") {
219
+ return fetch(callUrl + "&_=" + encodeURIComponent(params), {
220
+ method: verb,
221
+ credentials: 'include',
222
+ headers: headers
223
+ });
224
+ } else {
225
+ return fetch(callUrl + "&_=" + encodeURIComponent(JSON.stringify(params)), {
226
+ method: verb,
227
+ credentials: 'include',
228
+ headers: headers
229
+ });
230
+ }
164
231
  }
232
+
233
+ return fetch(callUrl, {
234
+ method: verb,
235
+ credentials: 'include',
236
+ headers: headers
237
+ });
165
238
  }
166
-
167
- return fetch(callUrl, {
168
- method: verb,
169
- credentials: 'include',
170
- headers: headers
171
- });
172
- }
173
239
 
174
- // Handle FormData
175
- if (typeof FormData !== "undefined" && (params instanceof FormData)) {
240
+ // Handle FormData
241
+ if (typeof FormData !== "undefined" && (params instanceof FormData)) {
242
+ return fetch(callUrl, {
243
+ method: verb,
244
+ credentials: 'include',
245
+ body: params,
246
+ headers: headers
247
+ });
248
+ }
249
+
250
+ // Handle JSON requests
251
+ headers['Content-Type'] = 'application/json; charset=utf-8';
252
+
176
253
  return fetch(callUrl, {
177
254
  method: verb,
178
255
  credentials: 'include',
179
- body: params,
256
+ body: JSON.stringify(params),
180
257
  headers: headers
181
258
  });
182
- }
183
-
184
- // Handle JSON requests
185
- headers['Content-Type'] = 'application/json; charset=utf-8';
186
-
187
- return fetch(callUrl, {
188
- method: verb,
189
- credentials: 'include',
190
- body: JSON.stringify(params),
191
- headers: headers
192
259
  });
193
260
  };
194
261
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karpeleslab/klbfw",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "description": "Frontend Framework",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
package/upload.js CHANGED
@@ -459,7 +459,7 @@ module.exports.upload = (function () {
459
459
  params.filename = up.file.name;
460
460
  params.size = up.file.size;
461
461
  params.lastModified = up.file.lastModified / 1000;
462
- params.type = up.file.type;
462
+ params.type = up.file.type || "application/octet-stream";
463
463
 
464
464
  // Initialize upload with the server
465
465
  rest.rest(up.path, "POST", params, up.context)
@@ -497,7 +497,7 @@ module.exports.upload = (function () {
497
497
  "POST",
498
498
  "uploads=",
499
499
  "",
500
- {"Content-Type": up.file.type, "X-Amz-Acl": "private"},
500
+ {"Content-Type": up.file.type || "application/octet-stream", "X-Amz-Acl": "private"},
501
501
  up.context
502
502
  )
503
503
  .then(response => response.text())
@@ -609,9 +609,18 @@ module.exports.upload = (function () {
609
609
  up.context
610
610
  )
611
611
  .then(response => {
612
+ // Verify the response is successful
613
+ if (!response.ok) {
614
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
615
+ }
612
616
  // Store ETag for this part (needed for completion)
613
- up.b[partNumber] = response.headers.get("ETag");
614
-
617
+ const etag = response.headers.get("ETag");
618
+ // Read response body to ensure request completed
619
+ return response.text().then(() => etag);
620
+ })
621
+ .then(etag => {
622
+ up.b[partNumber] = etag;
623
+
615
624
  // Update progress and continue processing
616
625
  sendProgress();
617
626
  upload.run();
@@ -629,7 +638,7 @@ module.exports.upload = (function () {
629
638
  function uploadPutPart(up, partNumber, startByte, data) {
630
639
  // Set up headers
631
640
  const headers = {
632
- "Content-Type": up.file.type
641
+ "Content-Type": up.file.type || "application/octet-stream"
633
642
  };
634
643
 
635
644
  // Add Content-Range header for multipart PUT
@@ -645,9 +654,17 @@ module.exports.upload = (function () {
645
654
  headers: headers,
646
655
  })
647
656
  .then(response => {
657
+ // Verify the response is successful
658
+ if (!response.ok) {
659
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
660
+ }
661
+ // Read response body to ensure request completed
662
+ return response.text();
663
+ })
664
+ .then(() => {
648
665
  // Mark part as done
649
666
  up.b[partNumber] = "done";
650
-
667
+
651
668
  // Update progress and continue processing
652
669
  sendProgress();
653
670
  upload.run();