00:30
<joyee>
I am fairly certain ESM in Node.js just isn’t optimized enough because even require(esm) was 1.2x faster than import esm when it came out 🤷‍♀️
15:06
<Ryan Cavanaugh>
TCQ isn't showing a Queue for me
15:06
<Ryan Cavanaugh>
oh, because the tab is too narrow. nm
15:08
<Jesse>
I'll add this to the agenda, but here are Ben's slides for the amount continuation: https://notes.igalia.com/p/2025-09-tc39-plenary-amount-continuation#/
15:10
<bakkot>
Ryan Cavanaugh: can you comment on https://github.com/tc39/notes/pull/382
15:10
<bakkot>
we don't have an alias for you in the notes yet
15:11
<Ryan Cavanaugh>
Yeah I approved that earlier
15:11
<bakkot>
sorry, I mean, Rob had a comment about the choice of alias
15:11
<Ryan Cavanaugh>
oh
15:12
<Ryan Cavanaugh>
done thanks
15:13
<Ashley Claymore>
I've been wondering. Was the J a middle name? My money's on 'John'?
15:14
<Ryan Cavanaugh>
yep
15:15
<nicolo-ribaudo>
Missed opportunity for your parents to call you Ryan JavaScript Cavanaugh
15:16
<kriskowal>
I am just going to say that technicalities did not stop Kim Dot Com.
15:22
<keith_miller>
Where can I find the HTML amount proposal?
15:26
<bakkot>
"there's a unit on the end so you need to strip out the unit before converting to a string" hahaha if only our parseFloat actually worked like that
15:26
<Ryan Cavanaugh>
Making a unit called "e3" just for funsies
15:27
<Chris de Almeida>
there is no such proposal AFAIK
15:31
<keith_miller>
Oh maybe I misunderstood. Is there a an HML amount that's going to proposed? What was the context here?
15:31
<bakkot>
it was definitely good that BigInt was correctly pigeonholed by the name, people adopting it as a generic Integer would have been much much worse
15:33
<ljharb>
that's fair, but since then we got complaints about a lack of adoption, perhaps we shouldn't have added it at all
15:34
<bakkot>
Lack of adoption was because the use cases it was for didn't actually end up happening that much, not because of the name
15:34
<bakkot>
engines would not have been happier if people started using it for the things they're currently doing, that would be worse
15:34
<ljharb>
i'll agree it's not the best example here
15:34
<nicolo-ribaudo>
https://github.com/mozilla/explainers/blob/main/amount.md
15:35
<bakkot>
(that said, it is extremely useful for wasm interop so I'm still very glad we have it.)
15:35
<nicolo-ribaudo>
Right now the idea is that you hover over it, and it shows a localized popup
15:35
<nicolo-ribaudo>
Kind of like <span title=...>...</span>
15:36
<James M Snell>
that's fair, but since then we got complaints about a lack of adoption, perhaps we shouldn't have added it at all
Eh, even with minimal adoption it's still a good primitive to have available. For the use cases it is used for it's very useful
15:36
<Ryan Cavanaugh>
It seems like you would only ever construct an Amount right before formatting a number
15:36
<nicolo-ribaudo>
No, as soon as you want to add information to that number, so that you pass them around as a single "thing"
15:37
<ljharb>
that's also fine. but browsers have blocked decimal primitives (and record and tuple primitives) because bigint didn't get enough adoption
15:37
<nicolo-ribaudo>
If it's right before, you can just pass the number to Intl as-is
15:37
<bakkot>
oh jeeze the idea of people using this for representing JSON output from other languages which can represent values not representable by double or BigInt is... not appealing to me
15:38
<Ryan Cavanaugh>
How do you write code that handles an arbitrary Amount?
15:39
<nicolo-ribaudo>
Mostly passes it around as-is, as an opaque set of information
15:40
<James M Snell>
that's also fine. but browsers have blocked decimal primitives (and record and tuple primitives) because bigint didn't get enough adoption
For decimal I can see that argument. Blocking things like record/tuple because of bigint adoption is like saying we won't sell oranges because no one eats the apples
15:41
<Ryan Cavanaugh>
We already have a type that represents a value with an encoded number of significant digits and unit which you shouldn't do math on, it's string. Unless this can be sent natively over the wire it doesn't even help the case where you have a server "Amount" that the client should render in its own locale
15:41
<ljharb>
that type represents many other things too tho, this would basically be a structured subset of what strings can do
15:42
<Ryan Cavanaugh>
The "other things" are what though?
15:42
<James M Snell>
But even decimal and bigint serve a sufficiently different use cases from each other that even that argument is tenuous. There are more use cases for decimal than bigint. I'm far less convinced about Amount
15:42
<ljharb>
prose/poetry, bytes, anything that's not a value?
15:43
<Ryan Cavanaugh>
oh I thought "that type" referred to Amount
15:45
<ljharb>
sorry for the confusion
15:51
<nicolo-ribaudo>

Fwiw even with .toNumber() math is terrible to do.

new Amount(amount1.toNumber() + amount2.toNumber(), {
  unit: amount1.unit,
  fractionDigits: Math.min(amount1.fractionDigits, amount2.fractionDigits)
})

\ + checking that the units match

15:53
<ljharb>
so then why bother removing it
15:54
<nicolo-ribaudo>
That message was directed to those that prefer to remove it. I'm neutral
15:55
<nicolo-ribaudo>
waldemar Do you think we could finish the 0.00&co discussion on GitHub rather than now?
15:58
<Ryan Cavanaugh>

This feels like we're trying to create a new Array type that encodes which delimiter you should use when toStringing it (comma-separated, semicolon-separated, newline-terminated, etc).

That's not a new noun, it's just metadata attached to an existing primitivelike. Combining those into one new object isn't precedented in the language AFAICT?

16:00
<bakkot>
MDN has a page for the duck-type Iterator incidentally: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator
16:05
<eemeli>
One difference cf. the given examples of protocol objects is that Amounts are more likely to persist, i.e. be stored by a user and used in potentially multiplayer places. So if we go that way, should we provide an `isAmount()` function somewhere?
16:05
<ljharb>
i'd prefer yes, but we don't have an "is iterator result" function or "is regexp match object", so there's not much precedent
16:07
<eemeli>
Are either of those commonly stored, or just immediately used?
16:08
<nicolo-ribaudo>
I think there is a difference in that those two things are just a workaround because we don't support multiple return values from functions
16:08
<nicolo-ribaudo>
If we did those two object shapes would not exist
16:08
<nicolo-ribaudo>
But we'd still have this proposal
16:16
<bakkot>
iterables, and to a lesser extent iterators, are very likely to be stored by a user and passed around
16:20
<bakkot>
one difference with iterables is that you often (usually, in fact) want other behavior too when making an iterable, e.g. you're making a Map and it just happens to also be iterable
16:20
<nicolo-ribaudo>
And users very rarely write iterators by hand, we provide utilities/factories for that
16:21
<bakkot>
this is probably less true for Amount. On the other hand, maybe it is not that rare? if you're representing some type of data, you might well want to e.g. provide arithmetic functions for that data.
16:21
<bakkot>
If this is a protocol you might want to implement on other objects, that would be a strong reason not to have a constructor.
16:21
<bakkot>
i'm guessing that is rare though
16:24
<nicolo-ribaudo>
If it was a protocol, do you think there should no built-in utility to make it more reachable? e.g. Number.prototype.toAmount(unit) = return { value: this, unit }, without it being a class
16:25
<bakkot>
return foo.toAmount('kg') is about the same as return { value: foo, unit: 'kg' } IMO, and the latter is easier to learn
16:27
<bakkot>
so, probably no. but this opinion is not strongly held; if there's cases where making it more reachable actually does significantly improve usability I'm open to that
16:28
<eemeli>
To me, `isAmount` seems like a much more important function than `toAmount`, if going the protocol route.
16:28
<bakkot>
I cannot imagine when you would want an isAmount function
16:28
<nicolo-ribaudo>
If we had this being just a protocol, the main reason to have this be very easily reachable is that it needs to be easier for people to create these objects rather than to separately pass the precision and the values to Intl formatters
16:29
<nicolo-ribaudo>
Since that's a common source of bugs
16:30
<eemeli>
I cannot imagine when you would want an isAmount function
How else could I know that a string value of { value } is a numerical string?
16:30
<bakkot>
why do you have a string value of { value } whose provenance is not known to you?
16:43
<eemeli>
why do you have a string value of { value } whose provenance is not known to you?
Because of the interchange uses for Amount, when the value has come from elsewhere and I'd like to retain and represent it in a lossless way.
16:44
<bakkot>
in my experience interchange protocols are always either tagged with types or have out-of-band schemas
16:45
<bakkot>
you're not just taking an arbitrary collection of values and trying to interpret them
16:45
<bakkot>
that doesn't really work
16:58
<bakkot>
ljharb: as far as I am aware you are literally the only person in the world who is of the opinion that the point of having a class in general is that other things can't pretend to be that thing
16:58
<bakkot>
that is a valid opinion but other people aren't generally going to assume that reason without you making the case for it
16:58
<ljharb>
i mean, everything with internal slots and everything with private fields qualifies
16:59
<ljharb>
that's how every builtin in this language works, with a very short list of exceptions
16:59
<bakkot>
there is a massive distinction between "that is how it works" and "that is the point of it"
17:01
<ljharb>
fair enough
17:01
<ljharb>
that's something that comes with "having a class", regardless of hte point
17:01
<ljharb>
if we're not using internal slots at all then there's no point having anything but a plain object, like an iterator result
17:03
<bakkot>
the Iterator class doesn't use internal slots at all and is nevertheless extremely useful
17:06
<ljharb>
fair, it's IteratorHelper that has the internal slots, but iterator's a bit of a special case in lots of ways
17:09
<ljharb>
notably we don't have an IteratorResult class tho, and if there's no internal slots or helper methods, then Amount seems more like that than a stateful iterator
18:04
<bakkot>
ok JS developers do often have lots of dependencies but hundreds of thousands of dependencies is probably not actually a thing
18:08
<Chris de Almeida>
perhaps worth noting, many (most?) are transitive and unshipped
18:08
<bakkot>
transitive I buy, unshipped I don't buy
18:08
<bakkot>
the static analysis developers are using is, unfortunately, still terrible
18:09
<Chris de Almeida>
one of our applications, out of thousands of deps, only like 30 have code that actually end up in the shipped bundle
18:09
<bakkot>
I'm assuming we're only talking about actual deps, not dev deps
18:09
<bakkot>
certainly most dev deps do not end up contributing shipping code, with exception of like babel or webpack
18:13
<Chris de Almeida>
yes, the actual deps. esp when using batteries-included libraries/frameworks, a lot of unused stuff gets shaken out
18:14
<bakkot>
huh, that is very much not my experience
18:15
<keith_miller>
Even if it's only on the order of hundreds, it still seems like an intractable problem to vet all of them for transitive problems.
18:15
<kriskowal>
That was certainly the least opportune moment for Google to insist I reauthenticate.
18:15
<Chris de Almeida>
bold of you to authenticate in the first place
18:17
<keith_miller>
The usefulness of Compartments also seems to depend on frozen globals. Does anyone deploy that at scale with lots of dependencies?
18:18
<Rob Palmer>
I thought V8 had a bunch of optimizations for proxies. Would love to hear for sure if this include JITing across the boundary.
18:21
<rekmarks>
The dependencies can still collude to e.g. exfiltrate data, but preventing single dependencies from exceeding their authority eliminates an entire class of attacks, e.g. the event-stream incident. Compromising multiple dependencies and shepherding them to conduct an attack is a higher bar that makes a practical difference for the security of applications with many dependencies (i.e. the common case).
18:25
<mgaudet>
Yeah -- I appreciate Kris's comment -- particularly the "unknown" aspect;
18:26
<keith_miller>
I guess I'd propose an alternative question. The approach that's becoming increasingly common on the web is that the core web process is assumed to be compromised. Instead privileged things are isolated from the core web process and are hardened much more aggressively. Why is that insufficient or intractable here?
18:27
<rekmarks>
What's the "core web process"?
18:27
<keith_miller>
The rendering process (JS/DOM)
18:28
<bakkot>
because the bank login runs in the core web process
18:28
<bakkot>
inherently
18:28
<Olivier Flückiger>
or even just JS, V8 has a heap sandbox now within the renderer...
18:28
<keith_miller>
I'm saying the same approach in JS. Not at the C++ layer
18:29
<bakkot>
I kind of doubt that you can feasibly move "access to the DOM" out of the root JS process
18:30
<keith_miller>
That's an analogy not what I'm actually proposing for sites. Although one could do it by origin isolating them.
18:31
<mgaudet>
This is just a small factoid, but hints at some of my personal worries: At least in SpiderMonkey we already have "oops wrong realm" objects that we're aware of, but have never fixed because it's been too low in our priority list (usually errors thrown that are from the wrong realm). I say this not yet really having made the conceptual leap from the previous module-global propsal to the current more compartment like one
18:32
<bakkot>
I know at least some engines had some inconsistencies about the realms of iterator result objects at some point, possibly also the realms of promises for certain kinds of async functions
18:33
<bakkot>
which, yes, I have usually avoided adding tests for these because I don't think we should usually care
18:33
<mgaudet>
(And to colour in the rest of my allusion -- if we make mistakes around this, it turns into compartment violation security bug)
18:34
<bakkot>
the current proposal does not involve having separate versions of Error or Promise or anything, so I don't think it ends up really mattering directly
18:34
<bakkot>
it's only Function (and friends) specifically which are different. not even their prototypes, just the ctor itself.
18:34
<bakkot>
the reason this is thought to be OK is because it is assumed that all the intrinsics are frozen (by something)
18:35
<bakkot>
and also that any powerful intrinsics have not been provided to the compartment
18:35
<mgaudet>
That's nice at least. I'll be excited to read the updated readme so I can try to piece it together
18:35
<Ashley Claymore>
Yeah. Language level values like Iterators and RangeError don't change
18:37
<Ashley Claymore>
Compartments: with {} done right
18:43
<bakkot>
I should say part of my previous topic is that wasm is increasingly moving in the direction of exposing information about modules to runtime: https://github.com/WebAssembly/js-types/blob/main/proposals/js-types/Overview.md
18:43
<bakkot>
and this is good and allows you to do lots of useful things
18:48
<kriskowal>
We are very much in favor of also exposing more information on ModuleSource instances, like all the externally visible bindings.
18:49
<kriskowal>
Like, writing a bundler that uses ModuleSource to gather the static transitive dependencies of a module graph would greatly benefit from that analysis. Last updated 3 years ago https://github.com/tc39/proposal-compartments/blob/master/1-static-analysis.md
18:50
<bakkot>
re: LLMs writing attacks: there's also the "just have an LLM do the attack at runtime" approach https://www.anthropic.com/news/detecting-countering-misuse-aug-2025#vibe-hacking-how-cybercriminals-used-claude-code-to-scale-a-data-extortion-operation
18:54
<Chris de Almeida>
link to "w3c amount" ?
18:55
<keith_miller>
You mean https://github.com/mozilla/explainers/blob/main/amount.md?
18:56
<Chris de Almeida>
looks like it
19:03
<Mathieu Hofman>
I think this is really the crux of it. The way I see it, it's mostly adding a "terminating scope" before evaluating code (including modules). We already have all the logic around to evaluate code in an existing scope stack.
19:04
<Bradford Smith>
bakkot: in my personal notes from the very end of the previous Amount continuation I have "KG: In order to maintain invariants, it will be necessary to use internal slots." Did I misunderstand you there? Isn't that a clear indicator that a class is needed?
19:05
<bakkot>
That is a claim WH made, not a position I advocate
19:05
<bakkot>
it is not clear to me which invariants exist or whether consumers actually need to be able to rely on them; my inclination would be to answer the latter question in the negative
19:06
<ljharb>
i am very skeptical that this is good; it can make things about the way you wrote the code be part of your observable API :-/
19:06
<bakkot>
the exports of code is always part of its observable API
19:07
<ljharb>
oh sure, exposing metadata about existing observable things is great!
19:07
<bakkot>
the imports less directly so but they're still pretty observable in practice
19:07
<ljharb>
i'm not super clear on how one would do that (from code, obv you can do it from dev tools etc)
19:07
<bakkot>
and with Compartments as proposed imports would be very observable anyway because there is an importHook
19:08
<ljharb>
that is true, and that is a concern i have for that part of the proposal
19:10
<kriskowal>
There are some funny things about ESM that bindings reflection does need to hide. You can’t just ship the import and export statements, because they entrain too many implementation details. We’ve discussed this pretty hard at Module Harmony.
19:11
<kriskowal>
It also has the downside that you cannot trivially create a proxy for another module by copying all the bindings from a module source to the virtual module source. But, that’s just a reality we have to live with.
19:12
<kriskowal>
(Or not pursue virtual modules sources at all, to be clear, but they’d be useful for CJS migration, for one.)
19:12
<ljharb>
couldn't that be enabled without actually exposing the list? like, provide an opaque identifier that just represents the list
19:14
<waldemar>
An Amount is not like a tuple. When receiving an Amount it would be problematic if the various fields such as digit counts and stored value were inconsistent with each other. So you don't want to do duck typing. There are various other ways to ensure the invariants.
21:09
<Chris de Almeida>
the agenda for the next meeting is available and ready for your topics to be added! 😀 https://github.com/tc39/agendas/blob/main/2025/11.md we currently have ~15 hours of time available