@qikdev/sdk 0.1.213 → 0.1.214

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.213",
3
+ "version": "0.1.214",
4
4
  "type": "module",
5
5
  "description": "Promise based Javascript SDK",
6
6
  "main": "./dist/main.js",
@@ -70,79 +70,60 @@ export default function (qik) {
70
70
  let inflightGlossaryRequest;
71
71
  let inflightGlossaryIndexRequest;
72
72
  let inflightDefinitionRequests = {};
73
- let indexItemsByKey = {};
74
- let hydrationQueue = [];
75
- let isHydrating = false;
76
-
77
- const CONCURRENT_HYDRATION_REQUESTS = 3;
78
73
 
79
74
  /**
80
- * Start background hydration of all definitions
81
- * Uses concurrent workers for faster loading
82
- * @private
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 });
83
86
  */
84
- async function startBackgroundHydration(keys) {
85
- hydrationQueue = [...keys];
86
- if (isHydrating) return;
87
- isHydrating = true;
88
-
89
- // Worker function that pulls from the shared queue
90
- async function worker() {
91
- while (hydrationQueue.length > 0) {
92
- const key = hydrationQueue.shift();
93
-
94
- // Skip if already populated or loading
95
- if (indexItemsByKey[key]?.populated) continue;
96
- if (inflightDefinitionRequests[key]) continue;
97
-
98
- try {
99
- await loadDefinition(key);
100
- } catch (e) {
101
- console.warn(`Failed to hydrate ${key}:`, e);
102
- }
103
- }
104
- }
105
-
106
- // Start concurrent workers
107
- const workers = [];
108
- for (let i = 0; i < CONCURRENT_HYDRATION_REQUESTS; i++) {
109
- workers.push(worker());
110
- }
111
- await Promise.all(workers);
87
+ service.loadGlossaryIndex = async function (options) {
88
+ options = options || {};
112
89
 
113
- isHydrating = false;
114
- }
90
+ let cached = glossaryIndexCache.get("index");
91
+ const reload = options.reload || options.refresh || !cached;
115
92
 
116
- /**
117
- * Load a single definition from the server
118
- * @private
119
- */
120
- async function loadDefinition(key) {
121
- inflightDefinitionRequests[key] = qik.api.get(`/glossary/${key}`);
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
+ }
122
105
 
123
- try {
124
- const { data } = await inflightDefinitionRequests[key];
106
+ const { data } = await inflightGlossaryIndexRequest;
107
+ glossaryIndexCache.set("index", data);
108
+ cached = data;
109
+ qik.dispatch("glossary:index", data);
110
+ }
125
111
 
126
- // Merge full data into existing index item (mutate in place)
127
- const indexItem = indexItemsByKey[key];
128
- if (indexItem) {
129
- Object.assign(indexItem, data, { populated: true });
130
- }
112
+ if (options.hash) {
113
+ return qik.utils.hash(cached, "key");
114
+ }
131
115
 
132
- // Also cache separately for getDefinition()
133
- const cached = indexItem || { ...data, populated: true };
134
- definitionCache.set(key, cached);
135
- qik.dispatch("glossary:definition", { key, data: cached });
136
- return cached;
137
- } finally {
138
- inflightDefinitionRequests[key] = null;
116
+ if (options.hex) {
117
+ return qik.utils.hash(cached, "hex");
139
118
  }
140
- }
119
+
120
+ return cached;
121
+ };
141
122
 
