Fedify currently uses Temporal extensively, while supporting runtimes where Temporal is not yet universally available. To support Bun and older supported Node.js versions, Fedify depends on @js-temporal/polyfill.
This has become increasingly awkward now that modern runtimes and TypeScript have native Temporal declarations. In particular, the types exported by @js-temporal/polyfill are distinct from the ambient Temporal namespace provided by TypeScript's lib.esnext.temporal.d.ts. This can lead to nominal/structural incompatibilities between values created by the polyfill and APIs typed against ambient Temporal types.
Fedify already added @fedify/vocab-runtime/temporal and switched several public declarations toward ambient Temporal types to reduce this problem, but the current setup still leaves room for type mismatches.
There is another Temporal polyfill, temporal-polyfill, which appears to be designed around TypeScript's native Temporal declarations. It re-exports types from temporal-spec, which is derived from TypeScript's Temporal lib declarations, and its default entrypoint prefers the host's native Temporal implementation when available.
A quick investigation suggests this may fit Fedify's direction better than @js-temporal/polyfill.
Relevant observations:
@js-temporal/polyfill values are not directly assignable to ambient Temporal.Duration/Temporal.Instant under TypeScript 6.0's Temporal lib declarations. For example, Duration.round() and Instant.until() signatures differ.
temporal-polyfill values are assignable to ambient Temporal types when using bundler-style module resolution.
temporal-polyfill works in Deno via npm:temporal-polyfill@1.0.1.
temporal-polyfill works in Bun via ESM import, and Bun currently still needs a polyfill because globalThis.Temporal is not available there.
temporal-polyfill is currently ESM-only from the package export-map perspective. require("temporal-polyfill") fails because the package does not expose a require, module-sync, or default condition for the root export.
- Fedify currently emits CJS builds that synchronously inject Temporal via
require("@js-temporal/polyfill"), so a direct replacement would break CJS builds.
Because of the CJS issue, this should not be a simple dependency rename. A safer direction may be:
- Replace ESM/Deno Temporal imports with
temporal-polyfill.
- For CJS builds, bundle
temporal-polyfill into the emitted output instead of leaving require("temporal-polyfill") as an external dependency.
- Keep
@fedify/vocab-runtime/temporal guards, since Fedify should continue accepting Temporal values from native implementations, @js-temporal/polyfill, temporal-polyfill, and other spec-conformant implementations.
- Add cross-runtime tests covering Node.js, Bun, and Deno.
- Add consumer type tests for at least
moduleResolution: "Bundler" and moduleResolution: "NodeNext".
Things to verify before making the switch:
- CJS output runs on the minimum supported Node.js version.
- ESM output runs on Node.js 22+, Node.js 26+, Deno, and Bun.
- Declarations do not leak
temporal-polyfill-specific types.
- APIs accepting
Temporal.Duration, Temporal.DurationLike, Temporal.Instant, and generated vocabulary date/duration fields continue to type-check with native Temporal values.
- Task payload serialization/deserialization continues to round-trip Temporal values through
devalue.
- Behavior remains compatible for malformed date/time and duration parsing, especially where Fedify currently relies on
Temporal.Instant.from() and Temporal.Duration.from() throwing RangeError.
- Documentation and changelog entries clearly explain that Fedify uses native Temporal where available and a polyfill where needed.
This issue is for investigating and, if feasible, replacing @js-temporal/polyfill with temporal-polyfill in a way that reduces Temporal type conflicts without regressing Fedify's supported runtime matrix.
Fedify currently uses Temporal extensively, while supporting runtimes where Temporal is not yet universally available. To support Bun and older supported Node.js versions, Fedify depends on
@js-temporal/polyfill.This has become increasingly awkward now that modern runtimes and TypeScript have native Temporal declarations. In particular, the types exported by
@js-temporal/polyfillare distinct from the ambientTemporalnamespace provided by TypeScript'slib.esnext.temporal.d.ts. This can lead to nominal/structural incompatibilities between values created by the polyfill and APIs typed against ambient Temporal types.Fedify already added
@fedify/vocab-runtime/temporaland switched several public declarations toward ambientTemporaltypes to reduce this problem, but the current setup still leaves room for type mismatches.There is another Temporal polyfill,
temporal-polyfill, which appears to be designed around TypeScript's native Temporal declarations. It re-exports types fromtemporal-spec, which is derived from TypeScript's Temporal lib declarations, and its default entrypoint prefers the host's nativeTemporalimplementation when available.A quick investigation suggests this may fit Fedify's direction better than
@js-temporal/polyfill.Relevant observations:
@js-temporal/polyfillvalues are not directly assignable to ambientTemporal.Duration/Temporal.Instantunder TypeScript 6.0's Temporal lib declarations. For example,Duration.round()andInstant.until()signatures differ.temporal-polyfillvalues are assignable to ambientTemporaltypes when using bundler-style module resolution.temporal-polyfillworks in Deno vianpm:temporal-polyfill@1.0.1.temporal-polyfillworks in Bun via ESM import, and Bun currently still needs a polyfill becauseglobalThis.Temporalis not available there.temporal-polyfillis currently ESM-only from the package export-map perspective.require("temporal-polyfill")fails because the package does not expose arequire,module-sync, ordefaultcondition for the root export.require("@js-temporal/polyfill"), so a direct replacement would break CJS builds.Because of the CJS issue, this should not be a simple dependency rename. A safer direction may be:
temporal-polyfill.temporal-polyfillinto the emitted output instead of leavingrequire("temporal-polyfill")as an external dependency.@fedify/vocab-runtime/temporalguards, since Fedify should continue accepting Temporal values from native implementations,@js-temporal/polyfill,temporal-polyfill, and other spec-conformant implementations.moduleResolution: "Bundler"andmoduleResolution: "NodeNext".Things to verify before making the switch:
temporal-polyfill-specific types.Temporal.Duration,Temporal.DurationLike,Temporal.Instant, and generated vocabulary date/duration fields continue to type-check with native Temporal values.devalue.Temporal.Instant.from()andTemporal.Duration.from()throwingRangeError.This issue is for investigating and, if feasible, replacing
@js-temporal/polyfillwithtemporal-polyfillin a way that reduces Temporal type conflicts without regressing Fedify's supported runtime matrix.