@fedify/postgres 0.1.0-dev.2

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright 2024 Hong Minhee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,69 @@
1
+ <!-- deno-fmt-ignore-file -->
2
+
3
+ @fedify/postgres: PostgreSQL drivers for Fedify
4
+ ===============================================
5
+
6
+ [![JSR][JSR badge]][JSR]
7
+ [![npm][npm badge]][npm]
8
+ [![GitHub Actions][GitHub Actions badge]][GitHub Actions]
9
+
10
+ This package provides [Fedify]'s [`KvStore`] and [`MessageQueue`]
11
+ implementations for PostgreSQL:
12
+
13
+ - [`PostgresKvStore`]
14
+ - [`PostgresMessageQueue`]
15
+
16
+ ~~~~ typescript
17
+ import { createFederation } from "@fedify/fedify";
18
+ import { PostgresKvStore, PostgresMessageQueue } from "@fedify/postgres";
19
+ import postgres from "postgres";
20
+
21
+ const sql = postgres("postgresql://user:password@localhost/dbname");
22
+
23
+ const federation = createFederation({
24
+ kv: new PostgresKvStore(sql),
25
+ queue: new PostgresMessageQueue(sql),
26
+ });
27
+ ~~~~
28
+
29
+ [JSR]: https://jsr.io/@fedify/postgres
30
+ [JSR badge]: https://jsr.io/badges/@fedify/postgres
31
+ [npm]: https://www.npmjs.com/package/@fedify/postgres
32
+ [npm badge]: https://img.shields.io/npm/v/@fedify/postgres?logo=npm
33
+ [GitHub Actions]: https://github.com/dahlia/fedify-postgres/actions/workflows/main.yaml
34
+ [GitHub Actions badge]: https://github.com/dahlia/fedify-postgres/actions/workflows/main.yaml/badge.svg
35
+ [Fedify]: https://fedify.dev/
36
+ [`KvStore`]: https://jsr.io/@fedify/fedify/doc/federation/~/KvStore
37
+ [`MessageQueue`]: https://jsr.io/@fedify/fedify/doc/federation/~/MessageQueue
38
+ [`PostgresKvStore`]: https://jsr.io/@fedify/postgres/doc/federation/~/PostgresKvStore
39
+ [`PostgresMessageQueue`]: https://jsr.io/@fedify/postgres/doc/federation/~/PostgresMessageQueue
40
+
41
+
42
+ Installation
43
+ ------------
44
+
45
+ ### Deno
46
+
47
+ ~~~~ sh
48
+ deno add @fedify/postgres
49
+ ~~~~
50
+
51
+ ### Node.js
52
+
53
+ ~~~~ sh
54
+ npm install @fedify/postgres
55
+ ~~~~
56
+
57
+ ### Bun
58
+
59
+ ~~~~ sh
60
+ bun add @fedify/postgres
61
+ ~~~~
62
+
63
+
64
+ Changelog
65
+ ---------
66
+
67
+ ### Version 0.1.0
68
+
69
+ To be released.
@@ -0,0 +1,64 @@
1
+ import { Deno } from "@deno/shim-deno";
2
+ export { Deno } from "@deno/shim-deno";
3
+ import { Temporal as Temporal } from "@js-temporal/polyfill";
4
+ export { Temporal as Temporal } from "@js-temporal/polyfill";
5
+ const dntGlobals = {
6
+ Deno,
7
+ Temporal,
8
+ };
9
+ export const dntGlobalThis = createMergeProxy(globalThis, dntGlobals);
10
+ function createMergeProxy(baseObj, extObj) {
11
+ return new Proxy(baseObj, {
12
+ get(_target, prop, _receiver) {
13
+ if (prop in extObj) {
14
+ return extObj[prop];
15
+ }
16
+ else {
17
+ return baseObj[prop];
18
+ }
19
+ },
20
+ set(_target, prop, value) {
21
+ if (prop in extObj) {
22
+ delete extObj[prop];
23
+ }
24
+ baseObj[prop] = value;
25
+ return true;
26
+ },
27
+ deleteProperty(_target, prop) {
28
+ let success = false;
29
+ if (prop in extObj) {
30
+ delete extObj[prop];
31
+ success = true;
32
+ }
33
+ if (prop in baseObj) {
34
+ delete baseObj[prop];
35
+ success = true;
36
+ }
37
+ return success;
38
+ },
39
+ ownKeys(_target) {
40
+ const baseKeys = Reflect.ownKeys(baseObj);
41
+ const extKeys = Reflect.ownKeys(extObj);
42
+ const extKeysSet = new Set(extKeys);
43
+ return [...baseKeys.filter((k) => !extKeysSet.has(k)), ...extKeys];
44
+ },
45
+ defineProperty(_target, prop, desc) {
46
+ if (prop in extObj) {
47
+ delete extObj[prop];
48
+ }
49
+ Reflect.defineProperty(baseObj, prop, desc);
50
+ return true;
51
+ },
52
+ getOwnPropertyDescriptor(_target, prop) {
53
+ if (prop in extObj) {
54
+ return Reflect.getOwnPropertyDescriptor(extObj, prop);
55
+ }
56
+ else {
57
+ return Reflect.getOwnPropertyDescriptor(baseObj, prop);
58
+ }
59
+ },
60
+ has(_target, prop) {
61
+ return prop in extObj || prop in baseObj;
62
+ },
63
+ });
64
+ }
package/esm/mod.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/mod.js";
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
package/esm/src/kv.js ADDED
@@ -0,0 +1,106 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _PostgresKvStore_instances, _PostgresKvStore_sql, _PostgresKvStore_tableName, _PostgresKvStore_initialized, _PostgresKvStore_expire;
13
+ /**
14
+ * A key-value store that uses PostgreSQL as the underlying storage.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { createFederation } from "@fedify/fedify";
19
+ * import { PostgresKvStore } from "@fedify/postgres";
20
+ * import postgres from "postgres";
21
+ *
22
+ * const federation = createFederation({
23
+ * // ...
24
+ * kv: new PostgresKvStore(postgres("postgres://user:pass@localhost/db")),
25
+ * });
26
+ * ```
27
+ */
28
+ export class PostgresKvStore {
29
+ /**
30
+ * Creates a new PostgreSQL key-value store.
31
+ * @param sql The PostgreSQL client to use.
32
+ * @param options The options for the key-value store.
33
+ */
34
+ constructor(
35
+ // deno-lint-ignore ban-types
36
+ sql, options = {}) {
37
+ _PostgresKvStore_instances.add(this);
38
+ // deno-lint-ignore ban-types
39
+ _PostgresKvStore_sql.set(this, void 0);
40
+ _PostgresKvStore_tableName.set(this, void 0);
41
+ _PostgresKvStore_initialized.set(this, void 0);
42
+ __classPrivateFieldSet(this, _PostgresKvStore_sql, sql, "f");
43
+ __classPrivateFieldSet(this, _PostgresKvStore_tableName, options.tableName ?? "fedify_kv", "f");
44
+ __classPrivateFieldSet(this, _PostgresKvStore_initialized, options.initialized ?? false, "f");
45
+ }
46
+ async get(key) {
47
+ await this.initialize();
48
+ const result = await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
49
+ SELECT value
50
+ FROM ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))}
51
+ WHERE key = ${key} AND (ttl IS NULL OR created + ttl > CURRENT_TIMESTAMP);
52
+ `;
53
+ if (result.length < 1)
54
+ return undefined;
55
+ return JSON.parse(result[0].value);
56
+ }
57
+ async set(key, value, options) {
58
+ await this.initialize();
59
+ const ttl = options?.ttl == null ? null : options.ttl.toString();
60
+ await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
61
+ INSERT INTO ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))} (key, value, ttl)
62
+ VALUES (${key}, ${JSON.stringify(value)}, ${ttl})
63
+ ON CONFLICT (key)
64
+ DO UPDATE SET value = EXCLUDED.value, ttl = EXCLUDED.ttl;
65
+ `;
66
+ await __classPrivateFieldGet(this, _PostgresKvStore_instances, "m", _PostgresKvStore_expire).call(this);
67
+ }
68
+ async delete(key) {
69
+ await this.initialize();
70
+ await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
71
+ DELETE FROM ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))}
72
+ WHERE key = ${key};
73
+ `;
74
+ await __classPrivateFieldGet(this, _PostgresKvStore_instances, "m", _PostgresKvStore_expire).call(this);
75
+ }
76
+ /**
77
+ * Creates the table used by the key-value store if it does not already exist.
78
+ * Does nothing if the table already exists.
79
+ */
80
+ async initialize() {
81
+ if (__classPrivateFieldGet(this, _PostgresKvStore_initialized, "f"))
82
+ return;
83
+ await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
84
+ CREATE UNLOGGED TABLE IF NOT EXISTS ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))} (
85
+ key text[] PRIMARY KEY,
86
+ value jsonb NOT NULL,
87
+ created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
88
+ ttl interval
89
+ );
90
+ `;
91
+ __classPrivateFieldSet(this, _PostgresKvStore_initialized, true, "f");
92
+ }
93
+ /**
94
+ * Drops the table used by the key-value store. Does nothing if the table
95
+ * does not exist.
96
+ */
97
+ async drop() {
98
+ await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `DROP TABLE IF EXISTS ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))};`;
99
+ }
100
+ }
101
+ _PostgresKvStore_sql = new WeakMap(), _PostgresKvStore_tableName = new WeakMap(), _PostgresKvStore_initialized = new WeakMap(), _PostgresKvStore_instances = new WeakSet(), _PostgresKvStore_expire = async function _PostgresKvStore_expire() {
102
+ await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
103
+ DELETE FROM ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))}
104
+ WHERE ttl IS NOT NULL AND created + ttl < CURRENT_TIMESTAMP;
105
+ `;
106
+ };
package/esm/src/mod.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./kv.js";
2
+ export * from "./mq.js";
package/esm/src/mq.js ADDED
@@ -0,0 +1,142 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _PostgresMessageQueue_sql, _PostgresMessageQueue_tableName, _PostgresMessageQueue_channelName, _PostgresMessageQueue_pollIntervalMs, _PostgresMessageQueue_initialized;
13
+ import * as dntShim from "../_dnt.shims.js";
14
+ /**
15
+ * A message queue that uses PostgreSQL as the underlying storage.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { createFederation } from "@fedify/fedify";
20
+ * import { PostgresMessageQueue } from "@fedify/postgres";
21
+ * import postgres from "postgres";
22
+ *
23
+ * const federation = createFederation({
24
+ * // ...
25
+ * queue: new PostgresMessageQueue(
26
+ * postgres("postgres://user:pass@localhost/db")
27
+ * ),
28
+ * });
29
+ * ```
30
+ */
31
+ export class PostgresMessageQueue {
32
+ constructor(
33
+ // deno-lint-ignore ban-types
34
+ sql, options = {}) {
35
+ // deno-lint-ignore ban-types
36
+ _PostgresMessageQueue_sql.set(this, void 0);
37
+ _PostgresMessageQueue_tableName.set(this, void 0);
38
+ _PostgresMessageQueue_channelName.set(this, void 0);
39
+ _PostgresMessageQueue_pollIntervalMs.set(this, void 0);
40
+ _PostgresMessageQueue_initialized.set(this, void 0);
41
+ __classPrivateFieldSet(this, _PostgresMessageQueue_sql, sql, "f");
42
+ __classPrivateFieldSet(this, _PostgresMessageQueue_tableName, options?.tableName ?? "fedify_message", "f");
43
+ __classPrivateFieldSet(this, _PostgresMessageQueue_channelName, options?.channelName ?? "fedify_channel", "f");
44
+ __classPrivateFieldSet(this, _PostgresMessageQueue_pollIntervalMs, dntShim.Temporal.Duration.from(options?.pollInterval ?? { seconds: 5 }).total("millisecond"), "f");
45
+ __classPrivateFieldSet(this, _PostgresMessageQueue_initialized, options?.initialized ?? false, "f");
46
+ }
47
+ async enqueue(
48
+ // deno-lint-ignore no-explicit-any
49
+ message, options) {
50
+ await this.initialize();
51
+ const delay = options?.delay ?? dntShim.Temporal.Duration.from({ seconds: 0 });
52
+ await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `
53
+ INSERT INTO ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))} (message, delay)
54
+ VALUES (${JSON.stringify(message)}, ${delay.toString()});
55
+ `;
56
+ await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").notify(__classPrivateFieldGet(this, _PostgresMessageQueue_channelName, "f"), delay.toString());
57
+ }
58
+ async listen(
59
+ // deno-lint-ignore no-explicit-any
60
+ handler, options = {}) {
61
+ const { signal } = options;
62
+ const poll = async () => {
63
+ if (signal?.aborted)
64
+ return;
65
+ const query = __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `
66
+ DELETE FROM ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))}
67
+ WHERE id = (
68
+ SELECT id
69
+ FROM ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))}
70
+ WHERE created + delay < CURRENT_TIMESTAMP
71
+ ORDER BY created
72
+ LIMIT 1
73
+ )
74
+ RETURNING message;
75
+ `.execute();
76
+ const cancel = query.cancel.bind(query);
77
+ signal?.addEventListener("abort", cancel);
78
+ for (const message of await query) {
79
+ if (signal?.aborted)
80
+ return;
81
+ await handler(JSON.parse(message.message));
82
+ }
83
+ signal?.removeEventListener("abort", cancel);
84
+ };
85
+ const timeouts = new Set();
86
+ const listen = await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").listen(__classPrivateFieldGet(this, _PostgresMessageQueue_channelName, "f"), async (delay) => {
87
+ const duration = dntShim.Temporal.Duration.from(delay);
88
+ const durationMs = duration.total("millisecond");
89
+ if (durationMs < 1)
90
+ await poll();
91
+ else
92
+ timeouts.add(setTimeout(poll, durationMs));
93
+ }, poll);
94
+ signal?.addEventListener("abort", () => {
95
+ listen.unlisten();
96
+ for (const timeout of timeouts)
97
+ clearTimeout(timeout);
98
+ });
99
+ while (!signal?.aborted) {
100
+ let timeout;
101
+ await new Promise((resolve) => {
102
+ signal?.addEventListener("abort", resolve);
103
+ timeout = setTimeout(() => {
104
+ signal?.removeEventListener("abort", resolve);
105
+ resolve(0);
106
+ }, __classPrivateFieldGet(this, _PostgresMessageQueue_pollIntervalMs, "f"));
107
+ timeouts.add(timeout);
108
+ });
109
+ if (timeout != null)
110
+ timeouts.delete(timeout);
111
+ await poll();
112
+ }
113
+ await new Promise((resolve) => {
114
+ signal?.addEventListener("abort", () => resolve());
115
+ if (signal?.aborted)
116
+ return resolve();
117
+ });
118
+ }
119
+ /**
120
+ * Initializes the message queue table if it does not already exist.
121
+ */
122
+ async initialize() {
123
+ if (__classPrivateFieldGet(this, _PostgresMessageQueue_initialized, "f"))
124
+ return;
125
+ await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `
126
+ CREATE TABLE IF NOT EXISTS ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))} (
127
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
128
+ message jsonb NOT NULL,
129
+ delay interval DEFAULT '0 seconds',
130
+ created timestamp with time zone DEFAULT CURRENT_TIMESTAMP
131
+ );
132
+ `;
133
+ __classPrivateFieldSet(this, _PostgresMessageQueue_initialized, true, "f");
134
+ }
135
+ /**
136
+ * Drops the message queue table if it exists.
137
+ */
138
+ async drop() {
139
+ await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `DROP TABLE IF EXISTS ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))};`;
140
+ }
141
+ }
142
+ _PostgresMessageQueue_sql = new WeakMap(), _PostgresMessageQueue_tableName = new WeakMap(), _PostgresMessageQueue_channelName = new WeakMap(), _PostgresMessageQueue_pollIntervalMs = new WeakMap(), _PostgresMessageQueue_initialized = new WeakMap();
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@fedify/postgres",
3
+ "version": "0.1.0-dev.2+463ee4d6",
4
+ "description": "PostgreSQL drivers for Fedify",
5
+ "keywords": [
6
+ "fedify",
7
+ "postgresql",
8
+ "postgres"
9
+ ],
10
+ "author": {
11
+ "name": "Hong Minhee",
12
+ "email": "hong@minhee.org",
13
+ "url": "https://hongminhee.org/"
14
+ },
15
+ "homepage": "https://github.com/dahlia/fedify-postgres",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/dahlia/fedify-postgres.git"
19
+ },
20
+ "license": "MIT",
21
+ "bugs": {
22
+ "url": "https://github.com/dahlia/fedify-postgres/issues"
23
+ },
24
+ "main": "./script/mod.js",
25
+ "module": "./esm/mod.js",
26
+ "types": "./types/mod.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "import": {
30
+ "types": "./types/mod.d.ts",
31
+ "default": "./esm/mod.js"
32
+ },
33
+ "require": {
34
+ "types": "./types/mod.d.ts",
35
+ "default": "./script/mod.js"
36
+ }
37
+ },
38
+ "./kv": {
39
+ "import": {
40
+ "types": "./types/src/kv.d.ts",
41
+ "default": "./esm/src/kv.js"
42
+ },
43
+ "require": {
44
+ "types": "./types/src/kv.d.ts",
45
+ "default": "./script/src/kv.js"
46
+ }
47
+ },
48
+ "./mq": {
49
+ "import": {
50
+ "types": "./types/src/mq.d.ts",
51
+ "default": "./esm/src/mq.js"
52
+ },
53
+ "require": {
54
+ "types": "./types/src/mq.d.ts",
55
+ "default": "./script/src/mq.js"
56
+ }
57
+ }
58
+ },
59
+ "funding": [
60
+ "https://github.com/sponsors/dahlia"
61
+ ],
62
+ "dependencies": {
63
+ "@fedify/fedify": "^1.0.0-dev.410+8793b61b",
64
+ "postgres": "^3.4.4",
65
+ "@deno/shim-deno": "~0.18.0",
66
+ "@js-temporal/polyfill": "^0.4.4"
67
+ },
68
+ "devDependencies": {
69
+ "@types/node": "^20.9.0"
70
+ },
71
+ "_generatedBy": "dnt@dev"
72
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dntGlobalThis = exports.Temporal = exports.Deno = void 0;
4
+ const shim_deno_1 = require("@deno/shim-deno");
5
+ var shim_deno_2 = require("@deno/shim-deno");
6
+ Object.defineProperty(exports, "Deno", { enumerable: true, get: function () { return shim_deno_2.Deno; } });
7
+ const polyfill_1 = require("@js-temporal/polyfill");
8
+ var polyfill_2 = require("@js-temporal/polyfill");
9
+ Object.defineProperty(exports, "Temporal", { enumerable: true, get: function () { return polyfill_2.Temporal; } });
10
+ const dntGlobals = {
11
+ Deno: shim_deno_1.Deno,
12
+ Temporal: polyfill_1.Temporal,
13
+ };
14
+ exports.dntGlobalThis = createMergeProxy(globalThis, dntGlobals);
15
+ function createMergeProxy(baseObj, extObj) {
16
+ return new Proxy(baseObj, {
17
+ get(_target, prop, _receiver) {
18
+ if (prop in extObj) {
19
+ return extObj[prop];
20
+ }
21
+ else {
22
+ return baseObj[prop];
23
+ }
24
+ },
25
+ set(_target, prop, value) {
26
+ if (prop in extObj) {
27
+ delete extObj[prop];
28
+ }
29
+ baseObj[prop] = value;
30
+ return true;
31
+ },
32
+ deleteProperty(_target, prop) {
33
+ let success = false;
34
+ if (prop in extObj) {
35
+ delete extObj[prop];
36
+ success = true;
37
+ }
38
+ if (prop in baseObj) {
39
+ delete baseObj[prop];
40
+ success = true;
41
+ }
42
+ return success;
43
+ },
44
+ ownKeys(_target) {
45
+ const baseKeys = Reflect.ownKeys(baseObj);
46
+ const extKeys = Reflect.ownKeys(extObj);
47
+ const extKeysSet = new Set(extKeys);
48
+ return [...baseKeys.filter((k) => !extKeysSet.has(k)), ...extKeys];
49
+ },
50
+ defineProperty(_target, prop, desc) {
51
+ if (prop in extObj) {
52
+ delete extObj[prop];
53
+ }
54
+ Reflect.defineProperty(baseObj, prop, desc);
55
+ return true;
56
+ },
57
+ getOwnPropertyDescriptor(_target, prop) {
58
+ if (prop in extObj) {
59
+ return Reflect.getOwnPropertyDescriptor(extObj, prop);
60
+ }
61
+ else {
62
+ return Reflect.getOwnPropertyDescriptor(baseObj, prop);
63
+ }
64
+ },
65
+ has(_target, prop) {
66
+ return prop in extObj || prop in baseObj;
67
+ },
68
+ });
69
+ }
package/script/mod.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./src/mod.js"), exports);
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _PostgresKvStore_instances, _PostgresKvStore_sql, _PostgresKvStore_tableName, _PostgresKvStore_initialized, _PostgresKvStore_expire;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.PostgresKvStore = void 0;
16
+ /**
17
+ * A key-value store that uses PostgreSQL as the underlying storage.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { createFederation } from "@fedify/fedify";
22
+ * import { PostgresKvStore } from "@fedify/postgres";
23
+ * import postgres from "postgres";
24
+ *
25
+ * const federation = createFederation({
26
+ * // ...
27
+ * kv: new PostgresKvStore(postgres("postgres://user:pass@localhost/db")),
28
+ * });
29
+ * ```
30
+ */
31
+ class PostgresKvStore {
32
+ /**
33
+ * Creates a new PostgreSQL key-value store.
34
+ * @param sql The PostgreSQL client to use.
35
+ * @param options The options for the key-value store.
36
+ */
37
+ constructor(
38
+ // deno-lint-ignore ban-types
39
+ sql, options = {}) {
40
+ _PostgresKvStore_instances.add(this);
41
+ // deno-lint-ignore ban-types
42
+ _PostgresKvStore_sql.set(this, void 0);
43
+ _PostgresKvStore_tableName.set(this, void 0);
44
+ _PostgresKvStore_initialized.set(this, void 0);
45
+ __classPrivateFieldSet(this, _PostgresKvStore_sql, sql, "f");
46
+ __classPrivateFieldSet(this, _PostgresKvStore_tableName, options.tableName ?? "fedify_kv", "f");
47
+ __classPrivateFieldSet(this, _PostgresKvStore_initialized, options.initialized ?? false, "f");
48
+ }
49
+ async get(key) {
50
+ await this.initialize();
51
+ const result = await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
52
+ SELECT value
53
+ FROM ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))}
54
+ WHERE key = ${key} AND (ttl IS NULL OR created + ttl > CURRENT_TIMESTAMP);
55
+ `;
56
+ if (result.length < 1)
57
+ return undefined;
58
+ return JSON.parse(result[0].value);
59
+ }
60
+ async set(key, value, options) {
61
+ await this.initialize();
62
+ const ttl = options?.ttl == null ? null : options.ttl.toString();
63
+ await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
64
+ INSERT INTO ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))} (key, value, ttl)
65
+ VALUES (${key}, ${JSON.stringify(value)}, ${ttl})
66
+ ON CONFLICT (key)
67
+ DO UPDATE SET value = EXCLUDED.value, ttl = EXCLUDED.ttl;
68
+ `;
69
+ await __classPrivateFieldGet(this, _PostgresKvStore_instances, "m", _PostgresKvStore_expire).call(this);
70
+ }
71
+ async delete(key) {
72
+ await this.initialize();
73
+ await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
74
+ DELETE FROM ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))}
75
+ WHERE key = ${key};
76
+ `;
77
+ await __classPrivateFieldGet(this, _PostgresKvStore_instances, "m", _PostgresKvStore_expire).call(this);
78
+ }
79
+ /**
80
+ * Creates the table used by the key-value store if it does not already exist.
81
+ * Does nothing if the table already exists.
82
+ */
83
+ async initialize() {
84
+ if (__classPrivateFieldGet(this, _PostgresKvStore_initialized, "f"))
85
+ return;
86
+ await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
87
+ CREATE UNLOGGED TABLE IF NOT EXISTS ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))} (
88
+ key text[] PRIMARY KEY,
89
+ value jsonb NOT NULL,
90
+ created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
91
+ ttl interval
92
+ );
93
+ `;
94
+ __classPrivateFieldSet(this, _PostgresKvStore_initialized, true, "f");
95
+ }
96
+ /**
97
+ * Drops the table used by the key-value store. Does nothing if the table
98
+ * does not exist.
99
+ */
100
+ async drop() {
101
+ await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `DROP TABLE IF EXISTS ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))};`;
102
+ }
103
+ }
104
+ exports.PostgresKvStore = PostgresKvStore;
105
+ _PostgresKvStore_sql = new WeakMap(), _PostgresKvStore_tableName = new WeakMap(), _PostgresKvStore_initialized = new WeakMap(), _PostgresKvStore_instances = new WeakSet(), _PostgresKvStore_expire = async function _PostgresKvStore_expire() {
106
+ await __classPrivateFieldGet(this, _PostgresKvStore_sql, "f").bind(this) `
107
+ DELETE FROM ${__classPrivateFieldGet(this, _PostgresKvStore_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresKvStore_tableName, "f"))}
108
+ WHERE ttl IS NOT NULL AND created + ttl < CURRENT_TIMESTAMP;
109
+ `;
110
+ };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./kv.js"), exports);
18
+ __exportStar(require("./mq.js"), exports);
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
26
+ if (kind === "m") throw new TypeError("Private method is not writable");
27
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
28
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
29
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
30
+ };
31
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
32
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
33
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
34
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
35
+ };
36
+ var _PostgresMessageQueue_sql, _PostgresMessageQueue_tableName, _PostgresMessageQueue_channelName, _PostgresMessageQueue_pollIntervalMs, _PostgresMessageQueue_initialized;
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.PostgresMessageQueue = void 0;
39
+ const dntShim = __importStar(require("../_dnt.shims.js"));
40
+ /**
41
+ * A message queue that uses PostgreSQL as the underlying storage.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * import { createFederation } from "@fedify/fedify";
46
+ * import { PostgresMessageQueue } from "@fedify/postgres";
47
+ * import postgres from "postgres";
48
+ *
49
+ * const federation = createFederation({
50
+ * // ...
51
+ * queue: new PostgresMessageQueue(
52
+ * postgres("postgres://user:pass@localhost/db")
53
+ * ),
54
+ * });
55
+ * ```
56
+ */
57
+ class PostgresMessageQueue {
58
+ constructor(
59
+ // deno-lint-ignore ban-types
60
+ sql, options = {}) {
61
+ // deno-lint-ignore ban-types
62
+ _PostgresMessageQueue_sql.set(this, void 0);
63
+ _PostgresMessageQueue_tableName.set(this, void 0);
64
+ _PostgresMessageQueue_channelName.set(this, void 0);
65
+ _PostgresMessageQueue_pollIntervalMs.set(this, void 0);
66
+ _PostgresMessageQueue_initialized.set(this, void 0);
67
+ __classPrivateFieldSet(this, _PostgresMessageQueue_sql, sql, "f");
68
+ __classPrivateFieldSet(this, _PostgresMessageQueue_tableName, options?.tableName ?? "fedify_message", "f");
69
+ __classPrivateFieldSet(this, _PostgresMessageQueue_channelName, options?.channelName ?? "fedify_channel", "f");
70
+ __classPrivateFieldSet(this, _PostgresMessageQueue_pollIntervalMs, dntShim.Temporal.Duration.from(options?.pollInterval ?? { seconds: 5 }).total("millisecond"), "f");
71
+ __classPrivateFieldSet(this, _PostgresMessageQueue_initialized, options?.initialized ?? false, "f");
72
+ }
73
+ async enqueue(
74
+ // deno-lint-ignore no-explicit-any
75
+ message, options) {
76
+ await this.initialize();
77
+ const delay = options?.delay ?? dntShim.Temporal.Duration.from({ seconds: 0 });
78
+ await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `
79
+ INSERT INTO ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))} (message, delay)
80
+ VALUES (${JSON.stringify(message)}, ${delay.toString()});
81
+ `;
82
+ await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").notify(__classPrivateFieldGet(this, _PostgresMessageQueue_channelName, "f"), delay.toString());
83
+ }
84
+ async listen(
85
+ // deno-lint-ignore no-explicit-any
86
+ handler, options = {}) {
87
+ const { signal } = options;
88
+ const poll = async () => {
89
+ if (signal?.aborted)
90
+ return;
91
+ const query = __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `
92
+ DELETE FROM ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))}
93
+ WHERE id = (
94
+ SELECT id
95
+ FROM ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))}
96
+ WHERE created + delay < CURRENT_TIMESTAMP
97
+ ORDER BY created
98
+ LIMIT 1
99
+ )
100
+ RETURNING message;
101
+ `.execute();
102
+ const cancel = query.cancel.bind(query);
103
+ signal?.addEventListener("abort", cancel);
104
+ for (const message of await query) {
105
+ if (signal?.aborted)
106
+ return;
107
+ await handler(JSON.parse(message.message));
108
+ }
109
+ signal?.removeEventListener("abort", cancel);
110
+ };
111
+ const timeouts = new Set();
112
+ const listen = await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").listen(__classPrivateFieldGet(this, _PostgresMessageQueue_channelName, "f"), async (delay) => {
113
+ const duration = dntShim.Temporal.Duration.from(delay);
114
+ const durationMs = duration.total("millisecond");
115
+ if (durationMs < 1)
116
+ await poll();
117
+ else
118
+ timeouts.add(setTimeout(poll, durationMs));
119
+ }, poll);
120
+ signal?.addEventListener("abort", () => {
121
+ listen.unlisten();
122
+ for (const timeout of timeouts)
123
+ clearTimeout(timeout);
124
+ });
125
+ while (!signal?.aborted) {
126
+ let timeout;
127
+ await new Promise((resolve) => {
128
+ signal?.addEventListener("abort", resolve);
129
+ timeout = setTimeout(() => {
130
+ signal?.removeEventListener("abort", resolve);
131
+ resolve(0);
132
+ }, __classPrivateFieldGet(this, _PostgresMessageQueue_pollIntervalMs, "f"));
133
+ timeouts.add(timeout);
134
+ });
135
+ if (timeout != null)
136
+ timeouts.delete(timeout);
137
+ await poll();
138
+ }
139
+ await new Promise((resolve) => {
140
+ signal?.addEventListener("abort", () => resolve());
141
+ if (signal?.aborted)
142
+ return resolve();
143
+ });
144
+ }
145
+ /**
146
+ * Initializes the message queue table if it does not already exist.
147
+ */
148
+ async initialize() {
149
+ if (__classPrivateFieldGet(this, _PostgresMessageQueue_initialized, "f"))
150
+ return;
151
+ await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `
152
+ CREATE TABLE IF NOT EXISTS ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))} (
153
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
154
+ message jsonb NOT NULL,
155
+ delay interval DEFAULT '0 seconds',
156
+ created timestamp with time zone DEFAULT CURRENT_TIMESTAMP
157
+ );
158
+ `;
159
+ __classPrivateFieldSet(this, _PostgresMessageQueue_initialized, true, "f");
160
+ }
161
+ /**
162
+ * Drops the message queue table if it exists.
163
+ */
164
+ async drop() {
165
+ await __classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").bind(this) `DROP TABLE IF EXISTS ${__classPrivateFieldGet(this, _PostgresMessageQueue_sql, "f").call(this, __classPrivateFieldGet(this, _PostgresMessageQueue_tableName, "f"))};`;
166
+ }
167
+ }
168
+ exports.PostgresMessageQueue = PostgresMessageQueue;
169
+ _PostgresMessageQueue_sql = new WeakMap(), _PostgresMessageQueue_tableName = new WeakMap(), _PostgresMessageQueue_channelName = new WeakMap(), _PostgresMessageQueue_pollIntervalMs = new WeakMap(), _PostgresMessageQueue_initialized = new WeakMap();
@@ -0,0 +1,9 @@
1
+ import { Deno } from "@deno/shim-deno";
2
+ export { Deno } from "@deno/shim-deno";
3
+ import { Temporal as Temporal } from "@js-temporal/polyfill";
4
+ export { Temporal as Temporal } from "@js-temporal/polyfill";
5
+ export declare const dntGlobalThis: Omit<typeof globalThis, "Deno" | "Temporal"> & {
6
+ Deno: typeof Deno;
7
+ Temporal: typeof Temporal;
8
+ };
9
+ //# sourceMappingURL=_dnt.shims.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_dnt.shims.d.ts","sourceRoot":"","sources":["../src/_dnt.shims.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,QAAQ,IAAI,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,QAAQ,IAAI,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAM7D,eAAO,MAAM,aAAa;;;CAA2C,CAAC"}
package/types/mod.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./src/mod.js";
2
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { KvKey, KvStore, KvStoreSetOptions } from "@fedify/fedify";
2
+ import type { Sql } from "postgres";
3
+ /**
4
+ * Options for the PostgreSQL key-value store.
5
+ */
6
+ export interface PostgresKvStoreOptions {
7
+ /**
8
+ * The table name to use for the key-value store. `"fedify_kv"` by default.
9
+ * @default `"fedify_kv"`
10
+ */
11
+ tableName?: string;
12
+ /**
13
+ * Whether the table has been initialized. `false` by default.
14
+ * @default `false`
15
+ */
16
+ initialized?: boolean;
17
+ }
18
+ /**
19
+ * A key-value store that uses PostgreSQL as the underlying storage.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { createFederation } from "@fedify/fedify";
24
+ * import { PostgresKvStore } from "@fedify/postgres";
25
+ * import postgres from "postgres";
26
+ *
27
+ * const federation = createFederation({
28
+ * // ...
29
+ * kv: new PostgresKvStore(postgres("postgres://user:pass@localhost/db")),
30
+ * });
31
+ * ```
32
+ */
33
+ export declare class PostgresKvStore implements KvStore {
34
+ #private;
35
+ /**
36
+ * Creates a new PostgreSQL key-value store.
37
+ * @param sql The PostgreSQL client to use.
38
+ * @param options The options for the key-value store.
39
+ */
40
+ constructor(sql: Sql<{}>, options?: PostgresKvStoreOptions);
41
+ get<T = unknown>(key: KvKey): Promise<T | undefined>;
42
+ set(key: KvKey, value: unknown, options?: KvStoreSetOptions | undefined): Promise<void>;
43
+ delete(key: KvKey): Promise<void>;
44
+ /**
45
+ * Creates the table used by the key-value store if it does not already exist.
46
+ * Does nothing if the table already exists.
47
+ */
48
+ initialize(): Promise<void>;
49
+ /**
50
+ * Drops the table used by the key-value store. Does nothing if the table
51
+ * does not exist.
52
+ */
53
+ drop(): Promise<void>;
54
+ }
55
+ //# sourceMappingURL=kv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../../src/src/kv.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAgB,YAAW,OAAO;;IAM7C;;;;OAIG;gBAGD,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,EACZ,OAAO,GAAE,sBAA2B;IAchC,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,KAAK,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAWpD,GAAG,CACP,GAAG,EAAE,KAAK,EACV,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,iBAAiB,GAAG,SAAS,GACtC,OAAO,CAAC,IAAI,CAAC;IAYV,MAAM,CAAC,GAAG,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IASvC;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAajC;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B"}
@@ -0,0 +1,3 @@
1
+ export * from "./kv.js";
2
+ export * from "./mq.js";
3
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
@@ -0,0 +1,62 @@
1
+ import * as dntShim from "../_dnt.shims.js";
2
+ import type { MessageQueue, MessageQueueEnqueueOptions, MessageQueueListenOptions } from "@fedify/fedify";
3
+ import type { Sql } from "postgres";
4
+ /**
5
+ * Options for the PostgreSQL message queue.
6
+ */
7
+ export interface PostgresMessageQueueOptions {
8
+ /**
9
+ * The table name to use for the message queue.
10
+ * `"fedify_message"` by default.
11
+ * @default `"fedify_message"`
12
+ */
13
+ tableName?: string;
14
+ /**
15
+ * The channel name to use for the message queue.
16
+ * `"fedify_channel"` by default.
17
+ * @default `"fedify_channel"`
18
+ */
19
+ channelName?: string;
20
+ /**
21
+ * Whether the table has been initialized. `false` by default.
22
+ * @default `false`
23
+ */
24
+ initialized?: boolean;
25
+ /**
26
+ * The poll interval for the message queue. 5 seconds by default.
27
+ * @default `{ seconds: 5 }`
28
+ */
29
+ pollInterval?: dntShim.Temporal.Duration | dntShim.Temporal.DurationLike;
30
+ }
31
+ /**
32
+ * A message queue that uses PostgreSQL as the underlying storage.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { createFederation } from "@fedify/fedify";
37
+ * import { PostgresMessageQueue } from "@fedify/postgres";
38
+ * import postgres from "postgres";
39
+ *
40
+ * const federation = createFederation({
41
+ * // ...
42
+ * queue: new PostgresMessageQueue(
43
+ * postgres("postgres://user:pass@localhost/db")
44
+ * ),
45
+ * });
46
+ * ```
47
+ */
48
+ export declare class PostgresMessageQueue implements MessageQueue {
49
+ #private;
50
+ constructor(sql: Sql<{}>, options?: PostgresMessageQueueOptions);
51
+ enqueue(message: any, options?: MessageQueueEnqueueOptions): Promise<void>;
52
+ listen(handler: (message: any) => void | Promise<void>, options?: MessageQueueListenOptions): Promise<void>;
53
+ /**
54
+ * Initializes the message queue table if it does not already exist.
55
+ */
56
+ initialize(): Promise<void>;
57
+ /**
58
+ * Drops the message queue table if it exists.
59
+ */
60
+ drop(): Promise<void>;
61
+ }
62
+ //# sourceMappingURL=mq.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mq.d.ts","sourceRoot":"","sources":["../../src/src/mq.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EACV,YAAY,EACZ,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;CAC1E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,oBAAqB,YAAW,YAAY;;gBAUrD,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,EACZ,OAAO,GAAE,2BAAgC;IAWrC,OAAO,CAEX,OAAO,EAAE,GAAG,EACZ,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,IAAI,CAAC;IAUV,MAAM,CAEV,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EAC/C,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,IAAI,CAAC;IAyDhB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAajC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B"}