
Research
/Security News
Weaponizing Discord for Command and Control Across npm, PyPI, and RubyGems.org
Socket researchers uncover how threat actors weaponize Discord across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.
@aklinker1/zero-factory
Advanced tools
import { createFactory, createSequence } from "@aklinker1/zero-factory";
const userFactory = createFactory<User>({
id: createSequence("user-"),
username: "example-username",
email: () => "example-email-" + Math.random(),
});
userFactory({ id: "test", username: "user" });
// => {
// id: "test",
// username: "user",
// email: "example-email-0.20088082049103195"
// }
npm i @aklinker1/zero-factory
Features:
@ngneat/falso
, faker-js
, chance
, casual
, etc)Not Supported:
Use createFactory
to build an object factory. Object factories are simple functions that return an object:
const userFactory = createFactory<User>({
id: "user-id",
username: "username",
email: "example@gmail.com",
preferences: {
receiveMarketingEmails: true,
receiveSecurityEmails: true,
},
});
// typeof userFactory = (overrides?: DeepPartial<User>) => User
Then, to get an object conforming to the User
type, just call the factory as a function:
const user = userFactory();
// => {
// id: "user-id",
// username: "username",
// email: "example@gmail.com",
// preferences: {
// receiveMarketingEmails: true,
// receiveSecurityEmails: true,
// }
// }
You can also override specific properties at any level:
const user = userFactory({
username: "overridden",
preferences: {
receiveMarketingEmails: false,
},
});
// => {
// id: "user-id",
// username: "overridden",
// email: "example@gmail.com",
// preferences: {
// receiveMarketingEmails: false,
// receiveSecurityEmails: true,
// }
// }
[!IMPORTANT] Arrays are not deeply merged. If a property is an array, overrides will fully replace it, like any other value.
In addition to static values, the factory definition accepts functions for properties:
const userFactory = createFactory({
email: () => `example.${Math.floor(Math.random() * 1000)}@gmail.com`,
// ...
});
Every time the factory is called, this will call the function and, in this case, generate a different email
each time:
userFactory(); // { email: "example.424@gmail.com", ... }
userFactory(); // { email: "example.133@gmail.com", ... }
This is where fake data generators and sequences come in clutch:
import { createFactory, createSequence } from "@aklinker1/zero-factory";
import {
randEmail, // () => string
randUsername, // () => string
randBoolean, // () => boolean
} from "@ngneat/falso";
const userFactory = createFactory({
id: createSequence("user-"),
username: randUsername,
email: randEmail,
preferences: {
receiveMarketingEmails: randBoolean,
receiveSecurityEmails: randBoolean,
},
});
You can generate multiple objects using factory.many(...)
. This method will return an array of objects.
userFactory.many(2, { username: "override" });
// [
// { usenrame: "override", ... }
// { usenrame: "override", ... }
// ]
Overridden fields apply to all the returned objects.
If there are common variants or "traits" of an object you want to be able to generate, use factory.trait(...)
:
const userFactory = createFactory({
// same as above
}).trait("noEmails", {
preferences: {
receiveMarketingEmails: false,
receiveSecurityEmails: false,
},
});
Then, to generate an object using this trait, the trait is a function defined on the object factory:
const user = userFactory.noEmails();
// => {
// id: "user-id",
// username: "username",
// email: "example@gmail.com",
// preferences: {
// receiveMarketingEmails: false,
// receiveSecurityEmails: false,
// }
// }
When using a trait and overriding specific properties, the trait's default values are applied before the overrides:
const user = userFactory.noEmails({ username: "overridden" });
// => {
// id: "user-id",
// username: "overridden",
// email: "example@gmail.com",
// preferences: {
// receiveMarketingEmails: false,
// receiveSecurityEmails: false,
// }
// }
If you want to override one or more fields based on a single value, use associations:
const postFactory = createFactory<Post>({
id: createSequence(),
userId: userIdSequence,
// ...
}).associate("user", (user: User) => ({ userId: user.id }));
Then to generate a post associated with a user, use with
:
user;
// => {
// id: 3,
// ...
// }
postFactory.with({ user })();
// => {
// id: 0,
// userId: 3,
// ...
// }
Note that with
returns a factory function, which needs to be called to generate the final object. This allows you to chain other utilities like .many
and/or traits:
postFactory.with({ user }).noEmails.many(3);
For values like IDs, it can be useful to generate them incrementally instead of using randomized values. Use the createSequence
function to do this:
const userIdSequence = createSequence((i) => `user-${i}`);
userIdSequence(); // "user-0"
userIdSequence(); // "user-1"
userIdSequence(); // "user-2"
// ...
The argument i
is a number starting at 0 that gets incremented by 1 each time the sequence is called. The return value can be anything (string, boolean, object, integer, etc).
const intSequence = createSequence((i) => i + 1);
intSequence(); // 1
intSequence(); // 2
intSequence(); // 3
// ...
const boolSequence = createSequence((i) => i % 2 === 0);
boolSequence(); // true
boolSequence(); // false
boolSequence(); // true
// ...
However, the most common types of return values are integers and strings. For both, there is a shorthand:
const intSequence = createSequence();
intSequence(); // 0
intSequence(); // 1
intSequence(); // 2
// ...
const strSequence = createSequence("prefix-");
intSequence(); // "prefix-0"
intSequence(); // "prefix-1"
intSequence(); // "prefix-2"
FAQs
Zero dependency object factory generator for testing
We found that @aklinker1/zero-factory demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Socket researchers uncover how threat actors weaponize Discord across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.
Security News
Socket now integrates with Bun 1.3’s Security Scanner API to block risky packages at install time and enforce your organization’s policies in local dev and CI.
Research
The Socket Threat Research Team is tracking weekly intrusions into the npm registry that follow a repeatable adversarial playbook used by North Korean state-sponsored actors.