This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory-site.git
The following commit(s) were added to refs/heads/main by this push:
new 644a8a6caf 🔄 synced local 'docs/guide/' with remote 'docs/guide/'
644a8a6caf is described below
commit 644a8a6cafaaef6d06faa82549b4d3b7e96e8ab1
Author: chaokunyang <[email protected]>
AuthorDate: Mon Apr 13 09:10:38 2026 +0000
🔄 synced local 'docs/guide/' with remote 'docs/guide/'
---
docs/guide/javascript/basic-serialization.md | 244 +++++++++++++++++++++++++++
docs/guide/javascript/cross-language.md | 137 +++++++++++++++
docs/guide/javascript/index.md | 164 ++++++++++++++++++
docs/guide/javascript/references.md | 105 ++++++++++++
docs/guide/javascript/schema-evolution.md | 102 +++++++++++
docs/guide/javascript/supported-types.md | 194 +++++++++++++++++++++
docs/guide/javascript/troubleshooting.md | 113 +++++++++++++
docs/guide/javascript/type-registration.md | 217 ++++++++++++++++++++++++
8 files changed, 1276 insertions(+)
diff --git a/docs/guide/javascript/basic-serialization.md
b/docs/guide/javascript/basic-serialization.md
new file mode 100644
index 0000000000..077ba9c541
--- /dev/null
+++ b/docs/guide/javascript/basic-serialization.md
@@ -0,0 +1,244 @@
+---
+title: Basic Serialization
+sidebar_position: 1
+id: basic_serialization
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+This guide covers the core serialization flow in Apache Fory JavaScript.
+
+## Create and Reuse a `Fory` Instance
+
+```ts
+import Fory from "@apache-fory/core";
+
+const fory = new Fory();
+```
+
+Create one instance, register your schemas, and reuse it. A `Fory` instance
caches generated serializers and type metadata, so recreating it for every
request adds unnecessary overhead.
+
+## Define a Schema with `Type.struct`
+
+The most common path is to define a schema and register it.
+
+```ts
+import Fory, { Type } from "@apache-fory/core";
+
+const accountType = Type.struct(
+ { typeName: "example.account" },
+ {
+ id: Type.int64(),
+ owner: Type.string(),
+ active: Type.bool(),
+ nickname: Type.string().setNullable(true),
+ },
+);
+
+const fory = new Fory();
+const { serialize, deserialize } = fory.register(accountType);
+```
+
+## Serialize and Deserialize
+
+```ts
+const bytes = serialize({
+ id: 42n,
+ owner: "Alice",
+ active: true,
+ nickname: null,
+});
+
+const value = deserialize(bytes);
+console.log(value);
+// { id: 42n, owner: 'Alice', active: true, nickname: null }
+```
+
+The returned `bytes` value is a `Uint8Array`/platform buffer and can be sent
over the network or written to storage.
+
+## Root-Level Dynamic Serialization
+
+`Fory` can also serialize dynamic root values without first binding a
schema-specific serializer.
+
+```ts
+const fory = new Fory();
+
+const bytes = fory.serialize(
+ new Map([
+ ["name", "Alice"],
+ ["age", 30],
+ ]),
+);
+
+const value = fory.deserialize(bytes);
+```
+
+This is convenient for dynamic payloads, but explicit schemas are usually
better for stable interfaces and cross-language contracts.
+
+## Primitive Values
+
+```ts
+const fory = new Fory();
+
+fory.deserialize(fory.serialize(true));
+// true
+
+fory.deserialize(fory.serialize("hello"));
+// 'hello'
+
+fory.deserialize(fory.serialize(123));
+// 123
+
+fory.deserialize(fory.serialize(123n));
+// 123n
+
+fory.deserialize(fory.serialize(new Date("2021-10-20T09:13:00Z")));
+// Date
+```
+
+### Number and `bigint` behavior
+
+JavaScript has both `number` and `bigint`, but xlang distinguishes between
32-bit, 64-bit, floating-point, and tagged integer representations. For any
cross-language or long-lived contract, prefer explicit field types in schemas
instead of depending on dynamic root-type inference.
+
+- use `Type.int32()` for 32-bit integers
+- use `Type.int64()` for 64-bit integers and pass `bigint`
+- use `Type.float32()` or `Type.float64()` for floating-point values
+
+Dynamic root serialization is convenient, but the exact heuristic for whether
a value comes back as `number` or `bigint` should not be treated as a stable
API contract.
+
+## Arrays, Maps, and Sets
+
+```ts
+const inventoryType = Type.struct("example.inventory", {
+ tags: Type.array(Type.string()),
+ counts: Type.map(Type.string(), Type.int32()),
+ labels: Type.set(Type.string()),
+});
+
+const fory = new Fory({ ref: true });
+const { serialize, deserialize } = fory.register(inventoryType);
+
+const bytes = serialize({
+ tags: ["hot", "new"],
+ counts: new Map([
+ ["apple", 3],
+ ["pear", 8],
+ ]),
+ labels: new Set(["featured", "seasonal"]),
+});
+
+const value = deserialize(bytes);
+```
+
+## Nested Structs
+
+```ts
+const addressType = Type.struct("example.address", {
+ city: Type.string(),
+ country: Type.string(),
+});
+
+const userType = Type.struct("example.user", {
+ name: Type.string(),
+ address: Type.struct("example.address", {
+ city: Type.string(),
+ country: Type.string(),
+ }),
+});
+
+const fory = new Fory();
+const { serialize, deserialize } = fory.register(userType);
+
+const bytes = serialize({
+ name: "Alice",
+ address: { city: "Hangzhou", country: "CN" },
+});
+
+const user = deserialize(bytes);
+```
+
+If a nested value can be missing, mark it nullable:
+
+```ts
+const wrapperType = Type.struct("example.wrapper", {
+ child: Type.struct("example.child", {
+ name: Type.string(),
+ }).setNullable(true),
+});
+```
+
+## Decorator-Based Registration
+
+TypeScript decorators are also supported.
+
+```ts
+import Fory, { Type } from "@apache-fory/core";
+
[email protected]("example.user")
+class User {
+ @Type.int64()
+ id!: bigint;
+
+ @Type.string()
+ name!: string;
+}
+
+const fory = new Fory();
+const { serialize, deserialize } = fory.register(User);
+
+const user = new User();
+user.id = 1n;
+user.name = "Alice";
+
+const copy = deserialize(serialize(user));
+console.log(copy instanceof User); // true
+```
+
+## Nullability
+
+Field nullability is explicit in schema-based structs.
+
+```ts
+const nullableType = Type.struct("example.optional_user", {
+ name: Type.string(),
+ email: Type.string().setNullable(true),
+});
+```
+
+If a field is not marked nullable and you try to write `null`, serialization
throws.
+
+## Debugging Generated Code
+
+You can inspect generated serializer code with `hooks.afterCodeGenerated`.
+
+```ts
+const fory = new Fory({
+ hooks: {
+ afterCodeGenerated(code) {
+ console.log(code);
+ return code;
+ },
+ },
+});
+```
+
+This is useful when debugging schema behavior, field ordering, or generated
fast paths.
+
+## Related Topics
+
+- [Type Registration](type-registration.md)
+- [Supported Types](supported-types.md)
+- [References](references.md)
diff --git a/docs/guide/javascript/cross-language.md
b/docs/guide/javascript/cross-language.md
new file mode 100644
index 0000000000..06f5c3e2cc
--- /dev/null
+++ b/docs/guide/javascript/cross-language.md
@@ -0,0 +1,137 @@
+---
+title: Cross-Language Serialization
+sidebar_position: 80
+id: cross_language
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Apache Fory JavaScript always uses the xlang wire format. Interoperability
depends on matching schemas and compatible type mappings rather than on
enabling a separate mode switch.
+
+Current limits to keep in mind:
+
+- JavaScript deserializes xlang payloads only
+- out-of-band mode is not currently supported in the JavaScript runtime
+
+## Interop rules
+
+For a payload to round-trip between JavaScript and another runtime:
+
+1. **Register the same logical type identity** on both sides.
+ - same numeric type ID, or
+ - same namespace + type name
+2. **Use compatible field types** according to the [type mapping
spec](../../specification/xlang_type_mapping.md).
+3. **Match nullability and reference-tracking expectations** where object
graphs require them.
+4. **Use compatible mode** when independent schema evolution is expected.
+
+## Interoperability workflow
+
+When wiring JavaScript to another runtime in production code:
+
+1. define the JavaScript schema with the same type identity used by the other
runtime
+2. register the same type name or type ID in every participating runtime
+3. keep field types, nullability, enum layout, and schema-evolution settings
aligned
+4. validate the end-to-end payload before relying on it in a shared contract
+
+Example JavaScript side:
+
+```ts
+import Fory, { Type } from "@apache-fory/core";
+
+const messageType = Type.struct(
+ { typeName: "example.message" },
+ {
+ id: Type.int64(),
+ content: Type.string(),
+ },
+);
+
+const fory = new Fory();
+const { serialize } = fory.register(messageType);
+
+const bytes = serialize({
+ id: 1n,
+ content: "hello from JavaScript",
+});
+```
+
+On the receiving side, register the same `example.message` type identity and
compatible field types using that runtime's public API and guide:
+
+- [Go guide](../go/index.md)
+- [Python guide](../python/index.md)
+- [Java guide](../java/index.md)
+- [Rust guide](../rust/index.md)
+
+## Field naming and ordering
+
+Cross-language matching depends on consistent field identity. When multiple
runtimes model the same struct, use a naming scheme that maps cleanly across
languages.
+
+Practical guidance:
+
+- prefer stable snake_case or clearly corresponding names across runtimes
+- avoid accidental renames without updating every participating runtime
+- use compatible mode when fields may be added or removed over time
+
+## Numeric mapping guidance
+
+JavaScript needs extra care because `number` is IEEE 754 double precision.
+
+- use `Type.int64()` with `bigint` for true 64-bit integers
+- use `Type.float32()` or `Type.float64()` for floating-point fields
+- avoid assuming that a dynamic JavaScript `number` maps cleanly to every
integer width in another language
+
+## Time mapping guidance
+
+- `Type.timestamp()` maps to a point in time and deserializes as `Date`
+- `Type.duration()` should be treated as a duration value, but JavaScript
currently exposes typed duration fields as numeric time values rather than a
dedicated duration class
+- `Type.date()` corresponds to a date-without-timezone type in the
specification and deserializes as `Date`
+
+## Polymorphism and `Type.any()`
+
+Use `Type.any()` only when you genuinely need runtime-dispatched values.
+
+```ts
+const wrapperType = Type.struct(
+ { typeId: 3001 },
+ {
+ payload: Type.any(),
+ },
+);
+```
+
+This works for polymorphic values, but explicit field schemas are easier to
keep aligned across languages.
+
+## Enums
+
+Enums must also be registered consistently across languages.
+
+```ts
+const Color = { Red: 1, Green: 2, Blue: 3 };
+const fory = new Fory();
+fory.register(Type.enum({ typeId: 210 }, Color));
+```
+
+Use the same type ID or type name in Java, Python, Go, and other runtimes.
+
+## Limits and safety
+
+Deserialization guardrails such as `maxDepth`, `maxBinarySize`, and
`maxCollectionSize` are local runtime protections. They do not affect the wire
format, but they can reject payloads that exceed local policy.
+
+## Related Topics
+
+- [Supported Types](supported-types.md)
+- [Schema Evolution](schema-evolution.md)
+- [Xlang Serialization
Specification](../../specification/xlang_serialization_spec.md)
diff --git a/docs/guide/javascript/index.md b/docs/guide/javascript/index.md
new file mode 100644
index 0000000000..c715ad8cf1
--- /dev/null
+++ b/docs/guide/javascript/index.md
@@ -0,0 +1,164 @@
+---
+title: JavaScript Serialization Guide
+sidebar_position: 0
+id: index
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Apache Fory JavaScript provides cross-language serialization for JavaScript
and TypeScript applications. It uses the xlang wire format described in the
[xlang serialization
specification](../../specification/xlang_serialization_spec.md), so it is
designed to interoperate with other Fory runtimes such as Java, Python, Go,
Rust, Swift, and C++.
+
+The JavaScript runtime is schema-driven: you describe your data shape with
`Type.*` builders or TypeScript decorators, register that schema with `Fory`,
and then reuse the returned serializer pair for serialization and
deserialization.
+
+## Why Fory JavaScript?
+
+- **Cross-language by design**: JavaScript uses the xlang wire format and
interoperates with other Fory runtimes.
+- **Generated hot paths**: serializers are generated at runtime and cached per
`Fory` instance.
+- **Reference-aware object graphs**: shared references and circular structures
are supported when enabled.
+- **Explicit schemas**: field types, nullability, dynamic dispatch, and type
identity are declared up front.
+- **Guardrails for untrusted data**: configurable depth, binary size, and
collection size limits help bound deserialization work.
+- **Modern numeric support**: `bigint`, typed arrays, `Map`, `Set`, `Date`,
`float16`, and `bfloat16` are supported.
+
+## Installation
+
+Install the JavaScript packages from npm:
+
+```bash
+npm install @apache-fory/core
+```
+
+Optional Node.js string fast-path support is available through
`@apache-fory/hps`:
+
+```bash
+npm install @apache-fory/core @apache-fory/hps
+```
+
+`@apache-fory/hps` depends on Node.js 20+ and is optional. If it is
unavailable, Fory still works correctly; omit `hps` from the configuration.
+
+## Quick Start
+
+```ts
+import Fory, { Type } from "@apache-fory/core";
+
+const userType = Type.struct(
+ { typeName: "example.user" },
+ {
+ id: Type.int64(),
+ name: Type.string(),
+ age: Type.int32(),
+ },
+);
+
+const fory = new Fory();
+const { serialize, deserialize } = fory.register(userType);
+
+const bytes = serialize({
+ id: 1n,
+ name: "Alice",
+ age: 30,
+});
+
+const user = deserialize(bytes);
+console.log(user);
+// { id: 1n, name: 'Alice', age: 30 }
+```
+
+## Core Model
+
+### `Fory`
+
+A `Fory` instance owns:
+
+- the type registry
+- generated serializers
+- read/write contexts
+- configuration such as reference tracking and guardrails
+
+Reuse the same `Fory` instance across many operations. Registration is per
instance.
+
+### `Type`
+
+`Type` is the schema DSL. It is used to describe:
+
+- primitive fields such as `Type.int32()` and `Type.string()`
+- collections such as `Type.array(...)`, `Type.map(...)`, and `Type.set(...)`
+- user types such as `Type.struct(...)` and `Type.enum(...)`
+- field-level metadata such as nullability, reference tracking, and dynamic
dispatch
+
+### Registration
+
+`fory.register(...)` compiles and registers a serializer. It returns:
+
+- `serializer`: the generated serializer object
+- `serialize(value)`: serialize using that schema
+- `deserialize(bytes)`: deserialize using that schema
+
+```ts
+const personType = Type.struct("example.person", {
+ name: Type.string(),
+ email: Type.string().setNullable(true),
+});
+
+const fory = new Fory();
+const personSerde = fory.register(personType);
+```
+
+## Configuration
+
+The JavaScript runtime always uses xlang serialization. The most important
options are:
+
+```ts
+import Fory from "@apache-fory/core";
+import hps from "@apache-fory/hps";
+
+const fory = new Fory({
+ ref: true,
+ compatible: true,
+ maxDepth: 100,
+ maxBinarySize: 64 * 1024 * 1024,
+ maxCollectionSize: 1_000_000,
+ useSliceString: false,
+ hps,
+});
+```
+
+| Option | Default | Meaning
|
+| -------------------------- | ------------------ |
---------------------------------------------------------------------------------------------------------------------------------
|
+| `ref` | `false` | Enables reference tracking
for graphs with shared or circular references.
|
+| `compatible` | `false` | Uses compatible struct
encoding for schema evolution.
|
+| `maxDepth` | `50` | Maximum nesting depth
accepted during deserialization. Must be `>= 2`.
|
+| `maxBinarySize` | `64 * 1024 * 1024` | Maximum allowed binary
payload for guarded binary reads.
|
+| `maxCollectionSize` | `1_000_000` | Maximum number of elements
accepted for lists, sets, and maps.
|
+| `useSliceString` | `false` | Optional string-reading
mode for Node.js environments. Leave it at the default unless you have
benchmarked a reason to change it. |
+| `hps` | unset | Optional Node.js string
fast-path helper from `@apache-fory/hps`.
|
+| `hooks.afterCodeGenerated` | unset | Callback to inspect or
transform generated serializer code. Useful for debugging.
|
+
+## Documentation
+
+| Topic | Description
|
+| --------------------------------------------- |
------------------------------------------------------- |
+| [Basic Serialization](basic-serialization.md) | Core APIs and everyday usage
|
+| [Type Registration](type-registration.md) | Numeric IDs, names,
decorators, and schema registration |
+| [Supported Types](supported-types.md) | Primitive, collection, time,
enum, and struct mappings |
+| [References](references.md) | Shared references and
circular object graphs |
+| [Schema Evolution](schema-evolution.md) | Compatible mode and evolving
structs |
+| [Cross-Language](cross-language.md) | Interop guidance and mapping
rules |
+| [Troubleshooting](troubleshooting.md) | Common issues, limits, and
debugging tips |
+
+## Related Resources
+
+- [Xlang Serialization
Specification](../../specification/xlang_serialization_spec.md)
+- [Cross-Language Type Mapping](../../specification/xlang_type_mapping.md)
diff --git a/docs/guide/javascript/references.md
b/docs/guide/javascript/references.md
new file mode 100644
index 0000000000..583dcc52c9
--- /dev/null
+++ b/docs/guide/javascript/references.md
@@ -0,0 +1,105 @@
+---
+title: References
+sidebar_position: 50
+id: references
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Fory can preserve shared references and circular object graphs, but in
JavaScript you should enable reference tracking globally and mark the specific
struct fields that participate in shared or circular references.
+
+## Enable reference tracking globally
+
+```ts
+const fory = new Fory({ ref: true });
+```
+
+Without `ref: true`, Fory treats values as ordinary tree-shaped data.
+
+## Mark reference-capable fields
+
+For schema-based structs, mark fields that can hold shared or circular
references with `.setTrackingRef(true)`.
+
+```ts
+const nodeType = Type.struct("example.node", {
+ value: Type.string(),
+ next: Type.struct("example.node").setNullable(true).setTrackingRef(true),
+});
+```
+
+## Circular self-reference example
+
+```ts
+import Fory, { Type } from "@apache-fory/core";
+
+const nodeType = Type.struct("example.node", {
+ name: Type.string(),
+ selfRef: Type.struct("example.node").setNullable(true).setTrackingRef(true),
+});
+
+const fory = new Fory({ ref: true });
+const { serialize, deserialize } = fory.register(nodeType);
+
+const node: any = { name: "root", selfRef: null };
+node.selfRef = node;
+
+const copy = deserialize(serialize(node));
+console.log(copy.selfRef === copy); // true
+```
+
+## Shared nested reference example
+
+```ts
+const innerType = Type.struct(501, {
+ value: Type.string(),
+});
+
+const outerType = Type.struct(502, {
+ left: Type.struct(501).setNullable(true).setTrackingRef(true),
+ right: Type.struct(501).setNullable(true).setTrackingRef(true),
+});
+
+const fory = new Fory({ ref: true });
+const { serialize, deserialize } = fory.register(outerType);
+
+const shared = { value: "same-object" };
+const copy = deserialize(serialize({ left: shared, right: shared }));
+console.log(copy.left === copy.right); // true
+```
+
+## When to enable it
+
+Enable reference tracking when:
+
+- the same object instance is reused in multiple fields
+- your graph can be cyclic
+- identity preservation matters after deserialization
+
+Leave it disabled when:
+
+- the data is a plain tree
+- you want the lowest overhead
+- object identity does not matter
+
+## Cross-language note
+
+Reference tracking is part of the xlang protocol, but every participating
runtime still needs compatible schema and configuration. If one side models a
graph as plain values and the other depends on object identity, behavior may
not match your expectations.
+
+## Related Topics
+
+- [Basic Serialization](basic-serialization.md)
+- [Schema Evolution](schema-evolution.md)
+- [Cross-Language](cross-language.md)
diff --git a/docs/guide/javascript/schema-evolution.md
b/docs/guide/javascript/schema-evolution.md
new file mode 100644
index 0000000000..7956e7a074
--- /dev/null
+++ b/docs/guide/javascript/schema-evolution.md
@@ -0,0 +1,102 @@
+---
+title: Schema Evolution
+sidebar_position: 60
+id: schema_evolution
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Fory JavaScript supports two struct encodings:
+
+- **schema-consistent mode**: more compact, assumes the schema matches exactly
+- **compatible mode**: writes extra metadata so readers can tolerate added or
missing fields
+
+## Enable compatible mode
+
+```ts
+const fory = new Fory({ compatible: true });
+```
+
+Compatible mode is the right choice when:
+
+- multiple services roll out schema changes independently
+- older readers may see newer payloads
+- newer readers may see older payloads
+
+## Example
+
+Writer schema:
+
+```ts
+const writerType = Type.struct(
+ { typeId: 1001 },
+ {
+ name: Type.string(),
+ age: Type.int32(),
+ },
+);
+```
+
+Reader schema with fewer fields:
+
+```ts
+const readerType = Type.struct(
+ { typeId: 1001 },
+ {
+ name: Type.string(),
+ },
+);
+```
+
+With `compatible: true`, the reader can ignore fields it does not know about.
+
+## Per-struct evolving override
+
+In JavaScript, struct schemas can explicitly disable evolving metadata even
when type identity is otherwise compatible.
+
+```ts
+const fixedType = Type.struct(
+ { typeId: 1002, evolving: false },
+ {
+ name: Type.string(),
+ },
+);
+```
+
+This produces a smaller payload than an otherwise evolving-compatible struct,
but the reader must then assume the schema matches. In cross-language use, both
sides must agree on whether that struct is evolving; if one side treats the
type as compatible and the other uses `evolving: false`, the on-wire type kind
no longer matches.
+
+## Practical guidance
+
+Choose **schema-consistent mode** when:
+
+- both ends deploy together
+- size and throughput matter most
+- schema drift is tightly controlled
+
+Choose **compatible mode** when:
+
+- services evolve independently
+- you need forward/backward tolerance
+- operational safety is more important than the last bytes of payload size
+
+## Cross-language requirement
+
+Compatible mode only helps when the logical type identity still matches across
runtimes. The same struct must still be registered with the same numeric ID or
name across languages.
+
+## Related Topics
+
+- [Type Registration](type-registration.md)
+- [Cross-Language](cross-language.md)
diff --git a/docs/guide/javascript/supported-types.md
b/docs/guide/javascript/supported-types.md
new file mode 100644
index 0000000000..0186a18726
--- /dev/null
+++ b/docs/guide/javascript/supported-types.md
@@ -0,0 +1,194 @@
+---
+title: Supported Types
+sidebar_position: 40
+id: supported_types
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+This page summarizes the main JavaScript and TypeScript values supported by
Fory JavaScript.
+
+## Primitive and Scalar Types
+
+| JavaScript/TypeScript | Fory schema
| Notes
|
+| ------------------------ |
---------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------
|
+| `boolean` | `Type.bool()`
| Boolean value
|
+| `number` | `Type.int8()` / `Type.int16()` / `Type.int32()` /
`Type.float32()` / `Type.float64()` / unsigned variants | Pick explicit numeric
width/encoding in schemas |
+| `bigint` | `Type.int64()` / `Type.varInt64()` /
`Type.uint64()` / tagged variants | Use for
64-bit integer fields |
+| `string` | `Type.string()`
| Encoded as Latin1,
UTF-16, or UTF-8 depending on content/runtime path |
+| `Uint8Array` | `Type.binary()`
| Variable-length
binary payload |
+| `Date` | `Type.timestamp()` / dynamic root date
| Timestamps round-trip
as `Date` |
+| `Date` or day count | `Type.date()`
| Date values
deserialize as `Date`; some typed APIs also accept numeric day counts |
+| duration in milliseconds | `Type.duration()`
| JavaScript currently
exposes duration fields as numeric millisecond values |
+| `BFloat16` or `number` | `Type.bfloat16()`
| Deserializes to
`BFloat16` |
+| `number` | `Type.float16()`
| Half-precision
floating-point support |
+
+## Integer Types
+
+Use explicit integer schema helpers when the wire contract matters.
+
+```ts
+Type.int8();
+Type.int16();
+Type.int32();
+Type.varInt32();
+Type.int64();
+Type.varInt64();
+Type.sliInt64();
+Type.uint8();
+Type.uint16();
+Type.uint32();
+Type.varUInt32();
+Type.uint64();
+Type.varUInt64();
+Type.taggedUInt64();
+```
+
+### Important JavaScript notes
+
+- `number` cannot safely represent all 64-bit integers.
+- For 64-bit integer fields, prefer `bigint` values in application code.
+- Dynamic root deserialization may return `bigint` for integer values that
exceed JavaScript's safe integer range.
+
+## Floating-Point Types
+
+```ts
+Type.float16();
+Type.float32();
+Type.float64();
+Type.bfloat16();
+```
+
+`float16` and `bfloat16` are useful when interoperating with runtimes or
payloads that use reduced-precision numeric formats.
+
+## Arrays and Typed Arrays
+
+### Generic arrays
+
+```ts
+Type.array(Type.string());
+Type.array(
+ Type.struct("example.item", {
+ id: Type.int64(),
+ }),
+);
+```
+
+These map to JavaScript arrays.
+
+### Optimized typed arrays
+
+Fory JavaScript supports specialized array schemas for compact numeric and
boolean arrays.
+
+```ts
+Type.boolArray();
+Type.int16Array();
+Type.int32Array();
+Type.int64Array();
+Type.float16Array();
+Type.bfloat16Array();
+Type.float32Array();
+Type.float64Array();
+```
+
+Typical runtime values are:
+
+| Schema | Typical JavaScript value
|
+| ---------------------- |
-------------------------------------------------------------------- |
+| `Type.boolArray()` | `boolean[]`
|
+| `Type.int16Array()` | `Int16Array`
|
+| `Type.int32Array()` | `Int32Array`
|
+| `Type.int64Array()` | `BigInt64Array`
|
+| `Type.float32Array()` | `Float32Array`
|
+| `Type.float64Array()` | `Float64Array`
|
+| `Type.float16Array()` | `number[]`
|
+| `Type.bfloat16Array()` | `BFloat16Array` or `number[]` as input;
deserializes to `BFloat16[]` |
+
+## Maps and Sets
+
+```ts
+Type.map(Type.string(), Type.int32());
+Type.set(Type.string());
+```
+
+These map to JavaScript `Map` and `Set` values.
+
+## Structs
+
+```ts
+Type.struct("example.user", {
+ id: Type.int64(),
+ name: Type.string(),
+ tags: Type.array(Type.string()),
+});
+```
+
+Structs can be declared inline, by decorators, or nested within other schemas.
+
+## Enums
+
+```ts
+Type.enum("example.color", {
+ Red: 1,
+ Green: 2,
+ Blue: 3,
+});
+```
+
+Both numeric and string enum values are supported. JavaScript encodes enum
members by ordinal position in the declared enum object order and maps that
ordinal back to the corresponding JavaScript value on read, so cross-language
peers must agree on the enum member order and shape, not only the literal
values.
+
+## Nullable fields
+
+Use `.setNullable(true)` when a field may be `null`.
+
+```ts
+Type.string().setNullable(true);
+```
+
+## Dynamic fields
+
+Use `Type.any()` for dynamically typed content.
+
+```ts
+const eventType = Type.struct("example.event", {
+ kind: Type.string(),
+ payload: Type.any(),
+});
+```
+
+This is useful for polymorphic payload slots, but more explicit field types
are preferable when the schema is stable.
+
+## Reference-tracked fields
+
+Fields that can participate in shared or circular graphs should opt in:
+
+```ts
+Type.struct("example.node").setTrackingRef(true).setNullable(true);
+```
+
+This requires `new Fory({ ref: true })` at the instance level.
+
+## Extension types and advanced areas
+
+JavaScript supports extension types through `Type.ext(...)` plus a custom
serializer passed to `fory.register(...)`.
+
+The xlang specification also includes additional kinds such as unions. If you
plan to depend on advanced features beyond the documented JavaScript surface,
validate the exact API and interoperability behavior in your target runtime
versions before committing to a shared wire contract.
+
+## Related Topics
+
+- [Basic Serialization](basic-serialization.md)
+- [References](references.md)
+- [Cross-Language](cross-language.md)
diff --git a/docs/guide/javascript/troubleshooting.md
b/docs/guide/javascript/troubleshooting.md
new file mode 100644
index 0000000000..fa2dc61358
--- /dev/null
+++ b/docs/guide/javascript/troubleshooting.md
@@ -0,0 +1,113 @@
+---
+title: Troubleshooting
+sidebar_position: 90
+id: troubleshooting
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+This page covers common problems when using Fory JavaScript.
+
+## Non-xlang payloads cannot be deserialized
+
+The JavaScript runtime reads xlang payloads only. If you try to deserialize a
non-xlang payload, deserialization fails.
+
+Make sure the producer is writing Fory xlang data.
+
+## `maxDepth must be an integer >= 2`
+
+`maxDepth` protects the deserializer from excessive nesting.
+
+```ts
+new Fory({ maxDepth: 100 });
+```
+
+Use a larger value only when your payloads genuinely need it.
+
+## `Binary size ... exceeds maxBinarySize`
+
+A binary field or payload exceeded the configured safety limit.
+
+```ts
+new Fory({ maxBinarySize: 128 * 1024 * 1024 });
+```
+
+Increase the limit only if the input size is expected and trusted.
+
+## `Collection size ... exceeds maxCollectionSize`
+
+A list, set, or map exceeded the configured collection limit.
+
+```ts
+new Fory({ maxCollectionSize: 2_000_000 });
+```
+
+This is commonly hit when a producer sends unexpectedly large arrays or maps.
+
+## `Field "..." is not nullable`
+
+A schema field was written as `null` but was not marked nullable.
+
+```ts
+const userType = Type.struct("example.user", {
+ name: Type.string(),
+ email: Type.string().setNullable(true),
+});
+```
+
+Mark nullable fields explicitly.
+
+## Reference graphs do not preserve identity
+
+Check both conditions:
+
+1. `new Fory({ ref: true })` is enabled
+2. the relevant schema fields use `.setTrackingRef(true)`
+
+Missing either one will usually turn the graph into ordinary value-based
serialization.
+
+## Large integers come back as `bigint`
+
+This is expected for 64-bit integer values or for dynamic numbers that exceed
JavaScript's safe integer range. Use explicit numeric schemas and `bigint` in
your application when exact 64-bit integer semantics matter.
+
+## Debugging generated serializers
+
+Use `hooks.afterCodeGenerated` to inspect generated code.
+
+```ts
+const fory = new Fory({
+ hooks: {
+ afterCodeGenerated(code) {
+ console.error(code);
+ return code;
+ },
+ },
+});
+```
+
+## Optional `@apache-fory/hps` install issues
+
+`@apache-fory/hps` is optional and Node-specific. If installation fails,
remove it from your config and continue with `@apache-fory/core` alone.
+
+```ts
+const fory = new Fory();
+```
+
+## Related Topics
+
+- [Basic Serialization](basic-serialization.md)
+- [References](references.md)
+- [Cross-Language](cross-language.md)
diff --git a/docs/guide/javascript/type-registration.md
b/docs/guide/javascript/type-registration.md
new file mode 100644
index 0000000000..07e908aec8
--- /dev/null
+++ b/docs/guide/javascript/type-registration.md
@@ -0,0 +1,217 @@
+---
+title: Type Registration
+sidebar_position: 30
+id: type_registration
+license: |
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+---
+
+Type registration tells Fory JavaScript how to identify and encode
user-defined structs and enums.
+
+## Registering Structs
+
+You can register a struct by numeric ID or by name.
+
+### Register by numeric type ID
+
+```ts
+const userType = Type.struct(
+ { typeId: 1001 },
+ {
+ id: Type.int64(),
+ name: Type.string(),
+ },
+);
+
+const fory = new Fory();
+const userSerde = fory.register(userType);
+```
+
+Use numeric IDs when:
+
+- you want compact metadata on the wire
+- you control IDs across all participating languages
+- the same logical type is registered everywhere with the same ID
+
+### Register by name
+
+```ts
+const userType = Type.struct(
+ { typeName: "example.user" },
+ {
+ id: Type.int64(),
+ name: Type.string(),
+ },
+);
+
+const fory = new Fory();
+const userSerde = fory.register(userType);
+```
+
+Named registration is usually easier to evolve operationally because it avoids
central numeric ID allocation, but it writes more metadata than numeric IDs.
+
+### Explicit namespace and type name
+
+```ts
+const userType = Type.struct(
+ {
+ namespace: "example",
+ typeName: "user",
+ },
+ {
+ id: Type.int64(),
+ name: Type.string(),
+ },
+);
+```
+
+This corresponds to the named xlang type identity carried in metadata.
+
+## Registering with Decorators
+
+```ts
[email protected]({ typeId: 1001 })
+class User {
+ @Type.int64()
+ id!: bigint;
+
+ @Type.string()
+ name!: string;
+}
+
+const fory = new Fory();
+const { serialize, deserialize } = fory.register(User);
+```
+
+Decorator-based registration is convenient when you want your TypeScript class
declaration and schema to live together.
+
+## Registering Enums
+
+Fory JavaScript supports both plain JavaScript enum-like objects and
TypeScript enums.
+
+### JavaScript object enum
+
+```ts
+const Color = {
+ Red: 1,
+ Green: 2,
+ Blue: 3,
+};
+
+const fory = new Fory();
+const colorSerde = fory.register(Type.enum("example.color", Color));
+```
+
+### TypeScript enum
+
+```ts
+enum Status {
+ Pending = "pending",
+ Active = "active",
+}
+
+const fory = new Fory();
+fory.register(Type.enum("example.status", Status));
+```
+
+## Registration Scope
+
+Registration is per `Fory` instance.
+
+```ts
+const fory1 = new Fory();
+const fory2 = new Fory();
+
+fory1.register(
+ Type.struct("example.user", {
+ id: Type.int64(),
+ }),
+);
+
+// fory2 does not know that schema until you register it again there.
+```
+
+## Schema Handles Returned by `register`
+
+`register` returns a bound serializer pair:
+
+```ts
+const orderType = Type.struct("example.order", {
+ id: Type.int64(),
+ total: Type.float64(),
+});
+
+const { serializer, serialize, deserialize } = new Fory().register(orderType);
+```
+
+Use these bound functions for repeated operations on the same type.
+
+## Field Metadata
+
+Each field type can be refined with schema metadata.
+
+### Nullability
+
+```ts
+Type.string().setNullable(true);
+```
+
+### Reference tracking on a field
+
+```ts
+Type.struct("example.node").setTrackingRef(true);
+```
+
+This matters only when `new Fory({ ref: true })` is also enabled globally.
+
+### Dynamic dispatch
+
+```ts
+import { Dynamic, Type } from "@apache-fory/core";
+
+Type.struct("example.child").setDynamic(Dynamic.FALSE);
+```
+
+Use `dynamic` when the runtime type behavior must be controlled explicitly. In
this implementation, `Dynamic.FALSE` forces monomorphic handling,
`Dynamic.TRUE` forces polymorphic handling, and `Dynamic.AUTO` leaves the
decision to the runtime. This is especially relevant for polymorphic fields in
xlang payloads, while most users should keep the default behavior unless they
are tuning a specific schema edge case.
+
+## Choosing IDs vs names
+
+Use **numeric IDs** when:
+
+- you want the smallest wire representation
+- your organization can keep IDs stable and unique
+- multiple runtimes are coordinated tightly
+
+Use **names** when:
+
+- you want easier decentralized coordination
+- schemas are shared by package/module name already
+- slightly larger metadata is acceptable
+
+## Cross-language requirement
+
+For xlang interoperability, the serializer and deserializer must agree on the
same type identity:
+
+- same numeric ID, or
+- same namespace + type name
+
+The field schema must also match in a cross-language-compatible way. See
[Cross-Language](cross-language.md).
+
+## Related Topics
+
+- [Basic Serialization](basic-serialization.md)
+- [Schema Evolution](schema-evolution.md)
+- [Cross-Language](cross-language.md)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]