@sola-air-ui/core 1.0.1 → 1.0.3
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/sola-core.iife.js +503 -0
- package/dist/sola-core.iife.min.js +3 -0
- package/package.json +15 -3
- package/src/index.js +540 -493
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
/* @sola-air-ui/core — IIFE build for ServiceNow and no-bundler environments */
|
|
2
|
+
var SolaCore = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.js
|
|
22
|
+
var src_exports = {};
|
|
23
|
+
__export(src_exports, {
|
|
24
|
+
SolaSentinel: () => SolaSentinel,
|
|
25
|
+
__flush_destroys: () => __flush_destroys,
|
|
26
|
+
__flush_mounts: () => __flush_mounts,
|
|
27
|
+
configureData: () => configureData,
|
|
28
|
+
configureIntent: () => configureIntent,
|
|
29
|
+
createData: () => createData,
|
|
30
|
+
createDerived: () => createDerived,
|
|
31
|
+
createEffect: () => createEffect,
|
|
32
|
+
createIntent: () => createIntent,
|
|
33
|
+
createSentinel: () => createSentinel,
|
|
34
|
+
createSignal: () => createSignal,
|
|
35
|
+
createTopicSignal: () => createTopicSignal,
|
|
36
|
+
flushSync: () => flushSync,
|
|
37
|
+
onDestroy: () => onDestroy,
|
|
38
|
+
onMount: () => onMount,
|
|
39
|
+
popContext: () => popContext,
|
|
40
|
+
pushContext: () => pushContext,
|
|
41
|
+
signalMesh: () => signalMesh
|
|
42
|
+
});
|
|
43
|
+
var effectStack = [];
|
|
44
|
+
var pendingEffects = /* @__PURE__ */ new Set();
|
|
45
|
+
var isFlushing = false;
|
|
46
|
+
function flushSync() {
|
|
47
|
+
while (pendingEffects.size > 0) {
|
|
48
|
+
const effects = [...pendingEffects];
|
|
49
|
+
pendingEffects.clear();
|
|
50
|
+
for (const effect of effects) {
|
|
51
|
+
effect.execute();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
isFlushing = false;
|
|
55
|
+
}
|
|
56
|
+
function scheduleFlush() {
|
|
57
|
+
if (!isFlushing) {
|
|
58
|
+
isFlushing = true;
|
|
59
|
+
queueMicrotask(flushSync);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function createSignal(initialValue) {
|
|
63
|
+
let value = initialValue;
|
|
64
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
65
|
+
const read = () => {
|
|
66
|
+
const currentEffect = effectStack[effectStack.length - 1];
|
|
67
|
+
if (currentEffect) {
|
|
68
|
+
subscribers.add(currentEffect);
|
|
69
|
+
currentEffect.dependencies.add(subscribers);
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
};
|
|
73
|
+
const write = (newValue) => {
|
|
74
|
+
if (value !== newValue) {
|
|
75
|
+
value = newValue;
|
|
76
|
+
for (const sub of [...subscribers]) {
|
|
77
|
+
pendingEffects.add(sub);
|
|
78
|
+
}
|
|
79
|
+
scheduleFlush();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return [read, write];
|
|
83
|
+
}
|
|
84
|
+
function createEffect(fn) {
|
|
85
|
+
const effect = {
|
|
86
|
+
execute() {
|
|
87
|
+
cleanup();
|
|
88
|
+
effectStack.push(effect);
|
|
89
|
+
try {
|
|
90
|
+
fn();
|
|
91
|
+
} finally {
|
|
92
|
+
effectStack.pop();
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
dependencies: /* @__PURE__ */ new Set(),
|
|
96
|
+
cleanup
|
|
97
|
+
};
|
|
98
|
+
function cleanup() {
|
|
99
|
+
for (const dep of effect.dependencies) {
|
|
100
|
+
dep.delete(effect);
|
|
101
|
+
}
|
|
102
|
+
effect.dependencies.clear();
|
|
103
|
+
}
|
|
104
|
+
effectStack.push(effect);
|
|
105
|
+
try {
|
|
106
|
+
fn();
|
|
107
|
+
} finally {
|
|
108
|
+
effectStack.pop();
|
|
109
|
+
}
|
|
110
|
+
return cleanup;
|
|
111
|
+
}
|
|
112
|
+
function createDerived(fn) {
|
|
113
|
+
let cachedValue;
|
|
114
|
+
let dirty = true;
|
|
115
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
116
|
+
let innerDependencies = /* @__PURE__ */ new Set();
|
|
117
|
+
const markDirty = {
|
|
118
|
+
execute() {
|
|
119
|
+
if (!dirty) {
|
|
120
|
+
dirty = true;
|
|
121
|
+
for (const sub of [...subscribers]) {
|
|
122
|
+
pendingEffects.add(sub);
|
|
123
|
+
}
|
|
124
|
+
scheduleFlush();
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
dependencies: innerDependencies,
|
|
128
|
+
cleanup() {
|
|
129
|
+
for (const dep of innerDependencies) {
|
|
130
|
+
dep.delete(markDirty);
|
|
131
|
+
}
|
|
132
|
+
innerDependencies.clear();
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const read = () => {
|
|
136
|
+
const currentEffect = effectStack[effectStack.length - 1];
|
|
137
|
+
if (currentEffect) {
|
|
138
|
+
subscribers.add(currentEffect);
|
|
139
|
+
currentEffect.dependencies.add(subscribers);
|
|
140
|
+
}
|
|
141
|
+
if (dirty) {
|
|
142
|
+
markDirty.cleanup();
|
|
143
|
+
innerDependencies = /* @__PURE__ */ new Set();
|
|
144
|
+
markDirty.dependencies = innerDependencies;
|
|
145
|
+
effectStack.push(markDirty);
|
|
146
|
+
try {
|
|
147
|
+
cachedValue = fn();
|
|
148
|
+
} finally {
|
|
149
|
+
effectStack.pop();
|
|
150
|
+
}
|
|
151
|
+
dirty = false;
|
|
152
|
+
}
|
|
153
|
+
return cachedValue;
|
|
154
|
+
};
|
|
155
|
+
return read;
|
|
156
|
+
}
|
|
157
|
+
var contextStack = [];
|
|
158
|
+
var activeContext = null;
|
|
159
|
+
function pushContext() {
|
|
160
|
+
const ctx = { mounts: [], destroys: [] };
|
|
161
|
+
contextStack.push(ctx);
|
|
162
|
+
activeContext = ctx;
|
|
163
|
+
return ctx;
|
|
164
|
+
}
|
|
165
|
+
function popContext(ctx) {
|
|
166
|
+
const idx = contextStack.lastIndexOf(ctx);
|
|
167
|
+
if (idx !== -1) {
|
|
168
|
+
contextStack.splice(idx, 1);
|
|
169
|
+
}
|
|
170
|
+
activeContext = contextStack.length > 0 ? contextStack[contextStack.length - 1] : null;
|
|
171
|
+
}
|
|
172
|
+
function onMount(fn) {
|
|
173
|
+
if (activeContext) {
|
|
174
|
+
activeContext.mounts.push(fn);
|
|
175
|
+
} else {
|
|
176
|
+
fn();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function onDestroy(fn) {
|
|
180
|
+
if (activeContext) {
|
|
181
|
+
activeContext.destroys.push(fn);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function __flush_mounts() {
|
|
185
|
+
if (activeContext && activeContext.mounts.length > 0) {
|
|
186
|
+
const cbs = [...activeContext.mounts];
|
|
187
|
+
activeContext.mounts = [];
|
|
188
|
+
for (const cb of cbs) {
|
|
189
|
+
cb();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function __flush_destroys() {
|
|
194
|
+
if (activeContext && activeContext.destroys.length > 0) {
|
|
195
|
+
const cbs = [...activeContext.destroys];
|
|
196
|
+
activeContext.destroys = [];
|
|
197
|
+
for (const cb of cbs) {
|
|
198
|
+
cb();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
var defaultIntentConfig = {
|
|
203
|
+
provider: "local",
|
|
204
|
+
endpoint: "/api/intent",
|
|
205
|
+
model: "gemini-2.5-flash",
|
|
206
|
+
stream: false
|
|
207
|
+
};
|
|
208
|
+
var globalIntentConfig = { ...defaultIntentConfig };
|
|
209
|
+
function configureIntent(config) {
|
|
210
|
+
globalIntentConfig = { ...globalIntentConfig, ...config };
|
|
211
|
+
}
|
|
212
|
+
async function _consumeSSE(response, onToken, onDone, onError) {
|
|
213
|
+
const reader = response.body.getReader();
|
|
214
|
+
const decoder = new TextDecoder();
|
|
215
|
+
let buf = "";
|
|
216
|
+
try {
|
|
217
|
+
while (true) {
|
|
218
|
+
const { done, value } = await reader.read();
|
|
219
|
+
if (done) break;
|
|
220
|
+
buf += decoder.decode(value, { stream: true });
|
|
221
|
+
const lines = buf.split("\n");
|
|
222
|
+
buf = lines.pop();
|
|
223
|
+
for (const line of lines) {
|
|
224
|
+
if (!line.startsWith("data: ")) continue;
|
|
225
|
+
const payload = line.slice(6).trim();
|
|
226
|
+
if (payload === "[DONE]") {
|
|
227
|
+
onDone();
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
const parsed = JSON.parse(payload);
|
|
232
|
+
const token = parsed.token ?? parsed.delta ?? parsed.content ?? "";
|
|
233
|
+
if (token) onToken(token);
|
|
234
|
+
} catch {
|
|
235
|
+
if (payload) onToken(payload);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
onDone();
|
|
240
|
+
} catch (err) {
|
|
241
|
+
if (err.name !== "AbortError") onError(err);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function createIntent(promptFn, options = {}) {
|
|
245
|
+
const config = { ...globalIntentConfig, ...options };
|
|
246
|
+
const [read, write] = createSignal(options.initial ?? null);
|
|
247
|
+
const [loading, setLoading] = createSignal(false);
|
|
248
|
+
const [error, setError] = createSignal(null);
|
|
249
|
+
let abortController = null;
|
|
250
|
+
onDestroy(() => {
|
|
251
|
+
if (abortController) abortController.abort();
|
|
252
|
+
});
|
|
253
|
+
createEffect(() => {
|
|
254
|
+
const prompt = typeof promptFn === "function" ? promptFn() : promptFn;
|
|
255
|
+
if (!prompt) return;
|
|
256
|
+
if (abortController) abortController.abort();
|
|
257
|
+
abortController = new AbortController();
|
|
258
|
+
write(null);
|
|
259
|
+
setError(null);
|
|
260
|
+
setLoading(true);
|
|
261
|
+
const body = JSON.stringify({
|
|
262
|
+
messages: [{ role: "user", content: prompt }],
|
|
263
|
+
model: config.model,
|
|
264
|
+
provider: config.provider,
|
|
265
|
+
stream: config.stream
|
|
266
|
+
});
|
|
267
|
+
fetch(config.endpoint, {
|
|
268
|
+
method: "POST",
|
|
269
|
+
headers: { "Content-Type": "application/json" },
|
|
270
|
+
body,
|
|
271
|
+
signal: abortController.signal
|
|
272
|
+
}).then((res) => {
|
|
273
|
+
if (!res.ok) throw new Error(`Intent failed: ${res.status}`);
|
|
274
|
+
if (config.stream) {
|
|
275
|
+
let accumulated = "";
|
|
276
|
+
return _consumeSSE(
|
|
277
|
+
res,
|
|
278
|
+
(token) => {
|
|
279
|
+
accumulated += token;
|
|
280
|
+
write(accumulated);
|
|
281
|
+
},
|
|
282
|
+
() => setLoading(false),
|
|
283
|
+
(err) => {
|
|
284
|
+
setError(err.message);
|
|
285
|
+
setLoading(false);
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
return res.json().then((data) => {
|
|
290
|
+
if (data?.components?.length > 0) write(data.components[0]);
|
|
291
|
+
else if (data?.result != null) write(data.result);
|
|
292
|
+
else write(data);
|
|
293
|
+
setLoading(false);
|
|
294
|
+
});
|
|
295
|
+
}).catch((err) => {
|
|
296
|
+
if (err.name !== "AbortError") {
|
|
297
|
+
console.error("[Sola Intent Error]", err);
|
|
298
|
+
setError(err.message);
|
|
299
|
+
setLoading(false);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
const accessor = read;
|
|
304
|
+
accessor.loading = loading;
|
|
305
|
+
accessor.error = error;
|
|
306
|
+
return accessor;
|
|
307
|
+
}
|
|
308
|
+
var defaultDataConfig = {
|
|
309
|
+
relayEndpoint: "http://localhost:4040/api/query",
|
|
310
|
+
refresh: null
|
|
311
|
+
// e.g. '30s', '1m', '5m'
|
|
312
|
+
};
|
|
313
|
+
var globalDataConfig = { ...defaultDataConfig };
|
|
314
|
+
function configureData(config) {
|
|
315
|
+
globalDataConfig = { ...globalDataConfig, ...config };
|
|
316
|
+
}
|
|
317
|
+
function parseInterval(str) {
|
|
318
|
+
if (!str) return null;
|
|
319
|
+
const match = str.match(/^(\d+)(s|m|h)$/);
|
|
320
|
+
if (!match) return null;
|
|
321
|
+
const val = parseInt(match[1]);
|
|
322
|
+
switch (match[2]) {
|
|
323
|
+
case "s":
|
|
324
|
+
return val * 1e3;
|
|
325
|
+
case "m":
|
|
326
|
+
return val * 60 * 1e3;
|
|
327
|
+
case "h":
|
|
328
|
+
return val * 3600 * 1e3;
|
|
329
|
+
}
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
function createData(source, options = {}) {
|
|
333
|
+
const config = { ...globalDataConfig, ...options };
|
|
334
|
+
const [read, write] = createSignal({ loading: true, data: null, error: null });
|
|
335
|
+
let abortController = null;
|
|
336
|
+
let refreshTimer = null;
|
|
337
|
+
function fetchData() {
|
|
338
|
+
if (abortController) abortController.abort();
|
|
339
|
+
abortController = new AbortController();
|
|
340
|
+
write({ loading: true, data: read().data, error: null });
|
|
341
|
+
fetch(config.relayEndpoint, {
|
|
342
|
+
method: "POST",
|
|
343
|
+
headers: { "Content-Type": "application/json" },
|
|
344
|
+
body: JSON.stringify({
|
|
345
|
+
source,
|
|
346
|
+
query: config.query || null,
|
|
347
|
+
filters: config.filters || null,
|
|
348
|
+
sort: config.sort || null,
|
|
349
|
+
limit: config.limit || null,
|
|
350
|
+
offset: config.offset || null
|
|
351
|
+
}),
|
|
352
|
+
signal: abortController.signal
|
|
353
|
+
}).then((res) => {
|
|
354
|
+
if (!res.ok) throw new Error(`Data fetch failed: ${res.status}`);
|
|
355
|
+
return res.json();
|
|
356
|
+
}).then((data) => {
|
|
357
|
+
write({ loading: false, data: data.rows || data, error: null });
|
|
358
|
+
}).catch((err) => {
|
|
359
|
+
if (err.name !== "AbortError") {
|
|
360
|
+
console.error("[Sola Data Error]", err);
|
|
361
|
+
write({ loading: false, data: null, error: err.message });
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
fetchData();
|
|
366
|
+
const interval = parseInterval(config.refresh);
|
|
367
|
+
if (interval) {
|
|
368
|
+
refreshTimer = setInterval(fetchData, interval);
|
|
369
|
+
}
|
|
370
|
+
const accessor = () => read();
|
|
371
|
+
accessor.refetch = fetchData;
|
|
372
|
+
accessor.stop = () => {
|
|
373
|
+
if (refreshTimer) clearInterval(refreshTimer);
|
|
374
|
+
if (abortController) abortController.abort();
|
|
375
|
+
};
|
|
376
|
+
return accessor;
|
|
377
|
+
}
|
|
378
|
+
var SignalMeshEngine = class {
|
|
379
|
+
constructor() {
|
|
380
|
+
this.topics = /* @__PURE__ */ new Map();
|
|
381
|
+
this.telemetrySubscribers = /* @__PURE__ */ new Set();
|
|
382
|
+
this.cycleStack = /* @__PURE__ */ new Set();
|
|
383
|
+
}
|
|
384
|
+
topic(name, initialValue) {
|
|
385
|
+
if (!this.topics.has(name)) {
|
|
386
|
+
const [read2, write2] = createSignal(initialValue);
|
|
387
|
+
this.topics.set(name, { read: read2, write: write2, value: initialValue, subscribers: /* @__PURE__ */ new Set() });
|
|
388
|
+
}
|
|
389
|
+
const entry = this.topics.get(name);
|
|
390
|
+
const read = () => entry.read();
|
|
391
|
+
const write = (next, originId = "signal") => {
|
|
392
|
+
const nextVal = typeof next === "function" ? next(entry.value) : next;
|
|
393
|
+
if (entry.value === nextVal) return;
|
|
394
|
+
if (this.cycleStack.has(name)) {
|
|
395
|
+
console.warn(`[Sola Signal Mesh] Cycle detected on topic "${name}". Aborting cyclic dispatch.`);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const prev = entry.value;
|
|
399
|
+
entry.value = nextVal;
|
|
400
|
+
entry.write(nextVal);
|
|
401
|
+
const event = {
|
|
402
|
+
topic: name,
|
|
403
|
+
value: nextVal,
|
|
404
|
+
prevValue: prev,
|
|
405
|
+
timestamp: typeof performance !== "undefined" ? performance.now() : Date.now(),
|
|
406
|
+
originWidgetId: originId
|
|
407
|
+
};
|
|
408
|
+
this.telemetrySubscribers.forEach((cb) => {
|
|
409
|
+
try {
|
|
410
|
+
cb(event);
|
|
411
|
+
} catch (e) {
|
|
412
|
+
console.error(e);
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
this.cycleStack.add(name);
|
|
416
|
+
try {
|
|
417
|
+
entry.subscribers.forEach((sub) => {
|
|
418
|
+
try {
|
|
419
|
+
sub(nextVal, event);
|
|
420
|
+
} catch (e) {
|
|
421
|
+
console.error(e);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
} finally {
|
|
425
|
+
this.cycleStack.delete(name);
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
return [read, write];
|
|
429
|
+
}
|
|
430
|
+
subscribe(name, fn) {
|
|
431
|
+
if (!this.topics.has(name)) {
|
|
432
|
+
this.topic(name, void 0);
|
|
433
|
+
}
|
|
434
|
+
const entry = this.topics.get(name);
|
|
435
|
+
entry.subscribers.add(fn);
|
|
436
|
+
return () => entry.subscribers.delete(fn);
|
|
437
|
+
}
|
|
438
|
+
onTelemetry(fn) {
|
|
439
|
+
this.telemetrySubscribers.add(fn);
|
|
440
|
+
return () => this.telemetrySubscribers.delete(fn);
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
var signalMesh = new SignalMeshEngine();
|
|
444
|
+
var createTopicSignal = (topic, initialVal) => signalMesh.topic(topic, initialVal);
|
|
445
|
+
var SolaSentinel = class {
|
|
446
|
+
constructor(name = "default", options = {}) {
|
|
447
|
+
this.name = name;
|
|
448
|
+
this.thresholdMs = options.thresholdMs || 600;
|
|
449
|
+
this.maxRageClicks = options.maxRageClicks || 3;
|
|
450
|
+
this.clickHistory = [];
|
|
451
|
+
this.subscribers = /* @__PURE__ */ new Set();
|
|
452
|
+
this.frictionEvents = [];
|
|
453
|
+
this.flowIndex = 99.8;
|
|
454
|
+
}
|
|
455
|
+
recordClick(actionId, target = "button") {
|
|
456
|
+
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
457
|
+
this.clickHistory.push({ actionId, target, timestamp: now });
|
|
458
|
+
this.clickHistory = this.clickHistory.filter((c) => now - c.timestamp < 2e3);
|
|
459
|
+
const recent = this.clickHistory.filter((c) => c.actionId === actionId && now - c.timestamp < this.thresholdMs);
|
|
460
|
+
if (recent.length >= this.maxRageClicks) {
|
|
461
|
+
this.triggerFrictionAlert({
|
|
462
|
+
type: "RAGE_CLICK",
|
|
463
|
+
actionId,
|
|
464
|
+
target,
|
|
465
|
+
count: recent.length,
|
|
466
|
+
timestamp: now,
|
|
467
|
+
severity: "HIGH",
|
|
468
|
+
message: `Rage-click burst: ${recent.length} taps in ${Math.round(now - recent[0].timestamp)}ms`
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
recordSignalDrop(topic, error) {
|
|
473
|
+
this.triggerFrictionAlert({
|
|
474
|
+
type: "SIGNAL_TIMEOUT",
|
|
475
|
+
topic,
|
|
476
|
+
error: error?.message || String(error),
|
|
477
|
+
timestamp: typeof performance !== "undefined" ? performance.now() : Date.now(),
|
|
478
|
+
severity: "CRITICAL",
|
|
479
|
+
message: `Signal channel "${topic}" breached SLA timeout (504 Gateway Stall)`
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
triggerFrictionAlert(event) {
|
|
483
|
+
this.frictionEvents.unshift(event);
|
|
484
|
+
if (this.frictionEvents.length > 50) this.frictionEvents.pop();
|
|
485
|
+
this.flowIndex = Math.max(68.5, Number((this.flowIndex - 3.8).toFixed(1)));
|
|
486
|
+
this.subscribers.forEach((cb) => {
|
|
487
|
+
try {
|
|
488
|
+
cb(event, this);
|
|
489
|
+
} catch (e) {
|
|
490
|
+
console.error(e);
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
onFriction(cb) {
|
|
495
|
+
this.subscribers.add(cb);
|
|
496
|
+
return () => this.subscribers.delete(cb);
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
function createSentinel(name, options) {
|
|
500
|
+
return new SolaSentinel(name, options);
|
|
501
|
+
}
|
|
502
|
+
return __toCommonJS(src_exports);
|
|
503
|
+
})();
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/* @sola-air-ui/core v1.0.2 | MIT */
|
|
2
|
+
var SolaCore=(()=>{var v=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var $=(r,e)=>{for(var t in e)v(r,t,{get:e[t],enumerable:!0})},N=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of H(e))!R.call(r,s)&&s!==t&&v(r,s,{get:()=>e[s],enumerable:!(n=O(e,s))||n.enumerable});return r};var F=r=>N(v({},"__esModule",{value:!0}),r);var ee={};$(ee,{SolaSentinel:()=>S,__flush_destroys:()=>P,__flush_mounts:()=>J,configureData:()=>B,configureIntent:()=>z,createData:()=>X,createDerived:()=>L,createEffect:()=>M,createIntent:()=>U,createSentinel:()=>Z,createSignal:()=>b,createTopicSignal:()=>Y,flushSync:()=>D,onDestroy:()=>T,onMount:()=>G,popContext:()=>q,pushContext:()=>j,signalMesh:()=>_});var p=[],w=new Set,E=!1;function D(){for(;w.size>0;){let r=[...w];w.clear();for(let e of r)e.execute()}E=!1}function A(){E||(E=!0,queueMicrotask(D))}function b(r){let e=r,t=new Set;return[()=>{let o=p[p.length-1];return o&&(t.add(o),o.dependencies.add(t)),e},o=>{if(e!==o){e=o;for(let i of[...t])w.add(i);A()}}]}function M(r){let e={execute(){t(),p.push(e);try{r()}finally{p.pop()}},dependencies:new Set,cleanup:t};function t(){for(let n of e.dependencies)n.delete(e);e.dependencies.clear()}p.push(e);try{r()}finally{p.pop()}return t}function L(r){let e,t=!0,n=new Set,s=new Set,o={execute(){if(!t){t=!0;for(let c of[...n])w.add(c);A()}},dependencies:s,cleanup(){for(let c of s)c.delete(o);s.clear()}};return()=>{let c=p[p.length-1];if(c&&(n.add(c),c.dependencies.add(n)),t){o.cleanup(),s=new Set,o.dependencies=s,p.push(o);try{e=r()}finally{p.pop()}t=!1}return e}}var m=[],u=null;function j(){let r={mounts:[],destroys:[]};return m.push(r),u=r,r}function q(r){let e=m.lastIndexOf(r);e!==-1&&m.splice(e,1),u=m.length>0?m[m.length-1]:null}function G(r){u?u.mounts.push(r):r()}function T(r){u&&u.destroys.push(r)}function J(){if(u&&u.mounts.length>0){let r=[...u.mounts];u.mounts=[];for(let e of r)e()}}function P(){if(u&&u.destroys.length>0){let r=[...u.destroys];u.destroys=[];for(let e of r)e()}}var W={provider:"local",endpoint:"/api/intent",model:"gemini-2.5-flash",stream:!1},k={...W};function z(r){k={...k,...r}}async function K(r,e,t,n){let s=r.body.getReader(),o=new TextDecoder,i="";try{for(;;){let{done:c,value:f}=await s.read();if(c)break;i+=o.decode(f,{stream:!0});let a=i.split(`
|
|
3
|
+
`);i=a.pop();for(let l of a){if(!l.startsWith("data: "))continue;let d=l.slice(6).trim();if(d==="[DONE]"){t();return}try{let g=JSON.parse(d),h=g.token??g.delta??g.content??"";h&&e(h)}catch{d&&e(d)}}}t()}catch(c){c.name!=="AbortError"&&n(c)}}function U(r,e={}){let t={...k,...e},[n,s]=b(e.initial??null),[o,i]=b(!1),[c,f]=b(null),a=null;T(()=>{a&&a.abort()}),M(()=>{let d=typeof r=="function"?r():r;if(!d)return;a&&a.abort(),a=new AbortController,s(null),f(null),i(!0);let g=JSON.stringify({messages:[{role:"user",content:d}],model:t.model,provider:t.provider,stream:t.stream});fetch(t.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:g,signal:a.signal}).then(h=>{if(!h.ok)throw new Error(`Intent failed: ${h.status}`);if(t.stream){let y="";return K(h,x=>{y+=x,s(y)},()=>i(!1),x=>{f(x.message),i(!1)})}return h.json().then(y=>{y?.components?.length>0?s(y.components[0]):y?.result!=null?s(y.result):s(y),i(!1)})}).catch(h=>{h.name!=="AbortError"&&(console.error("[Sola Intent Error]",h),f(h.message),i(!1))})});let l=n;return l.loading=o,l.error=c,l}var V={relayEndpoint:"http://localhost:4040/api/query",refresh:null},C={...V};function B(r){C={...C,...r}}function Q(r){if(!r)return null;let e=r.match(/^(\d+)(s|m|h)$/);if(!e)return null;let t=parseInt(e[1]);switch(e[2]){case"s":return t*1e3;case"m":return t*60*1e3;case"h":return t*3600*1e3}return null}function X(r,e={}){let t={...C,...e},[n,s]=b({loading:!0,data:null,error:null}),o=null,i=null;function c(){o&&o.abort(),o=new AbortController,s({loading:!0,data:n().data,error:null}),fetch(t.relayEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({source:r,query:t.query||null,filters:t.filters||null,sort:t.sort||null,limit:t.limit||null,offset:t.offset||null}),signal:o.signal}).then(l=>{if(!l.ok)throw new Error(`Data fetch failed: ${l.status}`);return l.json()}).then(l=>{s({loading:!1,data:l.rows||l,error:null})}).catch(l=>{l.name!=="AbortError"&&(console.error("[Sola Data Error]",l),s({loading:!1,data:null,error:l.message}))})}c();let f=Q(t.refresh);f&&(i=setInterval(c,f));let a=()=>n();return a.refetch=c,a.stop=()=>{i&&clearInterval(i),o&&o.abort()},a}var I=class{constructor(){this.topics=new Map,this.telemetrySubscribers=new Set,this.cycleStack=new Set}topic(e,t){if(!this.topics.has(e)){let[i,c]=b(t);this.topics.set(e,{read:i,write:c,value:t,subscribers:new Set})}let n=this.topics.get(e);return[()=>n.read(),(i,c="signal")=>{let f=typeof i=="function"?i(n.value):i;if(n.value===f)return;if(this.cycleStack.has(e)){console.warn(`[Sola Signal Mesh] Cycle detected on topic "${e}". Aborting cyclic dispatch.`);return}let a=n.value;n.value=f,n.write(f);let l={topic:e,value:f,prevValue:a,timestamp:typeof performance<"u"?performance.now():Date.now(),originWidgetId:c};this.telemetrySubscribers.forEach(d=>{try{d(l)}catch(g){console.error(g)}}),this.cycleStack.add(e);try{n.subscribers.forEach(d=>{try{d(f,l)}catch(g){console.error(g)}})}finally{this.cycleStack.delete(e)}}]}subscribe(e,t){this.topics.has(e)||this.topic(e,void 0);let n=this.topics.get(e);return n.subscribers.add(t),()=>n.subscribers.delete(t)}onTelemetry(e){return this.telemetrySubscribers.add(e),()=>this.telemetrySubscribers.delete(e)}},_=new I,Y=(r,e)=>_.topic(r,e),S=class{constructor(e="default",t={}){this.name=e,this.thresholdMs=t.thresholdMs||600,this.maxRageClicks=t.maxRageClicks||3,this.clickHistory=[],this.subscribers=new Set,this.frictionEvents=[],this.flowIndex=99.8}recordClick(e,t="button"){let n=typeof performance<"u"?performance.now():Date.now();this.clickHistory.push({actionId:e,target:t,timestamp:n}),this.clickHistory=this.clickHistory.filter(o=>n-o.timestamp<2e3);let s=this.clickHistory.filter(o=>o.actionId===e&&n-o.timestamp<this.thresholdMs);s.length>=this.maxRageClicks&&this.triggerFrictionAlert({type:"RAGE_CLICK",actionId:e,target:t,count:s.length,timestamp:n,severity:"HIGH",message:`Rage-click burst: ${s.length} taps in ${Math.round(n-s[0].timestamp)}ms`})}recordSignalDrop(e,t){this.triggerFrictionAlert({type:"SIGNAL_TIMEOUT",topic:e,error:t?.message||String(t),timestamp:typeof performance<"u"?performance.now():Date.now(),severity:"CRITICAL",message:`Signal channel "${e}" breached SLA timeout (504 Gateway Stall)`})}triggerFrictionAlert(e){this.frictionEvents.unshift(e),this.frictionEvents.length>50&&this.frictionEvents.pop(),this.flowIndex=Math.max(68.5,Number((this.flowIndex-3.8).toFixed(1))),this.subscribers.forEach(t=>{try{t(e,this)}catch(n){console.error(n)}})}onFriction(e){return this.subscribers.add(e),()=>this.subscribers.delete(e)}};function Z(r,e){return new S(r,e)}return F(ee);})();
|
package/package.json
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sola-air-ui/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Zero-VDOM reactivity engine — signals, effects, lifecycle, and intent primitives",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"exports": {
|
|
8
|
-
".": "./src/index.js"
|
|
8
|
+
".": "./src/index.js",
|
|
9
|
+
"./iife": "./dist/sola-core.iife.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "node build.js",
|
|
13
|
+
"prepare": "node build.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"esbuild": "^0.21.5"
|
|
9
21
|
},
|
|
10
22
|
"keywords": [
|
|
11
23
|
"sola",
|
|
@@ -19,7 +31,7 @@
|
|
|
19
31
|
"homepage": "https://sola-air.dev",
|
|
20
32
|
"repository": {
|
|
21
33
|
"type": "git",
|
|
22
|
-
"url": "https://github.com/rbm3267/sola"
|
|
34
|
+
"url": "https://github.com/rbm3267/sola-air"
|
|
23
35
|
},
|
|
24
36
|
"publishConfig": {
|
|
25
37
|
"access": "public",
|