@orpc/experimental-publisher-durable-object 0.0.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.mjs +57 -49
- package/package.json +6 -6
package/dist/index.d.mts
CHANGED
|
@@ -58,15 +58,15 @@ declare class ResumeStorage {
|
|
|
58
58
|
* Inactivity means: no active connections AND no active events.
|
|
59
59
|
*/
|
|
60
60
|
alarm(): Promise<void>;
|
|
61
|
-
private
|
|
62
|
-
private
|
|
61
|
+
private ensureSchemaAndCleanup;
|
|
62
|
+
private resetSchema;
|
|
63
63
|
private scheduleAlarm;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
interface PublisherDurableObjectOptions {
|
|
67
67
|
resume?: ResumeStorageOptions;
|
|
68
68
|
}
|
|
69
|
-
declare class PublisherDurableObject<Env = Cloudflare.Env, Props =
|
|
69
|
+
declare class PublisherDurableObject<Env = Cloudflare.Env, Props = unknown> extends DurableObject<Env, Props> {
|
|
70
70
|
private readonly resumeStorage;
|
|
71
71
|
constructor(ctx: DurableObjectState<Props>, env: Env, options?: PublisherDurableObjectOptions);
|
|
72
72
|
fetch(request: Request): Promise<Response>;
|
|
@@ -94,7 +94,7 @@ declare class DurablePublisher<T extends Record<string, object>> extends Publish
|
|
|
94
94
|
private readonly prefix;
|
|
95
95
|
private readonly serializer;
|
|
96
96
|
private readonly getStubByName;
|
|
97
|
-
constructor(namespace: DurableObjectNamespace
|
|
97
|
+
constructor(namespace: DurableObjectNamespace<any>, { prefix, getStubByName, ...options }?: DurablePublisherOptions);
|
|
98
98
|
publish<K extends keyof T & string>(event: K, payload: T[K]): Promise<void>;
|
|
99
99
|
protected subscribeListener<K extends keyof T & string>(event: K, listener: (payload: T[K]) => void, options?: PublisherSubscribeListenerOptions): Promise<() => Promise<void>>;
|
|
100
100
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -58,15 +58,15 @@ declare class ResumeStorage {
|
|
|
58
58
|
* Inactivity means: no active connections AND no active events.
|
|
59
59
|
*/
|
|
60
60
|
alarm(): Promise<void>;
|
|
61
|
-
private
|
|
62
|
-
private
|
|
61
|
+
private ensureSchemaAndCleanup;
|
|
62
|
+
private resetSchema;
|
|
63
63
|
private scheduleAlarm;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
interface PublisherDurableObjectOptions {
|
|
67
67
|
resume?: ResumeStorageOptions;
|
|
68
68
|
}
|
|
69
|
-
declare class PublisherDurableObject<Env = Cloudflare.Env, Props =
|
|
69
|
+
declare class PublisherDurableObject<Env = Cloudflare.Env, Props = unknown> extends DurableObject<Env, Props> {
|
|
70
70
|
private readonly resumeStorage;
|
|
71
71
|
constructor(ctx: DurableObjectState<Props>, env: Env, options?: PublisherDurableObjectOptions);
|
|
72
72
|
fetch(request: Request): Promise<Response>;
|
|
@@ -94,7 +94,7 @@ declare class DurablePublisher<T extends Record<string, object>> extends Publish
|
|
|
94
94
|
private readonly prefix;
|
|
95
95
|
private readonly serializer;
|
|
96
96
|
private readonly getStubByName;
|
|
97
|
-
constructor(namespace: DurableObjectNamespace
|
|
97
|
+
constructor(namespace: DurableObjectNamespace<any>, { prefix, getStubByName, ...options }?: DurablePublisherOptions);
|
|
98
98
|
publish<K extends keyof T & string>(event: K, payload: T[K]): Promise<void>;
|
|
99
99
|
protected subscribeListener<K extends keyof T & string>(event: K, listener: (payload: T[K]) => void, options?: PublisherSubscribeListenerOptions): Promise<() => Promise<void>>;
|
|
100
100
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -27,7 +27,7 @@ class ResumeStorage {
|
|
|
27
27
|
if (!this.isEnabled) {
|
|
28
28
|
return stringified;
|
|
29
29
|
}
|
|
30
|
-
await this.
|
|
30
|
+
await this.ensureSchemaAndCleanup();
|
|
31
31
|
const message = JSON.parse(stringified);
|
|
32
32
|
const insertEvent = () => {
|
|
33
33
|
const result = this.ctx.storage.sql.exec(
|
|
@@ -43,8 +43,9 @@ class ResumeStorage {
|
|
|
43
43
|
};
|
|
44
44
|
try {
|
|
45
45
|
return insertEvent();
|
|
46
|
-
} catch {
|
|
47
|
-
|
|
46
|
+
} catch (e) {
|
|
47
|
+
console.error("Failed to insert event, resetting resume storage schema.", e);
|
|
48
|
+
await this.resetSchema();
|
|
48
49
|
return insertEvent();
|
|
49
50
|
}
|
|
50
51
|
}
|
|
@@ -55,7 +56,7 @@ class ResumeStorage {
|
|
|
55
56
|
if (!this.isEnabled) {
|
|
56
57
|
return [];
|
|
57
58
|
}
|
|
58
|
-
await this.
|
|
59
|
+
await this.ensureSchemaAndCleanup();
|
|
59
60
|
const result = this.ctx.storage.sql.exec(`
|
|
60
61
|
SELECT CAST(id AS TEXT) as id, payload
|
|
61
62
|
FROM "${this.schemaPrefix}events"
|
|
@@ -79,62 +80,69 @@ class ResumeStorage {
|
|
|
79
80
|
*/
|
|
80
81
|
async alarm() {
|
|
81
82
|
this.isInitedAlarm = true;
|
|
82
|
-
await this.
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
await this.ctx.blockConcurrencyWhile(async () => {
|
|
83
|
+
await this.ensureSchemaAndCleanup();
|
|
84
|
+
const shouldReschedule = await this.ctx.blockConcurrencyWhile(async () => {
|
|
85
|
+
const hasActiveWebSockets = this.ctx.getWebSockets().length > 0;
|
|
86
|
+
if (hasActiveWebSockets) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
const activeEventsCount = this.ctx.storage.sql.exec(`
|
|
90
|
+
SELECT COUNT(*) as count
|
|
91
|
+
FROM "${this.schemaPrefix}events"
|
|
92
|
+
`);
|
|
93
|
+
const hasActiveEvents = activeEventsCount.one()?.count > 0;
|
|
94
|
+
if (hasActiveEvents) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
98
97
|
this.isInitedSchema = false;
|
|
99
98
|
this.isInitedAlarm = false;
|
|
100
99
|
await this.ctx.storage.deleteAll();
|
|
100
|
+
return false;
|
|
101
101
|
});
|
|
102
|
+
if (shouldReschedule) {
|
|
103
|
+
await this.scheduleAlarm();
|
|
104
|
+
}
|
|
102
105
|
}
|
|
103
|
-
async
|
|
104
|
-
if (this.
|
|
105
|
-
const
|
|
106
|
-
if (
|
|
107
|
-
|
|
106
|
+
async ensureSchemaAndCleanup() {
|
|
107
|
+
if (!this.isInitedAlarm) {
|
|
108
|
+
const currentAlarm = await this.ctx.storage.getAlarm();
|
|
109
|
+
if (currentAlarm === null) {
|
|
110
|
+
await this.scheduleAlarm();
|
|
108
111
|
}
|
|
109
|
-
this.
|
|
112
|
+
this.isInitedAlarm = true;
|
|
113
|
+
}
|
|
114
|
+
if (!this.isInitedSchema) {
|
|
115
|
+
const initTableResult = this.ctx.storage.sql.exec(`
|
|
116
|
+
CREATE TABLE IF NOT EXISTS "${this.schemaPrefix}events" (
|
|
117
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
118
|
+
payload TEXT NOT NULL,
|
|
119
|
+
stored_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
120
|
+
)
|
|
121
|
+
`);
|
|
122
|
+
this.ctx.storage.sql.exec(`
|
|
123
|
+
CREATE INDEX IF NOT EXISTS "${this.schemaPrefix}idx_events_id" ON "${this.schemaPrefix}events" (id)
|
|
124
|
+
`);
|
|
110
125
|
this.ctx.storage.sql.exec(`
|
|
111
|
-
|
|
112
|
-
|
|
126
|
+
CREATE INDEX IF NOT EXISTS "${this.schemaPrefix}idx_events_stored_at" ON "${this.schemaPrefix}events" (stored_at)
|
|
127
|
+
`);
|
|
128
|
+
this.isInitedSchema = true;
|
|
129
|
+
if (initTableResult.rowsWritten > 0) {
|
|
130
|
+
this.lastCleanupTime = Date.now();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const now = Date.now();
|
|
134
|
+
if (this.lastCleanupTime && this.lastCleanupTime + this.retentionSeconds * 1e3 > now) {
|
|
113
135
|
return;
|
|
114
136
|
}
|
|
115
|
-
|
|
116
|
-
CREATE TABLE IF NOT EXISTS "${this.schemaPrefix}events" (
|
|
117
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
118
|
-
payload TEXT NOT NULL,
|
|
119
|
-
stored_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
120
|
-
)
|
|
121
|
-
`);
|
|
137
|
+
this.lastCleanupTime = now;
|
|
122
138
|
this.ctx.storage.sql.exec(`
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
this.ctx.storage.sql.exec(`
|
|
126
|
-
CREATE INDEX IF NOT EXISTS "${this.schemaPrefix}idx_events_stored_at" ON "${this.schemaPrefix}events" (stored_at)
|
|
127
|
-
`);
|
|
128
|
-
this.isInitedSchema = true;
|
|
129
|
-
if (!this.isInitedAlarm || result.rowsWritten > 0) {
|
|
130
|
-
await this.scheduleAlarm();
|
|
131
|
-
this.isInitedAlarm = true;
|
|
132
|
-
}
|
|
139
|
+
DELETE FROM "${this.schemaPrefix}events" WHERE stored_at < unixepoch() - ?
|
|
140
|
+
`, this.retentionSeconds);
|
|
133
141
|
}
|
|
134
|
-
async
|
|
142
|
+
async resetSchema() {
|
|
135
143
|
this.ctx.storage.sql.exec(`DROP TABLE IF EXISTS "${this.schemaPrefix}events"`);
|
|
136
144
|
this.isInitedSchema = false;
|
|
137
|
-
await this.
|
|
145
|
+
await this.ensureSchemaAndCleanup();
|
|
138
146
|
}
|
|
139
147
|
scheduleAlarm() {
|
|
140
148
|
return this.ctx.storage.setAlarm(Date.now() + (this.retentionSeconds + this.inactiveDataRetentionTime) * 1e3);
|
|
@@ -205,10 +213,10 @@ class DurablePublisher extends Publisher {
|
|
|
205
213
|
data: { json: json_, meta: meta_ },
|
|
206
214
|
meta: getEventMeta(payload)
|
|
207
215
|
};
|
|
208
|
-
const response = await stub.fetch(
|
|
216
|
+
const response = await stub.fetch("http://localhost/publish", {
|
|
209
217
|
method: "POST",
|
|
210
218
|
body: stringifyJSON(serialized)
|
|
211
|
-
})
|
|
219
|
+
});
|
|
212
220
|
if (!response.ok) {
|
|
213
221
|
throw new Error(`Failed to publish event: ${response.status} ${response.statusText}`, {
|
|
214
222
|
cause: response
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orpc/experimental-publisher-durable-object",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.12.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://orpc.unnoq.com",
|
|
7
7
|
"repository": {
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
"dist"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@orpc/client": "1.
|
|
28
|
-
"@orpc/experimental-publisher": "1.
|
|
29
|
-
"@orpc/shared": "1.
|
|
30
|
-
"@orpc/standard-server": "1.
|
|
27
|
+
"@orpc/client": "1.12.0",
|
|
28
|
+
"@orpc/experimental-publisher": "1.12.0",
|
|
29
|
+
"@orpc/shared": "1.12.0",
|
|
30
|
+
"@orpc/standard-server": "1.12.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@cloudflare/workers-types": "^4.20251118.0",
|
|
34
34
|
"@types/node": "^22.15.30",
|
|
35
|
-
"@orpc/standard-server-peer": "1.
|
|
35
|
+
"@orpc/standard-server-peer": "1.12.0"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "unbuild",
|