@qikdev/sdk 0.1.211 → 0.1.213
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/dist/main.js +1843 -1775
- package/package.json +1 -1
- package/src/api/qik.content.js +180 -0
- package/src/version.js +1 -1
package/package.json
CHANGED
package/src/api/qik.content.js
CHANGED
|
@@ -64,8 +64,141 @@ 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");
|
|
67
69
|
|
|
68
70
|
let inflightGlossaryRequest;
|
|
71
|
+
let inflightGlossaryIndexRequest;
|
|
72
|
+
let inflightDefinitionRequests = {};
|
|
73
|
+
let indexItemsByKey = {};
|
|
74
|
+
let hydrationQueue = [];
|
|
75
|
+
let isHydrating = false;
|
|
76
|
+
|
|
77
|
+
const CONCURRENT_HYDRATION_REQUESTS = 3;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Start background hydration of all definitions
|
|
81
|
+
* Uses concurrent workers for faster loading
|
|
82
|
+
* @private
|
|
83
|
+
*/
|
|
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);
|
|
112
|
+
|
|
113
|
+
isHydrating = false;
|
|
114
|
+
}
|
|
115
|
+
|
|
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}`);
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const { data } = await inflightDefinitionRequests[key];
|
|
125
|
+
|
|
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
|
+
}
|
|
131
|
+
|
|
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;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get a full definition for a specific type.
|
|
144
|
+
* Returns cached if available, otherwise fetches from server.
|
|
145
|
+
* If background hydration is in progress, prioritizes this key.
|
|
146
|
+
* @alias content.getDefinition
|
|
147
|
+
* @param {String} key The type key (e.g., 'article', 'profile')
|
|
148
|
+
* @param {Object} options Additional options
|
|
149
|
+
* @param {Boolean} options.reload Force reload from server
|
|
150
|
+
* @returns {Promise<Object>} The full type definition
|
|
151
|
+
* @example
|
|
152
|
+
* const article = await sdk.content.getDefinition('article');
|
|
153
|
+
* console.log(article.fields);
|
|
154
|
+
*/
|
|
155
|
+
service.getDefinition = async function (key, options) {
|
|
156
|
+
options = options || {};
|
|
157
|
+
|
|
158
|
+
// Return cached if available and not forcing reload
|
|
159
|
+
let cached = definitionCache.get(key);
|
|
160
|
+
if (cached && !options.reload && !options.refresh) {
|
|
161
|
+
return cached;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// If already loading, wait for it
|
|
165
|
+
if (inflightDefinitionRequests[key]) {
|
|
166
|
+
await inflightDefinitionRequests[key];
|
|
167
|
+
return definitionCache.get(key);
|
|
168
|
+
}
|
|
169
|
+
|
|
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
|
+
}
|
|
176
|
+
|
|
177
|
+
// Load it now
|
|
178
|
+
return loadDefinition(key);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
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
|
|
186
|
+
* @example
|
|
187
|
+
* await sdk.content.glossary({ index: true });
|
|
188
|
+
* sdk.content.hydrateInBackground();
|
|
189
|
+
*/
|
|
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;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const keys = cached.map((item) => item.key);
|
|
200
|
+
startBackgroundHydration(keys);
|
|
201
|
+
};
|
|
69
202
|
|
|
70
203
|
/**
|
|
71
204
|
* Inflate a single value from compressed format
|
|
@@ -203,15 +336,62 @@ export default function (qik) {
|
|
|
203
336
|
* @param {Boolean} options.reload Force glossary to reload and not be cached.
|
|
204
337
|
If false will retrieve content type data from the in memory cache
|
|
205
338
|
* @param {Boolean} options.uncompressed Use the uncompressed endpoint
|
|
339
|
+
* @param {Boolean} options.index Use lightweight index mode with background hydration
|
|
206
340
|
* @example
|
|
207
341
|
*
|
|
208
342
|
* const { article, profile } = await sdk.content.glossary({hash:true});
|
|
209
343
|
* // Use compressed endpoint for faster loading
|
|
210
344
|
* 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});
|
|
211
347
|
*/
|
|
212
348
|
service.glossary = async function (options) {
|
|
213
349
|
options = options || {};
|
|
214
350
|
|
|
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)
|
|
215
395
|
// Check if we already have the glossary cached
|
|
216
396
|
let cached = glossaryCache.get("glossary");
|
|
217
397
|
const uncompressed = !!options.uncompressed;
|
package/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "0.1.
|
|
1
|
+
export const version = "0.1.213";
|