sproutboat 0.5.0 → 0.6.0

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.
@@ -14,15 +14,22 @@
14
14
  // Duck-typing helpers, `typeof`-free (the repo's anti-slop lint bans `typeof`;
15
15
  // these express the same spec-mandated checks and are verified under Porffor
16
16
  // alpha-4 by examples/kitchen-sink/harness.ts).
17
- function __sbIsStr(v) { return Object(v) !== v && v === String(v); }
18
- function __sbIsFn(v) { return v instanceof Function; }
19
- function __sbIsObj(v) { return v !== null && Object(v) === v; }
17
+ function __sbIsStr(v) {
18
+ return Object(v) !== v && v === String(v);
19
+ }
20
+ function __sbIsFn(v) {
21
+ return v instanceof Function;
22
+ }
23
+ function __sbIsObj(v) {
24
+ return v !== null && Object(v) === v;
25
+ }
20
26
 
21
27
  // #41 — cold-start phase marker. Runs as the first thing in the bundle: writes
22
28
  // the current wall-clock ms to $SB_STARTUP_FILE so the supervisor can split
23
29
  // cold-start into "spawn -> JS starts" (process + runtime bootstrap) and
24
30
  // "JS starts -> listening" (module eval + server bind). No-op when unset.
25
31
  function __sbStartupMark() {
32
+ // oxlint-disable-next-line no-unused-expressions -- Porffor.c`...` is inline C the compiler consumes, not a JS expression.
26
33
  Porffor.c`
27
34
  const char* __f = getenv("SB_STARTUP_FILE");
28
35
  if (__f) {
@@ -43,7 +50,8 @@ __sbStartupMark();
43
50
  // then parsed — Porffor's number boxing for a bare inline-C assignment is not
44
51
  // relied on. `__sbEntry` samples it around the handler for per-invocation CPU.
45
52
  function __sbCpuMs() {
46
- let res = '';
53
+ let res = "";
54
+ // oxlint-disable-next-line no-unused-expressions -- Porffor.c`...` is inline C the compiler consumes, not a JS expression.
47
55
  Porffor.c`
48
56
  struct timespec __ts;
49
57
  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &__ts);
