toilscript 0.1.47 → 0.1.49

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "imports": {
3
- "toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.47/dist/toilscript.js",
4
- "toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.47/dist/cli.js",
3
+ "toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.49/dist/toilscript.js",
4
+ "toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.49/dist/cli.js",
5
5
  "binaryen": "https://cdn.jsdelivr.net/npm/binaryen@130.0.0-nightly.20260609/index.js",
6
6
  "long": "https://cdn.jsdelivr.net/npm/long@5.3.2/index.js"
7
7
  }
package/dist/web.js CHANGED
@@ -1,8 +1,8 @@
1
- var ASSEMBLYSCRIPT_VERSION = "0.1.47";
1
+ var ASSEMBLYSCRIPT_VERSION = "0.1.49";
2
2
  var ASSEMBLYSCRIPT_IMPORTMAP = {
3
3
  "imports": {
4
- "toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.47/dist/toilscript.js",
5
- "toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.47/dist/cli.js",
4
+ "toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.49/dist/toilscript.js",
5
+ "toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.49/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
@@ -8,7 +8,7 @@
8
8
  "toilscript",
9
9
  "wasm"
10
10
  ],
11
- "version": "0.1.47",
11
+ "version": "0.1.49",
12
12
  "author": "Daniel Wirtz <dcode+assemblyscript@dcode.io>",
13
13
  "license": "Apache-2.0",
14
14
  "homepage": "https://github.com/dacely-cloud/toilscript",
@@ -273,3 +273,19 @@ export namespace toildbHost {
273
273
  @external("env", "data.write_allowed")
274
274
  export declare function writeAllowed(): i32;
275
275
  }
276
+
277
+ // Per-domain analytics read. The host stashes a versioned little-endian TenantStats
278
+ // frame in the SAME result buffer the `data.*` ops use, so the guest drains it with
279
+ // `toildbHost.takeResult`. Returns the frame length (>= 0), -2 absent (no caller
280
+ // context / unknown domain), -3 forbidden (a non-dacely caller asked for another domain).
281
+ export namespace analyticsHost {
282
+ // @ts-ignore: decorator
283
+ @external("env", "analytics_read")
284
+ export declare function read(domainPtr: usize, domainLen: i32): i32;
285
+
286
+ // analytics_list_sites(cursor, limit): frame length (count u32 | (u32 nameLen, name)* |
287
+ // has_more u8) stashed for takeResult; -3 forbidden when the caller is not dacely.com.
288
+ // @ts-ignore: decorator
289
+ @external("env", "analytics_list_sites")
290
+ export declare function listSites(cursorPtr: usize, cursorLen: i32, limit: i32): i32;
291
+ }
@@ -13,8 +13,8 @@
13
13
  // static through a type parameter, but `instantiate<V>()` + `v.decodeInto(buf)`
14
14
  // works). Value types must be default-constructible.
15
15
 
16
- import { toildbHost } from "bindings/toildb";
17
- import { DataWriter } from "data";
16
+ import { analyticsHost, toildbHost } from "bindings/toildb";
17
+ import { DataReader, DataWriter } from "data";
18
18
 
19
19
  /// Resolve a `"<db>/<collection>"` name to its numeric host handle. Called once
20
20
  /// per collection at module init by the generated `App` binding.
@@ -438,6 +438,80 @@ export class Counter<K> {
438
438
  }
439
439
  }
440
440
 
