@karpeleslab/klbfw 0.1.12 → 0.2.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.
Files changed (46) hide show
  1. package/CLAUDE.md +50 -0
  2. package/README.md +199 -35
  3. package/cookies.js +107 -41
  4. package/coverage/clover.xml +835 -0
  5. package/coverage/coverage-final.json +9 -0
  6. package/coverage/lcov-report/base.css +224 -0
  7. package/coverage/lcov-report/block-navigation.js +87 -0
  8. package/coverage/lcov-report/cookies.js.html +334 -0
  9. package/coverage/lcov-report/favicon.png +0 -0
  10. package/coverage/lcov-report/fw-wrapper.js.html +163 -0
  11. package/coverage/lcov-report/index.html +131 -0
  12. package/coverage/lcov-report/index.js.html +196 -0
  13. package/coverage/lcov-report/internal.js.html +604 -0
  14. package/coverage/lcov-report/klbfw/cookies.js.html +490 -0
  15. package/coverage/lcov-report/klbfw/fw-wrapper.js.html +745 -0
  16. package/coverage/lcov-report/klbfw/index.html +206 -0
  17. package/coverage/lcov-report/klbfw/index.js.html +235 -0
  18. package/coverage/lcov-report/klbfw/internal.js.html +811 -0
  19. package/coverage/lcov-report/klbfw/rest.js.html +565 -0
  20. package/coverage/lcov-report/klbfw/test/index.html +116 -0
  21. package/coverage/lcov-report/klbfw/test/setup.js.html +1105 -0
  22. package/coverage/lcov-report/klbfw/upload.js.html +3487 -0
  23. package/coverage/lcov-report/klbfw/util.js.html +388 -0
  24. package/coverage/lcov-report/prettify.css +1 -0
  25. package/coverage/lcov-report/prettify.js +2 -0
  26. package/coverage/lcov-report/rest.js.html +472 -0
  27. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  28. package/coverage/lcov-report/sorter.js +196 -0
  29. package/coverage/lcov-report/upload.js.html +1789 -0
  30. package/coverage/lcov-report/util.js.html +313 -0
  31. package/coverage/lcov.info +1617 -0
  32. package/fw-wrapper.js +221 -26
  33. package/index.js +16 -2
  34. package/internal.js +186 -102
  35. package/package.json +21 -3
  36. package/rest.js +129 -81
  37. package/test/README.md +62 -0
  38. package/test/api.test.js +102 -0
  39. package/test/cookies.test.js +65 -0
  40. package/test/integration.test.js +481 -0
  41. package/test/rest.test.js +93 -0
  42. package/test/setup.js +341 -0
  43. package/test/upload.test.js +689 -0
  44. package/test/util.test.js +46 -0
  45. package/upload.js +1012 -442
  46. package/util.js +59 -21
package/CLAUDE.md ADDED
@@ -0,0 +1,50 @@
1
+ # KarpelesLab Frontend Framework (klbfw) Guidelines
2
+
3
+ ## Commands
4
+ ```
5
+ # Install dependencies
6
+ npm install
7
+
8
+ # Run tests
9
+ npm test
10
+
11
+ # Run tests in watch mode
12
+ npm run test:watch
13
+ ```
14
+
15
+ ## Code Style Guidelines
16
+
17
+ ### Formatting
18
+ - Use 'use strict' directive at top of files
19
+ - 4-space indentation (configured in vim: et:ts=4:sw=4)
20
+ - Use semicolons consistently
21
+ - Use single quotes for strings
22
+
23
+ ### Imports/Exports
24
+ - Use CommonJS module system (require/module.exports)
25
+ - Export using module.exports.<func> = <func>
26
+
27
+ ### Variables & Functions
28
+ - Use camelCase for variables and functions
29
+ - Use snake_case for some function names (rest_get, get_timezone_data)
30
+ - Function declarations: mix of standard functions and arrow functions
31
+
32
+ ### Error Handling
33
+ - Use Promise-based error handling with reject/resolve pattern
34
+ - Include descriptive error objects with properties (message, body, headers)
35
+ - Check input parameters and provide defaults (params = params || {})
36
+
37
+ ### Browser Compatibility
38
+ - Check for feature availability before using (typeof window, Intl.DateTimeFormat)
39
+ - Handle both browser and non-browser environments
40
+
41
+ ### Documentation
42
+ - Include comments for complex functions
43
+ - Add function descriptions where appropriate
44
+
45
+ ### Testing
46
+ - Tests are written using Jest
47
+ - Test modules are in the test/ directory
48
+ - Each module has a separate test file
49
+ - Tests should cover both SSR and client modes
50
+ - Use setup.js for test utilities and mocks
package/README.md CHANGED
@@ -1,95 +1,259 @@
1
1
  # klbfw
