Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@miniflare/durable-objects

Package Overview
Dependencies
Maintainers
2
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@miniflare/durable-objects - npm Package Compare versions

Comparing version 2.4.0 to 2.5.0

63

dist/src/index.d.ts

@@ -0,1 +1,3 @@

/// <reference types="node" />
import { Awaitable } from '@miniflare/shared';

@@ -19,6 +21,29 @@ import { Context } from '@miniflare/shared';

export declare const ALARM_KEY = "__MINIFLARE_ALARMS__";
export declare class AlarmStore {
#private;
setupStore(storage: StorageFactory, persist?: boolean | string): Promise<void>;
setupAlarms(callback: (objectKey: string) => Promise<void>): Promise<void>;
buildBridge(objectKey: string): DurableObjectAlarmBridge;
setAlarm(objectKey: string, scheduledTime: number | Date): Promise<void>;
deleteAlarm(key: string): Promise<void>;
dispose(): void;
}
export declare interface DurableObject {
fetch(request: Request): Awaitable<Response>;
alarm?(): Awaitable<void>;
}
export declare interface DurableObjectAlarm {
scheduledTime: number;
timeout?: NodeJS.Timeout;
}
export declare interface DurableObjectAlarmBridge {
setAlarm: (scheduledTime: number | Date) => Promise<void>;
deleteAlarm: () => Promise<void>;
}
export declare interface DurableObjectConstructor {

@@ -35,2 +60,6 @@ new (state: DurableObjectState, env: Context): DurableObject;

export declare interface DurableObjectGetAlarmOptions {
allowConcurrency?: boolean;
}
export declare interface DurableObjectGetOptions {

@@ -52,2 +81,3 @@ allowConcurrency?: boolean;

start?: string;
startAfter?: string;
end?: string;

@@ -76,2 +106,5 @@ prefix?: string;

list<Value = unknown>(options?: DurableObjectListOptions): Promise<Map<string, Value>>;
getAlarm(options?: DurableObjectGetAlarmOptions): Promise<number | null>;
setAlarm(scheduledTime: number | Date, options?: DurableObjectSetAlarmOptions): Promise<void>;
deleteAlarm(options?: DurableObjectSetAlarmOptions): Promise<void>;
}

@@ -83,2 +116,7 @@

export declare interface DurableObjectSetAlarmOptions {
allowConcurrency?: boolean;
allowUnconfirmed?: boolean;
}
export declare type DurableObjectsObjectsOptions = Record<string, string | {

@@ -92,2 +130,3 @@ className: string;

durableObjectsPersist?: boolean | string;
durableObjectsAlarms?: boolean;
}

@@ -99,6 +138,7 @@

durableObjectsPersist?: boolean | string;
durableObjectsAlarms?: boolean;
constructor(ctx: PluginContext, options?: DurableObjectsOptions);
getObject(storage: StorageFactory, id: DurableObjectId): Promise<DurableObjectState>;
getNamespace(storage: StorageFactory, objectName: string): DurableObjectNamespace;
setup(storageFactory: StorageFactory): SetupResult;
setup(storageFactory: StorageFactory): Promise<SetupResult>;
beforeReload(): void;

@@ -118,2 +158,3 @@ reload(bindings: Context, moduleExports: Context, mounts: Map<string, Mount>): void;

[kFetch](request: Request): Promise<Response>;
[kAlarm](): Promise<void>;
}

@@ -123,3 +164,4 @@

#private;
constructor(inner: Storage);
[kAlarmExists]: boolean;
constructor(inner: Storage, alarmBridge?: DurableObjectAlarmBridge);
transaction<T>(closure: (txn: DurableObjectTransaction) => Promise<T>): Promise<T>;

@@ -134,2 +176,5 @@ get<Value = unknown>(key: string, options?: DurableObjectGetOptions): Promise<Value | undefined>;

