
Research
/Security News
10 npm Typosquatted Packages Deploy Multi-Stage Credential Harvester
Socket researchers found 10 typosquatted npm packages that auto-run on install, show fake CAPTCHAs, fingerprint by IP, and deploy a credential stealer.
@prsm/arcdb
Advanced tools
A lightweight, in-memory document database for smaller projects. You can think of this as MongoDB's little brother.
A lightweight, in-memory document database for smaller projects. You can think of this as MongoDB's little brother.
npm i @prsm/arcdb
For a more thorough API reference, please look at the tests in this repository.
A collection is just a .json file.
import { Collection } from "@prsm/arcdb";
type Planet = {
planet: string;
diameter: number;
population?: number;
temp: {
avg: number;
};
};
// from `./.data` load or create `planets.json`
const collection = new Collection<Planet>(".data", "planets");
collection.insert({ planet: "Mercury", diameter: 4880, temp: { avg: 475 } });
collection.insert([
{ planet: "Venus", diameter: 12_104, temp: { avg: 737_000 } },
{ planet: "Earth", diameter: 12_742, temp: { avg: 288 } },
]);
// finds Earth document
collection.find({ avg: 288 });
collection.find({ planet: "Earth" });
// finds Venus and Earth documents
collection.find({ diameter: { $gt: 12_000 } });
// finds Mercury and Earth documents
collection.find({ temp: { avg: { $lt: 1_000 } } });
// finds Mercury and Earth documents
collection.find({ $and: [{ avg: { $gt: 100 } }, { avg: { $lt: 10_000 } }] });
Any queries that work with .find work with .update.
// increase population, creating the property if it doesn't exist.
collection.update({ planet: "Earth" }, { $inc: { population: 1 } });
Any queries that work with .find work with .remove.
// remove every planet except Earth
collection.remove({ $not: { planet: "Earth" } });
find, update and remove accept a QueryOptions object.
{
/** When true, attempts to deeply match the query against documents. */
deep: boolean;
/** Provide fallback values for null or undefined properties */
ifNull: Record<string, any>;
/** Provide fallback values for 'empty' properties ([], {}, "") */
ifEmpty: Record<string, any>;
/** Provide fallback values for null, undefined, or 'empty' properties. */
ifNullOrEmpty: Record<string, any>;
/**
* -1 || 0: descending
* 1: ascending
*/
sort: { [property: string]: -1 | 0 | 1 };
/**
* Particularly useful when sorting, `skip` defines the number of documents
* to ignore from the beginning of the result set.
*/
skip: number;
/** Determines the number of documents returned. */
take: number;
/**
* 1: property included in result document
* 0: property excluded from result document
*/
project: {
[property: string]: 0 | 1;
};
aggregate: {
[property: string]:
Record<"$floor", string> |
Record<"$ceil", string> |
Record<"$sub", (string|number)[]> |
Record<"$mult", (string|number)[]> |
Record<"$div", (string|number)[]> |
Record<"$add", (string|number)[]>;
};
join: Array<{
/** The collection to join on. */
collection: Collection<any>;
/** The property containing the foreign key(s). */
from: string;
/** The property on the joining collection that the foreign key should point to. */
on: string;
/** The name of the property to be created while will contain the joined documents. */
as: string;
/** QueryOptions that will be applied to the joined collection. */
options?: QueryOptions;
}>;
}
// [
// { a: 1, b: 2, c: 3 },
// ];
collection.find({ a: 1 }, { ifNull: { d: 4 } });
// [
// { a: 1, b: 2, c: 3, d: 4 },
// ];
// [
// { a: 1, b: 2, c: 3, d: " " },
// { a: 1, b: 2, c: 3, d: [] },
// { a: 1, b: 2, c: 3, d: {} },
// ];
collection.find({ a: 1 }, { ifEmpty: { d: 4 } });
// [
// { a: 1, b: 2, c: 3, d: 4 },
// { a: 1, b: 2, c: 3, d: 4 },
// { a: 1, b: 2, c: 3, d: 4 },
// ];
// [
// { name: "Deanna Troi", age: 28 },
// { name: "Worf", age: 24 },
// { name: "Xorf", age: 24 },
// { name: "Zorf", age: 24 },
// { name: "Jean-Luc Picard", age: 59 },
// { name: "William Riker", age: 29 },
// ];
collection.find({ age: { $gt: 1 } }, { sort: { age: 1, name: -1 } });
// └─ asc └─ desc
// [
// { name: "Zorf", age: 24 },
// { name: "Xorf", age: 24 },
// { name: "Worf", age: 24 },
// { name: "Deanna Troi", age: 28 },
// { name: "William Riker", age: 29 },
// { name: "Jean-Luc Picard", age: 59 },
// ];
Mostly useful when paired with sort.
// [
// { a: 1, b: 1, c: 1 },
// { a: 2, b: 2, c: 2 },
// { a: 3, b: 3, c: 3 },
// ];
collection.find({ a: { $gt: 0 } }, { skip: 1, take: 1 });
// [
// { a: 2, b: 2, c: 2 },
// ];
The ID property of a document is always included unless explicitly excluded.
When all projected properties have a value of 1, this
is "implicit exclusion" mode.
In this mode, all document properties that are not defined in the projection are excluded from the result document.
// [
// { a: 1, b: 1, c: 1 },
// ];
collection.find({ a: 1 }, { project: { b: 1 } });
// [
// { _id: .., b: 1 },
// ];
When all projected properties have a value of 0, this
is "implicit inclusion" mode.
In this mode, all document properties that are not defined in the projection are included from the result document.
// [
// { a: 1, b: 1, c: 1 },
// ];
collection.find({ a: 1 }, { project: { b: 0 } });
// [
// { _id: .., a: 1, c: 1 },
// ];
In the only remaining case, all document properties
are included unless explicitly removed with a 0.
This is effectively the same behavior as implicit inclusion.
// [
// { a: 1, b: 1, c: 1 },
// ];
collection.find({ a: 1 }, { project: { b: 1, c: 0 } });
// [
// { _id: .., a: 1, b: 1 },
// ];
// [
// { math: 72, english: 82, science: 92 },
// { math: 60, english: 70, science: 80 },
// { math: 90, english: 72, science: 84 }
// ]
collection.find(
{},
{
aggregate: {
total: { $add: ["math", "english", "science"] },
average: { $div: ["total", 3] },
},
project: {
_id: 0,
total: 0,
},
}
);
// [
// { math: 72, english: 82, science: 92, average: 82 },
// { math: 60, english: 70, science: 80, average: 70 },
// { math: 90, english: 72, science: 84, average: 82 },
// ]
// "users" collection
// [
// { name: "Alice", purchasedTicketIds: [1, 2] },
// ];
// "tickets" collection
// [
// { _id: 0, seat: "A1" },
// { _id: 1, seat: "B1" },
// { _id: 2, seat: "C1" },
// { _id: 3, seat: "D1" },
// ];
users.find(
{ name: "Alice" },
{
join: [
{
collection: tickets,
from: "purchasedTicketIds",
on: "_id",
as: "tickets",
options: {
project: { _id: 0 },
},
},
],
}
);
// [
// {
// name: "Alice",
// purchasedTicketIds: [1, 2],
// tickets: [
// { seat: "B1" },
// { seat: "C1" },
// ],
// },
// ];
join allows for QueryOptions which in turn alows for join.
This means that joins can be chained for more complex relationships
between collections.
users.find(
{ .. },
{
join: [{
collection: tickets,
options: {
join: [{
collection: seats,
options: {
join: [{
collection: auditoriums,
}]
}
}]
}
}]
}
);
The default property names for document ID (default _id), "created at"
(default _created_at) and "updated at" (default _updated_at) timestamps can all be changed.
import { ID_KEY, CREATED_AT_KEY, UPDATED_AT_KEY } from "@prsm/arcdb";
ID_KEY = "id";
CREATED_AT_KEY = "createdAt";
UPDATED_AT_KEY = "updatedAt";
If you do this, make sure to do it at the beginning of collection creation.
The returned value from find, update and remove is always an array, even when there
are no results.
FAQs
A lightweight, in-memory document database for smaller projects. You can think of this as MongoDB's little brother.
We found that @prsm/arcdb demonstrated a not healthy version release cadence and project activity because the last version was released 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 found 10 typosquatted npm packages that auto-run on install, show fake CAPTCHAs, fingerprint by IP, and deploy a credential stealer.

Product
Socket Firewall Enterprise is now available with flexible deployment, configurable policies, and expanded language support.

Security News
Open source dashboard CNAPulse tracks CVE Numbering Authorities’ publishing activity, highlighting trends and transparency across the CVE ecosystem.