@@ -52,7 +60,7 @@ function __sbCpuMs() {
52
60
  int __n = snprintf(__b, sizeof(__b), "%.3f", __ms);
53
61
  if (__n > 0) res = porf_box((f64)porf_native_fetch_alloc_bytestring(__b, (size_t)__n), 195);
54
62
  `;
55
- return res === '' ? 0 : parseFloat(res);
63
+ return res === "" ? 0 : parseFloat(res);
56
64
  }
57
65
 
58
66
  // #28 — stamp `x-sb-cpu-ms` onto a handler Response. Porffor alpha-4's
@@ -66,13 +74,17 @@ function __sbTagCpu(res, t0) {
66
74
  const cpu = __sbCpuMs() - t0;
67
75
  try {
68
76
  const body = res && res.body;
69
- if (__sbIsStr(body) && !res.headers.has('set-cookie')) {
77
+ if (__sbIsStr(body) && !res.headers.has("set-cookie")) {
70
78
  const headers = {};
71
- res.headers.forEach(function (value, name) { headers[name] = value; });
72
- headers['x-sb-cpu-ms'] = (cpu >= 0 ? cpu : 0).toFixed(3);
79
+ res.headers.forEach(function (value, name) {
80
+ headers[name] = value;
81
+ });
82
+ headers["x-sb-cpu-ms"] = (cpu >= 0 ? cpu : 0).toFixed(3);
73
83
  return new Response(body, { status: res.status, headers: headers });
74
84
  }
75
- } catch { /* fall through to the original response */ }
85
+ } catch {
86
+ /* fall through to the original response */
87
+ }
76
88
  return res;
77
89
  }
78
90
 
@@ -80,53 +92,87 @@ class __SproutboatURLSearchParams {
80
92
  constructor(init) {
81
93
  this._keys = [];
82
94
  this._vals = [];
83
- let raw = init == null ? '' : String(init);
95
+ let raw = init == null ? "" : String(init);
84
96
  if (raw.charCodeAt(0) === 63) raw = raw.slice(1); // strip a leading '?'
85
97
  if (raw.length === 0) return;
86
- const pairs = raw.split('&');
98
+ const pairs = raw.split("&");
87
99
  for (let i = 0; i < pairs.length; i++) {
88
100
  const pair = pairs[i];
89
101
  if (pair.length === 0) continue;
90
- const eq = pair.indexOf('=');
102
+ const eq = pair.indexOf("=");
91
103
  const k = eq === -1 ? pair : pair.slice(0, eq);
92
- const v = eq === -1 ? '' : pair.slice(eq + 1);
93
- this._keys.push(decodeURIComponent(k.split('+').join(' ')));
94
- this._vals.push(decodeURIComponent(v.split('+').join(' ')));
104
+ const v = eq === -1 ? "" : pair.slice(eq + 1);
105
+ this._keys.push(decodeURIComponent(k.split("+").join(" ")));
106
+ this._vals.push(decodeURIComponent(v.split("+").join(" ")));
95
107
  }
96
108
  }
97
- get(name) { for (let i = 0; i < this._keys.length; i++) if (this._keys[i] === name) return this._vals[i]; return null; }
98
- getAll(name) { const out = []; for (let i = 0; i < this._keys.length; i++) if (this._keys[i] === name) out.push(this._vals[i]); return out; }
99
- has(name) { for (let i = 0; i < this._keys.length; i++) if (this._keys[i] === name) return true; return false; }
100
- forEach(cb) { for (let i = 0; i < this._keys.length; i++) cb(this._vals[i], this._keys[i], this); }
109
+ get(name) {
110
+ for (let i = 0; i < this._keys.length; i++) if (this._keys[i] === name) return this._vals[i];
111
+ return null;
112
+ }
113
+ getAll(name) {
114
+ const out = [];
115
+ for (let i = 0; i < this._keys.length; i++) if (this._keys[i] === name) out.push(this._vals[i]);
116
+ return out;
117
+ }
118
+ has(name) {
119
+ for (let i = 0; i < this._keys.length; i++) if (this._keys[i] === name) return true;
120
+ return false;
121
+ }
122
+ forEach(cb) {
123
+ for (let i = 0; i < this._keys.length; i++) cb(this._vals[i], this._keys[i], this);
124
+ }
101
125
  // Mutators: standalone `new URLSearchParams()` building works. They do NOT
102
126
  // write back into a URL's `search` (Porffor's URL has no setter) — build the
103
127
  // string with toString() and assign it yourself.
104
- append(name, value) { this._keys.push(String(name)); this._vals.push(String(value)); }
128
+ append(name, value) {
129
+ this._keys.push(String(name));
130
+ this._vals.push(String(value));
131
+ }
105
132
  set(name, value) {
106
133
  let found = false;
107
134
  for (let i = 0; i < this._keys.length; i++) {
108
135
  if (this._keys[i] !== name) continue;
109
- if (found) { this._keys.splice(i, 1); this._vals.splice(i, 1); i--; }
110
- else { this._vals[i] = String(value); found = true; }
136
+ if (found) {
137
+ this._keys.splice(i, 1);
138
+ this._vals.splice(i, 1);
139
+ i--;
140
+ } else {
141
+ this._vals[i] = String(value);
142
+ found = true;
143
+ }
111
144
  }
112
145
  if (!found) this.append(name, value);
113
146
  }
114
147
  delete(name) {
115
- for (let i = 0; i < this._keys.length; i++) if (this._keys[i] === name) { this._keys.splice(i, 1); this._vals.splice(i, 1); i--; }
148
+ for (let i = 0; i < this._keys.length; i++)
149
+ if (this._keys[i] === name) {
150
+ this._keys.splice(i, 1);
151
+ this._vals.splice(i, 1);
152
+ i--;
153
+ }
116
154
  }
117
155
  sort() {
118
- const idx = this._keys.map((_, i) => i).sort((a, b) => (this._keys[a] < this._keys[b] ? -1 : this._keys[a] > this._keys[b] ? 1 : 0));
156
+ const idx = this._keys
157
+ .map((_, i) => i)
158
+ .sort((a, b) => (this._keys[a] < this._keys[b] ? -1 : this._keys[a] > this._keys[b] ? 1 : 0));
119
159
  this._keys = idx.map((i) => this._keys[i]);
120
160
  this._vals = idx.map((i) => this._vals[i]);
121
161
  }
122
- keys() { return this._keys.slice(); }
123
- values() { return this._vals.slice(); }
124
- get size() { return this._keys.length; }
162
+ keys() {
163
+ return this._keys.slice();
164
+ }
165
+ values() {
166
+ return this._vals.slice();
167
+ }
168
+ get size() {
169
+ return this._keys.length;
170
+ }
125
171
  toString() {
126
- let out = '';
172
+ let out = "";
127
173
  for (let i = 0; i < this._keys.length; i++) {
128
- if (i > 0) out += '&';
129
- out += encodeURIComponent(this._keys[i]) + '=' + encodeURIComponent(this._vals[i]);
174
+ if (i > 0) out += "&";
175
+ out += encodeURIComponent(this._keys[i]) + "=" + encodeURIComponent(this._vals[i]);
130
176
  }
131
177
  return out;
132
178
  }
@@ -135,8 +181,8 @@ class __SproutboatURLSearchParams {
135
181
  // URL and Response are always defined by Porffor's fetch-globals.js banner.
136
182
  if (globalThis.URLSearchParams == null) globalThis.URLSearchParams = __SproutboatURLSearchParams;
137
183
 
138
- if (!('searchParams' in URL.prototype)) {
139
- Object.defineProperty(URL.prototype, 'searchParams', {
184
+ if (!("searchParams" in URL.prototype)) {
185
+ Object.defineProperty(URL.prototype, "searchParams", {
140
186
  configurable: true,
141
187
  get() {
142
188
  if (this.__sbSearchParams == null) this.__sbSearchParams = new __SproutboatURLSearchParams(this.search);
@@ -148,7 +194,7 @@ if (!('searchParams' in URL.prototype)) {
148
194
  if (Response.json == null) {
149
195
  Response.json = function (data, init) {
150
196
  const response = new Response(JSON.stringify(data), init);
151
- if (!response.headers.has('content-type')) response.headers.set('content-type', 'application/json;charset=utf-8');
197
+ if (!response.headers.has("content-type")) response.headers.set("content-type", "application/json;charset=utf-8");
152
198
  return response;
153
199
  };
154
200
  }
@@ -160,27 +206,33 @@ if (Response.json == null) {
160
206
  function __sbDefineURLAccessor(name, get) {
161
207
  if (!(name in URL.prototype)) Object.defineProperty(URL.prototype, name, { configurable: true, get });
162
208
  }
163
- __sbDefineURLAccessor('protocol', function () {
164
- const i = this.origin.indexOf('://');
165
- return i === -1 ? '' : this.origin.slice(0, i + 1);
209
+ __sbDefineURLAccessor("protocol", function () {
210
+ const i = this.origin.indexOf("://");
211
+ return i === -1 ? "" : this.origin.slice(0, i + 1);
166
212
  });
167
- __sbDefineURLAccessor('host', function () {
168
- const i = this.origin.indexOf('://');
169
- return i === -1 ? '' : this.origin.slice(i + 3);
213
+ __sbDefineURLAccessor("host", function () {
214
+ const i = this.origin.indexOf("://");
215
+ return i === -1 ? "" : this.origin.slice(i + 3);
170
216
  });
171
- __sbDefineURLAccessor('hostname', function () {
217
+ __sbDefineURLAccessor("hostname", function () {
172
218
  const h = this.host;
173
- const c = h.indexOf(':');
219
+ const c = h.indexOf(":");
174
220
  return c === -1 ? h : h.slice(0, c);
175
221
  });
176
- __sbDefineURLAccessor('port', function () {
222
+ __sbDefineURLAccessor("port", function () {
177
223
  const h = this.host;
178
- const c = h.indexOf(':');
179
- return c === -1 ? '' : h.slice(c + 1);
224
+ const c = h.indexOf(":");
225
+ return c === -1 ? "" : h.slice(c + 1);
226
+ });
227
+ __sbDefineURLAccessor("hash", function () {
228
+ return "";
229
+ });
230
+ __sbDefineURLAccessor("username", function () {
231
+ return "";
232
+ });
233
+ __sbDefineURLAccessor("password", function () {
234
+ return "";
180
235
  });
181
- __sbDefineURLAccessor('hash', function () { return ''; });
182
- __sbDefineURLAccessor('username', function () { return ''; });
183
- __sbDefineURLAccessor('password', function () { return ''; });
184
236
 
185
237
  // crypto.randomUUID / getRandomValues are absent in native-fetch. Provide them
186
238
  // backed by the OS CSPRNG (`__sbRandomBytes` -> inline C -> /dev/urandom), so
@@ -207,7 +259,9 @@ if (globalThis.structuredClone == null) {
207
259
  // The suggested fix (use structuredClone) is circular — this IS the polyfill,
208
260
  // and Porffor exposes no other deep-clone primitive.
209
261
  // react-doctor-disable-next-line react-doctor/no-json-parse-stringify-clone
210
- globalThis.structuredClone = function (value) { return JSON.parse(JSON.stringify(value)); };
262
+ globalThis.structuredClone = function (value) {
263
+ return JSON.parse(JSON.stringify(value));
264
+ };
211
265
  }
212
266
 
213
267
  if (globalThis.crypto.randomUUID == null) {
@@ -239,6 +293,7 @@ if (globalThis.crypto.randomUUID == null) {
239
293
  // the old fresh-connection-per-call path just failed the call there instead.
240
294
  // Binary values + AF_UNIX = v2.
241
295
 
296
+ // oxlint-disable-next-line no-unused-expressions -- Porffor.c`...` is inline C the compiler consumes, not a JS expression.
242
297
  Porffor.c`
243
298
  #include <sys/socket.h>
244
299
  #include <netinet/in.h>
@@ -366,8 +421,10 @@ static int sb_broker_roundtrip(const char* req, size_t req_len, char** resp_out,
366
421
 
367
422
  // One request string in, one reply string out. `reqJson` is a parameter, so the
368
423
  // generated C names it directly in the RawC block below.
424
+ // oxlint-disable-next-line no-unused-vars -- `reqJson` is read inside the RawC block below, not by JS.
369
425
  function __sbCall(reqJson) {
370
- let res = '';
426
+ let res = "";
427
+ // oxlint-disable-next-line no-unused-expressions -- Porffor.c`...` is inline C the compiler consumes, not a JS expression.
371
428
  Porffor.c`
372
429
  const char* __req; size_t __reqlen; char* __reqowned = 0;
373
430
  porf_native_fetch_read_value(reqJson, &__req, &__reqlen, &__reqowned);
@@ -388,8 +445,10 @@ function __sbCall(reqJson) {
388
445
 
389
446
  // `nStr` is the decimal byte count as a string (same string-param pattern as
390
447
  // __sbEnv). Returns a bytestring of that many CSPRNG bytes, or '' on failure.
448
+ // oxlint-disable-next-line no-unused-vars -- `nStr` is read inside the RawC block below, not by JS.
391
449
  function __sbRandomBytes(nStr) {
392
- let out = '';
450
+ let out = "";
451
+ // oxlint-disable-next-line no-unused-expressions -- Porffor.c`...` is inline C the compiler consumes, not a JS expression.
393
452
  Porffor.c`
394
453
  const char* __ns; size_t __nsl; char* __nso = 0;
395
454
  porf_native_fetch_read_value(nStr, &__ns, &__nsl, &__nso);
@@ -414,7 +473,7 @@ function __sbRpc(op, extra) {
414
473
  const req = { op };
415
474
  if (extra) for (const k in extra) req[k] = extra[k];
416
475
  const reply = JSON.parse(__sbCall(JSON.stringify(req)));
417
- if (reply && reply.ok === false) throw new Error(`sproutboat ${op}: ${reply.error || 'failed'}`);
476
+ if (reply && reply.ok === false) throw new Error(`sproutboat ${op}: ${reply.error || "failed"}`);
418
477
  return reply;
419
478
  }
420
479
 
@@ -425,12 +484,16 @@ function __sbMakeD1(dbName) {
425
484
  const s = {
426
485
  __sql: sql,
427
486
  __params: params,
428
- bind() { return stmt(sql, Array.prototype.slice.call(arguments)); },
487
+ bind() {
488
+ return stmt(sql, Array.prototype.slice.call(arguments));
489
+ },
429
490
  all() {
430
- const r = __sbRpc('d1.query', { db: dbName, sql, params });
491
+ const r = __sbRpc("d1.query", { db: dbName, sql, params });
431
492
  return { results: r.results || [], success: true, meta: r.meta || {} };
432
493
  },
433
- run() { return s.all(); },
494
+ run() {
495
+ return s.all();
496
+ },
434
497
  raw() {
435
498
  const rows = s.all().results;
436
499
  const out = [];
@@ -450,17 +513,21 @@ function __sbMakeD1(dbName) {
450
513
  return s;
451
514
  }
452
515
  return {
453
- prepare(sql) { return stmt(String(sql), []); },
516
+ prepare(sql) {
517
+ return stmt(String(sql), []);
518
+ },
454
519
  batch(statements) {
455
520
  const list = [];
456
- for (let i = 0; i < (statements || []).length; i++) list.push({ sql: statements[i].__sql, params: statements[i].__params });
457
- const r = __sbRpc('d1.batch', { db: dbName, statements: list });
521
+ for (let i = 0; i < (statements || []).length; i++)
522
+ list.push({ sql: statements[i].__sql, params: statements[i].__params });
523
+ const r = __sbRpc("d1.batch", { db: dbName, statements: list });
458
524
  const out = [];
459
- for (let i = 0; i < (r.results || []).length; i++) out.push({ results: r.results[i].results || [], success: true, meta: r.results[i].meta || {} });
525
+ for (let i = 0; i < (r.results || []).length; i++)
526
+ out.push({ results: r.results[i].results || [], success: true, meta: r.results[i].meta || {} });
460
527
  return out;
461
528
  },
462
529
  exec(sql) {
463
- __sbRpc('d1.exec', { db: dbName, sql: String(sql) });
530
+ __sbRpc("d1.exec", { db: dbName, sql: String(sql) });
464
531
  return { count: (String(sql).match(/;/g) || []).length, duration: 0 };
465
532
  },
466
533
  };
@@ -480,8 +547,12 @@ function __sbR2Object(meta, body) {
480
547
  };
481
548
  if (body != null) {
482
549
  obj.body = body;
483
- obj.text = function () { return body; };
484
- obj.json = function () { return JSON.parse(body); };
550
+ obj.text = function () {
551
+ return body;
552
+ };
553
+ obj.json = function () {
554
+ return JSON.parse(body);
555
+ };
485
556
  }
486
557
  return obj;
487
558
  }
@@ -497,17 +568,17 @@ globalThis.__sbInstallBindings = function (target, bindings) {
497
568
  const ns = bindings.kv[i];
498
569
  target[ns] = {
499
570
  get(key) {
500
- const r = __sbRpc('kv.get', { ns, key: String(key) });
571
+ const r = __sbRpc("kv.get", { ns, key: String(key) });
501
572
  return r.found ? r.value : null;
502
573
  },
503
574
  put(key, value) {
504
- __sbRpc('kv.put', { ns, key: String(key), value: String(value) });
575
+ __sbRpc("kv.put", { ns, key: String(key), value: String(value) });
505
576
  },
506
577
  delete(key) {
507
- __sbRpc('kv.delete', { ns, key: String(key) });
578
+ __sbRpc("kv.delete", { ns, key: String(key) });
508
579
  },
509
580
  list(prefix) {
510
- return __sbRpc('kv.list', { ns, prefix: prefix == null ? '' : String(prefix) }).keys || [];
581
+ return __sbRpc("kv.list", { ns, prefix: prefix == null ? "" : String(prefix) }).keys || [];
511
582
  },
512
583
  };
513
584
  }
@@ -521,7 +592,7 @@ globalThis.__sbInstallBindings = function (target, bindings) {
521
592
  Object.defineProperty(target, name, {
522
593
  configurable: true,
523
594
  get() {
524
- const value = __sbRpc('secret.get', { name }).value;
595
+ const value = __sbRpc("secret.get", { name }).value;
525
596
  Object.defineProperty(target, name, { value, configurable: true, enumerable: true });
526
597
  return value;
527
598
  },
@@ -538,31 +609,31 @@ globalThis.__sbInstallBindings = function (target, bindings) {
538
609
  target[name] = {
539
610
  put(key, value, options) {
540
611
  const o = options || {};
541
- return __sbRpc('r2.put', {
612
+ return __sbRpc("r2.put", {
542
613
  bucket: name,
543
614
  key: String(key),
544
- body: value == null ? '' : String(value),
615
+ body: value == null ? "" : String(value),
545
616
  httpMetadata: o.httpMetadata || {},
546
617
  customMetadata: o.customMetadata || {},
547
618
  }).object;
548
619
  },
549
620
  get(key) {
550
- const r = __sbRpc('r2.get', { bucket: name, key: String(key) });
551
- return r.found ? __sbR2Object(r.object, r.body == null ? '' : r.body) : null;
621
+ const r = __sbRpc("r2.get", { bucket: name, key: String(key) });
622
+ return r.found ? __sbR2Object(r.object, r.body == null ? "" : r.body) : null;
552
623
  },
553
624
  head(key) {
554
- const r = __sbRpc('r2.head', { bucket: name, key: String(key) });
625
+ const r = __sbRpc("r2.head", { bucket: name, key: String(key) });
555
626
  return r.found ? __sbR2Object(r.object, null) : null;
556
627
  },
557
628
  delete(key) {
558
- __sbRpc('r2.delete', { bucket: name, key: String(key) });
629
+ __sbRpc("r2.delete", { bucket: name, key: String(key) });
559
630
  },
560
631
  list(options) {
561
632
  const o = options || {};
562
- const r = __sbRpc('r2.list', {
633
+ const r = __sbRpc("r2.list", {
563
634
  bucket: name,
564
- prefix: o.prefix == null ? '' : String(o.prefix),
565
- cursor: o.cursor == null ? '' : String(o.cursor),
635
+ prefix: o.prefix == null ? "" : String(o.prefix),
636
+ cursor: o.cursor == null ? "" : String(o.cursor),
566
637
  limit: o.limit == null ? 1000 : o.limit,
567
638
  });
568
639
  const objects = [];
@@ -577,15 +648,19 @@ globalThis.__sbInstallBindings = function (target, bindings) {
577
648
  target[name] = {
578
649
  send(body, options) {
579
650
  const o = options || {};
580
- __sbRpc('queue.send', { queue: name, body: __sbIsStr(body) ? body : JSON.stringify(body), delaySeconds: o.delaySeconds || 0 });
651
+ __sbRpc("queue.send", {
652
+ queue: name,
653
+ body: __sbIsStr(body) ? body : JSON.stringify(body),
654
+ delaySeconds: o.delaySeconds || 0,
655
+ });
581
656
  },
582
657
  sendBatch(messages) {
583
658
  const list = [];
584
659
  for (let j = 0; j < (messages || []).length; j++) {
585
660
  const m = messages[j];
586
- list.push({ body: __sbIsStr(m.body) ? m.body : JSON.stringify(m.body), delaySeconds: (m.delaySeconds || 0) });
661
+ list.push({ body: __sbIsStr(m.body) ? m.body : JSON.stringify(m.body), delaySeconds: m.delaySeconds || 0 });
587
662
  }
588
- __sbRpc('queue.send_batch', { queue: name, messages: list });
663
+ __sbRpc("queue.send_batch", { queue: name, messages: list });
589
664
  },
590
665
  };
591
666
  }
@@ -595,7 +670,7 @@ globalThis.__sbInstallBindings = function (target, bindings) {
595
670
  target[name] = {
596
671
  writeDataPoint(event) {
597
672
  const e = event || {};
598
- __sbRpc('ae.write', {
673
+ __sbRpc("ae.write", {
599
674
  dataset: name,
600
675
  indexes: e.indexes || [],
601
676
  blobs: e.blobs || [],
@@ -606,7 +681,7 @@ globalThis.__sbInstallBindings = function (target, bindings) {
606
681
  // query it via the SQL API). Returns { count, rows }.
607
682
  query(options) {
608
683
  const o = options || {};
609
- return __sbRpc('ae.query', { dataset: name, limit: o.limit || 20 });
684
+ return __sbRpc("ae.query", { dataset: name, limit: o.limit || 20 });
610
685
  },
611
686
  };
612
687
  }
@@ -623,13 +698,17 @@ globalThis.__sbInstallBindings = function (target, bindings) {
623
698
  if (bindings.assets) {
624
699
  target[bindings.assets] = {
625
700
  fetch(input) {
626
- let path = __sbIsStr(input) ? input : String(input && input.url || '/');
627
- try { path = new URL(path, 'http://a').pathname; } catch { /* use as-is */ }
628
- const r = __sbRpc('assets.get', { path });
701
+ let path = __sbIsStr(input) ? input : String((input && input.url) || "/");
702
+ try {
703
+ path = new URL(path, "http://a").pathname;
704
+ } catch {
705
+ /* use as-is */
706
+ }
707
+ const r = __sbRpc("assets.get", { path });
629
708
  const headers = {};
630
- if (r.type) headers['content-type'] = r.type;
631
- if (r.found) headers['etag'] = '"' + r.hash + '"';
632
- return new Response(r.body == null ? '' : r.body, { status: r.status || (r.found ? 200 : 404), headers });
709
+ if (r.type) headers["content-type"] = r.type;
710
+ if (r.found) headers["etag"] = '"' + r.hash + '"';
711
+ return new Response(r.body == null ? "" : r.body, { status: r.status || (r.found ? 200 : 404), headers });
633
712
  },
634
713
  };
635
714
  }
@@ -643,15 +722,15 @@ globalThis.__sbInstallBindings = function (target, bindings) {
643
722
  if (__sbIsFn(opts.headers.forEach)) opts.headers.forEach((v, k) => headers.push([k, v]));
644
723
  else for (const k in opts.headers) headers.push([k, opts.headers[k]]);
645
724
  }
646
- const r = __sbRpc('fetch', {
725
+ const r = __sbRpc("fetch", {
647
726
  url,
648
- method: opts.method || 'GET',
727
+ method: opts.method || "GET",
649
728
  headers,
650
729
  body: opts.body == null ? null : String(opts.body),
651
730
  });
652
731
  const respHeaders = new Headers();
653
732
  for (let j = 0; j < (r.headers || []).length; j++) respHeaders.set(r.headers[j][0], r.headers[j][1]);
654
- return new Response(r.body == null ? '' : r.body, { status: r.status || 502, headers: respHeaders });
733
+ return new Response(r.body == null ? "" : r.body, { status: r.status || 502, headers: respHeaders });
655
734
  };
656
735
  }
657
736
  };
@@ -669,10 +748,27 @@ globalThis.__sbInstallBindings = function (target, bindings) {
669
748
 
670
749
  function __sbMakeDONamespace(binding, className) {
671
750
  return {
672
- idFromName(name) { return { toString() { return 'name:' + String(name); }, name: String(name) }; },
673
- idFromString(hex) { return { toString() { return String(hex); } }; },
751
+ idFromName(name) {
752
+ return {
753
+ toString() {
754
+ return "name:" + String(name);
755
+ },
756
+ name: String(name),
757
+ };
758
+ },
759
+ idFromString(hex) {
760
+ return {
761
+ toString() {
762
+ return String(hex);
763
+ },
764
+ };
765
+ },
674
766
  newUniqueId() {
675
- return { toString() { return 'uid:' + crypto.randomUUID(); } };
767
+ return {
768
+ toString() {
769
+ return "uid:" + crypto.randomUUID();
770
+ },
771
+ };
676
772
  },
677
773
  get(id) {
678
774
  const idStr = __sbIsStr(id) ? id : id.toString();
@@ -682,14 +778,14 @@ function __sbMakeDONamespace(binding, className) {
682
778
  if (__sbIsObj(input) && __sbIsStr(input.url) && !init) {
683
779
  req = input;
684
780
  } else {
685
- const url = __sbIsStr(input) ? input : String((input && input.url) || 'https://do/');
781
+ const url = __sbIsStr(input) ? input : String((input && input.url) || "https://do/");
686
782
  const opts = init || {};
687
783
  const headers = new Headers();
688
784
  if (opts.headers) {
689
785
  if (__sbIsFn(opts.headers.forEach)) opts.headers.forEach((v, k) => headers.set(k, v));
690
786
  else for (const k in opts.headers) headers.set(k, opts.headers[k]);
691
787
  }
692
- req = new Request(url, { method: opts.method || 'GET', headers });
788
+ req = new Request(url, { method: opts.method || "GET", headers });
693
789
  if (opts.body != null) req.body = String(opts.body);
694
790
  }
695
791
  return __sbGetDOInstance(className, idStr).fetch(req);
@@ -707,14 +803,20 @@ globalThis.__sbRegisterDO = function (map) {
707
803
 
708
804
  function __sbGetDOInstance(cls, id) {
709
805
  const Ctor = __sbDOClasses[cls];
710
- if (!Ctor) throw new Error('no such Durable Object class: ' + cls);
711
- const cacheKey = cls + ' ' + id;
806
+ if (!Ctor) throw new Error("no such Durable Object class: " + cls);
807
+ const cacheKey = cls + " " + id;
712
808
  let inst = __sbDOInstances[cacheKey];
713
809
  if (!inst) {
714
810
  const state = {
715
- id: { toString() { return id; } },
811
+ id: {
812
+ toString() {
813
+ return id;
814
+ },
815
+ },
716
816
  storage: __sbDOStorage(cls, id),
717
- blockConcurrencyWhile(fn) { return fn(); },
817
+ blockConcurrencyWhile(fn) {
818
+ return fn();
819
+ },
718
820
  waitUntil() {},
719
821
  };
720
822
  inst = new Ctor(state, globalThis.env);
@@ -729,33 +831,41 @@ function __sbDOStorage(cls, id) {
729
831
  if (Array.isArray(key)) {
730
832
  const out = new Map();
731
833
  for (let i = 0; i < key.length; i++) {
732
- const r = __sbRpc('do.storage.get', { cls, id, key: String(key[i]) });
834
+ const r = __sbRpc("do.storage.get", { cls, id, key: String(key[i]) });
733
835
  if (r.found) out.set(key[i], JSON.parse(r.value));
734
836
  }
735
837
  return out;
736
838
  }
737
- const r = __sbRpc('do.storage.get', { cls, id, key: String(key) });
839
+ const r = __sbRpc("do.storage.get", { cls, id, key: String(key) });
738
840
  return r.found ? JSON.parse(r.value) : undefined;
739
841
  },
740
842
  put(key, value) {
741
843
  if (key != null && __sbIsObj(key)) {
742
- for (const k in key) __sbRpc('do.storage.put', { cls, id, key: String(k), value: JSON.stringify(key[k]) });
844
+ for (const k in key) __sbRpc("do.storage.put", { cls, id, key: String(k), value: JSON.stringify(key[k]) });
743
845
  return;
744
846
  }
745
- __sbRpc('do.storage.put', { cls, id, key: String(key), value: JSON.stringify(value) });
847
+ __sbRpc("do.storage.put", { cls, id, key: String(key), value: JSON.stringify(value) });
746
848
  },
747
849
  delete(key) {
748
850
  if (Array.isArray(key)) {
749
851
  let n = 0;
750
- for (let i = 0; i < key.length; i++) n += __sbRpc('do.storage.delete', { cls, id, key: String(key[i]) }).deleted ? 1 : 0;
852
+ for (let i = 0; i < key.length; i++)
853
+ n += __sbRpc("do.storage.delete", { cls, id, key: String(key[i]) }).deleted ? 1 : 0;
751
854
  return n;
752
855
  }
753
- return !!__sbRpc('do.storage.delete', { cls, id, key: String(key) }).deleted;
856
+ return !!__sbRpc("do.storage.delete", { cls, id, key: String(key) }).deleted;
857
+ },
858
+ deleteAll() {
859
+ __sbRpc("do.storage.delete_all", { cls, id });
754
860
  },
755
- deleteAll() { __sbRpc('do.storage.delete_all', { cls, id }); },
756
861
  list(options) {
757
862
  const o = options || {};
758
- const r = __sbRpc('do.storage.list', { cls, id, prefix: o.prefix == null ? '' : String(o.prefix), limit: o.limit == null ? 1000 : o.limit });
863
+ const r = __sbRpc("do.storage.list", {
864
+ cls,
865
+ id,
866
+ prefix: o.prefix == null ? "" : String(o.prefix),
867
+ limit: o.limit == null ? 1000 : o.limit,
868
+ });
759
869
  const out = new Map();
760
870
  for (let i = 0; i < (r.entries || []).length; i++) out.set(r.entries[i][0], JSON.parse(r.entries[i][1]));
761
871
  return out;
@@ -769,8 +879,10 @@ function __sbDOStorage(cls, id) {
769
879
  // with SB_BROKER_TOKEN) to the right user handler, and everything else to
770
880
  // `handlers.fetch`.
771
881
 
882
+ // oxlint-disable-next-line no-unused-vars -- `name` is read inside the RawC block below, not by JS.
772
883
  function __sbEnv(name) {
773
- let res = '';
884
+ let res = "";
885
+ // oxlint-disable-next-line no-unused-expressions -- Porffor.c`...` is inline C the compiler consumes, not a JS expression.
774
886
  Porffor.c`
775
887
  const char* __n; size_t __nl; char* __no = 0;
776
888
  porf_native_fetch_read_value(name, &__n, &__nl, &__no);
@@ -785,13 +897,13 @@ function __sbEnv(name) {
785
897
  }
786
898
 
787
899
  function __sbTriggerAuthed(request) {
788
- const want = __sbEnv('SB_BROKER_TOKEN');
900
+ const want = __sbEnv("SB_BROKER_TOKEN");
789
901
  if (!want) return true; // no token configured (local/dev)
790
- return request.headers.get('x-sb-token') === want;
902
+ return request.headers.get("x-sb-token") === want;
791
903
  }
792
904
 
793
905
  globalThis.__sbEntry = function (handlers, request) {
794
- const trigger = request.headers.get('x-sb-trigger');
906
+ const trigger = request.headers.get("x-sb-trigger");
795
907
  if (!trigger) {
796
908
  // #28 — per-invocation CPU time. One fetch turn per process (serial), so the
797
909
  // process CPU delta across the handler is this invocation's CPU.
@@ -808,17 +920,17 @@ globalThis.__sbEntry = function (handlers, request) {
808
920
  if (__res && __sbIsFn(__res.then)) return __res;
809
921
  return __sbTagCpu(__res, __t0);
810
922
  }
811
- if (!__sbTriggerAuthed(request)) return new Response('forbidden', { status: 403 });
923
+ if (!__sbTriggerAuthed(request)) return new Response("forbidden", { status: 403 });
812
924
 
813
- if (trigger === 'scheduled') {
814
- if (!__sbIsFn(handlers.scheduled)) return new Response('no scheduled handler', { status: 404 });
925
+ if (trigger === "scheduled") {
926
+ if (!__sbIsFn(handlers.scheduled)) return new Response("no scheduled handler", { status: 404 });
815
927
  const body = __sbReadJson(request);
816
- handlers.scheduled({ cron: body.cron || '', scheduledTime: body.scheduledTime || Date.now(), noRetry() {} });
817
- return new Response('', { status: 204 });
928
+ handlers.scheduled({ cron: body.cron || "", scheduledTime: body.scheduledTime || Date.now(), noRetry() {} });
929
+ return new Response("", { status: 204 });
818
930
  }
819
931
 
820
- if (trigger === 'queue') {
821
- if (!__sbIsFn(handlers.queue)) return new Response('no queue handler', { status: 404 });
932
+ if (trigger === "queue") {
933
+ if (!__sbIsFn(handlers.queue)) return new Response("no queue handler", { status: 404 });
822
934
  const body = __sbReadJson(request);
823
935
  const acked = [];
824
936
  const retried = [];
@@ -831,32 +943,49 @@ globalThis.__sbEntry = function (handlers, request) {
831
943
  timestamp: m.timestamp,
832
944
  attempts: m.attempts || 1,
833
945
  body: __sbTryParse(m.body),
834
- ack() { if (acked.indexOf(m.id) === -1) acked.push(m.id); },
835
- retry() { if (retried.indexOf(m.id) === -1) retried.push(m.id); },
946
+ ack() {
947
+ if (acked.indexOf(m.id) === -1) acked.push(m.id);
948
+ },
949
+ retry() {
950
+ if (retried.indexOf(m.id) === -1) retried.push(m.id);
951
+ },
836
952
  };
837
953
  messages.push(msg);
838
954
  }
839
955
  const batch = {
840
- queue: body.queue || '',
956
+ queue: body.queue || "",
841
957
  messages,
842
- ackAll() { for (let i = 0; i < messages.length; i++) messages[i].ack(); },
843
- retryAll() { for (let i = 0; i < messages.length; i++) messages[i].retry(); },
958
+ ackAll() {
959
+ for (let i = 0; i < messages.length; i++) messages[i].ack();
960
+ },
961
+ retryAll() {
962
+ for (let i = 0; i < messages.length; i++) messages[i].retry();
963
+ },
844
964
  };
845
965
  handlers.queue(batch);
846
966
  // default: any message neither acked nor retried is treated as acked
847
967
  for (let i = 0; i < messages.length; i++) {
848
968
  if (acked.indexOf(messages[i].id) === -1 && retried.indexOf(messages[i].id) === -1) acked.push(messages[i].id);
849
969
  }
850
- return new Response(JSON.stringify({ ack: acked, retry: retried }), { headers: { 'content-type': 'application/json' } });
970
+ return new Response(JSON.stringify({ ack: acked, retry: retried }), {
971
+ headers: { "content-type": "application/json" },
972
+ });
851
973
  }
852
974
 
853
-
854
- return new Response('unknown trigger', { status: 400 });
975
+ return new Response("unknown trigger", { status: 400 });
855
976
  };
856
977
 
857
978
  function __sbReadJson(request) {
858
- try { return JSON.parse(request.body == null ? '{}' : String(request.body)); } catch { return {}; }
979
+ try {
980
+ return JSON.parse(request.body == null ? "{}" : String(request.body));
981
+ } catch {
982
+ return {};
983
+ }
859
984
  }
860
985
  function __sbTryParse(s) {
861
- try { return JSON.parse(s); } catch { return s; }
986
+ try {
987
+ return JSON.parse(s);
988
+ } catch {
989
+ return s;
990
+ }
862
991
  }