toilscript 0.1.49 → 0.1.51
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/NOTICE +0 -1
- package/dist/cli.generated.d.ts +2 -2
- package/dist/cli.js +181 -12
- package/dist/cli.js.map +2 -2
- package/dist/importmap.json +2 -2
- package/dist/toilscript.generated.d.ts +2 -2
- package/dist/toilscript.js +1 -1
- package/dist/toilscript.js.map +1 -1
- package/dist/web.js +3 -3
- package/package.json +1 -1
- package/std/assembly/bindings/toildb.ts +6 -0
- package/std/assembly/toildb.ts +173 -10
- package/std/assembly/toilscript.d.ts +71 -6
package/dist/web.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var ASSEMBLYSCRIPT_VERSION = "0.1.
|
|
1
|
+
var ASSEMBLYSCRIPT_VERSION = "0.1.51";
|
|
2
2
|
var ASSEMBLYSCRIPT_IMPORTMAP = {
|
|
3
3
|
"imports": {
|
|
4
|
-
"toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.
|
|
5
|
-
"toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.
|
|
4
|
+
"toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.51/dist/toilscript.js",
|
|
5
|
+
"toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.51/dist/cli.js",
|
|
6
6
|
"binaryen": "https://cdn.jsdelivr.net/npm/binaryen@130.0.0-nightly.20260609/index.js",
|
|
7
7
|
"long": "https://cdn.jsdelivr.net/npm/long@5.3.2/index.js"
|
|
8
8
|
}
|
package/package.json
CHANGED
|
@@ -283,6 +283,12 @@ export namespace analyticsHost {
|
|
|
283
283
|
@external("env", "analytics_read")
|
|
284
284
|
export declare function read(domainPtr: usize, domainLen: i32): i32;
|
|
285
285
|
|
|
286
|
+
// analytics_series(domain, metricId, range): frame length (v2 series frame) stashed for takeResult,
|
|
287
|
+
// or a negative status (-2 absent / -3 forbidden / bad metric or range).
|
|
288
|
+
// @ts-ignore: decorator
|
|
289
|
+
@external("env", "analytics_series")
|
|
290
|
+
export declare function series(domainPtr: usize, domainLen: i32, metricId: i32, range: i32): i32;
|
|
291
|
+
|
|
286
292
|
// analytics_list_sites(cursor, limit): frame length (count u32 | (u32 nameLen, name)* |
|
|
287
293
|
// has_more u8) stashed for takeResult; -3 forbidden when the caller is not dacely.com.
|
|
288
294
|
// @ts-ignore: decorator
|
package/std/assembly/toildb.ts
CHANGED
|
@@ -438,16 +438,145 @@ export class Counter<K> {
|
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
-
///
|
|
442
|
-
/// `
|
|
443
|
-
///
|
|
444
|
-
///
|
|
441
|
+
/// Every per-domain metric, by stable numeric id. This is the WIRE CONTRACT shared with the edge
|
|
442
|
+
/// (`src/analytics/metric_id.rs`) and the dev server; it orders the snapshot frame and addresses a
|
|
443
|
+
/// time-series. Ids `0..=40` are cumulative COUNTERS (a rate is `value / seconds`); `41..=44` are the
|
|
444
|
+
/// avg/peak series of the two GAUGES. Append-only: never renumber.
|
|
445
|
+
export enum MetricId {
|
|
446
|
+
Requests = 0,
|
|
447
|
+
BytesOutL1 = 1,
|
|
448
|
+
BytesInL1 = 2,
|
|
449
|
+
Status2xx = 3,
|
|
450
|
+
Status3xx = 4,
|
|
451
|
+
Status4xx = 5,
|
|
452
|
+
Status5xx = 6,
|
|
453
|
+
StaticHits = 7,
|
|
454
|
+
WasmDispatches = 8,
|
|
455
|
+
ExecutorFullRejects = 9,
|
|
456
|
+
UnknownHostRejects = 10,
|
|
457
|
+
RateLimitedRejects = 11,
|
|
458
|
+
GasUsed = 12,
|
|
459
|
+
DbOps = 13,
|
|
460
|
+
DbReads = 14,
|
|
461
|
+
DbWrites = 15,
|
|
462
|
+
DbErrors = 16,
|
|
463
|
+
DbLatencyNsSum = 17,
|
|
464
|
+
StreamAccepts = 18,
|
|
465
|
+
StreamRejectWrongNode = 19,
|
|
466
|
+
StreamRejectCapacity = 20,
|
|
467
|
+
StreamRejectArtifact = 21,
|
|
468
|
+
StreamRejectGuest = 22,
|
|
469
|
+
StreamTraps = 23,
|
|
470
|
+
StreamIdleTimeouts = 24,
|
|
471
|
+
StreamBytesIn = 25,
|
|
472
|
+
StreamBytesOut = 26,
|
|
473
|
+
StreamBackpressureEvents = 27,
|
|
474
|
+
StreamCloses = 28,
|
|
475
|
+
StreamDisconnects = 29,
|
|
476
|
+
DaemonStarts = 30,
|
|
477
|
+
DaemonStartFailures = 31,
|
|
478
|
+
DaemonTicksFired = 32,
|
|
479
|
+
DaemonTicksSkippedNotLeader = 33,
|
|
480
|
+
DaemonTicksFailed = 34,
|
|
481
|
+
DaemonLeaderAcquires = 35,
|
|
482
|
+
DaemonLeaderFenced = 36,
|
|
483
|
+
DaemonHttpCallAttempts = 37,
|
|
484
|
+
DaemonHttpCallFailures = 38,
|
|
485
|
+
MemGrownBytes = 39,
|
|
486
|
+
Emails = 40,
|
|
487
|
+
ConnectedStreamsAvg = 41,
|
|
488
|
+
ConnectedStreamsPeak = 42,
|
|
489
|
+
CommittedMemoryAvg = 43,
|
|
490
|
+
CommittedMemoryPeak = 44,
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/// The number of cumulative counter metrics (`MetricId 0..=40`) = the length of the snapshot's lifetime
|
|
494
|
+
/// section.
|
|
495
|
+
export const METRIC_COUNTERS: i32 = 41;
|
|
496
|
+
|
|
497
|
+
/// A dashboard time range for `Analytics.series`. Short ranges (1h/6h) read the per-MINUTE ring; the rest
|
|
498
|
+
/// read the per-HOUR ring (30-day retention).
|
|
499
|
+
export enum AnalyticsRange {
|
|
500
|
+
H1 = 0,
|
|
501
|
+
H6 = 1,
|
|
502
|
+
H12 = 2,
|
|
503
|
+
H24 = 3,
|
|
504
|
+
D3 = 4,
|
|
505
|
+
D7 = 5,
|
|
506
|
+
D14 = 6,
|
|
507
|
+
D30 = 7,
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/// One tenant's analytics snapshot: the lifetime totals (indexed by `MetricId`, NO string keys), the two
|
|
511
|
+
/// live gauge levels, and the request windows paired with the plan caps (cap 0 = unlimited). Read every
|
|
512
|
+
/// value either by the typed getter (`stats.requests`) or by id (`stats.metric(MetricId.Requests)`).
|
|
445
513
|
export class TenantStats {
|
|
446
|
-
|
|
514
|
+
/// Lifetime totals indexed by `MetricId` (length `METRIC_COUNTERS`). Prefer the named getters below.
|
|
515
|
+
life: StaticArray<i64> = new StaticArray<i64>(METRIC_COUNTERS);
|
|
516
|
+
/// Live gauges (current level, not a total).
|
|
517
|
+
connectedStreams: i64 = 0;
|
|
518
|
+
committedMemory: i64 = 0;
|
|
519
|
+
/// Request windows: current bucket usage + plan cap (0 = unlimited).
|
|
447
520
|
reqMinuteUsed: i64 = 0;
|
|
448
521
|
reqMinuteCap: u64 = 0;
|
|
449
522
|
reqDayUsed: i64 = 0;
|
|
450
523
|
reqDayCap: u64 = 0;
|
|
524
|
+
/// Edge wall-clock (ms) when the snapshot was read.
|
|
525
|
+
nowMs: u64 = 0;
|
|
526
|
+
|
|
527
|
+
/// Any counter metric by id (0 for an out-of-range id).
|
|
528
|
+
metric(id: MetricId): i64 {
|
|
529
|
+
return <i32>id < METRIC_COUNTERS ? this.life[<i32>id] : 0;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Typed getters for every counter (the catalog: no magic strings, self-documenting).
|
|
533
|
+
get requests(): i64 { return this.life[MetricId.Requests]; }
|
|
534
|
+
get bytesOutL1(): i64 { return this.life[MetricId.BytesOutL1]; }
|
|
535
|
+
get bytesInL1(): i64 { return this.life[MetricId.BytesInL1]; }
|
|
536
|
+
get status2xx(): i64 { return this.life[MetricId.Status2xx]; }
|
|
537
|
+
get status3xx(): i64 { return this.life[MetricId.Status3xx]; }
|
|
538
|
+
get status4xx(): i64 { return this.life[MetricId.Status4xx]; }
|
|
539
|
+
get status5xx(): i64 { return this.life[MetricId.Status5xx]; }
|
|
540
|
+
get staticHits(): i64 { return this.life[MetricId.StaticHits]; }
|
|
541
|
+
get wasmDispatches(): i64 { return this.life[MetricId.WasmDispatches]; }
|
|
542
|
+
get executorFullRejects(): i64 { return this.life[MetricId.ExecutorFullRejects]; }
|
|
543
|
+
get unknownHostRejects(): i64 { return this.life[MetricId.UnknownHostRejects]; }
|
|
544
|
+
get rateLimitedRejects(): i64 { return this.life[MetricId.RateLimitedRejects]; }
|
|
545
|
+
get gasUsed(): i64 { return this.life[MetricId.GasUsed]; }
|
|
546
|
+
get dbOps(): i64 { return this.life[MetricId.DbOps]; }
|
|
547
|
+
get dbReads(): i64 { return this.life[MetricId.DbReads]; }
|
|
548
|
+
get dbWrites(): i64 { return this.life[MetricId.DbWrites]; }
|
|
549
|
+
get dbErrors(): i64 { return this.life[MetricId.DbErrors]; }
|
|
550
|
+
get dbLatencyNsSum(): i64 { return this.life[MetricId.DbLatencyNsSum]; }
|
|
551
|
+
get streamAccepts(): i64 { return this.life[MetricId.StreamAccepts]; }
|
|
552
|
+
get streamBytesIn(): i64 { return this.life[MetricId.StreamBytesIn]; }
|
|
553
|
+
get streamBytesOut(): i64 { return this.life[MetricId.StreamBytesOut]; }
|
|
554
|
+
get streamCloses(): i64 { return this.life[MetricId.StreamCloses]; }
|
|
555
|
+
get streamDisconnects(): i64 { return this.life[MetricId.StreamDisconnects]; }
|
|
556
|
+
get daemonTicks(): i64 { return this.life[MetricId.DaemonTicksFired]; }
|
|
557
|
+
get memGrownBytes(): i64 { return this.life[MetricId.MemGrownBytes]; }
|
|
558
|
+
get emails(): i64 { return this.life[MetricId.Emails]; }
|
|
559
|
+
|
|
560
|
+
/// Mean host-observed DB op latency (ns), or 0 with no ops.
|
|
561
|
+
get meanDbLatencyNs(): i64 {
|
|
562
|
+
const ops = this.dbOps;
|
|
563
|
+
return ops > 0 ? this.dbLatencyNsSum / ops : 0;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/// One metric's time series for a range: `points` oldest→newest, `bucketSecs` the per-bucket width, and
|
|
568
|
+
/// `headMs` the newest bucket's end. Rates are derived, never stored.
|
|
569
|
+
export class Series {
|
|
570
|
+
metric: MetricId = MetricId.Requests;
|
|
571
|
+
bucketSecs: u32 = 0;
|
|
572
|
+
headMs: u64 = 0;
|
|
573
|
+
points: i64[] = [];
|
|
574
|
+
|
|
575
|
+
/// Per-second rate of bucket `i` (its total divided by the bucket width). 0 for an out-of-range index.
|
|
576
|
+
ratePerSec(i: i32): f64 {
|
|
577
|
+
if (i < 0 || i >= this.points.length || this.bucketSecs == 0) return 0;
|
|
578
|
+
return <f64>this.points[i] / <f64>this.bucketSecs;
|
|
579
|
+
}
|
|
451
580
|
}
|
|
452
581
|
|
|
453
582
|
/// A page of site names from `Analytics.listSites` (dacely.com only). When `hasMore` is
|
|
@@ -465,12 +594,16 @@ export class Analytics {
|
|
|
465
594
|
private static decode(buf: Uint8Array): TenantStats {
|
|
466
595
|
const r = new DataReader(buf);
|
|
467
596
|
const stats = new TenantStats();
|
|
468
|
-
r.readU16();
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
597
|
+
const version = r.readU16();
|
|
598
|
+
if (version < 2) return stats; // pre-v2 edge: refuse rather than mis-decode
|
|
599
|
+
stats.nowMs = r.readU64();
|
|
600
|
+
const count = <i32>r.readU32();
|
|
601
|
+
for (let i: i32 = 0; i < count && r.ok; i++) {
|
|
602
|
+
const v = r.readI64();
|
|
603
|
+
if (i < METRIC_COUNTERS) stats.life[i] = v; // ignore any extra (forward-compat)
|
|
473
604
|
}
|
|
605
|
+
stats.connectedStreams = r.readI64();
|
|
606
|
+
stats.committedMemory = r.readI64();
|
|
474
607
|
stats.reqMinuteUsed = r.readI64();
|
|
475
608
|
stats.reqMinuteCap = r.readU64();
|
|
476
609
|
stats.reqDayUsed = r.readI64();
|
|
@@ -478,6 +611,21 @@ export class Analytics {
|
|
|
478
611
|
return stats;
|
|
479
612
|
}
|
|
480
613
|
|
|
614
|
+
private static decodeSeries(buf: Uint8Array): Series {
|
|
615
|
+
const r = new DataReader(buf);
|
|
616
|
+
const out = new Series();
|
|
617
|
+
const version = r.readU16();
|
|
618
|
+
if (version < 2) return out;
|
|
619
|
+
out.metric = <MetricId>r.readU16();
|
|
620
|
+
out.bucketSecs = r.readU32();
|
|
621
|
+
out.headMs = r.readU64();
|
|
622
|
+
const count = <i32>r.readU32();
|
|
623
|
+
const pts = new Array<i64>(count);
|
|
624
|
+
for (let i: i32 = 0; i < count && r.ok; i++) pts[i] = r.readI64();
|
|
625
|
+
out.points = pts;
|
|
626
|
+
return out;
|
|
627
|
+
}
|
|
628
|
+
|
|
481
629
|
/// This site's own analytics. Returns empty stats if unavailable.
|
|
482
630
|
static self(): TenantStats {
|
|
483
631
|
const status = analyticsHost.read(0, 0);
|
|
@@ -494,6 +642,21 @@ export class Analytics {
|
|
|
494
642
|
return Analytics.decode(__toildbTake(status));
|
|
495
643
|
}
|
|
496
644
|
|
|
645
|
+
/// This site's time-series for `metric` over `range` (for graphs). Empty series if unavailable.
|
|
646
|
+
static series(metric: MetricId, range: AnalyticsRange): Series {
|
|
647
|
+
const status = analyticsHost.series(0, 0, <i32>metric, <i32>range);
|
|
648
|
+
if (status < 0) return new Series();
|
|
649
|
+
return Analytics.decodeSeries(__toildbTake(status));
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/// Another site's time-series (dacely.com only, else `null`).
|
|
653
|
+
static siteSeries(domain: string, metric: MetricId, range: AnalyticsRange): Series | null {
|
|
654
|
+
const db = Uint8Array.wrap(String.UTF8.encode(domain));
|
|
655
|
+
const status = analyticsHost.series(db.dataStart, db.byteLength, <i32>metric, <i32>range);
|
|
656
|
+
if (status < 0) return null;
|
|
657
|
+
return Analytics.decodeSeries(__toildbTake(status));
|
|
658
|
+
}
|
|
659
|
+
|
|
497
660
|
/// Enumerate sites, paginated. ONLY `dacely.com` gets results; any other caller gets an
|
|
498
661
|
/// empty list. `cursor` is the previous page's last name (`""` = from the start); reads up
|
|
499
662
|
/// to `limit` names. When `hasMore` is true, pass the last `sites` entry as the next cursor.
|
|
@@ -282,19 +282,79 @@ declare class Events<K, V> {
|
|
|
282
282
|
latest(key: K, limit: i32): V[];
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
/**
|
|
286
|
-
*
|
|
285
|
+
/** Every per-domain metric, by stable numeric id (the wire contract). `0..=40` are cumulative
|
|
286
|
+
* COUNTERS (rate = value/seconds); `41..=44` are the avg/peak series of the two GAUGES. */
|
|
287
|
+
declare const enum MetricId {
|
|
288
|
+
Requests = 0, BytesOutL1 = 1, BytesInL1 = 2,
|
|
289
|
+
Status2xx = 3, Status3xx = 4, Status4xx = 5, Status5xx = 6,
|
|
290
|
+
StaticHits = 7, WasmDispatches = 8,
|
|
291
|
+
ExecutorFullRejects = 9, UnknownHostRejects = 10, RateLimitedRejects = 11, GasUsed = 12,
|
|
292
|
+
DbOps = 13, DbReads = 14, DbWrites = 15, DbErrors = 16, DbLatencyNsSum = 17,
|
|
293
|
+
StreamAccepts = 18, StreamRejectWrongNode = 19, StreamRejectCapacity = 20, StreamRejectArtifact = 21,
|
|
294
|
+
StreamRejectGuest = 22, StreamTraps = 23, StreamIdleTimeouts = 24, StreamBytesIn = 25,
|
|
295
|
+
StreamBytesOut = 26, StreamBackpressureEvents = 27, StreamCloses = 28, StreamDisconnects = 29,
|
|
296
|
+
DaemonStarts = 30, DaemonStartFailures = 31, DaemonTicksFired = 32, DaemonTicksSkippedNotLeader = 33,
|
|
297
|
+
DaemonTicksFailed = 34, DaemonLeaderAcquires = 35, DaemonLeaderFenced = 36,
|
|
298
|
+
DaemonHttpCallAttempts = 37, DaemonHttpCallFailures = 38, MemGrownBytes = 39, Emails = 40,
|
|
299
|
+
ConnectedStreamsAvg = 41, ConnectedStreamsPeak = 42, CommittedMemoryAvg = 43, CommittedMemoryPeak = 44,
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** A dashboard time range for `Analytics.series`. 1h/6h are per-minute; the rest per-hour (30-day). */
|
|
303
|
+
declare const enum AnalyticsRange {
|
|
304
|
+
H1 = 0, H6 = 1, H12 = 2, H24 = 3, D3 = 4, D7 = 5, D14 = 6, D30 = 7,
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** One tenant's analytics snapshot: lifetime totals (indexed by `MetricId`, no string keys), the two
|
|
308
|
+
* live gauge levels, and the request windows (current usage + plan cap; cap 0 = unlimited). Read a
|
|
309
|
+
* value by typed getter (`stats.requests`) or by id (`stats.metric(MetricId.Requests)`). */
|
|
287
310
|
declare class TenantStats {
|
|
288
|
-
|
|
311
|
+
metric(id: MetricId): i64;
|
|
312
|
+
readonly requests: i64;
|
|
313
|
+
readonly bytesOutL1: i64;
|
|
314
|
+
readonly bytesInL1: i64;
|
|
315
|
+
readonly status2xx: i64;
|
|
316
|
+
readonly status3xx: i64;
|
|
317
|
+
readonly status4xx: i64;
|
|
318
|
+
readonly status5xx: i64;
|
|
319
|
+
readonly staticHits: i64;
|
|
320
|
+
readonly wasmDispatches: i64;
|
|
321
|
+
readonly executorFullRejects: i64;
|
|
322
|
+
readonly unknownHostRejects: i64;
|
|
323
|
+
readonly rateLimitedRejects: i64;
|
|
324
|
+
readonly gasUsed: i64;
|
|
325
|
+
readonly dbOps: i64;
|
|
326
|
+
readonly dbReads: i64;
|
|
327
|
+
readonly dbWrites: i64;
|
|
328
|
+
readonly dbErrors: i64;
|
|
329
|
+
readonly dbLatencyNsSum: i64;
|
|
330
|
+
readonly meanDbLatencyNs: i64;
|
|
331
|
+
readonly streamAccepts: i64;
|
|
332
|
+
readonly streamBytesIn: i64;
|
|
333
|
+
readonly streamBytesOut: i64;
|
|
334
|
+
readonly streamCloses: i64;
|
|
335
|
+
readonly streamDisconnects: i64;
|
|
336
|
+
readonly daemonTicks: i64;
|
|
337
|
+
readonly memGrownBytes: i64;
|
|
338
|
+
readonly emails: i64;
|
|
339
|
+
connectedStreams: i64;
|
|
340
|
+
committedMemory: i64;
|
|
289
341
|
reqMinuteUsed: i64;
|
|
290
342
|
reqMinuteCap: u64;
|
|
291
343
|
reqDayUsed: i64;
|
|
292
344
|
reqDayCap: u64;
|
|
345
|
+
nowMs: u64;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** One metric's time series for a range: `points` oldest→newest, `bucketSecs` bucket width,
|
|
349
|
+
* `headMs` newest bucket end. `ratePerSec(i)` derives the per-second rate of point `i`. */
|
|
350
|
+
declare class Series {
|
|
351
|
+
metric: MetricId;
|
|
352
|
+
bucketSecs: u32;
|
|
353
|
+
headMs: u64;
|
|
354
|
+
points: i64[];
|
|
355
|
+
ratePerSec(i: i32): f64;
|
|
293
356
|
}
|
|
294
357
|
|
|
295
|
-
/** Per-domain analytics. `Analytics.self()` reads this site's own stats; the privileged
|
|
296
|
-
* `dacely.com` domain may read any site via `Analytics.site(domain)` (any other caller,
|
|
297
|
-
* or an unknown domain, gets `null`). The calling domain is decided host-side. */
|
|
298
358
|
/** A page of site names from `Analytics.listSites` (dacely.com only). When `hasMore` is
|
|
299
359
|
* true, pass the last `sites` entry back as the next call's cursor. */
|
|
300
360
|
declare class SiteList {
|
|
@@ -302,9 +362,14 @@ declare class SiteList {
|
|
|
302
362
|
hasMore: bool;
|
|
303
363
|
}
|
|
304
364
|
|
|
365
|
+
/** Per-domain analytics. `Analytics.self()` reads this site's own stats; the privileged
|
|
366
|
+
* `dacely.com` domain may read any site via `Analytics.site(domain)` (any other caller,
|
|
367
|
+
* or an unknown domain, gets `null`). The calling domain is decided host-side. */
|
|
305
368
|
declare class Analytics {
|
|
306
369
|
static self(): TenantStats;
|
|
307
370
|
static site(domain: string): TenantStats | null;
|
|
371
|
+
static series(metric: MetricId, range: AnalyticsRange): Series;
|
|
372
|
+
static siteSeries(domain: string, metric: MetricId, range: AnalyticsRange): Series | null;
|
|
308
373
|
static listSites(cursor?: string, limit?: i32): SiteList;
|
|
309
374
|
}
|
|
310
375
|
|