142
123
  /**
143
124
  * Get a full definition for a specific type.
144
125
  * Returns cached if available, otherwise fetches from server.
145
- * If background hydration is in progress, prioritizes this key.
126
+ * Multiple simultaneous calls for the same key share one request.
146
127
  * @alias content.getDefinition
147
128
  * @param {String} key The type key (e.g., 'article', 'profile')
148
129
  * @param {Object} options Additional options
@@ -161,43 +142,81 @@ export default function (qik) {
161
142
  return cached;
162
143
  }
163
144
 
164
- // If already loading, wait for it
145
+ // If already loading, wait for it (request deduplication)
165
146
  if (inflightDefinitionRequests[key]) {
166
147
  await inflightDefinitionRequests[key];
167
148
  return definitionCache.get(key);
168
149
  }
169
150
 
170
- // Prioritize: move to front of queue
171
- const queueIndex = hydrationQueue.indexOf(key);
172
- if (queueIndex > 0) {
173
- hydrationQueue.splice(queueIndex, 1);
174
- hydrationQueue.unshift(key);
175
- }
151
+ // Make the request
152
+ inflightDefinitionRequests[key] = qik.api.get(`/glossary/index/${key}`);
176
153
 
177
- // Load it now
178
- return loadDefinition(key);
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
+ }
179
162
  };
180
163
 
164
+ let inflightTypeRequests = {};
165
+ let typeResultsCache = {};
166
+
181
167
  /**
182
- * Start loading all remaining definitions in the background.
183
- * Requires glossary({ index: true }) to be called first.
184
- * Uses concurrent requests for faster loading.
185
- * @alias content.hydrateInBackground
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
186
177
  * @example
187
- * await sdk.content.glossary({ index: true });
188
- * sdk.content.hydrateInBackground();
178
+ * const submissions = await sdk.content.loadDefinitionsForType('submission');
179
+ * const workflowCards = await sdk.content.loadDefinitionsForType('workflowcard', { hash: true });
189
180
  */
190
- service.hydrateInBackground = function () {
191
- const cached = glossaryIndexCache.get("index");
192
- if (!cached) {
193
- console.warn(
194
- "Call glossary({ index: true }) before hydrateInBackground()",
195
- );
196
- return;
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;
197
195
  }
198
196
 
199
- const keys = cached.map((item) => item.key);
200
- startBackgroundHydration(keys);
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");
215
+ }
216
+ return data;
217
+ } finally {
218
+ inflightTypeRequests[type] = null;
219
+ }
201
220
  };
202
221
 
203
222
  /**
@@ -336,62 +355,15 @@ export default function (qik) {
336
355
  * @param {Boolean} options.reload Force glossary to reload and not be cached.
337
356
  If false will retrieve content type data from the in memory cache
338
357
  * @param {Boolean} options.uncompressed Use the uncompressed endpoint
339
- * @param {Boolean} options.index Use lightweight index mode with background hydration
340
358
  * @example
341
359
  *
342
360
  * const { article, profile } = await sdk.content.glossary({hash:true});
343
361
  * // Use compressed endpoint for faster loading
344
362
  * const glossary = await sdk.content.glossary({compressed:true});
345
- * // Use lightweight index with background hydration
346
- * const glossary = await sdk.content.glossary({index:true, hash:true});
347
363
  */
348
364
  service.glossary = async function (options) {
349
365
  options = options || {};
350
366
 
351
- // Index mode: lightweight load with background hydration
352
- if (options.index) {
353
- let cached = glossaryIndexCache.get("index");
354
- const reload = options.reload || options.refresh || !cached;
355
-
356
- if (reload) {
357
- if (!inflightGlossaryIndexRequest) {
358
- inflightGlossaryIndexRequest = qik.api.get("/glossary/index");
359
- inflightGlossaryIndexRequest.then(
360
- () => {
361
- inflightGlossaryIndexRequest = null;
362
- },
363
- () => {
364
- inflightGlossaryIndexRequest = null;
365
- },
366
- );
367
- }
368
-
369
- const { data } = await inflightGlossaryIndexRequest;
370
-
371
- // Add populated:false to each item and build lookup map
372
- data.forEach((item) => {
373
- item.populated = false;
374
- indexItemsByKey[item.key] = item;
375
- });
376
-
377
- glossaryIndexCache.set("index", data);
378
- cached = data;
379
- qik.dispatch("glossary:index", data);
380
- // No auto-hydration - call hydrateInBackground() explicitly if needed
381
- }
382
-
383
- if (options.hash) {
384
- return qik.utils.hash(cached, "key");
385
- }
386
-
387
- if (options.hex) {
388
- return qik.utils.hash(cached, "hex");
389
- }
390
-
391
- return cached;
392
- }
393
-
394
- // Full glossary mode (existing behavior)
395
367
  // Check if we already have the glossary cached
396
368
  let cached = glossaryCache.get("glossary");
397
369
  const uncompressed = !!options.uncompressed;
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export const version = "0.1.213";
1
+ export const version = "0.1.214";