toilscript 0.1.35 → 0.1.37

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/web.js CHANGED
@@ -1,8 +1,8 @@
1
- var ASSEMBLYSCRIPT_VERSION = "0.1.35";
1
+ var ASSEMBLYSCRIPT_VERSION = "0.1.37";
2
2
  var ASSEMBLYSCRIPT_IMPORTMAP = {
3
3
  "imports": {
4
- "toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.35/dist/toilscript.js",
5
- "toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.35/dist/cli.js",
4
+ "toilscript": "https://cdn.jsdelivr.net/npm/toilscript@0.1.37/dist/toilscript.js",
5
+ "toilscript/cli": "https://cdn.jsdelivr.net/npm/toilscript@0.1.37/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.35",
11
+ "version": "0.1.37",
12
12
  "author": "Daniel Wirtz <dcode+assemblyscript@dcode.io>",
13
13
  "license": "Apache-2.0",
14
14
  "homepage": "https://github.com/dacely-cloud/toilscript",
@@ -134,7 +134,7 @@ export declare namespace Object {
134
134
 
135
135
  export declare namespace Date {
136
136
  @external("env", "Date.now")
137
- export function now(): f64;
137
+ export function now(): u64;
138
138
  }
139
139
 
140
140
  export declare namespace console {
@@ -221,6 +221,33 @@ export namespace toildbHost {
221
221
  @external("env", "data.latest")
222
222
  export declare function latest(handle: u32, keyPtr: usize, keyLen: i32, limit: i32): i32;
223
223
 
224
+ // events.append_once -> 1 appended | 0 duplicate (deduped on eventId) | <0 error.
225
+ // Idempotent append: a retried call with the same eventId never doubles the event.
226
+ // @ts-ignore: decorator
227
+ @external("env", "data.append_once")
228
+ export declare function appendOnce(
229
+ handle: u32,
230
+ keyPtr: usize,
231
+ keyLen: i32,
232
+ evidPtr: usize,
233
+ evidLen: i32,
234
+ evPtr: usize,
235
+ evLen: i32
236
+ ): i32;
237
+
238
+ // records.enqueue -> 0 ok | <0 error (Conflict if a concurrent write won, NotFound
239
+ // if absent). A version-checked replace of an existing record's value.
240
+ // @ts-ignore: decorator
241
+ @external("env", "data.enqueue")
242
+ export declare function enqueue(
243
+ handle: u32,
244
+ keyPtr: usize,
245
+ keyLen: i32,
246
+ valPtr: usize,
247
+ valLen: i32,
248
+ idemPtr: usize
249
+ ): i32;
250
+
224
251
  // Copy the last stashed variable-length result into outPtr (outLen must equal
225
252
  // the length the producing op returned). Returns bytes written, or -1 if the
226
253
  // buffer is too small.
@@ -37,8 +37,8 @@ export class Date {
37
37
  return ms;
38
38
  }
39
39
 
40
- @inline static now(): i64 {
41
- return <i64>Date_binding.now();
40
+ @inline static now(): u64 {
41
+ return Date_binding.now();
42
42
  }
43
43
 
44
44
  // It can parse only ISO 8601 inputs like YYYY-MM-DDTHH:MM:SS.000Z
@@ -2231,7 +2231,7 @@ declare class Date {
2231
2231
  millisecond: i32
2232
2232
  ): i64;
2233
2233
  /** Returns the current UTC timestamp in milliseconds. */
2234
- static now(): i64;
2234
+ static now(): u64;
2235
2235
  /** Parses a string representation of a date, and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC. */
2236
2236
  static parse(dateString: string): Date;
2237
2237
  static fromString(dateString: string): Date;
@@ -38,7 +38,14 @@ export function __toildbReadVersion(): i64 {
38
38
  /// before each decode and reads it after; the dispatch marks it AFTER the
39
39
  /// transform runs, so a transform that itself reads (resetting the flag) does not
40
40
  /// clear the outer migration.
41
- let __toildbMigratedFlag: bool = false;
41
+ // `@lazy`: initialized on first access rather than in module-init order. A value
42
+ // type's woven `decodeInto` (which, under the cross-file `@migrate` convention,
43
+ // lives in a DIFFERENT module than this one) compiles these exported accessors on
44
+ // demand; @lazy breaks the init-order dependency so that never trips a
45
+ // use-before-declaration that a plain global would in that circular import graph.
46
+ // @ts-ignore: decorator
47
+ @lazy
48
+ var __toildbMigratedFlag: bool = false;
42
49
  export function __toildbResetMigrated(): void { __toildbMigratedFlag = false; }
43
50
  export function __toildbMarkMigrated(): void { __toildbMigratedFlag = true; }
44
51
  export function __toildbWasMigrated(): bool { return __toildbMigratedFlag; }
@@ -123,10 +130,12 @@ export class Documents<K, V> {
123
130
  results.push(null);
124
131
  continue;
125
132
  }
133
+ const ver = <i64>load<u32>(out.dataStart + off);
134
+ off += 4;
126
135
  const len = <i32>load<u32>(out.dataStart + off);
127
136
  off += 4;
128
137
  const v = instantiate<V>();
129
- v.decodeInto(out.subarray(off, off + len));
138
+ v.decodeIntoVersioned(out.subarray(off, off + len), ver);
130
139
  off += len;
131
140
  results.push(v);
132
141
  }
@@ -161,6 +170,15 @@ export class Documents<K, V> {
161
170
  return v;
162
171
  }
163
172
 
173
+ /// Atomically replace an EXISTING record's value, version-checked: returns true
174
+ /// if applied, false if a concurrent write changed the record first (optimistic
175
+ /// concurrency - re-read and retry) or the record is absent.
176
+ enqueue(key: K, value: V): bool {
177
+ const kb = key.encode();
178
+ const vb = value.encode();
179
+ return toildbHost.enqueue(this.__handle, kb.dataStart, kb.byteLength, vb.dataStart, vb.byteLength, 0) == 0;
180
+ }
181
+
164
182
  /// Delete the record (idempotent).
165
183
  delete(key: K): void {
166
184
  const kb = key.encode();
@@ -323,10 +341,12 @@ export class Membership<K, M> {
323
341
  const count = load<u32>(blob.dataStart + off);
324
342
  off += 4;
325
343
  for (let i: u32 = 0; i < count; i++) {
344
+ const ver = <i64>load<u32>(blob.dataStart + off);
345
+ off += 4;
326
346
  const len = <i32>load<u32>(blob.dataStart + off);
327
347
  off += 4;
328
348
  const m = instantiate<M>();
329
- m.decodeInto(blob.subarray(off, off + len));
349
+ m.decodeIntoVersioned(blob.subarray(off, off + len), ver);
330
350
  out.push(m);
331
351
  off += len;
332
352
  }
@@ -435,6 +455,20 @@ export class Events<K, V> {
435
455
  toildbHost.append(this.__handle, kb.dataStart, kb.byteLength, eb.dataStart, eb.byteLength, 0);
436
456
  }
437
457
 
458
+ /// Append `event` exactly once per `eventId`: a retried call with the same id is
459
+ /// a no-op and returns false; the first call appends and returns true. Idempotent
460
+ /// under at-least-once delivery / client retries (dedup on the caller-chosen id).
461
+ appendOnce(key: K, eventId: string, event: V): bool {
462
+ const kb = key.encode();
463
+ const idb = Uint8Array.wrap(String.UTF8.encode(eventId));
464
+ const eb = event.encode();
465
+ const status = toildbHost.appendOnce(
466
+ this.__handle, kb.dataStart, kb.byteLength,
467
+ idb.dataStart, idb.byteLength, eb.dataStart, eb.byteLength);
468
+ if (status < 0) unreachable();
469
+ return status == 1;
470
+ }
471
+
438
472
  /// The newest `limit` events, newest first. Decodes each framed event into a
439
473
  /// `V`. The host frames them as `u32 count` then per event `u32 len + bytes`.
440
474
  latest(key: K, limit: i32): V[] {
@@ -447,10 +481,12 @@ export class Events<K, V> {
447
481
  const count = load<u32>(blob.dataStart + off);
448
482
  off += 4;
449
483
  for (let i: u32 = 0; i < count; i++) {
484
+ const ver = <i64>load<u32>(blob.dataStart + off);
485
+ off += 4;
450
486
  const len = <i32>load<u32>(blob.dataStart + off);
451
487
  off += 4;
452
488
  const ev = instantiate<V>();
453
- ev.decodeInto(blob.subarray(off, off + len));
489
+ ev.decodeIntoVersioned(blob.subarray(off, off + len), ver);
454
490
  out.push(ev);
455
491
  off += len;
456
492
  }
package/std/ts-plugin.cjs CHANGED
@@ -235,6 +235,15 @@ function init(modules) {
235
235
  node.members.forEach((m) => {
236
236
  if (!ts.isPropertyDeclaration(m) || !declHasDecorator(m, 'collection')) return;
237
237
  if (!m.type || !m.name || !ts.isIdentifier(m.name)) return;
238
+ // A `static` @collection field is ALREADY a static member of the class, so
239
+ // synthesizing a namespace const for it duplicates the name (TS2300). Only
240
+ // the legacy instance (type-carrier) form needs the synthesized static
241
+ // handle; the static form type-checks `Db.coll` on its own (no plugin).
242
+ const mods =
243
+ ts.getModifiers && ts.canHaveModifiers && ts.canHaveModifiers(m)
244
+ ? ts.getModifiers(m)
245
+ : m.modifiers;
246
+ if (mods && mods.some((mod) => mod.kind === ts.SyntaxKind.StaticKeyword)) return;
238
247
  consts += ` const ${m.name.text}: ${m.type.getText(sf)};\n`;
239
248
  });
240
249
  if (consts) {