2
2
 
3
- Karpeles Lab framework lib
3
+ Karpeles Lab Frontend Framework - A JavaScript library for communicating with KLB API.
4
4
 
5
- This lib is used on frontend sites to communicate through the KLB API.
5
+ This library provides a unified interface for interacting with KLB API services from both browser and Node.js environments.
6
+
7
+ ## Features
8
+
9
+ - **Cross-environment compatibility**: Works in both browser and Node.js environments
10
+ - **REST API client**: Simple and consistent interface for API requests
11
+ - **File upload**: Supports file uploads in any environment with both direct PUT and AWS S3 multipart protocols
12
+ - **Context handling**: Manages authentication, locale, and other contextual information
13
+ - **Cookie management**: Cross-platform cookie handling that works in SSR mode
14
+ - **Internationalization**: Easy access to i18n data
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @karpeleslab/klbfw
20
+ ```
21
+
22
+ For Node.js environments with file upload support, install optional dependencies:
23
+
24
+ ```bash
25
+ npm install @karpeleslab/klbfw node-fetch xmldom
26
+ ```
27
+
28
+ ## Development
29
+
30
+ ```bash
31
+ # Install dependencies
32
+ npm install
33
+
34
+ # Run tests
35
+ npm test
36
+
37
+ # Run tests with coverage
38
+ npm run test:coverage
39
+
40
+ # Run integration tests (requires KLB API server)
41
+ npm run test:integration
42
+ ```
43
+
44
+ ## Version 0.2.0 Changes
45
+
46
+ - **Modern JavaScript**: Refactored to use ES6+ features (arrow functions, const/let, template literals)
47
+ - **Improved Documentation**: Added comprehensive JSDoc comments for all modules and functions
48
+ - **Better Code Organization**: Restructured code for improved readability and maintainability
49
+ - **Cross-Platform Support**: Enhanced environment detection and compatibility
50
+ - **Standardized Naming**: Consistent use of camelCase with backward compatibility for legacy APIs
51
+ - **Enhanced Error Handling**: More robust error handling and reporting
6
52
 
7
53
  # API
8
54
 
9
- ## rest(api, method, params, context)
55
+ ## REST API Methods
56
+
57
+ ### rest(api, method, params, context)
58
+
59
+ Performs a REST query and returns a promise to the response.
60
+
61
+ ### rest_get(name, params) / restGet(name, params)
62
+
63
+ Simplified version of rest() that uses HTTP GET. Takes a REST API endpoint name and optional parameters, returning a Promise with the response.
64
+
65
+ Note: Starting from version 0.2.0, camelCase method names are also available (e.g., `restGet` instead of `rest_get`).
66
+
67
+ ### upload
68
+
69
+ The upload module provides cross-platform file upload capabilities, supporting both browser and Node.js environments.
70
+
71
+ #### Browser Usage
72
+
73
+ ```javascript
74
+ // Open file picker and upload selected files
75
+ upload.upload.init('Misc/Debug:testUpload')()
76
+ .then(result => console.log('Upload complete', result));
77
+
78
+ // Upload a specific File object
79
+ upload.upload.append('Misc/Debug:testUpload', fileObject)
80
+ .then(result => console.log('Upload complete', result));
81
+
82
+ // Track progress
83
+ upload.upload.onprogress = (status) => {
84
+ console.log('Progress:', status.running.map(i => i.status));
85
+ };
86
+
87
+ // Cancel an upload
88
+ upload.upload.cancelItem(uploadId);
89
+ ```
90
+
91
+ #### Node.js Usage
92
+
93
+ ```javascript
94
+ // For Node.js environments, first install dependencies:
95
+ // npm install node-fetch xmldom
96
+
97
+ // Initialize upload with specific file paths
98
+ upload.upload.init('Misc/Debug:testUpload')(['./file1.txt', './file2.jpg'])
99
+ .then(result => console.log('Upload complete', result));
100
+
101
+ // Or create a custom file object with path
102
+ const file = {
103
+ name: 'test.txt',
104
+ size: 1024,
105
+ type: 'text/plain',
106
+ path: '/path/to/file.txt'
107
+ };
108
+ upload.upload.append('Misc/Debug:testUpload', file)
109
+ .then(result => console.log('Upload complete', result));
110
+ ```
111
+
112
+ #### Upload Management
113
+
114
+ The upload module provides methods to manage active uploads:
115
+
116
+ - `upload.getStatus()`: Get current upload status (queue, running, failed)
117
+ - `upload.cancelItem(uploadId)`: Cancel an upload
118
+ - `upload.pauseItem(uploadId)`: Pause an active upload
119
+ - `upload.resumeItem(uploadId)`: Resume a paused upload
120
+ - `upload.retryItem(uploadId)`: Retry a failed upload
121
+ - `upload.deleteItem(uploadId)`: Remove an upload from the queue or failed list
122
+
123
+ ## Query Parameter Methods
124
+
125
+ ### GET
10
126
 
11
- Performs a rest query and returns a promise to the response.
127
+ Object containing all URL query parameters parsed from the request.
12
128
 
13
- ## upload.init(api, params, context)
129
+ ### Get(key)
14
130
 
15
- Perform an upload. This API will show a file selector and allow the user to select one or more files.
131
+ Retrieves a specific query parameter value by key. If no key is provided, returns the entire GET object.
16
132
 
17
- ## getPrefix()
133
+ ### flushGet()
134
+
135
+ Clears the GET parameters by resetting the internal GET object to an empty object.
136
+
137
+ ## URL and Path Methods
138
+
139
+ ### getPrefix()
18
140
 
19
141
  Returns the language/etc prefix part of the URL, for example `/l/en-US`. The prefix should be inserted before the path in the URL.
20
142
 
21
- ## getSettings()
143
+ ### getUrl()
144
+
145
+ Returns the active URL.
146
+
147
+ ### getPath()
148
+
149
+ Returns the non-prefixed request path.
150
+
151
+ ### trimPrefix(url)
152
+
153
+ Processes a URL to separate the prefix parts from the main path. Returns an array with two elements: an object containing the identified prefixes and the remaining path.
154
+
155
+ ## Context and State Methods
156
+
157
+ ### getSettings()
22
158
 
23
159
  Returns active settings if any.
24
160
 
25
- ## getRealm()
161
+ ### getRealm()
26
162
 
27
163
  Returns realm information.
28
164
 
29
- ## getContext()
165
+ ### getContext()
30
166
 
31
167
  Returns current context.
32
168
 
33
- ## setContext(ctx)
169
+ ### setContext(ctx)
34
170
 
35
171
  Modifies the current context.
36
172
 
37
- ## getMode()
173
+ ### getInitialState()
174
+
175
+ Returns the initial state passed from SSR execution (or null if no SSR was performed).
176
+
177
+ ### getMode()
38
178
 
39
- Returns the current rending mode `ssr`, `js` etc.
179
+ Returns the current rendering mode `ssr`, `js` etc.
40
180
 
41
- ## getHostname()
181
+ ### getHostname()
42
182
 
43
183
  Returns the hostname part of the current URL.
44
184
 
45
- ## getRegistry()
185
+ ### getRegistry()
46
186
 
47
187
  Returns data from the registry.
48
188
 
49
- ## getLocale()
189
+ ### getLocale()
50
190
 
51
191
  Returns the currently active locale, for example `en-US`.
52
192
 
53
- ## getUserGroup()
193
+ ### getUserGroup()
54
194
 
55
195
  Returns `g` from context, which is the current active user group.
56
196
 
57
- ## getCurrency()
197
+ ### getCurrency()
58
198
 
59
199
  Returns the currently selected currency, such as `USD`.
60
200
 
61
- ## getToken()
201
+ ### getToken()
62
202
 
63
203
  Returns the CSRF token.
64
204
 
65
- ## getUrl()
66
-
67
- Returns the active URL.
68
-
69
- ## getPath()
70
-
71
- Returns the non-prefixed request path.
72
-
73
- ## getUuid()
205
+ ### getUuid()
74
206
 
75
207
  Returns the UUID of the request.
76
208
 
77
- ## getInitialState()
209
+ ### getI18N(language)
78
210
 
79
- Returns the initial state passed from SSR execution (or null if no SSR was performed).
211
+ Retrieves internationalization (i18n) data for a specified language. If no language is provided, uses the current locale.
80
212
 
81
- # Cookie functions
213
+ ## Cookie Methods
82
214
 
83
- Those methods are a requirement as using things like `document.cookie` will not work in SSR mode. The methods described here will work when SSR is enabled, and will cause cookies to be added to the HTTP response.
215
+ These methods are required as using things like `document.cookie` will not work in SSR mode. The methods described here will work when SSR is enabled, and will cause cookies to be added to the HTTP response.
84
216
 
85
- ## getCookie(cookie)
217
+ ### getCookie(cookie)
86
218
 
87
219
  Get the value of a specific cookie.
88
220
 
89
- ## setCookie(cookie, value)
221
+ ### setCookie(cookie, value)
90
222
 
91
223
  Sets value for a cookie.
92
224
 
93
- ## hasCookie(cookie)
225
+ ### hasCookie(cookie)
94
226
 
95
227
  Checks for presence of a given cookie.
228
+
229
+ ## Cross-Platform Support
230
+
231
+ As of version 0.2.0, klbfw includes improved environment detection and cross-platform utilities to support both browser and Node.js environments.
232
+
233
+ ### Environment Detection
234
+
235
+ The library automatically detects the current environment:
236
+
237
+ ```javascript
238
+ const env = {
239
+ isBrowser: typeof window !== 'undefined' && typeof document !== 'undefined',
240
+ isNode: typeof process !== 'undefined' && process.versions && process.versions.node
241
+ };
242
+ ```
243
+
244
+ ### Cross-Platform Utilities
245
+
246
+ Several utilities have been designed to work across environments:
247
+
248
+ - **Fetch**: Uses the browser's native `fetch` or `node-fetch` in Node.js
249
+ - **XML Parsing**: Uses the browser's `DOMParser` or `xmldom` in Node.js
250
+ - **File Reading**: Uses `FileReader` in the browser or `fs` in Node.js
251
+ - **Event Dispatching**: Uses `CustomEvent` in the browser or `EventEmitter` in Node.js
252
+
253
+ ### Node.js Requirements
254
+
255
+ To use klbfw with full functionality in Node.js, install the optional dependencies:
256
+
257
+ ```bash
258
+ npm install node-fetch xmldom
259
+ ```
package/cookies.js CHANGED
@@ -1,70 +1,136 @@
1
- 'use strict'
2
- // vim: et:ts=4:sw=4
1
+ 'use strict';
2
+ /**
3
+ * @fileoverview Cookie handling utilities for KLB Frontend Framework
4
+ *
5
+ * This module provides functions for getting, setting, and checking cookies
6
+ * in both browser and server-side rendering environments.
7
+ */
3
8
 
4
- module.exports.getCookie = function(cname) {
9
+ /**
10
+ * Parses cookies from document.cookie
11
+ * @private
12
+ * @returns {Object} Parsed cookies as key-value pairs
13
+ */
14
+ const parseCookies = () => {
15
+ if (typeof document === "undefined") {
16
+ return {};
17
+ }
18
+
19
+ const cookies = {};
20
+ const decodedCookie = decodeURIComponent(document.cookie);
21
+ const cookieParts = decodedCookie.split(';');
22
+
23
+ for (const part of cookieParts) {
24
+ let cookiePart = part.trim();
25
+ const equalsIndex = cookiePart.indexOf('=');
26
+
27
+ if (equalsIndex > 0) {
28
+ const name = cookiePart.substring(0, equalsIndex);
29
+ const value = cookiePart.substring(equalsIndex + 1);
30
+ cookies[name] = value;
31
+ }
32
+ }
33
+
34
+ return cookies;
35
+ };
36
+
37
+ /**
38
+ * Gets a cookie value by name
39
+ * @param {string} name - Cookie name
40
+ * @returns {string|undefined} Cookie value or undefined if not found
41
+ */
42
+ const getCookie = (name) => {
43
+ // Check for framework cookie handling
5
44
  if (typeof FW !== "undefined") {
6
- return FW.cookies[cname];
45
+ return FW.cookies[name];
46
+ }
47
+
48
+ // Server-side rendering without framework
49
+ if (typeof document === "undefined") {
50
+ return undefined;
7
51
  }
8
52
 
9
- var name = cname + "=";
10
- var decodedCookie = decodeURIComponent(document.cookie);
11
- var ca = decodedCookie.split(';');
12
- for(var i = 0; i <ca.length; i++) {
13
- var c = ca[i];
14
- while (c.charAt(0) == ' ') {
15
- c = c.substring(1);
16
- }
17
- if (c.indexOf(name) == 0) {
18
- return c.substring(name.length, c.length);
53
+ // Browser environment without framework
54
+ const cookieName = name + "=";
55
+ const decodedCookie = decodeURIComponent(document.cookie);
56
+ const cookieParts = decodedCookie.split(';');
57
+
58
+ for (const part of cookieParts) {
59
+ let c = part.trim();
60
+ if (c.indexOf(cookieName) === 0) {
61
+ return c.substring(cookieName.length);
19
62
  }
20
63
  }
64
+
21
65
  return undefined;
22
66
  };
23
67
 
24
- module.exports.hasCookie = function(cname) {
68
+ /**
69
+ * Checks if a cookie exists
70
+ * @param {string} name - Cookie name
71
+ * @returns {boolean} Whether the cookie exists
72
+ */
73
+ const hasCookie = (name) => {
74
+ // Check for framework cookie handling
25
75
  if (typeof FW !== "undefined") {
26
- return ((FW.cookies.hasOwnProperty(cname)) && (FW.cookies[cname]));
76
+ return (FW.cookies.hasOwnProperty(name) && FW.cookies[name] !== undefined);
27
77
  }
28
-
29
- var name = cname + "=";
30
- var decodedCookie = decodeURIComponent(document.cookie);
31
- var ca = decodedCookie.split(';');
32
- for(var i = 0; i <ca.length; i++) {
33
- var c = ca[i];
34
- while (c.charAt(0) == ' ') {
35
- c = c.substring(1);
36
- }
37
- if (c.indexOf(name) == 0) {
38
- return true;
39
- }
78
+
79
+ // Server-side rendering without framework
80
+ if (typeof document === "undefined") {
81
+ return false;
40
82
  }
41
- return false;
83
+
84
+ // Browser environment without framework
85
+ return getCookie(name) !== undefined;
42
86
  };
43
87
 
44
- module.exports.setCookie = function(cname, value, exdays) {
88
+ /**
89
+ * Sets a cookie
90
+ * @param {string} name - Cookie name
91
+ * @param {string} value - Cookie value
92
+ * @param {number} exdays - Expiration days (0 or negative for session cookie)
93
+ */
94
+ const setCookie = (name, value, exdays) => {
95
+ // Check for framework cookie handling
45
96
  if (typeof FW !== "undefined") {
46
- // always override value
47
- FW.cookies[cname] = value;
97
+ // Always override value
98
+ FW.cookies[name] = value;
48
99
  }
49
100
 
50
- var d = undefined;
101
+ // Calculate expiration if needed
102
+ let d;
51
103
  if (exdays > 0) {
52
104
  d = new Date();
53
- d.setTime(d.getTime() + (exdays*24*60*60*1000));
105
+ d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
54
106
  }
107
+
108
+ // Server-side rendering
55
109
  if (typeof __platformSetCookie !== "undefined") {
56
- // ssr mode
57
- return __platformSetCookie(cname, value, d);
110
+ return __platformSetCookie(name, value, d);
58
111
  }
112
+
113
+ // Server-side without cookie handling
114
+ if (typeof document === "undefined") {
115
+ return;
116
+ }
117
+
118
+ // Handle cookie deletion
59
119
  if (typeof value === "undefined") {
60
- // remove cookie
61
- document.cookie = cname+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
120
+ document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
62
121
  return;
63
122
  }
64
123
 
65
- var expires;
124
+ // Set cookie in browser
125
+ let expires = "";
66
126
  if (d) {
67
- expires = "expires="+ d.toUTCString();
127
+ expires = "expires=" + d.toUTCString();
68
128
  }
69
- document.cookie = cname + "=" + value + ";" + expires + ";path=/;secure;samesite=none";
129
+
130
+ document.cookie = name + "=" + value + ";" + expires + ";path=/;secure;samesite=none";
70
131
  };
132
+
133
+ // Export functions
134
+ module.exports.getCookie = getCookie;
135
+ module.exports.hasCookie = hasCookie;
136
+ module.exports.setCookie = setCookie;