
Security News
CVE Volume Surges Past 48,000 in 2025 as WordPress Plugin Ecosystem Drives Growth
CVE disclosures hit a record 48,185 in 2025, driven largely by vulnerabilities in third-party WordPress plugins.
@trap_stevo/ventry
Advanced tools
The universal engine for creating, tracking, and evolving interactive content — from posts, comments, and likes to offers, auctions, events, and beyond. Define, extend, and analyze content objects in real time. Turn anything into user-driven content.
Turn anything into user-driven content.
The universal engine for creating, tracking, and evolving interactive content — from posts, comments, and likes to offers, auctions, events, and beyond.
Define, extend, and analyze content objects in real time.
| Requirement | Version |
|---|---|
| Node.js | ≥ 18.x |
| npm | ≥ 9.x (recommended) |
| OS | Windows, macOS, Linux |
new Ventry(options?: VentryOptions)
VentryOptions (Top-Level)| Key | Type | Default | Description |
|---|---|---|---|
contentVault | StarVault | string | null | — | Existing Star-Vault instance or a path/string to trigger internal creation (see vaultOptions). |
vaultOptions | object | {} | Options passed to internal ContentVaultInstanceManager (and used to construct Star-Vault when contentVault is not provided). |
contentMetrics | MetricTide | string | null | — | Existing MetricTide instance or options for internal creation (see metricOptions). |
metricOptions | object | {} | Options passed to internal Contalytics instance. |
vaultActionInfoDefault | object | {} | Default actionInfo metadata (propagated into vault calls). |
vaultClientAuthDefault | object | null | null | Default clientAuth context for vault operations. |
metricPrefix | string | "ugc" | Prefix for metric names (e.g., ugc.visit, ugc.like). |
eventPrefix | string | "ugc" | Prefix for emitted events. |
autoStartScheduler | boolean | true | Auto-start expiration scheduler on init. |
vaultOptionsIf you don’t pass an existing contentVault instance, Ventry will construct one with these Star-Vault parameters:
new StarVault(
dbPath, // default: "./Ventry"
logPath, // default: "./Ventry_Logs"
shardCount, // default: 4
maxLogSize, // default: "869MB"
logRetention, // default: "1w"
options // default: {}
)
vaultOptions (Ventry)| Key | Type | Default | Used For |
|---|---|---|---|
dbPath | string | "./Ventry" | Star-Vault constructor dbPath. |
logPath | string | "./Ventry_Logs" | Star-Vault constructor logPath. |
shardCount | number | 4 | Star-Vault shardCount. |
maxLogSize | string | "869MB" | Star-Vault maxLogSize. |
logRetention | string | "1w" | Star-Vault logRetention. |
options | object | {} | Star-Vault low-level options (permissions, encryption, auth, etc.). |
prefix | string | "ugc" | Collection key prefix used by Ventry: items stored under ${prefix}-items, types under ${prefix}-types, etc. |
Collections used (derived from prefix):
${prefix}-types${prefix}-items${prefix}-comments${prefix}-offers${prefix}-auctions${prefix}-bidsmetricOptionsIf you don’t pass an existing contentMetrics instance, Ventry will construct one with these MetricTide parameters:
new MetricTide({
dbPath: "./.ventry-metrics",
persistence: { alwaysOn: true },
loadMetricsOnLaunch: true,
// ...your metricOptions (merged)
})
metricOptions (Ventry)| Key | Type | Default | Description |
|---|---|---|---|
dbPath | string | "./.ventry-metrics" | Storage for metrics (MetricTide). |
persistence | object | { alwaysOn: true } | MetricTide persistence config. |
loadMetricsOnLaunch | boolean | true | Hydrate metrics on boot. |
metricPrefix | string | from Ventry | Prefix applied to tracked metrics (e.g., ugc.like). |
| (any MetricTide option) | any | — | Forwarded to MetricTide constructor. |
Types let you define how a class of content behaves (posts, listings, experiences, etc.). You can attach visibility policies, defaults, validation rules, allowed statuses, indexing hints, and branch-specific subvault behavior—without changing your item schema.
Register types early at boot. You can update any field later with
updateType.
const { Ventry } = require("@trap_stevo/ventry");
const v = new Ventry({ /* ...options... */ });
v.registerType({
typeID : "post",
// Identity & docs
title : "User Post",
description : "Short text posts with optional media attachments",
// Default fields applied to new items of this type
defaults : {
status : "active",
deployment : { scope : "global" },
commentsEnabled : true,
data : {
maxChars : 280
},
labels : [],
tags : []
},
// Validation run on create/update (throw string to reject)
validate : ({ record, phase }) => {
if (!record.data || typeof record.data.text !== "string") {
throw "post.data.text is required";
}
if (record.data.text.length > (record.data.maxChars || 280)) {
throw "text exceeds maxChars";
}
},
// Allowed lifecycle states for this type
allowedStatuses : [ "active", "hidden", "archived", "banned" ],
// Visibility policy used by feed/query (overrides default scoring if returns a number)
// Return a number for rank score, or a boolean to allow/deny.
visibilityPolicy : ({ item, metrics, boosts, geoContext, visibilityContext, now }) => {
// Example: deny if explicitly flagged
if (item.data.labels?.includes("flagged")) { return false; }
// Example: soft boost if "featured"
const base = (metrics.visits24h || 0) + (metrics.likes7d || 0) * 4 + (metrics.favorites7d || 0) * 5;
const isFeatured = item.data.labels?.includes("featured");
return isFeatured ? base * 1.25 : base;
},
// Indexing hints (forwarded to the underlying vault)
// Useful keys to accelerate queries
indexes : [
{ key : "ownerID" },
{ key : "status" },
{ key : "tags" },
{ key : "timestamp" }
],
// Subvault branches commonly used with this type (optional, declarative)
// Purely a convention aid; you can still use any branch name ad-hoc.
branches : {
"post_Reactions" : { ttlMs : 0 },
"post_Moderation" : { ttlMs : 0 }
}
});
v.updateType("post", {
description : "Short text posts (≤ 280 chars) with optional media",
allowedStatuses : [ "active", "hidden", "archived", "banned", "locked" ],
defaults : {
commentsEnabled : false
}
});
TypeConfig Shape| Field | Type | Required | Description |
|---|---|---|---|
typeID | string | Yes | Unique identifier for the type. |
title | string | No | Human-friendly name. |
description | string | No | What this type represents. |
defaults | object | No | Default fields merged into new items of this type. Supports any item fields (status, deployment, expiration, boosts, commentsEnabled, data, tags, labels, attachments). |
validate | function({ record, phase }) | No | Throw a string to reject; receives { phase : "create" | "update" }. |
allowedStatuses | string[] | No | Whitelist of legal statuses for items of this type. |
visibilityPolicy | function(ctx) | No | Custom ranking / gate. Return false to hide, true to allow (use default scoring), or number to override score. |
indexes | { key : string }[] | No | Index hints passed to the vault. |
branches | Record<string, { ttlMs? : number }> | No | Common subvault branches (convention only). |
⚠️ If
validatethrows,create/updatewill fail. Keep messages user-readable.
These are item-level fields that your type defaults and validation often manage:
status — One of your allowedStatuses. Common: "active", "hidden", "archived", "banned", "locked".deployment — { scope : "global" \| "regional", geo? : { allow? : string[], deny? : string[] } }.expiration — { data : { ttlMs? : number, expiresAt? : number }, onExpire : "hide" \| "archive" \| "delete" }.boosts — [{ weight : number, startsAt? : number, endsAt? : number }] used by ranking.commentsEnabled — boolean to toggle comment capability.labels / tags — Freeform classification for moderation, ranking, search.attachments — Array of attachment descriptors you define (URLs, blobs, content IDs).data — Arbitrary payload. Put your domain fields here and validate in validate.Enforce status constraints in your validate:
v.registerType({
typeID : "listing",
allowedStatuses : [ "draft", "active", "sold", "archived", "banned" ],
validate : ({ record, phase }) => {
const s = record.status;
if (s && ![ "draft", "active", "sold", "archived", "banned" ].includes(s)) {
throw "invalid status for listing";
}
if (s === "sold" && typeof record.data?.price !== "number") {
throw "sold listings must include final price in data.price";
}
}
});
deny first, then allow, else fallback allow.v.registerType({
typeID : "event",
defaults : {
deployment : {
scope : "regional",
geo : { allow : [ "US", "CA" ], deny : [ "PR" ] }
}
}
});
v.registerType({
typeID : "story",
defaults : {
expiration : {
data : { ttlMs : 24 * 60 * 60 * 1000 },
onExpire : "delete"
}
}
});
Use boosts + visibilityPolicy to shape ranking windows:
v.registerType({
typeID : "announcement",
visibilityPolicy : ({ item, metrics, now }) => {
const within24h = (now - (item.timestamp || now)) < 86_400_000;
const base = (metrics.visits24h || 0) + (metrics.likes7d || 0) * 3;
return within24h ? base * 2 : base;
}
});
Declare common branches as documentation (you can still pass any branch at call-time):
v.registerType({
typeID : "experience",
branches : {
"Experience_Stats" : {},
"Experience_Sessions" : {}
}
});
// Usage
v.upsertSubvaultByKey(expId, userId, "lifetime", { hours : 12 }, {}, null, "Experience_Stats");
Index keys you frequently filter on (e.g., status, ownerID, typeID, timestamp, tags).
v.registerType({
typeID : "photo",
indexes : [
{ key : "ownerID" },
{ key : "status" },
{ key : "labels" },
{ key : "timestamp" }
]
});
v.registerType({
typeID : "market_listing",
title : "Marketplace Listing",
description : "Buy/sell listings with ask price and inventory",
allowedStatuses : [ "draft", "active", "paused", "sold", "archived", "banned" ],
defaults : {
status : "draft",
commentsEnabled : true,
deployment : { scope : "global" },
data : {
currency : "USD",
inventory : 1
},
labels : [],
tags : []
},
validate : ({ record, phase }) => {
const d = record.data || {};
if (phase === "create" && typeof d.title !== "string") {
throw "listing.data.title is required";
}
if (typeof d.price !== "number" || d.price <= 0) {
throw "listing.data.price must be a positive number";
}
if (!Number.isInteger(d.inventory) || d.inventory < 0) {
throw "listing.data.inventory must be a non-negative integer";
}
if (record.status === "sold" && d.inventory !== 0) {
throw "sold listings must have inventory 0";
}
},
visibilityPolicy : ({ item, metrics }) => {
// Promote fresh, popular, reasonably priced items
const price = item.data.data?.price || 0.50;
const w = price > 0 ? Math.min(1.0, 250 / price) : 1.0;
return ((metrics.visits24h || 0) + (metrics.likes7d || 0) * 3 + (metrics.favorites7d || 0) * 4) * w;
},
indexes : [
{ key : "status" },
{ key : "ownerID" },
{ key : "tags" },
{ key : "timestamp" }
],
branches : {
"Listing_Offers" : {},
"Listing_Audit" : {}
}
});
// Create with type defaults + validation
const { id } = await v.create("seller-42", {
typeID : "market_listing",
data : { title : "Gaming Laptop", price : 1299.00, inventory : 3 },
tags : [ "electronics", "laptop" ]
});
// Move to active (allowed by type)
await v.update(id, { id : "seller-42", strictOwner : true }, { status : "active" });
| Method | Signature | Returns | Description | Async/Sync |
|---|---|---|---|---|
create(ownerID, payload, actionInfo?) | (string, object, object?) | { id } | null | Creates a new content item. | Async |
getItems(actionInfo?) | (object?) | StarVaultQueryBuilder | Opens a chainable query on the items collection. Call `.execute(true | false)` to get results. |
get(id, actionInfo?) | (string, object?) | object | null | Retrieves an item by ID. | Async |
update(id, actor, patch, actionInfo?) | (string, object, object, object?) | object | null | Updates an item with patch semantics. | Async |
remove(id, actor, opts?, actionInfo?) | (string, object, { hard?: boolean }, object?) | object | null | Soft- or hard-deletes an item. | Async |
getContentRecordHistory(collectionID, id, options?, actionInfo?, clientAuth?) | (string, string, object?, object?, object?) | Array<object> | History for a specific record in a collection. | Sync |
getContentRecordTimeline(collectionID, id, options?, actionInfo?, clientAuth?) | (string, string, object?, object?, object?) | Array<object> | Timeline (ordered events) for a specific record. | Sync |
getContentHistory(collectionID, options?, actionInfo?, clientAuth?) | (string, object?, object?, object?) | Array<object> | History across a collection (items, types, etc.). | Sync |
getContentTimeline(collectionID, options?, actionInfo?, clientAuth?) | (string, object?, object?, object?) | Array<object> | Timeline view across a collection. | Sync |
getHistory(options?, actionInfo?, clientAuth?) | (object?, object?, object?) | Array<object> | Vault-wide history inspection across collections. | Sync |
syncHistory(actionInfo?, clientAuth?) | (object?, object?) | object | Forces history/log sync (e.g. compaction, ingestion). | Async |
registerType(config, actionInfo?) | (object, object?) | object | null | Registers or upserts a content type. | Sync |
updateType(typeID, patch, actionInfo?) | (string, object, object?) | object | null | Patches a registered content type. | Sync |
listTypes(actionInfo?) | (object?) | Array<object> | Lists all registered content types. | Sync |
feed(params) | (object) | { items, nextCursor } | Ranked feed with optional custom scoring. | Sync |
query(params) | (object) | { items, nextCursor } | Flexible item queries. | Sync |
trackItemMetric(itemID, metric, value?, actorID?, extras?, actionInfo?) | (string, string, number?, string?, { tags?: object, metadata?: object }?, object?) | { ok: boolean, reason?: string } | Universal metric tracker. Auto-tags with itemID, typeID, ownerID, optional actorID; merges extras.tags; passes extras.metadata. Emits item.metric and item.metric.<metric>. | Sync |
trackItemMetrics(batch, actionInfo?) | ({ itemID: string, metric: string, value?: number, actorID?: string, extras?: { tags?: object, metadata?: object } }[], object?) | { ok: boolean, count: number } | Batch version of trackItemMetric. Processes all records; returns count of successful writes. | Sync |
visit(id, actorID, ctx?) | (string, string, object?) | void | Tracks a visit metric, emits item.visit. | Sync |
like(id, actorID) | (string, string) | void | +1 like (metric), emits item.like. | Sync |
unlike(id, actorID) | (string, string) | void | −1 like (metric), emits item.unlike. | Sync |
favorite(id, actorID) | (string, string) | void | +1 favorite (metric), emits item.favorite. | Sync |
unfavorite(id, actorID) | (string, string) | void | −1 favorite (metric), emits item.unfavorite. | Sync |
reportItem(id, reporter, reason, meta?) | (string, string, any, any?) | void | Tracks a report metric, emits item.report. | Sync |
addComment(itemID, ownerID, payload) | (string, string, object) | object | Adds a comment via CommentsManager. | Sync |
listComments(itemID, params?) | (string, object?) | Array<object> | Lists comments. | Sync |
reactToComment(id, actorID, rt) | (string, string, string) | object | Reacts to a comment. | Sync |
reportComment(id, reporter, reason, meta?) | (string, string, any, any?) | object | Reports a comment. | Sync |
proposeOffer(itemID, bidderID, input) | (string, string, object) | object | Offer lifecycle (OffersManager). | Sync |
acceptOffer(offerID, ownerID) | (string, string) | object | Accepts an offer. | Sync |
rejectOffer(offerID, ownerID, reason) | (string, string, any) | object | Rejects an offer. | Sync |
withdrawOffer(offerID, bidderID) | (string, string) | object | Withdraws an offer. | Sync |
listOffers(itemID, filter?, page?) | (string, any?, any?) | Array<object> | Lists offers. | Sync |
markItemSold(itemID, ownerID, sale) | (string, string, object) | object | Marks an item sold. | Sync |
toggleForSale(itemID, ownerID, forSale) | (string, string, boolean) | object | Toggles listing state. | Sync |
updatePrice(itemID, ownerID, price) | (string, string, number) | object | Updates listing price. | Sync |
startAuction(itemID, ownerID, cfg) | (string, string, object) | object | Starts an auction. | Sync |
cancelAuction(auctionID, ownerID, reason) | (string, string, any) | object | Cancels an auction. | Sync |
getAuction(auctionID) | (string) | object | null | Reads an auction. | Sync |
listAuctions(filter?, page?) | (object?, any?) | Array<object> | Lists auctions. | Sync |
watchAuction(auctionID, actorID) | (string, string) | object | Watch an auction. | Sync |
unwatchAuction(auctionID, actorID) | (string, string) | object | Unwatch an auction. | Sync |
placeBid(auctionID, bidderID, input) | (string, string, object) | object | Places a bid. | Sync |
retractBid(bidID, bidderID, reason) | (string, string, any) | object | Retracts a bid. | Sync |
listBids(auctionID, page?) | (string, any?) | Array<object> | Lists bids. | Sync |
getLeadingBid(auctionID) | (string) | object | null | Gets current leader. | Sync |
endAuction(auctionID, systemActor) | (string, object) | object | Ends an auction. | Sync |
settleAuction(auctionID, ownerID, settlement) | (string, string, object) | object | Settles an auction. | Sync |
getAllAnalytics(opts?) | (object?) | Array<object> | All metrics (since window / filters). | Sync |
getItemAnalytics(itemID, opts?) | (string, object?) | Array<object> | Raw metrics for an item. | Sync/Async* |
getItemAnalyticsSummary(itemID, opts?) | (string, object?) | object | Aggregated counts for an item. | Async |
getItemMetricTimeSeries(itemID, metric, opts?) | (string, string, object?) | object | Metric time series (delegates to MetricTide). | Sync |
getTopItemsBy(metric, opts?) | (string, object?) | Array<{ itemID, total }> | Top items by a metric. | Async |
* getItemAnalytics performs an in-memory scan, and optionally augments with persisted “since” lookups via MetricTide if since is provided (async path).
Ventry reconstructs record history and a human-readable timeline from write-ahead logs. These calls support filtering, integrity checks, decryption-aware output, and optional auditing.
options (history/timeline)| Key | Type | Default | Notes |
|---|---|---|---|
includeArchived | boolean | true | Include rotated *.archived segments. |
verifyChecksums | boolean | true | Verify SHA-256 checksums of entries; skip failures. |
includeSystem | boolean | true | Merge related system-level events (DELETE, TX markers). |
actions | string | string[] | undefined | Allow-list: e.g., "UPDATE" or ["WRITE","UPDATE"]. Case-insensitive. |
excludeActions | string | string[] | undefined | Block-list: e.g., ["DELETE"]. Case-insensitive. |
since | number | string | Date | undefined | Only include entries at/after this timestamp. |
until | number | string | Date | undefined | Only include entries at/before this timestamp. |
match | (row) => boolean | undefined | Custom predicate applied after other filters. |
includeDecrypted | boolean | auto | When true and encryption is enabled, decrypt entries and populate dataDecrypted. |
audit | boolean | undefined | Enables per-call auditing; see “Auditing”. |
History entries include
source,collection,action,id,timestamp,client,data,checksum, and when present:eventID,transactionID,idempotencyKey. WithincludeDecrypted, output may containdataEncryptedanddataDecrypted.
// Full history (archived segments, checksum verification)
const history = v.getContentRecordHistory("users/region1", "1760233994625", {
includeArchived : true,
verifyChecksums : true
}, { actor : "admin-1" }, { token : "valid" });
// Windowed, updates only
const updates = v.getContentRecordHistory("users/region1", "1760233994625", {
actions : "UPDATE",
since : Date.now() - 60_000,
until : Date.now()
});
// Compact timeline, no deletions, explicit audit
const timeline = v.getContentRecordTimeline("users/region1", "1760233994625", {
excludeActions : ["DELETE", "SOFT_DELETE"]
}, { audit : true }, { token : "valid" });
// Collection-level history
const collectionHistory = v.getContentHistory("users/region1", {
includeArchived : true,
includeSystem : true
});
// Vault-wide history with collection filtering
const vaultHistory = v.getHistory({
collections : ["users/*", "orders/*"],
actions : ["CREATE", "UPDATE"]
});
// Synchronous WAL flush before backup/export
await v.syncHistory({}, { token : "valid" });
History/timeline reads can write entries to audit.log for compliance, governance, or access tracking.
Auditing activates when any of the following are true:
options.audit === trueactionInfo.audit === trueEach audited read emits:
action : "HISTORY_READ" or "TIMELINE_READ"details : { kind, collection, id, count, filters }
filters is sanitized (booleans, timestamps, allow/block lists, and a flag if match is used)v.getContentRecordHistory("orders", "o-123", { audit : true });
const v = new Ventry({
vaultOptions : {
options : {
auditHistory : true
}
}
});
HISTORY_READTIMELINE_READThese cover record-level, collection-level, and global history/timeline reads.
includeDecrypted : false unless absolutely required.Ventry exposes structured, high-integrity content import helpers for migrating data, seeding environments, snapshot restoration, collection cloning, and bulk ingestion pipelines.
All import functions support per-call options, actionInfo, and clientAuth.
| Method | Signature | Returns | Description | Sync/Async |
|---|---|---|---|---|
importContentRecord(collectionID, record, options?, actionInfo?, clientAuth?) | (string, object, object?, object?, object?) | object | Imports a single record into a collection. Validates structure, preserves timestamps, and applies import-mode semantics. | Sync |
importManyContentRecords(collectionID, records, options?, actionInfo?, clientAuth?) | (string, object[], object?, object?, object?) | { imported, failed } | Bulk import for many records. Performs batched write-ahead logging and integrity checks. | Sync |
importContent(collectionID, records, options?, actionInfo?, clientAuth?) | (string, any, object?, object?, object?) | { imported, failed } | Flexible import accepting arrays, maps, or normalized payloads. Best for ETL pipelines or heterogeneous migrations. | Sync |
importSnapshot(snapshot, options?, actionInfo?, clientAuth?) | (object, object?, object?, object?) | { collections, count } | Restores a full snapshot of collections/items/types into the vault. Supports filtered restore, ID remapping, and migration guards. | Sync |
createdAt, updatedAt) are preserved when provided.options (overwrite, skip, or error).v.importContentRecord("items", {
id : "post-001",
ownerID : "user-123",
typeID : "post",
data : { text : "Migrated post" },
timestamp : 1700000000000
}, {
overwrite : true
}, { source : "migration" }, { token : "system" });
const result = v.importManyContentRecords("items", [
{ id : "a", ownerID : "u1", typeID : "post", data : { text : "Hello" } },
{ id : "b", ownerID : "u2", typeID : "post", data : { text : "World" } }
], {
skipExisting : true
});
// A snapshot may contain multiple collections.
const snapshot = {
"ugc-items" : [{ id : "1", ownerID : "x", typeID : "post", data : { text : "Imported" } }],
"ugc-types" : [{ typeID : "post", defaults : { commentsEnabled : true } }]
};
v.importSnapshot(snapshot, {
collections : ["ugc-items", "ugc-types"]
}, { source : "snapshot_restore" }, { token : "system" });
Items support nested, branch-aware data for structured, isolated extensions integrating seamlessly into storage, querying, and event workflows without altering the core item model.
These methods operate on the subvault branch by default, but you can provide a custom branch (e.g. "Experience_Stats").
| Method | Signature | Returns | Description | Async/Sync |
|---|---|---|---|---|
addSubvault(itemID, ownerID, input?, actionInfo?, branch?) | (string, string, object?, object?, string?) | { id } | Adds a new Subvault record under an item. Emits subvault.created. | Sync |
listSubvault(itemID, opts?, actionInfo?, branch?) | (string, object?, object?, string?) | { items, nextCursor } | Lists all Subvault entries for a given parent item. | Sync |
getSubvaultByKey(itemID, key, actionInfo?, branch?) | (string, string, object?, string?) | object | null | Retrieves a Subvault record by key under the given item. | Sync |
upsertSubvaultByKey(itemID, ownerID, key, payload?, extras?, actionInfo?, branch?) | (string, string, string, object?, object?, object?, string?) | object | Creates or updates a Subvault record under the same key. Emits subvault.upserted. | Sync |
updateSubvault(subvaultID, actor, patch?, actionInfo?, branch?) | (string, object, object?, object?, string?) | object | null | Updates a Subvault entry. Performs patch semantics internally. Emits subvault.updated. | Sync |
removeSubvault(subvaultID, actor, opts?, actionInfo?, branch?) | (string, object, { hard?: boolean }?, object?, string?) | object | Deletes a Subvault (soft by default). Emits subvault.deleted_soft or subvault.deleted_hard. | Sync |
existsSubvaultKey(itemID, key, actionInfo?, branch?) | (string, string, object?, string?) | boolean | Returns whether a Subvault entry exists for the given key. | Sync |
countSubvault(itemID, filter?, actionInfo?, branch?) | (string, object?, object?, string?) | number | Counts Subvault entries matching a filter. | Sync |
listSubvaultKeys(itemID, filter?, actionInfo?, branch?) | (string, object?, object?, string?) | Array<string> | Returns all keys under the specified item. | Sync |
moveSubvault(subvaultID, toItemID, actionInfo?, branch?) | (string, string, object?, string?) | object | Moves a Subvault record to another parent. Emits subvault.moved. | Sync |
cloneSubvaultRecords(fromItemID, toItemID, options?, actionInfo?, fromBranch?, toBranch?) | (string, string, object?, object?, string?, string?) | { created } | Clones all or selected Subvault records between items. Emits subvault.cloned. | Sync |
touchSubvault(subvaultID, actionInfo?, branch?) | (string, object?, string?) | object | Updates updatedAt timestamp. | Sync |
setSubvaultStatus(subvaultID, status, actionInfo?, branch?) | (string, string, object?, string?) | object | Updates the Subvault record’s status. | Sync |
purgeExpiredSubvault(itemID?, actionInfo?, branch?) | (string?, object?, string?) | { deleted } | Removes expired Subvault records (expiresAt <= now). | Sync |
The following events are emitted automatically through Ventry’s event system:
| Event | Trigger |
|---|---|
subvault.created | When a new Subvault record is added. |
subvault.updated | When a Subvault is modified. |
subvault.upserted | When a Subvault is created or updated by key. |
subvault.deleted_soft | When a Subvault is soft-deleted. |
subvault.deleted_hard | When a Subvault is hard-deleted. |
subvault.moved | When a Subvault is moved to another parent. |
subvault.cloned | When Subvault records are cloned between items. |
EventsManager)| Method | Description |
|---|---|
on(event, fn) | Subscribe to Ventry events. |
once(event, fn) | One-shot subscription. |
off(event, fn) | Unsubscribe. |
setEventPrefix(prefix) | Change runtime event prefix. |
configureScheduler(cfg) | Configure expiration scheduler. |
startScheduler() / stopScheduler() | Control scheduler loop. |
Item lifecycle events emitted by Ventry (prefix configurable):
item.createditem.updateditem.deleted_softitem.deleted_harditem.visititem.like / item.unlikeitem.favorite / item.unfavoriteitem.reportItems can define:
deployment: {
scope: "global",
geo: {
allow: ["US", "CA"],
deny: ["CN"]
}
}
At query/feed time Ventry applies deny→allow→fallback logic.
Pass geoContext to query/feed to enable filtering.
Items can define:
expiration: {
data: { ttlMs: 86400000 },
onExpire: "archive"
}
Scheduler will hide/archive/delete expired items.
Default score:
score = ((visits24h + likes7d*4 + favorites7d*5) * (1 + boostSum)) / ageHours^1.15
Provide onRanking({ item, metrics, boosts, now }) for custom ranking.
npm install @trap_stevo/ventry
const { Ventry } = require("@trap_stevo/ventry");
const v = new Ventry({
vaultOptions: {
prefix : "myapp",
dbPath : "./MyApp",
logPath : "./MyApp_Logs",
options : {
enableEncryption : false,
authHandler : (auth) => {
return auth.token === "any-token";
}
}
},
metricOptions: {
dbPath: "./.myappalytics"
},
metricPrefix: "myapp",
eventPrefix: "myapp",
vaultActionInfoDefault : { source : `myapp_core_${Date.now()}` },
vaultClientAuthDefault : { token : "any-token" }
});
// Create an item
const { id } = await v.create("user-123", {
typeID: "post",
data: { text: "Hello, world!" },
commentsEnabled: true
});
// Act on it
v.like(id, "user-456");
v.visit(id, "user-789", { ref: "home" });
// Query a feed
const feed = v.feed({ typeID: "post", limit: 10 });
console.log(feed.items);
const { id } = await v.create("seller-1", {
typeID: "listing",
data: { title: "Concert tickets", price: 120 },
tags: ["tickets", "event"],
deployment: { scope: "regional", geo: { allow: ["US"] } },
expiration: { data: { ttlMs: 86400000 }, onExpire: "archive" },
boosts: [{ weight: 0.25, startsAt: Date.now(), endsAt: Date.now() + 3600_000 }],
commentsEnabled: true
});
// Add experience data under an item
const sv = v.addSubvault("item-123", "user-123", {
key: "stats",
payload: { level: 5, exp: 340 },
tags: ["progress", "gameplay"]
});
// Update later
v.updateSubvault(sv.id, { id: "user-123" }, { payload: { level: 6 } });
// Retrieve or upsert by key
v.upsertSubvaultByKey("item-123", "user-123", "stats", { level: 7 });
// List all Subvaults under an item
const list = v.listSubvault("item-123");
// Clone all Subvaults from one item to another branch
v.cloneSubvaultRecords("item-123", "item-999", { includeKeys: ["stats"] }, null, "subvault", "Experience_Stats");
See License in LICENSE.md
🌐 Ventry — The Gateway to User-Driven Content.
Transform anything into interactive, measurable, and living content with one API.
FAQs
The universal engine for creating, tracking, and evolving interactive content — from posts, comments, and likes to offers, auctions, events, and beyond. Define, extend, and analyze content objects in real time. Turn anything into user-driven content.
The npm package @trap_stevo/ventry receives a total of 22 weekly downloads. As such, @trap_stevo/ventry popularity was classified as not popular.
We found that @trap_stevo/ventry 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.

Security News
CVE disclosures hit a record 48,185 in 2025, driven largely by vulnerabilities in third-party WordPress plugins.

Security News
Socket CEO Feross Aboukhadijeh joins Insecure Agents to discuss CVE remediation and why supply chain attacks require a different security approach.

Security News
Tailwind Labs laid off 75% of its engineering team after revenue dropped 80%, as LLMs redirect traffic away from documentation where developers discover paid products.