list<Value = unknown>(options?: DurableObjectListOptions): Promise<Map<string, Value>>;
getAlarm(options?: DurableObjectGetAlarmOptions): Promise<number | null>;
setAlarm(scheduledTime: number | Date, options?: DurableObjectSetAlarmOptions): Promise<void>;
deleteAlarm(options?: DurableObjectSetAlarmOptions): Promise<void>;
}

@@ -152,3 +197,4 @@

readonly [kWriteSet]: Set<string>;
constructor(inner: Storage, startTxnCount: number);
readonly [kAlarmExists]: boolean;
constructor(inner: Storage, startTxnCount: number, alarmExists: boolean);
get<Value = unknown>(key: string, options?: DurableObjectGetOptions): Promise<Value | undefined>;

@@ -162,5 +208,12 @@ get<Value = unknown>(keys: string[], options?: DurableObjectGetOptions): Promise<Map<string, Value>>;

list<Value = unknown>(options?: DurableObjectListOptions): Promise<Map<string, Value>>;
getAlarm(options?: DurableObjectGetAlarmOptions): Promise<number | null>;
setAlarm(scheduledTime: number | Date, options?: DurableObjectSetAlarmOptions): Promise<void>;
deleteAlarm(options?: DurableObjectSetAlarmOptions): Promise<void>;
rollback(): void;
}
declare const kAlarm: unique symbol;
export declare const kAlarmExists: unique symbol;
declare const kCommitted: unique symbol;

@@ -202,2 +255,3 @@

readonly copies: Map<string, StoredValue | undefined>;
alarm?: number | null;
constructor(inner: Storage, recordReads?: boolean);

@@ -212,4 +266,7 @@ has(key: string): Promise<boolean>;

list(options?: Omit<StorageListOptions, "cursor">): Promise<StorageListResult<StoredKey>>;
getAlarm(): Promise<number | null>;
setAlarm(scheduledTime: number | Date): Promise<void>;
deleteAlarm(): Promise<void>;
}
export { }

@@ -36,2 +36,4 @@ var __create = Object.create;

__export(exports, {
ALARM_KEY: () => ALARM_KEY,
AlarmStore: () => AlarmStore,
DurableObjectError: () => DurableObjectError,

@@ -46,5 +48,80 @@ DurableObjectId: () => DurableObjectId,

ReadWriteMutex: () => ReadWriteMutex,
ShadowStorage: () => ShadowStorage
ShadowStorage: () => ShadowStorage,
kAlarmExists: () => kAlarmExists
});
// packages/durable-objects/src/alarms.ts
var import_assert = __toModule(require("assert"));
var ALARM_KEY = "__MINIFLARE_ALARMS__";
var AlarmStore = class {
#store;
#alarms = new Map();
#alarmTimeout;
async setupStore(storage, persist) {
this.#store = await storage.storage(ALARM_KEY, persist);
const { keys } = await this.#store.list();
for (const { name, metadata } of keys) {
this.#alarms.set(name, { scheduledTime: metadata?.scheduledTime || 0 });
}
}
async setupAlarms(callback) {
if (this.#alarmTimeout)
return;
const now = Date.now();
for (const [objectKey, doAlarm] of this.#alarms) {
const { scheduledTime } = doAlarm;
if (scheduledTime < now + 3e4) {
doAlarm.timeout = setTimeout(() => {
this.#deleteAlarm(objectKey, doAlarm);
callback(objectKey);
}, Math.max(scheduledTime - now, 0));
}
}
this.#alarmTimeout = setTimeout(() => {
this.#alarmTimeout = void 0;
this.setupAlarms(callback);
}, 3e4);
this.#alarmTimeout.unref();
}
buildBridge(objectKey) {
return {
setAlarm: (scheduledTime) => this.setAlarm(objectKey, scheduledTime),
deleteAlarm: () => this.deleteAlarm(objectKey)
};
}
async setAlarm(objectKey, scheduledTime) {
if (typeof scheduledTime !== "number")
scheduledTime = scheduledTime.getTime();
this.#alarms.set(objectKey, { scheduledTime });
(0, import_assert.default)(this.#store);
await this.#store.put(objectKey, {
metadata: { scheduledTime },
value: new Uint8Array()
});
}
async deleteAlarm(key) {
const alarm = this.#alarms.get(key);
if (alarm)
await this.#deleteAlarm(key, alarm);
}
async #deleteAlarm(key, alarm) {
if (alarm.timeout)
clearTimeout(alarm.timeout);
this.#alarms.delete(key);
(0, import_assert.default)(this.#store);
await this.#store.delete(key);
}
dispose() {
if (this.#alarmTimeout) {
clearTimeout(this.#alarmTimeout);
this.#alarmTimeout = void 0;
}
for (const doAlarm of this.#alarms.values()) {
if (doAlarm.timeout)
clearTimeout(doAlarm.timeout);
}
this.#alarms.clear();
}
};
// packages/durable-objects/src/error.ts