441
+ /// One tenant's analytics snapshot (the metering counters + plan limits), read via the
442
+ /// `Analytics` API. `lifetime` holds the per-domain lifetime totals by metric name
443
+ /// (`requests`, `bytes_served`, `status_2xx`.., `db_ops`, `stream_*`, ...); the request
444
+ /// windows pair the current minute/day usage with the plan cap (cap 0 = unlimited).
445
+ export class TenantStats {
446
+ lifetime: Map<string, i64> = new Map<string, i64>();
447
+ reqMinuteUsed: i64 = 0;
448
+ reqMinuteCap: u64 = 0;
449
+ reqDayUsed: i64 = 0;
450
+ reqDayCap: u64 = 0;
451
+ }
452
+
453
+ /// A page of site names from `Analytics.listSites` (dacely.com only). When `hasMore` is
454
+ /// true, pass the last `sites` entry back as the next call's cursor.
455
+ export class SiteList {
456
+ sites: string[] = [];
457
+ hasMore: bool = false;
458
+ }
459
+
460
+ /// Per-domain analytics. A site reads its OWN stats with `Analytics.self()`. The
461
+ /// privileged `dacely.com` domain may read ANY site with `Analytics.site(domain)`; any
462
+ /// other caller gets `null` for a cross-domain read (`null` is also an unknown domain).
463
+ /// The trusted calling domain is decided host-side — the guest cannot forge it.
464
+ export class Analytics {
465
+ private static decode(buf: Uint8Array): TenantStats {
466
+ const r = new DataReader(buf);
467
+ const stats = new TenantStats();
468
+ r.readU16(); // frame version (currently 1)
469
+ const count = r.readU32();
470
+ for (let i: u32 = 0; i < count && r.ok; i++) {
471
+ const name = r.readString();
472
+ stats.lifetime.set(name, r.readI64());
473
+ }
474
+ stats.reqMinuteUsed = r.readI64();
475
+ stats.reqMinuteCap = r.readU64();
476
+ stats.reqDayUsed = r.readI64();
477
+ stats.reqDayCap = r.readU64();
478
+ return stats;
479
+ }
480
+
481
+ /// This site's own analytics. Returns empty stats if unavailable.
482
+ static self(): TenantStats {
483
+ const status = analyticsHost.read(0, 0);
484
+ if (status < 0) return new TenantStats();
485
+ return Analytics.decode(__toildbTake(status));
486
+ }
487
+
488
+ /// Another site's analytics. Only `dacely.com` may call this for a domain other than
489
+ /// its own; every other caller (and an unknown domain) gets `null`.
490
+ static site(domain: string): TenantStats | null {
491
+ const db = Uint8Array.wrap(String.UTF8.encode(domain));
492
+ const status = analyticsHost.read(db.dataStart, db.byteLength);
493
+ if (status < 0) return null;
494
+ return Analytics.decode(__toildbTake(status));
495
+ }
496
+
497
+ /// Enumerate sites, paginated. ONLY `dacely.com` gets results; any other caller gets an
498
+ /// empty list. `cursor` is the previous page's last name (`""` = from the start); reads up
499
+ /// to `limit` names. When `hasMore` is true, pass the last `sites` entry as the next cursor.
500
+ static listSites(cursor: string = "", limit: i32 = 256): SiteList {
501
+ const cb = Uint8Array.wrap(String.UTF8.encode(cursor));
502
+ const out = new SiteList();
503
+ const status = analyticsHost.listSites(cb.dataStart, cb.byteLength, limit);
504
+ if (status < 0) return out;
505
+ const r = new DataReader(__toildbTake(status));
506
+ const count = r.readU32();
507
+ for (let i: u32 = 0; i < count && r.ok; i++) {
508
+ out.sites.push(r.readString());
509
+ }
510
+ out.hasMore = r.readU8() != 0;
511
+ return out;
512
+ }
513
+ }
514
+
441
515
  /// An append-only event log (spec 7.5): activity feeds, audit trails, the
442
516
  /// fact stream a `@derive` consumes. `V` is the `@data` event type, `K` the
443
517
  /// `@data` stream-key type.
@@ -204,10 +204,15 @@ declare function collection(options: CollectionOptions): (target: Object, proper
204
204
  * compiler enforces the family x kind matrix (a `@query` calling `.patch` is a
205
205
  * compile error). */
206
206
  declare function query(target: Function): void;
207
+ declare function query(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<any>): void;
207
208
  declare function action(target: Function): void;
209
+ declare function action(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<any>): void;
208
210
  declare function job(target: Function): void;
211
+ declare function job(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<any>): void;
209
212
  declare function derive(target: Function): void;
213
+ declare function derive(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<any>): void;
210
214
  declare function admin(target: Function): void;
215
+ declare function admin(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<any>): void;
211
216
 
212
217
  // The ToilDB collection HANDLES are ambient globals (NO import, like the bignum
213
218
  // natives below) - the compiler provides them (`std/assembly/toildb`, `@global`);
@@ -277,6 +282,32 @@ declare class Events<K, V> {
277
282
  latest(key: K, limit: i32): V[];
278
283
  }
279
284
 
285
+ /** One tenant's analytics snapshot: per-metric lifetime totals + the request rate
286
+ * windows (current usage paired with the plan cap; cap 0 = unlimited). */
287
+ declare class TenantStats {
288
+ lifetime: Map<string, i64>;
289
+ reqMinuteUsed: i64;
290
+ reqMinuteCap: u64;
291
+ reqDayUsed: i64;
292
+ reqDayCap: u64;
293
+ }
294
+
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
+ /** A page of site names from `Analytics.listSites` (dacely.com only). When `hasMore` is
299
+ * true, pass the last `sites` entry back as the next call's cursor. */
300
+ declare class SiteList {
301
+ sites: string[];
302
+ hasMore: bool;
303
+ }
304
+
305
+ declare class Analytics {
306
+ static self(): TenantStats;
307
+ static site(domain: string): TenantStats | null;
308
+ static listSites(cursor?: string, limit?: i32): SiteList;
309
+ }
310
+
280
311
  // Big integers, native globals implemented in std/assembly/bignum. The
281
312
  // arithmetic/bitwise/comparison operators
282
313
  // (+ - * / % & | ^ << >> == != < > <= >=) are operator overloads resolved by