@qikdev/sdk 0.1.214 → 0.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qikdev/sdk",
3
- "version": "0.1.214",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "description": "Promise based Javascript SDK",
6
6
  "main": "./dist/main.js",
@@ -64,167 +64,30 @@ export default function (qik) {
64
64
  ///////////////////////////////////////////////////
65
65
 
66
66
  const glossaryCache = qik.cache.get("user:glossary");
67
- const glossaryIndexCache = qik.cache.get("user:glossary:index");
68
- const definitionCache = qik.cache.get("user:glossary:definitions");
69
67
 
70
68
  let inflightGlossaryRequest;
71
- let inflightGlossaryIndexRequest;
72
- let inflightDefinitionRequests = {};
73
69
 
74
70
  /**
75
- * Load the lightweight glossary index.
76
- * Returns cached version unless reload is specified.
77
- * @alias content.loadGlossaryIndex
78
- * @param {Object} options Additional options
79
- * @param {Boolean} options.hash Return as object keyed by type key
80
- * @param {Boolean} options.hex Return as object keyed by hex
81
- * @param {Boolean} options.reload Force reload from server
82
- * @returns {Promise<Array|Object>} The glossary index
83
- * @example
84
- * const index = await sdk.content.loadGlossaryIndex();
85
- * const indexHash = await sdk.content.loadGlossaryIndex({ hash: true });
86
- */
87
- service.loadGlossaryIndex = async function (options) {
88
- options = options || {};
89
-
90
- let cached = glossaryIndexCache.get("index");
91
- const reload = options.reload || options.refresh || !cached;
92
-
93
- if (reload) {
94
- if (!inflightGlossaryIndexRequest) {
95
- inflightGlossaryIndexRequest = qik.api.get("/glossary/index");
96
- inflightGlossaryIndexRequest.then(
97
- () => {
98
- inflightGlossaryIndexRequest = null;
99
- },
100
- () => {
101
- inflightGlossaryIndexRequest = null;
102
- },
103
- );
104
- }
105
-
106
- const { data } = await inflightGlossaryIndexRequest;
107
- glossaryIndexCache.set("index", data);
108
- cached = data;
109
- qik.dispatch("glossary:index", data);
110
- }
111
-
112
- if (options.hash) {
113
- return qik.utils.hash(cached, "key");
114
- }
115
-
116
- if (options.hex) {
117
- return qik.utils.hash(cached, "hex");
118
- }
119
-
120
- return cached;
121
- };
122
-
123
- /**
124
- * Get a full definition for a specific type.
125
- * Returns cached if available, otherwise fetches from server.
126
- * Multiple simultaneous calls for the same key share one request.
127
- * @alias content.getDefinition
128
- * @param {String} key The type key (e.g., 'article', 'profile')
129
- * @param {Object} options Additional options
130
- * @param {Boolean} options.reload Force reload from server
131
- * @returns {Promise<Object>} The full type definition
132
- * @example
133
- * const article = await sdk.content.getDefinition('article');
134
- * console.log(article.fields);
135
- */
136
- service.getDefinition = async function (key, options) {
137
- options = options || {};
138
-
139
- // Return cached if available and not forcing reload
140
- let cached = definitionCache.get(key);
141
- if (cached && !options.reload && !options.refresh) {
142
- return cached;
143
- }
144
-
145
- // If already loading, wait for it (request deduplication)
146
- if (inflightDefinitionRequests[key]) {
147
- await inflightDefinitionRequests[key];
148
- return definitionCache.get(key);
149
- }
150
-
151
- // Make the request
152
- inflightDefinitionRequests[key] = qik.api.get(`/glossary/index/${key}`);
153
-
154
- try {
155
- const { data } = await inflightDefinitionRequests[key];
156
- definitionCache.set(key, data);
157
- qik.dispatch("glossary:definition", { key, data });
158
- return data;
159
- } finally {
160
- inflightDefinitionRequests[key] = null;
161
- }
162
- };
163
-
164
- let inflightTypeRequests = {};
165
- let typeResultsCache = {};
166
-
167
- /**
168
- * Load all definitions that match or extend a given type.
169
- * For example, loadDefinitionsForType('submission') returns all form definitions.
170
- * Results are cached individually - subsequent getDefinition() calls return from cache.
171
- * @alias content.loadDefinitionsForType
172
- * @param {String} type The base type key (e.g., 'submission', 'workflowcard', 'article')
173
- * @param {Object} options Additional options
174
- * @param {Boolean} options.hash Return as object keyed by definition key
175
- * @param {Boolean} options.reload Force reload from server
176
- * @returns {Promise<Array|Object>} Array of definitions, or hash if options.hash
177
- * @example
178
- * const submissions = await sdk.content.loadDefinitionsForType('submission');
179
- * const workflowCards = await sdk.content.loadDefinitionsForType('workflowcard', { hash: true });
71
+ * Yield to the event loop to keep the UI responsive
72
+ * @private
180
73
  */
181
- service.loadDefinitionsForType = async function (type, options) {
182
- options = options || {};
183
-
184
- // Return cached if available and not forcing reload
185
- if (typeResultsCache[type] && !options.reload && !options.refresh) {
186
- const data = typeResultsCache[type];
187
- return options.hash ? qik.utils.hash(data, "key") : data;
188
- }
189
-
190
- // If already loading this type, wait for it
191
- if (inflightTypeRequests[type]) {
192
- await inflightTypeRequests[type];
193
- const data = typeResultsCache[type];
194
- return options.hash ? qik.utils.hash(data, "key") : data;
195
- }
196
-
197
- // Make the request
198
- inflightTypeRequests[type] = qik.api.get(`/glossary/index/${type}/all`);
199
-
200
- try {
201
- const { data } = await inflightTypeRequests[type];
202
-
203
- // Cache the type results for subsequent calls
204
- typeResultsCache[type] = data;
205
-
206
- // Cache each definition individually in the unified cache
207
- data.forEach((definition) => {
208
- definitionCache.set(definition.key, definition);
209
- });
210
-
211
- qik.dispatch("glossary:type", { type, definitions: data });
212
-
213
- if (options.hash) {
214
- return qik.utils.hash(data, "key");
74
+ function yieldToMain() {
75
+ return new Promise((resolve) => {
76
+ if (typeof requestIdleCallback === "function") {
77
+ requestIdleCallback(resolve, { timeout: 50 });
78
+ } else {
79
+ setTimeout(resolve, 0);
215
80
  }
216
- return data;
217
- } finally {
218
- inflightTypeRequests[type] = null;
219
- }
220
- };
81
+ });
82
+ }
221
83
 
222
84
  /**
223
- * Inflate a single value from compressed format
85
+ * Inflate compressed glossary data from the /glossary/compressed endpoint
86
+ * Processes in chunks to avoid blocking the main thread
224
87
  * @private
225
88
  */
226
- function createInflator(strings, keyMap) {
227
- return function inflate(val) {
89
+ async function inflateGlossary({ _s: strings, _k: keyMap, types }) {
90
+ function inflate(val) {
228
91
  if (typeof val === "string" && val[0] === "~") {
229
92
  return strings[parseInt(val.slice(1))];
230
93
  }
@@ -237,111 +100,22 @@ export default function (qik) {
237
100
  return result;
238
101
  }
239
102
  return val;
240
- };
241
- }
103
+ }
242
104
 
243
- /**
244
- * Create a lazy-inflating array that only inflates items when accessed
245
- * This avoids the upfront cost of inflating the entire glossary
246
- * @private
247
- */
248
- function createLazyGlossary({ _s: strings, _k: keyMap, types }) {
249
- const inflate = createInflator(strings, keyMap);
250
- const cache = new Array(types.length);
251
- const inflated = new Array(types.length).fill(false);
252
-
253
- return new Proxy(types, {
254
- get(target, prop) {
255
- // Handle array methods and properties
256
- if (prop === "length") return target.length;
257
- if (prop === Symbol.iterator) {
258
- return function* () {
259
- for (let i = 0; i < target.length; i++) {
260
- if (!inflated[i]) {
261
- cache[i] = inflate(target[i]);
262
- inflated[i] = true;
263
- }
264
- yield cache[i];
265
- }
266
- };
267
- }
268
- if (prop === "map") {
269
- return function (fn) {
270
- const result = [];
271
- for (let i = 0; i < target.length; i++) {
272
- if (!inflated[i]) {
273
- cache[i] = inflate(target[i]);
274
- inflated[i] = true;
275
- }
276
- result.push(fn(cache[i], i, this));
277
- }
278
- return result;
279
- };
280
- }
281
- if (prop === "filter") {
282
- return function (fn) {
283
- const result = [];
284
- for (let i = 0; i < target.length; i++) {
285
- if (!inflated[i]) {
286
- cache[i] = inflate(target[i]);
287
- inflated[i] = true;
288
- }
289
- if (fn(cache[i], i, this)) {
290
- result.push(cache[i]);
291
- }
292
- }
293
- return result;
294
- };
295
- }
296
- if (prop === "find") {
297
- return function (fn) {
298
- for (let i = 0; i < target.length; i++) {
299
- if (!inflated[i]) {
300
- cache[i] = inflate(target[i]);
301
- inflated[i] = true;
302
- }
303
- if (fn(cache[i], i, this)) {
304
- return cache[i];
305
- }
306
- }
307
- return undefined;
308
- };
309
- }
310
- if (prop === "forEach") {
311
- return function (fn) {
312
- for (let i = 0; i < target.length; i++) {
313
- if (!inflated[i]) {
314
- cache[i] = inflate(target[i]);
315
- inflated[i] = true;
316
- }
317
- fn(cache[i], i, this);
318
- }
319
- };
320
- }
105
+ const CHUNK_SIZE = 50;
106
+ const results = [];
321
107
 
322
- // Handle numeric indices
323
- const index = typeof prop === "string" ? parseInt(prop, 10) : prop;
324
- if (Number.isInteger(index) && index >= 0 && index < target.length) {
325
- if (!inflated[index]) {
326
- cache[index] = inflate(target[index]);
327
- inflated[index] = true;
328
- }
329
- return cache[index];
330
- }
108
+ for (let i = 0; i < types.length; i += CHUNK_SIZE) {
109
+ const chunk = types.slice(i, i + CHUNK_SIZE);
110
+ results.push(...chunk.map(inflate));
331
111
 
332
- // Pass through other properties
333
- return Reflect.get(target, prop);
334
- },
335
- });
336
- }
112
+ // Yield to main thread between chunks
113
+ if (i + CHUNK_SIZE < types.length) {
114
+ await yieldToMain();
115
+ }
116
+ }
337
117
 
338
- /**
339
- * Process compressed glossary data
340
- * Uses lazy inflation to avoid blocking the main thread
341
- * @private
342
- */
343
- function inflateGlossary(data) {
344
- return createLazyGlossary(data);
118
+ return results;
345
119
  }
346
120
 
347
121
  /**
@@ -388,9 +162,9 @@ export default function (qik) {
388
162
  // Now we have the glossary
389
163
  const { data } = await inflightGlossaryRequest;
390
164
 
391
- // Inflate if compressed format (lazy - inflates on access)
165
+ // Inflate if compressed format (async to avoid blocking UI)
392
166
  const glossaryData =
393
- data._s && data._k && data.types ? inflateGlossary(data) : data;
167
+ data._s && data._k && data.types ? await inflateGlossary(data) : data;
394
168
 
395
169
  // Cache it for later
396
170
  glossaryCache.set("glossary", glossaryData);
@@ -797,8 +797,12 @@ service.mapFields = function (fields, options) {
797
797
  mapped.trail.push(fieldKey);
798
798
 
799
799
  mapped.path = mapped.trail.join(".");
800
- mapped.titles = titles.slice();
801
- mapped.titles.push(field.filterTitle || field.title || "");
800
+ if (field.titles && field.titles.length) {
801
+ mapped.titles = field.titles.slice();
802
+ } else {
803
+ mapped.titles = titles.slice();
804
+ mapped.titles.push(field.filterTitle || field.title || "");
805
+ }
802
806
 
803
807
  const isNotLayoutOrIsAllowed = !isLayout || options.includeLayout;
804
808
 
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export const version = "0.1.214";
1
+ export const version = "0.2.2";