@@ -83,2 +160,3 @@ var import_shared = __toModule(require("@miniflare/shared"));

var kInstance = Symbol("kInstance");
var kAlarm = Symbol("kAlarm");
var kFetch = Symbol("kFetch");

@@ -107,2 +185,13 @@ var DurableObjectState = class {

}
[kAlarm]() {
const outputGate = new import_shared2.OutputGate();
return outputGate.runWith(() => this.#inputGate.runWith(() => {
this.storage.deleteAlarm();
const instance = this[kInstance];
if (!instance?.alarm) {
throw new DurableObjectError("ERR_NO_HANDLER", "No alarm handler defined in Durable Object");
}
return instance.alarm();
}));
}
};

@@ -194,7 +283,7 @@ var DurableObjectStub = class {

// packages/durable-objects/src/plugin.ts
var import_assert3 = __toModule(require("assert"));
var import_assert4 = __toModule(require("assert"));
var import_shared5 = __toModule(require("@miniflare/shared"));
// packages/durable-objects/src/storage.ts
var import_assert2 = __toModule(require("assert"));
var import_assert3 = __toModule(require("assert"));
var import_v8 = __toModule(require("v8"));

@@ -266,6 +355,5 @@ var import_shared4 = __toModule(require("@miniflare/shared"));

// packages/durable-objects/src/shadow.ts
var import_assert = __toModule(require("assert"));
var import_assert2 = __toModule(require("assert"));
var import_shared3 = __toModule(require("@miniflare/shared"));
var import_storage_memory = __toModule(require("@miniflare/storage-memory"));
var collator = new Intl.Collator();
var ShadowStorage = class extends import_shared3.Storage {

@@ -280,2 +368,3 @@ constructor(inner, recordReads = true) {

copies = new Map();
alarm;
async has(key) {

@@ -323,7 +412,7 @@ return await this.hasMany([key]) > 0;

}
import_assert.default.strictEqual(innerGetKeys.length, innerGetIndices.length);
import_assert2.default.strictEqual(innerGetKeys.length, innerGetIndices.length);
if (innerGetKeys.length === 0)
return result;
const innerGetResult = await this.inner.getMany(innerGetKeys, true);
import_assert.default.strictEqual(innerGetKeys.length, innerGetResult.length);
import_assert2.default.strictEqual(innerGetKeys.length, innerGetResult.length);
for (let i = 0; i < innerGetKeys.length; i++) {

@@ -381,3 +470,3 @@ result[innerGetIndices[i]] = innerGetResult[i];

const direction = options?.reverse ? -1 : 1;
keys.sort((a, b) => direction * collator.compare(a.name, b.name));
keys.sort((a, b) => direction * (0, import_shared3.lexicographicCompare)(a.name, b.name));
if (options?.limit)

@@ -390,2 +479,19 @@ keys = keys.slice(0, options.limit);

}
async getAlarm() {
this.readSet?.add(ALARM_KEY);
if (this.alarm !== void 0)
return this.alarm;
const { metadata } = await this.inner.get(ALARM_KEY) ?? {};
return metadata?.scheduledTime ?? null;
}
setAlarm(scheduledTime) {
if (typeof scheduledTime !== "number")
scheduledTime = scheduledTime.getTime();
this.alarm = scheduledTime;
return Promise.resolve();
}
deleteAlarm() {
this.alarm = null;
return Promise.resolve();
}
};

@@ -442,3 +548,3 @@

const values = await storage.getMany(defined);
import_assert2.default.strictEqual(defined.length, values.length);
import_assert3.default.strictEqual(defined.length, values.length);
for (let i = 0; i < defined.length; i++) {

@@ -460,4 +566,19 @@ const value2 = values[i];

}
if (options.start !== void 0 && options.startAfter !== void 0) {
throw new TypeError("list() cannot be called with both start and startAfter values.");
}
const originalLimit = options.limit;
if (options.startAfter !== void 0) {
options = { ...options, start: options.startAfter };
if (options.limit !== void 0)
options.limit++;
}
const { keys } = await storage.list(options);
return get(storage, keys.map(({ name }) => name), false);
let keyNames = keys.map(({ name }) => name);
if (keyNames[0] === options.startAfter) {
keyNames.splice(0, 1);
} else if (originalLimit !== void 0) {
keyNames = keyNames.slice(0, originalLimit);
}
return get(storage, keyNames, false);
}

@@ -512,2 +633,3 @@ function normalisePutEntries(keyEntries, valueOptions) {

var kWriteSet = Symbol("kWriteSet");
var kAlarmExists = Symbol("kAlarmExists");
var DurableObjectTransaction = class {

@@ -519,5 +641,7 @@ [kInner];

[kWriteSet] = new Set();
constructor(inner, startTxnCount) {
[kAlarmExists];
constructor(inner, startTxnCount, alarmExists) {
this[kInner] = new ShadowStorage(inner);
this[kStartTxnCount] = startTxnCount;
this[kAlarmExists] = alarmExists;
}

@@ -579,2 +703,19 @@ #check(op) {

}
async getAlarm(options) {
this.#check("getAlarm");
if (!this[kAlarmExists])
return null;
return (0, import_shared4.runWithInputGateClosed)(() => this[kInner].getAlarm(), options?.allowConcurrency);
}
setAlarm(scheduledTime, options) {
this.#check("setAlarm");
if (!this[kAlarmExists]) {
throw new Error("Your Durable Object class must have an alarm() handler in order to call setAlarm()");
}
return (0, import_shared4.waitUntilOnOutputGate)((0, import_shared4.runWithInputGateClosed)(() => this[kInner].setAlarm(scheduledTime), options?.allowConcurrency), options?.allowUnconfirmed);
}
deleteAlarm(options) {
this.#check("deleteAlarm");
return (0, import_shared4.waitUntilOnOutputGate)((0, import_shared4.runWithInputGateClosed)(() => this[kInner].deleteAlarm(), options?.allowConcurrency), options?.allowUnconfirmed);
}
rollback() {

@@ -599,4 +740,7 @@ if (this[kRolledback])

#shadow;
constructor(inner) {
#alarmBridge;
[kAlarmExists] = true;
constructor(inner, alarmBridge) {
this.#inner = inner;
this.#alarmBridge = alarmBridge;
this.#shadow = new ShadowStorage(inner, false);

@@ -606,3 +750,3 @@ }

const startTxnCount = this.#txnCount;
const txn = new DurableObjectTransaction(this.#shadow, startTxnCount);
const txn = new DurableObjectTransaction(this.#shadow, startTxnCount, this[kAlarmExists]);
const result = await closure(txn);

@@ -619,3 +763,3 @@ txn[kCommitted] = true;

for (let t = txn[kStartTxnCount] + 1; t <= finishTxnCount; t++) {
const otherWriteSet = await this.#txnWriteSets.get(t);
const otherWriteSet = this.#txnWriteSets.get(t);
if (!otherWriteSet || intersects(otherWriteSet, readSet)) {

@@ -629,2 +773,3 @@ return false;

}
this.#shadow.alarm = txn[kInner].alarm;
await this.#flush();

@@ -642,3 +787,4 @@ return true;

while (true) {
const { txn, result } = await this.#txnRead(closure);
const outputGate = new import_shared4.OutputGate();
const { txn, result } = await outputGate.runWith(() => this.#txnRead(closure));
if (await this.#txnValidateWrite(txn))

@@ -656,4 +802,15 @@ return result;

#flush = async () => {
if (typeof this.#shadow.alarm === "number") {
await this.#inner.put(ALARM_KEY, {
metadata: { scheduledTime: this.#shadow.alarm },
value: new Uint8Array()
});
await this.#alarmBridge?.setAlarm(this.#shadow.alarm);
} else if (this.#shadow.alarm === null) {
await this.#inner.delete(ALARM_KEY);
await this.#alarmBridge?.deleteAlarm();
}
this.#shadow.alarm = void 0;
if (this.#shadow.copies.size === 0) {
import_assert2.default.strictEqual(this.#deletedKeySets.length, 0);
import_assert3.default.strictEqual(this.#deletedKeySets.length, 0);
return;

@@ -735,6 +892,6 @@ }

if (deletedKeySet.length) {
(0, import_assert2.default)(!this.#deletedKeySets.includes(deletedKeySet));
(0, import_assert3.default)(!this.#deletedKeySets.includes(deletedKeySet));
const result = this.#deletedKeyResults.get(deletedKeySet);
this.#deletedKeyResults.delete(deletedKeySet);
(0, import_assert2.default)(result !== void 0);
(0, import_assert3.default)(result !== void 0);
deleted += result;

@@ -759,2 +916,30 @@ }

}
async getAlarm(options) {
if (!this[kAlarmExists])
return null;
return (0, import_shared4.runWithInputGateClosed)(() => this.#mutex.runWithRead(() => this.#shadow.getAlarm()), options?.allowConcurrency);
}
async setAlarm(scheduledTime, options) {
if (!this[kAlarmExists]) {
throw new Error("Your Durable Object class must have an alarm() handler in order to call setAlarm()");
}
return runWithGatesClosed(async () => {
await this.#mutex.runWithWrite(async () => {
this.#shadow.setAlarm(scheduledTime);
this.#txnRecordWriteSet(new Set([ALARM_KEY]));
});
await Promise.resolve();
return this.#mutex.runWithWrite(this.#flush);
}, options);
}
async deleteAlarm(options) {
return runWithGatesClosed(async () => {
await this.#mutex.runWithWrite(async () => {
await this.#shadow.deleteAlarm();
this.#txnRecordWriteSet(new Set([ALARM_KEY]));
});
await Promise.resolve();
return this.#mutex.runWithWrite(this.#flush);
}, options);
}
};

@@ -766,2 +951,3 @@

durableObjectsPersist;
durableObjectsAlarms;
#persist;

@@ -775,2 +961,3 @@ #processedObjects;

#objects = new Map();
#alarmStore;
constructor(ctx, options) {

@@ -780,2 +967,3 @@ super(ctx);

this.#persist = (0, import_shared5.resolveStoragePersist)(ctx.rootPath, this.durableObjectsPersist);
this.#alarmStore = new AlarmStore();
this.#processedObjects = Object.entries(this.durableObjects ?? {}).map(([name, options2]) => {

@@ -789,3 +977,3 @@ const className = typeof options2 === "object" ? options2.className : options2;

async getObject(storage, id) {
(0, import_assert3.default)(this.#contextPromise, "beforeReload() must be called before getObject()");
(0, import_assert4.default)(this.#contextPromise, "beforeReload() must be called before getObject()");
await this.#contextPromise;

@@ -798,7 +986,9 @@ const objectName = id[kObjectName];

statePromise = (async () => {
const objectStorage = new DurableObjectStorage(await storage.storage(key, this.#persist));
const objectStorage = new DurableObjectStorage(await storage.storage(key, this.#persist), this.#alarmStore.buildBridge(key));
const state = new DurableObjectState(id, objectStorage);
const constructor = this.#constructors.get(objectName);
(0, import_assert3.default)(constructor);
(0, import_assert4.default)(constructor);
state[kInstance] = new constructor(state, this.#bindings);
if (!state[kInstance]?.alarm)
objectStorage[kAlarmExists] = false;
return state;

@@ -813,3 +1003,3 @@ })();

}
setup(storageFactory) {
async setup(storageFactory) {
const bindings = {};

@@ -819,2 +1009,3 @@ for (const { name } of this.#processedObjects) {

}
await this.#setupAlarms(storageFactory);
return {

@@ -825,2 +1016,19 @@ bindings,

}
async #setupAlarms(storage) {
if (this.durableObjectsAlarms === false)
return;
await this.#alarmStore.setupStore(storage, this.#persist);
await this.#alarmStore.setupAlarms(async (objectKey) => {
const index = objectKey.lastIndexOf(":");
const objectName = objectKey.substring(0, index);
const hexId = objectKey.substring(index + 1);
const id = new DurableObjectId(objectName, hexId);
const state = await this.getObject(storage, id);
await new import_shared5.RequestContext({
requestDepth: 1,
pipelineDepth: 1,
durableObject: true
}).runWith(() => state[kAlarm]());
});
}
beforeReload() {

@@ -851,6 +1059,7 @@ this.#objects.clear();

this.#bindings = bindings;
(0, import_assert3.default)(this.#contextResolve, "beforeReload() must be called before reload()");
(0, import_assert4.default)(this.#contextResolve, "beforeReload() must be called before reload()");
this.#contextResolve();
}
dispose() {
this.#alarmStore.dispose();
return this.beforeReload();

@@ -891,4 +1100,16 @@ }

], DurableObjectsPlugin.prototype, "durableObjectsPersist", 2);
__decorateClass([
(0, import_shared5.Option)({
type: import_shared5.OptionType.BOOLEAN,
name: "do-alarms",
description: "Enable Durable Object alarms (enabled by default)",
negatable: true,
logName: "Durable Object Alarms",
fromWrangler: ({ miniflare }) => miniflare?.durable_objects_alarms
})
], DurableObjectsPlugin.prototype, "durableObjectsAlarms", 2);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ALARM_KEY,
AlarmStore,
DurableObjectError,

@@ -903,4 +1124,5 @@ DurableObjectId,

ReadWriteMutex,
ShadowStorage
ShadowStorage,
kAlarmExists
});
//# sourceMappingURL=index.js.map

16

package.json
{
"name": "@miniflare/durable-objects",
"version": "2.4.0",
"version": "2.5.0",
"description": "Durable Objects module for Miniflare: a fun, full-featured, fully-local simulator for Cloudflare Workers",

@@ -38,12 +38,12 @@ "keywords": [

"dependencies": {
"@miniflare/core": "2.4.0",
"@miniflare/shared": "2.4.0",
"@miniflare/storage-memory": "2.4.0",
"undici": "4.13.0"
"@miniflare/core": "2.5.0",
"@miniflare/shared": "2.5.0",
"@miniflare/storage-memory": "2.5.0",
"undici": "5.3.0"
},
"devDependencies": {
"@miniflare/cache": "2.4.0",
"@miniflare/runner-vm": "2.4.0",
"@miniflare/shared-test": "2.4.0"
"@miniflare/cache": "2.5.0",
"@miniflare/runner-vm": "2.5.0",
"@miniflare/shared-test": "2.5.0"
}
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc