-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprimordials.ts
More file actions
892 lines (847 loc) · 44.1 KB
/
primordials.ts
File metadata and controls
892 lines (847 loc) · 44.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
/**
* @fileoverview Safe references to built-in functions and constructors.
*
* Captures references to JavaScript built-ins at module load time, before
* user code can tamper with prototypes or globals. Consumers that process
* adversarial input (PURL parsers, manifest readers, config validators,
* anything that ingests untrusted strings or JSON) should import from here
* instead of using globals directly, so prototype-pollution attacks on the
* caller realm can't silently redirect library internals.
*
* Convention follows Node.js's internal primordials module:
*
* - **Static methods** retain their original name: `ObjectKeys`,
* `ArrayIsArray`, `JSONParse`.
* - **Prototype methods** are uncurried via `uncurryThis`, so you call
* `StringPrototypeSlice(str, 0, 3)` instead of `str.slice(0, 3)`.
* - **Constructors** get a `Ctor` suffix to avoid shadowing the capital-
* case global: `MapCtor`, `SetCtor`.
*
* **IMPORTANT**: do not use destructuring on `globalThis` or `Reflect`
* here. tsgo has a bug that mis-transpiles destructured exports.
* See: https://github.com/SocketDev/socket-packageurl-js/issues/3
*
* @see https://github.com/nicolo-ribaudo/tc39-proposal-primordials
* @see https://github.com/nodejs/node/blob/main/lib/internal/per_context/primordials.js
*/
// ─── Smol bindings (feature-detect) ────────────────────────────────────
// When running on socket-btm's smol Node binary, two extra builtins
// are available:
//
// - `node:smol-util` — native uncurryThis / applyBind. ~2x faster
// than the JS form's two-dispatch path.
// - `node:smol-primordial` — V8 Fast API typed Math.* / Number.is*.
// TurboFan inlines them into JIT-compiled callers. ~30-50% gain
// on hot loops.
//
// On stock Node, browsers, Deno, and Bun, both probes return undefined
// and exports below fall back to the standard built-ins. Same identifier
// name across runtimes — consumer code never changes.
import { getSmolPrimordial } from './smol/primordial'
import { getSmolUtil } from './smol/util'
const _smolUtil = getSmolUtil()
const _smolPrimordial = getSmolPrimordial()
// ─── uncurryThis ───────────────────────────────────────────────────────
// Mirrors Node.js internal/per_context/primordials.js:
// const { apply, bind, call } = Function.prototype
// const uncurryThis = bind.bind(call)
const { apply, bind, call } = Function.prototype
export const uncurryThis =
_smolUtil?.uncurryThis ??
(bind.bind(call) as <T, A extends readonly unknown[], R>(
fn: (this: T, ...args: A) => R,
) => (self: T, ...args: A) => R)
export const applyBind =
_smolUtil?.applyBind ??
(bind.bind(apply) as <T, A extends readonly unknown[], R>(
fn: (this: T, ...args: A) => R,
) => (self: T, args: A) => R)
// ─── applySafe ─────────────────────────────────────────────────────────
// Native form skips JS-level throw construction on the swallow path.
// JS fallback is the obvious shape: applyBind + try/catch around the
// inner call. Used by logger sinks, debug hooks, abort handlers — any
// place where the callee is untrusted user code and the host doesn't
// care whether it threw.
const _applyBoundForSafe = applyBind
export const applySafe: <T, A extends readonly unknown[], R>(
fn: (this: T, ...args: A) => R,
) => (self: T, args: A) => R | undefined =
_smolUtil?.applySafe ??
(<T, A extends readonly unknown[], R>(fn: (this: T, ...args: A) => R) => {
const apply2 = _applyBoundForSafe(fn)
return (self: T, args: A): R | undefined => {
try {
return apply2(self, args)
} catch {
return undefined
}
}
})
// ─── bindCall ──────────────────────────────────────────────────────────
// Native form is single-dispatch; JS fallback is `Function.prototype.bind`,
// which goes through V8's BoundFunction adapter on every invocation.
// 2x per call when the bound function is hot.
type BindCall = <
T,
P extends readonly unknown[],
A extends readonly unknown[],
R,
>(
fn: (this: T, ...args: [...P, ...A]) => R,
thisArg: T,
...presetArgs: P
) => (...newArgs: A) => R
const _bindCallFallback = ((
fn: (...a: unknown[]) => unknown,
thisArg: unknown,
...presetArgs: unknown[]
) =>
Function.prototype.bind.apply(fn, [
thisArg,
...presetArgs,
])) as unknown as BindCall
export const bindCall: BindCall = _smolUtil?.bindCall ?? _bindCallFallback
// ─── weakRefSafe ───────────────────────────────────────────────────────
// `new WeakRef(target)` throws for non-Object, non-Symbol inputs. The
// Safe form predicates the input first and returns `undefined` for
// non-wrappable values without paying exception-construction cost.
export const weakRefSafe: <T extends object | symbol>(
target: T,
) => WeakRef<T> | undefined =
_smolUtil?.weakRefSafe ??
(<T extends object | symbol>(target: T): WeakRef<T> | undefined => {
try {
return new WeakRef(target)
} catch {
return undefined
}
})
// ─── Constructors ──────────────────────────────────────────────────────
export const ArrayCtor: ArrayConstructor = Array
export const ArrayBufferCtor: ArrayBufferConstructor = ArrayBuffer
export const BigIntCtor: BigIntConstructor = BigInt
export const BooleanCtor: BooleanConstructor = Boolean
// BufferCtor is a Node-only global; `undefined` in the browser. Callers
// that import it in browser code get a type-safe `undefined` rather than
// a runtime ReferenceError.
export const BufferCtor: typeof globalThis.Buffer | undefined = (
globalThis as { Buffer?: typeof globalThis.Buffer }
).Buffer
export const DataViewCtor: DataViewConstructor = DataView
export const DateCtor: DateConstructor = Date
export const ErrorCtor: ErrorConstructor = Error
// Error subclasses commonly thrown in validation paths.
export const AggregateErrorCtor: AggregateErrorConstructor = AggregateError
export const EvalErrorCtor: EvalErrorConstructor = EvalError
export const RangeErrorCtor: RangeErrorConstructor = RangeError
export const ReferenceErrorCtor: ReferenceErrorConstructor = ReferenceError
export const SyntaxErrorCtor: SyntaxErrorConstructor = SyntaxError
export const TypeErrorCtor: TypeErrorConstructor = TypeError
export const URIErrorCtor: URIErrorConstructor = URIError
export const MapCtor: MapConstructor = Map
export const NumberCtor: NumberConstructor = Number
export const ObjectCtor: ObjectConstructor = Object
export const PromiseCtor: PromiseConstructor = Promise
export const ProxyCtor: ProxyConstructor = Proxy
export const RegExpCtor: RegExpConstructor = RegExp
export const SetCtor: SetConstructor = Set
export const SharedArrayBufferCtor: SharedArrayBufferConstructor =
SharedArrayBuffer
export const StringCtor: StringConstructor = String
export const SymbolCtor: SymbolConstructor = Symbol
// Typed-array constructors. Same shape as Array — bundled externals
// (npm-pack, adm-zip, tar-fs, etc.) reach for these directly.
export const Float32ArrayCtor: Float32ArrayConstructor = Float32Array
export const Float64ArrayCtor: Float64ArrayConstructor = Float64Array
export const Int8ArrayCtor: Int8ArrayConstructor = Int8Array
export const Int16ArrayCtor: Int16ArrayConstructor = Int16Array
export const Int32ArrayCtor: Int32ArrayConstructor = Int32Array
export const Uint8ArrayCtor: Uint8ArrayConstructor = Uint8Array
export const Uint8ClampedArrayCtor: Uint8ClampedArrayConstructor =
Uint8ClampedArray
export const Uint16ArrayCtor: Uint16ArrayConstructor = Uint16Array
export const Uint32ArrayCtor: Uint32ArrayConstructor = Uint32Array
export const URLCtor: typeof URL = URL
export const URLSearchParamsCtor: typeof URLSearchParams = URLSearchParams
export const WeakMapCtor: WeakMapConstructor = WeakMap
export const WeakRefCtor: WeakRefConstructor = WeakRef
export const WeakSetCtor: WeakSetConstructor = WeakSet
// ─── Global values ─────────────────────────────────────────────────────
// `Infinity` and `NaN` are the language's two non-finite number primitives.
// They are non-writable / non-configurable on globalThis since ES5, so the
// captured value is guaranteed to match the live global. Re-exported here
// for symmetry with `NumberPOSITIVE_INFINITY` / `NumberNaN`.
export const InfinityValue: number = Infinity
export const NaNValue: number = NaN
// `globalThisRef` is the captured `globalThis` reference — same object
// in every realm and frozen on the spec side. Importers that need to
// install or read globals safely use this rather than the keyword
// directly.
export const globalThisRef: typeof globalThis = globalThis
// ─── Global functions ──────────────────────────────────────────────────
export const decodeComponent = globalThis.decodeURIComponent
export const encodeComponent = globalThis.encodeURIComponent
// ─── JSON ──────────────────────────────────────────────────────────────
export const JSONParse = JSON.parse
export const JSONStringify = JSON.stringify
// ─── Array (static) ────────────────────────────────────────────────────
export const ArrayFrom = Array.from
// `Array.fromAsync` is ES2024 (Node 22.0+ / V8 ≥ 12.0). Typed as
// `Function | undefined` for safety even though Node 22+ always has it.
// Unbound: matches `ArrayFrom`. The spec algorithm uses `this` as the
// species constructor, so an undefined `this` falls back to a plain
// Array — exactly what we want.
//
// TS lib may not include `Array.fromAsync` yet (it's in ES2024
// `lib.es2024.array.d.ts`); typed via the local signature.
export type ArrayFromAsync = <T>(
source:
| AsyncIterable<T>
| Iterable<T | PromiseLike<T>>
| ArrayLike<T | PromiseLike<T>>,
) => Promise<T[]>
export const ArrayFromAsync: ArrayFromAsync | undefined = (
Array as unknown as { fromAsync?: ArrayFromAsync }
).fromAsync
// `arrayIsArray` is a Fast API binding — a single map-pointer
// comparison that V8 inlines into JIT'd callers. Spec semantics
// match Array.isArray (excludes typed arrays + array-like objects).
export const ArrayIsArray = _smolPrimordial?.arrayIsArray ?? Array.isArray
export const ArrayOf = Array.of
// ─── ArrayBuffer (static) ──────────────────────────────────────────────
export const ArrayBufferIsView = ArrayBuffer.isView
// ─── Atomics (static) ──────────────────────────────────────────────────
// Atomics.wait blocks the calling thread until either notified or the
// timeout elapses. Used by the sync retry loop in fs.safeDeleteSync to
// sleep without spinning the CPU.
export const AtomicsWait = Atomics.wait
// ─── Array (prototype) ─────────────────────────────────────────────────
export const ArrayPrototypeAt = uncurryThis(Array.prototype.at)
export const ArrayPrototypeConcat = uncurryThis(Array.prototype.concat) as <T>(
self: T[],
...items: Array<T | readonly T[]>
) => T[]
export const ArrayPrototypeCopyWithin = uncurryThis(Array.prototype.copyWithin)
export const ArrayPrototypeEntries = uncurryThis(Array.prototype.entries)
export const ArrayPrototypeEvery = uncurryThis(Array.prototype.every)
export const ArrayPrototypeFill = uncurryThis(Array.prototype.fill)
export const ArrayPrototypeFilter = uncurryThis(Array.prototype.filter)
export const ArrayPrototypeFind = uncurryThis(Array.prototype.find)
export const ArrayPrototypeFindIndex = uncurryThis(Array.prototype.findIndex)
export const ArrayPrototypeFindLast = uncurryThis(Array.prototype.findLast)
export const ArrayPrototypeFindLastIndex = uncurryThis(
Array.prototype.findLastIndex,
)
export const ArrayPrototypeFlat = uncurryThis(Array.prototype.flat)
export const ArrayPrototypeFlatMap = uncurryThis(Array.prototype.flatMap)
export const ArrayPrototypeForEach = uncurryThis(Array.prototype.forEach)
export const ArrayPrototypeIncludes = uncurryThis(Array.prototype.includes)
export const ArrayPrototypeIndexOf = uncurryThis(Array.prototype.indexOf)
export const ArrayPrototypeJoin = uncurryThis(Array.prototype.join)
export const ArrayPrototypeKeys = uncurryThis(Array.prototype.keys)
export const ArrayPrototypeLastIndexOf = uncurryThis(
Array.prototype.lastIndexOf,
)
export const ArrayPrototypeMap = uncurryThis(Array.prototype.map)
export const ArrayPrototypePop = uncurryThis(Array.prototype.pop)
export const ArrayPrototypePush = uncurryThis(Array.prototype.push) as <T>(
self: T[],
...items: T[]
) => number
export const ArrayPrototypeReduce = uncurryThis(Array.prototype.reduce)
export const ArrayPrototypeReduceRight = uncurryThis(
Array.prototype.reduceRight,
)
export const ArrayPrototypeReverse = uncurryThis(Array.prototype.reverse)
export const ArrayPrototypeShift = uncurryThis(Array.prototype.shift)
export const ArrayPrototypeSlice = uncurryThis(Array.prototype.slice)
export const ArrayPrototypeSome = uncurryThis(Array.prototype.some)
export const ArrayPrototypeSort = uncurryThis(Array.prototype.sort)
export const ArrayPrototypeSplice = uncurryThis(Array.prototype.splice) as <T>(
self: T[],
start: number,
deleteCount?: number,
...items: T[]
) => T[]
export const ArrayPrototypeToReversed = uncurryThis(Array.prototype.toReversed)
export const ArrayPrototypeToSorted = uncurryThis(Array.prototype.toSorted)
// `toSpliced` is a copying variant of `splice`; same `(start, deleteCount, ...items)` signature.
export const ArrayPrototypeToSpliced = uncurryThis(
Array.prototype.toSpliced,
) as <T>(self: T[], start: number, deleteCount?: number, ...items: T[]) => T[]
export const ArrayPrototypeUnshift = uncurryThis(Array.prototype.unshift) as <
T,
>(
self: T[],
...items: T[]
) => number
export const ArrayPrototypeValues = uncurryThis(Array.prototype.values)
// ES2023 Change Array By Copy — `arr.with(i, v)` returns a copy with
// index `i` replaced by `v`.
export const ArrayPrototypeWith = uncurryThis(Array.prototype.with) as <T>(
self: T[],
index: number,
value: T,
) => T[]
// ─── Buffer (static) ───────────────────────────────────────────────────
// Buffer is a Node-only global; these helpers are `undefined` in browsers.
// Typed as the corresponding member type | undefined so TS forces a
// null-check in cross-env code.
export const BufferAlloc: typeof Buffer.alloc | undefined = BufferCtor?.alloc
export const BufferAllocUnsafe: typeof Buffer.allocUnsafe | undefined =
BufferCtor?.allocUnsafe
export const BufferAllocUnsafeSlow: typeof Buffer.allocUnsafeSlow | undefined =
BufferCtor?.allocUnsafeSlow
export const BufferByteLength: typeof Buffer.byteLength | undefined =
BufferCtor?.byteLength
export const BufferConcat: typeof Buffer.concat | undefined = BufferCtor?.concat
export const BufferFrom: typeof Buffer.from | undefined = BufferCtor?.from
export const BufferIsBuffer: typeof Buffer.isBuffer | undefined =
BufferCtor?.isBuffer
export const BufferIsEncoding: typeof Buffer.isEncoding | undefined =
BufferCtor?.isEncoding
// ─── Buffer (prototype) ────────────────────────────────────────────────
export const BufferPrototypeSlice:
| ((buf: Buffer, start?: number, end?: number) => Buffer)
| undefined = BufferCtor ? uncurryThis(BufferCtor.prototype.slice) : undefined
export const BufferPrototypeToString:
| ((
buf: Buffer,
encoding?: BufferEncoding,
start?: number,
end?: number,
) => string)
| undefined = BufferCtor
? uncurryThis(BufferCtor.prototype.toString)
: undefined
// ─── Date (static) ─────────────────────────────────────────────────────
// `dateNow` Fast API binding inlines the wallclock-read into JIT'd
// callers — meaningful win in tight monitoring loops where Date.now()
// is called millions of times/sec for performance traces.
export const DateNow = _smolPrimordial?.dateNow ?? Date.now
export const DateParse = Date.parse
export const DateUTC = Date.UTC
// ─── Date (prototype) ──────────────────────────────────────────────────
export const DatePrototypeGetTime = uncurryThis(Date.prototype.getTime)
export const DatePrototypeToISOString = uncurryThis(Date.prototype.toISOString)
export const DatePrototypeToLocaleString = uncurryThis(
Date.prototype.toLocaleString,
)
export const DatePrototypeValueOf = uncurryThis(Date.prototype.valueOf)
// ─── Error (static) ────────────────────────────────────────────────────
// `Error.isError` is ES2025 (Node 22.18+). Older Node falls back to
// `instanceof Error` via the polyfill in src/errors.ts. The primordial
// reference is typed `Function | undefined` so callers in older
// environments don't crash at import time.
export const ErrorIsError: ((value: unknown) => value is Error) | undefined = (
Error as { isError?: (v: unknown) => v is Error }
).isError
// V8-specific stack trace API. See https://v8.dev/docs/stack-trace-api.
// These are present on V8 (Node, Chromium, Deno) but not in
// JavaScriptCore / SpiderMonkey, so each is typed `| undefined` to keep
// non-V8 importers safe.
// `Error.captureStackTrace(targetObject, constructorOpt?)` — attaches a
// `.stack` property to `targetObject`. Captured at load time so callers
// can't intercept by overwriting the global later.
export const ErrorCaptureStackTrace:
| ((targetObject: object, constructorOpt?: Function) => void)
| undefined = (
Error as {
captureStackTrace?: (
targetObject: object,
constructorOpt?: Function,
) => void
}
).captureStackTrace
// `Error.prepareStackTrace` — invoked by V8 when `error.stack` is first
// read. Captured at load time so we have the engine default even if
// user code later overwrites it (some libraries clobber this for
// source-map remapping). Setter not exposed — assigning to the
// primordial wouldn't affect V8's lookup, which always reads
// `Error.prepareStackTrace` fresh.
export const ErrorPrepareStackTrace:
| ((error: Error, structuredStackTrace: NodeJS.CallSite[]) => unknown)
| undefined = (
Error as {
prepareStackTrace?: (
error: Error,
structuredStackTrace: NodeJS.CallSite[],
) => unknown
}
).prepareStackTrace
// `Error.stackTraceLimit` — max frames V8 captures per stack. May be a
// data property (today on Node) or an accessor (some bundler shims).
// Returning a function avoids capturing a stale snapshot — callers that
// need the live value invoke `ErrorStackTraceLimit()` and get whatever
// V8 currently reports.
//
// `__lookupGetter__` is "annex B legacy" but supported in V8 / SpiderMonkey
// / JavaScriptCore. We probe it once at load time and fall back to
// reading the data property if no accessor exists.
const _stackTraceLimitGetter: (() => number) | undefined = (() => {
const getter = (
Error as unknown as {
__lookupGetter__?: (key: string) => (() => number) | undefined
}
).__lookupGetter__?.('stackTraceLimit')
if (typeof getter === 'function') {
return () => getter.call(Error)
}
return undefined
})()
export function ErrorStackTraceLimit(): number | undefined {
if (_stackTraceLimitGetter) {
return _stackTraceLimitGetter()
}
return (Error as { stackTraceLimit?: number }).stackTraceLimit
}
// ─── Function ──────────────────────────────────────────────────────────
export const FunctionPrototypeApply = uncurryThis(Function.prototype.apply) as (
self: (...args: unknown[]) => unknown,
thisArg: unknown,
args: unknown[],
) => unknown
export const FunctionPrototypeBind = uncurryThis(Function.prototype.bind) as (
self: (...args: unknown[]) => unknown,
thisArg: unknown,
...args: unknown[]
) => (...args: unknown[]) => unknown
export const FunctionPrototypeCall = uncurryThis(Function.prototype.call) as (
self: (...args: unknown[]) => unknown,
thisArg: unknown,
...args: unknown[]
) => unknown
export const FunctionPrototypeToString = uncurryThis(
Function.prototype.toString,
) as (self: (...args: unknown[]) => unknown) => string
// ─── Iterator (prototype) ──────────────────────────────────────────────
// Map#keys() / Set#values() / etc. share an iterator prototype chain.
// In some engines `.next` lives on the immediate prototype; in others it
// lives on a shared ancestor. Walk up until we find the level that owns
// the method so `uncurryThis` grabs the same one regardless of engine.
const _anyIterator = new Map().keys() as Iterator<unknown>
let _iteratorLookup: object | null = Object.getPrototypeOf(_anyIterator)
while (
_iteratorLookup &&
typeof (_iteratorLookup as { next?: unknown }).next !== 'function'
) {
_iteratorLookup = Object.getPrototypeOf(_iteratorLookup)
}
const _iteratorProto = _iteratorLookup as {
next: (this: Iterator<unknown>) => IteratorResult<unknown>
return?: (this: Iterator<unknown>, value?: unknown) => IteratorResult<unknown>
}
export const IteratorPrototypeNext = uncurryThis(_iteratorProto.next)
export const IteratorPrototypeReturn =
typeof _iteratorProto.return === 'function'
? uncurryThis(_iteratorProto.return)
: undefined
// ─── Map (prototype) ───────────────────────────────────────────────────
export const MapPrototypeClear = uncurryThis(Map.prototype.clear)
export const MapPrototypeDelete = uncurryThis(Map.prototype.delete)
export const MapPrototypeEntries = uncurryThis(Map.prototype.entries)
export const MapPrototypeForEach = uncurryThis(Map.prototype.forEach)
export const MapPrototypeGet = uncurryThis(Map.prototype.get)
export const MapPrototypeHas = uncurryThis(Map.prototype.has)
export const MapPrototypeKeys = uncurryThis(Map.prototype.keys)
export const MapPrototypeSet = uncurryThis(Map.prototype.set)
export const MapPrototypeValues = uncurryThis(Map.prototype.values)
// ─── Math (constants) ──────────────────────────────────────────────────
export const MathE = Math.E
export const MathLN2 = Math.LN2
export const MathLN10 = Math.LN10
export const MathLOG2E = Math.LOG2E
export const MathLOG10E = Math.LOG10E
export const MathPI = Math.PI
export const MathSQRT1_2 = Math.SQRT1_2
export const MathSQRT2 = Math.SQRT2
// ─── Math (methods) ────────────────────────────────────────────────────
// Each entry prefers `_smolPrimordial.mathX` when running on the smol
// Node binary (V8 Fast API typed implementation, TurboFan-inlinable),
// falling back to `Math.x` on stock Node + non-Node runtimes. Math
// constants don't get fast-pathed (no benefit — they're already
// pre-computed scalar values).
export const MathAbs = _smolPrimordial?.mathAbs ?? Math.abs
export const MathAcos = _smolPrimordial?.mathAcos ?? Math.acos
export const MathAcosh = _smolPrimordial?.mathAcosh ?? Math.acosh
export const MathAsin = _smolPrimordial?.mathAsin ?? Math.asin
export const MathAsinh = _smolPrimordial?.mathAsinh ?? Math.asinh
export const MathAtan = _smolPrimordial?.mathAtan ?? Math.atan
export const MathAtan2 = _smolPrimordial?.mathAtan2 ?? Math.atan2
export const MathAtanh = _smolPrimordial?.mathAtanh ?? Math.atanh
export const MathCbrt = _smolPrimordial?.mathCbrt ?? Math.cbrt
export const MathCeil = _smolPrimordial?.mathCeil ?? Math.ceil
export const MathClz32 = _smolPrimordial?.mathClz32 ?? Math.clz32
export const MathCos = _smolPrimordial?.mathCos ?? Math.cos
export const MathCosh = _smolPrimordial?.mathCosh ?? Math.cosh
export const MathExp = _smolPrimordial?.mathExp ?? Math.exp
export const MathExpm1 = _smolPrimordial?.mathExpm1 ?? Math.expm1
// `Math.f16round` is ES2025 (Node 22+ / V8 12.x). Older engines lack
// it; the runtime check keeps us undefined-safe instead of crashing
// at import time. No smol fast-path yet (would need a separate ES2025
// type signature in the binding).
export const MathF16round: ((value: number) => number) | undefined = (
Math as { f16round?: (value: number) => number }
).f16round
export const MathFloor = _smolPrimordial?.mathFloor ?? Math.floor
export const MathFround = _smolPrimordial?.mathFround ?? Math.fround
export const MathHypot = _smolPrimordial?.mathHypot ?? Math.hypot
export const MathImul = _smolPrimordial?.mathImul ?? Math.imul
export const MathLog = _smolPrimordial?.mathLog ?? Math.log
export const MathLog1p = _smolPrimordial?.mathLog1p ?? Math.log1p
export const MathLog2 = _smolPrimordial?.mathLog2 ?? Math.log2
export const MathLog10 = _smolPrimordial?.mathLog10 ?? Math.log10
// Math.max / Math.min are variadic. The smol fast path only specializes
// the 2-arg case at the C++ level; variadic callers fall back to
// Math.max/min anyway via V8's slow-path machinery. Stick with the
// stock builtins here — they're already V8-inlined for the common 2-arg
// case via type feedback.
export const MathMax = Math.max
export const MathMin = Math.min
export const MathPow = _smolPrimordial?.mathPow ?? Math.pow
// Math.random doesn't fit a fast-path shape (no args, side-effecting
// PRNG state). Stock builtin is already V8-inlined.
export const MathRandom = Math.random
export const MathRound = _smolPrimordial?.mathRound ?? Math.round
export const MathSign = _smolPrimordial?.mathSign ?? Math.sign
export const MathSin = _smolPrimordial?.mathSin ?? Math.sin
export const MathSinh = _smolPrimordial?.mathSinh ?? Math.sinh
export const MathSqrt = _smolPrimordial?.mathSqrt ?? Math.sqrt
export const MathTan = _smolPrimordial?.mathTan ?? Math.tan
export const MathTanh = _smolPrimordial?.mathTanh ?? Math.tanh
export const MathTrunc = _smolPrimordial?.mathTrunc ?? Math.trunc
// ─── Number (constants) ────────────────────────────────────────────────
export const NumberEPSILON = Number.EPSILON
export const NumberMAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER
export const NumberMAX_VALUE = Number.MAX_VALUE
export const NumberMIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER
export const NumberMIN_VALUE = Number.MIN_VALUE
export const NumberNEGATIVE_INFINITY = Number.NEGATIVE_INFINITY
export const NumberPOSITIVE_INFINITY = Number.POSITIVE_INFINITY
// ─── Number (methods) ──────────────────────────────────────────────────
// Predicates prefer the smol fast-path; static parse* keep the stock
// builtins (their fast paths require Local<String> handling, deferred
// to a future binding extension).
export const NumberIsFinite = _smolPrimordial?.numberIsFinite ?? Number.isFinite
export const NumberIsInteger =
_smolPrimordial?.numberIsInteger ?? Number.isInteger
export const NumberIsNaN = _smolPrimordial?.numberIsNaN ?? Number.isNaN
export const NumberIsSafeInteger =
_smolPrimordial?.numberIsSafeInteger ?? Number.isSafeInteger
// `numberParseFloat` and `numberParseInt10` are FastOneByteString-typed
// bindings — V8 only invokes the C++ fast path when the input string
// is sequential one-byte (ASCII). Two-byte strings, BigInt-as-string,
// etc. fall through to the slow path automatically. parseInt is
// specialized to radix 10 because every parseInt site in this repo
// (and in socket-cli) uses `parseInt(s, 10)`. The wrapper below
// preserves the "missing radix" and "radix !== 10" cases by routing
// to stock Number.parseInt — only radix 10 (or omitted) hits the
// Fast API path.
export const NumberParseFloat =
_smolPrimordial?.numberParseFloat ?? Number.parseFloat
const _smolParseInt10 = _smolPrimordial?.numberParseInt10
export const NumberParseInt: typeof Number.parseInt = _smolParseInt10
? (s, radix) =>
radix === undefined || radix === 10
? _smolParseInt10(s as string)
: Number.parseInt(s, radix)
: Number.parseInt
export const NumberPrototypeToFixed = uncurryThis(Number.prototype.toFixed)
export const NumberPrototypeToString = uncurryThis(Number.prototype.toString)
// ─── Object (static) ───────────────────────────────────────────────────
export const ObjectAssign = Object.assign
export const ObjectCreate = Object.create
export const ObjectDefineProperties = Object.defineProperties
export const ObjectDefineProperty = Object.defineProperty
export const ObjectEntries = Object.entries
export const ObjectFreeze = Object.freeze
export const ObjectFromEntries = Object.fromEntries
export const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor
export const ObjectGetOwnPropertyDescriptors = Object.getOwnPropertyDescriptors
export const ObjectGetOwnPropertyNames = Object.getOwnPropertyNames
export const ObjectGetOwnPropertySymbols = Object.getOwnPropertySymbols
export const ObjectGetPrototypeOf = Object.getPrototypeOf
export const ObjectHasOwn = Object.hasOwn
export const ObjectIs = Object.is
export const ObjectIsExtensible = Object.isExtensible
export const ObjectIsFrozen = Object.isFrozen
export const ObjectIsSealed = Object.isSealed
export const ObjectKeys = Object.keys
export const ObjectPreventExtensions = Object.preventExtensions
export const ObjectSeal = Object.seal
export const ObjectSetPrototypeOf = Object.setPrototypeOf
export const ObjectValues = Object.values
// ─── Object (prototype) ────────────────────────────────────────────────
export const ObjectPrototype = Object.prototype
export const ObjectPrototypeHasOwnProperty = uncurryThis(
Object.prototype.hasOwnProperty,
)
export const ObjectPrototypeIsPrototypeOf = uncurryThis(
Object.prototype.isPrototypeOf,
)
export const ObjectPrototypePropertyIsEnumerable = uncurryThis(
Object.prototype.propertyIsEnumerable,
)
export const ObjectPrototypeToString = uncurryThis(Object.prototype.toString)
export const ObjectPrototypeValueOf = uncurryThis(Object.prototype.valueOf)
// Annex B legacy accessor methods. Spec'd as "normative optional" but
// implemented in every major engine (V8, SpiderMonkey, JavaScriptCore).
// Equivalent to Object.defineProperty / Object.getOwnPropertyDescriptor
// but operate on a target's prototype chain rather than its own props,
// which is occasionally what you actually want (e.g. probing whether
// a class defines a getter without instantiating).
//
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/__lookupGetter__
const _objectProto = Object.prototype as unknown as {
__defineGetter__: (this: object, key: PropertyKey, fn: () => unknown) => void
__defineSetter__: (
this: object,
key: PropertyKey,
fn: (value: unknown) => void,
) => void
__lookupGetter__: (
this: object,
key: PropertyKey,
) => (() => unknown) | undefined
__lookupSetter__: (
this: object,
key: PropertyKey,
) => ((value: unknown) => void) | undefined
}
export const ObjectPrototypeDefineGetter = uncurryThis(
_objectProto.__defineGetter__,
)
export const ObjectPrototypeDefineSetter = uncurryThis(
_objectProto.__defineSetter__,
)
export const ObjectPrototypeLookupGetter = uncurryThis(
_objectProto.__lookupGetter__,
)
export const ObjectPrototypeLookupSetter = uncurryThis(
_objectProto.__lookupSetter__,
)
// ─── Promise (static) ──────────────────────────────────────────────────
export const PromiseAll = Promise.all.bind(Promise)
export const PromiseAllSettled = Promise.allSettled.bind(Promise)
export const PromiseAny = Promise.any.bind(Promise)
export const PromiseRace = Promise.race.bind(Promise)
export const PromiseReject = Promise.reject.bind(Promise)
export const PromiseResolve = Promise.resolve.bind(Promise)
// `Promise.withResolvers` is ES2024 (Node 22.0+). Typed as
// `Function | undefined` for safety even though Node 22+ always has it.
export const PromiseWithResolvers: typeof Promise.withResolvers | undefined = (
Promise as { withResolvers?: typeof Promise.withResolvers }
).withResolvers?.bind(Promise) as typeof Promise.withResolvers | undefined
// ─── Promise (prototype) ───────────────────────────────────────────────
export const PromisePrototypeCatch = uncurryThis(Promise.prototype.catch)
export const PromisePrototypeFinally = uncurryThis(Promise.prototype.finally)
export const PromisePrototypeThen = uncurryThis(Promise.prototype.then)
// ─── Reflect ───────────────────────────────────────────────────────────
export const ReflectApply = Reflect.apply
export const ReflectConstruct = Reflect.construct
export const ReflectDefineProperty = Reflect.defineProperty
export const ReflectDeleteProperty = Reflect.deleteProperty
export const ReflectGet = Reflect.get
export const ReflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor
export const ReflectGetPrototypeOf = Reflect.getPrototypeOf
export const ReflectHas = Reflect.has
export const ReflectIsExtensible = Reflect.isExtensible
export const ReflectOwnKeys = Reflect.ownKeys
export const ReflectPreventExtensions = Reflect.preventExtensions
export const ReflectSet = Reflect.set
export const ReflectSetPrototypeOf = Reflect.setPrototypeOf
// ─── RegExp (static) ───────────────────────────────────────────────────
// `RegExp.escape` is ES2025 (Node 22.18+). Typed `Function | undefined`
// for safety even though Node 22.18+ always has it. Callers needing a
// portable shape should null-check.
export const RegExpEscape: ((s: string) => string) | undefined = (
RegExp as { escape?: (s: string) => string }
).escape
// ─── RegExp (prototype) ────────────────────────────────────────────────
export const RegExpPrototypeExec = uncurryThis(RegExp.prototype.exec)
export const RegExpPrototypeTest = uncurryThis(RegExp.prototype.test)
export const RegExpPrototypeSymbolMatch = uncurryThis(
RegExp.prototype[Symbol.match] as (this: RegExp, str: string) => unknown,
)
export const RegExpPrototypeSymbolReplace = uncurryThis(
RegExp.prototype[Symbol.replace] as (
this: RegExp,
str: string,
replaceValue: string,
) => string,
)
// ─── Set (prototype) ───────────────────────────────────────────────────
export const SetPrototypeAdd = uncurryThis(Set.prototype.add)
export const SetPrototypeClear = uncurryThis(Set.prototype.clear)
export const SetPrototypeDelete = uncurryThis(Set.prototype.delete)
export const SetPrototypeEntries = uncurryThis(Set.prototype.entries)
export const SetPrototypeForEach = uncurryThis(Set.prototype.forEach)
export const SetPrototypeHas = uncurryThis(Set.prototype.has)
export const SetPrototypeKeys = uncurryThis(Set.prototype.keys)
export const SetPrototypeValues = uncurryThis(Set.prototype.values)
// ─── String (static) ───────────────────────────────────────────────────
export const StringFromCharCode = String.fromCharCode
export const StringFromCodePoint = String.fromCodePoint
export const StringRaw = String.raw
// ─── String (prototype) ────────────────────────────────────────────────
export const StringPrototypeAt = uncurryThis(String.prototype.at)
export const StringPrototypeCharAt = uncurryThis(String.prototype.charAt)
// `stringCharCodeAt` is a Fast API binding with a FastOneByteString
// receiver — V8 only invokes the C++ fast path for ASCII strings,
// where it does a single byte load. Two-byte strings fall back.
// The fast path returns -1 for OOB indices (Fast API can't return
// NaN from an int32 signature); the wrapper here translates -1 back
// to NaN to match `String.prototype.charCodeAt` spec.
const _smolCharCodeAt = _smolPrimordial?.stringCharCodeAt
export const StringPrototypeCharCodeAt: (s: string, i: number) => number =
_smolCharCodeAt
? (s, i) => {
const code = _smolCharCodeAt(s, i)
return code === -1 ? NaN : code
}
: uncurryThis(String.prototype.charCodeAt)
export const StringPrototypeCodePointAt = uncurryThis(
String.prototype.codePointAt,
)
export const StringPrototypeConcat = uncurryThis(String.prototype.concat) as (
self: string,
...strs: string[]
) => string
export const StringPrototypeEndsWith = uncurryThis(String.prototype.endsWith)
export const StringPrototypeIncludes = uncurryThis(String.prototype.includes)
export const StringPrototypeIndexOf = uncurryThis(String.prototype.indexOf)
export const StringPrototypeLastIndexOf = uncurryThis(
String.prototype.lastIndexOf,
)
export const StringPrototypeLocaleCompare = uncurryThis(
String.prototype.localeCompare,
)
export const StringPrototypeMatch = uncurryThis(
String.prototype.match as (
this: string,
matcher: string | RegExp,
) => RegExpMatchArray | null,
)
export const StringPrototypeMatchAll = uncurryThis(
String.prototype.matchAll as (
this: string,
matcher: RegExp | string,
) => IterableIterator<RegExpMatchArray>,
)
export const StringPrototypeNormalize = uncurryThis(String.prototype.normalize)
export const StringPrototypePadEnd = uncurryThis(String.prototype.padEnd)
export const StringPrototypePadStart = uncurryThis(String.prototype.padStart)
export const StringPrototypeRepeat = uncurryThis(String.prototype.repeat)
export const StringPrototypeReplace = uncurryThis(
String.prototype.replace as (
this: string,
searchValue: string | RegExp,
replaceValue: string | ((substring: string, ...args: any[]) => string),
) => string,
)
export const StringPrototypeReplaceAll = uncurryThis(
String.prototype.replaceAll as (
this: string,
searchValue: string | RegExp,
replaceValue: string | ((substring: string, ...args: any[]) => string),
) => string,
)
export const StringPrototypeSearch = uncurryThis(String.prototype.search)
export const StringPrototypeSlice = uncurryThis(String.prototype.slice)
export const StringPrototypeSplit = uncurryThis(String.prototype.split) as (
self: string,
separator: string | RegExp,
limit?: number,
) => string[]
export const StringPrototypeStartsWith = uncurryThis(
String.prototype.startsWith,
)
export const StringPrototypeSubstring = uncurryThis(String.prototype.substring)
export const StringPrototypeToLocaleLowerCase = uncurryThis(
String.prototype.toLocaleLowerCase,
)
export const StringPrototypeToLocaleUpperCase = uncurryThis(
String.prototype.toLocaleUpperCase,
)
export const StringPrototypeToLowerCase = uncurryThis(
String.prototype.toLowerCase,
)
export const StringPrototypeToUpperCase = uncurryThis(
String.prototype.toUpperCase,
)
export const StringPrototypeTrim = uncurryThis(String.prototype.trim)
export const StringPrototypeTrimEnd = uncurryThis(String.prototype.trimEnd)
export const StringPrototypeTrimStart = uncurryThis(String.prototype.trimStart)
// ─── Symbol ────────────────────────────────────────────────────────────
// `Symbol.asyncDispose` and `Symbol.dispose` are ES2024 (Node 20.4+).
// Older engines lack them; use `| undefined` so importers don't crash
// at load time.
export const SymbolAsyncDispose: typeof Symbol.asyncDispose | undefined = (
Symbol as { asyncDispose?: typeof Symbol.asyncDispose }
).asyncDispose
export const SymbolAsyncIterator = Symbol.asyncIterator
export const SymbolDispose: typeof Symbol.dispose | undefined = (
Symbol as { dispose?: typeof Symbol.dispose }
).dispose
export const SymbolFor = Symbol.for
export const SymbolHasInstance = Symbol.hasInstance
export const SymbolIsConcatSpreadable = Symbol.isConcatSpreadable
export const SymbolIterator = Symbol.iterator
export const SymbolKeyFor = Symbol.keyFor
export const SymbolMatch = Symbol.match
export const SymbolMatchAll = Symbol.matchAll
export const SymbolReplace = Symbol.replace
export const SymbolSearch = Symbol.search
export const SymbolSpecies = Symbol.species
export const SymbolSplit = Symbol.split
export const SymbolToPrimitive = Symbol.toPrimitive
export const SymbolToStringTag = Symbol.toStringTag
export const SymbolUnscopables = Symbol.unscopables
// `description` is an accessor on `Symbol.prototype`, not a method.
// `__lookupGetter__` resolves it cleanly across engines without
// touching the live property descriptor.
const _symbolDescriptionGetter = (
Symbol.prototype as unknown as {
__lookupGetter__: (key: string) => (() => string | undefined) | undefined
}
).__lookupGetter__('description')
export function SymbolPrototypeDescription(self: symbol): string | undefined {
return _symbolDescriptionGetter
? _symbolDescriptionGetter.call(self)
: self.description
}
export const SymbolPrototypeToString = uncurryThis(Symbol.prototype.toString)
export const SymbolPrototypeValueOf = uncurryThis(Symbol.prototype.valueOf) as (
self: symbol,
) => symbol
// ─── URLSearchParams (prototype) ───────────────────────────────────────
export const URLSearchParamsPrototypeAppend = uncurryThis(
URLSearchParams.prototype.append,
)
export const URLSearchParamsPrototypeDelete = uncurryThis(
URLSearchParams.prototype.delete,
)
export const URLSearchParamsPrototypeForEach = uncurryThis(
URLSearchParams.prototype.forEach,
)
export const URLSearchParamsPrototypeGet = uncurryThis(
URLSearchParams.prototype.get,
)
export const URLSearchParamsPrototypeGetAll = uncurryThis(
URLSearchParams.prototype.getAll,
)
export const URLSearchParamsPrototypeHas = uncurryThis(
URLSearchParams.prototype.has,
)
export const URLSearchParamsPrototypeSet = uncurryThis(
URLSearchParams.prototype.set,
)
// ─── WeakMap (prototype) ───────────────────────────────────────────────
export const WeakMapPrototypeDelete = uncurryThis(WeakMap.prototype.delete)
export const WeakMapPrototypeGet = uncurryThis(WeakMap.prototype.get)
export const WeakMapPrototypeHas = uncurryThis(WeakMap.prototype.has)
export const WeakMapPrototypeSet = uncurryThis(WeakMap.prototype.set)
// ─── WeakSet (prototype) ───────────────────────────────────────────────
export const WeakSetPrototypeAdd = uncurryThis(WeakSet.prototype.add)
export const WeakSetPrototypeDelete = uncurryThis(WeakSet.prototype.delete)
export const WeakSetPrototypeHas = uncurryThis(WeakSet.prototype.has)