Custom s.xxx() factories
Last updated: 2026-06-18
Use a custom factory when you want a reusable type to be discoverable from the namespace object:
Factories are different from DSL literals. The literal gives you compact configuration ('tenant-id!'); the factory gives you editor discovery and a typed builder.
Register a factory with one extension definition
literal controls the DSL string form. factoryName controls the s.xxx() method. Both forms share the same JSON Schema fragment.
TypeScript declaration
Runtime registration makes the factory available at runtime. TypeScript also needs a module augmentation so the method appears in editor hints:
If your extension package exports an installer, place this declaration in the same package so downstream users get the factory type when they import your setup module.
Naming and conflict rules
factoryNamemust be a valid JavaScript/TypeScript identifier.- Use lower camel case, such as
tenantId,orderCode, orcurrencyCode. - Do not reuse built-in factory names such as
string,number,email,array,enum, ortype. - Do not use reserved namespace helpers such as
config,if,match,error,defineExtension, orregisterExtension.
Runtime-scoped factory
Frameworks, tenants, plugin hosts, and isolated tests can attach factories to a runtime instance:
This keeps the factory on runtime.s and does not mutate the process-global namespace.
Relationship with chain methods
s.tenantId() creates a builder from a custom type. It does not automatically add .tenantId() as a method on every string builder. If you want s('string!').tenantId(), read Custom Chain Methods.
Corresponding sample file
Example entry: custom-factories.ts
Note: Registers a custom factory on s, uses the same DSL literal, and shows a runtime-scoped factory.